aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sql/base/characters_database.sql2
-rw-r--r--sql/base/world_database.sql14
-rw-r--r--sql/updates/9081_access_requirement.sql12
-rw-r--r--sql/updates/9081_areatrigger_teleport.sql1
-rw-r--r--sql/updates/9081_characters_characters.sql1
-rw-r--r--src/server/game/DataStores/DBCStores.cpp26
-rw-r--r--src/server/game/DataStores/DBCStores.h1
-rw-r--r--src/server/game/DataStores/DBCStructure.h23
-rw-r--r--src/server/game/DataStores/DBCfmt.h2
-rw-r--r--src/server/game/Entities/Player/Player.cpp93
-rw-r--r--src/server/game/Entities/Player/Player.h16
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp86
-rw-r--r--src/server/game/Globals/ObjectMgr.h5
-rw-r--r--src/server/game/Groups/Group.cpp8
-rw-r--r--src/server/game/Maps/MapInstanced.cpp4
-rw-r--r--src/server/game/Maps/MapManager.cpp21
-rw-r--r--src/server/game/Server/Protocol/Handlers/CharacterHandler.cpp2
-rw-r--r--src/server/game/Server/Protocol/Handlers/MiscHandler.cpp6
-rw-r--r--src/server/game/Spells/Spell.cpp5
19 files changed, 172 insertions, 156 deletions
diff --git a/sql/base/characters_database.sql b/sql/base/characters_database.sql
index 16ed16de332..7bd03bffb07 100644
--- a/sql/base/characters_database.sql
+++ b/sql/base/characters_database.sql
@@ -342,7 +342,7 @@ CREATE TABLE `characters` (
`position_z` float NOT NULL default '0',
`map` int(11) unsigned NOT NULL default '0' COMMENT 'Map Identifier',
`instance_id` int(11) unsigned NOT NULL default '0',
- `dungeon_difficulty` tinyint(1) unsigned NOT NULL default '0',
+ `instance_mode_mask` tinyint(2) unsigned NOT NULL default '0',
`orientation` float NOT NULL default '0',
`taximask` longtext,
`online` tinyint(3) unsigned NOT NULL default '0',
diff --git a/sql/base/world_database.sql b/sql/base/world_database.sql
index 7720b40f901..efca1c78603 100644
--- a/sql/base/world_database.sql
+++ b/sql/base/world_database.sql
@@ -25,20 +25,18 @@ DROP TABLE IF EXISTS `access_requirement`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `access_requirement` (
- `id` bigint(20) unsigned NOT NULL COMMENT 'Identifier',
+ `mapId` mediumint(8) unsigned NOT NULL,
+ `difficulty` tinyint(3) unsigned NOT NULL DEFAULT '0',
`level_min` tinyint(3) unsigned NOT NULL DEFAULT '0',
- `heroic_level_min` tinyint(3) unsigned NOT NULL DEFAULT '0',
`level_max` tinyint(3) unsigned NOT NULL DEFAULT '0',
`item` mediumint(8) unsigned NOT NULL DEFAULT '0',
`item2` mediumint(8) unsigned NOT NULL DEFAULT '0',
- `heroic_key` mediumint(8) unsigned NOT NULL DEFAULT '0',
- `heroic_key2` mediumint(8) unsigned NOT NULL DEFAULT '0',
- `quest_done` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `quest_done_A` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `quest_done_H` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `completed_achievement` mediumint(8) unsigned NOT NULL DEFAULT '0',
`quest_failed_text` text,
- `heroic_quest_done` mediumint(8) unsigned NOT NULL DEFAULT '0',
- `heroic_quest_failed_text` text,
`comment` text,
- PRIMARY KEY (`id`)
+ PRIMARY KEY (`mapId`,`difficulty`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Access Requirements';
/*!40101 SET character_set_client = @saved_cs_client */;
diff --git a/sql/updates/9081_access_requirement.sql b/sql/updates/9081_access_requirement.sql
new file mode 100644
index 00000000000..da7e108636a
--- /dev/null
+++ b/sql/updates/9081_access_requirement.sql
@@ -0,0 +1,12 @@
+ALTER TABLE `access_requirement`
+ DROP PRIMARY KEY,
+ CHANGE `id` `mapId` mediumint(8) unsigned NOT NULL FIRST,
+ ADD `difficulty` tinyint(3) unsigned NOT NULL DEFAULT '0' AFTER `mapId`,
+ DROP `heroic_level_min`,
+ DROP `heroic_key`,
+ DROP `heroic_key2`,
+ CHANGE `quest_done` `quest_done_A` mediumint(8) unsigned NOT NULL DEFAULT '0' AFTER `item2`,
+ CHANGE `heroic_quest_done` `quest_done_H` mediumint(8) unsigned NOT NULL DEFAULT '0' AFTER `quest_done_A`,
+ ADD `completed_achievement` mediumint(8) unsigned NOT NULL DEFAULT '0' AFTER `quest_done_H`,
+ DROP `heroic_quest_failed_text`,
+ ADD PRIMARY KEY(`mapId`,`difficulty`);
diff --git a/sql/updates/9081_areatrigger_teleport.sql b/sql/updates/9081_areatrigger_teleport.sql
new file mode 100644
index 00000000000..d8df8fafbf9
--- /dev/null
+++ b/sql/updates/9081_areatrigger_teleport.sql
@@ -0,0 +1 @@
+ALTER TABLE `areatrigger_teleport` DROP `access_id`;
diff --git a/sql/updates/9081_characters_characters.sql b/sql/updates/9081_characters_characters.sql
new file mode 100644
index 00000000000..1e7b32e47a5
--- /dev/null
+++ b/sql/updates/9081_characters_characters.sql
@@ -0,0 +1 @@
+ALTER TABLE `characters` CHANGE `dungeon_difficulty` `instance_mode_mask` tinyint(2) UNSIGNED NOT NULL DEFAULT 0 AFTER `instance_id`;
diff --git a/src/server/game/DataStores/DBCStores.cpp b/src/server/game/DataStores/DBCStores.cpp
index 7ec071a4b54..022f5b3d2f0 100644
--- a/src/server/game/DataStores/DBCStores.cpp
+++ b/src/server/game/DataStores/DBCStores.cpp
@@ -352,7 +352,7 @@ void LoadDBCStores(const std::string& dataPath)
// fill data
for (uint32 i = 1; i < sMapDifficultyStore.GetNumRows(); ++i)
if (MapDifficultyEntry const* entry = sMapDifficultyStore.LookupEntry(i))
- sMapDifficultyMap[MAKE_PAIR32(entry->MapId,entry->Difficulty)] = MapDifficulty(entry->resetTime,entry->maxPlayers);
+ sMapDifficultyMap[MAKE_PAIR32(entry->MapId,entry->Difficulty)] = MapDifficulty(entry->resetTime,entry->maxPlayers,strlen(entry->areaTriggerText)>0);
sMapDifficultyStore.Clear();
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sMovieStore, dbcPath,"Movie.dbc");
@@ -782,6 +782,30 @@ MapDifficulty const* GetMapDifficultyData(uint32 mapId, Difficulty difficulty)
return itr != sMapDifficultyMap.end() ? &itr->second : NULL;
}
+MapDifficulty const* GetDownscaledMapDifficultyData(uint32 mapId, Difficulty &difficulty)
+{
+ uint32 tmpDiff = difficulty;
+ MapDifficulty const* mapDiff = GetMapDifficultyData(mapId, Difficulty(tmpDiff));
+ if (!mapDiff)
+ {
+ if (tmpDiff > RAID_DIFFICULTY_25MAN_NORMAL) // heroic, downscale to normal
+ tmpDiff -= 2;
+ else
+ tmpDiff -= 1; // any non-normal mode for raids like tbc (only one mode)
+
+ // pull new data
+ mapDiff = GetMapDifficultyData(mapId, Difficulty(tmpDiff)); // we are 10 normal or 25 normal
+ if (!mapDiff)
+ {
+ tmpDiff -= 1;
+ mapDiff = GetMapDifficultyData(mapId, Difficulty(tmpDiff)); // 10 normal
+ }
+ }
+
+ difficulty = Difficulty(tmpDiff);
+ return mapDiff;
+}
+
PvPDifficultyEntry const* GetBattlegroundBracketByLevel(uint32 mapid, uint32 level)
{
// prevent out-of-range levels for dbc data
diff --git a/src/server/game/DataStores/DBCStores.h b/src/server/game/DataStores/DBCStores.h
index cd08f23b9d4..4b5e6724fe9 100644
--- a/src/server/game/DataStores/DBCStores.h
+++ b/src/server/game/DataStores/DBCStores.h
@@ -58,6 +58,7 @@ void Map2ZoneCoordinates(float &x, float &y, uint32 zone);
typedef std::map<uint32/*pair32(map,diff)*/,MapDifficulty> MapDifficultyMap;
MapDifficulty const* GetMapDifficultyData(uint32 mapId, Difficulty difficulty);
+MapDifficulty const* GetDownscaledMapDifficultyData(uint32 mapId, Difficulty &difficulty);
uint32 const* /*[3]*/ GetTalentTabPages(uint8 cls);
diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h
index 7663aaf3dcb..c8eb3701c33 100644
--- a/src/server/game/DataStores/DBCStructure.h
+++ b/src/server/game/DataStores/DBCStructure.h
@@ -1099,22 +1099,22 @@ struct ItemSetEntry
struct LFGDungeonEntry
{
uint32 ID; // 0
- //char* name[16]; // 1-17 Name lang
+ //char* name[16]; // 1-17 Name lang
uint32 minlevel; // 18
uint32 maxlevel; // 19
uint32 reclevel; // 20
uint32 recminlevel; // 21
uint32 recmaxlevel; // 22
- uint32 map; // 23
- uint32 heroic; // 24
- //uint32 unk; // 25
+ int32 map; // 23
+ uint32 difficulty; // 24
+ //uint32 unk; // 25
uint32 type; // 26
- //uint32 unk2; // 27
- //char* unk3; // 28
+ //uint32 unk2; // 27
+ //char* unk3; // 28
uint32 expansion; // 29
- //uint32 unk4; // 30
+ //uint32 unk4; // 30
uint32 grouptype; // 31
- //char* desc[16]; // 32-47 Description
+ //char* desc[16]; // 32-47 Description
// Helpers
uint32 Entry() const { return ID + (type << 24); }
};
@@ -1194,7 +1194,7 @@ struct MapDifficultyEntry
//uint32 Id; // 0
uint32 MapId; // 1
uint32 Difficulty; // 2 (for arenas: arena slot)
- //char* areaTriggerText[16]; // 3-18 text showed when transfer to map failed (missing requirements)
+ char* areaTriggerText; // 3-18 text showed when transfer to map failed (missing requirements)
//uint32 textFlags; // 19
uint32 resetTime; // 20
uint32 maxPlayers; // 21
@@ -1881,11 +1881,12 @@ struct WorldSafeLocsEntry
// Structures not used for casting to loaded DBC data and not required then packing
struct MapDifficulty
{
- MapDifficulty() : resetTime(0), maxPlayers(0) {}
- MapDifficulty(uint32 _resetTime, uint32 _maxPlayers) : resetTime(_resetTime), maxPlayers(_maxPlayers) {}
+ MapDifficulty() : resetTime(0), maxPlayers(0), hasErrorMessage(false) {}
+ MapDifficulty(uint32 _resetTime, uint32 _maxPlayers, bool _hasErrorMessage) : resetTime(_resetTime), maxPlayers(_maxPlayers), hasErrorMessage(_hasErrorMessage) {}
uint32 resetTime;
uint32 maxPlayers;
+ bool hasErrorMessage;
};
struct TalentSpellPos
diff --git a/src/server/game/DataStores/DBCfmt.h b/src/server/game/DataStores/DBCfmt.h
index 80d8791bd01..b83ea207804 100644
--- a/src/server/game/DataStores/DBCfmt.h
+++ b/src/server/game/DataStores/DBCfmt.h
@@ -77,7 +77,7 @@ const char LFGDungeonEntryfmt[]="nxxxxxxxxxxxxxxxxxiiiiiiixixxixixxxxxxxxxxxxxxx
const char LockEntryfmt[]="niiiiiiiiiiiiiiiiiiiiiiiixxxxxxxx";
const char MailTemplateEntryfmt[]="nxxxxxxxxxxxxxxxxxssssssssssssssssx";
const char MapEntryfmt[]="nxixxssssssssssssssssxixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxixiffxiix";
-const char MapDifficultyEntryfmt[]="diixxxxxxxxxxxxxxxxxiix";
+const char MapDifficultyEntryfmt[]="diisxxxxxxxxxxxxxxxxiix";
const char MovieEntryfmt[]="nxx";
const char QuestSortEntryfmt[]="nxxxxxxxxxxxxxxxxx";
const char QuestXPfmt[]="niiiiiiiiii";
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 8b2b74b572d..44f39528146 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -6540,15 +6540,13 @@ void Player::RewardReputation(Unit *pVictim, float rate)
Map const *pMap = GetMap();
if (pMap && pMap->IsDungeon())
{
- bool Heroic = ((InstanceMap*)pMap)->GetDifficulty() == DUNGEON_DIFFICULTY_HEROIC;
-
InstanceTemplate const *pInstance = objmgr.GetInstanceTemplate(pMap->GetId());
if (pInstance)
{
- AccessRequirement const *pAccessRequirement = objmgr.GetAccessRequirement(pInstance->access_id);
+ AccessRequirement const *pAccessRequirement = objmgr.GetAccessRequirement(pMap->GetId(), ((InstanceMap*)pMap)->GetDifficulty());
if (pAccessRequirement)
{
- if (!pMap->IsRaid() && ((!Heroic && pAccessRequirement->levelMin == 80) || (Heroic && pAccessRequirement->heroicLevelMin == 80)))
+ if (!pMap->IsRaid() && pAccessRequirement->levelMin == 80)
ChampioningFaction = GetChampioningFaction();
}
}
@@ -15891,7 +15889,7 @@ bool Player::LoadFromDB(uint32 guid, SqlQueryHolder *holder)
// 12 13 14 15 16 17 18 19 20 21 22 23 24
//"position_x, position_y, position_z, map, orientation, taximask, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost,"
// 25 26 27 28 29 30 31 32 33 34 35 36 37 38
- //"resettalents_time, trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, online, death_expire_time, taxi_path, dungeon_difficulty,"
+ //"resettalents_time, trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, online, death_expire_time, taxi_path, instance_mode_mask,"
// 39 40 41 42 43 44 45 46 47 48 49
//"arenaPoints, totalHonorPoints, todayHonorPoints, yesterdayHonorPoints, totalKills, todayKills, yesterdayKills, chosenTitle, knownCurrencies, watchedFaction, drunk,"
// 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
@@ -15997,10 +15995,15 @@ bool Player::LoadFromDB(uint32 guid, SqlQueryHolder *holder)
uint32 mapId = fields[15].GetUInt32();
uint32 instanceId = fields[58].GetFloat();
- uint32 difficulty = fields[38].GetUInt32();
- if (difficulty >= MAX_DUNGEON_DIFFICULTY)
- difficulty = DUNGEON_DIFFICULTY_NORMAL;
- SetDungeonDifficulty(Difficulty(difficulty)); // may be changed in _LoadGroup
+ uint32 dungeonDiff = fields[38].GetUInt32() & 0x0F;
+ if (dungeonDiff >= MAX_DUNGEON_DIFFICULTY)
+ dungeonDiff = DUNGEON_DIFFICULTY_NORMAL;
+ uint32 raidDiff = (fields[38].GetUInt32() >> 4) & 0x0F;
+ if (raidDiff >= MAX_RAID_DIFFICULTY)
+ raidDiff = RAID_DIFFICULTY_10MAN_NORMAL;
+ SetDungeonDifficulty(Difficulty(dungeonDiff)); // may be changed in _LoadGroup
+ SetRaidDifficulty(Difficulty(raidDiff)); // may be changed in _LoadGroup
+
std::string taxi_nodes = fields[37].GetCppString();
#define RelocateToHomebind(){ mapId = m_homebindMapId; instanceId = 0; Relocate(m_homebindX, m_homebindY, m_homebindZ); }
@@ -16252,6 +16255,7 @@ bool Player::LoadFromDB(uint32 guid, SqlQueryHolder *holder)
}
SetMap(map);
+ StoreRaidMapDifficulty();
// randomize first save time in range [CONFIG_INTERVAL_SAVE] around [CONFIG_INTERVAL_SAVE]
// this must help in case next save after mass player load after server startup
@@ -17293,7 +17297,7 @@ void Player::_LoadBoundInstances(QueryResult_AutoPtr result)
InstancePlayerBind* Player::GetBoundInstance(uint32 mapid, Difficulty difficulty)
{
// some instances only have one difficulty
- MapDifficulty const* mapDiff = GetMapDifficultyData(mapid,difficulty);
+ MapDifficulty const* mapDiff = GetDownscaledMapDifficultyData(mapid,difficulty);
if (!mapDiff)
return NULL;
@@ -17489,7 +17493,7 @@ void Player::ConvertInstancesToGroup(Player *player, Group *group, uint64 player
CharacterDatabase.PExecute("DELETE FROM character_instance WHERE guid = '%d' AND permanent = 0", GUID_LOPART(player_guid));
}
-bool Player::Satisfy(AccessRequirement const *ar, uint32 target_map, bool report)
+bool Player::Satisfy(AccessRequirement const* ar, uint32 target_map, bool report)
{
if (!isGameMaster() && ar)
{
@@ -17504,8 +17508,6 @@ bool Player::Satisfy(AccessRequirement const *ar, uint32 target_map, bool report
{
if (ar->levelMin && getLevel() < ar->levelMin)
LevelMin = ar->levelMin;
- if (mapEntry->IsNonRaidDungeon() && ar->heroicLevelMin && GetDungeonDifficulty() == DUNGEON_DIFFICULTY_HEROIC && getLevel() < ar->heroicLevelMin)
- LevelMin = ar->heroicLevelMin;
if (ar->levelMax && getLevel() > ar->levelMax)
LevelMax = ar->levelMax;
}
@@ -17530,39 +17532,28 @@ bool Player::Satisfy(AccessRequirement const *ar, uint32 target_map, bool report
? (GetRaidDifficulty() == RAID_DIFFICULTY_10MAN_NORMAL)
: (GetDungeonDifficulty() == DUNGEON_DIFFICULTY_NORMAL);
- uint32 missingKey = 0;
- uint32 missingHeroicQuest = 0;
- if (!isNormalTargetMap)
- {
- if (ar->heroicKey)
- {
- if (!HasItemCount(ar->heroicKey, 1) &&
- (!ar->heroicKey2 || !HasItemCount(ar->heroicKey2, 1)))
- missingKey = ar->heroicKey;
- }
- else if (ar->heroicKey2 && !HasItemCount(ar->heroicKey2, 1))
- missingKey = ar->heroicKey2;
-
- if (ar->heroicQuest && !GetQuestRewardStatus(ar->heroicQuest))
- missingHeroicQuest = ar->heroicQuest;
- }
-
uint32 missingQuest = 0;
- if (ar->quest && !GetQuestRewardStatus(ar->quest))
- missingQuest = ar->quest;
+ if (GetTeam() == ALLIANCE && ar->quest_A && !GetQuestRewardStatus(ar->quest_A))
+ missingQuest = ar->quest_A;
+ else if (GetTeam() == HORDE && ar->quest_H && !GetQuestRewardStatus(ar->quest_H))
+ missingQuest = ar->quest_H;
- if (LevelMin || LevelMax || missingItem || missingKey || missingQuest || missingHeroicQuest)
+ uint32 missingAchievement = 0;
+ if (ar->achievement && !GetAchievementMgr().HasAchieved(sAchievementStore.LookupEntry(ar->achievement)))
+ missingAchievement = ar->achievement;
+
+ Difficulty target_difficulty = GetDifficulty(mapEntry->IsRaid());
+ MapDifficulty const* mapDiff = GetDownscaledMapDifficultyData(target_map, target_difficulty);
+ if (LevelMin || LevelMax || missingItem || missingQuest || missingAchievement)
{
if (report)
{
- if (missingItem)
+ if (missingQuest && !ar->questFailedText.empty())
+ ChatHandler(GetSession()).PSendSysMessage(ar->questFailedText.c_str());
+ else if (mapDiff->hasErrorMessage) // if (missingAchievement) covered by this case
+ SendTransferAborted(target_map, TRANSFER_ABORT_DIFFICULTY, target_difficulty);
+ else if (missingItem)
GetSession()->SendAreaTriggerMessage(GetSession()->GetTrinityString(LANG_LEVEL_MINREQUIRED_AND_ITEM), LevelMin, objmgr.GetItemPrototype(missingItem)->Name1);
- else if (missingKey)
- SendTransferAborted(target_map, TRANSFER_ABORT_DIFFICULTY, isNormalTargetMap ? DUNGEON_DIFFICULTY_NORMAL : DUNGEON_DIFFICULTY_HEROIC);
- else if (missingHeroicQuest)
- GetSession()->SendAreaTriggerMessage(ar->heroicQuestFailedText.c_str());
- else if (missingQuest)
- GetSession()->SendAreaTriggerMessage(ar->questFailedText.c_str());
else if (LevelMin)
GetSession()->SendAreaTriggerMessage(GetSession()->GetTrinityString(LANG_LEVEL_MINREQUIRED), LevelMin);
}
@@ -17672,7 +17663,7 @@ void Player::SaveToDB()
std::ostringstream ss;
ss << "REPLACE INTO characters (guid,account,name,race,class,gender,level,xp,money,playerBytes,playerBytes2,playerFlags,"
- "map, instance_id, dungeon_difficulty, position_x, position_y, position_z, orientation, "
+ "map, instance_id, instance_mode_mask, position_x, position_y, position_z, orientation, "
"taximask, online, cinematic, "
"totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, resettalents_time, "
"trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, "
@@ -17696,7 +17687,7 @@ void Player::SaveToDB()
{
ss << GetMapId() << ", "
<< (uint32)GetInstanceId() << ", "
- << (uint32)GetDungeonDifficulty() << ", "
+ << uint32(uint8(GetDungeonDifficulty()) | uint8(GetRaidDifficulty()) << 4) << ", "
<< finiteAlways(GetPositionX()) << ", "
<< finiteAlways(GetPositionY()) << ", "
<< finiteAlways(GetPositionZ()) << ", "
@@ -17706,7 +17697,7 @@ void Player::SaveToDB()
{
ss << GetTeleportDest().GetMapId() << ", "
<< (uint32)0 << ", "
- << (uint32)GetDungeonDifficulty() << ", "
+ << uint32(uint8(GetDungeonDifficulty()) | uint8(GetRaidDifficulty()) << 4) << ", "
<< finiteAlways(GetTeleportDest().GetPositionX()) << ", "
<< finiteAlways(GetTeleportDest().GetPositionY()) << ", "
<< finiteAlways(GetTeleportDest().GetPositionZ()) << ", "
@@ -18387,11 +18378,11 @@ void Player::SendDungeonDifficulty(bool IsInGroup)
GetSession()->SendPacket(&data);
}
-void Player::SendRaidDifficulty(bool IsInGroup)
+void Player::SendRaidDifficulty(bool IsInGroup, int32 forcedDifficulty)
{
uint8 val = 0x00000001;
WorldPacket data(MSG_SET_RAID_DIFFICULTY, 12);
- data << uint32(GetRaidDifficulty());
+ data << uint32(forcedDifficulty == -1 ? GetRaidDifficulty() : forcedDifficulty);
data << uint32(val);
data << uint32(IsInGroup);
GetSession()->SendPacket(&data);
@@ -21005,6 +20996,18 @@ void Player::SendInitialPacketsAfterAddToMap()
SendAurasForTarget(this);
SendEnchantmentDurations(); // must be after add to map
SendItemDurations(); // must be after add to map
+
+ // raid downscaling - send difficulty to player
+ if (GetMap()->IsRaid())
+ {
+ if (GetMap()->GetDifficulty() != GetRaidDifficulty())
+ {
+ StoreRaidMapDifficulty();
+ SendRaidDifficulty(GetGroup() != NULL, GetStoredRaidDifficulty());
+ }
+ }
+ else if (GetRaidDifficulty() != GetStoredRaidDifficulty())
+ SendRaidDifficulty(GetGroup() != NULL);
}
void Player::SendUpdateToOutOfRangeGroupMembers()
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index cfe956320af..82efe19e3c7 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -829,15 +829,12 @@ struct AccessRequirement
{
uint8 levelMin;
uint8 levelMax;
- uint8 heroicLevelMin;
uint32 item;
uint32 item2;
- uint32 heroicKey;
- uint32 heroicKey2;
- uint32 quest;
+ uint32 quest_A;
+ uint32 quest_H;
+ uint32 achievement;
std::string questFailedText;
- uint32 heroicQuest;
- std::string heroicQuestFailedText;
};
enum CharDeleteMethod
@@ -1743,8 +1740,10 @@ class Player : public Unit, public GridObject<Player>
Difficulty GetDifficulty(bool isRaid) const { return isRaid ? m_raidDifficulty : m_dungeonDifficulty; }
Difficulty GetDungeonDifficulty() const { return m_dungeonDifficulty; }
Difficulty GetRaidDifficulty() const { return m_raidDifficulty; }
+ Difficulty GetStoredRaidDifficulty() const { return m_raidMapDifficulty; } // only for use in difficulty packet after exiting to raid map
void SetDungeonDifficulty(Difficulty dungeon_difficulty) { m_dungeonDifficulty = dungeon_difficulty; }
void SetRaidDifficulty(Difficulty raid_difficulty) { m_raidDifficulty = raid_difficulty; }
+ void StoreRaidMapDifficulty() { m_raidMapDifficulty = GetMap()->GetDifficulty(); }
bool UpdateSkill(uint32 skill_id, uint32 step);
bool UpdateSkillPro(uint16 SkillId, int32 Chance, uint32 step);
@@ -1830,7 +1829,7 @@ class Player : public Unit, public GridObject<Player>
void SendExplorationExperience(uint32 Area, uint32 Experience);
void SendDungeonDifficulty(bool IsInGroup);
- void SendRaidDifficulty(bool IsInGroup);
+ void SendRaidDifficulty(bool IsInGroup, int32 forcedDifficulty = -1);
void ResetInstances(uint8 method, bool isRaid);
void SendResetInstanceSuccess(uint32 MapId);
void SendResetInstanceFailed(uint32 reason, uint32 MapId);
@@ -2268,7 +2267,7 @@ class Player : public Unit, public GridObject<Player>
void SendRaidInfo();
void SendSavedInstances();
static void ConvertInstancesToGroup(Player *player, Group *group = NULL, uint64 player_guid = 0);
- bool Satisfy(AccessRequirement const*, uint32 target_map, bool report = false);
+ bool Satisfy(AccessRequirement const* ar, uint32 target_map, bool report = false);
bool CheckInstanceLoginValid();
// last used pet number (for BG's)
@@ -2458,6 +2457,7 @@ class Player : public Unit, public GridObject<Player>
uint32 m_speakCount;
Difficulty m_dungeonDifficulty;
Difficulty m_raidDifficulty;
+ Difficulty m_raidMapDifficulty;
uint32 m_atLoginFlags;
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp
index 4890c67c6b4..d0af5081c89 100644
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -5885,8 +5885,8 @@ void ObjectMgr::LoadAreaTriggerTeleports()
uint32 count = 0;
- // 0 1 2 3 4 5 6
- QueryResult_AutoPtr result = WorldDatabase.Query("SELECT id, access_id, target_map, target_position_x, target_position_y, target_position_z, target_orientation FROM areatrigger_teleport");
+ // 0 1 2 3 4 5
+ QueryResult_AutoPtr result = WorldDatabase.Query("SELECT id, target_map, target_position_x, target_position_y, target_position_z, target_orientation FROM areatrigger_teleport");
if (!result)
{
@@ -5913,12 +5913,11 @@ void ObjectMgr::LoadAreaTriggerTeleports()
AreaTrigger at;
- at.access_id = fields[1].GetUInt32();
- at.target_mapId = fields[2].GetUInt32();
- at.target_X = fields[3].GetFloat();
- at.target_Y = fields[4].GetFloat();
- at.target_Z = fields[5].GetFloat();
- at.target_Orientation = fields[6].GetFloat();
+ at.target_mapId = fields[1].GetUInt32();
+ at.target_X = fields[2].GetFloat();
+ at.target_Y = fields[3].GetFloat();
+ at.target_Z = fields[4].GetFloat();
+ at.target_Orientation = fields[5].GetFloat();
AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(Trigger_ID);
if (!atEntry)
@@ -5954,8 +5953,8 @@ void ObjectMgr::LoadAccessRequirements()
uint32 count = 0;
- // 0 1 2 3 4 5 6 7 8 9 10 11
- QueryResult_AutoPtr result = WorldDatabase.Query("SELECT id, level_min, level_max, item, item2, heroic_key, heroic_key2, quest_done, quest_failed_text, heroic_quest_done, heroic_quest_failed_text, heroic_level_min FROM access_requirement");
+ // 0 1 2 3 4 5 6 7 8 9
+ QueryResult_AutoPtr result = WorldDatabase.Query("SELECT mapid, difficulty, level_min, level_max, item, item2, quest_done_A, quest_done_H, completed_achievement, quest_failed_text FROM access_requirement");
if (!result)
{
@@ -5978,28 +5977,27 @@ void ObjectMgr::LoadAccessRequirements()
++count;
- uint32 requiremt_ID = fields[0].GetUInt32();
+ uint32 mapid = fields[0].GetUInt32();
+ uint8 difficulty = fields[1].GetUInt8();
+ uint32 requirement_ID = MAKE_PAIR32(mapid,difficulty);
AccessRequirement ar;
- ar.levelMin = fields[1].GetUInt8();
- ar.levelMax = fields[2].GetUInt8();
- ar.heroicLevelMin = fields[11].GetUInt8();
- ar.item = fields[3].GetUInt32();
- ar.item2 = fields[4].GetUInt32();
- ar.heroicKey = fields[5].GetUInt32();
- ar.heroicKey2 = fields[6].GetUInt32();
- ar.quest = fields[7].GetUInt32();
- ar.questFailedText = fields[8].GetCppString();
- ar.heroicQuest = fields[9].GetUInt32();
- ar.heroicQuestFailedText = fields[10].GetCppString();
+ ar.levelMin = fields[2].GetUInt8();
+ ar.levelMax = fields[3].GetUInt8();
+ ar.item = fields[4].GetUInt32();
+ ar.item2 = fields[5].GetUInt32();
+ ar.quest_A = fields[6].GetUInt32();
+ ar.quest_H = fields[7].GetUInt32();
+ ar.achievement = fields[8].GetUInt32();
+ ar.questFailedText = fields[9].GetCppString();
if (ar.item)
{
ItemPrototype const *pProto = GetItemPrototype(ar.item);
if (!pProto)
{
- sLog.outError("Key item %u does not exist for requirement %u, removing key requirement.", ar.item, requiremt_ID);
+ sLog.outError("Key item %u does not exist for map %u difficulty %u, removing key requirement.", ar.item, mapid, difficulty);
ar.item = 0;
}
}
@@ -6009,53 +6007,39 @@ void ObjectMgr::LoadAccessRequirements()
ItemPrototype const *pProto = GetItemPrototype(ar.item2);
if (!pProto)
{
- sLog.outError("Second item %u does not exist for requirement %u, removing key requirement.", ar.item2, requiremt_ID);
+ sLog.outError("Second item %u does not exist for map %u difficulty %u, removing key requirement.", ar.item2, mapid, difficulty);
ar.item2 = 0;
}
}
- if (ar.heroicKey)
+ if (ar.quest_A)
{
- ItemPrototype const *pProto = GetItemPrototype(ar.heroicKey);
- if (!pProto)
- {
- sLog.outError("Heroic key %u not exist for trigger %u, remove key requirement.", ar.heroicKey, requiremt_ID);
- ar.heroicKey = 0;
- }
- }
-
- if (ar.heroicKey2)
- {
- ItemPrototype const *pProto = GetItemPrototype(ar.heroicKey2);
- if (!pProto)
+ if (!GetQuestTemplate(ar.quest_A))
{
- sLog.outError("Second heroic key %u not exist for trigger %u, remove key requirement.", ar.heroicKey2, requiremt_ID);
- ar.heroicKey2 = 0;
+ sLog.outErrorDb("Required Alliance Quest %u not exist for map %u difficulty %u, remove quest done requirement.", ar.quest_A, mapid, difficulty);
+ ar.quest_A = 0;
}
}
- if (ar.heroicQuest)
+ if (ar.quest_H)
{
- QuestMap::iterator qReqItr = mQuestTemplates.find(ar.heroicQuest);
- if (qReqItr == mQuestTemplates.end())
+ if (!GetQuestTemplate(ar.quest_H))
{
- sLog.outErrorDb("Required Heroic Quest %u not exist for trigger %u, remove heroic quest done requirement.",ar.heroicQuest,requiremt_ID);
- ar.heroicQuest = 0;
+ sLog.outErrorDb("Required Horde Quest %u not exist for map %u difficulty %u, remove quest done requirement.", ar.quest_H, mapid, difficulty);
+ ar.quest_H = 0;
}
}
- if (ar.quest)
+ if (ar.achievement)
{
- QuestMap::iterator qReqItr = mQuestTemplates.find(ar.quest);
- if (qReqItr == mQuestTemplates.end())
+ if (!sAchievementStore.LookupEntry(ar.achievement))
{
- sLog.outErrorDb("Required Quest %u not exist for trigger %u, remove quest done requirement.",ar.quest,requiremt_ID);
- ar.quest = 0;
+ sLog.outErrorDb("Required Achievement %u not exist for map %u difficulty %u, remove quest done requirement.", ar.achievement, mapid, difficulty);
+ ar.achievement = 0;
}
}
- mAccessRequirements[requiremt_ID] = ar;
-
+ mAccessRequirements[requirement_ID] = ar;
} while (result->NextRow());
sLog.outString();
diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h
index 53be3a0e1e0..f3f15faeeb4 100644
--- a/src/server/game/Globals/ObjectMgr.h
+++ b/src/server/game/Globals/ObjectMgr.h
@@ -120,7 +120,6 @@ typedef std::pair<SpellClickInfoMap::const_iterator,SpellClickInfoMap::const_ite
struct AreaTrigger
{
- uint32 access_id;
uint32 target_mapId;
float target_X;
float target_Y;
@@ -529,9 +528,9 @@ class ObjectMgr
return NULL;
}
- AccessRequirement const* GetAccessRequirement(uint32 requirement) const
+ AccessRequirement const* GetAccessRequirement(uint32 mapid, Difficulty difficulty) const
{
- AccessRequirementMap::const_iterator itr = mAccessRequirements.find(requirement);
+ AccessRequirementMap::const_iterator itr = mAccessRequirements.find(MAKE_PAIR32(mapid,difficulty));
if (itr != mAccessRequirements.end())
return &itr->second;
return NULL;
diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp
index 2679cbb412d..3f5d422e957 100644
--- a/src/server/game/Groups/Group.cpp
+++ b/src/server/game/Groups/Group.cpp
@@ -1769,9 +1769,7 @@ InstanceGroupBind* Group::GetBoundInstance(Map* aMap)
Difficulty difficulty = GetDifficulty(aMap->IsRaid());
// some instances only have one difficulty
- MapDifficulty const* mapDiff = GetMapDifficultyData(aMap->GetId(),difficulty);
- if (!mapDiff)
- return NULL;
+ MapDifficulty const* mapDiff = GetDownscaledMapDifficultyData(aMap->GetId(),difficulty);
BoundInstancesMap::iterator itr = m_boundInstances[difficulty].find(aMap->GetId());
if (itr != m_boundInstances[difficulty].end())
@@ -1788,9 +1786,7 @@ InstanceGroupBind* Group::GetBoundInstance(MapEntry const* mapEntry)
Difficulty difficulty = GetDifficulty(mapEntry->IsRaid());
// some instances only have one difficulty
- MapDifficulty const* mapDiff = GetMapDifficultyData(mapEntry->MapID,difficulty);
- if (!mapDiff)
- difficulty = DUNGEON_DIFFICULTY_NORMAL;
+ MapDifficulty const* mapDiff = GetDownscaledMapDifficultyData(mapEntry->MapID,difficulty);
BoundInstancesMap::iterator itr = m_boundInstances[difficulty].find(mapEntry->MapID);
if (itr != m_boundInstances[difficulty].end())
diff --git a/src/server/game/Maps/MapInstanced.cpp b/src/server/game/Maps/MapInstanced.cpp
index 008baeb79d9..3a7375f52f4 100644
--- a/src/server/game/Maps/MapInstanced.cpp
+++ b/src/server/game/Maps/MapInstanced.cpp
@@ -200,9 +200,7 @@ InstanceMap* MapInstanced::CreateInstance(uint32 InstanceId, InstanceSave *save,
}
// some instances only have one difficulty
- MapDifficulty const* mapDiff = GetMapDifficultyData(GetId(),difficulty);
- if (!mapDiff)
- difficulty = DUNGEON_DIFFICULTY_NORMAL;
+ MapDifficulty const* mapDiff = GetDownscaledMapDifficultyData(GetId(),difficulty);
sLog.outDebug("MapInstanced::CreateInstance: %s map instance %d for %d created with difficulty %s", save?"":"new ", InstanceId, GetId(), difficulty?"heroic":"normal");
diff --git a/src/server/game/Maps/MapManager.cpp b/src/server/game/Maps/MapManager.cpp
index 5cdd2f90089..5e8a2803419 100644
--- a/src/server/game/Maps/MapManager.cpp
+++ b/src/server/game/Maps/MapManager.cpp
@@ -165,18 +165,19 @@ bool MapManager::CanPlayerEnter(uint32 mapid, Player* player, bool loginCheck)
if (!instance)
return false;
+ Difficulty targetDifficulty = player->GetDifficulty(entry->IsRaid());
//The player has a heroic mode and tries to enter into instance which has no a heroic mode
- MapDifficulty const* mapDiff = GetMapDifficultyData(entry->MapID,player->GetDifficulty(entry->IsRaid()));
+ MapDifficulty const* mapDiff = GetMapDifficultyData(entry->MapID, targetDifficulty);
if (!mapDiff)
{
- bool isNormalTargetMap = entry->IsRaid()
- ? (player->GetRaidDifficulty() == RAID_DIFFICULTY_10MAN_NORMAL)
- : (player->GetDungeonDifficulty() == DUNGEON_DIFFICULTY_NORMAL);
-
- // Send aborted message
- // FIX ME: what about absent normal/heroic mode with specific players limit...
- player->SendTransferAborted(mapid, TRANSFER_ABORT_DIFFICULTY, isNormalTargetMap ? DUNGEON_DIFFICULTY_NORMAL : DUNGEON_DIFFICULTY_HEROIC);
- return false;
+ // Send aborted message for dungeons
+ if (entry->IsNonRaidDungeon())
+ {
+ player->SendTransferAborted(mapid, TRANSFER_ABORT_DIFFICULTY, player->GetDungeonDifficulty());
+ return false;
+ }
+ else // attempt to downscale
+ mapDiff = GetDownscaledMapDifficultyData(entry->MapID, targetDifficulty);
}
//Bypass checks for GMs
@@ -249,7 +250,7 @@ bool MapManager::CanPlayerEnter(uint32 mapid, Player* player, bool loginCheck)
}
//Other requirements
- return player->Satisfy(objmgr.GetAccessRequirement(instance->access_id), mapid, true);
+ return player->Satisfy(objmgr.GetAccessRequirement(mapid, targetDifficulty), mapid, true);
}
void MapManager::RemoveBonesFromMap(uint32 mapid, uint64 guid, float x, float y)
diff --git a/src/server/game/Server/Protocol/Handlers/CharacterHandler.cpp b/src/server/game/Server/Protocol/Handlers/CharacterHandler.cpp
index ca08d197c3f..9d9132ae3c3 100644
--- a/src/server/game/Server/Protocol/Handlers/CharacterHandler.cpp
+++ b/src/server/game/Server/Protocol/Handlers/CharacterHandler.cpp
@@ -67,7 +67,7 @@ bool LoginQueryHolder::Initialize()
// !!! NOTE: including unused `zone`,`online`
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADFROM, "SELECT guid, account, name, race, class, gender, level, xp, money, playerBytes, playerBytes2, playerFlags,"
"position_x, position_y, position_z, map, orientation, taximask, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost,"
- "resettalents_time, trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, online, death_expire_time, taxi_path, dungeon_difficulty,"
+ "resettalents_time, trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, online, death_expire_time, taxi_path, instance_mode_mask,"
"arenaPoints, totalHonorPoints, todayHonorPoints, yesterdayHonorPoints, totalKills, todayKills, yesterdayKills, chosenTitle, knownCurrencies, watchedFaction, drunk,"
"health, power1, power2, power3, power4, power5, power6, power7, instance_id, speccount, activespec, exploredZones, equipmentCache, ammoId, knownTitles, actionBars FROM characters WHERE guid = '%u'", GUID_LOPART(m_guid));
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADGROUP, "SELECT guid FROM group_member WHERE memberGuid =%u", GUID_LOPART(m_guid));
diff --git a/src/server/game/Server/Protocol/Handlers/MiscHandler.cpp b/src/server/game/Server/Protocol/Handlers/MiscHandler.cpp
index 4225a99c72b..88e4e70998d 100644
--- a/src/server/game/Server/Protocol/Handlers/MiscHandler.cpp
+++ b/src/server/game/Server/Protocol/Handlers/MiscHandler.cpp
@@ -931,10 +931,6 @@ void WorldSession::HandleAreaTriggerOpcode(WorldPacket & recv_data)
if (!at)
return;
- // MapManager::CanPlayerEnter() calls players->Satisfy() so this is not needed here
- // if (!GetPlayer()->Satisfy(objmgr.GetAccessRequirement(at->access_id), at->target_mapId, true))
- // return;
-
// Check only if target map != current player's map
// check if player can enter instance : instance not full, and raid instance not in encounter fight
if (GetPlayer()->GetMapId() != at->target_mapId && !sMapMgr.CanPlayerEnter(at->target_mapId, GetPlayer(), false))
@@ -1623,7 +1619,7 @@ void WorldSession::HandleSetRaidDifficultyOpcode(WorldPacket & recv_data)
{
_player->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY, true);
_player->SetRaidDifficulty(Difficulty(mode));
- }
+ }
}
void WorldSession::HandleCancelMountAuraOpcode(WorldPacket & /*recv_data*/)
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index 9582286ab23..f8cbfd76ad2 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -5312,10 +5312,11 @@ SpellCastResult Spell::CheckCast(bool strict)
// check if our map is dungeon
if (sMapStore.LookupEntry(m_caster->GetMapId())->IsDungeon())
{
- InstanceTemplate const* instance = ObjectMgr::GetInstanceTemplate(m_caster->GetMapId());
+ Map const* pMap = m_caster->GetMap();
+ InstanceTemplate const* instance = ObjectMgr::GetInstanceTemplate(pMap->GetId());
if (!instance)
return SPELL_FAILED_TARGET_NOT_IN_INSTANCE;
- if (!target->Satisfy(objmgr.GetAccessRequirement(instance->access_id), m_caster->GetMapId()))
+ if (!target->Satisfy(objmgr.GetAccessRequirement(pMap->GetId(), pMap->GetDifficulty()), pMap->GetId()))
return SPELL_FAILED_BAD_TARGETS;
}
break;