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
20 #include "Database/DatabaseEnv.h"
23 #include "ObjectMgr.h"
25 #include "WorldPacket.h"
26 #include "WorldSession.h"
27 #include "UpdateMask.h"
30 #include "GossipDef.h"
32 #include "UpdateData.h"
35 #include "MapManager.h"
36 #include "ObjectMgr.h"
37 #include "ObjectAccessor.h"
38 #include "CreatureAI.h"
43 #include "SpellAuras.h"
45 #include "Transports.h"
49 Player::Player (WorldSession
*session
): Unit()
57 m_objectType
|= TYPE_PLAYER
;
58 m_objectTypeId
= TYPEID_PLAYER
;
60 m_valuesCount
= PLAYER_END
;
67 if(GetSession()->GetSecurity() >=2)
68 SetAcceptTicket(true);
69 if(GetSession()->GetSecurity() >=1 && sWorld
.getConfig(CONFIG_GM_WISPERING_TO
))
70 SetAcceptWhispers(true);
82 m_nextSave
= sWorld
.getConfig(CONFIG_INTERVAL_SAVE
);
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
));
92 //m_pDuelSender = NULL;
104 m_total_honor_points
= 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;
129 m_DetectInvTimer
= 1000;
131 m_enableDetect
= true;
134 m_pvp_counting
= false;
136 m_bgInBattleGround
= false;
137 m_bgBattleGroundID
= 0;
139 m_movement_flags
= 0;
143 m_logintime
= time(NULL
);
144 m_Last_tick
= m_logintime
;
146 m_soulStoneSpell
= 0;
147 m_WeaponProficiency
= 0;
148 m_ArmorProficiency
= 0;
150 m_canDualWield
= false;
152 ////////////////////Rest System/////////////////////
159 ////////////////////Rest System/////////////////////
161 m_mailsLoaded
= false;
162 m_mailsUpdated
= false;
164 m_resetTalentsCost
= 0;
165 m_resetTalentsTime
= 0;
166 m_itemUpdateQueueBlocked
= false;
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
++)
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
)
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
;
205 m_transport
->RemovePassenger(this);
209 bool Player::Create( uint32 guidlow
, WorldPacket
& data
)
212 uint8 race
,class_
,gender
,skin
,face
,hairStyle
,hairColor
,facialHair
,outfitId
;
214 Object::_Create(guidlow
, HIGHGUID_PLAYER
);
218 if(m_name
.size() == 0)
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_
);
229 sLog
.outError("Player have incorrect race/class pair. Can't be loaded.");
233 for (i
= 0; i
< BANK_SLOT_BAG_END
; i
++)
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);
249 m_mapId
= info
->mapId
;
250 m_positionX
= info
->positionX
;
251 m_positionY
= info
->positionY
;
252 m_positionZ
= info
->positionZ
;
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
);
261 sLog
.outError("Race %u not found in DBÑ (Wrong DBC files?)",race
);
265 m_taximask
[0] = rEntry
->startingTaxiMask
;
267 ChrClassesEntry
const* cEntry
= sChrClassesStore
.LookupEntry(class_
);
270 sLog
.outError("Class %u not found in DBÑ (Wrong DBC files?)",class_
);
274 uint8 powertype
= cEntry
->powerType
;
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;
285 sLog
.outError("Invalid default powertype %u for player (class %u)",powertype
,class_
);
289 if ( race
== RACE_TAUREN
)
290 SetFloatValue(OBJECT_FIELD_SCALE_X
, 1.35f
);
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);
328 m_Last_tick
= time(NULL
);
329 m_Played_time
[0] = 0;
330 m_Played_time
[1] = 0;
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
;
345 sLog
.outDebug("PLAYER: Adding initial spell, id = %u",tspell
);
346 addSpell(tspell
,spell_itr
->second
);
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(); )
356 tskill
[i
] = (*skill_itr
[i
]);
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]);
369 action_itr
[i
] = info
->action
[i
].begin();
371 for (; action_itr
[0]!=info
->action
[0].end() && action_itr
[1]!=info
->action
[1].end();)
374 taction
[i
] = (*action_itr
[i
]);
376 addAction((uint8
)taction
[0], taction
[1], (uint8
)taction
[2], (uint8
)taction
[3]);
390 UpdateBlockPercentage();
392 // apply original stats mods before item equipment that call before equip _RemoveStatsMods()
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
;
405 sLog
.outDebug("STORAGE: Creating initial item, itemId = %u, count = %u",titem_id
, titem_amount
);
407 pItem
= CreateItem( titem_id
, titem_amount
);
410 msg
= CanEquipItem( NULL_SLOT
, dest
, pItem
, false );
411 if( msg
== EQUIP_ERR_OK
)
412 EquipItem( dest
, pItem
, true);
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);
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
);
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
);
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);
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
471 void Player::StartMirrorTimer(MirrorTimerType Type
, uint32 MaxValue
)
474 uint32 BreathRegen
= (uint32
)-1;
475 data
.Initialize(SMSG_START_MIRROR_TIMER
);
476 data
<< (uint32
)Type
;
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
;
491 data
.Initialize(SMSG_START_MIRROR_TIMER
);
492 data
<< (uint32
)Type
;
493 data
<< CurrentValue
;
498 GetSession()->SendPacket( &data
);
501 void Player::StopMirrorTimer(MirrorTimerType Type
)
503 if(Type
==BREATH_TIMER
)
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
)
515 data
.Initialize(SMSG_ENVIRONMENTALDAMAGELOG
);
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
)
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
);
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;
579 else if ((m_breathTimer
< 50) && !(m_isunderwater
& 0x01) && (m_isunderwater
== 0x10))
581 StopMirrorTimer(BREATH_TIMER
);
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
600 //uint32 damage = 10;
601 uint32 damage
= (GetMaxHealth() / 3) + rand()%getLevel();
604 EnvironmentalDamage(guid
, DAMAGE_LAVA
, damage
);
605 m_breathTimer
= 1000;
609 //Death timer disabled and WaterFlags reset
610 else if (m_deathState
== DEAD
)
617 void Player::HandleSobering()
620 if (m_drunk
<= (0xFFFF / 30))
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
)
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();
682 mQuestStatus
[*iter
].m_timer
-= p_time
;
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)
703 if(GetItemByPos( INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND ) != 0)
706 if(GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_HANDS) != 0)
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();
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);
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
);
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
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
);
795 if(p_time
>= m_regenTimer
)
798 m_regenTimer
-= p_time
;
806 if (m_deathState
== JUST_DIED
)
809 if( GetSoulStoneSpell() && GetSoulStone())
811 SpellEntry
*spellInfo
= sSpellStore
.LookupEntry(GetSoulStoneSpell());
814 Spell
spell(this, spellInfo
, true, 0);
816 SpellCastTargets targets
;
817 targets
.setUnitTarget( this );
818 spell
.m_CastItem
= GetSoulStone();
819 spell
.prepare(&targets
);
822 SetSoulStoneSpell(0);
828 if(p_time
>= m_nextSave
)
830 // m_nextSave reseted in SaveToDB call
832 sLog
.outBasic("Player '%u' '%s' Saved", GetGUIDLow(), GetName());
836 m_nextSave
-= p_time
;
841 if(m_breathTimer
> 0)
843 if(p_time
>= m_breathTimer
)
846 m_breathTimer
-= p_time
;
850 //Handle Water/drowning
851 HandleDrowing(60000);
856 //Handle detect invisible players
857 if (m_DetectInvTimer
> 0)
859 if (p_time
>= m_DetectInvTimer
)
861 m_DetectInvTimer
= 3000;
862 HandleInvisiblePjs();
865 m_DetectInvTimer
-= p_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
879 m_drunkTimer
+= p_time
;
881 if (m_drunkTimer
> 30000)
887 if(p_time
>= m_deathTimer
)
894 m_deathTimer
-= p_time
;
896 UpdateEnchantTime(p_time
);
899 void Player::BuildEnumData( WorldPacket
* p_data
)
901 *p_data
<< GetGUID();
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
);
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????
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
++)
944 QueryResult
*result
= sDatabase
.PQuery("SELECT `slot`,`item_template` FROM `character_inventory` WHERE `guid` = '%u' AND `bag` = 0",GetGUIDLow());
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
)
955 items
[slot
] = objmgr
.GetItemPrototype(item_id
);
958 sLog
.outError( "Player::BuildEnumData: Player %s have unknown item (id: #%u) in inventory, skipped.", GetName(),item_id
);
961 } while (result
->NextRow());
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
;
974 *p_data
<< (uint32
)0;
978 // EQUIPMENT_SLOT_END always 0,0
979 *p_data
<< (uint32
)0;
983 bool Player::ToggleAFK()
985 if(HasFlag(PLAYER_FLAGS
,PLAYER_FLAGS_AFK
))
986 RemoveFlag(PLAYER_FLAGS
,PLAYER_FLAGS_AFK
);
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
);
998 SetFlag(PLAYER_FLAGS
,PLAYER_FLAGS_DND
);
1000 return HasFlag(PLAYER_FLAGS
,PLAYER_FLAGS_DND
);
1003 uint8
Player::chatTag()
1015 void Player::SendFriendlist()
1021 FriendStr friendstr
[255];
1023 QueryResult
*result
= sDatabase
.PQuery("SELECT `friend` FROM `character_social` WHERE `flags` = 'FRIEND' AND `guid` = '%u'",GetGUIDLow());
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))
1035 friendstr
[i
].Status
= 2;
1036 else if(pObj
->isDND())
1037 friendstr
[i
].Status
= 4;
1039 friendstr
[i
].Status
= 1;
1040 friendstr
[i
].Area
= pObj
->GetZoneId();
1041 friendstr
[i
].Level
= pObj
->getLevel();
1042 friendstr
[i
].Class
= pObj
->getClass();
1046 friendstr
[i
].Status
= 0;
1047 friendstr
[i
].Area
= 0;
1048 friendstr
[i
].Level
= 0;
1049 friendstr
[i
].Class
= 0;
1056 } while( result
->NextRow() );
1061 data
.Initialize( SMSG_FRIEND_LIST
);
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))
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());
1103 Field
*fields
= result
->Fetch();
1104 m_ignorelist
.insert(fields
[0].GetUInt32());
1106 // prevent list (client-side) overflow
1107 if(m_ignorelist
.size() >= 255)
1110 while( result
->NextRow() );
1115 void Player::SendIgnorelist()
1118 if(m_ignorelist
.empty())
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);
1150 if ((this->GetMapId() == mapid
) && (!m_transport
))
1154 BuildTeleportAckMsg(&data
, x
, y
, z
, orientation
);
1155 GetSession()->SendPacket(&data
);
1156 SetPosition( x
, y
, z
, orientation
);
1157 BuildHeartBeatMsg(&data
);
1158 SendMessageToSet(&data
, true);
1162 MapManager::Instance().GetMap(GetMapId())->Remove(this, false);
1164 data
.Initialize(SMSG_TRANSFER_PENDING
);
1165 data
<< uint32(mapid
);
1168 data
<< m_transport
->GetEntry() << GetMapId();
1170 GetSession()->SendPacket(&data
);
1172 data
.Initialize(SMSG_NEW_WORLD
);
1175 data
<< (uint32
)mapid
<< m_transX
<< m_transY
<< m_transZ
<< m_transO
;
1179 data
<< (uint32
)mapid
<< (float)x
<< (float)y
<< (float)z
<< (float)orientation
;
1181 GetSession()->SendPacket( &data
);
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
);
1191 Relocate(x
, y
, z
, orientation
);
1192 SetPosition(x
, y
, z
, orientation
);
1197 //MapManager::Instance().GetMap(GetMapId())->Add(this);
1199 // Resend spell list to client after far teleport.
1200 SendInitialSpells();
1210 Unit
* unit
= ObjectAccessor::Instance().GetUnit(*this, GetSelection());
1212 SendOutOfRange(unit
);
1215 // unsommon pet if lost
1216 if(pet
&& !IsWithinDistInMap(pet
, OWNER_MAX_DISTANCE
))
1221 void Player::AddToWorld()
1223 Object::AddToWorld();
1225 for(int i
= 0; i
< BANK_SLOT_BAG_END
; i
++)
1228 m_items
[i
]->AddToWorld();
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
++)
1242 m_items
[i
]->RemoveFromWorld();
1245 Object::RemoveFromWorld();
1248 void Player::CalcRage( uint32 damage
,bool attacker
)
1253 addRage
= (uint32
)(10*damage
/(getLevel()*0.5f
));
1255 addRage
= (uint32
)(10*damage
/(getLevel()*1.5f
));
1257 ModifyPower(POWER_RAGE
, addRage
);
1260 void Player::RegenerateAll()
1263 if (m_regenTimer
!= 0)
1265 uint32 regenDelay
= 2000;
1267 // Not in combat or they have regeneration
1268 if (!isInCombat() || HasAuraType(SPELL_AURA_MOD_REGEN_DURING_COMBAT
))
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)
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;
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;
1319 long regenInterrupt
= GetTotalAuraModifier(SPELL_AURA_MOD_MANA_REGEN_INTERRUPT
);
1320 if (msecSinceLastCast
< 5000)
1322 ManaIncreaseRate
*= (float)regenInterrupt
/ 100;
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;
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;
1344 case POWER_RAGE
: // Regenerate rage
1345 addvalue
= 30 * RageIncreaseRate
; // 3 rage by tick
1347 case POWER_ENERGY
: // Regenerate energy (rogue)
1351 case POWER_HAPPINESS
:
1355 if (power
!= POWER_RAGE
)
1357 curValue
+= uint32(addvalue
);
1358 if (curValue
> maxValue
) curValue
= maxValue
;
1362 if(curValue
<= uint32(addvalue
))
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;
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;
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
;
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;
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
)
1437 SetFlag(PLAYER_BYTES_2
, 0x8);
1438 SetFlag(PLAYER_FLAGS
, PLAYER_FLAGS_GM
);
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
)
1453 m_GMFlags
&= ~GM_INVISIBLE
; //remove flag
1455 SetVisibility(VISIBILITY_ON
);
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
)
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
)
1485 uint32 level
= getLevel();
1487 // XP to money conversion processed in Player::RewardQuest
1488 if(level
>= sWorld
.getConfig(CONFIG_MAX_PLAYER_LEVEL
))
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
) )
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
) )
1524 InitStatsForLevel(level
);
1527 void Player::InitStatsForLevel(uint32 level
, bool sendgain
, bool remove_mods
)
1529 // Remove item, aura, stats bonuses
1532 _RemoveAllItemMods();
1533 _RemoveAllAuraMods();
1537 PlayerLevelInfo info
;
1539 objmgr
.GetPlayerLevelInfo(getRace(),getClass(),level
,&info
);
1543 // send levelup info to client
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
));
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)
1565 // Remove all talent points
1566 if(getLevel() >= 10) // Free any used talentes
1569 SetUInt32Value(PLAYER_CHARACTER_POINTS1
,0);
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));
1578 if(level
< getLevel()) // Free if need talentes, remove some amount talent points
1580 if(GetUInt32Value(PLAYER_CHARACTER_POINTS1
) < (getLevel() - level
))
1582 SetUInt32Value(PLAYER_CHARACTER_POINTS1
,GetUInt32Value(PLAYER_CHARACTER_POINTS1
)-(getLevel() - level
));
1586 // update level, max level of skills
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
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;
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
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()
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
)
1707 if(itr
->second
->active
)
1711 data
.Initialize( SMSG_INITIAL_SPELLS
);
1713 data
<< uint16(spellCount
);
1715 for (itr
= m_spells
.begin(); itr
!= m_spells
.end(); ++itr
)
1717 if(itr
->second
->state
== PLAYERSPELL_REMOVED
)
1720 if(!itr
->second
->active
)
1723 data
<< uint16(itr
->first
);
1724 data
<< uint16(itr
->second
->slotId
);
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.
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
)
1758 Mail
* m
= new Mail
;
1759 m
->messageID
= mailId
;
1760 m
->messageType
= messageType
;
1762 m
->receiver
= this->GetGUIDLow();
1763 m
->subject
= subject
;
1764 m
->itemPageId
= itemPageId
;
1765 m
->item_guid
= itemGuid
;
1766 m
->item_template
= item_template
;
1770 m
->checked
= checked
;
1771 m
->state
= UNCHANGED
;
1778 void Player::SendMailResult(uint32 mailId
, uint32 mailAction
, uint32 mailError
, uint32 equipError
)
1781 data
.Initialize(SMSG_SEND_MAIL_RESULT
);
1782 data
<< (uint32
) mailId
;
1783 data
<< (uint32
) mailAction
;
1784 data
<< (uint32
) mailError
;
1786 data
<< (uint32
) equipError
;
1787 GetSession()->SendPacket(&data
);
1790 //call this function only when sending new mail
1791 void Player::AddMail(Mail
*m
)
1795 data
.Initialize(SMSG_RECEIVED_MAIL
);
1797 GetSession()->SendPacket(&data
);
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
);
1813 sLog
.outError("Player::addSpell: Non-existed in SpellStore spell #%u request.",spell_id
);
1817 PlayerSpellMap::iterator itr
= m_spells
.find(spell_id
);
1818 if (itr
!= m_spells
.end())
1820 if (itr
->second
->state
== PLAYERSPELL_REMOVED
)
1823 m_spells
.erase(itr
);
1824 state
= PLAYERSPELL_CHANGED
;
1830 PlayerSpell
*newspell
;
1832 newspell
= new PlayerSpell
;
1833 newspell
->active
= active
;
1834 newspell
->state
= state
;
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;
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)
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);
1898 void Player::learnSpell(uint16 spell_id
)
1900 SpellEntry
*spellInfo
= sSpellStore
.LookupEntry(spell_id
);
1903 sLog
.outError("Player::addSpell: Non-existed in SpellStore spell #%u request.",spell_id
);
1908 data
.Initialize(SMSG_LEARNED_SPELL
);
1909 data
<<uint32(spell_id
);
1910 GetSession()->SendPacket(&data
);
1912 if (!addSpell(spell_id
,1))
1915 uint16 maxskill
= getLevel()*5 > 300 ? 300 :getLevel()*5;
1922 case 9077: //Leather
1928 case 750: //Plate Mail
1936 SetSkill(44,1,maxskill
);
1938 case 197: //Two-Handed Axes
1939 SetSkill(172,1,maxskill
);
1942 SetSkill(136,1,maxskill
);
1945 SetSkill(54,1,maxskill
);
1947 case 199: //Two-Handed Maces
1948 SetSkill(160,1,maxskill
);
1951 SetSkill(43,1,maxskill
);
1953 case 202: //Two-Handed Swords
1954 SetSkill(55,1,maxskill
);
1956 case 1180: //Daggers
1957 SetSkill(173,1,maxskill
);
1959 case 15590: //Fist Weapons
1960 SetSkill(473,1,maxskill
);
1962 case 200: //Polearms
1963 SetSkill(229,1,maxskill
);
1965 case 3386: //Polearms
1966 SetSkill(227,1,maxskill
);
1970 SetSkill(45,1,maxskill
);
1972 case 5011: //Crossbows
1973 SetSkill(226,1,maxskill
);
1976 SetSkill(46,1,maxskill
);
1979 SetSkill(176,1,maxskill
);
1982 SetSkill(228,1,maxskill
);
1985 case 2842: //poisons
1986 SetSkill(40,1,maxskill
);
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);
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;
2006 data
.Initialize(SMSG_REMOVED_SPELL
);
2008 GetSession()->SendPacket(&data
);
2010 if(itr
->second
->state
== PLAYERSPELL_NEW
)
2013 m_spells
.erase(itr
);
2016 itr
->second
->state
= PLAYERSPELL_REMOVED
;
2018 RemoveAurasDueToSpell(spell_id
);
2024 void Player::_LoadSpellCooldowns()
2026 m_spellCooldowns
.clear();
2028 QueryResult
*result
= sDatabase
.PQuery("SELECT `spell`,`time` FROM `character_spell_cooldown` WHERE `guid` = '%u'",GetGUIDLow());
2032 time_t curTime
= time(NULL
);
2036 data
.Initialize(SMSG_SPELL_COOLDOWN
);
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
);
2052 // skip outdated cooldown
2053 if(db_time
<= curTime
)
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() );
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
);
2085 data
.Initialize(SMSG_ITEM_COOLDOWN
);
2086 data
<< pItem
->GetGUID();
2087 data
<< uint32(spell_id
);
2088 GetSession()->SendPacket(&data
);
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
);
2109 data
.Initialize(SMSG_ITEM_COOLDOWN
);
2110 data
<< pItem
->GetGUID();
2111 data
<< uint32(spell_id
);
2112 GetSession()->SendPacket(&data
);
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
++);
2136 sDatabase
.PExecute("INSERT INTO `character_spell_cooldown` (`guid`,`spell`,`time`) VALUES ('%u', '%u', '" I64FMTD
"')", GetGUIDLow(), itr
->first
, uint64(itr
->second
));
2142 uint32
Player::resetTalentsCost() const
2144 // The first time reset costs 1 gold
2145 if(m_resetTalentsCost
< 1*GOLD
)
2148 else if(m_resetTalentsCost
< 5*GOLD
)
2150 // After that it increases in increments of 5 gold
2151 else if(m_resetTalentsCost
< 10*GOLD
)
2155 uint32 months
= (sWorld
.GetLastTickTime() - m_resetTalentsTime
)/MONTH
;
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
);
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
)
2175 bool Player::resetTalents(bool no_cost
)
2177 uint32 level
= getLevel();
2178 if (level
< 10 || (GetUInt32Value(PLAYER_CHARACTER_POINTS1
) >= level
- 9))
2185 cost
= resetTalentsCost();
2187 if (GetMoney() < cost
)
2189 SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY
, 0, 0, 0);
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
);
2216 SetUInt32Value(PLAYER_CHARACTER_POINTS1
, level
- 9);
2220 ModifyMoney(-(int32
)cost
);
2222 m_resetTalentsCost
= cost
;
2223 m_resetTalentsTime
= time(NULL
);
2228 bool Player::_removeSpell(uint16 spell_id
)
2230 PlayerSpellMap::iterator itr
= m_spells
.find(spell_id
);
2231 if (itr
!= m_spells
.end())
2234 m_spells
.erase(itr
);
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
)
2253 void Player::_SetCreateBits(UpdateMask
*updateMask
, Player
*target
) const
2257 Object::_SetCreateBits(updateMask
, target
);
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
2277 Object::_SetUpdateBits(updateMask
, target
);
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
)
2383 m_items
[i
]->BuildCreateUpdateBlockForPlayer( data
, target
);
2389 for(int i
= EQUIPMENT_SLOT_END
; i
< BANK_SLOT_BAG_END
; i
++)
2391 if(m_items
[i
] == NULL
)
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
)
2410 m_items
[i
]->DestroyForPlayer( target
);
2416 for(int i
= EQUIPMENT_SLOT_END
; i
< BANK_SLOT_BAG_END
; i
++)
2418 if(m_items
[i
] == NULL
)
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] )
2442 else if(itr->first == spellInfo->Id)
2450 bool Player::CanLearnProSpell(uint32 spell
)
2452 SpellEntry
*spellInfo
= sSpellStore
.LookupEntry(spell
);
2456 if(spellInfo
->Effect
[0] != 36)
2459 uint32 skill
= spellInfo
->EffectMiscValue
[1];
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
)
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
)
2481 // not check prof count for not first prof. spells (when skill already known)
2485 // count only first rank prof. spells
2486 if(FindSpellRank(pSpellInfo
->Id
)==1)
2490 if(value
>= sWorld
.getConfig(CONFIG_MAX_PRIMARY_TRADE_SKILL
))
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
2503 // remove from guild
2504 if(GetGuildId() != 0)
2506 Guild
* guild
= objmgr
.GetGuildById(GetGuildId());
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;
2533 Field
*fields
= resultCount
->Fetch();
2534 charCount
= fields
[0].GetUInt32();
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
)
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
)
2562 data
.Initialize(SMSG_FORCE_MOVE_ROOT
);
2563 data
.append(GetPackGUID());
2564 GetSession()->SendPacket( &data
);
2568 data
.Initialize(SMSG_FORCE_MOVE_UNROOT
);
2569 data
.append(GetPackGUID());
2570 GetSession()->SendPacket( &data
);
2572 case MOVE_WATER_WALK
:
2574 data
.Initialize(SMSG_MOVE_WATER_WALK
);
2575 data
.append(GetPackGUID());
2576 GetSession()->SendPacket( &data
);
2578 case MOVE_LAND_WALK
:
2580 data
.Initialize(SMSG_MOVE_LAND_WALK
);
2581 data
.append(GetPackGUID());
2582 GetSession()->SendPacket( &data
);
2588 void Player::SetPlayerSpeed(uint8 SpeedType
, float value
, bool forced
)
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());
2601 data
<< float(value
);
2602 GetSession()->SendPacket( &data
);
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());
2611 data
<< float(value
);
2612 GetSession()->SendPacket( &data
);
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());
2621 data
<< float(value
);
2622 GetSession()->SendPacket( &data
);
2626 SetSpeed( value
/ SPEED_SWIMBACK
);
2627 data
.Initialize(MSG_MOVE_SET_SWIM_BACK_SPEED
);
2628 data
.append(GetPackGUID());
2630 data
<< float(value
);
2631 GetSession()->SendPacket( &data
);
2637 void Player::BuildPlayerRepop()
2639 // place corpse instead player body
2640 Corpse
* corpse
= GetCorpse();
2642 corpse
= CreateCorpse();
2644 // now show corpse for all
2645 MapManager::Instance().GetMap(corpse
->GetMapId())->Add(corpse
);
2647 // convert player body to ghost
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);
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
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
)
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
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
)
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
2780 Corpse
* Player::CreateCorpse()
2782 // prevent existance 2 corpse for player
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()))
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
) );
2815 uint16 iIventoryType
;
2817 for (int i
= 0; i
< EQUIPMENT_SLOT_END
; 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
);
2831 // register for player, but not show
2832 corpse
->AddToWorld();
2836 void Player::SpawnCorpseBones()
2838 Corpse
* corpse
= GetCorpse();
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
])
2864 uint32 pDurability
= m_items
[equip_pos
]->GetUInt32Value(ITEM_FIELD_DURABILITY
);
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
);
2899 uint32 maxDurability
= item
->GetUInt32Value(ITEM_FIELD_MAXDURABILITY
);
2903 uint32 curDurability
= item
->GetUInt32Value(ITEM_FIELD_DURABILITY
);
2905 // some simple repair formula depending on durability lost
2908 uint32 costs
= maxDurability
- curDurability
;
2910 if (GetMoney() < costs
)
2912 DEBUG_LOG("You do not have enough money");
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() );
2933 // stop countdown until repop
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
)
2965 QueryResult
*result
= sDatabase
.PQuery("SELECT `guid` FROM `character_social` WHERE `flags` = 'FRIEND' AND `friend` = '%u'", GetGUIDLow());
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() );
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;
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);
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
3077 case SKILL_HERBALISM
:
3078 return UpdateSkillPro(SkillId
, SkillGainChance(SkillValue
, RedLevel
+100, RedLevel
+50, RedLevel
+25)*Multiplicator
);
3079 case SKILL_SKINNING
:
3081 return UpdateSkillPro(SkillId
, (SkillGainChance(SkillValue
, RedLevel
+100, RedLevel
+50, RedLevel
+25)*Multiplicator
) >> (SkillValue
/HalfChanceSkillSteps
) );
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);
3104 for (; i
< PLAYER_MAX_SKILLS
; i
++)
3105 if ( SKILL_VALUE(GetUInt32Value(PLAYER_SKILL(i
))) == SkillId
) break;
3106 if ( i
>= PLAYER_MAX_SKILLS
)
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
)
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);
3125 sLog
.outDebug("Player::UpdateSkillPro Chance=%3.1f%% missed", Chance
/10.0);
3129 void Player::UpdateWeaponSkill (WeaponAttackType attType
)
3131 // no skill gain in pvp
3132 Unit
*pVictim
= getVictim();
3133 if(pVictim
&& pVictim
->GetTypeId() == TYPEID_PLAYER
)
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());
3150 Item
*tmpitem
= GetItemByPos(INVENTORY_SLOT_BAG_0
, EQUIPMENT_SLOT_OFFHAND
);
3152 if (tmpitem
&& !tmpitem
->IsBroken())
3153 UpdateSkill(tmpitem
->GetSkill());
3157 Item
* tmpitem
= GetItemByPos(INVENTORY_SLOT_BAG_0
, EQUIPMENT_SLOT_RANGED
);
3159 if (tmpitem
&& !tmpitem
->IsBroken())
3160 UpdateSkill(tmpitem
->GetSkill());
3165 void Player::UpdateCombatSkills(Unit
*pVictim
, WeaponAttackType attType
, MeleeHitOutcome outcome
, bool defence
)
3169 case MELEE_HIT_CRIT
:
3171 case MELEE_HIT_DODGE
:
3173 case MELEE_HIT_PARRY
:
3175 case MELEE_HIT_BLOCK
:
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
)
3188 if (moblevel
> plevel
+ 5)
3189 moblevel
= plevel
+ 5;
3191 uint32 lvldif
= moblevel
- greylevel
;
3195 uint32 skilldif
= 5 * plevel
- (defence
? GetPureDefenceSkillValue() : GetPureWeaponSkillValue(attType
));
3199 float chance
= 3 * lvldif
* skilldif
/ plevel
;
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))
3213 UpdateWeaponSkill(attType
);
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
);
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
)
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
)
3263 uint32 data
= GetUInt32Value(PLAYER_SKILL(i
)+1);
3265 uint32 max
= data
>>16;
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
)
3285 for (; i
< PLAYER_MAX_SKILLS
; i
++)
3286 if ((GetUInt32Value(PLAYER_SKILL(i
)) & 0x0000FFFF) == id
) break;
3288 if(i
<PLAYER_MAX_SKILLS
) //has skill
3291 SetUInt32Value(PLAYER_SKILL(i
)+1,currVal
+maxVal
*0x10000);
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
)
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
);
3315 sLog
.outError("Skill not found in SkillLineStore: skill #%u", id
);
3318 // enable unlearn button for professions only
3319 if (pSkill
->categoryId
== 11)
3320 SetUInt32Value(PLAYER_SKILL(i
), id
| (1 << 16));
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);
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
)
3354 uint16
Player::GetSkillValue(uint32 skill
) const
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);
3367 uint16
Player::GetPureSkillValue(uint32 skill
) const
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));
3380 void Player::SendInitialActions()
3382 sLog
.outDetail( "Initializing Action Buttons for '%u'", GetGUIDLow() );
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
);
3406 for (int temp_counter
=(120-button
); temp_counter
>0; temp_counter
--)
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() );
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() );
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
)
3443 ButtonExists
= true;
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
);
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())
3482 Group
*grp
= objmgr
.GetGroupByLeader(plyr
->GetGroupLeader());
3483 if(grp
->GroupCheck(plyr
->GetGUID()))
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());
3513 float water_z
= m
->GetWaterLevel(x
,y
);
3514 uint8 flag1
= m
->GetTerrainType(x
,y
);
3517 if ((z
< (water_z
- 2)) && (flag1
& 0x01))
3518 m_isunderwater
|= 0x01;
3519 else if (z
> (water_z
- 2))
3520 m_isunderwater
&= 0x7A;
3523 if ((z
< (water_z
- 0)) && (flag1
& 0x02))
3524 m_isunderwater
|= 0x80;
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();
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()
3570 uint16 areaFlag
=MapManager::Instance().GetMap(GetMapId())->GetAreaFlag(m_positionX
,m_positionY
);
3571 if(areaFlag
==0xffff)return;
3572 int offset
= areaFlag
/ 32;
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
);
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
);
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);
3601 uint32 XP
= uint32(p
->area_level
*10*sWorld
.getRate(RATE_XP_EXPLORE
));
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
);
3616 sLog
.outError("Race %u not found in DBC: wrong DBC files?",uint32(race
));
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
);
3630 void Player::setFactionForRace(uint8 race
)
3632 m_team
= TeamForRace(race
);
3634 ChrRacesEntry
const* rEntry
= sChrRacesStore
.LookupEntry(race
);
3637 sLog
.outError("Race %u not found in DBC: wrong DBC files?",uint32(race
));
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
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;
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);
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
);
3727 FactionEntry
*factionEntry
= sFactionStore
.LookupEntry(factionTemplateEntry
->faction
);
3729 // Faction without recorded reputation. Just ignore.
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
;
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
);
3754 FactionEntry
*factionEntry
= sFactionStore
.LookupEntry(factionTemplateEntry
->faction
);
3756 // Faction without recorded reputation. Just ignore.
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
);
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
);
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)
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;
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());
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();
3873 today_honorableKills
++;
3875 if( date
== Yestarday
)
3878 yestardayHonor
+= fields
[1].GetFloat();
3880 if( (date
>= ThisWeekBegin
) && (date
< ThisWeekEnd
) )
3883 thisWeekHonor
+= fields
[1].GetFloat();
3885 if( (date
>= LastWeekBegin
) && (date
< LastWeekEnd
) )
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();
3905 today_dishonorableKills
++;
3908 //All honor points until last week
3909 if( date
< LastWeekEnd
)
3911 total_honor
-= fields
[1].GetFloat();
3915 while( result
->NextRow() );
3920 //Store Total Honor points...
3921 SetTotalHonor(total_honor
);
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
) );
3931 SetHonorRating( MaNGOS::Honor::CalculeRating(this) );
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...
3938 SetUInt32Value(PLAYER_FIELD_HONOR_BAR
, (uint32
)( (total_honor
< 0) ? 0: total_honor
) );
3941 if( CalculateHonorRank(total_honor
) )
3942 SetUInt32Value(PLAYER_BYTES_3
, (( CalculateHonorRank(total_honor
) << 24) + 0x04000000) + (m_drunk
& 0xFFFE) + getGender());
3944 SetUInt32Value(PLAYER_BYTES_3
, (m_drunk
& 0xFFFE) + getGender());
3947 SetUInt32Value(PLAYER_FIELD_SESSION_KILLS
, (today_dishonorableKills
<< 16) + today_honorableKills
);
3949 SetUInt32Value(PLAYER_FIELD_YESTERDAY_KILLS
, yestardayKills
);
3950 SetUInt32Value(PLAYER_FIELD_YESTERDAY_CONTRIBUTION
, (uint32
)yestardayHonor
);
3952 SetUInt32Value(PLAYER_FIELD_THIS_WEEK_KILLS
, thisWeekKills
);
3953 SetUInt32Value(PLAYER_FIELD_THIS_WEEK_CONTRIBUTION
, (uint32
)thisWeekHonor
);
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());
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
3977 if(honor_points
<= 0.00) rank
= 0; else
3978 if(honor_points
< 2000.00) rank
= 1;
3980 rank
= ( (int)(honor_points
/ 5000) + 1);
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());
3994 total_kills
= result
->GetRowCount();
4000 //How much honor Player gains/loses killing uVictim
4001 void Player::CalculateHonor(Unit
*uVictim
)
4003 float parcial_honor_points
= 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
;
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
;
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
);
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() );
4057 return (*result
)[0].GetUInt32();
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() );
4068 return (*result
)[0].GetUInt32();
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() );
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
)
4089 uint64 duelFlagGUID
= GetUInt64Value(PLAYER_DUEL_ARBITER
);
4090 GameObject
* obj
= ObjectAccessor::Instance().GetGameObject(*this, duelFlagGUID
);
4094 if(duel
->outOfBound
== 0)
4096 if(!IsWithinDist(obj
, 50))
4098 duel
->outOfBound
= currTime
;
4101 data
.Initialize(SMSG_DUEL_OUTOFBOUNDS
);
4102 GetSession()->SendPacket(&data
);
4107 if(IsWithinDist(obj
, 40))
4109 duel
->outOfBound
= 0;
4112 data
.Initialize(SMSG_DUEL_INBOUNDS
);
4113 GetSession()->SendPacket(&data
);
4115 else if(currTime
>= (duel
->outOfBound
+10))
4122 //type: 0=cleanup ; 1=i won ; 2=i fled
4123 void Player::DuelComplete(uint8 type
)
4125 // duel not requested
4131 data
.Initialize(SMSG_DUEL_COMPLETE
);
4132 data
<< (uint8
)((type
!=0) ? 1 : 0);
4133 GetSession()->SendPacket(&data
);
4134 duel
->opponent
->GetSession()->SendPacket(&data
);
4138 data
.Initialize(SMSG_DUEL_WINNER
);
4139 data
<< (uint8
)((type
==1) ? 0 : 1); // 0 = just won; 1 = fled
4140 data
<< duel
->opponent
->GetName();
4142 SendMessageToSet(&data
,true);
4145 // cool-down duel spell
4146 data
.Initialize(SMSG_SPELL_COOLDOWN
);
4149 GetSession()->SendPacket(&data
);
4150 data
.Initialize(SMSG_SPELL_COOLDOWN
);
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
));
4158 duel
->initiator
->RemoveGameObject(obj
,true);
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
]);
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
;
4193 static uint32 holdrand
= 0x89abcdef;
4195 void Rand_Init(uint32 seed
)
4200 int32
irand(int32 min
, int32 max
)
4202 assert((max
- min
) < 32768);
4205 holdrand
= (holdrand
* 214013) + 2531011;
4207 return (((holdrand
>> 17) * (max
- min
)) >> 15) + min
;
4210 //---------------------------------------------------------//
4212 void Player::FlightComplete()
4214 clearUnitState(UNIT_STAT_IN_FLIGHT
);
4215 SetMoney( m_dismountCost
);
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();
4230 sLog
.outDetail("applying mods for item %u ",item
->GetGUIDLow());
4234 AddItemsSetItem(this,item
);
4236 RemoveItemsSetItem(this,proto
);
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);
4256 CastItemEquipSpell(item
);
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);
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;
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
);
4289 case ITEM_STAT_HEALTH
: // modify HP
4290 ApplyMaxHealthMod(val
, apply
);
4293 case ITEM_STAT_AGILITY
: // modify agility
4294 ApplyStatMod(STAT_AGILITY
, val
, apply
);
4295 ApplyPosStatMod(STAT_AGILITY
, val
, apply
);
4296 typestr
= "AGILITY";
4298 case ITEM_STAT_STRENGTH
: //modify strength
4299 ApplyStatMod(STAT_STRENGTH
, val
, apply
);
4300 ApplyPosStatMod(STAT_STRENGTH
, val
, apply
);
4301 typestr
= "STRENGHT";
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";
4309 case ITEM_STAT_SPIRIT
: //modify spirit
4310 ApplyStatMod(STAT_SPIRIT
, val
, apply
);
4311 ApplyPosStatMod(STAT_SPIRIT
, val
, apply
);
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";
4322 sLog
.outDebug("%s %s: \t\t%u", applystr
.c_str(), typestr
.c_str(), val
);
4328 ApplyArmorMod( proto
->Armor
, apply
);
4329 sLog
.outDebug("%s Armor: \t\t%u", applystr
.c_str(), proto
->Armor
);
4334 ApplyBlockValueMod(proto
->Block
, apply
);
4335 sLog
.outDebug("%s Block: \t\t%u", applystr
.c_str(), proto
->Block
);
4340 ApplyResistanceMod(SPELL_SCHOOL_HOLY
, proto
->HolyRes
, apply
);
4341 sLog
.outDebug("%s HolyRes: \t\t%u", applystr
.c_str(), proto
->HolyRes
);
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
;
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
));
4411 if(slot
== EQUIPMENT_SLOT_RANGED
)
4413 SetAttackTime(RANGED_ATTACK
, apply
? proto
->Delay
: 2000);
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
)
4436 ItemPrototype
const *proto
= item
->GetProto();
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
);
4450 sLog
.outError("WORLD: unknown Item spellid %i", proto
->Spells
[i
].SpellId
);
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())
4470 ItemPrototype
const *proto
= item
->GetProto();
4474 if (!Target
|| Target
== this )
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
);
4486 sLog
.outError("WORLD: unknown Item spellid %i", proto
->Spells
[i
].SpellId
);
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])
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])
4571 void Player::_RemoveAllItemMods()
4573 sLog
.outDebug("_RemoveAllItemMods start.");
4575 for (int i
= 0; i
< INVENTORY_SLOT_BAG_END
; i
++)
4579 if(m_items
[i
]->IsBroken())
4582 ItemPrototype
const *proto
= m_items
[i
]->GetProto();
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);
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);
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
++)
4618 if(m_items
[i
]->IsBroken())
4620 ItemPrototype
const *proto
= m_items
[i
]->GetProto();
4623 _ApplyItemBonuses(proto
,i
, false);
4627 for(AuraList::iterator i
= mModBaseResistancePct
.begin(); i
!= mModBaseResistancePct
.end(); ++i
)
4628 (*i
)->ApplyModifier(true);
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);
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
++)
4656 if(m_items
[i
]->IsBroken())
4659 ItemPrototype
const *proto
= m_items
[i
]->GetProto();
4663 _ApplyItemBonuses(proto
,i
, true);
4667 for(AuraList::iterator i
= mModBaseResistancePct
.begin(); i
!= mModBaseResistancePct
.end(); ++i
)
4668 (*i
)->ApplyModifier(true);
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
++)
4679 if(m_items
[i
]->IsBroken())
4682 ItemPrototype
const *proto
= m_items
[i
]->GetProto();
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);
4695 AddItemEnchant(m_items
[i
],Enchant_id
, true);
4700 sLog
.outDebug("_ApplyAllItemMods complete.");
4709 void Player::SendLoot(uint64 guid
, LootType loot_type
)
4712 PermissionTypes permission
= ALL_PERMISSION
;
4714 sLog
.outDebug("Player::SendLoot");
4715 if (IS_GAMEOBJECT_GUID(guid
))
4717 sLog
.outDebug(" IS_GAMEOBJECT_GUID(guid)");
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
))
4727 if(go
->getLootState() == GO_CLOSED
)
4729 uint32 lootid
= go
->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
));
4752 if(!item
->m_lootGenerated
)
4754 item
->m_lootGenerated
= true;
4755 FillLoot(this,loot
,item
->GetEntry(),LootTemplates_Item
);
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
))
4767 if(loot_type
== LOOT_PICKPOKETING
&& IsFriendlyTo(creature
))
4770 loot
= &creature
->loot
;
4772 uint32 lootid
= creature
->GetCreatureInfo()->lootid
;
4774 if(loot_type
== LOOT_PICKPOKETING
)
4776 if ( !creature
->lootForPickPocketed
)
4778 creature
->lootForPickPocketed
= true;
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
));
4789 // the player whose group may loot the corpse
4790 Player
*recipient
= creature
->GetLootRecipient();
4793 creature
->SetLootRecipient(this);
4797 if (creature
->lootForPickPocketed
)
4799 creature
->lootForPickPocketed
= false;
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();
4818 for (pos
= 0; pos
<siz
; pos
++)
4819 if (group
->GetMemberGUID(pos
) == group
->GetLooterGuid())
4821 group
->SetLooterGuid(group
->GetMemberGUID((pos
+1)%siz
));
4823 switch (group
->GetLootMethod())
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
);
4829 case NEED_BEFORE_GREED
:
4830 group
->NeedBeforeGreed(recipient
->GetGUID(), loot
, creature
);
4838 if (loot_type
== LOOT_SKINNING
)
4839 FillLoot(this,loot
,creature
->GetCreatureInfo()->SkinLootId
,LootTemplates_Skinning
);
4841 if (!IsInGroup() && recipient
== this)
4842 permission
= ALL_PERMISSION
;
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
;
4851 if (GetGroupLeader() == recipient
->GetGroupLeader())
4852 permission
= GROUP_PERMISSION
;
4854 permission
= NONE_PERMISSION
;
4857 permission
= NONE_PERMISSION
;
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
);
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
;
4879 data
.Initialize (SMSG_LOOT_RESPONSE
);
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()
4895 data
.Initialize( SMSG_LOOT_CLEAR_MONEY
);
4896 GetSession()->SendPacket( &data
);
4899 void Player::SendNotifyLootItemRemoved(uint8 lootSlot
)
4902 data
.Initialize( SMSG_LOOT_REMOVED
);
4903 data
<< uint8(lootSlot
);
4904 GetSession()->SendPacket( &data
);
4907 void Player::SendUpdateWordState(uint16 Field
, uint16 Value
)
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;
4926 data
.Initialize (SMSG_INIT_WORLD_STATES
); //0x2C5
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;
5049 data
.Initialize (SMSG_INIT_WORLD_STATES
);
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
;
6198 if((ZoneMaxSkill
-50) > fish_value
)
6200 else if(ZoneMaxSkill
-50 <= fish_value
&& fish_value
< ZoneMaxSkill
-25)
6202 else if(ZoneMaxSkill
-25 <= fish_value
&& fish_value
< ZoneMaxSkill
)
6204 else if(ZoneMaxSkill
<= fish_value
&& fish_value
< ZoneMaxSkill
+ 25)
6209 void Player::SetBindPoint(uint64 guid
)
6212 data
.Initialize( SMSG_BINDER_CONFIRM
);
6214 GetSession()->SendPacket( &data
);
6217 void Player::SendTalentWipeConfirm(uint64 guid
)
6220 data
.Initialize( MSG_TALENT_WIPE_CONFIRM
);
6222 data
<< (uint32
)resetTalentsCost();
6223 GetSession()->SendPacket( &data
);
6226 /*********************************************************/
6227 /*** STORAGE SYSTEM ***/
6228 /*********************************************************/
6230 void Player::SetVirtualItemSlot( uint8 i
, Item
* item
)
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);
6238 if(!item
->GetUInt32Value(ITEM_FIELD_ENCHANTMENT
+3))
6240 uint32 charges
= item
->GetUInt32Value(ITEM_FIELD_ENCHANTMENT
+3+2);
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
)
6259 case 0: // no prepeared weapon
6260 SetVirtualItemSlot(0,NULL
);
6261 SetVirtualItemSlot(1,NULL
);
6262 SetVirtualItemSlot(2,NULL
);
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
);
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
);
6279 SetVirtualItemSlot(0,NULL
);
6280 SetVirtualItemSlot(1,NULL
);
6281 SetVirtualItemSlot(2,NULL
);
6286 uint8
Player::FindEquipSlot( uint32 type
, uint32 slot
, bool swap
) const
6289 slots
[0] = NULL_SLOT
;
6290 slots
[1] = NULL_SLOT
;
6291 slots
[2] = NULL_SLOT
;
6292 slots
[3] = NULL_SLOT
;
6296 slots
[0] = EQUIPMENT_SLOT_HEAD
;
6299 slots
[0] = EQUIPMENT_SLOT_NECK
;
6301 case INVTYPE_SHOULDERS
:
6302 slots
[0] = EQUIPMENT_SLOT_SHOULDERS
;
6305 slots
[0] = EQUIPMENT_SLOT_BODY
;
6308 slots
[0] = EQUIPMENT_SLOT_CHEST
;
6311 slots
[0] = EQUIPMENT_SLOT_CHEST
;
6314 slots
[0] = EQUIPMENT_SLOT_WAIST
;
6317 slots
[0] = EQUIPMENT_SLOT_LEGS
;
6320 slots
[0] = EQUIPMENT_SLOT_FEET
;
6322 case INVTYPE_WRISTS
:
6323 slots
[0] = EQUIPMENT_SLOT_WRISTS
;
6326 slots
[0] = EQUIPMENT_SLOT_HANDS
;
6328 case INVTYPE_FINGER
:
6329 slots
[0] = EQUIPMENT_SLOT_FINGER1
;
6330 slots
[1] = EQUIPMENT_SLOT_FINGER2
;
6332 case INVTYPE_TRINKET
:
6333 slots
[0] = EQUIPMENT_SLOT_TRINKET1
;
6334 slots
[1] = EQUIPMENT_SLOT_TRINKET2
;
6337 slots
[0] = EQUIPMENT_SLOT_BACK
;
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" ...
6346 slots
[1] = EQUIPMENT_SLOT_OFFHAND
;
6348 case INVTYPE_SHIELD
:
6349 slots
[0] = EQUIPMENT_SLOT_OFFHAND
;
6351 case INVTYPE_RANGED
:
6352 slots
[0] = EQUIPMENT_SLOT_RANGED
;
6354 case INVTYPE_2HWEAPON
:
6355 slots
[0] = EQUIPMENT_SLOT_MAINHAND
;
6357 case INVTYPE_TABARD
:
6358 slots
[0] = EQUIPMENT_SLOT_TABARD
;
6360 case INVTYPE_WEAPONMAINHAND
:
6361 slots
[0] = EQUIPMENT_SLOT_MAINHAND
;
6363 case INVTYPE_WEAPONOFFHAND
:
6364 slots
[0] = EQUIPMENT_SLOT_OFFHAND
;
6366 case INVTYPE_HOLDABLE
:
6367 slots
[0] = EQUIPMENT_SLOT_OFFHAND
;
6369 case INVTYPE_THROWN
:
6370 slots
[0] = EQUIPMENT_SLOT_RANGED
;
6372 case INVTYPE_RANGEDRIGHT
:
6373 slots
[0] = EQUIPMENT_SLOT_RANGED
;
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
;
6382 slots
[0] = EQUIPMENT_SLOT_RANGED
;
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
)
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
] ) )
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
)
6420 Item
* Player::CreateItem( uint32 item
, uint32 count
) const
6422 ItemPrototype
const *pProto
= objmgr
.GetItemPrototype( item
);
6425 Item
*pItem
= NewItemOrBag( pProto
);
6426 if ( count
> pProto
->Stackable
)
6427 count
= pProto
->Stackable
;
6430 if( pItem
->Create(objmgr
.GenerateLowGuid(HIGHGUID_ITEM
), item
, const_cast<Player
*>(this)) )
6432 pItem
->SetCount( count
);
6441 uint32
Player::GetItemCount( uint32 item
) const
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();
6452 for(int i
= INVENTORY_SLOT_BAG_START
; i
< INVENTORY_SLOT_BAG_END
; i
++)
6454 pBag
= (Bag
*)GetItemByPos( INVENTORY_SLOT_BAG_0
, i
);
6456 count
+= pBag
->GetItemCount(item
);
6461 uint32
Player::GetBankItemCount( uint32 item
) const
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();
6472 for(int i
= BANK_SLOT_BAG_START
; i
< BANK_SLOT_BAG_END
; i
++)
6474 pBag
= (Bag
*)GetItemByPos( INVENTORY_SLOT_BAG_0
, i
);
6476 count
+= pBag
->GetItemCount(item
);
6481 uint16
Player::GetPosByGuid( uint64 guid
) const
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
)
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
);
6500 pBagProto
= pBag
->GetProto();
6503 for(uint32 j
= 0; j
< pBagProto
->ContainerSlots
; j
++)
6505 pos
= ((i
<< 8) | j
);
6506 pItem
= GetItemByPos( pos
);
6507 if( pItem
&& pItem
->GetGUID() == guid
)
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
);
6519 pBagProto
= pBag
->GetProto();
6522 for(uint32 j
= 0; j
< pBagProto
->ContainerSlots
; j
++)
6524 pos
= ((i
<< 8) | j
);
6525 pItem
= GetItemByPos( pos
);
6526 if( pItem
&& pItem
->GetGUID() == guid
)
6533 // In this case GUID is trade slot (enchanting fix)
6534 if (7 > guid
&& GetTrader())
6536 Item
*item
= GetItemByPos(tradeItems
[guid
]);
6538 return GetPosByGuid(item
->GetGUID());
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
);
6560 return pBag
->GetItemByPos(slot
);
6565 bool Player::HasBankBagSlot( uint8 slot
) const
6567 uint32 maxslot
= ((GetUInt32Value(PLAYER_BYTES_2
) & 0x70000) >> 16) + BANK_SLOT_BAG_START
;
6568 if( slot
< maxslot
)
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
)
6579 if( bag
== INVENTORY_SLOT_BAG_0
&& ( slot
>= INVENTORY_SLOT_ITEM_START
&& slot
< INVENTORY_SLOT_ITEM_END
) )
6581 if( bag
>= INVENTORY_SLOT_BAG_START
&& bag
< INVENTORY_SLOT_BAG_END
)
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
) )
6592 if( bag
== INVENTORY_SLOT_BAG_0
&& ( slot
>= INVENTORY_SLOT_BAG_START
&& slot
< INVENTORY_SLOT_BAG_END
) )
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
) )
6603 if( bag
== INVENTORY_SLOT_BAG_0
&& ( slot
>= BANK_SLOT_BAG_START
&& slot
< BANK_SLOT_BAG_END
) )
6605 if( bag
>= BANK_SLOT_BAG_START
&& bag
< BANK_SLOT_BAG_END
)
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
) )
6616 if( bag
== INVENTORY_SLOT_BAG_0
&& ( slot
>= BANK_SLOT_BAG_START
&& slot
< BANK_SLOT_BAG_END
) )
6621 bool Player::HasItemCount( uint32 item
, uint32 count
) const
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
)
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
);
6642 pBagProto
= pBag
->GetProto();
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
)
6661 uint8
Player::CanStoreNewItem( uint8 bag
, uint8 slot
, uint16
&dest
, uint32 item
, uint32 count
, bool swap
) const
6664 Item
*pItem
= CreateItem( item
, count
);
6667 uint8 result
= CanStoreItem( bag
, slot
, dest
, pItem
, swap
);
6672 return EQUIP_ERR_ITEM_NOT_FOUND
;
6674 return EQUIP_ERR_ITEMS_CANT_BE_SWAPPED
;
6677 uint8
Player::CanStoreItem( uint8 bag
, uint8 slot
, uint16
&dest
, Item
*pItem
, bool swap
) const
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();
6688 ItemPrototype
const *pBagProto
;
6690 if(pItem
->IsBindedNotWith(GetGUID()))
6691 return EQUIP_ERR_DONT_OWN_THAT_ITEM
;
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
);
6715 pBagProto
= pBag
->GetProto();
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
);
6738 pBagProto
= pBag
->GetProto();
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
)
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
);
6776 pBagProto
= pBag
->GetProto();
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
)
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
);
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
);
6812 dest
= ( (i
<< 8) | j
);
6813 return EQUIP_ERR_OK
;
6822 for(int i
= INVENTORY_SLOT_ITEM_START
; i
< INVENTORY_SLOT_ITEM_END
; i
++)
6824 pItem2
= GetItemByPos( INVENTORY_SLOT_BAG_0
, i
);
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
);
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
);
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
;
6882 pBag
= (Bag
*)GetItemByPos( INVENTORY_SLOT_BAG_0
, bag
);
6885 pBagProto
= pBag
->GetProto();
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
);
6908 dest
= ( (INVENTORY_SLOT_BAG_0
<< 8) | i
);
6909 return EQUIP_ERR_OK
;
6915 pBag
= (Bag
*)GetItemByPos( INVENTORY_SLOT_BAG_0
, bag
);
6918 pBagProto
= pBag
->GetProto();
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
);
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
;
6956 return EQUIP_ERR_COULDNT_SPLIT_ITEMS
;
6960 if( bag
== INVENTORY_SLOT_BAG_0
)
6962 dest
= ( (bag
<< 8) | slot
);
6963 return EQUIP_ERR_OK
;
6967 pBag
= (Bag
*)GetItemByPos( INVENTORY_SLOT_BAG_0
, bag
);
6970 pBagProto
= pBag
->GetProto();
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
;
6988 return EQUIP_ERR_ITEM_NOT_FOUND
;
6990 return EQUIP_ERR_ITEMS_CANT_BE_SWAPPED
;
6994 uint8
Player::CanEquipItem( uint8 slot
, uint16
&dest
, Item
*pItem
, bool swap
, bool check_alive
) const
6999 sLog
.outDebug( "STORAGE: CanEquipItem slot = %u, item = %u, count = %u", slot
, pItem
->GetEntry(), pItem
->GetCount());
7000 ItemPrototype
const *pProto
= pItem
->GetProto();
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
)
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
)
7023 return EQUIP_ERR_CANT_DUAL_WIELD
;
7026 Item
*mainItem
= GetItemByPos( INVENTORY_SLOT_BAG_0
, EQUIPMENT_SLOT_MAINHAND
);
7029 if(mainItem
->GetProto()->InventoryType
== INVTYPE_2HWEAPON
)
7030 return EQUIP_ERR_CANT_EQUIP_WITH_TWOHANDED
;
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
);
7042 return EQUIP_ERR_ITEM_CANT_BE_EQUIPPED
;
7044 dest
= ((INVENTORY_SLOT_BAG_0
<< 8) | eslot
);
7045 return EQUIP_ERR_OK
;
7049 return EQUIP_ERR_ITEM_NOT_FOUND
;
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
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();
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)
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
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();
7103 ItemPrototype
const *pBagProto
;
7105 if( pItem
->IsBindedNotWith(GetGUID()) )
7106 return EQUIP_ERR_DONT_OWN_THAT_ITEM
;
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
);
7129 pBagProto
= pBag
->GetProto();
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
);
7152 pBagProto
= pBag
->GetProto();
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
)
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
);
7188 pBagProto
= pBag
->GetProto();
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
)
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
);
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
);
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
);
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
);
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
);
7252 dest
= ( (i
<< 8) | j
);
7253 return EQUIP_ERR_OK
;
7259 return EQUIP_ERR_BANK_FULL
;
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
;
7287 pBag
= (Bag
*)GetItemByPos( INVENTORY_SLOT_BAG_0
, bag
);
7290 pBagProto
= pBag
->GetProto();
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
);
7313 dest
= ( (INVENTORY_SLOT_BAG_0
<< 8) | i
);
7314 return EQUIP_ERR_OK
;
7320 pBag
= (Bag
*)GetItemByPos( INVENTORY_SLOT_BAG_0
, bag
);
7323 pBagProto
= pBag
->GetProto();
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
);
7335 dest
= ( (bag
<< 8) | j
);
7336 return EQUIP_ERR_OK
;
7342 return EQUIP_ERR_BAG_FULL
;
7346 if( pProto
->InventoryType
== INVTYPE_BAG
)
7348 Bag
*pBag
= (Bag
*)pItem
;
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
)
7360 if( !pBag
->IsEmpty() )
7361 return EQUIP_ERR_NONEMPTY_BAG_OVER_OTHER_BAG
;
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
;
7379 return EQUIP_ERR_COULDNT_SPLIT_ITEMS
;
7383 if( bag
== INVENTORY_SLOT_BAG_0
)
7385 dest
= ( (bag
<< 8) | slot
);
7386 return EQUIP_ERR_OK
;
7390 pBag
= (Bag
*)GetItemByPos( INVENTORY_SLOT_BAG_0
, bag
);
7393 pBagProto
= pBag
->GetProto();
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
;
7411 return EQUIP_ERR_ITEM_NOT_FOUND
;
7413 return EQUIP_ERR_ITEMS_CANT_BE_SWAPPED
;
7417 uint8
Player::CanUseItem( Item
*pItem
, bool check_alive
) const
7421 sLog
.outDebug( "STORAGE: CanUseItem item = %u", pItem
->GetEntry());
7422 if( !isAlive() && check_alive
)
7423 return EQUIP_ERR_YOU_ARE_DEAD
;
7425 // return EQUIP_ERR_YOU_ARE_STUNNED;
7426 ItemPrototype
const *pProto
= pItem
->GetProto();
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
7466 if( (pProto
->AllowableClass
& getClassMask()) == 0 || (pProto
->AllowableRace
& getRaceMask()) == 0 )
7468 if( pProto
->RequiredSkill
!= 0 )
7470 if( GetSkillValue( pProto
->RequiredSkill
) == 0 )
7472 else if( GetSkillValue( pProto
->RequiredSkill
) < pProto
->RequiredSkillRank
)
7475 if( pProto
->RequiredSpell
!= 0 && !HasSpell( pProto
->RequiredSpell
) )
7477 if( GetHonorRank() < pProto
->RequiredHonorRank
)
7479 if( getLevel() < pProto
->RequiredLevel
)
7486 uint8
Player::CanUseAmmo( uint32 item
) const
7488 sLog
.outDebug( "STORAGE: CanUseAmmo item = %u", item
);
7490 return EQUIP_ERR_YOU_ARE_DEAD
;
7492 // return EQUIP_ERR_YOU_ARE_STUNNED;
7493 ItemPrototype
const *pProto
= objmgr
.GetItemPrototype( item
);
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
);
7527 ItemPrototype
const *pProto
= pItem
->GetProto();
7528 ItemAddedQuestCheck( item
, count
);
7530 pItem
->SetItemRandomProperties();
7531 Item
* retItem
= StoreItem( pos
, pItem
, update
);
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
)
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
);
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);
7575 Bag
*pBag
= (Bag
*)GetItemByPos( INVENTORY_SLOT_BAG_0
, bag
);
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);
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);
7611 void Player::EquipItem( uint16 pos
, Item
*pItem
, bool update
)
7615 VisualizeItem( pos
, pItem
);
7616 uint8 slot
= pos
& 255;
7619 _ApplyItemMods(pItem
, slot
, true);
7621 if( IsInWorld() && update
)
7623 pItem
->AddToWorld();
7624 pItem
->SendUpdateToPlayer( this );
7629 void Player::QuickEquipItem( uint16 pos
, Item
*pItem
)
7633 VisualizeItem( pos
, pItem
);
7637 pItem
->AddToWorld();
7638 pItem
->SendUpdateToPlayer( this );
7643 void Player::VisualizeItem( uint16 pos
, Item
*pItem
)
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
);
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);
7716 Bag
*pBag
= (Bag
*)GetItemByPos( INVENTORY_SLOT_BAG_0
, bag
);
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
);
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
)
7748 pItem
->SetCount( pItem
->GetCount() - count
+ remcount
);
7749 if( IsInWorld() && update
)
7750 pItem
->SendUpdateToPlayer( this );
7751 pItem
->SetState(ITEM_CHANGED
, this);
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
);
7763 pBagProto
= pBag
->GetProto();
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
)
7781 pItem
->SetCount( pItem
->GetCount() - count
+ remcount
);
7782 if( IsInWorld() && update
)
7783 pItem
->SendUpdateToPlayer( this );
7784 pItem
->SetState(ITEM_CHANGED
, this);
7794 void Player::DestroyItem( uint8 bag
, uint8 slot
, bool update
)
7796 Item
*pItem
= GetItemByPos( bag
, slot
);
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
++);
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);
7831 SpellItemEnchantmentEntry
*pEnchant
= sSpellItemEnchantmentStore
.LookupEntry(Enchant_id
);
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
);
7850 RemoveAurasDueToSpell(enchant_spell_id
);
7856 m_items
[slot
] = NULL
;
7858 if( IsInWorld() && update
)
7860 pItem
->RemoveFromWorld();
7861 pItem
->DestroyForPlayer( this );
7866 Bag
*pBag
= (Bag
*)GetItemByPos( INVENTORY_SLOT_BAG_0
, bag
);
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
);
7889 ItemPrototype
const *pProto
;
7890 uint32 remcount
= 0;
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
)
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);
7919 // in inventory bags
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
);
7927 pBagProto
= pBag
->GetProto();
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
)
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);
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
)
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);
7987 void Player::DestroyItemCount( Item
* pItem
, uint32
&count
, bool update
)
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
);
8003 ItemPrototype
const* pProto
= pItem
->GetProto();
8004 ItemRemovedQuestCheck( pItem
->GetEntry(), count
);
8005 pItem
->SetCount( pItem
->GetCount() - count
);
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
);
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
);
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
);
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
);
8044 if( IsInventoryPos( dst
) )
8046 msg
= CanStoreItem( dstbag
, dstslot
, dest
, pNewItem
, false );
8047 if( msg
== EQUIP_ERR_OK
)
8049 pSrcItem
->SetCount( pSrcItem
->GetCount() - count
);
8051 pSrcItem
->SendUpdateToPlayer( this );
8052 pSrcItem
->SetState(ITEM_CHANGED
, this);
8053 StoreItem( dest
, pNewItem
, true);
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
);
8068 pSrcItem
->SendUpdateToPlayer( this );
8069 pSrcItem
->SetState(ITEM_CHANGED
, this);
8070 BankItem( dest
, pNewItem
, true);
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
);
8085 pSrcItem
->SendUpdateToPlayer( this );
8086 pSrcItem
->SetState(ITEM_CHANGED
, this);
8087 EquipItem( dest
, pNewItem
, true);
8092 SendEquipError( msg
, pSrcItem
, NULL
);
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
);
8114 sLog
.outDebug( "STORAGE: SwapItem bag = %u, slot = %u, item = %u", dstbag
, dstslot
, pSrcItem
->GetEntry());
8118 SendEquipError( EQUIP_ERR_YOU_ARE_DEAD
, pSrcItem
, pDstItem
);
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
);
8133 if( srcslot
== dstbag
)
8135 SendEquipError( EQUIP_ERR_NONEMPTY_BAG_OVER_OTHER_BAG
, pSrcItem
, 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);
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);
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);
8177 SendEquipError( msg
, pSrcItem
, NULL
);
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);
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);
8199 pSrcItem
->SendUpdateToPlayer( this );
8200 pDstItem
->SendUpdateToPlayer( this );
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);
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);
8223 pSrcItem
->SendUpdateToPlayer( this );
8224 pDstItem
->SendUpdateToPlayer( this );
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);
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);
8247 pSrcItem
->SendUpdateToPlayer( this );
8248 pDstItem
->SendUpdateToPlayer( this );
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
)
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
);
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
);
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
);
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);
8315 SendEquipError( msg
, pSrcItem
, pDstItem
);
8321 void Player::AddItemToBuyBackSlot( Item
*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
)
8335 if(!m_buybackitems
[i
])
8337 slot
= BUYBACK_SLOT_START
+i
;
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
;
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();
8365 SetUInt32Value( PLAYER_FIELD_BUYBACK_PRICE_1
+ eslot
, pProto
->SellPrice
* pItem
->GetCount() );
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
];
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
];
8393 pItem
->RemoveFromWorld();
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" );
8413 data
.Initialize( SMSG_INVENTORY_CHANGE_FAILURE
);
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));
8420 GetSession()->SendPacket(&data
);
8423 void Player::SendBuyError( uint8 msg
, Creature
* pCreature
, uint32 item
, uint32 param
)
8425 sLog
.outDetail( "WORLD: Sent SMSG_BUY_FAILED" );
8427 data
.Initialize( SMSG_BUY_FAILED
);
8428 data
<< (pCreature
? pCreature
->GetGUID() : uint64(0));
8433 GetSession()->SendPacket(&data
);
8436 void Player::SendSellError( uint8 msg
, Creature
* pCreature
, uint64 guid
, uint32 param
)
8438 sLog
.outDetail( "WORLD: Sent SMSG_SELL_ITEM" );
8440 data
.Initialize( SMSG_SELL_ITEM
);
8441 data
<< (pCreature
? pCreature
->GetGUID() : uint64(0));
8446 GetSession()->SendPacket(&data
);
8449 void Player::ClearTrade()
8452 acceptTrade
= false;
8453 for(int i
=0; i
<7; i
++)
8454 tradeItems
[i
] = NULL_SLOT
;
8457 void Player::TradeCancel(bool sendback
)
8461 // prevent loop cancel message (already processed)
8463 pTrader
->pTrader
= NULL
;
8465 WorldSession
* ws
= pTrader
->GetSession();
8467 ws
->SendCancelTrade();
8472 void Player::UpdateEnchantTime(uint32 time
)
8474 for(std::list
<struct EnchantDuration
*>::iterator itr
= m_enchantDuration
.begin(),next
;itr
!= m_enchantDuration
.end();itr
=next
)
8482 if(!(*itr
)->item
->GetUInt32Value(ITEM_FIELD_ENCHANTMENT
+(*itr
)->slot
*3))
8485 m_enchantDuration
.erase(itr
);
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);
8494 m_enchantDuration
.erase(itr
);
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
)
8511 for(std::list
<struct EnchantDuration
*>::iterator itr
= m_enchantDuration
.begin(),next
;itr
!= m_enchantDuration
.end();itr
=next
)
8519 if((*itr
)->item
== item
&& (*itr
)->slot
== slot
)
8522 m_enchantDuration
.erase(itr
);
8528 if(item
&& duration
> 0 )
8530 GetSession()->SendItemEnchantTimeUpdate(item
->GetGUID(),slot
,uint32(duration
/1000));
8531 EnchantDuration
*ed
= new EnchantDuration();
8533 ed
->leftduration
= duration
;
8535 m_enchantDuration
.push_back(ed
);
8539 void Player::ReducePoisonCharges(uint32 enchantId
)
8543 uint32 pEnchantId
= 0;
8548 for(int i
= EQUIPMENT_SLOT_MAINHAND
; i
< EQUIPMENT_SLOT_RANGED
; i
++)
8550 pos
= ((INVENTORY_SLOT_BAG_0
<< 8) | i
);
8552 pItem
= GetItemByPos( pos
);
8555 for(int x
=0;x
<7;x
++)
8557 charges
= pItem
->GetUInt32Value(ITEM_FIELD_ENCHANTMENT
+x
*3+2);
8562 AddItemEnchant(pItem
,enchantId
,false);
8563 for(int y
=0;y
<3;y
++)
8564 pItem
->SetUInt32Value(ITEM_FIELD_ENCHANTMENT
+x
*3+y
,0);
8569 pItem
->SetUInt32Value(ITEM_FIELD_ENCHANTMENT
+x
*3+2,charges
-1);
8576 void Player::SaveEnchant()
8578 uint32 duration
= 0;
8580 for(std::list
<struct EnchantDuration
*>::iterator itr
= m_enchantDuration
.begin();itr
!= m_enchantDuration
.end();itr
++)
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;
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
);
8609 if(pItem
->GetProto()->Class
!= ITEM_CLASS_WEAPON
&& pItem
->GetProto()->Class
!= ITEM_CLASS_ARMOR
)
8611 for(int x
=0;x
<7;x
++)
8613 duration
= pItem
->GetUInt32Value(ITEM_FIELD_ENCHANTMENT
+x
*3+1);
8616 else if( duration
> 0 )
8617 AddEnchantDuration(pItem
,x
,duration
);
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
);
8628 pBagProto
= pBag
->GetProto();
8631 for(uint32 j
= 0; j
< pBagProto
->ContainerSlots
; j
++)
8633 pos
= ((i
<< 8) | j
);
8634 pItem
= GetItemByPos( pos
);
8637 if(pItem
->GetProto()->Class
!= ITEM_CLASS_WEAPON
&& pItem
->GetProto()->Class
!= ITEM_CLASS_ARMOR
)
8639 for(int x
=0;x
<7;x
++)
8641 duration
= pItem
->GetUInt32Value(ITEM_FIELD_ENCHANTMENT
+x
*3+1);
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
);
8657 pBagProto
= pBag
->GetProto();
8660 for(uint32 j
= 0; j
< pBagProto
->ContainerSlots
; j
++)
8662 pos
= ((i
<< 8) | j
);
8663 pItem
= GetItemByPos( pos
);
8666 if(pItem
->GetProto()->Class
!= ITEM_CLASS_WEAPON
&& pItem
->GetProto()->Class
!= ITEM_CLASS_ARMOR
)
8668 for(int x
=0;x
<7;x
++)
8670 duration
= pItem
->GetUInt32Value(ITEM_FIELD_ENCHANTMENT
+x
*3+1);
8673 else if( duration
> 0 )
8674 AddEnchantDuration(pItem
,x
,duration
);
8683 /*********************************************************/
8684 /*** QUEST SYSTEM ***/
8685 /*********************************************************/
8687 void Player::PrepareQuestMenu( uint64 guid
)
8690 Creature
*pCreature
= ObjectAccessor::Instance().GetCreature(*this, guid
);
8692 pObject
= (Object
*)pCreature
;
8695 GameObject
*pGameObject
= ObjectAccessor::Instance().GetGameObject(*this, guid
);
8697 pObject
= (Object
*)pGameObject
;
8702 QuestMenu
*qm
= PlayerTalkClass
->GetQuestMenu();
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 )
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
];
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 );
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);
8759 PlayerTalkClass
->SendQuestGiverRequestItems( pQuest
, guid
, CanCompleteQuest(quest_id
), true);
8763 PlayerTalkClass
->SendQuestGiverQuestDetails( pQuest
, guid
, true );
8773 std::string title
= "";
8774 Creature
*pCreature
= ObjectAccessor::Instance().GetCreature(*this, guid
);
8777 uint32 textid
= pCreature
->GetNpcTextId();
8778 GossipText
* gossiptext
= objmgr
.GetGossipText(textid
);
8781 qe
._Delay
= 0; //TEXTEMOTE_MESSAGE; //zyg: player emote
8782 qe
._Emote
= 0; //TEXTEMOTE_HELLO; //zyg: NPC emote
8787 qe
= gossiptext
->Options
[0].Emotes
[0];
8788 title
= gossiptext
->Options
[0].Text_0
;
8789 if( &title
== NULL
)
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
)
8809 Creature
*pCreature
= ObjectAccessor::Instance().GetCreature(*this, guid
);
8812 pObject
= (Object
*)pCreature
;
8816 GameObject
*pGameObject
= ObjectAccessor::Instance().GetGameObject(*this, guid
);
8818 pObject
= (Object
*)pGameObject
;
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
];
8833 bool Player::CanSeeStartQuest( uint32 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() );
8845 bool Player::CanTakeQuest( Quest
*pQuest
, bool msg
)
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
) );
8859 bool Player::CanAddQuest( Quest
*pQuest
, bool msg
)
8863 if(!GetQuestSlot( 0 ))
8866 if( !SatisfyQuestLog( msg
) )
8869 uint32 srcitem
= pQuest
->GetSrcItemId();
8872 uint32 count
= pQuest
->GetSrcItemCount();
8876 uint8 msg
= CanStoreNewItem( NULL_BAG
, NULL_SLOT
, dest
, srcitem
, count
, false );
8877 if( msg
!= EQUIP_ERR_OK
)
8879 SendEquipError( msg
, NULL
, NULL
);
8888 bool Player::CanCompleteQuest( uint32 quest_id
)
8892 QuestStatus qStatus
= mQuestStatus
[quest_id
].m_status
;
8893 if( qStatus
== QUEST_STATUS_COMPLETE
)
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])
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 )
8921 if( qInfo
->ReqCreatureOrGOCount
[i
] != 0 && mQuestStatus
[quest_id
].m_creatureOrGOcount
[i
] < qInfo
->ReqCreatureOrGOCount
[i
] )
8926 if ( qInfo
->HasSpecialFlag( QUEST_SPECIAL_FLAGS_EXPLORATION
) && !mQuestStatus
[quest_id
].m_explored
)
8929 if ( qInfo
->HasSpecialFlag( QUEST_SPECIAL_FLAGS_TIMED
) && mQuestStatus
[quest_id
].m_timer
== 0 )
8932 if ( qInfo
->GetRewOrReqMoney() < 0 )
8934 if ( int32(GetMoney()) < -qInfo
->GetRewOrReqMoney() )
8943 bool Player::CanRewardQuest( Quest
*pQuest
, bool msg
)
8947 // auto complete quest, return true (maybe need a better check)
8948 if ((strlen(pQuest
->GetObjectives()) == 0) && CanTakeQuest(pQuest
, false))
8951 // not completed quest (only cheating case, then ignore without message)
8952 if(GetQuestStatus(pQuest
->GetQuestId()) != QUEST_STATUS_COMPLETE
)
8955 // rewarded and not repeatable quest (only cheating case, then ignore without message)
8956 if(GetQuestRewardStatus(pQuest
->GetQuestId()) && !pQuest
->HasSpecialFlag(QUEST_SPECIAL_FLAGS_REPEATABLE
))
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
] )
8968 SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND
, NULL
, NULL
);
8979 bool Player::CanRewardQuest( Quest
*pQuest
, uint32 reward
, bool msg
)
8983 // prevent recive reward with quest items in bank or for not completed quest
8984 if(!CanRewardQuest(pQuest
,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
);
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
);
9023 void Player::AddQuest( Quest
*pQuest
)
9027 uint16 log_slot
= GetQuestSlot( 0 );
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
);
9064 mQuestStatus
[quest_id
].m_timer
= 0;
9065 SetUInt32Value( log_slot
+ 2, 0 );
9070 void Player::CompleteQuest( uint32 quest_id
)
9074 SetQuestStatus( quest_id
, QUEST_STATUS_COMPLETE
);
9076 uint16 log_slot
= GetQuestSlot( quest_id
);
9079 uint32 state
= GetUInt32Value( log_slot
+ 1 );
9081 SetUInt32Value( log_slot
+ 1, state
);
9084 SendQuestComplete( quest_id
);
9088 void Player::IncompleteQuest( uint32 quest_id
)
9092 SetQuestStatus( quest_id
, QUEST_STATUS_INCOMPLETE
);
9094 uint16 log_slot
= GetQuestSlot( quest_id
);
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
)
9108 uint32 quest_id
= pQuest
->GetQuestId();
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
);
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
);
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;
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
)
9184 IncompleteQuest( quest_id
);
9186 uint16 log_slot
= GetQuestSlot( quest_id
);
9189 SetUInt32Value( log_slot
+ 2, 1 );
9191 uint32 state
= GetUInt32Value( log_slot
+ 1 );
9193 SetUInt32Value( log_slot
+ 1, state
);
9195 SendQuestFailed( quest_id
);
9199 void Player::FailTimedQuest( uint32 quest_id
)
9203 mQuestStatus
[quest_id
].m_timer
= 0;
9205 IncompleteQuest( quest_id
);
9207 uint16 log_slot
= GetQuestSlot( quest_id
);
9210 SetUInt32Value( log_slot
+ 2, 1 );
9212 uint32 state
= GetUInt32Value( log_slot
+ 1 );
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
];
9225 uint32 reqclasses
= qInfo
->GetRequiredClass();
9226 if ( reqclasses
== 0 )
9228 if( (reqclasses
& getClassMask()) == 0 )
9231 SendCanTakeQuestResponse( INVALIDREASON_DONT_HAVE_REQ
);
9240 bool Player::SatisfyQuestLevel( uint32 quest_id
, bool msg
)
9242 Quest
* qInfo
= objmgr
.QuestTemplates
[quest_id
];
9245 if( getLevel() < qInfo
->GetMinLevel() )
9248 SendCanTakeQuestResponse( INVALIDREASON_DONT_HAVE_REQ
);
9256 bool Player::SatisfyQuestLog( bool msg
)
9258 uint16 log_slot
= GetQuestSlot( 0 );
9266 data
.Initialize( SMSG_QUESTLOG_FULL
);
9267 GetSession()->SendPacket( &data
);
9268 sLog
.outDebug( "WORLD: Sent QUEST_LOG_FULL_MESSAGE" );
9274 bool Player::SatisfyQuestPreviousQuest( uint32 quest_id
, bool msg
)
9278 Quest
* qInfo
= objmgr
.QuestTemplates
[quest_id
];
9280 // No previous quest (might be first quest in a series)
9281 if( qInfo
->prevQuests
.size() == 0)
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
)
9295 // Have only prev. quests in non-rewarded state
9297 SendCanTakeQuestResponse( INVALIDREASON_DONT_HAVE_REQ
);
9302 bool Player::SatisfyQuestHaveQuest( uint32 quest_id
, bool msg
)
9304 Quest
* qInfo
= objmgr
.QuestTemplates
[quest_id
];
9308 if (!qInfo
->GetHaveQuestId())
9311 StatusMap::iterator iter
= mQuestStatus
.find(qInfo
->GetHaveQuestId());
9312 if (iter
== mQuestStatus
.end())
9315 if (iter
->second
.m_status
== QUEST_STATUS_NONE
)
9321 bool Player::SatisfyQuestRace( uint32 quest_id
, bool msg
)
9323 Quest
* qInfo
= objmgr
.QuestTemplates
[quest_id
];
9326 uint32 reqraces
= qInfo
->GetRequiredRaces();
9327 if ( reqraces
== 0 )
9329 if( (reqraces
& getRaceMask()) == 0 )
9332 SendCanTakeQuestResponse( INVALIDREASON_DONT_HAVE_RACE
);
9340 bool Player::SatisfyQuestReputation( uint32 quest_id
, bool msg
)
9342 Quest
* qInfo
= objmgr
.QuestTemplates
[quest_id
];
9345 uint32 faction_id
= qInfo
->GetRequiredRepFaction();
9349 return GetStanding(faction_id
) >= qInfo
->GetRequiredRepValue();
9354 bool Player::SatisfyQuestSkill( uint32 quest_id
, bool msg
)
9356 Quest
* qInfo
= objmgr
.QuestTemplates
[quest_id
];
9359 uint32 reqskill
= qInfo
->GetRequiredSkill();
9360 if( reqskill
== QUEST_TRSKILL_NONE
)
9362 if( GetSkillValue( reqskill
) < qInfo
->GetRequiredSkillValue() )
9365 SendCanTakeQuestResponse( INVALIDREASON_DONT_HAVE_REQ
);
9373 bool Player::SatisfyQuestStatus( uint32 quest_id
, bool msg
)
9377 StatusMap::iterator itr
= mQuestStatus
.find( quest_id
);
9378 if ( itr
!= mQuestStatus
.end() && itr
->second
.m_status
!= QUEST_STATUS_NONE
)
9381 SendCanTakeQuestResponse( INVALIDREASON_HAVE_QUEST
);
9389 bool Player::SatisfyQuestTimed( uint32 quest_id
, bool msg
)
9391 Quest
* qInfo
= objmgr
.QuestTemplates
[quest_id
];
9394 if ( (find(m_timedquests
.begin(), m_timedquests
.end(), quest_id
) != m_timedquests
.end()) && qInfo
->HasSpecialFlag(QUEST_SPECIAL_FLAGS_TIMED
) )
9397 SendCanTakeQuestResponse( INVALIDREASON_HAVE_TIMED_QUEST
);
9405 bool Player::SatisfyQuestExclusiveGroup( uint32 quest_id
, bool msg
)
9407 Quest
* qInfo
= objmgr
.QuestTemplates
[quest_id
];
9410 if(!qInfo
->GetExclusiveGroup())
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
)
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
) )
9438 bool Player::GiveQuestSourceItem( uint32 quest_id
)
9440 Quest
* qInfo
= objmgr
.QuestTemplates
[quest_id
];
9444 uint32 srcitem
= qInfo
->GetSrcItemId();
9448 uint32 count
= qInfo
->GetSrcItemCount();
9451 uint8 msg
= CanStoreNewItem( NULL_BAG
, NULL_SLOT
, dest
, srcitem
, count
, false );
9452 if( msg
== EQUIP_ERR_OK
)
9454 StoreNewItem(dest
, srcitem
, count
, true);
9458 SendEquipError( msg
, NULL
, NULL
);
9465 void Player::TakeQuestSourceItem( uint32 quest_id
)
9467 Quest
* qInfo
= objmgr
.QuestTemplates
[quest_id
];
9470 uint32 srcitem
= qInfo
->GetSrcItemId();
9473 uint32 count
= qInfo
->GetSrcItemCount();
9476 DestroyItemCount(srcitem
, count
, true);
9481 bool Player::GetQuestRewardStatus( uint32 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
;
9494 uint32
Player::GetQuestStatus( uint32 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
];
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
];
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
;
9550 void Player::AreaExplored( uint32 questId
)
9554 uint16 log_slot
= GetQuestSlot( questId
);
9557 mQuestStatus
[questId
].m_explored
= true;
9559 if( CanCompleteQuest( questId
) )
9560 CompleteQuest( questId
);
9564 void Player::ItemAddedQuestCheck( uint32 entry
, uint32 count
)
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
);
9602 void Player::ItemRemovedQuestCheck( uint32 entry
, uint32 count
)
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
];
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
];
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
);
9641 void Player::KilledMonster( uint32 entry
, uint64 guid
)
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
);
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)
9666 // skip Cast at creature objective
9667 if(qInfo
->ReqSpell
[j
] !=0 )
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
);
9691 void Player::CastedCreatureOrGO( uint32 entry
, uint64 guid
, uint32 spell_id
)
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
);
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
)
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
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
);
9751 void Player::MoneyChanged( uint32 count
)
9754 for( int i
= 0; i
< MAX_QUEST_LOG_SIZE
; i
++ )
9756 questid
= GetUInt32Value(PLAYER_QUEST_LOG_1_1
+ 3*i
);
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
] )
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
])
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
])
9821 void Player::SendQuestComplete( uint32 quest_id
)
9826 data
.Initialize( SMSG_QUESTUPDATE_COMPLETE
);
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
)
9837 uint32 questid
= pQuest
->GetQuestId();
9838 sLog
.outDebug( "WORLD: Sent SMSG_QUESTGIVER_QUEST_COMPLETE quest = %u", questid
);
9840 data
.Initialize( SMSG_QUESTGIVER_QUEST_COMPLETE
);
9842 data
<< uint32(0x03);
9844 if ( getLevel() < sWorld
.getConfig(CONFIG_MAX_PLAYER_LEVEL
) )
9847 data
<< uint32(pQuest
->GetRewOrReqMoney());
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())
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)
9878 sa
.source
= questGiver
;
9879 sa
.script
= &iter
->second
;
9881 sWorld
.scriptSchedule
.insert(pair
<uint64
, ScriptAction
>(0, sa
));
9887 sa
.source
= questGiver
;
9888 sa
.script
= &iter
->second
;
9890 sWorld
.scriptSchedule
.insert(pair
<uint64
, ScriptAction
>(sWorld
.internalGameTime
+ iter
->first
, sa
));
9894 sWorld
.ScriptsProcess();
9899 void Player::SendQuestFailed( uint32 quest_id
)
9904 data
.Initialize( SMSG_QUESTGIVER_QUEST_FAILED
);
9906 GetSession()->SendPacket( &data
);
9907 sLog
.outDebug("WORLD: Sent SMSG_QUESTGIVER_QUEST_FAILED");
9911 void Player::SendQuestTimerFailed( uint32 quest_id
)
9916 data
.Initialize( SMSG_QUESTUPDATE_FAILEDTIMER
);
9918 GetSession()->SendPacket( &data
);
9919 sLog
.outDebug("WORLD: Sent SMSG_QUESTUPDATE_FAILEDTIMER");
9923 void Player::SendCanTakeQuestResponse( uint32 msg
)
9926 data
.Initialize( SMSG_QUESTGIVER_QUEST_INVALID
);
9928 GetSession()->SendPacket( &data
);
9929 sLog
.outDebug("WORLD: Sent SMSG_QUESTGIVER_QUEST_INVALID");
9932 void Player::SendPushToPartyResponse( Player
*pPlayer
, uint32 msg
)
9937 data
.Initialize( MSG_QUEST_PUSH_RESULT
);
9938 data
<< pPlayer
->GetGUID();
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
)
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
];
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
];
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
];
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
);
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
));
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
++)
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
);
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();
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() );
10041 Field
*fields
= result
->Fetch();
10043 data
= StrSplit(fields
[0].GetString(), " ");
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
)
10058 uint32 temp
= Player::GetUInt32ValueFromArray(data
,index
);
10059 memcpy(&result
, &temp
, sizeof(result
));
10064 uint32
Player::GetUInt32ValueFromDB(uint16 index
, uint64 guid
)
10066 vector
<string
> data
;
10067 if(!LoadValuesArrayFromDB(data
,guid
))
10070 return GetUInt32ValueFromArray(data
,index
);
10073 float Player::GetFloatValueFromDB(uint16 index
, uint64 guid
)
10076 uint32 temp
= Player::GetUInt32ValueFromDB(index
, guid
);
10077 memcpy(&result
, &temp
, sizeof(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
);
10089 sLog
.outError("ERROR: Player (GUID: %u) not found in table `character`, can't load. ",guid
);
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
));
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);
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());
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
);
10133 m_class
= fields
[6].GetUInt8();
10135 PlayerInfo
const *info
= objmgr
.GetPlayerInfo(m_race
, m_class
);
10138 sLog
.outError("Player have incorrect race/class pair. Can't be loaded.");
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() );
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
10227 //mails are loaded only when needed ;-) - when player in game click on mailbox.
10230 _LoadAuras(time_diff
);
10232 _LoadSpells(time_diff
);
10234 _LoadQuestStatus();
10238 _LoadInventory(time_diff
);
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());
10257 void Player::_LoadActions()
10262 QueryResult
*result
= sDatabase
.PQuery("SELECT `button`,`action`,`type`,`misc` FROM `character_action` WHERE `guid` = '%u' ORDER BY `button`",GetGUIDLow());
10268 Field
*fields
= result
->Fetch();
10270 addAction(fields
[0].GetUInt8(), fields
[1].GetUInt16(), fields
[2].GetUInt8(), fields
[3].GetUInt8());
10272 while( result
->NextRow() );
10278 void Player::_LoadAuras(uint32 timediff
)
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());
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
);
10303 sLog
.outError("Unknown aura (spellid %u, effindex %u), ignore.",spellid
,effindex
);
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
);
10320 while( result
->NextRow() );
10325 if(m_class
== CLASS_WARRIOR
)
10326 CastSpell(this,SPELL_PASSIVE_BATTLE_STANCE
,true);
10329 void Player::LoadCorpse()
10331 if(Corpse
* corpse
= GetCorpse())
10335 if( corpse
->GetType() == CORPSE_RESURRECTABLE
)
10336 corpse
->ConvertCorpseToBones();
10339 corpse
->UpdateForPlayer(this,true);
10343 //Prevent Dead Player login without corpse
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());
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
);
10369 sLog
.outError( "Player::_LoadInventory: Player %s have unknown item (id: #%u) in inventory, skipped.", GetName(),item_id
);
10373 Item
*item
= NewItemOrBag(proto
);
10374 item
->SetSlot( slot
);
10375 item
->SetContainer( NULL
);
10377 if(!item
->LoadFromDB(item_guid
, GetGUID()))
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
)
10393 StoreItem(dest
, item
, true);
10395 else if( IsEquipmentPos( dest
) )
10397 if( !CanEquipItem( slot
, dest
, item
, false, false ) == EQUIP_ERR_OK
)
10403 QuickEquipItem(dest
, item
);
10405 else if( IsBankPos( dest
) )
10407 if( !CanBankItem( INVENTORY_SLOT_BAG_0
, slot
, dest
, item
, false, false ) == EQUIP_ERR_OK
)
10413 BankItem(dest
, item
, true);
10416 // item's state may have changed after stored
10417 if (success
) item
->SetState(ITEM_UNCHANGED
, this);
10419 } while (result
->NextRow());
10422 m_itemUpdateQueueBlocked
= false;
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());
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
);
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
);
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
);
10459 while( result
->NextRow() );
10464 void Player::_LoadMail()
10466 time_t base
= time(NULL
);
10468 _LoadMailedItems();
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());
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() );
10496 m_mailsLoaded
= true;
10499 void Player::LoadPet()
10501 uint64 pet_guid
= GetPetGUID();
10504 Creature
* in_pet
= ObjectAccessor::Instance().GetCreature(*this, pet_guid
);
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());
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?
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
);
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;
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() );
10570 void Player::_LoadReputation()
10572 Factions newFaction
;
10576 QueryResult
*result
= sDatabase
.PQuery("SELECT `faction`,`reputation`,`standing`,`flags` FROM `character_reputation` WHERE `guid` = '%u'",GetGUIDLow());
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() );
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
;
10609 QueryResult
*result
= sDatabase
.PQuery("SELECT `spell`,`slot`,`active` FROM `character_spell` WHERE `guid` = '%u'",GetGUIDLow());
10615 Field
*fields
= result
->Fetch();
10617 addSpell(fields
[0].GetUInt16(), fields
[2].GetUInt8(), PLAYERSPELL_UNCHANGED
, fields
[1].GetUInt16());
10619 while( result
->NextRow() );
10625 void Player::_LoadTaxiMask(const char* data
)
10627 vector
<string
> tokens
= StrSplit(data
, " ");
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());
10647 Field
*fields
= result
->Fetch();
10649 for (int iI
=0; iI
<8; iI
++)
10650 m_Tutorials
[iI
] = fields
[iI
].GetUInt32();
10653 while( result
->NextRow() );
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
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());
10696 _RemoveAllItemMods();
10697 _RemoveAllAuraMods();
10700 bool inworld
= IsInWorld();
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() << ", "
10714 << GetSession()->GetAccountId() << ", '"
10719 << m_positionX
<< ", "
10720 << m_positionY
<< ", "
10721 << m_positionZ
<< ", "
10722 << m_orientation
<< ", '";
10725 for( i
= 0; i
< m_valuesCount
; i
++ )
10727 ss
<< GetUInt32Value(i
) << " ";
10732 for( i
= 0; i
< 8; i
++ )
10733 ss
<< m_taximask
[i
] << " ";
10736 inworld
? ss
<< 1: ss
<< 0;
10739 ss
<< m_highest_rank
;
10751 ss
<< m_Played_time
[0];
10753 ss
<< m_Played_time
[1];
10760 ss
<< is_logout_resting
;
10762 ss
<< m_resetTalentsCost
;
10764 ss
<< (uint64
)m_resetTalentsTime
;
10776 ss
<< m_transport
->GetGUIDLow();
10782 sDatabase
.Execute( ss
.str().c_str() );
10786 if(m_mailsUpdated
) //save mails only when needed
10790 _SaveQuestStatus();
10793 _SaveSpellCooldowns();
10799 sLog
.outDebug("Save Basic value of player %s is: ", m_name
.c_str());
10804 _ApplyAllAuraMods();
10805 _ApplyAllItemMods();
10809 SetUInt32Value(UNIT_FIELD_BYTES_1
, tmp_bytes
);
10810 SetUInt32Value(UNIT_FIELD_FLAGS
, tmp_flags
);
10811 SetUInt32Value(PLAYER_FLAGS
, tmp_pflags
);
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();
10837 for (i
= 0; i
< 3; i
++)
10838 if (spellInfo
->EffectApplyAuraName
[i
] == SPELL_AURA_MOD_SHAPESHIFT
||
10839 spellInfo
->EffectApplyAuraName
[i
] == SPELL_AURA_MOD_STEALTH
)
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());
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());
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());
10883 sLog
.outError("Player::_SaveInventory - one or more errors occured save aborted!");
10884 sChatHandler
.SendSysMessage(GetSession(), "Item save failed!");
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())
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());
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());
10905 sDatabase
.PExecute("DELETE FROM `character_inventory` WHERE `item` = '%u'", item
->GetGUIDLow());
10910 m_itemUpdateQueue
.clear();
10913 void Player::_SaveMail()
10915 if (!m_mailsLoaded
)
10918 std::deque
<Mail
*>::iterator itr
;
10919 for (itr
= m_mail
.begin(); itr
!= m_mail
.end(); 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
)
10931 sDatabase
.PExecute("DELETE FROM `item_instance` WHERE `guid` = '%u'", m
->item_guid
);
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
)
10950 continueDeleting
= true;
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
)
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
);
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()))
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()
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
;
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
)
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
))
11085 snprintf(buf
,11,"%u",value
);
11086 tokens
[index
] = buf
;
11088 SaveValuesArrayInDB(tokens
,guid
);
11091 void Player::SetFloatValueInDB(uint16 index
, float value
, uint64 guid
)
11094 memcpy(&temp
, &value
, sizeof(value
));
11095 Player::SetUInt32ValueInDB(index
, temp
, guid
);
11098 inline void Player::SendAttackSwingNotStanding()
11101 data
.Initialize(SMSG_ATTACKSWING_NOTSTANDING
);
11102 GetSession()->SendPacket( &data
);
11105 inline void Player::SendAttackSwingDeadTarget()
11108 data
.Initialize(SMSG_ATTACKSWING_DEADTARGET
);
11109 GetSession()->SendPacket( &data
);
11112 inline void Player::SendAttackSwingCantAttack()
11115 data
.Initialize(SMSG_ATTACKSWING_CANT_ATTACK
);
11116 GetSession()->SendPacket( &data
);
11119 inline void Player::SendAttackSwingCancelAttack()
11122 data
.Initialize(SMSG_CANCEL_COMBAT
);
11123 GetSession()->SendPacket( &data
);
11126 inline void Player::SendAttackSwingBadFacingAttack()
11129 data
.Initialize(SMSG_ATTACKSWING_BADFACING
);
11130 GetSession()->SendPacket( &data
);
11133 void Player::PlaySound(uint32 Sound
, bool OnlySelf
)
11136 data
.Initialize(SMSG_PLAY_SOUND
);
11139 GetSession()->SendPacket( &data
);
11141 SendMessageToSet( &data
, true );
11144 void Player::SendExplorationExperience(uint32 Area
, uint32 Experience
)
11147 data
.Initialize( SMSG_EXPLORATION_EXPERIENCE
);
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
);
11172 //Wait 5 min until remove pvp mode
11173 if( currTime
< m_pvp_count
+ 300 ) return;
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
)
11199 if(!pet
||pet
->GetGUID()!=GetPetGUID()) return;
11209 data
.Initialize(SMSG_DESTROY_OBJECT
);
11210 data
<< pet
->GetGUID();
11211 SendMessageToSet (&data
, true);
11213 data
.Initialize(SMSG_PET_SPELLS
);
11215 GetSession()->SendPacket(&data
);
11217 ObjectAccessor::Instance().AddObjectToRemoveList(pet
);
11220 void Player::UnTamePet(Creature
* pet
)
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);
11237 pet
->AIM_Initialize();
11241 data
.Initialize(SMSG_PET_SPELLS
);
11243 GetSession()->SendPacket(&data
);
11246 void Player::Uncharm()
11248 Creature
* charm
= GetCharm();
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();
11259 data
.Initialize(SMSG_PET_SPELLS
);
11261 GetSession()->SendPacket(&data
);
11264 void Player::PetSpellInitialize()
11266 Creature
* pet
= GetPet();
11273 uint16 Command
= 7;
11277 sLog
.outDebug("Pet Spells Groups");
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)
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;
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;
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
;
11350 int32
Player::GetTotalPctMods(uint32 spellId
, uint8 op
)
11352 SpellEntry
*spellInfo
= sSpellStore
.LookupEntry(spellId
);
11353 if (!spellInfo
) return 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
;
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());
11377 for(uint32 p
=0;p
<pGroup
->GetMembersCount();p
++)
11379 Unit
* Member
= ObjectAccessor::Instance().FindPlayer(pGroup
->GetMemberGUID(p
));
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
)
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
);
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
);
11412 owner
->GetSession()->SendPetitionQueryOpcode(charterguid
);
11414 } while ( result
->NextRow() );
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
;
11435 rest_bonus
= rest_bonus_new
;
11437 // update data for client
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
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();