aboutsummaryrefslogtreecommitdiff
path: root/src/game/Player.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/game/Player.cpp')
-rw-r--r--src/game/Player.cpp2048
1 files changed, 1155 insertions, 893 deletions
diff --git a/src/game/Player.cpp b/src/game/Player.cpp
index 17203faadde..8a3a4bffd93 100644
--- a/src/game/Player.cpp
+++ b/src/game/Player.cpp
@@ -316,10 +316,6 @@ Player::Player (WorldSession *session): Unit(), m_achievementMgr(this), m_reputa
m_nextSave = sWorld.getConfig(CONFIG_INTERVAL_SAVE);
- // randomize first save time in range [CONFIG_INTERVAL_SAVE] around [CONFIG_INTERVAL_SAVE]
- // this must help in case next save after mass player load after server startup
- m_nextSave = urand(m_nextSave/2,m_nextSave*3/2);
-
clearResurrectRequestData();
memset(m_items, 0, sizeof(Item*)*PLAYER_SLOTS_COUNT);
@@ -341,6 +337,11 @@ Player::Player (WorldSession *session): Unit(), m_achievementMgr(this), m_reputa
mSemaphoreTeleport_Near = false;
mSemaphoreTeleport_Far = false;
+ m_DelayedOperations = 0;
+ m_bCanDelayTeleport = false;
+ m_bHasDelayedTeleport = false;
+ m_teleport_options = 0;
+
pTrader = 0;
ClearTrade();
@@ -471,6 +472,8 @@ Player::Player (WorldSession *session): Unit(), m_achievementMgr(this), m_reputa
m_lastFallZ = 0;
m_ControlledByPlayer = true;
+
+ sWorld.IncreasePlayerCount();
}
Player::~Player ()
@@ -478,6 +481,10 @@ Player::~Player ()
// it must be unloaded already in PlayerLogout and accessed only for loggined player
//m_social = NULL;
+ // Player may still set map - remove it to correctly unload instances
+ if (FindMap())
+ ResetMap();
+
// Note: buy back item already deleted from DB when player was saved
for(uint8 i = 0; i < PLAYER_SLOTS_COUNT; ++i)
{
@@ -503,6 +510,8 @@ Player::~Player ()
delete m_declinedname;
delete m_runes;
+
+ sWorld.DecreasePlayerCount();
}
void Player::CleanupsBeforeDelete()
@@ -539,10 +548,6 @@ bool Player::Create( uint32 guidlow, const std::string& name, uint8 race, uint8
for (uint8 i = 0; i < PLAYER_SLOTS_COUNT; i++)
m_items[i] = NULL;
- m_race = race;
- m_class = class_;
-
- SetMapId(info->mapId);
Relocate(info->positionX,info->positionY,info->positionZ);
ChrClassesEntry const* cEntry = sChrClassesStore.LookupEntry(class_);
@@ -552,32 +557,19 @@ bool Player::Create( uint32 guidlow, const std::string& name, uint8 race, uint8
return false;
}
+ SetMap(MapManager::Instance().CreateMap(info->mapId, this, 0));
+
uint8 powertype = cEntry->powerType;
SetFloatValue(UNIT_FIELD_BOUNDINGRADIUS, DEFAULT_WORLD_OBJECT_SIZE);
SetFloatValue(UNIT_FIELD_COMBATREACH, 1.5f);
- switch(gender)
- {
- case GENDER_FEMALE:
- SetDisplayId(info->displayId_f );
- SetNativeDisplayId(info->displayId_f );
- break;
- case GENDER_MALE:
- SetDisplayId(info->displayId_m );
- SetNativeDisplayId(info->displayId_m );
- break;
- default:
- sLog.outError("Invalid gender %u for player",gender);
- return false;
- break;
- }
-
- setFactionForRace(m_race);
+ setFactionForRace(race);
uint32 RaceClassGender = ( race ) | ( class_ << 8 ) | ( gender << 16 );
SetUInt32Value(UNIT_FIELD_BYTES_0, ( RaceClassGender | ( powertype << 24 ) ) );
+ InitDisplayIds();
SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_PVP );
SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE );
SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_REGENERATE_POWER);
@@ -676,8 +668,8 @@ bool Player::Create( uint32 guidlow, const std::string& name, uint8 race, uint8
// Played time
m_Last_tick = time(NULL);
- m_Played_time[0] = 0;
- m_Played_time[1] = 0;
+ m_Played_time[PLAYED_TIME_TOTAL] = 0;
+ m_Played_time[PLAYED_TIME_LEVEL] = 0;
// base stats and related field values
InitStatsForLevel();
@@ -707,21 +699,8 @@ bool Player::Create( uint32 guidlow, const std::string& name, uint8 race, uint8
learnDefaultSpells();
// original action bar
- std::list<uint16>::const_iterator action_itr[4];
- for(uint8 i=0; i<4; i++)
- action_itr[i] = info->action[i].begin();
-
- for (; action_itr[0]!=info->action[0].end() && action_itr[1]!=info->action[1].end();)
- {
- uint16 taction[4];
- for(uint8 i=0; i<4 ;i++)
- taction[i] = (*action_itr[i]);
-
- addActionButton((uint8)taction[0], taction[1], (uint8)taction[2], (uint8)taction[3]);
-
- for(uint8 i=0; i<4 ;i++)
- ++action_itr[i];
- }
+ for (PlayerCreateInfoActions::const_iterator action_itr = info->action.begin(); action_itr != info->action.end(); ++action_itr)
+ addActionButton(action_itr->button,action_itr->action,action_itr->type);
// original items
CharStartOutfitEntry const* oEntry = NULL;
@@ -746,7 +725,6 @@ bool Player::Create( uint32 guidlow, const std::string& name, uint8 race, uint8
uint32 item_id = oEntry->ItemId[j];
-
// Hack for not existed item id in dbc 3.0.3
if(item_id==40582)
continue;
@@ -758,22 +736,23 @@ bool Player::Create( uint32 guidlow, const std::string& name, uint8 race, uint8
continue;
}
- // max stack by default (mostly 1), 1 for infinity stackable
- uint32 count = iProto->Stackable > 0 ? uint32(iProto->Stackable) : 1;
+ // BuyCount by default
+ uint32 count = iProto->BuyCount;
+ // special amount for foor/drink
if(iProto->Class==ITEM_CLASS_CONSUMABLE && iProto->SubClass==ITEM_SUBCLASS_FOOD)
{
switch(iProto->Spells[0].SpellCategory)
{
case 11: // food
- if(iProto->Stackable > 4)
- count = 4;
+ count = getClass()==CLASS_DEATH_KNIGHT ? 10 : 4;
break;
case 59: // drink
- if(iProto->Stackable > 2)
- count = 2;
+ count = 2;
break;
}
+ if(iProto->Stackable < count)
+ count = iProto->Stackable;
}
StoreNewItemInBestSlots(item_id, count);
@@ -1138,7 +1117,10 @@ void Player::Update( uint32 p_time )
// Having this would prevent more aura charges to be dropped, so let's crash
assert (!m_spellModTakingSpell);
+ //used to implement delayed far teleports
+ SetCanDelayTeleport(true);
Unit::Update( p_time );
+ SetCanDelayTeleport(false);
time_t now = time (NULL);
@@ -1346,8 +1328,8 @@ void Player::Update( uint32 p_time )
{
if (p_time >= m_DetectInvTimer)
{
- m_DetectInvTimer = 3000;
HandleStealthedUnitsDetection();
+ m_DetectInvTimer = 3000;
}
else
m_DetectInvTimer -= p_time;
@@ -1357,8 +1339,8 @@ void Player::Update( uint32 p_time )
if (now > m_Last_tick)
{
uint32 elapsed = uint32(now - m_Last_tick);
- m_Played_time[0] += elapsed; // Total played time
- m_Played_time[1] += elapsed; // Level played time
+ m_Played_time[PLAYED_TIME_TOTAL] += elapsed; // Total played time
+ m_Played_time[PLAYED_TIME_LEVEL] += elapsed; // Level played time
m_Last_tick = now;
}
@@ -1394,8 +1376,12 @@ void Player::Update( uint32 p_time )
//if(pet && !IsWithinDistInMap(pet, OWNER_MAX_DISTANCE) && (GetCharmGUID() && (pet->GetGUID() != GetCharmGUID())))
{
RemovePet(pet, PET_SAVE_NOT_IN_SLOT, true);
- return;
}
+
+ //we should execute delayed teleports only for alive(!) players
+ //because we don't want player's ghost teleported from graveyard
+ if(IsHasDelayedTeleport() && isAlive())
+ TeleportTo(m_teleport_dest, m_teleport_options);
}
void Player::setDeathState(DeathState s)
@@ -1452,53 +1438,67 @@ void Player::setDeathState(DeathState s)
}
}
-void Player::BuildEnumData( QueryResult * result, WorldPacket * p_data )
+bool Player::BuildEnumData( QueryResult * result, WorldPacket * p_data )
{
+ // 0 1 2 3 4 5 6 7
+ // "SELECT characters.guid, characters.name, characters.race, characters.class, characters.gender, characters.playerBytes, characters.playerBytes2, characters.level, "
+ // 8 9 10 11 12 13 14
+ // "characters.zone, characters.map, characters.position_x, characters.position_y, characters.position_z, guild_member.guildid, characters.playerFlags, "
+ // 15 16 17 18 19 20
+ // "characters.at_login, character_pet.entry, character_pet.modelid, character_pet.level, characters.data, character_declinedname.genitive "
+
Field *fields = result->Fetch();
- *p_data << uint64(GetGUID());
- *p_data << m_name;
+ uint32 guid = fields[0].GetUInt32();
+ uint8 pRace = fields[2].GetUInt8();
+ uint8 pClass = fields[3].GetUInt8();
- *p_data << uint8(getRace());
- uint8 pClass = getClass();
- *p_data << uint8(pClass);
- *p_data << uint8(getGender());
+ PlayerInfo const *info = objmgr.GetPlayerInfo(pRace, pClass);
+ if(!info)
+ {
+ sLog.outError("Player %u has incorrect race/class pair. Don't build enum.", guid);
+ return false;
+ }
+
+ *p_data << uint64(MAKE_NEW_GUID(guid, 0, HIGHGUID_PLAYER));
+ *p_data << fields[1].GetString(); // name
+ *p_data << uint8(pRace); // race
+ *p_data << uint8(pClass); // class
+ *p_data << uint8(fields[4].GetUInt8()); // gender
- uint32 bytes = GetUInt32Value(PLAYER_BYTES);
- *p_data << uint8(bytes);
- *p_data << uint8(bytes >> 8);
- *p_data << uint8(bytes >> 16);
- *p_data << uint8(bytes >> 24);
+ uint32 playerBytes = fields[5].GetUInt32();
+ *p_data << uint8(playerBytes); // skin
+ *p_data << uint8(playerBytes >> 8); // face
+ *p_data << uint8(playerBytes >> 16); // hair style
+ *p_data << uint8(playerBytes >> 24); // hair color
- bytes = GetUInt32Value(PLAYER_BYTES_2);
- *p_data << uint8(bytes);
+ uint32 playerBytes2 = fields[6].GetUInt32();
+ *p_data << uint8(playerBytes2 & 0xFF); // facial hair
- *p_data << uint8(getLevel()); // player level
- // do not use GetMap! it will spawn a new instance since the bound instances are not loaded
- uint32 zoneId = fields[10].GetUInt32();
- sLog.outDebug("Player::BuildEnumData: map:%u, x:%f, y:%f, z:%f zone:%u", GetMapId(), GetPositionX(), GetPositionY(), GetPositionZ(), zoneId);
- *p_data << uint32(zoneId);
- *p_data << uint32(GetMapId());
+ *p_data << uint8(fields[7].GetUInt8()); // level
+ *p_data << uint32(fields[8].GetUInt32()); // zone
+ *p_data << uint32(fields[9].GetUInt32()); // map
- *p_data << GetPositionX();
- *p_data << GetPositionY();
- *p_data << GetPositionZ();
+ *p_data << fields[10].GetFloat(); // x
+ *p_data << fields[11].GetFloat(); // y
+ *p_data << fields[12].GetFloat(); // z
- // guild id
- *p_data << uint32(fields[14].GetUInt32());
+ *p_data << uint32(fields[13].GetUInt32()); // guild id
uint32 char_flags = 0;
- if(HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_HELM))
+ uint32 playerFlags = fields[14].GetUInt32();
+ uint32 atLoginFlags = fields[15].GetUInt32();
+ if(playerFlags & PLAYER_FLAGS_HIDE_HELM)
char_flags |= CHARACTER_FLAG_HIDE_HELM;
- if(HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_CLOAK))
+ if(playerFlags & PLAYER_FLAGS_HIDE_CLOAK)
char_flags |= CHARACTER_FLAG_HIDE_CLOAK;
- if(HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST))
+ if(playerFlags & PLAYER_FLAGS_GHOST)
char_flags |= CHARACTER_FLAG_GHOST;
- if(HasAtLoginFlag(AT_LOGIN_RENAME))
+ if(atLoginFlags & AT_LOGIN_RENAME)
char_flags |= CHARACTER_FLAG_RENAME;
if(sWorld.getConfig(CONFIG_DECLINED_NAMES_USED))
{
- if(!fields[15].GetCppString().empty())
+ if(!fields[20].GetCppString().empty())
char_flags |= CHARACTER_FLAG_DECLINED;
}
else
@@ -1506,7 +1506,7 @@ void Player::BuildEnumData( QueryResult * result, WorldPacket * p_data )
*p_data << uint32(char_flags); // character flags
// character customize (flags?)
- *p_data << uint32(HasAtLoginFlag(AT_LOGIN_CUSTOMIZE) ? 1 : 0);
+ *p_data << uint32(atLoginFlags & AT_LOGIN_CUSTOMIZE ? 1 : 0);
*p_data << uint8(1); // unknown
// Pets info
@@ -1515,15 +1515,15 @@ void Player::BuildEnumData( QueryResult * result, WorldPacket * p_data )
uint32 petLevel = 0;
uint32 petFamily = 0;
- // show pet at selection character in character list only for non-ghost character
- if (result && isAlive() && (pClass == CLASS_WARLOCK || pClass == CLASS_HUNTER || pClass == CLASS_DEATH_KNIGHT))
+ // show pet at selection character in character list only for non-ghost character
+ if (result && !(playerFlags & PLAYER_FLAGS_GHOST) && (pClass == CLASS_WARLOCK || pClass == CLASS_HUNTER || pClass == CLASS_DEATH_KNIGHT))
{
- uint32 entry = fields[11].GetUInt32();
+ uint32 entry = fields[16].GetUInt32();
CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(entry);
if(cInfo)
{
- petDisplayId = fields[12].GetUInt32();
- petLevel = fields[13].GetUInt32();
+ petDisplayId = fields[17].GetUInt32();
+ petLevel = fields[18].GetUInt32();
petFamily = cInfo->family;
}
}
@@ -1533,36 +1533,45 @@ void Player::BuildEnumData( QueryResult * result, WorldPacket * p_data )
*p_data << uint32(petFamily);
}
+ // TODO: do not access data field here
+ Tokens data = StrSplit(fields[19].GetCppString(), " ");
+
for (uint8 slot = 0; slot < EQUIPMENT_SLOT_END; slot++)
{
uint32 visualbase = PLAYER_VISIBLE_ITEM_1_ENTRYID + (slot * 2);
- uint32 item_id = GetUInt32Value(visualbase);
+ uint32 item_id = GetUInt32ValueFromArray(data, visualbase);
const ItemPrototype * proto = objmgr.GetItemPrototype(item_id);
+ if(!proto)
+ {
+ *p_data << uint32(0);
+ *p_data << uint8(0);
+ *p_data << uint32(0);
+ continue;
+ }
+
SpellItemEnchantmentEntry const *enchant = NULL;
+ uint32 enchants = GetUInt32ValueFromArray(data, visualbase + 1);
for(uint8 enchantSlot = PERM_ENCHANTMENT_SLOT; enchantSlot <= TEMP_ENCHANTMENT_SLOT; ++enchantSlot)
{
- uint32 enchantId = GetUInt16Value(visualbase + 1, enchantSlot);
+ // values stored in 2 uint16
+ uint32 enchantId = 0x0000FFFF & (enchants >> enchantSlot*16);
+ if(!enchantId)
+ continue;
+
if(enchant = sSpellItemEnchantmentStore.LookupEntry(enchantId))
break;
}
- if (proto != NULL)
- {
- *p_data << uint32(proto->DisplayInfoID);
- *p_data << uint8(proto->InventoryType);
- *p_data << uint32(enchant ? enchant->aura_id : 0);
- }
- else
- {
- *p_data << uint32(0);
- *p_data << uint8(0);
- *p_data << uint32(0); // enchant?
- }
+ *p_data << uint32(proto->DisplayInfoID);
+ *p_data << uint8(proto->InventoryType);
+ *p_data << uint32(enchant ? enchant->aura_id : 0);
}
*p_data << uint32(0); // first bag display id
*p_data << uint8(0); // first bag inventory type
*p_data << uint32(0); // enchant?
+
+ return true;
}
bool Player::ToggleAFK()
@@ -1611,6 +1620,27 @@ void Player::SendTeleportAckMsg()
GetSession()->SendPacket(&data);
}
+void Player::TeleportOutOfMap(Map *oldMap)
+{
+ while(IsBeingTeleportedFar())
+ GetSession()->HandleMoveWorldportAckOpcode();
+
+ if(FindMap() != oldMap)
+ return;
+
+ TeleportTo(m_homebindMapId, m_homebindX, m_homebindY, m_homebindZ, GetOrientation());
+
+ while(IsBeingTeleportedFar())
+ GetSession()->HandleMoveWorldportAckOpcode();
+
+ if(FindMap() == oldMap)
+ {
+ sLog.outCrash("Cannot teleport player out of map!");
+ ResetMap();
+ assert(false);
+ }
+}
+
bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientation, uint32 options)
{
if(!MapManager::IsValidMapCoord(mapid, x, y, z, orientation))
@@ -1683,6 +1713,21 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
if ((GetMapId() == mapid) && (!m_transport))
{
+ //lets reset far teleport flag if it wasn't reset during chained teleports
+ SetSemaphoreTeleportFar(false);
+ //setup delayed teleport flag
+ SetDelayedTeleportFlag(IsCanDelayTeleport());
+ //if teleport spell is casted in Unit::Update() func
+ //then we need to delay it until update process will be finished
+ if(IsHasDelayedTeleport())
+ {
+ SetSemaphoreTeleportNear(true);
+ //lets save teleport destination for player
+ m_teleport_dest = WorldLocation(mapid, x, y, z, orientation);
+ m_teleport_options = options;
+ return true;
+ }
+
if (!(options & TELE_TO_NOT_UNSUMMON_PET))
{
//same map, only remove pet if out of range for new position
@@ -1697,7 +1742,7 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
m_teleport_dest = WorldLocation(mapid, x, y, z, orientation);
SetFallInformation(0, z);
- // code for finish transfer called in WorldSession::HandleMovementOpcodes()
+ // code for finish transfer called in WorldSession::HandleMovementOpcodes()
// at client packet MSG_MOVE_TELEPORT_ACK
SetSemaphoreTeleportNear(true);
// near teleport, triggering send MSG_MOVE_TELEPORT_ACK from client at landing
@@ -1712,6 +1757,10 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
}
else
{
+ if(getClass() == CLASS_DEATH_KNIGHT && GetMapId() == 609 && !isGameMaster()
+ && !IsActiveQuest(13165))
+ return false;
+
// far teleport to another map
Map* oldmap = IsInWorld() ? GetMap() : NULL;
// check if we can enter before stopping combat / removing pet / totems / interrupting spells
@@ -1726,6 +1775,21 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
Map *map = MapManager::Instance().FindMap(mapid);
if (!map || map->CanEnter(this))
{
+ //lets reset near teleport flag if it wasn't reset during chained teleports
+ SetSemaphoreTeleportNear(false);
+ //setup delayed teleport flag
+ SetDelayedTeleportFlag(IsCanDelayTeleport());
+ //if teleport spell is casted in Unit::Update() func
+ //then we need to delay it until update process will be finished
+ if(IsHasDelayedTeleport())
+ {
+ SetSemaphoreTeleportFar(true);
+ //lets save teleport destination for player
+ m_teleport_dest = WorldLocation(mapid, x, y, z, orientation);
+ m_teleport_options = options;
+ return true;
+ }
+
SetSelection(0);
CombatStop();
@@ -1755,6 +1819,9 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
if(IsNonMeleeSpellCasted(true))
InterruptNonMeleeSpells(true);
+ //remove auras before removing from map...
+ RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_CHANGE_MAP | AURA_INTERRUPT_FLAG_MOVE | AURA_INTERRUPT_FLAG_TURNING);
+
if(!GetSession()->PlayerLogout())
{
// send transfer packets
@@ -1801,8 +1868,6 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
// if the player is saved before worldportack (at logout for example)
// this will be used instead of the current location in SaveToDB
- RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_CHANGE_MAP | AURA_INTERRUPT_FLAG_MOVE | AURA_INTERRUPT_FLAG_TURNING);
-
// move packet sent by client always after far teleport
// code for finish transfer to new map called in WorldSession::HandleMoveWorldportAckOpcode at client packet
SetSemaphoreTeleportFar(true);
@@ -1813,6 +1878,53 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
return true;
}
+void Player::ProcessDelayedOperations()
+{
+ if(m_DelayedOperations == 0)
+ return;
+
+ if(m_DelayedOperations & DELAYED_RESURRECT_PLAYER)
+ {
+ ResurrectPlayer(0.0f, false);
+
+ if(GetMaxHealth() > m_resurrectHealth)
+ SetHealth( m_resurrectHealth );
+ else
+ SetHealth( GetMaxHealth() );
+
+ if(GetMaxPower(POWER_MANA) > m_resurrectMana)
+ SetPower(POWER_MANA, m_resurrectMana );
+ else
+ SetPower(POWER_MANA, GetMaxPower(POWER_MANA) );
+
+ SetPower(POWER_RAGE, 0 );
+ SetPower(POWER_ENERGY, GetMaxPower(POWER_ENERGY) );
+
+ SpawnCorpseBones();
+ }
+
+ if(m_DelayedOperations & DELAYED_SAVE_PLAYER)
+ {
+ SaveToDB();
+ }
+
+ if(m_DelayedOperations & DELAYED_SPELL_CAST_DESERTER)
+ {
+ CastSpell(this, 26013, true); // Deserter
+ }
+
+ //we have executed ALL delayed ops, so clear the flag
+ m_DelayedOperations = 0;
+}
+
+void Player::ScheduleDelayedOperation(uint32 operation)
+{
+ if(operation >= DELAYED_END)
+ return;
+
+ m_DelayedOperations |= operation;
+}
+
void Player::AddToWorld()
{
///- Do not add/remove the player from the object storage
@@ -1863,33 +1975,6 @@ void Player::RemoveFromWorld()
}
}
-void Player::RewardRage( uint32 damage, uint32 weaponSpeedHitFactor, bool attacker )
-{
- float addRage;
-
- float rageconversion = ((0.0091107836 * getLevel()*getLevel())+3.225598133*getLevel())+4.2652911;
-
- if(attacker)
- {
- addRage = ((damage/rageconversion*7.5 + weaponSpeedHitFactor)/2);
-
- // talent who gave more rage on attack
- addRage *= 1.0f + GetTotalAuraModifier(SPELL_AURA_MOD_RAGE_FROM_DAMAGE_DEALT) / 100.0f;
- }
- else
- {
- addRage = damage/rageconversion*2.5;
-
- // Berserker Rage effect
- if(HasAura(18499))
- addRage *= 1.3;
- }
-
- addRage *= sWorld.getRate(RATE_POWER_RAGE_INCOME);
-
- ModifyPower(POWER_RAGE, uint32(addRage*10));
-}
-
void Player::RegenerateAll()
{
if (m_regenTimer != 0)
@@ -2372,9 +2457,12 @@ void Player::GiveLevel(uint32 level)
SetUInt32Value(PLAYER_NEXT_LEVEL_XP, objmgr.GetXPForLevel(level));
//update level, max level of skills
- if(getLevel()!= level)
- m_Played_time[1] = 0; // Level Played Time reset
+ m_Played_time[PLAYED_TIME_LEVEL] = 0; // Level Played Time reset
+
+ _ApplyAllLevelScaleItemMods(false);
+
SetLevel(level);
+
UpdateSkillsForLevel ();
// save base values (bonuses already included in stored stats
@@ -2402,6 +2490,8 @@ void Player::GiveLevel(uint32 level)
SetPower(POWER_FOCUS, 0);
SetPower(POWER_HAPPINESS, 0);
+ _ApplyAllLevelScaleItemMods(true);
+
// update level to hunter/summon pet
if (Pet* pet = GetPet())
pet->SynchronizeLevelWithOwner();
@@ -2603,7 +2693,7 @@ void Player::InitStatsForLevel(bool reapplyMods)
void Player::SendInitialSpells()
{
time_t curTime = time(NULL);
- time_t infTime = curTime + MONTH/2;
+ time_t infTime = curTime + infinityCooldownDelayCheck;
uint16 spellCount = 0;
@@ -2637,18 +2727,21 @@ void Player::SendInitialSpells()
if(!sEntry)
continue;
- // not send infinity cooldown
- if(itr->second.end > infTime)
- continue;
-
data << uint32(itr->first);
- time_t cooldown = 0;
- if(itr->second.end > curTime)
- cooldown = (itr->second.end-curTime)*IN_MILISECONDS;
-
data << uint16(itr->second.itemid); // cast item id
data << uint16(sEntry->Category); // spell category
+
+ // send infinity cooldown in special format
+ if(itr->second.end >= infTime)
+ {
+ data << uint32(1); // cooldown
+ data << uint32(0x80000000); // category cooldown
+ continue;
+ }
+
+ time_t cooldown = itr->second.end > curTime ? (itr->second.end-curTime)*IN_MILISECONDS : 0;
+
if(sEntry->Category) // may be wrong, but anyway better than nothing...
{
data << uint32(0); // cooldown
@@ -2897,7 +2990,7 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen
if(!rankSpellId || rankSpellId==spell_id)
continue;
- removeSpell(rankSpellId);
+ removeSpell(rankSpellId,false,false);
}
}
}
@@ -3125,7 +3218,6 @@ bool Player::IsNeedCastPassiveSpellAtLearn(SpellEntry const* spellInfo) const
switch(spellInfo->Id)
{
// some spells not have stance data expected cast at form change or present
- case 5420: need_cast = (m_form == FORM_TREE); break;
case 5419: need_cast = (m_form == FORM_TRAVEL); break;
case 7376: need_cast = (m_form == FORM_DEFENSIVESTANCE); break;
case 7381: need_cast = (m_form == FORM_BERSERKERSTANCE); break;
@@ -3173,7 +3265,7 @@ void Player::learnSpell(uint32 spell_id, bool dependent)
GetSession()->SendPacket(&data);
}
-void Player::removeSpell(uint32 spell_id, bool disabled, bool update_action_bar_for_low_rank)
+void Player::removeSpell(uint32 spell_id, bool disabled, bool learn_low_rank)
{
PlayerSpellMap::iterator itr = m_spells.find(spell_id);
if (itr == m_spells.end())
@@ -3193,7 +3285,7 @@ void Player::removeSpell(uint32 spell_id, bool disabled, bool update_action_bar_
SpellsRequiringSpellMap const& reqMap = spellmgr.GetSpellsRequiringSpell();
SpellsRequiringSpellMap::const_iterator itr2 = reqMap.find(spell_id);
for (uint32 i=reqMap.count(spell_id);i>0;i--,itr2++)
- removeSpell(itr2->second,disabled);
+ removeSpell(itr2->second,disabled,false);
// re-search, it can be corrupted in prev loop
itr = m_spells.find(spell_id);
@@ -3223,8 +3315,9 @@ void Player::removeSpell(uint32 spell_id, bool disabled, bool update_action_bar_
RemoveAurasDueToSpell(spell_id);
// remove pet auras
- if(PetAura const* petSpell = spellmgr.GetPetAura(spell_id))
- RemovePetAura(petSpell);
+ for(int i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ if(PetAura const* petSpell = spellmgr.GetPetAura(spell_id, i))
+ RemovePetAura(petSpell);
// free talent points
uint32 talentCosts = GetTalentSpellCost(spell_id);
@@ -3321,15 +3414,17 @@ void Player::removeSpell(uint32 spell_id, bool disabled, bool update_action_bar_
{
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spell_id);
- // if talent then lesser rank also talent and need learn
+ // if talent then lesser rank also talent and need learn
if(talentCosts)
{
- //learnSpell (prev_id,false);
+ // I cannot see why mangos has these lines.
+ //if(learn_low_rank)
+ // learnSpell (prev_id,false);
}
- // if ranked non-stackable spell: need activate lesser rank and update dendence state
+ // if ranked non-stackable spell: need activate lesser rank and update dendence state
else if(cur_active && !SpellMgr::canStackSpellRanks(spellInfo) && spellmgr.GetSpellRank(spellInfo->Id) != 0)
{
- // need manually update dependence state (learn spell ignore like attempts)
+ // need manually update dependence state (learn spell ignore like attempts)
PlayerSpellMap::iterator prev_itr = m_spells.find(prev_id);
if (prev_itr != m_spells.end())
{
@@ -3341,19 +3436,16 @@ void Player::removeSpell(uint32 spell_id, bool disabled, bool update_action_bar_
}
// now re-learn if need re-activate
- if(cur_active && !prev_itr->second->active)
+ if(cur_active && !prev_itr->second->active && learn_low_rank)
{
if(addSpell(prev_id,true,false,prev_itr->second->dependent,prev_itr->second->disabled))
{
- if(update_action_bar_for_low_rank)
- {
- // downgrade spell ranks in spellbook and action bar
- WorldPacket data(SMSG_SUPERCEDED_SPELL, 4 + 4);
- data << uint32(spell_id);
- data << uint32(prev_id);
- GetSession()->SendPacket( &data );
- prev_activate = true;
- }
+ // downgrade spell ranks in spellbook and action bar
+ WorldPacket data(SMSG_SUPERCEDED_SPELL, 4 + 4);
+ data << uint32(spell_id);
+ data << uint32(prev_id);
+ GetSession()->SendPacket( &data );
+ prev_activate = true;
}
}
}
@@ -3374,14 +3466,10 @@ void Player::RemoveSpellCooldown( uint32 spell_id, bool update /* = false */ )
m_spellCooldowns.erase(spell_id);
if(update)
- {
- WorldPacket data(SMSG_CLEAR_COOLDOWN, 4+8);
- data << uint32(spell_id);
- data << uint64(GetGUID());
- SendDirectMessage(&data);
- }
+ SendClearCooldown(spell_id, this);
}
+// I am not sure which one is more efficient
void Player::RemoveCategoryCooldown( uint32 cat )
{
SpellCategoryStore::const_iterator i_scstore = sSpellCategoryStore.find(cat);
@@ -3390,6 +3478,22 @@ void Player::RemoveCategoryCooldown( uint32 cat )
RemoveSpellCooldown(*i_scset, true);
}
+void Player::RemoveSpellCategoryCooldown(uint32 cat, bool update /* = false */)
+{
+ SpellCategoryStore::const_iterator ct = sSpellCategoryStore.find(cat);
+ if (ct == sSpellCategoryStore.end())
+ return;
+
+ const SpellCategorySet& ct_set = ct->second;
+ for (SpellCooldowns::const_iterator i = m_spellCooldowns.begin(); i != m_spellCooldowns.end();)
+ {
+ if (ct_set.find(i->first) != ct_set.end())
+ RemoveSpellCooldown((i++)->first, update);
+ else
+ ++i;
+ }
+}
+
void Player::RemoveArenaSpellCooldowns()
{
// remove cooldowns on spells that has < 15 min CD
@@ -3405,13 +3509,8 @@ void Player::RemoveArenaSpellCooldowns()
entry->RecoveryTime <= 15 * MINUTE * IN_MILISECONDS &&
entry->CategoryRecoveryTime <= 15 * MINUTE * IN_MILISECONDS )
{
- // notify player
- WorldPacket data(SMSG_CLEAR_COOLDOWN, 4+8);
- data << uint32(itr->first);
- data << uint64(GetGUID());
- GetSession()->SendPacket(&data);
- // remove cooldown
- m_spellCooldowns.erase(itr);
+ // remove & notify
+ RemoveSpellCooldown(itr->first, true);
}
}
}
@@ -3421,12 +3520,8 @@ void Player::RemoveAllSpellCooldown()
if(!m_spellCooldowns.empty())
{
for(SpellCooldowns::const_iterator itr = m_spellCooldowns.begin();itr != m_spellCooldowns.end(); ++itr)
- {
- WorldPacket data(SMSG_CLEAR_COOLDOWN, 4+8);
- data << uint32(itr->first);
- data << uint64(GetGUID());
- GetSession()->SendPacket(&data);
- }
+ SendClearCooldown(itr->first, this);
+
m_spellCooldowns.clear();
}
}
@@ -3451,7 +3546,7 @@ void Player::_LoadSpellCooldowns(QueryResult *result)
if(!sSpellStore.LookupEntry(spell_id))
{
- sLog.outError("Player %u have unknown spell %u in `character_spell_cooldown`, skipping.",GetGUIDLow(),spell_id);
+ sLog.outError("Player %u has unknown spell %u in `character_spell_cooldown`, skipping.",GetGUIDLow(),spell_id);
continue;
}
@@ -3474,7 +3569,7 @@ void Player::_SaveSpellCooldowns()
CharacterDatabase.PExecute("DELETE FROM character_spell_cooldown WHERE guid = '%u'", GetGUIDLow());
time_t curTime = time(NULL);
- time_t infTime = curTime + MONTH/2;
+ time_t infTime = curTime + infinityCooldownDelayCheck;
// remove outdated and save active
for(SpellCooldowns::iterator itr = m_spellCooldowns.begin();itr != m_spellCooldowns.end();)
@@ -3528,10 +3623,7 @@ bool Player::resetTalents(bool no_cost)
{
// not need after this call
if(HasAtLoginFlag(AT_LOGIN_RESET_TALENTS))
- {
- m_atLoginFlags = m_atLoginFlags & ~AT_LOGIN_RESET_TALENTS;
- CharacterDatabase.PExecute("UPDATE characters set at_login = at_login & ~ %u WHERE guid ='%u'", uint32(AT_LOGIN_RESET_TALENTS), GetGUIDLow());
- }
+ RemoveAtLoginFlag(AT_LOGIN_RESET_TALENTS,true);
uint32 talentPointsForLevel = CalculateTalentsPoints();
@@ -3585,7 +3677,13 @@ bool Player::resetTalents(bool no_cost)
uint32 itrFirstId = spellmgr.GetFirstSpellInChain(itr->first);
// unlearn if first rank is talent or learned by talent
- if (itrFirstId == talentInfo->RankID[j] || spellmgr.IsSpellLearnToSpell(talentInfo->RankID[j],itrFirstId))
+ if (itrFirstId == talentInfo->RankID[j])
+ {
+ removeSpell(itr->first,!IsPassiveSpell(itr->first),false);
+ itr = GetSpellMap().begin();
+ continue;
+ }
+ else if (spellmgr.IsSpellLearnToSpell(talentInfo->RankID[j],itrFirstId))
{
removeSpell(itr->first,!IsPassiveSpell(itr->first));
itr = GetSpellMap().begin();
@@ -3791,9 +3889,9 @@ void Player::BuildCreateUpdateBlockForPlayer( UpdateData *data, Player *target )
Unit::BuildCreateUpdateBlockForPlayer( data, target );
}
-void Player::DestroyForPlayer( Player *target ) const
+void Player::DestroyForPlayer( Player *target, bool anim ) const
{
- Unit::DestroyForPlayer( target );
+ Unit::DestroyForPlayer( target, anim );
for(uint8 i = 0; i < INVENTORY_SLOT_BAG_END; i++)
{
@@ -4036,7 +4134,7 @@ void Player::DeleteFromDB(uint64 playerguid, uint32 accountId, bool updateRealmC
CharacterDatabase.PExecute("DELETE FROM character_equipmentsets WHERE guid = '%u'",guid);
CharacterDatabase.CommitTransaction();
- //LoginDatabase.PExecute("UPDATE realmcharacters SET numchars = numchars - 1 WHERE acctid = %d AND realmid = %d", accountId, realmID);
+ //loginDatabase.PExecute("UPDATE realmcharacters SET numchars = numchars - 1 WHERE acctid = %d AND realmid = %d", accountId, realmID);
if(updateRealmChars) sWorld.UpdateRealmCharCount(accountId);
}
@@ -4458,7 +4556,7 @@ uint32 Player::DurabilityRepair(uint16 pos, bool cost, float discountMod, bool g
uint32 dmultiplier = dcost->multiplier[ItemSubClassToDurabilityMultiplierId(ditemProto->Class,ditemProto->SubClass)];
uint32 costs = uint32(LostDurability*dmultiplier*double(dQualitymodEntry->quality_mod));
- costs = uint32(costs * discountMod);
+ costs = uint32(costs * discountMod) * sWorld.getRate(RATE_REPAIRCOST);
if (costs==0) //fix for ITEM_QUALITY_ARTIFACT
costs = 1;
@@ -5214,6 +5312,9 @@ void Player::UpdateWeaponSkill (WeaponAttackType attType)
if(m_form == FORM_TREE)
return; // use weapon but not skill up
+ if(pVictim && pVictim->GetTypeId() == TYPEID_UNIT && (((Creature*)pVictim)->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_SKILLGAIN))
+ return;
+
uint32 weapon_skill_gain = sWorld.getConfig(CONFIG_SKILL_GAIN_WEAPON);
switch(attType)
@@ -5557,65 +5658,69 @@ void Player::SendInitialActionButtons() const
sLog.outDetail( "Initializing Action Buttons for '%u'", GetGUIDLow() );
WorldPacket data(SMSG_ACTION_BUTTONS, 1+(MAX_ACTION_BUTTONS*4));
- data << uint8(0); // can be 0, 1, 2
+ data << uint8(0); // can be 0, 1, 2 (talent spec)
for(int button = 0; button < MAX_ACTION_BUTTONS; ++button)
{
ActionButtonList::const_iterator itr = m_actionButtons.find(button);
if(itr != m_actionButtons.end() && itr->second.uState != ACTIONBUTTON_DELETED)
- {
- data << uint16(itr->second.action);
- data << uint8(itr->second.misc);
- data << uint8(itr->second.type);
- }
+ data << uint32(itr->second.packedData);
else
- {
data << uint32(0);
- }
}
GetSession()->SendPacket( &data );
sLog.outDetail( "Action Buttons for '%u' Initialized", GetGUIDLow() );
}
-bool Player::addActionButton(const uint8 button, const uint16 action, const uint8 type, const uint8 misc)
+ActionButton* Player::addActionButton(uint8 button, uint32 action, uint8 type)
{
if(button >= MAX_ACTION_BUTTONS)
{
sLog.outError( "Action %u not added into button %u for player %s: button must be < 132", action, button, GetName() );
- return false;
+ return NULL;
}
- // check cheating with adding non-known spells to action bar
- if(type==ACTION_BUTTON_SPELL)
+ if(action >= MAX_ACTION_BUTTON_ACTION_VALUE)
{
- if(!sSpellStore.LookupEntry(action))
- {
- sLog.outError( "Action %u not added into button %u for player %s: spell not exist", action, button, GetName() );
- return false;
- }
-
- if(!HasSpell(action))
- {
- sLog.outError( "Action %u not added into button %u for player %s: player don't known this spell", action, button, GetName() );
- return false;
- }
+ sLog.outError( "Action %u not added into button %u for player %s: action must be < %u", action, button, GetName(), MAX_ACTION_BUTTON_ACTION_VALUE );
+ return NULL;
}
- ActionButtonList::iterator buttonItr = m_actionButtons.find(button);
+ switch(type)
+ {
+ case ACTION_BUTTON_SPELL:
+ if(!sSpellStore.LookupEntry(action))
+ {
+ sLog.outError( "Action %u not added into button %u for player %s: spell not exist", action, button, GetName() );
+ return NULL;
+ }
- if (buttonItr==m_actionButtons.end())
- { // just add new button
- m_actionButtons[button] = ActionButton(action,type,misc);
+ if(!HasSpell(action))
+ {
+ sLog.outError( "Action %u not added into button %u for player %s: player don't known this spell", action, button, GetName() );
+ return NULL;
+ }
+ break;
+ case ACTION_BUTTON_ITEM:
+ if(!objmgr.GetItemPrototype(action))
+ {
+ sLog.outError( "Action %u not added into button %u for player %s: item not exist", action, button, GetName() );
+ return NULL;
+ }
+ break;
+ default:
+ break; // pther cases not checked at this moment
}
- else
- { // change state of current button
- ActionButtonUpdateState uState = buttonItr->second.uState;
- buttonItr->second = ActionButton(action,type,misc);
- if (uState != ACTIONBUTTON_NEW) buttonItr->second.uState = ACTIONBUTTON_CHANGED;
- };
- sLog.outDetail( "Player '%u' Added Action '%u' to Button '%u'", GetGUIDLow(), action, button );
- return true;
+
+ // it create new button (NEW state) if need or return existed
+ ActionButton& ab = m_actionButtons[button];
+
+ // set data and update to CHANGED if not NEW
+ ab.SetActionAndType(action,ActionButtonType(type));
+
+ sLog.outDetail( "Player '%u' Added Action '%u' (type %u) to Button '%u'", GetGUIDLow(), action, uint32(type), button );
+ return &ab;
}
void Player::removeActionButton(uint8 button)
@@ -5883,7 +5988,7 @@ int32 Player::CalculateReputationGain(uint32 creatureOrQuestLevel, int32 rep, in
if (percent <= 0.0f)
return 0;
- return int32(rep*percent*0.01f);
+ return int32(rep*percent)/100;
}
//Calculates how many reputation points player gains in victim's enemy factions
@@ -6010,7 +6115,7 @@ bool Player::RewardHonor(Unit *uVictim, uint32 groupsize, float honor, bool pvpt
}
// 'Inactive' this aura prevents the player from gaining honor points and battleground tokens
- if(GetDummyAura(SPELL_AURA_PLAYER_INACTIVE))
+ if(HasAura(SPELL_AURA_PLAYER_INACTIVE))
return false;
uint64 victim_guid = 0;
@@ -6259,6 +6364,19 @@ uint32 Player::GetZoneIdFromDB(uint64 guid)
return zone;
}
+uint32 Player::GetLevelFromDB(uint64 guid)
+{
+ QueryResult *result = CharacterDatabase.PQuery( "SELECT level FROM characters WHERE guid='%u'", GUID_LOPART(guid) );
+ if (!result)
+ return 0;
+
+ Field* fields = result->Fetch();
+ uint32 level = fields[0].GetUInt32();
+ delete result;
+
+ return level;
+}
+
void Player::UpdateArea(uint32 newArea)
{
// FFA_PVP flags are area and not zone id dependent
@@ -6328,10 +6446,11 @@ void Player::UpdateZone(uint32 newZone, uint32 newArea)
}
pvpInfo.inNoPvPArea = false;
- if((zone->flags & AREA_FLAG_SANCTUARY) || zone->mapid == 609) // in sanctuary
+ if(zone->IsSanctuary()) // in sanctuary
{
SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY);
pvpInfo.inNoPvPArea = true;
+ CombatStopWithPets();
}
else
{
@@ -6456,22 +6575,6 @@ void Player::DuelComplete(DuelCompleteType type)
duel->opponent->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL, 1);
}
- // cool-down duel spell
- /*data.Initialize(SMSG_SPELL_COOLDOWN, 17);
-
- data<<GetGUID();
- data<<uint8(0x0);
-
- data<<(uint32)7266;
- data<<uint32(0x0);
- GetSession()->SendPacket(&data);
- data.Initialize(SMSG_SPELL_COOLDOWN, 17);
- data<<duel->opponent->GetGUID();
- data<<uint8(0x0);
- data<<(uint32)7266;
- data<<uint32(0x0);
- duel->opponent->GetSession()->SendPacket(&data);*/
-
//Remove Duel Flag object
GameObject* obj = GetMap()->GetGameObject(GetUInt64Value(PLAYER_DUEL_ARBITER));
if(obj)
@@ -6568,13 +6671,16 @@ void Player::_ApplyItemMods(Item *item, uint8 slot,bool apply)
sLog.outDebug("_ApplyItemMods complete.");
}
-void Player::_ApplyItemBonuses(ItemPrototype const *proto, uint8 slot, bool apply)
+void Player::_ApplyItemBonuses(ItemPrototype const *proto, uint8 slot, bool apply, bool only_level_scale /*= false*/)
{
if(slot >= INVENTORY_SLOT_BAG_END || !proto)
return;
- ScalingStatDistributionEntry const *ssd = proto->ScalingStatDistribution ? sScalingStatDistributionStore.LookupEntry(proto->ScalingStatDistribution) : 0;
- ScalingStatValuesEntry const *ssv = proto->ScalingStatValue ? sScalingStatValuesStore.LookupEntry(getLevel()) : 0;
+ ScalingStatDistributionEntry const *ssd = proto->ScalingStatDistribution ? sScalingStatDistributionStore.LookupEntry(proto->ScalingStatDistribution) : NULL;
+ ScalingStatValuesEntry const *ssv = proto->ScalingStatValue ? sScalingStatValuesStore.LookupEntry(getLevel()) : NULL;
+
+ if(only_level_scale && !(ssd && ssv))
+ return;
for (uint8 i = 0; i < MAX_ITEM_PROTO_STATS; ++i)
{
@@ -6755,7 +6861,8 @@ void Player::_ApplyItemBonuses(ItemPrototype const *proto, uint8 slot, bool appl
}
// Add armor bonus from ArmorDamageModifier if > 0
if (proto->ArmorDamageModifier > 0)
- armor+=proto->ArmorDamageModifier;
+ armor += uint32(proto->ArmorDamageModifier);
+
if (armor)
HandleStatModifier(UNIT_MOD_ARMOR, BASE_VALUE, float(armor), apply);
@@ -7015,17 +7122,48 @@ void Player::UpdateEquipSpellsAtFormChange()
}
}
}
-
-void Player::CastItemCombatSpell(Item *item, CalcDamageInfo *damageInfo, ItemPrototype const * proto)
+void Player::CastItemCombatSpell(Unit *target, WeaponAttackType attType, uint32 procVictim, uint32 procEx)
{
- Unit * Target = damageInfo->target;
- WeaponAttackType attType = damageInfo->attackType;
-
- if (!Target || Target == this )
+ if(!target || !target->isAlive() || target == this)
return;
+ for(int i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; i++)
+ {
+ // If usable, try to cast item spell
+ if (Item * item = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0,i))
+ if(!item->IsBroken())
+ if (ItemPrototype const *proto = item->GetProto())
+ {
+ // Additional check for weapons
+ if (proto->Class==ITEM_CLASS_WEAPON)
+ {
+ // offhand item cannot proc from main hand hit etc
+ EquipmentSlots slot;
+ switch (attType)
+ {
+ case BASE_ATTACK: slot = EQUIPMENT_SLOT_MAINHAND; break;
+ case OFF_ATTACK: slot = EQUIPMENT_SLOT_OFFHAND; break;
+ case RANGED_ATTACK: slot = EQUIPMENT_SLOT_RANGED; break;
+ default: slot = EQUIPMENT_SLOT_END; break;
+ }
+ if (slot != i)
+ continue;
+ // Check if item is useable (forms or disarm)
+ if (attType == BASE_ATTACK)
+ {
+ if (!((Player*)this)->IsUseEquipedWeapon(true))
+ continue;
+ }
+ }
+ ((Player*)this)->CastItemCombatSpell(target, attType, procVictim, procEx, item, proto);
+ }
+ }
+}
+
+void Player::CastItemCombatSpell(Unit *target, WeaponAttackType attType, uint32 procVictim, uint32 procEx, Item *item, ItemPrototype const * proto)
+{
// Can do effect if any damage done to target
- if (damageInfo->damage)
+ if (procVictim & PROC_FLAG_TAKEN_ANY_DAMAGE)
//if (damageInfo->procVictim & PROC_FLAG_TAKEN_ANY_DAMAGE)
{
for (int i = 0; i < 5; i++)
@@ -7048,7 +7186,7 @@ void Player::CastItemCombatSpell(Item *item, CalcDamageInfo *damageInfo, ItemPro
}
// not allow proc extra attack spell at extra attack
- if( m_extraAttacks && IsSpellHaveEffect(spellInfo,SPELL_EFFECT_ADD_EXTRA_ATTACKS) )
+ if( m_extraAttacks && IsSpellHaveEffect(spellInfo, SPELL_EFFECT_ADD_EXTRA_ATTACKS) )
return;
float chance = spellInfo->procChance;
@@ -7064,7 +7202,7 @@ void Player::CastItemCombatSpell(Item *item, CalcDamageInfo *damageInfo, ItemPro
}
if (roll_chance_f(chance))
- CastSpell(Target, spellInfo->Id, true, item);
+ CastSpell(target, spellInfo->Id, true, item);
}
}
@@ -7084,13 +7222,13 @@ void Player::CastItemCombatSpell(Item *item, CalcDamageInfo *damageInfo, ItemPro
if (entry && entry->procEx)
{
// Check hit/crit/dodge/parry requirement
- if((entry->procEx & damageInfo->procEx) == 0)
+ if((entry->procEx & procEx) == 0)
continue;
}
else
{
// Can do effect if any damage done to target
- if (!(damageInfo->damage))
+ if (!(procVictim & PROC_FLAG_TAKEN_ANY_DAMAGE))
//if (!(damageInfo->procVictim & PROC_FLAG_TAKEN_ANY_DAMAGE))
continue;
}
@@ -7105,10 +7243,7 @@ void Player::CastItemCombatSpell(Item *item, CalcDamageInfo *damageInfo, ItemPro
float chance = pEnchant->amount[s] != 0 ? float(pEnchant->amount[s]) : GetWeaponProcChance();
if (entry && entry->PPMChance)
- {
- uint32 WeaponSpeed = GetAttackTime(attType);
- chance = GetPPMProcChance(WeaponSpeed, entry->PPMChance, spellInfo);
- }
+ chance = GetPPMProcChance(proto->Delay, entry->PPMChance, spellInfo);
else if (entry && entry->customChance)
chance = entry->customChance;
@@ -7120,7 +7255,7 @@ void Player::CastItemCombatSpell(Item *item, CalcDamageInfo *damageInfo, ItemPro
if(IsPositiveSpell(pEnchant->spellid[s]))
CastSpell(this, pEnchant->spellid[s], true, item);
else
- CastSpell(Target, pEnchant->spellid[s], true, item);
+ CastSpell(target, pEnchant->spellid[s], true, item);
}
}
}
@@ -7309,6 +7444,24 @@ void Player::_ApplyAllItemMods()
sLog.outDebug("_ApplyAllItemMods complete.");
}
+void Player::_ApplyAllLevelScaleItemMods(bool apply)
+{
+ for (int i = 0; i < INVENTORY_SLOT_BAG_END; ++i)
+ {
+ if(m_items[i])
+ {
+ if(m_items[i]->IsBroken())
+ continue;
+
+ ItemPrototype const *proto = m_items[i]->GetProto();
+ if(!proto)
+ continue;
+
+ _ApplyItemBonuses(proto,i, apply, true);
+ }
+ }
+}
+
void Player::_ApplyAmmoBonuses()
{
// check ammo
@@ -7434,7 +7587,7 @@ void Player::SendLoot(uint64 guid, LootType loot_type)
if (go->getLootState() == GO_READY)
{
- uint32 lootid = go->GetLootId();
+ uint32 lootid = go->GetGOInfo()->GetLootId();
//TODO: fix this big hack
if((go->GetEntry() == BG_AV_OBJECTID_MINE_N || go->GetEntry() == BG_AV_OBJECTID_MINE_S))
@@ -9040,39 +9193,42 @@ uint8 Player::_CanStoreItem_InSpecificSlot( uint8 bag, uint8 slot, ItemPosCountV
Item* pItem2 = GetItemByPos( bag, slot );
// ignore move item (this slot will be empty at move)
- if(pItem2==pSrcItem)
+ if (pItem2==pSrcItem)
pItem2 = NULL;
uint32 need_space;
// empty specific slot - check item fit to slot
- if( !pItem2 || swap )
+ if (!pItem2 || swap)
{
- if( bag == INVENTORY_SLOT_BAG_0 )
+ if (bag == INVENTORY_SLOT_BAG_0)
{
// keyring case
- if(slot >= KEYRING_SLOT_START && slot < KEYRING_SLOT_START+GetMaxKeyringSize() && !(pProto->BagFamily & BAG_FAMILY_MASK_KEYS))
+ if (slot >= KEYRING_SLOT_START && slot < KEYRING_SLOT_START+GetMaxKeyringSize() && !(pProto->BagFamily & BAG_FAMILY_MASK_KEYS))
return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG;
// currencytoken case
- if(slot >= CURRENCYTOKEN_SLOT_START && slot < CURRENCYTOKEN_SLOT_END && !(pProto->BagFamily & BAG_FAMILY_MASK_CURRENCY_TOKENS))
+ if (slot >= CURRENCYTOKEN_SLOT_START && slot < CURRENCYTOKEN_SLOT_END && !(pProto->BagFamily & BAG_FAMILY_MASK_CURRENCY_TOKENS))
return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG;
// prevent cheating
- if(slot >= BUYBACK_SLOT_START && slot < BUYBACK_SLOT_END || slot >= PLAYER_SLOT_END)
+ if (slot >= BUYBACK_SLOT_START && slot < BUYBACK_SLOT_END || slot >= PLAYER_SLOT_END)
return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG;
}
else
{
Bag* pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, bag );
- if( !pBag )
+ if (!pBag)
return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG;
ItemPrototype const* pBagProto = pBag->GetProto();
- if( !pBagProto )
+ if (!pBagProto)
return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG;
- if( !ItemCanGoIntoBag(pProto,pBagProto) )
+ if (slot >= pBagProto->ContainerSlots)
+ return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG;
+
+ if (!ItemCanGoIntoBag(pProto,pBagProto))
return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG;
}
@@ -9083,22 +9239,22 @@ uint8 Player::_CanStoreItem_InSpecificSlot( uint8 bag, uint8 slot, ItemPosCountV
else
{
// check item type
- if(pItem2->GetEntry() != pProto->ItemId)
+ if (pItem2->GetEntry() != pProto->ItemId)
return EQUIP_ERR_ITEM_CANT_STACK;
// check free space
- if(pItem2->GetCount() >= pProto->GetMaxStackSize())
+ if (pItem2->GetCount() >= pProto->GetMaxStackSize())
return EQUIP_ERR_ITEM_CANT_STACK;
// free stack space or infinity
need_space = pProto->GetMaxStackSize() - pItem2->GetCount();
}
- if(need_space > count)
+ if (need_space > count)
need_space = count;
ItemPosCount newPosition = ItemPosCount((bag << 8) | slot, need_space);
- if(!newPosition.isContainedIn(dest))
+ if (!newPosition.isContainedIn(dest))
{
dest.push_back(newPosition);
count -= need_space;
@@ -9109,55 +9265,55 @@ uint8 Player::_CanStoreItem_InSpecificSlot( uint8 bag, uint8 slot, ItemPosCountV
uint8 Player::_CanStoreItem_InBag( uint8 bag, ItemPosCountVec &dest, ItemPrototype const *pProto, uint32& count, bool merge, bool non_specialized, Item* pSrcItem, uint8 skip_bag, uint8 skip_slot ) const
{
// skip specific bag already processed in first called _CanStoreItem_InBag
- if(bag==skip_bag)
+ if (bag==skip_bag)
return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG;
Bag* pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, bag );
- if( !pBag )
+ if (!pBag)
return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG;
ItemPrototype const* pBagProto = pBag->GetProto();
- if( !pBagProto )
+ if (!pBagProto)
return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG;
// specialized bag mode or non-specilized
- if( non_specialized != (pBagProto->Class == ITEM_CLASS_CONTAINER && pBagProto->SubClass == ITEM_SUBCLASS_CONTAINER) )
+ if (non_specialized != (pBagProto->Class == ITEM_CLASS_CONTAINER && pBagProto->SubClass == ITEM_SUBCLASS_CONTAINER))
return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG;
- if( !ItemCanGoIntoBag(pProto,pBagProto) )
+ if (!ItemCanGoIntoBag(pProto,pBagProto))
return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG;
for(uint32 j = 0; j < pBag->GetBagSize(); j++)
{
// skip specific slot already processed in first called _CanStoreItem_InSpecificSlot
- if(j==skip_slot)
+ if (j==skip_slot)
continue;
Item* pItem2 = GetItemByPos( bag, j );
// ignore move item (this slot will be empty at move)
- if(pItem2==pSrcItem)
+ if (pItem2==pSrcItem)
pItem2 = NULL;
// if merge skip empty, if !merge skip non-empty
- if((pItem2!=NULL)!=merge)
+ if ((pItem2!=NULL)!=merge)
continue;
- if( pItem2 )
+ if (pItem2)
{
- if(pItem2->GetEntry() == pProto->ItemId && pItem2->GetCount() < pProto->GetMaxStackSize())
+ if (pItem2->GetEntry() == pProto->ItemId && pItem2->GetCount() < pProto->GetMaxStackSize())
{
uint32 need_space = pProto->GetMaxStackSize() - pItem2->GetCount();
if(need_space > count)
need_space = count;
ItemPosCount newPosition = ItemPosCount((bag << 8) | j, need_space);
- if(!newPosition.isContainedIn(dest))
+ if (!newPosition.isContainedIn(dest))
{
dest.push_back(newPosition);
count -= need_space;
- if(count==0)
+ if (count==0)
return EQUIP_ERR_OK;
}
}
@@ -9165,16 +9321,16 @@ uint8 Player::_CanStoreItem_InBag( uint8 bag, ItemPosCountVec &dest, ItemPrototy
else
{
uint32 need_space = pProto->GetMaxStackSize();
- if(need_space > count)
+ if (need_space > count)
need_space = count;
ItemPosCount newPosition = ItemPosCount((bag << 8) | j, need_space);
- if(!newPosition.isContainedIn(dest))
+ if (!newPosition.isContainedIn(dest))
{
dest.push_back(newPosition);
count -= need_space;
- if(count==0)
+ if (count==0)
return EQUIP_ERR_OK;
}
}
@@ -9187,33 +9343,33 @@ uint8 Player::_CanStoreItem_InInventorySlots( uint8 slot_begin, uint8 slot_end,
for(uint32 j = slot_begin; j < slot_end; j++)
{
// skip specific slot already processed in first called _CanStoreItem_InSpecificSlot
- if(INVENTORY_SLOT_BAG_0==skip_bag && j==skip_slot)
+ if (INVENTORY_SLOT_BAG_0==skip_bag && j==skip_slot)
continue;
Item* pItem2 = GetItemByPos( INVENTORY_SLOT_BAG_0, j );
// ignore move item (this slot will be empty at move)
- if(pItem2==pSrcItem)
+ if (pItem2==pSrcItem)
pItem2 = NULL;
// if merge skip empty, if !merge skip non-empty
- if((pItem2!=NULL)!=merge)
+ if ((pItem2!=NULL)!=merge)
continue;
- if( pItem2 )
+ if (pItem2)
{
- if(pItem2->GetEntry() == pProto->ItemId && pItem2->GetCount() < pProto->GetMaxStackSize())
+ if (pItem2->GetEntry() == pProto->ItemId && pItem2->GetCount() < pProto->GetMaxStackSize())
{
uint32 need_space = pProto->GetMaxStackSize() - pItem2->GetCount();
- if(need_space > count)
+ if (need_space > count)
need_space = count;
ItemPosCount newPosition = ItemPosCount((INVENTORY_SLOT_BAG_0 << 8) | j, need_space);
- if(!newPosition.isContainedIn(dest))
+ if (!newPosition.isContainedIn(dest))
{
dest.push_back(newPosition);
count -= need_space;
- if(count==0)
+ if (count==0)
return EQUIP_ERR_OK;
}
}
@@ -9221,16 +9377,16 @@ uint8 Player::_CanStoreItem_InInventorySlots( uint8 slot_begin, uint8 slot_end,
else
{
uint32 need_space = pProto->GetMaxStackSize();
- if(need_space > count)
+ if (need_space > count)
need_space = count;
ItemPosCount newPosition = ItemPosCount((INVENTORY_SLOT_BAG_0 << 8) | j, need_space);
- if(!newPosition.isContainedIn(dest))
+ if (!newPosition.isContainedIn(dest))
{
dest.push_back(newPosition);
count -= need_space;
- if(count==0)
+ if (count==0)
return EQUIP_ERR_OK;
}
}
@@ -9243,16 +9399,16 @@ uint8 Player::_CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, uint3
sLog.outDebug( "STORAGE: CanStoreItem bag = %u, slot = %u, item = %u, count = %u", bag, slot, entry, count);
ItemPrototype const *pProto = objmgr.GetItemPrototype(entry);
- if( !pProto )
+ if (!pProto)
{
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count;
return swap ? EQUIP_ERR_ITEMS_CANT_BE_SWAPPED :EQUIP_ERR_ITEM_NOT_FOUND;
}
- if(pItem && pItem->IsBindedNotWith(this))
+ if (pItem && pItem->IsBindedNotWith(this))
{
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count;
return EQUIP_ERR_DONT_OWN_THAT_ITEM;
}
@@ -9260,11 +9416,11 @@ uint8 Player::_CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, uint3
// check count of items (skip for auto move for same player from bank)
uint32 no_similar_count = 0; // can't store this amount similar items
uint8 res = _CanTakeMoreSimilarItems(entry,count,pItem,&no_similar_count);
- if(res!=EQUIP_ERR_OK)
+ if (res!=EQUIP_ERR_OK)
{
- if(count==no_similar_count)
+ if (count==no_similar_count)
{
- if(no_space_count)
+ if (no_space_count)
*no_space_count = no_similar_count;
return res;
}
@@ -9272,22 +9428,22 @@ uint8 Player::_CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, uint3
}
// in specific slot
- if( bag != NULL_BAG && slot != NULL_SLOT )
+ if (bag != NULL_BAG && slot != NULL_SLOT)
{
res = _CanStoreItem_InSpecificSlot(bag,slot,dest,pProto,count,swap,pItem);
- if(res!=EQUIP_ERR_OK)
+ if (res!=EQUIP_ERR_OK)
{
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return res;
}
- if(count==0)
+ if (count==0)
{
- if(no_similar_count==0)
+ if (no_similar_count==0)
return EQUIP_ERR_OK;
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
}
@@ -9296,45 +9452,45 @@ uint8 Player::_CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, uint3
// not specific slot or have space for partly store only in specific slot
// in specific bag
- if( bag != NULL_BAG )
+ if (bag != NULL_BAG)
{
// search stack in bag for merge to
- if( pProto->Stackable != 1 )
+ if (pProto->Stackable != 1)
{
- if( bag == INVENTORY_SLOT_BAG_0 ) // inventory
+ if (bag == INVENTORY_SLOT_BAG_0) // inventory
{
res = _CanStoreItem_InInventorySlots(KEYRING_SLOT_START,CURRENCYTOKEN_SLOT_END,dest,pProto,count,true,pItem,bag,slot);
- if(res!=EQUIP_ERR_OK)
+ if (res!=EQUIP_ERR_OK)
{
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return res;
}
- if(count==0)
+ if (count==0)
{
- if(no_similar_count==0)
+ if (no_similar_count==0)
return EQUIP_ERR_OK;
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
}
res = _CanStoreItem_InInventorySlots(INVENTORY_SLOT_ITEM_START,INVENTORY_SLOT_ITEM_END,dest,pProto,count,true,pItem,bag,slot);
- if(res!=EQUIP_ERR_OK)
+ if (res!=EQUIP_ERR_OK)
{
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return res;
}
- if(count==0)
+ if (count==0)
{
- if(no_similar_count==0)
+ if (no_similar_count==0)
return EQUIP_ERR_OK;
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
}
@@ -9343,22 +9499,22 @@ uint8 Player::_CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, uint3
{
// we need check 2 time (specialized/non_specialized), use NULL_BAG to prevent skipping bag
res = _CanStoreItem_InBag(bag,dest,pProto,count,true,false,pItem,NULL_BAG,slot);
- if(res!=EQUIP_ERR_OK)
+ if (res!=EQUIP_ERR_OK)
res = _CanStoreItem_InBag(bag,dest,pProto,count,true,true,pItem,NULL_BAG,slot);
- if(res!=EQUIP_ERR_OK)
+ if (res!=EQUIP_ERR_OK)
{
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return res;
}
- if(count==0)
+ if (count==0)
{
- if(no_similar_count==0)
+ if (no_similar_count==0)
return EQUIP_ERR_OK;
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
}
@@ -9366,83 +9522,83 @@ uint8 Player::_CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, uint3
}
// search free slot in bag for place to
- if( bag == INVENTORY_SLOT_BAG_0 ) // inventory
+ if(bag == INVENTORY_SLOT_BAG_0) // inventory
{
// search free slot - keyring case
- if(pProto->BagFamily & BAG_FAMILY_MASK_KEYS)
+ if (pProto->BagFamily & BAG_FAMILY_MASK_KEYS)
{
uint32 keyringSize = GetMaxKeyringSize();
res = _CanStoreItem_InInventorySlots(KEYRING_SLOT_START,KEYRING_SLOT_START+keyringSize,dest,pProto,count,false,pItem,bag,slot);
- if(res!=EQUIP_ERR_OK)
+ if (res!=EQUIP_ERR_OK)
{
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return res;
}
- if(count==0)
+ if (count==0)
{
- if(no_similar_count==0)
+ if (no_similar_count==0)
return EQUIP_ERR_OK;
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
}
res = _CanStoreItem_InInventorySlots(CURRENCYTOKEN_SLOT_START,CURRENCYTOKEN_SLOT_END,dest,pProto,count,false,pItem,bag,slot);
- if(res!=EQUIP_ERR_OK)
+ if (res!=EQUIP_ERR_OK)
{
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return res;
}
- if(count==0)
+ if (count==0)
{
- if(no_similar_count==0)
+ if (no_similar_count==0)
return EQUIP_ERR_OK;
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
}
}
- else if(pProto->BagFamily & BAG_FAMILY_MASK_CURRENCY_TOKENS)
+ else if (pProto->BagFamily & BAG_FAMILY_MASK_CURRENCY_TOKENS)
{
res = _CanStoreItem_InInventorySlots(CURRENCYTOKEN_SLOT_START,CURRENCYTOKEN_SLOT_END,dest,pProto,count,false,pItem,bag,slot);
- if(res!=EQUIP_ERR_OK)
+ if (res!=EQUIP_ERR_OK)
{
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return res;
}
- if(count==0)
+ if (count==0)
{
- if(no_similar_count==0)
+ if (no_similar_count==0)
return EQUIP_ERR_OK;
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
}
}
res = _CanStoreItem_InInventorySlots(INVENTORY_SLOT_ITEM_START,INVENTORY_SLOT_ITEM_END,dest,pProto,count,false,pItem,bag,slot);
- if(res!=EQUIP_ERR_OK)
+ if (res!=EQUIP_ERR_OK)
{
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return res;
}
- if(count==0)
+ if (count==0)
{
- if(no_similar_count==0)
+ if (no_similar_count==0)
return EQUIP_ERR_OK;
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
}
@@ -9450,22 +9606,22 @@ uint8 Player::_CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, uint3
else // equipped bag
{
res = _CanStoreItem_InBag(bag,dest,pProto,count,false,false,pItem,NULL_BAG,slot);
- if(res!=EQUIP_ERR_OK)
+ if (res!=EQUIP_ERR_OK)
res = _CanStoreItem_InBag(bag,dest,pProto,count,false,true,pItem,NULL_BAG,slot);
- if(res!=EQUIP_ERR_OK)
+ if (res!=EQUIP_ERR_OK)
{
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return res;
}
- if(count==0)
+ if (count==0)
{
- if(no_similar_count==0)
+ if (no_similar_count==0)
return EQUIP_ERR_OK;
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
}
@@ -9475,58 +9631,58 @@ uint8 Player::_CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, uint3
// not specific bag or have space for partly store only in specific bag
// search stack for merge to
- if( pProto->Stackable != 1 )
+ if (pProto->Stackable != 1)
{
res = _CanStoreItem_InInventorySlots(KEYRING_SLOT_START,CURRENCYTOKEN_SLOT_END,dest,pProto,count,true,pItem,bag,slot);
- if(res!=EQUIP_ERR_OK)
+ if (res!=EQUIP_ERR_OK)
{
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return res;
}
- if(count==0)
+ if (count==0)
{
- if(no_similar_count==0)
+ if (no_similar_count==0)
return EQUIP_ERR_OK;
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
}
res = _CanStoreItem_InInventorySlots(INVENTORY_SLOT_ITEM_START,INVENTORY_SLOT_ITEM_END,dest,pProto,count,true,pItem,bag,slot);
- if(res!=EQUIP_ERR_OK)
+ if (res!=EQUIP_ERR_OK)
{
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return res;
}
- if(count==0)
+ if (count==0)
{
- if(no_similar_count==0)
+ if (no_similar_count==0)
return EQUIP_ERR_OK;
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
}
- if( pProto->BagFamily )
+ if (pProto->BagFamily)
{
for(uint32 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)
{
res = _CanStoreItem_InBag(i,dest,pProto,count,true,false,pItem,bag,slot);
- if(res!=EQUIP_ERR_OK)
+ if (res!=EQUIP_ERR_OK)
continue;
- if(count==0)
+ if (count==0)
{
- if(no_similar_count==0)
+ if (no_similar_count==0)
return EQUIP_ERR_OK;
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
}
@@ -9536,15 +9692,15 @@ uint8 Player::_CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, uint3
for(uint32 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)
{
res = _CanStoreItem_InBag(i,dest,pProto,count,true,true,pItem,bag,slot);
- if(res!=EQUIP_ERR_OK)
+ if (res!=EQUIP_ERR_OK)
continue;
- if(count==0)
+ if (count==0)
{
- if(no_similar_count==0)
+ if (no_similar_count==0)
return EQUIP_ERR_OK;
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
}
@@ -9552,45 +9708,45 @@ uint8 Player::_CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, uint3
}
// search free slot - special bag case
- if( pProto->BagFamily )
+ if (pProto->BagFamily)
{
- if(pProto->BagFamily & BAG_FAMILY_MASK_KEYS)
+ if (pProto->BagFamily & BAG_FAMILY_MASK_KEYS)
{
uint32 keyringSize = GetMaxKeyringSize();
res = _CanStoreItem_InInventorySlots(KEYRING_SLOT_START,KEYRING_SLOT_START+keyringSize,dest,pProto,count,false,pItem,bag,slot);
- if(res!=EQUIP_ERR_OK)
+ if (res!=EQUIP_ERR_OK)
{
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return res;
}
- if(count==0)
+ if (count==0)
{
- if(no_similar_count==0)
+ if (no_similar_count==0)
return EQUIP_ERR_OK;
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
}
}
- else if(pProto->BagFamily & BAG_FAMILY_MASK_CURRENCY_TOKENS)
+ else if (pProto->BagFamily & BAG_FAMILY_MASK_CURRENCY_TOKENS)
{
res = _CanStoreItem_InInventorySlots(CURRENCYTOKEN_SLOT_START,CURRENCYTOKEN_SLOT_END,dest,pProto,count,false,pItem,bag,slot);
- if(res!=EQUIP_ERR_OK)
+ if (res!=EQUIP_ERR_OK)
{
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return res;
}
- if(count==0)
+ if (count==0)
{
- if(no_similar_count==0)
+ if (no_similar_count==0)
return EQUIP_ERR_OK;
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
}
@@ -9599,15 +9755,15 @@ uint8 Player::_CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, uint3
for(uint32 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)
{
res = _CanStoreItem_InBag(i,dest,pProto,count,false,false,pItem,bag,slot);
- if(res!=EQUIP_ERR_OK)
+ if (res!=EQUIP_ERR_OK)
continue;
- if(count==0)
+ if (count==0)
{
- if(no_similar_count==0)
+ if (no_similar_count==0)
return EQUIP_ERR_OK;
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
}
@@ -9616,19 +9772,19 @@ uint8 Player::_CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, uint3
// search free slot
res = _CanStoreItem_InInventorySlots(INVENTORY_SLOT_ITEM_START,INVENTORY_SLOT_ITEM_END,dest,pProto,count,false,pItem,bag,slot);
- if(res!=EQUIP_ERR_OK)
+ if (res!=EQUIP_ERR_OK)
{
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return res;
}
- if(count==0)
+ if (count==0)
{
- if(no_similar_count==0)
+ if (no_similar_count==0)
return EQUIP_ERR_OK;
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
}
@@ -9636,21 +9792,21 @@ uint8 Player::_CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, uint3
for(uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)
{
res = _CanStoreItem_InBag(i,dest,pProto,count,false,true,pItem,bag,slot);
- if(res!=EQUIP_ERR_OK)
+ if (res!=EQUIP_ERR_OK)
continue;
- if(count==0)
+ if (count==0)
{
- if(no_similar_count==0)
+ if (no_similar_count==0)
return EQUIP_ERR_OK;
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
}
}
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return EQUIP_ERR_INVENTORY_FULL;
@@ -10378,7 +10534,7 @@ uint8 Player::CanUseAmmo( uint32 item ) const
return EQUIP_ERR_CANT_EQUIP_LEVEL_I;
// Requires No Ammo
- if(GetDummyAura(46699))
+ if(HasAura(46699))
return EQUIP_ERR_BAG_FULL6;
return EQUIP_ERR_OK;
@@ -10474,7 +10630,7 @@ Item* Player::_StoreItem( uint16 pos, Item *pItem, uint32 count, bool clone, boo
uint8 bag = pos >> 8;
uint8 slot = pos & 255;
- sLog.outDebug( "STORAGE: StoreItem bag = %u, slot = %u, item = %u, count = %u", bag, slot, pItem->GetEntry(), count);
+ sLog.outDebug( "STORAGE: StoreItem bag = %u, slot = %u, item = %u, count = %u, guid = %u", bag, slot, pItem->GetEntry(), count, pItem->GetGUIDLow());
Item *pItem2 = GetItemByPos( bag, slot );
@@ -10581,7 +10737,6 @@ Item* Player::EquipNewItem( uint16 pos, uint32 item, bool update )
Item* Player::EquipItem( uint16 pos, Item *pItem, bool update )
{
-
AddEnchantmentDurations(pItem);
AddItemDurations(pItem);
@@ -12311,7 +12466,11 @@ void Player::PrepareQuestMenu( uint64 guid )
}
else
{
- GameObject *pGameObject = GetMap()->GetGameObject(guid);
+ //we should obtain map pointer from GetMap() in 99% of cases. Special case
+ //only for quests which cast teleport spells on player
+ Map * _map = IsInWorld() ? GetMap() : MapManager::Instance().FindMap(GetMapId(), GetInstanceId());
+ ASSERT(_map);
+ GameObject *pGameObject = _map->GetGameObject(guid);
if( pGameObject )
{
pObject = (Object*)pGameObject;
@@ -12333,8 +12492,8 @@ void Player::PrepareQuestMenu( uint64 guid )
qm.AddMenuItem(quest_id, DIALOG_STATUS_UNK2);
else if ( status == QUEST_STATUS_INCOMPLETE )
qm.AddMenuItem(quest_id, DIALOG_STATUS_UNK2);
- else if (status == QUEST_STATUS_AVAILABLE )
- qm.AddMenuItem(quest_id, DIALOG_STATUS_CHAT);
+ //else if (status == QUEST_STATUS_AVAILABLE )
+ // qm.AddMenuItem(quest_id, DIALOG_STATUS_CHAT);
}
for(QuestRelations::const_iterator i = pObjectQR->lower_bound(pObject->GetEntry()); i != pObjectQR->upper_bound(pObject->GetEntry()); ++i)
@@ -12464,7 +12623,11 @@ Quest const * Player::GetNextQuest( uint64 guid, Quest const *pQuest )
}
else
{
- GameObject *pGameObject = GetMap()->GetGameObject(guid);
+ //we should obtain map pointer from GetMap() in 99% of cases. Special case
+ //only for quests which cast teleport spells on player
+ Map * _map = IsInWorld() ? GetMap() : MapManager::Instance().FindMap(GetMapId(), GetInstanceId());
+ ASSERT(_map);
+ GameObject *pGameObject = _map->GetGameObject(guid);
if( pGameObject )
{
pObject = (Object*)pGameObject;
@@ -12746,7 +12909,7 @@ void Player::AddQuest( Quest const *pQuest, Object *questGiver )
//starting initial quest script
if(questGiver && pQuest->GetQuestStartScript()!=0)
- sWorld.ScriptsStart(sQuestStartScripts, pQuest->GetQuestStartScript(), questGiver, this);
+ GetMap()->ScriptsStart(sQuestStartScripts, pQuest->GetQuestStartScript(), questGiver, this);
// Some spells applied at quest activation
SpellAreaForQuestMapBounds saBounds = spellmgr.GetSpellAreaForQuestMapBounds(quest_id,true);
@@ -12798,11 +12961,15 @@ void Player::IncompleteQuest( uint32 quest_id )
void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver, bool announce )
{
+ //this THING should be here to protect code from quest, which cast on player far teleport as a reward
+ //should work fine, cause far teleport will be executed in Player::Update()
+ SetCanDelayTeleport(true);
+
uint32 quest_id = pQuest->GetQuestId();
for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; i++ )
{
- if ( pQuest->ReqItemId[i] )
+ if (pQuest->ReqItemId[i])
DestroyItemCount( pQuest->ReqItemId[i], pQuest->ReqItemCount[i], true);
}
@@ -12810,29 +12977,29 @@ void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver
// SetTimedQuest( 0 );
m_timedquests.erase(pQuest->GetQuestId());
- if ( pQuest->GetRewChoiceItemsCount() > 0 )
+ if (pQuest->GetRewChoiceItemsCount() > 0)
{
- if( pQuest->RewChoiceItemId[reward] )
+ if (uint32 itemId = pQuest->RewChoiceItemId[reward])
{
ItemPosCountVec dest;
- if( CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, pQuest->RewChoiceItemId[reward], pQuest->RewChoiceItemCount[reward] ) == EQUIP_ERR_OK )
+ if (CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, itemId, pQuest->RewChoiceItemCount[reward] ) == EQUIP_ERR_OK)
{
- Item* item = StoreNewItem( dest, pQuest->RewChoiceItemId[reward], true);
+ Item* item = StoreNewItem( dest, itemId, true, Item::GenerateItemRandomPropertyId(itemId));
SendNewItem(item, pQuest->RewChoiceItemCount[reward], true, false);
}
}
}
- if ( pQuest->GetRewItemsCount() > 0 )
+ if (pQuest->GetRewItemsCount() > 0)
{
for (uint32 i=0; i < pQuest->GetRewItemsCount(); ++i)
{
- if( pQuest->RewItemId[i] )
+ if (uint32 itemId = pQuest->RewItemId[i])
{
ItemPosCountVec dest;
- if( CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, pQuest->RewItemId[i], pQuest->RewItemCount[i] ) == EQUIP_ERR_OK )
+ if (CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, itemId, pQuest->RewItemCount[i] ) == EQUIP_ERR_OK)
{
- Item* item = StoreNewItem( dest, pQuest->RewItemId[i], true);
+ Item* item = StoreNewItem( dest, itemId, true, Item::GenerateItemRandomPropertyId(itemId));
SendNewItem(item, pQuest->RewItemCount[i], true, false);
}
}
@@ -12841,13 +13008,8 @@ void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver
RewardReputation( pQuest );
- if( pQuest->GetRewSpellCast() > 0 )
- CastSpell( this, pQuest->GetRewSpellCast(), true);
- else if( pQuest->GetRewSpell() > 0)
- CastSpell( this, pQuest->GetRewSpell(), true);
-
uint16 log_slot = FindQuestSlot( quest_id );
- if( log_slot < MAX_QUEST_LOG_SIZE)
+ if (log_slot < MAX_QUEST_LOG_SIZE)
SetQuestSlot(log_slot,0);
QuestStatusData& q_status = mQuestStatus[quest_id];
@@ -12855,7 +13017,7 @@ void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver
// Not give XP in case already completed once repeatable quest
uint32 XP = q_status.m_rewarded ? 0 : uint32(pQuest->XPValue( this )*sWorld.getRate(RATE_XP_QUEST));
- if ( getLevel() < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL) )
+ if (getLevel() < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
GiveXP( XP , NULL );
else
{
@@ -12865,33 +13027,33 @@ void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver
}
// Give player extra money if GetRewOrReqMoney > 0 and get ReqMoney if negative
- if(pQuest->GetRewOrReqMoney())
+ if (pQuest->GetRewOrReqMoney())
{
ModifyMoney( pQuest->GetRewOrReqMoney() );
- if(pQuest->GetRewOrReqMoney() > 0)
+ if (pQuest->GetRewOrReqMoney() > 0)
GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD, pQuest->GetRewOrReqMoney());
}
// honor reward
- if(pQuest->GetRewHonorableKills())
- RewardHonor(NULL, 0, Trinity::Honor::hk_honor_at_level(getLevel(), pQuest->GetRewHonorableKills()));
+ if (pQuest->GetRewHonorableKills())
+ RewardHonor(NULL, 0, MaNGOS::Honor::hk_honor_at_level(getLevel(), pQuest->GetRewHonorableKills()));
// title reward
- if(pQuest->GetCharTitleId())
+ if (pQuest->GetCharTitleId())
{
- if(CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(pQuest->GetCharTitleId()))
+ if (CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(pQuest->GetCharTitleId()))
SetTitle(titleEntry);
}
- if(pQuest->GetBonusTalents())
+ if (pQuest->GetBonusTalents())
{
m_questRewardTalentCount+=pQuest->GetBonusTalents();
InitTalentForLevel();
}
// Send reward mail
- if(pQuest->GetRewMailTemplateId())
+ if (pQuest->GetRewMailTemplateId())
{
MailMessageType mailType;
uint32 senderGuidOrEntry;
@@ -12929,9 +13091,9 @@ void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver
uint32 max_slot = questMailLoot.GetMaxSlotInLootFor(this);
for(uint32 i = 0; mi.size() < MAX_MAIL_ITEMS && i < max_slot; ++i)
{
- if(LootItem* lootitem = questMailLoot.LootItemInSlot(i,this))
+ if (LootItem* lootitem = questMailLoot.LootItemInSlot(i,this))
{
- if(Item* item = Item::CreateItem(lootitem->itemid,lootitem->count,this))
+ if (Item* item = Item::CreateItem(lootitem->itemid,lootitem->count,this))
{
item->SaveToDB(); // save for prevent lost at next mail load, if send fail then item will deleted
mi.AddItem(item->GetGUIDLow(), item->GetEntry(), item);
@@ -12942,23 +13104,30 @@ void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver
WorldSession::SendMailTo(this, mailType, MAIL_STATIONERY_NORMAL, senderGuidOrEntry, GetGUIDLow(), "", 0, &mi, 0, 0, MAIL_CHECK_MASK_NONE,pQuest->GetRewMailDelaySecs(),pQuest->GetRewMailTemplateId());
}
- if(pQuest->IsDaily())
+ if (pQuest->IsDaily())
{
SetDailyQuestStatus(quest_id);
GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST, 1);
}
- if ( !pQuest->IsRepeatable() )
+ if (!pQuest->IsRepeatable())
SetQuestStatus(quest_id, QUEST_STATUS_COMPLETE);
else
SetQuestStatus(quest_id, QUEST_STATUS_NONE);
q_status.m_rewarded = true;
+ if (q_status.uState != QUEST_NEW)
+ q_status.uState = QUEST_CHANGED;
- if(announce)
+ if (announce)
SendQuestReward( pQuest, XP, questGiver );
- if (q_status.uState != QUEST_NEW) q_status.uState = QUEST_CHANGED;
+ // cast spells after mark quest complete (some spells have quest completed state reqyurements in spell_area data)
+ if (pQuest->GetRewSpellCast() > 0)
+ CastSpell( this, pQuest->GetRewSpellCast(), true);
+ else if ( pQuest->GetRewSpell() > 0)
+ CastSpell( this, pQuest->GetRewSpell(), true);
+
if (pQuest->GetZoneOrSort() > 0)
GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE, pQuest->GetZoneOrSort());
GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST_COUNT);
@@ -12990,6 +13159,9 @@ void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver
if( !HasAura(itr->second->spellId) )
CastSpell(this,itr->second->spellId,true);
}
+
+ //lets remove flag for delayed teleports
+ SetCanDelayTeleport(false);
}
void Player::FailQuest( uint32 quest_id )
@@ -13657,7 +13829,17 @@ void Player::ItemRemovedQuestCheck( uint32 entry, uint32 count )
UpdateForQuestWorldObjects();
}
-void Player::KilledMonster( uint32 entry, uint64 guid )
+void Player::KilledMonster( CreatureInfo const* cInfo, uint64 guid )
+{
+ if(cInfo->Entry)
+ KilledMonsterCredit(cInfo->Entry,guid);
+
+ for(int i = 0; i < MAX_KILL_CREDIT; ++i)
+ if(cInfo->KillCredit[i])
+ KilledMonsterCredit(cInfo->KillCredit[i],guid);
+}
+
+void Player::KilledMonsterCredit( uint32 entry, uint64 guid )
{
uint32 addkillcount = 1;
GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, entry, addkillcount);
@@ -13987,7 +14169,7 @@ void Player::SendQuestReward( Quest const *pQuest, uint32 XP, Object * questGive
GetSession()->SendPacket( &data );
if (pQuest->GetQuestCompleteScript() != 0)
- sWorld.ScriptsStart(sQuestEndScripts, pQuest->GetQuestCompleteScript(), questGiver, this);
+ GetMap()->ScriptsStart(sQuestEndScripts, pQuest->GetQuestCompleteScript(), questGiver, this);
}
void Player::SendQuestFailed( uint32 quest_id )
@@ -14074,8 +14256,8 @@ bool Player::MinimalLoadFromDB( QueryResult *result, uint32 guid )
bool delete_result = true;
if (!result)
{
- // 0 1 2 3 4 5 6 7 8 9 10
- result = CharacterDatabase.PQuery("SELECT guid, data, name, position_x, position_y, position_z, map, totaltime, leveltime, at_login, zone FROM characters WHERE guid = '%u'",guid);
+ // 0 1 2 3 4 5 6 7 8 9 10 11
+ result = CharacterDatabase.PQuery("SELECT guid, data, name, position_x, position_y, position_z, map, totaltime, leveltime, at_login, zone, level FROM characters WHERE guid = '%u'",guid);
if (!result)
return false;
}
@@ -14098,11 +14280,17 @@ bool Player::MinimalLoadFromDB( QueryResult *result, uint32 guid )
m_name = fields[2].GetCppString();
Relocate(fields[3].GetFloat(),fields[4].GetFloat(),fields[5].GetFloat());
- SetMapId(fields[6].GetUInt32());
+ Map *map = MapManager::Instance().CreateMap(fields[6].GetUInt32(), this, 0);
+ SetMap(map);
+
+ // randomize first save time in range [CONFIG_INTERVAL_SAVE] around [CONFIG_INTERVAL_SAVE]
+ // this must help in case next save after mass player load after server startup
+ m_nextSave = urand(m_nextSave/2,m_nextSave*3/2);
+
// the instance id is not needed at character enum
- m_Played_time[0] = fields[7].GetUInt32();
- m_Played_time[1] = fields[8].GetUInt32();
+ m_Played_time[PLAYED_TIME_TOTAL] = fields[7].GetUInt32();
+ m_Played_time[PLAYED_TIME_LEVEL] = fields[8].GetUInt32();
m_atLoginFlags = fields[9].GetUInt32();
@@ -14308,8 +14496,8 @@ float Player::GetFloatValueFromDB(uint16 index, uint64 guid)
bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
{
- //// 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] 30 31 32 33 34 35 36 37 38 39 40
- //QueryResult *result = CharacterDatabase.PQuery("SELECT guid, account, data, name, race, class, position_x, position_y, position_z, map, orientation, taximask, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, resettalents_time, trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, online, death_expire_time, taxi_path, dungeon_difficulty, arena_pending_points,bgid,bgteam,bgmap,bgx,bgy,bgz,bgo FROM characters WHERE guid = '%u'", guid);
+ //// 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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
+ //QueryResult *result = CharacterDatabase.PQuery("SELECT guid, account, data, name, race, class, gender, level, xp, money, playerBytes, playerBytes2, playerFlags, position_x, position_y, position_z, map, orientation, taximask, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, resettalents_time, trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, online, death_expire_time, taxi_path, dungeon_difficulty, arena_pending_points,bgid,bgteam,bgmap,bgx,bgy,bgz,bgo FROM characters WHERE guid = '%u'", guid);
QueryResult *result = holder->GetResult(PLAYER_LOGIN_QUERY_LOADFROM);
if(!result)
@@ -14336,7 +14524,8 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
m_name = fields[3].GetCppString();
// check name limitations
- if(!ObjectMgr::IsValidName(m_name) || (GetSession()->GetSecurity() == SEC_PLAYER && objmgr.IsReservedName(m_name)))
+ if (ObjectMgr::CheckPlayerName(m_name) != CHAR_NAME_SUCCESS ||
+ GetSession()->GetSecurity() == SEC_PLAYER && objmgr.IsReservedName(m_name))
{
delete result;
CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '%u' WHERE guid ='%u'", uint32(AT_LOGIN_RENAME),guid);
@@ -14353,6 +14542,23 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
// overwrite possible wrong/corrupted guid
SetUInt64Value(OBJECT_FIELD_GUID, MAKE_NEW_GUID(guid, 0, HIGHGUID_PLAYER));
+ // overwrite some data fields
+ uint32 bytes0 = GetUInt32Value(UNIT_FIELD_BYTES_0) & 0xFF000000;
+ bytes0 |= fields[4].GetUInt8(); // race
+ bytes0 |= fields[5].GetUInt8() << 8; // class
+ bytes0 |= fields[6].GetUInt8() << 16; // gender
+ SetUInt32Value(UNIT_FIELD_BYTES_0, bytes0);
+
+ SetUInt32Value(UNIT_FIELD_LEVEL, fields[7].GetUInt8());
+ SetUInt32Value(PLAYER_XP, fields[8].GetUInt32());
+ SetUInt32Value(PLAYER_FIELD_COINAGE, fields[9].GetUInt32());
+ SetUInt32Value(PLAYER_BYTES, fields[10].GetUInt32());
+ SetUInt32Value(PLAYER_BYTES_2, fields[11].GetUInt32());
+ SetUInt32Value(PLAYER_BYTES_3, (GetUInt32Value(PLAYER_BYTES_3) & ~1) | fields[6].GetUInt8());
+ SetUInt32Value(PLAYER_FLAGS, fields[12].GetUInt32());
+
+ InitDisplayIds();
+
// cleanup inventory related item value fields (its will be filled correctly in _LoadInventory)
for(uint8 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; ++slot)
{
@@ -14373,12 +14579,9 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
sLog.outDebug("Load Basic value of player %s is: ", m_name.c_str());
outDebugValues();
- m_race = fields[4].GetUInt8();
- //Need to call it to initialize m_team (m_team can be calculated from m_race)
+ //Need to call it to initialize m_team (m_team can be calculated from race)
//Other way is to saves m_team into characters table.
- setFactionForRace(m_race);
-
- m_class = fields[5].GetUInt8();
+ setFactionForRace(getRace());
// load home bind and check in same time class/race pair, it used later for restore broken positions
if(!_LoadHomeBind(holder->GetResult(PLAYER_LOGIN_QUERY_LOADHOMEBIND)))
@@ -14389,18 +14592,13 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
InitPrimaryProfessions(); // to max set before any spell loaded
- // init saved position, and fix it later if problematic
- uint32 transGUID = fields[24].GetUInt32();
- Relocate(fields[6].GetFloat(),fields[7].GetFloat(),fields[8].GetFloat(),fields[10].GetFloat());
- SetMapId(fields[9].GetUInt32());
- SetInstanceId(fields[41].GetFloat());
- SetDifficulty(fields[32].GetUInt32()); // may be changed in _LoadGroup
+ SetDifficulty(fields[39].GetUInt32()); // may be changed in _LoadGroup
_LoadGroup(holder->GetResult(PLAYER_LOGIN_QUERY_LOADGROUP));
_LoadArenaTeamInfo(holder->GetResult(PLAYER_LOGIN_QUERY_LOADARENAINFO));
- uint32 arena_currency = GetUInt32Value(PLAYER_FIELD_ARENA_CURRENCY) + fields[33].GetUInt32();
+ uint32 arena_currency = GetUInt32Value(PLAYER_FIELD_ARENA_CURRENCY) + fields[40].GetUInt32();
if (arena_currency > sWorld.getConfig(CONFIG_MAX_ARENA_POINTS))
arena_currency = sWorld.getConfig(CONFIG_MAX_ARENA_POINTS);
@@ -14424,35 +14622,42 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
_LoadBoundInstances(holder->GetResult(PLAYER_LOGIN_QUERY_LOADBOUNDINSTANCES));
+ // load player map related values
+ uint32 transGUID = fields[31].GetUInt32();
+ Relocate(fields[13].GetFloat(),fields[14].GetFloat(),fields[15].GetFloat(),fields[17].GetFloat());
+ uint32 mapId = fields[16].GetUInt32();
+ uint32 instanceId = fields[41].GetFloat();
+ std::string taxi_nodes = fields[38].GetCppString();
+
+ MapEntry const * mapEntry = sMapStore.LookupEntry(mapId);
if(!IsPositionValid())
{
sLog.outError("Player (guidlow %d) have invalid coordinates (X: %f Y: %f Z: %f O: %f). Teleport to default race/class locations.",guid,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
- RelocateToHomebind();
+ RelocateToHomebind(mapId);
transGUID = 0;
+ instanceId = 0;
m_movementInfo.t_x = 0.0f;
m_movementInfo.t_y = 0.0f;
m_movementInfo.t_z = 0.0f;
m_movementInfo.t_o = 0.0f;
}
-
- uint32 bgid = fields[34].GetUInt32();
- uint32 bgteam = fields[35].GetUInt32();
-
- if(bgid) //saved in BattleGround
+ // Player was saved in Arena or Bg
+ else if (mapEntry && mapEntry->IsBattleGroundOrArena())
{
- SetBattleGroundEntryPoint(fields[36].GetUInt32(),fields[37].GetFloat(),fields[38].GetFloat(),fields[39].GetFloat(),fields[40].GetFloat());
+ // Get Entry Point(bg master) or Homebind
+ SetBattleGroundEntryPoint(fields[43].GetUInt32(),fields[44].GetFloat(),fields[45].GetFloat(),fields[46].GetFloat(),fields[47].GetFloat());
- // check entry point and fix to homebind if need
- MapEntry const* mapEntry = sMapStore.LookupEntry(m_bgEntryPoint.mapid);
- if(!mapEntry || mapEntry->Instanceable() || !MapManager::IsValidMapCoord(m_bgEntryPoint))
+ MapEntry const* bgEntry = sMapStore.LookupEntry(m_bgEntryPoint.mapid);
+ if(!bgEntry || bgEntry->Instanceable() || !MapManager::IsValidMapCoord(m_bgEntryPoint))
SetBattleGroundEntryPoint(m_homebindMapId,m_homebindX,m_homebindY,m_homebindZ,0.0f);
- BattleGround *currentBg = sBattleGroundMgr.GetBattleGround(bgid, BATTLEGROUND_TYPE_NONE);
-
+ // Bg still exists - join it!
+ BattleGround *currentBg = sBattleGroundMgr.GetBattleGround(instanceId, BATTLEGROUND_TYPE_NONE);
if(currentBg && currentBg->IsPlayerInBattleGround(GetGUID()))
{
+ uint32 bgteam = fields[42].GetUInt32();
BattleGroundQueueTypeId bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(currentBg->GetTypeID(), currentBg->GetArenaType());
AddBattleGroundQueueId(bgQueueTypeId);
@@ -14465,38 +14670,25 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
SetInviteForBattleGroundQueueType(bgQueueTypeId,currentBg->GetInstanceID());
}
+ // Bg was not found - go to Entry Point
else
{
+ // Do not look for instance if bg not found
+ instanceId = 0;
const WorldLocation& _loc = GetBattleGroundEntryPoint();
- SetMapId(_loc.mapid);
+ mapId = _loc.mapid;
Relocate(_loc.coord_x, _loc.coord_y, _loc.coord_z, _loc.orientation);
- //RemoveArenaAuras(true);
}
}
- else
+ else if (transGUID != 0)
{
- MapEntry const* mapEntry = sMapStore.LookupEntry(GetMapId());
- // if server restart after player save in BG or area
- // player can have current coordinates in to BG/Arean map, fix this
- if(!mapEntry || mapEntry->IsBattleGroundOrArena())
- {
- // return to BG master
- SetMapId(fields[36].GetUInt32());
- Relocate(fields[37].GetFloat(),fields[38].GetFloat(),fields[39].GetFloat(),fields[40].GetFloat());
-
- // check entry point and fix to homebind if need
- mapEntry = sMapStore.LookupEntry(GetMapId());
- if(!mapEntry || mapEntry->IsBattleGroundOrArena() || !IsPositionValid())
- RelocateToHomebind();
- }
- }
+ // There are no transports on instances
+ instanceId = 0;
- if (transGUID != 0)
- {
- m_movementInfo.t_x = fields[20].GetFloat();
- m_movementInfo.t_y = fields[21].GetFloat();
- m_movementInfo.t_z = fields[22].GetFloat();
- m_movementInfo.t_o = fields[23].GetFloat();
+ m_movementInfo.t_x = fields[27].GetFloat();
+ m_movementInfo.t_y = fields[28].GetFloat();
+ m_movementInfo.t_z = fields[29].GetFloat();
+ m_movementInfo.t_o = fields[30].GetFloat();
if( !Trinity::IsValidMapCoord(
GetPositionX()+m_movementInfo.t_x,GetPositionY()+m_movementInfo.t_y,
@@ -14508,7 +14700,7 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
guid,GetPositionX()+m_movementInfo.t_x,GetPositionY()+m_movementInfo.t_y,
GetPositionZ()+m_movementInfo.t_z,GetOrientation()+m_movementInfo.t_o);
- RelocateToHomebind();
+ RelocateToHomebind(mapId);
m_movementInfo.t_x = 0.0f;
m_movementInfo.t_y = 0.0f;
@@ -14517,112 +14709,146 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
transGUID = 0;
}
- }
-
- if (transGUID != 0)
- {
- for (MapManager::TransportSet::iterator iter = MapManager::Instance().m_Transports.begin(); iter != MapManager::Instance().m_Transports.end(); ++iter)
+ else
{
- if( (*iter)->GetGUIDLow() == transGUID)
+ for (MapManager::TransportSet::iterator iter = MapManager::Instance().m_Transports.begin(); iter != MapManager::Instance().m_Transports.end(); ++iter)
{
- MapEntry const* transMapEntry = sMapStore.LookupEntry((*iter)->GetMapId());
- // client without expansion support
- if(GetSession()->Expansion() < transMapEntry->Expansion())
+ if( (*iter)->GetGUIDLow() == transGUID)
{
- sLog.outDebug("Player %s using client without required expansion tried login at transport at non accessible map %u", GetName(), (*iter)->GetMapId());
+ m_transport = *iter;
+ m_transport->AddPassenger(this);
+ mapId = (m_transport->GetMapId());
break;
}
-
- m_transport = *iter;
- m_transport->AddPassenger(this);
- SetMapId(m_transport->GetMapId());
- break;
}
- }
-
- if(!m_transport)
- {
- sLog.outError("Player (guidlow %d) have problems with transport guid (%u). Teleport to default race/class locations.",
- guid,transGUID);
+ if(!m_transport)
+ {
+ sLog.outError("Player (guidlow %d) have problems with transport guid (%u). Teleport to default race/class locations.",
+ guid,transGUID);
- RelocateToHomebind();
+ RelocateToHomebind(mapId);
- m_movementInfo.t_x = 0.0f;
- m_movementInfo.t_y = 0.0f;
- m_movementInfo.t_z = 0.0f;
- m_movementInfo.t_o = 0.0f;
+ m_movementInfo.t_x = 0.0f;
+ m_movementInfo.t_y = 0.0f;
+ m_movementInfo.t_z = 0.0f;
+ m_movementInfo.t_o = 0.0f;
- transGUID = 0;
+ transGUID = 0;
+ }
}
}
- else // not transport case
+ else if (!taxi_nodes.empty()) // Taxi Flight path loaded from db
{
- MapEntry const* mapEntry = sMapStore.LookupEntry(GetMapId());
- // client without expansion support
- if(GetSession()->Expansion() < mapEntry->Expansion())
+ // There are no flightpaths in instances
+ instanceId = 0;
+
+ if(!m_taxi.LoadTaxiDestinationsFromString(taxi_nodes,GetTeam()))
+ {
+ // problems with taxi path loading
+ TaxiNodesEntry const* nodeEntry = NULL;
+ if(uint32 node_id = m_taxi.GetTaxiSource())
+ nodeEntry = sTaxiNodesStore.LookupEntry(node_id);
+
+ if(!nodeEntry) // don't know taxi start node, to homebind
+ {
+ sLog.outError("Character %u have wrong data in taxi destination list, teleport to homebind.",GetGUIDLow());
+ RelocateToHomebind(mapId);
+ }
+ else // have start node, to it
+ {
+ sLog.outError("Character %u have too short taxi destination list, teleport to original node.",GetGUIDLow());
+ mapId = nodeEntry->map_id;
+ Relocate(nodeEntry->x, nodeEntry->y, nodeEntry->z,0.0f);
+ }
+ }
+ // Taxi path loading succesfull
+ else if(uint32 node_id = m_taxi.GetTaxiSource())
{
- sLog.outDebug("Player %s using client without required expansion tried login at non accessible map %u", GetName(), GetMapId());
- RelocateToHomebind();
+ // save source node as recall coord to prevent recall and fall from sky
+ TaxiNodesEntry const* nodeEntry = sTaxiNodesStore.LookupEntry(node_id);
+ assert(nodeEntry); // checked in m_taxi.LoadTaxiDestinationsFromString
+ Relocate(nodeEntry->x,nodeEntry->y,nodeEntry->z,0);
+ mapId = nodeEntry->map_id;
+ // flight will started later
}
}
+ // Map could be changed before
+ mapEntry = sMapStore.LookupEntry(mapId);
+ // client without expansion support
+ if(GetSession()->Expansion() < mapEntry->Expansion())
+ {
+ sLog.outDebug("Player %s using client without required expansion tried login at non accessible map %u", GetName(), mapId);
+ RelocateToHomebind(mapId);
+ instanceId = 0;
+ }
+
+ // fix crash (because of if(Map *map = _FindMap(instanceId)) in MapInstanced::CreateInstance)
+ if(instanceId)
+ if(InstanceSave * save = GetInstanceSave(mapId))
+ if(save->GetInstanceId() != instanceId)
+ instanceId = 0;
// NOW player must have valid map
// load the player's map here if it's not already loaded
- Map *map = GetMap();
+ Map *map = MapManager::Instance().CreateMap(mapId, this, instanceId);
if (!map)
{
- AreaTrigger const* at = objmgr.GetGoBackTrigger(GetMapId());
+ instanceId = 0;
+ AreaTrigger const* at = objmgr.GetGoBackTrigger(mapId);
if(at)
{
- SetMapId(at->target_mapId);
+ sLog.outError("Player (guidlow %d) is teleported to gobacktrigger (Map: %u X: %f Y: %f Z: %f O: %f).",guid,mapId,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
Relocate(at->target_X, at->target_Y, at->target_Z, GetOrientation());
- sLog.outError("Player (guidlow %d) is teleported to gobacktrigger (Map: %u X: %f Y: %f Z: %f O: %f).",guid,GetMapId(),GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
+ mapId = at->target_mapId;
}
else
{
- RelocateToHomebind();
- sLog.outError("Player (guidlow %d) is teleported to home (Map: %u X: %f Y: %f Z: %f O: %f).",guid,GetMapId(),GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
+ sLog.outError("Player (guidlow %d) is teleported to home (Map: %u X: %f Y: %f Z: %f O: %f).",guid,mapId,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
+ RelocateToHomebind(mapId);
}
- map = GetMap();
+ map = MapManager::Instance().CreateMap(mapId, this, 0);
if(!map)
{
- sLog.outError("ERROR: Player (guidlow %d) have invalid coordinates (X: %f Y: %f Z: %f O: %f). Teleport to default race/class locations.",guid,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
- delete result;
- return false;
-
- /*SetMapId(info->mapId);
+ PlayerInfo const *info = objmgr.GetPlayerInfo(getRace(), getClass());
+ mapId = info->mapId;
Relocate(info->positionX,info->positionY,info->positionZ,0.0f);
-
- map = GetMap();
- if(!map)
+ sLog.outError("ERROR: Player (guidlow %d) have invalid coordinates (X: %f Y: %f Z: %f O: %f). Teleport to default race/class locations.",guid,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
+ map = MapManager::Instance().CreateMap(mapId, this, 0);
+ if (!map)
{
- sLog.outError("ERROR: Player (guidlow %d) have invalid coordinates (X: %f Y: %f Z: %f O: %f). Teleport to default race/class locations.",guid,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
- sLog.outError("CRASH.");
- assert(false);
- }*/
+ sLog.outError("ERROR: Player (guidlow %d) has invalid default map coordinates (X: %f Y: %f Z: %f O: %f). or instance couldn't be created",guid,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
+ delete result;
+ return false;
+ }
}
}
- // since the player may not be bound to the map yet, make sure subsequent
- // getmap calls won't create new maps
- SetInstanceId(map->GetInstanceId());
-
// if the player is in an instance and it has been reset in the meantime teleport him to the entrance
- if(GetInstanceId() && !sInstanceSaveManager.GetInstanceSave(GetInstanceId()))
+ if(instanceId && !sInstanceSaveManager.GetInstanceSave(instanceId))
{
- AreaTrigger const* at = objmgr.GetMapEntranceTrigger(GetMapId());
+ AreaTrigger const* at = objmgr.GetMapEntranceTrigger(mapId);
if(at)
Relocate(at->target_X, at->target_Y, at->target_Z, at->target_Orientation);
else
- sLog.outError("Player %s(GUID: %u) logged in to a reset instance (map: %u) and there is no area-trigger leading to this map. Thus he can't be ported back to the entrance. This _might_ be an exploit attempt.", GetName(), GetGUIDLow(), GetMapId());
+ {
+ sLog.outError("Player %s(GUID: %u) logged in to a reset instance (map: %u) and there is no area-trigger leading to this map. Thus he can't be ported back to the entrance. This _might_ be an exploit attempt.", GetName(), GetGUIDLow(), mapId);
+ RelocateToHomebind(mapId);
+ instanceId = 0;
+ }
}
+ SetMap(map);
+
+ // randomize first save time in range [CONFIG_INTERVAL_SAVE] around [CONFIG_INTERVAL_SAVE]
+ // this must help in case next save after mass player load after server startup
+ m_nextSave = urand(m_nextSave/2,m_nextSave*3/2);
+
SaveRecallPosition();
time_t now = time(NULL);
- time_t logoutTime = time_t(fields[16].GetUInt64());
+ time_t logoutTime = time_t(fields[23].GetUInt64());
// since last logout (in seconds)
uint64 time_diff = uint64(now - logoutTime);
@@ -14637,27 +14863,27 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
uint16 newDrunkenValue = uint16(soberFactor*(GetUInt32Value(PLAYER_BYTES_3) & 0xFFFE));
SetDrunkValue(newDrunkenValue);
- m_rest_bonus = fields[15].GetFloat();
+ m_rest_bonus = fields[22].GetFloat();
//speed collect rest bonus in offline, in logout, far from tavern, city (section/in hour)
float bubble0 = 0.031;
//speed collect rest bonus in offline, in logout, in tavern, city (section/in hour)
float bubble1 = 0.125;
- if((int32)fields[16].GetUInt32() > 0)
+ if(time_diff > 0)
{
- float bubble = fields[17].GetUInt32() > 0
+ float bubble = fields[24].GetUInt32() > 0
? bubble1*sWorld.getRate(RATE_REST_OFFLINE_IN_TAVERN_OR_CITY)
: bubble0*sWorld.getRate(RATE_REST_OFFLINE_IN_WILDERNESS);
SetRestBonus(GetRestBonus()+ time_diff*((float)GetUInt32Value(PLAYER_NEXT_LEVEL_XP)/72000)*bubble);
}
- m_cinematic = fields[12].GetUInt32();
- m_Played_time[0]= fields[13].GetUInt32();
- m_Played_time[1]= fields[14].GetUInt32();
+ m_cinematic = fields[19].GetUInt32();
+ m_Played_time[PLAYED_TIME_TOTAL]= fields[20].GetUInt32();
+ m_Played_time[PLAYED_TIME_LEVEL]= fields[21].GetUInt32();
- m_resetTalentsCost = fields[18].GetUInt32();
- m_resetTalentsTime = time_t(fields[19].GetUInt64());
+ m_resetTalentsCost = fields[25].GetUInt32();
+ m_resetTalentsTime = time_t(fields[26].GetUInt64());
// reserve some flags
uint32 old_safe_flags = GetUInt32Value(PLAYER_FLAGS) & ( PLAYER_FLAGS_HIDE_CLOAK | PLAYER_FLAGS_HIDE_HELM );
@@ -14665,30 +14891,28 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
if( HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GM) )
SetUInt32Value(PLAYER_FLAGS, 0 | old_safe_flags);
- m_taxi.LoadTaxiMask( fields[11].GetString() ); // must be before InitTaxiNodesForLevel
+ m_taxi.LoadTaxiMask( fields[18].GetString() ); // must be before InitTaxiNodesForLevel
- uint32 extraflags = fields[25].GetUInt32();
+ uint32 extraflags = fields[32].GetUInt32();
- m_stableSlots = fields[26].GetUInt32();
+ m_stableSlots = fields[33].GetUInt32();
if(m_stableSlots > MAX_PET_STABLES)
{
sLog.outError("Player can have not more %u stable slots, but have in DB %u",MAX_PET_STABLES,uint32(m_stableSlots));
m_stableSlots = MAX_PET_STABLES;
}
- m_atLoginFlags = fields[27].GetUInt32();
+ m_atLoginFlags = fields[34].GetUInt32();
// Honor system
// Update Honor kills data
m_lastHonorUpdateTime = logoutTime;
UpdateHonorFields();
- m_deathExpireTime = (time_t)fields[30].GetUInt64();
+ m_deathExpireTime = (time_t)fields[37].GetUInt64();
if(m_deathExpireTime > now+MAX_DEATH_COUNT*DEATH_EXPIRE_STEP)
m_deathExpireTime = now+MAX_DEATH_COUNT*DEATH_EXPIRE_STEP-1;
- std::string taxi_nodes = fields[31].GetCppString();
-
delete result;
// clear channel spell data (if saved at channel spell casting)
@@ -14774,42 +14998,6 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
SetUInt32Value(PLAYER_CHOSEN_TITLE, 0);
}
- // Not finish taxi flight path
- if(!m_taxi.LoadTaxiDestinationsFromString(taxi_nodes,GetTeam()))
- {
- // problems with taxi path loading
- TaxiNodesEntry const* nodeEntry = NULL;
- if(uint32 node_id = m_taxi.GetTaxiSource())
- nodeEntry = sTaxiNodesStore.LookupEntry(node_id);
-
- if(!nodeEntry) // don't know taxi start node, to homebind
- {
- sLog.outError("Character %u have wrong data in taxi destination list, teleport to homebind.",GetGUIDLow());
- RelocateToHomebind();
- SaveRecallPosition(); // save as recall also to prevent recall and fall from sky
- }
- else // have start node, to it
- {
- sLog.outError("Character %u have too short taxi destination list, teleport to original node.",GetGUIDLow());
- SetMapId(nodeEntry->map_id);
- Relocate(nodeEntry->x, nodeEntry->y, nodeEntry->z,0.0f);
- SaveRecallPosition(); // save as recall also to prevent recall and fall from sky
- }
- m_taxi.ClearTaxiDestinations();
- }
- else if(uint32 node_id = m_taxi.GetTaxiSource())
- {
- // save source node as recall coord to prevent recall and fall from sky
- TaxiNodesEntry const* nodeEntry = sTaxiNodesStore.LookupEntry(node_id);
- assert(nodeEntry); // checked in m_taxi.LoadTaxiDestinationsFromString
- m_recallMap = nodeEntry->map_id;
- m_recallX = nodeEntry->x;
- m_recallY = nodeEntry->y;
- m_recallZ = nodeEntry->z;
-
- // flight will started later
- }
-
// has to be called after last Relocate() in Player::LoadFromDB
SetFallInformation(0, GetPositionZ());
@@ -14928,7 +15116,7 @@ void Player::_LoadActions(QueryResult *result)
{
m_actionButtons.clear();
- //QueryResult *result = CharacterDatabase.PQuery("SELECT button,action,type,misc FROM character_action WHERE guid = '%u' ORDER BY button",GetGUIDLow());
+ //QueryResult *result = CharacterDatabase.PQuery("SELECT button,action,type FROM character_action WHERE guid = '%u' ORDER BY button",GetGUIDLow());
if(result)
{
@@ -14937,9 +15125,11 @@ void Player::_LoadActions(QueryResult *result)
Field *fields = result->Fetch();
uint8 button = fields[0].GetUInt8();
+ uint32 action = fields[1].GetUInt32();
+ uint8 type = fields[2].GetUInt8();
- if(addActionButton(button, fields[1].GetUInt16(), fields[2].GetUInt8(), fields[3].GetUInt8()))
- m_actionButtons[button].uState = ACTIONBUTTON_UNCHANGED;
+ if(ActionButton* ab = addActionButton(button, action, type))
+ ab->uState = ACTIONBUTTON_UNCHANGED;
else
{
sLog.outError( " ...at loading, and will deleted in DB also");
@@ -15012,7 +15202,7 @@ void Player::_LoadAuras(QueryResult *result, uint32 timediff)
delete result;
}
- if(m_class == CLASS_WARRIOR)
+ if(getClass() == CLASS_WARRIOR && !HasAuraType(SPELL_AURA_MOD_SHAPESHIFT))
CastSpell(this,SPELL_ID_PASSIVE_BATTLE_STANCE,true);
}
@@ -15248,7 +15438,7 @@ void Player::_LoadMailedItems(Mail *mail)
if(!proto)
{
- sLog.outError( "Player %u have unknown item_template (ProtoType) in mailed items(GUID: %u template: %u) in mail (%u), deleted.", GetGUIDLow(), item_guid_low, item_template,mail->messageID);
+ sLog.outError( "Player %u has unknown item_template (ProtoType) in mailed items(GUID: %u template: %u) in mail (%u), deleted.", GetGUIDLow(), item_guid_low, item_template,mail->messageID);
CharacterDatabase.PExecute("DELETE FROM mail_items WHERE item_guid = '%u'", item_guid_low);
CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid = '%u'", item_guid_low);
continue;
@@ -15508,7 +15698,7 @@ void Player::_LoadSpells(QueryResult *result)
{
Field *fields = result->Fetch();
- addSpell(fields[0].GetUInt16(), fields[1].GetBool(), false, false, fields[2].GetBool());
+ addSpell(fields[0].GetUInt32(), fields[1].GetBool(), false, false, fields[2].GetBool());
}
while( result->NextRow() );
@@ -15595,6 +15785,19 @@ InstancePlayerBind* Player::GetBoundInstance(uint32 mapid, uint8 difficulty)
return NULL;
}
+InstanceSave * Player::GetInstanceSave(uint32 mapid)
+{
+ InstancePlayerBind *pBind = GetBoundInstance(mapid, GetDifficulty());
+ InstanceSave *pSave = pBind ? pBind->save : NULL;
+ if(!pBind || !pBind->perm)
+ {
+ if(Group *group = GetGroup())
+ if(InstanceGroupBind *groupBind = group->GetBoundInstance(mapid, GetDifficulty()))
+ pSave = groupBind->save;
+ }
+ return pSave;
+}
+
void Player::UnbindInstance(uint32 mapid, uint8 difficulty, bool unload)
{
BoundInstancesMap::iterator itr = m_boundInstances[difficulty].find(mapid);
@@ -15764,8 +15967,7 @@ bool Player::Satisfy(AccessRequirement const *ar, uint32 target_map, bool report
{
if(ar->levelMin && getLevel() < ar->levelMin)
LevelMin = ar->levelMin;
- else if(ar->heroicLevelMin && GetDifficulty() == DIFFICULTY_HEROIC
- && getLevel() < ar->heroicLevelMin)
+ if(ar->heroicLevelMin && GetDifficulty() == DIFFICULTY_HEROIC && getLevel() < ar->heroicLevelMin)
LevelMin = ar->heroicLevelMin;
if(ar->levelMax && getLevel() > ar->levelMax)
LevelMax = ar->levelMax;
@@ -15807,7 +16009,7 @@ bool Player::Satisfy(AccessRequirement const *ar, uint32 target_map, bool report
if(report)
{
if(missingItem)
- GetSession()->SendAreaTriggerMessage(GetSession()->GetTrinityString(LANG_LEVEL_MINREQUIRED_AND_ITEM), ar->levelMin, objmgr.GetItemPrototype(missingItem)->Name1);
+ GetSession()->SendAreaTriggerMessage(GetSession()->GetTrinityString(LANG_LEVEL_MINREQUIRED_AND_ITEM), LevelMin, objmgr.GetItemPrototype(missingItem)->Name1);
else if(missingKey)
SendTransferAborted(target_map, TRANSFER_ABORT_DIFFICULTY);
else if(missingHeroicQuest)
@@ -15882,30 +16084,19 @@ void Player::SaveToDB()
// delay auto save at any saves (manual, in code, or autosave)
m_nextSave = sWorld.getConfig(CONFIG_INTERVAL_SAVE);
+ //lets allow only players in world to be saved
+ if(IsBeingTeleportedFar())
+ {
+ ScheduleDelayedOperation(DELAYED_SAVE_PLAYER);
+ return;
+ }
+
// first save/honor gain after midnight will also update the player's honor fields
UpdateHonorFields();
- uint32 is_save_resting = HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING) ? 1 : 0;
- //save, far from tavern/city
- //save, but in tavern/city
sLog.outDebug("The value of player %s at save: ", m_name.c_str());
outDebugValues();
- // save state (after auras removing), if aura remove some flags then it must set it back by self)
- uint32 tmp_bytes = GetUInt32Value(UNIT_FIELD_BYTES_1);
- uint32 tmp_bytes2 = GetUInt32Value(UNIT_FIELD_BYTES_2);
- uint32 tmp_flags = GetUInt32Value(UNIT_FIELD_FLAGS);
- uint32 tmp_pflags = GetUInt32Value(PLAYER_FLAGS);
- uint32 tmp_displayid = GetDisplayId();
-
- // Set player sit state to standing on save, also stealth and shifted form
- SetByteValue(UNIT_FIELD_BYTES_1, 0, UNIT_STAND_STATE_STAND);
- SetByteValue(UNIT_FIELD_BYTES_2, 3, 0); // shapeshift
- RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED);
- SetDisplayId(GetNativeDisplayId());
-
- bool inworld = IsInWorld();
-
CharacterDatabase.BeginTransaction();
CharacterDatabase.PExecute("DELETE FROM characters WHERE guid = '%u'",GetGUIDLow());
@@ -15914,7 +16105,7 @@ void Player::SaveToDB()
CharacterDatabase.escape_string(sql_name);
std::ostringstream ss;
- ss << "INSERT INTO characters (guid,account,name,race,class,"
+ ss << "INSERT INTO characters (guid,account,name,race,class,gender,level,xp,money,playerBytes,playerBytes2,playerFlags,"
"map, instance_id, dungeon_difficulty, position_x, position_y, position_z, orientation, data, "
"taximask, online, cinematic, "
"totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, resettalents_time, "
@@ -15923,8 +16114,15 @@ void Player::SaveToDB()
<< GetGUIDLow() << ", "
<< GetSession()->GetAccountId() << ", '"
<< sql_name << "', "
- << m_race << ", "
- << m_class << ", ";
+ << (uint32)getRace() << ", "
+ << (uint32)getClass() << ", "
+ << (uint32)getGender() << ", "
+ << getLevel() << ", "
+ << GetUInt32Value(PLAYER_XP) << ", "
+ << GetMoney() << ", "
+ << GetUInt32Value(PLAYER_BYTES) << ", "
+ << GetUInt32Value(PLAYER_BYTES_2) << ", "
+ << GetUInt32Value(PLAYER_FLAGS) << ", ";
if(!IsBeingTeleported())
{
@@ -15955,69 +16153,48 @@ void Player::SaveToDB()
ss << "', ";
- ss << m_taxi; // string with TaxiMaskSize numbers
+ ss << m_taxi << ", "; // string with TaxiMaskSize numbers
- ss << ", ";
- ss << (inworld ? 1 : 0);
+ ss << (IsInWorld() ? 1 : 0) << ", ";
- ss << ", ";
- ss << m_cinematic;
+ ss << m_cinematic << ", ";
- ss << ", ";
- ss << m_Played_time[0];
- ss << ", ";
- ss << m_Played_time[1];
+ ss << m_Played_time[PLAYED_TIME_TOTAL] << ", ";
+ ss << m_Played_time[PLAYED_TIME_LEVEL] << ", ";
- ss << ", ";
- ss << finiteAlways(m_rest_bonus);
- ss << ", ";
- ss << (uint64)time(NULL);
- ss << ", ";
- ss << is_save_resting;
- ss << ", ";
- ss << m_resetTalentsCost;
- ss << ", ";
- ss << (uint64)m_resetTalentsTime;
+ ss << finiteAlways(m_rest_bonus) << ", ";
+ ss << (uint64)time(NULL) << ", ";
+ ss << (HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING) ? 1 : 0) << ", ";
+ //save, far from tavern/city
+ //save, but in tavern/city
+ ss << m_resetTalentsCost << ", ";
+ ss << (uint64)m_resetTalentsTime << ", ";
- ss << ", ";
- ss << finiteAlways(m_movementInfo.t_x);
- ss << ", ";
- ss << finiteAlways(m_movementInfo.t_y);
- ss << ", ";
- ss << finiteAlways(m_movementInfo.t_z);
- ss << ", ";
- ss << finiteAlways(m_movementInfo.t_o);
- ss << ", ";
+ ss << finiteAlways(m_movementInfo.t_x) << ", ";
+ ss << finiteAlways(m_movementInfo.t_y) << ", ";
+ ss << finiteAlways(m_movementInfo.t_z) << ", ";
+ ss << finiteAlways(m_movementInfo.t_o) << ", ";
if (m_transport)
ss << m_transport->GetGUIDLow();
else
ss << "0";
-
ss << ", ";
- ss << m_ExtraFlags;
- ss << ", ";
- ss << uint32(m_stableSlots); // to prevent save uint8 as char
+ ss << m_ExtraFlags << ", ";
- ss << ", ";
- ss << uint32(m_atLoginFlags & ((1<<AT_LOAD_PET_FLAGS) -1));
+ ss << uint32(m_stableSlots) << ", "; // to prevent save uint8 as char
- ss << ", ";
- ss << GetZoneId();
+ ss << uint32(m_atLoginFlags) << ", ";
- ss << ", ";
- ss << (uint64)m_deathExpireTime;
+ ss << GetZoneId() << ", ";
- ss << ", '";
- ss << m_taxi.SaveTaxiDestinationsToString();
+ ss << (uint64)m_deathExpireTime << ", '";
- ss << "', '0', ";
- ss << GetSession()->GetLatency();
- ss << ", ";
- ss << GetBattleGroundId();
- ss << ", ";
- ss << GetBGTeam();
- ss << ", ";
+ ss << m_taxi.SaveTaxiDestinationsToString() << "', ";
+ ss << "'0', "; // arena_pending_points
+ ss << GetSession()->GetLatency() << ", ";
+ ss << GetBattleGroundId() << ", ";
+ ss << GetBGTeam() << ", ";
ss << m_bgEntryPoint.mapid << ", "
<< finiteAlways(m_bgEntryPoint.coord_x) << ", "
<< finiteAlways(m_bgEntryPoint.coord_y) << ", "
@@ -16044,13 +16221,6 @@ void Player::SaveToDB()
CharacterDatabase.CommitTransaction();
- // restore state (before aura apply, if aura remove flag then aura must set it ack by self)
- SetDisplayId(tmp_displayid);
- SetUInt32Value(UNIT_FIELD_BYTES_1, tmp_bytes);
- SetUInt32Value(UNIT_FIELD_BYTES_2, tmp_bytes2);
- SetUInt32Value(UNIT_FIELD_FLAGS, tmp_flags);
- SetUInt32Value(PLAYER_FLAGS, tmp_pflags);
-
// save pet (hunter pet level and experience and all type pets health/mana).
if(Pet* pet = GetPet())
pet->SavePetToDB(PET_SAVE_AS_CURRENT);
@@ -16060,8 +16230,12 @@ void Player::SaveToDB()
void Player::SaveInventoryAndGoldToDB()
{
_SaveInventory();
- //money is in data field
- SaveDataFieldToDB();
+ SaveGoldToDB();
+}
+
+void Player::SaveGoldToDB()
+{
+ CharacterDatabase.PExecute("UPDATE characters SET money = '%u' WHERE guid = '%u'", GetMoney(), GetGUIDLow());
}
void Player::_SaveActions()
@@ -16071,14 +16245,14 @@ void Player::_SaveActions()
switch (itr->second.uState)
{
case ACTIONBUTTON_NEW:
- CharacterDatabase.PExecute("INSERT INTO character_action (guid,button,action,type,misc) VALUES ('%u', '%u', '%u', '%u', '%u')",
- GetGUIDLow(), (uint32)itr->first, (uint32)itr->second.action, (uint32)itr->second.type, (uint32)itr->second.misc );
+ CharacterDatabase.PExecute("INSERT INTO character_action (guid,button,action,type) VALUES ('%u', '%u', '%u', '%u')",
+ GetGUIDLow(), (uint32)itr->first, (uint32)itr->second.GetAction(), (uint32)itr->second.GetType() );
itr->second.uState = ACTIONBUTTON_UNCHANGED;
++itr;
break;
case ACTIONBUTTON_CHANGED:
- CharacterDatabase.PExecute("UPDATE character_action SET action = '%u', type = '%u', misc= '%u' WHERE guid= '%u' AND button= '%u' ",
- (uint32)itr->second.action, (uint32)itr->second.type, (uint32)itr->second.misc, GetGUIDLow(), (uint32)itr->first );
+ CharacterDatabase.PExecute("UPDATE character_action SET action = '%u', type = '%u' WHERE guid= '%u' AND button= '%u' ",
+ (uint32)itr->second.GetAction(), (uint32)itr->second.GetType(), GetGUIDLow(), (uint32)itr->first );
itr->second.uState = ACTIONBUTTON_UNCHANGED;
++itr;
break;
@@ -16089,7 +16263,7 @@ void Player::_SaveActions()
default:
++itr;
break;
- };
+ }
}
}
@@ -16103,13 +16277,11 @@ void Player::_SaveAuras()
// skip:
// area auras or single cast auras casted by other unit
// passive auras and stances
- if (itr->second->IsPassive()
- || itr->second->IsAuraType(SPELL_AURA_MOD_SHAPESHIFT)
- || itr->second->IsRemovedOnShapeLost())
+ if (itr->second->IsPassive())
continue;
- bool isCaster = itr->second->GetCasterGUID() == GetGUID();
- if (!isCaster)
- if (itr->second->IsSingleTarget()
+
+ if (itr->second->GetCasterGUID() != GetGUID())
+ if (IsSingleTargetSpell(itr->second->GetSpellProto())
|| itr->second->IsAreaAura())
continue;
@@ -16330,7 +16502,7 @@ void Player::outDebugValues() const
sLog.outDebug("HP is: \t\t\t%u\t\tMP is: \t\t\t%u",GetMaxHealth(), GetMaxPower(POWER_MANA));
sLog.outDebug("AGILITY is: \t\t%f\t\tSTRENGTH is: \t\t%f",GetStat(STAT_AGILITY), GetStat(STAT_STRENGTH));
sLog.outDebug("INTELLECT is: \t\t%f\t\tSPIRIT is: \t\t%f",GetStat(STAT_INTELLECT), GetStat(STAT_SPIRIT));
- sLog.outDebug("STAMINA is: \t\t%f\t\tSPIRIT is: \t\t%f",GetStat(STAT_STAMINA), GetStat(STAT_SPIRIT));
+ sLog.outDebug("STAMINA is: \t\t%f",GetStat(STAT_STAMINA));
sLog.outDebug("Armor is: \t\t%u\t\tBlock is: \t\t%f",GetArmor(), GetFloatValue(PLAYER_BLOCK_PERCENTAGE));
sLog.outDebug("HolyRes is: \t\t%u\t\tFireRes is: \t\t%u",GetResistance(SPELL_SCHOOL_HOLY), GetResistance(SPELL_SCHOOL_FIRE));
sLog.outDebug("NatureRes is: \t\t%u\t\tFrostRes is: \t\t%u",GetResistance(SPELL_SCHOOL_NATURE), GetResistance(SPELL_SCHOOL_FROST));
@@ -16465,38 +16637,20 @@ void Player::SetFloatValueInDB(uint16 index, float value, uint64 guid)
void Player::Customize(uint64 guid, uint8 gender, uint8 skin, uint8 face, uint8 hairStyle, uint8 hairColor, uint8 facialHair)
{
- Tokens tokens;
- if(!LoadValuesArrayFromDB(tokens, guid))
- return;
-
- uint32 unit_bytes0 = GetUInt32ValueFromArray(tokens, UNIT_FIELD_BYTES_0);
- uint8 race = unit_bytes0 & 0xFF;
- uint8 class_ = (unit_bytes0 >> 8) & 0xFF;
-
- PlayerInfo const* info = objmgr.GetPlayerInfo(race, class_);
- if(!info)
+ // 0
+ QueryResult* result = CharacterDatabase.PQuery("SELECT playerBytes2 FROM characters WHERE guid = '%u'", GUID_LOPART(guid));
+ if(!result)
return;
- unit_bytes0 &= ~(0xFF << 16);
- unit_bytes0 |= (gender << 16);
- SetUInt32ValueInArray(tokens, UNIT_FIELD_BYTES_0, unit_bytes0);
-
- SetUInt32ValueInArray(tokens, UNIT_FIELD_DISPLAYID, gender ? info->displayId_f : info->displayId_m);
- SetUInt32ValueInArray(tokens, UNIT_FIELD_NATIVEDISPLAYID, gender ? info->displayId_f : info->displayId_m);
-
- SetUInt32ValueInArray(tokens, PLAYER_BYTES, (skin | (face << 8) | (hairStyle << 16) | (hairColor << 24)));
+ Field* fields = result->Fetch();
- uint32 player_bytes2 = GetUInt32ValueFromArray(tokens, PLAYER_BYTES_2);
+ uint32 player_bytes2 = fields[0].GetUInt32();
player_bytes2 &= ~0xFF;
player_bytes2 |= facialHair;
- SetUInt32ValueInArray(tokens, PLAYER_BYTES_2, player_bytes2);
- uint32 player_bytes3 = GetUInt32ValueFromArray(tokens, PLAYER_BYTES_3);
- player_bytes3 &= ~0xFF;
- player_bytes3 |= gender;
- SetUInt32ValueInArray(tokens, PLAYER_BYTES_3, player_bytes3);
+ CharacterDatabase.PExecute("UPDATE characters SET gender = '%u', playerBytes = '%u', playerBytes2 = '%u' WHERE guid = '%u'", gender, skin | (face << 8) | (hairStyle << 16) | (hairColor << 24), player_bytes2, GUID_LOPART(guid));
- SaveValuesArrayInDB(tokens, guid);
+ delete result;
}
void Player::SendAttackSwingDeadTarget()
@@ -16523,10 +16677,10 @@ void Player::SendAttackSwingBadFacingAttack()
GetSession()->SendPacket( &data );
}
-void Player::SendAutoRepeatCancel()
+void Player::SendAutoRepeatCancel(Unit *target)
{
- WorldPacket data(SMSG_CANCEL_AUTO_REPEAT, GetPackGUID().size());
- data.append(GetPackGUID()); // may be it's target guid
+ WorldPacket data(SMSG_CANCEL_AUTO_REPEAT, target->GetPackGUID().size());
+ data.append(target->GetPackGUID()); // may be it's target guid
GetSession()->SendPacket( &data );
}
@@ -16751,7 +16905,6 @@ void Player::RemovePet(Pet* pet, PetSaveMode mode, bool returnreagent)
SetMinion(pet, false);
- pet->CleanupsBeforeDelete();
pet->AddObjectToRemoveList();
pet->m_removed = true;
@@ -16784,8 +16937,14 @@ void Player::StopCastingCharm()
if(GetCharmGUID())
{
- sLog.outCrash("Player %s is not able to uncharm unit (Entry: %u, Type: %u)", GetName(), charm->GetEntry(), charm->GetTypeId());
- assert(false);
+ sLog.outCrash("Player %s (GUID: " UI64FMTD " is not able to uncharm unit (GUID: " UI64FMTD " Entry: %u, Type: %u)", GetName(), GetGUID(), GetCharmGUID(), charm->GetEntry(), charm->GetTypeId());
+ if(charm->GetCharmerGUID())
+ {
+ sLog.outCrash("Charmed unit has charmer guid " UI64FMTD, charm->GetCharmerGUID());
+ assert(false);
+ }
+ else
+ SetCharm(charm, false);
}
}
@@ -16911,8 +17070,7 @@ void Player::PetSpellInitialize()
if(itr->second.state == PETSPELL_REMOVED)
continue;
- data << uint16(itr->first);
- data << uint16(itr->second.active); // pet spell active state isn't boolean
+ data << uint32(MAKE_UNIT_ACTION_BUTTON(itr->first,itr->second.active));
++addlist;
}
}
@@ -17037,7 +17195,7 @@ void Player::CharmSpellInitialize()
{
for(uint32 i = 0; i < MAX_SPELL_CHARM; ++i)
{
- if(charmInfo->GetCharmSpell(i)->spellId)
+ if(charmInfo->GetCharmSpell(i)->GetAction())
++addlist;
}
}
@@ -17062,11 +17220,8 @@ void Player::CharmSpellInitialize()
for(uint32 i = 0; i < MAX_SPELL_CHARM; ++i)
{
CharmSpellEntry *cspell = charmInfo->GetCharmSpell(i);
- if(cspell->spellId)
- {
- data << uint16(cspell->spellId);
- data << uint16(cspell->active);
- }
+ if(cspell->GetAction())
+ data << uint32(cspell->packedData);
}
}
@@ -17162,6 +17317,10 @@ void Player::RestoreSpellMods(Spell * spell)
else
mod->charges++;
+ // Do not set more spellmods than avalible
+ if (mod->ownerAura->GetAuraCharges() < mod->charges)
+ mod->charges = mod->ownerAura->GetAuraCharges();
+
// Skip this check for now - aura charges may change due to various reason
// TODO: trac these changes correctly
//assert (mod->ownerAura->GetAuraCharges() <= mod->charges);
@@ -17189,11 +17348,7 @@ void Player::RemoveSpellMods(Spell * spell)
checkedSpells.find(aur->GetParentAura()) != checkedSpells.end())
continue;
- flag96 const * mask = spellmgr.GetSpellAffect(aur->GetId(), aur->GetEffIndex());
- if (!mask)
- mask = &spellInfo->EffectSpellClassMask[aur->GetEffIndex()];
-
- if (spell->m_spellInfo->SpellFamilyFlags & *mask)
+ if (spell->m_spellInfo->SpellFamilyFlags & spellInfo->EffectSpellClassMask[aur->GetEffIndex()])
{
checkedSpells.insert(aur->GetParentAura());
spell->m_appliedMods.erase(aur->GetParentAura());
@@ -17248,6 +17403,9 @@ void Player::SetSpellModTakingSpell(Spell * spell, bool apply)
if (!spell || (m_spellModTakingSpell && m_spellModTakingSpell != spell))
return;
+ if (apply && spell->getState() == SPELL_STATE_FINISHED)
+ return;
+
if (apply)
m_spellModTakingSpell = spell;
else
@@ -17360,19 +17518,38 @@ void Player::HandleStealthedUnitsDetection()
Trinity::UnitListSearcher<Trinity::AnyStealthedCheck > searcher(this, stealthedUnits, u_check);
VisitNearbyObject(World::GetMaxVisibleDistance(), searcher);
- for (std::list<Unit*>::iterator i = stealthedUnits.begin(); i != stealthedUnits.end(); ++i)
+ for (std::list<Unit*>::const_iterator i = stealthedUnits.begin(); i != stealthedUnits.end(); ++i)
{
- if (!HaveAtClient(*i) && canSeeOrDetect(*i, true))
+ if((*i)==this)
+ continue;
+
+ bool hasAtClient = HaveAtClient((*i));
+ bool hasDetected = canSeeOrDetect(*i, true);
+
+ if (hasDetected)
{
- (*i)->SendUpdateToPlayer(this);
- m_clientGUIDs.insert((*i)->GetGUID());
+ if(!hasAtClient)
+ {
+ (*i)->SendUpdateToPlayer(this);
+ m_clientGUIDs.insert((*i)->GetGUID());
- #ifdef TRINITY_DEBUG
- if((sLog.getLogFilter() & LOG_FILTER_VISIBILITY_CHANGES)==0)
- sLog.outDebug("Object %u (Type: %u) is detected in stealth by player %u. Distance = %f",(*i)->GetGUIDLow(),(*i)->GetTypeId(),GetGUIDLow(),GetDistance(*i));
- #endif
+ #ifdef MANGOS_DEBUG
+ if((sLog.getLogFilter() & LOG_FILTER_VISIBILITY_CHANGES)==0)
+ sLog.outDebug("Object %u (Type: %u) is detected in stealth by player %u. Distance = %f",(*i)->GetGUIDLow(),(*i)->GetTypeId(),GetGUIDLow(),GetDistance(*i));
+ #endif
- SendInitialVisiblePackets(*i);
+ // target aura duration for caster show only if target exist at caster client
+ // send data at target visibility change (adding to client)
+ SendInitialVisiblePackets(*i);
+ }
+ }
+ else
+ {
+ if(hasAtClient)
+ {
+ (*i)->DestroyForPlayer(this);
+ m_clientGUIDs.erase((*i)->GetGUID());
+ }
}
}
}
@@ -17382,8 +17559,8 @@ bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc
if(nodes.size() < 2)
return false;
- // not let cheating with start flight in time of logout process || if casting not finished || while in combat || if not use Spell's with EffectSendTaxi
- if(GetSession()->isLogingOut() || isInCombat())
+ // not let cheating with start flight in time of logout process || while in combat || has type state: stunned || has type state: root
+ if(GetSession()->isLogingOut() || isInCombat() || hasUnitState(UNIT_STAT_STUNNED) || hasUnitState(UNIT_STAT_ROOT))
{
WorldPacket data(SMSG_ACTIVATETAXIREPLY, 4);
data << uint32(ERR_TAXIPLAYERBUSY);
@@ -17585,6 +17762,14 @@ bool Player::ActivateTaxiPathTo( uint32 taxi_path_id, uint32 spellid /*= 0*/ )
return ActivateTaxiPathTo(nodes,NULL,spellid);
}
+void Player::CleanupAfterTaxiFlight()
+{
+ m_taxi.ClearTaxiDestinations(); // not destinations, clear source node
+ Unmount();
+ RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT);
+ getHostilRefManager().setOnlineOfflineState(true);
+}
+
void Player::ProhibitSpellScholl(SpellSchoolMask idSchoolMask, uint32 unTimeMs )
{
// last check 2.0.10
@@ -17666,17 +17851,47 @@ void Player::InitDataForForm(bool reapplyMods)
UpdateAttackPowerAndDamage(true);
}
+void Player::InitDisplayIds()
+{
+ PlayerInfo const *info = objmgr.GetPlayerInfo(getRace(), getClass());
+ if(!info)
+ {
+ sLog.outError("Player %u has incorrect race/class pair. Can't init display ids.", GetGUIDLow());
+ return;
+ }
+
+ uint8 gender = getGender();
+ switch(gender)
+ {
+ case GENDER_FEMALE:
+ SetDisplayId(info->displayId_f );
+ SetNativeDisplayId(info->displayId_f );
+ break;
+ case GENDER_MALE:
+ SetDisplayId(info->displayId_m );
+ SetNativeDisplayId(info->displayId_m );
+ break;
+ default:
+ sLog.outError("Invalid gender %u for player",gender);
+ return;
+ }
+}
+
// Return true is the bought item has a max count to force refresh of window by caller
-bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint64 bagguid, uint8 slot)
+bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint8 bag, uint8 slot)
{
// cheating attempt
- if(count < 1) count = 1;
+ if (count < 1) count = 1;
- if(!isAlive())
+ // cheating attempt
+ if(slot > MAX_BAG_SIZE && slot !=NULL_SLOT)
+ return false;
+
+ if (!isAlive())
return false;
ItemPrototype const *pProto = objmgr.GetItemPrototype( item );
- if( !pProto )
+ if (!pProto)
{
SendBuyError( BUY_ERR_CANT_FIND_ITEM, NULL, item, 0);
return false;
@@ -17698,7 +17913,7 @@ bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint
}
size_t vendor_slot = vItems->FindItemSlot(item);
- if(vendor_slot >= vItems->GetItemCount())
+ if (vendor_slot >= vItems->GetItemCount())
{
SendBuyError( BUY_ERR_CANT_FIND_ITEM, pCreature, item, 0);
return false;
@@ -17707,39 +17922,39 @@ bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint
VendorItem const* crItem = vItems->m_items[vendor_slot];
// check current item amount if it limited
- if( crItem->maxcount != 0 )
+ if (crItem->maxcount != 0)
{
- if(pCreature->GetVendorItemCurrentCount(crItem) < pProto->BuyCount * count )
+ if (pCreature->GetVendorItemCurrentCount(crItem) < pProto->BuyCount * count )
{
SendBuyError( BUY_ERR_ITEM_ALREADY_SOLD, pCreature, item, 0);
return false;
}
}
- if( uint32(GetReputationRank(pProto->RequiredReputationFaction)) < pProto->RequiredReputationRank)
+ if (uint32(GetReputationRank(pProto->RequiredReputationFaction)) < pProto->RequiredReputationRank)
{
SendBuyError( BUY_ERR_REPUTATION_REQUIRE, pCreature, item, 0);
return false;
}
- if(crItem->ExtendedCost)
+ if (crItem->ExtendedCost)
{
ItemExtendedCostEntry const* iece = sItemExtendedCostStore.LookupEntry(crItem->ExtendedCost);
- if(!iece)
+ if (!iece)
{
sLog.outError("Item %u have wrong ExtendedCost field value %u", pProto->ItemId, crItem->ExtendedCost);
return false;
}
// honor points price
- if(GetHonorPoints() < (iece->reqhonorpoints * count))
+ if (GetHonorPoints() < (iece->reqhonorpoints * count))
{
SendEquipError(EQUIP_ERR_NOT_ENOUGH_HONOR_POINTS, NULL, NULL);
return false;
}
// arena points price
- if(GetArenaPoints() < (iece->reqarenapoints * count))
+ if (GetArenaPoints() < (iece->reqarenapoints * count))
{
SendEquipError(EQUIP_ERR_NOT_ENOUGH_ARENA_POINTS, NULL, NULL);
return false;
@@ -17769,63 +17984,38 @@ bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint
// reputation discount
price = uint32(floor(price * GetReputationPriceDiscount(pCreature)));
- if( GetMoney() < price )
+ if (GetMoney() < price)
{
SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, pCreature, item, 0);
return false;
}
- uint8 bag = 0; // init for case invalid bagGUID
-
- if (bagguid != NULL_BAG && slot != NULL_SLOT)
- {
- if( bagguid == GetGUID() )
- {
- bag = INVENTORY_SLOT_BAG_0;
- }
- else
- {
- for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END;i++)
- {
- if( Bag *pBag = (Bag*)GetItemByPos(INVENTORY_SLOT_BAG_0,i) )
- {
- if( bagguid == pBag->GetGUID() )
- {
- if(slot < pBag->GetBagSlot() && !pBag->GetItemByPos(slot))
- bag = i;
- break;
- }
- }
- }
- }
- }
-
- if( IsInventoryPos( bag, slot ) || (bagguid == NULL_BAG && slot == NULL_SLOT) )
+ if ((bag == NULL_BAG && slot == NULL_SLOT) || IsInventoryPos(bag, slot))
{
ItemPosCountVec dest;
uint8 msg = CanStoreNewItem( bag, slot, dest, item, pProto->BuyCount * count );
- if( msg != EQUIP_ERR_OK )
+ if (msg != EQUIP_ERR_OK)
{
SendEquipError( msg, NULL, NULL );
return false;
}
ModifyMoney( -(int32)price );
- if(crItem->ExtendedCost) // case for new honor system
+ if (crItem->ExtendedCost) // case for new honor system
{
ItemExtendedCostEntry const* iece = sItemExtendedCostStore.LookupEntry(crItem->ExtendedCost);
- if(iece->reqhonorpoints)
+ if (iece->reqhonorpoints)
ModifyHonorPoints( - int32(iece->reqhonorpoints * count));
- if(iece->reqarenapoints)
+ if (iece->reqarenapoints)
ModifyArenaPoints( - int32(iece->reqarenapoints * count));
for (uint8 i = 0; i < 5; ++i)
{
- if(iece->reqitem[i])
+ if (iece->reqitem[i])
DestroyItemCount(iece->reqitem[i], (iece->reqitemcount[i] * count), true);
}
}
- if(Item *it = StoreNewItem( dest, item, true ))
+ if (Item *it = StoreNewItem( dest, item, true ))
{
uint32 new_count = pCreature->UpdateVendorItemCurrentCount(crItem,pProto->BuyCount * count);
@@ -17839,9 +18029,9 @@ bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint
SendNewItem(it, pProto->BuyCount*count, true, false, false);
}
}
- else if( IsEquipmentPos( bag, slot ) )
+ else if (IsEquipmentPos(bag, slot))
{
- if(pProto->BuyCount * count != 1)
+ if (pProto->BuyCount * count != 1)
{
SendEquipError( EQUIP_ERR_ITEM_CANT_BE_EQUIPPED, NULL, NULL );
return false;
@@ -17849,19 +18039,19 @@ bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint
uint16 dest;
uint8 msg = CanEquipNewItem( slot, dest, item, false );
- if( msg != EQUIP_ERR_OK )
+ if (msg != EQUIP_ERR_OK)
{
SendEquipError( msg, NULL, NULL );
return false;
}
ModifyMoney( -(int32)price );
- if(crItem->ExtendedCost) // case for new honor system
+ if (crItem->ExtendedCost) // case for new honor system
{
ItemExtendedCostEntry const* iece = sItemExtendedCostStore.LookupEntry(crItem->ExtendedCost);
- if(iece->reqhonorpoints)
+ if (iece->reqhonorpoints)
ModifyHonorPoints( - int32(iece->reqhonorpoints));
- if(iece->reqarenapoints)
+ if (iece->reqarenapoints)
ModifyArenaPoints( - int32(iece->reqarenapoints));
for (uint8 i = 0; i < 5; ++i)
{
@@ -17870,7 +18060,7 @@ bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint
}
}
- if(Item *it = EquipNewItem( dest, item, true ))
+ if (Item *it = EquipNewItem( dest, item, true ))
{
uint32 new_count = pCreature->UpdateVendorItemCurrentCount(crItem,pProto->BuyCount * count);
@@ -17892,7 +18082,7 @@ bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint
return false;
}
- return crItem->maxcount!=0;
+ return crItem->maxcount != 0;
}
uint32 Player::GetMaxPersonalArenaRatingRequirement()
@@ -18051,8 +18241,8 @@ void Player::AddSpellAndCategoryCooldowns(SpellEntry const* spellInfo, uint32 it
{
// use +MONTH as infinity mark for spell cooldown (will checked as MONTH/2 at save ans skipped)
// but not allow ignore until reset or re-login
- catrecTime = catrec > 0 ? curTime+MONTH : 0;
- recTime = rec > 0 ? curTime+MONTH : catrecTime;
+ catrecTime = catrec > 0 ? curTime+infinityCooldownDelay : 0;
+ recTime = rec > 0 ? curTime+infinityCooldownDelay : catrecTime;
}
else
{
@@ -18314,7 +18504,16 @@ void Player::LeaveBattleground(bool teleportToEntryPoint)
if( bg->isBattleGround() && !isGameMaster() && sWorld.getConfig(CONFIG_BATTLEGROUND_CAST_DESERTER) )
{
if( bg->GetStatus() == STATUS_IN_PROGRESS || bg->GetStatus() == STATUS_WAIT_JOIN )
+ {
+ //lets check if player was teleported from BG and schedule delayed Deserter spell cast
+ if(IsBeingTeleportedFar())
+ {
+ ScheduleDelayedOperation(DELAYED_SPELL_CAST_DESERTER);
+ return;
+ }
+
CastSpell(this, 26013, true); // Deserter
+ }
}
}
}
@@ -18322,7 +18521,7 @@ void Player::LeaveBattleground(bool teleportToEntryPoint)
bool Player::CanJoinToBattleground() const
{
// check Deserter debuff
- if(GetDummyAura(26013))
+ if(HasAura(26013))
return false;
return true;
@@ -18558,7 +18757,7 @@ void Player::UpdateVisibilityOf(WorldObject* target)
{
if(HaveAtClient(target))
{
- if(!target->isVisibleForInState(this,true))
+ if(!target->isVisibleForInState(this, true))
{
target->DestroyForPlayer(this);
m_clientGUIDs.erase(target->GetGUID());
@@ -18656,17 +18855,19 @@ void Player::SendComboPoints()
}
}
-void Player::AddComboPoints(Unit* target, int8 count)
+void Player::AddComboPoints(Unit* target, int8 count, Spell * spell)
{
if(!count)
return;
+ int8 * comboPoints = spell ? &spell->m_comboPointGain : &m_comboPoints;
+
// without combo points lost (duration checked in aura)
RemoveAurasByType(SPELL_AURA_RETAIN_COMBO_POINTS);
if(target->GetGUID() == m_comboTarget)
{
- m_comboPoints += count;
+ *comboPoints += count;
}
else
{
@@ -18675,13 +18876,26 @@ void Player::AddComboPoints(Unit* target, int8 count)
target2->RemoveComboPointHolder(GetGUIDLow());
m_comboTarget = target->GetGUID();
- m_comboPoints = count;
+ *comboPoints = count;
target->AddComboPointHolder(GetGUIDLow());
}
+ if (*comboPoints > 5) *comboPoints = 5;
+ else if (*comboPoints < 0) *comboPoints = 0;
+
+ if (!spell)
+ SendComboPoints();
+}
+
+void Player::GainSpellComboPoints(int8 count)
+{
+ if(!count)
+ return;
+
+ m_comboPoints += count;
if (m_comboPoints > 5) m_comboPoints = 5;
- if (m_comboPoints < 0) m_comboPoints = 0;
+ else if (m_comboPoints < 0) m_comboPoints = 0;
SendComboPoints();
}
@@ -18746,11 +18960,6 @@ void Player::SendInitialPacketsBeforeAddToMap()
m_reputationMgr.SendInitialReputations();
m_achievementMgr.SendAllAchievementData();
- // update zone
- uint32 newzone, newarea;
- GetZoneAndAreaId(newzone,newarea);
- UpdateZone(newzone,newarea); // also call SendInitWorldStates();
-
SendEquipmentSetList();
data.Initialize(SMSG_LOGIN_SETTIMESPEED, 4 + 4 + 4);
@@ -18762,6 +18971,11 @@ void Player::SendInitialPacketsBeforeAddToMap()
void Player::SendInitialPacketsAfterAddToMap()
{
+ // update zone
+ uint32 newzone, newarea;
+ GetZoneAndAreaId(newzone,newarea);
+ UpdateZone(newzone,newarea); // also call SendInitWorldStates();
+
WorldPacket data(SMSG_TIME_SYNC_REQ, 4); // new 2.0.x, enable movement
data << uint32(0x00000000); // on blizz it increments periodically
GetSession()->SendPacket(&data);
@@ -18883,17 +19097,14 @@ void Player::resetSpells()
{
// not need after this call
if(HasAtLoginFlag(AT_LOGIN_RESET_SPELLS))
- {
- m_atLoginFlags = m_atLoginFlags & ~AT_LOGIN_RESET_SPELLS;
- CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login & ~ %u WHERE guid ='%u'", uint32(AT_LOGIN_RESET_SPELLS), GetGUIDLow());
- }
+ RemoveAtLoginFlag(AT_LOGIN_RESET_SPELLS,true);
// make full copy of map (spells removed and marked as deleted at another spell remove
// and we can't use original map for safe iterative with visit each spell at loop end
PlayerSpellMap smap = GetSpellMap();
for(PlayerSpellMap::const_iterator iter = smap.begin();iter != smap.end(); ++iter)
- removeSpell(iter->first); // only iter->first can be accessed, object by iter->second can be deleted already
+ removeSpell(iter->first,false,false); // only iter->first can be accessed, object by iter->second can be deleted already
learnDefaultSpells();
learnQuestRewardedSpells();
@@ -18954,8 +19165,10 @@ void Player::learnQuestRewardedSpells(Quest const* quest)
if(!learnedInfo)
return;
+ uint32 profSpell = spellmgr.GetSpellRequired(learned_0);
+
// specialization
- if(learnedInfo->Effect[0]==SPELL_EFFECT_TRADE_SKILL && learnedInfo->Effect[1]==0)
+ if(learnedInfo->Effect[0]==SPELL_EFFECT_TRADE_SKILL && learnedInfo->Effect[1]==0 && profSpell)
{
// search other specialization for same prof
for(PlayerSpellMap::const_iterator itr = m_spells.begin(); itr != m_spells.end(); ++itr)
@@ -18972,11 +19185,7 @@ void Player::learnQuestRewardedSpells(Quest const* quest)
continue;
// compare same chain spells
- if(spellmgr.GetFirstSpellInChain(itr->first) != first_spell)
- continue;
-
- // now we have 2 specialization, learn possible only if found is lesser specialization rank
- if(!spellmgr.IsHighRankOfSpell(learned_0,itr->first))
+ if (spellmgr.GetSpellRequired(itr->first) == profSpell)
return;
}
}
@@ -19273,7 +19482,7 @@ void Player::SummonIfPossible(bool agree)
if(isInFlight())
{
GetMotionMaster()->MovementExpired();
- m_taxi.ClearTaxiDestinations();
+ CleanupAfterTaxiFlight();
}
// drop flag at summon
@@ -19572,7 +19781,7 @@ bool Player::RewardPlayerAndGroupAtKill(Unit* pVictim)
{
// normal creature (not pet/etc) can be only in !PvP case
if(pVictim->GetTypeId()==TYPEID_UNIT)
- pGroupGuy->KilledMonster(pVictim->GetEntry(), pVictim->GetGUID());
+ pGroupGuy->KilledMonster(((Creature*)pVictim)->GetCreatureInfo(), pVictim->GetGUID());
}
}
}
@@ -19597,7 +19806,7 @@ bool Player::RewardPlayerAndGroupAtKill(Unit* pVictim)
// normal creature (not pet/etc) can be only in !PvP case
if(pVictim->GetTypeId()==TYPEID_UNIT)
- KilledMonster(pVictim->GetEntry(),pVictim->GetGUID());
+ KilledMonster(((Creature*)pVictim)->GetCreatureInfo(), pVictim->GetGUID());
}
}
return xp || honored_kill;
@@ -19621,26 +19830,23 @@ void Player::RewardPlayerAndGroupAtEvent(uint32 creature_id, WorldObject* pRewar
// quest objectives updated only for alive group member or dead but with not released body
if(pGroupGuy->isAlive()|| !pGroupGuy->GetCorpse())
- pGroupGuy->KilledMonster(creature_id, creature_guid);
+ pGroupGuy->KilledMonsterCredit(creature_id, creature_guid);
}
}
else // if (!pGroup)
- KilledMonster(creature_id, creature_guid);
+ KilledMonsterCredit(creature_id, creature_guid);
}
bool Player::IsAtGroupRewardDistance(WorldObject const* pRewardSource) const
{
- if (pRewardSource->IsWithinDistInMap(this,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE)))
- return true;
+ const WorldObject* player = GetCorpse();
+ if(!player || isAlive())
+ player = this;
- if (isAlive())
+ if(player->GetMapId() != pRewardSource->GetMapId() || player->GetInstanceId() != pRewardSource->GetInstanceId())
return false;
- Corpse* corpse = GetCorpse();
- if (!corpse)
- return false;
-
- return pRewardSource->IsWithinDistInMap(corpse,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE));
+ return pRewardSource->GetDistance(player) <= sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE);
}
uint32 Player::GetBaseWeaponSkillValue (WeaponAttackType attType) const
@@ -19662,6 +19868,14 @@ void Player::ResurectUsingRequestData()
if(IS_PLAYER_GUID(m_resurrectGUID))
TeleportTo(m_resurrectMap, m_resurrectX, m_resurrectY, m_resurrectZ, GetOrientation());
+ //we cannot resurrect player when we triggered far teleport
+ //player will be resurrected upon teleportation
+ if(IsBeingTeleportedFar())
+ {
+ ScheduleDelayedOperation(DELAYED_RESURRECT_PLAYER);
+ return;
+ }
+
ResurrectPlayer(0.0f,false);
if(GetMaxHealth() > m_resurrectHealth)
@@ -19693,13 +19907,6 @@ void Player::SetClientControl(Unit* target, uint8 allowMove)
void Player::UpdateZoneDependentAuras( uint32 newZone )
{
- // remove new continent flight forms
- if( !IsAllowUseFlyMountsHere() )
- {
- RemoveAurasByType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED);
- RemoveAurasByType(SPELL_AURA_FLY);
- }
-
// Some spells applied at enter into zone (with subzones), aura removed in UpdateAreaDependentAuras that called always at zone->area update
SpellAreaForAreaMapBounds saBounds = spellmgr.GetSpellAreaForAreaMapBounds(newZone);
for(SpellAreaForAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr)
@@ -20122,7 +20329,7 @@ bool Player::isTotalImmune()
bool Player::HasTitle(uint32 bitIndex)
{
- if (bitIndex > 192)
+ if (bitIndex > MAX_TITLE_INDEX)
return false;
uint32 fieldIndexOffset = bitIndex / 32;
@@ -20130,11 +20337,30 @@ bool Player::HasTitle(uint32 bitIndex)
return HasFlag(PLAYER__FIELD_KNOWN_TITLES + fieldIndexOffset, flag);
}
-void Player::SetTitle(CharTitlesEntry const* title)
+void Player::SetTitle(CharTitlesEntry const* title, bool lost)
{
uint32 fieldIndexOffset = title->bit_index / 32;
uint32 flag = 1 << (title->bit_index % 32);
- SetFlag(PLAYER__FIELD_KNOWN_TITLES + fieldIndexOffset, flag);
+
+ if(lost)
+ {
+ if(!HasFlag(PLAYER__FIELD_KNOWN_TITLES + fieldIndexOffset, flag))
+ return;
+
+ RemoveFlag(PLAYER__FIELD_KNOWN_TITLES + fieldIndexOffset, flag);
+ }
+ else
+ {
+ if(HasFlag(PLAYER__FIELD_KNOWN_TITLES + fieldIndexOffset, flag))
+ return;
+
+ SetFlag(PLAYER__FIELD_KNOWN_TITLES + fieldIndexOffset, flag);
+ }
+
+ WorldPacket data(SMSG_TITLE_EARNED, 4 + 4);
+ data << uint32(title->bit_index);
+ data << uint32(lost ? 0 : 1); // 1 - earned, 0 - lost
+ GetSession()->SendPacket(&data);
}
/*-----------------------TRINITY--------------------------*/
@@ -20230,6 +20456,7 @@ void Player::InitRunes()
m_runes = new Runes;
m_runes->runeState = 0;
+ m_runes->lastUsedRune = RUNE_BLOOD;
for(uint32 i = 0; i < MAX_RUNES; ++i)
{
@@ -20272,29 +20499,25 @@ void Player::AutoStoreLoot(uint8 bag, uint8 slot, uint32 loot_id, LootStore cons
uint32 Player::CalculateTalentsPoints() const
{
- uint32 base_talent = getLevel() < 10 ? 0 : uint32((getLevel()-9)*sWorld.getRate(RATE_TALENT));
+ uint32 base_talent = getLevel() < 10 ? 0 : getLevel()-9;
- if(getClass() != CLASS_DEATH_KNIGHT)
- return base_talent;
+ if(getClass() != CLASS_DEATH_KNIGHT || GetMapId() != 609)
+ return uint32(base_talent * sWorld.getRate(RATE_TALENT));
- uint32 talentPointsForLevel =
- (getLevel() < 56 ? 0 : uint32((getLevel()-55)*sWorld.getRate(RATE_TALENT)))
- + m_questRewardTalentCount;
+ uint32 talentPointsForLevel = getLevel() < 56 ? 0 : getLevel() - 55;
+ talentPointsForLevel += m_questRewardTalentCount;
if(talentPointsForLevel > base_talent)
talentPointsForLevel = base_talent;
- return talentPointsForLevel;
+ return uint32(talentPointsForLevel * sWorld.getRate(RATE_TALENT));
}
-bool Player::IsAllowUseFlyMountsHere() const
+bool Player::IsKnowHowFlyIn(uint32 mapid, uint32 zone) const
{
- if (isGameMaster())
- return true;
-
- uint32 zoneId = GetZoneId();
- uint32 v_map = GetVirtualMapForMapAndZone(GetMapId(), zoneId);
- return v_map == 530 || v_map == 571 && HasSpell(54197) && zoneId != 4197;
+ // continent checked in SpellMgr::GetSpellAllowedInLocationError at cast and area update
+ uint32 v_map = GetVirtualMapForMapAndZone(mapid, zone);
+ return v_map != 571 || HasSpell(54197) && zone != 4197; // Cold Weather Flying
}
void Player::learnSpellHighRank(uint32 spellid)
@@ -20484,7 +20707,7 @@ void Player::HandleFall(MovementInfo const& movementInfo)
damage = GetMaxHealth();
// Gust of Wind
- if (GetDummyAura(43621))
+ if (HasAura(43621))
damage = GetMaxHealth()/2;
EnvironmentalDamage(DAMAGE_FALL, damage);
@@ -20502,7 +20725,12 @@ void Player::HandleFall(MovementInfo const& movementInfo)
void Player::UpdateAchievementCriteria( AchievementCriteriaTypes type, uint32 miscvalue1/*=0*/, uint32 miscvalue2/*=0*/, Unit *unit/*=NULL*/, uint32 time/*=0*/ )
{
- GetAchievementMgr().UpdateAchievementCriteria(type, miscvalue1,miscvalue2,unit,time);
+ GetAchievementMgr().UpdateAchievementCriteria(type, miscvalue1, miscvalue2, unit, time);
+}
+
+void Player::CompletedAchievement(AchievementEntry const* entry)
+{
+ GetAchievementMgr().CompletedAchievement(entry);
}
void Player::LearnTalent(uint32 talentId, uint32 talentRank)
@@ -21130,3 +21358,37 @@ void Player::ActivateSpec(uint32 specNum)
resetTalents(true);
}
+
+void Player::RemoveAtLoginFlag( AtLoginFlags f, bool in_db_also /*= false*/ )
+{
+ m_atLoginFlags &= ~f;
+
+ if(in_db_also)
+ CharacterDatabase.PExecute("UPDATE characters set at_login = at_login & ~ %u WHERE guid ='%u'", uint32(f), GetGUIDLow());
+}
+
+void Player::SendClearCooldown( uint32 spell_id, Unit* target )
+{
+ WorldPacket data(SMSG_CLEAR_COOLDOWN, 4+8);
+ data << uint32(spell_id);
+ data << uint64(target->GetGUID());
+ SendDirectMessage(&data);
+}
+
+void Player::ResetMap()
+{
+ // this may be called during Map::Update
+ // after decrement+unlink, ++m_mapRefIter will continue correctly
+ // when the first element of the list is being removed
+ // nocheck_prev will return the padding element of the RefManager
+ // instead of NULL in the case of prev
+ GetMap()->UpdateIteratorBack(this);
+ Unit::ResetMap();
+ GetMapRef().unlink();
+}
+
+void Player::SetMap(Map * map)
+{
+ Unit::SetMap(map);
+ m_mapRef.link(map, this);
+}