From d38df50a7e6b0f30955d91e4ba538ca1480e4d34 Mon Sep 17 00:00:00 2001 From: VladimirMangos Date: Tue, 28 Dec 2010 23:32:57 +0300 Subject: [PATCH] [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. --- sql/mangos.sql | 49 ++++++----- ...932_01_mangos_game_event_creature_data.sql | 14 +++ sql/updates/Makefile.am | 2 + src/game/Creature.cpp | 30 ++++++- src/game/Creature.h | 2 + src/game/GameEventMgr.cpp | 88 ++++++++++++++----- src/game/GameEventMgr.h | 7 +- src/game/Level3.cpp | 2 +- src/game/SpellMgr.h | 2 +- src/shared/revision_nr.h | 2 +- src/shared/revision_sql.h | 2 +- 11 files changed, 145 insertions(+), 55 deletions(-) create mode 100644 sql/updates/10932_01_mangos_game_event_creature_data.sql diff --git a/sql/mangos.sql b/sql/mangos.sql index 4ccf99acb..6036625ac 100644 --- a/sql/mangos.sql +++ b/sql/mangos.sql @@ -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` -- diff --git a/sql/updates/10932_01_mangos_game_event_creature_data.sql b/sql/updates/10932_01_mangos_game_event_creature_data.sql new file mode 100644 index 000000000..c64910dd9 --- /dev/null +++ b/sql/updates/10932_01_mangos_game_event_creature_data.sql @@ -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`); diff --git a/sql/updates/Makefile.am b/sql/updates/Makefile.am index e37f3fc2e..e4e6ac156 100644 --- a/sql/updates/Makefile.am +++ b/sql/updates/Makefile.am @@ -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 diff --git a/src/game/Creature.cpp b/src/game/Creature.cpp index 1e873c8e7..fec894a0c 100644 --- a/src/game/Creature.cpp +++ b/src/game/Creature.cpp @@ -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); +} diff --git a/src/game/Creature.h b/src/game/Creature.h index e5f59cd3e..06ea1f538 100644 --- a/src/game/Creature.h +++ b/src/game/Creature.h @@ -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); diff --git a/src/game/GameEventMgr.cpp b/src/game/GameEventMgr.cpp index 6895930b5..3ac5978d3 100644 --- a/src/game/GameEventMgr.cpp +++ b/src/game/GameEventMgr.cpp @@ -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); + } } } diff --git a/src/game/GameEventMgr.h b/src/game/GameEventMgr.h index 030e8a2a9..cbc814454 100644 --- a/src/game/GameEventMgr.h +++ b/src/game/GameEventMgr.h @@ -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 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 GameEventIdMap; typedef std::list GameEventCreatureDataList; typedef std::vector GameEventCreatureDataMap; - typedef UNORDERED_MAP GameEventCreatureDataPerGuidMap; + typedef std::multimap GameEventCreatureDataPerGuidMap; + typedef std::pair GameEventCreatureDataPerGuidBounds; typedef std::list QuestList; typedef std::vector GameEventQuestMap; diff --git a/src/game/Level3.cpp b/src/game/Level3.cpp index 8963e34b9..335bac715 100644 --- a/src/game/Level3.cpp +++ b/src/game/Level3.cpp @@ -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); diff --git a/src/game/SpellMgr.h b/src/game/SpellMgr.h index 21030e311..04449685b 100644 --- a/src/game/SpellMgr.h +++ b/src/game/SpellMgr.h @@ -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) { diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 5fabe2352..8c6a12d08 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "10931" + #define REVISION_NR "10932" #endif // __REVISION_NR_H__ diff --git a/src/shared/revision_sql.h b/src/shared/revision_sql.h index 6db97692f..58ec3aef8 100644 --- a/src/shared/revision_sql.h +++ b/src/shared/revision_sql.h @@ -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__