Skip to content

Instantly share code, notes, and snippets.

@DDuarte
Created July 4, 2011 03:28
Show Gist options
  • Save DDuarte/1062871 to your computer and use it in GitHub Desktop.
Save DDuarte/1062871 to your computer and use it in GitHub Desktop.
From 45893c65965d2d52cd16fbfa8306d7feb955e79b Mon Sep 17 00:00:00 2001
From: [M]axx <19Maxx83@googlemail.com>
Date: Wed, 5 Jan 2011 14:06:14 +0100
Subject: [PATCH] * Rename CreatureGroups to CreatureFormation
** Rewrite CreatureFormation System to new Databasetablelayout
** Little fix for .npc addformation angle calculation
* Implement CreatureGroup System to Core
** You could now bind some Creatures together to get "real" Packs like on Officials
** groupType = 0 -> Groups could be killed without respawn after Wipe (Blizzlike in Dungeons)
** groupType = 1 -> Groups respawn if atleast one Member is alive after Wipe (Blizzlike in most Raid Instances)
* All SQL Querys done as Prepared Statement
* Uses new Command Script System
* Patch is done by [M]axx with minor changes done by Dark0r
Important:
execute the sql files in this order
* 10931_world_creature_formation.sql
* 10931_world_creature_groups.sql
* 10931_world_creature_group_data.sql
* 10931_world_command.sql
Signed-off-by: [M]axx <19Maxx83@googlemail.com>
---
sql/updates/10931_world_command.sql | 7 +
sql/updates/10931_world_creature_formations.sql | 22 ++
sql/updates/10931_world_creature_group_data.sql | 6 +
sql/updates/10931_world_creature_groups.sql | 8 +
src/server/game/Entities/Creature/Creature.cpp | 36 ++-
src/server/game/Entities/Creature/Creature.h | 13 +-
.../game/Entities/Creature/CreatureFormations.cpp | 332 ++++++++++++++++++++
.../game/Entities/Creature/CreatureFormations.h | 93 ++++++
.../game/Entities/Creature/CreatureGroups.cpp | 228 +++++++-------
src/server/game/Entities/Creature/CreatureGroups.h | 29 +-
src/server/game/Entities/Unit/Unit.cpp | 4 +
src/server/game/Maps/Map.h | 5 +-
.../MovementGenerators/RandomMovementGenerator.cpp | 2 +-
.../WaypointMovementGenerator.cpp | 2 +-
src/server/game/World/World.cpp | 4 +
src/server/scripts/Commands/cs_npc.cpp | 236 +++++++++++++-
.../Database/Implementation/WorldDatabase.cpp | 20 ++
.../shared/Database/Implementation/WorldDatabase.h | 17 +
18 files changed, 909 insertions(+), 155 deletions(-)
create mode 100644 sql/updates/10931_world_command.sql
create mode 100644 sql/updates/10931_world_creature_formations.sql
create mode 100644 sql/updates/10931_world_creature_group_data.sql
create mode 100644 sql/updates/10931_world_creature_groups.sql
create mode 100644 src/server/game/Entities/Creature/CreatureFormations.cpp
create mode 100644 src/server/game/Entities/Creature/CreatureFormations.h
diff --git a/sql/updates/10931_world_command.sql b/sql/updates/10931_world_command.sql
new file mode 100644
index 0000000..6650e7e
--- /dev/null
+++ b/sql/updates/10931_world_command.sql
@@ -0,0 +1,7 @@
+DELETE FROM `command` WHERE `name`='npc add group';
+INSERT INTO `command` (`name`, `security`, `help`) VALUES
+('npc add group', 1, 'Syntax: .npc add group $leader $comment $groupType\r\nAdd selected creature to a leader\'s group with groupType.\r\nYou could also add a comment...');
+
+DELETE FROM `command` WHERE `name`='npc add formation';
+INSERT INTO `command` (`name`, `security`, `help`) VALUES
+('npc add formation', 1, 'Syntax: .npc add formation $leader $comment $formationAI\r\nAdd selected creature to a leader\'s formation with formationAI.\r\nYou could also add a comment...');
\ No newline at end of file
diff --git a/sql/updates/10931_world_creature_formations.sql b/sql/updates/10931_world_creature_formations.sql
new file mode 100644
index 0000000..c0f410b
--- /dev/null
+++ b/sql/updates/10931_world_creature_formations.sql
@@ -0,0 +1,22 @@
+ALTER TABLE `creature_formations` CHANGE `groupAI` `formationAI` int(11);
+ALTER TABLE `creature_formations` RENAME `creature_formations_old`;
+DROP TABLE IF EXISTS `creature_formations`;
+CREATE TABLE `creature_formations` (
+ `formationId` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Formation Unique Identifier',
+ `leaderGUID` int(11) unsigned NOT NULL COMMENT 'Formation Leader Creature',
+ `formationAI` int(11) DEFAULT NULL COMMENT 'Formation AI',
+ `comment` varchar(255) DEFAULT NULL,
+ PRIMARY KEY (`formationId`,`leaderGUID`)
+) ENGINE=MyISAM AUTO_INCREMENT=0 DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC COMMENT='Creature Formation System';
+INSERT INTO `creature_formations` (`leaderGUID`,`formationAI`) SELECT `leaderGUID`, `formationAI` FROM `creature_formations_old` WHERE `memberGUID` = `leaderGUID`;
+DROP TABLE IF EXISTS `creature_formation_data`;
+CREATE TABLE `creature_formation_data` (
+ `formationId` int(10) unsigned NOT NULL COMMENT 'Formation Unique Identifier',
+ `memberGUID` int(11) unsigned NOT NULL COMMENT 'Formation Member Creature',
+ `dist` float unsigned NOT NULL COMMENT 'Formation Member Distance to Leader',
+ `angle` float unsigned NOT NULL COMMENT 'Formation Member Angle to Leader',
+ PRIMARY KEY (`memberGUID`)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC COMMENT='Creature Formation System';
+INSERT INTO `creature_formation_data` (`formationId`, `memberGUID`, `dist`, `angle`)
+SELECT cf.`formationId`, cfo.`memberGUID`, cfo.`dist`, cfo.`angle` FROM `creature_formations` cf LEFT JOIN `creature_formations_old` cfo ON cf.`leaderGUID` = cfo.`leaderGUID`;
+DROP TABLE IF EXISTS `creature_formations_old`;
\ No newline at end of file
diff --git a/sql/updates/10931_world_creature_group_data.sql b/sql/updates/10931_world_creature_group_data.sql
new file mode 100644
index 0000000..62a4b46
--- /dev/null
+++ b/sql/updates/10931_world_creature_group_data.sql
@@ -0,0 +1,6 @@
+DROP TABLE IF EXISTS `creature_group_data`;
+CREATE TABLE `creature_group_data` (
+ `groupId` int(10) unsigned NOT NULL,
+ `memberGUID` int(10) unsigned NOT NULL,
+ PRIMARY KEY (`memberGUID`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
\ No newline at end of file
diff --git a/sql/updates/10931_world_creature_groups.sql b/sql/updates/10931_world_creature_groups.sql
new file mode 100644
index 0000000..e5b5717
--- /dev/null
+++ b/sql/updates/10931_world_creature_groups.sql
@@ -0,0 +1,8 @@
+DROP TABLE IF EXISTS `creature_groups`;
+CREATE TABLE `creature_groups` (
+ `groupId` int(10) unsigned NOT NULL auto_increment,
+ `leaderGUID` int(10) unsigned NOT NULL,
+ `groupType` int(11) default NULL,
+ `comment` varchar(255) default NULL,
+ PRIMARY KEY (`groupId`,`leaderGUID`)
+) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
\ No newline at end of file
diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp
index 13e3234..f864a12 100755
--- a/src/server/game/Entities/Creature/Creature.cpp
+++ b/src/server/game/Entities/Creature/Creature.cpp
@@ -43,6 +43,7 @@
#include "CellImpl.h"
#include "OutdoorPvPMgr.h"
#include "GameEventMgr.h"
+#include "CreatureFormations.h"
#include "CreatureGroups.h"
#include "Vehicle.h"
#include "SpellAuraEffects.h"
@@ -144,7 +145,7 @@ m_respawnDelay(300), m_corpseDelay(60), m_respawnradius(0.0f), m_reactState(REAC
m_defaultMovementType(IDLE_MOTION_TYPE), m_DBTableGuid(0), m_equipmentId(0), m_AlreadyCallAssistance(false),
m_AlreadySearchedAssistance(false), m_regenHealth(true), m_AI_locked(false), m_isDeadByDefault(false),
m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL), m_creatureInfo(NULL), m_creatureData(NULL),
-m_formation(NULL)
+m_formation(NULL), m_group(NULL)
{
m_regenTimer = CREATURE_REGEN_INTERVAL;
m_valuesCount = UNIT_END;
@@ -186,6 +187,7 @@ void Creature::AddToWorld()
sObjectAccessor->AddObject(this);
Unit::AddToWorld();
SearchFormation();
+ SearchGroup();
AIM_Initialize();
if (IsVehicle())
GetVehicleKit()->Install();
@@ -199,7 +201,7 @@ void Creature::RemoveFromWorld()
if (m_zoneScript)
m_zoneScript->OnCreatureRemove(this);
if (m_formation)
- sFormationMgr->RemoveCreatureFromGroup(m_formation, this);
+ sFormationMgr->RemoveCreatureFromFormation(m_formation, this);
Unit::RemoveFromWorld();
sObjectAccessor->RemoveObject(this);
}
@@ -224,9 +226,23 @@ void Creature::SearchFormation()
if (!lowguid)
return;
- CreatureGroupInfoType::iterator frmdata = CreatureGroupMap.find(lowguid);
- if (frmdata != CreatureGroupMap.end())
- sFormationMgr->AddCreatureToGroup(frmdata->second->leaderGUID, this);
+ CreatureFormationDataType::iterator frmdata = CreatureFormationDataMap.find(lowguid);
+ if (frmdata != CreatureFormationDataMap.end())
+ sFormationMgr->AddCreatureToFormation(frmdata->second->formationId, this);
+}
+
+void Creature::SearchGroup()
+{
+ if (isSummon())
+ return;
+
+ uint32 lowguid = GetDBTableGUIDLow();
+ if (!lowguid)
+ return;
+
+ CreatureGroupDataType::iterator grpdata = CreatureGroupDataMap.find(lowguid);
+ if (grpdata != CreatureGroupDataMap.end())
+ sGroupMgr->AddCreatureToGroup(grpdata->second, this);
}
void Creature::RemoveCorpse(bool setSpawnTime)
@@ -234,6 +250,12 @@ void Creature::RemoveCorpse(bool setSpawnTime)
if ((getDeathState() != CORPSE && !m_isDeadByDefault) || (getDeathState() != ALIVE && m_isDeadByDefault))
return;
+ if (GetGroup() && GetGroup()->IsAllowedToRespawn(this))
+ {
+ Respawn();
+ return;
+ }
+
m_corpseRemoveTime = time(NULL);
setDeathState(DEAD);
UpdateObjectVisibility();
@@ -733,7 +755,7 @@ void Creature::Motion_Initialize()
i_motionMaster.Initialize();
else if (m_formation->getLeader() == this)
{
- m_formation->FormationReset(false);
+ m_formation->Reset(false);
i_motionMaster.Initialize();
}
else if (m_formation->isFormed())
@@ -1523,7 +1545,7 @@ void Creature::setDeathState(DeathState s)
//Dismiss group if is leader
if (m_formation && m_formation->getLeader() == this)
- m_formation->FormationReset(true);
+ m_formation->Reset(true);
if ((canFly() || IsFlying()) && FallGround())
return;
diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h
index 5794167..f43b06c 100755
--- a/src/server/game/Entities/Creature/Creature.h
+++ b/src/server/game/Entities/Creature/Creature.h
@@ -35,6 +35,7 @@ class CreatureAI;
class Quest;
class Player;
class WorldSession;
+class CreatureFormation;
class CreatureGroup;
enum CreatureFlagsExtra
@@ -644,8 +645,12 @@ class Creature : public Unit, public GridObject<Creature>
void UpdateWaypointID(uint32 wpID){m_waypointID = wpID;}
void SearchFormation();
- CreatureGroup *GetFormation() {return m_formation;}
- void SetFormation(CreatureGroup *formation) {m_formation = formation;}
+ CreatureFormation *GetFormation() {return m_formation;}
+ void SetFormation(CreatureFormation *formation) {m_formation = formation;}
+
+ void SearchGroup();
+ CreatureGroup *GetGroup() {return m_group;}
+ void SetGroup(CreatureGroup *group) {m_group = group;}
Unit *SelectVictim();
void SetDeadByDefault (bool death_state) {m_isDeadByDefault = death_state;}
@@ -728,7 +733,9 @@ class Creature : public Unit, public GridObject<Creature>
uint32 m_path_id;
//Formation var
- CreatureGroup *m_formation;
+ CreatureFormation *m_formation;
+ //Group var
+ CreatureGroup *m_group;
bool TriggerJustRespawned;
};
diff --git a/src/server/game/Entities/Creature/CreatureFormations.cpp b/src/server/game/Entities/Creature/CreatureFormations.cpp
new file mode 100644
index 0000000..add4ce1
--- /dev/null
+++ b/src/server/game/Entities/Creature/CreatureFormations.cpp
@@ -0,0 +1,332 @@
+/*
+ * Copyright (C) 2008-2010 TrinityCore <http://www.trinitycore.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * 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 "Creature.h"
+#include "CreatureFormations.h"
+#include "ObjectMgr.h"
+
+#include "CreatureAI.h"
+
+#define MAX_DESYNC 5.0f
+
+CreatureFormationInfoType CreatureFormationMap;
+CreatureFormationDataType CreatureFormationDataMap;
+
+void CreatureFormationManager::AddCreatureToFormation(uint32 formationId, Creature *member)
+{
+ Map *map = member->FindMap();
+ if (!map)
+ return;
+
+ CreatureFormationHolderType::iterator itr = map->CreatureFormationHolder.find(formationId);
+
+ //Add member to an existing formation
+ if (itr != map->CreatureFormationHolder.end())
+ {
+ sLog->outDebug("Formation found: %u, inserting creature GUID: %u, Formation InstanceID %u", formationId, member->GetGUIDLow(), member->GetInstanceId());
+ itr->second->AddMember(member);
+ }
+ //Create new formation
+ else
+ {
+ sLog->outDebug("Formation not found: %u. Creating new formation.", formationId);
+ CreatureFormation* formation = new CreatureFormation(formationId);
+ map->CreatureFormationHolder[formationId] = formation;
+ formation->AddMember(member);
+ }
+}
+
+void CreatureFormationManager::RemoveCreatureFromFormation(CreatureFormation *formation, Creature *member)
+{
+ sLog->outDebug("Deleting member pointer to GUID: %u from formation %u", formation->GetId(), member->GetDBTableGUIDLow());
+ formation->RemoveMember(member);
+
+ if (formation->isEmpty())
+ {
+ Map *map = member->FindMap();
+ if (!map)
+ return;
+
+ sLog->outDebug("Deleting formation with InstanceID %u", member->GetInstanceId());
+ map->CreatureFormationHolder.erase(formation->GetId());
+ delete formation;
+ }
+}
+
+void CreatureFormationManager::LoadCreatureFormations()
+{
+ uint32 oldMSTime = getMSTime();
+
+ //Clear existing map
+ for (CreatureFormationInfoType::iterator itr = CreatureFormationMap.begin(); itr != CreatureFormationMap.end(); ++itr) // for reload case
+ delete itr->second;
+ CreatureFormationMap.clear();
+
+ CreatureFormationDataMap.clear();
+
+ //Check if member without formation exist
+ PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_LOAD_CREFORMATION_DATA_WITHOUT_FORMATION);
+ PreparedQueryResult result = WorldDatabase.Query(stmt);
+
+ if (result)
+ {
+ sLog->outDetail(">> %u Member without formation found, member skipped.",result->Fetch()->GetInt32());
+ }
+
+ //Get formations
+ stmt = WorldDatabase.GetPreparedStatement(WORLD_LOAD_CREFORMATIONS);
+ PreparedQueryResult result_data = WorldDatabase.Query(stmt);
+
+ if (!result_data)
+ {
+ sLog->outString(">> Loaded 0 creature formations. DB table `creature_formations` is empty.");
+ sLog->outString();
+ return;
+ }
+
+ //Get member
+ stmt = WorldDatabase.GetPreparedStatement(WORLD_LOAD_CREFORMATION_DATA);
+ PreparedQueryResult result_member = WorldDatabase.Query(stmt);
+
+ if (!result_member)
+ {
+ sLog->outString(">> Loaded 0 formation formations. DB table `creature_formation_data` is empty.");
+ sLog->outString();
+ return;
+ }
+
+ std::set<uint32> guidSet;
+
+ stmt = WorldDatabase.GetPreparedStatement(WORLD_LOAD_CREATURE_GUIDS);
+ PreparedQueryResult guidResult = WorldDatabase.Query(stmt);
+
+ if (guidResult)
+ {
+ do
+ {
+ Field *fields = guidResult->Fetch();
+ uint32 guid = fields[0].GetUInt32();
+
+ guidSet.insert(guid);
+
+ } while (guidResult->NextRow());
+ }
+
+ //Loading formations...
+ uint32 formation_count = 0;
+ Field *fields;
+
+ FormationInfo *formation_info;
+
+ do
+ {
+ fields = result_data->Fetch();
+
+ //Load formation member data
+ uint32 formationId = fields[0].GetUInt32();
+ uint32 leaderGUID = fields[1].GetUInt32();
+ uint8 formationAI = fields[2].GetUInt8();
+
+ formation_info = new FormationInfo;
+ formation_info->leaderGUID = leaderGUID;
+ formation_info->formationAI = formationAI;
+
+ // check data correctness
+ if (guidSet.find(formation_info->leaderGUID) == guidSet.end())
+ {
+ sLog->outErrorDb("creature_formations table leader guid %u incorrect (not exist)", formation_info->leaderGUID);
+ delete formation_info;
+ return;
+ }
+
+ CreatureFormationMap[formationId] = formation_info;
+
+ sLog->outDebug("CreatureFormation::LoadCreatureFormations: Load Formation %u with Leader %u and formationAI %u.", formationId, leaderGUID, formationAI);
+ ++formation_count;
+ }
+ while (result_data->NextRow()) ;
+
+
+ //Loading member...
+ uint32 member_count = 0;
+ FormationData *formation_data;
+
+ do
+ {
+ fields = result_member->Fetch();
+
+ //Load formation member data
+ uint32 formationId = fields[0].GetUInt32();
+ uint32 memberGUID = fields[1].GetUInt32();
+ float follow_dist = fields[2].GetFloat();
+ float follow_angle = fields[3].GetFloat() * M_PI / 180;
+
+ formation_data = new FormationData;
+ formation_data->formationId = formationId;
+ formation_data->follow_dist = follow_dist;
+ formation_data->follow_angle = follow_angle;
+
+ // check data correctness
+ if (guidSet.find(memberGUID) == guidSet.end())
+ {
+ sLog->outErrorDb("creature_formation_data table member guid %u incorrect (not exist)", memberGUID);
+ continue;
+ }
+
+ CreatureFormationDataMap[memberGUID] = formation_data;
+
+ sLog->outDebug("CreatureFormation::LoadCreatureFormations: Load Member %u for Formation with formationId %u.", memberGUID, formation_data->formationId);
+ ++member_count;
+ }
+ while (result_member->NextRow()) ;
+
+ sLog->outString(">> Loaded %u formations and %u creatures in formations in %u ms", formation_count, member_count, GetMSTimeDiffToNow(oldMSTime));
+ sLog->outString();
+}
+
+void CreatureFormation::AddMember(Creature *member)
+{
+ if (!member)
+ return;
+
+ uint32 memberGUID = member->GetDBTableGUIDLow();
+
+ sLog->outDebug("CreatureFormation::AddMember: Adding unit GUID: %u to formation.", memberGUID);
+
+ Formation *formation;
+ formation = new Formation;
+
+ //Check if it is a leader
+ if (member->GetDBTableGUIDLow() == CreatureFormationMap.find(m_formationID)->second->leaderGUID)
+ {
+ sLog->outDebug("Unit GUID: %u is formation leader.", memberGUID);
+ m_leader = member;
+ formation->follow_dist = 0;
+ formation->follow_angle = 0;
+ }
+ else
+ {
+ formation->follow_dist = CreatureFormationDataMap.find(memberGUID)->second->follow_dist;
+ formation->follow_angle = CreatureFormationDataMap.find(memberGUID)->second->follow_angle;
+ }
+
+ formation->formationAI = CreatureFormationMap.find(m_formationID)->second->formationAI;
+ formation->leaderGUID = CreatureFormationMap.find(m_formationID)->second->leaderGUID;
+
+ m_members[member] = formation;
+ member->SetFormation(this);
+}
+
+void CreatureFormation::RemoveMember(Creature *member)
+{
+ if (!member)
+ return;
+
+ if (m_leader == member)
+ m_leader = NULL;
+
+ m_members.erase(member);
+ member->SetFormation(NULL);
+}
+
+void CreatureFormation::MemberAttackStart(Creature *member, Unit *target)
+{
+ uint8 formationAI = CreatureFormationMap[m_formationID]->formationAI;
+
+ if (!formationAI)
+ return;
+
+ if (formationAI == 1 && member != m_leader)
+ return;
+
+ for (CreatureFormationMemberType::iterator itr = m_members.begin(); itr != m_members.end(); ++itr)
+ {
+ Creature* pCreature = itr->first;
+
+ if (m_leader) // avoid crash if leader was killed and reset.
+ sLog->outDebug("CreatureFormation::MemberAttackStart: formation instance id %u calls member instid %u", m_leader->GetInstanceId(), member->GetInstanceId());
+
+ //Skip one check
+ if (pCreature == member)
+ continue;
+
+ if (!pCreature->isAlive())
+ continue;
+
+ if (pCreature->getVictim())
+ continue;
+
+ if (pCreature->IsAIEnabled)
+ if (pCreature->canAttack(target))
+ pCreature->AI()->AttackStart(target);
+ }
+}
+
+void CreatureFormation::Reset(bool dismiss)
+{
+ for (CreatureFormationMemberType::iterator itr = m_members.begin(); itr != m_members.end(); ++itr)
+ {
+ Creature* pCreature = itr->first;
+
+ if (pCreature != m_leader && pCreature->isAlive())
+ {
+ if (dismiss)
+ pCreature->GetMotionMaster()->Initialize();
+ else
+ pCreature->GetMotionMaster()->MoveIdle(MOTION_SLOT_IDLE);
+
+ sLog->outDebug("Set %s movement for member GUID: %u", dismiss ? "default" : "idle", pCreature->GetGUIDLow());
+ }
+ }
+ m_Formed = !dismiss;
+}
+
+void CreatureFormation::LeaderMoveTo(float x, float y, float z)
+{
+ if (!m_leader)
+ return;
+
+ float pathangle = atan2(m_leader->GetPositionY() - y, m_leader->GetPositionX() - x);
+
+ for (CreatureFormationMemberType::iterator itr = m_members.begin(); itr != m_members.end(); ++itr)
+ {
+ Creature *pCreature = itr->first;
+ if (pCreature == m_leader || !pCreature->isAlive() || pCreature->getVictim())
+ continue;
+
+ float angle = itr->second->follow_angle;
+ float dist = itr->second->follow_dist;
+
+ float dx = x + cos(angle + pathangle) * dist;
+ float dy = y + sin(angle + pathangle) * dist;
+ float dz = z;
+
+ Trinity::NormalizeMapCoord(dx);
+ Trinity::NormalizeMapCoord(dy);
+
+ pCreature->UpdateGroundPositionZ(dx, dy, dz);
+
+ if (pCreature->IsWithinDist(m_leader, dist + MAX_DESYNC))
+ pCreature->SetUnitMovementFlags(m_leader->GetUnitMovementFlags());
+ else
+ pCreature->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING);
+
+ pCreature->GetMotionMaster()->MovePoint(0, dx, dy, dz);
+ pCreature->SetHomePosition(dx, dy, dz, pathangle);
+ }
+}
\ No newline at end of file
diff --git a/src/server/game/Entities/Creature/CreatureFormations.h b/src/server/game/Entities/Creature/CreatureFormations.h
new file mode 100644
index 0000000..ab0ba48
--- /dev/null
+++ b/src/server/game/Entities/Creature/CreatureFormations.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2008-2010 TrinityCore <http://www.trinitycore.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * 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 _FORMATIONS_H
+#define _FORMATIONS_H
+
+#include "Common.h"
+
+class CreatureFormation;
+
+struct FormationInfo
+{
+ uint32 leaderGUID;
+ uint8 formationAI;
+};
+
+struct FormationData
+{
+ uint32 formationId;
+ float follow_dist;
+ float follow_angle;
+};
+
+struct Formation
+{
+ uint32 leaderGUID;
+ float follow_dist;
+ float follow_angle;
+ uint8 formationAI;
+};
+
+
+class CreatureFormationManager
+{
+ friend class ACE_Singleton<CreatureFormationManager, ACE_Null_Mutex>;
+ public:
+ void AddCreatureToFormation(uint32 formation_id, Creature *creature);
+ void RemoveCreatureFromFormation(CreatureFormation *formation, Creature *creature);
+ void LoadCreatureFormations();
+};
+
+#define sFormationMgr ACE_Singleton<CreatureFormationManager, ACE_Null_Mutex>::instance()
+
+typedef UNORDERED_MAP<uint32/*formationId*/, FormationInfo*> CreatureFormationInfoType;
+typedef UNORDERED_MAP<uint32/*memberGUID*/, FormationData*> CreatureFormationDataType;
+
+extern CreatureFormationInfoType CreatureFormationMap;
+extern CreatureFormationDataType CreatureFormationDataMap;
+
+class CreatureFormation
+{
+ private:
+ Creature *m_leader;
+ typedef std::map<Creature*, Formation*> CreatureFormationMemberType;
+ CreatureFormationMemberType m_members;
+
+ uint32 m_formationID;
+ bool m_Formed;
+
+ public:
+ //Fromation cannot be created empty
+ explicit CreatureFormation(uint32 id) : m_leader(NULL), m_formationID(id), m_Formed(false) {}
+ ~CreatureFormation() { sLog->outDebug("Destroying formation"); }
+
+ Creature* getLeader() const { return m_leader; }
+ uint32 GetId() const { return m_formationID; }
+ bool isEmpty() const { return m_members.empty(); }
+ bool isFormed() const { return m_Formed; }
+
+ void AddMember(Creature *member);
+ void RemoveMember(Creature *member);
+ void Reset(bool dismiss);
+
+ void LeaderMoveTo(float x, float y, float z);
+ void MemberAttackStart(Creature* member, Unit *target);
+};
+
+#endif
\ No newline at end of file
diff --git a/src/server/game/Entities/Creature/CreatureGroups.cpp b/src/server/game/Entities/Creature/CreatureGroups.cpp
index 4a37227..73a2ea1 100755
--- a/src/server/game/Entities/Creature/CreatureGroups.cpp
+++ b/src/server/game/Entities/Creature/CreatureGroups.cpp
@@ -25,6 +25,7 @@
#define MAX_DESYNC 5.0f
CreatureGroupInfoType CreatureGroupMap;
+CreatureGroupDataType CreatureGroupDataMap;
void CreatureGroupManager::AddCreatureToGroup(uint32 groupId, Creature *member)
{
@@ -67,7 +68,7 @@ void CreatureGroupManager::RemoveCreatureFromGroup(CreatureGroup *group, Creatur
}
}
-void CreatureGroupManager::LoadCreatureFormations()
+void CreatureGroupManager::LoadCreatureGroups()
{
uint32 oldMSTime = getMSTime();
@@ -75,19 +76,53 @@ void CreatureGroupManager::LoadCreatureFormations()
delete itr->second;
CreatureGroupMap.clear();
- //Get group data
- QueryResult result = WorldDatabase.Query("SELECT leaderGUID, memberGUID, dist, angle, groupAI FROM creature_formations ORDER BY leaderGUID");
+ CreatureGroupDataMap.clear();
- if (!result)
+ //Check if groups without member exist
+ PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_LOAD_CREGROUPS_WITHOUT_DATA);
+ PreparedQueryResult result = WorldDatabase.Query(stmt);
+
+ if (result)
+ {
+ sLog->outDetail(">> %u Groups without member found, groups skipped.",result->Fetch()->GetInt32());
+ }
+
+ //Check if member without group exist
+ stmt = WorldDatabase.GetPreparedStatement(WORLD_LOAD_CREGROUP_DATA_WITHOUT_GROUP);
+ result = WorldDatabase.Query(stmt);
+
+ if (result)
{
- sLog->outErrorDb(">> Loaded 0 creatures in formations. DB table `creature_formations` is empty!");
+ sLog->outDetail(">> %u Member without group found, member skipped.",result->Fetch()->GetInt32());
+ }
+
+ //Get groups
+ stmt = WorldDatabase.GetPreparedStatement(WORLD_LOAD_CREGROUPS);
+ PreparedQueryResult result_data = WorldDatabase.Query(stmt);
+
+ if (!result_data)
+ {
+ sLog->outString(">> Loaded 0 creature groups. DB table `creature_groups` is empty.");
sLog->outString();
return;
}
+ //Get member
+ stmt = WorldDatabase.GetPreparedStatement(WORLD_LOAD_CREGROUP_DATA);
+ PreparedQueryResult result_member = WorldDatabase.Query(stmt);
+
+ if (!result_member)
+ {
+ sLog->outString(">> Loaded 0 creature groups. DB table `creature_group_data` is empty.");
+ sLog->outString();
+ return;
+ }
+
std::set<uint32> guidSet;
- QueryResult guidResult = WorldDatabase.PQuery("SELECT guid FROM creature");
+ stmt = WorldDatabase.GetPreparedStatement(WORLD_LOAD_CREATURE_GUIDS);
+ PreparedQueryResult guidResult = WorldDatabase.Query(stmt);
+
if (guidResult)
{
do
@@ -100,157 +135,132 @@ void CreatureGroupManager::LoadCreatureFormations()
} while (guidResult->NextRow());
}
- uint32 count = 0;
+ //Loading groups...
+
+ uint32 group_count = 0;
Field *fields;
- FormationInfo *group_member;
+ GroupInfo *group_member;
do
{
- fields = result->Fetch();
+ fields = result_data->Fetch();
//Load group member data
- group_member = new FormationInfo;
- group_member->leaderGUID = fields[0].GetUInt32();
- uint32 memberGUID = fields[1].GetUInt32();
- group_member->groupAI = fields[4].GetUInt8();
- //If creature is group leader we may skip loading of dist/angle
- if (group_member->leaderGUID != memberGUID)
- {
- group_member->follow_dist = fields[2].GetFloat();
- group_member->follow_angle = fields[3].GetFloat() * M_PI / 180;
- }
- else
+ uint32 groupId = fields[0].GetUInt32();
+ uint32 leaderGUID = fields[1].GetUInt32();
+ uint8 groupType = fields[2].GetUInt8();
+
+ group_member = new GroupInfo;
+ group_member->leaderGUID = leaderGUID;
+ group_member->groupType = groupType;
+
+ // check data correctness
+ if (guidSet.find(group_member->leaderGUID) == guidSet.end())
{
- group_member->follow_dist = 0;
- group_member->follow_angle = 0;
+ sLog->outErrorDb("creature_groups table leader guid %u incorrect (not exist)", group_member->leaderGUID);
+ delete group_member;
+ return;
}
+ CreatureGroupMap[groupId] = group_member;
+
+ sLog->outDebug("CreatureGroup::LoadCreatureGroups: Load Group %u with Leader %u and groupType %u.", groupId, leaderGUID, groupType);
+ ++group_count;
+ }
+ while (result_data->NextRow()) ;
+
+ //Loading member...
+ uint32 member_count = 0;
+ do
+ {
+ fields = result_member->Fetch();
+
+ //Load group member data
+ uint32 groupId = fields[0].GetUInt32();
+ uint32 memberGUID = fields[1].GetUInt32();
+
// check data correctness
+ if (guidSet.find(memberGUID) == guidSet.end())
{
- if (guidSet.find(group_member->leaderGUID) == guidSet.end())
- {
- sLog->outErrorDb("creature_formations table leader guid %u incorrect (not exist)", group_member->leaderGUID);
- delete group_member;
- continue;
- }
-
- if (guidSet.find(memberGUID) == guidSet.end())
- {
- sLog->outErrorDb("creature_formations table member guid %u incorrect (not exist)", memberGUID);
- delete group_member;
- continue;
- }
+ sLog->outErrorDb("creature_group_data table member guid %u incorrect (not exist)", memberGUID);
+ continue;
}
- CreatureGroupMap[memberGUID] = group_member;
- ++count;
+ CreatureGroupDataMap[memberGUID] = groupId;
+
+ sLog->outDebug("CreatureGroup::LoadCreatureGroups: Load Member %u for Group with groupId %u.", memberGUID, groupId);
+ ++member_count;
}
while (result->NextRow()) ;
- sLog->outString(">> Loaded %u creatures in formations in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
+ sLog->outString(">> Loaded %u creatures in %u groups in %u ms", member_count, group_count, GetMSTimeDiffToNow(oldMSTime));
sLog->outString();
}
void CreatureGroup::AddMember(Creature *member)
{
- sLog->outDebug("CreatureGroup::AddMember: Adding unit GUID: %u.", member->GetGUIDLow());
+ if (!member)
+ return;
- //Check if it is a leader
- if (member->GetDBTableGUIDLow() == m_groupID)
- {
- sLog->outDebug("Unit GUID: %u is formation leader. Adding group.", member->GetGUIDLow());
- m_leader = member;
- }
+ sLog->outDebug("CreatureGroup::AddMember: Adding unit GUID: %u to group.", member->GetGUIDLow());
- m_members[member] = CreatureGroupMap.find(member->GetDBTableGUIDLow())->second;
- member->SetFormation(this);
+ m_members[member] = CreatureGroupMap.find(m_groupID)->second;
+ member->SetGroup(this);
}
void CreatureGroup::RemoveMember(Creature *member)
{
- if (m_leader == member)
- m_leader = NULL;
+ if (!member)
+ return;
m_members.erase(member);
- member->SetFormation(NULL);
+ member->SetGroup(NULL);
}
void CreatureGroup::MemberAttackStart(Creature *member, Unit *target)
{
- uint8 groupAI = CreatureGroupMap[member->GetDBTableGUIDLow()]->groupAI;
- if (!groupAI)
- return;
-
- if (groupAI == 1 && member != m_leader)
- return;
-
for (CreatureGroupMemberType::iterator itr = m_members.begin(); itr != m_members.end(); ++itr)
{
- if (m_leader) // avoid crash if leader was killed and reset.
- sLog->outDebug("GROUP ATTACK: group instance id %u calls member instid %u", m_leader->GetInstanceId(), member->GetInstanceId());
+ Creature* pCreature = itr->first;
+
+ sLog->outDebug("CreatureGroup::MemberAttackStart: group member instanceId %u .",member->GetInstanceId());
//Skip one check
- if (itr->first == member)
+ if (pCreature == member)
continue;
- if (!itr->first->isAlive())
+ if (!pCreature->isAlive())
continue;
- if (itr->first->getVictim())
+ if (pCreature->getVictim())
continue;
- if (itr->first->canAttack(target) && itr->first->AI())
- itr->first->AI()->AttackStart(target);
- }
-}
-
-void CreatureGroup::FormationReset(bool dismiss)
-{
- for (CreatureGroupMemberType::iterator itr = m_members.begin(); itr != m_members.end(); ++itr)
- {
- if (itr->first != m_leader && itr->first->isAlive())
- {
- if (dismiss)
- itr->first->GetMotionMaster()->Initialize();
- else
- itr->first->GetMotionMaster()->MoveIdle(MOTION_SLOT_IDLE);
- sLog->outDebug("Set %s movement for member GUID: %u", dismiss ? "default" : "idle", itr->first->GetGUIDLow());
- }
+ if (pCreature->IsAIEnabled)
+ if (pCreature->canAttack(target))
+ pCreature->AI()->AttackStart(target);
}
- m_Formed = !dismiss;
}
-void CreatureGroup::LeaderMoveTo(float x, float y, float z)
+bool CreatureGroup::IsAllowedToRespawn(Creature *member)
{
- if (!m_leader)
- return;
+ uint8 groupType = CreatureGroupMap[m_groupID]->groupType;
- float pathangle = atan2(m_leader->GetPositionY() - y, m_leader->GetPositionX() - x);
+ if (!member->GetMap()->IsRaid() || groupType == 0)
+ return false;
+ bool exist = false;
+ //Check if at least one groupmember lives if no -> no respawn.
for (CreatureGroupMemberType::iterator itr = m_members.begin(); itr != m_members.end(); ++itr)
- {
- Creature *member = itr->first;
- if (member == m_leader || !member->isAlive() || member->getVictim())
- continue;
-
- float angle = itr->second->follow_angle;
- float dist = itr->second->follow_dist;
+ if (itr->first->isAlive())
+ exist = true;
- float dx = x + cos(angle + pathangle) * dist;
- float dy = y + sin(angle + pathangle) * dist;
- float dz = z;
-
- Trinity::NormalizeMapCoord(dx);
- Trinity::NormalizeMapCoord(dy);
-
- member->UpdateGroundPositionZ(dx, dy, dz);
-
- if (member->IsWithinDist(m_leader, dist + MAX_DESYNC))
- member->SetUnitMovementFlags(m_leader->GetUnitMovementFlags());
- else
- member->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING);
-
- member->GetMotionMaster()->MovePoint(0, dx, dy, dz);
- member->SetHomePosition(dx, dy, dz, pathangle);
- }
-}
+ //Check if an groupmember is in combat, if yes -> no respawn.
+ for (CreatureGroupMemberType::iterator itr = m_members.begin(); itr != m_members.end(); ++itr)
+ if (itr->first->isInCombat())
+ exist = false;
+
+ if (exist)
+ sLog->outDebug("CreatureGroup::IsAllowedToRespawn: group member instanceId %u can respawn.",member->GetInstanceId());
+
+ return exist;
+}
\ No newline at end of file
diff --git a/src/server/game/Entities/Creature/CreatureGroups.h b/src/server/game/Entities/Creature/CreatureGroups.h
index ff35ee0..1084170 100755
--- a/src/server/game/Entities/Creature/CreatureGroups.h
+++ b/src/server/game/Entities/Creature/CreatureGroups.h
@@ -16,19 +16,17 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef _FORMATIONS_H
-#define _FORMATIONS_H
+#ifndef _GROUPS_H
+#define _GROUPS_H
#include "Common.h"
class CreatureGroup;
-struct FormationInfo
+struct GroupInfo
{
uint32 leaderGUID;
- float follow_dist;
- float follow_angle;
- uint8 groupAI;
+ uint8 groupType;
};
class CreatureGroupManager
@@ -37,41 +35,38 @@ class CreatureGroupManager
public:
void AddCreatureToGroup(uint32 group_id, Creature *creature);
void RemoveCreatureFromGroup(CreatureGroup *group, Creature *creature);
- void LoadCreatureFormations();
+ void LoadCreatureGroups();
};
-#define sFormationMgr ACE_Singleton<CreatureGroupManager, ACE_Null_Mutex>::instance()
+#define sGroupMgr ACE_Singleton<CreatureGroupManager, ACE_Null_Mutex>::instance()
-typedef UNORDERED_MAP<uint32/*memberDBGUID*/, FormationInfo*> CreatureGroupInfoType;
+typedef UNORDERED_MAP<uint32/*groupId*/, GroupInfo*> CreatureGroupInfoType;
+typedef UNORDERED_MAP<uint32/*memberGUID*/, uint32/*groupId*/> CreatureGroupDataType;
extern CreatureGroupInfoType CreatureGroupMap;
+extern CreatureGroupDataType CreatureGroupDataMap;
class CreatureGroup
{
private:
- Creature *m_leader; //Important do not forget sometimes to work with pointers instead synonims :D:D
- typedef std::map<Creature*, FormationInfo*> CreatureGroupMemberType;
+ typedef std::map<Creature*, GroupInfo*> CreatureGroupMemberType;
CreatureGroupMemberType m_members;
uint32 m_groupID;
- bool m_Formed;
public:
//Group cannot be created empty
- explicit CreatureGroup(uint32 id) : m_leader(NULL), m_groupID(id), m_Formed(false) {}
+ explicit CreatureGroup(uint32 id) : m_groupID(id) {}
~CreatureGroup() { sLog->outDebug("Destroying group"); }
- Creature* getLeader() const { return m_leader; }
uint32 GetId() const { return m_groupID; }
bool isEmpty() const { return m_members.empty(); }
- bool isFormed() const { return m_Formed; }
void AddMember(Creature *member);
void RemoveMember(Creature *member);
- void FormationReset(bool dismiss);
- void LeaderMoveTo(float x, float y, float z);
void MemberAttackStart(Creature* member, Unit *target);
+ bool IsAllowedToRespawn(Creature *member);
};
#endif
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index b35ba61..7a61ba2 100755
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -46,6 +46,7 @@
#include "GridNotifiersImpl.h"
#include "CellImpl.h"
#include "Path.h"
+#include "CreatureFormations.h"
#include "CreatureGroups.h"
#include "PetAI.h"
#include "PassiveAI.h"
@@ -11765,6 +11766,9 @@ void Unit::SetInCombatState(bool PvP, Unit* enemy)
}
if (this->ToCreature()->GetFormation())
this->ToCreature()->GetFormation()->MemberAttackStart(this->ToCreature(), enemy);
+
+ if (this->ToCreature()->GetGroup())
+ this->ToCreature()->GetGroup()->MemberAttackStart(this->ToCreature(), enemy);
}
if (isPet())
diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h
index 8da8a18..7dbc83c 100755
--- a/src/server/game/Maps/Map.h
+++ b/src/server/game/Maps/Map.h
@@ -43,6 +43,7 @@ class Object;
class WorldObject;
class TempSummon;
class Player;
+class CreatureFormation;
class CreatureGroup;
struct ScriptInfo;
struct ScriptAction;
@@ -245,7 +246,8 @@ typedef UNORDERED_MAP<Creature*, CreatureMover> CreatureMoveList;
#define DEFAULT_HEIGHT_SEARCH 10.0f // default search distance to find height at nearby locations
#define MIN_UNLOAD_DELAY 1 // immediate unload
-typedef std::map<uint32/*leaderDBGUID*/, CreatureGroup*> CreatureGroupHolderType;
+typedef std::map<uint32/*leaderDBGUID*/, CreatureFormation*> CreatureFormationHolderType;
+typedef std::map<uint32/*groupId*/, CreatureGroup*> CreatureGroupHolderType;
class Map : public GridRefManager<NGridType>
{
@@ -429,6 +431,7 @@ class Map : public GridRefManager<NGridType>
template<class NOTIFIER> void VisitAll(const float &x, const float &y, float radius, NOTIFIER &notifier);
template<class NOTIFIER> void VisitWorld(const float &x, const float &y, float radius, NOTIFIER &notifier);
template<class NOTIFIER> void VisitGrid(const float &x, const float &y, float radius, NOTIFIER &notifier);
+ CreatureFormationHolderType CreatureFormationHolder;
CreatureGroupHolderType CreatureGroupHolder;
void UpdateIteratorBack(Player *player);
diff --git a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp
index 83e0f86..1cf92db 100755
--- a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp
@@ -24,7 +24,7 @@
#include "DestinationHolderImp.h"
#include "Map.h"
#include "Util.h"
-#include "CreatureGroups.h"
+#include "CreatureFormations.h"
#define RUNNING_CHANCE_RANDOMMV 20 //will be "1 / RUNNING_CHANCE_RANDOMMV"
diff --git a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp
index efae233..444e5d7 100755
--- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp
@@ -25,7 +25,7 @@
//Creature-specific headers
#include "Creature.h"
#include "CreatureAI.h"
-#include "CreatureGroups.h"
+#include "CreatureFormations.h"
//Player-specific
#include "Player.h"
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index 1567277..2877571 100755
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -58,6 +58,7 @@
#include "InstanceSaveMgr.h"
#include "Util.h"
#include "Language.h"
+#include "CreatureFormations.h"
#include "CreatureGroups.h"
#include "Transport.h"
#include "ScriptMgr.h"
@@ -1544,6 +1545,9 @@ void World::SetInitialWorldSettings()
sLog->outString("Loading Creature Formations...");
sFormationMgr->LoadCreatureFormations();
+ sLog->outString("Loading Creature Groups...");
+ sGroupMgr->LoadCreatureGroups();
+
sLog->outString("Loading Conditions...");
sConditionMgr->LoadConditions();
diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp
index 7b99017..d3d5f11 100644
--- a/src/server/scripts/Commands/cs_npc.cpp
+++ b/src/server/scripts/Commands/cs_npc.cpp
@@ -27,6 +27,7 @@ EndScriptData */
#include "Chat.h"
#include "Transport.h"
#include "CreatureGroups.h"
+#include "CreatureFormations.h"
#include "TargetedMovementGenerator.h" // for HandleNpcUnFollowCommand
class npc_commandscript : public CommandScript
@@ -39,6 +40,7 @@ public:
static ChatCommand npcAddCommandTable[] =
{
{ "formation", SEC_MODERATOR, false, &HandleNpcAddFormationCommand, "", NULL },
+ { "group", SEC_MODERATOR, false, &HandleNpcAddGroupCommand, "", NULL },
{ "item", SEC_GAMEMASTER, false, &HandleNpcAddVendorItemCommand, "", NULL },
{ "move", SEC_GAMEMASTER, false, &HandleNpcAddMoveCommand, "", NULL },
{ "temp", SEC_GAMEMASTER, false, &HandleNpcAddTempSpawnCommand, "", NULL },
@@ -1193,7 +1195,30 @@ public:
if (!*args)
return false;
- uint32 leaderGUID = (uint32) atoi((char*)args);
+ char* ldrGUID = strtok((char*)args, " ");
+
+ if (!ldrGUID)
+ return false;
+
+ uint32 leaderGUID = (uint32) atoi(ldrGUID);
+
+ char* cmt = strtok(NULL, "");
+ char* commentText = "";
+
+ if (cmt)
+ commentText = handler->extractQuotedArg(cmt);
+
+ char* frmAI = strtok(NULL, " ");
+ uint8 formationAI = 0;
+
+ if (frmAI)
+ formationAI = (uint8) atoi(frmAI);
+
+ uint32 formationId = 0;
+ uint32 memberGUID = 0;
+ float follow_dist = 0;
+ float follow_angle = 0;
+
Creature *pCreature = handler->getSelectedCreature();
if (!pCreature || !pCreature->GetDBTableGUIDLow())
@@ -1203,32 +1228,211 @@ public:
return false;
}
- uint32 lowguid = pCreature->GetDBTableGUIDLow();
+ Player *chr = handler->GetSession()->GetPlayer();
+
+ memberGUID = pCreature->GetDBTableGUIDLow();
+ follow_dist = sqrtf(pow(chr->GetPositionX() - pCreature->GetPositionX(),int(2))+pow(chr->GetPositionY()-pCreature->GetPositionY(),int(2)));
+ follow_angle = (pCreature->GetAngle(chr) - chr->GetOrientation()) * 180 / M_PI;
+
+ if (follow_angle < 0)
+ follow_angle = follow_angle + 360;
+
+ if (!memberGUID)
+ return false;
+
if (pCreature->GetFormation())
{
- handler->PSendSysMessage("Selected creature is already member of group %u", pCreature->GetFormation()->GetId());
+ handler->PSendSysMessage("Selected creature is already member of formation %u", pCreature->GetFormation()->GetId());
return false;
}
- if (!lowguid)
+ //Check if formation with given leaderGUID exist
+ PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_LOAD_CREFORMATIONS_BY_LEADER);
+ stmt->setUInt32(0, leaderGUID);
+ PreparedQueryResult result_FormationId = WorldDatabase.Query(stmt);
+
+ if (result_FormationId)
+ {
+ //Load FormationId
+ Field *fields = result_FormationId->Fetch();
+ formationId = fields[0].GetUInt32();
+ //Overwrite given Data
+ leaderGUID = fields[1].GetUInt32();
+ formationAI = fields[2].GetUInt8();
+
+ stmt = WorldDatabase.GetPreparedStatement(WORLD_ADD_CREFORMATION_DATA);
+ stmt->setUInt32(0, formationId);
+ stmt->setUInt32(1, memberGUID);
+ stmt->setFloat(2, follow_dist);
+ stmt->setFloat(3, follow_angle);
+ WorldDatabase.Execute(stmt);
+
+ handler->PSendSysMessage("Creature %u added to formation %u with leader %u and formationAI %u", memberGUID, formationId, leaderGUID, formationAI);
+ }
+ else
+ {
+ //Create newFormation and load formationId
+ if (memberGUID != leaderGUID)
+ {
+ handler->PSendSysMessage("You should set the Leader for this Formation first.");
+ return false;
+ }
+
+ stmt = WorldDatabase.GetPreparedStatement(WORLD_ADD_CREFORMATIONS);
+ stmt->setUInt32(0, leaderGUID);
+ stmt->setUInt8(1, formationAI);
+ stmt->setString(2, commentText);
+ //Must be executed direct, not asyncron
+ WorldDatabase.DirectExecute(stmt);
+
+ stmt = WorldDatabase.GetPreparedStatement(WORLD_LOAD_CREFORMATIONS_MAXID);
+ PreparedQueryResult result_newFormationId = WorldDatabase.Query(stmt);
+
+ formationId = result_newFormationId->Fetch()->GetInt32();
+
+ FormationInfo *formation_info;
+
+ formation_info = new FormationInfo;
+ formation_info->leaderGUID = leaderGUID;
+ formation_info->formationAI = formationAI;
+
+ CreatureFormationMap[formationId] = formation_info;
+
+ stmt = WorldDatabase.GetPreparedStatement(WORLD_ADD_CREFORMATION_DATA);
+ stmt->setUInt32(0, formationId);
+ stmt->setUInt32(1, memberGUID);
+ stmt->setFloat(2, 0);
+ stmt->setFloat(3, 0);
+ WorldDatabase.Execute(stmt);
+
+ handler->PSendSysMessage("Creature %u added to new formation %u with leader %u and formationAI %u", memberGUID, formationId, leaderGUID, formationAI);
+ }
+
+ FormationData *formation_data;
+
+ formation_data = new FormationData;
+ formation_data->formationId = formationId;
+ formation_data->follow_dist = follow_dist;
+ formation_data->follow_angle = follow_angle;
+
+ if (memberGUID == leaderGUID) {
+ formation_data->follow_dist = 0;
+ formation_data->follow_angle = 0;
+ }
+
+ CreatureFormationDataMap[memberGUID] = formation_data;
+ pCreature->SearchFormation();
+
+ return true;
+ }
+
+ static bool HandleNpcAddGroupCommand(ChatHandler* handler, const char* args)
+ {
+ if (!*args)
return false;
+
+ char* ldrGUID = strtok((char*)args, " ");
+
+ if (!ldrGUID)
+ return false;
+
+ uint32 leaderGUID = (uint32) atoi(ldrGUID);
+
+ char* cmt = strtok(NULL, "");
+ char* commentText = "";
+
+ if (cmt)
+ commentText = handler->extractQuotedArg(cmt);
+
+ char* grpType = strtok(NULL, " ");
+ uint8 groupType = 0;
+
+ if (grpType)
+ groupType = (uint8) atoi(grpType);
+
+ uint32 groupId = 0;
+ uint32 memberGUID = 0;
- Player *chr = handler->GetSession()->GetPlayer();
- FormationInfo *group_member;
+ Creature *pCreature = handler->getSelectedCreature();
+
+ if (!pCreature || !pCreature->GetDBTableGUIDLow())
+ {
+ handler->SendSysMessage(LANG_SELECT_CREATURE);
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
- group_member = new FormationInfo;
- group_member->follow_angle = (pCreature->GetAngle(chr) - chr->GetOrientation()) * 180 / M_PI;
- group_member->follow_dist = sqrtf(pow(chr->GetPositionX() - pCreature->GetPositionX(),int(2))+pow(chr->GetPositionY()-pCreature->GetPositionY(),int(2)));
- group_member->leaderGUID = leaderGUID;
- group_member->groupAI = 0;
+ memberGUID = pCreature->GetDBTableGUIDLow();
+
+ if (!memberGUID)
+ return false;
+
+ if (pCreature->GetGroup())
+ {
+ handler->PSendSysMessage("Selected creature is already member of group %u", pCreature->GetGroup()->GetId());
+ return false;
+ }
- CreatureGroupMap[lowguid] = group_member;
- pCreature->SearchFormation();
+ //Check if group with given leaderGUID exist
+ PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_LOAD_CREGROUPS_BY_LEADER);
+ stmt->setUInt32(0, leaderGUID);
+ PreparedQueryResult result_GroupId = WorldDatabase.Query(stmt);
- WorldDatabase.PExecute("INSERT INTO creature_formations (leaderGUID, memberGUID, dist, angle, groupAI) VALUES ('%u','%u','%f', '%f', '%u')",
- leaderGUID, lowguid, group_member->follow_dist, group_member->follow_angle, group_member->groupAI);
+ if (result_GroupId)
+ {
+ //Load GroupId
+ Field *fields = result_GroupId->Fetch();
+ groupId = fields[0].GetUInt32();
+ //Overwrite given Data
+ leaderGUID = fields[1].GetUInt32();
+ groupType = fields[2].GetUInt8();
+
+ stmt = WorldDatabase.GetPreparedStatement(WORLD_ADD_CREGROUP_DATA);
+ stmt->setUInt32(0, groupId);
+ stmt->setUInt32(1, memberGUID);
+ WorldDatabase.Execute(stmt);
+
+ handler->PSendSysMessage("Creature %u added to group %u with leader %u and GroupType %u", memberGUID, groupId, leaderGUID, groupType);
+ }
+ else
+ {
+ //Create newGroup and load groupId
+ if (memberGUID != leaderGUID)
+ {
+ handler->PSendSysMessage("You should set the Leader for this Group first.");
+ return false;
+ }
+
+ stmt = WorldDatabase.GetPreparedStatement(WORLD_ADD_CREGROUPS);
+ stmt->setUInt32(0, leaderGUID);
+ stmt->setUInt8(1, groupType);
+ stmt->setString(2, commentText);
+ //Must be executed direct, not asyncron
+ WorldDatabase.DirectExecute(stmt);
+
+ stmt = WorldDatabase.GetPreparedStatement(WORLD_LOAD_CREGROUPS_MAXID);
+ PreparedQueryResult result_newGroupId = WorldDatabase.Query(stmt);
+
+ groupId = result_newGroupId->Fetch()->GetInt32();
+
+ GroupInfo *group_member;
+
+ group_member = new GroupInfo;
+ group_member->leaderGUID = leaderGUID;
+ group_member->groupType = groupType;
+
+ CreatureGroupMap[groupId] = group_member;
+
+ stmt = WorldDatabase.GetPreparedStatement(WORLD_ADD_CREGROUP_DATA);
+ stmt->setUInt32(0, groupId);
+ stmt->setUInt32(1, memberGUID);
+ WorldDatabase.Execute(stmt);
+
+ handler->PSendSysMessage("Creature %u added to new group %u with leader %u and GroupType %u", memberGUID, groupId, leaderGUID, groupType);
+ }
- handler->PSendSysMessage("Creature %u added to formation with leader %u", lowguid, leaderGUID);
+ CreatureGroupDataMap[memberGUID] = groupId;
+ pCreature->SearchGroup();
return true;
}
diff --git a/src/server/shared/Database/Implementation/WorldDatabase.cpp b/src/server/shared/Database/Implementation/WorldDatabase.cpp
index cef1c26..9271b99 100755
--- a/src/server/shared/Database/Implementation/WorldDatabase.cpp
+++ b/src/server/shared/Database/Implementation/WorldDatabase.cpp
@@ -37,5 +37,25 @@ bool WorldDatabaseConnection::Open()
PrepareStatement(WORLD_LOAD_SMART_SCRIPTS, "SELECT entryorguid, source_type, id, link, event_type, event_phase_mask, event_chance, event_flags, event_param1, event_param2, event_param3, event_param4, action_type, action_param1, action_param2, action_param3, action_param4, action_param5, action_param6, target_type, target_param1, target_param2, target_param3, target_x, target_y, target_z, target_o FROM smart_scripts ORDER BY entryorguid, source_type, id, link");
PrepareStatement(WORLD_LOAD_SMARTAI_WP, "SELECT entry, pointid, position_x, position_y, position_z FROM waypoints ORDER BY entry, pointid");
+ PrepareStatement(WORLD_LOAD_CREATURE_GUIDS, "SELECT guid FROM creature");
+
+ PrepareStatement(WORLD_LOAD_CREFORMATIONS_MAXID, "SELECT MAX(formationId) FROM creature_formations");
+ PrepareStatement(WORLD_LOAD_CREFORMATIONS_WITHOUT_DATA, "SELECT COUNT(formationId) FROM creature_formations WHERE formationId NOT IN (SELECT formationId FROM creature_formation_data)");
+ PrepareStatement(WORLD_LOAD_CREFORMATION_DATA_WITHOUT_FORMATION, "SELECT COUNT(formationId) FROM creature_formation_data WHERE formationId NOT IN (SELECT formationId FROM creature_formations)");
+ PrepareStatement(WORLD_LOAD_CREFORMATIONS, "SELECT formationId, leaderGUID, formationAI FROM creature_formations WHERE formationId IN (SELECT formationId FROM creature_formation_data) ORDER BY formationId");
+ PrepareStatement(WORLD_LOAD_CREFORMATION_DATA, "SELECT formationId, memberGUID, dist, angle FROM creature_formation_data WHERE formationId IN (SELECT formationId FROM creature_formations) ORDER BY formationId");
+ PrepareStatement(WORLD_LOAD_CREFORMATIONS_BY_LEADER, "SELECT formationId, leaderGUID, formationAI FROM creature_formations WHERE leaderGUID = ? ");
+ PrepareStatement(WORLD_ADD_CREFORMATION_DATA, "INSERT INTO creature_formation_data (formationId, memberGUID, dist, angle) VALUES (?, ?, ?, ?)");
+ PrepareStatement(WORLD_ADD_CREFORMATIONS, "INSERT INTO creature_formations (leaderGUID, formationAI, comment) VALUES (?, ?, ?)");
+
+ PrepareStatement(WORLD_LOAD_CREGROUPS_MAXID, "SELECT MAX(groupId) FROM creature_groups");
+ PrepareStatement(WORLD_LOAD_CREGROUPS_WITHOUT_DATA, "SELECT COUNT(groupId) FROM creature_groups WHERE groupId NOT IN (SELECT groupId FROM creature_group_data)");
+ PrepareStatement(WORLD_LOAD_CREGROUP_DATA_WITHOUT_GROUP, "SELECT COUNT(groupId) FROM creature_group_data WHERE groupId NOT IN (SELECT groupId FROM creature_groups)");
+ PrepareStatement(WORLD_LOAD_CREGROUPS, "SELECT groupId, leaderGUID, groupType FROM creature_groups WHERE groupId IN (SELECT groupId FROM creature_group_data) ORDER BY groupId");
+ PrepareStatement(WORLD_LOAD_CREGROUP_DATA, "SELECT groupId, memberGUID FROM creature_group_data WHERE groupId IN (SELECT groupId FROM creature_groups) ORDER BY groupId");
+ PrepareStatement(WORLD_LOAD_CREGROUPS_BY_LEADER, "SELECT groupId, leaderGUID, groupType FROM creature_groups WHERE leaderGUID = ? ");
+ PrepareStatement(WORLD_ADD_CREGROUP_DATA, "INSERT INTO creature_group_data (groupId, memberGUID) VALUES (?, ?)");
+ PrepareStatement(WORLD_ADD_CREGROUPS, "INSERT INTO creature_groups (leaderGUID, groupType, comment) VALUES (?, ?, ?)");
+
return true;
}
diff --git a/src/server/shared/Database/Implementation/WorldDatabase.h b/src/server/shared/Database/Implementation/WorldDatabase.h
index bd976f7..0454a5f 100755
--- a/src/server/shared/Database/Implementation/WorldDatabase.h
+++ b/src/server/shared/Database/Implementation/WorldDatabase.h
@@ -48,6 +48,23 @@ enum WorldDatabaseStatements
WORLD_LOAD_CRETEXT,
WORLD_LOAD_SMART_SCRIPTS,
WORLD_LOAD_SMARTAI_WP,
+ WORLD_LOAD_CREATURE_GUIDS,
+ WORLD_LOAD_CREFORMATIONS_MAXID,
+ WORLD_LOAD_CREFORMATIONS_WITHOUT_DATA,
+ WORLD_LOAD_CREFORMATION_DATA_WITHOUT_FORMATION,
+ WORLD_LOAD_CREFORMATIONS,
+ WORLD_LOAD_CREFORMATION_DATA,
+ WORLD_LOAD_CREFORMATIONS_BY_LEADER,
+ WORLD_ADD_CREFORMATION_DATA,
+ WORLD_ADD_CREFORMATIONS,
+ WORLD_LOAD_CREGROUPS_MAXID,
+ WORLD_LOAD_CREGROUPS_WITHOUT_DATA,
+ WORLD_LOAD_CREGROUP_DATA_WITHOUT_GROUP,
+ WORLD_LOAD_CREGROUPS,
+ WORLD_LOAD_CREGROUP_DATA,
+ WORLD_LOAD_CREGROUPS_BY_LEADER,
+ WORLD_ADD_CREGROUP_DATA,
+ WORLD_ADD_CREGROUPS,
MAX_WORLDDATABASE_STATEMENTS,
};
--
1.7.0.2.msysgit.0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment