[2771] Applied MaNGOS coding style (see trunk/bcpp.cfg).
[mangos-git.git] / src / game / Player.cpp
blobb3b611118062c7018f29d17c69d8b623d0899ae1
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"
45 #include "Transports.h"
47 #include <cmath>
49 Player::Player (WorldSession *session): Unit()
51 m_transport = NULL;
52 m_transX = 0.0f;
53 m_transY = 0.0f;
54 m_transZ = 0.0f;
55 m_transO = 0.0f;
57 m_objectType |= TYPE_PLAYER;
58 m_objectTypeId = TYPEID_PLAYER;
60 m_valuesCount = PLAYER_END;
62 m_session = session;
64 m_divider = 0;
66 m_GMFlags = 0;
67 if(GetSession()->GetSecurity() >=2)
68 SetAcceptTicket(true);
69 if(GetSession()->GetSecurity() >=1 && sWorld.getConfig(CONFIG_GM_WISPERING_TO))
70 SetAcceptWhispers(true);
72 m_curTarget = 0;
73 m_curSelection = 0;
74 m_lootGuid = 0;
75 m_petInfoId = 0;
76 m_petLevel = 0;
77 m_petFamilyId = 0;
79 m_regenTimer = 0;
80 m_dismountCost = 0;
82 m_nextSave = sWorld.getConfig(CONFIG_INTERVAL_SAVE);
84 m_resurrectGUID = 0;
85 m_resurrectX = m_resurrectY = m_resurrectZ = 0;
86 m_resurrectHealth = m_resurrectMana = 0;
88 memset(m_items, 0, sizeof(Item*)*BANK_SLOT_BAG_END);
89 memset(m_buybackitems, 0, sizeof(Item*)*(BUYBACK_SLOT_END - BUYBACK_SLOT_START));
91 //m_pDuel = NULL;
92 //m_pDuelSender = NULL;
93 //m_isInDuel = false;
94 duel = NULL;
96 m_GuildIdInvited = 0;
98 m_groupLeader = 0;
99 m_isInGroup = false;
100 m_isInvited = false;
102 m_dontMove = false;
104 m_total_honor_points = 0;
106 pTrader = NULL;
108 ClearTrade();
110 m_cinematic = 0;
112 PlayerTalkClass = new PlayerMenu( GetSession() );
113 m_currentBuybackSlot = BUYBACK_SLOT_START;
115 for ( int aX = 0 ; aX < 8 ; aX++ )
116 m_Tutorials[ aX ] = 0x00;
117 ItemsSetEff[0]=NULL;
118 ItemsSetEff[1]=NULL;
119 ItemsSetEff[2]=NULL;
120 m_regenTimer = 0;
121 m_breathTimer = 0;
122 m_isunderwater = 0;
123 m_drunkTimer = 0;
124 m_drunk = 0;
125 m_restTime = 0;
126 m_lastManaUse = 0;
127 m_deathTimer = 0;
129 m_DetectInvTimer = 1000;
130 m_DiscoveredPj = 0;
131 m_enableDetect = true;
133 m_pvp_count = 0;
134 m_pvp_counting = false;
136 m_bgInBattleGround = false;
137 m_bgBattleGroundID = 0;
139 m_movement_flags = 0;
141 m_BlockValue = 0;
143 m_logintime = time(NULL);
144 m_Last_tick = m_logintime;
145 m_soulStone = NULL;
146 m_soulStoneSpell = 0;
147 m_WeaponProficiency = 0;
148 m_ArmorProficiency = 0;
149 m_canParry = false;
150 m_canDualWield = false;
152 ////////////////////Rest System/////////////////////
153 time_inn_enter=0;
154 inn_pos_x=0;
155 inn_pos_y=0;
156 inn_pos_z=0;
157 rest_bonus=0;
158 rest_type=0;
159 ////////////////////Rest System/////////////////////
161 m_mailsLoaded = false;
162 m_mailsUpdated = false;
164 m_resetTalentsCost = 0;
165 m_resetTalentsTime = 0;
166 m_itemUpdateQueueBlocked = false;
169 Player::~Player ()
171 DuelComplete(0);
173 CombatStop();
175 TradeCancel(false);
177 RemoveAllAuras();
179 uint32 eslot;
180 for(int j = BUYBACK_SLOT_START; j < BUYBACK_SLOT_END; j++)
182 eslot = j - BUYBACK_SLOT_START;
183 if(m_buybackitems[eslot])
184 delete m_buybackitems[eslot];
185 // already deleted from DB when player was saved
187 for(int i = 0; i < BANK_SLOT_BAG_END; i++)
189 if(m_items[i])
190 delete m_items[i];
192 CleanupChannels();
194 //all mailed items should be deleted, also all mail should be dealocated
195 for (std::deque<Mail*>::iterator itr = m_mail.begin(); itr != m_mail.end();++itr)
196 delete *itr;
198 for (ItemMap::iterator iter = mMitems.begin(); iter != mMitems.end(); ++iter)
199 delete iter->second; //if item is duplicated... then server may crash ... but that item should be dealocated
201 delete PlayerTalkClass;
203 if (m_transport)
205 m_transport->RemovePassenger(this);
209 bool Player::Create( uint32 guidlow, WorldPacket& data )
211 int i;
212 uint8 race,class_,gender,skin,face,hairStyle,hairColor,facialHair,outfitId;
214 Object::_Create(guidlow, HIGHGUID_PLAYER);
216 data >> m_name;
218 if(m_name.size() == 0)
219 return false;
221 normalizePlayerName(m_name);
223 data >> race >> class_ >> gender >> skin >> face;
224 data >> hairStyle >> hairColor >> facialHair >> outfitId;
226 PlayerInfo const* info = objmgr.GetPlayerInfo(race, class_);
227 if(!info)
229 sLog.outError("Player have incorrect race/class pair. Can't be loaded.");
230 return false;
233 for (i = 0; i < BANK_SLOT_BAG_END; i++)
234 m_items[i] = NULL;
236 uint32 eslot;
237 for(int j = BUYBACK_SLOT_START; j < BUYBACK_SLOT_END; j++)
239 eslot = j - BUYBACK_SLOT_START;
240 m_buybackitems[eslot] = NULL;
241 // SetUInt64Value(PLAYER_FIELD_VENDORBUYBACK_SLOT_1+j*2,0);
242 // SetUInt32Value(PLAYER_FIELD_BUYBACK_PRICE_1+j,0);
243 // SetUInt32Value(PLAYER_FIELD_BUYBACK_TIMESTAMP_1+j,0);
246 m_race = race;
247 m_class = class_;
249 m_mapId = info->mapId;
250 m_positionX = info->positionX;
251 m_positionY = info->positionY;
252 m_positionZ = info->positionZ;
254 // Taxi nodes setup
255 memset(m_taximask, 0, sizeof(m_taximask));
257 // Automatically add the race's taxi hub to the character's taximask at creation time ( 1 << (taxi_node_id-1) )
258 ChrRacesEntry const* rEntry = sChrRacesStore.LookupEntry(race);
259 if(!rEntry)
261 sLog.outError("Race %u not found in DBÑ (Wrong DBC files?)",race);
262 return false;
265 m_taximask[0] = rEntry->startingTaxiMask;
267 ChrClassesEntry const* cEntry = sChrClassesStore.LookupEntry(class_);
268 if(!cEntry)
270 sLog.outError("Class %u not found in DBÑ (Wrong DBC files?)",class_);
271 return false;
274 uint8 powertype = cEntry->powerType;
276 uint32 unitfield;
277 if(powertype == POWER_RAGE)
278 unitfield = 0x1100EE00;
279 else if(powertype == POWER_ENERGY)
280 unitfield = 0x00000000;
281 else if(powertype == POWER_MANA)
282 unitfield = 0x0000EE00;
283 else
285 sLog.outError("Invalid default powertype %u for player (class %u)",powertype,class_);
286 return false;
289 if ( race == RACE_TAUREN )
290 SetFloatValue(OBJECT_FIELD_SCALE_X, 1.35f);
291 else
292 SetFloatValue(OBJECT_FIELD_SCALE_X, 1.0f);
294 SetFloatValue(UNIT_FIELD_BOUNDINGRADIUS, 0.388999998569489f );
295 SetFloatValue(UNIT_FIELD_COMBATREACH, 1.5f );
297 SetUInt32Value(UNIT_FIELD_DISPLAYID, info->displayId + gender );
298 SetUInt32Value(UNIT_FIELD_NATIVEDISPLAYID, info->displayId + gender );
300 setFactionForRace(m_race);
302 SetUInt32Value(UNIT_FIELD_BYTES_0, ( ( race ) | ( class_ << 8 ) | ( gender << 16 ) | ( powertype << 24 ) ) );
303 SetUInt32Value(UNIT_FIELD_BYTES_1, unitfield );
304 SetUInt32Value(UNIT_FIELD_BYTES_2, 0xEEEEEE00 );
305 SetUInt32Value(UNIT_FIELD_FLAGS , UNIT_FLAG_NONE | UNIT_FLAG_ALLOW_SWIM );
307 SetUInt32Value(UNIT_DYNAMIC_FLAGS, 0x10);
308 //-1 is default value
309 SetUInt32Value(PLAYER_FIELD_WATCHED_FACTION_INDEX, uint32(-1));
311 SetUInt32Value(PLAYER_BYTES, ((skin) | (face << 8) | (hairStyle << 16) | (hairColor << 24)));
312 SetUInt32Value(PLAYER_BYTES_2, (facialHair | (0xEE << 8) | (0x00 << 16) | (0x02 << 24)));
313 SetUInt32Value(PLAYER_BYTES_3, gender);
314 SetUInt32Value(PLAYER_FIELD_BYTES, 0xEEE00000 );
317 SetUInt32Value(PLAYER_GUILDID, 0);
318 SetUInt32Value(PLAYER_GUILDRANK, 0);
319 SetUInt32Value(PLAYER_GUILD_TIMESTAMP, 0);
321 SetUInt32Value(PLAYER_FIELD_HONOR_RANK, 0);
322 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);
325 InitStatsForLevel(1,false,false);
327 // Played time
328 m_Last_tick = time(NULL);
329 m_Played_time[0] = 0;
330 m_Played_time[1] = 0;
332 uint32 titem_id;
333 uint32 titem_amount;
334 uint16 tspell, tskill[3], taction[4];
335 std::list<uint16>::const_iterator skill_itr[3], action_itr[4];
336 std::list<CreateSpellPair>::const_iterator spell_itr;
338 spell_itr = info->spell.begin();
340 for (; spell_itr!=info->spell.end(); spell_itr++)
342 tspell = spell_itr->first;
343 if (tspell)
345 sLog.outDebug("PLAYER: Adding initial spell, id = %u",tspell);
346 addSpell(tspell,spell_itr->second);
350 for(i=0 ; i<3; i++)
351 skill_itr[i] = info->skill[i].begin();
353 for (; skill_itr[0]!=info->skill[0].end() && skill_itr[1]!=info->skill[1].end() && skill_itr[2]!=info->skill[2].end(); )
355 for (i=0; i<3; i++)
356 tskill[i] = (*skill_itr[i]);
358 if (tskill[0])
360 sLog.outDebug("PLAYER: Adding initial skill line, skillId = %u, value = %u, max = %u", tskill[0], tskill[1], tskill[2]);
361 SetSkill(tskill[0], tskill[1], tskill[2]);
364 for(i=0; i<3; i++)
365 skill_itr[i]++;
368 for(i=0; i<4; i++)
369 action_itr[i] = info->action[i].begin();
371 for (; action_itr[0]!=info->action[0].end() && action_itr[1]!=info->action[1].end();)
373 for( i=0; i<4 ;i++)
374 taction[i] = (*action_itr[i]);
376 addAction((uint8)taction[0], taction[1], (uint8)taction[2], (uint8)taction[3]);
378 for( i=0; i<4 ;i++)
379 action_itr[i]++;
382 m_petInfoId = 0;
383 m_petLevel = 0;
384 m_petFamilyId = 0;
386 m_rating = 0;
387 m_highest_rank = 0;
388 m_standing = 0;
390 UpdateBlockPercentage();
392 // apply original stats mods before item equipment that call before equip _RemoveStatsMods()
393 _ApplyStatsMods();
395 uint16 dest;
396 uint8 msg;
397 Item *pItem;
398 for (PlayerCreateInfoItems::const_iterator item_id_itr = info->item.begin(); item_id_itr!=info->item.end(); ++item_id_itr++)
400 titem_id = item_id_itr->item_id;
401 titem_amount = item_id_itr->item_amount;
403 if (titem_id)
405 sLog.outDebug("STORAGE: Creating initial item, itemId = %u, count = %u",titem_id, titem_amount);
407 pItem = CreateItem( titem_id, titem_amount);
408 if( pItem )
410 msg = CanEquipItem( NULL_SLOT, dest, pItem, false );
411 if( msg == EQUIP_ERR_OK )
412 EquipItem( dest, pItem, true);
413 else
415 // store in main bag to simplify second pass
416 msg = CanStoreItem( INVENTORY_SLOT_BAG_0, NULL_SLOT, dest, pItem, false );
417 if( msg == EQUIP_ERR_OK )
418 StoreItem( dest, pItem, true);
419 else
421 sLog.outError("STORAGE: Can't equip or store initial item %u for race %u class %u , error msg = %u",titem_id,race,class_,msg);
422 delete pItem;
426 else
427 sLog.outError("STORAGE: Can't create initial item %u (not existed item id) for race %u class %u , error msg = %u",titem_id,race,class_,msg);
431 // bags and main-hamd weapon must equiped ant this moment
432 // now second pass for not equiped (offhand weapon/shield if it attempt equiped before main-hand weapon)
433 // or ammo not equiped in special bag
434 for(int i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; i++)
436 int16 pos = ( (INVENTORY_SLOT_BAG_0 << 8) | i );
437 pItem = GetItemByPos( pos );
439 if(pItem)
441 // equip offhand weapon/shield if it attempt equiped before main-hand weapon
442 msg = CanEquipItem( NULL_SLOT, dest, pItem, false );
443 if( msg == EQUIP_ERR_OK )
445 RemoveItem(INVENTORY_SLOT_BAG_0, i,true);
446 EquipItem( dest, pItem, true);
447 }else
448 // move other items to more appropriate slots (ammo not equiped in special bag)
450 msg = CanStoreItem( NULL_BAG, NULL_SLOT, dest, pItem, false );
451 if( msg == EQUIP_ERR_OK )
453 RemoveItem(INVENTORY_SLOT_BAG_0, i,true);
454 StoreItem( dest, pItem, true);
457 // if this is ammo then use it
458 uint8 msg = CanUseAmmo( pItem->GetProto()->ItemId );
459 if( msg == EQUIP_ERR_OK )
460 SetUInt32Value(PLAYER_AMMO_ID, pItem->GetProto()->ItemId);
464 // all item positions resolved
466 // remove applied original stats mods before item equipment
467 _RemoveStatsMods();
468 return true;
471 void Player::StartMirrorTimer(MirrorTimerType Type, uint32 MaxValue)
473 WorldPacket data;
474 uint32 BreathRegen = (uint32)-1;
475 data.Initialize(SMSG_START_MIRROR_TIMER);
476 data << (uint32)Type;
477 data << MaxValue;
478 data << MaxValue;
479 data << BreathRegen;
480 data << (uint32)0;
481 data << (uint8)0;
482 GetSession()->SendPacket(&data);
485 void Player::ModifyMirrorTimer(MirrorTimerType Type, uint32 MaxValue, uint32 CurrentValue, uint32 Regen)
487 if(Type==BREATH_TIMER)
488 m_breathTimer = ((MaxValue + 1000) - CurrentValue) / Regen;
490 WorldPacket data;
491 data.Initialize(SMSG_START_MIRROR_TIMER);
492 data << (uint32)Type;
493 data << CurrentValue;
494 data << MaxValue;
495 data << Regen;
496 data << (uint32)0;
497 data << (uint8)0;
498 GetSession()->SendPacket( &data );
501 void Player::StopMirrorTimer(MirrorTimerType Type)
503 if(Type==BREATH_TIMER)
504 m_breathTimer = 0;
506 WorldPacket data;
507 data.Initialize(SMSG_STOP_MIRROR_TIMER);
508 data << (uint32)Type;
509 GetSession()->SendPacket( &data );
512 void Player::EnvironmentalDamage(uint64 Guid, uint8 Type, uint32 Amount)
514 WorldPacket data;
515 data.Initialize(SMSG_ENVIRONMENTALDAMAGELOG);
516 data << Guid;
517 data << (uint8)Type;
518 data << Amount;
519 data << (uint32)0;
520 data << (uint32)0;
521 //m_session->SendPacket(&data);
522 //Let other players see that you get damage
523 SendMessageToSet(&data, true);
524 DealDamage((Unit*)this, Amount, SELF_DAMAGE, 0, true);
527 void Player::HandleDrowing(uint32 UnderWaterTime)
529 if(!m_isunderwater)
530 return;
532 AuraList& mModWaterBreathing = GetAurasByType(SPELL_AURA_MOD_WATER_BREATHING);
533 for(AuraList::iterator i = mModWaterBreathing.begin(); i != mModWaterBreathing.end(); ++i)
534 UnderWaterTime = uint32(UnderWaterTime * (100.0f + (*i)->GetModifier()->m_amount) / 100.0f);
536 //if have water breath , then remove bar
537 if(waterbreath || !isAlive())
539 StopMirrorTimer(BREATH_TIMER);
540 m_isunderwater = 0;
541 return;
544 if ((m_isunderwater & 0x01) && !(m_isunderwater & 0x80) && isAlive())
546 //single trigger timer
547 if (!(m_isunderwater & 0x02))
549 m_isunderwater|= 0x02;
550 m_breathTimer = UnderWaterTime + 1000;
552 //single trigger "Breathbar"
553 if ( m_breathTimer <= UnderWaterTime && !(m_isunderwater & 0x04))
555 m_isunderwater|= 0x04;
556 StartMirrorTimer(BREATH_TIMER, UnderWaterTime);
558 //continius trigger drowning "Damage"
559 if ((m_breathTimer == 0) && (m_isunderwater & 0x01))
561 //TODO: Check this formula
562 uint64 guid = GetGUID();
563 uint32 damage = (GetMaxHealth() / 5) + rand()%getLevel();
565 EnvironmentalDamage(guid, DAMAGE_DROWNING,damage);
566 m_breathTimer = 2000;
569 //single trigger retract bar
570 else if (!(m_isunderwater & 0x01) && !(m_isunderwater & 0x08) && (m_isunderwater & 0x02) && (m_breathTimer > 0) && isAlive())
572 m_isunderwater = 0x08;
574 uint32 BreathRegen = 10;
575 ModifyMirrorTimer(BREATH_TIMER, UnderWaterTime, m_breathTimer,BreathRegen);
576 m_isunderwater = 0x10;
578 //remove bar
579 else if ((m_breathTimer < 50) && !(m_isunderwater & 0x01) && (m_isunderwater == 0x10))
581 StopMirrorTimer(BREATH_TIMER);
582 m_isunderwater = 0;
586 void Player::HandleLava()
588 if ((m_isunderwater & 0x80) && isAlive())
590 //Single trigger Set BreathTimer
591 if (!(m_isunderwater & 0x04))
593 m_isunderwater|= 0x04;
594 m_breathTimer = 1000;
596 //Reset BreathTimer and still in the lava
597 if (!m_breathTimer)
599 uint64 guid;
600 //uint32 damage = 10;
601 uint32 damage = (GetMaxHealth() / 3) + rand()%getLevel();
603 guid = GetGUID();
604 EnvironmentalDamage(guid, DAMAGE_LAVA, damage);
605 m_breathTimer = 1000;
609 //Death timer disabled and WaterFlags reset
610 else if (m_deathState == DEAD)
612 m_breathTimer = 0;
613 m_isunderwater = 0;
617 void Player::HandleSobering()
619 m_drunkTimer = 0;
620 if (m_drunk <= (0xFFFF / 30))
622 m_drunk = 0;
624 else
626 m_drunk -= (0xFFFF / 30);
628 SetUInt32Value(PLAYER_BYTES_3, (GetUInt32Value(PLAYER_BYTES_3) & 0xFFFF0001) | m_drunk);
631 void Player::SetDrunkValue(uint16 newDrunkValue)
633 m_drunk = newDrunkValue;
634 SetUInt32Value(PLAYER_BYTES_3,
635 (GetUInt32Value(PLAYER_BYTES_3) & 0xFFFF0001) | m_drunk);
638 void Player::Update( uint32 p_time )
640 if(!IsInWorld())
641 return;
643 WorldPacket data;
645 Unit::Update( p_time );
647 // update player only attacks
648 if(uint32 ranged_att = getAttackTimer(RANGED_ATTACK))
650 setAttackTimer(RANGED_ATTACK, (p_time >= ranged_att ? 0 : ranged_att - p_time) );
653 if(uint32 off_att = getAttackTimer(OFF_ATTACK))
655 setAttackTimer(OFF_ATTACK, (p_time >= off_att ? 0 : off_att - p_time) );
658 time_t now = time (NULL);
660 UpdatePVPFlag(time(NULL));
662 UpdateDuelFlag(time(NULL));
664 CheckDuelDistance(time(NULL));
666 CheckExploreSystem();
668 if (m_timedquests.size() > 0)
670 list<uint32>::iterator iter = m_timedquests.begin();
671 while (iter != m_timedquests.end())
673 //if( mQuestStatus[*iter].m_timer > 0 )
675 if( mQuestStatus[*iter].m_timer <= p_time )
677 FailTimedQuest( *iter );
678 iter = m_timedquests.begin();
680 else
682 mQuestStatus[*iter].m_timer -= p_time;
683 iter++;
689 if (isAttacking())
691 Unit *pVictim = getVictim();
692 if( m_currentSpell == 0 && pVictim)
695 // default combat reach 10
696 // TODO add weapon,skill check
698 float pldistance = 5.0f;
700 /*if(getClass() == WARRIOR)
701 pldistance += 1;
703 if(GetItemByPos( INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND ) != 0)
704 pldistance += 2;
706 if(GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_HANDS) != 0)
707 pldistance += 3;*/
709 if (isAttackReady(BASE_ATTACK))
711 if(!IsWithinDist(pVictim, pldistance))
713 setAttackTimer(BASE_ATTACK,1000);
714 SendAttackSwingNotInRange();
716 //120 degreas of radiant range
717 else if( !HasInArc( 2*M_PI/3, pVictim ))
719 setAttackTimer(BASE_ATTACK,1000);
720 SendAttackSwingBadFacingAttack();
722 else
724 // prevent base and off attack in same time, delay attack at 0.2 sec
725 if(haveOffhandWeapon())
727 uint32 off_att = getAttackTimer(OFF_ATTACK);
728 if(off_att < ATTACK_DISPLAY_DELAY)
729 setAttackTimer(OFF_ATTACK,ATTACK_DISPLAY_DELAY);
731 AttackerStateUpdate(pVictim, BASE_ATTACK);
732 resetAttackTimer(BASE_ATTACK);
736 if ( haveOffhandWeapon() && isAttackReady(OFF_ATTACK))
738 if(! IsWithinDist(pVictim, pldistance))
740 setAttackTimer(OFF_ATTACK,1000);
742 else if( !HasInArc( 2*M_PI/3, pVictim ))
744 setAttackTimer(OFF_ATTACK,1000);
746 else
748 // prevent base and off attack in same time, delay attack at 0.2 sec
749 uint32 base_att = getAttackTimer(BASE_ATTACK);
750 if(base_att < ATTACK_DISPLAY_DELAY)
751 setAttackTimer(BASE_ATTACK,ATTACK_DISPLAY_DELAY);
752 // do attack
753 AttackerStateUpdate(pVictim, OFF_ATTACK);
754 resetAttackTimer(OFF_ATTACK);
760 else if (isAttacked())
762 // Leave here so we don't forget this case
763 // Attacked, but not necessarily attacking
765 else
767 // Leave here so we don't forget this case
768 // Not attacking or attacked
771 if(HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING))
773 if(irand(0,100)<=3 && GetTimeInnEter() > 0) //freeze update
775 int time_inn = time(NULL)-GetTimeInnEter();
776 if (time_inn >= 10) //freeze update
778 float bubble = sWorld.getRate(RATE_REST_INGAME);
779 //speed collect rest bonus (section/in hour)
780 SetRestBonus( GetRestBonus()+ time_inn*((float)GetUInt32Value(PLAYER_NEXT_LEVEL_XP)/144000)*bubble );
781 UpdateInnerTime(time(NULL));
784 if(GetRestType()==1) //rest in tavern
786 if(sqrt((GetPositionX()-GetInnPosX())*(GetPositionX()-GetInnPosX())+(GetPositionY()-GetInnPosY())*(GetPositionY()-GetInnPosY())+(GetPositionZ()-GetInnPosZ())*(GetPositionZ()-GetInnPosZ()))>40)
788 RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING);
793 if(m_regenTimer > 0)
795 if(p_time >= m_regenTimer)
796 m_regenTimer = 0;
797 else
798 m_regenTimer -= p_time;
801 if (isAlive())
803 RegenerateAll();
806 if (m_deathState == JUST_DIED)
808 KillPlayer();
809 if( GetSoulStoneSpell() && GetSoulStone())
811 SpellEntry *spellInfo = sSpellStore.LookupEntry(GetSoulStoneSpell());
812 if(spellInfo)
814 Spell spell(this, spellInfo, true, 0);
816 SpellCastTargets targets;
817 targets.setUnitTarget( this );
818 spell.m_CastItem = GetSoulStone();
819 spell.prepare(&targets);
821 SetSoulStone(NULL);
822 SetSoulStoneSpell(0);
826 if(m_nextSave > 0)
828 if(p_time >= m_nextSave)
830 // m_nextSave reseted in SaveToDB call
831 SaveToDB();
832 sLog.outBasic("Player '%u' '%s' Saved", GetGUIDLow(), GetName());
834 else
836 m_nextSave -= p_time;
840 //Breathtimer
841 if(m_breathTimer > 0)
843 if(p_time >= m_breathTimer)
844 m_breathTimer = 0;
845 else
846 m_breathTimer -= p_time;
850 //Handle Water/drowning
851 HandleDrowing(60000);
853 //Handle lava
854 HandleLava();
856 //Handle detect invisible players
857 if (m_DetectInvTimer > 0)
859 if (p_time >= m_DetectInvTimer)
861 m_DetectInvTimer = 3000;
862 HandleInvisiblePjs();
864 else
865 m_DetectInvTimer -= p_time;
868 // Played time
869 if (now > m_Last_tick)
871 uint32 elapsed = uint32(now - m_Last_tick);
872 m_Played_time[0] += elapsed; // Total played time
873 m_Played_time[1] += elapsed; // Level played time
874 m_Last_tick = now;
877 if (m_drunk)
879 m_drunkTimer += p_time;
881 if (m_drunkTimer > 30000)
882 HandleSobering();
885 if(m_deathTimer > 0)
887 if(p_time >= m_deathTimer)
889 m_deathTimer = 0;
890 BuildPlayerRepop();
891 RepopAtGraveyard();
893 else
894 m_deathTimer -= p_time;
896 UpdateEnchantTime(p_time);
899 void Player::BuildEnumData( WorldPacket * p_data )
901 *p_data << GetGUID();
902 *p_data << m_name;
904 *p_data << getRace();
905 *p_data << getClass();
906 *p_data << getGender();
908 uint32 bytes = GetUInt32Value(PLAYER_BYTES);
909 *p_data << uint8(bytes);
910 *p_data << uint8(bytes >> 8);
911 *p_data << uint8(bytes >> 16);
912 *p_data << uint8(bytes >> 24);
914 bytes = GetUInt32Value(PLAYER_BYTES_2);
915 *p_data << uint8(bytes);
917 *p_data << uint8(getLevel()); //1
918 uint32 zoneId = MapManager::Instance ().GetMap(m_mapId)->GetZoneId(m_positionX,m_positionY);
920 *p_data << zoneId;
921 *p_data << GetMapId();
923 *p_data << m_positionX;
924 *p_data << m_positionY;
925 *p_data << m_positionZ;
927 *p_data << GetUInt32Value(PLAYER_GUILDID); //probebly wrong
929 //*p_data << GetUInt32Value(PLAYER_GUILDRANK); //this was
930 *p_data << uint8(0x0);
931 *p_data << uint8(GetUInt32Value(PLAYER_FLAGS) << 1);
932 *p_data << uint8(0x0); //Bit 4 is something dono
933 *p_data << uint8(0x0); //is this player_GUILDRANK????
935 *p_data << (uint8)0;
936 *p_data << (uint32)m_petInfoId;
937 *p_data << (uint32)m_petLevel;
938 *p_data << (uint32)m_petFamilyId;
940 ItemPrototype const *items[EQUIPMENT_SLOT_END];
941 for (int i = 0; i < EQUIPMENT_SLOT_END; i++)
942 items[i] = NULL;
944 QueryResult *result = sDatabase.PQuery("SELECT `slot`,`item_template` FROM `character_inventory` WHERE `guid` = '%u' AND `bag` = 0",GetGUIDLow());
945 if (result)
949 Field *fields = result->Fetch();
950 uint8 slot = fields[0].GetUInt8() & 255;
951 uint32 item_id = fields[1].GetUInt32();
952 if( slot >= EQUIPMENT_SLOT_END )
953 continue;
955 items[slot] = objmgr.GetItemPrototype(item_id);
956 if(!items[slot])
958 sLog.outError( "Player::BuildEnumData: Player %s have unknown item (id: #%u) in inventory, skipped.", GetName(),item_id );
959 continue;
961 } while (result->NextRow());
962 delete result;
965 for (int i = 0; i < EQUIPMENT_SLOT_END; i++)
967 if (items[i] != NULL)
969 *p_data << (uint32)items[i]->DisplayInfoID;
970 *p_data << (uint8)items[i]->InventoryType;
972 else
974 *p_data << (uint32)0;
975 *p_data << (uint8)0;
978 // EQUIPMENT_SLOT_END always 0,0
979 *p_data << (uint32)0;
980 *p_data << (uint8)0;
983 bool Player::ToggleAFK()
985 if(HasFlag(PLAYER_FLAGS,PLAYER_FLAGS_AFK))
986 RemoveFlag(PLAYER_FLAGS,PLAYER_FLAGS_AFK);
987 else
988 SetFlag(PLAYER_FLAGS,PLAYER_FLAGS_AFK);
990 return HasFlag(PLAYER_FLAGS,PLAYER_FLAGS_AFK);
993 bool Player::ToggleDND()
995 if(HasFlag(PLAYER_FLAGS,PLAYER_FLAGS_DND))
996 RemoveFlag(PLAYER_FLAGS,PLAYER_FLAGS_DND);
997 else
998 SetFlag(PLAYER_FLAGS,PLAYER_FLAGS_DND);
1000 return HasFlag(PLAYER_FLAGS,PLAYER_FLAGS_DND);
1003 uint8 Player::chatTag()
1005 if(isGameMaster())
1006 return 3;
1007 else if(isDND())
1008 return 2;
1009 if(isAFK())
1010 return 1;
1011 else
1012 return 0;
1015 void Player::SendFriendlist()
1017 WorldPacket data;
1018 uint8 i=0;
1019 Field *fields;
1020 Player* pObj;
1021 FriendStr friendstr[255];
1023 QueryResult *result = sDatabase.PQuery("SELECT `friend` FROM `character_social` WHERE `flags` = 'FRIEND' AND `guid` = '%u'",GetGUIDLow());
1024 if(result)
1026 fields = result->Fetch();
1030 friendstr[i].PlayerGUID = fields[0].GetUInt64();
1031 pObj = ObjectAccessor::Instance().FindPlayer(friendstr[i].PlayerGUID);
1032 if( pObj && pObj->isVisibleFor(this))
1034 if(pObj->isAFK())
1035 friendstr[i].Status = 2;
1036 else if(pObj->isDND())
1037 friendstr[i].Status = 4;
1038 else
1039 friendstr[i].Status = 1;
1040 friendstr[i].Area = pObj->GetZoneId();
1041 friendstr[i].Level = pObj->getLevel();
1042 friendstr[i].Class = pObj->getClass();
1044 else
1046 friendstr[i].Status = 0;
1047 friendstr[i].Area = 0;
1048 friendstr[i].Level = 0;
1049 friendstr[i].Class = 0;
1051 i++;
1053 // prevent overflow
1054 if(i==255)
1055 break;
1056 } while( result->NextRow() );
1058 delete result;
1061 data.Initialize( SMSG_FRIEND_LIST );
1062 data << i;
1064 for (int j=0; j < i; j++)
1067 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 );
1069 data << friendstr[j].PlayerGUID << friendstr[j].Status ;
1070 if (friendstr[j].Status != 0)
1071 data << friendstr[j].Area << friendstr[j].Level << friendstr[j].Class;
1074 this->GetSession()->SendPacket( &data );
1075 sLog.outDebug( "WORLD: Sent (SMSG_FRIEND_LIST)" );
1078 void Player::AddToIgnoreList(uint64 guid, std::string name)
1080 // prevent list (client-side) overflow
1081 if(m_ignorelist.size() >= (255-1))
1082 return;
1084 sDatabase.PExecute("INSERT INTO `character_social` (`guid`,`name`,`friend`,`flags`) VALUES ('%u', '%s', '%u', 'IGNORE')",
1085 GetGUIDLow(), name.c_str(), GUID_LOPART(guid));
1086 m_ignorelist.insert(GUID_LOPART(guid));
1089 void Player::RemoveFromIgnoreList(uint64 guid)
1091 sDatabase.PExecute("DELETE FROM `character_social` WHERE `flags` = 'IGNORE' AND `guid` = '%u' AND `friend` = '%u'",GetGUIDLow(), GUID_LOPART(guid));
1092 m_ignorelist.erase(GUID_LOPART(guid));
1095 void Player::LoadIgnoreList()
1097 QueryResult *result = sDatabase.PQuery("SELECT `friend` FROM `character_social` WHERE `flags` = 'IGNORE' AND `guid` = '%u'", GetGUIDLow());
1099 if(!result) return;
1103 Field *fields = result->Fetch();
1104 m_ignorelist.insert(fields[0].GetUInt32());
1106 // prevent list (client-side) overflow
1107 if(m_ignorelist.size() >= 255)
1108 break;
1110 while( result->NextRow() );
1112 delete result;
1115 void Player::SendIgnorelist()
1118 if(m_ignorelist.empty())
1119 return;
1121 WorldPacket dataI;
1122 dataI.Initialize( SMSG_IGNORE_LIST );
1123 dataI << uint8(m_ignorelist.size());
1125 for(IgnoreList::iterator iter = m_ignorelist.begin(); iter != m_ignorelist.end(); ++iter)
1127 dataI << uint64(MAKE_GUID(*iter,HIGHGUID_PLAYER));
1130 GetSession()->SendPacket( &dataI );
1131 sLog.outDebug( "WORLD: Sent (SMSG_IGNORE_LIST)" );
1134 void Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientation, bool outofrange, bool ignore_transport)
1136 // prepering unsommon pet if lost (we must get pet before teleportation or will not find it later)
1137 Creature* pet = GetPet();
1139 // if we were on a transport, leave
1140 if (ignore_transport && m_transport)
1142 m_transport->RemovePassenger(this);
1143 m_transport = NULL;
1144 m_transX = 0.0f;
1145 m_transY = 0.0f;
1146 m_transZ = 0.0f;
1147 m_transO = 0.0f;
1150 if ((this->GetMapId() == mapid) && (!m_transport))
1152 // near teleport
1153 WorldPacket data;
1154 BuildTeleportAckMsg(&data, x, y, z, orientation);
1155 GetSession()->SendPacket(&data);
1156 SetPosition( x, y, z, orientation );
1157 BuildHeartBeatMsg(&data);
1158 SendMessageToSet(&data, true);
1160 else
1162 MapManager::Instance().GetMap(GetMapId())->Remove(this, false);
1163 WorldPacket data;
1164 data.Initialize(SMSG_TRANSFER_PENDING);
1165 data << uint32(mapid);
1166 if (m_transport)
1168 data << m_transport->GetEntry() << GetMapId();
1170 GetSession()->SendPacket(&data);
1172 data.Initialize(SMSG_NEW_WORLD);
1173 if (m_transport)
1175 data << (uint32)mapid << m_transX << m_transY << m_transZ << m_transO;
1177 else
1179 data << (uint32)mapid << (float)x << (float)y << (float)z << (float)orientation;
1181 GetSession()->SendPacket( &data );
1183 SetMapId(mapid);
1184 if(m_transport)
1186 Relocate(x + m_transX, y + m_transY, z + m_transZ, orientation + m_transO);
1187 SetPosition(x + m_transX, y + m_transY, z + m_transZ, orientation + m_transO);
1189 else
1191 Relocate(x, y, z, orientation);
1192 SetPosition(x, y, z, orientation);
1194 SetDontMove(true);
1195 //SaveToDB();
1197 //MapManager::Instance().GetMap(GetMapId())->Add(this);
1199 // Resend spell list to client after far teleport.
1200 SendInitialSpells();
1203 if (outofrange)
1205 CombatStop();
1207 // remove selection
1208 if(GetSelection())
1210 Unit* unit = ObjectAccessor::Instance().GetUnit(*this, GetSelection());
1211 if(unit)
1212 SendOutOfRange(unit);
1215 // unsommon pet if lost
1216 if(pet && !IsWithinDistInMap(pet, OWNER_MAX_DISTANCE))
1217 UnsummonPet(pet);
1221 void Player::AddToWorld()
1223 Object::AddToWorld();
1225 for(int i = 0; i < BANK_SLOT_BAG_END; i++)
1227 if(m_items[i])
1228 m_items[i]->AddToWorld();
1230 AddWeather();
1232 if(Corpse* corpse = GetCorpse())
1233 corpse->UpdateForPlayer(this,true);
1236 void Player::RemoveFromWorld()
1239 for(int i = 0; i < BANK_SLOT_BAG_END; i++)
1241 if(m_items[i])
1242 m_items[i]->RemoveFromWorld();
1245 Object::RemoveFromWorld();
1248 void Player::CalcRage( uint32 damage,bool attacker )
1250 uint32 addRage = 0;
1252 if(attacker)
1253 addRage = (uint32)(10*damage/(getLevel()*0.5f));
1254 else
1255 addRage = (uint32)(10*damage/(getLevel()*1.5f));
1257 ModifyPower(POWER_RAGE, addRage);
1260 void Player::RegenerateAll()
1263 if (m_regenTimer != 0)
1264 return;
1265 uint32 regenDelay = 2000;
1267 // Not in combat or they have regeneration
1268 if (!isInCombat() || HasAuraType(SPELL_AURA_MOD_REGEN_DURING_COMBAT))
1270 RegenerateHealth();
1271 if (!isInCombat())
1272 Regenerate(POWER_RAGE);
1275 Regenerate( POWER_ENERGY );
1276 Regenerate( POWER_MANA );
1278 m_regenTimer = regenDelay;
1282 void Player::Regenerate(Powers power)
1284 uint32 curValue = GetPower(power);
1285 uint32 maxValue = GetMaxPower(power);
1287 if(power != POWER_RAGE)
1289 if (curValue >= maxValue) return;
1291 else if (curValue == 0)
1292 return;
1294 float ManaIncreaseRate = sWorld.getRate(RATE_POWER_MANA);
1295 float RageIncreaseRate = sWorld.getRate(RATE_POWER_RAGE);
1297 float Spirit = GetStat(STAT_SPIRIT);
1298 uint8 Class = getClass();
1300 if( ManaIncreaseRate <= 0 ) ManaIncreaseRate = 1;
1301 if( RageIncreaseRate <= 0 ) RageIncreaseRate = 1;
1303 float addvalue = 0.0;
1305 switch (power)
1307 case POWER_MANA:
1308 // If < 5s after previous cast which used mana, no regeneration unless
1309 // we happen to have a modifer that adds it back
1310 // If > 5s, get portion between the 5s and now, up to a maximum of 2s worth
1311 uint32 msecSinceLastCast;
1312 msecSinceLastCast = ((uint32)getMSTime() - m_lastManaUse);
1313 if (msecSinceLastCast >= 7000)
1315 ManaIncreaseRate *= 1;
1317 else
1319 long regenInterrupt = GetTotalAuraModifier(SPELL_AURA_MOD_MANA_REGEN_INTERRUPT);
1320 if (msecSinceLastCast < 5000)
1322 ManaIncreaseRate *= (float)regenInterrupt / 100;
1324 else
1326 ManaIncreaseRate = (((1 - (float)(msecSinceLastCast - 5000)/2000)) * regenInterrupt)
1327 + (((float)(msecSinceLastCast - 5000)/2000) * ManaIncreaseRate * 100);
1328 ManaIncreaseRate /= 100;
1331 ManaIncreaseRate = (ManaIncreaseRate * 100 + GetTotalAuraModifier(SPELL_AURA_MOD_POWER_REGEN_PERCENT)) / 100;
1333 switch (Class)
1335 case CLASS_DRUID: addvalue = (Spirit/5 + 15) * ManaIncreaseRate; break;
1336 case CLASS_HUNTER: addvalue = (Spirit/5 + 15) * ManaIncreaseRate; break;
1337 case CLASS_MAGE: addvalue = (Spirit/4 + 12.5) * ManaIncreaseRate; break;
1338 case CLASS_PALADIN: addvalue = (Spirit/5 + 15) * ManaIncreaseRate; break;
1339 case CLASS_PRIEST: addvalue = (Spirit/4 + 12.5) * ManaIncreaseRate; break;
1340 case CLASS_SHAMAN: addvalue = (Spirit/5 + 17) * ManaIncreaseRate; break;
1341 case CLASS_WARLOCK: addvalue = (Spirit/5 + 15) * ManaIncreaseRate; break;
1343 break;
1344 case POWER_RAGE: // Regenerate rage
1345 addvalue = 30 * RageIncreaseRate; // 3 rage by tick
1346 break;
1347 case POWER_ENERGY: // Regenerate energy (rogue)
1348 addvalue = 20;
1349 break;
1350 case POWER_FOCUS:
1351 case POWER_HAPPINESS:
1352 break;
1355 if (power != POWER_RAGE)
1357 curValue += uint32(addvalue);
1358 if (curValue > maxValue) curValue = maxValue;
1360 else
1362 if(curValue <= uint32(addvalue))
1363 curValue = 0;
1364 else
1365 curValue -= uint32(addvalue);
1367 SetPower(power, curValue);
1370 void Player::RegenerateHealth()
1372 uint32 curValue = GetHealth();
1373 uint32 maxValue = GetMaxHealth();
1375 if (curValue >= maxValue) return;
1377 float HealthIncreaseRate = sWorld.getRate(RATE_HEALTH);
1379 float Spirit = GetStat(STAT_SPIRIT);
1380 uint8 Class = getClass();
1382 if( HealthIncreaseRate <= 0 ) HealthIncreaseRate = 1;
1384 float addvalue = 0.0;
1386 switch (Class)
1388 case CLASS_DRUID: addvalue = (Spirit*0.11 + 1) * HealthIncreaseRate; break;
1389 case CLASS_HUNTER: addvalue = (Spirit*0.43 - 5.5) * HealthIncreaseRate; break;
1390 case CLASS_MAGE: addvalue = (Spirit*0.11 + 1) * HealthIncreaseRate; break;
1391 case CLASS_PALADIN: addvalue = (Spirit*0.25) * HealthIncreaseRate; break;
1392 case CLASS_PRIEST: addvalue = (Spirit*0.15 + 1.4) * HealthIncreaseRate; break;
1393 case CLASS_ROGUE: addvalue = (Spirit*0.84 - 13) * HealthIncreaseRate; break;
1394 case CLASS_SHAMAN: addvalue = (Spirit*0.28 - 3.6) * HealthIncreaseRate; break;
1395 case CLASS_WARLOCK: addvalue = (Spirit*0.12 + 1.5) * HealthIncreaseRate; break;
1396 case CLASS_WARRIOR: addvalue = (Spirit*1.26 - 22.6)* HealthIncreaseRate; break;
1399 if (!isInCombat())
1401 AuraList& mModHealthRegenPct = GetAurasByType(SPELL_AURA_MOD_HEALTH_REGEN_PERCENT);
1402 for(AuraList::iterator i = mModHealthRegenPct.begin(); i != mModHealthRegenPct.end(); ++i)
1403 addvalue *= (100.0f + (*i)->GetModifier()->m_amount) / 100.0f;
1405 else
1406 addvalue *= m_AuraModifiers[SPELL_AURA_MOD_REGEN_DURING_COMBAT] / 100.0f;
1408 switch (getStandState())
1410 case PLAYER_STATE_SIT_CHAIR:
1411 case PLAYER_STATE_SIT_LOW_CHAIR:
1412 case PLAYER_STATE_SIT_MEDIUM_CHAIR:
1413 case PLAYER_STATE_SIT_HIGH_CHAIR:
1414 case PLAYER_STATE_SIT:
1415 case PLAYER_STATE_SLEEP:
1416 case PLAYER_STATE_KNEEL:
1417 addvalue *= 1.5; break;
1420 if(addvalue < 0)
1421 addvalue = 0;
1423 ModifyHealth(int32(addvalue));
1426 bool Player::isAcceptTickets() const
1428 return GetSession()->GetSecurity() >=2 && (m_GMFlags & GM_ACCEPT_TICKETS);
1431 void Player::SetGameMaster(bool on)
1433 if(on)
1435 m_GMFlags |= GM_ON;
1436 setFaction(35);
1437 SetFlag(PLAYER_BYTES_2, 0x8);
1438 SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_GM);
1440 else
1442 m_GMFlags &= ~GM_ON;
1443 setFactionForRace(getRace());
1444 RemoveFlag(PLAYER_BYTES_2, 0x8);
1445 RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_GM);
1449 void Player::SetGMVisible(bool on)
1451 if(on)
1453 m_GMFlags &= ~GM_INVISIBLE; //remove flag
1455 SetVisibility(VISIBILITY_ON);
1457 else
1459 m_GMFlags |= GM_INVISIBLE; //add flag
1461 SetAcceptWhispers(false);
1462 SetGameMaster(true);
1464 SetVisibility(VISIBILITY_OFF);
1468 void Player::SendLogXPGain(uint32 GivenXP, Unit* victim, uint32 RestXP)
1470 WorldPacket data;
1471 data.Initialize( SMSG_LOG_XPGAIN );
1472 data << ( victim ? victim->GetGUID() : uint64(0) );
1473 data << uint32(GivenXP+RestXP); // given experience
1474 data << ( victim ? (uint8)0 : (uint8)1 ); // 00-kill_xp type, 01-non_kill_xp type
1475 data << uint32(RestXP); // rested given experience
1476 data << float(1); // 1 - none 0 - 100% group bonus output
1477 GetSession()->SendPacket(&data);
1480 void Player::GiveXP(uint32 xp, Unit* victim)
1482 if ( xp < 1 )
1483 return;
1485 uint32 level = getLevel();
1487 // XP to money conversion processed in Player::RewardQuest
1488 if(level >= sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
1489 return;
1491 // XP resting bonus for kill
1492 uint32 rested_bonus_xp = victim ? GetXPRestBonus(xp) : 0;
1494 SendLogXPGain(xp,victim,rested_bonus_xp);
1496 uint32 curXP = GetUInt32Value(PLAYER_XP);
1497 uint32 nextLvlXP = GetUInt32Value(PLAYER_NEXT_LEVEL_XP);
1498 uint32 newXP = curXP + xp + rested_bonus_xp;
1500 while( newXP >= nextLvlXP && level < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL) )
1502 newXP -= nextLvlXP;
1504 GiveLevel();
1506 level = getLevel();
1507 nextLvlXP = GetUInt32Value(PLAYER_NEXT_LEVEL_XP);
1510 SetUInt32Value(PLAYER_XP, newXP);
1513 // Update player to next level
1514 // Current player expirience not update (must be update by caller)
1515 void Player::GiveLevel()
1517 uint32 level = getLevel();
1519 if ( level >= sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL) )
1520 return;
1522 level += 1;
1524 InitStatsForLevel(level);
1527 void Player::InitStatsForLevel(uint32 level, bool sendgain, bool remove_mods)
1529 // Remove item, aura, stats bonuses
1530 if(remove_mods)
1532 _RemoveAllItemMods();
1533 _RemoveAllAuraMods();
1534 _RemoveStatsMods();
1537 PlayerLevelInfo info;
1539 objmgr.GetPlayerLevelInfo(getRace(),getClass(),level,&info);
1541 if(sendgain)
1543 // send levelup info to client
1544 WorldPacket data;
1545 data.Initialize(SMSG_LEVELUP_INFO);
1546 data << uint32(level);
1547 data << uint32(int32(info.health) - GetMaxHealth());
1548 data << uint32(int32(info.mana) - GetMaxPower(POWER_MANA));
1549 data << uint32(0);
1550 data << uint32(0);
1551 data << uint32(0);
1552 data << uint32(0);
1554 for(int i = STAT_STRENGTH; i < MAX_STATS; ++i)
1555 data << uint32(int32(info.stats[i]) - GetStat(Stats(i)));
1557 GetSession()->SendPacket(&data);
1560 SetUInt32Value(PLAYER_NEXT_LEVEL_XP, MaNGOS::XP::xp_to_level(level));
1562 // talentes base at level diff ( talentes = level - 9 but some can be used already)
1563 if(level < 10)
1565 // Remove all talent points
1566 if(getLevel() >= 10) // Free any used talentes
1568 resetTalents(true);
1569 SetUInt32Value(PLAYER_CHARACTER_POINTS1,0);
1572 else
1574 // Update talent points amount
1575 if(level > getLevel()) // Add new talent points
1576 SetUInt32Value(PLAYER_CHARACTER_POINTS1,GetUInt32Value(PLAYER_CHARACTER_POINTS1)+min(level-getLevel(),level-9));
1577 else
1578 if(level < getLevel()) // Free if need talentes, remove some amount talent points
1580 if(GetUInt32Value(PLAYER_CHARACTER_POINTS1) < (getLevel() - level))
1581 resetTalents(true);
1582 SetUInt32Value(PLAYER_CHARACTER_POINTS1,GetUInt32Value(PLAYER_CHARACTER_POINTS1)-(getLevel() - level));
1586 // update level, max level of skills
1587 SetLevel( level);
1588 UpdateMaxSkills ();
1590 // save new stats
1591 SetMaxPower(POWER_MANA, info.mana);
1592 if(getPowerType() == POWER_RAGE)
1593 SetMaxPower(POWER_RAGE, 1000 );
1594 else if(getPowerType()== POWER_ENERGY)
1595 SetMaxPower(POWER_ENERGY, 100 );
1597 SetMaxPower(POWER_FOCUS, 0 );
1598 SetMaxPower(POWER_HAPPINESS, 0 );
1600 SetMaxHealth(info.health);
1602 // save base values (bonuses already included in stored stats
1603 for(int i = STAT_STRENGTH; i < MAX_STATS; ++i)
1604 SetCreateStat(Stats(i), info.stats[i]);
1606 for(int i = STAT_STRENGTH; i < MAX_STATS; ++i)
1607 SetStat(Stats(i), info.stats[i]);
1609 // reset misc. values
1610 SetAttackTime(BASE_ATTACK, 2000 );
1611 SetAttackTime(OFF_ATTACK, 2000 );
1612 SetAttackTime(RANGED_ATTACK, 2000 );
1614 SetFloatValue(UNIT_FIELD_MINDAMAGE, 0 );
1615 SetFloatValue(UNIT_FIELD_MAXDAMAGE, 0 );
1616 SetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE, 0 );
1617 SetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE, 0 );
1618 SetFloatValue(UNIT_FIELD_MINRANGEDDAMAGE, 0 );
1619 SetFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE, 0 );
1621 SetArmor(m_createStats[STAT_AGILITY]*2);
1622 SetUInt32Value(UNIT_FIELD_ATTACK_POWER, 0 );
1623 SetUInt32Value(UNIT_FIELD_RANGED_ATTACK_POWER, 0 );
1625 SetFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT, 1.00);
1626 SetFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG, 0);
1627 SetFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_POS, 0);
1629 for(int i = STAT_STRENGTH; i < MAX_STATS; ++i)
1630 SetPosStat(Stats(i), 0);
1632 for(int i = STAT_STRENGTH; i < MAX_STATS; ++i)
1633 SetNegStat(Stats(i), 0);
1635 // Base crit/parry values
1636 SetFloatValue(PLAYER_CRIT_PERCENTAGE, 5);
1637 SetFloatValue(PLAYER_PARRY_PERCENTAGE, 5);
1639 // Base dodge values
1640 switch(getClass())
1642 case CLASS_PALADIN: SetFloatValue(PLAYER_DODGE_PERCENTAGE, 0.75); break;
1643 case CLASS_HUNTER: SetFloatValue(PLAYER_DODGE_PERCENTAGE, 0.64); break;
1644 case CLASS_PRIEST: SetFloatValue(PLAYER_DODGE_PERCENTAGE, 3.0 ); break;
1645 case CLASS_SHAMAN: SetFloatValue(PLAYER_DODGE_PERCENTAGE, 1.75); break;
1646 case CLASS_MAGE: SetFloatValue(PLAYER_DODGE_PERCENTAGE, 3.25); break;
1647 case CLASS_WARLOCK: SetFloatValue(PLAYER_DODGE_PERCENTAGE, 2.0 ); break;
1648 case CLASS_DRUID: SetFloatValue(PLAYER_DODGE_PERCENTAGE, 0.75); break;
1649 case CLASS_ROGUE:
1650 case CLASS_WARRIOR:
1651 default: SetFloatValue(PLAYER_DODGE_PERCENTAGE, 0.0 ); break;
1654 // set armor (resistence 0) to original value (create_agility*2)
1655 SetArmor(m_createStats[STAT_AGILITY]*2);
1656 SetResistanceBuffMods(SpellSchools(0), true, 0);
1657 SetResistanceBuffMods(SpellSchools(0), false, 0);
1658 // set other resistence to original value (0)
1659 for (int i = 1; i < MAX_SPELL_SCHOOOL; i++)
1661 SetResistance(SpellSchools(i), 0);
1662 SetResistanceBuffMods(SpellSchools(i), true, 0);
1663 SetResistanceBuffMods(SpellSchools(i), false, 0);
1666 // cleanup mounted state (it will set correctly at aura loading if player saved at mount.
1667 SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID, 0);
1668 RemoveFlag( UNIT_FIELD_FLAGS, UNIT_FLAG_MOUNT );
1670 // apply stats, aura, items mods
1671 if(remove_mods)
1673 _ApplyStatsMods();
1674 _ApplyAllAuraMods();
1675 _ApplyAllItemMods();
1678 // update dependent from level part BlockChanceWithoutMods = 5 + (GetDefenceSkillValue() - getLevel()*5)*0.04);
1679 // must called with applied AuraMods (removed in call code)
1680 UpdateBlockPercentage();
1682 // set current level health and mana/energy to maximum after appling all mods.
1683 SetHealth(GetMaxHealth());
1684 SetPower(POWER_MANA, GetMaxPower(POWER_MANA));
1685 SetPower(POWER_ENERGY, GetMaxPower(POWER_ENERGY));
1686 if(GetPower(POWER_RAGE) > GetMaxPower(POWER_RAGE))
1687 SetPower(POWER_RAGE, GetMaxPower(POWER_RAGE));
1688 SetPower(POWER_FOCUS, 0);
1689 SetPower(POWER_HAPPINESS, 0);
1691 // Level Played Time reset
1692 m_Played_time[1] = 0;
1695 void Player::SendInitialSpells()
1697 WorldPacket data;
1698 uint16 spellCount = 0;
1700 PlayerSpellMap::const_iterator itr;
1702 for (itr = m_spells.begin(); itr != m_spells.end(); ++itr)
1704 if(itr->second->state == PLAYERSPELL_REMOVED)
1705 continue;
1707 if(itr->second->active)
1708 spellCount +=1;
1711 data.Initialize( SMSG_INITIAL_SPELLS );
1712 data << uint8(0);
1713 data << uint16(spellCount);
1715 for (itr = m_spells.begin(); itr != m_spells.end(); ++itr)
1717 if(itr->second->state == PLAYERSPELL_REMOVED)
1718 continue;
1720 if(!itr->second->active)
1721 continue;
1723 data << uint16(itr->first);
1724 data << uint16(itr->second->slotId);
1726 data << uint16(0);
1728 WPAssert(data.size() == 5+(4*size_t(spellCount)));
1730 GetSession()->SendPacket(&data);
1732 sLog.outDetail( "CHARACTER: Sent Initial Spells" );
1735 void Player::RemoveMail(uint32 id)
1737 std::deque<Mail*>::iterator itr;
1738 for (itr = m_mail.begin(); itr != m_mail.end();++itr)
1740 if ((*itr)->messageID == id)
1742 //do not delete item. beacuse Player::removeMail() is called when returning mail to sender.
1743 m_mail.erase(itr);
1744 return;
1749 //call this function when mail receiver is online
1750 void Player::CreateMail(uint32 mailId, uint8 messageType, uint32 sender, std::string subject, uint32 itemPageId, uint32 itemGuid, uint32 item_template, time_t etime, uint32 money, uint32 COD, uint32 checked, Item* pItem)
1752 if ( !m_mailsLoaded )
1754 if ( pItem )
1755 delete pItem;
1756 return;
1758 Mail * m = new Mail;
1759 m->messageID = mailId;
1760 m->messageType = messageType;
1761 m->sender = sender;
1762 m->receiver = this->GetGUIDLow();
1763 m->subject = subject;
1764 m->itemPageId = itemPageId;
1765 m->item_guid = itemGuid;
1766 m->item_template = item_template;
1767 m->time = etime;
1768 m->money = money;
1769 m->COD = COD;
1770 m->checked = checked;
1771 m->state = UNCHANGED;
1773 AddMail(m);
1774 if ( pItem )
1775 AddMItem(pItem);
1778 void Player::SendMailResult(uint32 mailId, uint32 mailAction, uint32 mailError, uint32 equipError)
1780 WorldPacket data;
1781 data.Initialize(SMSG_SEND_MAIL_RESULT);
1782 data << (uint32) mailId;
1783 data << (uint32) mailAction;
1784 data << (uint32) mailError;
1785 if (equipError)
1786 data << (uint32) equipError;
1787 GetSession()->SendPacket(&data);
1790 //call this function only when sending new mail
1791 void Player::AddMail(Mail *m)
1793 WorldPacket data;
1795 data.Initialize(SMSG_RECEIVED_MAIL);
1796 data << (uint32) 0;
1797 GetSession()->SendPacket(&data);
1798 unReadMails++;
1800 if(!m_mailsLoaded)
1802 delete m;
1803 return;
1805 m_mail.push_front(m); //to insert new mail to beginning of maillist
1808 bool Player::addSpell(uint16 spell_id, uint8 active, PlayerSpellState state, uint16 slot_id)
1810 SpellEntry *spellInfo = sSpellStore.LookupEntry(spell_id);
1811 if (!spellInfo)
1813 sLog.outError("Player::addSpell: Non-existed in SpellStore spell #%u request.",spell_id);
1814 return false;
1817 PlayerSpellMap::iterator itr = m_spells.find(spell_id);
1818 if (itr != m_spells.end())
1820 if (itr->second->state == PLAYERSPELL_REMOVED)
1822 delete itr->second;
1823 m_spells.erase(itr);
1824 state = PLAYERSPELL_CHANGED;
1826 else
1827 return false;
1830 PlayerSpell *newspell;
1832 newspell = new PlayerSpell;
1833 newspell->active = active;
1834 newspell->state = state;
1836 WorldPacket data;
1837 if(newspell->active && !canStackSpellRank(spellInfo))
1839 PlayerSpellMap::iterator itr;
1840 for (itr = m_spells.begin(); itr != m_spells.end(); itr++)
1842 if(itr->second->state == PLAYERSPELL_REMOVED) continue;
1843 SpellEntry *i_spellInfo = sSpellStore.LookupEntry(itr->first);
1844 if(!i_spellInfo) continue;
1846 if(IsRankSpellDueToSpell(spellInfo,itr->first))
1848 if(itr->second->active)
1850 data.Initialize(SMSG_SUPERCEDED_SPELL);
1852 if(FindSpellRank(spell_id) >= FindSpellRank(itr->first))
1854 data << uint32(itr->first);
1855 data << uint32(spell_id);
1856 itr->second->active = 0;
1858 else
1860 data << uint32(spell_id);
1861 data << uint32(itr->first);
1862 newspell->active = 0;
1865 GetSession()->SendPacket( &data );
1871 uint16 tmpslot=slot_id;
1873 if (tmpslot == 0xffff)
1875 uint16 maxid = 0;
1876 PlayerSpellMap::iterator itr;
1877 for (itr = m_spells.begin(); itr != m_spells.end(); ++itr)
1879 if(itr->second->state == PLAYERSPELL_REMOVED) continue;
1880 if (itr->second->slotId > maxid) maxid = itr->second->slotId;
1882 tmpslot = maxid + 1;
1885 newspell->slotId = tmpslot;
1886 m_spells[spell_id] = newspell;
1888 if (IsPassiveSpell(spell_id))
1890 // if spell doesnt require a stance or the player is in the required stance
1891 if ((!spellInfo->Stances && spell_id != 5419) || (spellInfo->Stances & (1<<(m_form-1)) || (spell_id == 5419 && m_form == FORM_TRAVEL)))
1892 CastSpell(this, spell_id, true);
1895 return true;
1898 void Player::learnSpell(uint16 spell_id)
1900 SpellEntry *spellInfo = sSpellStore.LookupEntry(spell_id);
1901 if (!spellInfo)
1903 sLog.outError("Player::addSpell: Non-existed in SpellStore spell #%u request.",spell_id);
1904 return;
1907 WorldPacket data;
1908 data.Initialize(SMSG_LEARNED_SPELL);
1909 data <<uint32(spell_id);
1910 GetSession()->SendPacket(&data);
1912 if (!addSpell(spell_id,1))
1913 return;
1915 uint16 maxskill = getLevel()*5 > 300 ? 300 :getLevel()*5;
1916 switch(spell_id)
1918 //Armor
1919 case 9078: //Cloth
1920 SetSkill(415,1,1);
1921 break;
1922 case 9077: //Leather
1923 SetSkill(414,1,1);
1924 break;
1925 case 8737: //Mail
1926 SetSkill(413,1,1);
1927 break;
1928 case 750: //Plate Mail
1929 SetSkill(293,1,1);
1930 break;
1931 case 9116: //Shield
1932 SetSkill(433,1,1);
1933 break;
1934 //Melee Weapons
1935 case 196: //Axes
1936 SetSkill(44,1,maxskill);
1937 break;
1938 case 197: //Two-Handed Axes
1939 SetSkill(172,1,maxskill);
1940 break;
1941 case 227: //Staves
1942 SetSkill(136,1,maxskill);
1943 break;
1944 case 198: //Maces
1945 SetSkill(54,1,maxskill);
1946 break;
1947 case 199: //Two-Handed Maces
1948 SetSkill(160,1,maxskill);
1949 break;
1950 case 201: //Swords
1951 SetSkill(43,1,maxskill);
1952 break;
1953 case 202: //Two-Handed Swords
1954 SetSkill(55,1,maxskill);
1955 break;
1956 case 1180: //Daggers
1957 SetSkill(173,1,maxskill);
1958 break;
1959 case 15590: //Fist Weapons
1960 SetSkill(473,1,maxskill);
1961 break;
1962 case 200: //Polearms
1963 SetSkill(229,1,maxskill);
1964 break;
1965 case 3386: //Polearms
1966 SetSkill(227,1,maxskill);
1967 break;
1968 //Range Weapons
1969 case 264: //Bows
1970 SetSkill(45,1,maxskill);
1971 break;
1972 case 5011: //Crossbows
1973 SetSkill(226,1,maxskill);
1974 break;
1975 case 266: //Guns
1976 SetSkill(46,1,maxskill);
1977 break;
1978 case 2567: //Thrown
1979 SetSkill(176,1,maxskill);
1980 break;
1981 case 5009: //Wands
1982 SetSkill(228,1,maxskill);
1983 break;
1984 //Others
1985 case 2842: //poisons
1986 SetSkill(40,1,maxskill);
1987 break;
1988 // Languages
1989 case 668: case 669: case 670: case 671: case 672: case 813: case 814:
1990 case 815: case 816: case 817: case 7340: case 7341: case 17737:
1991 if(LanguageDesc const* lang = GetLanguageDescBySpell(spell_id))
1992 SetSkill(lang->skill_id,1,300);
1993 break;
1994 default:break;
1998 bool Player::removeSpell(uint16 spell_id)
2000 PlayerSpellMap::iterator itr = m_spells.find(spell_id);
2001 if (itr != m_spells.end())
2003 if(itr->second->state == PLAYERSPELL_REMOVED) return false;
2005 WorldPacket data;
2006 data.Initialize(SMSG_REMOVED_SPELL);
2007 data << itr->first;
2008 GetSession()->SendPacket(&data);
2010 if(itr->second->state == PLAYERSPELL_NEW)
2012 delete itr->second;
2013 m_spells.erase(itr);
2015 else
2016 itr->second->state = PLAYERSPELL_REMOVED;
2018 RemoveAurasDueToSpell(spell_id);
2019 return true;
2021 return false;
2024 void Player::_LoadSpellCooldowns()
2026 m_spellCooldowns.clear();
2028 QueryResult *result = sDatabase.PQuery("SELECT `spell`,`time` FROM `character_spell_cooldown` WHERE `guid` = '%u'",GetGUIDLow());
2030 if(result)
2032 time_t curTime = time(NULL);
2034 WorldPacket data;
2036 data.Initialize(SMSG_SPELL_COOLDOWN);
2037 data << GetGUID();
2041 Field *fields = result->Fetch();
2043 uint32 spell_id = fields[0].GetUInt32();
2044 time_t db_time = (time_t)fields[1].GetUInt64();
2046 if(!sSpellStore.LookupEntry(spell_id))
2048 sLog.outError("Player %u have unknown spell %u in `character_spell_cooldown`, skipping.",GetGUIDLow(),spell_id);
2049 continue;
2052 // skip outdated cooldown
2053 if(db_time <= curTime)
2054 continue;
2056 data << uint32(spell_id);
2057 data << uint32(uint32(db_time-curTime)*1000); // in m.secs
2059 AddSpellCooldown(spell_id,db_time);
2061 sLog.outDebug("Player (GUID: %u) spell %u cooldown loaded (%u secs).",GetGUIDLow(),spell_id,uint32(db_time-curTime));
2063 while( result->NextRow() );
2065 delete result;
2067 if(m_spellCooldowns.size() > 0)
2068 GetSession()->SendPacket(&data);
2071 // setup item coldowns
2072 if(m_spellCooldowns.size() > 0)
2074 for(int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; i++)
2076 if(Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ))
2078 for(int ii = 0; ii < 5; ++ii)
2080 uint32 spell_id = pItem->GetProto()->Spells[ii].SpellId;
2081 if(spell_id != 0 && HaveSpellCooldown(spell_id))
2083 sLog.outDebug("Item (GUID: %u Entry: %u) for spell: %u cooldown loaded.",pItem->GetGUIDLow(),pItem->GetEntry(),spell_id);
2084 WorldPacket data;
2085 data.Initialize(SMSG_ITEM_COOLDOWN);
2086 data << pItem->GetGUID();
2087 data << uint32(spell_id);
2088 GetSession()->SendPacket(&data);
2089 break;
2094 for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)
2096 if(Bag *pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i ))
2098 for(uint32 j = 0; j < pBag->GetProto()->ContainerSlots; j++)
2100 if(Item* pItem = GetItemByPos( i, j ))
2102 for(int ii = 0; ii < 5; ++ii)
2104 uint32 spell_id = pItem->GetProto()->Spells[ii].SpellId;
2105 if(spell_id != 0 && HaveSpellCooldown(spell_id))
2107 sLog.outDebug("Item (GUID: %u Entry: %u) for spell: %u cooldown loaded.",pItem->GetGUIDLow(),pItem->GetEntry(),spell_id);
2108 WorldPacket data;
2109 data.Initialize(SMSG_ITEM_COOLDOWN);
2110 data << pItem->GetGUID();
2111 data << uint32(spell_id);
2112 GetSession()->SendPacket(&data);
2113 break;
2123 void Player::_SaveSpellCooldowns()
2125 sDatabase.PExecute("DELETE FROM `character_spell_cooldown` WHERE `guid` = '%u'", GetGUIDLow());
2127 time_t curTime = time(NULL);
2129 // remove oudated and save active
2130 for(SpellCooldowns::iterator itr = m_spellCooldowns.begin();itr != m_spellCooldowns.end();)
2132 if(itr->second <= curTime)
2133 m_spellCooldowns.erase(itr++);
2134 else
2136 sDatabase.PExecute("INSERT INTO `character_spell_cooldown` (`guid`,`spell`,`time`) VALUES ('%u', '%u', '" I64FMTD "')", GetGUIDLow(), itr->first, uint64(itr->second));
2137 ++itr;
2142 uint32 Player::resetTalentsCost() const
2144 // The first time reset costs 1 gold
2145 if(m_resetTalentsCost < 1*GOLD)
2146 return 1*GOLD;
2147 // then 5 gold
2148 else if(m_resetTalentsCost < 5*GOLD)
2149 return 5*GOLD;
2150 // After that it increases in increments of 5 gold
2151 else if(m_resetTalentsCost < 10*GOLD)
2152 return 10*GOLD;
2153 else
2155 uint32 months = (sWorld.GetLastTickTime() - m_resetTalentsTime)/MONTH;
2156 if(months > 0)
2158 // This cost will be reduced by a rate of 5 gold per month
2159 int32 new_cost = int32(m_resetTalentsCost) - 5*GOLD*months;
2160 // to a minimum of 10 gold.
2161 return (new_cost < 10*GOLD ? 10*GOLD : new_cost);
2163 else
2165 // After that it increases in increments of 5 gold
2166 int32 new_cost = m_resetTalentsCost + 5*GOLD;
2167 // until it hits a cap of 50 gold.
2168 if(new_cost > 50*GOLD)
2169 new_cost = 50*GOLD;
2170 return new_cost;
2175 bool Player::resetTalents(bool no_cost)
2177 uint32 level = getLevel();
2178 if (level < 10 || (GetUInt32Value(PLAYER_CHARACTER_POINTS1) >= level - 9))
2179 return false;
2181 uint32 cost = 0;
2183 if(!no_cost)
2185 cost = resetTalentsCost();
2187 if (GetMoney() < cost)
2189 SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, 0, 0, 0);
2190 return false;
2194 for (int i = 0; i < sTalentStore.GetNumRows(); i++)
2196 TalentEntry *talentInfo = sTalentStore.LookupEntry(i);
2197 if (!talentInfo) continue;
2198 for (int j = 0; j < 5; j++)
2200 SpellEntry *spellInfo = sSpellStore.LookupEntry(talentInfo->RankID[j]);
2201 if (!spellInfo) continue;
2202 const PlayerSpellMap& s_list = GetSpellMap();
2203 for(PlayerSpellMap::const_iterator itr = s_list.begin(); itr != s_list.end(); ++itr)
2205 if(itr->second->state == PLAYERSPELL_REMOVED) continue;
2206 if (itr->first == spellInfo->Id)
2208 RemoveAurasDueToSpell(itr->first);
2209 removeSpell(itr->first);
2210 break;
2216 SetUInt32Value(PLAYER_CHARACTER_POINTS1, level - 9);
2218 if(!no_cost)
2220 ModifyMoney(-(int32)cost);
2222 m_resetTalentsCost = cost;
2223 m_resetTalentsTime = time(NULL);
2225 return true;
2228 bool Player::_removeSpell(uint16 spell_id)
2230 PlayerSpellMap::iterator itr = m_spells.find(spell_id);
2231 if (itr != m_spells.end())
2233 delete itr->second;
2234 m_spells.erase(itr);
2235 return true;
2237 return false;
2240 Mail* Player::GetMail(uint32 id)
2242 std::deque<Mail*>::iterator itr;
2243 for (itr = m_mail.begin(); itr != m_mail.end(); itr++)
2245 if ((*itr)->messageID == id)
2247 return (*itr);
2250 return NULL;
2253 void Player::_SetCreateBits(UpdateMask *updateMask, Player *target) const
2255 if(target == this)
2257 Object::_SetCreateBits(updateMask, target);
2259 else
2261 UpdateMask mask;
2262 mask.SetCount(m_valuesCount);
2263 _SetVisibleBits(&mask, target);
2265 for(uint16 index = 0; index < m_valuesCount; index++)
2267 if(GetUInt32Value(index) != 0 && mask.GetBit(index))
2268 updateMask->SetBit(index);
2273 void Player::_SetUpdateBits(UpdateMask *updateMask, Player *target) const
2275 if(target == this)
2277 Object::_SetUpdateBits(updateMask, target);
2279 else
2281 UpdateMask mask;
2282 mask.SetCount(m_valuesCount);
2283 _SetVisibleBits(&mask, target);
2285 Object::_SetUpdateBits(updateMask, target);
2286 *updateMask &= mask;
2290 void Player::_SetVisibleBits(UpdateMask *updateMask, Player *target) const
2292 updateMask->SetBit(OBJECT_FIELD_GUID);
2293 updateMask->SetBit(OBJECT_FIELD_TYPE);
2294 updateMask->SetBit(OBJECT_FIELD_SCALE_X);
2296 updateMask->SetBit(UNIT_FIELD_SUMMON);
2297 updateMask->SetBit(UNIT_FIELD_SUMMON+1);
2299 updateMask->SetBit(UNIT_FIELD_TARGET);
2300 updateMask->SetBit(UNIT_FIELD_TARGET+1);
2302 updateMask->SetBit(UNIT_FIELD_HEALTH);
2303 updateMask->SetBit(UNIT_FIELD_POWER1);
2304 updateMask->SetBit(UNIT_FIELD_POWER2);
2305 updateMask->SetBit(UNIT_FIELD_POWER3);
2306 updateMask->SetBit(UNIT_FIELD_POWER4);
2307 updateMask->SetBit(UNIT_FIELD_POWER5);
2309 updateMask->SetBit(UNIT_FIELD_MAXHEALTH);
2310 updateMask->SetBit(UNIT_FIELD_MAXPOWER1);
2311 updateMask->SetBit(UNIT_FIELD_MAXPOWER2);
2312 updateMask->SetBit(UNIT_FIELD_MAXPOWER3);
2313 updateMask->SetBit(UNIT_FIELD_MAXPOWER4);
2314 updateMask->SetBit(UNIT_FIELD_MAXPOWER5);
2316 updateMask->SetBit(UNIT_FIELD_LEVEL);
2317 updateMask->SetBit(UNIT_FIELD_FACTIONTEMPLATE);
2318 updateMask->SetBit(UNIT_FIELD_BYTES_0);
2319 updateMask->SetBit(UNIT_FIELD_FLAGS);
2320 for(uint16 i = UNIT_FIELD_AURA; i < UNIT_FIELD_AURASTATE; i ++)
2321 updateMask->SetBit(i);
2322 updateMask->SetBit(UNIT_FIELD_BASEATTACKTIME);
2323 updateMask->SetBit(UNIT_FIELD_OFFHANDATTACKTIME);
2324 updateMask->SetBit(UNIT_FIELD_RANGEDATTACKTIME);
2325 updateMask->SetBit(UNIT_FIELD_BOUNDINGRADIUS);
2326 updateMask->SetBit(UNIT_FIELD_COMBATREACH);
2327 updateMask->SetBit(UNIT_FIELD_DISPLAYID);
2328 updateMask->SetBit(UNIT_FIELD_NATIVEDISPLAYID);
2329 updateMask->SetBit(UNIT_FIELD_MOUNTDISPLAYID);
2330 updateMask->SetBit(UNIT_FIELD_BYTES_1);
2331 updateMask->SetBit(UNIT_FIELD_MOUNTDISPLAYID);
2332 updateMask->SetBit(UNIT_FIELD_PETNUMBER);
2333 updateMask->SetBit(UNIT_FIELD_PET_NAME_TIMESTAMP);
2334 updateMask->SetBit(UNIT_DYNAMIC_FLAGS);
2336 updateMask->SetBit(PLAYER_FLAGS);
2337 updateMask->SetBit(PLAYER_BYTES);
2338 updateMask->SetBit(PLAYER_BYTES_2);
2339 updateMask->SetBit(PLAYER_BYTES_3);
2340 updateMask->SetBit(PLAYER_GUILDID);
2341 updateMask->SetBit(PLAYER_GUILDRANK);
2342 updateMask->SetBit(PLAYER_GUILD_TIMESTAMP);
2343 updateMask->SetBit(PLAYER_DUEL_TEAM);
2344 updateMask->SetBit(PLAYER_DUEL_ARBITER);
2345 updateMask->SetBit(PLAYER_DUEL_ARBITER+1);
2347 for(uint16 i = 0; i < INVENTORY_SLOT_BAG_END; i++)
2350 updateMask->SetBit((uint16)(PLAYER_FIELD_INV_SLOT_HEAD + i*2));
2352 updateMask->SetBit((uint16)(PLAYER_FIELD_INV_SLOT_HEAD + (i*2) + 1));
2355 //Players visible items are not inventory stuff
2356 //431) = 884 (0x374) = main weapon
2357 for(uint16 i = 0; i < EQUIPMENT_SLOT_END; i++)
2359 updateMask->SetBit((uint16)(PLAYER_VISIBLE_ITEM_1_0 + (i*12)));
2360 //updateMask->SetBit((uint16)(PLAYER_VISIBLE_ITEM_1_0 + 1 + (i*12)));
2363 updateMask->SetBit(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY);
2364 updateMask->SetBit(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY_01);
2365 updateMask->SetBit(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY_02);
2366 updateMask->SetBit(UNIT_VIRTUAL_ITEM_INFO);
2367 updateMask->SetBit(UNIT_VIRTUAL_ITEM_INFO_01);
2368 updateMask->SetBit(UNIT_VIRTUAL_ITEM_INFO_02);
2369 updateMask->SetBit(UNIT_VIRTUAL_ITEM_INFO_03);
2370 updateMask->SetBit(UNIT_VIRTUAL_ITEM_INFO_04);
2371 updateMask->SetBit(UNIT_VIRTUAL_ITEM_INFO_05);
2375 void Player::BuildCreateUpdateBlockForPlayer( UpdateData *data, Player *target ) const
2378 for(int i = 0; i < EQUIPMENT_SLOT_END; i++)
2380 if(m_items[i] == NULL)
2381 continue;
2383 m_items[i]->BuildCreateUpdateBlockForPlayer( data, target );
2386 if(target == this)
2389 for(int i = EQUIPMENT_SLOT_END; i < BANK_SLOT_BAG_END; i++)
2391 if(m_items[i] == NULL)
2392 continue;
2394 m_items[i]->BuildCreateUpdateBlockForPlayer( data, target );
2398 Unit::BuildCreateUpdateBlockForPlayer( data, target );
2401 void Player::DestroyForPlayer( Player *target ) const
2403 Unit::DestroyForPlayer( target );
2405 for(int i = 0; i < INVENTORY_SLOT_BAG_END; i++)
2407 if(m_items[i] == NULL)
2408 continue;
2410 m_items[i]->DestroyForPlayer( target );
2413 if(target == this)
2416 for(int i = EQUIPMENT_SLOT_END; i < BANK_SLOT_BAG_END; i++)
2418 if(m_items[i] == NULL)
2419 continue;
2421 m_items[i]->DestroyForPlayer( target );
2426 bool Player::HasSpell(uint32 spell) const
2428 PlayerSpellMap::const_iterator itr = m_spells.find((uint16)spell);
2429 return (itr != m_spells.end() && itr->second->state != PLAYERSPELL_REMOVED);
2431 // Look in the effects of spell , if is a Learn Spell Effect, see if is equal to triggerspell
2432 // If inst, look if have this spell.
2433 /*for (PlayerSpellMap::const_iterator itr = m_spells.begin(); itr != m_spells.end(); ++itr)
2435 for(uint8 i=0;i<3;i++)
2437 if(spellInfo->Effect[i]==36) // Learn Spell effect
2439 if ( itr->first == spellInfo->EffectTriggerSpell[i] )
2440 return true;
2442 else if(itr->first == spellInfo->Id)
2443 return true;
2447 return false;*/
2450 bool Player::CanLearnProSpell(uint32 spell)
2452 SpellEntry *spellInfo = sSpellStore.LookupEntry(spell);
2454 if (!spellInfo)
2455 return false;
2456 if(spellInfo->Effect[0] != 36)
2457 return true;
2459 uint32 skill = spellInfo->EffectMiscValue[1];
2460 uint32 value = 0;
2462 if( skill != SKILL_HERBALISM && skill != SKILL_MINING && skill != SKILL_LEATHERWORKING
2463 && skill != SKILL_BLACKSMITHING && skill != SKILL_ALCHEMY && skill != SKILL_ENCHANTING
2464 && skill != SKILL_TAILORING && skill != SKILL_ENGINERING && skill != SKILL_SKINNING)
2465 return true;
2467 for (PlayerSpellMap::const_iterator itr = m_spells.begin(); itr != m_spells.end(); ++itr)
2469 if (itr->second->state == PLAYERSPELL_REMOVED) continue;
2470 SpellEntry *pSpellInfo = sSpellStore.LookupEntry(itr->first);
2471 if(!pSpellInfo) continue;
2473 if(pSpellInfo->Effect[1] == SPELL_EFFECT_SKILL)
2475 uint32 pskill = pSpellInfo->EffectMiscValue[1];
2476 if( pskill != SKILL_HERBALISM && pskill != SKILL_MINING && pskill != SKILL_LEATHERWORKING
2477 && pskill != SKILL_BLACKSMITHING && pskill != SKILL_ALCHEMY && pskill != SKILL_ENCHANTING
2478 && pskill != SKILL_TAILORING && pskill != SKILL_ENGINERING && pskill != SKILL_SKINNING)
2479 continue;
2481 // not check prof count for not first prof. spells (when skill already known)
2482 if(pskill == skill)
2483 return true;
2485 // count only first rank prof. spells
2486 if(FindSpellRank(pSpellInfo->Id)==1)
2487 value += 1;
2490 if(value >= sWorld.getConfig(CONFIG_MAX_PRIMARY_TRADE_SKILL))
2491 return false;
2492 else return true;
2495 void Player::DeleteFromDB()
2497 uint32 guid = GetGUIDLow();
2499 // convert corpse to bones if exist (to prevent exiting Corpse in World without DB entry)
2500 // bones will be deleted by corpse/bones deleting thread shortly
2501 SpawnCorpseBones();
2503 // remove from guild
2504 if(GetGuildId() != 0)
2506 Guild* guild = objmgr.GetGuildById(GetGuildId());
2507 if(guild)
2508 guild->DelMember(guid);
2511 // remove signs from petitions (also remove petitions if owner);
2512 RemovePetitionsAndSigns(GetGUID());
2514 sDatabase.PExecute("DELETE FROM `character` WHERE `guid` = '%u'",guid);
2515 sDatabase.PExecute("DELETE FROM `character_aura` WHERE `guid` = '%u'",guid);
2516 sDatabase.PExecute("DELETE FROM `character_spell` WHERE `guid` = '%u'",guid);
2517 sDatabase.PExecute("DELETE FROM `character_tutorial` WHERE `guid` = '%u'",guid);
2518 sDatabase.PExecute("DELETE FROM `item_instance` WHERE `guid` IN ( SELECT `item` FROM `character_inventory` WHERE `guid` = '%u' )",guid);
2519 sDatabase.PExecute("DELETE FROM `character_inventory` WHERE `guid` = '%u'",guid);
2521 sDatabase.PExecute("DELETE FROM `character_social` WHERE `guid` = '%u' OR `friend`='%u'",guid,guid);
2522 sDatabase.PExecute("DELETE FROM `item_instance` WHERE `guid` IN ( SELECT `item_guid` FROM `mail` WHERE `receiver` = '%u' AND `item_guid` > 0 ",guid);
2523 m_ignorelist.clear();
2525 sDatabase.PExecute("DELETE FROM `mail` WHERE `receiver` = '%u'",guid);
2526 sDatabase.PExecute("DELETE FROM `character_pet` WHERE `owner` = '%u'",guid);
2528 //loginDatabase.PExecute("UPDATE `realmcharacters` SET `numchars` = `numchars` - 1 WHERE `acctid` = %d AND `realmid` = %d", GetSession()->GetAccountId(), realmID);
2529 QueryResult *resultCount = sDatabase.PQuery("SELECT COUNT(guid) FROM `character` WHERE `account` = '%d'", GetSession()->GetAccountId());
2530 uint32 charCount = 0;
2531 if (resultCount)
2533 Field *fields = resultCount->Fetch();
2534 charCount = fields[0].GetUInt32();
2535 delete resultCount;
2536 loginDatabase.PExecute("INSERT INTO `realmcharacters` (`numchars`, `acctid`, `realmid`) VALUES (%d, %d, %d) ON DUPLICATE KEY UPDATE `numchars` = '%d'", charCount, GetSession()->GetAccountId(), realmID, charCount);
2539 for(int i = 0; i < BANK_SLOT_ITEM_END; i++)
2541 if(m_items[i] == NULL)
2542 continue;
2543 m_items[i]->DeleteFromDB(); // Bag items delete also by virtual call Bag::DeleteFromDB
2546 sDatabase.PExecute("DELETE FROM `character_queststatus` WHERE `guid` = '%u'",guid);
2547 sDatabase.PExecute("DELETE FROM `character_action` WHERE `guid` = '%u'",guid);
2548 sDatabase.PExecute("DELETE FROM `character_reputation` WHERE `guid` = '%u'",guid);
2549 sDatabase.PExecute("DELETE FROM `character_homebind` WHERE `guid` = '%u'",guid);
2550 sDatabase.PExecute("DELETE FROM `character_kill` WHERE `guid` = '%u'",guid);
2551 sDatabase.PExecute("DELETE FROM `character_stable` WHERE `owner` = '%u'",guid);
2554 void Player::SetMovement(uint8 pType)
2556 WorldPacket data;
2558 switch(pType)
2560 case MOVE_ROOT:
2562 data.Initialize(SMSG_FORCE_MOVE_ROOT);
2563 data.append(GetPackGUID());
2564 GetSession()->SendPacket( &data );
2565 }break;
2566 case MOVE_UNROOT:
2568 data.Initialize(SMSG_FORCE_MOVE_UNROOT);
2569 data.append(GetPackGUID());
2570 GetSession()->SendPacket( &data );
2571 }break;
2572 case MOVE_WATER_WALK:
2574 data.Initialize(SMSG_MOVE_WATER_WALK);
2575 data.append(GetPackGUID());
2576 GetSession()->SendPacket( &data );
2577 }break;
2578 case MOVE_LAND_WALK:
2580 data.Initialize(SMSG_MOVE_LAND_WALK);
2581 data.append(GetPackGUID());
2582 GetSession()->SendPacket( &data );
2583 }break;
2584 default:break;
2588 void Player::SetPlayerSpeed(uint8 SpeedType, float value, bool forced)
2590 WorldPacket data;
2592 switch(SpeedType)
2594 case MOVE_RUN:
2596 SetSpeed( value / SPEED_RUN );
2597 if(forced) { data.Initialize(SMSG_FORCE_RUN_SPEED_CHANGE); }
2598 else { data.Initialize(MSG_MOVE_SET_RUN_SPEED); }
2599 data.append(GetPackGUID());
2600 data << (uint32)0;
2601 data << float(value);
2602 GetSession()->SendPacket( &data );
2603 }break;
2604 case MOVE_WALKBACK:
2606 SetSpeed( value / SPEED_WALKBACK );
2607 if(forced) { data.Initialize(SMSG_FORCE_RUN_BACK_SPEED_CHANGE); }
2608 else { data.Initialize(MSG_MOVE_SET_RUN_BACK_SPEED); }
2609 data.append(GetPackGUID());
2610 data << (uint32)0;
2611 data << float(value);
2612 GetSession()->SendPacket( &data );
2613 }break;
2614 case MOVE_SWIM:
2616 SetSpeed( value / SPEED_SWIM );
2617 if(forced) { data.Initialize(SMSG_FORCE_SWIM_SPEED_CHANGE); }
2618 else { data.Initialize(MSG_MOVE_SET_SWIM_SPEED); }
2619 data.append(GetPackGUID());
2620 data << (uint32)0;
2621 data << float(value);
2622 GetSession()->SendPacket( &data );
2623 }break;
2624 case MOVE_SWIMBACK:
2626 SetSpeed( value / SPEED_SWIMBACK );
2627 data.Initialize(MSG_MOVE_SET_SWIM_BACK_SPEED);
2628 data.append(GetPackGUID());
2629 data << (uint32)0;
2630 data << float(value);
2631 GetSession()->SendPacket( &data );
2632 }break;
2633 default:break;
2637 void Player::BuildPlayerRepop()
2639 // place corpse instead player body
2640 Corpse* corpse = GetCorpse();
2641 if(!corpse)
2642 corpse = CreateCorpse();
2644 // now show corpse for all
2645 MapManager::Instance().GetMap(corpse->GetMapId())->Add(corpse);
2647 // convert player body to ghost
2648 WorldPacket data;
2650 SetHealth( 1 );
2652 SetMovement(MOVE_WATER_WALK);
2653 SetMovement(MOVE_UNROOT);
2655 // setting new speed
2656 if (getRace() == RACE_NIGHTELF)
2658 SetPlayerSpeed(MOVE_RUN, (float)12.75, true);
2659 SetPlayerSpeed(MOVE_SWIM, (float)8.85, true);
2661 else
2663 SetPlayerSpeed(MOVE_RUN, (float)10.625, true);
2664 SetPlayerSpeed(MOVE_SWIM, (float)7.375, true);
2667 //! corpse reclaim delay 30 * 1000ms
2668 data.Initialize(SMSG_CORPSE_RECLAIM_DELAY );
2669 data << (uint32)(CORPSE_RECLAIM_DELAY*1000);
2670 GetSession()->SendPacket( &data );
2672 // to prevent cheating
2673 corpse->ResetGhostTime();
2675 //TODO: Check/research this
2676 data.Initialize(SMSG_SPELL_START );
2677 data.append(GetPackGUID()); //9
2678 data.append(GetPackGUID()); //9
2679 //<< uint16(8326); //2
2680 data << uint32(20305); //2
2681 data << uint16(2);
2682 data << uint32(0) << uint16(0); //6
2683 GetSession()->SendPacket( &data );
2685 data.Initialize(SMSG_SPELL_GO);
2686 data.append(GetPackGUID());
2687 data.append(GetPackGUID());
2688 data << uint16(8326);
2689 /// uint8(0x0D) = probably race + 2
2690 data << uint16(0) << uint8(0x0D) << uint8(0x01)<< uint8(0x01) << GetGUID();
2691 data << uint32(0) << uint16(0x0200) << uint16(0);
2692 GetSession()->SendPacket( &data );
2694 data.Initialize(SMSG_UPDATE_AURA_DURATION);
2695 data << uint32(0x20) << uint8(0);
2696 GetSession()->SendPacket( &data );
2698 StopMirrorTimer(FATIGUE_TIMER); //disable timers(bars)
2699 StopMirrorTimer(BREATH_TIMER);
2700 StopMirrorTimer(FIRE_TIMER);
2702 SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_NONE | UNIT_FLAG_ALLOW_SWIM );
2703 SetUInt32Value(UNIT_FIELD_AURA + 32, 8326); // set ghost form
2704 SetUInt32Value(UNIT_FIELD_AURA + 33, 0x5068 ); //!dono
2706 SetUInt32Value(UNIT_FIELD_AURAFLAGS + 4, 0xEE);
2708 SetUInt32Value(UNIT_FIELD_AURASTATE, 0x02);
2710 SetFloatValue(UNIT_FIELD_BOUNDINGRADIUS,(float)1.0); //see radius of death player?
2712 SetUInt32Value(UNIT_FIELD_BYTES_1, 0x1000000); //Set standing so always be standing
2714 if (getRace() == RACE_NIGHTELF)
2715 SetUInt32Value(UNIT_FIELD_DISPLAYID, 10045); //10045 correct wisp model
2717 SetUInt32Value(PLAYER_FLAGS, PLAYER_FLAGS_GHOST);
2720 void Player::SendDelayResponse(const uint32 ml_seconds)
2722 WorldPacket data;
2723 data.Initialize( SMSG_QUERY_TIME_RESPONSE );
2724 data << (uint32)getMSTime();
2725 GetSession()->SendPacket( &data );
2728 void Player::ResurrectPlayer()
2730 // remove death flag + set aura
2731 RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST);
2733 // return the PvP enable flag to normal
2734 SetPvP( GetPvP() );
2736 setDeathState(ALIVE);
2738 SetMovement(MOVE_LAND_WALK);
2739 SetMovement(MOVE_UNROOT);
2741 SetPlayerSpeed(MOVE_RUN, (float)7.5, true);
2742 SetPlayerSpeed(MOVE_SWIM, (float)4.9, true);
2744 SetUInt32Value(CONTAINER_FIELD_SLOT_1+29, 0);
2746 SetUInt32Value(UNIT_FIELD_AURA+32, 0);
2747 SetUInt32Value(UNIT_FIELD_AURALEVELS+8, 0xeeeeeeee);
2748 SetUInt32Value(UNIT_FIELD_AURAAPPLICATIONS+8, 0xeeeeeeee);
2749 SetUInt32Value(UNIT_FIELD_AURAFLAGS+4, 0);
2750 SetUInt32Value(UNIT_FIELD_AURASTATE, 0);
2752 if(getRace() == RACE_NIGHTELF)
2754 DeMorph();
2757 m_deathTimer = 0;
2760 void Player::KillPlayer()
2762 SetMovement(MOVE_ROOT);
2764 StopMirrorTimer(FATIGUE_TIMER); //disable timers(bars)
2765 StopMirrorTimer(BREATH_TIMER);
2766 StopMirrorTimer(FIRE_TIMER);
2768 setDeathState(CORPSE);
2769 //SetFlag( UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_IN_PVP );
2771 SetFlag( UNIT_DYNAMIC_FLAGS, 0x00 );
2773 // 6 minutes until repop at graveyard
2774 m_deathTimer = 360000;
2776 // dead player body showed at this moment, corpse wiil be show at Player ghost repop
2777 CreateCorpse();
2780 Corpse* Player::CreateCorpse()
2782 // prevent existance 2 corpse for player
2783 SpawnCorpseBones();
2785 uint32 _uf, _pb, _pb2, _cfb1, _cfb2;
2787 Corpse* corpse = new Corpse(CORPSE_RESURRECTABLE);
2788 if(!corpse->Create(objmgr.GenerateLowGuid(HIGHGUID_CORPSE), this, GetMapId(), GetPositionX(),
2789 GetPositionY(), GetPositionZ(), GetOrientation()))
2791 delete corpse;
2792 return NULL;
2795 _uf = GetUInt32Value(UNIT_FIELD_BYTES_0);
2796 _pb = GetUInt32Value(PLAYER_BYTES);
2797 _pb2 = GetUInt32Value(PLAYER_BYTES_2);
2799 uint8 race = (uint8)(_uf);
2800 uint8 skin = (uint8)(_pb);
2801 uint8 face = (uint8)(_pb >> 8);
2802 uint8 hairstyle = (uint8)(_pb >> 16);
2803 uint8 haircolor = (uint8)(_pb >> 24);
2804 uint8 facialhair = (uint8)(_pb2);
2806 _cfb1 = ((0x00) | (race << 8) | (0x00 << 16) | (skin << 24));
2807 _cfb2 = ((face) | (hairstyle << 8) | (haircolor << 16) | (facialhair << 24));
2809 corpse->SetUInt32Value( CORPSE_FIELD_BYTES_1, _cfb1 );
2810 corpse->SetUInt32Value( CORPSE_FIELD_BYTES_2, _cfb2 );
2811 corpse->SetUInt32Value( CORPSE_FIELD_FLAGS, 4 );
2812 corpse->SetUInt32Value( CORPSE_FIELD_DISPLAY_ID, GetUInt32Value(UNIT_FIELD_DISPLAYID) );
2814 uint32 iDisplayID;
2815 uint16 iIventoryType;
2816 uint32 _cfi;
2817 for (int i = 0; i < EQUIPMENT_SLOT_END; i++)
2819 if(m_items[i])
2821 iDisplayID = m_items[i]->GetProto()->DisplayInfoID;
2822 iIventoryType = (uint16)m_items[i]->GetProto()->InventoryType;
2824 _cfi = (uint16(iDisplayID)) | (iIventoryType)<< 24;
2825 corpse->SetUInt32Value(CORPSE_FIELD_ITEM + i,_cfi);
2829 corpse->SaveToDB();
2831 // register for player, but not show
2832 corpse->AddToWorld();
2833 return corpse;
2836 void Player::SpawnCorpseBones()
2838 Corpse* corpse = GetCorpse();
2839 if(!corpse) return;
2841 if( corpse->GetType() == CORPSE_RESURRECTABLE )
2843 corpse->ConvertCorpseToBones();
2844 SaveToDB(); // prevent loading as ghost without corpse
2848 Corpse* Player::GetCorpse() const
2850 return ObjectAccessor::Instance().GetCorpseForPlayer(*this);
2853 void Player::DurabilityLossAll(double percent)
2855 for (uint16 i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; i++)
2856 DurabilityLoss(i,percent);
2859 void Player::DurabilityLoss(uint8 equip_pos, double percent)
2861 if(!m_items[equip_pos])
2862 return;
2864 uint32 pDurability = m_items[equip_pos]->GetUInt32Value(ITEM_FIELD_DURABILITY);
2866 if(!pDurability)
2867 return;
2869 uint32 pDurabilityLoss = (uint32)(pDurability*percent);
2871 if(pDurabilityLoss < 1 )
2872 pDurabilityLoss = 1;
2874 uint32 pNewDurability = pDurability - pDurabilityLoss;
2876 // we have durability 25% or 0 we should modify item stats
2877 // modify item stats _before_ Durability set to 0 to pass _ApplyItemMods internal check
2878 // if ( pNewDurability == 0 || pNewDurability * 100 / pDurability < 25)
2879 if ( pNewDurability == 0 )
2880 _ApplyItemMods(m_items[equip_pos],equip_pos, false);
2882 m_items[equip_pos]->SetUInt32Value(ITEM_FIELD_DURABILITY, pNewDurability);
2883 m_items[equip_pos]->SetState(ITEM_CHANGED, this);
2886 void Player::DurabilityRepairAll(bool cost)
2888 for (uint16 i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; i++)
2889 DurabilityRepair(( (INVENTORY_SLOT_BAG_0 << 8) | i ),cost);
2892 void Player::DurabilityRepair(uint16 pos, bool cost)
2894 Item* item = GetItemByPos(pos);
2896 if(!item)
2897 return;
2899 uint32 maxDurability = item->GetUInt32Value(ITEM_FIELD_MAXDURABILITY);
2900 if(!maxDurability)
2901 return;
2903 uint32 curDurability = item->GetUInt32Value(ITEM_FIELD_DURABILITY);
2905 // some simple repair formula depending on durability lost
2906 if(cost)
2908 uint32 costs = maxDurability - curDurability;
2910 if (GetMoney() < costs)
2912 DEBUG_LOG("You do not have enough money");
2913 return;
2916 ModifyMoney( -int32(costs) );
2919 item->SetUInt32Value(ITEM_FIELD_DURABILITY, maxDurability);
2920 item->SetState(ITEM_CHANGED, this);
2922 // reapply mods for total broken and repaired item if equiped
2923 if(IsEquipmentPos(pos) && !curDurability)
2924 _ApplyItemMods(item,pos & 255, true);
2927 void Player::RepopAtGraveyard()
2929 WorldSafeLocsEntry *ClosestGrave = objmgr.GetClosestGraveYard( m_positionX, m_positionY, m_positionZ, GetMapId(), GetTeam() );
2931 if(ClosestGrave)
2933 // stop countdown until repop
2934 m_deathTimer = 0;
2936 TeleportTo(ClosestGrave->map_id, ClosestGrave->x, ClosestGrave->y, ClosestGrave->z, GetOrientation());
2938 if(Corpse* corpse = GetCorpse())
2939 corpse->UpdateForPlayer(this,true);
2943 void Player::JoinedChannel(Channel *c)
2945 m_channels.push_back(c);
2948 void Player::LeftChannel(Channel *c)
2950 m_channels.remove(c);
2953 void Player::CleanupChannels()
2955 list<Channel *>::iterator i;
2956 for(i = m_channels.begin(); i != m_channels.end(); i++)
2957 (*i)->Leave(this,false);
2960 void Player::BroadcastPacketToFriendListers(WorldPacket *packet)
2962 Field *fields;
2963 Player *pfriend;
2965 QueryResult *result = sDatabase.PQuery("SELECT `guid` FROM `character_social` WHERE `flags` = 'FRIEND' AND `friend` = '%u'", GetGUIDLow());
2967 if(!result) return;
2971 WorldPacket data;
2972 fields = result->Fetch();
2974 pfriend = ObjectAccessor::Instance().FindPlayer(fields[0].GetUInt64());
2976 if (pfriend && pfriend->IsInWorld())
2977 pfriend->GetSession()->SendPacket(packet);
2979 }while( result->NextRow() );
2980 delete result;
2983 void Player::UpdateDefense()
2985 if(UpdateSkill(SKILL_DEFENSE))
2987 // update dependent from defense skill part BlockChanceWithoutMods = 5 + (GetDefenceSkillValue() - getLevel()*5)*0.04);
2988 UpdateBlockPercentage();
2992 void Player::ApplyDefenseBonusesMod(float value, bool apply)
2994 ApplyModFloatValue(PLAYER_BLOCK_PERCENTAGE, value * 0.04, apply);
2995 ApplyModFloatValue(PLAYER_PARRY_PERCENTAGE, value * 0.04, apply);
2996 ApplyModFloatValue(PLAYER_DODGE_PERCENTAGE, value * 0.04, apply);
2999 void Player::UpdateBlockPercentage()
3001 AuraList& mModBlockPercent = GetAurasByType(SPELL_AURA_MOD_BLOCK_PERCENT);
3002 for(AuraList::iterator i = mModBlockPercent.begin(); i != mModBlockPercent.end(); ++i)
3003 (*i)->ApplyModifier(false);
3005 float chance = 5 - (getLevel()*5 - GetPureDefenceSkillValue()) * 0.04;
3006 chance = chance < 0 ? 0 : chance;
3008 SetFloatValue(PLAYER_BLOCK_PERCENTAGE, chance);
3010 for(AuraList::iterator i = mModBlockPercent.begin(); i != mModBlockPercent.end(); ++i)
3011 (*i)->ApplyModifier(true);
3015 //skill+1, checking for max value
3016 bool Player::UpdateSkill(uint32 skill_id)
3018 if(!skill_id) return false;
3019 uint16 i=0;
3020 for (; i < PLAYER_MAX_SKILLS; i++)
3021 if ((GetUInt32Value(PLAYER_SKILL(i)) & 0x0000FFFF) == skill_id) break;
3022 if(i>=PLAYER_MAX_SKILLS) return false;
3024 uint32 data = GetUInt32Value(PLAYER_SKILL(i)+1);
3025 uint32 value = SKILL_VALUE(data);
3026 uint32 max = SKILL_MAX(data);
3028 if ((!max) || (!value) || (value >= max)) return false;
3030 if (value*512 < max*urand(0,512))
3032 SetUInt32Value(PLAYER_SKILL(i)+1,data+1);
3033 return true;
3036 return false;
3039 #define HalfChanceSkillSteps 75
3041 inline int SkillGainChance(uint32 SkillValue, uint32 GrayLevel, uint32 GreenLevel, uint32 YellowLevel)
3043 if ( SkillValue >= GrayLevel )
3044 return sWorld.getConfig(CONFIG_SKILL_CHANCE_GREY)*10;
3045 if ( SkillValue >= GreenLevel )
3046 return sWorld.getConfig(CONFIG_SKILL_CHANCE_GREEN)*10;
3047 if ( SkillValue >= YellowLevel )
3048 return sWorld.getConfig(CONFIG_SKILL_CHANCE_YELLOW)*10;
3049 return sWorld.getConfig(CONFIG_SKILL_CHANCE_ORANGE)*10;
3052 bool Player::UpdateCraftSkill(uint32 spellid)
3054 sLog.outDebug("UpdateCraftSkill spellid %d", spellid);
3056 SkillLineAbilityEntry *pAbility = sSkillLineAbilityStore.LookupEntry(spellid);
3057 if ( !pAbility ) return false;
3059 uint32 SkillId = pAbility->skillId;
3060 if ( !SkillId ) return false;
3062 uint32 SkillValue = GetSkillValue(SkillId);
3064 return UpdateSkillPro(pAbility->skillId, SkillGainChance(SkillValue,
3065 pAbility->max_value,
3066 (pAbility->max_value + pAbility->min_value)/2,
3067 pAbility->min_value));
3070 bool Player::UpdateGatherSkill(uint32 SkillId, uint32 SkillValue, uint32 RedLevel, uint32 Multiplicator )
3072 sLog.outDebug("UpdateGatherSkill(SkillId %d SkillLevel %d RedLevel %d)", SkillId, SkillValue, RedLevel);
3074 // For skinning and Mining chance decrease with level. 1-74 - no decrease, 75-149 - 2 times, 225-299 - 8 times
3075 switch (SkillId)
3077 case SKILL_HERBALISM:
3078 return UpdateSkillPro(SkillId, SkillGainChance(SkillValue, RedLevel+100, RedLevel+50, RedLevel+25)*Multiplicator);
3079 case SKILL_SKINNING:
3080 case SKILL_MINING:
3081 return UpdateSkillPro(SkillId, (SkillGainChance(SkillValue, RedLevel+100, RedLevel+50, RedLevel+25)*Multiplicator) >> (SkillValue/HalfChanceSkillSteps) );
3083 return false;
3086 bool Player::UpdateFishingSkill()
3088 sLog.outDebug("UpdateFishingSkill");
3090 uint32 SkillValue = GetSkillValue(SKILL_FISHING);
3092 int32 chance = SkillValue < 75 ? 100 : 2500/(SkillValue-50);
3094 return UpdateSkillPro(SKILL_FISHING,chance*10);
3097 bool Player::UpdateSkillPro(uint16 SkillId, int32 Chance)
3099 sLog.outDebug("UpdateSkillPro(SkillId %d, Chance %3.1f%%)", SkillId, Chance/10.0);
3100 if ( !SkillId )
3101 return false;
3103 uint16 i=0;
3104 for (; i < PLAYER_MAX_SKILLS; i++)
3105 if ( SKILL_VALUE(GetUInt32Value(PLAYER_SKILL(i))) == SkillId ) break;
3106 if ( i >= PLAYER_MAX_SKILLS )
3107 return false;
3109 uint32 data = GetUInt32Value(PLAYER_SKILL(i)+1);
3110 uint32 SkillValue = SKILL_VALUE(data);
3111 uint32 MaxValue = SKILL_MAX(data);
3113 if ( !MaxValue || !SkillValue || SkillValue >= MaxValue )
3114 return false;
3116 int32 Roll = irand(1,1000);
3118 if ( Roll <= Chance )
3120 SetUInt32Value(PLAYER_SKILL(i)+1,data+1);
3121 sLog.outDebug("Player::UpdateSkillPro Chance=%3.1f%% taken", Chance/10.0);
3122 return true;
3125 sLog.outDebug("Player::UpdateSkillPro Chance=%3.1f%% missed", Chance/10.0);
3126 return false;
3129 void Player::UpdateWeaponSkill (WeaponAttackType attType)
3131 // no skill gain in pvp
3132 Unit *pVictim = getVictim();
3133 if(pVictim && pVictim->GetTypeId() == TYPEID_PLAYER)
3134 return;
3136 switch(attType)
3138 case BASE_ATTACK:
3140 Item *tmpitem = GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
3142 if (!tmpitem || tmpitem->IsBroken())
3143 UpdateSkill(SKILL_UNARMED);
3144 else if(tmpitem->GetProto()->SubClass != ITEM_SUBCLASS_WEAPON_FISHING_POLE)
3145 UpdateSkill(tmpitem->GetSkill());
3147 };break;
3148 case OFF_ATTACK:
3150 Item *tmpitem = GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
3152 if (tmpitem && !tmpitem->IsBroken())
3153 UpdateSkill(tmpitem->GetSkill());
3154 };break;
3155 case RANGED_ATTACK:
3157 Item* tmpitem = GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_RANGED);
3159 if (tmpitem && !tmpitem->IsBroken())
3160 UpdateSkill(tmpitem->GetSkill());
3161 };break;
3165 void Player::UpdateCombatSkills(Unit *pVictim, WeaponAttackType attType, MeleeHitOutcome outcome, bool defence)
3167 switch(outcome)
3169 case MELEE_HIT_CRIT:
3170 return;
3171 case MELEE_HIT_DODGE:
3172 return;
3173 case MELEE_HIT_PARRY:
3174 return;
3175 case MELEE_HIT_BLOCK:
3176 return;
3178 default:
3179 break;
3182 uint32 plevel = getLevel(); // if defence than pVictim == attacker
3183 uint32 greylevel = MaNGOS::XP::GetGrayLevel(plevel);
3184 uint32 moblevel = pVictim->getLevel();
3185 if(moblevel < greylevel)
3186 return;
3188 if (moblevel > plevel + 5)
3189 moblevel = plevel + 5;
3191 uint32 lvldif = moblevel - greylevel;
3192 if(lvldif < 3)
3193 lvldif = 3;
3195 uint32 skilldif = 5 * plevel - (defence ? GetPureDefenceSkillValue() : GetPureWeaponSkillValue(attType));
3196 if(skilldif <= 0)
3197 return;
3199 float chance = 3 * lvldif * skilldif / plevel;
3200 if(!defence)
3202 if(getClass() == CLASS_WARRIOR || getClass() == CLASS_ROGUE)
3203 chance *= 0.1 * GetStat(STAT_INTELLECT);
3206 chance = chance < 1 ? 1 : chance; //minimum chance to increase skill is 1%
3208 if(chance > urand(0,100))
3210 if(defence)
3211 UpdateDefense();
3212 else
3213 UpdateWeaponSkill(attType);
3215 else
3216 return;
3219 void Player::ModifySkillBonus(uint32 skillid,int32 val)
3221 for (uint16 i=0; i < PLAYER_MAX_SKILLS; i++)
3222 if ((GetUInt32Value(PLAYER_SKILL(i)) & 0x0000FFFF) == skillid)
3225 SetUInt32Value(PLAYER_SKILL(i)+2,((int32)(GetUInt32Value(PLAYER_SKILL(i)+2)))+val);
3226 return;
3230 void Player::UpdateMaxSkills()
3232 for (uint16 i=0; i < PLAYER_MAX_SKILLS; i++)
3233 if (GetUInt32Value(PLAYER_SKILL(i)))
3235 uint32 pskill = GetUInt32Value(PLAYER_SKILL(i)) & 0x0000FFFF;
3236 if(pskill == SKILL_HERBALISM || pskill == SKILL_MINING || pskill ==SKILL_FISHING
3237 || pskill == SKILL_FIRST_AID || pskill == SKILL_COOKING || pskill == SKILL_LEATHERWORKING
3238 || pskill == SKILL_BLACKSMITHING || pskill == SKILL_ALCHEMY || pskill == SKILL_ENCHANTING
3239 || pskill == SKILL_TAILORING || pskill == SKILL_ENGINERING || pskill == SKILL_SKINNING)
3240 continue;
3241 uint32 data = GetUInt32Value(PLAYER_SKILL(i)+1);
3242 uint32 max = data>>16;
3243 uint32 max_Skill = data%0x10000+getLevel()*5*0x10000;
3244 if((max_Skill>>16) > 300)
3245 max_Skill = data%0x10000+300*0x10000;
3247 if(max!=1 && max != 300)
3248 SetUInt32Value(PLAYER_SKILL(i)+1,max_Skill);
3252 void Player::UpdateSkillsToMaxSkillsForLevel()
3254 for (uint16 i=0; i < PLAYER_MAX_SKILLS; i++)
3255 if (GetUInt32Value(PLAYER_SKILL(i)))
3257 uint32 pskill = GetUInt32Value(PLAYER_SKILL(i)) & 0x0000FFFF;
3258 if(pskill == SKILL_HERBALISM || pskill == SKILL_MINING || pskill ==SKILL_FISHING
3259 || pskill == SKILL_FIRST_AID || pskill == SKILL_COOKING || pskill == SKILL_LEATHERWORKING
3260 || pskill == SKILL_BLACKSMITHING || pskill == SKILL_ALCHEMY || pskill == SKILL_ENCHANTING
3261 || pskill == SKILL_TAILORING || pskill == SKILL_ENGINERING || pskill == SKILL_SKINNING)
3262 continue;
3263 uint32 data = GetUInt32Value(PLAYER_SKILL(i)+1);
3265 uint32 max = data>>16;
3267 if(max > 1)
3269 uint32 new_data = max * 0x10000 + max;
3270 SetUInt32Value(PLAYER_SKILL(i)+1,new_data);
3272 if(pskill == SKILL_DEFENSE)
3274 UpdateBlockPercentage();
3279 // This functions sets a skill line value (and adds if doesn't exist yet)
3280 // To "remove" a skill line, set it's values to zero
3281 void Player::SetSkill(uint32 id, uint16 currVal, uint16 maxVal)
3283 if(!id) return;
3284 uint16 i=0;
3285 for (; i < PLAYER_MAX_SKILLS; i++)
3286 if ((GetUInt32Value(PLAYER_SKILL(i)) & 0x0000FFFF) == id) break;
3288 if(i<PLAYER_MAX_SKILLS) //has skill
3290 if(currVal)
3291 SetUInt32Value(PLAYER_SKILL(i)+1,currVal+maxVal*0x10000);
3292 else //remove
3294 SetUInt64Value(PLAYER_SKILL(i),0);
3295 SetUInt32Value(PLAYER_SKILL(i)+2,0);
3296 // remove spells that depend on this skill when removing the skill
3297 for (PlayerSpellMap::const_iterator itr = m_spells.begin(), next = m_spells.begin(); itr != m_spells.end(); itr = next)
3299 next++;
3300 if(itr->second->state == PLAYERSPELL_REMOVED) continue;
3301 SkillLineAbilityEntry *ability = sSkillLineAbilityStore.LookupEntry(itr->first);
3302 if (ability && ability->skillId == id)
3303 removeSpell(itr->first);
3306 }else if(currVal) //add
3309 for (i=0; i < PLAYER_MAX_SKILLS; i++)
3310 if (!GetUInt32Value(PLAYER_SKILL(i)))
3312 SkillLineEntry *pSkill = sSkillLineStore.LookupEntry(id);
3313 if(!pSkill)
3315 sLog.outError("Skill not found in SkillLineStore: skill #%u", id);
3316 return;
3318 // enable unlearn button for professions only
3319 if (pSkill->categoryId == 11)
3320 SetUInt32Value(PLAYER_SKILL(i), id | (1 << 16));
3321 else
3322 SetUInt32Value(PLAYER_SKILL(i),id);
3323 SetUInt32Value(PLAYER_SKILL(i)+1,maxVal*0x10000+currVal);
3324 // apply skill bonuses
3325 SetUInt32Value(PLAYER_SKILL(i)+2,0);
3326 AuraList& mModSkill = GetAurasByType(SPELL_AURA_MOD_SKILL);
3327 for(AuraList::iterator i = mModSkill.begin(); i != mModSkill.end(); ++i)
3328 if ((*i)->GetModifier()->m_miscvalue == id)
3329 (*i)->ApplyModifier(true);
3330 AuraList& mModSkillTalent = GetAurasByType(SPELL_AURA_MOD_SKILL_TALENT);
3331 for(AuraList::iterator i = mModSkillTalent.begin(); i != mModSkillTalent.end(); ++i)
3332 if ((*i)->GetModifier()->m_miscvalue == id)
3333 (*i)->ApplyModifier(true);
3334 return;
3341 bool Player::HasSkill(uint32 skill) const
3343 if(!skill)return false;
3344 for (uint16 i=0; i < PLAYER_MAX_SKILLS; i++)
3346 if ((GetUInt32Value(PLAYER_SKILL(i)) & 0x0000FFFF) == skill)
3348 return true;
3351 return false;
3354 uint16 Player::GetSkillValue(uint32 skill) const
3356 if(!skill)return 0;
3357 for (uint16 i=0; i < PLAYER_MAX_SKILLS; i++)
3359 if ((GetUInt32Value(PLAYER_SKILL(i)) & 0x0000FFFF) == skill)
3361 return SKILL_VALUE(GetUInt32Value(PLAYER_SKILL(i)+1))+GetUInt32Value(PLAYER_SKILL(i)+2);
3364 return 0;
3367 uint16 Player::GetPureSkillValue(uint32 skill) const
3369 if(!skill)return 0;
3370 for (uint16 i=0; i < PLAYER_MAX_SKILLS; i++)
3372 if ((GetUInt32Value(PLAYER_SKILL(i)) & 0x0000FFFF) == skill)
3374 return SKILL_VALUE(GetUInt32Value(PLAYER_SKILL(i)+1));
3377 return 0;
3380 void Player::SendInitialActions()
3382 sLog.outDetail( "Initializing Action Buttons for '%u'", GetGUIDLow() );
3383 WorldPacket data;
3384 uint16 button=0;
3386 std::list<struct actions>::iterator itr;
3387 data.Initialize(SMSG_ACTION_BUTTONS);
3388 for (itr = m_actions.begin(); itr != m_actions.end();)
3390 if (itr->button == button)
3392 data << uint16(itr->action);
3393 data << uint8(itr->misc);
3394 data << uint8(itr->type);
3395 ++itr;
3397 else
3399 data << uint32(0);
3401 button++;
3404 if (button < 120 )
3406 for (int temp_counter=(120-button); temp_counter>0; temp_counter--)
3408 data << uint32(0);
3411 GetSession()->SendPacket( &data );
3412 sLog.outDetail( "Action Buttons for '%u' Initialized", GetGUIDLow() );
3415 void Player::addAction(const uint8 button, const uint16 action, const uint8 type, const uint8 misc)
3417 // check cheating with adding non-known spells to action bar
3418 if(type==ACTION_BUTTON_SPELL)
3420 if(!sSpellStore.LookupEntry(action))
3422 sLog.outError( "Action %u not added into button %u for player %s: spell not exist", action, button, GetName() );
3423 return;
3426 if(!HasSpell(action))
3428 sLog.outError( "Action %u not added into button %u for player %s: player don't known this spell", action, button, GetName() );
3429 return;
3433 bool ButtonExists = false;
3434 std::list<struct actions>::iterator itr;
3435 for (itr = m_actions.begin(); itr != m_actions.end(); ++itr)
3437 if (itr->button == button)
3439 itr->button=button;
3440 itr->action=action;
3441 itr->type=type;
3442 itr->misc=misc;
3443 ButtonExists = true;
3444 break;
3447 if (!ButtonExists)
3449 struct actions newaction;
3450 newaction.button=button;
3451 newaction.action=action;
3452 newaction.type=type;
3453 newaction.misc=misc;
3454 m_actions.push_back(newaction);
3456 sLog.outDetail( "Player '%u' Added Action '%u' to Button '%u'", GetGUIDLow(), action, button );
3459 void Player::removeAction(uint8 button)
3461 std::list<struct actions>::iterator itr;
3462 for (itr = m_actions.begin(); itr != m_actions.end(); ++itr)
3464 if (itr->button == button)
3466 m_actions.erase(itr);
3467 break;
3470 sLog.outDetail( "Action Button '%u' Removed from Player '%u'", button, GetGUIDLow() );
3473 void Player::SetDontMove(bool dontMove)
3475 m_dontMove = dontMove;
3478 bool Player::IsGroupMember(Player *plyr)
3480 if(!plyr->IsInGroup())
3481 return false;
3482 Group *grp = objmgr.GetGroupByLeader(plyr->GetGroupLeader());
3483 if(grp->GroupCheck(plyr->GetGUID()))
3485 return true;
3487 return false;
3490 bool Player::SetPosition(float x, float y, float z, float orientation)
3492 Map *m = MapManager::Instance().GetMap(m_mapId);
3494 const float old_x = m_positionX;
3495 const float old_y = m_positionY;
3496 const float old_r = m_orientation;
3498 if( old_x != x || old_y != y || old_r != orientation)
3500 m->PlayerRelocation(this, x, y, z, orientation);
3502 // remove at movement non-move stealth aura
3503 if(HasFlag(UNIT_FIELD_BYTES_1,0x2000000))
3504 RemoveAurasDueToSpell(20580);
3507 // reread after Ma::Relocation
3508 m = MapManager::Instance().GetMap(GetMapId());
3509 x = m_positionX;
3510 y = m_positionY;
3511 z = m_positionZ;
3513 float water_z = m->GetWaterLevel(x,y);
3514 uint8 flag1 = m->GetTerrainType(x,y);
3516 //!Underwater check
3517 if ((z < (water_z - 2)) && (flag1 & 0x01))
3518 m_isunderwater|= 0x01;
3519 else if (z > (water_z - 2))
3520 m_isunderwater&= 0x7A;
3522 //!in lava check
3523 if ((z < (water_z - 0)) && (flag1 & 0x02))
3524 m_isunderwater|= 0x80;
3526 // form checks
3527 if ( IsUnderWater() )
3529 // remove travel forms
3530 if(m_form == FORM_TRAVEL || m_form == FORM_GHOSTWOLF)
3531 RemoveAurasDueToSpell(m_ShapeShiftForm);
3533 // IsInWater check ignore bridge and underwater ways case, check additional z
3534 else if( !IsInWater() && z < water_z + 1 )
3536 if(m_form == FORM_AQUA)
3537 RemoveAurasDueToSpell(m_ShapeShiftForm);
3540 CheckExploreSystem();
3542 return true;
3545 void Player::SendMessageToSet(WorldPacket *data, bool self)
3547 MapManager::Instance().GetMap(m_mapId)->MessageBoardcast(this, data, self);
3550 void Player::SendMessageToOwnTeamSet(WorldPacket *data, bool self)
3552 MapManager::Instance().GetMap(m_mapId)->MessageBoardcast(this, data, self,true);
3555 void Player::SendDirectMessage(WorldPacket *data)
3557 GetSession()->SendPacket(data);
3560 void Player::CheckExploreSystem()
3563 if (!isAlive())
3564 return;
3566 if (isInFlight())
3567 return;
3569 WorldPacket data;
3570 uint16 areaFlag=MapManager::Instance().GetMap(GetMapId())->GetAreaFlag(m_positionX,m_positionY);
3571 if(areaFlag==0xffff)return;
3572 int offset = areaFlag / 32;
3574 if(offset >= 64)
3576 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);
3577 return;
3580 uint32 val = (uint32)(1 << (areaFlag % 32));
3581 uint32 currFields = GetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset);
3583 if( !(currFields & val) )
3585 SetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset, (uint32)(currFields | val));
3587 AreaTableEntry *p = GetAreaEntryByAreaFlag(areaFlag);
3588 if(!p)
3590 sLog.outError("PLAYER: Player %u discovered unknown area (x: %f y: %f map: %u", GetGUIDLow(), m_positionX,m_positionY,GetMapId());
3592 else if(p->area_level > 0)
3594 uint32 area = p->ID;
3595 if (getLevel() >= sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
3597 SendExplorationExperience(area,0);
3599 else
3601 uint32 XP = uint32(p->area_level*10*sWorld.getRate(RATE_XP_EXPLORE));
3602 GiveXP( XP, NULL );
3603 SendExplorationExperience(area,XP);
3605 sLog.outDetail("PLAYER: Player %u discovered a new area: %u", GetGUIDLow(), area);
3611 uint32 Player::TeamForRace(uint8 race)
3613 ChrRacesEntry const* rEntry = sChrRacesStore.LookupEntry(race);
3614 if(!rEntry)
3616 sLog.outError("Race %u not found in DBC: wrong DBC files?",uint32(race));
3617 return ALLIANCE;
3620 switch(rEntry->TeamID)
3622 case 7: return ALLIANCE;
3623 case 1: return HORDE;
3626 sLog.outError("Race %u have wrong team id in DBC: wrong DBC files?",uint32(race),rEntry->TeamID);
3627 return ALLIANCE;
3630 void Player::setFactionForRace(uint8 race)
3632 m_team = TeamForRace(race);
3634 ChrRacesEntry const* rEntry = sChrRacesStore.LookupEntry(race);
3635 if(!rEntry)
3637 sLog.outError("Race %u not found in DBC: wrong DBC files?",uint32(race));
3638 return;
3641 setFaction( rEntry->FactionID );
3644 void Player::UpdateReputation() const
3646 std::list<struct Factions>::const_iterator itr;
3648 sLog.outDebug( "WORLD: Player::UpdateReputation" );
3650 for(itr = factions.begin(); itr != factions.end(); ++itr)
3652 SendSetFactionStanding(&*itr);
3656 void Player::SendSetFactionStanding(const Factions* faction) const
3658 WorldPacket data;
3660 if(faction->Flags & 0x00000001 ) //If faction is visible then update it
3662 data.Initialize(SMSG_SET_FACTION_STANDING);
3663 data << (uint32) faction->Flags;
3664 data << (uint32) faction->ReputationListID;
3665 data << (uint32) faction->Standing;
3666 GetSession()->SendPacket(&data);
3670 bool Player::FactionIsInTheList(uint32 faction)
3672 std::list<struct Factions>::iterator itr;
3674 for(itr = factions.begin(); itr != factions.end(); ++itr)
3676 if(itr->ReputationListID == faction) return true;
3678 return false;
3681 void Player::SetInitialFactions()
3683 Factions newFaction;
3684 FactionEntry *factionEntry = NULL;
3686 for(unsigned int i = 1; i <= sFactionStore.GetNumRows(); i++)
3688 factionEntry = sFactionStore.LookupEntry(i);
3690 if( factionEntry && (factionEntry->reputationListID >= 0))
3692 newFaction.ID = factionEntry->ID;
3693 newFaction.ReputationListID = factionEntry->reputationListID;
3694 newFaction.Standing = 0;
3695 //Set visible to factions of own team
3696 if( GetTeam() == factionEntry->team ) newFaction.Flags = 1;
3697 else newFaction.Flags = 0;
3699 //If the faction's team is enemy of my one we are at war!
3700 if(GetTeam() == ALLIANCE )
3702 if( factionEntry->team == HORDE || factionEntry->team == HORDE_FORCES )
3703 newFaction.Flags = (newFaction.Flags | 2);
3705 else
3706 if(GetTeam() == HORDE )
3708 if( factionEntry->team == ALLIANCE || factionEntry->team == ALLIANCE_FORCES )
3709 newFaction.Flags = (newFaction.Flags | 2);
3712 factions.push_back(newFaction);
3717 uint32 Player::GetStanding(uint32 faction) const
3719 FactionTemplateEntry *factionTemplateEntry = sFactionTemplateStore.LookupEntry(faction);
3721 if(!factionTemplateEntry)
3723 sLog.outError("Player::GetStanding: Can't get reputation of %s for unknown faction (faction template id) #%u.",GetName(),faction);
3724 return 0;
3727 FactionEntry *factionEntry = sFactionStore.LookupEntry(factionTemplateEntry->faction);
3729 // Faction without recorded reputation. Just ignore.
3730 if(!factionEntry)
3731 return 0;
3733 std::list<struct Factions>::const_iterator itr;
3734 for(itr = factions.begin(); itr != factions.end(); ++itr)
3736 if(int32(itr->ReputationListID) == factionEntry->reputationListID)
3738 return itr->Standing;
3741 return 0;
3744 bool Player::SetStanding(uint32 faction, int standing)
3746 FactionTemplateEntry *factionTemplateEntry = sFactionTemplateStore.LookupEntry(faction);
3748 if(!factionTemplateEntry)
3750 sLog.outError("Player::SetStanding: Can't update reputation of %s for unknown faction (faction template id) #%u.",GetName(),faction);
3751 return false;
3754 FactionEntry *factionEntry = sFactionStore.LookupEntry(factionTemplateEntry->faction);
3756 // Faction without recorded reputation. Just ignore.
3757 if(!factionEntry)
3758 return false;
3760 return ModifyFactionReputation(factionEntry,standing);
3763 bool Player::ModifyFactionReputation(FactionEntry* factionEntry, int32 standing)
3765 std::list<struct Factions>::iterator itr;
3766 for(itr = factions.begin(); itr != factions.end(); ++itr)
3768 if(int32(itr->ReputationListID) == factionEntry->reputationListID)
3770 itr->Standing = (((int32)itr->Standing + standing) > 0 ? itr->Standing + standing: 0);
3771 itr->Flags = (itr->Flags | 0x00000001);
3772 SendSetFactionStanding(&*itr);
3773 return true;
3776 return false;
3779 //Calculates how many reputation points player gains in wich victim's enemy factions
3780 void Player::CalculateReputation(Unit *pVictim)
3782 if( !pVictim ) return;
3784 if( pVictim->GetTypeId() != TYPEID_PLAYER )
3786 SetStanding( pVictim->getFaction(), (-100) );
3790 //Calculate how many reputation points player gain with the quest
3791 void Player::CalculateReputation(Quest *pQuest, uint64 guid)
3793 Creature *pCreature = ObjectAccessor::Instance().GetCreature(*this, guid);
3794 if( pCreature )
3796 int dif = getLevel() - pQuest->GetMinLevel();
3797 if(dif < 0) dif = 0;
3798 else if(dif > 5) dif = 5;
3800 int RepPoints = (uint32)(((5-dif)*0.20)*(100.0f + m_AuraModifiers[SPELL_AURA_MOD_REPUTATION_GAIN]));
3801 // correct would be multiplicative but currently only one such aura in game
3803 SetStanding(pCreature->getFaction(), (RepPoints > 0 ? RepPoints : 1) );
3806 // special quest reputation reward/losts
3807 if(pQuest->GetRewRepFaction1() && pQuest->GetRewRepValue1() )
3808 SetStanding(pQuest->GetRewRepFaction1(), pQuest->GetRewRepValue1() );
3810 if(pQuest->GetRewRepFaction2() && pQuest->GetRewRepValue2() )
3811 SetStanding(pQuest->GetRewRepFaction2(), pQuest->GetRewRepValue2() );
3814 //Update honor fields
3815 void Player::UpdateHonor(void)
3817 WorldPacket data;
3819 time_t rawtime;
3820 struct tm * now;
3821 uint32 today = 0;
3822 uint32 date = 0;
3824 uint32 Yestarday = 0;
3825 uint32 ThisWeekBegin = 0;
3826 uint32 ThisWeekEnd = 0;
3827 uint32 LastWeekBegin = 0;
3828 uint32 LastWeekEnd = 0;
3830 uint32 lifetime_honorableKills = 0;
3831 uint32 lifetime_dishonorableKills = 0;
3832 uint32 today_honorableKills = 0;
3833 uint32 today_dishonorableKills = 0;
3835 uint32 yestardayKills = 0;
3836 uint32 thisWeekKills = 0;
3837 uint32 lastWeekKills = 0;
3839 float total_honor = 0;
3840 float yestardayHonor = 0;
3841 float thisWeekHonor = 0;
3842 float lastWeekHonor = 0;
3844 time( &rawtime );
3845 now = localtime( &rawtime );
3847 today = ((uint32)(now->tm_year << 16)|(uint32)(now->tm_yday));
3849 Yestarday = today - 1;
3850 ThisWeekBegin = today - now->tm_wday;
3851 ThisWeekEnd = ThisWeekBegin + 7;
3852 LastWeekBegin = ThisWeekBegin - 7;
3853 LastWeekEnd = LastWeekBegin + 7;
3855 sLog.outDetail("PLAYER: UpdateHonor");
3857 QueryResult *result = sDatabase.PQuery("SELECT `type`,`honor`,`date` FROM `character_kill` WHERE `guid` = '%u'", GetGUIDLow());
3859 if(result)
3863 Field *fields = result->Fetch();
3864 date = fields[2].GetUInt32();
3866 if(fields[0].GetUInt32() == HONORABLE_KILL)
3868 lifetime_honorableKills++;
3869 //total_honor += fields[1].GetFloat();
3871 if( date == today)
3873 today_honorableKills++;
3875 if( date == Yestarday)
3877 yestardayKills++;
3878 yestardayHonor += fields[1].GetFloat();
3880 if( (date >= ThisWeekBegin) && (date < ThisWeekEnd) )
3882 thisWeekKills++;
3883 thisWeekHonor += fields[1].GetFloat();
3885 if( (date >= LastWeekBegin) && (date < LastWeekEnd) )
3887 lastWeekKills++;
3888 lastWeekHonor += fields[1].GetFloat();
3891 //All honor points until last week
3892 if( date < LastWeekEnd )
3894 total_honor += fields[1].GetFloat();
3898 else if(fields[0].GetUInt32() == DISHONORABLE_KILL)
3900 lifetime_dishonorableKills++;
3901 //total_honor -= fields[1].GetFloat();
3903 if( date == today)
3905 today_dishonorableKills++;
3908 //All honor points until last week
3909 if( date < LastWeekEnd )
3911 total_honor -= fields[1].GetFloat();
3915 while( result->NextRow() );
3917 delete result;
3920 //Store Total Honor points...
3921 SetTotalHonor(total_honor);
3923 //RIGHEST RANK
3924 //If the new rank is highest then the old one, then m_highest_rank is updated
3925 if( CalculateHonorRank(total_honor) > GetHonorHighestRank() )
3927 SetHonorHighestRank( CalculateHonorRank(total_honor) );
3930 //RATING
3931 SetHonorRating( MaNGOS::Honor::CalculeRating(this) );
3933 //STANDING
3934 SetHonorLastWeekStanding( MaNGOS::Honor::CalculeStanding(this) );
3936 //TODO Fix next rank bar... it is not working fine! For while it be set with the total honor points...
3937 //NEXT RANK BAR
3938 SetUInt32Value(PLAYER_FIELD_HONOR_BAR, (uint32)( (total_honor < 0) ? 0: total_honor) );
3940 //RANK (Patent)
3941 if( CalculateHonorRank(total_honor) )
3942 SetUInt32Value(PLAYER_BYTES_3, (( CalculateHonorRank(total_honor) << 24) + 0x04000000) + (m_drunk & 0xFFFE) + getGender());
3943 else
3944 SetUInt32Value(PLAYER_BYTES_3, (m_drunk & 0xFFFE) + getGender());
3946 //TODAY
3947 SetUInt32Value(PLAYER_FIELD_SESSION_KILLS, (today_dishonorableKills << 16) + today_honorableKills );
3948 //YESTERDAY
3949 SetUInt32Value(PLAYER_FIELD_YESTERDAY_KILLS, yestardayKills);
3950 SetUInt32Value(PLAYER_FIELD_YESTERDAY_CONTRIBUTION, (uint32)yestardayHonor);
3951 //THIS WEEK
3952 SetUInt32Value(PLAYER_FIELD_THIS_WEEK_KILLS, thisWeekKills);
3953 SetUInt32Value(PLAYER_FIELD_THIS_WEEK_CONTRIBUTION, (uint32)thisWeekHonor);
3954 //LAST WEEK
3955 SetUInt32Value(PLAYER_FIELD_LAST_WEEK_KILLS, lastWeekKills);
3956 SetUInt32Value(PLAYER_FIELD_LAST_WEEK_CONTRIBUTION, (uint32)lastWeekHonor);
3957 SetUInt32Value(PLAYER_FIELD_LAST_WEEK_RANK, GetHonorLastWeekStanding());
3959 //LIFE TIME
3960 SetUInt32Value(PLAYER_FIELD_SESSION_KILLS, (lifetime_dishonorableKills << 16) + lifetime_honorableKills );
3961 SetUInt32Value(PLAYER_FIELD_LIFETIME_DISHONORABLE_KILLS, lifetime_dishonorableKills);
3962 SetUInt32Value(PLAYER_FIELD_LIFETIME_HONORABLE_KILLS, lifetime_honorableKills);
3963 //TODO: Into what field we need to set it? Fix it!
3964 SetUInt32Value(PLAYER_FIELD_PVP_MEDALS/*???*/, (GetHonorHighestRank() != 0 ? ((GetHonorHighestRank() << 24) + 0x040F0001) : 0) );
3967 uint32 Player::GetHonorRank() const
3969 return CalculateHonorRank(m_total_honor_points);
3972 //What is Player's rank... private, scout...
3973 uint32 Player::CalculateHonorRank(float honor_points) const
3975 int rank = 0;
3977 if(honor_points <= 0.00) rank = 0; else
3978 if(honor_points < 2000.00) rank = 1;
3979 else
3980 rank = ( (int)(honor_points / 5000) + 1);
3982 return rank;
3985 //How many times Player kill pVictim...
3986 int Player::CalculateTotalKills(Player *pVictim) const
3988 int total_kills = 0;
3990 QueryResult *result = sDatabase.PQuery("SELECT `honor` FROM `character_kill` WHERE `guid` = '%u' AND `creature_template` = '%u'", GetGUIDLow(), pVictim->GetEntry());
3992 if(result)
3994 total_kills = result->GetRowCount();
3995 delete result;
3997 return total_kills;
4000 //How much honor Player gains/loses killing uVictim
4001 void Player::CalculateHonor(Unit *uVictim)
4003 float parcial_honor_points = 0;
4004 int kill_type = 0;
4005 bool savekill = false;
4007 sLog.outDetail("PLAYER: CalculateHonor");
4009 if( !uVictim ) return;
4011 if( uVictim->GetTypeId() == TYPEID_UNIT )
4013 Creature *cVictim = (Creature *)uVictim;
4014 if( cVictim->isCivilian() )
4016 parcial_honor_points = MaNGOS::Honor::DishonorableKillPoints( getLevel() );
4017 kill_type = DISHONORABLE_KILL;
4018 savekill = true;
4021 else
4022 if( uVictim->GetTypeId() == TYPEID_PLAYER )
4024 Player *pVictim = (Player *)uVictim;
4026 if( GetTeam() == pVictim->GetTeam() ) return;
4028 if( getLevel() < (pVictim->getLevel()+5) )
4030 parcial_honor_points = MaNGOS::Honor::HonorableKillPoints( this, pVictim );
4031 kill_type = HONORABLE_KILL;
4032 savekill = true;
4036 if (savekill)
4038 time_t rawtime;
4039 struct tm * now;
4040 uint32 today = 0;
4041 time( &rawtime );
4042 now = localtime( &rawtime );
4043 today = ((uint32)(now->tm_year << 16)|(uint32)(now->tm_yday));
4045 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);
4047 UpdateHonor();
4051 uint32 Player::GetGuildIdFromDB(uint64 guid)
4053 std::ostringstream ss;
4054 ss<<"SELECT `guildid` FROM `guild_member` WHERE `guid`='"<<guid<<"'";
4055 QueryResult *result = sDatabase.Query( ss.str().c_str() );
4056 if( result )
4057 return (*result)[0].GetUInt32();
4058 else
4059 return 0;
4062 uint32 Player::GetRankFromDB(uint64 guid)
4064 std::ostringstream ss;
4065 ss<<"SELECT `rank` FROM `guild_member` WHERE `guid`='"<<guid<<"'";
4066 QueryResult *result = sDatabase.Query( ss.str().c_str() );
4067 if( result )
4068 return (*result)[0].GetUInt32();
4069 else
4070 return 0;
4073 uint32 Player::GetZoneIdFromDB(uint64 guid)
4075 std::ostringstream ss;
4076 ss<<"SELECT `map`,`position_x`,`position_y` FROM `character` WHERE `guid`='"<<guid<<"'";
4077 QueryResult *result = sDatabase.Query( ss.str().c_str() );
4078 if( !result )
4079 return 0;
4081 return MapManager::Instance().GetMap((*result)[0].GetUInt32())->GetZoneId((*result)[0].GetFloat(),(*result)[0].GetFloat());
4084 //If players are too far way of duel flag... then player loose the duel
4085 void Player::CheckDuelDistance(time_t currTime)
4087 if(!duel) return;
4089 uint64 duelFlagGUID = GetUInt64Value(PLAYER_DUEL_ARBITER);
4090 GameObject* obj = ObjectAccessor::Instance().GetGameObject(*this, duelFlagGUID);
4091 if(!obj)
4092 return;
4094 if(duel->outOfBound == 0)
4096 if(!IsWithinDist(obj, 50))
4098 duel->outOfBound = currTime;
4100 WorldPacket data;
4101 data.Initialize(SMSG_DUEL_OUTOFBOUNDS);
4102 GetSession()->SendPacket(&data);
4105 else
4107 if(IsWithinDist(obj, 40))
4109 duel->outOfBound = 0;
4111 WorldPacket data;
4112 data.Initialize(SMSG_DUEL_INBOUNDS);
4113 GetSession()->SendPacket(&data);
4115 else if(currTime >= (duel->outOfBound+10))
4117 DuelComplete(2);
4122 //type: 0=cleanup ; 1=i won ; 2=i fled
4123 void Player::DuelComplete(uint8 type)
4125 // duel not requested
4126 if(!duel)
4127 return;
4129 WorldPacket data;
4131 data.Initialize(SMSG_DUEL_COMPLETE);
4132 data << (uint8)((type!=0) ? 1 : 0);
4133 GetSession()->SendPacket(&data);
4134 duel->opponent->GetSession()->SendPacket(&data);
4136 if(type != 0)
4138 data.Initialize(SMSG_DUEL_WINNER);
4139 data << (uint8)((type==1) ? 0 : 1); // 0 = just won; 1 = fled
4140 data << duel->opponent->GetName();
4141 data << GetName();
4142 SendMessageToSet(&data,true);
4145 // cool-down duel spell
4146 data.Initialize(SMSG_SPELL_COOLDOWN);
4147 data<<(uint32)7266;
4148 data<<GetGUID();
4149 GetSession()->SendPacket(&data);
4150 data.Initialize(SMSG_SPELL_COOLDOWN);
4151 data<<(uint32)7266;
4152 data<<duel->opponent->GetGUID();
4153 duel->opponent->GetSession()->SendPacket(&data);
4155 //Remove Duel Flag object
4156 GameObject* obj = ObjectAccessor::Instance().GetGameObject(*this, GetUInt64Value(PLAYER_DUEL_ARBITER));
4157 if(obj)
4158 duel->initiator->RemoveGameObject(obj,true);
4160 /* remove auras */
4161 vector<uint32> auras2remove;
4162 AuraMap& vAuras = duel->opponent->GetAuras();
4163 for (AuraMap::iterator i = vAuras.begin(); i != vAuras.end(); i++)
4165 if (!i->second->IsPositive() && i->second->GetCasterGUID() == GetGUID() && i->second->GetAuraApplyTime() >= duel->startTime)
4166 auras2remove.push_back(i->second->GetId());
4168 for(int i=0; i<auras2remove.size(); i++)
4169 duel->opponent->RemoveAurasDueToSpell(auras2remove[i]);
4171 auras2remove.clear();
4172 AuraMap& Auras = GetAuras();
4173 for (AuraMap::iterator i = Auras.begin(); i != Auras.end(); i++)
4175 if (!i->second->IsPositive() && i->second->GetCasterGUID() == duel->opponent->GetGUID() && i->second->GetAuraApplyTime() >= duel->startTime)
4176 auras2remove.push_back(i->second->GetId());
4178 for(int i=0; i<auras2remove.size(); i++)
4179 RemoveAurasDueToSpell(auras2remove[i]);
4181 //cleanups
4182 SetUInt64Value(PLAYER_DUEL_ARBITER, 0);
4183 SetUInt32Value(PLAYER_DUEL_TEAM, 0);
4184 duel->opponent->SetUInt64Value(PLAYER_DUEL_ARBITER, 0);
4185 duel->opponent->SetUInt32Value(PLAYER_DUEL_TEAM, 0);
4187 delete duel->opponent->duel;
4188 duel->opponent->duel = NULL;
4189 delete duel;
4190 duel = NULL;
4193 static uint32 holdrand = 0x89abcdef;
4195 void Rand_Init(uint32 seed)
4197 holdrand = seed;
4200 int32 irand(int32 min, int32 max)
4202 assert((max - min) < 32768);
4204 max++;
4205 holdrand = (holdrand * 214013) + 2531011;
4207 return (((holdrand >> 17) * (max - min)) >> 15) + min;
4210 //---------------------------------------------------------//
4211 // Flight callback
4212 void Player::FlightComplete()
4214 clearUnitState(UNIT_STAT_IN_FLIGHT);
4215 SetMoney( m_dismountCost);
4216 Unmount();
4219 void Player::_ApplyItemMods(Item *item, uint8 slot,bool apply)
4221 if(slot >= INVENTORY_SLOT_BAG_END || !item) return;
4223 // not apply/remove mods for broken item
4224 if(item->IsBroken()) return;
4226 ItemPrototype const *proto = item->GetProto();
4228 if(!proto) return;
4230 sLog.outDetail("applying mods for item %u ",item->GetGUIDLow());
4231 if(proto->ItemSet)
4233 if (apply)
4234 AddItemsSetItem(this,item);
4235 else
4236 RemoveItemsSetItem(this,proto);
4239 _RemoveStatsMods();
4240 AuraList& mModBaseResistancePct = GetAurasByType(SPELL_AURA_MOD_BASE_RESISTANCE_PCT);
4241 AuraList& mModDamagePercentDone = GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE);
4242 for(AuraList::iterator i = mModDamagePercentDone.begin(); i != mModDamagePercentDone.end(); ++i)
4243 (*i)->ApplyModifier(false);
4244 for(AuraList::iterator i = mModBaseResistancePct.begin(); i != mModBaseResistancePct.end(); ++i)
4245 (*i)->ApplyModifier(false);
4247 _ApplyItemBonuses(proto,slot,apply);
4249 for(AuraList::iterator i = mModDamagePercentDone.begin(); i != mModDamagePercentDone.end(); ++i)
4250 (*i)->ApplyModifier(true);
4251 for(AuraList::iterator i = mModBaseResistancePct.begin(); i != mModBaseResistancePct.end(); ++i)
4252 (*i)->ApplyModifier(true);
4253 _ApplyStatsMods();
4255 if(apply)
4256 CastItemEquipSpell(item);
4257 else
4258 for (int i = 0; i < 5; i++)
4259 if(proto->Spells[i].SpellId)
4260 RemoveAurasDueToSpell(proto->Spells[i].SpellId );
4262 for(int enchant_slot = 0 ; enchant_slot < 7; enchant_slot++)
4264 uint32 Enchant_id = item->GetUInt32Value(ITEM_FIELD_ENCHANTMENT+enchant_slot*3);
4265 if(Enchant_id)
4266 AddItemEnchant(item,Enchant_id, apply);
4269 sLog.outDebug("_ApplyItemMods complete.");
4272 void Player::_ApplyItemBonuses(ItemPrototype const *proto,uint8 slot,bool apply)
4274 if(slot >= INVENTORY_SLOT_BAG_END || !proto) return;
4276 int32 val;
4277 std::string typestr;
4278 std::string applystr = apply ? "Add" : "Remove";
4279 for (int i = 0; i < 10; i++)
4281 val = proto->ItemStat[i].ItemStatValue ;
4283 switch (proto->ItemStat[i].ItemStatType)
4285 case ITEM_STAT_POWER: // modify MP
4286 ApplyMaxPowerMod(POWER_MANA, val, apply);
4287 typestr = "Mana";
4288 break;
4289 case ITEM_STAT_HEALTH: // modify HP
4290 ApplyMaxHealthMod(val, apply);
4291 typestr = "Health";
4292 break;
4293 case ITEM_STAT_AGILITY: // modify agility
4294 ApplyStatMod(STAT_AGILITY, val, apply);
4295 ApplyPosStatMod(STAT_AGILITY, val, apply);
4296 typestr = "AGILITY";
4297 break;
4298 case ITEM_STAT_STRENGTH: //modify strength
4299 ApplyStatMod(STAT_STRENGTH, val, apply);
4300 ApplyPosStatMod(STAT_STRENGTH, val, apply);
4301 typestr = "STRENGHT";
4302 break;
4303 case ITEM_STAT_INTELLECT: //modify intellect
4304 ApplyStatMod(STAT_INTELLECT, val, apply);
4305 ApplyPosStatMod(STAT_INTELLECT, val, apply);
4306 //ApplyMaxPowerMod(POWER_MANA, val*15, apply);
4307 typestr = "INTELLECT";
4308 break;
4309 case ITEM_STAT_SPIRIT: //modify spirit
4310 ApplyStatMod(STAT_SPIRIT, val, apply);
4311 ApplyPosStatMod(STAT_SPIRIT, val, apply);
4312 typestr = "SPIRIT";
4313 break;
4314 case ITEM_STAT_STAMINA: //modify stamina
4315 ApplyStatMod(STAT_STAMINA ,val, apply);
4316 ApplyPosStatMod(STAT_STAMINA ,val, apply);
4317 //ApplyMaxHealthMod( val*10,apply);
4318 typestr = "STAMINA";
4319 break;
4321 if(val > 0)
4322 sLog.outDebug("%s %s: \t\t%u", applystr.c_str(), typestr.c_str(), val);
4326 if (proto->Armor)
4328 ApplyArmorMod( proto->Armor, apply);
4329 sLog.outDebug("%s Armor: \t\t%u", applystr.c_str(), proto->Armor);
4332 if (proto->Block)
4334 ApplyBlockValueMod(proto->Block, apply);
4335 sLog.outDebug("%s Block: \t\t%u", applystr.c_str(), proto->Block);
4338 if (proto->HolyRes)
4340 ApplyResistanceMod(SPELL_SCHOOL_HOLY, proto->HolyRes, apply);
4341 sLog.outDebug("%s HolyRes: \t\t%u", applystr.c_str(), proto->HolyRes);
4344 if (proto->FireRes)
4346 ApplyResistanceMod(SPELL_SCHOOL_FIRE, proto->FireRes, apply);
4347 sLog.outDebug("%s FireRes: \t\t%u", applystr.c_str(), proto->FireRes);
4350 if (proto->NatureRes)
4352 ApplyResistanceMod(SPELL_SCHOOL_NATURE, proto->NatureRes, apply);
4353 sLog.outDebug("%s NatureRes: \t\t%u", applystr.c_str(), proto->NatureRes);
4356 if (proto->FrostRes)
4358 ApplyResistanceMod(SPELL_SCHOOL_FROST, proto->FrostRes, apply);
4359 sLog.outDebug("%s FrostRes: \t\t%u", applystr.c_str(), proto->FrostRes);
4362 if (proto->ShadowRes)
4364 ApplyResistanceMod(SPELL_SCHOOL_SHADOW, proto->ShadowRes, apply);
4365 sLog.outDebug("%s ShadowRes: \t\t%u", applystr.c_str(), proto->ShadowRes);
4368 if (proto->ArcaneRes)
4370 ApplyResistanceMod(SPELL_SCHOOL_ARCANE, proto->ArcaneRes, apply);
4371 sLog.outDebug("%s ArcaneRes: \t\t%u", applystr.c_str(), proto->ArcaneRes);
4374 uint8 MINDAMAGEFIELD = 0;
4375 uint8 MAXDAMAGEFIELD = 0;
4377 if( slot == EQUIPMENT_SLOT_RANGED && ( proto->InventoryType == INVTYPE_RANGED ||
4378 proto->InventoryType == INVTYPE_THROWN || proto->InventoryType == INVTYPE_RANGEDRIGHT))
4380 MINDAMAGEFIELD = UNIT_FIELD_MINRANGEDDAMAGE;
4381 MAXDAMAGEFIELD = UNIT_FIELD_MAXRANGEDDAMAGE;
4382 typestr = "Ranged";
4384 else if(slot==EQUIPMENT_SLOT_MAINHAND)
4386 MINDAMAGEFIELD = UNIT_FIELD_MINDAMAGE;
4387 MAXDAMAGEFIELD = UNIT_FIELD_MAXDAMAGE;
4388 typestr = "Mainhand";
4390 else if(slot==EQUIPMENT_SLOT_OFFHAND)
4392 MINDAMAGEFIELD = UNIT_FIELD_MINOFFHANDDAMAGE;
4393 MAXDAMAGEFIELD = UNIT_FIELD_MAXOFFHANDDAMAGE;
4394 typestr = "Offhand";
4397 if (proto->Damage[0].DamageMin > 0 && MINDAMAGEFIELD)
4399 ApplyModFloatValue(MINDAMAGEFIELD, proto->Damage[0].DamageMin, apply);
4400 sLog.outDetail("%s %s mindam: %f, now is: %f", applystr.c_str(), typestr.c_str(), proto->Damage[0].DamageMin, GetFloatValue(MINDAMAGEFIELD));
4403 if (proto->Damage[0].DamageMax > 0 && MAXDAMAGEFIELD)
4405 ApplyModFloatValue(MAXDAMAGEFIELD, proto->Damage[0].DamageMax, apply);
4406 sLog.outDetail("%s %s mindam: %f, now is: %f", applystr.c_str(), typestr.c_str(), proto->Damage[0].DamageMax, GetFloatValue(MAXDAMAGEFIELD));
4409 if (proto->Delay)
4411 if(slot == EQUIPMENT_SLOT_RANGED)
4413 SetAttackTime(RANGED_ATTACK, apply ? proto->Delay: 2000);
4414 typestr = "Range";
4415 sLog.outDebug("%s %s Delay: \t\t%u", applystr.c_str(), typestr.c_str(), proto->Delay);
4417 else if(slot==EQUIPMENT_SLOT_MAINHAND)
4419 SetAttackTime(BASE_ATTACK, apply ? proto->Delay: 2000);
4420 typestr = "Mainhand";
4421 sLog.outDebug("%s %s Delay: \t\t%u", applystr.c_str(), typestr.c_str(), proto->Delay);
4423 else if(slot==EQUIPMENT_SLOT_OFFHAND)
4425 SetAttackTime(OFF_ATTACK, apply ? proto->Delay: 2000);
4426 typestr = "Offhand";
4427 sLog.outDebug("%s %s Delay: \t\t%u", applystr.c_str(), typestr.c_str(), proto->Delay);
4432 void Player::CastItemEquipSpell(Item *item)
4434 if(!item) return;
4436 ItemPrototype const *proto = item->GetProto();
4438 if(!proto) return;
4440 SpellEntry *spellInfo;
4442 for (int i = 0; i < 5; i++)
4444 if(!proto->Spells[i].SpellId ) continue;
4445 if(proto->Spells[i].SpellTrigger != ON_EQUIP) continue;
4447 spellInfo = sSpellStore.LookupEntry(proto->Spells[i].SpellId);
4448 if(!spellInfo)
4450 sLog.outError("WORLD: unknown Item spellid %i", proto->Spells[i].SpellId);
4451 continue;
4454 DEBUG_LOG("WORLD: cast Item spellId - %i", proto->Spells[i].SpellId);
4456 Spell spell(this, spellInfo, true, 0);
4458 SpellCastTargets targets;
4459 targets.setUnitTarget( this );
4460 spell.m_CastItem = item;
4461 spell.prepare(&targets);
4465 void Player::CastItemCombatSpell(Item *item,Unit* Target)
4467 if(!item || item->IsBroken())
4468 return;
4470 ItemPrototype const *proto = item->GetProto();
4471 if(!proto)
4472 return;
4474 if (!Target || Target == this )
4475 return;
4477 SpellEntry *spellInfo;
4479 for (int i = 0; i < 5; i++)
4481 if(!proto->Spells[i].SpellId ) continue;
4483 spellInfo = sSpellStore.LookupEntry(proto->Spells[i].SpellId);
4484 if(!spellInfo)
4486 sLog.outError("WORLD: unknown Item spellid %i", proto->Spells[i].SpellId);
4487 continue;
4490 if(proto->Spells[i].SpellTrigger != CHANCE_ON_HIT) continue;
4492 uint32 chance = spellInfo->procChance <= 100 ? spellInfo->procChance : GetWeaponProcChance();
4493 if (chance > rand_chance())
4494 this->CastSpell(Target, spellInfo->Id, true, item);
4497 // item combat enchantments
4498 for(int e_slot = 0; e_slot < 7; e_slot++)
4500 uint32 enchant_id = item->GetUInt32Value(ITEM_FIELD_ENCHANTMENT+e_slot*3);
4501 SpellItemEnchantmentEntry *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
4502 if(!pEnchant) continue;
4503 uint32 enchant_display = pEnchant->display_type;
4504 uint32 chance = pEnchant->value1 != 0 ? pEnchant->value1 : GetWeaponProcChance();
4505 uint32 enchant_spell_id = pEnchant->spellid;
4506 SpellEntry *enchantSpell_info = sSpellStore.LookupEntry(enchant_spell_id);
4507 if(!enchantSpell_info) continue;
4508 if(enchant_display!=4 && enchant_display!=2 && this->IsItemSpellToCombat(enchantSpell_info))
4509 if (chance > rand_chance())
4510 this->CastSpell(Target, enchantSpell_info->Id, true);
4514 // only some item spell/auras effects can be executed when item is equiped.
4515 // If not you can have unexpected beaviur. like item giving damage to player when equip.
4516 bool Player::IsItemSpellToEquip(SpellEntry *spellInfo)
4518 return (GetDuration(spellInfo) == -1); // infinite duration -> passive aura
4520 for(int j = 0; j< 3; j++)
4522 if(spellInfo->Effect[j] == 6)
4524 switch(spellInfo->EffectApplyAuraName[j])
4526 case 3:
4527 case 23:
4528 case 8:
4529 case 84:
4530 case 85:
4531 case 42:
4532 case 43:
4533 return false;
4538 return true;
4542 // only some item spell/auras effects can be executed when in combat.
4543 // If not you can have unexpected beaviur. like having stats always growing each attack.
4544 bool Player::IsItemSpellToCombat(SpellEntry *spellInfo)
4546 return (GetDuration(spellInfo) != -1); // infinite duration -> passive aura
4549 for(int j = 0; j< 3; j++)
4551 if(spellInfo->Effect[j] == 6)
4553 switch(spellInfo->EffectApplyAuraName[j])
4555 case 3:
4556 case 23:
4557 case 8:
4558 case 84:
4559 case 85:
4560 case 42:
4561 case 43:
4562 return true;
4567 return false;
4571 void Player::_RemoveAllItemMods()
4573 sLog.outDebug("_RemoveAllItemMods start.");
4575 for (int i = 0; i < INVENTORY_SLOT_BAG_END; i++)
4577 if(m_items[i])
4579 if(m_items[i]->IsBroken())
4580 continue;
4582 ItemPrototype const *proto = m_items[i]->GetProto();
4583 if(!proto)
4584 continue;
4586 if(proto->ItemSet)
4587 RemoveItemsSetItem(this,proto);
4589 for (int m = 0; m < 5; m++)
4591 if(proto->Spells[m].SpellId)
4592 RemoveAurasDueToSpell(proto->Spells[m].SpellId );
4595 for(int enchant_slot = 0 ; enchant_slot < 7; enchant_slot++)
4597 uint32 Enchant_id = m_items[i]->GetUInt32Value(ITEM_FIELD_ENCHANTMENT+enchant_slot*3);
4598 if(Enchant_id)
4599 AddItemEnchant(m_items[i],Enchant_id, false);
4604 AuraList& mModDamagePercentDone = GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE);
4605 for(AuraList::iterator i = mModDamagePercentDone.begin(); i != mModDamagePercentDone.end(); ++i)
4606 (*i)->ApplyModifier(false);
4608 _RemoveStatsMods();
4610 AuraList& mModBaseResistancePct = GetAurasByType(SPELL_AURA_MOD_BASE_RESISTANCE_PCT);
4611 for(AuraList::iterator i = mModBaseResistancePct.begin(); i != mModBaseResistancePct.end(); ++i)
4612 (*i)->ApplyModifier(false);
4614 for (int i = 0; i < INVENTORY_SLOT_BAG_END; i++)
4616 if(m_items[i])
4618 if(m_items[i]->IsBroken())
4619 continue;
4620 ItemPrototype const *proto = m_items[i]->GetProto();
4621 if(!proto)
4622 continue;
4623 _ApplyItemBonuses(proto,i, false);
4627 for(AuraList::iterator i = mModBaseResistancePct.begin(); i != mModBaseResistancePct.end(); ++i)
4628 (*i)->ApplyModifier(true);
4630 _ApplyStatsMods();
4632 for(AuraList::iterator i = mModDamagePercentDone.begin(); i != mModDamagePercentDone.end(); ++i)
4633 (*i)->ApplyModifier(true);
4635 sLog.outDebug("_RemoveAllItemMods complete.");
4638 void Player::_ApplyAllItemMods()
4640 sLog.outDebug("_ApplyAllItemMods start.");
4642 AuraList& mModDamagePercentDone = GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE);
4643 for(AuraList::iterator i = mModDamagePercentDone.begin(); i != mModDamagePercentDone.end(); ++i)
4644 (*i)->ApplyModifier(false);
4646 _RemoveStatsMods();
4648 AuraList& mModBaseResistancePct = GetAurasByType(SPELL_AURA_MOD_BASE_RESISTANCE_PCT);
4649 for(AuraList::iterator i = mModBaseResistancePct.begin(); i != mModBaseResistancePct.end(); ++i)
4650 (*i)->ApplyModifier(false);
4652 for (int i = 0; i < INVENTORY_SLOT_BAG_END; i++)
4654 if(m_items[i])
4656 if(m_items[i]->IsBroken())
4657 continue;
4659 ItemPrototype const *proto = m_items[i]->GetProto();
4660 if(!proto)
4661 continue;
4663 _ApplyItemBonuses(proto,i, true);
4667 for(AuraList::iterator i = mModBaseResistancePct.begin(); i != mModBaseResistancePct.end(); ++i)
4668 (*i)->ApplyModifier(true);
4670 _ApplyStatsMods();
4672 for(AuraList::iterator i = mModDamagePercentDone.begin(); i != mModDamagePercentDone.end(); ++i)
4673 (*i)->ApplyModifier(true);
4675 for (int i = 0; i < INVENTORY_SLOT_BAG_END; i++)
4677 if(m_items[i])
4679 if(m_items[i]->IsBroken())
4680 continue;
4682 ItemPrototype const *proto = m_items[i]->GetProto();
4683 if(!proto)
4684 continue;
4686 if(proto->ItemSet)
4687 AddItemsSetItem(this,m_items[i]);
4689 CastItemEquipSpell(m_items[i]);
4691 for(int enchant_slot = 0 ; enchant_slot < 7; enchant_slot++)
4693 uint32 Enchant_id = m_items[i]->GetUInt32Value(ITEM_FIELD_ENCHANTMENT+enchant_slot*3);
4694 if(Enchant_id)
4695 AddItemEnchant(m_items[i],Enchant_id, true);
4700 sLog.outDebug("_ApplyAllItemMods complete.");
4703 /*Loot type MUST be
4704 1-corpse, go
4705 2-skinning
4706 3-Fishing
4709 void Player::SendLoot(uint64 guid, LootType loot_type)
4711 Loot *loot = NULL;
4712 PermissionTypes permission = ALL_PERMISSION;
4714 sLog.outDebug("Player::SendLoot");
4715 if (IS_GAMEOBJECT_GUID(guid))
4717 sLog.outDebug(" IS_GAMEOBJECT_GUID(guid)");
4718 GameObject *go =
4719 ObjectAccessor::Instance().GetGameObject(*this, guid);
4721 // not check distance for GO in case owned GO (fishing bobber case, for example)
4722 if (!go || (loot_type != LOOT_FISHING || go->GetOwnerGUID() != GetGUID()) && !go->IsWithinDistInMap(this,OBJECT_ITERACTION_DISTANCE))
4723 return;
4725 loot = &go->loot;
4727 if(go->getLootState() == GO_CLOSED)
4729 uint32 lootid = go->lootid;
4731 if(lootid)
4733 sLog.outDebug(" if(lootid)");
4734 FillLoot(this,loot,lootid,LootTemplates_Gameobject);
4737 if(loot_type == LOOT_FISHING)
4738 go->getFishLoot(loot);
4740 go->SetLootState(GO_OPEN);
4743 else if (IS_ITEM_GUID(guid))
4745 Item *item = this->GetItemByPos( this->GetPosByGuid( guid ));
4747 if (!item)
4748 return;
4750 loot = &item->loot;
4752 if(!item->m_lootGenerated)
4754 item->m_lootGenerated = true;
4755 FillLoot(this,loot,item->GetEntry(),LootTemplates_Item);
4758 else
4760 Creature *creature =
4761 ObjectAccessor::Instance().GetCreature(*this, guid);
4763 // must be in range and creature must be alive for pickpocket and must be dead for another loot
4764 if (!creature || creature->isAlive()!=(loot_type == LOOT_PICKPOKETING) || !creature->IsWithinDistInMap(this,OBJECT_ITERACTION_DISTANCE))
4765 return;
4767 if(loot_type == LOOT_PICKPOKETING && IsFriendlyTo(creature))
4768 return;
4770 loot = &creature->loot;
4772 uint32 lootid = creature->GetCreatureInfo()->lootid;
4774 if(loot_type == LOOT_PICKPOKETING)
4776 if ( !creature->lootForPickPocketed )
4778 creature->lootForPickPocketed = true;
4779 loot->clear();
4781 if (!creature->HasFlag(UNIT_NPC_FLAGS,UNIT_NPC_FLAG_VENDOR) && lootid)
4782 FillLoot(this,loot,lootid,LootTemplates_Pickpocketing);
4783 // Generate extra money for pick pocket loot
4784 loot->gold = uint32((10* (rand() % ( (creature->getLevel() / 2) + 1) + rand() % ( (getLevel() / 2) + 1 )))*sWorld.getRate(RATE_DROP_MONEY));
4787 else
4789 // the player whose group may loot the corpse
4790 Player *recipient = creature->GetLootRecipient();
4791 if (!recipient)
4793 creature->SetLootRecipient(this);
4794 recipient = this;
4797 if (creature->lootForPickPocketed)
4799 creature->lootForPickPocketed = false;
4800 loot->clear();
4803 if(!creature->lootForBody)
4805 creature->lootForBody = true;
4806 if (!creature->HasFlag(UNIT_NPC_FLAGS,UNIT_NPC_FLAG_VENDOR) && lootid)
4807 FillLoot(this,loot,lootid,LootTemplates_Creature);
4809 creature->generateMoneyLoot();
4811 if (recipient->IsInGroup())
4813 // round robin style looting applies for all low
4814 // quality items in each loot metho except free for all
4815 Group *group = objmgr.GetGroupByLeader(recipient->GetGroupLeader());
4816 uint32 siz = group->GetMembersCount();
4817 uint32 pos = 0;
4818 for (pos = 0; pos<siz; pos++)
4819 if (group->GetMemberGUID(pos) == group->GetLooterGuid())
4820 break;
4821 group->SetLooterGuid(group->GetMemberGUID((pos+1)%siz));
4823 switch (group->GetLootMethod())
4825 case GROUP_LOOT:
4826 // GroupLoot delete items over threshold (threshold even not implemented), and roll them. Items with quality<threshold, round robin
4827 group->GroupLoot(recipient->GetGUID(), loot, creature);
4828 break;
4829 case NEED_BEFORE_GREED:
4830 group->NeedBeforeGreed(recipient->GetGUID(), loot, creature);
4831 break;
4832 default:
4833 break;
4838 if (loot_type == LOOT_SKINNING)
4839 FillLoot(this,loot,creature->GetCreatureInfo()->SkinLootId,LootTemplates_Skinning);
4841 if (!IsInGroup() && recipient == this)
4842 permission = ALL_PERMISSION;
4843 else
4845 if (IsInGroup())
4847 Group *group = objmgr.GetGroupByLeader(recipient->GetGroupLeader());
4848 if ((GetGroupLeader() == recipient->GetGroupLeader()) && (group->GetLooterGuid() == GetGUID() || loot->released || group->GetLootMethod() == FREE_FOR_ALL))
4849 permission = ALL_PERMISSION;
4850 else
4851 if (GetGroupLeader() == recipient->GetGroupLeader())
4852 permission = GROUP_PERMISSION;
4853 else
4854 permission = NONE_PERMISSION;
4856 else
4857 permission = NONE_PERMISSION;
4862 m_lootGuid = guid;
4864 QuestItemList *q_list = NULL;
4865 if (permission != NONE_PERMISSION)
4867 QuestItemMap::iterator itr = loot->PlayerQuestItems.find(this);
4868 if (itr == loot->PlayerQuestItems.end())
4869 q_list = FillQuestLoot(this, loot);
4870 else
4871 q_list = itr->second;
4874 // LOOT_PICKPOKETING unsupported by client, sending LOOT_SKINNING instead
4875 if(loot_type == LOOT_PICKPOKETING)
4876 loot_type = LOOT_SKINNING;
4878 WorldPacket data;
4879 data.Initialize (SMSG_LOOT_RESPONSE);
4881 data << guid;
4882 data << uint8(loot_type);
4883 data << LootView(*loot, q_list, permission);
4885 SendDirectMessage(&data);
4887 // add 'this' player as one of the players that are looting 'loot'
4888 if (permission != NONE_PERMISSION)
4889 loot->AddLooter(this);
4892 void Player::SendNotifyLootMoneyRemoved()
4894 WorldPacket data;
4895 data.Initialize( SMSG_LOOT_CLEAR_MONEY );
4896 GetSession()->SendPacket( &data );
4899 void Player::SendNotifyLootItemRemoved(uint8 lootSlot)
4901 WorldPacket data;
4902 data.Initialize( SMSG_LOOT_REMOVED );
4903 data << uint8(lootSlot);
4904 GetSession()->SendPacket( &data );
4907 void Player::SendUpdateWordState(uint16 Field, uint16 Value)
4909 WorldPacket data;
4910 data.Initialize(SMSG_UPDATE_WORLD_STATE); //0x2D4
4911 data << uint32(Field);
4912 data << uint32(Value);
4913 GetSession()->SendPacket(&data);
4916 void Player::SendInitWorldStates(uint32 MapID)
4918 // TODO Figure out the unknown data.
4920 if ((MapID == 0) || (MapID == 1))
4922 sLog.outDebug("Sending SMSG_INIT_WORLD_STATES to Map:%u",MapID);
4924 uint16 NumberOfFields = 108;
4925 WorldPacket data;
4926 data.Initialize (SMSG_INIT_WORLD_STATES); //0x2C5
4927 data <<
4928 (uint32)MapID <<
4929 (uint16)NumberOfFields <<
4930 //field (uint16) value (uint16)
4931 (uint16)0x07AE<< (uint16)0x01<<
4932 (uint16)0x0532<< (uint16)0x01<<
4933 (uint16)0x0531<< (uint16)0x00<<
4934 (uint16)0x052E<< (uint16)0x00<<
4935 (uint16)0x06F9<< (uint16)0x00<<
4936 (uint16)0x06F3<< (uint16)0x00<<
4937 (uint16)0x06F1<< (uint16)0x00<<
4938 (uint16)0x06EE<< (uint16)0x00<<
4939 (uint16)0x06ED<< (uint16)0x00<<
4940 (uint16)0x0571<< (uint16)0x00<<
4941 (uint16)0x0570<< (uint16)0x00<<
4942 (uint16)0x0567<< (uint16)0x01<<
4943 (uint16)0x0566<< (uint16)0x01<<
4944 (uint16)0x0550<< (uint16)0x01<<
4945 (uint16)0x0544<< (uint16)0x00<<
4946 (uint16)0x0536<< (uint16)0x00<<
4947 (uint16)0x0535<< (uint16)0x01<<
4948 (uint16)0x03C6<< (uint16)0x00<<
4949 (uint16)0x03C4<< (uint16)0x00<<
4950 (uint16)0x03C2<< (uint16)0x00<<
4951 (uint16)0x07A8<< (uint16)0x00<<
4952 (uint16)0x07A3<< (uint16)0x270F<<
4953 (uint16)0x0574<< (uint16)0x00<<
4954 (uint16)0x0573<< (uint16)0x00<<
4955 (uint16)0x0572<< (uint16)0x00<<
4956 (uint16)0x056F<< (uint16)0x00<<
4957 (uint16)0x056E<< (uint16)0x00<<
4958 (uint16)0x056D<< (uint16)0x00<<
4959 (uint16)0x056C<< (uint16)0x00<<
4960 (uint16)0x056B<< (uint16)0x00<<
4961 (uint16)0x056A<< (uint16)0x01<<
4962 (uint16)0x0569<< (uint16)0x01<<
4963 (uint16)0x0568<< (uint16)0x01<<
4964 (uint16)0x0565<< (uint16)0x00<<
4965 (uint16)0x0564<< (uint16)0x00<<
4966 (uint16)0x0563<< (uint16)0x00<<
4967 (uint16)0x0562<< (uint16)0x00<<
4968 (uint16)0x0561<< (uint16)0x00<<
4969 (uint16)0x0560<< (uint16)0x00<<
4970 (uint16)0x055F<< (uint16)0x00<<
4971 (uint16)0x055E<< (uint16)0x00<<
4972 (uint16)0x055D<< (uint16)0x00<<
4973 (uint16)0x055C<< (uint16)0x00<<
4974 (uint16)0x055B<< (uint16)0x00<<
4975 (uint16)0x055A<< (uint16)0x00<<
4976 (uint16)0x0559<< (uint16)0x00<<
4977 (uint16)0x0558<< (uint16)0x00<<
4978 (uint16)0x0557<< (uint16)0x00<<
4979 (uint16)0x0556<< (uint16)0x00<<
4980 (uint16)0x0555<< (uint16)0x00<<
4981 (uint16)0x0554<< (uint16)0x01<<
4982 (uint16)0x0553<< (uint16)0x01<<
4983 (uint16)0x0552<< (uint16)0x01<<
4984 (uint16)0x0551<< (uint16)0x01<<
4985 (uint16)0x054F<< (uint16)0x00<<
4986 (uint16)0x054E<< (uint16)0x00<<
4987 (uint16)0x054D<< (uint16)0x01<<
4988 (uint16)0x054C<< (uint16)0x00<<
4989 (uint16)0x054B<< (uint16)0x00<<
4990 (uint16)0x0545<< (uint16)0x00<<
4991 (uint16)0x0543<< (uint16)0x01<<
4992 (uint16)0x0542<< (uint16)0x00<<
4993 (uint16)0x0540<< (uint16)0x00<<
4994 (uint16)0x053F<< (uint16)0x00<<
4995 (uint16)0x053E<< (uint16)0x00<<
4996 (uint16)0x053D<< (uint16)0x00<<
4997 (uint16)0x053C<< (uint16)0x00<<
4998 (uint16)0x053B<< (uint16)0x00<<
4999 (uint16)0x053A<< (uint16)0x01<<
5000 (uint16)0x0539<< (uint16)0x00<<
5001 (uint16)0x0538<< (uint16)0x00<<
5002 (uint16)0x0537<< (uint16)0x00<<
5003 (uint16)0x0534<< (uint16)0x00<<
5004 (uint16)0x0533<< (uint16)0x00<<
5005 (uint16)0x0530<< (uint16)0x00<<
5006 (uint16)0x052F<< (uint16)0x00<<
5007 (uint16)0x052D<< (uint16)0x01<<
5008 (uint16)0x0516<< (uint16)0x01<<
5009 (uint16)0x0515<< (uint16)0x00<<
5010 (uint16)0x03B6<< (uint16)0x00<<
5011 (uint16)0x0745<< (uint16)0x02<<
5012 (uint16)0x0736<< (uint16)0x01<<
5013 (uint16)0x0735<< (uint16)0x01<<
5014 (uint16)0x0734<< (uint16)0x01<<
5015 (uint16)0x0733<< (uint16)0x01<<
5016 (uint16)0x0732<< (uint16)0x01<<
5017 (uint16)0x0702<< (uint16)0x00<<
5018 (uint16)0x0701<< (uint16)0x00<<
5019 (uint16)0x0700<< (uint16)0x00<<
5020 (uint16)0x06FE<< (uint16)0x00<<
5021 (uint16)0x06FD<< (uint16)0x00<<
5022 (uint16)0x06FC<< (uint16)0x00<<
5023 (uint16)0x06FB<< (uint16)0x00<<
5024 (uint16)0x06F8<< (uint16)0x00<<
5025 (uint16)0x06F7<< (uint16)0x00<<
5026 (uint16)0x06F6<< (uint16)0x00<<
5027 (uint16)0x06F4<< (uint16)0x7D0<<
5028 (uint16)0x06F2<< (uint16)0x00<<
5029 (uint16)0x06F0<< (uint16)0x00<<
5030 (uint16)0x06EF<< (uint16)0x00<<
5031 (uint16)0x06EC<< (uint16)0x00<<
5032 (uint16)0x06EA<< (uint16)0x00<<
5033 (uint16)0x06E9<< (uint16)0x00<<
5034 (uint16)0x06E8<< (uint16)0x00<<
5035 (uint16)0x06E7<< (uint16)0x00<<
5036 (uint16)0x0518<< (uint16)0x00<<
5037 (uint16)0x0517<< (uint16)0x00<<
5038 (uint16)0x0703<< (uint16)0x00;
5039 GetSession()->SendPacket(&data);
5042 //BattleGround currently only map 489
5043 else if (MapID == 489) // && and guid is in a current Battlefield)
5045 sLog.outDebug("Sending SMSG_INIT_WORLD_STATES to Map:%u",MapID);
5047 uint16 NumberOfFields = 114;
5048 WorldPacket data;
5049 data.Initialize (SMSG_INIT_WORLD_STATES);
5050 data <<
5052 (uint32)MapID<<
5053 (uint16)NumberOfFields <<
5054 //field (uint16) value (uint16)
5055 (uint16)0x07AE<< (uint16)0x01<<
5056 (uint16)0x0532<< (uint16)0x01<<
5057 (uint16)0x0531<< (uint16)0x00<<
5058 (uint16)0x052E<< (uint16)0x00<<
5059 (uint16)0x06F9<< (uint16)0x00<<
5060 (uint16)0x06F3<< (uint16)0x00<<
5061 (uint16)0x06F1<< (uint16)0x00<<
5062 (uint16)0x06EE<< (uint16)0x00<<
5063 (uint16)0x06ED<< (uint16)0x00<<
5064 (uint16)0x0571<< (uint16)0x00<<
5065 (uint16)0x0570<< (uint16)0x00<<
5066 (uint16)0x0567<< (uint16)0x01<<
5067 (uint16)0x0566<< (uint16)0x01<<
5068 (uint16)0x0550<< (uint16)0x01<<
5069 (uint16)0x0544<< (uint16)0x00<<
5070 (uint16)0x0536<< (uint16)0x00<<
5071 (uint16)0x0535<< (uint16)0x01<<
5072 (uint16)0x03C6<< (uint16)0x00<<
5073 (uint16)0x03C4<< (uint16)0x00<<
5074 (uint16)0x03C2<< (uint16)0x00<<
5075 (uint16)0x07A8<< (uint16)0x00<<
5076 (uint16)0x07A3<< (uint16)0x270F <<
5077 (uint16)0x060B<< (uint16)0x02<<
5078 (uint16)0x0574<< (uint16)0x00<<
5079 (uint16)0x0573<< (uint16)0x00<<
5080 (uint16)0x0572<< (uint16)0x00<<
5081 (uint16)0x056F<< (uint16)0x00<<
5082 (uint16)0x056E<< (uint16)0x00<<
5083 (uint16)0x056D<< (uint16)0x00<<
5084 (uint16)0x056C<< (uint16)0x00<<
5085 (uint16)0x056B<< (uint16)0x00<<
5086 (uint16)0x056A<< (uint16)0x01<<
5087 (uint16)0x0569<< (uint16)0x01<<
5088 (uint16)0x0568<< (uint16)0x01<<
5089 (uint16)0x0565<< (uint16)0x00<<
5090 (uint16)0x0564<< (uint16)0x00<<
5091 (uint16)0x0563<< (uint16)0x00<<
5092 (uint16)0x0562<< (uint16)0x00<<
5093 (uint16)0x0561<< (uint16)0x00<<
5094 (uint16)0x0560<< (uint16)0x00<<
5095 (uint16)0x055F<< (uint16)0x00<<
5096 (uint16)0x055E<< (uint16)0x00<<
5097 (uint16)0x055D<< (uint16)0x00<<
5098 (uint16)0x055C<< (uint16)0x00<<
5099 (uint16)0x055B<< (uint16)0x00<<
5100 (uint16)0x055A<< (uint16)0x00<<
5101 (uint16)0x0559<< (uint16)0x00<<
5102 (uint16)0x0558<< (uint16)0x00<<
5103 (uint16)0x0557<< (uint16)0x00<<
5104 (uint16)0x0556<< (uint16)0x00<<
5105 (uint16)0x0555<< (uint16)0x00<<
5106 (uint16)0x0554<< (uint16)0x01<<
5107 (uint16)0x0553<< (uint16)0x01<<
5108 (uint16)0x0552<< (uint16)0x01<<
5109 (uint16)0x0551<< (uint16)0x01<<
5110 (uint16)0x054F<< (uint16)0x00<<
5111 (uint16)0x054E<< (uint16)0x00<<
5112 (uint16)0x054D<< (uint16)0x01<<
5113 (uint16)0x054C<< (uint16)0x00<<
5114 (uint16)0x054B<< (uint16)0x00<<
5115 (uint16)0x0545<< (uint16)0x00<<
5116 (uint16)0x0543<< (uint16)0x01<<
5117 (uint16)0x0542<< (uint16)0x00<<
5118 (uint16)0x0540<< (uint16)0x00<<
5119 (uint16)0x053F<< (uint16)0x00<<
5120 (uint16)0x053E<< (uint16)0x00<<
5121 (uint16)0x053D<< (uint16)0x00<<
5122 (uint16)0x053C<< (uint16)0x00<<
5123 (uint16)0x053B<< (uint16)0x00<<
5124 (uint16)0x053A<< (uint16)0x01<<
5125 (uint16)0x0539<< (uint16)0x00<<
5126 (uint16)0x0538<< (uint16)0x00<<
5127 (uint16)0x0537<< (uint16)0x00<<
5128 (uint16)0x0534<< (uint16)0x00<<
5129 (uint16)0x0533<< (uint16)0x00<<
5130 (uint16)0x0530<< (uint16)0x00<<
5131 (uint16)0x052F<< (uint16)0x00<<
5132 (uint16)0x052D<< (uint16)0x01<<
5133 (uint16)0x0516<< (uint16)0x01<<
5134 (uint16)0x0515<< (uint16)0x00<<
5135 (uint16)0x03B6<< (uint16)0x00<<
5136 (uint16)0x0745<< (uint16)0x02<<
5137 (uint16)0x0736<< (uint16)0x01<<
5138 (uint16)0x0735<< (uint16)0x01<<
5139 (uint16)0x0734<< (uint16)0x01<<
5140 (uint16)0x0733<< (uint16)0x01<<
5141 (uint16)0x0732<< (uint16)0x01<<
5142 (uint16)0x0702<< (uint16)0x00<<
5143 (uint16)0x0701<< (uint16)0x00<<
5144 (uint16)0x0700<< (uint16)0x00<<
5145 (uint16)0x06FE<< (uint16)0x00<<
5146 (uint16)0x06FD<< (uint16)0x00<<
5147 (uint16)0x06FC<< (uint16)0x00<<
5148 (uint16)0x06FB<< (uint16)0x00<<
5149 (uint16)0x06F8<< (uint16)0x00<<
5150 (uint16)0x06F7<< (uint16)0x00<<
5151 (uint16)0x06F6<< (uint16)0x00<<
5152 (uint16)0x06F4<< (uint16)0x07D0 <<
5153 (uint16)0x06F2<< (uint16)0x00<<
5154 (uint16)0x06F0<< (uint16)0x00<<
5155 (uint16)0x06EF<< (uint16)0x00<<
5156 (uint16)0x06EC<< (uint16)0x00<<
5157 (uint16)0x06EA<< (uint16)0x00<<
5158 (uint16)0x06E9<< (uint16)0x00<<
5159 (uint16)0x06E8<< (uint16)0x00<<
5160 (uint16)0x06E7<< (uint16)0x00<<
5161 (uint16)0x0641<< (uint16)0x03<<
5162 (uint16)0x062E<< (uint16)0x00<<
5163 (uint16)0x062D<< (uint16)0x00<<
5164 (uint16)0x060A<< (uint16)0x00<<
5165 (uint16)0x0609<< (uint16)0x00<<
5166 (uint16)0x0518<< (uint16)0x00<<
5167 (uint16)0x0517<< (uint16)0x00<<
5168 (uint16)0x0703<< (uint16)0x00;
5169 GetSession()->SendPacket(&data);
5173 void Player::AddWeather()
5175 uint32 zoneid = GetZoneId();
5176 if(!sWorld.FindWeather(zoneid))
5178 Weather *wth = new Weather(this);
5179 sWorld.AddWeather(wth);
5183 uint32 Player::GetXPRestBonus(uint32 xp)
5185 float rested_xp = 2 * GetRestBonus(); //xp for each rested bonus
5187 float rest_xp_percent = rested_xp / ((float)xp / 100); //% rest bonuse from total rest bonus
5188 if(rest_xp_percent>100)rest_xp_percent=100;
5190 sLog.outDetail("XP_GAIN: %f, rest_xp_percent=%f",(float)xp,rest_xp_percent);
5192 rested_xp = ((float)xp / 100 * rest_xp_percent);
5194 SetRestBonus( GetRestBonus() - ( (float)(xp + rested_xp) / 2 ));
5196 sLog.outDetail("Player gain %u xp (+ %u Rested Bonus). Rested bonus=%f",xp+(uint32)rested_xp,(uint32)rested_xp,GetRestBonus());
5197 return (uint32)rested_xp;
5200 uint8 Player::CheckFishingAble() const
5202 uint32 zone = GetZoneId();
5203 uint32 fish_value = GetSkillValue(SKILL_FISHING);
5204 uint32 ZoneMaxSkill;
5205 switch(zone)
5207 case 1:
5208 ZoneMaxSkill=50;
5209 break;
5210 case 2:
5211 ZoneMaxSkill=100;
5212 break;
5213 case 8:
5214 ZoneMaxSkill=225;
5215 break;
5216 case 9:
5217 ZoneMaxSkill=50;
5218 break;
5219 case 10:
5220 ZoneMaxSkill=50;
5221 break;
5222 case 11:
5223 ZoneMaxSkill=150;
5224 break;
5225 case 12:
5226 ZoneMaxSkill=50;
5227 break;
5228 case 14:
5229 ZoneMaxSkill=50;
5230 break;
5231 case 15:
5232 ZoneMaxSkill=225;
5233 break;
5234 case 16:
5235 ZoneMaxSkill=275;
5236 break;
5237 case 17:
5238 ZoneMaxSkill=275;
5239 break;
5240 case 18:
5241 ZoneMaxSkill=50;
5242 break;
5243 case 28:
5244 ZoneMaxSkill=290;
5245 break;
5246 case 33:
5247 ZoneMaxSkill=225;
5248 break;
5249 case 35:
5250 ZoneMaxSkill=225;
5251 break;
5252 case 37:
5253 ZoneMaxSkill=225;
5254 break;
5255 case 38:
5256 ZoneMaxSkill=100;
5257 break;
5258 case 40:
5259 ZoneMaxSkill=100;
5260 break;
5261 case 43:
5262 ZoneMaxSkill=225;
5263 break;
5264 case 44:
5265 ZoneMaxSkill=125;
5266 break;
5267 case 45:
5268 ZoneMaxSkill=200;
5269 break;
5270 case 47:
5271 ZoneMaxSkill=250;
5272 break;
5273 case 55:
5274 ZoneMaxSkill=200;
5275 break;
5276 case 57:
5277 ZoneMaxSkill=50;
5278 break;
5279 case 60:
5280 ZoneMaxSkill=50;
5281 break;
5282 case 61:
5283 ZoneMaxSkill=50;
5284 break;
5285 case 62:
5286 ZoneMaxSkill=50;
5287 break;
5288 case 63:
5289 ZoneMaxSkill=50;
5290 break;
5291 case 64:
5292 ZoneMaxSkill=50;
5293 break;
5294 case 68:
5295 ZoneMaxSkill=150;
5296 break;
5297 case 69:
5298 ZoneMaxSkill=125;
5299 break;
5300 case 71:
5301 ZoneMaxSkill=225;
5302 break;
5303 case 74:
5304 ZoneMaxSkill=225;
5305 break;
5306 case 75:
5307 ZoneMaxSkill=225;
5308 break;
5309 case 76:
5310 ZoneMaxSkill=225;
5311 break;
5312 case 85:
5313 ZoneMaxSkill=50;
5314 break;
5315 case 86:
5316 ZoneMaxSkill=50;
5317 break;
5318 case 87:
5319 ZoneMaxSkill=50;
5320 break;
5321 case 88:
5322 ZoneMaxSkill=50;
5323 break;
5324 case 89:
5325 ZoneMaxSkill=50;
5326 break;
5327 case 92:
5328 ZoneMaxSkill=50;
5329 break;
5330 case 100:
5331 ZoneMaxSkill=225;
5332 break;
5333 case 102:
5334 ZoneMaxSkill=225;
5335 break;
5336 case 104:
5337 ZoneMaxSkill=225;
5338 break;
5339 case 115:
5340 ZoneMaxSkill=100;
5341 break;
5342 case 116:
5343 ZoneMaxSkill=225;
5344 break;
5345 case 117:
5346 ZoneMaxSkill=225;
5347 break;
5348 case 122:
5349 ZoneMaxSkill=225;
5350 break;
5351 case 129:
5352 ZoneMaxSkill=225;
5353 break;
5354 case 130:
5355 ZoneMaxSkill=100;
5356 break;
5357 case 139:
5358 ZoneMaxSkill=300;
5359 break;
5360 case 141:
5361 ZoneMaxSkill=50;
5362 break;
5363 case 146:
5364 ZoneMaxSkill=50;
5365 break;
5366 case 150:
5367 ZoneMaxSkill=150;
5368 break;
5369 case 162:
5370 ZoneMaxSkill=50;
5371 break;
5372 case 163:
5373 ZoneMaxSkill=50;
5374 break;
5375 case 168:
5376 ZoneMaxSkill=50;
5377 break;
5378 case 169:
5379 ZoneMaxSkill=50;
5380 break;
5381 case 172:
5382 ZoneMaxSkill=100;
5383 break;
5384 case 187:
5385 ZoneMaxSkill=50;
5386 break;
5387 case 188:
5388 ZoneMaxSkill=50;
5389 break;
5390 case 193:
5391 ZoneMaxSkill=290;
5392 break;
5393 case 202:
5394 ZoneMaxSkill=290;
5395 break;
5396 case 211:
5397 ZoneMaxSkill=50;
5398 break;
5399 case 221:
5400 ZoneMaxSkill=50;
5401 break;
5402 case 223:
5403 ZoneMaxSkill=50;
5404 break;
5405 case 226:
5406 ZoneMaxSkill=100;
5407 break;
5408 case 227:
5409 ZoneMaxSkill=100;
5410 break;
5411 case 237:
5412 ZoneMaxSkill=100;
5413 break;
5414 case 249:
5415 ZoneMaxSkill=280;
5416 break;
5417 case 256:
5418 ZoneMaxSkill=50;
5419 break;
5420 case 258:
5421 ZoneMaxSkill=50;
5422 break;
5423 case 259:
5424 ZoneMaxSkill=50;
5425 break;
5426 case 265:
5427 ZoneMaxSkill=50;
5428 break;
5429 case 266:
5430 ZoneMaxSkill=50;
5431 break;
5432 case 267:
5433 ZoneMaxSkill=150;
5434 break;
5435 case 271:
5436 ZoneMaxSkill=150;
5437 break;
5438 case 272:
5439 ZoneMaxSkill=150;
5440 break;
5441 case 279:
5442 ZoneMaxSkill=200;
5443 break;
5444 case 284:
5445 ZoneMaxSkill=200;
5446 break;
5447 case 295:
5448 ZoneMaxSkill=150;
5449 break;
5450 case 297:
5451 ZoneMaxSkill=225;
5452 break;
5453 case 298:
5454 ZoneMaxSkill=150;
5455 break;
5456 case 299:
5457 ZoneMaxSkill=150;
5458 break;
5459 case 300:
5460 ZoneMaxSkill=225;
5461 break;
5462 case 301:
5463 ZoneMaxSkill=225;
5464 break;
5465 case 302:
5466 ZoneMaxSkill=225;
5467 break;
5468 case 305:
5469 ZoneMaxSkill=100;
5470 break;
5471 case 306:
5472 ZoneMaxSkill=100;
5473 break;
5474 case 307:
5475 ZoneMaxSkill=250;
5476 break;
5477 case 309:
5478 ZoneMaxSkill=100;
5479 break;
5480 case 310:
5481 ZoneMaxSkill=225;
5482 break;
5483 case 311:
5484 ZoneMaxSkill=225;
5485 break;
5486 case 312:
5487 ZoneMaxSkill=225;
5488 break;
5489 case 314:
5490 ZoneMaxSkill=200;
5491 break;
5492 case 317:
5493 ZoneMaxSkill=200;
5494 break;
5495 case 323:
5496 ZoneMaxSkill=100;
5497 break;
5498 case 324:
5499 ZoneMaxSkill=200;
5500 break;
5501 case 327:
5502 ZoneMaxSkill=200;
5503 break;
5504 case 328:
5505 ZoneMaxSkill=200;
5506 break;
5507 case 331:
5508 ZoneMaxSkill=150;
5509 break;
5510 case 350:
5511 ZoneMaxSkill=250;
5512 break;
5513 case 351:
5514 ZoneMaxSkill=250;
5515 break;
5516 case 353:
5517 ZoneMaxSkill=250;
5518 break;
5519 case 356:
5520 ZoneMaxSkill=250;
5521 break;
5522 case 361:
5523 ZoneMaxSkill=250;
5524 break;
5525 case 363:
5526 ZoneMaxSkill=50;
5527 break;
5528 case 367:
5529 ZoneMaxSkill=50;
5530 break;
5531 case 368:
5532 ZoneMaxSkill=50;
5533 break;
5534 case 373:
5535 ZoneMaxSkill=50;
5536 break;
5537 case 374:
5538 ZoneMaxSkill=50;
5539 break;
5540 case 375:
5541 ZoneMaxSkill=300;
5542 break;
5543 case 382:
5544 ZoneMaxSkill=125;
5545 break;
5546 case 384:
5547 ZoneMaxSkill=125;
5548 break;
5549 case 385:
5550 ZoneMaxSkill=125;
5551 break;
5552 case 386:
5553 ZoneMaxSkill=125;
5554 break;
5555 case 387:
5556 ZoneMaxSkill=125;
5557 break;
5558 case 388:
5559 ZoneMaxSkill=125;
5560 break;
5561 case 391:
5562 ZoneMaxSkill=125;
5563 break;
5564 case 392:
5565 ZoneMaxSkill=125;
5566 break;
5567 case 393:
5568 ZoneMaxSkill=50;
5569 break;
5570 case 401:
5571 ZoneMaxSkill=125;
5572 break;
5573 case 405:
5574 ZoneMaxSkill=200;
5575 break;
5576 case 406:
5577 ZoneMaxSkill=135;
5578 break;
5579 case 414:
5580 ZoneMaxSkill=150;
5581 break;
5582 case 415:
5583 ZoneMaxSkill=150;
5584 break;
5585 case 416:
5586 ZoneMaxSkill=150;
5587 break;
5588 case 418:
5589 ZoneMaxSkill=150;
5590 break;
5591 case 420:
5592 ZoneMaxSkill=150;
5593 break;
5594 case 421:
5595 ZoneMaxSkill=150;
5596 break;
5597 case 422:
5598 ZoneMaxSkill=150;
5599 break;
5600 case 424:
5601 ZoneMaxSkill=150;
5602 break;
5603 case 429:
5604 ZoneMaxSkill=150;
5605 break;
5606 case 433:
5607 ZoneMaxSkill=150;
5608 break;
5609 case 434:
5610 ZoneMaxSkill=150;
5611 break;
5612 case 437:
5613 ZoneMaxSkill=150;
5614 break;
5615 case 441:
5616 ZoneMaxSkill=150;
5617 break;
5618 case 442:
5619 ZoneMaxSkill=100;
5620 break;
5621 case 443:
5622 ZoneMaxSkill=100;
5623 break;
5624 case 445:
5625 ZoneMaxSkill=100;
5626 break;
5627 case 448:
5628 ZoneMaxSkill=100;
5629 break;
5630 case 449:
5631 ZoneMaxSkill=100;
5632 break;
5633 case 452:
5634 ZoneMaxSkill=100;
5635 break;
5636 case 453:
5637 ZoneMaxSkill=100;
5638 break;
5639 case 454:
5640 ZoneMaxSkill=100;
5641 break;
5642 case 456:
5643 ZoneMaxSkill=100;
5644 break;
5645 case 460:
5646 ZoneMaxSkill=135;
5647 break;
5648 case 463:
5649 ZoneMaxSkill=275;
5650 break;
5651 case 464:
5652 ZoneMaxSkill=135;
5653 break;
5654 case 478:
5655 ZoneMaxSkill=50;
5656 break;
5657 case 490:
5658 ZoneMaxSkill=275;
5659 break;
5660 case 493:
5661 ZoneMaxSkill=300;
5662 break;
5663 case 496:
5664 ZoneMaxSkill=225;
5665 break;
5666 case 497:
5667 ZoneMaxSkill=225;
5668 break;
5669 case 501:
5670 ZoneMaxSkill=225;
5671 break;
5672 case 502:
5673 ZoneMaxSkill=225;
5674 break;
5675 case 504:
5676 ZoneMaxSkill=225;
5677 break;
5678 case 508:
5679 ZoneMaxSkill=225;
5680 break;
5681 case 509:
5682 ZoneMaxSkill=225;
5683 break;
5684 case 510:
5685 ZoneMaxSkill=225;
5686 break;
5687 case 511:
5688 ZoneMaxSkill=225;
5689 break;
5690 case 513:
5691 ZoneMaxSkill=225;
5692 break;
5693 case 516:
5694 ZoneMaxSkill=225;
5695 break;
5696 case 517:
5697 ZoneMaxSkill=225;
5698 break;
5699 case 518:
5700 ZoneMaxSkill=200;
5701 break;
5702 case 537:
5703 ZoneMaxSkill=250;
5704 break;
5705 case 538:
5706 ZoneMaxSkill=250;
5707 break;
5708 case 542:
5709 ZoneMaxSkill=250;
5710 break;
5711 case 543:
5712 ZoneMaxSkill=250;
5713 break;
5714 case 556:
5715 ZoneMaxSkill=50;
5716 break;
5717 case 576:
5718 ZoneMaxSkill=150;
5719 break;
5720 case 598:
5721 ZoneMaxSkill=200;
5722 break;
5723 case 602:
5724 ZoneMaxSkill=200;
5725 break;
5726 case 604:
5727 ZoneMaxSkill=200;
5728 break;
5729 case 618:
5730 ZoneMaxSkill=300;
5731 break;
5732 case 636:
5733 ZoneMaxSkill=135;
5734 break;
5735 case 656:
5736 ZoneMaxSkill=300;
5737 break;
5738 case 657:
5739 ZoneMaxSkill=225;
5740 break;
5741 case 702:
5742 ZoneMaxSkill=50;
5743 break;
5744 case 719:
5745 ZoneMaxSkill=135;
5746 break;
5747 case 720:
5748 ZoneMaxSkill=135;
5749 break;
5750 case 797:
5751 ZoneMaxSkill=225;
5752 break;
5753 case 799:
5754 ZoneMaxSkill=150;
5755 break;
5756 case 810:
5757 ZoneMaxSkill=50;
5758 break;
5759 case 814:
5760 ZoneMaxSkill=50;
5761 break;
5762 case 815:
5763 ZoneMaxSkill=125;
5764 break;
5765 case 818:
5766 ZoneMaxSkill=50;
5767 break;
5768 case 878:
5769 ZoneMaxSkill=275;
5770 break;
5771 case 879:
5772 ZoneMaxSkill=150;
5773 break;
5774 case 896:
5775 ZoneMaxSkill=150;
5776 break;
5777 case 917:
5778 ZoneMaxSkill=100;
5779 break;
5780 case 919:
5781 ZoneMaxSkill=100;
5782 break;
5783 case 922:
5784 ZoneMaxSkill=100;
5785 break;
5786 case 923:
5787 ZoneMaxSkill=50;
5788 break;
5789 case 927:
5790 ZoneMaxSkill=50;
5791 break;
5792 case 968:
5793 ZoneMaxSkill=250;
5794 break;
5795 case 977:
5796 ZoneMaxSkill=250;
5797 break;
5798 case 978:
5799 ZoneMaxSkill=250;
5800 break;
5801 case 979:
5802 ZoneMaxSkill=250;
5803 break;
5804 case 983:
5805 ZoneMaxSkill=250;
5806 break;
5807 case 988:
5808 ZoneMaxSkill=250;
5809 break;
5810 case 997:
5811 ZoneMaxSkill=125;
5812 break;
5813 case 998:
5814 ZoneMaxSkill=125;
5815 break;
5816 case 1001:
5817 ZoneMaxSkill=125;
5818 break;
5819 case 1002:
5820 ZoneMaxSkill=125;
5821 break;
5822 case 1008:
5823 ZoneMaxSkill=250;
5824 break;
5825 case 1017:
5826 ZoneMaxSkill=150;
5827 break;
5828 case 1018:
5829 ZoneMaxSkill=150;
5830 break;
5831 case 1020:
5832 ZoneMaxSkill=150;
5833 break;
5834 case 1021:
5835 ZoneMaxSkill=150;
5836 break;
5837 case 1022:
5838 ZoneMaxSkill=150;
5839 break;
5840 case 1023:
5841 ZoneMaxSkill=150;
5842 break;
5843 case 1024:
5844 ZoneMaxSkill=150;
5845 break;
5846 case 1025:
5847 ZoneMaxSkill=150;
5848 break;
5849 case 1039:
5850 ZoneMaxSkill=150;
5851 break;
5852 case 1056:
5853 ZoneMaxSkill=290;
5854 break;
5855 case 1097:
5856 ZoneMaxSkill=150;
5857 break;
5858 case 1099:
5859 ZoneMaxSkill=300;
5860 break;
5861 case 1101:
5862 ZoneMaxSkill=250;
5863 break;
5864 case 1102:
5865 ZoneMaxSkill=250;
5866 break;
5867 case 1106:
5868 ZoneMaxSkill=250;
5869 break;
5870 case 1112:
5871 ZoneMaxSkill=250;
5872 break;
5873 case 1116:
5874 ZoneMaxSkill=250;
5875 break;
5876 case 1117:
5877 ZoneMaxSkill=250;
5878 break;
5879 case 1119:
5880 ZoneMaxSkill=250;
5881 break;
5882 case 1120:
5883 ZoneMaxSkill=250;
5884 break;
5885 case 1121:
5886 ZoneMaxSkill=250;
5887 break;
5888 case 1126:
5889 ZoneMaxSkill=225;
5890 break;
5891 case 1136:
5892 ZoneMaxSkill=250;
5893 break;
5894 case 1156:
5895 ZoneMaxSkill=225;
5896 break;
5897 case 1176:
5898 ZoneMaxSkill=250;
5899 break;
5900 case 1222:
5901 ZoneMaxSkill=275;
5902 break;
5903 case 1227:
5904 ZoneMaxSkill=275;
5905 break;
5906 case 1228:
5907 ZoneMaxSkill=275;
5908 break;
5909 case 1229:
5910 ZoneMaxSkill=275;
5911 break;
5912 case 1230:
5913 ZoneMaxSkill=275;
5914 break;
5915 case 1231:
5916 ZoneMaxSkill=275;
5917 break;
5918 case 1234:
5919 ZoneMaxSkill=275;
5920 break;
5921 case 1256:
5922 ZoneMaxSkill=275;
5923 break;
5924 case 1296:
5925 ZoneMaxSkill=50;
5926 break;
5927 case 1297:
5928 ZoneMaxSkill=50;
5929 break;
5930 case 1336:
5931 ZoneMaxSkill=250;
5932 break;
5933 case 1337:
5934 ZoneMaxSkill=250;
5935 break;
5936 case 1338:
5937 ZoneMaxSkill=100;
5938 break;
5939 case 1339:
5940 ZoneMaxSkill=200;
5941 break;
5942 case 1477:
5943 ZoneMaxSkill=275;
5944 break;
5945 case 1519:
5946 ZoneMaxSkill=50;
5947 break;
5948 case 1557:
5949 ZoneMaxSkill=175;
5950 break;
5951 case 1577:
5952 ZoneMaxSkill=225;
5953 break;
5954 case 1578:
5955 ZoneMaxSkill=225;
5956 break;
5957 case 1581:
5958 ZoneMaxSkill=100;
5959 break;
5960 case 1617:
5961 ZoneMaxSkill=50;
5962 break;
5963 case 1638:
5964 ZoneMaxSkill=50;
5965 break;
5966 case 1662:
5967 ZoneMaxSkill=50;
5968 break;
5969 case 1681:
5970 ZoneMaxSkill=200;
5971 break;
5972 case 1682:
5973 ZoneMaxSkill=200;
5974 break;
5975 case 1684:
5976 ZoneMaxSkill=200;
5977 break;
5978 case 1701:
5979 ZoneMaxSkill=125;
5980 break;
5981 case 1738:
5982 ZoneMaxSkill=225;
5983 break;
5984 case 1739:
5985 ZoneMaxSkill=225;
5986 break;
5987 case 1740:
5988 ZoneMaxSkill=225;
5989 break;
5990 case 1760:
5991 ZoneMaxSkill=225;
5992 break;
5993 case 1762:
5994 ZoneMaxSkill=250;
5995 break;
5996 case 1764:
5997 ZoneMaxSkill=225;
5998 break;
5999 case 1765:
6000 ZoneMaxSkill=225;
6001 break;
6002 case 1767:
6003 ZoneMaxSkill=275;
6004 break;
6005 case 1770:
6006 ZoneMaxSkill=275;
6007 break;
6008 case 1777:
6009 ZoneMaxSkill=225;
6010 break;
6011 case 1778:
6012 ZoneMaxSkill=225;
6013 break;
6014 case 1780:
6015 ZoneMaxSkill=225;
6016 break;
6017 case 1797:
6018 ZoneMaxSkill=225;
6019 break;
6020 case 1798:
6021 ZoneMaxSkill=225;
6022 break;
6023 case 1883:
6024 ZoneMaxSkill=250;
6025 break;
6026 case 1884:
6027 ZoneMaxSkill=250;
6028 break;
6029 case 1939:
6030 ZoneMaxSkill=250;
6031 break;
6032 case 1940:
6033 ZoneMaxSkill=250;
6034 break;
6035 case 1942:
6036 ZoneMaxSkill=250;
6037 break;
6038 case 1977:
6039 ZoneMaxSkill=225;
6040 break;
6041 case 1997:
6042 ZoneMaxSkill=275;
6043 break;
6044 case 1998:
6045 ZoneMaxSkill=275;
6046 break;
6047 case 2017:
6048 ZoneMaxSkill=300;
6049 break;
6050 case 2077:
6051 ZoneMaxSkill=100;
6052 break;
6053 case 2078:
6054 ZoneMaxSkill=100;
6055 break;
6056 case 2079:
6057 ZoneMaxSkill=225;
6058 break;
6059 case 2097:
6060 ZoneMaxSkill=175;
6061 break;
6062 case 2100:
6063 ZoneMaxSkill=245;
6064 break;
6065 case 2158:
6066 ZoneMaxSkill=250;
6067 break;
6068 case 2246:
6069 ZoneMaxSkill=300;
6070 break;
6071 case 2256:
6072 ZoneMaxSkill=300;
6073 break;
6074 case 2270:
6075 ZoneMaxSkill=300;
6076 break;
6077 case 2272:
6078 ZoneMaxSkill=300;
6079 break;
6080 case 2277:
6081 ZoneMaxSkill=300;
6082 break;
6083 case 2279:
6084 ZoneMaxSkill=300;
6085 break;
6086 case 2298:
6087 ZoneMaxSkill=300;
6088 break;
6089 case 2302:
6090 ZoneMaxSkill=225;
6091 break;
6092 case 2317:
6093 ZoneMaxSkill=250;
6094 break;
6095 case 2318:
6096 ZoneMaxSkill=225;
6097 break;
6098 case 2321:
6099 ZoneMaxSkill=275;
6100 break;
6101 case 2322:
6102 ZoneMaxSkill=50;
6103 break;
6104 case 2323:
6105 ZoneMaxSkill=250;
6106 break;
6107 case 2324:
6108 ZoneMaxSkill=200;
6109 break;
6110 case 2325:
6111 ZoneMaxSkill=150;
6112 break;
6113 case 2326:
6114 ZoneMaxSkill=100;
6115 break;
6116 case 2364:
6117 ZoneMaxSkill=100;
6118 break;
6119 case 2365:
6120 ZoneMaxSkill=150;
6121 break;
6122 case 2398:
6123 ZoneMaxSkill=100;
6124 break;
6125 case 2399:
6126 ZoneMaxSkill=50;
6127 break;
6128 case 2400:
6129 ZoneMaxSkill=250;
6130 break;
6131 case 2401:
6132 ZoneMaxSkill=200;
6133 break;
6134 case 2402:
6135 ZoneMaxSkill=100;
6136 break;
6137 case 2403:
6138 ZoneMaxSkill=225;
6139 break;
6140 case 2405:
6141 ZoneMaxSkill=200;
6142 break;
6143 case 2408:
6144 ZoneMaxSkill=200;
6145 break;
6146 case 2457:
6147 ZoneMaxSkill=150;
6148 break;
6149 case 2477:
6150 ZoneMaxSkill=300;
6151 break;
6152 case 2481:
6153 ZoneMaxSkill=275;
6154 break;
6155 case 2521:
6156 ZoneMaxSkill=250;
6157 break;
6158 case 2522:
6159 ZoneMaxSkill=250;
6160 break;
6161 case 2558:
6162 ZoneMaxSkill=300;
6163 break;
6164 case 2562:
6165 ZoneMaxSkill=300;
6166 break;
6167 case 2597:
6168 ZoneMaxSkill=300;
6169 break;
6170 case 2618:
6171 ZoneMaxSkill=275;
6172 break;
6173 case 2619:
6174 ZoneMaxSkill=300;
6175 break;
6176 case 2620:
6177 ZoneMaxSkill=290;
6178 break;
6179 case 2624:
6180 ZoneMaxSkill=300;
6181 break;
6182 case 2631:
6183 ZoneMaxSkill=300;
6184 break;
6185 case 2797:
6186 ZoneMaxSkill=150;
6187 break;
6188 case 2837:
6189 ZoneMaxSkill=300;
6190 break;
6191 case 2897:
6192 ZoneMaxSkill=150;
6193 break;
6194 default:
6195 ZoneMaxSkill=50;
6196 break;
6198 if((ZoneMaxSkill-50) > fish_value )
6199 return 0;
6200 else if(ZoneMaxSkill-50 <= fish_value && fish_value < ZoneMaxSkill-25)
6201 return 1;
6202 else if(ZoneMaxSkill-25 <= fish_value && fish_value < ZoneMaxSkill)
6203 return 2;
6204 else if(ZoneMaxSkill <= fish_value && fish_value < ZoneMaxSkill + 25)
6205 return 3;
6206 else return 4;
6209 void Player::SetBindPoint(uint64 guid)
6211 WorldPacket data;
6212 data.Initialize( SMSG_BINDER_CONFIRM );
6213 data << guid;
6214 GetSession()->SendPacket( &data );
6217 void Player::SendTalentWipeConfirm(uint64 guid)
6219 WorldPacket data;
6220 data.Initialize( MSG_TALENT_WIPE_CONFIRM );
6221 data << guid;
6222 data << (uint32)resetTalentsCost();
6223 GetSession()->SendPacket( &data );
6226 /*********************************************************/
6227 /*** STORAGE SYSTEM ***/
6228 /*********************************************************/
6230 void Player::SetVirtualItemSlot( uint8 i, Item* item)
6232 assert(i < 3);
6233 SetUInt32Value(UNIT_VIRTUAL_ITEM_INFO + 2*i, item ? item->GetGUIDLow() : 0);
6234 SetUInt32Value(UNIT_VIRTUAL_ITEM_INFO + 2*i +1, item ? item->GetProto()->Sheath : 0);
6235 SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+i,item ? item->GetProto()->DisplayInfoID : 0);
6236 if(i < 2 && item)
6238 if(!item->GetUInt32Value(ITEM_FIELD_ENCHANTMENT+3))
6239 return;
6240 uint32 charges = item->GetUInt32Value(ITEM_FIELD_ENCHANTMENT+3+2);
6241 if(charges == 0)
6242 return;
6243 if(charges > 1)
6244 item->SetUInt32Value(ITEM_FIELD_ENCHANTMENT+3+2,charges-1);
6245 else if(charges <= 1)
6247 AddItemEnchant(item,item->GetUInt32Value(ITEM_FIELD_ENCHANTMENT+3),false);
6248 for(int y=0;y<3;y++)
6249 item->SetUInt32Value(ITEM_FIELD_ENCHANTMENT+3+y,0);
6254 void Player::SetSheath( uint32 sheathed )
6256 Item* item;
6257 switch (sheathed)
6259 case 0: // no prepeared weapon
6260 SetVirtualItemSlot(0,NULL);
6261 SetVirtualItemSlot(1,NULL);
6262 SetVirtualItemSlot(2,NULL);
6263 break;
6264 case 1: // prepeared melee weapon
6266 item = GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
6267 SetVirtualItemSlot(0,item && !item->IsBroken() ? item : NULL);
6268 item = GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
6269 SetVirtualItemSlot(1,item && !item->IsBroken() ? item : NULL);
6270 SetVirtualItemSlot(2,NULL);
6271 }; break;
6272 case 2: // prepeared ranged weapon
6273 SetVirtualItemSlot(0,NULL);
6274 SetVirtualItemSlot(1,NULL);
6275 item = GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_RANGED);
6276 SetVirtualItemSlot(2,item && !item->IsBroken() ? item : NULL);
6277 break;
6278 default:
6279 SetVirtualItemSlot(0,NULL);
6280 SetVirtualItemSlot(1,NULL);
6281 SetVirtualItemSlot(2,NULL);
6282 break;
6286 uint8 Player::FindEquipSlot( uint32 type, uint32 slot, bool swap ) const
6288 uint8 slots[4];
6289 slots[0] = NULL_SLOT;
6290 slots[1] = NULL_SLOT;
6291 slots[2] = NULL_SLOT;
6292 slots[3] = NULL_SLOT;
6293 switch( type )
6295 case INVTYPE_HEAD:
6296 slots[0] = EQUIPMENT_SLOT_HEAD;
6297 break;
6298 case INVTYPE_NECK:
6299 slots[0] = EQUIPMENT_SLOT_NECK;
6300 break;
6301 case INVTYPE_SHOULDERS:
6302 slots[0] = EQUIPMENT_SLOT_SHOULDERS;
6303 break;
6304 case INVTYPE_BODY:
6305 slots[0] = EQUIPMENT_SLOT_BODY;
6306 break;
6307 case INVTYPE_CHEST:
6308 slots[0] = EQUIPMENT_SLOT_CHEST;
6309 break;
6310 case INVTYPE_ROBE:
6311 slots[0] = EQUIPMENT_SLOT_CHEST;
6312 break;
6313 case INVTYPE_WAIST:
6314 slots[0] = EQUIPMENT_SLOT_WAIST;
6315 break;
6316 case INVTYPE_LEGS:
6317 slots[0] = EQUIPMENT_SLOT_LEGS;
6318 break;
6319 case INVTYPE_FEET:
6320 slots[0] = EQUIPMENT_SLOT_FEET;
6321 break;
6322 case INVTYPE_WRISTS:
6323 slots[0] = EQUIPMENT_SLOT_WRISTS;
6324 break;
6325 case INVTYPE_HANDS:
6326 slots[0] = EQUIPMENT_SLOT_HANDS;
6327 break;
6328 case INVTYPE_FINGER:
6329 slots[0] = EQUIPMENT_SLOT_FINGER1;
6330 slots[1] = EQUIPMENT_SLOT_FINGER2;
6331 break;
6332 case INVTYPE_TRINKET:
6333 slots[0] = EQUIPMENT_SLOT_TRINKET1;
6334 slots[1] = EQUIPMENT_SLOT_TRINKET2;
6335 break;
6336 case INVTYPE_CLOAK:
6337 slots[0] = EQUIPMENT_SLOT_BACK;
6338 break;
6339 case INVTYPE_WEAPON:
6341 slots[0] = EQUIPMENT_SLOT_MAINHAND;
6343 // suggest offhand slot only if know dual wielding
6344 // (this will be replace mainhand weapon at auto equip instead unwonted "you don't known dual weilding" ...
6345 if(CanDualWield())
6346 slots[1] = EQUIPMENT_SLOT_OFFHAND;
6347 };break;
6348 case INVTYPE_SHIELD:
6349 slots[0] = EQUIPMENT_SLOT_OFFHAND;
6350 break;
6351 case INVTYPE_RANGED:
6352 slots[0] = EQUIPMENT_SLOT_RANGED;
6353 break;
6354 case INVTYPE_2HWEAPON:
6355 slots[0] = EQUIPMENT_SLOT_MAINHAND;
6356 break;
6357 case INVTYPE_TABARD:
6358 slots[0] = EQUIPMENT_SLOT_TABARD;
6359 break;
6360 case INVTYPE_WEAPONMAINHAND:
6361 slots[0] = EQUIPMENT_SLOT_MAINHAND;
6362 break;
6363 case INVTYPE_WEAPONOFFHAND:
6364 slots[0] = EQUIPMENT_SLOT_OFFHAND;
6365 break;
6366 case INVTYPE_HOLDABLE:
6367 slots[0] = EQUIPMENT_SLOT_OFFHAND;
6368 break;
6369 case INVTYPE_THROWN:
6370 slots[0] = EQUIPMENT_SLOT_RANGED;
6371 break;
6372 case INVTYPE_RANGEDRIGHT:
6373 slots[0] = EQUIPMENT_SLOT_RANGED;
6374 break;
6375 case INVTYPE_BAG:
6376 slots[0] = INVENTORY_SLOT_BAG_1;
6377 slots[1] = INVENTORY_SLOT_BAG_2;
6378 slots[2] = INVENTORY_SLOT_BAG_3;
6379 slots[3] = INVENTORY_SLOT_BAG_4;
6380 break;
6381 case INVTYPE_RELIC:
6382 slots[0] = EQUIPMENT_SLOT_RANGED;
6383 break;
6384 default :
6385 return NULL_SLOT;
6388 if( slot != NULL_SLOT )
6390 if( swap || !GetItemByPos( INVENTORY_SLOT_BAG_0, slot ) )
6392 for (int i = 0; i < 4; i++)
6394 if ( slots[i] == slot )
6395 return slot;
6399 else
6401 // search empty slot at first
6402 for (int i = 0; i < 4; i++)
6404 if ( slots[i] != NULL_SLOT && !GetItemByPos( INVENTORY_SLOT_BAG_0, slots[i] ) )
6405 return slots[i];
6408 // if not found empty and can swap return first appropriate
6409 for (int i = 0; i < 4; i++)
6411 if ( slots[i] != NULL_SLOT && swap )
6412 return slots[i];
6416 // no free position
6417 return NULL_SLOT;
6420 Item* Player::CreateItem( uint32 item, uint32 count ) const
6422 ItemPrototype const *pProto = objmgr.GetItemPrototype( item );
6423 if( pProto )
6425 Item *pItem = NewItemOrBag( pProto );
6426 if ( count > pProto->Stackable )
6427 count = pProto->Stackable;
6428 if ( count < 1 )
6429 count = 1;
6430 if( pItem->Create(objmgr.GenerateLowGuid(HIGHGUID_ITEM), item, const_cast<Player*>(this)) )
6432 pItem->SetCount( count );
6433 return pItem;
6435 else
6436 delete pItem;
6438 return NULL;
6441 uint32 Player::GetItemCount( uint32 item ) const
6443 Item *pItem;
6444 uint32 count = 0;
6445 for(int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; i++)
6447 pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
6448 if( pItem && pItem->GetEntry() == item )
6449 count += pItem->GetCount();
6451 Bag *pBag;
6452 for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)
6454 pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i );
6455 if( pBag )
6456 count += pBag->GetItemCount(item);
6458 return count;
6461 uint32 Player::GetBankItemCount( uint32 item ) const
6463 Item *pItem;
6464 uint32 count = 0;
6465 for(int i = BANK_SLOT_ITEM_START; i < BANK_SLOT_ITEM_END; i++)
6467 pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
6468 if( pItem && pItem->GetEntry() == item )
6469 count += pItem->GetCount();
6471 Bag *pBag;
6472 for(int i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++)
6474 pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i );
6475 if( pBag )
6476 count += pBag->GetItemCount(item);
6478 return count;
6481 uint16 Player::GetPosByGuid( uint64 guid ) const
6483 Item *pItem;
6484 uint16 pos;
6485 for(int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; i++)
6487 pos = ((INVENTORY_SLOT_BAG_0 << 8) | i);
6488 pItem = GetItemByPos( pos );
6489 if( pItem && pItem->GetGUID() == guid )
6490 return pos;
6492 Bag *pBag;
6493 ItemPrototype const *pBagProto;
6494 for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)
6496 pos = ((INVENTORY_SLOT_BAG_0 << 8) | i);
6497 pBag = (Bag*)GetItemByPos( pos );
6498 if( pBag )
6500 pBagProto = pBag->GetProto();
6501 if( pBagProto )
6503 for(uint32 j = 0; j < pBagProto->ContainerSlots; j++)
6505 pos = ((i << 8) | j);
6506 pItem = GetItemByPos( pos );
6507 if( pItem && pItem->GetGUID() == guid )
6508 return pos;
6513 for(int i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++)
6515 pos = ((INVENTORY_SLOT_BAG_0 << 8) | i);
6516 pBag = (Bag*)GetItemByPos( pos );
6517 if( pBag )
6519 pBagProto = pBag->GetProto();
6520 if( pBagProto )
6522 for(uint32 j = 0; j < pBagProto->ContainerSlots; j++)
6524 pos = ((i << 8) | j);
6525 pItem = GetItemByPos( pos );
6526 if( pItem && pItem->GetGUID() == guid )
6527 return pos;
6533 // In this case GUID is trade slot (enchanting fix)
6534 if (7 > guid && GetTrader())
6536 Item *item = GetItemByPos(tradeItems[guid]);
6537 if (item)
6538 return GetPosByGuid(item->GetGUID());
6541 return 0;
6544 Item* Player::GetItemByPos( uint16 pos ) const
6546 uint8 bag = pos >> 8;
6547 uint8 slot = pos & 255;
6548 return GetItemByPos( bag, slot );
6551 Item* Player::GetItemByPos( uint8 bag, uint8 slot ) const
6553 if( bag == INVENTORY_SLOT_BAG_0 && ( slot < BANK_SLOT_BAG_END ) )
6554 return m_items[slot];
6555 else if(bag >= INVENTORY_SLOT_BAG_START && bag < INVENTORY_SLOT_BAG_END
6556 || bag >= BANK_SLOT_BAG_START && bag < BANK_SLOT_BAG_END )
6558 Bag *pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, bag );
6559 if ( pBag )
6560 return pBag->GetItemByPos(slot);
6562 return NULL;
6565 bool Player::HasBankBagSlot( uint8 slot ) const
6567 uint32 maxslot = ((GetUInt32Value(PLAYER_BYTES_2) & 0x70000) >> 16) + BANK_SLOT_BAG_START;
6568 if( slot < maxslot )
6569 return true;
6570 return false;
6573 bool Player::IsInventoryPos( uint16 pos ) const
6575 uint8 bag = pos >> 8;
6576 uint8 slot = pos & 255;
6577 if( bag == INVENTORY_SLOT_BAG_0 && slot == NULL_SLOT )
6578 return true;
6579 if( bag == INVENTORY_SLOT_BAG_0 && ( slot >= INVENTORY_SLOT_ITEM_START && slot < INVENTORY_SLOT_ITEM_END ) )
6580 return true;
6581 if( bag >= INVENTORY_SLOT_BAG_START && bag < INVENTORY_SLOT_BAG_END )
6582 return true;
6583 return false;
6586 bool Player::IsEquipmentPos( uint16 pos ) const
6588 uint8 bag = pos >> 8;
6589 uint8 slot = pos & 255;
6590 if( bag == INVENTORY_SLOT_BAG_0 && ( slot < EQUIPMENT_SLOT_END ) )
6591 return true;
6592 if( bag == INVENTORY_SLOT_BAG_0 && ( slot >= INVENTORY_SLOT_BAG_START && slot < INVENTORY_SLOT_BAG_END ) )
6593 return true;
6594 return false;
6597 bool Player::IsBankPos( uint16 pos ) const
6599 uint8 bag = pos >> 8;
6600 uint8 slot = pos & 255;
6601 if( bag == INVENTORY_SLOT_BAG_0 && ( slot >= BANK_SLOT_ITEM_START && slot < BANK_SLOT_ITEM_END ) )
6602 return true;
6603 if( bag == INVENTORY_SLOT_BAG_0 && ( slot >= BANK_SLOT_BAG_START && slot < BANK_SLOT_BAG_END ) )
6604 return true;
6605 if( bag >= BANK_SLOT_BAG_START && bag < BANK_SLOT_BAG_END )
6606 return true;
6607 return false;
6610 bool Player::IsBagPos( uint16 pos ) const
6612 uint8 bag = pos >> 8;
6613 uint8 slot = pos & 255;
6614 if( bag == INVENTORY_SLOT_BAG_0 && ( slot >= INVENTORY_SLOT_BAG_START && slot < INVENTORY_SLOT_BAG_END ) )
6615 return true;
6616 if( bag == INVENTORY_SLOT_BAG_0 && ( slot >= BANK_SLOT_BAG_START && slot < BANK_SLOT_BAG_END ) )
6617 return true;
6618 return false;
6621 bool Player::HasItemCount( uint32 item, uint32 count ) const
6623 Item *pItem;
6624 uint32 tempcount = 0;
6625 for(int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; i++)
6627 pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
6628 if( pItem && pItem->GetEntry() == item )
6630 tempcount += pItem->GetCount();
6631 if( tempcount >= count )
6632 return true;
6635 Bag *pBag;
6636 ItemPrototype const *pBagProto;
6637 for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)
6639 pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i );
6640 if( pBag )
6642 pBagProto = pBag->GetProto();
6643 if( pBagProto )
6645 for(uint32 j = 0; j < pBagProto->ContainerSlots; j++)
6647 pItem = GetItemByPos( i, j );
6648 if( pItem && pItem->GetEntry() == item )
6650 tempcount += pItem->GetCount();
6651 if( tempcount >= count )
6652 return true;
6658 return false;
6661 uint8 Player::CanStoreNewItem( uint8 bag, uint8 slot, uint16 &dest, uint32 item, uint32 count, bool swap ) const
6663 dest = 0;
6664 Item *pItem = CreateItem( item, count );
6665 if( pItem )
6667 uint8 result = CanStoreItem( bag, slot, dest, pItem, swap );
6668 delete pItem;
6669 return result;
6671 if( !swap )
6672 return EQUIP_ERR_ITEM_NOT_FOUND;
6673 else
6674 return EQUIP_ERR_ITEMS_CANT_BE_SWAPPED;
6677 uint8 Player::CanStoreItem( uint8 bag, uint8 slot, uint16 &dest, Item *pItem, bool swap ) const
6679 dest = 0;
6680 if( pItem )
6682 sLog.outDebug( "STORAGE: CanStoreItem bag = %u, slot = %u, item = %u, count = %u", bag, slot, pItem->GetEntry(), pItem->GetCount());
6683 ItemPrototype const *pProto = pItem->GetProto();
6684 if( pProto )
6686 Item *pItem2;
6687 Bag *pBag;
6688 ItemPrototype const *pBagProto;
6689 uint16 pos;
6690 if(pItem->IsBindedNotWith(GetGUID()))
6691 return EQUIP_ERR_DONT_OWN_THAT_ITEM;
6692 if( bag == 0 )
6694 // check count of items
6695 if( !swap && pProto->MaxCount > 0 )
6697 uint32 curcount = 0;
6698 for(int i = EQUIPMENT_SLOT_START; i < BANK_SLOT_BAG_END; i++)
6700 pos = ((INVENTORY_SLOT_BAG_0 << 8) | i );
6701 pItem2 = GetItemByPos( pos );
6702 if( pItem2 && pItem2->GetEntry() == pItem->GetEntry() )
6704 curcount += pItem2->GetCount();
6705 if( curcount + pItem->GetCount() > pProto->MaxCount )
6706 return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
6709 for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)
6711 pos = ((INVENTORY_SLOT_BAG_0 << 8) | i );
6712 pBag = (Bag*)GetItemByPos( pos );
6713 if( pBag )
6715 pBagProto = pBag->GetProto();
6716 if( pBagProto )
6718 for(uint32 j = 0; j < pBagProto->ContainerSlots; j++)
6720 pos = ((i << 8) | j );
6721 pItem2 = GetItemByPos( pos );
6722 if( pItem2 && pItem2->GetEntry() == pItem->GetEntry() )
6724 curcount += pItem2->GetCount();
6725 if( curcount + pItem->GetCount() > pProto->MaxCount )
6726 return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
6732 for(int i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++)
6734 pos = ((INVENTORY_SLOT_BAG_0 << 8) | i );
6735 pBag = (Bag*)GetItemByPos( pos );
6736 if( pBag )
6738 pBagProto = pBag->GetProto();
6739 if( pBagProto )
6741 for(uint32 j = 0; j < pBagProto->ContainerSlots; j++)
6743 pos = ((i << 8) | j );
6744 pItem2 = GetItemByPos( pos );
6745 if( pItem2 && pItem2->GetEntry() == pItem->GetEntry() )
6747 curcount += pItem2->GetCount();
6748 if( curcount + pItem->GetCount() > pProto->MaxCount )
6749 return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
6757 // search stack for merge to
6758 if( pProto->Stackable > 1 )
6760 for(int i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; i++)
6762 pos = ( (INVENTORY_SLOT_BAG_0 << 8) | i );
6763 pItem2 = GetItemByPos( pos );
6764 if( pItem2 && pItem2->GetEntry() == pItem->GetEntry() && pItem2->GetCount() + pItem->GetCount() <= pProto->Stackable )
6766 dest = pos;
6767 return EQUIP_ERR_OK;
6770 for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)
6772 pos = ( (INVENTORY_SLOT_BAG_0 << 8) | i );
6773 pBag = (Bag*)GetItemByPos( pos );
6774 if( pBag )
6776 pBagProto = pBag->GetProto();
6777 if( pBagProto )
6779 for(uint32 j = 0; j < pBagProto->ContainerSlots; j++)
6781 pos = ( (i << 8) | j );
6782 pItem2 = GetItemByPos( pos );
6783 if( pItem2 && pItem2->GetEntry() == pItem->GetEntry() && pItem2->GetCount() + pItem->GetCount() <= pProto->Stackable )
6785 dest = pos;
6786 return EQUIP_ERR_OK;
6794 // search free slot - ammo special case
6795 if( pProto->Class == ITEM_CLASS_PROJECTILE )
6797 for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)
6799 pos = ( (INVENTORY_SLOT_BAG_0 << 8) | i );
6800 pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i );
6801 if( pBag )
6803 pBagProto = pBag->GetProto();
6804 if( pBagProto && pBagProto->SubClass == pProto->SubClass )
6806 for(uint32 j = 0; j < pBagProto->ContainerSlots; j++)
6808 pos = ( (INVENTORY_SLOT_BAG_0 << 8) | i );
6809 pItem2 = GetItemByPos( i, j );
6810 if( !pItem2 )
6812 dest = ( (i << 8) | j );
6813 return EQUIP_ERR_OK;
6821 // search free slot
6822 for(int i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; i++)
6824 pItem2 = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
6825 if( !pItem2 )
6827 dest = ( (INVENTORY_SLOT_BAG_0 << 8) | i );
6828 return EQUIP_ERR_OK;
6832 for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)
6834 pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i );
6835 if( pBag )
6837 pBagProto = pBag->GetProto();
6838 if( pBagProto && pBagProto->Class != ITEM_CLASS_QUIVER )
6840 for(uint32 j = 0; j < pBagProto->ContainerSlots; j++)
6842 pItem2 = GetItemByPos( i, j );
6843 if( !pItem2 )
6845 dest = ( (i << 8) | j );
6846 return EQUIP_ERR_OK;
6852 return EQUIP_ERR_INVENTORY_FULL;
6854 else // in specific bag
6856 if( slot == NULL_SLOT )
6858 if( pProto->InventoryType == INVTYPE_BAG )
6860 Bag *pBag = (Bag*)pItem;
6861 if( pBag && !pBag->IsEmpty() )
6862 return EQUIP_ERR_NONEMPTY_BAG_OVER_OTHER_BAG;
6865 // search stack in bag for merge to
6866 if( pProto->Stackable > 1 )
6868 if( bag == INVENTORY_SLOT_BAG_0 )
6870 for(int i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; i++)
6872 pItem2 = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
6873 if( pItem2 && pItem2->GetEntry() == pItem->GetEntry() && pItem2->GetCount() + pItem->GetCount() <= pProto->Stackable )
6875 dest = ( (INVENTORY_SLOT_BAG_0 << 8) | i );
6876 return EQUIP_ERR_OK;
6880 else
6882 pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, bag );
6883 if( pBag )
6885 pBagProto = pBag->GetProto();
6886 if( pBagProto )
6888 for(uint32 j = 0; j < pBagProto->ContainerSlots; j++)
6890 pItem2 = GetItemByPos( bag, j );
6891 if( pItem2 && pItem2->GetEntry() == pItem->GetEntry() && pItem2->GetCount() + pItem->GetCount() <= pProto->Stackable )
6893 dest = ( (bag << 8) | j );
6894 return EQUIP_ERR_OK;
6901 if( bag == INVENTORY_SLOT_BAG_0 )
6903 for(int i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; i++)
6905 pItem2 = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
6906 if( !pItem2 )
6908 dest = ( (INVENTORY_SLOT_BAG_0 << 8) | i );
6909 return EQUIP_ERR_OK;
6913 else
6915 pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, bag );
6916 if( pBag )
6918 pBagProto = pBag->GetProto();
6919 if( pBagProto )
6921 if( pBagProto->Class == ITEM_CLASS_QUIVER && pBagProto->SubClass != pProto->SubClass )
6922 return EQUIP_ERR_ONLY_AMMO_CAN_GO_HERE;
6923 if( pBagProto->Class == ITEM_CLASS_CONTAINER && pBagProto->SubClass > ITEM_SUBCLASS_CONTAINER && pBagProto->SubClass != pProto->SubClass )
6924 return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG;
6925 for(uint32 j = 0; j < pBagProto->ContainerSlots; j++)
6927 pItem2 = GetItemByPos( bag, j );
6928 if( !pItem2 )
6930 dest = ( (bag << 8) | j );
6931 return EQUIP_ERR_OK;
6937 return EQUIP_ERR_BAG_FULL;
6939 else // specific bag and slot
6941 if( pProto->InventoryType == INVTYPE_BAG )
6943 Bag *pBag = (Bag*)pItem;
6944 if( pBag && !pBag->IsEmpty() )
6945 return EQUIP_ERR_NONEMPTY_BAG_OVER_OTHER_BAG;
6947 pItem2 = GetItemByPos( bag, slot );
6948 if( pItem2 && !swap )
6950 if( pProto->Stackable > 1 && pItem2->GetEntry() == pItem->GetEntry() && pItem2->GetCount() < pProto->Stackable )
6952 dest = ( (bag << 8) | slot );
6953 return EQUIP_ERR_OK;
6955 else
6956 return EQUIP_ERR_COULDNT_SPLIT_ITEMS;
6958 else
6960 if( bag == INVENTORY_SLOT_BAG_0 )
6962 dest = ( (bag << 8) | slot );
6963 return EQUIP_ERR_OK;
6965 else
6967 pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, bag );
6968 if( pBag )
6970 pBagProto = pBag->GetProto();
6971 if( pBagProto )
6973 if( pBagProto->Class == ITEM_CLASS_QUIVER && pBagProto->SubClass != pProto->SubClass )
6974 return EQUIP_ERR_ONLY_AMMO_CAN_GO_HERE;
6975 if( pBagProto->Class == ITEM_CLASS_CONTAINER && pBagProto->SubClass > ITEM_SUBCLASS_CONTAINER && pBagProto->SubClass != pProto->SubClass )
6976 return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG;
6977 dest = ( (bag << 8) | slot );
6978 return EQUIP_ERR_OK;
6987 if( !swap )
6988 return EQUIP_ERR_ITEM_NOT_FOUND;
6989 else
6990 return EQUIP_ERR_ITEMS_CANT_BE_SWAPPED;
6991 return 0;
6994 uint8 Player::CanEquipItem( uint8 slot, uint16 &dest, Item *pItem, bool swap, bool check_alive ) const
6996 dest = 0;
6997 if( pItem )
6999 sLog.outDebug( "STORAGE: CanEquipItem slot = %u, item = %u, count = %u", slot, pItem->GetEntry(), pItem->GetCount());
7000 ItemPrototype const *pProto = pItem->GetProto();
7001 if( pProto )
7003 if( isInCombat()&& pProto->Class != ITEM_CLASS_WEAPON && pProto->Class != ITEM_CLASS_PROJECTILE &&
7004 pProto->SubClass != ITEM_SUBCLASS_ARMOR_SHIELD && pProto->InventoryType != INVTYPE_RELIC)
7005 return EQUIP_ERR_CANT_DO_IN_COMBAT;
7007 uint32 type = pProto->InventoryType;
7008 uint8 eslot = FindEquipSlot( type, slot, swap );
7009 if( eslot == NULL_SLOT )
7010 return EQUIP_ERR_ITEM_CANT_BE_EQUIPPED;
7012 uint8 msg = CanUseItem( pItem , check_alive );
7013 if( msg != EQUIP_ERR_OK )
7014 return msg;
7015 if( !swap && GetItemByPos( INVENTORY_SLOT_BAG_0, eslot ) )
7016 return EQUIP_ERR_NO_EQUIPMENT_SLOT_AVAILABLE;
7018 if(eslot == EQUIPMENT_SLOT_OFFHAND)
7020 if( type == INVTYPE_WEAPON || type == INVTYPE_WEAPONOFFHAND )
7022 if(!CanDualWield())
7023 return EQUIP_ERR_CANT_DUAL_WIELD;
7026 Item *mainItem = GetItemByPos( INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND );
7027 if(mainItem)
7029 if(mainItem->GetProto()->InventoryType == INVTYPE_2HWEAPON)
7030 return EQUIP_ERR_CANT_EQUIP_WITH_TWOHANDED;
7031 }else
7032 // not let equip offhand item if mainhand not equiped
7033 return EQUIP_ERR_ITEM_CANT_BE_EQUIPPED;
7037 if( type == INVTYPE_2HWEAPON )
7039 uint8 twinslot = ( eslot == EQUIPMENT_SLOT_MAINHAND ? EQUIPMENT_SLOT_OFFHAND : EQUIPMENT_SLOT_MAINHAND );
7040 Item *twinItem = GetItemByPos( INVENTORY_SLOT_BAG_0, twinslot );
7041 if( twinItem )
7042 return EQUIP_ERR_ITEM_CANT_BE_EQUIPPED;
7044 dest = ((INVENTORY_SLOT_BAG_0 << 8) | eslot);
7045 return EQUIP_ERR_OK;
7048 if( !swap )
7049 return EQUIP_ERR_ITEM_NOT_FOUND;
7050 else
7051 return EQUIP_ERR_ITEMS_CANT_BE_SWAPPED;
7054 uint8 Player::CanUnequipItem( uint16 pos, bool swap ) const
7056 // Applied only to equiped items
7057 if(!IsEquipmentPos(pos))
7058 return EQUIP_ERR_OK;
7060 Item* pItem = GetItemByPos(pos);
7062 // Applied only to existed equiped item
7063 if( !pItem )
7064 return EQUIP_ERR_OK;
7066 sLog.outDebug( "STORAGE: CanUnequipItem slot = %u, item = %u, count = %u", pos, pItem->GetEntry(), pItem->GetCount());
7068 ItemPrototype const *pProto = pItem->GetProto();
7069 if( !pProto )
7070 return EQUIP_ERR_ITEM_NOT_FOUND;
7072 if( isInCombat()&& pProto->Class != ITEM_CLASS_WEAPON && pProto->Class != ITEM_CLASS_PROJECTILE &&
7073 pProto->SubClass != ITEM_SUBCLASS_ARMOR_SHIELD && pProto->InventoryType != INVTYPE_RELIC )
7074 return EQUIP_ERR_CANT_DO_IN_COMBAT;
7076 if(!swap && pItem->IsBag() && !((Bag*)pItem)->IsEmpty())
7077 return EQUIP_ERR_CAN_ONLY_DO_WITH_EMPTY_BAGS;
7079 // All equiped items can swaped (not in combat case)
7080 if(swap)
7081 return EQUIP_ERR_OK;
7083 uint8 slot = pos & 255;
7085 // can't unequip mainhand item if offhand item equiped
7086 if(slot == EQUIPMENT_SLOT_MAINHAND && GetItemByPos( INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND ))
7087 return EQUIP_ERR_CANT_DO_RIGHT_NOW;
7089 return EQUIP_ERR_OK;
7092 uint8 Player::CanBankItem( uint8 bag, uint8 slot, uint16 &dest, Item *pItem, bool swap, bool check_alive ) const
7094 dest = 0;
7095 if( pItem )
7097 sLog.outDebug( "STORAGE: CanBankItem bag = %u, slot = %u, item = %u, count = %u", bag, slot, pItem->GetEntry(), pItem->GetCount());
7098 ItemPrototype const *pProto = pItem->GetProto();
7099 if( pProto )
7101 Item *pItem2;
7102 Bag *pBag;
7103 ItemPrototype const *pBagProto;
7104 uint16 pos;
7105 if( pItem->IsBindedNotWith(GetGUID()) )
7106 return EQUIP_ERR_DONT_OWN_THAT_ITEM;
7107 if( bag == 0 )
7109 if( !swap && pProto->MaxCount > 0 )
7111 uint32 curcount = 0;
7112 for(int i = EQUIPMENT_SLOT_START; i < BANK_SLOT_BAG_END; i++)
7114 pos = ((INVENTORY_SLOT_BAG_0 << 8) | i );
7115 pItem2 = GetItemByPos( pos );
7116 if( pItem2 && pItem2->GetEntry() == pItem->GetEntry() )
7118 curcount += pItem2->GetCount();
7119 if( curcount + pItem->GetCount() > pProto->MaxCount )
7120 return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
7123 for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)
7125 pos = ((INVENTORY_SLOT_BAG_0 << 8) | i );
7126 pBag = (Bag*)GetItemByPos( pos );
7127 if( pBag )
7129 pBagProto = pBag->GetProto();
7130 if( pBagProto )
7132 for(uint32 j = 0; j < pBagProto->ContainerSlots; j++)
7134 pos = ((i << 8) | j );
7135 pItem2 = GetItemByPos( pos );
7136 if( pItem2 && pItem2->GetEntry() == pItem->GetEntry() )
7138 curcount += pItem2->GetCount();
7139 if( curcount + pItem->GetCount() > pProto->MaxCount )
7140 return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
7146 for(int i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++)
7148 pos = ((INVENTORY_SLOT_BAG_0 << 8) | i );
7149 pBag = (Bag*)GetItemByPos( pos );
7150 if( pBag )
7152 pBagProto = pBag->GetProto();
7153 if( pBagProto )
7155 for(uint32 j = 0; j < pBagProto->ContainerSlots; j++)
7157 pos = ((i << 8) | j );
7158 pItem2 = GetItemByPos( pos );
7159 if( pItem2 && pItem2->GetEntry() == pItem->GetEntry() )
7161 curcount += pItem2->GetCount();
7162 if( curcount + pItem->GetCount() > pProto->MaxCount )
7163 return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
7170 if( pProto->Stackable > 1 )
7172 for(int i = BANK_SLOT_ITEM_START; i < BANK_SLOT_ITEM_END; i++)
7174 pos = ( (INVENTORY_SLOT_BAG_0 << 8) | i );
7175 pItem2 = GetItemByPos( pos );
7176 if( pItem2 && pItem2->GetEntry() == pItem->GetEntry() && pItem2->GetCount() + pItem->GetCount() <= pProto->Stackable )
7178 dest = pos;
7179 return EQUIP_ERR_OK;
7182 for(int i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++)
7184 pos = ( (INVENTORY_SLOT_BAG_0 << 8) | i );
7185 pBag = (Bag*)GetItemByPos( pos );
7186 if( pBag )
7188 pBagProto = pBag->GetProto();
7189 if( pBagProto )
7191 for(uint32 j = 0; j < pBagProto->ContainerSlots; j++)
7193 pos = ( (i << 8) | j );
7194 pItem2 = GetItemByPos( pos );
7195 if( pItem2 && pItem2->GetEntry() == pItem->GetEntry() && pItem2->GetCount() + pItem->GetCount() <= pProto->Stackable )
7197 dest = pos;
7198 return EQUIP_ERR_OK;
7205 if( pProto->Class == ITEM_CLASS_PROJECTILE )
7207 for(int i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++)
7209 pos = ( (INVENTORY_SLOT_BAG_0 << 8) | i );
7210 pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i );
7211 if( pBag )
7213 pBagProto = pBag->GetProto();
7214 if( pBagProto && pBagProto->SubClass == pProto->SubClass )
7216 for(int j = 0; j < pBagProto->ContainerSlots; j++)
7218 pos = ( (INVENTORY_SLOT_BAG_0 << 8) | i );
7219 pItem2 = GetItemByPos( i, j );
7220 if( !pItem2 )
7222 dest = ( (i << 8) | j );
7223 return EQUIP_ERR_OK;
7230 for(int i = BANK_SLOT_ITEM_START; i < BANK_SLOT_ITEM_END; i++)
7232 pItem2 = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
7233 if( !pItem2 )
7235 dest = ( (INVENTORY_SLOT_BAG_0 << 8) | i );
7236 return EQUIP_ERR_OK;
7239 for(int i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++)
7241 pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i );
7242 if( pBag )
7244 pBagProto = pBag->GetProto();
7245 if( pBagProto && pBagProto->Class != ITEM_CLASS_QUIVER )
7247 for(uint32 j = 0; j < pBagProto->ContainerSlots; j++)
7249 pItem2 = GetItemByPos( i, j );
7250 if( !pItem2 )
7252 dest = ( (i << 8) | j );
7253 return EQUIP_ERR_OK;
7259 return EQUIP_ERR_BANK_FULL;
7261 else
7263 if( slot == NULL_SLOT )
7265 if( pProto->InventoryType == INVTYPE_BAG )
7267 Bag *pBag = (Bag*)pItem;
7268 if( pBag && !pBag->IsEmpty() )
7269 return EQUIP_ERR_NONEMPTY_BAG_OVER_OTHER_BAG;
7271 if( pProto->Stackable > 1 )
7273 if( bag == INVENTORY_SLOT_BAG_0 )
7275 for(int i = BANK_SLOT_ITEM_START; i < BANK_SLOT_ITEM_END; i++)
7277 pItem2 = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
7278 if( pItem2 && pItem2->GetEntry() == pItem->GetEntry() && pItem2->GetCount() + pItem->GetCount() <= pProto->Stackable )
7280 dest = ( (INVENTORY_SLOT_BAG_0 << 8) | i );
7281 return EQUIP_ERR_OK;
7285 else
7287 pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, bag );
7288 if( pBag )
7290 pBagProto = pBag->GetProto();
7291 if( pBagProto )
7293 for(uint32 j = 0; j < pBagProto->ContainerSlots; j++)
7295 pItem2 = GetItemByPos( bag, j );
7296 if( pItem2 && pItem2->GetEntry() == pItem->GetEntry() && pItem2->GetCount() + pItem->GetCount() <= pProto->Stackable )
7298 dest = ( (bag << 8) | j );
7299 return EQUIP_ERR_OK;
7306 if( bag == INVENTORY_SLOT_BAG_0 )
7308 for(int i = BANK_SLOT_ITEM_START; i < BANK_SLOT_ITEM_END; i++)
7310 pItem2 = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
7311 if( !pItem2 )
7313 dest = ( (INVENTORY_SLOT_BAG_0 << 8) | i );
7314 return EQUIP_ERR_OK;
7318 else
7320 pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, bag );
7321 if( pBag )
7323 pBagProto = pBag->GetProto();
7324 if( pBagProto )
7326 if( pBagProto->Class == ITEM_CLASS_QUIVER && pBagProto->SubClass != pProto->SubClass )
7327 return EQUIP_ERR_ONLY_AMMO_CAN_GO_HERE;
7328 if( pBagProto->Class == ITEM_CLASS_CONTAINER && pBagProto->SubClass > ITEM_SUBCLASS_CONTAINER && pBagProto->SubClass != pProto->SubClass )
7329 return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG;
7330 for(uint32 j = 0; j < pBagProto->ContainerSlots; j++)
7332 pItem2 = GetItemByPos( bag, j );
7333 if( !pItem2 )
7335 dest = ( (bag << 8) | j );
7336 return EQUIP_ERR_OK;
7342 return EQUIP_ERR_BAG_FULL;
7344 else
7346 if( pProto->InventoryType == INVTYPE_BAG )
7348 Bag *pBag = (Bag*)pItem;
7349 if( pBag )
7351 if( slot >= BANK_SLOT_BAG_START && slot < BANK_SLOT_BAG_END )
7353 if( !HasBankBagSlot( slot ) )
7354 return EQUIP_ERR_MUST_PURCHASE_THAT_BAG_SLOT;
7355 if( uint8 cantuse = CanUseItem( pItem, check_alive ) != EQUIP_ERR_OK )
7356 return cantuse;
7358 else
7360 if( !pBag->IsEmpty() )
7361 return EQUIP_ERR_NONEMPTY_BAG_OVER_OTHER_BAG;
7365 else
7367 if( slot >= BANK_SLOT_BAG_START && slot < BANK_SLOT_BAG_END )
7368 return EQUIP_ERR_ITEM_DOESNT_GO_TO_SLOT;
7370 pItem2 = GetItemByPos( bag, slot );
7371 if( pItem2 && !swap )
7373 if( pProto->Stackable > 1 && pItem2->GetEntry() == pItem->GetEntry() && pItem2->GetCount() + pItem->GetCount() <= pProto->Stackable )
7375 dest = ( (bag << 8) | slot );
7376 return EQUIP_ERR_OK;
7378 else
7379 return EQUIP_ERR_COULDNT_SPLIT_ITEMS;
7381 else
7383 if( bag == INVENTORY_SLOT_BAG_0 )
7385 dest = ( (bag << 8) | slot );
7386 return EQUIP_ERR_OK;
7388 else
7390 pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, bag );
7391 if( pBag )
7393 pBagProto = pBag->GetProto();
7394 if( pBagProto )
7396 if( pBagProto->Class == ITEM_CLASS_QUIVER && pBagProto->SubClass != pProto->SubClass )
7397 return EQUIP_ERR_ONLY_AMMO_CAN_GO_HERE;
7398 if( pBagProto->Class == ITEM_CLASS_CONTAINER && pBagProto->SubClass > ITEM_SUBCLASS_CONTAINER && pBagProto->SubClass != pProto->SubClass )
7399 return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG;
7400 dest = ( (bag << 8) | slot );
7401 return EQUIP_ERR_OK;
7410 if( !swap )
7411 return EQUIP_ERR_ITEM_NOT_FOUND;
7412 else
7413 return EQUIP_ERR_ITEMS_CANT_BE_SWAPPED;
7414 return 0;
7417 uint8 Player::CanUseItem( Item *pItem, bool check_alive ) const
7419 if( pItem )
7421 sLog.outDebug( "STORAGE: CanUseItem item = %u", pItem->GetEntry());
7422 if( !isAlive() && check_alive )
7423 return EQUIP_ERR_YOU_ARE_DEAD;
7424 //if( isStunned() )
7425 // return EQUIP_ERR_YOU_ARE_STUNNED;
7426 ItemPrototype const *pProto = pItem->GetProto();
7427 if( pProto )
7429 if( pItem->IsBindedNotWith(GetGUID()) )
7430 return EQUIP_ERR_DONT_OWN_THAT_ITEM;
7431 if( (pProto->AllowableClass & getClassMask()) == 0 || (pProto->AllowableRace & getRaceMask()) == 0 )
7432 return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM;
7433 if( pItem->GetSkill() != 0 )
7435 if( GetSkillValue( pItem->GetSkill() ) == 0 )
7436 return EQUIP_ERR_NO_REQUIRED_PROFICIENCY;
7438 if( pProto->RequiredSkill != 0 )
7440 if( GetSkillValue( pProto->RequiredSkill ) == 0 )
7441 return EQUIP_ERR_NO_REQUIRED_PROFICIENCY;
7442 else if( GetSkillValue( pProto->RequiredSkill ) < pProto->RequiredSkillRank )
7443 return EQUIP_ERR_SKILL_ISNT_HIGH_ENOUGH;
7445 if( pProto->RequiredSpell != 0 && !HasSpell( pProto->RequiredSpell ) )
7446 return EQUIP_ERR_NO_REQUIRED_PROFICIENCY;
7447 if( GetHonorRank() < pProto->RequiredHonorRank )
7448 return EQUIP_ITEM_RANK_NOT_ENOUGH;
7449 /*if( GetREputation() < pProto->RequiredReputation )
7450 return EQUIP_ITEM_REPUTATION_NOT_ENOUGH;
7452 if( getLevel() < pProto->RequiredLevel )
7453 return EQUIP_ERR_YOU_MUST_REACH_LEVEL_N;
7454 return EQUIP_ERR_OK;
7457 return EQUIP_ERR_ITEM_NOT_FOUND;
7460 bool Player::CanUseItem( ItemPrototype const *pProto )
7462 // Used by group, function NeedBeforeGreed, to know if a prototype can be used by a player
7464 if( pProto )
7466 if( (pProto->AllowableClass & getClassMask()) == 0 || (pProto->AllowableRace & getRaceMask()) == 0 )
7467 return false;
7468 if( pProto->RequiredSkill != 0 )
7470 if( GetSkillValue( pProto->RequiredSkill ) == 0 )
7471 return false;
7472 else if( GetSkillValue( pProto->RequiredSkill ) < pProto->RequiredSkillRank )
7473 return false;
7475 if( pProto->RequiredSpell != 0 && !HasSpell( pProto->RequiredSpell ) )
7476 return false;
7477 if( GetHonorRank() < pProto->RequiredHonorRank )
7478 return false;
7479 if( getLevel() < pProto->RequiredLevel )
7480 return false;
7481 return true;
7483 return false;
7486 uint8 Player::CanUseAmmo( uint32 item ) const
7488 sLog.outDebug( "STORAGE: CanUseAmmo item = %u", item);
7489 if( !isAlive() )
7490 return EQUIP_ERR_YOU_ARE_DEAD;
7491 //if( isStunned() )
7492 // return EQUIP_ERR_YOU_ARE_STUNNED;
7493 ItemPrototype const *pProto = objmgr.GetItemPrototype( item );
7494 if( pProto )
7496 if( pProto->InventoryType!= INVTYPE_AMMO )
7497 return EQUIP_ERR_ONLY_AMMO_CAN_GO_HERE;
7498 if( (pProto->AllowableClass & getClassMask()) == 0 || (pProto->AllowableRace & getRaceMask()) == 0 )
7499 return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM;
7500 if( pProto->RequiredSkill != 0 )
7502 if( GetSkillValue( pProto->RequiredSkill ) == 0 )
7503 return EQUIP_ERR_NO_REQUIRED_PROFICIENCY;
7504 else if( GetSkillValue( pProto->RequiredSkill ) < pProto->RequiredSkillRank )
7505 return EQUIP_ERR_SKILL_ISNT_HIGH_ENOUGH;
7507 if( pProto->RequiredSpell != 0 && !HasSpell( pProto->RequiredSpell ) )
7508 return EQUIP_ERR_NO_REQUIRED_PROFICIENCY;
7509 if( GetHonorRank() < pProto->RequiredHonorRank )
7510 return EQUIP_ITEM_RANK_NOT_ENOUGH;
7511 /*if( GetREputation() < pProto->RequiredReputation )
7512 return EQUIP_ITEM_REPUTATION_NOT_ENOUGH;
7514 if( getLevel() < pProto->RequiredLevel )
7515 return EQUIP_ERR_YOU_MUST_REACH_LEVEL_N;
7516 return EQUIP_ERR_OK;
7518 return EQUIP_ERR_ITEM_NOT_FOUND;
7521 // Return stored item (if stored to stack, it can diff. from pItem). And pItem ca be deleted in this case.
7522 Item* Player::StoreNewItem( uint16 pos, uint32 item, uint32 count, bool update ,bool fromLoot )
7524 Item *pItem = CreateItem( item, count );
7525 if( pItem )
7527 ItemPrototype const *pProto = pItem->GetProto();
7528 ItemAddedQuestCheck( item, count );
7529 if(fromLoot)
7530 pItem->SetItemRandomProperties();
7531 Item * retItem = StoreItem( pos, pItem, update );
7533 return retItem;
7535 return NULL;
7538 // Return stored item (if stored to stack, it can diff. from pItem). And pItem ca be deleted in this case.
7539 Item* Player::StoreItem( uint16 pos, Item *pItem, bool update )
7541 if( pItem )
7543 if( pItem->GetProto()->Bonding == BIND_WHEN_PICKED_UP || pItem->GetProto()->Class == ITEM_CLASS_QUEST)
7544 pItem->SetBinding( true );
7546 uint8 bag = pos >> 8;
7547 uint8 slot = pos & 255;
7549 sLog.outDebug( "STORAGE: StoreItem bag = %u, slot = %u, item = %u, count = %u", bag, slot, pItem->GetEntry(), pItem->GetCount());
7551 Item *pItem2 = GetItemByPos( bag, slot );
7553 if( !pItem2 )
7555 if( bag == INVENTORY_SLOT_BAG_0 )
7557 m_items[slot] = pItem;
7558 SetUInt64Value( (uint16)(PLAYER_FIELD_INV_SLOT_HEAD + (slot * 2) ), pItem->GetGUID() );
7559 pItem->SetUInt64Value( ITEM_FIELD_CONTAINED, GetGUID() );
7560 pItem->SetUInt64Value( ITEM_FIELD_OWNER, GetGUID() );
7562 pItem->SetSlot( slot );
7563 pItem->SetContainer( NULL );
7565 if( IsInWorld() && update )
7567 pItem->AddToWorld();
7568 pItem->SendUpdateToPlayer( this );
7571 pItem->SetState(ITEM_CHANGED, this);
7573 else
7575 Bag *pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, bag );
7576 if( pBag )
7578 pBag->StoreItem( slot, pItem, update );
7579 if( IsInWorld() && update )
7581 pItem->AddToWorld();
7582 pItem->SendUpdateToPlayer( this );
7584 pItem->SetState(ITEM_CHANGED, this);
7585 pBag->SetState(ITEM_CHANGED, this);
7589 else
7591 pItem2->SetCount( pItem2->GetCount() + pItem->GetCount() );
7592 if( IsInWorld() && update )
7593 pItem2->SendUpdateToPlayer( this );
7595 // delete item (it not in any slot currently)
7596 //pItem->DeleteFromDB();
7597 if( IsInWorld() && update )
7599 pItem->RemoveFromWorld();
7600 pItem->DestroyForPlayer( this );
7602 pItem->SetState(ITEM_REMOVED, this);
7603 pItem2->SetState(ITEM_CHANGED, this);
7605 return pItem2;
7608 return pItem;
7611 void Player::EquipItem( uint16 pos, Item *pItem, bool update )
7613 if( pItem )
7615 VisualizeItem( pos, pItem);
7616 uint8 slot = pos & 255;
7618 if(isAlive())
7619 _ApplyItemMods(pItem, slot, true);
7621 if( IsInWorld() && update )
7623 pItem->AddToWorld();
7624 pItem->SendUpdateToPlayer( this );
7629 void Player::QuickEquipItem( uint16 pos, Item *pItem)
7631 if( pItem )
7633 VisualizeItem( pos, pItem);
7635 if( IsInWorld() )
7637 pItem->AddToWorld();
7638 pItem->SendUpdateToPlayer( this );
7643 void Player::VisualizeItem( uint16 pos, Item *pItem)
7645 if(!pItem)
7646 return;
7648 // check also BIND_WHEN_PICKED_UP for .additem or .additemset case by GM (not binded at adding to inventory)
7649 if( pItem->GetProto()->Bonding == BIND_WHEN_EQUIPED || pItem->GetProto()->Bonding == BIND_WHEN_PICKED_UP )
7650 pItem->SetBinding( true );
7652 uint8 bag = pos >> 8;
7653 uint8 slot = pos & 255;
7655 sLog.outDebug( "STORAGE: EquipItem bag = %u, slot = %u, item = %u", bag, slot, pItem->GetEntry());
7657 m_items[slot] = pItem;
7658 SetUInt64Value( (uint16)(PLAYER_FIELD_INV_SLOT_HEAD + (slot * 2) ), pItem->GetGUID() );
7659 pItem->SetUInt64Value( ITEM_FIELD_CONTAINED, GetGUID() );
7660 pItem->SetUInt64Value( ITEM_FIELD_OWNER, GetGUID() );
7661 pItem->SetSlot( slot );
7662 pItem->SetContainer( NULL );
7664 if( slot < EQUIPMENT_SLOT_END )
7666 int VisibleBase = PLAYER_VISIBLE_ITEM_1_0 + (slot * 12);
7667 SetUInt32Value(VisibleBase, pItem->GetEntry());
7668 SetUInt32Value(VisibleBase + 1, pItem->GetUInt32Value(ITEM_FIELD_ENCHANTMENT));
7669 SetUInt32Value(VisibleBase + 2, pItem->GetUInt32Value(ITEM_FIELD_ENCHANTMENT + 1*3));
7670 SetUInt32Value(VisibleBase + 3, pItem->GetUInt32Value(ITEM_FIELD_ENCHANTMENT + 2*3));
7671 SetUInt32Value(VisibleBase + 4, pItem->GetUInt32Value(ITEM_FIELD_ENCHANTMENT + 3*3));
7672 SetUInt32Value(VisibleBase + 5, pItem->GetUInt32Value(ITEM_FIELD_ENCHANTMENT + 4*3));
7673 SetUInt32Value(VisibleBase + 6, pItem->GetUInt32Value(ITEM_FIELD_ENCHANTMENT + 5*3));
7674 SetUInt32Value(VisibleBase + 7, pItem->GetUInt32Value(ITEM_FIELD_ENCHANTMENT + 6*3));
7675 SetUInt32Value(VisibleBase + 8, pItem->GetUInt32Value(ITEM_FIELD_RANDOM_PROPERTIES_ID));
7678 pItem->SetState(ITEM_CHANGED, this);
7681 // Return stored item (if stored to stack, it can diff. from pItem). And pItem ca be deleted in this case.
7682 Item* Player::BankItem( uint16 pos, Item *pItem, bool update )
7684 return StoreItem( pos, pItem, update);
7687 void Player::RemoveItem( uint8 bag, uint8 slot, bool update )
7689 // note: removeitem does not actualy change the item
7690 // it only takes the item out of storage temporarily
7691 // note2: if removeitem is to be used for delinking
7692 // the item must be removed from the player's updatequeue
7694 Item *pItem = GetItemByPos( bag, slot );
7695 if( pItem )
7697 sLog.outDebug( "STORAGE: RemoveItem bag = %u, slot = %u, item = %u", bag, slot, pItem->GetEntry());
7699 if( bag == INVENTORY_SLOT_BAG_0 )
7701 if ( slot < INVENTORY_SLOT_BAG_END )
7702 _ApplyItemMods(pItem, slot, false);
7704 m_items[slot] = NULL;
7705 SetUInt64Value((uint16)(PLAYER_FIELD_INV_SLOT_HEAD + (slot*2)), 0);
7707 if ( slot < EQUIPMENT_SLOT_END )
7709 int VisibleBase = PLAYER_VISIBLE_ITEM_1_0 + (slot * 12);
7710 for (int i = VisibleBase; i < VisibleBase + 12; ++i)
7711 SetUInt32Value(i, 0);
7714 else
7716 Bag *pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, bag );
7717 if( pBag )
7718 pBag->RemoveItem(slot, update);
7720 pItem->SetUInt64Value( ITEM_FIELD_CONTAINED, 0 );
7721 // pItem->SetUInt64Value( ITEM_FIELD_OWNER, 0 ); not clear owner at remove (it will be set at store). This used in mail and auction code
7722 pItem->SetSlot( NULL_SLOT );
7723 if( IsInWorld() && update )
7724 pItem->SendUpdateToPlayer( this );
7728 void Player::RemoveItemCount( uint32 item, uint32 count, bool update )
7730 sLog.outDebug( "STORAGE: RemoveItemCount item = %u, count = %u", item, count);
7731 Item *pItem;
7732 uint32 remcount = 0;
7733 for(int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; i++)
7735 pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
7736 if( pItem && pItem->GetEntry() == item )
7738 if( pItem->GetCount() + remcount <= count )
7740 remcount += pItem->GetCount();
7741 RemoveItem( INVENTORY_SLOT_BAG_0, i, update );
7743 if(remcount >=count)
7744 return;
7746 else
7748 pItem->SetCount( pItem->GetCount() - count + remcount );
7749 if( IsInWorld() && update )
7750 pItem->SendUpdateToPlayer( this );
7751 pItem->SetState(ITEM_CHANGED, this);
7752 return;
7756 Bag *pBag;
7757 ItemPrototype const *pBagProto;
7758 for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)
7760 pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i );
7761 if( pBag )
7763 pBagProto = pBag->GetProto();
7764 if( pBagProto )
7766 for(uint32 j = 0; j < pBagProto->ContainerSlots; j++)
7768 pItem = GetItemByPos( i, j );
7769 if( pItem && pItem->GetEntry() == item )
7771 if( pItem->GetCount() + remcount <= count )
7773 remcount += pItem->GetCount();
7774 RemoveItem( i, j, update );
7776 if(remcount >=count)
7777 return;
7779 else
7781 pItem->SetCount( pItem->GetCount() - count + remcount );
7782 if( IsInWorld() && update )
7783 pItem->SendUpdateToPlayer( this );
7784 pItem->SetState(ITEM_CHANGED, this);
7785 return;
7794 void Player::DestroyItem( uint8 bag, uint8 slot, bool update )
7796 Item *pItem = GetItemByPos( bag, slot );
7797 if( pItem )
7799 sLog.outDebug( "STORAGE: DestroyItem bag = %u, slot = %u, item = %u", bag, slot, pItem->GetEntry());
7801 //pItem->SetOwnerGUID(0);
7802 pItem->SetSlot( NULL_SLOT );
7803 pItem->SetUInt64Value( ITEM_FIELD_CONTAINED, 0 );
7804 ItemPrototype const *pProto = pItem->GetProto();
7806 for(std::list<struct EnchantDuration*>::iterator itr = m_enchantDuration.begin(),next;itr != m_enchantDuration.end();)
7808 if((*itr)->item == pItem)
7809 m_enchantDuration.erase(itr++);
7810 else
7811 ++itr;
7814 if( bag == INVENTORY_SLOT_BAG_0 )
7816 ItemRemovedQuestCheck( pItem->GetEntry(), pItem->GetCount() );
7818 SetUInt64Value((uint16)(PLAYER_FIELD_INV_SLOT_HEAD + (slot*2)), 0);
7820 if ( slot < EQUIPMENT_SLOT_END )
7822 _ApplyItemMods(pItem, slot, false);
7823 int VisibleBase = PLAYER_VISIBLE_ITEM_1_0 + (slot * 12);
7824 for (int i = VisibleBase; i < VisibleBase + 12; ++i)
7825 SetUInt32Value(i, 0);
7826 for(int enchant_slot = 0 ; enchant_slot < 7; enchant_slot++)
7828 uint32 Enchant_id = pItem->GetUInt32Value(ITEM_FIELD_ENCHANTMENT+enchant_slot*3);
7829 if( Enchant_id)
7831 SpellItemEnchantmentEntry *pEnchant = sSpellItemEnchantmentStore.LookupEntry(Enchant_id);
7832 if(!pEnchant)
7833 continue;
7834 uint32 enchant_display = pEnchant->display_type;
7835 uint32 enchant_value1 = pEnchant->value1;
7836 //uint32 enchant_value2 = pEnchant->value2;
7837 uint32 enchant_spell_id = pEnchant->spellid;
7838 //uint32 enchant_aura_id = pEnchant->aura_id;
7839 //uint32 enchant_description = pEnchant->description;
7840 //SpellEntry *enchantSpell_info = sSpellStore.LookupEntry(enchant_spell_id);
7841 if(enchant_display ==4)
7842 SetArmor(GetArmor()-enchant_value1);
7843 else if(enchant_display ==2)
7845 SetFloatValue(UNIT_FIELD_MINDAMAGE,GetFloatValue(UNIT_FIELD_MINDAMAGE)-enchant_value1);
7846 SetFloatValue(UNIT_FIELD_MAXDAMAGE,GetFloatValue(UNIT_FIELD_MAXDAMAGE)-enchant_value1);
7848 else
7850 RemoveAurasDueToSpell(enchant_spell_id);
7856 m_items[slot] = NULL;
7858 if( IsInWorld() && update )
7860 pItem->RemoveFromWorld();
7861 pItem->DestroyForPlayer( this );
7864 else
7866 Bag *pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, bag );
7867 if( pBag )
7869 if( pProto && pProto->Class == ITEM_CLASS_QUEST )
7870 ItemRemovedQuestCheck( pItem->GetEntry(), pItem->GetCount() );
7872 pBag->RemoveItem(slot, update);
7874 if( IsInWorld() && update )
7876 pItem->RemoveFromWorld();
7877 pItem->DestroyForPlayer(this);
7881 pItem->DeleteFromDB();
7885 void Player::DestroyItemCount( uint32 item, uint32 count, bool update )
7887 sLog.outDebug( "STORAGE: DestroyItemCount item = %u, count = %u", item, count);
7888 Item *pItem;
7889 ItemPrototype const *pProto;
7890 uint32 remcount = 0;
7892 // in inventory
7893 for(int i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; i++)
7895 pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
7896 if( pItem && pItem->GetEntry() == item )
7898 if( pItem->GetCount() + remcount <= count )
7900 remcount += pItem->GetCount();
7901 DestroyItem( INVENTORY_SLOT_BAG_0, i, update);
7903 if(remcount >=count)
7904 return;
7906 else
7908 pProto = pItem->GetProto();
7909 ItemRemovedQuestCheck( pItem->GetEntry(), count - remcount );
7910 pItem->SetCount( pItem->GetCount() - count + remcount );
7911 if( IsInWorld() & update )
7912 pItem->SendUpdateToPlayer( this );
7913 pItem->SetState(ITEM_CHANGED, this);
7914 return;
7919 // in inventory bags
7920 Bag *pBag;
7921 ItemPrototype const *pBagProto;
7922 for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)
7924 pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i );
7925 if( pBag )
7927 pBagProto = pBag->GetProto();
7928 if( pBagProto )
7930 for(uint32 j = 0; j < pBagProto->ContainerSlots; j++)
7932 pItem = pBag->GetItemByPos(j);
7933 if( pItem && pItem->GetEntry() == item )
7935 if( pItem->GetCount() + remcount <= count )
7937 remcount += pItem->GetCount();
7938 DestroyItem( i, j, update );
7940 if(remcount >=count)
7941 return;
7943 else
7945 pProto = pItem->GetProto();
7946 ItemRemovedQuestCheck( pItem->GetEntry(), count - remcount );
7947 pItem->SetCount( pItem->GetCount() - count + remcount );
7948 if( IsInWorld() && update )
7949 pItem->SendUpdateToPlayer( this );
7950 pItem->SetState(ITEM_CHANGED, this);
7951 return;
7959 // in equipment and bag list
7960 for(int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_BAG_END; i++)
7962 pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
7963 if( pItem && pItem->GetEntry() == item )
7965 if( pItem->GetCount() + remcount <= count )
7967 remcount += pItem->GetCount();
7968 DestroyItem( INVENTORY_SLOT_BAG_0, i, update);
7970 if(remcount >=count)
7971 return;
7973 else
7975 pProto = pItem->GetProto();
7976 ItemRemovedQuestCheck( pItem->GetEntry(), count - remcount );
7977 pItem->SetCount( pItem->GetCount() - count + remcount );
7978 if( IsInWorld() & update )
7979 pItem->SendUpdateToPlayer( this );
7980 pItem->SetState(ITEM_CHANGED, this);
7981 return;
7987 void Player::DestroyItemCount( Item* pItem, uint32 &count, bool update )
7989 if(!pItem)
7990 return;
7992 sLog.outDebug( "STORAGE: DestroyItemCount item (GUID: %u, Entry: %u) count = %u", pItem->GetGUIDLow(),pItem->GetEntry(), count);
7994 if( pItem->GetCount() <= count )
7996 count-= pItem->GetCount();
7998 uint16 pos = GetPosByGuid(pItem->GetGUID());
7999 DestroyItem( (pos >> 8),(pos & 255), update);
8001 else
8003 ItemPrototype const* pProto = pItem->GetProto();
8004 ItemRemovedQuestCheck( pItem->GetEntry(), count);
8005 pItem->SetCount( pItem->GetCount() - count );
8006 count = 0;
8007 if( IsInWorld() & update )
8008 pItem->SendUpdateToPlayer( this );
8009 pItem->SetState(ITEM_CHANGED, this);
8013 void Player::SplitItem( uint16 src, uint16 dst, uint32 count )
8015 uint8 srcbag = src >> 8;
8016 uint8 srcslot = src & 255;
8018 uint8 dstbag = dst >> 8;
8019 uint8 dstslot = dst & 255;
8021 Item *pSrcItem = GetItemByPos( srcbag, srcslot );
8022 if( pSrcItem )
8024 // not let split all items (can be only at cheating)
8025 if(pSrcItem->GetCount() == count)
8027 SendEquipError( EQUIP_ERR_COULDNT_SPLIT_ITEMS, pSrcItem, NULL );
8028 return;
8031 // not let split more existed items (can be only at cheating)
8032 if(pSrcItem->GetCount() < count)
8034 SendEquipError( EQUIP_ERR_TRIED_TO_SPLIT_MORE_THAN_COUNT, pSrcItem, NULL );
8035 return;
8038 sLog.outDebug( "STORAGE: SplitItem bag = %u, slot = %u, item = %u, count = %u", dstbag, dstslot, pSrcItem->GetEntry(), count);
8039 Item *pNewItem = CreateItem( pSrcItem->GetEntry(), count );
8040 if( pNewItem )
8042 uint16 dest;
8043 uint8 msg;
8044 if( IsInventoryPos( dst ) )
8046 msg = CanStoreItem( dstbag, dstslot, dest, pNewItem, false );
8047 if( msg == EQUIP_ERR_OK )
8049 pSrcItem->SetCount( pSrcItem->GetCount() - count );
8050 if( IsInWorld() )
8051 pSrcItem->SendUpdateToPlayer( this );
8052 pSrcItem->SetState(ITEM_CHANGED, this);
8053 StoreItem( dest, pNewItem, true);
8055 else
8057 delete pNewItem;
8058 SendEquipError( msg, pSrcItem, NULL );
8061 else if( IsBankPos ( dst ) )
8063 msg = CanBankItem( dstbag, dstslot, dest, pNewItem, false );
8064 if( msg == EQUIP_ERR_OK )
8066 pSrcItem->SetCount( pSrcItem->GetCount() - count );
8067 if( IsInWorld() )
8068 pSrcItem->SendUpdateToPlayer( this );
8069 pSrcItem->SetState(ITEM_CHANGED, this);
8070 BankItem( dest, pNewItem, true);
8072 else
8074 delete pNewItem;
8075 SendEquipError( msg, pSrcItem, NULL );
8078 else if( IsEquipmentPos ( dst ) )
8080 msg = CanEquipItem( dstslot, dest, pNewItem, false );
8081 if( msg == EQUIP_ERR_OK )
8083 pSrcItem->SetCount( pSrcItem->GetCount() - count );
8084 if( IsInWorld() )
8085 pSrcItem->SendUpdateToPlayer( this );
8086 pSrcItem->SetState(ITEM_CHANGED, this);
8087 EquipItem( dest, pNewItem, true);
8089 else
8091 delete pNewItem;
8092 SendEquipError( msg, pSrcItem, NULL );
8095 return;
8098 SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, pSrcItem, NULL );
8101 void Player::SwapItem( uint16 src, uint16 dst )
8103 uint8 srcbag = src >> 8;
8104 uint8 srcslot = src & 255;
8106 uint8 dstbag = dst >> 8;
8107 uint8 dstslot = dst & 255;
8109 Item *pSrcItem = GetItemByPos( srcbag, srcslot );
8110 Item *pDstItem = GetItemByPos( dstbag, dstslot );
8112 if( pSrcItem )
8114 sLog.outDebug( "STORAGE: SwapItem bag = %u, slot = %u, item = %u", dstbag, dstslot, pSrcItem->GetEntry());
8116 if(!isAlive() )
8118 SendEquipError( EQUIP_ERR_YOU_ARE_DEAD, pSrcItem, pDstItem );
8119 return;
8122 if(IsEquipmentPos ( src ))
8124 // bags can be swapped with empty bag slots
8125 uint8 msg = CanUnequipItem( src, pDstItem != NULL || IsBagPos ( src ) && IsBagPos ( dst ));
8126 if(msg != EQUIP_ERR_OK)
8128 SendEquipError( msg, pSrcItem, pDstItem );
8129 return;
8133 if( srcslot == dstbag )
8135 SendEquipError( EQUIP_ERR_NONEMPTY_BAG_OVER_OTHER_BAG, pSrcItem, pDstItem );
8136 return;
8139 uint16 dest;
8140 uint8 msg;
8141 if( !pDstItem )
8143 if( IsInventoryPos( dst ) )
8145 msg = CanStoreItem( dstbag, dstslot, dest, pSrcItem, false );
8146 if( msg == EQUIP_ERR_OK )
8148 RemoveItem(srcbag, srcslot, true);
8149 StoreItem( dest, pSrcItem, true);
8150 return;
8152 else
8153 SendEquipError( msg, pSrcItem, NULL );
8155 else if( IsBankPos ( dst ) )
8157 msg = CanBankItem( dstbag, dstslot, dest, pSrcItem, false);
8158 if( msg == EQUIP_ERR_OK )
8160 RemoveItem(srcbag, srcslot, true);
8161 BankItem( dest, pSrcItem, true);
8162 return;
8164 else
8165 SendEquipError( msg, pSrcItem, NULL );
8167 else if( IsEquipmentPos ( dst ) )
8169 msg = CanEquipItem( dstslot, dest, pSrcItem, false );
8170 if( msg == EQUIP_ERR_OK )
8172 RemoveItem(srcbag, srcslot, true);
8173 EquipItem( dest, pSrcItem, true);
8174 return;
8176 else
8177 SendEquipError( msg, pSrcItem, NULL );
8180 else
8182 if( IsInventoryPos( dst ) )
8184 if( CanStoreItem( dstbag, dstslot, dest, pSrcItem, false ) == EQUIP_ERR_OK )
8186 if( pSrcItem->GetCount() + pDstItem->GetCount() <= pSrcItem->GetProto()->Stackable )
8188 RemoveItem(srcbag, srcslot, true);
8189 StoreItem( dest, pSrcItem, true);
8191 else
8193 pSrcItem->SetCount( pSrcItem->GetCount() + pDstItem->GetCount() - pSrcItem->GetProto()->Stackable );
8194 pDstItem->SetCount( pSrcItem->GetProto()->Stackable );
8195 pSrcItem->SetState(ITEM_CHANGED, this);
8196 pDstItem->SetState(ITEM_CHANGED, this);
8197 if( IsInWorld() )
8199 pSrcItem->SendUpdateToPlayer( this );
8200 pDstItem->SendUpdateToPlayer( this );
8203 return;
8206 else if( IsBankPos ( dst ) )
8208 if( CanBankItem( dstbag, dstslot, dest, pSrcItem, false ) == EQUIP_ERR_OK )
8210 if( pSrcItem->GetCount() + pDstItem->GetCount() <= pSrcItem->GetProto()->Stackable )
8212 RemoveItem(srcbag, srcslot, true);
8213 BankItem( dest, pSrcItem, true);
8215 else
8217 pSrcItem->SetCount( pSrcItem->GetCount() + pDstItem->GetCount() - pSrcItem->GetProto()->Stackable );
8218 pDstItem->SetCount( pSrcItem->GetProto()->Stackable );
8219 pSrcItem->SetState(ITEM_CHANGED, this);
8220 pDstItem->SetState(ITEM_CHANGED, this);
8221 if( IsInWorld() )
8223 pSrcItem->SendUpdateToPlayer( this );
8224 pDstItem->SendUpdateToPlayer( this );
8227 return;
8230 else if( IsEquipmentPos ( dst ) )
8232 if( CanEquipItem( dstslot, dest, pSrcItem, false ) == EQUIP_ERR_OK )
8234 if( pSrcItem->GetCount() + pDstItem->GetCount() <= pSrcItem->GetProto()->Stackable )
8236 RemoveItem(srcbag, srcslot, true);
8237 EquipItem( dest, pSrcItem, true);
8239 else
8241 pSrcItem->SetCount( pSrcItem->GetCount() + pDstItem->GetCount() - pSrcItem->GetProto()->Stackable );
8242 pDstItem->SetCount( pSrcItem->GetProto()->Stackable );
8243 pSrcItem->SetState(ITEM_CHANGED, this);
8244 pDstItem->SetState(ITEM_CHANGED, this);
8245 if( IsInWorld() )
8247 pSrcItem->SendUpdateToPlayer( this );
8248 pDstItem->SendUpdateToPlayer( this );
8251 return;
8254 if( IsInventoryPos( dst ) )
8255 msg = CanStoreItem( dstbag, dstslot, dest, pSrcItem, true );
8256 else if( IsBankPos( dst ) )
8257 msg = CanBankItem( dstbag, dstslot, dest, pSrcItem, true );
8258 else if( IsEquipmentPos( dst ) )
8260 msg = CanEquipItem( dstslot, dest, pSrcItem, true );
8261 if( msg == EQUIP_ERR_OK )
8262 msg = CanUnequipItem( dest, true );
8265 if( msg == EQUIP_ERR_OK )
8267 uint16 dest2;
8268 if( IsInventoryPos( src ) )
8270 msg = CanStoreItem( srcbag, srcslot, dest2, pDstItem, true );
8271 if( msg != EQUIP_ERR_OK )
8273 SendEquipError( EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG, pSrcItem, pDstItem );
8274 return;
8277 else if( IsBankPos( src ) )
8279 msg = CanBankItem( srcbag, srcslot, dest2, pDstItem, true );
8280 if( msg != EQUIP_ERR_OK )
8282 SendEquipError( EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG, pSrcItem, pDstItem );
8283 return;
8286 else if( IsEquipmentPos( src ) )
8288 msg = CanEquipItem( srcslot, dest2, pDstItem, true);
8289 if( msg == EQUIP_ERR_OK )
8290 msg = CanUnequipItem( dest2, true);
8292 if( msg != EQUIP_ERR_OK )
8294 SendEquipError( EQUIP_ERR_ITEM_DOESNT_GO_TO_SLOT, pSrcItem, pDstItem );
8295 return;
8298 RemoveItem(dstbag, dstslot, false);
8299 RemoveItem(srcbag, srcslot, false);
8300 if( IsInventoryPos( dst ) )
8301 StoreItem(dest, pSrcItem, true);
8302 else if( IsBankPos( dst ) )
8303 BankItem(dest, pSrcItem, true);
8304 else if( IsEquipmentPos( dst ) )
8305 EquipItem(dest, pSrcItem, true);
8306 if( IsInventoryPos( src ) )
8307 StoreItem(dest2, pDstItem, true);
8308 else if( IsBankPos( src ) )
8309 BankItem(dest2, pDstItem, true);
8310 else if( IsEquipmentPos( src ) )
8311 EquipItem(dest2, pDstItem, true);
8312 return;
8314 else
8315 SendEquipError( msg, pSrcItem, pDstItem );
8316 return;
8321 void Player::AddItemToBuyBackSlot( Item *pItem )
8323 if( pItem )
8325 uint32 slot = m_currentBuybackSlot;
8326 // if current back slot non-empty search oldest or free
8327 if(m_buybackitems[slot-BUYBACK_SLOT_START])
8329 uint32 oldest_time = GetUInt32Value( PLAYER_FIELD_BUYBACK_TIMESTAMP_1 );
8330 uint32 oldest_slot = BUYBACK_SLOT_START;
8332 for(uint32 i = 1; i < BUYBACK_SLOT_END-BUYBACK_SLOT_START; ++i )
8334 // found empty
8335 if(!m_buybackitems[i])
8337 slot = BUYBACK_SLOT_START+i;
8338 break;
8341 uint32 i_time = GetUInt32Value( PLAYER_FIELD_BUYBACK_TIMESTAMP_1 + i);
8343 if(oldest_time > i_time)
8345 oldest_time = i_time;
8346 oldest_slot = BUYBACK_SLOT_START+i;
8350 // find oldest
8351 slot = oldest_slot;
8354 RemoveItemFromBuyBackSlot( slot, true );
8355 sLog.outDebug( "STORAGE: AddItemToBuyBackSlot item = %u, slot = %u", pItem->GetEntry(), slot);
8356 uint32 eslot = slot - BUYBACK_SLOT_START;
8358 m_buybackitems[eslot] = pItem;
8359 time_t base = time(NULL);
8360 uint32 etime = uint32(base - m_logintime + (30 * 3600));
8362 SetUInt64Value( PLAYER_FIELD_VENDORBUYBACK_SLOT_1 + eslot * 2, pItem->GetGUID() );
8363 ItemPrototype const *pProto = pItem->GetProto();
8364 if( pProto )
8365 SetUInt32Value( PLAYER_FIELD_BUYBACK_PRICE_1 + eslot, pProto->SellPrice * pItem->GetCount() );
8366 else
8367 SetUInt32Value( PLAYER_FIELD_BUYBACK_PRICE_1 + eslot, 0 );
8368 SetUInt32Value( PLAYER_FIELD_BUYBACK_TIMESTAMP_1 + eslot, (uint32)etime );
8370 // move to next (for non filled list is move most optimized choice)
8371 if(m_currentBuybackSlot < BUYBACK_SLOT_END-1)
8372 ++m_currentBuybackSlot;
8376 Item* Player::GetItemFromBuyBackSlot( uint32 slot )
8378 sLog.outDebug( "STORAGE: GetItemFromBuyBackSlot slot = %u", slot);
8379 if( slot >= BUYBACK_SLOT_START && slot < BUYBACK_SLOT_END )
8380 return m_buybackitems[slot - BUYBACK_SLOT_START];
8381 return NULL;
8384 void Player::RemoveItemFromBuyBackSlot( uint32 slot, bool del )
8386 sLog.outDebug( "STORAGE: RemoveItemFromBuyBackSlot slot = %u", slot);
8387 if( slot >= BUYBACK_SLOT_START && slot < BUYBACK_SLOT_END )
8389 uint32 eslot = slot - BUYBACK_SLOT_START;
8390 Item *pItem = m_buybackitems[eslot];
8391 if( pItem )
8393 pItem->RemoveFromWorld();
8394 if(del)
8395 delete pItem;
8398 m_buybackitems[eslot] = NULL;
8399 SetUInt64Value( PLAYER_FIELD_VENDORBUYBACK_SLOT_1 + eslot * 2, 0 );
8400 SetUInt32Value( PLAYER_FIELD_BUYBACK_PRICE_1 + eslot, 0 );
8401 SetUInt32Value( PLAYER_FIELD_BUYBACK_TIMESTAMP_1 + eslot, 0 );
8403 // if cuurent backslot is filled set to now free slot
8404 if(m_buybackitems[m_currentBuybackSlot])
8405 m_currentBuybackSlot = slot;
8409 void Player::SendEquipError( uint8 msg, Item* pItem, Item *pItem2 )
8411 sLog.outDetail( "WORLD: Sent SMSG_INVENTORY_CHANGE_FAILURE" );
8412 WorldPacket data;
8413 data.Initialize( SMSG_INVENTORY_CHANGE_FAILURE );
8414 data << msg;
8415 if( msg == EQUIP_ERR_YOU_MUST_REACH_LEVEL_N )
8416 data << (pItem && pItem->GetProto() ? pItem->GetProto()->RequiredLevel : uint32(0));
8417 data << (pItem ? pItem->GetGUID() : uint64(0));
8418 data << (pItem2 ? pItem2->GetGUID() : uint64(0));
8419 data << uint8(0);
8420 GetSession()->SendPacket(&data);
8423 void Player::SendBuyError( uint8 msg, Creature* pCreature, uint32 item, uint32 param )
8425 sLog.outDetail( "WORLD: Sent SMSG_BUY_FAILED" );
8426 WorldPacket data;
8427 data.Initialize( SMSG_BUY_FAILED );
8428 data << (pCreature ? pCreature->GetGUID() : uint64(0));
8429 data << item;
8430 if( param > 0 )
8431 data << param;
8432 data << msg;
8433 GetSession()->SendPacket(&data);
8436 void Player::SendSellError( uint8 msg, Creature* pCreature, uint64 guid, uint32 param )
8438 sLog.outDetail( "WORLD: Sent SMSG_SELL_ITEM" );
8439 WorldPacket data;
8440 data.Initialize( SMSG_SELL_ITEM );
8441 data << (pCreature ? pCreature->GetGUID() : uint64(0));
8442 data << guid;
8443 if( param > 0 )
8444 data << param;
8445 data << msg;
8446 GetSession()->SendPacket(&data);
8449 void Player::ClearTrade()
8451 tradeGold = 0;
8452 acceptTrade = false;
8453 for(int i=0; i<7; i++)
8454 tradeItems[i] = NULL_SLOT;
8457 void Player::TradeCancel(bool sendback)
8459 if(pTrader)
8461 // prevent loop cancel message (already processed)
8462 if(!sendback)
8463 pTrader->pTrader = NULL;
8465 WorldSession* ws = pTrader->GetSession();
8466 pTrader = NULL;
8467 ws->SendCancelTrade();
8469 ClearTrade();
8472 void Player::UpdateEnchantTime(uint32 time)
8474 for(std::list<struct EnchantDuration*>::iterator itr = m_enchantDuration.begin(),next;itr != m_enchantDuration.end();itr=next)
8476 next=itr;
8477 next++;
8478 if(*itr)
8480 if((*itr)->item)
8482 if(!(*itr)->item->GetUInt32Value(ITEM_FIELD_ENCHANTMENT+(*itr)->slot*3))
8484 delete *itr;
8485 m_enchantDuration.erase(itr);
8486 continue;
8488 if((*itr)->leftduration <= time)
8490 AddItemEnchant((*itr)->item,(*itr)->item->GetUInt32Value(ITEM_FIELD_ENCHANTMENT+(*itr)->slot*3),false);
8491 for(int y=0;y<3;y++)
8492 (*itr)->item->SetUInt32Value(ITEM_FIELD_ENCHANTMENT+(*itr)->slot*3+y,0);
8493 delete *itr;
8494 m_enchantDuration.erase(itr);
8495 continue;
8497 else if((*itr)->leftduration > time)
8499 (*itr)->leftduration -= time;
8506 // duration == 0 will remove item enchant
8507 void Player::AddEnchantDuration(Item *item,uint32 slot,uint32 duration)
8509 if(!item)
8510 return;
8511 for(std::list<struct EnchantDuration*>::iterator itr = m_enchantDuration.begin(),next;itr != m_enchantDuration.end();itr=next)
8513 next=itr;
8514 next++;
8515 if(*itr)
8517 if((*itr)->item)
8519 if((*itr)->item == item && (*itr)->slot == slot)
8521 delete *itr;
8522 m_enchantDuration.erase(itr);
8523 break;
8528 if(item && duration > 0 )
8530 GetSession()->SendItemEnchantTimeUpdate(item->GetGUID(),slot,uint32(duration/1000));
8531 EnchantDuration *ed = new EnchantDuration();
8532 ed->item = item;
8533 ed->leftduration = duration;
8534 ed->slot = slot;
8535 m_enchantDuration.push_back(ed);
8539 void Player::ReducePoisonCharges(uint32 enchantId)
8541 if(!enchantId)
8542 return;
8543 uint32 pEnchantId = 0;
8544 uint32 charges = 0;
8545 Item *pItem;
8546 uint16 pos;
8548 for(int i = EQUIPMENT_SLOT_MAINHAND; i < EQUIPMENT_SLOT_RANGED; i++)
8550 pos = ((INVENTORY_SLOT_BAG_0 << 8) | i);
8552 pItem = GetItemByPos( pos );
8553 if(!pItem)
8554 continue;
8555 for(int x=0;x<7;x++)
8557 charges = pItem->GetUInt32Value(ITEM_FIELD_ENCHANTMENT+x*3+2);
8558 if(charges == 0)
8559 continue;
8560 if(charges <= 1)
8562 AddItemEnchant(pItem,enchantId,false);
8563 for(int y=0;y<3;y++)
8564 pItem->SetUInt32Value(ITEM_FIELD_ENCHANTMENT+x*3+y,0);
8565 break;
8567 else
8569 pItem->SetUInt32Value(ITEM_FIELD_ENCHANTMENT+x*3+2,charges-1);
8570 break;
8576 void Player::SaveEnchant()
8578 uint32 duration = 0;
8580 for(std::list<struct EnchantDuration*>::iterator itr = m_enchantDuration.begin();itr != m_enchantDuration.end();itr++)
8582 if(*itr)
8584 if((*itr)->item)
8586 if((*itr)->leftduration > 0)
8588 (*itr)->item->SetUInt32Value(ITEM_FIELD_ENCHANTMENT+(*itr)->slot*3+1,(*itr)->leftduration);
8589 (*itr)->item->SetState(ITEM_CHANGED, this);
8596 void Player::LoadEnchant()
8598 uint32 duration = 0;
8599 Item *pItem;
8600 uint16 pos;
8602 for(int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; i++)
8604 pos = ((INVENTORY_SLOT_BAG_0 << 8) | i);
8606 pItem = GetItemByPos( pos );
8607 if(!pItem)
8608 continue;
8609 if(pItem->GetProto()->Class != ITEM_CLASS_WEAPON && pItem->GetProto()->Class != ITEM_CLASS_ARMOR)
8610 continue;
8611 for(int x=0;x<7;x++)
8613 duration = pItem->GetUInt32Value(ITEM_FIELD_ENCHANTMENT+x*3+1);
8614 if( duration == 0 )
8615 continue;
8616 else if( duration > 0 )
8617 AddEnchantDuration(pItem,x,duration);
8620 Bag *pBag;
8621 ItemPrototype const *pBagProto;
8622 for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)
8624 pos = ((INVENTORY_SLOT_BAG_0 << 8) | i);
8625 pBag = (Bag*)GetItemByPos( pos );
8626 if( pBag )
8628 pBagProto = pBag->GetProto();
8629 if( pBagProto )
8631 for(uint32 j = 0; j < pBagProto->ContainerSlots; j++)
8633 pos = ((i << 8) | j);
8634 pItem = GetItemByPos( pos );
8635 if(!pItem)
8636 continue;
8637 if(pItem->GetProto()->Class != ITEM_CLASS_WEAPON && pItem->GetProto()->Class != ITEM_CLASS_ARMOR)
8638 continue;
8639 for(int x=0;x<7;x++)
8641 duration = pItem->GetUInt32Value(ITEM_FIELD_ENCHANTMENT+x*3+1);
8642 if( duration == 0 )
8643 continue;
8644 else if( duration > 0 )
8645 AddEnchantDuration(pItem,x,duration);
8651 for(int i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++)
8653 pos = ((INVENTORY_SLOT_BAG_0 << 8) | i);
8654 pBag = (Bag*)GetItemByPos( pos );
8655 if( pBag )
8657 pBagProto = pBag->GetProto();
8658 if( pBagProto )
8660 for(uint32 j = 0; j < pBagProto->ContainerSlots; j++)
8662 pos = ((i << 8) | j);
8663 pItem = GetItemByPos( pos );
8664 if(!pItem)
8665 continue;
8666 if(pItem->GetProto()->Class != ITEM_CLASS_WEAPON && pItem->GetProto()->Class != ITEM_CLASS_ARMOR)
8667 continue;
8668 for(int x=0;x<7;x++)
8670 duration = pItem->GetUInt32Value(ITEM_FIELD_ENCHANTMENT+x*3+1);
8671 if( duration == 0 )
8672 continue;
8673 else if( duration > 0 )
8674 AddEnchantDuration(pItem,x,duration);
8683 /*********************************************************/
8684 /*** QUEST SYSTEM ***/
8685 /*********************************************************/
8687 void Player::PrepareQuestMenu( uint64 guid )
8689 Object *pObject;
8690 Creature *pCreature = ObjectAccessor::Instance().GetCreature(*this, guid);
8691 if( pCreature )
8692 pObject = (Object*)pCreature;
8693 else
8695 GameObject *pGameObject = ObjectAccessor::Instance().GetGameObject(*this, guid);
8696 if( pGameObject )
8697 pObject = (Object*)pGameObject;
8698 else
8699 return;
8702 QuestMenu *qm = PlayerTalkClass->GetQuestMenu();
8703 qm->ClearMenu();
8705 for( std::list<uint32>::iterator i = pObject->mInvolvedQuests.begin( ); i != pObject->mInvolvedQuests.end( ); i++ )
8707 uint32 quest_id = *i;
8708 uint32 status = GetQuestStatus( quest_id );
8709 if ( status == QUEST_STATUS_COMPLETE && !GetQuestRewardStatus( quest_id ) )
8710 qm->AddMenuItem(quest_id, DIALOG_STATUS_REWARD_REP);
8711 else if ( status == QUEST_STATUS_INCOMPLETE )
8712 qm->AddMenuItem(quest_id, DIALOG_STATUS_INCOMPLETE);
8713 else if (status == QUEST_STATUS_AVAILABLE )
8714 qm->AddMenuItem(quest_id, DIALOG_STATUS_CHAT);
8717 for( std::list<uint32>::iterator i = pObject->mQuests.begin( ); i != pObject->mQuests.end( ); i++ )
8719 uint32 quest_id = *i;
8720 Quest* pQuest = objmgr.QuestTemplates[quest_id];
8722 uint32 status = GetQuestStatus( quest_id );
8724 if ((strlen(pQuest->GetObjectives()) == 0) && (CanTakeQuest(pQuest, false)))
8726 // perhaps find a better check for quests that autocomplete
8727 qm->AddMenuItem(quest_id, DIALOG_STATUS_REWARD_REP);
8728 } else if ( status == QUEST_STATUS_NONE && CanTakeQuest( pQuest, false ) )
8729 qm->AddMenuItem(quest_id, DIALOG_STATUS_AVAILABLE);
8733 void Player::SendPreparedQuest( uint64 guid )
8735 QuestMenu* pQuestMenu = PlayerTalkClass->GetQuestMenu();
8736 if( !pQuestMenu || pQuestMenu->MenuItemCount() < 1 )
8737 return;
8739 uint32 status = pQuestMenu->GetItem(0).m_qIcon;
8740 if ( pQuestMenu->MenuItemCount() == 1 )
8742 // Auto open -- maybe also should verify there is no greeting
8743 uint32 quest_id = pQuestMenu->GetItem(0).m_qId;
8744 Quest *pQuest = objmgr.QuestTemplates[quest_id];
8745 if ( pQuest )
8747 if( status == DIALOG_STATUS_REWARD_REP && !GetQuestRewardStatus( quest_id ) )
8748 PlayerTalkClass->SendQuestGiverRequestItems( pQuest, guid, CanRewardQuest(pQuest,false), true );
8749 else if( status == DIALOG_STATUS_INCOMPLETE )
8750 PlayerTalkClass->SendQuestGiverRequestItems( pQuest, guid, false, true );
8751 else
8753 // perhaps find a better auto-complete test
8754 if ((strlen(pQuest->GetObjectives()) == 0) && (CanTakeQuest(pQuest, false)))
8756 //if (CanCompleteQuest(quest_id))
8757 // PlayerTalkClass->SendQuestGiverOfferReward(quest_id, guid, true, NULL, 0);
8758 //else
8759 PlayerTalkClass->SendQuestGiverRequestItems( pQuest, guid, CanCompleteQuest(quest_id), true);
8761 else
8763 PlayerTalkClass->SendQuestGiverQuestDetails( pQuest, guid, true );
8768 else
8770 QEmote qe;
8771 qe._Delay = 0;
8772 qe._Emote = 0;
8773 std::string title = "";
8774 Creature *pCreature = ObjectAccessor::Instance().GetCreature(*this, guid);
8775 if( pCreature )
8777 uint32 textid = pCreature->GetNpcTextId();
8778 GossipText * gossiptext = objmgr.GetGossipText(textid);
8779 if( !gossiptext )
8781 qe._Delay = 0; //TEXTEMOTE_MESSAGE; //zyg: player emote
8782 qe._Emote = 0; //TEXTEMOTE_HELLO; //zyg: NPC emote
8783 title = "";
8785 else
8787 qe = gossiptext->Options[0].Emotes[0];
8788 title = gossiptext->Options[0].Text_0;
8789 if( &title == NULL )
8790 title = "";
8793 PlayerTalkClass->SendQuestGiverQuestList( qe, title, guid );
8797 Quest *Player::GetActiveQuest( uint32 quest_id ) const
8799 StatusMap::const_iterator itr = mQuestStatus.find(quest_id);
8801 return itr != mQuestStatus.end() && itr->second.m_status != QUEST_STATUS_NONE ? itr->second.m_quest : NULL;
8804 Quest* Player::GetNextQuest( uint64 guid, Quest *pQuest )
8806 if( pQuest )
8808 Object *pObject;
8809 Creature *pCreature = ObjectAccessor::Instance().GetCreature(*this, guid);
8810 if( pCreature )
8812 pObject = (Object*)pCreature;
8814 else
8816 GameObject *pGameObject = ObjectAccessor::Instance().GetGameObject(*this, guid);
8817 if( pGameObject )
8818 pObject = (Object*)pGameObject;
8819 else
8820 return NULL;
8823 uint32 nextQuestID = pQuest->GetNextQuestId();
8824 list<uint32>::iterator iter = find(pObject->mQuests.begin(), pObject->mQuests.end(), nextQuestID);
8825 if (iter != pObject->mQuests.end())
8827 return objmgr.QuestTemplates[nextQuestID];
8830 return NULL;
8833 bool Player::CanSeeStartQuest( uint32 quest_id )
8835 if( quest_id )
8837 if( SatisfyQuestRace( quest_id, false ) && SatisfyQuestClass( quest_id, false ) && SatisfyQuestExclusiveGroup( quest_id, false )
8838 && SatisfyQuestSkill( quest_id, false ) && SatisfyQuestReputation( quest_id, false )
8839 && SatisfyQuestPreviousQuest( quest_id, false ) && SatisfyQuestHaveQuest(quest_id, false) )
8840 return ( getLevel() + 7 >= objmgr.QuestTemplates[quest_id]->GetMinLevel() );
8842 return false;
8845 bool Player::CanTakeQuest( Quest *pQuest, bool msg )
8847 if( pQuest)
8849 uint32 quest_id = pQuest->GetQuestId();
8850 return ( SatisfyQuestStatus( quest_id, msg ) && SatisfyQuestExclusiveGroup( quest_id, msg )
8851 && SatisfyQuestRace( quest_id, msg ) && SatisfyQuestLevel( quest_id, msg ) && SatisfyQuestClass( quest_id, msg )
8852 && SatisfyQuestSkill( quest_id, msg ) && SatisfyQuestReputation( quest_id, msg )
8853 && SatisfyQuestPreviousQuest( quest_id, msg ) && SatisfyQuestTimed( quest_id, msg )
8854 && SatisfyQuestHaveQuest( quest_id, msg ) );
8856 return false;
8859 bool Player::CanAddQuest( Quest *pQuest, bool msg )
8861 if( pQuest )
8863 if(!GetQuestSlot( 0 ))
8864 return false;
8866 if( !SatisfyQuestLog( msg ) )
8867 return false;
8869 uint32 srcitem = pQuest->GetSrcItemId();
8870 if( srcitem > 0 )
8872 uint32 count = pQuest->GetSrcItemCount();
8873 uint16 dest;
8874 if( count <= 0 )
8875 count = 1;
8876 uint8 msg = CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, srcitem, count, false );
8877 if( msg != EQUIP_ERR_OK )
8879 SendEquipError( msg, NULL, NULL );
8880 return false;
8883 return true;
8885 return false;
8888 bool Player::CanCompleteQuest( uint32 quest_id )
8890 if( quest_id )
8892 QuestStatus qStatus = mQuestStatus[quest_id].m_status;
8893 if( qStatus == QUEST_STATUS_COMPLETE )
8894 return true;
8896 Quest* qInfo = objmgr.QuestTemplates[quest_id];
8898 if ((mQuestStatus[quest_id].m_status == QUEST_STATUS_INCOMPLETE) ||
8899 (strlen(qInfo->GetObjectives()) == 0))
8902 //if ( qInfo->HasSpecialFlag( QUEST_SPECIAL_FLAGS_DELIVER ) )
8904 for(int i = 0; i < QUEST_OBJECTIVES_COUNT; i++)
8906 if( qInfo->ReqItemCount[i]!= 0 && mQuestStatus[quest_id].m_itemcount[i] < qInfo->ReqItemCount[i] )
8907 // Need to do something so repeatable quests can be counted:
8908 //if (GetItemCount(qInfo->ReqItemId[i]) < qInfo->ReqItemCount[i])
8909 return false;
8913 if ( qInfo->HasSpecialFlag( QUEST_SPECIAL_FLAGS_KILL_OR_CAST ) )
8915 for(int i = 0; i < QUEST_OBJECTIVES_COUNT; i++)
8917 // skip GO activate objectives
8918 if( qInfo->ReqCreatureOrGOId[i] <= 0 )
8919 continue;
8921 if( qInfo->ReqCreatureOrGOCount[i] != 0 && mQuestStatus[quest_id].m_creatureOrGOcount[i] < qInfo->ReqCreatureOrGOCount[i] )
8922 return false;
8926 if ( qInfo->HasSpecialFlag( QUEST_SPECIAL_FLAGS_EXPLORATION ) && !mQuestStatus[quest_id].m_explored )
8927 return false;
8929 if ( qInfo->HasSpecialFlag( QUEST_SPECIAL_FLAGS_TIMED ) && mQuestStatus[quest_id].m_timer == 0 )
8930 return false;
8932 if ( qInfo->GetRewOrReqMoney() < 0 )
8934 if ( int32(GetMoney()) < -qInfo->GetRewOrReqMoney() )
8935 return false;
8937 return true;
8940 return false;
8943 bool Player::CanRewardQuest( Quest *pQuest, bool msg )
8945 if( pQuest )
8947 // auto complete quest, return true (maybe need a better check)
8948 if ((strlen(pQuest->GetObjectives()) == 0) && CanTakeQuest(pQuest, false))
8949 return true;
8951 // not completed quest (only cheating case, then ignore without message)
8952 if(GetQuestStatus(pQuest->GetQuestId()) != QUEST_STATUS_COMPLETE)
8953 return false;
8955 // rewarded and not repeatable quest (only cheating case, then ignore without message)
8956 if(GetQuestRewardStatus(pQuest->GetQuestId()) && !pQuest->HasSpecialFlag(QUEST_SPECIAL_FLAGS_REPEATABLE))
8957 return false;
8959 // prevent recive reward with quest items in bank
8960 if ( pQuest->HasSpecialFlag( QUEST_SPECIAL_FLAGS_DELIVER ) )
8962 for(int i = 0; i < QUEST_OBJECTIVES_COUNT; i++)
8964 if( pQuest->ReqItemCount[i]!= 0 &&
8965 GetItemCount(pQuest->ReqItemId[i]) < pQuest->ReqItemCount[i] )
8967 if(msg)
8968 SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL );
8969 return false;
8974 return true;
8976 return false;
8979 bool Player::CanRewardQuest( Quest *pQuest, uint32 reward, bool msg )
8981 if( pQuest )
8983 // prevent recive reward with quest items in bank or for not completed quest
8984 if(!CanRewardQuest(pQuest,msg))
8985 return false;
8987 uint16 dest;
8988 uint8 msg;
8990 if ( pQuest->GetRewChoiceItemsCount() > 0 )
8992 if( pQuest->RewChoiceItemId[reward] )
8994 msg = CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, pQuest->RewChoiceItemId[reward], pQuest->RewChoiceItemCount[reward], false );
8995 if( msg != EQUIP_ERR_OK )
8997 SendEquipError( msg, NULL, NULL );
8998 return false;
9003 if ( pQuest->GetRewItemsCount() > 0 )
9005 for (int i = 0; i < pQuest->GetRewItemsCount(); i++)
9007 if( pQuest->RewItemId[i] )
9009 msg = CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, pQuest->RewItemId[i], pQuest->RewItemCount[i], false );
9010 if( msg != EQUIP_ERR_OK )
9012 SendEquipError( msg, NULL, NULL );
9013 return false;
9018 return true;
9020 return false;
9023 void Player::AddQuest( Quest *pQuest )
9025 if( pQuest )
9027 uint16 log_slot = GetQuestSlot( 0 );
9028 assert(log_slot);
9030 uint32 quest_id = pQuest->GetQuestId();
9032 mQuestStatus[quest_id].m_quest = pQuest;
9033 mQuestStatus[quest_id].m_status = QUEST_STATUS_INCOMPLETE;
9034 mQuestStatus[quest_id].m_rewarded = false;
9035 mQuestStatus[quest_id].m_explored = false;
9037 if ( pQuest->HasSpecialFlag( QUEST_SPECIAL_FLAGS_DELIVER ) )
9039 for(int i = 0; i < QUEST_OBJECTIVES_COUNT; i++)
9040 mQuestStatus[quest_id].m_itemcount[i] = 0;
9042 if ( pQuest->HasSpecialFlag( QUEST_SPECIAL_FLAGS_KILL_OR_CAST ) )
9044 for(int i = 0; i < QUEST_OBJECTIVES_COUNT; i++)
9045 mQuestStatus[quest_id].m_creatureOrGOcount[i] = 0;
9048 GiveQuestSourceItem( quest_id );
9049 AdjustQuestReqItemCount( quest_id );
9051 SetUInt32Value(log_slot + 0, quest_id);
9052 SetUInt32Value(log_slot + 1, 0);
9054 if( pQuest->HasSpecialFlag( QUEST_SPECIAL_FLAGS_TIMED ) )
9056 uint32 limittime = pQuest->GetLimitTime();
9057 AddTimedQuest( quest_id );
9058 mQuestStatus[quest_id].m_timer = limittime * 1000;
9059 uint32 qtime = static_cast<uint32>(time(NULL)) + limittime;
9060 SetUInt32Value( log_slot + 2, qtime );
9062 else
9064 mQuestStatus[quest_id].m_timer = 0;
9065 SetUInt32Value( log_slot + 2, 0 );
9070 void Player::CompleteQuest( uint32 quest_id )
9072 if( quest_id )
9074 SetQuestStatus( quest_id, QUEST_STATUS_COMPLETE);
9076 uint16 log_slot = GetQuestSlot( quest_id );
9077 if( log_slot )
9079 uint32 state = GetUInt32Value( log_slot + 1 );
9080 state |= 1 << 24;
9081 SetUInt32Value( log_slot + 1, state );
9084 SendQuestComplete( quest_id );
9088 void Player::IncompleteQuest( uint32 quest_id )
9090 if( quest_id )
9092 SetQuestStatus( quest_id, QUEST_STATUS_INCOMPLETE );
9094 uint16 log_slot = GetQuestSlot( quest_id );
9095 if( log_slot )
9097 uint32 state = GetUInt32Value( log_slot + 1 );
9098 state &= ~(1 << 24);
9099 SetUInt32Value( log_slot + 1, state );
9104 void Player::RewardQuest( Quest *pQuest, uint32 reward, Object* questGiver )
9106 if( pQuest )
9108 uint32 quest_id = pQuest->GetQuestId();
9110 uint16 dest;
9111 for (int i = 0; i < QUEST_OBJECTIVES_COUNT; i++ )
9113 if ( pQuest->ReqItemId[i] )
9114 DestroyItemCount( pQuest->ReqItemId[i], pQuest->ReqItemCount[i], true);
9117 //if( qInfo->HasSpecialFlag( QUEST_SPECIAL_FLAGS_TIMED ) )
9118 // SetTimedQuest( 0 );
9119 if (find(m_timedquests.begin(), m_timedquests.end(), pQuest->GetQuestId()) != m_timedquests.end())
9120 m_timedquests.remove(pQuest->GetQuestId());
9122 if ( pQuest->GetRewChoiceItemsCount() > 0 )
9124 if( pQuest->RewChoiceItemId[reward] )
9126 if( CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, pQuest->RewChoiceItemId[reward], pQuest->RewChoiceItemCount[reward], false ) == EQUIP_ERR_OK )
9127 StoreNewItem( dest, pQuest->RewChoiceItemId[reward], pQuest->RewChoiceItemCount[reward], true);
9131 if ( pQuest->GetRewItemsCount() > 0 )
9133 for (int i=0; i < pQuest->GetRewItemsCount(); i++)
9135 if( pQuest->RewItemId[i] )
9137 if( CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, pQuest->RewItemId[i], pQuest->RewItemCount[i], false ) == EQUIP_ERR_OK )
9138 StoreNewItem( dest, pQuest->RewItemId[i], pQuest->RewItemCount[i], true);
9143 if( pQuest->GetRewSpell() > 0 )
9144 CastSpell( this, pQuest->GetRewSpell(), true);
9146 uint16 log_slot = GetQuestSlot( quest_id );
9147 if( log_slot )
9149 SetUInt32Value(log_slot + 0, 0);
9150 SetUInt32Value(log_slot + 1, 0);
9151 SetUInt32Value(log_slot + 2, 0);
9154 // Not give XP in case already completed once repeatable quest
9155 uint32 XP = mQuestStatus[quest_id].m_completed_once && pQuest->HasSpecialFlag( QUEST_SPECIAL_FLAGS_REPEATABLE )
9156 ? 0 : uint32(pQuest->XPValue( this )*sWorld.getRate(RATE_XP_QUEST));
9158 if ( getLevel() < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL) )
9159 GiveXP( XP , NULL );
9160 else
9161 ModifyMoney( MaNGOS::XP::xp_to_money(XP) );
9163 ModifyMoney( pQuest->GetRewOrReqMoney() );
9165 if ( !pQuest->IsRepeatable() )
9167 SetQuestStatus(quest_id, QUEST_STATUS_COMPLETE);
9168 mQuestStatus[quest_id].m_rewarded = true;
9170 else
9172 SetQuestStatus(quest_id, QUEST_STATUS_NONE);
9175 SendQuestReward( pQuest, XP, questGiver );
9176 mQuestStatus[quest_id].m_completed_once = true; // in repeated quest case prevent recive XP at second complete
9180 void Player::FailQuest( uint32 quest_id )
9182 if( quest_id )
9184 IncompleteQuest( quest_id );
9186 uint16 log_slot = GetQuestSlot( quest_id );
9187 if( log_slot )
9189 SetUInt32Value( log_slot + 2, 1 );
9191 uint32 state = GetUInt32Value( log_slot + 1 );
9192 state |= 1 << 25;
9193 SetUInt32Value( log_slot + 1, state );
9195 SendQuestFailed( quest_id );
9199 void Player::FailTimedQuest( uint32 quest_id )
9201 if( quest_id )
9203 mQuestStatus[quest_id].m_timer = 0;
9205 IncompleteQuest( quest_id );
9207 uint16 log_slot = GetQuestSlot( quest_id );
9208 if( log_slot )
9210 SetUInt32Value( log_slot + 2, 1 );
9212 uint32 state = GetUInt32Value( log_slot + 1 );
9213 state |= 1 << 25;
9214 SetUInt32Value( log_slot + 1, state );
9216 SendQuestTimerFailed( quest_id );
9220 bool Player::SatisfyQuestClass( uint32 quest_id, bool msg )
9222 Quest * qInfo = objmgr.QuestTemplates[quest_id];
9223 if( qInfo )
9225 uint32 reqclasses = qInfo->GetRequiredClass();
9226 if ( reqclasses == 0 )
9227 return true;
9228 if( (reqclasses & getClassMask()) == 0 )
9230 if( msg )
9231 SendCanTakeQuestResponse( INVALIDREASON_DONT_HAVE_REQ );
9232 return false;
9234 return true;
9237 return false;
9240 bool Player::SatisfyQuestLevel( uint32 quest_id, bool msg )
9242 Quest * qInfo = objmgr.QuestTemplates[quest_id];
9243 if( qInfo )
9245 if( getLevel() < qInfo->GetMinLevel() )
9247 if( msg )
9248 SendCanTakeQuestResponse( INVALIDREASON_DONT_HAVE_REQ );
9249 return false;
9251 return true;
9253 return false;
9256 bool Player::SatisfyQuestLog( bool msg )
9258 uint16 log_slot = GetQuestSlot( 0 );
9259 if( log_slot )
9260 return true;
9261 else
9263 if( msg )
9265 WorldPacket data;
9266 data.Initialize( SMSG_QUESTLOG_FULL );
9267 GetSession()->SendPacket( &data );
9268 sLog.outDebug( "WORLD: Sent QUEST_LOG_FULL_MESSAGE" );
9270 return false;
9274 bool Player::SatisfyQuestPreviousQuest( uint32 quest_id, bool msg )
9276 if( quest_id)
9278 Quest * qInfo = objmgr.QuestTemplates[quest_id];
9280 // No previous quest (might be first quest in a series)
9281 if( qInfo->prevQuests.size() == 0)
9282 return true;
9284 // If any of the previous quests completed, return true
9285 for(vector<uint32>::iterator iter = qInfo->prevQuests.begin(); iter != qInfo->prevQuests.end(); iter++ )
9287 uint32 prevId = *iter;
9289 StatusMap::iterator i_prevstatus = mQuestStatus.find( prevId );
9291 if( i_prevstatus != mQuestStatus.end() && i_prevstatus->second.m_rewarded )
9292 return true;
9295 // Have only prev. quests in non-rewarded state
9296 if( msg )
9297 SendCanTakeQuestResponse( INVALIDREASON_DONT_HAVE_REQ );
9299 return false;
9302 bool Player::SatisfyQuestHaveQuest( uint32 quest_id, bool msg )
9304 Quest * qInfo = objmgr.QuestTemplates[quest_id];
9305 if(!qInfo)
9306 return false;
9308 if (!qInfo->GetHaveQuestId())
9309 return true;
9311 StatusMap::iterator iter = mQuestStatus.find(qInfo->GetHaveQuestId());
9312 if (iter == mQuestStatus.end())
9313 return false;
9315 if (iter->second.m_status == QUEST_STATUS_NONE)
9316 return false;
9318 return true;
9321 bool Player::SatisfyQuestRace( uint32 quest_id, bool msg )
9323 Quest * qInfo = objmgr.QuestTemplates[quest_id];
9324 if( qInfo )
9326 uint32 reqraces = qInfo->GetRequiredRaces();
9327 if ( reqraces == 0 )
9328 return true;
9329 if( (reqraces & getRaceMask()) == 0 )
9331 if( msg )
9332 SendCanTakeQuestResponse( INVALIDREASON_DONT_HAVE_RACE );
9333 return false;
9335 return true;
9337 return false;
9340 bool Player::SatisfyQuestReputation( uint32 quest_id, bool msg )
9342 Quest * qInfo = objmgr.QuestTemplates[quest_id];
9343 if( qInfo )
9345 uint32 faction_id = qInfo->GetRequiredRepFaction();
9346 if(!faction_id)
9347 return true;
9349 return GetStanding(faction_id) >= qInfo->GetRequiredRepValue();
9351 return false;
9354 bool Player::SatisfyQuestSkill( uint32 quest_id, bool msg )
9356 Quest * qInfo = objmgr.QuestTemplates[quest_id];
9357 if( qInfo )
9359 uint32 reqskill = qInfo->GetRequiredSkill();
9360 if( reqskill == QUEST_TRSKILL_NONE )
9361 return true;
9362 if( GetSkillValue( reqskill ) < qInfo->GetRequiredSkillValue() )
9364 if( msg )
9365 SendCanTakeQuestResponse( INVALIDREASON_DONT_HAVE_REQ );
9366 return false;
9368 return true;
9370 return false;
9373 bool Player::SatisfyQuestStatus( uint32 quest_id, bool msg )
9375 if( quest_id )
9377 StatusMap::iterator itr = mQuestStatus.find( quest_id );
9378 if ( itr != mQuestStatus.end() && itr->second.m_status != QUEST_STATUS_NONE )
9380 if( msg )
9381 SendCanTakeQuestResponse( INVALIDREASON_HAVE_QUEST );
9382 return false;
9384 return true;
9386 return false;
9389 bool Player::SatisfyQuestTimed( uint32 quest_id, bool msg )
9391 Quest * qInfo = objmgr.QuestTemplates[quest_id];
9392 if( qInfo )
9394 if ( (find(m_timedquests.begin(), m_timedquests.end(), quest_id) != m_timedquests.end()) && qInfo->HasSpecialFlag(QUEST_SPECIAL_FLAGS_TIMED) )
9396 if( msg )
9397 SendCanTakeQuestResponse( INVALIDREASON_HAVE_TIMED_QUEST );
9398 return false;
9400 return true;
9402 return false;
9405 bool Player::SatisfyQuestExclusiveGroup( uint32 quest_id, bool msg )
9407 Quest * qInfo = objmgr.QuestTemplates[quest_id];
9408 if( qInfo )
9410 if(!qInfo->GetExclusiveGroup())
9411 return true;
9413 multimap<uint32, uint32>::iterator iter = objmgr.ExclusiveQuestGroups.lower_bound(qInfo->GetExclusiveGroup());
9414 multimap<uint32, uint32>::iterator end = objmgr.ExclusiveQuestGroups.upper_bound(qInfo->GetExclusiveGroup());
9416 assert(iter!=end); // always must be found if qInfo->ExclusiveGroup != 0
9418 for(; iter != end; ++iter)
9420 uint32 exclude_Id = iter->second;
9422 // skip checked quest id, intrested only state of another quests in group
9423 if(exclude_Id == quest_id)
9424 continue;
9426 StatusMap::iterator i_exstatus = mQuestStatus.find( exclude_Id );
9428 // altearnative quest already start or complete
9429 if( i_exstatus != mQuestStatus.end()
9430 && (i_exstatus->second.m_status == QUEST_STATUS_COMPLETE || i_exstatus->second.m_status == QUEST_STATUS_INCOMPLETE) )
9431 return false;
9433 return true;
9435 return false;
9438 bool Player::GiveQuestSourceItem( uint32 quest_id )
9440 Quest * qInfo = objmgr.QuestTemplates[quest_id];
9441 if( qInfo )
9444 uint32 srcitem = qInfo->GetSrcItemId();
9445 if( srcitem > 0 )
9447 uint16 dest;
9448 uint32 count = qInfo->GetSrcItemCount();
9449 if( count <= 0 )
9450 count = 1;
9451 uint8 msg = CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, srcitem, count, false );
9452 if( msg == EQUIP_ERR_OK )
9454 StoreNewItem(dest, srcitem, count, true);
9455 return true;
9457 else
9458 SendEquipError( msg, NULL, NULL );
9459 return false;
9462 return true;
9465 void Player::TakeQuestSourceItem( uint32 quest_id )
9467 Quest * qInfo = objmgr.QuestTemplates[quest_id];
9468 if( qInfo )
9470 uint32 srcitem = qInfo->GetSrcItemId();
9471 if( srcitem > 0 )
9473 uint32 count = qInfo->GetSrcItemCount();
9474 if( count <= 0 )
9475 count = 1;
9476 DestroyItemCount(srcitem, count, true);
9481 bool Player::GetQuestRewardStatus( uint32 quest_id )
9483 if( quest_id )
9485 StatusMap::iterator itr = mQuestStatus.find( quest_id );
9486 if ( itr != mQuestStatus.end() && itr->second.m_status != QUEST_STATUS_NONE )
9487 return mQuestStatus[quest_id ].m_rewarded;
9489 return false;
9491 return false;
9494 uint32 Player::GetQuestStatus( uint32 quest_id )
9496 if( quest_id )
9498 if ( mQuestStatus.find( quest_id ) != mQuestStatus.end() )
9499 return mQuestStatus[quest_id].m_status;
9501 return QUEST_STATUS_NONE;
9504 void Player::SetQuestStatus( uint32 quest_id, QuestStatus status )
9506 Quest * qInfo = objmgr.QuestTemplates[quest_id];
9507 if( qInfo )
9509 if ((status == QUEST_STATUS_NONE) || (status == QUEST_STATUS_INCOMPLETE))
9511 if( qInfo->HasSpecialFlag( QUEST_SPECIAL_FLAGS_TIMED ) )
9512 if (find(m_timedquests.begin(), m_timedquests.end(), quest_id) != m_timedquests.end())
9513 m_timedquests.remove(qInfo->GetQuestId());
9516 mQuestStatus[quest_id].m_status = status;
9520 void Player::AdjustQuestReqItemCount( uint32 quest_id )
9522 Quest * qInfo = objmgr.QuestTemplates[quest_id];
9523 if( qInfo )
9525 if ( qInfo->HasSpecialFlag( QUEST_SPECIAL_FLAGS_DELIVER ) )
9527 for(int i = 0; i < QUEST_OBJECTIVES_COUNT; i++)
9529 uint32 reqitemcount = qInfo->ReqItemCount[i];
9530 if( reqitemcount != 0 )
9532 uint32 curitemcount = GetItemCount(qInfo->ReqItemId[i]) + GetBankItemCount(qInfo->ReqItemId[i]);
9533 mQuestStatus[quest_id].m_itemcount[i] = min(curitemcount, reqitemcount);
9540 uint16 Player::GetQuestSlot( uint32 quest_id )
9542 for ( uint16 i = 0; i < MAX_QUEST_LOG_SIZE; i++ )
9544 if ( GetUInt32Value(PLAYER_QUEST_LOG_1_1 + 3*i) == quest_id )
9545 return PLAYER_QUEST_LOG_1_1 + 3*i;
9547 return 0;
9550 void Player::AreaExplored( uint32 questId )
9552 if( questId )
9554 uint16 log_slot = GetQuestSlot( questId );
9555 if( log_slot )
9557 mQuestStatus[questId].m_explored = true;
9559 if( CanCompleteQuest( questId ) )
9560 CompleteQuest( questId );
9564 void Player::ItemAddedQuestCheck( uint32 entry, uint32 count )
9566 uint32 questid;
9567 uint32 reqitem;
9568 uint32 reqitemcount;
9569 uint32 curitemcount;
9570 uint32 additemcount;
9571 for( int i = 0; i < MAX_QUEST_LOG_SIZE; i++ )
9573 questid = GetUInt32Value(PLAYER_QUEST_LOG_1_1 + 3*i);
9574 if ( questid != 0 && mQuestStatus[questid].m_status == QUEST_STATUS_INCOMPLETE )
9576 Quest * qInfo = objmgr.QuestTemplates[questid];
9577 if( qInfo && qInfo->HasSpecialFlag( QUEST_SPECIAL_FLAGS_DELIVER ) )
9579 for (int j = 0; j < QUEST_OBJECTIVES_COUNT; j++)
9581 reqitem = qInfo->ReqItemId[j];
9582 if ( reqitem == entry )
9584 reqitemcount = qInfo->ReqItemCount[j];
9585 curitemcount = mQuestStatus[questid].m_itemcount[j];
9586 if ( curitemcount < reqitemcount )
9588 additemcount = ( curitemcount + count <= reqitemcount ? count : reqitemcount - curitemcount);
9589 mQuestStatus[questid].m_itemcount[j] += additemcount;
9590 SendQuestUpdateAddItem( questid, j, additemcount );
9592 if ( CanCompleteQuest( questid ) )
9593 CompleteQuest( questid );
9594 return;
9602 void Player::ItemRemovedQuestCheck( uint32 entry, uint32 count )
9604 uint32 questid;
9605 uint32 reqitem;
9606 uint32 reqitemcount;
9607 uint32 curitemcount;
9608 uint32 remitemcount;
9609 for( int i = 0; i < MAX_QUEST_LOG_SIZE; i++ )
9611 questid = GetUInt32Value(PLAYER_QUEST_LOG_1_1 + 3*i);
9612 Quest * qInfo = objmgr.QuestTemplates[questid];
9613 if ( qInfo )
9615 if( qInfo->HasSpecialFlag( QUEST_SPECIAL_FLAGS_DELIVER ) )
9617 for (int j = 0; j < QUEST_OBJECTIVES_COUNT; j++)
9619 reqitem = qInfo->ReqItemId[j];
9620 if ( reqitem == entry )
9622 reqitemcount = qInfo->ReqItemCount[j];
9623 if( mQuestStatus[questid].m_status != QUEST_STATUS_COMPLETE )
9624 curitemcount = mQuestStatus[questid].m_itemcount[j];
9625 else
9626 curitemcount = GetItemCount(entry) + GetBankItemCount(entry);
9627 if ( curitemcount - count < reqitemcount )
9629 remitemcount = ( curitemcount <= reqitemcount ? count : count + reqitemcount - curitemcount);
9630 mQuestStatus[questid].m_itemcount[j] = curitemcount - remitemcount;
9631 IncompleteQuest( questid );
9633 return;
9641 void Player::KilledMonster( uint32 entry, uint64 guid )
9643 uint32 questid;
9644 uint32 reqkill;
9645 uint32 reqkillcount;
9646 uint32 curkillcount;
9647 uint32 addkillcount = 1;
9648 for( int i = 0; i < MAX_QUEST_LOG_SIZE; i++ )
9650 questid = GetUInt32Value(PLAYER_QUEST_LOG_1_1 + 3*i);
9652 if(!questid)
9653 continue;
9655 Quest * qInfo = objmgr.QuestTemplates[questid];
9656 if ( qInfo && mQuestStatus[questid].m_status == QUEST_STATUS_INCOMPLETE )
9658 if( qInfo->HasSpecialFlag( QUEST_SPECIAL_FLAGS_KILL_OR_CAST ) )
9660 for (int j = 0; j < QUEST_OBJECTIVES_COUNT; j++)
9662 // skip GO activate objective or none
9663 if(qInfo->ReqCreatureOrGOId[j] <=0)
9664 continue;
9666 // skip Cast at creature objective
9667 if(qInfo->ReqSpell[j] !=0 )
9668 continue;
9670 reqkill = qInfo->ReqCreatureOrGOId[j];
9672 if ( reqkill == entry )
9674 reqkillcount = qInfo->ReqCreatureOrGOCount[j];
9675 curkillcount = mQuestStatus[questid].m_creatureOrGOcount[j];
9676 if ( curkillcount < reqkillcount )
9678 mQuestStatus[questid].m_creatureOrGOcount[j] = curkillcount + addkillcount;
9679 SendQuestUpdateAddCreature( questid, guid, j, curkillcount, addkillcount);
9681 if ( CanCompleteQuest( questid ) )
9682 CompleteQuest( questid );
9683 return;
9691 void Player::CastedCreatureOrGO( uint32 entry, uint64 guid, uint32 spell_id )
9693 uint32 questid;
9694 uint32 reqCastCount;
9695 uint32 curCastCount;
9696 uint32 addCastCount = 1;
9697 for( int i = 0; i < MAX_QUEST_LOG_SIZE; i++ )
9699 questid = GetUInt32Value(PLAYER_QUEST_LOG_1_1 + 3*i);
9701 if(!questid)
9702 continue;
9704 Quest * qInfo = objmgr.QuestTemplates[questid];
9705 if ( qInfo && mQuestStatus[questid].m_status == QUEST_STATUS_INCOMPLETE )
9707 if( qInfo->HasSpecialFlag( QUEST_SPECIAL_FLAGS_KILL_OR_CAST ) )
9709 for (int j = 0; j < QUEST_OBJECTIVES_COUNT; j++)
9711 // skip kill creature objective (0) or wrong spell casts
9712 if(qInfo->ReqSpell[j] != spell_id )
9713 continue;
9715 uint32 reqTarget = 0;
9716 // GO activate objective
9717 if(qInfo->ReqCreatureOrGOId[j] < 0)
9719 reqTarget = - qInfo->ReqCreatureOrGOId[j];
9720 assert(sGOStorage.LookupEntry<GameObject>(reqTarget));
9722 // creature acivate objectives
9723 else if(qInfo->ReqCreatureOrGOId[j] > 0)
9725 reqTarget = qInfo->ReqCreatureOrGOId[j];
9726 assert(sCreatureStorage.LookupEntry<Creature>(reqTarget));
9728 // other not creature/GO related obejctives
9729 else
9730 continue;
9732 if ( reqTarget == entry )
9734 reqCastCount = qInfo->ReqCreatureOrGOCount[j];
9735 curCastCount = mQuestStatus[questid].m_creatureOrGOcount[j];
9736 if ( curCastCount < reqCastCount )
9738 mQuestStatus[questid].m_creatureOrGOcount[j] = curCastCount + addCastCount;
9739 SendQuestUpdateAddCreature( questid, guid, j, curCastCount, addCastCount);
9741 if ( CanCompleteQuest( questid ) )
9742 CompleteQuest( questid );
9743 return;
9751 void Player::MoneyChanged( uint32 count )
9753 uint32 questid;
9754 for( int i = 0; i < MAX_QUEST_LOG_SIZE; i++ )
9756 questid = GetUInt32Value(PLAYER_QUEST_LOG_1_1 + 3*i);
9757 if ( questid != 0 )
9759 Quest * qInfo = objmgr.QuestTemplates[questid];
9760 if( qInfo && qInfo->GetRewOrReqMoney() < 0 )
9762 if( mQuestStatus[questid].m_status == QUEST_STATUS_INCOMPLETE )
9764 if(int32(count) >= -qInfo->GetRewOrReqMoney())
9766 if ( CanCompleteQuest( questid ) )
9767 CompleteQuest( questid );
9770 else if( mQuestStatus[questid].m_status == QUEST_STATUS_COMPLETE )
9772 if(int32(count) < -qInfo->GetRewOrReqMoney())
9773 IncompleteQuest( questid );
9780 bool Player::HaveQuestForItem( uint32 itemid )
9782 for( StatusMap::iterator i = mQuestStatus.begin( ); i != mQuestStatus.end( ); ++ i )
9784 quest_status qs=i->second;
9786 if (qs.m_status == QUEST_STATUS_INCOMPLETE)
9788 if (!qs.m_quest) continue;
9789 Quest * qinfo = qs.m_quest;
9791 // There should be no mixed ReqItem/ReqSource drop
9792 // This part for ReqItem drop
9793 for (int j = 0; j < QUEST_OBJECTIVES_COUNT; j++)
9795 if(itemid == qinfo->ReqItemId[j] && qs.m_itemcount[j] < qinfo->ReqItemCount[j] )
9796 return true;
9798 // This part - for ReqSource
9799 for (int j = 0; j < QUEST_SOURCE_ITEM_IDS_COUNT; j++)
9801 // examined item is a source item
9802 if (qinfo->ReqSourceId[j] == itemid && qinfo->ReqSourceRef[j] > 0 && qinfo->ReqSourceRef[j] <= QUEST_OBJECTIVES_COUNT)
9804 uint32 idx = qinfo->ReqSourceRef[j]-1;
9805 // total count of created ReqItems and SourceItems is less than ReqItemCount
9806 if(qinfo->ReqItemId[idx] != 0 &&
9807 qs.m_itemcount[idx] + GetItemCount(itemid)+ GetBankItemCount(itemid) < qinfo->ReqItemCount[idx])
9808 return true;
9810 // total count of casted ReqCreatureOrGOs and SourceItems is less than ReqCreatureOrGOCount
9811 if (qinfo->ReqCreatureOrGOId[idx] != 0 &&
9812 qs.m_creatureOrGOcount[idx] + GetItemCount(itemid)+ GetBankItemCount(itemid) < qinfo->ReqCreatureOrGOCount[idx])
9813 return true;
9818 return false;
9821 void Player::SendQuestComplete( uint32 quest_id )
9823 if( quest_id )
9825 WorldPacket data;
9826 data.Initialize( SMSG_QUESTUPDATE_COMPLETE );
9827 data << quest_id;
9828 GetSession()->SendPacket( &data );
9829 sLog.outDebug( "WORLD: Sent SMSG_QUESTUPDATE_COMPLETE quest = %u", quest_id );
9833 void Player::SendQuestReward( Quest *pQuest, uint32 XP, Object * questGiver )
9835 if( pQuest )
9837 uint32 questid = pQuest->GetQuestId();
9838 sLog.outDebug( "WORLD: Sent SMSG_QUESTGIVER_QUEST_COMPLETE quest = %u", questid );
9839 WorldPacket data;
9840 data.Initialize( SMSG_QUESTGIVER_QUEST_COMPLETE );
9841 data << questid;
9842 data << uint32(0x03);
9844 if ( getLevel() < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL) )
9846 data << XP;
9847 data << uint32(pQuest->GetRewOrReqMoney());
9849 else
9851 data << uint32(0);
9852 data << uint32(pQuest->GetRewOrReqMoney() + XP);
9854 data << uint32( pQuest->GetRewItemsCount() );
9856 for (int i = 0; i < pQuest->GetRewItemsCount(); i++)
9858 if ( pQuest->RewItemId[i] > 0 )
9859 data << pQuest->RewItemId[i] << pQuest->RewItemCount[i];
9862 GetSession()->SendPacket( &data );
9864 if (pQuest->GetQuestCompleteScript() != 0)
9866 ScriptMapMap::iterator s = sScripts.find(pQuest->GetQuestCompleteScript());
9867 if (s == sScripts.end())
9868 return;
9870 ScriptMap *s2 = &(s->second);
9871 ScriptMap::iterator iter;
9872 bool immedScript = false;
9873 for (iter = s2->begin(); iter != s2->end(); iter++)
9875 if (iter->first == 0)
9877 ScriptAction sa;
9878 sa.source = questGiver;
9879 sa.script = &iter->second;
9880 sa.target = this;
9881 sWorld.scriptSchedule.insert(pair<uint64, ScriptAction>(0, sa));
9882 immedScript = true;
9884 else
9886 ScriptAction sa;
9887 sa.source = questGiver;
9888 sa.script = &iter->second;
9889 sa.target = this;
9890 sWorld.scriptSchedule.insert(pair<uint64, ScriptAction>(sWorld.internalGameTime + iter->first, sa));
9893 if (immedScript)
9894 sWorld.ScriptsProcess();
9899 void Player::SendQuestFailed( uint32 quest_id )
9901 if( quest_id )
9903 WorldPacket data;
9904 data.Initialize( SMSG_QUESTGIVER_QUEST_FAILED );
9905 data << quest_id;
9906 GetSession()->SendPacket( &data );
9907 sLog.outDebug("WORLD: Sent SMSG_QUESTGIVER_QUEST_FAILED");
9911 void Player::SendQuestTimerFailed( uint32 quest_id )
9913 if( quest_id )
9915 WorldPacket data;
9916 data.Initialize( SMSG_QUESTUPDATE_FAILEDTIMER );
9917 data << quest_id;
9918 GetSession()->SendPacket( &data );
9919 sLog.outDebug("WORLD: Sent SMSG_QUESTUPDATE_FAILEDTIMER");
9923 void Player::SendCanTakeQuestResponse( uint32 msg )
9925 WorldPacket data;
9926 data.Initialize( SMSG_QUESTGIVER_QUEST_INVALID );
9927 data << msg;
9928 GetSession()->SendPacket( &data );
9929 sLog.outDebug("WORLD: Sent SMSG_QUESTGIVER_QUEST_INVALID");
9932 void Player::SendPushToPartyResponse( Player *pPlayer, uint32 msg )
9934 if( pPlayer )
9936 WorldPacket data;
9937 data.Initialize( MSG_QUEST_PUSH_RESULT );
9938 data << pPlayer->GetGUID();
9939 data << msg;
9940 data << uint8(0);
9941 GetSession()->SendPacket( &data );
9942 sLog.outDebug("WORLD: Sent MSG_QUEST_PUSH_RESULT");
9946 void Player::SendQuestUpdateAddItem( uint32 quest_id, uint32 item_idx, uint32 count )
9948 if( quest_id )
9950 WorldPacket data;
9951 data.Initialize( SMSG_QUESTUPDATE_ADD_ITEM );
9952 sLog.outDebug( "WORLD: Sent SMSG_QUESTUPDATE_ADD_ITEM" );
9953 data << objmgr.QuestTemplates[quest_id]->ReqItemId[item_idx];
9954 data << count;
9955 GetSession()->SendPacket( &data );
9959 void Player::SendQuestUpdateAddCreature( uint32 quest_id, uint64 guid, uint32 creature_idx, uint32 old_count, uint32 add_count )
9961 assert(old_count + add_count < 64 && "mob/GO count store in 6 bits 2^6 = 64 (0..63)");
9963 Quest * qInfo = objmgr.QuestTemplates[quest_id];
9964 if( qInfo )
9966 WorldPacket data;
9967 data.Initialize( SMSG_QUESTUPDATE_ADD_KILL );
9968 sLog.outDebug( "WORLD: Sent SMSG_QUESTUPDATE_ADD_KILL" );
9969 data << qInfo->GetQuestId();
9970 data << uint32(qInfo->ReqCreatureOrGOId[ creature_idx ]);
9971 data << old_count + add_count;
9972 data << qInfo->ReqCreatureOrGOCount[ creature_idx ];
9973 data << guid;
9974 GetSession()->SendPacket(&data);
9976 uint16 log_slot = GetQuestSlot( quest_id );
9977 uint32 kills = GetUInt32Value( log_slot + 1 );
9978 kills = kills + (add_count << ( 6 * creature_idx ));
9979 SetUInt32Value( log_slot + 1, kills );
9983 /*********************************************************/
9984 /*** LOAD SYSTEM ***/
9985 /*********************************************************/
9987 bool Player::MinimalLoadFromDB( uint32 guid )
9989 QueryResult *result = sDatabase.PQuery("SELECT `data`,`name`,`position_x`,`position_y`,`position_z`,`map` FROM `character` WHERE `guid` = '%u'",guid);
9990 if(!result)
9991 return false;
9993 Field *fields = result->Fetch();
9995 if(!LoadValues( fields[0].GetString()))
9997 sLog.outError("ERROR: Player #%d have broken data in `data` field. Can't be loaded.",GUID_LOPART(guid));
9998 delete result;
9999 return false;
10002 m_name = fields[1].GetCppString();
10003 m_positionX = fields[2].GetFloat();
10004 m_positionY = fields[3].GetFloat();
10005 m_positionZ = fields[4].GetFloat();
10006 m_mapId = fields[5].GetUInt32();
10008 for (int i = 0; i < MAX_QUEST_LOG_SIZE; i++)
10009 m_items[i] = NULL;
10011 delete result;
10012 return true;
10015 bool Player::LoadPositionFromDB(uint32& mapid, float& x,float& y,float& z,float& o, uint64 guid)
10017 QueryResult *result = sDatabase.PQuery("SELECT `position_x`,`position_y`,`position_z`,`orientation`,`map` FROM `character` WHERE `guid` = '%u'",guid);
10018 if(!result)
10019 return false;
10021 Field *fields = result->Fetch();
10023 x = fields[0].GetFloat();
10024 y = fields[1].GetFloat();
10025 z = fields[2].GetFloat();
10026 o = fields[3].GetFloat();
10027 mapid = fields[4].GetUInt32();
10029 delete result;
10030 return true;
10033 bool Player::LoadValuesArrayFromDB(vector<string> & data, uint64 guid)
10035 std::ostringstream ss;
10036 ss<<"SELECT `data` FROM `character` WHERE `guid`='"<<guid<<"'";
10037 QueryResult *result = sDatabase.Query( ss.str().c_str() );
10038 if( !result )
10039 return false;
10041 Field *fields = result->Fetch();
10043 data = StrSplit(fields[0].GetString(), " ");
10045 delete result;
10047 return true;
10050 uint32 Player::GetUInt32ValueFromArray(vector<string> const& data, uint16 index)
10052 return (uint32)atoi(data[index].c_str());
10055 float Player::GetFloatValueFromArray(vector<string> const& data, uint16 index)
10057 float result;
10058 uint32 temp = Player::GetUInt32ValueFromArray(data,index);
10059 memcpy(&result, &temp, sizeof(result));
10061 return result;
10064 uint32 Player::GetUInt32ValueFromDB(uint16 index, uint64 guid)
10066 vector<string> data;
10067 if(!LoadValuesArrayFromDB(data,guid))
10068 return 0;
10070 return GetUInt32ValueFromArray(data,index);
10073 float Player::GetFloatValueFromDB(uint16 index, uint64 guid)
10075 float result;
10076 uint32 temp = Player::GetUInt32ValueFromDB(index, guid);
10077 memcpy(&result, &temp, sizeof(result));
10079 return result;
10082 bool Player::LoadFromDB( uint32 guid )
10084 // 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 25 26 27 28 29
10085 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`,`trans_x`, `trans_y`, `trans_z`, `trans_o`, `transguid` FROM `character` WHERE `guid` = '%u'",guid);
10087 if(!result)
10089 sLog.outError("ERROR: Player (GUID: %u) not found in table `character`, can't load. ",guid);
10090 return false;
10093 Field *fields = result->Fetch();
10095 Object::_Create( guid, HIGHGUID_PLAYER );
10097 if(!LoadValues( fields[3].GetString()))
10099 sLog.outError("ERROR: Player #%d have broken data in `data` field. Can't be loaded.",GUID_LOPART(guid));
10100 delete result;
10101 return false;
10104 // cleanup inventory related item value fields (its will be filled correctly in _LoadInventory)
10105 for(uint8 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; ++slot)
10107 SetUInt64Value( (uint16)(PLAYER_FIELD_INV_SLOT_HEAD + (slot * 2) ), 0 );
10109 int VisibleBase = PLAYER_VISIBLE_ITEM_1_0 + (slot * 12);
10110 for(int i = 0; i < 9; ++i )
10111 SetUInt32Value(VisibleBase + i, 0);
10113 if (m_items[slot])
10115 delete m_items[slot];
10116 m_items[slot] = NULL;
10120 m_drunk = GetUInt32Value(PLAYER_BYTES_3) & 0xFFFE;
10122 m_name = fields[4].GetCppString();
10124 sLog.outDebug("Load Basic value of player %s is: ", m_name.c_str());
10125 outDebugValues();
10127 m_race = fields[5].GetUInt8();
10128 //Need to call it to initialize m_team (m_team can be calculated from m_race)
10129 //Other way is to saves m_team into characters table.
10130 setFactionForRace(m_race);
10131 SetCharm(0);
10133 m_class = fields[6].GetUInt8();
10135 PlayerInfo const *info = objmgr.GetPlayerInfo(m_race, m_class);
10136 if(!info)
10138 sLog.outError("Player have incorrect race/class pair. Can't be loaded.");
10139 delete result;
10140 return false;
10143 uint32 transGUID = fields[29].GetUInt32();
10144 m_positionX = fields[7].GetFloat();
10145 m_positionY = fields[8].GetFloat();
10146 m_positionZ = fields[9].GetFloat();
10147 m_mapId = fields[10].GetUInt32();
10148 m_orientation = fields[11].GetFloat();
10150 if (transGUID != 0)
10152 m_transX = fields[25].GetFloat();
10153 m_transY = fields[26].GetFloat();
10154 m_transZ = fields[27].GetFloat();
10155 m_transO = fields[28].GetFloat();
10157 for (int i = 0; i < MapManager::Instance().m_Transports.size(); i++)
10159 if ((MapManager::Instance().m_Transports[i])->GetGUIDLow() == transGUID)
10161 m_transport = MapManager::Instance().m_Transports[i];
10162 m_transport->AddPassenger(this);
10163 m_mapId = m_transport->GetMapId();
10168 // since last logout (in seconds)
10169 uint32 time_diff = (time(NULL) - fields[21].GetUInt32());
10171 rest_bonus = fields[20].GetFloat();
10172 //speed collect rest bonus in offline, in logout, far from tavern, city (section/in hour)
10173 float bubble0 = 0.0416;
10174 //speed collect rest bonus in offline, in logout, in tavern, city (section/in hour)
10175 float bubble1 = 0.083;
10177 if((int32)fields[21].GetUInt32() > 0)
10179 float bubble = fields[22].GetUInt32() > 0
10180 ? bubble1*sWorld.getRate(RATE_REST_OFFLINE_IN_TAVERN_OR_CITY)
10181 : bubble0*sWorld.getRate(RATE_REST_OFFLINE_IN_WILDERNESS);
10183 SetRestBonus(GetRestBonus()+ (time(NULL)-(int32)fields[21].GetUInt32())*((float)GetUInt32Value(PLAYER_NEXT_LEVEL_XP)/144000)*bubble);
10186 if(!IsPositionValid())
10188 sLog.outError("ERROR: Player (guidlow %d) have invalid coordinates (X: %d Y: ^%d). Teleport to default race/class locations.",guid,m_positionX,m_positionY);
10190 m_mapId = info->mapId;
10191 m_positionX = info->positionX;
10192 m_positionY = info->positionY;
10193 m_positionZ = info->positionZ;
10196 m_highest_rank = fields[14].GetUInt32();
10197 m_standing = fields[15].GetUInt32();
10198 m_rating = fields[16].GetFloat();
10199 m_cinematic = fields[17].GetUInt32();
10200 m_Played_time[0]= fields[18].GetUInt32();
10201 m_Played_time[1]= fields[19].GetUInt32();
10203 m_resetTalentsCost = fields[23].GetUInt32();
10204 m_resetTalentsTime = fields[24].GetUInt64();
10206 if( HasFlag(PLAYER_FLAGS, 8) )
10207 SetUInt32Value(PLAYER_FLAGS, 0);
10209 if( HasFlag(PLAYER_FLAGS, 0x11) )
10210 m_deathState = DEAD;
10212 _LoadTaxiMask( fields[12].GetString() );
10214 delete result;
10216 // remember loaded power values to restore after stats initialization and modifier appling
10217 float savedPower[MAX_POWERS];
10218 for(uint32 i = 0; i < MAX_POWERS; ++i)
10219 savedPower[i] = GetPower(Powers(i));
10221 // reset stats before loading any modifiers
10222 InitStatsForLevel(getLevel(),false,false);
10224 // make sure the unit is considered out of combat for proper loading
10225 ClearInCombat();
10227 //mails are loaded only when needed ;-) - when player in game click on mailbox.
10228 //_LoadMail();
10230 _LoadAuras(time_diff);
10232 _LoadSpells(time_diff);
10234 _LoadQuestStatus();
10236 _LoadTutorials();
10238 _LoadInventory(time_diff);
10240 _LoadActions();
10242 _LoadReputation();
10244 // Skip _ApplyAllAuraMods(); -- applied in _LoadAuras by AddAura calls at aura load
10245 // Skip _ApplyAllItemMods(); -- already applied in _LoadInventory()
10247 // restore remembered power values
10248 for(uint32 i = 0; i < MAX_POWERS; ++i)
10249 SetPower(Powers(i),savedPower[i]);
10251 sLog.outDebug("The value of player %s after load item and aura is: ", m_name.c_str());
10252 outDebugValues();
10254 return true;
10257 void Player::_LoadActions()
10260 m_actions.clear();
10262 QueryResult *result = sDatabase.PQuery("SELECT `button`,`action`,`type`,`misc` FROM `character_action` WHERE `guid` = '%u' ORDER BY `button`",GetGUIDLow());
10264 if(result)
10268 Field *fields = result->Fetch();
10270 addAction(fields[0].GetUInt8(), fields[1].GetUInt16(), fields[2].GetUInt8(), fields[3].GetUInt8());
10272 while( result->NextRow() );
10274 delete result;
10278 void Player::_LoadAuras(uint32 timediff)
10280 m_Auras.clear();
10281 for (int i = 0; i < TOTAL_AURAS; i++)
10282 m_modAuras[i].clear();
10284 for(uint8 i = 0; i < 48; i++)
10285 SetUInt32Value((uint16)(UNIT_FIELD_AURA + i), 0);
10286 for(uint8 j = 0; j < 6; j++)
10287 SetUInt32Value((uint16)(UNIT_FIELD_AURAFLAGS + j), 0);
10289 QueryResult *result = sDatabase.PQuery("SELECT `spell`,`effect_index`,`remaintime` FROM `character_aura` WHERE `guid` = '%u'",GetGUIDLow());
10291 if(result)
10295 Field *fields = result->Fetch();
10296 uint32 spellid = fields[0].GetUInt32();
10297 uint32 effindex = fields[1].GetUInt32();
10298 int32 remaintime = (int32)fields[2].GetUInt32();
10300 SpellEntry* spellproto = sSpellStore.LookupEntry(spellid);
10301 if(!spellproto)
10303 sLog.outError("Unknown aura (spellid %u, effindex %u), ignore.",spellid,effindex);
10304 continue;
10307 // negative effects should continue counting down after logout
10308 if (remaintime != -1 && !IsPositiveEffect(spellid, effindex))
10310 remaintime -= timediff;
10311 if(remaintime <= 0) continue;
10314 // FIXME: real caster not stored in DB currently
10316 Aura* aura = new Aura(spellproto, effindex, this, this/*caster*/);
10317 aura->SetAuraDuration(remaintime);
10318 AddAura(aura);
10320 while( result->NextRow() );
10322 delete result;
10325 if(m_class == CLASS_WARRIOR)
10326 CastSpell(this,SPELL_PASSIVE_BATTLE_STANCE,true);
10329 void Player::LoadCorpse()
10331 if(Corpse* corpse = GetCorpse())
10333 if( isAlive() )
10335 if( corpse->GetType() == CORPSE_RESURRECTABLE )
10336 corpse->ConvertCorpseToBones();
10338 else
10339 corpse->UpdateForPlayer(this,true);
10341 else
10343 //Prevent Dead Player login without corpse
10344 if(!isAlive())
10345 ResurrectPlayer();
10349 void Player::_LoadInventory(uint32 timediff)
10351 QueryResult *result = sDatabase.PQuery("SELECT `slot`,`item`,`item_template` FROM `character_inventory` WHERE `guid` = '%u' AND `bag` = '0' ORDER BY `slot`",GetGUIDLow());
10353 uint16 dest;
10354 if (result)
10356 // prevent items from being added to the queue when stored
10357 m_itemUpdateQueueBlocked = true;
10360 Field *fields = result->Fetch();
10361 uint8 slot = fields[0].GetUInt8();
10362 uint32 item_guid = fields[1].GetUInt32();
10363 uint32 item_id = fields[2].GetUInt32();
10365 ItemPrototype const * proto = objmgr.GetItemPrototype(item_id);
10367 if(!proto)
10369 sLog.outError( "Player::_LoadInventory: Player %s have unknown item (id: #%u) in inventory, skipped.", GetName(),item_id );
10370 continue;
10373 Item *item = NewItemOrBag(proto);
10374 item->SetSlot( slot );
10375 item->SetContainer( NULL );
10377 if(!item->LoadFromDB(item_guid, GetGUID()))
10379 delete item;
10380 continue;
10383 bool success = true;
10384 dest = ((INVENTORY_SLOT_BAG_0 << 8) | slot);
10385 if( IsInventoryPos( dest ) )
10387 if( !CanStoreItem( INVENTORY_SLOT_BAG_0, slot, dest, item, false ) == EQUIP_ERR_OK )
10389 success = false;
10390 continue;
10393 StoreItem(dest, item, true);
10395 else if( IsEquipmentPos( dest ) )
10397 if( !CanEquipItem( slot, dest, item, false, false ) == EQUIP_ERR_OK )
10399 success = false;
10400 continue;
10403 QuickEquipItem(dest, item);
10405 else if( IsBankPos( dest ) )
10407 if( !CanBankItem( INVENTORY_SLOT_BAG_0, slot, dest, item, false, false ) == EQUIP_ERR_OK )
10409 success = false;
10410 continue;
10413 BankItem(dest, item, true);
10416 // item's state may have changed after stored
10417 if (success) item->SetState(ITEM_UNCHANGED, this);
10418 else delete item;
10419 } while (result->NextRow());
10421 delete result;
10422 m_itemUpdateQueueBlocked = false;
10424 if(isAlive())
10425 _ApplyAllItemMods();
10428 // load mailed items which should receive current player
10429 void Player::_LoadMailedItems()
10431 QueryResult *result = sDatabase.PQuery( "SELECT `item_guid`,`item_template` FROM `mail` WHERE `receiver` = '%u' AND `item_guid` > 0", GetGUIDLow());
10433 if( !result )
10434 return;
10436 Field *fields;
10439 fields = result->Fetch();
10440 uint32 item_guid = fields[0].GetUInt32();
10441 uint32 item_template = fields[1].GetUInt32();
10443 ItemPrototype const *proto = objmgr.GetItemPrototype(item_template);
10445 if(!proto)
10447 sLog.outError( "Player %u have unknown item_template (ProtoType) in mailed items(GUID: %u template: %u) in mail, skipped.", GetGUIDLow(), item_guid, item_template);
10448 continue;
10450 Item *item = NewItemOrBag(proto);
10451 if(!item->LoadFromDB(item_guid, 0))
10453 sLog.outError( "Player::_LoadMailedItems - Mailed Item doesn't exist!!!! - item guid: %u", item_guid);
10454 delete item;
10455 continue;
10457 AddMItem(item);
10459 while( result->NextRow() );
10461 delete result;
10464 void Player::_LoadMail()
10466 time_t base = time(NULL);
10468 _LoadMailedItems();
10470 m_mail.clear();
10471 //mails are in right order
10472 QueryResult *result = sDatabase.PQuery("SELECT `id`,`messageType`,`sender`,`receiver`,`subject`,`itemPageId`,`item_guid`,`item_template`,`time`,`money`,`cod`,`checked` FROM `mail` WHERE `receiver` = '%u' ORDER BY `id` DESC",GetGUIDLow());
10473 if(result)
10477 Field *fields = result->Fetch();
10478 Mail *m = new Mail;
10479 m->messageID = fields[0].GetUInt32();
10480 m->messageType = fields[1].GetUInt8();
10481 m->sender = fields[2].GetUInt32();
10482 m->receiver = fields[3].GetUInt32();
10483 m->subject = fields[4].GetCppString();
10484 m->itemPageId = fields[5].GetUInt32();
10485 m->item_guid = fields[6].GetUInt32();
10486 m->item_template = fields[7].GetUInt32();
10487 m->time = fields[8].GetUInt32();
10488 m->money = fields[9].GetUInt32();
10489 m->COD = fields[10].GetUInt32();
10490 m->checked = fields[11].GetUInt32();
10491 m->state = UNCHANGED;
10492 m_mail.push_back(m);
10493 } while( result->NextRow() );
10494 delete result;
10496 m_mailsLoaded = true;
10499 void Player::LoadPet()
10501 uint64 pet_guid = GetPetGUID();
10502 if(pet_guid)
10504 Creature* in_pet = ObjectAccessor::Instance().GetCreature(*this, pet_guid);
10505 if(in_pet)
10506 return;
10507 Pet *pet = new Pet();
10508 pet->LoadPetFromDB(this);
10512 void Player::_LoadQuestStatus()
10514 mQuestStatus.clear();
10516 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());
10518 if(result)
10522 Field *fields = result->Fetch();
10524 uint32 quest_id = fields[0].GetUInt32();
10525 Quest* pQuest = objmgr.QuestTemplates[quest_id];// used to be new, no delete?
10526 if( pQuest )
10528 mQuestStatus[quest_id].m_quest = pQuest;
10530 uint32 qstatus = fields[1].GetUInt32();
10531 if(qstatus < MAX_QUEST_STATUS)
10532 mQuestStatus[quest_id].m_status = QuestStatus(qstatus);
10533 else
10535 mQuestStatus[quest_id].m_status = QUEST_STATUS_NONE;
10536 sLog.outError("Player %s have invalid quest %d status (%d), replaced by QUEST_STATUS_NONE(0).",GetName(),quest_id,qstatus);
10539 mQuestStatus[quest_id].m_rewarded = ( fields[2].GetUInt8() > 0 );
10540 mQuestStatus[quest_id].m_explored = ( fields[3].GetUInt8() > 0 );
10541 mQuestStatus[quest_id].m_completed_once = ( fields[4].GetUInt8() > 0 );
10543 if( objmgr.QuestTemplates[quest_id]->HasSpecialFlag( QUEST_SPECIAL_FLAGS_TIMED ) && !mQuestStatus[quest_id].m_rewarded )
10544 AddTimedQuest( quest_id );
10546 if (fields[5].GetUInt32() <= sWorld.GetGameTime())
10548 mQuestStatus[quest_id].m_timer = 1;
10549 } else
10550 mQuestStatus[quest_id].m_timer = (fields[5].GetUInt32() - sWorld.GetGameTime()) * 1000;
10552 mQuestStatus[quest_id].m_creatureOrGOcount[0] = fields[6].GetUInt32();
10553 mQuestStatus[quest_id].m_creatureOrGOcount[1] = fields[7].GetUInt32();
10554 mQuestStatus[quest_id].m_creatureOrGOcount[2] = fields[8].GetUInt32();
10555 mQuestStatus[quest_id].m_creatureOrGOcount[3] = fields[9].GetUInt32();
10556 mQuestStatus[quest_id].m_itemcount[0] = fields[10].GetUInt32();
10557 mQuestStatus[quest_id].m_itemcount[1] = fields[11].GetUInt32();
10558 mQuestStatus[quest_id].m_itemcount[2] = fields[12].GetUInt32();
10559 mQuestStatus[quest_id].m_itemcount[3] = fields[13].GetUInt32();
10561 sLog.outDebug("Quest status is {%u} for quest {%u}", mQuestStatus[quest_id].m_status, quest_id);
10564 while( result->NextRow() );
10566 delete result;
10570 void Player::_LoadReputation()
10572 Factions newFaction;
10574 factions.clear();
10576 QueryResult *result = sDatabase.PQuery("SELECT `faction`,`reputation`,`standing`,`flags` FROM `character_reputation` WHERE `guid` = '%u'",GetGUIDLow());
10578 if(result)
10582 Field *fields = result->Fetch();
10584 newFaction.ID = fields[0].GetUInt32();
10585 newFaction.ReputationListID = fields[1].GetUInt32();
10586 newFaction.Standing = fields[2].GetUInt32();
10587 newFaction.Flags = fields[3].GetUInt32();
10589 factions.push_back(newFaction);
10591 while( result->NextRow() );
10593 delete result;
10595 else
10597 //LoadReputationFromDBC();
10598 //Set initial reputations
10599 SetInitialFactions();
10603 void Player::_LoadSpells(uint32 timediff)
10605 for (PlayerSpellMap::iterator itr = m_spells.begin(); itr != m_spells.end(); ++itr)
10606 delete itr->second;
10607 m_spells.clear();
10609 QueryResult *result = sDatabase.PQuery("SELECT `spell`,`slot`,`active` FROM `character_spell` WHERE `guid` = '%u'",GetGUIDLow());
10611 if(result)
10615 Field *fields = result->Fetch();
10617 addSpell(fields[0].GetUInt16(), fields[2].GetUInt8(), PLAYERSPELL_UNCHANGED, fields[1].GetUInt16());
10619 while( result->NextRow() );
10621 delete result;
10625 void Player::_LoadTaxiMask(const char* data)
10627 vector<string> tokens = StrSplit(data, " ");
10629 int index;
10630 vector<string>::iterator iter;
10632 for (iter = tokens.begin(), index = 0;
10633 (index < 8) && (iter != tokens.end()); ++iter, ++index)
10635 m_taximask[index] = atol((*iter).c_str());
10639 void Player::_LoadTutorials()
10641 QueryResult *result = sDatabase.PQuery("SELECT `tut0`,`tut1`,`tut2`,`tut3`,`tut4`,`tut5`,`tut6`,`tut7` FROM `character_tutorial` WHERE `guid` = '%u'",GetGUIDLow());
10643 if(result)
10647 Field *fields = result->Fetch();
10649 for (int iI=0; iI<8; iI++)
10650 m_Tutorials[iI] = fields[iI].GetUInt32();
10653 while( result->NextRow() );
10655 delete result;
10659 /*********************************************************/
10660 /*** SAVE SYSTEM ***/
10661 /*********************************************************/
10663 void Player::SaveToDB()
10665 // delay auto save at any saves (manual, in code, or autosave)
10666 m_nextSave = sWorld.getConfig(CONFIG_INTERVAL_SAVE);
10668 // saved before flight
10669 if (isInFlight())
10670 return;
10672 // save state
10673 uint32 tmp_bytes = GetUInt32Value(UNIT_FIELD_BYTES_1);
10674 uint32 tmp_flags = GetUInt32Value(UNIT_FIELD_FLAGS);
10675 uint32 tmp_pflags = GetUInt32Value(PLAYER_FLAGS);
10677 int is_logout_resting=0; //logout, far from tavern/city
10678 //logout, but in tavern/city
10679 if(!IsInWorld()&&HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING))is_logout_resting=1;
10681 // Set player sit state to standing on save
10682 RemoveFlag(UNIT_FIELD_BYTES_1,PLAYER_STATE_SIT);
10683 RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_ROTATE);
10685 //remove restflag when save
10686 //this is becouse of the rename char stuff
10687 RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING);
10689 ClearInCombat(); // Remove combat flag
10691 sLog.outDebug("The value of player %s before unload item and aura is: ", m_name.c_str());
10692 outDebugValues();
10694 if(isAlive())
10696 _RemoveAllItemMods();
10697 _RemoveAllAuraMods();
10700 bool inworld = IsInWorld();
10701 if (inworld)
10702 RemoveFromWorld();
10704 sDatabase.PExecute("DELETE FROM `character` WHERE `guid` = '%u'",GetGUIDLow());
10706 std::ostringstream ss;
10707 ss << "INSERT INTO `character` (`guid`,`realm`,`account`,`name`,`race`,`class`,"
10708 "`map`,`position_x`,`position_y`,`position_z`,`orientation`,`data`,"
10709 "`taximask`,`online`,`highest_rank`,`standing`,`rating`,`cinematic`,"
10710 "`totaltime`,`leveltime`,`rest_bonus`,`logout_time`,`is_logout_resting`,`resettalents_cost`,`resettalents_time`,"
10711 "`trans_x`, `trans_y`, `trans_z`, `trans_o`, `transguid`) VALUES ("
10712 << GetGUIDLow() << ", "
10713 << realmID << ", "
10714 << GetSession()->GetAccountId() << ", '"
10715 << m_name << "', "
10716 << m_race << ", "
10717 << m_class << ", "
10718 << m_mapId << ", "
10719 << m_positionX << ", "
10720 << m_positionY << ", "
10721 << m_positionZ << ", "
10722 << m_orientation << ", '";
10724 uint16 i;
10725 for( i = 0; i < m_valuesCount; i++ )
10727 ss << GetUInt32Value(i) << " ";
10730 ss << "', '";
10732 for( i = 0; i < 8; i++ )
10733 ss << m_taximask[i] << " ";
10735 ss << "', ";
10736 inworld ? ss << 1: ss << 0;
10738 ss << ", ";
10739 ss << m_highest_rank;
10741 ss << ", ";
10742 ss << m_standing;
10744 ss << ", ";
10745 ss << m_rating;
10747 ss << ", ";
10748 ss << m_cinematic;
10750 ss << ", ";
10751 ss << m_Played_time[0];
10752 ss << ", ";
10753 ss << m_Played_time[1];
10755 ss << ", ";
10756 ss << rest_bonus;
10757 ss << ", ";
10758 ss << time(NULL);
10759 ss << ", ";
10760 ss << is_logout_resting;
10761 ss << ", ";
10762 ss << m_resetTalentsCost;
10763 ss << ", ";
10764 ss << (uint64)m_resetTalentsTime;
10766 ss << ", ";
10767 ss << m_transX;
10768 ss << ", ";
10769 ss << m_transY;
10770 ss << ", ";
10771 ss << m_transZ;
10772 ss << ", ";
10773 ss << m_transO;
10774 ss << ", ";
10775 if (m_transport)
10776 ss << m_transport->GetGUIDLow();
10777 else
10778 ss << "0";
10780 ss << " )";
10782 sDatabase.Execute( ss.str().c_str() );
10784 SaveEnchant();
10786 if(m_mailsUpdated) //save mails only when needed
10787 _SaveMail();
10789 _SaveInventory();
10790 _SaveQuestStatus();
10791 _SaveTutorials();
10792 _SaveSpells();
10793 _SaveSpellCooldowns();
10794 _SaveActions();
10795 _SaveAuras();
10796 _SaveReputation();
10797 SavePet();
10799 sLog.outDebug("Save Basic value of player %s is: ", m_name.c_str());
10800 outDebugValues();
10802 if(isAlive())
10804 _ApplyAllAuraMods();
10805 _ApplyAllItemMods();
10808 // restore state
10809 SetUInt32Value(UNIT_FIELD_BYTES_1, tmp_bytes);
10810 SetUInt32Value(UNIT_FIELD_FLAGS, tmp_flags);
10811 SetUInt32Value(PLAYER_FLAGS, tmp_pflags);
10813 if (inworld)
10814 AddToWorld();
10817 void Player::_SaveActions()
10819 sDatabase.PExecute("DELETE FROM `character_action` WHERE `guid` = '%u'",GetGUIDLow());
10821 std::list<struct actions>::iterator itr;
10822 for (itr = m_actions.begin(); itr != m_actions.end(); ++itr)
10824 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);
10828 void Player::_SaveAuras()
10830 sDatabase.PExecute("DELETE FROM `character_aura` WHERE `guid` = '%u'",GetGUIDLow());
10832 AuraMap const& auras = GetAuras();
10833 for(AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
10835 SpellEntry *spellInfo = itr->second->GetSpellProto();
10836 uint8 i;
10837 for (i = 0; i < 3; i++)
10838 if (spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_SHAPESHIFT ||
10839 spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_STEALTH)
10840 break;
10841 if (i == 3 && !itr->second->IsPassive())
10842 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()));
10846 void Player::_SaveInventory()
10848 // force items in buyback slots to new state
10849 // and remove those that aren't already
10850 for (uint8 i = 0; i < 12; i++)
10852 Item *item = m_buybackitems[i];
10853 if (!item || item->GetState() == ITEM_NEW) continue;
10854 sDatabase.PExecute("DELETE FROM `character_inventory` WHERE `item` = '%u'", item->GetGUIDLow());
10855 sDatabase.PExecute("DELETE FROM `item_instance` WHERE `guid` = '%u'", item->GetGUIDLow());
10856 m_buybackitems[i]->FSetState(ITEM_NEW);
10859 if (m_itemUpdateQueue.empty()) return;
10861 // do not save if the update queue is corrupt
10862 bool error = false;
10863 for(int i = 0; i < m_itemUpdateQueue.size(); i++)
10865 Item *item = m_itemUpdateQueue[i];
10866 if(!item || item->GetState() == ITEM_REMOVED) continue;
10867 Item *test = GetItemByPos( item->GetBagSlot(), item->GetSlot());
10869 if (test == NULL)
10871 sLog.outError("Player::_SaveInventory - the bag(%d) and slot(%d) values for the item with guid %d are incorrect, the player doesn't have an item at that position!", item->GetBagSlot(), item->GetSlot(), item->GetGUIDLow());
10872 error = true;
10874 else if (test != item)
10876 sLog.outError("Player::_SaveInventory - the bag(%d) and slot(%d) values for the item with guid %d are incorrect, the item with guid %d is there instead!", item->GetBagSlot(), item->GetSlot(), item->GetGUIDLow(), test->GetGUIDLow());
10877 error = true;
10881 if (error)
10883 sLog.outError("Player::_SaveInventory - one or more errors occured save aborted!");
10884 sChatHandler.SendSysMessage(GetSession(), "Item save failed!");
10885 return;
10888 for(int i = 0; i < m_itemUpdateQueue.size(); i++)
10890 Item *item = m_itemUpdateQueue[i];
10891 if(!item) continue;
10893 Bag *container = item->GetContainer();
10894 uint32 bag_guid = container ? container->GetGUIDLow() : 0;
10896 switch(item->GetState())
10898 case ITEM_NEW:
10899 sDatabase.PExecute("INSERT INTO `character_inventory` (`guid`,`bag`,`slot`,`item`,`item_template`) VALUES ('%u', '%u', '%u', '%u', '%u')", GetGUIDLow(), bag_guid, item->GetSlot(), item->GetGUIDLow(), item->GetEntry());
10900 break;
10901 case ITEM_CHANGED:
10902 sDatabase.PExecute("UPDATE `character_inventory` SET `guid`='%u', `bag`='%u', `slot`='%u', `item_template`='%u' WHERE `item`='%u'", GetGUIDLow(), bag_guid, item->GetSlot(), item->GetEntry(), item->GetGUIDLow());
10903 break;
10904 case ITEM_REMOVED:
10905 sDatabase.PExecute("DELETE FROM `character_inventory` WHERE `item` = '%u'", item->GetGUIDLow());
10908 item->SaveToDB();
10910 m_itemUpdateQueue.clear();
10913 void Player::_SaveMail()
10915 if (!m_mailsLoaded)
10916 return;
10918 std::deque<Mail*>::iterator itr;
10919 for (itr = m_mail.begin(); itr != m_mail.end(); itr++)
10921 Mail *m = (*itr);
10922 if (m->state == CHANGED)
10924 sDatabase.PExecute("UPDATE `mail` SET `itemPageId` = '%u',`item_guid` = '%u',`item_template` = '%u',`time` = '" I64FMTD "',`money` = '%u',`cod` = '%u',`checked` = '%u' WHERE `id` = '%u'",
10925 m->itemPageId, m->item_guid, m->item_template, (uint64)m->time, m->money, m->COD, m->checked, m->messageID);
10926 m->state = UNCHANGED;
10928 else if (m->state == DELETED)
10930 if (m->item_guid)
10931 sDatabase.PExecute("DELETE FROM `item_instance` WHERE `guid` = '%u'", m->item_guid);
10932 if (m->itemPageId)
10934 sDatabase.PExecute("DELETE FROM `item_page` WHERE `id` = '%u'", m->itemPageId);
10936 sDatabase.PExecute("DELETE FROM `mail` WHERE `id` = '%u'", m->messageID);
10939 //dealocate deleted mails...
10940 bool continueDeleting = true;
10941 while ( continueDeleting )
10943 continueDeleting = false;
10944 for (itr = m_mail.begin(); itr != m_mail.end(); itr++)
10946 if ((*itr)->state == DELETED)
10948 Mail* m = *itr;
10949 m_mail.erase(itr);
10950 continueDeleting = true;
10951 delete m;
10952 break; //break only from for cycle
10956 m_mailsUpdated = false;
10959 void Player::_SaveQuestStatus()
10961 sDatabase.PExecute("DELETE FROM `character_queststatus` WHERE `guid` = '%u'",GetGUIDLow());
10963 for( StatusMap::iterator i = mQuestStatus.begin( ); i != mQuestStatus.end( ); ++ i )
10965 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')",
10966 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]);
10970 void Player::_SaveReputation()
10972 std::list<Factions>::iterator itr;
10974 sDatabase.PExecute("DELETE FROM `character_reputation` WHERE `guid` = '%u'",GetGUIDLow());
10976 for(itr = factions.begin(); itr != factions.end(); ++itr)
10978 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);
10982 void Player::_SaveSpells()
10984 for (PlayerSpellMap::const_iterator itr = m_spells.begin(), next = m_spells.begin(); itr != m_spells.end(); itr = next)
10986 next++;
10987 if (itr->second->state == PLAYERSPELL_REMOVED || itr->second->state == PLAYERSPELL_CHANGED)
10988 sDatabase.PExecute("DELETE FROM `character_spell` WHERE `guid` = '%u' and `spell` = '%u'", GetGUIDLow(), itr->first);
10989 if (itr->second->state == PLAYERSPELL_NEW || itr->second->state == PLAYERSPELL_CHANGED)
10990 sDatabase.PExecute("INSERT INTO `character_spell` (`guid`,`spell`,`slot`,`active`) VALUES ('%u', '%u', '%u','%u')", GetGUIDLow(), itr->first, itr->second->slotId,itr->second->active);
10991 if (itr->second->state == PLAYERSPELL_REMOVED)
10992 _removeSpell(itr->first);
10993 else
10994 itr->second->state = PLAYERSPELL_UNCHANGED;
10998 void Player::_SaveTutorials()
11000 sDatabase.PExecute("DELETE FROM `character_tutorial` WHERE `guid` = '%u'",GetGUIDLow());
11001 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]);
11004 void Player::SavePet()
11006 Creature* pet = GetPet();
11007 if(pet && (pet->isPet() || pet->isTamed()))
11008 pet->SaveAsPet();
11011 void Player::outDebugValues() const
11013 sLog.outDebug("HP is: \t\t\t%u\t\tMP is: \t\t\t%u",GetMaxHealth(), GetMaxPower(POWER_MANA));
11014 sLog.outDebug("AGILITY is: \t\t%f\t\tSTRENGTH is: \t\t%f",GetStat(STAT_AGILITY), GetStat(STAT_STRENGTH));
11015 sLog.outDebug("INTELLECT is: \t\t%f\t\tSPIRIT is: \t\t%f",GetStat(STAT_INTELLECT), GetStat(STAT_SPIRIT));
11016 sLog.outDebug("STAMINA is: \t\t%f\t\tSPIRIT is: \t\t%f",GetStat(STAT_STAMINA), GetStat(STAT_SPIRIT));
11017 sLog.outDebug("Armor is: \t\t%f\t\tBlock is: \t\t%f",GetArmor(), GetFloatValue(PLAYER_BLOCK_PERCENTAGE));
11018 sLog.outDebug("HolyRes is: \t\t%f\t\tFireRes is: \t\t%f",GetResistance(SPELL_SCHOOL_HOLY), GetResistance(SPELL_SCHOOL_FIRE));
11019 sLog.outDebug("NatureRes is: \t\t%f\t\tFrostRes is: \t\t%f",GetResistance(SPELL_SCHOOL_NATURE), GetResistance(SPELL_SCHOOL_FROST));
11020 sLog.outDebug("ShadowRes is: \t\t%f\t\tArcaneRes is: \t\t%f",GetResistance(SPELL_SCHOOL_SHADOW), GetResistance(SPELL_SCHOOL_ARCANE));
11021 sLog.outDebug("MIN_DAMAGE is: \t\t%f\tMAX_DAMAGE is: \t\t%f",GetFloatValue(UNIT_FIELD_MINDAMAGE), GetFloatValue(UNIT_FIELD_MAXDAMAGE));
11022 sLog.outDebug("MIN_OFFHAND_DAMAGE is: \t%f\tMAX_OFFHAND_DAMAGE is: \t%f",GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE), GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE));
11023 sLog.outDebug("MIN_RANGED_DAMAGE is: \t%f\tMAX_RANGED_DAMAGE is: \t%f",GetFloatValue(UNIT_FIELD_MINRANGEDDAMAGE), GetFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE));
11024 sLog.outDebug("ATTACK_TIME is: \t%u\t\tRANGE_ATTACK_TIME is: \t%u",GetAttackTime(BASE_ATTACK), GetAttackTime(RANGED_ATTACK));
11027 /*********************************************************/
11028 /*** LOW LEVEL FUNCTIONS:Notifiers ***/
11029 /*********************************************************/
11031 void Player::SendOutOfRange(Object* obj)
11033 UpdateData his_data;
11034 WorldPacket his_pk;
11035 obj->BuildOutOfRangeUpdateBlock(&his_data);
11036 his_data.BuildPacket(&his_pk);
11037 GetSession()->SendPacket(&his_pk);
11040 inline void Player::SendAttackSwingNotInRange()
11042 WorldPacket data;
11043 data.Initialize(SMSG_ATTACKSWING_NOTINRANGE);
11044 GetSession()->SendPacket( &data );
11047 void Player::SavePositionInDB(uint32 mapid, float x,float y,float z,float o,uint64 guid)
11049 std::ostringstream ss2;
11050 ss2 << "UPDATE `character` SET `position_x`='"<<x<<"',`position_y`='"<<y
11051 << "',`position_z`='"<<z<<"',`orientation`='"<<o<<"',`map`='"<<mapid
11052 << "' WHERE `guid`='"<<guid<<"'";
11053 sDatabase.Execute(ss2.str().c_str());
11056 bool Player::SaveValuesArrayInDB(vector<string> const& tokens, uint64 guid)
11058 std::ostringstream ss2;
11059 ss2<<"UPDATE `character` SET `data`='";
11060 vector<string>::const_iterator iter;
11061 int i=0;
11062 for (iter = tokens.begin(); iter != tokens.end(); ++iter, ++i)
11064 ss2<<tokens[i]<<" ";
11066 ss2<<"' WHERE `guid`='"<<guid<<"'";
11068 return sDatabase.Execute(ss2.str().c_str());
11071 void Player::SetUInt32ValueInArray(vector<string>& tokens,uint16 index, uint32 value)
11073 char buf[11];
11074 snprintf(buf,11,"%u",value);
11075 tokens[index] = buf;
11078 void Player::SetUInt32ValueInDB(uint16 index, uint32 value, uint64 guid)
11080 vector<string> tokens;
11081 if(!LoadValuesArrayFromDB(tokens,guid))
11082 return;
11084 char buf[11];
11085 snprintf(buf,11,"%u",value);
11086 tokens[index] = buf;
11088 SaveValuesArrayInDB(tokens,guid);
11091 void Player::SetFloatValueInDB(uint16 index, float value, uint64 guid)
11093 uint32 temp;
11094 memcpy(&temp, &value, sizeof(value));
11095 Player::SetUInt32ValueInDB(index, temp, guid);
11098 inline void Player::SendAttackSwingNotStanding()
11100 WorldPacket data;
11101 data.Initialize(SMSG_ATTACKSWING_NOTSTANDING);
11102 GetSession()->SendPacket( &data );
11105 inline void Player::SendAttackSwingDeadTarget()
11107 WorldPacket data;
11108 data.Initialize(SMSG_ATTACKSWING_DEADTARGET);
11109 GetSession()->SendPacket( &data );
11112 inline void Player::SendAttackSwingCantAttack()
11114 WorldPacket data;
11115 data.Initialize(SMSG_ATTACKSWING_CANT_ATTACK);
11116 GetSession()->SendPacket( &data );
11119 inline void Player::SendAttackSwingCancelAttack()
11121 WorldPacket data;
11122 data.Initialize(SMSG_CANCEL_COMBAT);
11123 GetSession()->SendPacket( &data );
11126 inline void Player::SendAttackSwingBadFacingAttack()
11128 WorldPacket data;
11129 data.Initialize(SMSG_ATTACKSWING_BADFACING);
11130 GetSession()->SendPacket( &data );
11133 void Player::PlaySound(uint32 Sound, bool OnlySelf)
11135 WorldPacket data;
11136 data.Initialize(SMSG_PLAY_SOUND);
11137 data << Sound;
11138 if (OnlySelf)
11139 GetSession()->SendPacket( &data );
11140 else
11141 SendMessageToSet( &data, true );
11144 void Player::SendExplorationExperience(uint32 Area, uint32 Experience)
11146 WorldPacket data;
11147 data.Initialize( SMSG_EXPLORATION_EXPERIENCE );
11148 data << Area;
11149 data << Experience;
11150 GetSession()->SendPacket(&data);
11153 /*********************************************************/
11154 /*** Update timers ***/
11155 /*********************************************************/
11157 void Player::UpdatePVPFlag(time_t currTime)
11159 if( !GetPvP() ) return;
11161 //Player is counting to set/unset pvp flag
11162 if( !m_pvp_counting ) return;
11164 //Is player is in a PvP action stop counting
11165 if( isInCombatWithPlayer() )
11167 m_pvp_counting = false;
11168 m_pvp_count = time(NULL);
11169 return;
11172 //Wait 5 min until remove pvp mode
11173 if( currTime < m_pvp_count + 300 ) return;
11175 SetPvP(false);
11176 //sChatHandler.SendSysMessage(GetSession(), "PvP toggled off.");
11180 void Player::UpdateDuelFlag(time_t currTime)
11182 if(!duel || duel->startTimer == 0) return;
11183 if(currTime < duel->startTimer + 3) return;
11185 SetUInt32Value(PLAYER_DUEL_TEAM, 1);
11186 duel->opponent->SetUInt32Value(PLAYER_DUEL_TEAM, 2);
11188 duel->startTimer = 0;
11189 duel->startTime = currTime;
11190 duel->opponent->duel->startTimer = 0;
11191 duel->opponent->duel->startTime = currTime;
11194 void Player::UnsummonPet(Creature* pet)
11196 if(!pet)
11197 pet = GetPet();
11199 if(!pet||pet->GetGUID()!=GetPetGUID()) return;
11201 SetPet(0);
11203 pet->CombatStop();
11205 if(pet->isPet())
11206 pet->SaveAsPet();
11208 WorldPacket data;
11209 data.Initialize(SMSG_DESTROY_OBJECT);
11210 data << pet->GetGUID();
11211 SendMessageToSet (&data, true);
11213 data.Initialize(SMSG_PET_SPELLS);
11214 data << uint64(0);
11215 GetSession()->SendPacket(&data);
11217 ObjectAccessor::Instance().AddObjectToRemoveList(pet);
11220 void Player::UnTamePet(Creature* pet)
11222 if(!pet)
11223 pet = GetPet();
11225 if(!pet||!pet->isTamed()||pet->GetGUID()!=GetPetGUID()) return;
11227 pet->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,pet->GetCreatureInfo()->faction);
11228 pet->SetMaxPower(POWER_HAPPINESS,0);
11229 pet->SetPower(POWER_HAPPINESS,0);
11230 pet->SetMaxPower(POWER_FOCUS,0);
11231 pet->SetPower(POWER_FOCUS,0);
11232 pet->SetUInt64Value(UNIT_FIELD_CREATEDBY, 0);
11233 pet->SetUInt32Value(UNIT_FIELD_PETNUMBER,0);
11234 pet->SetTamed(false);
11235 SetPet(0);
11237 pet->AIM_Initialize();
11239 WorldPacket data;
11241 data.Initialize(SMSG_PET_SPELLS);
11242 data << uint64(0);
11243 GetSession()->SendPacket(&data);
11246 void Player::Uncharm()
11248 Creature* charm = GetCharm();
11249 if(!charm) return;
11251 SetCharm(0);
11253 CreatureInfo const *cinfo = charm->GetCreatureInfo();
11254 charm->SetUInt64Value(UNIT_FIELD_CHARMEDBY,0);
11255 charm->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,cinfo->faction);
11257 charm->AIM_Initialize();
11258 WorldPacket data;
11259 data.Initialize(SMSG_PET_SPELLS);
11260 data << uint64(0);
11261 GetSession()->SendPacket(&data);
11264 void Player::PetSpellInitialize()
11266 Creature* pet = GetPet();
11267 if(!pet)
11268 pet = GetCharm();
11269 if(pet)
11272 WorldPacket data;
11273 uint16 Command = 7;
11274 uint16 State = 6;
11275 uint8 addlist = 0;
11277 sLog.outDebug("Pet Spells Groups");
11279 data.clear();
11280 data.Initialize(SMSG_PET_SPELLS);
11282 data << (uint64)pet->GetGUID() << uint32(0x00000000) << uint32(0x1010000);
11284 data << uint16 (2) << uint16(Command << 8) << uint16 (1) << uint16(Command << 8) << uint16 (0) << uint16(Command << 8);
11286 for(uint32 i=0; i < CREATURE_MAX_SPELLS; i++)
11287 //C100 = maybe group
11288 data << uint16 (pet->m_spells[i]) << uint16 (0xC100);
11290 data << uint16 (2) << uint16(State << 8) << uint16 (1) << uint16(State << 8) << uint16 (0) << uint16(State << 8);
11292 if(pet->GetUInt32Value(UNIT_FIELD_PETNUMBER))
11294 for(PlayerSpellMap::iterator itr = m_spells.begin();itr != m_spells.end();itr++)
11296 if(itr->second->active == 4)
11297 addlist++;
11301 data << uint8(addlist);
11303 if(pet->GetUInt32Value(UNIT_FIELD_PETNUMBER))
11305 for(PlayerSpellMap::iterator itr = m_spells.begin();itr != m_spells.end();itr++)
11307 if(itr->second->active == 4)
11309 bool hasthisspell = false;
11311 SpellEntry *spellInfo = sSpellStore.LookupEntry(itr->first);
11312 data << uint16(spellInfo->EffectTriggerSpell[0]);
11313 for(uint32 i=0; i < CREATURE_MAX_SPELLS; i++)
11315 if(pet->m_spells[i] == spellInfo->EffectTriggerSpell[0])
11317 data << uint16(0xC1);
11318 hasthisspell = true;
11319 break;
11322 if(!hasthisspell)
11323 data << uint16(0x01);
11328 data << uint8(0x01) << uint32(0x6010) << uint32(0x00) << uint32(0x00) << uint16(0x00);
11330 GetSession()->SendPacket(&data);
11334 int32 Player::GetTotalFlatMods(uint32 spellId, uint8 op)
11336 SpellEntry *spellInfo = sSpellStore.LookupEntry(spellId);
11337 if (!spellInfo) return 0;
11338 int32 total = 0;
11339 for (SpellModList::iterator itr = m_spellMods[op].begin(); itr != m_spellMods[op].end(); ++itr)
11341 SpellModifier *mod = *itr;
11342 if (!mod) continue;
11343 if ((mod->mask & spellInfo->SpellFamilyFlags) == 0) continue;
11344 if (mod->type == SPELLMOD_FLAT)
11345 total += mod->value;
11347 return total;
11350 int32 Player::GetTotalPctMods(uint32 spellId, uint8 op)
11352 SpellEntry *spellInfo = sSpellStore.LookupEntry(spellId);
11353 if (!spellInfo) return 0;
11354 int32 total = 0;
11355 for (SpellModList::iterator itr = m_spellMods[op].begin(); itr != m_spellMods[op].end(); ++itr)
11357 SpellModifier *mod = *itr;
11358 if (!mod) continue;
11359 if ((mod->mask & spellInfo->SpellFamilyFlags) == 0) continue;
11360 if (mod->type == SPELLMOD_PCT)
11361 total += mod->value;
11363 return total;
11366 void Player::ApplyBlockValueMod(int32 val,bool apply)
11368 ApplyModUInt32Var(m_BlockValue,val,apply);
11371 void Player::RemoveAreaAurasFromGroup()
11373 Group* pGroup = objmgr.GetGroupByLeader(this->GetGroupLeader());
11374 if(!pGroup)
11375 return;
11377 for(uint32 p=0;p<pGroup->GetMembersCount();p++)
11379 Unit* Member = ObjectAccessor::Instance().FindPlayer(pGroup->GetMemberGUID(p));
11380 if(!Member)
11381 continue;
11382 Member->RemoveAreaAurasByOthers(GetGUID());
11383 for (uint8 i = 0; i < 4; i++)
11384 if (m_TotemSlot[i])
11385 Member->RemoveAreaAurasByOthers(m_TotemSlot[i]);
11389 // send Proficiency
11390 void Player::SendProficiency(uint8 pr1, uint32 pr2)
11392 WorldPacket data;
11393 data.Initialize (SMSG_SET_PROFICIENCY);
11394 data << pr1 << pr2;
11395 GetSession()->SendPacket (&data);
11398 void Player::RemovePetitionsAndSigns(uint64 guid)
11400 QueryResult *result = sDatabase.PQuery("SELECT `ownerguid`,`charterguid` FROM `guild_charter_sign` WHERE `playerguid` = '%u'", guid);
11401 if(result)
11405 Field *fields = result->Fetch();
11406 uint64 ownerguid = MAKE_GUID(fields[0].GetUInt32(),HIGHGUID_PLAYER);
11407 uint64 charterguid = MAKE_GUID(fields[1].GetUInt32(),HIGHGUID_ITEM);
11409 // send update if charter owner in game
11410 Player* owner = objmgr.GetPlayer(ownerguid);
11411 if(owner)
11412 owner->GetSession()->SendPetitionQueryOpcode(charterguid);
11414 } while ( result->NextRow() );
11416 delete result;
11418 sDatabase.PExecute("DELETE FROM `guild_charter_sign` WHERE `playerguid` = '%u'",guid);
11421 sDatabase.PExecute("DELETE FROM `guild_charter` WHERE `ownerguid` = '%u'",guid);
11422 sDatabase.PExecute("DELETE FROM `guild_charter_sign` WHERE `ownerguid` = '%u'",guid);
11425 void Player::SetRestBonus (float rest_bonus_new)
11427 if(rest_bonus_new < 0)
11428 rest_bonus_new = 0;
11430 float rest_bonus_max = (float)GetUInt32Value(PLAYER_NEXT_LEVEL_XP)/2;
11432 if(rest_bonus_new > rest_bonus_max)
11433 rest_bonus = rest_bonus_max;
11434 else
11435 rest_bonus = rest_bonus_new;
11437 // update data for client
11438 if(rest_bonus>10)
11440 SetFlag(PLAYER_BYTES_2, 0x1000000); // Set Reststate = Rested
11441 RemoveFlag(PLAYER_BYTES_2, 0x2000000); // Remove Reststate = Normal
11443 else if(rest_bonus<=0)
11445 SetFlag(PLAYER_BYTES_2, 0x2000000); // Set Reststate = Normal
11446 RemoveFlag(PLAYER_BYTES_2, 0x1000000); // Remove Reststate = Rested
11449 //RestTickUpdate
11450 SetUInt32Value(PLAYER_REST_STATE_EXPERIENCE, rest_bonus);
11453 void Player::HandleInvisiblePjs()
11455 Map *m = MapManager::Instance().GetMap(m_mapId);
11457 //this is to be sure that InvisiblePjsNear vector has active pjs only.
11458 m->PlayerRelocation(this, m_positionX, m_positionY, m_positionZ, m_orientation, true);
11460 for (std::vector<Player *>::iterator i = InvisiblePjsNear.begin(); i != InvisiblePjsNear.end(); i++)
11462 if ((*i)->isVisibleFor(this))
11464 m_DiscoveredPj = *i;
11465 m_enableDetect = false;
11466 m->PlayerRelocation(this, m_positionX, m_positionY, m_positionZ, m_orientation, true);
11467 m_enableDetect = true;
11468 m_DiscoveredPj = 0;
11471 if (!InvisiblePjsNear.size())
11472 m_DetectInvTimer = 0;
11473 InvisiblePjsNear.clear();