diff options
Diffstat (limited to 'src')
26 files changed, 245 insertions, 130 deletions
diff --git a/src/server/game/Achievements/AchievementMgr.cpp b/src/server/game/Achievements/AchievementMgr.cpp index 327b4360292..228af5838df 100755 --- a/src/server/game/Achievements/AchievementMgr.cpp +++ b/src/server/game/Achievements/AchievementMgr.cpp @@ -38,7 +38,6 @@ #include "BattlegroundAB.h" #include "Map.h" #include "InstanceScript.h" -#include "LFGMgr.h" namespace Trinity { @@ -1548,9 +1547,6 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui if (IsCompletedAchievement(*itr)) CompletedAchievement(*itr); } - - if (const uint32 dungeonId = sLFGMgr->GetDungeonIdForAchievement(achievement->ID)) - sLFGMgr->RewardDungeonDoneFor(dungeonId, GetPlayer()); } } diff --git a/src/server/game/DataStores/DBCStores.cpp b/src/server/game/DataStores/DBCStores.cpp index 021e5f9d62e..07d0ec037e3 100755 --- a/src/server/game/DataStores/DBCStores.cpp +++ b/src/server/game/DataStores/DBCStores.cpp @@ -75,6 +75,7 @@ DBCStorage <CreatureSpellDataEntry> sCreatureSpellDataStore(CreatureSpellDatafmt DBCStorage <CreatureTypeEntry> sCreatureTypeStore(CreatureTypefmt); DBCStorage <CurrencyTypesEntry> sCurrencyTypesStore(CurrencyTypesfmt); +DBCStorage <DungeonEncounterEntry> sDungeonEncounterStore(DungeonEncounterfmt); DBCStorage <DurabilityQualityEntry> sDurabilityQualityStore(DurabilityQualityfmt); DBCStorage <DurabilityCostsEntry> sDurabilityCostsStore(DurabilityCostsfmt); @@ -246,7 +247,7 @@ void LoadDBCStores(const std::string& dataPath) uint32 oldMSTime = getMSTime(); std::string dbcPath = dataPath+"dbc/"; - const uint32 DBCFilesCount = 91; + const uint32 DBCFilesCount = 92; StoreProblemList bad_dbc_files; uint32 availableDbcLocales = 0xFFFFFFFF; @@ -287,6 +288,7 @@ void LoadDBCStores(const std::string& dataPath) LoadDBC(availableDbcLocales,bad_dbc_files,sCreatureSpellDataStore, dbcPath,"CreatureSpellData.dbc"); LoadDBC(availableDbcLocales,bad_dbc_files,sCreatureTypeStore, dbcPath,"CreatureType.dbc"); LoadDBC(availableDbcLocales,bad_dbc_files,sCurrencyTypesStore, dbcPath,"CurrencyTypes.dbc"); + LoadDBC(availableDbcLocales,bad_dbc_files,sDungeonEncounterStore, dbcPath,"DungeonEncounter.dbc"); LoadDBC(availableDbcLocales,bad_dbc_files,sDurabilityCostsStore, dbcPath,"DurabilityCosts.dbc"); LoadDBC(availableDbcLocales,bad_dbc_files,sDurabilityQualityStore, dbcPath,"DurabilityQuality.dbc"); LoadDBC(availableDbcLocales,bad_dbc_files,sEmotesStore, dbcPath,"Emotes.dbc"); @@ -581,12 +583,8 @@ void LoadDBCStores(const std::string& dataPath) LoadDBC(availableDbcLocales,bad_dbc_files,sVehicleSeatStore, dbcPath,"VehicleSeat.dbc"); LoadDBC(availableDbcLocales,bad_dbc_files,sWMOAreaTableStore, dbcPath,"WMOAreaTable.dbc"); for(uint32 i = 0; i < sWMOAreaTableStore.GetNumRows(); ++i) - { if(WMOAreaTableEntry const* entry = sWMOAreaTableStore.LookupEntry(i)) - { sWMOAreaInfoByTripple.insert(WMOAreaInfoByTripple::value_type(WMOAreaTableTripple(entry->rootId, entry->adtId, entry->groupId), entry)); - } - } LoadDBC(availableDbcLocales,bad_dbc_files,sWorldMapAreaStore, dbcPath,"WorldMapArea.dbc"); LoadDBC(availableDbcLocales,bad_dbc_files,sWorldMapOverlayStore, dbcPath,"WorldMapOverlay.dbc"); LoadDBC(availableDbcLocales,bad_dbc_files,sWorldSafeLocsStore, dbcPath,"WorldSafeLocs.dbc"); diff --git a/src/server/game/DataStores/DBCStores.h b/src/server/game/DataStores/DBCStores.h index fbd61153509..3b7a5764281 100755 --- a/src/server/game/DataStores/DBCStores.h +++ b/src/server/game/DataStores/DBCStores.h @@ -26,8 +26,8 @@ #include <list> typedef std::list<uint32> SimpleFactionsList; - SimpleFactionsList const* GetFactionTeamList(uint32 faction); + char* GetPetName(uint32 petfamily, uint32 dbclang); uint32 GetTalentSpellCost(uint32 spellId); TalentSpellPos const* GetTalentSpellPos(uint32 spellId); @@ -84,6 +84,7 @@ extern DBCStorage <CreatureFamilyEntry> sCreatureFamilyStore; extern DBCStorage <CreatureSpellDataEntry> sCreatureSpellDataStore; extern DBCStorage <CreatureTypeEntry> sCreatureTypeStore; extern DBCStorage <CurrencyTypesEntry> sCurrencyTypesStore; +extern DBCStorage <DungeonEncounterEntry> sDungeonEncounterStore; extern DBCStorage <DurabilityCostsEntry> sDurabilityCostsStore; extern DBCStorage <DurabilityQualityEntry> sDurabilityQualityStore; extern DBCStorage <EmotesEntry> sEmotesStore; diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h index ef09795d731..3ece8f93e39 100755 --- a/src/server/game/DataStores/DBCStructure.h +++ b/src/server/game/DataStores/DBCStructure.h @@ -784,6 +784,18 @@ struct CurrencyTypesEntry uint32 BitIndex; // 3 bit index in PLAYER_FIELD_KNOWN_CURRENCIES (1 << (index-1)) }; +struct DungeonEncounterEntry +{ + uint32 id; // 0 unique id + uint32 mapId; // 1 map id + uint32 difficulty; // 2 instance mode + //uint32 unk0; // 3 + uint32 encounterIndex; // 4 encounter index for creating completed mask + char* encounterName[16]; // 5-20 encounter name + //uint32 nameFlags; // 21 + //uint32 unk1; // 22 +}; + struct DurabilityCostsEntry { uint32 Itemlvl; // 0 diff --git a/src/server/game/DataStores/DBCfmt.h b/src/server/game/DataStores/DBCfmt.h index a6d3f8e983a..89495b786dd 100755 --- a/src/server/game/DataStores/DBCfmt.h +++ b/src/server/game/DataStores/DBCfmt.h @@ -41,6 +41,7 @@ const char CreatureFamilyfmt[]="nfifiiiiixssssssssssssssssxx"; const char CreatureSpellDatafmt[]="niiiixxxx"; const char CreatureTypefmt[]="nxxxxxxxxxxxxxxxxxx"; const char CurrencyTypesfmt[]="xnxi"; +const char DungeonEncounterfmt[]="niixissssssssssssssssxx"; const char DurabilityCostsfmt[]="niiiiiiiiiiiiiiiiiiiiiiiiiiiii"; const char DurabilityQualityfmt[]="nf"; const char EmotesEntryfmt[]="nxxiiix"; diff --git a/src/server/game/DungeonFinding/LFGMgr.cpp b/src/server/game/DungeonFinding/LFGMgr.cpp index 97b31a37cf1..d7a329737a6 100755 --- a/src/server/game/DungeonFinding/LFGMgr.cpp +++ b/src/server/game/DungeonFinding/LFGMgr.cpp @@ -71,61 +71,6 @@ LFGMgr::~LFGMgr() delete it->second; } -/// Load achievement <-> encounter associations -void LFGMgr::LoadDungeonEncounters() -{ - uint32 oldMSTime = getMSTime(); - - m_EncountersByAchievement.clear(); - - QueryResult result = WorldDatabase.Query("SELECT achievementId, dungeonId FROM lfg_dungeon_encounters"); - - if (!result) - { - - sLog->outString(); - sLog->outErrorDb(">> Loaded 0 dungeon encounter lfg associations. DB table `lfg_dungeon_encounters` is empty!"); - return; - } - - uint32 count = 0; - - Field* fields = NULL; - do - { - fields = result->Fetch(); - uint32 achievementId = fields[0].GetUInt32(); - uint32 dungeonId = fields[1].GetUInt32(); - - if (AchievementEntry const* achievement = sAchievementStore.LookupEntry(achievementId)) - { - if (!(achievement->flags & ACHIEVEMENT_FLAG_COUNTER)) - { - sLog->outErrorDb("Achievement %u specified in table `lfg_dungeon_encounters` is not a statistic!", achievementId); - continue; - } - } - else - { - sLog->outErrorDb("Achievement %u specified in table `lfg_dungeon_encounters` does not exist!", achievementId); - continue; - } - - if (!sLFGDungeonStore.LookupEntry(dungeonId)) - { - sLog->outErrorDb("Dungeon %u specified in table `lfg_dungeon_encounters` does not exist!", dungeonId); - continue; - } - - m_EncountersByAchievement[achievementId] = dungeonId; - ++count; - } while (result->NextRow()); - - sLog->outString(">> Loaded %u dungeon encounter lfg associations in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); - sLog->outString(); -} - - /// Load rewards for completing dungeons void LFGMgr::LoadRewards() { @@ -1730,7 +1675,6 @@ void LFGMgr::TeleportPlayer(Player* plr, bool out, bool fromOpcode /*= false*/) if (!fromOpcode) { - // Select a player inside to be teleported to for (GroupReference* itr = grp->GetFirstMember(); itr != NULL && !mapid; itr = itr->next()) { @@ -1923,21 +1867,6 @@ LfgType LFGMgr::GetDungeonType(uint32 dungeonId) } /** - Given a Achievement id returns the related dungeon id - - @param[in] achievementId Achievement id - @returns dungeon id -*/ -uint32 LFGMgr::GetDungeonIdForAchievement(uint32 achievementId) -{ - std::map<uint32, uint32>::iterator itr = m_EncountersByAchievement.find(achievementId); - if (itr != m_EncountersByAchievement.end()) - return itr->second; - - return 0; -}; - -/** Given a list of guids returns the concatenation using | as delimiter @param[in] check list of guids diff --git a/src/server/game/DungeonFinding/LFGMgr.h b/src/server/game/DungeonFinding/LFGMgr.h index 775c1e05837..493bed3305b 100755 --- a/src/server/game/DungeonFinding/LFGMgr.h +++ b/src/server/game/DungeonFinding/LFGMgr.h @@ -262,10 +262,8 @@ class LFGMgr void Update(uint32 diff); // Reward - void LoadDungeonEncounters(); void LoadRewards(); void RewardDungeonDoneFor(const uint32 dungeonId, Player* player); - uint32 GetDungeonIdForAchievement(uint32 achievementId); LfgReward const* GetRandomDungeonReward(uint32 dungeon, uint8 level); // Queue @@ -348,7 +346,6 @@ class LFGMgr LfgDungeonMap m_CachedDungeonMap; ///< Stores all dungeons by groupType // Reward System LfgRewardMap m_RewardMap; ///< Stores rewards for random dungeons - std::map<uint32, uint32> m_EncountersByAchievement;///< Stores dungeon ids associated with achievements (for rewards) // Queue LfgQueueInfoMap m_QueueInfoMap; ///< Queued groups LfgGuidListMap m_currentQueue; ///< Ordered list. Used to find groups diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 29d1d136687..a6a8e9a6bb0 100755 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -68,6 +68,7 @@ #include "WeatherMgr.h" #include "LFGMgr.h" #include "CharacterDatabaseCleaner.h" +#include "InstanceScript.h" #include <cmath> #define ZONE_UPDATE_INTERVAL (1*IN_MILLISECONDS) @@ -17709,6 +17710,10 @@ InstancePlayerBind* Player::BindToInstance(InstanceSave *save, bool permanent, b void Player::BindToInstance() { + // Player left the instance + if (_pendingBind->GetInstanceId() != GetInstanceId()) + return; + WorldPacket data(SMSG_INSTANCE_SAVE_CREATED, 4); data << uint32(0); GetSession()->SendPacket(&data); @@ -22116,6 +22121,12 @@ bool Player::RewardPlayerAndGroupAtKill(Unit* pVictim) KilledMonster(pVictim->ToCreature()->GetCreatureInfo(), pVictim->GetGUID()); } } + + // Credit encounter in instance + if (pVictim->GetTypeId() == TYPEID_UNIT && GetMap()->IsDungeon()) + if (InstanceScript* instance = pVictim->GetInstanceScript()) + instance->UpdateEncounterState(ENCOUNTER_CREDIT_KILL_CREATURE, pVictim->GetEntry(), pVictim); + return xp || honored_kill; } diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 013c8afe6e8..940f3c5ad1a 100755 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -5553,6 +5553,84 @@ void ObjectMgr::LoadInstanceTemplate() sLog->outString(); } +void ObjectMgr::LoadInstanceEncounters() +{ + uint32 oldMSTime = getMSTime(); + + QueryResult result = WorldDatabase.Query("SELECT entry, creditType, creditEntry, lastEncounterDungeon FROM instance_encounters"); + if (!result) + { + sLog->outErrorDb(">> Loaded 0 instance encounters, table is empty!"); + sLog->outString(); + return; + } + + uint32 count = 0; + std::map<uint32, DungeonEncounterEntry const*> dungeonLastBosses; + do + { + Field* fields = result->Fetch(); + uint32 entry = fields[0].GetUInt32(); + DungeonEncounterEntry const* dungeonEncounter = sDungeonEncounterStore.LookupEntry(entry); + if (!dungeonEncounter) + { + sLog->outErrorDb("Table `instance_encounters` has an invalid encounter id %u, skipped!", entry); + continue; + } + + uint8 creditType = fields[1].GetUInt8(); + uint32 creditEntry = fields[2].GetUInt32(); + + switch (creditType) + { + case ENCOUNTER_CREDIT_KILL_CREATURE: + if (!GetCreatureInfo(creditEntry)) + { + sLog->outErrorDb("Table `instance_encounters` has an invalid creature (entry %u) linked to the encounter %u (%s), skipped!", creditEntry, entry, dungeonEncounter->encounterName[0]); + continue; + } + break; + case ENCOUNTER_CREDIT_CAST_SPELL: + if (!sSpellStore.LookupEntry(creditEntry)) + { + sLog->outErrorDb("Table `instance_encounters` has an invalid spell (entry %u) linked to the encounter %u (%s), skipped!", creditEntry, entry, dungeonEncounter->encounterName[0]); + continue; + } + break; + default: + sLog->outErrorDb("Table `instance_encounters` has an invalid credit type (%u) for encounter %u (%s), skipped!", creditType, entry, dungeonEncounter->encounterName[0]); + continue; + } + + uint32 lastEncounterDungeon = fields[3].GetUInt32(); + + if (lastEncounterDungeon && !sLFGDungeonStore.LookupEntry(lastEncounterDungeon)) + { + sLog->outErrorDb("Table `instance_encounters` has an encounter %u (%s) marked as final for invalid dungeon id %u, skipped!", entry, dungeonEncounter->encounterName[0], lastEncounterDungeon); + continue; + } + + std::map<uint32, DungeonEncounterEntry const*>::const_iterator itr = dungeonLastBosses.find(lastEncounterDungeon); + if (lastEncounterDungeon) + { + if (itr != dungeonLastBosses.end()) + { + sLog->outErrorDb("Table `instance_encounters` specified encounter %u (%s) as last encounter but %u (%s) is already marked as one, skipped!", entry, dungeonEncounter->encounterName[0], itr->second->id, itr->second->encounterName[0]); + continue; + } + + dungeonLastBosses[lastEncounterDungeon] = dungeonEncounter; + } + + DungeonEncounterList& encounters = mDungeonEncounters[MAKE_PAIR32(dungeonEncounter->mapId, dungeonEncounter->difficulty)]; + encounters.push_back(new DungeonEncounter(dungeonEncounter, EncounterCreditType(creditType), creditEntry, lastEncounterDungeon)); + ++count; + } while (result->NextRow()); + + sLog->outString(">> Loaded %u instance encounters in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); + sLog->outString(); +} + GossipText const *ObjectMgr::GetGossipText(uint32 Text_ID) const { GossipTextMap::const_iterator itr = mGossipText.find(Text_ID); diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index 4efbbc7e5f0..13d3a3ec418 100755 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -557,7 +557,27 @@ struct LanguageDesc }; extern LanguageDesc lang_description[LANGUAGES_COUNT]; - LanguageDesc const* GetLanguageDescByID(uint32 lang); +LanguageDesc const* GetLanguageDescByID(uint32 lang); + +enum EncounterCreditType +{ + ENCOUNTER_CREDIT_KILL_CREATURE = 0, + ENCOUNTER_CREDIT_CAST_SPELL = 1, +}; + +struct DungeonEncounter +{ + DungeonEncounter(DungeonEncounterEntry const* _dbcEntry, EncounterCreditType _creditType, uint32 _creditEntry, uint32 _lastEncounterDungeon) + : dbcEntry(_dbcEntry), creditType(_creditType), creditEntry(_creditEntry), lastEncounterDungeon(_lastEncounterDungeon) { } + + DungeonEncounterEntry const* dbcEntry; + EncounterCreditType creditType; + uint32 creditEntry; + uint32 lastEncounterDungeon; +}; + +typedef std::list<DungeonEncounter const*> DungeonEncounterList; +typedef UNORDERED_MAP<uint32,DungeonEncounterList> DungeonEncounterMap; class PlayerDumpReader; @@ -796,6 +816,14 @@ class ObjectMgr return NULL; } + DungeonEncounterList const* GetDungeonEncounterList(uint32 mapId, Difficulty difficulty) + { + UNORDERED_MAP<uint32, DungeonEncounterList>::const_iterator itr = mDungeonEncounters.find(MAKE_PAIR32(mapId, difficulty)); + if (itr != mDungeonEncounters.end()) + return &itr->second; + return NULL; + } + void LoadGuilds(); void LoadArenaTeams(); void LoadGroups(); @@ -884,6 +912,7 @@ class ObjectMgr void LoadGossipMenuItemsLocales(); void LoadPointOfInterestLocales(); void LoadInstanceTemplate(); + void LoadInstanceEncounters(); void LoadMailLevelRewards(); void LoadVehicleAccessories(); void LoadVehicleScaling(); @@ -1253,6 +1282,7 @@ class ObjectMgr AreaTriggerMap mAreaTriggers; AreaTriggerScriptMap mAreaTriggerScripts; AccessRequirementMap mAccessRequirements; + DungeonEncounterMap mDungeonEncounters; RepRewardRateMap m_RepRewardRateMap; RepOnKillMap mRepOnKill; diff --git a/src/server/game/Instances/InstanceSaveMgr.cpp b/src/server/game/Instances/InstanceSaveMgr.cpp index 4c2f8117ba7..ad385a7334d 100755 --- a/src/server/game/Instances/InstanceSaveMgr.cpp +++ b/src/server/game/Instances/InstanceSaveMgr.cpp @@ -165,20 +165,27 @@ void InstanceSave::SaveToDB() { // save instance data too std::string data; + uint32 completedEncounters = 0; - Map *map = sMapMgr->FindMap(GetMapId(),m_instanceid); + Map *map = sMapMgr->FindMap(GetMapId(), m_instanceid); if (map) { ASSERT(map->IsDungeon()); - if (InstanceScript *iData = ((InstanceMap*)map)->GetInstanceScript()) + if (InstanceScript *instanceScript = ((InstanceMap*)map)->GetInstanceScript()) { - data = iData->GetSaveData(); - if (!data.empty()) - CharacterDatabase.escape_string(data); + data = instanceScript->GetSaveData(); + completedEncounters = instanceScript->GetCompletedEncounterMask(); } } - CharacterDatabase.PExecute("INSERT INTO instance VALUES ('%u', '%u', '%u', '%u', '%s')", m_instanceid, GetMapId(), (uint32)GetResetTimeForDB(), GetDifficulty(), data.c_str()); + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_ADD_INSTANCE_SAVE); + stmt->setUInt32(0, m_instanceid); + stmt->setUInt16(1, GetMapId()); + stmt->setUInt32(2, uint32(GetResetTimeForDB())); + stmt->setUInt8(3, uint8(GetDifficulty())); + stmt->setUInt32(4, completedEncounters); + stmt->setString(5, data); + CharacterDatabase.Execute(stmt); } time_t InstanceSave::GetResetTimeForDB() diff --git a/src/server/game/Instances/InstanceScript.cpp b/src/server/game/Instances/InstanceScript.cpp index 348ff7a766c..231d6ab6667 100755 --- a/src/server/game/Instances/InstanceScript.cpp +++ b/src/server/game/Instances/InstanceScript.cpp @@ -24,14 +24,19 @@ #include "Creature.h" #include "CreatureAI.h" #include "Log.h" +#include "LFGMgr.h" void InstanceScript::SaveToDB() { std::string data = GetSaveData(); if (data.empty()) return; - CharacterDatabase.escape_string(data); - CharacterDatabase.PExecute("UPDATE instance SET data = '%s' WHERE id = '%d'", data.c_str(), instance->GetInstanceId()); + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPDATE_INSTANCE_DATA); + stmt->setUInt32(0, GetCompletedEncounterMask()); + stmt->setString(1, data); + stmt->setUInt32(2, instance->GetInstanceId()); + CharacterDatabase.Execute(stmt); } void InstanceScript::HandleGameObject(uint64 GUID, bool open, GameObject *go) @@ -427,3 +432,29 @@ void InstanceScript::SendEncounterUnit(uint32 type, Unit* unit /*= NULL*/, uint8 instance->SendToPlayers(&data); } + +void InstanceScript::UpdateEncounterState(EncounterCreditType type, uint32 creditEntry, Unit* source) +{ + DungeonEncounterList const* encounters = sObjectMgr->GetDungeonEncounterList(instance->GetId(), instance->GetDifficulty()); + if (!encounters) + return; + + for (DungeonEncounterList::const_iterator itr = encounters->begin(); itr != encounters->end(); ++itr) + { + if ((*itr)->creditType == type && (*itr)->creditEntry == creditEntry) + { + completedEncounters |= 1 << (*itr)->dbcEntry->encounterIndex; + sLog->outDebug("Instance %s (instanceId %u) completed encounter %s", instance->GetMapName(), instance->GetInstanceId(), (*itr)->dbcEntry->encounterName[0]); + if (uint32 dungeonId = (*itr)->lastEncounterDungeon) + { + Map::PlayerList const& players = instance->GetPlayers(); + if (!players.isEmpty()) + for (Map::PlayerList::const_iterator i = players.begin(); i != players.end(); ++i) + if (Player* player = i->getSource()) + if (!source || player->IsAtGroupRewardDistance(source)) + sLFGMgr->RewardDungeonDoneFor(dungeonId, player); + } + return; + } + } +} diff --git a/src/server/game/Instances/InstanceScript.h b/src/server/game/Instances/InstanceScript.h index 5e293eee0ca..2ba81c963a4 100755 --- a/src/server/game/Instances/InstanceScript.h +++ b/src/server/game/Instances/InstanceScript.h @@ -21,6 +21,7 @@ #include "ZoneScript.h" #include "World.h" +#include "ObjectMgr.h" //#include "GameObject.h" //#include "Map.h" @@ -124,7 +125,8 @@ class InstanceScript : public ZoneScript { public: - explicit InstanceScript(Map *map) : instance(map) {} + explicit InstanceScript(Map* map) : instance(map), completedEncounters(0) {} + virtual ~InstanceScript() {} Map *instance; @@ -196,9 +198,14 @@ class InstanceScript : public ZoneScript // Checks boss requirements (one boss required to kill other) virtual bool CheckRequiredBosses(uint32 /*bossId*/, Player const* /*player*/ = NULL) const { return true; } + // Checks encounter state at kill/spellcast + void UpdateEncounterState(EncounterCreditType type, uint32 creditEntry, Unit* source); + + // Used only during loading + void SetCompletedEncountersMask(uint32 newMask) { completedEncounters = newMask; } + // Returns completed encounters mask for packets - // NOTE: MUST USE ENCOUNTER IDS FROM DungeonEncounter.dbc 4th column - virtual uint32 GetCompletedEncounterMask() const { return 0; } + uint32 GetCompletedEncounterMask() const { return completedEncounters; } void SendEncounterUnit(uint32 type, Unit* unit = NULL, uint8 param1 = 0, uint8 param2 = 0); @@ -219,6 +226,7 @@ class InstanceScript : public ZoneScript std::vector<BossInfo> bosses; DoorInfoMap doors; MinionInfoMap minions; + uint32 completedEncounters; // completed encounter mask, bit indexes are DungeonEncounter.dbc boss numbers, used for packets }; #endif diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index c4187ff626f..1e2e55a7cde 100755 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -2425,11 +2425,12 @@ void InstanceMap::CreateInstanceData(bool load) if (load) { // TODO: make a global storage for this - QueryResult result = CharacterDatabase.PQuery("SELECT data FROM instance WHERE map = '%u' AND id = '%u'", GetId(), i_InstanceId); + QueryResult result = CharacterDatabase.PQuery("SELECT data, completedEncounters FROM instance WHERE map = '%u' AND id = '%u'", GetId(), i_InstanceId); if (result) { Field* fields = result->Fetch(); std::string data = fields[0].GetString(); + i_data->SetCompletedEncountersMask(fields[1].GetUInt32()); if (data != "") { sLog->outDebug("Loading instance data for `%s` with id %u", sObjectMgr->GetScriptName(i_script_id), i_InstanceId); diff --git a/src/server/game/Server/Protocol/Handlers/LFGHandler.cpp b/src/server/game/Server/Protocol/Handlers/LFGHandler.cpp index 2ac129973a9..ac8ce189f4b 100755 --- a/src/server/game/Server/Protocol/Handlers/LFGHandler.cpp +++ b/src/server/game/Server/Protocol/Handlers/LFGHandler.cpp @@ -22,7 +22,7 @@ #include "Group.h" #include "LFGMgr.h" #include "ObjectMgr.h" - +#include "InstanceScript.h" void BuildPlayerLockDungeonBlock(WorldPacket& data, const LfgLockMap& lock) { @@ -555,6 +555,7 @@ void WorldSession::SendLfgUpdateProposal(uint32 proposalId, const LfgProposal* p bool isSameDungeon = false; bool isContinue = false; Group* grp = dLowGuid ? sObjectMgr->GetGroupByGUID(dLowGuid) : NULL; + uint32 completedEncounters = 0; if (grp) { uint64 gguid = grp->GetGUID(); @@ -571,12 +572,31 @@ void WorldSession::SendLfgUpdateProposal(uint32 proposalId, const LfgProposal* p if (playerDungeons.size() == 1) dungeonId = (*playerDungeons.begin()); } + if (LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(dungeonId)) + { dungeonId = dungeon->Entry(); + + // Select a player inside to be get completed encounters from + if (grp) + { + for (GroupReference* itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) + { + Player* groupMember = itr->getSource(); + if (groupMember && groupMember->GetMapId() == uint32(dungeon->map)) + { + if (InstanceScript* instance = groupMember->GetInstanceScript()) + completedEncounters = instance->GetCompletedEncounterMask(); + break; + } + } + } + } + data << uint32(dungeonId); // Dungeon data << uint8(pProp->state); // Result state data << uint32(proposalId); // Internal Proposal ID - data << uint32(0); // Bosses killed - FIXME + data << uint32(completedEncounters); // Bosses killed data << uint8(isSameDungeon); // Silent (show client window) data << uint8(pProp->players.size()); // Group size diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 2cc6d08c0be..f0ecb5307b6 100755 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -51,6 +51,7 @@ #include "ConditionMgr.h" #include "DisableMgr.h" #include "SpellScript.h" +#include "InstanceScript.h" #define SPELL_CHANNEL_UPDATE_INTERVAL (1 * IN_MILLISECONDS) @@ -3717,16 +3718,17 @@ void Spell::finish(bool ok) // triggered spell pointer can be not set in some cases // this is needed for proper apply of triggered spell mods m_caster->ToPlayer()->SetSpellModTakingSpell(this, true); - } - // Take mods after trigger spell (needed for 14177 to affect 48664) - // mods are taken only on succesfull cast and independantly from targets of the spell - if (m_caster->GetTypeId() == TYPEID_PLAYER) - { + // Take mods after trigger spell (needed for 14177 to affect 48664) + // mods are taken only on succesfull cast and independantly from targets of the spell m_caster->ToPlayer()->RemoveSpellMods(this); m_caster->ToPlayer()->SetSpellModTakingSpell(this, false); } + if (m_caster->GetTypeId() == TYPEID_UNIT) + if (InstanceScript* instance = m_caster->GetInstanceScript()) + instance->UpdateEncounterState(ENCOUNTER_CREDIT_CAST_SPELL, m_spellInfo->Id, m_caster); + // Stop Attack for some spells if (m_spellInfo->Attributes & SPELL_ATTR0_STOP_ATTACK_TARGET) m_caster->AttackStop(); diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 08193860413..ab5071a18bd 100755 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -1403,7 +1403,7 @@ void World::SetInitialWorldSettings() sGameEventMgr->LoadFromDB(); // TODOLEAK: add scopes sLog->outString("Loading Dungeon boss data..."); - sLFGMgr->LoadDungeonEncounters(); + sObjectMgr->LoadInstanceEncounters(); sLog->outString("Loading LFG rewards..."); sLFGMgr->LoadRewards(); diff --git a/src/server/scripts/Commands/cs_reload.cpp b/src/server/scripts/Commands/cs_reload.cpp index 6a35982b74a..ae86a16fae9 100644 --- a/src/server/scripts/Commands/cs_reload.cpp +++ b/src/server/scripts/Commands/cs_reload.cpp @@ -102,7 +102,6 @@ public: { "item_enchantment_template", SEC_ADMINISTRATOR, true, &HandleReloadItemEnchantementsCommand, "", NULL }, { "item_loot_template", SEC_ADMINISTRATOR, true, &HandleReloadLootTemplatesItemCommand, "", NULL }, { "item_set_names", SEC_ADMINISTRATOR, true, &HandleReloadItemSetNamesCommand, "", NULL }, - { "lfg_dungeon_encounters", SEC_ADMINISTRATOR, true, &HandleReloadLfgEncountersCommand, "", NULL }, { "lfg_dungeon_rewards", SEC_ADMINISTRATOR, true, &HandleReloadLfgRewardsCommand, "", NULL }, { "locales_achievement_reward", SEC_ADMINISTRATOR, true, &HandleReloadLocalesAchievementRewardCommand, "", NULL }, { "locales_creature", SEC_ADMINISTRATOR, true, &HandleReloadLocalesCreatureCommand, "", NULL }, @@ -1164,14 +1163,6 @@ public: return true; } - static bool HandleReloadLfgEncountersCommand(ChatHandler* handler, const char* /*args*/) - { - sLog->outString("Re-Loading dungeon encounter lfg associations..."); - sLFGMgr->LoadDungeonEncounters(); - handler->SendGlobalGMSysMessage("DB table `lfg_dungeon_encounters` reloaded."); - return true; - } - static bool HandleReloadLfgRewardsCommand(ChatHandler* handler, const char* /*args*/) { sLog->outString("Re-Loading lfg dungeon rewards..."); diff --git a/src/server/scripts/EasternKingdoms/BlackrockDepths/blackrock_depths.cpp b/src/server/scripts/EasternKingdoms/BlackrockDepths/blackrock_depths.cpp index f458084e9b2..0e72c048a03 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockDepths/blackrock_depths.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockDepths/blackrock_depths.cpp @@ -237,6 +237,7 @@ public: case 5: if (pInstance) { + pInstance->UpdateEncounterState(ENCOUNTER_CREDIT_KILL_CREATURE, NPC_GRIMSTONE, me); pInstance->SetData(TYPE_RING_OF_LAW,DONE); sLog->outDebug("TSCR: npc_grimstone: event reached end and set complete."); } diff --git a/src/server/scripts/EasternKingdoms/Karazhan/instance_karazhan.cpp b/src/server/scripts/EasternKingdoms/Karazhan/instance_karazhan.cpp index 8f8cde5bb31..1a48ab455e3 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/instance_karazhan.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/instance_karazhan.cpp @@ -138,7 +138,11 @@ public: break; case TYPE_MAIDEN: m_auiEncounter[2] = uiData; break; case TYPE_OPTIONAL_BOSS: m_auiEncounter[3] = uiData; break; - case TYPE_OPERA: m_auiEncounter[4] = uiData; break; + case TYPE_OPERA: + m_auiEncounter[4] = uiData; + if (uiData == DONE) + UpdateEncounterState(ENCOUNTER_CREDIT_KILL_CREATURE, 16812, NULL); + break; case TYPE_CURATOR: m_auiEncounter[5] = uiData; break; case TYPE_ARAN: m_auiEncounter[6] = uiData; break; case TYPE_TERESTIAN: m_auiEncounter[7] = uiData; break; diff --git a/src/server/scripts/EasternKingdoms/MoltenCore/boss_majordomo_executus.cpp b/src/server/scripts/EasternKingdoms/MoltenCore/boss_majordomo_executus.cpp index ffa48d8846b..f5291af6620 100644 --- a/src/server/scripts/EasternKingdoms/MoltenCore/boss_majordomo_executus.cpp +++ b/src/server/scripts/EasternKingdoms/MoltenCore/boss_majordomo_executus.cpp @@ -107,7 +107,7 @@ class boss_majordomo : public CreatureScript if (!me->FindNearestCreature(NPC_FLAMEWAKER_HEALER, 100.0f) && !me->FindNearestCreature(NPC_FLAMEWAKER_ELITE, 100.0f)) { - //instance->UpdateEncounterState(ENCOUNTER_CREDIT_KILL_CREATURE, me->GetEntry()); + instance->UpdateEncounterState(ENCOUNTER_CREDIT_KILL_CREATURE, me->GetEntry()); me->setFaction(35); me->AI()->EnterEvadeMode(); DoScriptText(SAY_DEFEAT, me); diff --git a/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp index 758bb92a1aa..c739364d23d 100755 --- a/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp @@ -395,16 +395,6 @@ class instance_icecrown_citadel : public InstanceMapScript return true; } - uint32 GetCompletedEncounterMask() const - { - uint32 mask = 0; - for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) - if (GetBossState(i) == DONE) - mask |= 1 << i; - - return mask; - } - void SetData(uint32 type, uint32 data) { switch (type) diff --git a/src/server/scripts/Northrend/Nexus/Oculus/boss_eregos.cpp b/src/server/scripts/Northrend/Nexus/Oculus/boss_eregos.cpp index 73c933301f7..51b75f19f7e 100644 --- a/src/server/scripts/Northrend/Nexus/Oculus/boss_eregos.cpp +++ b/src/server/scripts/Northrend/Nexus/Oculus/boss_eregos.cpp @@ -139,7 +139,7 @@ public: Talk(SAY_AGGRO); } - + void DoAction(const int32 action) { if (action != ACTION_SET_NORMAL_EVENTS) @@ -157,7 +157,7 @@ public: if (summon->GetEntry() != NPC_PLANAR_ANOMALY) return; - + summon->CombatStop(true); summon->SetReactState(REACT_PASSIVE); summon->GetMotionMaster()->MoveRandom(100.0f); diff --git a/src/server/scripts/Northrend/VioletHold/instance_violet_hold.cpp b/src/server/scripts/Northrend/VioletHold/instance_violet_hold.cpp index 031bfa33bd9..a0d5eb3d173 100644 --- a/src/server/scripts/Northrend/VioletHold/instance_violet_hold.cpp +++ b/src/server/scripts/Northrend/VioletHold/instance_violet_hold.cpp @@ -315,11 +315,13 @@ public: switch(type) { case DATA_1ST_BOSS_EVENT: + UpdateEncounterState(ENCOUNTER_CREDIT_KILL_CREATURE, CREATURE_EREKEM, NULL); m_auiEncounter[0] = data; if (data == DONE) SaveToDB(); break; case DATA_2ND_BOSS_EVENT: + UpdateEncounterState(ENCOUNTER_CREDIT_KILL_CREATURE, CREATURE_MORAGG, NULL); m_auiEncounter[1] = data; if (data == DONE) SaveToDB(); diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.cpp b/src/server/shared/Database/Implementation/CharacterDatabase.cpp index 6d251824338..44aaeec07ab 100755 --- a/src/server/shared/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/shared/Database/Implementation/CharacterDatabase.cpp @@ -259,10 +259,12 @@ bool CharacterDatabaseConnection::Open() PREPARE_STATEMENT(CHAR_ADD_AURA, "INSERT INTO character_aura (guid,caster_guid,item_guid,spell,effect_mask,recalculate_mask,stackcount,amount0,amount1,amount2,base_amount0,base_amount1,base_amount2,maxduration,remaintime,remaincharges) " "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC) + // Instance saves + PREPARE_STATEMENT(CHAR_ADD_INSTANCE_SAVE, "INSERT INTO instance (id,map,resettime,difficulty,completedEncounters,data) VALUES (?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC) + PREPARE_STATEMENT(CHAR_UPDATE_INSTANCE_DATA, "UPDATE instance SET completedEncounters=?, data=? WHERE id=?", CONNECTION_ASYNC) + for (PreparedStatementMap::const_iterator itr = m_queries.begin(); itr != m_queries.end(); ++itr) - { PrepareStatement(itr->first, itr->second.first, itr->second.second); - } return true; } diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.h b/src/server/shared/Database/Implementation/CharacterDatabase.h index 412dd6145cd..4d47878eba6 100755 --- a/src/server/shared/Database/Implementation/CharacterDatabase.h +++ b/src/server/shared/Database/Implementation/CharacterDatabase.h @@ -218,6 +218,9 @@ enum CharacterDatabaseStatements CHAR_DEL_AURA, CHAR_ADD_AURA, + CHAR_ADD_INSTANCE_SAVE, + CHAR_UPDATE_INSTANCE_DATA, + MAX_CHARACTERDATABASE_STATEMENTS, }; |
