diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/game/WaypointManager.cpp | 406 | ||||
-rw-r--r-- | src/game/WaypointManager.h | 82 | ||||
-rw-r--r-- | src/game/WaypointMovementGenerator.cpp | 306 | ||||
-rw-r--r-- | src/game/WaypointMovementGenerator.h | 72 |
4 files changed, 299 insertions, 567 deletions
diff --git a/src/game/WaypointManager.cpp b/src/game/WaypointManager.cpp index 831f616060b..c18c09bcc17 100644 --- a/src/game/WaypointManager.cpp +++ b/src/game/WaypointManager.cpp @@ -10,333 +10,143 @@ * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "Database/DatabaseEnv.h" #include "GridDefines.h" -#include "Policies/SingletonImp.h" #include "WaypointManager.h" #include "ProgressBar.h" #include "MapManager.h" -#include "ObjectMgr.h" -INSTANTIATE_SINGLETON_1(WaypointManager); +UNORDERED_MAP<uint32, WaypointPath*> waypoint_map; +WaypointStore WaypointMgr; -bool WaypointBehavior::isEmpty() +void WaypointStore::Free() { - if (emote || spell || model1 || model2) - return false; - - for(int i = 0; i < MAX_WAYPOINT_TEXT; ++i) - if(textid[i]) - return false; - - return true; -} - -WaypointBehavior::WaypointBehavior(const WaypointBehavior &b) -{ - emote = b.emote; - spell = b.spell; - model1 = b.model1; - model2 = b.model2; - for(int i=0; i < MAX_WAYPOINT_TEXT; ++i) - textid[i] = b.textid[i]; + waypoint_map.clear(); } -void WaypointManager::Load() +void WaypointStore::Load() { - Cleanup(); - - uint32 total_paths = 0; - uint32 total_nodes = 0; - uint32 total_behaviors = 0; - - QueryResult *result = WorldDatabase.Query("SELECT id, COUNT(point) FROM creature_movement GROUP BY id"); - if(result) + QueryResult *result = WorldDatabase.PQuery("SELECT MAX(`id`) FROM `waypoint_data"); + if(!result) { - total_paths = result->GetRowCount(); - barGoLink bar( total_paths ); - do - { - Field *fields = result->Fetch(); - uint32 id = fields[0].GetUInt32(); - uint32 count = fields[1].GetUInt32(); - m_pathMap[id].resize(count); - - total_nodes += count; - bar.step(); - } while( result->NextRow() ); - delete result; + sLog.outError(" an error occured while loading the table `waypoint_data` ( maybe it doesn't exist ?)\n"); + exit(1); // Stop server at loading non exited table or not accessable table } - result = WorldDatabase.Query("SELECT position_x, position_y, position_z, orientation, model1, model2, waittime, emote, spell, textid1, textid2, textid3, textid4, textid5, id, point FROM creature_movement"); - if(result) - { - barGoLink bar( result->GetRowCount() ); - do - { - Field *fields = result->Fetch(); - uint32 point = fields[15].GetUInt32(); - uint32 id = fields[14].GetUInt32(); - - 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]; - - node.x = fields[0].GetFloat(); - node.y = fields[1].GetFloat(); - node.z = fields[2].GetFloat(); - node.orientation = fields[3].GetFloat(); - node.delay = fields[6].GetUInt16(); - - // prevent using invalid coordinates - if(!Trinity::IsValidMapCoord(node.x, node.y, node.z, node.orientation)) - { - QueryResult *result1 = WorldDatabase.PQuery("SELECT id, map FROM creature WHERE guid = '%u'", id); - if(result1) - sLog.outErrorDb("ERROR: 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("ERROR: Waypoint path %d, have invalid coordinates in his waypoint %d (X: %f, Y: %f).", - id, point, node.x, node.y); - - Trinity::NormalizeMapCoord(node.x); - Trinity::NormalizeMapCoord(node.y); - if(result1) - { - node.z = MapManager::Instance ().GetBaseMap(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); - } - - 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]) - { - 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; - } - } - } - - // save memory by not storing empty behaviors - if(!be.isEmpty()) - { - node.behavior = new WaypointBehavior(be); - ++total_behaviors; - } - else - node.behavior = NULL; - bar.step(); - } while( result->NextRow() ); - delete result; - } - 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")) - { - delete result; - WorldDatabase.DirectExecute("CREATE TEMPORARY TABLE temp LIKE creature_movement"); - WorldDatabase.DirectExecute("INSERT INTO temp SELECT * FROM creature_movement"); - WorldDatabase.DirectExecute("ALTER TABLE creature_movement DROP PRIMARY KEY"); - 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"); - 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"))); - } -} - -void WaypointManager::Unload() -{ - for(WaypointPathMap::iterator itr = m_pathMap.begin(); itr != m_pathMap.end(); ++itr) - _clearPath(itr->second); - m_pathMap.clear(); -} - -void WaypointManager::_clearPath(WaypointPath &path) -{ - for(WaypointPath::iterator itr = path.begin(); itr != path.end(); ++itr) - if(itr->behavior) - delete itr->behavior; - path.clear(); -} - -/// - Insert after the last point -void WaypointManager::AddLastNode(uint32 id, float x, float y, float z, float o, uint32 delay, uint32 wpGuid) -{ - _addNode(id, GetLastPoint(id, 0) + 1, x, y, z, o, delay, wpGuid); -} - -/// - Insert after a certain point -void WaypointManager::AddAfterNode(uint32 id, uint32 point, float x, float y, float z, float o, uint32 delay, uint32 wpGuid) -{ - for(uint32 i = GetLastPoint(id, 0); i > point; i--) - WorldDatabase.PExecuteLog("UPDATE creature_movement SET point=point+1 WHERE id='%u' AND point='%u'", id, i); - - _addNode(id, point + 1, x, y, z, o, delay, wpGuid); -} + records = (*result)[0].GetUInt32(); + delete result; -/// - Insert without checking for collision -void WaypointManager::_addNode(uint32 id, uint32 point, float x, float y, float z, float o, uint32 delay, uint32 wpGuid) -{ - if(point == 0) return; // counted from 1 in the DB - WorldDatabase.PExecuteLog("INSERT INTO creature_movement (id,point,position_x,position_y,position_z,orientation,wpguid,waittime) VALUES ('%u','%u','%f', '%f', '%f', '%f', '%d', '%d')", id, point, x, y, z, o, wpGuid, delay); - WaypointPathMap::iterator itr = m_pathMap.find(id); - if(itr == m_pathMap.end()) - itr = m_pathMap.insert(WaypointPathMap::value_type(id, WaypointPath())).first; - itr->second.insert(itr->second.begin() + (point - 1), WaypointNode(x, y, z, o, delay, NULL)); -} -uint32 WaypointManager::GetLastPoint(uint32 id, uint32 default_notfound) -{ - uint32 point = default_notfound; - /*QueryResult *result = WorldDatabase.PQuery( "SELECT MAX(point) FROM creature_movement WHERE id = '%u'", id); - if( result ) + result = WorldDatabase.PQuery("SELECT `id`,`point`,`position_x`,`position_y`,`position_z`,`move_flag`,`delay`,`action`,`action_chance` FROM `waypoint_data` ORDER BY `id`, `point`"); + if(!result) { - point = (*result)[0].GetUInt32()+1; - delete result; - }*/ - WaypointPathMap::iterator itr = m_pathMap.find(id); - if(itr != m_pathMap.end() && itr->second.size() != 0) - point = itr->second.size(); - return point; -} - -void WaypointManager::DeleteNode(uint32 id, uint32 point) -{ - if(point == 0) return; // counted from 1 in the DB - WorldDatabase.PExecuteLog("DELETE FROM creature_movement WHERE id='%u' AND point='%u'", id, point); - WorldDatabase.PExecuteLog("UPDATE creature_movement SET point=point-1 WHERE id='%u' AND point>'%u'", id, point); - WaypointPathMap::iterator itr = m_pathMap.find(id); - if(itr != m_pathMap.end() && point <= itr->second.size()) - itr->second.erase(itr->second.begin() + (point-1)); -} - -void WaypointManager::DeletePath(uint32 id) -{ - WorldDatabase.PExecuteLog("DELETE FROM creature_movement WHERE id='%u'", id); - WaypointPathMap::iterator itr = m_pathMap.find(id); - if(itr != m_pathMap.end()) - _clearPath(itr->second); - // the path is not removed from the map, just cleared - // WMGs have pointers to the path, so deleting them would crash - // this wastes some memory, but these functions are - // only meant to be called by GM commands -} - -void WaypointManager::SetNodePosition(uint32 id, uint32 point, float x, float y, float z) -{ - if(point == 0) return; // counted from 1 in the DB - WorldDatabase.PExecuteLog("UPDATE creature_movement SET position_x = '%f',position_y = '%f',position_z = '%f' where id = '%u' AND point='%u'", x, y, z, id, point); - WaypointPathMap::iterator itr = m_pathMap.find(id); - if(itr != m_pathMap.end() && point <= itr->second.size()) - { - itr->second[point-1].x = x; - itr->second[point-1].y = y; - itr->second[point-1].z = z; + sLog.outErrorDb("The table `creature_addon` is empty or corrupted"); + return; } -} -void WaypointManager::SetNodeText(uint32 id, uint32 point, const char *text_field, const char *text) -{ - if(point == 0) return; // counted from 1 in the DB - if(!text_field) return; - std::string field = text_field; - WorldDatabase.escape_string(field); + WaypointPath* path_data; + uint32 total_records = result->GetRowCount(); - if(!text) + barGoLink bar( total_records); + Field *fields; + uint32 last_id = 0; + + do { - WorldDatabase.PExecuteLog("UPDATE creature_movement SET %s=NULL WHERE id='%u' AND point='%u'", field.c_str(), id, point); - } - else - { - std::string text2 = text; - WorldDatabase.escape_string(text2); - WorldDatabase.PExecuteLog("UPDATE creature_movement SET %s='%s' WHERE id='%u' AND point='%u'", field.c_str(), text2.c_str(), id, point); - } - - WaypointPathMap::iterator itr = m_pathMap.find(id); - if(itr != m_pathMap.end() && point <= itr->second.size()) - { - WaypointNode &node = itr->second[point-1]; - if(!node.behavior) node.behavior = new WaypointBehavior(); - -// if(field == "text1") node.behavior->text[0] = text ? text : ""; -// if(field == "text2") node.behavior->text[1] = text ? text : ""; -// if(field == "text3") node.behavior->text[2] = text ? text : ""; -// if(field == "text4") node.behavior->text[3] = text ? text : ""; -// if(field == "text5") node.behavior->text[4] = text ? text : ""; - if(field == "emote") node.behavior->emote = text ? atoi(text) : 0; - if(field == "spell") node.behavior->spell = text ? atoi(text) : 0; - if(field == "model1") node.behavior->model1 = text ? atoi(text) : 0; - if(field == "model2") node.behavior->model2 = text ? atoi(text) : 0; - } + fields = result->Fetch(); + uint32 id = fields[0].GetUInt32(); + bar.step(); + WaypointData *wp = new WaypointData; + + if(last_id != id) + path_data = new WaypointPath; + + float x,y,z; + x = fields[2].GetFloat(); + y = fields[3].GetFloat(); + z = fields[4].GetFloat(); + + Trinity::NormalizeMapCoord(x); + Trinity::NormalizeMapCoord(y); + + wp->id = fields[1].GetUInt32(); + wp->x = x; + wp->y = y; + wp->z = z; + wp->run = fields[5].GetBool(); + wp->delay = fields[6].GetUInt32(); + wp->event_id = fields[7].GetUInt32(); + wp->event_chance = fields[8].GetUInt8(); + + path_data->push_back(wp); + + if(id != last_id) + waypoint_map[id] = path_data; + + last_id = id; + + } while(result->NextRow()) ; + + + delete result; } -void WaypointManager::CheckTextsExistance(std::set<int32>& ids) +void WaypointStore::UpdatePath(uint32 id) { - WaypointPathMap::iterator pmItr = m_pathMap.begin(); - for ( ; pmItr != m_pathMap.end(); ++pmItr) + + if(waypoint_map.find(id)!= waypoint_map.end()) + waypoint_map[id]->clear(); + + QueryResult *result; + + result = WorldDatabase.PQuery("SELECT `id`,`point`,`position_x`,`position_y`,`position_z`,`move_flag`,`delay`,`action`,`action_chance` FROM `waypoint_data` WHERE id = %u ORDER BY `point`", id); + + if(!result) + return; + + WaypointPath* path_data; + + path_data = new WaypointPath; + + Field *fields; + + do { - for (int i = 0; i < pmItr->second.size(); ++i) - { - if (!pmItr->second[i].behavior) - continue; - - // Now we check text existence and put all zero texts ids to the end of array - - // Counting leading zeros for futher textid shift - int zeroCount = 0; - for (int j = 0; j < MAX_WAYPOINT_TEXT; ++j) - { - if (!pmItr->second[i].behavior->textid[j]) - { - ++zeroCount; - continue; - } - else - { - if (!objmgr.GetTrinityStringLocale(pmItr->second[i].behavior->textid[j])) - { - sLog.outErrorDb("ERROR: Some waypoint has textid%u with not existing %u text.", j, pmItr->second[i].behavior->textid[j]); - pmItr->second[i].behavior->textid[j] = 0; - ++zeroCount; - continue; - } - else - ids.erase(pmItr->second[i].behavior->textid[j]); - - // Shifting check - if (zeroCount) - { - // Correct textid but some zeros leading, so move it forward. - pmItr->second[i].behavior->textid[j-zeroCount] = pmItr->second[i].behavior->textid[j]; - pmItr->second[i].behavior->textid[j] = 0; - } - } - } - } - } + fields = result->Fetch(); + uint32 id = fields[0].GetUInt32(); + + WaypointData *wp = new WaypointData; + + float x,y,z; + x = fields[2].GetFloat(); + y = fields[3].GetFloat(); + z = fields[4].GetFloat(); + + Trinity::NormalizeMapCoord(x); + Trinity::NormalizeMapCoord(y); + + wp->id = fields[1].GetUInt32(); + wp->x = x; + wp->y = y; + wp->z = z; + wp->run = fields[5].GetBool(); + wp->delay = fields[6].GetUInt32(); + wp->event_id = fields[7].GetUInt32(); + wp->event_chance = fields[8].GetUInt8(); + + path_data->push_back(wp); + + }while (result->NextRow()); + + waypoint_map[id] = path_data; + + delete result; } diff --git a/src/game/WaypointManager.h b/src/game/WaypointManager.h index 38cf5551d64..ec6d46c3b31 100644 --- a/src/game/WaypointManager.h +++ b/src/game/WaypointManager.h @@ -22,72 +22,40 @@ #define TRINITY_WAYPOINTMANAGER_H #include <vector> -#include <string> -#include "Utilities/UnorderedMap.h" -#define MAX_WAYPOINT_TEXT 5 -struct WaypointBehavior +struct WaypointData { - uint32 emote; - uint32 spell; - int32 textid[MAX_WAYPOINT_TEXT]; - uint32 model1; - uint32 model2; - - bool isEmpty(); - WaypointBehavior() {} - WaypointBehavior(const WaypointBehavior &b); -}; - -struct WaypointNode -{ - float x; - float y; - float z; - float orientation; + uint32 id; + float x,y,z; + bool run; uint32 delay; - WaypointBehavior * behavior; - WaypointNode() {} - WaypointNode(float _x, float _y, float _z, float _o, uint32 _delay, WaypointBehavior * _behavior) - : x(_x), y(_y), z(_z), orientation(_o), delay(_delay), behavior(_behavior) {} + uint32 event_id; + uint8 event_chance; }; -typedef std::vector<WaypointNode> WaypointPath; +typedef std::vector<WaypointData*> WaypointPath; +extern UNORDERED_MAP<uint32, WaypointPath*> waypoint_map; -class WaypointManager +class WaypointStore { - public: - WaypointManager() {} - ~WaypointManager() { Unload(); } - - void Load(); - void Unload(); - - void Cleanup(); - - WaypointPath *GetPath(uint32 id) + private : + uint32 records; + + public: + void UpdatePath(uint32 id); + void Load(); + void Free(); + + WaypointPath* GetPath(uint32 id) { - WaypointPathMap::iterator itr = m_pathMap.find(id); - return itr != m_pathMap.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); - void DeleteNode(uint32 id, uint32 point); - void DeletePath(uint32 id); - void SetNodePosition(uint32 id, uint32 point, float x, float y, float z); - void SetNodeText(uint32 id, uint32 point, const char *text_field, const char *text); - void CheckTextsExistance(std::set<int32>& ids); - - private: - void _addNode(uint32 id, uint32 point, float x, float y, float z, float o, uint32 delay, uint32 wpGuid); - void _clearPath(WaypointPath &path); - - typedef UNORDERED_MAP<uint32, WaypointPath> WaypointPathMap; - WaypointPathMap m_pathMap; + if(waypoint_map.find(id) != waypoint_map.end()) + return waypoint_map[id]; + else return 0; + } + + inline uint32 GetRecordsCount() { return records; } }; -#define WaypointMgr Trinity::Singleton<WaypointManager>::Instance() +extern WaypointStore WaypointMgr; #endif diff --git a/src/game/WaypointMovementGenerator.cpp b/src/game/WaypointMovementGenerator.cpp index 3dc3ddebf42..84f121eb9b3 100644 --- a/src/game/WaypointMovementGenerator.cpp +++ b/src/game/WaypointMovementGenerator.cpp @@ -1,8 +1,6 @@ /* * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/> * - * Copyright (C) 2008 Trinity <http://www.trinitycore.org/> - * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -10,209 +8,187 @@ * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* -creature_movement Table - -alter table creature_movement add `textid1` int(11) NOT NULL default '0'; -alter table creature_movement add `textid2` int(11) NOT NULL default '0'; -alter table creature_movement add `textid3` int(11) NOT NULL default '0'; -alter table creature_movement add `textid4` int(11) NOT NULL default '0'; -alter table creature_movement add `textid5` int(11) NOT NULL default '0'; -alter table creature_movement add `emote` int(10) unsigned default '0'; -alter table creature_movement add `spell` int(5) unsigned default '0'; -alter table creature_movement add `wpguid` int(11) default '0'; - -*/ - +//Basic header #include <ctime> #include "WaypointMovementGenerator.h" +//Accessors +#include "Database/DatabaseEnv.h" #include "ObjectMgr.h" +#include "World.h" +//Creature-specific headers #include "Creature.h" -#include "DestinationHolderImp.h" #include "CreatureAI.h" -#include "WaypointManager.h" +//Player-Specific +#include "Player.h" +//Visual +#include "ProgressBar.h" +#include "MapManager.h" -#include <cassert> +template<class T> +void +WaypointMovementGenerator<T>::Initialize(T &u){} -//-----------------------------------------------// +template<> void -WaypointMovementGenerator<Creature>::LoadPath(Creature &c) +WaypointMovementGenerator<Creature>::Initialize(Creature &u) { - sLog.outDetail("LoadPath: loading waypoint path for creature %d,%d", c.GetGUIDLow(), c.GetDBTableGUIDLow()); + i_currentNode = -1; + u.StopMoving(); + if(!path_id) + path_id = u.GetWaypointPath(); + waypoints = WaypointMgr.GetPath(path_id); +} - i_path = WaypointMgr.GetPath(c.GetDBTableGUIDLow()); - if(!i_path) - { - sLog.outErrorDb("WaypointMovementGenerator::LoadPath: creature %s (Entry: %u GUID: %d) doesn't have waypoint path", - c.GetName(), c.GetEntry(), c.GetDBTableGUIDLow()); - return; - } +template<> +void +WaypointMovementGenerator<Creature>::Finalize(Creature &u){} + +template<> +void +WaypointMovementGenerator<Player>::Finalize(Player &u){} - uint32 node_count = i_path->size(); - i_hasDone.resize(node_count); - for(uint32 i = 0; i < node_count-1; i++) - i_hasDone[i] = false; +template<class T> +void +WaypointMovementGenerator<T>::MovementInform(T &unit){} - // to prevent a misbehaviour inside "update" - // update is always called with the next wp - but the wpSys needs the current - // so when the routine is called the first time, wpSys gets the last waypoint - // and this prevents the system from performing text/emote, etc - i_hasDone[node_count - 1] = true; +template<> +void WaypointMovementGenerator<Creature>::MovementInform(Creature &unit) +{ + unit.AI()->MovementInform(WAYPOINT_MOTION_TYPE, i_currentNode); } -void -WaypointMovementGenerator<Creature>::ClearWaypoints() +template<> +void WaypointMovementGenerator<Creature>::Reset(Creature &unit){} + +template<> +void WaypointMovementGenerator<Player>::Reset(Player &unit){} + +template<> +void WaypointMovementGenerator<Creature>::InitTraveller(Creature &unit, const WaypointData &node) { - i_path = NULL; + node.run ? unit.RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE): unit.AddUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); + + unit.SetUInt32Value(UNIT_NPC_EMOTESTATE, 0); + unit.SetUInt32Value(UNIT_FIELD_BYTES_1, 0); + + if(unit.canFly()) + unit.AddUnitMovementFlag(MOVEMENTFLAG_FLYING2); + + unit.addUnitState(UNIT_STAT_ROAMING); } -void -WaypointMovementGenerator<Creature>::Initialize() +template<> +void WaypointMovementGenerator<Player>::InitTraveller(Player &unit, const WaypointData &node){} + +template<class T> +bool +WaypointMovementGenerator<T>::Update(T &unit, const uint32 &diff) { + return false; } +template<> bool -WaypointMovementGenerator<Creature>::Update(Creature &creature, const uint32 &diff) +WaypointMovementGenerator<Creature>::Update(Creature &unit, const uint32 &diff) { - if(!&creature) + if(!&unit) return true; - // Waypoint movement can be switched on/off + if(!path_id) + return false; + + // Waypoint movement can be switched on/off // This is quite handy for escort quests and other stuff - if(creature.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DISTRACTED)) - return true; + if(unit.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DISTRACTED)) + return true; - // prevent a crash at empty waypoint path. - if(!i_path || i_path->empty()) - return true; + // Clear the generator if the path doesn't exist + if(!waypoints || !waypoints->size()) + return false; - // i_path was modified by chat commands for example - if(i_path->size() != i_hasDone.size()) - i_hasDone.resize(i_path->size()); - if(i_currentNode >= i_path->size()) - i_currentNode = 0; + Traveller<Creature> traveller(unit); - CreatureTraveller traveller(creature); - - i_nextMoveTime.Update(diff); + i_nextMoveTime.Update(diff); i_destinationHolder.UpdateTraveller(traveller, diff, false, true); - // creature has been stoped in middle of the waypoint segment - if (!i_destinationHolder.HasArrived() && creature.IsStopped()) - { - if( i_nextMoveTime.Passed()) // Timer has elapsed, meaning this part controlled it - { - SetStopedByPlayer(false); - // Now we re-set destination to same node and start travel - creature.addUnitState(UNIT_STAT_ROAMING); - if (creature.canFly()) - creature.AddUnitMovementFlag(MOVEMENTFLAG_FLYING2); - const WaypointNode &node = i_path->at(i_currentNode); - i_destinationHolder.SetDestination(traveller, node.x, node.y, node.z); - i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime()); - } - else // if( !i_nextMoveTime.Passed()) - { // unexpected end of timer && creature stopped && not at end of segment - if (!IsStopedByPlayer()) - { // Put 30 seconds delay - i_destinationHolder.IncreaseTravelTime(STOP_TIME_FOR_PLAYER); - i_nextMoveTime.Reset(STOP_TIME_FOR_PLAYER); - SetStopedByPlayer(true); // Mark we did it - } - } - return true; // Abort here this update + if(i_nextMoveTime.Passed()) + { + if(unit.IsStopped()) + { + if(StopedByPlayer) + { + InitTraveller(unit,node); + i_destinationHolder.SetDestination(traveller, node.x, node.y, node.z); + i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime()); + StopedByPlayer = false; + return true; + } + + if(i_currentNode == waypoints->size() - 1) //If that's our last waypoint + { + if(repeating) //If the movement is repeating + i_currentNode = 0; //Start moving all over again + else + { + unit.GetMotionMaster()->Initialize(); + return false; //Clear the waypoint movement + } + } + else + i_currentNode++; + + node = *(waypoints->at(i_currentNode)); + InitTraveller(unit,node); + i_destinationHolder.SetDestination(traveller, node.x, node.y, node.z); + i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime()); + } + else + { + //Determine waittime + if(node.delay) + i_nextMoveTime.Reset(node.delay); + else + i_nextMoveTime.Reset(100); //Prevents some lag + + if(node.event_id && rand()%100 < node.event_chance && !ExecuteScript) + { + sWorld.ScriptsStart(sWaypointScripts, node.event_id, &unit, NULL); + ExecuteScript = true; + } + + MovementInform(unit); + unit.UpdateWaypointID(i_currentNode); + traveller.Relocation(node.x, node.y, node.z); + unit.clearUnitState(UNIT_STAT_MOVING); + } } - - if( creature.IsStopped()) - { - uint32 idx = i_currentNode > 0 ? i_currentNode-1 : i_path->size()-1; - - if (!i_hasDone[idx]) - { - if (i_path->at(idx).orientation !=100) - creature.SetOrientation(i_path->at(idx).orientation); - - if(WaypointBehavior *behavior = i_path->at(idx).behavior) - { - if(behavior->emote != 0) - creature.SetUInt32Value(UNIT_NPC_EMOTESTATE,behavior->emote); - if(behavior->spell != 0) - creature.CastSpell(&creature,behavior->spell, false); - if(behavior->model1 != 0) - creature.SetDisplayId(behavior->model1); - if(behavior->textid[0]) - { - // Not only one text is set - if( behavior->textid[1] ) - { - // Select one from max 5 texts (0 and 1 already checked) - int i = 2; - for( ; i < MAX_WAYPOINT_TEXT; ++i ) - if( !behavior->textid[i] ) - break; - - creature.Say(behavior->textid[rand() % i], 0, 0); - } - else - creature.Say(behavior->textid[0], 0, 0); - } - } // wpBehaviour found - i_hasDone[idx] = true; - MovementInform(creature); - } // HasDone == false - } // i_creature.IsStopped() - - if( i_nextMoveTime.Passed() ) // This is at the end of waypoint segment or has been stopped by player - { - if( creature.IsStopped() ) // If stopped then begin a new move segment - { - creature.addUnitState(UNIT_STAT_ROAMING); - if (creature.canFly()) - creature.AddUnitMovementFlag(MOVEMENTFLAG_FLYING2); - const WaypointNode &node = i_path->at(i_currentNode); - i_destinationHolder.SetDestination(traveller, node.x, node.y, node.z); - i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime()); - uint32 idx = i_currentNode > 0 ? i_currentNode-1 : i_path->size()-1; - - if (i_path->at(idx).orientation !=100) - creature.SetOrientation(i_path->at(idx).orientation); - - if(WaypointBehavior *behavior = i_path->at(idx).behavior ) - { - i_hasDone[idx] = false; - if(behavior->model2 != 0) - creature.SetDisplayId(behavior->model2); - - creature.SetUInt32Value(UNIT_NPC_EMOTESTATE, 0); - } - } - else // If not stopped then stop it and set the reset of TimeTracker to waittime - { - creature.StopMoving(); - SetStopedByPlayer(false); - i_nextMoveTime.Reset(i_path->at(i_currentNode).delay); - ++i_currentNode; - if( i_currentNode >= i_path->size() ) - i_currentNode = 0; - } - } - return true; + else + { + if(unit.IsStopped() && !i_destinationHolder.HasArrived()) + { + if(!StopedByPlayer) + { + i_destinationHolder.IncreaseTravelTime(STOP_TIME_FOR_PLAYER); + i_nextMoveTime.Reset(STOP_TIME_FOR_PLAYER); + StopedByPlayer = true; + } + } + } + return true; } -void WaypointMovementGenerator<Creature>::MovementInform(Creature &unit) -{ - if(unit.AI()) - unit.AI()->MovementInform(WAYPOINT_MOTION_TYPE, i_currentNode); -} +template void WaypointMovementGenerator<Player>::Initialize(Player &); +template bool WaypointMovementGenerator<Player>::Update(Player &, const uint32 &); +template void WaypointMovementGenerator<Player>::MovementInform(Player &); //----------------------------------------------------// void diff --git a/src/game/WaypointMovementGenerator.h b/src/game/WaypointMovementGenerator.h index 86e1b0beea3..78752c771f0 100644 --- a/src/game/WaypointMovementGenerator.h +++ b/src/game/WaypointMovementGenerator.h @@ -50,64 +50,41 @@ class TRINITY_DLL_SPEC PathMovementBase inline bool MovementInProgress(void) const { return i_currentNode < i_path.Size(); } - // template pattern, not defined .. override required void LoadPath(T &); void ReloadPath(T &); uint32 GetCurrentNode() const { return i_currentNode; } - + protected: uint32 i_currentNode; DestinationHolder< Traveller<T> > i_destinationHolder; P i_path; }; -/** WaypointMovementGenerator loads a series of way points - * from the DB and apply it to the creature's movement generator. - * Hence, the creature will move according to its predefined way points. - */ - template<class T> -class TRINITY_DLL_SPEC WaypointMovementGenerator; -template<> -class TRINITY_DLL_SPEC WaypointMovementGenerator<Creature> -: public MovementGeneratorMedium< Creature, WaypointMovementGenerator<Creature> >, -public PathMovementBase<Creature, WaypointPath*> +class TRINITY_DLL_SPEC WaypointMovementGenerator + : public MovementGeneratorMedium< T, WaypointMovementGenerator<T> >, public PathMovementBase<T> { - TimeTrackerSmall i_nextMoveTime; - std::vector<bool> i_hasDone; - public: - WaypointMovementGenerator(Creature &) : i_nextMoveTime(0) {} - ~WaypointMovementGenerator() { ClearWaypoints(); } - void Initialize(Creature &u) - { - i_nextMoveTime.Reset(0); // TODO: check the lower bound (0 is probably too small) - u.StopMoving(); - LoadPath(u); - } - void Finalize(Creature &) {} - void Reset(Creature &u) { ReloadPath(u); } - bool Update(Creature &u, const uint32 &diff); - - void MovementInform(Creature &); - - MovementGeneratorType GetMovementGeneratorType() { return WAYPOINT_MOTION_TYPE; } - - // now path movement implmementation - void LoadPath(Creature &c); - void ReloadPath(Creature &c) { ClearWaypoints(); LoadPath(c); } - - // Player stoping creature - bool IsStopedByPlayer() { return b_StopedByPlayer; } - void SetStopedByPlayer(bool val) { b_StopedByPlayer = val; } - - // statics - static void Initialize(void); - - bool GetDestination(float& x, float& y, float& z) const { i_destinationHolder.GetDestination(x,y,z); return true; } - private: - void ClearWaypoints(); - bool b_StopedByPlayer; + public: + WaypointMovementGenerator(uint32 _path_id = 0, bool _repeating = true) : + i_nextMoveTime(0), path_id(_path_id), repeating(_repeating), StopedByPlayer(false){} + + void Initialize(T &); + void Finalize(T &); + void MovementInform(T &); + void InitTraveller(T &, const WaypointData &); + void GeneratePathId(T &); + void Reset(T &unit); + bool Update(T &, const uint32 &); + bool GetDestination(float &x, float &y, float &z) const{if(i_destinationHolder.HasArrived())return false; i_destinationHolder.GetDestination(x, y, z); return true;} + MovementGeneratorType GetMovementGeneratorType() { return WAYPOINT_MOTION_TYPE; } + + private: + WaypointData node; + uint32 i_currentNode, path_id; + TimeTrackerSmall i_nextMoveTime; + WaypointPath *waypoints; + bool repeating, custom_path, ExecuteScript, StopedByPlayer; }; /** FlightPathMovementGenerator generates movement of the player for the paths @@ -135,6 +112,7 @@ public PathMovementBase<Player> inline bool HasArrived() const { return (i_currentNode >= i_path.Size()); } void SetCurrentNodeAfterTeleport(); void SkipCurrentNode() { ++i_currentNode; } - bool GetDestination(float& x, float& y, float& z) const { i_destinationHolder.GetDestination(x,y,z); return true; } + bool GetDestination(float& x, float& y, float& z) const { i_destinationHolder.GetDestination(x,y,z); return true; } + }; #endif |