mirror of
https://github.com/mangosfour/server.git
synced 2025-12-14 16:37:01 +00:00
[10362] Implement creature_movement_template
Template can be used for several cases: * Unique creature that are already spawned in database (requires creature.MovementType=2 like guid based creature_movement) * Summoned creature that has a pre-defined path (requires creature_template.MovementType=2) Note that creature_template.MovementType=2 should be used with care, and must not be used for creatures that may be summoned in random locations in world. Added additional startup checks for existing creature_movement-table Signed-off-by: NoFantasy <nofantasy@nf.no>
This commit is contained in:
parent
4dae2cfe89
commit
db7db6382a
8 changed files with 411 additions and 117 deletions
|
|
@ -24,7 +24,7 @@ CREATE TABLE `db_version` (
|
|||
`version` varchar(120) default NULL,
|
||||
`creature_ai_version` varchar(120) default NULL,
|
||||
`cache_id` int(10) default '0',
|
||||
`required_10353_02_mangos_command` bit(1) default NULL
|
||||
`required_10362_01_mangos_creature_movement_template` bit(1) default NULL
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Used DB version notes';
|
||||
|
||||
--
|
||||
|
|
@ -1057,6 +1057,42 @@ LOCK TABLES `creature_movement_scripts` WRITE;
|
|||
/*!40000 ALTER TABLE `creature_movement_scripts` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `creature_movement_template`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `creature_movement_template`;
|
||||
CREATE TABLE `creature_movement_template` (
|
||||
`entry` mediumint(8) unsigned NOT NULL COMMENT 'Creature entry',
|
||||
`point` mediumint(8) unsigned NOT NULL default '0',
|
||||
`position_x` float NOT NULL default '0',
|
||||
`position_y` float NOT NULL default '0',
|
||||
`position_z` float NOT NULL default '0',
|
||||
`waittime` int(10) unsigned NOT NULL default '0',
|
||||
`script_id` mediumint(8) unsigned NOT NULL default '0',
|
||||
`textid1` int(11) NOT NULL default '0',
|
||||
`textid2` int(11) NOT NULL default '0',
|
||||
`textid3` int(11) NOT NULL default '0',
|
||||
`textid4` int(11) NOT NULL default '0',
|
||||
`textid5` int(11) NOT NULL default '0',
|
||||
`emote` mediumint(8) unsigned NOT NULL default '0',
|
||||
`spell` mediumint(8) unsigned NOT NULL default '0',
|
||||
`wpguid` int(11) NOT NULL default '0',
|
||||
`orientation` float NOT NULL default '0',
|
||||
`model1` mediumint(9) NOT NULL default '0',
|
||||
`model2` mediumint(9) NOT NULL default '0',
|
||||
PRIMARY KEY (`entry`,`point`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Creature waypoint system';
|
||||
|
||||
--
|
||||
-- Dumping data for table `creature_movement_template`
|
||||
--
|
||||
|
||||
LOCK TABLES `creature_movement_template` WRITE;
|
||||
/*!40000 ALTER TABLE `creature_movement_template` DISABLE KEYS */;
|
||||
/*!40000 ALTER TABLE `creature_movement_template` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `creature_onkill_reputation`
|
||||
--
|
||||
|
|
|
|||
24
sql/updates/10362_01_mangos_creature_movement_template.sql
Normal file
24
sql/updates/10362_01_mangos_creature_movement_template.sql
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
ALTER TABLE db_version CHANGE COLUMN required_10353_02_mangos_command required_10362_01_mangos_creature_movement_template bit;
|
||||
|
||||
DROP TABLE IF EXISTS `creature_movement_template`;
|
||||
CREATE TABLE `creature_movement_template` (
|
||||
`entry` mediumint(8) unsigned NOT NULL COMMENT 'Creature entry',
|
||||
`point` mediumint(8) unsigned NOT NULL default '0',
|
||||
`position_x` float NOT NULL default '0',
|
||||
`position_y` float NOT NULL default '0',
|
||||
`position_z` float NOT NULL default '0',
|
||||
`waittime` int(10) unsigned NOT NULL default '0',
|
||||
`script_id` mediumint(8) unsigned NOT NULL default '0',
|
||||
`textid1` int(11) NOT NULL default '0',
|
||||
`textid2` int(11) NOT NULL default '0',
|
||||
`textid3` int(11) NOT NULL default '0',
|
||||
`textid4` int(11) NOT NULL default '0',
|
||||
`textid5` int(11) NOT NULL default '0',
|
||||
`emote` mediumint(8) unsigned NOT NULL default '0',
|
||||
`spell` mediumint(8) unsigned NOT NULL default '0',
|
||||
`wpguid` int(11) NOT NULL default '0',
|
||||
`orientation` float NOT NULL default '0',
|
||||
`model1` mediumint(9) NOT NULL default '0',
|
||||
`model2` mediumint(9) NOT NULL default '0',
|
||||
PRIMARY KEY (`entry`,`point`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Creature waypoint system';
|
||||
|
|
@ -80,6 +80,7 @@ pkgdata_DATA = \
|
|||
10350_02_mangos_command.sql \
|
||||
10353_01_mangos_mangos_string.sql \
|
||||
10353_02_mangos_command.sql \
|
||||
10362_01_mangos_creature_movement_template.sql \
|
||||
README
|
||||
|
||||
## Additional files to include when running 'make dist'
|
||||
|
|
@ -140,4 +141,5 @@ EXTRA_DIST = \
|
|||
10350_02_mangos_command.sql \
|
||||
10353_01_mangos_mangos_string.sql \
|
||||
10353_02_mangos_command.sql \
|
||||
10362_01_mangos_creature_movement_template.sql \
|
||||
README
|
||||
|
|
|
|||
|
|
@ -56,159 +56,347 @@ void WaypointManager::Load()
|
|||
uint32 total_nodes = 0;
|
||||
uint32 total_behaviors = 0;
|
||||
|
||||
QueryResult *result = WorldDatabase.Query("SELECT id, COUNT(point) FROM creature_movement GROUP BY id");
|
||||
|
||||
if(!result)
|
||||
{
|
||||
barGoLink bar(1);
|
||||
bar.step();
|
||||
sLog.outString();
|
||||
sLog.outString( ">> Loaded 0 paths. DB table `creature_movement` is empty." );
|
||||
return;
|
||||
} else {
|
||||
total_paths = (uint32)result->GetRowCount();
|
||||
barGoLink bar( total_paths );
|
||||
do
|
||||
{
|
||||
bar.step();
|
||||
Field *fields = result->Fetch();
|
||||
uint32 id = fields[0].GetUInt32();
|
||||
uint32 count = fields[1].GetUInt32();
|
||||
m_pathMap[id].resize(count);
|
||||
total_nodes += count;
|
||||
} while( result->NextRow() );
|
||||
delete result;
|
||||
|
||||
sLog.outString();
|
||||
sLog.outString( ">> Paths loaded" );
|
||||
}
|
||||
|
||||
// 0 1 2 3 4 5
|
||||
result = WorldDatabase.Query("SELECT position_x, position_y, position_z, orientation, model1, model2,"
|
||||
// 6 7 8 9 10 11 12 13 14 15 16
|
||||
"waittime, emote, spell, textid1, textid2, textid3, textid4, textid5, id, point, script_id FROM creature_movement");
|
||||
|
||||
std::set<uint32> movementScriptSet;
|
||||
|
||||
for(ScriptMapMap::const_iterator itr = sCreatureMovementScripts.begin(); itr != sCreatureMovementScripts.end(); ++itr)
|
||||
movementScriptSet.insert(itr->first);
|
||||
|
||||
barGoLink bar( (int)result->GetRowCount() );
|
||||
do
|
||||
// creature_movement
|
||||
QueryResult *result = WorldDatabase.Query("SELECT id, COUNT(point) FROM creature_movement GROUP BY id");
|
||||
|
||||
if (!result)
|
||||
{
|
||||
barGoLink bar(1);
|
||||
bar.step();
|
||||
Field *fields = result->Fetch();
|
||||
uint32 point = fields[15].GetUInt32();
|
||||
uint32 id = fields[14].GetUInt32();
|
||||
if (!sObjectMgr.GetCreatureData(id))
|
||||
sLog.outString();
|
||||
sLog.outString( ">> Loaded 0 paths. DB table `creature_movement` is empty." );
|
||||
}
|
||||
else
|
||||
{
|
||||
total_paths = (uint32)result->GetRowCount();
|
||||
barGoLink bar( total_paths );
|
||||
|
||||
do
|
||||
{
|
||||
sLog.outErrorDb("Table creature_movement references unknown creature %u. Skipping.", id);
|
||||
continue;
|
||||
bar.step();
|
||||
Field *fields = result->Fetch();
|
||||
|
||||
uint32 id = fields[0].GetUInt32();
|
||||
uint32 count = fields[1].GetUInt32();
|
||||
|
||||
m_pathMap[id].resize(count);
|
||||
total_nodes += count;
|
||||
}
|
||||
while(result->NextRow());
|
||||
|
||||
WaypointPath &path = m_pathMap[id];
|
||||
// the cleanup queries make sure the following is true
|
||||
ASSERT(point >= 1 && point <= path.size());
|
||||
WaypointNode &node = path[point-1];
|
||||
sLog.outString();
|
||||
sLog.outString( ">> Paths loaded" );
|
||||
|
||||
node.x = fields[0].GetFloat();
|
||||
node.y = fields[1].GetFloat();
|
||||
node.z = fields[2].GetFloat();
|
||||
node.orientation = fields[3].GetFloat();
|
||||
node.delay = fields[6].GetUInt32();
|
||||
node.script_id = fields[16].GetUInt32();
|
||||
delete result;
|
||||
|
||||
// prevent using invalid coordinates
|
||||
if(!MaNGOS::IsValidMapCoord(node.x, node.y, node.z, node.orientation))
|
||||
// 0 1 2 3 4 5 6
|
||||
result = WorldDatabase.Query("SELECT id, point, position_x, position_y, position_z, waittime, script_id,"
|
||||
// 7 8 9 10 11 12 13 14 15 16
|
||||
"textid1, textid2, textid3, textid4, textid5, emote, spell, orientation, model1, model2 FROM creature_movement");
|
||||
|
||||
barGoLink barRow((int)result->GetRowCount());
|
||||
|
||||
// error after load, we check if creature guid corresponding to the path id has proper MovementType
|
||||
std::set<uint32> creatureNoMoveType;
|
||||
|
||||
do
|
||||
{
|
||||
QueryResult *result1 = WorldDatabase.PQuery("SELECT id, map FROM creature WHERE guid = '%u'", id);
|
||||
if(result1)
|
||||
sLog.outErrorDb("Creature (guidlow %d, entry %d) have invalid coordinates in his waypoint %d (X: %f, Y: %f).",
|
||||
id, result1->Fetch()[0].GetUInt32(), point, node.x, node.y);
|
||||
else
|
||||
sLog.outErrorDb("Waypoint path %d, have invalid coordinates in his waypoint %d (X: %f, Y: %f).",
|
||||
id, point, node.x, node.y);
|
||||
barRow.step();
|
||||
Field *fields = result->Fetch();
|
||||
uint32 id = fields[0].GetUInt32();
|
||||
uint32 point = fields[1].GetUInt32();
|
||||
|
||||
MaNGOS::NormalizeMapCoord(node.x);
|
||||
MaNGOS::NormalizeMapCoord(node.y);
|
||||
if(result1)
|
||||
{
|
||||
node.z = MapManager::Instance ().CreateBaseMap(result1->Fetch()[1].GetUInt32())->GetHeight(node.x, node.y, node.z);
|
||||
delete result1;
|
||||
}
|
||||
WorldDatabase.PExecute("UPDATE creature_movement SET position_x = '%f', position_y = '%f', position_z = '%f' WHERE id = '%u' AND point = '%u'", node.x, node.y, node.z, id, point);
|
||||
}
|
||||
const CreatureData* cData = sObjectMgr.GetCreatureData(id);
|
||||
|
||||
if (node.script_id)
|
||||
{
|
||||
if (sCreatureMovementScripts.find(node.script_id) == sCreatureMovementScripts.end())
|
||||
if (!cData)
|
||||
{
|
||||
sLog.outErrorDb("Table creature_movement for id %u, point %u have script_id %u that does not exist in `creature_movement_scripts`, ignoring", id, point, node.script_id);
|
||||
sLog.outErrorDb("Table creature_movement contain path for creature guid %u, but this creature guid does not exist. Skipping.", id);
|
||||
continue;
|
||||
}
|
||||
|
||||
movementScriptSet.erase(node.script_id);
|
||||
}
|
||||
if (cData->movementType != WAYPOINT_MOTION_TYPE)
|
||||
creatureNoMoveType.insert(id);
|
||||
|
||||
// WaypointBehavior can be dropped in time. Script_id added may 2010 and can handle all the below behavior.
|
||||
WaypointPath &path = m_pathMap[id];
|
||||
|
||||
WaypointBehavior be;
|
||||
be.model1 = fields[4].GetUInt32();
|
||||
be.model2 = fields[5].GetUInt32();
|
||||
be.emote = fields[7].GetUInt32();
|
||||
be.spell = fields[8].GetUInt32();
|
||||
for(int i = 0; i < MAX_WAYPOINT_TEXT; ++i)
|
||||
{
|
||||
be.textid[i] = fields[9+i].GetUInt32();
|
||||
if(be.textid[i])
|
||||
// the cleanup queries make sure the following is true
|
||||
ASSERT(point >= 1 && point <= path.size());
|
||||
|
||||
WaypointNode &node = path[point-1];
|
||||
|
||||
node.x = fields[2].GetFloat();
|
||||
node.y = fields[3].GetFloat();
|
||||
node.z = fields[4].GetFloat();
|
||||
node.orientation = fields[14].GetFloat();
|
||||
node.delay = fields[5].GetUInt32();
|
||||
node.script_id = fields[6].GetUInt32();
|
||||
|
||||
// prevent using invalid coordinates
|
||||
if (!MaNGOS::IsValidMapCoord(node.x, node.y, node.z, node.orientation))
|
||||
{
|
||||
if (be.textid[i] < MIN_DB_SCRIPT_STRING_ID || be.textid[i] >= MAX_DB_SCRIPT_STRING_ID)
|
||||
QueryResult *result1 = WorldDatabase.PQuery("SELECT id, map FROM creature WHERE guid = '%u'", id);
|
||||
if (result1)
|
||||
sLog.outErrorDb("Creature (guidlow %d, entry %d) have invalid coordinates in his waypoint %d (X: %f, Y: %f).",
|
||||
id, result1->Fetch()[0].GetUInt32(), point, node.x, node.y);
|
||||
else
|
||||
sLog.outErrorDb("Waypoint path %d, have invalid coordinates in his waypoint %d (X: %f, Y: %f).",
|
||||
id, point, node.x, node.y);
|
||||
|
||||
MaNGOS::NormalizeMapCoord(node.x);
|
||||
MaNGOS::NormalizeMapCoord(node.y);
|
||||
|
||||
if (result1)
|
||||
{
|
||||
sLog.outErrorDb( "Table `db_script_string` not have string id %u", be.textid[i]);
|
||||
node.z = MapManager::Instance ().CreateBaseMap(result1->Fetch()[1].GetUInt32())->GetHeight(node.x, node.y, node.z);
|
||||
delete result1;
|
||||
}
|
||||
|
||||
WorldDatabase.PExecute("UPDATE creature_movement SET position_x = '%f', position_y = '%f', position_z = '%f' WHERE id = '%u' AND point = '%u'", node.x, node.y, node.z, id, point);
|
||||
}
|
||||
|
||||
if (node.script_id)
|
||||
{
|
||||
if (sCreatureMovementScripts.find(node.script_id) == sCreatureMovementScripts.end())
|
||||
{
|
||||
sLog.outErrorDb("Table creature_movement for id %u, point %u have script_id %u that does not exist in `creature_movement_scripts`, ignoring", id, point, node.script_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
movementScriptSet.erase(node.script_id);
|
||||
}
|
||||
|
||||
// WaypointBehavior can be dropped in time. Script_id added may 2010 and can handle all the below behavior.
|
||||
|
||||
WaypointBehavior be;
|
||||
be.model1 = fields[15].GetUInt32();
|
||||
be.model2 = fields[16].GetUInt32();
|
||||
be.emote = fields[12].GetUInt32();
|
||||
be.spell = fields[13].GetUInt32();
|
||||
|
||||
for(int i = 0; i < MAX_WAYPOINT_TEXT; ++i)
|
||||
{
|
||||
be.textid[i] = fields[7+i].GetUInt32();
|
||||
|
||||
if (be.textid[i])
|
||||
{
|
||||
if (be.textid[i] < MIN_DB_SCRIPT_STRING_ID || be.textid[i] >= MAX_DB_SCRIPT_STRING_ID)
|
||||
{
|
||||
sLog.outErrorDb( "Table `db_script_string` not have string id %u", be.textid[i]);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (be.spell && ! sSpellStore.LookupEntry(be.spell))
|
||||
{
|
||||
sLog.outErrorDb("Table creature_movement references unknown spellid %u. Skipping id %u with point %u.", be.spell, id, point);
|
||||
be.spell = 0;
|
||||
}
|
||||
|
||||
if (be.emote)
|
||||
{
|
||||
if (!sEmotesStore.LookupEntry(be.emote))
|
||||
sLog.outErrorDb("Waypoint path %u (Point %u) are using emote %u, but emote does not exist.",id, point, be.emote);
|
||||
}
|
||||
|
||||
// save memory by not storing empty behaviors
|
||||
if (!be.isEmpty())
|
||||
{
|
||||
node.behavior = new WaypointBehavior(be);
|
||||
++total_behaviors;
|
||||
}
|
||||
else
|
||||
node.behavior = NULL;
|
||||
}
|
||||
while(result->NextRow());
|
||||
|
||||
if (!creatureNoMoveType.empty())
|
||||
{
|
||||
for(std::set<uint32>::const_iterator itr = creatureNoMoveType.begin(); itr != creatureNoMoveType.end(); ++itr)
|
||||
{
|
||||
const CreatureData* cData = sObjectMgr.GetCreatureData(*itr);
|
||||
const CreatureInfo* cInfo = sObjectMgr.GetCreatureTemplate(cData->id);
|
||||
|
||||
sLog.outErrorDb("Table creature_movement has waypoint for creature guid %u (entry %u), but MovementType is not WAYPOINT_MOTION_TYPE(2). Creature will not use this path.", *itr, cData->id);
|
||||
|
||||
if (cInfo->MovementType == WAYPOINT_MOTION_TYPE)
|
||||
sLog.outErrorDb(" creature_template for this entry has MovementType WAYPOINT_MOTION_TYPE(2), did you intend to use creature_movement_template ?");
|
||||
}
|
||||
}
|
||||
|
||||
if (be.spell && ! sSpellStore.LookupEntry(be.spell))
|
||||
{
|
||||
sLog.outErrorDb("Table creature_movement references unknown spellid %u. Skipping id %u with point %u.", be.spell, id, point);
|
||||
be.spell = 0;
|
||||
}
|
||||
sLog.outString();
|
||||
sLog.outString( ">> Waypoints and behaviors loaded" );
|
||||
sLog.outString();
|
||||
sLog.outString( ">>> Loaded %u paths, %u nodes and %u behaviors", total_paths, total_nodes, total_behaviors);
|
||||
|
||||
if (be.emote)
|
||||
{
|
||||
if (!sEmotesStore.LookupEntry(be.emote))
|
||||
sLog.outErrorDb("Waypoint path %u (Point %u) are using emote %u, but emote does not exist.",id, point, be.emote);
|
||||
}
|
||||
delete result;
|
||||
}
|
||||
|
||||
// save memory by not storing empty behaviors
|
||||
if(!be.isEmpty())
|
||||
// creature_movement_template
|
||||
result = WorldDatabase.Query("SELECT entry, COUNT(point) FROM creature_movement_template GROUP BY entry");
|
||||
|
||||
if (!result)
|
||||
{
|
||||
barGoLink bar(1);
|
||||
bar.step();
|
||||
sLog.outString();
|
||||
sLog.outString( ">> Loaded 0 path templates. DB table `creature_movement_template` is empty." );
|
||||
}
|
||||
else
|
||||
{
|
||||
total_nodes = 0;
|
||||
total_behaviors = 0;
|
||||
total_paths = (uint32)result->GetRowCount();
|
||||
barGoLink barRow(total_paths);
|
||||
|
||||
do
|
||||
{
|
||||
node.behavior = new WaypointBehavior(be);
|
||||
++total_behaviors;
|
||||
barRow.step();
|
||||
Field *fields = result->Fetch();
|
||||
|
||||
uint32 entry = fields[0].GetUInt32();
|
||||
uint32 count = fields[1].GetUInt32();
|
||||
|
||||
m_pathTemplateMap[entry].resize(count);
|
||||
total_nodes += count;
|
||||
}
|
||||
else
|
||||
node.behavior = NULL;
|
||||
} while( result->NextRow() );
|
||||
delete result;
|
||||
while(result->NextRow());
|
||||
|
||||
delete result;
|
||||
|
||||
sLog.outString();
|
||||
sLog.outString(">> Path templates loaded");
|
||||
|
||||
// 0 1 2 3 4 5 6
|
||||
result = WorldDatabase.Query("SELECT entry, point, position_x, position_y, position_z, waittime, script_id,"
|
||||
// 7 8 9 10 11 12 13 14 15 16
|
||||
"textid1, textid2, textid3, textid4, textid5, emote, spell, orientation, model1, model2 FROM creature_movement_template");
|
||||
|
||||
barGoLink bar( (int)result->GetRowCount() );
|
||||
|
||||
do
|
||||
{
|
||||
bar.step();
|
||||
Field *fields = result->Fetch();
|
||||
|
||||
uint32 entry = fields[0].GetUInt32();
|
||||
uint32 point = fields[1].GetUInt32();
|
||||
|
||||
const CreatureInfo* cInfo = sObjectMgr.GetCreatureTemplate(entry);
|
||||
|
||||
if (!cInfo)
|
||||
{
|
||||
sLog.outErrorDb("Table creature_movement_template references unknown creature template %u. Skipping.", entry);
|
||||
continue;
|
||||
}
|
||||
|
||||
WaypointPath &path = m_pathTemplateMap[entry];
|
||||
|
||||
// the cleanup queries make sure the following is true
|
||||
ASSERT(point >= 1 && point <= path.size());
|
||||
|
||||
WaypointNode &node = path[point-1];
|
||||
|
||||
node.x = fields[2].GetFloat();
|
||||
node.y = fields[3].GetFloat();
|
||||
node.z = fields[4].GetFloat();
|
||||
node.orientation = fields[14].GetFloat();
|
||||
node.delay = fields[5].GetUInt32();
|
||||
node.script_id = fields[6].GetUInt32();
|
||||
|
||||
// prevent using invalid coordinates
|
||||
if (!MaNGOS::IsValidMapCoord(node.x, node.y, node.z, node.orientation))
|
||||
{
|
||||
sLog.outErrorDb("Table creature_movement_template for entry %u (point %u) are using invalid coordinates position_x: %f, position_y: %f)",
|
||||
entry, point, node.x, node.y);
|
||||
|
||||
MaNGOS::NormalizeMapCoord(node.x);
|
||||
MaNGOS::NormalizeMapCoord(node.y);
|
||||
|
||||
sLog.outErrorDb("Table creature_movement_template for entry %u (point %u) are auto corrected to normalized position_x=%f, position_y=%f",
|
||||
entry, point, node.x, node.y);
|
||||
|
||||
WorldDatabase.PExecute("UPDATE creature_movement_template SET position_x = '%f', position_y = '%f' WHERE entry = %u AND point = %u", node.x, node.y, entry, point);
|
||||
}
|
||||
|
||||
if (node.script_id)
|
||||
{
|
||||
if (sCreatureMovementScripts.find(node.script_id) == sCreatureMovementScripts.end())
|
||||
{
|
||||
sLog.outErrorDb("Table creature_movement_template for entry %u, point %u have script_id %u that does not exist in `creature_movement_scripts`, ignoring", entry, point, node.script_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
movementScriptSet.erase(node.script_id);
|
||||
}
|
||||
|
||||
WaypointBehavior be;
|
||||
be.model1 = fields[15].GetUInt32();
|
||||
be.model2 = fields[16].GetUInt32();
|
||||
be.emote = fields[12].GetUInt32();
|
||||
be.spell = fields[13].GetUInt32();
|
||||
|
||||
for(int i = 0; i < MAX_WAYPOINT_TEXT; ++i)
|
||||
{
|
||||
be.textid[i] = fields[7+i].GetUInt32();
|
||||
|
||||
if (be.textid[i])
|
||||
{
|
||||
if (be.textid[i] < MIN_DB_SCRIPT_STRING_ID || be.textid[i] >= MAX_DB_SCRIPT_STRING_ID)
|
||||
{
|
||||
sLog.outErrorDb( "Table `db_script_string` not have string id %u", be.textid[i]);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (be.spell && ! sSpellStore.LookupEntry(be.spell))
|
||||
{
|
||||
sLog.outErrorDb("Table creature_movement_template references unknown spellid %u. Skipping id %u with point %u.", be.spell, entry, point);
|
||||
be.spell = 0;
|
||||
}
|
||||
|
||||
if (be.emote)
|
||||
{
|
||||
if (!sEmotesStore.LookupEntry(be.emote))
|
||||
sLog.outErrorDb("Waypoint template path %u (point %u) are using emote %u, but emote does not exist.", entry, point, be.emote);
|
||||
}
|
||||
|
||||
// save memory by not storing empty behaviors
|
||||
if (!be.isEmpty())
|
||||
{
|
||||
node.behavior = new WaypointBehavior(be);
|
||||
++total_behaviors;
|
||||
}
|
||||
else
|
||||
node.behavior = NULL;
|
||||
}
|
||||
while(result->NextRow());
|
||||
|
||||
delete result;
|
||||
|
||||
sLog.outString();
|
||||
sLog.outString( ">> Waypoint templates loaded" );
|
||||
sLog.outString();
|
||||
sLog.outString( ">>> Loaded %u path templates with %u nodes and %u behaviors", total_paths, total_nodes, total_behaviors);
|
||||
}
|
||||
|
||||
if (!movementScriptSet.empty())
|
||||
{
|
||||
for(std::set<uint32>::const_iterator itr = movementScriptSet.begin(); itr != movementScriptSet.end(); ++itr)
|
||||
sLog.outErrorDb("Table `creature_movement_scripts` contain unused script, id %u.", *itr);
|
||||
}
|
||||
|
||||
sLog.outString();
|
||||
sLog.outString( ">> Waypoints and behaviors loaded" );
|
||||
sLog.outString();
|
||||
sLog.outString( ">>> Loaded %u paths, %u nodes and %u behaviors", total_paths, total_nodes, total_behaviors);
|
||||
}
|
||||
|
||||
void WaypointManager::Cleanup()
|
||||
{
|
||||
// check if points need to be renumbered and do it
|
||||
if(QueryResult *result = WorldDatabase.Query("SELECT 1 from creature_movement As T WHERE point <> (SELECT COUNT(*) FROM creature_movement WHERE id = T.id AND point <= T.point) LIMIT 1"))
|
||||
if (QueryResult *result = WorldDatabase.Query("SELECT 1 from creature_movement As T WHERE point <> (SELECT COUNT(*) FROM creature_movement WHERE id = T.id AND point <= T.point) LIMIT 1"))
|
||||
{
|
||||
delete result;
|
||||
WorldDatabase.DirectExecute("CREATE TEMPORARY TABLE temp LIKE creature_movement");
|
||||
|
|
@ -217,8 +405,26 @@ void WaypointManager::Cleanup()
|
|||
WorldDatabase.DirectExecute("UPDATE creature_movement AS T SET point = (SELECT COUNT(*) FROM temp WHERE id = T.id AND point <= T.point)");
|
||||
WorldDatabase.DirectExecute("ALTER TABLE creature_movement ADD PRIMARY KEY (id, point)");
|
||||
WorldDatabase.DirectExecute("DROP TABLE temp");
|
||||
|
||||
sLog.outErrorDb("Table `creature_movement` was auto corrected for using points out of order (invalid or points missing)");
|
||||
|
||||
ASSERT(!(result = WorldDatabase.Query("SELECT 1 from creature_movement As T WHERE point <> (SELECT COUNT(*) FROM creature_movement WHERE id = T.id AND point <= T.point) LIMIT 1")));
|
||||
}
|
||||
|
||||
if (QueryResult *result = WorldDatabase.Query("SELECT 1 from creature_movement_template As T WHERE point <> (SELECT COUNT(*) FROM creature_movement_template WHERE entry = T.entry AND point <= T.point) LIMIT 1"))
|
||||
{
|
||||
delete result;
|
||||
WorldDatabase.DirectExecute("CREATE TEMPORARY TABLE temp LIKE creature_movement_template");
|
||||
WorldDatabase.DirectExecute("INSERT INTO temp SELECT * FROM creature_movement_template");
|
||||
WorldDatabase.DirectExecute("ALTER TABLE creature_movement_template DROP PRIMARY KEY");
|
||||
WorldDatabase.DirectExecute("UPDATE creature_movement_template AS T SET point = (SELECT COUNT(*) FROM temp WHERE entry = T.entry AND point <= T.point)");
|
||||
WorldDatabase.DirectExecute("ALTER TABLE creature_movement_template ADD PRIMARY KEY (entry, point)");
|
||||
WorldDatabase.DirectExecute("DROP TABLE temp");
|
||||
|
||||
sLog.outErrorDb("Table `creature_movement_template` was auto corrected for using points out of order (invalid or points missing)");
|
||||
|
||||
ASSERT(!(result = WorldDatabase.Query("SELECT 1 from creature_movement_template As T WHERE point <> (SELECT COUNT(*) FROM creature_movement_template WHERE entry = T.entry AND point <= T.point) LIMIT 1")));
|
||||
}
|
||||
}
|
||||
|
||||
void WaypointManager::Unload()
|
||||
|
|
|
|||
|
|
@ -71,6 +71,12 @@ class WaypointManager
|
|||
return itr != m_pathMap.end() ? &itr->second : NULL;
|
||||
}
|
||||
|
||||
WaypointPath *GetPathTemplate(uint32 entry)
|
||||
{
|
||||
WaypointPathTemplateMap::iterator itr = m_pathTemplateMap.find(entry);
|
||||
return itr != m_pathTemplateMap.end() ? &itr->second : NULL;
|
||||
}
|
||||
|
||||
void AddLastNode(uint32 id, float x, float y, float z, float o, uint32 delay, uint32 wpGuid);
|
||||
void AddAfterNode(uint32 id, uint32 point, float x, float y, float z, float o, uint32 delay, uint32 wpGuid);
|
||||
uint32 GetLastPoint(uint32 id, uint32 default_notfound);
|
||||
|
|
@ -86,6 +92,8 @@ class WaypointManager
|
|||
|
||||
typedef UNORDERED_MAP<uint32, WaypointPath> WaypointPathMap;
|
||||
WaypointPathMap m_pathMap;
|
||||
typedef UNORDERED_MAP<uint32, WaypointPath> WaypointPathTemplateMap;
|
||||
WaypointPathTemplateMap m_pathTemplateMap;
|
||||
};
|
||||
|
||||
#define sWaypointMgr MaNGOS::Singleton<WaypointManager>::Instance()
|
||||
|
|
|
|||
|
|
@ -50,11 +50,29 @@ void WaypointMovementGenerator<Creature>::LoadPath(Creature &creature)
|
|||
|
||||
i_path = sWaypointMgr.GetPath(creature.GetDBTableGUIDLow());
|
||||
|
||||
// We may LoadPath() for several occasions:
|
||||
|
||||
// 1: When creature.MovementType=2
|
||||
// 1a) Path is selected by creature.guid == creature_movement.id
|
||||
// 1b) Path for 1a) does not exist and then use path from creature.GetEntry() == creature_movement_template.entry
|
||||
|
||||
// 2: When creature_template.MovementType=2
|
||||
// 2a) Creature is summoned and has creature_template.MovementType=2
|
||||
// Creators need to be sure that creature_movement_template is always valid for summons.
|
||||
// Mob that can be summoned anywhere should not have creature_movement_template for example.
|
||||
|
||||
// No movement found for guid
|
||||
if (!i_path)
|
||||
{
|
||||
sLog.outErrorDb("WaypointMovementGenerator::LoadPath: creature %s (Entry: %u GUID: %u) doesn't have waypoint path",
|
||||
creature.GetName(), creature.GetEntry(), creature.GetDBTableGUIDLow());
|
||||
return;
|
||||
i_path = sWaypointMgr.GetPathTemplate(creature.GetEntry());
|
||||
|
||||
// No movement found for entry
|
||||
if (!i_path)
|
||||
{
|
||||
sLog.outErrorDb("WaypointMovementGenerator::LoadPath: creature %s (Entry: %u GUID: %u) doesn't have waypoint path",
|
||||
creature.GetName(), creature.GetEntry(), creature.GetDBTableGUIDLow());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// We have to set the destination here (for the first point), right after Initialize. Without, we may not have valid xyz for GetResetPosition
|
||||
|
|
@ -266,7 +284,7 @@ bool WaypointMovementGenerator<Creature>::Update(Creature &creature, const uint3
|
|||
else
|
||||
{
|
||||
// If not stopped then stop it
|
||||
creature.StopMoving();
|
||||
creature.clearUnitState(UNIT_STAT_ROAMING_MOVE);
|
||||
|
||||
SetStoppedByPlayer(false);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#ifndef __REVISION_NR_H__
|
||||
#define __REVISION_NR_H__
|
||||
#define REVISION_NR "10361"
|
||||
#define REVISION_NR "10362"
|
||||
#endif // __REVISION_NR_H__
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#ifndef __REVISION_SQL_H__
|
||||
#define __REVISION_SQL_H__
|
||||
#define REVISION_DB_CHARACTERS "required_10332_02_characters_pet_aura"
|
||||
#define REVISION_DB_MANGOS "required_10353_02_mangos_command"
|
||||
#define REVISION_DB_MANGOS "required_10362_01_mangos_creature_movement_template"
|
||||
#define REVISION_DB_REALMD "required_10008_01_realmd_realmd_db_version"
|
||||
#endif // __REVISION_SQL_H__
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue