diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/game/Chat.cpp | 30 | ||||
-rw-r--r-- | src/game/Chat.h | 18 | ||||
-rw-r--r-- | src/game/Creature.cpp | 4 | ||||
-rw-r--r-- | src/game/Creature.h | 18 | ||||
-rw-r--r-- | src/game/Level2.cpp | 2277 | ||||
-rw-r--r-- | src/game/Level3.cpp | 27 | ||||
-rw-r--r-- | src/game/MotionMaster.cpp | 25 | ||||
-rw-r--r-- | src/game/MotionMaster.h | 1 | ||||
-rw-r--r-- | src/game/MovementGeneratorImpl.h | 3 | ||||
-rw-r--r-- | src/game/ObjectMgr.cpp | 16 | ||||
-rw-r--r-- | src/game/ObjectMgr.h | 2 | ||||
-rw-r--r-- | src/game/RandomMovementGenerator.h | 2 | ||||
-rw-r--r-- | src/game/WaypointManager.cpp | 494 | ||||
-rw-r--r-- | src/game/WaypointManager.h | 154 | ||||
-rw-r--r-- | src/game/WaypointMovementGenerator.cpp | 1282 | ||||
-rw-r--r-- | src/game/WaypointMovementGenerator.h | 258 | ||||
-rw-r--r-- | src/game/World.cpp | 30 | ||||
-rw-r--r-- | src/game/World.h | 1 | ||||
-rw-r--r-- | src/shared/Database/SQLStorage.cpp | 4 |
19 files changed, 2231 insertions, 2415 deletions
diff --git a/src/game/Chat.cpp b/src/game/Chat.cpp index 951f443e479..745a2f6e268 100644 --- a/src/game/Chat.cpp +++ b/src/game/Chat.cpp @@ -134,15 +134,18 @@ ChatCommand * ChatHandler::getCommandTable() { NULL, 0, false, NULL, "", NULL } }; - static ChatCommand wpCommandTable[] = - { - { "show", SEC_GAMEMASTER, false, &ChatHandler::HandleWpShowCommand, "", NULL }, - { "add", SEC_GAMEMASTER, false, &ChatHandler::HandleWpAddCommand, "", NULL }, - { "modify", SEC_GAMEMASTER, false, &ChatHandler::HandleWpModifyCommand, "", NULL }, - { "export", SEC_ADMINISTRATOR, false, &ChatHandler::HandleWpExportCommand, "", NULL }, - { "import", SEC_ADMINISTRATOR, false, &ChatHandler::HandleWpImportCommand, "", NULL }, - { NULL, 0, false, NULL, "", NULL } - }; + static ChatCommand wpCommandTable[] =
+ {
+ { "show", SEC_GAMEMASTER, false, &ChatHandler::HandleWpShowCommand, "", NULL },
+ { "addwp", SEC_GAMEMASTER, false, &ChatHandler::HandleWpAddCommand, "", NULL },
+ { "load", SEC_GAMEMASTER, false, &ChatHandler::HandleWpLoadPathCommand, "", NULL },
+ { "modify", SEC_GAMEMASTER, false, &ChatHandler::HandleWpModifyCommand, "", NULL },
+ { "event", SEC_GAMEMASTER, false, &ChatHandler::HandleWpEventCommand, "", NULL },
+ { "unload", SEC_GAMEMASTER, false, &ChatHandler::HandleWpUnLoadPathCommand, "", NULL },
+
+ { NULL, 0, false, NULL, "", NULL }
+ };
+ static ChatCommand banCommandTable[] = { @@ -293,6 +296,7 @@ ChatCommand * ChatHandler::getCommandTable() { "locales_npc_text", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesNpcTextCommand, "", NULL }, { "locales_page_text", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesPageTextCommand, "", NULL }, { "locales_quest", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesQuestCommand, "", NULL }, + { "waypoint_scripts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadWpScriptsCommand, "", NULL }, { "", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } @@ -507,8 +511,12 @@ ChatCommand * ChatHandler::getCommandTable() { "event", SEC_GAMEMASTER, false, NULL, "", eventCommandTable }, { "gobject", SEC_GAMEMASTER, false, NULL, "", gobjectCommandTable }, { "honor", SEC_GAMEMASTER, false, NULL, "", honorCommandTable }, - { "wp", SEC_GAMEMASTER, false, NULL, "", wpCommandTable }, - { "quest", SEC_ADMINISTRATOR, false, NULL, "", questCommandTable }, + + //wp commands
+ { "path", SEC_GAMEMASTER, false, NULL, "", wpCommandTable },
+ { "loadpath", SEC_ADMINISTRATOR, false, &ChatHandler::HandleReloadAllPaths, "", NULL },
+ + { "quest", SEC_ADMINISTRATOR, false, NULL, "", questCommandTable }, { "reload", SEC_ADMINISTRATOR, true, NULL, "", reloadCommandTable }, { "list", SEC_ADMINISTRATOR, true, NULL, "", listCommandTable }, { "lookup", SEC_ADMINISTRATOR, true, NULL, "", lookupCommandTable }, diff --git a/src/game/Chat.h b/src/game/Chat.h index b62bae39d17..faa84b032b9 100644 --- a/src/game/Chat.h +++ b/src/game/Chat.h @@ -211,7 +211,8 @@ class ChatHandler bool HandleReloadConfigCommand(const char* args); - bool HandleReloadAreaTriggerTavernCommand(const char* args); + bool HandleReloadWpScriptsCommand(const char* args); + bool HandleReloadAreaTriggerTavernCommand(const char* args); bool HandleReloadAreaTriggerTeleportCommand(const char* args); bool HandleReloadEventScriptsCommand(const char* args); bool HandleReloadCommandCommand(const char* args); @@ -410,11 +411,16 @@ class ChatHandler bool HandlePasswordCommand(const char* args); bool HandleLockAccountCommand(const char* args); bool HandleRespawnCommand(const char* args); - bool HandleWpAddCommand(const char* args); - bool HandleWpModifyCommand(const char* args); - bool HandleWpShowCommand(const char* args); - bool HandleWpExportCommand(const char* args); - bool HandleWpImportCommand(const char* args); +
+ //New Wp Commands
+ bool HandleWpAddCommand(const char* args);
+ bool HandleWpLoadPathCommand(const char* args);
+ bool HandleWpUnLoadPathCommand(const char* args);
+ bool HandleWpModifyCommand(const char* args);
+ bool HandleWpEventCommand(const char* args);
+ bool HandleWpShowCommand(const char* args);
+ bool HandleReloadAllPaths(const char *args);
+ bool HandleFlyModeCommand(const char* args); bool HandleSendOpcodeCommand(const char* args); bool HandleSellErrorCommand(const char* args); diff --git a/src/game/Creature.cpp b/src/game/Creature.cpp index 80eba6fde98..4f8132fe404 100644 --- a/src/game/Creature.cpp +++ b/src/game/Creature.cpp @@ -2068,6 +2068,10 @@ bool Creature::LoadCreaturesAddon(bool reload) if (cainfo->move_flags != 0) SetUnitMovementFlags(cainfo->move_flags); + //Load Path
+ if (cainfo->path_id != 0)
+ m_path_id = cainfo->path_id;
+ if(cainfo->auras) { for (CreatureDataAddonAura const* cAura = cainfo->auras; cAura->spell_id; ++cAura) diff --git a/src/game/Creature.h b/src/game/Creature.h index 31386d3b180..fce9854e6cf 100644 --- a/src/game/Creature.h +++ b/src/game/Creature.h @@ -279,7 +279,8 @@ struct CreatureDataAddonAura struct CreatureDataAddon { uint32 guidOrEntry; - uint32 mount; + uint32 path_id; + uint32 mount; uint32 bytes0; uint32 bytes1; uint32 bytes2; @@ -616,7 +617,14 @@ class TRINITY_DLL_SPEC Creature : public Unit void GetCombatStartPosition(float &x, float &y, float &z) { x = CombatStartX; y = CombatStartY; z = CombatStartZ; } uint32 GetGlobalCooldown() const { return m_GlobalCooldown; } - protected: + + uint32 GetWaypointPath(){return m_path_id;}
+ void LoadPath(uint32 pathid) { m_path_id = pathid; }
+
+ uint32 GetCurrentWaypointID(){return m_waypointID;}
+ void UpdateWaypointID(uint32 wpID){m_waypointID = wpID;}
+ + protected: bool CreateFromProto(uint32 guidlow,uint32 Entry,uint32 team, const CreatureData *data = NULL); bool InitEntry(uint32 entry, uint32 team=ALLIANCE, const CreatureData* data=NULL); @@ -666,7 +674,11 @@ class TRINITY_DLL_SPEC Creature : public Unit float CombatStartZ; private: - GridReference<Creature> m_gridRef; + //WaypointMovementGenerator vars
+ uint32 m_waypointID;
+ uint32 m_path_id;
+ + GridReference<Creature> m_gridRef; CreatureInfo const* m_creatureInfo; // in heroic mode can different from ObjMgr::GetCreatureTemplate(GetEntry()) }; diff --git a/src/game/Level2.cpp b/src/game/Level2.cpp index bb6a4473e0b..a9e74926a76 100644 --- a/src/game/Level2.cpp +++ b/src/game/Level2.cpp @@ -1371,11 +1371,9 @@ bool ChatHandler::HandleNpcAddMoveCommand(const char* args) Player* player = m_session->GetPlayer(); - WaypointMgr.AddLastNode(lowguid, player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), player->GetOrientation(), wait, 0); - // update movement type WorldDatabase.PExecuteLog("UPDATE creature SET MovementType = '%u' WHERE guid = '%u'", WAYPOINT_MOTION_TYPE,lowguid); - if(pCreature) + if(pCreature && pCreature->GetWaypointPath()) { pCreature->SetDefaultMovementType(WAYPOINT_MOTION_TYPE); pCreature->GetMotionMaster()->Initialize(); @@ -1387,8 +1385,6 @@ bool ChatHandler::HandleNpcAddMoveCommand(const char* args) pCreature->SaveToDB(); } - SendSysMessage(LANG_WAYPOINT_ADDED); - return true; } @@ -1507,13 +1503,13 @@ bool ChatHandler::HandleNpcSetMoveTypeCommand(const char* args) else return false; - // update movement type - if(doNotDelete == false) - WaypointMgr.DeletePath(lowguid); - if(pCreature) { - pCreature->SetDefaultMovementType(move_type); + // update movement type + if(doNotDelete == false) + pCreature->LoadPath(0); + + pCreature->SetDefaultMovementType(move_type); pCreature->GetMotionMaster()->Initialize(); if(pCreature->isAlive()) // dead creature will reset movement generator at respawn { @@ -2159,1151 +2155,1122 @@ bool ChatHandler::HandleNpcSpawnTimeCommand(const char* args) return true; } - -/** - * Add a waypoint to a creature. - * - * The user can either select an npc or provide its GUID. - * - * The user can even select a visual waypoint - then the new waypoint - * is placed *after* the selected one - this makes insertion of new - * waypoints possible. - * - * eg: - * .wp add 12345 - * -> adds a waypoint to the npc with the GUID 12345 - * - * .wp add - * -> adds a waypoint to the currently selected creature - * - * - * @param args if the user did not provide a GUID, it is NULL - * - * @return true - command did succeed, false - something went wrong - */ -bool ChatHandler::HandleWpAddCommand(const char* args) -{ - sLog.outDebug("DEBUG: HandleWpAddCommand"); - - // optional - char* guid_str = NULL; - - if(*args) - { - guid_str = strtok((char*)args, " "); - } - - uint32 lowguid = 0; - uint32 point = 0; - Creature* target = getSelectedCreature(); - // Did player provide a GUID? - if (!guid_str) - { - sLog.outDebug("DEBUG: HandleWpAddCommand - No GUID provided"); - - // No GUID provided - // -> Player must have selected a creature - - if(!target || target->isPet()) - { - SendSysMessage(LANG_SELECT_CREATURE); - SetSentErrorMessage(true); - return false; - } - if (target->GetEntry() == VISUAL_WAYPOINT ) - { - sLog.outDebug("DEBUG: HandleWpAddCommand - target->GetEntry() == VISUAL_WAYPOINT (1) "); - - QueryResult *result = - WorldDatabase.PQuery( "SELECT id, point FROM creature_movement WHERE wpguid = %u", - target->GetGUIDLow() ); - if(!result) - { - PSendSysMessage(LANG_WAYPOINT_NOTFOUNDSEARCH, target->GetGUIDLow()); - // User selected a visual spawnpoint -> get the NPC - // Select NPC GUID - // Since we compare float values, we have to deal with - // some difficulties. - // Here we search for all waypoints that only differ in one from 1 thousand - // (0.001) - There is no other way to compare C++ floats with mySQL floats - // See also: http://dev.mysql.com/doc/refman/5.0/en/problems-with-float.html - const char* maxDIFF = "0.01"; - result = WorldDatabase.PQuery( "SELECT id, point FROM creature_movement WHERE (abs(position_x - %f) <= %s ) and (abs(position_y - %f) <= %s ) and (abs(position_z - %f) <= %s )", - target->GetPositionX(), maxDIFF, target->GetPositionY(), maxDIFF, target->GetPositionZ(), maxDIFF); - if(!result) - { - PSendSysMessage(LANG_WAYPOINT_NOTFOUNDDBPROBLEM, target->GetGUIDLow()); - SetSentErrorMessage(true); - return false; - } - } - do - { - Field *fields = result->Fetch(); - lowguid = fields[0].GetUInt32(); - point = fields[1].GetUInt32(); - }while( result->NextRow() ); - delete result; - - CreatureData const* data = objmgr.GetCreatureData(lowguid); - if(!data) - { - PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, lowguid); - SetSentErrorMessage(true); - return false; - } - - target = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_NEW_GUID(lowguid,data->id,HIGHGUID_UNIT)); - if(!target) - { - PSendSysMessage(LANG_WAYPOINT_NOTFOUNDDBPROBLEM, lowguid); - SetSentErrorMessage(true); - return false; - } - } - else - { - lowguid = target->GetDBTableGUIDLow(); - } - } - else - { - sLog.outDebug("DEBUG: HandleWpAddCommand - GUID provided"); - - // GUID provided - // Warn if player also selected a creature - // -> Creature selection is ignored <- - if(target) - { - SendSysMessage(LANG_WAYPOINT_CREATSELECTED); - } - lowguid = atoi((char*)guid_str); - - CreatureData const* data = objmgr.GetCreatureData(lowguid); - if(!data) - { - PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, lowguid); - SetSentErrorMessage(true); - return false; - } - - target = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_NEW_GUID(lowguid,data->id,HIGHGUID_UNIT)); - if(!target || target->isPet()) - { - PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, lowguid); - SetSentErrorMessage(true); - return false; - } - } - // lowguid -> GUID of the NPC - // point -> number of the waypoint (if not 0) - sLog.outDebug("DEBUG: HandleWpAddCommand - danach"); - - sLog.outDebug("DEBUG: HandleWpAddCommand - point == 0"); - - Player* player = m_session->GetPlayer(); - WaypointMgr.AddLastNode(lowguid, player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), player->GetOrientation(), 0, 0); - - // update movement type - if(target) - { - target->SetDefaultMovementType(WAYPOINT_MOTION_TYPE); - target->GetMotionMaster()->Initialize(); - if(target->isAlive()) // dead creature will reset movement generator at respawn - { - target->setDeathState(JUST_DIED); - target->Respawn(); - } - target->SaveToDB(); - } - else - WorldDatabase.PExecuteLog("UPDATE creature SET MovementType = '%u' WHERE guid = '%u'", WAYPOINT_MOTION_TYPE,lowguid); - - PSendSysMessage(LANG_WAYPOINT_ADDED, point, lowguid); - - return true; -} // HandleWpAddCommand - -/** - * .wp modify emote | spell | text | del | move | add - * - * add -> add a WP after the selected visual waypoint - * User must select a visual waypoint and then issue ".wp modify add" - * - * emote <emoteID> - * User has selected a visual waypoint before. - * <emoteID> is added to this waypoint. Everytime the - * NPC comes to this waypoint, the emote is called. - * - * emote <GUID> <WPNUM> <emoteID> - * User has not selected visual waypoint before. - * For the waypoint <WPNUM> for the NPC with <GUID> - * an emote <emoteID> is added. - * Everytime the NPC comes to this waypoint, the emote is called. - * - * - * info <GUID> <WPNUM> -> User did not select a visual waypoint and - */ -bool ChatHandler::HandleWpModifyCommand(const char* args) -{ - sLog.outDebug("DEBUG: HandleWpModifyCommand"); - - if(!*args) - return false; - - // first arg: add del text emote spell waittime move - char* show_str = strtok((char*)args, " "); - if (!show_str) - { - return false; - } - - std::string show = show_str; - // Check - // Remember: "show" must also be the name of a column! - if( (show != "emote") && (show != "spell") && (show != "textid1") && (show != "textid2") - && (show != "textid3") && (show != "textid4") && (show != "textid5") - && (show != "waittime") && (show != "del") && (show != "move") && (show != "add") - && (show != "model1") && (show != "model2") && (show != "orientation")) - { - return false; - } - - // Next arg is: <GUID> <WPNUM> <ARGUMENT> - - // Did user provide a GUID - // or did the user select a creature? - // -> variable lowguid is filled with the GUID of the NPC - uint32 lowguid = 0; - uint32 point = 0; - uint32 wpGuid = 0; - Creature* target = getSelectedCreature(); - - if(target) - { - sLog.outDebug("DEBUG: HandleWpModifyCommand - User did select an NPC"); - - // Did the user select a visual spawnpoint? - if (target->GetEntry() != VISUAL_WAYPOINT ) - { - PSendSysMessage(LANG_WAYPOINT_VP_SELECT); - SetSentErrorMessage(true); - return false; - } - - wpGuid = target->GetGUIDLow(); - - // The visual waypoint - QueryResult *result = - WorldDatabase.PQuery( "SELECT id, point FROM creature_movement WHERE wpguid = %u LIMIT 1", - target->GetGUIDLow() ); - if(!result) - { - PSendSysMessage(LANG_WAYPOINT_NOTFOUNDDBPROBLEM, wpGuid); - SetSentErrorMessage(true); - return false; - } - sLog.outDebug("DEBUG: HandleWpModifyCommand - After getting wpGuid"); - - Field *fields = result->Fetch(); - lowguid = fields[0].GetUInt32(); - point = fields[1].GetUInt32(); - - // Cleanup memory - sLog.outDebug("DEBUG: HandleWpModifyCommand - Cleanup memory"); - delete result; - } - else - { - // User did provide <GUID> <WPNUM> - - char* guid_str = strtok((char*)NULL, " "); - if( !guid_str ) - { - SendSysMessage(LANG_WAYPOINT_NOGUID); - return false; - } - lowguid = atoi((char*)guid_str); - - CreatureData const* data = objmgr.GetCreatureData(lowguid); - if(!data) - { - PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, lowguid); - SetSentErrorMessage(true); - return false; - } - - PSendSysMessage("DEBUG: GUID provided: %d", lowguid); - - char* point_str = strtok((char*)NULL, " "); - if( !point_str ) - { - SendSysMessage(LANG_WAYPOINT_NOWAYPOINTGIVEN); - return false; - } - point = atoi((char*)point_str); - - PSendSysMessage("DEBUG: wpNumber provided: %d", point); - - // Now we need the GUID of the visual waypoint - // -> "del", "move", "add" command - - QueryResult *result = WorldDatabase.PQuery( "SELECT wpguid FROM creature_movement WHERE id = '%u' AND point = '%u' LIMIT 1", lowguid, point); - if (!result) - { - PSendSysMessage(LANG_WAYPOINT_NOTFOUNDSEARCH, lowguid, point); - SetSentErrorMessage(true); - return false; - } - - Field *fields = result->Fetch(); - wpGuid = fields[0].GetUInt32(); - - // Free memory - delete result; - } - - char* arg_str = NULL; - // Check for argument - if( (show.find("text") == std::string::npos ) && (show != "del") && (show != "move") && (show != "add")) - { - // Text is enclosed in "<>", all other arguments not - if( show.find("text") != std::string::npos ) - arg_str = strtok((char*)NULL, "<>"); - else - arg_str = strtok((char*)NULL, " "); - - if( !arg_str) - { - PSendSysMessage(LANG_WAYPOINT_ARGUMENTREQ, show_str); - return false; - } - } - - sLog.outDebug("DEBUG: HandleWpModifyCommand - Parameters parsed - now execute the command"); - - // wpGuid -> GUID of the waypoint creature - // lowguid -> GUID of the NPC - // point -> waypoint number - - // Special functions: - // add - move - del -> no args commands - // Add a waypoint after the selected visual - if(show == "add" && target) - { - PSendSysMessage("DEBUG: wp modify add, GUID: %u", lowguid); - - // Get the creature for which we read the waypoint - CreatureData const* data = objmgr.GetCreatureData(lowguid); - if(!data) - { - PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, lowguid); - SetSentErrorMessage(true); - return false; - } - - Creature* npcCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), MAKE_NEW_GUID(lowguid, data->id, HIGHGUID_UNIT)); - - if( !npcCreature ) - { - PSendSysMessage(LANG_WAYPOINT_NPCNOTFOUND); - SetSentErrorMessage(true); - return false; - } - - sLog.outDebug("DEBUG: HandleWpModifyCommand - add -- npcCreature"); - - // What to do: - // Add the visual spawnpoint (DB only) - // Adjust the waypoints - // Respawn the owner of the waypoints - sLog.outDebug("DEBUG: HandleWpModifyCommand - add"); - - Player* chr = m_session->GetPlayer(); - Map *map = chr->GetMap(); - - if(npcCreature) - { - npcCreature->GetMotionMaster()->Initialize(); - if(npcCreature->isAlive()) // dead creature will reset movement generator at respawn - { - npcCreature->setDeathState(JUST_DIED); - npcCreature->Respawn(); - } - } - - // create the waypoint creature - wpGuid = 0; - Creature* wpCreature = new Creature; - if (!wpCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map,VISUAL_WAYPOINT,0)) - { - PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, VISUAL_WAYPOINT); - delete wpCreature; - } - else - { - wpCreature->Relocate(chr->GetPositionX(), chr->GetPositionY(), chr->GetPositionZ(), chr->GetOrientation()); - - if(!wpCreature->IsPositionValid()) - { - sLog.outError("ERROR: Creature (guidlow %d, entry %d) not created. Suggested coordinates isn't valid (X: %f Y: %f)",wpCreature->GetGUIDLow(),wpCreature->GetEntry(),wpCreature->GetPositionX(),wpCreature->GetPositionY()); - delete wpCreature; - } - else - { - wpCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode())); - // To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells(); - wpCreature->LoadFromDB(wpCreature->GetDBTableGUIDLow(), map); - map->Add(wpCreature); - wpGuid = wpCreature->GetGUIDLow(); - } - } - - WaypointMgr.AddAfterNode(lowguid, point, chr->GetPositionX(), chr->GetPositionY(), chr->GetPositionZ(), 0, 0, wpGuid); - - if(!wpGuid) - return false; - - PSendSysMessage(LANG_WAYPOINT_ADDED_NO, point+1); - return true; - } // add - - if(show == "del" && target) - { - PSendSysMessage("DEBUG: wp modify del, GUID: %u", lowguid); - - // Get the creature for which we read the waypoint - CreatureData const* data = objmgr.GetCreatureData(lowguid); - if(!data) - { - PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, lowguid); - SetSentErrorMessage(true); - return false; - } - - Creature* npcCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), MAKE_NEW_GUID(lowguid, data->id, HIGHGUID_UNIT)); - - // wpCreature - Creature* wpCreature = NULL; - if( wpGuid != 0 ) - { - wpCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_NEW_GUID(wpGuid, VISUAL_WAYPOINT, HIGHGUID_UNIT)); - wpCreature->DeleteFromDB(); - wpCreature->CleanupsBeforeDelete(); - wpCreature->AddObjectToRemoveList(); - } - - // What to do: - // Remove the visual spawnpoint - // Adjust the waypoints - // Respawn the owner of the waypoints - - WaypointMgr.DeleteNode(lowguid, point); - - if(npcCreature) - { - // Any waypoints left? - QueryResult *result2 = WorldDatabase.PQuery( "SELECT point FROM creature_movement WHERE id = '%u'",lowguid); - if(!result2) - { - npcCreature->SetDefaultMovementType(RANDOM_MOTION_TYPE); - } - else - { - npcCreature->SetDefaultMovementType(WAYPOINT_MOTION_TYPE); - delete result2; - } - npcCreature->GetMotionMaster()->Initialize(); - if(npcCreature->isAlive()) // dead creature will reset movement generator at respawn - { - npcCreature->setDeathState(JUST_DIED); - npcCreature->Respawn(); - } - npcCreature->SaveToDB(); - } - - PSendSysMessage(LANG_WAYPOINT_REMOVED); - return true; - } // del - - if(show == "move" && target) - { - PSendSysMessage("DEBUG: wp move, GUID: %u", lowguid); - - Player *chr = m_session->GetPlayer(); - Map *map = chr->GetMap(); - { - // Get the creature for which we read the waypoint - CreatureData const* data = objmgr.GetCreatureData(lowguid); - if(!data) - { - PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, lowguid); - SetSentErrorMessage(true); - return false; - } - - Creature* npcCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), MAKE_NEW_GUID(lowguid, data->id, HIGHGUID_UNIT)); - - // wpCreature - Creature* wpCreature = NULL; - // What to do: - // Move the visual spawnpoint - // Respawn the owner of the waypoints - if( wpGuid != 0 ) - { - wpCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_NEW_GUID(wpGuid, VISUAL_WAYPOINT, HIGHGUID_UNIT)); - wpCreature->DeleteFromDB(); - wpCreature->CleanupsBeforeDelete(); - wpCreature->AddObjectToRemoveList(); - // re-create - Creature* wpCreature2 = new Creature; - if (!wpCreature2->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map, VISUAL_WAYPOINT, 0)) - { - PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, VISUAL_WAYPOINT); - delete wpCreature2; - return false; - } - - wpCreature2->Relocate(chr->GetPositionX(), chr->GetPositionY(), chr->GetPositionZ(), chr->GetOrientation()); - - if(!wpCreature2->IsPositionValid()) - { - sLog.outError("ERROR: Creature (guidlow %d, entry %d) not created. Suggested coordinates isn't valid (X: %f Y: %f)",wpCreature2->GetGUIDLow(),wpCreature2->GetEntry(),wpCreature2->GetPositionX(),wpCreature2->GetPositionY()); - delete wpCreature2; - return false; - } - - wpCreature2->SaveToDB(map->GetId(), (1 << map->GetSpawnMode())); - // To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells(); - wpCreature2->LoadFromDB(wpCreature2->GetDBTableGUIDLow(), map); - map->Add(wpCreature2); - //MapManager::Instance().GetMap(npcCreature->GetMapId())->Add(wpCreature2); - } - - WaypointMgr.SetNodePosition(lowguid, point, chr->GetPositionX(), chr->GetPositionY(), chr->GetPositionZ()); - - if(npcCreature) - { - npcCreature->GetMotionMaster()->Initialize(); - if(npcCreature->isAlive()) // dead creature will reset movement generator at respawn - { - npcCreature->setDeathState(JUST_DIED); - npcCreature->Respawn(); - } - } - PSendSysMessage(LANG_WAYPOINT_CHANGED); - } - return true; - } // move - - // Create creature - npc that has the waypoint - CreatureData const* data = objmgr.GetCreatureData(lowguid); - if(!data) - { - PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, lowguid); - SetSentErrorMessage(true); - return false; - } - - // set in game textids not supported - if( show == "textid1" || show == "textid2" || show == "textid3" || - show == "textid4" || show == "textid5" ) - { - return false; - } - - WaypointMgr.SetNodeText(lowguid, point, show_str, arg_str); - - Creature* npcCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), MAKE_NEW_GUID(lowguid, data->id, HIGHGUID_UNIT)); - if(npcCreature) - { - npcCreature->SetDefaultMovementType(WAYPOINT_MOTION_TYPE); - npcCreature->GetMotionMaster()->Initialize(); - if(npcCreature->isAlive()) // dead creature will reset movement generator at respawn - { - npcCreature->setDeathState(JUST_DIED); - npcCreature->Respawn(); - } - } - PSendSysMessage(LANG_WAYPOINT_CHANGED_NO, show_str); - - return true; -} - -/** - * .wp show info | on | off - * - * info -> User has selected a visual waypoint before - * - * info <GUID> <WPNUM> -> User did not select a visual waypoint and - * provided the GUID of the NPC and the number of - * the waypoint. - * - * on -> User has selected an NPC; all visual waypoints for this - * NPC are added to the world - * - * on <GUID> -> User did not select an NPC - instead the GUID of the - * NPC is provided. All visual waypoints for this NPC - * are added from the world. - * - * off -> User has selected an NPC; all visual waypoints for this - * NPC are removed from the world. - * - * on <GUID> -> User did not select an NPC - instead the GUID of the - * NPC is provided. All visual waypoints for this NPC - * are removed from the world. - * - * - */ -bool ChatHandler::HandleWpShowCommand(const char* args) -{ - sLog.outDebug("DEBUG: HandleWpShowCommand"); - - if(!*args) - return false; - - // first arg: on, off, first, last - char* show_str = strtok((char*)args, " "); - if (!show_str) - { - return false; - } - // second arg: GUID (optional, if a creature is selected) - char* guid_str = strtok((char*)NULL, " "); - sLog.outDebug("DEBUG: HandleWpShowCommand: show_str: %s guid_str: %s", show_str, guid_str); - //if (!guid_str) { - // return false; - //} - - // Did user provide a GUID - // or did the user select a creature? - // -> variable lowguid is filled with the GUID - Creature* target = getSelectedCreature(); - // Did player provide a GUID? - if (!guid_str) - { - sLog.outDebug("DEBUG: HandleWpShowCommand: !guid_str"); - // No GUID provided - // -> Player must have selected a creature - - if(!target) - { - SendSysMessage(LANG_SELECT_CREATURE); - SetSentErrorMessage(true); - return false; - } - } - else - { - sLog.outDebug("DEBUG: HandleWpShowCommand: GUID provided"); - // GUID provided - // Warn if player also selected a creature - // -> Creature selection is ignored <- - if(target) - { - SendSysMessage(LANG_WAYPOINT_CREATSELECTED); - } - - uint32 lowguid = atoi((char*)guid_str); - - CreatureData const* data = objmgr.GetCreatureData(lowguid); - if(!data) - { - PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, lowguid); - SetSentErrorMessage(true); - return false; - } - - target = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_NEW_GUID(lowguid,data->id,HIGHGUID_UNIT)); - - if(!target) - { - PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, lowguid); - SetSentErrorMessage(true); - return false; - } - } - - uint32 lowguid = target->GetDBTableGUIDLow(); - - std::string show = show_str; - uint32 Maxpoint; - - sLog.outDebug("DEBUG: HandleWpShowCommand: lowguid: %u show: %s", lowguid, show_str); - - // Show info for the selected waypoint - if(show == "info") - { - PSendSysMessage("DEBUG: wp info, GUID: %u", lowguid); - - // Check if the user did specify a visual waypoint - if( target->GetEntry() != VISUAL_WAYPOINT ) - { - PSendSysMessage(LANG_WAYPOINT_VP_SELECT); - SetSentErrorMessage(true); - return false; - } - - //PSendSysMessage("wp on, GUID: %u", lowguid); - - //pCreature->GetPositionX(); - - QueryResult *result = - WorldDatabase.PQuery( "SELECT id, point, waittime, emote, spell, textid1, textid2, textid3, textid4, textid5, model1, model2 FROM creature_movement WHERE wpguid = %u", - target->GetGUIDLow() ); - if(!result) - { - // Since we compare float values, we have to deal with - // some difficulties. - // Here we search for all waypoints that only differ in one from 1 thousand - // (0.001) - There is no other way to compare C++ floats with mySQL floats - // See also: http://dev.mysql.com/doc/refman/5.0/en/problems-with-float.html - const char* maxDIFF = "0.01"; - PSendSysMessage(LANG_WAYPOINT_NOTFOUNDSEARCH, target->GetGUID()); - - result = WorldDatabase.PQuery( "SELECT id, point, waittime, emote, spell, textid1, textid2, textid3, textid4, textid5, model1, model2 FROM creature_movement WHERE (abs(position_x - %f) <= %s ) and (abs(position_y - %f) <= %s ) and (abs(position_z - %f) <= %s )", - target->GetPositionX(), maxDIFF, target->GetPositionY(), maxDIFF, target->GetPositionZ(), maxDIFF); - if(!result) - { - PSendSysMessage(LANG_WAYPOINT_NOTFOUNDDBPROBLEM, lowguid); - SetSentErrorMessage(true); - return false; - } - } - do - { - Field *fields = result->Fetch(); - uint32 creGUID = fields[0].GetUInt32(); - uint32 point = fields[1].GetUInt32(); - int waittime = fields[2].GetUInt32(); - uint32 emote = fields[3].GetUInt32(); - uint32 spell = fields[4].GetUInt32(); - uint32 textid[MAX_WAYPOINT_TEXT]; - for(int i = 0; i < MAX_WAYPOINT_TEXT; ++i) - textid[i] = fields[5+i].GetUInt32(); - uint32 model1 = fields[10].GetUInt32(); - uint32 model2 = fields[11].GetUInt32(); - - // Get the creature for which we read the waypoint - Creature* wpCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_NEW_GUID(creGUID,VISUAL_WAYPOINT,HIGHGUID_UNIT)); - - PSendSysMessage(LANG_WAYPOINT_INFO_TITLE, point, (wpCreature ? wpCreature->GetName() : "<not found>"), creGUID); - PSendSysMessage(LANG_WAYPOINT_INFO_WAITTIME, waittime); - PSendSysMessage(LANG_WAYPOINT_INFO_MODEL, 1, model1); - PSendSysMessage(LANG_WAYPOINT_INFO_MODEL, 2, model2); - PSendSysMessage(LANG_WAYPOINT_INFO_EMOTE, emote); - PSendSysMessage(LANG_WAYPOINT_INFO_SPELL, spell); - for(int i = 0; i < MAX_WAYPOINT_TEXT; ++i) - PSendSysMessage(LANG_WAYPOINT_INFO_TEXT, i+1, textid[i], (textid[i] ? GetTrinityString(textid[i]) : "")); - - }while( result->NextRow() ); - // Cleanup memory - delete result; - return true; - } - - if(show == "on") - { - PSendSysMessage("DEBUG: wp on, GUID: %u", lowguid); - - QueryResult *result = WorldDatabase.PQuery( "SELECT point, position_x,position_y,position_z FROM creature_movement WHERE id = '%u'",lowguid); - if(!result) - { - PSendSysMessage(LANG_WAYPOINT_NOTFOUND, lowguid); - SetSentErrorMessage(true); - return false; - } - // Delete all visuals for this NPC - QueryResult *result2 = WorldDatabase.PQuery( "SELECT wpguid FROM creature_movement WHERE id = '%u' and wpguid <> 0", lowguid); - if(result2) - { - bool hasError = false; - do - { - Field *fields = result2->Fetch(); - uint32 wpguid = fields[0].GetUInt32(); - Creature* pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_NEW_GUID(wpguid,VISUAL_WAYPOINT,HIGHGUID_UNIT)); - - if(!pCreature) - { - PSendSysMessage(LANG_WAYPOINT_NOTREMOVED, wpguid); - hasError = true; - WorldDatabase.PExecuteLog("DELETE FROM creature WHERE guid = '%u'", wpguid); - } - else - { - pCreature->DeleteFromDB(); - pCreature->CleanupsBeforeDelete(); - pCreature->AddObjectToRemoveList(); - } - - }while( result2->NextRow() ); - delete result2; - if( hasError ) - { - PSendSysMessage(LANG_WAYPOINT_TOOFAR1); - PSendSysMessage(LANG_WAYPOINT_TOOFAR2); - PSendSysMessage(LANG_WAYPOINT_TOOFAR3); - } - } - - do - { - Field *fields = result->Fetch(); - uint32 point = fields[0].GetUInt32(); - float x = fields[1].GetFloat(); - float y = fields[2].GetFloat(); - float z = fields[3].GetFloat(); - - uint32 id = VISUAL_WAYPOINT; - - Player *chr = m_session->GetPlayer(); - Map *map = chr->GetMap(); - float o = chr->GetOrientation(); - - Creature* wpCreature = new Creature; - if (!wpCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map, id, 0)) - { - PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, id); - delete wpCreature; - delete result; - return false; - } - - wpCreature->Relocate(x, y, z, o); - - if(!wpCreature->IsPositionValid()) - { - sLog.outError("ERROR: Creature (guidlow %d, entry %d) not created. Suggested coordinates isn't valid (X: %f Y: %f)",wpCreature->GetGUIDLow(),wpCreature->GetEntry(),wpCreature->GetPositionX(),wpCreature->GetPositionY()); - delete wpCreature; - delete result; - return false; - } - - wpCreature->SetVisibility(VISIBILITY_OFF); - sLog.outDebug("DEBUG: UPDATE creature_movement SET wpguid = '%u"); - // set "wpguid" column to the visual waypoint - WorldDatabase.PExecuteLog("UPDATE creature_movement SET wpguid = '%u' WHERE id = '%u' and point = '%u'", wpCreature->GetGUIDLow(), lowguid, point); - - wpCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode())); - // To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells(); - wpCreature->LoadFromDB(wpCreature->GetDBTableGUIDLow(),map); - map->Add(wpCreature); - //MapManager::Instance().GetMap(wpCreature->GetMapId())->Add(wpCreature); - }while( result->NextRow() ); - - // Cleanup memory - delete result; - return true; - } - - if(show == "first") - { - PSendSysMessage("DEBUG: wp first, GUID: %u", lowguid); - - QueryResult *result = WorldDatabase.PQuery( "SELECT position_x,position_y,position_z FROM creature_movement WHERE point='1' AND id = '%u'",lowguid); - if(!result) - { - PSendSysMessage(LANG_WAYPOINT_NOTFOUND, lowguid); - SetSentErrorMessage(true); - return false; - } - - Field *fields = result->Fetch(); - float x = fields[0].GetFloat(); - float y = fields[1].GetFloat(); - float z = fields[2].GetFloat(); - uint32 id = VISUAL_WAYPOINT; - - Player *chr = m_session->GetPlayer(); - float o = chr->GetOrientation(); - Map *map = chr->GetMap(); - - Creature* pCreature = new Creature; - if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT),map, id, 0)) - { - PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, id); - delete pCreature; - delete result; - return false; - } - - pCreature->Relocate(x, y, z, o); - - if(!pCreature->IsPositionValid()) - { - sLog.outError("ERROR: Creature (guidlow %d, entry %d) not created. Suggested coordinates isn't valid (X: %f Y: %f)",pCreature->GetGUIDLow(),pCreature->GetEntry(),pCreature->GetPositionX(),pCreature->GetPositionY()); - delete pCreature; - delete result; - return false; - } - - pCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode())); - pCreature->LoadFromDB(pCreature->GetDBTableGUIDLow(), map); - map->Add(pCreature); - //player->PlayerTalkClass->SendPointOfInterest(x, y, 6, 6, 0, "First Waypoint"); - - // Cleanup memory - delete result; - return true; - } - - if(show == "last") - { - PSendSysMessage("DEBUG: wp last, GUID: %u", lowguid); - - QueryResult *result = WorldDatabase.PQuery( "SELECT MAX(point) FROM creature_movement WHERE id = '%u'",lowguid); - if( result ) - { - Maxpoint = (*result)[0].GetUInt32(); - - delete result; - } - else - Maxpoint = 0; - - result = WorldDatabase.PQuery( "SELECT position_x,position_y,position_z FROM creature_movement WHERE point ='%u' AND id = '%u'",Maxpoint, lowguid); - if(!result) - { - PSendSysMessage(LANG_WAYPOINT_NOTFOUNDLAST, lowguid); - SetSentErrorMessage(true); - return false; - } - Field *fields = result->Fetch(); - float x = fields[0].GetFloat(); - float y = fields[1].GetFloat(); - float z = fields[2].GetFloat(); - uint32 id = VISUAL_WAYPOINT; - - Player *chr = m_session->GetPlayer(); - float o = chr->GetOrientation(); - Map *map = chr->GetMap(); - - Creature* pCreature = new Creature; - if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map, id, 0)) - { - PSendSysMessage(LANG_WAYPOINT_NOTCREATED, id); - delete pCreature; - delete result; - return false; - } - - pCreature->Relocate(x, y, z, o); - - if(!pCreature->IsPositionValid()) - { - sLog.outError("ERROR: Creature (guidlow %d, entry %d) not created. Suggested coordinates isn't valid (X: %f Y: %f)",pCreature->GetGUIDLow(),pCreature->GetEntry(),pCreature->GetPositionX(),pCreature->GetPositionY()); - delete pCreature; - delete result; - return false; - } - - pCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode())); - pCreature->LoadFromDB(pCreature->GetDBTableGUIDLow(), map); - map->Add(pCreature); - //player->PlayerTalkClass->SendPointOfInterest(x, y, 6, 6, 0, "Last Waypoint"); - // Cleanup memory - delete result; - return true; - } - - if(show == "off") - { - QueryResult *result = WorldDatabase.PQuery("SELECT guid FROM creature WHERE id = '%d'", VISUAL_WAYPOINT); - if(!result) - { - SendSysMessage(LANG_WAYPOINT_VP_NOTFOUND); - SetSentErrorMessage(true); - return false; - } - bool hasError = false; - do - { - Field *fields = result->Fetch(); - uint32 guid = fields[0].GetUInt32(); - Creature* pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_NEW_GUID(guid,VISUAL_WAYPOINT,HIGHGUID_UNIT)); - - //Creature* pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), guid); - - if(!pCreature) - { - PSendSysMessage(LANG_WAYPOINT_NOTREMOVED, guid); - hasError = true; - WorldDatabase.PExecuteLog("DELETE FROM creature WHERE guid = '%u'", guid); - } - else - { - pCreature->DeleteFromDB(); - pCreature->CleanupsBeforeDelete(); - pCreature->AddObjectToRemoveList(); - } - }while(result->NextRow()); - // set "wpguid" column to "empty" - no visual waypoint spawned - WorldDatabase.PExecuteLog("UPDATE creature_movement SET wpguid = '0'"); - - if( hasError ) - { - PSendSysMessage(LANG_WAYPOINT_TOOFAR1); - PSendSysMessage(LANG_WAYPOINT_TOOFAR2); - PSendSysMessage(LANG_WAYPOINT_TOOFAR3); - } - - SendSysMessage(LANG_WAYPOINT_VP_ALLREMOVED); - // Cleanup memory - delete result; - - return true; - } - - PSendSysMessage("DEBUG: wpshow - no valid command found"); - - return true; -} // HandleWpShowCommand - -bool ChatHandler::HandleWpExportCommand(const char *args) -{ - if(!*args) - return false; - - // Next arg is: <GUID> <ARGUMENT> - - // Did user provide a GUID - // or did the user select a creature? - // -> variable lowguid is filled with the GUID of the NPC - uint32 lowguid = 0; - Creature* target = getSelectedCreature(); - char* arg_str = NULL; - if (target) - { - if (target->GetEntry() != VISUAL_WAYPOINT) - lowguid = target->GetGUIDLow(); - else - { - QueryResult *result = WorldDatabase.PQuery( "SELECT id FROM creature_movement WHERE wpguid = %u LIMIT 1", target->GetGUIDLow() ); - if (!result) - { - PSendSysMessage(LANG_WAYPOINT_NOTFOUNDDBPROBLEM, target->GetGUIDLow()); - return true; - } - Field *fields = result->Fetch(); - lowguid = fields[0].GetUInt32();; - delete result; - } - - arg_str = strtok((char*)args, " "); - } - else - { - // user provided <GUID> - char* guid_str = strtok((char*)args, " "); - if( !guid_str ) - { - SendSysMessage(LANG_WAYPOINT_NOGUID); - return false; - } - lowguid = atoi((char*)guid_str); - - arg_str = strtok((char*)NULL, " "); - } - - if( !arg_str) - { - PSendSysMessage(LANG_WAYPOINT_ARGUMENTREQ, "export"); - return false; - } - - PSendSysMessage("DEBUG: wp export, GUID: %u", lowguid); - - QueryResult *result = WorldDatabase.PQuery( - // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - "SELECT point, position_x, position_y, position_z, orientation, model1, model2, waittime, emote, spell, textid1, textid2, textid3, textid4, textid5, id FROM creature_movement WHERE id = '%u' ORDER BY point", lowguid ); - - if (!result) - { - PSendSysMessage(LANG_WAYPOINT_NOTHINGTOEXPORT); - SetSentErrorMessage(true); - return false; - } - - std::ofstream outfile; - outfile.open (arg_str); - - do - { - Field *fields = result->Fetch(); - - outfile << "INSERT INTO creature_movement "; - outfile << "( id, point, position_x, position_y, position_z, orientation, model1, model2, waittime, emote, spell, textid1, textid2, textid3, textid4, textid5 ) VALUES "; - - outfile << "( "; - outfile << fields[15].GetUInt32(); // id - outfile << ", "; - outfile << fields[0].GetUInt32(); // point - outfile << ", "; - outfile << fields[1].GetFloat(); // position_x - outfile << ", "; - outfile << fields[2].GetFloat(); // position_y - outfile << ", "; - outfile << fields[3].GetUInt32(); // position_z - outfile << ", "; - outfile << fields[4].GetUInt32(); // orientation - outfile << ", "; - outfile << fields[5].GetUInt32(); // model1 - outfile << ", "; - outfile << fields[6].GetUInt32(); // model2 - outfile << ", "; - outfile << fields[7].GetUInt16(); // waittime - outfile << ", "; - outfile << fields[8].GetUInt32(); // emote - outfile << ", "; - outfile << fields[9].GetUInt32(); // spell - outfile << ", "; - outfile << fields[10].GetUInt32(); // textid1 - outfile << ", "; - outfile << fields[11].GetUInt32(); // textid2 - outfile << ", "; - outfile << fields[12].GetUInt32(); // textid3 - outfile << ", "; - outfile << fields[13].GetUInt32(); // textid4 - outfile << ", "; - outfile << fields[14].GetUInt32(); // textid5 - outfile << ");\n "; - - } while( result->NextRow() ); - delete result; - - PSendSysMessage(LANG_WAYPOINT_EXPORTED); - outfile.close(); - - return true; -} - -bool ChatHandler::HandleWpImportCommand(const char *args) -{ - if(!*args) - return false; - - char* arg_str = strtok((char*)args, " "); - if (!arg_str) - return false; - - std::string line; - std::ifstream infile (arg_str); - if (infile.is_open()) - { - while (! infile.eof() ) - { - getline (infile,line); - //cout << line << endl; - QueryResult *result = WorldDatabase.Query(line.c_str()); - delete result; - } - infile.close(); - } - PSendSysMessage(LANG_WAYPOINT_IMPORTED); - - return true; -} +
+/////WAYPOINT COMMANDS
+
+bool ChatHandler::HandleWpAddCommand(const char* args)
+{
+ sLog.outDebug("DEBUG: HandleWpAddCommand");
+
+ // optional
+ char* path_number = NULL;
+ uint32 pathid = 0;
+
+ if(*args)
+ path_number = strtok((char*)args, " ");
+
+ uint32 point = 0;
+ Creature* target = getSelectedCreature();
+
+ if (!path_number)
+ {
+ if(target)
+ pathid = target->GetWaypointPath();
+ else
+ {
+ QueryResult *result = WorldDatabase.PQuery( "SELECT MAX(id) FROM waypoint_data");
+ uint32 maxpathid = result->Fetch()->GetInt32();
+ pathid = maxpathid+1;
+ sLog.outDebug("DEBUG: HandleWpAddCommand - New path started.");
+ PSendSysMessage("%s%s|r", "|cff00ff00", "New path started.");
+
+ }
+ }
+ else
+ pathid = atoi(path_number);
+
+ // path_id -> ID of the Path
+ // point -> number of the waypoint (if not 0)
+
+ if(!pathid)
+ {
+ sLog.outDebug("DEBUG: HandleWpAddCommand - Current creature haven't loaded path.");
+ PSendSysMessage("%s%s|r", "|cffff33ff", "Current creature haven't loaded path.");
+ return true;
+ }
+
+ sLog.outDebug("DEBUG: HandleWpAddCommand - point == 0");
+
+ QueryResult *result = WorldDatabase.PQuery( "SELECT MAX(point) FROM waypoint_data WHERE id = '%u'",pathid);
+
+ if( result )
+ {
+ point = (*result)[0].GetUInt32();
+ delete result;
+ }
+
+ Player* player = m_session->GetPlayer();
+ Map *map = player->GetMap();
+
+ WorldDatabase.PExecuteLog("INSERT INTO waypoint_data (id,point,position_x,position_y,position_z) VALUES ('%u','%u','%f', '%f', '%f')",
+ pathid, point+1, player->GetPositionX(), player->GetPositionY(), player->GetPositionZ());
+
+ PSendSysMessage("%s%s%u%s%u%s|r", "|cff00ff00", "PathID: |r|cff00ffff", pathid, "|r|cff00ff00: Waypoint |r|cff00ffff", point,"|r|cff00ff00 created. ");
+
+ return true;
+} // HandleWpAddCommand
+
+bool ChatHandler::HandleWpLoadPathCommand(const char *args)
+{
+
+ if(!*args)
+ return false;
+
+ // optional
+ char* path_number = NULL;
+
+ if(*args)
+ {
+ path_number = strtok((char*)args, " ");
+ }
+
+ uint32 pathid = 0;
+ uint32 guidlow = 0;
+ Creature* target = getSelectedCreature();
+
+ // Did player provide a path_id?
+ if (!path_number)
+ sLog.outDebug("DEBUG: HandleWpLoadPathCommand - No path number provided");
+
+ if(!target)
+ {
+ SendSysMessage(LANG_SELECT_CREATURE);
+ SetSentErrorMessage(true);
+ return false;
+ }
+ if(target->GetEntry() == 1)
+ {
+ PSendSysMessage("%s%s|r", "|cffff33ff", "You want to load path to a waypoint? Aren't you?");
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ pathid = atoi(path_number);
+ if(!pathid)
+ {
+ PSendSysMessage("%s%s|r", "|cffff33ff", "No vallid path number provided.");
+ return true;
+ }
+
+ guidlow = target->GetGUIDLow();
+
+ QueryResult *result = WorldDatabase.PQuery( "SELECT guid FROM creature_addon WHERE guid = '%u'",guidlow);
+
+ if( result )
+ {
+ WorldDatabase.PExecute("UPDATE creature_addon SET path_id = '%u' WHERE guid = '%u'", pathid, guidlow);
+ delete result;
+ }
+ else
+ WorldDatabase.PExecute("INSERT INTO creature_addon(guid,path_id) VALUES ('%u','%u')", guidlow, pathid);
+
+ WorldDatabase.PExecute("UPDATE creature SET MovementType = '%u' WHERE guid = '%u'", WAYPOINT_MOTION_TYPE, guidlow);
+
+ target->LoadPath(pathid);
+
+ target->SetDefaultMovementType(WAYPOINT_MOTION_TYPE);
+
+ target->GetMotionMaster()->Initialize();
+
+ target->Say("Path loaded.",0,0);
+
+ return true;
+}
+
+
+bool ChatHandler::HandleReloadAllPaths(const char* args)
+{
+if(!*args)
+ return false;
+
+uint32 id = atoi(args);
+
+if(!id)
+ return false;
+
+ PSendSysMessage("%s%s|r|cff00ffff%u|r", "|cff00ff00", "Loading Path: ", id);
+ WaypointMgr.UpdatePath(id);
+ return true;
+}
+
+bool ChatHandler::HandleWpUnLoadPathCommand(const char *args)
+{
+ uint32 guidlow = 0;
+ Creature* target = getSelectedCreature();
+
+ if(!target)
+ {
+ PSendSysMessage("%s%s|r", "|cff33ffff", "You must select target.");
+ return true;
+ }
+
+ if(target->GetCreatureAddon())
+ {
+ if(target->GetCreatureAddon()->path_id != 0)
+ {
+ WorldDatabase.PExecute("DELETE FROM creature_addon WHERE guid = %u", target->GetGUIDLow());
+ target->UpdateWaypointID(0);
+ WorldDatabase.PExecute("UPDATE creature SET MovementType = '%u' WHERE guid = '%u'", IDLE_MOTION_TYPE, guidlow);
+ target->LoadPath(0);
+ target->SetDefaultMovementType(IDLE_MOTION_TYPE);
+ target->GetMotionMaster()->MoveTargetedHome();
+ target->GetMotionMaster()->Initialize();
+ target->Say("Path unloaded.",0,0);
+ return true;
+ }
+ PSendSysMessage("%s%s|r", "|cffff33ff", "Target have no loaded path.");
+ return true;
+ }
+ PSendSysMessage("%s%s|r", "|cffff33ff", "Target have no loaded path.");
+ return true;
+}
+
+bool ChatHandler::HandleWpEventCommand(const char* args)
+{
+if(!*args)
+ return false;
+
+ char* show_str = strtok((char*)args, " ");
+
+ std::string show = show_str;
+
+ // Check
+ if( (show != "add") && (show != "mod") && (show != "del") && (show != "listid")) return false;
+
+
+ if(show == "add")
+ {
+ uint32 id = 0;
+ char* arg_id = strtok(NULL, " ");
+
+ if(arg_id)
+ uint32 id = atoi(arg_id);
+
+ if(id)
+ {
+ QueryResult *result = WorldDatabase.PQuery( "SELECT `id` FROM waypoint_scripts WHERE guid = %u", id);
+
+ if( !result )
+ {
+ WorldDatabase.PExecute("INSERT INTO waypoint_scripts(guid)VALUES(%u)", id);
+ PSendSysMessage("%s%s%u|r", "|cff00ff00", "Wp Event: New waypoint event added: ", id);
+ }
+ else
+ {
+ PSendSysMessage("|cff00ff00Wp Event: You have choosed an existing waypoint script guid: %u|r", id);
+ delete result;
+ }
+ }
+ else
+ {
+ QueryResult *result = WorldDatabase.PQuery( "SELECT MAX(guid) FROM waypoint_scripts");
+ id = result->Fetch()->GetUInt32();
+ WorldDatabase.PExecute("INSERT INTO waypoint_scripts(guid)VALUES(%u)", id+1);
+ PSendSysMessage("%s%s%u|r", "|cff00ff00","Wp Event: New waypoint event added: |r|cff00ffff", id+1);
+ }
+
+ return true;
+ }
+
+
+ if(show == "listid")
+ {
+ uint32 id;
+ char* arg_id = strtok(NULL, " ");
+
+ if(!arg_id)
+ {
+ PSendSysMessage("%s%s|r", "|cff33ffff","Wp Event: You must provide waypoint script id.");
+ return true;
+ }
+
+ id = atoi(arg_id);
+
+ uint32 a2, a3, a4, a5, a6;
+ float a8, a9, a10, a11;
+ char const* a7;
+
+ QueryResult *result = WorldDatabase.PQuery( "SELECT `guid`, `delay`, `command`, `datalong`, `datalong2`, `dataint`, `x`, `y`, `z`, `o` FROM waypoint_scripts WHERE id = %u", id);
+
+ if( !result )
+ {
+ PSendSysMessage("%s%s%u|r", "|cff33ffff", "Wp Event: No waypoint scripts found on id: ", id);
+ return true;
+ }
+
+ Field *fields;
+
+ do
+ {
+ fields = result->Fetch();
+ a2 = fields[0].GetUInt32();
+ a3 = fields[1].GetUInt32();
+ a4 = fields[2].GetUInt32();
+ a5 = fields[3].GetUInt32();
+ a6 = fields[4].GetUInt32();
+ a7 = fields[5].GetString();
+ a8 = fields[6].GetFloat();
+ a9 = fields[7].GetFloat();
+ a10 = fields[8].GetFloat();
+ a11 = fields[9].GetFloat();
+
+ PSendSysMessage("|cffff33ffid:|r|cff00ffff %u|r|cff00ff00, guid: |r|cff00ffff%u|r|cff00ff00, delay: |r|cff00ffff%u|r|cff00ff00, command: |r|cff00ffff%u|r|cff00ff00, datalong: |r|cff00ffff%u|r|cff00ff00, datalong2: |r|cff00ffff%u|r|cff00ff00, datatext: |r|cff00ffff%s|r|cff00ff00, posx: |r|cff00ffff%f|r|cff00ff00, posy: |r|cff00ffff%f|r|cff00ff00, posz: |r|cff00ffff%f|r|cff00ff00, orientation: |r|cff00ffff%f|r", id, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11);
+ }while(result->NextRow());
+
+ delete result;
+ }
+
+ if(show == "del")
+ {
+
+ char* arg_id = strtok(NULL, " ");
+ uint32 id = atoi(arg_id);
+
+ QueryResult *result = WorldDatabase.PQuery( "SELECT `guid` FROM waypoint_scripts WHERE guid = %u", id);
+
+ if( result )
+ {
+
+ WorldDatabase.PExecuteLog("DELETE FROM waypoint_scripts WHERE guid = %u", id);
+ PSendSysMessage("%s%s%u|r","|cff00ff00","Wp Event: Waypoint script removed: ", id);
+ delete result;
+ }
+ else
+ PSendSysMessage("|cffff33ffWp Event: ERROR: you have selected a non existing script: %u|r", id);
+
+ return true;
+ }
+
+
+ if(show == "mod")
+ {
+ char* arg_1 = strtok(NULL," ");
+
+ if(!arg_1)
+ {
+ SendSysMessage("|cffff33ffERROR: Waypoint script guid not present.|r");
+ return true;
+ }
+
+ uint32 id = atoi(arg_1);
+
+ if(!id)
+ {
+ SendSysMessage("|cffff33ffERROR: No vallid waypoint script id not present.|r");
+ return true;
+ }
+
+ char* arg_2 = strtok(NULL," ");
+
+ if(!arg_2)
+ { SendSysMessage("|cffff33ffERROR: No argument present.|r");
+ return true;}
+
+
+ std::string arg_string = arg_2;
+
+
+if( (arg_string != "setid") && (arg_string != "delay") && (arg_string != "command")
+&& (arg_string != "datalong") && (arg_string != "datalong2") && (arg_string != "dataint") && (arg_string != "posx")
+&& (arg_string != "posy") && (arg_string != "posz") && (arg_string != "orientation")
+) { SendSysMessage("|cffff33ffERROR: No valid argument present.|r");
+ return true;}
+
+
+char* arg_3;
+std::string arg_str_2 = arg_2;
+arg_3 = strtok(NULL," ");
+
+if(!arg_3)
+{SendSysMessage("|cffff33ffERROR: No additional argument present.|r");
+ return true;}
+
+float coord;
+
+ if(arg_str_2 == "setid")
+ {
+ uint32 newid = atoi(arg_3);
+ PSendSysMessage("%s%s|r|cff00ffff%u|r|cff00ff00%s|r|cff00ffff%u|r","|cff00ff00","Wp Event: Wypoint scipt guid: ", newid," id changed: ", id);
+ WorldDatabase.PExecuteLog("UPDATE waypoint_scripts SET id='%u' WHERE guid='%u'",
+ newid, id); return true;
+ }
+ else
+ {
+
+ QueryResult *result = WorldDatabase.PQuery("SELECT id FROM waypoint_scripts WHERE guid='%u'",id);
+
+ if(!result)
+ {
+ SendSysMessage("|cffff33ffERROR: You have selected an non existing waypoint script guid.|r");
+ return true;
+ }
+
+ delete result;
+
+if(arg_str_2 == "posx")
+{
+ coord = atof(arg_3);
+ WorldDatabase.PExecuteLog("UPDATE waypoint_scripts SET x='%f' WHERE guid='%u'",
+ coord, id);
+ PSendSysMessage("|cff00ff00Waypoint script:|r|cff00ffff %u|r|cff00ff00 position_x updated.|r", id);
+ return true;
+}else if(arg_str_2 == "posy")
+{
+ coord = atof(arg_3);
+ WorldDatabase.PExecuteLog("UPDATE waypoint_scripts SET y='%f' WHERE guid='%u'",
+ coord, id);
+ PSendSysMessage("|cff00ff00Waypoint script: %u position_y updated.|r", id);
+ return true;
+} else if(arg_str_2 == "posz")
+{
+ coord = atof(arg_3);
+ WorldDatabase.PExecuteLog("UPDATE waypoint_scripts SET z='%f' WHERE guid='%u'",
+ coord, id);
+ PSendSysMessage("|cff00ff00Waypoint script: |r|cff00ffff%u|r|cff00ff00 position_z updated.|r", id);
+ return true;
+} else if(arg_str_2 == "orientation")
+{
+ coord = atof(arg_3);
+ WorldDatabase.PExecuteLog("UPDATE waypoint_scripts SET o='%f' WHERE guid='%u'",
+ coord, id);
+ PSendSysMessage("|cff00ff00Waypoint script: |r|cff00ffff%u|r|cff00ff00 orientation updated.|r", id);
+ return true;
+} else if(arg_str_2 == "dataint")
+{
+ WorldDatabase.PExecuteLog("UPDATE waypoint_scripts SET %s='%u' WHERE guid='%u'",
+ arg_2, atoi(arg_3), id);
+ PSendSysMessage("|cff00ff00Waypoint script: |r|cff00ffff%u|r|cff00ff00 dataint updated.|r", id);
+ return true;
+}else
+{
+ std::string arg_str_3 = arg_3;
+ WorldDatabase.escape_string(arg_str_3);
+ WorldDatabase.PExecuteLog("UPDATE waypoint_scripts SET %s='%s' WHERE guid='%u'",
+ arg_2, arg_str_3.c_str(), id);
+}
+}
+ PSendSysMessage("%s%s|r|cff00ffff%u:|r|cff00ff00 %s %s|r","|cff00ff00","Waypoint script:", id, arg_2,"updated.");
+}
+return true;
+}
+
+bool ChatHandler::HandleWpModifyCommand(const char* args)
+{
+ sLog.outDebug("DEBUG: HandleWpModifyCommand");
+
+ if(!*args)
+ return false;
+
+ // first arg: add del text emote spell waittime move
+ char* show_str = strtok((char*)args, " ");
+ if (!show_str)
+ {
+ return false;
+ }
+
+ std::string show = show_str;
+ // Check
+ // Remember: "show" must also be the name of a column!
+ if( (show != "delay") && (show != "event_id") && (show != "event_chance")
+ && (show != "move_flag") && (show != "del") && (show != "move") && (show != "wpadd")
+ )
+ {
+ return false;
+ }
+
+ // Next arg is: <GUID> <WPNUM> <ARGUMENT>
+ char* arg_str = NULL;
+
+ // Did user provide a GUID
+ // or did the user select a creature?
+ // -> variable lowguid is filled with the GUID of the NPC
+ uint32 pathid = 0;
+ uint32 point = 0;
+ uint32 wpGuid = 0;
+ Creature* target = getSelectedCreature();
+
+ if(target)
+ {
+ sLog.outDebug("DEBUG: HandleWpModifyCommand - User did select an NPC");
+
+ // The visual waypoint
+ Creature* wpCreature = NULL;
+
+ wpGuid = target->GetGUIDLow();
+
+ // Did the user select a visual spawnpoint?
+
+ if(wpGuid)
+ wpCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_NEW_GUID(wpGuid, VISUAL_WAYPOINT, HIGHGUID_UNIT));
+
+ // attempt check creature existence by DB data
+ else
+ {
+
+ QueryResult *result = WorldDatabase.PQuery( "SELECT guid FROM creature_addon WHERE path_id = '%u'",wpGuid);
+ if(!result)
+ {
+ PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, wpGuid);
+ return true;
+ }
+
+ }
+ // User did select a visual waypoint?
+ // Check the creature
+ if (wpCreature->GetEntry() == VISUAL_WAYPOINT )
+ {
+ QueryResult *result =
+ WorldDatabase.PQuery( "SELECT id, point FROM waypoint_data WHERE wpguid = %u",
+ wpGuid);
+ if(!result)
+ {
+ sLog.outDebug("DEBUG: HandleWpModifyCommand - No waypoint found - used 'wpguid'");
+
+ PSendSysMessage(LANG_WAYPOINT_NOTFOUNDSEARCH, target->GetGUIDLow());
+ // Select waypoint number from database
+ // Since we compare float values, we have to deal with
+ // some difficulties.
+ // Here we search for all waypoints that only differ in one from 1 thousand
+ // (0.001) - There is no other way to compare C++ floats with mySQL floats
+ // See also: http://dev.mysql.com/doc/refman/5.0/en/problems-with-float.html
+ const char* maxDIFF = "0.01";
+ result = WorldDatabase.PQuery( "SELECT id, point FROM waypoint_data WHERE (abs(position_x - %f) <= %s ) and (abs(position_y - %f) <= %s ) and (abs(position_z - %f) <= %s )",
+ wpCreature->GetPositionX(), maxDIFF, wpCreature->GetPositionY(), maxDIFF, wpCreature->GetPositionZ(), maxDIFF);
+ if(!result)
+ {
+ PSendSysMessage(LANG_WAYPOINT_NOTFOUNDDBPROBLEM, wpGuid);
+ return true;
+ }
+ }
+ sLog.outDebug("DEBUG: HandleWpModifyCommand - After getting wpGuid");
+
+ do
+ {
+ Field *fields = result->Fetch();
+ pathid = fields[0].GetUInt32();
+ point = fields[1].GetUInt32();
+ }while( result->NextRow() );
+
+ // Cleanup memory
+ sLog.outDebug("DEBUG: HandleWpModifyCommand - Cleanup memory");
+ delete result;
+ // We have the waypoint number and the GUID of the "master npc"
+ // Text is enclosed in "<>", all other arguments not
+
+ arg_str = strtok((char*)NULL, " ");
+
+ }
+ }
+ else
+ {
+ // User did provide <GUID> <WPNUM>
+ char* guid_str = strtok((char*)NULL, " ");
+ char* point_str = strtok((char*)NULL, " ");
+
+ arg_str = strtok((char*)NULL, " ");
+
+ if( !guid_str )
+ {
+ SendSysMessage(LANG_WAYPOINT_NOGUID);
+ return false;
+ }
+
+ if( !point_str )
+ {
+ SendSysMessage(LANG_WAYPOINT_NOWAYPOINTGIVEN);
+ return false;
+ }
+ if( (show != "del") && (show != "move") )
+ {
+ if( !arg_str )
+ {
+ PSendSysMessage(LANG_WAYPOINT_ARGUMENTREQ, show.c_str());
+ return false;
+ }
+ }
+
+ pathid = atoi((char*)guid_str);
+ PSendSysMessage("|cff33ffffDEBUG: GUID provided: %d|r", pathid);
+
+ point = atoi((char*)point_str);
+ PSendSysMessage("|cff33ffffDEBUG: wpNumber provided: %d|r", point);
+
+ // Now we need the GUID of the visual waypoint
+ // -> "del", "move", "add" command
+
+ QueryResult *result = WorldDatabase.PQuery( "SELECT wpguid FROM waypoint_data WHERE id = '%u' AND point = '%u'", pathid, point);
+ if(result)
+ {
+
+ do
+ {
+ Field *fields = result->Fetch();
+ wpGuid = fields[0].GetUInt32();
+ }while( result->NextRow() );
+
+
+ // Free memory
+ delete result;
+ }
+ else
+ {
+ PSendSysMessage(LANG_WAYPOINT_NOTFOUNDSEARCH, pathid, point);
+ // Select waypoint number from database
+ QueryResult *result = WorldDatabase.PQuery( "SELECT position_x,position_y,position_z FROM waypoint_data WHERE point='%d' AND id = '%u'", point, pathid);
+ if(!result)
+ {
+ PSendSysMessage(LANG_WAYPOINT_NOTFOUND, pathid);
+ return true;
+ }
+
+ Field *fields = result->Fetch();
+ float x = fields[0].GetFloat();
+ float y = fields[1].GetFloat();
+ float z = fields[2].GetFloat();
+ // Cleanup memory
+ delete result;
+
+ // Select waypoint number from database
+ // Since we compare float values, we have to deal with
+ // some difficulties.
+ // Here we search for all waypoints that only differ in one from 1 thousand
+ // (0.001) - There is no other way to compare C++ floats with mySQL floats
+ // See also: http://dev.mysql.com/doc/refman/5.0/en/problems-with-float.html
+ const char* maxDIFF = "0.01";
+
+ result = WorldDatabase.PQuery( "SELECT guid FROM creature WHERE (abs(position_x - %f) <= %s ) and (abs(position_y - %f) <= %s ) and (abs(position_z - %f) <= %s ) and id=%d",
+ x, maxDIFF, y, maxDIFF, z, maxDIFF, VISUAL_WAYPOINT);
+ if(!result)
+ {
+
+ PSendSysMessage(LANG_WAYPOINT_WPCREATNOTFOUND, VISUAL_WAYPOINT);
+ return true;
+ }
+ do
+ {
+ Field *fields = result->Fetch();
+ wpGuid = fields[0].GetUInt32();
+ }while( result->NextRow() );
+
+
+ // Free memory
+ delete result;
+
+ }
+ }
+
+ sLog.outDebug("DEBUG: HandleWpModifyCommand - Parameters parsed - now execute the command");
+
+ // Check for argument
+ if((show != "del") && (show != "move"))
+ {
+ if( arg_str == NULL )
+ {
+ PSendSysMessage(LANG_WAYPOINT_ARGUMENTREQ, show_str);
+ return false;
+ }
+ }
+
+ if(show == "del" && target)
+ {
+ PSendSysMessage("|cff00ff00DEBUG: wp modify del, PathID: |r|cff00ffff%u|r", pathid);
+
+ // wpCreature
+
+ Creature* wpCreature = NULL;
+ if( wpGuid != 0 )
+ {
+ wpCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_NEW_GUID(wpGuid, VISUAL_WAYPOINT, HIGHGUID_UNIT));
+ wpCreature->CombatStop();
+ wpCreature->DeleteFromDB();
+ wpCreature->AddObjectToRemoveList();
+ }
+
+ WorldDatabase.PExecuteLog("DELETE FROM waypoint_data WHERE id='%u' AND point='%u'",
+ pathid, point);
+ WorldDatabase.PExecuteLog("UPDATE waypoint_data SET point=point-1 WHERE id='%u' AND point>'%u'",
+ pathid, point);
+
+ PSendSysMessage(LANG_WAYPOINT_REMOVED);
+ return true;
+ } // del
+
+ if(show == "move" && target)
+ {
+ PSendSysMessage("|cff00ff00DEBUG: wp move, PathID: |r|cff00ffff%u|r", pathid);
+
+ Player *chr = m_session->GetPlayer();
+ Map *map = chr->GetMap();
+ {
+ // wpCreature
+ Creature* wpCreature = NULL;
+ // What to do:
+ // Move the visual spawnpoint
+ // Respawn the owner of the waypoints
+ if( wpGuid != 0 )
+ {
+ wpCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_NEW_GUID(wpGuid, VISUAL_WAYPOINT, HIGHGUID_UNIT));
+ wpCreature->CombatStop();
+ wpCreature->DeleteFromDB();
+ wpCreature->AddObjectToRemoveList();
+ // re-create
+ Creature* wpCreature2 = new Creature;
+ if (!wpCreature2->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map, VISUAL_WAYPOINT, 0))
+ {
+ PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, VISUAL_WAYPOINT);
+ delete wpCreature2;
+ return false;
+ }
+ wpCreature2->Relocate(chr->GetPositionX(), chr->GetPositionY(), chr->GetPositionZ(), chr->GetOrientation());
+
+ if(!wpCreature2->IsPositionValid())
+ {
+ sLog.outError("ERROR: Creature (guidlow %d, entry %d) not created. Suggested coordinates isn't valid (X: %f Y: %f)",wpCreature2->GetGUIDLow(),wpCreature2->GetEntry(),wpCreature2->GetPositionX(),wpCreature2->GetPositionY());
+ delete wpCreature2;
+ return false;
+ }
+
+ wpCreature2->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()));
+ // To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells();
+ wpCreature2->LoadFromDB(wpCreature2->GetDBTableGUIDLow(), map);
+ map->Add(wpCreature2);
+ //MapManager::Instance().GetMap(npcCreature->GetMapId())->Add(wpCreature2);
+ }
+
+ WorldDatabase.PExecuteLog("UPDATE waypoint_data SET position_x = '%f',position_y = '%f',position_z = '%f' where id = '%u' AND point='%u'",
+ chr->GetPositionX(), chr->GetPositionY(), chr->GetPositionZ(), pathid, point );
+
+ PSendSysMessage(LANG_WAYPOINT_CHANGED);
+ }
+ return true;
+ } // move
+
+
+ const char *text = arg_str;
+
+ if( text == 0 )
+ {
+ // show_str check for present in list of correct values, no sql injection possible
+ WorldDatabase.PExecuteLog("UPDATE waypoint_data SET %s=NULL WHERE id='%u' AND point='%u'",
+ show_str, pathid, point);
+ }
+ else
+ {
+ // show_str check for present in list of correct values, no sql injection possible
+ std::string text2 = text;
+ WorldDatabase.escape_string(text2);
+ WorldDatabase.PExecuteLog("UPDATE waypoint_data SET %s='%s' WHERE id='%u' AND point='%u'",
+ show_str, text2.c_str(), pathid, point);
+ }
+
+ PSendSysMessage(LANG_WAYPOINT_CHANGED_NO, show_str);
+
+ return true;
+}
+
+
+bool ChatHandler::HandleWpShowCommand(const char* args)
+{
+ sLog.outDebug("DEBUG: HandleWpShowCommand");
+
+ if(!*args)
+ return false;
+
+ // first arg: on, off, first, last
+ char* show_str = strtok((char*)args, " ");
+ if (!show_str)
+ {
+ return false;
+ }
+ // second arg: GUID (optional, if a creature is selected)
+ char* guid_str = strtok((char*)NULL, " ");
+ sLog.outDebug("DEBUG: HandleWpShowCommand: show_str: %s guid_str: %s", show_str, guid_str);
+
+ uint32 pathid = 0;
+ Creature* target = getSelectedCreature();
+
+ // Did player provide a PathID?
+
+ if (!guid_str)
+ {
+ sLog.outDebug("DEBUG: HandleWpShowCommand: !guid_str");
+ // No PathID provided
+ // -> Player must have selected a creature
+
+ if(!target)
+ {
+ SendSysMessage(LANG_SELECT_CREATURE);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ pathid = target->GetWaypointPath();
+ }
+
+ else
+ {
+ sLog.outDebug("|cff00ff00DEBUG: HandleWpShowCommand: PathID provided|r");
+ // PathID provided
+ // Warn if player also selected a creature
+ // -> Creature selection is ignored <-
+ if(target)
+ {
+ SendSysMessage(LANG_WAYPOINT_CREATSELECTED);
+ }
+
+ pathid = atoi((char*)guid_str);
+ }
+
+
+ sLog.outDebug("DEBUG: HandleWpShowCommand: danach");
+
+
+
+ std::string show = show_str;
+ uint32 Maxpoint;
+
+ sLog.outDebug("DEBUG: HandleWpShowCommand: PathID: %u", pathid);
+
+ //PSendSysMessage("wpshow - show: %s", show);
+
+ // Show info for the selected waypoint
+ if(show == "info")
+
+ {
+
+ // Check if the user did specify a visual waypoint
+ if( target->GetEntry() != VISUAL_WAYPOINT )
+
+ {
+ PSendSysMessage(LANG_WAYPOINT_VP_SELECT);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+
+ QueryResult *result = WorldDatabase.PQuery( "SELECT id, point, delay, move_flag, action, action_chance FROM waypoint_data WHERE wpguid = %u", target->GetGUIDLow());
+
+ if(!result)
+
+ {
+ SendSysMessage(LANG_WAYPOINT_NOTFOUNDDBPROBLEM);
+ return true;
+ }
+
+ SendSysMessage("|cff00ffffDEBUG: wp show info:|r");
+
+ do
+ {
+ Field *fields = result->Fetch();
+ pathid = fields[0].GetUInt32();
+ uint32 point = fields[1].GetUInt32();
+ uint32 delay = fields[2].GetUInt32();
+ uint32 flag = fields[3].GetUInt32();
+ uint32 ev_id = fields[4].GetUInt32();
+ uint32 ev_chance = fields[5].GetUInt32();
+
+ PSendSysMessage("|cff00ff00Show info: for current point: |r|cff00ffff%u|r|cff00ff00, Path ID: |r|cff00ffff%u|r", point, pathid);
+ PSendSysMessage("|cff00ff00Show info: delay: |r|cff00ffff%u|r", delay);
+ PSendSysMessage("|cff00ff00Show info: Move flag: |r|cff00ffff%u|r", flag);
+ PSendSysMessage("|cff00ff00Show info: Waypoint event: |r|cff00ffff%u|r", ev_id);
+ PSendSysMessage("|cff00ff00Show info: Event chance: |r|cff00ffff%u|r", ev_chance);
+ }while( result->NextRow() );
+
+ // Cleanup memory
+ delete result;
+ return true;
+ }
+
+ if(show == "on")
+ {
+ QueryResult *result = WorldDatabase.PQuery( "SELECT point, position_x,position_y,position_z FROM waypoint_data WHERE id = '%u'", pathid);
+
+ if(!result)
+ {
+ SendSysMessage("|cffff33ffPath no found.|r");
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ PSendSysMessage("|cff00ff00DEBUG: wp on, PathID: |cff00ffff%u|r", pathid);
+
+ // Delete all visuals for this NPC
+ QueryResult *result2 = WorldDatabase.PQuery( "SELECT wpguid FROM waypoint_data WHERE id = '%u' and wpguid <> 0", pathid);
+
+ if(result2)
+ {
+ bool hasError = false;
+ do
+ {
+ Field *fields = result2->Fetch();
+ uint32 wpguid = fields[0].GetUInt32();
+ Creature* pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_NEW_GUID(wpguid,VISUAL_WAYPOINT,HIGHGUID_UNIT));
+
+ if(!pCreature)
+ {
+ PSendSysMessage(LANG_WAYPOINT_NOTREMOVED, wpguid);
+ hasError = true;
+ WorldDatabase.PExecuteLog("DELETE FROM creature WHERE guid = '%u'", wpguid);
+ }
+ else
+ {
+ pCreature->CombatStop();
+ pCreature->DeleteFromDB();
+ pCreature->AddObjectToRemoveList();
+ }
+
+ }while( result2->NextRow() );
+
+ delete result2;
+
+ if( hasError )
+ {
+ PSendSysMessage(LANG_WAYPOINT_TOOFAR1);
+ PSendSysMessage(LANG_WAYPOINT_TOOFAR2);
+ PSendSysMessage(LANG_WAYPOINT_TOOFAR3);
+ }
+ }
+
+ do
+ {
+ Field *fields = result->Fetch();
+ uint32 point = fields[0].GetUInt32();
+ float x = fields[1].GetFloat();
+ float y = fields[2].GetFloat();
+ float z = fields[3].GetFloat();
+
+ uint32 id = VISUAL_WAYPOINT;
+
+ Player *chr = m_session->GetPlayer();
+ Map *map = chr->GetMap();
+ float o = chr->GetOrientation();
+
+ Creature* wpCreature = new Creature;
+ if (!wpCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map, id, 0))
+ {
+ PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, id);
+ delete wpCreature;
+ delete result;
+ return false;
+ }
+
+ wpCreature->Relocate(x, y, z, o);
+
+ if(!wpCreature->IsPositionValid())
+ {
+ sLog.outError("ERROR: Creature (guidlow %d, entry %d) not created. Suggested coordinates isn't valid (X: %f Y: %f)",wpCreature->GetGUIDLow(),wpCreature->GetEntry(),wpCreature->GetPositionX(),wpCreature->GetPositionY());
+ delete wpCreature;
+ delete result;
+ return false;
+ }
+
+ sLog.outDebug("DEBUG: UPDATE waypoint_data SET wpguid = '%u");
+ // set "wpguid" column to the visual waypoint
+ WorldDatabase.PExecuteLog("UPDATE waypoint_data SET wpguid = '%u' WHERE id = '%u' and point = '%u'", wpCreature->GetGUIDLow(), pathid, point);
+
+ wpCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()));
+ wpCreature->LoadFromDB(wpCreature->GetDBTableGUIDLow(),map);
+ map->Add(wpCreature);
+
+ if(target)
+ {
+ wpCreature->SetDisplayId(target->GetDisplayId());
+ wpCreature->SetFloatValue(OBJECT_FIELD_SCALE_X, 0.5);
+ }
+ }
+ while( result->NextRow() );
+
+ SendSysMessage("|cff00ff00Showing the current creature's path.|r");
+ // Cleanup memory
+ delete result;
+ return true;
+ }
+
+ if(show == "first")
+ {
+ PSendSysMessage("|cff00ff00DEBUG: wp first, GUID: %u|r", pathid);
+
+ QueryResult *result = WorldDatabase.PQuery( "SELECT position_x,position_y,position_z FROM waypoint_data WHERE point='1' AND id = '%u'",pathid);
+ if(!result)
+ {
+ PSendSysMessage(LANG_WAYPOINT_NOTFOUND, pathid);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ Field *fields = result->Fetch();
+ float x = fields[0].GetFloat();
+ float y = fields[1].GetFloat();
+ float z = fields[2].GetFloat();
+ uint32 id = VISUAL_WAYPOINT;
+
+ Player *chr = m_session->GetPlayer();
+ float o = chr->GetOrientation();
+ Map *map = chr->GetMap();
+
+ Creature* pCreature = new Creature;
+ if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT),map, id, 0))
+ {
+ PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, id);
+ delete pCreature;
+ delete result;
+ return false;
+ }
+
+ pCreature->Relocate(x, y, z, o);
+
+ if(!pCreature->IsPositionValid())
+ {
+ sLog.outError("ERROR: Creature (guidlow %d, entry %d) not created. Suggested coordinates isn't valid (X: %f Y: %f)",pCreature->GetGUIDLow(),pCreature->GetEntry(),pCreature->GetPositionX(),pCreature->GetPositionY());
+ delete pCreature;
+ delete result;
+ return false;
+ }
+
+ pCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()));
+ pCreature->LoadFromDB(pCreature->GetDBTableGUIDLow(), map);
+ map->Add(pCreature);
+
+ if(target)
+ {
+ pCreature->SetDisplayId(target->GetDisplayId());
+ pCreature->SetFloatValue(OBJECT_FIELD_SCALE_X, 0.5);
+ }
+
+ // Cleanup memory
+ delete result;
+ return true;
+ }
+
+ if(show == "last")
+ {
+ PSendSysMessage("|cff00ff00DEBUG: wp last, PathID: |r|cff00ffff%u|r", pathid);
+
+ QueryResult *result = WorldDatabase.PQuery( "SELECT MAX(point) FROM waypoint_data WHERE id = '%u'",pathid);
+ if( result )
+ {
+ Maxpoint = (*result)[0].GetUInt32();
+
+ delete result;
+ }
+ else
+ Maxpoint = 0;
+
+ result = WorldDatabase.PQuery( "SELECT position_x,position_y,position_z FROM waypoint_data WHERE point ='%u' AND id = '%u'",Maxpoint, pathid);
+ if(!result)
+ {
+ PSendSysMessage(LANG_WAYPOINT_NOTFOUNDLAST, pathid);
+ SetSentErrorMessage(true);
+ return false;
+ }
+ Field *fields = result->Fetch();
+ float x = fields[0].GetFloat();
+ float y = fields[1].GetFloat();
+ float z = fields[2].GetFloat();
+ uint32 id = VISUAL_WAYPOINT;
+
+ Player *chr = m_session->GetPlayer();
+ float o = chr->GetOrientation();
+ Map *map = chr->GetMap();
+
+ Creature* pCreature = new Creature;
+ if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map, id, 0))
+ {
+ PSendSysMessage(LANG_WAYPOINT_NOTCREATED, id);
+ delete pCreature;
+ delete result;
+ return false;
+ }
+
+ pCreature->Relocate(x, y, z, o);
+
+ if(!pCreature->IsPositionValid())
+ {
+ sLog.outError("ERROR: Creature (guidlow %d, entry %d) not created. Suggested coordinates isn't valid (X: %f Y: %f)",pCreature->GetGUIDLow(),pCreature->GetEntry(),pCreature->GetPositionX(),pCreature->GetPositionY());
+ delete pCreature;
+ delete result;
+ return false;
+ }
+
+ pCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()));
+ pCreature->LoadFromDB(pCreature->GetDBTableGUIDLow(), map);
+ map->Add(pCreature);
+
+ if(target)
+ {
+ pCreature->SetDisplayId(target->GetDisplayId());
+ pCreature->SetFloatValue(OBJECT_FIELD_SCALE_X, 0.5);
+ }
+
+ // Cleanup memory
+ delete result;
+ return true;
+ }
+
+ if(show == "off")
+ {
+ QueryResult *result = WorldDatabase.PQuery("SELECT guid FROM creature WHERE id = '%u'", 1);
+ if(!result)
+ {
+ SendSysMessage(LANG_WAYPOINT_VP_NOTFOUND);
+ SetSentErrorMessage(true);
+ return false;
+ }
+ bool hasError = false;
+ do
+ {
+ Field *fields = result->Fetch();
+ uint32 guid = fields[0].GetUInt32();
+ Creature* pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_NEW_GUID(guid,VISUAL_WAYPOINT,HIGHGUID_UNIT));
+
+ if(!pCreature)
+ {
+ PSendSysMessage(LANG_WAYPOINT_NOTREMOVED, guid);
+ hasError = true;
+ WorldDatabase.PExecuteLog("DELETE FROM creature WHERE guid = '%u'", guid);
+ }
+ else
+ {
+ pCreature->CombatStop();
+
+ pCreature->DeleteFromDB();
+
+ pCreature->AddObjectToRemoveList();
+ }
+ }while(result->NextRow());
+ // set "wpguid" column to "empty" - no visual waypoint spawned
+ WorldDatabase.PExecuteLog("UPDATE waypoint_data SET wpguid = '0'");
+
+ if( hasError )
+ {
+ PSendSysMessage(LANG_WAYPOINT_TOOFAR1);
+ PSendSysMessage(LANG_WAYPOINT_TOOFAR2);
+ PSendSysMessage(LANG_WAYPOINT_TOOFAR3);
+ }
+
+ SendSysMessage(LANG_WAYPOINT_VP_ALLREMOVED);
+ // Cleanup memory
+ delete result;
+
+ return true;
+ }
+
+ PSendSysMessage("|cffff33ffDEBUG: wpshow - no valid command found|r");
+
+ return true;
+}
+
+//////////// WAYPOINT COMMANDS //
//rename characters bool ChatHandler::HandleRenameCommand(const char* args) diff --git a/src/game/Level3.cpp b/src/game/Level3.cpp index 51b9a092ba3..0ead2940ccb 100644 --- a/src/game/Level3.cpp +++ b/src/game/Level3.cpp @@ -136,7 +136,8 @@ bool ChatHandler::HandleReloadAllScriptsCommand(const char*) HandleReloadSpellScriptsCommand("a"); SendGlobalSysMessage("DB tables `*_scripts` reloaded."); HandleReloadDbScriptStringCommand("a"); - return true; + HandleReloadWpScriptsCommand("a"); + return true; } bool ChatHandler::HandleReloadAllSpellCommand(const char*) @@ -535,8 +536,28 @@ bool ChatHandler::HandleReloadEventScriptsCommand(const char* arg) sLog.outString( "Re-Loading Scripts from `event_scripts`..."); objmgr.LoadEventScripts(); - - if(*arg!='a') +
+ if(*arg!='a')
+ SendGlobalSysMessage("DB table `event_scripts` reloaded.");
+
+ return true;
+}
+
+bool ChatHandler::HandleReloadWpScriptsCommand(const char* arg)
+{
+ if(sWorld.IsScriptScheduled())
+ {
+ SendSysMessage("DB scripts used currently, please attempt reload later.");
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ if(*arg!='a')
+ sLog.outString( "Re-Loading Scripts from `event_scripts`...");
+
+ objmgr.LoadWaypointScripts();
+ + if(*arg!='a') SendGlobalSysMessage("DB table `event_scripts` reloaded."); return true; diff --git a/src/game/MotionMaster.cpp b/src/game/MotionMaster.cpp index d3167e180a0..9050c95b651 100644 --- a/src/game/MotionMaster.cpp +++ b/src/game/MotionMaster.cpp @@ -319,6 +319,31 @@ void MotionMaster::Mutate(MovementGenerator *m) push(m); } +void MotionMaster::MovePath(uint32 path_id, bool repeatable)
+{
+ if(!path_id)
+ return;
+ //We set waypoint movement as new default movement generator
+ // clear ALL movement generators (including default)
+ while(!empty())
+ {
+ MovementGenerator *curr = top();
+ curr->Finalize(*i_owner);
+ pop();
+ if( !isStatic( curr ) )
+ delete curr;
+ }
+
+ sLog.outError("attempting to move");
+ //i_owner->GetTypeId()==TYPEID_PLAYER ?
+ //Mutate(new WaypointMovementGenerator<Player>(path_id, repeatable)):
+ Mutate(new WaypointMovementGenerator<Creature>(path_id, repeatable));
+
+ DEBUG_LOG("%s (GUID: %u) start moving over path(Id:%u, repeatable: %s)",
+ i_owner->GetTypeId()==TYPEID_PLAYER ? "Player" : "Creature",
+ i_owner->GetGUIDLow(), path_id, repeatable ? "YES" : "NO" );
+}
+ void MotionMaster::propagateSpeedChange() { Impl::container_type::iterator it = Impl::c.begin(); diff --git a/src/game/MotionMaster.h b/src/game/MotionMaster.h index f6d244db2db..3a17b8e135e 100644 --- a/src/game/MotionMaster.h +++ b/src/game/MotionMaster.h @@ -80,6 +80,7 @@ class TRINITY_DLL_SPEC MotionMaster : private std::stack<MovementGenerator *> void MovePoint(uint32 id, float x,float y,float z); void MoveTaxiFlight(uint32 path, uint32 pathnode); void MoveDistract(uint32 time); + void MovePath(uint32 path_id, bool repeatable); MovementGeneratorType GetCurrentMovementGeneratorType() const; diff --git a/src/game/MovementGeneratorImpl.h b/src/game/MovementGeneratorImpl.h index c8270094b52..43c18ac6866 100644 --- a/src/game/MovementGeneratorImpl.h +++ b/src/game/MovementGeneratorImpl.h @@ -27,7 +27,6 @@ template<class MOVEMENT_GEN> inline MovementGenerator* MovementGeneratorFactory<MOVEMENT_GEN>::Create(void *data) const { - Creature* creature = reinterpret_cast<Creature *>(data); - return (new MOVEMENT_GEN(*creature)); + return (new MOVEMENT_GEN()); } #endif diff --git a/src/game/ObjectMgr.cpp b/src/game/ObjectMgr.cpp index 36d4317b3ec..b640307c64d 100644 --- a/src/game/ObjectMgr.cpp +++ b/src/game/ObjectMgr.cpp @@ -54,6 +54,7 @@ ScriptMapMap sQuestStartScripts; ScriptMapMap sSpellScripts; ScriptMapMap sGameObjectScripts; ScriptMapMap sEventScripts; +ScriptMapMap sWaypointScripts; bool normalizePlayerName(std::string& name) { @@ -4110,6 +4111,19 @@ void ObjectMgr::LoadEventScripts() } } +//Load WP Scripts
+void ObjectMgr::LoadWaypointScripts()
+{
+ LoadScripts(sWaypointScripts, "waypoint_scripts");
+
+ for(ScriptMapMap::const_iterator itr = sWaypointScripts.begin(); itr != sWaypointScripts.end(); ++itr)
+ {
+ QueryResult *query = WorldDatabase.PQuery("SELECT * FROM `waypoint_scripts` WHERE `id` = %u", itr->first);
+ if(!query || !query->GetRowCount())
+ sLog.outErrorDb("There is no waypoint which links to the waypoint script %u", itr->first);
+ }
+}
+ void ObjectMgr::LoadItemTexts() { QueryResult *result = CharacterDatabase.Query("SELECT id, text FROM item_text"); @@ -7481,7 +7495,7 @@ void ObjectMgr::LoadDbScriptStrings() CheckScripts(sGameObjectScripts,ids); CheckScripts(sEventScripts,ids); - WaypointMgr.CheckTextsExistance(ids); + CheckScripts(sWaypointScripts,ids); for(std::set<int32>::const_iterator itr = ids.begin(); itr != ids.end(); ++itr) sLog.outErrorDb( "Table `db_script_string` has unused string id %u", *itr); diff --git a/src/game/ObjectMgr.h b/src/game/ObjectMgr.h index 8c7f8728b0b..7dc6c1f8a9f 100644 --- a/src/game/ObjectMgr.h +++ b/src/game/ObjectMgr.h @@ -98,6 +98,7 @@ extern ScriptMapMap sQuestStartScripts; extern ScriptMapMap sSpellScripts; extern ScriptMapMap sGameObjectScripts; extern ScriptMapMap sEventScripts; +extern ScriptMapMap sWaypointScripts; struct AreaTrigger { @@ -531,6 +532,7 @@ class ObjectMgr void LoadQuestStartScripts(); void LoadEventScripts(); void LoadSpellScripts(); + void LoadWaypointScripts(); bool LoadTrinityStrings(DatabaseType& db, char const* table, int32 min_value, int32 max_value); bool LoadTrinityStrings() { return LoadTrinityStrings(WorldDatabase,"trinity_string",MIN_TRINITY_STRING_ID,MAX_TRINITY_STRING_ID); } diff --git a/src/game/RandomMovementGenerator.h b/src/game/RandomMovementGenerator.h index 229761423e6..2825bc306a8 100644 --- a/src/game/RandomMovementGenerator.h +++ b/src/game/RandomMovementGenerator.h @@ -31,7 +31,7 @@ class TRINITY_DLL_SPEC RandomMovementGenerator : public MovementGeneratorMedium< T, RandomMovementGenerator<T> > { public: - RandomMovementGenerator(const Unit &) : i_nextMoveTime(0) {} + RandomMovementGenerator() : i_nextMoveTime(0) {} void _setRandomLocation(T &); void Initialize(T &); diff --git a/src/game/WaypointManager.cpp b/src/game/WaypointManager.cpp index 831f616060b..501a95f6442 100644 --- a/src/game/WaypointManager.cpp +++ b/src/game/WaypointManager.cpp @@ -1,342 +1,152 @@ -/* - * 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 - * (at your option) any later version. - * - * 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 - * 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 - */ - -#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); - -bool WaypointBehavior::isEmpty() -{ - 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]; -} - -void WaypointManager::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) - { - 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; - } - - 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); -} - -/// - 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 ) - { - 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; - } -} - -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); - - if(!text) - { - 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; - } -} - -void WaypointManager::CheckTextsExistance(std::set<int32>& ids) -{ - WaypointPathMap::iterator pmItr = m_pathMap.begin(); - for ( ; pmItr != m_pathMap.end(); ++pmItr) - { - 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; - } - } - } - } - } -} +/*
+ * 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
+ * (at your option) any later version.
+ *
+ * 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
+ * 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
+ */
+
+#include "Database/DatabaseEnv.h"
+#include "GridDefines.h"
+#include "WaypointManager.h"
+#include "ProgressBar.h"
+#include "MapManager.h"
+
+UNORDERED_MAP<uint32, WaypointPath*> waypoint_map;
+WaypointStore WaypointMgr;
+
+void WaypointStore::Free()
+{
+ waypoint_map.clear();
+}
+
+void WaypointStore::Load()
+{
+ QueryResult *result = WorldDatabase.PQuery("SELECT MAX(`id`) FROM `waypoint_data");
+ if(!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
+ }
+
+ records = (*result)[0].GetUInt32();
+ delete 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)
+ {
+ sLog.outErrorDb("The table `creature_addon` is empty or corrupted");
+ return;
+ }
+
+ WaypointPath* path_data;
+ uint32 total_records = result->GetRowCount();
+
+ barGoLink bar( total_records);
+ Field *fields;
+ uint32 last_id = 0;
+
+ do
+ {
+ 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 WaypointStore::UpdatePath(uint32 id)
+{
+
+ 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
+ {
+ 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..fd7f533e0da 100644 --- a/src/game/WaypointManager.h +++ b/src/game/WaypointManager.h @@ -1,93 +1,61 @@ -/* - * 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 - * (at your option) any later version. - * - * 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 - * 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 - */ - -#ifndef TRINITY_WAYPOINTMANAGER_H -#define TRINITY_WAYPOINTMANAGER_H - -#include <vector> -#include <string> -#include "Utilities/UnorderedMap.h" - -#define MAX_WAYPOINT_TEXT 5 -struct WaypointBehavior -{ - 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 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) {} -}; - -typedef std::vector<WaypointNode> WaypointPath; - -class WaypointManager -{ - public: - WaypointManager() {} - ~WaypointManager() { Unload(); } - - void Load(); - void Unload(); - - void Cleanup(); - - 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; -}; - -#define WaypointMgr Trinity::Singleton<WaypointManager>::Instance() - -#endif +/*
+ * 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
+ * (at your option) any later version.
+ *
+ * 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
+ * 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
+ */
+
+#ifndef TRINITY_WAYPOINTMANAGER_H
+#define TRINITY_WAYPOINTMANAGER_H
+
+#include <vector>
+
+struct WaypointData
+{
+ uint32 id;
+ float x,y,z;
+ bool run;
+ uint32 delay;
+ uint32 event_id;
+ uint8 event_chance;
+};
+
+typedef std::vector<WaypointData*> WaypointPath;
+extern UNORDERED_MAP<uint32, WaypointPath*> waypoint_map;
+
+class WaypointStore
+{
+ private :
+ uint32 records;
+
+ public:
+ void UpdatePath(uint32 id);
+ void Load();
+ void Free();
+
+ WaypointPath* GetPath(uint32 id)
+ {
+ if(waypoint_map.find(id) != waypoint_map.end())
+ return waypoint_map[id];
+ else return 0;
+ }
+
+ inline uint32 GetRecordsCount() { return records; }
+};
+
+extern WaypointStore WaypointMgr;
+
+#endif
diff --git a/src/game/WaypointMovementGenerator.cpp b/src/game/WaypointMovementGenerator.cpp index 3dc3ddebf42..31872ce7f98 100644 --- a/src/game/WaypointMovementGenerator.cpp +++ b/src/game/WaypointMovementGenerator.cpp @@ -1,653 +1,629 @@ -/* - * 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 - * (at your option) any later version. - * - * 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 - * 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 - */ - -/* -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'; - -*/ - -#include <ctime> - -#include "WaypointMovementGenerator.h" -#include "ObjectMgr.h" -#include "Creature.h" -#include "DestinationHolderImp.h" -#include "CreatureAI.h" -#include "WaypointManager.h" - -#include <cassert> - -//-----------------------------------------------// -void -WaypointMovementGenerator<Creature>::LoadPath(Creature &c) -{ - sLog.outDetail("LoadPath: loading waypoint path for creature %d,%d", c.GetGUIDLow(), c.GetDBTableGUIDLow()); - - 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; - } - - uint32 node_count = i_path->size(); - i_hasDone.resize(node_count); - for(uint32 i = 0; i < node_count-1; i++) - i_hasDone[i] = false; - - // 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; -} - -void -WaypointMovementGenerator<Creature>::ClearWaypoints() -{ - i_path = NULL; -} - -void -WaypointMovementGenerator<Creature>::Initialize() -{ -} - -bool -WaypointMovementGenerator<Creature>::Update(Creature &creature, const uint32 &diff) -{ - if(!&creature) - return true; - - // 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; - - // prevent a crash at empty waypoint path. - if(!i_path || i_path->empty()) - return true; - - // 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; - - CreatureTraveller traveller(creature); - - 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( 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; -} - -void WaypointMovementGenerator<Creature>::MovementInform(Creature &unit) -{ - if(unit.AI()) - unit.AI()->MovementInform(WAYPOINT_MOTION_TYPE, i_currentNode); -} - -//----------------------------------------------------// -void -FlightPathMovementGenerator::LoadPath(Player &) -{ - objmgr.GetTaxiPathNodes(i_pathId, i_path,i_mapIds); -} - -uint32 -FlightPathMovementGenerator::GetPathAtMapEnd() const -{ - if(i_currentNode >= i_mapIds.size()) - return i_mapIds.size(); - - uint32 curMapId = i_mapIds[i_currentNode]; - for(uint32 i = i_currentNode; i < i_mapIds.size(); ++i) - { - if(i_mapIds[i] != curMapId) - return i; - } - - return i_mapIds.size(); -} - -void -FlightPathMovementGenerator::Initialize(Player &player) -{ - player.getHostilRefManager().setOnlineOfflineState(false); - player.addUnitState(UNIT_STAT_IN_FLIGHT); - player.SetFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT); - LoadPath(player); - Traveller<Player> traveller(player); - // do not send movement, it was sent already - i_destinationHolder.SetDestination(traveller, i_path[i_currentNode].x, i_path[i_currentNode].y, i_path[i_currentNode].z, false); - - player.SendMonsterMoveByPath(GetPath(),GetCurrentNode(),GetPathAtMapEnd(),MOVEMENTFLAG_WALK_MODE|MOVEMENTFLAG_ONTRANSPORT); -} - -void FlightPathMovementGenerator::Finalize(Player & player) -{ - - float x, y, z; - i_destinationHolder.GetLocationNow(player.GetMapId(), x, y, z); - player.SetPosition(x, y, z, player.GetOrientation()); - - player.clearUnitState(UNIT_STAT_IN_FLIGHT); - player.Unmount(); - player.RemoveFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT); - - if(player.m_taxi.empty()) - { - player.getHostilRefManager().setOnlineOfflineState(true); - if(player.pvpInfo.inHostileArea) - player.CastSpell(&player, 2479, true); - - player.SetUnitMovementFlags(MOVEMENTFLAG_WALK_MODE); - player.StopMoving(); - } -} - -bool -FlightPathMovementGenerator::Update(Player &player, const uint32 &diff) -{ - if( MovementInProgress() ) - { - Traveller<Player> traveller(player); - if( i_destinationHolder.UpdateTraveller(traveller, diff, false) ) - { - i_destinationHolder.ResetUpdate(FLIGHT_TRAVEL_UPDATE); - if( i_destinationHolder.HasArrived() ) - { - uint32 curMap = i_mapIds[i_currentNode]; - ++i_currentNode; - if( MovementInProgress() ) - { - DEBUG_LOG("loading node %u for player %s", i_currentNode, player.GetName()); - if(i_mapIds[i_currentNode]==curMap) - { - // do not send movement, it was sent already - i_destinationHolder.SetDestination(traveller, i_path[i_currentNode].x, i_path[i_currentNode].y, i_path[i_currentNode].z, false); - } - return true; - } - //else HasArrived() - } - else - return true; - } - else - return true; - } - - // we have arrived at the end of the path - return false; -} - -void -FlightPathMovementGenerator::SetCurrentNodeAfterTeleport() -{ - if(i_mapIds.empty()) - return; - - uint32 map0 = i_mapIds[0]; - for(int i = 1; i < i_mapIds.size(); ++i) - { - if(i_mapIds[i]!=map0) - { - i_currentNode = i; - return; - } - } -} - -// -// Unique1's ASTAR Pathfinding Code... For future use & reference... -// - -#ifdef __PATHFINDING__ - -int GetFCost(int to, int num, int parentNum, float *gcost); // Below... - -int ShortenASTARRoute(short int *pathlist, int number) -{ // Wrote this to make the routes a little smarter (shorter)... No point looping back to the same places... Unique1 - short int temppathlist[MAX_PATHLIST_NODES]; - int count = 0; - // int count2 = 0; - int temp, temp2; - int link; - int upto = 0; - - for (temp = number; temp >= 0; temp--) - { - qboolean shortened = qfalse; - - for (temp2 = 0; temp2 < temp; temp2++) - { - for (link = 0; link < nodes[pathlist[temp]].enodenum; link++) - { - if (nodes[pathlist[temp]].links[link].flags & PATH_BLOCKED) - continue; - - //if ((bot->client->ps.eFlags & EF_TANK) && nodes[bot->current_node].links[link].flags & PATH_NOTANKS) //if this path is blocked, skip it - // continue; - - //if (nodes[nodes[pathlist[temp]].links[link].targetNode].origin[2] > nodes[pathlist[temp]].origin[2] + 32) - // continue; - - if (nodes[pathlist[temp]].links[link].targetNode == pathlist[temp2]) - { // Found a shorter route... - //if (OrgVisible(nodes[pathlist[temp2]].origin, nodes[pathlist[temp]].origin, -1)) - { - temppathlist[count] = pathlist[temp2]; - temp = temp2; - ++count; - shortened = qtrue; - } - } - } - } - - if (!shortened) - { - temppathlist[count] = pathlist[temp]; - ++count; - } - } - - upto = count; - - for (temp = 0; temp < count; temp++) - { - pathlist[temp] = temppathlist[upto]; - --upto; - } - - G_Printf("ShortenASTARRoute: Path size reduced from %i to %i nodes...n", number, count); - return count; -} - -/* -=========================================================================== -CreatePathAStar -This function uses the A* pathfinding algorithm to determine the -shortest path between any two nodes. -It's fairly complex, so I'm not really going to explain it much. -Look up A* and binary heaps for more info. -pathlist stores the ideal path between the nodes, in reverse order, -and the return value is the number of nodes in that path -=========================================================================== -*/ -int CreatePathAStar(gentity_t *bot, int from, int to, short int *pathlist) -{ - //all the data we have to hold...since we can't do dynamic allocation, has to be MAX_NODES - //we can probably lower this later - eg, the open list should never have more than at most a few dozen items on it - short int openlist[MAX_NODES+1]; //add 1 because it's a binary heap, and they don't use 0 - 1 is the first used index - float gcost[MAX_NODES]; - int fcost[MAX_NODES]; - char list[MAX_NODES]; //0 is neither, 1 is open, 2 is closed - char because it's the smallest data type - short int parent[MAX_NODES]; - - short int numOpen = 0; - short int atNode, temp, newnode=-1; - qboolean found = qfalse; - int count = -1; - float gc; - int i, u, v, m; - vec3_t vec; - - //clear out all the arrays - memset(openlist, 0, sizeof(short int)*(MAX_NODES+1)); - memset(fcost, 0, sizeof(int)*MAX_NODES); - memset(list, 0, sizeof(char)*MAX_NODES); - memset(parent, 0, sizeof(short int)*MAX_NODES); - memset(gcost, -1, sizeof(float)*MAX_NODES); - - //make sure we have valid data before calculating everything - if ((from == NODE_INVALID) || (to == NODE_INVALID) || (from >= MAX_NODES) || (to >= MAX_NODES) || (from == to)) - return -1; - - openlist[1] = from; //add the starting node to the open list - ++numOpen; - gcost[from] = 0; //its f and g costs are obviously 0 - fcost[from] = 0; - - while (1) - { - if (numOpen != 0) //if there are still items in the open list - { - //pop the top item off of the list - atNode = openlist[1]; - list[atNode] = 2; //put the node on the closed list so we don't check it again - --numOpen; - - openlist[1] = openlist[numOpen+1]; //move the last item in the list to the top position - v = 1; - - //this while loop reorders the list so that the new lowest fcost is at the top again - while (1) - { - u = v; - if ((2*u+1) < numOpen) //if both children exist - { - if (fcost[openlist[u]] >= fcost[openlist[2*u]]) - v = 2*u; - if (fcost[openlist[v]] >= fcost[openlist[2*u+1]]) - v = 2*u+1; - } - else - { - if ((2*u) < numOpen) //if only one child exists - { - if (fcost[openlist[u]] >= fcost[openlist[2*u]]) - v = 2*u; - } - } - - if (u != v) //if they're out of order, swap this item with its parent - { - temp = openlist[u]; - openlist[u] = openlist[v]; - openlist[v] = temp; - } - else - break; - } - - for (i = 0; i < nodes[atNode].enodenum; i++) //loop through all the links for this node - { - newnode = nodes[atNode].links[i].targetNode; - - //if this path is blocked, skip it - if (nodes[atNode].links[i].flags & PATH_BLOCKED) - continue; - //if this path is blocked, skip it - if (bot->client && (bot->client->ps.eFlags & EF_TANK) && nodes[atNode].links[i].flags & PATH_NOTANKS) - continue; - //skip any unreachable nodes - if (bot->client && (nodes[newnode].type & NODE_ALLY_UNREACHABLE) && (bot->client->sess.sessionTeam == TEAM_ALLIES)) - continue; - if (bot->client && (nodes[newnode].type & NODE_AXIS_UNREACHABLE) && (bot->client->sess.sessionTeam == TEAM_AXIS)) - continue; - - if (list[newnode] == 2) //if this node is on the closed list, skip it - continue; - - if (list[newnode] != 1) //if this node is not already on the open list - { - openlist[++numOpen] = newnode; //add the new node to the open list - list[newnode] = 1; - parent[newnode] = atNode; //record the node's parent - - if (newnode == to) //if we've found the goal, don't keep computing paths! - break; //this will break the 'for' and go all the way to 'if (list[to] == 1)' - - //store it's f cost value - fcost[newnode] = GetFCost(to, newnode, parent[newnode], gcost); - - //this loop re-orders the heap so that the lowest fcost is at the top - m = numOpen; - while (m != 1) //while this item isn't at the top of the heap already - { - //if it has a lower fcost than its parent - if (fcost[openlist[m]] <= fcost[openlist[m/2]]) - { - temp = openlist[m/2]; - openlist[m/2] = openlist[m]; - openlist[m] = temp; //swap them - m /= 2; - } - else - break; - } - } - else //if this node is already on the open list - { - gc = gcost[atNode]; - VectorSubtract(nodes[newnode].origin, nodes[atNode].origin, vec); - gc += VectorLength(vec); //calculate what the gcost would be if we reached this node along the current path - - if (gc < gcost[newnode]) //if the new gcost is less (ie, this path is shorter than what we had before) - { - parent[newnode] = atNode; //set the new parent for this node - gcost[newnode] = gc; //and the new g cost - - for (i = 1; i < numOpen; i++) //loop through all the items on the open list - { - if (openlist[i] == newnode) //find this node in the list - { - //calculate the new fcost and store it - fcost[newnode] = GetFCost(to, newnode, parent[newnode], gcost); - - //reorder the list again, with the lowest fcost item on top - m = i; - while (m != 1) - { - //if the item has a lower fcost than it's parent - if (fcost[openlist[m]] < fcost[openlist[m/2]]) - { - temp = openlist[m/2]; - openlist[m/2] = openlist[m]; - openlist[m] = temp; //swap them - m /= 2; - } - else - break; - } - break; //exit the 'for' loop because we already changed this node - } //if - } //for - } //if (gc < gcost[newnode]) - } //if (list[newnode] != 1) --> else - } //for (loop through links) - } //if (numOpen != 0) - else - { - found = qfalse; //there is no path between these nodes - break; - } - - if (list[to] == 1) //if the destination node is on the open list, we're done - { - found = qtrue; - break; - } - } //while (1) - - if (found == qtrue) //if we found a path - { - //G_Printf("%s - path found!n", bot->client->pers.netname); - count = 0; - - temp = to; //start at the end point - while (temp != from) //travel along the path (backwards) until we reach the starting point - { - pathlist[count++] = temp; //add the node to the pathlist and increment the count - temp = parent[temp]; //move to the parent of this node to continue the path - } - - pathlist[count++] = from; //add the beginning node to the end of the pathlist - - #ifdef __BOT_SHORTEN_ROUTING__ - count = ShortenASTARRoute(pathlist, count); // This isn't working... Dunno why.. Unique1 - #endif //__BOT_SHORTEN_ROUTING__ - } - else - { - //G_Printf("^1*** ^4BOT DEBUG^5: (CreatePathAStar) There is no route between node ^7%i^5 and node ^7%i^5.n", from, to); - count = CreateDumbRoute(from, to, pathlist); - - if (count > 0) - { - #ifdef __BOT_SHORTEN_ROUTING__ - count = ShortenASTARRoute(pathlist, count); // This isn't working... Dunno why.. Unique1 - #endif //__BOT_SHORTEN_ROUTING__ - return count; - } - } - - return count; //return the number of nodes in the path, -1 if not found -} - -/* -=========================================================================== -GetFCost -Utility function used by A* pathfinding to calculate the -cost to move between nodes towards a goal. Using the A* -algorithm F = G + H, G here is the distance along the node -paths the bot must travel, and H is the straight-line distance -to the goal node. -Returned as an int because more precision is unnecessary and it -will slightly speed up heap access -=========================================================================== -*/ -int GetFCost(int to, int num, int parentNum, float *gcost) -{ - float gc = 0; - float hc = 0; - vec3_t v; - - if (gcost[num] == -1) - { - if (parentNum != -1) - { - gc = gcost[parentNum]; - VectorSubtract(nodes[num].origin, nodes[parentNum].origin, v); - gc += VectorLength(v); - } - gcost[num] = gc; - } - else - gc = gcost[num]; - - VectorSubtract(nodes[to].origin, nodes[num].origin, v); - hc = VectorLength(v); - - return (int)(gc + hc); -} -#endif //__PATHFINDING__ +/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.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
+ * (at your option) any later version.
+ *
+ * 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
+ * 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
+ */
+
+//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 "CreatureAI.h"
+//Player-Specific
+#include "Player.h"
+//Visual
+#include "ProgressBar.h"
+#include "MapManager.h"
+
+template<class T>
+void
+WaypointMovementGenerator<T>::Initialize(T &u){}
+
+template<>
+void
+WaypointMovementGenerator<Creature>::Initialize(Creature &u)
+{
+ i_currentNode = -1;
+ u.StopMoving();
+ if(!path_id)
+ path_id = u.GetWaypointPath();
+ waypoints = WaypointMgr.GetPath(path_id);
+}
+
+template<>
+void
+WaypointMovementGenerator<Creature>::Finalize(Creature &u){}
+
+template<>
+void
+WaypointMovementGenerator<Player>::Finalize(Player &u){}
+
+template<class T>
+void
+WaypointMovementGenerator<T>::MovementInform(T &unit){}
+
+template<>
+void WaypointMovementGenerator<Creature>::MovementInform(Creature &unit)
+{
+ unit.AI()->MovementInform(WAYPOINT_MOTION_TYPE, i_currentNode);
+}
+
+template<>
+void WaypointMovementGenerator<Creature>::Reset(Creature &unit){}
+
+template<>
+void WaypointMovementGenerator<Player>::Reset(Player &unit){}
+
+template<>
+void WaypointMovementGenerator<Creature>::InitTraveller(Creature &unit, const WaypointData &node)
+{
+ 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);
+}
+
+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 &unit, const uint32 &diff)
+{
+ if(!&unit)
+ return true;
+
+ if(!path_id)
+ return false;
+
+ // Waypoint movement can be switched on/off
+ // This is quite handy for escort quests and other stuff
+ if(unit.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DISTRACTED))
+ return true;
+
+ // Clear the generator if the path doesn't exist
+ if(!waypoints || !waypoints->size())
+ return false;
+
+ Traveller<Creature> traveller(unit);
+
+ i_nextMoveTime.Update(diff);
+ i_destinationHolder.UpdateTraveller(traveller, diff, false, true);
+
+ 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);
+ }
+ }
+ 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;
+}
+
+template void WaypointMovementGenerator<Player>::Initialize(Player &);
+template bool WaypointMovementGenerator<Player>::Update(Player &, const uint32 &);
+template void WaypointMovementGenerator<Player>::MovementInform(Player &);
+
+//----------------------------------------------------//
+void
+FlightPathMovementGenerator::LoadPath(Player &)
+{
+ objmgr.GetTaxiPathNodes(i_pathId, i_path,i_mapIds);
+}
+
+uint32
+FlightPathMovementGenerator::GetPathAtMapEnd() const
+{
+ if(i_currentNode >= i_mapIds.size())
+ return i_mapIds.size();
+
+ uint32 curMapId = i_mapIds[i_currentNode];
+ for(uint32 i = i_currentNode; i < i_mapIds.size(); ++i)
+ {
+ if(i_mapIds[i] != curMapId)
+ return i;
+ }
+
+ return i_mapIds.size();
+}
+
+void
+FlightPathMovementGenerator::Initialize(Player &player)
+{
+ player.getHostilRefManager().setOnlineOfflineState(false);
+ player.addUnitState(UNIT_STAT_IN_FLIGHT);
+ player.SetFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT);
+ LoadPath(player);
+ Traveller<Player> traveller(player);
+ // do not send movement, it was sent already
+ i_destinationHolder.SetDestination(traveller, i_path[i_currentNode].x, i_path[i_currentNode].y, i_path[i_currentNode].z, false);
+
+ player.SendMonsterMoveByPath(GetPath(),GetCurrentNode(),GetPathAtMapEnd(),MOVEMENTFLAG_WALK_MODE|MOVEMENTFLAG_ONTRANSPORT);
+}
+
+void FlightPathMovementGenerator::Finalize(Player & player)
+{
+
+ float x, y, z;
+ i_destinationHolder.GetLocationNow(player.GetMapId(), x, y, z);
+ player.SetPosition(x, y, z, player.GetOrientation());
+
+ player.clearUnitState(UNIT_STAT_IN_FLIGHT);
+ player.Unmount();
+ player.RemoveFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT);
+
+ if(player.m_taxi.empty())
+ {
+ player.getHostilRefManager().setOnlineOfflineState(true);
+ if(player.pvpInfo.inHostileArea)
+ player.CastSpell(&player, 2479, true);
+
+ player.SetUnitMovementFlags(MOVEMENTFLAG_WALK_MODE);
+ player.StopMoving();
+ }
+}
+
+bool
+FlightPathMovementGenerator::Update(Player &player, const uint32 &diff)
+{
+ if( MovementInProgress() )
+ {
+ Traveller<Player> traveller(player);
+ if( i_destinationHolder.UpdateTraveller(traveller, diff, false) )
+ {
+ i_destinationHolder.ResetUpdate(FLIGHT_TRAVEL_UPDATE);
+ if( i_destinationHolder.HasArrived() )
+ {
+ uint32 curMap = i_mapIds[i_currentNode];
+ ++i_currentNode;
+ if( MovementInProgress() )
+ {
+ DEBUG_LOG("loading node %u for player %s", i_currentNode, player.GetName());
+ if(i_mapIds[i_currentNode]==curMap)
+ {
+ // do not send movement, it was sent already
+ i_destinationHolder.SetDestination(traveller, i_path[i_currentNode].x, i_path[i_currentNode].y, i_path[i_currentNode].z, false);
+ }
+ return true;
+ }
+ //else HasArrived()
+ }
+ else
+ return true;
+ }
+ else
+ return true;
+ }
+
+ // we have arrived at the end of the path
+ return false;
+}
+
+void
+FlightPathMovementGenerator::SetCurrentNodeAfterTeleport()
+{
+ if(i_mapIds.empty())
+ return;
+
+ uint32 map0 = i_mapIds[0];
+ for(int i = 1; i < i_mapIds.size(); ++i)
+ {
+ if(i_mapIds[i]!=map0)
+ {
+ i_currentNode = i;
+ return;
+ }
+ }
+}
+
+//
+// Unique1's ASTAR Pathfinding Code... For future use & reference...
+//
+
+#ifdef __PATHFINDING__
+
+int GetFCost(int to, int num, int parentNum, float *gcost); // Below...
+
+int ShortenASTARRoute(short int *pathlist, int number)
+{ // Wrote this to make the routes a little smarter (shorter)... No point looping back to the same places... Unique1
+ short int temppathlist[MAX_PATHLIST_NODES];
+ int count = 0;
+ // int count2 = 0;
+ int temp, temp2;
+ int link;
+ int upto = 0;
+
+ for (temp = number; temp >= 0; temp--)
+ {
+ qboolean shortened = qfalse;
+
+ for (temp2 = 0; temp2 < temp; temp2++)
+ {
+ for (link = 0; link < nodes[pathlist[temp]].enodenum; link++)
+ {
+ if (nodes[pathlist[temp]].links[link].flags & PATH_BLOCKED)
+ continue;
+
+ //if ((bot->client->ps.eFlags & EF_TANK) && nodes[bot->current_node].links[link].flags & PATH_NOTANKS) //if this path is blocked, skip it
+ // continue;
+
+ //if (nodes[nodes[pathlist[temp]].links[link].targetNode].origin[2] > nodes[pathlist[temp]].origin[2] + 32)
+ // continue;
+
+ if (nodes[pathlist[temp]].links[link].targetNode == pathlist[temp2])
+ { // Found a shorter route...
+ //if (OrgVisible(nodes[pathlist[temp2]].origin, nodes[pathlist[temp]].origin, -1))
+ {
+ temppathlist[count] = pathlist[temp2];
+ temp = temp2;
+ ++count;
+ shortened = qtrue;
+ }
+ }
+ }
+ }
+
+ if (!shortened)
+ {
+ temppathlist[count] = pathlist[temp];
+ ++count;
+ }
+ }
+
+ upto = count;
+
+ for (temp = 0; temp < count; temp++)
+ {
+ pathlist[temp] = temppathlist[upto];
+ --upto;
+ }
+
+ G_Printf("ShortenASTARRoute: Path size reduced from %i to %i nodes...n", number, count);
+ return count;
+}
+
+/*
+===========================================================================
+CreatePathAStar
+This function uses the A* pathfinding algorithm to determine the
+shortest path between any two nodes.
+It's fairly complex, so I'm not really going to explain it much.
+Look up A* and binary heaps for more info.
+pathlist stores the ideal path between the nodes, in reverse order,
+and the return value is the number of nodes in that path
+===========================================================================
+*/
+int CreatePathAStar(gentity_t *bot, int from, int to, short int *pathlist)
+{
+ //all the data we have to hold...since we can't do dynamic allocation, has to be MAX_NODES
+ //we can probably lower this later - eg, the open list should never have more than at most a few dozen items on it
+ short int openlist[MAX_NODES+1]; //add 1 because it's a binary heap, and they don't use 0 - 1 is the first used index
+ float gcost[MAX_NODES];
+ int fcost[MAX_NODES];
+ char list[MAX_NODES]; //0 is neither, 1 is open, 2 is closed - char because it's the smallest data type
+ short int parent[MAX_NODES];
+
+ short int numOpen = 0;
+ short int atNode, temp, newnode=-1;
+ qboolean found = qfalse;
+ int count = -1;
+ float gc;
+ int i, u, v, m;
+ vec3_t vec;
+
+ //clear out all the arrays
+ memset(openlist, 0, sizeof(short int)*(MAX_NODES+1));
+ memset(fcost, 0, sizeof(int)*MAX_NODES);
+ memset(list, 0, sizeof(char)*MAX_NODES);
+ memset(parent, 0, sizeof(short int)*MAX_NODES);
+ memset(gcost, -1, sizeof(float)*MAX_NODES);
+
+ //make sure we have valid data before calculating everything
+ if ((from == NODE_INVALID) || (to == NODE_INVALID) || (from >= MAX_NODES) || (to >= MAX_NODES) || (from == to))
+ return -1;
+
+ openlist[1] = from; //add the starting node to the open list
+ ++numOpen;
+ gcost[from] = 0; //its f and g costs are obviously 0
+ fcost[from] = 0;
+
+ while (1)
+ {
+ if (numOpen != 0) //if there are still items in the open list
+ {
+ //pop the top item off of the list
+ atNode = openlist[1];
+ list[atNode] = 2; //put the node on the closed list so we don't check it again
+ --numOpen;
+
+ openlist[1] = openlist[numOpen+1]; //move the last item in the list to the top position
+ v = 1;
+
+ //this while loop reorders the list so that the new lowest fcost is at the top again
+ while (1)
+ {
+ u = v;
+ if ((2*u+1) < numOpen) //if both children exist
+ {
+ if (fcost[openlist[u]] >= fcost[openlist[2*u]])
+ v = 2*u;
+ if (fcost[openlist[v]] >= fcost[openlist[2*u+1]])
+ v = 2*u+1;
+ }
+ else
+ {
+ if ((2*u) < numOpen) //if only one child exists
+ {
+ if (fcost[openlist[u]] >= fcost[openlist[2*u]])
+ v = 2*u;
+ }
+ }
+
+ if (u != v) //if they're out of order, swap this item with its parent
+ {
+ temp = openlist[u];
+ openlist[u] = openlist[v];
+ openlist[v] = temp;
+ }
+ else
+ break;
+ }
+
+ for (i = 0; i < nodes[atNode].enodenum; i++) //loop through all the links for this node
+ {
+ newnode = nodes[atNode].links[i].targetNode;
+
+ //if this path is blocked, skip it
+ if (nodes[atNode].links[i].flags & PATH_BLOCKED)
+ continue;
+ //if this path is blocked, skip it
+ if (bot->client && (bot->client->ps.eFlags & EF_TANK) && nodes[atNode].links[i].flags & PATH_NOTANKS)
+ continue;
+ //skip any unreachable nodes
+ if (bot->client && (nodes[newnode].type & NODE_ALLY_UNREACHABLE) && (bot->client->sess.sessionTeam == TEAM_ALLIES))
+ continue;
+ if (bot->client && (nodes[newnode].type & NODE_AXIS_UNREACHABLE) && (bot->client->sess.sessionTeam == TEAM_AXIS))
+ continue;
+
+ if (list[newnode] == 2) //if this node is on the closed list, skip it
+ continue;
+
+ if (list[newnode] != 1) //if this node is not already on the open list
+ {
+ openlist[++numOpen] = newnode; //add the new node to the open list
+ list[newnode] = 1;
+ parent[newnode] = atNode; //record the node's parent
+
+ if (newnode == to) //if we've found the goal, don't keep computing paths!
+ break; //this will break the 'for' and go all the way to 'if (list[to] == 1)'
+
+ //store it's f cost value
+ fcost[newnode] = GetFCost(to, newnode, parent[newnode], gcost);
+
+ //this loop re-orders the heap so that the lowest fcost is at the top
+ m = numOpen;
+ while (m != 1) //while this item isn't at the top of the heap already
+ {
+ //if it has a lower fcost than its parent
+ if (fcost[openlist[m]] <= fcost[openlist[m/2]])
+ {
+ temp = openlist[m/2];
+ openlist[m/2] = openlist[m];
+ openlist[m] = temp; //swap them
+ m /= 2;
+ }
+ else
+ break;
+ }
+ }
+ else //if this node is already on the open list
+ {
+ gc = gcost[atNode];
+ VectorSubtract(nodes[newnode].origin, nodes[atNode].origin, vec);
+ gc += VectorLength(vec); //calculate what the gcost would be if we reached this node along the current path
+
+ if (gc < gcost[newnode]) //if the new gcost is less (ie, this path is shorter than what we had before)
+ {
+ parent[newnode] = atNode; //set the new parent for this node
+ gcost[newnode] = gc; //and the new g cost
+
+ for (i = 1; i < numOpen; i++) //loop through all the items on the open list
+ {
+ if (openlist[i] == newnode) //find this node in the list
+ {
+ //calculate the new fcost and store it
+ fcost[newnode] = GetFCost(to, newnode, parent[newnode], gcost);
+
+ //reorder the list again, with the lowest fcost item on top
+ m = i;
+ while (m != 1)
+ {
+ //if the item has a lower fcost than it's parent
+ if (fcost[openlist[m]] < fcost[openlist[m/2]])
+ {
+ temp = openlist[m/2];
+ openlist[m/2] = openlist[m];
+ openlist[m] = temp; //swap them
+ m /= 2;
+ }
+ else
+ break;
+ }
+ break; //exit the 'for' loop because we already changed this node
+ } //if
+ } //for
+ } //if (gc < gcost[newnode])
+ } //if (list[newnode] != 1) --> else
+ } //for (loop through links)
+ } //if (numOpen != 0)
+ else
+ {
+ found = qfalse; //there is no path between these nodes
+ break;
+ }
+
+ if (list[to] == 1) //if the destination node is on the open list, we're done
+ {
+ found = qtrue;
+ break;
+ }
+ } //while (1)
+
+ if (found == qtrue) //if we found a path
+ {
+ //G_Printf("%s - path found!n", bot->client->pers.netname);
+ count = 0;
+
+ temp = to; //start at the end point
+ while (temp != from) //travel along the path (backwards) until we reach the starting point
+ {
+ pathlist[count++] = temp; //add the node to the pathlist and increment the count
+ temp = parent[temp]; //move to the parent of this node to continue the path
+ }
+
+ pathlist[count++] = from; //add the beginning node to the end of the pathlist
+
+ #ifdef __BOT_SHORTEN_ROUTING__
+ count = ShortenASTARRoute(pathlist, count); // This isn't working... Dunno why.. Unique1
+ #endif //__BOT_SHORTEN_ROUTING__
+ }
+ else
+ {
+ //G_Printf("^1*** ^4BOT DEBUG^5: (CreatePathAStar) There is no route between node ^7%i^5 and node ^7%i^5.n", from, to);
+ count = CreateDumbRoute(from, to, pathlist);
+
+ if (count > 0)
+ {
+ #ifdef __BOT_SHORTEN_ROUTING__
+ count = ShortenASTARRoute(pathlist, count); // This isn't working... Dunno why.. Unique1
+ #endif //__BOT_SHORTEN_ROUTING__
+ return count;
+ }
+ }
+
+ return count; //return the number of nodes in the path, -1 if not found
+}
+
+/*
+===========================================================================
+GetFCost
+Utility function used by A* pathfinding to calculate the
+cost to move between nodes towards a goal. Using the A*
+algorithm F = G + H, G here is the distance along the node
+paths the bot must travel, and H is the straight-line distance
+to the goal node.
+Returned as an int because more precision is unnecessary and it
+will slightly speed up heap access
+===========================================================================
+*/
+int GetFCost(int to, int num, int parentNum, float *gcost)
+{
+ float gc = 0;
+ float hc = 0;
+ vec3_t v;
+
+ if (gcost[num] == -1)
+ {
+ if (parentNum != -1)
+ {
+ gc = gcost[parentNum];
+ VectorSubtract(nodes[num].origin, nodes[parentNum].origin, v);
+ gc += VectorLength(v);
+ }
+ gcost[num] = gc;
+ }
+ else
+ gc = gcost[num];
+
+ VectorSubtract(nodes[to].origin, nodes[num].origin, v);
+ hc = VectorLength(v);
+
+ return (int)(gc + hc);
+}
+#endif //__PATHFINDING__
diff --git a/src/game/WaypointMovementGenerator.h b/src/game/WaypointMovementGenerator.h index 86e1b0beea3..5d86154a3d9 100644 --- a/src/game/WaypointMovementGenerator.h +++ b/src/game/WaypointMovementGenerator.h @@ -1,140 +1,118 @@ -/* - * 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 - * (at your option) any later version. - * - * 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 - * 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 - */ - -#ifndef TRINITY_WAYPOINTMOVEMENTGENERATOR_H -#define TRINITY_WAYPOINTMOVEMENTGENERATOR_H - -/** @page PathMovementGenerator is used to generate movements - * of waypoints and flight paths. Each serves the purpose - * of generate activities so that it generates updated - * packets for the players. - */ - -#include "MovementGenerator.h" -#include "DestinationHolder.h" -#include "WaypointManager.h" -#include "Path.h" -#include "Traveller.h" - -#include "Player.h" - -#include <vector> -#include <set> - -#define FLIGHT_TRAVEL_UPDATE 100 -#define STOP_TIME_FOR_PLAYER 3 * 60 * 1000 // 3 Minutes - -template<class T, class P = Path> -class TRINITY_DLL_SPEC PathMovementBase -{ - public: - PathMovementBase() : i_currentNode(0) {} - virtual ~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*> -{ - 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; -}; - -/** FlightPathMovementGenerator generates movement of the player for the paths - * and hence generates ground and activities for the player. - */ -class TRINITY_DLL_SPEC FlightPathMovementGenerator -: public MovementGeneratorMedium< Player, FlightPathMovementGenerator >, -public PathMovementBase<Player> -{ - uint32 i_pathId; - std::vector<uint32> i_mapIds; - public: - explicit FlightPathMovementGenerator(uint32 id, uint32 startNode = 0) : i_pathId(id) { i_currentNode = startNode; } - void Initialize(Player &); - void Finalize(Player &); - void Reset(Player &) {} - bool Update(Player &, const uint32 &); - MovementGeneratorType GetMovementGeneratorType() { return FLIGHT_MOTION_TYPE; } - - void LoadPath(Player &); - void ReloadPath(Player &) { /* don't reload flight path */ } - - Path& GetPath() { return i_path; } - uint32 GetPathAtMapEnd() const; - 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; } -}; -#endif +/*
+ * 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
+ * (at your option) any later version.
+ *
+ * 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
+ * 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
+ */
+
+#ifndef TRINITY_WAYPOINTMOVEMENTGENERATOR_H
+#define TRINITY_WAYPOINTMOVEMENTGENERATOR_H
+
+/** @page PathMovementGenerator is used to generate movements
+ * of waypoints and flight paths. Each serves the purpose
+ * of generate activities so that it generates updated
+ * packets for the players.
+ */
+
+#include "MovementGenerator.h"
+#include "DestinationHolder.h"
+#include "WaypointManager.h"
+#include "Path.h"
+#include "Traveller.h"
+
+#include "Player.h"
+
+#include <vector>
+#include <set>
+
+#define FLIGHT_TRAVEL_UPDATE 100
+#define STOP_TIME_FOR_PLAYER 3 * 60 * 1000 // 3 Minutes
+
+template<class T, class P = Path>
+class TRINITY_DLL_SPEC PathMovementBase
+{
+ public:
+ PathMovementBase() : i_currentNode(0) {}
+ virtual ~PathMovementBase() {};
+
+ inline bool MovementInProgress(void) const { return i_currentNode < i_path.Size(); }
+
+ void LoadPath(T &);
+ void ReloadPath(T &);
+ uint32 GetCurrentNode() const { return i_currentNode; }
+
+ protected:
+ uint32 i_currentNode;
+ DestinationHolder< Traveller<T> > i_destinationHolder;
+ P i_path;
+};
+
+template<class T>
+
+class TRINITY_DLL_SPEC WaypointMovementGenerator
+ : public MovementGeneratorMedium< T, WaypointMovementGenerator<T> >, public PathMovementBase<T>
+{
+ 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
+ * and hence generates ground and activities for the player.
+ */
+class TRINITY_DLL_SPEC FlightPathMovementGenerator
+: public MovementGeneratorMedium< Player, FlightPathMovementGenerator >,
+public PathMovementBase<Player>
+{
+ uint32 i_pathId;
+ std::vector<uint32> i_mapIds;
+ public:
+ explicit FlightPathMovementGenerator(uint32 id, uint32 startNode = 0) : i_pathId(id) { i_currentNode = startNode; }
+ void Initialize(Player &);
+ void Finalize(Player &);
+ void Reset(Player &) {}
+ bool Update(Player &, const uint32 &);
+ MovementGeneratorType GetMovementGeneratorType() { return FLIGHT_MOTION_TYPE; }
+
+ void LoadPath(Player &);
+ void ReloadPath(Player &) { /* don't reload flight path */ }
+
+ Path& GetPath() { return i_path; }
+ uint32 GetPathAtMapEnd() const;
+ 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; }
+
+};
+#endif
diff --git a/src/game/World.cpp b/src/game/World.cpp index 04b3a1004c9..8cf6147842b 100644 --- a/src/game/World.cpp +++ b/src/game/World.cpp @@ -1271,6 +1271,7 @@ void World::SetInitialWorldSettings() objmgr.LoadSpellScripts(); // must be after load Creature/Gameobject(Template/Data) objmgr.LoadGameObjectScripts(); // must be after load Creature/Gameobject(Template/Data) objmgr.LoadEventScripts(); // must be after load Creature/Gameobject(Template/Data) + objmgr.LoadWaypointScripts(); sLog.outString( "Loading Scripts text locales..." ); // must be after Load*Scripts calls objmgr.LoadDbScriptStrings(); @@ -1313,7 +1314,6 @@ void World::SetInitialWorldSettings() ///- Initilize static helper structures AIRegistry::Initialize(); - WaypointMovementGenerator<Creature>::Initialize(); Player::InitVisibleBits(); ///- Initialize MapManager @@ -2203,8 +2203,32 @@ void World::ScriptsProcess() break; } - - default: +
+ case SCRIPT_COMMAND_LOAD_PATH:
+ {
+ if(!source)
+ {
+ sLog.outError("SCRIPT_COMMAND_START_MOVE is tried to apply to NON-existing unit.");
+ break;
+ }
+
+ if(!source->isType(TYPEMASK_UNIT))
+ {
+ sLog.outError("SCRIPT_COMMAND_START_MOVE source mover isn't unit (TypeId: %u), skipping.",source->GetTypeId());
+ break;
+ }
+
+ if(!WaypointMgr.GetPath(step.script->datalong))
+ {
+ sLog.outError("SCRIPT_COMMAND_START_MOVE source mover has an invallid path, skipping.", step.script->datalong2);
+ break;
+ }
+
+ dynamic_cast<Unit*>(source)->GetMotionMaster()->MovePath(step.script->datalong, step.script->datalong2);
+ break;
+ } + + default: sLog.outError("Unknown script command %u called.",step.script->command); break; } diff --git a/src/game/World.h b/src/game/World.h index fc11301f883..885047e6685 100644 --- a/src/game/World.h +++ b/src/game/World.h @@ -326,6 +326,7 @@ enum RealmZone #define SCRIPT_COMMAND_ACTIVATE_OBJECT 13 // source = unit, target=GO #define SCRIPT_COMMAND_REMOVE_AURA 14 // source (datalong2!=0) or target (datalong==0) unit, datalong = spell_id #define SCRIPT_COMMAND_CAST_SPELL 15 // source (datalong2!=0) or target (datalong==0) unit, datalong = spell_id +#define SCRIPT_COMMAND_LOAD_PATH 16 // source = unit, path = datalong, repeatable datalong2 /// Storage class for commands issued for delayed execution struct CliCommandHolder diff --git a/src/shared/Database/SQLStorage.cpp b/src/shared/Database/SQLStorage.cpp index 720e6e3e683..4845841b6d6 100644 --- a/src/shared/Database/SQLStorage.cpp +++ b/src/shared/Database/SQLStorage.cpp @@ -29,9 +29,9 @@ extern DatabaseMysql WorldDatabase; const char CreatureInfosrcfmt[]="iiiiiisssiiiiiiiiiiffiffiiiiiiiiiiiffiiiiiiiiiiiiiiiiiiisiilliiis"; const char CreatureInfodstfmt[]="iiiiiisssiiiiiiiiiiffiffiiiiiiiiiiiffiiiiiiiiiiiiiiiiiiisiilliiii"; -const char CreatureDataAddonInfofmt[]="iiiiiiis"; +const char CreatureDataAddonInfofmt[]="iiiiiiiis"; const char CreatureModelfmt[]="iffbi"; -const char CreatureInfoAddonInfofmt[]="iiiiiiis"; +const char CreatureInfoAddonInfofmt[]="iiiiiiiis"; const char EquipmentInfofmt[]="iiiiiiiiii"; const char GameObjectInfosrcfmt[]="iiissiifiiiiiiiiiiiiiiiiiiiiiiiis"; const char GameObjectInfodstfmt[]="iiissiifiiiiiiiiiiiiiiiiiiiiiiiii"; |