[7860] Implement creature event ai ACTION_T_CALL_FOR_HELP for explicit call for help in some script cases.

This commit is contained in:
VladimirMangos 2009-05-20 21:53:53 +04:00
parent 159258b668
commit f332c000d1
8 changed files with 142 additions and 61 deletions

View file

@ -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 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 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. 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) * = 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)

View file

@ -85,8 +85,7 @@ VendorItem const* VendorItemData::FindItem(uint32 item_id) const
bool AssistDelayEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/) bool AssistDelayEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
{ {
Unit* victim = Unit::GetUnit(m_owner, m_victim); if(Unit* victim = Unit::GetUnit(m_owner, m_victim))
if (victim)
{ {
while (!m_assistants.empty()) while (!m_assistants.empty())
{ {
@ -1725,26 +1724,34 @@ void Creature::CallAssistance()
} }
} }
bool Creature::CanAssistTo(const Unit* u, const Unit* enemy) const bool Creature::CanAssistTo(const Unit* u, const Unit* enemy, bool checkfaction /*= true*/) const
{ {
// we don't need help from zombies :) // we don't need help from zombies :)
if( !isAlive() ) if (!isAlive())
return false; return false;
// skip fighting creature // skip fighting creature
if( isInCombat() ) if (isInCombat())
return false;
// only from same creature faction
if(getFaction() != u->getFaction() )
return false; return false;
// only free creature // only free creature
if( GetCharmerOrOwnerGUID() ) if (GetCharmerOrOwnerGUID())
return false; 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 // skip non hostile to caster enemy creatures
if( !IsHostileTo(enemy) ) if (!IsHostileTo(enemy))
return false; return false;
return true; return true;

View file

@ -603,7 +603,7 @@ class MANGOS_DLL_SPEC Creature : public Unit
void CallAssistance(); void CallAssistance();
void SetNoCallAssistance(bool val) { m_AlreadyCallAssistance = val; } void SetNoCallAssistance(bool val) { m_AlreadyCallAssistance = val; }
bool CanAssistTo(const Unit* u, const Unit* enemy) const; bool CanAssistTo(const Unit* u, const Unit* enemy, bool checkfaction = true) const;
MovementGeneratorType GetDefaultMovementType() const { return m_defaultMovementType; } MovementGeneratorType GetDefaultMovementType() const { return m_defaultMovementType; }
void SetDefaultMovementType(MovementGeneratorType mgt) { m_defaultMovementType = mgt; } void SetDefaultMovementType(MovementGeneratorType mgt) { m_defaultMovementType = mgt; }

View file

@ -30,6 +30,40 @@
#include "WorldPacket.h" #include "WorldPacket.h"
#include "InstanceData.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 ) bool CreatureEventAIHolder::UpdateRepeatTimer( Creature* creature, uint32 repeatMin, uint32 repeatMax )
{ {
if (repeatMin == repeatMax) if (repeatMin == repeatMax)
@ -705,7 +739,6 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32
break; break;
} }
case ACTION_T_UPDATE_TEMPLATE: case ACTION_T_UPDATE_TEMPLATE:
{
if (m_creature->GetEntry() == action.update_template.creatureId) if (m_creature->GetEntry() == action.update_template.creatureId)
{ {
@ -714,10 +747,8 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32
} }
m_creature->UpdateEntry(action.update_template.creatureId, action.update_template.team ? HORDE : ALLIANCE); m_creature->UpdateEntry(action.update_template.creatureId, action.update_template.team ? HORDE : ALLIANCE);
} break;
break;
case ACTION_T_DIE: case ACTION_T_DIE:
{
if (m_creature->isDead()) if (m_creature->isDead())
{ {
@ -725,10 +756,8 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32
return; return;
} }
m_creature->DealDamage(m_creature, m_creature->GetMaxHealth(),NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); 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: case ACTION_T_ZONE_COMBAT_PULSE:
{
if (!m_creature->isInCombat() || !m_creature->GetMap()->IsDungeon()) if (!m_creature->isInCombat() || !m_creature->GetMap()->IsDungeon())
{ {
@ -737,8 +766,26 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32
} }
DoZoneInCombat(m_creature); 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;
} }
} }

View file

@ -63,45 +63,46 @@ enum EventAI_Type
enum EventAI_ActionType enum EventAI_ActionType
{ {
ACTION_T_NONE = 0, //*No action 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_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_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_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_SOUND = 4, // SoundId
ACTION_T_EMOTE = 5, //*EmoteId ACTION_T_EMOTE = 5, // EmoteId
ACTION_T_RANDOM_SAY = 6, //*UNUSED ACTION_T_RANDOM_SAY = 6, // UNUSED
ACTION_T_RANDOM_YELL = 7, //*UNUSED ACTION_T_RANDOM_YELL = 7, // UNUSED
ACTION_T_RANDOM_TEXTEMOTE = 8, //*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_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_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_CAST = 11, // SpellId, Target, CastFlags
ACTION_T_SUMMON = 12, //*CreatureID, Target, Duration in ms ACTION_T_SUMMON = 12, // CreatureID, Target, Duration in ms
ACTION_T_THREAT_SINGLE_PCT = 13, //*Threat%, Target ACTION_T_THREAT_SINGLE_PCT = 13, // Threat%, Target
ACTION_T_THREAT_ALL_PCT = 14, //Threat% ACTION_T_THREAT_ALL_PCT = 14, // Threat%
ACTION_T_QUEST_EVENT = 15, //*QuestID, Target ACTION_T_QUEST_EVENT = 15, // QuestID, Target
ACTION_T_CAST_EVENT = 16, //*QuestID, SpellId, Target - must be removed as hack? 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_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_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_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_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_COMBAT_MOVEMENT = 21, // AllowCombatMovement (0 = stop combat based movement, anything else continue attacking)
ACTION_T_SET_PHASE = 22, //*Phase ACTION_T_SET_PHASE = 22, // Phase
ACTION_T_INC_PHASE = 23, //*Value (may be negative to decrement phase, should not be 0) ACTION_T_INC_PHASE = 23, // Value (may be negative to decrement phase, should not be 0)
ACTION_T_EVADE = 24, //No Params ACTION_T_EVADE = 24, // No Params
ACTION_T_FLEE = 25, //No Params ACTION_T_FLEE = 25, // No Params
ACTION_T_QUEST_EVENT_ALL = 26, //*QuestID ACTION_T_QUEST_EVENT_ALL = 26, // QuestID
ACTION_T_CAST_EVENT_ALL = 27, //*QuestId, SpellId ACTION_T_CAST_EVENT_ALL = 27, // CreatureId, SpellId
ACTION_T_REMOVEAURASFROMSPELL = 28, //*Target, Spellid ACTION_T_REMOVEAURASFROMSPELL = 28, // Target, Spellid
ACTION_T_RANGED_MOVEMENT = 29, //Distance, Angle ACTION_T_RANGED_MOVEMENT = 29, // Distance, Angle
ACTION_T_RANDOM_PHASE = 30, //PhaseId1, PhaseId2, PhaseId3 ACTION_T_RANDOM_PHASE = 30, // PhaseId1, PhaseId2, PhaseId3
ACTION_T_RANDOM_PHASE_RANGE = 31, //PhaseMin, PhaseMax ACTION_T_RANDOM_PHASE_RANGE = 31, // PhaseMin, PhaseMax
ACTION_T_SUMMON_ID = 32, //*CreatureId, Target, SpawnId ACTION_T_SUMMON_ID = 32, // CreatureId, Target, SpawnId
ACTION_T_KILLED_MONSTER = 33, //*CreatureId, Target ACTION_T_KILLED_MONSTER = 33, // CreatureId, Target
ACTION_T_SET_INST_DATA = 34, //*Field, Data ACTION_T_SET_INST_DATA = 34, // Field, Data
ACTION_T_SET_INST_DATA64 = 35, //*Field, Target ACTION_T_SET_INST_DATA64 = 35, // Field, Target
ACTION_T_UPDATE_TEMPLATE = 36, //*Entry, Team ACTION_T_UPDATE_TEMPLATE = 36, // Entry, Team
ACTION_T_DIE = 37, //No Params ACTION_T_DIE = 37, // No Params
ACTION_T_ZONE_COMBAT_PULSE = 38, //No Params ACTION_T_ZONE_COMBAT_PULSE = 38, // No Params
ACTION_T_CALL_FOR_HELP = 39, // Radius
ACTION_T_END, ACTION_T_END,
}; };
@ -346,12 +347,17 @@ struct CreatureEventAI_Action
uint32 field; uint32 field;
uint32 target; uint32 target;
} set_inst_data64; } set_inst_data64;
// ACTION_T_UPDATE_TEMPLATE = 36, //*Entry, Team // ACTION_T_UPDATE_TEMPLATE = 36
struct struct
{ {
uint32 creatureId; uint32 creatureId;
uint32 team; uint32 team;
} update_template; } update_template;
// ACTION_T_CALL_FOR_HELP = 39
struct
{
uint32 radius;
} call_for_help;
// RAW // RAW
struct struct
{ {

View file

@ -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_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_COMBAT_MOVEMENT: //AllowCombatMovement (0 = stop combat based movement, anything else continue attacking)
case ACTION_T_RANGED_MOVEMENT: //Distance, Angle case ACTION_T_RANGED_MOVEMENT: //Distance, Angle
case ACTION_T_CALL_FOR_HELP: //Distance
break; break;
case ACTION_T_RANDOM_SAY: case ACTION_T_RANDOM_SAY:

View file

@ -445,6 +445,25 @@ namespace MaNGOS
template<class NOT_INTERESTED> void Visit(GridRefManager<NOT_INTERESTED> &) {} 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 // Player searchers
template<class Check> template<class Check>

View file

@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__ #ifndef __REVISION_NR_H__
#define __REVISION_NR_H__ #define __REVISION_NR_H__
#define REVISION_NR "7859" #define REVISION_NR "7860"
#endif // __REVISION_NR_H__ #endif // __REVISION_NR_H__