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