Created
July 4, 2011 03:28
-
-
Save DDuarte/1062871 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 ¬ifier); | |
template<class NOTIFIER> void VisitWorld(const float &x, const float &y, float radius, NOTIFIER ¬ifier); | |
template<class NOTIFIER> void VisitGrid(const float &x, const float &y, float radius, NOTIFIER ¬ifier); | |
+ 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