*Creature formations implemented.
--HG-- branch : trunk
This commit is contained in:
@@ -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 */;
|
||||
+18
-2
@@ -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 )
|
||||
|
||||
+9
-1
@@ -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())
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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())
|
||||
{
|
||||
|
||||
+5
-1
@@ -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)
|
||||
|
||||
+10
-2
@@ -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"
|
||||
>
|
||||
@@ -951,6 +951,14 @@
|
||||
RelativePath="..\..\src\game\CreatureAISelector.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\game\CreatureGroups.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\game\CreatureGroups.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\game\DestinationHolder.cpp"
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user