[10932] Imporvments gameevent creature morphing.

* Table `game_event_model_equip` renamed to `game_event_creature_data`
* Table allow now store same creatures for different events, BUT
  expected that related events no active in same time.
* Added possibility switch entry at gameevent time.
  This let have diff factions/loot and etc for creatures.
* Added possibility cast spells at gameevent start/end.
  Exist some spells that expected casted to creature at gameevent start
  for model replace, and for animation in other cases.

Note: `game_event_creature_data`.`modelid` field posisble will removed soon in fowor related spell use.
      Ofc, when spells will implemented in core.
This commit is contained in:
VladimirMangos 2010-12-28 23:32:57 +03:00
parent e52ebaf7a9
commit d38df50a7e
11 changed files with 145 additions and 55 deletions

View file

@ -24,7 +24,7 @@ CREATE TABLE `db_version` (
`version` varchar(120) default NULL,
`creature_ai_version` varchar(120) default NULL,
`cache_id` int(10) default '0',
`required_10906_02_mangos_spell_bonus_data` bit(1) default NULL
`required_10932_01_mangos_game_event_creature_data` bit(1) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Used DB version notes';
--
@ -1649,6 +1649,31 @@ LOCK TABLES `game_event_creature` WRITE;
/*!40000 ALTER TABLE `game_event_creature` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `game_event_creature_data`
--
DROP TABLE IF EXISTS `game_event_creature_data`;
CREATE TABLE `game_event_creature_data` (
`guid` int(10) unsigned NOT NULL default '0',
`entry_id` mediumint(8) unsigned NOT NULL default '0',
`modelid` mediumint(8) unsigned NOT NULL default '0',
`equipment_id` mediumint(8) unsigned NOT NULL default '0',
`spell_start` mediumint(8) unsigned NOT NULL default '0',
`spell_end` mediumint(8) unsigned NOT NULL default '0',
`event` smallint(5) unsigned NOT NULL default '0',
PRIMARY KEY (`guid`,`event`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
--
-- Dumping data for table `game_event_creature_data`
--
LOCK TABLES `game_event_model_equip` WRITE;
/*!40000 ALTER TABLE `game_event_creature_data` DISABLE KEYS */;
/*!40000 ALTER TABLE `game_event_creature_data` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `game_event_gameobject`
--
@ -1669,28 +1694,6 @@ LOCK TABLES `game_event_gameobject` WRITE;
/*!40000 ALTER TABLE `game_event_gameobject` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `game_event_model_equip`
--
DROP TABLE IF EXISTS `game_event_model_equip`;
CREATE TABLE `game_event_model_equip` (
`guid` int(10) unsigned NOT NULL default '0',
`modelid` mediumint(8) unsigned NOT NULL default '0',
`equipment_id` mediumint(8) unsigned NOT NULL default '0',
`event` smallint(5) unsigned NOT NULL default '0',
PRIMARY KEY (`guid`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
--
-- Dumping data for table `game_event_model_equip`
--
LOCK TABLES `game_event_model_equip` WRITE;
/*!40000 ALTER TABLE `game_event_model_equip` DISABLE KEYS */;
/*!40000 ALTER TABLE `game_event_model_equip` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `game_event_quest`
--

View file

@ -0,0 +1,14 @@
ALTER TABLE db_version CHANGE COLUMN required_10906_02_mangos_spell_bonus_data required_10932_01_mangos_game_event_creature_data bit;
DROP TABLE IF EXISTS game_event_creature_data;
RENAME TABLE game_event_model_equip TO game_event_creature_data;
ALTER TABLE game_event_creature_data
ADD COLUMN entry_id mediumint(8) unsigned NOT NULL default '0' AFTER guid,
ADD COLUMN spell_start mediumint(8) unsigned NOT NULL default '0' AFTER equipment_id,
ADD COLUMN spell_end mediumint(8) unsigned NOT NULL default '0' AFTER spell_start;
ALTER TABLE game_event_creature_data
DROP PRIMARY KEY,
ADD PRIMARY KEY (`guid`,`event`);

View file

@ -138,6 +138,7 @@ pkgdata_DATA = \
10883_01_mangos_spell_proc_event.sql \
10906_01_mangos_spell_proc_event.sql \
10906_02_mangos_spell_bonus_data.sql \
10932_01_mangos_game_event_creature_data.sql \
README
## Additional files to include when running 'make dist'
@ -256,4 +257,5 @@ EXTRA_DIST = \
10883_01_mangos_spell_proc_event.sql \
10906_01_mangos_spell_proc_event.sql \
10906_02_mangos_spell_bonus_data.sql \
10932_01_mangos_game_event_creature_data.sql \
README

View file

@ -200,6 +200,10 @@ void Creature::RemoveCorpse()
*/
bool Creature::InitEntry(uint32 Entry, CreatureData const* data /*=NULL*/, GameEventCreatureData const* eventData /*=NULL*/ )
{
// use game event entry if any instead default suggested
if (eventData && eventData->entry_id)
Entry = eventData->entry_id;
CreatureInfo const *normalInfo = ObjectMgr::GetCreatureTemplate(Entry);
if(!normalInfo)
{
@ -357,6 +361,10 @@ bool Creature::UpdateEntry(uint32 Entry, Team team, const CreatureData *data /*=
for(int i = 0; i < CREATURE_MAX_SPELLS; ++i)
m_spells[i] = GetCreatureInfo()->spells[i];
// if eventData set then event active and need apply spell_start
if (eventData)
ApplyGameEventSpells(eventData, true);
return true;
}
@ -447,7 +455,11 @@ void Creature::Update(uint32 update_diff, uint32 diff)
lootForSkin = false;
if(m_originalEntry != GetEntry())
UpdateEntry(m_originalEntry);
{
// need preserver gameevent state
GameEventCreatureData const* eventData = sGameEventMgr.GetCreatureUpdateDataForActiveEvent(GetDBTableGUIDLow());
UpdateEntry(m_originalEntry, TEAM_NONE, NULL, eventData);
}
CreatureInfo const *cinfo = GetCreatureInfo();
@ -1351,7 +1363,7 @@ void Creature::DeleteFromDB()
WorldDatabase.PExecuteLog("DELETE FROM creature_addon WHERE guid = '%u'", m_DBTableGuid);
WorldDatabase.PExecuteLog("DELETE FROM creature_movement WHERE id = '%u'", m_DBTableGuid);
WorldDatabase.PExecuteLog("DELETE FROM game_event_creature WHERE guid = '%u'", m_DBTableGuid);
WorldDatabase.PExecuteLog("DELETE FROM game_event_model_equip WHERE guid = '%u'", m_DBTableGuid);
WorldDatabase.PExecuteLog("DELETE FROM game_event_creature_data WHERE guid = '%u'", m_DBTableGuid);
WorldDatabase.PExecuteLog("DELETE FROM creature_battleground WHERE guid = '%u'", m_DBTableGuid);
WorldDatabase.CommitTransaction();
}
@ -2344,3 +2356,17 @@ void Creature::RelocationNotify()
float radius = MAX_CREATURE_ATTACK_RADIUS * sWorld.getConfig(CONFIG_FLOAT_RATE_CREATURE_AGGRO);
Cell::VisitAllObjects(this, relocationNotifier, radius);
}
void Creature::ApplyGameEventSpells(GameEventCreatureData const* eventData, bool activated)
{
uint32 cast_spell = activated ? eventData->spell_id_start : eventData->spell_id_end;
uint32 remove_spell = activated ? eventData->spell_id_end : eventData->spell_id_start;
if (remove_spell)
if (SpellEntry const* spellEntry = sSpellStore.LookupEntry(remove_spell))
if (IsSpellAppliesAura(spellEntry))
RemoveAurasDueToSpell(remove_spell);
if (cast_spell)
CastSpell(this, cast_spell, true);
}

View file

@ -502,6 +502,8 @@ class MANGOS_DLL_SPEC Creature : public Unit
bool HasSpell(uint32 spellID) const;
bool UpdateEntry(uint32 entry, Team team = ALLIANCE, const CreatureData* data = NULL, GameEventCreatureData const* eventData = NULL, bool preserveHPAndPower = true);
void ApplyGameEventSpells(GameEventCreatureData const* eventData, bool activated);
bool UpdateStats(Stats stat);
bool UpdateAllStats();
void UpdateResistances(uint32 school);

View file

@ -26,6 +26,7 @@
#include "Log.h"
#include "MapManager.h"
#include "BattleGroundMgr.h"
#include "SpellMgr.h"
#include "Policies/SingletonImp.h"
INSTANTIATE_SINGLETON_1(GameEventMgr);
@ -345,10 +346,12 @@ void GameEventMgr::LoadFromDB()
mGameEventCreatureData.resize(mGameEvent.size());
// 0 1 2
result = WorldDatabase.Query("SELECT creature.guid, game_event_model_equip.event, game_event_model_equip.modelid,"
// 3
"game_event_model_equip.equipment_id "
"FROM creature JOIN game_event_model_equip ON creature.guid=game_event_model_equip.guid");
result = WorldDatabase.Query("SELECT creature.guid, game_event_creature_data.event, game_event_creature_data.modelid,"
// 3 4
"game_event_creature_data.equipment_id, game_event_creature_data.entry_id, "
// 5 6
"game_event_creature_data.spell_start, game_event_creature_data.spell_end "
"FROM creature JOIN game_event_creature_data ON creature.guid=game_event_creature_data.guid");
count = 0;
if( !result )
@ -357,7 +360,7 @@ void GameEventMgr::LoadFromDB()
bar.step();
sLog.outString();
sLog.outString(">> Loaded %u model/equipment changes in game events", count );
sLog.outString(">> Loaded %u creature reactions at game events", count );
}
else
{
@ -371,35 +374,59 @@ void GameEventMgr::LoadFromDB()
uint32 guid = fields[0].GetUInt32();
uint16 event_id = fields[1].GetUInt16();
if(event_id==0)
{
sLog.outErrorDb("`game_event_creature_data` game event id (%i) is reserved and can't be used.",event_id);
continue;
}
if(event_id >= mGameEventCreatureData.size())
{
sLog.outErrorDb("`game_event_model_equip` game event id (%u) is out of range compared to max event id in `game_event`",event_id);
sLog.outErrorDb("`game_event_creature_data` game event id (%u) is out of range compared to max event id in `game_event`",event_id);
continue;
}
++count;
GameEventCreatureDataList& equiplist = mGameEventCreatureData[event_id];
GameEventCreatureData newModelEquipSet;
newModelEquipSet.modelid = fields[2].GetUInt32();
newModelEquipSet.equipment_id = fields[3].GetUInt32();
GameEventCreatureData newData;
newData.modelid = fields[2].GetUInt32();
newData.equipment_id = fields[3].GetUInt32();
newData.entry_id = fields[4].GetUInt32();
newData.spell_id_start = fields[5].GetUInt32();
newData.spell_id_end = fields[6].GetUInt32();
if(newModelEquipSet.equipment_id > 0)
if (newData.equipment_id && !sObjectMgr.GetEquipmentInfo(newData.equipment_id))
{
if(!sObjectMgr.GetEquipmentInfo(newModelEquipSet.equipment_id))
{
sLog.outErrorDb("Table `game_event_model_equip` have creature (Guid: %u) with equipment_id %u not found in table `creature_equip_template`, set to no equipment.", guid, newModelEquipSet.equipment_id);
continue;
}
sLog.outErrorDb("Table `game_event_creature_data` have creature (Guid: %u) with equipment_id %u not found in table `creature_equip_template`, set to no equipment.", guid, newData.equipment_id);
newData.equipment_id = 0;
}
equiplist.push_back(GameEventCreatureDataPair(guid, newModelEquipSet));
mGameEventCreatureDataPerGuid[guid] = event_id;
if (newData.entry_id && !sObjectMgr.GetCreatureTemplate(newData.entry_id))
{
sLog.outErrorDb("Table `game_event_creature_data` have creature (Guid: %u) with event time entry %u not found in table `creature_template`, set to no 0.", guid, newData.entry_id);
newData.entry_id = 0;
}
if (newData.spell_id_start && !sSpellStore.LookupEntry(newData.spell_id_start))
{
sLog.outErrorDb("Table `game_event_creature_data` have creature (Guid: %u) with nonexistent spell_start %u, set to no start spell.", guid, newData.spell_id_start);
newData.spell_id_start = 0;
}
if (newData.spell_id_end && !sSpellStore.LookupEntry(newData.spell_id_end))
{
sLog.outErrorDb("Table `game_event_creature_data` have creature (Guid: %u) with nonexistent spell_end %u, set to no end spell.", guid, newData.spell_id_end);
newData.spell_id_end = 0;
}
equiplist.push_back(GameEventCreatureDataPair(guid, newData));
mGameEventCreatureDataPerGuid.insert(GameEventCreatureDataPerGuidMap::value_type(guid, event_id));
} while( result->NextRow() );
delete result;
sLog.outString();
sLog.outString( ">> Loaded %u model/equipment changes in game events", count );
sLog.outString(">> Loaded %u creature reactions at game events", count );
}
mGameEventQuests.resize(mGameEvent.size());
@ -726,15 +753,22 @@ void GameEventMgr::GameEventUnspawn(int16 event_id)
}
}
GameEventCreatureData const* GameEventMgr::GetCreatureUpdateDataForActiveEvent(uint32 lowguid) const
{
// only for active event
GameEventCreatureDataPerGuidMap::const_iterator itr = mGameEventCreatureDataPerGuid.find(lowguid);
if (itr == mGameEventCreatureDataPerGuid.end() || !IsActiveEvent(itr->second))
return NULL;
// only for active event, creature can be listed for many so search all
uint32 event_id = 0;
GameEventCreatureDataPerGuidBounds bounds = mGameEventCreatureDataPerGuid.equal_range(lowguid);
for(GameEventCreatureDataPerGuidMap::const_iterator itr = bounds.first; itr != bounds.second; ++itr)
{
if (IsActiveEvent(itr->second))
{
event_id = itr->second;
break;
}
}
uint32 event_id = itr->second;
if (!event_id)
return NULL;
for(GameEventCreatureDataList::const_iterator itr = mGameEventCreatureData[event_id].begin();itr != mGameEventCreatureData[event_id].end();++itr)
if (itr->first == lowguid)
@ -754,7 +788,13 @@ void GameEventMgr::UpdateCreatureData(int16 event_id, bool activate)
// Update if spawned
if (Creature* pCreature = ObjectAccessor::GetCreatureInWorld(ObjectGuid(HIGHGUID_UNIT, data->id, itr->first)))
{
pCreature->UpdateEntry(data->id, TEAM_NONE, data, activate ? &itr->second : NULL);
// spells not casted for event remove case (sent NULL into update), do it
if (!activate)
pCreature->ApplyGameEventSpells(&itr->second, false);
}
}
}

View file

@ -44,8 +44,11 @@ struct GameEventData
struct GameEventCreatureData
{
uint32 entry_id;
uint32 modelid;
uint32 equipment_id;
uint32 spell_id_start;
uint32 spell_id_end;
};
typedef std::pair<uint32, GameEventCreatureData> GameEventCreatureDataPair;
@ -79,7 +82,6 @@ class GameEventMgr
void GameEventSpawn(int16 event_id);
void GameEventUnspawn(int16 event_id);
void UpdateCreatureData(int16 event_id, bool activate);
void UpdateEventQuests(uint16 event_id, bool Activate);
void UpdateWorldStates(uint16 event_id, bool Activate);
protected:
@ -89,7 +91,8 @@ class GameEventMgr
typedef std::vector<IdList> GameEventIdMap;
typedef std::list<GameEventCreatureDataPair> GameEventCreatureDataList;
typedef std::vector<GameEventCreatureDataList> GameEventCreatureDataMap;
typedef UNORDERED_MAP<uint32, uint32> GameEventCreatureDataPerGuidMap;
typedef std::multimap<uint32, uint32> GameEventCreatureDataPerGuidMap;
typedef std::pair<GameEventCreatureDataPerGuidMap::const_iterator,GameEventCreatureDataPerGuidMap::const_iterator> GameEventCreatureDataPerGuidBounds;
typedef std::list<uint32> QuestList;
typedef std::vector<QuestList> GameEventQuestMap;

View file

@ -3833,7 +3833,7 @@ bool ChatHandler::HandleAuraCommand(char* args)
if (!spellInfo)
return false;
if (!IsSpellAppliesAura(spellInfo, (1 << EFFECT_INDEX_0) | (1 << EFFECT_INDEX_1) | (1 << EFFECT_INDEX_2)) &&
if (!IsSpellAppliesAura(spellInfo) &&
!IsSpellHaveEffect(spellInfo, SPELL_EFFECT_PERSISTENT_AREA_AURA))
{
PSendSysMessage(LANG_SPELL_NO_HAVE_AURAS, spellID);

View file

@ -119,7 +119,7 @@ inline bool IsSpellHaveEffect(SpellEntry const *spellInfo, SpellEffects effect)
return false;
}
inline bool IsSpellAppliesAura(SpellEntry const *spellInfo, uint32 effectMask)
inline bool IsSpellAppliesAura(SpellEntry const *spellInfo, uint32 effectMask = ((1 << EFFECT_INDEX_0) | (1 << EFFECT_INDEX_1) | (1 << EFFECT_INDEX_2)))
{
for(int i = 0; i < MAX_EFFECT_INDEX; ++i)
{

View file

@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__
#define __REVISION_NR_H__
#define REVISION_NR "10931"
#define REVISION_NR "10932"
#endif // __REVISION_NR_H__

View file

@ -1,6 +1,6 @@
#ifndef __REVISION_SQL_H__
#define __REVISION_SQL_H__
#define REVISION_DB_CHARACTERS "required_10862_01_characters_mail"
#define REVISION_DB_MANGOS "required_10906_02_mangos_spell_bonus_data"
#define REVISION_DB_MANGOS "required_10932_01_mangos_game_event_creature_data"
#define REVISION_DB_REALMD "required_10008_01_realmd_realmd_db_version"
#endif // __REVISION_SQL_H__