mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-22 05:06:24 +00:00
fix(Core/Creature): Fixed GroupAI flags usage in creature_formations (#7544)
* fix(Core/Creature): Fixed GroupAI flags usage * fix(Core/Creature): build fix + code style... * fix(Core/Creatures): trailing white spaces... * Core/Formations: allow only certain members to have follow formation * Core/Formations: fixed ancient data corruption in CreatureGroup::LeaderMoveTo * Core/Formations: minor optimization * Core/Formations: improved some warning messages * Core/Formations: do not load invalid formation data which has unsupported group ai * Core/Formations: minor adjust for recent commit * Core/Formations: log formation data which has angle and distance but dont have GROUP_AI_FLAG_FOLLOW_LEADER flag * Core/Formations: Minor optimization for formation data handling * Core/Formations: make sure that FormationInfo members are always initialized on its creation * Core/Formations: minor warnings adjustments * DB/Formations: fixed some warnings * Core/Formations: check group flags only if there is any I have gues that maybe leader could not assist any member at all but members maybe could be linked for motion * DB/Formations: fixed rest of DB warnings * Core/Formations: more improvements for supported AI mask check * Core/Formations: more improvements for data checks * DB/Formations: fixed warnings * meh * DB/Formations: minor correction * Core/Formations: code style - brackets, you suck... :D
This commit is contained in:
@@ -270,15 +270,21 @@ void Creature::DisappearAndDie()
|
||||
void Creature::SearchFormation()
|
||||
{
|
||||
if (IsSummon())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ObjectGuid::LowType spawnId = GetSpawnId();
|
||||
if (!spawnId)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CreatureGroupInfoType::iterator frmdata = sFormationMgr->CreatureGroupMap.find(spawnId);
|
||||
CreatureGroupInfoType::const_iterator frmdata = sFormationMgr->CreatureGroupMap.find(spawnId);
|
||||
if (frmdata != sFormationMgr->CreatureGroupMap.end())
|
||||
sFormationMgr->AddCreatureToGroup(frmdata->second->leaderGUID, this);
|
||||
{
|
||||
sFormationMgr->AddCreatureToGroup(frmdata->second.leaderGUID, this);
|
||||
}
|
||||
}
|
||||
|
||||
void Creature::RemoveCorpse(bool setSpawnTime, bool skipVisibility)
|
||||
|
||||
@@ -9,11 +9,10 @@
|
||||
#include "CreatureGroups.h"
|
||||
#include "MoveSplineInit.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "Log.h"
|
||||
|
||||
FormationMgr::~FormationMgr()
|
||||
{
|
||||
for (CreatureGroupInfoType::iterator itr = CreatureGroupMap.begin(); itr != CreatureGroupMap.end(); ++itr)
|
||||
delete itr->second;
|
||||
}
|
||||
|
||||
FormationMgr* FormationMgr::instance()
|
||||
@@ -26,7 +25,9 @@ void FormationMgr::AddCreatureToGroup(uint32 groupId, Creature* member)
|
||||
{
|
||||
Map* map = member->FindMap();
|
||||
if (!map)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CreatureGroupHolderType::iterator itr = map->CreatureGroupHolder.find(groupId);
|
||||
|
||||
@@ -55,7 +56,9 @@ void FormationMgr::RemoveCreatureFromGroup(CreatureGroup* group, Creature* membe
|
||||
{
|
||||
Map* map = member->FindMap();
|
||||
if (!map)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_DEBUG("entities.unit", "Deleting group with InstanceID %u", member->GetInstanceId());
|
||||
map->CreatureGroupHolder.erase(group->GetId());
|
||||
@@ -65,15 +68,11 @@ void FormationMgr::RemoveCreatureFromGroup(CreatureGroup* group, Creature* membe
|
||||
|
||||
void FormationMgr::LoadCreatureFormations()
|
||||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
|
||||
for (CreatureGroupInfoType::iterator itr = CreatureGroupMap.begin(); itr != CreatureGroupMap.end(); ++itr) // for reload case
|
||||
delete itr->second;
|
||||
uint32 const oldMSTime = getMSTime();
|
||||
CreatureGroupMap.clear();
|
||||
|
||||
//Get group data
|
||||
QueryResult result = WorldDatabase.Query("SELECT leaderGUID, memberGUID, dist, angle, groupAI, point_1, point_2 FROM creature_formations ORDER BY leaderGUID");
|
||||
|
||||
if (!result)
|
||||
{
|
||||
LOG_ERROR("sql.sql", ">> Loaded 0 creatures in formations. DB table `creature_formations` is empty!");
|
||||
@@ -82,47 +81,68 @@ void FormationMgr::LoadCreatureFormations()
|
||||
}
|
||||
|
||||
uint32 count = 0;
|
||||
Field* fields;
|
||||
FormationInfo* group_member;
|
||||
|
||||
do
|
||||
{
|
||||
fields = result->Fetch();
|
||||
Field const* fields = result->Fetch();
|
||||
|
||||
//Load group member data
|
||||
group_member = new FormationInfo();
|
||||
group_member->leaderGUID = fields[0].GetUInt32();
|
||||
ObjectGuid::LowType memberGUID = fields[1].GetUInt32();
|
||||
group_member->groupAI = fields[4].GetUInt32();
|
||||
group_member->point_1 = fields[5].GetUInt16();
|
||||
group_member->point_2 = fields[6].GetUInt16();
|
||||
FormationInfo group_member;
|
||||
group_member.leaderGUID = fields[0].GetUInt32();
|
||||
ObjectGuid::LowType const memberGUID = fields[1].GetUInt32();
|
||||
float const follow_dist = fields[2].GetFloat();
|
||||
float const follow_angle = fields[3].GetFloat() * static_cast<float>(M_PI) / 180;
|
||||
group_member.groupAI = fields[4].GetUInt16();
|
||||
group_member.point_1 = fields[5].GetUInt16();
|
||||
group_member.point_2 = fields[6].GetUInt16();
|
||||
|
||||
//If creature is group leader we may skip loading of dist/angle
|
||||
if (group_member->leaderGUID != memberGUID)
|
||||
if (group_member.leaderGUID != memberGUID)
|
||||
{
|
||||
group_member->follow_dist = fields[2].GetFloat();
|
||||
group_member->follow_angle = fields[3].GetFloat() * M_PI / 180;
|
||||
if (!group_member.HasGroupFlag(std::underlying_type_t<GroupAIFlags>(GroupAIFlags::GROUP_AI_FLAG_SUPPORTED)))
|
||||
{
|
||||
LOG_ERROR("sql.sql", "creature_formations table leader guid %u and member guid %u has unsupported GroupAI flag value (%u). Skipped", group_member.leaderGUID, memberGUID, group_member.groupAI);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!group_member.HasGroupFlag(std::underlying_type_t<GroupAIFlags>(GroupAIFlags::GROUP_AI_FLAG_FOLLOW_LEADER)) && (follow_dist > 0.0f || follow_angle > 0.0f))
|
||||
{
|
||||
LOG_ERROR("sql.sql", "creature_formations table member guid %u and leader guid %u cannot have follow distance or follow angle because don't have GROUP_AI_FLAG_FOLLOW_LEADER flag. Values are not gonna be used", memberGUID, group_member.leaderGUID);
|
||||
group_member.follow_dist = 0.0f;
|
||||
group_member.follow_angle = 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
group_member.follow_dist = follow_dist;
|
||||
group_member.follow_angle = follow_angle * static_cast<float>(M_PI) / 180;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
group_member->follow_dist = 0;
|
||||
group_member->follow_angle = 0;
|
||||
// Leader can have 0 AI flags - its allowed
|
||||
if (group_member.groupAI && !group_member.HasGroupFlag(std::underlying_type_t<GroupAIFlags>(GroupAIFlags::GROUP_AI_FLAG_SUPPORTED)))
|
||||
{
|
||||
LOG_ERROR("sql.sql", "creature_formations table leader guid %u and member guid %u has unsupported GroupAI flag value (%u). Skipped", group_member.leaderGUID, memberGUID, group_member.groupAI);
|
||||
continue;
|
||||
}
|
||||
|
||||
group_member.follow_dist = 0.0f;
|
||||
group_member.follow_angle = 0.0f;
|
||||
if (follow_dist > 0.0f || follow_angle > 0.0f)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "creature_formations table member guid %u and leader guid %u cannot have follow distance or follow angle. Values are not gonna be used", memberGUID, group_member.leaderGUID);
|
||||
}
|
||||
}
|
||||
|
||||
// check data correctness
|
||||
if (!sObjectMgr->GetCreatureData(group_member.leaderGUID))
|
||||
{
|
||||
if (!sObjectMgr->GetCreatureData(group_member->leaderGUID))
|
||||
{
|
||||
LOG_ERROR("sql.sql", "creature_formations table leader guid %u incorrect (not exist)", group_member->leaderGUID);
|
||||
delete group_member;
|
||||
continue;
|
||||
}
|
||||
LOG_ERROR("sql.sql", "creature_formations table leader guid %u incorrect (does not exist). Skipped", group_member.leaderGUID);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!sObjectMgr->GetCreatureData(memberGUID))
|
||||
{
|
||||
LOG_ERROR("sql.sql", "creature_formations table member guid %u incorrect (not exist)", memberGUID);
|
||||
delete group_member;
|
||||
continue;
|
||||
}
|
||||
if (!sObjectMgr->GetCreatureData(memberGUID))
|
||||
{
|
||||
LOG_ERROR("sql.sql", "creature_formations table member guid %u incorrect (does not exist). Skipped", memberGUID);
|
||||
continue;
|
||||
}
|
||||
|
||||
CreatureGroupMap[memberGUID] = group_member;
|
||||
@@ -151,7 +171,9 @@ void CreatureGroup::AddMember(Creature* member)
|
||||
void CreatureGroup::RemoveMember(Creature* member)
|
||||
{
|
||||
if (m_leader == member)
|
||||
{
|
||||
m_leader = nullptr;
|
||||
}
|
||||
|
||||
m_members.erase(member);
|
||||
member->SetFormation(nullptr);
|
||||
@@ -159,53 +181,63 @@ void CreatureGroup::RemoveMember(Creature* member)
|
||||
|
||||
void CreatureGroup::MemberAttackStart(Creature* member, Unit* target)
|
||||
{
|
||||
uint8 groupAI = sFormationMgr->CreatureGroupMap[member->GetSpawnId()]->groupAI;
|
||||
if (!groupAI)
|
||||
return;
|
||||
|
||||
if (groupAI == 1 && member != m_leader)
|
||||
return;
|
||||
|
||||
for (CreatureGroupMemberType::iterator itr = m_members.begin(); itr != m_members.end(); ++itr)
|
||||
uint8 const groupAI = sFormationMgr->CreatureGroupMap[member->GetSpawnId()].groupAI;
|
||||
if (member == m_leader)
|
||||
{
|
||||
if (!(groupAI & std::underlying_type_t<GroupAIFlags>(GroupAIFlags::GROUP_AI_FLAG_MEMBER_ASSIST_LEADER)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (!(groupAI & std::underlying_type_t<GroupAIFlags>(GroupAIFlags::GROUP_AI_FLAG_LEADER_ASSIST_MEMBER)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto const& itr : m_members)
|
||||
{
|
||||
Creature* pMember = itr.first;
|
||||
if (m_leader) // avoid crash if leader was killed and reset.
|
||||
LOG_DEBUG("entities.unit", "GROUP ATTACK: group instance id %u calls member instid %u", m_leader->GetInstanceId(), member->GetInstanceId());
|
||||
|
||||
//Skip one check
|
||||
if (itr->first == member)
|
||||
if (pMember == member)
|
||||
continue;
|
||||
|
||||
if (!itr->first->IsAlive())
|
||||
if (!pMember->IsAlive())
|
||||
continue;
|
||||
|
||||
if (itr->first->GetVictim())
|
||||
if (pMember->GetVictim())
|
||||
continue;
|
||||
|
||||
if (itr->first->IsValidAttackTarget(target) && itr->first->AI())
|
||||
itr->first->AI()->AttackStart(target);
|
||||
if (pMember->IsValidAttackTarget(target) && pMember->AI())
|
||||
pMember->AI()->AttackStart(target);
|
||||
}
|
||||
}
|
||||
|
||||
void CreatureGroup::FormationReset(bool dismiss, bool initMotionMaster)
|
||||
{
|
||||
if (m_members.size() && m_members.begin()->second->groupAI == 5)
|
||||
return;
|
||||
|
||||
for (CreatureGroupMemberType::iterator itr = m_members.begin(); itr != m_members.end(); ++itr)
|
||||
if (m_members.size() && !(m_members.begin()->second.HasGroupFlag(std::underlying_type_t<GroupAIFlags>(GroupAIFlags::GROUP_AI_FLAG_FOLLOW_LEADER))))
|
||||
{
|
||||
if (itr->first != m_leader && itr->first->IsAlive())
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto const& itr : m_members)
|
||||
{
|
||||
Creature* member = itr.first;
|
||||
if (member && member != m_leader && member->IsAlive())
|
||||
{
|
||||
if (initMotionMaster)
|
||||
{
|
||||
if (dismiss)
|
||||
{
|
||||
itr->first->GetMotionMaster()->Initialize();
|
||||
member->GetMotionMaster()->Initialize();
|
||||
}
|
||||
else
|
||||
{
|
||||
itr->first->GetMotionMaster()->MoveIdle();
|
||||
member->GetMotionMaster()->MoveIdle();
|
||||
}
|
||||
LOG_DEBUG("entities.unit", "Set %s movement for member %s", dismiss ? "default" : "idle", itr->first->GetGUID().ToString().c_str());
|
||||
LOG_DEBUG("entities.unit", "Set %s movement for member %s", dismiss ? "default" : "idle", member->GetGUID().ToString().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -217,58 +249,64 @@ void CreatureGroup::LeaderMoveTo(float x, float y, float z, bool run)
|
||||
//! To do: This should probably get its own movement generator or use WaypointMovementGenerator.
|
||||
//! If the leader's path is known, member's path can be plotted as well using formation offsets.
|
||||
if (!m_leader)
|
||||
{
|
||||
return;
|
||||
|
||||
uint8 groupAI = sFormationMgr->CreatureGroupMap[m_leader->GetSpawnId()]->groupAI;
|
||||
if (groupAI == 5)
|
||||
return;
|
||||
}
|
||||
|
||||
float pathDist = m_leader->GetExactDist(x, y, z);
|
||||
float pathAngle = m_leader->GetAngle(x, y);
|
||||
float pathAngle = std::atan2(m_leader->GetPositionY() - y, m_leader->GetPositionX() - x);
|
||||
|
||||
for (CreatureGroupMemberType::iterator itr = m_members.begin(); itr != m_members.end(); ++itr)
|
||||
for (auto const& itr : m_members)
|
||||
{
|
||||
Creature* member = itr->first;
|
||||
if (member == m_leader || !member->IsAlive() || member->GetVictim())
|
||||
Creature* member = itr.first;
|
||||
FormationInfo const& pFormationInfo = itr.second;
|
||||
if (member == m_leader || !member->IsAlive() || member->GetVictim() || !pFormationInfo.HasGroupFlag(std::underlying_type_t<GroupAIFlags>(GroupAIFlags::GROUP_AI_FLAG_FOLLOW_LEADER)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Xinef: If member is stunned / rooted etc don't allow to move him
|
||||
if (member->HasUnitState(UNIT_STATE_NOT_MOVE))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Xinef: this should be automatized, if turn angle is greater than PI/2 (90<39>) we should swap formation angle
|
||||
if (M_PI - fabs(fabs(m_leader->GetOrientation() - pathAngle) - M_PI) > M_PI * 0.50f)
|
||||
float followAngle = pFormationInfo.follow_angle;
|
||||
if (static_cast<float>(M_PI) - fabs(fabs(m_leader->GetOrientation() - pathAngle) - static_cast<float>(M_PI)) > static_cast<float>(M_PI)* 0.5f)
|
||||
{
|
||||
// pussywizard: in both cases should be 2*M_PI - follow_angle
|
||||
// pussywizard: also, GetCurrentWaypointID() returns 0..n-1, while point_1 must be > 0, so +1
|
||||
// pussywizard: db table waypoint_data shouldn't have point id 0 and shouldn't have any gaps for this to work!
|
||||
// if (m_leader->GetCurrentWaypointID()+1 == itr->second->point_1 || m_leader->GetCurrentWaypointID()+1 == itr->second->point_2)
|
||||
itr->second->follow_angle = Position::NormalizeOrientation(itr->second->follow_angle + M_PI); //(2 * M_PI) - itr->second->follow_angle;
|
||||
// if (m_leader->GetCurrentWaypointID()+1 == pFormationInfo->point_1 || m_leader->GetCurrentWaypointID()+1 == itr->second->point_2)
|
||||
followAngle = Position::NormalizeOrientation(pFormationInfo.follow_angle + static_cast<float>(M_PI)); //(2 * M_PI) - itr->second->follow_angle;
|
||||
}
|
||||
|
||||
float followAngle = itr->second->follow_angle;
|
||||
float followDist = itr->second->follow_dist;
|
||||
float const followDist = pFormationInfo.follow_dist;
|
||||
|
||||
float dx = x + cos(followAngle + pathAngle) * followDist;
|
||||
float dy = y + sin(followAngle + pathAngle) * followDist;
|
||||
float dx = x + std::cos(followAngle + pathAngle) * followDist;
|
||||
float dy = y + std::sin(followAngle + pathAngle) * followDist;
|
||||
float dz = z;
|
||||
|
||||
Acore::NormalizeMapCoord(dx);
|
||||
Acore::NormalizeMapCoord(dy);
|
||||
|
||||
member->UpdateGroundPositionZ(dx, dy, dz);
|
||||
|
||||
member->SetUnitMovementFlags(m_leader->GetUnitMovementFlags());
|
||||
// pussywizard: setting the same movementflags is not enough, spline decides whether leader walks/runs, so spline param is now passed as "run" parameter to this function
|
||||
if (run && member->IsWalking())
|
||||
{
|
||||
member->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING);
|
||||
}
|
||||
else if (!run && !member->IsWalking())
|
||||
{
|
||||
member->AddUnitMovementFlag(MOVEMENTFLAG_WALKING);
|
||||
}
|
||||
|
||||
// xinef: if we move members to position without taking care of sizes, we should compare distance without sizes
|
||||
// xinef: change members speed basing on distance - if too far speed up, if too close slow down
|
||||
UnitMoveType mtype = Movement::SelectSpeedType(member->GetUnitMovementFlags());
|
||||
float speedRate = m_leader->GetSpeedRate(mtype) * member->GetExactDist(dx, dy, dz) / pathDist;
|
||||
UnitMoveType const mtype = Movement::SelectSpeedType(member->GetUnitMovementFlags());
|
||||
float const speedRate = m_leader->GetSpeedRate(mtype) * member->GetExactDist(dx, dy, dz) / pathDist;
|
||||
|
||||
if (speedRate > 0.01f) // don't move if speed rate is too low
|
||||
{
|
||||
|
||||
@@ -15,17 +15,46 @@
|
||||
class Creature;
|
||||
class CreatureGroup;
|
||||
|
||||
enum class GroupAIFlags : uint16
|
||||
{
|
||||
GROUP_AI_FLAG_MEMBER_ASSIST_LEADER = 0x001,
|
||||
GROUP_AI_FLAG_LEADER_ASSIST_MEMBER = 0x002,
|
||||
//GROUP_AI_FLAG_UNK1 = 0x004,
|
||||
//GROUP_AI_FLAG_UNK2 = 0x008,
|
||||
//GROUP_AI_FLAG_UNK3 = 0x010,
|
||||
//GROUP_AI_FLAG_UNK4 = 0x020,
|
||||
//GROUP_AI_FLAG_UNK5 = 0x040,
|
||||
//GROUP_AI_FLAG_UNK6 = 0x080,
|
||||
//GROUP_AI_FLAG_UNK7 = 0x100,
|
||||
GROUP_AI_FLAG_FOLLOW_LEADER = 0x200,
|
||||
|
||||
// Used to verify valid and usable flags
|
||||
GROUP_AI_FLAG_SUPPORTED = GROUP_AI_FLAG_MEMBER_ASSIST_LEADER | GROUP_AI_FLAG_LEADER_ASSIST_MEMBER | GROUP_AI_FLAG_FOLLOW_LEADER
|
||||
};
|
||||
|
||||
struct FormationInfo
|
||||
{
|
||||
FormationInfo() :
|
||||
leaderGUID(0),
|
||||
follow_dist(0.0f),
|
||||
follow_angle(0.0f),
|
||||
groupAI(0),
|
||||
point_1(0),
|
||||
point_2(0)
|
||||
{
|
||||
}
|
||||
|
||||
ObjectGuid::LowType leaderGUID;
|
||||
float follow_dist;
|
||||
float follow_angle;
|
||||
uint8 groupAI;
|
||||
uint16 groupAI;
|
||||
uint32 point_1;
|
||||
uint32 point_2;
|
||||
|
||||
bool HasGroupFlag(uint16 flag) const { return !!(groupAI & flag); }
|
||||
};
|
||||
|
||||
typedef std::unordered_map<ObjectGuid::LowType/*memberDBGUID*/, FormationInfo*> CreatureGroupInfoType;
|
||||
typedef std::unordered_map<ObjectGuid::LowType/*memberDBGUID*/, FormationInfo /*formationInfo*/> CreatureGroupInfoType;
|
||||
|
||||
class FormationMgr
|
||||
{
|
||||
@@ -45,7 +74,7 @@ class CreatureGroup
|
||||
{
|
||||
public:
|
||||
// pussywizard: moved public to the top so it compiles and typedef is public
|
||||
typedef std::map<Creature*, FormationInfo*> CreatureGroupMemberType;
|
||||
typedef std::map<Creature*, FormationInfo> CreatureGroupMemberType;
|
||||
|
||||
//Group cannot be created empty
|
||||
explicit CreatureGroup(uint32 id) : m_leader(nullptr), m_groupID(id), m_Formed(false) {}
|
||||
|
||||
@@ -1474,13 +1474,11 @@ public:
|
||||
return false;
|
||||
|
||||
Player* chr = handler->GetSession()->GetPlayer();
|
||||
FormationInfo* group_member;
|
||||
|
||||
group_member = new FormationInfo;
|
||||
group_member->follow_angle = (creature->GetAngle(chr) - chr->GetOrientation()) * 180 / M_PI;
|
||||
group_member->follow_dist = sqrtf(pow(chr->GetPositionX() - creature->GetPositionX(), int(2)) + pow(chr->GetPositionY() - creature->GetPositionY(), int(2)));
|
||||
group_member->leaderGUID = leaderGUID;
|
||||
group_member->groupAI = 0;
|
||||
FormationInfo group_member;
|
||||
group_member.follow_angle = (creature->GetAngle(chr) - chr->GetOrientation()) * 180 / M_PI;
|
||||
group_member.follow_dist = sqrtf(pow(chr->GetPositionX() - creature->GetPositionX(), int(2)) + pow(chr->GetPositionY() - creature->GetPositionY(), int(2)));
|
||||
group_member.leaderGUID = leaderGUID;
|
||||
group_member.groupAI = 0;
|
||||
|
||||
sFormationMgr->CreatureGroupMap[lowguid] = group_member;
|
||||
creature->SearchFormation();
|
||||
@@ -1488,9 +1486,9 @@ public:
|
||||
WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_INS_CREATURE_FORMATION);
|
||||
stmt->setUInt32(0, leaderGUID);
|
||||
stmt->setUInt32(1, lowguid);
|
||||
stmt->setFloat(2, group_member->follow_dist);
|
||||
stmt->setFloat(3, group_member->follow_angle);
|
||||
stmt->setUInt32(4, uint32(group_member->groupAI));
|
||||
stmt->setFloat(2, group_member.follow_dist);
|
||||
stmt->setFloat(3, group_member.follow_angle);
|
||||
stmt->setUInt32(4, uint32(group_member.groupAI));
|
||||
|
||||
WorldDatabase.Execute(stmt);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user