aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bindings/scripts/include/sc_creature.cpp8
-rw-r--r--src/game/AchievementMgr.cpp6
-rw-r--r--src/game/BattleGroundMgr.cpp32
-rw-r--r--src/game/Chat.cpp71
-rw-r--r--src/game/Chat.h2
-rw-r--r--src/game/GameObject.cpp6
-rw-r--r--src/game/Level2.cpp4
-rw-r--r--src/game/Level3.cpp141
-rw-r--r--src/game/NPCHandler.cpp24
-rw-r--r--src/game/ObjectAccessor.cpp29
-rw-r--r--src/game/ObjectAccessor.h4
-rw-r--r--src/game/ObjectMgr.cpp24
-rw-r--r--src/game/ObjectMgr.h7
-rw-r--r--src/game/Pet.cpp47
-rw-r--r--src/game/Pet.h12
-rw-r--r--src/game/Player.cpp517
-rw-r--r--src/game/Player.h26
-rw-r--r--src/game/SharedDefines.h1
-rw-r--r--src/game/SkillHandler.cpp2
-rw-r--r--src/game/Spell.cpp192
-rw-r--r--src/game/Spell.h11
-rw-r--r--src/game/SpellAuraDefines.h4
-rw-r--r--src/game/SpellAuras.cpp71
-rw-r--r--src/game/SpellEffects.cpp50
-rw-r--r--src/game/SpellHandler.cpp4
-rw-r--r--src/game/SpellMgr.cpp62
-rw-r--r--src/game/SpellMgr.h12
-rw-r--r--src/game/Unit.cpp112
-rw-r--r--src/game/World.cpp4
-rw-r--r--src/game/World.h3
-rw-r--r--src/mangosd/mangosd.conf.dist.in31
-rw-r--r--src/shared/revision.h4
-rw-r--r--src/shared/revision_nr.h2
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,&param1_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__