diff options
-rw-r--r-- | sql/updates/505_world.sql | 32 | ||||
-rw-r--r-- | src/game/Creature.cpp | 20 | ||||
-rw-r--r-- | src/game/Creature.h | 10 | ||||
-rw-r--r-- | src/game/CreatureGroups.cpp | 218 | ||||
-rw-r--r-- | src/game/CreatureGroups.h | 66 | ||||
-rw-r--r-- | src/game/Traveller.h | 7 | ||||
-rw-r--r-- | src/game/Unit.cpp | 5 | ||||
-rw-r--r-- | src/game/World.cpp | 6 | ||||
-rw-r--r-- | win/VC90/game.vcproj | 12 |
9 files changed, 369 insertions, 7 deletions
diff --git a/sql/updates/505_world.sql b/sql/updates/505_world.sql new file mode 100644 index 00000000000..644ee9ee5de --- /dev/null +++ b/sql/updates/505_world.sql @@ -0,0 +1,32 @@ +/* +SQLyog Community Edition- MySQL GUI v6.16 +MySQL - 5.0.27-community-nt : Database - world +********************************************************************* +*/
+ +/*!40101 SET NAMES utf8 */; + +/*!40101 SET SQL_MODE=''*/; + +create database if not exists `world`; + +USE `world`; + +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; + +/*Table structure for table `creature_formations` */ + +DROP TABLE IF EXISTS `creature_formations`; + +CREATE TABLE `creature_formations` ( + `leader` int(11) unsigned NOT NULL, + `follower` int(11) unsigned NOT NULL, + `dist` float unsigned NOT NULL, + `angle` float unsigned NOT NULL, + `groupAI` int(11) unsigned NOT NULL, + PRIMARY KEY (`follower`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; diff --git a/src/game/Creature.cpp b/src/game/Creature.cpp index 5ab31242bc8..c70ffdba940 100644 --- a/src/game/Creature.cpp +++ b/src/game/Creature.cpp @@ -47,6 +47,7 @@ #include "OutdoorPvPMgr.h" #include "GameEvent.h" #include "PossessedAI.h" +#include "CreatureGroups.h" // apply implementation of the singletons #include "Policies/SingletonImp.h" @@ -147,7 +148,7 @@ m_deathTimer(0), m_respawnTime(0), m_respawnDelay(25), m_corpseDelay(60), m_resp m_gossipOptionLoaded(false), m_emoteState(0), m_isPet(false), m_isTotem(false), m_reactState(REACT_AGGRESSIVE), m_regenTimer(2000), m_defaultMovementType(IDLE_MOTION_TYPE), m_equipmentId(0), m_AlreadyCallAssistance(false), m_regenHealth(true), m_AI_locked(false), m_isDeadByDefault(false), -m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL),m_creatureInfo(NULL), m_DBTableGuid(0) +m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL),m_creatureInfo(NULL), m_DBTableGuid(0), m_formationID(0) { m_valuesCount = UNIT_END; @@ -181,15 +182,30 @@ void Creature::AddToWorld() ///- Register the creature for guid lookup if(!IsInWorld()) ObjectAccessor::Instance().AddObject(this); Unit::AddToWorld(); + SearchFormation(); } void Creature::RemoveFromWorld() { - ///- Remove the creature from the accessor + if(m_formationID) + formation_mgr.DestroyGroup(m_formationID, GetGUID()); + + ///- Remove the creature from the accessor if(IsInWorld()) ObjectAccessor::Instance().RemoveObject(this); Unit::RemoveFromWorld(); } +void Creature::SearchFormation() +{ + uint32 lowguid = GetDBTableGUIDLow(); + + if(CreatureGroupMap.find(lowguid) != CreatureGroupMap.end()) + { + m_formationID = CreatureGroupMap[lowguid]->leaderGUID; + formation_mgr.UpdateCreatureGroup(m_formationID, this); + } +} + void Creature::RemoveCorpse() { if( getDeathState()!=CORPSE && !m_isDeadByDefault || getDeathState()!=ALIVE && m_isDeadByDefault ) diff --git a/src/game/Creature.h b/src/game/Creature.h index 59dd8ea3132..f35c833d4d8 100644 --- a/src/game/Creature.h +++ b/src/game/Creature.h @@ -28,6 +28,7 @@ #include "LootMgr.h" #include "Database/DatabaseEnv.h" #include "Cell.h" +#include "CreatureGroups.h" #include <list> @@ -625,6 +626,10 @@ class TRINITY_DLL_SPEC Creature : public Unit uint32 GetCurrentWaypointID(){return m_waypointID;} void UpdateWaypointID(uint32 wpID){m_waypointID = wpID;} + void SearchFormation(); + bool IsFormationLeader() {return GetDBTableGUIDLow() == m_formationID;} + uint32 GetFormationID(){return m_formationID;} + protected: bool CreateFromProto(uint32 guidlow,uint32 Entry,uint32 team, const CreatureData *data = NULL); bool InitEntry(uint32 entry, uint32 team=ALLIANCE, const CreatureData* data=NULL); @@ -678,7 +683,10 @@ class TRINITY_DLL_SPEC Creature : public Unit //WaypointMovementGenerator vars uint32 m_waypointID; uint32 m_path_id; - + + //Formation var + uint32 m_formationID; + GridReference<Creature> m_gridRef; CreatureInfo const* m_creatureInfo; // in heroic mode can different from ObjMgr::GetCreatureTemplate(GetEntry()) }; diff --git a/src/game/CreatureGroups.cpp b/src/game/CreatureGroups.cpp new file mode 100644 index 00000000000..cea13db04b6 --- /dev/null +++ b/src/game/CreatureGroups.cpp @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/> + * + * Copyright (C) 2008 Trinity <http://www.trinitycore.org/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Creature.h" +#include "CreatureGroups.h" +#include "ObjectMgr.h" +#include "ProgressBar.h" +#include "Policies/SingletonImp.h" + +#define MAX_DESYNC 5.0f + +INSTANTIATE_SINGLETON_1(CreatureGroupManager); + +UNORDERED_MAP<uint32, CreatureGroup*> CreatureGroupHolder; +UNORDERED_MAP<uint32, FormationMember*> CreatureGroupMap; + +void CreatureGroupManager::UpdateCreatureGroup(uint32 group_id, Creature *member) +{ + if(CreatureGroupHolder.find(group_id) != CreatureGroupHolder.end()) + { + sLog.outDebug("Group found: %u, inserting creature GUID: %u", group_id, member->GetGUIDLow()); + CreatureGroupHolder[group_id]->AddMember(member); + } + else + { + sLog.outDebug("Group not found: %u. Creating new group.", group_id); + CreatureGroup* formation = new CreatureGroup; + CreatureGroupHolder[group_id] = formation; + formation->AddMember(member); + } +} + +void CreatureGroupManager::DestroyGroup(uint32 group_id, uint64 guid) +{ + if(CreatureGroupHolder.find(group_id) != CreatureGroupHolder.end()) + { + sLog.outDebug("Deleting member pointer to GUID: %u from group %u", group_id, guid); + CreatureGroupHolder[group_id]->RemoveMember(guid); + + if(CreatureGroupHolder[group_id]->isEmpty()) + { + sLog.outDebug("Deleting group %u", group_id); + delete CreatureGroupHolder[group_id]; + CreatureGroupHolder.erase(group_id); + } + } +} + +void CreatureGroupManager::LoadCreatureFormations() +{ + //Clear existing map + CreatureGroupMap.clear(); + + //Check Integrity of the table + QueryResult *result = WorldDatabase.PQuery("SELECT MAX(`leader`) FROM `creature_formations`"); + + if(!result) + { + sLog.outErrorDb(" an error occured while loading the table `creature_formations` ( maybe it doesn't exist ?)\n"); + return; + } + + delete result; + + //Get data + result = WorldDatabase.PQuery("SELECT `leader`, `follower`, `dist`, `angle`, `groupAI` FROM `creature_formations` ORDER BY `leader`"); + + if(!result) + { + sLog.outErrorDb("The table `creature_formations` is empty or corrupted"); + return; + } + + uint32 total_records = result->GetRowCount(); + + barGoLink bar( total_records); + Field *fields; + uint32 count = 0, lastLeaderGUID = 0; + + FormationMember *group_member; + //Loading data... + do + { + fields = result->Fetch(); + + bar.step(); + count++; + + group_member = new FormationMember; + + group_member->leaderGUID = fields[0].GetUInt32(); + group_member->followerGUID = fields[1].GetUInt32(); + group_member->follow_dist = fields[2].GetUInt32(); + group_member->follow_angle = fields[3].GetUInt32(); + group_member->groupAI = fields[4].GetUInt8(); + + CreatureGroupMap[group_member->followerGUID] = group_member; + + if(lastLeaderGUID != group_member->leaderGUID) + { + lastLeaderGUID = group_member->leaderGUID; + CreatureGroupMap[lastLeaderGUID] = group_member; + } + } + while(result->NextRow()) ; + + delete result; + + sLog.outString(); + sLog.outString( ">> Loaded %u creatures in formations", count ); + sLog.outString(); +} + +void CreatureGroup::AddMember(Creature *member) +{ + sLog.outDebug("Adding unit GUID: %u.", member->GetGUIDLow()); + + uint64 guid = member->GetGUID(); + //We first search creature member if exist + if(CreatureGroupMembers.find(guid) != CreatureGroupMembers.end()) + return; + //Check is that shit is a leader + if(member->IsFormationLeader()) + { + sLog.outDebug("Unit GUID: %u is formation leader. Adding group.", member->GetGUIDLow()); + m_leader = member; + } + //Add to the club + CreatureGroupMembers[guid] = member; + sLog.outDebug("Unit GUID: %u added.", member->GetGUID()); +} + +void CreatureGroup::RemoveMember(uint64 guid) +{ + if(CreatureGroupMembers.find(guid) != CreatureGroupMembers.end()) + CreatureGroupMembers.erase(guid); +} + +void CreatureGroup::MemberHasAttacked(Creature *member) +{ + uint8 groupAI = CreatureGroupMap[member->GetGUIDLow()]->groupAI;; + + for(UNORDERED_MAP<uint64, Creature*>::iterator itr = CreatureGroupMembers.begin(); itr != CreatureGroupMembers.end(); itr++) + { + sLog.outDebug("AI:%u:Group member found: %u, attacked by %s.", groupAI, itr->second->GetGUIDLow(), member->getVictim()->GetName()); + if(itr->second) + { + switch(groupAI) + { + case 0: + return; + case 1: + if(!member->IsFormationLeader()) + return; + } + //Attack if everything is OK + itr->second->AI()->AttackStart(member->getVictim()); + } + } +} + +void CreatureGroup::LeaderMovedInEvade() +{ + for(UNORDERED_MAP<uint64, Creature*>::iterator itr = CreatureGroupMembers.begin(); itr != CreatureGroupMembers.end(); itr++) + { + if(itr->second && itr->second->isAlive() && !itr->second->isInCombat() && !itr->second->getVictim()) + SetMemberDestination(itr->second); + } +} + +void CreatureGroup::SetMemberDestination(Creature *member) +{ + if(!member || !m_leader || member->IsFormationLeader()) + return; + + float x,y,z; + uint32 lowguid = member->GetGUIDLow(); + + UNORDERED_MAP<uint32, FormationMember*>::iterator itr2 = CreatureGroupMap.find(lowguid); + + if(m_leader->GetMotionMaster()->GetDestination(x,y,z) && itr2 != CreatureGroupMap.end()) + { + float dist, angle, pathangle; + + angle = CreatureGroupMap[lowguid]->follow_angle; + dist = CreatureGroupMap[lowguid]->follow_dist; + pathangle = atan2(m_leader->GetPositionY()-y, m_leader->GetPositionX()-x); + + x = x+cos(angle+pathangle)*dist; + y = y+sin(angle+pathangle)*dist; + + member->GetMotionMaster()->Clear(); + + if(member->GetDistance(m_leader) < dist+MAX_DESYNC) + member->SetUnitMovementFlags(m_leader->GetUnitMovementFlags()); + else + member->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); + + member->GetMotionMaster()->MovePoint(0, x, y, z); + } +}
\ No newline at end of file diff --git a/src/game/CreatureGroups.h b/src/game/CreatureGroups.h new file mode 100644 index 00000000000..fa846563205 --- /dev/null +++ b/src/game/CreatureGroups.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/> + * + * Copyright (C) 2008 Trinity <http://www.trinitycore.org/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _FORMATIONS_H +#define _FORMATIONS_H + +#include <map> +#include "Creature.h" +#include "Policies/Singleton.h" + +struct FormationMember +{ + float follow_dist; + float follow_angle; + uint32 followerGUID; + uint32 leaderGUID; + uint8 groupAI; +}; + +class CreatureGroupManager +{ + public: + void UpdateCreatureGroup(uint32 group_id, Creature *member); + void DestroyGroup(uint32 group_id, uint64 guid); + void LoadCreatureFormations(); +}; + +class CreatureGroup +{ + UNORDERED_MAP<uint64, Creature*>CreatureGroupMembers; + Creature *m_leader; //Important do not forget sometimes to work with pointers instead synonims :D:D + + public: + CreatureGroup() : m_leader(NULL) {} + ~CreatureGroup(){sLog.outDebug("Destroying group");} + void AddMember(Creature *); + void RemoveMember(uint64 guid); + void LeaderMovedInEvade(); + void MemberHasAttacked(Creature *); + void SetMemberDestination(Creature *); + bool isEmpty() {return CreatureGroupMembers.empty();} +}; + +extern UNORDERED_MAP<uint32, CreatureGroup*> CreatureGroupHolder; +extern UNORDERED_MAP<uint32, FormationMember*> CreatureGroupMap; + +#define formation_mgr Trinity::Singleton<CreatureGroupManager>::Instance() + +#endif
\ No newline at end of file diff --git a/src/game/Traveller.h b/src/game/Traveller.h index 4a70353e7c0..9611f2ea6e6 100644 --- a/src/game/Traveller.h +++ b/src/game/Traveller.h @@ -25,6 +25,7 @@ #include "Creature.h" #include "Player.h" #include <cassert> +#include "CreatureGroups.h" /** Traveller is a wrapper for units (creatures or players) that * travel from point A to point B using the destination holder. @@ -78,7 +79,11 @@ inline void Traveller<Creature>::Relocation(float x, float y, float z, float ori template<> inline void Traveller<Creature>::MoveTo(float x, float y, float z, uint32 t) { - i_traveller.AI_SendMoveToPacket(x, y, z, t, i_traveller.GetUnitMovementFlags(), 0); + //Call for creature group update + if(i_traveller.IsFormationLeader() && !i_traveller.isInCombat()) + CreatureGroupHolder[i_traveller.GetFormationID()]->LeaderMovedInEvade(); + + i_traveller.AI_SendMoveToPacket(x, y, z, t, i_traveller.GetUnitMovementFlags(), 0); } // specialization for players diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index 414c0afa836..6dcc96500cc 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -46,6 +46,7 @@ #include "GridNotifiersImpl.h" #include "CellImpl.h" #include "Path.h" +#include "CreatureGroups.h" #include <math.h> @@ -9686,6 +9687,10 @@ void Unit::CombatStart(Unit* target) if(!target->IsStandState() && !target->hasUnitState(UNIT_STAT_STUNNED)) target->SetStandState(PLAYER_STATE_NONE); + //Call creature group update + if(GetTypeId()==TYPEID_UNIT && ((Creature *)this)->GetFormationID()) + CreatureGroupHolder[((Creature *)this)->GetFormationID()]->MemberHasAttacked(((Creature *)this)); + if(!target->isInCombat() && target->GetTypeId() != TYPEID_PLAYER && !((Creature*)target)->HasReactState(REACT_PASSIVE) && ((Creature*)target)->AI()) { diff --git a/src/game/World.cpp b/src/game/World.cpp index 6ab82fffed2..7d4be651077 100644 --- a/src/game/World.cpp +++ b/src/game/World.cpp @@ -62,6 +62,7 @@ #include "GMTicketMgr.h" #include "Util.h" #include "Language.h" +#include "CreatureGroups.h" INSTANTIATE_SINGLETON_1( World ); @@ -1257,7 +1258,10 @@ void World::SetInitialWorldSettings() sLog.outString( "Loading Waypoints..." ); WaypointMgr.Load(); - sLog.outString( "Loading GM tickets..."); + sLog.outString( "Loading Creature Formations..." ); + formation_mgr.LoadCreatureFormations(); + + sLog.outString( "Loading GM tickets..."); ticketmgr.LoadGMTickets(); ///- Handle outdated emails (delete/return) diff --git a/win/VC90/game.vcproj b/win/VC90/game.vcproj index 89f4341ebc6..a6497190443 100644 --- a/win/VC90/game.vcproj +++ b/win/VC90/game.vcproj @@ -520,7 +520,7 @@ > </File> <File - RelativePath="..\..\src\game\GMTicketHandler.cpp" + RelativePath="..\..\src\game\GMTicketHandler.cpp" > </File> <File @@ -638,7 +638,7 @@ <File RelativePath="..\..\src\game\MapRefManager.h" > - </File> + </File> <File RelativePath="..\..\src\game\MiscHandler.cpp" > @@ -952,6 +952,14 @@ > </File> <File + RelativePath="..\..\src\game\CreatureGroups.cpp" + > + </File> + <File + RelativePath="..\..\src\game\CreatureGroups.h" + > + </File> + <File RelativePath="..\..\src\game\DestinationHolder.cpp" > </File> |