mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-16 07:30:42 +01:00
Core/AI: implemented SmartScripts System (still beta) not 100% complete
WARNING: Use scripts at own risk. You were warned. NOTE0: creature, gameobject, areatrigger type scripts should be fully functional NOTE1: has no effect on any core related stuff if not using any SmartScript NOTE2: all event/action/etc descriptions can be found in SmartScriptMgr.h SmartScripts is a reloadable DB-Sript system, with full control for special scripting, like escorting, following, complex combat handling, pre-stored AI templates(caster, turret, etc) and much more with a total of 66 events, 78 actions, 22 target types, and can be easily extended --HG-- branch : trunk
This commit is contained in:
32
sql/updates/10320_world_smart_scripts.sql
Normal file
32
sql/updates/10320_world_smart_scripts.sql
Normal file
@@ -0,0 +1,32 @@
|
||||
DROP TABLE IF EXISTS smart_scripts;
|
||||
CREATE TABLE `smart_scripts` (
|
||||
`entryorguid` mediumint(11) NOT NULL,
|
||||
`source_type` mediumint(5) unsigned NOT NULL DEFAULT '0',
|
||||
`id` mediumint(11) unsigned NOT NULL DEFAULT '0',
|
||||
`link` mediumint(11) unsigned NOT NULL DEFAULT '0',
|
||||
`event_type` mediumint(5) unsigned NOT NULL DEFAULT '0',
|
||||
`event_phase_mask` mediumint(11) unsigned NOT NULL DEFAULT '0',
|
||||
`event_chance` mediumint(5) unsigned NOT NULL DEFAULT '100',
|
||||
`event_flags` mediumint(11) unsigned NOT NULL DEFAULT '0',
|
||||
`event_param1` mediumint(11) unsigned NOT NULL DEFAULT '0',
|
||||
`event_param2` mediumint(11) unsigned NOT NULL DEFAULT '0',
|
||||
`event_param3` mediumint(11) unsigned NOT NULL DEFAULT '0',
|
||||
`event_param4` mediumint(11) unsigned NOT NULL DEFAULT '0',
|
||||
`action_type` mediumint(5) unsigned NOT NULL DEFAULT '0',
|
||||
`action_param1` mediumint(11) unsigned NOT NULL DEFAULT '0',
|
||||
`action_param2` mediumint(11) unsigned NOT NULL DEFAULT '0',
|
||||
`action_param3` mediumint(11) unsigned NOT NULL DEFAULT '0',
|
||||
`action_param4` mediumint(11) unsigned NOT NULL DEFAULT '0',
|
||||
`action_param5` mediumint(11) unsigned NOT NULL DEFAULT '0',
|
||||
`action_param6` mediumint(11) unsigned NOT NULL DEFAULT '0',
|
||||
`target_type` mediumint(11) unsigned NOT NULL DEFAULT '0',
|
||||
`target_param1` mediumint(11) unsigned NOT NULL DEFAULT '0',
|
||||
`target_param2` mediumint(11) unsigned NOT NULL DEFAULT '0',
|
||||
`target_param3` mediumint(11) unsigned NOT NULL DEFAULT '0',
|
||||
`target_x` float NOT NULL DEFAULT '0',
|
||||
`target_y` float NOT NULL DEFAULT '0',
|
||||
`target_z` float NOT NULL DEFAULT '0',
|
||||
`target_o` float NOT NULL DEFAULT '0',
|
||||
`comment` varchar(255) NOT NULL DEFAULT '' COMMENT 'Event Comment',
|
||||
PRIMARY KEY (`entryorguid`,`source_type`,`id`,`link`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED;
|
||||
10
sql/updates/10320_world_waypoints.sql
Normal file
10
sql/updates/10320_world_waypoints.sql
Normal file
@@ -0,0 +1,10 @@
|
||||
DROP TABLE IF EXISTS waypoints;
|
||||
CREATE TABLE `waypoints` (
|
||||
`entry` mediumint(8) unsigned NOT NULL DEFAULT '0',
|
||||
`pointid` mediumint(8) unsigned NOT NULL DEFAULT '0',
|
||||
`position_x` float NOT NULL DEFAULT '0',
|
||||
`position_y` float NOT NULL DEFAULT '0',
|
||||
`position_z` float NOT NULL DEFAULT '0',
|
||||
`point_comment` text,
|
||||
PRIMARY KEY (`entry`,`pointid`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Creature waypoints';
|
||||
@@ -40,6 +40,15 @@ class GameObjectAI
|
||||
virtual void Reset() {};
|
||||
|
||||
static int Permissible(const GameObject* go);
|
||||
|
||||
virtual bool GossipHello(Player* player) {return false;}
|
||||
virtual bool GossipSelect(Player* player, uint32 sender, uint32 action) {return false;}
|
||||
virtual bool GossipSelectCode(Player* /*player*/, uint32 /*sender*/, uint32 /*action*/, const char* /*code*/) {return false;}
|
||||
virtual bool QuestAccept(Player* player, Quest const* quest) {return false;}
|
||||
virtual bool QuestReward(Player* player, Quest const* quest, uint32 opt) {return false;}
|
||||
uint32 GetDialogStatus(Player* /*player*/) {return 100;}
|
||||
virtual void Destroyed(Player* player, uint32 eventId) {}
|
||||
virtual void SetData(uint32 id, uint32 value) {}
|
||||
};
|
||||
|
||||
class NullGameObjectAI : public GameObjectAI
|
||||
|
||||
@@ -53,6 +53,7 @@ namespace AIRegistry
|
||||
(new CreatureAIFactory<SmartAI>("SmartAI"))->RegisterSelf();
|
||||
|
||||
(new GameObjectAIFactory<GameObjectAI>("GameObjectAI"))->RegisterSelf();
|
||||
(new GameObjectAIFactory<SmartGameObjectAI>("SmartGameObjectAI"))->RegisterSelf();
|
||||
|
||||
(new MovementGeneratorFactory<RandomMovementGenerator<Creature> >(RANDOM_MOTION_TYPE))->RegisterSelf();
|
||||
(new MovementGeneratorFactory<WaypointMovementGenerator<Creature> >(WAYPOINT_MOTION_TYPE))->RegisterSelf();
|
||||
|
||||
@@ -1,190 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2010 TrinityCore <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Common.h"
|
||||
#include "DatabaseEnv.h"
|
||||
#include "SQLStorage.h"
|
||||
#include "SmartAI.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "ProgressBar.h"
|
||||
#include "ObjectDefines.h"
|
||||
#include "GridDefines.h"
|
||||
#include "ConditionMgr.h"
|
||||
#include "CreatureTextMgr.h"
|
||||
|
||||
void SmartAIMgr::LoadSmartAIFromDB()
|
||||
{
|
||||
//Drop Existing SmartAI List
|
||||
}
|
||||
|
||||
SmartAI::SmartAI(Creature *c) : CreatureAI(c)
|
||||
{
|
||||
// copy script to local (pretection for table reload)
|
||||
}
|
||||
|
||||
int SmartAI::Permissible(const Creature* creature)
|
||||
{
|
||||
if (creature->GetAIName() == "SmartAI")
|
||||
return PERMIT_BASE_SPECIAL;
|
||||
return PERMIT_BASE_NO;
|
||||
}
|
||||
|
||||
void SmartAI::UpdateAI(const uint32 /*diff*/)
|
||||
{
|
||||
}
|
||||
|
||||
void SmartAI::JustRespawned()
|
||||
{
|
||||
}
|
||||
|
||||
void SmartAI::Reset()
|
||||
{
|
||||
}
|
||||
|
||||
void SmartAI::JustReachedHome()
|
||||
{
|
||||
}
|
||||
|
||||
void SmartAI::EnterCombat(Unit* /*enemy*/)
|
||||
{
|
||||
}
|
||||
|
||||
void SmartAI::EnterEvadeMode()
|
||||
{
|
||||
}
|
||||
|
||||
void SmartAI::JustDied(Unit* /*killer*/)
|
||||
{
|
||||
}
|
||||
|
||||
void SmartAI::KilledUnit(Unit* /*victim*/)
|
||||
{
|
||||
}
|
||||
|
||||
void SmartAI::JustSummoned(Creature* /*pUnit*/)
|
||||
{
|
||||
}
|
||||
|
||||
void SmartAI::AttackStart(Unit* who)
|
||||
{
|
||||
if (who && me->Attack(who, true))
|
||||
me->GetMotionMaster()->MoveChase(who);
|
||||
}
|
||||
|
||||
void SmartAI::MoveInLineOfSight(Unit* /*who*/)
|
||||
{
|
||||
//CanAIAttack
|
||||
}
|
||||
|
||||
void SmartAI::SpellHit(Unit* /*pUnit*/, const SpellEntry* /*pSpell*/)
|
||||
{
|
||||
}
|
||||
|
||||
void SmartAI::SpellHitTarget(Unit* /*target*/, const SpellEntry* /*pSpell*/)
|
||||
{
|
||||
}
|
||||
|
||||
void SmartAI::DamageTaken(Unit* /*done_by*/, uint32& /*damage*/, DamageEffectType /*damagetype*/)
|
||||
{
|
||||
}
|
||||
|
||||
void SmartAI::HealReceived(Unit* /*done_by*/, uint32& /*addhealth*/)
|
||||
{
|
||||
}
|
||||
|
||||
void SmartAI::ReceiveEmote(Player* /*pPlayer*/, uint32 /*text_emote*/)
|
||||
{
|
||||
}
|
||||
|
||||
void SmartAI::MovementInform(uint32 /*MovementType*/, uint32 /*Data*/)
|
||||
{
|
||||
}
|
||||
|
||||
void SmartAI::IsSummonedBy(Unit* /*summoner*/)
|
||||
{
|
||||
}
|
||||
|
||||
void SmartAI::DamageDealt(Unit* /*done_to*/, uint32& /*damage*/)
|
||||
{
|
||||
}
|
||||
|
||||
void SmartAI::SummonedCreatureDespawn(Creature* /*unit*/)
|
||||
{
|
||||
}
|
||||
|
||||
void SmartAI::UpdateAIWhileCharmed(const uint32 /*diff*/)
|
||||
{
|
||||
}
|
||||
|
||||
void SmartAI::CorpseRemoved(uint32& /*respawnDelay*/)
|
||||
{
|
||||
}
|
||||
|
||||
void SmartAI::PassengerBoarded(Unit* /*who*/, int8 /*seatId*/, bool /*apply*/)
|
||||
{
|
||||
}
|
||||
|
||||
void SmartAI::InitializeAI()
|
||||
{
|
||||
}
|
||||
|
||||
void SmartAI::OnCharmed(bool /*apply*/)
|
||||
{
|
||||
}
|
||||
|
||||
bool SmartAI::CanAIAttack(const Unit* /*who*/) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void SmartAI::DoAction(const int32 /*param*/)
|
||||
{
|
||||
}
|
||||
|
||||
uint32 SmartAI::GetData(uint32 /*id*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SmartAI::SetData(uint32 /*id*/, uint32 /*value*/)
|
||||
{
|
||||
}
|
||||
|
||||
void SmartAI::SetGUID(const uint64& /*guid*/, int32 /*id*/)
|
||||
{
|
||||
}
|
||||
|
||||
uint64 SmartAI::GetGUID(int32 /*id*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SmartAI::MovepointReached(uint32 /*id*/)
|
||||
{
|
||||
}
|
||||
|
||||
void SmartAI::MovepointStart(uint32 /*id*/)
|
||||
{
|
||||
}
|
||||
|
||||
void SmartAI::SetRun(bool /*run*/)
|
||||
{
|
||||
}
|
||||
|
||||
void SmartAI::SetMovePathEndAction(SMARTAI_ACTION /*action*/)
|
||||
{
|
||||
}
|
||||
@@ -1,367 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2010 TrinityCore <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TRINITY_SMARTAI_H
|
||||
#define TRINITY_SMARTAI_H
|
||||
|
||||
#include "Common.h"
|
||||
#include "Creature.h"
|
||||
#include "CreatureAI.h"
|
||||
#include "Unit.h"
|
||||
|
||||
/*
|
||||
N O T E S
|
||||
|
||||
|
||||
movepoints:
|
||||
create ingame commands
|
||||
|
||||
commands:
|
||||
smartai
|
||||
smartai movepoints
|
||||
smartai movepoints start (id)
|
||||
smartai movepoints add
|
||||
smartai movepoints end
|
||||
smartai movepoints show (id)
|
||||
smartai reload
|
||||
smartai create [reload creature]
|
||||
|
||||
|
||||
void passenger removed
|
||||
void setcanrun
|
||||
void setcanfly
|
||||
void setcanswim
|
||||
void setinhabittype
|
||||
|
||||
event change flags
|
||||
|
||||
need a local SendChat()
|
||||
|
||||
*/
|
||||
|
||||
//temp copied from eai, will be modded
|
||||
enum SMARTAI_EVENT
|
||||
{
|
||||
SMART_EVENT_TIMER_IC = 0, // InitialMin, InitialMax, RepeatMin, RepeatMax
|
||||
SMART_EVENT_TIMER_OOC = 1, // InitialMin, InitialMax, RepeatMin, RepeatMax
|
||||
SMART_EVENT_HP = 2, // HPMax%, HPMin%, RepeatMin, RepeatMax
|
||||
SMART_EVENT_MANA = 3, // ManaMax%,ManaMin% RepeatMin, RepeatMax
|
||||
SMART_EVENT_AGGRO = 4, // NONE
|
||||
SMART_EVENT_KILL = 5, // RepeatMin, RepeatMax
|
||||
SMART_EVENT_DEATH = 6, // NONE
|
||||
SMART_EVENT_EVADE = 7, // NONE
|
||||
SMART_EVENT_SPELLHIT = 8, // SpellID, School, RepeatMin, RepeatMax
|
||||
SMART_EVENT_RANGE = 9, // MinDist, MaxDist, RepeatMin, RepeatMax
|
||||
SMART_EVENT_OOC_LOS = 10, // NoHostile, MaxRnage, RepeatMin, RepeatMax
|
||||
SMART_EVENT_SPAWNED = 11, // Condition, CondValue1
|
||||
SMART_EVENT_TARGET_HP = 12, // HPMax%, HPMin%, RepeatMin, RepeatMax
|
||||
SMART_EVENT_TARGET_CASTING = 13, // RepeatMin, RepeatMax
|
||||
SMART_EVENT_FRIENDLY_HP = 14, // HPDeficit, Radius, RepeatMin, RepeatMax
|
||||
SMART_EVENT_FRIENDLY_IS_CC = 15, // DispelType, Radius, RepeatMin, RepeatMax
|
||||
SMART_EVENT_FRIENDLY_MISSING_BUFF = 16, // SpellId, Radius, RepeatMin, RepeatMax
|
||||
SMART_EVENT_SUMMONED_UNIT = 17, // CreatureId, RepeatMin, RepeatMax
|
||||
SMART_EVENT_TARGET_MANA = 18, // ManaMax%, ManaMin%, RepeatMin, RepeatMax
|
||||
SMART_EVENT_QUEST_ACCEPT = 19, // QuestID
|
||||
SMART_EVENT_QUEST_COMPLETE = 20, //
|
||||
SMART_EVENT_REACHED_HOME = 21, // NONE
|
||||
SMART_EVENT_RECEIVE_EMOTE = 22, // EmoteId, Condition, CondValue1, CondValue2
|
||||
SMART_EVENT_BUFFED = 23, // Param1 = SpellID, Param2 = Number of Time STacked, Param3/4 Repeat Min/Max
|
||||
SMART_EVENT_TARGET_BUFFED = 24, // Param1 = SpellID, Param2 = Number of Time STacked, Param3/4 Repeat Min/Max
|
||||
SMART_EVENT_RESET = 35, // Is it called after combat, when the creature respawn and spawn. -- TRINITY ONLY
|
||||
|
||||
SMART_EVENT_END = 36,
|
||||
};
|
||||
|
||||
//temp copied from eai, will be modded
|
||||
enum SMARTAI_ACTION
|
||||
{
|
||||
SMART_ACTION_NONE = 0, // No action
|
||||
SMART_ACTION_TEXT = 1, // TextId1, optionally -TextId2, optionally -TextId3(if -TextId2 exist). If more than just -TextId1 is defined, randomize. Negative values.
|
||||
SMART_ACTION_SET_FACTION = 2, // FactionId (or 0 for default)
|
||||
SMART_ACTION_MORPH_TO_ENTRY_OR_MODEL = 3, // Creature_template entry(param1) OR ModelId (param2) (or 0 for both to demorph)
|
||||
SMART_ACTION_SOUND = 4, // SoundId
|
||||
SMART_ACTION_EMOTE = 5, // EmoteId
|
||||
SMART_ACTION_RANDOM_SAY = 6, // UNUSED
|
||||
SMART_ACTION_RANDOM_YELL = 7, // UNUSED
|
||||
SMART_ACTION_RANDOM_TEXTEMOTE = 8, // UNUSED
|
||||
SMART_ACTION_RANDOM_SOUND = 9, // SoundId1, SoundId2, SoundId3 (-1 in any field means no output if randomed that field)
|
||||
SMART_ACTION_RANDOM_EMOTE = 10, // EmoteId1, EmoteId2, EmoteId3 (-1 in any field means no output if randomed that field)
|
||||
SMART_ACTION_CAST = 11, // SpellId, Target, CastFlags
|
||||
SMART_ACTION_SUMMON = 12, // CreatureID, Target, Duration in ms
|
||||
SMART_ACTION_THREAT_SINGLE_PCT = 13, // Threat%, Target
|
||||
SMART_ACTION_THREAT_ALL_PCT = 14, // Threat%
|
||||
SMART_ACTION_QUEST_EVENT = 15, // QuestID, Target
|
||||
SMART_ACTION_CAST_EVENT = 16, // QuestID, SpellId, Target - must be removed as hack?
|
||||
SMART_ACTION_SET_UNIT_FIELD = 17, // Field_Number, Value, Target
|
||||
SMART_ACTION_SET_UNIT_FLAG = 18, // Flags (may be more than one field OR'd together), Target
|
||||
SMART_ACTION_REMOVE_UNIT_FLAG = 19, // Flags (may be more than one field OR'd together), Target
|
||||
SMART_ACTION_AUTO_ATTACK = 20, // AllowAttackState (0 = stop attack, anything else means continue attacking)
|
||||
SMART_ACTION_COMBAT_MOVEMENT = 21, // AllowCombatMovement (0 = stop combat based movement, anything else continue attacking)
|
||||
SMART_ACTION_SET_PHASE = 22, // Phase
|
||||
SMART_ACTION_INC_PHASE = 23, // Value (may be negative to decrement phase, should not be 0)
|
||||
SMART_ACTION_EVADE = 24, // No Params
|
||||
SMART_ACTION_FLEE_FOR_ASSIST = 25, // No Params
|
||||
SMART_ACTION_QUEST_EVENT_ALL = 26, // QuestID
|
||||
SMART_ACTION_CAST_EVENT_ALL = 27, // CreatureId, SpellId
|
||||
SMART_ACTION_REMOVEAURASFROMSPELL = 28, // Target, Spellid
|
||||
SMART_ACTION_RANGED_MOVEMENT = 29, // Distance, Angle
|
||||
SMART_ACTION_RANDOM_PHASE = 30, // PhaseId1, PhaseId2, PhaseId3
|
||||
SMART_ACTION_RANDOM_PHASE_RANGE = 31, // PhaseMin, PhaseMax
|
||||
SMART_ACTION_SUMMON_ID = 32, // CreatureId, Target, SpawnId
|
||||
SMART_ACTION_KILLED_MONSTER = 33, // CreatureId, Target
|
||||
SMART_ACTION_SET_INST_DATA = 34, // Field, Data
|
||||
SMART_ACTION_SET_INST_DATA64 = 35, // Field, Target
|
||||
SMART_ACTION_UPDATE_TEMPLATE = 36, // Entry, Team
|
||||
SMART_ACTION_DIE = 37, // No Params
|
||||
SMART_ACTION_ZONE_COMBAT_PULSE = 38, // No Params
|
||||
SMART_ACTION_CALL_FOR_HELP = 39, // Radius
|
||||
SMART_ACTION_SET_SHEATH = 40, // Sheath (0-passive,1-melee,2-ranged)
|
||||
SMART_ACTION_FORCE_DESPAWN = 41, // No Params
|
||||
SMART_ACTION_SET_INVINCIBILITY_HP_LEVEL = 42, // MinHpValue, format(0-flat,1-percent from max health)
|
||||
SMART_ACTION_MOUNT_TO_ENTRY_OR_MODEL = 43, // Creature_template entry(param1) OR ModelId (param2) (or 0 for both to unmount)
|
||||
|
||||
SMART_ACTION_SET_PHASE_MASK = 97,
|
||||
SMART_ACTION_SET_STAND_STATE = 98,
|
||||
SMART_ACTION_MOVE_RANDOM_POINT = 99,
|
||||
SMART_ACTION_SET_VISIBILITY = 100,
|
||||
SMART_ACTION_SET_ACTIVE = 101, //Apply
|
||||
SMART_ACTION_SET_AGGRESSIVE = 102, //Apply
|
||||
SMART_ACTION_ATTACK_START_PULSE = 103, //Distance
|
||||
SMART_ACTION_SUMMON_GO = 104, //GameObjectID, DespawnTime in ms
|
||||
|
||||
SMART_ACTION_END = 105,
|
||||
};
|
||||
|
||||
//temp copied from eai, will be modded
|
||||
enum SMARTAI_TARGETS
|
||||
{
|
||||
SMART_TARGET_SELF = 0, //Self cast
|
||||
|
||||
//Hostile targets (if pet then returns pet owner)
|
||||
SMART_TARGET_VICTIM = 1, //Our current target (ie: highest aggro)
|
||||
SMART_TARGET_HOSTILE_SECOND_AGGRO = 2, //Second highest aggro (generaly used for cleaves and some special attacks)
|
||||
SMART_TARGET_HOSTILE_LAST_AGGRO = 3, //Dead last on aggro (no idea what this could be used for)
|
||||
SMART_TARGET_HOSTILE_RANDOM = 4, //Just any random target on our threat list
|
||||
SMART_TARGET_HOSTILE_RANDOM_NOT_TOP = 5, //Any random target except top threat
|
||||
|
||||
//Invoker targets (if pet then returns pet owner)
|
||||
SMART_TARGET_ACTION_INVOKER = 6, //Unit who caused this Event to occur (only works for EVENT_T_AGGRO, EVENT_T_KILL, EVENT_T_DEATH, EVENT_T_SPELLHIT, EVENT_T_OOC_LOS, EVENT_T_FRIENDLY_HP, EVENT_T_FRIENDLY_IS_CC, EVENT_T_FRIENDLY_MISSING_BUFF)
|
||||
|
||||
//Hostile targets (including pets)
|
||||
SMART_TARGET_HOSTILE_WPET = 7, //Current target (can be a pet)
|
||||
SMART_TARGET_HOSTILE_WPET_SECOND_AGGRO = 8, //Second highest aggro (generaly used for cleaves and some special attacks)
|
||||
SMART_TARGET_HOSTILE_WPET_LAST_AGGRO = 9, //Dead last on aggro (no idea what this could be used for)
|
||||
SMART_TARGET_HOSTILE_WPET_RANDOM = 10, //Just any random target on our threat list
|
||||
SMART_TARGET_HOSTILE_WPET_RANDOM_NOT_TOP = 11, //Any random target except top threat
|
||||
|
||||
SMART_TARGET_ACTION_INVOKER_WPET = 12,
|
||||
|
||||
SMART_TARGET_END = 13,
|
||||
};
|
||||
|
||||
#define SMARTAI_EVENT_PARAM_COUNT 6
|
||||
#define SMARTAI_ACTION_PARAM_COUNT 6
|
||||
|
||||
struct MovePoint
|
||||
{
|
||||
MovePoint(uint32 _id, float _x, float _y, float _z)
|
||||
{
|
||||
id = _id;
|
||||
x = _x;
|
||||
y = _y;
|
||||
z = _z;
|
||||
}
|
||||
|
||||
uint32 id;
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
};
|
||||
|
||||
// one line in DB is one event
|
||||
struct SMARTAI_EVENT_HOLDER
|
||||
{
|
||||
uint32 event_id;
|
||||
SMARTAI_EVENT event_type;
|
||||
uint32 event_phase_mask;
|
||||
uint32 event_chance;
|
||||
uint32 event_flags;
|
||||
int32 event_param[SMARTAI_EVENT_PARAM_COUNT];
|
||||
|
||||
SMARTAI_ACTION action_type;
|
||||
int32 action_param[SMARTAI_ACTION_PARAM_COUNT];
|
||||
|
||||
float param_x;
|
||||
float param_y;
|
||||
float param_z;
|
||||
float param_o;
|
||||
};
|
||||
|
||||
// all events for a single entry
|
||||
typedef std::vector<SMARTAI_EVENT_HOLDER> SmartAIEventList;
|
||||
|
||||
// all events for all entries
|
||||
typedef UNORDERED_MAP<int32, SmartAIEventList> SmartAIEventMap;
|
||||
|
||||
class SmartAIMgr
|
||||
{
|
||||
SmartAIMgr(){};
|
||||
public:
|
||||
~SmartAIMgr(){};
|
||||
|
||||
void LoadSmartAIFromDB();
|
||||
|
||||
// only use this after EntryExists() check
|
||||
SmartAIEventList const& GetEventList(int32 entry) const
|
||||
{
|
||||
SmartAIEventMap::const_iterator sList = m_EventMap.find(entry);
|
||||
return (*sList).second;
|
||||
}
|
||||
SmartAIEventMap const& GetEventMap() const { return m_EventMap; }
|
||||
|
||||
// do we have entry's eventList from DB?
|
||||
bool EntryExists(int32 entry)
|
||||
{
|
||||
SmartAIEventMap::const_iterator sList = m_EventMap.find(entry);
|
||||
if (sList != m_EventMap.end())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
SmartAIEventMap m_EventMap;
|
||||
};
|
||||
|
||||
class SmartAI : public CreatureAI
|
||||
{
|
||||
public:
|
||||
~SmartAI(){};
|
||||
explicit SmartAI(Creature *c);
|
||||
|
||||
// Called when creature is spawned or respawned
|
||||
void JustRespawned();
|
||||
|
||||
// Called after InitializeAI(), EnterEvadeMode() for resetting variables
|
||||
void Reset();
|
||||
|
||||
// Called at reaching home after evade
|
||||
void JustReachedHome();
|
||||
|
||||
// Called for reaction at enter to combat if not in combat yet (enemy can be NULL)
|
||||
void EnterCombat(Unit *enemy);
|
||||
|
||||
// Called for reaction at stopping attack at no attackers or targets
|
||||
void EnterEvadeMode();
|
||||
|
||||
// Called when the creature is killed
|
||||
void JustDied(Unit* killer);
|
||||
|
||||
// Called when the creature kills a unit
|
||||
void KilledUnit(Unit* victim);
|
||||
|
||||
// Called when the creature summon successfully other creature
|
||||
void JustSummoned(Creature* pUnit);
|
||||
|
||||
// Tell creature to attack and follow the victim
|
||||
void AttackStart(Unit *who);
|
||||
|
||||
// Called if IsVisible(Unit *who) is true at each *who move, reaction at visibility zone enter
|
||||
void MoveInLineOfSight(Unit *who);
|
||||
|
||||
// Called when hit by a spell
|
||||
void SpellHit(Unit* pUnit, const SpellEntry* pSpell);
|
||||
|
||||
// Called when spell hits a target
|
||||
void SpellHitTarget(Unit* target, const SpellEntry*);
|
||||
|
||||
// Called at any Damage from any attacker (before damage apply)
|
||||
void DamageTaken(Unit* done_by, uint32& damage, DamageEffectType damagetype);
|
||||
|
||||
// Called when the creature receives heal
|
||||
void HealReceived(Unit* done_by, uint32& addhealth);
|
||||
|
||||
// Called at World update tick
|
||||
void UpdateAI(const uint32 diff);
|
||||
|
||||
// Called at text emote receive from player
|
||||
void ReceiveEmote(Player* pPlayer, uint32 text_emote);
|
||||
|
||||
// Called at waypoint reached or point movement finished
|
||||
void MovementInform(uint32 MovementType, uint32 Data);
|
||||
|
||||
// Called when creature is summoned by another unit
|
||||
void IsSummonedBy(Unit* summoner);
|
||||
|
||||
// Called at any Damage to any victim (before damage apply)
|
||||
void DamageDealt(Unit * done_to, uint32 & damage);
|
||||
|
||||
// Called when a summoned creature dissapears (UnSommoned)
|
||||
void SummonedCreatureDespawn(Creature* unit);
|
||||
|
||||
// called when the corpse of this creature gets removed
|
||||
void CorpseRemoved(uint32 & respawnDelay);
|
||||
|
||||
// Called at World update tick if creature is charmed
|
||||
void UpdateAIWhileCharmed(const uint32 diff);
|
||||
|
||||
// Called when a Player/Creature enters the creature (vehicle)
|
||||
void PassengerBoarded(Unit* who, int8 seatId, bool apply);
|
||||
|
||||
// Called when gets initialized, when creature is added to world
|
||||
void InitializeAI();
|
||||
|
||||
// Called when creature gets charmed by another unit
|
||||
void OnCharmed(bool apply);
|
||||
|
||||
// Called when victim is in line of sight
|
||||
bool CanAIAttack(const Unit* who) const;
|
||||
|
||||
// Used in scripts to share variables
|
||||
void DoAction(const int32 param = 0);
|
||||
|
||||
// Used in scripts to share variables
|
||||
uint32 GetData(uint32 id = 0);
|
||||
|
||||
// Used in scripts to share variables
|
||||
void SetData(uint32 id, uint32 value);
|
||||
|
||||
// Used in scripts to share variables
|
||||
void SetGUID(const uint64 &guid, int32 id = 0);
|
||||
|
||||
// Used in scripts to share variables
|
||||
uint64 GetGUID(int32 id = 0);
|
||||
|
||||
//core related
|
||||
static int Permissible(const Creature *);
|
||||
|
||||
// Called at movepoint reached
|
||||
void MovepointReached(uint32 id);
|
||||
|
||||
// Start moving to the desired MovePoint
|
||||
void MovepointStart(uint32 id);
|
||||
|
||||
// Makes the creature run/walk
|
||||
void SetRun(bool bRun = true);
|
||||
|
||||
// Sets the action that will be called when creature reaches the last movepoint
|
||||
void SetMovePathEndAction(SMARTAI_ACTION action = SMART_ACTION_FORCE_DESPAWN);
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
#define sSmartAIMgr (*ACE_Singleton<SmartAIMgr, ACE_Null_Mutex>::instance())
|
||||
#endif
|
||||
900
src/server/game/AI/SmartScripts/SmartAI.cpp
Normal file
900
src/server/game/AI/SmartScripts/SmartAI.cpp
Normal file
@@ -0,0 +1,900 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2010 TrinityCore <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include "DatabaseEnv.h"
|
||||
#include "SQLStorage.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "ProgressBar.h"
|
||||
#include "ObjectDefines.h"
|
||||
#include "GridDefines.h"
|
||||
#include "GridNotifiers.h"
|
||||
#include "SpellMgr.h"
|
||||
#include "GridNotifiersImpl.h"
|
||||
#include "Cell.h"
|
||||
#include "CellImpl.h"
|
||||
#include "InstanceScript.h"
|
||||
#include "ScriptedCreature.h"
|
||||
|
||||
#include "SmartAI.h"
|
||||
#include "ScriptPCH.h"
|
||||
|
||||
SmartAI::SmartAI(Creature *c) : CreatureAI(c)
|
||||
{
|
||||
// copy script to local (pretection for table reload)
|
||||
|
||||
mWayPoints = NULL;
|
||||
mEscortState = SMART_ESCORT_NONE;
|
||||
mCurrentWPID = 0;//first wp id is 1 !!
|
||||
mWPReached = false;
|
||||
mWPPauseTimer = 0;
|
||||
mLastWP = NULL;
|
||||
|
||||
mCanRepeatPath = false;
|
||||
|
||||
// spawn in run mode
|
||||
me->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING);
|
||||
mRun = true;
|
||||
|
||||
me->GetPosition(&mLastOOCPos);
|
||||
|
||||
mCanAutoAttack = true;
|
||||
mCanCombatMove = true;
|
||||
|
||||
mForcedPaused = false;
|
||||
mLastWPIDReached = 0;
|
||||
|
||||
mEscortQuestID = 0;
|
||||
|
||||
mDespawnTime = 0;
|
||||
mDespawnState = 0;
|
||||
|
||||
mEscortInvokerCheckTimer = 1000;
|
||||
mFollowGuid = 0;
|
||||
mFollowDist = 0;
|
||||
mFollowAngle = 0;
|
||||
mFollowCredit = 0;
|
||||
mFollowArrivedEntry = 0;
|
||||
mFollowCreditType = 0;
|
||||
}
|
||||
|
||||
void SmartAI::UpdateDespawn(const uint32 diff)
|
||||
{
|
||||
if (mDespawnState <= 1 || mDespawnState > 3) return;
|
||||
if (mDespawnTime < diff)
|
||||
{
|
||||
if (mDespawnState == 2)
|
||||
{
|
||||
me->SetVisibility(VISIBILITY_OFF);
|
||||
mDespawnTime = 5000;
|
||||
mDespawnState++;
|
||||
}
|
||||
else
|
||||
me->ForcedDespawn();
|
||||
} else mDespawnTime -= diff;
|
||||
}
|
||||
|
||||
void SmartAI::Reset()
|
||||
{
|
||||
SetRun(true);
|
||||
GetScript()->OnReset();
|
||||
}
|
||||
|
||||
WayPoint* SmartAI::GetNextWayPoint()
|
||||
{
|
||||
if (!mWayPoints || mWayPoints->empty())
|
||||
return NULL;
|
||||
|
||||
mCurrentWPID++;
|
||||
WPPath::const_iterator itr = mWayPoints->find(mCurrentWPID);
|
||||
if (itr != mWayPoints->end())
|
||||
{
|
||||
mLastWP = (*itr).second;
|
||||
if (mLastWP->id != mCurrentWPID)
|
||||
{
|
||||
sLog.outError("SmartAI::GetNextWayPoint: Got not expected waypoint id %u, expected %u", mLastWP->id, mCurrentWPID);
|
||||
}
|
||||
return (*itr).second;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void SmartAI::StartPath(bool run, uint32 path, bool repeat, Unit* invoker)
|
||||
{
|
||||
if (me->isInCombat())// no wp movement in combat
|
||||
{
|
||||
sLog.outError("SmartAI::StartPath: Creature entry %u wanted to start waypoint movement while in combat, ignoring.", me->GetEntry());
|
||||
return;
|
||||
}
|
||||
if (HasEscortState(SMART_ESCORT_ESCORTING))
|
||||
StopPath();
|
||||
if (path)
|
||||
if (!LoadPath(path))
|
||||
return;
|
||||
if (!mWayPoints || mWayPoints->empty())
|
||||
return;
|
||||
|
||||
AddEscortState(SMART_ESCORT_ESCORTING);
|
||||
mCanRepeatPath = repeat;
|
||||
|
||||
SetRun(run);
|
||||
|
||||
WayPoint* wp = GetNextWayPoint();
|
||||
if (wp)
|
||||
{
|
||||
me->GetPosition(&mLastOOCPos);
|
||||
me->GetMotionMaster()->MovePoint(wp->id, wp->x, wp->y, wp->z);
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_START, NULL, wp->id, GetScript()->GetPathId());
|
||||
}
|
||||
}
|
||||
|
||||
bool SmartAI::LoadPath(uint32 entry)
|
||||
{
|
||||
if (HasEscortState(SMART_ESCORT_ESCORTING))
|
||||
return false;
|
||||
mWayPoints = sSmartWaypointMgr.GetPath(entry);
|
||||
if (!mWayPoints)
|
||||
{
|
||||
GetScript()->SetPathId(0);
|
||||
return false;
|
||||
}
|
||||
GetScript()->SetPathId(entry);
|
||||
return true;
|
||||
}
|
||||
|
||||
void SmartAI::PausePath(uint32 delay, bool forced)
|
||||
{
|
||||
if (!HasEscortState(SMART_ESCORT_ESCORTING))
|
||||
return;
|
||||
if (HasEscortState(SMART_ESCORT_PAUSED))
|
||||
{
|
||||
sLog.outError("SmartAI::StartPath: Creature entry %u wanted to pause waypoint movement while already paused, ignoring.", me->GetEntry());
|
||||
return;
|
||||
}
|
||||
mForcedPaused = forced;
|
||||
me->GetPosition(&mLastOOCPos);
|
||||
AddEscortState(SMART_ESCORT_PAUSED);
|
||||
mWPPauseTimer = delay;
|
||||
if (forced)
|
||||
{
|
||||
SetRun(mRun);
|
||||
me->StopMoving();//force stop
|
||||
me->GetMotionMaster()->MoveIdle();//force stop
|
||||
}
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_PAUSED, NULL, mLastWP->id, GetScript()->GetPathId());
|
||||
}
|
||||
|
||||
void SmartAI::StopPath(uint32 DespawnTime, uint32 quest, bool fail)
|
||||
{
|
||||
if (!HasEscortState(SMART_ESCORT_ESCORTING))
|
||||
return;
|
||||
|
||||
if (quest)
|
||||
mEscortQuestID = quest;
|
||||
SetDespawnTime(DespawnTime);
|
||||
//mDespawnTime = DespawnTime;
|
||||
|
||||
me->GetPosition(&mLastOOCPos);
|
||||
me->StopMoving();//force stop
|
||||
me->GetMotionMaster()->MoveIdle();
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_STOPPED, NULL, mLastWP->id, GetScript()->GetPathId());
|
||||
EndPath(fail);
|
||||
}
|
||||
|
||||
void SmartAI::EndPath(bool fail)
|
||||
{
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_ENDED, NULL, mLastWP->id, GetScript()->GetPathId());
|
||||
|
||||
RemoveEscortState(SMART_ESCORT_ESCORTING | SMART_ESCORT_PAUSED | SMART_ESCORT_RETURNING);
|
||||
mWayPoints = NULL;
|
||||
mCurrentWPID = 0;
|
||||
mWPPauseTimer = 0;
|
||||
mLastWP = NULL;
|
||||
|
||||
if (mCanRepeatPath)
|
||||
StartPath(mRun, GetScript()->GetPathId(), mCanRepeatPath);
|
||||
else
|
||||
GetScript()->SetPathId(0);
|
||||
|
||||
|
||||
ObjectList* targets = GetScript()->GetTargetList(SMART_ESCORT_TARGETS);
|
||||
if (targets && mEscortQuestID)
|
||||
{
|
||||
if (targets->size() == 1 && GetScript()->IsPlayer((*targets->begin())))
|
||||
{
|
||||
Player* plr = (*targets->begin())->ToPlayer();
|
||||
if(!fail && plr->IsAtGroupRewardDistance(me) && !plr->GetCorpse())
|
||||
plr->GroupEventHappens(mEscortQuestID, me);
|
||||
|
||||
if(fail && plr->GetQuestStatus(mEscortQuestID) == QUEST_STATUS_INCOMPLETE)
|
||||
plr->FailQuest(mEscortQuestID);
|
||||
|
||||
if (Group *pGroup = plr->GetGroup())
|
||||
{
|
||||
for (GroupReference *gr = pGroup->GetFirstMember(); gr != NULL; gr = gr->next())
|
||||
{
|
||||
Player *pGroupGuy = gr->getSource();
|
||||
|
||||
if(!fail && pGroupGuy->IsAtGroupRewardDistance(me) && !pGroupGuy->GetCorpse())
|
||||
pGroupGuy->AreaExploredOrEventHappens(mEscortQuestID);
|
||||
if(fail && pGroupGuy->GetQuestStatus(mEscortQuestID) == QUEST_STATUS_INCOMPLETE)
|
||||
pGroupGuy->FailQuest(mEscortQuestID);
|
||||
}
|
||||
}
|
||||
}else
|
||||
{
|
||||
for (ObjectList::iterator iter = targets->begin(); iter != targets->end(); iter++)
|
||||
{
|
||||
if (GetScript()->IsPlayer((*iter)))
|
||||
{
|
||||
Player* plr = (*iter)->ToPlayer();
|
||||
if(!fail && plr->IsAtGroupRewardDistance(me) && !plr->GetCorpse())
|
||||
plr->AreaExploredOrEventHappens(mEscortQuestID);
|
||||
if(fail && plr->GetQuestStatus(mEscortQuestID) == QUEST_STATUS_INCOMPLETE)
|
||||
plr->FailQuest(mEscortQuestID);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mDespawnState == 1)
|
||||
StartDespawn();
|
||||
}
|
||||
|
||||
void SmartAI::ResumePath()
|
||||
{
|
||||
//mWPReached = false;
|
||||
SetRun(mRun);
|
||||
if (mLastWP)
|
||||
me->GetMotionMaster()->MovePoint(mLastWP->id, mLastWP->x, mLastWP->y, mLastWP->z);
|
||||
}
|
||||
|
||||
void SmartAI::ReturnToLastOOCPos()
|
||||
{
|
||||
SetRun(mRun);
|
||||
me->GetMotionMaster()->MovePoint(SMART_ESCORT_LAST_OOC_POINT, mLastOOCPos);
|
||||
}
|
||||
|
||||
void SmartAI::UpdatePath(const uint32 diff)
|
||||
{
|
||||
if (!HasEscortState(SMART_ESCORT_ESCORTING))
|
||||
return;
|
||||
if (mEscortInvokerCheckTimer < diff)
|
||||
{
|
||||
if (!IsEscortInvokerInRange())
|
||||
{
|
||||
StopPath(mDespawnTime, mEscortQuestID, true);
|
||||
}
|
||||
mEscortInvokerCheckTimer = 1000;
|
||||
} else mEscortInvokerCheckTimer -= diff;
|
||||
// handle pause
|
||||
if (HasEscortState(SMART_ESCORT_PAUSED))
|
||||
{
|
||||
if (mWPPauseTimer < diff)
|
||||
{
|
||||
if (!me->isInCombat() && !HasEscortState(SMART_ESCORT_RETURNING) && (mWPReached || mLastWPIDReached == SMART_ESCORT_LAST_OOC_POINT || mForcedPaused))
|
||||
{
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_RESUMED, NULL, mLastWP->id, GetScript()->GetPathId());
|
||||
RemoveEscortState(SMART_ESCORT_PAUSED);
|
||||
if (mForcedPaused)// if paused between 2 wps resend movement
|
||||
{
|
||||
ResumePath();
|
||||
mWPReached = false;
|
||||
mForcedPaused = false;
|
||||
}
|
||||
if (mLastWPIDReached == SMART_ESCORT_LAST_OOC_POINT)
|
||||
mWPReached = true;
|
||||
}
|
||||
mWPPauseTimer = 0;
|
||||
} else {
|
||||
mWPPauseTimer -= diff;
|
||||
|
||||
}
|
||||
}
|
||||
if (HasEscortState(SMART_ESCORT_RETURNING))
|
||||
{
|
||||
if (mWPReached)//reached OOC WP
|
||||
{
|
||||
RemoveEscortState(SMART_ESCORT_RETURNING);
|
||||
if (!HasEscortState(SMART_ESCORT_PAUSED))
|
||||
ResumePath();
|
||||
mWPReached = false;
|
||||
}
|
||||
}
|
||||
if (me->isInCombat() || HasEscortState(SMART_ESCORT_PAUSED | SMART_ESCORT_RETURNING))
|
||||
return;
|
||||
// handle next wp
|
||||
if (mWPReached)//reached WP
|
||||
{
|
||||
mWPReached = false;
|
||||
if (mCurrentWPID == GetWPCount())
|
||||
{
|
||||
EndPath();
|
||||
} else {
|
||||
WayPoint* wp = GetNextWayPoint();
|
||||
if (wp)
|
||||
{
|
||||
SetRun(mRun);
|
||||
me->GetMotionMaster()->MovePoint(wp->id, wp->x, wp->y, wp->z);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void SmartAI::UpdateAI(const uint32 diff)
|
||||
{
|
||||
GetScript()->OnUpdate(diff);
|
||||
UpdatePath(diff);
|
||||
UpdateDespawn(diff);
|
||||
|
||||
//TODO move to void
|
||||
if (mFollowGuid)
|
||||
{
|
||||
if (mFollowArrivedTimer < diff)
|
||||
{
|
||||
if (Creature* target = me->FindNearestCreature(mFollowArrivedEntry,INTERACTION_DISTANCE, true))
|
||||
{
|
||||
if (Player* plr = me->GetPlayer(*me, mFollowGuid))
|
||||
{
|
||||
if (!mFollowCreditType)
|
||||
plr->RewardPlayerAndGroupAtEvent(mFollowCredit, me);
|
||||
else
|
||||
plr->GroupEventHappens(mFollowCredit, me);
|
||||
}
|
||||
mFollowGuid = 0;
|
||||
mFollowDist = 0;
|
||||
mFollowAngle = 0;
|
||||
mFollowCredit = 0;
|
||||
mFollowArrivedTimer = 1000;
|
||||
mFollowArrivedEntry = 0;
|
||||
mFollowCreditType = 0;
|
||||
SetDespawnTime(5000);
|
||||
me->StopMoving();
|
||||
me->GetMotionMaster()->MoveIdle();
|
||||
StartDespawn();
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_FOLLOW_COPMLETE);
|
||||
return;
|
||||
}
|
||||
mFollowArrivedTimer = 1000;
|
||||
} else mFollowArrivedTimer -= diff;
|
||||
}
|
||||
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
if(mCanAutoAttack)
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
bool SmartAI::IsEscortInvokerInRange()
|
||||
{
|
||||
ObjectList* targets = GetScript()->GetTargetList(SMART_ESCORT_TARGETS);
|
||||
if (targets)
|
||||
{
|
||||
if (targets->size() == 1 && GetScript()->IsPlayer((*targets->begin())))
|
||||
{
|
||||
Player* plr = (*targets->begin())->ToPlayer();
|
||||
if (me->GetDistance(plr) <= SMART_ESCORT_MAX_PLAYER_DIST)
|
||||
return true;
|
||||
|
||||
if (Group *pGroup = plr->GetGroup())
|
||||
{
|
||||
for (GroupReference *gr = pGroup->GetFirstMember(); gr != NULL; gr = gr->next())
|
||||
{
|
||||
Player *pGroupGuy = gr->getSource();
|
||||
|
||||
if (me->GetDistance(pGroupGuy) <= SMART_ESCORT_MAX_PLAYER_DIST)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}else
|
||||
{
|
||||
for (ObjectList::iterator iter = targets->begin(); iter != targets->end(); iter++)
|
||||
{
|
||||
if (GetScript()->IsPlayer((*iter)))
|
||||
{
|
||||
if (me->GetDistance((*iter)->ToPlayer()) <= SMART_ESCORT_MAX_PLAYER_DIST)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void SmartAI::MovepointReached(uint32 id)
|
||||
{
|
||||
if (id != SMART_ESCORT_LAST_OOC_POINT)
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_REACHED, NULL, id);
|
||||
|
||||
mLastWPIDReached = id;
|
||||
mWPReached = true;
|
||||
}
|
||||
|
||||
void SmartAI::MovementInform(uint32 MovementType, uint32 Data)
|
||||
{
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_MOVEMENTINFORM, NULL, MovementType, Data);
|
||||
if (MovementType != POINT_MOTION_TYPE || !HasEscortState(SMART_ESCORT_ESCORTING))
|
||||
return;
|
||||
MovepointReached(Data);
|
||||
}
|
||||
|
||||
void SmartAI::EnterEvadeMode()
|
||||
{
|
||||
if (!me->isAlive())
|
||||
return;
|
||||
|
||||
me->RemoveAllAuras();
|
||||
me->DeleteThreatList();
|
||||
me->CombatStop(true);
|
||||
me->LoadCreaturesAddon();
|
||||
me->SetLootRecipient(NULL);
|
||||
me->ResetPlayerDamageReq();
|
||||
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_EVADE);//must be after aura clear so we can cast spells from db
|
||||
|
||||
SetRun(mRun);
|
||||
if (HasEscortState(SMART_ESCORT_ESCORTING))
|
||||
{
|
||||
AddEscortState(SMART_ESCORT_RETURNING);
|
||||
ReturnToLastOOCPos();
|
||||
} else if (mFollowGuid){
|
||||
if (Unit* target = me->GetUnit(*me, mFollowGuid))
|
||||
me->GetMotionMaster()->MoveFollow(target, mFollowDist, mFollowAngle);
|
||||
} else {
|
||||
me->GetMotionMaster()->MoveTargetedHome();
|
||||
}
|
||||
|
||||
Reset();
|
||||
}
|
||||
|
||||
void SmartAI::MoveInLineOfSight(Unit* who)
|
||||
{
|
||||
if (!who) return;
|
||||
GetScript()->OnMoveInLineOfSight(who);
|
||||
//HasEscortState(SMART_ESCORT_ESCORTING) ||
|
||||
if (me->HasReactState(REACT_PASSIVE) || AssistPlayerInCombat(who))
|
||||
return;
|
||||
|
||||
if (!CanAIAttack(who))
|
||||
return;
|
||||
|
||||
if (me->IsHostileTo(who))
|
||||
{
|
||||
float fAttackRadius = me->GetAttackDistance(who);
|
||||
if (me->IsWithinDistInMap(who, fAttackRadius) && me->IsWithinLOSInMap(who))
|
||||
{
|
||||
if (!me->getVictim())
|
||||
{
|
||||
who->RemoveAurasByType(SPELL_AURA_MOD_STEALTH);
|
||||
AttackStart(who);
|
||||
}
|
||||
else/* if (me->GetMap()->IsDungeon())*/
|
||||
{
|
||||
who->SetInCombatWith(me);
|
||||
me->AddThreat(who, 0.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//if (me->canStartAttack(who, false))
|
||||
// AttackStart(who);
|
||||
}
|
||||
|
||||
bool SmartAI::CanAIAttack(const Unit* who) const
|
||||
{
|
||||
if (me->GetReactState() == REACT_PASSIVE)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SmartAI::AssistPlayerInCombat(Unit* pWho)
|
||||
{
|
||||
if (!pWho || !pWho->getVictim())
|
||||
return false;
|
||||
|
||||
//experimental (unknown) flag not present
|
||||
if (!(me->GetCreatureInfo()->type_flags & CREATURE_TYPEFLAGS_AID_PLAYERS))
|
||||
return false;
|
||||
|
||||
//not a player
|
||||
if (!pWho->getVictim()->GetCharmerOrOwnerPlayerOrPlayerItself())
|
||||
return false;
|
||||
|
||||
//never attack friendly
|
||||
if (me->IsFriendlyTo(pWho))
|
||||
return false;
|
||||
|
||||
//too far away and no free sight?
|
||||
if (me->IsWithinDistInMap(pWho, SMART_MAX_AID_DIST) && me->IsWithinLOSInMap(pWho))
|
||||
{
|
||||
//already fighting someone?
|
||||
if (!me->getVictim())
|
||||
{
|
||||
AttackStart(pWho);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
pWho->SetInCombatWith(me);
|
||||
me->AddThreat(pWho, 0.0f);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void SmartAI::JustRespawned()
|
||||
{
|
||||
mDespawnTime = 0;
|
||||
mDespawnState = 0;
|
||||
mEscortState = SMART_ESCORT_NONE;
|
||||
me->SetVisibility(VISIBILITY_ON);
|
||||
if (me->getFaction() != me->GetCreatureInfo()->faction_A)
|
||||
me->RestoreFaction();
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_RESPAWN);
|
||||
Reset();
|
||||
mFollowGuid = 0;//do not reset follower on Reset(), we need it after combat evade
|
||||
mFollowDist = 0;
|
||||
mFollowAngle = 0;
|
||||
mFollowCredit = 0;
|
||||
mFollowArrivedTimer = 1000;
|
||||
mFollowArrivedEntry = 0;
|
||||
mFollowCreditType = 0;
|
||||
}
|
||||
|
||||
int SmartAI::Permissible(const Creature* creature)
|
||||
{
|
||||
if (creature->GetAIName() == "SmartAI")
|
||||
return PERMIT_BASE_SPECIAL;
|
||||
return PERMIT_BASE_NO;
|
||||
}
|
||||
|
||||
void SmartAI::JustReachedHome()
|
||||
{
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_REACHED_HOME);
|
||||
}
|
||||
|
||||
void SmartAI::EnterCombat(Unit* enemy)
|
||||
{
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_AGGRO, enemy);
|
||||
me->GetPosition(&mLastOOCPos);
|
||||
}
|
||||
|
||||
void SmartAI::JustDied(Unit* killer)
|
||||
{
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_DEATH, killer);
|
||||
if (HasEscortState(SMART_ESCORT_ESCORTING))
|
||||
EndPath(true);
|
||||
}
|
||||
|
||||
void SmartAI::KilledUnit(Unit* victim)
|
||||
{
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_KILL, victim);
|
||||
}
|
||||
|
||||
void SmartAI::JustSummoned(Creature* pUnit)
|
||||
{
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_SUMMONED_UNIT, pUnit);
|
||||
}
|
||||
|
||||
void SmartAI::AttackStart(Unit* who)
|
||||
{
|
||||
if (who && me->Attack(who, true))
|
||||
{
|
||||
SetRun(mRun);
|
||||
if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == POINT_MOTION_TYPE)
|
||||
me->GetMotionMaster()->MovementExpired();
|
||||
|
||||
if (mCanCombatMove)
|
||||
me->GetMotionMaster()->MoveChase(who);
|
||||
|
||||
me->GetPosition(&mLastOOCPos);
|
||||
}
|
||||
}
|
||||
|
||||
void SmartAI::SpellHit(Unit* pUnit, const SpellEntry* pSpell)
|
||||
{
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_SPELLHIT, pUnit, 0, 0, false, pSpell);
|
||||
}
|
||||
|
||||
void SmartAI::SpellHitTarget(Unit* target, const SpellEntry* pSpell)
|
||||
{
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_SPELLHIT_TARGET, target, 0, 0, false, pSpell);
|
||||
}
|
||||
|
||||
void SmartAI::DamageTaken(Unit* done_by, uint32& damage, DamageEffectType /*damagetype*/)
|
||||
{
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_DAMAGED, done_by, damage);
|
||||
}
|
||||
|
||||
void SmartAI::HealReceived(Unit* done_by, uint32& addhealth)
|
||||
{
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_RECEIVE_HEAL, done_by, addhealth);
|
||||
}
|
||||
|
||||
void SmartAI::ReceiveEmote(Player* pPlayer, uint32 text_emote)
|
||||
{
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_RECEIVE_EMOTE, pPlayer, text_emote);
|
||||
}
|
||||
|
||||
void SmartAI::IsSummonedBy(Unit* summoner)
|
||||
{
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_JUST_SUMMONED, summoner);
|
||||
}
|
||||
|
||||
void SmartAI::DamageDealt(Unit* done_to, uint32& damage)
|
||||
{
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_DAMAGED_TARGET, done_to, damage);
|
||||
}
|
||||
|
||||
void SmartAI::SummonedCreatureDespawn(Creature* unit)
|
||||
{
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_SUMMON_DESPAWNED, unit);
|
||||
}
|
||||
|
||||
void SmartAI::UpdateAIWhileCharmed(const uint32 diff)
|
||||
{
|
||||
}
|
||||
|
||||
void SmartAI::CorpseRemoved(uint32& respawnDelay)
|
||||
{
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_CORPSE_REMOVED, NULL, respawnDelay);
|
||||
}
|
||||
|
||||
void SmartAI::PassengerBoarded(Unit* who, int8 seatId, bool apply)
|
||||
{
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_PASSENGER_BOARDED, who, (uint32)seatId, 0, apply);
|
||||
}
|
||||
|
||||
void SmartAI::InitializeAI()
|
||||
{
|
||||
GetScript()->OnInitialize(me);
|
||||
if (!me->isDead())
|
||||
Reset();
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_RESPAWN);
|
||||
}
|
||||
|
||||
void SmartAI::OnCharmed(bool apply)
|
||||
{
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_CHARMED, NULL, 0, 0, apply);
|
||||
}
|
||||
|
||||
void SmartAI::DoAction(const int32 param)
|
||||
{
|
||||
}
|
||||
|
||||
uint32 SmartAI::GetData(uint32 id)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SmartAI::SetData(uint32 id, uint32 value)
|
||||
{
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_DATA_SET, NULL, id, value);
|
||||
}
|
||||
|
||||
void SmartAI::SetGUID(const uint64& guid, int32 id)
|
||||
{
|
||||
}
|
||||
|
||||
uint64 SmartAI::GetGUID(int32 id)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SmartAI::SetRun(bool run)
|
||||
{
|
||||
if (run)
|
||||
me->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING);
|
||||
else
|
||||
me->AddUnitMovementFlag(MOVEMENTFLAG_WALKING);
|
||||
mRun = run;
|
||||
}
|
||||
|
||||
void SmartAI::SetFly(bool bFly)
|
||||
{
|
||||
me->SetFlying(bFly);
|
||||
}
|
||||
|
||||
void SmartAI::SetSwimm(bool bSwimm)
|
||||
{
|
||||
if (bSwimm)
|
||||
me->AddUnitMovementFlag(MOVEMENTFLAG_SWIMMING);
|
||||
else
|
||||
me->RemoveUnitMovementFlag(MOVEMENTFLAG_SWIMMING);
|
||||
}
|
||||
|
||||
void SmartAI::sGossipHello(Player* player)
|
||||
{
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_GOSSIP_HELLO, player);
|
||||
}
|
||||
|
||||
void SmartAI::sGossipSelect(Player* player, uint32 sender, uint32 action)
|
||||
{
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_GOSSIP_SELECT, player, sender, action);
|
||||
}
|
||||
|
||||
void SmartAI::sGossipSelectCode(Player* player, uint32 sender, uint32 action, const char* code)
|
||||
{
|
||||
}
|
||||
|
||||
void SmartAI::sQuestAccept(Player* player, Quest const* quest)
|
||||
{
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_ACCEPTED_QUEST, player, quest->GetQuestId());
|
||||
}
|
||||
|
||||
void SmartAI::sQuestReward(Player* player, Quest const* quest, uint32 opt)
|
||||
{
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_REWARD_QUEST, player, quest->GetQuestId(), opt);
|
||||
}
|
||||
void SmartAI::SetCombatMove(bool on)
|
||||
{
|
||||
if (mCanCombatMove == on)
|
||||
return;
|
||||
mCanCombatMove = on;
|
||||
if (!HasEscortState(SMART_ESCORT_ESCORTING))
|
||||
{
|
||||
if (on && me->getVictim())
|
||||
{
|
||||
if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == IDLE_MOTION_TYPE)
|
||||
{
|
||||
SetRun(mRun);
|
||||
me->GetMotionMaster()->MoveChase(me->getVictim());
|
||||
me->CastStop();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
me->StopMoving();
|
||||
me->GetMotionMaster()->MoveIdle();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SmartAI::SetFollow(Unit* target, float dist, float angle, uint32 credit, uint32 end, uint32 creditType)
|
||||
{
|
||||
if (!target)
|
||||
return;
|
||||
SetRun(mRun);
|
||||
mFollowGuid = target->GetGUID();
|
||||
mFollowDist = dist;
|
||||
mFollowAngle = angle;
|
||||
mFollowArrivedTimer = 1000;
|
||||
mFollowCredit = credit;
|
||||
mFollowArrivedEntry = end;
|
||||
me->GetMotionMaster()->MoveFollow(target, dist, angle);
|
||||
mFollowCreditType = creditType;
|
||||
}
|
||||
/*
|
||||
SMART_EVENT_UPDATE_OOC
|
||||
SMART_EVENT_SPELLHIT
|
||||
SMART_EVENT_RANGE
|
||||
SMART_EVENT_RESPAWN
|
||||
SMART_EVENT_SUMMONED_UNIT
|
||||
SMART_EVENT_ACCEPTED_QUEST
|
||||
SMART_EVENT_REWARD_QUEST
|
||||
SMART_EVENT_TARGET_BUFFED
|
||||
SMART_EVENT_SUMMON_DESPAWNED
|
||||
SMART_EVENT_AI_INIT
|
||||
SMART_EVENT_DATA_SET
|
||||
SMART_EVENT_TEXT_OVER
|
||||
SMART_EVENT_TIMED_EVENT_TRIGGERED
|
||||
SMART_EVENT_UPDATE
|
||||
SMART_EVENT_LINK
|
||||
SMART_EVENT_GOSSIP_SELECT
|
||||
SMART_EVENT_JUST_CREATED
|
||||
SMART_EVENT_GOSSIP_HELLO
|
||||
SMART_EVENT_DEATH
|
||||
*/
|
||||
|
||||
int SmartGameObjectAI::Permissible(const GameObject* g)
|
||||
{
|
||||
if (g->GetAIName() == "SmartGameObjectAI")
|
||||
return PERMIT_BASE_SPECIAL;
|
||||
return PERMIT_BASE_NO;
|
||||
}
|
||||
|
||||
void SmartGameObjectAI::UpdateAI(const uint32 diff)
|
||||
{
|
||||
GetScript()->OnUpdate(diff);
|
||||
}
|
||||
|
||||
void SmartGameObjectAI::InitializeAI()
|
||||
{
|
||||
GetScript()->OnInitialize(go);
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_RESPAWN);
|
||||
//Reset();
|
||||
}
|
||||
|
||||
void SmartGameObjectAI::Reset()
|
||||
{
|
||||
GetScript()->OnReset();
|
||||
}
|
||||
|
||||
// Called when a player opens a gossip dialog with the gameobject.
|
||||
bool SmartGameObjectAI::GossipHello(Player* player)
|
||||
{
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_GOSSIP_HELLO, player, 0 ,0 , false, NULL, go);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Called when a player selects a gossip item in the gameobject's gossip menu.
|
||||
bool SmartGameObjectAI::GossipSelect(Player* player, uint32 sender, uint32 action)
|
||||
{
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_GOSSIP_SELECT, player, sender, action, false, NULL, go);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Called when a player selects a gossip with a code in the gameobject's gossip menu.
|
||||
bool SmartGameObjectAI::GossipSelectCode(Player* /*player*/, uint32 /*sender*/, uint32 /*action*/, const char* /*code*/)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Called when a player accepts a quest from the gameobject.
|
||||
bool SmartGameObjectAI::QuestAccept(Player* player, Quest const* quest)
|
||||
{
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_ACCEPTED_QUEST, player, quest->GetQuestId() ,0 , false, NULL, go);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Called when a player selects a quest reward.
|
||||
bool SmartGameObjectAI::QuestReward(Player* player, Quest const* quest, uint32 opt)
|
||||
{
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_REWARD_QUEST, player, quest->GetQuestId() ,opt , false, NULL, go);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Called when the dialog status between a player and the gameobject is requested.
|
||||
uint32 SmartGameObjectAI::GetDialogStatus(Player* /*player*/) { return 100; }
|
||||
|
||||
// Called when the gameobject is destroyed (destructible buildings only).
|
||||
void SmartGameObjectAI::Destroyed(Player* player, uint32 eventId)
|
||||
{
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_DEATH, player, eventId ,0 , false, NULL, go);
|
||||
}
|
||||
|
||||
void SmartGameObjectAI::SetData(uint32 id, uint32 value)
|
||||
{
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_DATA_SET, NULL, id, value);
|
||||
}
|
||||
|
||||
class SmartTrigger : public AreaTriggerScript
|
||||
{
|
||||
public:
|
||||
|
||||
SmartTrigger()
|
||||
: AreaTriggerScript("SmartTrigger")
|
||||
{
|
||||
}
|
||||
|
||||
bool OnTrigger(Player* player, AreaTriggerEntry const* trigger)
|
||||
{
|
||||
sLog.outDebug("AreaTrigger %u is using SmartTrigger script", trigger->id);
|
||||
SmartScript script;
|
||||
script.OnInitialize(NULL, trigger);
|
||||
script.ProcessEventsFor(SMART_EVENT_AREATRIGGER_ONTRIGGER, player, trigger->id);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_SmartSCripts()
|
||||
{
|
||||
new SmartTrigger();
|
||||
}
|
||||
254
src/server/game/AI/SmartScripts/SmartAI.h
Normal file
254
src/server/game/AI/SmartScripts/SmartAI.h
Normal file
@@ -0,0 +1,254 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2010 TrinityCore <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TRINITY_SMARTAI_H
|
||||
#define TRINITY_SMARTAI_H
|
||||
|
||||
#include "Common.h"
|
||||
#include "Creature.h"
|
||||
#include "CreatureAI.h"
|
||||
#include "Unit.h"
|
||||
#include "ConditionMgr.h"
|
||||
#include "CreatureTextMgr.h"
|
||||
#include "Spell.h"
|
||||
|
||||
#include "SmartScript.h"
|
||||
#include "SmartScriptMgr.h"
|
||||
#include "GameObjectAI.h"
|
||||
|
||||
enum SmartEscortState
|
||||
{
|
||||
SMART_ESCORT_NONE = 0x000, //nothing in progress
|
||||
SMART_ESCORT_ESCORTING = 0x001, //escort is in progress
|
||||
SMART_ESCORT_RETURNING = 0x002, //escort is returning after being in combat
|
||||
SMART_ESCORT_PAUSED = 0x004 //will not proceed with waypoints before state is removed
|
||||
};
|
||||
|
||||
enum SmartEscortVars
|
||||
{
|
||||
SMART_ESCORT_MAX_PLAYER_DIST = 50,
|
||||
SMART_MAX_AID_DIST = SMART_ESCORT_MAX_PLAYER_DIST / 2,
|
||||
};
|
||||
|
||||
class SmartAI : public CreatureAI
|
||||
{
|
||||
public:
|
||||
~SmartAI(){};
|
||||
explicit SmartAI(Creature *c);
|
||||
|
||||
// Start moving to the desired MovePoint
|
||||
void StartPath(bool run = false, uint32 path = 0, bool repeat = false, Unit* invoker = NULL);
|
||||
bool LoadPath(uint32 entry);
|
||||
void PausePath(uint32 delay, bool forced = false);
|
||||
void StopPath(uint32 DespawnTime = 0, uint32 quest = 0, bool fail = false);
|
||||
void EndPath(bool fail = false);
|
||||
void ResumePath();
|
||||
WayPoint* GetNextWayPoint();
|
||||
bool HasEscortState(uint32 uiEscortState) { return (mEscortState & uiEscortState); }
|
||||
void AddEscortState(uint32 uiEscortState) { mEscortState |= uiEscortState; }
|
||||
void RemoveEscortState(uint32 uiEscortState) { mEscortState &= ~uiEscortState; }
|
||||
void SetAutoAttack(bool on) { mCanAutoAttack = on; }
|
||||
void SetCombatMove(bool on);
|
||||
void SetFollow(Unit* target, float dist = 0.0f, float angle = 0.0f, uint32 credit = 0, uint32 end = 0, uint32 creditType = 0);
|
||||
|
||||
SmartScript* GetScript() { return &mScript; }
|
||||
bool IsEscortInvokerInRange();
|
||||
|
||||
// Called when creature is spawned or respawned
|
||||
void JustRespawned();
|
||||
|
||||
// Called after InitializeAI(), EnterEvadeMode() for resetting variables
|
||||
void Reset();
|
||||
|
||||
// Called at reaching home after evade
|
||||
void JustReachedHome();
|
||||
|
||||
// Called for reaction at enter to combat if not in combat yet (enemy can be NULL)
|
||||
void EnterCombat(Unit *enemy);
|
||||
|
||||
// Called for reaction at stopping attack at no attackers or targets
|
||||
void EnterEvadeMode();
|
||||
|
||||
// Called when the creature is killed
|
||||
void JustDied(Unit* killer);
|
||||
|
||||
// Called when the creature kills a unit
|
||||
void KilledUnit(Unit* victim);
|
||||
|
||||
// Called when the creature summon successfully other creature
|
||||
void JustSummoned(Creature* pUnit);
|
||||
|
||||
// Tell creature to attack and follow the victim
|
||||
void AttackStart(Unit *who);
|
||||
|
||||
// Called if IsVisible(Unit *who) is true at each *who move, reaction at visibility zone enter
|
||||
void MoveInLineOfSight(Unit *who);
|
||||
|
||||
// Called when hit by a spell
|
||||
void SpellHit(Unit* pUnit, const SpellEntry* pSpell);
|
||||
|
||||
// Called when spell hits a target
|
||||
void SpellHitTarget(Unit* target, const SpellEntry* pSpell);
|
||||
|
||||
// Called at any Damage from any attacker (before damage apply)
|
||||
void DamageTaken(Unit* done_by, uint32& damage, DamageEffectType damagetype);
|
||||
|
||||
// Called when the creature receives heal
|
||||
void HealReceived(Unit* done_by, uint32& addhealth);
|
||||
|
||||
// Called at World update tick
|
||||
void UpdateAI(const uint32 diff);
|
||||
|
||||
// Called at text emote receive from player
|
||||
void ReceiveEmote(Player* pPlayer, uint32 text_emote);
|
||||
|
||||
// Called at waypoint reached or point movement finished
|
||||
void MovementInform(uint32 MovementType, uint32 Data);
|
||||
|
||||
// Called when creature is summoned by another unit
|
||||
void IsSummonedBy(Unit* summoner);
|
||||
|
||||
// Called at any Damage to any victim (before damage apply)
|
||||
void DamageDealt(Unit * done_to, uint32 & damage);
|
||||
|
||||
// Called when a summoned creature dissapears (UnSommoned)
|
||||
void SummonedCreatureDespawn(Creature* unit);
|
||||
|
||||
// called when the corpse of this creature gets removed
|
||||
void CorpseRemoved(uint32 & respawnDelay);
|
||||
|
||||
// Called at World update tick if creature is charmed
|
||||
void UpdateAIWhileCharmed(const uint32 diff);
|
||||
|
||||
// Called when a Player/Creature enters the creature (vehicle)
|
||||
void PassengerBoarded(Unit* who, int8 seatId, bool apply);
|
||||
|
||||
// Called when gets initialized, when creature is added to world
|
||||
void InitializeAI();
|
||||
|
||||
// Called when creature gets charmed by another unit
|
||||
void OnCharmed(bool apply);
|
||||
|
||||
// Called when victim is in line of sight
|
||||
bool CanAIAttack(const Unit* who) const;
|
||||
|
||||
// Used in scripts to share variables
|
||||
void DoAction(const int32 param = 0);
|
||||
|
||||
// Used in scripts to share variables
|
||||
uint32 GetData(uint32 id = 0);
|
||||
|
||||
// Used in scripts to share variables
|
||||
void SetData(uint32 id, uint32 value);
|
||||
|
||||
// Used in scripts to share variables
|
||||
void SetGUID(const uint64 &guid, int32 id = 0);
|
||||
|
||||
// Used in scripts to share variables
|
||||
uint64 GetGUID(int32 id = 0);
|
||||
|
||||
//core related
|
||||
static int Permissible(const Creature *);
|
||||
|
||||
// Called at movepoint reached
|
||||
void MovepointReached(uint32 id);
|
||||
|
||||
// Makes the creature run/walk
|
||||
void SetRun(bool bRun = true);
|
||||
|
||||
void SetFly(bool bFly = true);
|
||||
|
||||
void SetSwimm(bool bSwimm = true);
|
||||
|
||||
void sGossipHello(Player* player);
|
||||
void sGossipSelect(Player* player, uint32 sender, uint32 action);
|
||||
void sGossipSelectCode(Player* player, uint32 sender, uint32 action, const char* code);
|
||||
void sQuestAccept(Player* player, Quest const* quest);
|
||||
//void sQuestSelect(Player* player, Quest const* quest);
|
||||
//void sQuestComplete(Player* player, Quest const* quest);
|
||||
void sQuestReward(Player* player, Quest const* quest, uint32 opt);
|
||||
|
||||
uint32 mEscortQuestID;
|
||||
|
||||
void SetDespawnTime (uint32 t)
|
||||
{
|
||||
mDespawnTime = t;
|
||||
mDespawnState = t ? 1 : 0;
|
||||
}
|
||||
void StartDespawn() { mDespawnState = 2; }
|
||||
|
||||
private:
|
||||
uint32 mFollowCreditType;
|
||||
uint32 mFollowArrivedTimer;
|
||||
uint32 mFollowCredit;
|
||||
uint32 mFollowArrivedEntry;
|
||||
uint64 mFollowGuid;
|
||||
float mFollowDist;
|
||||
float mFollowAngle;
|
||||
|
||||
void ReturnToLastOOCPos();
|
||||
void UpdatePath(const uint32 diff);
|
||||
SmartScript mScript;
|
||||
WPPath* mWayPoints;
|
||||
uint32 mEscortState;
|
||||
uint32 mCurrentWPID;
|
||||
uint32 mLastWPIDReached;
|
||||
bool mWPReached;
|
||||
uint32 mWPPauseTimer;
|
||||
WayPoint* mLastWP;
|
||||
Position mLastOOCPos;//set on enter combat
|
||||
uint32 GetWPCount() { return mWayPoints ? mWayPoints->size() : 0; }
|
||||
bool mCanRepeatPath;
|
||||
bool mRun;
|
||||
bool mCanAutoAttack;
|
||||
bool mCanCombatMove;
|
||||
bool mForcedPaused;
|
||||
|
||||
bool AssistPlayerInCombat(Unit* pWho);
|
||||
|
||||
uint32 mDespawnTime;
|
||||
uint32 mDespawnState;
|
||||
void UpdateDespawn(const uint32 diff);
|
||||
uint32 mEscortInvokerCheckTimer;
|
||||
};
|
||||
|
||||
class SmartGameObjectAI : public GameObjectAI
|
||||
{
|
||||
public:
|
||||
SmartGameObjectAI(GameObject *g) : go(g), GameObjectAI(g) {}
|
||||
~SmartGameObjectAI() {}
|
||||
|
||||
void UpdateAI(const uint32 diff);
|
||||
void InitializeAI();
|
||||
void Reset();
|
||||
SmartScript* GetScript() { return &mScript; }
|
||||
static int Permissible(const GameObject* g);
|
||||
|
||||
bool GossipHello(Player* player) ;
|
||||
bool GossipSelect(Player* player, uint32 sender, uint32 action);
|
||||
bool GossipSelectCode(Player* /*player*/, uint32 /*sender*/, uint32 /*action*/, const char* /*code*/);
|
||||
bool QuestAccept(Player* player, Quest const* quest);
|
||||
bool QuestReward(Player* player, Quest const* quest, uint32 opt);
|
||||
uint32 GetDialogStatus(Player* /*player*/);
|
||||
void Destroyed(Player* player, uint32 eventId);
|
||||
void SetData(uint32 id, uint32 value);
|
||||
|
||||
protected:
|
||||
GameObject * const go;
|
||||
SmartScript mScript;
|
||||
};
|
||||
#endif
|
||||
1949
src/server/game/AI/SmartScripts/SmartScript.cpp
Normal file
1949
src/server/game/AI/SmartScripts/SmartScript.cpp
Normal file
File diff suppressed because it is too large
Load Diff
244
src/server/game/AI/SmartScripts/SmartScript.h
Normal file
244
src/server/game/AI/SmartScripts/SmartScript.h
Normal file
@@ -0,0 +1,244 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2010 TrinityCore <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TRINITY_SMARTSCRIPT_H
|
||||
#define TRINITY_SMARTSCRIPT_H
|
||||
|
||||
#include "Common.h"
|
||||
#include "Creature.h"
|
||||
#include "CreatureAI.h"
|
||||
#include "Unit.h"
|
||||
#include "ConditionMgr.h"
|
||||
#include "CreatureTextMgr.h"
|
||||
#include "Spell.h"
|
||||
#include "GridNotifiers.h"
|
||||
|
||||
#include "SmartScriptMgr.h"
|
||||
//#include "SmartAI.h"
|
||||
|
||||
class SmartScript
|
||||
{
|
||||
public:
|
||||
~SmartScript(){};
|
||||
SmartScript();
|
||||
|
||||
void OnInitialize(WorldObject* obj, AreaTriggerEntry const* at = NULL);
|
||||
void GetScript();
|
||||
void FillScript(SmartAIEventList e, WorldObject* obj, AreaTriggerEntry const* at);
|
||||
|
||||
void ProcessEventsFor(SMART_EVENT e, Unit* unit = NULL, uint32 var0 = 0, uint32 var1 = 0, bool bvar = false, const SpellEntry* spell = NULL, GameObject* gob = NULL);
|
||||
void ProcessEvent(SmartScriptHolder &e, Unit* unit = NULL, uint32 var0 = 0, uint32 var1 = 0, bool bvar = false, const SpellEntry* spell = NULL, GameObject* gob = NULL);
|
||||
bool CheckTimer(SmartScriptHolder &e);
|
||||
void RecalcTimer(SmartScriptHolder &e, uint32 min, uint32 max);
|
||||
void UpdateTimer(SmartScriptHolder &e, const uint32 diff);
|
||||
void InitTimer(SmartScriptHolder &e);
|
||||
void ProcessAction(SmartScriptHolder &e, Unit* unit = NULL, uint32 var0 = 0, uint32 var1 = 0, bool bvar = false, const SpellEntry* spell = NULL, GameObject* gob = NULL);
|
||||
ObjectList* GetTargets(SmartScriptHolder e, Unit* invoker = NULL);
|
||||
ObjectList* GetWorldObjectsInDist(float dist);
|
||||
void InstallTemplate(SmartScriptHolder e);
|
||||
SmartScriptHolder CreateEvent(SMART_EVENT e, uint32 event_flags, uint32 event_param1, uint32 event_param2, uint32 event_param3, uint32 event_param4, SMART_ACTION action, uint32 action_param1, uint32 action_param2, uint32 action_param3, uint32 action_param4, uint32 action_param5, uint32 action_param6, SMARTAI_TARGETS t, uint32 target_param1, uint32 target_param2, uint32 target_param3, uint32 phaseMask = 0);
|
||||
void AddEvent(SMART_EVENT e, uint32 event_flags, uint32 event_param1, uint32 event_param2, uint32 event_param3, uint32 event_param4, SMART_ACTION action, uint32 action_param1, uint32 action_param2, uint32 action_param3, uint32 action_param4, uint32 action_param5, uint32 action_param6, SMARTAI_TARGETS t, uint32 target_param1, uint32 target_param2, uint32 target_param3, uint32 phaseMask = 0);
|
||||
void SetPathId(uint32 id) { mPathId = id; }
|
||||
uint32 GetPathId() { return mPathId; }
|
||||
WorldObject* GetBaseObject()
|
||||
{
|
||||
WorldObject* obj = NULL;
|
||||
if (me)
|
||||
obj = me;
|
||||
else if (go)
|
||||
obj = go;
|
||||
return obj;
|
||||
}
|
||||
bool IsUnit(WorldObject* obj)
|
||||
{
|
||||
return obj && (obj->GetTypeId() == TYPEID_UNIT || obj->GetTypeId() == TYPEID_PLAYER);
|
||||
}
|
||||
bool IsPlayer(WorldObject* obj)
|
||||
{
|
||||
return obj && obj->GetTypeId() == TYPEID_PLAYER;
|
||||
}
|
||||
bool IsCreature(WorldObject* obj)
|
||||
{
|
||||
return obj && obj->GetTypeId() == TYPEID_UNIT;
|
||||
}
|
||||
bool IsGameObject(WorldObject* obj)
|
||||
{
|
||||
return obj && obj->GetTypeId() == TYPEID_GAMEOBJECT;
|
||||
}
|
||||
bool ConditionValid(Unit* u, int32 c, int32 v1, int32 v2, int32 v3)
|
||||
{
|
||||
if (c == 0) return true;
|
||||
if (!u || !u->ToPlayer()) return false;
|
||||
Condition cond;
|
||||
cond.mConditionType = ConditionType(uint32(c));
|
||||
cond.mConditionValue1 = uint32(v1);
|
||||
cond.mConditionValue1 = uint32(v2);
|
||||
cond.mConditionValue1 = uint32(v3);
|
||||
return cond.Meets(u->ToPlayer());
|
||||
}
|
||||
|
||||
void OnUpdate(const uint32 diff);
|
||||
void OnMoveInLineOfSight(Unit *who);
|
||||
|
||||
Unit* DoSelectLowestHpFriendly(float range, uint32 MinHPDiff);
|
||||
void DoFindFriendlyCC(std::list<Creature*>& _list, float range);
|
||||
void DoFindFriendlyMissingBuff(std::list<Creature*>& _list, float range, uint32 spellid);
|
||||
|
||||
void StoreTargetList(ObjectList* targets, uint32 id)
|
||||
{
|
||||
if (!targets) return;
|
||||
if(mTargetStorage->find(id) != mTargetStorage->end())
|
||||
mTargetStorage->erase(id);
|
||||
(*mTargetStorage)[id] = targets;
|
||||
}
|
||||
bool IsSmart(Creature* c = NULL)
|
||||
{
|
||||
if (c && c->GetAIName() != "SmartAI") return false;
|
||||
if (!me || me->GetAIName() != "SmartAI") return false;
|
||||
return true;
|
||||
}
|
||||
ObjectList* GetTargetList(uint32 id)
|
||||
{
|
||||
ObjectListMap::iterator itr = mTargetStorage->find(id);
|
||||
if(itr != mTargetStorage->end())
|
||||
return (*itr).second;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
inline GameObject* FindGameObjectNear(WorldObject* pSearchObject, uint32 guid) const
|
||||
{
|
||||
GameObject *pGameObject = NULL;
|
||||
|
||||
CellPair p(Trinity::ComputeCellPair(pSearchObject->GetPositionX(), pSearchObject->GetPositionY()));
|
||||
Cell cell(p);
|
||||
cell.data.Part.reserved = ALL_DISTRICT;
|
||||
|
||||
Trinity::GameObjectWithDbGUIDCheck goCheck(*pSearchObject, guid);
|
||||
Trinity::GameObjectSearcher<Trinity::GameObjectWithDbGUIDCheck> checker(pSearchObject, pGameObject, goCheck);
|
||||
|
||||
TypeContainerVisitor<Trinity::GameObjectSearcher<Trinity::GameObjectWithDbGUIDCheck>, GridTypeMapContainer > objectChecker(checker);
|
||||
cell.Visit(p, objectChecker, *pSearchObject->GetMap());
|
||||
|
||||
return pGameObject;
|
||||
}
|
||||
|
||||
inline Creature* FindCreatureNear(WorldObject* pSearchObject, uint32 guid) const
|
||||
{
|
||||
Creature *crea = NULL;
|
||||
CellPair p(Trinity::ComputeCellPair(pSearchObject->GetPositionX(), pSearchObject->GetPositionY()));
|
||||
Cell cell(p);
|
||||
cell.data.Part.reserved = ALL_DISTRICT;
|
||||
|
||||
Trinity::CreatureWithDbGUIDCheck target_check(pSearchObject, guid);
|
||||
Trinity::CreatureSearcher<Trinity::CreatureWithDbGUIDCheck> checker(pSearchObject, crea, target_check);
|
||||
|
||||
TypeContainerVisitor<Trinity::CreatureSearcher <Trinity::CreatureWithDbGUIDCheck>, GridTypeMapContainer > unit_checker(checker);
|
||||
cell.Visit(p, unit_checker, *pSearchObject->GetMap());
|
||||
|
||||
return crea;
|
||||
}
|
||||
|
||||
ObjectListMap* mTargetStorage;
|
||||
void ResetTexts() { mTextIDs.clear(); }
|
||||
|
||||
void OnReset();
|
||||
void ResetBaseObject()
|
||||
{
|
||||
if (meOrigGUID)
|
||||
{
|
||||
if (Creature* m = HashMapHolder<Creature>::Find(meOrigGUID))
|
||||
{
|
||||
me = m;
|
||||
go = NULL;
|
||||
}
|
||||
}
|
||||
if (goOrigGUID)
|
||||
{
|
||||
if (GameObject* o = HashMapHolder<GameObject>::Find(goOrigGUID))
|
||||
{
|
||||
me = NULL;
|
||||
go = o;
|
||||
}
|
||||
}
|
||||
goOrigGUID = 0;
|
||||
meOrigGUID = 0;
|
||||
}
|
||||
|
||||
private:
|
||||
void IncPhase(int32 p = 1) { p >= 0 ? mEventPhase += (uint32)p : DecPhase(abs(p)); }
|
||||
void DecPhase(int32 p = 1) { mEventPhase -= (mEventPhase < (uint32)p ? (uint32)p - mEventPhase : (uint32)p); }
|
||||
bool IsInPhase(uint32 p) { return mEventPhase & p; }
|
||||
void SetPhase(uint32 p = 0) { mEventPhase = p; }
|
||||
|
||||
SmartAIEventList mEvents;
|
||||
SmartAIEventList mInstallEvents;
|
||||
Creature* me;
|
||||
uint64 meOrigGUID;
|
||||
GameObject* go;
|
||||
uint64 goOrigGUID;
|
||||
AreaTriggerEntry const* trigger;
|
||||
SmartScriptType mScriptType;
|
||||
uint32 mEventPhase;
|
||||
|
||||
uint32 mInvinceabilityHpLevel;
|
||||
UNORDERED_MAP<int32, int32> mStoredDecimals;
|
||||
uint32 mPathId;
|
||||
SmartAIEventList mStoredEvents;
|
||||
std::list<uint32>mRemIDs;
|
||||
|
||||
std::vector<uint32>mTextIDs;
|
||||
uint32 mTextTimer;
|
||||
uint32 mLastTextID;
|
||||
uint64 mTextGUID;
|
||||
bool mUseTextTimer;
|
||||
SMARTAI_TEMPLATE mTemplate;
|
||||
void InstallEvents();
|
||||
|
||||
void RemoveStoredEvent (uint32 id)
|
||||
{
|
||||
if (!mStoredEvents.empty())
|
||||
{
|
||||
for (SmartAIEventList::iterator i = mStoredEvents.begin(); i != mStoredEvents.end(); ++i)
|
||||
{
|
||||
if (i->event_id = id)
|
||||
{
|
||||
mStoredEvents.erase(i);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
SmartScriptHolder FindLinkedEvent (uint32 link)
|
||||
{
|
||||
if (!mEvents.empty())
|
||||
{
|
||||
for (SmartAIEventList::iterator i = mEvents.begin(); i != mEvents.end(); ++i)
|
||||
{
|
||||
if (i->event_id == link)
|
||||
{
|
||||
return (*i);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
SmartScriptHolder s;
|
||||
return s;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
776
src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
Normal file
776
src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
Normal file
@@ -0,0 +1,776 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2010 TrinityCore <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include "DatabaseEnv.h"
|
||||
#include "SQLStorage.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "ProgressBar.h"
|
||||
#include "ObjectDefines.h"
|
||||
#include "GridDefines.h"
|
||||
#include "GridNotifiers.h"
|
||||
#include "SpellMgr.h"
|
||||
#include "GridNotifiersImpl.h"
|
||||
#include "Cell.h"
|
||||
#include "CellImpl.h"
|
||||
#include "InstanceScript.h"
|
||||
#include "ScriptedCreature.h"
|
||||
|
||||
#include "SmartScriptMgr.h"
|
||||
|
||||
void SmartWaypointMgr::LoadFromDB()
|
||||
{
|
||||
waypoint_map.clear();
|
||||
|
||||
PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_LOAD_SMARTAI_WP);
|
||||
PreparedQueryResult result = WorldDatabase.Query(stmt);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
barGoLink bar(1);
|
||||
bar.step();
|
||||
sLog.outString();
|
||||
sLog.outString(">> Loaded 0 SmartAI Waypoint Paths. DB table `waypoints` is empty.");
|
||||
return;
|
||||
}
|
||||
|
||||
WPPath* path = NULL;
|
||||
uint32 last_entry = 0;
|
||||
uint32 last_id = 1;
|
||||
barGoLink bar(result->GetRowCount());
|
||||
uint32 count = 0;
|
||||
uint32 total = 0;
|
||||
|
||||
do
|
||||
{
|
||||
bar.step();
|
||||
Field *fields = result->Fetch();
|
||||
uint32 entry = fields[0].GetUInt32();
|
||||
uint32 id = fields[1].GetUInt32();
|
||||
float x,y,z;
|
||||
x = fields[2].GetFloat();
|
||||
y = fields[3].GetFloat();
|
||||
z = fields[4].GetFloat();
|
||||
|
||||
|
||||
WayPoint *wp = new WayPoint(id, x, y, z);
|
||||
|
||||
if (last_entry != entry)
|
||||
{
|
||||
path = new WPPath;
|
||||
last_id = 1;
|
||||
}
|
||||
if (last_id != id)
|
||||
{
|
||||
sLog.outErrorDb("SmartWaypointMgr::LoadFromDB: Path entry %u, unexpected point id %u, expected %u.", entry, id, last_id);
|
||||
}
|
||||
last_id++;
|
||||
(*path)[id] = wp;
|
||||
|
||||
if (last_entry != entry)
|
||||
{
|
||||
count++;
|
||||
waypoint_map[entry] = path;
|
||||
}
|
||||
last_entry = entry;
|
||||
total++;
|
||||
} while (result->NextRow());
|
||||
|
||||
sLog.outString();
|
||||
sLog.outString(">> Loaded %u SmartAI Waypoint Paths, total %u waypoints.", count, total);
|
||||
}
|
||||
|
||||
void SmartAIMgr::LoadSmartAIFromDB()
|
||||
{
|
||||
for (uint8 i = 0; i < SMART_SCRIPT_TYPE_MAX; i++)
|
||||
mEventMap[i].clear(); //Drop Existing SmartAI List
|
||||
|
||||
PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_LOAD_SMART_SCRIPTS);
|
||||
PreparedQueryResult result = WorldDatabase.Query(stmt);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
barGoLink bar(1);
|
||||
bar.step();
|
||||
sLog.outString();
|
||||
sLog.outString(">> Loaded 0 SmartAI scripts. DB table `smartai_scripts` is empty.");
|
||||
return;
|
||||
}
|
||||
|
||||
barGoLink bar(result->GetRowCount());
|
||||
uint32 ScriptCount = 0;
|
||||
|
||||
do
|
||||
{
|
||||
bar.step();
|
||||
Field* fields = result->Fetch();
|
||||
|
||||
SmartScriptHolder temp;
|
||||
|
||||
temp.entryOrGuid = fields[0].GetInt32();
|
||||
SmartScriptType source_type = (SmartScriptType)fields[1].GetUInt32();
|
||||
if (source_type >= SMART_SCRIPT_TYPE_MAX)
|
||||
{
|
||||
sLog.outErrorDb("SmartAIMgr::LoadSmartAIFromDB: invalid source_type (%u), skipped loading.", uint32(source_type));
|
||||
continue;
|
||||
}
|
||||
if (temp.entryOrGuid >= 0)
|
||||
{
|
||||
switch(source_type)
|
||||
{
|
||||
case SMART_SCRIPT_TYPE_CREATURE:
|
||||
{
|
||||
if (!sCreatureStorage.LookupEntry<CreatureInfo>((uint32)temp.entryOrGuid))
|
||||
{
|
||||
sLog.outErrorDb("SmartAIMgr::LoadSmartAIFromDB: Creature entry (%u) does not exist, skipped loading.", uint32(temp.entryOrGuid));
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SMART_SCRIPT_TYPE_GAMEOBJECT:
|
||||
{
|
||||
if (!sGOStorage.LookupEntry<GameObjectInfo>((uint32)temp.entryOrGuid))
|
||||
{
|
||||
sLog.outErrorDb("SmartAIMgr::LoadSmartAIFromDB: GameObject entry (%u) does not exist, skipped loading.", uint32(temp.entryOrGuid));
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SMART_SCRIPT_TYPE_AREATRIGGER:
|
||||
{
|
||||
if (!sAreaTriggerStore.LookupEntry((uint32)temp.entryOrGuid))
|
||||
{
|
||||
sLog.outErrorDb("SmartAIMgr::LoadSmartAIFromDB: AreaTrigger entry (%u) does not exist, skipped loading.", uint32(temp.entryOrGuid));
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
sLog.outErrorDb("SmartAIMgr::LoadSmartAIFromDB: not yet implemented source_type %u", (uint32)source_type);
|
||||
continue;
|
||||
}
|
||||
}else
|
||||
{
|
||||
if (!sObjectMgr.GetCreatureData(uint32(abs(temp.entryOrGuid))))
|
||||
{
|
||||
sLog.outErrorDb("SmartAIMgr::LoadSmartAIFromDB: Creature guid (%u) does not exist, skipped loading.", uint32(abs(temp.entryOrGuid)));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
temp.source_type = source_type;
|
||||
temp.event_id = fields[2].GetUInt32();
|
||||
temp.link = fields[3].GetUInt32();
|
||||
temp.event.type = (SMART_EVENT)fields[4].GetUInt32();
|
||||
temp.event.event_phase_mask = fields[5].GetUInt32();
|
||||
temp.event.event_chance = fields[6].GetUInt32();
|
||||
temp.event.event_flags = fields[7].GetUInt32();
|
||||
|
||||
temp.event.raw.param1 = fields[8].GetUInt32();
|
||||
temp.event.raw.param2 = fields[9].GetUInt32();
|
||||
temp.event.raw.param3 = fields[10].GetUInt32();
|
||||
temp.event.raw.param4 = fields[11].GetUInt32();
|
||||
|
||||
temp.action.type = (SMART_ACTION)fields[12].GetUInt32();
|
||||
|
||||
temp.action.raw.param1 = fields[13].GetUInt32();
|
||||
temp.action.raw.param2 = fields[14].GetUInt32();
|
||||
temp.action.raw.param3 = fields[15].GetUInt32();
|
||||
temp.action.raw.param4 = fields[16].GetUInt32();
|
||||
temp.action.raw.param5 = fields[17].GetUInt32();
|
||||
temp.action.raw.param6 = fields[18].GetUInt32();
|
||||
|
||||
temp.target.type = (SMARTAI_TARGETS)fields[19].GetUInt32();
|
||||
temp.target.raw.param1 = fields[20].GetUInt32();
|
||||
temp.target.raw.param2 = fields[21].GetUInt32();
|
||||
temp.target.raw.param3 = fields[22].GetUInt32();
|
||||
temp.target.x = fields[23].GetFloat();
|
||||
temp.target.y = fields[24].GetFloat();
|
||||
temp.target.z = fields[25].GetFloat();
|
||||
temp.target.o = fields[26].GetFloat();
|
||||
|
||||
//check target
|
||||
if (!IsTargetValid(temp))
|
||||
continue;
|
||||
|
||||
// check all event and action params
|
||||
if (!IsEventValid(temp))
|
||||
continue;
|
||||
|
||||
// creature entry / guid not found in storage, create empty event list for it and increase counters
|
||||
if (mEventMap[source_type].find(temp.entryOrGuid) == mEventMap[source_type].end())
|
||||
{
|
||||
++ScriptCount;
|
||||
SmartAIEventList eventList;
|
||||
mEventMap[source_type][temp.entryOrGuid] = eventList;
|
||||
}
|
||||
// store the new event
|
||||
mEventMap[source_type][temp.entryOrGuid].push_back(temp);
|
||||
} while (result->NextRow());
|
||||
|
||||
sLog.outString();
|
||||
sLog.outString(">> Loaded %u SmartAI scripts.", ScriptCount);
|
||||
}
|
||||
|
||||
bool SmartAIMgr::IsTargetValid(SmartScriptHolder e)
|
||||
{
|
||||
if (e.GetActionType() == SMART_ACTION_INSTALL_AI_TEMPLATE)
|
||||
return true; //AI template has special handling
|
||||
switch (e.GetTargetType())
|
||||
{
|
||||
case SMART_TARGET_CREATURE_DISTANCE:
|
||||
case SMART_TARGET_CREATURE_RANGE:
|
||||
{
|
||||
if (e.target.unitDistance.creature && !sCreatureStorage.LookupEntry<CreatureInfo>(e.target.unitDistance.creature))
|
||||
{
|
||||
sLog.outErrorDb("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Creature entry %u as target_param1, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.target.unitDistance.creature);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SMART_TARGET_GAMEOBJECT_DISTANCE:
|
||||
case SMART_TARGET_GAMEOBJECT_RANGE:
|
||||
{
|
||||
if (e.target.goDistance.entry && !sGOStorage.LookupEntry<GameObjectInfo>(e.target.goDistance.entry))
|
||||
{
|
||||
sLog.outErrorDb("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent GameObject entry %u as target_param1, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.target.goDistance.entry);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SMART_TARGET_CREATURE_GUID:
|
||||
{
|
||||
if (e.target.unitGUID.entry && !IsCreatureValid(e, e.target.unitGUID.entry)) return false;
|
||||
break;
|
||||
}
|
||||
case SMART_TARGET_GAMEOBJECT_GUID:
|
||||
{
|
||||
if (e.target.goGUID.entry && !IsGameObjectValid(e, e.target.goGUID.entry)) return false;
|
||||
break;
|
||||
}
|
||||
case SMART_TARGET_PLAYER_RANGE:
|
||||
case SMART_TARGET_PLAYER_DISTANCE:
|
||||
case SMART_TARGET_SELF:
|
||||
case SMART_TARGET_VICTIM:
|
||||
case SMART_TARGET_HOSTILE_SECOND_AGGRO:
|
||||
case SMART_TARGET_HOSTILE_LAST_AGGRO:
|
||||
case SMART_TARGET_HOSTILE_RANDOM:
|
||||
case SMART_TARGET_HOSTILE_RANDOM_NOT_TOP:
|
||||
case SMART_TARGET_ACTION_INVOKER:
|
||||
case SMART_TARGET_POSITION:
|
||||
case SMART_TARGET_NONE:
|
||||
case SMART_TARGET_CLOSEST_CREATURE:
|
||||
case SMART_TARGET_CLOSEST_GAMEOBJECT:
|
||||
case SMART_TARGET_CLOSEST_PLAYER:
|
||||
break;
|
||||
default:
|
||||
sLog.outErrorDb("SmartAIMgr: Not handled target_type(%u), Entry %d SourceType %u Event %u Action %u, skipped.", e.GetTargetType(), e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SmartAIMgr::IsEventValid(SmartScriptHolder e)
|
||||
{
|
||||
if (e.event.type >= SMART_EVENT_END)
|
||||
{
|
||||
sLog.outErrorDb("SmartAIMgr: EntryOrGuid %d using event(%u) has invalid event type (%u), skipped.", e.entryOrGuid, e.event_id, e.GetEventType());
|
||||
return false;
|
||||
}
|
||||
if (!(SmartAIEventMask[e.event.type][1] & SmartAITypeMask[e.GetScriptType()][1]))
|
||||
{
|
||||
sLog.outErrorDb("SmartAIMgr: EntryOrGuid %d, event type %u can not be used for Script type %u", e.entryOrGuid, e.GetEventType(), e.GetScriptType());
|
||||
return false;
|
||||
}
|
||||
if (e.action.type >= SMART_ACTION_END)
|
||||
{
|
||||
sLog.outErrorDb("SmartAIMgr: EntryOrGuid %d using event(%u) has invalid action type (%u), skipped.", e.entryOrGuid, e.event_id, e.GetActionType());
|
||||
return false;
|
||||
}
|
||||
if (e.event.event_phase_mask > SMART_EVENT_PHASE_ALL)
|
||||
{
|
||||
sLog.outErrorDb("SmartAIMgr: EntryOrGuid %d using event(%u) has invalid phase mask (%u), skipped.", e.entryOrGuid, e.event_id, e.event.event_phase_mask);
|
||||
return false;
|
||||
}
|
||||
switch (e.event.type)
|
||||
{
|
||||
case SMART_EVENT_UPDATE:
|
||||
case SMART_EVENT_UPDATE_IC:
|
||||
case SMART_EVENT_UPDATE_OOC:
|
||||
case SMART_EVENT_HEALT_PCT:
|
||||
case SMART_EVENT_MANA_PCT:
|
||||
case SMART_EVENT_TARGET_HEALTH_PCT:
|
||||
case SMART_EVENT_TARGET_MANA_PCT:
|
||||
case SMART_EVENT_RANGE:
|
||||
case SMART_EVENT_DAMAGED:
|
||||
case SMART_EVENT_DAMAGED_TARGET:
|
||||
case SMART_EVENT_RECEIVE_HEAL:
|
||||
if (!IsMinMaxValid(e, e.event.minMaxRepeat.min, e.event.minMaxRepeat.max)) return false;
|
||||
if (!IsMinMaxValid(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax)) return false;
|
||||
break;
|
||||
case SMART_EVENT_SPELLHIT:
|
||||
case SMART_EVENT_SPELLHIT_TARGET:
|
||||
if (e.event.spellHit.spell)
|
||||
{
|
||||
SpellEntry const* pSpell = sSpellStore.LookupEntry(e.event.spellHit.spell);
|
||||
if (!pSpell)
|
||||
{
|
||||
sLog.outErrorDb("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Spell entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.spellHit.spell);
|
||||
return false;
|
||||
}
|
||||
if (e.event.spellHit.school && (e.event.spellHit.school & pSpell->SchoolMask) != pSpell->SchoolMask)
|
||||
{
|
||||
sLog.outErrorDb("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses Spell entry %u with invalid school mask, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.spellHit.spell);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!IsMinMaxValid(e, e.event.spellHit.cooldownMin, e.event.spellHit.cooldownMax)) return false;
|
||||
break;
|
||||
case SMART_EVENT_OOC_LOS:
|
||||
case SMART_EVENT_IC_LOS:
|
||||
if (!IsMinMaxValid(e, e.event.los.cooldownMin, e.event.los.cooldownMax)) return false;
|
||||
break;
|
||||
case SMART_EVENT_RESPAWN:
|
||||
if (e.event.respawn.type == SMART_SCRIPT_RESPAWN_CONDITION_MAP && !sMapStore.LookupEntry(e.event.respawn.map))
|
||||
{
|
||||
sLog.outErrorDb("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Map entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.respawn.map);
|
||||
return false;
|
||||
}
|
||||
if (e.event.respawn.type == SMART_SCRIPT_RESPAWN_CONDITION_AREA && !GetAreaEntryByAreaID(e.event.respawn.area))
|
||||
{
|
||||
sLog.outErrorDb("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Area entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.respawn.area);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case SMART_EVENT_FRIENDLY_HEALTH:
|
||||
if (!NotNULL(e, e.event.friendlyHealt.radius)) return false;
|
||||
if (!IsMinMaxValid(e, e.event.friendlyHealt.repeatMin, e.event.friendlyHealt.repeatMax)) return false;
|
||||
break;
|
||||
case SMART_EVENT_FRIENDLY_IS_CC:
|
||||
if (!IsMinMaxValid(e, e.event.friendlyCC.repeatMin, e.event.friendlyCC.repeatMax)) return false;
|
||||
break;
|
||||
case SMART_EVENT_FRIENDLY_MISSING_BUFF:
|
||||
{
|
||||
if (!IsSpellValid(e, e.event.missingBuff.spell)) return false;
|
||||
if (!NotNULL(e, e.event.missingBuff.radius)) return false;
|
||||
if (!IsMinMaxValid(e, e.event.missingBuff.repeatMin, e.event.missingBuff.repeatMax)) return false;
|
||||
break;
|
||||
}
|
||||
case SMART_EVENT_KILL:
|
||||
if (!IsMinMaxValid(e, e.event.kill.cooldownMin, e.event.kill.cooldownMax)) return false;
|
||||
if (e.event.kill.creature && !IsCreatureValid(e, e.event.kill.creature)) return false;
|
||||
break;
|
||||
case SMART_EVENT_TARGET_CASTING:
|
||||
case SMART_EVENT_PASSENGER_BOARDED:
|
||||
case SMART_EVENT_PASSENGER_REMOVED:
|
||||
if (!IsMinMaxValid(e, e.event.minMax.repeatMin, e.event.minMax.repeatMax)) return false;
|
||||
break;
|
||||
case SMART_EVENT_SUMMON_DESPAWNED:
|
||||
case SMART_EVENT_SUMMONED_UNIT:
|
||||
if (e.event.summoned.creature && !IsCreatureValid(e, e.event.summoned.creature)) return false;
|
||||
if (!IsMinMaxValid(e, e.event.summoned.cooldownMin, e.event.summoned.cooldownMax)) return false;
|
||||
break;
|
||||
case SMART_EVENT_ACCEPTED_QUEST:
|
||||
case SMART_EVENT_REWARD_QUEST:
|
||||
if (!IsQuestValid(e, e.event.quest.quest)) return false;
|
||||
break;
|
||||
case SMART_EVENT_RECEIVE_EMOTE:
|
||||
{
|
||||
if (e.event.emote.emote && !IsEmoteValid(e, e.event.emote.emote)) return false;
|
||||
if (!IsMinMaxValid(e, e.event.emote.cooldownMin, e.event.emote.cooldownMax)) return false;
|
||||
break;
|
||||
}
|
||||
case SMART_EVENT_HAS_AURA:
|
||||
case SMART_EVENT_TARGET_BUFFED:
|
||||
{
|
||||
if (!IsSpellValid(e, e.event.aura.spell)) return false;
|
||||
if (!IsMinMaxValid(e, e.event.aura.repeatMin, e.event.aura.repeatMax)) return false;
|
||||
break;
|
||||
}
|
||||
case SMART_EVENT_TRANSPORT_ADDCREATURE:
|
||||
{
|
||||
if (e.event.transportAddCreature.creature && !IsCreatureValid(e, e.event.transportAddCreature.creature)) return false;
|
||||
break;
|
||||
}
|
||||
case SMART_EVENT_MOVEMENTINFORM:
|
||||
{
|
||||
if (e.event.movementInform.type > NULL_MOTION_TYPE)
|
||||
{
|
||||
sLog.outErrorDb("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses invalid Motion type %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.movementInform.type);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SMART_EVENT_DATA_SET:
|
||||
{
|
||||
if (!IsMinMaxValid(e, e.event.dataSet.cooldownMin, e.event.dataSet.cooldownMax)) return false;
|
||||
break;
|
||||
}
|
||||
case SMART_EVENT_AREATRIGGER_ONTRIGGER:
|
||||
{
|
||||
if (e.event.areatrigger.id && !IsAreaTriggerValid(e, e.event.areatrigger.id)) return false;
|
||||
break;
|
||||
}
|
||||
case SMART_EVENT_TEXT_OVER:
|
||||
if (e.event.textOver.textGroupID && !IsTextValid(e, e.event.textOver.textGroupID)) return false;
|
||||
break;
|
||||
case SMART_EVENT_LINK:
|
||||
{
|
||||
if (e.link && e.link == e.event_id)
|
||||
{
|
||||
sLog.outErrorDb("SmartAIMgr: Entry %d SourceType %u, Event %u, Link Event is linking self (infinite loop), skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SMART_EVENT_TIMED_EVENT_TRIGGERED:
|
||||
case SMART_EVENT_INSTANCE_PLAYER_ENTER:
|
||||
case SMART_EVENT_TRANSPORT_RELOCATE:
|
||||
case SMART_EVENT_CHARMED:
|
||||
case SMART_EVENT_CHARMED_TARGET:
|
||||
case SMART_EVENT_CORPSE_REMOVED:
|
||||
case SMART_EVENT_AI_INIT:
|
||||
case SMART_EVENT_TRANSPORT_ADDPLAYER:
|
||||
case SMART_EVENT_TRANSPORT_REMOVE_PLAYER:
|
||||
case SMART_EVENT_AGGRO:
|
||||
case SMART_EVENT_DEATH:
|
||||
case SMART_EVENT_EVADE:
|
||||
case SMART_EVENT_REACHED_HOME:
|
||||
case SMART_EVENT_RESET:
|
||||
case SMART_EVENT_QUEST_ACCEPTED:
|
||||
case SMART_EVENT_QUEST_OBJ_COPLETETION:
|
||||
case SMART_EVENT_QUEST_COMPLETION:
|
||||
case SMART_EVENT_QUEST_REWARDED:
|
||||
case SMART_EVENT_QUEST_FAIL:
|
||||
case SMART_EVENT_JUST_SUMMONED:
|
||||
case SMART_EVENT_WAYPOINT_START:
|
||||
case SMART_EVENT_WAYPOINT_REACHED:
|
||||
case SMART_EVENT_WAYPOINT_PAUSED:
|
||||
case SMART_EVENT_WAYPOINT_RESUMED:
|
||||
case SMART_EVENT_WAYPOINT_STOPPED:
|
||||
case SMART_EVENT_WAYPOINT_ENDED:
|
||||
case SMART_ACTION_PLAYMOVIE:
|
||||
case SMART_EVENT_GOSSIP_SELECT:
|
||||
case SMART_EVENT_GOSSIP_HELLO:
|
||||
case SMART_EVENT_JUST_CREATED:
|
||||
case SMART_EVENT_FOLLOW_COPMLETE:
|
||||
break;
|
||||
default:
|
||||
sLog.outErrorDb("SmartAIMgr: Not handled event_type(%u), Entry %d SourceType %u Event %u Action %u, skipped.", e.GetEventType(), e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
|
||||
return false;
|
||||
}
|
||||
switch (e.GetActionType())
|
||||
{
|
||||
case SMART_ACTION_TALK:
|
||||
if (!IsTextValid(e, e.action.talk.textGroupID1)) return false;
|
||||
if (e.action.talk.textGroupID2 && !IsTextValid(e, e.action.talk.textGroupID2)) return false;
|
||||
if (e.action.talk.textGroupID3 && !IsTextValid(e, e.action.talk.textGroupID3)) return false;
|
||||
if (e.action.talk.textGroupID4 && !IsTextValid(e, e.action.talk.textGroupID4)) return false;
|
||||
if (e.action.talk.textGroupID5 && !IsTextValid(e, e.action.talk.textGroupID5)) return false;
|
||||
if (e.action.talk.textGroupID6 && !IsTextValid(e, e.action.talk.textGroupID6)) return false;
|
||||
|
||||
break;
|
||||
case SMART_ACTION_SET_FACTION:
|
||||
if (e.action.faction.factionID && !sFactionStore.LookupEntry(e.action.faction.factionID))
|
||||
{
|
||||
sLog.outErrorDb("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Faction %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.faction.factionID);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case SMART_ACTION_MORPH_TO_ENTRY_OR_MODEL:
|
||||
case SMART_ACTION_MOUNT_TO_ENTRY_OR_MODEL:
|
||||
if (e.action.morphOrMount.creature || e.action.morphOrMount.model)
|
||||
{
|
||||
if (e.action.morphOrMount.creature > 0 && !sCreatureStorage.LookupEntry<CreatureInfo>(e.action.morphOrMount.creature))
|
||||
{
|
||||
sLog.outErrorDb("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Creature entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.morphOrMount.creature);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (e.action.morphOrMount.model)
|
||||
{
|
||||
if (e.action.morphOrMount.creature)
|
||||
{
|
||||
sLog.outErrorDb("SmartAIMgr: Entry %d SourceType %u Event %u Action %u has ModelID set with also set CreatureId, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
|
||||
return false;
|
||||
}
|
||||
else if (!sCreatureDisplayInfoStore.LookupEntry(e.action.morphOrMount.model))
|
||||
{
|
||||
sLog.outErrorDb("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Model id %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.morphOrMount.model);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SMART_ACTION_SOUND:
|
||||
if (!IsSoundValid(e, e.action.sound.sound)) return false;
|
||||
if (e.action.sound.range > TEXT_RANGE_WORLD)
|
||||
{
|
||||
sLog.outErrorDb("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses invalid Text Range %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.sound.range);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case SMART_ACTION_SET_EMOTE_STATE:
|
||||
case SMART_ACTION_PLAY_EMOTE:
|
||||
if (!IsEmoteValid(e, e.action.emote.emote)) return false;
|
||||
break;
|
||||
case SMART_ACTION_FAIL_QUEST:
|
||||
case SMART_ACTION_ADD_QUEST:
|
||||
if (e.action.quest.quest && !IsQuestValid(e, e.action.quest.quest)) return false;
|
||||
break;
|
||||
case SMART_ACTION_RANDOM_EMOTE:
|
||||
if (e.action.randomEmote.emote1 && !IsEmoteValid(e, e.action.randomEmote.emote1)) return false;
|
||||
if (e.action.randomEmote.emote2 && !IsEmoteValid(e, e.action.randomEmote.emote2)) return false;
|
||||
if (e.action.randomEmote.emote3 && !IsEmoteValid(e, e.action.randomEmote.emote3)) return false;
|
||||
if (e.action.randomEmote.emote4 && !IsEmoteValid(e, e.action.randomEmote.emote4)) return false;
|
||||
if (e.action.randomEmote.emote5 && !IsEmoteValid(e, e.action.randomEmote.emote5)) return false;
|
||||
if (e.action.randomEmote.emote6 && !IsEmoteValid(e, e.action.randomEmote.emote6)) return false;
|
||||
break;
|
||||
case SMART_ACTION_ADD_AURA:
|
||||
case SMART_ACTION_CAST:
|
||||
if (!IsSpellValid(e, e.action.cast.spell)) return false;
|
||||
break;
|
||||
case SMART_ACTION_CALL_AREAEXPLOREDOREVENTHAPPENS:
|
||||
case SMART_ACTION_CALL_GROUPEVENTHAPPENS:
|
||||
if (Quest const* qid = sObjectMgr.GetQuestTemplate(e.action.quest.quest))
|
||||
{
|
||||
if (!qid->HasFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT))
|
||||
{
|
||||
sLog.outErrorDb("SmartAIMgr: Entry %d SourceType %u Event %u Action %u SpecialFlags for Quest entry %u does not include FLAGS_EXPLORATION_OR_EVENT(2), skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.quest.quest);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sLog.outErrorDb("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Quest entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.quest.quest);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case SMART_ACTION_SEND_CASTCREATUREORGO:
|
||||
if (!IsQuestValid(e, e.action.castCreatureOrGO.quest)) return false;
|
||||
if (!IsSpellValid(e, e.action.castCreatureOrGO.spell)) return false;
|
||||
break;
|
||||
|
||||
|
||||
|
||||
case SMART_ACTION_SET_EVENT_PHASE:
|
||||
if (e.action.setEventPhase.phase >= SMART_EVENT_PHASE_MAX)
|
||||
{
|
||||
sLog.outErrorDb("SmartAIMgr: Entry %d SourceType %u Event %u Action %u attempts to set phase %u. Phase mask cannot be used past phase %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.setEventPhase.phase, SMART_EVENT_PHASE_MAX-1);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case SMART_ACTION_INC_EVENT_PHASE:
|
||||
if (!e.action.incEventPhase.inc && !e.action.incEventPhase.dec)
|
||||
{
|
||||
sLog.outErrorDb("SmartAIMgr: Entry %d SourceType %u Event %u Action %u is incrementing phase by 0, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
|
||||
return false;
|
||||
}
|
||||
else if (e.action.incEventPhase.inc > SMART_EVENT_PHASE_MAX || e.action.incEventPhase.dec > SMART_EVENT_PHASE_MAX)
|
||||
{
|
||||
sLog.outErrorDb("SmartAIMgr: Entry %d SourceType %u Event %u Action %u attempts to increment phase by too large value, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case SMART_ACTION_CALL_CASTEDCREATUREORGO:
|
||||
if (!IsCreatureValid(e, e.action.castedCreatureOrGO.creature)) return false;
|
||||
if (!IsSpellValid(e, e.action.castedCreatureOrGO.spell)) return false;
|
||||
break;
|
||||
case SMART_ACTION_REMOVEAURASFROMSPELL:
|
||||
if (!IsSpellValid(e, e.action.removeAura.spell)) return false;
|
||||
break;
|
||||
case SMART_ACTION_RANDOM_PHASE:
|
||||
{
|
||||
if (e.action.randomPhase.phase1 >= SMART_EVENT_PHASE_MAX ||
|
||||
e.action.randomPhase.phase2 >= SMART_EVENT_PHASE_MAX ||
|
||||
e.action.randomPhase.phase3 >= SMART_EVENT_PHASE_MAX ||
|
||||
e.action.randomPhase.phase4 >= SMART_EVENT_PHASE_MAX ||
|
||||
e.action.randomPhase.phase5 >= SMART_EVENT_PHASE_MAX ||
|
||||
e.action.randomPhase.phase6 >= SMART_EVENT_PHASE_MAX)
|
||||
{
|
||||
sLog.outErrorDb("SmartAIMgr: Entry %d SourceType %u Event %u Action %u attempts to set invalid phase, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SMART_ACTION_RANDOM_PHASE_RANGE: //PhaseMin, PhaseMax
|
||||
{
|
||||
if (e.action.randomPhaseRange.phaseMin >= SMART_EVENT_PHASE_MAX ||
|
||||
e.action.randomPhaseRange.phaseMax >= SMART_EVENT_PHASE_MAX)
|
||||
{
|
||||
sLog.outErrorDb("SmartAIMgr: Entry %d SourceType %u Event %u Action %u attempts to set invalid phase, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
|
||||
return false;
|
||||
}
|
||||
if (!IsMinMaxValid(e, e.action.randomPhaseRange.phaseMin, e.action.randomPhaseRange.phaseMax)) return false;
|
||||
break;
|
||||
}
|
||||
case SMART_ACTION_SUMMON_CREATURE:
|
||||
if (!IsCreatureValid(e, e.action.summonCreature.creature)) return false;
|
||||
if (e.action.summonCreature.type > TEMPSUMMON_MANUAL_DESPAWN)
|
||||
{
|
||||
sLog.outErrorDb("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses incorrect TempSummonType %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.summonCreature.type);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case SMART_ACTION_CALL_KILLEDMONSTER:
|
||||
if (!IsCreatureValid(e, e.action.killedMonster.creature)) return false;
|
||||
break;
|
||||
case SMART_ACTION_UPDATE_TEMPLATE:
|
||||
if (e.action.updateTemplate.creature && !IsCreatureValid(e, e.action.updateTemplate.creature)) return false;
|
||||
break;
|
||||
case SMART_ACTION_SET_SHEATH:
|
||||
if (e.action.setSheath.sheath && e.action.setSheath.sheath >= MAX_SHEATH_STATE)
|
||||
{
|
||||
sLog.outErrorDb("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses incorrect Sheath state %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.setSheath.sheath);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case SMART_ACTION_SET_REACT_STATE:
|
||||
{
|
||||
if (e.action.react.state > REACT_AGGRESSIVE)
|
||||
{
|
||||
sLog.outErrorDb("SmartAIMgr: Creature %d Event %u Action %u uses invalid React State %u, skipped.", e.entryOrGuid, e.event_id, e.GetActionType(), e.action.react.state);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SMART_ACTION_SUMMON_GO:
|
||||
if (!IsGameObjectValid(e, e.action.summonGO.entry)) return false;
|
||||
break;
|
||||
case SMART_ACTION_WP_LOAD:
|
||||
if (!sSmartWaypointMgr.GetPath(e.action.wpLoad.id))
|
||||
{
|
||||
sLog.outErrorDb("SmartAIMgr: Creature %d Event %u Action %u uses non-existent WaypointPath id %u, skipped.", e.entryOrGuid, e.event_id, e.GetActionType(), e.action.wpLoad.id);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case SMART_ACTION_ADD_ITEM:
|
||||
case SMART_ACTION_REMOVE_ITEM:
|
||||
if (!IsItemValid(e, e.action.item.entry)) return false;
|
||||
if (!NotNULL(e, e.action.item.count)) return false;
|
||||
break;
|
||||
case SMART_ACTION_TELEPORT:
|
||||
if (!sMapStore.LookupEntry(e.action.teleport.mapID))
|
||||
{
|
||||
sLog.outErrorDb("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Map entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.teleport.mapID);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case SMART_ACTION_INSTALL_AI_TEMPLATE:
|
||||
if (e.action.installTtemplate.id >= SMARTAI_TEMPLATE_END)
|
||||
{
|
||||
sLog.outErrorDb("SmartAIMgr: Creature %d Event %u Action %u uses non-existent AI template id %u, skipped.", e.entryOrGuid, e.event_id, e.GetActionType(), e.action.installTtemplate.id);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case SMART_ACTION_WP_STOP:
|
||||
if (e.action.wpStop.quest && !IsQuestValid(e, e.action.wpStop.quest)) return false;
|
||||
break;
|
||||
case SMART_ACTION_WP_START:
|
||||
{
|
||||
if (e.action.wpStart.quest && !IsQuestValid(e, e.action.wpStart.quest)) return false;
|
||||
if (e.action.wpStart.reactState > REACT_AGGRESSIVE)
|
||||
{
|
||||
sLog.outErrorDb("SmartAIMgr: Creature %d Event %u Action %u uses invalid React State %u, skipped.", e.entryOrGuid, e.event_id, e.GetActionType(), e.action.wpStart.reactState);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SMART_ACTION_CREATE_TIMED_EVENT:
|
||||
{
|
||||
if (!IsMinMaxValid(e, e.action.timeEvent.min, e.action.timeEvent.max)) return false;
|
||||
if (!IsMinMaxValid(e, e.action.timeEvent.repeatMin, e.action.timeEvent.repeatMax)) return false;
|
||||
break;
|
||||
}
|
||||
case SMART_ACTION_FOLLOW:
|
||||
case SMART_ACTION_SET_ORIENTATION:
|
||||
case SMART_ACTION_STORE_TARGET_LIST:
|
||||
case SMART_ACTION_EVADE:
|
||||
case SMART_ACTION_FLEE_FOR_ASSIST:
|
||||
case SMART_ACTION_DIE:
|
||||
case SMART_ACTION_SET_IN_COMBAT_WITH_ZONE:
|
||||
case SMART_ACTION_SET_ACTIVE:
|
||||
case SMART_ACTION_STORE_VARIABLE_DECIMAL:
|
||||
case SMART_ACTION_WP_RESUME:
|
||||
case SMART_ACTION_KILL_UNIT:
|
||||
case SMART_ACTION_SET_INVINCIBILITY_HP_LEVEL:
|
||||
case SMART_ACTION_RESET_GOBJECT:
|
||||
case SMART_ACTION_ATTACK_START:
|
||||
case SMART_ACTION_THREAT_ALL_PCT:
|
||||
case SMART_ACTION_THREAT_SINGLE_PCT:
|
||||
case SMART_ACTION_SET_INST_DATA:
|
||||
case SMART_ACTION_SET_INST_DATA64:
|
||||
case SMART_ACTION_AUTO_ATTACK:
|
||||
case SMART_ACTION_ALLOW_COMBAT_MOVEMENT:
|
||||
case SMART_ACTION_CALL_FOR_HELP:
|
||||
case SMART_ACTION_SET_DATA:
|
||||
case SMART_ACTION_MOVE_FORWARD:
|
||||
case SMART_ACTION_SET_VISIBILITY:
|
||||
case SMART_ACTION_WP_PAUSE:
|
||||
case SMART_ACTION_SET_FLY:
|
||||
case SMART_ACTION_SET_RUN:
|
||||
case SMART_ACTION_SET_SWIMM:
|
||||
case SMART_ACTION_FORCE_DESPAWN:
|
||||
case SMART_ACTION_SET_INGAME_PHASE_MASK:
|
||||
case SMART_ACTION_SET_UNIT_FLAG:
|
||||
case SMART_ACTION_REMOVE_UNIT_FLAG:
|
||||
case SMART_ACTION_PLAYMOVIE:
|
||||
case SMART_ACTION_MOVE_TO_POS:
|
||||
case SMART_ACTION_RESPAWN_TARGET:
|
||||
case SMART_ACTION_CLOSE_GOSSIP:
|
||||
case SMART_ACTION_EQUIP:
|
||||
case SMART_ACTION_TRIGGER_TIMED_EVENT:
|
||||
case SMART_ACTION_REMOVE_TIMED_EVENT:
|
||||
case SMART_ACTION_OVERRIDE_SCRIPT_BASE_OBJECT:
|
||||
case SMART_ACTION_RESET_SCRIPT_BASE_OBJECT:
|
||||
case SMART_ACTION_ACTIVATE_GOBJECT:
|
||||
case SMART_ACTION_CALL_SCRIPT_RESET:
|
||||
case SMART_ACTION_NONE:
|
||||
break;
|
||||
default:
|
||||
sLog.outErrorDb("SmartAIMgr: Not handled action_type(%u), Entry %d SourceType %u Event %u, skipped.", e.GetActionType(), e.GetEventType(), e.entryOrGuid, e.GetScriptType(), e.event_id);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SmartAIMgr::IsTextValid(SmartScriptHolder e, uint32 id)
|
||||
{
|
||||
bool error = false;
|
||||
uint32 entry = 0;
|
||||
if (e.entryOrGuid >= 0)
|
||||
entry = uint32(e.entryOrGuid);
|
||||
else {
|
||||
entry = uint32(abs(e.entryOrGuid));
|
||||
CreatureData const* data = sObjectMgr.GetCreatureData(entry);
|
||||
if (!data)
|
||||
{
|
||||
sLog.outErrorDb("SmartAIMgr: Entry %d SourceType %u Event %u Action %u using non-existent Creature guid %d, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), entry);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
entry = data->id;
|
||||
}
|
||||
if (!entry || !sCreatureTextMgr.TextExist(entry, uint8(id)))
|
||||
error = true;
|
||||
if (error)
|
||||
{
|
||||
sLog.outErrorDb("SmartAIMgr: Entry %d SourceType %u Event %u Action %u using non-existent Text id %d, skipped.", e.entryOrGuid, e.GetScriptType(), e.source_type, e.GetActionType(), id);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
1276
src/server/game/AI/SmartScripts/SmartScriptMgr.h
Normal file
1276
src/server/game/AI/SmartScripts/SmartScriptMgr.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -130,7 +130,7 @@ include_directories(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/AI/CoreAI
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/AI/EventAI
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/AI/ScriptedAI
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/AI/SmartAI
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/AI/SmartScripts
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/AuctionHouse
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Battlegrounds
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Battlegrounds/Zones
|
||||
|
||||
@@ -527,6 +527,7 @@ ChatCommand * ChatHandler::getCommandTable()
|
||||
{ "reserved_name", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadReservedNameCommand, "", NULL },
|
||||
{ "reputation_reward_rate", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadReputationRewardRateCommand, "", NULL },
|
||||
{ "reputation_spillover_template",SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadReputationRewardRateCommand, "", NULL },
|
||||
{ "smartai_scripts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSmartAI, "", NULL },
|
||||
{ "skill_discovery_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSkillDiscoveryTemplateCommand, "", NULL },
|
||||
{ "skill_extra_item_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSkillExtraItemTemplateCommand, "", NULL },
|
||||
{ "skill_fishing_base_level", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSkillFishingBaseLevelCommand, "", NULL },
|
||||
|
||||
@@ -450,6 +450,7 @@ class ChatHandler
|
||||
bool HandleReloadWpScriptsCommand(const char* args);
|
||||
bool HandleReloadConditions(const char* args);
|
||||
bool HandleReloadCreatureText(const char* args);
|
||||
bool HandleReloadSmartAI(const char* args);
|
||||
|
||||
bool HandleResetAchievementsCommand(const char * args);
|
||||
bool HandleResetAllCommand(const char * args);
|
||||
|
||||
@@ -59,6 +59,7 @@
|
||||
#include "ScriptMgr.h"
|
||||
#include "LFGMgr.h"
|
||||
#include "CreatureTextMgr.h"
|
||||
#include "SmartAI.h"
|
||||
|
||||
//reload commands
|
||||
bool ChatHandler::HandleReloadAllCommand(const char*)
|
||||
@@ -1177,6 +1178,14 @@ bool ChatHandler::HandleReloadCreatureText(const char* /*args*/)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ChatHandler::HandleReloadSmartAI(const char* /*args*/)
|
||||
{
|
||||
sLog.outString("Re-Loading SmartAI Scripts...");
|
||||
sSmartScriptMgr.LoadSmartAIFromDB();
|
||||
SendGlobalGMSysMessage("SmartAI Scripts reloaded.");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ChatHandler::HandleAccountSetGmLevelCommand(const char *args)
|
||||
{
|
||||
if (!*args)
|
||||
|
||||
@@ -41,6 +41,8 @@ void AddSC_quest_spell_scripts();
|
||||
void AddSC_item_spell_scripts();
|
||||
void AddSC_example_spell_scripts();
|
||||
|
||||
void AddSC_SmartSCripts();
|
||||
|
||||
#ifdef SCRIPTS
|
||||
//world
|
||||
void AddSC_areatrigger_scripts();
|
||||
@@ -565,6 +567,7 @@ void AddScripts()
|
||||
{
|
||||
AddExampleScripts();
|
||||
AddSpellScripts();
|
||||
AddSC_SmartSCripts();
|
||||
#ifdef SCRIPTS
|
||||
AddWorldScripts();
|
||||
AddEasternKingdomsScripts();
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
#include "MapManager.h"
|
||||
#include "InstanceScript.h"
|
||||
#include "LFGMgr.h"
|
||||
#include "GameObjectAI.h"
|
||||
|
||||
void WorldSession::HandleRepopRequestOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
@@ -144,7 +145,10 @@ void WorldSession::HandleGossipSelectOptionOpcode(WorldPacket & recv_data)
|
||||
unit->AI()->sGossipSelectCode(_player, _player->PlayerTalkClass->GossipOptionSender(gossipListId), _player->PlayerTalkClass->GossipOptionAction(gossipListId), code.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
sScriptMgr.OnGossipSelectCode(_player, go, _player->PlayerTalkClass->GossipOptionSender(gossipListId), _player->PlayerTalkClass->GossipOptionAction(gossipListId), code.c_str());
|
||||
go->AI()->GossipSelectCode(_player, _player->PlayerTalkClass->GossipOptionSender(gossipListId), _player->PlayerTalkClass->GossipOptionAction(gossipListId), code.c_str());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -156,7 +160,10 @@ void WorldSession::HandleGossipSelectOptionOpcode(WorldPacket & recv_data)
|
||||
unit->AI()->sGossipSelect(_player, _player->PlayerTalkClass->GossipOptionSender(gossipListId), _player->PlayerTalkClass->GossipOptionAction(gossipListId));
|
||||
}
|
||||
else
|
||||
{
|
||||
sScriptMgr.OnGossipSelect(_player, go, _player->PlayerTalkClass->GossipOptionSender(gossipListId), _player->PlayerTalkClass->GossipOptionAction(gossipListId));
|
||||
go->AI()->GossipSelect(_player, _player->PlayerTalkClass->GossipOptionSender(gossipListId), _player->PlayerTalkClass->GossipOptionAction(gossipListId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include "ConditionMgr.h"
|
||||
#include "Creature.h"
|
||||
#include "CreatureAI.h"
|
||||
#include "GameObjectAI.h"
|
||||
|
||||
void WorldSession::HandleQuestgiverStatusQueryOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
@@ -217,6 +218,7 @@ void WorldSession::HandleQuestgiverAcceptQuestOpcode(WorldPacket & recv_data)
|
||||
}
|
||||
case TYPEID_GAMEOBJECT:
|
||||
sScriptMgr.OnQuestAccept(_player, ((GameObject*)pObject), qInfo);
|
||||
(pObject->ToGameObject())->AI()->QuestAccept(_player, qInfo);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -331,6 +333,7 @@ void WorldSession::HandleQuestgiverChooseRewardOpcode(WorldPacket & recv_data)
|
||||
// Send next quest
|
||||
if (Quest const* nextquest = _player->GetNextQuest(guid ,pQuest))
|
||||
_player->PlayerTalkClass->SendQuestGiverQuestDetails(nextquest,guid,true);
|
||||
pObject->ToGameObject()->AI()->QuestReward(_player, pQuest, reward);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "SpellAuras.h"
|
||||
#include "CreatureAI.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "GameObjectAI.h"
|
||||
|
||||
void WorldSession::HandleClientCastFlags(WorldPacket& recvPacket, uint8 castFlags, SpellCastTargets & targets)
|
||||
{
|
||||
@@ -287,6 +288,8 @@ void WorldSession::HandleGameObjectUseOpcode(WorldPacket & recv_data)
|
||||
if (sScriptMgr.OnGossipHello(_player, obj))
|
||||
return;
|
||||
|
||||
obj->AI()->GossipHello(_player);
|
||||
|
||||
obj->Use(_player);
|
||||
}
|
||||
|
||||
|
||||
@@ -60,6 +60,7 @@
|
||||
#include "Formulas.h"
|
||||
#include "Vehicle.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "GameObjectAI.h"
|
||||
|
||||
pEffect SpellEffects[TOTAL_SPELL_EFFECTS]=
|
||||
{
|
||||
@@ -2649,6 +2650,8 @@ void Spell::SendLoot(uint64 guid, LootType loottype)
|
||||
if (sScriptMgr.OnGossipHello(player, gameObjTarget))
|
||||
return;
|
||||
|
||||
gameObjTarget->AI()->GossipHello(player);
|
||||
|
||||
switch (gameObjTarget->GetGoType())
|
||||
{
|
||||
case GAMEOBJECT_TYPE_DOOR:
|
||||
|
||||
@@ -419,14 +419,14 @@ bool CreatureTextMgr::TextExist(uint32 sourceEntry, uint8 textGroup)
|
||||
CreatureTextMap::const_iterator sList = mTextMap.find(sourceEntry);
|
||||
if (sList == mTextMap.end())
|
||||
{
|
||||
sLog.outErrorDb("CreatureTextMgr::TextExist: Could not find Text for Creature (entry %u) in 'creature_text' table.", sourceEntry);
|
||||
sLog.outDebug("CreatureTextMgr::TextExist: Could not find Text for Creature (entry %u) in 'creature_text' table.", sourceEntry);
|
||||
return false;
|
||||
}
|
||||
CreatureTextHolder TextHolder = (*sList).second;
|
||||
CreatureTextHolder::const_iterator itr = TextHolder.find(textGroup);
|
||||
if (itr == TextHolder.end())
|
||||
{
|
||||
sLog.outErrorDb("CreatureTextMgr::TextExist: Could not find TextGroup %u for Creature (entry %u).",uint32(textGroup), sourceEntry);
|
||||
sLog.outDebug("CreatureTextMgr::TextExist: Could not find TextGroup %u for Creature (entry %u).",uint32(textGroup), sourceEntry);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -70,6 +70,7 @@
|
||||
#include "ScriptMgr.h"
|
||||
#include "WeatherMgr.h"
|
||||
#include "CreatureTextMgr.h"
|
||||
#include "SmartAI.h"
|
||||
|
||||
volatile bool World::m_stopEvent = false;
|
||||
uint8 World::m_ExitCode = SHUTDOWN_EXIT_CODE;
|
||||
@@ -1571,6 +1572,9 @@ void World::SetInitialWorldSettings()
|
||||
sLog.outString("Loading Waypoints...");
|
||||
sWaypointMgr->Load();
|
||||
|
||||
sLog.outString("Loading SmartAI Waypoints...");
|
||||
sSmartWaypointMgr.LoadFromDB();
|
||||
|
||||
sLog.outString("Loading Creature Formations...");
|
||||
formation_mgr.LoadCreatureFormations();
|
||||
|
||||
@@ -1641,6 +1645,9 @@ void World::SetInitialWorldSettings()
|
||||
sLog.outString("Validating spell scripts...");
|
||||
sObjectMgr.ValidateSpellScripts();
|
||||
|
||||
sLog.outString("Loading SmartAI scripts...");
|
||||
sSmartScriptMgr.LoadSmartAIFromDB();
|
||||
|
||||
///- Initialize game time and timers
|
||||
sLog.outDebug("DEBUG:: Initialize game time and timers");
|
||||
m_gameTime = time(NULL);
|
||||
|
||||
@@ -36,6 +36,8 @@ bool WorldDatabaseConnection::Open()
|
||||
PrepareStatement(WORLD_REP_CRELINKED_RESPAWN, "REPLACE INTO creature_linked_respawn (guid,linkedGuid) VALUES (?, ?)");
|
||||
PrepareStatement(WORLD_DEL_GAMEOBJECT_RESPAWN_TIMES, "DELETE FROM gameobject_respawn WHERE respawntime <= UNIX_TIMESTAMP(NOW())");
|
||||
PrepareStatement(WORLD_LOAD_CRETEXT, "SELECT entry, groupid, id, text, type, language, probability, emote, duration, sound FROM creature_text");
|
||||
PrepareStatement(WORLD_LOAD_SMART_SCRIPTS, "SELECT entryorguid, source_type, id, link, event_type, event_phase_mask, event_chance, event_flags, event_param1, event_param2, event_param3, event_param4, action_type, action_param1, action_param2, action_param3, action_param4, action_param5, action_param6, target_type, target_param1, target_param2, target_param3, target_x, target_y, target_z, target_o FROM smart_scripts");
|
||||
PrepareStatement(WORLD_LOAD_SMARTAI_WP, "SELECT entry, pointid, position_x, position_y, position_z FROM waypoints ORDER BY entry, pointid");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -49,6 +49,8 @@ enum WorldDatabaseStatements
|
||||
WORLD_REP_CRELINKED_RESPAWN,
|
||||
WORLD_DEL_GAMEOBJECT_RESPAWN_TIMES,
|
||||
WORLD_LOAD_CRETEXT,
|
||||
WORLD_LOAD_SMART_SCRIPTS,
|
||||
WORLD_LOAD_SMARTAI_WP,
|
||||
MAX_WORLDDATABASE_STATEMENTS,
|
||||
};
|
||||
|
||||
|
||||
@@ -73,6 +73,7 @@ include_directories(
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/AI/CoreAI
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/AI/EventAI
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/AI/ScriptedAI
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/AI/SmartScripts
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/AuctionHouse
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/AuctionHouse/AuctionHouseBot
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Battlegrounds
|
||||
|
||||
Reference in New Issue
Block a user