Core/LFG:

* added missing dungeon ID to high priestess Azil's encounter credit
* fixed the last encounter lfg reward. Cataclysm dungeons use a single entry for both difficulties so the instance needs to find the proper dungeon for the difficulty. Fixed.
* increased amount of required votes to kick a player from a party
* use the remaining teleport error messages for their according purpose
* use a bgdata location as teleport location when teleporting out of a dungeon
* fixed lfg state after group has been formed
* the amount of required roles is now determined by dbc values (thanks to Onkelz28)
* added some safety checks for reward data packets if no quest is found
* fixed lfr queue and reward display
* add the possibility to make lfg reward quests repeatable. This is getting used for dungeon quests with valor point rewards. Setting the alternative quest once the limit has been reached is handled corewise now.
* implement valor points display in the lfg window. Note: to see it for the first time you need at least 1 valor point
* implement Call to Arms system. Thanks to Tisk for the base code
* added loot for the Call to Arms Satches of Exotic mysteries
This commit is contained in:
Ovalord committed 2017-12-04 18:43:51 +01:00
1 parent f1c8505e9a
commit 7525fb165e
18 files changed
+512 -132

No files matched your search

@@ -0,0 +1,72 @@
-- Make Cataclysm lfg quests repeatable. Their currency weekly cap is handled by the core
UPDATE `quest_template_addon` SET `SpecialFlags`= 8 | 1 WHERE `ID` IN (29185, 28905, 28907);
-- Add loot to Satches of Exotic Mysteries
DELETE FROM `item_loot_template` WHERE `entry`= 69903;
INSERT INTO `item_loot_template` (`Entry`, `Item`, `Reference`, `Chance`, `MinCount`, `MaxCount`) VALUES
(69903, 0, 69903, 100, 2, 2);
DELETE FROM `reference_loot_template` WHERE `entry`= 69903;
INSERT INTO `reference_loot_template` (`Entry`, `Item`, `Chance`, `Lootmode`, `GroupId`, `MinCount`, `MaxCount`) VALUES
(69903, 58085, 10, 1, 1, 1, 1),
(69903, 58090, 7, 1, 1, 1, 3),
(69903, 57191, 7, 1, 1, 1, 3),
(69903, 58087, 6, 1, 1, 1, 1),
(69903, 52195, 5, 1, 1, 1, 1),
(69903, 52194, 5, 1, 1, 1, 1),
(69903, 52192, 5, 1, 1, 1, 1),
(69903, 52193, 5, 1, 1, 1, 1),
(69903, 58086, 5, 1, 1, 1, 1),
(69903, 52190, 5, 1, 1, 1, 1),
(69903, 58145, 5, 1, 1, 1, 3),
(69903, 52191, 4, 1, 1, 1, 1),
(69903, 58088, 3, 1, 1, 1, 1),
(69903, 57192, 3, 1, 1, 1, 3),
(69903, 62251, 3, 1, 1, 1, 3),
(69903, 57193, 1.7, 1, 1, 1, 3),
(69903, 58091, 1.6, 1, 1, 1, 3),
(69903, 58146, 1.5, 1, 1, 1, 3),
(69903, 57194, 1.5, 1, 1, 1, 3),
(69903, 67438, 1.4, 1, 1, 1, 1),
(69903, 54436, 0.6, 1, 1, 1, 1),
(69903, 8490, 0.6, 1, 1, 1, 1),
(69903, 48120, 0.6, 1, 1, 1, 1),
(69903, 8495, 0.6, 1, 1, 1, 1),
(69903, 46398, 0.5, 1, 1, 1, 1),
(69903, 8496, 0.5, 1, 1, 1, 1),
(69903, 69991, 0.5, 1, 1, 1, 1),
(69903, 43698, 0.4, 1, 1, 1, 1),
(69903, 44980, 0.4, 1, 1, 1, 1),
(69903, 44721, 0.4, 1, 1, 1, 1),
(69903, 69992, 0.4, 1, 1, 1, 1),
(69903, 44965, 0.4, 1, 1, 1, 1),
(69903, 44971, 0.4, 1, 1, 1, 1),
(69903, 44984, 0.3, 1, 1, 1, 1),
(69903, 29901, 0.3, 1, 1, 1, 1),
(69903, 8491, 0.3, 1, 1, 1, 1),
(69903, 8485, 0.3, 1, 1, 1, 1),
(69903, 8487, 0.3, 1, 1, 1, 1),
(69903, 10392, 0.3, 1, 1, 1, 1),
(69903, 44970, 0.3, 1, 1, 1, 1),
(69903, 44973, 0.3, 1, 1, 1, 1),
(69903, 44974, 0.3, 1, 1, 1, 1),
(69903, 44982, 0.3, 1, 1, 1, 1),
(69903, 29953, 0.3, 1, 1, 1, 1),
(69903, 8500, 0.3, 1, 1, 1, 1),
(69903, 45002, 0.3, 1, 1, 1, 1),
(69903, 8492, 0.3, 1, 1, 1, 1),
(69903, 10394, 0.3, 1, 1, 1, 1),
(69903, 8497, 0.3, 1, 1, 1, 1),
(69903, 44707, 0.3, 1, 1, 1, 1),
(69903, 45606, 0.3, 1, 1, 1, 1),
(69903, 10393, 0.3, 1, 1, 1, 1),
(69903, 29904, 0.3, 1, 1, 1, 1),
(69903, 35504, 0.2, 1, 1, 1, 1),
(69903, 43953, 0.2, 1, 1, 1, 1),
(69903, 43962, 0.2, 1, 1, 1, 1),
(69903, 44151, 0.19, 1, 1, 1, 1),
(69903, 13335, 0.07, 1, 1, 1, 1),
(69903, 32768, 0.07, 1, 1, 1, 1),
(69903, 8494, 0.06, 1, 1, 1, 1);
-- Add missing dungeon ID to High Priestess Azil
UPDATE `instance_encounters` SET `lastEncounterDungeon`= 307 WHERE `entry`= 1057;
@@ -1540,6 +1540,9 @@ struct LFGDungeonEntry
uint32 grouptype; // 15
//char* desc; // 16 Description
uint32 randomCategoryId; // 17 RandomDungeonID assigned for this dungeon
uint32 requiredTanks; // 18
uint32 requiredHealers; // 19
uint32 requiredDamageDealers; // 20
// Helpers
uint32 Entry() const { return ID + (type << 24); }
};
+1 -1
View File
@@ -101,7 +101,7 @@ char const ItemLimitCategoryEntryfmt[] = "nxii";
char const ItemRandomPropertiesfmt[] = "nxiiixxs";
char const ItemRandomSuffixfmt[] = "nsxiiiiiiiiii";
char const ItemSetEntryfmt[] = "dsiiiiiiiiiixxxxxxxiiiiiiiiiiiiiiiiii";
char const LFGDungeonEntryfmt[] = "nsiiiiiiiiixxixixixxx";
char const LFGDungeonEntryfmt[] = "nsiiiiiiiiixxixixiiii";
char const LightEntryfmt[] = "nifffxxxxxxxxxx";
char const LiquidTypefmt[] = "nxxixixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
char const LockEntryfmt[] = "niiiiiiiiiiiiiiiiiiiiiiiixxxxxxxx";
-7
View File
@@ -24,13 +24,6 @@
namespace lfg
{
enum LFGEnum
{
LFG_TANKS_NEEDED = 1,
LFG_HEALERS_NEEDED = 1,
LFG_DPS_NEEDED = 3
};
enum LfgRoles
{
PLAYER_ROLE_NONE = 0x00,
+128 -29
View File
@@ -28,6 +28,7 @@
#include "LFGQueue.h"
#include "Group.h"
#include "Player.h"
#include "Map.h"
#include "RBAC.h"
#include "GroupMgr.h"
#include "GameEventMgr.h"
@@ -38,7 +39,9 @@ namespace lfg
{
LFGMgr::LFGMgr(): m_QueueTimer(0), m_lfgProposalId(1),
m_options(sWorld->getIntConfig(CONFIG_LFG_OPTIONSMASK))
m_options(sWorld->getIntConfig(CONFIG_LFG_OPTIONSMASK)),
_isCallToArmEligible(sWorld->getBoolConfig(CONFIG_LFG_CALL_TO_ARMS_ENABLED)),
_callToArmsRoles(PLAYER_ROLE_TANK | PLAYER_ROLE_HEALER)
{
}
@@ -167,6 +170,14 @@ LFGDungeonData const* LFGMgr::GetLFGDungeon(uint32 id)
return NULL;
}
bool LFGMgr::IsCallToArmEligible(uint32 level, uint32 dungeonId)
{
if (LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(dungeonId))
return (level == DEFAULT_MAX_LEVEL && dungeon->type == LFG_TYPE_RANDOM && dungeon->difficulty == DUNGEON_DIFFICULTY_HEROIC);
return false;
}
void LFGMgr::LoadLFGDungeons(bool reload /* = false */)
{
uint32 oldMSTime = getMSTime();
@@ -186,7 +197,7 @@ void LFGMgr::LoadLFGDungeons(bool reload /* = false */)
case LFG_TYPE_HEROIC:
case LFG_TYPE_RAID:
case LFG_TYPE_RANDOM:
LfgDungeonStore[dungeon->ID] = LFGDungeonData(dungeon);
LfgDungeonStore.insert(LFGDungeonContainer::value_type(dungeon->ID, LFGDungeonData(dungeon)));
break;
}
}
@@ -356,8 +367,22 @@ void LFGMgr::Update(uint32 diff)
if (m_QueueTimer > LFG_QUEUEUPDATE_INTERVAL)
{
m_QueueTimer = 0;
uint32 tankCount = 0;
uint32 healerCount = 0;
uint32 dpsCount = 0;
for (LfgQueueContainer::iterator it = QueuesStore.begin(); it != QueuesStore.end(); ++it)
it->second.UpdateQueueTimers(it->first, currTime);
it->second.UpdateQueueTimers(it->first, currTime, tankCount, healerCount, dpsCount);
LFGMgr::RemoveCallToArmsRole(PLAYER_ROLE_HEALER);
LFGMgr::RemoveCallToArmsRole(PLAYER_ROLE_TANK);
LFGMgr::RemoveCallToArmsRole(PLAYER_ROLE_DAMAGE);
if (!tankCount || tankCount < dpsCount)
LFGMgr::AddCallToArmsRole(PLAYER_ROLE_TANK);
if (!healerCount || healerCount < dpsCount)
LFGMgr::AddCallToArmsRole(PLAYER_ROLE_HEALER);
if (dpsCount && (dpsCount < tankCount || dpsCount < healerCount))
AddCallToArmsRole(PLAYER_ROLE_DAMAGE);
}
else
m_QueueTimer += diff;
@@ -671,6 +696,16 @@ void LFGMgr::UpdateRoleCheck(ObjectGuid gguid, ObjectGuid guid /* = ObjectGuid::
LfgRoleCheck& roleCheck = itRoleCheck->second;
bool sendRoleChosen = roleCheck.state != LFG_ROLECHECK_DEFAULT && guid;
LfgDungeonSet dungeons;
if (roleCheck.rDungeonId)
dungeons.insert(roleCheck.rDungeonId);
else
dungeons = roleCheck.dungeons;
LFGDungeonData const* dungeon = nullptr;
if (!dungeons.empty())
dungeon = sLFGMgr->GetLFGDungeon(*dungeons.begin());
if (!guid)
roleCheck.state = LFG_ROLECHECK_ABORTED;
else if (roles < PLAYER_ROLE_TANK) // Player selected no role.
@@ -688,16 +723,10 @@ void LFGMgr::UpdateRoleCheck(ObjectGuid gguid, ObjectGuid guid /* = ObjectGuid::
{
// use temporal var to check roles, CheckGroupRoles modifies the roles
check_roles = roleCheck.roles;
roleCheck.state = CheckGroupRoles(check_roles) ? LFG_ROLECHECK_FINISHED : LFG_ROLECHECK_WRONG_ROLES;
roleCheck.state = (dungeon && CheckGroupRoles(check_roles, dungeon)) ? LFG_ROLECHECK_FINISHED : LFG_ROLECHECK_WRONG_ROLES;
}
}
LfgDungeonSet dungeons;
if (roleCheck.rDungeonId)
dungeons.insert(roleCheck.rDungeonId);
else
dungeons = roleCheck.dungeons;
LfgJoinResult joinResult = LFG_JOIN_FAILED;
if (roleCheck.state == LFG_ROLECHECK_MISSING_ROLE || roleCheck.state == LFG_ROLECHECK_WRONG_ROLES)
joinResult = LFG_JOIN_ROLE_CHECK_FAILED;
@@ -806,8 +835,9 @@ void LFGMgr::GetCompatibleDungeons(LfgDungeonSet& dungeons, GuidSet const& playe
@param[in] groles Map of roles to check
@return True if roles are compatible
*/
bool LFGMgr::CheckGroupRoles(LfgRolesMap& groles)
bool LFGMgr::CheckGroupRoles(LfgRolesMap& groles, LFGDungeonData const* dungeon)
{
ASSERT(dungeon);
if (groles.empty())
return false;
@@ -826,11 +856,11 @@ bool LFGMgr::CheckGroupRoles(LfgRolesMap& groles)
if (role != PLAYER_ROLE_DAMAGE)
{
it->second -= PLAYER_ROLE_DAMAGE;
if (CheckGroupRoles(groles))
if (CheckGroupRoles(groles, dungeon))
return true;
it->second += PLAYER_ROLE_DAMAGE;
}
else if (damage == LFG_DPS_NEEDED)
else if (damage == dungeon->requiredDamageDealers)
return false;
else
damage++;
@@ -841,11 +871,11 @@ bool LFGMgr::CheckGroupRoles(LfgRolesMap& groles)
if (role != PLAYER_ROLE_HEALER)
{
it->second -= PLAYER_ROLE_HEALER;
if (CheckGroupRoles(groles))
if (CheckGroupRoles(groles, dungeon))
return true;
it->second += PLAYER_ROLE_HEALER;
}
else if (healer == LFG_HEALERS_NEEDED)
else if (healer == dungeon->requiredHealers)
return false;
else
healer++;
@@ -856,11 +886,11 @@ bool LFGMgr::CheckGroupRoles(LfgRolesMap& groles)
if (role != PLAYER_ROLE_TANK)
{
it->second -= PLAYER_ROLE_TANK;
if (CheckGroupRoles(groles))
if (CheckGroupRoles(groles, dungeon))
return true;
it->second += PLAYER_ROLE_TANK;
}
else if (tank == LFG_TANKS_NEEDED)
else if (tank == dungeon->requiredTanks)
return false;
else
tank++;
@@ -909,7 +939,10 @@ void LFGMgr::MakeNewGroup(LfgProposal const& proposal)
if (!grp)
{
grp = new Group();
grp->ConvertToLFG();
if (dungeon->IsRaid())
grp->ConvertToLFR();
else
grp->ConvertToLFG();
grp->Create(player);
ObjectGuid gguid = grp->GetGUID();
SetState(gguid, LFG_STATE_PROPOSAL);
@@ -920,26 +953,35 @@ void LFGMgr::MakeNewGroup(LfgProposal const& proposal)
grp->SetLfgRoles(pguid, proposal.players.find(pguid)->second.role);
for (GuidList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
{
ObjectGuid temppguid = (*itr);
player->GetSession()->SendNameQueryOpcode(temppguid);
}
// Add the cooldown spell if queued for a random dungeon
if (dungeon->type == LFG_TYPE_RANDOM)
player->CastSpell(player, LFG_SPELL_DUNGEON_COOLDOWN, false);
}
ASSERT(grp);
grp->SetDungeonDifficulty(Difficulty(dungeon->difficulty));
if (dungeon->IsRaid())
grp->SetRaidDifficulty(Difficulty(dungeon->difficulty));
else
grp->SetDungeonDifficulty(Difficulty(dungeon->difficulty));
ObjectGuid gguid = grp->GetGUID();
SetDungeon(gguid, dungeon->Entry());
SetState(gguid, LFG_STATE_DUNGEON);
_SaveToDB(gguid, grp->GetDbStoreId());
// Update group info
grp->SendUpdate();
// Teleport Player
for (GuidList::const_iterator it = playersToTeleport.begin(); it != playersToTeleport.end(); ++it)
if (Player* player = ObjectAccessor::FindPlayer(*it))
TeleportPlayer(player, false);
// Update group info
grp->SendUpdate();
}
uint32 LFGMgr::AddProposal(LfgProposal& proposal)
@@ -1221,8 +1263,14 @@ void LFGMgr::UpdateBoot(ObjectGuid guid, bool accept)
}
}
bool raidFinderGroup = false;
if (Group* group = sGroupMgr->GetGroupByGUID(gguid.GetCounter()))
if (group->isLFRGroup())
raidFinderGroup = true;
// if we don't have enough votes (agree or deny) do nothing
if (agreeNum < LFG_GROUP_KICK_VOTES_NEEDED && (votesNum - agreeNum) < LFG_GROUP_KICK_VOTES_NEEDED)
if (agreeNum < (raidFinderGroup ? LFR_GROUP_KICK_VOTES_NEEDED : LFG_GROUP_KICK_VOTES_NEEDED)
&& (votesNum - agreeNum) < (raidFinderGroup ? LFR_GROUP_KICK_VOTES_NEEDED : LFG_GROUP_KICK_VOTES_NEEDED))
return;
// Send update info to all players
@@ -1235,7 +1283,7 @@ void LFGMgr::UpdateBoot(ObjectGuid guid, bool accept)
}
SetVoteKick(gguid, false);
if (agreeNum == LFG_GROUP_KICK_VOTES_NEEDED) // Vote passed - Kick player
if (agreeNum == (raidFinderGroup ? LFR_GROUP_KICK_VOTES_NEEDED : LFG_GROUP_KICK_VOTES_NEEDED)) // Vote passed - Kick player
{
if (Group* group = sGroupMgr->GetGroupByGUID(gguid.GetCounter()))
Player::RemoveFromGroup(group, boot.victim, GROUP_REMOVEMETHOD_KICK_LFG);
@@ -1251,7 +1299,7 @@ void LFGMgr::UpdateBoot(ObjectGuid guid, bool accept)
@param[in] out Teleport out (true) or in (false)
@param[in] fromOpcode Function called from opcode handlers? (Default false)
*/
void LFGMgr::TeleportPlayer(Player* player, bool out, bool fromOpcode /*= false*/)
void LFGMgr::TeleportPlayer(Player* player, bool out, bool fromOpcode /*= false*/, bool saveEntryPoint /*= true*/)
{
LFGDungeonData const* dungeon = NULL;
Group* group = player->GetGroup();
@@ -1299,7 +1347,7 @@ void LFGMgr::TeleportPlayer(Player* player, bool out, bool fromOpcode /*= false*
float z = dungeon->z;
float orientation = dungeon->o;
if (!fromOpcode)
if (!fromOpcode && saveEntryPoint)
{
// Select a player inside to be teleported to
for (GroupReference* itr = group->GetFirstMember(); itr != NULL && !mapid; itr = itr->next())
@@ -1316,8 +1364,17 @@ void LFGMgr::TeleportPlayer(Player* player, bool out, bool fromOpcode /*= false*
}
}
}
else if (player->HasValidLFGLeavePoint(mapid) && saveEntryPoint)
{
Position pos;
player->GetLFGLeavePoint(&pos);
x = pos.m_positionX;
y = pos.m_positionY;
z = pos.m_positionZ;
orientation = pos.GetOrientation();
}
if (!player->GetMap()->IsDungeon())
if (!player->GetMap()->IsDungeon() && saveEntryPoint)
player->SetBattlegroundEntryPoint();
if (player->IsInFlight())
@@ -1330,7 +1387,15 @@ void LFGMgr::TeleportPlayer(Player* player, bool out, bool fromOpcode /*= false*
error = LFG_TELEPORTERROR_INVALID_LOCATION;
}
else
error = LFG_TELEPORTERROR_INVALID_LOCATION;
{
if (player->IsInCombat())
error = LFG_TELEPORTERROR_IN_COMBAT;
else if (player->GetMapId() == uint32(dungeon->map))
{
player->SetLFGLeavePoint();
player->TeleportToBGEntryPoint();
}
}
if (error != LFG_TELEPORTERROR_OK)
player->GetSession()->SendLfgTeleportError(uint8(error));
@@ -1430,6 +1495,17 @@ void LFGMgr::FinishDungeon(ObjectGuid gguid, const uint32 dungeonId, Map const*
// we give reward without informing client (retail does this)
player->RewardQuest(quest, 0, NULL, false);
}
uint8 tmpRole = 0;
if (Group *group = player->GetGroup())
tmpRole = group->GetLfgRoles(player->GetGUID());
if (IsCallToArmEligible(player->getLevel(), rDungeonId & 0x00FFFFFF))
if (player->GetCallToArmsTempRoles() & tmpRole)
{
const Quest *q = sObjectMgr->GetQuestTemplate(LFG_CALL_TO_ARMS_QUEST);
player->RewardQuest(q, 0, NULL, false);
}
player->SetTempCallToArmsRoles(0);
// Give rewards
TC_LOG_DEBUG("lfg.dungeon.finish", "Group: %s, Player: %s done dungeon %u, %s previously done.", gguid.ToString().c_str(), guid.ToString().c_str(), GetDungeon(gguid), done ? " " : " not");
@@ -1556,6 +1632,20 @@ uint32 LFGMgr::GetDungeonMapId(ObjectGuid guid)
return mapId;
}
uint32 LFGMgr::GetDungeonIdForDifficulty(uint32 dungeonId, Difficulty difficulty)
{
if (LFGDungeonData const* baseDungeon = GetLFGDungeon(dungeonId))
{
uint16 mapId = baseDungeon->map;
LfgDungeonSet const& dungeons = GetDungeonsByRandom(0);
for (LfgDungeonSet::const_iterator it = dungeons.begin(); it != dungeons.end(); ++it)
if (LFGDungeonData const* dungeon = GetLFGDungeon(*it))
if (dungeon->map == mapId && Difficulty(dungeon->difficulty) == difficulty)
return dungeon->id;
}
return 0;
}
uint8 LFGMgr::GetRoles(ObjectGuid guid)
{
uint8 roles = PlayersStore[guid].GetRoles();
@@ -1608,6 +1698,8 @@ LfgLockMap const LFGMgr::GetLockedDungeons(ObjectGuid guid)
lockStatus = LFG_LOCKSTATUS_RAID_LOCKED;
else if (dungeon->difficulty > DUNGEON_DIFFICULTY_NORMAL && player->GetBoundInstance(dungeon->map, Difficulty(dungeon->difficulty)))
lockStatus = LFG_LOCKSTATUS_RAID_LOCKED;
else if (dungeon->difficulty > DUNGEON_DIFFICULTY_NORMAL && player->GetBoundInstance(dungeon->map, Difficulty(dungeon->difficulty), dungeon->type == LFG_TYPE_RAID))
lockStatus = LFG_LOCKSTATUS_RAID_LOCKED;
else if (dungeon->minlevel > level)
lockStatus = LFG_LOCKSTATUS_TOO_LOW_LEVEL;
else if (dungeon->maxlevel < level)
@@ -2039,11 +2131,18 @@ LfgDungeonSet LFGMgr::GetRandomAndSeasonalDungeons(uint8 level, uint8 expansion)
for (lfg::LFGDungeonContainer::const_iterator itr = LfgDungeonStore.begin(); itr != LfgDungeonStore.end(); ++itr)
{
lfg::LFGDungeonData const& dungeon = itr->second;
if ((dungeon.type == lfg::LFG_TYPE_RANDOM || (dungeon.seasonal && sLFGMgr->IsSeasonActive(dungeon.id)))
if ((dungeon.type == lfg::LFG_TYPE_RANDOM || dungeon.IsRaid()|| (dungeon.seasonal && sLFGMgr->IsSeasonActive(dungeon.id)))
&& dungeon.expansion <= expansion && dungeon.minlevel <= level && level <= dungeon.maxlevel)
randomDungeons.insert(dungeon.Entry());
}
return randomDungeons;
}
bool LFGDungeonData::IsRaid() const
{
if (MapEntry const* mapInfo = sMapStore.LookupEntry(map))
return mapInfo->IsRaid();
return false;
}
} // namespace lfg
+31 -11
View File
@@ -48,7 +48,8 @@ enum LFGMgrEnum
LFG_SPELL_DUNGEON_COOLDOWN = 71328,
LFG_SPELL_DUNGEON_DESERTER = 71041,
LFG_SPELL_LUCK_OF_THE_DRAW = 72221,
LFG_GROUP_KICK_VOTES_NEEDED = 3
LFG_GROUP_KICK_VOTES_NEEDED = 4,
LFR_GROUP_KICK_VOTES_NEEDED = 15
};
enum LfgFlags
@@ -56,7 +57,7 @@ enum LfgFlags
LFG_FLAG_UNK1 = 0x1,
LFG_FLAG_UNK2 = 0x2,
LFG_FLAG_SEASONAL = 0x4,
LFG_FLAG_UNK3 = 0x8
LFG_FLAG_UNK3 = 0x8,
};
/// Determines the type of instance
@@ -87,7 +88,8 @@ enum LfgTeleportError
LFG_TELEPORTERROR_IN_VEHICLE = 3,
LFG_TELEPORTERROR_FATIGUE = 4,
LFG_TELEPORTERROR_INVALID_LOCATION = 6,
LFG_TELEPORTERROR_CHARMING = 8 // FIXME - It can be 7 or 8 (Need proper data)
LFG_TELEPORTERROR_CHARMING = 7,
LFG_TELEPORTERROR_IN_COMBAT = 8
};
/// Queue join results
@@ -126,6 +128,8 @@ enum LfgRoleCheckState
LFG_ROLECHECK_NO_ROLE = 6 // Someone selected no role
};
#define LFG_CALL_TO_ARMS_QUEST 29339
// Forward declaration (just to have all typedef together)
struct LFGDungeonData;
struct LfgReward;
@@ -268,15 +272,14 @@ struct LfgPlayerBoot
struct LFGDungeonData
{
LFGDungeonData(): id(0), name(""), map(0), type(0), expansion(0), group(0), minlevel(0),
maxlevel(0), difficulty(REGULAR_DIFFICULTY), seasonal(false), x(0.0f), y(0.0f), z(0.0f), o(0.0f),
requiredItemLevel(0)
{ }
LFGDungeonData() = delete;
LFGDungeonData(LFGDungeonEntry const* dbc): id(dbc->ID), name(dbc->name), map(dbc->map),
type(dbc->type), expansion(dbc->expansion), group(dbc->grouptype),
minlevel(dbc->minlevel), maxlevel(dbc->maxlevel), difficulty(Difficulty(dbc->difficulty)),
seasonal((dbc->flags & LFG_FLAG_SEASONAL) != 0), x(0.0f), y(0.0f), z(0.0f), o(0.0f),
requiredItemLevel(0)
requiredItemLevel(0), requiredTanks(dbc->requiredTanks), requiredHealers(dbc->requiredHealers),
requiredDamageDealers(dbc->requiredDamageDealers)
{ }
uint32 id;
@@ -291,9 +294,14 @@ struct LFGDungeonData
bool seasonal;
float x, y, z, o;
uint16 requiredItemLevel;
uint32 requiredTanks;
uint32 requiredHealers;
uint32 requiredDamageDealers;
// Helpers
uint32 Entry() const { return id + (type << 24); }
uint32 GetMaxGroupSize() const { return requiredTanks + requiredHealers + requiredDamageDealers; }
bool IsRaid() const;
};
class TC_GAME_API LFGMgr
@@ -331,6 +339,8 @@ class TC_GAME_API LFGMgr
uint32 GetDungeon(ObjectGuid guid, bool asId = true);
/// Get the map id of the current dungeon
uint32 GetDungeonMapId(ObjectGuid guid);
//// Get the heroic version of the current dungeon Id
uint32 GetDungeonIdForDifficulty(uint32 dungeonId, Difficulty difficulty);
/// Get kicks left in current group
uint8 GetKicksLeft(ObjectGuid gguid);
/// Load Lfg group info from DB
@@ -339,6 +349,12 @@ class TC_GAME_API LFGMgr
void SetupGroupMember(ObjectGuid guid, ObjectGuid gguid);
/// Return Lfg dungeon entry for given dungeon id
uint32 GetLFGDungeonEntry(uint32 id);
/// Handles Call to Arms bonuses
bool IsCallToArmEligible(uint32 level, uint32 dungeonId);
uint8 GetRolesForCallToArms() { return _callToArmsRoles; }
void AddCallToArmsRole(uint8 role) { _callToArmsRoles |= role; }
void RemoveCallToArmsRole(uint8 role) { _callToArmsRoles = _callToArmsRoles & ~role; }
void SetCallToArmEligible(bool val) { _isCallToArmEligible = val; }
// cs_lfg
/// Get current player roles
@@ -386,7 +402,7 @@ class TC_GAME_API LFGMgr
/// Returns all random and seasonal dungeons for given level and expansion
LfgDungeonSet GetRandomAndSeasonalDungeons(uint8 level, uint8 expansion);
/// Teleport a player to/from selected dungeon
void TeleportPlayer(Player* player, bool out, bool fromOpcode = false);
void TeleportPlayer(Player* player, bool out, bool fromOpcode = false, bool saveEntryPoint = true);
/// Inits new proposal to boot a player
void InitBoot(ObjectGuid gguid, ObjectGuid kguid, ObjectGuid vguid, std::string const& reason);
/// Updates player boot proposal with new player answer
@@ -420,11 +436,13 @@ class TC_GAME_API LFGMgr
/// Gets queue join time
time_t GetQueueJoinTime(ObjectGuid guid);
/// Checks if given roles match, modifies given roles map with new roles
static bool CheckGroupRoles(LfgRolesMap &groles);
static bool CheckGroupRoles(LfgRolesMap& groles, LFGDungeonData const* dungeon);
/// Checks if given players are ignoring each other
static bool HasIgnore(ObjectGuid guid1, ObjectGuid guid2);
/// Sends queue status to player
static void SendLfgQueueStatus(ObjectGuid guid, LfgQueueStatusData const& data);
/// Returns dungeon datas based on the dungeon ID
LFGDungeonData const* GetLFGDungeon(uint32 id);
private:
uint8 GetTeam(ObjectGuid guid);
@@ -438,7 +456,6 @@ class TC_GAME_API LFGMgr
void RemovePlayerData(ObjectGuid guid);
void GetCompatibleDungeons(LfgDungeonSet& dungeons, GuidSet const& players, LfgLockPartyMap& lockMap, bool isContinue);
void _SaveToDB(ObjectGuid guid, uint32 db_guid);
LFGDungeonData const* GetLFGDungeon(uint32 id);
// Proposals
void RemoveProposal(LfgProposalContainer::iterator itProposal, LfgUpdateType type);
@@ -475,6 +492,9 @@ class TC_GAME_API LFGMgr
LfgPlayerBootContainer BootsStore; ///< Current player kicks
LfgPlayerDataContainer PlayersStore; ///< Player data
LfgGroupDataContainer GroupsStore; ///< Group data
// Call to Arms System
bool _isCallToArmEligible;
uint8 _callToArmsRoles;
};
} // namespace lfg
+79 -51
View File
@@ -80,6 +80,23 @@ char const* GetCompatibleString(LfgCompatibility compatibles)
}
}
void LfgQueueData::InitializeGroupSetup()
{
tanks = -1;
healers = -1;
dps = -1;
if (!dungeons.empty())
{
if (LFGDungeonData const* dungeon = sLFGMgr->GetLFGDungeon(*dungeons.begin()))
{
tanks = dungeon->requiredTanks;
healers = dungeon->requiredHealers;
dps = dungeon->requiredDamageDealers;
}
}
}
std::string LFGQueue::GetDetailedMatchRoles(GuidList const& check) const
{
if (check.empty())
@@ -365,7 +382,7 @@ LfgCompatibility LFGQueue::CheckCompatibility(GuidList check)
LfgRolesMap proposalRoles;
// Check for correct size
if (check.size() > MAXGROUPSIZE || check.empty())
if (check.empty())
{
TC_LOG_DEBUG("lfg.queue.match.compatibility.check", "Guids: (%s): Size wrong - Not compatibles", GetDetailedMatchRoles(check).c_str());
return LFG_INCOMPATIBLES_WRONG_GROUP_SIZE;
@@ -388,10 +405,54 @@ LfgCompatibility LFGQueue::CheckCompatibility(GuidList check)
check.push_front(frontGuid);
}
std::ostringstream o;
// Find compatible dungeons
if (check.size() > 1)
{
GuidList::iterator itguid = check.begin();
proposalDungeons = QueueDataStore[*itguid].dungeons;
for (++itguid; itguid != check.end(); ++itguid)
{
LfgDungeonSet temporal;
LfgDungeonSet& dungeons = QueueDataStore[*itguid].dungeons;
std::set_intersection(proposalDungeons.begin(), proposalDungeons.end(), dungeons.begin(), dungeons.end(), std::inserter(temporal, temporal.begin()));
proposalDungeons = temporal;
}
}
else
{
proposalDungeons = QueueDataStore[check.front()].dungeons;
}
LFGDungeonData const* dungeon = nullptr;
do
{
if (proposalDungeons.empty())
{
TC_LOG_DEBUG("lfg.queue.match.compatibility.check", "LFGQueue::CheckCompatibility: (%s) No compatible dungeons%s", strGuids.c_str(), o.str().c_str());
SetCompatibles(strGuids, LFG_INCOMPATIBLES_NO_DUNGEONS);
return LFG_INCOMPATIBLES_NO_DUNGEONS;
}
proposal.dungeonId = Trinity::Containers::SelectRandomContainerElement(proposalDungeons);
proposalDungeons.erase(proposal.dungeonId);
dungeon = sLFGMgr->GetLFGDungeon(proposal.dungeonId);
} while (!dungeon);
// Check for correct size
if (check.size() > dungeon->GetMaxGroupSize())
{
TC_LOG_DEBUG("lfg.queue.match.compatibility.check", "LFGQueue::CheckCompatibility: (%s): Size wrong - Not compatibles", strGuids.c_str());
return LFG_INCOMPATIBLES_WRONG_GROUP_SIZE;
}
// Check if more than one LFG group and number of players joining
uint8 numPlayers = 0;
uint8 numLfgGroups = 0;
for (GuidList::const_iterator it = check.begin(); it != check.end() && numLfgGroups < 2 && numPlayers <= MAXGROUPSIZE; ++it)
for (GuidList::const_iterator it = check.begin(); it != check.end() && numLfgGroups < 1 && numPlayers <= dungeon->GetMaxGroupSize(); ++it)
{
ObjectGuid guid = *it;
LfgQueueDataContainer::iterator itQueue = QueueDataStore.find(guid);
@@ -416,21 +477,6 @@ LfgCompatibility LFGQueue::CheckCompatibility(GuidList check)
}
}
// Group with less that MAXGROUPSIZE members always compatible
if (check.size() == 1 && numPlayers != MAXGROUPSIZE)
{
TC_LOG_DEBUG("lfg.queue.match.compatibility.check", "Guids: (%s) single group. Compatibles", GetDetailedMatchRoles(check).c_str());
LfgQueueDataContainer::iterator itQueue = QueueDataStore.find(check.front());
LfgCompatibilityData data(LFG_COMPATIBLES_WITH_LESS_PLAYERS);
data.roles = itQueue->second.roles;
LFGMgr::CheckGroupRoles(data.roles);
UpdateBestCompatibleInQueue(itQueue, strGuids, data.roles);
SetCompatibilityData(strGuids, data);
return LFG_COMPATIBLES_WITH_LESS_PLAYERS;
}
if (numLfgGroups > 1)
{
TC_LOG_DEBUG("lfg.queue.match.compatibility.check", "Guids: (%s) More than one Lfggroup (%u)", GetDetailedMatchRoles(check).c_str(), numLfgGroups);
@@ -438,7 +484,7 @@ LfgCompatibility LFGQueue::CheckCompatibility(GuidList check)
return LFG_INCOMPATIBLES_MULTIPLE_LFG_GROUPS;
}
if (numPlayers > MAXGROUPSIZE)
if (numPlayers > dungeon->GetMaxGroupSize())
{
TC_LOG_DEBUG("lfg.queue.match.compatibility.check", "Guids: (%s) Too many players (%u)", GetDetailedMatchRoles(check).c_str(), numPlayers);
SetCompatibles(strGuids, LFG_INCOMPATIBLES_TOO_MUCH_PLAYERS);
@@ -474,7 +520,7 @@ LfgCompatibility LFGQueue::CheckCompatibility(GuidList check)
}
LfgRolesMap debugRoles = proposalRoles;
if (!LFGMgr::CheckGroupRoles(proposalRoles))
if (!LFGMgr::CheckGroupRoles(proposalRoles, dungeon))
{
std::ostringstream o;
for (LfgRolesMap::const_iterator it = debugRoles.begin(); it != debugRoles.end(); ++it)
@@ -484,38 +530,15 @@ LfgCompatibility LFGQueue::CheckCompatibility(GuidList check)
SetCompatibles(strGuids, LFG_INCOMPATIBLES_NO_ROLES);
return LFG_INCOMPATIBLES_NO_ROLES;
}
GuidList::iterator itguid = check.begin();
proposalDungeons = QueueDataStore[*itguid].dungeons;
std::ostringstream o;
o << ", " << itguid->GetRawValue() << ": (" << ConcatenateDungeons(proposalDungeons) << ")";
for (++itguid; itguid != check.end(); ++itguid)
{
LfgDungeonSet temporal;
LfgDungeonSet& dungeons = QueueDataStore[*itguid].dungeons;
o << ", " << itguid->GetRawValue() << ": (" << ConcatenateDungeons(dungeons) << ")";
std::set_intersection(proposalDungeons.begin(), proposalDungeons.end(), dungeons.begin(), dungeons.end(), std::inserter(temporal, temporal.begin()));
proposalDungeons = temporal;
}
if (proposalDungeons.empty())
{
TC_LOG_DEBUG("lfg.queue.match.compatibility.check", "Guids: (%s) No compatible dungeons%s", GetDetailedMatchRoles(check).c_str(), o.str().c_str());
SetCompatibles(strGuids, LFG_INCOMPATIBLES_NO_DUNGEONS);
return LFG_INCOMPATIBLES_NO_DUNGEONS;
}
}
else
{
ObjectGuid gguid = *check.begin();
const LfgQueueData &queue = QueueDataStore[gguid];
proposalDungeons = queue.dungeons;
proposalRoles = queue.roles;
LFGMgr::CheckGroupRoles(proposalRoles); // assing new roles
proposalRoles = QueueDataStore[check.front()].roles;
LFGMgr::CheckGroupRoles(proposalRoles, dungeon); // assign new roles
}
// Enough players?
if (numPlayers != MAXGROUPSIZE)
if (numPlayers != dungeon->GetMaxGroupSize())
{
TC_LOG_DEBUG("lfg.queue.match.compatibility.check", "Guids: (%s) Compatibles but not enough players(%u)", GetDetailedMatchRoles(check).c_str(), numPlayers);
LfgCompatibilityData data(LFG_COMPATIBLES_WITH_LESS_PLAYERS);
@@ -528,7 +551,7 @@ LfgCompatibility LFGQueue::CheckCompatibility(GuidList check)
return LFG_COMPATIBLES_WITH_LESS_PLAYERS;
}
ObjectGuid gguid = *check.begin();
ObjectGuid gguid = check.front();
proposal.queues = check;
proposal.isNew = numLfgGroups != 1 || sLFGMgr->GetOldState(gguid) != LFG_STATE_DUNGEON;
@@ -543,7 +566,6 @@ LfgCompatibility LFGQueue::CheckCompatibility(GuidList check)
proposal.cancelTime = time(NULL) + LFG_TIME_PROPOSAL;
proposal.state = LFG_PROPOSAL_INITIATING;
proposal.leader.Clear();
proposal.dungeonId = Trinity::Containers::SelectRandomContainerElement(proposalDungeons);
bool leader = false;
for (LfgRolesMap::const_iterator itRoles = proposalRoles.begin(); itRoles != proposalRoles.end(); ++itRoles)
@@ -581,7 +603,7 @@ LfgCompatibility LFGQueue::CheckCompatibility(GuidList check)
return LFG_COMPATIBLES_MATCH;
}
void LFGQueue::UpdateQueueTimers(uint8 queueId, time_t currTime)
void LFGQueue::UpdateQueueTimers(uint8 queueId, time_t currTime, uint32 &tankCount, uint32 &healerCount, uint32 &dpsCount)
{
TC_LOG_TRACE("lfg.queue.timers.update", "Updating queue timers...");
for (LfgQueueDataContainer::iterator itQueue = QueueDataStore.begin(); itQueue != QueueDataStore.end(); ++itQueue)
@@ -600,6 +622,13 @@ void LFGQueue::UpdateQueueTimers(uint8 queueId, time_t currTime)
role |= itPlayer->second;
role &= ~PLAYER_ROLE_LEADER;
if (role & PLAYER_ROLE_TANK)
tankCount++;
if (role & PLAYER_ROLE_HEALER)
healerCount++;
if (role & PLAYER_ROLE_DAMAGE)
dpsCount++;
switch (role)
{
case PLAYER_ROLE_NONE: // Should not happen - just in case
@@ -724,9 +753,8 @@ void LFGQueue::UpdateBestCompatibleInQueue(LfgQueueDataContainer::iterator itrQu
queueData.bestCompatible.c_str(), key.c_str(), itrQueue->first.ToString().c_str());
queueData.bestCompatible = key;
queueData.tanks = LFG_TANKS_NEEDED;
queueData.healers = LFG_HEALERS_NEEDED;
queueData.dps = LFG_DPS_NEEDED;
queueData.InitializeGroupSetup();
for (LfgRolesMap::const_iterator it = roles.begin(); it != roles.end(); ++it)
{
uint8 role = it->second;
+12 -8
View File
@@ -51,14 +51,16 @@ struct LfgCompatibilityData
/// Stores player or group queue info
struct LfgQueueData
{
LfgQueueData(): joinTime(time_t(time(NULL))), tanks(LFG_TANKS_NEEDED),
healers(LFG_HEALERS_NEEDED), dps(LFG_DPS_NEEDED)
{ }
LfgQueueData(): joinTime(time_t(time(NULL)))
{
InitializeGroupSetup();
}
LfgQueueData(time_t _joinTime, LfgDungeonSet const& _dungeons, LfgRolesMap const& _roles):
joinTime(_joinTime), tanks(LFG_TANKS_NEEDED), healers(LFG_HEALERS_NEEDED),
dps(LFG_DPS_NEEDED), dungeons(_dungeons), roles(_roles)
{ }
LfgQueueData(time_t _joinTime, LfgDungeonSet const& _dungeons, LfgRolesMap const& _roles) :
joinTime(_joinTime), dungeons(_dungeons), roles(_roles)
{
InitializeGroupSetup();
}
time_t joinTime; ///< Player queue join time (to calculate wait times)
uint8 tanks; ///< Tanks needed
@@ -67,6 +69,8 @@ struct LfgQueueData
LfgDungeonSet dungeons; ///< Selected Player/Group Dungeon/s
LfgRolesMap roles; ///< Selected Player Role/s
std::string bestCompatible; ///< Best compatible combination of people queued
void InitializeGroupSetup();
};
struct LfgWaitTime
@@ -101,7 +105,7 @@ class TC_GAME_API LFGQueue
void UpdateWaitTimeDps(int32 waitTime, uint32 dungeonId);
// Update Queue timers
void UpdateQueueTimers(uint8 queueId, time_t currTime);
void UpdateQueueTimers(uint8 queueId, time_t currTime, uint32 &tankCount, uint32 &healerCount, uint32 &dpsCount);
time_t GetJoinTime(ObjectGuid guid) const;
// Find new group
+33 -2
View File
@@ -540,6 +540,8 @@ Player::Player(WorldSession* session): Unit(true), _archaeology(this)
m_achievementMgr = new AchievementMgr<Player>(this);
m_reputationMgr = new ReputationMgr(this);
_hasValidLFGLeavePoint = false;
}
Player::~Player()
@@ -14865,6 +14867,13 @@ bool Player::CanRewardQuest(Quest const* quest, bool msg)
if (quest->GetRewOrReqMoney() < 0 && !HasEnoughMoney(-int64(quest->GetRewOrReqMoney())))
return false;
// dungeon finder quests cannot be rewarded when hit weekly currency limit
if (quest->IsDFQuest())
for (uint8 i = 0; i < QUEST_REWARD_CURRENCY_COUNT; i++)
if (CurrencyTypesEntry const* currency = sCurrencyTypesStore.LookupEntry(quest->RewardCurrencyId[i]))
if (GetCurrencyOnWeek(quest->RewardCurrencyId[i], false) == GetCurrencyWeekCap(currency))
return false;
return true;
}
@@ -15224,7 +15233,7 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver,
CharacterDatabase.CommitTransaction(trans);
}
if (quest->IsDaily() || quest->IsDFQuest())
if ((quest->IsDaily() || quest->IsDFQuest()) && !quest->IsRepeatable())
{
SetDailyQuestStatus(quest_id);
if (quest->IsDaily())
@@ -15779,7 +15788,7 @@ bool Player::SatisfyQuestDay(Quest const* qInfo, bool msg) const
if (!qInfo->IsDaily() && !qInfo->IsDFQuest())
return true;
if (qInfo->IsDFQuest())
if (qInfo->IsDFQuest() && !qInfo->IsRepeatable())
{
if (m_DFQuests.find(qInfo->GetQuestId()) != m_DFQuests.end())
return false;
@@ -22575,6 +22584,28 @@ void Player::SetBattlegroundEntryPoint()
m_bgData.joinPos = WorldLocation(m_homebindMapId, m_homebindX, m_homebindY, m_homebindZ, 0.0f);
}
void Player::GetLFGLeavePoint(Position* pos)
{
if (pos)
{
pos->Relocate(m_bgData.leavePos.m_positionX, m_bgData.leavePos.m_positionY,
m_bgData.leavePos.m_positionZ, m_bgData.leavePos.GetOrientation());
_hasValidLFGLeavePoint = false;
}
}
bool Player::HasValidLFGLeavePoint(uint32 mapid)
{
return _hasValidLFGLeavePoint && MapManager::IsValidMapCoord(mapid, m_bgData.leavePos.m_positionX, m_bgData.leavePos.m_positionY,
m_bgData.leavePos.m_positionZ, m_bgData.leavePos.GetOrientation());
}
void Player::SetLFGLeavePoint()
{
m_bgData.leavePos = WorldLocation(GetMapId(), GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation());
_hasValidLFGLeavePoint = true;
}
void Player::SetBGTeam(uint32 team)
{
m_bgData.bgTeam = team;
+12
View File
@@ -1115,6 +1115,7 @@ struct BGData
uint32 taxiPath[2];
WorldLocation joinPos; ///< From where player entered BG
WorldLocation leavePos;
void ClearTaxiPath() { taxiPath[0] = taxiPath[1] = 0; }
bool HasTaxiPath() const { return taxiPath[0] && taxiPath[1]; }
@@ -2376,6 +2377,10 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
bool isUsingLfg() const;
bool inRandomLfgDungeon() const;
void GetLFGLeavePoint(Position* pos);
bool HasValidLFGLeavePoint(uint32 mapid);
void SetLFGLeavePoint();
typedef std::set<uint32> DFQuestsDoneList;
DFQuestsDoneList m_DFQuests;
@@ -2540,6 +2545,9 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
VoidStorageItem* GetVoidStorageItem(uint8 slot) const;
VoidStorageItem* GetVoidStorageItem(uint64 id, uint8& slot) const;
void SetTempCallToArmsRoles(uint8 roles) { _tmpLfgRolesCheck = roles; }
uint8 GetCallToArmsTempRoles() { return _tmpLfgRolesCheck; }
protected:
// Gamemaster whisper whitelist
GuidList WhisperList;
@@ -2890,6 +2898,8 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
uint32 _activeCheats;
uint32 _maxPersonalArenaRate;
bool _hasValidLFGLeavePoint;
// variables to save health and mana before duel and restore them after duel
uint32 healthBeforeDuel;
uint32 manaBeforeDuel;
@@ -2897,6 +2907,8 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
WorldLocation _corpseLocation;
Archaeology _archaeology;
uint8 _tmpLfgRolesCheck;
};
TC_GAME_API void AddItemsSetItem(Player* player, Item* item);
+34
View File
@@ -241,6 +241,26 @@ void Group::ConvertToLFG()
SendUpdate();
}
void Group::ConvertToLFR()
{
m_groupType = GroupType(m_groupType | GROUPTYPE_LFG | GROUPTYPE_LFG_RESTRICTED | GROUPTYPE_RAID);
m_lootMethod = NEED_BEFORE_GREED;
_initRaidSubGroupsCounter();
if (!isBGGroup() && !isBFGroup())
{
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GROUP_TYPE);
stmt->setUInt8(0, uint8(m_groupType));
stmt->setUInt32(1, m_dbStoreId);
CharacterDatabase.Execute(stmt);
}
SendUpdate();
}
void Group::ConvertToRaid()
{
m_groupType = GroupType(m_groupType | GROUPTYPE_RAID);
@@ -2374,6 +2394,15 @@ void Group::SetLfgRoles(ObjectGuid guid, uint8 roles)
SendUpdate();
}
uint8 Group::GetLfgRoles(ObjectGuid guid)
{
member_witerator slot = _getMemberWSlot(guid);
if (slot == m_memberSlots.end())
return 0;
return slot->roles;
}
bool Group::IsFull() const
{
return isRaidGroup() ? (m_memberSlots.size() >= MAXRAIDSIZE) : (m_memberSlots.size() >= MAXGROUPSIZE);
@@ -2384,6 +2413,11 @@ bool Group::isLFGGroup() const
return (m_groupType & GROUPTYPE_LFG) != 0;
}
bool Group::isLFRGroup() const
{
return (m_groupType & GROUPTYPE_LFG) && (m_groupType & GROUPTYPE_RAID);
}
bool Group::isRaidGroup() const
{
return (m_groupType & GROUPTYPE_RAID) != 0;
+3
View File
@@ -206,6 +206,7 @@ class TC_GAME_API Group
void SetLootThreshold(ItemQualities threshold);
void Disband(bool hideDestroy = false);
void SetLfgRoles(ObjectGuid guid, uint8 roles);
uint8 GetLfgRoles(ObjectGuid guid);
void SetGroupMarkerMask(uint32 mask) { m_markerMask = mask; }
void AddGroupMarkerMask(uint32 mask) { m_markerMask |= mask; }
@@ -222,6 +223,7 @@ class TC_GAME_API Group
// properties accessories
bool IsFull() const;
bool isLFGGroup() const;
bool isLFRGroup() const;
bool isRaidGroup() const;
bool isBGGroup() const;
bool isBFGroup() const;
@@ -265,6 +267,7 @@ class TC_GAME_API Group
uint8 GetMemberGroup(ObjectGuid guid) const;
void ConvertToLFG();
void ConvertToLFR();
void ConvertToRaid();
void ConvertToGroup();
+1 -1
View File
@@ -794,7 +794,7 @@ void WorldSession::HandleGroupRaidConvertOpcode(WorldPacket& recvData)
if (!group)
return;
if (_player->InBattleground())
if (_player->InBattleground() || group->isLFGGroup())
return;
// error handling
+88 -21
View File
@@ -132,6 +132,8 @@ void WorldSession::HandleLfgJoinOpcode(WorldPacket& recvData)
TC_LOG_DEBUG("lfg", "CMSG_LFG_JOIN %s roles: %u, Dungeons: %u, Comment: %s",
GetPlayerInfo().c_str(), roles, uint8(newDungeons.size()), comment.c_str());
GetPlayer()->SetTempCallToArmsRoles(sLFGMgr->GetRolesForCallToArms());
sLFGMgr->JoinLfg(GetPlayer(), uint8(roles), newDungeons, comment);
}
@@ -170,7 +172,10 @@ void WorldSession::HandleLfgLeaveOpcode(WorldPacket& recvData)
// Check cheating - only leader can leave the queue
if (!group || group->GetLeaderGUID() == guid)
{
GetPlayer()->SetTempCallToArmsRoles(0);
sLFGMgr->LeaveLfg(gguid);
}
}
void WorldSession::HandleLfgProposalResultOpcode(WorldPacket& recvData)
@@ -309,8 +314,9 @@ void WorldSession::SendLfgPlayerLockInfo()
data << uint8(randomDungeons.size()); // Random Dungeon count
for (lfg::LfgDungeonSet::const_iterator it = randomDungeons.begin(); it != randomDungeons.end(); ++it)
{
data << uint32(*it); // Dungeon Entry (id + type)
lfg::LfgReward const* reward = sLFGMgr->GetRandomDungeonReward(*it, level);
uint32 dungeonId = *it;
data << uint32(dungeonId); // Dungeon Entry (id + type)
lfg::LfgReward const* reward = sLFGMgr->GetRandomDungeonReward(dungeonId, level);
Quest const* quest = NULL;
bool done = false;
if (reward)
@@ -325,26 +331,87 @@ void WorldSession::SendLfgPlayerLockInfo()
}
data << uint8(done);
data << uint32(0); // currencyQuantity
data << uint32(0); // some sort of overall cap/weekly cap
data << uint32(0); // currencyID
data << uint32(0); // tier1Quantity
data << uint32(0); // tier1Limit
data << uint32(0); // overallQuantity
data << uint32(0); // overallLimit
data << uint32(0); // periodPurseQuantity
data << uint32(0); // periodPurseLimit
data << uint32(0); // purseQuantity
data << uint32(0); // purseLimit
data << uint32(0); // some sort of reward for completion
data << uint32(0); // completedEncounters
data << uint8(0); // Call to Arms eligible
for (uint32 i = 0; i < 3; ++i)
CurrencyTypesEntry const* currency = sCurrencyTypesStore.LookupEntry(CURRENCY_TYPE_VALOR_POINTS);
int8 valorPointsField = -1;
for (uint8 i = 0; i < QUEST_REWARD_CURRENCY_COUNT; i++)
if (quest && quest->RewardCurrencyId[i] == CURRENCY_TYPE_VALOR_POINTS)
valorPointsField = i;
if (currency && quest)
{
data << uint32(0); // Call to Arms Role
//if (role)
// BuildQuestReward(data, ctaRoleQuest, GetPlayer());
data << uint32(valorPointsField >= 0 ? quest->RewardCurrencyCount[valorPointsField] : 0); // currencyQuantity
data << uint32(GetPlayer()->GetCurrencyWeekCap(currency)); // some sort of overall cap/weekly cap
data << uint32(quest->RewardCurrencyId[0]); // currencyID
data << uint32(GetPlayer()->GetCurrencyOnWeek(CURRENCY_TYPE_VALOR_POINTS, false)); // tier1Quantity
data << uint32(GetPlayer()->GetCurrencyWeekCap(currency)); // tier1Limit
data << uint32(0); // overallQuantity
data << uint32(GetPlayer()->GetCurrencyWeekCap(currency)); // overallLimit
data << uint32(GetPlayer()->GetCurrencyOnWeek(CURRENCY_TYPE_VALOR_POINTS, false)); // periodPurseQuantity
data << uint32(GetPlayer()->GetCurrencyWeekCap(currency)); // periodPurseLimit
data << uint32(GetPlayer()->GetCurrencyTotalCap(currency)); // purseQuantity
data << uint32(0); // purseLimit
data << uint32(valorPointsField >= 0 ? quest->RewardCurrencyCount[valorPointsField] : 0); // some sort of reward for completion
}
else
{
data << uint32(0); // currencyQuantity
data << uint32(0); // some sort of overall cap/weekly cap
data << uint32(0); // currencyID
data << uint32(0); // tier1Quantity
data << uint32(0); // tier1Limit
data << uint32(0); // overallQuantity
data << uint32(0); // overallLimit
data << uint32(0); // periodPurseQuantity
data << uint32(0); // periodPurseLimit
data << uint32(0); // purseQuantity
data << uint32(0); // purseLimit
data << uint32(0); // some sort of reward for completion
}
data << uint32(0); // completedEncounters
bool isCallToArmEligible = sLFGMgr->IsCallToArmEligible(level, dungeonId & 0x00FFFFFF);
data << uint8(isCallToArmEligible); // Call to Arms eligible
if (isCallToArmEligible)
{
uint8 roleTank = sLFGMgr->GetRolesForCallToArms() & lfg::PLAYER_ROLE_TANK ? lfg::PLAYER_ROLE_TANK : 0;
uint8 roleHeal = sLFGMgr->GetRolesForCallToArms() & lfg::PLAYER_ROLE_HEALER ? lfg::PLAYER_ROLE_HEALER : 0;
uint8 roleDPS = sLFGMgr->GetRolesForCallToArms() & lfg::PLAYER_ROLE_DAMAGE ? lfg::PLAYER_ROLE_DAMAGE : 0;
Quest const* ctaQuest = sObjectMgr->GetQuestTemplate(LFG_CALL_TO_ARMS_QUEST);
if (roleTank)
{
data << uint32(roleTank);
BuildQuestReward(data, ctaQuest, GetPlayer());
}
else
data << uint32(0);
if (roleHeal)
{
data << uint32(roleHeal);
BuildQuestReward(data, ctaQuest, GetPlayer());
}
else
data << uint32(0);
if (roleDPS)
{
data << uint32(roleDPS);
BuildQuestReward(data, ctaQuest, GetPlayer());
}
else
data << uint32(0);
}
else
{
for (uint32 i = 0; i < 3; ++i)
{
data << uint32(0); // Call to Arms Role
//if (role)
// BuildQuestReward(data, ctaRoleQuest, GetPlayer());
}
}
if (quest)
@@ -473,7 +540,7 @@ void WorldSession::SendLfgUpdateStatus(lfg::LfgUpdateData const& updateData, boo
data.WriteBit(party);
data.WriteBits(size, 24);
data.WriteBit(guid[6]);
data.WriteBit(size > 0); // Extra info
data.WriteBit(queued); // Extra info
data.WriteBits(updateData.comment.length(), 9);
data.WriteBit(guid[4]);
data.WriteBit(guid[7]);
+5 -1
View File
@@ -663,7 +663,11 @@ void InstanceScript::UpdateEncounterState(EncounterCreditType type, uint32 credi
completedEncounters |= 1 << encounter->dbcEntry->encounterIndex;
if (encounter->lastEncounterDungeon)
{
dungeonId = encounter->lastEncounterDungeon;
if (instance->GetDifficulty() != sLFGDungeonStore.LookupEntry(encounter->lastEncounterDungeon)->difficulty)
dungeonId = sLFGMgr->GetDungeonIdForDifficulty(encounter->lastEncounterDungeon, instance->GetDifficulty());
else
dungeonId = encounter->lastEncounterDungeon;
TC_LOG_DEBUG("lfg", "UpdateEncounterState: Instance %s (instanceId %u) completed encounter %s. Credit Dungeon: %u", instance->GetMapName(), instance->GetInstanceId(), encounter->dbcEntry->encounterName, dungeonId);
break;
}
+1
View File
@@ -1327,6 +1327,7 @@ void World::LoadConfigSettings(bool reload)
// Dungeon finder
m_int_configs[CONFIG_LFG_OPTIONSMASK] = sConfigMgr->GetIntDefault("DungeonFinder.OptionsMask", 1);
m_bool_configs[CONFIG_LFG_CALL_TO_ARMS_ENABLED] = sConfigMgr->GetBoolDefault("DungeonFinder.CallToArmsEnable", false);
// DBC_ItemAttributes
m_bool_configs[CONFIG_DBC_ENFORCE_ITEM_ATTRIBUTES] = sConfigMgr->GetBoolDefault("DBC.EnforceItemAttributes", true);
+1
View File
@@ -188,6 +188,7 @@ enum WorldBoolConfigs
CONFIG_HOTSWAP_PREFIX_CORRECTION_ENABLED,
CONFIG_CHECK_GOBJECT_LOS,
CONFIG_RESPAWN_DYNAMIC_ESCORTNPC,
CONFIG_LFG_CALL_TO_ARMS_ENABLED,
BOOL_CONFIG_VALUE_COUNT
};
@@ -1213,6 +1213,14 @@ DeletedCharacterTicketTrace = 0
DungeonFinder.OptionsMask = 1
#
# DungeonFinder.CallToArmsEnable
# Description: Enable Call to Arms bonus mechanism for random Cataclysm dungeons
# Default: 0 - (Disabled)
# 1 - (Enabled)
DungeonFinder.CallToArmsEnable = 0
#
# DBC.EnforceItemAttributes
# Description: Disallow overriding item attributes stored in DBC files with values from the