mirror of
https://github.com/Sarjuuk/aowow.git
synced 2025-11-29 15:58:16 +08:00
SmartAI/Update
* update events and actions to match TrinityCore again * removed events and actions have been kept but marked as deprecated * general rewording and use of UIES for better readability * move constants to respective classes * reevaluate usage of UNIT_FIELD_BYTES1 content
This commit is contained in:
755
includes/components/SmartAI/SmartAI.class.php
Normal file
755
includes/components/SmartAI/SmartAI.class.php
Normal file
@@ -0,0 +1,755 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
// TrinityCore - SmartAI
|
||||
|
||||
trait SmartHelper
|
||||
{
|
||||
private function resolveGuid(int $type, int $guid) : ?int
|
||||
{
|
||||
if ($_ = DB::Aowow()->selectCell('SELECT `typeId` FROM ?_spawns WHERE `type` = ?d AND `guid` = ?d', $type, $guid))
|
||||
return $_;
|
||||
|
||||
trigger_error('SmartAI::resolveGuid - failed to resolve guid '.$guid.' of type '.$type, E_USER_WARNING);
|
||||
return null;
|
||||
}
|
||||
|
||||
private function numRange(int $min, int $max, bool $isTime) : string
|
||||
{
|
||||
if (!$min && !$max)
|
||||
return '';
|
||||
|
||||
$str = $isTime ? Util::formatTime($min, true) : $min;
|
||||
if ($max > $min)
|
||||
$str .= ' – '.($isTime ? Util::formatTime($max, true) : $max);
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
private function formatTime(int $time, int $_, bool $isMilliSec) : string
|
||||
{
|
||||
if (!$time)
|
||||
return '';
|
||||
|
||||
return Util::formatTime($time * ($isMilliSec ? 1 : 1000), false);
|
||||
}
|
||||
|
||||
private function castFlags(int $flags) : string
|
||||
{
|
||||
$cf = [];
|
||||
for ($i = 1; $i <= SmartAI::CAST_FLAG_COMBAT_MOVE; $i <<= 1)
|
||||
if (($flags & $i) && ($x = Lang::smartAI('castFlags', $i)))
|
||||
$cf[] = $x;
|
||||
|
||||
return Lang::concat($cf);
|
||||
}
|
||||
|
||||
private function npcFlags(int $flags) : string
|
||||
{
|
||||
$nf = [];
|
||||
for ($i = 1; $i <= NPC_FLAG_MAILBOX; $i <<= 1)
|
||||
if (($flags & $i) && ($x = Lang::npc('npcFlags', $i)))
|
||||
$nf[] = $x;
|
||||
|
||||
return Lang::concat($nf ?: [Lang::smartAI('empty')]);
|
||||
}
|
||||
|
||||
private function dynFlags(int $flags) : string
|
||||
{
|
||||
$df = [];
|
||||
for ($i = 1; $i <= UNIT_DYNFLAG_TAPPED_BY_ALL_THREAT_LIST; $i <<= 1)
|
||||
if (($flags & $i) && ($x = Lang::unit('dynFlags', $i)))
|
||||
$df[] = $x;
|
||||
|
||||
return Lang::concat($df ?: [Lang::smartAI('empty')]);
|
||||
}
|
||||
|
||||
private function goFlags(int $flags) : string
|
||||
{
|
||||
$gf = [];
|
||||
for ($i = 1; $i <= GO_FLAG_DESTROYED; $i <<= 1)
|
||||
if (($flags & $i) && ($x = Lang::gameObject('goFlags', $i)))
|
||||
$gf[] = $x;
|
||||
|
||||
return Lang::concat($gf ?: [Lang::smartAI('empty')]);
|
||||
}
|
||||
|
||||
private function spawnFlags(int $flags) : string
|
||||
{
|
||||
$sf = [];
|
||||
for ($i = 1; $i <= SmartAI::SPAWN_FLAG_NOSAVE_RESPAWN; $i <<= 1)
|
||||
if (($flags & $i) && ($x = Lang::smartAI('spawnFlags', $i)))
|
||||
$sf[] = $x;
|
||||
|
||||
return Lang::concat($sf ?: [Lang::smartAI('empty')]);
|
||||
}
|
||||
|
||||
private function unitFlags(int $flags, int $flags2) : string
|
||||
{
|
||||
$field = $flags2 ? 'flags2' : 'flags';
|
||||
$max = $flags2 ? UNIT_FLAG2_ALLOW_CHEAT_SPELLS : UNIT_FLAG_UNK_31;
|
||||
$uf = [];
|
||||
|
||||
for ($i = 1; $i <= $max; $i <<= 1)
|
||||
if (($flags & $i) && ($x = Lang::unit($field, $i)))
|
||||
$uf[] = $x;
|
||||
|
||||
return Lang::concat($uf ?: [Lang::smartAI('empty')]);
|
||||
}
|
||||
|
||||
private function unitFieldBytes1(int $flags, int $idx) : string
|
||||
{
|
||||
switch ($idx)
|
||||
{
|
||||
case 0:
|
||||
case 3:
|
||||
return Lang::unit('bytes1', 'bytesIdx', $idx).Lang::main('colon').(Lang::unit('bytes1', $idx, $flags) ?? Lang::unit('bytes1', 'valueUNK', [$flags, $idx]));
|
||||
case 2:
|
||||
$buff = [];
|
||||
for ($i = 1; $i <= 0x10; $i <<= 1)
|
||||
if (($flags & $i) && ($x = Lang::unit('bytes1', $idx, $flags)))
|
||||
$buff[] = $x;
|
||||
|
||||
return Lang::unit('bytes1', 'bytesIdx', $idx).Lang::main('colon').($buff ? Lang::concat($buff) : Lang::unit('bytes1', 'valueUNK', [$flags, $idx]));
|
||||
default:
|
||||
return Lang::unit('bytes1', 'idxUNK', [$idx]);
|
||||
}
|
||||
}
|
||||
|
||||
private function summonType(int $x) : string
|
||||
{
|
||||
return Lang::smartAI('summonTypes', $x) ?? Lang::smartAI('summonType', 'summonTypeUNK', [$x]);
|
||||
}
|
||||
|
||||
private function sheathState(int $x) : string
|
||||
{
|
||||
return Lang::smartAI('sheaths', $x) ?? Lang::smartAI('sheathUNK', [$x]);
|
||||
}
|
||||
|
||||
private function aiTemplate(int $x) : string
|
||||
{
|
||||
return Lang::smartAI('aiTpl', $x) ?? Lang::smartAI('aiTplUNK', [$x]);
|
||||
}
|
||||
|
||||
private function reactState(int $x) : string
|
||||
{
|
||||
return Lang::smartAI('reactStates', $x) ?? Lang::smartAI('reactStateUNK', [$x]);
|
||||
}
|
||||
|
||||
private function powerType(int $x) : string
|
||||
{
|
||||
return Lang::spell('powerTypes', $x) ?? Lang::smartAI('powerTypeUNK', [$x]);
|
||||
}
|
||||
|
||||
private function hostilityMode(int $x) : string
|
||||
{
|
||||
return Lang::smartAI('hostilityModes', $x) ?? Lang::smartAI('hostilityModeUNK', [$x]);
|
||||
}
|
||||
|
||||
private function motionType(int $x) : string
|
||||
{
|
||||
return Lang::smartAI('motionTypes', $x) ?? Lang::smartAI('motionTypeUNK', [$x]);
|
||||
}
|
||||
|
||||
private function lootState(int $x) : string
|
||||
{
|
||||
return Lang::smartAI('lootStates', $x) ?? Lang::smartAI('lootStateUNK', [$x]);
|
||||
}
|
||||
private function weatherState(int $x) : string
|
||||
{
|
||||
return Lang::smartAI('weatherStates', $x) ?? Lang::smartAI('weatherStateUNK', [$x]);
|
||||
}
|
||||
|
||||
private function magicSchool(int $x) : string
|
||||
{
|
||||
return Lang::getMagicSchools($x);
|
||||
}
|
||||
}
|
||||
|
||||
class SmartAI
|
||||
{
|
||||
public const SRC_TYPE_CREATURE = 0;
|
||||
public const SRC_TYPE_OBJECT = 1;
|
||||
public const SRC_TYPE_AREATRIGGER = 2;
|
||||
public const SRC_TYPE_ACTIONLIST = 9;
|
||||
|
||||
public const CAST_FLAG_INTERRUPT_PREV = 0x01; // Interrupt any spell casting
|
||||
public const CAST_FLAG_TRIGGERED = 0x02; // Triggered (this makes spell cost zero mana and have no cast time)
|
||||
// public const CAST_FORCE_CAST = 0x04; // Forces cast even if creature is out of mana or out of range
|
||||
// public const CAST_NO_MELEE_IF_OOM = 0x08; // Prevents creature from entering melee if out of mana or out of range
|
||||
// public const CAST_FORCE_TARGET_SELF = 0x10; // the target to cast this spell on itself
|
||||
public const CAST_FLAG_AURA_MISSING = 0x20; // Only casts the spell if the target does not have an aura from the spell
|
||||
public const CAST_FLAG_COMBAT_MOVE = 0x40; // Prevents combat movement if cast successful. Allows movement on range, OOM, LOS
|
||||
|
||||
public const REACT_PASSIVE = 0;
|
||||
public const REACT_DEFENSIVE = 1;
|
||||
public const REACT_AGGRESSIVE = 2;
|
||||
public const REACT_ASSIST = 3;
|
||||
|
||||
public const SUMMON_TIMED_OR_DEAD_DESPAWN = 1;
|
||||
public const SUMMON_TIMED_OR_CORPSE_DESPAWN = 2;
|
||||
public const SUMMON_TIMED_DESPAWN = 3;
|
||||
public const SUMMON_TIMED_DESPAWN_OOC = 4;
|
||||
public const SUMMON_CORPSE_DESPAWN = 5;
|
||||
public const SUMMON_CORPSE_TIMED_DESPAWN = 6;
|
||||
public const SUMMON_DEAD_DESPAWN = 7;
|
||||
public const SUMMON_MANUAL_DESPAWN = 8;
|
||||
|
||||
public const TEMPLATE_BASIC = 0; //
|
||||
public const TEMPLATE_CASTER = 1; // +JOIN: target_param1 as castFlag
|
||||
public const TEMPLATE_TURRET = 2; // +JOIN: target_param1 as castflag
|
||||
public const TEMPLATE_PASSIVE = 3; //
|
||||
public const TEMPLATE_CAGED_GO_PART = 4; //
|
||||
public const TEMPLATE_CAGED_NPC_PART = 5; //
|
||||
|
||||
public const SPAWN_FLAG_NONE = 0x00;
|
||||
public const SPAWN_FLAG_IGNORE_RESPAWN = 0x01; // onSpawnIn - ignore & reset respawn timer
|
||||
public const SPAWN_FLAG_FORCE_SPAWN = 0x02; // onSpawnIn - force additional spawn if already in world
|
||||
public const SPAWN_FLAG_NOSAVE_RESPAWN = 0x04; // onDespawn - remove respawn time
|
||||
|
||||
private array $jsGlobals = [];
|
||||
private array $rawData = [];
|
||||
private array $result = [];
|
||||
private array $tabs = [];
|
||||
private array $itr = [];
|
||||
|
||||
private array $quotes = [];
|
||||
|
||||
// misc data
|
||||
public readonly int $baseEntry; // I'm a timed action list belonging to this entry
|
||||
public readonly string $title; // title appendix for the [toggle]
|
||||
public readonly int $teleportTargetArea; // precalculated areaId so we don't have to look it up right now
|
||||
|
||||
public function __construct(public readonly int $srcType = 0, public readonly int $entry = 0, array $miscData = [])
|
||||
{
|
||||
$this->baseEntry = $miscData['baseEntry'] ?? 0;
|
||||
$this->title = $miscData['title'] ?? '';
|
||||
$this->teleportTargetArea = $miscData['teleportTargetArea'] ?? 0;
|
||||
|
||||
$raw = DB::World()->select(
|
||||
'SELECT `id`, `link`,
|
||||
`event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`,
|
||||
`action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`,
|
||||
`target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`
|
||||
FROM smart_scripts
|
||||
WHERE `entryorguid` = ?d AND `source_type` = ?d
|
||||
ORDER BY `id` ASC',
|
||||
$this->entry, $this->srcType);
|
||||
|
||||
foreach ($raw as $r)
|
||||
{
|
||||
$this->rawData[$r['id']] = array(
|
||||
'id' => $r['id'],
|
||||
'link' => $r['link'],
|
||||
'event' => new SmartEvent($r['id'], $r['event_type'], $r['event_phase_mask'], $r['event_chance'], $r['event_flags'], [$r['event_param1'], $r['event_param2'], $r['event_param3'], $r['event_param4'], $r['event_param5']], $this),
|
||||
'action' => new SmartAction($r['id'], $r['action_type'], [$r['action_param1'], $r['action_param2'], $r['action_param3'], $r['action_param4'], $r['action_param5'], $r['action_param6']], $this),
|
||||
'target' => new SmartTarget($r['id'], $r['target_type'], [$r['target_param1'], $r['target_param2'], $r['target_param3'], $r['target_param4']], [$r['target_x'], $r['target_y'], $r['target_z'], $r['target_o']], $this)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*********************/
|
||||
/* Lookups by action */
|
||||
/*********************/
|
||||
|
||||
public static function getOwnerOfNPCSummon(int $npcId, int $typeFilter = 0) : array
|
||||
{
|
||||
if ($npcId <= 0)
|
||||
return [];
|
||||
|
||||
$lookup = array(
|
||||
SmartAction::ACTION_SUMMON_CREATURE => [1 => $npcId],
|
||||
SmartAction::ACTION_MOUNT_TO_ENTRY_OR_MODEL => [1 => $npcId]
|
||||
);
|
||||
|
||||
if ($npcGuids = DB::Aowow()->selectCol('SELECT `guid` FROM ?_spawns WHERE `type` = ?d AND `typeId` = ?d', Type::NPC, $npcId))
|
||||
if ($groups = DB::World()->selectCol('SELECT `groupId` FROM spawn_group WHERE `spawnType` = 0 AND `spawnId` IN (?a)', $npcGuids))
|
||||
foreach ($groups as $g)
|
||||
$lookup[SmartAction::ACTION_SPAWN_SPAWNGROUP][1] = $g;
|
||||
|
||||
$result = self::getActionOwner($lookup, $typeFilter);
|
||||
|
||||
// can skip lookups for SmartAction::ACTION_SUMMON_CREATURE_GROUP as creature_summon_groups already contains summoner info
|
||||
if ($sgs = DB::World()->select('SELECT `summonerType` AS "0", `summonerId` AS "1" FROM creature_summon_groups WHERE `entry` = ?d', $npcId))
|
||||
foreach ($sgs as [$type, $typeId])
|
||||
$result[$type][] = $typeId;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public static function getOwnerOfObjectSummon(int $objectId, int $typeFilter = 0) : array
|
||||
{
|
||||
if ($objectId <= 0)
|
||||
return [];
|
||||
|
||||
$lookup = array(
|
||||
SmartAction::ACTION_SUMMON_GO => [1 => $objectId]
|
||||
);
|
||||
|
||||
if ($objGuids = DB::Aowow()->selectCol('SELECT `guid` FROM ?_spawns WHERE `type` = ?d AND `typeId` = ?d', Type::OBJECT, $objectId))
|
||||
if ($groups = DB::World()->selectCol('SELECT `groupId` FROM spawn_group WHERE `spawnType` = 1 AND `spawnId` IN (?a)', $objGuids))
|
||||
foreach ($groups as $g)
|
||||
$lookup[SmartAction::ACTION_SPAWN_SPAWNGROUP][1] = $g;
|
||||
|
||||
return self::getActionOwner($lookup, $typeFilter);
|
||||
}
|
||||
|
||||
public static function getOwnerOfSpellCast(int $spellId, int $typeFilter = 0) : array
|
||||
{
|
||||
if ($spellId <= 0)
|
||||
return [];
|
||||
|
||||
$lookup = array(
|
||||
SmartAction::ACTION_CAST => [1 => $spellId],
|
||||
SmartAction::ACTION_ADD_AURA => [1 => $spellId],
|
||||
SmartAction::ACTION_SELF_CAST => [1 => $spellId],
|
||||
SmartAction::ACTION_CROSS_CAST => [1 => $spellId],
|
||||
SmartAction::ACTION_INVOKER_CAST => [1 => $spellId]
|
||||
);
|
||||
|
||||
return self::getActionOwner($lookup, $typeFilter);
|
||||
}
|
||||
|
||||
public static function getOwnerOfSoundPlayed(int $soundId, int $typeFilter = 0) : array
|
||||
{
|
||||
if ($soundId <= 0)
|
||||
return [];
|
||||
|
||||
$lookup = array(
|
||||
SmartAction::ACTION_SOUND => [1 => $soundId]
|
||||
);
|
||||
|
||||
return self::getActionOwner($lookup, $typeFilter);
|
||||
}
|
||||
|
||||
// lookup: SmartActionId => [[paramIdx => value], ...]
|
||||
private static function getActionOwner(array $lookup, int $typeFilter = 0) : array
|
||||
{
|
||||
$qParts = [];
|
||||
$result = [];
|
||||
$genFilter = $talFilter = [];
|
||||
switch ($typeFilter)
|
||||
{
|
||||
case Type::NPC:
|
||||
$genFilter = [self::SRC_TYPE_CREATURE, self::SRC_TYPE_ACTIONLIST];
|
||||
$talFilter = [self::SRC_TYPE_CREATURE];
|
||||
break;
|
||||
case Type::OBJECT:
|
||||
$genFilter = [self::SRC_TYPE_OBJECT, self::SRC_TYPE_ACTIONLIST];
|
||||
$talFilter = [self::SRC_TYPE_OBJECT];
|
||||
break;
|
||||
case Type::AREATRIGGER:
|
||||
$genFilter = [self::SRC_TYPE_AREATRIGGER, self::SRC_TYPE_ACTIONLIST];
|
||||
$talFilter = [self::SRC_TYPE_AREATRIGGER];
|
||||
break;
|
||||
}
|
||||
|
||||
foreach ($lookup as $action => $params)
|
||||
{
|
||||
$aq = '(`action_type` = '.(int)$action.' AND (';
|
||||
$pq = [];
|
||||
foreach ($params as $idx => $p)
|
||||
$pq[] = '`action_param'.(int)$idx.'` = '.(int)$p;
|
||||
|
||||
if ($pq)
|
||||
$qParts[] = $aq.implode(' OR ', $pq).'))';
|
||||
}
|
||||
|
||||
$smartS = DB::World()->select(sprintf('SELECT `source_type` AS "0", `entryOrGUID` AS "1" FROM smart_scripts WHERE (%s){ AND `source_type` IN (?a)}', $qParts ? implode(' OR ', $qParts) : '0'), $genFilter ?: DBSIMPLE_SKIP);
|
||||
|
||||
// filter for TAL shenanigans
|
||||
if ($smartTAL = array_filter($smartS, fn($x) => $x[0] == self::SRC_TYPE_ACTIONLIST))
|
||||
{
|
||||
$smartS = array_diff_key($smartS, $smartTAL);
|
||||
|
||||
$q = [];
|
||||
foreach ($smartTAL as [, $eog])
|
||||
{
|
||||
// SmartAction::ACTION_CALL_TIMED_ACTIONLIST
|
||||
$q[] = '`action_type` = '.SmartAction::ACTION_CALL_TIMED_ACTIONLIST.' AND `action_param1` = '.$eog;
|
||||
|
||||
// SmartAction::ACTION_CALL_RANDOM_TIMED_ACTIONLIST
|
||||
$q[] = '`action_type` = '.SmartAction::ACTION_CALL_RANDOM_TIMED_ACTIONLIST.' AND (`action_param1` = '.$eog.' OR `action_param2` = '.$eog.' OR `action_param3` = '.$eog.' OR `action_param4` = '.$eog.' OR `action_param5` = '.$eog.')';
|
||||
|
||||
// SmartAction::ACTION_CALL_RANDOM_RANGE_TIMED_ACTIONLIST
|
||||
$q[] = '`action_type` = '.SmartAction::ACTION_CALL_RANDOM_RANGE_TIMED_ACTIONLIST.' AND `action_param1` <= '.$eog.' AND `action_param2` >= '.$eog;
|
||||
}
|
||||
|
||||
if ($_ = DB::World()->select(sprintf('SELECT `source_type` AS "0", `entryOrGUID` AS "1" FROM smart_scripts WHERE ((%s)){ AND `source_type` IN (?a)}', $q ? implode(') OR (', $q) : '0'), $talFilter ?: DBSIMPLE_SKIP))
|
||||
$smartS = array_merge($smartS, $_);
|
||||
}
|
||||
|
||||
// filter guids for entries
|
||||
if ($smartG = array_filter($smartS, fn($x) => $x[1] < 0))
|
||||
{
|
||||
$smartS = array_diff_key($smartS, $smartG);
|
||||
|
||||
$q = [];
|
||||
foreach ($smartG as [$st, $eog])
|
||||
{
|
||||
if ($st == self::SRC_TYPE_CREATURE)
|
||||
$q[] = '`type` = '.Type::NPC.' AND `guid` = '.-$eog;
|
||||
else if ($st == self::SRC_TYPE_OBJECT)
|
||||
$q[] = '`type` = '.Type::OBJECT.' AND `guid` = '.-$eog;
|
||||
}
|
||||
|
||||
if ($q)
|
||||
{
|
||||
$owner = DB::Aowow()->select(sprintf('SELECT `type`, `typeId` FROM ?_spawns WHERE (%s)', implode(') OR (', $q)));
|
||||
foreach ($owner as $o)
|
||||
$result[$o['type']][] = $o['typeId'];
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($smartS as [$st, $eog])
|
||||
{
|
||||
if ($st == self::SRC_TYPE_CREATURE)
|
||||
$result[Type::NPC][] = $eog;
|
||||
else if ($st == self::SRC_TYPE_OBJECT)
|
||||
$result[Type::OBJECT][] = $eog;
|
||||
else if ($st == self::SRC_TYPE_AREATRIGGER)
|
||||
$result[Type::AREATRIGGER][] = $eog;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
/********************/
|
||||
/* Lookups by owner */
|
||||
/********************/
|
||||
|
||||
public static function getNPCSummonsForOwner(int $entry, int $srcType = self::SRC_TYPE_CREATURE) : array
|
||||
{
|
||||
// action => paramIdx with npcIds/spawnGoupIds
|
||||
$lookup = array(
|
||||
SmartAction::ACTION_SUMMON_CREATURE => [1],
|
||||
SmartAction::ACTION_MOUNT_TO_ENTRY_OR_MODEL => [1],
|
||||
SmartAction::ACTION_SPAWN_SPAWNGROUP => [1]
|
||||
);
|
||||
|
||||
$result = self::getOwnerAction($srcType, $entry, $lookup, $moreInfo);
|
||||
|
||||
// can skip lookups for SmartAction::ACTION_SUMMON_CREATURE_GROUP as creature_summon_groups already contains summoner info
|
||||
if ($srcType == self::SRC_TYPE_CREATURE || $srcType == self::SRC_TYPE_OBJECT)
|
||||
{
|
||||
$st = $srcType == self::SRC_TYPE_CREATURE ? SUMMONER_TYPE_CREATURE : SUMMONER_TYPE_GAMEOBJECT;
|
||||
if ($csg = DB::World()->selectCol('SELECT `entry` FROM creature_summon_groups WHERE `summonerType` = ?d AND `summonerId` = ?d', $st, $entry))
|
||||
$result = array_merge($result, $csg);
|
||||
}
|
||||
|
||||
if (!empty($moreInfo[SmartAction::ACTION_SPAWN_SPAWNGROUP]))
|
||||
{
|
||||
$grp = $moreInfo[SmartAction::ACTION_SPAWN_SPAWNGROUP];
|
||||
if ($sgs = DB::World()->selectCol('SELECT `spawnId` FROM spawn_group WHERE `spawnType` = ?d AND `groupId` IN (?a)', SUMMONER_TYPE_CREATURE, $grp))
|
||||
if ($ids = DB::Aowow()->selectCol('SELECT DISTINCT `typeId` FROM ?_spawns WHERE `type` = ?d AND `guid` IN (?a)', Type::NPC, $sgs))
|
||||
$result = array_merge($result, $ids);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public static function getObjectSummonsForOwner(int $entry, int $srcType = self::SRC_TYPE_CREATURE) : array
|
||||
{
|
||||
// action => paramIdx with gobIds/spawnGoupIds
|
||||
$lookup = array(
|
||||
SmartAction::ACTION_SUMMON_GO => [1],
|
||||
SmartAction::ACTION_SPAWN_SPAWNGROUP => [1]
|
||||
);
|
||||
|
||||
$result = self::getOwnerAction($srcType, $entry, $lookup, $moreInfo);
|
||||
|
||||
if (!empty($moreInfo[SmartAction::ACTION_SPAWN_SPAWNGROUP]))
|
||||
{
|
||||
$grp = $moreInfo[SmartAction::ACTION_SPAWN_SPAWNGROUP];
|
||||
if ($sgs = DB::World()->selectCol('SELECT `spawnId` FROM spawn_group WHERE `spawnType` = ?d AND `groupId` IN (?a)', SUMMONER_TYPE_GAMEOBJECT, $grp))
|
||||
if ($ids = DB::Aowow()->selectCol('SELECT DISTINCT `typeId` FROM ?_spawns WHERE `type` = ?d AND `guid` IN (?a)', Type::OBJECT, $sgs))
|
||||
$result = array_merge($result, $ids);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public static function getSpellCastsForOwner(int $entry, int $srcType = self::SRC_TYPE_CREATURE) : array
|
||||
{
|
||||
// action => paramIdx with spellIds
|
||||
$lookup = array(
|
||||
self::SRC_TYPE_CREATURE => [1],
|
||||
SmartAction::ACTION_CAST => [1],
|
||||
SmartAction::ACTION_ADD_AURA => [1],
|
||||
SmartAction::ACTION_INVOKER_CAST => [1],
|
||||
SmartAction::ACTION_CROSS_CAST => [1]
|
||||
);
|
||||
|
||||
return self::getOwnerAction($srcType, $entry, $lookup);
|
||||
}
|
||||
|
||||
public static function getSoundsPlayedForOwner(int $entry, int $srcType = self::SRC_TYPE_CREATURE) : array
|
||||
{
|
||||
// action => paramIdx with soundIds
|
||||
$lookup = array(
|
||||
SmartAction::ACTION_SOUND => [1]
|
||||
);
|
||||
|
||||
return self::getOwnerAction($srcType, $entry, $lookup);
|
||||
}
|
||||
|
||||
// lookup: [SmartActionId => [paramIdx, ...], ...]
|
||||
private static function getOwnerAction(int $sourceType, int $entry, array $lookup, ?array &$moreInfo = []) : array
|
||||
{
|
||||
if ($entry < 0) // no lookup by GUID
|
||||
return [];
|
||||
|
||||
$actionQuery = 'SELECT `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6` FROM smart_scripts WHERE `source_type` = ?d AND `action_type` IN (?a) AND `entryOrGUID` IN (?a)';
|
||||
|
||||
$smartScripts = DB::World()->select($actionQuery, $sourceType, array_merge(array_keys($lookup), SmartAction::ACTION_ALL_TIMED_ACTION_LISTS), [$entry]);
|
||||
$smartResults = [];
|
||||
$smartTALs = [];
|
||||
foreach ($smartScripts as $s)
|
||||
{
|
||||
if ($s['action_type'] == SmartAction::ACTION_SPAWN_SPAWNGROUP)
|
||||
$moreInfo[SmartAction::ACTION_SPAWN_SPAWNGROUP][] = $s['action_param1'];
|
||||
else if (in_array($s['action_type'], array_keys($lookup)))
|
||||
{
|
||||
foreach ($lookup[$s['action_type']] as $p)
|
||||
$smartResults[] = $s['action_param'.$p];
|
||||
}
|
||||
else if ($s['action_type'] == SmartAction::ACTION_CALL_TIMED_ACTIONLIST)
|
||||
$smartTALs[] = $s['action_param1'];
|
||||
else if ($s['action_type'] == SmartAction::ACTION_CALL_RANDOM_TIMED_ACTIONLIST)
|
||||
{
|
||||
for ($i = 1; $i < 7; $i++)
|
||||
if ($s['action_param'.$i])
|
||||
$smartTALs[] = $s['action_param'.$i];
|
||||
}
|
||||
else if ($s['action_type'] == SmartAction::ACTION_CALL_RANDOM_RANGE_TIMED_ACTIONLIST)
|
||||
{
|
||||
for ($i = $s['action_param1']; $i <= $s['action_param2']; $i++)
|
||||
$smartTALs[] = $i;
|
||||
}
|
||||
}
|
||||
|
||||
if ($smartTALs)
|
||||
{
|
||||
if ($TALActList = DB::World()->select($actionQuery, self::SRC_TYPE_ACTIONLIST, array_keys($lookup), $smartTALs))
|
||||
{
|
||||
foreach ($TALActList as $e)
|
||||
{
|
||||
foreach ($lookup[$e['action_type']] as $i)
|
||||
{
|
||||
if ($e['action_type'] == SmartAction::ACTION_SPAWN_SPAWNGROUP)
|
||||
$moreInfo[SmartAction::ACTION_SPAWN_SPAWNGROUP][] = $e['action_param'.$i];
|
||||
else
|
||||
$smartResults[] = $e['action_param'.$i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $smartResults;
|
||||
}
|
||||
|
||||
|
||||
/******************************/
|
||||
/* Structured Lisview Display */
|
||||
/******************************/
|
||||
|
||||
private function &iterate() : Generator
|
||||
{
|
||||
reset($this->rawData);
|
||||
|
||||
foreach ($this->rawData as $k => $__)
|
||||
{
|
||||
$this->itr = &$this->rawData[$k];
|
||||
|
||||
yield $this->itr;
|
||||
}
|
||||
}
|
||||
|
||||
public function prepare() : bool
|
||||
{
|
||||
if (!$this->rawData)
|
||||
return false;
|
||||
|
||||
if ($this->result)
|
||||
return true;
|
||||
|
||||
$hidePhase =
|
||||
$hideChance = true;
|
||||
|
||||
foreach ($this->iterate() as $id => $__)
|
||||
{
|
||||
$rowIdx = Util::createHash(8);
|
||||
|
||||
if ($this->itr['action']->type == SmartAction::ACTION_TALK || $this->itr['action']->type == SmartAction::ACTION_SIMPLE_TALK)
|
||||
if ($ts = $this->itr['target']->getTalkSource())
|
||||
$this->initQuotes($ts);
|
||||
|
||||
[$evtBody, $evtFooter] = $this->itr['event']->process();
|
||||
[$actBody, $actFooter] = $this->itr['action']->process();
|
||||
|
||||
$evtBody = str_replace(['#target#', '#rowIdx#'], [$this->itr['target']->process(), $rowIdx], $evtBody);
|
||||
$actBody = str_replace(['#target#', '#rowIdx#'], [$this->itr['target']->process(), $rowIdx], $actBody);
|
||||
|
||||
if (!$this->itr['event']->hasPhases())
|
||||
$hidePhase = false;
|
||||
|
||||
if ($this->itr['event']->chance != 100)
|
||||
$hideChance = false;
|
||||
|
||||
$this->result[] = array(
|
||||
$this->itr['id'],
|
||||
implode(', ', Util::mask2bits($this->itr['event']->phaseMask, 1)),
|
||||
$evtBody.($evtFooter ? '[div float=right margin=0px clear=both][i][small class=q0]'.$evtFooter.'[/small][/i][/div]' : null),
|
||||
$this->itr['event']->chance.'%',
|
||||
$actBody.($actFooter ? '[div float=right margin=0px clear=both][i][small class=q0]'.$actFooter.'[/small][/i][/div]' : null)
|
||||
);
|
||||
}
|
||||
|
||||
$th = array(
|
||||
'#' => 16,
|
||||
'Phase' => 32,
|
||||
'Event' => 350,
|
||||
'Chance' => 24,
|
||||
'Action' => 0
|
||||
);
|
||||
|
||||
if ($hidePhase)
|
||||
{
|
||||
unset($th['Phase']);
|
||||
foreach ($this->result as &$r)
|
||||
unset($r[1]);
|
||||
}
|
||||
unset($r);
|
||||
|
||||
if ($hideChance)
|
||||
{
|
||||
unset($th['Chance']);
|
||||
foreach ($this->result as &$r)
|
||||
unset($r[3]);
|
||||
}
|
||||
unset($r);
|
||||
|
||||
$tbl = '[tr]';
|
||||
foreach ($th as $n => $w)
|
||||
$tbl .= '[td header '.($w ? 'width='.$w.'px' : null).']'.$n.'[/td]';
|
||||
$tbl .= '[/tr]';
|
||||
|
||||
foreach ($this->result as $r)
|
||||
$tbl .= '[tr][td]'.implode('[/td][td]', $r).'[/td][/tr]';
|
||||
|
||||
if ($this->srcType == self::SRC_TYPE_ACTIONLIST)
|
||||
$this->tabs[$this->entry] = $tbl;
|
||||
else
|
||||
$this->tabs[0] = $tbl;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getMarkdown() : string
|
||||
{
|
||||
# id | event (footer phase) | chance | action + target
|
||||
|
||||
if (!$this->rawData)
|
||||
return '';
|
||||
|
||||
$return = '[style]#text-generic .grid { clear:left; } #text-generic .tabbed-contents { padding:0px; clear:left; }[/style][pad][h3][toggler id=sai]SmartAI'.$this->title.'[/toggler][/h3][div id=sai clear=left]%s[/div]';
|
||||
if (count($this->tabs) > 1)
|
||||
{
|
||||
$wrapper = '[tabs name=sai width=942px]%s[/tabs]';
|
||||
$return = '[script]function TalTabClick(id) { $(\'#dsf67g4d-sai\').find(\\\'[href=\\\\\'#sai-actionlist-\' + id + \'\\\\\']\\\').click(); }[/script]' . $return;
|
||||
$tabs = '';
|
||||
foreach ($this->tabs as $guid => $data)
|
||||
{
|
||||
$buff = '[tab name=\"'.($guid ? 'ActionList #'.$guid : 'Main').'\"][table class=grid width=940px]'.$data.'[/table][/tab]';
|
||||
if ($guid)
|
||||
$tabs .= $buff;
|
||||
else
|
||||
$tabs = $buff . $tabs;
|
||||
}
|
||||
|
||||
return sprintf($return, sprintf($wrapper, $tabs));
|
||||
}
|
||||
else
|
||||
return sprintf($return, '[table class=grid width=940px]'.$this->tabs[0].'[/table]');
|
||||
}
|
||||
|
||||
public function addJsGlobals(array $jsg) : void
|
||||
{
|
||||
Util::mergeJsGlobals($this->jsGlobals, $jsg);
|
||||
}
|
||||
|
||||
public function getJSGlobals() : array
|
||||
{
|
||||
return $this->jsGlobals;
|
||||
}
|
||||
|
||||
public function getTabs() : array
|
||||
{
|
||||
return $this->tabs;
|
||||
}
|
||||
|
||||
public function addTab(int $guid, string $tt) : void
|
||||
{
|
||||
$this->tabs[$guid] = $tt;
|
||||
}
|
||||
|
||||
public function getTarget(int $id = -1) : ?SmartTarget
|
||||
{
|
||||
if ($id < 0)
|
||||
return $this->itr['target'];
|
||||
|
||||
return $this->rawData[$id]['target'] ?? null;
|
||||
}
|
||||
|
||||
public function getAction(int $id = -1) : ?SmartAction
|
||||
{
|
||||
if ($id < 0)
|
||||
return $this->itr['action'];
|
||||
|
||||
return $this->rawData[$id]['action'] ?? null;
|
||||
}
|
||||
|
||||
public function getEvent(int $id = -1) : ?SmartEvent
|
||||
{
|
||||
if ($id < 0)
|
||||
return $this->itr['event'];
|
||||
|
||||
return $this->rawData[$id]['event'] ?? null;
|
||||
}
|
||||
|
||||
public function getEntry() : int
|
||||
{
|
||||
return $this->baseEntry ?: $this->entry;
|
||||
}
|
||||
|
||||
private function initQuotes(int $creatureId) : void
|
||||
{
|
||||
if (isset($this->quotes[$creatureId]))
|
||||
return;
|
||||
|
||||
[$quotes, , ] = Game::getQuotesForCreature($creatureId);
|
||||
|
||||
$this->quotes[$creatureId] = $quotes;
|
||||
|
||||
if (!empty($this->quotes[$creatureId]))
|
||||
$this->quotes[$creatureId]['src'] = CreatureList::getName($creatureId);
|
||||
}
|
||||
|
||||
public function getQuote(int $creatureId, int $group, ?string &$npcSrc) : array
|
||||
{
|
||||
if (isset($this->quotes[$creatureId][$group]))
|
||||
{
|
||||
$npcSrc = $this->quotes[$creatureId]['src'];
|
||||
return $this->quotes[$creatureId][$group];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
746
includes/components/SmartAI/SmartAction.class.php
Normal file
746
includes/components/SmartAI/SmartAction.class.php
Normal file
@@ -0,0 +1,746 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
// TrinityCore - SmartAI
|
||||
class SmartAction
|
||||
{
|
||||
use SmartHelper;
|
||||
|
||||
public const ACTION_NONE = 0; // Do nothing
|
||||
public const ACTION_TALK = 1; // Param2 in Milliseconds.
|
||||
public const ACTION_SET_FACTION = 2; // Sets faction to creature.
|
||||
public const ACTION_MORPH_TO_ENTRY_OR_MODEL = 3; // Take DisplayID of creature (param1) OR Turn to DisplayID (param2) OR Both = 0 for Demorph
|
||||
public const ACTION_SOUND = 4; // TextRange = 0 only sends sound to self, TextRange = 1 sends sound to everyone in visibility range
|
||||
public const ACTION_PLAY_EMOTE = 5; // Play Emote
|
||||
public const ACTION_FAIL_QUEST = 6; // Fail Quest of Target
|
||||
public const ACTION_OFFER_QUEST = 7; // Add Quest to Target
|
||||
public const ACTION_SET_REACT_STATE = 8; // React State. Can be Passive (0), Defensive (1), Aggressive (2), Assist (3).
|
||||
public const ACTION_ACTIVATE_GOBJECT = 9; // Activate Object
|
||||
public const ACTION_RANDOM_EMOTE = 10; // Play Random Emote
|
||||
public const ACTION_CAST = 11; // Cast Spell ID at Target
|
||||
public const ACTION_SUMMON_CREATURE = 12; // Summon Unit
|
||||
public const ACTION_THREAT_SINGLE_PCT = 13; // Change Threat Percentage for Single Target
|
||||
public const ACTION_THREAT_ALL_PCT = 14; // Change Threat Percentage for All Enemies
|
||||
public const ACTION_CALL_AREAEXPLOREDOREVENTHAPPENS = 15; //
|
||||
public const ACTION_SET_INGAME_PHASE_ID = 16; // [RESERVED] For 4.3.4 + only
|
||||
public const ACTION_SET_EMOTE_STATE = 17; // Play Emote Continuously
|
||||
public const ACTION_SET_UNIT_FLAG = 18; // [DEPRECATED] Can set Multi-able flags at once
|
||||
public const ACTION_REMOVE_UNIT_FLAG = 19; // [DEPRECATED] Can Remove Multi-able flags at once
|
||||
public const ACTION_AUTO_ATTACK = 20; // Stop or Continue Automatic Attack.
|
||||
public const ACTION_ALLOW_COMBAT_MOVEMENT = 21; // Allow or Disable Combat Movement
|
||||
public const ACTION_SET_EVENT_PHASE = 22; //
|
||||
public const ACTION_INC_EVENT_PHASE = 23; // Set param1 OR param2 (not both). Value 0 has no effect.
|
||||
public const ACTION_EVADE = 24; // Evade Incoming Attack
|
||||
public const ACTION_FLEE_FOR_ASSIST = 25; // If you want the fleeing NPC to say '%s attempts to run away in fear' on flee, use 1 on param1. 0 for no message.
|
||||
public const ACTION_CALL_GROUPEVENTHAPPENS = 26; //
|
||||
public const ACTION_COMBAT_STOP = 27; //
|
||||
public const ACTION_REMOVEAURASFROMSPELL = 28; // 0 removes all auras
|
||||
public const ACTION_FOLLOW = 29; // Follow Target
|
||||
public const ACTION_RANDOM_PHASE = 30; //
|
||||
public const ACTION_RANDOM_PHASE_RANGE = 31; //
|
||||
public const ACTION_RESET_GOBJECT = 32; // Reset Gameobject
|
||||
public const ACTION_CALL_KILLEDMONSTER = 33; // This is the ID from quest_template.RequiredNpcOrGo
|
||||
public const ACTION_SET_INST_DATA = 34; // Set Instance Data
|
||||
public const ACTION_SET_INST_DATA64 = 35; // Set Instance Data uint64
|
||||
public const ACTION_UPDATE_TEMPLATE = 36; // Updates creature_template to given entry
|
||||
public const ACTION_DIE = 37; // Kill Target
|
||||
public const ACTION_SET_IN_COMBAT_WITH_ZONE = 38; //
|
||||
public const ACTION_CALL_FOR_HELP = 39; // If you want the NPC to say '%s calls for help!'. Use 1 on param1, 0 for no message.
|
||||
public const ACTION_SET_SHEATH = 40; //
|
||||
public const ACTION_FORCE_DESPAWN = 41; // Despawn Target after param1 in Milliseconds. If you want to set respawn time set param2 in seconds.
|
||||
public const ACTION_SET_INVINCIBILITY_HP_LEVEL = 42; // If you use both params, only percent will be used.
|
||||
public const ACTION_MOUNT_TO_ENTRY_OR_MODEL = 43; // Mount to Creature Entry (param1) OR Mount to Creature Display (param2) Or both = 0 for Unmount
|
||||
public const ACTION_SET_INGAME_PHASE_MASK = 44; //
|
||||
public const ACTION_SET_DATA = 45; // Set Data For Target, can be used with SMART_EVENT_DATA_SET
|
||||
public const ACTION_ATTACK_STOP = 46; //
|
||||
public const ACTION_SET_VISIBILITY = 47; // Makes creature Visible = 1 or Invisible = 0
|
||||
public const ACTION_SET_ACTIVE = 48; //
|
||||
public const ACTION_ATTACK_START = 49; // Allows basic melee swings to creature.
|
||||
public const ACTION_SUMMON_GO = 50; // Spawns Gameobject, use target_type to set spawn position.
|
||||
public const ACTION_KILL_UNIT = 51; // Kills Creature.
|
||||
public const ACTION_ACTIVATE_TAXI = 52; // Sends player to flight path. You have to be close to Flight Master, which gives Taxi ID you need.
|
||||
public const ACTION_WP_START = 53; // Creature starts Waypoint Movement. Use waypoints table to create movement.
|
||||
public const ACTION_WP_PAUSE = 54; // Creature pauses its Waypoint Movement for given time.
|
||||
public const ACTION_WP_STOP = 55; // Creature stops its Waypoint Movement.
|
||||
public const ACTION_ADD_ITEM = 56; // Adds item(s) to player.
|
||||
public const ACTION_REMOVE_ITEM = 57; // Removes item(s) from player.
|
||||
public const ACTION_INSTALL_AI_TEMPLATE = 58; // [DEPRECATED]
|
||||
public const ACTION_SET_RUN = 59; //
|
||||
public const ACTION_SET_DISABLE_GRAVITY = 60; // Only works for creatures with inhabit air.
|
||||
public const ACTION_SET_SWIM = 61; // [DEPRECATED]
|
||||
public const ACTION_TELEPORT = 62; // Continue this action with the TARGET_TYPE column. Use any target_type (except 0), and use target_x, target_y, target_z, target_o as the coordinates
|
||||
public const ACTION_SET_COUNTER = 63; //
|
||||
public const ACTION_STORE_TARGET_LIST = 64; //
|
||||
public const ACTION_WP_RESUME = 65; // Creature continues in its Waypoint Movement.
|
||||
public const ACTION_SET_ORIENTATION = 66; //
|
||||
public const ACTION_CREATE_TIMED_EVENT = 67; //
|
||||
public const ACTION_PLAYMOVIE = 68; //
|
||||
public const ACTION_MOVE_TO_POS = 69; // PointId is called by SMART_EVENT_MOVEMENTINFORM. Continue this action with the TARGET_TYPE column. Use any target_type, and use target_x, target_y, target_z, target_o as the coordinates
|
||||
public const ACTION_ENABLE_TEMP_GOBJ = 70; // param1 = duration
|
||||
public const ACTION_EQUIP = 71; // only slots with mask set will be sent to client, bits are 1, 2, 4, leaving mask 0 is defaulted to mask 7 (send all), Slots1-3 are only used if no Param1 is set
|
||||
public const ACTION_CLOSE_GOSSIP = 72; // Closes gossip window.
|
||||
public const ACTION_TRIGGER_TIMED_EVENT = 73; //
|
||||
public const ACTION_REMOVE_TIMED_EVENT = 74; //
|
||||
public const ACTION_ADD_AURA = 75; // [DEPRECATED] Adds aura to player(s). Use target_type 17 to make AoE aura.
|
||||
public const ACTION_OVERRIDE_SCRIPT_BASE_OBJECT = 76; // [DEPRECATED] WARNING: CAN CRASH CORE, do not use if you dont know what you are doing
|
||||
public const ACTION_RESET_SCRIPT_BASE_OBJECT = 77; // [DEPRECATED]
|
||||
public const ACTION_CALL_SCRIPT_RESET = 78; //
|
||||
public const ACTION_SET_RANGED_MOVEMENT = 79; // Sets movement to follow at a specific range to the target.
|
||||
public const ACTION_CALL_TIMED_ACTIONLIST = 80; //
|
||||
public const ACTION_SET_NPC_FLAG = 81; //
|
||||
public const ACTION_ADD_NPC_FLAG = 82; //
|
||||
public const ACTION_REMOVE_NPC_FLAG = 83; //
|
||||
public const ACTION_SIMPLE_TALK = 84; // Makes a player say text. SMART_EVENT_TEXT_OVER is not triggered and whispers can not be used.
|
||||
public const ACTION_SELF_CAST = 85; // spellID, castFlags
|
||||
public const ACTION_CROSS_CAST = 86; // This action is used to make selected caster (in CasterTargetType) to cast spell. Actual target is entered in target_type as normally.
|
||||
public const ACTION_CALL_RANDOM_TIMED_ACTIONLIST = 87; // Will select one entry from the ones provided. 0 is ignored.
|
||||
public const ACTION_CALL_RANDOM_RANGE_TIMED_ACTIONLIST = 88; // 0 is ignored.
|
||||
public const ACTION_RANDOM_MOVE = 89; // Creature moves to random position in given radius.
|
||||
public const ACTION_SET_UNIT_FIELD_BYTES_1 = 90; //
|
||||
public const ACTION_REMOVE_UNIT_FIELD_BYTES_1 = 91; //
|
||||
public const ACTION_INTERRUPT_SPELL = 92; // This action allows you to interrupt the current spell being cast. If you do not set the spellId, the core will find the current spell depending on the withDelay and the withInstant values.
|
||||
public const ACTION_SEND_GO_CUSTOM_ANIM = 93; // [DEPRECATED] oldFlag = newFlag
|
||||
public const ACTION_SET_DYNAMIC_FLAG = 94; // [DEPRECATED] oldFlag |= newFlag
|
||||
public const ACTION_ADD_DYNAMIC_FLAG = 95; // [DEPRECATED] oldFlag &= ~newFlag
|
||||
public const ACTION_REMOVE_DYNAMIC_FLAG = 96; // [DEPRECATED]
|
||||
public const ACTION_JUMP_TO_POS = 97; //
|
||||
public const ACTION_SEND_GOSSIP_MENU = 98; // Can be used together with 'SMART_EVENT_GOSSIP_HELLO' to set custom gossip.
|
||||
public const ACTION_GO_SET_LOOT_STATE = 99; //
|
||||
public const ACTION_SEND_TARGET_TO_TARGET = 100; // Send targets previously stored with SMART_ACTION_STORE_TARGET, to another npc/go, the other npc/go can then access them as if it was its own stored list
|
||||
public const ACTION_SET_HOME_POS = 101; // Use with SMART_TARGET_SELF or SMART_TARGET_POSITION
|
||||
public const ACTION_SET_HEALTH_REGEN = 102; // Sets the current creatures health regen on or off.
|
||||
public const ACTION_SET_ROOT = 103; // Enables or disables creature movement
|
||||
public const ACTION_SET_GO_FLAG = 104; // [DEPRECATED] oldFlag = newFlag
|
||||
public const ACTION_ADD_GO_FLAG = 105; // [DEPRECATED] oldFlag |= newFlag
|
||||
public const ACTION_REMOVE_GO_FLAG = 106; // [DEPRECATED] oldFlag &= ~newFlag
|
||||
public const ACTION_SUMMON_CREATURE_GROUP = 107; // Use creature_summon_groups table. SAI target has no effect, use 0
|
||||
public const ACTION_SET_POWER = 108; //
|
||||
public const ACTION_ADD_POWER = 109; //
|
||||
public const ACTION_REMOVE_POWER = 110; //
|
||||
public const ACTION_GAME_EVENT_STOP = 111; //
|
||||
public const ACTION_GAME_EVENT_START = 112; //
|
||||
public const ACTION_START_CLOSEST_WAYPOINT = 113; // Make target follow closest waypoint to its location
|
||||
public const ACTION_MOVE_OFFSET = 114; // Use target_x, target_y, target_z With target_type=1
|
||||
public const ACTION_RANDOM_SOUND = 115; //
|
||||
public const ACTION_SET_CORPSE_DELAY = 116; //
|
||||
public const ACTION_DISABLE_EVADE = 117; //
|
||||
public const ACTION_GO_SET_GO_STATE = 118; //
|
||||
public const ACTION_SET_CAN_FLY = 119; // [DEPRECATED]
|
||||
public const ACTION_REMOVE_AURAS_BY_TYPE = 120; // [DEPRECATED]
|
||||
public const ACTION_SET_SIGHT_DIST = 121; // [DEPRECATED]
|
||||
public const ACTION_FLEE = 122; // [DEPRECATED]
|
||||
public const ACTION_ADD_THREAT = 123; //
|
||||
public const ACTION_LOAD_EQUIPMENT = 124; //
|
||||
public const ACTION_TRIGGER_RANDOM_TIMED_EVENT = 125; //
|
||||
public const ACTION_REMOVE_ALL_GAMEOBJECTS = 126; // [DEPRECATED]
|
||||
public const ACTION_PAUSE_MOVEMENT = 127; // MovementSlot (default = 0, active = 1, controlled = 2), PauseTime (ms), Force
|
||||
public const ACTION_PLAY_ANIMKIT = 128; // [RESERVED] don't use on 3.3.5a
|
||||
public const ACTION_SCENE_PLAY = 129; // [RESERVED] don't use on 3.3.5a
|
||||
public const ACTION_SCENE_CANCEL = 130; // [RESERVED] don't use on 3.3.5a
|
||||
public const ACTION_SPAWN_SPAWNGROUP = 131; //
|
||||
public const ACTION_DESPAWN_SPAWNGROUP = 132; //
|
||||
public const ACTION_RESPAWN_BY_SPAWNID = 133; // type, typeGuid - Use to respawn npcs and gobs, the target in this case is always=1 and only a single unit could be a target via the spawnId (action_param1, action_param2)
|
||||
public const ACTION_INVOKER_CAST = 134; // spellID, castFlags
|
||||
public const ACTION_PLAY_CINEMATIC = 135; // cinematic
|
||||
public const ACTION_SET_MOVEMENT_SPEED = 136; // movementType, speedInteger, speedFraction
|
||||
public const ACTION_PLAY_SPELL_VISUAL_KIT = 137; // [RESERVED] spellVisualKitId
|
||||
public const ACTION_OVERRIDE_LIGHT = 138; // zoneId, areaLightId, overrideLightID, transitionMilliseconds
|
||||
public const ACTION_OVERRIDE_WEATHER = 139; // zoneId, weatherId, intensity
|
||||
public const ACTION_SET_AI_ANIM_KIT = 140; // [RESERVED]
|
||||
public const ACTION_SET_HOVER = 141; // Enable/Disable hover for target units.
|
||||
public const ACTION_SET_HEALTH_PCT = 142; // Set current health percentage of target units.
|
||||
public const ACTION_CREATE_CONVERSATION = 143; // [RESERVED]
|
||||
public const ACTION_SET_IMMUNE_PC = 144; // Enable/Disable immunity to players of target units.
|
||||
public const ACTION_SET_IMMUNE_NPC = 145; // Enable/Disable immunity to creatures of target units.
|
||||
public const ACTION_SET_UNINTERACTIBLE = 146; // Make/Reset target units uninteractible.
|
||||
public const ACTION_ACTIVATE_GAMEOBJECT = 147; // Activate target gameobjects, using given action.
|
||||
public const ACTION_ADD_TO_STORED_TARGET_LIST = 148; // Add selected targets to varID for later use.
|
||||
public const ACTION_BECOME_PERSONAL_CLONE_FOR_PLAYER = 149; // [RESERVED]
|
||||
public const ACTION_TRIGGER_GAME_EVENT = 150; // [RESERVED]
|
||||
public const ACTION_DO_ACTION = 151; // [RESERVED]
|
||||
|
||||
public const ACTION_ALL_SPELLCASTS = [self::ACTION_CAST, self::ACTION_ADD_AURA, self::ACTION_INVOKER_CAST, self::ACTION_SELF_CAST, self::ACTION_CROSS_CAST];
|
||||
public const ACTION_ALL_TIMED_ACTION_LISTS = [self::ACTION_CALL_TIMED_ACTIONLIST, self::ACTION_CALL_RANDOM_TIMED_ACTIONLIST, self::ACTION_CALL_RANDOM_RANGE_TIMED_ACTIONLIST];
|
||||
|
||||
private const ACTION_CELL_TPL = '[tooltip name=a-#rowIdx#]%1$s[/tooltip][span tooltip=a-#rowIdx#]%2$s[/span]';
|
||||
private const TAL_TAB_ANCHOR = '[url=#sai-actionlist-%1$d onclick=TalTabClick(%1$d)]#%1$d[/url]';
|
||||
|
||||
private array $data = array(
|
||||
self::ACTION_NONE => [null, null, null, null, null, null, 0], // No action
|
||||
self::ACTION_TALK => [null, ['formatTime', -1, true], null, null, null, null, 0], // groupID from creature_text, duration to wait before TEXT_OVER event is triggered, useTalkTarget (0/1) - use target as talk target
|
||||
self::ACTION_SET_FACTION => [null, null, null, null, null, null, 0], // FactionId (or 0 for default)
|
||||
self::ACTION_MORPH_TO_ENTRY_OR_MODEL => [Type::NPC, null, null, null, null, null, 0], // Creature_template entry(param1) OR ModelId (param2) (or 0 for both to demorph)
|
||||
self::ACTION_SOUND => [Type::SOUND, null, null, null, null, null, 0], // SoundId, onlySelf
|
||||
self::ACTION_PLAY_EMOTE => [null, null, null, null, null, null, 0], // EmoteId
|
||||
self::ACTION_FAIL_QUEST => [Type::QUEST, null, null, null, null, null, 0], // QuestID
|
||||
self::ACTION_OFFER_QUEST => [Type::QUEST, null, null, null, null, null, 0], // QuestID, directAdd
|
||||
self::ACTION_SET_REACT_STATE => [['reactState', 10, false], null, null, null, null, null, 0], // state
|
||||
self::ACTION_ACTIVATE_GOBJECT => [null, null, null, null, null, null, 0], //
|
||||
self::ACTION_RANDOM_EMOTE => [null, null, null, null, null, null, 0], // EmoteId1, EmoteId2, EmoteId3...
|
||||
self::ACTION_CAST => [Type::SPELL, ['castFlags', -1, false], null, null, null, null, 0], // SpellId, CastFlags, TriggeredFlags
|
||||
self::ACTION_SUMMON_CREATURE => [Type::NPC, ['summonType', -1, false], ['formatTime', 10, true], null, null, null, 0], // CreatureID, summonType, duration in ms, attackInvoker, flags(SmartActionSummonCreatureFlags)
|
||||
self::ACTION_THREAT_SINGLE_PCT => [null, null, null, null, null, null, 0], // Threat%
|
||||
self::ACTION_THREAT_ALL_PCT => [null, null, null, null, null, null, 0], // Threat%
|
||||
self::ACTION_CALL_AREAEXPLOREDOREVENTHAPPENS => [Type::QUEST, null, null, null, null, null, 0], // QuestID
|
||||
self::ACTION_SET_INGAME_PHASE_ID => [null, null, null, null, null, null, 2], // used on 4.3.4 and higher scripts
|
||||
self::ACTION_SET_EMOTE_STATE => [null, null, null, null, null, null, 0], // emoteID
|
||||
self::ACTION_SET_UNIT_FLAG => [['unitFlags', 10, false], null, null, null, null, null, 1], // UNUSED, DO NOT REUSE
|
||||
self::ACTION_REMOVE_UNIT_FLAG => [['unitFlags', 10, false], null, null, null, null, null, 1], // UNUSED, DO NOT REUSE
|
||||
self::ACTION_AUTO_ATTACK => [null, null, null, null, null, null, 0], // AllowAttackState (0 = stop attack, anything else means continue attacking)
|
||||
self::ACTION_ALLOW_COMBAT_MOVEMENT => [null, null, null, null, null, null, 0], // AllowCombatMovement (0 = stop combat based movement, anything else continue attacking)
|
||||
self::ACTION_SET_EVENT_PHASE => [null, null, null, null, null, null, 0], // Phase
|
||||
self::ACTION_INC_EVENT_PHASE => [null, null, null, null, null, null, 0], // Value (may be negative to decrement phase, should not be 0)
|
||||
self::ACTION_EVADE => [null, null, null, null, null, null, 0], // toRespawnPosition (0 = Move to RespawnPosition, 1 = Move to last stored home position)
|
||||
self::ACTION_FLEE_FOR_ASSIST => [null, null, null, null, null, null, 0], // With Emote
|
||||
self::ACTION_CALL_GROUPEVENTHAPPENS => [Type::QUEST, null, null, null, null, null, 0], // QuestID
|
||||
self::ACTION_COMBAT_STOP => [null, null, null, null, null, null, 0], //
|
||||
self::ACTION_REMOVEAURASFROMSPELL => [Type::SPELL, null, null, null, null, null, 0], // Spellid (0 removes all auras), charges (0 removes aura)
|
||||
self::ACTION_FOLLOW => [null, null, null, null, null, null, 0], // Distance (0 = default), Angle (0 = default), EndCreatureEntry, credit, creditType (0monsterkill, 1event)
|
||||
self::ACTION_RANDOM_PHASE => [null, null, null, null, null, null, 0], // PhaseId1, PhaseId2, PhaseId3...
|
||||
self::ACTION_RANDOM_PHASE_RANGE => [null, null, null, null, null, null, 0], // PhaseMin, PhaseMax
|
||||
self::ACTION_RESET_GOBJECT => [null, null, null, null, null, null, 0], //
|
||||
self::ACTION_CALL_KILLEDMONSTER => [Type::NPC, null, null, null, null, null, 0], // CreatureId,
|
||||
self::ACTION_SET_INST_DATA => [null, null, null, null, null, null, 0], // Field, Data, Type (0 = SetData, 1 = SetBossState)
|
||||
self::ACTION_SET_INST_DATA64 => [null, null, null, null, null, null, 0], // Field,
|
||||
self::ACTION_UPDATE_TEMPLATE => [Type::NPC, null, null, null, null, null, 0], // Entry
|
||||
self::ACTION_DIE => [null, null, null, null, null, null, 0], // No Params
|
||||
self::ACTION_SET_IN_COMBAT_WITH_ZONE => [null, null, null, null, null, null, 0], // No Params
|
||||
self::ACTION_CALL_FOR_HELP => [null, null, null, null, null, null, 0], // Radius, With Emote
|
||||
self::ACTION_SET_SHEATH => [['sheathState', 10, false], null, null, null, null, null, 0], // Sheath (0-unarmed, 1-melee, 2-ranged)
|
||||
self::ACTION_FORCE_DESPAWN => [['formatTime', 10, true], ['formatTime', 11, false], null, null, null, null, 0], // timer
|
||||
self::ACTION_SET_INVINCIBILITY_HP_LEVEL => [null, null, null, null, null, null, 0], // MinHpValue(+pct, -flat)
|
||||
self::ACTION_MOUNT_TO_ENTRY_OR_MODEL => [Type::NPC, null, null, null, null, null, 0], // Creature_template entry(param1) OR ModelId (param2) (or 0 for both to dismount)
|
||||
self::ACTION_SET_INGAME_PHASE_MASK => [null, null, null, null, null, null, 0], // mask
|
||||
self::ACTION_SET_DATA => [null, null, null, null, null, null, 0], // Field, Data (only creature @todo)
|
||||
self::ACTION_ATTACK_STOP => [null, null, null, null, null, null, 0], //
|
||||
self::ACTION_SET_VISIBILITY => [null, null, null, null, null, null, 0], // on/off
|
||||
self::ACTION_SET_ACTIVE => [null, null, null, null, null, null, 0], // on/off
|
||||
self::ACTION_ATTACK_START => [null, null, null, null, null, null, 0], //
|
||||
self::ACTION_SUMMON_GO => [Type::OBJECT, ['formatTime', 10, false], null, null, null, null, 0], // GameObjectID, DespawnTime in s
|
||||
self::ACTION_KILL_UNIT => [null, null, null, null, null, null, 0], //
|
||||
self::ACTION_ACTIVATE_TAXI => [null, null, null, null, null, null, 0], // TaxiID
|
||||
self::ACTION_WP_START => [null, null, null, Type::QUEST, ['formatTime', 10, true], ['reactState', 11, false], 0], // run/walk, pathID, canRepeat, quest, despawntime
|
||||
self::ACTION_WP_PAUSE => [['formatTime', 10, true], null, null, null, null, null, 0], // time
|
||||
self::ACTION_WP_STOP => [['formatTime', 10, true], Type::QUEST, null, null, null, null, 0], // despawnTime, quest, fail?
|
||||
self::ACTION_ADD_ITEM => [Type::ITEM, null, null, null, null, null, 0], // itemID, count
|
||||
self::ACTION_REMOVE_ITEM => [Type::ITEM, null, null, null, null, null, 0], // itemID, count
|
||||
self::ACTION_INSTALL_AI_TEMPLATE => [['aiTemplate', 10, false], null, null, null, null, null, 1], // UNUSED, DO NOT REUSE
|
||||
self::ACTION_SET_RUN => [null, null, null, null, null, null, 0], // 0/1
|
||||
self::ACTION_SET_DISABLE_GRAVITY => [null, null, null, null, null, null, 0], // 0/1
|
||||
self::ACTION_SET_SWIM => [null, null, null, null, null, null, 1], // UNUSED, DO NOT REUSE
|
||||
self::ACTION_TELEPORT => [null, null, null, null, null, null, 0], // mapID,
|
||||
self::ACTION_SET_COUNTER => [null, null, null, null, null, null, 0], // id, value, reset (0/1)
|
||||
self::ACTION_STORE_TARGET_LIST => [null, null, null, null, null, null, 0], // varID,
|
||||
self::ACTION_WP_RESUME => [null, null, null, null, null, null, 0], // none
|
||||
self::ACTION_SET_ORIENTATION => [null, null, null, null, null, null, 0], //
|
||||
self::ACTION_CREATE_TIMED_EVENT => [null, ['numRange', 10, true], null, ['numRange', -1, true], null, null, 0], // id, InitialMin, InitialMax, RepeatMin(only if it repeats), RepeatMax(only if it repeats), chance
|
||||
self::ACTION_PLAYMOVIE => [null, null, null, null, null, null, 0], // entry
|
||||
self::ACTION_MOVE_TO_POS => [null, null, null, null, null, null, 0], // PointId, transport, disablePathfinding, ContactDistance
|
||||
self::ACTION_ENABLE_TEMP_GOBJ => [['formatTime', 10, false], null, null, null, null, null, 0], // despawnTimer (sec)
|
||||
self::ACTION_EQUIP => [null, null, Type::ITEM, Type::ITEM, Type::ITEM, null, 0], // entry, slotmask slot1, slot2, slot3 , only slots with mask set will be sent to client, bits are 1, 2, 4, leaving mask 0 is defaulted to mask 7 (send all), slots1-3 are only used if no entry is set
|
||||
self::ACTION_CLOSE_GOSSIP => [null, null, null, null, null, null, 0], // none
|
||||
self::ACTION_TRIGGER_TIMED_EVENT => [null, null, null, null, null, null, 0], // id(>1)
|
||||
self::ACTION_REMOVE_TIMED_EVENT => [null, null, null, null, null, null, 0], // id(>1)
|
||||
self::ACTION_ADD_AURA => [null, null, null, null, null, null, 1], // UNUSED, DO NOT REUSE
|
||||
self::ACTION_OVERRIDE_SCRIPT_BASE_OBJECT => [null, null, null, null, null, null, 1], // UNUSED, DO NOT REUSE
|
||||
self::ACTION_RESET_SCRIPT_BASE_OBJECT => [null, null, null, null, null, null, 1], // UNUSED, DO NOT REUSE
|
||||
self::ACTION_CALL_SCRIPT_RESET => [null, null, null, null, null, null, 0], // none
|
||||
self::ACTION_SET_RANGED_MOVEMENT => [null, null, null, null, null, null, 0], // Distance, angle
|
||||
self::ACTION_CALL_TIMED_ACTIONLIST => [null, null, null, null, null, null, 0], // ID (overwrites already running actionlist), stop after combat?(0/1), timer update type(0-OOC, 1-IC, 2-ALWAYS)
|
||||
self::ACTION_SET_NPC_FLAG => [['npcFlags', 10, false], null, null, null, null, null, 0], // Flags
|
||||
self::ACTION_ADD_NPC_FLAG => [['npcFlags', 10, false], null, null, null, null, null, 0], // Flags
|
||||
self::ACTION_REMOVE_NPC_FLAG => [['npcFlags', 10, false], null, null, null, null, null, 0], // Flags
|
||||
self::ACTION_SIMPLE_TALK => [null, null, null, null, null, null, 0], // groupID, can be used to make players say groupID, Text_over event is not triggered, whisper can not be used (Target units will say the text)
|
||||
self::ACTION_SELF_CAST => [Type::SPELL, ['castFlags', -1, false], null, null, null, null, 0], // spellID, castFlags
|
||||
self::ACTION_CROSS_CAST => [Type::SPELL, ['castFlags', -1, false], null, null, null, null, 0], // spellID, castFlags, CasterTargetType, CasterTarget param1, CasterTarget param2, CasterTarget param3, ( + the origonal target fields as Destination target), CasterTargets will cast spellID on all Targets (use with caution if targeting multiple * multiple units)
|
||||
self::ACTION_CALL_RANDOM_TIMED_ACTIONLIST => [null, null, null, null, null, null, 0], // script9 ids 1-9
|
||||
self::ACTION_CALL_RANDOM_RANGE_TIMED_ACTIONLIST => [null, null, null, null, null, null, 0], // script9 id min, max
|
||||
self::ACTION_RANDOM_MOVE => [null, null, null, null, null, null, 0], // maxDist
|
||||
self::ACTION_SET_UNIT_FIELD_BYTES_1 => [['unitFieldBytes1', 10, false], null, null, null, null, null, 0], // bytes, target
|
||||
self::ACTION_REMOVE_UNIT_FIELD_BYTES_1 => [['unitFieldBytes1', 10, false], null, null, null, null, null, 0], // bytes, target
|
||||
self::ACTION_INTERRUPT_SPELL => [null, Type::SPELL, null, null, null, null, 0], //
|
||||
self::ACTION_SEND_GO_CUSTOM_ANIM => [['dynFlags', 10, false], null, null, null, null, null, 1], // UNUSED, DO NOT REUSE
|
||||
self::ACTION_SET_DYNAMIC_FLAG => [['dynFlags', 10, false], null, null, null, null, null, 1], // UNUSED, DO NOT REUSE
|
||||
self::ACTION_ADD_DYNAMIC_FLAG => [['dynFlags', 10, false], null, null, null, null, null, 1], // UNUSED, DO NOT REUSE
|
||||
self::ACTION_REMOVE_DYNAMIC_FLAG => [null, null, null, null, null, null, 1], // UNUSED, DO NOT REUSE
|
||||
self::ACTION_JUMP_TO_POS => [null, null, null, null, null, null, 0], // speedXY, speedZ, targetX, targetY, targetZ
|
||||
self::ACTION_SEND_GOSSIP_MENU => [null, null, null, null, null, null, 0], // menuId, optionId
|
||||
self::ACTION_GO_SET_LOOT_STATE => [['lootState', 10, false], null, null, null, null, null, 0], // state
|
||||
self::ACTION_SEND_TARGET_TO_TARGET => [null, null, null, null, null, null, 0], // id
|
||||
self::ACTION_SET_HOME_POS => [null, null, null, null, null, null, 0], // none
|
||||
self::ACTION_SET_HEALTH_REGEN => [null, null, null, null, null, null, 0], // 0/1
|
||||
self::ACTION_SET_ROOT => [null, null, null, null, null, null, 0], // off/on
|
||||
self::ACTION_SET_GO_FLAG => [['goFlags', 10, false], null, null, null, null, null, 1], // UNUSED, DO NOT REUSE
|
||||
self::ACTION_ADD_GO_FLAG => [['goFlags', 10, false], null, null, null, null, null, 1], // UNUSED, DO NOT REUSE
|
||||
self::ACTION_REMOVE_GO_FLAG => [['goFlags', 10, false], null, null, null, null, null, 1], // UNUSED, DO NOT REUSE
|
||||
self::ACTION_SUMMON_CREATURE_GROUP => [null, null, null, null, null, null, 0], // Group, attackInvoker
|
||||
self::ACTION_SET_POWER => [['powerType', 10, false], null, null, null, null, null, 0], // PowerType, newPower
|
||||
self::ACTION_ADD_POWER => [['powerType', 10, false], null, null, null, null, null, 0], // PowerType, newPower
|
||||
self::ACTION_REMOVE_POWER => [['powerType', 10, false], null, null, null, null, null, 0], // PowerType, newPower
|
||||
self::ACTION_GAME_EVENT_STOP => [Type::WORLDEVENT, null, null, null, null, null, 0], // GameEventId
|
||||
self::ACTION_GAME_EVENT_START => [Type::WORLDEVENT, null, null, null, null, null, 0], // GameEventId
|
||||
self::ACTION_START_CLOSEST_WAYPOINT => [null, null, null, null, null, null, 0], // wp1, wp2, wp3, wp4, wp5, wp6, wp7
|
||||
self::ACTION_MOVE_OFFSET => [null, null, null, null, null, null, 0], //
|
||||
self::ACTION_RANDOM_SOUND => [Type::SOUND, Type::SOUND, Type::SOUND, Type::SOUND, null, null, 0], // soundId1, soundId2, soundId3, soundId4, soundId5, onlySelf
|
||||
self::ACTION_SET_CORPSE_DELAY => [['formatTime', 10, false], null, null, null, null, null, 0], // timer
|
||||
self::ACTION_DISABLE_EVADE => [null, null, null, null, null, null, 0], // 0/1 (1 = disabled, 0 = enabled)
|
||||
self::ACTION_GO_SET_GO_STATE => [null, null, null, null, null, null, 0], // state
|
||||
self::ACTION_SET_CAN_FLY => [null, null, null, null, null, null, 1], // UNUSED, DO NOT REUSE
|
||||
self::ACTION_REMOVE_AURAS_BY_TYPE => [null, null, null, null, null, null, 1], // UNUSED, DO NOT REUSE
|
||||
self::ACTION_SET_SIGHT_DIST => [null, null, null, null, null, null, 1], // UNUSED, DO NOT REUSE
|
||||
self::ACTION_FLEE => [['formatTime', 10, false], null, null, null, null, null, 1], // UNUSED, DO NOT REUSE
|
||||
self::ACTION_ADD_THREAT => [null, null, null, null, null, null, 0], // +threat, -threat
|
||||
self::ACTION_LOAD_EQUIPMENT => [null, null, null, null, null, null, 0], // id
|
||||
self::ACTION_TRIGGER_RANDOM_TIMED_EVENT => [['numRange', 10, false], null, null, null, null, null, 0], // id min range, id max range
|
||||
self::ACTION_REMOVE_ALL_GAMEOBJECTS => [null, null, null, null, null, null, 1], // UNUSED, DO NOT REUSE
|
||||
self::ACTION_PAUSE_MOVEMENT => [null, ['formatTime', 10, true], null, null, null, null, 0], // MovementSlot (default = 0, active = 1, controlled = 2), PauseTime (ms), Force
|
||||
self::ACTION_PLAY_ANIMKIT => [null, null, null, null, null, null, 2], // don't use on 3.3.5a
|
||||
self::ACTION_SCENE_PLAY => [null, null, null, null, null, null, 2], // don't use on 3.3.5a
|
||||
self::ACTION_SCENE_CANCEL => [null, null, null, null, null, null, 2], // don't use on 3.3.5a
|
||||
self::ACTION_SPAWN_SPAWNGROUP => [null, null, null, ['spawnFlags', 11, false], null, null, 0], // Group ID, min secs, max secs, spawnflags
|
||||
self::ACTION_DESPAWN_SPAWNGROUP => [null, null, null, ['spawnFlags', 11, false], null, null, 0], // Group ID, min secs, max secs, spawnflags
|
||||
self::ACTION_RESPAWN_BY_SPAWNID => [null, null, null, null, null, null, 0], // spawnType, spawnId
|
||||
self::ACTION_INVOKER_CAST => [Type::SPELL, ['castFlags', -1, false], null, null, null, null, 0], // spellID, castFlags
|
||||
self::ACTION_PLAY_CINEMATIC => [null, null, null, null, null, null, 0], // entry, cinematic
|
||||
self::ACTION_SET_MOVEMENT_SPEED => [null, null, null, null, null, null, 0], // movementType, speedInteger, speedFraction
|
||||
self::ACTION_PLAY_SPELL_VISUAL_KIT => [null, null, null, null, null, null, 2], // spellVisualKitId (RESERVED, PENDING CHERRYPICK)
|
||||
self::ACTION_OVERRIDE_LIGHT => [Type::ZONE, null, null, ['formatTime', -1, true], null, null, 0], // zoneId, overrideLightID, transitionMilliseconds
|
||||
self::ACTION_OVERRIDE_WEATHER => [Type::ZONE, ['weatherState', 10, false], null, null, null, null, 0], // zoneId, weatherId, intensity
|
||||
self::ACTION_SET_AI_ANIM_KIT => [null, null, null, null, null, null, 2], // DEPRECATED, DO REUSE (it was never used in any branch, treat as free action id)
|
||||
self::ACTION_SET_HOVER => [null, null, null, null, null, null, 0], // 0/1
|
||||
self::ACTION_SET_HEALTH_PCT => [null, null, null, null, null, null, 0], // percent
|
||||
self::ACTION_CREATE_CONVERSATION => [null, null, null, null, null, null, 2], // don't use on 3.3.5a
|
||||
self::ACTION_SET_IMMUNE_PC => [null, null, null, null, null, null, 0], // 0/1
|
||||
self::ACTION_SET_IMMUNE_NPC => [null, null, null, null, null, null, 0], // 0/1
|
||||
self::ACTION_SET_UNINTERACTIBLE => [null, null, null, null, null, null, 0], // 0/1
|
||||
self::ACTION_ACTIVATE_GAMEOBJECT => [null, null, null, null, null, null, 0], // GameObjectActions
|
||||
self::ACTION_ADD_TO_STORED_TARGET_LIST => [null, null, null, null, null, null, 0], // varID
|
||||
self::ACTION_BECOME_PERSONAL_CLONE_FOR_PLAYER => [null, null, null, null, null, null, 2], // don't use on 3.3.5a
|
||||
self::ACTION_TRIGGER_GAME_EVENT => [null, null, null, null, null, null, 2], // eventId, useSaiTargetAsGameEventSource (RESERVED, PENDING CHERRYPICK)
|
||||
self::ACTION_DO_ACTION => [null, null, null, null, null, null, 2] // actionId (RESERVED, PENDING CHERRYPICK)
|
||||
);
|
||||
|
||||
private array $jsGlobals = [];
|
||||
private ?array $summons = null;
|
||||
|
||||
public function __construct(
|
||||
private int $id,
|
||||
public readonly int $type,
|
||||
private array $param,
|
||||
private SmartAI &$smartAI)
|
||||
{
|
||||
// init additional parameters
|
||||
Util::checkNumeric($this->param, NUM_CAST_INT);
|
||||
$this->param = array_pad($this->param, 15, '');
|
||||
}
|
||||
|
||||
public function process() : array
|
||||
{
|
||||
$body =
|
||||
$footer = '';
|
||||
|
||||
$actionTT = Lang::smartAI('actionTT', array_merge([$this->type], $this->param));
|
||||
|
||||
for ($i = 0; $i < 5; $i++)
|
||||
{
|
||||
$aParams = $this->data[$this->type];
|
||||
|
||||
if (is_array($aParams[$i]))
|
||||
{
|
||||
[$fn, $idx, $extraParam] = $aParams[$i];
|
||||
|
||||
if ($idx < 0)
|
||||
$footer = $this->{$fn}($this->param[$i], $this->param[$i + 1], $extraParam);
|
||||
else
|
||||
$this->param[$idx] = $this->{$fn}($this->param[$i], $this->param[$i + 1], $extraParam);
|
||||
}
|
||||
else if (is_int($aParams[$i]) && $this->param[$i])
|
||||
$this->jsGlobals[$aParams[$i]][$this->param[$i]] = $this->param[$i];
|
||||
}
|
||||
|
||||
// non-generic cases
|
||||
switch ($this->type)
|
||||
{
|
||||
case self::ACTION_FLEE_FOR_ASSIST: // 25 -> none
|
||||
case self::ACTION_CALL_FOR_HELP: // 39 -> self
|
||||
if ($this->param[0])
|
||||
$footer = $this->param;
|
||||
break;
|
||||
case self::ACTION_INTERRUPT_SPELL: // 92 -> self
|
||||
if (!$this->param[1])
|
||||
$footer = $this->param;
|
||||
break;
|
||||
case self::ACTION_UPDATE_TEMPLATE: // 36
|
||||
case self::ACTION_SET_CORPSE_DELAY: // 116
|
||||
if ($this->param[1])
|
||||
$footer = $this->param;
|
||||
break;
|
||||
case self::ACTION_PAUSE_MOVEMENT: // 127 -> any target [ye, not gonna resolve this nonsense]
|
||||
case self::ACTION_REMOVEAURASFROMSPELL: // 28 -> any target
|
||||
case self::ACTION_SOUND: // 4 -> self [param3 set in DB but not used in core?]
|
||||
case self::ACTION_SUMMON_GO: // 50 -> self, world coords
|
||||
case self::ACTION_MOVE_TO_POS: // 69 -> any target
|
||||
if ($this->param[2])
|
||||
$footer = $this->param;
|
||||
break;
|
||||
case self::ACTION_WP_START: // 53 -> any .. why tho?
|
||||
if ($this->param[2] || $this->param[5])
|
||||
$footer = $this->param;
|
||||
break;
|
||||
case self::ACTION_PLAY_EMOTE: // 5 -> any target
|
||||
case self::ACTION_SET_EMOTE_STATE: // 17 -> any target
|
||||
if ($this->param[0])
|
||||
{
|
||||
$this->param[0] *= -1; // handle creature emote
|
||||
$this->jsGlobals[Type::EMOTE][$this->param[0]] = $this->param[0];
|
||||
}
|
||||
break;
|
||||
case self::ACTION_RANDOM_EMOTE: // 10 -> any target
|
||||
$buff = [];
|
||||
for ($i = 0; $i < 6; $i++)
|
||||
{
|
||||
if (empty($this->param[$i]))
|
||||
continue;
|
||||
|
||||
$this->param[$i] *= -1; // handle creature emote
|
||||
$buff[] = '[emote='.$this->param[$i].']';
|
||||
$this->jsGlobals[Type::EMOTE][$this->param[$i]] = $this->param[$i];
|
||||
}
|
||||
$this->param[10] = Lang::concat($buff, false);
|
||||
break;
|
||||
case self::ACTION_SET_FACTION: // 2 -> any target
|
||||
if ($this->param[0])
|
||||
{
|
||||
$this->param[10] = DB::Aowow()->selectCell('SELECT `factionId` FROM ?_factiontemplate WHERE `id` = ?d', $this->param[0]);
|
||||
$this->jsGlobals[Type::FACTION][$this->param[10]] = $this->param[10];
|
||||
}
|
||||
break;
|
||||
case self::ACTION_MORPH_TO_ENTRY_OR_MODEL: // 3 -> self
|
||||
case self::ACTION_MOUNT_TO_ENTRY_OR_MODEL: // 43 -> self
|
||||
if (!$this->param[0] && !$this->param[1])
|
||||
$this->param[10] = 1;
|
||||
break;
|
||||
case self::ACTION_THREAT_SINGLE_PCT: // 13 -> victim
|
||||
case self::ACTION_THREAT_ALL_PCT: // 14 -> self
|
||||
case self::ACTION_ADD_THREAT: // 123 -> any target
|
||||
$this->param[10] = $this->param[0] - $this->param[1];
|
||||
break;
|
||||
case self::ACTION_FOLLOW: // 29 -> any target
|
||||
if ($this->param[1])
|
||||
{
|
||||
$this->param[10] = Util::O2Deg($this->param[1])[0];
|
||||
$footer = $this->param;
|
||||
}
|
||||
if ($this->param[3])
|
||||
{
|
||||
if ($this->param[4])
|
||||
{
|
||||
$this->jsGlobals[Type::QUEST][$this->param[3]] = $this->param[3];
|
||||
$this->param[11] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->jsGlobals[Type::NPC][$this->param[3]] = $this->param[3];
|
||||
$this->param[12] = 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case self::ACTION_RANDOM_PHASE: // 30 -> self
|
||||
$buff = [];
|
||||
for ($i = 0; $i < 7; $i++)
|
||||
if ($_ = $this->param[$i])
|
||||
$buff[] = $_;
|
||||
|
||||
$this->param[10] = Lang::concat($buff);
|
||||
break;
|
||||
case self::ACTION_ACTIVATE_TAXI: // 52 -> invoker
|
||||
$nodes = DB::Aowow()->selectRow(
|
||||
'SELECT tn1.`name_loc0` AS "start_loc0", tn1.name_loc?d AS start_loc?d, tn2.`name_loc0` AS "end_loc0", tn2.name_loc?d AS end_loc?d
|
||||
FROM ?_taxipath tp
|
||||
JOIN ?_taxinodes tn1 ON tp.`startNodeId` = tn1.`id`
|
||||
JOIN ?_taxinodes tn2 ON tp.`endNodeId` = tn2.`id`
|
||||
WHERE tp.`id` = ?d',
|
||||
Lang::getLocale()->value, Lang::getLocale()->value, Lang::getLocale()->value, Lang::getLocale()->value, $this->param[0]
|
||||
);
|
||||
$this->param[10] = Util::jsEscape(Util::localizedString($nodes, 'start'));
|
||||
$this->param[11] = Util::jsEscape(Util::localizedString($nodes, 'end'));
|
||||
break;
|
||||
case self::ACTION_SET_INGAME_PHASE_MASK: // 44 -> any target
|
||||
if ($this->param[0])
|
||||
$this->param[10] = Lang::concat(Util::mask2bits($this->param[0]));
|
||||
break;
|
||||
case self::ACTION_TELEPORT: // 62 -> invoker
|
||||
[$x, $y, $z, $o] = $this->smartAI->getTarget()->getWorldPos();
|
||||
// try from areatrigger setup data
|
||||
if ($this->smartAI->teleportTargetArea)
|
||||
$this->param[10] = $this->smartAI->teleportTargetArea;
|
||||
// try calc from SmartTarget data
|
||||
else if ($pos = Game::worldPosToZonePos($this->param[0], $x, $y))
|
||||
{
|
||||
$this->param[10] = $pos[0]['areaId'];
|
||||
$this->param[11] = str_pad($pos[0]['posX'] * 10, 3, '0', STR_PAD_LEFT).str_pad($pos[0]['posY'] * 10, 3, '0', STR_PAD_LEFT);
|
||||
}
|
||||
// maybe the mapId is an instane map
|
||||
else if ($areaId = DB::Aowow()->selectCell('SELECT `id` FROM ?_zones WHERE `mapId` = ?d', $this->param[0]))
|
||||
$this->param[10] = $areaId;
|
||||
// ...whelp
|
||||
else
|
||||
trigger_error('SmartAction::process - could not resolve teleport target: map:'.$this->param[0].' x:'.$x.' y:'.$y);
|
||||
|
||||
if ($this->param[10])
|
||||
$this->jsGlobals[Type::ZONE][$this->param[10]] = $this->param[10];
|
||||
break;
|
||||
case self::ACTION_SET_ORIENTATION: // 66 -> any target
|
||||
if ($this->smartAI->getTarget()->type == SmartTarget::TARGET_POSITION)
|
||||
$this->param[10] = Util::O2Deg($this->smartAI->getTarget()->getWorldPos()[3])[1];
|
||||
else if ($this->smartAI->getTarget()->type != SmartTarget::TARGET_SELF)
|
||||
$this->param[10] = '#target#';
|
||||
break;
|
||||
case self::ACTION_EQUIP: // 71 -> any
|
||||
$equip = [];
|
||||
|
||||
if ($this->param[0])
|
||||
{
|
||||
$slots = $this->param[1] ? Util::mask2bits($this->param[1], 1) : [1, 2, 3];
|
||||
$items = DB::World()->selectRow('SELECT `ItemID1`, `ItemID2`, `ItemID3` FROM creature_equip_template WHERE `CreatureID` = ?d AND `ID` = ?d', $this->smartAI->getEntry(), $this->param[0]);
|
||||
|
||||
foreach ($slots as $s)
|
||||
if ($_ = $items['ItemID'.$s])
|
||||
$equip[] = $_;
|
||||
}
|
||||
else if ($this->param[2] || $this->param[3] || $this->param[4])
|
||||
{
|
||||
if ($_ = $this->param[2])
|
||||
$equip[] = $_;
|
||||
if ($_ = $this->param[3])
|
||||
$equip[] = $_;
|
||||
if ($_ = $this->param[4])
|
||||
$equip[] = $_;
|
||||
}
|
||||
|
||||
if ($equip)
|
||||
{
|
||||
$this->param[10] = Lang::concat($equip, callback: fn($x) => '[item='.$x.']');
|
||||
$footer = true;
|
||||
|
||||
foreach ($equip as $_)
|
||||
$this->jsGlobals[Type::ITEM][$_] = $_;
|
||||
}
|
||||
break;
|
||||
case self::ACTION_LOAD_EQUIPMENT: // 124 -> any target
|
||||
$buff = [];
|
||||
if ($this->param[0])
|
||||
{
|
||||
$items = DB::World()->selectRow('SELECT `ItemID1`, `ItemID2`, `ItemID3` FROM creature_equip_template WHERE `CreatureID` = ?d AND `ID` = ?d', $this->smartAI->getEntry(), $this->param[0]);
|
||||
foreach ($items as $i)
|
||||
{
|
||||
if (!$i)
|
||||
continue;
|
||||
|
||||
$this->jsGlobals[Type::ITEM][$i] = $i;
|
||||
$buff[] = '[item='.$i.']';
|
||||
}
|
||||
}
|
||||
else if (!$this->param[1])
|
||||
trigger_error('SmartAI::action - action #124 (SmartAction::ACTION_LOAD_EQIPMENT) is malformed');
|
||||
|
||||
$this->param[10] = Lang::concat($buff);
|
||||
$footer = true;
|
||||
break;
|
||||
case self::ACTION_CALL_TIMED_ACTIONLIST: // 80 -> any target
|
||||
$this->param[10] = match ($this->param[1])
|
||||
{
|
||||
0, 1, 2 => Lang::smartAI('saiUpdate', $this->param[1]),
|
||||
default => Lang::smartAI('saiUpdateUNK', [$this->param[1]])
|
||||
};
|
||||
|
||||
$tal = new SmartAI(SmartAI::SRC_TYPE_ACTIONLIST, $this->param[0], ['baseEntry' => $this->smartAI->getEntry()]);
|
||||
$tal->prepare();
|
||||
|
||||
Util::mergeJsGlobals($this->jsGlobals, $tal->getJSGlobals());
|
||||
|
||||
foreach ($tal->getTabs() as $guid => $tt)
|
||||
$this->smartAI->addTab($guid, $tt);
|
||||
|
||||
break;
|
||||
case self::ACTION_CALL_KILLEDMONSTER: // 33: Note: If target is SMART_TARGET_NONE (0) or SMART_TARGET_SELF (1), the kill is credited to all players eligible for loot from this creature.
|
||||
if ($this->smartAI->getTarget()->type == SmartTarget::TARGET_SELF || $this->smartAI->getTarget()->type == SmartTarget::TARGET_NONE)
|
||||
$this->param[10] = (new SmartTarget($this->id, SmartTarget::TARGET_LOOT_RECIPIENTS, [], [], $this->smartAI))->process();
|
||||
break;
|
||||
case self::ACTION_CROSS_CAST: // 86 -> entity by TargetingBlock(param3, param4, param5, param6) cross cast spell <param1> at any target
|
||||
$this->param[10] = (new SmartTarget($this->id, $this->param[2], [$this->param[3], $this->param[4], $this->param[5]], [], $this->smartAI))->process();
|
||||
break;
|
||||
case self::ACTION_CALL_RANDOM_TIMED_ACTIONLIST: // 87 -> self
|
||||
$talBuff = [];
|
||||
for ($i = 0; $i < 6; $i++)
|
||||
{
|
||||
if (!$this->param[$i])
|
||||
continue;
|
||||
|
||||
$talBuff[] = sprintf(self::TAL_TAB_ANCHOR, $this->param[$i]);
|
||||
|
||||
$tal = new SmartAI(SmartAI::SRC_TYPE_ACTIONLIST, $this->param[$i], ['baseEntry' => $this->smartAI->getEntry()]);
|
||||
$tal->prepare();
|
||||
|
||||
Util::mergeJsGlobals($this->jsGlobals, $tal->getJSGlobals());
|
||||
|
||||
foreach ($tal->getTabs() as $guid => $tt)
|
||||
$this->smartAI->addTab($guid, $tt);
|
||||
}
|
||||
$this->param[10] = Lang::concat($talBuff, false);
|
||||
break;
|
||||
case self::ACTION_CALL_RANDOM_RANGE_TIMED_ACTIONLIST:// 88 -> self
|
||||
$talBuff = [];
|
||||
for ($i = $this->param[0]; $i <= $this->param[1]; $i++)
|
||||
{
|
||||
$talBuff[] = sprintf(self::TAL_TAB_ANCHOR, $i);
|
||||
|
||||
$tal = new SmartAI(SmartAI::SRC_TYPE_ACTIONLIST, $i, ['baseEntry' => $this->smartAI->getEntry()]);
|
||||
$tal->prepare();
|
||||
|
||||
Util::mergeJsGlobals($this->jsGlobals, $tal->getJSGlobals());
|
||||
|
||||
foreach ($tal->getTabs() as $guid => $tt)
|
||||
$this->smartAI->addTab($guid, $tt);
|
||||
}
|
||||
$this->param[10] = Lang::concat($talBuff, false);
|
||||
break;
|
||||
case self::ACTION_SET_HOME_POS: // 101 -> self
|
||||
if ($this->smartAI->getTarget()?->type == Smarttarget::TARGET_SELF)
|
||||
$this->param[10] = 1;
|
||||
// do not break;
|
||||
case self::ACTION_JUMP_TO_POS: // 97 -> self
|
||||
case self::ACTION_MOVE_OFFSET: // 114 -> self
|
||||
array_splice($this->param, 11, replacement: $this->smartAI->getTarget()->getWorldPos());
|
||||
break;
|
||||
case self::ACTION_SUMMON_CREATURE_GROUP: // 107 -> untargeted
|
||||
if ($this->summons === null)
|
||||
$this->summons = DB::World()->selectCol('SELECT `groupId` AS ARRAY_KEY, `entry` AS ARRAY_KEY2, COUNT(*) AS "n" FROM creature_summon_groups WHERE `summonerId` = ?d GROUP BY `groupId`, `entry`', $this->smartAI->getEntry());
|
||||
|
||||
$buff = [];
|
||||
if (!empty($this->summons[$this->param[0]]))
|
||||
{
|
||||
foreach ($this->summons[$this->param[0]] as $id => $n)
|
||||
{
|
||||
$this->jsGlobals[Type::NPC][$id] = $id;
|
||||
$buff[] = $n.'x [npc='.$id.']';
|
||||
}
|
||||
}
|
||||
|
||||
if ($buff)
|
||||
$this->param[10] = Lang::concat($buff);
|
||||
break;
|
||||
case self::ACTION_START_CLOSEST_WAYPOINT: // 113 -> any target
|
||||
$this->param[10] = Lang::concat(array_filter($this->param), false, fn($x) => '#[b]'.$x.'[/b]');
|
||||
break;
|
||||
case self::ACTION_RANDOM_SOUND: // 115 -> self
|
||||
for ($i = 0; $i < 4; $i++)
|
||||
{
|
||||
if ($x = $this->param[$i])
|
||||
{
|
||||
$this->jsGlobals[Type::SOUND][$x] = $x;
|
||||
$this->param[10] .= '[sound='.$x.']';
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->param[5])
|
||||
$footer = true;
|
||||
break;
|
||||
case self::ACTION_GO_SET_GO_STATE: // 118 -> ???
|
||||
$this->param[10] = match ($this->param[0])
|
||||
{
|
||||
0, 1, 2 => Lang::smartAI('GOStates', $this->param[0]),
|
||||
default => Lang::smartAI('GOStateUNK', [$this->param[0]])
|
||||
};
|
||||
break;
|
||||
case self::ACTION_REMOVE_AURAS_BY_TYPE: // 120 -> any target
|
||||
$this->param[10] = Lang::spell('auras', $this->param[0]);
|
||||
break;
|
||||
case self::ACTION_SPAWN_SPAWNGROUP: // 131
|
||||
case self::ACTION_DESPAWN_SPAWNGROUP: // 132
|
||||
$this->param[10] = Util::jsEscape(DB::World()->selectCell('SELECT `GroupName` FROM spawn_group_template WHERE `groupId` = ?d', $this->param[0]));
|
||||
$entities = DB::World()->select('SELECT `spawnType` AS "0", `spawnId` AS "1" FROM spawn_group WHERE `groupId` = ?d', $this->param[0]);
|
||||
|
||||
$n = 5;
|
||||
$buff = [];
|
||||
foreach ($entities as [$spawnType, $guid])
|
||||
{
|
||||
$type = Type::NPC;
|
||||
if ($spawnType == 1)
|
||||
$type == Type::OBJECT;
|
||||
|
||||
if ($_ = $this->resolveGuid($type, $guid))
|
||||
{
|
||||
$this->jsGlobals[$type][$_] = $_;
|
||||
$buff[] = '['.Type::getFileString($type).'='.$_.'][small class=q0] (GUID: '.$guid.')[/small]';
|
||||
}
|
||||
else
|
||||
$buff[] = Lang::smartAI('entityUNK').'[small class=q0] (GUID: '.$guid.')[/small]';
|
||||
|
||||
if (!--$n)
|
||||
break;
|
||||
}
|
||||
|
||||
if (count($entities) > 5)
|
||||
$buff[] = '+'.(count($entities) - 5).'…';
|
||||
|
||||
$this->param[12] = '[ul][li]'.implode('[/li][li]', $buff).'[/li][/ul]';
|
||||
|
||||
// i'd like this stored in $data but numRange can only handle msec
|
||||
if ($time = $this->numRange($this->param[1] * 1000, $this->param[2] * 1000, true))
|
||||
$footer = [$time];
|
||||
break;
|
||||
case self::ACTION_RESPAWN_BY_SPAWNID: // 133
|
||||
$type = Type::NPC;
|
||||
if ($this->param[0] == 1)
|
||||
$type == Type::OBJECT;
|
||||
|
||||
if ($_ = $this->resolveGuid($type, $this->param[1]))
|
||||
{
|
||||
$this->param[10] = '['.Type::getFileString($type).'='.$_.']';
|
||||
$this->jsGlobals[$type][$_] = $_;
|
||||
}
|
||||
else
|
||||
$this->param[10] = Lang::smartAI('entityUNK');
|
||||
break;
|
||||
case self::ACTION_SET_MOVEMENT_SPEED: // 136
|
||||
$this->param[10] = $this->param[1] + $this->param[2] / pow(10, floor(log10($this->param[2] ?: 1.0) + 1)); // i know string concatenation is a thing. don't @ me!
|
||||
break;
|
||||
case self::ACTION_TALK: // 1 -> any target
|
||||
case self::ACTION_SIMPLE_TALK: // 84 -> any target
|
||||
$noSrc = false;
|
||||
if ($npcId = $this->smartAI->getTarget()->getTalkSource($noSrc))
|
||||
{
|
||||
if ($quotes = $this->smartAI->getQuote($npcId, $this->param[0], $npcSrc))
|
||||
foreach ($quotes as ['text' => $text, 'prefix' => $prefix])
|
||||
$this->param[10] .= sprintf($text, $noSrc ? '' : sprintf($prefix, $npcSrc), $npcSrc);
|
||||
}
|
||||
else
|
||||
trigger_error('SmartAI::action - could not determine talk source for action #'.$this->type);
|
||||
break;
|
||||
}
|
||||
|
||||
$this->smartAI->addJsGlobals($this->jsGlobals);
|
||||
|
||||
$body = Lang::smartAI('actions', $this->type, 0, $this->param) ?? Lang::smartAI('actionUNK', [$this->type]);
|
||||
if ($footer)
|
||||
$footer = Lang::smartAI('actions', $this->type, 1, (array)$footer);
|
||||
|
||||
// resolve conditionals
|
||||
$i = 0;
|
||||
while (strstr($body, ')?') && $i++ < 3)
|
||||
$body = preg_replace_callback('/\(([^\)]*?)\)\?([^:]*):(([^;]*);*);/i', fn($m) => $m[1] ? $m[2] : $m[3], $body);
|
||||
|
||||
$i = 0;
|
||||
while (strstr($footer, ')?') && $i++ < 3)
|
||||
$footer = preg_replace_callback('/\(([^\)]*?)\)\?([^:]*):(([^;]*);*);/i', fn($m) => $m[1] ? $m[2] : $m[3], $footer);
|
||||
|
||||
// wrap body in tooltip
|
||||
return [sprintf(self::ACTION_CELL_TPL, $actionTT, $body), $footer];
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
380
includes/components/SmartAI/SmartEvent.class.php
Normal file
380
includes/components/SmartAI/SmartEvent.class.php
Normal file
@@ -0,0 +1,380 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
// TrinityCore - SmartAI
|
||||
class SmartEvent
|
||||
{
|
||||
use SmartHelper;
|
||||
|
||||
public const EVENT_UPDATE_IC = 0; // In combat.
|
||||
public const EVENT_UPDATE_OOC = 1; // Out of combat.
|
||||
public const EVENT_HEALTH_PCT = 2; // Health Percentage
|
||||
public const EVENT_MANA_PCT = 3; // Mana Percentage
|
||||
public const EVENT_AGGRO = 4; // On Creature Aggro
|
||||
public const EVENT_KILL = 5; // On Creature Kill
|
||||
public const EVENT_DEATH = 6; // On Creature Death
|
||||
public const EVENT_EVADE = 7; // On Creature Evade Attack
|
||||
public const EVENT_SPELLHIT = 8; // On Creature/Gameobject Spell Hit
|
||||
public const EVENT_RANGE = 9; // On Target In Range
|
||||
public const EVENT_OOC_LOS = 10; // On Target In Distance Out of Combat
|
||||
public const EVENT_RESPAWN = 11; // On Creature/Gameobject Respawn
|
||||
public const EVENT_TARGET_HEALTH_PCT = 12; // [DEPRECATED] On Target Health Percentage
|
||||
public const EVENT_VICTIM_CASTING = 13; // On Target Casting Spell
|
||||
public const EVENT_FRIENDLY_HEALTH = 14; // [DEPRECATED] On Friendly Health Deficit
|
||||
public const EVENT_FRIENDLY_IS_CC = 15; //
|
||||
public const EVENT_FRIENDLY_MISSING_BUFF = 16; // On Friendly Lost Buff
|
||||
public const EVENT_SUMMONED_UNIT = 17; // On Creature/Gameobject Summoned Unit
|
||||
public const EVENT_TARGET_MANA_PCT = 18; // [DEPRECATED] On Target Mana Percentage
|
||||
public const EVENT_ACCEPTED_QUEST = 19; // On Target Accepted Quest
|
||||
public const EVENT_REWARD_QUEST = 20; // On Target Rewarded Quest
|
||||
public const EVENT_REACHED_HOME = 21; // On Creature Reached Home
|
||||
public const EVENT_RECEIVE_EMOTE = 22; // On Receive Emote.
|
||||
public const EVENT_HAS_AURA = 23; // On Creature Has Aura
|
||||
public const EVENT_TARGET_BUFFED = 24; // On Target Buffed With Spell
|
||||
public const EVENT_RESET = 25; // After Combat, On Respawn or Spawn
|
||||
public const EVENT_IC_LOS = 26; // On Target In Distance In Combat
|
||||
public const EVENT_PASSENGER_BOARDED = 27; //
|
||||
public const EVENT_PASSENGER_REMOVED = 28; //
|
||||
public const EVENT_CHARMED = 29; // On Creature Charmed
|
||||
public const EVENT_CHARMED_TARGET = 30; // [DEPRECATED] On Target Charmed
|
||||
public const EVENT_SPELLHIT_TARGET = 31; // On Target Spell Hit
|
||||
public const EVENT_DAMAGED = 32; // On Creature Damaged
|
||||
public const EVENT_DAMAGED_TARGET = 33; // On Target Damaged
|
||||
public const EVENT_MOVEMENTINFORM = 34; // WAYPOINT_MOTION_TYPE = 2, POINT_MOTION_TYPE = 8
|
||||
public const EVENT_SUMMON_DESPAWNED = 35; // On Summoned Unit Despawned
|
||||
public const EVENT_CORPSE_REMOVED = 36; // On Creature Corpse Removed
|
||||
public const EVENT_AI_INIT = 37; //
|
||||
public const EVENT_DATA_SET = 38; // On Creature/Gameobject Data Set, Can be used with SMART_ACTION_SET_DATA
|
||||
public const EVENT_WAYPOINT_START = 39; // [DEPRECATED] On Creature Waypoint ID Started
|
||||
public const EVENT_WAYPOINT_REACHED = 40; // On Creature Waypoint ID Reached
|
||||
public const EVENT_TRANSPORT_ADDPLAYER = 41; // [RESERVED]
|
||||
public const EVENT_TRANSPORT_ADDCREATURE = 42; // [RESERVED]
|
||||
public const EVENT_TRANSPORT_REMOVE_PLAYER = 43; // [RESERVED]
|
||||
public const EVENT_TRANSPORT_RELOCATE = 44; // [RESERVED]
|
||||
public const EVENT_INSTANCE_PLAYER_ENTER = 45; // [RESERVED]
|
||||
public const EVENT_AREATRIGGER_ONTRIGGER = 46; //
|
||||
public const EVENT_QUEST_ACCEPTED = 47; // [RESERVED] On Target Quest Accepted
|
||||
public const EVENT_QUEST_OBJ_COMPLETION = 48; // [RESERVED] On Target Quest Objective Completed
|
||||
public const EVENT_QUEST_COMPLETION = 49; // [RESERVED] On Target Quest Completed
|
||||
public const EVENT_QUEST_REWARDED = 50; // [RESERVED] On Target Quest Rewarded
|
||||
public const EVENT_QUEST_FAIL = 51; // [RESERVED] On Target Quest Field
|
||||
public const EVENT_TEXT_OVER = 52; // On TEXT_OVER Event Triggered After SMART_ACTION_TALK
|
||||
public const EVENT_RECEIVE_HEAL = 53; // On Creature Received Healing
|
||||
public const EVENT_JUST_SUMMONED = 54; // On Creature Just spawned
|
||||
public const EVENT_WAYPOINT_PAUSED = 55; // On Creature Paused at Waypoint ID
|
||||
public const EVENT_WAYPOINT_RESUMED = 56; // On Creature Resumed after Waypoint ID
|
||||
public const EVENT_WAYPOINT_STOPPED = 57; // On Creature Stopped On Waypoint ID
|
||||
public const EVENT_WAYPOINT_ENDED = 58; // On Creature Waypoint Path Ended
|
||||
public const EVENT_TIMED_EVENT_TRIGGERED = 59; //
|
||||
public const EVENT_UPDATE = 60; //
|
||||
public const EVENT_LINK = 61; // Used to link together multiple events as a chain of events.
|
||||
public const EVENT_GOSSIP_SELECT = 62; // On gossip clicked (gossip_menu_option335).
|
||||
public const EVENT_JUST_CREATED = 63; //
|
||||
public const EVENT_GOSSIP_HELLO = 64; // On Right-Click Creature/Gameobject that have gossip enabled.
|
||||
public const EVENT_FOLLOW_COMPLETED = 65; //
|
||||
public const EVENT_EVENT_PHASE_CHANGE = 66; // [DEPRECATED] On event phase mask set
|
||||
public const EVENT_IS_BEHIND_TARGET = 67; // [DEPRECATED] On Creature is behind target.
|
||||
public const EVENT_GAME_EVENT_START = 68; // On game_event started.
|
||||
public const EVENT_GAME_EVENT_END = 69; // On game_event ended.
|
||||
public const EVENT_GO_LOOT_STATE_CHANGED = 70; //
|
||||
public const EVENT_GO_EVENT_INFORM = 71; //
|
||||
public const EVENT_ACTION_DONE = 72; //
|
||||
public const EVENT_ON_SPELLCLICK = 73; //
|
||||
public const EVENT_FRIENDLY_HEALTH_PCT = 74; //
|
||||
public const EVENT_DISTANCE_CREATURE = 75; // On creature guid OR any instance of creature entry is within distance.
|
||||
public const EVENT_DISTANCE_GAMEOBJECT = 76; // On gameobject guid OR any instance of gameobject entry is within distance.
|
||||
public const EVENT_COUNTER_SET = 77; // If the value of specified counterID is equal to a specified value
|
||||
public const EVENT_SCENE_START = 78; // [RESERVED] don't use on 3.3.5a
|
||||
public const EVENT_SCENE_TRIGGER = 79; // [RESERVED] don't use on 3.3.5a
|
||||
public const EVENT_SCENE_CANCEL = 80; // [RESERVED] don't use on 3.3.5a
|
||||
public const EVENT_SCENE_COMPLETE = 81; // [RESERVED] don't use on 3.3.5a
|
||||
public const EVENT_SUMMONED_UNIT_DIES = 82; //
|
||||
public const EVENT_ON_SPELL_CAST = 83; // On Spell::cast
|
||||
public const EVENT_ON_SPELL_FAILED = 84; // On Unit::InterruptSpell
|
||||
public const EVENT_ON_SPELL_START = 85; // On Spell::prapare
|
||||
public const EVENT_ON_DESPAWN = 86; // On before creature removed
|
||||
|
||||
public const FLAG_NO_REPEAT = 0x0001;
|
||||
public const FLAG_DIFFICULTY_0 = 0x0002;
|
||||
public const FLAG_DIFFICULTY_1 = 0x0004;
|
||||
public const FLAG_DIFFICULTY_2 = 0x0008;
|
||||
public const FLAG_DIFFICULTY_3 = 0x0010;
|
||||
public const FLAG_DEBUG_ONLY = 0x0080;
|
||||
public const FLAG_NO_RESET = 0x0100;
|
||||
public const FLAG_WHILE_CHARMED = 0x0200;
|
||||
public const FLAG_ALL_DIFFICULTIES = self::FLAG_DIFFICULTY_0 | self::FLAG_DIFFICULTY_1 | self::FLAG_DIFFICULTY_2 | self::FLAG_DIFFICULTY_3;
|
||||
|
||||
private const EVENT_CELL_TPL = '[tooltip name=e-#rowIdx#]%1$s[/tooltip][span tooltip=e-#rowIdx#]%2$s[/span]';
|
||||
|
||||
private array $data = array( // param 1-5 - int > 0: type, array: [fn, newIdx, extraParam]; error class: int
|
||||
self::EVENT_UPDATE_IC => [['numRange', 10, true], null, ['numRange', -1, true], null, null, 0], // InitialMin, InitialMax, RepeatMin, RepeatMax
|
||||
self::EVENT_UPDATE_OOC => [['numRange', 10, true], null, ['numRange', -1, true], null, null, 0], // InitialMin, InitialMax, RepeatMin, RepeatMax
|
||||
self::EVENT_HEALTH_PCT => [['numRange', 10, false], null, ['numRange', -1, true], null, null, 0], // HPMin%, HPMax%, RepeatMin, RepeatMax
|
||||
self::EVENT_MANA_PCT => [['numRange', 10, false], null, ['numRange', -1, true], null, null, 0], // ManaMin%, ManaMax%, RepeatMin, RepeatMax
|
||||
self::EVENT_AGGRO => [null, null, null, null, null, 0], // NONE
|
||||
self::EVENT_KILL => [['numRange', -1, true], null, null, Type::NPC, null, 0], // CooldownMin0, CooldownMax1, playerOnly2, else creature entry3
|
||||
self::EVENT_DEATH => [null, null, null, null, null, 0], // NONE
|
||||
self::EVENT_EVADE => [null, null, null, null, null, 0], // NONE
|
||||
self::EVENT_SPELLHIT => [Type::SPELL, ['magicSchool', 10, false], ['numRange', -1, true], null, null, 0], // SpellID, School, CooldownMin, CooldownMax
|
||||
self::EVENT_RANGE => [['numRange', 10, false], null, ['numRange', -1, true], null, null, 0], // MinDist, MaxDist, RepeatMin, RepeatMax
|
||||
self::EVENT_OOC_LOS => [['hostilityMode', 10, false], null, ['numRange', -1, true], null, null, 0], // hostilityModes, MaxRange, CooldownMin, CooldownMax
|
||||
self::EVENT_RESPAWN => [null, null, Type::ZONE, null, null, 0], // type, MapId, ZoneId
|
||||
self::EVENT_TARGET_HEALTH_PCT => [['numRange', 10, false], null, ['numRange', -1, true], null, null, 1], // UNUSED, DO NOT REUSE
|
||||
self::EVENT_VICTIM_CASTING => [['numRange', -1, true], null, Type::SPELL, null, null, 0], // RepeatMin, RepeatMax, spellid
|
||||
self::EVENT_FRIENDLY_HEALTH => [null, null, ['numRange', -1, true], null, null, 1], // UNUSED, DO NOT REUSE
|
||||
self::EVENT_FRIENDLY_IS_CC => [null, ['numRange', -1, true], null, null, null, 0], // Radius, RepeatMin, RepeatMax
|
||||
self::EVENT_FRIENDLY_MISSING_BUFF => [Type::SPELL, null, ['numRange', -1, true], null, null, 0], // SpellId, Radius, RepeatMin, RepeatMax
|
||||
self::EVENT_SUMMONED_UNIT => [Type::NPC, ['numRange', -1, true], null, null, null, 0], // CreatureId(0 all), CooldownMin, CooldownMax
|
||||
self::EVENT_TARGET_MANA_PCT => [['numRange', 10, false], null, ['numRange', -1, true], null, null, 1], // UNUSED, DO NOT REUSE
|
||||
self::EVENT_ACCEPTED_QUEST => [Type::QUEST, ['numRange', -1, true], null, null, null, 0], // QuestID (0 = any), CooldownMin, CooldownMax
|
||||
self::EVENT_REWARD_QUEST => [Type::QUEST, ['numRange', -1, true], null, null, null, 0], // QuestID (0 = any), CooldownMin, CooldownMax
|
||||
self::EVENT_REACHED_HOME => [null, null, null, null, null, 0], // NONE
|
||||
self::EVENT_RECEIVE_EMOTE => [Type::EMOTE, ['numRange', -1, true], null, null, null, 0], // EmoteId, CooldownMin, CooldownMax, condition, val1, val2, val3
|
||||
self::EVENT_HAS_AURA => [Type::SPELL, null, ['numRange', -1, true], null, null, 0], // Param1 = SpellID, Param2 = Stack amount, Param3/4 RepeatMin, RepeatMax
|
||||
self::EVENT_TARGET_BUFFED => [Type::SPELL, null, ['numRange', -1, true], null, null, 0], // Param1 = SpellID, Param2 = Stack amount, Param3/4 RepeatMin, RepeatMax
|
||||
self::EVENT_RESET => [null, null, null, null, null, 0], // Called after combat, when the creature respawn and spawn.
|
||||
self::EVENT_IC_LOS => [['hostilityMode', 10, false], null, ['numRange', -1, true], null, null, 0], // hostilityModes, MaxRnage, CooldownMin, CooldownMax
|
||||
self::EVENT_PASSENGER_BOARDED => [['numRange', -1, true], null, null, null, null, 0], // CooldownMin, CooldownMax
|
||||
self::EVENT_PASSENGER_REMOVED => [['numRange', -1, true], null, null, null, null, 0], // CooldownMin, CooldownMax
|
||||
self::EVENT_CHARMED => [null, null, null, null, null, 0], // onRemove (0 - on apply, 1 - on remove)
|
||||
self::EVENT_CHARMED_TARGET => [null, null, null, null, null, 1], // UNUSED, DO NOT REUSE
|
||||
self::EVENT_SPELLHIT_TARGET => [Type::SPELL, ['magicSchool', 10, false], ['numRange', -1, true], null, null, 0], // SpellID, School, CooldownMin, CooldownMax
|
||||
self::EVENT_DAMAGED => [['numRange', 10, false], null, ['numRange', -1, true], null, null, 0], // MinDmg, MaxDmg, CooldownMin, CooldownMax
|
||||
self::EVENT_DAMAGED_TARGET => [['numRange', 10, false], null, ['numRange', -1, true], null, null, 0], // MinDmg, MaxDmg, CooldownMin, CooldownMax
|
||||
self::EVENT_MOVEMENTINFORM => [['motionType', 10, false], null, null, null, null, 0], // MovementType(any), PointID
|
||||
self::EVENT_SUMMON_DESPAWNED => [Type::NPC, ['numRange', -1, true], null, null, null, 0], // Entry, CooldownMin, CooldownMax
|
||||
self::EVENT_CORPSE_REMOVED => [null, null, null, null, null, 0], // NONE
|
||||
self::EVENT_AI_INIT => [null, null, null, null, null, 0], // NONE
|
||||
self::EVENT_DATA_SET => [null, null, ['numRange', -1, true], null, null, 0], // Id, Value, CooldownMin, CooldownMax
|
||||
self::EVENT_WAYPOINT_START => [null, null, null, null, null, 1], // UNUSED, DO NOT REUSE
|
||||
self::EVENT_WAYPOINT_REACHED => [null, null, null, null, null, 0], // PointId(0any), pathID(0any)
|
||||
self::EVENT_TRANSPORT_ADDPLAYER => [null, null, null, null, null, 2], // NONE
|
||||
self::EVENT_TRANSPORT_ADDCREATURE => [null, null, null, null, null, 2], // Entry (0 any)
|
||||
self::EVENT_TRANSPORT_REMOVE_PLAYER => [null, null, null, null, null, 2], // NONE
|
||||
self::EVENT_TRANSPORT_RELOCATE => [null, null, null, null, null, 2], // PointId
|
||||
self::EVENT_INSTANCE_PLAYER_ENTER => [null, null, null, null, null, 2], // Team (0 any), CooldownMin, CooldownMax
|
||||
self::EVENT_AREATRIGGER_ONTRIGGER => [Type::AREATRIGGER, null, null, null, null, 0], // TriggerId(0 any)
|
||||
self::EVENT_QUEST_ACCEPTED => [null, null, null, null, null, 2], // none
|
||||
self::EVENT_QUEST_OBJ_COMPLETION => [null, null, null, null, null, 2], // none
|
||||
self::EVENT_QUEST_COMPLETION => [null, null, null, null, null, 2], // none
|
||||
self::EVENT_QUEST_REWARDED => [null, null, null, null, null, 2], // none
|
||||
self::EVENT_QUEST_FAIL => [null, null, null, null, null, 2], // none
|
||||
self::EVENT_TEXT_OVER => [null, Type::NPC, null, null, null, 0], // GroupId from creature_text, creature entry who talks (0 any)
|
||||
self::EVENT_RECEIVE_HEAL => [['numRange', 10, false], null, ['numRange', -1, true], null, null, 0], // MinHeal, MaxHeal, CooldownMin, CooldownMax
|
||||
self::EVENT_JUST_SUMMONED => [null, null, null, null, null, 0], // none
|
||||
self::EVENT_WAYPOINT_PAUSED => [null, null, null, null, null, 0], // PointId(0any), pathID(0any)
|
||||
self::EVENT_WAYPOINT_RESUMED => [null, null, null, null, null, 0], // PointId(0any), pathID(0any)
|
||||
self::EVENT_WAYPOINT_STOPPED => [null, null, null, null, null, 0], // PointId(0any), pathID(0any)
|
||||
self::EVENT_WAYPOINT_ENDED => [null, null, null, null, null, 0], // PointId(0any), pathID(0any)
|
||||
self::EVENT_TIMED_EVENT_TRIGGERED => [null, null, null, null, null, 0], // id
|
||||
self::EVENT_UPDATE => [['numRange', 10, true], null, ['numRange', -1, true], null, null, 0], // InitialMin, InitialMax, RepeatMin, RepeatMax
|
||||
self::EVENT_LINK => [null, null, null, null, null, 0], // INTERNAL USAGE, no params, used to link together multiple events, does not use any extra resources to iterate event lists needlessly
|
||||
self::EVENT_GOSSIP_SELECT => [null, null, null, null, null, 0], // menuID, actionID
|
||||
self::EVENT_JUST_CREATED => [null, null, null, null, null, 0], // none
|
||||
self::EVENT_GOSSIP_HELLO => [null, null, null, null, null, 0], // noReportUse (for GOs)
|
||||
self::EVENT_FOLLOW_COMPLETED => [null, null, null, null, null, 0], // none
|
||||
self::EVENT_EVENT_PHASE_CHANGE => [null, null, null, null, null, 1], // UNUSED, DO NOT REUSE
|
||||
self::EVENT_IS_BEHIND_TARGET => [['numRange', -1, true], null, null, null, null, 1], // UNUSED, DO NOT REUSE
|
||||
self::EVENT_GAME_EVENT_START => [Type::WORLDEVENT, null, null, null, null, 0], // game_event.Entry
|
||||
self::EVENT_GAME_EVENT_END => [Type::WORLDEVENT, null, null, null, null, 0], // game_event.Entry
|
||||
self::EVENT_GO_LOOT_STATE_CHANGED => [['lootState', 10, false], null, null, null, null, 0], // go LootState
|
||||
self::EVENT_GO_EVENT_INFORM => [null, null, null, null, null, 0], // eventId
|
||||
self::EVENT_ACTION_DONE => [null, null, null, null, null, 0], // eventId (SharedDefines.EventId)
|
||||
self::EVENT_ON_SPELLCLICK => [null, null, null, null, null, 0], // clicker (unit)
|
||||
self::EVENT_FRIENDLY_HEALTH_PCT => [['numRange', 10, false], null, ['numRange', -1, true], null, null, 0], // minHpPct, maxHpPct, repeatMin, repeatMax
|
||||
self::EVENT_DISTANCE_CREATURE => [null, Type::NPC, null, ['numRange', -1, true], null, 0], // guid, entry, distance, repeat
|
||||
self::EVENT_DISTANCE_GAMEOBJECT => [null, Type::OBJECT, null, ['numRange', -1, true], null, 0], // guid, entry, distance, repeat
|
||||
self::EVENT_COUNTER_SET => [null, null, ['numRange', -1, true], null, null, 0], // id, value, cooldownMin, cooldownMax
|
||||
self::EVENT_SCENE_START => [null, null, null, null, null, 2], // don't use on 3.3.5a
|
||||
self::EVENT_SCENE_TRIGGER => [null, null, null, null, null, 2], // don't use on 3.3.5a
|
||||
self::EVENT_SCENE_CANCEL => [null, null, null, null, null, 2], // don't use on 3.3.5a
|
||||
self::EVENT_SCENE_COMPLETE => [null, null, null, null, null, 2], // don't use on 3.3.5a
|
||||
self::EVENT_SUMMONED_UNIT_DIES => [Type::NPC, ['numRange', -1, true], null, null, null, 0], // CreatureId(0 all), CooldownMin, CooldownMax
|
||||
self::EVENT_ON_SPELL_CAST => [Type::SPELL, ['numRange', -1, true], null, null, null, 0], // SpellID, CooldownMin, CooldownMax
|
||||
self::EVENT_ON_SPELL_FAILED => [Type::SPELL, ['numRange', -1, true], null, null, null, 0], // SpellID, CooldownMin, CooldownMax
|
||||
self::EVENT_ON_SPELL_START => [Type::SPELL, ['numRange', -1, true], null, null, null, 0], // SpellID, CooldownMin, CooldownMax
|
||||
self::EVENT_ON_DESPAWN => [null, null, null, null, null, 0] // NONE
|
||||
);
|
||||
|
||||
private array $jsGlobals = [];
|
||||
|
||||
public function __construct(
|
||||
private int $id,
|
||||
public readonly int $type,
|
||||
public readonly int $phaseMask,
|
||||
public readonly int $chance,
|
||||
private int $flags,
|
||||
private array $param,
|
||||
private SmartAI &$smartAI)
|
||||
{
|
||||
// additional parameters
|
||||
Util::checkNumeric($this->param, NUM_CAST_INT);
|
||||
$this->param = array_pad($this->param, 15, '');
|
||||
}
|
||||
|
||||
public function process() : array
|
||||
{
|
||||
$body =
|
||||
$footer = '';
|
||||
|
||||
$phases = Util::mask2bits($this->phaseMask, 1) ?: [0];
|
||||
$eventTT = Lang::smartAI('eventTT', array_merge([$this->type, $phases, $this->chance, $this->flags], $this->param));
|
||||
|
||||
for ($i = 0; $i < 5; $i++)
|
||||
{
|
||||
$eParams = $this->data[$this->type];
|
||||
|
||||
if (is_array($eParams[$i]))
|
||||
{
|
||||
[$fn, $idx, $extraParam] = $eParams[$i];
|
||||
|
||||
if ($idx < 0)
|
||||
$footer = $this->{$fn}($this->param[$i], $this->param[$i + 1], $extraParam);
|
||||
else
|
||||
$this->param[$idx] = $this->{$fn}($this->param[$i], $this->param[$i + 1], $extraParam);
|
||||
}
|
||||
else if (is_int($eParams[$i]) && $this->param[$i])
|
||||
$this->jsGlobals[$eParams[$i]][$this->param[$i]] = $this->param[$i];
|
||||
}
|
||||
|
||||
// non-generic cases
|
||||
switch ($this->type)
|
||||
{
|
||||
case self::EVENT_UPDATE_IC: // 0 - In combat.
|
||||
case self::EVENT_UPDATE_OOC: // 1 - Out of combat.
|
||||
if ($this->smartAI->srcType == SmartAI::SRC_TYPE_ACTIONLIST)
|
||||
$this->param[11] = 1;
|
||||
// do not break;
|
||||
case self::EVENT_GOSSIP_HELLO: // 64 - On Right-Click Creature/Gameobject that have gossip enabled.
|
||||
if ($this->smartAI->srcType == SmartAI::SRC_TYPE_OBJECT)
|
||||
$footer = array(
|
||||
$this->param[0] == 1,
|
||||
$this->param[0] == 2,
|
||||
);
|
||||
break;
|
||||
case self::EVENT_RESPAWN: // 11 - On Creature/Gameobject Respawn in Zone/Map
|
||||
if ($this->param[0] == 1) // per map
|
||||
{
|
||||
switch ($this->param[1])
|
||||
{
|
||||
case 0: $this->param[10] = Lang::maps('EasternKingdoms'); break;
|
||||
case 1: $this->param[10] = Lang::maps('Kalimdor'); break;
|
||||
case 530: $this->param[10] = Lang::maps('Outland'); break;
|
||||
case 571: $this->param[10] = Lang::maps('Northrend'); break;
|
||||
default:
|
||||
if ($aId = DB::Aowow()->selectCell('SELECT `id` FROM ?_zones WHERE `mapId` = ?d', $this->param[1]))
|
||||
{
|
||||
$this->param[11] = $aId;
|
||||
$this->jsGlobals[Type::ZONE][$aId] = $aId;
|
||||
}
|
||||
else
|
||||
$this->param[11] = '[span class=q10]Unknown Map[/span] #'.$this->param[1];
|
||||
};
|
||||
}
|
||||
else if ($this->param[0] == 2) // per zone
|
||||
$this->param[11] = $this->param[2];
|
||||
|
||||
break;
|
||||
case self::EVENT_LINK: // 61 - Used to link together multiple events as a chain of events.
|
||||
if ($links = DB::World()->selectCol('SELECT `id` FROM smart_scripts WHERE `link` = ?d AND `entryorguid` = ?d AND `source_type` = ?d', $this->id, $this->smartAI->entry, $this->smartAI->srcType))
|
||||
$this->param[10] = LANG::concat($links, false, fn($x) => "#[b]".$x."[/b]");
|
||||
break;
|
||||
case self::EVENT_GOSSIP_SELECT: // 62 - On gossip clicked (gossip_menu_option335).
|
||||
$gmo = DB::World()->selectRow(
|
||||
'SELECT gmo.`OptionText` AS "text_loc0" {, gmol.`OptionText` AS text_loc?d }
|
||||
FROM gossip_menu_option gmo
|
||||
LEFT JOIN gossip_menu_option_locale gmol ON gmo.`MenuID` = gmol.`MenuID` AND gmo.`OptionID` = gmol.`OptionID` AND gmol.`Locale` = ?d
|
||||
WHERE gmo.`MenuId` = ?d AND gmo.`OptionID` = ?d',
|
||||
Lang::getLocale() != Locale::EN ? Lang::getLocale()->value : DBSIMPLE_SKIP,
|
||||
Lang::getLocale()->json(),
|
||||
$this->param[0], $this->param[1]
|
||||
);
|
||||
|
||||
if ($gmo)
|
||||
$this->param[10] = Util::jsEscape(Util::localizedString($gmo, 'text'));
|
||||
else
|
||||
trigger_error('SmartAI::event - could not find gossip menu option for event #'.$this->type);
|
||||
break;
|
||||
case self::EVENT_DISTANCE_CREATURE: // 75 - On creature guid OR any instance of creature entry is within distance.
|
||||
if ($this->param[0])
|
||||
if ($_ = $this->resolveGuid(Type::NPC, $this->param[0]))
|
||||
{
|
||||
$this->jsGlobals[Type::NPC][$this->param[0]] = $this->param[0];
|
||||
$this->param[10] = $_;
|
||||
}
|
||||
// do not break;
|
||||
case self::EVENT_DISTANCE_GAMEOBJECT: // 76 - On gameobject guid OR any instance of gameobject entry is within distance.
|
||||
if ($this->param[0] && !$this->param[10])
|
||||
{
|
||||
if ($_ = $this->resolveGuid(Type::OBJECT, $this->param[0]))
|
||||
{
|
||||
$this->jsGlobals[Type::OBJECT][$this->param[0]] = $this->param[0];
|
||||
$this->param[10] = $_;
|
||||
}
|
||||
}
|
||||
else if ($this->param[1])
|
||||
$this->param[10] = $this->param[1];
|
||||
else if (!$this->param[10])
|
||||
trigger_error('SmartAI::event - entity for event #'.$this->type.' not defined');
|
||||
break;
|
||||
case self::EVENT_EVENT_PHASE_CHANGE: // 66 - On event phase mask set
|
||||
$this->param[10] = Lang::concat(Util::mask2bits($this->param[0]), false);
|
||||
break;
|
||||
}
|
||||
|
||||
$this->smartAI->addJsGlobals($this->jsGlobals);
|
||||
|
||||
$body = Lang::smartAI('events', $this->type, 0, $this->param) ?? Lang::smartAI('eventUNK', [$this->type]);
|
||||
if ($footer)
|
||||
$footer = Lang::smartAI('events', $this->type, 1, (array)$footer);
|
||||
|
||||
// resolve conditionals
|
||||
$i = 0;
|
||||
while (strstr($body, ')?') && $i++ < 3)
|
||||
$body = preg_replace_callback('/\(([^\)]*?)\)\?([^:]*):(([^;]*);*);/i', fn($m) => $m[1] ? $m[2] : $m[3], $body);
|
||||
|
||||
$i = 0;
|
||||
while (strstr($footer, ')?') && $i++ < 3)
|
||||
$footer = preg_replace_callback('/\(([^\)]*?)\)\?([^:]*):(([^;]*);*);/i', fn($m) => $m[1] ? $m[2] : $m[3], $footer);
|
||||
|
||||
if ($_ = $this->formatFlags())
|
||||
$footer = $_ . ($footer ? '; '.$footer : '');
|
||||
|
||||
if (User::isInGroup(U_GROUP_EMPLOYEE))
|
||||
{
|
||||
if ($eParams[5] == 1)
|
||||
$footer = '[span class=rep2]DEPRECATED[/span] ' . $footer;
|
||||
else if ($eParams[5] == 2)
|
||||
$footer = '[span class=rep0]RESERVED[/span] ' . $footer;
|
||||
}
|
||||
|
||||
// wrap body in tooltip
|
||||
return [sprintf(self::EVENT_CELL_TPL, $eventTT, $body), $footer];
|
||||
}
|
||||
|
||||
public function hasPhases() : bool
|
||||
{
|
||||
return $this->phaseMask == 0;
|
||||
}
|
||||
|
||||
private function formatFlags() : string
|
||||
{
|
||||
$flags = $this->flags;
|
||||
|
||||
if (($flags & self::FLAG_ALL_DIFFICULTIES) == self::FLAG_ALL_DIFFICULTIES)
|
||||
$flags &= ~self::FLAG_ALL_DIFFICULTIES;
|
||||
|
||||
$ef = [];
|
||||
for ($i = 1; $i <= self::FLAG_WHILE_CHARMED; $i <<= 1)
|
||||
if ($flags & $i)
|
||||
if ($x = Lang::smartAI('eventFlags', $i))
|
||||
$ef[] = $x;
|
||||
|
||||
return Lang::concat($ef);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
183
includes/components/SmartAI/SmartTarget.class.php
Normal file
183
includes/components/SmartAI/SmartTarget.class.php
Normal file
@@ -0,0 +1,183 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
// TrinityCore - SmartAI
|
||||
class SmartTarget
|
||||
{
|
||||
use SmartHelper;
|
||||
|
||||
public const TARGET_NONE = 0; // None.
|
||||
public const TARGET_SELF = 1; // Self cast.
|
||||
public const TARGET_VICTIM = 2; // Our current target. (ie: highest aggro)
|
||||
public const TARGET_HOSTILE_SECOND_AGGRO = 3; // Second highest aggro.
|
||||
public const TARGET_HOSTILE_LAST_AGGRO = 4; // Dead last on aggro.
|
||||
public const TARGET_HOSTILE_RANDOM = 5; // Just any random target on our threat list.
|
||||
public const TARGET_HOSTILE_RANDOM_NOT_TOP = 6; // Any random target except top threat.
|
||||
public const TARGET_ACTION_INVOKER = 7; // Unit who caused this Event to occur.
|
||||
public const TARGET_POSITION = 8; // Use xyz from event params.
|
||||
public const TARGET_CREATURE_RANGE = 9; // (Random?) creature with specified ID within specified range.
|
||||
public const TARGET_CREATURE_GUID = 10; // Creature with specified GUID.
|
||||
public const TARGET_CREATURE_DISTANCE = 11; // Creature with specified ID within distance. (Different from #9?)
|
||||
public const TARGET_STORED = 12; // Uses pre-stored target(list)
|
||||
public const TARGET_GAMEOBJECT_RANGE = 13; // (Random?) object with specified ID within specified range.
|
||||
public const TARGET_GAMEOBJECT_GUID = 14; // Object with specified GUID.
|
||||
public const TARGET_GAMEOBJECT_DISTANCE = 15; // Object with specified ID within distance. (Different from #13?)
|
||||
public const TARGET_INVOKER_PARTY = 16; // Invoker's party members
|
||||
public const TARGET_PLAYER_RANGE = 17; // (Random?) player within specified range.
|
||||
public const TARGET_PLAYER_DISTANCE = 18; // (Random?) player within specified distance. (Different from #17?)
|
||||
public const TARGET_CLOSEST_CREATURE = 19; // Closest creature with specified ID within specified range.
|
||||
public const TARGET_CLOSEST_GAMEOBJECT = 20; // Closest object with specified ID within specified range.
|
||||
public const TARGET_CLOSEST_PLAYER = 21; // Closest player within specified range.
|
||||
public const TARGET_ACTION_INVOKER_VEHICLE = 22; // Unit's vehicle who caused this Event to occur
|
||||
public const TARGET_OWNER_OR_SUMMONER = 23; // Unit's owner or summoner
|
||||
public const TARGET_THREAT_LIST = 24; // All units on creature's threat list
|
||||
public const TARGET_CLOSEST_ENEMY = 25; // Any attackable target (creature or player) within maxDist
|
||||
public const TARGET_CLOSEST_FRIENDLY = 26; // Any friendly unit (creature, player or pet) within maxDist
|
||||
public const TARGET_LOOT_RECIPIENTS = 27; // All tagging players
|
||||
public const TARGET_FARTHEST = 28; // Farthest unit on the threat list
|
||||
public const TARGET_VEHICLE_PASSENGER = 29; // Vehicle can target unit in given seat
|
||||
public const TARGET_CLOSEST_UNSPAWNED_GO = 30; // entry(0any), maxDist
|
||||
|
||||
private const TARGET_TPL = '[tooltip name=t-#rowIdx#]%1$s[/tooltip][span class=tip tooltip=t-#rowIdx#]%2$s[/span]';
|
||||
|
||||
private array $targets = array(
|
||||
self::TARGET_NONE => [null, null, null, null], // NONE
|
||||
self::TARGET_SELF => [null, null, null, null], // Self cast
|
||||
self::TARGET_VICTIM => [null, null, null, null], // Our current target (ie: highest aggro)
|
||||
self::TARGET_HOSTILE_SECOND_AGGRO => [null, null, null, null], // Second highest aggro, maxdist, playerOnly, powerType + 1
|
||||
self::TARGET_HOSTILE_LAST_AGGRO => [null, null, null, null], // Dead last on aggro, maxdist, playerOnly, powerType + 1
|
||||
self::TARGET_HOSTILE_RANDOM => [null, null, null, null], // Just any random target on our threat list, maxdist, playerOnly, powerType + 1
|
||||
self::TARGET_HOSTILE_RANDOM_NOT_TOP => [null, null, null, null], // Any random target except top threat, maxdist, playerOnly, powerType + 1
|
||||
self::TARGET_ACTION_INVOKER => [null, null, null, null], // Unit who caused this Event to occur
|
||||
self::TARGET_POSITION => [null, null, null, null], // use xyz from event params
|
||||
self::TARGET_CREATURE_RANGE => [Type::NPC, ['numRange', 10, false], null, null], // CreatureEntry(0any), minDist, maxDist
|
||||
self::TARGET_CREATURE_GUID => [null, Type::NPC, null, null], // guid, entry
|
||||
self::TARGET_CREATURE_DISTANCE => [Type::NPC, null, null, null], // CreatureEntry(0any), maxDist
|
||||
self::TARGET_STORED => [null, null, null, null], // id, uses pre-stored target(list)
|
||||
self::TARGET_GAMEOBJECT_RANGE => [Type::OBJECT, ['numRange', 10, false], null, null], // entry(0any), min, max
|
||||
self::TARGET_GAMEOBJECT_GUID => [null, Type::OBJECT, null, null], // guid, entry
|
||||
self::TARGET_GAMEOBJECT_DISTANCE => [Type::OBJECT, null, null, null], // entry(0any), maxDist
|
||||
self::TARGET_INVOKER_PARTY => [null, null, null, null], // invoker's party members
|
||||
self::TARGET_PLAYER_RANGE => [['numRange', 10, false], null, null, null], // min, max
|
||||
self::TARGET_PLAYER_DISTANCE => [null, null, null, null], // maxDist
|
||||
self::TARGET_CLOSEST_CREATURE => [Type::NPC, null, null, null], // CreatureEntry(0any), maxDist, dead?
|
||||
self::TARGET_CLOSEST_GAMEOBJECT => [Type::OBJECT, null, null, null], // entry(0any), maxDist
|
||||
self::TARGET_CLOSEST_PLAYER => [null, null, null, null], // maxDist
|
||||
self::TARGET_ACTION_INVOKER_VEHICLE => [null, null, null, null], // Unit's vehicle who caused this Event to occur
|
||||
self::TARGET_OWNER_OR_SUMMONER => [null, null, null, null], // Unit's owner or summoner, Use Owner/Charmer of this unit
|
||||
self::TARGET_THREAT_LIST => [null, null, null, null], // All units on creature's threat list, maxdist
|
||||
self::TARGET_CLOSEST_ENEMY => [null, null, null, null], // maxDist, playerOnly
|
||||
self::TARGET_CLOSEST_FRIENDLY => [null, null, null, null], // maxDist, playerOnly
|
||||
self::TARGET_LOOT_RECIPIENTS => [null, null, null, null], // all players that have tagged this creature (for kill credit)
|
||||
self::TARGET_FARTHEST => [null, null, null, null], // maxDist, playerOnly, isInLos
|
||||
self::TARGET_VEHICLE_PASSENGER => [null, null, null, null], // seatMask (0 - all seats)
|
||||
self::TARGET_CLOSEST_UNSPAWNED_GO => [Type::OBJECT, null, null, null] // entry(0any), maxDist
|
||||
);
|
||||
|
||||
private array $jsGlobals = [];
|
||||
|
||||
public function __construct(
|
||||
private int $id,
|
||||
public readonly int $type,
|
||||
private array $param,
|
||||
private array $worldPos,
|
||||
private SmartAI &$smartAI)
|
||||
{
|
||||
// additional parameters
|
||||
Util::checkNumeric($this->param, NUM_CAST_INT);
|
||||
Util::checkNumeric($this->worldPos, NUM_CAST_FLOAT);
|
||||
$this->param = array_pad($this->param, 15, '');
|
||||
$this->worldPos = array_pad($this->worldPos, 4, 0.0);
|
||||
}
|
||||
|
||||
public function process() : string
|
||||
{
|
||||
$target = '';
|
||||
|
||||
$targetTT = Lang::smartAI('targetTT', array_merge([$this->type], $this->param, $this->worldPos));
|
||||
|
||||
for ($i = 0; $i < 4; $i++)
|
||||
{
|
||||
$tParams = $this->targets[$this->type];
|
||||
|
||||
if (is_array($tParams[$i]))
|
||||
{
|
||||
[$fn, $idx, $extraParam] = $tParams[$i];
|
||||
|
||||
$this->param[$idx] = $this->{$fn}($this->param[$i], $this->param[$i + 1], $extraParam);
|
||||
}
|
||||
else if (is_int($tParams[$i]) && $this->param[$i])
|
||||
$this->jsGlobals[$tParams[$i]][$this->param[$i]] = $this->param[$i];
|
||||
}
|
||||
|
||||
// non-generic cases
|
||||
switch ($this->type)
|
||||
{
|
||||
case self::TARGET_HOSTILE_SECOND_AGGRO:
|
||||
case self::TARGET_HOSTILE_LAST_AGGRO:
|
||||
case self::TARGET_HOSTILE_RANDOM:
|
||||
case self::TARGET_HOSTILE_RANDOM_NOT_TOP:
|
||||
if ($this->param[2])
|
||||
$this->param[10] = Lang::spell('powerTypes', $this->param[2] - 1);
|
||||
break;
|
||||
case self::TARGET_VEHICLE_PASSENGER:
|
||||
if ($this->param[0])
|
||||
$this->param[10] = Lang::concat(Util::mask2bits($this->param[0]));
|
||||
break;
|
||||
case self::TARGET_CREATURE_GUID:
|
||||
if ($_ = $this->resolveGuid(Type::NPC, $this->param[0]))
|
||||
{
|
||||
$this->jsGlobals[Type::NPC][$_] = $_;
|
||||
$this->param[10] = $_;
|
||||
}
|
||||
break;
|
||||
case self::TARGET_GAMEOBJECT_GUID:
|
||||
if ($_ = $this->resolveGuid(Type::OBJECT, $this->param[0]))
|
||||
{
|
||||
$this->jsGlobals[Type::OBJECT][$_] = $_;
|
||||
$this->param[10] = $_;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
$this->smartAI->addJsGlobals($this->jsGlobals);
|
||||
|
||||
$target = Lang::smartAI('targets', $this->type, $this->param) ?? Lang::smartAI('targetUNK', [$this->type]);
|
||||
|
||||
// resolve conditionals
|
||||
$i = 0;
|
||||
while (strstr($target, ')?') && $i++ < 3)
|
||||
$target = preg_replace_callback('/\(([^\)]*?)\)\?([^:]*):(([^;]*);*);/i', fn($m) => $m[1] ? $m[2] : $m[3], $target);
|
||||
|
||||
// wrap in tooltip (suspend action-tooltip)
|
||||
return '[/span]'.sprintf(self::TARGET_TPL, $targetTT, $target).'[span tooltip=a-#rowIdx#]';
|
||||
}
|
||||
|
||||
public function getWorldPos() : array
|
||||
{
|
||||
return $this->worldPos;
|
||||
}
|
||||
|
||||
// not really feasable. Too many target types can be players or creatures, depending on context
|
||||
public function getTalkSource(bool &$playerSrc = false) : int
|
||||
{
|
||||
if ($this->type == SmartTarget::TARGET_CLOSEST_PLAYER)
|
||||
$playerSrc = true;
|
||||
|
||||
return match ($this->type)
|
||||
{
|
||||
SmartTarget::TARGET_CREATURE_GUID => $this->resolveGuid(Type::NPC, $this->param[0]) ?? 0,
|
||||
SmartTarget::TARGET_CREATURE_RANGE,
|
||||
SmartTarget::TARGET_CREATURE_DISTANCE,
|
||||
SmartTarget::TARGET_CLOSEST_CREATURE => $this->param[0],
|
||||
SmartTarget::TARGET_CLOSEST_PLAYER,
|
||||
SmartTarget::TARGET_SELF => $this->smartAI->getEntry(),
|
||||
default => $this->smartAI->getEntry()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -230,6 +230,67 @@ define('MENU_IDX_URL', 2); // URL: A string
|
||||
define('MENU_IDX_SUB', 3); // Submenu: Child menu
|
||||
define('MENU_IDX_OPT', 4); // Options: JSON array with additional options
|
||||
|
||||
// profiler queue interactions
|
||||
define('PR_QUEUE_STATUS_ENDED', 0);
|
||||
define('PR_QUEUE_STATUS_WAITING', 1);
|
||||
define('PR_QUEUE_STATUS_WORKING', 2);
|
||||
define('PR_QUEUE_STATUS_READY', 3);
|
||||
define('PR_QUEUE_STATUS_ERROR', 4);
|
||||
define('PR_QUEUE_ERROR_UNK', 0);
|
||||
define('PR_QUEUE_ERROR_CHAR', 1);
|
||||
define('PR_QUEUE_ERROR_ARMORY', 2);
|
||||
|
||||
// profiler completion manager
|
||||
define('PR_EXCLUDE_GROUP_UNAVAILABLE', 0x001);
|
||||
define('PR_EXCLUDE_GROUP_TCG', 0x002);
|
||||
define('PR_EXCLUDE_GROUP_COLLECTORS_EDITION', 0x004);
|
||||
define('PR_EXCLUDE_GROUP_PROMOTION', 0x008);
|
||||
define('PR_EXCLUDE_GROUP_WRONG_REGION', 0x010);
|
||||
define('PR_EXCLUDE_GROUP_REQ_ALLIANCE', 0x020);
|
||||
define('PR_EXCLUDE_GROUP_REQ_HORDE', 0x040);
|
||||
define('PR_EXCLUDE_GROUP_OTHER_FACTION', PR_EXCLUDE_GROUP_REQ_ALLIANCE | PR_EXCLUDE_GROUP_REQ_HORDE);
|
||||
define('PR_EXCLUDE_GROUP_REQ_FISHING', 0x080);
|
||||
define('PR_EXCLUDE_GROUP_REQ_ENGINEERING', 0x100);
|
||||
define('PR_EXCLUDE_GROUP_REQ_TAILORING', 0x200);
|
||||
define('PR_EXCLUDE_GROUP_WRONG_PROFESSION', PR_EXCLUDE_GROUP_REQ_FISHING | PR_EXCLUDE_GROUP_REQ_ENGINEERING | PR_EXCLUDE_GROUP_REQ_TAILORING);
|
||||
define('PR_EXCLUDE_GROUP_REQ_CANT_BE_EXALTED', 0x400);
|
||||
define('PR_EXCLUDE_GROUP_ANY', 0x7FF);
|
||||
|
||||
// Drop Sources
|
||||
define('SRC_CRAFTED', 1);
|
||||
define('SRC_DROP', 2);
|
||||
define('SRC_PVP', 3);
|
||||
define('SRC_QUEST', 4);
|
||||
define('SRC_VENDOR', 5);
|
||||
define('SRC_TRAINER', 6);
|
||||
define('SRC_DISCOVERY', 7);
|
||||
define('SRC_REDEMPTION', 8); // unused
|
||||
define('SRC_TALENT', 9);
|
||||
define('SRC_STARTER', 10);
|
||||
define('SRC_EVENT', 11); // unused
|
||||
define('SRC_ACHIEVEMENT', 12);
|
||||
define('SRC_CUSTOM_STRING', 13);
|
||||
// define('SRC_BLACK_MARKET', 14); // not in 3.3.5
|
||||
define('SRC_DISENCHANTMENT', 15);
|
||||
define('SRC_FISHING', 16);
|
||||
define('SRC_GATHERING', 17);
|
||||
define('SRC_MILLING', 18);
|
||||
define('SRC_MINING', 19);
|
||||
define('SRC_PROSPECTING', 20);
|
||||
define('SRC_PICKPOCKETING', 21);
|
||||
define('SRC_SALVAGING', 22);
|
||||
define('SRC_SKINNING', 23);
|
||||
// define('SRC_INGAME_STORE', 24); // not in 3.3.5
|
||||
|
||||
define('SRC_SUB_PVP_ARENA', 1);
|
||||
define('SRC_SUB_PVP_BG', 2);
|
||||
define('SRC_SUB_PVP_WORLD', 4);
|
||||
|
||||
define('SRC_FLAG_BOSSDROP', 0x01);
|
||||
define('SRC_FLAG_COMMON', 0x02);
|
||||
define('SRC_FLAG_DUNGEON_DROP', 0x10);
|
||||
define('SRC_FLAG_RAID_DROP', 0x20);
|
||||
|
||||
|
||||
/*
|
||||
* Game
|
||||
@@ -648,17 +709,19 @@ define('UNIT_STAND_STATE_DEAD', 7);
|
||||
define('UNIT_STAND_STATE_KNEEL', 8);
|
||||
define('UNIT_STAND_STATE_SUBMERGED', 9);
|
||||
|
||||
// UNIT_FIELD_BYTES_1 - idx 2 (UnitStandFlags)
|
||||
define('UNIT_STAND_FLAGS_UNK1', 0x01);
|
||||
define('UNIT_STAND_FLAGS_CREEP', 0x02);
|
||||
define('UNIT_STAND_FLAGS_UNTRACKABLE', 0x04);
|
||||
define('UNIT_STAND_FLAGS_UNK4', 0x08);
|
||||
define('UNIT_STAND_FLAGS_UNK5', 0x10);
|
||||
// UNIT_FIELD_BYTES_1 - idx 2 (UnitVisFlags)
|
||||
define('UNIT_VIS_FLAGS_UNK1', 0x01);
|
||||
define('UNIT_VIS_FLAGS_CREEP', 0x02);
|
||||
define('UNIT_VIS_FLAGS_UNTRACKABLE', 0x04);
|
||||
define('UNIT_VIS_FLAGS_UNK4', 0x08);
|
||||
define('UNIT_VIS_FLAGS_UNK5', 0x10);
|
||||
|
||||
// UNIT_FIELD_BYTES_1 - idx 3 (UnitBytes1_Flags)
|
||||
define('UNIT_BYTE1_FLAG_ALWAYS_STAND', 0x01);
|
||||
define('UNIT_BYTE1_FLAG_HOVER', 0x02);
|
||||
define('UNIT_BYTE1_FLAG_UNK_3', 0x04);
|
||||
// UNIT_FIELD_BYTES_1 - idx 3 (UnitAnimTier)
|
||||
define('UNIT_BYTE1_ANIM_TIER_GROUND', 0);
|
||||
define('UNIT_BYTE1_ANIM_TIER_SWIM', 1);
|
||||
define('UNIT_BYTE1_ANIM_TIER_HOVER', 2);
|
||||
define('UNIT_BYTE1_ANIM_TIER_FLY', 3);
|
||||
define('UNIT_BYTE1_ANIM_TIER_SUMBERGED', 4);
|
||||
|
||||
define('UNIT_DYNFLAG_LOOTABLE', 0x01); //
|
||||
define('UNIT_DYNFLAG_TRACK_UNIT', 0x02); // Creature's location will be seen as a small dot in the minimap
|
||||
@@ -1840,314 +1903,6 @@ define('ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LINE', 112);
|
||||
// define('ACHIEVEMENT_CRITERIA_TYPE_DISENCHANT_ROLLS', 117);
|
||||
// define('ACHIEVEMENT_CRITERIA_TYPE_USE_LFD_TO_GROUP_WITH_PLAYERS', 119);
|
||||
|
||||
// TrinityCore - SmartAI
|
||||
define('SAI_SRC_TYPE_CREATURE', 0);
|
||||
define('SAI_SRC_TYPE_OBJECT', 1);
|
||||
define('SAI_SRC_TYPE_AREATRIGGER', 2);
|
||||
define('SAI_SRC_TYPE_ACTIONLIST', 9);
|
||||
|
||||
define('SAI_EVENT_FLAG_NO_REPEAT', 0x0001);
|
||||
define('SAI_EVENT_FLAG_DIFFICULTY_0', 0x0002);
|
||||
define('SAI_EVENT_FLAG_DIFFICULTY_1', 0x0004);
|
||||
define('SAI_EVENT_FLAG_DIFFICULTY_2', 0x0008);
|
||||
define('SAI_EVENT_FLAG_DIFFICULTY_3', 0x0010);
|
||||
define('SAI_EVENT_FLAG_NO_RESET', 0x0100);
|
||||
define('SAI_EVENT_FLAG_WHILE_CHARMED', 0x0200);
|
||||
|
||||
define('SAI_EVENT_UPDATE_IC', 0); // In combat.
|
||||
define('SAI_EVENT_UPDATE_OOC', 1); // Out of combat.
|
||||
define('SAI_EVENT_HEALTH_PCT', 2); // Health Percentage
|
||||
define('SAI_EVENT_MANA_PCT', 3); // Mana Percentage
|
||||
define('SAI_EVENT_AGGRO', 4); // On Creature Aggro
|
||||
define('SAI_EVENT_KILL', 5); // On Creature Kill
|
||||
define('SAI_EVENT_DEATH', 6); // On Creature Death
|
||||
define('SAI_EVENT_EVADE', 7); // On Creature Evade Attack
|
||||
define('SAI_EVENT_SPELLHIT', 8); // On Creature/Gameobject Spell Hit
|
||||
define('SAI_EVENT_RANGE', 9); // On Target In Range
|
||||
define('SAI_EVENT_OOC_LOS', 10); // On Target In Distance Out of Combat
|
||||
define('SAI_EVENT_RESPAWN', 11); // On Creature/Gameobject Respawn
|
||||
define('SAI_EVENT_TARGET_HEALTH_PCT', 12); // On Target Health Percentage
|
||||
define('SAI_EVENT_VICTIM_CASTING', 13); // On Target Casting Spell
|
||||
define('SAI_EVENT_FRIENDLY_HEALTH', 14); // On Friendly Health Deficit
|
||||
define('SAI_EVENT_FRIENDLY_IS_CC', 15); //
|
||||
define('SAI_EVENT_FRIENDLY_MISSING_BUFF', 16); // On Friendly Lost Buff
|
||||
define('SAI_EVENT_SUMMONED_UNIT', 17); // On Creature/Gameobject Summoned Unit
|
||||
define('SAI_EVENT_TARGET_MANA_PCT', 18); // On Target Mana Percentage
|
||||
define('SAI_EVENT_ACCEPTED_QUEST', 19); // On Target Accepted Quest
|
||||
define('SAI_EVENT_REWARD_QUEST', 20); // On Target Rewarded Quest
|
||||
define('SAI_EVENT_REACHED_HOME', 21); // On Creature Reached Home
|
||||
define('SAI_EVENT_RECEIVE_EMOTE', 22); // On Receive Emote.
|
||||
define('SAI_EVENT_HAS_AURA', 23); // On Creature Has Aura
|
||||
define('SAI_EVENT_TARGET_BUFFED', 24); // On Target Buffed With Spell
|
||||
define('SAI_EVENT_RESET', 25); // After Combat, On Respawn or Spawn
|
||||
define('SAI_EVENT_IC_LOS', 26); // On Target In Distance In Combat
|
||||
define('SAI_EVENT_PASSENGER_BOARDED', 27); //
|
||||
define('SAI_EVENT_PASSENGER_REMOVED', 28); //
|
||||
define('SAI_EVENT_CHARMED', 29); // On Creature Charmed
|
||||
define('SAI_EVENT_CHARMED_TARGET', 30); // On Target Charmed
|
||||
define('SAI_EVENT_SPELLHIT_TARGET', 31); // On Target Spell Hit
|
||||
define('SAI_EVENT_DAMAGED', 32); // On Creature Damaged
|
||||
define('SAI_EVENT_DAMAGED_TARGET', 33); // On Target Damaged
|
||||
define('SAI_EVENT_MOVEMENTINFORM', 34); // WAYPOINT_MOTION_TYPE = 2, POINT_MOTION_TYPE = 8
|
||||
define('SAI_EVENT_SUMMON_DESPAWNED', 35); // On Summoned Unit Despawned
|
||||
define('SAI_EVENT_CORPSE_REMOVED', 36); // On Creature Corpse Removed
|
||||
define('SAI_EVENT_AI_INIT', 37); //
|
||||
define('SAI_EVENT_DATA_SET', 38); // On Creature/Gameobject Data Set, Can be used with SMART_ACTION_SET_DATA
|
||||
define('SAI_EVENT_WAYPOINT_START', 39); // On Creature Waypoint ID Started
|
||||
define('SAI_EVENT_WAYPOINT_REACHED', 40); // On Creature Waypoint ID Reached
|
||||
// define('SAI_EVENT_TRANSPORT_ADDPLAYER', 41); //
|
||||
// define('SAI_EVENT_TRANSPORT_ADDCREATURE', 42); //
|
||||
// define('SAI_EVENT_TRANSPORT_REMOVE_PLAYER', 43); //
|
||||
// define('SAI_EVENT_TRANSPORT_RELOCATE', 44); //
|
||||
// define('SAI_EVENT_INSTANCE_PLAYER_ENTER', 45); //
|
||||
define('SAI_EVENT_AREATRIGGER_ONTRIGGER', 46); //
|
||||
// define('SAI_EVENT_QUEST_ACCEPTED', 47); // On Target Quest Accepted
|
||||
// define('SAI_EVENT_QUEST_OBJ_COMPLETION', 48); // On Target Quest Objective Completed
|
||||
// define('SAI_EVENT_QUEST_COMPLETION', 49); // On Target Quest Completed
|
||||
// define('SAI_EVENT_QUEST_REWARDED', 50); // On Target Quest Rewarded
|
||||
// define('SAI_EVENT_QUEST_FAIL', 51); // On Target Quest Field
|
||||
define('SAI_EVENT_TEXT_OVER', 52); // On TEXT_OVER Event Triggered After SMART_ACTION_TALK
|
||||
define('SAI_EVENT_RECEIVE_HEAL', 53); // On Creature Received Healing
|
||||
define('SAI_EVENT_JUST_SUMMONED', 54); // On Creature Just spawned
|
||||
define('SAI_EVENT_WAYPOINT_PAUSED', 55); // On Creature Paused at Waypoint ID
|
||||
define('SAI_EVENT_WAYPOINT_RESUMED', 56); // On Creature Resumed after Waypoint ID
|
||||
define('SAI_EVENT_WAYPOINT_STOPPED', 57); // On Creature Stopped On Waypoint ID
|
||||
define('SAI_EVENT_WAYPOINT_ENDED', 58); // On Creature Waypoint Path Ended
|
||||
define('SAI_EVENT_TIMED_EVENT_TRIGGERED', 59); //
|
||||
define('SAI_EVENT_UPDATE', 60); //
|
||||
define('SAI_EVENT_LINK', 61); // Used to link together multiple events as a chain of events.
|
||||
define('SAI_EVENT_GOSSIP_SELECT', 62); // On gossip clicked (gossip_menu_option335).
|
||||
define('SAI_EVENT_JUST_CREATED', 63); //
|
||||
define('SAI_EVENT_GOSSIP_HELLO', 64); // On Right-Click Creature/Gameobject that have gossip enabled.
|
||||
define('SAI_EVENT_FOLLOW_COMPLETED', 65); //
|
||||
define('SAI_EVENT_EVENT_PHASE_CHANGE', 66); // On event phase mask set
|
||||
define('SAI_EVENT_IS_BEHIND_TARGET', 67); // On Creature is behind target.
|
||||
define('SAI_EVENT_GAME_EVENT_START', 68); // On game_event started.
|
||||
define('SAI_EVENT_GAME_EVENT_END', 69); // On game_event ended.
|
||||
define('SAI_EVENT_GO_STATE_CHANGED', 70); //
|
||||
define('SAI_EVENT_GO_EVENT_INFORM', 71); //
|
||||
define('SAI_EVENT_ACTION_DONE', 72); //
|
||||
define('SAI_EVENT_ON_SPELLCLICK', 73); //
|
||||
define('SAI_EVENT_FRIENDLY_HEALTH_PCT', 74); //
|
||||
define('SAI_EVENT_DISTANCE_CREATURE', 75); // On creature guid OR any instance of creature entry is within distance.
|
||||
define('SAI_EVENT_DISTANCE_GAMEOBJECT', 76); // On gameobject guid OR any instance of gameobject entry is within distance.
|
||||
define('SAI_EVENT_COUNTER_SET', 77); // If the value of specified counterID is equal to a specified value
|
||||
// define('SAI_EVENT_SCENE_START', 78); // don't use on 3.3.5a
|
||||
// define('SAI_EVENT_SCENE_TRIGGER', 79); // don't use on 3.3.5a
|
||||
// define('SAI_EVENT_SCENE_CANCEL', 80); // don't use on 3.3.5a
|
||||
// define('SAI_EVENT_SCENE_COMPLETE', 81); // don't use on 3.3.5a
|
||||
define('SAI_EVENT_SUMMONED_UNIT_DIES', 82); // CreatureId(0 all), CooldownMin, CooldownMax
|
||||
|
||||
define('SAI_ACTION_NONE', 0); // Do nothing
|
||||
define('SAI_ACTION_TALK', 1); // Param2 in Milliseconds.
|
||||
define('SAI_ACTION_SET_FACTION', 2); // Sets faction to creature.
|
||||
define('SAI_ACTION_MORPH_TO_ENTRY_OR_MODEL', 3); // Take DisplayID of creature (param1) OR Turn to DisplayID (param2) OR Both = 0 for Demorph
|
||||
define('SAI_ACTION_SOUND', 4); // TextRange = 0 only sends sound to self, TextRange = 1 sends sound to everyone in visibility range
|
||||
define('SAI_ACTION_PLAY_EMOTE', 5); // Play Emote
|
||||
define('SAI_ACTION_FAIL_QUEST', 6); // Fail Quest of Target
|
||||
define('SAI_ACTION_OFFER_QUEST', 7); // Add Quest to Target
|
||||
define('SAI_ACTION_SET_REACT_STATE', 8); // React State. Can be Passive (0), Defensive (1), Aggressive (2), Assist (3).
|
||||
define('SAI_ACTION_ACTIVATE_GOBJECT', 9); // Activate Object
|
||||
define('SAI_ACTION_RANDOM_EMOTE', 10); // Play Random Emote
|
||||
define('SAI_ACTION_CAST', 11); // Cast Spell ID at Target
|
||||
define('SAI_ACTION_SUMMON_CREATURE', 12); // Summon Unit
|
||||
define('SAI_ACTION_THREAT_SINGLE_PCT', 13); // Change Threat Percentage for Single Target
|
||||
define('SAI_ACTION_THREAT_ALL_PCT', 14); // Change Threat Percentage for All Enemies
|
||||
define('SAI_ACTION_CALL_AREAEXPLOREDOREVENTHAPPENS', 15); //
|
||||
// define('SAI_ACTION_SET_INGAME_PHASE_ID', 16); // For 4.3.4 + only
|
||||
define('SAI_ACTION_SET_EMOTE_STATE', 17); // Play Emote Continuously
|
||||
define('SAI_ACTION_SET_UNIT_FLAG', 18); // Can set Multi-able flags at once
|
||||
define('SAI_ACTION_REMOVE_UNIT_FLAG', 19); // Can Remove Multi-able flags at once
|
||||
define('SAI_ACTION_AUTO_ATTACK', 20); // Stop or Continue Automatic Attack.
|
||||
define('SAI_ACTION_ALLOW_COMBAT_MOVEMENT', 21); // Allow or Disable Combat Movement
|
||||
define('SAI_ACTION_SET_EVENT_PHASE', 22); //
|
||||
define('SAI_ACTION_INC_EVENT_PHASE', 23); // Set param1 OR param2 (not both). Value 0 has no effect.
|
||||
define('SAI_ACTION_EVADE', 24); // Evade Incoming Attack
|
||||
define('SAI_ACTION_FLEE_FOR_ASSIST', 25); // If you want the fleeing NPC to say '%s attempts to run away in fear' on flee, use 1 on param1. 0 for no message.
|
||||
define('SAI_ACTION_CALL_GROUPEVENTHAPPENS', 26); //
|
||||
define('SAI_ACTION_COMBAT_STOP', 27); //
|
||||
define('SAI_ACTION_REMOVEAURASFROMSPELL', 28); // 0 removes all auras
|
||||
define('SAI_ACTION_FOLLOW', 29); // Follow Target
|
||||
define('SAI_ACTION_RANDOM_PHASE', 30); //
|
||||
define('SAI_ACTION_RANDOM_PHASE_RANGE', 31); //
|
||||
define('SAI_ACTION_RESET_GOBJECT', 32); // Reset Gameobject
|
||||
define('SAI_ACTION_CALL_KILLEDMONSTER', 33); // This is the ID from quest_template.RequiredNpcOrGo
|
||||
define('SAI_ACTION_SET_INST_DATA', 34); // Set Instance Data
|
||||
// define('SAI_ACTION_SET_INST_DATA64', 35); // Set Instance Data uint64
|
||||
define('SAI_ACTION_UPDATE_TEMPLATE', 36); // Updates creature_template to given entry
|
||||
define('SAI_ACTION_DIE', 37); // Kill Target
|
||||
define('SAI_ACTION_SET_IN_COMBAT_WITH_ZONE', 38); //
|
||||
define('SAI_ACTION_CALL_FOR_HELP', 39); // If you want the NPC to say '%s calls for help!'. Use 1 on param1, 0 for no message.
|
||||
define('SAI_ACTION_SET_SHEATH', 40); //
|
||||
define('SAI_ACTION_FORCE_DESPAWN', 41); // Despawn Target after param1 in Milliseconds. If you want to set respawn time set param2 in seconds.
|
||||
define('SAI_ACTION_SET_INVINCIBILITY_HP_LEVEL', 42); // If you use both params, only percent will be used.
|
||||
define('SAI_ACTION_MOUNT_TO_ENTRY_OR_MODEL', 43); // Mount to Creature Entry (param1) OR Mount to Creature Display (param2) Or both = 0 for Unmount
|
||||
define('SAI_ACTION_SET_INGAME_PHASE_MASK', 44); //
|
||||
define('SAI_ACTION_SET_DATA', 45); // Set Data For Target, can be used with SMART_EVENT_DATA_SET
|
||||
define('SAI_ACTION_ATTACK_STOP', 46); //
|
||||
define('SAI_ACTION_SET_VISIBILITY', 47); // Makes creature Visible = 1 or Invisible = 0
|
||||
define('SAI_ACTION_SET_ACTIVE', 48); //
|
||||
define('SAI_ACTION_ATTACK_START', 49); // Allows basic melee swings to creature.
|
||||
define('SAI_ACTION_SUMMON_GO', 50); // Spawns Gameobject, use target_type to set spawn position.
|
||||
define('SAI_ACTION_KILL_UNIT', 51); // Kills Creature.
|
||||
define('SAI_ACTION_ACTIVATE_TAXI', 52); // Sends player to flight path. You have to be close to Flight Master, which gives Taxi ID you need.
|
||||
define('SAI_ACTION_WP_START', 53); // Creature starts Waypoint Movement. Use waypoints table to create movement.
|
||||
define('SAI_ACTION_WP_PAUSE', 54); // Creature pauses its Waypoint Movement for given time.
|
||||
define('SAI_ACTION_WP_STOP', 55); // Creature stops its Waypoint Movement.
|
||||
define('SAI_ACTION_ADD_ITEM', 56); // Adds item(s) to player.
|
||||
define('SAI_ACTION_REMOVE_ITEM', 57); // Removes item(s) from player.
|
||||
define('SAI_ACTION_INSTALL_AI_TEMPLATE', 58); //
|
||||
define('SAI_ACTION_SET_RUN', 59); //
|
||||
define('SAI_ACTION_SET_DISABLE_GRAVITY', 60); // Only works for creatures with inhabit air.
|
||||
define('SAI_ACTION_SET_SWIM', 61); //
|
||||
define('SAI_ACTION_TELEPORT', 62); // Continue this action with the TARGET_TYPE column. Use any target_type (except 0), and use target_x, target_y, target_z, target_o as the coordinates
|
||||
define('SAI_ACTION_SET_COUNTER', 63); //
|
||||
define('SAI_ACTION_STORE_TARGET_LIST', 64); //
|
||||
define('SAI_ACTION_WP_RESUME', 65); // Creature continues in its Waypoint Movement.
|
||||
define('SAI_ACTION_SET_ORIENTATION', 66); //
|
||||
define('SAI_ACTION_CREATE_TIMED_EVENT', 67); //
|
||||
define('SAI_ACTION_PLAYMOVIE', 68); //
|
||||
define('SAI_ACTION_MOVE_TO_POS', 69); // PointId is called by SMART_EVENT_MOVEMENTINFORM. Continue this action with the TARGET_TYPE column. Use any target_type, and use target_x, target_y, target_z, target_o as the coordinates
|
||||
define('SAI_ACTION_ENABLE_TEMP_GOBJ', 70); // param1 = duration
|
||||
define('SAI_ACTION_EQUIP', 71); // only slots with mask set will be sent to client, bits are 1, 2, 4, leaving mask 0 is defaulted to mask 7 (send all), Slots1-3 are only used if no Param1 is set
|
||||
define('SAI_ACTION_CLOSE_GOSSIP', 72); // Closes gossip window.
|
||||
define('SAI_ACTION_TRIGGER_TIMED_EVENT', 73); //
|
||||
define('SAI_ACTION_REMOVE_TIMED_EVENT', 74); //
|
||||
define('SAI_ACTION_ADD_AURA', 75); // Adds aura to player(s). Use target_type 17 to make AoE aura.
|
||||
define('SAI_ACTION_OVERRIDE_SCRIPT_BASE_OBJECT', 76); // WARNING: CAN CRASH CORE, do not use if you dont know what you are doing
|
||||
define('SAI_ACTION_RESET_SCRIPT_BASE_OBJECT', 77); //
|
||||
define('SAI_ACTION_CALL_SCRIPT_RESET', 78); //
|
||||
define('SAI_ACTION_SET_RANGED_MOVEMENT', 79); // Sets movement to follow at a specific range to the target.
|
||||
define('SAI_ACTION_CALL_TIMED_ACTIONLIST', 80); //
|
||||
define('SAI_ACTION_SET_NPC_FLAG', 81); //
|
||||
define('SAI_ACTION_ADD_NPC_FLAG', 82); //
|
||||
define('SAI_ACTION_REMOVE_NPC_FLAG', 83); //
|
||||
define('SAI_ACTION_SIMPLE_TALK', 84); // Makes a player say text. SMART_EVENT_TEXT_OVER is not triggered and whispers can not be used.
|
||||
define('SAI_ACTION_SELF_CAST', 85); // spellID, castFlags
|
||||
define('SAI_ACTION_CROSS_CAST', 86); // This action is used to make selected caster (in CasterTargetType) to cast spell. Actual target is entered in target_type as normally.
|
||||
define('SAI_ACTION_CALL_RANDOM_TIMED_ACTIONLIST', 87); // Will select one entry from the ones provided. 0 is ignored.
|
||||
define('SAI_ACTION_CALL_RANDOM_RANGE_TIMED_ACTIONLIST', 88); // 0 is ignored.
|
||||
define('SAI_ACTION_RANDOM_MOVE', 89); // Creature moves to random position in given radius.
|
||||
define('SAI_ACTION_SET_UNIT_FIELD_BYTES_1', 90); //
|
||||
define('SAI_ACTION_REMOVE_UNIT_FIELD_BYTES_1', 91); //
|
||||
define('SAI_ACTION_INTERRUPT_SPELL', 92); // This action allows you to interrupt the current spell being cast. If you do not set the spellId, the core will find the current spell depending on the withDelay and the withInstant values.
|
||||
define('SAI_ACTION_SEND_GO_CUSTOM_ANIM', 93); //
|
||||
define('SAI_ACTION_SET_DYNAMIC_FLAG', 94); //
|
||||
define('SAI_ACTION_ADD_DYNAMIC_FLAG', 95); //
|
||||
define('SAI_ACTION_REMOVE_DYNAMIC_FLAG', 96); //
|
||||
define('SAI_ACTION_JUMP_TO_POS', 97); //
|
||||
define('SAI_ACTION_SEND_GOSSIP_MENU', 98); // Can be used together with 'SMART_EVENT_GOSSIP_HELLO' to set custom gossip.
|
||||
define('SAI_ACTION_GO_SET_LOOT_STATE', 99); //
|
||||
define('SAI_ACTION_SEND_TARGET_TO_TARGET', 100); // Send targets previously stored with SMART_ACTION_STORE_TARGET, to another npc/go, the other npc/go can then access them as if it was its own stored list
|
||||
define('SAI_ACTION_SET_HOME_POS', 101); // Use with SMART_TARGET_SELF or SMART_TARGET_POSITION
|
||||
define('SAI_ACTION_SET_HEALTH_REGEN', 102); // Sets the current creatures health regen on or off.
|
||||
define('SAI_ACTION_SET_ROOT', 103); // Enables or disables creature movement
|
||||
define('SAI_ACTION_SET_GO_FLAG', 104); // oldFlag = newFlag
|
||||
define('SAI_ACTION_ADD_GO_FLAG', 105); // oldFlag |= newFlag
|
||||
define('SAI_ACTION_REMOVE_GO_FLAG', 106); // oldFlag &= ~newFlag
|
||||
define('SAI_ACTION_SUMMON_CREATURE_GROUP', 107); // Use creature_summon_groups table. SAI target has no effect, use 0
|
||||
define('SAI_ACTION_SET_POWER', 108); //
|
||||
define('SAI_ACTION_ADD_POWER', 109); //
|
||||
define('SAI_ACTION_REMOVE_POWER', 110); //
|
||||
define('SAI_ACTION_GAME_EVENT_STOP', 111); //
|
||||
define('SAI_ACTION_GAME_EVENT_START', 112); //
|
||||
define('SAI_ACTION_START_CLOSEST_WAYPOINT', 113); // Make target follow closest waypoint to its location
|
||||
define('SAI_ACTION_MOVE_OFFSET', 114); // Use target_x, target_y, target_z With target_type=1
|
||||
define('SAI_ACTION_RANDOM_SOUND', 115); //
|
||||
define('SAI_ACTION_SET_CORPSE_DELAY', 116); //
|
||||
define('SAI_ACTION_DISABLE_EVADE', 117); //
|
||||
define('SAI_ACTION_GO_SET_GO_STATE', 118); //
|
||||
define('SAI_ACTION_SET_CAN_FLY', 119); //
|
||||
define('SAI_ACTION_REMOVE_AURAS_BY_TYPE', 120); //
|
||||
define('SAI_ACTION_SET_SIGHT_DIST', 121); //
|
||||
define('SAI_ACTION_FLEE', 122); //
|
||||
define('SAI_ACTION_ADD_THREAT', 123); //
|
||||
define('SAI_ACTION_LOAD_EQUIPMENT', 124); //
|
||||
define('SAI_ACTION_TRIGGER_RANDOM_TIMED_EVENT', 125); //
|
||||
define('SAI_ACTION_REMOVE_ALL_GAMEOBJECTS', 126); //
|
||||
define('SAI_ACTION_PAUSE_MOVEMENT', 127); // MovementSlot (default = 0, active = 1, controlled = 2), PauseTime (ms), Force
|
||||
// define('SAI_ACTION_PLAY_ANIMKIT', 128); // don't use on 3.3.5a
|
||||
// define('SAI_ACTION_SCENE_PLAY', 129); // don't use on 3.3.5a
|
||||
// define('SAI_ACTION_SCENE_CANCEL', 130); // don't use on 3.3.5a
|
||||
define('SAI_ACTION_SPAWN_SPAWNGROUP', 131); //
|
||||
define('SAI_ACTION_DESPAWN_SPAWNGROUP', 132); //
|
||||
define('SAI_ACTION_RESPAWN_BY_SPAWNID', 133); // type, typeGuid - Use to respawn npcs and gobs, the target in this case is always=1 and only a single unit could be a target via the spawnId (action_param1, action_param2)
|
||||
define('SAI_ACTION_INVOKER_CAST', 134); // spellID, castFlags
|
||||
define('SAI_ACTION_PLAY_CINEMATIC', 135); // cinematic
|
||||
define('SAI_ACTION_SET_MOVEMENT_SPEED', 136); // movementType, speedInteger, speedFraction
|
||||
define('SAI_ACTION_PLAY_SPELL_VISUAL_KIT', 137); // spellVisualKitId (RESERVED, PENDING CHERRYPICK)
|
||||
define('SAI_ACTION_OVERRIDE_LIGHT', 138); // zoneId, areaLightId, overrideLightID, transitionMilliseconds
|
||||
define('SAI_ACTION_OVERRIDE_WEATHER', 139); // zoneId, weatherId, intensity
|
||||
|
||||
define('SAI_ACTION_ALL_SPELLCASTS', [SAI_ACTION_CAST, SAI_ACTION_ADD_AURA, SAI_ACTION_INVOKER_CAST, SAI_ACTION_SELF_CAST, SAI_ACTION_CROSS_CAST]);
|
||||
define('SAI_ACTION_ALL_TIMED_ACTION_LISTS', [SAI_ACTION_CALL_TIMED_ACTIONLIST, SAI_ACTION_CALL_RANDOM_TIMED_ACTIONLIST, SAI_ACTION_CALL_RANDOM_RANGE_TIMED_ACTIONLIST]);
|
||||
|
||||
define('SAI_CAST_FLAG_INTERRUPT_PREV', 0x01);
|
||||
define('SAI_CAST_FLAG_TRIGGERED', 0x02);
|
||||
// define('SAI_CAST_FORCE_CAST', 0x04); // Forces cast even if creature is out of mana or out of range
|
||||
// define('SAI_CAST_NO_MELEE_IF_OOM', 0x08); // Prevents creature from entering melee if out of mana or out of range
|
||||
// define('SAI_CAST_FORCE_TARGET_SELF', 0x10); // the target to cast this spell on itself
|
||||
define('SAI_CAST_FLAG_AURA_MISSING', 0x20);
|
||||
define('SAI_CAST_FLAG_COMBAT_MOVE', 0x40);
|
||||
|
||||
define('SAI_REACT_PASSIVE', 0);
|
||||
define('SAI_REACT_DEFENSIVE', 1);
|
||||
define('SAI_REACT_AGGRESSIVE', 2);
|
||||
define('SAI_REACT_ASSIST', 3);
|
||||
|
||||
define('SAI_SUMMON_TIMED_OR_DEAD_DESPAWN', 1);
|
||||
define('SAI_SUMMON_TIMED_OR_CORPSE_DESPAWN', 2);
|
||||
define('SAI_SUMMON_TIMED_DESPAWN', 3);
|
||||
define('SAI_SUMMON_TIMED_DESPAWN_OOC', 4);
|
||||
define('SAI_SUMMON_CORPSE_DESPAWN', 5);
|
||||
define('SAI_SUMMON_CORPSE_TIMED_DESPAWN', 6);
|
||||
define('SAI_SUMMON_DEAD_DESPAWN', 7);
|
||||
define('SAI_SUMMON_MANUAL_DESPAWN', 8);
|
||||
|
||||
define('SAI_TARGET_NONE', 0); // None.
|
||||
define('SAI_TARGET_SELF', 1); // Self cast.
|
||||
define('SAI_TARGET_VICTIM', 2); // Our current target. (ie: highest aggro)
|
||||
define('SAI_TARGET_HOSTILE_SECOND_AGGRO', 3); // Second highest aggro.
|
||||
define('SAI_TARGET_HOSTILE_LAST_AGGRO', 4); // Dead last on aggro.
|
||||
define('SAI_TARGET_HOSTILE_RANDOM', 5); // Just any random target on our threat list.
|
||||
define('SAI_TARGET_HOSTILE_RANDOM_NOT_TOP', 6); // Any random target except top threat.
|
||||
define('SAI_TARGET_ACTION_INVOKER', 7); // Unit who caused this Event to occur.
|
||||
define('SAI_TARGET_POSITION', 8); // Use xyz from event params.
|
||||
define('SAI_TARGET_CREATURE_RANGE', 9); // (Random?) creature with specified ID within specified range.
|
||||
define('SAI_TARGET_CREATURE_GUID', 10); // Creature with specified GUID.
|
||||
define('SAI_TARGET_CREATURE_DISTANCE', 11); // Creature with specified ID within distance. (Different from #9?)
|
||||
define('SAI_TARGET_STORED', 12); // Uses pre-stored target(list)
|
||||
define('SAI_TARGET_GAMEOBJECT_RANGE', 13); // (Random?) object with specified ID within specified range.
|
||||
define('SAI_TARGET_GAMEOBJECT_GUID', 14); // Object with specified GUID.
|
||||
define('SAI_TARGET_GAMEOBJECT_DISTANCE', 15); // Object with specified ID within distance. (Different from #13?)
|
||||
define('SAI_TARGET_INVOKER_PARTY', 16); // Invoker's party members
|
||||
define('SAI_TARGET_PLAYER_RANGE', 17); // (Random?) player within specified range.
|
||||
define('SAI_TARGET_PLAYER_DISTANCE', 18); // (Random?) player within specified distance. (Different from #17?)
|
||||
define('SAI_TARGET_CLOSEST_CREATURE', 19); // Closest creature with specified ID within specified range.
|
||||
define('SAI_TARGET_CLOSEST_GAMEOBJECT', 20); // Closest object with specified ID within specified range.
|
||||
define('SAI_TARGET_CLOSEST_PLAYER', 21); // Closest player within specified range.
|
||||
define('SAI_TARGET_ACTION_INVOKER_VEHICLE', 22); // Unit's vehicle who caused this Event to occur
|
||||
define('SAI_TARGET_OWNER_OR_SUMMONER', 23); // Unit's owner or summoner
|
||||
define('SAI_TARGET_THREAT_LIST', 24); // All units on creature's threat list
|
||||
define('SAI_TARGET_CLOSEST_ENEMY', 25); // Any attackable target (creature or player) within maxDist
|
||||
define('SAI_TARGET_CLOSEST_FRIENDLY', 26); // Any friendly unit (creature, player or pet) within maxDist
|
||||
define('SAI_TARGET_LOOT_RECIPIENTS', 27); // All tagging players
|
||||
define('SAI_TARGET_FARTHEST', 28); // Farthest unit on the threat list
|
||||
define('SAI_TARGET_VEHICLE_PASSENGER', 29); // Vehicle can target unit in given seat
|
||||
define('SAI_TARGET_CLOSEST_UNSPAWNED_GO', 30); // entry(0any), maxDist
|
||||
|
||||
define('SAI_TEMPLATE_BASIC', 0); //
|
||||
define('SAI_TEMPLATE_CASTER', 1); // +JOIN: target_param1 as castFlag
|
||||
define('SAI_TEMPLATE_TURRET', 2); // +JOIN: target_param1 as castflag
|
||||
define('SAI_TEMPLATE_PASSIVE', 3); //
|
||||
define('SAI_TEMPLATE_CAGED_GO_PART', 4); //
|
||||
define('SAI_TEMPLATE_CAGED_NPC_PART', 5); //
|
||||
|
||||
define('SAI_SPAWN_FLAG_NONE', 0x00);
|
||||
define('SAI_SPAWN_FLAG_IGNORE_RESPAWN', 0x01); // onSpawnIn - ignore & reset respawn timer
|
||||
define('SAI_SPAWN_FLAG_FORCE_SPAWN', 0x02); // onSpawnIn - force additional spawn if already in world
|
||||
define('SAI_SPAWN_FLAG_NOSAVE_RESPAWN', 0x04); // onDespawn - remove respawn time
|
||||
|
||||
// TrinityCore - Account Security
|
||||
define('SEC_PLAYER', 0);
|
||||
define('SEC_MODERATOR', 1);
|
||||
@@ -2155,32 +1910,6 @@ define('SEC_GAMEMASTER', 2);
|
||||
define('SEC_ADMINISTRATOR', 3);
|
||||
define('SEC_CONSOLE', 4); // console only - should not be encountered
|
||||
|
||||
// profiler queue interactions
|
||||
define('PR_QUEUE_STATUS_ENDED', 0);
|
||||
define('PR_QUEUE_STATUS_WAITING', 1);
|
||||
define('PR_QUEUE_STATUS_WORKING', 2);
|
||||
define('PR_QUEUE_STATUS_READY', 3);
|
||||
define('PR_QUEUE_STATUS_ERROR', 4);
|
||||
define('PR_QUEUE_ERROR_UNK', 0);
|
||||
define('PR_QUEUE_ERROR_CHAR', 1);
|
||||
define('PR_QUEUE_ERROR_ARMORY', 2);
|
||||
|
||||
// profiler completion manager
|
||||
define('PR_EXCLUDE_GROUP_UNAVAILABLE', 0x001);
|
||||
define('PR_EXCLUDE_GROUP_TCG', 0x002);
|
||||
define('PR_EXCLUDE_GROUP_COLLECTORS_EDITION', 0x004);
|
||||
define('PR_EXCLUDE_GROUP_PROMOTION', 0x008);
|
||||
define('PR_EXCLUDE_GROUP_WRONG_REGION', 0x010);
|
||||
define('PR_EXCLUDE_GROUP_REQ_ALLIANCE', 0x020);
|
||||
define('PR_EXCLUDE_GROUP_REQ_HORDE', 0x040);
|
||||
define('PR_EXCLUDE_GROUP_OTHER_FACTION', PR_EXCLUDE_GROUP_REQ_ALLIANCE | PR_EXCLUDE_GROUP_REQ_HORDE);
|
||||
define('PR_EXCLUDE_GROUP_REQ_FISHING', 0x080);
|
||||
define('PR_EXCLUDE_GROUP_REQ_ENGINEERING', 0x100);
|
||||
define('PR_EXCLUDE_GROUP_REQ_TAILORING', 0x200);
|
||||
define('PR_EXCLUDE_GROUP_WRONG_PROFESSION', PR_EXCLUDE_GROUP_REQ_FISHING | PR_EXCLUDE_GROUP_REQ_ENGINEERING | PR_EXCLUDE_GROUP_REQ_TAILORING);
|
||||
define('PR_EXCLUDE_GROUP_REQ_CANT_BE_EXALTED', 0x400);
|
||||
define('PR_EXCLUDE_GROUP_ANY', 0x7FF);
|
||||
|
||||
// Areatrigger types
|
||||
define('AT_TYPE_NONE', 0);
|
||||
define('AT_TYPE_TAVERN', 1);
|
||||
@@ -2189,40 +1918,9 @@ define('AT_TYPE_OBJECTIVE', 3);
|
||||
define('AT_TYPE_SMART', 4);
|
||||
define('AT_TYPE_SCRIPT', 5);
|
||||
|
||||
// Drop Sources
|
||||
define('SRC_CRAFTED', 1);
|
||||
define('SRC_DROP', 2);
|
||||
define('SRC_PVP', 3);
|
||||
define('SRC_QUEST', 4);
|
||||
define('SRC_VENDOR', 5);
|
||||
define('SRC_TRAINER', 6);
|
||||
define('SRC_DISCOVERY', 7);
|
||||
define('SRC_REDEMPTION', 8); // unused
|
||||
define('SRC_TALENT', 9);
|
||||
define('SRC_STARTER', 10);
|
||||
define('SRC_EVENT', 11); // unused
|
||||
define('SRC_ACHIEVEMENT', 12);
|
||||
define('SRC_CUSTOM_STRING', 13);
|
||||
// define('SRC_BLACK_MARKET', 14); // not in 3.3.5
|
||||
define('SRC_DISENCHANTMENT', 15);
|
||||
define('SRC_FISHING', 16);
|
||||
define('SRC_GATHERING', 17);
|
||||
define('SRC_MILLING', 18);
|
||||
define('SRC_MINING', 19);
|
||||
define('SRC_PROSPECTING', 20);
|
||||
define('SRC_PICKPOCKETING', 21);
|
||||
define('SRC_SALVAGING', 22);
|
||||
define('SRC_SKINNING', 23);
|
||||
// define('SRC_INGAME_STORE', 24); // not in 3.3.5
|
||||
|
||||
define('SRC_SUB_PVP_ARENA', 1);
|
||||
define('SRC_SUB_PVP_BG', 2);
|
||||
define('SRC_SUB_PVP_WORLD', 4);
|
||||
|
||||
define('SRC_FLAG_BOSSDROP', 0x01);
|
||||
define('SRC_FLAG_COMMON', 0x02);
|
||||
define('SRC_FLAG_DUNGEON_DROP', 0x10);
|
||||
define('SRC_FLAG_RAID_DROP', 0x20);
|
||||
// summon types
|
||||
define('SUMMONER_TYPE_CREATURE', 0);
|
||||
define('SUMMONER_TYPE_GAMEOBJECT', 1);
|
||||
|
||||
// Map Types
|
||||
define('MAP_TYPE_ZONE', 0);
|
||||
|
||||
@@ -330,7 +330,7 @@ class Game
|
||||
$result = array_replace($result, DB::World()->select(
|
||||
'SELECT -`ID` AS ARRAY_KEY, ID AS `id`, `target_map` AS `mapId`, `target_position_x` AS `posX`, `target_position_y` AS `posY` FROM areatrigger_teleport WHERE -`id` IN (?a) UNION
|
||||
SELECT -`entryorguid` AS ARRAY_KEY, entryorguid AS `id`, `action_param1` AS `mapId`, `target_x` AS `posX`, `target_y` AS `posY` FROM smart_scripts WHERE -`entryorguid` IN (?a) AND `source_type` = ?d AND `action_type` = ?d',
|
||||
$endpoints, $endpoints, SAI_SRC_TYPE_AREATRIGGER, SAI_ACTION_TELEPORT
|
||||
$endpoints, $endpoints, SmartAI::SRC_TYPE_AREATRIGGER, SmartAction::ACTION_TELEPORT
|
||||
));
|
||||
break;
|
||||
default:
|
||||
@@ -425,7 +425,7 @@ class Game
|
||||
if (in_array($t['talkType'], [2, 16]) && strpos($msg, '%s') === false)
|
||||
$msg = '%s '.$msg;
|
||||
|
||||
// fixup: bad case-insensivity
|
||||
// fixup: bad case-insensitivity
|
||||
$msg = Util::parseHtmlText(str_replace('%S', '%s', htmlentities($msg)), !$asHTML);
|
||||
|
||||
if ($talkSource)
|
||||
|
||||
@@ -28,25 +28,45 @@ if ($error)
|
||||
|
||||
require_once 'includes/defines.php';
|
||||
require_once 'includes/locale.class.php';
|
||||
require_once 'includes/stats.class.php'; // Game entity statistics conversion
|
||||
require_once 'localization/lang.class.php';
|
||||
require_once 'includes/libs/DbSimple/Generic.php'; // Libraray: http://en.dklab.ru/lib/DbSimple (using variant: https://github.com/ivan1986/DbSimple/tree/master)
|
||||
require_once 'includes/database.class.php'; // wrap DBSimple
|
||||
require_once 'includes/utilities.php'; // helper functions
|
||||
require_once 'includes/config.class.php'; // Config holder
|
||||
require_once 'includes/user.class.php'; // Session handling (could be skipped for CLI context except for username and password validation used in account creation)
|
||||
|
||||
// todo: make everything below autoloaded
|
||||
require_once 'includes/stats.class.php'; // Game entity statistics conversion
|
||||
require_once 'includes/game.php'; // game related data & functions
|
||||
require_once 'includes/profiler.class.php'; // Profiler feature
|
||||
require_once 'includes/user.class.php'; // Session handling
|
||||
require_once 'includes/markup.class.php'; // manipulate markup text
|
||||
require_once 'includes/database.class.php'; // wrap DBSimple
|
||||
require_once 'includes/community.class.php'; // handle comments, screenshots and videos
|
||||
require_once 'includes/loot.class.php'; // build lv-tabs containing loot-information
|
||||
require_once 'includes/smartAI.class.php'; // TC: SmartAI system
|
||||
require_once 'includes/conditions.class.php'; // TC: Conditions system
|
||||
require_once 'localization/lang.class.php';
|
||||
require_once 'pages/genericPage.class.php';
|
||||
|
||||
// TC systems
|
||||
spl_autoload_register(function ($class)
|
||||
{
|
||||
switch($class)
|
||||
{
|
||||
case 'SmartAI':
|
||||
case 'SmartEvent':
|
||||
case 'SmartAction':
|
||||
case 'SmartTarget':
|
||||
require_once 'includes/components/SmartAI/SmartAI.class.php';
|
||||
require_once 'includes/components/SmartAI/SmartEvent.class.php';
|
||||
require_once 'includes/components/SmartAI/SmartAction.class.php';
|
||||
require_once 'includes/components/SmartAI/SmartTarget.class.php';
|
||||
break;
|
||||
case 'Conditions':
|
||||
require_once 'includes/components/Conditions/Conditions.class.php';
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
// autoload List-classes, associated filters and pages
|
||||
spl_autoload_register(function ($class) {
|
||||
spl_autoload_register(function ($class)
|
||||
{
|
||||
$class = strtolower(str_replace('ListFilter', 'List', $class));
|
||||
|
||||
if (class_exists($class)) // already registered
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -578,7 +578,7 @@ class QuestListFilter extends Filter
|
||||
|
||||
protected function cbQuestRelation($cr, $flags)
|
||||
{
|
||||
return match($cr[1])
|
||||
return match ($cr[1])
|
||||
{
|
||||
Type::NPC,
|
||||
Type::OBJECT,
|
||||
|
||||
Reference in New Issue
Block a user