mirror of
https://github.com/Sarjuuk/aowow.git
synced 2025-11-29 15:58:16 +08:00
Map/Spawns
* move areatrigger teleport endpoints and instance entrance points to spawns. This makes them editable like spawn points. * since instance entrances aren't shown on maps they are moved through the admin menu on the instances page. * rewrote spawns SetupScript. Individual groups can now be recalculated separately.
This commit is contained in:
@@ -383,7 +383,7 @@ class AjaxAdmin extends AjaxHandler
|
||||
$area = $this->_get['area'];
|
||||
$floor = $this->_get['floor'];
|
||||
|
||||
if (!in_array($type, [Type::NPC, Type::OBJECT, Type::SOUND, Type::AREATRIGGER]))
|
||||
if (!in_array($type, [Type::NPC, Type::OBJECT, Type::SOUND, Type::AREATRIGGER, Type::ZONE]))
|
||||
return '-3';
|
||||
|
||||
DB::Aowow()->query('REPLACE INTO ?_spawns_override VALUES (?d, ?d, ?d, ?d, ?d)', $type, $guid, $area, $floor, AOWOW_REVISION);
|
||||
|
||||
@@ -591,14 +591,16 @@ trait spawnHelper
|
||||
return;
|
||||
|
||||
if (User::isInGroup(U_GROUP_MODERATOR))
|
||||
if ($guids = array_filter(array_column($spawns, 'guid'), function ($x) { return $x > 0; }))
|
||||
if ($guids = array_column(array_filter($spawns, function ($x) { return $x['guid'] > 0 || $x['type'] != Type::NPC; }), 'guid'))
|
||||
$worldPos = Game::getWorldPosForGUID(self::$type, ...$guids);
|
||||
|
||||
foreach ($spawns as $s)
|
||||
{
|
||||
$isAccessory = $s['guid'] < 0 && $s['type'] == Type::NPC;
|
||||
|
||||
// check, if we can attach waypoints to creature
|
||||
// we will get a nice clusterfuck of dots if we do this for more GUIDs, than we have colors though
|
||||
if (count($spawns) < 6 && self::$type == Type::NPC)
|
||||
if (count($spawns) < 6 && $s['type'] == Type::NPC)
|
||||
{
|
||||
if ($wPoints = DB::Aowow()->select('SELECT * FROM ?_creature_waypoints WHERE creatureOrPath = ?d AND floor = ?d', $s['pathId'] ? -$s['pathId'] : $this->id, $s['floor']))
|
||||
{
|
||||
@@ -641,7 +643,10 @@ trait spawnHelper
|
||||
|
||||
if (User::isInGroup(U_GROUP_STAFF))
|
||||
{
|
||||
$info[0] = $s['guid'] < 0 ? 'Vehicle Accessory' : 'GUID'.Lang::main('colon').$s['guid'];
|
||||
if ($isAccessory)
|
||||
$info[0] = 'Vehicle Accessory';
|
||||
else if ($s['guid'] > 0 && ($s['type'] == Type::NPC || $s['type'] == Type::OBJECT))
|
||||
$info[0] = 'GUID'.Lang::main('colon').$s['guid'];
|
||||
|
||||
if ($s['phaseMask'] > 1 && ($s['phaseMask'] & 0xFFFF) != 0xFFFF)
|
||||
$info[2] = Lang::game('phases').Lang::main('colon').Util::asHex($s['phaseMask']);
|
||||
@@ -658,56 +663,27 @@ trait spawnHelper
|
||||
$info[4] = Lang::game('mode').Lang::main('colon').implode(', ', $_);
|
||||
}
|
||||
|
||||
if (self::$type == Type::AREATRIGGER)
|
||||
if ($s['type'] == Type::AREATRIGGER)
|
||||
{
|
||||
$o = Util::O2Deg($this->getField('orientation'));
|
||||
$info[5] = 'Orientation'.Lang::main('colon').$o[0].'° ('.$o[1].')';
|
||||
// teleporter endpoint
|
||||
if ($s['guid'] < 0)
|
||||
{
|
||||
$opts['type'] = 4;
|
||||
$info[5] = 'Teleport Destination';
|
||||
}
|
||||
else
|
||||
{
|
||||
$o = Util::O2Deg($this->getField('orientation'));
|
||||
$info[5] = 'Orientation'.Lang::main('colon').$o[0].'° ('.$o[1].')';
|
||||
}
|
||||
}
|
||||
|
||||
// guid < 0 are vehicle accessories. those are moved by moving the vehicle
|
||||
if (User::isInGroup(U_GROUP_MODERATOR) && $worldPos && $s['guid'] > 0 && isset($worldPos[$s['guid']]))
|
||||
{
|
||||
if ($points = Game::worldPosToZonePos($worldPos[$s['guid']]['mapId'], $worldPos[$s['guid']]['posX'], $worldPos[$s['guid']]['posY']))
|
||||
{
|
||||
$floors = [];
|
||||
foreach ($points as $p)
|
||||
{
|
||||
if ($p['multifloor'])
|
||||
$floors[$p['areaId']][] = $p['floor'];
|
||||
if (User::isInGroup(U_GROUP_MODERATOR) && $worldPos && !$isAccessory && isset($worldPos[$s['guid']]))
|
||||
$menu = Util::buildPosFixMenu($worldPos[$s['guid']]['mapId'], $worldPos[$s['guid']]['posX'], $worldPos[$s['guid']]['posY'], $s['type'], $s['guid'], $s['areaId'], $s['floor']);
|
||||
|
||||
if (isset($menu[$p['areaId']]))
|
||||
continue;
|
||||
else if ($p['areaId'] == $s['areaId'])
|
||||
$menu[$p['areaId']] = [$p['areaId'], '$g_zones['.$p['areaId'].']', '', null, ['class' => 'checked q0']];
|
||||
else
|
||||
$menu[$p['areaId']] = [$p['areaId'], '$g_zones['.$p['areaId'].']', '$spawnposfix.bind(null, '.self::$type.', '.$s['guid'].', '.$p['areaId'].', 0)', null, null];
|
||||
}
|
||||
|
||||
foreach ($floors as $area => $f)
|
||||
{
|
||||
$menu[$area][2] = '';
|
||||
$menu[$area][3] = [];
|
||||
if ($menu[$area][4])
|
||||
$menu[$area][4]['class'] = 'checked';
|
||||
|
||||
foreach ($f as $n)
|
||||
{
|
||||
if ($n == $s['floor'])
|
||||
$menu[$area][3][] = [$n, '$g_zone_areas['.$area.']['.($n - 1).']', '', null, ['class' => 'checked q0']];
|
||||
else
|
||||
$menu[$area][3][] = [$n, '$g_zone_areas['.$area.']['.($n - 1).']', '$spawnposfix.bind(null, '.self::$type.', '.$s['guid'].', '.$area.', '.$n.')'];
|
||||
}
|
||||
}
|
||||
|
||||
$menu = array_values($menu);
|
||||
}
|
||||
|
||||
if ($menu)
|
||||
{
|
||||
$footer = '<br /><span class="q2">Click to move displayed spawn point</span>';
|
||||
array_unshift($menu, [null, "Move to..."]);
|
||||
}
|
||||
}
|
||||
if ($menu)
|
||||
$footer = '<br /><span class="q2">Click to move pin</span>';
|
||||
}
|
||||
|
||||
if ($info)
|
||||
|
||||
@@ -257,6 +257,13 @@ define('GUIDE_STATUS_ARCHIVED', 5);
|
||||
|
||||
define('DEFAULT_ICON', 'inv_misc_questionmark');
|
||||
|
||||
define('MENU_IDX_ID', 0); // ID: A number or string; null makes the menu item a separator
|
||||
define('MENU_IDX_NAME', 1); // Name: A string
|
||||
define('MENU_IDX_URL', 2); // URL: A string for the URL, or a function to call when the menu item is clicked
|
||||
define('MENU_IDX_SUB', 3); // Submenu: Child menu
|
||||
define('MENU_IDX_OPT', 4); // Options: JSON array with additional options
|
||||
|
||||
|
||||
/*
|
||||
* Game
|
||||
*/
|
||||
|
||||
@@ -311,16 +311,27 @@ class Game
|
||||
switch ($type)
|
||||
{
|
||||
case Type::NPC:
|
||||
$result = DB::World()->select('SELECT `guid` AS ARRAY_KEY, `id`, `map` AS `mapId`, `position_x` AS `posX`, `position_y` AS `posY` FROM creature WHERE `guid` IN (?a)', $guids);
|
||||
$result = DB::World()->select('SELECT `guid` AS ARRAY_KEY, `id`, `map` AS `mapId`, `position_x` AS `posX`, `position_y` AS `posY` FROM creature WHERE `guid` IN (?a)', $guids);
|
||||
break;
|
||||
case Type::OBJECT:
|
||||
$result = DB::World()->select('SELECT `guid` AS ARRAY_KEY, `id`, `map` AS `mapId`, `position_x` AS `posX`, `position_y` AS `posY` FROM gameobject WHERE `guid` IN (?a)', $guids);
|
||||
$result = DB::World()->select('SELECT `guid` AS ARRAY_KEY, `id`, `map` AS `mapId`, `position_x` AS `posX`, `position_y` AS `posY` FROM gameobject WHERE `guid` IN (?a)', $guids);
|
||||
break;
|
||||
case Type::SOUND:
|
||||
$result = DB::AoWoW()->select('SELECT `id` AS ARRAY_KEY, `soundId` AS `id`, `mapId`, `posX`, `posY` FROM ?_soundemitters WHERE `id` IN (?a)', $guids);
|
||||
$result = DB::AoWoW()->select('SELECT `id` AS ARRAY_KEY, `soundId` AS `id`, `mapId`, `posX`, `posY` FROM ?_soundemitters WHERE `id` IN (?a)', $guids);
|
||||
break;
|
||||
case Type::ZONE:
|
||||
$result = DB::Aowow()->select('SELECT -`id` AS ARRAY_KEY, `id`, `parentMapId` AS `mapId`, `parentX` AS `posX`, `parentY` AS `posY` FROM ?_zones WHERE -`id` IN (?a)', $guids);
|
||||
break;
|
||||
case Type::AREATRIGGER:
|
||||
$result = DB::AoWoW()->select('SELECT `id` AS ARRAY_KEY, `id`, `mapId`, `posX`, `posY` FROM ?_areatrigger WHERE `id` IN (?a)', $guids);
|
||||
$result = [];
|
||||
if ($base = array_filter($guids, function ($x) { return $x > 0; }))
|
||||
$result = array_replace($result, DB::AoWoW()->select('SELECT `id` AS ARRAY_KEY, `id`, `mapId`, `posX`, `posY` FROM ?_areatrigger WHERE `id` IN (?a)', $base));
|
||||
if ($endpoints = array_filter($guids, function ($x) { return $x < 0; }))
|
||||
$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
|
||||
));
|
||||
break;
|
||||
default:
|
||||
trigger_error('Game::getWorldPosForGUID - instanced with unsupported TYPE #'.$type, E_USER_WARNING);
|
||||
|
||||
@@ -140,6 +140,7 @@ abstract class CLI
|
||||
private const CHR_ESC = 27;
|
||||
private const CHR_BACKSPACE = 127;
|
||||
|
||||
public const LOG_NONE = -1;
|
||||
public const LOG_BLANK = 0;
|
||||
public const LOG_ERROR = 1;
|
||||
public const LOG_WARN = 2;
|
||||
@@ -190,13 +191,13 @@ abstract class CLI
|
||||
}
|
||||
|
||||
if ($i || $headless)
|
||||
self::write(' '.implode(' ' . self::tblDelim(' ') . ' ', $row), -1, $timestamp);
|
||||
self::write(' '.implode(' ' . self::tblDelim(' ') . ' ', $row), CLI::LOG_NONE, $timestamp);
|
||||
else
|
||||
self::write(self::tblHead(' '.implode(' ', $row)), -1, $timestamp);
|
||||
self::write(self::tblHead(' '.implode(' ', $row)), CLI::LOG_NONE, $timestamp);
|
||||
}
|
||||
|
||||
if (!$headless)
|
||||
self::write(self::tblHead(str_pad('', array_sum($pads) + count($pads) * 3 - 2)), -1, $timestamp);
|
||||
self::write(self::tblHead(str_pad('', array_sum($pads) + count($pads) * 3 - 2)), CLI::LOG_NONE, $timestamp);
|
||||
|
||||
self::write();
|
||||
}
|
||||
@@ -1576,7 +1577,7 @@ abstract class Util
|
||||
}
|
||||
|
||||
// orientation is 2*M_PI for a full circle, increasing counterclockwise
|
||||
static function O2Deg($o)
|
||||
public static function O2Deg($o)
|
||||
{
|
||||
// orientation values can exceed boundaries (for whatever reason)
|
||||
while ($o < 0)
|
||||
@@ -1609,7 +1610,7 @@ abstract class Util
|
||||
return [(int)$deg, $desc];
|
||||
}
|
||||
|
||||
static function mask2bits(int $bitmask, int $offset = 0) : array
|
||||
public static function mask2bits(int $bitmask, int $offset = 0) : array
|
||||
{
|
||||
$bits = [];
|
||||
$i = 0;
|
||||
@@ -1625,6 +1626,46 @@ abstract class Util
|
||||
|
||||
return $bits;
|
||||
}
|
||||
|
||||
public static function buildPosFixMenu(int $mapId, float $posX, float $posY, int $type, int $guid, int $parentArea = 0, int $parentFloor = 0) : array
|
||||
{
|
||||
$points = Game::worldPosToZonePos($mapId, $posX, $posY);
|
||||
if (!$points || count($points) < 2)
|
||||
return [];
|
||||
|
||||
$floors = [];
|
||||
$menu = [[null, "Move Location to..."]];
|
||||
foreach ($points as $p)
|
||||
{
|
||||
if ($p['multifloor'])
|
||||
$floors[$p['areaId']][] = $p['floor'];
|
||||
|
||||
if (isset($menu[$p['areaId']]))
|
||||
continue;
|
||||
else if ($p['areaId'] == $parentArea)
|
||||
$menu[$p['areaId']] = [$p['areaId'], '$g_zones['.$p['areaId'].']', '', null, ['class' => 'checked q0']];
|
||||
else
|
||||
$menu[$p['areaId']] = [$p['areaId'], '$g_zones['.$p['areaId'].']', '$spawnposfix.bind(null, '.$type.', '.$guid.', '.$p['areaId'].', 0)', null, null];
|
||||
}
|
||||
|
||||
foreach ($floors as $area => $f)
|
||||
{
|
||||
$menu[$area][MENU_IDX_URL] = null;
|
||||
$menu[$area][MENU_IDX_SUB] = [];
|
||||
if ($menu[$area][MENU_IDX_OPT])
|
||||
$menu[$area][MENU_IDX_OPT]['class'] = 'checked';
|
||||
|
||||
foreach ($f as $n)
|
||||
{
|
||||
if ($n == $parentFloor)
|
||||
$menu[$area][MENU_IDX_SUB][] = [$n, '$g_zone_areas['.$area.']['.($n - 1).']', '', null, ['class' => 'checked q0']];
|
||||
else
|
||||
$menu[$area][MENU_IDX_SUB][] = [$n, '$g_zone_areas['.$area.']['.($n - 1).']', '$spawnposfix.bind(null, '.$type.', '.$guid.', '.$area.', '.$n.')'];
|
||||
}
|
||||
}
|
||||
|
||||
return array_values($menu);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -58,36 +58,7 @@ class AreaTriggerPage extends GenericPage
|
||||
$map = null;
|
||||
if ($spawns = $this->subject->getSpawns(SPAWNINFO_FULL))
|
||||
{
|
||||
$ta = $this->subject->getField('teleportA');
|
||||
$tf = $this->subject->getField('teleportF');
|
||||
$tx = $this->subject->getField('teleportX');
|
||||
$ty = $this->subject->getField('teleportY');
|
||||
$to = $this->subject->getField('teleportO');
|
||||
|
||||
// add teleport target
|
||||
if ($ta && $tx && $ty)
|
||||
{
|
||||
$o = Util::O2Deg($to);
|
||||
$endPoint = array($tx, $ty, array(
|
||||
'type' => 4,
|
||||
'tooltip' => array(
|
||||
'Teleport Destination' => array(
|
||||
'info' => ['Orientation'.Lang::main('colon').$o[0].'° ('.$o[1].')']
|
||||
)
|
||||
)
|
||||
));
|
||||
|
||||
if (isset($spawns[$ta][$tf]))
|
||||
$spawns[$ta][$tf]['coords'][] = $endPoint;
|
||||
else
|
||||
$spawns[$ta][$tf]['coords'] = [$endPoint];
|
||||
}
|
||||
|
||||
$map = array(
|
||||
'data' => ['parent' => 'mapper-generic'],
|
||||
'mapperData' => &$spawns
|
||||
);
|
||||
|
||||
$map = ['data' => ['parent' => 'mapper-generic'], 'mapperData' => &$spawns];
|
||||
foreach ($spawns as $areaId => &$areaData)
|
||||
$map['extra'][$areaId] = ZoneList::getName($areaId);
|
||||
}
|
||||
|
||||
@@ -113,21 +113,19 @@ class ZonePage extends GenericPage
|
||||
}
|
||||
|
||||
// Instances
|
||||
if ($_ = DB::Aowow()->selectCol('SELECT `id` FROM ?_zones WHERE `parentAreaId` = ?d AND (`cuFlags` & ?d) = 0', $this->typeId, CUSTOM_EXCLUDE_FOR_LISTVIEW))
|
||||
if ($_ = DB::Aowow()->selectCol('SELECT `typeId` FROM ?_spawns WHERE `type`= ?d AND `areaId` = ?d ', Type::ZONE, $this->typeId))
|
||||
{
|
||||
$this->extendGlobalIds(Type::ZONE, ...$_);
|
||||
$infobox[] = Lang::maps('Instances').Lang::main('colon')."\n[zone=".implode("], \n[zone=", $_).']';
|
||||
}
|
||||
|
||||
// location (if instance)
|
||||
if ($pa = $this->subject->getField('parentAreaId'))
|
||||
if ($pa = DB::Aowow()->selectRow('SELECT `areaId`, `posX`, `posY`, `floor` FROM ?_spawns WHERE `type`= ?d AND `typeId` = ?d ', Type::ZONE, $this->typeId))
|
||||
{
|
||||
$paO = new ZoneList(array(['id', $pa]));
|
||||
if (!$paO->error)
|
||||
{
|
||||
$pins = str_pad($this->subject->getField('parentX') * 10, 3, '0', STR_PAD_LEFT) . str_pad($this->subject->getField('parentY') * 10, 3, '0', STR_PAD_LEFT);
|
||||
$infobox[] = Lang::zone('location').Lang::main('colon').'[lightbox=map zone='.$pa.' pins='.$pins.']'.$paO->getField('name', true).'[/lightbox]';
|
||||
}
|
||||
$this->addMoveLocationMenu($pa['areaId'], $pa['floor']);
|
||||
|
||||
$pins = str_pad($pa['posX'] * 10, 3, '0', STR_PAD_LEFT) . str_pad($pa['posY'] * 10, 3, '0', STR_PAD_LEFT);
|
||||
$infobox[] = Lang::zone('location').Lang::main('colon').'[lightbox=map zone='.$pa['areaId'].' '.($pa['floor'] > 1 ? 'floor='.--$pa['floor'] : '').' pins='.$pins.']'.ZoneList::getName($pa['areaId']).'[/lightbox]';
|
||||
}
|
||||
|
||||
/* has to be defined in an article, i think
|
||||
@@ -413,6 +411,9 @@ class ZonePage extends GenericPage
|
||||
|
||||
foreach ($aSpawns as $spawn)
|
||||
{
|
||||
if ($spawn['guid'] < 0) // skip teleporter endpoints
|
||||
continue;
|
||||
|
||||
$tpl = $atSpawns->getEntry($spawn['typeId']);
|
||||
if (!$tpl)
|
||||
continue;
|
||||
@@ -423,7 +424,7 @@ class ZonePage extends GenericPage
|
||||
'name' => Util::localizedString($tpl, 'name', true, true),
|
||||
'type' => Type::AREATRIGGER,
|
||||
'id' => $spawn['typeId'],
|
||||
'description' => 'Type: '.Lang::areatrigger('types', $tpl['type'])
|
||||
'description' => Lang::game('type').Lang::main('colon').Lang::areatrigger('types', $tpl['type'])
|
||||
));
|
||||
}
|
||||
|
||||
@@ -785,6 +786,25 @@ class ZonePage extends GenericPage
|
||||
}
|
||||
}
|
||||
|
||||
private function addMoveLocationMenu($parentArea, $parentFloor)
|
||||
{
|
||||
// hide for non-staff
|
||||
if (!User::isInGroup(U_GROUP_EMPLOYEE))
|
||||
return;
|
||||
|
||||
$worldPos = Game::getWorldPosForGUID(Type::ZONE, -$this->typeId);
|
||||
if (!$worldPos)
|
||||
return;
|
||||
|
||||
$menu = Util::buildPosFixMenu($worldPos[-$this->typeId]['mapId'], $worldPos[-$this->typeId]['posX'], $worldPos[-$this->typeId]['posY'], Type::ZONE, -$this->typeId, $parentArea, $parentFloor);
|
||||
if (!$menu)
|
||||
return;
|
||||
|
||||
$menu = [1002, 'Edit DB Entry', null, $menu];
|
||||
|
||||
$this->addScript([SC_JS_STRING, '$(document).ready(function () { mn_staff.push('.Util::toJSON(array_values($menu)).'); });']);
|
||||
}
|
||||
|
||||
protected function generatePath()
|
||||
{
|
||||
$this->path[] = $this->subject->getField('category');
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -15,12 +15,11 @@ CLISetup::registerSetup('sql', new class extends SetupScript
|
||||
|
||||
protected $dbcSourceFiles = ['areatrigger'];
|
||||
protected $worldDependency = ['areatrigger_involvedrelation', 'areatrigger_scripts', 'areatrigger_tavern', 'areatrigger_teleport', 'quest_template', 'quest_template_addon'];
|
||||
protected $setupAfter = [['dungeonmap', 'worldmaparea'], []];
|
||||
|
||||
public function generate(array $ids = []) : bool
|
||||
{
|
||||
DB::Aowow()->query('TRUNCATE ?_areatrigger');
|
||||
DB::Aowow()->query('INSERT INTO ?_areatrigger SELECT `id`, 0, 0, `mapId`, `posX`, `posY`, `orientation`, NULL, NULL, NULL, NULL, NULL, NULL, NULL FROM dbc_areatrigger');
|
||||
DB::Aowow()->query('INSERT INTO ?_areatrigger SELECT `id`, 0, 0, `mapId`, `posX`, `posY`, `orientation`, NULL, NULL FROM dbc_areatrigger');
|
||||
|
||||
/* notes:
|
||||
* while areatrigger DO have dimensions, displaying them on a map is almost always futile,
|
||||
@@ -34,40 +33,18 @@ CLISetup::registerSetup('sql', new class extends SetupScript
|
||||
foreach ($addData as $id => $ad)
|
||||
DB::Aowow()->query('UPDATE ?_areatrigger SET ?a WHERE `id` = ?d', $ad, $id);
|
||||
|
||||
// 2: Teleporter + teleporting 4: Smart Trigger
|
||||
CLI::write('[areatrigger] - calculation teleporter coordinates');
|
||||
|
||||
// 2: Teleporter
|
||||
CLI::write('[areatrigger] - teleporter type and name');
|
||||
|
||||
$addData = DB::World()->select(
|
||||
'SELECT ID AS ARRAY_KEY, Name AS `name`, target_map AS `map`, target_position_x AS `posX`, target_position_y AS `posY`, target_orientation AS `orientation`
|
||||
FROM areatrigger_teleport
|
||||
UNION
|
||||
SELECT entryorguid AS ARRAY_KEY, "TBD" AS `name`, action_param1 AS `map`, target_x AS `posX`, target_y AS `posY`, target_o AS `orientation`
|
||||
FROM smart_scripts
|
||||
WHERE source_type = 2 AND action_type = 62'
|
||||
'SELECT `ID` AS ARRAY_KEY, `Name` AS `name` FROM areatrigger_teleport UNION
|
||||
SELECT `entryorguid` AS ARRAY_KEY, "SAI Teleport" AS `name` FROM smart_scripts WHERE `source_type` = ?d AND `action_type` = ?d',
|
||||
SAI_SRC_TYPE_AREATRIGGER, SAI_ACTION_TELEPORT
|
||||
);
|
||||
|
||||
foreach ($addData as $id => $ad)
|
||||
{
|
||||
$points = Game::worldPosToZonePos($ad['map'], $ad['posX'], $ad['posY']);
|
||||
if (!$points)
|
||||
{
|
||||
CLI::write('[areatrigger] '.str_pad('['.$id.']', 8).' teleporter endpoint '.CLI::bold($ad['name']).' could not be matched to displayable area [M:'.$ad['map'].'; X:'.$ad['posY'].'; Y:'.$ad['posX'].']', CLI::LOG_WARN);
|
||||
DB::Aowow()->query('UPDATE ?_areatrigger SET `name` = ?, `type` = ?d WHERE `id` = ?d', $ad['name'], AT_TYPE_TELEPORT, $id);
|
||||
continue;
|
||||
}
|
||||
DB::Aowow()->query('UPDATE ?_areatrigger SET `name` = ?, `type` = ?d WHERE `id` = ?d', $ad['name'], AT_TYPE_TELEPORT, $id);
|
||||
|
||||
$update = array(
|
||||
'name' => $ad['name'],
|
||||
'type' => AT_TYPE_TELEPORT,
|
||||
'teleportA' => $points[0]['areaId'],
|
||||
'teleportX' => $points[0]['posX'],
|
||||
'teleportY' => $points[0]['posY'],
|
||||
'teleportO' => $ad['orientation'],
|
||||
'teleportF' => $points[0]['floor']
|
||||
);
|
||||
|
||||
DB::Aowow()->query('UPDATE ?_areatrigger SET ?a WHERE `id` = ?d', $update, $id);
|
||||
}
|
||||
|
||||
// 3: Quest Objectives
|
||||
CLI::write('[areatrigger] - satisfying quest objectives');
|
||||
@@ -81,6 +58,7 @@ CLISetup::registerSetup('sql', new class extends SetupScript
|
||||
DB::Aowow()->query('UPDATE ?_areatrigger SET `name` = ?, type = ?d, `quest` = ?d WHERE `id` = ?d', $ad['name'], AT_TYPE_OBJECTIVE, $ad['quest'], $id);
|
||||
}
|
||||
|
||||
|
||||
// 4/5 Scripted
|
||||
CLI::write('[areatrigger] - assigning scripts');
|
||||
|
||||
|
||||
@@ -12,59 +12,82 @@ if (!CLI)
|
||||
CLISetup::registerSetup("sql", new class extends SetupScript
|
||||
{
|
||||
protected $info = array(
|
||||
'spawns' => [[], CLISetup::ARGV_PARAM, 'Compiles spawns/waypoints for type: GObject, NPC, Sound & Areatrigger from dbc and world db.']
|
||||
);
|
||||
'spawns' => [[ ], CLISetup::ARGV_PARAM, 'Compiles map points from dbc and world db.' ],
|
||||
'creatures' => [['1'], CLISetup::ARGV_OPTIONAL, '...just the creature positions.' ],
|
||||
'objects' => [['2'], CLISetup::ARGV_OPTIONAL, '...just the gameobject positions.' ],
|
||||
'soundemitter' => [['3'], CLISetup::ARGV_OPTIONAL, '...just the soundemitter positions.' ],
|
||||
'areatrigger' => [['4'], CLISetup::ARGV_OPTIONAL, '...just the areatrigger and teleporter positions.'],
|
||||
'instances' => [['5'], CLISetup::ARGV_OPTIONAL, '...just the instance portal positions.' ],
|
||||
'waypoints' => [['6'], CLISetup::ARGV_OPTIONAL, '...just the creature waypoints.' ]
|
||||
);
|
||||
|
||||
protected $dbcSourceFiles = ['worldmaparea', 'map', 'taxipathnode', 'soundemitters', 'areatrigger', 'areatable'];
|
||||
protected $worldDependency = ['creature', 'creature_addon', 'gameobject', 'gameobject_template', 'vehicle_accessory', 'vehicle_accessory_template', 'script_waypoint', 'waypoints', 'waypoint_data'];
|
||||
protected $worldDependency = ['creature', 'creature_addon', 'gameobject', 'gameobject_template', 'vehicle_accessory', 'vehicle_accessory_template', 'script_waypoint', 'waypoints', 'waypoint_data', 'smart_scripts', 'areatrigger_teleport'];
|
||||
protected $setupAfter = [['dungeonmap', 'worldmaparea', 'zones'], ['img-maps']];
|
||||
|
||||
private $querys = array(
|
||||
1 => ['SELECT c.`guid`, 1 AS `type`, c.`id` AS `typeId`, c.`spawntimesecs` AS `respawn`, c.`phaseMask`, c.`zoneId` AS `areaId`, c.`map`, IFNULL(ca.`path_id`, 0) AS `pathId`, c.`position_x` AS `posX`, c.`position_y` AS `posY` ' .
|
||||
'FROM creature c LEFT JOIN creature_addon ca ON ca.guid = c.guid',
|
||||
'`creature` spawns', Type::NPC],
|
||||
private $transports = [];
|
||||
private $overrideData = [];
|
||||
|
||||
2 => ['SELECT c.`guid`, 2 AS `type`, c.`id` AS `typeId`, c.`spawntimesecs` AS `respawn`, c.`phaseMask`, c.`zoneId` AS `areaId`, c.`map`, 0 AS `pathId`, c.`position_x` AS `posX`, c.`position_y` AS `posY` ' .
|
||||
'FROM gameobject c',
|
||||
'`gameobject` spawns', Type::OBJECT],
|
||||
|
||||
3 => ['SELECT `id` AS `guid`, 19 AS `type`, `soundId` AS `typeId`, 0 AS `respawn`, 0 AS `phaseMask`, 0 AS `areaId`, `mapId` AS `map`, 0 AS `pathId`, `posX`, `posY` ' .
|
||||
'FROM dbc_soundemitters',
|
||||
'SoundEmitters.dbc spawns', Type::SOUND],
|
||||
|
||||
4 => ['SELECT `id` AS `guid`, 503 AS `type`, `id` AS `typeId`, 0 AS `respawn`, 0 AS `phaseMask`, 0 AS `areaId`, `mapId` AS `map`, 0 AS `pathId`, `posX`, `posY` ' .
|
||||
'FROM dbc_areatrigger',
|
||||
'AreaTrigger.dbc spawns', Type::AREATRIGGER],
|
||||
|
||||
5 => ['SELECT c.`guid`, w.`entry` AS `npcOrPath`, w.`pointId` AS `point`, c.`zoneId` AS `areaId`, c.`map`, w.`waittime` AS `wait`, w.`location_x` AS `posX`, w.`location_y` AS `posY` ' .
|
||||
'FROM creature c JOIN script_waypoint w ON c.`id` = w.`entry`',
|
||||
'`script_waypoint`', Type::NPC],
|
||||
|
||||
6 => ['SELECT c.`guid`, w.`entry` AS `npcOrPath`, w.`pointId` AS `point`, c.`zoneId` AS `areaId`, c.`map`, 0 AS `wait`, w.`position_x` AS `posX`, w.`position_y` AS `posY` ' .
|
||||
'FROM creature c JOIN waypoints w ON c.`id` = w.`entry`',
|
||||
'`waypoints`', Type::NPC],
|
||||
|
||||
7 => ['SELECT c.`guid`, -w.`id` AS `npcOrPath`, w.`point`, c.`zoneId` AS `areaId`, c.`map`, w.`delay` AS `wait`, w.`position_x` AS `posX`, w.`position_y` AS `posY` ' .
|
||||
'FROM creature c JOIN creature_addon ca ON ca.`guid` = c.`guid` JOIN waypoint_data w ON w.`id` = ca.`path_id` WHERE ca.`path_id` <> 0',
|
||||
'`waypoint_data`', Type::NPC]
|
||||
private $steps = array(
|
||||
0x01 => ['creature', Type::NPC, false, '`creature` spawns', ],
|
||||
0x02 => ['gameobject', Type::OBJECT, false, '`gameobject` spawns', ],
|
||||
0x04 => ['soundemitter', Type::SOUND, false, 'SoundEmitters.dbc positions', ],
|
||||
0x08 => ['areatrigger', Type::AREATRIGGER, false, 'AreaTrigger.dbc positions and teleporter endpoints' ],
|
||||
0x10 => ['instances', Type::ZONE, false, 'Map.dbc instance portals positions' ],
|
||||
0x20 => ['waypoints', Type::NPC, true, 'NPC waypoints from `script_waypoint`, `waypoints` & `waypoint_data`'],
|
||||
);
|
||||
|
||||
|
||||
public function generate(array $ids = []) : bool
|
||||
{
|
||||
/*********************/
|
||||
/* truncate old data */
|
||||
/*********************/
|
||||
/*****************************/
|
||||
/* find out what to generate */
|
||||
/*****************************/
|
||||
|
||||
DB::Aowow()->query('TRUNCATE TABLE ?_spawns');
|
||||
DB::Aowow()->query('TRUNCATE TABLE ?_creature_waypoints');
|
||||
$opts = array_slice(array_keys($this->info), 1);
|
||||
$getOpt = CLISetup::getOpt(...$opts);
|
||||
$todoMask = 0x0;
|
||||
|
||||
if ($getOpt['creatures'])
|
||||
$todoMask |= 0x01;
|
||||
if ($getOpt['objects'])
|
||||
$todoMask |= 0x02;
|
||||
if ($getOpt['soundemitter'])
|
||||
$todoMask |= 0x04;
|
||||
if ($getOpt['areatrigger'])
|
||||
$todoMask |= 0x08;
|
||||
if ($getOpt['instances'])
|
||||
$todoMask |= 0x10;
|
||||
if ($getOpt['waypoints'])
|
||||
$todoMask |= 0x20;
|
||||
|
||||
if ($todoMask)
|
||||
foreach ($this->steps as $idx => $_)
|
||||
if (!($todoMask & $idx))
|
||||
unset($this->steps[$idx]);
|
||||
|
||||
|
||||
/*********************************/
|
||||
/* selectively truncate old data */
|
||||
/*********************************/
|
||||
|
||||
if (!$todoMask || ($todoMask & 0x1F) == 0x1F)
|
||||
DB::Aowow()->query('TRUNCATE TABLE ?_spawns');
|
||||
else
|
||||
foreach ($this->steps as $idx => [, $type, $isWP, ])
|
||||
if (($idx & $todoMask) && !$isWP)
|
||||
DB::Aowow()->query('DELETE FROM ?_spawns WHERE `type` = ?d', $type);
|
||||
|
||||
if (!$todoMask || ($todoMask & 0x20))
|
||||
DB::Aowow()->query('TRUNCATE TABLE ?_creature_waypoints');
|
||||
|
||||
|
||||
/**************************/
|
||||
/* offsets for transports */
|
||||
/**************************/
|
||||
|
||||
$transports = DB::World()->selectCol('SELECT `data0` AS `pathId`, `data6` AS ARRAY_KEY FROM gameobject_template WHERE `type` = ?d AND `data6` <> 0', OBJECT_MO_TRANSPORT);
|
||||
foreach ($transports as &$t)
|
||||
$this->transports = DB::World()->selectCol('SELECT `data0` AS `pathId`, `data6` AS ARRAY_KEY FROM gameobject_template WHERE `type` = ?d AND `data6` <> 0', OBJECT_MO_TRANSPORT);
|
||||
foreach ($this->transports as &$t)
|
||||
$t = DB::Aowow()->selectRow('SELECT `posX`, `posY`, `mapId` FROM dbc_taxipathnode tpn WHERE tpn.`pathId` = ?d AND `nodeIdx` = 0', $t);
|
||||
|
||||
|
||||
@@ -72,109 +95,57 @@ CLISetup::registerSetup("sql", new class extends SetupScript
|
||||
/* get override data */
|
||||
/*********************/
|
||||
|
||||
$overrideData = DB::Aowow()->select('SELECT `type` AS ARRAY_KEY, `typeGuid` AS ARRAY_KEY2, `areaId`, `floor` FROM ?_spawns_override');
|
||||
$this->overrideData = DB::Aowow()->select('SELECT `type` AS ARRAY_KEY, `typeGuid` AS ARRAY_KEY2, `areaId`, `floor` FROM ?_spawns_override');
|
||||
|
||||
|
||||
/**************/
|
||||
/* perform... */
|
||||
/**************/
|
||||
|
||||
foreach ($this->querys as $idx => $q)
|
||||
foreach (array_values($this->steps) as $i => [$generator, $type, $isWP, $comment])
|
||||
{
|
||||
$time = new Timer(500);
|
||||
$sum = 0;
|
||||
$time = new Timer(500);
|
||||
$sum = 0;
|
||||
$lastOverride = 0;
|
||||
$nSteps = count($this->steps);
|
||||
$queryResult = $this->$generator();
|
||||
$queryTotal = count($queryResult);
|
||||
$queryTotalLen = strlen($queryTotal);
|
||||
|
||||
if ($idx == 3 || $idx == 4)
|
||||
$queryResult = DB::Aowow()->select($q[0]);
|
||||
else
|
||||
$queryResult = DB::World()->select($q[0]);
|
||||
CLI::write(' - '.$generator);
|
||||
|
||||
$qryTotal = count($queryResult);
|
||||
$qtLen = strlen($qryTotal);
|
||||
$doneGUID = 0;
|
||||
foreach ($queryResult as $spawn)
|
||||
{
|
||||
$notice = '';
|
||||
$sum++;
|
||||
if ($time->update())
|
||||
CLI::write(' * '.$idx.'/'.count($this->querys).': '. CLI::bold($q[1]).' - '.sprintf('%'.$qtLen.'d / %d (%4.1f%%)', $sum, $qryTotal, round(100 * $sum / $qryTotal, 1)), CLI::LOG_BLANK, true, true);
|
||||
CLI::write(' * '.($i + 1).'/'.$nSteps.': '. CLI::bold($comment).' - '.sprintf('%'.$queryTotalLen.'d / %d (%4.1f%%)', $sum, $queryTotal, round(100 * $sum / $queryTotal, 1)), CLI::LOG_BLANK, true, true);
|
||||
|
||||
// npc/object is on a transport -> apply offsets to path of transport
|
||||
// note, that transport DO spawn outside of displayable area maps .. another todo i guess..
|
||||
if (isset($transports[$spawn['map']]))
|
||||
$point = $this->transformPoint($spawn, $type, $notice);
|
||||
|
||||
if (!$notice && !$lastOverride)
|
||||
{
|
||||
$spawn['posX'] += $transports[$spawn['map']]['posX'];
|
||||
$spawn['posY'] += $transports[$spawn['map']]['posY'];
|
||||
$spawn['map'] = $transports[$spawn['map']]['mapId'];
|
||||
CLI::write($notice, CLI::LOG_INFO);
|
||||
$time->reset();
|
||||
$lastOverride = $spawn['guid']; // don't spam this for waypoints
|
||||
}
|
||||
|
||||
$area = $spawn['areaId'];
|
||||
$floor = -1;
|
||||
if (isset($overrideData[$q[2]][$spawn['guid']]))
|
||||
if (!$point)
|
||||
{
|
||||
$area = $overrideData[$q[2]][$spawn['guid']]['areaId'];
|
||||
$floor = $overrideData[$q[2]][$spawn['guid']]['floor'];
|
||||
if ($doneGUID != $spawn['guid'])
|
||||
{
|
||||
CLI::write('[spawns] '.str_pad('['.$spawn['guid'].']', 9).' manually moved to [A:'.$spawn['areaId'].' => '.$area.'; F: '.$floor.']', CLI::LOG_INFO);
|
||||
$time->reset();
|
||||
$doneGUID = $spawn['guid']; // do not spam on waypoints
|
||||
}
|
||||
}
|
||||
|
||||
$points = Game::worldPosToZonePos($spawn['map'], $spawn['posX'], $spawn['posY'], $area, $floor);
|
||||
|
||||
// cannot be placed, but we know the instanced map and can thus at least assign a zone
|
||||
if (!$points && !in_array($spawn['map'], [0, 1, 530, 571]) && $idx < 5)
|
||||
{
|
||||
// use server calculated areaId if possible
|
||||
$area = $area ?: DB::Aowow()->selectCell('SELECT `id` FROM ?_zones WHERE `mapId` = ?d AND `parentArea` = 0 AND (`cuFlags` & ?d) = 0', $spawn['map'], CUSTOM_EXCLUDE_FOR_LISTVIEW);
|
||||
if (!$area)
|
||||
{
|
||||
CLI::write('[spawns] '.str_pad('['.$spawn['guid'].']', 9).' could not be defaulted to instanced area by mapId [M:'.$spawn['map'].']', CLI::LOG_WARN);
|
||||
$time->reset();
|
||||
continue;
|
||||
}
|
||||
$final = ['areaId' => $area, 'posX' => 0, 'posY' => 0, 'floor' => 0];
|
||||
}
|
||||
else if (!$points) // still impossible (there are areas that are intentionally off the map (e.g. the isles south of tanaris))
|
||||
{
|
||||
CLI::write('[spawns] '.str_pad('['.$spawn['guid'].']', 9).' '.($idx < 5 ? '' : 'with path/point ['.$spawn['npcOrPath'].'; '.$spawn['point'].'] ').'could not be matched to displayable area [A:'.$area.'; X:'.$spawn['posY'].'; Y:'.$spawn['posX'].']', CLI::LOG_WARN);
|
||||
CLI::write('[points] '.str_pad('['.$spawn['guid'].']', 9).' '.(isset($spawn['point']) ? 'with path/point ['.$spawn['npcOrPath'].'; '.$spawn['point'].'] ' : '').'could not be matched to displayable area [A:'.($spawn['areaId'] ?? 0).'; X:'.$spawn['posY'].'; Y:'.$spawn['posX'].']', CLI::LOG_WARN);
|
||||
$time->reset();
|
||||
continue;
|
||||
}
|
||||
else // if areaId is set, area was determined by TC .. we're fine .. mostly
|
||||
$final = $area ? $points[0] : Game::checkCoords($points);
|
||||
|
||||
if ($idx < 5)
|
||||
$set = array_merge($spawn, $point);
|
||||
if (!$isWP) // REPLACE: because there is bogus data where one path may be assigned to multiple npcs
|
||||
{
|
||||
$set = array(
|
||||
'guid' => $spawn['guid'],
|
||||
'type' => $spawn['type'],
|
||||
'typeId' => $spawn['typeId'],
|
||||
'respawn' => $spawn['respawn'],
|
||||
'phaseMask' => $spawn['phaseMask'],
|
||||
'pathId' => $spawn['pathId'],
|
||||
'areaId' => $final['areaId'],
|
||||
'floor' => $final['floor'],
|
||||
'posX' => $final['posX'],
|
||||
'posY' => $final['posY']
|
||||
);
|
||||
|
||||
unset($set['map']);
|
||||
DB::Aowow()->query('REPLACE INTO ?_spawns (?#) VALUES (?a)', array_keys($set), array_values($set));
|
||||
}
|
||||
else
|
||||
{
|
||||
$set = array(
|
||||
'creatureOrPath' => $spawn['npcOrPath'],
|
||||
'point' => $spawn['point'],
|
||||
'wait' => $spawn['wait'],
|
||||
'areaId' => $final['areaId'],
|
||||
'floor' => $final['floor'],
|
||||
'posX' => $final['posX'],
|
||||
'posY' => $final['posY']
|
||||
);
|
||||
|
||||
// REPLACE: because there is bogus data where one path may be assigned to multiple npcs
|
||||
unset($set['map'], $set['guid']);
|
||||
DB::Aowow()->query('REPLACE INTO ?_creature_waypoints (?#) VALUES (?a)', array_keys($set), array_values($set));
|
||||
}
|
||||
}
|
||||
@@ -185,44 +156,47 @@ CLISetup::registerSetup("sql", new class extends SetupScript
|
||||
/* spawn vehicle accessories */
|
||||
/*****************************/
|
||||
|
||||
// get vehicle template accessories
|
||||
$accessories = DB::World()->select(
|
||||
'SELECT vta.`accessory_entry` AS `typeId`, c.`guid`, vta.`entry`, COUNT(1) AS `nSeats` FROM vehicle_template_accessory vta LEFT JOIN creature c ON c.`id` = vta.`entry` GROUP BY `accessory_entry`, c.`guid` UNION
|
||||
SELECT va.`accessory_entry` AS `typeId`, va.`guid`, 0 AS `entry`, COUNT(1) AS `nSeats` FROM vehicle_accessory va GROUP BY `accessory_entry`, va.`guid`'
|
||||
);
|
||||
|
||||
// accessories may also be vehicles (e.g. "Kor'kron Infiltrator" is seated on "Kor'kron Suppression Turret" is seated on "Kor'kron Troop Transport")
|
||||
// so we will retry finding a spawned vehicle if none were found on the previous pass and a change occured
|
||||
$vGuid = 0; // not really used, but we need some kind of index
|
||||
$n = 0;
|
||||
$matches = -1;
|
||||
while ($matches)
|
||||
if ($todoMask & 0x01) // only when creature is set
|
||||
{
|
||||
$matches = 0;
|
||||
foreach ($accessories as $idx => $data)
|
||||
// get vehicle template accessories
|
||||
$accessories = DB::World()->select(
|
||||
'SELECT vta.`accessory_entry` AS `typeId`, c.`guid`, vta.`entry`, COUNT(1) AS `nSeats` FROM vehicle_template_accessory vta LEFT JOIN creature c ON c.`id` = vta.`entry` GROUP BY `accessory_entry`, c.`guid` UNION
|
||||
SELECT va.`accessory_entry` AS `typeId`, va.`guid`, 0 AS `entry`, COUNT(1) AS `nSeats` FROM vehicle_accessory va GROUP BY `accessory_entry`, va.`guid`'
|
||||
);
|
||||
|
||||
// accessories may also be vehicles (e.g. "Kor'kron Infiltrator" is seated on "Kor'kron Suppression Turret" is seated on "Kor'kron Troop Transport")
|
||||
// so we will retry finding a spawned vehicle if none were found on the previous pass and a change occured
|
||||
$vGuid = 0; // not really used, but we need some kind of index
|
||||
$n = 0;
|
||||
$matches = -1;
|
||||
while ($matches)
|
||||
{
|
||||
$vehicles = [];
|
||||
if ($data['guid']) // vehicle already spawned
|
||||
$vehicles = DB::Aowow()->select('SELECT s.`areaId`, s.`posX`, s.`posY`, s.`floor` FROM ?_spawns s WHERE s.`guid` = ?d AND s.`type` = ?d', $data['guid'], Type::NPC);
|
||||
else if ($data['entry']) // vehicle on unspawned vehicle action
|
||||
$vehicles = DB::Aowow()->select('SELECT s.`areaId`, s.`posX`, s.`posY`, s.`floor` FROM ?_spawns s WHERE s.`typeId` = ?d AND s.`type` = ?d', $data['entry'], Type::NPC);
|
||||
|
||||
if ($vehicles)
|
||||
$matches = 0;
|
||||
foreach ($accessories as $idx => $data)
|
||||
{
|
||||
$matches++;
|
||||
foreach ($vehicles as $v) // if there is more than one vehicle, its probably due to overlapping zones
|
||||
for ($i = 0; $i < $data['nSeats']; $i++)
|
||||
DB::Aowow()->query('INSERT INTO ?_spawns (`guid`, `type`, `typeId`, `respawn`, `spawnMask`, `phaseMask`, `areaId`, `floor`, `posX`, `posY`, `pathId`) VALUES (?d, ?d, ?d, 0, 0, 1, ?d, ?d, ?f, ?f, 0)',
|
||||
--$vGuid, Type::NPC, $data['typeId'], $v['areaId'], $v['floor'], $v['posX'], $v['posY']);
|
||||
$vehicles = [];
|
||||
if ($data['guid']) // vehicle already spawned
|
||||
$vehicles = DB::Aowow()->select('SELECT s.`areaId`, s.`posX`, s.`posY`, s.`floor` FROM ?_spawns s WHERE s.`guid` = ?d AND s.`type` = ?d', $data['guid'], Type::NPC);
|
||||
else if ($data['entry']) // vehicle on unspawned vehicle action
|
||||
$vehicles = DB::Aowow()->select('SELECT s.`areaId`, s.`posX`, s.`posY`, s.`floor` FROM ?_spawns s WHERE s.`typeId` = ?d AND s.`type` = ?d', $data['entry'], Type::NPC);
|
||||
|
||||
unset($accessories[$idx]);
|
||||
if ($vehicles)
|
||||
{
|
||||
$matches++;
|
||||
foreach ($vehicles as $v) // if there is more than one vehicle, its probably due to overlapping zones
|
||||
for ($i = 0; $i < $data['nSeats']; $i++)
|
||||
DB::Aowow()->query('INSERT INTO ?_spawns (`guid`, `type`, `typeId`, `respawn`, `spawnMask`, `phaseMask`, `areaId`, `floor`, `posX`, `posY`, `pathId`) VALUES (?d, ?d, ?d, 0, 0, 1, ?d, ?d, ?f, ?f, 0)',
|
||||
--$vGuid, Type::NPC, $data['typeId'], $v['areaId'], $v['floor'], $v['posX'], $v['posY']);
|
||||
|
||||
unset($accessories[$idx]);
|
||||
}
|
||||
}
|
||||
if ($matches)
|
||||
CLI::write(' * assigned '.$matches.' accessories on '.++$n.'. pass on vehicle accessories', CLI::LOG_BLANK, true, true);
|
||||
}
|
||||
if ($matches)
|
||||
CLI::write(' * assigned '.$matches.' accessories on '.++$n.'. pass on vehicle accessories', CLI::LOG_BLANK, true, true);
|
||||
if ($accessories)
|
||||
CLI::write('[spawns] - '.count($accessories).' accessories could not be fitted onto a spawned vehicle.', CLI::LOG_WARN);
|
||||
}
|
||||
if ($accessories)
|
||||
CLI::write('[spawns] - '.count($accessories).' accessories could not be fitted onto a spawned vehicle.', CLI::LOG_WARN);
|
||||
|
||||
|
||||
/********************************/
|
||||
@@ -233,6 +207,131 @@ CLISetup::registerSetup("sql", new class extends SetupScript
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function creature() : array
|
||||
{
|
||||
// [guid, type, typeId, map, posX, posY [, respawn, spawnMask, phaseMask, areaId, floor, pathId]]
|
||||
return DB::World()->select(
|
||||
'SELECT c.`guid`, ?d AS `type`, c.`id` AS `typeId`, c.`map`, c.`position_x` AS `posX`, c.`position_y` AS `posY`, c.`spawntimesecs` AS `respawn`, c.`spawnMask`, c.`phaseMask`, c.`zoneId` AS `areaId`, IFNULL(ca.`path_id`, 0) AS `pathId`
|
||||
FROM creature c
|
||||
LEFT JOIN creature_addon ca ON ca.guid = c.guid',
|
||||
Type::NPC
|
||||
);
|
||||
}
|
||||
|
||||
private function gameobject() : array
|
||||
{
|
||||
// [guid, type, typeId, map, posX, posY [, respawn, spawnMask, phaseMask, areaId, floor, pathId]]
|
||||
return DB::World()->select(
|
||||
'SELECT `guid`, ?d AS `type`, `id` AS `typeId`, `map`, `position_x` AS `posX`, `position_y` AS `posY`, `spawntimesecs` AS `respawn`, `spawnMask`, `phaseMask`, `zoneId` AS `areaId`
|
||||
FROM gameobject',
|
||||
Type::OBJECT
|
||||
);
|
||||
}
|
||||
|
||||
private function soundemitter() : array
|
||||
{
|
||||
// [guid, type, typeId, map, posX, posY [, respawn, spawnMask, phaseMask, areaId, floor, pathId]]
|
||||
return DB::Aowow()->select(
|
||||
'SELECT `id` AS `guid`, ?d AS `type`, `soundId` AS `typeId`, `mapId` AS `map`, `posX`, `posY`
|
||||
FROM dbc_soundemitters',
|
||||
Type::SOUND
|
||||
);
|
||||
}
|
||||
|
||||
private function areatrigger() : array
|
||||
{
|
||||
// [guid, type, typeId, map, posX, posY [, respawn, spawnMask, phaseMask, areaId, floor, pathId]]
|
||||
$base = DB::Aowow()->select(
|
||||
'SELECT `id` AS `guid`, ?d AS `type`, `id` AS `typeId`, `mapId` AS `map`, `posX`, `posY`
|
||||
FROM dbc_areatrigger',
|
||||
Type::AREATRIGGER
|
||||
);
|
||||
|
||||
$addData = DB::World()->select(
|
||||
'SELECT -`ID` AS `guid`, ?d AS `type`, ID AS `typeId`, `target_map` AS `map`, `target_position_x` AS `posX`, `target_position_y` AS `posY`
|
||||
FROM areatrigger_teleport UNION
|
||||
SELECT -`entryorguid` AS `guid`, ?d AS `type`, entryorguid AS `typeId`, `action_param1` AS `map`, `target_x` AS `posX`, `target_y` AS `posY`
|
||||
FROM smart_scripts
|
||||
WHERE `source_type` = ?d AND `action_type` = ?d',
|
||||
Type::AREATRIGGER, Type::AREATRIGGER, SAI_SRC_TYPE_AREATRIGGER, SAI_ACTION_TELEPORT
|
||||
);
|
||||
|
||||
return array_merge($base, $addData);
|
||||
}
|
||||
|
||||
private function instances() : array
|
||||
{
|
||||
// maps with set graveyard
|
||||
return DB::Aowow()->select(
|
||||
'SELECT -`id` AS `guid`, ?d AS `type`, `id` AS `typeId`, `parentMapId` AS `map`, `parentX` AS `posX`, `parentY` AS `posY`
|
||||
FROM ?_zones
|
||||
WHERE `parentX` <> 0 AND `parentY` <> 0 AND `parentArea` = 0 AND (`cuFlags` & ?d) = 0',
|
||||
Type::ZONE, CUSTOM_EXCLUDE_FOR_LISTVIEW
|
||||
);
|
||||
}
|
||||
|
||||
private function waypoints() : array
|
||||
{
|
||||
return DB::World()->select(
|
||||
'SELECT c.`guid`, w.`entry` AS `creatureOrPath`, w.`pointId` AS `point`, c.`zoneId` AS `areaId`, c.`map`, w.`waittime` AS `wait`, w.`location_x` AS `posX`, w.`location_y` AS `posY`
|
||||
FROM creature c
|
||||
JOIN script_waypoint w ON c.`id` = w.`entry` UNION
|
||||
SELECT c.`guid`, w.`entry` AS `creatureOrPath`, w.`pointId` AS `point`, c.`zoneId` AS `areaId`, c.`map`, 0 AS `wait`, w.`position_x` AS `posX`, w.`position_y` AS `posY`
|
||||
FROM creature c
|
||||
JOIN waypoints w ON c.`id` = w.`entry` UNION
|
||||
SELECT c.`guid`, -w.`id` AS `creatureOrPath`, w.`point`, c.`zoneId` AS `areaId`, c.`map`, w.`delay` AS `wait`, w.`position_x` AS `posX`, w.`position_y` AS `posY`
|
||||
FROM creature c
|
||||
JOIN creature_addon ca ON ca.`guid` = c.`guid`
|
||||
JOIN waypoint_data w ON w.`id` = ca.`path_id`
|
||||
WHERE ca.`path_id` <> 0'
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
private function transformPoint(array $point, int $type, ?string $notice = '') : array
|
||||
{
|
||||
// npc/object is on a transport -> apply offsets to path of transport
|
||||
// note, that transport DO spawn outside of displayable area maps .. another todo i guess..
|
||||
if (isset($this->transports[$point['map']]))
|
||||
{
|
||||
$point['posX'] += $this->transports[$point['map']]['posX'];
|
||||
$point['posY'] += $this->transports[$point['map']]['posY'];
|
||||
$point['map'] = $this->transports[$point['map']]['mapId'];
|
||||
}
|
||||
|
||||
$area = $point['areaId'] ?? 0;
|
||||
$floor = -1;
|
||||
if (isset($this->overrideData[$type][$point['guid']]))
|
||||
{
|
||||
$area = $this->overrideData[$type][$point['guid']]['areaId'];
|
||||
$floor = $this->overrideData[$type][$point['guid']]['floor'];
|
||||
$notice = '[points] '.str_pad('['.$point['guid'].']', 9).' manually moved to [A:'.($point['areaId'] ?? 0).' => '.$area.'; F: '.$floor.']';
|
||||
}
|
||||
|
||||
if ($points = Game::worldPosToZonePos($point['map'], $point['posX'], $point['posY'], $area, $floor))
|
||||
{
|
||||
if ($area) // if areaId is set, area was determined by TC .. we're fine .. mostly
|
||||
return ['areaId' => $area, 'posX' => $points[0]['posX'], 'posY' => $points[0]['posY'], 'floor' => $points[0]['floor']];
|
||||
|
||||
$point = Game::checkCoords($points); // try to determine best found point by alphamap
|
||||
return ['areaId' => $point['areaId'], 'posX' => $point['posX'], 'posY' => $point['posY'], 'floor' => $point['floor']];
|
||||
}
|
||||
|
||||
// cannot be placed on a map, try to reuse TC assigned areaId
|
||||
if ($area)
|
||||
{
|
||||
$selfOrParent = DB::Aowow()->selectCell('SELECT IF(`parentArea`, `parentArea`, `id`) FROM ?_zones WHERE `id` = ?d', $area);
|
||||
return ['areaId' => $selfOrParent, 'posX' => 0, 'posY' => 0, 'floor' => 0];
|
||||
}
|
||||
|
||||
// we know the instanced map; try to assign a zone this way
|
||||
if (!in_array($point['map'], [0, 1, 530, 571]))
|
||||
if ($area = DB::Aowow()->selectCell('SELECT `id` FROM ?_zones WHERE `mapId` = ?d AND `parentArea` = 0 AND (`cuFlags` & ?d) = 0', $point['map'], CUSTOM_EXCLUDE_FOR_LISTVIEW))
|
||||
return ['areaId' => $area, 'posX' => 0, 'posY' => 0, 'floor' => 0];
|
||||
|
||||
return [];
|
||||
}
|
||||
});
|
||||
|
||||
?>
|
||||
|
||||
@@ -20,8 +20,8 @@ CLISetup::registerSetup("sql", new class extends SetupScript
|
||||
'zones' => [[], CLISetup::ARGV_PARAM, 'Compiles supplemental data for type: Zone from dbc and world db.']
|
||||
);
|
||||
|
||||
protected $dbcSourceFiles = ['worldmaptransforms', 'worldmaparea', 'map', 'mapdifficulty', 'areatable', 'lfgdungeons', 'battlemasterlist'];
|
||||
protected $worldDependency = ['access_requirement'];
|
||||
protected $dbcSourceFiles = ['worldmaptransforms', 'worldmaparea', 'map', 'mapdifficulty', 'areatable', 'lfgdungeons', 'battlemasterlist', 'areatrigger'];
|
||||
protected $worldDependency = ['access_requirement', 'areatrigger_teleport'];
|
||||
protected $setupAfter = [['dungeonmap', 'worldmaparea'], []];
|
||||
|
||||
public function generate(array $ids = []) : bool
|
||||
@@ -49,9 +49,9 @@ CLISetup::registerSetup("sql", new class extends SetupScript
|
||||
IF(a.flags & 0x8, ?d, IFNULL(bm.maxLevel, IFNULL(lfgIni.levelMax, IFNULL(lfgOpen.levelMax, 0)))) AS `levelMax`,
|
||||
"" AS `attunementsN`,
|
||||
"" AS `attunementsH`,
|
||||
m.parentMapId, -- IFNULL(pa.areaId, 0),
|
||||
m.parentX, -- IFNULL(pa.posX, 0),
|
||||
m.parentY, -- IFNULL(pa.posY, 0),
|
||||
GREATEST(m.parentMapId, 0),
|
||||
m.parentX,
|
||||
m.parentY,
|
||||
IF(wma.id IS NULL OR m.areaType = 0 OR a.mapId IN (269, 560) OR a.areaTable, a.name_loc0, m.name_loc0),
|
||||
IF(wma.id IS NULL OR m.areaType = 0 OR a.mapId IN (269, 560) OR a.areaTable, a.name_loc2, m.name_loc2),
|
||||
IF(wma.id IS NULL OR m.areaType = 0 OR a.mapId IN (269, 560) OR a.areaTable, a.name_loc3, m.name_loc3),
|
||||
@@ -77,26 +77,18 @@ CLISetup::registerSetup("sql", new class extends SetupScript
|
||||
CUSTOM_EXCLUDE_FOR_LISTVIEW, MAX_LEVEL
|
||||
);
|
||||
|
||||
foreach ($baseData as &$bd)
|
||||
{
|
||||
// usually parent = -1 means no parent but some maps have this touple set to 0
|
||||
if (!$bd['parentMapId'] && !$bd['parentX'] && !$bd['parentY'])
|
||||
continue;
|
||||
|
||||
if ($gPos = Game::worldPosToZonePos($bd['parentMapId'], $bd['parentY'], $bd['parentX']))
|
||||
{
|
||||
$pos = Game::checkCoords($gPos);
|
||||
$bd['parentMapId'] = $pos['areaId'] ?? $gPos[0]['areaId'];
|
||||
$bd['parentX'] = $pos['posX'] ?? $gPos[0]['posX'];
|
||||
$bd['parentY'] = $pos['posY'] ?? $gPos[0]['posY'];
|
||||
continue;
|
||||
}
|
||||
|
||||
$bd['parentMapId'] = 0;
|
||||
}
|
||||
|
||||
DB::Aowow()->query('INSERT INTO ?_zones VALUES (?a)', $baseData);
|
||||
|
||||
|
||||
// set missing graveyards from areatrigger data (auto-resurrect map or just plain errors)
|
||||
// grouped because naxxramas _just has_ to be special with 4 entrances...
|
||||
if ($missingMaps = DB::Aowow()->selectCol('SELECT `id` FROM dbc_map WHERE `parentX` = 0 AND `parentY` = 0 AND `parentMapId` > -1 AND `areaType` NOT IN (0, 3, 4)'))
|
||||
if ($triggerIds = DB::World()->selectCol('SELECT `target_map`, `id` AS ARRAY_KEY FROM areatrigger_teleport WHERE `target_map` IN (?a) GROUP BY `target_map`', $missingMaps))
|
||||
if ($positions = DB::Aowow()->select('SELECT `id` AS `ARRAY_KEY`, `mapId` AS "parentMapId", `posX` AS "parentX", `posY` AS "parentY" FROM dbc_areatrigger WHERE `id` IN (?a)', array_keys($triggerIds)))
|
||||
foreach ($positions as $atId => $parentPos)
|
||||
DB::Aowow()->query('UPDATE ?_zones SET ?a WHERE `mapId` = ?d', $parentPos, $triggerIds[$atId]);
|
||||
|
||||
|
||||
// get requirements from world.access_requirement
|
||||
$zoneReq = DB::World()->select(
|
||||
'SELECT mapId AS ARRAY_KEY,
|
||||
|
||||
25
setup/updates/1719445945_01.sql
Normal file
25
setup/updates/1719445945_01.sql
Normal file
@@ -0,0 +1,25 @@
|
||||
DROP TABLE IF EXISTS `aowow_areatrigger`;
|
||||
CREATE TABLE `aowow_areatrigger` (
|
||||
`id` int unsigned NOT NULL,
|
||||
`cuFlags` int unsigned NOT NULL DEFAULT 0 COMMENT 'see defines.php for flags',
|
||||
`type` smallint unsigned NOT NULL,
|
||||
`mapId` smallint unsigned NOT NULL COMMENT 'world pos. from dbc',
|
||||
`posX` float NOT NULL COMMENT 'world pos. from dbc',
|
||||
`posY` float NOT NULL COMMENT 'world pos. from dbc',
|
||||
`orientation` float NOT NULL,
|
||||
`name` varchar(100) DEFAULT NULL,
|
||||
`quest` mediumint unsigned DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `quest` (`quest`),
|
||||
KEY `type` (`type`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
ALTER TABLE `aowow_zones`
|
||||
CHANGE COLUMN `parentAreaId` `parentMapId` smallint unsigned NOT NULL;
|
||||
|
||||
DELETE FROM aowow_setup_custom_data WHERE
|
||||
`command` = 'zones' AND
|
||||
`entry` IN (3456, 3845, 3847, 3848, 3849) AND
|
||||
`field` IN ('parentAreaId', 'parentX', 'parentY');
|
||||
|
||||
UPDATE `aowow_dbversion` SET `sql` = CONCAT(IFNULL(`sql`, ''), ' areatrigger zones spawns');
|
||||
Reference in New Issue
Block a user