[2] | 1 | /* |
---|
| 2 | * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/> |
---|
| 3 | * |
---|
| 4 | * This program is free software; you can redistribute it and/or modify |
---|
| 5 | * it under the terms of the GNU General Public License as published by |
---|
| 6 | * the Free Software Foundation; either version 2 of the License, or |
---|
| 7 | * (at your option) any later version. |
---|
| 8 | * |
---|
| 9 | * This program is distributed in the hope that it will be useful, |
---|
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
| 12 | * GNU General Public License for more details. |
---|
| 13 | * |
---|
| 14 | * You should have received a copy of the GNU General Public License |
---|
| 15 | * along with this program; if not, write to the Free Software |
---|
| 16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
---|
| 17 | */ |
---|
| 18 | |
---|
| 19 | #include "Common.h" |
---|
| 20 | #include "WorldPacket.h" |
---|
| 21 | #include "WorldSession.h" |
---|
| 22 | #include "World.h" |
---|
| 23 | #include "Opcodes.h" |
---|
| 24 | #include "Log.h" |
---|
| 25 | #include "ObjectMgr.h" |
---|
| 26 | #include "Player.h" |
---|
| 27 | #include "Item.h" |
---|
| 28 | #include "UpdateData.h" |
---|
| 29 | #include "ObjectAccessor.h" |
---|
| 30 | |
---|
| 31 | void WorldSession::HandleSplitItemOpcode( WorldPacket & recv_data ) |
---|
| 32 | { |
---|
| 33 | CHECK_PACKET_SIZE(recv_data,1+1+1+1+1); |
---|
| 34 | |
---|
| 35 | //sLog.outDebug("WORLD: CMSG_SPLIT_ITEM"); |
---|
| 36 | uint8 srcbag, srcslot, dstbag, dstslot, count; |
---|
| 37 | |
---|
| 38 | recv_data >> srcbag >> srcslot >> dstbag >> dstslot >> count; |
---|
| 39 | //sLog.outDebug("STORAGE: receive srcbag = %u, srcslot = %u, dstbag = %u, dstslot = %u, count = %u", srcbag, srcslot, dstbag, dstslot, count); |
---|
| 40 | |
---|
| 41 | uint16 src = ( (srcbag << 8) | srcslot ); |
---|
| 42 | uint16 dst = ( (dstbag << 8) | dstslot ); |
---|
| 43 | |
---|
| 44 | if(src==dst) |
---|
| 45 | return; |
---|
| 46 | |
---|
| 47 | if (count==0) |
---|
| 48 | return; //check count - if zero it's fake packet |
---|
| 49 | |
---|
| 50 | _player->SplitItem( src, dst, count ); |
---|
| 51 | } |
---|
| 52 | |
---|
| 53 | void WorldSession::HandleSwapInvItemOpcode( WorldPacket & recv_data ) |
---|
| 54 | { |
---|
| 55 | CHECK_PACKET_SIZE(recv_data,1+1); |
---|
| 56 | |
---|
| 57 | //sLog.outDebug("WORLD: CMSG_SWAP_INV_ITEM"); |
---|
| 58 | uint8 srcslot, dstslot; |
---|
| 59 | |
---|
| 60 | recv_data >> srcslot >> dstslot; |
---|
| 61 | //sLog.outDebug("STORAGE: receive srcslot = %u, dstslot = %u", srcslot, dstslot); |
---|
| 62 | |
---|
| 63 | // prevent attempt swap same item to current position generated by client at special checting sequence |
---|
| 64 | if(srcslot==dstslot) |
---|
| 65 | return; |
---|
| 66 | |
---|
| 67 | uint16 src = ( (INVENTORY_SLOT_BAG_0 << 8) | srcslot ); |
---|
| 68 | uint16 dst = ( (INVENTORY_SLOT_BAG_0 << 8) | dstslot ); |
---|
| 69 | |
---|
| 70 | _player->SwapItem( src, dst ); |
---|
| 71 | } |
---|
| 72 | |
---|
| 73 | void WorldSession::HandleAutoEquipItemSlotOpcode( WorldPacket & recv_data ) |
---|
| 74 | { |
---|
| 75 | CHECK_PACKET_SIZE(recv_data,8+1); |
---|
| 76 | uint64 itemguid; |
---|
| 77 | uint8 dstslot; |
---|
| 78 | recv_data >> itemguid >> dstslot; |
---|
| 79 | |
---|
| 80 | // cheating attempt, client should never send opcode in that case |
---|
| 81 | if(!Player::IsEquipmentPos(INVENTORY_SLOT_BAG_0, dstslot)) |
---|
| 82 | return; |
---|
| 83 | |
---|
| 84 | Item* item = _player->GetItemByGuid(itemguid); |
---|
| 85 | uint16 dstpos = dstslot | (INVENTORY_SLOT_BAG_0 << 8); |
---|
| 86 | |
---|
| 87 | if(!item || item->GetPos() == dstpos) |
---|
| 88 | return; |
---|
| 89 | |
---|
| 90 | _player->SwapItem(item->GetPos(), dstpos); |
---|
| 91 | } |
---|
| 92 | |
---|
| 93 | void WorldSession::HandleSwapItem( WorldPacket & recv_data ) |
---|
| 94 | { |
---|
| 95 | CHECK_PACKET_SIZE(recv_data,1+1+1+1); |
---|
| 96 | |
---|
| 97 | //sLog.outDebug("WORLD: CMSG_SWAP_ITEM"); |
---|
| 98 | uint8 dstbag, dstslot, srcbag, srcslot; |
---|
| 99 | |
---|
| 100 | recv_data >> dstbag >> dstslot >> srcbag >> srcslot ; |
---|
| 101 | //sLog.outDebug("STORAGE: receive srcbag = %u, srcslot = %u, dstbag = %u, dstslot = %u", srcbag, srcslot, dstbag, dstslot); |
---|
| 102 | |
---|
| 103 | uint16 src = ( (srcbag << 8) | srcslot ); |
---|
| 104 | uint16 dst = ( (dstbag << 8) | dstslot ); |
---|
| 105 | |
---|
| 106 | // prevent attempt swap same item to current position generated by client at special checting sequence |
---|
| 107 | if(src==dst) |
---|
| 108 | return; |
---|
| 109 | |
---|
| 110 | _player->SwapItem( src, dst ); |
---|
| 111 | } |
---|
| 112 | |
---|
| 113 | void WorldSession::HandleAutoEquipItemOpcode( WorldPacket & recv_data ) |
---|
| 114 | { |
---|
| 115 | CHECK_PACKET_SIZE(recv_data,1+1); |
---|
| 116 | |
---|
| 117 | //sLog.outDebug("WORLD: CMSG_AUTOEQUIP_ITEM"); |
---|
| 118 | uint8 srcbag, srcslot; |
---|
| 119 | |
---|
| 120 | recv_data >> srcbag >> srcslot; |
---|
| 121 | //sLog.outDebug("STORAGE: receive srcbag = %u, srcslot = %u", srcbag, srcslot); |
---|
| 122 | |
---|
| 123 | Item *pSrcItem = _player->GetItemByPos( srcbag, srcslot ); |
---|
| 124 | if( !pSrcItem ) |
---|
| 125 | return; // only at cheat |
---|
| 126 | |
---|
| 127 | if(pSrcItem->m_lootGenerated) // prevent swap looting item |
---|
| 128 | { |
---|
| 129 | //best error message found for attempting to swap while looting |
---|
| 130 | _player->SendEquipError( EQUIP_ERR_CANT_DO_RIGHT_NOW, pSrcItem, NULL ); |
---|
| 131 | return; |
---|
| 132 | } |
---|
| 133 | |
---|
| 134 | uint16 dest; |
---|
| 135 | uint8 msg = _player->CanEquipItem( NULL_SLOT, dest, pSrcItem, !pSrcItem->IsBag() ); |
---|
| 136 | if( msg != EQUIP_ERR_OK ) |
---|
| 137 | { |
---|
| 138 | _player->SendEquipError( msg, pSrcItem, NULL ); |
---|
| 139 | return; |
---|
| 140 | } |
---|
| 141 | |
---|
| 142 | uint16 src = pSrcItem->GetPos(); |
---|
| 143 | if(dest==src) // prevent equip in same slot, only at cheat |
---|
| 144 | return; |
---|
| 145 | |
---|
| 146 | Item *pDstItem = _player->GetItemByPos( dest ); |
---|
| 147 | if( !pDstItem ) // empty slot, simple case |
---|
| 148 | { |
---|
| 149 | _player->RemoveItem( srcbag, srcslot, true ); |
---|
| 150 | _player->EquipItem( dest, pSrcItem, true ); |
---|
| 151 | _player->AutoUnequipOffhandIfNeed(); |
---|
| 152 | } |
---|
| 153 | else // have currently equipped item, not simple case |
---|
| 154 | { |
---|
| 155 | uint8 dstbag = pDstItem->GetBagSlot(); |
---|
| 156 | uint8 dstslot = pDstItem->GetSlot(); |
---|
| 157 | |
---|
| 158 | msg = _player->CanUnequipItem( dest, !pSrcItem->IsBag() ); |
---|
| 159 | if( msg != EQUIP_ERR_OK ) |
---|
| 160 | { |
---|
| 161 | _player->SendEquipError( msg, pDstItem, NULL ); |
---|
| 162 | return; |
---|
| 163 | } |
---|
| 164 | |
---|
| 165 | // check dest->src move possibility |
---|
| 166 | ItemPosCountVec sSrc; |
---|
| 167 | uint16 eSrc; |
---|
| 168 | if( _player->IsInventoryPos( src ) ) |
---|
| 169 | { |
---|
| 170 | msg = _player->CanStoreItem( srcbag, srcslot, sSrc, pDstItem, true ); |
---|
| 171 | if( msg != EQUIP_ERR_OK ) |
---|
| 172 | msg = _player->CanStoreItem( srcbag, NULL_SLOT, sSrc, pDstItem, true ); |
---|
| 173 | if( msg != EQUIP_ERR_OK ) |
---|
| 174 | msg = _player->CanStoreItem( NULL_BAG, NULL_SLOT, sSrc, pDstItem, true ); |
---|
| 175 | } |
---|
| 176 | else if( _player->IsBankPos( src ) ) |
---|
| 177 | { |
---|
| 178 | msg = _player->CanBankItem( srcbag, srcslot, sSrc, pDstItem, true ); |
---|
| 179 | if( msg != EQUIP_ERR_OK ) |
---|
| 180 | msg = _player->CanBankItem( srcbag, NULL_SLOT, sSrc, pDstItem, true ); |
---|
| 181 | if( msg != EQUIP_ERR_OK ) |
---|
| 182 | msg = _player->CanBankItem( NULL_BAG, NULL_SLOT, sSrc, pDstItem, true ); |
---|
| 183 | } |
---|
| 184 | else if( _player->IsEquipmentPos( src ) ) |
---|
| 185 | { |
---|
| 186 | msg = _player->CanEquipItem( srcslot, eSrc, pDstItem, true); |
---|
| 187 | if( msg == EQUIP_ERR_OK ) |
---|
| 188 | msg = _player->CanUnequipItem( eSrc, true); |
---|
| 189 | } |
---|
| 190 | |
---|
| 191 | if( msg != EQUIP_ERR_OK ) |
---|
| 192 | { |
---|
| 193 | _player->SendEquipError( msg, pDstItem, pSrcItem ); |
---|
| 194 | return; |
---|
| 195 | } |
---|
| 196 | |
---|
| 197 | // now do moves, remove... |
---|
| 198 | _player->RemoveItem(dstbag, dstslot, false); |
---|
| 199 | _player->RemoveItem(srcbag, srcslot, false); |
---|
| 200 | |
---|
| 201 | // add to dest |
---|
| 202 | _player->EquipItem(dest, pSrcItem, true); |
---|
| 203 | |
---|
| 204 | // add to src |
---|
| 205 | if( _player->IsInventoryPos( src ) ) |
---|
| 206 | _player->StoreItem(sSrc, pDstItem, true); |
---|
| 207 | else if( _player->IsBankPos( src ) ) |
---|
| 208 | _player->BankItem(sSrc, pDstItem, true); |
---|
| 209 | else if( _player->IsEquipmentPos( src ) ) |
---|
| 210 | _player->EquipItem(eSrc, pDstItem, true); |
---|
| 211 | |
---|
| 212 | _player->AutoUnequipOffhandIfNeed(); |
---|
| 213 | } |
---|
| 214 | } |
---|
| 215 | |
---|
| 216 | void WorldSession::HandleDestroyItemOpcode( WorldPacket & recv_data ) |
---|
| 217 | { |
---|
| 218 | CHECK_PACKET_SIZE(recv_data,1+1+1+1+1+1); |
---|
| 219 | |
---|
| 220 | //sLog.outDebug("WORLD: CMSG_DESTROYITEM"); |
---|
| 221 | uint8 bag, slot, count, data1, data2, data3; |
---|
| 222 | |
---|
| 223 | recv_data >> bag >> slot >> count >> data1 >> data2 >> data3; |
---|
| 224 | //sLog.outDebug("STORAGE: receive bag = %u, slot = %u, count = %u", bag, slot, count); |
---|
| 225 | |
---|
| 226 | uint16 pos = (bag << 8) | slot; |
---|
| 227 | |
---|
| 228 | // prevent drop unequipable items (in combat, for example) and non-empty bags |
---|
| 229 | if(_player->IsEquipmentPos(pos) || _player->IsBagPos(pos)) |
---|
| 230 | { |
---|
| 231 | uint8 msg = _player->CanUnequipItem( pos, false ); |
---|
| 232 | if( msg != EQUIP_ERR_OK ) |
---|
| 233 | { |
---|
| 234 | _player->SendEquipError( msg, _player->GetItemByPos(pos), NULL ); |
---|
| 235 | return; |
---|
| 236 | } |
---|
| 237 | } |
---|
| 238 | |
---|
| 239 | Item *pItem = _player->GetItemByPos( bag, slot ); |
---|
| 240 | if(!pItem) |
---|
| 241 | { |
---|
| 242 | _player->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL ); |
---|
| 243 | return; |
---|
| 244 | } |
---|
| 245 | |
---|
| 246 | if(count) |
---|
| 247 | { |
---|
| 248 | uint32 i_count = count; |
---|
| 249 | _player->DestroyItemCount( pItem, i_count, true ); |
---|
| 250 | } |
---|
| 251 | else |
---|
| 252 | _player->DestroyItem( bag, slot, true ); |
---|
| 253 | } |
---|
| 254 | |
---|
| 255 | // Only _static_ data send in this packet !!! |
---|
| 256 | void WorldSession::HandleItemQuerySingleOpcode( WorldPacket & recv_data ) |
---|
| 257 | { |
---|
| 258 | CHECK_PACKET_SIZE(recv_data, 4); |
---|
| 259 | |
---|
| 260 | //sLog.outDebug("WORLD: CMSG_ITEM_QUERY_SINGLE"); |
---|
| 261 | uint32 item; |
---|
| 262 | recv_data >> item; |
---|
| 263 | |
---|
| 264 | sLog.outDetail("STORAGE: Item Query = %u", item); |
---|
| 265 | |
---|
| 266 | ItemPrototype const *pProto = objmgr.GetItemPrototype( item ); |
---|
| 267 | if( pProto ) |
---|
| 268 | { |
---|
| 269 | std::string Name = pProto->Name1; |
---|
| 270 | std::string Description = pProto->Description; |
---|
| 271 | |
---|
| 272 | int loc_idx = GetSessionDbLocaleIndex(); |
---|
| 273 | if ( loc_idx >= 0 ) |
---|
| 274 | { |
---|
| 275 | ItemLocale const *il = objmgr.GetItemLocale(pProto->ItemId); |
---|
| 276 | if (il) |
---|
| 277 | { |
---|
| 278 | if (il->Name.size() > loc_idx && !il->Name[loc_idx].empty()) |
---|
| 279 | Name = il->Name[loc_idx]; |
---|
| 280 | if (il->Description.size() > loc_idx && !il->Description[loc_idx].empty()) |
---|
| 281 | Description = il->Description[loc_idx]; |
---|
| 282 | } |
---|
| 283 | } |
---|
| 284 | // guess size |
---|
| 285 | WorldPacket data( SMSG_ITEM_QUERY_SINGLE_RESPONSE, 600); |
---|
| 286 | data << pProto->ItemId; |
---|
| 287 | data << pProto->Class; |
---|
| 288 | data << pProto->SubClass; |
---|
| 289 | data << uint32(-1); // new 2.0.3, not exist in wdb cache? |
---|
| 290 | data << Name; |
---|
| 291 | data << uint8(0x00); //pProto->Name2; // blizz not send name there, just uint8(0x00); <-- \0 = empty string = empty name... |
---|
| 292 | data << uint8(0x00); //pProto->Name3; // blizz not send name there, just uint8(0x00); |
---|
| 293 | data << uint8(0x00); //pProto->Name4; // blizz not send name there, just uint8(0x00); |
---|
| 294 | data << pProto->DisplayInfoID; |
---|
| 295 | data << pProto->Quality; |
---|
| 296 | data << pProto->Flags; |
---|
| 297 | data << pProto->BuyPrice; |
---|
| 298 | data << pProto->SellPrice; |
---|
| 299 | data << pProto->InventoryType; |
---|
| 300 | data << pProto->AllowableClass; |
---|
| 301 | data << pProto->AllowableRace; |
---|
| 302 | data << pProto->ItemLevel; |
---|
| 303 | data << pProto->RequiredLevel; |
---|
| 304 | data << pProto->RequiredSkill; |
---|
| 305 | data << pProto->RequiredSkillRank; |
---|
| 306 | data << pProto->RequiredSpell; |
---|
| 307 | data << pProto->RequiredHonorRank; |
---|
| 308 | data << pProto->RequiredCityRank; |
---|
| 309 | data << pProto->RequiredReputationFaction; |
---|
| 310 | data << pProto->RequiredReputationRank; |
---|
| 311 | data << pProto->MaxCount; |
---|
| 312 | data << pProto->Stackable; |
---|
| 313 | data << pProto->ContainerSlots; |
---|
| 314 | for(int i = 0; i < 10; i++) |
---|
| 315 | { |
---|
| 316 | data << pProto->ItemStat[i].ItemStatType; |
---|
| 317 | data << pProto->ItemStat[i].ItemStatValue; |
---|
| 318 | } |
---|
| 319 | for(int i = 0; i < 5; i++) |
---|
| 320 | { |
---|
| 321 | data << pProto->Damage[i].DamageMin; |
---|
| 322 | data << pProto->Damage[i].DamageMax; |
---|
| 323 | data << pProto->Damage[i].DamageType; |
---|
| 324 | } |
---|
| 325 | data << pProto->Armor; |
---|
| 326 | data << pProto->HolyRes; |
---|
| 327 | data << pProto->FireRes; |
---|
| 328 | data << pProto->NatureRes; |
---|
| 329 | data << pProto->FrostRes; |
---|
| 330 | data << pProto->ShadowRes; |
---|
| 331 | data << pProto->ArcaneRes; |
---|
| 332 | data << pProto->Delay; |
---|
| 333 | data << pProto->Ammo_type; |
---|
| 334 | |
---|
| 335 | data << (float)pProto->RangedModRange; |
---|
| 336 | for(int s = 0; s < 5; s++) |
---|
| 337 | { |
---|
| 338 | // send DBC data for cooldowns in same way as it used in Spell::SendSpellCooldown |
---|
| 339 | // use `item_template` or if not set then only use spell cooldowns |
---|
| 340 | SpellEntry const* spell = sSpellStore.LookupEntry(pProto->Spells[s].SpellId); |
---|
| 341 | if(spell) |
---|
| 342 | { |
---|
| 343 | bool db_data = pProto->Spells[s].SpellCooldown >= 0 || pProto->Spells[s].SpellCategoryCooldown >= 0; |
---|
| 344 | |
---|
| 345 | data << pProto->Spells[s].SpellId; |
---|
| 346 | data << pProto->Spells[s].SpellTrigger; |
---|
| 347 | data << uint32(-abs(pProto->Spells[s].SpellCharges)); |
---|
| 348 | |
---|
| 349 | if(db_data) |
---|
| 350 | { |
---|
| 351 | data << uint32(pProto->Spells[s].SpellCooldown); |
---|
| 352 | data << uint32(pProto->Spells[s].SpellCategory); |
---|
| 353 | data << uint32(pProto->Spells[s].SpellCategoryCooldown); |
---|
| 354 | } |
---|
| 355 | else |
---|
| 356 | { |
---|
| 357 | data << uint32(spell->RecoveryTime); |
---|
| 358 | data << uint32(spell->Category); |
---|
| 359 | data << uint32(spell->CategoryRecoveryTime); |
---|
| 360 | } |
---|
| 361 | } |
---|
| 362 | else |
---|
| 363 | { |
---|
| 364 | data << uint32(0); |
---|
| 365 | data << uint32(0); |
---|
| 366 | data << uint32(0); |
---|
| 367 | data << uint32(-1); |
---|
| 368 | data << uint32(0); |
---|
| 369 | data << uint32(-1); |
---|
| 370 | } |
---|
| 371 | } |
---|
| 372 | data << pProto->Bonding; |
---|
| 373 | data << Description; |
---|
| 374 | data << pProto->PageText; |
---|
| 375 | data << pProto->LanguageID; |
---|
| 376 | data << pProto->PageMaterial; |
---|
| 377 | data << pProto->StartQuest; |
---|
| 378 | data << pProto->LockID; |
---|
| 379 | data << pProto->Material; |
---|
| 380 | data << pProto->Sheath; |
---|
| 381 | data << pProto->RandomProperty; |
---|
| 382 | data << pProto->RandomSuffix; |
---|
| 383 | data << pProto->Block; |
---|
| 384 | data << pProto->ItemSet; |
---|
| 385 | data << pProto->MaxDurability; |
---|
| 386 | data << pProto->Area; |
---|
| 387 | data << pProto->Map; // Added in 1.12.x & 2.0.1 client branch |
---|
| 388 | data << pProto->BagFamily; |
---|
| 389 | data << pProto->TotemCategory; |
---|
| 390 | for(int s = 0; s < 3; s++) |
---|
| 391 | { |
---|
| 392 | data << pProto->Socket[s].Color; |
---|
| 393 | data << pProto->Socket[s].Content; |
---|
| 394 | } |
---|
| 395 | data << pProto->socketBonus; |
---|
| 396 | data << pProto->GemProperties; |
---|
| 397 | data << pProto->RequiredDisenchantSkill; |
---|
| 398 | data << pProto->ArmorDamageModifier; |
---|
| 399 | data << uint32(0); // added in 2.4.2.8209, duration (seconds) |
---|
| 400 | SendPacket( &data ); |
---|
| 401 | } |
---|
| 402 | else |
---|
| 403 | { |
---|
| 404 | sLog.outDebug( "WORLD: CMSG_ITEM_QUERY_SINGLE - NO item INFO! (ENTRY: %u)", item ); |
---|
| 405 | WorldPacket data( SMSG_ITEM_QUERY_SINGLE_RESPONSE, 4); |
---|
| 406 | data << uint32(item | 0x80000000); |
---|
| 407 | SendPacket( &data ); |
---|
| 408 | } |
---|
| 409 | } |
---|
| 410 | |
---|
| 411 | void WorldSession::HandleReadItem( WorldPacket & recv_data ) |
---|
| 412 | { |
---|
| 413 | CHECK_PACKET_SIZE(recv_data,1+1); |
---|
| 414 | |
---|
| 415 | //sLog.outDebug( "WORLD: CMSG_READ_ITEM"); |
---|
| 416 | |
---|
| 417 | uint8 bag, slot; |
---|
| 418 | recv_data >> bag >> slot; |
---|
| 419 | |
---|
| 420 | //sLog.outDetail("STORAGE: Read bag = %u, slot = %u", bag, slot); |
---|
| 421 | Item *pItem = _player->GetItemByPos( bag, slot ); |
---|
| 422 | |
---|
| 423 | if( pItem && pItem->GetProto()->PageText ) |
---|
| 424 | { |
---|
| 425 | WorldPacket data; |
---|
| 426 | |
---|
| 427 | uint8 msg = _player->CanUseItem( pItem ); |
---|
| 428 | if( msg == EQUIP_ERR_OK ) |
---|
| 429 | { |
---|
| 430 | data.Initialize (SMSG_READ_ITEM_OK, 8); |
---|
| 431 | sLog.outDetail("STORAGE: Item page sent"); |
---|
| 432 | } |
---|
| 433 | else |
---|
| 434 | { |
---|
| 435 | data.Initialize( SMSG_READ_ITEM_FAILED, 8 ); |
---|
| 436 | sLog.outDetail("STORAGE: Unable to read item"); |
---|
| 437 | _player->SendEquipError( msg, pItem, NULL ); |
---|
| 438 | } |
---|
| 439 | data << pItem->GetGUID(); |
---|
| 440 | SendPacket(&data); |
---|
| 441 | } |
---|
| 442 | else |
---|
| 443 | _player->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL ); |
---|
| 444 | } |
---|
| 445 | |
---|
| 446 | void WorldSession::HandlePageQuerySkippedOpcode( WorldPacket & recv_data ) |
---|
| 447 | { |
---|
| 448 | CHECK_PACKET_SIZE(recv_data,4+8); |
---|
| 449 | |
---|
| 450 | sLog.outDebug( "WORLD: Received CMSG_PAGE_TEXT_QUERY" ); |
---|
| 451 | |
---|
| 452 | uint32 itemid; |
---|
| 453 | uint64 guid; |
---|
| 454 | |
---|
| 455 | recv_data >> itemid >> guid; |
---|
| 456 | |
---|
| 457 | sLog.outDetail( "Packet Info: itemid: %u guidlow: %u guidentry: %u guidhigh: %u", |
---|
| 458 | itemid, GUID_LOPART(guid), GUID_ENPART(guid), GUID_HIPART(guid)); |
---|
| 459 | } |
---|
| 460 | |
---|
| 461 | void WorldSession::HandleSellItemOpcode( WorldPacket & recv_data ) |
---|
| 462 | { |
---|
| 463 | CHECK_PACKET_SIZE(recv_data,8+8+1); |
---|
| 464 | |
---|
| 465 | sLog.outDebug( "WORLD: Received CMSG_SELL_ITEM" ); |
---|
| 466 | uint64 vendorguid, itemguid; |
---|
| 467 | uint8 _count; |
---|
| 468 | |
---|
| 469 | recv_data >> vendorguid >> itemguid >> _count; |
---|
| 470 | |
---|
| 471 | // prevent possible overflow, as mangos uses uint32 for item count |
---|
| 472 | uint32 count = _count; |
---|
| 473 | |
---|
| 474 | if(!itemguid) |
---|
| 475 | return; |
---|
| 476 | |
---|
| 477 | Creature *pCreature = ObjectAccessor::GetNPCIfCanInteractWith(*_player, vendorguid,UNIT_NPC_FLAG_VENDOR); |
---|
| 478 | if (!pCreature) |
---|
| 479 | { |
---|
| 480 | sLog.outDebug( "WORLD: HandleSellItemOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(vendorguid)) ); |
---|
| 481 | _player->SendSellError( SELL_ERR_CANT_FIND_VENDOR, NULL, itemguid, 0); |
---|
| 482 | return; |
---|
| 483 | } |
---|
| 484 | |
---|
| 485 | // remove fake death |
---|
| 486 | if(GetPlayer()->hasUnitState(UNIT_STAT_DIED)) |
---|
| 487 | GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); |
---|
| 488 | |
---|
| 489 | Item *pItem = _player->GetItemByGuid( itemguid ); |
---|
| 490 | if( pItem ) |
---|
| 491 | { |
---|
| 492 | // prevent sell not owner item |
---|
| 493 | if(_player->GetGUID()!=pItem->GetOwnerGUID()) |
---|
| 494 | { |
---|
| 495 | _player->SendSellError( SELL_ERR_CANT_SELL_ITEM, pCreature, itemguid, 0); |
---|
| 496 | return; |
---|
| 497 | } |
---|
| 498 | |
---|
| 499 | // prevent sell non empty bag by drag-and-drop at vendor's item list |
---|
| 500 | if(pItem->IsBag() && !((Bag*)pItem)->IsEmpty()) |
---|
| 501 | { |
---|
| 502 | _player->SendSellError( SELL_ERR_CANT_SELL_ITEM, pCreature, itemguid, 0); |
---|
| 503 | return; |
---|
| 504 | } |
---|
| 505 | |
---|
| 506 | // prevent sell currently looted item |
---|
| 507 | if(_player->GetLootGUID()==pItem->GetGUID()) |
---|
| 508 | { |
---|
| 509 | _player->SendSellError( SELL_ERR_CANT_SELL_ITEM, pCreature, itemguid, 0); |
---|
| 510 | return; |
---|
| 511 | } |
---|
| 512 | |
---|
| 513 | // special case at auto sell (sell all) |
---|
| 514 | if(count==0) |
---|
| 515 | { |
---|
| 516 | count = pItem->GetCount(); |
---|
| 517 | } |
---|
| 518 | else |
---|
| 519 | { |
---|
| 520 | // prevent sell more items that exist in stack (possable only not from client) |
---|
| 521 | if(count > pItem->GetCount()) |
---|
| 522 | { |
---|
| 523 | _player->SendSellError( SELL_ERR_CANT_SELL_ITEM, pCreature, itemguid, 0); |
---|
| 524 | return; |
---|
| 525 | } |
---|
| 526 | } |
---|
| 527 | |
---|
| 528 | ItemPrototype const *pProto = pItem->GetProto(); |
---|
| 529 | if( pProto ) |
---|
| 530 | { |
---|
| 531 | if( pProto->SellPrice > 0 ) |
---|
| 532 | { |
---|
| 533 | if(count < pItem->GetCount()) // need split items |
---|
| 534 | { |
---|
| 535 | Item *pNewItem = pItem->CloneItem( count, _player ); |
---|
| 536 | if (!pNewItem) |
---|
| 537 | { |
---|
| 538 | sLog.outError("WORLD: HandleSellItemOpcode - could not create clone of item %u; count = %u", pItem->GetEntry(), count ); |
---|
| 539 | _player->SendSellError( SELL_ERR_CANT_SELL_ITEM, pCreature, itemguid, 0); |
---|
| 540 | return; |
---|
| 541 | } |
---|
| 542 | |
---|
| 543 | pItem->SetCount( pItem->GetCount() - count ); |
---|
| 544 | _player->ItemRemovedQuestCheck( pItem->GetEntry(), count ); |
---|
| 545 | if( _player->IsInWorld() ) |
---|
| 546 | pItem->SendUpdateToPlayer( _player ); |
---|
| 547 | pItem->SetState(ITEM_CHANGED, _player); |
---|
| 548 | |
---|
| 549 | _player->AddItemToBuyBackSlot( pNewItem ); |
---|
| 550 | if( _player->IsInWorld() ) |
---|
| 551 | pNewItem->SendUpdateToPlayer( _player ); |
---|
| 552 | } |
---|
| 553 | else |
---|
| 554 | { |
---|
| 555 | _player->ItemRemovedQuestCheck( pItem->GetEntry(), pItem->GetCount()); |
---|
| 556 | _player->RemoveItem( pItem->GetBagSlot(), pItem->GetSlot(), true); |
---|
| 557 | pItem->RemoveFromUpdateQueueOf(_player); |
---|
| 558 | _player->AddItemToBuyBackSlot( pItem ); |
---|
| 559 | } |
---|
| 560 | |
---|
| 561 | _player->ModifyMoney( pProto->SellPrice * count ); |
---|
| 562 | } |
---|
| 563 | else |
---|
| 564 | _player->SendSellError( SELL_ERR_CANT_SELL_ITEM, pCreature, itemguid, 0); |
---|
| 565 | return; |
---|
| 566 | } |
---|
| 567 | } |
---|
| 568 | _player->SendSellError( SELL_ERR_CANT_FIND_ITEM, pCreature, itemguid, 0); |
---|
| 569 | return; |
---|
| 570 | } |
---|
| 571 | |
---|
| 572 | void WorldSession::HandleBuybackItem(WorldPacket & recv_data) |
---|
| 573 | { |
---|
| 574 | CHECK_PACKET_SIZE(recv_data,8+4); |
---|
| 575 | |
---|
| 576 | sLog.outDebug( "WORLD: Received CMSG_BUYBACK_ITEM" ); |
---|
| 577 | uint64 vendorguid; |
---|
| 578 | uint32 slot; |
---|
| 579 | |
---|
| 580 | recv_data >> vendorguid >> slot; |
---|
| 581 | |
---|
| 582 | Creature *pCreature = ObjectAccessor::GetNPCIfCanInteractWith(*_player, vendorguid,UNIT_NPC_FLAG_VENDOR); |
---|
| 583 | if (!pCreature) |
---|
| 584 | { |
---|
| 585 | sLog.outDebug( "WORLD: HandleBuybackItem - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(vendorguid)) ); |
---|
| 586 | _player->SendSellError( SELL_ERR_CANT_FIND_VENDOR, NULL, 0, 0); |
---|
| 587 | return; |
---|
| 588 | } |
---|
| 589 | |
---|
| 590 | // remove fake death |
---|
| 591 | if(GetPlayer()->hasUnitState(UNIT_STAT_DIED)) |
---|
| 592 | GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); |
---|
| 593 | |
---|
| 594 | Item *pItem = _player->GetItemFromBuyBackSlot( slot ); |
---|
| 595 | if( pItem ) |
---|
| 596 | { |
---|
| 597 | uint32 price = _player->GetUInt32Value( PLAYER_FIELD_BUYBACK_PRICE_1 + slot - BUYBACK_SLOT_START ); |
---|
| 598 | if( _player->GetMoney() < price ) |
---|
| 599 | { |
---|
| 600 | _player->SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, pCreature, pItem->GetEntry(), 0); |
---|
| 601 | return; |
---|
| 602 | } |
---|
| 603 | |
---|
| 604 | ItemPosCountVec dest; |
---|
| 605 | uint8 msg = _player->CanStoreItem( NULL_BAG, NULL_SLOT, dest, pItem, false ); |
---|
| 606 | if( msg == EQUIP_ERR_OK ) |
---|
| 607 | { |
---|
| 608 | _player->ModifyMoney( -(int32)price ); |
---|
| 609 | _player->RemoveItemFromBuyBackSlot( slot, false ); |
---|
| 610 | _player->ItemAddedQuestCheck( pItem->GetEntry(), pItem->GetCount()); |
---|
| 611 | _player->StoreItem( dest, pItem, true ); |
---|
| 612 | } |
---|
| 613 | else |
---|
| 614 | _player->SendEquipError( msg, pItem, NULL ); |
---|
| 615 | return; |
---|
| 616 | } |
---|
| 617 | else |
---|
| 618 | _player->SendBuyError( BUY_ERR_CANT_FIND_ITEM, pCreature, 0, 0); |
---|
| 619 | } |
---|
| 620 | |
---|
| 621 | void WorldSession::HandleBuyItemInSlotOpcode( WorldPacket & recv_data ) |
---|
| 622 | { |
---|
| 623 | CHECK_PACKET_SIZE(recv_data,8+4+8+1+1); |
---|
| 624 | |
---|
| 625 | sLog.outDebug( "WORLD: Received CMSG_BUY_ITEM_IN_SLOT" ); |
---|
| 626 | uint64 vendorguid, bagguid; |
---|
| 627 | uint32 item; |
---|
| 628 | uint8 slot, count; |
---|
| 629 | |
---|
| 630 | recv_data >> vendorguid >> item >> bagguid >> slot >> count; |
---|
| 631 | |
---|
| 632 | GetPlayer()->BuyItemFromVendor(vendorguid,item,count,bagguid,slot); |
---|
| 633 | } |
---|
| 634 | |
---|
| 635 | void WorldSession::HandleBuyItemOpcode( WorldPacket & recv_data ) |
---|
| 636 | { |
---|
| 637 | CHECK_PACKET_SIZE(recv_data,8+4+1+1); |
---|
| 638 | |
---|
| 639 | sLog.outDebug( "WORLD: Received CMSG_BUY_ITEM" ); |
---|
| 640 | uint64 vendorguid; |
---|
| 641 | uint32 item; |
---|
| 642 | uint8 count, unk1; |
---|
| 643 | |
---|
| 644 | recv_data >> vendorguid >> item >> count >> unk1; |
---|
| 645 | |
---|
| 646 | GetPlayer()->BuyItemFromVendor(vendorguid,item,count,NULL_BAG,NULL_SLOT); |
---|
| 647 | } |
---|
| 648 | |
---|
| 649 | void WorldSession::HandleListInventoryOpcode( WorldPacket & recv_data ) |
---|
| 650 | { |
---|
| 651 | CHECK_PACKET_SIZE(recv_data,8); |
---|
| 652 | |
---|
| 653 | uint64 guid; |
---|
| 654 | |
---|
| 655 | recv_data >> guid; |
---|
| 656 | |
---|
| 657 | if(!GetPlayer()->isAlive()) |
---|
| 658 | return; |
---|
| 659 | |
---|
| 660 | sLog.outDebug( "WORLD: Recvd CMSG_LIST_INVENTORY" ); |
---|
| 661 | |
---|
| 662 | SendListInventory( guid ); |
---|
| 663 | } |
---|
| 664 | |
---|
| 665 | void WorldSession::SendListInventory( uint64 vendorguid ) |
---|
| 666 | { |
---|
| 667 | sLog.outDebug( "WORLD: Sent SMSG_LIST_INVENTORY" ); |
---|
| 668 | |
---|
| 669 | Creature *pCreature = ObjectAccessor::GetNPCIfCanInteractWith(*_player, vendorguid,UNIT_NPC_FLAG_VENDOR); |
---|
| 670 | if (!pCreature) |
---|
| 671 | { |
---|
| 672 | sLog.outDebug( "WORLD: SendListInventory - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(vendorguid)) ); |
---|
| 673 | _player->SendSellError( SELL_ERR_CANT_FIND_VENDOR, NULL, 0, 0); |
---|
| 674 | return; |
---|
| 675 | } |
---|
| 676 | |
---|
| 677 | // remove fake death |
---|
| 678 | if(GetPlayer()->hasUnitState(UNIT_STAT_DIED)) |
---|
| 679 | GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); |
---|
| 680 | |
---|
| 681 | // Stop the npc if moving |
---|
| 682 | pCreature->StopMoving(); |
---|
| 683 | // load vendor items if not yet |
---|
| 684 | pCreature->LoadGoods(); |
---|
| 685 | |
---|
| 686 | uint8 numitems = pCreature->GetItemCount(); |
---|
| 687 | uint8 count = 0; |
---|
| 688 | uint32 ptime = time(NULL); |
---|
| 689 | uint32 diff; |
---|
| 690 | |
---|
| 691 | WorldPacket data( SMSG_LIST_INVENTORY, (8+1+numitems*8*4) ); |
---|
| 692 | data << uint64(vendorguid); |
---|
| 693 | data << uint8(numitems); |
---|
| 694 | |
---|
| 695 | float discountMod = _player->GetReputationPriceDiscount(pCreature); |
---|
| 696 | |
---|
| 697 | ItemPrototype const *pProto; |
---|
| 698 | for(int i = 0; i < numitems; i++ ) |
---|
| 699 | { |
---|
| 700 | CreatureItem* crItem = pCreature->GetItem(i); |
---|
| 701 | if( crItem ) |
---|
| 702 | { |
---|
| 703 | pProto = objmgr.GetItemPrototype(crItem->id); |
---|
| 704 | if( pProto ) |
---|
| 705 | { |
---|
| 706 | if((pProto->AllowableClass & _player->getClassMask()) == 0 && pProto->Bonding == BIND_WHEN_PICKED_UP && !_player->isGameMaster()) |
---|
| 707 | continue; |
---|
| 708 | ++count; |
---|
| 709 | if( crItem->incrtime != 0 && (crItem->lastincr + crItem->incrtime <= ptime) ) |
---|
| 710 | { |
---|
| 711 | diff = uint32((ptime - crItem->lastincr)/crItem->incrtime); |
---|
| 712 | if( (crItem->count + diff * pProto->BuyCount) <= crItem->maxcount ) |
---|
| 713 | crItem->count += diff * pProto->BuyCount; |
---|
| 714 | else |
---|
| 715 | crItem->count = crItem->maxcount; |
---|
| 716 | crItem->lastincr = ptime; |
---|
| 717 | } |
---|
| 718 | data << uint32(count); |
---|
| 719 | data << uint32(crItem->id); |
---|
| 720 | data << uint32(pProto->DisplayInfoID); |
---|
| 721 | data << uint32(crItem->maxcount <= 0 ? 0xFFFFFFFF : crItem->count); |
---|
| 722 | |
---|
| 723 | uint32 price = pProto->BuyPrice; |
---|
| 724 | |
---|
| 725 | // reputation discount |
---|
| 726 | price = uint32(floor(pProto->BuyPrice * discountMod)); |
---|
| 727 | |
---|
| 728 | data << uint32(price); |
---|
| 729 | data << uint32(pProto->MaxDurability); |
---|
| 730 | data << uint32(pProto->BuyCount); |
---|
| 731 | data << uint32(crItem->ExtendedCost); |
---|
| 732 | } |
---|
| 733 | } |
---|
| 734 | } |
---|
| 735 | |
---|
| 736 | if ( count == 0 || data.size() != 8 + 1 + size_t(count) * 8 * 4 ) |
---|
| 737 | return; |
---|
| 738 | |
---|
| 739 | data.put<uint8>(8, count); |
---|
| 740 | SendPacket( &data ); |
---|
| 741 | } |
---|
| 742 | |
---|
| 743 | void WorldSession::HandleAutoStoreBagItemOpcode( WorldPacket & recv_data ) |
---|
| 744 | { |
---|
| 745 | CHECK_PACKET_SIZE(recv_data,1+1+1); |
---|
| 746 | |
---|
| 747 | //sLog.outDebug("WORLD: CMSG_AUTOSTORE_BAG_ITEM"); |
---|
| 748 | uint8 srcbag, srcslot, dstbag; |
---|
| 749 | |
---|
| 750 | recv_data >> srcbag >> srcslot >> dstbag; |
---|
| 751 | //sLog.outDebug("STORAGE: receive srcbag = %u, srcslot = %u, dstbag = %u", srcbag, srcslot, dstbag); |
---|
| 752 | |
---|
| 753 | Item *pItem = _player->GetItemByPos( srcbag, srcslot ); |
---|
| 754 | if( !pItem ) |
---|
| 755 | return; |
---|
| 756 | |
---|
| 757 | uint16 src = pItem->GetPos(); |
---|
| 758 | |
---|
| 759 | // check unequip potability for equipped items and bank bags |
---|
| 760 | if(_player->IsEquipmentPos ( src ) || _player->IsBagPos ( src )) |
---|
| 761 | { |
---|
| 762 | uint8 msg = _player->CanUnequipItem( src, !_player->IsBagPos ( src )); |
---|
| 763 | if(msg != EQUIP_ERR_OK) |
---|
| 764 | { |
---|
| 765 | _player->SendEquipError( msg, pItem, NULL ); |
---|
| 766 | return; |
---|
| 767 | } |
---|
| 768 | } |
---|
| 769 | |
---|
| 770 | ItemPosCountVec dest; |
---|
| 771 | uint8 msg = _player->CanStoreItem( dstbag, NULL_SLOT, dest, pItem, false ); |
---|
| 772 | if( msg != EQUIP_ERR_OK ) |
---|
| 773 | { |
---|
| 774 | _player->SendEquipError( msg, pItem, NULL ); |
---|
| 775 | return; |
---|
| 776 | } |
---|
| 777 | |
---|
| 778 | // no-op: placed in same slot |
---|
| 779 | if(dest.size()==1 && dest[0].pos==src) |
---|
| 780 | { |
---|
| 781 | // just remove grey item state |
---|
| 782 | _player->SendEquipError( EQUIP_ERR_NONE, pItem, NULL ); |
---|
| 783 | return; |
---|
| 784 | } |
---|
| 785 | |
---|
| 786 | _player->RemoveItem(srcbag, srcslot, true ); |
---|
| 787 | _player->StoreItem( dest, pItem, true ); |
---|
| 788 | } |
---|
| 789 | |
---|
| 790 | void WorldSession::HandleBuyBankSlotOpcode(WorldPacket& /*recvPacket*/) |
---|
| 791 | { |
---|
| 792 | sLog.outDebug("WORLD: CMSG_BUY_BANK_SLOT"); |
---|
| 793 | |
---|
| 794 | uint32 slot = _player->GetByteValue(PLAYER_BYTES_2, 2); |
---|
| 795 | |
---|
| 796 | // next slot |
---|
| 797 | ++slot; |
---|
| 798 | |
---|
| 799 | sLog.outDetail("PLAYER: Buy bank bag slot, slot number = %u", slot); |
---|
| 800 | |
---|
| 801 | BankBagSlotPricesEntry const* slotEntry = sBankBagSlotPricesStore.LookupEntry(slot); |
---|
| 802 | |
---|
| 803 | if(!slotEntry) |
---|
| 804 | return; |
---|
| 805 | |
---|
| 806 | uint32 price = slotEntry->price; |
---|
| 807 | |
---|
| 808 | if (_player->GetMoney() < price) |
---|
| 809 | return; |
---|
| 810 | |
---|
| 811 | _player->SetByteValue(PLAYER_BYTES_2, 2, slot); |
---|
| 812 | _player->ModifyMoney(-int32(price)); |
---|
| 813 | } |
---|
| 814 | |
---|
| 815 | void WorldSession::HandleAutoBankItemOpcode(WorldPacket& recvPacket) |
---|
| 816 | { |
---|
| 817 | CHECK_PACKET_SIZE(recvPacket,1+1); |
---|
| 818 | |
---|
| 819 | sLog.outDebug("WORLD: CMSG_AUTOBANK_ITEM"); |
---|
| 820 | uint8 srcbag, srcslot; |
---|
| 821 | |
---|
| 822 | recvPacket >> srcbag >> srcslot; |
---|
| 823 | sLog.outDebug("STORAGE: receive srcbag = %u, srcslot = %u", srcbag, srcslot); |
---|
| 824 | |
---|
| 825 | Item *pItem = _player->GetItemByPos( srcbag, srcslot ); |
---|
| 826 | if( !pItem ) |
---|
| 827 | return; |
---|
| 828 | |
---|
| 829 | ItemPosCountVec dest; |
---|
| 830 | uint8 msg = _player->CanBankItem( NULL_BAG, NULL_SLOT, dest, pItem, false ); |
---|
| 831 | if( msg != EQUIP_ERR_OK ) |
---|
| 832 | { |
---|
| 833 | _player->SendEquipError( msg, pItem, NULL ); |
---|
| 834 | return; |
---|
| 835 | } |
---|
| 836 | |
---|
| 837 | _player->RemoveItem(srcbag, srcslot, true); |
---|
| 838 | _player->BankItem( dest, pItem, true ); |
---|
| 839 | } |
---|
| 840 | |
---|
| 841 | void WorldSession::HandleAutoStoreBankItemOpcode(WorldPacket& recvPacket) |
---|
| 842 | { |
---|
| 843 | CHECK_PACKET_SIZE(recvPacket,1+1); |
---|
| 844 | |
---|
| 845 | sLog.outDebug("WORLD: CMSG_AUTOSTORE_BANK_ITEM"); |
---|
| 846 | uint8 srcbag, srcslot; |
---|
| 847 | |
---|
| 848 | recvPacket >> srcbag >> srcslot; |
---|
| 849 | sLog.outDebug("STORAGE: receive srcbag = %u, srcslot = %u", srcbag, srcslot); |
---|
| 850 | |
---|
| 851 | Item *pItem = _player->GetItemByPos( srcbag, srcslot ); |
---|
| 852 | if( !pItem ) |
---|
| 853 | return; |
---|
| 854 | |
---|
| 855 | if(_player->IsBankPos(srcbag, srcslot)) // moving from bank to inventory |
---|
| 856 | { |
---|
| 857 | ItemPosCountVec dest; |
---|
| 858 | uint8 msg = _player->CanStoreItem( NULL_BAG, NULL_SLOT, dest, pItem, false ); |
---|
| 859 | if( msg != EQUIP_ERR_OK ) |
---|
| 860 | { |
---|
| 861 | _player->SendEquipError( msg, pItem, NULL ); |
---|
| 862 | return; |
---|
| 863 | } |
---|
| 864 | |
---|
| 865 | _player->RemoveItem(srcbag, srcslot, true); |
---|
| 866 | _player->StoreItem( dest, pItem, true ); |
---|
| 867 | } |
---|
| 868 | else // moving from inventory to bank |
---|
| 869 | { |
---|
| 870 | ItemPosCountVec dest; |
---|
| 871 | uint8 msg = _player->CanBankItem( NULL_BAG, NULL_SLOT, dest, pItem, false ); |
---|
| 872 | if( msg != EQUIP_ERR_OK ) |
---|
| 873 | { |
---|
| 874 | _player->SendEquipError( msg, pItem, NULL ); |
---|
| 875 | return; |
---|
| 876 | } |
---|
| 877 | |
---|
| 878 | _player->RemoveItem(srcbag, srcslot, true); |
---|
| 879 | _player->BankItem( dest, pItem, true ); |
---|
| 880 | } |
---|
| 881 | } |
---|
| 882 | |
---|
| 883 | void WorldSession::HandleSetAmmoOpcode(WorldPacket & recv_data) |
---|
| 884 | { |
---|
| 885 | CHECK_PACKET_SIZE(recv_data,4); |
---|
| 886 | |
---|
| 887 | if(!GetPlayer()->isAlive()) |
---|
| 888 | { |
---|
| 889 | GetPlayer()->SendEquipError( EQUIP_ERR_YOU_ARE_DEAD, NULL, NULL ); |
---|
| 890 | return; |
---|
| 891 | } |
---|
| 892 | |
---|
| 893 | sLog.outDebug("WORLD: CMSG_SET_AMMO"); |
---|
| 894 | uint32 item; |
---|
| 895 | |
---|
| 896 | recv_data >> item; |
---|
| 897 | |
---|
| 898 | if(!item) |
---|
| 899 | GetPlayer()->RemoveAmmo(); |
---|
| 900 | else |
---|
| 901 | GetPlayer()->SetAmmo(item); |
---|
| 902 | } |
---|
| 903 | |
---|
| 904 | void WorldSession::SendEnchantmentLog(uint64 Target, uint64 Caster,uint32 ItemID,uint32 SpellID) |
---|
| 905 | { |
---|
| 906 | WorldPacket data(SMSG_ENCHANTMENTLOG, (8+8+4+4+1)); // last check 2.0.10 |
---|
| 907 | data << Target; |
---|
| 908 | data << Caster; |
---|
| 909 | data << ItemID; |
---|
| 910 | data << SpellID; |
---|
| 911 | data << uint8(0); |
---|
| 912 | SendPacket(&data); |
---|
| 913 | } |
---|
| 914 | |
---|
| 915 | void WorldSession::SendItemEnchantTimeUpdate(uint64 Playerguid, uint64 Itemguid,uint32 slot,uint32 Duration) |
---|
| 916 | { |
---|
| 917 | // last check 2.0.10 |
---|
| 918 | WorldPacket data(SMSG_ITEM_ENCHANT_TIME_UPDATE, (8+4+4+8)); |
---|
| 919 | data << uint64(Itemguid); |
---|
| 920 | data << uint32(slot); |
---|
| 921 | data << uint32(Duration); |
---|
| 922 | data << uint64(Playerguid); |
---|
| 923 | SendPacket(&data); |
---|
| 924 | } |
---|
| 925 | |
---|
| 926 | void WorldSession::HandleItemNameQueryOpcode(WorldPacket & recv_data) |
---|
| 927 | { |
---|
| 928 | CHECK_PACKET_SIZE(recv_data,4); |
---|
| 929 | |
---|
| 930 | uint32 itemid; |
---|
| 931 | recv_data >> itemid; |
---|
| 932 | sLog.outDebug("WORLD: CMSG_ITEM_NAME_QUERY %u", itemid); |
---|
| 933 | ItemPrototype const *pProto = objmgr.GetItemPrototype( itemid ); |
---|
| 934 | if( pProto ) |
---|
| 935 | { |
---|
| 936 | std::string Name; |
---|
| 937 | Name = pProto->Name1; |
---|
| 938 | |
---|
| 939 | int loc_idx = GetSessionDbLocaleIndex(); |
---|
| 940 | if (loc_idx >= 0) |
---|
| 941 | { |
---|
| 942 | ItemLocale const *il = objmgr.GetItemLocale(pProto->ItemId); |
---|
| 943 | if (il) |
---|
| 944 | { |
---|
| 945 | if (il->Name.size() > loc_idx && !il->Name[loc_idx].empty()) |
---|
| 946 | Name = il->Name[loc_idx]; |
---|
| 947 | } |
---|
| 948 | } |
---|
| 949 | // guess size |
---|
| 950 | WorldPacket data(SMSG_ITEM_NAME_QUERY_RESPONSE, (4+10)); |
---|
| 951 | data << uint32(pProto->ItemId); |
---|
| 952 | data << Name; |
---|
| 953 | data << uint32(pProto->InventoryType); |
---|
| 954 | SendPacket(&data); |
---|
| 955 | return; |
---|
| 956 | } |
---|
| 957 | else |
---|
| 958 | sLog.outDebug("WORLD: CMSG_ITEM_NAME_QUERY for item %u failed (unknown item)", itemid); |
---|
| 959 | } |
---|
| 960 | |
---|
| 961 | void WorldSession::HandleWrapItemOpcode(WorldPacket& recv_data) |
---|
| 962 | { |
---|
| 963 | CHECK_PACKET_SIZE(recv_data,1+1+1+1); |
---|
| 964 | |
---|
| 965 | sLog.outDebug("Received opcode CMSG_WRAP_ITEM"); |
---|
| 966 | |
---|
| 967 | uint8 gift_bag, gift_slot, item_bag, item_slot; |
---|
| 968 | //recv_data.hexlike(); |
---|
| 969 | |
---|
| 970 | recv_data >> gift_bag >> gift_slot; // paper |
---|
| 971 | recv_data >> item_bag >> item_slot; // item |
---|
| 972 | |
---|
| 973 | sLog.outDebug("WRAP: receive gift_bag = %u, gift_slot = %u, item_bag = %u, item_slot = %u", gift_bag, gift_slot, item_bag, item_slot); |
---|
| 974 | |
---|
| 975 | Item *gift = _player->GetItemByPos( gift_bag, gift_slot ); |
---|
| 976 | if(!gift) |
---|
| 977 | { |
---|
| 978 | _player->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, gift, NULL ); |
---|
| 979 | return; |
---|
| 980 | } |
---|
| 981 | |
---|
| 982 | if(!gift->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_WRAPPER))// cheating: non-wrapper wrapper |
---|
| 983 | { |
---|
| 984 | _player->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, gift, NULL ); |
---|
| 985 | return; |
---|
| 986 | } |
---|
| 987 | |
---|
| 988 | Item *item = _player->GetItemByPos( item_bag, item_slot ); |
---|
| 989 | |
---|
| 990 | if( !item ) |
---|
| 991 | { |
---|
| 992 | _player->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, item, NULL ); |
---|
| 993 | return; |
---|
| 994 | } |
---|
| 995 | |
---|
| 996 | if(item==gift) // not possable with pacjket from real client |
---|
| 997 | { |
---|
| 998 | _player->SendEquipError( EQUIP_ERR_WRAPPED_CANT_BE_WRAPPED, item, NULL ); |
---|
| 999 | return; |
---|
| 1000 | } |
---|
| 1001 | |
---|
| 1002 | if(item->IsEquipped()) |
---|
| 1003 | { |
---|
| 1004 | _player->SendEquipError( EQUIP_ERR_EQUIPPED_CANT_BE_WRAPPED, item, NULL ); |
---|
| 1005 | return; |
---|
| 1006 | } |
---|
| 1007 | |
---|
| 1008 | if(item->GetUInt64Value(ITEM_FIELD_GIFTCREATOR)) // HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_WRAPPED); |
---|
| 1009 | { |
---|
| 1010 | _player->SendEquipError( EQUIP_ERR_WRAPPED_CANT_BE_WRAPPED, item, NULL ); |
---|
| 1011 | return; |
---|
| 1012 | } |
---|
| 1013 | |
---|
| 1014 | if(item->IsBag()) |
---|
| 1015 | { |
---|
| 1016 | _player->SendEquipError( EQUIP_ERR_BAGS_CANT_BE_WRAPPED, item, NULL ); |
---|
| 1017 | return; |
---|
| 1018 | } |
---|
| 1019 | |
---|
| 1020 | if(item->IsSoulBound()) |
---|
| 1021 | { |
---|
| 1022 | _player->SendEquipError( EQUIP_ERR_BOUND_CANT_BE_WRAPPED, item, NULL ); |
---|
| 1023 | return; |
---|
| 1024 | } |
---|
| 1025 | |
---|
| 1026 | if(item->GetMaxStackCount() != 1) |
---|
| 1027 | { |
---|
| 1028 | _player->SendEquipError( EQUIP_ERR_STACKABLE_CANT_BE_WRAPPED, item, NULL ); |
---|
| 1029 | return; |
---|
| 1030 | } |
---|
| 1031 | |
---|
| 1032 | // maybe not correct check (it is better than nothing) |
---|
| 1033 | if(item->GetProto()->MaxCount>0) |
---|
| 1034 | { |
---|
| 1035 | _player->SendEquipError( EQUIP_ERR_UNIQUE_CANT_BE_WRAPPED, item, NULL ); |
---|
| 1036 | return; |
---|
| 1037 | } |
---|
| 1038 | |
---|
| 1039 | CharacterDatabase.BeginTransaction(); |
---|
| 1040 | CharacterDatabase.PExecute("INSERT INTO character_gifts VALUES ('%u', '%u', '%u', '%u')", GUID_LOPART(item->GetOwnerGUID()), item->GetGUIDLow(), item->GetEntry(), item->GetUInt32Value(ITEM_FIELD_FLAGS)); |
---|
| 1041 | item->SetUInt32Value(OBJECT_FIELD_ENTRY, gift->GetUInt32Value(OBJECT_FIELD_ENTRY)); |
---|
| 1042 | |
---|
| 1043 | switch (item->GetEntry()) |
---|
| 1044 | { |
---|
| 1045 | case 5042: item->SetUInt32Value(OBJECT_FIELD_ENTRY, 5043); break; |
---|
| 1046 | case 5048: item->SetUInt32Value(OBJECT_FIELD_ENTRY, 5044); break; |
---|
| 1047 | case 17303: item->SetUInt32Value(OBJECT_FIELD_ENTRY, 17302); break; |
---|
| 1048 | case 17304: item->SetUInt32Value(OBJECT_FIELD_ENTRY, 17305); break; |
---|
| 1049 | case 17307: item->SetUInt32Value(OBJECT_FIELD_ENTRY, 17308); break; |
---|
| 1050 | case 21830: item->SetUInt32Value(OBJECT_FIELD_ENTRY, 21831); break; |
---|
| 1051 | } |
---|
| 1052 | item->SetUInt64Value(ITEM_FIELD_GIFTCREATOR, _player->GetGUID()); |
---|
| 1053 | item->SetUInt32Value(ITEM_FIELD_FLAGS, ITEM_FLAGS_WRAPPED); |
---|
| 1054 | item->SetState(ITEM_CHANGED, _player); |
---|
| 1055 | |
---|
| 1056 | if(item->GetState()==ITEM_NEW) // save new item, to have alway for `character_gifts` record in `item_instance` |
---|
| 1057 | { |
---|
| 1058 | // after save it will be impossible to remove the item from the queue |
---|
| 1059 | item->RemoveFromUpdateQueueOf(_player); |
---|
| 1060 | item->SaveToDB(); // item gave inventory record unchanged and can be save standalone |
---|
| 1061 | } |
---|
| 1062 | CharacterDatabase.CommitTransaction(); |
---|
| 1063 | |
---|
| 1064 | uint32 count = 1; |
---|
| 1065 | _player->DestroyItemCount(gift, count, true); |
---|
| 1066 | } |
---|
| 1067 | |
---|
| 1068 | void WorldSession::HandleSocketOpcode(WorldPacket& recv_data) |
---|
| 1069 | { |
---|
| 1070 | sLog.outDebug("WORLD: CMSG_SOCKET_GEMS"); |
---|
| 1071 | |
---|
| 1072 | CHECK_PACKET_SIZE(recv_data,8*4); |
---|
| 1073 | |
---|
| 1074 | uint64 guids[4]; |
---|
| 1075 | uint32 GemEnchants[3], OldEnchants[3]; |
---|
| 1076 | Item *Gems[3]; |
---|
| 1077 | bool SocketBonusActivated, SocketBonusToBeActivated; |
---|
| 1078 | |
---|
| 1079 | for(int i = 0; i < 4; i++) |
---|
| 1080 | recv_data >> guids[i]; |
---|
| 1081 | |
---|
| 1082 | if(!guids[0]) |
---|
| 1083 | return; |
---|
| 1084 | |
---|
| 1085 | //cheat -> tried to socket same gem multiple times |
---|
| 1086 | if((guids[1] && (guids[1] == guids[2] || guids[1] == guids[3])) || (guids[2] && (guids[2] == guids[3]))) |
---|
| 1087 | return; |
---|
| 1088 | |
---|
| 1089 | Item *itemTarget = _player->GetItemByGuid(guids[0]); |
---|
| 1090 | if(!itemTarget) //missing item to socket |
---|
| 1091 | return; |
---|
| 1092 | |
---|
| 1093 | //this slot is excepted when applying / removing meta gem bonus |
---|
| 1094 | uint8 slot = itemTarget->IsEquipped() ? itemTarget->GetSlot() : NULL_SLOT; |
---|
| 1095 | |
---|
| 1096 | for(int i = 0; i < 3; i++) |
---|
| 1097 | Gems[i] = guids[i + 1] ? _player->GetItemByGuid(guids[i + 1]) : NULL; |
---|
| 1098 | |
---|
| 1099 | GemPropertiesEntry const *GemProps[3]; |
---|
| 1100 | for(int i = 0; i < 3; ++i) //get geminfo from dbc storage |
---|
| 1101 | { |
---|
| 1102 | GemProps[i] = (Gems[i]) ? sGemPropertiesStore.LookupEntry(Gems[i]->GetProto()->GemProperties) : NULL; |
---|
| 1103 | } |
---|
| 1104 | |
---|
| 1105 | for(int i = 0; i < 3; ++i) //check for hack maybe |
---|
| 1106 | { |
---|
| 1107 | // tried to put gem in socket where no socket exists / tried to put normal gem in meta socket |
---|
| 1108 | // tried to put meta gem in normal socket |
---|
| 1109 | if( GemProps[i] && ( !itemTarget->GetProto()->Socket[i].Color || |
---|
| 1110 | itemTarget->GetProto()->Socket[i].Color == SOCKET_COLOR_META && GemProps[i]->color != SOCKET_COLOR_META || |
---|
| 1111 | itemTarget->GetProto()->Socket[i].Color != SOCKET_COLOR_META && GemProps[i]->color == SOCKET_COLOR_META ) ) |
---|
| 1112 | return; |
---|
| 1113 | } |
---|
| 1114 | |
---|
| 1115 | for(int i = 0; i < 3; ++i) //get new and old enchantments |
---|
| 1116 | { |
---|
| 1117 | GemEnchants[i] = (GemProps[i]) ? GemProps[i]->spellitemenchantement : 0; |
---|
| 1118 | OldEnchants[i] = itemTarget->GetEnchantmentId(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT+i)); |
---|
| 1119 | } |
---|
| 1120 | |
---|
| 1121 | // check unique-equipped conditions |
---|
| 1122 | for(int i = 0; i < 3; ++i) |
---|
| 1123 | { |
---|
| 1124 | if (Gems[i] && (Gems[i]->GetProto()->Flags & ITEM_FLAGS_UNIQUE_EQUIPPED)) |
---|
| 1125 | { |
---|
| 1126 | // for equipped item check all equipment for duplicate equipped gems |
---|
| 1127 | if(itemTarget->IsEquipped()) |
---|
| 1128 | { |
---|
| 1129 | if(GetPlayer()->GetItemOrItemWithGemEquipped(Gems[i]->GetEntry())) |
---|
| 1130 | { |
---|
| 1131 | _player->SendEquipError( EQUIP_ERR_ITEM_UNIQUE_EQUIPABLE, itemTarget, NULL ); |
---|
| 1132 | return; |
---|
| 1133 | } |
---|
| 1134 | } |
---|
| 1135 | |
---|
| 1136 | // continue check for case when attempt add 2 similar unique equipped gems in one item. |
---|
| 1137 | for (int j = 0; j < 3; ++j) |
---|
| 1138 | { |
---|
| 1139 | if ((i != j) && (Gems[j]) && (Gems[i]->GetProto()->ItemId == Gems[j]->GetProto()->ItemId)) |
---|
| 1140 | { |
---|
| 1141 | _player->SendEquipError( EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED, itemTarget, NULL ); |
---|
| 1142 | return; |
---|
| 1143 | } |
---|
| 1144 | } |
---|
| 1145 | for (int j = 0; j < 3; ++j) |
---|
| 1146 | { |
---|
| 1147 | if (OldEnchants[j]) |
---|
| 1148 | { |
---|
| 1149 | SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(OldEnchants[j]); |
---|
| 1150 | if(!enchantEntry) |
---|
| 1151 | continue; |
---|
| 1152 | |
---|
| 1153 | if ((enchantEntry->GemID == Gems[i]->GetProto()->ItemId) && (i != j)) |
---|
| 1154 | { |
---|
| 1155 | _player->SendEquipError( EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED, itemTarget, NULL ); |
---|
| 1156 | return; |
---|
| 1157 | } |
---|
| 1158 | } |
---|
| 1159 | } |
---|
| 1160 | } |
---|
| 1161 | } |
---|
| 1162 | |
---|
| 1163 | SocketBonusActivated = itemTarget->GemsFitSockets(); //save state of socketbonus |
---|
| 1164 | _player->ToggleMetaGemsActive(slot, false); //turn off all metagems (except for the target item) |
---|
| 1165 | |
---|
| 1166 | //if a meta gem is being equipped, all information has to be written to the item before testing if the conditions for the gem are met |
---|
| 1167 | |
---|
| 1168 | //remove ALL enchants |
---|
| 1169 | for(uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+3; ++enchant_slot) |
---|
| 1170 | _player->ApplyEnchantment(itemTarget,EnchantmentSlot(enchant_slot),false); |
---|
| 1171 | |
---|
| 1172 | for(int i = 0; i < 3; ++i) |
---|
| 1173 | { |
---|
| 1174 | if(GemEnchants[i]) |
---|
| 1175 | { |
---|
| 1176 | itemTarget->SetEnchantment(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT+i), GemEnchants[i],0,0); |
---|
| 1177 | if(Item* guidItem = _player->GetItemByGuid(guids[i + 1])) |
---|
| 1178 | _player->DestroyItem(guidItem->GetBagSlot(), guidItem->GetSlot(), true ); |
---|
| 1179 | } |
---|
| 1180 | } |
---|
| 1181 | |
---|
| 1182 | for(uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+3; ++enchant_slot) |
---|
| 1183 | _player->ApplyEnchantment(itemTarget,EnchantmentSlot(enchant_slot),true); |
---|
| 1184 | |
---|
| 1185 | SocketBonusToBeActivated = itemTarget->GemsFitSockets();//current socketbonus state |
---|
| 1186 | if(SocketBonusActivated ^ SocketBonusToBeActivated) //if there was a change... |
---|
| 1187 | { |
---|
| 1188 | _player->ApplyEnchantment(itemTarget,BONUS_ENCHANTMENT_SLOT,false); |
---|
| 1189 | itemTarget->SetEnchantment(BONUS_ENCHANTMENT_SLOT, (SocketBonusToBeActivated ? itemTarget->GetProto()->socketBonus : 0), 0, 0); |
---|
| 1190 | _player->ApplyEnchantment(itemTarget,BONUS_ENCHANTMENT_SLOT,true); |
---|
| 1191 | //it is not displayed, client has an inbuilt system to determine if the bonus is activated |
---|
| 1192 | } |
---|
| 1193 | |
---|
| 1194 | _player->ToggleMetaGemsActive(slot, true); //turn on all metagems (except for target item) |
---|
| 1195 | } |
---|
| 1196 | |
---|
| 1197 | void WorldSession::HandleCancelTempItemEnchantmentOpcode(WorldPacket& recv_data) |
---|
| 1198 | { |
---|
| 1199 | sLog.outDebug("WORLD: CMSG_CANCEL_TEMP_ENCHANTMENT"); |
---|
| 1200 | |
---|
| 1201 | CHECK_PACKET_SIZE(recv_data,4); |
---|
| 1202 | |
---|
| 1203 | uint32 eslot; |
---|
| 1204 | |
---|
| 1205 | recv_data >> eslot; |
---|
| 1206 | |
---|
| 1207 | // apply only to equipped item |
---|
| 1208 | if(!Player::IsEquipmentPos(INVENTORY_SLOT_BAG_0,eslot)) |
---|
| 1209 | return; |
---|
| 1210 | |
---|
| 1211 | Item* item = GetPlayer()->GetItemByPos(INVENTORY_SLOT_BAG_0, eslot); |
---|
| 1212 | |
---|
| 1213 | if(!item) |
---|
| 1214 | return; |
---|
| 1215 | |
---|
| 1216 | if(!item->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT)) |
---|
| 1217 | return; |
---|
| 1218 | |
---|
| 1219 | GetPlayer()->ApplyEnchantment(item,TEMP_ENCHANTMENT_SLOT,false); |
---|
| 1220 | item->ClearEnchantment(TEMP_ENCHANTMENT_SLOT); |
---|
| 1221 | } |
---|