diff --git a/sql/updates/characters/4.3.4/custom_2017_12_21_00_characters.sql b/sql/updates/characters/4.3.4/custom_2017_12_21_00_characters.sql new file mode 100644 index 00000000000..bf45daafcc7 --- /dev/null +++ b/sql/updates/characters/4.3.4/custom_2017_12_21_00_characters.sql @@ -0,0 +1,4 @@ +ALTER TABLE `guild` +ADD COLUMN `completedDungeonChallenges` int(10) unsigned DEFAULT '0' AFTER `todayExperience`, +ADD COLUMN `completedRaidChallenges` int(10) unsigned DEFAULT '0' AFTER `completedDungeonChallenges`, +ADD COLUMN `completedRatedBattlegroundChallenges` int(10) unsigned DEFAULT '0' AFTER `completedRaidChallenges`; diff --git a/src/server/database/Database/Implementation/CharacterDatabase.cpp b/src/server/database/Database/Implementation/CharacterDatabase.cpp index 38e8d29adeb..e9bae4bcb4d 100644 --- a/src/server/database/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/database/Database/Implementation/CharacterDatabase.cpp @@ -235,6 +235,8 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_UPD_GUILD_RESET_TODAY_EXPERIENCE, "UPDATE guild SET todayExperience = 0", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_GUILD_NEWS, "INSERT INTO guild_newslog (guildid, LogGuid, EventType, PlayerGuid, Flags, Value, Timestamp) VALUES (?, ?, ?, ?, ?, ?, ?)" " ON DUPLICATE KEY UPDATE LogGuid = VALUES (LogGuid), EventType = VALUES (EventType), PlayerGuid = VALUES (PlayerGuid), Flags = VALUES (Flags), Value = VALUES (Value), Timestamp = VALUES (Timestamp)", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_GUILD_CHALLENGE, "UPDATE guild SET completedDungeonChallenges = ?, completedRaidChallenges = ?, completedRatedBattlegroundChallenges = ? WHERE guildId = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_GUILD_RESET_CHALLENGE, "UPDATE guild SET completedDungeonChallenges = 0, completedRaidChallenges = 0, completedRatedBattlegroundChallenges = 0 WHERE guildId = ?", CONNECTION_ASYNC); // Chat channel handling PrepareStatement(CHAR_SEL_CHANNEL, "SELECT name, announce, ownership, password, bannedList FROM channels WHERE name = ? AND team = ?", CONNECTION_SYNCH); diff --git a/src/server/database/Database/Implementation/CharacterDatabase.h b/src/server/database/Database/Implementation/CharacterDatabase.h index bb3c4da5d70..60a32afd326 100644 --- a/src/server/database/Database/Implementation/CharacterDatabase.h +++ b/src/server/database/Database/Implementation/CharacterDatabase.h @@ -202,6 +202,8 @@ enum CharacterDatabaseStatements CHAR_UPD_GUILD_EXPERIENCE, CHAR_UPD_GUILD_RESET_TODAY_EXPERIENCE, CHAR_INS_GUILD_NEWS, + CHAR_UPD_GUILD_CHALLENGE, + CHAR_UPD_GUILD_RESET_CHALLENGE, CHAR_SEL_CHANNEL, CHAR_INS_CHANNEL, diff --git a/src/server/game/Cache/CharacterCache.cpp b/src/server/game/Cache/CharacterCache.cpp index 49bc58745d5..205d737eff4 100644 --- a/src/server/game/Cache/CharacterCache.cpp +++ b/src/server/game/Cache/CharacterCache.cpp @@ -220,6 +220,19 @@ bool CharacterCache::GetCharacterNameByGuid(ObjectGuid guid, std::string& name) return true; } +bool CharacterCache::GetPlayerGuildIdByGUID(ObjectGuid guid, uint32& guildId) const +{ + auto itr = _characterCacheStore.find(guid); + if (itr == _characterCacheStore.end()) + return false; + + if (!itr->second.GuildId) + return false; + + guildId = itr->second.GuildId; + return true; +} + uint32 CharacterCache::GetCharacterTeamByGuid(ObjectGuid guid) const { auto itr = _characterCacheStore.find(guid); diff --git a/src/server/game/Cache/CharacterCache.h b/src/server/game/Cache/CharacterCache.h index 641339b730d..1f62e970fd6 100644 --- a/src/server/game/Cache/CharacterCache.h +++ b/src/server/game/Cache/CharacterCache.h @@ -58,6 +58,7 @@ class TC_GAME_API CharacterCache ObjectGuid GetCharacterGuidByName(std::string const& name) const; bool GetCharacterNameByGuid(ObjectGuid guid, std::string& name) const; + bool GetPlayerGuildIdByGUID(ObjectGuid guid, uint32 &guildId) const; uint32 GetCharacterTeamByGuid(ObjectGuid guid) const; uint32 GetCharacterAccountIdByGuid(ObjectGuid guid) const; uint32 GetCharacterAccountIdByName(std::string const& name) const; diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp index 857a81ff3cc..def4c89e5ae 100644 --- a/src/server/game/Groups/Group.cpp +++ b/src/server/game/Groups/Group.cpp @@ -26,6 +26,7 @@ #include "ObjectMgr.h" #include "GroupMgr.h" #include "Group.h" +#include "Guild.h" #include "Formulas.h" #include "ObjectAccessor.h" #include "Battleground.h" @@ -205,7 +206,8 @@ void Group::LoadMemberFromDB(ObjectGuid::LowType guidLow, uint8 memberFlags, uin member.guid = ObjectGuid(HighGuid::Player, guidLow); // skip non-existed member - if (!sCharacterCache->GetCharacterNameByGuid(member.guid, member.name)) + if (!sCharacterCache->GetCharacterNameByGuid(member.guid, member.name) || + !sCharacterCache->GetPlayerGuildIdByGUID(member.guid, member.guildId)) { PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GROUP_MEMBER); stmt->setUInt32(0, guidLow); @@ -411,6 +413,7 @@ bool Group::AddMember(Player* player) member.group = subGroup; member.flags = 0; member.roles = 0; + member.guildId = player->GetGuildId(); m_memberSlots.push_back(member); SubGroupCounterIncrease(subGroup); @@ -1867,6 +1870,87 @@ bool Group::_setMembersGroup(ObjectGuid guid, uint8 group) return true; } +bool Group::MemberLevelIsInRange(uint32 levelMin, uint32 levelMax) +{ + for (member_citerator itr = m_memberSlots.begin(); itr != m_memberSlots.end(); ++itr) + if (Player *member = ObjectAccessor::FindPlayer(itr->guid)) + if (member->getLevel() < levelMin || member->getLevel() > levelMax) + return false; + + return true; +} + +bool Group::IsGuildGroupFor(Player* player) +{ + if (!IsMember(player->GetGUID())) + return false; + + if (!player->GetGuildId()) + return false; + + if (!player->GetMap()->IsDungeon() && + !(player->InArena() && player->GetBattleground()->isRated())) + return false; + + if (GetMembersCountOfGuild(player->GetGuildId()) < GetNeededMembersOfSameGuild((player->InArena() && player->GetBattleground()->isRated()) + ? player->GetBattleground()->GetArenaType() : 0, player->GetMap())) + return false; + + return true; +} + +uint32 Group::GetMembersCountOfGuild(uint32 guildId) +{ + uint32 count = 0; + + for (member_citerator itr = m_memberSlots.begin(); itr != m_memberSlots.end(); ++itr) + if (itr->guildId == guildId) + count++; + + return count; +} + +uint32 Group::GetNeededMembersOfSameGuild(uint8 arenaType, Map const *map) +{ + // For arena (100% of member) + if (arenaType && map->IsBattleArena()) + return arenaType; + + if (map->IsNonRaidDungeon()) + return 3; + + if (map->IsRaid()) + { + if (map->GetEntry()->Expansion() == 0) // classic + return 10; + + if (map->GetEntry()->Expansion() == 1) // TBC + return 8; + + if (map->Is25ManRaid()) + return 20; + + return 8; + } + + return 0; +} + +void Group::UpdateGuildFor(ObjectGuid guid, uint32 guildId) +{ + for (member_witerator itr = m_memberSlots.begin(); itr != m_memberSlots.end(); ++itr) + { + if (itr->guid == guid) + itr->guildId = guildId; // Change guild ID + + // Update guild flag + if (itr->guildId == guildId) + if (Player* member = ObjectAccessor::FindPlayer(itr->guid)) + if (Guild* guild = member->GetGuild()) + guild->HandleGuildPartyRequest(member->GetSession()); + } +} + bool Group::SameSubGroup(Player const* member1, Player const* member2) const { if (!member1 || !member2) diff --git a/src/server/game/Groups/Group.h b/src/server/game/Groups/Group.h index 4f676dc6909..49701f41da5 100644 --- a/src/server/game/Groups/Group.h +++ b/src/server/game/Groups/Group.h @@ -172,6 +172,7 @@ class TC_GAME_API Group uint8 group; uint8 flags; uint8 roles; + uint32 guildId; }; typedef std::list MemberSlotList; typedef MemberSlotList::const_iterator member_citerator; @@ -353,6 +354,13 @@ class TC_GAME_API Group // FG: evil hacks void BroadcastGroupUpdate(void); + // guild misc + bool IsGuildGroupFor(Player* player); + uint32 GetMembersCountOfGuild(uint32 guildId); + uint32 GetNeededMembersOfSameGuild(uint8 arenaType, Map const* map); + bool MemberLevelIsInRange(uint32 levelMin, uint32 levelMax); + void UpdateGuildFor(ObjectGuid guid, uint32 guildId); + protected: bool _setMembersGroup(ObjectGuid guid, uint8 group); void _homebindIfInstance(Player* player); diff --git a/src/server/game/Guilds/Guild.cpp b/src/server/game/Guilds/Guild.cpp index 5d17e690320..e581a7a8c17 100644 --- a/src/server/game/Guilds/Guild.cpp +++ b/src/server/game/Guilds/Guild.cpp @@ -30,6 +30,8 @@ #include "ScriptMgr.h" #include "SocialMgr.h" #include "Opcodes.h" +#include "Group.h" +#include "Battleground.h" #define MAX_GUILD_BANK_TAB_TEXT_LEN 500 #define EMBLEM_PRICE 10 * GOLD @@ -1175,6 +1177,9 @@ Guild::Guild(): _todayExperience(0) { memset(&m_bankEventLog, 0, (GUILD_BANK_MAX_TABS + 1) * sizeof(LogHolder*)); + + for (uint8 i = 0; i < MAX_GUILD_CHALLENGE_TYPE; i++) + _currChallengeCount[i] = 0; } Guild::~Guild() @@ -1224,6 +1229,9 @@ bool Guild::Create(Player* pLeader, std::string const& name) _todayExperience = 0; _CreateLogHolders(); + for (uint8 i = 0; i < MAX_GUILD_CHALLENGE_TYPE; i++) + _currChallengeCount[i] = 0; + TC_LOG_DEBUG("guild", "GUILD: creating guild [%s] for leader %s (%u)", name.c_str(), pLeader->GetName().c_str(), m_leaderGuid.GetCounter()); @@ -2177,18 +2185,29 @@ void Guild::HandleDisband(WorldSession* session) void Guild::HandleGuildPartyRequest(WorldSession* session) { Player* player = session->GetPlayer(); - Group* group = player->GetGroup(); // Make sure player is a member of the guild and that he is in a group. - if (!IsMember(player->GetGUID()) || !group) + if (!IsMember(player->GetGUID())) return; + bool guildParty = false; + float xpMultiplier = 0.0f; + uint32 CurrGuildPartyMembers = 0, NeededGuildPartyMembers = 0; + + if (Group* group = player->GetGroup()) + { + guildParty = group->IsGuildGroupFor(player); + CurrGuildPartyMembers = group->GetMembersCountOfGuild(player->GetGuildId()); + NeededGuildPartyMembers = group->GetNeededMembersOfSameGuild((player->InArena() && player->GetBattleground()->isRated()) ? + player->GetBattleground()->GetArenaType() : 0, player->GetMap()); + } + WorldPacket data(SMSG_GUILD_PARTY_STATE_RESPONSE, 13); - data.WriteBit(player->GetMap()->GetOwnerGuildId(player->GetTeam()) == GetId()); // Is guild group + data.WriteBit(guildParty); // Is guild group data.FlushBits(); - data << float(0.f); // Guild XP multiplier - data << uint32(0); // Current guild members - data << uint32(0); // Needed guild members + data << float(xpMultiplier); // Guild XP multiplier + data << uint32(CurrGuildPartyMembers); // Current guild members + data << uint32(NeededGuildPartyMembers); // Needed guild members session->SendPacket(&data); TC_LOG_DEBUG("guild", "SMSG_GUILD_PARTY_STATE_RESPONSE [%s]", session->GetPlayerInfo().c_str()); @@ -2196,22 +2215,32 @@ void Guild::HandleGuildPartyRequest(WorldSession* session) void Guild::HandleGuildRequestChallengeUpdate(WorldSession* session) { - WorldPacket data(SMSG_GUILD_CHALLENGE_UPDATED, 4 * GUILD_CHALLENGES_TYPES * 5); + WorldPacket data(SMSG_GUILD_CHALLENGE_UPDATED, 80); - for (int i = 0; i < GUILD_CHALLENGES_TYPES; ++i) - data << uint32(GuildChallengeXPReward[i]); + data << uint32(0); + data << uint32(sWorld->getIntConfig(CONFIG_GUILD_CHALLENGE_DUNGEON_XP)); + data << uint32(sWorld->getIntConfig(CONFIG_GUILD_CHALLENGE_RAID_XP)); + data << uint32(sWorld->getIntConfig(CONFIG_GUILD_CHALLENGE_RATEDBG_XP)); - for (int i = 0; i < GUILD_CHALLENGES_TYPES; ++i) - data << uint32(GuildChallengeGoldReward[i]); + data << uint32(0); + data << uint32(sWorld->getIntConfig(CONFIG_GUILD_CHALLENGE_DUNGEON_GOLD) * 2); + data << uint32(sWorld->getIntConfig(CONFIG_GUILD_CHALLENGE_RAID_GOLD) * 2); + data << uint32(sWorld->getIntConfig(CONFIG_GUILD_CHALLENGE_RATEDBG_GOLD) * 2); - for (int i = 0; i < GUILD_CHALLENGES_TYPES; ++i) - data << uint32(GuildChallengesPerWeek[i]); + data << uint32(0); + data << uint32(sWorld->getIntConfig(CONFIG_GUILD_CHALLENGE_DUNGEON_NEEDED)); + data << uint32(sWorld->getIntConfig(CONFIG_GUILD_CHALLENGE_RAID_NEEDED)); + data << uint32(sWorld->getIntConfig(CONFIG_GUILD_CHALLENGE_RATEDBG_NEEDED)); - for (int i = 0; i < GUILD_CHALLENGES_TYPES; ++i) - data << uint32(GuildChallengeMaxLevelGoldReward[i]); + data << uint32(0); + data << uint32(sWorld->getIntConfig(CONFIG_GUILD_CHALLENGE_DUNGEON_GOLD)); + data << uint32(sWorld->getIntConfig(CONFIG_GUILD_CHALLENGE_RAID_GOLD)); + data << uint32(sWorld->getIntConfig(CONFIG_GUILD_CHALLENGE_RATEDBG_GOLD)); - for (int i = 0; i < GUILD_CHALLENGES_TYPES; ++i) - data << uint32(0); /// @todo current count + data << uint32(0); + data << uint32(_currChallengeCount[GUILD_CHALLENGE_TYPE_DUNGEON]); + data << uint32(_currChallengeCount[GUILD_CHALLENGE_TYPE_RAID]); + data << uint32(_currChallengeCount[GUILD_CHALLENGE_TYPE_RATED_BG]); session->SendPacket(&data); } @@ -2445,6 +2474,11 @@ bool Guild::LoadFromDB(Field* fields) for (uint8 i = 0; i < purchasedTabs; ++i) m_bankTabs[i] = new BankTab(m_id, i); + _currChallengeCount[GUILD_CHALLENGE_TYPE_DUNGEON] = uint8(fields[16].GetUInt32()); + _currChallengeCount[GUILD_CHALLENGE_TYPE_RAID] = uint8(fields[17].GetUInt32()); + _currChallengeCount[GUILD_CHALLENGE_TYPE_RATED_BG] = uint8(fields[18].GetUInt32()); + + _CreateLogHolders(); return true; } @@ -2810,6 +2844,11 @@ bool Guild::AddMember(SQLTransaction& trans, ObjectGuid guid, uint8 rankId) _BroadcastEvent(GE_JOINED, guid, name.c_str()); sGuildFinderMgr->RemoveAllMembershipRequestsFromPlayer(lowguid); + // Update GuildId in group + if (player) + if (Group* group = player->GetGroup()) + group->UpdateGuildFor(guid, m_id); + // Call scripts if member was succesfully added (and stored to database) sScriptMgr->OnGuildAddMember(this, player, rankId); @@ -2874,6 +2913,10 @@ void Guild::DeleteMember(SQLTransaction& trans, ObjectGuid guid, bool isDisbandi if (GuildPerkSpellsEntry const* entry = sGuildPerkSpellsStore.LookupEntry(i)) if (entry->Level <= GetLevel()) player->RemoveSpell(entry->SpellId, false, false); + + // Update GuildId in group + if (Group* group = player->GetGroup()) + group->UpdateGuildFor(guid, 0); } else sCharacterCache->UpdateCharacterGuildId(guid, 0); @@ -3609,7 +3652,74 @@ void Guild::SendGuildRanksUpdate(ObjectGuid setterGuid, ObjectGuid targetGuid, u targetGuid.ToString().c_str(), setterGuid.ToString().c_str(), rank); } -void Guild::GiveXP(uint32 xp, Player* source) +void Guild::CompleteChallenge(uint8 challengeType, Player* source) +{ + /* + source is used to complete guild level achievement (UpdateAchievementCriteria need a player) + */ + + uint32 countNeeded = 0; + uint32 gold = 0; + uint32 xp = 0; + + switch (challengeType) + { + case GUILD_CHALLENGE_TYPE_DUNGEON: + gold = sWorld->getIntConfig(CONFIG_GUILD_CHALLENGE_DUNGEON_GOLD); + xp = sWorld->getIntConfig(CONFIG_GUILD_CHALLENGE_DUNGEON_XP); + countNeeded = sWorld->getIntConfig(CONFIG_GUILD_CHALLENGE_DUNGEON_NEEDED); + break; + case GUILD_CHALLENGE_TYPE_RAID: + gold = sWorld->getIntConfig(CONFIG_GUILD_CHALLENGE_RAID_GOLD); + xp = sWorld->getIntConfig(CONFIG_GUILD_CHALLENGE_RAID_XP); + countNeeded = sWorld->getIntConfig(CONFIG_GUILD_CHALLENGE_RAID_NEEDED); + break; + case GUILD_CHALLENGE_TYPE_RATED_BG: + gold = sWorld->getIntConfig(CONFIG_GUILD_CHALLENGE_RATEDBG_GOLD); + xp = sWorld->getIntConfig(CONFIG_GUILD_CHALLENGE_RATEDBG_XP); + countNeeded = sWorld->getIntConfig(CONFIG_GUILD_CHALLENGE_RATEDBG_NEEDED); + break; + default: + return; + } + + if (_currChallengeCount[challengeType] >= countNeeded) + return; + + _currChallengeCount[challengeType] += 1; + + if (GetLevel() >= sWorld->getIntConfig(CONFIG_GUILD_MAX_LEVEL)) + gold *= 2; + + // Send notification + WorldPacket data(SMSG_GUILD_CHALLENGE_COMPLETED, 20); + data << uint32(challengeType); + data << gold; + data << uint32(_currChallengeCount[challengeType]); + data << xp; + data << countNeeded; + BroadcastPacket(&data); + + UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GUILD_CHALLENGE_TYPE, challengeType, 0, 0, NULL, source); + UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GUILD_CHALLENGE, 0, 0, 0, NULL, source); + + // Give Reward now + GiveXP(xp, source, true); + SaveToDB(); // Save xp + + SQLTransaction trans = CharacterDatabase.BeginTransaction(); + _ModifyBankMoney(trans, uint64(gold * 10000), true); + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GUILD_CHALLENGE); + stmt->setUInt32(0, _currChallengeCount[GUILD_CHALLENGE_TYPE_DUNGEON]); + stmt->setUInt32(1, _currChallengeCount[GUILD_CHALLENGE_TYPE_RAID]); + stmt->setUInt32(2, _currChallengeCount[GUILD_CHALLENGE_TYPE_RATED_BG]); + stmt->setUInt32(3, m_id); + trans->Append(stmt); + CharacterDatabase.CommitTransaction(trans); +} + +void Guild::GiveXP(uint32 xp, Player* source, bool rewardedByChallenge) { if (!sWorld->getBoolConfig(CONFIG_GUILD_LEVELING_ENABLED)) return; @@ -3622,12 +3732,16 @@ void Guild::GiveXP(uint32 xp, Player* source) if (GetLevel() < GUILD_EXPERIENCE_UNCAPPED_LEVEL) xp = std::min(xp, sWorld->getIntConfig(CONFIG_GUILD_DAILY_XP_CAP) - uint32(_todayExperience)); - WorldPacket data(SMSG_GUILD_XP_GAIN, 8); - data << uint64(xp); - source->GetSession()->SendPacket(&data); - _experience += xp; - _todayExperience += xp; + + if (!rewardedByChallenge) + { + _todayExperience += xp; + + WorldPacket data(SMSG_GUILD_XP_GAIN, 8); + data << uint64(xp); + source->GetSession()->SendPacket(&data); + } if (!xp) return; @@ -3663,6 +3777,10 @@ void Guild::GiveXP(uint32 xp, Player* source) ++oldLevel; } + + for (Members::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr) + if (Player* player = itr->second->FindPlayer()) + SendGuildXP(player->GetSession()); } void Guild::SendGuildXP(WorldSession* session /* = NULL */) const @@ -3691,6 +3809,17 @@ void Guild::SendGuildReputationWeeklyCap(WorldSession* session, uint32 reputatio void Guild::ResetTimes(bool weekly) { _todayExperience = 0; + + if (weekly) + { + for (uint8 i = 0; i < MAX_GUILD_CHALLENGE_TYPE; i++) + _currChallengeCount[i] = 0; + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GUILD_RESET_CHALLENGE); + stmt->setInt32(0, m_id); + CharacterDatabase.Execute(stmt); + } + for (Members::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr) { itr->second->ResetValues(weekly); diff --git a/src/server/game/Guilds/Guild.h b/src/server/game/Guilds/Guild.h index 624b5e5fa7b..28047ae0d31 100644 --- a/src/server/game/Guilds/Guild.h +++ b/src/server/game/Guilds/Guild.h @@ -269,12 +269,13 @@ struct GuildReward uint32 const MinNewsItemLevel[MAX_CONTENT] = { 61, 90, 200, 353 }; // Guild Challenge -#define GUILD_CHALLENGES_TYPES 4 - -const uint32 GuildChallengeGoldReward[GUILD_CHALLENGES_TYPES] = { 0, 250, 1000, 500 }; -const uint32 GuildChallengeMaxLevelGoldReward[GUILD_CHALLENGES_TYPES] = { 0, 125, 500, 250 }; -const uint32 GuildChallengeXPReward[GUILD_CHALLENGES_TYPES] = { 0, 300000, 3000000, 1500000 }; -const uint32 GuildChallengesPerWeek[GUILD_CHALLENGES_TYPES] = { 0, 7, 1, 3 }; +enum GuildChallengeTypes +{ + GUILD_CHALLENGE_TYPE_DUNGEON = 1, + GUILD_CHALLENGE_TYPE_RAID = 2, + GUILD_CHALLENGE_TYPE_RATED_BG = 3, + MAX_GUILD_CHALLENGE_TYPE, +}; // Emblem info class TC_GAME_API EmblemInfo @@ -882,10 +883,12 @@ public: // Guild leveling uint8 GetLevel() const { return _level; } - void GiveXP(uint32 xp, Player* source); + void GiveXP(uint32 xp, Player* source, bool rewardedByChallenge = false); uint64 GetExperience() const { return _experience; } uint64 GetTodayExperience() const { return _todayExperience; } + void CompleteChallenge(uint8 challengeType, Player* source); + void AddGuildNews(uint8 type, ObjectGuid guid, uint32 flags, uint32 value); EmblemInfo const& GetEmblemInfo() const { return m_emblemInfo; } @@ -920,6 +923,8 @@ protected: uint64 _experience; uint64 _todayExperience; + uint8 _currChallengeCount[MAX_GUILD_CHALLENGE_TYPE]; + private: inline uint8 _GetRanksSize() const { return uint8(m_ranks.size()); } inline const RankInfo* GetRankInfo(uint8 rankId) const { return rankId < _GetRanksSize() ? &m_ranks[rankId] : nullptr; } diff --git a/src/server/game/Guilds/GuildMgr.cpp b/src/server/game/Guilds/GuildMgr.cpp index 8f06119a8d9..ab994c6fd2a 100644 --- a/src/server/game/Guilds/GuildMgr.cpp +++ b/src/server/game/Guilds/GuildMgr.cpp @@ -128,7 +128,9 @@ void GuildMgr::LoadGuilds() // 0 1 2 3 4 5 6 QueryResult result = CharacterDatabase.Query("SELECT g.guildid, g.name, g.leaderguid, g.EmblemStyle, g.EmblemColor, g.BorderStyle, g.BorderColor, " // 7 8 9 10 11 12 13 14 15 - "g.BackgroundColor, g.info, g.motd, g.createdate, g.BankMoney, g.level, g.experience, g.todayExperience, COUNT(gbt.guildid) " + "g.BackgroundColor, g.info, g.motd, g.createdate, g.BankMoney, g.level, g.experience, g.todayExperience, COUNT(gbt.guildid), " + // 16 17 18 + "g.completedDungeonChallenges, g.completedRaidChallenges, g.completedRatedBattlegroundChallenges " "FROM guild g LEFT JOIN guild_bank_tab gbt ON g.guildid = gbt.guildid GROUP BY g.guildid ORDER BY g.guildid ASC"); if (!result) diff --git a/src/server/game/Handlers/GuildHandler.cpp b/src/server/game/Handlers/GuildHandler.cpp index dee85e9acf7..d5de8c86fa9 100644 --- a/src/server/game/Handlers/GuildHandler.cpp +++ b/src/server/game/Handlers/GuildHandler.cpp @@ -1021,59 +1021,3 @@ void WorldSession::HandleGuildRenameCallback(std::string newName, PreparedQueryR if(pGuild && hasRenamed) pGuild->SetName(newName); } -/* -void WorldSession::HandleGuildChallengeRequest(WorldPacket& recvPacket) -{ - uint8 counter = 4; - - if (Guild* pGuild = GetPlayer()->GetGuild()) - { - if (Guild::ChallengesMgr* challengesMgr = pGuild->GetChallengesMgr()) - { - // First check if it's time to reset the challenges. - time_t thisTime = time(NULL); - if (pGuild->GetChallengesMgr()->CompletedFirstChallenge(pGuild->GetId()) && pGuild->GetChallengesMgr()->GetFirstCompletedChallengeTime(pGuild->GetId()) + WEEK <= thisTime) - pGuild->GetChallengesMgr()->ResetWeeklyChallenges(); - - WorldPacket data(SMSG_GUILD_CHALLENGE_UPDATED, 5 * 4 * 4); - - //Guild Experience Reward block - - data << uint32(0); //in the block its always 1 - data << challengesMgr->GetXPRewardForType(CHALLENGE_TYPE_DUNGEON); //dungeon - data << challengesMgr->GetXPRewardForType(CHALLENGE_TYPE_RAID); //raid - data << challengesMgr->GetXPRewardForType(CHALLENGE_TYPE_RATEDBG); //rated BG - - //Gold Bonus block - data << uint32(0); //in the block its always 1 - data << challengesMgr->GetGoldBonusForType(CHALLENGE_TYPE_DUNGEON); //dungeon - data << challengesMgr->GetGoldBonusForType(CHALLENGE_TYPE_RAID); //raid - data << challengesMgr->GetGoldBonusForType(CHALLENGE_TYPE_RATEDBG); //rated BG - - //Total Count block - - data << uint32(0); //in the block its always 1 - data << challengesMgr->GetTotalCountFor(CHALLENGE_TYPE_DUNGEON); //dungeon - data << challengesMgr->GetTotalCountFor(CHALLENGE_TYPE_RAID); //raid - data << challengesMgr->GetTotalCountFor(CHALLENGE_TYPE_RATEDBG); //rated BG - - //Completion Gold Reward block - - data << uint32(0); //in the block its always 1 - data << challengesMgr->GetGoldRewardForType(CHALLENGE_TYPE_DUNGEON); //dungeon - data << challengesMgr->GetGoldRewardForType(CHALLENGE_TYPE_RAID); //raid - data << challengesMgr->GetGoldRewardForType(CHALLENGE_TYPE_RATEDBG); //rated BG - - //Current Count block - - data << uint32(0); //in the block its always 1 - data << challengesMgr->GetCurrentCountFor(CHALLENGE_TYPE_DUNGEON); //dungeon - data << challengesMgr->GetCurrentCountFor(CHALLENGE_TYPE_RAID); //raid - data << challengesMgr->GetCurrentCountFor(CHALLENGE_TYPE_RATEDBG); //rated BG - - SendPacket(&data); - } - return; - } -} -*/ diff --git a/src/server/game/Instances/InstanceScript.cpp b/src/server/game/Instances/InstanceScript.cpp index 15dee928089..081279e701e 100644 --- a/src/server/game/Instances/InstanceScript.cpp +++ b/src/server/game/Instances/InstanceScript.cpp @@ -29,6 +29,7 @@ #include "Pet.h" #include "WorldSession.h" #include "Opcodes.h" +#include "Guild.h" #include "ScriptReloadMgr.h" #include "ScriptMgr.h" @@ -654,6 +655,7 @@ void InstanceScript::UpdateEncounterState(EncounterCreditType type, uint32 credi return; uint32 dungeonId = 0; + uint32 encounterId = 0; for (DungeonEncounterList::const_iterator itr = encounters->begin(); itr != encounters->end(); ++itr) { @@ -661,6 +663,7 @@ void InstanceScript::UpdateEncounterState(EncounterCreditType type, uint32 credi if (encounter->creditType == type && encounter->creditEntry == creditEntry) { completedEncounters |= 1 << encounter->dbcEntry->encounterIndex; + encounterId = encounter->dbcEntry->id; if (encounter->lastEncounterDungeon) { if (instance->GetDifficulty() != sLFGDungeonStore.LookupEntry(encounter->lastEncounterDungeon)->difficulty) @@ -674,19 +677,48 @@ void InstanceScript::UpdateEncounterState(EncounterCreditType type, uint32 credi } } - if (dungeonId) + bool LFGRewarded = false; + std::vector guildList; + Map::PlayerList const& players = instance->GetPlayers(); + for (Map::PlayerList::const_iterator i = players.begin(); i != players.end(); ++i) { - Map::PlayerList const& players = instance->GetPlayers(); - for (Map::PlayerList::const_iterator i = players.begin(); i != players.end(); ++i) - { - if (Player* player = i->GetSource()) - if (Group* grp = player->GetGroup()) - if (grp->isLFGGroup()) + if (Player* player = i->GetSource()) + if (Group* grp = player->GetGroup()) + { + bool guildAlreadyUpdate = false; + for (std::vector::const_iterator guildItr = guildList.begin(); guildItr != guildList.end(); guildItr++) + if (*guildItr == player->GetGuildId()) + guildAlreadyUpdate = true; + + if (!guildAlreadyUpdate) + { + if (Guild* guild = player->GetGuild()) { - sLFGMgr->FinishDungeon(grp->GetGUID(), dungeonId, instance); - return; + if (grp->IsGuildGroupFor(player)) + { + if (LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(dungeonId)) + { + if (grp->MemberLevelIsInRange(dungeon->minlevel, dungeon->maxlevel)) + { + if (dungeonId) + guild->CompleteChallenge(instance->IsNonRaidDungeon() ? GUILD_CHALLENGE_TYPE_DUNGEON : GUILD_CHALLENGE_TYPE_RAID, player); + else if (instance->IsRaid()) + guild->CompleteChallenge(GUILD_CHALLENGE_TYPE_RAID, player); + } + } + + guild->AddGuildNews(GUILD_NEWS_DUNGEON_ENCOUNTER, player->GetGUID(), 0, encounterId); + guildList.push_back(player->GetGuildId()); + } } - } + } + + if (grp->isLFGGroup() && !LFGRewarded && dungeonId) + { + sLFGMgr->FinishDungeon(grp->GetGUID(), dungeonId, instance); + LFGRewarded = true; + } + } } } diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index b291011c2d4..9bd0902e183 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -271,7 +271,7 @@ void OpcodeTable::Initialize() DEFINE_OPCODE_HANDLER(CMSG_GUILD_PERMISSIONS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildPermissions ); DEFINE_OPCODE_HANDLER(CMSG_GUILD_PROMOTE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildPromoteOpcode ); DEFINE_OPCODE_HANDLER(CMSG_GUILD_QUERY, STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildQueryOpcode ); - DEFINE_OPCODE_HANDLER(CMSG_GUILD_QUERY_NEWS, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleGuildQueryNewsOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_GUILD_QUERY_NEWS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildQueryNewsOpcode ); DEFINE_OPCODE_HANDLER(CMSG_GUILD_QUERY_RANKS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildQueryRanksOpcode ); DEFINE_OPCODE_HANDLER(CMSG_GUILD_REMOVE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildRemoveOpcode ); DEFINE_OPCODE_HANDLER(CMSG_GUILD_REPLACE_GUILD_MASTER, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); @@ -853,7 +853,7 @@ void OpcodeTable::Initialize() DEFINE_OPCODE_HANDLER(SMSG_GUILD_BANK_LOG_QUERY_RESULT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); DEFINE_OPCODE_HANDLER(SMSG_GUILD_BANK_MONEY_WITHDRAWN, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); DEFINE_OPCODE_HANDLER(SMSG_GUILD_BANK_QUERY_TEXT_RESULT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); - DEFINE_OPCODE_HANDLER(SMSG_GUILD_CHALLENGE_COMPLETED, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GUILD_CHALLENGE_COMPLETED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); DEFINE_OPCODE_HANDLER(SMSG_GUILD_CHALLENGE_UPDATED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); DEFINE_OPCODE_HANDLER(SMSG_GUILD_CHANGE_NAME_RESULT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); DEFINE_OPCODE_HANDLER(SMSG_GUILD_COMMAND_RESULT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 7215f3842a4..493ffe9833d 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -1362,7 +1362,7 @@ void World::LoadConfigSettings(bool reload) // MySQL ping time interval m_int_configs[CONFIG_DB_PING_INTERVAL] = sConfigMgr->GetIntDefault("MaxPingTime", 30); - // Guild save interval + // Guild configs m_bool_configs[CONFIG_GUILD_LEVELING_ENABLED] = sConfigMgr->GetBoolDefault("Guild.LevelingEnabled", true); m_int_configs[CONFIG_GUILD_SAVE_INTERVAL] = sConfigMgr->GetIntDefault("Guild.SaveInterval", 15); m_int_configs[CONFIG_GUILD_MAX_LEVEL] = sConfigMgr->GetIntDefault("Guild.MaxLevel", 25); @@ -1370,6 +1370,15 @@ void World::LoadConfigSettings(bool reload) rate_values[RATE_XP_GUILD_MODIFIER] = sConfigMgr->GetFloatDefault("Guild.XPModifier", 0.25f); m_int_configs[CONFIG_GUILD_DAILY_XP_CAP] = sConfigMgr->GetIntDefault("Guild.DailyXPCap", 7807500); m_int_configs[CONFIG_GUILD_WEEKLY_REP_CAP] = sConfigMgr->GetIntDefault("Guild.WeeklyReputationCap", 4375); + m_int_configs[CONFIG_GUILD_CHALLENGE_DUNGEON_XP] = sConfigMgr->GetIntDefault("Guild.Challenge.DungeonXP", 300000); + m_int_configs[CONFIG_GUILD_CHALLENGE_DUNGEON_GOLD] = sConfigMgr->GetIntDefault("Guild.Challenge.DungeonGold", 125); + m_int_configs[CONFIG_GUILD_CHALLENGE_DUNGEON_NEEDED] = sConfigMgr->GetIntDefault("Guild.Challenge.DungeonsNedeed", 7); + m_int_configs[CONFIG_GUILD_CHALLENGE_RAID_XP] = sConfigMgr->GetIntDefault("Guild.Challenge.RaidXP", 3000000); + m_int_configs[CONFIG_GUILD_CHALLENGE_RAID_GOLD] = sConfigMgr->GetIntDefault("Guild.Challenge.RaidGold", 500); + m_int_configs[CONFIG_GUILD_CHALLENGE_RAID_NEEDED] = sConfigMgr->GetIntDefault("Guild.Challenge.RaidsNedeed", 1); + m_int_configs[CONFIG_GUILD_CHALLENGE_RATEDBG_XP] = sConfigMgr->GetIntDefault("Guild.Challenge.RatedBattlegroundXP", 1500000); + m_int_configs[CONFIG_GUILD_CHALLENGE_RATEDBG_GOLD] = sConfigMgr->GetIntDefault("Guild.Challenge.RatedBattlegroundGold", 250); + m_int_configs[CONFIG_GUILD_CHALLENGE_RATEDBG_NEEDED] = sConfigMgr->GetIntDefault("Guild.Challenge.RatedBattlegroundsNedeed", 3); // misc m_bool_configs[CONFIG_PDUMP_NO_PATHS] = sConfigMgr->GetBoolDefault("PlayerDump.DisallowPaths", true); diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h index 7749ff8a7c8..9d6eaf91123 100644 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -386,6 +386,15 @@ enum WorldIntConfigs CONFIG_GUILD_UNDELETABLE_LEVEL, CONFIG_GUILD_DAILY_XP_CAP, CONFIG_GUILD_WEEKLY_REP_CAP, + CONFIG_GUILD_CHALLENGE_DUNGEON_XP, + CONFIG_GUILD_CHALLENGE_DUNGEON_GOLD, + CONFIG_GUILD_CHALLENGE_DUNGEON_NEEDED, + CONFIG_GUILD_CHALLENGE_RAID_XP, + CONFIG_GUILD_CHALLENGE_RAID_GOLD, + CONFIG_GUILD_CHALLENGE_RAID_NEEDED, + CONFIG_GUILD_CHALLENGE_RATEDBG_XP, + CONFIG_GUILD_CHALLENGE_RATEDBG_GOLD, + CONFIG_GUILD_CHALLENGE_RATEDBG_NEEDED, CONFIG_PACKET_SPOOF_POLICY, CONFIG_PACKET_SPOOF_BANMODE, CONFIG_PACKET_SPOOF_BANDURATION, diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist index 691632aff92..5a6cdd3b2b0 100644 --- a/src/server/worldserver/worldserver.conf.dist +++ b/src/server/worldserver/worldserver.conf.dist @@ -3879,6 +3879,30 @@ Guild.DailyXPCap = 7807500 Guild.WeeklyReputationCap = 4375 +# +# Guild.Challenge +# Description: defines the required challenge completions and reward amount for completing guild challenges +# Default: 300000 - (DungeonXP) +# 125 - (DungeonGold) +# 7 - (DungeonsNeeded) +# 3000000 - (RaidXP) +# 125 - (RaidGold) +# 1 - (RaidsNeeded) +# 1500000 - (RatedBattlegroundXP) +# 250 - (RatedBattlegroundGold) +# 3 - (RatedBattlegroundsNedeed) +# + +Guild.Challenge.DungeonXP = 300000 +Guild.Challenge.DungeonGold = 125 +Guild.Challenge.DungeonsNedeed = 7 +Guild.Challenge.RaidXP = 3000000 +Guild.Challenge.RaidGold = 500 +Guild.Challenge.RaidsNedeed = 1 +Guild.Challenge.RatedBattlegroundXP = 1500000 +Guild.Challenge.RatedBattlegroundGold = 250 +Guild.Challenge.RatedBattlegroundsNedeed = 3 + # ###################################################################################################