OregonCore  revision fb2a440-git
Your Favourite TBC server
CreatureGroups.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of the OregonCore Project. See AUTHORS file for Copyright information
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License as published by the
6  * Free Software Foundation; either version 2 of the License, or (at your
7  * option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12  * more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "Creature.h"
19 #include "CreatureGroups.h"
20 #include "ObjectMgr.h"
21 
22 #include "CreatureAI.h"
23 
24 #define MAX_DESYNC 5.0f
25 
27 
29 {
30  for (CreatureGroupInfoType::iterator itr = CreatureGroupMap.begin(); itr != CreatureGroupMap.end(); ++itr)
31  delete itr->second;
32 }
33 
35 {
36  Map* map = creature->FindMap();
37  if (!map)
38  return;
39 
40  CreatureGroupHolderType::iterator itr = map->CreatureGroupHolder.find(leaderGuid);
41 
42  //Add member to an existing group
43  if (itr != map->CreatureGroupHolder.end())
44  {
45  sLog.outDebug("Group found: %u, inserting creature GUID: %u, Group InstanceID %u", leaderGuid, creature->GetGUIDLow(), creature->GetInstanceId());
46  itr->second->AddMember(creature);
47  }
48  //Create new group
49  else
50  {
51  sLog.outDebug("Group not found: %u. Creating new group.", leaderGuid);
52  CreatureGroup* group = new CreatureGroup(leaderGuid);
53  map->CreatureGroupHolder[leaderGuid] = group;
54  group->AddMember(creature);
55  }
56 }
57 
59 {
60  sLog.outDebug("Deleting member pointer to GUID: %u from group %u", group->GetId(), member->GetDBTableGUIDLow());
61  group->RemoveMember(member);
62 
63  if (group->isEmpty())
64  {
65  Map* map = member->FindMap();
66  if (!map)
67  return;
68 
69  sLog.outDebug("Deleting group with InstanceID %u", member->GetInstanceId());
70  map->CreatureGroupHolder.erase(group->GetId());
71  delete group;
72  }
73 }
74 
76 {
77  //Clear existing map
78  for (CreatureGroupInfoType::iterator itr = CreatureGroupMap.begin(); itr != CreatureGroupMap.end(); ++itr) // for reload case
79  delete itr->second;
80  CreatureGroupMap.clear();
81 
82  //Get group data
83  QueryResult_AutoPtr result = WorldDatabase.Query("SELECT leaderGUID, memberGUID, dist, angle, groupAI, point_1, point_2 FROM creature_formations ORDER BY leaderGUID");
84 
85  if (!result)
86  {
87  sLog.outError(">> Loaded 0 creatures in formations. DB table `creature_formations` is empty!");
88  return;
89  }
90 
91  uint32 count = 0;
92  Field* fields;
93  FormationInfo* group_member;
94 
95  //Loading data...
96  do
97  {
98  fields = result->Fetch();
99 
100  //Load group member data
101  group_member = new FormationInfo;
102  group_member->leaderGUID = fields[0].GetUInt32();
103  uint32 memberGUID = fields[1].GetUInt32();
104  group_member->groupAI = fields[4].GetUInt32();
105  group_member->point_1 = fields[5].GetUInt16();
106  group_member->point_2 = fields[6].GetUInt16();
107  //If creature is group leader we may skip loading of dist/angle
108  if (group_member->leaderGUID != memberGUID)
109  {
110  group_member->follow_dist = fields[2].GetFloat();
111  group_member->follow_angle = fields[3].GetFloat() * float(M_PI) / 180;
112  }
113  else
114  {
115  group_member->follow_dist = 0;
116  group_member->follow_angle = 0;
117  }
118 
119  // check data correctness
120  {
121  if (!sObjectMgr.GetCreatureData(group_member->leaderGUID))
122  {
123  sLog.outErrorDb("creature_formations table leader guid %u incorrect (not exist)", group_member->leaderGUID);
124  delete group_member;
125  continue;
126  }
127 
128  if (!sObjectMgr.GetCreatureData(memberGUID))
129  {
130  sLog.outErrorDb("creature_formations table member guid %u incorrect (not exist)", memberGUID);
131  delete group_member;
132  continue;
133  }
134  }
135 
136  CreatureGroupMap[memberGUID] = group_member;
137  ++count;
138  }
139  while (result->NextRow());
140 
141  sLog.outString(">> Loaded %u creatures in formations", count);
142 }
143 
145 {
146  sLog.outDebug("CreatureGroup::AddMember: Adding unit GUID: %u.", member->GetGUIDLow());
147 
148  //Check if it is a leader
149  if (member->GetDBTableGUIDLow() == m_groupID)
150  {
151  sLog.outDebug("Unit GUID: %u is formation leader. Adding group.", member->GetGUIDLow());
152  m_leader = member;
153  }
154 
155  m_members[member] = sFormationMgr.CreatureGroupMap.find(member->GetDBTableGUIDLow())->second;
156  member->SetFormation(this);
157 }
158 
160 {
161  if (m_leader == member)
162  m_leader = NULL;
163 
164  m_members.erase(member);
165  member->SetFormation(NULL);
166 }
167 
169 {
170  uint8 groupAI = sFormationMgr.CreatureGroupMap[member->GetDBTableGUIDLow()]->groupAI;
171  if (!groupAI)
172  return;
173 
174  if (member == m_leader)
175  {
176  if (!(groupAI & FLAG_MEMBERS_ASSIST_LEADER))
177  return;
178  }
179  else if (!(groupAI & FLAG_LEADER_ASSISTS_MEMBER))
180  return;
181 
182  for (CreatureGroupMemberType::iterator itr = m_members.begin(); itr != m_members.end(); ++itr)
183  {
184  if (m_leader) // avoid crash if leader was killed and reset.
185  sLog.outDebug("GROUP ATTACK: group instance id %u calls member instid %u", m_leader->GetInstanceId(), member->GetInstanceId());
186 
187  Creature* other = itr->first;
188 
189  // Skip self
190  if (other == member)
191  continue;
192 
193  if (!other->IsAlive())
194  continue;
195 
196  if (other->GetVictim())
197  continue;
198 
199  if (((other != m_leader && (groupAI & FLAG_MEMBERS_ASSIST_LEADER)) || (other == m_leader && (groupAI & FLAG_LEADER_ASSISTS_MEMBER))) && other->IsValidAttackTarget(target))
200  other->AI()->AttackStart(target);
201  }
202 }
203 
205 {
206  for (CreatureGroupMemberType::iterator itr = m_members.begin(); itr != m_members.end(); ++itr)
207  {
208  if (itr->first != m_leader && itr->first->IsAlive())
209  {
210  if (dismiss)
211  itr->first->GetMotionMaster()->Initialize();
212  else
213  itr->first->GetMotionMaster()->MoveIdle();
214  sLog.outError("Set %s movement for member GUID: %u", dismiss ? "default" : "idle", itr->first->GetGUIDLow());
215  }
216  }
217  m_Formed = !dismiss;
218 }
219 
220 void CreatureGroup::LeaderMoveTo(float x, float y, float z)
221 {
224  if (!m_leader)
225  return;
226 
227  float pathangle = std::atan2(m_leader->GetPositionY() - y, m_leader->GetPositionX() - x);
228 
229  for (CreatureGroupMemberType::iterator itr = m_members.begin(); itr != m_members.end(); ++itr)
230  {
231  Creature* member = itr->first;
232  if (member == m_leader || !member->IsAlive() || member->IsInCombat() || !(itr->second->groupAI & FLAG_IDLE_IN_FORMATION))
233  continue;
234 
235  if (itr->second->point_1)
236  if (m_leader->GetCurrentWaypointID() == itr->second->point_1 - 1 || m_leader->GetCurrentWaypointID() == itr->second->point_2 - 1)
237  itr->second->follow_angle = float(M_PI) * 2 - itr->second->follow_angle;
238 
239  float angle = itr->second->follow_angle;
240  float dist = itr->second->follow_dist;
241 
242  float dx = x + std::cos(angle + pathangle) * dist;
243  float dy = y + std::sin(angle + pathangle) * dist;
244  float dz = z;
245 
248 
249  if (!member->IsFlying())
250  member->UpdateGroundPositionZ(dx, dy, dz);
251 
252  if (member->IsWithinDist(m_leader, dist + MAX_DESYNC))
253  member->SetUnitMovementFlags(m_leader->GetUnitMovementFlags());
254  else
255  member->SetWalk(false);
256 
257  member->GetMotionMaster()->MovePoint(0, dx, dy, dz);
258  member->SetHomePosition(dx, dy, dz, pathangle);
259  }
260 }
261 
CreatureGroupInfoType CreatureGroupMap
void AddCreatureToGroup(uint32 group_id, Creature *creature)
bool SetWalk(bool enable) override
Definition: Creature.cpp:2528
void AddMember(Creature *member)
bool IsFlying() const
Definition: Unit.h:1973
DatabaseType WorldDatabase
Accessor to the world database.
Definition: Main.cpp:53
uint32 GetDBTableGUIDLow() const
Definition: Creature.h:476
void MemberAttackStart(Creature *member, Unit *target)
Definition: Field.h:24
MotionMaster * GetMotionMaster()
Definition: Unit.h:1890
bool IsInCombat() const
Definition: Unit.h:1243
void RemoveMember(Creature *member)
bool IsValidAttackTarget(Unit const *target) const
Definition: Unit.cpp:9510
#define sLog
Log class singleton.
Definition: Log.h:187
void SetFormation(CreatureGroup *formation)
Definition: Creature.h:764
QueryResult_AutoPtr Query(const char *sql)
Definition: Database.cpp:383
void SetHomePosition(float x, float y, float z, float o)
Definition: Creature.h:719
void MovePoint(uint32 id, const Position &pos, bool usePathfinding=true)
Definition: MotionMaster.h:179
uint32 GetGUIDLow() const
Definition: Object.h:166
#define sObjectMgr
Definition: ObjectMgr.h:1285
#define MAX_DESYNC
bool IsWithinDist(WorldObject const *obj, float dist2compare, bool is3D=true) const
Definition: Object.h:770
uint32 GetId() const
ACE_UINT8 uint8
Definition: Define.h:73
void LoadCreatureFormations()
Map * FindMap() const
Definition: Object.h:842
bool IsAlive() const
Definition: Unit.h:1336
Unit * GetVictim() const
Definition: Unit.h:1013
CreatureAI * AI() const
Definition: Creature.h:517
CreatureGroupHolderType CreatureGroupHolder
Definition: Map.h:522
uint32 GetInstanceId() const
Definition: Object.h:688
void SetUnitMovementFlags(uint32 f)
Definition: Unit.h:1905
Definition: Map.h:266
ACE_Refcounted_Auto_Ptr< QueryResult, ACE_Null_Mutex > QueryResult_AutoPtr
Definition: QueryResult.h:113
#define sFormationMgr
INSTANTIATE_SINGLETON_1(FormationMgr)
ACE_UINT32 uint32
Definition: Define.h:71
void RemoveCreatureFromGroup(CreatureGroup *group, Creature *creature)
void LeaderMoveTo(float x, float y, float z)
Definition: Unit.h:908
virtual void AttackStart(Unit *)
Definition: UnitAI.cpp:25
bool isEmpty() const
void FormationReset(bool dismiss)
void UpdateGroundPositionZ(float x, float y, float &z) const
Definition: Object.cpp:1483
void NormalizeMapCoord(float &c)
Definition: GridDefines.h:184