diff options
-rw-r--r-- | src/game/CMakeLists.txt | 3 | ||||
-rw-r--r-- | src/game/Channel.cpp | 3 | ||||
-rw-r--r-- | src/game/CharacterHandler.cpp | 2 | ||||
-rw-r--r-- | src/game/DBCStores.cpp | 3 | ||||
-rw-r--r-- | src/game/DBCStores.h | 1 | ||||
-rw-r--r-- | src/game/DBCStructure.h | 23 | ||||
-rw-r--r-- | src/game/DBCfmt.h | 1 | ||||
-rw-r--r-- | src/game/Group.cpp | 6 | ||||
-rw-r--r-- | src/game/GroupHandler.cpp | 11 | ||||
-rw-r--r-- | src/game/LFG.h | 72 | ||||
-rw-r--r-- | src/game/LFGHandler.cpp | 468 | ||||
-rw-r--r-- | src/game/LFGMgr.cpp | 440 | ||||
-rw-r--r-- | src/game/LFGMgr.h | 162 | ||||
-rw-r--r-- | src/game/Opcodes.cpp | 28 | ||||
-rw-r--r-- | src/game/Player.h | 69 | ||||
-rw-r--r-- | src/game/World.cpp | 5 | ||||
-rw-r--r-- | src/game/WorldSession.h | 19 | ||||
-rw-r--r-- | win/VC90/game.vcproj | 12 |
18 files changed, 851 insertions, 477 deletions
diff --git a/src/game/CMakeLists.txt b/src/game/CMakeLists.txt index ab5ef6c2f56..3197185240d 100644 --- a/src/game/CMakeLists.txt +++ b/src/game/CMakeLists.txt @@ -146,7 +146,10 @@ SET(game_STAT_SRCS Level1.cpp Level2.cpp Level3.cpp + LFG.h LFGHandler.cpp + LFGMgr.cpp + LFGMgr.h LootHandler.cpp LootMgr.cpp LootMgr.h diff --git a/src/game/Channel.cpp b/src/game/Channel.cpp index 68de32fd690..0047892972b 100644 --- a/src/game/Channel.cpp +++ b/src/game/Channel.cpp @@ -161,8 +161,7 @@ void Channel::Join(uint64 p, const char *pass) if (plr) { if (HasFlag(CHANNEL_FLAG_LFG) && - sWorld.getConfig(CONFIG_RESTRICTED_LFG_CHANNEL) && plr->GetSession()->GetSecurity() == SEC_PLAYER && - (plr->GetGroup() || plr->m_lookingForGroup.Empty())) + sWorld.getConfig(CONFIG_RESTRICTED_LFG_CHANNEL) && plr->GetSession()->GetSecurity() == SEC_PLAYER && plr->GetGroup()) { MakeNotInLfg(&data); SendToOne(&data, p); diff --git a/src/game/CharacterHandler.cpp b/src/game/CharacterHandler.cpp index 066585175c4..d7f5d11cdfe 100644 --- a/src/game/CharacterHandler.cpp +++ b/src/game/CharacterHandler.cpp @@ -851,7 +851,7 @@ void WorldSession::HandleMeetingStoneInfo(WorldPacket & /*recv_data*/) { DEBUG_LOG("WORLD: Received CMSG_MEETING_STONE_INFO"); - SendLfgUpdate(0, 0, 0); + //SendLfgUpdate(0, 0, 0); } void WorldSession::HandleTutorialFlag(WorldPacket & recv_data) diff --git a/src/game/DBCStores.cpp b/src/game/DBCStores.cpp index aeeb3f50e68..31848b26788 100644 --- a/src/game/DBCStores.cpp +++ b/src/game/DBCStores.cpp @@ -96,6 +96,8 @@ DBCStorage <ItemRandomPropertiesEntry> sItemRandomPropertiesStore(ItemRandomProp DBCStorage <ItemRandomSuffixEntry> sItemRandomSuffixStore(ItemRandomSuffixfmt); DBCStorage <ItemSetEntry> sItemSetStore(ItemSetEntryfmt); +DBCStorage <LFGDungeonEntry> sLFGDungeonStore(LFGDungeonEntryfmt); + DBCStorage <LockEntry> sLockStore(LockEntryfmt); DBCStorage <MailTemplateEntry> sMailTemplateStore(MailTemplateEntryfmt); @@ -319,6 +321,7 @@ void LoadDBCStores(const std::string& dataPath) LoadDBC(availableDbcLocales,bar,bad_dbc_files,sItemRandomPropertiesStore,dbcPath,"ItemRandomProperties.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sItemRandomSuffixStore, dbcPath,"ItemRandomSuffix.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sItemSetStore, dbcPath,"ItemSet.dbc"); + LoadDBC(availableDbcLocales,bar,bad_dbc_files,sLFGDungeonStore, dbcPath,"LFGDungeons.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sLockStore, dbcPath,"Lock.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sMailTemplateStore, dbcPath,"MailTemplate.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sMapStore, dbcPath,"Map.dbc"); diff --git a/src/game/DBCStores.h b/src/game/DBCStores.h index e1d0c3e7721..acf5ac8ec41 100644 --- a/src/game/DBCStores.h +++ b/src/game/DBCStores.h @@ -113,6 +113,7 @@ extern DBCStorage <ItemLimitCategoryEntry> sItemLimitCategoryStore; extern DBCStorage <ItemRandomPropertiesEntry> sItemRandomPropertiesStore; extern DBCStorage <ItemRandomSuffixEntry> sItemRandomSuffixStore; extern DBCStorage <ItemSetEntry> sItemSetStore; +extern DBCStorage <LFGDungeonEntry> sLFGDungeonStore; extern DBCStorage <LockEntry> sLockStore; extern DBCStorage <MailTemplateEntry> sMailTemplateStore; extern DBCStorage <MapEntry> sMapStore; diff --git a/src/game/DBCStructure.h b/src/game/DBCStructure.h index 77393f2c4b4..f86eecc7644 100644 --- a/src/game/DBCStructure.h +++ b/src/game/DBCStructure.h @@ -1092,6 +1092,29 @@ struct ItemSetEntry uint32 required_skill_value; // 52 m_requiredSkillRank }; +struct LFGDungeonEntry +{ + uint32 ID; // 0 + //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 + uint32 type; // 26 + //uint32 unk2; // 27 + //char* unk3; // 28 + uint32 expansion; // 29 + //uint32 unk4; // 30 + uint32 grouptype; // 31 + //char* desc[16]; // 32-47 Description + // Helpers + uint32 Entry() const { return ID + (type << 24); } +}; + #define MAX_LOCK_CASE 8 struct LockEntry diff --git a/src/game/DBCfmt.h b/src/game/DBCfmt.h index e192f3594b5..a5c1bc92d65 100644 --- a/src/game/DBCfmt.h +++ b/src/game/DBCfmt.h @@ -73,6 +73,7 @@ const char ItemLimitCategoryEntryfmt[]="nxxxxxxxxxxxxxxxxxix"; const char ItemRandomPropertiesfmt[]="nxiiiiissssssssssssssssx"; const char ItemRandomSuffixfmt[]="nssssssssssssssssxxiiiiiiiiii"; const char ItemSetEntryfmt[]="dssssssssssssssssxxxxxxxxxxxxxxxxxxiiiiiiiiiiiiiiiiii"; +const char LFGDungeonEntryfmt[]="nxxxxxxxxxxxxxxxxxiiiiiiixixxixixxxxxxxxxxxxxxxxx"; const char LockEntryfmt[]="niiiiiiiiiiiiiiiiiiiiiiiixxxxxxxx"; const char MailTemplateEntryfmt[]="nxxxxxxxxxxxxxxxxxssssssssssssssssx"; const char MapEntryfmt[]="nxixxssssssssssssssssxixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxixiffxiix"; diff --git a/src/game/Group.cpp b/src/game/Group.cpp index 91d6a263c85..ceec11fa94a 100644 --- a/src/game/Group.cpp +++ b/src/game/Group.cpp @@ -33,6 +33,7 @@ #include "InstanceSaveMgr.h" #include "MapInstanced.h" #include "Util.h" +#include "LFG.h" Group::Group() { @@ -384,7 +385,7 @@ uint32 Group::RemoveMember(const uint64 &guid, const uint8 &method) } // if group before remove <= 2 disband it else - Disband(true); + Disband(); return m_memberSlots.size(); } @@ -425,6 +426,8 @@ void Group::Disband(bool hideDestroy) player->SetOriginalGroup(NULL); else player->SetGroup(NULL); + player->GetSession()->SendLfgUpdateParty(LFG_UPDATETYPE_GROUP_DISBAND); + player->GetSession()->SendLfgUpdateParty(LFG_UPDATETYPE_LEADER); } // quest related GO state dependent from raid membership @@ -1260,6 +1263,7 @@ bool Group::_removeMember(const uint64 &guid) player->SetOriginalGroup(NULL); else player->SetGroup(NULL); + player->GetSession()->SendLfgUpdateParty(LFG_UPDATETYPE_LEADER); } } diff --git a/src/game/GroupHandler.cpp b/src/game/GroupHandler.cpp index cd58b30042c..f973bc24722 100644 --- a/src/game/GroupHandler.cpp +++ b/src/game/GroupHandler.cpp @@ -32,6 +32,7 @@ #include "Util.h" #include "SpellAuras.h" #include "Vehicle.h" +#include "LFG.h" class Aura; @@ -176,6 +177,8 @@ void WorldSession::HandleGroupInviteOpcode(WorldPacket & recv_data) data << uint32(0); // unk player->GetSession()->SendPacket(&data); + SendLfgUpdatePlayer(LFG_UPDATETYPE_REMOVED_FROM_QUEUE); + SendLfgUpdateParty(LFG_UPDATETYPE_REMOVED_FROM_QUEUE); SendPartyResult(PARTY_OP_INVITE, membername, ERR_PARTY_RESULT_OK); } @@ -218,6 +221,14 @@ void WorldSession::HandleGroupAcceptOpcode(WorldPacket & /*recv_data*/) if (!group->AddMember(GetPlayer()->GetGUID(), GetPlayer()->GetName())) return; + SendLfgUpdatePlayer(LFG_UPDATETYPE_REMOVED_FROM_QUEUE); + for (GroupReference *itr = group->GetFirstMember(); itr != NULL; itr = itr->next()) + if (Player *plrg = itr->getSource()) + { + plrg->GetSession()->SendLfgUpdatePlayer(LFG_UPDATETYPE_CLEAR_LOCK_LIST); + plrg->GetSession()->SendLfgUpdateParty(LFG_UPDATETYPE_CLEAR_LOCK_LIST); + } + group->BroadcastGroupUpdate(); } diff --git a/src/game/LFG.h b/src/game/LFG.h new file mode 100644 index 00000000000..d30d694f43e --- /dev/null +++ b/src/game/LFG.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _LFG_H +#define _LFG_H + +#include "Platform/Define.h" +#include "Object.h" + +enum LfgRoles +{ + NONE = 0x00, + LEADER = 0x01, + TANK = 0x02, + HEALER = 0x04, + DAMAGE = 0x08, +}; + +enum LfgUpdateType +{ + LFG_UPDATETYPE_LEADER = 1, + LFG_UPDATETYPE_ROLECHECK_ABORTED = 4, + LFG_UPDATETYPE_JOIN_PROPOSAL = 5, + LFG_UPDATETYPE_ROLECHECK_FAILED = 6, + LFG_UPDATETYPE_REMOVED_FROM_QUEUE = 7, + LFG_UPDATETYPE_PROPOSAL_FAILED = 8, + LFG_UPDATETYPE_PROPOSAL_DECLINED = 9, + LFG_UPDATETYPE_GROUP_FOUND = 10, + LFG_UPDATETYPE_ADDED_TO_QUEUE = 12, + LFG_UPDATETYPE_PROPOSAL_FOUND = 13, + LFG_UPDATETYPE_CLEAR_LOCK_LIST = 14, + LFG_UPDATETYPE_GROUP_MEMBER_OFFLINE = 15, + LFG_UPDATETYPE_GROUP_DISBAND = 16, +}; + +typedef std::set<uint32> LfgDungeonSet; + +struct LookingForGroup +{ + LookingForGroup(): roles(0) + { + donerandomDungeons.clear(); + applyDungeons.clear(); + } + std::string comment; + int8 roles; + + bool isDungeonDone(const uint32 entry) + { + return donerandomDungeons.find(entry) != donerandomDungeons.end(); + } + + LfgDungeonSet applyDungeons; // Dungeons the player have applied for + LfgDungeonSet donerandomDungeons; // Finished random Dungeons (to calculate the bonus); +}; + +#endif diff --git a/src/game/LFGHandler.cpp b/src/game/LFGHandler.cpp index a98ec48e864..da9e32338cd 100644 --- a/src/game/LFGHandler.cpp +++ b/src/game/LFGHandler.cpp @@ -1,5 +1,4 @@ /* - * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> * * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/> * @@ -18,417 +17,128 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include "LFGMgr.h" #include "WorldSession.h" -#include "Log.h" -#include "Database/DatabaseEnv.h" -#include "Player.h" #include "WorldPacket.h" -#include "ObjectMgr.h" -#include "World.h" - -static void AttemptJoin(Player* _player) -{ - // skip not can autojoin cases and player group case - if (!_player->m_lookingForGroup.canAutoJoin() || _player->GetGroup()) - return; - - ObjectAccessor::Guard guard(*HashMapHolder<Player>::GetLock()); - HashMapHolder<Player>::MapType const& players = ObjectAccessor::Instance().GetPlayers(); - for (HashMapHolder<Player>::MapType::const_iterator iter = players.begin(); iter != players.end(); ++iter) - { - Player *plr = iter->second; - - // skip enemies and self - if (!plr || plr == _player || plr->GetTeam() != _player->GetTeam()) - continue; - - //skip players not in world - if (!plr->IsInWorld()) - continue; - - // skip not auto add, not group leader cases - if (!plr->GetSession()->LookingForGroup_auto_add || plr->GetGroup() && plr->GetGroup()->GetLeaderGUID() != plr->GetGUID()) - continue; - - // skip non auto-join or empty slots, or non compatible slots - if (!plr->m_lookingForGroup.more.canAutoJoin() || !_player->m_lookingForGroup.HaveInSlot(plr->m_lookingForGroup.more)) - continue; - - // attempt create group, or skip - if (!plr->GetGroup()) - { - Group* group = new Group; - if (!group->Create(plr->GetGUID(), plr->GetName())) - { - delete group; - continue; - } - - objmgr.AddGroup(group); - } - - // stop at success join - if (plr->GetGroup()->AddMember(_player->GetGUID(), _player->GetName())) - { - if (sWorld.getConfig(CONFIG_RESTRICTED_LFG_CHANNEL) && _player->GetSession()->GetSecurity() == SEC_PLAYER) - _player->LeaveLFGChannel(); - break; - } - // full - else - { - if (sWorld.getConfig(CONFIG_RESTRICTED_LFG_CHANNEL) && plr->GetSession()->GetSecurity() == SEC_PLAYER) - plr->LeaveLFGChannel(); - } - } -} - -static void AttemptAddMore(Player* _player) -{ - // skip not group leader case - if (_player->GetGroup() && _player->GetGroup()->GetLeaderGUID() != _player->GetGUID()) - return; - - if (!_player->m_lookingForGroup.more.canAutoJoin()) - return; - - ObjectAccessor::Guard guard(*HashMapHolder<Player>::GetLock()); - HashMapHolder<Player>::MapType const& players = ObjectAccessor::Instance().GetPlayers(); - for (HashMapHolder<Player>::MapType::const_iterator iter = players.begin(); iter != players.end(); ++iter) - { - Player *plr = iter->second; - - // skip enemies and self - if (!plr || plr == _player || plr->GetTeam() != _player->GetTeam()) - continue; - - if (!plr->IsInWorld()) - continue; - - // skip not auto join or in group - if (!plr->GetSession()->LookingForGroup_auto_join || plr->GetGroup()) - continue; - - if (!plr->m_lookingForGroup.HaveInSlot(_player->m_lookingForGroup.more)) - continue; - - // attempt create group if need, or stop attempts - if (!_player->GetGroup()) - { - Group* group = new Group; - if (!group->Create(_player->GetGUID(), _player->GetName())) - { - delete group; - return; // can't create group (??) - } - - objmgr.AddGroup(group); - } - - // stop at join fail (full) - if (!_player->GetGroup()->AddMember(plr->GetGUID(), plr->GetName())) - { - if (sWorld.getConfig(CONFIG_RESTRICTED_LFG_CHANNEL) && _player->GetSession()->GetSecurity() == SEC_PLAYER) - _player->LeaveLFGChannel(); - - break; - } - - // joined - if (sWorld.getConfig(CONFIG_RESTRICTED_LFG_CHANNEL) && plr->GetSession()->GetSecurity() == SEC_PLAYER) - plr->LeaveLFGChannel(); - - // and group full - if (_player->GetGroup()->IsFull()) - { - if (sWorld.getConfig(CONFIG_RESTRICTED_LFG_CHANNEL) && _player->GetSession()->GetSecurity() == SEC_PLAYER) - _player->LeaveLFGChannel(); - - break; - } - } -} - -void WorldSession::HandleLfgSetAutoJoinOpcode(WorldPacket & /*recv_data*/) -{ - sLog.outDebug("CMSG_LFG_SET_AUTOJOIN"); - LookingForGroup_auto_join = true; - - if (!_player) // needed because STATUS_AUTHED - return; - - AttemptJoin(_player); -} - -void WorldSession::HandleLfgClearAutoJoinOpcode(WorldPacket & /*recv_data*/) -{ - sLog.outDebug("CMSG_LFG_CLEAR_AUTOJOIN"); - LookingForGroup_auto_join = false; -} - -void WorldSession::HandleLfmSetAutoFillOpcode(WorldPacket & /*recv_data*/) -{ - sLog.outDebug("CMSG_LFM_SET_AUTOFILL"); - LookingForGroup_auto_add = true; - - if (!_player) // needed because STATUS_AUTHED - return; - - AttemptAddMore(_player); -} - -void WorldSession::HandleLfmClearAutoFillOpcode(WorldPacket & /*recv_data*/) -{ - sLog.outDebug("CMSG_LFM_CLEAR_AUTOFILL"); - LookingForGroup_auto_add = false; -} - -void WorldSession::HandleLfgClearOpcode(WorldPacket & /*recv_data */) -{ - // empty packet - sLog.outDebug("CMSG_CLEAR_LOOKING_FOR_GROUP"); - - for (int i = 0; i < MAX_LOOKING_FOR_GROUP_SLOT; ++i) - _player->m_lookingForGroup.slots[i].Clear(); - - if (sWorld.getConfig(CONFIG_RESTRICTED_LFG_CHANNEL) && _player->GetSession()->GetSecurity() == SEC_PLAYER) - _player->LeaveLFGChannel(); - - SendLfgUpdate(0, 0, 0); -} - -void WorldSession::HandleLfmClearOpcode(WorldPacket & /*recv_data */) -{ - // empty packet - sLog.outDebug("CMSG_CLEAR_LOOKING_FOR_MORE"); - - _player->m_lookingForGroup.more.Clear(); -} - -void WorldSession::HandleSetLfmOpcode(WorldPacket & recv_data) -{ - sLog.outDebug("CMSG_SET_LOOKING_FOR_MORE"); - //recv_data.hexlike(); - uint32 temp, entry, type; - uint8 unk1; - uint8 unk2[3]; - - recv_data >> temp >> unk1 >> unk2[0] >> unk2[1] >> unk2[2]; - - entry = (temp & 0x00FFFFFF); - type = ((temp >> 24) & 0x000000FF); - - _player->m_lookingForGroup.more.Set(entry,type); - sLog.outDebug("LFM set: temp %u, zone %u, type %u", temp, entry, type); - - if (LookingForGroup_auto_add) - AttemptAddMore(_player); - - SendLfgResult(type, entry, 1); -} void WorldSession::HandleSetLfgCommentOpcode(WorldPacket & recv_data) { sLog.outDebug("CMSG_SET_LFG_COMMENT"); - //recv_data.hexlike(); std::string comment; recv_data >> comment; - sLog.outDebug("LFG comment %s", comment.c_str()); - _player->m_lookingForGroup.comment = comment; + GetPlayer()->m_lookingForGroup.comment = comment; } -void WorldSession::HandleLookingForGroup(WorldPacket& recv_data) +void WorldSession::HandleLfgPlayerLockInfoRequestOpcode(WorldPacket &/*recv_data*/) { - sLog.outDebug("MSG_LOOKING_FOR_GROUP"); - //recv_data.hexlike(); - uint32 type, entry, unk; - - recv_data >> type >> entry >> unk; - sLog.outDebug("MSG_LOOKING_FOR_GROUP: type %u, entry %u, unk %u", type, entry, unk); - - if (LookingForGroup_auto_add) - AttemptAddMore(_player); - - if (LookingForGroup_auto_join) - AttemptJoin(_player); - - SendLfgResult(type, entry, 0); - SendLfgUpdate(0, 1, 0); + sLog.outDebug("CMSG_LFD_PLAYER_LOCK_INFO_REQUEST"); + sLFGMgr.SendLfgPlayerInfo(GetPlayer()); } -void WorldSession::SendLfgResult(uint32 /*type*/, uint32 /*entry*/, uint8 /*lfg_type*/) -{/* - uint32 number = 0; +void WorldSession::HandleLfgPartyLockInfoRequestOpcode(WorldPacket &/*recv_data*/) +{ + sLog.outDebug("CMSG_LFD_PARTY_LOCK_INFO_REQUEST"); + sLFGMgr.SendLfgPartyInfo(GetPlayer()); +} - WorldPacket data(MSG_LOOKING_FOR_GROUP); - data << uint32(type); // type - data << uint32(entry); // entry from LFGDungeons.dbc +void WorldSession::SendLfgUpdatePlayer(uint8 updateType, uint32 dungeonEntry /* = 0*/) +{ + bool queued = false; + bool extrainfo = false; - data << uint8(0); - if (uint8) + switch(updateType) { - uint32 count1; - for (count1) - { - uint64; // player guid - } + case LFG_UPDATETYPE_JOIN_PROPOSAL: + case LFG_UPDATETYPE_ADDED_TO_QUEUE: + queued = true; + extrainfo = true; + break; + //case LFG_UPDATETYPE_CLEAR_LOCK_LIST: // TODO: Sometimes has extrainfo - Check ocurrences... + case LFG_UPDATETYPE_PROPOSAL_FOUND: + extrainfo = true; + break; } - - data << uint32(0); // count2 - data << uint32(0); - for (count2) + sLog.outDebug("SMSG_LFG_UPDATE_PLAYER"); + WorldPacket data(SMSG_LFG_UPDATE_PLAYER, 1 + 1 + (extrainfo ? 1 : 0) * (1 + 1 + 1 + 1 + !dungeonEntry ? 4 : GetPlayer()->m_lookingForGroup.applyDungeons.size() * 4 + GetPlayer()->m_lookingForGroup.comment.length())); + data << uint8(updateType); // Lfg Update type + data << uint8(extrainfo); // Extra info + if (extrainfo) { - uint64 // not player guid - uint32 flags; - if (flags & 0x2) - { - string - } - if (flags & 0x10) + data << uint8(queued); // Join the queue + data << uint8(0); // unk - Always 0 + data << uint8(0); // unk - Always 0 + + if (dungeonEntry) { - uint8 + data << uint8(1); + data << uint32(dungeonEntry); } - if (flags & 0x20) + else { - for (3) - { - uint8 - } + uint8 size = GetPlayer()->m_lookingForGroup.applyDungeons.size(); + data << uint8(size); + + for (LfgDungeonSet::const_iterator it = GetPlayer()->m_lookingForGroup.applyDungeons.begin(); it != GetPlayer()->m_lookingForGroup.applyDungeons.end(); ++it) + data << uint32(*it); } + data << GetPlayer()->m_lookingForGroup.comment; } + SendPacket(&data); +} - size_t count3_pos = data.wpos(); - data << uint32(0); // count3 - data << uint32(0); // unk +void WorldSession::SendLfgUpdateParty(uint8 updateType, uint32 dungeonEntry /* = 0*/) +{ + bool join = false; + bool extrainfo = false; + bool queued = false; - //TODO: Guard Player map - HashMapHolder<Player>::MapType const& players = ObjectAccessor::Instance().GetPlayers(); - for (HashMapHolder<Player>::MapType::const_iterator iter = players.begin(); iter != players.end(); ++iter) + switch(updateType) { - Player *plr = iter->second; - - if (!plr || plr->GetTeam() != _player->GetTeam()) - continue; - - if (!plr->IsInWorld()) - continue; - - if (!plr->m_lookingForGroup.HaveInSlot(entry, type)) - continue; - - ++number; - - data << uint64(plr->GetGUID()); // guid + case LFG_UPDATETYPE_JOIN_PROPOSAL: + extrainfo = true; + break; + case LFG_UPDATETYPE_ADDED_TO_QUEUE: + extrainfo = true; + join = true; + queued = true; + break; + case LFG_UPDATETYPE_CLEAR_LOCK_LIST: + // join = true; // TODO: Sometimes queued and extrainfo - Check ocurrences... + queued = true; + break; + case LFG_UPDATETYPE_PROPOSAL_FOUND: + extrainfo = true; + join = true; + break; + } - uint32 flags = 0x1FF; - data << uint32(flags); // flags + sLog.outDebug("SMSG_LFG_UPDATE_PARTY"); + WorldPacket data(SMSG_LFG_UPDATE_PARTY, 1 + 1 + (extrainfo ? 1 : 0) * (1 + 1 + 1 + 1 + 1 + !dungeonEntry ? 4 : GetPlayer()->m_lookingForGroup.applyDungeons.size() * 4 + GetPlayer()->m_lookingForGroup.comment.length())); + data << uint8(updateType); // Lfg Update type + data << uint8(extrainfo); // Extra info + if (extrainfo) + { + data << uint8(join); // LFG Join + data << uint8(queued); // Join the queue + data << uint8(0); // unk - Always 0 + data << uint8(0); // unk - Always 0 - if (flags & 0x1) + if (dungeonEntry) { - data << uint8(plr->getLevel()); - data << uint8(plr->getClass()); - data << uint8(plr->getRace()); - - for (int i = 0; i < 3; ++i) - data << uint8(0); // spent talents count in specific tab - - data << uint32(0); // resistances1 - data << uint32(0); // spd/heal - data << uint32(0); // spd/heal - data << uint32(0); // combat_rating9 - data << uint32(0); // combat_rating10 - data << uint32(0); // combat_rating11 - data << float(0); // mp5 - data << float(0); // unk - data << uint32(0); // attack power - data << uint32(0); // stat1 - data << uint32(0); // maxhealth - data << uint32(0); // maxpower1 - data << uint32(0); // unk - data << float(0); // unk - data << uint32(0); // unk - data << uint32(0); // unk - data << uint32(0); // unk - data << uint32(0); // unk - data << uint32(0); // combat_rating20 - data << uint32(0); // unk + data << uint8(1); + data << uint32(dungeonEntry); } - - if (flags & 0x2) - data << plr->m_lookingForGroup.comment; // comment - - if (flags & 0x4) - data << uint8(0); // unk - - if (flags & 0x8) - data << uint64(0); // guid from count2 block, not player guid - - if (flags & 0x10) - data << uint8(0); // unk - - if (flags & 0x20) - data << uint8(plr->m_lookingForGroup.roles); // roles - - if (flags & 0x40) - data << uint32(plr->GetZoneId()); // areaid - - if (flags & 0x100) - data << uint8(0); // LFG/LFM flag? - - if (flags & 0x80) + else { - for (uint8 j = 0; j < MAX_LOOKING_FOR_GROUP_SLOT; ++j) - { - data << uint32(plr->m_lookingForGroup.slots[j].entry | (plr->m_lookingForGroup.slots[j].type << 24)); - } + uint8 size = GetPlayer()->m_lookingForGroup.applyDungeons.size(); + data << uint8(size); + + for (LfgDungeonSet::const_iterator it = GetPlayer()->m_lookingForGroup.applyDungeons.begin(); it != GetPlayer()->m_lookingForGroup.applyDungeons.end(); ++it) + data << uint32(*it); } + data << GetPlayer()->m_lookingForGroup.comment; } - - data.put<uint32>(count3_pos, number); // fill count placeholder - SendPacket(&data); -*/ -} - -void WorldSession::HandleSetLfgOpcode(WorldPacket & recv_data) -{ - sLog.outDebug("CMSG_SET_LOOKING_FOR_GROUP"); - recv_data.hexlike(); - uint32 slot, temp, entry, type; - uint8 roles, unk1; - - recv_data >> slot >> temp >> roles >> unk1; - - entry = (temp & 0x00FFFFFF); - type = ((temp >> 24) & 0x000000FF); - - if (slot >= MAX_LOOKING_FOR_GROUP_SLOT) - return; - - _player->m_lookingForGroup.slots[slot].Set(entry, type); - _player->m_lookingForGroup.roles = roles; - sLog.outDebug("LFG set: looknumber %u, temp %X, type %u, entry %u", slot, temp, type, entry); - - if (LookingForGroup_auto_join) - AttemptJoin(_player); - - //SendLfgResult(type, entry, 0); - SendLfgUpdate(0, 1, 0); -} - -void WorldSession::HandleLfgSetRoles(WorldPacket &recv_data) -{ - sLog.outDebug("CMSG_LFG_SET_ROLES"); - - uint8 roles; - recv_data >> roles; - - _player->m_lookingForGroup.roles = roles; -} - -void WorldSession::SendLfgUpdate(uint8 /*unk1*/, uint8 /*unk2*/, uint8 /*unk3*/) -{ - -} +}
\ No newline at end of file diff --git a/src/game/LFGMgr.cpp b/src/game/LFGMgr.cpp new file mode 100644 index 00000000000..474a34fe9d6 --- /dev/null +++ b/src/game/LFGMgr.cpp @@ -0,0 +1,440 @@ +/* + * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "Policies/SingletonImp.h" +#include "Common.h" +#include "SharedDefines.h" +#include "Group.h" +#include "Player.h" +#include "LFGMgr.h" +#include "ObjectMgr.h" +#include "WorldPacket.h" + +INSTANTIATE_SINGLETON_1(LFGMgr); + +LFGMgr::LFGMgr() +{ +} + +LFGMgr::~LFGMgr() +{ + for (LfgRewardList::iterator it = m_RewardList.begin(); it != m_RewardList.end(); ++it) + delete *it; + m_RewardList.clear(); + + for (LfgRewardList::iterator it = m_RewardDoneList.begin(); it != m_RewardDoneList.end(); ++it) + delete *it; + m_RewardDoneList.clear(); + + for (LfgDungeonMap::iterator it = m_DungeonsMap.begin(); it != m_DungeonsMap.end(); ++it) + { + it->second->clear(); + delete it->second; + } + m_DungeonsMap.clear(); +} + +/// <summary> +/// Initialize Looking For Group +/// </summary> +void LFGMgr::InitLFG() +{ + // Fill reward data + LfgReward *reward; + for (uint8 i = 0; i <= LFG_REWARD_DATA_SIZE; ++i) + { + reward = new LfgReward(); + reward->strangers = 0; + reward->baseXP = RewardDungeonData[i][0]; + reward->baseMoney = RewardDungeonData[i][1]; + reward->variableMoney = 0; + reward->variableXP = 0; + reward->itemId = RewardDungeonData[i][2]; + reward->displayId = RewardDungeonData[i][3]; + reward->stackCount = RewardDungeonData[i][4]; + m_RewardList.push_back(reward); + } + + for (uint8 i = 0; i < LFG_REWARD_DATA_SIZE; ++i) + { + reward = new LfgReward(); + reward->strangers = 0; + reward->baseXP = RewardDungeonDoneData[i][0]; + reward->baseMoney = RewardDungeonDoneData[i][1]; + reward->variableMoney = 0; + reward->variableXP = 0; + reward->itemId = RewardDungeonDoneData[i][2]; + reward->displayId = RewardDungeonDoneData[i][3]; + reward->stackCount = RewardDungeonDoneData[i][4]; + m_RewardDoneList.push_back(reward); + } + // Initialize dungeonMap + m_DungeonsMap[LFG_ALL_DUNGEONS] = GetAllDungeons(); + /* This will be used later. + m_DungeonsMap[LFG_RANDOM_CLASSIC] = GetDungeonsByRandom(LFG_RANDOM_CLASSIC); + m_DungeonsMap[LFG_RANDOM_BC_NORMAL] = GetDungeonsByRandom(LFG_RANDOM_BC_NORMAL); + m_DungeonsMap[LFG_RANDOM_BC_HEROIC] = GetDungeonsByRandom(LFG_RANDOM_BC_HEROIC); + m_DungeonsMap[LFG_RANDOM_LK_NORMAL] = GetDungeonsByRandom(LFG_RANDOM_LK_NORMAL); + m_DungeonsMap[LFG_RANDOM_LK_HEROIC] = GetDungeonsByRandom(LFG_RANDOM_LK_HEROIC); + */ +} + + + +// --------------------------------------------------------------------------// +// Packet Functions +// --------------------------------------------------------------------------// + +/// <summary> +/// Build and Send LFG lock player info and reward +/// </summary> +/// <param name="plr">Player</param> +void LFGMgr::SendLfgPlayerInfo(Player *plr) +{ + uint32 rsize = 0; + uint32 lsize = 0; + LfgDungeonSet *randomlist = GetRandomDungeons(plr->getLevel(), plr->GetSession()->Expansion()); + LfgLockStatusSet *lockSet = GetPlayerLockStatusDungeons(plr, m_DungeonsMap[LFG_ALL_DUNGEONS]); + if (randomlist) + rsize = randomlist->size(); + if (lockSet) + lsize = lockSet->size(); + + sLog.outDebug("SMSG_LFG_PLAYER_INFO"); + WorldPacket data(SMSG_LFG_PLAYER_INFO, 1 + rsize * (4 + 1 + 4 + 4 + 4 + 4 + 1 + 4 + 4 + 4) + 4 + lsize * (4 + 4)); + if (!randomlist) + { + data << uint8(0); + } + else + { + data << uint8(randomlist->size()); // Random Dungeon count + for (LfgDungeonSet::iterator it = randomlist->begin(); it != randomlist->end(); ++it) + { + data << uint32(*it); // Entry + BuildRewardBlock(data, *it, plr); + } + randomlist->clear(); + delete randomlist; + } + BuildPlayerLockDungeonBlock(data, lockSet); + plr->GetSession()->SendPacket(&data); +} + +/// <summary> +/// Build and Send LFG lock party info and reward +/// </summary> +/// <param name="plr">Player</param> +void LFGMgr::SendLfgPartyInfo(Player *plr) +{ + if (LfgLockStatusMap *lockMap = GetPartyLockStatusDungeons(plr, m_DungeonsMap[LFG_ALL_DUNGEONS])) + { + uint32 size = 0; + for (LfgLockStatusMap::const_iterator it = lockMap->begin(); it != lockMap->end(); ++it) + size += 8 + 4 + it->second->size() * (4 + 4); + sLog.outDebug("SMSG_LFG_PARTY_INFO"); + WorldPacket data(SMSG_LFG_PARTY_INFO, 1 + size); + BuildPartyLockDungeonBlock(data, lockMap); + plr->GetSession()->SendPacket(&data); + } +} + +/// <summary> +/// Build Reward packet structure for a given dungeon +/// </summary> +/// <param name="data">WorldPacket</param> +/// <param name="dungeon">Dungeon entry</param> +/// <param name="plr">Player</param> +void LFGMgr::BuildRewardBlock(WorldPacket &data, uint32 dungeon, Player *plr) +{ + bool done = plr->m_lookingForGroup.isDungeonDone(dungeon); + LfgReward *reward = GetRandomDungeonReward(dungeon, done, plr->getLevel()); + + if (!reward) + return; + + data << uint8(done); + if (data.GetOpcode() == SMSG_LFG_PLAYER_REWARD) + data << uint32(reward->strangers); + data << uint32(reward->baseMoney); + data << uint32(reward->baseXP); + data << uint32(reward->variableMoney); + data << uint32(reward->variableXP); + data << uint8(reward->itemId != 0); + if (reward->itemId) + { + data << uint32(reward->itemId); + data << uint32(reward->displayId); + data << uint32(reward->stackCount); + } +} + +/// <summary> +/// Build Party Dungeon lock status packet +/// </summary> +/// <param name="data">WorldPacket</param> +/// <param name="lock">lock status map</param> +void LFGMgr::BuildPartyLockDungeonBlock(WorldPacket &data, LfgLockStatusMap *lockMap) +{ + assert(lockMap); + + data << uint8(lockMap->size()); + + LfgLockStatusSet *lockSet; + uint64 guid; + for (LfgLockStatusMap::const_iterator it = lockMap->begin(); it != lockMap->end(); ++it) + { + guid = it->first; + lockSet = it->second; + if (!lockSet) + continue; + + data << uint64(guid); // Player guid + BuildPlayerLockDungeonBlock(data, lockSet); + } + lockMap->clear(); + delete lockMap; +} + +/// <summary> +/// Build Player Dungeon lock status packet +/// </summary> +/// <param name="data">WorldPacket</param> +/// <param name="lock">lock status list</param> +void LFGMgr::BuildPlayerLockDungeonBlock(WorldPacket &data, LfgLockStatusSet *lockSet) +{ + assert(lockSet); + data << uint32(lockSet->size()); // Size of lock dungeons + for (LfgLockStatusSet::iterator it = lockSet->begin(); it != lockSet->end(); ++it) + { + data << uint32((*it)->dungeon); // Dungeon entry + type + data << uint32((*it)->lockstatus); // Lock status + delete (*it); + } + lockSet->clear(); + delete lockSet; +} + + + + +// --------------------------------------------------------------------------// +// Auxiliar Functions +// --------------------------------------------------------------------------// + +/// <summary> +/// Get all Group members list of dungeons that can't be done and reason +/// leader excluded as the list given is he list he can do +/// </summary> +/// <param name="grp">Group</param> +/// <param name="dungeons">Dungeons to check</param> +/// <returns>LfgLockStatusMap*</returns> +LfgLockStatusMap* LFGMgr::GetPartyLockStatusDungeons(Player *plr, LfgDungeonSet *dungeons) +{ + assert(plr); + assert(dungeons); + Group *grp = plr->GetGroup(); + if (!grp) + return NULL; + + Player *plrg; + LfgLockStatusMap *dungeonMap = new LfgLockStatusMap(); + for (GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) + { + plrg = itr->getSource(); + if (!plrg || plrg == plr) + continue; + (*dungeonMap)[plrg->GetGUID()] = GetPlayerLockStatusDungeons(plrg, dungeons); + } + return dungeonMap; +} + +/// <summary> +/// Get list of dungeons player can't do and reasons +/// </summary> +/// <param name="plr">Player</param> +/// <param name="dungeons">Dungeons to check</param> +/// <returns>LfgLockStatusSet*</returns> +LfgLockStatusSet* LFGMgr::GetPlayerLockStatusDungeons(Player *plr, LfgDungeonSet *dungeons) +{ + LfgLockStatusSet *list = new LfgLockStatusSet(); + LfgLockStatus *lockstatus = NULL; + LFGDungeonEntry const *dungeon; + LfgLockStatusType locktype; + uint8 level = plr->getLevel(); + uint8 expansion = plr->GetSession()->Expansion(); + + for (LfgDungeonSet::const_iterator it = dungeons->begin(); it != dungeons->end(); ++it) + { + dungeon = sLFGDungeonStore.LookupEntry(*it); + assert(dungeon); // Will never happen - We provide a list from sLFGDungeonStore + + locktype = LFG_LOCKSTATUS_OK; + if (dungeon->expansion > expansion) + locktype = LFG_LOCKSTATUS_INSUFFICIENT_EXPANSION; + else if (dungeon->minlevel > level) + locktype = LFG_LOCKSTATUS_TOO_LOW_LEVEL; + else if (dungeon->maxlevel < level) + locktype = LFG_LOCKSTATUS_TOO_HIGH_LEVEL; + /* TODO - Use these types when needed... + else if () + locktype = LFG_LOCKSTATUS_TOO_LOG_GEAR_SCORE; + else if () + locktype = LFG_LOCKSTATUS_TOO_HIGH_GEAR_SCORE; + else if () // Locked due to WG, closed by GM, done daily, etc + locktype = LFG_LOCKSTATUS_RAID_LOCKED; + else if () + locktype = LFG_LOCKSTATUS_ATTUNEMENT_TOO_LOW_LEVEL; + else if () + locktype = LFG_LOCKSTATUS_ATTUNEMENT_TOO_HIGH_LEVEL; + else if () // Need list of instances and needed quest to enter + locktype = LFG_LOCKSTATUS_QUEST_NOT_COMPLETED; + else if () // Need list of instances and needed key to enter + locktype = LFG_LOCKSTATUS_MISSING_ITEM; + else if () // Need list of instances and needed season to open + locktype = LFG_LOCKSTATUS_NOT_IN_SEASON; + */ + + if (locktype != LFG_LOCKSTATUS_OK) + { + lockstatus = new LfgLockStatus(); + lockstatus->dungeon = dungeon->Entry(); + lockstatus->lockstatus = locktype; + list->insert(lockstatus); + } + } + return list; +} + +/// <summary> +/// Get the dungeon list that can be done. +/// </summary> +/// <returns>LfgDungeonSet*</returns> +LfgDungeonSet* LFGMgr::GetAllDungeons() +{ + LfgDungeonSet *dungeons = new LfgDungeonSet(); + LFGDungeonEntry const *dungeon; + for (uint32 i = 0; i < sLFGDungeonStore.GetNumRows(); ++i) + { + dungeon = sLFGDungeonStore.LookupEntry(i); + if (!dungeon || dungeon->type == LFG_TYPE_ZONE) + continue; + dungeons->insert(dungeon->ID); + } + if (!dungeons->size()) + { + delete dungeons; + return NULL; + } + else + return dungeons; +} + +/// <summary> +/// Get the dungeon list that can be done given a random dungeon entry. +/// </summary> +/// <param name="randomdungeon">Random dungeon entry</param> +/// <returns>LfgDungeonSet*</returns> +LfgDungeonSet* LFGMgr::GetDungeonsByRandom(uint32 randomdungeon) +{ + LFGDungeonEntry const *dungeon = sLFGDungeonStore.LookupEntry(randomdungeon); + if (!dungeon) + return NULL; + + uint32 grouptype = dungeon->grouptype; + LfgDungeonSet *random = new LfgDungeonSet(); + for (uint32 i = 0; i < sLFGDungeonStore.GetNumRows(); ++i) + { + dungeon = sLFGDungeonStore.LookupEntry(i); + if (!dungeon || dungeon->type == LFG_TYPE_RANDOM || dungeon->grouptype != grouptype) + continue; + random->insert(dungeon->ID); + } + if (!random->size()) + { + delete random; + return NULL; + } + else + return random; +} + +/// <summary> +/// Get the random dungeon list that can be done at a certain level and expansion. +/// </summary> +/// <param name="level">Player level</param> +/// <param name="expansion">Player account expansion</param> +/// <returns>LfgDungeonSet*</returns> +LfgDungeonSet* LFGMgr::GetRandomDungeons(uint8 level, uint8 expansion) +{ + LfgDungeonSet *list = new LfgDungeonSet(); + LFGDungeonEntry const *dungeon; + for (uint32 i = 0; i < sLFGDungeonStore.GetNumRows(); ++i) + { + dungeon = sLFGDungeonStore.LookupEntry(i); + if (dungeon && dungeon->expansion <= expansion && dungeon->type == LFG_TYPE_RANDOM && + dungeon->minlevel <= level && level <= dungeon->maxlevel) + list->insert(dungeon->Entry()); + } + return list; +} + +/// <summary> +/// Get the reward of a given random dungeon +/// </summary> +/// <param name="dungeon">random dungeon id</param> +/// <param name="done">Dungeon previously done</param> +/// <returns></returns> +LfgReward* LFGMgr::GetRandomDungeonReward(uint32 dungeon, bool done, uint8 level) +{ + uint8 index = 0; + switch((dungeon & 0x00FFFFFF)) // Get dungeon id from dungeon entry + { + case LFG_RANDOM_CLASSIC: + if (level < 15) + index = LFG_REWARD_LEVEL0; + else if (level < 24) + index = LFG_REWARD_LEVEL1; + else if (level < 35) + index = LFG_REWARD_LEVEL2; + else if (level < 46) + index = LFG_REWARD_LEVEL3; + else if (level < 56) + index = LFG_REWARD_LEVEL4; + else + index = LFG_REWARD_LEVEL5; + break; + case LFG_RANDOM_BC_NORMAL: + index = LFG_REWARD_BC_NORMAL; + break; + case LFG_RANDOM_BC_HEROIC: + index = LFG_REWARD_BC_HEROIC; + break; + case LFG_RANDOM_LK_NORMAL: + index = level == 80 ? LFG_REWARD_LK_NORMAL80 : LFG_REWARD_LK_NORMAL; + break; + case LFG_RANDOM_LK_HEROIC: + index = LFG_REWARD_LK_HEROIC; + break; + default: // This should never happen! + done = false; + index = LFG_REWARD_LEVEL0; + sLog.outError("LFGMgr::GetRandomDungeonReward: Dungeon %u is not random dungeon!", dungeon); + break; + } + return done ? m_RewardDoneList.at(index) : m_RewardList.at(index); +}
\ No newline at end of file diff --git a/src/game/LFGMgr.h b/src/game/LFGMgr.h new file mode 100644 index 00000000000..ce58d468931 --- /dev/null +++ b/src/game/LFGMgr.h @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _LFGMGR_H +#define _LFGMGR_H + +#include "Common.h" +#include "Policies/Singleton.h" +#include "Group.h" +#include "LFG.h" + + +enum LfgType +{ + LFG_TYPE_DUNGEON = 1, + LFG_TYPE_RAID = 2, + LFG_TYPE_QUEST = 3, + LFG_TYPE_ZONE = 4, + LFG_TYPE_HEROIC = 5, + LFG_TYPE_RANDOM = 6, +}; + +enum LfgLockStatusType +{ + LFG_LOCKSTATUS_OK = 0, // Internal use only + LFG_LOCKSTATUS_INSUFFICIENT_EXPANSION = 1, + LFG_LOCKSTATUS_TOO_LOW_LEVEL = 2, + LFG_LOCKSTATUS_TOO_HIGH_LEVEL = 3, + LFG_LOCKSTATUS_TOO_LOG_GEAR_SCORE = 4, + LFG_LOCKSTATUS_TOO_HIGH_GEAR_SCORE = 5, + LFG_LOCKSTATUS_RAID_LOCKED = 6, + LFG_LOCKSTATUS_ATTUNEMENT_TOO_LOW_LEVEL = 1001, + LFG_LOCKSTATUS_ATTUNEMENT_TOO_HIGH_LEVEL = 1002, + LFG_LOCKSTATUS_QUEST_NOT_COMPLETED = 1022, + LFG_LOCKSTATUS_MISSING_ITEM = 1025, + LFG_LOCKSTATUS_NOT_IN_SEASON = 1031, +}; + +enum LfgRandomDungeonEntries +{ + LFG_ALL_DUNGEONS = 0, + LFG_RANDOM_CLASSIC = 258, + LFG_RANDOM_BC_NORMAL = 259, + LFG_RANDOM_BC_HEROIC = 260, + LFG_RANDOM_LK_NORMAL = 261, + LFG_RANDOM_LK_HEROIC = 262, +}; + +enum LfgRewardEnums +{ + LFG_REWARD_LEVEL0 = 10, + LFG_REWARD_LEVEL1 = 0, + LFG_REWARD_LEVEL2 = 1, + LFG_REWARD_LEVEL3 = 2, + LFG_REWARD_LEVEL4 = 3, + LFG_REWARD_LEVEL5 = 4, + LFG_REWARD_BC_NORMAL = 5, + LFG_REWARD_BC_HEROIC = 6, + LFG_REWARD_LK_NORMAL = 7, + LFG_REWARD_LK_NORMAL80 = 7, + LFG_REWARD_LK_HEROIC = 8, + LFG_REWARD_DATA_SIZE = 10, +}; + +const uint32 RewardDungeonData[LFG_REWARD_DATA_SIZE+1][5] = +{ // XP, money, item, item display, count + {310, 3500, 51999, 56915, 1}, // Classic 15-23 + {470, 7000, 52000, 56915, 1}, // Classic 24-34 + {825, 13000, 52001, 56915, 1}, // Classic 35-45 + {12250, 16500, 52002, 56915, 1}, // Classic 46-55 + {14300, 18000, 52003, 56915, 1}, // Classic 56-60 + {1600, 62000, 52004, 56915, 1}, // BC Normal + {1900, 88000, 52005, 56915, 1}, // BC Heroic + {33100, 148000, 47241, 62232, 2}, // LK Normal + {0, 198600, 47241, 62232, 2}, // LK Normal - Level 80 + {0, 264600, 49426, 64062, 2}, // LK Heroic + {0, 0, 0, 0, 0}, // Classic - No level +}; + +const uint32 RewardDungeonDoneData[LFG_REWARD_DATA_SIZE][5] = +{ // XP, money, item, item display, count + {200, 1800, 51999, 56915, 1}, // Classic 15-23 + {310, 3500, 52000, 56915, 1}, // Classic 24-34 + {550, 6500, 52001, 56915, 1}, // Classic 35-45 + {8150, 8500, 52002, 56915, 1}, // Classic 46-55 + {9550, 9000, 52003, 56915, 1}, // Classic 56-60 + {1100, 31000, 52004, 56915, 1}, // BC Normal + {12650, 44000, 52005, 56915, 1}, // BC Heroic + {16550, 74000, 0, 0, 0}, // LK Normal + {0, 99300, 0, 0, 0}, // LK Normal - Level 80 + {0, 132300, 47241, 62232, 2}, // LK Heroic +}; + +// Dungeon and reason why player can't join +struct LfgLockStatus +{ + uint32 dungeon; + LfgLockStatusType lockstatus; +}; + +// Reward info +struct LfgReward +{ + uint32 strangers; + uint32 baseMoney; + uint32 baseXP; + uint32 variableMoney; + uint32 variableXP; + uint32 itemId; + uint32 displayId; + uint32 stackCount; +}; + +typedef std::set<LfgLockStatus*> LfgLockStatusSet; +typedef std::vector<LfgReward*> LfgRewardList; +typedef std::map<uint64, LfgLockStatusSet*> LfgLockStatusMap; +typedef std::map<uint32, LfgDungeonSet*> LfgDungeonMap; + +class LFGMgr +{ +public: + LFGMgr(); + ~LFGMgr(); + + void InitLFG(); + void SendLfgPlayerInfo(Player *plr); + void SendLfgPartyInfo(Player *plr); + +private: + void BuildAvailableRandomDungeonList(WorldPacket &data, Player *plr); + void BuildRewardBlock(WorldPacket &data, uint32 dungeon, Player *plr); + void BuildPlayerLockDungeonBlock(WorldPacket &data, LfgLockStatusSet *lockSet); + void BuildPartyLockDungeonBlock(WorldPacket &data, LfgLockStatusMap *lockMap); + LfgLockStatusMap* GetPartyLockStatusDungeons(Player *plr, LfgDungeonSet *dungeons); + LfgLockStatusSet* GetPlayerLockStatusDungeons(Player *plr, LfgDungeonSet *dungeons); + LfgDungeonSet* GetRandomDungeons(uint8 level, uint8 expansion); + LfgDungeonSet* GetDungeonsByRandom(uint32 randomdungeon); + LfgDungeonSet* GetAllDungeons(); + LfgReward* GetRandomDungeonReward(uint32 dungeon, bool done, uint8 level); + + LfgRewardList m_RewardList; + LfgRewardList m_RewardDoneList; + LfgDungeonMap m_DungeonsMap; +}; + +#define sLFGMgr Trinity::Singleton<LFGMgr>::Instance() +#endif diff --git a/src/game/Opcodes.cpp b/src/game/Opcodes.cpp index 2a69553abdf..d45e264cfd6 100644 --- a/src/game/Opcodes.cpp +++ b/src/game/Opcodes.cpp @@ -539,8 +539,8 @@ OpcodeHandler opcodeTable[NUM_MSG_TYPES] = /*0x1FC*/ { "SMSG_ENVIRONMENTALDAMAGELOG", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x1FD*/ { "CMSG_PLAYER_DIFFICULTY_CHANGE", STATUS_NEVER, &WorldSession::Handle_NULL }, /*0x1FE*/ { "SMSG_RWHOIS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x1FF*/ { "SMSG_LFG_PLAYER_REWARD", STATUS_LOGGEDIN, &WorldSession::Handle_ServerSide }, - /*0x200*/ { "SMSG_LFG_TELEPORT_DENIED", STATUS_LOGGEDIN, &WorldSession::Handle_ServerSide }, + /*0x1FF*/ { "SMSG_LFG_PLAYER_REWARD", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x200*/ { "SMSG_LFG_TELEPORT_DENIED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x201*/ { "CMSG_UNLEARN_SPELL", STATUS_NEVER, &WorldSession::Handle_NULL }, /*0x202*/ { "CMSG_UNLEARN_SKILL", STATUS_LOGGEDIN, &WorldSession::HandleUnlearnSkillOpcode }, /*0x203*/ { "SMSG_REMOVED_SPELL", STATUS_NEVER, &WorldSession::Handle_ServerSide }, @@ -888,10 +888,10 @@ OpcodeHandler opcodeTable[NUM_MSG_TYPES] = /*0x359*/ { "MSG_MOVE_START_ASCEND", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, /*0x35A*/ { "MSG_MOVE_STOP_ASCEND", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, /*0x35B*/ { "SMSG_ARENA_TEAM_STATS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x35C*/ { "CMSG_LFG_JOIN", STATUS_LOGGEDIN, &WorldSession::HandleLfgSetAutoJoinOpcode }, - /*0x35D*/ { "CMSG_LFG_LEAVE", STATUS_LOGGEDIN, &WorldSession::HandleLfgClearAutoJoinOpcode }, - /*0x35E*/ { "CMSG_SEARCH_LFG_JOIN", STATUS_LOGGEDIN, &WorldSession::HandleLfmSetAutoFillOpcode }, - /*0x35F*/ { "CMSG_SEARCH_LFG_LEAVE", STATUS_LOGGEDIN, &WorldSession::HandleLfmClearAutoFillOpcode }, + /*0x35C*/ { "CMSG_LFG_JOIN", STATUS_LOGGEDIN, &WorldSession::Handle_NULL }, + /*0x35D*/ { "CMSG_LFG_LEAVE", STATUS_LOGGEDIN, &WorldSession::Handle_NULL }, + /*0x35E*/ { "CMSG_SEARCH_LFG_JOIN", STATUS_LOGGEDIN, &WorldSession::Handle_NULL }, + /*0x35F*/ { "CMSG_SEARCH_LFG_LEAVE", STATUS_LOGGEDIN, &WorldSession::Handle_NULL }, /*0x360*/ { "SMSG_UPDATE_LFG_LIST", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x361*/ { "SMSG_LFG_PROPOSAL_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x362*/ { "CMSG_LFG_PROPOSAL_RESULT", STATUS_LOGGEDIN, &WorldSession::Handle_NULL }, @@ -902,15 +902,15 @@ OpcodeHandler opcodeTable[NUM_MSG_TYPES] = /*0x367*/ { "SMSG_LFG_UPDATE_PLAYER", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x368*/ { "SMSG_LFG_UPDATE_PARTY", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x369*/ { "SMSG_LFG_UPDATE_LIST", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x36A*/ { "CMSG_LFG_SET_ROLES", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x36B*/ { "CMSG_LFG_SET_NEEDS", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x36C*/ { "CMSG_LFG_SET_BOOT_VOTE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x36A*/ { "CMSG_LFG_SET_ROLES", STATUS_LOGGEDIN, &WorldSession::Handle_NULL }, + /*0x36B*/ { "CMSG_LFG_SET_NEEDS", STATUS_LOGGEDIN, &WorldSession::Handle_NULL }, + /*0x36C*/ { "CMSG_LFG_SET_BOOT_VOTE", STATUS_LOGGEDIN, &WorldSession::Handle_NULL }, /*0x36D*/ { "SMSG_LFG_BOOT_PROPOSAL_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x36E*/ { "CMSG_LFD_PLAYER_LOCK_INFO_REQUEST", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x36E*/ { "CMSG_LFD_PLAYER_LOCK_INFO_REQUEST", STATUS_LOGGEDIN, &WorldSession::HandleLfgPlayerLockInfoRequestOpcode}, /*0x36F*/ { "SMSG_LFG_PLAYER_INFO", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x370*/ { "CMSG_LFG_TELEPORT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x371*/ { "CMSG_LFD_PARTY_LOCK_INFO_REQUEST", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x372*/ { "SMSG_LFG_PARTY", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x370*/ { "CMSG_LFG_TELEPORT", STATUS_LOGGEDIN, &WorldSession::Handle_NULL }, + /*0x371*/ { "CMSG_LFD_PARTY_LOCK_INFO_REQUEST", STATUS_LOGGEDIN, &WorldSession::HandleLfgPartyLockInfoRequestOpcode}, + /*0x372*/ { "SMSG_LFG_PARTY_INFO", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x373*/ { "SMSG_TITLE_EARNED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x374*/ { "CMSG_SET_TITLE", STATUS_LOGGEDIN, &WorldSession::HandleSetTitleOpcode }, /*0x375*/ { "CMSG_CANCEL_MOUNT_AURA", STATUS_LOGGEDIN, &WorldSession::HandleCancelMountAuraOpcode }, @@ -1236,7 +1236,7 @@ OpcodeHandler opcodeTable[NUM_MSG_TYPES] = /*0x4B5*/ { "SMSG_ITEM_REFUND_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x4B6*/ { "CMSG_CORPSE_MAP_POSITION_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleCorpseMapPositionQuery }, /*0x4B7*/ { "SMSG_CORPSE_MAP_POSITION_QUERY_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x4B8*/ { "CMSG_LFG_SET_ROLES_2", STATUS_LOGGEDIN, &WorldSession::HandleLfgSetRoles }, + /*0x4B8*/ { "CMSG_LFG_SET_ROLES_2", STATUS_LOGGEDIN, &WorldSession::Handle_NULL }, /*0x4B9*/ { "UMSG_UNKNOWN_1209", STATUS_NEVER, &WorldSession::Handle_NULL }, /*0x4BA*/ { "CMSG_CALENDAR_CONTEXT_EVENT_SIGNUP", STATUS_NEVER, &WorldSession::Handle_NULL }, /*0x4BB*/ { "SMSG_CALENDAR_ACTION_PENDING", STATUS_NEVER, &WorldSession::Handle_ServerSide }, diff --git a/src/game/Player.h b/src/game/Player.h index b1ab6a683aa..5ea6e22154f 100644 --- a/src/game/Player.h +++ b/src/game/Player.h @@ -39,6 +39,7 @@ #include "ReputationMgr.h" #include "BattleGround.h" #include "DBCEnums.h" +#include "LFG.h" #include<string> #include<vector> @@ -337,74 +338,6 @@ struct EnchantDuration typedef std::list<EnchantDuration> EnchantDurationList; typedef std::list<Item*> ItemDurationList; -enum LfgType -{ - LFG_TYPE_NONE = 0, - LFG_TYPE_DUNGEON = 1, - LFG_TYPE_RAID = 2, - LFG_TYPE_QUEST = 3, - LFG_TYPE_ZONE = 4, - LFG_TYPE_HEROIC_DUNGEON = 5, - LFG_TYPE_RANDOM_DUNGEON = 6 -}; - -enum LfgRoles -{ - LEADER = 0x01, - TANK = 0x02, - HEALER = 0x04, - DAMAGE = 0x08 -}; - -struct LookingForGroupSlot -{ - LookingForGroupSlot() : entry(0), type(0) {} - bool Empty() const { return !entry && !type; } - void Clear() { entry = 0; type = 0; } - void Set(uint32 _entry, uint32 _type) { entry = _entry; type = _type; } - bool Is(uint32 _entry, uint32 _type) const { return entry == _entry && type == _type; } - bool canAutoJoin() const { return entry && (type == LFG_TYPE_DUNGEON || type == LFG_TYPE_HEROIC_DUNGEON); } - - uint32 entry; - uint32 type; -}; - -#define MAX_LOOKING_FOR_GROUP_SLOT 3 - -struct LookingForGroup -{ - LookingForGroup() {} - bool HaveInSlot(LookingForGroupSlot const& slot) const { return HaveInSlot(slot.entry, slot.type); } - bool HaveInSlot(uint32 _entry, uint32 _type) const - { - for (uint8 i = 0; i < MAX_LOOKING_FOR_GROUP_SLOT; ++i) - if (slots[i].Is(_entry, _type)) - return true; - return false; - } - - bool canAutoJoin() const - { - for (uint8 i = 0; i < MAX_LOOKING_FOR_GROUP_SLOT; ++i) - if (slots[i].canAutoJoin()) - return true; - return false; - } - - bool Empty() const - { - for (uint8 i = 0; i < MAX_LOOKING_FOR_GROUP_SLOT; ++i) - if (!slots[i].Empty()) - return false; - return more.Empty(); - } - - LookingForGroupSlot slots[MAX_LOOKING_FOR_GROUP_SLOT]; - LookingForGroupSlot more; - std::string comment; - uint8 roles; -}; - enum PlayerMovementType { MOVE_ROOT = 1, diff --git a/src/game/World.cpp b/src/game/World.cpp index e6c3ebb974f..684ec7b970a 100644 --- a/src/game/World.cpp +++ b/src/game/World.cpp @@ -69,6 +69,7 @@ #include "ProgressBar.h" #include "ScriptMgr.h" #include "AddonMgr.h" +#include "LFGMgr.h" INSTANTIATE_SINGLETON_1(World); @@ -1667,6 +1668,10 @@ void World::SetInitialWorldSettings() sLog.outString("Loading World States..."); // must be loaded before battleground and outdoor PvP LoadWorldStates(); + ///- Initialize Looking For Group + sLog.outString("Starting Looking For Group System"); + sLFGMgr.InitLFG(); + ///- Initialize Battlegrounds sLog.outString("Starting BattleGround System"); sBattleGroundMgr.CreateInitialBattleGrounds(); diff --git a/src/game/WorldSession.h b/src/game/WorldSession.h index a6cfae9c06d..a8abe9054d7 100644 --- a/src/game/WorldSession.h +++ b/src/game/WorldSession.h @@ -147,8 +147,6 @@ class WorldSession void SendNotification(const char *format,...) ATTR_PRINTF(2,3); void SendNotification(int32 string_id,...); void SendPetNameInvalid(uint32 error, const std::string& name, DeclinedName *declinedName); - void SendLfgResult(uint32 type, uint32 entry, uint8 lfg_type); - void SendLfgUpdate(uint8 unk1, uint8 unk2, uint8 unk3); void SendPartyResult(PartyOperation operation, const std::string& member, PartyResult res); void SendAreaTriggerMessage(const char* Text, ...) ATTR_PRINTF(2,3); void SendSetPhaseShift(uint32 phaseShift); @@ -684,25 +682,22 @@ class WorldSession void HandleMinimapPingOpcode(WorldPacket& recv_data); void HandleRandomRollOpcode(WorldPacket& recv_data); void HandleFarSightOpcode(WorldPacket& recv_data); - void HandleSetLfgOpcode(WorldPacket& recv_data); void HandleSetDungeonDifficultyOpcode(WorldPacket& recv_data); void HandleSetRaidDifficultyOpcode(WorldPacket& recv_data); void HandleMoveSetCanFlyAckOpcode(WorldPacket& recv_data); - void HandleLfgSetAutoJoinOpcode(WorldPacket& recv_data); - void HandleLfgClearAutoJoinOpcode(WorldPacket& recv_data); - void HandleLfmSetAutoFillOpcode(WorldPacket& recv_data); - void HandleLfmClearAutoFillOpcode(WorldPacket& recv_data); - void HandleLfgClearOpcode(WorldPacket& recv_data); - void HandleLfmClearOpcode(WorldPacket& recv_data); - void HandleSetLfmOpcode(WorldPacket& recv_data); - void HandleSetLfgCommentOpcode(WorldPacket& recv_data); - void HandleLfgSetRoles(WorldPacket& recv_data); void HandleSetTitleOpcode(WorldPacket& recv_data); void HandleRealmSplitOpcode(WorldPacket& recv_data); void HandleTimeSyncResp(WorldPacket& recv_data); void HandleWhoisOpcode(WorldPacket& recv_data); void HandleResetInstancesOpcode(WorldPacket& recv_data); + // Looking for Dungeon/Raid + void HandleSetLfgCommentOpcode(WorldPacket & recv_data); + void HandleLfgPlayerLockInfoRequestOpcode(WorldPacket& recv_data); + void HandleLfgPartyLockInfoRequestOpcode(WorldPacket& recv_data); + void SendLfgUpdatePlayer(uint8 updateType, uint32 dungeonEntry = 0); + void SendLfgUpdateParty(uint8 updateType, uint32 dungeonEntry = 0); + // Arena Team void HandleInspectArenaTeamsOpcode(WorldPacket& recv_data); void HandleArenaTeamQueryOpcode(WorldPacket& recv_data); diff --git a/win/VC90/game.vcproj b/win/VC90/game.vcproj index 13e2d79f83f..8151b0b09a5 100644 --- a/win/VC90/game.vcproj +++ b/win/VC90/game.vcproj @@ -647,10 +647,22 @@ > </File> <File + RelativePath="..\..\src\game\LFG.h" + > + </File> + <File RelativePath="..\..\src\game\LFGHandler.cpp" > </File> <File + RelativePath="..\..\src\game\LFGMgr.cpp" + > + </File> + <File + RelativePath="..\..\src\game\LFGMgr.h" + > + </File> + <File RelativePath="..\..\src\game\LootHandler.cpp" > </File> |