*Creature formations implemented.

--HG--
branch : trunk
This commit is contained in:
2008-12-15 00:07:21 +02:00
parent d1fc67b44e
commit 9948e98703
9 changed files with 369 additions and 7 deletions
+32
View File
@@ -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 */;
+17 -1
View File
@@ -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()
{
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 )
+8
View File
@@ -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);
@@ -679,6 +684,9 @@ class TRINITY_DLL_SPEC Creature : public Unit
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())
};
+218
View File
@@ -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);
}
}
+66
View File
@@ -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
+5
View File
@@ -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,6 +79,10 @@ 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)
{
//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);
}
+5
View File
@@ -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())
{
+4
View File
@@ -62,6 +62,7 @@
#include "GMTicketMgr.h"
#include "Util.h"
#include "Language.h"
#include "CreatureGroups.h"
INSTANTIATE_SINGLETON_1( World );
@@ -1257,6 +1258,9 @@ void World::SetInitialWorldSettings()
sLog.outString( "Loading Waypoints..." );
WaypointMgr.Load();
sLog.outString( "Loading Creature Formations..." );
formation_mgr.LoadCreatureFormations();
sLog.outString( "Loading GM tickets...");
ticketmgr.LoadGMTickets();
+8
View File
@@ -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"
>