Core/Movement: implement cyclic spline database support

This commit is contained in:
Ovahlord committed 2020-09-21 00:32:55 +02:00
1 parent a7cd689bb8
commit 27c1fd6aee
13 files changed
+288 -37

No files matched your search

@@ -0,0 +1,7 @@
ALTER TABLE `creature_addon`
CHANGE `path_id` `waypointPathId` INT(10) UNSIGNED DEFAULT 0 NOT NULL,
ADD COLUMN `cyclicSplinePathId` INT(10) UNSIGNED DEFAULT 0 NOT NULL AFTER `waypointPathId`;
ALTER TABLE `creature_template_addon`
CHANGE `path_id` `waypointPathId` INT(10) UNSIGNED DEFAULT 0 NOT NULL,
ADD COLUMN `cyclicSplinePathId` INT(10) UNSIGNED DEFAULT 0 NOT NULL AFTER `waypointPathId`;
@@ -62,8 +62,8 @@ void WorldDatabaseConnection::DoPrepareStatements()
PrepareStatement(WORLD_SEL_WAYPOINT_DATA_WPGUID_BY_ID, "SELECT wpguid FROM waypoint_data WHERE id = ? and wpguid <> 0", CONNECTION_SYNCH);
PrepareStatement(WORLD_SEL_WAYPOINT_DATA_ACTION, "SELECT DISTINCT action FROM waypoint_data", CONNECTION_SYNCH);
PrepareStatement(WORLD_SEL_WAYPOINT_SCRIPTS_MAX_ID, "SELECT MAX(guid) FROM waypoint_scripts", CONNECTION_SYNCH);
PrepareStatement(WORLD_INS_CREATURE_ADDON, "INSERT INTO creature_addon(guid, path_id) VALUES (?, ?)", CONNECTION_ASYNC);
PrepareStatement(WORLD_UPD_CREATURE_ADDON_PATH, "UPDATE creature_addon SET path_id = ? WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(WORLD_INS_CREATURE_ADDON, "INSERT INTO creature_addon(guid, waypointPathId) VALUES (?, ?)", CONNECTION_ASYNC);
PrepareStatement(WORLD_UPD_CREATURE_ADDON_PATH, "UPDATE creature_addon SET waypointPathId = ? WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(WORLD_DEL_CREATURE_ADDON, "DELETE FROM creature_addon WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(WORLD_SEL_CREATURE_ADDON_BY_GUID, "SELECT guid FROM creature_addon WHERE guid = ?", CONNECTION_SYNCH);
PrepareStatement(WORLD_INS_WAYPOINT_SCRIPT, "INSERT INTO waypoint_scripts (guid) VALUES (?)", CONNECTION_ASYNC);
@@ -26,6 +26,7 @@
#include "SmartAI.h"
#include "TotemAI.h"
#include "CyclicMovementGenerator.h"
#include "MovementGenerator.h"
#include "RandomMovementGenerator.h"
#include "WaypointMovementGenerator.h"
@@ -56,5 +57,6 @@ namespace AIRegistry
(new IdleMovementFactory())->RegisterSelf();
(new MovementGeneratorFactory<RandomMovementGenerator<Creature>>(RANDOM_MOTION_TYPE))->RegisterSelf();
(new MovementGeneratorFactory<WaypointMovementGenerator<Creature>>(WAYPOINT_MOTION_TYPE))->RegisterSelf();
(new MovementGeneratorFactory<CyclicMovementGenerator<Creature>>(CYCLIC_SPLINE_MOTION_TYPE))->RegisterSelf();
}
}
@@ -603,6 +603,8 @@ void SmartAI::JustReachedHome()
{
if (me->GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_IDLE) != WAYPOINT_MOTION_TYPE && me->GetWaypointPath())
me->GetMotionMaster()->MovePath(me->GetWaypointPath(), true);
else if (me->GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_IDLE) != CYCLIC_SPLINE_MOTION_TYPE && me->GetCyclicSplinePathId())
me->GetMotionMaster()->MoveCyclicPath(me->GetCyclicSplinePathId());
else
me->ResumeMovement();
}
@@ -264,7 +264,7 @@ m_lootRecipient(), m_lootRecipientGroup(0), _skinner(), _pickpocketLootRestore(0
m_respawnDelay(300), m_corpseDelay(60), m_respawnradius(0.0f), m_boundaryCheckTime(2500), m_combatPulseTime(0), m_combatPulseDelay(0), m_reactState(REACT_AGGRESSIVE),
m_defaultMovementType(IDLE_MOTION_TYPE), m_spawnId(0), m_equipmentId(0), m_originalEquipmentId(0), m_AlreadyCallAssistance(false),
m_AlreadySearchedAssistance(false), m_regenHealth(true), m_cannotReachTarget(false), m_cannotReachTimer(0), m_AI_locked(false), m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL),
m_originalEntry(0), m_homePosition(), m_transportHomePosition(), m_creatureInfo(nullptr), m_creatureData(nullptr), _waypointPathId(0), _currentWaypointNodeInfo(0, 0),
m_originalEntry(0), m_homePosition(), m_transportHomePosition(), m_creatureInfo(nullptr), m_creatureData(nullptr), _waypointPathId(0), _currentWaypointNodeInfo(0, 0), _cyclicSplinePathId(0),
m_formation(nullptr), m_triggerJustAppeared(true), m_respawnCompatibilityMode(false)
{
m_valuesCount = UNIT_END;
@@ -2595,9 +2595,12 @@ bool Creature::LoadCreaturesAddon()
if (cainfo->visibilityDistanceType != VisibilityDistanceType::Normal)
SetVisibilityDistanceOverride(cainfo->visibilityDistanceType);
// Load Path
if (cainfo->path_id != 0)
_waypointPathId = cainfo->path_id;
// Load pathing data
if (cainfo->waypointPathId)
_waypointPathId = cainfo->waypointPathId;
if (cainfo->cyclicSplinePathId)
_cyclicSplinePathId = cainfo->cyclicSplinePathId;
if (!cainfo->auras.empty())
{
@@ -306,6 +306,8 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma
uint32 GetWaypointPath() const { return _waypointPathId; }
void LoadPath(uint32 pathid) { _waypointPathId = pathid; }
uint32 GetCyclicSplinePathId() const { return _cyclicSplinePathId; }
// nodeId, pathId
std::pair<uint32, uint32> GetCurrentWaypointInfo() const { return _currentWaypointNodeInfo; }
void UpdateCurrentWaypointInfo(uint32 nodeId, uint32 pathId) { _currentWaypointNodeInfo = { nodeId, pathId }; }
@@ -426,6 +428,8 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma
uint32 _waypointPathId;
std::pair<uint32/*nodeId*/, uint32/*pathId*/> _currentWaypointNodeInfo;
// Cyclic spline path
uint32 _cyclicSplinePathId;
//Formation var
CreatureGroup* m_formation;
@@ -327,7 +327,8 @@ enum InhabitTypeValues
// `creature_addon` table
struct CreatureAddon
{
uint32 path_id;
uint32 waypointPathId;
uint32 cyclicSplinePathId;
uint32 mount;
uint32 bytes1;
uint32 bytes2;
+48 -25
View File
@@ -563,8 +563,8 @@ void ObjectMgr::LoadCreatureTemplateAddons()
{
uint32 oldMSTime = getMSTime();
// 0 1 2 3 4 5 6 7 8 9 10
QueryResult result = WorldDatabase.Query("SELECT entry, path_id, mount, bytes1, bytes2, emote, aiAnimKit, movementAnimKit, meleeAnimKit, visibilityDistanceType, auras FROM creature_template_addon");
// 0 1 2 3 4 5 6 7 8 9 10 11
QueryResult result = WorldDatabase.Query("SELECT entry, waypointPathId, cyclicSplinePathId, mount, bytes1, bytes2, emote, aiAnimKit, movementAnimKit, meleeAnimKit, visibilityDistanceType, auras FROM creature_template_addon");
if (!result)
{
@@ -587,17 +587,18 @@ void ObjectMgr::LoadCreatureTemplateAddons()
CreatureAddon& creatureAddon = _creatureTemplateAddonStore[entry];
creatureAddon.path_id = fields[1].GetUInt32();
creatureAddon.mount = fields[2].GetUInt32();
creatureAddon.bytes1 = fields[3].GetUInt32();
creatureAddon.bytes2 = fields[4].GetUInt32();
creatureAddon.emote = fields[5].GetUInt32();
creatureAddon.aiAnimKit = fields[6].GetUInt16();
creatureAddon.movementAnimKit = fields[7].GetUInt16();
creatureAddon.meleeAnimKit = fields[8].GetUInt16();
creatureAddon.visibilityDistanceType = VisibilityDistanceType(fields[9].GetUInt8());
creatureAddon.waypointPathId = fields[1].GetUInt32();
creatureAddon.cyclicSplinePathId = fields[2].GetUInt32();
creatureAddon.mount = fields[3].GetUInt32();
creatureAddon.bytes1 = fields[4].GetUInt32();
creatureAddon.bytes2 = fields[5].GetUInt32();
creatureAddon.emote = fields[6].GetUInt32();
creatureAddon.aiAnimKit = fields[7].GetUInt16();
creatureAddon.movementAnimKit = fields[8].GetUInt16();
creatureAddon.meleeAnimKit = fields[9].GetUInt16();
creatureAddon.visibilityDistanceType = VisibilityDistanceType(fields[10].GetUInt8());
Tokenizer tokens(fields[10].GetString(), ' ');
Tokenizer tokens(fields[11].GetString(), ' ');
uint8 i = 0;
creatureAddon.auras.resize(tokens.size());
for (Tokenizer::const_iterator itr = tokens.begin(); itr != tokens.end(); ++itr)
@@ -1146,8 +1147,8 @@ void ObjectMgr::LoadCreatureAddons()
{
uint32 oldMSTime = getMSTime();
// 0 1 2 3 4 5 6 7 8 9 10
QueryResult result = WorldDatabase.Query("SELECT guid, path_id, mount, bytes1, bytes2, emote, aiAnimKit, movementAnimKit, meleeAnimKit, visibilityDistanceType, auras FROM creature_addon");
// 0 1 2 3 4 5 6 7 8 9 10 11
QueryResult result = WorldDatabase.Query("SELECT guid, waypointPathId, cyclicSplinePathId, mount, bytes1, bytes2, emote, aiAnimKit, movementAnimKit, meleeAnimKit, visibilityDistanceType, auras FROM creature_addon");
if (!result)
{
@@ -1171,23 +1172,45 @@ void ObjectMgr::LoadCreatureAddons()
CreatureAddon& creatureAddon = _creatureAddonStore[guid];
creatureAddon.path_id = fields[1].GetUInt32();
if (creData->movementType == WAYPOINT_MOTION_TYPE && !creatureAddon.path_id)
creatureAddon.waypointPathId = fields[1].GetUInt32();
creatureAddon.cyclicSplinePathId = fields[2].GetUInt32();
if (creatureAddon.waypointPathId && creatureAddon.cyclicSplinePathId)
{
if (creData->movementType == WAYPOINT_MOTION_TYPE)
{
creatureAddon.cyclicSplinePathId = 0;
TC_LOG_ERROR("sql.sql", "Creature (GUID %u) has a waypoint and cyclic spline path at the same time but uses WAYPOINT_MOTION_TYPE. Prefered waypoint path", guid);
}
else if (creData->movementType == CYCLIC_SPLINE_MOTION_TYPE)
{
creatureAddon.waypointPathId = 0;
TC_LOG_ERROR("sql.sql", "Creature (GUID %u) has a waypoint and cyclic spline path at the same time but uses CYCLIC_SPLINE_MOTION_TYPE. Prefered cyclic spline path", guid);
}
}
if (creData->movementType == WAYPOINT_MOTION_TYPE && !creatureAddon.waypointPathId)
{
const_cast<CreatureData*>(creData)->movementType = IDLE_MOTION_TYPE;
TC_LOG_ERROR("sql.sql", "Creature (GUID %u) has movement type set to WAYPOINT_MOTION_TYPE but no path assigned", guid);
}
creatureAddon.mount = fields[2].GetUInt32();
creatureAddon.bytes1 = fields[3].GetUInt32();
creatureAddon.bytes2 = fields[4].GetUInt32();
creatureAddon.emote = fields[5].GetUInt32();
creatureAddon.aiAnimKit = fields[6].GetUInt16();
creatureAddon.movementAnimKit = fields[7].GetUInt16();
creatureAddon.meleeAnimKit = fields[8].GetUInt16();
creatureAddon.visibilityDistanceType = VisibilityDistanceType(fields[9].GetUInt8());
if (creData->movementType == CYCLIC_SPLINE_MOTION_TYPE && !creatureAddon.cyclicSplinePathId)
{
const_cast<CreatureData*>(creData)->movementType = IDLE_MOTION_TYPE;
TC_LOG_ERROR("sql.sql", "Creature (GUID %u) has movement type set to CYCLIC_SPLINE_MOTION_TYPE but no path assigned", guid);
}
Tokenizer tokens(fields[10].GetString(), ' ');
creatureAddon.mount = fields[3].GetUInt32();
creatureAddon.bytes1 = fields[4].GetUInt32();
creatureAddon.bytes2 = fields[5].GetUInt32();
creatureAddon.emote = fields[6].GetUInt32();
creatureAddon.aiAnimKit = fields[7].GetUInt16();
creatureAddon.movementAnimKit = fields[8].GetUInt16();
creatureAddon.meleeAnimKit = fields[9].GetUInt16();
creatureAddon.visibilityDistanceType = VisibilityDistanceType(fields[10].GetUInt8());
Tokenizer tokens(fields[11].GetString(), ' ');
uint8 i = 0;
creatureAddon.auras.resize(tokens.size());
for (Tokenizer::const_iterator itr = tokens.begin(); itr != tokens.end(); ++itr)
+10 -2
View File
@@ -20,6 +20,7 @@
#include "ConfusedMovementGenerator.h"
#include "Creature.h"
#include "CreatureAISelector.h"
#include "CyclicMovementGenerator.h"
#include "DBCStores.h"
#include "G3DPosition.hpp"
#include "FleeingMovementGenerator.h"
@@ -42,6 +43,7 @@
#include "Unit.h"
#include "WaypointDefines.h"
#include "WaypointMovementGenerator.h"
#include "WaypointManager.h"
inline MovementGenerator* GetIdleMovementGenerator()
{
@@ -498,7 +500,7 @@ void MotionMaster::MoveCirclePath(float x, float y, float z, float radius, bool
if (velocity > 0.f)
init.SetVelocity(velocity);
Mutate(new GenericMovementGenerator(std::move(init), EFFECT_MOTION_TYPE, 0), MOTION_SLOT_ACTIVE);
Mutate(new GenericMovementGenerator(std::move(init), CYCLIC_SPLINE_MOTION_TYPE, 0), MOTION_SLOT_ACTIVE);
}
void MotionMaster::MoveCyclicPath(Position const* pathPoints, size_t pathSize, bool walk /*= false*/, bool fly /*= false*/, float velocity /*= 0.0f*/)
@@ -524,7 +526,13 @@ void MotionMaster::MoveCyclicPath(Position const* pathPoints, size_t pathSize, b
init.SetSmooth();
init.SetWalk(walk);
init.SetCyclic();
Mutate(new GenericMovementGenerator(std::move(init), EFFECT_MOTION_TYPE, 0), MOTION_SLOT_IDLE);
Mutate(new GenericMovementGenerator(std::move(init), CYCLIC_SPLINE_MOTION_TYPE, 0), MOTION_SLOT_IDLE);
}
void MotionMaster::MoveCyclicPath(uint32 pathId)
{
if (WaypointPath const* splinePath = sWaypointMgr->GetPath(pathId))
Mutate(new CyclicMovementGenerator<Creature>(splinePath), MOTION_SLOT_IDLE);
}
void MotionMaster::MoveSmoothPath(uint32 pointId, Position const* pathPoints, size_t pathSize, bool walk /*= false*/, bool fly /*= false*/, float velocity /*= 0.0f*/)
+4 -2
View File
@@ -49,7 +49,8 @@ enum MovementGeneratorType : uint8
IDLE_MOTION_TYPE = 0, // IdleMovementGenerator.h
RANDOM_MOTION_TYPE = 1, // RandomMovementGenerator.h
WAYPOINT_MOTION_TYPE = 2, // WaypointMovementGenerator.h
MAX_DB_MOTION_TYPE = 3, // Below motion types can't be set in DB.
CYCLIC_SPLINE_MOTION_TYPE = 3, // CyclicMovementGenerator.h
MAX_DB_MOTION_TYPE = 4, // Below motion types can't be set in DB.
CONFUSED_MOTION_TYPE = 4, // ConfusedMovementGenerator.h
CHASE_MOTION_TYPE = 5, // TargetedMovementGenerator.h
HOME_MOTION_TYPE = 6, // HomeMovementGenerator.h
@@ -60,7 +61,7 @@ enum MovementGeneratorType : uint8
ASSISTANCE_MOTION_TYPE = 11, // PointMovementGenerator.h
ASSISTANCE_DISTRACT_MOTION_TYPE = 12, // IdleMovementGenerator.h
TIMED_FLEEING_MOTION_TYPE = 13, // FleeingMovementGenerator.h
FOLLOW_MOTION_TYPE = 14,
FOLLOW_MOTION_TYPE = 14, // FollowMovementGenerator.h
ROTATE_MOTION_TYPE = 15,
EFFECT_MOTION_TYPE = 16,
SPLINE_CHAIN_MOTION_TYPE = 17, // SplineChainMovementGenerator.h
@@ -182,6 +183,7 @@ class TC_GAME_API MotionMaster
void MoveJump(float x, float y, float z, float o, float speedXY, float speedZ, uint32 id = EVENT_JUMP, bool hasOrientation = false);
void MoveCirclePath(float x, float y, float z, float radius, bool clockwise, uint8 stepCount, float velocity = 0.f);
void MoveCyclicPath(Position const* pathPoints, size_t pathSize, bool walk = false, bool fly = false, float velocity = 0.f);
void MoveCyclicPath(uint32 pathId);
void MoveSmoothPath(uint32 pointId, Position const* pathPoints, size_t pathSize, bool walk = false, bool fly = false, float velocity = 0.f);
// Walk along spline chain stored in DB (script_spline_chain_meta and script_spline_chain_waypoints)
void MoveAlongSplineChain(uint32 pointId, uint16 dbChainId, bool walk);
@@ -0,0 +1,141 @@
/*
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "CyclicMovementGenerator.h"
#include "Creature.h"
#include "CreatureAI.h"
#include "G3DPosition.hpp"
#include "Log.h"
#include "Map.h"
#include "MoveSpline.h"
#include "MoveSplineInit.h"
#include "ObjectMgr.h"
#include "Transport.h"
#include "WaypointManager.h"
inline bool CanMove(Creature const* creature)
{
return (!creature->HasUnitState(UNIT_STATE_NOT_MOVE) && !creature->IsMovementPreventedByCasting());
}
CyclicMovementGenerator<Creature>::CyclicMovementGenerator(WaypointPath const* path, Optional<bool> enforceFlight, Optional<bool> enforceWalk, Optional<float> velocity) : _path(path), _moveTimer(0)
{
if (enforceFlight.is_initialized())
_enforceFlight = *enforceFlight;
if (enforceWalk.is_initialized())
_enforceWalk = *enforceWalk;
if (velocity.is_initialized())
_velocity = *velocity;
}
CyclicMovementGenerator<Creature>::CyclicMovementGenerator() : _path(nullptr), _moveTimer(0)
{
}
void CyclicMovementGenerator<Creature>::DoInitialize(Creature* creature)
{
if (!_path)
if (uint32 pathId = creature->GetCyclicSplinePathId())
_path = sWaypointMgr->GetPath(pathId);
if (_path)
_moveTimer.Reset(1000);
}
void CyclicMovementGenerator<Creature>::DoFinalize(Creature* creature)
{
creature->setActive(false);
}
void CyclicMovementGenerator<Creature>::DoReset(Creature* creature)
{
if (_moveTimer.Passed() && CanMove(creature))
StartMovement(creature);
}
bool CyclicMovementGenerator<Creature>::DoUpdate(Creature* creature, uint32 diff)
{
if (!creature || !creature->IsAlive())
return true;
if (!_path || _path->nodes.empty())
return true;
if (!CanMove(creature))
{
creature->StopMoving();
return true;
}
// dont update wait timer while moving
if (creature->movespline->Finalized())
{
_moveTimer.Update(diff);
if (_moveTimer.Passed())
{
_moveTimer.Reset(0);
StartMovement(creature);
}
}
return true;
}
void CyclicMovementGenerator<Creature>::StartMovement(Creature* creature)
{
if (!creature || !creature->IsAlive() || !CanMove(creature) || !_path || _path->nodes.empty())
return;
if (!CanMove(creature) || (creature->IsFormationLeader() && !creature->IsFormationLeaderMoveAllowed())) // if cannot move OR cannot move because of formation
{
_moveTimer.Reset(1000); // delay 1s
return;
}
// Cyclic splines get asynchronous if the serverside position is not being tracked constantly.
creature->setActive(true);
bool const flying = creature->IsFlying() || creature->IsInWater(); // Swimming units also use flying and uncompressed splines
Movement::MoveSplineInit init(creature);
Movement::PointsArray path;
path.reserve(_path->nodes.size() + 1);
path.push_back(PositionToVector3(creature->GetPosition()));
std::transform(_path->nodes.begin(), _path->nodes.end(), std::back_inserter(path), [](WaypointNode const& node)
{
return G3D::Vector3(node.x, node.y, node.z);
});
if (flying || (_enforceFlight.is_initialized() && *_enforceFlight))
{
init.SetFly();
init.SetUncompressed();
}
if (_velocity.is_initialized())
init.SetVelocity(*_velocity);
if (_enforceWalk.is_initialized())
init.SetWalk(*_enforceWalk);
init.MovebyPath(path);
init.SetSmooth();
init.SetCyclic();
init.Launch();
}
@@ -0,0 +1,58 @@
/*
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TRINITY_CYCLICMOVEMENTGENERATOR_H
#define TRINITY_CYCLICMOVEMENTGENERATOR_H
#include "MovementGenerator.h"
#include "Timer.h"
#include "OptionalFwd.h"
enum MovementGeneratorType : uint8;
class Creature;
struct WaypointPath;
template<class T>
class CyclicMovementGenerator;
template<>
class CyclicMovementGenerator<Creature> : public MovementGeneratorMedium<Creature, CyclicMovementGenerator<Creature>>
{
public:
explicit CyclicMovementGenerator(WaypointPath const* path, Optional<bool> enforceFlight = { }, Optional<bool> enforceWalk = { }, Optional<float> velocity = { });
explicit CyclicMovementGenerator();
void DoInitialize(Creature*);
void DoFinalize(Creature*);
void DoReset(Creature*);
bool DoUpdate(Creature*, uint32);
MovementGeneratorType GetMovementGeneratorType() const override { return CYCLIC_SPLINE_MOTION_TYPE; }
private:
void StartMovement(Creature*);
WaypointPath const* _path;
Optional<bool> _enforceFlight;
Optional<bool> _enforceWalk;
Optional<float> _velocity;
TimeTrackerSmall _moveTimer;
};
#endif // TRINITY_CYCLICMOVEMENTGENERATOR_H
+1 -1
View File
@@ -260,7 +260,7 @@ public:
}
CreatureAddon const* addon = sObjectMgr->GetCreatureAddon(guidLow);
if (!addon || addon->path_id == 0)
if (!addon || addon->waypointPathId == 0)
{
handler->PSendSysMessage("%s%s|r", "|cffff33ff", "Target does not have a loaded path.");
return true;