1 | /* |
---|
2 | * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/> |
---|
3 | * |
---|
4 | * Copyright (C) 2008 Trinity <http://www.trinitycore.org/> |
---|
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 |
---|
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
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 |
---|
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
---|
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 | |
---|
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 | |
---|
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 | |
---|
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 | |
---|
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 | |
---|
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 | |
---|
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 | |
---|
509 | // prevent possible overflow, as Trinity uses uint32 for item count |
---|
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 | |
---|
785 | if(!_player->IsValidPos(dstbag,NULL_SLOT)) |
---|
786 | { |
---|
787 | _player->SendEquipError( EQUIP_ERR_ITEM_DOESNT_GO_TO_SLOT, NULL, NULL ); |
---|
788 | return; |
---|
789 | } |
---|
790 | |
---|
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 | } |
---|