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:
@@ -0,0 +1,17 @@
|
|||||||
|
INSERT INTO `version_db_world` (`sql_rev`) VALUES ('1631783274789936800');
|
||||||
|
|
||||||
|
-- Warning fixes
|
||||||
|
UPDATE creature_formations SET groupAI=groupAI|512 WHERE (angle > 0 OR dist > 0) AND leaderGUID != memberGUID and NOT (groupAI & 512);
|
||||||
|
update creature_formations set angle=0, dist=0 where leaderGUID=7209 and memberGUID=7209;
|
||||||
|
update creature_formations set angle=0, dist=0 where leaderGUID=37523 and memberGUID=37523;
|
||||||
|
update creature_formations set angle=0, dist=0 where leaderGUID=47613 and memberGUID=47613;
|
||||||
|
update creature_formations set angle=0, dist=0 where leaderGUID=79524 and memberGUID=79524;
|
||||||
|
update creature_formations set angle=0, dist=0 where leaderGUID=79720 and memberGUID=79720;
|
||||||
|
update creature_formations set angle=0, dist=0 where leaderGUID=80219 and memberGUID=80219;
|
||||||
|
update creature_formations set angle=0, dist=0 where leaderGUID=80235 and memberGUID=80235;
|
||||||
|
update creature_formations set angle=0, dist=0 where leaderGUID=134935 and memberGUID=134935;
|
||||||
|
update creature_formations set angle=0, dist=0 where leaderGUID=134944 and memberGUID=134944;
|
||||||
|
update creature_formations set angle=0, dist=0 where leaderGUID=134952 and memberGUID=134952;
|
||||||
|
update creature_formations set groupAI = 1 | 2 where leaderGUID=85221 and memberGUID=85221;
|
||||||
|
update creature_formations set groupAI = 1 | 2 where leaderGUID=114937 and memberGUID=114937;
|
||||||
|
update creature_formations set groupAI = 1 | 2 where leaderGUID=248035 and memberGUID != 248035;
|
||||||
@@ -270,15 +270,21 @@ void Creature::DisappearAndDie()
|
|||||||
void Creature::SearchFormation()
|
void Creature::SearchFormation()
|
||||||
{
|
{
|
||||||
if (IsSummon())
|
if (IsSummon())
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ObjectGuid::LowType spawnId = GetSpawnId();
|
ObjectGuid::LowType spawnId = GetSpawnId();
|
||||||
if (!spawnId)
|
if (!spawnId)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
CreatureGroupInfoType::iterator frmdata = sFormationMgr->CreatureGroupMap.find(spawnId);
|
CreatureGroupInfoType::const_iterator frmdata = sFormationMgr->CreatureGroupMap.find(spawnId);
|
||||||
if (frmdata != sFormationMgr->CreatureGroupMap.end())
|
if (frmdata != sFormationMgr->CreatureGroupMap.end())
|
||||||
sFormationMgr->AddCreatureToGroup(frmdata->second->leaderGUID, this);
|
{
|
||||||
|
sFormationMgr->AddCreatureToGroup(frmdata->second.leaderGUID, this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Creature::RemoveCorpse(bool setSpawnTime, bool skipVisibility)
|
void Creature::RemoveCorpse(bool setSpawnTime, bool skipVisibility)
|
||||||
|
|||||||
@@ -9,11 +9,10 @@
|
|||||||
#include "CreatureGroups.h"
|
#include "CreatureGroups.h"
|
||||||
#include "MoveSplineInit.h"
|
#include "MoveSplineInit.h"
|
||||||
#include "ObjectMgr.h"
|
#include "ObjectMgr.h"
|
||||||
|
#include "Log.h"
|
||||||
|
|
||||||
FormationMgr::~FormationMgr()
|
FormationMgr::~FormationMgr()
|
||||||
{
|
{
|
||||||
for (CreatureGroupInfoType::iterator itr = CreatureGroupMap.begin(); itr != CreatureGroupMap.end(); ++itr)
|
|
||||||
delete itr->second;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FormationMgr* FormationMgr::instance()
|
FormationMgr* FormationMgr::instance()
|
||||||
@@ -26,7 +25,9 @@ void FormationMgr::AddCreatureToGroup(uint32 groupId, Creature* member)
|
|||||||
{
|
{
|
||||||
Map* map = member->FindMap();
|
Map* map = member->FindMap();
|
||||||
if (!map)
|
if (!map)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
CreatureGroupHolderType::iterator itr = map->CreatureGroupHolder.find(groupId);
|
CreatureGroupHolderType::iterator itr = map->CreatureGroupHolder.find(groupId);
|
||||||
|
|
||||||
@@ -55,7 +56,9 @@ void FormationMgr::RemoveCreatureFromGroup(CreatureGroup* group, Creature* membe
|
|||||||
{
|
{
|
||||||
Map* map = member->FindMap();
|
Map* map = member->FindMap();
|
||||||
if (!map)
|
if (!map)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
LOG_DEBUG("entities.unit", "Deleting group with InstanceID %u", member->GetInstanceId());
|
LOG_DEBUG("entities.unit", "Deleting group with InstanceID %u", member->GetInstanceId());
|
||||||
map->CreatureGroupHolder.erase(group->GetId());
|
map->CreatureGroupHolder.erase(group->GetId());
|
||||||
@@ -65,15 +68,11 @@ void FormationMgr::RemoveCreatureFromGroup(CreatureGroup* group, Creature* membe
|
|||||||
|
|
||||||
void FormationMgr::LoadCreatureFormations()
|
void FormationMgr::LoadCreatureFormations()
|
||||||
{
|
{
|
||||||
uint32 oldMSTime = getMSTime();
|
uint32 const oldMSTime = getMSTime();
|
||||||
|
|
||||||
for (CreatureGroupInfoType::iterator itr = CreatureGroupMap.begin(); itr != CreatureGroupMap.end(); ++itr) // for reload case
|
|
||||||
delete itr->second;
|
|
||||||
CreatureGroupMap.clear();
|
CreatureGroupMap.clear();
|
||||||
|
|
||||||
//Get group data
|
//Get group data
|
||||||
QueryResult result = WorldDatabase.Query("SELECT leaderGUID, memberGUID, dist, angle, groupAI, point_1, point_2 FROM creature_formations ORDER BY leaderGUID");
|
QueryResult result = WorldDatabase.Query("SELECT leaderGUID, memberGUID, dist, angle, groupAI, point_1, point_2 FROM creature_formations ORDER BY leaderGUID");
|
||||||
|
|
||||||
if (!result)
|
if (!result)
|
||||||
{
|
{
|
||||||
LOG_ERROR("sql.sql", ">> Loaded 0 creatures in formations. DB table `creature_formations` is empty!");
|
LOG_ERROR("sql.sql", ">> Loaded 0 creatures in formations. DB table `creature_formations` is empty!");
|
||||||
@@ -82,48 +81,69 @@ void FormationMgr::LoadCreatureFormations()
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint32 count = 0;
|
uint32 count = 0;
|
||||||
Field* fields;
|
|
||||||
FormationInfo* group_member;
|
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
fields = result->Fetch();
|
Field const* fields = result->Fetch();
|
||||||
|
|
||||||
//Load group member data
|
//Load group member data
|
||||||
group_member = new FormationInfo();
|
FormationInfo group_member;
|
||||||
group_member->leaderGUID = fields[0].GetUInt32();
|
group_member.leaderGUID = fields[0].GetUInt32();
|
||||||
ObjectGuid::LowType memberGUID = fields[1].GetUInt32();
|
ObjectGuid::LowType const memberGUID = fields[1].GetUInt32();
|
||||||
group_member->groupAI = fields[4].GetUInt32();
|
float const follow_dist = fields[2].GetFloat();
|
||||||
group_member->point_1 = fields[5].GetUInt16();
|
float const follow_angle = fields[3].GetFloat() * static_cast<float>(M_PI) / 180;
|
||||||
group_member->point_2 = fields[6].GetUInt16();
|
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 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();
|
if (!group_member.HasGroupFlag(std::underlying_type_t<GroupAIFlags>(GroupAIFlags::GROUP_AI_FLAG_SUPPORTED)))
|
||||||
group_member->follow_angle = fields[3].GetFloat() * M_PI / 180;
|
{
|
||||||
|
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
|
else
|
||||||
{
|
{
|
||||||
group_member->follow_dist = 0;
|
group_member.follow_dist = follow_dist;
|
||||||
group_member->follow_angle = 0;
|
group_member.follow_angle = follow_angle * static_cast<float>(M_PI) / 180;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check data correctness
|
group_member.follow_dist = 0.0f;
|
||||||
|
group_member.follow_angle = 0.0f;
|
||||||
|
if (follow_dist > 0.0f || follow_angle > 0.0f)
|
||||||
{
|
{
|
||||||
if (!sObjectMgr->GetCreatureData(group_member->leaderGUID))
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sObjectMgr->GetCreatureData(group_member.leaderGUID))
|
||||||
{
|
{
|
||||||
LOG_ERROR("sql.sql", "creature_formations table leader guid %u incorrect (not exist)", group_member->leaderGUID);
|
LOG_ERROR("sql.sql", "creature_formations table leader guid %u incorrect (does not exist). Skipped", group_member.leaderGUID);
|
||||||
delete group_member;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sObjectMgr->GetCreatureData(memberGUID))
|
if (!sObjectMgr->GetCreatureData(memberGUID))
|
||||||
{
|
{
|
||||||
LOG_ERROR("sql.sql", "creature_formations table member guid %u incorrect (not exist)", memberGUID);
|
LOG_ERROR("sql.sql", "creature_formations table member guid %u incorrect (does not exist). Skipped", memberGUID);
|
||||||
delete group_member;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
CreatureGroupMap[memberGUID] = group_member;
|
CreatureGroupMap[memberGUID] = group_member;
|
||||||
++count;
|
++count;
|
||||||
@@ -151,7 +171,9 @@ void CreatureGroup::AddMember(Creature* member)
|
|||||||
void CreatureGroup::RemoveMember(Creature* member)
|
void CreatureGroup::RemoveMember(Creature* member)
|
||||||
{
|
{
|
||||||
if (m_leader == member)
|
if (m_leader == member)
|
||||||
|
{
|
||||||
m_leader = nullptr;
|
m_leader = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
m_members.erase(member);
|
m_members.erase(member);
|
||||||
member->SetFormation(nullptr);
|
member->SetFormation(nullptr);
|
||||||
@@ -159,53 +181,63 @@ void CreatureGroup::RemoveMember(Creature* member)
|
|||||||
|
|
||||||
void CreatureGroup::MemberAttackStart(Creature* member, Unit* target)
|
void CreatureGroup::MemberAttackStart(Creature* member, Unit* target)
|
||||||
{
|
{
|
||||||
uint8 groupAI = sFormationMgr->CreatureGroupMap[member->GetSpawnId()]->groupAI;
|
uint8 const groupAI = sFormationMgr->CreatureGroupMap[member->GetSpawnId()].groupAI;
|
||||||
if (!groupAI)
|
if (member == m_leader)
|
||||||
return;
|
|
||||||
|
|
||||||
if (groupAI == 1 && member != m_leader)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (CreatureGroupMemberType::iterator itr = m_members.begin(); itr != m_members.end(); ++itr)
|
|
||||||
{
|
{
|
||||||
|
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.
|
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());
|
LOG_DEBUG("entities.unit", "GROUP ATTACK: group instance id %u calls member instid %u", m_leader->GetInstanceId(), member->GetInstanceId());
|
||||||
|
|
||||||
//Skip one check
|
//Skip one check
|
||||||
if (itr->first == member)
|
if (pMember == member)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!itr->first->IsAlive())
|
if (!pMember->IsAlive())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (itr->first->GetVictim())
|
if (pMember->GetVictim())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (itr->first->IsValidAttackTarget(target) && itr->first->AI())
|
if (pMember->IsValidAttackTarget(target) && pMember->AI())
|
||||||
itr->first->AI()->AttackStart(target);
|
pMember->AI()->AttackStart(target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreatureGroup::FormationReset(bool dismiss, bool initMotionMaster)
|
void CreatureGroup::FormationReset(bool dismiss, bool initMotionMaster)
|
||||||
{
|
{
|
||||||
if (m_members.size() && m_members.begin()->second->groupAI == 5)
|
if (m_members.size() && !(m_members.begin()->second.HasGroupFlag(std::underlying_type_t<GroupAIFlags>(GroupAIFlags::GROUP_AI_FLAG_FOLLOW_LEADER))))
|
||||||
return;
|
|
||||||
|
|
||||||
for (CreatureGroupMemberType::iterator itr = m_members.begin(); itr != m_members.end(); ++itr)
|
|
||||||
{
|
{
|
||||||
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 (initMotionMaster)
|
||||||
{
|
{
|
||||||
if (dismiss)
|
if (dismiss)
|
||||||
{
|
{
|
||||||
itr->first->GetMotionMaster()->Initialize();
|
member->GetMotionMaster()->Initialize();
|
||||||
}
|
}
|
||||||
else
|
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.
|
//! 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 the leader's path is known, member's path can be plotted as well using formation offsets.
|
||||||
if (!m_leader)
|
if (!m_leader)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
uint8 groupAI = sFormationMgr->CreatureGroupMap[m_leader->GetSpawnId()]->groupAI;
|
|
||||||
if (groupAI == 5)
|
|
||||||
return;
|
|
||||||
|
|
||||||
float pathDist = m_leader->GetExactDist(x, y, z);
|
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;
|
||||||
|
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)))
|
||||||
{
|
{
|
||||||
Creature* member = itr->first;
|
|
||||||
if (member == m_leader || !member->IsAlive() || member->GetVictim())
|
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Xinef: If member is stunned / rooted etc don't allow to move him
|
// Xinef: If member is stunned / rooted etc don't allow to move him
|
||||||
if (member->HasUnitState(UNIT_STATE_NOT_MOVE))
|
if (member->HasUnitState(UNIT_STATE_NOT_MOVE))
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Xinef: this should be automatized, if turn angle is greater than PI/2 (90�) we should swap formation angle
|
// Xinef: this should be automatized, if turn angle is greater than PI/2 (90�) 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: 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: 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!
|
// 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)
|
// if (m_leader->GetCurrentWaypointID()+1 == pFormationInfo->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;
|
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 const followDist = pFormationInfo.follow_dist;
|
||||||
float followDist = itr->second->follow_dist;
|
|
||||||
|
|
||||||
float dx = x + cos(followAngle + pathAngle) * followDist;
|
float dx = x + std::cos(followAngle + pathAngle) * followDist;
|
||||||
float dy = y + sin(followAngle + pathAngle) * followDist;
|
float dy = y + std::sin(followAngle + pathAngle) * followDist;
|
||||||
float dz = z;
|
float dz = z;
|
||||||
|
|
||||||
Acore::NormalizeMapCoord(dx);
|
Acore::NormalizeMapCoord(dx);
|
||||||
Acore::NormalizeMapCoord(dy);
|
Acore::NormalizeMapCoord(dy);
|
||||||
|
|
||||||
member->UpdateGroundPositionZ(dx, dy, dz);
|
member->UpdateGroundPositionZ(dx, dy, dz);
|
||||||
|
|
||||||
member->SetUnitMovementFlags(m_leader->GetUnitMovementFlags());
|
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
|
// 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())
|
if (run && member->IsWalking())
|
||||||
|
{
|
||||||
member->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING);
|
member->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING);
|
||||||
|
}
|
||||||
else if (!run && !member->IsWalking())
|
else if (!run && !member->IsWalking())
|
||||||
|
{
|
||||||
member->AddUnitMovementFlag(MOVEMENTFLAG_WALKING);
|
member->AddUnitMovementFlag(MOVEMENTFLAG_WALKING);
|
||||||
|
}
|
||||||
|
|
||||||
// xinef: if we move members to position without taking care of sizes, we should compare distance without sizes
|
// 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
|
// xinef: change members speed basing on distance - if too far speed up, if too close slow down
|
||||||
UnitMoveType mtype = Movement::SelectSpeedType(member->GetUnitMovementFlags());
|
UnitMoveType const mtype = Movement::SelectSpeedType(member->GetUnitMovementFlags());
|
||||||
float speedRate = m_leader->GetSpeedRate(mtype) * member->GetExactDist(dx, dy, dz) / pathDist;
|
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
|
if (speedRate > 0.01f) // don't move if speed rate is too low
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -15,17 +15,46 @@
|
|||||||
class Creature;
|
class Creature;
|
||||||
class CreatureGroup;
|
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
|
struct FormationInfo
|
||||||
{
|
{
|
||||||
|
FormationInfo() :
|
||||||
|
leaderGUID(0),
|
||||||
|
follow_dist(0.0f),
|
||||||
|
follow_angle(0.0f),
|
||||||
|
groupAI(0),
|
||||||
|
point_1(0),
|
||||||
|
point_2(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
ObjectGuid::LowType leaderGUID;
|
ObjectGuid::LowType leaderGUID;
|
||||||
float follow_dist;
|
float follow_dist;
|
||||||
float follow_angle;
|
float follow_angle;
|
||||||
uint8 groupAI;
|
uint16 groupAI;
|
||||||
uint32 point_1;
|
uint32 point_1;
|
||||||
uint32 point_2;
|
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
|
class FormationMgr
|
||||||
{
|
{
|
||||||
@@ -45,7 +74,7 @@ class CreatureGroup
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// pussywizard: moved public to the top so it compiles and typedef is 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
|
//Group cannot be created empty
|
||||||
explicit CreatureGroup(uint32 id) : m_leader(nullptr), m_groupID(id), m_Formed(false) {}
|
explicit CreatureGroup(uint32 id) : m_leader(nullptr), m_groupID(id), m_Formed(false) {}
|
||||||
|
|||||||
@@ -1474,13 +1474,11 @@ public:
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
Player* chr = handler->GetSession()->GetPlayer();
|
Player* chr = handler->GetSession()->GetPlayer();
|
||||||
FormationInfo* group_member;
|
FormationInfo group_member;
|
||||||
|
group_member.follow_angle = (creature->GetAngle(chr) - chr->GetOrientation()) * 180 / M_PI;
|
||||||
group_member = new FormationInfo;
|
group_member.follow_dist = sqrtf(pow(chr->GetPositionX() - creature->GetPositionX(), int(2)) + pow(chr->GetPositionY() - creature->GetPositionY(), int(2)));
|
||||||
group_member->follow_angle = (creature->GetAngle(chr) - chr->GetOrientation()) * 180 / M_PI;
|
group_member.leaderGUID = leaderGUID;
|
||||||
group_member->follow_dist = sqrtf(pow(chr->GetPositionX() - creature->GetPositionX(), int(2)) + pow(chr->GetPositionY() - creature->GetPositionY(), int(2)));
|
group_member.groupAI = 0;
|
||||||
group_member->leaderGUID = leaderGUID;
|
|
||||||
group_member->groupAI = 0;
|
|
||||||
|
|
||||||
sFormationMgr->CreatureGroupMap[lowguid] = group_member;
|
sFormationMgr->CreatureGroupMap[lowguid] = group_member;
|
||||||
creature->SearchFormation();
|
creature->SearchFormation();
|
||||||
@@ -1488,9 +1486,9 @@ public:
|
|||||||
WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_INS_CREATURE_FORMATION);
|
WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_INS_CREATURE_FORMATION);
|
||||||
stmt->setUInt32(0, leaderGUID);
|
stmt->setUInt32(0, leaderGUID);
|
||||||
stmt->setUInt32(1, lowguid);
|
stmt->setUInt32(1, lowguid);
|
||||||
stmt->setFloat(2, group_member->follow_dist);
|
stmt->setFloat(2, group_member.follow_dist);
|
||||||
stmt->setFloat(3, group_member->follow_angle);
|
stmt->setFloat(3, group_member.follow_angle);
|
||||||
stmt->setUInt32(4, uint32(group_member->groupAI));
|
stmt->setUInt32(4, uint32(group_member.groupAI));
|
||||||
|
|
||||||
WorldDatabase.Execute(stmt);
|
WorldDatabase.Execute(stmt);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user