mirror of
https://github.com/mangosfour/server.git
synced 2025-12-12 19:37:03 +00:00
Update Waypoint System and Commands
Update Waypoint System and Commands
This commit is contained in:
parent
870b4dd0a4
commit
6ac38a0d65
48 changed files with 455 additions and 323 deletions
|
|
@ -490,7 +490,7 @@ class BattleGround
|
|||
|
||||
/* Triggers handle */
|
||||
// must be implemented in BG subclass
|
||||
virtual void HandleAreaTrigger(Player* /*Source*/, uint32 /*Trigger*/) {}
|
||||
virtual bool HandleAreaTrigger(Player* /*Source*/, uint32 /*Trigger*/) { return false; }
|
||||
// must be implemented in BG subclass if need AND call base class generic code
|
||||
virtual void HandleKillPlayer(Player* player, Player* killer);
|
||||
virtual void HandleKillUnit(Creature* /*unit*/, Player* /*killer*/) {}
|
||||
|
|
|
|||
|
|
@ -183,7 +183,7 @@ void BattleGroundAB::RemovePlayer(Player * /*plr*/, ObjectGuid /*guid*/)
|
|||
{
|
||||
}
|
||||
|
||||
void BattleGroundAB::HandleAreaTrigger(Player* source, uint32 trigger)
|
||||
bool BattleGroundAB::HandleAreaTrigger(Player* source, uint32 trigger)
|
||||
{
|
||||
switch (trigger)
|
||||
{
|
||||
|
|
@ -199,19 +199,10 @@ void BattleGroundAB::HandleAreaTrigger(Player* source, uint32 trigger)
|
|||
else
|
||||
source->LeaveBattleground();
|
||||
break;
|
||||
case 3866: // Stables
|
||||
case 3869: // Gold Mine
|
||||
case 3867: // Farm
|
||||
case 3868: // Lumber Mill
|
||||
case 3870: // Black Smith
|
||||
case 4020: // Unk1
|
||||
case 4021: // Unk2
|
||||
// break;
|
||||
default:
|
||||
// sLog.outError("WARNING: Unhandled AreaTrigger in Battleground: %u", trigger);
|
||||
// source->GetSession()->SendAreaTriggerMessage("Warning: Unhandled AreaTrigger in Battleground: %u", trigger);
|
||||
break;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* type: 0-neutral, 1-contested, 3-occupied
|
||||
|
|
|
|||
|
|
@ -173,7 +173,7 @@ class BattleGroundAB : public BattleGround
|
|||
void AddPlayer(Player* plr) override;
|
||||
virtual void StartingEventOpenDoors() override;
|
||||
void RemovePlayer(Player* plr, ObjectGuid guid) override;
|
||||
void HandleAreaTrigger(Player* source, uint32 trigger) override;
|
||||
bool HandleAreaTrigger(Player* source, uint32 trigger) override;
|
||||
virtual void Reset() override;
|
||||
void EndBattleGround(Team winner) override;
|
||||
virtual WorldSafeLocsEntry const* GetClosestGraveYard(Player* player) override;
|
||||
|
|
|
|||
|
|
@ -350,7 +350,7 @@ void BattleGroundAV::EndBattleGround(Team winner)
|
|||
BattleGround::EndBattleGround(winner);
|
||||
}
|
||||
|
||||
void BattleGroundAV::HandleAreaTrigger(Player* source, uint32 trigger)
|
||||
bool BattleGroundAV::HandleAreaTrigger(Player* source, uint32 trigger)
|
||||
{
|
||||
// this is wrong way to implement these things. On official it done by gameobject spell cast.
|
||||
switch (trigger)
|
||||
|
|
@ -368,19 +368,10 @@ void BattleGroundAV::HandleAreaTrigger(Player* source, uint32 trigger)
|
|||
else
|
||||
source->LeaveBattleground();
|
||||
break;
|
||||
case 3326:
|
||||
case 3327:
|
||||
case 3328:
|
||||
case 3329:
|
||||
case 3330:
|
||||
case 3331:
|
||||
// source->Unmount();
|
||||
break;
|
||||
default:
|
||||
DEBUG_LOG("BattleGroundAV: WARNING: Unhandled AreaTrigger in Battleground: %u", trigger);
|
||||
// source->GetSession()->SendAreaTriggerMessage("Warning: Unhandled AreaTrigger in Battleground: %u", trigger);
|
||||
break;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void BattleGroundAV::UpdatePlayerScore(Player* source, uint32 type, uint32 value)
|
||||
|
|
|
|||
|
|
@ -339,8 +339,8 @@ class BattleGroundAV : public BattleGround
|
|||
virtual void StartingEventOpenDoors() override;
|
||||
// world states
|
||||
virtual void FillInitialWorldStates(WorldPacket& data, uint32& count) override;
|
||||
|
||||
void HandleAreaTrigger(Player* source, uint32 trigger) override;
|
||||
|
||||
bool HandleAreaTrigger(Player* source, uint32 trigger) override;
|
||||
virtual void Reset() override;
|
||||
|
||||
/*general stuff*/
|
||||
|
|
|
|||
|
|
@ -96,32 +96,6 @@ bool BattleGroundBE::HandlePlayerUnderMap(Player* player)
|
|||
return true;
|
||||
}
|
||||
|
||||
void BattleGroundBE::HandleAreaTrigger(Player* source, uint32 trigger)
|
||||
{
|
||||
// this is wrong way to implement these things. On official it done by gameobject spell cast.
|
||||
if (GetStatus() != STATUS_IN_PROGRESS)
|
||||
return;
|
||||
|
||||
// uint32 spellId = 0;
|
||||
// uint64 buff_guid = 0;
|
||||
switch (trigger)
|
||||
{
|
||||
case 4538: // buff trigger?
|
||||
// buff_guid = -nonexistingStorage-[BG_BE_OBJECT_BUFF_1];
|
||||
break;
|
||||
case 4539: // buff trigger?
|
||||
// buff_guid = -nonexistingStorage-[BG_BE_OBJECT_BUFF_2];
|
||||
break;
|
||||
default:
|
||||
sLog.outError("WARNING: Unhandled AreaTrigger in Battleground: %u", trigger);
|
||||
source->GetSession()->SendAreaTriggerMessage("Warning: Unhandled AreaTrigger in Battleground: %u", trigger);
|
||||
break;
|
||||
}
|
||||
|
||||
// if (buff_guid)
|
||||
// HandleTriggerBuff(buff_guid, source);
|
||||
}
|
||||
|
||||
void BattleGroundBE::FillInitialWorldStates(WorldPacket& data, uint32& count)
|
||||
{
|
||||
FillInitialWorldState(data, count, 0x9f1, GetAlivePlayersCountByTeam(ALLIANCE));
|
||||
|
|
@ -138,18 +112,3 @@ void BattleGroundBE::UpdatePlayerScore(Player* source, uint32 type, uint32 value
|
|||
// there is nothing special in this score
|
||||
BattleGround::UpdatePlayerScore(source, type, value);
|
||||
}
|
||||
|
||||
/*
|
||||
21:45:46 id:231310 [S2C] SMSG_INIT_WORLD_STATES (706 = 0x02C2) len: 86
|
||||
0000: 32 02 00 00 76 0e 00 00 00 00 00 00 09 00 f3 09 | 2...v...........
|
||||
0010: 00 00 01 00 00 00 f1 09 00 00 01 00 00 00 f0 09 | ................
|
||||
0020: 00 00 02 00 00 00 d4 08 00 00 00 00 00 00 d8 08 | ................
|
||||
0030: 00 00 00 00 00 00 d7 08 00 00 00 00 00 00 d6 08 | ................
|
||||
0040: 00 00 00 00 00 00 d5 08 00 00 00 00 00 00 d3 08 | ................
|
||||
0050: 00 00 00 00 00 00 | ......
|
||||
|
||||
spell 32724 - Gold Team
|
||||
spell 32725 - Green Team
|
||||
35774 Gold Team
|
||||
35775 Green Team
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -45,7 +45,6 @@ class BattleGroundBE : public BattleGround
|
|||
virtual void StartingEventOpenDoors() override;
|
||||
|
||||
void RemovePlayer(Player* plr, ObjectGuid guid) override;
|
||||
void HandleAreaTrigger(Player* source, uint32 trigger) override;
|
||||
virtual void FillInitialWorldStates(WorldPacket& d, uint32& count) override;
|
||||
void HandleKillPlayer(Player* player, Player* killer) override;
|
||||
bool HandlePlayerUnderMap(Player* plr) override;
|
||||
|
|
|
|||
|
|
@ -298,13 +298,13 @@ void BattleGroundEY::ProcessCaptureEvent(GameObject* go, uint32 towerId, Team te
|
|||
m_towerOwner[towerId] = team;
|
||||
}
|
||||
|
||||
void BattleGroundEY::HandleAreaTrigger(Player* source, uint32 trigger)
|
||||
bool BattleGroundEY::HandleAreaTrigger(Player* source, uint32 trigger)
|
||||
{
|
||||
if (GetStatus() != STATUS_IN_PROGRESS)
|
||||
return;
|
||||
return false;
|
||||
|
||||
if (!source->IsAlive()) // hack code, must be removed later
|
||||
return;
|
||||
return false;
|
||||
|
||||
switch (trigger)
|
||||
{
|
||||
|
|
@ -324,7 +324,10 @@ void BattleGroundEY::HandleAreaTrigger(Player* source, uint32 trigger)
|
|||
if (m_towerOwner[NODE_DRAENEI_RUINS] == source->GetTeam())
|
||||
EventPlayerCapturedFlag(source, NODE_DRAENEI_RUINS);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void BattleGroundEY::Reset()
|
||||
|
|
|
|||
|
|
@ -264,7 +264,7 @@ class BattleGroundEY : public BattleGround
|
|||
void RemovePlayer(Player* plr, ObjectGuid guid) override;
|
||||
bool HandleEvent(uint32 eventId, GameObject* go) override;
|
||||
void HandleGameObjectCreate(GameObject* go) override;
|
||||
void HandleAreaTrigger(Player* source, uint32 trigger) override;
|
||||
bool HandleAreaTrigger(Player* source, uint32 trigger) override;
|
||||
void HandleKillPlayer(Player* player, Player* killer) override;
|
||||
|
||||
virtual WorldSafeLocsEntry const* GetClosestGraveYard(Player* player) override;
|
||||
|
|
|
|||
|
|
@ -33,6 +33,8 @@
|
|||
#include "BattleGround.h"
|
||||
#include "ace/Recursive_Thread_Mutex.h"
|
||||
|
||||
#include <mutex>
|
||||
|
||||
typedef std::map<uint32, BattleGround*> BattleGroundSet;
|
||||
|
||||
// this container can't be deque, because deque doesn't like removing the last element - if you remove it, it invalidates next iterator and crash appears
|
||||
|
|
|
|||
|
|
@ -97,41 +97,9 @@ bool BattleGroundNA::HandlePlayerUnderMap(Player* player)
|
|||
return true;
|
||||
}
|
||||
|
||||
void BattleGroundNA::HandleAreaTrigger(Player* source, uint32 trigger)
|
||||
{
|
||||
if (GetStatus() != STATUS_IN_PROGRESS)
|
||||
return;
|
||||
|
||||
// uint32 spellId = 0;
|
||||
// uint64 buff_guid = 0;
|
||||
switch (trigger)
|
||||
{
|
||||
case 4536: // buff trigger?
|
||||
case 4537: // buff trigger?
|
||||
break;
|
||||
default:
|
||||
sLog.outError("WARNING: Unhandled AreaTrigger in Battleground: %u", trigger);
|
||||
source->GetSession()->SendAreaTriggerMessage("Warning: Unhandled AreaTrigger in Battleground: %u", trigger);
|
||||
break;
|
||||
}
|
||||
|
||||
// if (buff_guid)
|
||||
// HandleTriggerBuff(buff_guid, source);
|
||||
}
|
||||
|
||||
void BattleGroundNA::FillInitialWorldStates(WorldPacket& data, uint32& count)
|
||||
{
|
||||
FillInitialWorldState(data, count, 0xa0f, GetAlivePlayersCountByTeam(ALLIANCE));
|
||||
FillInitialWorldState(data, count, 0xa10, GetAlivePlayersCountByTeam(HORDE));
|
||||
FillInitialWorldState(data, count, 0xa11, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
20:12:14 id:036668 [S2C] SMSG_INIT_WORLD_STATES (706 = 0x02C2) len: 86
|
||||
0000: 2f 02 00 00 72 0e 00 00 00 00 00 00 09 00 11 0a | /...r...........
|
||||
0010: 00 00 01 00 00 00 0f 0a 00 00 00 00 00 00 10 0a | ................
|
||||
0020: 00 00 00 00 00 00 d4 08 00 00 00 00 00 00 d8 08 | ................
|
||||
0030: 00 00 00 00 00 00 d7 08 00 00 00 00 00 00 d6 08 | ................
|
||||
0040: 00 00 00 00 00 00 d5 08 00 00 00 00 00 00 d3 08 | ................
|
||||
0050: 00 00 00 00 00 00 | ......
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -46,7 +46,6 @@ class BattleGroundNA : public BattleGround
|
|||
virtual void StartingEventOpenDoors() override;
|
||||
|
||||
void RemovePlayer(Player* plr, ObjectGuid guid) override;
|
||||
void HandleAreaTrigger(Player* source, uint32 trigger) override;
|
||||
virtual void FillInitialWorldStates(WorldPacket& d, uint32& count) override;
|
||||
void HandleKillPlayer(Player* player, Player* killer) override;
|
||||
bool HandlePlayerUnderMap(Player* plr) override;
|
||||
|
|
|
|||
|
|
@ -96,42 +96,9 @@ bool BattleGroundRL::HandlePlayerUnderMap(Player* player)
|
|||
return true;
|
||||
}
|
||||
|
||||
void BattleGroundRL::HandleAreaTrigger(Player* source, uint32 trigger)
|
||||
{
|
||||
// this is wrong way to implement these things. On official it done by gameobject spell cast.
|
||||
if (GetStatus() != STATUS_IN_PROGRESS)
|
||||
return;
|
||||
|
||||
// uint32 spellId = 0;
|
||||
// uint64 buff_guid = 0;
|
||||
switch (trigger)
|
||||
{
|
||||
case 4696: // buff trigger?
|
||||
case 4697: // buff trigger?
|
||||
break;
|
||||
default:
|
||||
sLog.outError("WARNING: Unhandled AreaTrigger in Battleground: %u", trigger);
|
||||
source->GetSession()->SendAreaTriggerMessage("Warning: Unhandled AreaTrigger in Battleground: %u", trigger);
|
||||
break;
|
||||
}
|
||||
|
||||
// if (buff_guid)
|
||||
// HandleTriggerBuff(buff_guid, source);
|
||||
}
|
||||
|
||||
void BattleGroundRL::FillInitialWorldStates(WorldPacket& data, uint32& count)
|
||||
{
|
||||
FillInitialWorldState(data, count, 0xbb8, GetAlivePlayersCountByTeam(ALLIANCE));
|
||||
FillInitialWorldState(data, count, 0xbb9, GetAlivePlayersCountByTeam(HORDE));
|
||||
FillInitialWorldState(data, count, 0xbba, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
Packet S->C, id 600, SMSG_INIT_WORLD_STATES (706), len 86
|
||||
0000: 3C 02 00 00 80 0F 00 00 00 00 00 00 09 00 BA 0B | <...............
|
||||
0010: 00 00 01 00 00 00 B9 0B 00 00 02 00 00 00 B8 0B | ................
|
||||
0020: 00 00 00 00 00 00 D8 08 00 00 00 00 00 00 D7 08 | ................
|
||||
0030: 00 00 00 00 00 00 D6 08 00 00 00 00 00 00 D5 08 | ................
|
||||
0040: 00 00 00 00 00 00 D3 08 00 00 00 00 00 00 D4 08 | ................
|
||||
0050: 00 00 00 00 00 00 | ......
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -47,7 +47,6 @@ class BattleGroundRL : public BattleGround
|
|||
virtual void StartingEventOpenDoors() override;
|
||||
|
||||
void RemovePlayer(Player* plr, ObjectGuid guid) override;
|
||||
void HandleAreaTrigger(Player* source, uint32 trigger) override;
|
||||
void HandleKillPlayer(Player* player, Player* killer) override;
|
||||
bool HandlePlayerUnderMap(Player* plr) override;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -483,23 +483,14 @@ void BattleGroundWS::UpdateTeamScore(Team team)
|
|||
UpdateWorldState(BG_WS_FLAG_CAPTURES_HORDE, m_TeamScores[TEAM_INDEX_HORDE]);
|
||||
}
|
||||
|
||||
void BattleGroundWS::HandleAreaTrigger(Player* source, uint32 trigger)
|
||||
bool BattleGroundWS::HandleAreaTrigger(Player* source, uint32 trigger)
|
||||
{
|
||||
// this is wrong way to implement these things. On official it done by gameobject spell cast.
|
||||
if (GetStatus() != STATUS_IN_PROGRESS)
|
||||
return;
|
||||
return false;
|
||||
|
||||
// uint32 SpellId = 0;
|
||||
// uint64 buff_guid = 0;
|
||||
switch (trigger)
|
||||
{
|
||||
case 3686: // Alliance elixir of speed spawn. Trigger not working, because located inside other areatrigger, can be replaced by IsWithinDist(object, dist) in BattleGround::Update().
|
||||
case 3687: // Horde elixir of speed spawn. Trigger not working, because located inside other areatrigger, can be replaced by IsWithinDist(object, dist) in BattleGround::Update().
|
||||
case 3706: // Alliance elixir of regeneration spawn
|
||||
case 3708: // Horde elixir of regeneration spawn
|
||||
case 3707: // Alliance elixir of berserk spawn
|
||||
case 3709: // Horde elixir of berserk spawn
|
||||
break;
|
||||
case 3646: // Alliance Flag spawn
|
||||
if (m_FlagState[TEAM_INDEX_HORDE] && !m_FlagState[TEAM_INDEX_ALLIANCE])
|
||||
if (GetHordeFlagCarrierGuid() == source->GetObjectGuid())
|
||||
|
|
@ -510,16 +501,10 @@ void BattleGroundWS::HandleAreaTrigger(Player* source, uint32 trigger)
|
|||
if (GetAllianceFlagCarrierGuid() == source->GetObjectGuid())
|
||||
EventPlayerCapturedFlag(source);
|
||||
break;
|
||||
case 3649: // unk1
|
||||
case 3688: // unk2
|
||||
case 4628: // unk3
|
||||
case 4629: // unk4
|
||||
break;
|
||||
default:
|
||||
sLog.outError("WARNING: Unhandled AreaTrigger in Battleground: %u", trigger);
|
||||
source->GetSession()->SendAreaTriggerMessage("Warning: Unhandled AreaTrigger in Battleground: %u", trigger);
|
||||
break;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void BattleGroundWS::Reset()
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ class BattleGroundWS : public BattleGround
|
|||
virtual void EventPlayerCapturedFlag(Player* source) override;
|
||||
|
||||
void RemovePlayer(Player* plr, ObjectGuid guid) override;
|
||||
void HandleAreaTrigger(Player* source, uint32 trigger) override;
|
||||
bool HandleAreaTrigger(Player* source, uint32 trigger) override;
|
||||
void HandleKillPlayer(Player* player, Player* killer) override;
|
||||
virtual void Reset() override;
|
||||
void EndBattleGround(Team winner) override;
|
||||
|
|
|
|||
|
|
@ -3140,7 +3140,7 @@ bool ChatHandler::HandleWpModifyCommand(char* args)
|
|||
|
||||
// Did user provide a GUID or did the user select a creature?
|
||||
Creature* targetCreature = getSelectedCreature(); // Expect a visual waypoint to be selected
|
||||
Creature* wpOwner = nullptr; // Who moves along the waypoint
|
||||
Creature* wpOwner; // Who moves along the waypoint
|
||||
uint32 wpId = 0;
|
||||
WaypointPathOrigin wpSource = PATH_NO_PATH;
|
||||
int32 wpPathId = 0;
|
||||
|
|
@ -3393,8 +3393,8 @@ bool ChatHandler::HandleWpShowCommand(char* args)
|
|||
}
|
||||
}
|
||||
|
||||
Creature* wpOwner = NULL; ///< Npc that is moving
|
||||
TemporarySummonWaypoint* wpTarget = NULL; // Define here for wp-info command
|
||||
Creature* wpOwner; ///< Npc that is moving
|
||||
TemporarySummonWaypoint* wpTarget = nullptr; // Define here for wp-info command
|
||||
|
||||
// Show info for the selected waypoint (Step one: get moving npc)
|
||||
if (subCmd == "info")
|
||||
|
|
@ -3431,7 +3431,7 @@ bool ChatHandler::HandleWpShowCommand(char* args)
|
|||
wpOwner = targetCreature;
|
||||
|
||||
// Get the path
|
||||
WaypointPath* wpPath = NULL;
|
||||
WaypointPath* wpPath = nullptr;
|
||||
if (wpOrigin != PATH_NO_PATH) // Might have been provided by param
|
||||
wpPath = sWaypointMgr.GetPathFromOrigin(wpOwner->GetEntry(), wpOwner->GetGUIDLow(), wpPathId, wpOrigin);
|
||||
else
|
||||
|
|
@ -3538,65 +3538,112 @@ bool ChatHandler::HandleWpShowCommand(char* args)
|
|||
return false;
|
||||
}
|
||||
|
||||
/// [Guid if no selected unit] <filename> [pathId [wpOrigin] ]
|
||||
bool ChatHandler::HandleWpExportCommand(char* args)
|
||||
{
|
||||
if (!*args)
|
||||
return false;
|
||||
|
||||
// Next arg is: <GUID> <ARGUMENT>
|
||||
Creature* wpOwner;
|
||||
WaypointPathOrigin wpOrigin = PATH_NO_PATH;
|
||||
int32 wpPathId = 0;
|
||||
|
||||
// Did user provide a GUID
|
||||
// or did the user select a creature?
|
||||
// -> variable lowguid is filled with the GUID of the NPC
|
||||
uint32 lowguid = 0;
|
||||
Creature* target = getSelectedCreature();
|
||||
char* arg_str = NULL;
|
||||
if (target)
|
||||
if (Creature* targetCreature = getSelectedCreature())
|
||||
{
|
||||
if (target->GetEntry() != VISUAL_WAYPOINT)
|
||||
lowguid = target->GetGUIDLow();
|
||||
else
|
||||
// Check if the user did specify a visual waypoint
|
||||
if (targetCreature->GetEntry() == VISUAL_WAYPOINT && targetCreature->GetSubtype() == CREATURE_SUBTYPE_TEMPORARY_SUMMON)
|
||||
{
|
||||
QueryResult* result = WorldDatabase.PQuery("SELECT id FROM creature_movement WHERE wpguid = %u LIMIT 1", target->GetGUIDLow());
|
||||
if (!result)
|
||||
TemporarySummonWaypoint* wpTarget = dynamic_cast<TemporarySummonWaypoint*>(targetCreature);
|
||||
if (!wpTarget)
|
||||
{
|
||||
PSendSysMessage(LANG_WAYPOINT_NOTFOUNDDBPROBLEM, target->GetGUIDLow());
|
||||
return true;
|
||||
PSendSysMessage(LANG_WAYPOINT_VP_SELECT);
|
||||
SetSentErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
Field* fields = result->Fetch();
|
||||
lowguid = fields[0].GetUInt32();;
|
||||
delete result;
|
||||
}
|
||||
|
||||
arg_str = strtok(args, " ");
|
||||
// Who moves along this waypoint?
|
||||
wpOwner = targetCreature->GetMap()->GetAnyTypeCreature(wpTarget->GetSummonerGuid());
|
||||
if (!wpOwner)
|
||||
{
|
||||
PSendSysMessage(LANG_WAYPOINT_NOTFOUND_NPC, wpTarget->GetSummonerGuid().GetString().c_str());
|
||||
SetSentErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
wpOrigin = (WaypointPathOrigin)wpTarget->GetPathOrigin();
|
||||
wpPathId = wpTarget->GetPathId();
|
||||
}
|
||||
else // normal creature selected
|
||||
wpOwner = targetCreature;
|
||||
}
|
||||
else
|
||||
{
|
||||
// user provided <GUID>
|
||||
char* guid_str = strtok(args, " ");
|
||||
if (!guid_str)
|
||||
uint32 dbGuid;
|
||||
if (!ExtractUInt32(&args, dbGuid))
|
||||
{
|
||||
SendSysMessage(LANG_WAYPOINT_NOGUID);
|
||||
PSendSysMessage(LANG_WAYPOINT_NOGUID);
|
||||
SetSentErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
lowguid = atoi((char*)guid_str);
|
||||
|
||||
arg_str = strtok((char*)NULL, " ");
|
||||
CreatureData const* data = sObjectMgr.GetCreatureData(dbGuid);
|
||||
if (!data)
|
||||
{
|
||||
PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, dbGuid);
|
||||
SetSentErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_session->GetPlayer()->GetMapId() != data->mapid)
|
||||
{
|
||||
PSendSysMessage(LANG_COMMAND_CREATUREATSAMEMAP, dbGuid);
|
||||
SetSentErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
wpOwner = m_session->GetPlayer()->GetMap()->GetAnyTypeCreature(data->GetObjectGuid(dbGuid));
|
||||
if (!wpOwner)
|
||||
{
|
||||
PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, dbGuid);
|
||||
SetSentErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!arg_str)
|
||||
// wpOwner is now known, in case of export by visual waypoint also the to be exported path
|
||||
char* export_str = ExtractLiteralArg(&args);
|
||||
if (!export_str)
|
||||
{
|
||||
PSendSysMessage(LANG_WAYPOINT_ARGUMENTREQ, "export");
|
||||
SetSentErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
PSendSysMessage("DEBUG: wp export, GUID: %u", lowguid);
|
||||
if (wpOrigin == PATH_NO_PATH) // No WP selected, Extract optional arguments
|
||||
{
|
||||
if (ExtractOptInt32(&args, wpPathId, 0)) // Fill path-id and source
|
||||
{
|
||||
uint32 src = (uint32)PATH_NO_PATH;
|
||||
if (ExtractOptUInt32(&args, src, src))
|
||||
wpOrigin = (WaypointPathOrigin)src;
|
||||
else // pathId provided but no destination
|
||||
{
|
||||
if (wpPathId != 0)
|
||||
wpOrigin = PATH_FROM_ENTRY; // Multiple Paths must only be assigned by entry
|
||||
}
|
||||
}
|
||||
|
||||
QueryResult* result = WorldDatabase.PQuery(
|
||||
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
||||
"SELECT point, position_x, position_y, position_z, orientation, model1, model2, waittime, emote, spell, textid1, textid2, textid3, textid4, textid5, id FROM creature_movement WHERE id = '%u' ORDER BY point", lowguid);
|
||||
if (wpOrigin == PATH_NO_PATH)
|
||||
{
|
||||
if (wpOwner->GetMotionMaster()->GetCurrentMovementGeneratorType() == WAYPOINT_MOTION_TYPE)
|
||||
if (WaypointMovementGenerator<Creature> const* wpMMGen = dynamic_cast<WaypointMovementGenerator<Creature> const*>(wpOwner->GetMotionMaster()->GetCurrent()))
|
||||
wpMMGen->GetPathInformation(wpPathId, wpOrigin);
|
||||
if (wpOrigin == PATH_NO_PATH)
|
||||
sWaypointMgr.GetDefaultPath(wpOwner->GetEntry(), wpOwner->GetGUIDLow(), &wpOrigin);
|
||||
}
|
||||
}
|
||||
|
||||
if (!result)
|
||||
WaypointPath const* wpPath = sWaypointMgr.GetPathFromOrigin(wpOwner->GetEntry(), wpOwner->GetGUIDLow(), wpPathId, wpOrigin);
|
||||
if (!wpPath || wpPath->empty())
|
||||
{
|
||||
PSendSysMessage(LANG_WAYPOINT_NOTHINGTOEXPORT);
|
||||
SetSentErrorMessage(true);
|
||||
|
|
@ -3604,51 +3651,44 @@ bool ChatHandler::HandleWpExportCommand(char* args)
|
|||
}
|
||||
|
||||
std::ofstream outfile;
|
||||
outfile.open(arg_str);
|
||||
outfile.open(export_str);
|
||||
|
||||
do
|
||||
std::string table;
|
||||
char const* key_field;
|
||||
uint32 key;
|
||||
switch (wpOrigin)
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
|
||||
outfile << "INSERT INTO creature_movement ";
|
||||
outfile << "(id, point, position_x, position_y, position_z, orientation, model1, model2, waittime, emote, spell, textid1, textid2, textid3, textid4, textid5) VALUES ";
|
||||
|
||||
outfile << "( ";
|
||||
outfile << fields[15].GetUInt32(); // id
|
||||
outfile << ", ";
|
||||
outfile << fields[0].GetUInt32(); // point
|
||||
outfile << ", ";
|
||||
outfile << fields[1].GetFloat(); // position_x
|
||||
outfile << ", ";
|
||||
outfile << fields[2].GetFloat(); // position_y
|
||||
outfile << ", ";
|
||||
outfile << fields[3].GetUInt32(); // position_z
|
||||
outfile << ", ";
|
||||
outfile << fields[4].GetUInt32(); // orientation
|
||||
outfile << ", ";
|
||||
outfile << fields[5].GetUInt32(); // model1
|
||||
outfile << ", ";
|
||||
outfile << fields[6].GetUInt32(); // model2
|
||||
outfile << ", ";
|
||||
outfile << fields[7].GetUInt16(); // waittime
|
||||
outfile << ", ";
|
||||
outfile << fields[8].GetUInt32(); // emote
|
||||
outfile << ", ";
|
||||
outfile << fields[9].GetUInt32(); // spell
|
||||
outfile << ", ";
|
||||
outfile << fields[10].GetUInt32(); // textid1
|
||||
outfile << ", ";
|
||||
outfile << fields[11].GetUInt32(); // textid2
|
||||
outfile << ", ";
|
||||
outfile << fields[12].GetUInt32(); // textid3
|
||||
outfile << ", ";
|
||||
outfile << fields[13].GetUInt32(); // textid4
|
||||
outfile << ", ";
|
||||
outfile << fields[14].GetUInt32(); // textid5
|
||||
outfile << ");\n ";
|
||||
case PATH_FROM_ENTRY: key = wpOwner->GetEntry(); key_field = "entry"; table = "creature_movement_template"; break;
|
||||
case PATH_FROM_GUID: key = wpOwner->GetGUIDLow(); key_field = "id"; table = "creature_movement"; break;
|
||||
case PATH_FROM_EXTERNAL: key = wpOwner->GetEntry(); key_field = "entry"; table = sWaypointMgr.GetExternalWPTable(); break;
|
||||
case PATH_NO_PATH:
|
||||
return false;
|
||||
}
|
||||
|
||||
outfile << "DELETE FROM " << table << " WHERE " << key_field << "=" << key << ";\n";
|
||||
if (wpOrigin != PATH_FROM_EXTERNAL)
|
||||
outfile << "INSERT INTO " << table << " (" << key_field << ", point, position_x, position_y, position_z, orientation, waittime, script_id) VALUES\n";
|
||||
else
|
||||
outfile << "INSERT INTO " << table << " (" << key_field << ", point, position_x, position_y, position_z, orientation, waittime) VALUES\n";
|
||||
|
||||
WaypointPath::const_iterator itr = wpPath->begin();
|
||||
uint32 countDown = wpPath->size();
|
||||
for (; itr != wpPath->end(); ++itr, --countDown)
|
||||
{
|
||||
outfile << "(" << key << ",";
|
||||
outfile << itr->first << ",";
|
||||
outfile << itr->second.x << ",";
|
||||
outfile << itr->second.y << ",";
|
||||
outfile << itr->second.z << ",";
|
||||
outfile << itr->second.orientation << ",";
|
||||
outfile << itr->second.delay << ",";
|
||||
if (wpOrigin != PATH_FROM_EXTERNAL) // Only for normal waypoints
|
||||
outfile << itr->second.script_id << ")";
|
||||
if (countDown > 1)
|
||||
outfile << ",\n";
|
||||
else
|
||||
outfile << ";\n";
|
||||
}
|
||||
while (result->NextRow());
|
||||
delete result;
|
||||
|
||||
PSendSysMessage(LANG_WAYPOINT_EXPORTED);
|
||||
outfile.close();
|
||||
|
|
@ -3656,33 +3696,6 @@ bool ChatHandler::HandleWpExportCommand(char* args)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool ChatHandler::HandleWpImportCommand(char* args)
|
||||
{
|
||||
if (!*args)
|
||||
return false;
|
||||
|
||||
char* arg_str = strtok(args, " ");
|
||||
if (!arg_str)
|
||||
return false;
|
||||
|
||||
std::string line;
|
||||
std::ifstream infile(arg_str);
|
||||
if (infile.is_open())
|
||||
{
|
||||
while (! infile.eof())
|
||||
{
|
||||
getline(infile, line);
|
||||
// cout << line << endl;
|
||||
QueryResult* result = WorldDatabase.Query(line.c_str());
|
||||
delete result;
|
||||
}
|
||||
infile.close();
|
||||
}
|
||||
PSendSysMessage(LANG_WAYPOINT_IMPORTED);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// rename characters
|
||||
bool ChatHandler::HandleCharacterRenameCommand(char* args)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -59,8 +59,10 @@ void MotionMaster::Initialize()
|
|||
if (m_owner->GetTypeId() == TYPEID_UNIT && !m_owner->hasUnitState(UNIT_STAT_CONTROLLED))
|
||||
{
|
||||
MovementGenerator* movement = FactorySelector::selectMovementGenerator((Creature*)m_owner);
|
||||
push(movement == NULL ? &si_idleMovement : movement);
|
||||
push(movement == nullptr ? &si_idleMovement : movement);
|
||||
top()->Initialize(*m_owner);
|
||||
if (top()->GetMovementGeneratorType() == WAYPOINT_MOTION_TYPE)
|
||||
(static_cast<WaypointMovementGenerator<Creature>*>(top()))->InitializeWaypointPath(*((Creature*)(m_owner)), 0, PATH_NO_PATH, 0, 0);
|
||||
}
|
||||
else
|
||||
push(&si_idleMovement);
|
||||
|
|
@ -376,20 +378,22 @@ void MotionMaster::MoveFleeing(Unit* enemy, uint32 time)
|
|||
}
|
||||
}
|
||||
|
||||
void MotionMaster::MoveWaypoint()
|
||||
void MotionMaster::MoveWaypoint(int32 id /*=0*/, uint32 source /*=0==PATH_NO_PATH*/, uint32 initialDelay /*=0*/, uint32 overwriteEntry /*=0*/)
|
||||
{
|
||||
if (m_owner->GetTypeId() == TYPEID_UNIT)
|
||||
{
|
||||
if (GetCurrentMovementGeneratorType() == WAYPOINT_MOTION_TYPE)
|
||||
{
|
||||
sLog.outError("Creature %s (Entry %u) attempt to MoveWaypoint() but creature is already using waypoint", m_owner->GetGuidStr().c_str(), m_owner->GetEntry());
|
||||
sLog.outError("%s attempt to MoveWaypoint() but is already using waypoint", m_owner->GetGuidStr().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
Creature* creature = (Creature*)m_owner;
|
||||
|
||||
DEBUG_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS, "Creature %s (Entry %u) start MoveWaypoint()", m_owner->GetGuidStr().c_str(), m_owner->GetEntry());
|
||||
Mutate(new WaypointMovementGenerator<Creature>(*creature));
|
||||
DEBUG_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS, "%s start MoveWaypoint()", m_owner->GetGuidStr().c_str());
|
||||
WaypointMovementGenerator<Creature>* newWPMMgen = new WaypointMovementGenerator<Creature>(*creature);
|
||||
Mutate(newWPMMgen);
|
||||
newWPMMgen->InitializeWaypointPath(*creature, id, (WaypointPathOrigin)source, initialDelay, overwriteEntry);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -469,6 +473,16 @@ void MotionMaster::propagateSpeedChange()
|
|||
}
|
||||
}
|
||||
|
||||
bool MotionMaster::SetNextWaypoint(uint32 pointId)
|
||||
{
|
||||
for (Impl::container_type::reverse_iterator rItr = Impl::c.rbegin(); rItr != Impl::c.rend(); ++rItr)
|
||||
{
|
||||
if ((*rItr)->GetMovementGeneratorType() == WAYPOINT_MOTION_TYPE)
|
||||
return (static_cast<WaypointMovementGenerator<Creature>*>(*rItr))->SetNextWaypoint(pointId);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 MotionMaster::getLastReachedWaypoint() const
|
||||
{
|
||||
for (Impl::container_type::const_reverse_iterator rItr = Impl::c.rbegin(); rItr != Impl::c.rend(); ++rItr)
|
||||
|
|
@ -487,6 +501,18 @@ MovementGeneratorType MotionMaster::GetCurrentMovementGeneratorType() const
|
|||
return top()->GetMovementGeneratorType();
|
||||
}
|
||||
|
||||
void MotionMaster::GetWaypointPathInformation(std::ostringstream& oss) const
|
||||
{
|
||||
for (Impl::container_type::const_reverse_iterator rItr = Impl::c.rbegin(); rItr != Impl::c.rend(); ++rItr)
|
||||
{
|
||||
if ((*rItr)->GetMovementGeneratorType() == WAYPOINT_MOTION_TYPE)
|
||||
{
|
||||
static_cast<WaypointMovementGenerator<Creature>*>(*rItr)->GetPathInformation(oss);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool MotionMaster::GetDestination(float& x, float& y, float& z)
|
||||
{
|
||||
if (m_owner->movespline->Finalized())
|
||||
|
|
|
|||
|
|
@ -55,6 +55,10 @@ enum MovementGeneratorType
|
|||
TIMED_FLEEING_MOTION_TYPE = 13, // FleeingMovementGenerator.h (alt.second part of flee for assistance)
|
||||
FOLLOW_MOTION_TYPE = 14, // TargetedMovementGenerator.h
|
||||
EFFECT_MOTION_TYPE = 15,
|
||||
|
||||
EXTERNAL_WAYPOINT_MOVE = 256, // Only used in CreatureAI::MovementInform when a waypoint is reached. The pathId >= 0 is added as additonal value
|
||||
EXTERNAL_WAYPOINT_MOVE_START = 512, // Only used in CreatureAI::MovementInform when a waypoint is started. The pathId >= 0 is added as additional value
|
||||
EXTERNAL_WAYPOINT_FINISHED_LAST = 1024, // Only used in CreatureAI::MovementInform when the waittime of the last wp is finished The pathId >= 0 is added as additional value
|
||||
};
|
||||
|
||||
enum MMCleanFlag
|
||||
|
|
@ -113,7 +117,7 @@ class MotionMaster : private std::stack<MovementGenerator*>
|
|||
void MovePoint(uint32 id, float x, float y, float z, bool generatePath = true);
|
||||
void MoveSeekAssistance(float x, float y, float z);
|
||||
void MoveSeekAssistanceDistract(uint32 timer);
|
||||
void MoveWaypoint();
|
||||
void MoveWaypoint(int32 id = 0, uint32 source = 0, uint32 initialDelay = 0, uint32 overwriteEntry = 0);
|
||||
void MoveTaxiFlight(uint32 path, uint32 pathnode);
|
||||
void MoveDistract(uint32 timeLimit);
|
||||
void MoveJump(float x, float y, float z, float horizontalSpeed, float max_height, uint32 id = 0);
|
||||
|
|
@ -124,7 +128,9 @@ class MotionMaster : private std::stack<MovementGenerator*>
|
|||
MovementGeneratorType GetCurrentMovementGeneratorType() const;
|
||||
|
||||
void propagateSpeedChange();
|
||||
bool SetNextWaypoint(uint32 pointId);
|
||||
uint32 getLastReachedWaypoint() const;
|
||||
void GetWaypointPathInformation(std::ostringstream& oss) const;
|
||||
|
||||
bool GetDestination(float& x, float& y, float& z);
|
||||
|
||||
|
|
|
|||
|
|
@ -77,6 +77,14 @@ void WaypointMovementGenerator<Creature>::Initialize(Creature& creature)
|
|||
creature.clearUnitState(UNIT_STAT_WAYPOINT_PAUSED);
|
||||
}
|
||||
|
||||
void WaypointMovementGenerator<Creature>::InitializeWaypointPath(Creature& u, int32 id, WaypointPathOrigin wpSource, uint32 initialDelay, uint32 overwriteEntry)
|
||||
{
|
||||
LoadPath(u, id, wpSource, overwriteEntry);
|
||||
i_nextMoveTime.Reset(initialDelay);
|
||||
// Start moving if possible
|
||||
StartMove(u);
|
||||
}
|
||||
|
||||
void WaypointMovementGenerator<Creature>::Finalize(Creature& creature)
|
||||
{
|
||||
creature.clearUnitState(UNIT_STAT_ROAMING | UNIT_STAT_ROAMING_MOVE);
|
||||
|
|
@ -156,6 +164,15 @@ void WaypointMovementGenerator<Creature>::OnArrived(Creature& creature)
|
|||
}
|
||||
|
||||
// Inform script
|
||||
if (creature.AI())
|
||||
{
|
||||
uint32 type = WAYPOINT_MOTION_TYPE;
|
||||
if (m_PathOrigin == PATH_FROM_EXTERNAL && m_pathId > 0)
|
||||
type = EXTERNAL_WAYPOINT_MOVE + m_pathId;
|
||||
creature.AI()->MovementInform(type, i_currentNode);
|
||||
}
|
||||
|
||||
// Wait delay ms
|
||||
Stop(node.delay);
|
||||
}
|
||||
|
||||
|
|
@ -182,9 +199,25 @@ void WaypointMovementGenerator<Creature>::StartMove(Creature& creature)
|
|||
|
||||
if (m_isArrivalDone)
|
||||
{
|
||||
bool reachedLast = false;
|
||||
++currPoint;
|
||||
if (currPoint == i_path->end())
|
||||
{
|
||||
reachedLast = true;
|
||||
currPoint = i_path->begin();
|
||||
}
|
||||
|
||||
// Inform AI
|
||||
if (creature.AI() && m_PathOrigin == PATH_FROM_EXTERNAL && m_pathId > 0)
|
||||
{
|
||||
if (!reachedLast)
|
||||
creature.AI()->MovementInform(EXTERNAL_WAYPOINT_MOVE_START + m_pathId, currPoint->first);
|
||||
else
|
||||
creature.AI()->MovementInform(EXTERNAL_WAYPOINT_FINISHED_LAST + m_pathId, currPoint->first);
|
||||
|
||||
if (creature.IsDead() || !creature.IsInWorld()) // Might have happened with above calls
|
||||
return;
|
||||
}
|
||||
|
||||
i_currentNode = currPoint->first;
|
||||
}
|
||||
|
|
@ -238,6 +271,20 @@ bool WaypointMovementGenerator<Creature>::Update(Creature& creature, const uint3
|
|||
return true;
|
||||
}
|
||||
|
||||
bool WaypointMovementGenerator<Creature>::Stopped(Creature& u)
|
||||
{
|
||||
return !i_nextMoveTime.Passed() || u.hasUnitState(UNIT_STAT_WAYPOINT_PAUSED);
|
||||
}
|
||||
|
||||
bool WaypointMovementGenerator<Creature>::CanMove(int32 diff, Creature& u)
|
||||
{
|
||||
i_nextMoveTime.Update(diff);
|
||||
if (i_nextMoveTime.Passed() && u.hasUnitState(UNIT_STAT_WAYPOINT_PAUSED))
|
||||
i_nextMoveTime.Reset(1);
|
||||
|
||||
return i_nextMoveTime.Passed() && !u.hasUnitState(UNIT_STAT_WAYPOINT_PAUSED);
|
||||
}
|
||||
|
||||
bool WaypointMovementGenerator<Creature>::GetResetPosition(Creature&, float& x, float& y, float& z, float& o) const
|
||||
{
|
||||
// prevent a crash at empty waypoint path.
|
||||
|
|
@ -280,18 +327,10 @@ bool WaypointMovementGenerator<Creature>::GetResetPosition(Creature&, float& x,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool WaypointMovementGenerator<Creature>::Stopped(Creature& u)
|
||||
void WaypointMovementGenerator<Creature>::GetPathInformation(std::ostringstream& oss) const
|
||||
{
|
||||
return !i_nextMoveTime.Passed() || u.hasUnitState(UNIT_STAT_WAYPOINT_PAUSED);
|
||||
}
|
||||
|
||||
bool WaypointMovementGenerator<Creature>::CanMove(int32 diff, Creature& u)
|
||||
{
|
||||
i_nextMoveTime.Update(diff);
|
||||
if (i_nextMoveTime.Passed() && u.hasUnitState(UNIT_STAT_WAYPOINT_PAUSED))
|
||||
i_nextMoveTime.Reset(1);
|
||||
|
||||
return i_nextMoveTime.Passed() && !u.hasUnitState(UNIT_STAT_WAYPOINT_PAUSED);
|
||||
oss << "WaypointMovement: Last Reached WP: " << m_lastReachedWaypoint << " ";
|
||||
oss << "(Loaded path " << m_pathId << " from " << WaypointManager::GetOriginString(m_PathOrigin) << ")\n";
|
||||
}
|
||||
|
||||
void WaypointMovementGenerator<Creature>::AddToWaypointPauseTime(int32 waitTimeDiff)
|
||||
|
|
@ -304,6 +343,26 @@ void WaypointMovementGenerator<Creature>::AddToWaypointPauseTime(int32 waitTimeD
|
|||
}
|
||||
}
|
||||
|
||||
bool WaypointMovementGenerator<Creature>::SetNextWaypoint(uint32 pointId)
|
||||
{
|
||||
if (!i_path || i_path->empty())
|
||||
return false;
|
||||
|
||||
WaypointPath::const_iterator currPoint = i_path->find(pointId);
|
||||
if (currPoint == i_path->end())
|
||||
return false;
|
||||
|
||||
// Allow Moving with next tick
|
||||
// Handle allow movement this way to not interact with PAUSED state.
|
||||
// If this function is called while PAUSED, it will move properly when unpaused.
|
||||
i_nextMoveTime.Reset(1);
|
||||
m_isArrivalDone = false;
|
||||
|
||||
// Set the point
|
||||
i_currentNode = pointId;
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------//
|
||||
uint32 FlightPathMovementGenerator::GetPathAtMapEnd() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -37,6 +37,8 @@
|
|||
#include "ObjectGuid.h"
|
||||
#include "World.h"
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#define CLASS_LOCK MaNGOS::ClassLevelLockable<ObjectAccessor, ACE_Thread_Mutex>
|
||||
|
|
|
|||
|
|
@ -40,6 +40,8 @@
|
|||
#include "Player.h"
|
||||
#include "Corpse.h"
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include <set>
|
||||
#include <list>
|
||||
|
||||
|
|
|
|||
|
|
@ -9568,7 +9568,7 @@ bool Unit::SelectHostileTarget()
|
|||
|
||||
// check if currently selected target is reachable
|
||||
// NOTE: path alrteady generated from AttackStart()
|
||||
if (!GetMotionMaster()->operator->()->IsReachable())
|
||||
if (!GetMotionMaster()->GetCurrent()->IsReachable())
|
||||
{
|
||||
// remove all taunts
|
||||
RemoveSpellsCausingAura(SPELL_AURA_MOD_TAUNT);
|
||||
|
|
|
|||
|
|
@ -58,6 +58,8 @@
|
|||
#include "Auth/HMACSHA1.h"
|
||||
#include "zlib.h"
|
||||
|
||||
#include <mutex>
|
||||
|
||||
// select opcodes appropriate for processing in Map::Update context for current session state
|
||||
static bool MapSessionFilterHelper(WorldSession* session, OpcodeHandler const& opHandle)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -37,6 +37,8 @@
|
|||
#include "Item.h"
|
||||
#include "LFGMgr.h"
|
||||
|
||||
#include <mutex>
|
||||
|
||||
struct ItemPrototype;
|
||||
struct AuctionEntry;
|
||||
struct AuctionHouseEntry;
|
||||
|
|
|
|||
|
|
@ -742,7 +742,6 @@ ChatCommand* ChatHandler::getCommandTable()
|
|||
{ "add", SEC_GAMEMASTER, false, &ChatHandler::HandleWpAddCommand, "", NULL },
|
||||
{ "modify", SEC_GAMEMASTER, false, &ChatHandler::HandleWpModifyCommand, "", NULL },
|
||||
{ "export", SEC_ADMINISTRATOR, false, &ChatHandler::HandleWpExportCommand, "", NULL },
|
||||
{ "import", SEC_ADMINISTRATOR, false, &ChatHandler::HandleWpImportCommand, "", NULL },
|
||||
{ NULL, 0, false, NULL, "", NULL }
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -566,7 +566,6 @@ class ChatHandler
|
|||
bool HandleWpModifyCommand(char* args);
|
||||
bool HandleWpShowCommand(char* args);
|
||||
bool HandleWpExportCommand(char* args);
|
||||
bool HandleWpImportCommand(char* args);
|
||||
|
||||
bool HandleHelpCommand(char* args);
|
||||
bool HandleCommandsCommand(char* args);
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@
|
|||
#include "Platform/Define.h"
|
||||
#include "Policies/Singleton.h"
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#define max_ge_check_delay 86400 // 1 day in seconds
|
||||
|
||||
class Creature;
|
||||
|
|
|
|||
|
|
@ -36,6 +36,8 @@
|
|||
#include "Policies/Singleton.h"
|
||||
#include "Util.h"
|
||||
|
||||
#include <mutex>
|
||||
|
||||
char const* MAP_MAGIC = "MAPS";
|
||||
char const* MAP_VERSION_MAGIC = "c1.4";
|
||||
char const* MAP_AREA_MAGIC = "AREA";
|
||||
|
|
|
|||
|
|
@ -35,6 +35,8 @@
|
|||
#include <bitset>
|
||||
#include <list>
|
||||
|
||||
#include <mutex>
|
||||
|
||||
class Creature;
|
||||
class Unit;
|
||||
class WorldPacket;
|
||||
|
|
|
|||
|
|
@ -38,6 +38,8 @@
|
|||
#include "ObjectGuid.h"
|
||||
#include "PoolManager.h"
|
||||
|
||||
#include <mutex>
|
||||
|
||||
struct InstanceTemplate;
|
||||
struct MapEntry;
|
||||
struct MapDifficultyEntry;
|
||||
|
|
|
|||
|
|
@ -779,8 +779,8 @@ void WorldSession::HandleAreaTriggerOpcode(WorldPacket& recv_data)
|
|||
|
||||
if (BattleGround* bg = player->GetBattleGround())
|
||||
{
|
||||
bg->HandleAreaTrigger(player, Trigger_ID);
|
||||
return;
|
||||
if (bg->HandleAreaTrigger(player, Trigger_ID))
|
||||
return;
|
||||
}
|
||||
else if (OutdoorPvP* outdoorPvP = sOutdoorPvPMgr.GetScript(player->GetCachedZoneId()))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2852,6 +2852,11 @@ uint32 GetScriptIdsCount()
|
|||
return sScriptMgr.GetScriptIdsCount();
|
||||
}
|
||||
|
||||
void SetExternalWaypointTable(char const* tableName)
|
||||
{
|
||||
sWaypointMgr.SetExternalWPTable(tableName);
|
||||
}
|
||||
|
||||
bool AddWaypointFromExternal(uint32 entry, int32 pathId, uint32 pointId, float x, float y, float z, float o, uint32 waittime)
|
||||
{
|
||||
return sWaypointMgr.AddExternalNode(entry, pathId, pointId, x, y, z, o, waittime);
|
||||
|
|
|
|||
|
|
@ -29,7 +29,8 @@
|
|||
#include "Policies/Singleton.h"
|
||||
#include "ObjectGuid.h"
|
||||
#include "DBCEnums.h"
|
||||
#include <ace/Atomic_Op.h>
|
||||
//#include <ace/Atomic_Op.h> <- delete this if the #include below works
|
||||
#include <atomic>
|
||||
|
||||
struct AreaTriggerEntry;
|
||||
struct SpellEntry;
|
||||
|
|
@ -614,6 +615,9 @@ class ScriptMgr
|
|||
void LoadEventIdScripts();
|
||||
void LoadSpellIdScripts();
|
||||
|
||||
uint32 GetAreaTriggerScriptId(uint32 triggerId) const;
|
||||
uint32 GetEventIdScriptId(uint32 eventId) const;
|
||||
|
||||
bool ReloadScriptBinding();
|
||||
|
||||
const char* GetScriptName(uint32 id) const
|
||||
|
|
@ -707,6 +711,14 @@ bool StartEvents_Event(Map* map, uint32 id, Object* source, Object* target, bool
|
|||
|
||||
#define sScriptMgr MaNGOS::Singleton<ScriptMgr>::Instance()
|
||||
|
||||
MANGOS_DLL_SPEC uint32 GetAreaTriggerScriptId(uint32 triggerId);
|
||||
MANGOS_DLL_SPEC uint32 GetEventIdScriptId(uint32 eventId);
|
||||
MANGOS_DLL_SPEC uint32 GetScriptId(const char* name);
|
||||
MANGOS_DLL_SPEC char const* GetScriptName(uint32 id);
|
||||
MANGOS_DLL_SPEC uint32 GetScriptIdsCount();
|
||||
MANGOS_DLL_SPEC void SetExternalWaypointTable(char const* tableName);
|
||||
MANGOS_DLL_SPEC bool AddWaypointFromExternal(uint32 entry, int32 pathId, uint32 pointId, float x, float y, float z, float o, uint32 waittime);
|
||||
|
||||
uint32 GetScriptId(const char* name);
|
||||
char const* GetScriptName(uint32 id);
|
||||
uint32 GetScriptIdsCount();
|
||||
|
|
|
|||
|
|
@ -112,6 +112,7 @@ void WaypointManager::Load()
|
|||
{
|
||||
barRow.step();
|
||||
Field* fields = result->Fetch();
|
||||
|
||||
uint32 id = fields[0].GetUInt32();
|
||||
uint32 point = fields[1].GetUInt32();
|
||||
|
||||
|
|
@ -126,7 +127,7 @@ void WaypointManager::Load()
|
|||
if (cData->movementType != WAYPOINT_MOTION_TYPE)
|
||||
creatureNoMoveType.insert(id);
|
||||
|
||||
WaypointPath& path = m_pathMap[id];
|
||||
WaypointPath& path = m_pathTemplateMap[id << 8];
|
||||
WaypointNode& node = path[point];
|
||||
|
||||
node.x = fields[2].GetFloat();
|
||||
|
|
@ -391,12 +392,16 @@ void WaypointManager::Load()
|
|||
void WaypointManager::Unload()
|
||||
{
|
||||
for (WaypointPathMap::iterator itr = m_pathMap.begin(); itr != m_pathMap.end(); ++itr)
|
||||
_clearPath(itr->second);
|
||||
{ _clearPath(itr->second); }
|
||||
m_pathMap.clear();
|
||||
|
||||
for (WaypointPathMap::iterator itr = m_pathTemplateMap.begin(); itr != m_pathTemplateMap.end(); ++itr)
|
||||
_clearPath(itr->second);
|
||||
{ _clearPath(itr->second); }
|
||||
m_pathTemplateMap.clear();
|
||||
|
||||
for (WaypointPathMap::iterator itr = m_externalPathTemplateMap.begin(); itr != m_externalPathTemplateMap.end(); ++itr)
|
||||
{ _clearPath(itr->second); }
|
||||
m_externalPathTemplateMap.clear();
|
||||
}
|
||||
|
||||
void WaypointManager::_clearPath(WaypointPath& path)
|
||||
|
|
|
|||
|
|
@ -110,8 +110,8 @@ class WaypointManager
|
|||
// Helper function to get a path provided the required information
|
||||
WaypointPath* GetPathFromOrigin(uint32 entry, uint32 lowGuid, int32 pathId, WaypointPathOrigin wpOrigin)
|
||||
{
|
||||
WaypointPathMap* wpMap = NULL;
|
||||
uint32 key = 0;
|
||||
WaypointPathMap* wpMap;
|
||||
uint32 key;
|
||||
|
||||
switch (wpOrigin)
|
||||
{
|
||||
|
|
@ -121,19 +121,19 @@ class WaypointManager
|
|||
break;
|
||||
case PATH_FROM_ENTRY:
|
||||
if (pathId >= 0xFF || pathId < 0)
|
||||
return NULL;
|
||||
return nullptr;
|
||||
key = (entry << 8) + pathId;
|
||||
wpMap = &m_pathTemplateMap;
|
||||
break;
|
||||
case PATH_FROM_EXTERNAL:
|
||||
if (pathId >= 0xFF || pathId < 0)
|
||||
return NULL;
|
||||
return nullptr;
|
||||
key = (entry << 8) + pathId;
|
||||
wpMap = &m_externalPathTemplateMap;
|
||||
break;
|
||||
case PATH_NO_PATH:
|
||||
default:
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
WaypointPathMap::iterator find = wpMap->find(key);
|
||||
return find != wpMap->end() ? &find->second : NULL;
|
||||
|
|
@ -197,6 +197,6 @@ class WaypointManager
|
|||
#define sWaypointMgr MaNGOS::Singleton<WaypointManager>::Instance()
|
||||
|
||||
/// Accessor for Scripting library
|
||||
MANGOS_DLL_SPEC bool AddWaypointFromExternal(uint32 entry, int32 pathId, uint32 pointId, float x, float y, float z, float o, uint32 waittime);
|
||||
bool AddWaypointFromExternal(uint32 entry, int32 pathId, uint32 pointId, float x, float y, float z, float o, uint32 waittime);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@
|
|||
#include <iomanip>
|
||||
#include <limits>
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
using G3D::Vector3;
|
||||
|
||||
namespace VMAP
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@
|
|||
#include "Platform/Define.h"
|
||||
#include <G3D/Vector3.h>
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
//===========================================================
|
||||
|
||||
#define MAP_FILENAME_EXTENSION2 ".vmtree"
|
||||
|
|
|
|||
|
|
@ -367,7 +367,12 @@ enum
|
|||
SAY_AT_CLOSE = -1000326,
|
||||
QUEST_GYROMAST_REV = 2078,
|
||||
NPC_GELKAK = 6667,
|
||||
FACTION_HOSTILE = 14
|
||||
FACTION_HOSTILE = 14,
|
||||
|
||||
TEXT_ID_THRESH_DEFAULT = 718,
|
||||
TEXT_ID_KEY_READY = 758,
|
||||
|
||||
GOSSIP_ITEM_TURN_KEY = -3000115,
|
||||
};
|
||||
|
||||
#define GOSSIP_ITEM_INSERT_KEY "[PH] Insert key"
|
||||
|
|
@ -416,10 +421,12 @@ struct npc_threshwackonator : public CreatureScript
|
|||
{
|
||||
if (pPlayer->GetQuestStatus(QUEST_GYROMAST_REV) == QUEST_STATUS_INCOMPLETE)
|
||||
{
|
||||
pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_INSERT_KEY, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
|
||||
pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_TURN_KEY, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
|
||||
pPlayer->SEND_GOSSIP_MENU(TEXT_ID_KEY_READY, pCreature->GetObjectGuid());
|
||||
}
|
||||
else
|
||||
pPlayer->SEND_GOSSIP_MENU(TEXT_ID_THRESH_DEFAULT, pCreature->GetObjectGuid());
|
||||
|
||||
pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ npc_captured_beryl_sorcerer
|
|||
npc_nexus_drake_hatchling
|
||||
npc_scourged_flamespitter
|
||||
npc_bonker_togglevolt
|
||||
npc_jenny
|
||||
EndContentData */
|
||||
|
||||
#include "precompiled.h"
|
||||
|
|
@ -1128,6 +1129,119 @@ struct npc_bonker_togglevolt : public CreatureScript
|
|||
}
|
||||
};
|
||||
|
||||
/*######
|
||||
## npc_jenny
|
||||
######*/
|
||||
|
||||
enum
|
||||
{
|
||||
SPELL_CREATES_CARRIED = 46340,
|
||||
SPELL_DROP_CRATE = 46342,
|
||||
SPELL_JENNY_CREDIT = 46358,
|
||||
|
||||
NPC_FEZZIX = 25849,
|
||||
|
||||
QUEST_ID_LOADER_UP = 11881,
|
||||
};
|
||||
|
||||
struct npc_jenny : public CreatureScript
|
||||
{
|
||||
npc_jenny() : CreatureScript("npc_jenny") {}
|
||||
|
||||
struct npc_jennyAI : public FollowerAI
|
||||
{
|
||||
npc_jennyAI(Creature* pCreature) : FollowerAI(pCreature)
|
||||
{
|
||||
m_bFollowStarted = false;
|
||||
m_bEventComplete = false;
|
||||
Reset();
|
||||
}
|
||||
|
||||
bool m_bEventComplete;
|
||||
bool m_bFollowStarted;
|
||||
|
||||
uint32 m_uiDropDelayTimer;
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
m_uiDropDelayTimer = 0;
|
||||
}
|
||||
|
||||
void AttackedBy(Unit* pAttacker) override
|
||||
{
|
||||
if (!m_uiDropDelayTimer)
|
||||
{
|
||||
if (DoCastSpellIfCan(m_creature, SPELL_DROP_CRATE) == CAST_OK)
|
||||
{
|
||||
m_creature->RemoveAuraHolderFromStack(SPELL_CREATES_CARRIED);
|
||||
m_uiDropDelayTimer = 10000;
|
||||
|
||||
// check if all crates are dropped
|
||||
if (!m_creature->HasAura(SPELL_CREATES_CARRIED))
|
||||
{
|
||||
FollowerAI::JustDied(pAttacker);
|
||||
m_creature->ForcedDespawn();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AttackStart(Unit* pWho) override { }
|
||||
|
||||
void MoveInLineOfSight(Unit* pWho) override
|
||||
{
|
||||
if (m_bEventComplete)
|
||||
return;
|
||||
|
||||
if (pWho->GetEntry() == NPC_FEZZIX && m_creature->IsWithinDistInMap(pWho, 10.0f))
|
||||
{
|
||||
if (DoCastSpellIfCan(m_creature, SPELL_JENNY_CREDIT) == CAST_OK)
|
||||
{
|
||||
SetFollowComplete(true);
|
||||
|
||||
float fX, fY, fZ;
|
||||
pWho->GetContactPoint(m_creature, fX, fY, fZ);
|
||||
m_creature->GetMotionMaster()->MovePoint(0, fX, fY, fZ);
|
||||
m_creature->ForcedDespawn(15000);
|
||||
|
||||
m_bEventComplete = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateFollowerAI(const uint32 uiDiff)
|
||||
{
|
||||
if (!m_bFollowStarted)
|
||||
{
|
||||
if (Player* pSummoner = m_creature->GetCharmerOrOwnerPlayerOrPlayerItself())
|
||||
{
|
||||
StartFollow(pSummoner, pSummoner->getFaction(), GetQuestTemplateStore(QUEST_ID_LOADER_UP));
|
||||
|
||||
if (DoCastSpellIfCan(m_creature, SPELL_CREATES_CARRIED) == CAST_OK)
|
||||
m_bFollowStarted = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_uiDropDelayTimer)
|
||||
{
|
||||
if (m_uiDropDelayTimer <= uiDiff)
|
||||
m_uiDropDelayTimer = 0;
|
||||
else
|
||||
m_uiDropDelayTimer -= uiDiff;
|
||||
}
|
||||
|
||||
if (!m_creature->SelectHostileTarget() || !m_creature->getVictim())
|
||||
return;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* pCreature) override
|
||||
{
|
||||
return new npc_jennyAI(pCreature);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_borean_tundra()
|
||||
{
|
||||
Script* s;
|
||||
|
|
@ -1146,6 +1260,8 @@ void AddSC_borean_tundra()
|
|||
s->RegisterSelf();
|
||||
s = new npc_bonker_togglevolt();
|
||||
s->RegisterSelf();
|
||||
s = new npc_jenny();
|
||||
s->RegisterSelf();
|
||||
|
||||
s = new spell_throw_wolf_batt();
|
||||
s->RegisterSelf();
|
||||
|
|
|
|||
|
|
@ -88,6 +88,7 @@
|
|||
#include <queue>
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "Utilities/Errors.h"
|
||||
#include "LockedQueue/LockedQueue.h"
|
||||
|
|
|
|||
|
|
@ -24,6 +24,11 @@
|
|||
|
||||
#include "Config.h"
|
||||
#include <ace/Configuration_Import_Export.h>
|
||||
#include <mutex>
|
||||
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
|
||||
#include "Policies/Singleton.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,10 @@
|
|||
#include "Common/Common.h"
|
||||
#include <Policies/Singleton.h>
|
||||
#include "Platform/Define.h"
|
||||
#include <mutex>
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
class ACE_Configuration_Heap;
|
||||
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@
|
|||
#include "LockedQueue/LockedQueue.h"
|
||||
#include "Threading/Threading.h"
|
||||
|
||||
#include <mutex>
|
||||
|
||||
class Database;
|
||||
class SqlOperation;
|
||||
class SqlConnection;
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@
|
|||
#include <queue>
|
||||
#include "Utilities/Callback.h"
|
||||
|
||||
#include <mutex>
|
||||
|
||||
/// ---- BASE ---
|
||||
|
||||
class Database;
|
||||
|
|
|
|||
|
|
@ -28,6 +28,8 @@
|
|||
#include "Common/Common.h"
|
||||
#include "Policies/Singleton.h"
|
||||
|
||||
#include <mutex>
|
||||
|
||||
class Config;
|
||||
class ByteBuffer;
|
||||
|
||||
|
|
|
|||
|
|
@ -67,23 +67,11 @@ else()
|
|||
target_link_libraries(${EXECUTABLE_NAME} ACE)
|
||||
endif()
|
||||
|
||||
target_link_libraries(${EXECUTABLE_NAME} g3dlite vmap detour recast zlib shared)
|
||||
|
||||
set(EXECUTABLE_LINK_FLAGS "")
|
||||
|
||||
if(UNIX)
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
|
||||
set(EXECUTABLE_LINK_FLAGS "-Wl,--no-as-needed -lrt -pthread ${EXECUTABLE_LINK_FLAGS}")
|
||||
elseif(CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||
set(EXECUTABLE_LINK_FLAGS "-Wl,--no-as-needed -ldl -pthread -lrt ${EXECUTABLE_LINK_FLAGS}")
|
||||
endif()
|
||||
target_link_libraries(${EXECUTABLE_NAME} rt)
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
set(EXECUTABLE_LINK_FLAGS "-framework CoreServices ${EXECUTABLE_LINK_FLAGS}")
|
||||
endif()
|
||||
|
||||
set_target_properties(${EXECUTABLE_NAME} PROPERTIES LINK_FLAGS "${EXECUTABLE_LINK_FLAGS}")
|
||||
target_link_libraries(${EXECUTABLE_NAME} g3dlite vmap detour recast zlib shared)
|
||||
|
||||
#Output the compiled exes to build/bin/$(Configuration)/tools directory on windows by default
|
||||
if(WIN32)
|
||||
|
|
|
|||
|
|
@ -47,22 +47,20 @@ else()
|
|||
target_link_libraries(${EXECUTABLE_NAME} ACE)
|
||||
endif()
|
||||
|
||||
if(UNIX)
|
||||
target_link_libraries(${EXECUTABLE_NAME} rt dl)
|
||||
endif()
|
||||
|
||||
target_link_libraries(${EXECUTABLE_NAME} vmap g3dlite zlib)
|
||||
|
||||
set(EXECUTABLE_LINK_FLAGS "")
|
||||
|
||||
if(UNIX)
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
|
||||
set(EXECUTABLE_LINK_FLAGS "-Wl,--no-as-needed -lrt -pthread ${EXECUTABLE_LINK_FLAGS}")
|
||||
elseif(CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||
set(EXECUTABLE_LINK_FLAGS "-Wl,--no-as-needed -ldl -pthread -lrt ${EXECUTABLE_LINK_FLAGS}")
|
||||
if(CMAKE_C_COMPILER MATCHES "clang" OR CMAKE_C_COMPILER_ID STREQUAL "Clang")
|
||||
set(EXECUTABLE_LINK_FLAGS "-pthread${EXECUTABLE_LINK_FLAGS}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
set(EXECUTABLE_LINK_FLAGS "-framework CoreServices ${EXECUTABLE_LINK_FLAGS}")
|
||||
endif()
|
||||
|
||||
set_target_properties(${EXECUTABLE_NAME} PROPERTIES LINK_FLAGS "${EXECUTABLE_LINK_FLAGS}")
|
||||
|
||||
#Output the compiled exes to build/bin/$(Configuration)/tools directory on windows by default
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue