diff options
Diffstat (limited to 'src')
33 files changed, 883 insertions, 642 deletions
diff --git a/src/bindings/scripts/include/sc_creature.cpp b/src/bindings/scripts/include/sc_creature.cpp index cbbb574d253..d18a65f66f5 100644 --- a/src/bindings/scripts/include/sc_creature.cpp +++ b/src/bindings/scripts/include/sc_creature.cpp @@ -615,7 +615,7 @@ void FillSpellSummary() //Spell targets AoE at enemy if ( TempSpell->EffectImplicitTargetA[j] == TARGET_ALL_ENEMY_IN_AREA || TempSpell->EffectImplicitTargetA[j] == TARGET_ALL_ENEMY_IN_AREA_INSTANT || - TempSpell->EffectImplicitTargetA[j] == TARGET_ALL_AROUND_CASTER || + TempSpell->EffectImplicitTargetA[j] == TARGET_DEST_CASTER || TempSpell->EffectImplicitTargetA[j] == TARGET_ALL_ENEMY_IN_AREA_CHANNELED ) SpellSummary[i].Targets |= 1 << (SELECT_TARGET_AOE_ENEMY-1); @@ -624,7 +624,7 @@ void FillSpellSummary() TempSpell->EffectImplicitTargetA[j] == TARGET_CURRENT_ENEMY_COORDINATES || TempSpell->EffectImplicitTargetA[j] == TARGET_ALL_ENEMY_IN_AREA || TempSpell->EffectImplicitTargetA[j] == TARGET_ALL_ENEMY_IN_AREA_INSTANT || - TempSpell->EffectImplicitTargetA[j] == TARGET_ALL_AROUND_CASTER || + TempSpell->EffectImplicitTargetA[j] == TARGET_DEST_CASTER || TempSpell->EffectImplicitTargetA[j] == TARGET_ALL_ENEMY_IN_AREA_CHANNELED ) SpellSummary[i].Targets |= 1 << (SELECT_TARGET_ANY_ENEMY-1); @@ -637,7 +637,7 @@ void FillSpellSummary() //Spell targets aoe friends if ( TempSpell->EffectImplicitTargetA[j] == TARGET_ALL_PARTY_AROUND_CASTER || TempSpell->EffectImplicitTargetA[j] == TARGET_AREAEFFECT_PARTY || - TempSpell->EffectImplicitTargetA[j] == TARGET_ALL_AROUND_CASTER) + TempSpell->EffectImplicitTargetA[j] == TARGET_DEST_CASTER) SpellSummary[i].Targets |= 1 << (SELECT_TARGET_AOE_FRIEND-1); //Spell targets any friend(or self) @@ -646,7 +646,7 @@ void FillSpellSummary() TempSpell->EffectImplicitTargetA[j] == TARGET_SINGLE_PARTY || TempSpell->EffectImplicitTargetA[j] == TARGET_ALL_PARTY_AROUND_CASTER || TempSpell->EffectImplicitTargetA[j] == TARGET_AREAEFFECT_PARTY || - TempSpell->EffectImplicitTargetA[j] == TARGET_ALL_AROUND_CASTER) + TempSpell->EffectImplicitTargetA[j] == TARGET_DEST_CASTER) SpellSummary[i].Targets |= 1 << (SELECT_TARGET_ANY_FRIEND-1); //Make sure that this spell includes a damage effect diff --git a/src/game/AchievementMgr.cpp b/src/game/AchievementMgr.cpp index ad8a4306109..36fdb216d17 100644 --- a/src/game/AchievementMgr.cpp +++ b/src/game/AchievementMgr.cpp @@ -325,6 +325,10 @@ void AchievementMgr::CheckAllAchievementCriteria() void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, uint32 miscvalue1, uint32 miscvalue2, Unit *unit, uint32 time) { sLog.outDetail("AchievementMgr::UpdateAchievementCriteria(%u, %u, %u, %u)", type, miscvalue1, miscvalue2, time); + + if (!sWorld.getConfig(CONFIG_GM_ALLOW_ACHIEVEMENT_GAINS) && m_player->GetSession()->GetSecurity() > SEC_PLAYER) + return; + AchievementCriteriaEntryList const& achievementCriteriaList = achievementmgr.GetAchievementCriteriaByType(type); for(AchievementCriteriaEntryList::const_iterator i = achievementCriteriaList.begin(); i!=achievementCriteriaList.end(); ++i) { @@ -930,7 +934,7 @@ void AchievementGlobalMgr::LoadAchievementCriteriaList() } sLog.outString(); - sLog.outErrorDb(">> Loaded %u achievement criteria.",m_AchievementCriteriasByType->size()); + sLog.outString(">> Loaded %u achievement criteria.",m_AchievementCriteriasByType->size()); } diff --git a/src/game/BattleGroundMgr.cpp b/src/game/BattleGroundMgr.cpp index 1065eecfa29..91a73bb2ae6 100644 --- a/src/game/BattleGroundMgr.cpp +++ b/src/game/BattleGroundMgr.cpp @@ -1244,17 +1244,18 @@ void BattleGroundMgr::BuildBattleGroundStatusPacket(WorldPacket *data, BattleGro void BattleGroundMgr::BuildPvpLogDataPacket(WorldPacket *data, BattleGround *bg) { uint8 type = (bg->isArena() ? 1 : 0); - // last check on 2.4.1 + // last check on 3.0.3 data->Initialize(MSG_PVP_LOG_DATA, (1+1+4+40*bg->GetPlayerScoresSize())); - *data << uint8(type); // seems to be type (battleground=0/arena=1) + *data << uint8(type); // type (battleground=0/arena=1) if(type) // arena { // it seems this must be according to BG_WINNER_A/H and _NOT_ BG_TEAM_A/H for(int i = 1; i >= 0; --i) { - *data << uint32(3000-bg->m_ArenaTeamRatingChanges[i]); // rating change: showed value - 3000 + *data << uint32(bg->m_ArenaTeamRatingChanges[i]); *data << uint32(3999); // huge thanks for TOM_RUS for this! + *data << uint32(0); // unknown - new in 3.0.3 sLog.outDebug("rating change: %d", bg->m_ArenaTeamRatingChanges[i]); } for(int i = 1; i >= 0; --i) @@ -1268,9 +1269,9 @@ void BattleGroundMgr::BuildPvpLogDataPacket(WorldPacket *data, BattleGround *bg) } } - if(bg->GetWinner() == 2) + if(bg->GetStatus() != STATUS_WAIT_LEAVE) { - *data << uint8(0); // bg in progress + *data << uint8(0); // bg not ended } else { @@ -1284,9 +1285,6 @@ void BattleGroundMgr::BuildPvpLogDataPacket(WorldPacket *data, BattleGround *bg) { *data << (uint64)itr->first; *data << (int32)itr->second->KillingBlows; - Player *plr = objmgr.GetPlayer(itr->first); - uint32 team = bg->GetPlayerTeam(itr->first); - if(!team && plr) team = plr->GetTeam(); if(type == 0) { *data << (int32)itr->second->HonorableKills; @@ -1295,18 +1293,12 @@ void BattleGroundMgr::BuildPvpLogDataPacket(WorldPacket *data, BattleGround *bg) } else { - // that part probably wrong - if(plr) - { - if(team == HORDE) - *data << uint8(0); - else if(team == ALLIANCE) - { - *data << uint8(1); - } - else - *data << uint8(0); - } + Player *plr = objmgr.GetPlayer(itr->first); + uint32 team = bg->GetPlayerTeam(itr->first); + if(!team && plr) + team = plr->GetTeam(); + if( ( bg->GetWinner()==0 && team == ALLIANCE ) || ( bg->GetWinner()==1 && team==HORDE ) ) + *data << uint8(1); else *data << uint8(0); } diff --git a/src/game/Chat.cpp b/src/game/Chat.cpp index 09eb5594f62..42fe369e1d4 100644 --- a/src/game/Chat.cpp +++ b/src/game/Chat.cpp @@ -36,6 +36,22 @@ #include "AccountMgr.h" #include "TicketMgr.h" +// Supported shift-links (client generated and server side) +// |color|Harea:area_id|h[name]|h|r +// |color|Hcreature:creature_guid|h[name]|h|r +// |color|Hcreature_entry:creature_id|h[name]|h|r +// |color|Hgameevent:id|h[name]|h|r +// |color|Hgameobject:go_guid|h[name]|h|r +// |color|Hgameobject_entry:go_id|h[name]|h|r +// |color|Hitem:item_id:perm_ench_id:0:0|h[name]|h|r +// |color|Hitemset:itemset_id|h[name]|h|r +// |color|Hquest:quest_id|h[name]|h|r +// |color|Hskill:skill_id|h[name]|h|r +// |color|Hspell:spell_id|h[name]|h|r - client, spellbook spell icon shift-click +// |color|Htalent:talent_id,rank|h[name]|h|r - client, talent icon shift-click +// |color|Htele:id|h[name]|h|r +// |color|Htrade:spell_id,cur_value,max_value,unk3int,unk3str|h[name]|h|r - client, spellbook profession icon shift-click + bool ChatHandler::load_command_table = true; ChatCommand * ChatHandler::getCommandTable() @@ -1317,9 +1333,18 @@ GameObject* ChatHandler::GetObjectGlobalyWithGuidOrNearWithDbGuid(uint32 lowguid return obj; } -static char const* const spellTalentKeys[] = { - "Hspell", - "Htalent", +enum SpellLinkType +{ + SPELL_LINK_SPELL = 0, + SPELL_LINK_TALENT = 1, + SPELL_LINK_TRADE = 2 +}; + +static char const* const spellKeys[] = +{ + "Hspell", // normal spell + "Htalent", // talent spell + "Htrade", // profession/skill spell 0 }; @@ -1327,31 +1352,41 @@ uint32 ChatHandler::extractSpellIdFromLink(char* text) { // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r // number or [name] Shift-click form |color|Htalent:talent_id,rank|h[name]|h|r + // number or [name] Shift-click form |color|Htrade:spell_id,skill_id,max_value,cur_value|h[name]|h|r int type = 0; - char* rankS = NULL; - char* idS = extractKeyFromLink(text,spellTalentKeys,&type,&rankS); + char* param1_str = NULL; + char* idS = extractKeyFromLink(text,spellKeys,&type,¶m1_str); if(!idS) return 0; uint32 id = (uint32)atol(idS); - // spell - if(type==0) - return id; + switch(type) + { + case SPELL_LINK_SPELL: + return id; + case SPELL_LINK_TALENT: + { + // talent + TalentEntry const* talentEntry = sTalentStore.LookupEntry(id); + if(!talentEntry) + return 0; - // talent - TalentEntry const* talentEntry = sTalentStore.LookupEntry(id); - if(!talentEntry) - return 0; + int32 rank = param1_str ? (uint32)atol(param1_str) : 0; + if(rank >= 5) + return 0; - int32 rank = rankS ? (uint32)atol(rankS) : 0; - if(rank >= 5) - return 0; + if(rank < 0) + rank = 0; - if(rank < 0) - rank = 0; + return talentEntry->RankID[rank]; + } + case SPELL_LINK_TRADE: + return id; + } - return talentEntry->RankID[rank]; + // unknown type? + return 0; } GameTele const* ChatHandler::extractGameTeleFromLink(char* text) diff --git a/src/game/Chat.h b/src/game/Chat.h index 73b561b164d..483f3c97863 100644 --- a/src/game/Chat.h +++ b/src/game/Chat.h @@ -499,8 +499,10 @@ class ChatHandler Player* getSelectedPlayer(); Creature* getSelectedCreature(); Unit* getSelectedUnit(); + char* extractKeyFromLink(char* text, char const* linkType, char** something1 = NULL); char* extractKeyFromLink(char* text, char const* const* linkTypes, int* found_idx, char** something1 = NULL); + uint32 extractSpellIdFromLink(char* text); GameTele const* extractGameTeleFromLink(char* text); bool GetPlayerGroupAndGUIDByName(const char* cname, Player* &plr, Group* &group, uint64 &guid, bool offline = false); diff --git a/src/game/GameObject.cpp b/src/game/GameObject.cpp index a888ba6ec5b..99fe5f725bc 100644 --- a/src/game/GameObject.cpp +++ b/src/game/GameObject.cpp @@ -360,8 +360,8 @@ void GameObject::Update(uint32 /*p_time*/) { //Unit *caster = owner ? owner : ok; - //caster->CastSpell(ok, goInfo->trap.spellId, true); CastSpell(ok, goInfo->trap.spellId); + //caster->CastSpell(ok, goInfo->trap.spellId, true, 0, 0, GetGUID()); m_cooldownTime = time(NULL) + 4; // 4 seconds if(NeedDespawn) @@ -411,7 +411,7 @@ void GameObject::Update(uint32 /*p_time*/) for (; it != end; it++) { Unit* owner = Unit::GetUnit(*this, uint64(*it)); - if (owner) owner->CastSpell(owner, spellId, false); + if (owner) owner->CastSpell(owner, spellId, false, 0, 0, GetGUID()); } m_unique_users.clear(); @@ -826,7 +826,7 @@ void GameObject::TriggeringLinkedGameObject( uint32 trapEntry, Unit* target) // found correct GO // FIXME: when GO casting will be implemented trap must cast spell to target if(trapGO) - target->CastSpell(target,trapSpell,true); + target->CastSpell(target,trapSpell,true, 0, 0, GetGUID()); } GameObject* GameObject::LookupFishingHoleAround(float range) diff --git a/src/game/Level2.cpp b/src/game/Level2.cpp index 3105c630157..63b00300639 100644 --- a/src/game/Level2.cpp +++ b/src/game/Level2.cpp @@ -3742,7 +3742,7 @@ bool ChatHandler::HandleLearnAllCraftsCommand(const char* /*args*/) if(!spellInfo || !SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer(),false)) continue; - m_session->GetPlayer()->learnSpell(skillLine->spellId); + m_session->GetPlayer()->learnSpell(skillLine->spellId,false); } } } @@ -3815,7 +3815,7 @@ bool ChatHandler::HandleLearnAllRecipesCommand(const char* args) continue; if( !target->HasSpell(spellInfo->Id) ) - m_session->GetPlayer()->learnSpell(skillLine->spellId); + m_session->GetPlayer()->learnSpell(skillLine->spellId,false); } uint16 maxLevel = target->GetPureMaxSkillValue(skillInfo->id); diff --git a/src/game/Level3.cpp b/src/game/Level3.cpp index 5016d0bcd56..74f012b55d7 100644 --- a/src/game/Level3.cpp +++ b/src/game/Level3.cpp @@ -1292,7 +1292,7 @@ bool ChatHandler::HandleSetSkillCommand(const char* args) { // number or [name] Shift-click form |color|Hskill:skill_id|h[name]|h|r char* skill_p = extractKeyFromLink((char*)args,"Hskill"); - if(!skill_p) + if(!skill_p) return false; char *level_p = strtok (NULL, " "); @@ -1303,7 +1303,6 @@ bool ChatHandler::HandleSetSkillCommand(const char* args) char *max_p = strtok (NULL, " "); int32 skill = atoi(skill_p); - if (skill <= 0) { PSendSysMessage(LANG_INVALID_SKILL_ID, skill); @@ -1353,27 +1352,12 @@ bool ChatHandler::HandleUnLearnCommand(const char* args) return false; // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r - uint32 min_id = extractSpellIdFromLink((char*)args); - if(!min_id) + uint32 spell_id = extractSpellIdFromLink((char*)args); + if(!spell_id) return false; - // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r - char* tail = strtok(NULL,""); - - uint32 max_id = extractSpellIdFromLink(tail); - - if (!max_id) - { - // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r - max_id = min_id+1; - } - else - { - if (max_id < min_id) - std::swap(min_id,max_id); - - max_id=max_id+1; - } + char const* allStr = strtok(NULL," "); + bool allRanks = allStr ? (strncmp(allStr, "all", strlen(allStr)) == 0) : false; Player* target = getSelectedPlayer(); if(!target) @@ -1383,13 +1367,13 @@ bool ChatHandler::HandleUnLearnCommand(const char* args) return false; } - for(uint32 spell=min_id;spell<max_id;spell++) - { - if (target->HasSpell(spell)) - target->removeSpell(spell); - else - SendSysMessage(LANG_FORGET_SPELL); - } + if(allRanks) + spell_id = spellmgr.GetFirstSpellInChain (spell_id); + + if (target->HasSpell(spell_id)) + target->removeSpell(spell_id,false,!allRanks); + else + SendSysMessage(LANG_FORGET_SPELL); return true; } @@ -2054,7 +2038,7 @@ bool ChatHandler::HandleLearnAllCommand(const char* /*args*/) continue; } - m_session->GetPlayer()->learnSpell(spell); + m_session->GetPlayer()->learnSpell(spell,false); } SendSysMessage(LANG_COMMAND_LEARN_MANY_SPELLS); @@ -2094,7 +2078,7 @@ bool ChatHandler::HandleLearnAllGMCommand(const char* /*args*/) continue; } - m_session->GetPlayer()->learnSpell(spell); + m_session->GetPlayer()->learnSpell(spell,false); } SendSysMessage(LANG_LEARNING_GM_SKILLS); @@ -2142,27 +2126,13 @@ bool ChatHandler::HandleLearnAllMySpellsCommand(const char* /*args*/) if(!SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer(),false)) continue; - m_session->GetPlayer()->learnSpell(i); + m_session->GetPlayer()->learnSpell(i,false); } SendSysMessage(LANG_COMMAND_LEARN_CLASS_SPELLS); return true; } -static void learnAllHighRanks(Player* player, uint32 spellid) -{ - SpellChainNode const* node; - do - { - node = spellmgr.GetSpellChainNode(spellid); - player->learnSpell(spellid); - if (!node) - break; - spellid=node->next; - } - while (node->next); -} - bool ChatHandler::HandleLearnAllMyTalentsCommand(const char* /*args*/) { Player* player = m_session->GetPlayer(); @@ -2200,11 +2170,8 @@ bool ChatHandler::HandleLearnAllMyTalentsCommand(const char* /*args*/) if(!spellInfo || !SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer(),false)) continue; - // learn highest rank of talent - player->learnSpell(spellid); - - // and learn all non-talent spell ranks (recursive by tree) - learnAllHighRanks(player,spellid); + // learn highest rank of talent and learn all non-talent spell ranks (recursive by tree) + player->learnSpellHighRank(spellid); } SendSysMessage(LANG_COMMAND_LEARN_CLASS_TALENTS); @@ -2215,7 +2182,7 @@ bool ChatHandler::HandleLearnAllLangCommand(const char* /*args*/) { // skipping UNIVERSAL language (0) for(int i = 1; i < LANGUAGES_COUNT; ++i) - m_session->GetPlayer()->learnSpell(lang_description[i].spell_id); + m_session->GetPlayer()->learnSpell(lang_description[i].spell_id,false); SendSysMessage(LANG_COMMAND_LEARN_ALL_LANG); return true; @@ -2271,25 +2238,31 @@ bool ChatHandler::HandleLearnCommand(const char* args) if(!spell || !sSpellStore.LookupEntry(spell)) return false; - if (targetPlayer->HasSpell(spell)) + char const* allStr = strtok(NULL," "); + bool allRanks = allStr ? (strncmp(allStr, "all", strlen(allStr)) == 0) : false; + + SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell); + if(!spellInfo || !SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer())) { - if(targetPlayer == m_session->GetPlayer()) - SendSysMessage(LANG_YOU_KNOWN_SPELL); - else - PSendSysMessage(LANG_TARGET_KNOWN_SPELL,targetPlayer->GetName()); + PSendSysMessage(LANG_COMMAND_SPELL_BROKEN,spell); SetSentErrorMessage(true); return false; } - SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell); - if(!spellInfo || !SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer())) + if (!allRanks && targetPlayer->HasSpell(spell)) { - PSendSysMessage(LANG_COMMAND_SPELL_BROKEN,spell); + if(targetPlayer == m_session->GetPlayer()) + SendSysMessage(LANG_YOU_KNOWN_SPELL); + else + PSendSysMessage(LANG_TARGET_KNOWN_SPELL,targetPlayer->GetName()); SetSentErrorMessage(true); return false; } - targetPlayer->learnSpell(spell); + if(allRanks) + targetPlayer->learnSpellHighRank(spell); + else + targetPlayer->learnSpell(spell,false); return true; } @@ -4703,11 +4676,28 @@ bool ChatHandler::HandleListAurasCommand (const char * /*args*/) for (Unit::AuraMap::const_iterator itr = uAuras.begin(); itr != uAuras.end(); ++itr) { bool talent = GetTalentSpellCost(itr->second->GetId()) > 0; - PSendSysMessage(LANG_COMMAND_TARGET_AURADETAIL, itr->second->GetId(), itr->second->GetEffIndex(), - itr->second->GetModifier()->m_auraname, itr->second->GetAuraDuration(), itr->second->GetAuraMaxDuration(), - itr->second->GetSpellProto()->SpellName[m_session->GetSessionDbcLocale()], - (itr->second->IsPassive() ? passiveStr : ""),(talent ? talentStr : ""), - IS_PLAYER_GUID(itr->second->GetCasterGUID()) ? "player" : "creature",GUID_LOPART(itr->second->GetCasterGUID())); + + char const* name = itr->second->GetSpellProto()->SpellName[m_session->GetSessionDbcLocale()]; + + if (m_session) + { + std::ostringstream ss_name; + ss_name << "|cffffffff|Hspell:" << itr->second->GetId() << "|h[" << name << "]|h|r"; + + PSendSysMessage(LANG_COMMAND_TARGET_AURADETAIL, itr->second->GetId(), itr->second->GetEffIndex(), + itr->second->GetModifier()->m_auraname, itr->second->GetAuraDuration(), itr->second->GetAuraMaxDuration(), + ss_name.str().c_str(), + (itr->second->IsPassive() ? passiveStr : ""),(talent ? talentStr : ""), + IS_PLAYER_GUID(itr->second->GetCasterGUID()) ? "player" : "creature",GUID_LOPART(itr->second->GetCasterGUID())); + } + else + { + PSendSysMessage(LANG_COMMAND_TARGET_AURADETAIL, itr->second->GetId(), itr->second->GetEffIndex(), + itr->second->GetModifier()->m_auraname, itr->second->GetAuraDuration(), itr->second->GetAuraMaxDuration(), + name, + (itr->second->IsPassive() ? passiveStr : ""),(talent ? talentStr : ""), + IS_PLAYER_GUID(itr->second->GetCasterGUID()) ? "player" : "creature",GUID_LOPART(itr->second->GetCasterGUID())); + } } for (int i = 0; i < TOTAL_AURAS; i++) { @@ -4717,9 +4707,24 @@ bool ChatHandler::HandleListAurasCommand (const char * /*args*/) for (Unit::AuraList::const_iterator itr = uAuraList.begin(); itr != uAuraList.end(); ++itr) { bool talent = GetTalentSpellCost((*itr)->GetId()) > 0; - PSendSysMessage(LANG_COMMAND_TARGET_AURASIMPLE, (*itr)->GetId(), (*itr)->GetEffIndex(), - (*itr)->GetSpellProto()->SpellName[m_session->GetSessionDbcLocale()],((*itr)->IsPassive() ? passiveStr : ""),(talent ? talentStr : ""), - IS_PLAYER_GUID((*itr)->GetCasterGUID()) ? "player" : "creature",GUID_LOPART((*itr)->GetCasterGUID())); + + char const* name = (*itr)->GetSpellProto()->SpellName[m_session->GetSessionDbcLocale()]; + + if (m_session) + { + std::ostringstream ss_name; + ss_name << "|cffffffff|Hspell:" << (*itr)->GetId() << "|h[" << name << "]|h|r"; + + PSendSysMessage(LANG_COMMAND_TARGET_AURASIMPLE, (*itr)->GetId(), (*itr)->GetEffIndex(), + ss_name.str().c_str(),((*itr)->IsPassive() ? passiveStr : ""),(talent ? talentStr : ""), + IS_PLAYER_GUID((*itr)->GetCasterGUID()) ? "player" : "creature",GUID_LOPART((*itr)->GetCasterGUID())); + } + else + { + PSendSysMessage(LANG_COMMAND_TARGET_AURASIMPLE, (*itr)->GetId(), (*itr)->GetEffIndex(), + name,((*itr)->IsPassive() ? passiveStr : ""),(talent ? talentStr : ""), + IS_PLAYER_GUID((*itr)->GetCasterGUID()) ? "player" : "creature",GUID_LOPART((*itr)->GetCasterGUID())); + } } } return true; diff --git a/src/game/NPCHandler.cpp b/src/game/NPCHandler.cpp index a99208e63bd..4f721c8a9de 100644 --- a/src/game/NPCHandler.cpp +++ b/src/game/NPCHandler.cpp @@ -243,24 +243,22 @@ void WorldSession::HandleTrainerBuySpellOpcode( WorldPacket & recv_data ) _player->ModifyMoney( -int32(nSpellCost) ); + WorldPacket data(SMSG_PLAY_SPELL_VISUAL, 12); // visual effect on trainer + data << uint64(guid) << uint32(0xB3); + SendPacket(&data); + + data.Initialize(SMSG_PLAY_SPELL_IMPACT, 12); // visual effect on player + data << uint64(_player->GetGUID()) << uint32(0x016A); + SendPacket(&data); + // learn explicitly or cast explicitly if(trainer_spell->IsCastable ()) //FIXME: prof. spell entry in trainer list not marked gray until list re-open. - unit->CastSpell(_player,trainer_spell->spell,true); + _player->CastSpell(_player,trainer_spell->spell,true); else - { - WorldPacket data(SMSG_PLAY_SPELL_VISUAL, 12); // visual effect on trainer - data << uint64(guid) << uint32(0xB3); - SendPacket(&data); - - data.Initialize(SMSG_PLAY_SPELL_IMPACT, 12); // visual effect on player - data << uint64(_player->GetGUID()) << uint32(0x016A); - SendPacket(&data); - - _player->learnSpell(spellId); - } + _player->learnSpell(spellId,false); - WorldPacket data(SMSG_TRAINER_BUY_SUCCEEDED, 12); + data.Initialize(SMSG_TRAINER_BUY_SUCCEEDED, 12); data << uint64(guid) << uint32(trainer_spell->spell); SendPacket(&data); } diff --git a/src/game/ObjectAccessor.cpp b/src/game/ObjectAccessor.cpp index 3c54244ae13..1891dc0396d 100644 --- a/src/game/ObjectAccessor.cpp +++ b/src/game/ObjectAccessor.cpp @@ -173,11 +173,16 @@ Corpse* ObjectAccessor::GetCorpse(WorldObject const &u, uint64 guid) { Corpse * ret = GetObjectInWorld(guid, (Corpse*)NULL); - if(ret && ret->GetMapId() != u.GetMapId()) ret = NULL; + if(!ret) + return NULL; + if(ret->GetMapId() != u.GetMapId()) + ret = NULL; + if(ret->GetInstanceId() != u.GetInstanceId()) + return NULL; return ret; } -Object* ObjectAccessor::GetObjectByTypeMask(Player const &p, uint64 guid, uint32 typemask) +Object* ObjectAccessor::GetObjectByTypeMask(WorldObject const &p, uint64 guid, uint32 typemask) { Object *obj = NULL; @@ -205,9 +210,9 @@ Object* ObjectAccessor::GetObjectByTypeMask(Player const &p, uint64 guid, uint32 if(obj) return obj; } - if(typemask & TYPEMASK_ITEM) + if(typemask & TYPEMASK_ITEM && p.GetTypeId() == TYPEID_PLAYER) { - obj = p.GetItemByGuid( guid ); + obj = ((Player const &)p).GetItemByGuid( guid ); if(obj) return obj; } @@ -218,15 +223,25 @@ GameObject* ObjectAccessor::GetGameObject(WorldObject const &u, uint64 guid) { GameObject * ret = GetObjectInWorld(guid, (GameObject*)NULL); - if(ret && ret->GetMapId() != u.GetMapId()) ret = NULL; + if(!ret) + return NULL; + if(ret->GetMapId() != u.GetMapId()) + ret = NULL; + if(ret->GetInstanceId() != u.GetInstanceId()) + return NULL; return ret; } DynamicObject* -ObjectAccessor::GetDynamicObject(Unit const &u, uint64 guid) +ObjectAccessor::GetDynamicObject(WorldObject const &u, uint64 guid) { DynamicObject * ret = GetObjectInWorld(guid, (DynamicObject*)NULL); - if(ret && ret->GetMapId() != u.GetMapId()) ret = NULL; + if(!ret) + return NULL; + if(ret->GetMapId() != u.GetMapId()) + ret = NULL; + if(ret->GetInstanceId() != u.GetInstanceId()) + return NULL; return ret; } diff --git a/src/game/ObjectAccessor.h b/src/game/ObjectAccessor.h index 6eb9e6ee0f5..350bc62ebad 100644 --- a/src/game/ObjectAccessor.h +++ b/src/game/ObjectAccessor.h @@ -138,7 +138,7 @@ class TRINITY_DLL_DECL ObjectAccessor : public Trinity::Singleton<ObjectAccessor else return NULL; } - static Object* GetObjectByTypeMask(Player const &, uint64, uint32 typemask); + static Object* GetObjectByTypeMask(WorldObject const &, uint64, uint32 typemask); static Creature* GetNPCIfCanInteractWith(Player const &player, uint64 guid, uint32 npcflagmask); static Creature* GetCreature(WorldObject const &, uint64); static Creature* GetCreatureOrPetOrVehicle(WorldObject const &, uint64); @@ -146,7 +146,7 @@ class TRINITY_DLL_DECL ObjectAccessor : public Trinity::Singleton<ObjectAccessor static Pet* GetPet(Unit const &, uint64 guid) { return GetPet(guid); } static Player* GetPlayer(Unit const &, uint64 guid) { return FindPlayer(guid); } static GameObject* GetGameObject(WorldObject const &, uint64); - static DynamicObject* GetDynamicObject(Unit const &, uint64); + static DynamicObject* GetDynamicObject(WorldObject const &, uint64); static Corpse* GetCorpse(WorldObject const &u, uint64 guid); static Pet* GetPet(uint64 guid); static Vehicle* GetVehicle(uint64 guid); diff --git a/src/game/ObjectMgr.cpp b/src/game/ObjectMgr.cpp index ccd78c4be20..4a5c0bbdf0b 100644 --- a/src/game/ObjectMgr.cpp +++ b/src/game/ObjectMgr.cpp @@ -6486,11 +6486,18 @@ void ObjectMgr::LoadReservedPlayersNames() bar.step(); fields = result->Fetch(); std::string name= fields[0].GetCppString(); - if(normalizePlayerName(name)) + + std::wstring wstr; + if(!Utf8toWStr (name,wstr)) { - m_ReservedNames.insert(name); - ++count; + sLog.outError("Table `reserved_name` have invalid name: %s", name.c_str() ); + continue; } + + wstrToLower(wstr); + + m_ReservedNames.insert(wstr); + ++count; } while ( result->NextRow() ); delete result; @@ -6499,6 +6506,17 @@ void ObjectMgr::LoadReservedPlayersNames() sLog.outString( ">> Loaded %u reserved player names", count ); } +bool ObjectMgr::IsReservedName( const std::string& name ) const +{ + std::wstring wstr; + if(!Utf8toWStr (name,wstr)) + return false; + + wstrToLower(wstr); + + return m_ReservedNames.find(wstr) != m_ReservedNames.end(); +} + enum LanguageType { LT_BASIC_LATIN = 0x0000, diff --git a/src/game/ObjectMgr.h b/src/game/ObjectMgr.h index cbf8514fe25..4c8339d7f6f 100644 --- a/src/game/ObjectMgr.h +++ b/src/game/ObjectMgr.h @@ -736,10 +736,7 @@ class ObjectMgr // reserved names void LoadReservedPlayersNames(); - bool IsReservedName(const std::string& name) const - { - return m_ReservedNames.find(name) != m_ReservedNames.end(); - } + bool IsReservedName(const std::string& name) const; // name with valid structure and symbols static bool IsValidName( const std::string& name, bool create = false ); @@ -872,7 +869,7 @@ class ObjectMgr PetCreateSpellMap mPetCreateSpell; //character reserved names - typedef std::set<std::string> ReservedNamesMap; + typedef std::set<std::wstring> ReservedNamesMap; ReservedNamesMap m_ReservedNames; std::set<uint32> m_DisabledPlayerSpells; diff --git a/src/game/Pet.cpp b/src/game/Pet.cpp index 6a39aeb6d3b..0da02b8fe14 100644 --- a/src/game/Pet.cpp +++ b/src/game/Pet.cpp @@ -41,25 +41,14 @@ char const* petTypeSuffix[MAX_PET_TYPE] = "'s Companion" // MINI_PET }; -Pet::Pet(PetType type) : Creature() +Pet::Pet(PetType type) : +Creature(), m_petType(type), m_removed(false), m_happinessTimer(7500), m_duration(0), m_bonusdamage(0), +m_resetTalentsCost(0), m_resetTalentsTime(0), m_usedTalentCount(0), m_auraUpdateMask(0), m_loading(false), +m_declinedname(NULL) { m_isPet = true; m_name = "Pet"; - m_petType = type; - - m_removed = false; m_regenTimer = 4000; - m_happinessTimer = 7500; - m_duration = 0; - m_bonusdamage = 0; - - m_resetTalentsCost = 0; - m_resetTalentsTime = 0; - m_usedTalentCount = 0; - - m_auraUpdateMask = 0; - - m_loading = false; // pets always have a charminfo, even if they are not actually charmed CharmInfo* charmInfo = InitCharmInfo(this); @@ -69,12 +58,6 @@ Pet::Pet(PetType type) : Creature() else if(type == GUARDIAN_PET) // always aggressive charmInfo->SetReactState(REACT_AGGRESSIVE); - m_spells.clear(); - m_Auras.clear(); - m_CreatureSpellCooldowns.clear(); - m_CreatureCategoryCooldowns.clear(); - m_autospells.clear(); - m_declinedname = NULL; m_isActive = true; } @@ -1117,7 +1100,7 @@ void Pet::_LoadSpells() { Field *fields = result->Fetch(); - addSpell(fields[0].GetUInt16(), fields[1].GetUInt16(), PETSPELL_UNCHANGED); + addSpell(fields[0].GetUInt32(), fields[1].GetUInt16(), PETSPELL_UNCHANGED); } while( result->NextRow() ); @@ -1270,7 +1253,7 @@ void Pet::_SaveAuras() } } -bool Pet::addSpell(uint16 spell_id, uint16 active, PetSpellState state, PetSpellType type) +bool Pet::addSpell(uint32 spell_id, uint16 active, PetSpellState state, PetSpellType type) { SpellEntry const *spellInfo = sSpellStore.LookupEntry(spell_id); if (!spellInfo) @@ -1387,7 +1370,7 @@ bool Pet::addSpell(uint16 spell_id, uint16 active, PetSpellState state, PetSpell return true; } -bool Pet::learnSpell(uint16 spell_id) +bool Pet::learnSpell(uint32 spell_id) { // prevent duplicated entires in spell book if (!addSpell(spell_id)) @@ -1424,7 +1407,7 @@ void Pet::learnLevelupSpells() } } -bool Pet::unlearnSpell(uint16 spell_id) +bool Pet::unlearnSpell(uint32 spell_id) { if(removeSpell(spell_id)) { @@ -1442,7 +1425,7 @@ bool Pet::unlearnSpell(uint16 spell_id) return false; } -bool Pet::removeSpell(uint16 spell_id) +bool Pet::removeSpell(uint32 spell_id) { PetSpellMap::iterator itr = m_spells.find(spell_id); if (itr == m_spells.end()) @@ -1476,7 +1459,7 @@ bool Pet::removeSpell(uint16 spell_id) return true; } -bool Pet::_removeSpell(uint16 spell_id) +bool Pet::_removeSpell(uint32 spell_id) { PetSpellMap::iterator itr = m_spells.find(spell_id); if (itr != m_spells.end()) @@ -1493,7 +1476,7 @@ void Pet::InitPetCreateSpells() m_charmInfo->InitPetActionBar(); m_spells.clear(); - int32 petspellid; + uint32 petspellid; PetCreateSpellEntry const* CreateSpells = objmgr.GetPetCreateSpellEntry(GetEntry()); if(CreateSpells) { @@ -1513,7 +1496,7 @@ void Pet::InitPetCreateSpells() if(owner->GetTypeId() == TYPEID_PLAYER && !((Player*)owner)->HasSpell(learn_spellproto->Id)) { if(IsPassiveSpell(petspellid)) //learn passive skills when tamed, not sure if thats right - ((Player*)owner)->learnSpell(learn_spellproto->Id); + ((Player*)owner)->learnSpell(learn_spellproto->Id,false); else AddTeachSpell(learn_spellproto->EffectTriggerSpell[0], learn_spellproto->Id); } @@ -1547,7 +1530,7 @@ void Pet::CheckLearning(uint32 spellid) if(urand(0, 100) < 10) { - ((Player*)owner)->learnSpell(itr->second); + ((Player*)owner)->learnSpell(itr->second,false); m_teachspells.erase(itr); } } @@ -1693,7 +1676,7 @@ void Pet::ToggleAutocast(uint32 spellid, bool apply) // && tempSpell->EffectImplicitTargetA[0] != TARGET_CHAIN_DAMAGE) // return; - PetSpellMap::const_iterator itr = m_spells.find((uint16)spellid); + PetSpellMap::const_iterator itr = m_spells.find(spellid); int i; @@ -1747,7 +1730,7 @@ bool Pet::Create(uint32 guidlow, Map *map, uint32 Entry, uint32 pet_number) bool Pet::HasSpell(uint32 spell) const { - PetSpellMap::const_iterator itr = m_spells.find((uint16)spell); + PetSpellMap::const_iterator itr = m_spells.find(spell); return (itr != m_spells.end() && itr->second->state != PETSPELL_REMOVED ); } diff --git a/src/game/Pet.h b/src/game/Pet.h index 113d1e203fa..3d0573d8f75 100644 --- a/src/game/Pet.h +++ b/src/game/Pet.h @@ -105,7 +105,7 @@ enum PetNameInvalidReason PET_NAME_DECLENSION_DOESNT_MATCH_BASE_NAME = 16 }; -typedef UNORDERED_MAP<uint16, PetSpell*> PetSpellMap; +typedef UNORDERED_MAP<uint32, PetSpell*> PetSpellMap; typedef std::map<uint32,uint32> TeachSpellMap; typedef std::vector<uint32> AutoSpellList; @@ -190,12 +190,12 @@ class Pet : public Creature void _LoadSpells(); void _SaveSpells(); - bool addSpell(uint16 spell_id,uint16 active = ACT_DECIDE, PetSpellState state = PETSPELL_NEW, PetSpellType type = PETSPELL_NORMAL); - bool learnSpell(uint16 spell_id); + bool addSpell(uint32 spell_id,uint16 active = ACT_DECIDE, PetSpellState state = PETSPELL_NEW, PetSpellType type = PETSPELL_NORMAL); + bool learnSpell(uint32 spell_id); void learnLevelupSpells(); - bool unlearnSpell(uint16 spell_id); - bool removeSpell(uint16 spell_id); - bool _removeSpell(uint16 spell_id); + bool unlearnSpell(uint32 spell_id); + bool removeSpell(uint32 spell_id); + bool _removeSpell(uint32 spell_id); PetSpellMap m_spells; TeachSpellMap m_teachspells; diff --git a/src/game/Player.cpp b/src/game/Player.cpp index fffe5ec5fb2..2d584da26f7 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -2649,7 +2649,7 @@ void Player::AddNewMailDeliverTime(time_t deliver_time) } } -bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool disabled) +bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependent, bool disabled) { SpellEntry const *spellInfo = sSpellStore.LookupEntry(spell_id); if (!spellInfo) @@ -2682,29 +2682,80 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool disabled PlayerSpellState state = learning ? PLAYERSPELL_NEW : PLAYERSPELL_UNCHANGED; + bool dependent_set = false; bool disabled_case = false; bool superceded_old = false; PlayerSpellMap::iterator itr = m_spells.find(spell_id); if (itr != m_spells.end()) { + 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(uint32 next = spellmgr.GetNextSpellInChain(spell_id)) + { + if(HasSpell(next)) + { + // high rank already known so this must !active + active = false; + next_active_spell_id = next; + } + } + } + + // not do anything if already known in expected state + 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 + itr->second->state = PLAYERSPELL_UNCHANGED; + + return false; + } + + // dependent spell known as not dependent, overwrite state + if (itr->second->state != PLAYERSPELL_REMOVED && !itr->second->dependent && dependent) + { + itr->second->dependent = dependent; + if (itr->second->state != PLAYERSPELL_NEW) + itr->second->state = PLAYERSPELL_CHANGED; + dependent_set = true; + } + // update active state for known spell if(itr->second->active != active && itr->second->state != PLAYERSPELL_REMOVED && !itr->second->disabled) { itr->second->active = active; - // !IsInWorld() && !learning == explicitly load from DB and then exist in it already and set correctly - if(!IsInWorld() && !learning) + 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) itr->second->state = PLAYERSPELL_CHANGED; - if(!active) + if(active) { - WorldPacket data(SMSG_REMOVED_SPELL, 4); - data << uint16(spell_id); - GetSession()->SendPacket(&data); + if (IsPassiveSpell(spell_id) && IsNeedCastPassiveSpellAtLearn(spellInfo)) + CastSpell (this,spell_id,true); + } + else if(IsInWorld()) + { + if(next_active_spell_id) + { + // update spell ranks in spellbook and action bar + WorldPacket data(SMSG_SUPERCEDED_SPELL, (4)); + data << uint16(spell_id); + data << uint16(next_active_spell_id); + GetSession()->SendPacket( &data ); + } + else + { + WorldPacket data(SMSG_REMOVED_SPELL, 4); + data << uint16(spell_id); + GetSession()->SendPacket(&data); + } } + return active; // learn (show in spell book if active now) } @@ -2733,7 +2784,7 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool disabled 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) + if(!IsInWorld() && !learning && !dependent_set) itr->second->state = PLAYERSPELL_UNCHANGED; return false; @@ -2755,10 +2806,6 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool disabled if(!rankSpellId || rankSpellId==spell_id) continue; - // skip unknown ranks - if(!HasSpell(rankSpellId)) - continue; - removeSpell(rankSpellId); } } @@ -2766,16 +2813,17 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool disabled // non talent spell: learn low ranks (recursive call) else if(uint32 prev_spell = spellmgr.GetPrevSpellInChain(spell_id)) { - if(!IsInWorld()) // at spells loading, no output, but allow save - addSpell(prev_spell,active,true,disabled); + 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); + learnSpell(prev_spell,true); } PlayerSpell *newspell = new PlayerSpell; - newspell->active = active; - newspell->state = state; - newspell->disabled = disabled; + newspell->state = state; + newspell->active = active; + newspell->dependent = dependent; + 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) @@ -2802,7 +2850,8 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool disabled // mark old spell as disable (SMSG_SUPERCEDED_SPELL replace it in client by new) itr->second->active = false; - itr->second->state = PLAYERSPELL_CHANGED; + if(itr->second->state != PLAYERSPELL_NEW) + itr->second->state = PLAYERSPELL_CHANGED; superceded_old = true; // new spell replace old in action bars and spell book. } else if(spellmgr.IsHighRankOfSpell(itr->first,spell_id)) @@ -2844,26 +2893,7 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool disabled // also cast passive spells (including all talents without SPELL_EFFECT_LEARN_SPELL) with additional checks else if (IsPassiveSpell(spell_id)) { - bool need_cast = false; - - switch(spell_id) - { - // some spells not have stance data expacted cast at form change or present - case 5420: need_cast = (m_form == FORM_TREE); break; - case 5419: need_cast = (m_form == FORM_TRAVEL); break; - case 7376: need_cast = (m_form == FORM_DEFENSIVESTANCE); break; - case 7381: need_cast = (m_form == FORM_BERSERKERSTANCE); break; - case 21156: need_cast = (m_form == FORM_BATTLESTANCE); break; - case 21178: need_cast = (m_form == FORM_BEAR || m_form == FORM_DIREBEAR); break; - case 33948: need_cast = (m_form == FORM_FLIGHT); break; - case 34764: need_cast = (m_form == FORM_FLIGHT); break; - case 40121: need_cast = (m_form == FORM_FLIGHT_EPIC); break; - case 40122: need_cast = (m_form == FORM_FLIGHT_EPIC); break; - // another spells have proper stance data - default: need_cast = !spellInfo->Stances || m_form != 0 && (spellInfo->Stances & (1<<(m_form-1))); break; - } - //Check CasterAuraStates - if (need_cast && (!spellInfo->CasterAuraState || HasAuraState(AuraState(spellInfo->CasterAuraState)))) + if(IsNeedCastPassiveSpellAtLearn(spellInfo)) CastSpell(this, spell_id, true); } else if( IsSpellHaveEffect(spellInfo,SPELL_EFFECT_SKILL_STEP) ) @@ -2948,9 +2978,9 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool disabled if(!itr->second.autoLearned) { if(!IsInWorld() || !itr->second.active) // at spells loading, no output, but allow save - addSpell(itr->second.spell,itr->second.active,true,false); + addSpell(itr->second.spell,itr->second.active,true,true,false); else // at normal learning - learnSpell(itr->second.spell); + learnSpell(itr->second.spell,true); } } @@ -2964,14 +2994,39 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool disabled return active && !disabled && !superceded_old; } -void Player::learnSpell(uint32 spell_id) +bool Player::IsNeedCastPassiveSpellAtLearn(SpellEntry const* spellInfo) const +{ + bool need_cast = false; + + switch(spellInfo->Id) + { + // some spells not have stance data expacted cast at form change or present + case 5420: need_cast = (m_form == FORM_TREE); break; + case 5419: need_cast = (m_form == FORM_TRAVEL); break; + case 7376: need_cast = (m_form == FORM_DEFENSIVESTANCE); break; + case 7381: need_cast = (m_form == FORM_BERSERKERSTANCE); break; + case 21156: need_cast = (m_form == FORM_BATTLESTANCE); break; + case 21178: need_cast = (m_form == FORM_BEAR || m_form == FORM_DIREBEAR); break; + case 33948: need_cast = (m_form == FORM_FLIGHT); break; + case 34764: need_cast = (m_form == FORM_FLIGHT); break; + case 40121: need_cast = (m_form == FORM_FLIGHT_EPIC); break; + case 40122: need_cast = (m_form == FORM_FLIGHT_EPIC); break; + // another spells have proper stance data + default: need_cast = !spellInfo->Stances || m_form != 0 && (spellInfo->Stances & (1<<(m_form-1))); break; + } + + //Check CasterAuraStates + return need_cast && (!spellInfo->CasterAuraState || HasAuraState(AuraState(spellInfo->CasterAuraState))); +} + +void Player::learnSpell(uint32 spell_id, bool dependent) { PlayerSpellMap::iterator itr = m_spells.find(spell_id); bool disabled = (itr != m_spells.end()) ? itr->second->disabled : false; bool active = disabled ? itr->second->active : true; - bool learning = addSpell(spell_id,active,true,false); + bool learning = addSpell(spell_id,active,true,dependent,false); // learn all disabled higher ranks (recursive) if(disabled) @@ -2981,7 +3036,7 @@ void Player::learnSpell(uint32 spell_id) { PlayerSpellMap::iterator iter = m_spells.find(node->next); if (iter != m_spells.end() && iter->second->disabled ) - learnSpell(node->next); + learnSpell(node->next,false); } } @@ -2994,7 +3049,7 @@ void Player::learnSpell(uint32 spell_id) GetSession()->SendPacket(&data); } -void Player::removeSpell(uint32 spell_id, bool disabled) +void Player::removeSpell(uint32 spell_id, bool disabled, bool update_action_bar_for_low_rank) { PlayerSpellMap::iterator itr = m_spells.find(spell_id); if (itr == m_spells.end()) @@ -3016,10 +3071,8 @@ void Player::removeSpell(uint32 spell_id, bool disabled) for (uint32 i=reqMap.count(spell_id);i>0;i--,itr2++) removeSpell(itr2->second,disabled); - // removing - WorldPacket data(SMSG_REMOVED_SPELL, 4); - data << uint16(spell_id); - GetSession()->SendPacket(&data); + bool cur_active = itr->second->active; + bool cur_dependent = itr->second->dependent; if (disabled) { @@ -3132,7 +3185,57 @@ void Player::removeSpell(uint32 spell_id, bool disabled) for(SpellLearnSpellMap::const_iterator itr2 = spell_begin; itr2 != spell_end; ++itr2) removeSpell(itr2->second.spell, disabled); - // TODO: recast if need lesser ranks spell for passive with IsPassiveSpellStackableWithRanks + // activate lesser rank in spellbook/action bar, and cast it if need + bool prev_activate = false; + + if(uint32 prev_id = spellmgr.GetPrevSpellInChain (spell_id)) + { + SpellEntry const *spellInfo = sSpellStore.LookupEntry(spell_id); + + // if talent then lesser rank also talent and need learn + if(talentCosts) + learnSpell (prev_id,false); + // if ranked non-stackable spell: need activate lesser rank and update dendence state + else if(cur_active && !SpellMgr::canStackSpellRanks(spellInfo) && spellmgr.GetSpellRank(spellInfo->Id) != 0) + { + // need manually update dependence state (learn spell ignore like attempts) + PlayerSpellMap::iterator prev_itr = m_spells.find(prev_id); + if (prev_itr != m_spells.end()) + { + if(prev_itr->second->dependent != cur_dependent) + { + prev_itr->second->dependent = cur_dependent; + if(prev_itr->second->state != PLAYERSPELL_NEW) + prev_itr->second->state = PLAYERSPELL_CHANGED; + } + + // now re-learn if need re-activate + if(cur_active && !prev_itr->second->active) + { + if(addSpell(prev_id,true,false,prev_itr->second->dependent,prev_itr->second->disabled)) + { + if(update_action_bar_for_low_rank) + { + // downgrade spell ranks in spellbook and action bar + WorldPacket data(SMSG_SUPERCEDED_SPELL, (4)); + data << uint16(spell_id); + data << uint16(prev_id); + GetSession()->SendPacket( &data ); + prev_activate = true; + } + } + } + } + } + } + + // remove from spell book if not replaced by lesser rank + if(!prev_activate) + { + WorldPacket data(SMSG_REMOVED_SPELL, 4); + data << uint16(spell_id); + GetSession()->SendPacket(&data); + } } void Player::RemoveArenaSpellCooldowns() @@ -3355,18 +3458,6 @@ bool Player::resetTalents(bool no_cost) return true; } -bool Player::_removeSpell(uint16 spell_id) -{ - PlayerSpellMap::iterator itr = m_spells.find(spell_id); - if (itr != m_spells.end()) - { - delete itr->second; - m_spells.erase(itr); - return true; - } - return false; -} - Mail* Player::GetMail(uint32 id) { for(PlayerMails::iterator itr = m_mail.begin(); itr != m_mail.end(); ++itr) @@ -3572,8 +3663,16 @@ void Player::DestroyForPlayer( Player *target ) const bool Player::HasSpell(uint32 spell) const { - PlayerSpellMap::const_iterator itr = m_spells.find((uint16)spell); - return (itr != m_spells.end() && itr->second->state != PLAYERSPELL_REMOVED && !itr->second->disabled); + PlayerSpellMap::const_iterator itr = m_spells.find(spell); + return (itr != m_spells.end() && itr->second->state != PLAYERSPELL_REMOVED && + !itr->second->disabled); +} + +bool Player::HasActiveSpell(uint32 spell) const +{ + PlayerSpellMap::const_iterator itr = m_spells.find(spell); + return (itr != m_spells.end() && itr->second->state != PLAYERSPELL_REMOVED && + itr->second->active && !itr->second->disabled); } TrainerSpellState Player::GetTrainerSpellState(TrainerSpell const* trainer_spell) const @@ -4828,7 +4927,7 @@ bool Player::UpdateCraftSkill(uint32 spellid) if(spellEntry && spellEntry->Mechanic==MECHANIC_DISCOVERY) { if(uint32 discoveredSpell = GetSkillDiscoverySpell(_spell_idx->second->skillId, spellid, this)) - learnSpell(discoveredSpell); + learnSpell(discoveredSpell,false); } uint32 craft_skill_gain = sWorld.getConfig(CONFIG_SKILL_GAIN_CRAFTING); @@ -4884,6 +4983,11 @@ bool Player::UpdateFishingSkill() return UpdateSkillPro(SKILL_FISHING,chance*10,gathering_skill_gain); } +// levels sync. with spell requirement for skill levels to learn +// bonus abilities in sSkillLineAbilityStore +// Used only to avoid scan DBC at each skill grow +static uint32 bonusSkillLevels[] = {75,150,225,300,375,450}; + bool Player::UpdateSkillPro(uint16 SkillId, int32 Chance, uint32 step) { sLog.outDebug("UpdateSkillPro(SkillId %d, Chance %3.1f%%)", SkillId, Chance/10.0); @@ -4918,6 +5022,14 @@ bool Player::UpdateSkillPro(uint16 SkillId, int32 Chance, uint32 step) new_value = MaxValue; SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i),MAKE_SKILL_VALUE(new_value,MaxValue)); + for(uint32* bsl = &bonusSkillLevels[0]; *bsl; ++bsl) + { + if((SkillValue < *bsl && new_value >= *bsl)) + { + learnSkillRewardedSpells( SkillId, new_value); + break; + } + } GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL); sLog.outDebug("Player::UpdateSkillPro Chance=%3.1f%% taken", Chance/10.0); return true; @@ -5094,6 +5206,7 @@ void Player::SetSkill(uint32 id, uint16 currVal, uint16 maxVal) if(currVal) { SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i),MAKE_SKILL_VALUE(currVal,maxVal)); + learnSkillRewardedSpells(id, currVal); GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL); } else //remove @@ -5103,27 +5216,11 @@ void Player::SetSkill(uint32 id, uint16 currVal, uint16 maxVal) SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i),0); SetUInt32Value(PLAYER_SKILL_BONUS_INDEX(i),0); - // remove spells that depend on this skill when removing the skill - for (PlayerSpellMap::const_iterator itr = m_spells.begin(), next = m_spells.begin(); itr != m_spells.end(); itr = next) - { - ++next; - if(itr->second->state == PLAYERSPELL_REMOVED) - continue; - - SkillLineAbilityMap::const_iterator lower = spellmgr.GetBeginSkillLineAbilityMap(itr->first); - SkillLineAbilityMap::const_iterator upper = spellmgr.GetEndSkillLineAbilityMap(itr->first); - - for(SkillLineAbilityMap::const_iterator _spell_idx = lower; _spell_idx != upper; ++_spell_idx) - { - if (_spell_idx->second->skillId == id) - { - // this may remove more than one spell (dependents) - removeSpell(itr->first); - next = m_spells.begin(); - break; - } - } - } + // remove all spells that related to this skill + for (uint32 j=0; j<sSkillLineAbilityStore.GetNumRows(); ++j) + if(SkillLineAbilityEntry const *pAbility = sSkillLineAbilityStore.LookupEntry(j)) + if (pAbility->skillId==id) + removeSpell(spellmgr.GetFirstSpellInChain(pAbility->spellId)); } } else if(currVal) //add @@ -5161,7 +5258,7 @@ void Player::SetSkill(uint32 id, uint16 currVal, uint16 maxVal) (*i)->ApplyModifier(true); // Learn all spells for skill - learnSkillRewardedSpells(id); + learnSkillRewardedSpells(id, currVal); return; } } @@ -9128,8 +9225,8 @@ uint8 Player::_CanStoreItem_InSpecificSlot( uint8 bag, uint8 slot, ItemPosCountV if(slot >= KEYRING_SLOT_START && slot < KEYRING_SLOT_START+GetMaxKeyringSize() && !(pProto->BagFamily & BAG_FAMILY_MASK_KEYS)) return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; - // vanitypet case (disabled until proper implement) - if(slot >= VANITYPET_SLOT_START && slot < VANITYPET_SLOT_END && !(false /*pProto->BagFamily & BAG_FAMILY_MASK_VANITY_PETS*/)) + // vanitypet case (not use, vanity pets stored as spells) + if(slot >= VANITYPET_SLOT_START && slot < VANITYPET_SLOT_END) return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; // currencytoken case (disabled until proper implement) @@ -9472,28 +9569,9 @@ uint8 Player::_CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, uint3 return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; } } - /* until proper implementation - else if(pProto->BagFamily & BAG_FAMILY_MASK_VANITY_PETS) - { - res = _CanStoreItem_InInventorySlots(VANITYPET_SLOT_START,VANITYPET_SLOT_END,dest,pProto,count,false,pItem,bag,slot); - if(res!=EQUIP_ERR_OK) - { - if(no_space_count) - *no_space_count = count + no_similar_count; - return res; - } - if(count==0) - { - if(no_similar_count==0) - return EQUIP_ERR_OK; + // Vanity pet case skipped as not used - if(no_space_count) - *no_space_count = count + no_similar_count; - return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; - } - } - */ /* until proper implementation else if(pProto->BagFamily & BAG_FAMILY_MASK_CURRENCY_TOKENS) { @@ -9685,28 +9763,9 @@ uint8 Player::_CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, uint3 return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; } } - /* until proper implementation - else if(false pProto->BagFamily & BAG_FAMILY_MASK_VANITY_PETS) - { - res = _CanStoreItem_InInventorySlots(VANITYPET_SLOT_START,VANITYPET_SLOT_END,dest,pProto,count,false,pItem,bag,slot); - if(res!=EQUIP_ERR_OK) - { - if(no_space_count) - *no_space_count = count + no_similar_count; - return res; - } - if(count==0) - { - if(no_similar_count==0) - return EQUIP_ERR_OK; + // Vanity pet case skipped as not used - if(no_space_count) - *no_space_count = count + no_similar_count; - return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; - } - } - */ /* until proper implementation else if(false pProto->BagFamily & BAG_FAMILY_MASK_CURRENCY_TOKENS) { @@ -9821,14 +9880,12 @@ uint8 Player::CanStoreItems( Item **pItems,int count) const int inv_slot_items[INVENTORY_SLOT_ITEM_END-INVENTORY_SLOT_ITEM_START]; int inv_bags[INVENTORY_SLOT_BAG_END-INVENTORY_SLOT_BAG_START][MAX_BAG_SIZE]; int inv_keys[KEYRING_SLOT_END-KEYRING_SLOT_START]; - int inv_pets[VANITYPET_SLOT_END-VANITYPET_SLOT_START]; int inv_tokens[CURRENCYTOKEN_SLOT_END-CURRENCYTOKEN_SLOT_START]; int inv_quests[QUESTBAG_SLOT_END-QUESTBAG_SLOT_START]; memset(inv_slot_items,0,sizeof(int)*(INVENTORY_SLOT_ITEM_END-INVENTORY_SLOT_ITEM_START)); memset(inv_bags,0,sizeof(int)*(INVENTORY_SLOT_BAG_END-INVENTORY_SLOT_BAG_START)*MAX_BAG_SIZE); memset(inv_keys,0,sizeof(int)*(KEYRING_SLOT_END-KEYRING_SLOT_START)); - memset(inv_pets,0,sizeof(int)*(VANITYPET_SLOT_END-VANITYPET_SLOT_START)); memset(inv_tokens,0,sizeof(int)*(CURRENCYTOKEN_SLOT_END-CURRENCYTOKEN_SLOT_START)); memset(inv_quests,0,sizeof(int)*(QUESTBAG_SLOT_END-QUESTBAG_SLOT_START)); @@ -9852,15 +9909,7 @@ uint8 Player::CanStoreItems( Item **pItems,int count) const } } - for(int i = VANITYPET_SLOT_START; i < VANITYPET_SLOT_END; i++) - { - pItem2 = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - - if (pItem2 && !pItem2->IsInTrade()) - { - inv_pets[i-VANITYPET_SLOT_START] = pItem2->GetCount(); - } - } + // Vanity pet case skipped as not used for(int i = CURRENCYTOKEN_SLOT_START; i < CURRENCYTOKEN_SLOT_END; i++) { @@ -9941,17 +9990,7 @@ uint8 Player::CanStoreItems( Item **pItems,int count) const } if (b_found) continue; - for(int t = VANITYPET_SLOT_START; t < VANITYPET_SLOT_END; t++) - { - pItem2 = GetItemByPos( INVENTORY_SLOT_BAG_0, t ); - if( pItem2 && pItem2->GetEntry() == pItem->GetEntry() && inv_pets[t-VANITYPET_SLOT_START] + pItem->GetCount() <= pProto->GetMaxStackSize()) - { - inv_pets[t-VANITYPET_SLOT_START] += pItem->GetCount(); - b_found = true; - break; - } - } - if (b_found) continue; + // Vanity pet case skipped as not used for(int t = CURRENCYTOKEN_SLOT_START; t < CURRENCYTOKEN_SLOT_END; t++) { @@ -10029,22 +10068,8 @@ uint8 Player::CanStoreItems( Item **pItems,int count) const if (b_found) continue; - /* until proper implementation - if(pProto->BagFamily & BAG_FAMILY_MASK_VANITY_PETS) - { - for(uint32 t = VANITYPET_SLOT_START; t < VANITYPET_SLOT_END; ++t) - { - if( inv_pets[t-VANITYPET_SLOT_START] == 0 ) - { - inv_pets[t-VANITYPET_SLOT_START] = 1; - b_found = true; - break; - } - } - } + // Vanity pet case skipped as not used - if (b_found) continue; - */ /* until proper implementation if(pProto->BagFamily & BAG_FAMILY_MASK_CURRENCY_TOKENS) { @@ -14687,24 +14712,7 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder ) SetUInt32Value(PLAYER_TRACK_CREATURES, 0 ); SetUInt32Value(PLAYER_TRACK_RESOURCES, 0 ); - // reset skill modifiers and set correct unlearn flags - for (uint32 i = 0; i < PLAYER_MAX_SKILLS; i++) - { - SetUInt32Value(PLAYER_SKILL_BONUS_INDEX(i),0); - - // set correct unlearn bit - uint32 id = GetUInt32Value(PLAYER_SKILL_INDEX(i)) & 0x0000FFFF; - if(!id) continue; - - SkillLineEntry const *pSkill = sSkillLineStore.LookupEntry(id); - if(!pSkill) continue; - - // enable unlearn button for primary professions only - if (pSkill->categoryId == SKILL_CATEGORY_PROFESSION) - SetUInt32Value(PLAYER_SKILL_INDEX(i), MAKE_PAIR32(id,1)); - else - SetUInt32Value(PLAYER_SKILL_INDEX(i), MAKE_PAIR32(id,0)); - } + _LoadSkills(); // make sure the unit is considered out of combat for proper loading ClearInCombat(); @@ -14745,7 +14753,6 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder ) // after spell and quest load InitTalentForLevel(); - learnSkillRewardedSpells(); learnDefaultSpells(); _LoadTutorials(holder->GetResult(PLAYER_LOGIN_QUERY_LOADTUTORIALS)); @@ -14849,6 +14856,28 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder ) break; } + switch(sWorld.getConfig(CONFIG_GM_VISIBLE_STATE)) + { + default: + case 0: SetGMVisible(false); break; // invisible + case 1: break; // visible + case 2: // save state + if(extraflags & PLAYER_EXTRA_GM_INVISIBLE) + SetGMVisible(false); + break; + } + + /*switch(sWorld.getConfig(CONFIG_GM_ACCEPT_TICKETS)) + { + default: + case 0: break; // disable + case 1: SetAcceptTicket(true); break; // enable + case 2: // save state + if(extraflags & PLAYER_EXTRA_GM_ACCEPT_TICKETS) + SetAcceptTicket(true); + break; + }*/ + switch(sWorld.getConfig(CONFIG_GM_CHAT)) { default: @@ -15540,7 +15569,7 @@ void Player::_LoadSpells(QueryResult *result) { Field *fields = result->Fetch(); - addSpell(fields[0].GetUInt16(), fields[1].GetBool(), false, fields[2].GetBool()); + addSpell(fields[0].GetUInt16(), fields[1].GetBool(), false, false, fields[2].GetBool()); } while( result->NextRow() ); @@ -16318,18 +16347,26 @@ void Player::_SaveReputation() void Player::_SaveSpells() { - for (PlayerSpellMap::const_iterator itr = m_spells.begin(), next = m_spells.begin(); itr != m_spells.end(); itr = next) + for (PlayerSpellMap::iterator itr = m_spells.begin(), next = m_spells.begin(); itr != m_spells.end();) { - ++next; if (itr->second->state == PLAYERSPELL_REMOVED || itr->second->state == PLAYERSPELL_CHANGED) CharacterDatabase.PExecute("DELETE FROM character_spell WHERE guid = '%u' and spell = '%u'", GetGUIDLow(), itr->first); - if (itr->second->state == PLAYERSPELL_NEW || itr->second->state == PLAYERSPELL_CHANGED) + + // add only changed/new not dependent spells + if (!itr->second->dependent && (itr->second->state == PLAYERSPELL_NEW || itr->second->state == PLAYERSPELL_CHANGED)) CharacterDatabase.PExecute("INSERT INTO character_spell (guid,spell,active,disabled) VALUES ('%u', '%u', '%u', '%u')", GetGUIDLow(), itr->first, itr->second->active ? 1 : 0,itr->second->disabled ? 1 : 0); if (itr->second->state == PLAYERSPELL_REMOVED) - _removeSpell(itr->first); + { + delete itr->second; + m_spells.erase(itr++); + } else + { itr->second->state = PLAYERSPELL_UNCHANGED; + ++itr; + } + } } @@ -18678,9 +18715,9 @@ void Player::learnDefaultSpells() uint32 tspell = *itr; sLog.outDebug("PLAYER (Class: %u Race: %u): Adding initial spell, id = %u",uint32(getClass()),uint32(getRace()), tspell); if(!IsInWorld()) // will send in INITIAL_SPELLS in list anyway at map add - addSpell(tspell,true,true,false); + addSpell(tspell,true,true,true,false); else // but send in normal spell in game learn case - learnSpell(tspell); + learnSpell(tspell,true); } } @@ -18772,7 +18809,7 @@ void Player::learnQuestRewardedSpells() } } -void Player::learnSkillRewardedSpells(uint32 skill_id ) +void Player::learnSkillRewardedSpells(uint32 skill_id, uint32 skill_value ) { uint32 raceMask = getRaceMask(); uint32 classMask = getClassMask(); @@ -18790,25 +18827,18 @@ void Player::learnSkillRewardedSpells(uint32 skill_id ) if (sSpellStore.LookupEntry(pAbility->spellId)) { - // Ok need learn spell - learnSpell(pAbility->spellId); + // need unlearn spell + if (skill_value < pAbility->req_skill_value) + removeSpell(pAbility->spellId); + // need learn + else if (!IsInWorld()) + addSpell(pAbility->spellId,true,true,true,false); + else + learnSpell(pAbility->spellId,true); } } } -void Player::learnSkillRewardedSpells() -{ - for (uint16 i=0; i < PLAYER_MAX_SKILLS; i++) - { - if(!GetUInt32Value(PLAYER_SKILL_INDEX(i))) - continue; - - uint32 pskill = GetUInt32Value(PLAYER_SKILL_INDEX(i)) & 0x0000FFFF; - - learnSkillRewardedSpells(pskill); - } -} - void Player::SendAurasForTarget(Unit *target) { if(target->GetVisibleAuras()->empty()) // speedup things @@ -19486,6 +19516,13 @@ void Player::UpdateAreaDependentAuras( uint32 newArea ) if( !HasAura(51721,0) ) CastSpell(this,51721,true); break; + // Mist of the Kvaldir + case 4028: //Riplash Strand + case 4029: //Riplash Ruins + case 4106: //Garrosh's Landing + case 4031: //Pal'ea + CastSpell(this,54119,true); + break; } } @@ -20178,3 +20215,67 @@ bool Player::IsAllowUseFlyMountsHere() const } return true; } + +void Player::learnSpellHighRank(uint32 spellid) +{ + learnSpell(spellid,false); + + if(uint32 next = spellmgr.GetNextSpellInChain(spellid)) + learnSpellHighRank(next); +} + +void Player::_LoadSkills() +{ + // Note: skill data itself loaded from `data` field. This is only cleanup part of load + + // reset skill modifiers and set correct unlearn flags + for (uint32 i = 0; i < PLAYER_MAX_SKILLS; i++) + { + SetUInt32Value(PLAYER_SKILL_BONUS_INDEX(i),0); + + // set correct unlearn bit + uint32 id = GetUInt32Value(PLAYER_SKILL_INDEX(i)) & 0x0000FFFF; + if(!id) continue; + + SkillLineEntry const *pSkill = sSkillLineStore.LookupEntry(id); + if(!pSkill) continue; + + // enable unlearn button for primary professions only + if (pSkill->categoryId == SKILL_CATEGORY_PROFESSION) + SetUInt32Value(PLAYER_SKILL_INDEX(i), MAKE_PAIR32(id,1)); + else + SetUInt32Value(PLAYER_SKILL_INDEX(i), MAKE_PAIR32(id,0)); + + uint32 vskill = SKILL_VALUE(GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i))); + + learnSkillRewardedSpells(id, vskill); + } + + // special settings + if(getClass()==CLASS_DEATH_KNIGHT) + { + uint32 base_level = std::min(getLevel(),sWorld.getConfig (CONFIG_START_HEROIC_PLAYER_LEVEL)); + if(base_level < 1) + base_level = 1; + uint32 base_skill = (base_level-1)*5; // 270 at starting level 55 + if(base_skill < 1) + base_skill = 1; // skill mast be known and then > 0 in any case + + if(GetPureSkillValue (SKILL_FIRST_AID) < base_skill) + SetSkill(SKILL_FIRST_AID,base_skill, base_skill); + if(GetPureSkillValue (SKILL_AXES) < base_skill) + SetSkill(SKILL_AXES, base_skill,base_skill); + if(GetPureSkillValue (SKILL_DEFENSE) < base_skill) + SetSkill(SKILL_DEFENSE, base_skill,base_skill); + if(GetPureSkillValue (SKILL_POLEARMS) < base_skill) + SetSkill(SKILL_POLEARMS, base_skill,base_skill); + if(GetPureSkillValue (SKILL_SWORDS) < base_skill) + SetSkill(SKILL_SWORDS, base_skill,base_skill); + if(GetPureSkillValue (SKILL_2H_AXES) < base_skill) + SetSkill(SKILL_2H_AXES, base_skill,base_skill); + if(GetPureSkillValue (SKILL_2H_SWORDS) < base_skill) + SetSkill(SKILL_2H_SWORDS, base_skill,base_skill); + if(GetPureSkillValue (SKILL_UNARMED) < base_skill) + SetSkill(SKILL_UNARMED, base_skill,base_skill); + } +} diff --git a/src/game/Player.h b/src/game/Player.h index 19dd5a4e06d..c6b99cefe70 100644 --- a/src/game/Player.h +++ b/src/game/Player.h @@ -88,8 +88,9 @@ enum PlayerSpellState struct PlayerSpell { PlayerSpellState state : 8; - bool active : 1; - bool disabled : 1; + bool active : 1; // show in spellbook + bool dependent : 1; // learned as result another spell learn, skill grow, quest reward, etc + bool disabled : 1; // first rank has been learned in result talent learn but currently talent unlearned, save max learned ranks }; // Spell modifier (used for modify other spells) @@ -106,7 +107,7 @@ struct SpellModifier Spell const* lastAffected; }; -typedef UNORDERED_MAP<uint16, PlayerSpell*> PlayerSpellMap; +typedef UNORDERED_MAP<uint32, PlayerSpell*> PlayerSpellMap; typedef std::list<SpellModifier*> SpellModList; struct SpellCooldown @@ -731,8 +732,8 @@ enum KeyRingSlots enum VanityPetSlots { - VANITYPET_SLOT_START = 118, - VANITYPET_SLOT_END = 136 + VANITYPET_SLOT_START = 118, // not use, vanity pets stored as spells + VANITYPET_SLOT_END = 136 // not alloed any content in. }; enum CurrencyTokenSlots @@ -1342,6 +1343,7 @@ class TRINITY_DLL_SPEC Player : public Unit /*********************************************************/ bool LoadFromDB(uint32 guid, SqlQueryHolder *holder); + bool MinimalLoadFromDB(QueryResult *result, uint32 guid); static bool LoadValuesArrayFromDB(Tokens& data,uint64 guid); static uint32 GetUInt32ValueFromArray(Tokens const& data, uint16 index); @@ -1475,18 +1477,21 @@ class TRINITY_DLL_SPEC Player : public Unit void CharmSpellInitialize(); void PossessSpellInitialize(); bool HasSpell(uint32 spell) const; + bool HasActiveSpell(uint32 spell) const; // show in spellbook TrainerSpellState GetTrainerSpellState(TrainerSpell const* trainer_spell) const; bool IsSpellFitByClassAndRace( uint32 spell_id ) const; + bool IsNeedCastPassiveSpellAtLearn(SpellEntry const* spellInfo) const; void SendProficiency(uint8 pr1, uint32 pr2); void SendInitialSpells(); - bool addSpell(uint32 spell_id, bool active, bool learning, bool disabled); - void learnSpell(uint32 spell_id); - void removeSpell(uint32 spell_id, bool disabled = false); + bool addSpell(uint32 spell_id, bool active, bool learning, bool dependent, bool disabled); + void learnSpell(uint32 spell_id, bool dependent); + void removeSpell(uint32 spell_id, bool disabled = false, bool update_action_bar_for_low_rank = false); void resetSpells(); void learnDefaultSpells(); void learnQuestRewardedSpells(); void learnQuestRewardedSpells(Quest const* quest); + void learnSpellHighRank(uint32 spellid); uint32 GetFreeTalentPoints() const { return GetUInt32Value(PLAYER_CHARACTER_POINTS1); } void SetFreeTalentPoints(uint32 points) { SetUInt32Value(PLAYER_CHARACTER_POINTS1,points); } @@ -1767,8 +1772,7 @@ class TRINITY_DLL_SPEC Player : public Unit int16 GetSkillPermBonusValue(uint32 skill) const; int16 GetSkillTempBonusValue(uint32 skill) const; bool HasSkill(uint32 skill) const; - void learnSkillRewardedSpells( uint32 id ); - void learnSkillRewardedSpells(); + void learnSkillRewardedSpells(uint32 id, uint32 value); void SetDontMove(bool dontMove); bool GetDontMove() const { return m_dontMove; } @@ -2270,6 +2274,7 @@ class TRINITY_DLL_SPEC Player : public Unit void _LoadDailyQuestStatus(QueryResult *result); void _LoadGroup(QueryResult *result); void _LoadReputation(QueryResult *result); + void _LoadSkills(); void _LoadSpells(QueryResult *result); void _LoadTutorials(QueryResult *result); void _LoadFriendList(QueryResult *result); @@ -2311,7 +2316,6 @@ class TRINITY_DLL_SPEC Player : public Unit time_t m_lastHonorUpdateTime; void outDebugValues() const; - bool _removeSpell(uint16 spell_id); uint64 m_lootGuid; uint32 m_race; diff --git a/src/game/SharedDefines.h b/src/game/SharedDefines.h index d5102857ca2..02c7fb6adc8 100644 --- a/src/game/SharedDefines.h +++ b/src/game/SharedDefines.h @@ -832,7 +832,6 @@ enum Targets TARGET_UNIT_PARTY_CASTER = 20, TARGET_SINGLE_FRIEND = 21, TARGET_UNIT_TARGET_ALLY = 21, - TARGET_ALL_AROUND_CASTER = 22, // used only in TargetA, target selection dependent from TargetB TARGET_DEST_CASTER = 22, TARGET_GAMEOBJECT = 23, //TARGET_OBJECT_OPEN diff --git a/src/game/SkillHandler.cpp b/src/game/SkillHandler.cpp index 9f3915c30cb..e909842dc86 100644 --- a/src/game/SkillHandler.cpp +++ b/src/game/SkillHandler.cpp @@ -129,7 +129,7 @@ void WorldSession::HandleLearnTalentOpcode( WorldPacket & recv_data ) return; // learn! (other talent ranks will unlearned at learning) - GetPlayer( )->learnSpell(spellid); + GetPlayer( )->learnSpell(spellid,false); sLog.outDetail("TalentID: %u Rank: %u Spell: %u\n", talent_id, requested_rank, spellid); // update free talent points diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp index d0e1e3f9db3..f2f03249e22 100644 --- a/src/game/Spell.cpp +++ b/src/game/Spell.cpp @@ -119,6 +119,14 @@ void SpellCastTargets::setDestination(Unit *target, bool send) m_targetMask |= TARGET_FLAG_DEST_LOCATION; } +void SpellCastTargets::setSource(float x, float y, float z) +{ + m_srcX = x; + m_srcY = y; + m_srcZ = z; + m_targetMask |= TARGET_FLAG_SOURCE_LOCATION; +} + void SpellCastTargets::setGOTarget(GameObject *target) { m_GOTarget = target; @@ -354,6 +362,7 @@ Spell::Spell( Unit* Caster, SpellEntry const *info, bool triggered, uint64 origi focusObject = NULL; m_cast_count = 0; m_glyphIndex = 0; + m_preCastSpell = 0; m_triggeredByAuraSpell = NULL; //Auto Shot & Shoot (wand) @@ -597,7 +606,6 @@ void Spell::FillTargetMap() } } - if(IsChanneledSpell(m_spellInfo) && !tmpUnitMap.empty()) m_needAliveTargetMask |= (1<<i); @@ -701,7 +709,7 @@ void Spell::prepareDataForTriggerSystem() } // Hunter traps spells (for Entrapment trigger) // Gives your Immolation Trap, Frost Trap, Explosive Trap, and Snake Trap .... - if (m_spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && m_spellInfo->SpellFamilyFlags & 0x0000200000000014LL) + if (m_spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && m_spellInfo->SpellFamilyFlags & 0x000020000000001CLL) m_procAttacker |= PROC_FLAG_ON_TRAP_ACTIVATION; } @@ -877,7 +885,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo *target) return; // Get original caster (if exist) and calculate damage/healing from him data - Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster; + Unit *caster = m_originalCaster ? m_originalCaster : m_caster; // Skip if m_originalCaster not avaiable if (!caster) @@ -970,25 +978,6 @@ void Spell::DoAllEffectOnTarget(TargetInfo *target) int32 damagePoint = damageInfo.damage * 33 / 100; m_caster->CastCustomSpell(m_caster, 32220, &damagePoint, NULL, NULL, true); } - // Bloodthirst - else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_WARRIOR && m_spellInfo->SpellFamilyFlags & 0x40000000000LL) - { - uint32 BTAura = 0; - switch(m_spellInfo->Id) - { - case 23881: BTAura = 23885; break; - case 23892: BTAura = 23886; break; - case 23893: BTAura = 23887; break; - case 23894: BTAura = 23888; break; - case 25251: BTAura = 25252; break; - case 30335: BTAura = 30339; break; - default: - sLog.outError("Spell::EffectSchoolDMG: Spell %u not handled in BTAura",m_spellInfo->Id); - break; - } - if (BTAura) - m_caster->CastSpell(m_caster,BTAura,true); - } } // Passive spell hits/misses or active spells only misses (only triggers) else @@ -1105,6 +1094,10 @@ void Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask) unit->IncrDiminishing(m_diminishGroup); } + // Apply additional spell effects to target + if (m_preCastSpell) + m_caster->CastSpell(unit,m_preCastSpell, true, m_CastItem); + for(uint32 effectNumber=0;effectNumber<3;effectNumber++) { if (effectMask & (1<<effectNumber)) @@ -1604,7 +1597,6 @@ void Spell::SetTargetMap(uint32 i,uint32 cur,std::list<Unit*> &TagUnitMap) m_targets.setDestination(((Player*)m_caster)->m_homebindX,((Player*)m_caster)->m_homebindY,((Player*)m_caster)->m_homebindZ, true, ((Player*)m_caster)->m_homebindMapId); break; - case TARGET_IN_FRONT_OF_CASTER: case TARGET_UNIT_CONE_ENEMY_UNKNOWN: if(m_customAttr & SPELL_ATTR_CU_CONE_BACK) @@ -2162,6 +2154,49 @@ void Spell::cast(bool skipCheck) if(m_customAttr & SPELL_ATTR_CU_DIRECT_DAMAGE) CalculateDamageDoneForAllTargets(); + switch(m_spellInfo->SpellFamilyName) + { + case SPELLFAMILY_GENERIC: + { + if (m_spellInfo->Mechanic == MECHANIC_BANDAGE) // Bandages + m_preCastSpell = 11196; // Recently Bandaged + else if(m_spellInfo->SpellIconID == 1662 && m_spellInfo->AttributesEx & 0x20) // Blood Fury (Racial) + m_preCastSpell = 23230; // Blood Fury - Healing Reduction + break; + } + case SPELLFAMILY_MAGE: + { + if (m_spellInfo->SpellFamilyFlags&0x0000008000000000LL) // Ice Block + m_preCastSpell = 41425; // Hypothermia + break; + } + case SPELLFAMILY_PRIEST: + { + if (m_spellInfo->Mechanic == MECHANIC_SHIELD && + m_spellInfo->SpellIconID == 566) // Power Word: Shield + m_preCastSpell = 6788; // Weakened Soul + if (m_spellInfo->Id == 47585) // Dispersion (transform) + m_preCastSpell = 60069; // Dispersion (mana regen) + break; + } + case SPELLFAMILY_PALADIN: + { + if (m_spellInfo->SpellFamilyFlags&0x0000000000400080LL) // Divine Shield, Divine Protection or Hand of Protection + m_preCastSpell = 25771; // Forbearance + break; + } + case SPELLFAMILY_SHAMAN: + { + if (m_spellInfo->Id == 2825) // Bloodlust + m_preCastSpell = 57724; // Sated + else if (m_spellInfo->Id == 32182) // Heroism + m_preCastSpell = 57723; // Exhaustion + break; + } + default: + break; + } + // traded items have trade slot instead of guid in m_itemTargetGUID // set to real guid to be sent later to the client m_targets.updateTradeSlotItem(); @@ -2644,68 +2679,6 @@ void Spell::finish(bool ok) m_caster->resetAttackTimer(RANGED_ATTACK); } - // Post effects apply on spell targets in some spells - if(!m_UniqueTargetInfo.empty()) - { - uint32 spellId = 0; - switch(m_spellInfo->SpellFamilyName) - { - case SPELLFAMILY_GENERIC: - { - if (m_spellInfo->Mechanic == MECHANIC_BANDAGE) // Bandages - spellId = 11196; // Recently Bandaged - else if(m_spellInfo->SpellIconID == 1662 && m_spellInfo->AttributesEx & 0x20) // Blood Fury (Racial) - spellId = 23230; // Blood Fury - Healing Reduction - break; - } - case SPELLFAMILY_MAGE: - { - if (m_spellInfo->SpellFamilyFlags&0x0000008000000000LL) // Ice Block - spellId = 41425; // Hypothermia - break; - } - case SPELLFAMILY_PRIEST: - { - if (m_spellInfo->Mechanic == MECHANIC_SHIELD && - m_spellInfo->SpellIconID == 566) // Power Word: Shield - spellId = 6788; // Weakened Soul - break; - } - case SPELLFAMILY_PALADIN: - { - if (m_spellInfo->SpellFamilyFlags&0x0000000000400080LL) // Divine Shield, Divine Protection or Hand of Protection - spellId = 25771; // Forbearance - break; - } - case SPELLFAMILY_SHAMAN: - { - if (m_spellInfo->Id == 2825) // Bloodlust - spellId = 57724; // Sated - else if (m_spellInfo->Id == 32182) // Heroism - spellId = 57723; // Exhaustion - break; - } - default: - break; - } - if (spellId) - { - for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit) - { - Unit* unit = m_caster->GetGUID()==ihit->targetGUID ? m_caster : ObjectAccessor::GetUnit(*m_caster, ihit->targetGUID); - if (unit) - { -// TODO: fix me use cast spell (now post spell can immune by this spell) -// m_caster->CastSpell(unit, spellId, true, m_CastItem); - SpellEntry const *AdditionalSpellInfo = sSpellStore.LookupEntry(spellId); - if (!AdditionalSpellInfo) - continue; - Aura* AdditionalAura = CreateAura(AdditionalSpellInfo, 0, &m_currentBasePoints[0], unit, m_caster, m_CastItem); - unit->AddAura(AdditionalAura); - } - } - } - } // call triggered spell only at successful cast (after clear combo points -> for add some if need) if(!m_TriggerSpells.empty()) TriggerSpell(); @@ -2852,6 +2825,7 @@ void Spell::SendSpellGo() } WorldPacket data(SMSG_SPELL_GO, 50); // guess size + if(m_CastItem) data.append(m_CastItem->GetPackGUID()); else @@ -2949,6 +2923,8 @@ void Spell::WriteAmmoToPacket( WorldPacket * data ) void Spell::WriteSpellGoTargets( WorldPacket * data ) { + // This function also fill data for channeled spells: + // m_needAliveTargetMask req for stop channelig if one target die uint32 hit = m_UniqueGOTargetInfo.size(); // Always hits on GO uint32 miss = 0; for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit) @@ -2968,7 +2944,10 @@ void Spell::WriteSpellGoTargets( WorldPacket * data ) *data << (uint8)hit; for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit) if ((*ihit).missCondition == SPELL_MISS_NONE) // Add only hits + { *data << uint64(ihit->targetGUID); + m_needAliveTargetMask |=ihit->effectMask; + } for(std::list<GOTargetInfo>::iterator ighit= m_UniqueGOTargetInfo.begin();ighit != m_UniqueGOTargetInfo.end();++ighit) *data << uint64(ighit->targetGUID); // Always hits @@ -2984,6 +2963,9 @@ void Spell::WriteSpellGoTargets( WorldPacket * data ) *data << uint8(ihit->reflectResult); } } + // Reset m_needAliveTargetMask for non channeled spell + if(!IsChanneledSpell(m_spellInfo)) + m_needAliveTargetMask = 0; } void Spell::SendLogExecute() @@ -5189,18 +5171,22 @@ void Spell::Delayed() // only called in DealDamage() //if (m_spellState == SPELL_STATE_DELAYED) // return; // spell is active and can't be time-backed + if(isDelayableNoMore()) // Spells may only be delayed twice + return; + // spells not loosing casting time ( slam, dynamites, bombs.. ) //if(!(m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_DAMAGE)) // return; - //check resist chance - int32 resistChance = 100; //must be initialized to 100 for percent modifiers - ((Player*)m_caster)->ApplySpellMod(m_spellInfo->Id,SPELLMOD_NOT_LOSE_CASTING_TIME,resistChance, this); - resistChance += m_caster->GetTotalAuraModifier(SPELL_AURA_RESIST_PUSHBACK) - 100; - if (roll_chance_i(resistChance)) + //check pushback reduce + int32 delaytime = 500; // spellcasting delay is normally 500ms + int32 delayReduce = 100; // must be initialized to 100 for percent modifiers + ((Player*)m_caster)->ApplySpellMod(m_spellInfo->Id,SPELLMOD_NOT_LOSE_CASTING_TIME, delayReduce, this); + delayReduce += m_caster->GetTotalAuraModifier(SPELL_AURA_REDUCE_PUSHBACK) - 100; + if(delayReduce >= 100) return; - int32 delaytime = GetNextDelayAtDamageMsTime(); + delaytime = delaytime * (100 - delayReduce) / 100; if(int32(m_timer) + delaytime > m_casttime) { @@ -5224,14 +5210,18 @@ void Spell::DelayedChannel() if(!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER || getState() != SPELL_STATE_CASTING) return; - //check resist chance - int32 resistChance = 100; //must be initialized to 100 for percent modifiers - ((Player*)m_caster)->ApplySpellMod(m_spellInfo->Id,SPELLMOD_NOT_LOSE_CASTING_TIME,resistChance, this); - resistChance += m_caster->GetTotalAuraModifier(SPELL_AURA_RESIST_PUSHBACK) - 100; - if (roll_chance_i(resistChance)) + if(isDelayableNoMore()) // Spells may only be delayed twice + return; + + //check pushback reduce + int32 delaytime = GetSpellDuration(m_spellInfo) * 25 / 100; // channeling delay is normally 25% of its time per hit + int32 delayReduce = 100; // must be initialized to 100 for percent modifiers + ((Player*)m_caster)->ApplySpellMod(m_spellInfo->Id,SPELLMOD_NOT_LOSE_CASTING_TIME,delayReduce, this); + delayReduce += m_caster->GetTotalAuraModifier(SPELL_AURA_REDUCE_PUSHBACK) - 100; + if(delayReduce >= 100) return; - int32 delaytime = GetNextDelayAtDamageMsTime(); + delaytime = delaytime * (100 - delayReduce) / 100; if(int32(m_timer) < delaytime) { @@ -5404,7 +5394,13 @@ bool Spell::CheckTarget( Unit* target, uint32 eff, bool hitPhase ) // all ok by some way or another, skip normal check break; default: // normal case - if(target!=m_caster && !target->IsWithinLOSInMap(m_caster)) + // Get GO cast coordinates if original caster -> GO + WorldObject *caster = NULL; + if (m_originalCasterGUID) + caster = ObjectAccessor::GetGameObject(*m_caster, m_originalCasterGUID); + if (!caster) + caster = m_caster; + if(target!=m_caster && !target->IsWithinLOSInMap(caster)) return false; break; } diff --git a/src/game/Spell.h b/src/game/Spell.h index afef4262058..f87cb9fc139 100644 --- a/src/game/Spell.h +++ b/src/game/Spell.h @@ -161,6 +161,7 @@ class SpellCastTargets void setUnitTarget(Unit *target); void setDestination(float x, float y, float z, bool send = true, int32 mapId = -1); void setDestination(Unit *target, bool send = true); + void setSource(float x, float y, float z); uint64 getGOTargetGUID() const { return m_GOTargetGUID; } GameObject *getGOTarget() const { return m_GOTarget; } @@ -419,6 +420,7 @@ class Spell uint64 m_castItemGUID; uint8 m_cast_count; uint32 m_glyphIndex; + uint32 m_preCastSpell; SpellCastTargets m_targets; int32 GetCastTime() const { return m_casttime; } @@ -485,7 +487,14 @@ class Spell uint8 m_runesState; uint8 m_delayAtDamageCount; - int32 GetNextDelayAtDamageMsTime() { return m_delayAtDamageCount < 5 ? 1000 - (m_delayAtDamageCount++)* 200 : 200; } + bool isDelayableNoMore() + { + if(m_delayAtDamageCount >= 2) + return true; + + m_delayAtDamageCount++; + return false; + } // Delayed spells system uint64 m_delayStart; // time of spell delay start, filled by event handler, zero = just started diff --git a/src/game/SpellAuraDefines.h b/src/game/SpellAuraDefines.h index eb802d1c934..a958722b0f9 100644 --- a/src/game/SpellAuraDefines.h +++ b/src/game/SpellAuraDefines.h @@ -193,7 +193,7 @@ enum AuraType SPELL_AURA_ALLOW_TAME_PET_TYPE = 146, SPELL_AURA_ADD_CREATURE_IMMUNITY = 147, SPELL_AURA_RETAIN_COMBO_POINTS = 148, - SPELL_AURA_RESIST_PUSHBACK = 149, // Resist Pushback + SPELL_AURA_REDUCE_PUSHBACK = 149, // Reduce Pushback SPELL_AURA_MOD_SHIELD_BLOCKVALUE_PCT = 150, SPELL_AURA_TRACK_STEALTHED = 151, // Track Stealthed SPELL_AURA_MOD_DETECTED_RANGE = 152, // Mod Detected Range @@ -304,7 +304,7 @@ enum AuraType SPELL_AURA_MOD_TARGET_RESIST_BY_SPELL_CLASS = 257, SPELL_AURA_258 = 258, SPELL_AURA_259 = 259, - SPELL_AURA_260 = 260, + SPELL_AURA_SCREEN_EFFECT = 260, SPELL_AURA_261 = 261, SPELL_AURA_262 = 262, SPELL_AURA_ALLOW_ONLY_ABILITY = 263, diff --git a/src/game/SpellAuras.cpp b/src/game/SpellAuras.cpp index 661fac9befe..3cf59160187 100644 --- a/src/game/SpellAuras.cpp +++ b/src/game/SpellAuras.cpp @@ -203,7 +203,7 @@ pAuraHandler AuraHandler[TOTAL_AURAS]= &Aura::HandleNoImmediateEffect, //146 SPELL_AURA_ALLOW_TAME_PET_TYPE &Aura::HandleNULL, //147 SPELL_AURA_ADD_CREATURE_IMMUNITY &Aura::HandleAuraRetainComboPoints, //148 SPELL_AURA_RETAIN_COMBO_POINTS - &Aura::HandleNoImmediateEffect, //149 SPELL_AURA_RESIST_PUSHBACK + &Aura::HandleNoImmediateEffect, //149 SPELL_AURA_REDUCE_PUSHBACK &Aura::HandleShieldBlockValue, //150 SPELL_AURA_MOD_SHIELD_BLOCKVALUE_PCT &Aura::HandleAuraTrackStealthed, //151 SPELL_AURA_TRACK_STEALTHED &Aura::HandleNoImmediateEffect, //152 SPELL_AURA_MOD_DETECTED_RANGE implemented in Creature::GetAttackDistance @@ -314,7 +314,7 @@ pAuraHandler AuraHandler[TOTAL_AURAS]= &Aura::HandleNULL, //257 SPELL_AURA_MOD_TARGET_RESIST_BY_SPELL_CLASS Use SpellClassMask for spell select &Aura::HandleNULL, //258 SPELL_AURA_MOD_SPELL_VISUAL &Aura::HandleNULL, //259 corrupt healing over time spell - &Aura::HandleNULL, //260 + &Aura::HandleNoImmediateEffect, //260 SPELL_AURA_SCREEN_EFFECT (miscvalue = id in ScreenEffect.dbc) not required any code &Aura::HandleNULL, //261 out of phase? &Aura::HandleNULL, //262 &Aura::HandleNULL, //263 SPELL_AURA_ALLOW_ONLY_ABILITY player can use only abilites set in SpellClassMask @@ -2141,6 +2141,28 @@ void Aura::HandleAuraDummy(bool apply, bool Real) { break; } + case SPELLFAMILY_PRIEST: + { + // Pain and Suffering + if( m_spellProto->SpellIconID == 2874 && m_target->GetTypeId()==TYPEID_PLAYER ) + { + if(apply) + { + // Reduce backfire damage (dot damage) from Shadow Word: Death + SpellModifier *mod = new SpellModifier; + mod->op = SPELLMOD_DOT; + mod->value = m_modifier.m_amount; + mod->type = SPELLMOD_PCT; + mod->spellId = GetId(); + mod->mask = 0x0000000200000000LL; + mod->mask2= 0LL; + m_spellmod = mod; + } + ((Player*)m_target)->AddSpellMod(m_spellmod, apply); + return; + } + break; + } case SPELLFAMILY_DRUID: { // Lifebloom @@ -5039,6 +5061,7 @@ void Aura::HandleShapeshiftBoosts(bool apply) break; case FORM_TREE: spellId = 5420; + spellId2 = 34123; break; case FORM_TRAVEL: spellId = 5419; @@ -6073,47 +6096,11 @@ void Aura::PeriodicDummyTick() { if ((*i)->GetId() == GetId()) { - // Get tick number - int32 tick = (m_maxduration - m_duration) / m_modifier.periodictime; - // Default case (not on arenas) - if (tick == 0) - { - (*i)->GetModifier()->m_amount = m_modifier.m_amount; - ((Player*)m_target)->UpdateManaRegen(); - // Disable continue - m_isPeriodic = false; - } - return; - //********************************************** - // Code commended since arena patch not added - // This feature uses only in arenas - //********************************************** - // Here need increase mana regen per tick (6 second rule) - // on 0 tick - 0 (handled in 2 second) - // on 1 tick - 166% (handled in 4 second) - // on 2 tick - 133% (handled in 6 second) - // Not need update after 3 tick - /* - if (tick > 3) - return; - // Apply bonus for 0 - 3 tick - switch (tick) - { - case 0: // 0% - (*i)->GetModifier()->m_amount = m_modifier.m_amount = 0; - break; - case 1: // 166% - (*i)->GetModifier()->m_amount = m_modifier.m_amount * 5 / 3; - break; - case 2: // 133% - (*i)->GetModifier()->m_amount = m_modifier.m_amount * 4 / 3; - break; - default: // 100% - normal regen - (*i)->GetModifier()->m_amount = m_modifier.m_amount; - break; - } + (*i)->GetModifier()->m_amount = m_modifier.m_amount; ((Player*)m_target)->UpdateManaRegen(); - return;*/ + // Disable continue + m_isPeriodic = false; + return; } } return; diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp index 78df7d77bd6..1cc4911a05a 100644 --- a/src/game/SpellEffects.cpp +++ b/src/game/SpellEffects.cpp @@ -1377,6 +1377,12 @@ void Spell::EffectDummy(uint32 i) m_caster->CastCustomSpell(m_caster, 12976, &healthModSpellBasePoints0, NULL, NULL, true, NULL); return; } + // Bloodthirst + case 23881: + { + m_caster->CastCustomSpell(unitTarget, 23885, &damage, NULL, NULL, true, NULL); + return; + } } break; case SPELLFAMILY_WARLOCK: @@ -1487,16 +1493,6 @@ void Spell::EffectDummy(uint32 i) } break; case SPELLFAMILY_DRUID: - switch(m_spellInfo->Id ) - { - case 5420: // Tree of Life passive - { - // Tree of Life area effect - int32 health_mod = int32(m_caster->GetStat(STAT_SPIRIT)/4); - m_caster->CastCustomSpell(m_caster,34123,&health_mod,NULL,NULL,true,NULL); - return; - } - } break; case SPELLFAMILY_ROGUE: switch(m_spellInfo->Id ) @@ -2228,7 +2224,7 @@ void Spell::EffectApplyAura(uint32 i) (unitTarget->GetTypeId()!=TYPEID_PLAYER || !((Player*)unitTarget)->GetSession()->PlayerLoading()) ) return; - Unit* caster = m_originalCasterGUID ? m_originalCaster : m_caster; + Unit* caster = m_originalCaster ? m_originalCaster : m_caster; if(!caster) return; @@ -3380,7 +3376,7 @@ void Spell::EffectLearnSpell(uint32 i) Player *player = (Player*)unitTarget; uint32 spellToLearn = ((m_spellInfo->Id==SPELL_ID_GENERIC_LEARN) || (m_spellInfo->Id==SPELL_ID_GENERIC_LEARN_PET)) ? damage : m_spellInfo->EffectTriggerSpell[i]; - player->learnSpell(spellToLearn); + player->learnSpell(spellToLearn,false); sLog.outDebug( "Spell: Player %u have learned spell %u from NpcGUID=%u", player->GetGUIDLow(), spellToLearn, m_caster->GetGUIDLow() ); } @@ -5045,7 +5041,7 @@ void Spell::EffectScriptEffect(uint32 effIndex) // learn random explicit discovery recipe (if any) if(uint32 discoveredSpell = GetExplicitDiscoverySpell(m_spellInfo->Id, player)) - player->learnSpell(discoveredSpell); + player->learnSpell(discoveredSpell,false); return; } } @@ -5120,6 +5116,34 @@ void Spell::EffectScriptEffect(uint32 effIndex) } break; } + case SPELLFAMILY_PRIEST: + { + switch(m_spellInfo->Id) + { + // Pain and Suffering + case 47948: + { + if (!unitTarget) + return; + // Refresh Shadow Word: Pain on target + Unit::AuraList const &mPeriodic = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE); + for(Unit::AuraList::const_iterator i = mPeriodic.begin(); i != mPeriodic.end(); ++i) + { + if( (*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_PRIEST && + (*i)->GetSpellProto()->SpellFamilyFlags & 0x0000000000008000LL && + (*i)->GetCasterGUID()==m_caster->GetGUID() ) + { + (*i)->RefreshAura(); + return; + } + } + return; + } + default: + break; + } + break; + } case SPELLFAMILY_HUNTER: { switch(m_spellInfo->Id) diff --git a/src/game/SpellHandler.cpp b/src/game/SpellHandler.cpp index cd8468c4c7b..790f0a60136 100644 --- a/src/game/SpellHandler.cpp +++ b/src/game/SpellHandler.cpp @@ -264,8 +264,8 @@ void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket) return; } - // not have spell or spell passive and not casted by client - if ( !_player->HasSpell (spellId) || IsPassiveSpell(spellId) ) + // not have spell in spellbook or spell passive and not casted by client + if ( !_player->HasActiveSpell (spellId) || IsPassiveSpell(spellId) ) { //cheater? kick? ban? return; diff --git a/src/game/SpellMgr.cpp b/src/game/SpellMgr.cpp index 9092b494013..c640dc58af4 100644 --- a/src/game/SpellMgr.cpp +++ b/src/game/SpellMgr.cpp @@ -480,8 +480,6 @@ bool IsPositiveTarget(uint32 targetA, uint32 targetB) case TARGET_CURRENT_ENEMY_COORDINATES: case TARGET_UNIT_CHANNEL: return false; - case TARGET_ALL_AROUND_CASTER: - return (targetB == TARGET_ALL_PARTY || targetB == TARGET_ALL_FRIENDLY_UNITS_AROUND_CASTER); default: break; } @@ -1095,7 +1093,7 @@ bool SpellMgr::IsSpellProcEventCanTriggeredBy(SpellProcEventEntry const * spellP return false; // Always trigger for this - if (EventProcFlag & (PROC_FLAG_KILLED | PROC_FLAG_KILL)) + if (EventProcFlag & (PROC_FLAG_KILLED | PROC_FLAG_KILL | PROC_FLAG_ON_TRAP_ACTIVATION)) return true; if (spellProcEvent) // Exist event data @@ -1223,28 +1221,38 @@ bool SpellMgr::IsRankSpellDueToSpell(SpellEntry const *spellInfo_1,uint32 spellI bool SpellMgr::canStackSpellRanks(SpellEntry const *spellInfo) { + if(IsPassiveSpell(spellInfo->Id)) // ranked passive spell + return false; if(spellInfo->powerType != POWER_MANA && spellInfo->powerType != POWER_HEALTH) return false; if(IsProfessionOrRidingSpell(spellInfo->Id)) return false; + if(spellmgr.IsSkillBonusSpell(spellInfo->Id)) + return false; + // All stance spells. if any better way, change it. for (int i = 0; i < 3; i++) { - // Paladin aura Spell - if(spellInfo->SpellFamilyName == SPELLFAMILY_PALADIN - && spellInfo->Effect[i]==SPELL_EFFECT_APPLY_AREA_AURA_RAID) - return false; - // Druid form Spell - if(spellInfo->SpellFamilyName == SPELLFAMILY_DRUID - && spellInfo->Effect[i]==SPELL_EFFECT_APPLY_AURA - && spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_SHAPESHIFT) - return false; - // Rogue Stealth - if(spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE - && spellInfo->Effect[i]==SPELL_EFFECT_APPLY_AURA - && spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_SHAPESHIFT) - return false; + switch(spellInfo->SpellFamilyName) + { + case SPELLFAMILY_PALADIN: + // Paladin aura Spell + if (spellInfo->Effect[i]==SPELL_EFFECT_APPLY_AREA_AURA_RAID) + return false; + break; + case SPELLFAMILY_DRUID: + // Druid form Spell + if (spellInfo->Effect[i]==SPELL_EFFECT_APPLY_AURA && + spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_SHAPESHIFT) + return false; + break; + case SPELLFAMILY_ROGUE: + // Rogue Stealth + if (spellInfo->Effect[i]==SPELL_EFFECT_APPLY_AURA && + spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_SHAPESHIFT) + return false; + } } return true; } @@ -1380,6 +1388,24 @@ bool SpellMgr::IsPrimaryProfessionFirstRankSpell(uint32 spellId) const return IsPrimaryProfessionSpell(spellId) && GetSpellRank(spellId)==1; } +bool SpellMgr::IsSkillBonusSpell(uint32 spellId) const +{ + SkillLineAbilityMap::const_iterator lower = GetBeginSkillLineAbilityMap(spellId); + SkillLineAbilityMap::const_iterator upper = GetEndSkillLineAbilityMap(spellId); + + for(SkillLineAbilityMap::const_iterator _spell_idx = lower; _spell_idx != upper; ++_spell_idx) + { + SkillLineAbilityEntry const *pAbility = _spell_idx->second; + if (!pAbility || pAbility->learnOnGetSkill != ABILITY_LEARNED_ON_GET_PROFESSION_SKILL) + continue; + + if(pAbility->req_skill_value > 0) + return true; + } + + return false; +} + SpellEntry const* SpellMgr::SelectAuraRankForPlayerLevel(SpellEntry const* spellInfo, uint32 playerLevel) const { // ignore passive spells @@ -2558,6 +2584,8 @@ uint8 GetSpellAllowedInLocationError(SpellEntry const *spellInfo,uint32 map_id,u case 51721: // Dominion Over Acherus case 54055: // Dominion Over Acherus return area_id == 4281 || area_id == 4342 ? 0 : SPELL_FAILED_INCORRECT_AREA; + case 54119: // Mist of the Kvaldir + return area_id == 4028 || area_id == 4029 || area_id == 4106 || area_id == 4031 ? 0 : SPELL_FAILED_INCORRECT_AREA; } return 0; diff --git a/src/game/SpellMgr.h b/src/game/SpellMgr.h index 9903220677f..77ee39e2249 100644 --- a/src/game/SpellMgr.h +++ b/src/game/SpellMgr.h @@ -397,6 +397,7 @@ bool IsAuraAddedBySpell(uint32 auraType, uint32 spellId); uint8 GetSpellAllowedInLocationError(SpellEntry const *spellInfo,uint32 map_id,uint32 zone_id,uint32 area_id); static bool IsAreaEffectTarget[TOTAL_SPELL_TARGETS]; + inline bool IsAreaOfEffectSpell(SpellEntry const *spellInfo) { if(IsAreaEffectTarget[spellInfo->EffectImplicitTargetA[0]] || IsAreaEffectTarget[spellInfo->EffectImplicitTargetB[0]]) @@ -873,6 +874,14 @@ class SpellMgr return 0; } + uint32 GetNextSpellInChain(uint32 spell_id) const + { + if(SpellChainNode const* node = GetSpellChainNode(spell_id)) + return node->next; + + return 0; + } + SpellsRequiringSpellMap const& GetSpellsRequiringSpell() const { return mSpellsReqSpell; } // Note: not use rank for compare to spell ranks: spell chains isn't linear order @@ -957,6 +966,9 @@ class SpellMgr static bool IsPrimaryProfessionSpell(uint32 spellId); bool IsPrimaryProfessionFirstRankSpell(uint32 spellId) const; + bool IsSkillBonusSpell(uint32 spellId) const; + + // Spell script targets SpellScriptTarget::const_iterator GetBeginSpellScriptTarget(uint32 spell_id) const { diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index b90bd733a6d..e635efa0457 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -4567,7 +4567,8 @@ bool Unit::HandleHasteAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAura, SpellEntry const * procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown) { SpellEntry const *dummySpell = triggeredByAura->GetSpellProto (); - uint32 effIndex = triggeredByAura->GetEffIndex (); + uint32 effIndex = triggeredByAura->GetEffIndex(); + int32 triggerAmount = triggeredByAura->GetModifier()->m_amount; Item* castItem = triggeredByAura->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER ? ((Player*)this)->GetItemByGuid(triggeredByAura->GetCastItemGUID()) : NULL; @@ -4591,7 +4592,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu return false; // return damage % to attacker but < 50% own total health - basepoints0 = triggeredByAura->GetModifier()->m_amount*int32(damage)/100; + basepoints0 = triggerAmount*int32(damage)/100; if(basepoints0 > GetMaxHealth()/2) basepoints0 = GetMaxHealth()/2; @@ -4913,7 +4914,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu case 48504: { triggered_spell_id = 48503; - basepoints0 = triggeredByAura->GetModifier()->m_amount; + basepoints0 = triggerAmount; target = this; break; } @@ -4931,7 +4932,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu case 31872: { // Roll chane - if (!roll_chance_i(triggeredByAura->GetModifier()->m_amount)) + if (!roll_chance_i(triggerAmount)) return false; // Remove any stun effect on target @@ -4962,7 +4963,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu return false; // mana reward - basepoints0 = (triggeredByAura->GetModifier()->m_amount * GetMaxPower(POWER_MANA) / 100); + basepoints0 = (triggerAmount * GetMaxPower(POWER_MANA) / 100); target = this; triggered_spell_id = 29442; break; @@ -4975,7 +4976,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu // mana cost save int32 cost = procSpell->manaCost + procSpell->ManaCostPercentage * GetCreateMana() / 100; - basepoints0 = cost * triggeredByAura->GetModifier()->m_amount/100; + basepoints0 = cost * triggerAmount/100; if( basepoints0 <=0 ) return false; @@ -4986,7 +4987,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu // Hot Streak if (dummySpell->SpellIconID == 2999) { - if (triggeredByAura->GetEffIndex()!=0) + if (effIndex!=0) return true; Aura *counter = GetAura(triggeredByAura->GetId(), 1); if (!counter) @@ -5000,7 +5001,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu if (mod->m_amount < 100) // not enough return true; // Crititcal counted -> roll chance - if (roll_chance_i(triggeredByAura->GetModifier()->m_amount)) + if (roll_chance_i(triggerAmount)) CastSpell(this, 48108, true, castItem, triggeredByAura); } mod->m_amount = 25; @@ -5013,7 +5014,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu return false; int32 cost = procSpell->manaCost + procSpell->ManaCostPercentage * GetCreateMana() / 100; - basepoints0 = cost * triggeredByAura->GetModifier()->m_amount/100; + basepoints0 = cost * triggerAmount/100; if( basepoints0 <=0 ) return false; triggered_spell_id = 44450; @@ -5109,7 +5110,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu if (dummySpell->SpellIconID == 3214) { triggered_spell_id = 59653; - basepoints0 = GetShieldBlockValue() * triggeredByAura->GetModifier()->m_amount / 100; + basepoints0 = GetShieldBlockValue() * triggerAmount / 100; break; } break; @@ -5168,7 +5169,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu if (!target) return false; triggered_spell_id = 54181; - basepoints0 = damage * triggeredByAura->GetModifier()->m_amount / 100; + basepoints0 = damage * triggerAmount / 100; break; } switch(dummySpell->Id) @@ -5187,7 +5188,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu case 30296: { // health - basepoints0 = int32(damage*triggeredByAura->GetModifier()->m_amount/100); + basepoints0 = int32(damage*triggerAmount/100); target = this; triggered_spell_id = 30294; break; @@ -5206,7 +5207,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu return false; // heal amount - basepoints0 = damage * triggeredByAura->GetModifier()->m_amount/100; + basepoints0 = damage * triggerAmount/100; triggered_spell_id = 37382; break; } @@ -5232,14 +5233,14 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu return false; // energize amount - basepoints0 = triggeredByAura->GetModifier()->m_amount*damage/100; + basepoints0 = triggerAmount*damage/100; pVictim->CastCustomSpell(pVictim,34919,&basepoints0,NULL,NULL,true,castItem,triggeredByAura); return true; // no hidden cooldown } // Divine Aegis if (dummySpell->SpellIconID == 2820) { - basepoints0 = damage * triggeredByAura->GetModifier()->m_amount/100; + basepoints0 = damage * triggerAmount/100; triggered_spell_id = 47753; break; } @@ -5256,8 +5257,9 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu return false; // heal amount - basepoints0 = triggeredByAura->GetModifier()->m_amount*damage/100; - pVictim->CastCustomSpell(pVictim,15290,&basepoints0,NULL,NULL,true,castItem,triggeredByAura); + int32 team = triggerAmount*damage/500; + int32 self = triggerAmount*damage/100 - team; + pVictim->CastCustomSpell(pVictim,15290,&team,&self,NULL,true,castItem,triggeredByAura); return true; // no hidden cooldown } // Priest Tier 6 Trinket (Ashtongue Talisman of Acumen) @@ -5291,7 +5293,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu return false; // heal amount - basepoints0 = damage * triggeredByAura->GetModifier()->m_amount/100; + basepoints0 = damage * triggerAmount/100; target = this; triggered_spell_id = 39373; break; @@ -5379,7 +5381,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu if (!procSpell) return false; // Only 0 aura can proc - if (triggeredByAura->GetEffIndex()!=0) + if (effIndex!=0) return true; // Wrath crit if (procSpell->SpellFamilyFlags & 0x0000000000000001LL) @@ -5403,7 +5405,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu else if (dummySpell->SpellIconID == 2860) { triggered_spell_id = 48504; - basepoints0 = triggeredByAura->GetModifier()->m_amount * damage / 100; + basepoints0 = triggerAmount * damage / 100; break; } break; @@ -5455,7 +5457,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu return false; // energy cost save - basepoints0 = procSpell->manaCost * triggeredByAura->GetModifier()->m_amount/100; + basepoints0 = procSpell->manaCost * triggerAmount/100; if(basepoints0 <= 0) return false; @@ -5474,7 +5476,8 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu return false; // mana cost save - basepoints0 = procSpell->manaCost * 40/100; + int32 mana = procSpell->manaCost + procSpell->ManaCostPercentage * GetCreateMana() / 100; + basepoints0 = mana * 40/100; if(basepoints0 <= 0) return false; @@ -5493,9 +5496,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu if ( dummySpell->SpellIconID == 3579 ) { // Proc only from periodic (from trap activation proc another aura of this spell) - if (!(procFlag & PROC_FLAG_ON_DO_PERIODIC)) - return false; - if (!roll_chance_i(triggeredByAura->GetModifier()->m_amount)) + if (!(procFlag & PROC_FLAG_ON_DO_PERIODIC) || !roll_chance_i(triggerAmount)) return false; triggered_spell_id = 56453; target = this; @@ -5516,7 +5517,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu case SPELLFAMILY_PALADIN: { // Seal of Righteousness - melee proc dummy (addition ${$MWS*(0.022*$AP+0.044*$SPH)} damage) - if (dummySpell->SpellFamilyFlags&0x000000008000000LL && triggeredByAura->GetEffIndex()==0) + if (dummySpell->SpellFamilyFlags&0x000000008000000LL && effIndex==0) { triggered_spell_id = 25742; float ap = GetTotalAttackPowerValue(BASE_ATTACK); @@ -5536,7 +5537,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu if (dummySpell->SpellIconID == 3025) { // 4 damage tick - basepoints0 = triggeredByAura->GetModifier()->m_amount*damage/400; + basepoints0 = triggerAmount*damage/400; triggered_spell_id = 61840; break; } @@ -5544,7 +5545,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu if (dummySpell->SpellIconID == 3030) { // 4 healing tick - basepoints0 = triggeredByAura->GetModifier()->m_amount*damage/400; + basepoints0 = triggerAmount*damage/400; triggered_spell_id = 54203; break; } @@ -5620,7 +5621,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu return false; // heal amount - basepoints0 = triggeredByAura->GetModifier()->m_amount*damage/100; + basepoints0 = triggerAmount*damage/100; target = this; triggered_spell_id = 31786; break; @@ -5628,13 +5629,13 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu // Seal of Blood do damage trigger case 31892: { - if (triggeredByAura->GetEffIndex() == 0) // 0 effect - is proc on enemy + if (effIndex == 0) // 0 effect - is proc on enemy triggered_spell_id = 31893; - else if (triggeredByAura->GetEffIndex() == 1) // 1 effect - is proc on self + else if (effIndex == 1) // 1 effect - is proc on self { // add spell damage from prev effect (27%) damage += CalculateDamage(BASE_ATTACK, false) * 27 / 100; - basepoints0 = triggeredByAura->GetModifier()->m_amount * damage / 100; + basepoints0 = triggerAmount * damage / 100; target = this; triggered_spell_id = 32221; } @@ -5645,13 +5646,13 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu // Seal of the Martyr do damage trigger case 53720: { - if (triggeredByAura->GetEffIndex() == 0) // 0 effect - is proc on enemy + if (effIndex == 0) // 0 effect - is proc on enemy triggered_spell_id = 53719; - else if (triggeredByAura->GetEffIndex() == 1) // 1 effect - is proc on self + else if (effIndex == 1) // 1 effect - is proc on self { // add spell damage from prev effect (27%) damage += CalculateDamage(BASE_ATTACK, false) * 27 / 100; - basepoints0 = triggeredByAura->GetModifier()->m_amount * damage / 100; + basepoints0 = triggerAmount * damage / 100; target = this; triggered_spell_id = 53718; } @@ -5704,14 +5705,14 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu case 54936: { triggered_spell_id = 54957; - basepoints0 = triggeredByAura->GetModifier()->m_amount*damage/100; + basepoints0 = triggerAmount*damage/100; break; } // Glyph of Holy Light case 54937: { triggered_spell_id = 54968; - basepoints0 = triggeredByAura->GetModifier()->m_amount*damage/100; + basepoints0 = triggerAmount*damage/100; break; } } @@ -5864,7 +5865,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu // Not proc from self heals if (this==pVictim) return false; - basepoints0 = triggeredByAura->GetModifier()->m_amount * damage / 100; + basepoints0 = triggerAmount * damage / 100; target = this; triggered_spell_id = 55533; break; @@ -5876,7 +5877,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu target = GetOwner(); if(!target) return false; - basepoints0 = triggeredByAura->GetModifier()->m_amount * damage / 100; + basepoints0 = triggerAmount * damage / 100; triggered_spell_id = 58879; break; } @@ -5886,14 +5887,14 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu { // TODO: frite dummy fot triggered spell triggered_spell_id = 52759; - basepoints0 = triggeredByAura->GetModifier()->m_amount * damage / 100; + basepoints0 = triggerAmount * damage / 100; target = this; break; } // Earth Shield if(dummySpell->SpellFamilyFlags & 0x0000040000000000LL) { - basepoints0 = triggeredByAura->GetModifier()->m_amount; + basepoints0 = triggerAmount; target = this; triggered_spell_id = 379; break; @@ -6027,14 +6028,14 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu { if (GetTypeId() != TYPEID_PLAYER || !((Player*)this)->isHonorOrXPTarget(pVictim)) return false; - basepoints0 = triggeredByAura->GetModifier()->m_amount * damage / 100; + basepoints0 = triggerAmount * damage / 100; triggered_spell_id = 53168; break; } // Butchery if (dummySpell->SpellIconID == 2664) { - basepoints0 = triggeredByAura->GetModifier()->m_amount; + basepoints0 = triggerAmount; triggered_spell_id = 50163; target = this; break; @@ -6043,7 +6044,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu if (dummySpell->Id == 49028) { // 1 dummy aura for dismiss rune blade - if (triggeredByAura->GetEffIndex()!=2) + if (effIndex!=2) return false; // TODO: wite script for this "fights on its own, doing the same attacks" // NOTE: Trigger here on every attack and spell cast @@ -6059,7 +6060,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu // Vendetta if (dummySpell->SpellFamilyFlags & 0x0000000000010000LL) { - basepoints0 = triggeredByAura->GetModifier()->m_amount * GetMaxHealth() / 100; + basepoints0 = triggerAmount * GetMaxHealth() / 100; triggered_spell_id = 50181; target = this; break; @@ -6067,7 +6068,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu // Necrosis if (dummySpell->SpellIconID == 2709) { - basepoints0 = triggeredByAura->GetModifier()->m_amount * damage / 100; + basepoints0 = triggerAmount * damage / 100; triggered_spell_id = 51460; break; } @@ -6089,7 +6090,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu { if (!roll_chance_f(GetUnitCriticalChance(BASE_ATTACK, pVictim))) return false; - basepoints0 = triggeredByAura->GetModifier()->m_amount * damage / 100; + basepoints0 = triggerAmount * damage / 100; triggered_spell_id = 50526; break; } @@ -6747,11 +6748,16 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredB // Need add combopoint AFTER finish movie (or they dropped in finish phase) break; } + // Bloodthirst (($m/100)% of max health) + case 23880: + { + basepoints0 = int32(GetMaxHealth() * triggerAmount / 10000); + break; + } // Shamanistic Rage triggered spell case 30824: { basepoints0 = int32(GetTotalAttackPowerValue(BASE_ATTACK) * triggerAmount / 100); - trigger_spell_id = 30824; break; } // Enlightenment (trigger only from mana cost spells) @@ -6806,6 +6812,14 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredB return false; break; } + // Lock and Load + case 56453: + { + // Proc only from trap activation (from periodic proc another aura of this spell) + if (!(procFlags & PROC_FLAG_ON_TRAP_ACTIVATION) || !roll_chance_i(triggerAmount)) + return false; + break; + } } if( cooldown && GetTypeId()==TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(trigger_spell_id)) @@ -10554,7 +10568,7 @@ bool InitTriggerAuraData() isTriggerAura[SPELL_AURA_MOD_DAMAGE_FROM_CASTER] = true; isNonTriggerAura[SPELL_AURA_MOD_POWER_REGEN]=true; - isNonTriggerAura[SPELL_AURA_RESIST_PUSHBACK]=true; + isNonTriggerAura[SPELL_AURA_REDUCE_PUSHBACK]=true; return true; } diff --git a/src/game/World.cpp b/src/game/World.cpp index 7dd1a54769f..71bc1058cee 100644 --- a/src/game/World.cpp +++ b/src/game/World.cpp @@ -777,7 +777,8 @@ void World::LoadConfigSettings(bool reload) } m_configs[CONFIG_GM_LOGIN_STATE] = sConfig.GetIntDefault("GM.LoginState", 2); -// m_configs[CONFIG_GM_ACCEPT_TICKETS] = sConfig.GetIntDefault("GM.AcceptTickets", 2); + m_configs[CONFIG_GM_VISIBLE_STATE] = sConfig.GetIntDefault("GM.Visible", 2); + //m_configs[CONFIG_GM_ACCEPT_TICKETS] = sConfig.GetIntDefault("GM.AcceptTickets", 2); m_configs[CONFIG_GM_CHAT] = sConfig.GetIntDefault("GM.Chat", 2); m_configs[CONFIG_GM_WISPERING_TO] = sConfig.GetIntDefault("GM.WhisperingTo", 2); m_configs[CONFIG_GM_IN_GM_LIST] = sConfig.GetBoolDefault("GM.InGMList", false); @@ -796,6 +797,7 @@ void World::LoadConfigSettings(bool reload) m_configs[CONFIG_START_GM_LEVEL] = MAX_LEVEL; } m_configs[CONFIG_GM_LOWER_SECURITY] = sConfig.GetBoolDefault("GM.LowerSecurity", false); + m_configs[CONFIG_GM_ALLOW_ACHIEVEMENT_GAINS] = sConfig.GetBoolDefault("GM.AllowAchievementGain", true); m_configs[CONFIG_GROUP_VISIBILITY] = sConfig.GetIntDefault("Visibility.GroupMode",0); diff --git a/src/game/World.h b/src/game/World.h index c35529b21f8..fb0d82e5069 100644 --- a/src/game/World.h +++ b/src/game/World.h @@ -125,6 +125,8 @@ enum WorldConfigs CONFIG_MAX_PRIMARY_TRADE_SKILL, CONFIG_MIN_PETITION_SIGNS, CONFIG_GM_LOGIN_STATE, + CONFIG_GM_VISIBLE_STATE, + CONFIG_GM_ACCEPT_TICKETS, CONFIG_GM_CHAT, CONFIG_GM_WISPERING_TO, CONFIG_GM_IN_GM_LIST, @@ -132,6 +134,7 @@ enum WorldConfigs CONFIG_GM_LOG_TRADE, CONFIG_START_GM_LEVEL, CONFIG_GM_LOWER_SECURITY, + CONFIG_GM_ALLOW_ACHIEVEMENT_GAINS, CONFIG_GROUP_VISIBILITY, CONFIG_MAIL_DELIVERY_DELAY, CONFIG_UPTIME_UPDATE, diff --git a/src/mangosd/mangosd.conf.dist.in b/src/mangosd/mangosd.conf.dist.in index 5d303e0c131..c0ec604a7aa 100644 --- a/src/mangosd/mangosd.conf.dist.in +++ b/src/mangosd/mangosd.conf.dist.in @@ -854,6 +854,12 @@ Channel.SilentlyGMJoin = 0 # 0 (disable) # 1 (enable) # +# GM.Visible +# GM visibility at login +# Default: 2 (last save state) +# 0 (invisible) +# 1 (visible) +# # GM.AcceptTickets # Is GM accepting tickets from player by default or not. # Default: 2 (last save state) @@ -896,17 +902,24 @@ Channel.SilentlyGMJoin = 0 # Default: 0 (disable) # 1 (enable) # +# GM.AllowAchievementGain +# If enabled it allows gaining achievements for GM characters +# Default: 0 (disable) +# 1 (enable) (default) +# ################################################################################################################### -GM.LoginState = 2 -GM.AcceptTickets = 2 -GM.Chat = 2 -GM.WhisperingTo = 2 -GM.InGMList = 0 -GM.InWhoList = 0 -GM.LogTrade = 1 -GM.StartLevel = 70 -GM.LowerSecurity = 0 +GM.LoginState = 2 +GM.Visible = 2 +GM.AcceptTickets = 2 +GM.Chat = 2 +GM.WhisperingTo = 2 +GM.InGMList = 0 +GM.InWhoList = 0 +GM.LogTrade = 1 +GM.StartLevel = 80 +GM.LowerSecurity = 0 +GM.AllowAchievementGain = 1 ################################################################################################################### # VISIBILITY AND RADIUSES diff --git a/src/shared/revision.h b/src/shared/revision.h index 028a5a28b40..fcee9b895b3 100644 --- a/src/shared/revision.h +++ b/src/shared/revision.h @@ -1,7 +1,7 @@ #ifndef __REVISION_H__ #define __REVISION_H__ - #define _REVISION "1066" - #define _HASH "1264da9c9234" + #define _REVISION "1083" + #define _HASH "b79b2c3d242f" #define _REVISION_DATE "*" #define _REVISION_TIME "*" #endif // __REVISION_H__ diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 7f75b49b7ca..aecd6e404c8 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7158" + #define REVISION_NR "7183" #endif // __REVISION_NR_H__ |