diff options
-rw-r--r-- | doc/EventAI.txt | 1 | ||||
-rw-r--r-- | src/game/Creature.cpp | 29 | ||||
-rw-r--r-- | src/game/Creature.h | 2 | ||||
-rw-r--r-- | src/game/CreatureEventAI.cpp | 66 | ||||
-rw-r--r-- | src/game/CreatureEventAI.h | 87 | ||||
-rw-r--r-- | src/game/CreatureEventAIMgr.cpp | 2 | ||||
-rw-r--r-- | src/game/GridNotifiers.h | 19 |
7 files changed, 141 insertions, 65 deletions
diff --git a/doc/EventAI.txt b/doc/EventAI.txt index 7a2087decc7..a22b94eea01 100644 --- a/doc/EventAI.txt +++ b/doc/EventAI.txt @@ -128,6 +128,7 @@ Params are always read from Param1, then Param2, then Param3. 36 ACTION_T_UPDATE_TEMPLATE TemplateId, Team Changes the creature to a new creature template of (param1) with team = Alliance if (param2) = false or Horde if (param2) = true 37 ACTION_T_DIE No Params Kills the creature 38 ACTION_T_ZONE_COMBAT_PULSE No Params Places all players within the instance into combat with the creature. Only works in combat and only works inside of instances. +39 ACTION_T_CALL_FOR_HELP Radius Call any friendly creatures (if its not in combat/etc) in radius attack creature target. * = Use -1 to specify that if this param is picked to do nothing. Random is constant between actions within an event. So if you have a random Yell and a random Sound they will match up (ex: param2 with param2) diff --git a/src/game/Creature.cpp b/src/game/Creature.cpp index 17828752aac..007e224b1e7 100644 --- a/src/game/Creature.cpp +++ b/src/game/Creature.cpp @@ -111,8 +111,7 @@ uint32 CreatureInfo::GetFirstValidModelId() const bool AssistDelayEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/) { - Unit* victim = Unit::GetUnit(m_owner, m_victim); - if (victim) + if(Unit* victim = Unit::GetUnit(m_owner, m_victim)) { while (!m_assistants.empty()) { @@ -2003,30 +2002,38 @@ void Creature::CallAssistance(float radius) } } -bool Creature::CanAssistTo(const Unit* u, const Unit* enemy) const +bool Creature::CanAssistTo(const Unit* u, const Unit* enemy, bool checkfaction /*= true*/) const { // is it true? if(!HasReactState(REACT_AGGRESSIVE)) return false; // we don't need help from zombies :) - if( !isAlive() ) + if (!isAlive()) return false; // skip fighting creature - if( isInCombat() ) - return false; - - // only from same creature faction - if(getFaction() != u->getFaction() ) + if (isInCombat()) return false; // only free creature - if( GetCharmerOrOwnerGUID() ) + if (GetCharmerOrOwnerGUID()) return false; + // only from same creature faction + if (checkfaction) + { + if (getFaction() != u->getFaction()) + return false; + } + else + { + if (!IsFriendlyTo(u)) + return false; + } + // skip non hostile to caster enemy creatures - if( !IsHostileTo(enemy) ) + if (!IsHostileTo(enemy)) return false; return true; diff --git a/src/game/Creature.h b/src/game/Creature.h index 504261c3e1e..e89af04126c 100644 --- a/src/game/Creature.h +++ b/src/game/Creature.h @@ -636,8 +636,8 @@ class TRINITY_DLL_SPEC Creature : public Unit Unit* SelectNearestTarget(float dist = 0) const; void CallAssistance(float radius = 0); void SetNoCallAssistance(bool val) { m_AlreadyCallAssistance = val; } - bool CanAssistTo(const Unit* u, const Unit* enemy) const; void DoFleeToGetAssistance(float radius = 50); + bool CanAssistTo(const Unit* u, const Unit* enemy, bool checkfaction = true) const; MovementGeneratorType GetDefaultMovementType() const { return m_defaultMovementType; } void SetDefaultMovementType(MovementGeneratorType mgt) { m_defaultMovementType = mgt; } diff --git a/src/game/CreatureEventAI.cpp b/src/game/CreatureEventAI.cpp index 0026658f319..7625ce0b74f 100644 --- a/src/game/CreatureEventAI.cpp +++ b/src/game/CreatureEventAI.cpp @@ -32,6 +32,40 @@ #include "WorldPacket.h" #include "InstanceData.h" +namespace MaNGOS +{ + class CallOfHelpCreatureInRangeDo // do attack at call of help to friendly crearture + { + public: + CallOfHelpCreatureInRangeDo(Unit* funit, Unit* enemy, float range) + : i_funit(funit), i_enemy(enemy), i_range(range) + {} + void operator()(Creature* u) + { + if (u == i_funit) + return; + + if (!u->CanAssistTo(i_funit, i_enemy, false)) + return; + + // too far + if( !i_funit->IsWithinDistInMap(u, i_range) ) + return; + + // only if see assisted creature + if( !i_funit->IsWithinLOSInMap(u) ) + return; + + if(u->AI()) + u->AI()->AttackStart(i_enemy); + } + private: + Unit* const i_funit; + Unit* const i_enemy; + float i_range; + }; +} + bool CreatureEventAIHolder::UpdateRepeatTimer( Creature* creature, uint32 repeatMin, uint32 repeatMax ) { if (repeatMin == repeatMax) @@ -697,7 +731,6 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32 break; } case ACTION_T_UPDATE_TEMPLATE: - { if (m_creature->GetEntry() == action.update_template.creatureId) { @@ -706,10 +739,8 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32 } m_creature->UpdateEntry(action.update_template.creatureId, action.update_template.team ? HORDE : ALLIANCE); - } - break; + break; case ACTION_T_DIE: - { if (m_creature->isDead()) { @@ -717,10 +748,8 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32 return; } m_creature->DealDamage(m_creature, m_creature->GetMaxHealth(),NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - } - break; + break; case ACTION_T_ZONE_COMBAT_PULSE: - { if (!m_creature->isInCombat() || !m_creature->GetMap()->IsDungeon()) { @@ -729,6 +758,25 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32 } DoZoneInCombat(m_creature); + break; + case ACTION_T_CALL_FOR_HELP: + { + if (!m_creature->getVictim()) + return; + + CellPair p(MaNGOS::ComputeCellPair(m_creature->GetPositionX(), m_creature->GetPositionY())); + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + + MaNGOS::CallOfHelpCreatureInRangeDo u_do(m_creature, m_creature->getVictim(), action.call_for_help.radius); + MaNGOS::CreatureWorker<MaNGOS::CallOfHelpCreatureInRangeDo> worker(m_creature, u_do); + + TypeContainerVisitor<MaNGOS::CreatureWorker<MaNGOS::CallOfHelpCreatureInRangeDo>, GridTypeMapContainer > grid_creature_searcher(worker); + + CellLock<GridReadGuard> cell_lock(cell, p); + cell_lock->Visit(cell_lock, grid_creature_searcher, *m_creature->GetMap()); + break; } break; @@ -755,10 +803,6 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32 } break; } - case ACTION_T_CALL_ASSISTANCE: - m_creature->SetNoCallAssistance(false); - m_creature->CallAssistance(action.raw.param1); - break; } } diff --git a/src/game/CreatureEventAI.h b/src/game/CreatureEventAI.h index 8baa551ec6a..3434a9cb55e 100644 --- a/src/game/CreatureEventAI.h +++ b/src/game/CreatureEventAI.h @@ -63,51 +63,51 @@ enum EventAI_Type enum EventAI_ActionType { - ACTION_T_NONE = 0, //*No action - ACTION_T_TEXT = 1, //*-TextId1, optionally -TextId2, optionally -TextId3(if -TextId2 exist). If more than just -TextId1 is defined, randomize. Negative values. - ACTION_T_SET_FACTION = 2, //*FactionId (or 0 for default) - ACTION_T_MORPH_TO_ENTRY_OR_MODEL = 3, //*Creature_template entry(param1) OR ModelId (param2) (or 0 for both to demorph) - ACTION_T_SOUND = 4, //*SoundId - ACTION_T_EMOTE = 5, //*EmoteId - ACTION_T_RANDOM_SAY = 6, //*UNUSED - ACTION_T_RANDOM_YELL = 7, //*UNUSED - ACTION_T_RANDOM_TEXTEMOTE = 8, //*UNUSED - ACTION_T_RANDOM_SOUND = 9, //SoundId1, SoundId2, SoundId3 (-1 in any field means no output if randomed that field) - ACTION_T_RANDOM_EMOTE = 10, //*EmoteId1, EmoteId2, EmoteId3 (-1 in any field means no output if randomed that field) - ACTION_T_CAST = 11, //*SpellId, Target, CastFlags - ACTION_T_SUMMON = 12, //*CreatureID, Target, Duration in ms - ACTION_T_THREAT_SINGLE_PCT = 13, //*Threat%, Target - ACTION_T_THREAT_ALL_PCT = 14, //Threat% - ACTION_T_QUEST_EVENT = 15, //*QuestID, Target - ACTION_T_CAST_EVENT = 16, //*QuestID, SpellId, Target - must be removed as hack? - ACTION_T_SET_UNIT_FIELD = 17, //*Field_Number, Value, Target - ACTION_T_SET_UNIT_FLAG = 18, //*Flags (may be more than one field OR'd together), Target - ACTION_T_REMOVE_UNIT_FLAG = 19, //*Flags (may be more than one field OR'd together), Target - ACTION_T_AUTO_ATTACK = 20, //AllowAttackState (0 = stop attack, anything else means continue attacking) - ACTION_T_COMBAT_MOVEMENT = 21, //AllowCombatMovement (0 = stop combat based movement, anything else continue attacking) - ACTION_T_SET_PHASE = 22, //*Phase - ACTION_T_INC_PHASE = 23, //*Value (may be negative to decrement phase, should not be 0) - ACTION_T_EVADE = 24, //No Params - ACTION_T_FLEE = 25, //No Params - ACTION_T_QUEST_EVENT_ALL = 26, //*QuestID - ACTION_T_CAST_EVENT_ALL = 27, //*QuestId, SpellId - ACTION_T_REMOVEAURASFROMSPELL = 28, //*Target, Spellid - ACTION_T_RANGED_MOVEMENT = 29, //Distance, Angle - ACTION_T_RANDOM_PHASE = 30, //PhaseId1, PhaseId2, PhaseId3 - ACTION_T_RANDOM_PHASE_RANGE = 31, //PhaseMin, PhaseMax - ACTION_T_SUMMON_ID = 32, //*CreatureId, Target, SpawnId - ACTION_T_KILLED_MONSTER = 33, //*CreatureId, Target - ACTION_T_SET_INST_DATA = 34, //*Field, Data - ACTION_T_SET_INST_DATA64 = 35, //*Field, Target - ACTION_T_UPDATE_TEMPLATE = 36, //*Entry, Team - ACTION_T_DIE = 37, //No Params - ACTION_T_ZONE_COMBAT_PULSE = 38, //No Params + ACTION_T_NONE = 0, // No action + ACTION_T_TEXT = 1, // TextId1, optionally -TextId2, optionally -TextId3(if -TextId2 exist). If more than just -TextId1 is defined, randomize. Negative values. + ACTION_T_SET_FACTION = 2, // FactionId (or 0 for default) + ACTION_T_MORPH_TO_ENTRY_OR_MODEL = 3, // Creature_template entry(param1) OR ModelId (param2) (or 0 for both to demorph) + ACTION_T_SOUND = 4, // SoundId + ACTION_T_EMOTE = 5, // EmoteId + ACTION_T_RANDOM_SAY = 6, // UNUSED + ACTION_T_RANDOM_YELL = 7, // UNUSED + ACTION_T_RANDOM_TEXTEMOTE = 8, // UNUSED + ACTION_T_RANDOM_SOUND = 9, // SoundId1, SoundId2, SoundId3 (-1 in any field means no output if randomed that field) + ACTION_T_RANDOM_EMOTE = 10, // EmoteId1, EmoteId2, EmoteId3 (-1 in any field means no output if randomed that field) + ACTION_T_CAST = 11, // SpellId, Target, CastFlags + ACTION_T_SUMMON = 12, // CreatureID, Target, Duration in ms + ACTION_T_THREAT_SINGLE_PCT = 13, // Threat%, Target + ACTION_T_THREAT_ALL_PCT = 14, // Threat% + ACTION_T_QUEST_EVENT = 15, // QuestID, Target + ACTION_T_CAST_EVENT = 16, // QuestID, SpellId, Target - must be removed as hack? + ACTION_T_SET_UNIT_FIELD = 17, // Field_Number, Value, Target + ACTION_T_SET_UNIT_FLAG = 18, // Flags (may be more than one field OR'd together), Target + ACTION_T_REMOVE_UNIT_FLAG = 19, // Flags (may be more than one field OR'd together), Target + ACTION_T_AUTO_ATTACK = 20, // AllowAttackState (0 = stop attack, anything else means continue attacking) + ACTION_T_COMBAT_MOVEMENT = 21, // AllowCombatMovement (0 = stop combat based movement, anything else continue attacking) + ACTION_T_SET_PHASE = 22, // Phase + ACTION_T_INC_PHASE = 23, // Value (may be negative to decrement phase, should not be 0) + ACTION_T_EVADE = 24, // No Params + ACTION_T_FLEE = 25, // No Params + ACTION_T_QUEST_EVENT_ALL = 26, // QuestID + ACTION_T_CAST_EVENT_ALL = 27, // CreatureId, SpellId + ACTION_T_REMOVEAURASFROMSPELL = 28, // Target, Spellid + ACTION_T_RANGED_MOVEMENT = 29, // Distance, Angle + ACTION_T_RANDOM_PHASE = 30, // PhaseId1, PhaseId2, PhaseId3 + ACTION_T_RANDOM_PHASE_RANGE = 31, // PhaseMin, PhaseMax + ACTION_T_SUMMON_ID = 32, // CreatureId, Target, SpawnId + ACTION_T_KILLED_MONSTER = 33, // CreatureId, Target + ACTION_T_SET_INST_DATA = 34, // Field, Data + ACTION_T_SET_INST_DATA64 = 35, // Field, Target + ACTION_T_UPDATE_TEMPLATE = 36, // Entry, Team + ACTION_T_DIE = 37, // No Params + ACTION_T_ZONE_COMBAT_PULSE = 38, // No Params + ACTION_T_CALL_FOR_HELP = 39, // Radius ACTION_T_SET_ACTIVE = 101, //Apply ACTION_T_SET_AGGRESSIVE = 102, //Apply ACTION_T_ATTACK_START_PULSE = 103, //Distance ACTION_T_SUMMON_GO = 104, //GameObjectID, DespawnTime in ms - ACTION_T_CALL_ASSISTANCE = 105, //Radius ACTION_T_END, }; @@ -352,12 +352,17 @@ struct CreatureEventAI_Action uint32 field; uint32 target; } set_inst_data64; - // ACTION_T_UPDATE_TEMPLATE = 36, //*Entry, Team + // ACTION_T_UPDATE_TEMPLATE = 36 struct { uint32 creatureId; uint32 team; } update_template; + // ACTION_T_CALL_FOR_HELP = 39 + struct + { + uint32 radius; + } call_for_help; // RAW struct { diff --git a/src/game/CreatureEventAIMgr.cpp b/src/game/CreatureEventAIMgr.cpp index a5f7395d68d..9bd262a5f9f 100644 --- a/src/game/CreatureEventAIMgr.cpp +++ b/src/game/CreatureEventAIMgr.cpp @@ -632,6 +632,7 @@ void CreatureEventAIMgr::LoadCreatureEventAI_Scripts() case ACTION_T_AUTO_ATTACK: //AllowAttackState (0 = stop attack, anything else means continue attacking) case ACTION_T_COMBAT_MOVEMENT: //AllowCombatMovement (0 = stop combat based movement, anything else continue attacking) case ACTION_T_RANGED_MOVEMENT: //Distance, Angle + case ACTION_T_CALL_FOR_HELP: //Distance break; case ACTION_T_RANDOM_SAY: @@ -644,7 +645,6 @@ void CreatureEventAIMgr::LoadCreatureEventAI_Scripts() case ACTION_T_SET_AGGRESSIVE: case ACTION_T_ATTACK_START_PULSE: case ACTION_T_SUMMON_GO: - case ACTION_T_CALL_ASSISTANCE: break; default: diff --git a/src/game/GridNotifiers.h b/src/game/GridNotifiers.h index b45f7f6d675..2295f72e4c9 100644 --- a/src/game/GridNotifiers.h +++ b/src/game/GridNotifiers.h @@ -440,6 +440,25 @@ namespace Trinity template<class NOT_INTERESTED> void Visit(GridRefManager<NOT_INTERESTED> &) {} }; + template<class Do> + struct MANGOS_DLL_DECL CreatureWorker + { + uint32 i_phaseMask; + Do& i_do; + + CreatureWorker(WorldObject const* searcher, Do& _do) + : i_phaseMask(searcher->GetPhaseMask()), i_do(_do) {} + + void Visit(CreatureMapType &m) + { + for(CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + if(itr->getSource()->InSamePhase(i_phaseMask)) + i_do(itr->getSource()); + } + + template<class NOT_INTERESTED> void Visit(GridRefManager<NOT_INTERESTED> &) {} + }; + // Player searchers template<class Check> |