diff options
-rw-r--r-- | src/bindings/scripts/scripts/zone/vault_of_archavon/boss_emalon.cpp | 285 | ||||
-rw-r--r-- | src/bindings/scripts/scripts/zone/vault_of_archavon/def_vault_of_archavon.h | 13 | ||||
-rw-r--r-- | src/bindings/scripts/scripts/zone/vault_of_archavon/instance_vault_of_archavon.cpp | 105 | ||||
-rw-r--r-- | src/game/Creature.cpp | 30 | ||||
-rw-r--r-- | src/game/Creature.h | 2 | ||||
-rw-r--r-- | src/game/Item.cpp | 3 | ||||
-rw-r--r-- | src/game/Player.cpp | 2 | ||||
-rw-r--r-- | src/game/TemporarySummon.cpp | 2 | ||||
-rw-r--r-- | src/game/ThreatManager.cpp | 2 | ||||
-rw-r--r-- | src/game/Unit.cpp | 5 | ||||
-rw-r--r-- | src/game/World.cpp | 2 | ||||
-rw-r--r-- | src/game/World.h | 1 | ||||
-rw-r--r-- | src/trinitycore/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/trinitycore/trinitycore.conf.dist | 5 |
14 files changed, 227 insertions, 232 deletions
diff --git a/src/bindings/scripts/scripts/zone/vault_of_archavon/boss_emalon.cpp b/src/bindings/scripts/scripts/zone/vault_of_archavon/boss_emalon.cpp index 7738b790abf..ba999ca766c 100644 --- a/src/bindings/scripts/scripts/zone/vault_of_archavon/boss_emalon.cpp +++ b/src/bindings/scripts/scripts/zone/vault_of_archavon/boss_emalon.cpp @@ -1,108 +1,93 @@ #include "precompiled.h" #include "def_vault_of_archavon.h" -#define EMOTE_OVERCHARGE_TEMPEST_MINION -1590000 -#define EMOTE_MINION_RESPAWN -1590001 - -//Spells Emalon -#define SPELL_CHAIN_LIGHTNING HEROIC(64213,64215) -#define SPELL_LIGHTNING_NOVA HEROIC(64216,65279) -#define SPELL_OVERCHARGE 64218 -#define SPELL_BERSERK 47008 - -//Spells Tempest Minions -#define SPELL_OVERCHARGED 64217 -#define SPELL_OVERCHARGED_BLAST 64219 -#define SPELL_SHOCK 64363 - -//4 Warders spawned -#define TEMPEST_MINIONS 33998 - -#define EVENT_CHAIN_LIGHTNING 1 //5s cd -#define EVENT_OVERCHARGE 2 //45s cd -#define EVENT_LIGHTNING_NOVA 3 //40s cd -#define EVENT_BERSERK 4 //360s cd -#define EVENT_SHOCK 5 //20s cd - -struct Location +//Emalon spells +#define SPELL_CHAIN_LIGHTNING HEROIC(64213, 64215) +#define SPELL_LIGHTNING_NOVA HEROIC(64216, 65279) +#define SPELL_OVERCHARGE 64218 //Casted every 45 sec on a random Tempest Minion +#define SPELL_BERSERK 26662 + +//Tempest Minion spells +#define SPELL_SHOCK 64363 +#define SPELL_OVERCHARGED 64217 +#define SPELL_OVERCHARGED_BLAST 64219 //Casted when Overcharged reaches 10 stacks. Mob dies after that + +//Emotes +#define EMOTE_OVERCHARGE -1590000 +#define EMOTE_MINION_RESPAWN -1590001 +#define EMOTE_BERSERK -1590002 + +//Events +#define EVENT_CHAIN_LIGHTNING 1 +#define EVENT_LIGHTNING_NOVA 2 +#define EVENT_OVERCHARGE 3 +#define EVENT_BERSERK 4 +#define EVENT_SHOCK 5 + +//Creatures +#define MOB_TEMPEST_MINION 33998 + +float TempestMinions[4][5] = { - float x, y, z, o; -}; - -static Location MinionLocation[]= -{ - -231.713,-281.96,91.466,1.53213, - -205.585,-281.549,91.4661,1.75204, - -205.651,-296.394,91.4661,1.69549, - -232.235,-296.433,91.4998,1.44417 + {33998, -203.980103, -281.287720, 91.650223, 1.598807}, + {33998, -233.489410, -281.139282, 91.652412, 1.598807}, + {33998, -233.267578, -297.104645, 91.681915, 1.598807}, + {33998, -203.842529, -297.097015, 91.745163, 1.598807} }; +/*###### +## Emalon the Storm Watcher +######*/ struct TRINITY_DLL_DECL boss_emalonAI : public ScriptedAI { - boss_emalonAI(Creature *c) : ScriptedAI(c) + boss_emalonAI(Creature *c) : ScriptedAI(c), summons(m_creature) { pInstance = c->GetInstanceData(); } ScriptedInstance* pInstance; + EventMap events; std::list<uint64> MinionList; + SummonList summons; void Reset() - { + { events.Reset(); - DespawnAllMinions(); - SummonAllMinions(); - - if (pInstance) - pInstance->SetData(DATA_EMALON_EVENT, NOT_STARTED); - } + summons.DespawnAll(); + MinionList.clear(); - void DespawnAllMinions() - { - if (!MinionList.empty()) + Creature* Minion; + for (uint32 i = 0; i < 4; ++i) { - for(std::list<uint64>::const_iterator itr = MinionList.begin(); itr != MinionList.end(); itr++) - { - if (Creature *Minion = Unit::GetCreature(*m_creature, (*itr))) - Minion->DisappearAndDie(); - } + Minion = m_creature->SummonCreature(((uint32)TempestMinions[i][0]),TempestMinions[i][1],TempestMinions[i][2],TempestMinions[i][3],TempestMinions[i][4],TEMPSUMMON_DEAD_DESPAWN, 0); + MinionList.push_back(Minion->GetGUID()); + if(Unit* target = m_creature->getVictim()) + Minion->AI()->AttackStart(target); } - - MinionList.clear(); - } - void JustSummoned(Creature *Summoned) - { - MinionList.push_back(Summoned->GetGUID()); - if (Unit* target = m_creature->getVictim()) - Summoned->AI()->AttackStart(target); + if (pInstance) + pInstance->SetData(DATA_EMALON_EVENT, NOT_STARTED); } - void SummonAllMinions() + void JustSummoned(Creature* summoned) { - if (MinionList.empty()) - for(uint8 i = 0; i < 4; ++i) - SummonMinion(m_creature, MinionLocation[i].x, MinionLocation[i].y, MinionLocation[i].z, MinionLocation[i].o); + summons.Summon(summoned); } - static void SummonMinion(Creature *Summoner, float x, float y, float z, float o) - { - Summoner->SummonCreature(TEMPEST_MINIONS, x, y, z, o, TEMPSUMMON_DEAD_DESPAWN, 0); - } - - void KilledUnit(Unit* Victim){} + void SummonedCreatureDespawn(Creature *summon) {summons.Despawn(summon);} void JustDied(Unit* Killer) { - DespawnAllMinions(); + summons.DespawnAll(); + if (pInstance) pInstance->SetData(DATA_EMALON_EVENT, DONE); } void EnterCombat(Unit *who) { - if (!MinionList.empty()) + if(!MinionList.empty()) { for(std::list<uint64>::const_iterator itr = MinionList.begin(); itr != MinionList.end(); ++itr) { @@ -113,69 +98,51 @@ struct TRINITY_DLL_DECL boss_emalonAI : public ScriptedAI DoZoneInCombat(); events.ScheduleEvent(EVENT_CHAIN_LIGHTNING, 5000); - events.ScheduleEvent(EVENT_OVERCHARGE, 45000); - events.ScheduleEvent(EVENT_LIGHTNING_NOVA, 30000); + events.ScheduleEvent(EVENT_LIGHTNING_NOVA, 40000); events.ScheduleEvent(EVENT_BERSERK, 360000); - events.ScheduleEvent(EVENT_SHOCK, 20000); + events.ScheduleEvent(EVENT_OVERCHARGE, 45000); if (pInstance) - pInstance->SetData(DATA_EMALON_EVENT, IN_PROGRESS); + pInstance->SetData(DATA_EMALON_EVENT, IN_PROGRESS); } void UpdateAI(const uint32 diff) { //Return since we have no target - if (!UpdateVictim()) + if(!UpdateVictim()) return; events.Update(diff); - if (me->hasUnitState(UNIT_STAT_CASTING)) - return; + if(me->hasUnitState(UNIT_STAT_CASTING)) + return; while(uint32 eventId = events.ExecuteEvent()) { switch(eventId) { - case EVENT_CHAIN_LIGHTNING: - if (Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0)) - DoCast(target, SPELL_CHAIN_LIGHTNING); - events.ScheduleEvent(EVENT_CHAIN_LIGHTNING, 20000); - return; - case EVENT_OVERCHARGE: - for(std::list<uint64>::const_iterator itr = MinionList.begin(); itr != MinionList.end(); ++itr) - { - Creature* Minion = (Unit::GetCreature(*m_creature, *itr)); - if (Minion && Minion->isAlive() && !Minion->HasAura(SPELL_OVERCHARGED)) - { - Minion->CastSpell(me, SPELL_OVERCHARGED, true); - Minion->SetHealth(Minion->GetMaxHealth()); - DoScriptText(EMOTE_OVERCHARGE_TEMPEST_MINION, m_creature); - events.ScheduleEvent(EVENT_OVERCHARGE, 45000); - return; - } - } - case EVENT_LIGHTNING_NOVA: - DoCast(me->getVictim(), SPELL_LIGHTNING_NOVA); - events.ScheduleEvent(EVENT_LIGHTNING_NOVA, 25000); - return; - case EVENT_SHOCK: - for(std::list<uint64>::const_iterator itr = MinionList.begin(); itr != MinionList.end(); ++itr) - { - Creature* Minion = (Unit::GetCreature(*m_creature, *itr)); - if (Minion && Minion->isAlive()) - { - if (Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0)) - { - Minion->CastSpell(target, SPELL_SHOCK, true); - events.ScheduleEvent(EVENT_SHOCK, 20000); - return; - } - } - } - case EVENT_BERSERK: - DoCast(m_creature, SPELL_BERSERK); - return; + case EVENT_CHAIN_LIGHTNING: + if(Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0)) + DoCast(target, SPELL_CHAIN_LIGHTNING); + events.ScheduleEvent(EVENT_CHAIN_LIGHTNING, 25000); + return; + case EVENT_LIGHTNING_NOVA: + DoCastAOE(SPELL_LIGHTNING_NOVA, false); + events.ScheduleEvent(EVENT_LIGHTNING_NOVA, 40000); + return; + case EVENT_OVERCHARGE: + if(Creature* Minion = GetClosestCreatureWithEntry(me, MOB_TEMPEST_MINION, 1000.0f)) + { + Minion->CastSpell(me, SPELL_OVERCHARGED, true); + Minion->SetHealth(Minion->GetMaxHealth()); + DoScriptText(EMOTE_OVERCHARGE, m_creature); + } + events.ScheduleEvent(EVENT_OVERCHARGE, 45000); + return; + case EVENT_BERSERK: + DoCast(m_creature, SPELL_BERSERK); + DoScriptText(EMOTE_BERSERK, m_creature); + return; } } @@ -184,11 +151,11 @@ struct TRINITY_DLL_DECL boss_emalonAI : public ScriptedAI }; /*###### -## Mob Tempest Minions +## Tempest Minion ######*/ struct TRINITY_DLL_DECL mob_tempest_minionAI : public ScriptedAI { - mob_tempest_minionAI(Creature *c) : ScriptedAI(c) + mob_tempest_minionAI(Creature *c) : ScriptedAI(c) { pInstance = c->GetInstanceData(); EmalonGUID = pInstance ? pInstance->GetData64(DATA_EMALON) : 0; @@ -196,74 +163,100 @@ struct TRINITY_DLL_DECL mob_tempest_minionAI : public ScriptedAI } ScriptedInstance* pInstance; + EventMap events; + uint64 EmalonGUID; - std::list<Creature*> MinionList; Creature* Emalon; - uint32 SPELL_OVERCHARGED_Timer; - bool AlreadyOvercharged; + + uint32 OverchargedTimer; void Reset() { events.Reset(); - AlreadyOvercharged = false; - SPELL_OVERCHARGED_Timer = 0; + + OverchargedTimer = 0; } - void EnterCombat(Unit *who) + void JustDied(Unit* Killer) { - DoZoneInCombat(); - if (Emalon) - Emalon->AI()->AttackStart(who); + Creature* Emalon; + Emalon = Unit::GetCreature(*m_creature, EmalonGUID); + float x,y,z; + Emalon->GetPosition(x,y,z); + Emalon->SummonCreature(MOB_TEMPEST_MINION,x,y,z,m_creature->GetOrientation(),TEMPSUMMON_DEAD_DESPAWN,0); + DoScriptText(EMOTE_MINION_RESPAWN, m_creature); } - void JustDied(Unit* Killer) + void EnterCombat(Unit *who) { - m_creature->DisappearAndDie(); - if (Emalon) - { - boss_emalonAI::SummonMinion(Emalon, Emalon->GetPositionX(), Emalon->GetPositionY(), Emalon->GetPositionZ(), Emalon->GetOrientation()); - DoScriptText(EMOTE_MINION_RESPAWN, m_creature); - } + DoZoneInCombat(); + events.ScheduleEvent(EVENT_SHOCK, 20000); + + if(Emalon) + Emalon->AI()->AttackStart(who); } void UpdateAI(const uint32 diff) { //Return since we have no target - if (!UpdateVictim()) - return; + if(!UpdateVictim()) + return; + + events.Update(diff); - if (Aura *OverchargedAura = m_creature->GetAura(SPELL_OVERCHARGED)) + if(me->hasUnitState(UNIT_STAT_CASTING)) + return; + + if(Aura *OverchargedAura = m_creature->GetAura(SPELL_OVERCHARGED)) { - if (OverchargedAura->GetStackAmount() < 10) + if(OverchargedAura->GetStackAmount() < 10) { - if (SPELL_OVERCHARGED_Timer < diff) + if(OverchargedTimer < diff) { DoCast(me, SPELL_OVERCHARGED); - SPELL_OVERCHARGED_Timer = 2000; - }else SPELL_OVERCHARGED_Timer -=diff; + OverchargedTimer = 2000; + }else OverchargedTimer -=diff; } else { - if (OverchargedAura->GetStackAmount() == 10 && (AlreadyOvercharged == false)) + if(OverchargedAura->GetStackAmount() == 10) { DoCast(me,SPELL_OVERCHARGED_BLAST); - AlreadyOvercharged = true; + m_creature->setDeathState(JUST_DIED); + Creature* Emalon; + Emalon = Unit::GetCreature(*m_creature, EmalonGUID); + float x,y,z; + Emalon->GetPosition(x,y,z); + Emalon->SummonCreature(MOB_TEMPEST_MINION,x,y,z,m_creature->GetOrientation(),TEMPSUMMON_DEAD_DESPAWN,0); + DoScriptText(EMOTE_MINION_RESPAWN, m_creature); } } } + + while(uint32 eventId = events.ExecuteEvent()) + { + switch(eventId) + { + case EVENT_SHOCK: + DoCast(me->getVictim(), SPELL_SHOCK); + events.ScheduleEvent(EVENT_SHOCK, 20000); + return; + } + } + DoMeleeAttackIfReady(); } }; -CreatureAI* GetAI_mob_tempest_minion(Creature* pCreature) +CreatureAI* GetAI_mob_tempest_minion(Creature *_Creature) { - return new mob_tempest_minionAI (pCreature); + return new mob_tempest_minionAI (_Creature); } -CreatureAI* GetAI_boss_emalon(Creature* pCreature) +CreatureAI* GetAI_boss_emalon(Creature *_Creature) { - return new boss_emalonAI (pCreature); + return new boss_emalonAI (_Creature); } void AddSC_boss_emalon() diff --git a/src/bindings/scripts/scripts/zone/vault_of_archavon/def_vault_of_archavon.h b/src/bindings/scripts/scripts/zone/vault_of_archavon/def_vault_of_archavon.h index 5b11d5729eb..0ebadb214d8 100644 --- a/src/bindings/scripts/scripts/zone/vault_of_archavon/def_vault_of_archavon.h +++ b/src/bindings/scripts/scripts/zone/vault_of_archavon/def_vault_of_archavon.h @@ -1,13 +1,8 @@ #ifndef DEF_ARCHAVON_H #define DEF_ARCHAVON_H -enum -{ - DATA_ARCHAVON = 1, - DATA_EMALON = 2, - - DATA_ARCHAVON_EVENT = 3, - DATA_EMALON_EVENT = 4 -}; - +#define DATA_ARCHAVON_EVENT 1 +#define DATA_EMALON_EVENT 2 +#define DATA_EMALON 3 +#define DATA_ARCHAVON 4 #endif diff --git a/src/bindings/scripts/scripts/zone/vault_of_archavon/instance_vault_of_archavon.cpp b/src/bindings/scripts/scripts/zone/vault_of_archavon/instance_vault_of_archavon.cpp index 1db6e7b0c10..4b5c8f371af 100644 --- a/src/bindings/scripts/scripts/zone/vault_of_archavon/instance_vault_of_archavon.cpp +++ b/src/bindings/scripts/scripts/zone/vault_of_archavon/instance_vault_of_archavon.cpp @@ -1,116 +1,117 @@ #include "precompiled.h" #include "def_vault_of_archavon.h" -#define NUMBER_OF_ENCOUNTERS 2 +#define ENCOUNTERS 2 + +/* Vault of Archavon encounters: +1 - Archavon the Stone Watcher event +2 - Emalon the Storm Watcher event +*/ struct TRINITY_DLL_DECL instance_archavon : public ScriptedInstance { - instance_archavon(Map* pMap) : ScriptedInstance(pMap) {Initialize();}; + instance_archavon(Map *Map) : ScriptedInstance(Map) {Initialize();}; + + uint32 Encounters[ENCOUNTERS]; - std::string strInstData; uint64 Archavon; uint64 Emalon; - uint32 m_auiEncounter[NUMBER_OF_ENCOUNTERS]; void Initialize() - { - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); - + { Archavon = 0; Emalon = 0; + + for(uint8 i = 0; i < ENCOUNTERS; i++) + Encounters[i] = NOT_STARTED; } bool IsEncounterInProgress() const { - for(uint8 i = 0; i < NUMBER_OF_ENCOUNTERS; ++i) - if (m_auiEncounter[i] == IN_PROGRESS) - return true; + for(uint8 i = 0; i < ENCOUNTERS; i++) + if(Encounters[i] == IN_PROGRESS) return true; return false; } - void OnCreatureCreate(Creature* pCreature, bool add) + void OnCreatureCreate(Creature *creature, bool add) { - switch(pCreature->GetEntry()) + switch(creature->GetEntry()) { - case 31125: Archavon = pCreature->GetGUID(); break; - case 33993: Emalon = pCreature->GetGUID(); break; + case 31125: Archavon = creature->GetGUID(); break; + case 33993: Emalon = creature->GetGUID(); break; } } - uint64 GetData64(uint32 identifier) + uint32 GetData(uint32 type) { - switch(identifier) + switch(type) { - case DATA_ARCHAVON: return Archavon; - case DATA_EMALON: return Emalon; + case DATA_ARCHAVON_EVENT: return Encounters[0]; + case DATA_EMALON_EVENT: return Encounters[1]; } return 0; } - uint32 GetData(uint32 identifier) + uint64 GetData64(uint32 identifier) { switch(identifier) { - case DATA_ARCHAVON_EVENT: return m_auiEncounter[0]; - case DATA_EMALON_EVENT: return m_auiEncounter[1]; + case DATA_ARCHAVON: return Archavon; + case DATA_EMALON: return Emalon; } return 0; } - void SetData(uint32 identifier, uint32 data) + void SetData(uint32 type, uint32 data) { - switch(identifier) + switch(type) { - case DATA_ARCHAVON_EVENT: m_auiEncounter[0] = data; break; - case DATA_EMALON_EVENT: m_auiEncounter[1] = data; break; + case DATA_ARCHAVON_EVENT: Encounters[0] = data; break; + case DATA_EMALON_EVENT: Encounters[1] = data; break; } - if (data == DONE) - { - OUT_SAVE_INST_DATA; - - std::ostringstream saveStream; - saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1]; - - strInstData = saveStream.str(); - + if(data == DONE) SaveToDB(); - OUT_SAVE_INST_DATA_COMPLETE; - } } std::string GetSaveData() { - return strInstData; + OUT_SAVE_INST_DATA; + std::ostringstream stream; + stream << Encounters[0] << " " << Encounters[1]; + char* out = new char[stream.str().length() + 1]; + strcpy(out, stream.str().c_str()); + if(out) + { + OUT_SAVE_INST_DATA_COMPLETE; + return out; + } + + return NULL; } - void Load(const char* chrIn) + void Load(const char* in) { - if (!chrIn) + if(!in) { OUT_LOAD_INST_DATA_FAIL; return; } - OUT_LOAD_INST_DATA(chrIn); - - std::istringstream loadStream(chrIn); - loadStream >> m_auiEncounter[0] >> m_auiEncounter[1]; - - for(uint8 i = 1; i < NUMBER_OF_ENCOUNTERS; ++i) - { - if (m_auiEncounter[i] == IN_PROGRESS) - m_auiEncounter[i] = NOT_STARTED; - } - + OUT_LOAD_INST_DATA(in); + std::istringstream stream(in); + stream >> Encounters[0] >> Encounters[1]; + for(uint8 i = 0; i < ENCOUNTERS; ++i) + if(Encounters[i] == IN_PROGRESS) + Encounters[i] = NOT_STARTED; OUT_LOAD_INST_DATA_COMPLETE; } }; -InstanceData* GetInstanceData_instance_archavon(Map* pMap) +InstanceData* GetInstanceData_instance_archavon(Map* map) { - return new instance_archavon(pMap); + return new instance_archavon(map); } void AddSC_instance_archavon() diff --git a/src/game/Creature.cpp b/src/game/Creature.cpp index 19eae315e9c..1fc31e8a93a 100644 --- a/src/game/Creature.cpp +++ b/src/game/Creature.cpp @@ -923,7 +923,7 @@ void Creature::prepareGossipMenu( Player *pPlayer,uint32 gossipid ) cantalking=false; break; case GOSSIP_OPTION_LEARNDUALSPEC: - if(!(pPlayer->GetSpecsCount() == 1 && isCanTrainingAndResetTalentsOf(pPlayer) && !(pPlayer->getLevel() < 40))) + if(!(pPlayer->GetSpecsCount() == 1 && isCanTrainingAndResetTalentsOf(pPlayer) && !(pPlayer->getLevel() < sWorld.getConfig(CONFIG_MIN_DUALSPEC_LEVEL)))) cantalking=false; break; case GOSSIP_OPTION_UNLEARNTALENTS: @@ -1074,7 +1074,7 @@ void Creature::OnGossipSelect(Player* player, uint32 option) player->SendTalentWipeConfirm(guid); break; case GOSSIP_OPTION_LEARNDUALSPEC: - if(player->GetSpecsCount() == 1 && !(player->getLevel() < 40)) + if(player->GetSpecsCount() == 1 && !(player->getLevel() < sWorld.getConfig(CONFIG_MIN_DUALSPEC_LEVEL))) { if (player->GetMoney() < 10000000) { @@ -1704,7 +1704,7 @@ bool Creature::IsWithinSightDist(Unit const* u) const bool Creature::canStartAttack(Unit const* who, bool force) const { - if(isCivilian() || !who->isInAccessiblePlaceFor(this)) + if(isCivilian()) return false; if(!canFly() && (GetDistanceZ(who) > CREATURE_Z_ATTACK_RANGE)) @@ -1716,7 +1716,7 @@ bool Creature::canStartAttack(Unit const* who, bool force) const if(!force && (IsNeutralToAll() || !IsWithinDistInMap(who, GetAttackDistance(who)))) return false; - if(!canAttack(who, force)) + if(!canCreatureAttack(who, force)) return false; return IsWithinLOSInMap(who); @@ -2180,29 +2180,29 @@ void Creature::SaveRespawnTime() objmgr.SaveCreatureRespawnTime(m_DBTableGuid,GetInstanceId(),time(NULL)+m_respawnDelay+m_deathTimer/IN_MILISECONDS); } -bool Creature::IsOutOfThreatArea(Unit* pVictim) const +// this should not be called by petAI or +bool Creature::canCreatureAttack(Unit const *pVictim, bool force) const { - if(!pVictim) - return true; - if(!pVictim->IsInMap(this)) - return true; + return false; - if(!canAttack(pVictim)) - return true; + if(!canAttack(pVictim, force)) + return false; if(!pVictim->isInAccessiblePlaceFor(this)) - return true; + return false; if(sMapStore.LookupEntry(GetMapId())->IsDungeon()) - return false; + return true; float AttackDist = GetAttackDistance(pVictim); uint32 ThreatRadius = sWorld.getConfig(CONFIG_THREAT_RADIUS); //Use AttackDistance in distance check if threat radius is lower. This prevents creature bounce in and out of combat every update tick. - return !pVictim->IsWithinDist3d(mHome_X,mHome_Y,mHome_Z, - ThreatRadius > AttackDist ? ThreatRadius : AttackDist); + if(Unit *unit = GetCharmerOrOwner()) + return pVictim->IsWithinDist(unit, ThreatRadius > AttackDist ? ThreatRadius : AttackDist); + else + return pVictim->IsWithinDist3d(mHome_X, mHome_Y, mHome_Z, ThreatRadius > AttackDist ? ThreatRadius : AttackDist); } CreatureDataAddon const* Creature::GetCreatureAddon() const diff --git a/src/game/Creature.h b/src/game/Creature.h index cec6a123579..fdab5157bd4 100644 --- a/src/game/Creature.h +++ b/src/game/Creature.h @@ -527,7 +527,7 @@ class TRINITY_DLL_SPEC Creature : public Unit bool isCanTrainingOf(Player* player, bool msg) const; bool isCanInteractWithBattleMaster(Player* player, bool msg) const; bool isCanTrainingAndResetTalentsOf(Player* pPlayer) const; - bool IsOutOfThreatArea(Unit* pVictim) const; + bool canCreatureAttack(Unit const *pVictim, bool force = true) const; bool IsImmunedToSpell(SpellEntry const* spellInfo); // redefine Unit::IsImmunedToSpell bool IsImmunedToSpellEffect(SpellEntry const* spellInfo, uint32 index) const; diff --git a/src/game/Item.cpp b/src/game/Item.cpp index 484fa766da0..dac3ca8b0c8 100644 --- a/src/game/Item.cpp +++ b/src/game/Item.cpp @@ -286,7 +286,8 @@ void Item::UpdateDuration(Player* owner, uint32 diff) if (GetUInt32Value(ITEM_FIELD_DURATION)<=diff) { owner->DestroyItem(GetBagSlot(), GetSlot(), true); - Script->ItemExpire(owner, GetProto()); + if(const ItemPrototype *proto = GetProto()) + Script->ItemExpire(owner, proto); return; } diff --git a/src/game/Player.cpp b/src/game/Player.cpp index 8fc7a170f70..96a48225d56 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -2547,7 +2547,7 @@ void Player::InitTalentForLevel() } else { - if (level < 40 || m_specsCount == 0) + if (level < sWorld.getConfig(CONFIG_MIN_DUALSPEC_LEVEL) || m_specsCount == 0) { m_specsCount = 1; m_activeSpec = 0; diff --git a/src/game/TemporarySummon.cpp b/src/game/TemporarySummon.cpp index 40c6d79c919..434750c8744 100644 --- a/src/game/TemporarySummon.cpp +++ b/src/game/TemporarySummon.cpp @@ -325,7 +325,7 @@ void Guardian::InitStats(uint32 duration) if(m_owner->GetTypeId() == TYPEID_PLAYER && HasSummonMask(SUMMON_MASK_CONTROLABLE_GUARDIAN)) m_charmInfo->InitCharmCreateSpells(); - SetReactState(REACT_DEFENSIVE); + SetReactState(REACT_AGGRESSIVE); } Puppet::Puppet(SummonPropertiesEntry const *properties, Unit *owner) : Minion(properties, owner) diff --git a/src/game/ThreatManager.cpp b/src/game/ThreatManager.cpp index 60c46c2307d..5db2a99440d 100644 --- a/src/game/ThreatManager.cpp +++ b/src/game/ThreatManager.cpp @@ -306,7 +306,7 @@ HostilReference* ThreatContainer::selectNextVictim(Creature* pAttacker, HostilRe } } - if(!pAttacker->IsOutOfThreatArea(target)) // skip non attackable currently targets + if(pAttacker->canCreatureAttack(target)) // skip non attackable currently targets { if(pCurrentVictim) // select 1.3/1.1 better target in comparison current target { diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index da55ce24576..567a3628c9c 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -11187,11 +11187,8 @@ Unit* Creature::SelectVictim() // search nearby enemy before enter evade mode if(HasReactState(REACT_AGGRESSIVE)) - { - target = SelectNearestTarget(); - if(target && !IsOutOfThreatArea(target)) + if(target = SelectNearestTarget()) return target; - } if(m_invisibilityMask) { diff --git a/src/game/World.cpp b/src/game/World.cpp index e09aab24e44..a5e6a66f491 100644 --- a/src/game/World.cpp +++ b/src/game/World.cpp @@ -729,6 +729,8 @@ void World::LoadConfigSettings(bool reload) m_configs[CONFIG_MAX_PLAYER_LEVEL] = MAX_LEVEL; } + m_configs[CONFIG_MIN_DUALSPEC_LEVEL] = sConfig.GetIntDefault("MinDualSpecLevel", 40); + m_configs[CONFIG_START_PLAYER_LEVEL] = sConfig.GetIntDefault("StartPlayerLevel", 1); if(m_configs[CONFIG_START_PLAYER_LEVEL] < 1) { diff --git a/src/game/World.h b/src/game/World.h index 9d1813f9752..bfc2947201a 100644 --- a/src/game/World.h +++ b/src/game/World.h @@ -124,6 +124,7 @@ enum WorldConfigs CONFIG_MIN_LEVEL_FOR_HEROIC_CHARACTER_CREATING, CONFIG_SKIP_CINEMATICS, CONFIG_MAX_PLAYER_LEVEL, + CONFIG_MIN_DUALSPEC_LEVEL, CONFIG_START_PLAYER_LEVEL, CONFIG_START_HEROIC_PLAYER_LEVEL, CONFIG_START_PLAYER_MONEY, diff --git a/src/trinitycore/CMakeLists.txt b/src/trinitycore/CMakeLists.txt index ffd8e6431c4..b8a51158665 100644 --- a/src/trinitycore/CMakeLists.txt +++ b/src/trinitycore/CMakeLists.txt @@ -47,7 +47,7 @@ trinityconfig vmaps ZThread g3dlite -readline +${READLINE_LIBRARY} gomp ${SCRIPT_LIB} ${MYSQL_LIBRARIES} diff --git a/src/trinitycore/trinitycore.conf.dist b/src/trinitycore/trinitycore.conf.dist index 242f1f52933..f8aa1eccb63 100644 --- a/src/trinitycore/trinitycore.conf.dist +++ b/src/trinitycore/trinitycore.conf.dist @@ -593,6 +593,10 @@ ChatLogTimestamp = 0 # Change not recommended # Default: 80 # +# MinDualSpecLevel +# Min level at which players can use Dual Spec functionality +# Default: 40 +# # StartPlayerLevel # Staring level that have character at creating (in range 1 to MaxPlayerLevel) # Default: 1 @@ -755,6 +759,7 @@ HeroicCharactersPerRealm = 1 MinLevelForHeroicCharacterCreating = 55 SkipCinematics = 0 MaxPlayerLevel = 80 +MinDualSpecLevel = 40 StartPlayerLevel = 1 StartHeroicPlayerLevel = 55 StartPlayerMoney = 0 |