diff options
author | raczman <none@none> | 2009-04-14 14:33:48 +0200 |
---|---|---|
committer | raczman <none@none> | 2009-04-14 14:33:48 +0200 |
commit | a712170758cf1b6c62352e1bede372eae8c96593 (patch) | |
tree | c6f4559af878c2f214d8d106f3b1898426cd705b /src | |
parent | 37f8ee06802e721fd0546d6c972e33700e694eaa (diff) |
Creature respawn linking, idea by Rat, wrote by Iskander, blessed by raczman.
--HG--
branch : trunk
Diffstat (limited to 'src')
-rw-r--r-- | src/game/Chat.cpp | 2 | ||||
-rw-r--r-- | src/game/Chat.h | 2 | ||||
-rw-r--r-- | src/game/Creature.cpp | 105 | ||||
-rw-r--r-- | src/game/Creature.h | 4 | ||||
-rw-r--r-- | src/game/Language.h | 3 | ||||
-rw-r--r-- | src/game/Level2.cpp | 33 | ||||
-rw-r--r-- | src/game/Level3.cpp | 11 | ||||
-rw-r--r-- | src/game/ObjectMgr.cpp | 91 | ||||
-rw-r--r-- | src/game/ObjectMgr.h | 11 | ||||
-rw-r--r-- | src/game/World.cpp | 3 |
10 files changed, 230 insertions, 35 deletions
diff --git a/src/game/Chat.cpp b/src/game/Chat.cpp index 27e54bd7bde..9671a3f89ec 100644 --- a/src/game/Chat.cpp +++ b/src/game/Chat.cpp @@ -252,6 +252,7 @@ ChatCommand * ChatHandler::getCommandTable() { "event_scripts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadEventScriptsCommand, "", NULL }, { "command", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadCommandCommand, "", NULL }, { "creature_involvedrelation", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadCreatureQuestInvRelationsCommand,"",NULL }, + { "creature_linked_respawn", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadCreatureLinkedRespawnCommand, "", NULL }, { "creature_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesCreatureCommand, "", NULL }, { "creature_questrelation", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadCreatureQuestRelationsCommand, "", NULL }, //{ "db_script_string", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadDbScriptStringCommand, "", NULL }, @@ -443,6 +444,7 @@ ChatCommand * ChatHandler::getCommandTable() { "yell", SEC_MODERATOR, false, &ChatHandler::HandleNpcYellCommand, "", NULL }, { "addtemp", SEC_GAMEMASTER, false, &ChatHandler::HandleTempAddSpwCommand, "", NULL }, { "addformation", SEC_MODERATOR, false, &ChatHandler::HandleNpcAddFormationCommand, "", NULL }, + { "setlink", SEC_MODERATOR, false, &ChatHandler::HandleNpcSetLinkCommand, "", NULL }, //{ TODO: fix or remove this commands { "name", SEC_GAMEMASTER, false, &ChatHandler::HandleNameCommand, "", NULL }, diff --git a/src/game/Chat.h b/src/game/Chat.h index 8a1d11b4886..64f923dad95 100644 --- a/src/game/Chat.h +++ b/src/game/Chat.h @@ -205,6 +205,7 @@ class ChatHandler bool HandleNpcWhisperCommand(const char* args); bool HandleNpcYellCommand(const char* args); bool HandleNpcAddFormationCommand(const char* args); + bool HandleNpcSetLinkCommand(const char* args); bool HandleReloadCommand(const char* args); bool HandleReloadAllCommand(const char* args); @@ -227,6 +228,7 @@ class ChatHandler bool HandleReloadCommandCommand(const char* args); bool HandleReloadCreatureQuestRelationsCommand(const char* args); bool HandleReloadCreatureQuestInvRelationsCommand(const char* args); + bool HandleReloadCreatureLinkedRespawnCommand(const char* args); bool HandleReloadDbScriptStringCommand(const char* args); bool HandleReloadGameGraveyardZoneCommand(const char* args); bool HandleReloadGameObjectScriptsCommand(const char* args); diff --git a/src/game/Creature.cpp b/src/game/Creature.cpp index 0681dcddd04..f8643543038 100644 --- a/src/game/Creature.cpp +++ b/src/game/Creature.cpp @@ -413,32 +413,21 @@ void Creature::Update(uint32 diff) { if( m_respawnTime <= time(NULL) ) { - DEBUG_LOG("Respawning..."); - m_respawnTime = 0; - lootForPickPocketed = false; - lootForBody = false; - - if(m_originalEntry != GetEntry()) - UpdateEntry(m_originalEntry); - - CreatureInfo const *cinfo = GetCreatureInfo(); - SelectLevel(cinfo); - - if (m_isDeadByDefault) + if(!GetLinkedCreatureRespawnTime()) // Can respawn + Respawn(); + else // the master is dead { - setDeathState(JUST_DIED); - SetHealth(0); - i_motionMaster.Clear(); - clearUnitState(UNIT_STAT_ALL_STATE); - LoadCreaturesAddon(true); + if(uint32 targetGuid = objmgr.GetLinkedRespawnGuid(m_DBTableGuid)) + { + if(targetGuid == m_DBTableGuid) // if linking self, never respawn (check delayed to next day) + SetRespawnTime(DAY); + else + m_respawnTime = GetLinkedCreatureRespawnTime()+urand(5,MINUTE); // else copy time from master and add a little + SaveRespawnTime(); // also save to DB immediately + } + else + Respawn(); } - else - setDeathState( JUST_ALIVED ); - - //Call AI respawn virtual function - AI()->JustRespawned(); - - GetMap()->Add(this); } break; } @@ -1424,7 +1413,7 @@ bool Creature::LoadFromDB(uint32 guid, Map *map) m_deathState = m_isDeadByDefault ? DEAD : ALIVE; m_respawnTime = objmgr.GetCreatureRespawnTime(m_DBTableGuid,GetInstanceId()); - if(m_respawnTime > time(NULL)) // not ready to respawn + if(m_respawnTime) // respawn on Update { m_deathState = DEAD; if(canFly()) @@ -1434,11 +1423,6 @@ bool Creature::LoadFromDB(uint32 guid, Map *map) Relocate(data->posX,data->posY,tz); } } - else if(m_respawnTime) // respawn time set but expired - { - m_respawnTime = 0; - objmgr.SaveCreatureRespawnTime(m_DBTableGuid,GetInstanceId(),0); - } uint32 curhealth = data->curhealth; if(curhealth) @@ -1709,7 +1693,33 @@ void Creature::Respawn() { if (m_DBTableGuid) objmgr.SaveCreatureRespawnTime(m_DBTableGuid,GetInstanceId(),0); - m_respawnTime = time(NULL); // respawn at next tick + + DEBUG_LOG("Respawning..."); + m_respawnTime = 0; + lootForPickPocketed = false; + lootForBody = false; + + if(m_originalEntry != GetEntry()) + UpdateEntry(m_originalEntry); + + CreatureInfo const *cinfo = GetCreatureInfo(); + SelectLevel(cinfo); + + if (m_isDeadByDefault) + { + setDeathState(JUST_DIED); + SetHealth(0); + i_motionMaster.Clear(); + clearUnitState(UNIT_STAT_ALL_STATE); + LoadCreaturesAddon(true); + } + else + setDeathState( JUST_ALIVED ); + + //Call AI respawn virtual function + AI()->JustRespawned(); + + GetMap()->Add(this); } } @@ -2323,3 +2333,36 @@ const char* Creature::GetNameForLocaleIdx(int32 loc_idx) const return GetName(); } +const CreatureData* Creature::GetLinkedRespawnCreatureData() const +{ + if(!m_DBTableGuid) // only hard-spawned creatures from DB can have a linked master + return NULL; + + if(uint32 targetGuid = objmgr.GetLinkedRespawnGuid(m_DBTableGuid)) + return objmgr.GetCreatureData(targetGuid); + + return NULL; +} + +// returns master's remaining respawn time if any +time_t Creature::GetLinkedCreatureRespawnTime() const +{ + if(!m_DBTableGuid) // only hard-spawned creatures from DB can have a linked master + return 0; + + if(uint32 targetGuid = objmgr.GetLinkedRespawnGuid(m_DBTableGuid)) + { + Map* targetMap = NULL; + if(const CreatureData* data = objmgr.GetCreatureData(targetGuid)) + { + if(data->mapid == GetMapId()) // look up on the same map + targetMap = GetMap(); + else // it shouldn't be instanceable map here + targetMap = MapManager::Instance().FindMap(data->mapid); + } + if(targetMap) + return objmgr.GetCreatureRespawnTime(targetGuid,targetMap->GetInstanceId()); + } + + return 0; +}
\ No newline at end of file diff --git a/src/game/Creature.h b/src/game/Creature.h index 0930fe00701..078edb7d865 100644 --- a/src/game/Creature.h +++ b/src/game/Creature.h @@ -594,6 +594,10 @@ class TRINITY_DLL_SPEC Creature : public Unit float GetRespawnRadius() const { return m_respawnradius; } void SetRespawnRadius(float dist) { m_respawnradius = dist; } + // Linked Creature Respawning System + time_t GetLinkedCreatureRespawnTime() const; + const CreatureData* GetLinkedRespawnCreatureData() const; + uint32 m_groupLootTimer; // (msecs)timer used for group loot uint64 lootingGroupLeaderGUID; // used to find group which is looting corpse diff --git a/src/game/Language.h b/src/game/Language.h index a1b1b3bf1b7..03c485a4b02 100644 --- a/src/game/Language.h +++ b/src/game/Language.h @@ -679,8 +679,9 @@ enum TrinityStrings LANG_BG_AV_H_NEAR_LOSE = 747, LANG_BG_AV_H_CAPTAIN_DEAD = 748, LANG_BG_AV_A_CAPTAIN_DEAD = 749, + LANG_NPCINFO_LINKGUID = 750, - // Room for BG/ARENA 750-769 not used + // Room for BG/ARENA 751-769 not used LANG_ARENA_TESTING = 785, diff --git a/src/game/Level2.cpp b/src/game/Level2.cpp index 26a701fc507..f79b8d9f04c 100644 --- a/src/game/Level2.cpp +++ b/src/game/Level2.cpp @@ -4054,3 +4054,36 @@ bool ChatHandler::HandleNpcAddFormationCommand(const char* args) return true; } +bool ChatHandler::HandleNpcSetLinkCommand(const char* args)
+{
+ if (!*args)
+ return false;
+
+ uint32 linkguid = (uint32) atoi((char*)args);
+
+ Creature* pCreature = getSelectedCreature();
+
+ if(!pCreature)
+ {
+ SendSysMessage(LANG_SELECT_CREATURE);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ if(!pCreature->GetDBTableGUIDLow())
+ {
+ PSendSysMessage("Selected creature isn't in `creature` table", pCreature->GetGUIDLow());
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ if(!objmgr.SetCreatureLinkedRespawn(pCreature->GetDBTableGUIDLow(), linkguid))
+ {
+ PSendSysMessage("Selected creature can't link with guid '%u'", linkguid);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ PSendSysMessage("LinkGUID '%u' added to creature with DBTableGUID: '%u'", linkguid, pCreature->GetDBTableGUIDLow());
+ return true;
+}
\ No newline at end of file diff --git a/src/game/Level3.cpp b/src/game/Level3.cpp index 73d1fa1e5c7..128971f0153 100644 --- a/src/game/Level3.cpp +++ b/src/game/Level3.cpp @@ -695,6 +695,14 @@ bool ChatHandler::HandleReloadCreatureQuestRelationsCommand(const char*) return true; } +bool ChatHandler::HandleReloadCreatureLinkedRespawnCommand(const char* args) +{ + sLog.outString( "Loading Linked Respawns... (`creature_linked_respawn`)" ); + objmgr.LoadCreatureLinkedRespawn(); + SendGlobalGMSysMessage("DB table `creature_linked_respawn` (creature linked respawns) reloaded."); + return true; +} + bool ChatHandler::HandleReloadCreatureQuestInvRelationsCommand(const char*) { sLog.outString( "Loading Quests Relations... (`creature_involvedrelation`)" ); @@ -4244,6 +4252,9 @@ bool ChatHandler::HandleNpcInfoCommand(const char* /*args*/) PSendSysMessage(LANG_NPCINFO_LOOT, cInfo->lootid,cInfo->pickpocketLootId,cInfo->SkinLootId); PSendSysMessage(LANG_NPCINFO_DUNGEON_ID, target->GetInstanceId()); PSendSysMessage(LANG_NPCINFO_POSITION,float(target->GetPositionX()), float(target->GetPositionY()), float(target->GetPositionZ())); + if(const CreatureData* const linked = target->GetLinkedRespawnCreatureData()) + if(CreatureInfo const *master = GetCreatureInfo(linked->id)) + PSendSysMessage(LANG_NPCINFO_LINKGUID, objmgr.GetLinkedRespawnGuid(target->GetDBTableGUIDLow()), linked->id, master->Name); if ((npcflags & UNIT_NPC_FLAG_VENDOR) ) { diff --git a/src/game/ObjectMgr.cpp b/src/game/ObjectMgr.cpp index 9d4e3020cfc..408d46ceb62 100644 --- a/src/game/ObjectMgr.cpp +++ b/src/game/ObjectMgr.cpp @@ -829,6 +829,94 @@ void ObjectMgr::LoadCreatureModelInfo() } } +bool ObjectMgr::CheckCreatureLinkedRespawn(uint32 guid, uint32 linkedGuid) const +{ + const CreatureData* const slave = GetCreatureData(guid); + const CreatureData* const master = GetCreatureData(linkedGuid); + + if(!slave || !master) // they must have a corresponding entry in db + { + sLog.outError("LinkedRespawn: Creature '%u' linking to '%u' which doesn't exist",guid,linkedGuid); + return false; + } + + const MapEntry* const map = sMapStore.LookupEntry(master->mapid); + + if(master->mapid != slave->mapid // link only to same map + && (!map || map->Instanceable())) // or to unistanced world + { + sLog.outError("LinkedRespawn: Creature '%u' linking to '%u' on an unpermitted map",guid,linkedGuid); + return false; + } + + if(!(master->spawnMask & slave->spawnMask) // they must have a possibility to meet (normal/heroic difficulty) + && (!map || map->Instanceable())) + { + sLog.outError("LinkedRespawn: Creature '%u' linking to '%u' with not corresponding spawnMask",guid,linkedGuid); + return false; + } + + return true; +} + +void ObjectMgr::LoadCreatureLinkedRespawn() +{ + mCreatureLinkedRespawnMap.clear(); + QueryResult *result = WorldDatabase.Query("SELECT guid, linkedGuid FROM creature_linked_respawn ORDER BY guid ASC"); + + if(!result) + { + barGoLink bar(1); + + bar.step(); + + sLog.outString(""); + sLog.outErrorDb(">> Loaded 0 linked respawns. DB table `creature_linked_respawn` is empty."); + return; + } + + barGoLink bar(result->GetRowCount()); + + do + { + Field *fields = result->Fetch(); + bar.step(); + + uint32 guid = fields[0].GetUInt32(); + uint32 linkedGuid = fields[1].GetUInt32(); + + if(CheckCreatureLinkedRespawn(guid,linkedGuid)) + mCreatureLinkedRespawnMap[guid] = linkedGuid; + + } while (result->NextRow()); + + delete result; + + sLog.outString(); + sLog.outString( ">> Loaded %u linked respawns", mCreatureLinkedRespawnMap.size() ); +} + +bool ObjectMgr::SetCreatureLinkedRespawn(uint32 guid, uint32 linkedGuid) +{ + if(!guid) + return false; + + if(!linkedGuid) // we're removing the linking + { + mCreatureLinkedRespawnMap.erase(guid); + WorldDatabase.DirectPExecute("DELETE FROM `creature_linked_respawn` WHERE `guid` = '%u'",guid); + return true; + } + + if(CheckCreatureLinkedRespawn(guid,linkedGuid)) // we add/change linking + { + mCreatureLinkedRespawnMap[guid] = linkedGuid; + WorldDatabase.DirectPExecute("REPLACE INTO `creature_linked_respawn`(`guid`,`linkedGuid`) VALUES ('%u','%u')",guid,linkedGuid); + return true; + } + return false; +} + void ObjectMgr::LoadCreatures() { uint32 count = 0; @@ -1089,9 +1177,6 @@ void ObjectMgr::RemoveGameobjectFromGrid(uint32 guid, GameObjectData const* data void ObjectMgr::LoadCreatureRespawnTimes() { - // remove outdated data - WorldDatabase.DirectExecute("DELETE FROM creature_respawn WHERE respawntime <= UNIX_TIMESTAMP(NOW())"); - uint32 count = 0; QueryResult *result = WorldDatabase.Query("SELECT guid,respawntime,instance FROM creature_respawn"); diff --git a/src/game/ObjectMgr.h b/src/game/ObjectMgr.h index 954bb6dbe61..8de6c3333b3 100644 --- a/src/game/ObjectMgr.h +++ b/src/game/ObjectMgr.h @@ -134,6 +134,7 @@ struct TrinityStringLocale std::vector<std::string> Content; // 0 -> default, i -> i-1 locale index }; +typedef std::map<uint32,uint32> CreatureLinkedRespawnMap; typedef UNORDERED_MAP<uint32,CreatureData> CreatureDataMap; typedef UNORDERED_MAP<uint32,GameObjectData> GameObjectDataMap; typedef UNORDERED_MAP<uint32,CreatureLocale> CreatureLocaleMap; @@ -513,6 +514,9 @@ class ObjectMgr void LoadCreatureLocales(); void LoadCreatureTemplates(); void LoadCreatures(); + void LoadCreatureLinkedRespawn(); + bool CheckCreatureLinkedRespawn(uint32 guid, uint32 linkedGuid) const; + bool SetCreatureLinkedRespawn(uint32 guid, uint32 linkedGuid); void LoadCreatureRespawnTimes(); void LoadCreatureAddons(); void LoadCreatureModelInfo(); @@ -618,6 +622,12 @@ class ObjectMgr } CreatureData& NewOrExistCreatureData(uint32 guid) { return mCreatureDataMap[guid]; } void DeleteCreatureData(uint32 guid); + uint32 GetLinkedRespawnGuid(uint32 guid) const + { + CreatureLinkedRespawnMap::const_iterator itr = mCreatureLinkedRespawnMap.find(guid); + if(itr == mCreatureLinkedRespawnMap.end()) return 0; + return itr->second; + } CreatureLocale const* GetCreatureLocale(uint32 entry) const { CreatureLocaleMap::const_iterator itr = mCreatureLocaleMap.find(entry); @@ -874,6 +884,7 @@ class ObjectMgr MapObjectGuids mMapObjectGuids; CreatureDataMap mCreatureDataMap; + CreatureLinkedRespawnMap mCreatureLinkedRespawnMap; CreatureLocaleMap mCreatureLocaleMap; GameObjectDataMap mGameObjectDataMap; GameObjectLocaleMap mGameObjectLocaleMap; diff --git a/src/game/World.cpp b/src/game/World.cpp index d138b15ac75..85a156c7206 100644 --- a/src/game/World.cpp +++ b/src/game/World.cpp @@ -1178,6 +1178,9 @@ void World::SetInitialWorldSettings() sLog.outString( "Loading Creature Data..." ); objmgr.LoadCreatures(); + sLog.outString( "Loading Creature Linked Respawn..." ); + objmgr.LoadCreatureLinkedRespawn(); // must be after LoadCreatures() + sLog.outString( "Loading Creature Addon Data..." ); objmgr.LoadCreatureAddons(); // must be after LoadCreatureTemplates() and LoadCreatures() |