diff options
-rw-r--r-- | src/game/Player.cpp | 796 | ||||
-rw-r--r-- | src/game/Player.h | 137 |
2 files changed, 576 insertions, 357 deletions
diff --git a/src/game/Player.cpp b/src/game/Player.cpp index 5d33d75f92b..c38835b7237 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -119,6 +119,14 @@ enum CharacterFlags CHARACTER_FLAG_UNK32 = 0x80000000 }; +enum CharacterCustomizeFlags +{ + CHAR_CUSTOMIZE_FLAG_NONE = 0x00000000, + CHAR_CUSTOMIZE_FLAG_CUSTOMIZE = 0x00000001, // name, gender, etc... + CHAR_CUSTOMIZE_FLAG_FACTION = 0x00010000, // name, gender, faction, etc... + CHAR_CUSTOMIZE_FLAG_RACE = 0x00100000 // name, gender, race, etc... +}; + // corpse reclaim times #define DEATH_EXPIRE_STEP (5*MINUTE) #define MAX_DEATH_COUNT 3 @@ -422,7 +430,8 @@ Player::Player (WorldSession *session): Unit(), m_achievementMgr(this), m_reputa m_HomebindTimer = 0; m_InstanceValid = true; - m_dungeonDifficulty = DIFFICULTY_NORMAL; + m_dungeonDifficulty = DUNGEON_DIFFICULTY_NORMAL; + m_raidDifficulty = RAID_DIFFICULTY_10MAN_NORMAL; m_lastPotionId = 0; @@ -449,6 +458,7 @@ Player::Player (WorldSession *session): Unit(), m_achievementMgr(this), m_reputa m_baseSpellPower = 0; m_baseFeralAP = 0; m_baseManaRegen = 0; + m_baseHealthRegen = 0; // Honor System m_lastHonorUpdateTime = time(NULL); @@ -541,7 +551,7 @@ void Player::CleanupsBeforeDelete() m_transport->RemovePassenger(this); // clean up player-instance binds, may unload some instance saves - for (uint8 i = 0; i < TOTAL_DIFFICULTIES; ++i) + for (uint8 i = 0; i < MAX_DIFFICULTY; ++i) for (BoundInstancesMap::iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end(); ++itr) itr->second.save->RemovePlayer(this); } @@ -1142,7 +1152,7 @@ void Player::Update( uint32 p_time ) //sLog.outCrash("Player has m_pad %u during update!", m_pad); //if(m_spellModTakingSpell) sLog.outCrash("Player has m_spellModTakingSpell %u during update!", m_spellModTakingSpell->m_spellInfo->Id); - return; + return; m_spellModTakingSpell = NULL; } @@ -1515,8 +1525,8 @@ bool Player::BuildEnumData( QueryResult * result, WorldPacket * p_data ) char_flags |= CHARACTER_FLAG_DECLINED; *p_data << uint32(char_flags); // character flags - // character customize (flags?) - *p_data << uint32(atLoginFlags & AT_LOGIN_CUSTOMIZE ? 1 : 0); + // character customize flags + *p_data << uint32(atLoginFlags & AT_LOGIN_CUSTOMIZE ? CHAR_CUSTOMIZE_FLAG_CUSTOMIZE : CHAR_CUSTOMIZE_FLAG_NONE); *p_data << uint8(1); // unknown // Pets info @@ -1707,6 +1717,7 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati m_movementInfo.t_z = 0.0f; m_movementInfo.t_o = 0.0f; m_movementInfo.t_time = 0; + m_movementInfo.t_seat = -1; } } @@ -2170,6 +2181,7 @@ void Player::RegenerateHealth() // always regeneration bonus (including combat) addvalue += GetTotalAuraModifier(SPELL_AURA_MOD_HEALTH_REGEN_IN_COMBAT); + addvalue += m_baseHealthRegen / 2.5f; if (addvalue < 0) addvalue = 0; @@ -2448,6 +2460,9 @@ void Player::GiveXP(uint32 xp, Unit* victim) if(!isAlive()) return; + if(HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_NO_XP_GAIN)) + return; + uint8 level = getLevel(); // Favored experience increase START @@ -2557,9 +2572,6 @@ void Player::GiveLevel(uint8 level) if (Pet* pet = GetPet()) pet->SynchronizeLevelWithOwner(); - if (MailLevelReward const* mailReward = objmgr.GetMailLevelReward(level,getRaceMask())) - MailDraft(mailReward->mailTemplateId).SendMailTo(this,MailSender(MAIL_CREATURE,mailReward->senderEntry)); - GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL); } @@ -2617,6 +2629,9 @@ void Player::InitStatsForLevel(bool reapplyMods) SetUInt32Value(PLAYER_FIELD_MAX_LEVEL, sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL) ); SetUInt32Value(PLAYER_NEXT_LEVEL_XP, objmgr.GetXPForLevel(getLevel())); + // reset before any aura state sources (health set/aura apply) + SetUInt32Value(UNIT_FIELD_AURASTATE, 0); + UpdateSkillsForLevel (); // set default cast time multiplier @@ -2916,7 +2931,7 @@ bool Player::AddTalent(uint32 spell_id, uint8 spec, bool learning) return false; } - if (!SpellMgr::IsSpellValid(spellInfo,this,false)) + if(!SpellMgr::IsSpellValid(spellInfo,this,false)) { // do character spell book cleanup (all characters) if(!IsInWorld() && !learning) // spell load case @@ -2968,7 +2983,7 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen if (!spellInfo) { // do character spell book cleanup (all characters) - if (!IsInWorld() && !learning) // spell load case + if(!IsInWorld() && !learning) // spell load case { sLog.outError("Player::addSpell: Non-existed in SpellStore spell #%u request, deleting for all characters in `character_spell`.",spell_id); CharacterDatabase.PExecute("DELETE FROM character_spell WHERE spell = '%u'",spell_id); @@ -2979,7 +2994,7 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen return false; } - if (!SpellMgr::IsSpellValid(spellInfo,this,false)) + if(!SpellMgr::IsSpellValid(spellInfo,this,false)) { // do character spell book cleanup (all characters) if(!IsInWorld() && !learning) // spell load case @@ -3008,11 +3023,11 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen { uint32 next_active_spell_id = 0; // fix activate state for non-stackable low rank (and find next spell for !active case) - if (!SpellMgr::canStackSpellRanks(spellInfo) && spellmgr.GetSpellRank(spellInfo->Id) != 0) + if(!SpellMgr::canStackSpellRanks(spellInfo) && spellmgr.GetSpellRank(spellInfo->Id) != 0) { - if (uint32 next = spellmgr.GetNextSpellInChain(spell_id)) + if(uint32 next = spellmgr.GetNextSpellInChain(spell_id)) { - if (HasSpell(next)) + if(HasSpell(next)) { // high rank already known so this must !active active = false; @@ -3022,10 +3037,10 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen } // not do anything if already known in expected state - if (itr->second->state != PLAYERSPELL_REMOVED && itr->second->active == active && + if(itr->second->state != PLAYERSPELL_REMOVED && itr->second->active == active && itr->second->dependent == dependent && itr->second->disabled == disabled) { - if (!IsInWorld() && !learning) // explicitly load from DB and then exist in it already and set correctly + if(!IsInWorld() && !learning) // explicitly load from DB and then exist in it already and set correctly itr->second->state = PLAYERSPELL_UNCHANGED; return false; @@ -3041,21 +3056,21 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen } // update active state for known spell - if (itr->second->active != active && itr->second->state != PLAYERSPELL_REMOVED && !itr->second->disabled) + if(itr->second->active != active && itr->second->state != PLAYERSPELL_REMOVED && !itr->second->disabled) { itr->second->active = active; - if (!IsInWorld() && !learning && !dependent_set) // explicitly load from DB and then exist in it already and set correctly + if(!IsInWorld() && !learning && !dependent_set) // explicitly load from DB and then exist in it already and set correctly itr->second->state = PLAYERSPELL_UNCHANGED; - else if (itr->second->state != PLAYERSPELL_NEW) + else if(itr->second->state != PLAYERSPELL_NEW) itr->second->state = PLAYERSPELL_CHANGED; - if (active) + if(active) { if (IsPassiveSpell(spell_id) && IsNeedCastPassiveSpellAtLearn(spellInfo)) - CastSpell(this, spell_id, true); + CastSpell (this,spell_id,true); } - else if (IsInWorld()) + else if(IsInWorld()) { if(next_active_spell_id) { @@ -3063,7 +3078,7 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen WorldPacket data(SMSG_SUPERCEDED_SPELL, 4 + 4); data << uint32(spell_id); data << uint32(next_active_spell_id); - GetSession()->SendPacket(&data); + GetSession()->SendPacket( &data ); } else { @@ -3076,18 +3091,18 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen return active; // learn (show in spell book if active now) } - if (itr->second->disabled != disabled && itr->second->state != PLAYERSPELL_REMOVED) + if(itr->second->disabled != disabled && itr->second->state != PLAYERSPELL_REMOVED) { - if (itr->second->state != PLAYERSPELL_NEW) + if(itr->second->state != PLAYERSPELL_NEW) itr->second->state = PLAYERSPELL_CHANGED; itr->second->disabled = disabled; - if (disabled) + if(disabled) return false; disabled_case = true; } - else switch (itr->second->state) + else switch(itr->second->state) { case PLAYERSPELL_UNCHANGED: // known saved spell return false; @@ -3101,7 +3116,7 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen default: // known not saved yet spell (new or modified) { // can be in case spell loading but learned at some previous spell loading - if (!IsInWorld() && !learning && !dependent_set) + if(!IsInWorld() && !learning && !dependent_set) itr->second->state = PLAYERSPELL_UNCHANGED; return false; @@ -3109,19 +3124,18 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen } } - // skip new spell adding if spell already known (disabled spells case) - if (!disabled_case) + if(!disabled_case) // skip new spell adding if spell already known (disabled spells case) { // talent: unlearn all other talent ranks (high and low) - if (TalentSpellPos const *talentPos = GetTalentSpellPos(spell_id)) + if(TalentSpellPos const *talentPos = GetTalentSpellPos(spell_id)) { - if (TalentEntry const *talentInfo = sTalentStore.LookupEntry( talentPos->talent_id )) + if(TalentEntry const *talentInfo = sTalentStore.LookupEntry( talentPos->talent_id )) { for (uint8 rank = 0; rank < MAX_TALENT_RANK; ++rank) { // skip learning spell and no rank spell case uint32 rankSpellId = talentInfo->RankID[rank]; - if (!rankSpellId || rankSpellId == spell_id) + if(!rankSpellId || rankSpellId == spell_id) continue; removeSpell(rankSpellId,false,false); @@ -3129,9 +3143,9 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen } } // non talent spell: learn low ranks (recursive call) - else if (uint32 prev_spell = spellmgr.GetPrevSpellInChain(spell_id)) + else if(uint32 prev_spell = spellmgr.GetPrevSpellInChain(spell_id)) { - if (!IsInWorld() || disabled) // at spells loading, no output, but allow save + if(!IsInWorld() || disabled) // at spells loading, no output, but allow save addSpell(prev_spell,active,true,true,disabled); else // at normal learning learnSpell(prev_spell,true); @@ -3144,23 +3158,21 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen newspell->disabled = disabled; // replace spells in action bars and spellbook to bigger rank if only one spell rank must be accessible - if (newspell->active && !newspell->disabled && !SpellMgr::canStackSpellRanks(spellInfo) && spellmgr.GetSpellRank(spellInfo->Id) != 0) + if(newspell->active && !newspell->disabled && !SpellMgr::canStackSpellRanks(spellInfo) && spellmgr.GetSpellRank(spellInfo->Id) != 0) { for (PlayerSpellMap::iterator itr2 = m_spells.begin(); itr2 != m_spells.end(); ++itr2 ) { - if (itr2->second->state == PLAYERSPELL_REMOVED) - continue; + if(itr2->second->state == PLAYERSPELL_REMOVED) continue; SpellEntry const *i_spellInfo = sSpellStore.LookupEntry(itr2->first); - if (!i_spellInfo) - continue; + if(!i_spellInfo) continue; - if (spellmgr.IsRankSpellDueToSpell(spellInfo,itr2->first)) + if( spellmgr.IsRankSpellDueToSpell(spellInfo,itr2->first) ) { - if (itr2->second->active) + if(itr2->second->active) { - if (spellmgr.IsHighRankOfSpell(spell_id,itr2->first)) + if(spellmgr.IsHighRankOfSpell(spell_id,itr2->first)) { - if (IsInWorld()) // not send spell (re-/over-)learn packets at loading + if(IsInWorld()) // not send spell (re-/over-)learn packets at loading { WorldPacket data(SMSG_SUPERCEDED_SPELL, 4 + 4); data << uint32(itr2->first); @@ -3174,19 +3186,19 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen itr2->second->state = PLAYERSPELL_CHANGED; superceded_old = true; // new spell replace old in action bars and spell book. } - else if (spellmgr.IsHighRankOfSpell(itr2->first, spell_id)) + else if(spellmgr.IsHighRankOfSpell(itr2->first,spell_id)) { - if (IsInWorld()) // not send spell (re-/over-)learn packets at loading + if(IsInWorld()) // not send spell (re-/over-)learn packets at loading { WorldPacket data(SMSG_SUPERCEDED_SPELL, 4 + 4); data << uint32(spell_id); data << uint32(itr2->first); - GetSession()->SendPacket(&data); + GetSession()->SendPacket( &data ); } // mark new spell as disable (not learned yet for client and will not learned) newspell->active = false; - if (newspell->state != PLAYERSPELL_NEW) + if(newspell->state != PLAYERSPELL_NEW) newspell->state = PLAYERSPELL_CHANGED; } } @@ -3228,7 +3240,7 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen // update free primary prof.points (if any, can be none in case GM .learn prof. learning) if (uint32 freeProfs = GetFreePrimaryProfessionPoints()) { - if (spellmgr.IsPrimaryProfessionFirstRankSpell(spell_id)) + if(spellmgr.IsPrimaryProfessionFirstRankSpell(spell_id)) SetFreePrimaryProfessions(freeProfs-1); } @@ -3252,7 +3264,7 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen if (skill_max_value < new_skill_max_value) skill_max_value = new_skill_max_value; - SetSkill(spellLearnSkill->skill, skill_value, skill_max_value); + SetSkill(spellLearnSkill->skill,skill_value,skill_max_value); } else { @@ -3270,16 +3282,16 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen // lockpicking/runeforging special case, not have ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL ((pSkill->id==SKILL_LOCKPICKING || pSkill->id==SKILL_RUNEFORGING) && _spell_idx->second->max_value==0)) { - switch (GetSkillRangeType(pSkill,_spell_idx->second->racemask!=0)) + switch(GetSkillRangeType(pSkill,_spell_idx->second->racemask!=0)) { case SKILL_RANGE_LANGUAGE: - SetSkill(pSkill->id, 300, 300); + SetSkill(pSkill->id, 300, 300 ); break; case SKILL_RANGE_LEVEL: - SetSkill(pSkill->id, 1, GetMaxSkillValueForLevel()); + SetSkill(pSkill->id, 1, GetMaxSkillValueForLevel() ); break; case SKILL_RANGE_MONO: - SetSkill(pSkill->id, 1, 1); + SetSkill(pSkill->id, 1, 1 ); break; default: break; @@ -3296,9 +3308,9 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen if (!itr2->second.autoLearned) { if (!IsInWorld() || !itr2->second.active) // at spells loading, no output, but allow save - addSpell(itr2->second.spell, itr2->second.active, true, true, false); + addSpell(itr2->second.spell,itr2->second.active,true,true,false); else // at normal learning - learnSpell(itr2->second.spell, true); + learnSpell(itr2->second.spell,true); } } @@ -3398,13 +3410,13 @@ void Player::removeSpell(uint32 spell_id, bool disabled, bool learn_low_rank) if (SpellChainNode const* node = spellmgr.GetSpellChainNode(spell_id)) { if (HasSpell(node->next) && !GetTalentSpellPos(node->next)) - removeSpell(node->next,disabled); + removeSpell(node->next,disabled); } //unlearn spells dependent from recently removed spells 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, false); + removeSpell(itr2->second,disabled,false); // re-search, it can be corrupted in prev loop itr = m_spells.find(spell_id); @@ -3510,7 +3522,7 @@ void Player::removeSpell(uint32 spell_id, bool disabled, bool learn_low_rank) ((pSkill->id == SKILL_LOCKPICKING || pSkill->id == SKILL_RUNEFORGING) && _spell_idx->second->max_value == 0)) { // not reset skills for professions and racial abilities - if ((pSkill->categoryId == SKILL_CATEGORY_SECONDARY || pSkill->categoryId == SKILL_CATEGORY_PROFESSION) && + if ((pSkill->categoryId==SKILL_CATEGORY_SECONDARY || pSkill->categoryId==SKILL_CATEGORY_PROFESSION) && (IsProfessionSkill(pSkill->id) || _spell_idx->second->racemask!=0)) continue; @@ -3722,7 +3734,7 @@ void Player::_SaveSpellCooldowns() } // if something changed execute if (!first_round) - CharacterDatabase.Execute(ss.str().c_str()); + CharacterDatabase.Execute( ss.str().c_str() ); } uint32 Player::resetTalentsCost() const @@ -3858,19 +3870,19 @@ Mail* Player::GetMail(uint32 id) void Player::_SetCreateBits(UpdateMask *updateMask, Player *target) const { - if (target == this) + if(target == this) Object::_SetCreateBits(updateMask, target); else { for (uint16 index = 0; index < m_valuesCount; index++) - if (GetUInt32Value(index) != 0 && updateVisualBits.GetBit(index)) + if(GetUInt32Value(index) != 0 && updateVisualBits.GetBit(index)) updateMask->SetBit(index); } } void Player::_SetUpdateBits(UpdateMask *updateMask, Player *target) const { - if (target == this) + if(target == this) Object::_SetUpdateBits(updateMask, target); else { @@ -4140,8 +4152,8 @@ void Player::DeleteFromDB(uint64 playerguid, uint32 accountId, bool updateRealmC // remove signs from petitions (also remove petitions if owner); RemovePetitionsAndSigns(playerguid, 10); - // return back all mails with COD and Item 0 1 2 3 4 5 6 7 - QueryResult *resultMail = CharacterDatabase.PQuery("SELECT id,messageType,mailTemplateId,sender,subject,itemTextId,money,has_items FROM mail WHERE receiver='%u' AND has_items<>0 AND cod<>0", guid); + // return back all mails with COD and Item 0 1 2 3 4 5 6 + QueryResult *resultMail = CharacterDatabase.PQuery("SELECT id,mailTemplateId,sender,subject,itemTextId,money,has_items FROM mail WHERE receiver='%u' AND has_items<>0 AND cod<>0", guid); if(resultMail) { do @@ -4149,30 +4161,18 @@ void Player::DeleteFromDB(uint64 playerguid, uint32 accountId, bool updateRealmC Field *fields = resultMail->Fetch(); uint32 mail_id = fields[0].GetUInt32(); - uint16 mailType = fields[1].GetUInt16(); - uint16 mailTemplateId= fields[2].GetUInt16(); - uint32 sender = fields[3].GetUInt32(); - std::string subject = fields[4].GetCppString(); - uint32 itemTextId = fields[5].GetUInt32(); - uint32 money = fields[6].GetUInt32(); - bool has_items = fields[7].GetBool(); + uint16 mailTemplateId= fields[1].GetUInt16(); + uint32 sender = fields[2].GetUInt32(); + std::string subject = fields[3].GetCppString(); + uint32 itemTextId = fields[4].GetUInt32(); + uint32 money = fields[5].GetUInt32(); + bool has_items = fields[6].GetBool(); //we can return mail now //so firstly delete the old one CharacterDatabase.PExecute("DELETE FROM mail WHERE id = '%u'", mail_id); - // mail not from player - if (mailType != MAIL_NORMAL) - { - if(has_items) - CharacterDatabase.PExecute("DELETE FROM mail_items WHERE mail_id = '%u'", mail_id); - continue; - } - - MailDraft draft(subject, itemTextId); - if (mailTemplateId) - draft = MailDraft(mailTemplateId,false); // itesm already included - + MailItemsInfo mi; if(has_items) { // data needs to be at first place for Item::LoadFromDB @@ -4201,7 +4201,7 @@ void Player::DeleteFromDB(uint64 playerguid, uint32 accountId, bool updateRealmC continue; } - draft.AddItem(pItem); + mi.AddItem(item_guidlow, item_template, pItem); } while (resultItems->NextRow()); @@ -4213,7 +4213,7 @@ void Player::DeleteFromDB(uint64 playerguid, uint32 accountId, bool updateRealmC uint32 pl_account = objmgr.GetPlayerAccountIdByGUID(MAKE_NEW_GUID(guid, 0, HIGHGUID_PLAYER)); - draft.AddMoney(money).SendReturnToSender(pl_account, guid, sender); + WorldSession::SendReturnToSender(MAIL_NORMAL, pl_account, guid, sender, subject, itemTextId, &mi, money, mailTemplateId); } while (resultMail->NextRow()); @@ -4248,6 +4248,7 @@ void Player::DeleteFromDB(uint64 playerguid, uint32 accountId, bool updateRealmC CharacterDatabase.PExecute("DELETE FROM group_instance WHERE leaderGuid = '%u'",guid); CharacterDatabase.PExecute("DELETE FROM groups WHERE leaderGuid = '%u'",guid); CharacterDatabase.PExecute("DELETE FROM group_member WHERE leaderGuid = '%u' OR memberGuid = '%u'",guid,guid); + CharacterDatabase.PExecute("DELETE FROM groups WHERE leaderGuid = '%u'",guid); CharacterDatabase.PExecute("DELETE FROM character_inventory WHERE guid = '%u'",guid); CharacterDatabase.PExecute("DELETE FROM character_queststatus WHERE guid = '%u'",guid); CharacterDatabase.PExecute("DELETE FROM character_reputation WHERE guid = '%u'",guid); @@ -4272,8 +4273,12 @@ void Player::DeleteFromDB(uint64 playerguid, uint32 accountId, bool updateRealmC CharacterDatabase.PExecute("DELETE FROM character_battleground_data WHERE guid = '%u'",guid); CharacterDatabase.PExecute("DELETE FROM character_glyphs WHERE guid = '%u'",guid); CharacterDatabase.PExecute("DELETE FROM character_queststatus_daily WHERE guid = '%u'",guid); + CharacterDatabase.PExecute("DELETE FROM character_battleground_data WHERE guid = '%u'",guid); + CharacterDatabase.PExecute("DELETE FROM character_glyphs WHERE guid = '%u'",guid); + CharacterDatabase.PExecute("DELETE FROM character_queststatus_daily WHERE guid = '%u'",guid); CharacterDatabase.PExecute("DELETE FROM character_talent WHERE guid = '%u'",guid); CharacterDatabase.PExecute("DELETE FROM character_skills WHERE guid = '%u'",guid); + CharacterDatabase.CommitTransaction(); //loginDatabase.PExecute("UPDATE realmcharacters SET numchars = numchars - 1 WHERE acctid = %d AND realmid = %d", accountId, realmID); @@ -4540,17 +4545,17 @@ void Player::CreateCorpse() corpse->SetUInt32Value( CORPSE_FIELD_GUILD, GetGuildId() ); uint32 iDisplayID; - uint16 iIventoryType; + uint32 iIventoryType; uint32 _cfi; for (uint8 i = 0; i < EQUIPMENT_SLOT_END; i++) { if(m_items[i]) { iDisplayID = m_items[i]->GetProto()->DisplayInfoID; - iIventoryType = (uint16)m_items[i]->GetProto()->InventoryType; + iIventoryType = m_items[i]->GetProto()->InventoryType; - _cfi = (uint16(iDisplayID)) | (iIventoryType)<< 24; - corpse->SetUInt32Value(CORPSE_FIELD_ITEM + i,_cfi); + _cfi = iDisplayID | (iIventoryType << 24); + corpse->SetUInt32Value(CORPSE_FIELD_ITEM + i, _cfi); } } @@ -5111,6 +5116,15 @@ uint32 Player::GetMeleeCritDamageReduction(uint32 damage) const return uint32 (melee * damage /100.0f); } +uint32 Player::GetMeleeDamageReduction(uint32 damage) const +{ + float rate = GetRatingBonusValue(CR_CRIT_TAKEN_MELEE); + // Resilience not limited (limit it by 100%) + if (rate > 100.0f) + rate = 100.0f; + return uint32 (rate * damage / 100.0f); +} + uint32 Player::GetRangedCritDamageReduction(uint32 damage) const { float ranged = GetRatingBonusValue(CR_CRIT_TAKEN_RANGED)*2.2f; @@ -5118,6 +5132,15 @@ uint32 Player::GetRangedCritDamageReduction(uint32 damage) const return uint32 (ranged * damage /100.0f); } +uint32 Player::GetRangedDamageReduction(uint32 damage) const +{ + float rate = GetRatingBonusValue(CR_CRIT_TAKEN_RANGED); + // Resilience not limited (limit it by 100%) + if (rate > 100.0f) + rate = 100.0f; + return uint32 (rate * damage / 100.0f); +} + uint32 Player::GetSpellCritDamageReduction(uint32 damage) const { float spell = GetRatingBonusValue(CR_CRIT_TAKEN_SPELL)*2.2f; @@ -5127,13 +5150,13 @@ uint32 Player::GetSpellCritDamageReduction(uint32 damage) const return uint32 (spell * damage / 100.0f); } -uint32 Player::GetDotDamageReduction(uint32 damage) const +uint32 Player::GetSpellDamageReduction(uint32 damage) const { - float spellDot = GetRatingBonusValue(CR_CRIT_TAKEN_SPELL); - // Dot resilience not limited (limit it by 100%) - if (spellDot > 100.0f) - spellDot = 100.0f; - return uint32 (spellDot * damage / 100.0f); + float rate = GetRatingBonusValue(CR_CRIT_TAKEN_SPELL); + // Resilience not limited (limit it by 100%) + if (rate > 100.0f) + rate = 100.0f; + return uint32 (rate * damage / 100.0f); } float Player::GetExpertiseDodgeOrParryReduction(WeaponAttackType attType) const @@ -5456,7 +5479,7 @@ bool Player::UpdateSkillPro(uint16 SkillId, int32 Chance, uint32 step) uint16 SkillValue = SKILL_VALUE(data); uint16 MaxValue = SKILL_MAX(data); - if (!MaxValue || !SkillValue || SkillValue >= MaxValue ) + if ( !MaxValue || !SkillValue || SkillValue >= MaxValue ) return false; int32 Roll = irand(1,1000); @@ -5874,7 +5897,7 @@ 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() ); + sLog.outError( "Action %u not added into button %u for player %s: button must be < 144", action, button, GetName() ); return NULL; } @@ -6001,7 +6024,6 @@ void Player::SendMessageToSet(WorldPacket *data, bool self) // we use World::GetMaxVisibleDistance() because i cannot see why not use a distance // update: replaced by GetMap()->GetVisibilityDistance() - Trinity::MessageDistDeliverer notifier(this, data, GetMap()->GetVisibilityDistance()); VisitNearbyWorldObject(GetMap()->GetVisibilityDistance(), notifier); } @@ -6025,7 +6047,7 @@ void Player::SendMessageToSetInRange(WorldPacket *data, float dist, bool self, b } void Player::SendDirectMessage(WorldPacket *data) -{ +{ if (m_session) m_session->SendPacket(data); } @@ -6212,7 +6234,7 @@ void Player::RewardReputation(Unit *pVictim, float rate) Map const *pMap = GetMap(); if(pMap && pMap->IsDungeon()) { - bool Heroic = pMap->IsHeroic(); + bool Heroic = ((InstanceMap*)pMap)->GetDifficulty() == DUNGEON_DIFFICULTY_HEROIC; InstanceTemplate const *pInstance = objmgr.GetInstanceTemplate(pMap->GetId()); if(pInstance) @@ -6348,6 +6370,7 @@ bool Player::RewardHonor(Unit *uVictim, uint32 groupsize, float honor, bool pvpt uint64 victim_guid = 0; uint32 victim_rank = 0; + uint32 rank_diff = 0; time_t now = time(NULL); // need call before fields update to have chance move yesterday data to appropriate fields before today data change. @@ -6500,7 +6523,7 @@ bool Player::RewardHonor(Unit *uVictim, uint32 groupsize, float honor, bool pvpt return true; } -void Player::ModifyHonorPoints( int32 value ) +void Player::ModifyHonorPoints(int32 value) { if(value < 0) { @@ -6513,7 +6536,7 @@ void Player::ModifyHonorPoints( int32 value ) SetUInt32Value(PLAYER_FIELD_HONOR_CURRENCY, GetHonorPoints() < sWorld.getConfig(CONFIG_MAX_HONOR_POINTS) - value ? GetHonorPoints() + value : sWorld.getConfig(CONFIG_MAX_HONOR_POINTS)); } -void Player::ModifyArenaPoints( int32 value ) +void Player::ModifyArenaPoints(int32 value) { if(value < 0) { @@ -6809,7 +6832,7 @@ void Player::DuelComplete(DuelCompleteType type) duel->opponent->AttackStop(); } break; - case DUEL_WON: + case DUEL_WON: GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOSE_DUEL, 1); if (duel->opponent) { @@ -7092,6 +7115,9 @@ void Player::_ApplyItemBonuses(ItemPrototype const *proto, uint8 slot, bool appl case ITEM_MOD_SPELL_POWER: ApplySpellPowerBonus(int32(val), apply); break; + case ITEM_MOD_HEALTH_REGEN: + ApplyHealthRegenBonus(int32(val), apply); + break; // depricated item mods case ITEM_MOD_SPELL_HEALING_DONE: case ITEM_MOD_SPELL_DAMAGE_DONE: @@ -7855,13 +7881,13 @@ void Player::SendLoot(uint64 guid, LootType loot_type) if (go->getLootState() == GO_READY) { - uint32 lootid = go->GetGOInfo()->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)) if( BattleGround *bg = GetBattleGround()) if(bg->GetTypeID() == BATTLEGROUND_AV) - if(!(((BattleGroundAV*)bg)->PlayerCanDoMineQuest(go->GetEntry(), GetTeam()))) + if(!(((BattleGroundAV*)bg)->PlayerCanDoMineQuest(go->GetEntry(),GetTeam()))) { SendLootRelease(guid); return; @@ -7871,11 +7897,11 @@ void Player::SendLoot(uint64 guid, LootType loot_type) { sLog.outDebug(" if(lootid)"); loot->clear(); - loot->FillLoot(lootid, LootTemplates_Gameobject, this, false, false, go->GetLootMode()); + loot->FillLoot(lootid, LootTemplates_Gameobject, this, false, go->GetLootMode()); } if (loot_type == LOOT_FISHING) - go->getFishLoot(loot, this); + go->getFishLoot(loot,this); go->SetLootState(GO_ACTIVATED); } @@ -7900,17 +7926,17 @@ void Player::SendLoot(uint64 guid, LootType loot_type) switch (loot_type) { case LOOT_DISENCHANTING: - loot->FillLoot(item->GetProto()->DisenchantID, LootTemplates_Disenchant, this, true); + loot->FillLoot(item->GetProto()->DisenchantID, LootTemplates_Disenchant, this,true); break; case LOOT_PROSPECTING: - loot->FillLoot(item->GetEntry(), LootTemplates_Prospecting, this, true); + loot->FillLoot(item->GetEntry(), LootTemplates_Prospecting, this,true); break; case LOOT_MILLING: - loot->FillLoot(item->GetEntry(), LootTemplates_Milling, this, true); + loot->FillLoot(item->GetEntry(), LootTemplates_Milling, this,true); break; default: - loot->FillLoot(item->GetEntry(), LootTemplates_Item, this, true); - loot->generateMoneyLoot(item->GetProto()->MinMoneyLoot, item->GetProto()->MaxMoneyLoot); + loot->FillLoot(item->GetEntry(), LootTemplates_Item, this,true); + loot->generateMoneyLoot(item->GetProto()->MinMoneyLoot,item->GetProto()->MaxMoneyLoot); break; } } @@ -8000,7 +8026,7 @@ void Player::SendLoot(uint64 guid, LootType loot_type) loot->clear(); if (uint32 lootid = creature->GetCreatureInfo()->lootid) - loot->FillLoot(lootid, LootTemplates_Creature, recipient, false, false, creature->GetLootMode()); + loot->FillLoot(lootid, LootTemplates_Creature, recipient, false, creature->GetLootMode()); loot->generateMoneyLoot(creature->GetCreatureInfo()->mingold,creature->GetCreatureInfo()->maxgold); @@ -8177,10 +8203,16 @@ void Player::SendInitWorldStates(uint32 zoneid, uint32 areaid) case 3968: NumberOfFields = 11; break; + case 4378: + NumberOfFields = 11; + break; case 3703: NumberOfFields = 11; break; - default: + case 4384: + NumberOfFields = 30; + break; + default: NumberOfFields = 12; break; } @@ -8200,6 +8232,13 @@ void Player::SendInitWorldStates(uint32 zoneid, uint32 areaid) data << uint32(0xC77) << uint32(sWorld.getConfig(CONFIG_ARENA_SEASON_IN_PROGRESS)); // 8 Arena season id data << uint32(0xF3D) << uint32(sWorld.getConfig(CONFIG_ARENA_SEASON_ID)); + + // May be send timer to start Wintergrasp + //if(sWorld.GetWintergrapsState()==4354) + // data << uint32(0x1102) << sWorld.GetWintergrapsTimer(); + //else + // data << uint32(0xEC5) << sWorld.GetWintergrapsTimer(); + // --- if(mapid == 530) // Outland { data << uint32(0x9bf) << uint32(0x0); // 7 @@ -8287,7 +8326,7 @@ void Player::SendInitWorldStates(uint32 zoneid, uint32 areaid) data << uint32(0x532) << uint32(0x1); // 8 frostwolfhut hc data << uint32(0x531) << uint32(0x0); // 9 frostwolfhut ac data << uint32(0x52e) << uint32(0x0); // 10 stormpike firstaid a_a - data << uint32(0x571) << uint32(0x0); // 11 east frostwolf tower horde assaulted - unused + data << uint32(0x571) << uint32(0x0); // 11 east frostwolf tower horde assaulted -unused data << uint32(0x570) << uint32(0x0); // 12 west frostwolf tower horde assaulted - unused data << uint32(0x567) << uint32(0x1); // 13 frostwolfe c data << uint32(0x566) << uint32(0x1); // 14 frostwolfw c @@ -8298,7 +8337,7 @@ void Player::SendInitWorldStates(uint32 zoneid, uint32 areaid) data << uint32(0x518) << uint32(0x0); // 19 stoneheart grave a_a data << uint32(0x517) << uint32(0x0); // 20 stoneheart grave h_a data << uint32(0x574) << uint32(0x0); // 21 1396 unk - data << uint32(0x573) << uint32(0x0); // 22 iceblood tower horde assaulted - unused + data << uint32(0x573) << uint32(0x0); // 22 iceblood tower horde assaulted -unused data << uint32(0x572) << uint32(0x0); // 23 towerpoint horde assaulted - unused data << uint32(0x56f) << uint32(0x0); // 24 1391 unk data << uint32(0x56e) << uint32(0x0); // 25 iceblood a @@ -8625,7 +8664,52 @@ void Player::SendInitWorldStates(uint32 zoneid, uint32 areaid) data << uint32(0xbba) << uint32(0x0); // 9 show } break; + case 4378: // Dalaran Sewers + if (bg && bg->GetTypeID() == BATTLEGROUND_DS) + bg->FillInitialWorldStates(data); + else + { + data << uint32(3601) << uint32(0x0); // 7 gold + data << uint32(3600) << uint32(0x0); // 8 green + data << uint32(3610) << uint32(0x0); // 9 show + } + break; case 3703: // Shattrath City + case 4384: // SA + /*if (bg && bg->GetTypeID() == BATTLEGROUND_SA) + bg->FillInitialWorldStates(data); + else + {*/ + // 1-3 A defend, 4-6 H defend, 7-9 unk defend, 1 - ok, 2 - half destroyed, 3 - destroyed + data << uint32(0xf09) << uint32(0x4); // 7 3849 Gate of Temple + data << uint32(0xe36) << uint32(0x4); // 8 3638 Gate of Yellow Moon + data << uint32(0xe27) << uint32(0x4); // 9 3623 Gate of Green Emerald + data << uint32(0xe24) << uint32(0x4); // 10 3620 Gate of Blue Sapphire + data << uint32(0xe21) << uint32(0x4); // 11 3617 Gate of Red Sun + data << uint32(0xe1e) << uint32(0x4); // 12 3614 Gate of Purple Ametyst + + data << uint32(0xdf3) << uint32(0x0); // 13 3571 bonus timer (1 - on, 0 - off) + data << uint32(0xded) << uint32(0x0); // 14 3565 Horde Attacker + data << uint32(0xdec) << uint32(0x1); // 15 3564 Alliance Attacker + // End Round (timer), better explain this by example, eg. ends in 19:59 -> A:BC + data << uint32(0xde9) << uint32(0x9); // 16 3561 C + data << uint32(0xde8) << uint32(0x5); // 17 3560 B + data << uint32(0xde7) << uint32(0x19); // 18 3559 A + data << uint32(0xe35) << uint32(0x1); // 19 3637 East g - Horde control + data << uint32(0xe34) << uint32(0x1); // 20 3636 West g - Horde control + data << uint32(0xe33) << uint32(0x1); // 21 3635 South g - Horde control + data << uint32(0xe32) << uint32(0x0); // 22 3634 East g - Alliance control + data << uint32(0xe31) << uint32(0x0); // 23 3633 West g - Alliance control + data << uint32(0xe30) << uint32(0x0); // 24 3632 South g - Alliance control + data << uint32(0xe2f) << uint32(0x1); // 25 3631 Chamber of Ancients - Horde control + data << uint32(0xe2e) << uint32(0x0); // 26 3630 Chamber of Ancients - Alliance control + data << uint32(0xe2d) << uint32(0x0); // 27 3629 Beach1 - Horde control + data << uint32(0xe2c) << uint32(0x0); // 28 3628 Beach2 - Horde control + data << uint32(0xe2b) << uint32(0x1); // 29 3627 Beach1 - Alliance control + data << uint32(0xe2a) << uint32(0x1); // 30 3626 Beach2 - Alliance control + // and many unks... + //} + break; break; case 4406: // Ring of Valor if (bg && bg->GetTypeID() == BATTLEGROUND_RV) @@ -8691,7 +8775,7 @@ void Player::SendPetSkillWipeConfirm() /*** STORAGE SYSTEM ***/ /*********************************************************/ -void Player::SetVirtualItemSlot(uint8 i, Item *item) +void Player::SetVirtualItemSlot( uint8 i, Item* item) { assert(i < 3); if (i < 2 && item) @@ -8711,7 +8795,7 @@ void Player::SetVirtualItemSlot(uint8 i, Item *item) } } -void Player::SetSheath(SheathState sheathed) +void Player::SetSheath( SheathState sheathed ) { switch (sheathed) { @@ -8740,7 +8824,7 @@ void Player::SetSheath(SheathState sheathed) Unit::SetSheath(sheathed); // this must visualize Sheath changing for other players... } -uint8 Player::FindEquipSlot(ItemPrototype const* proto, uint32 slot, bool swap) const +uint8 Player::FindEquipSlot( ItemPrototype const* proto, uint32 slot, bool swap ) const { uint8 pClass = getClass(); @@ -8958,10 +9042,10 @@ uint8 Player::CanUnequipItems( uint32 item, uint32 count ) const return res; } -uint32 Player::GetItemCount(uint32 item, bool inBankAlso, Item *skipItem) const +uint32 Player::GetItemCount(uint32 item, bool inBankAlso, Item* skipItem) const { uint32 count = 0; - for (uint8 i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; ++i) + for (uint8 i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; i++) if (Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i)) if (pItem != skipItem && pItem->GetEntry() == item) count += pItem->GetCount(); @@ -9031,21 +9115,21 @@ Item* Player::GetItemByGuid( uint64 guid ) const return NULL; } -Item* Player::GetItemByPos(uint16 pos) const +Item* Player::GetItemByPos( uint16 pos ) const { uint8 bag = pos >> 8; uint8 slot = pos & 255; - return GetItemByPos(bag, slot); + return GetItemByPos( bag, slot ); } Item* Player::GetItemByPos( uint8 bag, uint8 slot ) const { - if (bag == INVENTORY_SLOT_BAG_0 && (slot < BANK_SLOT_BAG_END || (slot >= KEYRING_SLOT_START && slot < CURRENCYTOKEN_SLOT_END))) + if (bag == INVENTORY_SLOT_BAG_0 && ( slot < BANK_SLOT_BAG_END || (slot >= KEYRING_SLOT_START && slot < CURRENCYTOKEN_SLOT_END) )) return m_items[slot]; else if ((bag >= INVENTORY_SLOT_BAG_START && bag < INVENTORY_SLOT_BAG_END) || (bag >= BANK_SLOT_BAG_START && bag < BANK_SLOT_BAG_END)) { - if (Bag *pBag = (Bag*)GetItemByPos(INVENTORY_SLOT_BAG_0, bag)) + if (Bag *pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, bag)) return pBag->GetItemByPos(slot); } return NULL; @@ -9090,9 +9174,9 @@ Item* Player::GetShield(bool useable) const return item; } -uint8 Player::GetAttackBySlot(uint8 slot) +uint8 Player::GetAttackBySlot( uint8 slot ) { - switch (slot) + switch(slot) { case EQUIPMENT_SLOT_MAINHAND: return BASE_ATTACK; case EQUIPMENT_SLOT_OFFHAND: return OFF_ATTACK; @@ -9101,35 +9185,35 @@ uint8 Player::GetAttackBySlot(uint8 slot) } } -bool Player::IsInventoryPos(uint8 bag, uint8 slot) +bool Player::IsInventoryPos( uint8 bag, uint8 slot ) { - if (bag == INVENTORY_SLOT_BAG_0 && slot == NULL_SLOT) + if( bag == INVENTORY_SLOT_BAG_0 && slot == NULL_SLOT ) return true; - if (bag == INVENTORY_SLOT_BAG_0 && slot >= INVENTORY_SLOT_ITEM_START && slot < INVENTORY_SLOT_ITEM_END) + if( bag == INVENTORY_SLOT_BAG_0 && ( slot >= INVENTORY_SLOT_ITEM_START && slot < INVENTORY_SLOT_ITEM_END ) ) return true; - if (bag >= INVENTORY_SLOT_BAG_START && bag < INVENTORY_SLOT_BAG_END) + if( bag >= INVENTORY_SLOT_BAG_START && bag < INVENTORY_SLOT_BAG_END ) return true; - if (bag == INVENTORY_SLOT_BAG_0 && slot >= KEYRING_SLOT_START && slot < CURRENCYTOKEN_SLOT_END) + if( bag == INVENTORY_SLOT_BAG_0 && ( slot >= KEYRING_SLOT_START && slot < CURRENCYTOKEN_SLOT_END ) ) return true; return false; } -bool Player::IsEquipmentPos(uint8 bag, uint8 slot) +bool Player::IsEquipmentPos( uint8 bag, uint8 slot ) { - if (bag == INVENTORY_SLOT_BAG_0 && slot < EQUIPMENT_SLOT_END) + if( bag == INVENTORY_SLOT_BAG_0 && ( slot < EQUIPMENT_SLOT_END ) ) return true; - if (bag == INVENTORY_SLOT_BAG_0 && slot >= INVENTORY_SLOT_BAG_START && slot < INVENTORY_SLOT_BAG_END) + if( bag == INVENTORY_SLOT_BAG_0 && ( slot >= INVENTORY_SLOT_BAG_START && slot < INVENTORY_SLOT_BAG_END ) ) return true; return false; } -bool Player::IsBankPos(uint8 bag, uint8 slot) +bool Player::IsBankPos( uint8 bag, uint8 slot ) { - if (bag == INVENTORY_SLOT_BAG_0 && slot >= BANK_SLOT_ITEM_START && slot < BANK_SLOT_ITEM_END) + if( bag == INVENTORY_SLOT_BAG_0 && ( slot >= BANK_SLOT_ITEM_START && slot < BANK_SLOT_ITEM_END ) ) return true; - if (bag == INVENTORY_SLOT_BAG_0 && slot >= BANK_SLOT_BAG_START && slot < BANK_SLOT_BAG_END) + if( bag == INVENTORY_SLOT_BAG_0 && ( slot >= BANK_SLOT_BAG_START && slot < BANK_SLOT_BAG_END ) ) return true; - if (bag >= BANK_SLOT_BAG_START && bag < BANK_SLOT_BAG_END) + if( bag >= BANK_SLOT_BAG_START && bag < BANK_SLOT_BAG_END ) return true; return false; } @@ -9138,14 +9222,14 @@ bool Player::IsBagPos( uint16 pos ) { uint8 bag = pos >> 8; uint8 slot = pos & 255; - if (bag == INVENTORY_SLOT_BAG_0 && slot >= INVENTORY_SLOT_BAG_START && slot < INVENTORY_SLOT_BAG_END) + if( bag == INVENTORY_SLOT_BAG_0 && ( slot >= INVENTORY_SLOT_BAG_START && slot < INVENTORY_SLOT_BAG_END ) ) return true; - if (bag == INVENTORY_SLOT_BAG_0 && slot >= BANK_SLOT_BAG_START && slot < BANK_SLOT_BAG_END) + if( bag == INVENTORY_SLOT_BAG_0 && ( slot >= BANK_SLOT_BAG_START && slot < BANK_SLOT_BAG_END ) ) return true; return false; } -bool Player::IsValidPos(uint8 bag, uint8 slot) +bool Player::IsValidPos( uint8 bag, uint8 slot ) { // post selected if(bag == NULL_BAG) @@ -9188,7 +9272,7 @@ bool Player::IsValidPos(uint8 bag, uint8 slot) if (bag >= INVENTORY_SLOT_BAG_START && bag < INVENTORY_SLOT_BAG_END) { Bag* pBag = (Bag*)GetItemByPos (INVENTORY_SLOT_BAG_0, bag); - if (!pBag) + if(!pBag) return false; // any post selected @@ -9202,7 +9286,7 @@ bool Player::IsValidPos(uint8 bag, uint8 slot) if( bag >= BANK_SLOT_BAG_START && bag < BANK_SLOT_BAG_END ) { Bag* pBag = (Bag*)GetItemByPos (INVENTORY_SLOT_BAG_0, bag); - if (!pBag) + if(!pBag) return false; // any post selected @@ -9219,66 +9303,66 @@ bool Player::IsValidPos(uint8 bag, uint8 slot) bool Player::HasItemCount( uint32 item, uint32 count, bool inBankAlso ) const { uint32 tempcount = 0; - for (uint8 i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; ++i) + for (uint8 i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; i++) { Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - if (pItem && pItem->GetEntry() == item) + if( pItem && pItem->GetEntry() == item ) { tempcount += pItem->GetCount(); - if (tempcount >= count) + if( tempcount >= count ) return true; } } for (uint8 i = KEYRING_SLOT_START; i < CURRENCYTOKEN_SLOT_END; ++i) { Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - if (pItem && pItem->GetEntry() == item) + if( pItem && pItem->GetEntry() == item ) { tempcount += pItem->GetCount(); - if (tempcount >= count) + if( tempcount >= count ) return true; } } - for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i) + for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) { - if (Bag* pBag = (Bag*)GetItemByPos(INVENTORY_SLOT_BAG_0, i)) + if(Bag* pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i )) { - for (uint32 j = 0; j < pBag->GetBagSize(); ++j) + for (uint32 j = 0; j < pBag->GetBagSize(); j++) { Item* pItem = GetItemByPos( i, j ); - if (pItem && pItem->GetEntry() == item) + if( pItem && pItem->GetEntry() == item ) { tempcount += pItem->GetCount(); - if (tempcount >= count) + if( tempcount >= count ) return true; } } } } - if (inBankAlso) + if(inBankAlso) { - for (uint8 i = BANK_SLOT_ITEM_START; i < BANK_SLOT_ITEM_END; ++i) + for (uint8 i = BANK_SLOT_ITEM_START; i < BANK_SLOT_ITEM_END; i++) { - Item *pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i); - if (pItem && pItem->GetEntry() == item) + Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); + if( pItem && pItem->GetEntry() == item ) { tempcount += pItem->GetCount(); - if (tempcount >= count) + if( tempcount >= count ) return true; } } - for (uint8 i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; ++i) + for (uint8 i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++) { - if(Bag* pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i)) + if(Bag* pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i )) { - for (uint32 j = 0; j < pBag->GetBagSize(); ++j) + for (uint32 j = 0; j < pBag->GetBagSize(); j++) { - Item *pItem = GetItemByPos(i, j); - if (pItem && pItem->GetEntry() == item) + Item* pItem = GetItemByPos( i, j ); + if( pItem && pItem->GetEntry() == item ) { tempcount += pItem->GetCount(); - if (tempcount >= count) + if( tempcount >= count ) return true; } } @@ -9289,19 +9373,19 @@ bool Player::HasItemCount( uint32 item, uint32 count, bool inBankAlso ) const return false; } -bool Player::HasItemOrGemWithIdEquipped(uint32 item, uint32 count, uint8 except_slot) const +bool Player::HasItemOrGemWithIdEquipped( uint32 item, uint32 count, uint8 except_slot ) const { uint32 tempcount = 0; for (uint8 i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; ++i) { - if (i == except_slot) + if(i == except_slot) continue; - Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i); - if (pItem && pItem->GetEntry() == item) + Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); + if( pItem && pItem->GetEntry() == item) { tempcount += pItem->GetCount(); - if (tempcount >= count) + if( tempcount >= count ) return true; } } @@ -9311,14 +9395,14 @@ bool Player::HasItemOrGemWithIdEquipped(uint32 item, uint32 count, uint8 except_ { for (uint8 i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; ++i) { - if (i == except_slot) + if(i == except_slot) continue; - Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i); - if (pItem && pItem->GetProto()->Socket[0].Color) + Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); + if( pItem && pItem->GetProto()->Socket[0].Color) { tempcount += pItem->GetGemCountWithID(item); - if (tempcount >= count) + if( tempcount >= count ) return true; } } @@ -12298,6 +12382,15 @@ void Player::ApplyEnchantment(Item *item, EnchantmentSlot slot, bool apply, bool if (!ignore_condition && pEnchant->EnchantmentCondition && !((Player*)this)->EnchantmentFitsRequirements(pEnchant->EnchantmentCondition, -1)) return; + if ((pEnchant->requiredLevel) > ((Player*)this)->getLevel()) + return; + + if ((pEnchant->requiredSkill) > 0) + { + if ((pEnchant->requiredSkillValue) > (((Player*)this)->GetSkillValue(pEnchant->requiredSkill))) + return; + } + if (!item->IsBroken()) { for (int s = 0; s < 3; ++s) @@ -12560,6 +12653,10 @@ void Player::ApplyEnchantment(Item *item, EnchantmentSlot slot, bool apply, bool ((Player*)this)->ApplySpellPowerBonus(enchant_amount, apply); sLog.outDebug("+ %u SPELL_POWER", enchant_amount); break; + case ITEM_MOD_HEALTH_REGEN: + ((Player*)this)->ApplyHealthRegenBonus(enchant_amount, apply); + sLog.outDebug("+ %u HEALTH_REGENERATION", enchant_amount); + break; case ITEM_MOD_SPELL_HEALING_DONE: // deprecated case ITEM_MOD_SPELL_DAMAGE_DONE: // deprecated default: @@ -12936,7 +13033,7 @@ bool Player::CanCompleteQuest( uint32 quest_id ) if ( qInfo->HasFlag( QUEST_TRINITY_FLAGS_DELIVER ) ) { - for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; i++) + for (uint8 i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; i++) { if( qInfo->ReqItemCount[i]!= 0 && q_status.m_itemcount[i] < qInfo->ReqItemCount[i] ) return false; @@ -12986,7 +13083,7 @@ bool Player::CanCompleteRepeatableQuest( Quest const *pQuest ) return false; if (pQuest->HasFlag( QUEST_TRINITY_FLAGS_DELIVER) ) - for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; i++) + for (uint8 i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; i++) if( pQuest->ReqItemId[i] && pQuest->ReqItemCount[i] && !HasItemCount(pQuest->ReqItemId[i],pQuest->ReqItemCount[i]) ) return false; @@ -13013,7 +13110,7 @@ bool Player::CanRewardQuest( Quest const *pQuest, bool msg ) // prevent receive reward with quest items in bank if ( pQuest->HasFlag( QUEST_TRINITY_FLAGS_DELIVER ) ) { - for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; i++) + for (uint8 i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; i++) { if( pQuest->ReqItemCount[i]!= 0 && GetItemCount(pQuest->ReqItemId[i]) < pQuest->ReqItemCount[i] ) @@ -13088,7 +13185,7 @@ void Player::AddQuest( Quest const *pQuest, Object *questGiver ) if ( pQuest->HasFlag( QUEST_TRINITY_FLAGS_DELIVER ) ) { - for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; ++i) + for (uint8 i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; ++i) questStatusData.m_itemcount[i] = 0; } @@ -13186,13 +13283,10 @@ void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver uint32 quest_id = pQuest->GetQuestId(); - for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; ++i) + for (uint8 i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; ++i) if (pQuest->ReqItemId[i]) DestroyItemCount( pQuest->ReqItemId[i], pQuest->ReqItemCount[i], true); -// This is wrong. If SrcItem is supposed to be destroyed on quest complete then the item will be either in ReqItemId or ReqSrcItemId -// TakeQuestSourceItem(quest_id, true); // take quest src item from player on completing quest - for (uint8 i = 0; i < QUEST_SOURCE_ITEM_IDS_COUNT; ++i) { if (pQuest->ReqSourceId[i]) @@ -13285,8 +13379,56 @@ void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver } // Send reward mail - if (uint32 mail_template_id = pQuest->GetRewMailTemplateId()) - MailDraft(mail_template_id).SendMailTo(this, questGiver, MAIL_CHECK_MASK_NONE, pQuest->GetRewMailDelaySecs()); + if (pQuest->GetRewMailTemplateId()) + { + MailMessageType mailType; + uint32 senderGuidOrEntry; + switch(questGiver->GetTypeId()) + { + case TYPEID_UNIT: + mailType = MAIL_CREATURE; + senderGuidOrEntry = questGiver->GetEntry(); + break; + case TYPEID_GAMEOBJECT: + mailType = MAIL_GAMEOBJECT; + senderGuidOrEntry = questGiver->GetEntry(); + break; + case TYPEID_ITEM: + mailType = MAIL_ITEM; + senderGuidOrEntry = questGiver->GetEntry(); + break; + case TYPEID_PLAYER: + mailType = MAIL_NORMAL; + senderGuidOrEntry = questGiver->GetGUIDLow(); + break; + default: + mailType = MAIL_NORMAL; + senderGuidOrEntry = GetGUIDLow(); + break; + } + + Loot questMailLoot; + + questMailLoot.FillLoot(pQuest->GetQuestId(), LootTemplates_QuestMail, this,true); + + // fill mail + MailItemsInfo mi; // item list preparing + + 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 (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); + } + } + } + + WorldSession::SendMailTo(this, mailType, MAIL_STATIONERY_NORMAL, senderGuidOrEntry, GetGUIDLow(), "", 0, &mi, 0, 0, MAIL_CHECK_MASK_NONE,pQuest->GetRewMailDelaySecs(),pQuest->GetRewMailTemplateId()); + } if (pQuest->IsDaily()) { @@ -13864,7 +14006,7 @@ void Player::AdjustQuestReqItemCount(Quest const* pQuest, QuestStatusData& quest { if (pQuest->HasFlag( QUEST_TRINITY_FLAGS_DELIVER)) { - for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; ++i) + for (uint8 i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; ++i) { uint32 reqitemcount = pQuest->ReqItemCount[i]; if (reqitemcount != 0) @@ -13944,7 +14086,7 @@ void Player::ItemAddedQuestCheck( uint32 entry, uint32 count) if( !qInfo || !qInfo->HasFlag(QUEST_TRINITY_FLAGS_DELIVER)) continue; - for (uint8 j = 0; j < QUEST_OBJECTIVES_COUNT; ++j) + for (uint8 j = 0; j < QUEST_ITEM_OBJECTIVES_COUNT; ++j) { uint32 reqitem = qInfo->ReqItemId[j]; if (reqitem == entry) @@ -13981,7 +14123,7 @@ void Player::ItemRemovedQuestCheck( uint32 entry, uint32 count) if( !qInfo->HasFlag(QUEST_TRINITY_FLAGS_DELIVER)) continue; - for (uint8 j = 0; j < QUEST_OBJECTIVES_COUNT; ++j) + for (uint8 j = 0; j < QUEST_ITEM_OBJECTIVES_COUNT; ++j) { uint32 reqitem = qInfo->ReqItemId[j]; if (reqitem == entry) @@ -14295,7 +14437,7 @@ bool Player::HasQuestForItem(uint32 itemid) const // There should be no mixed ReqItem/ReqSource drop // This part for ReqItem drop - for (uint8 j = 0; j < QUEST_OBJECTIVES_COUNT; ++j) + for (uint8 j = 0; j < QUEST_ITEM_OBJECTIVES_COUNT; ++j) { if (itemid == qinfo->ReqItemId[j] && q_status.m_itemcount[j] < qinfo->ReqItemCount[j]) return true; @@ -14369,7 +14511,7 @@ void Player::SendQuestFailed( uint32 quest_id ) if( quest_id ) { WorldPacket data( SMSG_QUESTGIVER_QUEST_FAILED, 4+4 ); - data << quest_id; + data << uint32(quest_id); data << uint32(0); // failed reason (4 for inventory is full) GetSession()->SendPacket( &data ); sLog.outDebug("WORLD: Sent SMSG_QUESTGIVER_QUEST_FAILED"); @@ -14381,7 +14523,7 @@ void Player::SendQuestTimerFailed( uint32 quest_id ) if( quest_id ) { WorldPacket data( SMSG_QUESTUPDATE_FAILEDTIMER, 4 ); - data << quest_id; + data << uint32(quest_id); GetSession()->SendPacket( &data ); sLog.outDebug("WORLD: Sent SMSG_QUESTUPDATE_FAILEDTIMER"); } @@ -14522,7 +14664,7 @@ void Player::_LoadDeclinedNames(QueryResult* result) void Player::_LoadArenaTeamInfo(QueryResult *result) { // arenateamid, played_week, played_season, personal_rating - memset((void*)&m_uint32Values[PLAYER_FIELD_ARENA_TEAM_INFO_1_1], 0, sizeof(uint32)*18); + memset((void*)&m_uint32Values[PLAYER_FIELD_ARENA_TEAM_INFO_1_1], 0, sizeof(uint32) * MAX_ARENA_SLOT * ARENA_TEAM_END); if (!result) return; @@ -14533,22 +14675,24 @@ void Player::_LoadArenaTeamInfo(QueryResult *result) uint32 arenateamid = fields[0].GetUInt32(); uint32 played_week = fields[1].GetUInt32(); uint32 played_season = fields[2].GetUInt32(); - uint32 personal_rating = fields[3].GetUInt32(); + uint32 wons_season = fields[3].GetUInt32(); + uint32 personal_rating = fields[4].GetUInt32(); ArenaTeam* aTeam = objmgr.GetArenaTeamById(arenateamid); if(!aTeam) { - sLog.outError("Player::_LoadArenaTeamInfo: couldn't load arenateam %u, week %u, season %u, rating %u", arenateamid, played_week, played_season, personal_rating); + sLog.outError("Player::_LoadArenaTeamInfo: couldn't load arenateam %u", arenateamid); continue; } uint8 arenaSlot = aTeam->GetSlot(); - m_uint32Values[PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + arenaSlot * 6] = arenateamid; // TeamID - m_uint32Values[PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + arenaSlot * 6 + 1] = ((aTeam->GetCaptain() == GetGUID()) ? (uint32)0 : (uint32)1); // Captain 0, member 1 - m_uint32Values[PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + arenaSlot * 6 + 2] = played_week; // Played Week - m_uint32Values[PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + arenaSlot * 6 + 3] = played_season; // Played Season - m_uint32Values[PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + arenaSlot * 6 + 4] = 0; // Unk - m_uint32Values[PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + arenaSlot * 6 + 5] = personal_rating; // Personal Rating + m_uint32Values[PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (arenaSlot * ARENA_TEAM_END) + ARENA_TEAM_ID] = arenateamid; // TeamID + m_uint32Values[PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (arenaSlot * ARENA_TEAM_END) + ARENA_TEAM_TYPE] = aTeam->GetType(); // team type + m_uint32Values[PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (arenaSlot * ARENA_TEAM_END) + ARENA_TEAM_MEMBER] = ((aTeam->GetCaptain() == GetGUID()) ? (uint32)0 : (uint32)1); // Captain 0, member 1 + m_uint32Values[PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (arenaSlot * ARENA_TEAM_END) + ARENA_TEAM_GAMES_WEEK] = played_week; // Played Week + m_uint32Values[PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (arenaSlot * ARENA_TEAM_END) + ARENA_TEAM_GAMES_SEASON] = played_season; // Played Season + m_uint32Values[PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (arenaSlot * ARENA_TEAM_END) + ARENA_TEAM_WINS_SEASON] = wons_season; // wins season + m_uint32Values[PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (arenaSlot * ARENA_TEAM_END) + ARENA_TEAM_PERSONAL_RATING] = personal_rating; // Personal Rating }while (result->NextRow()); delete result; @@ -14661,37 +14805,6 @@ float Player::GetFloatValueFromArray(Tokens const& data, uint16 index) uint32 Player::GetUInt32ValueFromDB(uint16 index, uint64 guid) { - // todo: cleanup in this, move to a separate function. - if( index == PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 0 * 6 + 5 - || index == PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 1 * 6 + 5 - || index == PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 2 * 6 + 5 - || index == PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (0 * 6) - || index == PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (1 * 6) - || index == PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (2 * 6) - || index == UNIT_FIELD_LEVEL) - { - CachePlayerInfoMap::iterator _iter = objmgr.m_mPlayerInfoMap.find(GUID_LOPART(guid)); - if(_iter != objmgr.m_mPlayerInfoMap.end()) - { - switch(index) - { - case (PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 0 * 6 + 5): - return _iter->second->unArenaInfoSlot0; - case (PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 1 * 6 + 5): - return _iter->second->unArenaInfoSlot1; - case (PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 2 * 6 + 5): - return _iter->second->unArenaInfoSlot2; - case (PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (0 * 6)): - return _iter->second->unArenaInfoId0; - case (PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (1 * 6)): - return _iter->second->unArenaInfoId1; - case (PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (2 * 6)): - return _iter->second->unArenaInfoId2; - case (UNIT_FIELD_LEVEL): - return _iter->second->unLevel; - } - } - } Tokens data; if(!LoadValuesArrayFromDB(data,guid)) return 0; @@ -14811,7 +14924,11 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder ) Relocate(fields[13].GetFloat(),fields[14].GetFloat(),fields[15].GetFloat(),fields[17].GetFloat()); uint32 mapId = fields[16].GetUInt32(); uint32 instanceId = fields[41].GetFloat(); - SetDifficulty(fields[39].GetUInt32()); // may be changed in _LoadGroup + + uint32 difficulty = fields[39].GetUInt32(); + if(difficulty >= MAX_DUNGEON_DIFFICULTY) + difficulty = DUNGEON_DIFFICULTY_NORMAL; + SetDungeonDifficulty(Difficulty(difficulty)); // may be changed in _LoadGroup std::string taxi_nodes = fields[38].GetCppString(); #define RelocateToHomebind(){ mapId = m_homebindMapId; instanceId = 0; Relocate(m_homebindX, m_homebindY, m_homebindZ); } @@ -14839,7 +14956,7 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder ) // arena team not exist or not member, cleanup fields for (int j = 0; j < 6; ++j) - SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + arena_slot * 6 + j, 0); + SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (arena_slot * ARENA_TEAM_END) + j, 0); } _LoadBoundInstances(holder->GetResult(PLAYER_LOGIN_QUERY_LOADBOUNDINSTANCES)); @@ -14989,7 +15106,7 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder ) // fix crash (because of if(Map *map = _FindMap(instanceId)) in MapInstanced::CreateInstance) if(instanceId) - if(InstanceSave * save = GetInstanceSave(mapId)) + if(InstanceSave * save = GetInstanceSave(mapId, mapEntry->IsRaid())) if(save->GetInstanceId() != instanceId) instanceId = 0; @@ -15611,20 +15728,20 @@ void Player::_LoadInventory(QueryResult *result, uint32 timediff) // send by mail problematic items while (!problematicItems.empty()) { - std::string subject = GetSession()->GetMangosString(LANG_NOT_EQUIPPED_ITEM); - // fill mail - MailDraft draft(subject); + MailItemsInfo mi; // item list preparing for (uint8 i = 0; !problematicItems.empty() && i < MAX_MAIL_ITEMS; ++i) { Item* item = problematicItems.front(); problematicItems.pop_front(); - draft.AddItem(item); + mi.AddItem(item->GetGUIDLow(), item->GetEntry(), item); } - draft.SendMailTo(this, MailSender(this, MAIL_STATIONERY_GM)); + std::string subject = GetSession()->GetTrinityString(LANG_NOT_EQUIPPED_ITEM); + + WorldSession::SendMailTo(this, MAIL_NORMAL, MAIL_STATIONERY_GM, GetGUIDLow(), GetGUIDLow(), subject, 0, &mi, 0, 0, MAIL_CHECK_MASK_NONE); } } //if(isAlive()) @@ -15816,7 +15933,7 @@ void Player::_LoadQuestStatus(QueryResult *result) ((questStatusData.m_status == QUEST_STATUS_INCOMPLETE || questStatusData.m_status == QUEST_STATUS_COMPLETE || questStatusData.m_status == QUEST_STATUS_FAILED) && - (!questStatusData.m_rewarded || pQuest->IsRepeatable()))) + (!questStatusData.m_rewarded || pQuest->IsDaily()))) { SetQuestSlot(slot, quest_id, quest_time); @@ -15935,15 +16052,18 @@ void Player::_LoadGroup(QueryResult *result) uint8 subgroup = group->GetMemberGroup(GetGUID()); SetGroup(group, subgroup); if (getLevel() >= LEVELREQUIREMENT_HEROIC) + { // the group leader may change the instance difficulty while the player is offline - SetDifficulty(group->GetDifficulty()); + SetDungeonDifficulty(group->GetDungeonDifficulty()); + SetRaidDifficulty(group->GetRaidDifficulty()); + } } } } void Player::_LoadBoundInstances(QueryResult *result) { - for (uint8 i = 0; i < TOTAL_DIFFICULTIES; ++i) + for (uint8 i = 0; i < MAX_DIFFICULTY; ++i) m_boundInstances[i].clear(); Group *group = GetGroup(); @@ -15958,6 +16078,7 @@ void Player::_LoadBoundInstances(QueryResult *result) uint32 mapId = fields[2].GetUInt32(); uint32 instanceId = fields[0].GetUInt32(); uint8 difficulty = fields[3].GetUInt8(); + time_t resetTime = (time_t)fields[4].GetUInt64(); // the resettime for normal instances is only saved when the InstanceSave is unloaded // so the value read from the DB may be wrong here but only if the InstanceSave is loaded @@ -15971,6 +16092,22 @@ void Player::_LoadBoundInstances(QueryResult *result) continue; } + if(difficulty >= MAX_DIFFICULTY) + { + sLog.outError("_LoadBoundInstances: player %s(%d) has bind to not existed difficulty %d instance for map %u", GetName(), GetGUIDLow(), difficulty, mapId); + CharacterDatabase.PExecute("DELETE FROM character_instance WHERE guid = '%d' AND instance = '%d'", GetGUIDLow(), instanceId); + continue; + } + + MapDifficulty const* mapDiff = GetMapDifficultyData(mapId,Difficulty(difficulty)); + if(!mapDiff) + { + sLog.outError("_LoadBoundInstances: player %s(%d) has bind to not existed difficulty %d instance for map %u", GetName(), GetGUIDLow(), difficulty, mapId); + CharacterDatabase.PExecute("DELETE FROM character_instance WHERE guid = '%d' AND instance = '%d'", GetGUIDLow(), instanceId); + continue; + } + + if (!perm && group) { sLog.outError("_LoadBoundInstances: player %s(%d) is in group %d but has a non-permanent character bind to map %d,%d,%d", GetName(), GetGUIDLow(), GUID_LOPART(group->GetLeaderGUID()), mapId, instanceId, difficulty); @@ -15979,18 +16116,19 @@ void Player::_LoadBoundInstances(QueryResult *result) } // since non permanent binds are always solo bind, they can always be reset - if (InstanceSave *save = sInstanceSaveManager.AddInstanceSave(mapId, instanceId, difficulty, resetTime, !perm, true)) + if (InstanceSave *save = sInstanceSaveManager.AddInstanceSave(mapId, instanceId, Difficulty(difficulty), resetTime, !perm, true)) BindToInstance(save, perm, true); } while (result->NextRow()); delete result; } } -InstancePlayerBind* Player::GetBoundInstance(uint32 mapid, uint8 difficulty) +InstancePlayerBind* Player::GetBoundInstance(uint32 mapid, Difficulty difficulty) { // some instances only have one difficulty - const MapEntry* entry = sMapStore.LookupEntry(mapid); - if (!entry || !entry->SupportsHeroicMode()) difficulty = DIFFICULTY_NORMAL; + MapDifficulty const* mapDiff = GetMapDifficultyData(mapid,difficulty); + if(!mapDiff) + return NULL; BoundInstancesMap::iterator itr = m_boundInstances[difficulty].find(mapid); if (itr != m_boundInstances[difficulty].end()) @@ -15999,25 +16137,25 @@ InstancePlayerBind* Player::GetBoundInstance(uint32 mapid, uint8 difficulty) return NULL; } -InstanceSave * Player::GetInstanceSave(uint32 mapid) +InstanceSave * Player::GetInstanceSave(uint32 mapid, bool raid) { - InstancePlayerBind *pBind = GetBoundInstance(mapid, GetDifficulty()); + InstancePlayerBind *pBind = GetBoundInstance(mapid, GetDifficulty(raid)); InstanceSave *pSave = pBind ? pBind->save : NULL; if (!pBind || !pBind->perm) if(Group *group = GetGroup()) - if(InstanceGroupBind *groupBind = group->GetBoundInstance(mapid, GetDifficulty())) + if(InstanceGroupBind *groupBind = group->GetBoundInstance(this)) pSave = groupBind->save; return pSave; } -void Player::UnbindInstance(uint32 mapid, uint8 difficulty, bool unload) +void Player::UnbindInstance(uint32 mapid, Difficulty difficulty, bool unload) { BoundInstancesMap::iterator itr = m_boundInstances[difficulty].find(mapid); UnbindInstance(itr, difficulty, unload); } -void Player::UnbindInstance(BoundInstancesMap::iterator &itr, uint8 difficulty, bool unload) +void Player::UnbindInstance(BoundInstancesMap::iterator &itr, Difficulty difficulty, bool unload) { if (itr != m_boundInstances[difficulty].end()) { @@ -16074,7 +16212,7 @@ void Player::SendRaidInfo() time_t now = time(NULL); - for (uint8 i = 0; i < TOTAL_DIFFICULTIES; ++i) + for (uint8 i = 0; i < MAX_DIFFICULTY; ++i) { for (BoundInstancesMap::iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end(); ++itr) { @@ -16084,8 +16222,9 @@ void Player::SendRaidInfo() data << uint32(save->GetMapId()); // map id data << uint32(save->GetDifficulty()); // difficulty data << uint64(save->GetInstanceId()); // instance id + data << uint8(1); // expired = 0 + data << uint8(0); // extended = 1 data << uint32(save->GetResetTime() - now); // reset time - data << uint32(0); // is extended ++counter; } } @@ -16102,7 +16241,7 @@ void Player::SendSavedInstances() bool hasBeenSaved = false; WorldPacket data; - for (uint8 i = 0; i < TOTAL_DIFFICULTIES; ++i) + for (uint8 i = 0; i < MAX_DIFFICULTY; ++i) { for (BoundInstancesMap::iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end(); ++itr) { @@ -16122,7 +16261,7 @@ void Player::SendSavedInstances() if (!hasBeenSaved) return; - for (uint8 i = 0; i < TOTAL_DIFFICULTIES; ++i) + for (uint8 i = 0; i < MAX_DIFFICULTY; ++i) { for (BoundInstancesMap::iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end(); ++itr) { @@ -16155,7 +16294,7 @@ void Player::ConvertInstancesToGroup(Player *player, Group *group, uint64 player if (player) { - for (uint8 i = 0; i < TOTAL_DIFFICULTIES; ++i) + for (uint8 i = 0; i < MAX_DIFFICULTY; ++i) { for (BoundInstancesMap::iterator itr = player->m_boundInstances[i].begin(); itr != player->m_boundInstances[i].end();) { @@ -16165,7 +16304,8 @@ void Player::ConvertInstancesToGroup(Player *player, Group *group, uint64 player // permanent binds are not removed if (!itr->second.perm) { - player->UnbindInstance(itr, i, true); // increments itr + // increments itr in call + player->UnbindInstance(itr, Difficulty(i), true); has_solo = true; } else @@ -16193,7 +16333,7 @@ bool Player::Satisfy(AccessRequirement const *ar, uint32 target_map, bool report { if (ar->levelMin && getLevel() < ar->levelMin) LevelMin = ar->levelMin; - if (ar->heroicLevelMin && GetDifficulty() == DIFFICULTY_HEROIC && getLevel() < ar->heroicLevelMin) + if(ar->heroicLevelMin && GetDungeonDifficulty() == DUNGEON_DIFFICULTY_HEROIC && getLevel() < ar->heroicLevelMin) LevelMin = ar->heroicLevelMin; if (ar->levelMax && getLevel() > ar->levelMax) LevelMax = ar->levelMax; @@ -16209,9 +16349,17 @@ bool Player::Satisfy(AccessRequirement const *ar, uint32 target_map, bool report else if(ar->item2 && !HasItemCount(ar->item2, 1)) missingItem = ar->item2; + MapEntry const* mapEntry = sMapStore.LookupEntry(target_map); + if(!mapEntry) + return false; + + bool isNormalTargetMap = mapEntry->IsRaid() + ? (GetRaidDifficulty() == RAID_DIFFICULTY_10MAN_NORMAL) + : (GetDungeonDifficulty() == DUNGEON_DIFFICULTY_NORMAL); + uint32 missingKey = 0; uint32 missingHeroicQuest = 0; - if (GetDifficulty() == DIFFICULTY_HEROIC) + if(!isNormalTargetMap) { if (ar->heroicKey) { @@ -16237,7 +16385,7 @@ bool Player::Satisfy(AccessRequirement const *ar, uint32 target_map, bool report if (missingItem) GetSession()->SendAreaTriggerMessage(GetSession()->GetTrinityString(LANG_LEVEL_MINREQUIRED_AND_ITEM), LevelMin, objmgr.GetItemPrototype(missingItem)->Name1); else if (missingKey) - SendTransferAborted(target_map, TRANSFER_ABORT_DIFFICULTY); + SendTransferAborted(target_map, TRANSFER_ABORT_DIFFICULTY, isNormalTargetMap ? DUNGEON_DIFFICULTY_NORMAL : DUNGEON_DIFFICULTY_HEROIC); else if (missingHeroicQuest) GetSession()->SendAreaTriggerMessage(ar->heroicQuestFailedText.c_str()); else if (missingQuest) @@ -16352,7 +16500,7 @@ void Player::SaveToDB() { ss << GetMapId() << ", " << (uint32)GetInstanceId() << ", " - << (uint32)GetDifficulty() << ", " + << (uint32)GetDungeonDifficulty() << ", " << finiteAlways(GetPositionX()) << ", " << finiteAlways(GetPositionY()) << ", " << finiteAlways(GetPositionZ()) << ", " @@ -16362,7 +16510,7 @@ void Player::SaveToDB() { ss << GetTeleportDest().GetMapId() << ", " << (uint32)0 << ", " - << (uint32)GetDifficulty() << ", " + << (uint32)GetDungeonDifficulty() << ", " << finiteAlways(GetTeleportDest().GetPositionX()) << ", " << finiteAlways(GetTeleportDest().GetPositionY()) << ", " << finiteAlways(GetTeleportDest().GetPositionZ()) << ", " @@ -16950,7 +17098,17 @@ void Player::SendDungeonDifficulty(bool IsInGroup) { uint8 val = 0x00000001; WorldPacket data(MSG_SET_DUNGEON_DIFFICULTY, 12); - data << (uint32)GetDifficulty(); + data << (uint32)GetDungeonDifficulty(); + data << uint32(val); + data << uint32(IsInGroup); + GetSession()->SendPacket(&data); +} + +void Player::SendRaidDifficulty(bool IsInGroup) +{ + uint8 val = 0x00000001; + WorldPacket data(MSG_SET_RAID_DIFFICULTY, 12); + data << uint32(GetRaidDifficulty()); data << uint32(val); data << uint32(IsInGroup); GetSession()->SendPacket(&data); @@ -16964,18 +17122,18 @@ void Player::SendResetFailedNotify(uint32 mapid) } /// Reset all solo instances and optionally send a message on success for each -void Player::ResetInstances(uint8 method) +void Player::ResetInstances(uint8 method, bool isRaid) { // method can be INSTANCE_RESET_ALL, INSTANCE_RESET_CHANGE_DIFFICULTY, INSTANCE_RESET_GROUP_JOIN // we assume that when the difficulty changes, all instances that can be reset will be - uint8 dif = GetDifficulty(); + Difficulty diff = GetDifficulty(isRaid); - for (BoundInstancesMap::iterator itr = m_boundInstances[dif].begin(); itr != m_boundInstances[dif].end();) + for (BoundInstancesMap::iterator itr = m_boundInstances[diff].begin(); itr != m_boundInstances[diff].end(); ) { InstanceSave *p = itr->second.save; const MapEntry *entry = sMapStore.LookupEntry(itr->first); - if(!entry || !p->CanReset()) + if(!entry || entry->IsRaid() != isRaid || !p->CanReset()) { ++itr; continue; @@ -16984,7 +17142,7 @@ void Player::ResetInstances(uint8 method) if(method == INSTANCE_RESET_ALL) { // the "reset all instances" method can only reset normal maps - if(dif == DIFFICULTY_HEROIC || entry->map_type == MAP_RAID) + if(entry->map_type == MAP_RAID || diff == DUNGEON_DIFFICULTY_HEROIC) { ++itr; continue; @@ -17005,7 +17163,7 @@ void Player::ResetInstances(uint8 method) SendResetInstanceSuccess(p->GetMapId()); p->DeleteFromDB(); - m_boundInstances[dif].erase(itr++); + m_boundInstances[diff].erase(itr++); // the following should remove the instance save from the manager and delete it as well p->RemovePlayer(this); @@ -17085,7 +17243,12 @@ Pet* Player::GetPet() const if(!IS_PET_GUID(pet_guid)) return NULL; - if(Pet* pet = ObjectAccessor::GetPet(pet_guid)) + Pet* pet = ObjectAccessor::GetPet(pet_guid); + + if (!pet) + return NULL; + + if(IsInWorld() && pet) return pet; //there may be a guardian in slot @@ -17395,6 +17558,10 @@ void Player::VehicleSpellInitialize() if(!veh) return; + // GetPosition_ is not a member of 'Vehicle', SetPosition is a member of 'Player': SetPosition(GetVehicle()->GetPositionX(), GetVehicle()->GetPositionY(), GetVehicle()->GetPositionZ(), GetVehicle()->GetOrientation()); + + // GetPosition_ is not a member of 'Vehicle', SetPosition is a member of 'Player': SetPosition(GetVehicle()->GetPositionX(), GetVehicle()->GetPositionY(), GetVehicle()->GetPositionZ(), GetVehicle()->GetOrientation()); + WorldPacket data(SMSG_PET_SPELLS, 8+2+4+4+4*10+1+1); data << uint64(veh->GetGUID()); data << uint16(0); @@ -18348,10 +18515,10 @@ bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint uint32 new_count = pCreature->UpdateVendorItemCurrentCount(crItem,pProto->BuyCount * count); WorldPacket data(SMSG_BUY_ITEM, (8+4+4+4)); - data << pCreature->GetGUID(); - data << (uint32)(vendor_slot+1); // numbered from 1 at client - data << (uint32)(crItem->maxcount > 0 ? new_count : 0xFFFFFFFF); - data << (uint32)count; + data << uint64(pCreature->GetGUID()); + data << uint32(vendor_slot+1); // numbered from 1 at client + data << uint32(crItem->maxcount > 0 ? new_count : 0xFFFFFFFF); + data << uint32(count); GetSession()->SendPacket(&data); SendNewItem(it, pProto->BuyCount*count, true, false, false); @@ -18393,10 +18560,10 @@ bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint uint32 new_count = pCreature->UpdateVendorItemCurrentCount(crItem,pProto->BuyCount * count); WorldPacket data(SMSG_BUY_ITEM, (8+4+4+4)); - data << pCreature->GetGUID(); - data << (uint32)(vendor_slot+1); // numbered from 1 at client - data << (uint32)(crItem->maxcount > 0 ? new_count : 0xFFFFFFFF); - data << (uint32)count; + data << uint64(pCreature->GetGUID()); + data << uint32(vendor_slot + 1); // numbered from 1 at client + data << uint32(crItem->maxcount > 0 ? new_count : 0xFFFFFFFF); + data << uint32(count); GetSession()->SendPacket(&data); SendNewItem(it, pProto->BuyCount*count, true, false, false); @@ -18423,9 +18590,9 @@ uint32 Player::GetMaxPersonalArenaRatingRequirement() { if(ArenaTeam * at = objmgr.GetArenaTeamById(GetArenaTeamId(i))) { - uint32 p_rating = GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (i * 6) + 5); + uint32 p_rating = GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (i * ARENA_TEAM_END) + ARENA_TEAM_PERSONAL_RATING); uint32 t_rating = at->GetRating(); - p_rating = p_rating<t_rating? p_rating : t_rating; + p_rating = p_rating < t_rating ? p_rating : t_rating; if(max_personal_rating < p_rating) max_personal_rating = p_rating; } @@ -18465,7 +18632,7 @@ void Player::UpdateHomebindTime(uint32 time) m_HomebindTimer = 60000; // send message to player WorldPacket data(SMSG_RAID_GROUP_ONLY, 4+4); - data << m_HomebindTimer; + data << uint32(m_HomebindTimer); data << uint32(1); GetSession()->SendPacket(&data); sLog.outDebug("PLAYER: Player '%s' (GUID: %u) will be teleported to homebind in 60 seconds", GetName(),GetGUIDLow()); @@ -18634,8 +18801,8 @@ void Player::SendCooldownEvent(SpellEntry const *spellInfo, uint32 itemId, Spell // Send activate cooldown timer (possible 0) at client side WorldPacket data(SMSG_COOLDOWN_EVENT, (4+8)); - data << spellInfo->Id; - data << GetGUID(); + data << uint32(spellInfo->Id); + data << uint64(GetGUID()); SendDirectMessage(&data); } @@ -19077,14 +19244,16 @@ bool Player::IsVisibleInGridForPlayer( Player const * pl ) const // It seems in battleground everyone sees everyone, except the enemy-faction ghosts if (InBattleGround()) { - if (!(isAlive() || m_deathTimer > 0) && !IsFriendlyTo(pl)) + if (!(isAlive() || m_deathTimer > 0) && !IsFriendlyTo(pl) ) return false; return true; } // Live player see live player or dead player with not realized corpse - if (pl->isAlive() || pl->m_deathTimer > 0) + if(pl->isAlive() || pl->m_deathTimer > 0) + { return isAlive() || m_deathTimer > 0; + } // Ghost see other friendly ghosts, that's for sure if(!(isAlive() || m_deathTimer > 0) && IsFriendlyTo(pl)) @@ -19275,7 +19444,7 @@ void Player::SendComboPoints() void Player::AddComboPoints(Unit* target, int8 count, Spell * spell) { - if (!count) + if(!count) return; int8 * comboPoints = spell ? &spell->m_comboPointGain : &m_comboPoints; @@ -19283,7 +19452,7 @@ void Player::AddComboPoints(Unit* target, int8 count, Spell * spell) // without combo points lost (duration checked in aura) RemoveAurasByType(SPELL_AURA_RETAIN_COMBO_POINTS); - if (target->GetGUID() == m_comboTarget) + if (target->GetGUID() == m_comboTarget) *comboPoints += count; else { @@ -19355,23 +19524,26 @@ void Player::SetGroup(Group *group, int8 subgroup) void Player::SendInitialPacketsBeforeAddToMap() { - WorldPacket data(SMSG_SET_REST_START_OBSOLETE, 4); - data << uint32(0); // unknown, may be rest state time or experience - GetSession()->SendPacket(&data); - GetSocial()->SendSocialList(); + // guild bank list wtf? + // Homebind - data.Initialize(SMSG_BINDPOINTUPDATE, 5*4); + WorldPacket data(SMSG_BINDPOINTUPDATE, 5*4); data << m_homebindX << m_homebindY << m_homebindZ; data << (uint32) m_homebindMapId; data << (uint32) m_homebindZoneId; GetSession()->SendPacket(&data); // SMSG_SET_PROFICIENCY + // SMSG_SET_PCT_SPELL_MODIFIER + // SMSG_SET_FLAT_SPELL_MODIFIER // SMSG_UPDATE_AURA_DURATION SendTalentsInfoData(false); + + // SMSG_INSTANCE_DIFFICULTY + SendInitialSpells(); data.Initialize(SMSG_SEND_UNLEARN_SPELLS, 4); @@ -19389,6 +19561,14 @@ void Player::SendInitialPacketsBeforeAddToMap() data << (float)0.01666667f; // game speed data << uint32(0); // added in 3.1.2 GetSession()->SendPacket( &data ); + + GetReputationMgr().SendForceReactions(); // SMSG_SET_FORCED_REACTIONS + + // SMSG_TALENTS_INFO x 2 for pet (unspent points and talents in separate packets...) + // SMSG_PET_GUIDS + // SMSG_UPDATE_WORLD_STATE + // SMSG_POWER_UPDATE + } void Player::SendInitialPacketsAfterAddToMap() @@ -19468,7 +19648,7 @@ void Player::SendTransferAborted(uint32 mapid, uint8 reason, uint8 arg) GetSession()->SendPacket(&data); } -void Player::SendInstanceResetWarning( uint32 mapid, uint32 difficulty, uint32 time ) +void Player::SendInstanceResetWarning( uint32 mapid, Difficulty difficulty, uint32 time ) { // type of warning, based on the time remaining until reset uint32 type; @@ -19800,12 +19980,8 @@ bool Player::GetBGAccessByLevel(BattleGroundTypeId bgTypeId) const BGQueueIdBasedOnLevel Player::GetBattleGroundQueueIdFromLevel(BattleGroundTypeId bgTypeId) const { - //returned to hardcoded version of this function, because there is no way to code it dynamic - uint8 level = getLevel(); - if (bgTypeId == BATTLEGROUND_AV) - level--; - - uint32 queue_id = (level / 10) - 1; // for ranges 0 - 19, 20 - 29, 30 - 39, 40 - 49, 50 - 59, 60 - 69, 70 -79, 80 + // for ranges 0 - 19, 20 - 29, 30 - 39, 40 - 49, 50 - 59, 60 - 69, 70 - 79, 80 + uint32 queue_id = ( getLevel() / 10) - 1; if (queue_id >= MAX_BATTLEGROUND_QUEUES) { sLog.outError("BattleGround: too high queue_id %u this shouldn't happen", queue_id); @@ -19996,6 +20172,8 @@ void Player::AutoUnequipOffhandIfNeed(bool force /*= false*/) } else { + MailItemsInfo mi; + mi.AddItem(offItem->GetGUIDLow(), offItem->GetEntry(), offItem); MoveItemFromInventory(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND, true); CharacterDatabase.BeginTransaction(); offItem->DeleteFromInventoryDB(); // deletes item from character's inventory @@ -20003,7 +20181,7 @@ void Player::AutoUnequipOffhandIfNeed(bool force /*= false*/) CharacterDatabase.CommitTransaction(); std::string subject = GetSession()->GetMangosString(LANG_NOT_EQUIPPED_ITEM); - MailDraft(subject).AddItem(offItem).SendMailTo(this, MailSender(this, MAIL_STATIONERY_GM)); + WorldSession::SendMailTo(this, MAIL_NORMAL, MAIL_STATIONERY_GM, GetGUIDLow(), GetGUIDLow(), subject, 0, &mi, 0, 0, MAIL_CHECK_MASK_NONE); } } @@ -20740,7 +20918,8 @@ bool Player::CanCaptureTowerPoint() ); } -uint32 Player::GetBarberShopCost(uint8 newhairstyle, uint8 newhaircolor, uint8 newfacialhair) +uint32 Player::GetBarberShopCost(uint8 newhairstyle, uint8 newhaircolor, uint8 newfacialhair, BarberShopStyleEntry const* newSkin ) + { uint8 level = getLevel(); @@ -20750,8 +20929,9 @@ uint32 Player::GetBarberShopCost(uint8 newhairstyle, uint8 newhaircolor, uint8 n uint8 hairstyle = GetByteValue(PLAYER_BYTES, 2); uint8 haircolor = GetByteValue(PLAYER_BYTES, 3); uint8 facialhair = GetByteValue(PLAYER_BYTES_2, 0); + uint8 skincolor = GetByteValue(PLAYER_BYTES, 0); - if((hairstyle == newhairstyle) && (haircolor == newhaircolor) && (facialhair == newfacialhair)) + if((hairstyle == newhairstyle) && (haircolor == newhaircolor) && (facialhair == newfacialhair) && (!newSkin || (newSkin->hair_id == skincolor))) return 0; GtBarberShopCostBaseEntry const *bsc = sGtBarberShopCostBaseStore.LookupEntry(level - 1); @@ -20770,6 +20950,9 @@ uint32 Player::GetBarberShopCost(uint8 newhairstyle, uint8 newhaircolor, uint8 n if(facialhair != newfacialhair) cost += bsc->cost * 0.75f; // +3/4 of price + if(newSkin && skincolor != newSkin->hair_id) + cost += bsc->cost * 0.75f; // +5/6 of price + return uint32(cost); } @@ -21259,7 +21442,7 @@ void Player::HandleFall(MovementInfo const& movementInfo) DEBUG_LOG("FALLDAMAGE z=%f sz=%f pZ=%f FallTime=%d mZ=%f damage=%d SF=%d" , movementInfo.z, height, GetPositionZ(), movementInfo.fallTime, height, damage, safe_fall); } } - RemoveAura(44795); // No fly zone - Parachute + RemoveAura(61243); // No fly zone - Parachute } void Player::UpdateAchievementCriteria( AchievementCriteriaTypes type, uint32 miscvalue1/*=0*/, uint32 miscvalue2/*=0*/, Unit *unit/*=NULL*/, uint32 time/*=0*/ ) @@ -22196,3 +22379,10 @@ std::string Player::GetGuildName() { return objmgr.GetGuildById(GetGuildId())->GetName(); } + +void Player::SendDuelCountdown(uint32 counter) +{ + WorldPacket data(SMSG_DUEL_COUNTDOWN, 4); + data << uint32(counter); // seconds + GetSession()->SendPacket(&data); +} diff --git a/src/game/Player.h b/src/game/Player.h index 4b3cf3245f7..9038c8926b9 100644 --- a/src/game/Player.h +++ b/src/game/Player.h @@ -38,6 +38,7 @@ #include "AchievementMgr.h" #include "ReputationMgr.h" #include "BattleGround.h" +#include "DBCEnums.h" #include<string> #include<vector> @@ -178,7 +179,7 @@ struct ActionButton } }; -#define MAX_ACTION_BUTTONS 132 //checked in 2.3.0 +#define MAX_ACTION_BUTTONS 144 //checked in 3.2.0 typedef std::map<uint8,ActionButton> ActionButtonList; @@ -339,10 +340,10 @@ enum LfgType enum LfgRoles { - LEADER = 1, - TANK = 2, - HEALER = 4, - DAMAGE = 8 + LEADER = 0x01, + TANK = 0x02, + HEALER = 0x04, + DAMAGE = 0x08 }; struct LookingForGroupSlot @@ -438,7 +439,9 @@ enum PlayerFlags PLAYER_FLAGS_UNK22 = 0x00200000, PLAYER_FLAGS_UNK23 = 0x00400000, PLAYER_ALLOW_ONLY_ABILITY = 0x00800000, // used by bladestorm and killing spree - PLAYER_FLAGS_UNK25 = 0x01000000 // disabled all melee ability on tab include autoattack + PLAYER_FLAGS_UNK25 = 0x01000000, // disabled all melee ability on tab include autoattack + + PLAYER_FLAGS_NO_XP_GAIN = 0x02000000 }; // used for PLAYER__FIELD_KNOWN_TITLES field (uint64), (1<<bit_index) without (-1) @@ -734,6 +737,9 @@ enum TransferAbortReason TRANSFER_ABORT_NEED_GROUP = 0x0B, // 3.1 TRANSFER_ABORT_NOT_FOUND2 = 0x0C, // 3.1 TRANSFER_ABORT_NOT_FOUND3 = 0x0D, // 3.1 + TRANSFER_ABORT_NOT_FOUND4 = 0x0E, // 3.2 + TRANSFER_ABORT_REALM_ONLY = 0x0F, // All players on party must be from the same realm. + TRANSFER_ABORT_MAP_NOT_ALLOWED = 0x10, // Map can't be entered at this time. }; enum InstanceResetWarningType @@ -745,6 +751,19 @@ enum InstanceResetWarningType RAID_INSTANCE_EXPIRED = 5 }; +// PLAYER_FIELD_ARENA_TEAM_INFO_1_1 offsets +enum ArenaTeamInfoType +{ + ARENA_TEAM_ID = 0, + ARENA_TEAM_TYPE = 1, // new in 3.2 - team type? + ARENA_TEAM_MEMBER = 2, // 0 - captain, 1 - member + ARENA_TEAM_GAMES_WEEK = 3, + ARENA_TEAM_GAMES_SEASON = 4, + ARENA_TEAM_WINS_SEASON = 5, + ARENA_TEAM_PERSONAL_RATING = 6, + ARENA_TEAM_END = 7 +}; + class InstanceSave; enum RestType @@ -827,8 +846,8 @@ enum PlayerDelayedOperations DELAYED_SAVE_PLAYER = 0x01, DELAYED_RESURRECT_PLAYER = 0x02, DELAYED_SPELL_CAST_DESERTER = 0x04, - DELAYED_BG_MOUNT_RESTORE = 0x08, ///< Flag to restore mount state after teleport from BG - DELAYED_BG_TAXI_RESTORE = 0x10, ///< Flag to restore taxi state after teleport from BG + DELAYED_BG_MOUNT_RESTORE = 0x08, ///< Flag to restore mount state after teleport from BG + DELAYED_BG_TAXI_RESTORE = 0x10, ///< Flag to restore taxi state after teleport from BG DELAYED_END }; @@ -988,12 +1007,11 @@ class MANGOS_DLL_SPEC Player : public Unit bool IsInWater() const { return m_isInWater; } bool IsUnderWater() const; - bool IsFalling() { return GetPositionZ() < m_lastFallZ; } void SendInitialPacketsBeforeAddToMap(); void SendInitialPacketsAfterAddToMap(); void SendTransferAborted(uint32 mapid, uint8 reason, uint8 arg = 0); - void SendInstanceResetWarning(uint32 mapid, uint32 difficulty, uint32 time); + void SendInstanceResetWarning(uint32 mapid, Difficulty difficulty, uint32 time); Creature* GetNPCIfCanInteractWith(uint64 guid, uint32 npcflagmask); bool CanInteractWithNPCs(bool alive = true) const; @@ -1001,13 +1019,13 @@ class MANGOS_DLL_SPEC Player : public Unit bool ToggleAFK(); bool ToggleDND(); - bool isAFK() const { return HasFlag(PLAYER_FLAGS,PLAYER_FLAGS_AFK); }; - bool isDND() const { return HasFlag(PLAYER_FLAGS,PLAYER_FLAGS_DND); }; + bool isAFK() const { return HasFlag(PLAYER_FLAGS,PLAYER_FLAGS_AFK); } + bool isDND() const { return HasFlag(PLAYER_FLAGS,PLAYER_FLAGS_DND); } uint8 chatTag() const; std::string afkMsg; std::string dndMsg; - uint32 GetBarberShopCost(uint8 newhairstyle, uint8 newhaircolor, uint8 newfacialhair); + uint32 GetBarberShopCost(uint8 newhairstyle, uint8 newhaircolor, uint8 newfacialhair, BarberShopStyleEntry const* newSkin=NULL); PlayerSocial *GetSocial() { return m_social; } @@ -1039,8 +1057,8 @@ class MANGOS_DLL_SPEC Player : public Unit time_t m_logintime; time_t m_Last_tick; uint32 m_Played_time[MAX_PLAYED_TIME_INDEX]; - uint32 GetTotalPlayedTime() { return m_Played_time[PLAYED_TIME_TOTAL]; }; - uint32 GetLevelPlayedTime() { return m_Played_time[PLAYED_TIME_LEVEL]; }; + uint32 GetTotalPlayedTime() { return m_Played_time[PLAYED_TIME_TOTAL]; } + uint32 GetLevelPlayedTime() { return m_Played_time[PLAYED_TIME_LEVEL]; } void setDeathState(DeathState s); // overwrite Unit::setDeathState @@ -1051,21 +1069,21 @@ class MANGOS_DLL_SPEC Player : public Unit inn_pos_y = y; inn_pos_z = z; time_inn_enter = time; - }; + } - float GetRestBonus() const { return m_rest_bonus; }; + float GetRestBonus() const { return m_rest_bonus; } void SetRestBonus(float rest_bonus_new); - RestType GetRestType() const { return rest_type; }; - void SetRestType(RestType n_r_type) { rest_type = n_r_type; }; + RestType GetRestType() const { return rest_type; } + void SetRestType(RestType n_r_type) { rest_type = n_r_type; } - uint32 GetInnPosMapId() const { return inn_pos_mapid; }; - float GetInnPosX() const { return inn_pos_x; }; - float GetInnPosY() const { return inn_pos_y; }; - float GetInnPosZ() const { return inn_pos_z; }; + uint32 GetInnPosMapId() const { return inn_pos_mapid; } + float GetInnPosX() const { return inn_pos_x; } + float GetInnPosY() const { return inn_pos_y; } + float GetInnPosZ() const { return inn_pos_z; } - int GetTimeInnEnter() const { return time_inn_enter; }; - void UpdateInnerTime (int time) { time_inn_enter = time; }; + int GetTimeInnEnter() const { return time_inn_enter; } + void UpdateInnerTime (int time) { time_inn_enter = time; } Pet* GetPet() const; Pet* SummonPet(uint32 entry, float x, float y, float z, float ang, PetType petType, uint32 despwtime); @@ -1324,12 +1342,12 @@ class MANGOS_DLL_SPEC Player : public Unit void SendQuestUpdateAddItem( Quest const* pQuest, uint32 item_idx, uint32 count ); void SendQuestUpdateAddCreatureOrGo( Quest const* pQuest, uint64 guid, uint32 creatureOrGO_idx, uint32 old_count, uint32 add_count ); - uint64 GetDivider() { return m_divider; }; - void SetDivider( uint64 guid ) { m_divider = guid; }; + uint64 GetDivider() { return m_divider; } + void SetDivider( uint64 guid ) { m_divider = guid; } - uint32 GetInGameTime() { return m_ingametime; }; + uint32 GetInGameTime() { return m_ingametime; } - void SetInGameTime( uint32 time ) { m_ingametime = time; }; + void SetInGameTime( uint32 time ) { m_ingametime = time; } void AddTimedQuest( uint32 quest_id ) { m_timedquests.insert(quest_id); } void RemoveTimedQuest( uint32 quest_id ) { m_timedquests.erase(quest_id); } @@ -1421,15 +1439,14 @@ class MANGOS_DLL_SPEC Player : public Unit void AddNewMailDeliverTime(time_t deliver_time); bool IsMailsLoaded() const { return m_mailsLoaded; } - //void SetMail(Mail *m); void RemoveMail(uint32 id); void AddMail(Mail* mail) { m_mail.push_front(mail);}// for call from WorldSession::SendMailTo - uint32 GetMailSize() { return m_mail.size();}; + uint32 GetMailSize() { return m_mail.size();} Mail* GetMail(uint32 id); - PlayerMails::iterator GetMailBegin() { return m_mail.begin();}; - PlayerMails::iterator GetMailEnd() { return m_mail.end();}; + PlayerMails::iterator GetMailBegin() { return m_mail.begin();} + PlayerMails::iterator GetMailEnd() { return m_mail.end();} /*********************************************************/ /*** MAILED ITEMS SYSTEM ***/ @@ -1575,7 +1592,7 @@ class MANGOS_DLL_SPEC Player : public Unit m_resurrectZ = Z; m_resurrectHealth = health; m_resurrectMana = mana; - }; + } void clearResurrectRequestData() { setResurrectRequestData(0,0,0.0f,0.0f,0.0f,0,0); } bool isRessurectRequestedBy(uint64 guid) const { return m_resurrectGUID == guid; } bool isRessurectRequested() const { return m_resurrectGUID != 0; } @@ -1626,6 +1643,7 @@ class MANGOS_DLL_SPEC Player : public Unit void UpdateDuelFlag(time_t currTime); void CheckDuelDistance(time_t currTime); void DuelComplete(DuelCompleteType type); + void SendDuelCountdown(uint32 counter); bool IsGroupVisibleFor(Player* p) const; bool IsInSameGroupWith(Player const* p) const; @@ -1646,19 +1664,22 @@ class MANGOS_DLL_SPEC Player : public Unit static void RemovePetitionsAndSigns(uint64 guid, uint32 type); // Arena Team - void SetInArenaTeam(uint32 ArenaTeamId, uint8 slot) + void SetInArenaTeam(uint32 ArenaTeamId, uint8 slot, uint8 type) { - SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (slot * 6), ArenaTeamId); + SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (slot * ARENA_TEAM_END) + ARENA_TEAM_ID, ArenaTeamId); + SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (slot * ARENA_TEAM_END) + ARENA_TEAM_TYPE, type); } - uint32 GetArenaTeamId(uint8 slot) { return GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (slot * 6)); } + uint32 GetArenaTeamId(uint8 slot) { return GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (slot * ARENA_TEAM_END)); } static uint32 GetArenaTeamIdFromDB(uint64 guid, uint8 slot); void SetArenaTeamIdInvited(uint32 ArenaTeamId) { m_ArenaTeamIdInvited = ArenaTeamId; } uint32 GetArenaTeamIdInvited() { return m_ArenaTeamIdInvited; } static void LeaveAllArenaTeams(uint64 guid); - void SetDifficulty(uint32 dungeon_difficulty) { m_dungeonDifficulty = dungeon_difficulty; } - uint8 GetDifficulty() { return m_dungeonDifficulty; } - bool IsHeroic() { return m_dungeonDifficulty == DIFFICULTY_HEROIC; } + Difficulty GetDifficulty(bool isRaid) const { return isRaid ? m_raidDifficulty : m_dungeonDifficulty; } + Difficulty GetDungeonDifficulty() const { return m_dungeonDifficulty; } + Difficulty GetRaidDifficulty() const { return m_raidDifficulty; } + void SetDungeonDifficulty(Difficulty dungeon_difficulty) { m_dungeonDifficulty = dungeon_difficulty; } + void SetRaidDifficulty(Difficulty raid_difficulty) { m_raidDifficulty = raid_difficulty; } bool UpdateSkill(uint32 skill_id, uint32 step); bool UpdateSkillPro(uint16 SkillId, int32 Chance, uint32 step); @@ -1701,9 +1722,11 @@ class MANGOS_DLL_SPEC Player : public Unit float GetRatingCoefficient(CombatRating cr) const; float GetRatingBonusValue(CombatRating cr) const; uint32 GetMeleeCritDamageReduction(uint32 damage) const; + uint32 GetMeleeDamageReduction(uint32 damage) const; uint32 GetRangedCritDamageReduction(uint32 damage) const; + uint32 GetRangedDamageReduction(uint32 damage) const; uint32 GetSpellCritDamageReduction(uint32 damage) const; - uint32 GetDotDamageReduction(uint32 damage) const; + uint32 GetSpellDamageReduction(uint32 damage) const; uint32 GetBaseSpellPowerBonus() { return m_baseSpellPower; } float GetExpertiseDodgeOrParryReduction(WeaponAttackType attType) const; @@ -1721,6 +1744,7 @@ class MANGOS_DLL_SPEC Player : public Unit void UpdateArmorPenetration(int32 amount); void UpdateExpertise(WeaponAttackType attType); void ApplyManaRegenBonus(int32 amount, bool apply); + void ApplyHealthRegenBonus(int32 amount, bool apply); void UpdateManaRegen(); const uint64& GetLootGUID() const { return m_lootGuid; } @@ -1746,7 +1770,8 @@ class MANGOS_DLL_SPEC Player : public Unit void SendExplorationExperience(uint32 Area, uint32 Experience); void SendDungeonDifficulty(bool IsInGroup); - void ResetInstances(uint8 method); + void SendRaidDifficulty(bool IsInGroup); + void ResetInstances(uint8 method, bool isRaid); void SendResetInstanceSuccess(uint32 MapId); void SendResetInstanceFailed(uint32 reason, uint32 MapId); void SendResetFailedNotify(uint32 mapid); @@ -2049,8 +2074,8 @@ class MANGOS_DLL_SPEC Player : public Unit bool isRested() const { return GetRestTime() >= 10*IN_MILISECONDS; } uint32 GetXPRestBonus(uint32 xp); - uint32 GetRestTime() const { return m_restTime;}; - void SetRestTime(uint32 v) { m_restTime = v;}; + uint32 GetRestTime() const { return m_restTime;} + void SetRestTime(uint32 v) { m_restTime = v;} /*********************************************************/ /*** ENVIROMENTAL SYSTEM ***/ @@ -2163,12 +2188,12 @@ class MANGOS_DLL_SPEC Player : public Unit uint32 m_HomebindTimer; bool m_InstanceValid; // permanent binds and solo binds by difficulty - BoundInstancesMap m_boundInstances[TOTAL_DIFFICULTIES]; - InstancePlayerBind* GetBoundInstance(uint32 mapid, uint8 difficulty); - BoundInstancesMap& GetBoundInstances(uint8 difficulty) { return m_boundInstances[difficulty]; } - InstanceSave * GetInstanceSave(uint32 mapid); - void UnbindInstance(uint32 mapid, uint8 difficulty, bool unload = false); - void UnbindInstance(BoundInstancesMap::iterator &itr, uint8 difficulty, bool unload = false); + BoundInstancesMap m_boundInstances[MAX_DIFFICULTY]; + InstancePlayerBind* GetBoundInstance(uint32 mapid, Difficulty difficulty); + BoundInstancesMap& GetBoundInstances(Difficulty difficulty) { return m_boundInstances[difficulty]; } + InstanceSave * GetInstanceSave(uint32 mapid, bool raid); + void UnbindInstance(uint32 mapid, Difficulty difficulty, bool unload = false); + void UnbindInstance(BoundInstancesMap::iterator &itr, Difficulty difficulty, bool unload = false); InstancePlayerBind* BindToInstance(InstanceSave *save, bool permanent, bool load = false); void SendRaidInfo(); void SendSavedInstances(); @@ -2239,6 +2264,11 @@ class MANGOS_DLL_SPEC Player : public Unit //bool isActiveObject() const { return true; } bool canSeeSpellClickOn(Creature const* creature) const; + uint32 GetActionButtonSpell(uint8 button) const + { + ActionButtonList::const_iterator ab = m_actionButtons.find(button); + return ab != m_actionButtons.end() && ab->second.uState != ACTIONBUTTON_DELETED && ab->second.GetType() == ACTION_BUTTON_SPELL ? ab->second.GetAction() : 0; + } uint32 GetChampioningFaction() const { return m_ChampioningFaction; } void SetChampioningFaction(uint32 faction) { m_ChampioningFaction = faction; } @@ -2342,7 +2372,8 @@ Spell * m_spellModTakingSpell; uint32 m_nextSave; time_t m_speakTime; uint32 m_speakCount; - uint32 m_dungeonDifficulty; + Difficulty m_dungeonDifficulty; + Difficulty m_raidDifficulty; uint32 m_atLoginFlags; @@ -2382,6 +2413,7 @@ Spell * m_spellModTakingSpell; uint16 m_baseSpellPower; uint16 m_baseFeralAP; uint16 m_baseManaRegen; + uint16 m_baseHealthRegen; SpellModList m_spellMods[MAX_SPELLMOD]; //uint32 m_pad; @@ -2407,8 +2439,6 @@ Spell * m_spellModTakingSpell; uint16 tradeItems[TRADE_SLOT_COUNT]; uint32 tradeGold; - time_t m_nextThinkTime; - bool m_DailyQuestChanged; time_t m_lastDailyQuestTime; @@ -2442,7 +2472,6 @@ Spell * m_spellModTakingSpell; float m_rest_bonus; RestType rest_type; ////////////////////Rest System///////////////////// - uint32 m_resetTalentsCost; time_t m_resetTalentsTime; uint32 m_usedTalentCount; |