Files
aowow/includes/conditions.class.php
Sarjuuk f861886fdf Misc/Fixup
* Conditions: loot rows initially have no 'id'
 * fixed building talent string for hunter pets (different talents can occupy the same row/col spot)
 * added keys loot cols on creature table
 * fixed trying to show itemset type for itemsets without type
 * fixed waypoint calculation when moving entity between floors
2024-06-02 21:15:29 +02:00

725 lines
37 KiB
PHP

<?php
if (!defined('AOWOW_REVISION'))
die('illegal access');
// TrinityCore - Condition System
class Conditions
{
// enum TypeID
private const TYPEID_OBJECT = 0;
private const TYPEID_ITEM = 1;
private const TYPEID_CONTAINER = 2;
private const TYPEID_UNIT = 3;
private const TYPEID_PLAYER = 4;
private const TYPEID_GAMEOBJECT = 5;
private const TYPEID_DYNAMICOBJECT = 6;
private const TYPEID_CORPSE = 7;
public const OP_E = 0; // ==
public const OP_GT = 1; // >
public const OP_LT = 2; // <
public const OP_GT_E = 3; // >=
public const OP_LT_E = 4; // <=
// Group, Entry, Id
public const SRC_NONE = 0; // null, null, null - use when adding external conditions
public const SRC_CREATURE_LOOT_TEMPLATE = 1; // tplEntry, itemId, null
public const SRC_DISENCHANT_LOOT_TEMPLATE = 2; // tplEntry, itemId, null
public const SRC_FISHING_LOOT_TEMPLATE = 3; // tplEntry, itemId, null
public const SRC_GAMEOBJECT_LOOT_TEMPLATE = 4; // tplEntry, itemId, null
public const SRC_ITEM_LOOT_TEMPLATE = 5; // tplEntry, itemId, null
public const SRC_MAIL_LOOT_TEMPLATE = 6; // tplEntry, itemId, null
public const SRC_MILLING_LOOT_TEMPLATE = 7; // tplEntry, itemId, null
public const SRC_PICKPOCKETING_LOOT_TEMPLATE = 8; // tplEntry, itemId, null
public const SRC_PROSPECTING_LOOT_TEMPLATE = 9; // tplEntry, itemId, null
public const SRC_REFERENCE_LOOT_TEMPLATE = 10; // tplEntry, itemId, null
public const SRC_SKINNING_LOOT_TEMPLATE = 11; // tplEntry, itemId, null
public const SRC_SPELL_LOOT_TEMPLATE = 12; // tplEntry, itemId, null
public const SRC_SPELL_IMPLICIT_TARGET = 13; // effectMask, spellId, null
public const SRC_GOSSIP_MENU = 14; // menuId, textId, null
public const SRC_GOSSIP_MENU_OPTION = 15; // menuId, optionId, null
public const SRC_CREATURE_TEMPLATE_VEHICLE = 16; // npcId, null, null
public const SRC_SPELL = 17; // null, spellId, null
public const SRC_SPELL_CLICK_EVENT = 18; // npcId, spellId, null
public const SRC_QUEST_AVAILABLE = 19; // null, questId, null
public const SRC_QUEST_SHOW_MARK = 20; // null, questId, null - ⚠️ unused as of 01.05.2024
public const SRC_VEHICLE_SPELL = 21; // npcId, spellId, null
public const SRC_SMART_EVENT = 22; // id, entryGuid, srcType
public const SRC_NPC_VENDOR = 23; // npcId, itemId, null
public const SRC_SPELL_PROC = 24; // null, spellId, null
// public const SRC_SPELL_TERRAIN_SWAP = 25; // - ❌ reserved for TC master
// public const SRC_SPELL_PHASE = 26; // - ❌ reserved for TC master
// public const SRC_SPELL_GRAVEYARD = 27; // - ❌ reserved for TC master
// public const SRC_SPELL_AREATRIGGER = 28; // - ❌ reserved for TC master
// public const SRC_SPELL_CONVERSATION_LINE = 29; // - ❌ reserved for TC master
public const SRC_AREATRIGGER_CLIENT = 30; // null, atId, null
// public const SRC_SPELL_TRAINER_SPELL = 31; // - ❌ reserved for TC master
// public const SRC_SPELL_OBJECT_VISIBILITY = 32; // - ❌ reserved for TC master
// public const SRC_SPELL_SPAWN_GROUP = 33; // - ❌ reserved for TC master
public const NONE = 0; // always true: NULL, NULL, NULL
public const AURA = 1; // aura is applied: spellId, effIdx, NULL
public const ITEM = 2; // owns item: itemId, count, includeBank?
public const ITEM_EQUIPPED = 3; // has item equipped: itemId, NULL, NULL
public const ZONEID = 4; // is in zone: areaId, NULL, NULL
public const REPUTATION_RANK = 5; // reputation status: factionId, rankMask, NULL
public const TEAM = 6; // is on team: teamId, NULL, NULL
public const SKILL = 7; // has skill: skillId, value, NULL
public const QUESTREWARDED = 8; // has finished quest: questId, NULL, NULL
public const QUESTTAKEN = 9; // has accepted quest: questId, NULL, NULL
public const DRUNKENSTATE = 10; // has drunken status: stateId, NULL, NULL
public const WORLD_STATE = 11; // world var == value: worldStateId, value, NULL
public const ACTIVE_EVENT = 12; // world event is active: eventId, NULL, NULL
public const INSTANCE_INFO = 13; // instance var == data: entry data, type
public const QUEST_NONE = 14; // never seen quest: questId, NULL, NULL
public const CHR_CLASS = 15; // belongs to classes: classMask, NULL, NULL
public const CHR_RACE = 16; // belongs to races: raceMask, NULL, NULL
public const ACHIEVEMENT = 17; // obtained achievement: achievementId, NULL, NULL
public const TITLE = 18; // obtained title: titleId, NULL, NULL
public const SPAWNMASK = 19; // spawnMask, NULL, NULL
public const GENDER = 20; // has gender: genderId, NULL, NULL
public const UNIT_STATE = 21; // unit has state: unitState, NULL, NULL
public const MAPID = 22; // is on map: mapId, NULL, NULL
public const AREAID = 23; // is in area: areaId, NULL, NULL
public const CREATURE_TYPE = 24; // creature is of type: creaturetypeId, NULL, NULL
public const SPELL = 25; // knows spell: spellId, NULL, NULL
public const PHASEMASK = 26; // is in phase: phaseMask, NULL, NULL
public const LEVEL = 27; // player level is..: level, comparator, NULL
public const QUEST_COMPLETE = 28; // has completed quest: questId, NULL, NULL
public const NEAR_CREATURE = 29; // is near creature: creatureId, dist, includeCorpse?
public const NEAR_GAMEOBJECT = 30; // is near gameObject: gameObjectId, dist, NULL
public const OBJECT_ENTRY_GUID = 31; // target is ???: objectType, id, guid
public const TYPE_MASK = 32; // target matches type: typeMask, NULL, NULL
public const RELATION_TO = 33; // Cond.Target, relation, NULL
public const REACTION_TO = 34; // Cond.Target, rankMask, NULL
public const DISTANCE_TO = 35; // distance to target Cond.Target, dist, comparator
public const ALIVE = 36; // target is alive: NULL, NULL, NULL
public const HP_VAL = 37; // targets absolute health: amount, comparator, NULL
public const HP_PCT = 38; // targets relative health: amount, comparator, NULL
public const REALM_ACHIEVEMENT = 39; // realmfirst was achieved: achievementId, NULL, NULL
public const IN_WATER = 40; // unit is swimming: NULL, NULL, NULL
// public const TERRAIN_SWAP = 41; // ❌ reserved for TC master
public const STAND_STATE = 42; // stateType, state, NULL
public const DAILY_QUEST_DONE = 43; // repeatable quest done: questId, NULL, NULL
public const CHARMED = 44; // unit is charmed: NULL, NULL, NULL
public const PET_TYPE = 45; // player has pet of type: petType, NULL, NULL
public const TAXI = 46; // player is on taxi: NULL, NULL, NULL
public const QUESTSTATE = 47; // questId, stateMask, NULL
public const QUEST_OBJECTIVE_PROGRESS = 48; // questId, objectiveIdx, count
public const DIFFICULTY_ID = 49; // map has difficulty id: difficulty, NULL, NULL
public const GAMEMASTER = 50; // player is GM: canBeGM?, NULL, NULL
// public const OBJECT_ENTRY_GUID_MASTER = 51; // ❌ reserved for TC master
// public const TYPE_MASK_MASTER = 52; // ❌ reserved for TC master
// public const BATTLE_PET_COUNT = 53; // ❌ reserved for TC master
// public const SCENARIO_STEP = 54; // ❌ reserved for TC master
// public const SCENE_IN_PROGRESS = 55; // ❌ reserved for TC master
// public const PLAYER_CONDITION = 56; // ❌ reserved for TC master
private const IDX_SRC_GROUP = 0;
private const IDX_SRC_ENTRY = 1;
private const IDX_SRC_ID = 2;
private const IDX_SRC_FN = 3;
private static $source = array( // [Group, Entry, Id]
self::SRC_NONE => [null, null, null, null],
self::SRC_CREATURE_LOOT_TEMPLATE => [Type::NPC, Type::ITEM, null, 'lootIdToNpc'],
self::SRC_DISENCHANT_LOOT_TEMPLATE => [Type::ITEM, Type::ITEM, null, 'disenchantIdToItem'],
self::SRC_FISHING_LOOT_TEMPLATE => [Type::ZONE, Type::ITEM, null, null],
self::SRC_GAMEOBJECT_LOOT_TEMPLATE => [Type::OBJECT, Type::ITEM, null, 'lootIdToGObject'],
self::SRC_ITEM_LOOT_TEMPLATE => [Type::ITEM, Type::ITEM, null, null],
self::SRC_MAIL_LOOT_TEMPLATE => [Type::QUEST, Type::ITEM, null, 'RewardTemplateToQuest'],
self::SRC_MILLING_LOOT_TEMPLATE => [Type::ITEM, Type::ITEM, null, null],
self::SRC_PICKPOCKETING_LOOT_TEMPLATE => [Type::NPC, Type::ITEM, null, 'PickpocketLootToNpc'],
self::SRC_PROSPECTING_LOOT_TEMPLATE => [Type::ITEM, Type::ITEM, null, null],
self::SRC_REFERENCE_LOOT_TEMPLATE => [null, Type::ITEM, null, null],
self::SRC_SKINNING_LOOT_TEMPLATE => [Type::NPC, Type::ITEM, null, 'SkinLootToNpc'],
self::SRC_SPELL_LOOT_TEMPLATE => [Type::SPELL, Type::ITEM, null, null],
self::SRC_SPELL_IMPLICIT_TARGET => [true, Type::SPELL, null, null],
self::SRC_GOSSIP_MENU => [true, true, null, null],
self::SRC_GOSSIP_MENU_OPTION => [true, true, null, null],
self::SRC_CREATURE_TEMPLATE_VEHICLE => [null, Type::NPC, null, null],
self::SRC_SPELL => [null, Type::SPELL, null, null],
self::SRC_SPELL_CLICK_EVENT => [Type::NPC, Type::SPELL, null, null],
self::SRC_QUEST_AVAILABLE => [null, Type::QUEST, null, null],
self::SRC_QUEST_SHOW_MARK => [null, Type::QUEST, null, null],
self::SRC_VEHICLE_SPELL => [Type::NPC, Type::SPELL, null, null],
self::SRC_SMART_EVENT => [true, true, true, null],
self::SRC_NPC_VENDOR => [Type::NPC, Type::ITEM, null, null],
self::SRC_SPELL_PROC => [null, Type::SPELL, null, null],
self::SRC_AREATRIGGER_CLIENT => [null, true, null, null]
);
private const IDX_CND_VAL1 = 0;
private const IDX_CND_VAL2 = 1;
private const IDX_CND_VAL3 = 2;
private const IDX_CND_FN = 3;
private static $conditions = array(// [Value1, Value2, Value3, handlerFn]
self::NONE => [null, null, null, null],
self::AURA => [Type::SPELL, null, null, null],
self::ITEM => [Type::ITEM, true, true, null],
self::ITEM_EQUIPPED => [Type::ITEM, null, null, null],
self::ZONEID => [Type::ZONE, null, null, null],
self::REPUTATION_RANK => [Type::FACTION, true, null, null],
self::TEAM => [true, null, null, 'factionToSide'],
self::SKILL => [Type::SKILL, true, null, null],
self::QUESTREWARDED => [Type::QUEST, null, null, null],
self::QUESTTAKEN => [Type::QUEST, null, null, null],
self::DRUNKENSTATE => [true, null, null, null],
self::WORLD_STATE => [true, true, null, null],
self::ACTIVE_EVENT => [Type::WORLDEVENT, null, null, null],
self::INSTANCE_INFO => [true, true, true, null],
self::QUEST_NONE => [Type::QUEST, null, null, null],
self::CHR_CLASS => [Type::CHR_CLASS, null, null, 'maskToBits'],
self::CHR_RACE => [Type::CHR_RACE, null, null, 'maskToBits'],
self::ACHIEVEMENT => [Type::ACHIEVEMENT, null, null, null],
self::TITLE => [Type::TITLE, null, null, null],
self::SPAWNMASK => [true, null, null, null],
self::GENDER => [true, null, null, null],
self::UNIT_STATE => [true, null, null, null],
self::MAPID => [true, true, null, 'mapToZone'],
self::AREAID => [Type::ZONE, null, null, null],
self::CREATURE_TYPE => [true, null, null, null],
self::SPELL => [Type::SPELL, null, null, null],
self::PHASEMASK => [true, null, null, null],
self::LEVEL => [true, true, null, null],
self::QUEST_COMPLETE => [Type::QUEST, null, null, null],
self::NEAR_CREATURE => [Type::NPC, true, true, null],
self::NEAR_GAMEOBJECT => [Type::OBJECT, true, true, null],
self::OBJECT_ENTRY_GUID => [true, true, true, 'typeidToId'],
self::TYPE_MASK => [true, null, null, null],
self::RELATION_TO => [true, true, null, null],
self::REACTION_TO => [true, true, null, null],
self::DISTANCE_TO => [true, true, true, null],
self::ALIVE => [null, null, null, null],
self::HP_VAL => [true, true, null, null],
self::HP_PCT => [true, true, null, null],
self::REALM_ACHIEVEMENT => [Type::ACHIEVEMENT, null, null, null],
self::IN_WATER => [null, null, null, null],
self::STAND_STATE => [true, true, null, null],
self::DAILY_QUEST_DONE => [Type::QUEST, null, null, null],
self::CHARMED => [null, null, null, null],
self::PET_TYPE => [true, null, null, null],
self::TAXI => [null, null, null, null],
self::QUESTSTATE => [Type::QUEST, true, null, null],
self::QUEST_OBJECTIVE_PROGRESS => [Type::QUEST, true, true, null],
self::DIFFICULTY_ID => [true, null, null, null],
self::GAMEMASTER => [true, null, null, null]
);
private $jsGlobals = [];
private $rows = [];
private $result = [];
private $resultExtra = [];
/******/
/* IN */
/******/
public function getBySourceEntry(int $entry, int ...$srcType) : bool
{
$this->rows = DB::World()->select(
'SELECT `SourceTypeOrReferenceId`, `SourceEntry`, `SourceGroup`, `SourceId`, `ElseGroup`,
`ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`
FROM conditions
WHERE `SourceTypeOrReferenceId` IN (?a) AND `SourceEntry` = ?d
ORDER BY `SourceTypeOrReferenceId`, `SourceEntry`, `SourceGroup`, `ElseGroup` ASC',
$srcType, $entry
);
return $this->fromSource();
}
public function getBySourceGroup(int $group, int ...$srcType) : bool
{
$this->rows = DB::World()->select(
'SELECT `SourceTypeOrReferenceId`, `SourceEntry`, `SourceGroup`, `SourceId`, `ElseGroup`,
`ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`
FROM conditions
WHERE `SourceTypeOrReferenceId` IN (?a) AND `SourceGroup` = ?d
ORDER BY `SourceTypeOrReferenceId`, `SourceEntry`, `SourceGroup`, `ElseGroup` ASC',
$srcType, $group
);
return $this->fromSource();
}
public function getByCondition(int $type, int $typeId/* , int ...$conditionIds */) : bool
{
$lookups = []; // can only be in val1 for now
foreach (self::$conditions as $cId => [$cVal1, , , ])
if ($type === $cVal1 /* && (!$conditionIds || in_array($cId, $conditionIds)) */ )
$lookups[] = sprintf("(c2.`ConditionTypeOrReference` = %d AND c2.`ConditionValue1` = %d)", $cId, $typeId);
if (!$lookups)
return false;
$this->rows = DB::World()->select(sprintf(
'SELECT c1.`SourceTypeOrReferenceId`, c1.`SourceEntry`, c1.`SourceGroup`, c1.`SourceId`, c1.`ElseGroup`,
c1.`ConditionTypeOrReference`, c1.`ConditionTarget`, c1.`ConditionValue1`, c1.`ConditionValue2`, c1.`ConditionValue3`, c1.`NegativeCondition`
FROM conditions c1
JOIN conditions c2 ON c1.SourceTypeOrReferenceId = c2.SourceTypeOrReferenceId AND c1.SourceEntry = c2.SourceEntry AND c1.SourceGroup = c2.SourceGroup AND c1.SourceId = c2.SourceId
WHERE %s
ORDER BY `SourceTypeOrReferenceId`, `SourceEntry`, `SourceGroup`, `ElseGroup` ASC'
, implode(' OR ', $lookups)));
return $this->fromSource();
}
public function addExternalCondition(int $srcType, string $groupKey, array $condition, bool $orGroup = false) : void
{
if (!isset(self::$source[$srcType]))
return;
[$cId, $cVal1, $cVal2, $cVal3] = array_pad($condition, 5, 0);
if (!isset(self::$conditions[abs($cId)]))
return;
while (substr_count($groupKey, ':') < 3)
$groupKey .= ':0'; // pad with missing srcEntry, SrcId, cndTarget to group key
if ($c = $this->prepareCondition($cId, $cVal1, $cVal2, $cVal3))
{
if ($orGroup)
$this->result[$srcType][$groupKey][] = [$c];
else if (!isset($this->result[$srcType][$groupKey][0]))
$this->result[$srcType][$groupKey][0] = [$c];
else
$this->result[$srcType][$groupKey][0][] = $c;
}
}
/*******/
/* OUT */
/*******/
public function toListviewTab(string $id = 'conditions', string $name = '') : array
{
if (!$this->result)
return [];
$out = [];
$nCnd = 0;
foreach ($this->result as $srcType => $srcData)
{
foreach ($srcData as $grpKey => $grpData)
{
if (!isset($this->resultExtra[$srcType][$grpKey]))
{
$nCnd++;
$out[$srcType][$grpKey] = $grpData;
}
else
{
$nCnd += count($this->resultExtra[$srcType][$grpKey]);
foreach ($this->resultExtra[$srcType][$grpKey] as $extraGrp)
$out[$srcType][$extraGrp] = $grpData;
}
}
}
$data = "<script type=\"text/javascript\">\n" .
" var markup = ConditionList.createTab(".Util::toJSON($out).");\n" .
" Markup.printHtml(markup, 'tab-".$id."', { allow: Markup.CLASS_STAFF })\n" .
"</script>";
$tab = array(
'data' => $data,
'id' => $id,
'name' => ($name ?: '$LANG.tab_conditions') . '+" ('.$nCnd.')"'
);
return [null, $tab];
}
public function toListviewColumn(array &$lvRows, ?array &$extraCols = [], int $srcEntry = 0) : bool
{
if (!$this->result)
return false;
$success = false;
foreach ($lvRows as $key => &$row)
{
$key = ($row['id'] ?? $key).':'.$srcEntry; // loot rows don't have an 'id' while being generated, but they have a usable $key
while (substr_count($key, ':') < 3) // pad with missing srcEntry, SrcId, cndTarget to group key
$key .= ':0';
foreach ($this->result as $cndData)
{
if (empty($cndData[$key]))
continue;
$row['condition'][self::SRC_NONE][$key] = $cndData[$key];
$success = true;
}
}
if ($success)
$extraCols[] = '$Listview.extraCols.condition';
return $success;
}
public function getJsGlobals() : array
{
return $this->jsGlobals;
}
/*********/
/* Other */
/*********/
public static function lootTableToConditionSource(string $lootTable) : int
{
switch ($lootTable)
{
case LOOT_FISHING: return self::SRC_FISHING_LOOT_TEMPLATE;
case LOOT_CREATURE: return self::SRC_CREATURE_LOOT_TEMPLATE;
case LOOT_GAMEOBJECT: return self::SRC_GAMEOBJECT_LOOT_TEMPLATE;
case LOOT_ITEM: return self::SRC_ITEM_LOOT_TEMPLATE;
case LOOT_DISENCHANT: return self::SRC_DISENCHANT_LOOT_TEMPLATE;
case LOOT_PROSPECTING: return self::SRC_PROSPECTING_LOOT_TEMPLATE;
case LOOT_MILLING: return self::SRC_MILLING_LOOT_TEMPLATE;
case LOOT_PICKPOCKET: return self::SRC_PICKPOCKETING_LOOT_TEMPLATE;
case LOOT_SKINNING: return self::SRC_SKINNING_LOOT_TEMPLATE;
case LOOT_MAIL: return self::SRC_MAIL_LOOT_TEMPLATE;
case LOOT_SPELL: return self::SRC_SPELL_LOOT_TEMPLATE;
case LOOT_REFERENCE: return self::SRC_REFERENCE_LOOT_TEMPLATE;
default: return self::SRC_NONE;
}
}
public static function extendListviewRow(array &$lvRow, int $srcType, int $groupKey, array $condition) : bool
{
if (!isset(self::$source[$srcType]))
return false;
[$cId, $cVal1, $cVal2, $cVal3] = array_pad($condition, 5, 0);
if (!isset(self::$conditions[abs($cId)]))
return false;
while (substr_count($groupKey, ':') < 3)
$groupKey .= ':0'; // pad with missing srcEntry, SrcId, cndTarget to group key
if ($c = (new self())->prepareCondition($cId, $cVal1, $cVal2, $cVal3))
$lvRow['condition'][$srcType][$groupKey][] = [$c];
return true;
}
private function fromSource() : bool
{
// itr over rows and prep data
if (!$this->rows)
return !empty($this->result); // respect previously added externalCnd
foreach ($this->rows as $r)
{
if (!isset(self::$source[$r['SourceTypeOrReferenceId']]))
{
trigger_error('Conditions: skipping condition with unknown SourceTypeOrReferenceId #'.$r['SourceTypeOrReferenceId'], E_USER_WARNING);
continue;
}
if (!isset(self::$conditions[$r['ConditionTypeOrReference']]))
{
trigger_error('Conditions: skipping condition with unknown ConditionTypeOrReference #'.$r['ConditionTypeOrReference'], E_USER_WARNING);
continue;
}
[$sType, $sGroup, $sEntry, $sId, $cTarget] = $this->prepareSource($r['SourceTypeOrReferenceId'], $r['SourceGroup'], $r['SourceEntry'], $r['SourceId'], $r['ConditionTarget']);
if ($sType === null)
continue;
$cnd = $this->prepareCondition(
$r['NegativeCondition'] ? -$r['ConditionTypeOrReference'] : $r['ConditionTypeOrReference'],
$r['ConditionValue1'],
$r['ConditionValue2'],
$r['ConditionValue3']
);
if (!$cnd)
continue;
$group = $sGroup . ':' . $sEntry . ':' . $sId . ':' . $cTarget;
$this->result[$r['SourceTypeOrReferenceId']] [$group] [$r['ElseGroup']] [] = $cnd;
}
return true;
}
private function prepareSource(int $sType, int $sGroup, int $sEntry, int $sId, int $cTarget) : array
{
// only one entry in array expected
if ($fn = self::$source[$sType][self::IDX_SRC_FN])
if (!$this->$fn($sType, $sGroup, $sEntry, $sId, $cTarget))
return [null, null, null, null, null];
[$grp, $entry, $id, $_] = self::$source[$sType];
if (is_int($grp))
$this->jsGlobals[$grp][$sGroup] = $sGroup;
if (is_int($entry))
$this->jsGlobals[$entry][$sEntry] = $sEntry;
// Note: sourceId currently has no typed content
// if (is_int($id))
// $this->jsGlobals[$id][$sId] = $sId;
// more checks? not all sources can retarget
$cTarget = min(1, max(0, $cTarget));
return [$sType, $sGroup, $sEntry, $sId, $cTarget];
}
private function prepareCondition($cId, $cVal1, $cVal2, $cVal3) : array
{
if ($fn = self::$conditions[abs($cId)][self::IDX_CND_FN])
if (!$this->$fn(abs($cId), $cVal1, $cVal2, $cVal3))
return [];
$result = [$cId];
for ($i = 0; $i < 3; $i++)
{
$field = self::$conditions[abs($cId)][$i];
if (is_int($field))
$this->jsGlobals[$field][${'cVal'.($i+1)}] = ${'cVal'.($i+1)};
if ($field)
$result[] = ${'cVal'.($i+1)}; // variable amount of condition values
}
return $result;
}
private function factionToSide($cId, &$cVal1, $cVal2, $cVal3) : bool
{
if ($cVal1 == 469)
$cVal1 = SIDE_ALLIANCE;
else if ($cVal1 == 67)
$cVal1 = SIDE_HORDE;
else
$cVal1 = SIDE_BOTH;
return true;
}
private function mapToZone($cId, &$cVal1, &$cVal2, $cVal3) : bool
{
// use g_zone_categories id
if ($cVal1 == 530) // outland
$cVal1 = 8;
else if ($cVal1 == 571) // northrend
$cVal1 = 10;
else if ($cVal1 == 0 || $cVal1 == 1) // eastern kingdoms / kalimdor
; // cVal alrady correct - NOP
else if ($id = DB::Aowow()->selectCell('SELECT `id` FROM ?_zones WHERE `mapId` = ?d AND `parentArea` = 0 AND (`cuFlags` & ?d) = 0', $cVal1, CUSTOM_EXCLUDE_FOR_LISTVIEW))
{
// remap for instanced area - do not use List (pointless overhead)
$this->jsGlobals[Type::ZONE][$id] = $id;
$cVal2 = $id;
$cVal1 = 0;
}
else
{
trigger_error('Conditions - CONDITION_MAPID has invalid mapId #'.$cVal1, E_USER_WARNING);
return false;
}
return true;
}
private function maskToBits($cId, &$cVal1, $cVal2, $cVal3) : bool
{
if ($cId == self::CHR_CLASS)
{
$cVal1 &= CLASS_MASK_ALL;
foreach (Util::mask2bits($cVal1, 1) as $cId)
$this->jsGlobals[Type::CHR_CLASS][$cId] = $cId;
}
if ($cId == self::CHR_RACE)
{
$cVal1 &= RACE_MASK_ALL;
foreach (Util::mask2bits($cVal1, 1) as $rId)
$this->jsGlobals[Type::CHR_RACE][$rId] = $rId;
}
return true;
}
private function typeidToId($cId, $cVal1, &$cVal2, &$cVal3) : bool
{
if ($cVal1 == self::TYPEID_UNIT)
{
if ($cVal3 && ($_ = DB::Aowow()->selectCell('SELECT `typeId` FROM ?_spawns WHERE `type` = ?d AND `guid` = ?d', Type::NPC, $cVal3)))
$cVal2 = intVal($_);
if ($cVal2)
$this->jsGlobals[Type::NPC][$cVal2] = $cVal2;
}
else if ($cVal1 == self::TYPEID_GAMEOBJECT)
{
if ($cVal3 && ($_ = DB::Aowow()->selectCell('SELECT `typeId` FROM ?_spawns WHERE `type` = ?d AND `guid` = ?d', Type::OBJECT, $cVal3)))
$cVal2 = intVal($_);
if ($cVal2)
$this->jsGlobals[Type::OBJECT][$cVal2] = $cVal2;
}
else // Player or Corpse .. no guid
$cVal2 = $cVal3 = 0;
// maybe prepare other types?
return true;
}
private function lootIdToNpc(int $sType, int $sGroup, int $sEntry, int $sId, int $cTarget) : bool
{
if (!$sGroup)
{
trigger_error('Conditions::lootToNpc - skipping reference to creature_loot_template entry 0', E_USER_WARNING);
return false;
}
if ($npcs = DB::Aowow()->selectCol('SELECT `id` FROM ?_creature WHERE `lootId` = ?d', $sGroup))
{
$group = $sGroup . ':' . $sEntry . ':' . $sId . ':' . $cTarget;
foreach ($npcs as $npcId)
{
$this->jsGlobals[Type::NPC][$npcId] = $npcId;
$this->resultExtra[$sType][$group][] = $npcId . ':' . $sEntry . ':' . $sId . ':' . $cTarget;
}
return true;
}
trigger_error('Conditions::lootToNpc - creature_loot_template #'.$sGroup.' unreferenced?', E_USER_WARNING);
return false;
}
private function disenchantIdToItem(int $sType, int $sGroup, int $sEntry, int $sId, int $cTarget) : bool
{
if (!$sGroup)
{
trigger_error('Conditions::disenchantIdToItem - skipping reference to disenchant_loot_template entry 0', E_USER_WARNING);
return false;
}
if ($items = DB::Aowow()->selectCol('SELECT `id` FROM ?_items WHERE `disenchantId` = ?d', $sGroup))
{
$group = $sGroup . ':' . $sEntry . ':' . $sId . ':' . $cTarget;
foreach ($items as $itemId)
{
$this->jsGlobals[Type::ITEM][$itemId] = $itemId;
$this->resultExtra[$sType][$group][] = $itemId . ':' . $sEntry . ':' . $sId . ':' . $cTarget;
}
return true;
}
trigger_error('Conditions::disenchantIdToItem - disenchant_loot_template #'.$sGroup.' unreferenced?', E_USER_WARNING);
return false;
}
private function lootIdToGObject(int $sType, int $sGroup, int $sEntry, int $sId, int $cTarget) : bool
{
if (!$sGroup)
{
trigger_error('Conditions::lootIdToGObject - skipping reference to gameobject_loot_template entry 0', E_USER_WARNING);
return false;
}
if ($gos = DB::Aowow()->selectCol('SELECT `id` FROM ?_objects WHERE `lootId` = ?d', $sGroup))
{
$group = $sGroup . ':' . $sEntry . ':' . $sId . ':' . $cTarget;
foreach ($gos as $goId)
{
$this->jsGlobals[Type::OBJECT][$goId] = $goId;
$this->resultExtra[$sType][$group][] = $goId . ':' . $sEntry . ':' . $sId . ':' . $cTarget;
}
return true;
}
trigger_error('Conditions::lootIdToGObject - gameobject_loot_template #'.$sGroup.' unreferenced?', E_USER_WARNING);
return false;
}
private function RewardTemplateToQuest(int $sType, int $sGroup, int $sEntry, int $sId, int $cTarget) : bool
{
if (!$sGroup)
{
trigger_error('Conditions::RewardTemplateToQuest - skipping reference to mail_loot_template entry 0', E_USER_WARNING);
return false;
}
if ($quests = DB::Aowow()->selectCol('SELECT `id` FROM ?_quests WHERE `rewardMailTemplateId` = ?d', $sGroup))
{
$group = $sGroup . ':' . $sEntry . ':' . $sId . ':' . $cTarget;
foreach ($quests as $questId)
{
$this->jsGlobals[Type::QUEST][$questId] = $questId;
$this->resultExtra[$sType][$group][] = $questId . ':' . $sEntry . ':' . $sId . ':' . $cTarget;
}
return true;
}
trigger_error('Conditions::RewardTemplateToQuest - mail_loot_template #'.$sGroup.' unreferenced?', E_USER_WARNING);
return false;
}
private function PickpocketLootToNpc(int $sType, int $sGroup, int $sEntry, int $sId, int $cTarget) : bool
{
if (!$sGroup)
{
trigger_error('Conditions::PickpocketLootToNpc - skipping reference to pickpocketing_loot_template entry 0', E_USER_WARNING);
return false;
}
if ($npcs = DB::Aowow()->selectCol('SELECT `id` FROM ?_creature WHERE `pickpocketLootId` = ?d', $sGroup))
{
$group = $sGroup . ':' . $sEntry . ':' . $sId . ':' . $cTarget;
foreach ($npcs as $npcId)
{
$this->jsGlobals[Type::NPC][$npcId] = $npcId;
$this->resultExtra[$sType][$group][] = $npcId . ':' . $sEntry . ':' . $sId . ':' . $cTarget;
}
return true;
}
trigger_error('Conditions::PickpocketLootToNpc - pickpocketing_loot_template #'.$sGroup.' unreferenced?', E_USER_WARNING);
return false;
}
private function SkinLootToNpc(int $sType, int $sGroup, int $sEntry, int $sId, int $cTarget) : bool
{
if (!$sGroup)
{
trigger_error('Conditions::SkinLootToNpc - skipping reference to skinning_loot_template entry 0', E_USER_WARNING);
return false;
}
if ($npcs = DB::Aowow()->selectCol('SELECT `id` FROM ?_creature WHERE `skinLootId` = ?d', $sGroup))
{
$group = $sGroup . ':' . $sEntry . ':' . $sId . ':' . $cTarget;
foreach ($npcs as $npcId)
{
$this->jsGlobals[Type::NPC][$npcId] = $npcId;
$this->resultExtra[$sType][$group][] = $npcId . ':' . $sEntry . ':' . $sId . ':' . $cTarget;
}
return true;
}
trigger_error('Conditions::SkinLootToNpc - skinning_loot_template #'.$sGroup.' unreferenced?', E_USER_WARNING);
return false;
}
}
?>