aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/server/game/Achievements/AchievementMgr.cpp4
-rwxr-xr-xsrc/server/game/DataStores/DBCStores.cpp8
-rwxr-xr-xsrc/server/game/DataStores/DBCStores.h3
-rwxr-xr-xsrc/server/game/DataStores/DBCStructure.h12
-rwxr-xr-xsrc/server/game/DataStores/DBCfmt.h1
-rwxr-xr-xsrc/server/game/DungeonFinding/LFGMgr.cpp71
-rwxr-xr-xsrc/server/game/DungeonFinding/LFGMgr.h3
-rwxr-xr-xsrc/server/game/Entities/Player/Player.cpp11
-rwxr-xr-xsrc/server/game/Globals/ObjectMgr.cpp78
-rwxr-xr-xsrc/server/game/Globals/ObjectMgr.h32
-rwxr-xr-xsrc/server/game/Instances/InstanceSaveMgr.cpp19
-rwxr-xr-xsrc/server/game/Instances/InstanceScript.cpp35
-rwxr-xr-xsrc/server/game/Instances/InstanceScript.h14
-rwxr-xr-xsrc/server/game/Maps/Map.cpp3
-rwxr-xr-xsrc/server/game/Server/Protocol/Handlers/LFGHandler.cpp24
-rwxr-xr-xsrc/server/game/Spells/Spell.cpp12
-rwxr-xr-xsrc/server/game/World/World.cpp2
-rw-r--r--src/server/scripts/Commands/cs_reload.cpp9
-rw-r--r--src/server/scripts/EasternKingdoms/BlackrockDepths/blackrock_depths.cpp1
-rw-r--r--src/server/scripts/EasternKingdoms/Karazhan/instance_karazhan.cpp6
-rw-r--r--src/server/scripts/EasternKingdoms/MoltenCore/boss_majordomo_executus.cpp2
-rwxr-xr-xsrc/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp10
-rw-r--r--src/server/scripts/Northrend/Nexus/Oculus/boss_eregos.cpp4
-rw-r--r--src/server/scripts/Northrend/VioletHold/instance_violet_hold.cpp2
-rwxr-xr-xsrc/server/shared/Database/Implementation/CharacterDatabase.cpp6
-rwxr-xr-xsrc/server/shared/Database/Implementation/CharacterDatabase.h3
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,
};