[2595] Applied MaNGOS coding style (see trunk/bcpp.cfg).
[mangos-git.git] / src / game / Player.cpp
blobdc6018d4f57f5d299ea9f60fcc9b713ea6e94a71
1 /*
2 * Copyright (C) 2005,2006 MaNGOS <http://www.mangosproject.org/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include "Common.h"
20 #include "Database/DatabaseEnv.h"
21 #include "Log.h"
22 #include "Opcodes.h"
23 #include "ObjectMgr.h"
24 #include "World.h"
25 #include "WorldPacket.h"
26 #include "WorldSession.h"
27 #include "UpdateMask.h"
28 #include "Player.h"
29 #include "QuestDef.h"
30 #include "GossipDef.h"
31 #include "Spell.h"
32 #include "UpdateData.h"
33 #include "Channel.h"
34 #include "Chat.h"
35 #include "MapManager.h"
36 #include "ObjectMgr.h"
37 #include "ObjectAccessor.h"
38 #include "CreatureAI.h"
39 #include "Formulas.h"
40 #include "Group.h"
41 #include "Guild.h"
42 #include "Pet.h"
43 #include "SpellAuras.h"
44 #include "Util.h"
46 #include <cmath>
48 Player::Player (WorldSession *session): Unit()
50 m_objectType |= TYPE_PLAYER;
51 m_objectTypeId = TYPEID_PLAYER;
53 m_valuesCount = PLAYER_END;
55 m_session = session;
57 info = NULL;
58 m_divider = 0;
60 m_GMFlags = 0;
61 if(GetSession()->GetSecurity() >=2)
62 SetAcceptTicket(true);
63 if(GetSession()->GetSecurity() >=1 && sWorld.getConfig(CONFIG_GM_WISPERING_TO))
64 SetAcceptWhispers(true);
66 m_curTarget = 0;
67 m_curSelection = 0;
68 m_lootGuid = 0;
69 m_petInfoId = 0;
70 m_petLevel = 0;
71 m_petFamilyId = 0;
73 m_regenTimer = 0;
74 m_dismountCost = 0;
76 m_nextSave = sWorld.getConfig(CONFIG_INTERVAL_SAVE);
78 m_resurrectGUID = 0;
79 m_resurrectX = m_resurrectY = m_resurrectZ = 0;
80 m_resurrectHealth = m_resurrectMana = 0;
82 memset(m_items, 0, sizeof(Item*)*BUYBACK_SLOT_END);
83 memset(m_buybackitems, 0, sizeof(Item*)*(BUYBACK_SLOT_END - BUYBACK_SLOT_START));
85 m_pDuel = NULL;
86 m_pDuelSender = NULL;
87 m_isInDuel = false;
89 m_GuildIdInvited = 0;
91 m_groupLeader = 0;
92 m_isInGroup = false;
93 m_isInvited = false;
95 m_dontMove = false;
97 m_total_honor_points = 0;
99 pTrader = NULL;
101 ClearTrade();
103 m_cinematic = 0;
105 PlayerTalkClass = new PlayerMenu( GetSession() );
106 m_currentBuybackSlot = BUYBACK_SLOT_START;
108 for ( int aX = 0 ; aX < 8 ; aX++ )
109 m_Tutorials[ aX ] = 0x00;
110 ItemsSetEff[0]=NULL;
111 ItemsSetEff[1]=NULL;
112 ItemsSetEff[2]=NULL;
113 m_regenTimer = 0;
114 m_breathTimer = 0;
115 m_isunderwater = 0;
116 m_drunkTimer = 0;
117 m_drunk = 0;
118 m_restTime = 0;
119 m_lastManaUse = 0;
120 m_deathTimer = 0;
122 m_pvp_count = 0;
123 m_pvp_counting = false;
125 m_bgInBattleGround = false;
126 m_bgBattleGroundID = 0;
128 m_movement_flags = 0;
130 m_BlockValue = 0;
132 m_logintime = time(NULL);
133 m_Last_tick = m_logintime;
134 m_soulStone = NULL;
135 m_soulStoneSpell = 0;
136 m_WeaponProficiency = 0;
137 m_ArmorProficiency = 0;
138 m_canParry = false;
139 m_canDualWield = false;
141 ////////////////////Rest System/////////////////////
142 time_inn_enter=0;
143 inn_pos_x=0;
144 inn_pos_y=0;
145 inn_pos_z=0;
146 rest_bonus=0;
147 rest_type=0;
148 ////////////////////Rest System/////////////////////
150 m_mailsLoaded = false;
151 m_mailsUpdated = false;
153 m_resetTalentsCost = 0;
154 m_resetTalentsTime = 0;
157 Player::~Player ()
159 DuelComplete();
161 CombatStop();
163 TradeCancel(false);
165 RemoveAllAuras();
167 uint32 eslot;
168 for(int j = BUYBACK_SLOT_START; j < BUYBACK_SLOT_END; j++)
170 eslot = j - BUYBACK_SLOT_START;
171 if(m_buybackitems[eslot])
173 m_buybackitems[eslot]->DeleteFromDB();
174 m_buybackitems[eslot]->RemoveFromWorld();
175 delete m_buybackitems[eslot];
178 for(int i = 0; i < BANK_SLOT_BAG_END; i++)
180 if(m_items[i])
181 delete m_items[i];
183 CleanupChannels();
185 //all mailed items should be deleted, also all mail should be dealocated
186 for (std::list<Mail*>::iterator itr = m_mail.begin(); itr != m_mail.end();++itr)
187 delete *itr;
189 for (ItemMap::iterator iter = mMitems.begin(); iter != mMitems.end(); ++iter)
190 delete iter->second; //if item is duplicated... then server may crash ... but that item should be dealocated
192 delete info;
193 delete PlayerTalkClass;
196 bool Player::Create( uint32 guidlow, WorldPacket& data )
198 int i;
199 uint8 race,class_,gender,skin,face,hairStyle,hairColor,facialHair,outfitId;
201 Object::_Create(guidlow, HIGHGUID_PLAYER);
203 data >> m_name;
205 normalizePlayerName(m_name);
207 data >> race >> class_ >> gender >> skin >> face;
208 data >> hairStyle >> hairColor >> facialHair >> outfitId;
210 info = objmgr.GetPlayerCreateInfo((uint32)race, (uint32)class_);
211 if(!info)
213 sLog.outError("Player have incorrect race/class pair. Can't be loaded.");
214 return false;
217 m_createStats[STAT_AGILITY] = (float)info->agility;
218 m_createStats[STAT_INTELLECT] = (float)info->intellect;
219 m_createStats[STAT_SPIRIT] = (float)info->spirit;
220 m_createStats[STAT_STAMINA] = (float)info->stamina;
221 m_createStats[STAT_STRENGTH] = (float)info->strength;
223 for (i = 0; i < BANK_SLOT_BAG_END; i++)
224 m_items[i] = NULL;
226 uint32 eslot;
227 for(int j = BUYBACK_SLOT_START; j < BUYBACK_SLOT_END; j++)
229 eslot = j - BUYBACK_SLOT_START;
230 m_buybackitems[eslot] = NULL;
231 // SetUInt64Value(PLAYER_FIELD_VENDORBUYBACK_SLOT_1+j*2,0);
232 // SetUInt32Value(PLAYER_FIELD_BUYBACK_PRICE_1+j,0);
233 // SetUInt32Value(PLAYER_FIELD_BUYBACK_TIMESTAMP_1+j,0);
236 m_race = race;
237 m_class = class_;
239 m_mapId = info->mapId;
240 m_positionX = info->positionX;
241 m_positionY = info->positionY;
242 m_positionZ = info->positionZ;
244 // Taxi nodes setup
245 memset(m_taximask, 0, sizeof(m_taximask));
247 // Automatically add the race's taxi hub to the character's taximask at creation time ( 1 << (taxi_node_id-1) )
248 switch(race)
250 case TAUREN: m_taximask[0]= 1 << (22-1); break;
251 case HUMAN: m_taximask[0]= 1 << ( 2-1); break;
252 case DWARF: m_taximask[0]= 1 << ( 6-1); break;
253 case NIGHTELF: m_taximask[0]= (1 << (26-1)) | (1 << (27-1)); break;
254 case GNOME: m_taximask[0]= 1 << ( 6-1); break;
255 case ORC: m_taximask[0]= 1 << (23-1); break;
256 case UNDEAD_PLAYER: m_taximask[0]= 1 << (11-1); break;
257 case TROLL: m_taximask[0]= 1 << (23-1); break;
260 uint8 powertype = 0;
261 uint32 unitfield = 0;
262 switch(class_)
264 case WARRIOR: powertype = 1; unitfield = 0x1100EE00; break;
265 case PALADIN: powertype = 0; unitfield = 0x0000EE00; break;
266 case HUNTER: powertype = 0; unitfield = 0x0000EE00; break;
267 case ROGUE: powertype = 3; unitfield = 0x00000000; break;
268 case PRIEST: powertype = 0; unitfield = 0x0000EE00; break;
269 case SHAMAN: powertype = 0; unitfield = 0x0000EE00; break;
270 case MAGE: powertype = 0; unitfield = 0x0000EE00; break;
271 case WARLOCK: powertype = 0; unitfield = 0x0000EE00; break;
272 case DRUID: powertype = 0; unitfield = 0x0000EE00; break;
275 if ( race == TAUREN )
277 SetFloatValue(OBJECT_FIELD_SCALE_X, 1.35f);
279 else SetFloatValue(OBJECT_FIELD_SCALE_X, 1.0f);
280 SetStat(STAT_STRENGTH,info->strength );
281 SetStat(STAT_AGILITY,info->agility );
282 SetStat(STAT_STAMINA,info->stamina );
283 SetStat(STAT_INTELLECT,info->intellect );
284 SetStat(STAT_SPIRIT,info->spirit );
285 SetArmor(info->basearmor );
286 SetUInt32Value(UNIT_FIELD_ATTACK_POWER, 0 );
288 SetHealth(info->health);
289 SetMaxHealth(info->health);
291 SetPower( POWER_MANA, info->mana );
292 SetMaxPower(POWER_MANA, info->mana );
293 SetPower( POWER_RAGE, 0 );
294 SetMaxPower(POWER_RAGE, info->rage );
295 SetPower( POWER_FOCUS, info->focus );
296 SetMaxPower(POWER_FOCUS, info->focus );
297 SetPower( POWER_ENERGY, info->energy );
298 SetMaxPower(POWER_ENERGY, info->energy );
300 SetFloatValue(UNIT_FIELD_MINDAMAGE, 0 );
301 SetFloatValue(UNIT_FIELD_MAXDAMAGE, 0 );
302 SetFloatValue(UNIT_FIELD_MINRANGEDDAMAGE, 0 );
303 SetFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE, 0 );
305 SetAttackTime(BASE_ATTACK, 2000 ); // melee attack time
306 SetAttackTime(RANGED_ATTACK, 2000 ); // ranged attack time
308 SetFloatValue(UNIT_FIELD_BOUNDINGRADIUS, 0.388999998569489f );
309 SetFloatValue(UNIT_FIELD_COMBATREACH, 1.5f );
311 SetUInt32Value(UNIT_FIELD_DISPLAYID, info->displayId + gender );
312 SetUInt32Value(UNIT_FIELD_NATIVEDISPLAYID, info->displayId + gender );
314 SetLevel( 1 );
316 setFactionForRace(m_race);
318 SetUInt32Value(UNIT_FIELD_BYTES_0, ( ( race ) | ( class_ << 8 ) | ( gender << 16 ) | ( powertype << 24 ) ) );
319 SetUInt32Value(UNIT_FIELD_BYTES_1, unitfield );
320 SetUInt32Value(UNIT_FIELD_BYTES_2, 0xEEEEEE00 );
321 SetUInt32Value(UNIT_FIELD_FLAGS , UNIT_FLAG_NONE | UNIT_FLAG_NOT_IN_PVP );
323 SetUInt32Value(UNIT_DYNAMIC_FLAGS, 0x10);
324 //-1 is default value
325 SetUInt32Value(PLAYER_FIELD_WATCHED_FACTION_INDEX, uint32(-1));
327 SetUInt32Value(PLAYER_BYTES, ((skin) | (face << 8) | (hairStyle << 16) | (hairColor << 24)));
328 SetUInt32Value(PLAYER_BYTES_2, (facialHair | (0xEE << 8) | (0x00 << 16) | (0x02 << 24)));
329 SetUInt32Value(PLAYER_BYTES_3, gender);
330 SetUInt32Value(PLAYER_NEXT_LEVEL_XP, 400);
331 SetUInt32Value(PLAYER_FIELD_BYTES, 0xEEE00000 );
333 SetFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT, 1.00);
334 SetFloatValue(PLAYER_CRIT_PERCENTAGE, 5);
335 SetFloatValue(PLAYER_PARRY_PERCENTAGE, 5);
338 SetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG, 0);
339 SetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS, 0);
341 SetUInt32Value(PLAYER_GUILDID, 0);
342 SetUInt32Value(PLAYER_GUILDRANK, 0);
343 SetUInt32Value(PLAYER_GUILD_TIMESTAMP, 0);
345 SetUInt32Value(PLAYER_FIELD_HONOR_RANK, 0);
346 SetUInt32Value(PLAYER_FIELD_HONOR_HIGHEST_RANK, 0); SetUInt32Value(PLAYER_FIELD_TODAY_KILLS, 0); SetUInt32Value(PLAYER_FIELD_YESTERDAY_HONORABLE_KILLS, 0); SetUInt32Value(PLAYER_FIELD_LAST_WEEK_HONORABLE_KILLS, 0); SetUInt32Value(PLAYER_FIELD_THIS_WEEK_HONORABLE_KILLS, 0); SetUInt32Value(PLAYER_FIELD_THIS_WEEK_HONOR, 0); SetUInt32Value(PLAYER_FIELD_LIFETIME_HONORABLE_KILLS, 0); SetUInt32Value(PLAYER_FIELD_LIFETIME_DISHONORABLE_KILLS, 0); SetUInt32Value(PLAYER_FIELD_YESTERDAY_HONOR, 0); SetUInt32Value(PLAYER_FIELD_LAST_WEEK_HONOR, 0); SetUInt32Value(PLAYER_FIELD_LAST_WEEK_STANDING, 0); SetUInt32Value(PLAYER_FIELD_LIFETIME_HONOR, 0); SetUInt32Value(PLAYER_FIELD_SESSION_KILLS, 0);
349 // Played time
350 m_Last_tick = time(NULL);
351 m_Played_time[0] = 0;
352 m_Played_time[1] = 0;
354 uint32 titem_id;
355 uint8 titem_slot;
356 uint8 titem_bagIndex;
357 uint32 titem_amount;
358 uint16 tspell, tskill[3], taction[4];
359 std::list<uint32>::iterator item_id_itr;
360 std::list<uint8>::iterator item_bagIndex_itr;
361 std::list<uint8>::iterator item_slot_itr;
362 std::list<uint32>::iterator item_amount_itr;
363 std::list<uint16>::iterator skill_itr[3], action_itr[4];
364 std::list<CreateSpellPair>::iterator spell_itr;
366 item_id_itr = info->item_id.begin();
367 item_bagIndex_itr = info->item_bagIndex.begin();
368 item_slot_itr = info->item_slot.begin();
369 item_amount_itr = info->item_amount.begin();
370 spell_itr = info->spell.begin();
372 for (; spell_itr!=info->spell.end(); spell_itr++)
374 tspell = spell_itr->first;
375 if (tspell)
377 sLog.outDebug("PLAYER: Adding initial spell, id = %u",tspell);
378 addSpell(tspell,spell_itr->second);
382 for(i=0 ; i<3; i++)
383 skill_itr[i] = info->skill[i].begin();
385 for (; skill_itr[0]!=info->skill[0].end() && skill_itr[1]!=info->skill[1].end() && skill_itr[2]!=info->skill[2].end(); )
387 for (i=0; i<3; i++)
388 tskill[i] = (*skill_itr[i]);
390 if (tskill[0])
392 sLog.outDebug("PLAYER: Adding initial skill line, skillId = %u, value = %u, max = %u", tskill[0], tskill[1], tskill[2]);
393 SetSkill(tskill[0], tskill[1], tskill[2]);
396 for(i=0; i<3; i++)
397 skill_itr[i]++;
400 for(i=0; i<4; i++)
401 action_itr[i] = info->action[i].begin();
403 for (; action_itr[0]!=info->action[0].end() && action_itr[1]!=info->action[1].end();)
405 for( i=0; i<4 ;i++)
406 taction[i] = (*action_itr[i]);
408 addAction((uint8)taction[0], taction[1], (uint8)taction[2], (uint8)taction[3]);
410 for( i=0; i<4 ;i++)
411 action_itr[i]++;
414 m_petInfoId = 0;
415 m_petLevel = 0;
416 m_petFamilyId = 0;
418 m_rating = 0;
419 m_highest_rank = 0;
420 m_standing = 0;
422 // initilize potential block chance (used if item with Block value equiped)
423 SetFloatValue(PLAYER_BLOCK_PERCENTAGE, 5 );
424 UpdateBlockPercentage(GetDefenceSkillValue(),getLevel());
426 // apply original stats mods before item equipment that call before equip _RemoveStatsMods()
427 _ApplyStatsMods();
429 uint16 dest;
430 uint8 msg;
431 Item *pItem;
432 for (; item_id_itr!=info->item_id.end(); item_id_itr++, item_bagIndex_itr++, item_slot_itr++, item_amount_itr++)
434 titem_id = (*item_id_itr);
435 titem_bagIndex = (*item_bagIndex_itr);
436 titem_slot = (*item_slot_itr);
437 titem_amount = (*item_amount_itr);
439 if (titem_id)
441 sLog.outDebug("STORAGE: Creating initial item, itemId = %u, bagIndex = %u, slot = %u, count = %u",titem_id, titem_bagIndex, titem_slot, titem_amount);
443 pItem = CreateItem( titem_id, titem_amount);
444 if( pItem )
446 dest = ((titem_bagIndex << 8) | titem_slot);
447 if( IsInventoryPos( dest ) )
449 msg = CanStoreItem( titem_bagIndex, titem_slot, dest, pItem, false );
450 if( msg == EQUIP_ERR_OK )
451 StoreItem( dest, pItem, true);
452 else
454 sLog.outDebug("STORAGE: Can't store item, error msg = %u",msg);
455 delete pItem;
458 else if( IsEquipmentPos( dest ) )
460 msg = CanEquipItem( titem_slot, dest, pItem, false );
461 if( msg == EQUIP_ERR_OK )
462 EquipItem( dest, pItem, true);
463 else
465 sLog.outDebug("STORAGE: Can't equip item, error msg = %u",msg);
466 delete pItem;
469 else if( IsBankPos( dest ) )
471 msg = CanBankItem( titem_bagIndex, titem_slot, dest, pItem, false );
472 if( msg == EQUIP_ERR_OK )
473 BankItem( dest, pItem, true);
474 else
476 sLog.outDebug("STORAGE: Can't bank item, error msg = %u",msg);
477 delete pItem;
480 else
481 delete pItem;
486 // remove applied original stats mods before item equipment
487 _RemoveStatsMods();
488 return true;
491 void Player::StartMirrorTimer(MirrorTimerType Type, uint32 MaxValue)
493 WorldPacket data;
494 uint32 BreathRegen = (uint32)-1;
495 data.Initialize(SMSG_START_MIRROR_TIMER);
496 data << (uint32)Type;
497 data << MaxValue;
498 data << MaxValue;
499 data << BreathRegen;
500 data << (uint32)0;
501 data << (uint8)0;
502 GetSession()->SendPacket(&data);
505 void Player::ModifyMirrorTimer(MirrorTimerType Type, uint32 MaxValue, uint32 CurrentValue, uint32 Regen)
507 if(Type==BREATH_TIMER)
508 m_breathTimer = ((MaxValue + 1000) - CurrentValue) / Regen;
510 WorldPacket data;
511 data.Initialize(SMSG_START_MIRROR_TIMER);
512 data << (uint32)Type;
513 data << CurrentValue;
514 data << MaxValue;
515 data << Regen;
516 data << (uint32)0;
517 data << (uint8)0;
518 GetSession()->SendPacket( &data );
521 void Player::StopMirrorTimer(MirrorTimerType Type)
523 if(Type==BREATH_TIMER)
524 m_breathTimer = 0;
526 WorldPacket data;
527 data.Initialize(SMSG_STOP_MIRROR_TIMER);
528 data << (uint32)Type;
529 GetSession()->SendPacket( &data );
532 void Player::EnvironmentalDamage(uint64 Guid, uint8 Type, uint32 Amount)
534 WorldPacket data;
535 data.Initialize(SMSG_ENVIRONMENTALDAMAGELOG);
536 data << Guid;
537 data << (uint8)Type;
538 data << Amount;
539 data << (uint32)0;
540 data << (uint32)0;
541 //m_session->SendPacket(&data);
542 //Let other players see that you get damage
543 SendMessageToSet(&data, true);
544 DealDamage((Unit*)this, Amount, 0, true);
547 void Player::HandleDrowing(uint32 UnderWaterTime)
549 AuraList& mModWaterBreathing = GetAurasByType(SPELL_AURA_MOD_WATER_BREATHING);
550 for(AuraList::iterator i = mModWaterBreathing.begin(); i != mModWaterBreathing.end(); ++i)
551 UnderWaterTime = uint32(UnderWaterTime * (100.0f + (*i)->GetModifier()->m_amount) / 100.0f);
553 //if have water breath , then remove bar
554 if(waterbreath || !isAlive())
556 StopMirrorTimer(BREATH_TIMER);
557 m_isunderwater = 0;
558 return;
561 if ((m_isunderwater & 0x01) && !(m_isunderwater & 0x80) && isAlive())
563 //single trigger timer
564 if (!(m_isunderwater & 0x02))
566 m_isunderwater|= 0x02;
567 m_breathTimer = UnderWaterTime + 1000;
569 //single trigger "Breathbar"
570 if ( m_breathTimer <= UnderWaterTime && !(m_isunderwater & 0x04))
572 m_isunderwater|= 0x04;
573 StartMirrorTimer(BREATH_TIMER, UnderWaterTime);
575 //continius trigger drowning "Damage"
576 if ((m_breathTimer == 0) && (m_isunderwater & 0x01))
578 //TODO: Check this formula
579 uint64 guid = GetGUID();
580 uint32 damage = (GetMaxHealth() / 5) + rand()%getLevel();
582 EnvironmentalDamage(guid, DAMAGE_DROWNING,damage);
583 m_breathTimer = 2000;
586 //single trigger retract bar
587 else if (!(m_isunderwater & 0x01) && !(m_isunderwater & 0x08) && (m_isunderwater & 0x02) && (m_breathTimer > 0) && isAlive())
589 m_isunderwater = 0x08;
591 uint32 BreathRegen = 10;
592 ModifyMirrorTimer(BREATH_TIMER, UnderWaterTime, m_breathTimer,BreathRegen);
593 m_isunderwater = 0x10;
595 //remove bar
596 else if ((m_breathTimer < 50) && !(m_isunderwater & 0x01) && (m_isunderwater == 0x10))
598 StopMirrorTimer(BREATH_TIMER);
599 m_isunderwater = 0;
603 void Player::HandleLava()
605 if ((m_isunderwater & 0x80) && isAlive())
607 //Single trigger Set BreathTimer
608 if (!(m_isunderwater & 0x04))
610 m_isunderwater|= 0x04;
611 m_breathTimer = 1000;
613 //Reset BreathTimer and still in the lava
614 if (!m_breathTimer)
616 uint64 guid;
617 //uint32 damage = 10;
618 uint32 damage = (GetMaxHealth() / 3) + rand()%getLevel();
620 guid = GetGUID();
621 EnvironmentalDamage(guid, DAMAGE_LAVA, damage);
622 m_breathTimer = 1000;
626 //Death timer disabled and WaterFlags reset
627 else if (m_deathState == DEAD)
629 m_breathTimer = 0;
630 m_isunderwater = 0;
634 void Player::HandleSobering()
636 m_drunkTimer = 0;
637 if (m_drunk <= (0xFFFF / 30))
639 m_drunk = 0;
641 else
643 m_drunk -= (0xFFFF / 30);
645 SetUInt32Value(PLAYER_BYTES_3, (GetUInt32Value(PLAYER_BYTES_3) & 0xFFFF0001) | m_drunk);
648 void Player::SetDrunkValue(uint16 newDrunkValue)
650 m_drunk = newDrunkValue;
651 SetUInt32Value(PLAYER_BYTES_3,
652 (GetUInt32Value(PLAYER_BYTES_3) & 0xFFFF0001) | m_drunk);
655 void Player::Update( uint32 p_time )
657 if(!IsInWorld())
658 return;
660 WorldPacket data;
662 Unit::Update( p_time );
664 // update player only attacks
665 if(uint32 ranged_att = getAttackTimer(RANGED_ATTACK))
667 setAttackTimer(RANGED_ATTACK, (p_time >= ranged_att ? 0 : ranged_att - p_time) );
670 if(uint32 off_att = getAttackTimer(OFF_ATTACK))
672 setAttackTimer(OFF_ATTACK, (p_time >= off_att ? 0 : off_att - p_time) );
675 time_t now = time (NULL);
677 UpdatePVPFlag(time(NULL));
679 CheckDuelDistance();
681 CheckExploreSystem();
683 if (m_timedquests.size() > 0)
685 list<uint32>::iterator iter = m_timedquests.begin();
686 while (iter != m_timedquests.end())
688 //if( mQuestStatus[*iter].m_timer > 0 )
690 if( mQuestStatus[*iter].m_timer <= p_time )
692 FailTimedQuest( *iter );
693 iter = m_timedquests.begin();
695 else
697 mQuestStatus[*iter].m_timer -= p_time;
698 iter++;
704 if (isAttacking())
706 Unit *pVictim = getVictim();
707 if( m_currentSpell == 0 && pVictim)
710 // default combat reach 10
711 // TODO add weapon,skill check
713 float pldistance = 5.0f;
715 /*if(getClass() == WARRIOR)
716 pldistance += 1;
718 if(GetItemByPos( INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND ) != 0)
719 pldistance += 2;
721 if(GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_HANDS) != 0)
722 pldistance += 3;*/
724 if (isAttackReady(BASE_ATTACK))
726 if(!IsWithinDist(pVictim, pldistance))
728 setAttackTimer(BASE_ATTACK,1000);
729 SendAttackSwingNotInRange();
731 //120 degreas of radiant range
732 else if( !HasInArc( 2*M_PI/3, pVictim ))
734 setAttackTimer(BASE_ATTACK,1000);
735 SendAttackSwingBadFacingAttack();
737 else
739 // prevent base and off attack in same time, delay attack at 0.2 sec
740 if(haveOffhandWeapon())
742 uint32 off_att = getAttackTimer(OFF_ATTACK);
743 if(off_att < ATTACK_DISPLAY_DELAY)
744 setAttackTimer(OFF_ATTACK,ATTACK_DISPLAY_DELAY);
746 AttackerStateUpdate(pVictim, BASE_ATTACK);
747 resetAttackTimer(BASE_ATTACK);
751 if ( haveOffhandWeapon() && isAttackReady(OFF_ATTACK))
753 if(! IsWithinDist(pVictim, pldistance))
755 setAttackTimer(OFF_ATTACK,1000);
757 else if( !HasInArc( 2*M_PI/3, pVictim ))
759 setAttackTimer(OFF_ATTACK,1000);
761 else
763 // prevent base and off attack in same time, delay attack at 0.2 sec
764 uint32 base_att = getAttackTimer(BASE_ATTACK);
765 if(base_att < ATTACK_DISPLAY_DELAY)
766 setAttackTimer(BASE_ATTACK,ATTACK_DISPLAY_DELAY);
767 // do attack
768 AttackerStateUpdate(pVictim, OFF_ATTACK);
769 resetAttackTimer(OFF_ATTACK);
775 else if (isAttacked())
777 // Leave here so we don't forget this case
778 // Attacked, but not necessarily attacking
780 else
782 // Leave here so we don't forget this case
783 // Not attacking or attacked
786 if(HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING))
789 if(GetRestType()==1) //rest in tavern
791 if(sqrt((GetPositionX()-GetInnPosX())*(GetPositionX()-GetInnPosX())+(GetPositionY()-GetInnPosY())*(GetPositionY()-GetInnPosY())+(GetPositionZ()-GetInnPosZ())*(GetPositionZ()-GetInnPosZ()))>40)
793 //speed collect rest bonus (section/in hour)
794 float bubble=1; //0% Blizzlike
795 if(GetTimeInnEter()>0)SetRestBonus( GetRestBonus()+ (time(NULL)-GetTimeInnEter())*0.0142108*bubble );
796 RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING);
801 if(m_regenTimer > 0)
803 if(p_time >= m_regenTimer)
804 m_regenTimer = 0;
805 else
806 m_regenTimer -= p_time;
809 if (isAlive())
811 RegenerateAll();
814 if (m_deathState == JUST_DIED)
816 if( isInDuel() )
818 DuelComplete();
820 else
822 KillPlayer();
824 if( GetSoulStoneSpell() && GetSoulStone())
826 SpellEntry *spellInfo = sSpellStore.LookupEntry(GetSoulStoneSpell());
827 if(spellInfo)
829 Spell spell(this, spellInfo, true, 0);
831 SpellCastTargets targets;
832 targets.setUnitTarget( this );
833 spell.m_CastItem = GetSoulStone();
834 spell.prepare(&targets);
836 SetSoulStone(NULL);
837 SetSoulStoneSpell(0);
841 if(m_nextSave > 0)
843 if(p_time >= m_nextSave)
845 m_nextSave = sWorld.getConfig(CONFIG_INTERVAL_SAVE);
846 SaveToDB();
847 sLog.outBasic("Player '%u' '%s' Saved", GetGUIDLow(), GetName());
849 else
851 m_nextSave -= p_time;
855 //Breathtimer
856 if(m_breathTimer > 0)
858 if(p_time >= m_breathTimer)
859 m_breathTimer = 0;
860 else
861 m_breathTimer -= p_time;
865 //Handle Water/drowning
866 HandleDrowing(60000);
868 //Handle lava
869 HandleLava();
871 // Played time
872 if (now > m_Last_tick)
874 uint32 elapsed = uint32(now - m_Last_tick);
875 m_Played_time[0] += elapsed; // Total played time
876 m_Played_time[1] += elapsed; // Level played time
877 m_Last_tick = now;
880 if (m_drunk)
882 m_drunkTimer += p_time;
884 if (m_drunkTimer > 30000)
885 HandleSobering();
888 if(m_deathTimer > 0)
890 if(p_time >= m_deathTimer)
892 m_deathTimer = 0;
893 BuildPlayerRepop();
894 RepopAtGraveyard();
896 else
897 m_deathTimer -= p_time;
899 UpdateEnchantTime(p_time);
902 void Player::BuildEnumData( WorldPacket * p_data )
904 *p_data << GetGUID();
905 *p_data << m_name;
907 *p_data << getRace();
908 *p_data << getClass();
909 *p_data << getGender();
911 uint32 bytes = GetUInt32Value(PLAYER_BYTES);
912 *p_data << uint8(bytes);
913 *p_data << uint8(bytes >> 8);
914 *p_data << uint8(bytes >> 16);
915 *p_data << uint8(bytes >> 24);
917 bytes = GetUInt32Value(PLAYER_BYTES_2);
918 *p_data << uint8(bytes);
920 *p_data << uint8(getLevel()); //1
921 uint32 zoneId = MapManager::Instance ().GetMap(m_mapId)->GetZoneId(m_positionX,m_positionY);
923 *p_data << zoneId;
924 *p_data << GetMapId();
926 *p_data << m_positionX;
927 *p_data << m_positionY;
928 *p_data << m_positionZ;
930 *p_data << GetUInt32Value(PLAYER_GUILDID); //probebly wrong
932 //*p_data << GetUInt32Value(PLAYER_GUILDRANK); //this was
933 *p_data << uint8(0x0);
934 *p_data << uint8(GetUInt32Value(PLAYER_FLAGS) << 1);
935 *p_data << uint8(0x0); //Bit 4 is something dono
936 *p_data << uint8(0x0); //is this player_GUILDRANK????
938 *p_data << (uint8)0;
939 *p_data << (uint32)m_petInfoId;
940 *p_data << (uint32)m_petLevel;
941 *p_data << (uint32)m_petFamilyId;
943 ItemPrototype const *items[EQUIPMENT_SLOT_END];
944 for (int i = 0; i < EQUIPMENT_SLOT_END; i++)
945 items[i] = NULL;
947 QueryResult *result = sDatabase.PQuery("SELECT `slot`,`item_template` FROM `character_inventory` WHERE `guid` = '%u' AND `bag` = '%u'",GetGUIDLow(),INVENTORY_SLOT_BAG_0);
948 if (result)
952 Field *fields = result->Fetch();
953 uint8 slot = fields[0].GetUInt8() & 255;
954 uint32 item_id = fields[1].GetUInt32();
955 if( slot >= EQUIPMENT_SLOT_END )
956 continue;
958 items[slot] = objmgr.GetItemPrototype(item_id);
959 if(!items[slot])
961 sLog.outError( "Player::BuildEnumData: Player %s have unknown item (id: #%u) in inventory, skipped.", GetName(),item_id );
962 continue;
964 } while (result->NextRow());
965 delete result;
968 for (int i = 0; i < EQUIPMENT_SLOT_END; i++)
970 if (items[i] != NULL)
972 *p_data << (uint32)items[i]->DisplayInfoID;
973 *p_data << (uint8)items[i]->InventoryType;
975 else
977 *p_data << (uint32)0;
978 *p_data << (uint8)0;
981 // EQUIPMENT_SLOT_END always 0,0
982 *p_data << (uint32)0;
983 *p_data << (uint8)0;
986 bool Player::ToggleAFK()
988 if(HasFlag(PLAYER_FLAGS,PLAYER_FLAGS_AFK))
989 RemoveFlag(PLAYER_FLAGS,PLAYER_FLAGS_AFK);
990 else
992 // to prevent show <AFK> in invisiable mode
993 if(isGMVisible())
994 SetFlag(PLAYER_FLAGS,PLAYER_FLAGS_AFK);
995 else
996 GetSession()->SendNotification("You invisible currently!");
999 return HasFlag(PLAYER_FLAGS,PLAYER_FLAGS_AFK);
1002 bool Player::ToggleDND()
1004 if(HasFlag(PLAYER_FLAGS,PLAYER_FLAGS_DND))
1005 RemoveFlag(PLAYER_FLAGS,PLAYER_FLAGS_DND);
1006 else
1008 // to prevent show <DND> in invisiable mode
1009 if(isGMVisible())
1010 SetFlag(PLAYER_FLAGS,PLAYER_FLAGS_DND);
1011 else
1012 GetSession()->SendNotification("You invisible currently!");
1015 return HasFlag(PLAYER_FLAGS,PLAYER_FLAGS_DND);
1018 uint8 Player::chatTag()
1020 if(isGameMaster())
1021 return 3;
1022 else if(isDND())
1023 return 2;
1024 if(isAFK())
1025 return 1;
1026 else
1027 return 0;
1030 void Player::SendFriendlist()
1032 WorldPacket data;
1033 uint8 i=0;
1034 Field *fields;
1035 Player* pObj;
1036 FriendStr friendstr[255];
1038 QueryResult *result = sDatabase.PQuery("SELECT `friend` FROM `character_social` WHERE `flags` = 'FRIEND' AND `guid` = '%u'",GetGUIDLow());
1039 if(result)
1041 fields = result->Fetch();
1045 friendstr[i].PlayerGUID = fields[0].GetUInt64();
1046 pObj = ObjectAccessor::Instance().FindPlayer(friendstr[i].PlayerGUID);
1047 if( pObj && pObj->isGMVisibleFor(this))
1049 if(pObj->isAFK())
1050 friendstr[i].Status = 2;
1051 else if(pObj->isDND())
1052 friendstr[i].Status = 4;
1053 else
1054 friendstr[i].Status = 1;
1055 friendstr[i].Area = pObj->GetZoneId();
1056 friendstr[i].Level = pObj->getLevel();
1057 friendstr[i].Class = pObj->getClass();
1059 else
1061 friendstr[i].Status = 0;
1062 friendstr[i].Area = 0;
1063 friendstr[i].Level = 0;
1064 friendstr[i].Class = 0;
1066 i++;
1068 // prevent overflow
1069 if(i==255)
1070 break;
1071 } while( result->NextRow() );
1073 delete result;
1076 data.Initialize( SMSG_FRIEND_LIST );
1077 data << i;
1079 for (int j=0; j < i; j++)
1082 sLog.outDetail( "WORLD: Adding Friend Guid: %u, Status:%u, Area:%u, Level:%u Class:%u",GUID_LOPART(friendstr[j].PlayerGUID), friendstr[j].Status, friendstr[j].Area,friendstr[j].Level,friendstr[j].Class );
1084 data << friendstr[j].PlayerGUID << friendstr[j].Status ;
1085 if (friendstr[j].Status != 0)
1086 data << friendstr[j].Area << friendstr[j].Level << friendstr[j].Class;
1089 this->GetSession()->SendPacket( &data );
1090 sLog.outDebug( "WORLD: Sent (SMSG_FRIEND_LIST)" );
1093 void Player::SendIgnorelist()
1095 WorldPacket dataI;
1097 unsigned char nrignore=0;
1098 uint8 i=0;
1099 Field *fields;
1101 QueryResult *result = sDatabase.PQuery("SELECT COUNT(`friend`) FROM `character_social` WHERE `flags` = 'IGNORE' AND `guid` = '%u'", GetGUIDLow());
1103 if(!result) return;
1105 fields = result->Fetch();
1106 nrignore=fields[0].GetUInt32();
1107 delete result;
1109 dataI.Initialize( SMSG_IGNORE_LIST );
1110 dataI << nrignore;
1112 result = sDatabase.PQuery("SELECT `friend` FROM `character_social` WHERE `flags` = 'IGNORE' AND `guid` = '%u'", GetGUIDLow());
1114 if(!result) return;
1119 fields = result->Fetch();
1120 dataI << fields[0].GetUInt64();
1122 }while( result->NextRow() );
1123 delete result;
1125 this->GetSession()->SendPacket( &dataI );
1126 sLog.outDebug( "WORLD: Sent (SMSG_IGNORE_LIST)" );
1129 void Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientation, bool outofrange)
1131 if(this->GetMapId() == mapid)
1133 // near teleport
1134 WorldPacket data;
1135 BuildTeleportAckMsg(&data, x, y, z, orientation);
1136 GetSession()->SendPacket(&data);
1137 SetPosition( x, y, z, orientation );
1138 BuildHeartBeatMsg(&data);
1139 SendMessageToSet(&data, true);
1141 else
1143 MapManager::Instance().GetMap(GetMapId())->Remove(this, false);
1144 WorldPacket data;
1145 data.Initialize(SMSG_TRANSFER_PENDING);
1146 data << uint32(mapid);
1147 GetSession()->SendPacket(&data);
1149 data.Initialize(SMSG_NEW_WORLD);
1150 data << (uint32)mapid << (float)x << (float)y << (float)z << (float)orientation;
1151 GetSession()->SendPacket( &data );
1153 SetMapId(mapid);
1154 Relocate(x,y,z,orientation);
1155 SetPosition(x,y,z,orientation);
1156 SetDontMove(true);
1157 //SaveToDB();
1159 MapManager::Instance().GetMap(GetMapId())->Add(this);
1161 // Resend spell list to client after far teleport.
1162 SendInitialSpells();
1165 if (outofrange)
1167 CombatStop();
1169 // remove selection
1170 if(GetSelection())
1172 Unit* unit = ObjectAccessor::Instance().GetUnit(*this, GetSelection());
1173 if(unit)
1174 SendOutOfRange(unit);
1177 // unsommon pet if lost
1178 Creature* pet = GetPet();
1179 if(!pet) return;
1180 if(!IsWithinDistInMap(pet, OWNER_MAX_DISTANCE))
1181 UnsummonPet(pet);
1185 void Player::AddToWorld()
1187 Object::AddToWorld();
1189 for(int i = 0; i < BANK_SLOT_BAG_END; i++)
1191 if(m_items[i])
1192 m_items[i]->AddToWorld();
1194 AddWeather();
1196 if(Corpse* corpse = GetCorpse())
1197 corpse->UpdateForPlayer(this,true);
1200 void Player::RemoveFromWorld()
1203 for(int i = 0; i < BANK_SLOT_BAG_END; i++)
1205 if(m_items[i])
1206 m_items[i]->RemoveFromWorld();
1209 Object::RemoveFromWorld();
1212 void Player::CalcRage( uint32 damage,bool attacker )
1214 uint32 addRage = 0;
1216 if(attacker)
1217 addRage = (uint32)(10*damage/(getLevel()*0.5f));
1218 else
1219 addRage = (uint32)(10*damage/(getLevel()*1.5f));
1221 ModifyPower(POWER_RAGE, addRage);
1224 void Player::RegenerateAll()
1227 if (m_regenTimer != 0)
1228 return;
1229 uint32 regenDelay = 2000;
1231 // Not in combat or they have regeneration
1232 if (!isInCombat() || HasAuraType(SPELL_AURA_MOD_REGEN_DURING_COMBAT))
1234 RegenerateHealth();
1235 if (!isInCombat())
1236 Regenerate(POWER_RAGE);
1239 Regenerate( POWER_ENERGY );
1240 Regenerate( POWER_MANA );
1242 m_regenTimer = regenDelay;
1246 void Player::Regenerate(Powers power)
1248 uint32 curValue = GetPower(power);
1249 uint32 maxValue = GetMaxPower(power);
1251 if(power != POWER_RAGE)
1253 if (curValue >= maxValue) return;
1255 else if (curValue == 0)
1256 return;
1258 float ManaIncreaseRate = sWorld.getRate(RATE_POWER_MANA);
1259 float RageIncreaseRate = sWorld.getRate(RATE_POWER_RAGE);
1261 float Spirit = GetStat(STAT_SPIRIT);
1262 uint8 Class = getClass();
1264 if( ManaIncreaseRate <= 0 ) ManaIncreaseRate = 1;
1265 if( RageIncreaseRate <= 0 ) RageIncreaseRate = 1;
1267 float addvalue = 0.0;
1269 switch (power)
1271 case POWER_MANA:
1272 // If < 5s after previous cast which used mana, no regeneration unless
1273 // we happen to have a modifer that adds it back
1274 // If > 5s, get portion between the 5s and now, up to a maximum of 2s worth
1275 uint32 msecSinceLastCast;
1276 msecSinceLastCast = ((uint32)getMSTime() - m_lastManaUse);
1277 if (msecSinceLastCast >= 7000)
1279 ManaIncreaseRate *= 1;
1281 else
1283 long regenInterrupt = GetTotalAuraModifier(SPELL_AURA_MOD_MANA_REGEN_INTERRUPT);
1284 if (msecSinceLastCast < 5000)
1286 ManaIncreaseRate *= (float)regenInterrupt / 100;
1288 else
1290 ManaIncreaseRate = (((1 - (float)(msecSinceLastCast - 5000)/2000)) * regenInterrupt)
1291 + (((float)(msecSinceLastCast - 5000)/2000) * ManaIncreaseRate * 100);
1292 ManaIncreaseRate /= 100;
1295 ManaIncreaseRate = (ManaIncreaseRate * 100 + GetTotalAuraModifier(SPELL_AURA_MOD_POWER_REGEN_PERCENT)) / 100;
1297 switch (Class)
1299 case DRUID: addvalue = (Spirit/5 + 15) * ManaIncreaseRate; break;
1300 case HUNTER: addvalue = (Spirit/5 + 15) * ManaIncreaseRate; break;
1301 case MAGE: addvalue = (Spirit/4 + 12.5) * ManaIncreaseRate; break;
1302 case PALADIN: addvalue = (Spirit/5 + 15) * ManaIncreaseRate; break;
1303 case PRIEST: addvalue = (Spirit/4 + 12.5) * ManaIncreaseRate; break;
1304 case SHAMAN: addvalue = (Spirit/5 + 17) * ManaIncreaseRate; break;
1305 case WARLOCK: addvalue = (Spirit/5 + 15) * ManaIncreaseRate; break;
1307 break;
1308 case POWER_RAGE: // Regenerate rage
1309 addvalue = 30 * RageIncreaseRate; // 3 rage by tick
1310 break;
1311 case POWER_ENERGY: // Regenerate energy (rogue)
1312 addvalue = 20;
1313 break;
1314 case POWER_FOCUS:
1315 case POWER_HAPPINESS:
1316 break;
1319 if (power != POWER_RAGE)
1321 curValue += uint32(addvalue);
1322 if (curValue > maxValue) curValue = maxValue;
1324 else
1326 if(curValue <= uint32(addvalue))
1327 curValue = 0;
1328 else
1329 curValue -= uint32(addvalue);
1331 SetPower(power, curValue);
1334 void Player::RegenerateHealth()
1336 uint32 curValue = GetHealth();
1337 uint32 maxValue = GetMaxHealth();
1339 if (curValue >= maxValue) return;
1341 float HealthIncreaseRate = sWorld.getRate(RATE_HEALTH);
1343 float Spirit = GetStat(STAT_SPIRIT);
1344 uint8 Class = getClass();
1346 if( HealthIncreaseRate <= 0 ) HealthIncreaseRate = 1;
1348 float addvalue = 0.0;
1350 switch (Class)
1352 case DRUID: addvalue = (Spirit*0.11 + 1) * HealthIncreaseRate; break;
1353 case HUNTER: addvalue = (Spirit*0.43 - 5.5) * HealthIncreaseRate; break;
1354 case MAGE: addvalue = (Spirit*0.11 + 1) * HealthIncreaseRate; break;
1355 case PALADIN: addvalue = (Spirit*0.25) * HealthIncreaseRate; break;
1356 case PRIEST: addvalue = (Spirit*0.15 + 1.4) * HealthIncreaseRate; break;
1357 case ROGUE: addvalue = (Spirit*0.84 - 13) * HealthIncreaseRate; break;
1358 case SHAMAN: addvalue = (Spirit*0.28 - 3.6) * HealthIncreaseRate; break;
1359 case WARLOCK: addvalue = (Spirit*0.12 + 1.5) * HealthIncreaseRate; break;
1360 case WARRIOR: addvalue = (Spirit*1.26 - 22.6) * HealthIncreaseRate; break;
1363 if (!isInCombat())
1365 AuraList& mModHealthRegenPct = GetAurasByType(SPELL_AURA_MOD_HEALTH_REGEN_PERCENT);
1366 for(AuraList::iterator i = mModHealthRegenPct.begin(); i != mModHealthRegenPct.end(); ++i)
1367 addvalue *= (100.0f + (*i)->GetModifier()->m_amount) / 100.0f;
1369 else
1370 addvalue *= m_AuraModifiers[SPELL_AURA_MOD_REGEN_DURING_COMBAT] / 100.0f;
1372 switch (getStandState())
1374 case PLAYER_STATE_SIT_CHAIR:
1375 case PLAYER_STATE_SIT_LOW_CHAIR:
1376 case PLAYER_STATE_SIT_MEDIUM_CHAIR:
1377 case PLAYER_STATE_SIT_HIGH_CHAIR:
1378 case PLAYER_STATE_SIT:
1379 case PLAYER_STATE_SLEEP:
1380 case PLAYER_STATE_KNEEL:
1381 addvalue *= 1.5; break;
1383 ModifyHealth(int32(addvalue));
1386 bool Player::isAcceptTickets() const
1388 return GetSession()->GetSecurity() >=2 && (m_GMFlags & GM_ACCEPT_TICKETS);
1391 void Player::SetGameMaster(bool on)
1393 if(on)
1395 m_GMFlags |= GM_ON;
1396 setFaction(35);
1397 SetFlag(PLAYER_BYTES_2, 0x8);
1399 // to prevent show <GM> in invisible mode
1400 if(isGMVisible())
1401 SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_GM);
1403 else
1405 m_GMFlags &= ~GM_ON;
1406 setFactionForRace(getRace());
1407 RemoveFlag(PLAYER_BYTES_2, 0x8);
1408 RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_GM);
1412 void Player::SetGMVisible(bool on)
1414 if(on)
1416 m_GMFlags &= ~GM_INVISIBLE; //remove flag
1418 // if in GM mode show <GM> befire removing invisibility
1419 if(isGameMaster())
1420 SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_GM);
1422 DeMorph();
1423 RemoveAura(10032,1); //crash?
1426 else
1428 m_GMFlags |= GM_INVISIBLE; //add flag
1430 // remove <AFK> before go to invisible mode
1431 if(isAFK())
1432 ToggleAFK();
1434 // remove <DND> before go to invisible mode
1435 if(isDND())
1436 ToggleDND();
1438 SetAcceptWhispers(false);
1439 SetGameMaster(true); // <GM> wiil be not added
1441 SetUInt32Value(UNIT_FIELD_DISPLAYID, 6908); //Set invisible model
1443 //Stealth spell
1444 SpellEntry *spellInfo = sSpellStore.LookupEntry( 10032 );
1445 Aura *Aur = new Aura(spellInfo, 1, this);
1446 AddAura(Aur);
1449 // hide or show name
1450 GetSession()->SendNameQueryOpcode(this,true);
1453 void Player::SendLogXPGain(uint32 GivenXP, Unit* victim, uint32 RestXP)
1455 WorldPacket data;
1456 data.Initialize( SMSG_LOG_XPGAIN );
1457 data << ( victim ? victim->GetGUID() : uint64(0) );
1458 data << uint32(GivenXP+RestXP); // given experience
1459 data << ( victim ? (uint8)0 : (uint8)1 ); // 00-kill_xp type, 01-non_kill_xp type
1460 data << uint32(RestXP); // rested given experience
1461 data << float(1); // 1 - none 0 - 100% group bonus output
1462 GetSession()->SendPacket(&data);
1465 void Player::GiveXP(uint32 xp, Unit* victim)
1467 if ( xp < 1 )
1468 return;
1470 uint32 level = getLevel();
1472 // XP to money conversion processed in Player::RewardQuest
1473 if(level >= sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
1474 return;
1476 // XP resting bonus for kill
1477 uint32 rested_bonus_xp = victim ? GetXPRestBonus(xp) : 0;
1479 SendLogXPGain(xp,victim,rested_bonus_xp);
1481 uint32 curXP = GetUInt32Value(PLAYER_XP);
1482 uint32 nextLvlXP = GetUInt32Value(PLAYER_NEXT_LEVEL_XP);
1483 uint32 newXP = curXP + xp + rested_bonus_xp;
1485 while( newXP >= nextLvlXP && level < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL) )
1487 newXP -= nextLvlXP;
1489 GiveLevel();
1491 level = getLevel();
1492 nextLvlXP = GetUInt32Value(PLAYER_NEXT_LEVEL_XP);
1495 SetUInt32Value(PLAYER_XP, newXP);
1498 // Update player to next level
1499 // Current player expirience not update (must be update by caller)
1500 void Player::GiveLevel()
1502 uint32 MPGain,HPGain;
1503 MPGain=HPGain=0;
1505 uint32 level = getLevel();
1507 if ( level >= sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL) )
1508 return;
1510 level += 1;
1512 // Remove item, aura, stats bonuses
1513 _RemoveAllItemMods();
1514 _RemoveAllAuraMods();
1515 _RemoveStatsMods();
1517 // base stats
1518 float newMP = (getClass() == WARRIOR || getClass() == ROGUE) ? 0 : GetMaxPower(POWER_MANA);
1520 float newHP = GetMaxHealth();
1522 float newStats[MAX_STATS];
1524 for(int i = STAT_STRENGTH; i < MAX_STATS; ++i)
1525 newStats[i] = GetStat(Stats(i));
1527 uint32 gainStats[MAX_STATS];
1529 for(int i = STAT_STRENGTH; i < MAX_STATS; ++i)
1530 gainStats[i] = 0;
1532 // Gain stats
1533 BuildLvlUpStats(&gainStats);
1535 // Apply gain stats
1536 for(int i = STAT_STRENGTH; i < MAX_STATS; ++i)
1537 newStats[i] += gainStats[i];
1539 MPGain = (getClass() == WARRIOR || getClass() == ROGUE) ? 0 : uint32(newStats[STAT_SPIRIT] / 2);
1540 HPGain = uint32(newStats[STAT_STAMINA] / 2);
1542 newMP += MPGain;
1543 newHP += HPGain;
1545 // update level, talants, max level of skills
1546 SetLevel( level);
1547 SetUInt32Value(PLAYER_NEXT_LEVEL_XP, MaNGOS::XP::xp_to_level(level));
1549 if( level > 9)
1550 SetUInt32Value(PLAYER_CHARACTER_POINTS1,GetUInt32Value(PLAYER_CHARACTER_POINTS1)+1);
1552 UpdateMaxSkills ();
1554 // save new stats
1555 if(getClass() != WARRIOR && getClass() != ROGUE)
1557 SetPower( POWER_MANA, uint32(newMP)); // only integer part
1558 SetMaxPower(POWER_MANA, uint32(newMP)); // only integer part
1561 SetHealth( uint32(newHP)); // only integer part
1562 SetMaxHealth(uint32(newHP)); // only integer part
1564 for(int i = STAT_STRENGTH; i < MAX_STATS; ++i)
1565 SetStat(Stats(i), uint32(newStats[i])); // only integer part
1567 // update dependent from level part BlockChanceWithoutMods = 5 + (GetDefenceSkillValue() - getLevel()*5)*0.04);
1568 UpdateBlockPercentage(0,1);
1570 // apply stats, aura, items mods
1571 _ApplyStatsMods();
1572 _ApplyAllAuraMods();
1573 _ApplyAllItemMods();
1575 // send levelup info to client
1576 WorldPacket data;
1577 data.Initialize(SMSG_LEVELUP_INFO);
1578 data << uint32(level);
1579 data << uint32(HPGain);
1580 data << uint32(MPGain);
1581 data << uint32(0);
1582 data << uint32(0);
1583 data << uint32(0);
1584 data << uint32(0);
1586 for(int i = STAT_STRENGTH; i < MAX_STATS; ++i)
1587 data << uint32(gainStats[i]);
1589 WPAssert(data.size() == 48);
1590 GetSession()->SendPacket(&data);
1592 // Level Played Time reset
1593 m_Played_time[1] = 0;
1596 void Player::BuildLvlUpStats(uint32 (*gainStats)[MAX_STATS])
1598 uint8 _class = getClass();
1599 uint8 lvl = getLevel();
1600 uint8 race = getRace();
1602 if (lvl < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
1604 for(int i = STAT_STRENGTH; i < MAX_STATS; ++i)
1605 (*gainStats)[i] += objmgr.GetLevelUpStatGain(_class,race,lvl,Stats(i));
1607 else
1609 switch(_class)
1611 case WARRIOR:
1612 (*gainStats)[STAT_STRENGTH] += (lvl > 23 ? 2: (lvl > 1 ? 1: 0));
1613 (*gainStats)[STAT_STAMINA] += (lvl > 23 ? 2: (lvl > 1 ? 1: 0));
1614 (*gainStats)[STAT_AGILITY] += (lvl > 36 ? 1: (lvl > 6 && (lvl%2) ? 1: 0));
1615 (*gainStats)[STAT_INTELLECT] += (lvl > 9 && !(lvl%2) ? 1: 0);
1616 (*gainStats)[STAT_SPIRIT] += (lvl > 9 && !(lvl%2) ? 1: 0);
1617 break;
1618 case PALADIN:
1619 (*gainStats)[STAT_STRENGTH] += (lvl > 3 ? 1: 0);
1620 (*gainStats)[STAT_STAMINA] += (lvl > 33 ? 2: (lvl > 1 ? 1: 0));
1621 (*gainStats)[STAT_AGILITY] += (lvl > 38 ? 1: (lvl > 7 && !(lvl%2) ? 1: 0));
1622 (*gainStats)[STAT_INTELLECT] += (lvl > 6 && (lvl%2) ? 1: 0);
1623 (*gainStats)[STAT_SPIRIT] += (lvl > 7 ? 1: 0);
1624 break;
1625 case HUNTER:
1626 (*gainStats)[STAT_STRENGTH] += (lvl > 4 ? 1: 0);
1627 (*gainStats)[STAT_STAMINA] += (lvl > 4 ? 1: 0);
1628 (*gainStats)[STAT_AGILITY] += (lvl > 33 ? 2: (lvl > 1 ? 1: 0));
1629 (*gainStats)[STAT_INTELLECT] += (lvl > 8 && (lvl%2) ? 1: 0);
1630 (*gainStats)[STAT_SPIRIT] += (lvl > 38 ? 1: (lvl > 9 && !(lvl%2) ? 1: 0));
1631 break;
1632 case ROGUE:
1633 (*gainStats)[STAT_STRENGTH] += (lvl > 5 ? 1: 0);
1634 (*gainStats)[STAT_STAMINA] += (lvl > 4 ? 1: 0);
1635 (*gainStats)[STAT_AGILITY] += (lvl > 16 ? 2: (lvl > 1 ? 1: 0));
1636 (*gainStats)[STAT_INTELLECT] += (lvl > 8 && !(lvl%2) ? 1: 0);
1637 (*gainStats)[STAT_SPIRIT] += (lvl > 38 ? 1: (lvl > 9 && !(lvl%2) ? 1: 0));
1638 break;
1639 case PRIEST:
1640 (*gainStats)[STAT_STRENGTH] += (lvl > 9 && !(lvl%2) ? 1: 0);
1641 (*gainStats)[STAT_STAMINA] += (lvl > 5 ? 1: 0);
1642 (*gainStats)[STAT_AGILITY] += (lvl > 38 ? 1: (lvl > 8 && (lvl%2) ? 1: 0));
1643 (*gainStats)[STAT_INTELLECT] += (lvl > 22 ? 2: (lvl > 1 ? 1: 0));
1644 (*gainStats)[STAT_SPIRIT] += (lvl > 3 ? 1: 0);
1645 break;
1646 case SHAMAN:
1647 (*gainStats)[STAT_STRENGTH] += (lvl > 34 ? 1: (lvl > 6 && (lvl%2) ? 1: 0));
1648 (*gainStats)[STAT_STAMINA] += (lvl > 4 ? 1: 0);
1649 (*gainStats)[STAT_AGILITY] += (lvl > 7 && !(lvl%2) ? 1: 0);
1650 (*gainStats)[STAT_INTELLECT] += (lvl > 5 ? 1: 0);
1651 (*gainStats)[STAT_SPIRIT] += (lvl > 4 ? 1: 0);
1652 break;
1653 case MAGE:
1654 (*gainStats)[STAT_STRENGTH] += (lvl > 9 && !(lvl%2) ? 1: 0);
1655 (*gainStats)[STAT_STAMINA] += (lvl > 5 ? 1: 0);
1656 (*gainStats)[STAT_AGILITY] += (lvl > 9 && !(lvl%2) ? 1: 0);
1657 (*gainStats)[STAT_INTELLECT] += (lvl > 24 ? 2: (lvl > 1 ? 1: 0));
1658 (*gainStats)[STAT_SPIRIT] += (lvl > 33 ? 2: (lvl > 2 ? 1: 0));
1659 break;
1660 case WARLOCK:
1661 (*gainStats)[STAT_STRENGTH] += (lvl > 9 && !(lvl%2) ? 1: 0);
1662 (*gainStats)[STAT_STAMINA] += (lvl > 38 ? 2: (lvl > 3 ? 1: 0));
1663 (*gainStats)[STAT_AGILITY] += (lvl > 9 && !(lvl%2) ? 1: 0);
1664 (*gainStats)[STAT_INTELLECT] += (lvl > 33 ? 2: (lvl > 2 ? 1: 0));
1665 (*gainStats)[STAT_SPIRIT] += (lvl > 38 ? 2: (lvl > 3 ? 1: 0));
1666 break;
1667 case DRUID:
1668 (*gainStats)[STAT_STRENGTH] += (lvl > 38 ? 2: (lvl > 6 && (lvl%2) ? 1: 0));
1669 (*gainStats)[STAT_STAMINA] += (lvl > 32 ? 2: (lvl > 4 ? 1: 0));
1670 (*gainStats)[STAT_AGILITY] += (lvl > 38 ? 2: (lvl > 8 && (lvl%2) ? 1: 0));
1671 (*gainStats)[STAT_INTELLECT] += (lvl > 38 ? 3: (lvl > 4 ? 1: 0));
1672 (*gainStats)[STAT_SPIRIT] += (lvl > 38 ? 3: (lvl > 5 ? 1: 0));
1677 void Player::SendInitialSpells()
1679 WorldPacket data;
1680 uint16 spellCount = 0;
1682 PlayerSpellMap::const_iterator itr;
1684 for (itr = m_spells.begin(); itr != m_spells.end(); ++itr)
1686 if(itr->second->state == PLAYERSPELL_REMOVED)
1687 continue;
1689 if(itr->second->active)
1690 spellCount +=1;
1693 data.Initialize( SMSG_INITIAL_SPELLS );
1694 data << uint8(0);
1695 data << uint16(spellCount);
1697 for (itr = m_spells.begin(); itr != m_spells.end(); ++itr)
1699 if(itr->second->state == PLAYERSPELL_REMOVED)
1700 continue;
1702 if(!itr->second->active)
1703 continue;
1705 data << uint16(itr->first);
1706 data << uint16(itr->second->slotId);
1708 data << uint16(0);
1710 WPAssert(data.size() == 5+(4*size_t(spellCount)));
1712 GetSession()->SendPacket(&data);
1714 sLog.outDetail( "CHARACTER: Sent Initial Spells" );
1717 void Player::RemoveMail(uint32 id)
1719 std::list<Mail*>::iterator itr;
1720 for (itr = m_mail.begin(); itr != m_mail.end();)
1722 if ((*itr)->messageID == id)
1724 //do not delete item. beacuse Player::removeMail() is called when returning mail to sender.
1725 m_mail.erase(itr++);
1727 else
1729 ++itr;
1734 //called when mail's state changed, removes mail and adds it to the end - mails are sorted
1735 void Player::SetMail(Mail *m)
1737 if (!m_mailsLoaded)
1738 return;
1740 std::list<Mail*>::iterator itr;
1741 for (itr = m_mail.begin(); itr != m_mail.end();)
1743 if ((*itr)->messageID == m->messageID)
1744 m_mail.erase(itr++);
1745 else
1746 ++itr;
1748 m_mail.push_back(m); //insert to the end
1751 //call this function only when sending new mail
1752 void Player::AddMail(Mail *m)
1754 WorldPacket data;
1756 data.Initialize(SMSG_RECEIVED_MAIL);
1757 data << uint32(0);
1758 GetSession()->SendPacket(&data);
1759 unReadMails++;
1761 if(!m_mailsLoaded)
1762 return;
1764 std::list<Mail*>::iterator itr;
1765 for (itr = m_mail.begin(); itr != m_mail.end();)
1767 if ((*itr)->messageID == m->messageID)
1769 m_mail.erase(itr++);
1771 else
1773 ++itr;
1776 m_mail.push_front(m); //to insert new mail to beginning of maillist
1779 bool Player::addSpell(uint16 spell_id, uint8 active, PlayerSpellState state, uint16 slot_id)
1781 SpellEntry *spellInfo = sSpellStore.LookupEntry(spell_id);
1782 if (!spellInfo)
1784 sLog.outError("Player::addSpell: Non-existed in SpellStore spell #%u request.",spell_id);
1785 return false;
1788 PlayerSpellMap::iterator itr = m_spells.find(spell_id);
1789 if (itr != m_spells.end())
1791 if (itr->second->state == PLAYERSPELL_REMOVED)
1793 delete itr->second;
1794 m_spells.erase(itr);
1795 state = PLAYERSPELL_CHANGED;
1797 else
1798 return false;
1801 PlayerSpell *newspell;
1803 newspell = new PlayerSpell;
1804 newspell->active = active;
1805 newspell->state = state;
1807 WorldPacket data;
1808 if(newspell->active && !canStackSpellRank(spellInfo))
1810 PlayerSpellMap::iterator itr;
1811 for (itr = m_spells.begin(); itr != m_spells.end(); itr++)
1813 if(itr->second->state == PLAYERSPELL_REMOVED) continue;
1814 SpellEntry *i_spellInfo = sSpellStore.LookupEntry(itr->first);
1815 if(!i_spellInfo) continue;
1817 if(IsRankSpellDueToSpell(spellInfo,itr->first))
1819 if(itr->second->active)
1821 data.Initialize(SMSG_SUPERCEDED_SPELL);
1823 if(FindSpellRank(spell_id) >= FindSpellRank(itr->first))
1825 data << uint32(itr->first);
1826 data << uint32(spell_id);
1827 itr->second->active = 0;
1829 else
1831 data << uint32(spell_id);
1832 data << uint32(itr->first);
1833 newspell->active = 0;
1836 GetSession()->SendPacket( &data );
1842 uint16 tmpslot=slot_id;
1844 if (tmpslot == 0xffff)
1846 uint16 maxid = 0;
1847 PlayerSpellMap::iterator itr;
1848 for (itr = m_spells.begin(); itr != m_spells.end(); ++itr)
1850 if(itr->second->state == PLAYERSPELL_REMOVED) continue;
1851 if (itr->second->slotId > maxid) maxid = itr->second->slotId;
1853 tmpslot = maxid + 1;
1856 newspell->slotId = tmpslot;
1857 m_spells[spell_id] = newspell;
1859 if (IsPassiveSpell(spell_id))
1861 // if spell doesnt require a stance or the player is in the required stance
1862 if ((!spellInfo->Stances && spell_id != 5419) || (spellInfo->Stances & (1<<(m_form-1)) || (spell_id == 5419 && m_form == FORM_TRAVEL)))
1863 CastSpell(this, spell_id, true);
1866 return true;
1869 void Player::learnSpell(uint16 spell_id)
1871 SpellEntry *spellInfo = sSpellStore.LookupEntry(spell_id);
1872 if (!spellInfo)
1874 sLog.outError("Player::addSpell: Non-existed in SpellStore spell #%u request.",spell_id);
1875 return;
1878 WorldPacket data;
1879 data.Initialize(SMSG_LEARNED_SPELL);
1880 data <<uint32(spell_id);
1881 GetSession()->SendPacket(&data);
1883 if (!addSpell(spell_id,1))
1884 return;
1886 uint16 maxskill = getLevel()*5 > 300 ? 300 :getLevel()*5;
1887 switch(spell_id)
1889 //Armor
1890 case 9078: //Cloth
1891 SetSkill(415,1,1);
1892 break;
1893 case 9077: //Leather
1894 SetSkill(414,1,1);
1895 break;
1896 case 8737: //Mail
1897 SetSkill(413,1,1);
1898 break;
1899 case 750: //Plate Mail
1900 SetSkill(293,1,1);
1901 break;
1902 case 9116: //Shield
1903 SetSkill(433,1,1);
1904 break;
1905 //Melee Weapons
1906 case 196: //Axes
1907 SetSkill(44,1,maxskill);
1908 break;
1909 case 197: //Two-Handed Axes
1910 SetSkill(172,1,maxskill);
1911 break;
1912 case 227: //Staves
1913 SetSkill(136,1,maxskill);
1914 break;
1915 case 198: //Maces
1916 SetSkill(54,1,maxskill);
1917 break;
1918 case 199: //Two-Handed Maces
1919 SetSkill(160,1,maxskill);
1920 break;
1921 case 201: //Swords
1922 SetSkill(43,1,maxskill);
1923 break;
1924 case 202: //Two-Handed Swords
1925 SetSkill(55,1,maxskill);
1926 break;
1927 case 1180: //Daggers
1928 SetSkill(173,1,maxskill);
1929 break;
1930 case 15590: //Fist Weapons
1931 SetSkill(473,1,maxskill);
1932 break;
1933 case 200: //Polearms
1934 SetSkill(229,1,maxskill);
1935 break;
1936 case 3386: //Polearms
1937 SetSkill(227,1,maxskill);
1938 break;
1939 //Range Weapons
1940 case 264: //Bows
1941 SetSkill(45,1,maxskill);
1942 break;
1943 case 5011: //Crossbows
1944 SetSkill(226,1,maxskill);
1945 break;
1946 case 266: //Guns
1947 SetSkill(46,1,maxskill);
1948 break;
1949 case 2567: //Thrown
1950 SetSkill(176,1,maxskill);
1951 break;
1952 case 5009: //Wands
1953 SetSkill(228,1,maxskill);
1954 break;
1955 //Others
1956 case 2842: //poisons
1957 SetSkill(40,1,maxskill);
1958 break;
1959 // Languages
1960 case 668:
1961 SetSkill(98,1,300);
1962 break;
1963 case 669:
1964 SetSkill(109,1,300);
1965 break;
1966 case 670:
1967 SetSkill(115,1,300);
1968 break;
1969 case 671:
1970 SetSkill(113,1,300);
1971 break;
1972 case 672:
1973 SetSkill(111,1,300);
1974 break;
1975 case 813:
1976 SetSkill(137,1,300);
1977 break;
1978 case 814:
1979 SetSkill(138,1,300);
1980 break;
1981 case 815:
1982 SetSkill(139,1,300);
1983 break;
1984 case 816:
1985 SetSkill(140,1,300);
1986 break;
1987 case 817:
1988 SetSkill(141,1,300);
1989 break;
1990 case 7340:
1991 SetSkill(313,1,300);
1992 break;
1993 case 7341:
1994 SetSkill(315,1,300);
1995 break;
1996 case 17737:
1997 SetSkill(673,1,300);
1998 break;
1999 default:break;
2003 bool Player::removeSpell(uint16 spell_id)
2005 PlayerSpellMap::iterator itr = m_spells.find(spell_id);
2006 if (itr != m_spells.end())
2008 if(itr->second->state == PLAYERSPELL_REMOVED) return false;
2010 WorldPacket data;
2011 data.Initialize(SMSG_REMOVED_SPELL);
2012 data << itr->first;
2013 GetSession()->SendPacket(&data);
2015 if(itr->second->state == PLAYERSPELL_NEW)
2017 delete itr->second;
2018 m_spells.erase(itr);
2020 else
2021 itr->second->state = PLAYERSPELL_REMOVED;
2023 RemoveAurasDueToSpell(spell_id);
2024 return true;
2026 return false;
2029 uint32 Player::resetTalentsCost() const
2031 // The first time reset costs 1 gold
2032 if(m_resetTalentsCost < 1*GOLD)
2033 return 1*GOLD;
2034 // then 5 gold
2035 else if(m_resetTalentsCost < 5*GOLD)
2036 return 5*GOLD;
2037 // After that it increases in increments of 5 gold
2038 else if(m_resetTalentsCost < 10*GOLD)
2039 return 10*GOLD;
2040 else
2042 uint32 months = (sWorld.GetLastTickTime() - m_resetTalentsTime)/MONTH;
2043 if(months > 0)
2045 // This cost will be reduced by a rate of 5 gold per month
2046 int32 new_cost = int32(m_resetTalentsCost) - 5*GOLD*months;
2047 // to a minimum of 10 gold.
2048 return (new_cost < 10*GOLD ? 10*GOLD : new_cost);
2050 else
2052 // After that it increases in increments of 5 gold
2053 int32 new_cost = m_resetTalentsCost + 5*GOLD;
2054 // until it hits a cap of 50 gold.
2055 if(new_cost > 50*GOLD)
2056 new_cost = 50*GOLD;
2057 return new_cost;
2062 bool Player::resetTalents()
2064 uint32 level = getLevel();
2065 if (level < 10 || (GetUInt32Value(PLAYER_CHARACTER_POINTS1) >= level - 9))
2066 return false;
2068 uint32 cost = resetTalentsCost();
2070 if (GetMoney() < cost)
2072 SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, 0, 0, 0);
2073 return false;
2076 for (int i = 0; i < sTalentStore.GetNumRows(); i++)
2078 TalentEntry *talentInfo = sTalentStore.LookupEntry(i);
2079 if (!talentInfo) continue;
2080 for (int j = 0; j < 5; j++)
2082 SpellEntry *spellInfo = sSpellStore.LookupEntry(talentInfo->RankID[j]);
2083 if (!spellInfo) continue;
2084 const PlayerSpellMap& s_list = GetSpellMap();
2085 for(PlayerSpellMap::const_iterator itr = s_list.begin(); itr != s_list.end(); ++itr)
2087 if(itr->second->state == PLAYERSPELL_REMOVED) continue;
2088 if (itr->first == spellInfo->Id)
2090 RemoveAurasDueToSpell(itr->first);
2091 removeSpell(itr->first);
2092 break;
2098 SetUInt32Value(PLAYER_CHARACTER_POINTS1, level - 9);
2099 ModifyMoney(-(int32)cost);
2101 m_resetTalentsCost = cost;
2102 m_resetTalentsTime = time(NULL);
2103 return true;
2106 bool Player::_removeSpell(uint16 spell_id)
2108 PlayerSpellMap::iterator itr = m_spells.find(spell_id);
2109 if (itr != m_spells.end())
2111 delete itr->second;
2112 m_spells.erase(itr);
2113 return true;
2115 return false;
2118 Mail* Player::GetMail(uint32 id)
2120 std::list<Mail*>::iterator itr;
2121 for (itr = m_mail.begin(); itr != m_mail.end(); itr++)
2123 if ((*itr)->messageID == id)
2125 return (*itr);
2128 return NULL;
2131 void Player::_SetCreateBits(UpdateMask *updateMask, Player *target) const
2133 if(target == this)
2135 Object::_SetCreateBits(updateMask, target);
2137 else
2139 UpdateMask mask;
2140 mask.SetCount(m_valuesCount);
2141 _SetVisibleBits(&mask, target);
2143 for(uint16 index = 0; index < m_valuesCount; index++)
2145 if(GetUInt32Value(index) != 0 && mask.GetBit(index))
2146 updateMask->SetBit(index);
2151 void Player::_SetUpdateBits(UpdateMask *updateMask, Player *target) const
2153 if(target == this)
2155 Object::_SetUpdateBits(updateMask, target);
2157 else
2159 UpdateMask mask;
2160 mask.SetCount(m_valuesCount);
2161 _SetVisibleBits(&mask, target);
2163 Object::_SetUpdateBits(updateMask, target);
2164 *updateMask &= mask;
2168 void Player::_SetVisibleBits(UpdateMask *updateMask, Player *target) const
2170 updateMask->SetBit(OBJECT_FIELD_GUID);
2171 updateMask->SetBit(OBJECT_FIELD_TYPE);
2172 updateMask->SetBit(OBJECT_FIELD_SCALE_X);
2174 updateMask->SetBit(UNIT_FIELD_SUMMON);
2175 updateMask->SetBit(UNIT_FIELD_SUMMON+1);
2177 updateMask->SetBit(UNIT_FIELD_TARGET);
2178 updateMask->SetBit(UNIT_FIELD_TARGET+1);
2180 updateMask->SetBit(UNIT_FIELD_HEALTH);
2181 updateMask->SetBit(UNIT_FIELD_POWER1);
2182 updateMask->SetBit(UNIT_FIELD_POWER2);
2183 updateMask->SetBit(UNIT_FIELD_POWER3);
2184 updateMask->SetBit(UNIT_FIELD_POWER4);
2185 updateMask->SetBit(UNIT_FIELD_POWER5);
2187 updateMask->SetBit(UNIT_FIELD_MAXHEALTH);
2188 updateMask->SetBit(UNIT_FIELD_MAXPOWER1);
2189 updateMask->SetBit(UNIT_FIELD_MAXPOWER2);
2190 updateMask->SetBit(UNIT_FIELD_MAXPOWER3);
2191 updateMask->SetBit(UNIT_FIELD_MAXPOWER4);
2192 updateMask->SetBit(UNIT_FIELD_MAXPOWER5);
2194 updateMask->SetBit(UNIT_FIELD_LEVEL);
2195 updateMask->SetBit(UNIT_FIELD_FACTIONTEMPLATE);
2196 updateMask->SetBit(UNIT_FIELD_BYTES_0);
2197 updateMask->SetBit(UNIT_FIELD_FLAGS);
2198 for(uint16 i = UNIT_FIELD_AURA; i < UNIT_FIELD_AURASTATE; i ++)
2199 updateMask->SetBit(i);
2200 updateMask->SetBit(UNIT_FIELD_BASEATTACKTIME);
2201 updateMask->SetBit(UNIT_FIELD_OFFHANDATTACKTIME);
2202 updateMask->SetBit(UNIT_FIELD_RANGEDATTACKTIME);
2203 updateMask->SetBit(UNIT_FIELD_BOUNDINGRADIUS);
2204 updateMask->SetBit(UNIT_FIELD_COMBATREACH);
2205 updateMask->SetBit(UNIT_FIELD_DISPLAYID);
2206 updateMask->SetBit(UNIT_FIELD_NATIVEDISPLAYID);
2207 updateMask->SetBit(UNIT_FIELD_MOUNTDISPLAYID);
2208 updateMask->SetBit(UNIT_FIELD_BYTES_1);
2209 updateMask->SetBit(UNIT_FIELD_MOUNTDISPLAYID);
2210 updateMask->SetBit(UNIT_FIELD_PETNUMBER);
2211 updateMask->SetBit(UNIT_FIELD_PET_NAME_TIMESTAMP);
2212 updateMask->SetBit(UNIT_DYNAMIC_FLAGS);
2214 updateMask->SetBit(PLAYER_FLAGS);
2215 updateMask->SetBit(PLAYER_BYTES);
2216 updateMask->SetBit(PLAYER_BYTES_2);
2217 updateMask->SetBit(PLAYER_BYTES_3);
2218 updateMask->SetBit(PLAYER_GUILDID);
2219 updateMask->SetBit(PLAYER_GUILDRANK);
2220 updateMask->SetBit(PLAYER_GUILD_TIMESTAMP);
2222 for(uint16 i = 0; i < INVENTORY_SLOT_BAG_END; i++)
2225 updateMask->SetBit((uint16)(PLAYER_FIELD_INV_SLOT_HEAD + i*2));
2227 updateMask->SetBit((uint16)(PLAYER_FIELD_INV_SLOT_HEAD + (i*2) + 1));
2230 //Players visible items are not inventory stuff
2231 //431) = 884 (0x374) = main weapon
2232 for(uint16 i = 0; i < EQUIPMENT_SLOT_END; i++)
2234 updateMask->SetBit((uint16)(PLAYER_VISIBLE_ITEM_1_0 + (i*12)));
2235 //updateMask->SetBit((uint16)(PLAYER_VISIBLE_ITEM_1_0 + 1 + (i*12)));
2238 updateMask->SetBit(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY);
2239 updateMask->SetBit(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY_01);
2240 updateMask->SetBit(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY_02);
2241 updateMask->SetBit(UNIT_VIRTUAL_ITEM_INFO);
2242 updateMask->SetBit(UNIT_VIRTUAL_ITEM_INFO_01);
2243 updateMask->SetBit(UNIT_VIRTUAL_ITEM_INFO_02);
2244 updateMask->SetBit(UNIT_VIRTUAL_ITEM_INFO_03);
2245 updateMask->SetBit(UNIT_VIRTUAL_ITEM_INFO_04);
2246 updateMask->SetBit(UNIT_VIRTUAL_ITEM_INFO_05);
2250 void Player::BuildCreateUpdateBlockForPlayer( UpdateData *data, Player *target ) const
2253 for(int i = 0; i < EQUIPMENT_SLOT_END; i++)
2255 if(m_items[i] == NULL)
2256 continue;
2258 m_items[i]->BuildCreateUpdateBlockForPlayer( data, target );
2261 if(target == this)
2264 for(int i = EQUIPMENT_SLOT_END; i < BANK_SLOT_BAG_END; i++)
2266 if(m_items[i] == NULL)
2267 continue;
2269 m_items[i]->BuildCreateUpdateBlockForPlayer( data, target );
2273 Unit::BuildCreateUpdateBlockForPlayer( data, target );
2276 void Player::DestroyForPlayer( Player *target ) const
2278 Unit::DestroyForPlayer( target );
2280 for(int i = 0; i < INVENTORY_SLOT_BAG_END; i++)
2282 if(m_items[i] == NULL)
2283 continue;
2285 m_items[i]->DestroyForPlayer( target );
2288 if(target == this)
2291 for(int i = EQUIPMENT_SLOT_END; i < BANK_SLOT_BAG_END; i++)
2293 if(m_items[i] == NULL)
2294 continue;
2296 m_items[i]->DestroyForPlayer( target );
2301 bool Player::HasSpell(uint32 spell) const
2303 PlayerSpellMap::const_iterator itr = m_spells.find((uint16)spell);
2304 return (itr != m_spells.end() && itr->second->state != PLAYERSPELL_REMOVED);
2306 // Look in the effects of spell , if is a Learn Spell Effect, see if is equal to triggerspell
2307 // If inst, look if have this spell.
2308 /*for (PlayerSpellMap::const_iterator itr = m_spells.begin(); itr != m_spells.end(); ++itr)
2310 for(uint8 i=0;i<3;i++)
2312 if(spellInfo->Effect[i]==36) // Learn Spell effect
2314 if ( itr->first == spellInfo->EffectTriggerSpell[i] )
2315 return true;
2317 else if(itr->first == spellInfo->Id)
2318 return true;
2322 return false;*/
2325 bool Player::CanLearnProSpell(uint32 spell)
2327 SpellEntry *spellInfo = sSpellStore.LookupEntry(spell);
2329 if (!spellInfo)
2330 return false;
2331 if(spellInfo->Effect[0] != 36)
2332 return true;
2334 uint32 skill = spellInfo->EffectMiscValue[1];
2335 uint32 value = 0;
2337 if( skill != SKILL_HERBALISM && skill != SKILL_MINING && skill != SKILL_LEATHERWORKING
2338 && skill != SKILL_BLACKSMITHING && skill != SKILL_ALCHEMY && skill != SKILL_ENCHANTING
2339 && skill != SKILL_TAILORING && skill != SKILL_ENGINERING && skill != SKILL_SKINNING)
2340 return true;
2342 for (PlayerSpellMap::const_iterator itr = m_spells.begin(); itr != m_spells.end(); ++itr)
2344 if (itr->second->state == PLAYERSPELL_REMOVED) continue;
2345 SpellEntry *pSpellInfo = sSpellStore.LookupEntry(itr->first);
2346 if(!pSpellInfo) continue;
2348 if(pSpellInfo->Effect[1] == 118)
2350 uint32 pskill = pSpellInfo->EffectMiscValue[1];
2351 if( pskill != SKILL_HERBALISM && pskill != SKILL_MINING && pskill != SKILL_LEATHERWORKING
2352 && pskill != SKILL_BLACKSMITHING && pskill != SKILL_ALCHEMY && pskill != SKILL_ENCHANTING
2353 && pskill != SKILL_TAILORING && pskill != SKILL_ENGINERING && pskill != SKILL_SKINNING)
2354 continue;
2356 // not check prof count for not first prof. spells (when skill already known)
2357 if(pskill == skill)
2358 return true;
2360 // count only first rank prof. spells
2361 if(FindSpellRank(pSpellInfo->Id)==1)
2362 value += 1;
2365 if(value >= sWorld.getConfig(CONFIG_MAX_PRIMARY_TRADE_SKILL))
2366 return false;
2367 else return true;
2370 void Player::DeleteFromDB()
2372 uint32 guid = GetGUIDLow();
2374 // convert corpse to bones if exist (to prevent exiting Corpse in World without DB entry)
2375 // bones will be deleted by corpse/bones deleting thread shortly
2376 SpawnCorpseBones();
2378 // remove from guild
2379 if(GetGuildId() != 0)
2380 objmgr.GetGuildById(GetGuildId())->DelMember(guid);
2382 // remove signs from petitions (also remove petitions if owner);
2383 RemovePetitionsAndSigns(GetGUID());
2385 sDatabase.PExecute("DELETE FROM `character` WHERE `guid` = '%u'",guid);
2386 sDatabase.PExecute("DELETE FROM `character_aura` WHERE `guid` = '%u'",guid);
2387 sDatabase.PExecute("DELETE FROM `character_spell` WHERE `guid` = '%u'",guid);
2388 sDatabase.PExecute("DELETE FROM `character_tutorial` WHERE `guid` = '%u'",guid);
2389 sDatabase.PExecute("DELETE FROM `character_inventory` WHERE `guid` = '%u'",guid);
2390 sDatabase.PExecute("DELETE FROM `character_social` WHERE `guid` = '%u' OR `friend`='%u'",guid,guid);
2391 sDatabase.PExecute("DELETE FROM `mail` WHERE `receiver` = '%u'",guid);
2392 sDatabase.PExecute("DELETE FROM `character_pet` WHERE `owner` = '%u'",guid);
2394 //loginDatabase.PExecute("UPDATE `realmcharacters` SET `numchars` = `numchars` - 1 WHERE `acctid` = %d AND `realmid` = %d", GetSession()->GetAccountId(), realmID);
2395 QueryResult *resultCount = sDatabase.PQuery("SELECT COUNT(guid) FROM `character` WHERE `account` = '%d'", GetSession()->GetAccountId());
2396 uint32 charCount = 0;
2397 if (resultCount)
2399 Field *fields = resultCount->Fetch();
2400 charCount = fields[0].GetUInt32();
2401 delete resultCount;
2402 loginDatabase.PExecute("INSERT INTO `realmcharacters` (`numchars`, `acctid`, `realmid`) VALUES (%d, %d, %d) ON DUPLICATE KEY UPDATE `numchars` = '%d'", charCount, GetSession()->GetAccountId(), realmID, charCount);
2405 for(int i = 0; i < BANK_SLOT_ITEM_END; i++)
2407 if(m_items[i] == NULL)
2408 continue;
2409 m_items[i]->DeleteFromDB(); // Bag items delete also by virtual call Bag::DeleteFromDB
2412 sDatabase.PExecute("DELETE FROM `character_queststatus` WHERE `guid` = '%u'",guid);
2413 sDatabase.PExecute("DELETE FROM `character_action` WHERE `guid` = '%u'",guid);
2414 sDatabase.PExecute("DELETE FROM `character_reputation` WHERE `guid` = '%u'",guid);
2415 sDatabase.PExecute("DELETE FROM `character_homebind` WHERE `guid` = '%u'",guid);
2416 sDatabase.PExecute("DELETE FROM `character_kill` WHERE `guid` = '%u'",guid);
2417 sDatabase.PExecute("DELETE FROM `character_stable` WHERE `owner` = '%u'",guid);
2420 void Player::SetMovement(uint8 pType)
2422 WorldPacket data;
2424 switch(pType)
2426 case MOVE_ROOT:
2428 data.Initialize(SMSG_FORCE_MOVE_ROOT);
2429 data << uint8(0xFF) << GetGUID();
2430 GetSession()->SendPacket( &data );
2431 }break;
2432 case MOVE_UNROOT:
2434 data.Initialize(SMSG_FORCE_MOVE_UNROOT);
2435 data << uint8(0xFF) << GetGUID();
2436 GetSession()->SendPacket( &data );
2437 }break;
2438 case MOVE_WATER_WALK:
2440 data.Initialize(SMSG_MOVE_WATER_WALK);
2441 data << uint8(0xFF) << GetGUID();
2442 GetSession()->SendPacket( &data );
2443 }break;
2444 case MOVE_LAND_WALK:
2446 data.Initialize(SMSG_MOVE_LAND_WALK);
2447 data << uint8(0xFF) << GetGUID();
2448 GetSession()->SendPacket( &data );
2449 }break;
2450 default:break;
2454 void Player::SetPlayerSpeed(uint8 SpeedType, float value, bool forced)
2456 WorldPacket data;
2458 switch(SpeedType)
2460 case MOVE_RUN:
2462 SetSpeed( value / SPEED_RUN );
2463 if(forced) { data.Initialize(SMSG_FORCE_RUN_SPEED_CHANGE); }
2464 else { data.Initialize(MSG_MOVE_SET_RUN_SPEED); }
2465 data << uint8(0xFF);
2466 data << GetGUID();
2467 data << (uint32)0;
2468 data << float(value);
2469 GetSession()->SendPacket( &data );
2470 }break;
2471 case MOVE_WALKBACK:
2473 SetSpeed( value / SPEED_WALKBACK );
2474 if(forced) { data.Initialize(SMSG_FORCE_RUN_BACK_SPEED_CHANGE); }
2475 else { data.Initialize(MSG_MOVE_SET_RUN_BACK_SPEED); }
2476 data << uint8(0xFF);
2477 data << GetGUID();
2478 data << (uint32)0;
2479 data << float(value);
2480 GetSession()->SendPacket( &data );
2481 }break;
2482 case MOVE_SWIM:
2484 SetSpeed( value / SPEED_SWIM );
2485 if(forced) { data.Initialize(SMSG_FORCE_SWIM_SPEED_CHANGE); }
2486 else { data.Initialize(MSG_MOVE_SET_SWIM_SPEED); }
2487 data << uint8(0xFF);
2488 data << GetGUID();
2489 data << (uint32)0;
2490 data << float(value);
2491 GetSession()->SendPacket( &data );
2492 }break;
2493 case MOVE_SWIMBACK:
2495 SetSpeed( value / SPEED_SWIMBACK );
2496 data.Initialize(MSG_MOVE_SET_SWIM_BACK_SPEED);
2497 data << uint8(0xFF);
2498 data << GetGUID();
2499 data << (uint32)0;
2500 data << float(value);
2501 GetSession()->SendPacket( &data );
2502 }break;
2503 default:break;
2507 void Player::BuildPlayerRepop()
2509 // place corpse instead player body
2510 Corpse* corpse = GetCorpse();
2511 if(!corpse)
2512 corpse = CreateCorpse();
2514 // now show corpse for all
2515 MapManager::Instance().GetMap(corpse->GetMapId())->Add(corpse);
2517 // convert player body to ghost
2518 WorldPacket data;
2520 SetHealth( 1 );
2522 SetMovement(MOVE_WATER_WALK);
2523 SetMovement(MOVE_UNROOT);
2525 // setting new speed
2526 if (getRace() == RACE_NIGHT_ELF)
2528 SetPlayerSpeed(MOVE_RUN, (float)12.75, true);
2529 SetPlayerSpeed(MOVE_SWIM, (float)8.85, true);
2531 else
2533 SetPlayerSpeed(MOVE_RUN, (float)10.625, true);
2534 SetPlayerSpeed(MOVE_SWIM, (float)7.375, true);
2537 //! corpse reclaim delay 30 * 1000ms
2538 data.Initialize(SMSG_CORPSE_RECLAIM_DELAY );
2539 data << (uint32)(CORPSE_RECLAIM_DELAY*1000);
2540 GetSession()->SendPacket( &data );
2542 // to prevent cheating
2543 corpse->ResetGhostTime();
2545 //TODO: Check/research this
2546 data.Initialize(SMSG_SPELL_START );
2547 data << uint8(0xFF) << GetGUID() //9
2548 << uint8(0xFF) << GetGUID() //9
2549 //<< uint16(8326); //2
2550 << uint32(20305) //2
2551 << uint16(0x02)
2553 << uint32(0x00)<< uint16(0x00); //6
2554 GetSession()->SendPacket( &data );
2556 data.Initialize(SMSG_SPELL_GO);
2557 data << uint8(0xFF) << GetGUID() << uint8(0xFF) << GetGUID() << uint16(8326);
2558 /// uint8(0x0D) = probably race + 2
2559 data << uint16(0x00) << uint8(0x0D) << uint8(0x01)<< uint8(0x01) << GetGUID();
2560 data << uint32(0x00) << uint16(0x0200) << uint16(0x00);
2561 GetSession()->SendPacket( &data );
2563 data.Initialize(SMSG_UPDATE_AURA_DURATION);
2564 data << uint32(0x20) << uint8(0);
2565 GetSession()->SendPacket( &data );
2567 StopMirrorTimer(FATIGUE_TIMER); //disable timers(bars)
2568 StopMirrorTimer(BREATH_TIMER);
2569 StopMirrorTimer(FIRE_TIMER);
2571 SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_NONE | UNIT_FLAG_NOT_IN_PVP );
2572 SetUInt32Value(UNIT_FIELD_AURA + 32, 8326); // set ghost form
2573 SetUInt32Value(UNIT_FIELD_AURA + 33, 0x5068 ); //!dono
2575 SetUInt32Value(UNIT_FIELD_AURAFLAGS + 4, 0xEE);
2577 SetUInt32Value(UNIT_FIELD_AURASTATE, 0x02);
2579 SetFloatValue(UNIT_FIELD_BOUNDINGRADIUS,(float)1.0); //see radius of death player?
2581 SetUInt32Value(UNIT_FIELD_BYTES_1, 0x1000000); //Set standing so always be standing
2583 if (getRace() == RACE_NIGHT_ELF)
2584 SetUInt32Value(UNIT_FIELD_DISPLAYID, 10045); //10045 correct wisp model
2586 SetUInt32Value(PLAYER_FLAGS, PLAYER_FLAGS_GHOST);
2589 void Player::SendDelayResponse(const uint32 ml_seconds)
2591 WorldPacket data;
2592 data.Initialize( SMSG_QUERY_TIME_RESPONSE );
2593 data << (uint32)getMSTime();
2594 GetSession()->SendPacket( &data );
2597 void Player::ResurrectPlayer()
2599 // remove death flag + set aura
2600 RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST);
2602 // return the PvP enable flag to normal
2603 SetPvP( GetPvP() );
2605 setDeathState(ALIVE);
2607 SetMovement(MOVE_LAND_WALK);
2608 SetMovement(MOVE_UNROOT);
2610 SetPlayerSpeed(MOVE_RUN, (float)7.5, true);
2611 SetPlayerSpeed(MOVE_SWIM, (float)4.9, true);
2613 SetUInt32Value(CONTAINER_FIELD_SLOT_1+29, 0);
2615 SetUInt32Value(UNIT_FIELD_AURA+32, 0);
2616 SetUInt32Value(UNIT_FIELD_AURALEVELS+8, 0xeeeeeeee);
2617 SetUInt32Value(UNIT_FIELD_AURAAPPLICATIONS+8, 0xeeeeeeee);
2618 SetUInt32Value(UNIT_FIELD_AURAFLAGS+4, 0);
2619 SetUInt32Value(UNIT_FIELD_AURASTATE, 0);
2621 if(getRace() == NIGHTELF)
2623 DeMorph();
2626 m_deathTimer = 0;
2629 void Player::KillPlayer()
2631 SetMovement(MOVE_ROOT);
2633 StopMirrorTimer(FATIGUE_TIMER); //disable timers(bars)
2634 StopMirrorTimer(BREATH_TIMER);
2635 StopMirrorTimer(FIRE_TIMER);
2637 setDeathState(CORPSE);
2638 SetFlag( UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_IN_PVP );
2640 SetFlag( UNIT_DYNAMIC_FLAGS, 0x00 );
2642 // 6 minutes until repop at graveyard
2643 m_deathTimer = 360000;
2645 // dead player body showed at this moment, corpse wiil be show at Player ghost repop
2646 CreateCorpse();
2649 Corpse* Player::CreateCorpse()
2651 // prevent existance 2 corpse for player
2652 SpawnCorpseBones();
2654 uint32 _uf, _pb, _pb2, _cfb1, _cfb2;
2656 Corpse* corpse = new Corpse(CORPSE_RESURRECTABLE);
2657 if(!corpse->Create(objmgr.GenerateLowGuid(HIGHGUID_CORPSE), this, GetMapId(), GetPositionX(),
2658 GetPositionY(), GetPositionZ(), GetOrientation()))
2660 delete corpse;
2661 return NULL;
2664 _uf = GetUInt32Value(UNIT_FIELD_BYTES_0);
2665 _pb = GetUInt32Value(PLAYER_BYTES);
2666 _pb2 = GetUInt32Value(PLAYER_BYTES_2);
2668 uint8 race = (uint8)(_uf);
2669 uint8 skin = (uint8)(_pb);
2670 uint8 face = (uint8)(_pb >> 8);
2671 uint8 hairstyle = (uint8)(_pb >> 16);
2672 uint8 haircolor = (uint8)(_pb >> 24);
2673 uint8 facialhair = (uint8)(_pb2);
2675 _cfb1 = ((0x00) | (race << 8) | (0x00 << 16) | (skin << 24));
2676 _cfb2 = ((face) | (hairstyle << 8) | (haircolor << 16) | (facialhair << 24));
2678 corpse->SetUInt32Value( CORPSE_FIELD_BYTES_1, _cfb1 );
2679 corpse->SetUInt32Value( CORPSE_FIELD_BYTES_2, _cfb2 );
2680 corpse->SetUInt32Value( CORPSE_FIELD_FLAGS, 4 );
2681 corpse->SetUInt32Value( CORPSE_FIELD_DISPLAY_ID, GetUInt32Value(UNIT_FIELD_DISPLAYID) );
2683 uint32 iDisplayID;
2684 uint16 iIventoryType;
2685 uint32 _cfi;
2686 for (int i = 0; i < EQUIPMENT_SLOT_END; i++)
2688 if(m_items[i])
2690 iDisplayID = m_items[i]->GetProto()->DisplayInfoID;
2691 iIventoryType = (uint16)m_items[i]->GetProto()->InventoryType;
2693 _cfi = (uint16(iDisplayID)) | (iIventoryType)<< 24;
2694 corpse->SetUInt32Value(CORPSE_FIELD_ITEM + i,_cfi);
2698 corpse->SaveToDB();
2700 // register for player, but not show
2701 corpse->AddToWorld();
2702 return corpse;
2705 void Player::SpawnCorpseBones()
2707 Corpse* corpse = GetCorpse();
2708 if(!corpse) return;
2710 corpse->ConvertCorpseToBones();
2711 SaveToDB(); // prevent loading as ghost without corpse
2714 Corpse* Player::GetCorpse() const
2716 return ObjectAccessor::Instance().GetCorpseForPlayer(*this);
2719 void Player::DurabilityLossAll(double percent)
2721 for (uint16 i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; i++)
2722 DurabilityLoss(i,percent);
2725 void Player::DurabilityLoss(uint8 equip_pos, double percent)
2727 if(!m_items[equip_pos])
2728 return;
2730 uint32 pDurability = m_items[equip_pos]->GetUInt32Value(ITEM_FIELD_DURABILITY);
2732 if(!pDurability)
2733 return;
2735 uint32 pDurabilityLoss = (uint32)(pDurability*percent);
2737 if(pDurabilityLoss < 1 )
2738 pDurabilityLoss = 1;
2740 uint32 pNewDurability = pDurability - pDurabilityLoss;
2742 // we have durability 25% or 0 we should modify item stats
2743 // modify item stats _before_ Durability set to 0 to pass _ApplyItemMods internal check
2744 // if ( pNewDurability == 0 || pNewDurability * 100 / pDurability < 25)
2745 if ( pNewDurability == 0 )
2746 _ApplyItemMods(m_items[equip_pos],equip_pos, false);
2748 m_items[equip_pos]->SetUInt32Value(ITEM_FIELD_DURABILITY, pNewDurability);
2751 void Player::DurabilityRepairAll(bool cost)
2753 for (uint16 i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; i++)
2754 DurabilityRepair(( (INVENTORY_SLOT_BAG_0 << 8) | i ),cost);
2757 void Player::DurabilityRepair(uint16 pos, bool cost)
2759 Item* item = GetItemByPos(pos);
2761 if(!item)
2762 return;
2764 uint32 maxDurability = item->GetUInt32Value(ITEM_FIELD_MAXDURABILITY);
2765 if(!maxDurability)
2766 return;
2768 uint32 curDurability = item->GetUInt32Value(ITEM_FIELD_DURABILITY);
2770 // some simple repair formula depending on durability lost
2771 if(cost)
2773 uint32 costs = maxDurability - curDurability;
2775 if (GetMoney() < costs)
2777 DEBUG_LOG("You do not have enough money");
2778 return;
2781 ModifyMoney( -int32(costs) );
2784 item->SetUInt32Value(ITEM_FIELD_DURABILITY, maxDurability);
2786 // reapply mods for total broken and repaired item if equiped
2787 if(IsEquipmentPos(pos) && !curDurability)
2788 _ApplyItemMods(item,pos & 255, true);
2791 void Player::RepopAtGraveyard()
2793 WorldSafeLocsEntry *ClosestGrave = objmgr.GetClosestGraveYard( m_positionX, m_positionY, m_positionZ, GetMapId(), GetTeam() );
2795 if(ClosestGrave)
2797 // stop countdown until repop
2798 m_deathTimer = 0;
2800 TeleportTo(ClosestGrave->map_id, ClosestGrave->x, ClosestGrave->y, ClosestGrave->z, GetOrientation());
2802 if(Corpse* corpse = GetCorpse())
2803 corpse->UpdateForPlayer(this,true);
2807 void Player::JoinedChannel(Channel *c)
2809 m_channels.push_back(c);
2812 void Player::LeftChannel(Channel *c)
2814 m_channels.remove(c);
2817 void Player::CleanupChannels()
2819 list<Channel *>::iterator i;
2820 for(i = m_channels.begin(); i != m_channels.end(); i++)
2821 (*i)->Leave(this,false);
2824 void Player::BroadcastPacketToFriendListers(WorldPacket *packet)
2826 Field *fields;
2827 Player *pfriend;
2829 QueryResult *result = sDatabase.PQuery("SELECT `guid` FROM `character_social` WHERE `flags` = 'FRIEND' AND `friend` = '%u'", GetGUIDLow());
2831 if(!result) return;
2835 WorldPacket data;
2836 fields = result->Fetch();
2838 pfriend = ObjectAccessor::Instance().FindPlayer(fields[0].GetUInt64());
2840 if (pfriend && pfriend->IsInWorld())
2841 pfriend->GetSession()->SendPacket(packet);
2843 }while( result->NextRow() );
2844 delete result;
2847 void Player::UpdateDefense()
2849 if(UpdateSkill(SKILL_DEFENSE))
2851 // update dependent from defense skill part BlockChanceWithoutMods = 5 + (GetDefenceSkillValue() - getLevel()*5)*0.04);
2852 UpdateBlockPercentage(1,0);
2856 //skill+1, checking for max value
2857 bool Player::UpdateSkill(uint32 skill_id)
2859 if(!skill_id) return false;
2860 uint16 i=0;
2861 for (; i < PLAYER_MAX_SKILLS; i++)
2862 if ((GetUInt32Value(PLAYER_SKILL(i)) & 0x0000FFFF) == skill_id) break;
2863 if(i>=PLAYER_MAX_SKILLS) return false;
2865 uint32 data = GetUInt32Value(PLAYER_SKILL(i)+1);
2866 uint32 value = SKILL_VALUE(data);
2867 uint32 max = SKILL_MAX(data);
2869 if ((!max) || (!value) || (value >= max)) return false;
2871 if (value*512 < max*urand(0,512))
2873 SetUInt32Value(PLAYER_SKILL(i)+1,data+1);
2874 return true;
2877 return false;
2880 void Player::UpdateSkillPro(uint32 spellid)
2882 SkillLineAbilityEntry *pAbility = sSkillLineAbilityStore.LookupEntry(spellid);
2883 if(!pAbility)
2884 return;
2885 uint32 minValue = pAbility->min_value;
2886 uint32 maxValue = pAbility->max_value;
2887 uint32 skill_id = pAbility->skillId;
2889 if(!skill_id)return;
2890 uint16 i=0;
2891 for (; i < PLAYER_MAX_SKILLS; i++)
2892 if ((GetUInt32Value(PLAYER_SKILL(i)) & 0x0000FFFF) == skill_id) break;
2893 if(i>=PLAYER_MAX_SKILLS) return;
2895 uint32 data = GetUInt32Value(PLAYER_SKILL(i)+1);
2896 uint32 value = SKILL_VALUE(data);
2897 uint32 max = SKILL_MAX(data);
2899 if ((!max) || (!value) || (value >= max)) return;
2900 //generates chance for unsuccess gain
2901 if (value*512 > max*urand(0,512)) return;
2902 if(skill_id == SKILL_POISONS && value < 125)
2904 SetUInt32Value(PLAYER_SKILL(i)+1,data+1);
2905 return;
2907 if(skill_id == SKILL_MINING && value>75)
2908 return;
2909 if(value >= maxValue+25 )
2910 return;
2911 else if(value >= maxValue)
2913 if(urand(0,100) <30)
2914 SetUInt32Value(PLAYER_SKILL(i)+1,data+1);
2915 return;
2917 else if(value >= minValue)
2919 if(urand(0,100) <70)
2920 SetUInt32Value(PLAYER_SKILL(i)+1,data+1);
2921 return;
2923 else if(value >= 1)
2925 SetUInt32Value(PLAYER_SKILL(i)+1,data+1);
2926 return;
2928 else return;
2932 void Player::UpdateWeaponSkill (WeaponAttackType attType)
2934 // no skill gain in pvp
2935 Unit *pVictim = getVictim();
2936 if(pVictim && pVictim->GetTypeId() == TYPEID_PLAYER)
2937 return;
2939 switch(attType)
2941 case BASE_ATTACK:
2943 Item *tmpitem = GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
2945 if (!tmpitem || tmpitem->IsBroken())
2946 UpdateSkill(SKILL_UNARMED);
2947 else if(tmpitem->GetProto()->SubClass != ITEM_SUBCLASS_WEAPON_FISHING_POLE)
2948 UpdateSkill(tmpitem->GetSkill());
2950 };break;
2951 case OFF_ATTACK:
2953 Item *tmpitem = GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
2955 if (tmpitem && !tmpitem->IsBroken())
2956 UpdateSkill(tmpitem->GetSkill());
2957 };break;
2958 case RANGED_ATTACK:
2960 Item* tmpitem = GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_RANGED);
2962 if (tmpitem && !tmpitem->IsBroken())
2963 UpdateSkill(tmpitem->GetSkill());
2964 };break;
2968 void Player::UpdateCombatSkills(Unit *pVictim, WeaponAttackType attType, MeleeHitOutcome outcome, bool defence)
2970 switch(outcome)
2972 case MELEE_HIT_CRIT:
2973 return;
2974 case MELEE_HIT_DODGE:
2975 return;
2976 case MELEE_HIT_PARRY:
2977 return;
2978 case MELEE_HIT_BLOCK:
2979 return;
2981 default:
2982 break;
2985 uint32 plevel = getLevel(); // if defence than pVictim == attacker
2986 uint32 greylevel = MaNGOS::XP::GetGrayLevel(plevel);
2987 uint32 moblevel = pVictim->getLevel();
2988 if(moblevel < greylevel)
2989 return;
2991 if (moblevel > plevel + 5)
2992 moblevel = plevel + 5;
2994 uint32 lvldif = moblevel - greylevel;
2995 if(lvldif < 3)
2996 lvldif = 3;
2998 uint32 skilldif = 5 * plevel - (defence ? GetPureDefenceSkillValue() : GetPureWeaponSkillValue(attType));
2999 if(skilldif <= 0)
3000 return;
3002 float chance = 3 * lvldif * skilldif / plevel;
3003 if(!defence)
3005 if(getClass() == WARRIOR || getClass() == ROGUE)
3006 chance *= 0.1 * GetStat(STAT_INTELLECT);
3009 chance = chance < 1 ? 1 : chance; //minimum chance to increase skill is 1%
3011 if(chance > urand(0,100))
3013 if(defence)
3014 UpdateDefense();
3015 else
3016 UpdateWeaponSkill(attType);
3018 else
3019 return;
3022 void Player::ModifySkillBonus(uint32 skillid,int32 val)
3024 for (uint16 i=0; i < PLAYER_MAX_SKILLS; i++)
3025 if ((GetUInt32Value(PLAYER_SKILL(i)) & 0x0000FFFF) == skillid)
3028 SetUInt32Value(PLAYER_SKILL(i)+2,((int32)(GetUInt32Value(PLAYER_SKILL(i)+2)))+val);
3029 return;
3033 void Player::UpdateMaxSkills()
3035 for (uint16 i=0; i < PLAYER_MAX_SKILLS; i++)
3036 if (GetUInt32Value(PLAYER_SKILL(i)))
3038 uint32 pskill = GetUInt32Value(PLAYER_SKILL(i)) & 0x0000FFFF;
3039 if(pskill == SKILL_HERBALISM || pskill == SKILL_MINING || pskill ==SKILL_FISHING
3040 || pskill == SKILL_FIRST_AID || pskill == SKILL_COOKING || pskill == SKILL_LEATHERWORKING
3041 || pskill == SKILL_BLACKSMITHING || pskill == SKILL_ALCHEMY || pskill == SKILL_ENCHANTING
3042 || pskill == SKILL_TAILORING || pskill == SKILL_ENGINERING || pskill == SKILL_SKINNING)
3043 continue;
3044 uint32 data = GetUInt32Value(PLAYER_SKILL(i)+1);
3045 uint32 max = data>>16;
3046 uint32 max_Skill = data%0x10000+getLevel()*5*0x10000;
3047 if((max_Skill>>16) > 300)
3048 max_Skill = data%0x10000+300*0x10000;
3050 if(max!=1 && max != 300)
3051 SetUInt32Value(PLAYER_SKILL(i)+1,max_Skill);
3055 void Player::UpdateSkillsToMaxSkillsForLevel()
3057 for (uint16 i=0; i < PLAYER_MAX_SKILLS; i++)
3058 if (GetUInt32Value(PLAYER_SKILL(i)))
3060 uint32 pskill = GetUInt32Value(PLAYER_SKILL(i)) & 0x0000FFFF;
3061 if(pskill == SKILL_HERBALISM || pskill == SKILL_MINING || pskill ==SKILL_FISHING
3062 || pskill == SKILL_FIRST_AID || pskill == SKILL_COOKING || pskill == SKILL_LEATHERWORKING
3063 || pskill == SKILL_BLACKSMITHING || pskill == SKILL_ALCHEMY || pskill == SKILL_ENCHANTING
3064 || pskill == SKILL_TAILORING || pskill == SKILL_ENGINERING || pskill == SKILL_SKINNING)
3065 continue;
3066 uint32 data = GetUInt32Value(PLAYER_SKILL(i)+1);
3068 uint32 max = data>>16;
3070 if(max > 1)
3072 uint32 new_data = max * 0x10000 + max;
3073 SetUInt32Value(PLAYER_SKILL(i)+1,new_data);
3078 // This functions sets a skill line value (and adds if doesn't exist yet)
3079 // To "remove" a skill line, set it's values to zero
3080 void Player::SetSkill(uint32 id, uint16 currVal, uint16 maxVal)
3082 if(!id) return;
3083 uint16 i=0;
3084 for (; i < PLAYER_MAX_SKILLS; i++)
3085 if ((GetUInt32Value(PLAYER_SKILL(i)) & 0x0000FFFF) == id) break;
3087 if(i<PLAYER_MAX_SKILLS) //has skill
3089 if(currVal)
3090 SetUInt32Value(PLAYER_SKILL(i)+1,currVal+maxVal*0x10000);
3091 else //remove
3093 SetUInt64Value(PLAYER_SKILL(i),0);
3094 SetUInt32Value(PLAYER_SKILL(i)+2,0);
3095 // remove spells that depend on this skill when removing the skill
3096 for (PlayerSpellMap::const_iterator itr = m_spells.begin(), next = m_spells.begin(); itr != m_spells.end(); itr = next)
3098 next++;
3099 if(itr->second->state == PLAYERSPELL_REMOVED) continue;
3100 SkillLineAbilityEntry *ability = sSkillLineAbilityStore.LookupEntry(itr->first);
3101 if (ability && ability->skillId == id)
3102 removeSpell(itr->first);
3105 }else if(currVal) //add
3108 for (i=0; i < PLAYER_MAX_SKILLS; i++)
3109 if (!GetUInt32Value(PLAYER_SKILL(i)))
3111 SkillLineEntry *pSkill = sSkillLineStore.LookupEntry(id);
3112 if(!pSkill)
3114 sLog.outError("Skill not found in SkillLineStore: skill #%u", id);
3115 return;
3117 // enable unlearn button for professions only
3118 if (pSkill->categoryId == 11)
3119 SetUInt32Value(PLAYER_SKILL(i), id | (1 << 16));
3120 else
3121 SetUInt32Value(PLAYER_SKILL(i),id);
3122 SetUInt32Value(PLAYER_SKILL(i)+1,maxVal*0x10000+currVal);
3123 // apply skill bonuses
3124 SetUInt32Value(PLAYER_SKILL(i)+2,0);
3125 AuraList& mModSkill = GetAurasByType(SPELL_AURA_MOD_SKILL);
3126 for(AuraList::iterator i = mModSkill.begin(); i != mModSkill.end(); ++i)
3127 if ((*i)->GetModifier()->m_miscvalue == id)
3128 (*i)->ApplyModifier(true);
3129 AuraList& mModSkillTalent = GetAurasByType(SPELL_AURA_MOD_SKILL_TALENT);
3130 for(AuraList::iterator i = mModSkillTalent.begin(); i != mModSkillTalent.end(); ++i)
3131 if ((*i)->GetModifier()->m_miscvalue == id)
3132 (*i)->ApplyModifier(true);
3133 return;
3140 bool Player::HasSkill(uint32 skill) const
3142 if(!skill)return false;
3143 for (uint16 i=0; i < PLAYER_MAX_SKILLS; i++)
3145 if ((GetUInt32Value(PLAYER_SKILL(i)) & 0x0000FFFF) == skill)
3147 return true;
3150 return false;
3153 uint16 Player::GetSkillValue(uint32 skill) const
3155 if(!skill)return 0;
3156 for (uint16 i=0; i < PLAYER_MAX_SKILLS; i++)
3158 if ((GetUInt32Value(PLAYER_SKILL(i)) & 0x0000FFFF) == skill)
3160 return SKILL_VALUE(GetUInt32Value(PLAYER_SKILL(i)+1))+GetUInt32Value(PLAYER_SKILL(i)+2);
3163 return 0;
3166 uint16 Player::GetPureSkillValue(uint32 skill) const
3168 if(!skill)return 0;
3169 for (uint16 i=0; i < PLAYER_MAX_SKILLS; i++)
3171 if ((GetUInt32Value(PLAYER_SKILL(i)) & 0x0000FFFF) == skill)
3173 return SKILL_VALUE(GetUInt32Value(PLAYER_SKILL(i)+1));
3176 return 0;
3179 void Player::SendInitialActions()
3181 sLog.outDetail( "Initializing Action Buttons for '%u'", GetGUIDLow() );
3182 WorldPacket data;
3183 uint16 button=0;
3185 std::list<struct actions>::iterator itr;
3186 data.Initialize(SMSG_ACTION_BUTTONS);
3187 for (itr = m_actions.begin(); itr != m_actions.end();)
3189 if (itr->button == button)
3191 data << uint16(itr->action);
3192 data << uint8(itr->misc);
3193 data << uint8(itr->type);
3194 ++itr;
3196 else
3198 data << uint32(0);
3200 button++;
3203 if (button < 120 )
3205 for (int temp_counter=(120-button); temp_counter>0; temp_counter--)
3207 data << uint32(0);
3210 GetSession()->SendPacket( &data );
3211 sLog.outDetail( "Action Buttons for '%u' Initialized", GetGUIDLow() );
3214 void Player::addAction(const uint8 button, const uint16 action, const uint8 type, const uint8 misc)
3216 // check cheating with adding non-known spells to action bar
3217 if(type==ACTION_BUTTON_SPELL)
3219 if(!sSpellStore.LookupEntry(action))
3221 sLog.outError( "Action %u not added into button %u for player %s: spell not exist", action, button, GetName() );
3222 return;
3225 if(!HasSpell(action))
3227 sLog.outError( "Action %u not added into button %u for player %s: player don't known this spell", action, button, GetName() );
3228 return;
3232 bool ButtonExists = false;
3233 std::list<struct actions>::iterator itr;
3234 for (itr = m_actions.begin(); itr != m_actions.end(); ++itr)
3236 if (itr->button == button)
3238 itr->button=button;
3239 itr->action=action;
3240 itr->type=type;
3241 itr->misc=misc;
3242 ButtonExists = true;
3243 break;
3246 if (!ButtonExists)
3248 struct actions newaction;
3249 newaction.button=button;
3250 newaction.action=action;
3251 newaction.type=type;
3252 newaction.misc=misc;
3253 m_actions.push_back(newaction);
3255 sLog.outDetail( "Player '%u' Added Action '%u' to Button '%u'", GetGUIDLow(), action, button );
3258 void Player::removeAction(uint8 button)
3260 std::list<struct actions>::iterator itr;
3261 for (itr = m_actions.begin(); itr != m_actions.end(); ++itr)
3263 if (itr->button == button)
3265 m_actions.erase(itr);
3266 break;
3269 sLog.outDetail( "Action Button '%u' Removed from Player '%u'", button, GetGUIDLow() );
3272 void Player::SetDontMove(bool dontMove)
3274 m_dontMove = dontMove;
3277 bool Player::IsGroupMember(Player *plyr)
3279 if(!plyr->IsInGroup())
3280 return false;
3281 Group *grp = objmgr.GetGroupByLeader(plyr->GetGroupLeader());
3282 if(grp->GroupCheck(plyr->GetGUID()))
3284 return true;
3286 return false;
3289 bool Player::SetPosition(float x, float y, float z, float orientation)
3291 Map *m = MapManager::Instance().GetMap(m_mapId);
3293 const float old_x = m_positionX;
3294 const float old_y = m_positionY;
3295 const float old_r = m_orientation;
3297 if( old_x != x || old_y != y || old_r != orientation)
3299 m->PlayerRelocation(this, x, y, z, orientation);
3301 // remove at movement non-move stealth aura
3302 if(HasFlag(UNIT_FIELD_BYTES_1,0x2000000))
3303 RemoveAurasDueToSpell(20580);
3306 // reread after Ma::Relocation
3307 m = MapManager::Instance().GetMap(GetMapId());
3308 x = m_positionX;
3309 y = m_positionY;
3310 z = m_positionZ;
3312 float water_z = m->GetWaterLevel(x,y);
3313 uint8 flag1 = m->GetTerrainType(x,y);
3315 //!Underwater check
3316 if ((z < (water_z - 2)) && (flag1 & 0x01))
3317 m_isunderwater|= 0x01;
3318 else if (z > (water_z - 2))
3319 m_isunderwater&= 0x7A;
3321 //!in lava check
3322 if ((z < (water_z - 0)) && (flag1 & 0x02))
3323 m_isunderwater|= 0x80;
3325 // form checks
3326 if ( IsUnderWater() )
3328 // remove travel forms
3329 if(m_form == FORM_TRAVEL || m_form == FORM_GHOSTWOLF)
3330 RemoveAurasDueToSpell(m_ShapeShiftForm);
3332 // IsInWater check ignore bridge and underwater ways case, check additional z
3333 else if( !IsInWater() && z < water_z + 1 )
3335 if(m_form == FORM_AQUA)
3336 RemoveAurasDueToSpell(m_ShapeShiftForm);
3339 CheckExploreSystem();
3341 return true;
3344 void Player::SendMessageToSet(WorldPacket *data, bool self)
3346 MapManager::Instance().GetMap(m_mapId)->MessageBoardcast(this, data, self);
3349 void Player::SendMessageToOwnTeamSet(WorldPacket *data, bool self)
3351 MapManager::Instance().GetMap(m_mapId)->MessageBoardcast(this, data, self,true);
3354 void Player::SendDirectMessage(WorldPacket *data)
3356 GetSession()->SendPacket(data);
3359 void Player::CheckExploreSystem()
3362 if (!isAlive())
3363 return;
3365 if (isInFlight())
3366 return;
3368 WorldPacket data;
3369 uint16 areaFlag=MapManager::Instance().GetMap(GetMapId())->GetAreaFlag(m_positionX,m_positionY);
3370 if(areaFlag==0xffff)return;
3371 int offset = areaFlag / 32;
3373 if(offset >= 64)
3375 sLog.outError("ERROR: Wrong area flag %u in map data for (X: %f Y: %f) point to field PLAYER_EXPLORED_ZONES_1 + %u ( %u must be < 64 ).",areaFlag,m_positionX,m_positionY,offset,offset);
3376 return;
3379 uint32 val = (uint32)(1 << (areaFlag % 32));
3380 uint32 currFields = GetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset);
3382 if( !(currFields & val) )
3384 SetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset, (uint32)(currFields | val));
3386 AreaTableEntry *p = GetAreaEntryByAreaFlag(areaFlag);
3387 if(!p)
3389 sLog.outError("PLAYER: Player %u discovered unknown area (x: %f y: %f map: %u", GetGUIDLow(), m_positionX,m_positionY,GetMapId());
3391 else if(p->area_level > 0)
3393 uint32 area = p->ID;
3394 if (getLevel() >= sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
3396 SendExplorationExperience(area,0);
3398 else
3400 uint32 XP = uint32(p->area_level*10*sWorld.getRate(RATE_XP_EXPLORE));
3401 GiveXP( XP, NULL );
3402 SendExplorationExperience(area,XP);
3404 sLog.outDetail("PLAYER: Player %u discovered a new area: %u", GetGUIDLow(), area);
3410 uint32 Player::TeamForRace(uint8 race)
3412 switch(race)
3414 case DWARF:
3415 case GNOME:
3416 case HUMAN:
3417 case NIGHTELF:
3418 return ALLIANCE;
3419 case ORC:
3420 case TAUREN:
3421 case TROLL:
3422 case UNDEAD_PLAYER:
3423 return HORDE;
3425 return 0;
3428 void Player::setFactionForRace(uint8 race)
3430 m_team = TeamForRace(race);
3431 uint32 faction = 0;
3432 switch(race)
3434 case HUMAN:
3435 faction = 1;
3436 break;
3437 case DWARF:
3438 faction = 3;
3439 break;
3440 case NIGHTELF:
3441 faction = 4;
3442 break;
3443 case GNOME:
3444 faction = 115;
3445 break;
3447 case ORC:
3448 faction = 2;
3449 break;
3450 case UNDEAD_PLAYER:
3451 faction = 5;
3452 break;
3453 case TAUREN:
3454 faction = 6;
3455 break;
3456 case TROLL:
3457 faction = 116;
3458 break;
3460 setFaction( faction );
3463 void Player::UpdateReputation() const
3465 std::list<struct Factions>::const_iterator itr;
3467 sLog.outDebug( "WORLD: Player::UpdateReputation" );
3469 for(itr = factions.begin(); itr != factions.end(); ++itr)
3471 SendSetFactionStanding(&*itr);
3475 void Player::SendSetFactionStanding(const Factions* faction) const
3477 WorldPacket data;
3479 if(faction->Flags & 0x00000001 ) //If faction is visible then update it
3481 data.Initialize(SMSG_SET_FACTION_STANDING);
3482 data << (uint32) faction->Flags;
3483 data << (uint32) faction->ReputationListID;
3484 data << (uint32) faction->Standing;
3485 GetSession()->SendPacket(&data);
3489 bool Player::FactionIsInTheList(uint32 faction)
3491 std::list<struct Factions>::iterator itr;
3493 for(itr = factions.begin(); itr != factions.end(); ++itr)
3495 if(itr->ReputationListID == faction) return true;
3497 return false;
3500 void Player::SetInitialFactions()
3502 Factions newFaction;
3503 FactionEntry *factionEntry = NULL;
3505 for(unsigned int i = 1; i <= sFactionStore.GetNumRows(); i++)
3507 factionEntry = sFactionStore.LookupEntry(i);
3509 if( factionEntry && (factionEntry->reputationListID >= 0))
3511 newFaction.ID = factionEntry->ID;
3512 newFaction.ReputationListID = factionEntry->reputationListID;
3513 newFaction.Standing = 0;
3514 //Set visible to factions of own team
3515 if( GetTeam() == factionEntry->team ) newFaction.Flags = 1;
3516 else newFaction.Flags = 0;
3518 //If the faction's team is enemy of my one we are at war!
3519 if(GetTeam() == ALLIANCE )
3521 if( factionEntry->team == HORDE || factionEntry->team == HORDE_FORCES )
3522 newFaction.Flags = (newFaction.Flags | 2);
3524 else
3525 if(GetTeam() == HORDE )
3527 if( factionEntry->team == ALLIANCE || factionEntry->team == ALLIANCE_FORCES )
3528 newFaction.Flags = (newFaction.Flags | 2);
3531 factions.push_back(newFaction);
3536 uint32 Player::GetReputation(uint32 faction_id) const
3538 FactionEntry *factionEntry = sFactionStore.LookupEntry(faction_id);
3540 std::list<struct Factions>::const_iterator itr;
3541 for(itr = factions.begin(); itr != factions.end(); ++itr)
3543 if(int32(itr->ReputationListID) == factionEntry->reputationListID)
3545 return itr->Standing;
3548 return 0;
3551 bool Player::SetStanding(uint32 faction, int standing)
3553 FactionTemplateEntry *factionTemplateEntry = sFactionTemplateStore.LookupEntry(faction);
3555 if(!factionTemplateEntry)
3557 sLog.outError("Player::SetStanding: Can't update reputation of %s for unknown faction (faction template id) #%u.",GetName(),faction);
3558 return false;
3561 FactionEntry *factionEntry = sFactionStore.LookupEntry(factionTemplateEntry->faction);
3563 // Faction without recorded reputation. Just ignore.
3564 if(!factionEntry)
3565 return false;
3567 return ModifyFactionReputation(factionEntry,standing);
3570 bool Player::ModifyFactionReputation(FactionEntry* factionEntry, int32 standing)
3572 std::list<struct Factions>::iterator itr;
3573 for(itr = factions.begin(); itr != factions.end(); ++itr)
3575 if(int32(itr->ReputationListID) == factionEntry->reputationListID)
3577 itr->Standing = (((int32)itr->Standing + standing) > 0 ? itr->Standing + standing: 0);
3578 itr->Flags = (itr->Flags | 0x00000001);
3579 SendSetFactionStanding(&*itr);
3580 return true;
3583 return false;
3586 //Calculates how many reputation points player gains in wich victim's enemy factions
3587 void Player::CalculateReputation(Unit *pVictim)
3589 if( !pVictim ) return;
3591 if( pVictim->GetTypeId() != TYPEID_PLAYER )
3593 SetStanding( pVictim->getFaction(), (-100) );
3597 //Calculate how many reputation points player gain with the quest
3598 void Player::CalculateReputation(Quest *pQuest, uint64 guid)
3600 Creature *pCreature = ObjectAccessor::Instance().GetCreature(*this, guid);
3601 if( pCreature )
3603 int dif = getLevel() - pQuest->GetQuestInfo()->MinLevel;
3604 if(dif < 0) dif = 0;
3605 else if(dif > 5) dif = 5;
3607 int RepPoints = (uint32)(((5-dif)*0.20)*(100.0f + m_AuraModifiers[SPELL_AURA_MOD_REPUTATION_GAIN]));
3608 // correct would be multiplicative but currently only one such aura in game
3610 SetStanding(pCreature->getFaction(), (RepPoints > 0 ? RepPoints : 1) );
3613 // special quest repuration reward/losts
3614 if(pQuest->GetQuestInfo()->RewRepFaction1 && pQuest->GetQuestInfo()->RewRepValue1 )
3615 SetStanding(pQuest->GetQuestInfo()->RewRepFaction1, pQuest->GetQuestInfo()->RewRepValue1 );
3617 if(pQuest->GetQuestInfo()->RewRepFaction2 && pQuest->GetQuestInfo()->RewRepValue2 )
3618 SetStanding(pQuest->GetQuestInfo()->RewRepFaction2, pQuest->GetQuestInfo()->RewRepValue2 );
3621 //Update honor fields
3622 void Player::UpdateHonor(void)
3624 WorldPacket data;
3626 time_t rawtime;
3627 struct tm * now;
3628 uint32 today = 0;
3629 uint32 date = 0;
3631 uint32 Yestarday = 0;
3632 uint32 ThisWeekBegin = 0;
3633 uint32 ThisWeekEnd = 0;
3634 uint32 LastWeekBegin = 0;
3635 uint32 LastWeekEnd = 0;
3637 uint32 lifetime_honorableKills = 0;
3638 uint32 lifetime_dishonorableKills = 0;
3639 uint32 today_honorableKills = 0;
3640 uint32 today_dishonorableKills = 0;
3642 uint32 yestardayKills = 0;
3643 uint32 thisWeekKills = 0;
3644 uint32 lastWeekKills = 0;
3646 float total_honor = 0;
3647 float yestardayHonor = 0;
3648 float thisWeekHonor = 0;
3649 float lastWeekHonor = 0;
3651 time( &rawtime );
3652 now = localtime( &rawtime );
3654 today = ((uint32)(now->tm_year << 16)|(uint32)(now->tm_yday));
3656 Yestarday = today - 1;
3657 ThisWeekBegin = today - now->tm_wday;
3658 ThisWeekEnd = ThisWeekBegin + 7;
3659 LastWeekBegin = ThisWeekBegin - 7;
3660 LastWeekEnd = LastWeekBegin + 7;
3662 sLog.outDetail("PLAYER: UpdateHonor");
3664 QueryResult *result = sDatabase.PQuery("SELECT `type`,`honor`,`date` FROM `character_kill` WHERE `guid` = '%u'", GetGUIDLow());
3666 if(result)
3670 Field *fields = result->Fetch();
3671 date = fields[2].GetUInt32();
3673 if(fields[0].GetUInt32() == HONORABLE_KILL)
3675 lifetime_honorableKills++;
3676 //total_honor += fields[1].GetFloat();
3678 if( date == today)
3680 today_honorableKills++;
3682 if( date == Yestarday)
3684 yestardayKills++;
3685 yestardayHonor += fields[1].GetFloat();
3687 if( (date >= ThisWeekBegin) && (date < ThisWeekEnd) )
3689 thisWeekKills++;
3690 thisWeekHonor += fields[1].GetFloat();
3692 if( (date >= LastWeekBegin) && (date < LastWeekEnd) )
3694 lastWeekKills++;
3695 lastWeekHonor += fields[1].GetFloat();
3698 //All honor points until last week
3699 if( date < LastWeekEnd )
3701 total_honor += fields[1].GetFloat();
3705 else if(fields[0].GetUInt32() == DISHONORABLE_KILL)
3707 lifetime_dishonorableKills++;
3708 //total_honor -= fields[1].GetFloat();
3710 if( date == today)
3712 today_dishonorableKills++;
3715 //All honor points until last week
3716 if( date < LastWeekEnd )
3718 total_honor -= fields[1].GetFloat();
3722 while( result->NextRow() );
3724 delete result;
3727 //Store Total Honor points...
3728 SetTotalHonor(total_honor);
3730 //RIGHEST RANK
3731 //If the new rank is highest then the old one, then m_highest_rank is updated
3732 if( CalculateHonorRank(total_honor) > GetHonorHighestRank() )
3734 SetHonorHighestRank( CalculateHonorRank(total_honor) );
3737 //RATING
3738 SetHonorRating( MaNGOS::Honor::CalculeRating(this) );
3740 //STANDING
3741 SetHonorLastWeekStanding( MaNGOS::Honor::CalculeStanding(this) );
3743 //TODO Fix next rank bar... it is not working fine! For while it be set with the total honor points...
3744 //NEXT RANK BAR
3745 SetUInt32Value(PLAYER_FIELD_HONOR_BAR, (uint32)( (total_honor < 0) ? 0: total_honor) );
3747 //RANK (Patent)
3748 if( CalculateHonorRank(total_honor) )
3749 SetUInt32Value(PLAYER_BYTES_3, (( CalculateHonorRank(total_honor) << 24) + 0x04000000) + (m_drunk & 0xFFFE) + getGender());
3750 else
3751 SetUInt32Value(PLAYER_BYTES_3, (m_drunk & 0xFFFE) + getGender());
3753 //TODAY
3754 SetUInt32Value(PLAYER_FIELD_SESSION_KILLS, (today_dishonorableKills << 16) + today_honorableKills );
3755 //YESTERDAY
3756 SetUInt32Value(PLAYER_FIELD_YESTERDAY_KILLS, yestardayKills);
3757 SetUInt32Value(PLAYER_FIELD_YESTERDAY_CONTRIBUTION, (uint32)yestardayHonor);
3758 //THIS WEEK
3759 SetUInt32Value(PLAYER_FIELD_THIS_WEEK_KILLS, thisWeekKills);
3760 SetUInt32Value(PLAYER_FIELD_THIS_WEEK_CONTRIBUTION, (uint32)thisWeekHonor);
3761 //LAST WEEK
3762 SetUInt32Value(PLAYER_FIELD_LAST_WEEK_KILLS, lastWeekKills);
3763 SetUInt32Value(PLAYER_FIELD_LAST_WEEK_CONTRIBUTION, (uint32)lastWeekHonor);
3764 SetUInt32Value(PLAYER_FIELD_LAST_WEEK_RANK, GetHonorLastWeekStanding());
3766 //LIFE TIME
3767 SetUInt32Value(PLAYER_FIELD_SESSION_KILLS, (lifetime_dishonorableKills << 16) + lifetime_honorableKills );
3768 SetUInt32Value(PLAYER_FIELD_LIFETIME_DISHONORABLE_KILLS, lifetime_dishonorableKills);
3769 SetUInt32Value(PLAYER_FIELD_LIFETIME_HONORABLE_KILLS, lifetime_honorableKills);
3770 //TODO: Into what field we need to set it? Fix it!
3771 SetUInt32Value(PLAYER_FIELD_PVP_MEDALS/*???*/, (GetHonorHighestRank() != 0 ? ((GetHonorHighestRank() << 24) + 0x040F0001) : 0) );
3774 uint32 Player::GetHonorRank() const
3776 return CalculateHonorRank(m_total_honor_points);
3779 //What is Player's rank... private, scout...
3780 uint32 Player::CalculateHonorRank(float honor_points) const
3782 int rank = 0;
3784 if(honor_points <= 0.00) rank = 0; else
3785 if(honor_points < 2000.00) rank = 1;
3786 else
3787 rank = ( (int)(honor_points / 5000) + 1);
3789 return rank;
3792 //How many times Player kill pVictim...
3793 int Player::CalculateTotalKills(Player *pVictim) const
3795 int total_kills = 0;
3797 QueryResult *result = sDatabase.PQuery("SELECT `honor` FROM `character_kill` WHERE `guid` = '%u' AND `creature_template` = '%u'", GetGUIDLow(), pVictim->GetEntry());
3799 if(result)
3801 total_kills = result->GetRowCount();
3802 delete result;
3804 return total_kills;
3807 //How much honor Player gains/loses killing uVictim
3808 void Player::CalculateHonor(Unit *uVictim)
3810 float parcial_honor_points = 0;
3811 int kill_type = 0;
3812 bool savekill = false;
3814 sLog.outDetail("PLAYER: CalculateHonor");
3816 if( !uVictim ) return;
3818 if( uVictim->GetTypeId() == TYPEID_UNIT )
3820 Creature *cVictim = (Creature *)uVictim;
3821 if( cVictim->isCivilian() )
3823 parcial_honor_points = MaNGOS::Honor::DishonorableKillPoints( getLevel() );
3824 kill_type = DISHONORABLE_KILL;
3825 savekill = true;
3828 else
3829 if( uVictim->GetTypeId() == TYPEID_PLAYER )
3831 Player *pVictim = (Player *)uVictim;
3833 if( GetTeam() == pVictim->GetTeam() ) return;
3835 if( getLevel() < (pVictim->getLevel()+5) )
3837 parcial_honor_points = MaNGOS::Honor::HonorableKillPoints( this, pVictim );
3838 kill_type = HONORABLE_KILL;
3839 savekill = true;
3843 if (savekill)
3845 time_t rawtime;
3846 struct tm * now;
3847 uint32 today = 0;
3848 time( &rawtime );
3849 now = localtime( &rawtime );
3850 today = ((uint32)(now->tm_year << 16)|(uint32)(now->tm_yday));
3852 sDatabase.PExecute("INSERT INTO `character_kill` (`guid`,`creature_template`,`honor`,`date`,`type`) VALUES (%u, %u, %f, %u, %u)", (uint32)GetGUIDLow(), (uint32)uVictim->GetEntry(), (float)parcial_honor_points, (uint32)today, (uint8)kill_type);
3854 UpdateHonor();
3858 uint32 Player::GetGuildIdFromDB(uint64 guid)
3860 std::ostringstream ss;
3861 ss<<"SELECT `guildid` FROM `guild_member` WHERE `guid`='"<<guid<<"'";
3862 QueryResult *result = sDatabase.Query( ss.str().c_str() );
3863 if( result )
3864 return (*result)[0].GetUInt32();
3865 else
3866 return 0;
3869 uint32 Player::GetRankFromDB(uint64 guid)
3871 std::ostringstream ss;
3872 ss<<"SELECT `rank` FROM `guild_member` WHERE `guid`='"<<guid<<"'";
3873 QueryResult *result = sDatabase.Query( ss.str().c_str() );
3874 if( result )
3875 return (*result)[0].GetUInt32();
3876 else
3877 return 0;
3880 uint32 Player::GetZoneIdFromDB(uint64 guid)
3882 std::ostringstream ss;
3883 ss<<"SELECT `map`,`position_x`,`position_y` FROM `character` WHERE `guid`='"<<guid<<"'";
3884 QueryResult *result = sDatabase.Query( ss.str().c_str() );
3885 if( !result )
3886 return 0;
3888 return MapManager::Instance().GetMap((*result)[0].GetUInt32())->GetZoneId((*result)[0].GetFloat(),(*result)[0].GetFloat());
3891 //If players are too far way of duel flag... then player loose the duel
3892 void Player::CheckDuelDistance()
3894 if( !isInDuel() ) return;
3896 uint64 duelFlagGUID = GetUInt64Value(PLAYER_DUEL_ARBITER);
3898 GameObject* obj = ObjectAccessor::Instance().GetGameObject(*this, duelFlagGUID);
3900 //If the distance of duel flag is > 50
3901 if( !obj || !IsWithinDist(obj, 50))
3903 DuelComplete();
3908 void Player::DuelComplete()
3910 // duel not requested
3911 if(!m_pDuel)
3912 return;
3914 WorldPacket data;
3915 uint64 duelFlagGUID = GetUInt64Value(PLAYER_DUEL_ARBITER);
3917 // if dual really started
3918 if(isInDuel())
3920 CombatStop();
3921 m_pDuel->CombatStop();
3923 data.Initialize(SMSG_DUEL_WINNER);
3924 data << (uint8)0;
3925 data << m_pDuel->GetName();
3926 data << GetName();
3927 SendMessageToSet(&data,true);
3929 data.Initialize(SMSG_DUEL_COMPLETE);
3930 data << (uint8)1;
3931 GetSession()->SendPacket(&data);
3932 m_pDuel->GetSession()->SendPacket(&data);
3934 SetInDuel(false);
3935 m_pDuel->SetInDuel(false);
3937 #if 1
3938 //Restore the state of pvpOn
3939 RestorePvpState();
3940 m_pDuel->RestorePvpState();
3941 //Restore to correct factiontemplate
3942 setFactionForRace(getRace());
3943 m_pDuel->setFactionForRace(m_pDuel->getRace());
3944 //Restore pet factiontemplate
3945 if(Creature* pet = GetPet())
3947 pet->CombatStop();
3948 pet->setFaction(getFaction());
3950 if(Creature* pet = m_pDuel->GetPet())
3952 pet->CombatStop();
3953 pet->setFaction(m_pDuel->getFaction());
3955 #endif
3957 //ResurrectPlayer();
3958 if(!isAlive())
3959 setDeathState(ALIVE);
3961 else // duel not started
3963 data.Initialize(SMSG_DUEL_COMPLETE);
3964 data << (uint8)0;
3965 GetSession()->SendPacket(&data);
3966 m_pDuel->GetSession()->SendPacket(&data);
3969 //Remove Duel Flag object
3970 GameObject* obj = ObjectAccessor::Instance().GetGameObject(*this, duelFlagGUID);
3971 if(obj)
3972 m_pDuelSender->RemoveGameObject(obj,true);
3974 //Player kneel when finish the duel
3975 if(isInDuel())
3976 HandleEmoteCommand(ANIM_EMOTE_BEG);
3978 SetUInt64Value(PLAYER_DUEL_ARBITER, 0);
3979 SetUInt32Value(PLAYER_DUEL_TEAM, 0);
3980 m_pDuel->SetUInt64Value(PLAYER_DUEL_ARBITER, 0);
3981 m_pDuel->SetUInt32Value(PLAYER_DUEL_TEAM, 0);
3983 // cleanup pointers
3984 m_pDuel->m_pDuelSender = NULL;
3985 m_pDuel->m_pDuel = NULL;
3986 m_pDuelSender = NULL;
3987 m_pDuel = NULL;
3990 static unsigned long holdrand = 0x89abcdef;
3992 void Rand_Init(int seed)
3994 holdrand = seed;
3997 int irand(int min, int max)
3999 assert((max - min) < 32768);
4001 max++;
4002 holdrand = (holdrand * 214013L) + 2531011L;
4004 return (((holdrand >> 17) * (max - min)) >> 15) + min;
4007 //---------------------------------------------------------//
4008 // Flight callback
4009 void Player::FlightComplete()
4011 clearUnitState(UNIT_STAT_IN_FLIGHT);
4012 SetMoney( m_dismountCost);
4013 Unmount();
4016 void Player::_ApplyItemMods(Item *item, uint8 slot,bool apply)
4018 if(slot >= INVENTORY_SLOT_BAG_END || !item) return;
4020 // not apply/premove mods for broken item
4021 if(item->IsBroken()) return;
4023 ItemPrototype const *proto = item->GetProto();
4025 if(!proto) return;
4027 sLog.outDetail("applying mods for item %u ",item->GetGUIDLow());
4028 if(proto->ItemSet)
4030 if (apply)
4031 AddItemsSetItem(this,item);
4032 else
4033 RemoveItemsSetItem(this,proto);
4036 _RemoveStatsMods();
4037 AuraList& mModBaseResistancePct = GetAurasByType(SPELL_AURA_MOD_BASE_RESISTANCE_PCT);
4038 for(AuraList::iterator i = mModBaseResistancePct.begin(); i != mModBaseResistancePct.end(); ++i)
4039 (*i)->ApplyModifier(false);
4041 _ApplyItemBonuses(proto,slot,apply);
4043 for(AuraList::iterator i = mModBaseResistancePct.begin(); i != mModBaseResistancePct.end(); ++i)
4044 (*i)->ApplyModifier(true);
4045 _ApplyStatsMods();
4047 if(apply)
4048 CastItemEquipSpell(item);
4049 else
4050 for (int i = 0; i < 5; i++)
4051 if(proto->Spells[i].SpellId)
4052 RemoveAurasDueToSpell(proto->Spells[i].SpellId );
4054 for(int enchant_slot = 0 ; enchant_slot < 7; enchant_slot++)
4056 uint32 Enchant_id = item->GetUInt32Value(ITEM_FIELD_ENCHANTMENT+enchant_slot*3);
4057 if(Enchant_id)
4058 AddItemEnchant(item,Enchant_id, apply);
4061 sLog.outDebug("_ApplyItemMods complete.");
4064 void Player::_ApplyItemBonuses(ItemPrototype const *proto,uint8 slot,bool apply)
4066 if(slot >= INVENTORY_SLOT_BAG_END || !proto) return;
4068 int32 val;
4069 std::string typestr;
4070 std::string applystr = apply ? "Add" : "Remove";
4071 for (int i = 0; i < 10; i++)
4073 val = proto->ItemStat[i].ItemStatValue ;
4075 switch (proto->ItemStat[i].ItemStatType)
4077 case POWER: // modify MP
4078 ApplyMaxPowerMod(POWER_MANA, val, apply);
4079 typestr = "Mana";
4080 break;
4081 case HEALTH: // modify HP
4082 ApplyMaxHealthMod(val, apply);
4083 typestr = "Health";
4084 break;
4085 case AGILITY: // modify agility
4086 ApplyStatMod(STAT_AGILITY, val, apply);
4087 ApplyPosStatMod(STAT_AGILITY, val, apply);
4088 typestr = "AGILITY";
4089 break;
4090 case STRENGHT: //modify strength
4091 ApplyStatMod(STAT_STRENGTH, val, apply);
4092 ApplyPosStatMod(STAT_STRENGTH, val, apply);
4093 typestr = "STRENGHT";
4094 break;
4095 case INTELLECT: //modify intellect
4096 ApplyStatMod(STAT_INTELLECT, val, apply);
4097 ApplyPosStatMod(STAT_INTELLECT, val, apply);
4098 //ApplyMaxPowerMod(POWER_MANA, val*15, apply);
4099 typestr = "INTELLECT";
4100 break;
4101 case SPIRIT: //modify spirit
4102 ApplyStatMod(STAT_SPIRIT, val, apply);
4103 ApplyPosStatMod(STAT_SPIRIT, val, apply);
4104 typestr = "SPIRIT";
4105 break;
4106 case STAMINA: //modify stamina
4107 ApplyStatMod(STAT_STAMINA ,val, apply);
4108 ApplyPosStatMod(STAT_STAMINA ,val, apply);
4109 //ApplyMaxHealthMod( val*10,apply);
4110 typestr = "STAMINA";
4111 break;
4113 if(val > 0)
4114 sLog.outDebug("%s %s: \t\t%u", applystr.c_str(), typestr.c_str(), val);
4118 if (proto->Armor)
4120 ApplyArmorMod( proto->Armor, apply);
4121 sLog.outDebug("%s Armor: \t\t%u", applystr.c_str(), proto->Armor);
4124 if (proto->Block)
4126 ApplyBlockValueMod(proto->Block, apply);
4127 sLog.outDebug("%s Block: \t\t%u", applystr.c_str(), proto->Block);
4130 if (proto->HolyRes)
4132 ApplyResistanceMod(SPELL_SCHOOL_HOLY, proto->HolyRes, apply);
4133 sLog.outDebug("%s HolyRes: \t\t%u", applystr.c_str(), proto->HolyRes);
4136 if (proto->FireRes)
4138 ApplyResistanceMod(SPELL_SCHOOL_FIRE, proto->FireRes, apply);
4139 sLog.outDebug("%s FireRes: \t\t%u", applystr.c_str(), proto->FireRes);
4142 if (proto->NatureRes)
4144 ApplyResistanceMod(SPELL_SCHOOL_NATURE, proto->NatureRes, apply);
4145 sLog.outDebug("%s NatureRes: \t\t%u", applystr.c_str(), proto->NatureRes);
4148 if (proto->FrostRes)
4150 ApplyResistanceMod(SPELL_SCHOOL_FROST, proto->FrostRes, apply);
4151 sLog.outDebug("%s FrostRes: \t\t%u", applystr.c_str(), proto->FrostRes);
4154 if (proto->ShadowRes)
4156 ApplyResistanceMod(SPELL_SCHOOL_SHADOW, proto->ShadowRes, apply);
4157 sLog.outDebug("%s ShadowRes: \t\t%u", applystr.c_str(), proto->ShadowRes);
4160 if (proto->ArcaneRes)
4162 ApplyResistanceMod(SPELL_SCHOOL_ARCANE, proto->ArcaneRes, apply);
4163 sLog.outDebug("%s ArcaneRes: \t\t%u", applystr.c_str(), proto->ArcaneRes);
4166 uint8 MINDAMAGEFIELD = 0;
4167 uint8 MAXDAMAGEFIELD = 0;
4169 if( slot == EQUIPMENT_SLOT_RANGED && ( proto->InventoryType == INVTYPE_RANGED ||
4170 proto->InventoryType == INVTYPE_THROWN || proto->InventoryType == INVTYPE_RANGEDRIGHT))
4172 MINDAMAGEFIELD = UNIT_FIELD_MINRANGEDDAMAGE;
4173 MAXDAMAGEFIELD = UNIT_FIELD_MAXRANGEDDAMAGE;
4174 typestr = "Ranged";
4176 else if(slot==EQUIPMENT_SLOT_MAINHAND)
4178 MINDAMAGEFIELD = UNIT_FIELD_MINDAMAGE;
4179 MAXDAMAGEFIELD = UNIT_FIELD_MAXDAMAGE;
4180 typestr = "Mainhand";
4182 else if(slot==EQUIPMENT_SLOT_OFFHAND)
4184 MINDAMAGEFIELD = UNIT_FIELD_MINOFFHANDDAMAGE;
4185 MAXDAMAGEFIELD = UNIT_FIELD_MAXOFFHANDDAMAGE;
4186 typestr = "Offhand";
4189 if (proto->Damage[0].DamageMin > 0 && MINDAMAGEFIELD)
4191 ApplyModFloatValue(MINDAMAGEFIELD, proto->Damage[0].DamageMin, apply);
4192 sLog.outDetail("%s %s mindam: %f, now is: %f", applystr.c_str(), typestr.c_str(), proto->Damage[0].DamageMin, GetFloatValue(MINDAMAGEFIELD));
4195 if (proto->Damage[0].DamageMax > 0 && MAXDAMAGEFIELD)
4197 ApplyModFloatValue(MAXDAMAGEFIELD, proto->Damage[0].DamageMax, apply);
4198 sLog.outDetail("%s %s mindam: %f, now is: %f", applystr.c_str(), typestr.c_str(), proto->Damage[0].DamageMax, GetFloatValue(MAXDAMAGEFIELD));
4201 if (proto->Delay)
4203 if(slot == EQUIPMENT_SLOT_RANGED)
4205 SetAttackTime(RANGED_ATTACK, apply ? proto->Delay: 2000);
4206 typestr = "Range";
4207 sLog.outDebug("%s %s Delay: \t\t%u", applystr.c_str(), typestr.c_str(), proto->Delay);
4209 else if(slot==EQUIPMENT_SLOT_MAINHAND)
4211 SetAttackTime(BASE_ATTACK, apply ? proto->Delay: 2000);
4212 typestr = "Mainhand";
4213 sLog.outDebug("%s %s Delay: \t\t%u", applystr.c_str(), typestr.c_str(), proto->Delay);
4215 else if(slot==EQUIPMENT_SLOT_OFFHAND)
4217 SetAttackTime(OFF_ATTACK, apply ? proto->Delay: 2000);
4218 typestr = "Offhand";
4219 sLog.outDebug("%s %s Delay: \t\t%u", applystr.c_str(), typestr.c_str(), proto->Delay);
4224 void Player::CastItemEquipSpell(Item *item)
4226 if(!item) return;
4228 ItemPrototype const *proto = item->GetProto();
4230 if(!proto) return;
4232 SpellEntry *spellInfo;
4234 for (int i = 0; i < 5; i++)
4236 if(!proto->Spells[i].SpellId ) continue;
4237 if(proto->Spells[i].SpellTrigger != ON_EQUIP) continue;
4239 spellInfo = sSpellStore.LookupEntry(proto->Spells[i].SpellId);
4240 if(!spellInfo)
4242 sLog.outError("WORLD: unknown Item spellid %i", proto->Spells[i].SpellId);
4243 continue;
4246 DEBUG_LOG("WORLD: cast Item spellId - %i", proto->Spells[i].SpellId);
4248 Spell spell(this, spellInfo, true, 0);
4250 SpellCastTargets targets;
4251 targets.setUnitTarget( this );
4252 spell.m_CastItem = item;
4253 spell.prepare(&targets);
4257 void Player::CastItemCombatSpell(Item *item,Unit* Target)
4259 if(!item || item->IsBroken())
4260 return;
4262 ItemPrototype const *proto = item->GetProto();
4263 if(!proto)
4264 return;
4266 if (!Target || Target == this )
4267 return;
4269 SpellEntry *spellInfo;
4271 for (int i = 0; i < 5; i++)
4273 if(!proto->Spells[i].SpellId ) continue;
4275 spellInfo = sSpellStore.LookupEntry(proto->Spells[i].SpellId);
4276 if(!spellInfo)
4278 sLog.outError("WORLD: unknown Item spellid %i", proto->Spells[i].SpellId);
4279 continue;
4282 if(proto->Spells[i].SpellTrigger != CHANCE_ON_HIT) continue;
4284 uint32 chance = spellInfo->procChance <= 100 ? spellInfo->procChance : GetWeaponProcChance();
4285 if (chance > rand_chance())
4286 this->CastSpell(Target, spellInfo->Id, true, item);
4289 // item combat enchantments
4290 for(int e_slot = 0; e_slot < 7; e_slot++)
4292 uint32 enchant_id = item->GetUInt32Value(ITEM_FIELD_ENCHANTMENT+e_slot*3);
4293 SpellItemEnchantmentEntry *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
4294 if(!pEnchant) continue;
4295 uint32 enchant_display = pEnchant->display_type;
4296 uint32 chance = pEnchant->value1 != 0 ? pEnchant->value1 : GetWeaponProcChance();
4297 uint32 enchant_spell_id = pEnchant->spellid;
4298 SpellEntry *enchantSpell_info = sSpellStore.LookupEntry(enchant_spell_id);
4299 if(!enchantSpell_info) continue;
4300 if(enchant_display!=4 && enchant_display!=2 && this->IsItemSpellToCombat(enchantSpell_info))
4301 if (chance > rand_chance())
4302 this->CastSpell(Target, enchantSpell_info->Id, true);
4306 // only some item spell/auras effects can be executed when item is equiped.
4307 // If not you can have unexpected beaviur. like item giving damage to player when equip.
4308 bool Player::IsItemSpellToEquip(SpellEntry *spellInfo)
4310 return (GetDuration(spellInfo) == -1); // infinite duration -> passive aura
4312 for(int j = 0; j< 3; j++)
4314 if(spellInfo->Effect[j] == 6)
4316 switch(spellInfo->EffectApplyAuraName[j])
4318 case 3:
4319 case 23:
4320 case 8:
4321 case 84:
4322 case 85:
4323 case 42:
4324 case 43:
4325 return false;
4330 return true;
4334 // only some item spell/auras effects can be executed when in combat.
4335 // If not you can have unexpected beaviur. like having stats always growing each attack.
4336 bool Player::IsItemSpellToCombat(SpellEntry *spellInfo)
4338 return (GetDuration(spellInfo) != -1); // infinite duration -> passive aura
4341 for(int j = 0; j< 3; j++)
4343 if(spellInfo->Effect[j] == 6)
4345 switch(spellInfo->EffectApplyAuraName[j])
4347 case 3:
4348 case 23:
4349 case 8:
4350 case 84:
4351 case 85:
4352 case 42:
4353 case 43:
4354 return true;
4359 return false;
4363 void Player::_RemoveAllItemMods()
4365 sLog.outDebug("_RemoveAllItemMods start.");
4367 for (int i = 0; i < INVENTORY_SLOT_BAG_END; i++)
4369 if(m_items[i])
4371 if(m_items[i]->IsBroken()) break;
4372 ItemPrototype const *proto = m_items[i]->GetProto();
4373 if(!proto) break;
4374 if(proto->ItemSet)
4375 RemoveItemsSetItem(this,proto);
4377 for (int m = 0; m < 5; m++)
4379 if(proto->Spells[m].SpellId)
4380 RemoveAurasDueToSpell(proto->Spells[m].SpellId );
4383 for(int enchant_slot = 0 ; enchant_slot < 7; enchant_slot++)
4385 uint32 Enchant_id = m_items[i]->GetUInt32Value(ITEM_FIELD_ENCHANTMENT+enchant_slot*3);
4386 if(Enchant_id)
4387 AddItemEnchant(m_items[i],Enchant_id, false);
4392 _RemoveStatsMods();
4394 AuraList& mModBaseResistancePct = GetAurasByType(SPELL_AURA_MOD_BASE_RESISTANCE_PCT);
4395 for(AuraList::iterator i = mModBaseResistancePct.begin(); i != mModBaseResistancePct.end(); ++i)
4396 (*i)->ApplyModifier(false);
4398 for (int i = 0; i < INVENTORY_SLOT_BAG_END; i++)
4400 if(m_items[i])
4402 if(m_items[i]->IsBroken()) break;
4403 ItemPrototype const *proto = m_items[i]->GetProto();
4404 if(!proto) break;
4405 _ApplyItemBonuses(proto,i, false);
4409 for(AuraList::iterator i = mModBaseResistancePct.begin(); i != mModBaseResistancePct.end(); ++i)
4410 (*i)->ApplyModifier(true);
4412 _ApplyStatsMods();
4414 sLog.outDebug("_RemoveAllItemMods complete.");
4417 void Player::_ApplyAllItemMods()
4419 sLog.outDebug("_ApplyAllItemMods start.");
4421 for (int i = 0; i < INVENTORY_SLOT_BAG_END; i++)
4423 if(m_items[i])
4425 if(m_items[i]->IsBroken()) break;
4426 ItemPrototype const *proto = m_items[i]->GetProto();
4427 if(!proto) break;
4428 if(proto->ItemSet)
4429 AddItemsSetItem(this,m_items[i]);
4431 CastItemEquipSpell(m_items[i]);
4433 for(int enchant_slot = 0 ; enchant_slot < 7; enchant_slot++)
4435 uint32 Enchant_id = m_items[i]->GetUInt32Value(ITEM_FIELD_ENCHANTMENT+enchant_slot*3);
4436 if(Enchant_id)
4437 AddItemEnchant(m_items[i],Enchant_id, true);
4442 _RemoveStatsMods();
4444 AuraList& mModBaseResistancePct = GetAurasByType(SPELL_AURA_MOD_BASE_RESISTANCE_PCT);
4445 for(AuraList::iterator i = mModBaseResistancePct.begin(); i != mModBaseResistancePct.end(); ++i)
4446 (*i)->ApplyModifier(false);
4448 for (int i = 0; i < INVENTORY_SLOT_BAG_END; i++)
4450 if(m_items[i])
4452 if(m_items[i]->IsBroken()) break;
4453 ItemPrototype const *proto = m_items[i]->GetProto();
4454 if(!proto) break;
4455 _ApplyItemBonuses(proto,i, true);
4459 for(AuraList::iterator i = mModBaseResistancePct.begin(); i != mModBaseResistancePct.end(); ++i)
4460 (*i)->ApplyModifier(true);
4462 _ApplyStatsMods();
4464 sLog.outDebug("_ApplyAllItemMods complete.");
4467 /*Loot type MUST be
4468 1-corpse, go
4469 2-skinning
4470 3-Fishing
4473 void Player::SendLoot(uint64 guid, LootType loot_type)
4475 Loot *loot = NULL;
4476 PermissionTypes permission = ALL_PERMISSION;
4478 if (IS_GAMEOBJECT_GUID(guid))
4480 GameObject *go =
4481 ObjectAccessor::Instance().GetGameObject(*this, guid);
4483 if (!go || !go->IsWithinDistInMap(this,OBJECT_ITERACTION_DISTANCE))
4484 return;
4486 loot = &go->loot;
4488 if(go->getLootState() == GO_CLOSED)
4490 uint32 lootid = go->lootid;
4492 if(lootid)
4493 FillLoot(this,loot,lootid,LootTemplates_Gameobject);
4495 if(loot_type == LOOT_FISHING)
4496 go->getFishLoot(loot);
4498 go->SetLootState(GO_OPEN);
4501 else if (IS_ITEM_GUID(guid))
4503 Item *item = this->GetItemByPos( this->GetPosByGuid( guid ));
4505 if (!item)
4506 return;
4508 loot = &item->loot;
4509 FillLoot(this,loot,item->GetEntry(),LootTemplates_Item);
4511 else
4513 Creature *creature =
4514 ObjectAccessor::Instance().GetCreature(*this, guid);
4516 if (!creature || creature->isAlive() || !creature->IsWithinDistInMap(this,OBJECT_ITERACTION_DISTANCE))
4517 return;
4519 loot = &creature->loot;
4521 uint32 lootid = creature->GetCreatureInfo()->lootid;
4523 if(loot_type == LOOT_PICKPOKETING)
4525 if ( !creature->lootForPickPocketed )
4527 creature->lootForPickPocketed = true;
4528 loot->clear();
4530 if (!creature->HasFlag(UNIT_NPC_FLAGS,UNIT_NPC_FLAG_VENDOR) && lootid)
4531 FillLoot(this,loot,lootid,LootTemplates_Pickpocketing);
4532 // Generate extra money for pick pocket loot
4533 loot->gold = uint32((10* (rand() % ( (creature->getLevel() / 2) + 1) + rand() % ( (getLevel() / 2) + 1 )))*sWorld.getRate(RATE_DROP_MONEY));
4536 else
4538 // the player whose group may loot the corpse
4539 Player *recipient = creature->GetLootRecipient();
4540 if (!recipient)
4542 creature->SetLootRecipient(this);
4543 recipient = this;
4546 if (creature->lootForPickPocketed)
4548 creature->lootForPickPocketed = false;
4549 loot->clear();
4552 if(!creature->lootForBody)
4554 creature->lootForBody = true;
4555 if (!creature->HasFlag(UNIT_NPC_FLAGS,UNIT_NPC_FLAG_VENDOR) && lootid)
4556 FillLoot(this,loot,lootid,LootTemplates_Creature);
4558 creature->generateMoneyLoot();
4560 if (recipient->IsInGroup())
4562 // round robin style looting applies for all low
4563 // quality items in each loot metho except free for all
4564 Group *group = objmgr.GetGroupByLeader(recipient->GetGroupLeader());
4565 uint32 siz = group->GetMembersCount();
4566 uint32 pos = 0;
4567 for (pos = 0; pos<siz; pos++)
4568 if (group->GetMemberGUID(pos) == group->GetLooterGuid())
4569 break;
4570 group->SetLooterGuid(group->GetMemberGUID((pos+1)%siz));
4572 switch (group->GetLootMethod())
4574 case GROUP_LOOT:
4575 // GroupLoot delete items over threshold (threshold even not implemented), and roll them. Items with quality<threshold, round robin
4576 group->GroupLoot(recipient->GetGUID(), loot, creature);
4577 break;
4578 case NEED_BEFORE_GREED:
4579 group->NeedBeforeGreed(recipient->GetGUID(), loot, creature);
4580 break;
4585 if (loot_type == LOOT_SKINNING)
4587 loot->clear();
4588 FillLoot(this,loot,creature->GetCreatureInfo()->SkinLootId,LootTemplates_Skinning);
4589 for(std::vector<LootItem>::iterator i = loot->items.begin(); i != loot->items.end(); ++i)
4591 LootSkinnigAlternative::iterator i2iter = sLootSkinnigAlternative.find(i->itemid);
4592 if(i2iter != sLootSkinnigAlternative.end())
4594 if(rand_chance() > 80)
4596 i->itemid = i2iter->second.itemid;
4597 i->displayid = i2iter->second.displayid;
4603 if (!IsInGroup() && recipient == this)
4604 permission = ALL_PERMISSION;
4605 else
4607 if (IsInGroup())
4609 Group *group = objmgr.GetGroupByLeader(recipient->GetGroupLeader());
4610 if ((GetGroupLeader() == recipient->GetGroupLeader()) && (group->GetLooterGuid() == GetGUID() || loot->released || group->GetLootMethod() == FREE_FOR_ALL))
4611 permission = ALL_PERMISSION;
4612 else
4613 if (GetGroupLeader() == recipient->GetGroupLeader())
4614 permission = GROUP_PERMISSION;
4615 else
4616 permission = NONE_PERMISSION;
4618 else
4619 permission = NONE_PERMISSION;
4624 m_lootGuid = guid;
4626 QuestItemList *q_list = NULL;
4627 if (permission != NONE_PERMISSION)
4629 QuestItemMap::iterator itr = loot->PlayerQuestItems.find(this);
4630 if (itr == loot->PlayerQuestItems.end())
4631 q_list = FillQuestLoot(this, loot);
4632 else
4633 q_list = itr->second;
4636 // LOOT_PICKPOKETING unsupported by client, sending LOOT_SKINNING instead
4637 if(loot_type == LOOT_PICKPOKETING)
4638 loot_type = LOOT_SKINNING;
4640 WorldPacket data;
4641 data.Initialize (SMSG_LOOT_RESPONSE);
4643 data << guid;
4644 data << uint8(loot_type);
4645 data << LootView(*loot, q_list, permission);
4647 SendDirectMessage(&data);
4649 // add 'this' player as one of the players that are looting 'loot'
4650 if (permission != NONE_PERMISSION)
4651 loot->AddLooter(this);
4654 void Player::SendNotifyLootMoneyRemoved()
4656 WorldPacket data;
4657 data.Initialize( SMSG_LOOT_CLEAR_MONEY );
4658 GetSession()->SendPacket( &data );
4661 void Player::SendNotifyLootItemRemoved(uint8 lootSlot)
4663 WorldPacket data;
4664 data.Initialize( SMSG_LOOT_REMOVED );
4665 data << uint8(lootSlot);
4666 GetSession()->SendPacket( &data );
4669 void Player::SendUpdateWordState(uint16 Field, uint16 Value)
4671 WorldPacket data;
4672 data.Initialize(SMSG_UPDATE_WORLD_STATE); //0x2D4
4673 data << uint32(Field);
4674 data << uint32(Value);
4675 GetSession()->SendPacket(&data);
4678 void Player::SendInitWorldStates(uint32 MapID)
4680 // TODO Figure out the unknown data.
4682 if ((MapID == 0) || (MapID == 1))
4684 sLog.outDebug("Sending SMSG_INIT_WORLD_STATES to Map:%u",MapID);
4686 uint16 NumberOfFields = 108;
4687 WorldPacket data;
4688 data.Initialize (SMSG_INIT_WORLD_STATES); //0x2C5
4689 data <<
4690 (uint32)MapID <<
4691 (uint16)NumberOfFields <<
4692 //field (uint16) value (uint16)
4693 (uint16)0x07AE<< (uint16)0x01<<
4694 (uint16)0x0532<< (uint16)0x01<<
4695 (uint16)0x0531<< (uint16)0x00<<
4696 (uint16)0x052E<< (uint16)0x00<<
4697 (uint16)0x06F9<< (uint16)0x00<<
4698 (uint16)0x06F3<< (uint16)0x00<<
4699 (uint16)0x06F1<< (uint16)0x00<<
4700 (uint16)0x06EE<< (uint16)0x00<<
4701 (uint16)0x06ED<< (uint16)0x00<<
4702 (uint16)0x0571<< (uint16)0x00<<
4703 (uint16)0x0570<< (uint16)0x00<<
4704 (uint16)0x0567<< (uint16)0x01<<
4705 (uint16)0x0566<< (uint16)0x01<<
4706 (uint16)0x0550<< (uint16)0x01<<
4707 (uint16)0x0544<< (uint16)0x00<<
4708 (uint16)0x0536<< (uint16)0x00<<
4709 (uint16)0x0535<< (uint16)0x01<<
4710 (uint16)0x03C6<< (uint16)0x00<<
4711 (uint16)0x03C4<< (uint16)0x00<<
4712 (uint16)0x03C2<< (uint16)0x00<<
4713 (uint16)0x07A8<< (uint16)0x00<<
4714 (uint16)0x07A3<< (uint16)0x270F<<
4715 (uint16)0x0574<< (uint16)0x00<<
4716 (uint16)0x0573<< (uint16)0x00<<
4717 (uint16)0x0572<< (uint16)0x00<<
4718 (uint16)0x056F<< (uint16)0x00<<
4719 (uint16)0x056E<< (uint16)0x00<<
4720 (uint16)0x056D<< (uint16)0x00<<
4721 (uint16)0x056C<< (uint16)0x00<<
4722 (uint16)0x056B<< (uint16)0x00<<
4723 (uint16)0x056A<< (uint16)0x01<<
4724 (uint16)0x0569<< (uint16)0x01<<
4725 (uint16)0x0568<< (uint16)0x01<<
4726 (uint16)0x0565<< (uint16)0x00<<
4727 (uint16)0x0564<< (uint16)0x00<<
4728 (uint16)0x0563<< (uint16)0x00<<
4729 (uint16)0x0562<< (uint16)0x00<<
4730 (uint16)0x0561<< (uint16)0x00<<
4731 (uint16)0x0560<< (uint16)0x00<<
4732 (uint16)0x055F<< (uint16)0x00<<
4733 (uint16)0x055E<< (uint16)0x00<<
4734 (uint16)0x055D<< (uint16)0x00<<
4735 (uint16)0x055C<< (uint16)0x00<<
4736 (uint16)0x055B<< (uint16)0x00<<
4737 (uint16)0x055A<< (uint16)0x00<<
4738 (uint16)0x0559<< (uint16)0x00<<
4739 (uint16)0x0558<< (uint16)0x00<<
4740 (uint16)0x0557<< (uint16)0x00<<
4741 (uint16)0x0556<< (uint16)0x00<<
4742 (uint16)0x0555<< (uint16)0x00<<
4743 (uint16)0x0554<< (uint16)0x01<<
4744 (uint16)0x0553<< (uint16)0x01<<
4745 (uint16)0x0552<< (uint16)0x01<<
4746 (uint16)0x0551<< (uint16)0x01<<
4747 (uint16)0x054F<< (uint16)0x00<<
4748 (uint16)0x054E<< (uint16)0x00<<
4749 (uint16)0x054D<< (uint16)0x01<<
4750 (uint16)0x054C<< (uint16)0x00<<
4751 (uint16)0x054B<< (uint16)0x00<<
4752 (uint16)0x0545<< (uint16)0x00<<
4753 (uint16)0x0543<< (uint16)0x01<<
4754 (uint16)0x0542<< (uint16)0x00<<
4755 (uint16)0x0540<< (uint16)0x00<<
4756 (uint16)0x053F<< (uint16)0x00<<
4757 (uint16)0x053E<< (uint16)0x00<<
4758 (uint16)0x053D<< (uint16)0x00<<
4759 (uint16)0x053C<< (uint16)0x00<<
4760 (uint16)0x053B<< (uint16)0x00<<
4761 (uint16)0x053A<< (uint16)0x01<<
4762 (uint16)0x0539<< (uint16)0x00<<
4763 (uint16)0x0538<< (uint16)0x00<<
4764 (uint16)0x0537<< (uint16)0x00<<
4765 (uint16)0x0534<< (uint16)0x00<<
4766 (uint16)0x0533<< (uint16)0x00<<
4767 (uint16)0x0530<< (uint16)0x00<<
4768 (uint16)0x052F<< (uint16)0x00<<
4769 (uint16)0x052D<< (uint16)0x01<<
4770 (uint16)0x0516<< (uint16)0x01<<
4771 (uint16)0x0515<< (uint16)0x00<<
4772 (uint16)0x03B6<< (uint16)0x00<<
4773 (uint16)0x0745<< (uint16)0x02<<
4774 (uint16)0x0736<< (uint16)0x01<<
4775 (uint16)0x0735<< (uint16)0x01<<
4776 (uint16)0x0734<< (uint16)0x01<<
4777 (uint16)0x0733<< (uint16)0x01<<
4778 (uint16)0x0732<< (uint16)0x01<<
4779 (uint16)0x0702<< (uint16)0x00<<
4780 (uint16)0x0701<< (uint16)0x00<<
4781 (uint16)0x0700<< (uint16)0x00<<
4782 (uint16)0x06FE<< (uint16)0x00<<
4783 (uint16)0x06FD<< (uint16)0x00<<
4784 (uint16)0x06FC<< (uint16)0x00<<
4785 (uint16)0x06FB<< (uint16)0x00<<
4786 (uint16)0x06F8<< (uint16)0x00<<
4787 (uint16)0x06F7<< (uint16)0x00<<
4788 (uint16)0x06F6<< (uint16)0x00<<
4789 (uint16)0x06F4<< (uint16)0x7D0<<
4790 (uint16)0x06F2<< (uint16)0x00<<
4791 (uint16)0x06F0<< (uint16)0x00<<
4792 (uint16)0x06EF<< (uint16)0x00<<
4793 (uint16)0x06EC<< (uint16)0x00<<
4794 (uint16)0x06EA<< (uint16)0x00<<
4795 (uint16)0x06E9<< (uint16)0x00<<
4796 (uint16)0x06E8<< (uint16)0x00<<
4797 (uint16)0x06E7<< (uint16)0x00<<
4798 (uint16)0x0518<< (uint16)0x00<<
4799 (uint16)0x0517<< (uint16)0x00<<
4800 (uint16)0x0703<< (uint16)0x00;
4801 GetSession()->SendPacket(&data);
4804 //BattleGround currently only map 489
4805 else if (MapID == 489) // && and guid is in a current Battlefield)
4807 sLog.outDebug("Sending SMSG_INIT_WORLD_STATES to Map:%u",MapID);
4809 uint16 NumberOfFields = 114;
4810 WorldPacket data;
4811 data.Initialize (SMSG_INIT_WORLD_STATES);
4812 data <<
4814 (uint32)MapID<<
4815 (uint16)NumberOfFields <<
4816 //field (uint16) value (uint16)
4817 (uint16)0x07AE<< (uint16)0x01<<
4818 (uint16)0x0532<< (uint16)0x01<<
4819 (uint16)0x0531<< (uint16)0x00<<
4820 (uint16)0x052E<< (uint16)0x00<<
4821 (uint16)0x06F9<< (uint16)0x00<<
4822 (uint16)0x06F3<< (uint16)0x00<<
4823 (uint16)0x06F1<< (uint16)0x00<<
4824 (uint16)0x06EE<< (uint16)0x00<<
4825 (uint16)0x06ED<< (uint16)0x00<<
4826 (uint16)0x0571<< (uint16)0x00<<
4827 (uint16)0x0570<< (uint16)0x00<<
4828 (uint16)0x0567<< (uint16)0x01<<
4829 (uint16)0x0566<< (uint16)0x01<<
4830 (uint16)0x0550<< (uint16)0x01<<
4831 (uint16)0x0544<< (uint16)0x00<<
4832 (uint16)0x0536<< (uint16)0x00<<
4833 (uint16)0x0535<< (uint16)0x01<<
4834 (uint16)0x03C6<< (uint16)0x00<<
4835 (uint16)0x03C4<< (uint16)0x00<<
4836 (uint16)0x03C2<< (uint16)0x00<<
4837 (uint16)0x07A8<< (uint16)0x00<<
4838 (uint16)0x07A3<< (uint16)0x270F <<
4839 (uint16)0x060B<< (uint16)0x02<<
4840 (uint16)0x0574<< (uint16)0x00<<
4841 (uint16)0x0573<< (uint16)0x00<<
4842 (uint16)0x0572<< (uint16)0x00<<
4843 (uint16)0x056F<< (uint16)0x00<<
4844 (uint16)0x056E<< (uint16)0x00<<
4845 (uint16)0x056D<< (uint16)0x00<<
4846 (uint16)0x056C<< (uint16)0x00<<
4847 (uint16)0x056B<< (uint16)0x00<<
4848 (uint16)0x056A<< (uint16)0x01<<
4849 (uint16)0x0569<< (uint16)0x01<<
4850 (uint16)0x0568<< (uint16)0x01<<
4851 (uint16)0x0565<< (uint16)0x00<<
4852 (uint16)0x0564<< (uint16)0x00<<
4853 (uint16)0x0563<< (uint16)0x00<<
4854 (uint16)0x0562<< (uint16)0x00<<
4855 (uint16)0x0561<< (uint16)0x00<<
4856 (uint16)0x0560<< (uint16)0x00<<
4857 (uint16)0x055F<< (uint16)0x00<<
4858 (uint16)0x055E<< (uint16)0x00<<
4859 (uint16)0x055D<< (uint16)0x00<<
4860 (uint16)0x055C<< (uint16)0x00<<
4861 (uint16)0x055B<< (uint16)0x00<<
4862 (uint16)0x055A<< (uint16)0x00<<
4863 (uint16)0x0559<< (uint16)0x00<<
4864 (uint16)0x0558<< (uint16)0x00<<
4865 (uint16)0x0557<< (uint16)0x00<<
4866 (uint16)0x0556<< (uint16)0x00<<
4867 (uint16)0x0555<< (uint16)0x00<<
4868 (uint16)0x0554<< (uint16)0x01<<
4869 (uint16)0x0553<< (uint16)0x01<<
4870 (uint16)0x0552<< (uint16)0x01<<
4871 (uint16)0x0551<< (uint16)0x01<<
4872 (uint16)0x054F<< (uint16)0x00<<
4873 (uint16)0x054E<< (uint16)0x00<<
4874 (uint16)0x054D<< (uint16)0x01<<
4875 (uint16)0x054C<< (uint16)0x00<<
4876 (uint16)0x054B<< (uint16)0x00<<
4877 (uint16)0x0545<< (uint16)0x00<<
4878 (uint16)0x0543<< (uint16)0x01<<
4879 (uint16)0x0542<< (uint16)0x00<<
4880 (uint16)0x0540<< (uint16)0x00<<
4881 (uint16)0x053F<< (uint16)0x00<<
4882 (uint16)0x053E<< (uint16)0x00<<
4883 (uint16)0x053D<< (uint16)0x00<<
4884 (uint16)0x053C<< (uint16)0x00<<
4885 (uint16)0x053B<< (uint16)0x00<<
4886 (uint16)0x053A<< (uint16)0x01<<
4887 (uint16)0x0539<< (uint16)0x00<<
4888 (uint16)0x0538<< (uint16)0x00<<
4889 (uint16)0x0537<< (uint16)0x00<<
4890 (uint16)0x0534<< (uint16)0x00<<
4891 (uint16)0x0533<< (uint16)0x00<<
4892 (uint16)0x0530<< (uint16)0x00<<
4893 (uint16)0x052F<< (uint16)0x00<<
4894 (uint16)0x052D<< (uint16)0x01<<
4895 (uint16)0x0516<< (uint16)0x01<<
4896 (uint16)0x0515<< (uint16)0x00<<
4897 (uint16)0x03B6<< (uint16)0x00<<
4898 (uint16)0x0745<< (uint16)0x02<<
4899 (uint16)0x0736<< (uint16)0x01<<
4900 (uint16)0x0735<< (uint16)0x01<<
4901 (uint16)0x0734<< (uint16)0x01<<
4902 (uint16)0x0733<< (uint16)0x01<<
4903 (uint16)0x0732<< (uint16)0x01<<
4904 (uint16)0x0702<< (uint16)0x00<<
4905 (uint16)0x0701<< (uint16)0x00<<
4906 (uint16)0x0700<< (uint16)0x00<<
4907 (uint16)0x06FE<< (uint16)0x00<<
4908 (uint16)0x06FD<< (uint16)0x00<<
4909 (uint16)0x06FC<< (uint16)0x00<<
4910 (uint16)0x06FB<< (uint16)0x00<<
4911 (uint16)0x06F8<< (uint16)0x00<<
4912 (uint16)0x06F7<< (uint16)0x00<<
4913 (uint16)0x06F6<< (uint16)0x00<<
4914 (uint16)0x06F4<< (uint16)0x07D0 <<
4915 (uint16)0x06F2<< (uint16)0x00<<
4916 (uint16)0x06F0<< (uint16)0x00<<
4917 (uint16)0x06EF<< (uint16)0x00<<
4918 (uint16)0x06EC<< (uint16)0x00<<
4919 (uint16)0x06EA<< (uint16)0x00<<
4920 (uint16)0x06E9<< (uint16)0x00<<
4921 (uint16)0x06E8<< (uint16)0x00<<
4922 (uint16)0x06E7<< (uint16)0x00<<
4923 (uint16)0x0641<< (uint16)0x03<<
4924 (uint16)0x062E<< (uint16)0x00<<
4925 (uint16)0x062D<< (uint16)0x00<<
4926 (uint16)0x060A<< (uint16)0x00<<
4927 (uint16)0x0609<< (uint16)0x00<<
4928 (uint16)0x0518<< (uint16)0x00<<
4929 (uint16)0x0517<< (uint16)0x00<<
4930 (uint16)0x0703<< (uint16)0x00;
4931 GetSession()->SendPacket(&data);
4935 void Player::AddWeather()
4937 uint32 zoneid = GetZoneId();
4938 if(!sWorld.FindWeather(zoneid))
4940 Weather *wth = new Weather(this);
4941 sWorld.AddWeather(wth);
4945 uint32 Player::GetXPRestBonus(uint32 xp)
4947 //xp for 1 section
4948 float xp_bl = (float)GetUInt32Value(PLAYER_NEXT_LEVEL_XP) / 20;
4949 float blpoint_bl=0; //rested bonuse for 1 section
4950 switch (getLevel())
4952 case 1: {blpoint_bl=50.9;break;}
4953 case 2: {blpoint_bl=51.05;break;}
4954 case 3: {blpoint_bl=51.1;break;}
4955 case 4: {blpoint_bl=51.1;break;}
4956 default: {blpoint_bl=51.15;break;}
4958 float rested_xp = (xp_bl/blpoint_bl) * GetRestBonus(); //xp for each rested bonus
4960 float rest_xp_percent = rested_xp / ((float)xp / 100); //% rest bonuse from total rest bonus
4961 if(rest_xp_percent>100)rest_xp_percent=100;
4963 sLog.outDetail("XP_GAIN: %f, value1=%f, rest_xp_percent=%f",(float)xp,(xp_bl/blpoint_bl),rest_xp_percent);
4965 rested_xp = ((float)xp / 100 * rest_xp_percent);
4967 SetRestBonus( GetRestBonus() - ((xp_bl / blpoint_bl) * (xp + rested_xp) ));
4969 sLog.outDetail("Player gain %u xp (+ %u Rested Bonus). Rested bonus=%f",xp+(uint32)rested_xp,(uint32)((float)xp / 100 * rest_xp_percent),GetRestBonus());
4970 return (uint32)rested_xp;
4973 uint8 Player::CheckFishingAble() const
4975 uint32 zone = GetZoneId();
4976 uint32 fish_value = GetSkillValue(SKILL_FISHING);
4977 uint32 ZoneMaxSkill;
4978 switch(zone)
4980 case 1:
4981 ZoneMaxSkill=50;
4982 break;
4983 case 2:
4984 ZoneMaxSkill=100;
4985 break;
4986 case 8:
4987 ZoneMaxSkill=225;
4988 break;
4989 case 9:
4990 ZoneMaxSkill=50;
4991 break;
4992 case 10:
4993 ZoneMaxSkill=50;
4994 break;
4995 case 11:
4996 ZoneMaxSkill=150;
4997 break;
4998 case 12:
4999 ZoneMaxSkill=50;
5000 break;
5001 case 14:
5002 ZoneMaxSkill=50;
5003 break;
5004 case 15:
5005 ZoneMaxSkill=225;
5006 break;
5007 case 16:
5008 ZoneMaxSkill=275;
5009 break;
5010 case 17:
5011 ZoneMaxSkill=275;
5012 break;
5013 case 18:
5014 ZoneMaxSkill=50;
5015 break;
5016 case 28:
5017 ZoneMaxSkill=290;
5018 break;
5019 case 33:
5020 ZoneMaxSkill=225;
5021 break;
5022 case 35:
5023 ZoneMaxSkill=225;
5024 break;
5025 case 37:
5026 ZoneMaxSkill=225;
5027 break;
5028 case 38:
5029 ZoneMaxSkill=100;
5030 break;
5031 case 40:
5032 ZoneMaxSkill=100;
5033 break;
5034 case 43:
5035 ZoneMaxSkill=225;
5036 break;
5037 case 44:
5038 ZoneMaxSkill=125;
5039 break;
5040 case 45:
5041 ZoneMaxSkill=200;
5042 break;
5043 case 47:
5044 ZoneMaxSkill=250;
5045 break;
5046 case 55:
5047 ZoneMaxSkill=200;
5048 break;
5049 case 57:
5050 ZoneMaxSkill=50;
5051 break;
5052 case 60:
5053 ZoneMaxSkill=50;
5054 break;
5055 case 61:
5056 ZoneMaxSkill=50;
5057 break;
5058 case 62:
5059 ZoneMaxSkill=50;
5060 break;
5061 case 63:
5062 ZoneMaxSkill=50;
5063 break;
5064 case 64:
5065 ZoneMaxSkill=50;
5066 break;
5067 case 68:
5068 ZoneMaxSkill=150;
5069 break;
5070 case 69:
5071 ZoneMaxSkill=125;
5072 break;
5073 case 71:
5074 ZoneMaxSkill=225;
5075 break;
5076 case 74:
5077 ZoneMaxSkill=225;
5078 break;
5079 case 75:
5080 ZoneMaxSkill=225;
5081 break;
5082 case 76:
5083 ZoneMaxSkill=225;
5084 break;
5085 case 85:
5086 ZoneMaxSkill=50;
5087 break;
5088 case 86:
5089 ZoneMaxSkill=50;
5090 break;
5091 case 87:
5092 ZoneMaxSkill=50;
5093 break;
5094 case 88:
5095 ZoneMaxSkill=50;
5096 break;
5097 case 89:
5098 ZoneMaxSkill=50;
5099 break;
5100 case 92:
5101 ZoneMaxSkill=50;
5102 break;
5103 case 100:
5104 ZoneMaxSkill=225;
5105 break;
5106 case 102:
5107 ZoneMaxSkill=225;
5108 break;
5109 case 104:
5110 ZoneMaxSkill=225;
5111 break;
5112 case 115:
5113 ZoneMaxSkill=100;
5114 break;
5115 case 116:
5116 ZoneMaxSkill=225;
5117 break;
5118 case 117:
5119 ZoneMaxSkill=225;
5120 break;
5121 case 122:
5122 ZoneMaxSkill=225;
5123 break;
5124 case 129:
5125 ZoneMaxSkill=225;
5126 break;
5127 case 130:
5128 ZoneMaxSkill=100;
5129 break;
5130 case 139:
5131 ZoneMaxSkill=300;
5132 break;
5133 case 141:
5134 ZoneMaxSkill=50;
5135 break;
5136 case 146:
5137 ZoneMaxSkill=50;
5138 break;
5139 case 150:
5140 ZoneMaxSkill=150;
5141 break;
5142 case 162:
5143 ZoneMaxSkill=50;
5144 break;
5145 case 163:
5146 ZoneMaxSkill=50;
5147 break;
5148 case 168:
5149 ZoneMaxSkill=50;
5150 break;
5151 case 169:
5152 ZoneMaxSkill=50;
5153 break;
5154 case 172:
5155 ZoneMaxSkill=100;
5156 break;
5157 case 187:
5158 ZoneMaxSkill=50;
5159 break;
5160 case 188:
5161 ZoneMaxSkill=50;
5162 break;
5163 case 193:
5164 ZoneMaxSkill=290;
5165 break;
5166 case 202:
5167 ZoneMaxSkill=290;
5168 break;
5169 case 211:
5170 ZoneMaxSkill=50;
5171 break;
5172 case 221:
5173 ZoneMaxSkill=50;
5174 break;
5175 case 223:
5176 ZoneMaxSkill=50;
5177 break;
5178 case 226:
5179 ZoneMaxSkill=100;
5180 break;
5181 case 227:
5182 ZoneMaxSkill=100;
5183 break;
5184 case 237:
5185 ZoneMaxSkill=100;
5186 break;
5187 case 249:
5188 ZoneMaxSkill=280;
5189 break;
5190 case 256:
5191 ZoneMaxSkill=50;
5192 break;
5193 case 258:
5194 ZoneMaxSkill=50;
5195 break;
5196 case 259:
5197 ZoneMaxSkill=50;
5198 break;
5199 case 265:
5200 ZoneMaxSkill=50;
5201 break;
5202 case 266:
5203 ZoneMaxSkill=50;
5204 break;
5205 case 267:
5206 ZoneMaxSkill=150;
5207 break;
5208 case 271:
5209 ZoneMaxSkill=150;
5210 break;
5211 case 272:
5212 ZoneMaxSkill=150;
5213 break;
5214 case 279:
5215 ZoneMaxSkill=200;
5216 break;
5217 case 284:
5218 ZoneMaxSkill=200;
5219 break;
5220 case 295:
5221 ZoneMaxSkill=150;
5222 break;
5223 case 297:
5224 ZoneMaxSkill=225;
5225 break;
5226 case 298:
5227 ZoneMaxSkill=150;
5228 break;
5229 case 299:
5230 ZoneMaxSkill=150;
5231 break;
5232 case 300:
5233 ZoneMaxSkill=225;
5234 break;
5235 case 301:
5236 ZoneMaxSkill=225;
5237 break;
5238 case 302:
5239 ZoneMaxSkill=225;
5240 break;
5241 case 305:
5242 ZoneMaxSkill=100;
5243 break;
5244 case 306:
5245 ZoneMaxSkill=100;
5246 break;
5247 case 307:
5248 ZoneMaxSkill=250;
5249 break;
5250 case 309:
5251 ZoneMaxSkill=100;
5252 break;
5253 case 310:
5254 ZoneMaxSkill=225;
5255 break;
5256 case 311:
5257 ZoneMaxSkill=225;
5258 break;
5259 case 312:
5260 ZoneMaxSkill=225;
5261 break;
5262 case 314:
5263 ZoneMaxSkill=200;
5264 break;
5265 case 317:
5266 ZoneMaxSkill=200;
5267 break;
5268 case 323:
5269 ZoneMaxSkill=100;
5270 break;
5271 case 324:
5272 ZoneMaxSkill=200;
5273 break;
5274 case 327:
5275 ZoneMaxSkill=200;
5276 break;
5277 case 328:
5278 ZoneMaxSkill=200;
5279 break;
5280 case 331:
5281 ZoneMaxSkill=150;
5282 break;
5283 case 350:
5284 ZoneMaxSkill=250;
5285 break;
5286 case 351:
5287 ZoneMaxSkill=250;
5288 break;
5289 case 353:
5290 ZoneMaxSkill=250;
5291 break;
5292 case 356:
5293 ZoneMaxSkill=250;
5294 break;
5295 case 361:
5296 ZoneMaxSkill=250;
5297 break;
5298 case 363:
5299 ZoneMaxSkill=50;
5300 break;
5301 case 367:
5302 ZoneMaxSkill=50;
5303 break;
5304 case 368:
5305 ZoneMaxSkill=50;
5306 break;
5307 case 373:
5308 ZoneMaxSkill=50;
5309 break;
5310 case 374:
5311 ZoneMaxSkill=50;
5312 break;
5313 case 375:
5314 ZoneMaxSkill=300;
5315 break;
5316 case 382:
5317 ZoneMaxSkill=125;
5318 break;
5319 case 384:
5320 ZoneMaxSkill=125;
5321 break;
5322 case 385:
5323 ZoneMaxSkill=125;
5324 break;
5325 case 386:
5326 ZoneMaxSkill=125;
5327 break;
5328 case 387:
5329 ZoneMaxSkill=125;
5330 break;
5331 case 388:
5332 ZoneMaxSkill=125;
5333 break;
5334 case 391:
5335 ZoneMaxSkill=125;
5336 break;
5337 case 392:
5338 ZoneMaxSkill=125;
5339 break;
5340 case 393:
5341 ZoneMaxSkill=50;
5342 break;
5343 case 401:
5344 ZoneMaxSkill=125;
5345 break;
5346 case 405:
5347 ZoneMaxSkill=200;
5348 break;
5349 case 406:
5350 ZoneMaxSkill=135;
5351 break;
5352 case 414:
5353 ZoneMaxSkill=150;
5354 break;
5355 case 415:
5356 ZoneMaxSkill=150;
5357 break;
5358 case 416:
5359 ZoneMaxSkill=150;
5360 break;
5361 case 418:
5362 ZoneMaxSkill=150;
5363 break;
5364 case 420:
5365 ZoneMaxSkill=150;
5366 break;
5367 case 421:
5368 ZoneMaxSkill=150;
5369 break;
5370 case 422:
5371 ZoneMaxSkill=150;
5372 break;
5373 case 424:
5374 ZoneMaxSkill=150;
5375 break;
5376 case 429:
5377 ZoneMaxSkill=150;
5378 break;
5379 case 433:
5380 ZoneMaxSkill=150;
5381 break;
5382 case 434:
5383 ZoneMaxSkill=150;
5384 break;
5385 case 437:
5386 ZoneMaxSkill=150;
5387 break;
5388 case 441:
5389 ZoneMaxSkill=150;
5390 break;
5391 case 442:
5392 ZoneMaxSkill=100;
5393 break;
5394 case 443:
5395 ZoneMaxSkill=100;
5396 break;
5397 case 445:
5398 ZoneMaxSkill=100;
5399 break;
5400 case 448:
5401 ZoneMaxSkill=100;
5402 break;
5403 case 449:
5404 ZoneMaxSkill=100;
5405 break;
5406 case 452:
5407 ZoneMaxSkill=100;
5408 break;
5409 case 453:
5410 ZoneMaxSkill=100;
5411 break;
5412 case 454:
5413 ZoneMaxSkill=100;
5414 break;
5415 case 456:
5416 ZoneMaxSkill=100;
5417 break;
5418 case 460:
5419 ZoneMaxSkill=135;
5420 break;
5421 case 463:
5422 ZoneMaxSkill=275;
5423 break;
5424 case 464:
5425 ZoneMaxSkill=135;
5426 break;
5427 case 478:
5428 ZoneMaxSkill=50;
5429 break;
5430 case 490:
5431 ZoneMaxSkill=275;
5432 break;
5433 case 493:
5434 ZoneMaxSkill=300;
5435 break;
5436 case 496:
5437 ZoneMaxSkill=225;
5438 break;
5439 case 497:
5440 ZoneMaxSkill=225;
5441 break;
5442 case 501:
5443 ZoneMaxSkill=225;
5444 break;
5445 case 502:
5446 ZoneMaxSkill=225;
5447 break;
5448 case 504:
5449 ZoneMaxSkill=225;
5450 break;
5451 case 508:
5452 ZoneMaxSkill=225;
5453 break;
5454 case 509:
5455 ZoneMaxSkill=225;
5456 break;
5457 case 510:
5458 ZoneMaxSkill=225;
5459 break;
5460 case 511:
5461 ZoneMaxSkill=225;
5462 break;
5463 case 513:
5464 ZoneMaxSkill=225;
5465 break;
5466 case 516:
5467 ZoneMaxSkill=225;
5468 break;
5469 case 517:
5470 ZoneMaxSkill=225;
5471 break;
5472 case 518:
5473 ZoneMaxSkill=200;
5474 break;
5475 case 537:
5476 ZoneMaxSkill=250;
5477 break;
5478 case 538:
5479 ZoneMaxSkill=250;
5480 break;
5481 case 542:
5482 ZoneMaxSkill=250;
5483 break;
5484 case 543:
5485 ZoneMaxSkill=250;
5486 break;
5487 case 556:
5488 ZoneMaxSkill=50;
5489 break;
5490 case 576:
5491 ZoneMaxSkill=150;
5492 break;
5493 case 598:
5494 ZoneMaxSkill=200;
5495 break;
5496 case 602:
5497 ZoneMaxSkill=200;
5498 break;
5499 case 604:
5500 ZoneMaxSkill=200;
5501 break;
5502 case 618:
5503 ZoneMaxSkill=300;
5504 break;
5505 case 636:
5506 ZoneMaxSkill=135;
5507 break;
5508 case 656:
5509 ZoneMaxSkill=300;
5510 break;
5511 case 657:
5512 ZoneMaxSkill=225;
5513 break;
5514 case 702:
5515 ZoneMaxSkill=50;
5516 break;
5517 case 719:
5518 ZoneMaxSkill=135;
5519 break;
5520 case 720:
5521 ZoneMaxSkill=135;
5522 break;
5523 case 797:
5524 ZoneMaxSkill=225;
5525 break;
5526 case 799:
5527 ZoneMaxSkill=150;
5528 break;
5529 case 810:
5530 ZoneMaxSkill=50;
5531 break;
5532 case 814:
5533 ZoneMaxSkill=50;
5534 break;
5535 case 815:
5536 ZoneMaxSkill=125;
5537 break;
5538 case 818:
5539 ZoneMaxSkill=50;
5540 break;
5541 case 878:
5542 ZoneMaxSkill=275;
5543 break;
5544 case 879:
5545 ZoneMaxSkill=150;
5546 break;
5547 case 896:
5548 ZoneMaxSkill=150;
5549 break;
5550 case 917:
5551 ZoneMaxSkill=100;
5552 break;
5553 case 919:
5554 ZoneMaxSkill=100;
5555 break;
5556 case 922:
5557 ZoneMaxSkill=100;
5558 break;
5559 case 923:
5560 ZoneMaxSkill=50;
5561 break;
5562 case 927:
5563 ZoneMaxSkill=50;
5564 break;
5565 case 968:
5566 ZoneMaxSkill=250;
5567 break;
5568 case 977:
5569 ZoneMaxSkill=250;
5570 break;
5571 case 978:
5572 ZoneMaxSkill=250;
5573 break;
5574 case 979:
5575 ZoneMaxSkill=250;
5576 break;
5577 case 983:
5578 ZoneMaxSkill=250;
5579 break;
5580 case 988:
5581 ZoneMaxSkill=250;
5582 break;
5583 case 997:
5584 ZoneMaxSkill=125;
5585 break;
5586 case 998:
5587 ZoneMaxSkill=125;
5588 break;
5589 case 1001:
5590 ZoneMaxSkill=125;
5591 break;
5592 case 1002:
5593 ZoneMaxSkill=125;
5594 break;
5595 case 1008:
5596 ZoneMaxSkill=250;
5597 break;
5598 case 1017:
5599 ZoneMaxSkill=150;
5600 break;
5601 case 1018:
5602 ZoneMaxSkill=150;
5603 break;
5604 case 1020:
5605 ZoneMaxSkill=150;
5606 break;
5607 case 1021:
5608 ZoneMaxSkill=150;
5609 break;
5610 case 1022:
5611 ZoneMaxSkill=150;
5612 break;
5613 case 1023:
5614 ZoneMaxSkill=150;
5615 break;
5616 case 1024:
5617 ZoneMaxSkill=150;
5618 break;
5619 case 1025:
5620 ZoneMaxSkill=150;
5621 break;
5622 case 1039:
5623 ZoneMaxSkill=150;
5624 break;
5625 case 1056:
5626 ZoneMaxSkill=290;
5627 break;
5628 case 1097:
5629 ZoneMaxSkill=150;
5630 break;
5631 case 1099:
5632 ZoneMaxSkill=300;
5633 break;
5634 case 1101:
5635 ZoneMaxSkill=250;
5636 break;
5637 case 1102:
5638 ZoneMaxSkill=250;
5639 break;
5640 case 1106:
5641 ZoneMaxSkill=250;
5642 break;
5643 case 1112:
5644 ZoneMaxSkill=250;
5645 break;
5646 case 1116:
5647 ZoneMaxSkill=250;
5648 break;
5649 case 1117:
5650 ZoneMaxSkill=250;
5651 break;
5652 case 1119:
5653 ZoneMaxSkill=250;
5654 break;
5655 case 1120:
5656 ZoneMaxSkill=250;
5657 break;
5658 case 1121:
5659 ZoneMaxSkill=250;
5660 break;
5661 case 1126:
5662 ZoneMaxSkill=225;
5663 break;
5664 case 1136:
5665 ZoneMaxSkill=250;
5666 break;
5667 case 1156:
5668 ZoneMaxSkill=225;
5669 break;
5670 case 1176:
5671 ZoneMaxSkill=250;
5672 break;
5673 case 1222:
5674 ZoneMaxSkill=275;
5675 break;
5676 case 1227:
5677 ZoneMaxSkill=275;
5678 break;
5679 case 1228:
5680 ZoneMaxSkill=275;
5681 break;
5682 case 1229:
5683 ZoneMaxSkill=275;
5684 break;
5685 case 1230:
5686 ZoneMaxSkill=275;
5687 break;
5688 case 1231:
5689 ZoneMaxSkill=275;
5690 break;
5691 case 1234:
5692 ZoneMaxSkill=275;
5693 break;
5694 case 1256:
5695 ZoneMaxSkill=275;
5696 break;
5697 case 1296:
5698 ZoneMaxSkill=50;
5699 break;
5700 case 1297:
5701 ZoneMaxSkill=50;
5702 break;
5703 case 1336:
5704 ZoneMaxSkill=250;
5705 break;
5706 case 1337:
5707 ZoneMaxSkill=250;
5708 break;
5709 case 1338:
5710 ZoneMaxSkill=100;
5711 break;
5712 case 1339:
5713 ZoneMaxSkill=200;
5714 break;
5715 case 1477:
5716 ZoneMaxSkill=275;
5717 break;
5718 case 1519:
5719 ZoneMaxSkill=50;
5720 break;
5721 case 1557:
5722 ZoneMaxSkill=175;
5723 break;
5724 case 1577:
5725 ZoneMaxSkill=225;
5726 break;
5727 case 1578:
5728 ZoneMaxSkill=225;
5729 break;
5730 case 1581:
5731 ZoneMaxSkill=100;
5732 break;
5733 case 1617:
5734 ZoneMaxSkill=50;
5735 break;
5736 case 1638:
5737 ZoneMaxSkill=50;
5738 break;
5739 case 1662:
5740 ZoneMaxSkill=50;
5741 break;
5742 case 1681:
5743 ZoneMaxSkill=200;
5744 break;
5745 case 1682:
5746 ZoneMaxSkill=200;
5747 break;
5748 case 1684:
5749 ZoneMaxSkill=200;
5750 break;
5751 case 1701:
5752 ZoneMaxSkill=125;
5753 break;
5754 case 1738:
5755 ZoneMaxSkill=225;
5756 break;
5757 case 1739:
5758 ZoneMaxSkill=225;
5759 break;
5760 case 1740:
5761 ZoneMaxSkill=225;
5762 break;
5763 case 1760:
5764 ZoneMaxSkill=225;
5765 break;
5766 case 1762:
5767 ZoneMaxSkill=250;
5768 break;
5769 case 1764:
5770 ZoneMaxSkill=225;
5771 break;
5772 case 1765:
5773 ZoneMaxSkill=225;
5774 break;
5775 case 1767:
5776 ZoneMaxSkill=275;
5777 break;
5778 case 1770:
5779 ZoneMaxSkill=275;
5780 break;
5781 case 1777:
5782 ZoneMaxSkill=225;
5783 break;
5784 case 1778:
5785 ZoneMaxSkill=225;
5786 break;
5787 case 1780:
5788 ZoneMaxSkill=225;
5789 break;
5790 case 1797:
5791 ZoneMaxSkill=225;
5792 break;
5793 case 1798:
5794 ZoneMaxSkill=225;
5795 break;
5796 case 1883:
5797 ZoneMaxSkill=250;
5798 break;
5799 case 1884:
5800 ZoneMaxSkill=250;
5801 break;
5802 case 1939:
5803 ZoneMaxSkill=250;
5804 break;
5805 case 1940:
5806 ZoneMaxSkill=250;
5807 break;
5808 case 1942:
5809 ZoneMaxSkill=250;
5810 break;
5811 case 1977:
5812 ZoneMaxSkill=225;
5813 break;
5814 case 1997:
5815 ZoneMaxSkill=275;
5816 break;
5817 case 1998:
5818 ZoneMaxSkill=275;
5819 break;
5820 case 2017:
5821 ZoneMaxSkill=300;
5822 break;
5823 case 2077:
5824 ZoneMaxSkill=100;
5825 break;
5826 case 2078:
5827 ZoneMaxSkill=100;
5828 break;
5829 case 2079:
5830 ZoneMaxSkill=225;
5831 break;
5832 case 2097:
5833 ZoneMaxSkill=175;
5834 break;
5835 case 2100:
5836 ZoneMaxSkill=245;
5837 break;
5838 case 2158:
5839 ZoneMaxSkill=250;
5840 break;
5841 case 2246:
5842 ZoneMaxSkill=300;
5843 break;
5844 case 2256:
5845 ZoneMaxSkill=300;
5846 break;
5847 case 2270:
5848 ZoneMaxSkill=300;
5849 break;
5850 case 2272:
5851 ZoneMaxSkill=300;
5852 break;
5853 case 2277:
5854 ZoneMaxSkill=300;
5855 break;
5856 case 2279:
5857 ZoneMaxSkill=300;
5858 break;
5859 case 2298:
5860 ZoneMaxSkill=300;
5861 break;
5862 case 2302:
5863 ZoneMaxSkill=225;
5864 break;
5865 case 2317:
5866 ZoneMaxSkill=250;
5867 break;
5868 case 2318:
5869 ZoneMaxSkill=225;
5870 break;
5871 case 2321:
5872 ZoneMaxSkill=275;
5873 break;
5874 case 2322:
5875 ZoneMaxSkill=50;
5876 break;
5877 case 2323:
5878 ZoneMaxSkill=250;
5879 break;
5880 case 2324:
5881 ZoneMaxSkill=200;
5882 break;
5883 case 2325:
5884 ZoneMaxSkill=150;
5885 break;
5886 case 2326:
5887 ZoneMaxSkill=100;
5888 break;
5889 case 2364:
5890 ZoneMaxSkill=100;
5891 break;
5892 case 2365:
5893 ZoneMaxSkill=150;
5894 break;
5895 case 2398:
5896 ZoneMaxSkill=100;
5897 break;
5898 case 2399:
5899 ZoneMaxSkill=50;
5900 break;
5901 case 2400:
5902 ZoneMaxSkill=250;
5903 break;
5904 case 2401:
5905 ZoneMaxSkill=200;
5906 break;
5907 case 2402:
5908 ZoneMaxSkill=100;
5909 break;
5910 case 2403:
5911 ZoneMaxSkill=225;
5912 break;
5913 case 2405:
5914 ZoneMaxSkill=200;
5915 break;
5916 case 2408:
5917 ZoneMaxSkill=200;
5918 break;
5919 case 2457:
5920 ZoneMaxSkill=150;
5921 break;
5922 case 2477:
5923 ZoneMaxSkill=300;
5924 break;
5925 case 2481:
5926 ZoneMaxSkill=275;
5927 break;
5928 case 2521:
5929 ZoneMaxSkill=250;
5930 break;
5931 case 2522:
5932 ZoneMaxSkill=250;
5933 break;
5934 case 2558:
5935 ZoneMaxSkill=300;
5936 break;
5937 case 2562:
5938 ZoneMaxSkill=300;
5939 break;
5940 case 2597:
5941 ZoneMaxSkill=300;
5942 break;
5943 case 2618:
5944 ZoneMaxSkill=275;
5945 break;
5946 case 2619:
5947 ZoneMaxSkill=300;
5948 break;
5949 case 2620:
5950 ZoneMaxSkill=290;
5951 break;
5952 case 2624:
5953 ZoneMaxSkill=300;
5954 break;
5955 case 2631:
5956 ZoneMaxSkill=300;
5957 break;
5958 case 2797:
5959 ZoneMaxSkill=150;
5960 break;
5961 case 2837:
5962 ZoneMaxSkill=300;
5963 break;
5964 case 2897:
5965 ZoneMaxSkill=150;
5966 break;
5967 default:
5968 ZoneMaxSkill=50;
5969 break;
5971 if((ZoneMaxSkill-50) > fish_value )
5972 return 0;
5973 else if(ZoneMaxSkill-50 <= fish_value && fish_value < ZoneMaxSkill-25)
5974 return 1;
5975 else if(ZoneMaxSkill-25 <= fish_value && fish_value < ZoneMaxSkill)
5976 return 2;
5977 else if(ZoneMaxSkill <= fish_value && fish_value < ZoneMaxSkill + 25)
5978 return 3;
5979 else return 4;
5982 void Player::SetBindPoint(uint64 guid)
5984 WorldPacket data;
5985 data.Initialize( SMSG_BINDER_CONFIRM );
5986 data << guid;
5987 GetSession()->SendPacket( &data );
5990 void Player::SendTalentWipeConfirm(uint64 guid)
5992 WorldPacket data;
5993 data.Initialize( MSG_TALENT_WIPE_CONFIRM );
5994 data << guid;
5995 data << (uint32)resetTalentsCost();
5996 GetSession()->SendPacket( &data );
5999 /*********************************************************/
6000 /*** STORAGE SYSTEM ***/
6001 /*********************************************************/
6003 void Player::SetVirtualItemSlot( uint8 i, Item* item)
6005 assert(i < 3);
6006 SetUInt32Value(UNIT_VIRTUAL_ITEM_INFO + 2*i, item ? item->GetGUIDLow() : 0);
6007 SetUInt32Value(UNIT_VIRTUAL_ITEM_INFO + 2*i +1, item ? item->GetProto()->Sheath : 0);
6008 SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+i,item ? item->GetProto()->DisplayInfoID : 0);
6009 if(i < 2 && item)
6011 if(!item->GetUInt32Value(ITEM_FIELD_ENCHANTMENT+3))
6012 return;
6013 uint32 charges = item->GetUInt32Value(ITEM_FIELD_ENCHANTMENT+3+2);
6014 if(charges == 0)
6015 return;
6016 if(charges > 1)
6017 item->SetUInt32Value(ITEM_FIELD_ENCHANTMENT+3+2,charges-1);
6018 else if(charges <= 1)
6020 AddItemEnchant(item,item->GetUInt32Value(ITEM_FIELD_ENCHANTMENT+3),false);
6021 for(int y=0;y<3;y++)
6022 item->SetUInt32Value(ITEM_FIELD_ENCHANTMENT+3+y,0);
6027 void Player::SetSheath( uint32 sheathed )
6029 Item* item;
6030 switch (sheathed)
6032 case 0: // no prepeared weapon
6033 SetVirtualItemSlot(0,NULL);
6034 SetVirtualItemSlot(1,NULL);
6035 SetVirtualItemSlot(2,NULL);
6036 break;
6037 case 1: // prepeared melee weapon
6039 item = GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
6040 SetVirtualItemSlot(0,item && !item->IsBroken() ? item : NULL);
6041 item = GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
6042 SetVirtualItemSlot(1,item && !item->IsBroken() ? item : NULL);
6043 SetVirtualItemSlot(2,NULL);
6044 }; break;
6045 case 2: // prepeared ranged weapon
6046 SetVirtualItemSlot(0,NULL);
6047 SetVirtualItemSlot(1,NULL);
6048 item = GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_RANGED);
6049 SetVirtualItemSlot(2,item && !item->IsBroken() ? item : NULL);
6050 break;
6051 default:
6052 SetVirtualItemSlot(0,NULL);
6053 SetVirtualItemSlot(1,NULL);
6054 SetVirtualItemSlot(2,NULL);
6055 break;
6059 uint8 Player::FindEquipSlot( uint32 type, uint32 slot, bool swap ) const
6061 uint8 slots[4];
6062 slots[0] = NULL_SLOT;
6063 slots[1] = NULL_SLOT;
6064 slots[2] = NULL_SLOT;
6065 slots[3] = NULL_SLOT;
6066 switch( type )
6068 case INVTYPE_HEAD:
6069 slots[0] = EQUIPMENT_SLOT_HEAD;
6070 break;
6071 case INVTYPE_NECK:
6072 slots[0] = EQUIPMENT_SLOT_NECK;
6073 break;
6074 case INVTYPE_SHOULDERS:
6075 slots[0] = EQUIPMENT_SLOT_SHOULDERS;
6076 break;
6077 case INVTYPE_BODY:
6078 slots[0] = EQUIPMENT_SLOT_BODY;
6079 break;
6080 case INVTYPE_CHEST:
6081 slots[0] = EQUIPMENT_SLOT_CHEST;
6082 break;
6083 case INVTYPE_ROBE:
6084 slots[0] = EQUIPMENT_SLOT_CHEST;
6085 break;
6086 case INVTYPE_WAIST:
6087 slots[0] = EQUIPMENT_SLOT_WAIST;
6088 break;
6089 case INVTYPE_LEGS:
6090 slots[0] = EQUIPMENT_SLOT_LEGS;
6091 break;
6092 case INVTYPE_FEET:
6093 slots[0] = EQUIPMENT_SLOT_FEET;
6094 break;
6095 case INVTYPE_WRISTS:
6096 slots[0] = EQUIPMENT_SLOT_WRISTS;
6097 break;
6098 case INVTYPE_HANDS:
6099 slots[0] = EQUIPMENT_SLOT_HANDS;
6100 break;
6101 case INVTYPE_FINGER:
6102 slots[0] = EQUIPMENT_SLOT_FINGER1;
6103 slots[1] = EQUIPMENT_SLOT_FINGER2;
6104 break;
6105 case INVTYPE_TRINKET:
6106 slots[0] = EQUIPMENT_SLOT_TRINKET1;
6107 slots[1] = EQUIPMENT_SLOT_TRINKET2;
6108 break;
6109 case INVTYPE_CLOAK:
6110 slots[0] = EQUIPMENT_SLOT_BACK;
6111 break;
6112 case INVTYPE_WEAPON:
6114 slots[0] = EQUIPMENT_SLOT_MAINHAND;
6116 // suggest offhand slot only if know dual wielding
6117 // (this will be replace mainhand weapon at auto equip instead unwonted "you don't known dual weilding" ...
6118 if(CanDualWield())
6119 slots[1] = EQUIPMENT_SLOT_OFFHAND;
6120 };break;
6121 case INVTYPE_SHIELD:
6122 slots[0] = EQUIPMENT_SLOT_OFFHAND;
6123 break;
6124 case INVTYPE_RANGED:
6125 slots[0] = EQUIPMENT_SLOT_RANGED;
6126 break;
6127 case INVTYPE_2HWEAPON:
6128 slots[0] = EQUIPMENT_SLOT_MAINHAND;
6129 break;
6130 case INVTYPE_TABARD:
6131 slots[0] = EQUIPMENT_SLOT_TABARD;
6132 break;
6133 case INVTYPE_WEAPONMAINHAND:
6134 slots[0] = EQUIPMENT_SLOT_MAINHAND;
6135 break;
6136 case INVTYPE_WEAPONOFFHAND:
6137 slots[0] = EQUIPMENT_SLOT_OFFHAND;
6138 break;
6139 case INVTYPE_HOLDABLE:
6140 slots[0] = EQUIPMENT_SLOT_OFFHAND;
6141 break;
6142 case INVTYPE_THROWN:
6143 slots[0] = EQUIPMENT_SLOT_RANGED;
6144 break;
6145 case INVTYPE_RANGEDRIGHT:
6146 slots[0] = EQUIPMENT_SLOT_RANGED;
6147 break;
6148 case INVTYPE_BAG:
6149 slots[0] = INVENTORY_SLOT_BAG_1;
6150 slots[1] = INVENTORY_SLOT_BAG_2;
6151 slots[2] = INVENTORY_SLOT_BAG_3;
6152 slots[3] = INVENTORY_SLOT_BAG_4;
6153 break;
6154 case INVTYPE_RELIC:
6155 slots[0] = EQUIPMENT_SLOT_RANGED;
6156 break;
6157 default :
6158 return NULL_SLOT;
6161 if( slot != NULL_SLOT )
6163 if( swap || !GetItemByPos( INVENTORY_SLOT_BAG_0, slot ) )
6165 for (int i = 0; i < 4; i++)
6167 if ( slots[i] == slot )
6168 return slot;
6172 else
6174 // search empty slot at first
6175 for (int i = 0; i < 4; i++)
6177 if ( slots[i] != NULL_SLOT && !GetItemByPos( INVENTORY_SLOT_BAG_0, slots[i] ) )
6178 return slots[i];
6181 // if not found empty and can swap return first appropriate
6182 for (int i = 0; i < 4; i++)
6184 if ( slots[i] != NULL_SLOT && swap )
6185 return slots[i];
6189 // no free position
6190 return NULL_SLOT;
6193 Item* Player::CreateItem( uint32 item, uint32 count ) const
6195 ItemPrototype const *pProto = objmgr.GetItemPrototype( item );
6196 if( pProto )
6198 Item *pItem = NewItemOrBag( pProto );
6199 if ( count > pProto->Stackable )
6200 count = pProto->Stackable;
6201 if ( count < 1 )
6202 count = 1;
6203 if( pItem->Create(objmgr.GenerateLowGuid(HIGHGUID_ITEM), item, const_cast<Player*>(this)) )
6205 pItem->SetCount( count );
6206 return pItem;
6208 else
6209 delete pItem;
6211 return NULL;
6214 uint32 Player::GetItemCount( uint32 item ) const
6216 Item *pItem;
6217 uint32 count = 0;
6218 for(int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; i++)
6220 pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
6221 if( pItem && pItem->GetEntry() == item )
6222 count += pItem->GetCount();
6224 Bag *pBag;
6225 for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)
6227 pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i );
6228 if( pBag )
6229 count += pBag->GetItemCount(item);
6231 return count;
6234 uint32 Player::GetBankItemCount( uint32 item ) const
6236 Item *pItem;
6237 uint32 count = 0;
6238 for(int i = BANK_SLOT_ITEM_START; i < BANK_SLOT_ITEM_END; i++)
6240 pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
6241 if( pItem && pItem->GetEntry() == item )
6242 count += pItem->GetCount();
6244 Bag *pBag;
6245 for(int i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++)
6247 pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i );
6248 if( pBag )
6249 count += pBag->GetItemCount(item);
6251 return count;
6254 uint16 Player::GetPosByGuid( uint64 guid ) const
6256 Item *pItem;
6257 uint16 pos;
6258 for(int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; i++)
6260 pos = ((INVENTORY_SLOT_BAG_0 << 8) | i);
6261 pItem = GetItemByPos( pos );
6262 if( pItem && pItem->GetGUID() == guid )
6263 return pos;
6265 Bag *pBag;
6266 ItemPrototype const *pBagProto;
6267 for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)
6269 pos = ((INVENTORY_SLOT_BAG_0 << 8) | i);
6270 pBag = (Bag*)GetItemByPos( pos );
6271 if( pBag )
6273 pBagProto = pBag->GetProto();
6274 if( pBagProto )
6276 for(uint32 j = 0; j < pBagProto->ContainerSlots; j++)
6278 pos = ((i << 8) | j);
6279 pItem = GetItemByPos( pos );
6280 if( pItem && pItem->GetGUID() == guid )
6281 return pos;
6286 for(int i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++)
6288 pos = ((INVENTORY_SLOT_BAG_0 << 8) | i);
6289 pBag = (Bag*)GetItemByPos( pos );
6290 if( pBag )
6292 pBagProto = pBag->GetProto();
6293 if( pBagProto )
6295 for(uint32 j = 0; j < pBagProto->ContainerSlots; j++)
6297 pos = ((i << 8) | j);
6298 pItem = GetItemByPos( pos );
6299 if( pItem && pItem->GetGUID() == guid )
6300 return pos;
6305 return 0;
6308 Item* Player::GetItemByPos( uint16 pos ) const
6310 uint8 bag = pos >> 8;
6311 uint8 slot = pos & 255;
6312 return GetItemByPos( bag, slot );
6315 Item* Player::GetItemByPos( uint8 bag, uint8 slot ) const
6317 if( bag == INVENTORY_SLOT_BAG_0 && ( slot < BANK_SLOT_BAG_END ) )
6318 return m_items[slot];
6319 else if(bag >= INVENTORY_SLOT_BAG_START && bag < INVENTORY_SLOT_BAG_END
6320 || bag >= BANK_SLOT_BAG_START && bag < BANK_SLOT_BAG_END )
6322 Bag *pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, bag );
6323 if ( pBag )
6324 return pBag->GetItemByPos(slot);
6326 return NULL;
6329 bool Player::HasBankBagSlot( uint8 slot ) const
6331 uint32 maxslot = ((GetUInt32Value(PLAYER_BYTES_2) & 0x70000) >> 16) + BANK_SLOT_BAG_START;
6332 if( slot < maxslot )
6333 return true;
6334 return false;
6337 bool Player::IsInventoryPos( uint16 pos ) const
6339 uint8 bag = pos >> 8;
6340 uint8 slot = pos & 255;
6341 if( bag == INVENTORY_SLOT_BAG_0 && slot == NULL_SLOT )
6342 return true;
6343 if( bag == INVENTORY_SLOT_BAG_0 && ( slot >= INVENTORY_SLOT_ITEM_START && slot < INVENTORY_SLOT_ITEM_END ) )
6344 return true;
6345 if( bag >= INVENTORY_SLOT_BAG_START && bag < INVENTORY_SLOT_BAG_END )
6346 return true;
6347 return false;
6350 bool Player::IsEquipmentPos( uint16 pos ) const
6352 uint8 bag = pos >> 8;
6353 uint8 slot = pos & 255;
6354 if( bag == INVENTORY_SLOT_BAG_0 && ( slot < EQUIPMENT_SLOT_END ) )
6355 return true;
6356 if( bag == INVENTORY_SLOT_BAG_0 && ( slot >= INVENTORY_SLOT_BAG_START && slot < INVENTORY_SLOT_BAG_END ) )
6357 return true;
6358 return false;
6361 bool Player::IsBankPos( uint16 pos ) const
6363 uint8 bag = pos >> 8;
6364 uint8 slot = pos & 255;
6365 if( bag == INVENTORY_SLOT_BAG_0 && ( slot >= BANK_SLOT_ITEM_START && slot < BANK_SLOT_ITEM_END ) )
6366 return true;
6367 if( bag == INVENTORY_SLOT_BAG_0 && ( slot >= BANK_SLOT_BAG_START && slot < BANK_SLOT_BAG_END ) )
6368 return true;
6369 if( bag >= BANK_SLOT_BAG_START && bag < BANK_SLOT_BAG_END )
6370 return true;
6371 return false;
6374 bool Player::HasItemCount( uint32 item, uint32 count ) const
6376 Item *pItem;
6377 uint32 tempcount = 0;
6378 for(int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; i++)
6380 pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
6381 if( pItem && pItem->GetEntry() == item )
6383 tempcount += pItem->GetCount();
6384 if( tempcount >= count )
6385 return true;
6388 Bag *pBag;
6389 ItemPrototype const *pBagProto;
6390 for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)
6392 pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i );
6393 if( pBag )
6395 pBagProto = pBag->GetProto();
6396 if( pBagProto )
6398 for(uint32 j = 0; j < pBagProto->ContainerSlots; j++)
6400 pItem = GetItemByPos( i, j );
6401 if( pItem && pItem->GetEntry() == item )
6403 tempcount += pItem->GetCount();
6404 if( tempcount >= count )
6405 return true;
6411 return false;
6414 uint8 Player::CanStoreNewItem( uint8 bag, uint8 slot, uint16 &dest, uint32 item, uint32 count, bool swap ) const
6416 dest = 0;
6417 Item *pItem = CreateItem( item, count );
6418 if( pItem )
6420 uint8 result = CanStoreItem( bag, slot, dest, pItem, swap );
6421 delete pItem;
6422 return result;
6424 if( !swap )
6425 return EQUIP_ERR_ITEM_NOT_FOUND;
6426 else
6427 return EQUIP_ERR_ITEMS_CANT_BE_SWAPPED;
6430 uint8 Player::CanStoreItem( uint8 bag, uint8 slot, uint16 &dest, Item *pItem, bool swap ) const
6432 dest = 0;
6433 if( pItem )
6435 sLog.outDebug( "STORAGE: CanStoreItem bag = %u, slot = %u, item = %u, count = %u", bag, slot, pItem->GetEntry(), pItem->GetCount());
6436 ItemPrototype const *pProto = pItem->GetProto();
6437 if( pProto )
6439 Item *pItem2;
6440 Bag *pBag;
6441 ItemPrototype const *pBagProto;
6442 uint16 pos;
6443 if(pItem->IsBindedNotWith(GetGUID()))
6444 return EQUIP_ERR_DONT_OWN_THAT_ITEM;
6445 if( bag == 0 )
6447 // check count of items
6448 if( !swap && pProto->MaxCount > 0 )
6450 uint32 curcount = 0;
6451 for(int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; i++)
6453 pos = ((INVENTORY_SLOT_BAG_0 << 8) | i );
6454 pItem2 = GetItemByPos( pos );
6455 if( pItem2 && pItem2->GetEntry() == pItem->GetEntry() )
6457 curcount += pItem2->GetCount();
6458 if( curcount + pItem->GetCount() > pProto->MaxCount )
6459 return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
6462 for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)
6464 pos = ((INVENTORY_SLOT_BAG_0 << 8) | i );
6465 pBag = (Bag*)GetItemByPos( pos );
6466 if( pBag )
6468 pBagProto = pBag->GetProto();
6469 if( pBagProto )
6471 for(uint32 j = 0; j < pBagProto->ContainerSlots; j++)
6473 pos = ((i << 8) | j );
6474 pItem2 = GetItemByPos( pos );
6475 if( pItem2 && pItem2->GetEntry() == pItem->GetEntry() )
6477 curcount += pItem2->GetCount();
6478 if( curcount + pItem->GetCount() > pProto->MaxCount )
6479 return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
6485 for(int i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++)
6487 pos = ((INVENTORY_SLOT_BAG_0 << 8) | i );
6488 pBag = (Bag*)GetItemByPos( pos );
6489 if( pBag )
6491 pBagProto = pBag->GetProto();
6492 if( pBagProto )
6494 for(uint32 j = 0; j < pBagProto->ContainerSlots; j++)
6496 pos = ((i << 8) | j );
6497 pItem2 = GetItemByPos( pos );
6498 if( pItem2 && pItem2->GetEntry() == pItem->GetEntry() )
6500 curcount += pItem2->GetCount();
6501 if( curcount + pItem->GetCount() > pProto->MaxCount )
6502 return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
6510 // search stack for merge to
6511 if( pProto->Stackable > 1 )
6513 for(int i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; i++)
6515 pos = ( (INVENTORY_SLOT_BAG_0 << 8) | i );
6516 pItem2 = GetItemByPos( pos );
6517 if( pItem2 && pItem2->GetEntry() == pItem->GetEntry() && pItem2->GetCount() + pItem->GetCount() <= pProto->Stackable )
6519 dest = pos;
6520 return EQUIP_ERR_OK;
6523 for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)
6525 pos = ( (INVENTORY_SLOT_BAG_0 << 8) | i );
6526 pBag = (Bag*)GetItemByPos( pos );
6527 if( pBag )
6529 pBagProto = pBag->GetProto();
6530 if( pBagProto )
6532 for(uint32 j = 0; j < pBagProto->ContainerSlots; j++)
6534 pos = ( (i << 8) | j );
6535 pItem2 = GetItemByPos( pos );
6536 if( pItem2 && pItem2->GetEntry() == pItem->GetEntry() && pItem2->GetCount() + pItem->GetCount() <= pProto->Stackable )
6538 dest = pos;
6539 return EQUIP_ERR_OK;
6547 // search free slot - ammo special case
6548 if( pProto->Class == ITEM_CLASS_PROJECTILE )
6550 for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)
6552 pos = ( (INVENTORY_SLOT_BAG_0 << 8) | i );
6553 pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i );
6554 if( pBag )
6556 pBagProto = pBag->GetProto();
6557 if( pBagProto && pBagProto->SubClass == pProto->SubClass )
6559 for(uint32 j = 0; j < pBagProto->ContainerSlots; j++)
6561 pos = ( (INVENTORY_SLOT_BAG_0 << 8) | i );
6562 pItem2 = GetItemByPos( i, j );
6563 if( !pItem2 )
6565 dest = ( (i << 8) | j );
6566 return EQUIP_ERR_OK;
6574 // search free slot
6575 for(int i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; i++)
6577 pItem2 = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
6578 if( !pItem2 )
6580 dest = ( (INVENTORY_SLOT_BAG_0 << 8) | i );
6581 return EQUIP_ERR_OK;
6585 for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)
6587 pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i );
6588 if( pBag )
6590 pBagProto = pBag->GetProto();
6591 if( pBagProto && pBagProto->Class != ITEM_CLASS_QUIVER )
6593 for(uint32 j = 0; j < pBagProto->ContainerSlots; j++)
6595 pItem2 = GetItemByPos( i, j );
6596 if( !pItem2 )
6598 dest = ( (i << 8) | j );
6599 return EQUIP_ERR_OK;
6605 return EQUIP_ERR_INVENTORY_FULL;
6607 else // in specific bag
6609 if( slot == NULL_SLOT )
6611 if( pProto->InventoryType == INVTYPE_BAG )
6613 Bag *pBag = (Bag*)pItem;
6614 if( pBag && !pBag->IsEmpty() )
6615 return EQUIP_ERR_NONEMPTY_BAG_OVER_OTHER_BAG;
6618 // search stack in bag for merge to
6619 if( pProto->Stackable > 1 )
6621 if( bag == INVENTORY_SLOT_BAG_0 )
6623 for(int i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; i++)
6625 pItem2 = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
6626 if( pItem2 && pItem2->GetEntry() == pItem->GetEntry() && pItem2->GetCount() + pItem->GetCount() <= pProto->Stackable )
6628 dest = ( (INVENTORY_SLOT_BAG_0 << 8) | i );
6629 return EQUIP_ERR_OK;
6633 else
6635 pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, bag );
6636 if( pBag )
6638 pBagProto = pBag->GetProto();
6639 if( pBagProto )
6641 for(uint32 j = 0; j < pBagProto->ContainerSlots; j++)
6643 pItem2 = GetItemByPos( bag, j );
6644 if( pItem2 && pItem2->GetEntry() == pItem->GetEntry() && pItem2->GetCount() + pItem->GetCount() <= pProto->Stackable )
6646 dest = ( (bag << 8) | j );
6647 return EQUIP_ERR_OK;
6654 if( bag == INVENTORY_SLOT_BAG_0 )
6656 for(int i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; i++)
6658 pItem2 = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
6659 if( !pItem2 )
6661 dest = ( (INVENTORY_SLOT_BAG_0 << 8) | i );
6662 return EQUIP_ERR_OK;
6666 else
6668 pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, bag );
6669 if( pBag )
6671 pBagProto = pBag->GetProto();
6672 if( pBagProto )
6674 if( pBagProto->Class == ITEM_CLASS_QUIVER && pBagProto->SubClass != pProto->SubClass )
6675 return EQUIP_ERR_ONLY_AMMO_CAN_GO_HERE;
6676 if( pBagProto->Class == ITEM_CLASS_CONTAINER && pBagProto->SubClass > ITEM_SUBCLASS_CONTAINER && pBagProto->SubClass != pProto->SubClass )
6677 return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG;
6678 for(uint32 j = 0; j < pBagProto->ContainerSlots; j++)
6680 pItem2 = GetItemByPos( bag, j );
6681 if( !pItem2 )
6683 dest = ( (bag << 8) | j );
6684 return EQUIP_ERR_OK;
6690 return EQUIP_ERR_BAG_FULL;
6692 else // specific bag and slot
6694 if( pProto->InventoryType == INVTYPE_BAG )
6696 Bag *pBag = (Bag*)pItem;
6697 if( pBag && !pBag->IsEmpty() )
6698 return EQUIP_ERR_NONEMPTY_BAG_OVER_OTHER_BAG;
6700 pItem2 = GetItemByPos( bag, slot );
6701 if( pItem2 && !swap )
6703 if( pProto->Stackable > 1 && pItem2->GetEntry() == pItem->GetEntry() && pItem2->GetCount() < pProto->Stackable )
6705 dest = ( (bag << 8) | slot );
6706 return EQUIP_ERR_OK;
6708 else
6709 return EQUIP_ERR_COULDNT_SPLIT_ITEMS;
6711 else
6713 if( bag == INVENTORY_SLOT_BAG_0 )
6715 dest = ( (bag << 8) | slot );
6716 return EQUIP_ERR_OK;
6718 else
6720 pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, bag );
6721 if( pBag )
6723 pBagProto = pBag->GetProto();
6724 if( pBagProto )
6726 if( pBagProto->Class == ITEM_CLASS_QUIVER && pBagProto->SubClass != pProto->SubClass )
6727 return EQUIP_ERR_ONLY_AMMO_CAN_GO_HERE;
6728 if( pBagProto->Class == ITEM_CLASS_CONTAINER && pBagProto->SubClass > ITEM_SUBCLASS_CONTAINER && pBagProto->SubClass != pProto->SubClass )
6729 return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG;
6730 dest = ( (bag << 8) | slot );
6731 return EQUIP_ERR_OK;
6740 if( !swap )
6741 return EQUIP_ERR_ITEM_NOT_FOUND;
6742 else
6743 return EQUIP_ERR_ITEMS_CANT_BE_SWAPPED;
6744 return 0;
6747 uint8 Player::CanEquipItem( uint8 slot, uint16 &dest, Item *pItem, bool swap, bool check_alive ) const
6749 dest = 0;
6750 if( pItem )
6752 sLog.outDebug( "STORAGE: CanEquipItem slot = %u, item = %u, count = %u", slot, pItem->GetEntry(), pItem->GetCount());
6753 ItemPrototype const *pProto = pItem->GetProto();
6754 if( pProto )
6756 if(isInCombat()&& pProto->Class != ITEM_CLASS_WEAPON && pProto->Class != ITEM_CLASS_PROJECTILE)
6757 return EQUIP_ERR_CANT_DO_IN_COMBAT;
6759 uint32 type = pProto->InventoryType;
6760 uint8 eslot = FindEquipSlot( type, slot, swap );
6761 if( eslot == NULL_SLOT )
6762 return EQUIP_ERR_ITEM_CANT_BE_EQUIPPED;
6764 uint8 msg = CanUseItem( pItem , check_alive );
6765 if( msg != EQUIP_ERR_OK )
6766 return msg;
6767 if( !swap && GetItemByPos( INVENTORY_SLOT_BAG_0, eslot ) )
6768 return EQUIP_ERR_NO_EQUIPMENT_SLOT_AVAILABLE;
6770 if(eslot == EQUIPMENT_SLOT_OFFHAND)
6772 if( type == INVTYPE_WEAPON || type == INVTYPE_WEAPONOFFHAND )
6774 if(!CanDualWield())
6775 return EQUIP_ERR_CANT_DUAL_WIELD;
6778 Item *mainItem = GetItemByPos( INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND );
6779 if(mainItem)
6781 if(mainItem->GetProto()->InventoryType == INVTYPE_2HWEAPON)
6782 return EQUIP_ERR_CANT_EQUIP_WITH_TWOHANDED;
6783 }else
6784 // not let equip offhand item if mainhand not equiped
6785 return EQUIP_ERR_ITEM_CANT_BE_EQUIPPED;
6789 if( type == INVTYPE_2HWEAPON )
6791 uint8 twinslot = ( eslot == EQUIPMENT_SLOT_MAINHAND ? EQUIPMENT_SLOT_OFFHAND : EQUIPMENT_SLOT_MAINHAND );
6792 Item *twinItem = GetItemByPos( INVENTORY_SLOT_BAG_0, twinslot );
6793 if( twinItem )
6794 return EQUIP_ERR_ITEM_CANT_BE_EQUIPPED;
6796 dest = ((INVENTORY_SLOT_BAG_0 << 8) | eslot);
6797 return EQUIP_ERR_OK;
6800 if( !swap )
6801 return EQUIP_ERR_ITEM_NOT_FOUND;
6802 else
6803 return EQUIP_ERR_ITEMS_CANT_BE_SWAPPED;
6806 uint8 Player::CanUnequipItem( uint16 pos, bool swap ) const
6808 // Applied only to equiped items
6809 if(!IsEquipmentPos(pos) )
6810 return EQUIP_ERR_OK;
6812 Item* pItem = GetItemByPos(pos);
6814 // Applied only to existed equiped item
6815 if( !pItem )
6816 return EQUIP_ERR_OK;
6818 sLog.outDebug( "STORAGE: CanUnequipItem slot = %u, item = %u, count = %u", pos, pItem->GetEntry(), pItem->GetCount());
6820 ItemPrototype const *pProto = pItem->GetProto();
6821 if( !pProto )
6822 return EQUIP_ERR_ITEM_NOT_FOUND;
6824 if(isInCombat()&& pProto->Class != ITEM_CLASS_WEAPON && pProto->Class != ITEM_CLASS_PROJECTILE)
6825 return EQUIP_ERR_CANT_DO_IN_COMBAT;
6827 // All equiped items can swaped (not in combat case)
6828 if(swap)
6829 return EQUIP_ERR_OK;
6831 uint32 type = pProto->InventoryType;
6832 uint8 slot = pos & 255;
6834 // can't unequip mainhand item if offhand item equiped
6835 if(slot == EQUIPMENT_SLOT_MAINHAND && GetItemByPos( INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND ))
6836 return EQUIP_ERR_CANT_DO_RIGHT_NOW;
6838 return EQUIP_ERR_OK;
6841 uint8 Player::CanBankItem( uint8 bag, uint8 slot, uint16 &dest, Item *pItem, bool swap ) const
6843 dest = 0;
6844 if( pItem )
6846 sLog.outDebug( "STORAGE: CanBankItem bag = %u, slot = %u, item = %u, count = %u", bag, slot, pItem->GetEntry(), pItem->GetCount());
6847 ItemPrototype const *pProto = pItem->GetProto();
6848 if( pProto )
6850 Item *pItem2;
6851 Bag *pBag;
6852 ItemPrototype const *pBagProto;
6853 uint16 pos;
6854 if( pItem->IsBindedNotWith(GetGUID()) )
6855 return EQUIP_ERR_DONT_OWN_THAT_ITEM;
6856 if( bag == 0 )
6858 if( !swap && pProto->MaxCount > 0 )
6860 uint32 curcount = 0;
6861 for(int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; i++)
6863 pos = ((INVENTORY_SLOT_BAG_0 << 8) | i );
6864 pItem2 = GetItemByPos( pos );
6865 if( pItem2 && pItem2->GetEntry() == pItem->GetEntry() )
6867 curcount += pItem2->GetCount();
6868 if( curcount + pItem->GetCount() > pProto->MaxCount )
6869 return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
6872 for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)
6874 pos = ((INVENTORY_SLOT_BAG_0 << 8) | i );
6875 pBag = (Bag*)GetItemByPos( pos );
6876 if( pBag )
6878 pBagProto = pBag->GetProto();
6879 if( pBagProto )
6881 for(uint32 j = 0; j < pBagProto->ContainerSlots; j++)
6883 pos = ((i << 8) | j );
6884 pItem2 = GetItemByPos( pos );
6885 if( pItem2 && pItem2->GetEntry() == pItem->GetEntry() )
6887 curcount += pItem2->GetCount();
6888 if( curcount + pItem->GetCount() > pProto->MaxCount )
6889 return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
6895 for(int i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++)
6897 pos = ((INVENTORY_SLOT_BAG_0 << 8) | i );
6898 pBag = (Bag*)GetItemByPos( pos );
6899 if( pBag )
6901 pBagProto = pBag->GetProto();
6902 if( pBagProto )
6904 for(uint32 j = 0; j < pBagProto->ContainerSlots; j++)
6906 pos = ((i << 8) | j );
6907 pItem2 = GetItemByPos( pos );
6908 if( pItem2 && pItem2->GetEntry() == pItem->GetEntry() )
6910 curcount += pItem2->GetCount();
6911 if( curcount + pItem->GetCount() > pProto->MaxCount )
6912 return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
6919 if( pProto->Stackable > 1 )
6921 for(int i = BANK_SLOT_ITEM_START; i < BANK_SLOT_ITEM_END; i++)
6923 pos = ( (INVENTORY_SLOT_BAG_0 << 8) | i );
6924 pItem2 = GetItemByPos( pos );
6925 if( pItem2 && pItem2->GetEntry() == pItem->GetEntry() && pItem2->GetCount() + pItem->GetCount() <= pProto->Stackable )
6927 dest = pos;
6928 return EQUIP_ERR_OK;
6931 for(int i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++)
6933 pos = ( (INVENTORY_SLOT_BAG_0 << 8) | i );
6934 pBag = (Bag*)GetItemByPos( pos );
6935 if( pBag )
6937 pBagProto = pBag->GetProto();
6938 if( pBagProto )
6940 for(uint32 j = 0; j < pBagProto->ContainerSlots; j++)
6942 pos = ( (i << 8) | j );
6943 pItem2 = GetItemByPos( pos );
6944 if( pItem2 && pItem2->GetEntry() == pItem->GetEntry() && pItem2->GetCount() + pItem->GetCount() <= pProto->Stackable )
6946 dest = pos;
6947 return EQUIP_ERR_OK;
6954 if( pProto->Class == ITEM_CLASS_PROJECTILE )
6956 for(int i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++)
6958 pos = ( (INVENTORY_SLOT_BAG_0 << 8) | i );
6959 pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i );
6960 if( pBag )
6962 pBagProto = pBag->GetProto();
6963 if( pBagProto && pBagProto->SubClass == pProto->SubClass )
6965 for(int j = 0; j < pBagProto->ContainerSlots; j++)
6967 pos = ( (INVENTORY_SLOT_BAG_0 << 8) | i );
6968 pItem2 = GetItemByPos( i, j );
6969 if( !pItem2 )
6971 dest = ( (i << 8) | j );
6972 return EQUIP_ERR_OK;
6979 for(int i = BANK_SLOT_ITEM_START; i < BANK_SLOT_ITEM_END; i++)
6981 pItem2 = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
6982 if( !pItem2 )
6984 dest = ( (INVENTORY_SLOT_BAG_0 << 8) | i );
6985 return EQUIP_ERR_OK;
6988 for(int i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++)
6990 pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i );
6991 if( pBag )
6993 pBagProto = pBag->GetProto();
6994 if( pBagProto && pBagProto->Class != ITEM_CLASS_QUIVER )
6996 for(uint32 j = 0; j < pBagProto->ContainerSlots; j++)
6998 pItem2 = GetItemByPos( i, j );
6999 if( !pItem2 )
7001 dest = ( (i << 8) | j );
7002 return EQUIP_ERR_OK;
7008 return EQUIP_ERR_BANK_FULL;
7010 else
7012 if( slot == NULL_SLOT )
7014 if( pProto->InventoryType == INVTYPE_BAG )
7016 Bag *pBag = (Bag*)pItem;
7017 if( pBag && !pBag->IsEmpty() )
7018 return EQUIP_ERR_NONEMPTY_BAG_OVER_OTHER_BAG;
7020 if( pProto->Stackable > 1 )
7022 if( bag == INVENTORY_SLOT_BAG_0 )
7024 for(int i = BANK_SLOT_ITEM_START; i < BANK_SLOT_ITEM_END; i++)
7026 pItem2 = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
7027 if( pItem2 && pItem2->GetEntry() == pItem->GetEntry() && pItem2->GetCount() + pItem->GetCount() <= pProto->Stackable )
7029 dest = ( (INVENTORY_SLOT_BAG_0 << 8) | i );
7030 return EQUIP_ERR_OK;
7034 else
7036 pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, bag );
7037 if( pBag )
7039 pBagProto = pBag->GetProto();
7040 if( pBagProto )
7042 for(uint32 j = 0; j < pBagProto->ContainerSlots; j++)
7044 pItem2 = GetItemByPos( bag, j );
7045 if( pItem2 && pItem2->GetEntry() == pItem->GetEntry() && pItem2->GetCount() + pItem->GetCount() <= pProto->Stackable )
7047 dest = ( (bag << 8) | j );
7048 return EQUIP_ERR_OK;
7055 if( bag == INVENTORY_SLOT_BAG_0 )
7057 for(int i = BANK_SLOT_ITEM_START; i < BANK_SLOT_ITEM_END; i++)
7059 pItem2 = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
7060 if( !pItem2 )
7062 dest = ( (INVENTORY_SLOT_BAG_0 << 8) | i );
7063 return EQUIP_ERR_OK;
7067 else
7069 pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, bag );
7070 if( pBag )
7072 pBagProto = pBag->GetProto();
7073 if( pBagProto )
7075 if( pBagProto->Class == ITEM_CLASS_QUIVER && pBagProto->SubClass != pProto->SubClass )
7076 return EQUIP_ERR_ONLY_AMMO_CAN_GO_HERE;
7077 if( pBagProto->Class == ITEM_CLASS_CONTAINER && pBagProto->SubClass > ITEM_SUBCLASS_CONTAINER && pBagProto->SubClass != pProto->SubClass )
7078 return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG;
7079 for(uint32 j = 0; j < pBagProto->ContainerSlots; j++)
7081 pItem2 = GetItemByPos( bag, j );
7082 if( !pItem2 )
7084 dest = ( (bag << 8) | j );
7085 return EQUIP_ERR_OK;
7091 return EQUIP_ERR_BAG_FULL;
7093 else
7095 if( pProto->InventoryType == INVTYPE_BAG )
7097 Bag *pBag = (Bag*)pItem;
7098 if( pBag )
7100 if( slot >= BANK_SLOT_BAG_START && slot < BANK_SLOT_BAG_END )
7102 if( !HasBankBagSlot( slot ) )
7103 return EQUIP_ERR_MUST_PURCHASE_THAT_BAG_SLOT;
7104 if( uint8 cantuse = CanUseItem( pItem ) != EQUIP_ERR_OK )
7105 return cantuse;
7107 else
7109 if( !pBag->IsEmpty() )
7110 return EQUIP_ERR_NONEMPTY_BAG_OVER_OTHER_BAG;
7114 else
7116 if( slot >= BANK_SLOT_BAG_START && slot < BANK_SLOT_BAG_END )
7117 return EQUIP_ERR_ITEM_DOESNT_GO_TO_SLOT;
7119 pItem2 = GetItemByPos( bag, slot );
7120 if( pItem2 && !swap )
7122 if( pProto->Stackable > 1 && pItem2->GetEntry() == pItem->GetEntry() && pItem2->GetCount() + pItem->GetCount() <= pProto->Stackable )
7124 dest = ( (bag << 8) | slot );
7125 return EQUIP_ERR_OK;
7127 else
7128 return EQUIP_ERR_COULDNT_SPLIT_ITEMS;
7130 else
7132 if( bag == INVENTORY_SLOT_BAG_0 )
7134 dest = ( (bag << 8) | slot );
7135 return EQUIP_ERR_OK;
7137 else
7139 pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, bag );
7140 if( pBag )
7142 pBagProto = pBag->GetProto();
7143 if( pBagProto )
7145 if( pBagProto->Class == ITEM_CLASS_QUIVER && pBagProto->SubClass != pProto->SubClass )
7146 return EQUIP_ERR_ONLY_AMMO_CAN_GO_HERE;
7147 if( pBagProto->Class == ITEM_CLASS_CONTAINER && pBagProto->SubClass > ITEM_SUBCLASS_CONTAINER && pBagProto->SubClass != pProto->SubClass )
7148 return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG;
7149 dest = ( (bag << 8) | slot );
7150 return EQUIP_ERR_OK;
7159 if( !swap )
7160 return EQUIP_ERR_ITEM_NOT_FOUND;
7161 else
7162 return EQUIP_ERR_ITEMS_CANT_BE_SWAPPED;
7163 return 0;
7166 uint8 Player::CanUseItem( Item *pItem, bool check_alive ) const
7168 if( pItem )
7170 sLog.outDebug( "STORAGE: CanUseItem item = %u", pItem->GetEntry());
7171 if( !isAlive() && check_alive )
7172 return EQUIP_ERR_YOU_ARE_DEAD;
7173 //if( isStunned() )
7174 // return EQUIP_ERR_YOU_ARE_STUNNED;
7175 ItemPrototype const *pProto = pItem->GetProto();
7176 if( pProto )
7178 if( pItem->IsBindedNotWith(GetGUID()) )
7179 return EQUIP_ERR_DONT_OWN_THAT_ITEM;
7180 if( (pProto->AllowableClass & getClassMask()) == 0 || (pProto->AllowableRace & getRaceMask()) == 0 )
7181 return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM;
7182 if( pItem->GetSkill() != 0 )
7184 if( GetSkillValue( pItem->GetSkill() ) == 0 )
7185 return EQUIP_ERR_NO_REQUIRED_PROFICIENCY;
7187 if( pProto->RequiredSkill != 0 )
7189 if( GetSkillValue( pProto->RequiredSkill ) == 0 )
7190 return EQUIP_ERR_NO_REQUIRED_PROFICIENCY;
7191 else if( GetSkillValue( pProto->RequiredSkill ) < pProto->RequiredSkillRank )
7192 return EQUIP_ERR_SKILL_ISNT_HIGH_ENOUGH;
7194 if( pProto->RequiredSpell != 0 && !HasSpell( pProto->RequiredSpell ) )
7195 return EQUIP_ERR_NO_REQUIRED_PROFICIENCY;
7196 if( GetHonorRank() < pProto->RequiredHonorRank )
7197 return EQUIP_ITEM_RANK_NOT_ENOUGH;
7198 /*if( GetREputation() < pProto->RequiredReputation )
7199 return EQUIP_ITEM_REPUTATION_NOT_ENOUGH;
7201 if( getLevel() < pProto->RequiredLevel )
7202 return EQUIP_ERR_YOU_MUST_REACH_LEVEL_N;
7203 return EQUIP_ERR_OK;
7206 return EQUIP_ERR_ITEM_NOT_FOUND;
7209 bool Player::CanUseItem( ItemPrototype const *pProto )
7211 // Used by group, function NeedBeforeGreed, to know if a prototype can be used by a player
7213 if( pProto )
7215 if( (pProto->AllowableClass & getClassMask()) == 0 || (pProto->AllowableRace & getRaceMask()) == 0 )
7216 return false;
7217 if( pProto->RequiredSkill != 0 )
7219 if( GetSkillValue( pProto->RequiredSkill ) == 0 )
7220 return false;
7221 else if( GetSkillValue( pProto->RequiredSkill ) < pProto->RequiredSkillRank )
7222 return false;
7224 if( pProto->RequiredSpell != 0 && !HasSpell( pProto->RequiredSpell ) )
7225 return false;
7226 if( GetHonorRank() < pProto->RequiredHonorRank )
7227 return false;
7228 if( getLevel() < pProto->RequiredLevel )
7229 return false;
7230 return true;
7232 return false;
7235 uint8 Player::CanUseAmmo( uint32 item ) const
7237 sLog.outDebug( "STORAGE: CanUseAmmo item = %u", item);
7238 if( !isAlive() )
7239 return EQUIP_ERR_YOU_ARE_DEAD;
7240 //if( isStunned() )
7241 // return EQUIP_ERR_YOU_ARE_STUNNED;
7242 ItemPrototype const *pProto = objmgr.GetItemPrototype( item );
7243 if( pProto )
7245 if( (pProto->AllowableClass & getClassMask()) == 0 || (pProto->AllowableRace & getRaceMask()) == 0 )
7246 return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM;
7247 if( pProto->RequiredSkill != 0 )
7249 if( GetSkillValue( pProto->RequiredSkill ) == 0 )
7250 return EQUIP_ERR_NO_REQUIRED_PROFICIENCY;
7251 else if( GetSkillValue( pProto->RequiredSkill ) < pProto->RequiredSkillRank )
7252 return EQUIP_ERR_SKILL_ISNT_HIGH_ENOUGH;
7254 if( pProto->RequiredSpell != 0 && !HasSpell( pProto->RequiredSpell ) )
7255 return EQUIP_ERR_NO_REQUIRED_PROFICIENCY;
7256 if( GetHonorRank() < pProto->RequiredHonorRank )
7257 return EQUIP_ITEM_RANK_NOT_ENOUGH;
7258 /*if( GetREputation() < pProto->RequiredReputation )
7259 return EQUIP_ITEM_REPUTATION_NOT_ENOUGH;
7261 if( getLevel() < pProto->RequiredLevel )
7262 return EQUIP_ERR_YOU_MUST_REACH_LEVEL_N;
7263 return EQUIP_ERR_OK;
7265 return EQUIP_ERR_ITEM_NOT_FOUND;
7268 // Return stored item (if stored to stack, it can diff. from pItem). And pItem ca be deleted in this case.
7269 Item* Player::StoreNewItem( uint16 pos, uint32 item, uint32 count, bool update ,bool fromLoot )
7271 Item *pItem = CreateItem( item, count );
7272 if( pItem )
7274 ItemPrototype const *pProto = pItem->GetProto();
7275 ItemAdded( item, count );
7276 if(fromLoot)
7277 pItem->SetItemRandomProperties();
7278 return StoreItem( pos, pItem, update );
7280 return NULL;
7283 // Return stored item (if stored to stack, it can diff. from pItem). And pItem ca be deleted in this case.
7284 Item* Player::StoreItem( uint16 pos, Item *pItem, bool update )
7286 if( pItem )
7288 if( pItem->GetProto()->Bonding == BIND_WHEN_PICKED_UP || pItem->GetProto()->Class == ITEM_CLASS_QUEST)
7289 pItem->SetBinding( true );
7291 uint8 bag = pos >> 8;
7292 uint8 slot = pos & 255;
7294 sLog.outDebug( "STORAGE: StoreItem bag = %u, slot = %u, item = %u, count = %u", bag, slot, pItem->GetEntry(), pItem->GetCount());
7296 Item *pItem2 = GetItemByPos( bag, slot );
7298 if( !pItem2 )
7300 if( bag == INVENTORY_SLOT_BAG_0 )
7302 m_items[slot] = pItem;
7303 SetUInt64Value( (uint16)(PLAYER_FIELD_INV_SLOT_HEAD + (slot * 2) ), pItem->GetGUID() );
7304 pItem->SetUInt64Value( ITEM_FIELD_CONTAINED, GetGUID() );
7305 pItem->SetUInt64Value( ITEM_FIELD_OWNER, GetGUID() );
7307 pItem->SetSlot( slot );
7309 if( IsInWorld() && update )
7311 pItem->AddToWorld();
7312 pItem->SendUpdateToPlayer( this );
7315 else
7317 Bag *pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, bag );
7318 if( pBag )
7320 pBag->StoreItem( slot, pItem, update );
7321 if( IsInWorld() && update )
7323 pItem->AddToWorld();
7324 pItem->SendUpdateToPlayer( this );
7329 else
7331 pItem2->SetCount( pItem2->GetCount() + pItem->GetCount() );
7332 if( IsInWorld() && update )
7333 pItem2->SendUpdateToPlayer( this );
7335 // delete item (it not in any slot currently)
7336 pItem->DeleteFromDB();
7337 if( IsInWorld() && update )
7339 pItem->RemoveFromWorld();
7340 pItem->DestroyForPlayer( this );
7342 delete pItem;
7344 return pItem2;
7347 return pItem;
7350 void Player::EquipItem( uint16 pos, Item *pItem, bool update )
7352 if( pItem )
7354 VisualizeItem( pos, pItem);
7355 uint8 slot = pos & 255;
7357 if(isAlive())
7358 _ApplyItemMods(pItem, slot, true);
7360 if( IsInWorld() && update )
7362 pItem->AddToWorld();
7363 pItem->SendUpdateToPlayer( this );
7368 void Player::QuickEquipItem( uint16 pos, Item *pItem)
7370 if( pItem )
7372 VisualizeItem( pos, pItem);
7374 if( IsInWorld() )
7376 pItem->AddToWorld();
7377 pItem->SendUpdateToPlayer( this );
7382 void Player::VisualizeItem( uint16 pos, Item *pItem)
7384 if(!pItem)
7385 return;
7387 // check also BIND_WHEN_PICKED_UP for .additem or .additemset case by GM (not binded at adding to inventory)
7388 if( pItem->GetProto()->Bonding == BIND_WHEN_EQUIPED || pItem->GetProto()->Bonding == BIND_WHEN_PICKED_UP )
7389 pItem->SetBinding( true );
7391 uint8 bag = pos >> 8;
7392 uint8 slot = pos & 255;
7394 sLog.outDebug( "STORAGE: EquipItem bag = %u, slot = %u, item = %u", bag, slot, pItem->GetEntry());
7396 m_items[slot] = pItem;
7397 SetUInt64Value( (uint16)(PLAYER_FIELD_INV_SLOT_HEAD + (slot * 2) ), pItem->GetGUID() );
7398 pItem->SetUInt64Value( ITEM_FIELD_CONTAINED, GetGUID() );
7399 pItem->SetUInt64Value( ITEM_FIELD_OWNER, GetGUID() );
7400 pItem->SetSlot( slot );
7402 if( slot < EQUIPMENT_SLOT_END )
7404 int VisibleBase = PLAYER_VISIBLE_ITEM_1_0 + (slot * 12);
7405 SetUInt32Value(VisibleBase, pItem->GetEntry());
7406 SetUInt32Value(VisibleBase + 1, pItem->GetUInt32Value(ITEM_FIELD_ENCHANTMENT));
7407 SetUInt32Value(VisibleBase + 2, pItem->GetUInt32Value(ITEM_FIELD_ENCHANTMENT + 1*3));
7408 SetUInt32Value(VisibleBase + 3, pItem->GetUInt32Value(ITEM_FIELD_ENCHANTMENT + 2*3));
7409 SetUInt32Value(VisibleBase + 4, pItem->GetUInt32Value(ITEM_FIELD_ENCHANTMENT + 3*3));
7410 SetUInt32Value(VisibleBase + 5, pItem->GetUInt32Value(ITEM_FIELD_ENCHANTMENT + 4*3));
7411 SetUInt32Value(VisibleBase + 6, pItem->GetUInt32Value(ITEM_FIELD_ENCHANTMENT + 5*3));
7412 SetUInt32Value(VisibleBase + 7, pItem->GetUInt32Value(ITEM_FIELD_ENCHANTMENT + 6*3));
7413 SetUInt32Value(VisibleBase + 8, pItem->GetUInt32Value(ITEM_FIELD_RANDOM_PROPERTIES_ID));
7418 // Return stored item (if stored to stack, it can diff. from pItem). And pItem ca be deleted in this case.
7419 Item* Player::BankItem( uint16 pos, Item *pItem, bool update )
7421 return StoreItem( pos, pItem, update);
7424 void Player::RemoveItem( uint8 bag, uint8 slot, bool update )
7426 Item *pItem = GetItemByPos( bag, slot );
7427 if( pItem )
7429 sLog.outDebug( "STORAGE: RemoveItem bag = %u, slot = %u, item = %u", bag, slot, pItem->GetEntry());
7431 if( bag == INVENTORY_SLOT_BAG_0 )
7433 m_items[slot] = NULL;
7434 SetUInt64Value((uint16)(PLAYER_FIELD_INV_SLOT_HEAD + (slot*2)), 0);
7436 if ( slot < INVENTORY_SLOT_BAG_END )
7438 _ApplyItemMods(pItem, slot, false);
7439 if ( slot < EQUIPMENT_SLOT_END )
7441 int VisibleBase = PLAYER_VISIBLE_ITEM_1_0 + (slot * 12);
7442 for (int i = VisibleBase; i < VisibleBase + 12; ++i)
7443 SetUInt32Value(i, 0);
7447 else
7449 Bag *pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, bag );
7450 if( pBag )
7451 pBag->RemoveItem(slot, update);
7453 pItem->SetUInt64Value( ITEM_FIELD_CONTAINED, 0 );
7454 // pItem->SetUInt64Value( ITEM_FIELD_OWNER, 0 ); not clear owner at remove (it will be set at store). This used in mail and auction code
7455 pItem->SetSlot( NULL_SLOT );
7456 if( IsInWorld() && update )
7457 pItem->SendUpdateToPlayer( this );
7461 void Player::RemoveItemCount( uint32 item, uint32 count, bool update )
7463 sLog.outDebug( "STORAGE: RemoveItemCount item = %u, count = %u", item, count);
7464 Item *pItem;
7465 uint32 remcount = 0;
7466 for(int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; i++)
7468 pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
7469 if( pItem && pItem->GetEntry() == item )
7471 if( pItem->GetCount() + remcount <= count )
7473 remcount += pItem->GetCount();
7474 RemoveItem( INVENTORY_SLOT_BAG_0, i, update );
7476 if(remcount >=count)
7477 return;
7479 else
7481 pItem->SetCount( pItem->GetCount() - count + remcount );
7482 if( IsInWorld() && update )
7483 pItem->SendUpdateToPlayer( this );
7484 return;
7488 Bag *pBag;
7489 ItemPrototype const *pBagProto;
7490 for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)
7492 pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i );
7493 if( pBag )
7495 pBagProto = pBag->GetProto();
7496 if( pBagProto )
7498 for(uint32 j = 0; j < pBagProto->ContainerSlots; j++)
7500 pItem = GetItemByPos( i, j );
7501 if( pItem && pItem->GetEntry() == item )
7503 if( pItem->GetCount() + remcount <= count )
7505 remcount += pItem->GetCount();
7506 RemoveItem( i, j, update );
7508 if(remcount >=count)
7509 return;
7511 else
7513 pItem->SetCount( pItem->GetCount() - count + remcount );
7514 if( IsInWorld() && update )
7515 pItem->SendUpdateToPlayer( this );
7516 return;
7525 void Player::DestroyItem( uint8 bag, uint8 slot, bool update )
7527 Item *pItem = GetItemByPos( bag, slot );
7528 if( pItem )
7530 sLog.outDebug( "STORAGE: DestroyItem bag = %u, slot = %u, item = %u", bag, slot, pItem->GetEntry());
7531 pItem->SetOwnerGUID(0);
7532 pItem->SetSlot( NULL_SLOT );
7533 pItem->SetUInt64Value( ITEM_FIELD_CONTAINED, 0 );
7534 pItem->DeleteFromDB();
7535 ItemPrototype const *pProto = pItem->GetProto();
7537 if( bag == INVENTORY_SLOT_BAG_0 )
7539 ItemRemoved( pItem->GetEntry(), pItem->GetCount() );
7541 SetUInt64Value((uint16)(PLAYER_FIELD_INV_SLOT_HEAD + (slot*2)), 0);
7543 if ( slot < EQUIPMENT_SLOT_END )
7545 _ApplyItemMods(pItem, slot, false);
7546 int VisibleBase = PLAYER_VISIBLE_ITEM_1_0 + (slot * 12);
7547 for (int i = VisibleBase; i < VisibleBase + 12; ++i)
7548 SetUInt32Value(i, 0);
7549 for(int enchant_slot = 0 ; enchant_slot < 7; enchant_slot++)
7551 uint32 Enchant_id = pItem->GetUInt32Value(ITEM_FIELD_ENCHANTMENT+enchant_slot*3);
7552 if( Enchant_id)
7554 SpellItemEnchantmentEntry *pEnchant = sSpellItemEnchantmentStore.LookupEntry(Enchant_id);
7555 if(!pEnchant)
7556 continue;
7557 uint32 enchant_display = pEnchant->display_type;
7558 uint32 enchant_value1 = pEnchant->value1;
7559 //uint32 enchant_value2 = pEnchant->value2;
7560 uint32 enchant_spell_id = pEnchant->spellid;
7561 //uint32 enchant_aura_id = pEnchant->aura_id;
7562 //uint32 enchant_description = pEnchant->description;
7563 //SpellEntry *enchantSpell_info = sSpellStore.LookupEntry(enchant_spell_id);
7564 if(enchant_display ==4)
7565 SetArmor(GetArmor()-enchant_value1);
7566 else if(enchant_display ==2)
7568 SetUInt32Value(UNIT_FIELD_MINDAMAGE,GetUInt32Value(UNIT_FIELD_MINDAMAGE)-enchant_value1);
7569 SetUInt32Value(UNIT_FIELD_MAXDAMAGE,GetUInt32Value(UNIT_FIELD_MAXDAMAGE)-enchant_value1);
7571 else
7573 RemoveAurasDueToSpell(enchant_spell_id);
7579 m_items[slot] = NULL;
7580 if( IsInWorld() && update )
7582 pItem->RemoveFromWorld();
7583 pItem->DestroyForPlayer( this );
7586 else
7588 Bag *pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, bag );
7589 if( pBag )
7591 if( pProto && pProto->Class == ITEM_CLASS_QUEST )
7592 ItemRemoved( pItem->GetEntry(), pItem->GetCount() );
7593 pBag->RemoveItem(slot, update);
7595 if( IsInWorld() && update )
7597 pItem->RemoveFromWorld();
7598 pItem->DestroyForPlayer(this);
7603 delete pItem;
7606 void Player::DestroyItemCount( uint32 item, uint32 count, bool update )
7608 sLog.outDebug( "STORAGE: DestroyItemCount item = %u, count = %u", item, count);
7609 Item *pItem;
7610 ItemPrototype const *pProto;
7611 uint32 remcount = 0;
7612 for(int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; i++)
7614 pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
7615 if( pItem && pItem->GetEntry() == item )
7617 if( pItem->GetCount() + remcount <= count )
7619 remcount += pItem->GetCount();
7620 DestroyItem( INVENTORY_SLOT_BAG_0, i, update);
7622 if(remcount >=count)
7623 return;
7625 else
7627 pProto = pItem->GetProto();
7628 ItemRemoved( pItem->GetEntry(), count - remcount );
7629 pItem->SetCount( pItem->GetCount() - count + remcount );
7630 if( IsInWorld() & update )
7631 pItem->SendUpdateToPlayer( this );
7632 return;
7636 Bag *pBag;
7637 ItemPrototype const *pBagProto;
7638 for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)
7640 pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i );
7641 if( pBag )
7643 pBagProto = pBag->GetProto();
7644 if( pBagProto )
7646 for(uint32 j = 0; j < pBagProto->ContainerSlots; j++)
7648 pItem = pBag->GetItemByPos(j);
7649 if( pItem && pItem->GetEntry() == item )
7651 if( pItem->GetCount() + remcount <= count )
7653 remcount += pItem->GetCount();
7654 DestroyItem( i, j, update );
7656 if(remcount >=count)
7657 return;
7659 else
7661 pProto = pItem->GetProto();
7662 ItemRemoved( pItem->GetEntry(), count - remcount );
7663 pItem->SetCount( pItem->GetCount() - count + remcount );
7664 if( IsInWorld() && update )
7665 pItem->SendUpdateToPlayer( this );
7666 return;
7675 void Player::SplitItem( uint16 src, uint16 dst, uint32 count )
7677 uint8 srcbag = src >> 8;
7678 uint8 srcslot = src & 255;
7680 uint8 dstbag = dst >> 8;
7681 uint8 dstslot = dst & 255;
7683 Item *pSrcItem = GetItemByPos( srcbag, srcslot );
7684 if( pSrcItem )
7686 sLog.outDebug( "STORAGE: SplitItem bag = %u, slot = %u, item = %u, count = %u", dstbag, dstslot, pSrcItem->GetEntry(), count);
7687 Item *pNewItem = CreateItem( pSrcItem->GetEntry(), count );
7688 if( pNewItem )
7690 uint16 dest;
7691 uint8 msg;
7692 if( IsInventoryPos( dst ) )
7694 msg = CanStoreItem( dstbag, dstslot, dest, pNewItem, false );
7695 if( msg == EQUIP_ERR_OK )
7697 pSrcItem->SetCount( pSrcItem->GetCount() - count );
7698 if( IsInWorld() )
7699 pSrcItem->SendUpdateToPlayer( this );
7700 StoreItem( dest, pNewItem, true);
7702 else
7704 delete pNewItem;
7705 SendEquipError( msg, pSrcItem, NULL );
7708 else if( IsBankPos ( dst ) )
7710 msg = CanBankItem( dstbag, dstslot, dest, pNewItem, false );
7711 if( msg == EQUIP_ERR_OK )
7713 pSrcItem->SetCount( pSrcItem->GetCount() - count );
7714 if( IsInWorld() )
7715 pSrcItem->SendUpdateToPlayer( this );
7716 BankItem( dest, pNewItem, true);
7718 else
7720 delete pNewItem;
7721 SendEquipError( msg, pSrcItem, NULL );
7724 else if( IsEquipmentPos ( dst ) )
7726 msg = CanEquipItem( dstslot, dest, pNewItem, false );
7727 if( msg == EQUIP_ERR_OK )
7729 pSrcItem->SetCount( pSrcItem->GetCount() - count );
7730 if( IsInWorld() )
7731 pSrcItem->SendUpdateToPlayer( this );
7732 EquipItem( dest, pNewItem, true);
7734 else
7736 delete pNewItem;
7737 SendEquipError( msg, pSrcItem, NULL );
7740 return;
7743 SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, pSrcItem, NULL );
7746 void Player::SwapItem( uint16 src, uint16 dst )
7748 uint8 srcbag = src >> 8;
7749 uint8 srcslot = src & 255;
7751 uint8 dstbag = dst >> 8;
7752 uint8 dstslot = dst & 255;
7754 Item *pSrcItem = GetItemByPos( srcbag, srcslot );
7755 Item *pDstItem = GetItemByPos( dstbag, dstslot );
7757 if( pSrcItem )
7759 sLog.outDebug( "STORAGE: SwapItem bag = %u, slot = %u, item = %u", dstbag, dstslot, pSrcItem->GetEntry());
7761 if(!isAlive() )
7763 SendEquipError( EQUIP_ERR_YOU_ARE_DEAD, pSrcItem, pDstItem );
7764 return;
7767 if(IsEquipmentPos ( src ))
7769 uint8 msg = CanUnequipItem( src, pDstItem != NULL );
7770 if(msg != EQUIP_ERR_OK)
7772 SendEquipError( msg, pSrcItem, pDstItem );
7773 return;
7777 if( srcslot == dstbag )
7779 SendEquipError( EQUIP_ERR_NONEMPTY_BAG_OVER_OTHER_BAG, pSrcItem, pDstItem );
7780 return;
7783 uint16 dest;
7784 uint8 msg;
7785 if( !pDstItem )
7787 if( IsInventoryPos( dst ) )
7789 msg = CanStoreItem( dstbag, dstslot, dest, pSrcItem, false );
7790 if( msg == EQUIP_ERR_OK )
7792 RemoveItem(srcbag, srcslot, true);
7793 StoreItem( dest, pSrcItem, true);
7794 return;
7796 else
7797 SendEquipError( msg, pSrcItem, NULL );
7799 else if( IsBankPos ( dst ) )
7801 msg = CanBankItem( dstbag, dstslot, dest, pSrcItem, false);
7802 if( msg == EQUIP_ERR_OK )
7804 RemoveItem(srcbag, srcslot, true);
7805 BankItem( dest, pSrcItem, true);
7806 return;
7808 else
7809 SendEquipError( msg, pSrcItem, NULL );
7811 else if( IsEquipmentPos ( dst ) )
7813 msg = CanEquipItem( dstslot, dest, pSrcItem, false );
7814 if( msg == EQUIP_ERR_OK )
7816 RemoveItem(srcbag, srcslot, true);
7817 EquipItem( dest, pSrcItem, true);
7818 return;
7820 else
7821 SendEquipError( msg, pSrcItem, NULL );
7824 else
7826 if( IsInventoryPos( dst ) )
7828 if( CanStoreItem( dstbag, dstslot, dest, pSrcItem, false ) == EQUIP_ERR_OK )
7830 if( pSrcItem->GetCount() + pDstItem->GetCount() <= pSrcItem->GetProto()->Stackable )
7832 RemoveItem(srcbag, srcslot, true);
7833 StoreItem( dest, pSrcItem, true);
7835 else
7837 pSrcItem->SetCount( pSrcItem->GetCount() + pDstItem->GetCount() - pSrcItem->GetProto()->Stackable );
7838 pDstItem->SetCount( pSrcItem->GetProto()->Stackable );
7839 if( IsInWorld() )
7841 pSrcItem->SendUpdateToPlayer( this );
7842 pDstItem->SendUpdateToPlayer( this );
7845 return;
7848 else if( IsBankPos ( dst ) )
7850 if( CanBankItem( dstbag, dstslot, dest, pSrcItem, false ) == EQUIP_ERR_OK )
7852 if( pSrcItem->GetCount() + pDstItem->GetCount() <= pSrcItem->GetProto()->Stackable )
7854 RemoveItem(srcbag, srcslot, true);
7855 BankItem( dest, pSrcItem, true);
7857 else
7859 pSrcItem->SetCount( pSrcItem->GetCount() + pDstItem->GetCount() - pSrcItem->GetProto()->Stackable );
7860 pDstItem->SetCount( pSrcItem->GetProto()->Stackable );
7861 if( IsInWorld() )
7863 pSrcItem->SendUpdateToPlayer( this );
7864 pDstItem->SendUpdateToPlayer( this );
7867 return;
7870 else if( IsEquipmentPos ( dst ) )
7872 if( CanEquipItem( dstslot, dest, pSrcItem, false ) == EQUIP_ERR_OK )
7874 if( pSrcItem->GetCount() + pDstItem->GetCount() <= pSrcItem->GetProto()->Stackable )
7876 RemoveItem(srcbag, srcslot, true);
7877 EquipItem( dest, pSrcItem, true);
7879 else
7881 pSrcItem->SetCount( pSrcItem->GetCount() + pDstItem->GetCount() - pSrcItem->GetProto()->Stackable );
7882 pDstItem->SetCount( pSrcItem->GetProto()->Stackable );
7883 if( IsInWorld() )
7885 pSrcItem->SendUpdateToPlayer( this );
7886 pDstItem->SendUpdateToPlayer( this );
7889 return;
7892 if( IsInventoryPos( dst ) )
7893 msg = CanStoreItem( dstbag, dstslot, dest, pSrcItem, true );
7894 else if( IsBankPos( dst ) )
7895 msg = CanBankItem( dstbag, dstslot, dest, pSrcItem, true );
7896 else if( IsEquipmentPos( dst ) )
7898 msg = CanEquipItem( dstslot, dest, pSrcItem, true );
7899 if( msg == EQUIP_ERR_OK )
7900 msg = CanUnequipItem( dest, true );
7903 if( msg == EQUIP_ERR_OK )
7905 uint16 dest2;
7906 if( IsInventoryPos( src ) )
7908 msg = CanStoreItem( srcbag, srcslot, dest2, pDstItem, true );
7909 if( msg != EQUIP_ERR_OK )
7911 SendEquipError( EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG, pSrcItem, pDstItem );
7912 return;
7915 else if( IsBankPos( src ) )
7917 msg = CanBankItem( srcbag, srcslot, dest2, pDstItem, true );
7918 if( msg != EQUIP_ERR_OK )
7920 SendEquipError( EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG, pSrcItem, pDstItem );
7921 return;
7924 else if( IsEquipmentPos( src ) )
7926 msg = CanEquipItem( srcslot, dest2, pDstItem, true);
7927 if( msg == EQUIP_ERR_OK )
7928 msg = CanUnequipItem( dest2, true);
7930 if( msg != EQUIP_ERR_OK )
7932 SendEquipError( EQUIP_ERR_ITEM_DOESNT_GO_TO_SLOT, pSrcItem, pDstItem );
7933 return;
7936 RemoveItem(dstbag, dstslot, false);
7937 RemoveItem(srcbag, srcslot, false);
7938 if( IsInventoryPos( dst ) )
7939 StoreItem(dest, pSrcItem, true);
7940 else if( IsBankPos( dst ) )
7941 BankItem(dest, pSrcItem, true);
7942 else if( IsEquipmentPos( dst ) )
7943 EquipItem(dest, pSrcItem, true);
7944 if( IsInventoryPos( src ) )
7945 StoreItem(dest2, pDstItem, true);
7946 else if( IsBankPos( src ) )
7947 BankItem(dest2, pDstItem, true);
7948 else if( IsEquipmentPos( src ) )
7949 EquipItem(dest2, pDstItem, true);
7950 return;
7952 else
7953 SendEquipError( msg, pSrcItem, pDstItem );
7954 return;
7959 void Player::AddItemToBuyBackSlot( uint32 slot, Item *pItem )
7961 if( pItem )
7963 if( slot >= BUYBACK_SLOT_START && slot < BUYBACK_SLOT_END )
7965 RemoveItemFromBuyBackSlot( slot );
7966 sLog.outDebug( "STORAGE: AddItemToBuyBackSlot item = %u, slot = %u", pItem->GetEntry(), slot);
7967 uint32 eslot = slot - BUYBACK_SLOT_START;
7969 m_buybackitems[eslot] = pItem;
7970 time_t base = time(NULL);
7971 time_t etime = base + (30 * 3600);
7973 SetUInt64Value( PLAYER_FIELD_VENDORBUYBACK_SLOT_1 + eslot * 2, pItem->GetGUID() );
7974 ItemPrototype const *pProto = pItem->GetProto();
7975 if( pProto )
7976 SetUInt32Value( PLAYER_FIELD_BUYBACK_PRICE_1 + eslot, pProto->SellPrice * pItem->GetCount() );
7977 else
7978 SetUInt32Value( PLAYER_FIELD_BUYBACK_PRICE_1 + eslot, 0 );
7979 SetUInt32Value( PLAYER_FIELD_BUYBACK_TIMESTAMP_1 + eslot, (uint32)etime );
7984 Item* Player::GetItemFromBuyBackSlot( uint32 slot )
7986 sLog.outDebug( "STORAGE: GetItemFromBuyBackSlot slot = %u", slot);
7987 if( slot >= BUYBACK_SLOT_START && slot < BUYBACK_SLOT_END )
7988 return m_buybackitems[slot - BUYBACK_SLOT_START];
7989 return NULL;
7992 void Player::RemoveItemFromBuyBackSlot( uint32 slot )
7994 sLog.outDebug( "STORAGE: RemoveItemFromBuyBackSlot slot = %u", slot);
7995 if( slot >= BUYBACK_SLOT_START && slot < BUYBACK_SLOT_END )
7997 uint32 eslot = slot - BUYBACK_SLOT_START;
7998 Item *pItem = m_buybackitems[eslot];
7999 if( pItem )
8000 pItem->RemoveFromWorld();
8002 m_buybackitems[eslot] = NULL;
8003 SetUInt64Value( PLAYER_FIELD_VENDORBUYBACK_SLOT_1 + eslot * 2, 0 );
8004 SetUInt32Value( PLAYER_FIELD_BUYBACK_PRICE_1 + eslot, 0 );
8005 SetUInt32Value( PLAYER_FIELD_BUYBACK_TIMESTAMP_1 + eslot, 0 );
8009 void Player::SendEquipError( uint8 msg, Item* pItem, Item *pItem2 )
8011 sLog.outDetail( "WORLD: Sent SMSG_INVENTORY_CHANGE_FAILURE" );
8012 WorldPacket data;
8013 data.Initialize( SMSG_INVENTORY_CHANGE_FAILURE );
8014 data << msg;
8015 if( msg == EQUIP_ERR_YOU_MUST_REACH_LEVEL_N )
8016 data << (pItem && pItem->GetProto() ? pItem->GetProto()->RequiredLevel : uint32(0));
8017 data << (pItem ? pItem->GetGUID() : uint64(0));
8018 data << (pItem2 ? pItem2->GetGUID() : uint64(0));
8019 data << uint8(0);
8020 GetSession()->SendPacket(&data);
8023 void Player::SendBuyError( uint8 msg, Creature* pCreature, uint32 item, uint32 param )
8025 sLog.outDetail( "WORLD: Sent SMSG_BUY_FAILED" );
8026 WorldPacket data;
8027 data.Initialize( SMSG_BUY_FAILED );
8028 data << (pCreature ? pCreature->GetGUID() : uint64(0));
8029 data << item;
8030 if( param > 0 )
8031 data << param;
8032 data << msg;
8033 GetSession()->SendPacket(&data);
8036 void Player::SendSellError( uint8 msg, Creature* pCreature, uint64 guid, uint32 param )
8038 sLog.outDetail( "WORLD: Sent SMSG_SELL_ITEM" );
8039 WorldPacket data;
8040 data.Initialize( SMSG_SELL_ITEM );
8041 data << (pCreature ? pCreature->GetGUID() : uint64(0));
8042 data << guid;
8043 if( param > 0 )
8044 data << param;
8045 data << msg;
8046 GetSession()->SendPacket(&data);
8049 void Player::ClearTrade()
8051 tradeGold = 0;
8052 acceptTrade = false;
8053 for(int i=0; i<7; i++)
8054 tradeItems[i] = NULL_SLOT;
8057 void Player::TradeCancel(bool sendback)
8059 if(pTrader)
8061 // prevent loop cancel message (already processed)
8062 if(!sendback)
8063 pTrader->pTrader = NULL;
8065 WorldSession* ws = pTrader->GetSession();
8066 pTrader = NULL;
8067 ws->SendCancelTrade();
8069 ClearTrade();
8072 void Player::UpdateEnchantTime(uint32 time)
8074 for(std::list<struct EnchantDuration*>::iterator itr = m_enchantDuration.begin(),next;itr != m_enchantDuration.end();itr=next)
8076 next=itr;
8077 next++;
8078 if(*itr)
8080 if((*itr)->item)
8082 if(!(*itr)->item->GetUInt32Value(ITEM_FIELD_ENCHANTMENT+(*itr)->slot*3))
8084 delete *itr;
8085 m_enchantDuration.erase(itr);
8086 continue;
8088 if((*itr)->leftduration <= time)
8090 AddItemEnchant((*itr)->item,(*itr)->item->GetUInt32Value(ITEM_FIELD_ENCHANTMENT+(*itr)->slot*3),false);
8091 for(int y=0;y<3;y++)
8092 (*itr)->item->SetUInt32Value(ITEM_FIELD_ENCHANTMENT+(*itr)->slot*3+y,0);
8093 delete *itr;
8094 m_enchantDuration.erase(itr);
8095 continue;
8097 else if((*itr)->leftduration > time)
8099 (*itr)->leftduration -= time;
8106 // duration == 0 will remove item enchant
8107 void Player::AddEnchantDuration(Item *item,uint32 slot,uint32 duration)
8109 if(!item)
8110 return;
8111 for(std::list<struct EnchantDuration*>::iterator itr = m_enchantDuration.begin(),next;itr != m_enchantDuration.end();itr=next)
8113 next=itr;
8114 next++;
8115 if(*itr)
8117 if((*itr)->item)
8119 if((*itr)->item == item && (*itr)->slot == slot)
8121 delete *itr;
8122 m_enchantDuration.erase(itr);
8123 break;
8128 if(item && duration > 0 )
8130 GetSession()->SendItemEnchantTimeUpdate(item->GetGUID(),slot,uint32(duration/1000));
8131 EnchantDuration *ed = new EnchantDuration();
8132 ed->item = item;
8133 ed->leftduration = duration;
8134 ed->slot = slot;
8135 m_enchantDuration.push_back(ed);
8139 void Player::ReducePoisonCharges(uint32 enchantId)
8141 if(!enchantId)
8142 return;
8143 uint32 pEnchantId = 0;
8144 uint32 charges = 0;
8145 Item *pItem;
8146 uint16 pos;
8148 for(int i = EQUIPMENT_SLOT_MAINHAND; i < EQUIPMENT_SLOT_RANGED; i++)
8150 pos = ((INVENTORY_SLOT_BAG_0 << 8) | i);
8152 pItem = GetItemByPos( pos );
8153 if(!pItem)
8154 continue;
8155 for(int x=0;x<7;x++)
8157 charges = pItem->GetUInt32Value(ITEM_FIELD_ENCHANTMENT+x*3+2);
8158 if(charges == 0)
8159 continue;
8160 if(charges <= 1)
8162 AddItemEnchant(pItem,enchantId,false);
8163 for(int y=0;y<3;y++)
8164 pItem->SetUInt32Value(ITEM_FIELD_ENCHANTMENT+x*3+y,0);
8165 break;
8167 else
8169 pItem->SetUInt32Value(ITEM_FIELD_ENCHANTMENT+x*3+2,charges-1);
8170 break;
8176 void Player::SaveEnchant()
8178 uint32 duration = 0;
8180 for(std::list<struct EnchantDuration*>::iterator itr = m_enchantDuration.begin();itr != m_enchantDuration.end();itr++)
8182 if(*itr)
8184 if((*itr)->item)
8186 if((*itr)->leftduration > 0)
8188 (*itr)->item->SetUInt32Value(ITEM_FIELD_ENCHANTMENT+(*itr)->slot*3+1,(*itr)->leftduration);
8195 void Player::LoadEnchant()
8197 uint32 duration = 0;
8198 Item *pItem;
8199 uint16 pos;
8201 for(int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; i++)
8203 pos = ((INVENTORY_SLOT_BAG_0 << 8) | i);
8205 pItem = GetItemByPos( pos );
8206 if(!pItem)
8207 continue;
8208 if(pItem->GetProto()->Class != ITEM_CLASS_WEAPON && pItem->GetProto()->Class != ITEM_CLASS_ARMOR)
8209 continue;
8210 for(int x=0;x<7;x++)
8212 duration = pItem->GetUInt32Value(ITEM_FIELD_ENCHANTMENT+x*3+1);
8213 if( duration == 0 )
8214 continue;
8215 else if( duration > 0 )
8216 AddEnchantDuration(pItem,x,duration);
8219 Bag *pBag;
8220 ItemPrototype const *pBagProto;
8221 for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)
8223 pos = ((INVENTORY_SLOT_BAG_0 << 8) | i);
8224 pBag = (Bag*)GetItemByPos( pos );
8225 if( pBag )
8227 pBagProto = pBag->GetProto();
8228 if( pBagProto )
8230 for(uint32 j = 0; j < pBagProto->ContainerSlots; j++)
8232 pos = ((i << 8) | j);
8233 pItem = GetItemByPos( pos );
8234 if(!pItem)
8235 continue;
8236 if(pItem->GetProto()->Class != ITEM_CLASS_WEAPON && pItem->GetProto()->Class != ITEM_CLASS_ARMOR)
8237 continue;
8238 for(int x=0;x<7;x++)
8240 duration = pItem->GetUInt32Value(ITEM_FIELD_ENCHANTMENT+x*3+1);
8241 if( duration == 0 )
8242 continue;
8243 else if( duration > 0 )
8244 AddEnchantDuration(pItem,x,duration);
8250 for(int i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++)
8252 pos = ((INVENTORY_SLOT_BAG_0 << 8) | i);
8253 pBag = (Bag*)GetItemByPos( pos );
8254 if( pBag )
8256 pBagProto = pBag->GetProto();
8257 if( pBagProto )
8259 for(uint32 j = 0; j < pBagProto->ContainerSlots; j++)
8261 pos = ((i << 8) | j);
8262 pItem = GetItemByPos( pos );
8263 if(!pItem)
8264 continue;
8265 if(pItem->GetProto()->Class != ITEM_CLASS_WEAPON && pItem->GetProto()->Class != ITEM_CLASS_ARMOR)
8266 continue;
8267 for(int x=0;x<7;x++)
8269 duration = pItem->GetUInt32Value(ITEM_FIELD_ENCHANTMENT+x*3+1);
8270 if( duration == 0 )
8271 continue;
8272 else if( duration > 0 )
8273 AddEnchantDuration(pItem,x,duration);
8282 /*********************************************************/
8283 /*** QUEST SYSTEM ***/
8284 /*********************************************************/
8286 void Player::PrepareQuestMenu( uint64 guid )
8288 Object *pObject;
8289 Creature *pCreature = ObjectAccessor::Instance().GetCreature(*this, guid);
8290 if( pCreature )
8291 pObject = (Object*)pCreature;
8292 else
8294 GameObject *pGameObject = ObjectAccessor::Instance().GetGameObject(*this, guid);
8295 if( pGameObject )
8296 pObject = (Object*)pGameObject;
8297 else
8298 return;
8301 QuestMenu *qm = PlayerTalkClass->GetQuestMenu();
8302 qm->ClearMenu();
8304 for( std::list<Quest*>::iterator i = pObject->mInvolvedQuests.begin( ); i != pObject->mInvolvedQuests.end( ); i++ )
8306 Quest* pQuest = *i;
8307 if ( !pQuest )
8308 continue;
8310 uint32 quest_id = pQuest->GetQuestId();
8311 uint32 status = GetQuestStatus( quest_id );
8313 if ( status == QUEST_STATUS_COMPLETE && !GetQuestRewardStatus( quest_id ) )
8314 qm->AddMenuItem( quest_id, DIALOG_STATUS_REWARD, false );
8315 else if ( status == QUEST_STATUS_INCOMPLETE )
8316 qm->AddMenuItem( quest_id, DIALOG_STATUS_INCOMPLETE, false );
8319 for( std::list<Quest*>::iterator i = pObject->mQuests.begin( ); i != pObject->mQuests.end( ); i++ )
8321 Quest* pQuest = *i;
8322 if ( !pQuest )
8323 continue;
8325 uint32 quest_id = pQuest->GetQuestId();
8326 uint32 status = GetQuestStatus( quest_id );
8328 if ( status == QUEST_STATUS_NONE && CanTakeQuest( pQuest, false ) )
8329 qm->AddMenuItem( quest_id, DIALOG_STATUS_AVAILABLE, true );
8333 void Player::SendPreparedQuest( uint64 guid )
8335 QuestMenu* pQuestMenu = PlayerTalkClass->GetQuestMenu();
8336 if( !pQuestMenu || pQuestMenu->MenuItemCount() < 1 )
8337 return;
8339 uint32 status = pQuestMenu->GetItem(0).m_qIcon;
8340 if ( pQuestMenu->MenuItemCount() == 1 )
8342 uint32 quest_id = pQuestMenu->GetItem(0).m_qId;
8343 Quest *pQuest = objmgr.NewQuest( quest_id );
8344 if ( pQuest )
8346 if( status == DIALOG_STATUS_REWARD && !GetQuestRewardStatus( quest_id ) )
8347 PlayerTalkClass->SendRequestedItems( pQuest, guid, CanRewardQuest(pQuest,false), true );
8348 else if( status == DIALOG_STATUS_INCOMPLETE )
8349 PlayerTalkClass->SendRequestedItems( pQuest, guid, false, true );
8350 else
8351 PlayerTalkClass->SendQuestDetails( pQuest, guid, true );
8352 delete pQuest;
8355 else
8357 QEmote qe;
8358 qe._Delay = 0;
8359 qe._Emote = 0;
8360 std::string title = "";
8361 Creature *pCreature = ObjectAccessor::Instance().GetCreature(*this, guid);
8362 if( pCreature )
8364 uint32 textid = pCreature->GetNpcTextId();
8365 GossipText * gossiptext = objmgr.GetGossipText(textid);
8366 if( !gossiptext )
8368 qe._Delay = TEXTEMOTE_MESSAGE; //zyg: player emote
8369 qe._Emote = TEXTEMOTE_HELLO; //zyg: NPC emote
8370 title = "Do Quest ?";
8372 else
8374 qe = gossiptext->Options[0].Emotes[0];
8375 title = gossiptext->Options[0].Text_0;
8376 if( &title == NULL )
8377 title = "";
8380 PlayerTalkClass->SendQuestMenu( qe, title, guid );
8384 Quest *Player::GetActiveQuest( uint32 quest_id ) const
8386 StatusMap::const_iterator itr = mQuestStatus.find(quest_id);
8388 return itr != mQuestStatus.end() && itr->second.m_status != QUEST_STATUS_NONE ? itr->second.m_quest : NULL;
8391 Quest* Player::GetNextQuest( uint64 guid, Quest *pQuest )
8393 if( pQuest )
8395 Object *pObject;
8396 Creature *pCreature = ObjectAccessor::Instance().GetCreature(*this, guid);
8397 if( pCreature )
8398 pObject = (Object*)pCreature;
8399 else
8401 GameObject *pGameObject = ObjectAccessor::Instance().GetGameObject(*this, guid);
8402 if( pGameObject )
8403 pObject = (Object*)pGameObject;
8404 else
8405 return NULL;;
8408 uint32 quest = pQuest->GetQuestInfo()->NextQuestId;
8409 for( std::list<Quest*>::iterator i = pObject->mQuests.begin( ); i != pObject->mQuests.end( ); i++ )
8411 Quest *pQuest2 = *i;
8412 if( pQuest2->GetQuestId() == quest )
8414 if ( CanTakeQuest( pQuest2, false ) )
8415 return pQuest2;
8416 else
8417 return NULL;
8421 return NULL;
8424 bool Player::CanSeeStartQuest( uint32 quest_id )
8426 if( quest_id )
8428 if( SatisfyQuestRace( quest_id, false ) && SatisfyQuestClass( quest_id, false ) && SatisfyQuestExclusiveGroup( quest_id, false )
8429 && SatisfyQuestSkill( quest_id, false ) && SatisfyQuestReputation( quest_id, false )
8430 && SatisfyQuestPreviousQuest( quest_id, false ) )
8431 return ( getLevel() + 7 >= objmgr.GetQuestInfo(quest_id)->MinLevel );
8433 return false;
8436 bool Player::CanTakeQuest( Quest *pQuest, bool msg )
8438 if( pQuest)
8440 uint32 quest_id = pQuest->GetQuestId();
8441 return ( SatisfyQuestStatus( quest_id, msg ) && SatisfyQuestExclusiveGroup( quest_id, msg )
8442 && SatisfyQuestRace( quest_id, msg ) && SatisfyQuestLevel( quest_id, msg ) && SatisfyQuestClass( quest_id, msg )
8443 && SatisfyQuestSkill( quest_id, msg ) && SatisfyQuestReputation( quest_id, msg )
8444 && SatisfyQuestPreviousQuest( quest_id, msg ) && SatisfyQuestTimed( quest_id, msg ) );
8446 return false;
8449 bool Player::CanAddQuest( Quest *pQuest, bool msg )
8451 if( pQuest )
8453 if(!GetQuestSlot( 0 ))
8454 return false;
8456 if( !SatisfyQuestLog( msg ) )
8457 return false;
8459 uint32 srcitem = pQuest->GetQuestInfo()->SrcItemId;
8460 if( srcitem > 0 )
8462 uint32 count = pQuest->GetQuestInfo()->SrcItemCount;
8463 uint16 dest;
8464 if( count <= 0 )
8465 count = 1;
8466 uint8 msg = CanStoreNewItem( 0, NULL_SLOT, dest, srcitem, count, false );
8467 if( msg != EQUIP_ERR_OK )
8469 SendEquipError( msg, NULL, NULL );
8470 return false;
8473 return true;
8475 return false;
8478 bool Player::CanCompleteQuest( uint32 quest_id )
8480 if( quest_id )
8482 if( mQuestStatus[quest_id].m_status == QUEST_STATUS_COMPLETE )
8483 return true;
8485 if ( mQuestStatus[quest_id].m_status == QUEST_STATUS_INCOMPLETE )
8487 QuestInfo const* qInfo = objmgr.GetQuestInfo(quest_id);
8489 if ( qInfo->HasSpecialFlag( QUEST_SPECIAL_FLAGS_DELIVER ) )
8491 for(int i = 0; i < QUEST_OBJECTIVES_COUNT; i++)
8493 if( qInfo->ReqItemCount[i]!= 0 && mQuestStatus[quest_id].m_itemcount[i] < qInfo->ReqItemCount[i] )
8494 return false;
8498 if ( qInfo->HasSpecialFlag( QUEST_SPECIAL_FLAGS_KILL_OR_CAST ) )
8500 for(int i = 0; i < QUEST_OBJECTIVES_COUNT; i++)
8502 // skip GO activate objectives
8503 if( qInfo->ReqCreatureOrGOId[i] <= 0 )
8504 continue;
8506 if( qInfo->ReqCreatureOrGOCount[i] != 0 && mQuestStatus[quest_id].m_creatureOrGOcount[i] < qInfo->ReqCreatureOrGOCount[i] )
8507 return false;
8511 if ( qInfo->HasSpecialFlag( QUEST_SPECIAL_FLAGS_EXPLORATION ) && !mQuestStatus[quest_id].m_explored )
8512 return false;
8514 if ( qInfo->HasSpecialFlag( QUEST_SPECIAL_FLAGS_TIMED ) && mQuestStatus[quest_id].m_timer == 0 )
8515 return false;
8517 if ( qInfo->RewOrReqMoney < 0 )
8519 if ( int32(GetMoney()) < -qInfo->RewOrReqMoney )
8520 return false;
8522 return true;
8525 return false;
8528 bool Player::CanRewardQuest( Quest *pQuest, bool msg )
8530 if( pQuest )
8532 // not completed quest (only cheating case, then ignore without message)
8533 if(GetQuestStatus(pQuest->GetQuestId()) != QUEST_STATUS_COMPLETE)
8534 return false;
8536 // rewarded and not repeatable quest (only cheating case, then ignore without message)
8537 if(GetQuestRewardStatus(pQuest->GetQuestId()) && !pQuest->GetQuestInfo()->HasSpecialFlag(QUEST_SPECIAL_FLAGS_REPEATABLE))
8538 return false;
8540 // prevent recive reward with quest items in bank
8541 if ( pQuest->GetQuestInfo()->HasSpecialFlag( QUEST_SPECIAL_FLAGS_DELIVER ) )
8543 for(int i = 0; i < QUEST_OBJECTIVES_COUNT; i++)
8545 if( pQuest->GetQuestInfo()->ReqItemCount[i]!= 0 &&
8546 GetItemCount(pQuest->GetQuestInfo()->ReqItemId[i]) < pQuest->GetQuestInfo()->ReqItemCount[i] )
8548 if(msg)
8549 SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL );
8550 return false;
8555 return true;
8557 return false;
8560 bool Player::CanRewardQuest( Quest *pQuest, uint32 reward, bool msg )
8562 if( pQuest )
8564 // prevent recive reward with quest items in bank or for not completed quest
8565 if(!CanRewardQuest(pQuest,msg))
8566 return false;
8568 uint16 dest;
8569 uint8 msg;
8571 if ( pQuest->m_rewchoiceitemscount > 0 )
8573 if( pQuest->GetQuestInfo()->RewChoiceItemId[reward] )
8575 msg = CanStoreNewItem( 0, NULL_SLOT, dest, pQuest->GetQuestInfo()->RewChoiceItemId[reward], pQuest->GetQuestInfo()->RewChoiceItemCount[reward], false );
8576 if( msg != EQUIP_ERR_OK )
8578 SendEquipError( msg, NULL, NULL );
8579 return false;
8584 if ( pQuest->m_rewitemscount > 0 )
8586 for (int i = 0; i < QUEST_REWARDS_COUNT; i++)
8588 if( pQuest->GetQuestInfo()->RewItemId[i] )
8590 msg = CanStoreNewItem( 0, NULL_SLOT, dest, pQuest->GetQuestInfo()->RewItemId[i], pQuest->GetQuestInfo()->RewItemCount[i], false );
8591 if( msg != EQUIP_ERR_OK )
8593 SendEquipError( msg, NULL, NULL );
8594 return false;
8599 return true;
8601 return false;
8604 void Player::AddQuest( Quest *pQuest )
8606 if( pQuest )
8608 uint16 log_slot = GetQuestSlot( 0 );
8609 assert(log_slot);
8611 uint32 quest_id = pQuest->GetQuestId();
8612 QuestInfo const* qInfo = pQuest->GetQuestInfo();
8614 mQuestStatus[quest_id].m_quest = pQuest;
8615 mQuestStatus[quest_id].m_status = QUEST_STATUS_INCOMPLETE;
8616 mQuestStatus[quest_id].m_rewarded = false;
8617 mQuestStatus[quest_id].m_explored = false;
8619 if ( qInfo->HasSpecialFlag( QUEST_SPECIAL_FLAGS_DELIVER ) )
8621 for(int i = 0; i < QUEST_OBJECTIVES_COUNT; i++)
8622 mQuestStatus[quest_id].m_itemcount[i] = 0;
8624 if ( qInfo->HasSpecialFlag( QUEST_SPECIAL_FLAGS_KILL_OR_CAST ) )
8626 for(int i = 0; i < QUEST_OBJECTIVES_COUNT; i++)
8627 mQuestStatus[quest_id].m_creatureOrGOcount[i] = 0;
8630 GiveQuestSourceItem( quest_id );
8631 AdjustQuestReqItemCount( quest_id );
8633 SetUInt32Value(log_slot + 0, quest_id);
8634 SetUInt32Value(log_slot + 1, 0);
8636 if( qInfo->HasSpecialFlag( QUEST_SPECIAL_FLAGS_TIMED ) )
8638 uint32 limittime = qInfo->LimitTime;
8639 AddTimedQuest( quest_id );
8640 mQuestStatus[quest_id].m_timer = limittime * 1000;
8641 uint32 qtime = static_cast<uint32>(time(NULL)) + limittime;
8642 SetUInt32Value( log_slot + 2, qtime );
8644 else
8646 mQuestStatus[quest_id].m_timer = 0;
8647 SetUInt32Value( log_slot + 2, 0 );
8652 void Player::CompleteQuest( uint32 quest_id )
8654 if( quest_id )
8656 SetQuestStatus( quest_id, QUEST_STATUS_COMPLETE);
8658 uint16 log_slot = GetQuestSlot( quest_id );
8659 if( log_slot )
8661 uint32 state = GetUInt32Value( log_slot + 1 );
8662 state |= 1 << 24;
8663 SetUInt32Value( log_slot + 1, state );
8666 SendQuestComplete( quest_id );
8670 void Player::IncompleteQuest( uint32 quest_id )
8672 if( quest_id )
8674 SetQuestStatus( quest_id, QUEST_STATUS_INCOMPLETE );
8676 uint16 log_slot = GetQuestSlot( quest_id );
8677 if( log_slot )
8679 uint32 state = GetUInt32Value( log_slot + 1 );
8680 state &= ~(1 << 24);
8681 SetUInt32Value( log_slot + 1, state );
8686 void Player::RewardQuest( Quest *pQuest, uint32 reward )
8688 if( pQuest )
8690 uint32 quest_id = pQuest->GetQuestId();
8691 QuestInfo const* qInfo = pQuest->GetQuestInfo();
8693 uint16 dest;
8694 for (int i = 0; i < QUEST_OBJECTIVES_COUNT; i++ )
8696 if ( qInfo->ReqItemId[i] )
8697 RemoveItemCount( qInfo->ReqItemId[i], qInfo->ReqItemCount[i], true);
8700 //if( qInfo->HasSpecialFlag( QUEST_SPECIAL_FLAGS_TIMED ) )
8701 // SetTimedQuest( 0 );
8702 if (find(m_timedquests.begin(), m_timedquests.end(), qInfo->QuestId) != m_timedquests.end())
8703 m_timedquests.remove(qInfo->QuestId);
8705 if ( pQuest->m_rewchoiceitemscount > 0 )
8707 if( qInfo->RewChoiceItemId[reward] )
8709 if( CanStoreNewItem( 0, NULL_SLOT, dest, qInfo->RewChoiceItemId[reward], qInfo->RewChoiceItemCount[reward], false ) == EQUIP_ERR_OK )
8710 StoreNewItem( dest, qInfo->RewChoiceItemId[reward], qInfo->RewChoiceItemCount[reward], true);
8714 if ( pQuest->m_rewitemscount > 0 )
8716 for (int i=0; i < QUEST_REWARDS_COUNT; i++)
8718 if( qInfo->RewItemId[i] )
8720 if( CanStoreNewItem( 0, NULL_SLOT, dest, qInfo->RewItemId[i], qInfo->RewItemCount[i], false ) == EQUIP_ERR_OK )
8721 StoreNewItem( dest, qInfo->RewItemId[i], qInfo->RewItemCount[i], true);
8726 if( qInfo->RewSpell > 0 )
8727 CastSpell( this, qInfo->RewSpell, true);
8729 uint16 log_slot = GetQuestSlot( quest_id );
8730 if( log_slot )
8732 SetUInt32Value(log_slot + 0, 0);
8733 SetUInt32Value(log_slot + 1, 0);
8734 SetUInt32Value(log_slot + 2, 0);
8737 // Not give XP in case already completed once repeatable quest
8738 uint32 XP = mQuestStatus[quest_id].m_completed_once && qInfo->HasSpecialFlag( QUEST_SPECIAL_FLAGS_REPEATABLE )
8739 ? 0 : uint32(pQuest->XPValue( this )*sWorld.getRate(RATE_XP_QUEST));
8741 if ( getLevel() < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL) )
8742 GiveXP( XP , NULL );
8743 else
8744 ModifyMoney( MaNGOS::XP::xp_to_money(XP) );
8746 ModifyMoney( qInfo->RewOrReqMoney );
8748 if ( !qInfo->HasSpecialFlag( QUEST_SPECIAL_FLAGS_REPEATABLE ) )
8749 mQuestStatus[quest_id].m_rewarded = true;
8750 else
8752 SetQuestStatus(quest_id, QUEST_STATUS_NONE);
8755 SendQuestReward( pQuest, XP );
8757 mQuestStatus[quest_id].m_completed_once = true; // in repeated quest case prevent recive XP at second complete
8761 void Player::FailQuest( uint32 quest_id )
8763 if( quest_id )
8765 IncompleteQuest( quest_id );
8767 uint16 log_slot = GetQuestSlot( quest_id );
8768 if( log_slot )
8770 SetUInt32Value( log_slot + 2, 1 );
8772 uint32 state = GetUInt32Value( log_slot + 1 );
8773 state |= 1 << 25;
8774 SetUInt32Value( log_slot + 1, state );
8776 SendQuestFailed( quest_id );
8780 void Player::FailTimedQuest( uint32 quest_id )
8782 if( quest_id )
8784 mQuestStatus[quest_id].m_timer = 0;
8786 IncompleteQuest( quest_id );
8788 uint16 log_slot = GetQuestSlot( quest_id );
8789 if( log_slot )
8791 SetUInt32Value( log_slot + 2, 1 );
8793 uint32 state = GetUInt32Value( log_slot + 1 );
8794 state |= 1 << 25;
8795 SetUInt32Value( log_slot + 1, state );
8797 SendQuestTimerFailed( quest_id );
8801 bool Player::SatisfyQuestClass( uint32 quest_id, bool msg )
8803 QuestInfo const* qInfo = objmgr.GetQuestInfo(quest_id);
8804 if( qInfo )
8806 uint32 reqclasses = qInfo->RequiredClass;
8807 if ( reqclasses == QUEST_CLASS_NONE )
8808 return true;
8809 if( (reqclasses & getClassMask()) == 0 )
8811 if( msg )
8812 SendCanTakeQuestResponse( INVALIDREASON_DONT_HAVE_REQ );
8813 return false;
8815 return true;
8818 return false;
8821 bool Player::SatisfyQuestLevel( uint32 quest_id, bool msg )
8823 QuestInfo const* qInfo = objmgr.GetQuestInfo(quest_id);
8824 if( qInfo )
8826 if( getLevel() < qInfo->MinLevel )
8828 if( msg )
8829 SendCanTakeQuestResponse( INVALIDREASON_DONT_HAVE_REQ );
8830 return false;
8832 return true;
8834 return false;
8837 bool Player::SatisfyQuestLog( bool msg )
8839 uint16 log_slot = GetQuestSlot( 0 );
8840 if( log_slot )
8841 return true;
8842 else
8844 if( msg )
8846 WorldPacket data;
8847 data.Initialize( SMSG_QUESTLOG_FULL );
8848 GetSession()->SendPacket( &data );
8849 sLog.outDebug( "WORLD: Sent QUEST_LOG_FULL_MESSAGE" );
8851 return false;
8855 bool Player::SatisfyQuestPreviousQuest( uint32 quest_id, bool msg )
8857 if( quest_id)
8859 QuestRelations::iterator iter = sPrevQuests.lower_bound(quest_id);
8860 QuestRelations::iterator end = sPrevQuests.upper_bound(quest_id);
8862 // First quest in series
8863 if(iter == end)
8864 return true;
8866 // Have one form prev, quests in rewarded state
8867 for(; iter != end; ++iter )
8869 uint32 prevId = iter->second;
8871 StatusMap::iterator i_prevstatus = mQuestStatus.find( prevId );
8873 if( i_prevstatus != mQuestStatus.end() && i_prevstatus->second.m_rewarded )
8874 return true;
8877 // Have only prev. quests in non-rewarded state
8878 if( msg )
8879 SendCanTakeQuestResponse( INVALIDREASON_DONT_HAVE_REQ );
8881 return false;
8884 bool Player::SatisfyQuestRace( uint32 quest_id, bool msg )
8886 QuestInfo const* qInfo = objmgr.GetQuestInfo(quest_id);
8887 if( qInfo )
8889 uint32 reqraces = qInfo->RequiredRaces;
8890 if ( reqraces == QUEST_RACE_NONE )
8891 return true;
8892 if( (reqraces & getRaceMask()) == 0 )
8894 if( msg )
8895 SendCanTakeQuestResponse( INVALIDREASON_DONT_HAVE_RACE );
8896 return false;
8898 return true;
8900 return false;
8903 bool Player::SatisfyQuestReputation( uint32 quest_id, bool msg )
8905 QuestInfo const* qInfo = objmgr.GetQuestInfo(quest_id);
8906 if( qInfo )
8908 uint32 faction_id = qInfo->RequiredRepFaction;
8909 if(!faction_id)
8910 return true;
8912 return GetReputation(faction_id) >= qInfo->RequiredRepValue;
8914 return false;
8917 bool Player::SatisfyQuestSkill( uint32 quest_id, bool msg )
8919 QuestInfo const* qInfo = objmgr.GetQuestInfo(quest_id);
8920 if( qInfo )
8922 uint32 reqskill = qInfo->RequiredSkill;
8923 if( reqskill == QUEST_TRSKILL_NONE )
8924 return true;
8925 if( GetSkillValue( reqskill ) < qInfo->RequiredSkillValue )
8927 if( msg )
8928 SendCanTakeQuestResponse( INVALIDREASON_DONT_HAVE_REQ );
8929 return false;
8931 return true;
8933 return false;
8936 bool Player::SatisfyQuestStatus( uint32 quest_id, bool msg )
8938 if( quest_id )
8940 StatusMap::iterator itr = mQuestStatus.find( quest_id );
8941 if ( itr != mQuestStatus.end() && itr->second.m_status != QUEST_STATUS_NONE )
8943 if( msg )
8944 SendCanTakeQuestResponse( INVALIDREASON_HAVE_QUEST );
8945 return false;
8947 return true;
8949 return false;
8952 bool Player::SatisfyQuestTimed( uint32 quest_id, bool msg )
8954 QuestInfo const* qInfo = objmgr.GetQuestInfo(quest_id);
8955 if( qInfo )
8957 if ( (find(m_timedquests.begin(), m_timedquests.end(), quest_id) != m_timedquests.end()) && qInfo->HasSpecialFlag(QUEST_SPECIAL_FLAGS_TIMED) )
8959 if( msg )
8960 SendCanTakeQuestResponse( INVALIDREASON_HAVE_TIMED_QUEST );
8961 return false;
8963 return true;
8965 return false;
8968 bool Player::SatisfyQuestExclusiveGroup( uint32 quest_id, bool msg )
8970 QuestInfo const* qInfo = objmgr.GetQuestInfo(quest_id);
8971 if( qInfo )
8973 if(!qInfo->ExclusiveGroup)
8974 return true;
8976 QuestRelations::iterator iter = sExclusiveQuestGroups.lower_bound(qInfo->ExclusiveGroup);
8977 QuestRelations::iterator end = sExclusiveQuestGroups.upper_bound(qInfo->ExclusiveGroup);
8979 assert(iter!=end); // always must be found if qInfo->ExclusiveGroup != 0
8981 for(; iter != end; ++iter)
8983 uint32 exclude_Id = iter->second;
8985 // skip checked quest id, intrested only state of another quests in group
8986 if(exclude_Id == quest_id)
8987 continue;
8989 StatusMap::iterator i_exstatus = mQuestStatus.find( exclude_Id );
8991 // altearnative quest already start or complete
8992 if( i_exstatus != mQuestStatus.end()
8993 && (i_exstatus->second.m_status == QUEST_STATUS_COMPLETE || i_exstatus->second.m_status == QUEST_STATUS_INCOMPLETE) )
8994 return false;
8996 return true;
8998 return false;
9001 bool Player::GiveQuestSourceItem( uint32 quest_id )
9003 QuestInfo const* qInfo = objmgr.GetQuestInfo(quest_id);
9004 if( qInfo )
9007 uint32 srcitem = qInfo->SrcItemId;
9008 if( srcitem > 0 )
9010 uint16 dest;
9011 uint32 count = qInfo->SrcItemCount;
9012 if( count <= 0 )
9013 count = 1;
9014 uint8 msg = CanStoreNewItem( 0, NULL_SLOT, dest, srcitem, count, false );
9015 if( msg == EQUIP_ERR_OK )
9017 StoreNewItem(dest, srcitem, count, true);
9018 return true;
9020 else
9021 SendEquipError( msg, NULL, NULL );
9022 return false;
9025 return true;
9028 void Player::TakeQuestSourceItem( uint32 quest_id )
9030 QuestInfo const* qInfo = objmgr.GetQuestInfo(quest_id);
9031 if( qInfo )
9033 uint32 srcitem = qInfo->SrcItemId;
9034 if( srcitem > 0 )
9036 uint32 count = qInfo->SrcItemCount;
9037 if( count <= 0 )
9038 count = 1;
9039 DestroyItemCount(srcitem, count, true);
9044 bool Player::GetQuestRewardStatus( uint32 quest_id )
9046 if( quest_id )
9048 StatusMap::iterator itr = mQuestStatus.find( quest_id );
9049 if ( itr != mQuestStatus.end() && itr->second.m_status != QUEST_STATUS_NONE )
9050 return mQuestStatus[quest_id ].m_rewarded;
9052 return false;
9054 return false;
9057 uint32 Player::GetQuestStatus( uint32 quest_id )
9059 if( quest_id )
9061 if ( mQuestStatus.find( quest_id ) != mQuestStatus.end() )
9062 return mQuestStatus[quest_id].m_status;
9064 return QUEST_STATUS_NONE;
9067 void Player::SetQuestStatus( uint32 quest_id, QuestStatus status )
9069 QuestInfo const* qInfo = objmgr.GetQuestInfo(quest_id);
9070 if( qInfo )
9072 if ((status == QUEST_STATUS_NONE) || (status == QUEST_STATUS_INCOMPLETE))
9074 if( qInfo->HasSpecialFlag( QUEST_SPECIAL_FLAGS_TIMED ) )
9075 if (find(m_timedquests.begin(), m_timedquests.end(), quest_id) != m_timedquests.end())
9076 m_timedquests.remove(qInfo->QuestId);
9079 mQuestStatus[quest_id].m_status = status;
9083 void Player::AdjustQuestReqItemCount( uint32 quest_id )
9085 QuestInfo const* qInfo = objmgr.GetQuestInfo(quest_id);
9086 if( qInfo )
9088 if ( qInfo->HasSpecialFlag( QUEST_SPECIAL_FLAGS_DELIVER ) )
9090 for(int i = 0; i < QUEST_OBJECTIVES_COUNT; i++)
9092 uint32 reqitemcount = qInfo->ReqItemCount[i];
9093 if( reqitemcount != 0 )
9095 uint32 curitemcount = GetItemCount(qInfo->ReqItemId[i]) + GetBankItemCount(qInfo->ReqItemId[i]);
9096 mQuestStatus[quest_id].m_itemcount[i] = min(curitemcount, reqitemcount);
9103 uint16 Player::GetQuestSlot( uint32 quest_id )
9105 for ( uint16 i = 0; i < MAX_QUEST_LOG_SIZE; i++ )
9107 if ( GetUInt32Value(PLAYER_QUEST_LOG_1_1 + 3*i) == quest_id )
9108 return PLAYER_QUEST_LOG_1_1 + 3*i;
9110 return 0;
9113 void Player::AreaExplored( uint32 questId )
9115 if( questId )
9117 uint16 log_slot = GetQuestSlot( questId );
9118 if( log_slot )
9120 mQuestStatus[questId].m_explored = true;
9122 if( CanCompleteQuest( questId ) )
9123 CompleteQuest( questId );
9127 void Player::ItemAdded( uint32 entry, uint32 count )
9129 uint32 quest;
9130 uint32 reqitem;
9131 uint32 reqitemcount;
9132 uint32 curitemcount;
9133 uint32 additemcount;
9134 for( int i = 0; i < MAX_QUEST_LOG_SIZE; i++ )
9136 quest = GetUInt32Value(PLAYER_QUEST_LOG_1_1 + 3*i);
9137 if ( quest != 0 && mQuestStatus[quest].m_status == QUEST_STATUS_INCOMPLETE )
9139 QuestInfo const *qInfo = objmgr.GetQuestInfo(quest);
9140 if( qInfo && qInfo->HasSpecialFlag( QUEST_SPECIAL_FLAGS_DELIVER ) )
9142 for (int j = 0; j < QUEST_OBJECTIVES_COUNT; j++)
9144 reqitem = qInfo->ReqItemId[j];
9145 if ( reqitem == entry )
9147 reqitemcount = qInfo->ReqItemCount[j];
9148 curitemcount = mQuestStatus[quest].m_itemcount[j];
9149 if ( curitemcount < reqitemcount )
9151 additemcount = ( curitemcount + count <= reqitemcount ? count : reqitemcount - curitemcount);
9152 mQuestStatus[quest].m_itemcount[j] += additemcount;
9153 SendQuestUpdateAddItem( quest, j, additemcount );
9155 if ( CanCompleteQuest( quest ) )
9156 CompleteQuest( quest );
9157 return;
9165 void Player::ItemRemoved( uint32 entry, uint32 count )
9167 uint32 quest;
9168 uint32 reqitem;
9169 uint32 reqitemcount;
9170 uint32 curitemcount;
9171 uint32 remitemcount;
9172 for( int i = 0; i < MAX_QUEST_LOG_SIZE; i++ )
9174 quest = GetUInt32Value(PLAYER_QUEST_LOG_1_1 + 3*i);
9175 QuestInfo const* qInfo = objmgr.GetQuestInfo(quest);
9176 if ( qInfo )
9178 if( qInfo->HasSpecialFlag( QUEST_SPECIAL_FLAGS_DELIVER ) )
9180 for (int j = 0; j < QUEST_OBJECTIVES_COUNT; j++)
9182 reqitem = qInfo->ReqItemId[j];
9183 if ( reqitem == entry )
9185 reqitemcount = qInfo->ReqItemCount[j];
9186 if( mQuestStatus[quest].m_status != QUEST_STATUS_COMPLETE )
9187 curitemcount = mQuestStatus[quest].m_itemcount[j];
9188 else
9189 curitemcount = GetItemCount(entry) + GetBankItemCount(entry);
9190 if ( curitemcount - count < reqitemcount )
9192 remitemcount = ( curitemcount <= reqitemcount ? count : count + reqitemcount - curitemcount);
9193 mQuestStatus[quest].m_itemcount[j] = curitemcount - remitemcount;
9194 IncompleteQuest( quest );
9196 return;
9204 void Player::KilledMonster( uint32 entry, uint64 guid )
9206 uint32 quest;
9207 uint32 reqkill;
9208 uint32 reqkillcount;
9209 uint32 curkillcount;
9210 uint32 addkillcount = 1;
9211 for( int i = 0; i < MAX_QUEST_LOG_SIZE; i++ )
9213 quest = GetUInt32Value(PLAYER_QUEST_LOG_1_1 + 3*i);
9215 if(!quest)
9216 continue;
9218 QuestInfo const* qInfo = objmgr.GetQuestInfo(quest);
9219 if ( qInfo && mQuestStatus[quest].m_status == QUEST_STATUS_INCOMPLETE )
9221 if( qInfo->HasSpecialFlag( QUEST_SPECIAL_FLAGS_KILL_OR_CAST ) )
9223 for (int j = 0; j < QUEST_OBJECTIVES_COUNT; j++)
9225 // skip GO activate objective or none
9226 if(qInfo->ReqCreatureOrGOId[j] <=0)
9227 continue;
9229 // skip Cast at creature objective
9230 if(qInfo->ReqSpell[j] !=0 )
9231 continue;
9233 reqkill = qInfo->ReqCreatureOrGOId[j];
9235 if ( reqkill == entry )
9237 reqkillcount = qInfo->ReqCreatureOrGOCount[j];
9238 curkillcount = mQuestStatus[quest].m_creatureOrGOcount[j];
9239 if ( curkillcount < reqkillcount )
9241 mQuestStatus[quest].m_creatureOrGOcount[j] = curkillcount + addkillcount;
9242 SendQuestUpdateAddCreature( quest, guid, j, curkillcount, addkillcount);
9244 if ( CanCompleteQuest( quest ) )
9245 CompleteQuest( quest );
9246 return;
9254 void Player::CastedCreatureOrGO( uint32 entry, uint64 guid, uint32 spell_id )
9256 uint32 quest;
9257 uint32 reqCastCount;
9258 uint32 curCastCount;
9259 uint32 addCastCount = 1;
9260 for( int i = 0; i < MAX_QUEST_LOG_SIZE; i++ )
9262 quest = GetUInt32Value(PLAYER_QUEST_LOG_1_1 + 3*i);
9264 if(!quest)
9265 continue;
9267 QuestInfo const* qInfo = objmgr.GetQuestInfo(quest);
9268 if ( qInfo && mQuestStatus[quest].m_status == QUEST_STATUS_INCOMPLETE )
9270 if( qInfo->HasSpecialFlag( QUEST_SPECIAL_FLAGS_KILL_OR_CAST ) )
9272 for (int j = 0; j < QUEST_OBJECTIVES_COUNT; j++)
9274 // skip kill creature objective (0) or wrong spell casts
9275 if(qInfo->ReqSpell[j] != spell_id )
9276 continue;
9278 uint32 reqTarget = 0;
9279 // GO activate objective
9280 if(qInfo->ReqCreatureOrGOId[j] < 0)
9282 reqTarget = - qInfo->ReqCreatureOrGOId[j];
9283 assert(sGOStorage.LookupEntry<GameObject>(reqTarget));
9285 // creature acivate objectives
9286 else if(qInfo->ReqCreatureOrGOId[j] > 0)
9288 reqTarget = qInfo->ReqCreatureOrGOId[j];
9289 assert(sCreatureStorage.LookupEntry<Creature>(reqTarget));
9291 // other not creature/GO related obejctives
9292 else
9293 continue;
9295 if ( reqTarget == entry )
9297 reqCastCount = qInfo->ReqCreatureOrGOCount[j];
9298 curCastCount = mQuestStatus[quest].m_creatureOrGOcount[j];
9299 if ( curCastCount < reqCastCount )
9301 mQuestStatus[quest].m_creatureOrGOcount[j] = curCastCount + addCastCount;
9302 SendQuestUpdateAddCreature( quest, guid, j, curCastCount, addCastCount);
9304 if ( CanCompleteQuest( quest ) )
9305 CompleteQuest( quest );
9306 return;
9314 void Player::MoneyChanged( uint32 count )
9316 uint32 quest;
9317 for( int i = 0; i < MAX_QUEST_LOG_SIZE; i++ )
9319 quest = GetUInt32Value(PLAYER_QUEST_LOG_1_1 + 3*i);
9320 if ( quest != 0 )
9322 QuestInfo const *qInfo = objmgr.GetQuestInfo(quest);
9323 if( qInfo && qInfo->RewOrReqMoney < 0 )
9325 if( mQuestStatus[quest].m_status == QUEST_STATUS_INCOMPLETE )
9327 if(int32(count) >= -qInfo->RewOrReqMoney)
9329 if ( CanCompleteQuest( quest ) )
9330 CompleteQuest( quest );
9333 else if( mQuestStatus[quest].m_status == QUEST_STATUS_COMPLETE )
9335 if(int32(count) < -qInfo->RewOrReqMoney)
9336 IncompleteQuest( quest );
9343 bool Player::HaveQuestForItem( uint32 itemid )
9345 for( StatusMap::iterator i = mQuestStatus.begin( ); i != mQuestStatus.end( ); ++ i )
9347 quest_status qs=i->second;
9349 if (qs.m_status == QUEST_STATUS_INCOMPLETE)
9351 if (!qs.m_quest) continue;
9352 QuestInfo const* qinfo = qs.m_quest->GetQuestInfo();
9354 // There should be no mixed ReqItem/ReqSource drop
9355 // This part for ReqItem drop
9356 for (int j = 0; j < QUEST_OBJECTIVES_COUNT; j++)
9358 if(itemid == qinfo->ReqItemId[j] && qs.m_itemcount[j] < qinfo->ReqItemCount[j] )
9359 return true;
9361 // This part - for ReqSource
9362 for (int j = 0; j < QUEST_SOURCE_ITEM_IDS_COUNT; j++)
9364 // examined item is a source item
9365 if (qinfo->ReqSourceId[j] == itemid && qinfo->ReqSourceRef[j] > 0 && qinfo->ReqSourceRef[j] <= QUEST_OBJECTIVES_COUNT)
9367 uint32 idx = qinfo->ReqSourceRef[j]-1;
9368 // total count of created ReqItems and SourceItems is less than ReqItemCount
9369 if(qinfo->ReqItemId[idx] != 0 &&
9370 qs.m_itemcount[idx] + GetItemCount(itemid)+ GetBankItemCount(itemid) < qinfo->ReqItemCount[idx])
9371 return true;
9373 // total count of casted ReqCreatureOrGOs and SourceItems is less than ReqCreatureOrGOCount
9374 if (qinfo->ReqCreatureOrGOId[idx] != 0 &&
9375 qs.m_creatureOrGOcount[idx] + GetItemCount(itemid)+ GetBankItemCount(itemid) < qinfo->ReqCreatureOrGOCount[idx])
9376 return true;
9381 return false;
9384 void Player::SendQuestComplete( uint32 quest_id )
9386 if( quest_id )
9388 WorldPacket data;
9389 data.Initialize( SMSG_QUESTUPDATE_COMPLETE );
9390 data << quest_id;
9391 GetSession()->SendPacket( &data );
9392 sLog.outDebug( "WORLD: Sent SMSG_QUESTUPDATE_COMPLETE quest = %u", quest_id );
9396 void Player::SendQuestReward( Quest *pQuest, uint32 XP )
9398 if( pQuest )
9400 uint32 quest = pQuest->GetQuestInfo()->QuestId;
9401 sLog.outDebug( "WORLD: Sent SMSG_QUESTGIVER_QUEST_COMPLETE quest = %u", quest );
9402 WorldPacket data;
9403 data.Initialize( SMSG_QUESTGIVER_QUEST_COMPLETE );
9404 data << quest;
9405 data << uint32(0x03);
9407 if ( getLevel() < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL) )
9409 data << XP;
9410 data << uint32(pQuest->GetQuestInfo()->RewOrReqMoney);
9412 else
9414 data << uint32(0);
9415 data << uint32(pQuest->GetQuestInfo()->RewOrReqMoney + XP);
9417 data << uint32( pQuest->m_rewitemscount );
9419 for (int i = 0; i < QUEST_REWARDS_COUNT; i++)
9421 if ( pQuest->GetQuestInfo()->RewItemId[i] > 0 )
9422 data << pQuest->GetQuestInfo()->RewItemId[i] << pQuest->GetQuestInfo()->RewItemCount[i];
9425 GetSession()->SendPacket( &data );
9429 void Player::SendQuestFailed( uint32 quest_id )
9431 if( quest_id )
9433 WorldPacket data;
9434 data.Initialize( SMSG_QUESTGIVER_QUEST_FAILED );
9435 data << quest_id;
9436 GetSession()->SendPacket( &data );
9437 sLog.outDebug("WORLD: Sent SMSG_QUESTGIVER_QUEST_FAILED");
9441 void Player::SendQuestTimerFailed( uint32 quest_id )
9443 if( quest_id )
9445 WorldPacket data;
9446 data.Initialize( SMSG_QUESTUPDATE_FAILEDTIMER );
9447 data << quest_id;
9448 GetSession()->SendPacket( &data );
9449 sLog.outDebug("WORLD: Sent SMSG_QUESTUPDATE_FAILEDTIMER");
9453 void Player::SendCanTakeQuestResponse( uint32 msg )
9455 WorldPacket data;
9456 data.Initialize( SMSG_QUESTGIVER_QUEST_INVALID );
9457 data << msg;
9458 GetSession()->SendPacket( &data );
9459 sLog.outDebug("WORLD: Sent SMSG_QUESTGIVER_QUEST_INVALID");
9462 void Player::SendPushToPartyResponse( Player *pPlayer, uint32 msg )
9464 if( pPlayer )
9466 WorldPacket data;
9467 data.Initialize( MSG_QUEST_PUSH_RESULT );
9468 data << pPlayer->GetGUID();
9469 data << msg;
9470 data << uint8(0);
9471 GetSession()->SendPacket( &data );
9472 sLog.outDebug("WORLD: Sent MSG_QUEST_PUSH_RESULT");
9476 void Player::SendQuestUpdateAddItem( uint32 quest_id, uint32 item_idx, uint32 count )
9478 if( quest_id )
9480 WorldPacket data;
9481 data.Initialize( SMSG_QUESTUPDATE_ADD_ITEM );
9482 sLog.outDebug( "WORLD: Sent SMSG_QUESTUPDATE_ADD_ITEM" );
9483 data << objmgr.GetQuestInfo(quest_id)->ReqItemId[item_idx];
9484 data << count;
9485 GetSession()->SendPacket( &data );
9489 void Player::SendQuestUpdateAddCreature( uint32 quest_id, uint64 guid, uint32 creature_idx, uint32 old_count, uint32 add_count )
9491 assert(old_count + add_count < 64 && "mob/GO count store in 6 bits 2^6 = 64 (0..63)");
9493 QuestInfo const* qInfo = objmgr.GetQuestInfo(quest_id);
9494 if( qInfo )
9496 WorldPacket data;
9497 data.Initialize( SMSG_QUESTUPDATE_ADD_KILL );
9498 sLog.outDebug( "WORLD: Sent SMSG_QUESTUPDATE_ADD_KILL" );
9499 data << qInfo->QuestId;
9500 data << uint32(qInfo->ReqCreatureOrGOId[ creature_idx ]);
9501 data << old_count + add_count;
9502 data << qInfo->ReqCreatureOrGOCount[ creature_idx ];
9503 data << guid;
9504 GetSession()->SendPacket(&data);
9506 uint16 log_slot = GetQuestSlot( quest_id );
9507 uint32 kills = GetUInt32Value( log_slot + 1 );
9508 kills = kills + (add_count << ( 6 * creature_idx ));
9509 SetUInt32Value( log_slot + 1, kills );
9513 /*********************************************************/
9514 /*** LOAD SYSTEM ***/
9515 /*********************************************************/
9517 bool Player::MinimalLoadFromDB( uint32 guid )
9519 QueryResult *result = sDatabase.PQuery("SELECT `data`,`name`,`position_x`,`position_y`,`position_z`,`map` FROM `character` WHERE `guid` = '%u'",guid);
9520 if(!result)
9521 return false;
9523 Field *fields = result->Fetch();
9525 if(!LoadValues( fields[0].GetString()))
9527 sLog.outError("ERROR: Player #%d have broken data in `data` field. Can't be loaded.",GUID_LOPART(guid));
9528 delete result;
9529 return false;
9532 m_name = fields[1].GetCppString();
9533 m_positionX = fields[2].GetFloat();
9534 m_positionY = fields[3].GetFloat();
9535 m_positionZ = fields[4].GetFloat();
9536 m_mapId = fields[5].GetUInt32();
9538 for (int i = 0; i < MAX_QUEST_LOG_SIZE; i++)
9539 m_items[i] = NULL;
9541 delete result;
9542 return true;
9545 bool Player::LoadPositionFromDB(uint32& mapid, float& x,float& y,float& z,float& o, uint64 guid)
9547 QueryResult *result = sDatabase.PQuery("SELECT `position_x`,`position_y`,`position_z`,`orientation`,`map` FROM `character` WHERE `guid` = '%u'",guid);
9548 if(!result)
9549 return false;
9551 Field *fields = result->Fetch();
9553 x = fields[0].GetFloat();
9554 y = fields[1].GetFloat();
9555 z = fields[2].GetFloat();
9556 o = fields[3].GetFloat();
9557 mapid = fields[4].GetUInt32();
9559 delete result;
9560 return true;
9563 bool Player::LoadValuesArrayFromDB(vector<string> & data, uint64 guid)
9565 std::ostringstream ss;
9566 ss<<"SELECT `data` FROM `character` WHERE `guid`='"<<guid<<"'";
9567 QueryResult *result = sDatabase.Query( ss.str().c_str() );
9568 if( !result )
9569 return false;
9571 Field *fields = result->Fetch();
9573 data = StrSplit(fields[0].GetString(), " ");
9575 delete result;
9577 return true;
9580 uint32 Player::GetUInt32ValueFromArray(vector<string> const& data, uint16 index)
9582 return (uint32)atoi(data[index].c_str());
9585 float Player::GetFloatValueFromArray(vector<string> const& data, uint16 index)
9587 float result;
9588 uint32 temp = Player::GetUInt32ValueFromArray(data,index);
9589 memcpy(&result, &temp, sizeof(result));
9591 return result;
9594 uint32 Player::GetUInt32ValueFromDB(uint16 index, uint64 guid)
9596 vector<string> data;
9597 if(!LoadValuesArrayFromDB(data,guid))
9598 return 0;
9600 return GetUInt32ValueFromArray(data,index);
9603 float Player::GetFloatValueFromDB(uint16 index, uint64 guid)
9605 float result;
9606 uint32 temp = Player::GetUInt32ValueFromDB(index, guid);
9607 memcpy(&result, &temp, sizeof(result));
9609 return result;
9612 bool Player::LoadFromDB( uint32 guid )
9614 // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
9615 QueryResult *result = sDatabase.PQuery("SELECT `guid`,`realm`,`account`,`data`,`name`,`race`,`class`,`position_x`,`position_y`,`position_z`,`map`,`orientation`,`taximask`,`online`,`highest_rank`,`standing`,`rating`,`cinematic`,`totaltime`,`leveltime`,`rest_bonus`,`logout_time`,`is_logout_resting`,`resettalents_cost`,`resettalents_time` FROM `character` WHERE `guid` = '%u'",guid);
9617 if(!result)
9619 sLog.outError("ERROR: Player (GUID: %u) not found in table `character`, can't load. ",guid);
9620 return false;
9623 Field *fields = result->Fetch();
9625 Object::_Create( guid, HIGHGUID_PLAYER );
9627 if(!LoadValues( fields[3].GetString()))
9629 sLog.outError("ERROR: Player #%d have broken data in `data` field. Can't be loaded.",GUID_LOPART(guid));
9630 delete result;
9631 return false;
9634 // cleanup inventory related item value fields (its will be filled correctly in _LoadInventory)
9635 for(uint8 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; ++slot)
9637 SetUInt64Value( (uint16)(PLAYER_FIELD_INV_SLOT_HEAD + (slot * 2) ), 0 );
9639 int VisibleBase = PLAYER_VISIBLE_ITEM_1_0 + (slot * 12);
9640 for(int i = 0; i < 9; ++i )
9641 SetUInt32Value(VisibleBase + i, 0);
9643 if (m_items[slot])
9645 delete m_items[slot];
9646 m_items[slot] = NULL;
9650 m_drunk = GetUInt32Value(PLAYER_BYTES_3) & 0xFFFE;
9652 m_name = fields[4].GetCppString();
9654 sLog.outDebug("Load Basic value of player %s is: ", m_name.c_str());
9655 outDebugValues();
9657 m_race = fields[5].GetUInt8();
9658 //Need to call it to initialize m_team (m_team can be calculated from m_race)
9659 //Other way is to saves m_team into characters table.
9660 setFactionForRace(m_race);
9661 SetCharm(0);
9663 m_class = fields[6].GetUInt8();
9665 info = objmgr.GetPlayerCreateInfo(m_race, m_class);
9666 if(!info)
9668 sLog.outError("Player have incorrect race/class pair. Can't be loaded.");
9669 delete result;
9670 return false;
9673 m_createStats[STAT_AGILITY] = (float)info->agility;
9674 m_createStats[STAT_INTELLECT] = (float)info->intellect;
9675 m_createStats[STAT_SPIRIT] = (float)info->spirit;
9676 m_createStats[STAT_STAMINA] = (float)info->stamina;
9677 m_createStats[STAT_STRENGTH] = (float)info->strength;
9679 m_positionX = fields[7].GetFloat();
9680 m_positionY = fields[8].GetFloat();
9681 m_positionZ = fields[9].GetFloat();
9682 m_mapId = fields[10].GetUInt32();
9683 m_orientation = fields[11].GetFloat();
9685 // since last logout (in ms)
9686 uint32 time_diff = (time(NULL) - fields[21].GetUInt32()) * 1000;
9688 rest_bonus = fields[20].GetFloat();
9689 //speed collect rest bonus in offline, in logaut, far from tavern, city (section/in hour)
9690 float bubble=0.0416; //100% Blizzlike
9691 //speed collect rest bonus in offline, in logaut, far from tavern, city (section/in hour)
9692 float bubble1=0.083; //100% Blizzlike
9693 if((int)fields[22].GetUInt32()==1&&(int)fields[21].GetUInt32()>0)
9694 SetRestBonus( GetRestBonus() + (time(NULL)-(int)fields[21].GetUInt32())*0.0142108*bubble1);
9695 if((int)fields[22].GetUInt32()==0&&(int)fields[21].GetUInt32()>0)
9696 SetRestBonus( GetRestBonus() + (time(NULL)-(int)fields[21].GetUInt32())*0.0142108*bubble);
9698 if(!IsPositionValid())
9700 sLog.outError("ERROR: Player (guidlow %d) have invalid coordinates (X: %d Y: ^%d). Teleport to default race/class locations.",guid,m_positionX,m_positionY);
9702 m_mapId = info->mapId;
9703 m_positionX = info->positionX;
9704 m_positionY = info->positionY;
9705 m_positionZ = info->positionZ;
9708 m_highest_rank = fields[14].GetUInt32();
9709 m_standing = fields[15].GetUInt32();
9710 m_rating = fields[16].GetFloat();
9711 m_cinematic = fields[17].GetUInt32();
9712 m_Played_time[0]= fields[18].GetUInt32();
9713 m_Played_time[1]= fields[19].GetUInt32();
9715 m_resetTalentsCost = fields[23].GetUInt32();
9716 m_resetTalentsTime = fields[24].GetUInt64();
9718 if( HasFlag(PLAYER_FLAGS, 8) )
9719 SetUInt32Value(PLAYER_FLAGS, 0);
9721 if( HasFlag(PLAYER_FLAGS, 0x11) )
9722 m_deathState = DEAD;
9724 _LoadTaxiMask( fields[12].GetString() );
9726 delete result;
9728 // make sure the unit is considered out of combat for proper loading
9729 RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT);
9731 //mails are loaded only when needed ;-) - when player in game click on mailbox.
9732 //_LoadMail();
9734 _LoadAuras(time_diff);
9736 _LoadSpells(time_diff);
9738 _LoadQuestStatus();
9740 _LoadTutorials();
9742 _LoadInventory(time_diff);
9744 _LoadActions();
9746 _LoadReputation();
9748 // Skip _ApplyAllAuraMods(); -- applied in _LoadAuras by AddAura calls at aura load
9749 // Skip _ApplyAllItemMods(); -- already applied in _LoadInventory()
9751 sLog.outDebug("The value of player %s after load item and aura is: ", m_name.c_str());
9752 outDebugValues();
9754 return true;
9757 void Player::_LoadActions()
9760 m_actions.clear();
9762 QueryResult *result = sDatabase.PQuery("SELECT `button`,`action`,`type`,`misc` FROM `character_action` WHERE `guid` = '%u' ORDER BY `button`",GetGUIDLow());
9764 if(result)
9768 Field *fields = result->Fetch();
9770 addAction(fields[0].GetUInt8(), fields[1].GetUInt16(), fields[2].GetUInt8(), fields[3].GetUInt8());
9772 while( result->NextRow() );
9774 delete result;
9778 void Player::_LoadAuras(uint32 timediff)
9780 m_Auras.clear();
9781 for (int i = 0; i < TOTAL_AURAS; i++)
9782 m_modAuras[i].clear();
9784 for(uint8 i = 0; i < 48; i++)
9785 SetUInt32Value((uint16)(UNIT_FIELD_AURA + i), 0);
9786 for(uint8 j = 0; j < 6; j++)
9787 SetUInt32Value((uint16)(UNIT_FIELD_AURAFLAGS + j), 0);
9789 QueryResult *result = sDatabase.PQuery("SELECT `spell`,`effect_index`,`remaintime` FROM `character_aura` WHERE `guid` = '%u'",GetGUIDLow());
9791 if(result)
9795 Field *fields = result->Fetch();
9796 uint32 spellid = fields[0].GetUInt32();
9797 uint32 effindex = fields[1].GetUInt32();
9798 int32 remaintime = (int32)fields[2].GetUInt32();
9800 SpellEntry* spellproto = sSpellStore.LookupEntry(spellid);
9801 if(!spellproto)
9803 sLog.outError("Unknown aura (spellid %u, effindex %u), ignore.",spellid,effindex);
9804 continue;
9807 // negative effects should continue counting down after logout
9808 if (remaintime != -1 && !IsPositiveEffect(spellid, effindex))
9810 remaintime -= timediff;
9811 if(remaintime <= 0) continue;
9814 // FIXME: real caster not stored in DB currently
9816 Aura* aura = new Aura(spellproto, effindex, this, this/*caster*/);
9817 aura->SetAuraDuration(remaintime);
9818 AddAura(aura);
9820 while( result->NextRow() );
9822 delete result;
9825 if(m_class == WARRIOR)
9826 CastSpell(this,SPELL_PASSIVE_BATTLE_STANCE,true);
9829 void Player::LoadCorpse()
9831 if(Corpse* corpse = GetCorpse())
9833 if(isAlive())
9834 corpse->ConvertCorpseToBones();
9835 else
9836 corpse->UpdateForPlayer(this,true);
9838 else
9840 //Prevent Dead Player login without corpse
9841 if(!isAlive())
9842 ResurrectPlayer();
9846 void Player::_LoadInventory(uint32 timediff)
9848 QueryResult *result = sDatabase.PQuery("SELECT `slot`,`item`,`item_template` FROM `character_inventory` WHERE `guid` = '%u' AND `bag` = '%u' ORDER BY `slot`",GetGUIDLow(),INVENTORY_SLOT_BAG_0);
9850 uint16 dest;
9851 if (result)
9855 Field *fields = result->Fetch();
9856 uint8 slot = fields[0].GetUInt8();
9857 uint32 item_guid = fields[1].GetUInt32();
9858 uint32 item_id = fields[2].GetUInt32();
9860 ItemPrototype const * proto = objmgr.GetItemPrototype(item_id);
9862 if(!proto)
9864 sLog.outError( "Player::_LoadInventory: Player %s have unknown item (id: #%u) in inventory, skipped.", GetName(),item_id );
9865 continue;
9868 Item *item = NewItemOrBag(proto);
9869 item->SetSlot(slot);
9871 if(!item->LoadFromDB(item_guid, GetGUID()))
9873 delete item;
9874 continue;
9877 dest = ((INVENTORY_SLOT_BAG_0 << 8) | slot);
9878 if( IsInventoryPos( dest ) )
9880 if( CanStoreItem( INVENTORY_SLOT_BAG_0, slot, dest, item, false ) == EQUIP_ERR_OK )
9881 StoreItem(dest, item, true);
9882 else
9883 delete item;
9885 else if( IsEquipmentPos( dest ) )
9887 if( CanEquipItem( slot, dest, item, false, false ) == EQUIP_ERR_OK )
9888 QuickEquipItem(dest, item);
9889 else
9890 delete item;
9892 else if( IsBankPos( dest ) )
9894 if( CanBankItem( INVENTORY_SLOT_BAG_0, slot, dest, item, false ) == EQUIP_ERR_OK )
9895 BankItem(dest, item, true);
9896 else
9897 delete item;
9899 } while (result->NextRow());
9901 delete result;
9903 if(isAlive())
9904 _ApplyAllItemMods();
9907 // load mailed items which should receive current player
9908 void Player::_LoadMailedItems()
9910 QueryResult *result = sDatabase.PQuery( "SELECT `item` FROM `mail` WHERE `receiver` = '%u' AND `item` > 0", GetGUIDLow());
9912 if( !result )
9913 return;
9915 Field *fields;
9918 fields = result->Fetch();
9919 Item* item = new Item;
9920 if(!item->LoadFromDB(fields[0].GetUInt32(), 0))
9922 delete item;
9923 continue;
9925 AddMItem(item);
9927 while( result->NextRow() );
9929 delete result;
9932 void Player::_LoadMail()
9934 //delete old mails, and if old mail has item so delete it too
9935 time_t base = time(NULL);
9937 //FIXME: mails with COD will not be returned, but deleted.
9939 //delete old mails:
9940 sDatabase.PExecute("DELETE a FROM item_instance AS a INNER JOIN mail AS ab ON a.guid=ab.item WHERE ab.time < '" I64FMTD "' AND `receiver` = '%u'", (uint64)base, GetGUIDLow());
9941 sDatabase.PExecute("DELETE FROM `mail` WHERE `time` < '" I64FMTD "' AND `receiver` = '%u'", (uint64)base, GetGUIDLow());
9943 _LoadMailedItems();
9945 m_mail.clear();
9947 QueryResult *result = sDatabase.PQuery("SELECT `id`,`sender`,`receiver`,`subject`,`body`,`item`,`time`,`money`,`cod`,`checked` FROM `mail` WHERE `receiver` = '%u'",GetGUIDLow());
9949 if(result)
9953 Field *fields = result->Fetch();
9954 Mail *be = new Mail;
9955 be->messageID = fields[0].GetUInt32();
9956 be->sender = fields[1].GetUInt32();
9957 be->receiver = fields[2].GetUInt32();
9958 be->subject = fields[3].GetCppString();
9959 be->body = fields[4].GetCppString();
9960 be->item = fields[5].GetUInt32();
9961 be->time = fields[6].GetUInt32();
9962 be->money = fields[7].GetUInt32();
9963 be->COD = fields[8].GetUInt32();
9964 be->checked = fields[9].GetUInt32();
9965 m_mail.push_back(be);
9967 while( result->NextRow() );
9969 delete result;
9972 m_mailsLoaded = true;
9975 void Player::LoadPet()
9977 uint64 pet_guid = GetPetGUID();
9978 if(pet_guid)
9980 Creature* in_pet = ObjectAccessor::Instance().GetCreature(*this, pet_guid);
9981 if(in_pet)
9982 return;
9983 Pet *pet = new Pet();
9984 pet->LoadPetFromDB(this);
9988 void Player::_LoadQuestStatus()
9990 mQuestStatus.clear();
9992 QueryResult *result = sDatabase.PQuery("SELECT `quest`,`status`,`rewarded`,`explored`,`completed_once`,`timer`,`mobcount1`,`mobcount2`,`mobcount3`,`mobcount4`,`itemcount1`,`itemcount2`,`itemcount3`,`itemcount4` FROM `character_queststatus` WHERE `guid` = '%u'", GetGUIDLow());
9994 if(result)
9998 Field *fields = result->Fetch();
10000 uint32 quest_id = fields[0].GetUInt32();
10001 Quest* pQuest = objmgr.NewQuest(quest_id);
10002 if( pQuest )
10004 mQuestStatus[quest_id].m_quest = pQuest;
10006 uint32 qstatus = fields[1].GetUInt32();
10007 if(qstatus < MAX_QUEST_STATUS)
10008 mQuestStatus[quest_id].m_status = QuestStatus(qstatus);
10009 else
10011 mQuestStatus[quest_id].m_status = QUEST_STATUS_NONE;
10012 sLog.outError("Player %s have invalid quest %d status (%d), replaced by QUEST_STATUS_NONE(0).",GetName(),quest_id,qstatus);
10015 mQuestStatus[quest_id].m_rewarded = ( fields[2].GetUInt8() > 0 );
10016 mQuestStatus[quest_id].m_explored = ( fields[3].GetUInt8() > 0 );
10017 mQuestStatus[quest_id].m_completed_once = ( fields[4].GetUInt8() > 0 );
10019 if( objmgr.GetQuestInfo(quest_id)->HasSpecialFlag( QUEST_SPECIAL_FLAGS_TIMED ) && !mQuestStatus[quest_id].m_rewarded )
10020 AddTimedQuest( quest_id );
10022 if (fields[5].GetUInt32() <= sWorld.GetGameTime())
10024 mQuestStatus[quest_id].m_timer = 1;
10025 } else
10026 mQuestStatus[quest_id].m_timer = (fields[5].GetUInt32() - sWorld.GetGameTime()) * 1000;
10028 mQuestStatus[quest_id].m_creatureOrGOcount[0] = fields[6].GetUInt32();
10029 mQuestStatus[quest_id].m_creatureOrGOcount[1] = fields[7].GetUInt32();
10030 mQuestStatus[quest_id].m_creatureOrGOcount[2] = fields[8].GetUInt32();
10031 mQuestStatus[quest_id].m_creatureOrGOcount[3] = fields[9].GetUInt32();
10032 mQuestStatus[quest_id].m_itemcount[0] = fields[10].GetUInt32();
10033 mQuestStatus[quest_id].m_itemcount[1] = fields[11].GetUInt32();
10034 mQuestStatus[quest_id].m_itemcount[2] = fields[12].GetUInt32();
10035 mQuestStatus[quest_id].m_itemcount[3] = fields[13].GetUInt32();
10037 sLog.outDebug("Quest status is {%u} for quest {%u}", mQuestStatus[quest_id].m_status, quest_id);
10040 while( result->NextRow() );
10042 delete result;
10046 void Player::_LoadReputation()
10048 Factions newFaction;
10050 factions.clear();
10052 QueryResult *result = sDatabase.PQuery("SELECT `faction`,`reputation`,`standing`,`flags` FROM `character_reputation` WHERE `guid` = '%u'",GetGUIDLow());
10054 if(result)
10058 Field *fields = result->Fetch();
10060 newFaction.ID = fields[0].GetUInt32();
10061 newFaction.ReputationListID = fields[1].GetUInt32();
10062 newFaction.Standing = fields[2].GetUInt32();
10063 newFaction.Flags = fields[3].GetUInt32();
10065 factions.push_back(newFaction);
10067 while( result->NextRow() );
10069 delete result;
10071 else
10073 //LoadReputationFromDBC();
10074 //Set initial reputations
10075 SetInitialFactions();
10079 void Player::_LoadSpells(uint32 timediff)
10081 for (PlayerSpellMap::iterator itr = m_spells.begin(); itr != m_spells.end(); ++itr)
10082 delete itr->second;
10083 m_spells.clear();
10085 QueryResult *result = sDatabase.PQuery("SELECT `spell`,`slot`,`active` FROM `character_spell` WHERE `guid` = '%u'",GetGUIDLow());
10087 if(result)
10091 Field *fields = result->Fetch();
10093 addSpell(fields[0].GetUInt16(), fields[2].GetUInt8(), PLAYERSPELL_UNCHANGED, fields[1].GetUInt16());
10095 while( result->NextRow() );
10097 delete result;
10101 void Player::_LoadTaxiMask(const char* data)
10103 vector<string> tokens = StrSplit(data, " ");
10105 int index;
10106 vector<string>::iterator iter;
10108 for (iter = tokens.begin(), index = 0;
10109 (index < 8) && (iter != tokens.end()); ++iter, ++index)
10111 m_taximask[index] = atol((*iter).c_str());
10115 void Player::_LoadTutorials()
10117 QueryResult *result = sDatabase.PQuery("SELECT `tut0`,`tut1`,`tut2`,`tut3`,`tut4`,`tut5`,`tut6`,`tut7` FROM `character_tutorial` WHERE `guid` = '%u'",GetGUIDLow());
10119 if(result)
10123 Field *fields = result->Fetch();
10125 for (int iI=0; iI<8; iI++)
10126 m_Tutorials[iI] = fields[iI].GetUInt32();
10129 while( result->NextRow() );
10131 delete result;
10135 /*********************************************************/
10136 /*** SAVE SYSTEM ***/
10137 /*********************************************************/
10139 void Player::SaveToDB()
10141 // saved before flight
10142 if (isInFlight())
10143 return;
10145 // save state
10146 uint32 tmp_bytes = GetUInt32Value(UNIT_FIELD_BYTES_1);
10147 uint32 tmp_flags = GetUInt32Value(UNIT_FIELD_FLAGS);
10148 uint32 tmp_pflags = GetUInt32Value(PLAYER_FLAGS);
10150 int is_logout_resting=0; //logaut far from tavern\city
10151 //logaut, but in tavern\city
10152 if(!IsInWorld()&&HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING))is_logout_resting=1;
10154 // Set player sit state to standing on save
10155 RemoveFlag(UNIT_FIELD_BYTES_1,PLAYER_STATE_SIT);
10156 RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_ROTATE);
10158 //remove restflag when save
10159 //this is becouse of the rename char stuff
10160 RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING);
10162 sLog.outDebug("The value of player %s before unload item and aura is: ", m_name.c_str());
10163 outDebugValues();
10165 if(isAlive())
10167 _RemoveAllItemMods();
10168 _RemoveAllAuraMods();
10171 bool inworld = IsInWorld();
10172 if (inworld)
10173 RemoveFromWorld();
10175 sDatabase.PExecute("DELETE FROM `character` WHERE `guid` = '%u'",GetGUIDLow());
10177 std::ostringstream ss;
10178 ss << "INSERT INTO `character` (`guid`,`realm`,`account`,`name`,`race`,`class`,"
10179 "`map`,`position_x`,`position_y`,`position_z`,`orientation`,`data`,"
10180 "`taximask`,`online`,`highest_rank`,`standing`,`rating`,`cinematic`,"
10181 "`totaltime`,`leveltime`,`rest_bonus`,`logout_time`,`is_logout_resting`,`resettalents_cost`,`resettalents_time`) VALUES ("
10182 << GetGUIDLow() << ", "
10183 << realmID << ", "
10184 << GetSession()->GetAccountId() << ", '"
10185 << m_name << "', "
10186 << m_race << ", "
10187 << m_class << ", "
10188 << m_mapId << ", "
10189 << m_positionX << ", "
10190 << m_positionY << ", "
10191 << m_positionZ << ", "
10192 << m_orientation << ", '";
10194 uint16 i;
10195 for( i = 0; i < m_valuesCount; i++ )
10197 ss << GetUInt32Value(i) << " ";
10200 ss << "', '";
10202 for( i = 0; i < 8; i++ )
10203 ss << m_taximask[i] << " ";
10205 ss << "', ";
10206 inworld ? ss << 1: ss << 0;
10208 ss << ", ";
10209 ss << m_highest_rank;
10211 ss << ", ";
10212 ss << m_standing;
10214 ss << ", ";
10215 ss << m_rating;
10217 ss << ", ";
10218 ss << m_cinematic;
10220 ss << ", ";
10221 ss << m_Played_time[0];
10222 ss << ", ";
10223 ss << m_Played_time[1];
10225 ss << ", ";
10226 ss << rest_bonus;
10227 ss << ", ";
10228 ss << (uint64)time(NULL);
10229 ss << ", ";
10230 ss << is_logout_resting;
10231 ss << ", ";
10232 ss << m_resetTalentsCost;
10233 ss << ", ";
10234 ss << (uint64)m_resetTalentsTime;
10236 ss << " )";
10238 sDatabase.Execute( ss.str().c_str() );
10240 SaveEnchant();
10242 if(m_mailsUpdated) //save mails only when needed
10243 _SaveMail();
10245 _SaveInventory();
10246 _SaveQuestStatus();
10247 _SaveTutorials();
10248 _SaveSpells();
10249 _SaveActions();
10250 _SaveAuras();
10251 _SaveReputation();
10252 SavePet();
10254 sLog.outDebug("Save Basic value of player %s is: ", m_name.c_str());
10255 outDebugValues();
10257 if(isAlive())
10259 _ApplyAllAuraMods();
10260 _ApplyAllItemMods();
10263 // restore state
10264 SetUInt32Value(UNIT_FIELD_BYTES_1, tmp_bytes);
10265 SetUInt32Value(UNIT_FIELD_FLAGS, tmp_flags);
10266 SetUInt32Value(PLAYER_FLAGS, tmp_pflags);
10268 if (inworld)
10269 AddToWorld();
10272 void Player::_SaveActions()
10274 sDatabase.PExecute("DELETE FROM `character_action` WHERE `guid` = '%u'",GetGUIDLow());
10276 std::list<struct actions>::iterator itr;
10277 for (itr = m_actions.begin(); itr != m_actions.end(); ++itr)
10279 sDatabase.PExecute("INSERT INTO `character_action` (`guid`,`button`,`action`,`type`,`misc`) VALUES ('%u', '%u', '%u', '%u', '%u')", GetGUIDLow(), (uint32)itr->button, (uint32)itr->action, (uint32)itr->type, (uint32)itr->misc);
10283 void Player::_SaveAuras()
10285 sDatabase.PExecute("DELETE FROM `character_aura` WHERE `guid` = '%u'",GetGUIDLow());
10287 AuraMap const& auras = GetAuras();
10288 for(AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
10290 SpellEntry *spellInfo = itr->second->GetSpellProto();
10291 uint8 i;
10292 for (i = 0; i < 3; i++)
10293 if (spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_SHAPESHIFT ||
10294 spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_STEALTH)
10295 break;
10296 if (i == 3 && !itr->second->IsPassive())
10297 sDatabase.PExecute("INSERT INTO `character_aura` (`guid`,`spell`,`effect_index`,`remaintime`) VALUES ('%u', '%u', '%u', '%d')", GetGUIDLow(), (uint32)(*itr).second->GetId(), (uint32)(*itr).second->GetEffIndex(), int((*itr).second->GetAuraDuration()));
10301 void Player::_SaveInventory()
10303 sDatabase.PExecute("DELETE FROM `character_inventory` WHERE `guid` = '%u' AND `bag` = '%u'",GetGUIDLow(), INVENTORY_SLOT_BAG_0);
10305 for(int i = EQUIPMENT_SLOT_START; i < BANK_SLOT_BAG_END; i++)
10307 if ( m_items[i] != 0 )
10309 sDatabase.PExecute("INSERT INTO `character_inventory` (`guid`,`bag`,`slot`,`item`,`item_template`) VALUES ('%u', '%u', '%u', '%u', '%u')", GetGUIDLow(), INVENTORY_SLOT_BAG_0, i, m_items[i]->GetGUIDLow(), m_items[i]->GetEntry());
10310 m_items[i]->SaveToDB();
10315 void Player::_SaveMail()
10317 if (!m_mailsLoaded)
10318 return;
10320 sDatabase.PExecute("DELETE FROM `mail` WHERE `receiver` = '%u'",GetGUIDLow());
10322 std::list<Mail*>::iterator itr;
10323 for (itr = m_mail.begin(); itr != m_mail.end(); itr++)
10325 Mail *m = (*itr);
10327 //escape apostrophes
10328 std::string subject = m->subject;
10329 std::string body = m->body;
10330 sDatabase.escape_string(body);
10331 sDatabase.escape_string(subject);
10333 sDatabase.PExecute("INSERT INTO `mail` (`id`,`sender`,`receiver`,`subject`,`body`,`item`,`time`,`money`,`cod`,`checked`) "
10334 "VALUES ('%u', '%u', '%u', '%s', '%s', '%u', '" I64FMTD "', '%u', '%u', '%u')",
10335 m->messageID, m->sender, m->receiver, subject.c_str(), body.c_str(), m->item, (uint64)m->time, m->money, m->COD, m->checked);
10337 m_mailsUpdated = false;
10340 void Player::_SaveQuestStatus()
10342 sDatabase.PExecute("DELETE FROM `character_queststatus` WHERE `guid` = '%u'",GetGUIDLow());
10344 for( StatusMap::iterator i = mQuestStatus.begin( ); i != mQuestStatus.end( ); ++ i )
10346 sDatabase.PExecute("INSERT INTO `character_queststatus` (`guid`,`quest`,`status`,`rewarded`,`explored`,`completed_once`,`timer`,`mobcount1`,`mobcount2`,`mobcount3`,`mobcount4`,`itemcount1`,`itemcount2`,`itemcount3`,`itemcount4`) VALUES ('%u', '%u', '%u', '%u', '%u', '%u', '" I64FMTD "', '%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u')",
10347 GetGUIDLow(), i->first, i->second.m_status, i->second.m_rewarded, i->second.m_explored, i->second.m_completed_once, uint64(i->second.m_timer / 1000 + sWorld.GetGameTime()), i->second.m_creatureOrGOcount[0], i->second.m_creatureOrGOcount[1], i->second.m_creatureOrGOcount[2], i->second.m_creatureOrGOcount[3], i->second.m_itemcount[0], i->second.m_itemcount[1], i->second.m_itemcount[2], i->second.m_itemcount[3]);
10351 void Player::_SaveReputation()
10353 std::list<Factions>::iterator itr;
10355 sDatabase.PExecute("DELETE FROM `character_reputation` WHERE `guid` = '%u'",GetGUIDLow());
10357 for(itr = factions.begin(); itr != factions.end(); ++itr)
10359 sDatabase.PExecute("INSERT INTO `character_reputation` (`guid`,`faction`,`reputation`,`standing`,`flags`) VALUES ('%u', '%u', '%u', '%u', '%u')", GetGUIDLow(), itr->ID, itr->ReputationListID, itr->Standing, itr->Flags);
10363 void Player::_SaveSpells()
10365 for (PlayerSpellMap::const_iterator itr = m_spells.begin(), next = m_spells.begin(); itr != m_spells.end(); itr = next)
10367 next++;
10368 if (itr->second->state == PLAYERSPELL_REMOVED || itr->second->state == PLAYERSPELL_CHANGED)
10369 sDatabase.PExecute("DELETE FROM `character_spell` WHERE `guid` = '%u' and `spell` = '%u'", GetGUIDLow(), itr->first);
10370 if (itr->second->state == PLAYERSPELL_NEW || itr->second->state == PLAYERSPELL_CHANGED)
10371 sDatabase.PExecute("INSERT INTO `character_spell` (`guid`,`spell`,`slot`,`active`) VALUES ('%u', '%u', '%u','%u')", GetGUIDLow(), itr->first, itr->second->slotId,itr->second->active);
10372 if (itr->second->state == PLAYERSPELL_REMOVED)
10373 _removeSpell(itr->first);
10374 else
10375 itr->second->state = PLAYERSPELL_UNCHANGED;
10379 void Player::_SaveTutorials()
10381 sDatabase.PExecute("DELETE FROM `character_tutorial` WHERE `guid` = '%u'",GetGUIDLow());
10382 sDatabase.PExecute("INSERT INTO `character_tutorial` (`guid`,`tut0`,`tut1`,`tut2`,`tut3`,`tut4`,`tut5`,`tut6`,`tut7`) VALUES ('%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u')", GetGUIDLow(), m_Tutorials[0], m_Tutorials[1], m_Tutorials[2], m_Tutorials[3], m_Tutorials[4], m_Tutorials[5], m_Tutorials[6], m_Tutorials[7]);
10385 void Player::SavePet()
10387 Creature* pet = GetPet();
10388 if(pet && (pet->isPet() || pet->isTamed()))
10389 pet->SaveAsPet();
10392 void Player::outDebugValues() const
10394 sLog.outDebug("HP is: \t\t\t%u\t\tMP is: \t\t\t%u",GetMaxHealth(), GetMaxPower(POWER_MANA));
10395 sLog.outDebug("AGILITY is: \t\t%f\t\tSTRENGTH is: \t\t%f",GetStat(STAT_AGILITY), GetStat(STAT_STRENGTH));
10396 sLog.outDebug("INTELLECT is: \t\t%f\t\tSPIRIT is: \t\t%f",GetStat(STAT_INTELLECT), GetStat(STAT_SPIRIT));
10397 sLog.outDebug("STAMINA is: \t\t%f\t\tSPIRIT is: \t\t%f",GetStat(STAT_STAMINA), GetStat(STAT_SPIRIT));
10398 sLog.outDebug("Armor is: \t\t%f\t\tBlock is: \t\t%f",GetArmor(), GetFloatValue(PLAYER_BLOCK_PERCENTAGE));
10399 sLog.outDebug("HolyRes is: \t\t%f\t\tFireRes is: \t\t%f",GetResistance(SPELL_SCHOOL_HOLY), GetResistance(SPELL_SCHOOL_FIRE));
10400 sLog.outDebug("NatureRes is: \t\t%f\t\tFrostRes is: \t\t%f",GetResistance(SPELL_SCHOOL_NATURE), GetResistance(SPELL_SCHOOL_FROST));
10401 sLog.outDebug("ShadowRes is: \t\t%f\t\tArcaneRes is: \t\t%f",GetResistance(SPELL_SCHOOL_SHADOW), GetResistance(SPELL_SCHOOL_ARCANE));
10402 sLog.outDebug("MIN_DAMAGE is: \t\t%f\tMAX_DAMAGE is: \t\t%f",GetFloatValue(UNIT_FIELD_MINDAMAGE), GetFloatValue(UNIT_FIELD_MAXDAMAGE));
10403 sLog.outDebug("MIN_OFFHAND_DAMAGE is: \t%f\tMAX_OFFHAND_DAMAGE is: \t%f",GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE), GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE));
10404 sLog.outDebug("MIN_RANGED_DAMAGE is: \t%f\tMAX_RANGED_DAMAGE is: \t%f",GetFloatValue(UNIT_FIELD_MINRANGEDDAMAGE), GetFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE));
10405 sLog.outDebug("ATTACK_TIME is: \t%u\t\tRANGE_ATTACK_TIME is: \t%u",GetAttackTime(BASE_ATTACK), GetAttackTime(RANGED_ATTACK));
10408 /*********************************************************/
10409 /*** LOW LEVEL FUNCTIONS:Notifiers ***/
10410 /*********************************************************/
10412 void Player::SendOutOfRange(Object* obj)
10414 UpdateData his_data;
10415 WorldPacket his_pk;
10416 obj->BuildOutOfRangeUpdateBlock(&his_data);
10417 his_data.BuildPacket(&his_pk);
10418 GetSession()->SendPacket(&his_pk);
10421 inline void Player::SendAttackSwingNotInRange()
10423 WorldPacket data;
10424 data.Initialize(SMSG_ATTACKSWING_NOTINRANGE);
10425 GetSession()->SendPacket( &data );
10428 void Player::SavePositionInDB(uint32 mapid, float x,float y,float z,float o,uint64 guid)
10430 std::ostringstream ss2;
10431 ss2 << "UPDATE `character` SET `position_x`='"<<x<<"',`position_y`='"<<y
10432 << "',`position_z`='"<<z<<"',`orientation`='"<<o<<"',`map`='"<<mapid
10433 << "' WHERE `guid`='"<<guid<<"'";
10434 sDatabase.Execute(ss2.str().c_str());
10437 bool Player::SaveValuesArrayInDB(vector<string> const& tokens, uint64 guid)
10439 std::ostringstream ss2;
10440 ss2<<"UPDATE `character` SET `data`='";
10441 vector<string>::const_iterator iter;
10442 int i=0;
10443 for (iter = tokens.begin(); iter != tokens.end(); ++iter, ++i)
10445 ss2<<tokens[i]<<" ";
10447 ss2<<"' WHERE `guid`='"<<guid<<"'";
10449 return sDatabase.Execute(ss2.str().c_str());
10452 void Player::SetUInt32ValueInArray(vector<string>& tokens,uint16 index, uint32 value)
10454 char buf[11];
10455 snprintf(buf,11,"%u",value);
10456 tokens[index] = buf;
10459 void Player::SetUInt32ValueInDB(uint16 index, uint32 value, uint64 guid)
10461 vector<string> tokens;
10462 if(!LoadValuesArrayFromDB(tokens,guid))
10463 return;
10465 char buf[11];
10466 snprintf(buf,11,"%u",value);
10467 tokens[index] = buf;
10469 SaveValuesArrayInDB(tokens,guid);
10472 void Player::SetFloatValueInDB(uint16 index, float value, uint64 guid)
10474 uint32 temp;
10475 memcpy(&temp, &value, sizeof(value));
10476 Player::SetUInt32ValueInDB(index, temp, guid);
10479 inline void Player::SendAttackSwingNotStanding()
10481 WorldPacket data;
10482 data.Initialize(SMSG_ATTACKSWING_NOTSTANDING);
10483 GetSession()->SendPacket( &data );
10486 inline void Player::SendAttackSwingDeadTarget()
10488 WorldPacket data;
10489 data.Initialize(SMSG_ATTACKSWING_DEADTARGET);
10490 GetSession()->SendPacket( &data );
10493 inline void Player::SendAttackSwingCantAttack()
10495 WorldPacket data;
10496 data.Initialize(SMSG_ATTACKSWING_CANT_ATTACK);
10497 GetSession()->SendPacket( &data );
10500 inline void Player::SendAttackSwingCancelAttack()
10502 WorldPacket data;
10503 data.Initialize(SMSG_CANCEL_COMBAT);
10504 GetSession()->SendPacket( &data );
10507 inline void Player::SendAttackSwingBadFacingAttack()
10509 WorldPacket data;
10510 data.Initialize(SMSG_ATTACKSWING_BADFACING);
10511 GetSession()->SendPacket( &data );
10514 void Player::PlaySound(uint32 Sound, bool OnlySelf)
10516 WorldPacket data;
10517 data.Initialize(SMSG_PLAY_SOUND);
10518 data << Sound;
10519 if (OnlySelf)
10520 GetSession()->SendPacket( &data );
10521 else
10522 SendMessageToSet( &data, true );
10525 void Player::SendExplorationExperience(uint32 Area, uint32 Experience)
10527 WorldPacket data;
10528 data.Initialize( SMSG_EXPLORATION_EXPERIENCE );
10529 data << Area;
10530 data << Experience;
10531 GetSession()->SendPacket(&data);
10534 /*********************************************************/
10535 /*** Update timers ***/
10536 /*********************************************************/
10538 void Player::UpdatePVPFlag(time_t currTime)
10540 if( !GetPvP() ) return;
10542 //Player is counting to set/unset pvp flag
10543 if( !m_pvp_counting ) return;
10545 //Is player is in a PvP action stop counting
10546 if( isInCombatWithPlayer() || isInDuel() )
10548 m_pvp_counting = false;
10549 m_pvp_count = time(NULL);
10550 return;
10553 //Wait 5 min until remove pvp mode
10554 if( currTime < m_pvp_count + 300 ) return;
10556 SetPvP(false);
10557 sChatHandler.SendSysMessage(GetSession(), "PvP toggled off.");
10561 void Player::UnsummonPet(Creature* pet)
10563 if(!pet)
10564 pet = GetPet();
10566 if(!pet||pet->GetGUID()!=GetPetGUID()) return;
10568 SetPet(0);
10570 pet->CombatStop();
10572 if(pet->isPet())
10573 pet->SaveAsPet();
10575 WorldPacket data;
10576 data.Initialize(SMSG_DESTROY_OBJECT);
10577 data << pet->GetGUID();
10578 SendMessageToSet (&data, true);
10580 data.Initialize(SMSG_PET_SPELLS);
10581 data << uint64(0);
10582 GetSession()->SendPacket(&data);
10584 ObjectAccessor::Instance().AddObjectToRemoveList(pet);
10587 void Player::UnTamePet(Creature* pet)
10589 if(!pet)
10590 pet = GetPet();
10592 if(!pet||!pet->isTamed()||pet->GetGUID()!=GetPetGUID()) return;
10594 pet->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,pet->GetCreatureInfo()->faction);
10595 pet->SetMaxPower(POWER_HAPPINESS,0);
10596 pet->SetPower(POWER_HAPPINESS,0);
10597 pet->SetMaxPower(POWER_FOCUS,0);
10598 pet->SetPower(POWER_FOCUS,0);
10599 pet->SetUInt64Value(UNIT_FIELD_CREATEDBY, 0);
10600 pet->SetUInt32Value(UNIT_FIELD_PETNUMBER,0);
10601 pet->SetTamed(false);
10602 SetPet(0);
10604 pet->AIM_Initialize();
10606 WorldPacket data;
10608 data.Initialize(SMSG_PET_SPELLS);
10609 data << uint64(0);
10610 GetSession()->SendPacket(&data);
10613 void Player::Uncharm()
10615 Creature* charm = GetCharm();
10616 if(!charm) return;
10618 SetCharm(0);
10620 CreatureInfo const *cinfo = charm->GetCreatureInfo();
10621 charm->SetUInt64Value(UNIT_FIELD_CHARMEDBY,0);
10622 charm->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,cinfo->faction);
10624 charm->AIM_Initialize();
10625 WorldPacket data;
10626 data.Initialize(SMSG_PET_SPELLS);
10627 data << uint64(0);
10628 GetSession()->SendPacket(&data);
10631 void Player::PetSpellInitialize()
10633 Creature* pet = GetPet();
10634 if(!pet)
10635 pet = GetCharm();
10636 if(pet)
10639 WorldPacket data;
10640 uint16 Command = 7;
10641 uint16 State = 6;
10642 uint8 addlist = 0;
10644 sLog.outDebug("Pet Spells Groups");
10646 data.clear();
10647 data.Initialize(SMSG_PET_SPELLS);
10649 data << (uint64)pet->GetGUID() << uint32(0x00000000) << uint32(0x1010000);
10651 data << uint16 (2) << uint16(Command << 8) << uint16 (1) << uint16(Command << 8) << uint16 (0) << uint16(Command << 8);
10653 for(uint32 i=0; i < CREATURE_MAX_SPELLS; i++)
10654 //C100 = maybe group
10655 data << uint16 (pet->m_spells[i]) << uint16 (0xC100);
10657 data << uint16 (2) << uint16(State << 8) << uint16 (1) << uint16(State << 8) << uint16 (0) << uint16(State << 8);
10659 if(pet->GetUInt32Value(UNIT_FIELD_PETNUMBER))
10661 for(PlayerSpellMap::iterator itr = m_spells.begin();itr != m_spells.end();itr++)
10663 if(itr->second->active == 4)
10664 addlist++;
10668 data << uint8(addlist);
10670 if(pet->GetUInt32Value(UNIT_FIELD_PETNUMBER))
10672 for(PlayerSpellMap::iterator itr = m_spells.begin();itr != m_spells.end();itr++)
10674 if(itr->second->active == 4)
10676 bool hasthisspell = false;
10678 SpellEntry *spellInfo = sSpellStore.LookupEntry(itr->first);
10679 data << uint16(spellInfo->EffectTriggerSpell[0]);
10680 for(uint32 i=0; i < CREATURE_MAX_SPELLS; i++)
10682 if(pet->m_spells[i] == spellInfo->EffectTriggerSpell[0])
10684 data << uint16(0xC1);
10685 hasthisspell = true;
10686 break;
10689 if(!hasthisspell)
10690 data << uint16(0x01);
10695 data << uint8(0x01) << uint32(0x6010) << uint32(0x00) << uint32(0x00) << uint16(0x00);
10697 GetSession()->SendPacket(&data);
10701 int32 Player::GetTotalFlatMods(uint32 spellId, uint8 op)
10703 SpellEntry *spellInfo = sSpellStore.LookupEntry(spellId);
10704 if (!spellInfo) return 0;
10705 int32 total = 0;
10706 for (SpellModList::iterator itr = m_spellMods[op].begin(); itr != m_spellMods[op].end(); ++itr)
10708 SpellModifier *mod = *itr;
10709 if (!mod) continue;
10710 if ((mod->mask & spellInfo->SpellFamilyFlags) == 0) continue;
10711 if (mod->type == SPELLMOD_FLAT)
10712 total += mod->value;
10714 return total;
10717 int32 Player::GetTotalPctMods(uint32 spellId, uint8 op)
10719 SpellEntry *spellInfo = sSpellStore.LookupEntry(spellId);
10720 if (!spellInfo) return 0;
10721 int32 total = 0;
10722 for (SpellModList::iterator itr = m_spellMods[op].begin(); itr != m_spellMods[op].end(); ++itr)
10724 SpellModifier *mod = *itr;
10725 if (!mod) continue;
10726 if ((mod->mask & spellInfo->SpellFamilyFlags) == 0) continue;
10727 if (mod->type == SPELLMOD_PCT)
10728 total += mod->value;
10730 return total;
10733 void Player::ApplyBlockValueMod(int32 val,bool apply)
10735 ApplyModUInt32Var(m_BlockValue,val,apply);
10738 void Player::RemoveAreaAurasFromGroup()
10740 Group* pGroup = objmgr.GetGroupByLeader(this->GetGroupLeader());
10741 if(!pGroup)
10742 return;
10744 for(uint32 p=0;p<pGroup->GetMembersCount();p++)
10746 Unit* Member = ObjectAccessor::Instance().FindPlayer(pGroup->GetMemberGUID(p));
10747 if(!Member)
10748 continue;
10749 Member->RemoveAreaAurasByOthers(GetGUID());
10750 for (uint8 i = 0; i < 4; i++)
10751 if (m_TotemSlot[i])
10752 Member->RemoveAreaAurasByOthers(m_TotemSlot[i]);
10756 // send Proficiency
10757 void Player::SendProficiency(uint8 pr1, uint32 pr2)
10759 WorldPacket data;
10760 data.Initialize (SMSG_SET_PROFICIENCY);
10761 data << pr1 << pr2;
10762 GetSession()->SendPacket (&data);
10765 void Player::RemovePetitionsAndSigns(uint64 guid)
10767 QueryResult *result = sDatabase.PQuery("SELECT `ownerguid`,`charterguid` FROM `guild_charter_sign` WHERE `playerguid` = '%u'", guid);
10768 if(result)
10772 Field *fields = result->Fetch();
10773 uint64 ownerguid = MAKE_GUID(fields[0].GetUInt32(),HIGHGUID_PLAYER);
10774 uint64 charterguid = MAKE_GUID(fields[1].GetUInt32(),HIGHGUID_ITEM);
10776 // send update if charter owner in game
10777 Player* owner = objmgr.GetPlayer(ownerguid);
10778 if(owner)
10779 owner->GetSession()->SendPetitionQueryOpcode(charterguid);
10781 } while ( result->NextRow() );
10783 delete result;
10785 sDatabase.PExecute("DELETE FROM `guild_charter_sign` WHERE `playerguid` = '%u'",guid);
10788 sDatabase.PExecute("DELETE FROM `guild_charter` WHERE `ownerguid` = '%u'",guid);
10789 sDatabase.PExecute("DELETE FROM `guild_charter_sign` WHERE `ownerguid` = '%u'",guid);