Index: src/game/AggressorAI.cpp =================================================================== --- src/game/AggressorAI.cpp (revision 5687) +++ src/game/AggressorAI.cpp (working copy) @@ -111,7 +111,6 @@ i_creature.DeleteThreatList(); i_victimGuid = 0; i_creature.CombatStop(); - } void Index: src/game/Chat.cpp =================================================================== --- src/game/Chat.cpp (revision 5687) +++ src/game/Chat.cpp (working copy) @@ -116,9 +116,13 @@ static ChatCommand wpCommandTable[] = { { "show", SEC_GAMEMASTER, &ChatHandler::HandleWpShowCommand, "", NULL }, - { "add", SEC_GAMEMASTER, &ChatHandler::HandleWpAddCommand, "", NULL }, - { "modify", SEC_GAMEMASTER, &ChatHandler::HandleWpModifyCommand, "", NULL }, - { NULL, 0, NULL, "", NULL } + { "addwp", SEC_GAMEMASTER, &ChatHandler::HandleWpAddCommand, "", NULL }, + { "load", SEC_GAMEMASTER, &ChatHandler::HandleWpLoadPathCommand, "", NULL }, + { "modify", SEC_GAMEMASTER, &ChatHandler::HandleWpModifyCommand, "", NULL }, + { "event", SEC_GAMEMASTER, &ChatHandler::HandleWpEventCommand, "", NULL }, + { "unload", SEC_GAMEMASTER, &ChatHandler::HandleWpUnLoadPathCommand, "", NULL }, + + { NULL, 0, NULL, "", NULL } }; static ChatCommand debugCommandTable[] = @@ -162,6 +166,7 @@ { "all_scripts", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadAllScriptsCommand, "", NULL }, { "all_spell", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadAllSpellCommand, "", NULL }, + { "waypoint_scripts", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadAreaTriggerTavernCommand, "", NULL }, { "areatrigger_tavern", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadAreaTriggerTavernCommand, "", NULL }, { "areatrigger_teleport", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadAreaTriggerTeleportCommand, "", NULL }, { "areatrigger_involvedrelation",SEC_ADMINISTRATOR, &ChatHandler::HandleReloadQuestAreaTriggersCommand, "", NULL }, @@ -234,7 +239,16 @@ { NULL, 0, NULL, "", NULL } }; - static ChatCommand resetCommandTable[] = + static ChatCommand formationCommandTable[] = + { + { "setleader", SEC_MODERATOR, &ChatHandler::HandleCreateFormationCommand, "", NULL }, + { "dismiss", SEC_MODERATOR, &ChatHandler::HandleDismissFormationCommand, "", NULL }, + { "followangle", SEC_MODERATOR, &ChatHandler::HandleAngleFormationCommand, "", NULL }, + { "followdist", SEC_MODERATOR, &ChatHandler::HandleDistFormationCommand, "", NULL }, + { NULL, 0, NULL, "", NULL } + }; + + static ChatCommand resetCommandTable[] = { { "honor", SEC_ADMINISTRATOR, &ChatHandler::HandleResetHonorCommand, "", NULL }, { "level", SEC_ADMINISTRATOR, &ChatHandler::HandleResetLevelCommand, "", NULL }, @@ -366,8 +380,9 @@ { "password", SEC_PLAYER, &ChatHandler::HandlePasswordCommand, "", NULL }, { "lockaccount", SEC_PLAYER, &ChatHandler::HandleLockAccountCommand, "", NULL }, { "respawn", SEC_ADMINISTRATOR, &ChatHandler::HandleRespawnCommand, "", NULL }, - { "wp", SEC_GAMEMASTER, NULL, "", wpCommandTable }, - { "flymode", SEC_ADMINISTRATOR, &ChatHandler::HandleFlyModeCommand, "", NULL }, + { "path", SEC_GAMEMASTER, NULL, "", wpCommandTable }, + { "formation", SEC_ADMINISTRATOR, NULL, "", formationCommandTable }, + { "flymode", SEC_ADMINISTRATOR, &ChatHandler::HandleFlyModeCommand, "", NULL }, { "sendmail", SEC_MODERATOR, &ChatHandler::HandleSendMailCommand, "", NULL }, { "rename", SEC_GAMEMASTER, &ChatHandler::HandleRenameCommand, "", NULL }, { "nametele", SEC_MODERATOR, &ChatHandler::HandleNameTeleCommand, "", NULL }, @@ -383,8 +398,14 @@ { "cast", SEC_ADMINISTRATOR, &ChatHandler::HandleCastCommand, "", NULL }, { "castback", SEC_ADMINISTRATOR, &ChatHandler::HandleCastBackCommand, "", NULL }, { "casttarget", SEC_ADMINISTRATOR, &ChatHandler::HandleCastTargetCommand, "", NULL }, + + { "loadpath", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadAllPaths, "", NULL }, + { "cometome", SEC_ADMINISTRATOR, &ChatHandler::HandleComeToMeCommand, "", NULL }, + + + //! Development Commands { "setvalue", SEC_ADMINISTRATOR, &ChatHandler::HandleSetValue, "", NULL }, { "getvalue", SEC_ADMINISTRATOR, &ChatHandler::HandleGetValue, "", NULL }, Index: src/game/Chat.h =================================================================== --- src/game/Chat.h (revision 5687) +++ src/game/Chat.h (working copy) @@ -145,7 +145,8 @@ bool HandleReloadAllScriptsCommand(const char* args); bool HandleReloadAllSpellCommand(const char* args); - bool HandleReloadAreaTriggerTavernCommand(const char* args); + bool HandleReloadWaypointScriptsCommand(const char* arg); + bool HandleReloadAreaTriggerTavernCommand(const char* args); bool HandleReloadAreaTriggerTeleportCommand(const char* args); bool HandleReloadEventScriptsCommand(const char* args); bool HandleReloadCommandCommand(const char* args); @@ -179,10 +180,13 @@ bool HandleReloadSpellScriptTargetCommand(const char* args); bool HandleReloadSpellScriptsCommand(const char* args); bool HandleReloadSpellTeleportCommand(const char* args); + bool HandleReloadAllPaths(const char* args); + + bool HandleAddHonorCommand(const char* args); + bool HandleReloadSpellThreatsCommand(const char* args); - bool HandleAddHonorCommand(const char* args); - bool HandleHonorAddKillCommand(const char* args); + bool HandleHonorAddKillCommand(const char* args); bool HandleHonorFlushKillsCommand(const char* args); bool HandleUpdateHonorFieldsCommand(const char* args); @@ -316,8 +320,15 @@ 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 HandleWpLoadPathCommand(const char* args); + bool HandleWpUnLoadPathCommand(const char* args); + bool HandleWpModifyCommand(const char* args); + bool HandleWpEventCommand(const char* args); + bool HandleCreateFormationCommand(const char* args); + bool ChatHandler::HandleDismissFormationCommand(const char* args); + bool ChatHandler::HandleDistFormationCommand(const char* args); + bool ChatHandler::HandleAngleFormationCommand(const char* args); + bool HandleWpShowCommand(const char* args); bool HandleFlyModeCommand(const char* args); bool HandleSendOpcodeCommand(const char* args); bool HandleSellErrorCommand(const char* args); Index: src/game/Creature.cpp =================================================================== --- src/game/Creature.cpp (revision 5687) +++ src/game/Creature.cpp (working copy) @@ -61,6 +61,7 @@ m_CreatureSpellCooldowns.clear(); m_CreatureCategoryCooldowns.clear(); m_GlobalCooldown = 0; + m_waypointID = 0; } Creature::~Creature() @@ -150,9 +151,13 @@ loot.clear(); m_respawnTime = time(NULL) + m_respawnDelay; - float x,y,z; - GetRespawnCoord(x, y, z); - MapManager::Instance().GetMap(GetMapId(), this)->CreatureRelocation(this,x,y,z,GetOrientation()); + + if(!this->GetCurrentWaypointID()) + { + float x,y,z; + GetRespawnCoord(x, y, z); + MapManager::Instance().GetMap(GetMapId(), this)->CreatureRelocation(this,x,y,z,GetOrientation()); + } } void Creature::Update(uint32 diff) @@ -201,12 +206,21 @@ clearUnitState(UNIT_STAT_ALL_STATE); i_motionMaster.Clear(); LoadCreaturesAddon(true); - + //Call AI respawn virtual function i_AI->JustRespawned(); MapManager::Instance().GetMap(GetMapId(), this)->Add(this); - } + + if(IsFollower()) + { + uint32 guid = this->GetCreatureFormation()->leader; + uint32 entry = objmgr.GetCreatureData(guid)->id; + Creature* Leader = ObjectAccessor::Instance().GetObjectInWorld(MAKE_NEW_GUID(guid, entry, HIGHGUID_UNIT), (Creature*)NULL); + if(Leader) + Leader->SetLinkedtoFormation(false); + } + } break; } case CORPSE: @@ -1116,8 +1130,9 @@ return false; } - Object::_Create(guidlow, Entry, HIGHGUID_UNIT); + Object::_Create(guidlow, Entry, HIGHGUID_UNIT); + m_DBTableGuid = guidlow; SetUInt32Value(OBJECT_FIELD_ENTRY, Entry); @@ -1249,7 +1264,8 @@ m_DBTableGuid = stored_guid; LoadCreaturesAddon(); - if(GetCreatureInfo()->rank > 0) + LoadCreatureFormation(); + if(GetCreatureInfo()->rank > 0) this->m_corpseDelay *= 3; //if creature is elite, then remove corpse later m_respawnradius = data->spawndist; @@ -1283,8 +1299,8 @@ // checked at creature_template loading m_defaultMovementType = MovementGeneratorType(data->movementType); - - AIM_Initialize(); + + AIM_Initialize(); return true; } @@ -1713,7 +1729,10 @@ if (cainfo->emote != 0) SetUInt32Value(UNIT_NPC_EMOTESTATE, cainfo->emote); - if(cainfo->auras) + if (cainfo->path_id != 0) + m_path_id = cainfo->path_id; + + if(cainfo->auras) { for (CreatureDataAddonAura const* cAura = cainfo->auras; cAura->spell_id; ++cAura) { @@ -1806,3 +1825,20 @@ break; return i < CREATURE_MAX_SPELLS; //broke before end of iteration of known spells } + + +CreatureFormation const* Creature::GetCreatureFormation() const +{ + CreatureFormation const* form = ObjectMgr::GetFormation(m_DBTableGuid); + return form; +} + +//Load Formations +bool Creature::LoadCreatureFormation() +{ +CreatureFormation const *info = GetCreatureFormation(); +if(!info) + return false; + m_formation = true; + return m_formation; +} \ No newline at end of file Index: src/game/Creature.h =================================================================== --- src/game/Creature.h (revision 5687) +++ src/game/Creature.h (working copy) @@ -257,7 +257,8 @@ struct CreatureDataAddon { uint32 guidOrEntry; - uint32 mount; + uint32 path_id; + uint32 mount; uint32 bytes0; uint32 bytes1; uint32 bytes2; @@ -281,6 +282,14 @@ INHAVIT_ANYWHERE = INHAVIT_GROUND | INHAVIT_WATER }; +struct CreatureFormation +{ +uint32 follower; +uint32 leader; +float offset_angle; +float offset_dist; +}; + // GCC have alternative #pragma pack() syntax and old gcc version not support pack(pop), also any gcc version not support it at some platform #if defined( __GNUC__ ) #pragma pack() @@ -303,7 +312,12 @@ public: - explicit Creature( WorldObject *instantiator ); + bool IsFollower(){return m_formation;} + bool LoadCreatureFormation(); + + CreatureFormation const* GetCreatureFormation() const; + + explicit Creature( WorldObject *instantiator ); virtual ~Creature(); void AddToWorld(); @@ -320,7 +334,11 @@ void Update( uint32 time ); // overwrited Unit::Update void GetRespawnCoord(float &x, float &y, float &z) const { x = respawn_cord[0]; y = respawn_cord[1]; z = respawn_cord[2]; } - void GetRespawnDist(float &d) const { d = m_respawnradius; } + + void SetCoordsBeforeBattle(float x, float y, float z) { last_cord[0] = x; last_cord[1] = y; last_cord[2] = z; } + void GetCoordsBeforeBattle(float &x, float &y, float &z) const { x = last_cord[0]; y = last_cord[1]; z = last_cord[2]; } + + void GetRespawnDist(float &d) const { d = m_respawnradius; } uint32 GetEquipmentId() const { return m_equipmentId; } bool isPet() const { return m_isPet; } @@ -375,9 +393,11 @@ bool HasSpellCooldown(uint32 spell_id) const; bool HasCategoryCooldown(uint32 spell_id) const; - bool HasSpell(uint32 spellID) const; - - bool UpdateStats(Stats stat); + bool HasSpell(uint32 spellID) const; + uint32 GetCurrentWaypointID(){return m_waypointID;} + void UpdateWaypointID(uint32 wpID){m_waypointID = wpID;} + + bool UpdateStats(Stats stat); bool UpdateAllStats(); void UpdateResistances(uint32 school); void UpdateArmor(); @@ -520,8 +540,17 @@ else return m_charmInfo->GetCharmSpell(pos)->spellId; } - - protected: + + bool isLinkedtoFormation(){return m_link;} + void SetLinkedtoFormation(bool link) {m_link = link;} + + uint32 Creature::GetWaypointPath(){return m_path_id;} + void LoadPath(uint32 pathid) { m_path_id = pathid; } + + bool IsStoppedByEvent(){return m_wpevent;} + void SetStoppedByEvent(bool wpevent) {m_wpevent = wpevent;} + + protected: // vendor items typedef std::vector CreatureItems; CreatureItems m_vendor_items; @@ -552,8 +581,9 @@ uint32 m_NPCTextId; // cached value float respawn_cord[3]; - - uint8 m_emoteState; + float last_cord[3]; + + uint8 m_emoteState; bool m_isPet; // set only in Pet::Pet bool m_isTotem; // set only in Totem::Totem void RegenerateMana(); @@ -568,7 +598,12 @@ bool m_regenHealth; bool m_AI_locked; bool m_isDeadByDefault; - private: + uint32 m_waypointID; + bool m_formation; + bool m_link; + bool m_wpevent; + uint32 m_path_id; + private: GridReference m_gridRef; }; #endif Index: src/game/CreatureAI.h =================================================================== --- src/game/CreatureAI.h (revision 5687) +++ src/game/CreatureAI.h (working copy) @@ -79,11 +79,15 @@ // Called when the creature is attacked virtual void AttackedBy(Unit * /*attacker*/) {} - // Called when creature is spawned or respawned (for reseting variables) + // Called when creature reach any waypoint + virtual void MovementInform(uint32) {} + + // Called when creature is spawned or respawned (for reseting variables) virtual void JustRespawned() {} + + // Called at waypoint reached or point movement finished + virtual void MovementInform(uint32 /*MovementType*/, uint32 /*Data*/) {} - // Called at waypoint reached or point movement finished - virtual void MovementInform(uint32 /*MovementType*/, uint32 /*Data*/) {} }; struct SelectableAI : public FactoryHolder, public Permissible Index: src/game/GameEvent.cpp =================================================================== --- src/game/GameEvent.cpp (revision 5687) +++ src/game/GameEvent.cpp (working copy) @@ -146,7 +146,7 @@ if(max_event_id + event_id >= mGameEventCreatureGuids.size()) { - sLog.outErrorDb("`game_event_creature` game event id (%i) is out of range compared to max event id in `game_event`",event_id); + sLog.outErrorDb("`creature_game_event` game event id (%i) is out of range compared to max event id in `game_event`",event_id); continue; } @@ -160,7 +160,52 @@ delete result; } - mGameEventGameobjectGuids.resize((max_event_id * 2) + 1); + ///////////////////////////////wp event + mWpEvent.resize((max_event_id * 2) + 1); + // 1 2 + result = WorldDatabase.Query("SELECT creature.guid, waypoint_event.event " + "FROM creature JOIN waypoint_event ON creature.guid = waypoint_event.guid"); + + count = 0; + if( !result ) + { + barGoLink bar2(1); + bar2.step(); + + sLog.outString(); + sLog.outString(">> Loaded %u creatures in waypoint events", count ); + } + else + { + + barGoLink bar2( result->GetRowCount() ); + do + { + Field *fields = result->Fetch(); + + bar2.step(); + + uint32 guid = fields[0].GetUInt32(); + int16 event_id = fields[1].GetInt16(); + + if(max_event_id + event_id >= mWpEvent.size()) + { + sLog.outErrorDb("`waypoint_event` game event id (%i) is out of range compared to max event id in `game_event`",event_id); + continue; + } + + ++count; + GuidList& crelist = mWpEvent[max_event_id + event_id]; + crelist.push_back(guid); + + } while( result->NextRow() ); + sLog.outString(); + sLog.outString( ">> Loaded %u creatures in waypoint events", count ); + delete result; + } +//////////////////////////// + + mGameEventGameobjectGuids.resize((max_event_id * 2) + 1); // 1 2 result = WorldDatabase.Query("SELECT gameobject.guid, game_event_gameobject.event " "FROM gameobject JOIN game_event_gameobject ON gameobject.guid=game_event_gameobject.guid"); @@ -361,6 +406,9 @@ ChangeEquipOrModel(event_id, false); // Remove quests that are events only to non event npc UpdateEventQuests(event_id, false); + //Make creatures stop moving + WaypointEvent(event_id, false); + } void GameEvent::ApplyNewEvent(uint16 event_id) @@ -386,6 +434,8 @@ ChangeEquipOrModel(event_id, true); // Add quests that are events only to non event npc UpdateEventQuests(event_id, true); + //Make creatures move + WaypointEvent(event_id, true); } void GameEvent::GameEventSpawn(int16 event_id) @@ -605,6 +655,43 @@ } } +void GameEvent::WaypointEvent(uint16 event_id, bool Activate) +{ + + for (GuidList::iterator itr = mWpEvent[max_event_id + event_id].begin();itr != mWpEvent[max_event_id + event_id].end();++itr) + + { + + CreatureData const* data = objmgr.GetCreatureData(*itr); + if(!data) + continue; + + Creature* pCreature; + pCreature = ObjectAccessor::Instance().GetObjectInWorld(MAKE_NEW_GUID(*itr, data->id, HIGHGUID_UNIT), (Creature*)NULL); + if (pCreature) + { + if (Activate) + { + WorldDatabase.PExecute("UPDATE creature SET MovementType = '%u' WHERE guid = '%u'", WAYPOINT_MOTION_TYPE, pCreature->GetGUIDLow()); + + pCreature->SetStoppedByEvent(false); + pCreature->SetDefaultMovementType(WAYPOINT_MOTION_TYPE); + pCreature->GetMotionMaster()->Initialize(); + pCreature->Say("Event Started",0,0); + } + else + { + WorldDatabase.PExecute("UPDATE creature SET MovementType = '%u' WHERE guid = '%u'", IDLE_MOTION_TYPE, pCreature->GetGUIDLow()); + + pCreature->SetStoppedByEvent(true); + pCreature->SetDefaultMovementType(IDLE_MOTION_TYPE); + pCreature->GetMotionMaster()->Initialize(); + pCreature->Say("Event Stopped",0,0); + } + } + } +} + GameEvent::GameEvent() { isSystemInit = false; Index: src/game/GameEvent.h =================================================================== --- src/game/GameEvent.h (revision 5687) +++ src/game/GameEvent.h (working copy) @@ -64,7 +64,8 @@ void ChangeEquipOrModel(int16 event_id, bool activate); void UpdateEventQuests(uint16 event_id, bool Activate); uint32 NextCheck(uint16 entry); - protected: + void WaypointEvent(uint16 event_id, bool Activate); + protected: typedef std::vector GameEventDataMap; typedef std::list GuidList; typedef std::vector GameEventGuidMap; @@ -79,7 +80,8 @@ GameEventGuidMap mGameEventCreatureGuids; GameEventGuidMap mGameEventGameobjectGuids; GameEventDataMap mGameEvent; - ActiveEvents m_ActiveEvents; + GameEventGuidMap mWpEvent; + ActiveEvents m_ActiveEvents; bool isSystemInit; uint16 max_event_id; }; Index: src/game/HomeMovementGenerator.cpp =================================================================== --- src/game/HomeMovementGenerator.cpp (revision 5687) +++ src/game/HomeMovementGenerator.cpp (working copy) @@ -47,10 +47,14 @@ return; float x, y, z; - owner.GetRespawnCoord(x, y, z); + + if(!owner.GetCurrentWaypointID()) + owner.GetRespawnCoord(x, y, z); + else + owner.GetCoordsBeforeBattle(x, y, z); + + CreatureTraveller traveller(owner); - CreatureTraveller traveller(owner); - uint32 travel_time = i_destinationHolder.SetDestination(traveller, x, y, z); modifyTravelTime(travel_time); owner.clearUnitState(UNIT_STAT_ALL_STATE); Index: src/game/Level2.cpp =================================================================== --- src/game/Level2.cpp (revision 5687) +++ src/game/Level2.cpp (working copy) @@ -1049,7 +1049,7 @@ uint32 point; - QueryResult *result = WorldDatabase.PQuery( "SELECT MAX(point) FROM creature_movement WHERE id = '%u'",lowguid); + QueryResult *result = WorldDatabase.PQuery( "SELECT MAX(point) FROM waypoint_data WHERE id = '%u'",lowguid); if( result ) { point = (*result)[0].GetUInt32()+1; @@ -1061,7 +1061,7 @@ Player* player = m_session->GetPlayer(); - WorldDatabase.PExecuteLog("INSERT INTO creature_movement (id,point,position_x,position_y,position_z,waittime) VALUES ('%u','%u','%f', '%f', '%f','%u')", + WorldDatabase.PExecuteLog("INSERT INTO waypoint_data(id,point,position_x,position_y,position_z,delay) VALUES ('%u','%u','%f', '%f', '%f','%u')", lowguid, point, player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), wait); // update movement type @@ -1203,7 +1203,7 @@ if( doNotDelete == false ) { //sLog.outError("DEBUG: doNotDelete == false"); - WorldDatabase.PExecuteLog("DELETE FROM creature_movement WHERE id = '%u'",lowguid); + WorldDatabase.PExecuteLog("DELETE FROM waypoint_data WHERE id = '%u'",lowguid); } WorldDatabase.CommitTransaction(); if(pCreature) @@ -1828,185 +1828,606 @@ 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 - */ +/////WAYPOINT COMMANDS + bool ChatHandler::HandleWpAddCommand(const char* args) { sLog.outDebug("DEBUG: HandleWpAddCommand"); // optional - char* guid_str = NULL; + 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."); + SendSysMessage("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."); + SendSysMessage("Current creature haven't loaded path."); + return true; + } + + sLog.outDebug("DEBUG: HandleWpAddCommand - point == 0"); - if(*args) + QueryResult *result = WorldDatabase.PQuery( "SELECT MAX(point) FROM waypoint_data WHERE id = '%u'",pathid); + if( result ) { - guid_str = strtok((char*)args, " "); + point = (*result)[0].GetUInt32()+1; + delete result; } + else + point = 1; - uint32 lowguid = 0; - uint32 point = 0; - Unit* target = getSelectedCreature(); - // Did player provide a GUID? - if (!guid_str) - { - sLog.outDebug("DEBUG: HandleWpAddCommand - No GUID provided"); + Player* player = m_session->GetPlayer(); - // No GUID provided - // -> Player must have selected a creature + WorldDatabase.PExecuteLog("INSERT INTO waypoint_data (id,point,position_x,position_y,position_z) VALUES ('%u','%u','%f', '%f', '%f')", + pathid, point, player->GetPositionX(), player->GetPositionY(), player->GetPositionZ()); - if(!target) + Creature* wpCreature = new Creature(player); + if (!wpCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), player->GetMapId(), + player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), player->GetOrientation(), VISUAL_WAYPOINT,0)) { - SendSysMessage(LANG_SELECT_CREATURE); - return true; + PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, VISUAL_WAYPOINT); + delete wpCreature; + return false; } - if (target->GetEntry() == VISUAL_WAYPOINT ) - { - sLog.outDebug("DEBUG: HandleWpAddCommand - target->GetEntry() == VISUAL_WAYPOINT (1) "); + WorldDatabase.PExecute("UPDATE waypoint_data SET wpguid = '%u' WHERE id = '%u' and point = '%u'", wpCreature->GetGUIDLow(), pathid, point); - 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()); - return true; - } - } - do - { - Field *fields = result->Fetch(); - lowguid = fields[0].GetUInt32(); - point = fields[1].GetUInt32(); - }while( result->NextRow() ); - delete result; - } - else - { - lowguid = target->GetGUIDLow(); - } + wpCreature->SaveToDB(); + // To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells(); + wpCreature->LoadFromDB(wpCreature->GetDBTableGUIDLow(), player->GetInstanceId()); + MapManager::Instance().GetMap(wpCreature->GetMapId(), wpCreature)->Add(wpCreature); + + if(target) + { + if(pathid = target->GetWaypointPath()) + { + wpCreature->SetDisplayId(target->GetDisplayId()); + wpCreature->SetFloatValue(OBJECT_FIELD_SCALE_X, 0.5); + } + } + + PSendSysMessage("PathID: %u: Waypoint %u created. ",pathid, point); - } - else - { - sLog.outDebug("DEBUG: HandleWpAddCommand - GUID provided"); + return true; +} // HandleWpAddCommand - // GUID provided - // Warn if player also selected a creature - // -> Creature selection is ignored <- - if(target) - { - SendSysMessage(LANG_WAYPOINT_CREATSELECTED); - } - lowguid = atoi((char*)guid_str); - } - // lowguid -> GUID of the NPC - // point -> number of the waypoint (if not 0) - sLog.outDebug("DEBUG: HandleWpAddCommand - danach"); +bool ChatHandler::HandleWpLoadPathCommand(const char *args) +{ - Creature* pCreature = NULL; + if(!*args) + return false; + + // optional + char* path_number = NULL; - /* impossible without entry - if(lowguid) - pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_GUID(lowguid,HIGHGUID_UNIT)); - */ + if(*args) + { + path_number = strtok((char*)args, " "); + } - // attempt check creature existence by DB data - if(!pCreature) - { - CreatureData const* data = objmgr.GetCreatureData(lowguid); - if(!data) +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); + return true; + } + if(target->GetEntry() == 1) { - PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, lowguid); + SendSysMessage("You want to load path to a waypoint? Aren't you?"); return true; } - } + + + pathid = atoi(path_number); + if(!pathid) + { + SendSysMessage("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; +} - sLog.outDebug("DEBUG: HandleWpAddCommand - point == 0"); +bool ChatHandler::HandleReloadAllPaths(const char* args) +{ +if(!*args) + return false; - QueryResult *result = WorldDatabase.PQuery( "SELECT MAX(point) FROM creature_movement WHERE id = '%u'",lowguid); - if( result ) +uint32 id = atoi(args); + +if(!id) + return false; + +PSendSysMessage("Loading Path: %u", id); + sWaypointStore.UpdatePath(id); + return true; +} + +bool ChatHandler::HandleWpUnLoadPathCommand(const char *args) +{ +uint32 guidlow = 0; +Creature* target = getSelectedCreature(); + +if(!target) +{ + SendSysMessage("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()->TargetedHome(); + target->Say("Path unloaded.",0,0); + return true; + } + SendSysMessage("Target have no loaded path."); + return true; +} +SendSysMessage("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("Wp Event: New waypoint event added: %u", id); + } + else + { + PSendSysMessage("Wp Event: You have choosed an existing waypoint script guid: %u", 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("Wp Event: New waypoint event added: %u", id+1); + } + + return true; + } + + + if(show == "listid") + { + uint32 id; + char* arg_id = strtok(NULL, " "); + + if(!arg_id) + { + SendSysMessage("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`, `datatext`, `x`, `y`, `z`, `o` FROM waypoint_scripts WHERE id = %u", id); + + if( !result ) + { + PSendSysMessage("Wp Event: No waypoint scripts found on id: %u", 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("id: %u, guid: %u, delay: %u, command: %u, datalong: %u, datalong2: %u, datatext: %s, posx: %f, posy: %f, posz: %f, orientation: %f", 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 ) { - point = (*result)[0].GetUInt32()+1; - delete result; - } + WorldDatabase.PExecuteLog("DELETE FROM waypoint_scripts WHERE guid = %u", id); + PSendSysMessage("Wp Event: Waypoint script removed: %u", id); + delete result; + } else - point = 1; + PSendSysMessage("Wp Event: ERROR: you have selected a non existing script: %u", id); + + return true; + } + + + if(show == "mod") + { + char* arg_1 = strtok(NULL," "); + + if(!arg_1) + { + SendSysMessage("ERROR: Waypoint script guid not present."); + return true; + } + + uint32 id = atoi(arg_1); - Player* player = m_session->GetPlayer(); + if(!id) + { + SendSysMessage("ERROR: No vallid waypoint script id not present."); + return true; + } - WorldDatabase.PExecuteLog("INSERT INTO creature_movement (id,point,position_x,position_y,position_z,orientation) VALUES ('%u','%u','%f', '%f', '%f', '%f')", - lowguid, point, player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), player->GetOrientation()); + char* arg_2 = strtok(NULL," "); + + if(!arg_2) + { SendSysMessage("ERROR: No argument present."); + 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 != "datatext") && (arg_string != "posx") +&& (arg_string != "posy") && (arg_string != "posz") && (arg_string != "orientation") +) { SendSysMessage("ERROR: No valid argument present."); + return true;} - // update movement type - WorldDatabase.PExecuteLog("UPDATE creature SET MovementType = '%u' WHERE guid = '%u'", WAYPOINT_MOTION_TYPE,lowguid); - if(pCreature) +char* arg_3; +std::string arg_str_2 = arg_2; + +if(arg_str_2 != "datatext") + arg_3 = strtok(NULL," "); + else arg_3 = strtok(NULL,"<>"); + +if(!arg_3) +{SendSysMessage("ERROR: No additional argument present."); + return true;} + +float coord; + + if(arg_str_2 == "setid") + { + uint32 newid = atoi(arg_3); + PSendSysMessage("Wp Event: Wypoint scipt guid: %u id changed: %u", newid, 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("ERROR: You have selected an non existing waypoint script guid."); + 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("Waypoint script: %u position_x updated.", 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("Waypoint script: %u position_y updated.", 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("Waypoint script: %u position_z updated.", 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("Waypoint script: %u orientation updated.", id); + return true; +} else if(arg_str_2 == "datatext") +{ + std::string arg_str_3 = arg_3; + + if(arg_str_3 == "NULL") + { + WorldDatabase.PExecute("UPDATE waypoint_scripts SET %s= NULL WHERE guid='%u'", arg_2, id); + PSendSysMessage("Waypoint script: %u datatext updated.", id); + return true; + } + 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("Waypoint script: %u datatext updated.", 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("Waypoint script: %u: %s updated.", id,arg_2); +} +return true; +} + +bool ChatHandler::HandleDistFormationCommand(const char* args) +{ +if(!*args) + { + SendSysMessage("No formation dist provided."); + return true; + } +uint32 dist = atoi(args); +Creature *target = getSelectedCreature(); + +if(!dist) + { + SendSysMessage("No valid formation dist provided."); + return true; + } + +QueryResult *result = WorldDatabase.PQuery("SELECT follower FROM creature_formations WHERE follower='%u'", target->GetGUIDLow()); + +if(!result) + { + QueryResult *result = WorldDatabase.PQuery("SELECT leader FROM creature_formations WHERE leader='%u'", target->GetGUIDLow()); + + if(!result) + SendSysMessage("Current creature is not in formation."); + else + { + WorldDatabase.PExecute("UPDATE creature_formations SET dist='%u' WHERE leader='%u'",dist,target->GetGUIDLow()); + delete result; + } + } + else + { + WorldDatabase.PExecute("UPDATE creature_formations SET dist='%u' WHERE follower='%u'", dist,target->GetGUIDLow()); + delete result; + } +SendSysMessage("Creature formation dist updated."); + + +return true; +} + +bool ChatHandler::HandleAngleFormationCommand(const char* args) +{ +if(!*args) + { + SendSysMessage("No formation angle provided."); + return true; + } +uint32 angle = atof(args); +Creature *target = getSelectedCreature(); + +if(!angle) + { + SendSysMessage("No valid formation angle provided."); + return true; + } + +QueryResult *result = WorldDatabase.PQuery("SELECT follower FROM creature_formations WHERE follower='%u'", target->GetGUIDLow()); + +if(!result) + { + QueryResult *result = WorldDatabase.PQuery("SELECT leader FROM creature_formations WHERE leader='%u'", target->GetGUIDLow()); + + if(!result) + SendSysMessage("Current creature is not in formation."); + else + { + WorldDatabase.PExecute("UPDATE creature_formations SET angle='%u' WHERE leader='%u'", angle,target->GetGUIDLow()); + delete result; + } + } + else + { + WorldDatabase.PExecute("UPDATE creature_formations SET angle='%u' WHERE follower='%u'", angle,target->GetGUIDLow()); + delete result; + } +SendSysMessage("Creature formation angle updated."); +return true; +} + +bool ChatHandler::HandleCreateFormationCommand(const char* args) +{ +if(!*args) + { + SendSysMessage("No leader GUID provided."); + return true; + } + +uint32 LeaderGuid = atoi(args); +Creature *target = getSelectedCreature(); + +if (!LeaderGuid) { - pCreature->SetDefaultMovementType(WAYPOINT_MOTION_TYPE); - pCreature->GetMotionMaster()->Initialize(); - if(pCreature->isAlive()) // dead creature will reset movement generator at respawn - { - pCreature->setDeathState(JUST_DIED); - pCreature->RemoveCorpse(); - pCreature->Respawn(); - } + SendSysMessage("No vallid leader GUID provided."); + return true; + } + +if(!target) + { + SendSysMessage("No follower selected."); + return true; } - PSendSysMessage(LANG_WAYPOINT_ADDED, point, lowguid); +QueryResult *result = WorldDatabase.PQuery("SELECT guid FROM creature WHERE guid='%u'", LeaderGuid); - return true; -} // HandleWpAddCommand + if(!result) + { + SendSysMessage("ERROR: You have selected GUID of non existing creature."); + return true; + } + else delete result; -/** - * .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 - * User has selected a visual waypoint before. - * is added to this waypoint. Everytime the - * NPC comes to this waypoint, the emote is called. - * - * emote - * User has not selected visual waypoint before. - * For the waypoint for the NPC with - * an emote is added. - * Everytime the NPC comes to this waypoint, the emote is called. - * - * - * info -> User did not select a visual waypoint and - */ +QueryResult *result1 = WorldDatabase.PQuery("SELECT follower FROM creature_formations WHERE follower='%u'", LeaderGuid); + +if(!result1) + { + WorldDatabase.PExecute("INSERT INTO creature_formations(leader,follower) VALUES('%u','%u')", LeaderGuid,target->GetGUIDLow()); + } + else + { + delete result1; + WorldDatabase.PExecute("UPDATE creature_formations SET leader='%u' WHERE follower='%u'", LeaderGuid,target->GetGUIDLow()); + } +SendSysMessage("Formation created successfuly."); +return true; +} + +bool ChatHandler::HandleDismissFormationCommand(const char* args) +{ + +Creature *target = getSelectedCreature(); + +if(!target) + { + SendSysMessage("No creature selected."); + return true; + } + +QueryResult *result = WorldDatabase.PQuery("SELECT follower FROM creature_formations WHERE follower='%u'", target->GetGUIDLow()); + +if(!result) + { + QueryResult *result = WorldDatabase.PQuery("SELECT leader FROM creature_formations WHERE leader='%u'", target->GetGUIDLow()); + + if(!result) + SendSysMessage("Current creature is not in formation."); + else + { + QueryResult *result = WorldDatabase.PQuery("DELETE * FROM creature_formations WHERE leader='%u'", target->GetGUIDLow()); + delete result; + } + } + else + { + WorldDatabase.PExecute("DELETE FROM creature_formations WHERE follower='%u'", target->GetGUIDLow()); + delete result; + } +SendSysMessage("Formation dismissed successfuly."); +return true; +} + bool ChatHandler::HandleWpModifyCommand(const char* args) { sLog.outDebug("DEBUG: HandleWpModifyCommand"); @@ -2024,11 +2445,9 @@ std::string show = show_str; // Check // Remember: "show" must also be the name of a column! - if( (show != "emote") && (show != "spell") && (show != "aiscript") - && (show != "text1") && (show != "text2") && (show != "text3") && (show != "text4") && (show != "text5") - && (show != "waittime") && (show != "del") && (show != "move") && (show != "add") - && (show != "model1") && (show != "model2") && (show != "orientation") - && (show != "import") && (show != "export") ) + if( (show != "delay") && (show != "event_id") && (show != "event_chance") + && (show != "flag") && (show != "del") && (show != "move") && (show != "wpadd") + ) { return false; } @@ -2039,10 +2458,10 @@ // 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 pathid = 0; uint32 point = 0; uint32 wpGuid = 0; - Unit* target = getSelectedCreature(); + Creature* target = getSelectedCreature(); if(target) { @@ -2051,39 +2470,30 @@ // The visual waypoint Creature* wpCreature = NULL; - wpGuid = target->GetGUIDLow(); + 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 + wpCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_NEW_GUID(wpGuid, VISUAL_WAYPOINT, HIGHGUID_UNIT)); + + // attempt check creature existence by DB data if(!wpCreature) { - CreatureData const* data = objmgr.GetCreatureData(wpGuid); - if(!data) - { + 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 ) - { - if( (show != "export") && (show != "import") ) - { - PSendSysMessage(LANG_WAYPOINT_VP_SELECT); - return true; - } - lowguid = wpGuid; - arg_str = strtok((char*)NULL, " "); - } - else - { + // User did select a visual waypoint? + // Check the creature + if (wpCreature->GetEntry() == VISUAL_WAYPOINT ) + { QueryResult *result = - WorldDatabase.PQuery( "SELECT id, point FROM creature_movement WHERE wpguid = %u", - target->GetGUIDLow() ); + WorldDatabase.PQuery( "SELECT id, point FROM waypoint_data WHERE wpguid = %u", + wpGuid); if(!result) { sLog.outDebug("DEBUG: HandleWpModifyCommand - No waypoint found - used 'wpguid'"); @@ -2096,7 +2506,7 @@ // (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 )", + 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) { @@ -2109,8 +2519,8 @@ do { Field *fields = result->Fetch(); - lowguid = fields[0].GetUInt32(); - point = fields[1].GetUInt32(); + pathid = fields[0].GetUInt32(); + point = fields[1].GetUInt32(); }while( result->NextRow() ); // Cleanup memory @@ -2118,14 +2528,9 @@ delete result; // We have the waypoint number and the GUID of the "master npc" // 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, " "); - } + + arg_str = strtok((char*)NULL, " "); + } } else @@ -2134,18 +2539,10 @@ char* guid_str = strtok((char*)NULL, " "); char* point_str = strtok((char*)NULL, " "); - // Text is enclosed in "<>", all other arguments not - if( show.find("text") != std::string::npos ) + arg_str = strtok((char*)NULL, " "); + + if( !guid_str ) { - arg_str = strtok((char*)NULL, "<>"); - } - else - { - arg_str = strtok((char*)NULL, " "); - } - - if( !guid_str ) - { SendSysMessage(LANG_WAYPOINT_NOGUID); return false; } @@ -2154,7 +2551,7 @@ SendSysMessage(LANG_WAYPOINT_NOWAYPOINTGIVEN); return false; } - if( (show != "del") && (show != "move") && (show != "add") ) + if( (show != "del") && (show != "move") ) { if( !arg_str ) { @@ -2162,15 +2559,15 @@ return false; } } - lowguid = atoi((char*)guid_str); - PSendSysMessage("DEBUG: GUID provided: %d", lowguid); + pathid = atoi((char*)guid_str); + PSendSysMessage("DEBUG: GUID provided: %d", pathid); 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'", lowguid, point); + QueryResult *result = WorldDatabase.PQuery( "SELECT wpguid FROM waypoint_data WHERE id = '%u' AND point = '%u'", pathid, point); if(result) { do @@ -2184,12 +2581,12 @@ } else { - PSendSysMessage(LANG_WAYPOINT_NOTFOUNDSEARCH, lowguid, point); + PSendSysMessage(LANG_WAYPOINT_NOTFOUNDSEARCH, pathid, point); // Select waypoint number from database - QueryResult *result = WorldDatabase.PQuery( "SELECT position_x,position_y,position_z FROM creature_movement WHERE point='%d' AND id = '%u'", point, lowguid); + 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, lowguid); + PSendSysMessage(LANG_WAYPOINT_NOTFOUND, pathid); return true; } @@ -2229,7 +2626,7 @@ sLog.outDebug("DEBUG: HandleWpModifyCommand - Parameters parsed - now execute the command"); // Check for argument - if( (show.find("text") == std::string::npos ) && (show != "del") && (show != "move") && (show != "add") && (show != "aiscript")) + if((show != "del") && (show != "move")) { if( arg_str == NULL ) { @@ -2237,97 +2634,12 @@ return false; } } - // 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 - /* impossible without entry - Creature* npcCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), MAKE_GUID(lowguid, HIGHGUID_UNIT)); - */ - Creature* npcCreature = (Creature*)target; - - if( !npcCreature ) - { - PSendSysMessage(LANG_WAYPOINT_NPCNOTFOUND); - return true; - } - else - { - // obtain real GUID for DB operations - lowguid = npcCreature->GetDBTableGUIDLow(); - } - 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 -- SELECT MAX(`point`)"); - QueryResult *result = WorldDatabase.PQuery( "SELECT MAX(point) FROM creature_movement WHERE id = '%u'",lowguid); - uint32 maxPoint = 0; - if( result ) - { - maxPoint = (*result)[0].GetUInt32(); - delete result; - } - for( uint32 i=maxPoint; i>point; i-- ) - { - WorldDatabase.PExecuteLog("UPDATE creature_movement SET point=point+1 WHERE id='%u' AND point='%u'", lowguid, i); - } - - Player* chr = m_session->GetPlayer(); - WorldDatabase.PExecuteLog("INSERT INTO creature_movement (id,point,position_x,position_y,position_z) VALUES ('%u','%u','%f', '%f', '%f')", - lowguid, point+1, 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->RemoveCorpse(); - npcCreature->Respawn(); - } - } - - Creature* wpCreature = new Creature(chr); - if (!wpCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), chr->GetMapId(), - chr->GetPositionX(), chr->GetPositionY(), chr->GetPositionZ(), chr->GetOrientation(), VISUAL_WAYPOINT,0)) - { - PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, VISUAL_WAYPOINT); - delete wpCreature; - return false; - } - WorldDatabase.PExecuteLog("UPDATE creature_movement SET wpguid = '%u' WHERE id = '%u' and point = '%u'", wpCreature->GetGUIDLow(), lowguid, point+1); - - wpCreature->SaveToDB(); - // To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells(); - wpCreature->LoadFromDB(wpCreature->GetDBTableGUIDLow(), chr->GetInstanceId()); - MapManager::Instance().GetMap(wpCreature->GetMapId(), wpCreature)->Add(wpCreature); - - PSendSysMessage(LANG_WAYPOINT_ADDED_NO, point+1); - return true; - } // add - + if(show == "del" && target) { - PSendSysMessage("DEBUG: wp modify del, GUID: %u", lowguid); + PSendSysMessage("DEBUG: wp modify del, PathID: %u", pathid); - // Get the creature for which we read the waypoint - /* impossible without entry - Creature* npcCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_GUID(lowguid, HIGHGUID_UNIT)); - */ - Creature* npcCreature = (Creature*)target; - - // wpCreature + // wpCreature Creature* wpCreature = NULL; if( wpGuid != 0 ) { @@ -2337,55 +2649,22 @@ ObjectAccessor::Instance().AddObjectToRemoveList(wpCreature); } - // What to do: - // Remove the visual spawnpoint - // Adjust the waypoints - // Respawn the owner of the waypoints + 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); - WorldDatabase.PExecuteLog("DELETE FROM creature_movement WHERE id='%u' AND point='%u'", - lowguid, point); - WorldDatabase.PExecuteLog("UPDATE creature_movement SET point=point-1 WHERE id='%u' AND point>'%u'", - 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->RemoveCorpse(); - npcCreature->Respawn(); - } - } - PSendSysMessage(LANG_WAYPOINT_REMOVED); return true; } // del if(show == "move" && target) { - PSendSysMessage("DEBUG: wp move, GUID: %u", lowguid); + PSendSysMessage("DEBUG: wp move, PathID: %u", pathid); Player *chr = m_session->GetPlayer(); { - // Get the creature for which we read the waypoint - /* impossible without entry - Creature* npcCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_GUID(lowguid,HIGHGUID_UNIT)); - */ - Creature* npcCreature = (Creature*)target; - - // wpCreature + // wpCreature Creature* wpCreature = NULL; // What to do: // Move the visual spawnpoint @@ -2406,263 +2685,42 @@ return false; } wpCreature2->SaveToDB(); - // To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells(); - wpCreature2->LoadFromDB(wpCreature2->GetDBTableGUIDLow(), chr->GetInstanceId()); - MapManager::Instance().GetMap(npcCreature->GetMapId(), npcCreature)->Add(wpCreature2); - //MapManager::Instance().GetMap(npcCreature->GetMapId())->Add(wpCreature2); + wpCreature2->LoadFromDB(wpCreature2->GetDBTableGUIDLow(), chr->GetInstanceId()); + MapManager::Instance().GetMap(chr->GetMapId(), chr)->Add(wpCreature2); + } - WorldDatabase.PExecuteLog("UPDATE creature_movement SET position_x = '%f',position_y = '%f',position_z = '%f' where id = '%u' AND point='%u'", - chr->GetPositionX(), chr->GetPositionY(), chr->GetPositionZ(), lowguid, point ); + 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 ); - if(npcCreature) - { - npcCreature->GetMotionMaster()->Initialize(); - if(npcCreature->isAlive()) // dead creature will reset movement generator at respawn - { - npcCreature->setDeathState(JUST_DIED); - npcCreature->RemoveCorpse(); - npcCreature->Respawn(); - } - } PSendSysMessage(LANG_WAYPOINT_CHANGED); } return true; } // move - if(show == "export") - { - PSendSysMessage("DEBUG: wp export, GUID: %u", lowguid); - - std::ofstream outfile; - outfile.open (arg_str); - - 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, text1, text2, text3, text4, text5, id FROM creature_movement WHERE id = '%u' ORDER BY point", lowguid ); - - if( result ) - { - 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, text1, text2, text3, text4, text5 ) values "; - - //sLog.outDebug("( "); - outfile << "( "; - //sLog.outDebug("id"); - outfile << fields[16].GetUInt32(); // id - outfile << ", "; - //sLog.outDebug("point"); - outfile << fields[0].GetUInt32(); // point - outfile << ", "; - //sLog.outDebug("position_x"); - outfile << fields[1].GetFloat(); // position_x - outfile << ", "; - //sLog.outDebug("position_y"); - outfile << fields[2].GetFloat(); // position_y - outfile << ", "; - //sLog.outDebug("position_z"); - outfile << fields[3].GetUInt32(); // position_z - outfile << ", "; - //sLog.outDebug("orientation"); - outfile << fields[4].GetUInt32(); // orientation - outfile << ", "; - //sLog.outDebug("model1"); - outfile << fields[5].GetUInt32(); // model1 - outfile << ", "; - //sLog.outDebug("model2"); - outfile << fields[6].GetUInt32(); // model2 - outfile << ", "; - //sLog.outDebug("waittime"); - outfile << fields[7].GetUInt16(); // waittime - outfile << ", "; - //sLog.outDebug("emote"); - outfile << fields[8].GetUInt32(); // emote - outfile << ", "; - //sLog.outDebug("spell"); - outfile << fields[9].GetUInt32(); // spell - outfile << ", "; - //sLog.outDebug("text1"); - const char *tmpChar = fields[10].GetString(); - if( !tmpChar ) - { - outfile << "NULL"; // text1 - } - else - { - outfile << "'"; - outfile << tmpChar; // text1 - outfile << "'"; - } - outfile << ", "; - //sLog.outDebug("text2"); - tmpChar = fields[11].GetString(); - if( !tmpChar ) - { - outfile << "NULL"; // text2 - } - else - { - outfile << "'"; - outfile << tmpChar; // text2 - outfile << "'"; - } - outfile << ", "; - //sLog.outDebug("text3"); - tmpChar = fields[12].GetString(); - if( !tmpChar ) - { - outfile << "NULL"; // text3 - } - else - { - outfile << "'"; - outfile << tmpChar; // text3 - outfile << "'"; - } - outfile << ", "; - //sLog.outDebug("text4"); - tmpChar = fields[13].GetString(); - if( !tmpChar ) - { - outfile << "NULL"; // text4 - } - else - { - outfile << "'"; - outfile << tmpChar; // text4 - outfile << "'"; - } - outfile << ", "; - //sLog.outDebug("text5"); - tmpChar = fields[14].GetString(); - if( !tmpChar ) - { - outfile << "NULL"; // text5 - } - else - { - outfile << "'"; - outfile << tmpChar; // text5 - outfile << "'"; - } - outfile << ");\n "; - - } while( result->NextRow() ); - delete result; - - PSendSysMessage(LANG_WAYPOINT_EXPORTED); - } - else - { - PSendSysMessage(LANG_WAYPOINT_NOTHINGTOEXPORT); - outfile << GetMangosString(LANG_WAYPOINT_NOTHINGTOEXPORT); - } - outfile.close(); - - return true; - } - if(show == "import") - { - PSendSysMessage("DEBUG: wp import, GUID: %u", lowguid); - - std::string line; - std::ifstream infile (arg_str); - if (infile.is_open()) - { - while (! infile.eof() ) - { - getline (infile,line); - //cout << line << endl; - QueryResult *result = WorldDatabase.PQuery(line.c_str()); - delete result; - } - infile.close(); - } - PSendSysMessage(LANG_WAYPOINT_IMPORTED); - - return true; - } - - // Create creature - npc that has the waypoint - Creature* npcCreature = NULL; - - /* FIXME: impossible withput entry - if(lowguid) - npcCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_GUID(lowguid,HIGHGUID_UNIT)); - */ - - // attempt check creature existance by DB - if(!npcCreature) - { - if(!objmgr.GetCreatureData(lowguid)) - { - PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, lowguid); - return true; - } - } - 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 creature_movement SET %s=NULL WHERE id='%u' AND point='%u'", - show_str, lowguid, point); + 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 creature_movement SET %s='%s' WHERE id='%u' AND point='%u'", - show_str, text2.c_str(), lowguid, point); + 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); - 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->RemoveCorpse(); - 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 -> 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 -> 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 -> 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"); @@ -2679,20 +2737,16 @@ // 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 + + uint32 pathid = 0; + Creature* target = getSelectedCreature(); uint32 lowguid = 0; - Unit* target = getSelectedCreature(); - // Did player provide a GUID? + + // Did player provide a PathID? if (!guid_str) { sLog.outDebug("DEBUG: HandleWpShowCommand: !guid_str"); - // No GUID provided + // No PathID provided // -> Player must have selected a creature if(!target) @@ -2700,20 +2754,20 @@ SendSysMessage(LANG_SELECT_CREATURE); return true; } - lowguid = target->GetGUIDLow(); - } + pathid = target->GetWaypointPath(); + } else { - sLog.outDebug("DEBUG: HandleWpShowCommand: GUID provided"); - // GUID provided + sLog.outDebug("DEBUG: HandleWpShowCommand: PathID provided"); + // PathID provided // Warn if player also selected a creature // -> Creature selection is ignored <- if(target) { SendSysMessage(LANG_WAYPOINT_CREATSELECTED); } - lowguid = atoi((char*)guid_str); - } + pathid = atoi((char*)guid_str); + } sLog.outDebug("DEBUG: HandleWpShowCommand: danach"); @@ -2722,114 +2776,71 @@ Creature* pCreature = NULL; - sLog.outDebug("DEBUG: HandleWpShowCommand: lowguid: %u", lowguid); + sLog.outDebug("DEBUG: HandleWpShowCommand: PathID: %u", pathid); + + sLog.outDebug("DEBUG: HandleWpShowCommand: wpshow - show: %s", show_str); - /* imposiible without entry - if(lowguid) - pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_GUID(lowguid,HIGHGUID_UNIT)); - */ - - sLog.outDebug("DEBUG: HandleWpShowCommand: Habe creature: %ld", pCreature ); - // attempt check creature existance by DB - if(!pCreature) - { - if(!objmgr.GetCreatureData(lowguid)) - { - PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, lowguid); - return true; - } - } - - sLog.outDebug("DEBUG: HandleWpShowCommand: wpshow - show: %s", show_str); //PSendSysMessage("wpshow - show: %s", show); // 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( pCreature->GetEntry() != VISUAL_WAYPOINT ) + { + + // Check if the user did specify a visual waypoint + if( target->GetEntry() != VISUAL_WAYPOINT ) { PSendSysMessage(LANG_WAYPOINT_VP_SELECT); return true; } - //PSendSysMessage("wp on, GUID: %u", lowguid); - - //pCreature->GetPositionX(); - - QueryResult *result = - WorldDatabase.PQuery( "SELECT id, point, waittime, emote, spell, text1, text2, text3, text4, text5, model1, model2 FROM creature_movement WHERE wpguid = %u", - pCreature->GetGUID() ); - if(!result) + QueryResult *result = WorldDatabase.PQuery( "SELECT id, point, delay, move_flag, event_id, event_chance FROM waypoint_data 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, pCreature->GetGUID()); - - result = WorldDatabase.PQuery( "SELECT id, point, waittime, emote, spell, text1, text2, text3, text4, text5, model1, model2 FROM creature_movement WHERE (abs(position_x - %f) <= %s ) and (abs(position_y - %f) <= %s ) and (abs(position_z - %f) <= %s )", - pCreature->GetPositionX(), maxDIFF, pCreature->GetPositionY(), maxDIFF, pCreature->GetPositionZ(), maxDIFF); - if(!result) - { - PSendSysMessage(LANG_WAYPOINT_NOTFOUNDDBPROBLEM, lowguid); - return true; - } + SendSysMessage(LANG_WAYPOINT_NOTFOUNDDBPROBLEM); + return true; } - do + + SendSysMessage("DEBUG: wp show info:"); + + 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(); - const char * text1 = fields[5].GetString(); - const char * text2 = fields[6].GetString(); - const char * text3 = fields[7].GetString(); - const char * text4 = fields[8].GetString(); - const char * text5 = fields[9].GetString(); - uint32 model1 = fields[10].GetUInt32(); - uint32 model2 = fields[11].GetUInt32(); + 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(); - // 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("Show info: for current point: %u, Path ID: %u", point, pathid); + PSendSysMessage("Show info: delay: %u", delay); + PSendSysMessage("Show info: Move flag: %u", flag); + PSendSysMessage("Show info: Waypoint event: %u", ev_id); + PSendSysMessage("Show info: Event chance: %u", ev_chance); + }while( result->NextRow() ); - PSendSysMessage(LANG_WAYPOINT_INFO_TITLE, point, (wpCreature ? wpCreature->GetName() : ""), 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); - PSendSysMessage(LANG_WAYPOINT_INFO_TEXT, 1, text1); - PSendSysMessage(LANG_WAYPOINT_INFO_TEXT, 2, text2); - PSendSysMessage(LANG_WAYPOINT_INFO_TEXT, 3, text3); - PSendSysMessage(LANG_WAYPOINT_INFO_TEXT, 4, text4); - PSendSysMessage(LANG_WAYPOINT_INFO_TEXT, 5, text5); - - }while( result->NextRow() ); - // Cleanup memory + // 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) + { + QueryResult *result = WorldDatabase.PQuery( "SELECT point, position_x,position_y,position_z FROM waypoint_data WHERE id = '%u'", pathid); + + if(!result) { - PSendSysMessage(LANG_WAYPOINT_NOTFOUND, lowguid); + PSendSysMessage("Path no found.", pathid); return true; } - // Delete all visuals for this NPC - QueryResult *result2 = WorldDatabase.PQuery( "SELECT wpguid FROM creature_movement WHERE id = '%u' and wpguid <> 0", lowguid); - if(result2) + + PSendSysMessage("DEBUG: wp on, PathID: %u", 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 @@ -2852,8 +2863,10 @@ } }while( result2->NextRow() ); - delete result2; - if( hasError ) + + delete result2; + + if( hasError ) { PSendSysMessage(LANG_WAYPOINT_TOOFAR1); PSendSysMessage(LANG_WAYPOINT_TOOFAR2); @@ -2882,19 +2895,25 @@ delete result; return false; } - wpCreature->SetVisibility(VISIBILITY_OFF); - sLog.outDebug("DEBUG: UPDATE creature_movement SET wpguid = '%u"); + + sLog.outDebug("DEBUG: UPDATE waypoint_data 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); + WorldDatabase.PExecuteLog("UPDATE waypoint_data SET wpguid = '%u' WHERE id = '%u' and point = '%u'", wpCreature->GetGUIDLow(), pathid, point); wpCreature->SaveToDB(); // To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells(); wpCreature->LoadFromDB(wpCreature->GetDBTableGUIDLow(), chr->GetInstanceId()); MapManager::Instance().GetMap(wpCreature->GetMapId(), wpCreature)->Add(wpCreature); - //MapManager::Instance().GetMap(wpCreature->GetMapId())->Add(wpCreature); + if(target) + { + wpCreature->SetDisplayId(target->GetDisplayId()); + wpCreature->SetFloatValue(OBJECT_FIELD_SCALE_X, 0.5); + } + //MapManager::Instance().GetMap(wpCreature->GetMapId())->Add(wpCreature); }while( result->NextRow() ); - // Cleanup memory + SendSysMessage("Showing the current creature's path."); + // Cleanup memory delete result; return true; } @@ -2903,10 +2922,10 @@ { 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); + 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, lowguid); + PSendSysMessage(LANG_WAYPOINT_NOTFOUND, pathid); return true; } @@ -2931,7 +2950,13 @@ pCreature->SaveToDB(); pCreature->LoadFromDB(pCreature->GetDBTableGUIDLow(), chr->GetInstanceId()); MapManager::Instance().GetMap(pCreature->GetMapId(), pCreature)->Add(pCreature); - //player->PlayerTalkClass->SendPointOfInterest(x, y, 6, 6, 0, "First Waypoint"); + + if(target) + { + pCreature->SetDisplayId(target->GetDisplayId()); + pCreature->SetFloatValue(OBJECT_FIELD_SCALE_X, 0.5); + } + //player->PlayerTalkClass->SendPointOfInterest(x, y, 6, 6, 0, "First Waypoint"); // Cleanup memory delete result; @@ -2940,9 +2965,9 @@ if(show == "last") { - PSendSysMessage("DEBUG: wp last, GUID: %u", lowguid); + PSendSysMessage("DEBUG: wp last, PathID: %u", pathid); - QueryResult *result = WorldDatabase.PQuery( "SELECT MAX(point) FROM creature_movement WHERE id = '%u'",lowguid); + QueryResult *result = WorldDatabase.PQuery( "SELECT MAX(point) FROM waypoint_data WHERE id = '%u'",pathid); if( result ) { Maxpoint = (*result)[0].GetUInt32(); @@ -2952,10 +2977,10 @@ else Maxpoint = 0; - result = WorldDatabase.PQuery( "SELECT position_x,position_y,position_z FROM creature_movement WHERE point ='%u' AND id = '%u'",Maxpoint, lowguid); + 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, lowguid); + PSendSysMessage(LANG_WAYPOINT_NOTFOUNDLAST, pathid); return true; } Field *fields = result->Fetch(); @@ -2979,7 +3004,13 @@ pCreature->SaveToDB(); pCreature->LoadFromDB(pCreature->GetDBTableGUIDLow(), chr->GetInstanceId()); MapManager::Instance().GetMap(pCreature->GetMapId(), pCreature)->Add(pCreature); - //player->PlayerTalkClass->SendPointOfInterest(x, y, 6, 6, 0, "Last Waypoint"); + + if(target) + { + pCreature->SetDisplayId(target->GetDisplayId()); + pCreature->SetFloatValue(OBJECT_FIELD_SCALE_X, 0.5); + } + //player->PlayerTalkClass->SendPointOfInterest(x, y, 6, 6, 0, "Last Waypoint"); // Cleanup memory delete result; return true; @@ -2987,7 +3018,7 @@ if(show == "off") { - QueryResult *result = WorldDatabase.PQuery("SELECT guid FROM creature WHERE id = '%d'", VISUAL_WAYPOINT); + QueryResult *result = WorldDatabase.PQuery("SELECT guid FROM creature WHERE id = '%u'", 1); if(!result) { SendSysMessage(LANG_WAYPOINT_VP_NOTFOUND); @@ -3018,7 +3049,7 @@ } }while(result->NextRow()); // set "wpguid" column to "empty" - no visual waypoint spawned - WorldDatabase.PExecuteLog("UPDATE creature_movement SET wpguid = '0'"); + WorldDatabase.PExecuteLog("UPDATE waypoint_data SET wpguid = '0'"); if( hasError ) { Index: src/game/Level3.cpp =================================================================== --- src/game/Level3.cpp (revision 5687) +++ src/game/Level3.cpp (working copy) @@ -108,7 +108,8 @@ HandleReloadQuestEndScriptsCommand("a"); HandleReloadQuestStartScriptsCommand("a"); HandleReloadSpellScriptsCommand("a"); - SendGlobalSysMessage("DB tables `*_scripts` reloaded."); + HandleReloadWaypointScriptsCommand("a"); + SendGlobalSysMessage("DB tables `*_scripts` reloaded."); return true; } @@ -125,7 +126,8 @@ HandleReloadSpellScriptTargetCommand("a"); HandleReloadSpellTeleportCommand("a"); HandleReloadSpellThreatsCommand("a"); - return true; + HandleReloadWaypointScriptsCommand("a"); + return true; } bool ChatHandler::HandleReloadAreaTriggerTavernCommand(const char*) @@ -435,6 +437,25 @@ return true; } +bool ChatHandler::HandleReloadWaypointScriptsCommand(const char* arg) +{ + if(sWorld.IsScriptScheduled()) + { + SendSysMessage("DB scripts used currently, please attempt reload later."); + return true; + } + + if(*arg!='a') + sLog.outString( "Re-Loading Scripts from `quest_start_scripts`..."); + + objmgr.LoadWaypointScripts(); + + if(*arg!='a') + SendGlobalSysMessage("DB table `quest_start_scripts` reloaded."); + + return true; +} + bool ChatHandler::HandleReloadSpellScriptsCommand(const char* arg) { if(sWorld.IsScriptScheduled()) Index: src/game/Object.cpp =================================================================== --- src/game/Object.cpp (revision 5687) +++ src/game/Object.cpp (working copy) @@ -525,9 +525,54 @@ { if(!target) return; + + bool reset = false; + uint32 oldflags = 0; + bool IsActivateToQuest = false; + + Creature const* pThis = static_cast(this); + /* + if(GetTypeId() == TYPEID_UNIT && pThis->isTagged && (pThis->loot.gold || pThis->loot.items.size())) + { + // Let's see if we're the tagger or not. + oldflags = m_uint32Values[UNIT_DYNAMIC_FLAGS]; + uint32 Flags = m_uint32Values[UNIT_DYNAMIC_FLAGS]; + uint32 oldFlags = 0; - bool IsActivateToQuest = false; - if (updatetype == UPDATETYPE_CREATE_OBJECT || updatetype == UPDATETYPE_CREATE_OBJECT2) + if(pThis->TaggerGuid == target->GetGUID()) + + { + // Our target is our tagger. + oldFlags = 4; + + if(Flags & 4) + Flags &= ~oldFlags; + + if(!(Flags & 1)) + Flags |= 1; + } + else + { + // Target is not the tagger. + oldFlags = 1; + + if(!(Flags & 4)) + Flags |= 4; + + if(Flags & 1) + Flags &= ~oldFlags; + } + + m_uint32Values[UNIT_DYNAMIC_FLAGS] = Flags; + + updateMask->SetBit(UNIT_DYNAMIC_FLAGS); + + + + reset = true; + }*/ + + if (updatetype == UPDATETYPE_CREATE_OBJECT || updatetype == UPDATETYPE_CREATE_OBJECT2) { if (isType(TYPE_GAMEOBJECT) && !((GameObject*)this)->IsTransport()) { @@ -584,14 +629,15 @@ { *data << (m_uint32Values[ index ] & ~UNIT_FLAG_NOT_SELECTABLE); } - else - { - // send in current format (float as float, uint32 as uint32) + + else + + // send in current format (float as float, uint32 as uint32) *data << m_uint32Values[ index ]; } } } - } + else if(isType(TYPE_GAMEOBJECT)) // gameobject case { for( uint16 index = 0; index < m_valuesCount; index ++ ) @@ -635,6 +681,12 @@ } } } + +//if(reset && GetTypeId() == TYPEID_UNIT) + //m_uint32Values[UNIT_DYNAMIC_FLAGS] = oldflags; + + + } void Object::ClearUpdateMask(bool remove) Index: src/game/ObjectAccessor.cpp =================================================================== --- src/game/ObjectAccessor.cpp (revision 5687) +++ src/game/ObjectAccessor.cpp (working copy) @@ -35,6 +35,7 @@ #include "GridNotifiersImpl.h" #include "Opcodes.h" #include "ObjectDefines.h" +#include "WaypointMovementGenerator.h" #include @@ -561,16 +562,24 @@ ObjectAccessor::Update(uint32 diff) { { - typedef std::multimap CreatureLocationHolderType; + typedef std::multimap CreatureLocationHolderType; CreatureLocationHolderType creature_locations; //TODO: Player guard HashMapHolder::MapType& playerMap = HashMapHolder::GetContainer(); - for(HashMapHolder::MapType::iterator iter = playerMap.begin(); iter != playerMap.end(); ++iter) + + for(HashMapHolder::MapType::iterator iter = playerMap.begin(); iter != playerMap.end(); ++iter) { if(iter->second->IsInWorld()) iter->second->Update(diff); creature_locations.insert( CreatureLocationHolderType::value_type(iter->second->GetMapId(), iter->second) ); } - + + WaypointMovementGenerator::ActiveCreatureList& WpMap = WaypointMovementGenerator::GetContainer(); + + for(WaypointMovementGenerator::ActiveCreatureList::iterator iter = WpMap.begin(); iter != WpMap.end(); ++iter) + { + creature_locations.insert( CreatureLocationHolderType::value_type(iter->second->GetMapId(), iter->second) ); + } + Map *map; MaNGOS::ObjectUpdater updater(diff); @@ -586,7 +595,7 @@ for(CreatureLocationHolderType::iterator iter=creature_locations.begin(); iter != creature_locations.end(); ++iter) { - Player *player = (*iter).second; + Unit *player = (*iter).second; map = MapManager::Instance().GetMap((*iter).first, player); CellPair standing_cell(MaNGOS::ComputeCellPair(player->GetPositionX(), player->GetPositionY())); Index: src/game/ObjectAccessor.h =================================================================== --- src/game/ObjectAccessor.h (revision 5687) +++ src/game/ObjectAccessor.h (working copy) @@ -24,6 +24,7 @@ #include "zthread/FastMutex.h" #include "Utilities/HashMap.h" #include "Policies/ThreadingModel.h" +#include "WaypointMovementGenerator.h" #include "ByteBuffer.h" #include "UpdateData.h" @@ -48,25 +49,27 @@ public: typedef HM_NAMESPACE::hash_map< uint64, T* > MapType; - typedef ZThread::FastMutex LockType; + typedef ZThread::FastMutex LockType; typedef MaNGOS::GeneralLock Guard; static void Insert(T* o) { m_objectMap[o->GetGUID()] = o; } - static void Remove(T* o) + + static void Remove(T* o) { Guard guard(i_lock); typename MapType::iterator itr = m_objectMap.find(o->GetGUID()); if (itr != m_objectMap.end()) m_objectMap.erase(itr); } - static T* Find(uint64 guid) + + static T* Find(uint64 guid) { typename MapType::iterator itr = m_objectMap.find(guid); return (itr != m_objectMap.end()) ? itr->second : NULL; } static MapType& GetContainer() { return m_objectMap; } - + static LockType* GetLock() { return &i_lock; } private: @@ -89,8 +92,8 @@ public: typedef HM_NAMESPACE::hash_map Player2CorpsesMapType; typedef HM_NAMESPACE::hash_map::value_type UpdateDataValueType; - - template static T* GetObjectInWorld(uint64 guid, T* /*fake*/) + + template static T* GetObjectInWorld(uint64 guid, T* /*fake*/) { return HashMapHolder::Find(guid); } @@ -140,7 +143,8 @@ static Creature* GetCreature(WorldObject const &, uint64); static Creature* GetCreatureOrPet(WorldObject const &, uint64); static Unit* GetUnit(WorldObject const &, uint64); - static Pet* GetPet(Unit const &, uint64 guid) { return GetPet(guid); } + static Creature* GetSqlIdCreature(uint32); + static Pet* GetPet(Unit const &, uint64 guid) { return GetPet(guid); } static Player* GetPlayer(Unit const &, uint64 guid) { return FindPlayer(guid); } static GameObject* GetGameObject(WorldObject const &, uint64); static DynamicObject* GetDynamicObject(Unit const &, uint64); @@ -149,8 +153,8 @@ static Player* FindPlayer(uint64); Player* FindPlayerByName(const char *name) ; - - HashMapHolder::MapType& GetPlayers() + + HashMapHolder::MapType& GetPlayers() { return HashMapHolder::GetContainer(); } Index: src/game/ObjectMgr.cpp =================================================================== --- src/game/ObjectMgr.cpp (revision 5687) +++ src/game/ObjectMgr.cpp (working copy) @@ -37,6 +37,7 @@ #include "GameEvent.h" #include "Spell.h" #include "Chat.h" +#include "WaypointMovementGenerator.h" INSTANTIATE_SINGLETON_1(ObjectMgr); @@ -45,6 +46,7 @@ ScriptMapMap sSpellScripts; ScriptMapMap sGameObjectScripts; ScriptMapMap sEventScripts; +ScriptMapMap sWaypointScripts; ObjectMgr::ObjectMgr() { @@ -658,6 +660,26 @@ } } +void ObjectMgr::LoadCreatureFormations() +{ + + sCreatureFormation.Load(); + + sLog.outString( ">> Loaded %u creature formations", sCreatureFormation.RecordCount ); + sLog.outString(); + + for(uint32 i = 1; i < sCreatureFormation.MaxEntry; ++i) + { + + CreatureFormation const* formation = sCreatureFormation.LookupEntry(i); + if(!formation) + continue; + + if(mCreatureDataMap.find(formation->follower)==mCreatureDataMap.end()) + sLog.outErrorDb("Creature (GUID: %u) does not exist but has a record in `creature_formation`",formation->follower); + } +} + EquipmentInfo const* ObjectMgr::GetEquipmentInfo(uint32 entry) { return sEquipmentStorage.LookupEntry(entry); @@ -808,6 +830,13 @@ cell_guids.creatures.erase(guid); } +void ObjectMgr::LoadWaypointData() +{ + sWaypointStore.Load(); + + sLog.outString(">> Loaded %u waypoints\n\n", sWaypointStore.GetRecordsCount() ); +} + void ObjectMgr::LoadGameobjects() { uint32 count = 0; @@ -3290,6 +3319,18 @@ } } +void ObjectMgr::LoadWaypointScripts() +{ + objmgr.LoadScripts(sWaypointScripts, "waypoint_scripts"); + + for(ScriptMapMap::const_iterator itr = sWaypointScripts.begin(); itr != sWaypointScripts.end(); ++itr) + { + QueryResult *query = WorldDatabase.PQuery("SELECT * FROM `waypoint_scripts` WHERE `event_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.PQuery("SELECT id, text FROM item_text"); Index: src/game/ObjectMgr.h =================================================================== --- src/game/ObjectMgr.h (revision 5687) +++ src/game/ObjectMgr.h (working copy) @@ -45,6 +45,7 @@ extern SQLStorage sCreatureStorage; extern SQLStorage sCreatureDataAddonStorage; +extern SQLStorage sCreatureFormation; extern SQLStorage sCreatureInfoAddonStorage; extern SQLStorage sCreatureModelStorage; extern SQLStorage sEquipmentStorage; @@ -81,6 +82,7 @@ extern ScriptMapMap sSpellScripts; extern ScriptMapMap sGameObjectScripts; extern ScriptMapMap sEventScripts; +extern ScriptMapMap sWaypointScripts; struct AreaTrigger { @@ -256,7 +258,12 @@ return sCreatureInfoAddonStorage.LookupEntry(entry); } - static ItemPrototype const* GetItemPrototype(uint32 id) { return sItemStorage.LookupEntry(id); } + static CreatureFormation const *GetFormation( uint32 lowguid ) + { + return sCreatureFormation.LookupEntry(lowguid); + } + + static ItemPrototype const* GetItemPrototype(uint32 id) { return sItemStorage.LookupEntry(id); } static InstanceTemplate const* GetInstanceTemplate(uint32 map) { @@ -409,6 +416,7 @@ void LoadQuestStartScripts(); void LoadEventScripts(); void LoadSpellScripts(); + void LoadWaypointScripts(); bool LoadMangosStrings(); void LoadMangosStringLocales(); @@ -419,7 +427,9 @@ void LoadCreatureRespawnTimes(); void LoadCreatureAddons(); void LoadCreatureModelInfo(); - void LoadEquipmentTemplates(); + void LoadWaypointData(); + void LoadCreatureFormations(); + void LoadEquipmentTemplates(); void LoadGameObjectLocales(); void LoadGameobjects(); void LoadGameobjectRespawnTimes(); @@ -693,8 +703,7 @@ MangosStringLocaleMap mMangosStringLocaleMap; RespawnTimes mCreatureRespawnTimes; RespawnTimes mGORespawnTimes; - - typedef std::vector GuildBankTabPriceMap; + typedef std::vector GuildBankTabPriceMap; GuildBankTabPriceMap mGuildBankTabPrice; }; Index: src/game/TargetedMovementGenerator.cpp =================================================================== --- src/game/TargetedMovementGenerator.cpp (revision 5687) +++ src/game/TargetedMovementGenerator.cpp (working copy) @@ -92,10 +92,22 @@ { if(!&owner) return; + owner.SetUnitMovementFlag(MOVEMENT_FLAG_RUN); + _setTargetLocation(owner); } +void +TargetedMovementGenerator::Initialize(Creature &owner) +{ + if(!&owner) + return; + + owner.SetUnitMovementFlag(MOVEMENT_FLAG_RUN); + _setTargetLocation(owner); +} + template void TargetedMovementGenerator::Finalize(T &owner) @@ -192,7 +204,7 @@ template void TargetedMovementGenerator::_setTargetLocation(Player &); template void TargetedMovementGenerator::_setTargetLocation(Creature &); template void TargetedMovementGenerator::Initialize(Player &); -template void TargetedMovementGenerator::Initialize(Creature &); +//template void TargetedMovementGenerator::Initialize(Creature &); template void TargetedMovementGenerator::Finalize(Player &); template void TargetedMovementGenerator::Finalize(Creature &); template void TargetedMovementGenerator::Reset(Player &); Index: src/game/Unit.cpp =================================================================== --- src/game/Unit.cpp (revision 5687) +++ src/game/Unit.cpp (working copy) @@ -442,7 +442,7 @@ // remove affects from attacker at any non-DoT damage (including 0 damage) if( damagetype != DOT) - { + { RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); @@ -474,7 +474,7 @@ if(!spellProto || spellProto->Mechanic != MECHANIC_ROOT) pVictim->RemoveSpellbyDamageTaken(SPELL_AURA_MOD_ROOT, damage); - if(pVictim->GetTypeId() != TYPEID_PLAYER) + if(pVictim->GetTypeId() != TYPEID_PLAYER) { //pVictim->SetInFront(this); // no xp,health if type 8 /critters/ @@ -9623,11 +9623,6 @@ // send explicit stop packet SendMonsterMove(GetPositionX(), GetPositionY(), GetPositionZ(),0, GetUnitMovementFlags(), 0); - - // update position and orientation; - WorldPacket data; - BuildHeartBeatMsg(&data); - SendMessageToSet(&data,false); } bool Unit::IsStandState() const Index: src/game/WaypointMovementGenerator.cpp =================================================================== --- src/game/WaypointMovementGenerator.cpp (revision 5687) +++ src/game/WaypointMovementGenerator.cpp (working copy) @@ -16,295 +16,396 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* -creature_movement Table -alter table creature_movement add `text1` varchar(255) default NULL; -alter table creature_movement add `text2` varchar(255) default NULL; -alter table creature_movement add `text3` varchar(255) default NULL; -alter table creature_movement add `text4` varchar(255) default NULL; -alter table creature_movement add `text5` varchar(255) default NULL; -alter table creature_movement add `emote` int(10) unsigned default '0'; -alter table creature_movement add `spell` int(5) unsigned default '0'; -alter table creature_movement add `wpguid` int(11) default '0'; - -*/ - +//Basic header #include #include "WaypointMovementGenerator.h" +//Accessors +#include "Database/DatabaseEnv.h" #include "ObjectMgr.h" +#include "World.h" +//Creature-specific headers #include "Creature.h" -#include "DestinationHolderImp.h" #include "CreatureAI.h" +//Player-Specific +#include "Player.h" +//Visual +#include "ProgressBar.h" +#include "MapManager.h" +#include "CreatureAI.h" -#include +WaypointStore sWaypointStore; -//-----------------------------------------------// -void -WaypointMovementGenerator::LoadPath(Creature &c) +void WaypointStore::Free() { - QueryResult *result = NULL; - sLog.outDebug("DEBUG: WaypointMovementGenerator::_load: GUID - %d", c.GetGUIDLow()); - // Identify by GUID - result = WorldDatabase.PQuery("SELECT position_x, position_y, position_z, orientation, model1, model2, waittime, emote, spell, text1, text2, text3, text4, text5 FROM creature_movement WHERE id = '%u' ORDER BY point", c.GetDBTableGUIDLow()); - /* - if( result ) { - sLog.outDebug("DEBUG: Number of hits: %d", result->GetRowCount()); - } else { - sLog.outDebug("DEBUG: Nothing found"); + wpdata.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 } - */ - if( result ) + records = (*result)[0].GetUInt32(); + delete result; + + + result = WorldDatabase.PQuery("SELECT `id`,`point`,`position_x`,`position_y`,`position_z`,`move_flag`,`delay`,`event_id`,`event_chance` FROM `waypoint_data` ORDER BY `id`, `point`"); + if(!result) { - unsigned int count = 0; - const unsigned int sz = result->GetRowCount(); - i_path.Resize( sz ); - i_delays.resize( sz ); - i_wpBehaviour.resize( sz ); + sLog.outErrorDb("The table `creature_addon` is empty or corrupted"); + return; + } - do - { - //sLog.outDebug("DEBUG: _load"); - Field *fields = result->Fetch(); - i_path[count].x = fields[0].GetFloat(); - i_path[count].y = fields[1].GetFloat(); - i_path[count].z = fields[2].GetFloat(); - float orientation = fields[3].GetFloat(); - uint32 model1 = fields[4].GetUInt32(); - uint32 model2 = fields[5].GetUInt32(); - i_delays[count] = fields[6].GetUInt16(); - uint32 emote = fields[7].GetUInt32(); - uint32 spell = fields[8].GetUInt32(); - std::string text1 = fields[9].GetCppString(); - std::string text2 = fields[10].GetCppString(); - std::string text3 = fields[11].GetCppString(); - std::string text4 = fields[12].GetCppString(); - std::string text5 = fields[13].GetCppString(); + WaypointPath* path_data; + uint32 total_records = result->GetRowCount(); - if( (emote != 0) || (spell != 0) - || !text1.empty() || !text2.empty() || !text3.empty() || !text4.empty() || !text5.empty() - || (model1 != 0) || (model2 != 0) || (orientation != 100)) - { - WaypointBehavior *tmpWPB = new WaypointBehavior; + 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 && id != 0) + path_data = new WaypointPath; + + float x,y,z; + x = fields[2].GetFloat(); + y = fields[3].GetFloat(); + z = fields[4].GetFloat(); - // sLog.outDebug("DEBUG: _load --- Adding WaypointBehavior"); + MaNGOS::NormalizeMapCoord(x); + MaNGOS::NormalizeMapCoord(y); - tmpWPB->text[0] = text1; - tmpWPB->text[1] = text2; - tmpWPB->text[2] = text3; - tmpWPB->text[3] = text4; - tmpWPB->text[4] = text5; - tmpWPB->orientation = orientation; - tmpWPB->emote = emote; - tmpWPB->spell = spell; - tmpWPB->model1 = model1; - tmpWPB->model2 = model2; - tmpWPB->HasDone = false; - i_wpBehaviour[count] = tmpWPB; - } - else - { - i_wpBehaviour[count] = NULL; - } + 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) + wpdata[id] = path_data; + + last_id = id; - if(!MaNGOS::IsValidMapCoord(i_path[count].x,i_path[count].y)) - { - sLog.outErrorDb("ERROR: Creature (guidlow %d,entry %d) have invalid coordinates in his waypoint %d (X: %d, Y: %d).", - c.GetGUIDLow(),c.GetEntry(),count,i_path[count].x,i_path[count].y - ); + } while(result->NextRow()) ; - // prevent invalid coordinates using - MaNGOS::NormalizeMapCoord(i_path[count].x); - MaNGOS::NormalizeMapCoord(i_path[count].y); - i_path[count].z = MapManager::Instance ().GetBaseMap(c.GetMapId())->GetHeight(i_path[count].x,i_path[count].y, i_path[count].z); - } - // to prevent a misbehaviour inside "update" - // update is alway 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 - if( count == (sz-1) ) - { - if( i_wpBehaviour[count] != NULL ) - { - i_wpBehaviour[count]->HasDone = true; - } - } - //if( i_delays[count] < 30 /* millisecond */ ) - // i_delays[count] = (rand() % 5000); - ++count; + delete result; +} - } while( result->NextRow() ); +void WaypointStore::UpdatePath(uint32 id) +{ + + if(wpdata.find(id)!= wpdata.end()) + wpdata[id]->clear(); + + QueryResult *result; - delete result; + result = WorldDatabase.PQuery("SELECT `id`,`point`,`position_x`,`position_y`,`position_z`,`move_flag`,`delay`,`event_id`,`event_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; - assert( sz == count ); - } + float x,y,z; + x = fields[2].GetFloat(); + y = fields[3].GetFloat(); + z = fields[4].GetFloat(); + + MaNGOS::NormalizeMapCoord(x); + MaNGOS::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()); + +wpdata[id] = path_data; + +delete result; } +WaypointData* CreateWaypoint(uint32 id, float x, float y, float z, bool run, uint32 delay, uint32 event_id, uint8 event_chance) +{ + WaypointData *wp = new WaypointData; + wp->id = id; + + MaNGOS::NormalizeMapCoord(x); + MaNGOS::NormalizeMapCoord(y); + + wp->x = x; + wp->y = y; + wp->z = z; + + wp->run = run; + wp->delay = delay; + wp->event_id = event_id; + wp->event_chance = event_chance; + + return wp; +} + +template void -WaypointMovementGenerator::ClearWaypoints() +WaypointMovementGenerator::Initialize(T &u) { - for (std::vector::iterator itr = i_wpBehaviour.begin(); itr != i_wpBehaviour.end(); ++itr) - delete (*itr); - i_wpBehaviour.clear(); + i_currentNode = 0; + i_nextMoveTime.Reset(0); + u.StopMoving(); + if(!path_id) + GeneratePathId(u); + waypoints = sWaypointStore.GetPath(path_id); + m_ActiveCreatureMap[u.GetGUID()] = &u; } void -WaypointMovementGenerator::Initialize() +WaypointMovementGenerator::Finalize(Creature &u) { - QueryResult *result = WorldDatabase.Query("SELECT distinct(id) as uniqueid FROM creature_movement"); + WaypointMovementGenerator::ActiveCreatureList::iterator itr = m_ActiveCreatureMap.find(u.GetGUID()); + if (itr != m_ActiveCreatureMap.end()) + m_ActiveCreatureMap.erase(itr); +} - if( result ) - { - do - { - Field *fields = result->Fetch(); - si_waypointHolders.insert( fields[0].GetUInt32() ); - } - while( result->NextRow() ); +void +WaypointMovementGenerator::Finalize(Player &u) +{ - delete result; - } } + +template +void +WaypointMovementGenerator::Reset(T &u) +{ + u.StopMoving(); + + float x,y,z; + i_destinationHolder.GetLocationNow(x,y,z); + + + Traveller traveller(u); + i_destinationHolder.GetDestination(x,y,z); + i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime()); +} + +template +void +WaypointMovementGenerator::GeneratePathId(T &unit) +{ + path_id = 0; +} + +void +WaypointMovementGenerator::GeneratePathId(Creature &unit) +{ + path_id = unit.GetWaypointPath(); +} + + +template +void +WaypointMovementGenerator::SetMoveFlag(T &unit, bool flag) + +{ + //I wonder how that should even work for players, empty for now +} + +void +WaypointMovementGenerator::SetMoveFlag(Creature &unit,bool flag) +{ + unit.SetUnitMovementFlag(flag); +} + +template +void +WaypointMovementGenerator::MovementInform(T &unit) +{ + +} + +void WaypointMovementGenerator::MovementInform(Creature &unit) +{ + unit.AI()->MovementInform(path_id); +} + +template bool -WaypointMovementGenerator::Update(Creature &creature, const uint32 &diff) +WaypointMovementGenerator::Update(T &unit, const uint32 &diff) { - if(!&creature) + if(!&unit) 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_STUNDED)) + if(unit.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNDED)) return true; - // prevent crash at empty waypoint path. - if(i_path.Empty()) - { + // Clear the generator if the path doesn't exist + if(!waypoints || !waypoints->size()) return true; - } - CreatureTraveller traveller(creature); + if(((Creature*)&unit)->IsStoppedByEvent()) + return true; + + Traveller traveller(unit); - /* - if( npcIsStopped[creature.GetGUID()] ) - { - i_nextMoveTime.Update(40000); - i_destinationHolder.UpdateTraveller(traveller, ((diff)-40000), false); - npcIsStopped[creature.GetGUID()] = false; - return true; - } - */ i_nextMoveTime.Update(diff); i_destinationHolder.UpdateTraveller(traveller, diff, false); - if( creature.IsStopped() ) - { - uint32 wpB = i_currentNode > 0 ? i_currentNode-1 : i_wpBehaviour.size()-1; - - if( i_wpBehaviour[wpB] != NULL ) - { - struct WaypointBehavior *tmpBehavior = i_wpBehaviour[wpB]; - - if (!tmpBehavior->HasDone) + if( i_nextMoveTime.Passed() ) + { + if( unit.IsStopped() ) + { + if(i_currentNode == waypoints->size() - 1) //If that's our last waypoint { - if(tmpBehavior->emote != 0) - { - creature.SetUInt32Value(UNIT_NPC_EMOTESTATE,tmpBehavior->emote); - } - //sLog.outDebug("DEBUG: tmpBehavior->text[0] TEST"); - if(!tmpBehavior->text[0].empty()) - { - //sLog.outDebug("DEBUG: tmpBehavior->text[0] != \"\""); - // Only one text is set - if( tmpBehavior->text[1].empty() ) - { - //sLog.outDebug("DEBUG: tmpBehavior->text[1] == NULL"); - creature.Say(tmpBehavior->text[0].c_str(), 0, 0); - } - else - { - // Select one from max 5 texts (0 and 1 laready checked) - int i = 2; - for( ; i < 5; ++i ) - if( tmpBehavior->text[i].empty() ) - break; + MovementInform(unit); + + if(repeating) //If the movement is repeating + i_currentNode = 0; //Start moving all over again + else + return false; //Clear the waypoint movement - //sLog.outDebug("DEBUG: tmpBehavior->text[i] == \"\": %d", i); - //sLog.outDebug("DEBUG: rand() % (i): %d", rand() % (i)); + } + else + i_currentNode++; - creature.Say(tmpBehavior->text[rand() % i].c_str(), 0, 0); - } - } - if(tmpBehavior->spell != 0) - { - //sLog.outDebug("DEBUG: wpSys - spell"); - creature.CastSpell(&creature,tmpBehavior->spell, false); - } - if (tmpBehavior->orientation !=100) - { - //sLog.outDebug("DEBUG: wpSys - orientation"); - creature.SetOrientation(tmpBehavior->orientation); - } - if(tmpBehavior->model1 != 0) - { - //sLog.outDebug("DEBUG: wpSys - model1"); - creature.SetDisplayId(tmpBehavior->model1); - } - tmpBehavior->HasDone = true; - MovementInform(creature); - } // HasDone == false - } // wpBehaviour found - } // i_creature.IsStopped() - - if( i_nextMoveTime.Passed() ) - { - if( creature.IsStopped() ) + ExecuteScript = false; + WaypointData* nextWP = *(waypoints->begin()+i_currentNode); + SetMoveFlag(unit, nextWP->run); + unit.addUnitState(UNIT_STAT_ROAMING); + + if(((Creature*)&unit)->IsFollower()) + { + + uint32 guid = ((Creature*)&unit)->GetCreatureFormation()->leader; + uint32 entry = objmgr.GetCreatureData(guid)->id; + + Creature* Leader = ObjectAccessor::Instance().GetObjectInWorld(MAKE_NEW_GUID(guid, entry, HIGHGUID_UNIT), (Creature*)NULL); + + if(Leader) + { + dist = ((Creature*)&unit)->GetCreatureFormation()->offset_dist; + offset = ((Creature*)&unit)->GetCreatureFormation()->offset_angle; + + if(dist && offset) + { + Map const* map = MapManager::Instance().GetBaseMap(unit.GetMapId()); + float x,y,z,pathangle; + pathangle = atan2(Leader->GetPositionY()-nextWP->y,Leader->GetPositionX()-nextWP->x); + + x = nextWP->x+cos(offset+pathangle)*dist; + y = nextWP->y+sin(offset+pathangle)*dist; + z = map->GetHeight(x,y,nextWP->z, false); // use .map base surface height + i_destinationHolder.SetDestination(traveller, x, y, z); + ((Creature*)&unit)->SetCoordsBeforeBattle(x,y,z); + Leader->SetLinkedtoFormation(true); + } + } + } + else + { + i_destinationHolder.SetDestination(traveller, nextWP->x, nextWP->y, nextWP->z); + ((Creature*)&unit)->SetCoordsBeforeBattle( nextWP->x, nextWP->y, nextWP->z); + } + i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime()); + } + else { - assert( i_currentNode < i_path.Size() ); - creature.addUnitState(UNIT_STAT_ROAMING); - const Path::PathNode &node(i_path(i_currentNode)); - i_destinationHolder.SetDestination(traveller, node.x, node.y, node.z); - i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime()); - uint32 wpB = i_currentNode > 0 ? i_currentNode-1 : i_wpBehaviour.size()-1; - - if( i_wpBehaviour[wpB] != NULL ) - { - struct WaypointBehavior *tmpBehavior = i_wpBehaviour[wpB]; - tmpBehavior->HasDone = false; - if(tmpBehavior->model2 != 0) - { - creature.SetDisplayId(tmpBehavior->model2); - } - if (tmpBehavior->orientation !=100) - { - creature.SetOrientation(tmpBehavior->orientation); - } - creature.SetUInt32Value(UNIT_NPC_EMOTESTATE, 0); - } - } - else - { - creature.StopMoving(); - i_nextMoveTime.Reset(i_delays[i_currentNode]); - ++i_currentNode; - if( i_currentNode >= i_path.Size() ) - i_currentNode = 0; - } - } - return true; + WaypointData* wp = *(waypoints->begin()+i_currentNode); + + //Determine waittime + if(wp->delay) + i_nextMoveTime.Reset(wp->delay); + else + i_nextMoveTime.Reset(200); //Prevents some lag + + if(wp->event_id && rand()%100 < wp->event_chance && !ExecuteScript) + { + sWorld.ScriptsStart(sWaypointScripts, wp->event_id, &unit, NULL); + ExecuteScript = true; + } + + ((Creature*)&unit)->UpdateWaypointID(i_currentNode); + + if(!((Creature*)&unit)->IsFollower()) + { + if(!((Creature*)&unit)->isLinkedtoFormation()) + ((Creature*)&unit)->clearUnitState(UNIT_STAT_MOVING); + + } + else + { + uint32 guid = ((Creature*)&unit)->GetCreatureFormation()->leader; + uint32 entry = objmgr.GetCreatureData(guid)->id; + + Creature* Leader = ObjectAccessor::Instance().GetObjectInWorld(MAKE_NEW_GUID(guid, entry, HIGHGUID_UNIT), (Creature*)NULL); + + if(Leader) + { + if(((Creature*)&unit)->GetCurrentWaypointID() == Leader->GetCurrentWaypointID()) + { + ((Creature*)&unit)->clearUnitState(UNIT_STAT_MOVING); + Leader->SetLinkedtoFormation(false); + } + else if(((Creature*)&unit)->GetCurrentWaypointID() == Leader->GetCurrentWaypointID()-1) + if(Leader->isLinkedtoFormation()) + { + ((Creature*)&unit)->clearUnitState(UNIT_STAT_MOVING); + } + } + } + } + } + return true; } -void WaypointMovementGenerator::MovementInform(Creature &unit) -{ - if(unit.AI()) - unit.AI()->MovementInform(WAYPOINT_MOTION_TYPE, i_currentNode); -} +template HM_NAMESPACE::hash_map< uint64, T* > WaypointMovementGenerator::m_ActiveCreatureMap; -std::set WaypointMovementGenerator::si_waypointHolders; +template void WaypointMovementGenerator::Initialize(Player &); +template void WaypointMovementGenerator::Initialize(Creature &); +template void WaypointMovementGenerator::Reset(Player &); +template void WaypointMovementGenerator::Reset(Creature &); +template bool WaypointMovementGenerator::Update(Player &, const uint32 &); +template bool WaypointMovementGenerator::Update(Creature &, const uint32 &); +template void WaypointMovementGenerator::GeneratePathId(Player &); +template void WaypointMovementGenerator::MovementInform(Player &); +template void WaypointMovementGenerator::SetMoveFlag(Player &, bool flag); //----------------------------------------------------// void Index: src/game/WaypointMovementGenerator.h =================================================================== --- src/game/WaypointMovementGenerator.h (revision 5687) +++ src/game/WaypointMovementGenerator.h (working copy) @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2008 MaNGOS + * Copyright (C) 2005,2006,2007 MaNGOS * * 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 @@ -25,31 +25,57 @@ * packets for the players. */ +class Player; + +//Movement classes #include "MovementGenerator.h" #include "DestinationHolder.h" #include "Path.h" #include "Traveller.h" +#include "FollowerReference.h" -#include "Player.h" - -#include -#include - #define FLIGHT_TRAVEL_UPDATE 100 #define VISUAL_WAYPOINT 1 -struct WaypointBehavior +struct WaypointData { - uint32 emote; - uint32 spell; - std::string text[5]; - float orientation; - uint32 model1; - uint32 model2; - bool HasDone; + uint32 id; + float x,y,z; + bool run; + uint32 delay; + uint32 event_id; + uint8 event_chance; }; +typedef std::vector WaypointPath; +typedef HM_NAMESPACE::hash_map waypoint_map; + +WaypointData* CreateWaypoint(uint32 id, float x, float y, float z, bool run, uint32 delay, uint32 event_id, uint8 event_chance); + +class WaypointStore +{ + private : + waypoint_map wpdata; + uint32 records; + + public: + void UpdatePath(uint32 id); + void Load(); + void Free(); + + WaypointPath* GetPath(uint32 id) + { + if(wpdata.find(id) != wpdata.end()) + return wpdata[id]; + else return 0; + } + + inline uint32 GetRecordsCount() { return records; } +}; + +extern WaypointStore sWaypointStore; + template class MANGOS_DLL_SPEC PathMovementBase { @@ -59,67 +85,78 @@ 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; } + void Finalize(T &); + protected: uint32 i_currentNode; DestinationHolder< Traveller > i_destinationHolder; Path 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 MANGOS_DLL_SPEC WaypointMovementGenerator; -template<> -class MANGOS_DLL_SPEC WaypointMovementGenerator -: public MovementGeneratorMedium< Creature, WaypointMovementGenerator >, -public PathMovementBase +class MANGOS_DLL_SPEC WaypointMovementGenerator + : public MovementGeneratorMedium< T, WaypointMovementGenerator > { - TimeTracker i_nextMoveTime; - std::vector i_delays; - std::vector i_wpBehaviour; public: - WaypointMovementGenerator(Creature &) : i_nextMoveTime(0) {} - ~WaypointMovementGenerator() { ClearWaypoints(); } - void Initialize(Creature &u) + WaypointMovementGenerator(T &, uint32 _path_id = 0, bool _repeating = true) : + i_nextMoveTime(0), path_id(_path_id), repeating(_repeating), custom_path(false) {} + ~WaypointMovementGenerator() + { + if(custom_path) + { + for(WaypointPath::iterator itr = waypoints->begin(); itr!= waypoints->end();) + { + delete (*itr); + itr = waypoints->erase(itr); + } + delete waypoints; + } + } + typedef HM_NAMESPACE::hash_map< uint64, T* > ActiveCreatureList; + + void Initialize(T &); + void Finalize(T &); + static ActiveCreatureList& GetContainer(){return m_ActiveCreatureMap;} + + void UseCustomPath(uint32 custom_id, WaypointPath *data) { - i_nextMoveTime.Reset(0); // TODO: check the lower bound (0 is probably too small) - u.StopMoving(); - LoadPath(u); + cucstom_path = true; + path_id = custom_id; + waypoints = data; } - void Finalize(Creature &) {} - void Reset(Creature &u) { ReloadPath(u); } - bool Update(Creature &u, const uint32 &diff); - void MovementInform(Creature &); + void MovementInform(T &); + void GeneratePathId(T &); + void SetMoveFlag(T &, bool flag); //Will change it to real type once we have real movement types ... + void Reset(T &); + bool Update(T &, const uint32 &); MovementGeneratorType GetMovementGeneratorType() { return WAYPOINT_MOTION_TYPE; } - - // now path movement implmementation - void LoadPath(Creature &c); - void ReloadPath(Creature &c) { ClearWaypoints(); LoadPath(c); } - - // statics - static void Initialize(void); + private: - void ClearWaypoints(); - static std::set si_waypointHolders; -}; + uint32 i_currentNode; + DestinationHolder< Traveller > i_destinationHolder; + TimeTracker i_nextMoveTime; + WaypointPath *waypoints; + uint32 path_id; + bool repeating, custom_path, ExecuteScript; + float offset; + float dist; + static ActiveCreatureList m_ActiveCreatureMap; + }; /** FlightPathMovementGenerator generates movement of the player for the paths * and hence generates ground and activities for the player. */ + class MANGOS_DLL_SPEC FlightPathMovementGenerator -: public MovementGeneratorMedium< Player, FlightPathMovementGenerator >, -public PathMovementBase + : public MovementGeneratorMedium< Player, FlightPathMovementGenerator >, + public PathMovementBase { uint32 i_pathId; std::vector i_mapIds; @@ -142,4 +179,5 @@ void SetCurrentNodeAfterTeleport(); void SkipCurrentNode() { ++i_currentNode; } }; + #endif Index: src/game/World.cpp =================================================================== --- src/game/World.cpp (revision 5687) +++ src/game/World.cpp (working copy) @@ -790,7 +790,13 @@ sLog.outString( "Loading BattleMasters..." ); objmgr.LoadBattleMastersEntry(); - ///- Handle outdated emails (delete/return) + sLog.outString( "Loading Waypoint Data..." ); + objmgr.LoadWaypointData(); + + sLog.outString( "Loading Creature Formations..." ); + objmgr.LoadCreatureFormations(); + + ///- Handle outdated emails (delete/return) sLog.outString( "Returning old mails..." ); objmgr.ReturnOrDeleteOldMails(false); @@ -801,6 +807,7 @@ 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( "Initializing Scripts..." ); if(!LoadScriptingModule()) @@ -839,7 +846,6 @@ ///- Initilize static helper structures AIRegistry::Initialize(); - WaypointMovementGenerator::Initialize(); Player::InitVisibleBits(); RedZone::Initialize(); @@ -1177,7 +1183,7 @@ sLog.outError("SCRIPT_COMMAND_TALK call for non-creature (TypeId: %u), skipping.",source->GetTypeId()); break; } - if(step.script->datalong > 2) + if(step.script->datalong > 3) { sLog.outError("SCRIPT_COMMAND_TALK invalid chat type (%u), skipping.",step.script->datalong); break; @@ -1185,7 +1191,7 @@ uint64 unit_target = target!=NULL ? target->GetGUID() : 0; - //datalong 0=normal say, datalong 1=whisper, datalong 2=yell + //datalong 0=normal say, datalong 1=whisper, datalong 2=yell, datalong 3=textemote switch(step.script->datalong) { case 0: // SAY @@ -1202,7 +1208,11 @@ case 2: // YELL ((Creature *)source)->Yell(step.script->datatext.c_str(), 0, unit_target); break; - default: + case 3: // TEXTEMOTE + ((Creature *)source)->TextEmote(step.script->datatext.c_str(),0); + break; + + default: break; // must be already checked at load } break; @@ -1580,8 +1590,28 @@ break; } + case SCRIPT_START_PATH: + { + if(!source) + { + sLog.outError("SCRIPT_COMMAND_EMOTE call for NULL creature."); + break; + } - default: + if(source->GetTypeId()!=TYPEID_UNIT) + { + sLog.outError("SCRIPT_COMMAND_EMOTE call for non-creature (TypeId: %u), skipping.",source->GetTypeId()); + break; + } + + ((Creature*)source)->LoadPath(step.script->datalong); + ((Creature*)source)->SetDefaultMovementType(WAYPOINT_MOTION_TYPE); + ((Creature*)source)->GetMotionMaster()->Initialize(); + + break; + } + + default: sLog.outError("Unknown script command %u called.",step.script->command); break; } Index: src/game/World.h =================================================================== --- src/game/World.h (revision 5687) +++ src/game/World.h (working copy) @@ -203,7 +203,7 @@ #define SCRIPT_COMMAND_TEMP_SUMMON_CREATURE 10 #define SCRIPT_COMMAND_OPEN_DOOR 11 #define SCRIPT_COMMAND_CLOSE_DOOR 12 - +#define SCRIPT_START_PATH 14 /// CLI related stuff, define here to prevent cyclic dependancies typedef int(* pPrintf)(const char*,...); Index: src/shared/Database/SQLStorage.cpp =================================================================== --- src/shared/Database/SQLStorage.cpp (revision 5687) +++ src/shared/Database/SQLStorage.cpp (working copy) @@ -28,9 +28,10 @@ #endif const char CreatureInfofmt[]="iiiiisssiiiiiiiiiiffiffiiiiiiiiiiiffiiliiiiiiiiiiiiiiiisiilliis"; -const char CreatureDataAddonInfofmt[]="iiiiiis"; +const char CreatureDataAddonInfofmt[]="iiiiiiis"; +const char CreatureDataFormationInfofmt[]="iiff"; const char CreatureModelfmt[]="iffii"; -const char CreatureInfoAddonInfofmt[]="iiiiiis"; +const char CreatureInfoAddonInfofmt[]="iiiiiiis"; const char EquipmentInfofmt[]="iiiiiiiiii"; const char GameObjectInfofmt[]="iiissiifiiiiiiiiiiiiiiiiiiiiiiiis"; const char ItemPrototypefmt[]="iiiisiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiffiffiffiffiffiiiiiiiiiifiiifiiiiiifiiiiiifiiiiiifiiiiiifiiiisiiiiiiiiiiiiiiiiiiiiiiiiifsiiiii"; @@ -40,6 +41,7 @@ SQLStorage sCreatureStorage(CreatureInfofmt,"entry","creature_template"); SQLStorage sCreatureDataAddonStorage(CreatureDataAddonInfofmt,"guid","creature_addon"); +SQLStorage sCreatureFormation(CreatureDataFormationInfofmt,"follower","creature_formations"); SQLStorage sCreatureModelStorage(CreatureModelfmt,"modelid","creature_model_info"); SQLStorage sCreatureInfoAddonStorage(CreatureInfoAddonInfofmt,"entry","creature_template_addon"); SQLStorage sEquipmentStorage(EquipmentInfofmt,"entry","creature_equip_template"); Index: win/VC90/game.vcproj =================================================================== --- win/VC90/game.vcproj (revision 5687) +++ win/VC90/game.vcproj (working copy) @@ -1,7 +1,7 @@