diff --git a/sql/updates/characters/4.3.4/custom_2018_07_09_00_characters.sql b/sql/updates/characters/4.3.4/custom_2018_07_09_00_characters.sql new file mode 100644 index 0000000000..389a64acae --- /dev/null +++ b/sql/updates/characters/4.3.4/custom_2018_07_09_00_characters.sql @@ -0,0 +1,16 @@ +DROP TABLE IF EXISTS `guild_old_member`; +CREATE TABLE `guild_old_member` ( + `guid` int(10) unsigned NOT NULL, + `guildId` int(10) unsigned NOT NULL, + `weekReputation` int(10) unsigned NOT NULL, + `leaveDate` int(10) unsigned NOT NULL, + PRIMARY KEY (`guid`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +ALTER TABLE `guild_member` +ADD COLUMN `activity` int(10) unsigned NOT NULL DEFAULT '0' AFTER `offnote`, +ADD COLUMN `weekActivity` int(10) unsigned NOT NULL DEFAULT '0' AFTER `activity`, +ADD COLUMN `weekReputation` int(10) unsigned NOT NULL DEFAULT '0' AFTER `weekActivity`; + +ALTER TABLE `characters` +ADD COLUMN `achievementPoints` int(10) unsigned NOT NULL DEFAULT '0' AFTER `grantableLevels`; diff --git a/src/server/database/Database/Implementation/CharacterDatabase.cpp b/src/server/database/Database/Implementation/CharacterDatabase.cpp index f99bc60e1f..6e616b088b 100644 --- a/src/server/database/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/database/Database/Implementation/CharacterDatabase.cpp @@ -178,7 +178,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() // 0: string, 1: uint32 PrepareStatement(CHAR_UPD_GUILD_NAME, "UPDATE guild SET name = ? WHERE guildid = ?", CONNECTION_ASYNC); // 0: uint32, 1: uint32, 2: uint8, 4: string, 5: string - PrepareStatement(CHAR_INS_GUILD_MEMBER, "INSERT INTO guild_member (guildid, guid, `rank`, pnote, offnote) VALUES (?, ?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_GUILD_MEMBER, "INSERT INTO guild_member (guildid, guid, `rank`, pnote, offnote, activity, weekActivity, weekReputation) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_GUILD_MEMBER, "DELETE FROM guild_member WHERE guid = ?", CONNECTION_ASYNC); // 0: uint32 PrepareStatement(CHAR_DEL_GUILD_MEMBERS, "DELETE FROM guild_member WHERE guildid = ?", CONNECTION_ASYNC); // 0: uint32 // 0: uint32, 1: uint8, 3: string, 4: uint32, 5: uint32 @@ -208,6 +208,10 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_UPD_GUILD_MEMBER_PNOTE, "UPDATE guild_member SET pnote = ? WHERE guid = ?", CONNECTION_ASYNC); // 0: string, 1: uint32 PrepareStatement(CHAR_UPD_GUILD_MEMBER_OFFNOTE, "UPDATE guild_member SET offnote = ? WHERE guid = ?", CONNECTION_ASYNC); // 0: string, 1: uint32 PrepareStatement(CHAR_UPD_GUILD_MEMBER_RANK, "UPDATE guild_member SET `rank` = ? WHERE guid = ?", CONNECTION_ASYNC); // 0: uint8, 1: uint32 + PrepareStatement(CHAR_UPD_GUILD_MEMBER_ACTIVITY, "UPDATE guild_member SET activity = ?, weekActivity = ? WHERE guid = ?", CONNECTION_ASYNC); // 0: uint64, 1: uint64, 2: uint32 + PrepareStatement(CHAR_UPD_GUILD_MEMBER_WEEK_REPUTATION, "UPDATE guild_member SET weekReputation = ? WHERE guid = ?", CONNECTION_ASYNC); // 0: uint32, 1: uint32 + PrepareStatement(CHAR_RESET_GUILD_MEMBER_WEEK_ACTIVITY, "UPDATE guild_member SET weekActivity = 0 WHERE guid = ?", CONNECTION_ASYNC); // 0: uint32 + PrepareStatement(CHAR_RESET_GUILD_MEMBER_WEEK_REPUTATION, "UPDATE guild_member SET weekReputation = 0 WHERE guid = ?", CONNECTION_ASYNC); // 0: uint32 PrepareStatement(CHAR_UPD_GUILD_MOTD, "UPDATE guild SET motd = ? WHERE guildid = ?", CONNECTION_ASYNC); // 0: string, 1: uint32 PrepareStatement(CHAR_UPD_GUILD_INFO, "UPDATE guild SET info = ? WHERE guildid = ?", CONNECTION_ASYNC); // 0: string, 1: uint32 PrepareStatement(CHAR_UPD_GUILD_LEADER, "UPDATE guild SET leaderguid = ? WHERE guildid = ?", CONNECTION_ASYNC); // 0: uint32, 1: uint32 @@ -229,7 +233,12 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_DEL_GUILD_MEMBER_WITHDRAW, "TRUNCATE guild_member_withdraw", CONNECTION_ASYNC); // 0: uint32, 1: uint32, 2: uint32 - PrepareStatement(CHAR_SEL_CHAR_DATA_FOR_GUILD, "SELECT name, level, class, zone, account FROM characters WHERE guid = ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_CHAR_DATA_FOR_GUILD, "SELECT c.name, c.level, c.class, c.zone, c.account, c.achievementPoints, r.standing FROM characters c LEFT JOIN character_reputation r ON c.guid = r.guid AND r.faction = 1168 WHERE c.guid = ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_OLD_GUILD_DATA, "SELECT guildId, weekReputation FROM guild_old_member WHERE guid = ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_DEL_OLD_GUILD_DATA, "DELETE FROM guild_old_member WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_RESET_OLD_GUILD_WEEK_REPUTATION, "UPDATE guild_old_member SET weekReputation = 0", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_OLD_OLD_GUILD_MEMBER, "DELETE FROM guild_old_member WHERE leaveDate < ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_LEAVE_GUILD_DATA, "INSERT INTO guild_old_member (guid, guildId, weekReputation, leaveDate) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_GUILD_ACHIEVEMENT, "DELETE FROM guild_achievement WHERE guildId = ? AND achievement = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_GUILD_ACHIEVEMENT, "INSERT INTO guild_achievement (guildId, achievement, date, guids) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_GUILD_ACHIEVEMENT_CRITERIA, "DELETE FROM guild_achievement_progress WHERE guildId = ? AND criteria = ?", CONNECTION_ASYNC); @@ -380,14 +389,14 @@ void CharacterDatabaseConnection::DoPrepareStatements() "extra_flags, stable_slots, at_login, zone, " "death_expire_time, taxi_path, totalKills, " "todayKills, yesterdayKills, chosenTitle, watchedFaction, drunk, health, power1, power2, power3, " - "power4, power5, latency, talentGroupsCount, activeTalentGroup, exploredZones, equipmentCache, knownTitles, actionBars, grantableLevels) VALUES " - "(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", CONNECTION_ASYNC); + "power4, power5, latency, talentGroupsCount, activeTalentGroup, exploredZones, equipmentCache, knownTitles, actionBars, grantableLevels, achievementPoints) VALUES " + "(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_CHARACTER, "UPDATE characters SET name=?,race=?,class=?,gender=?,level=?,xp=?,money=?,skin=?,face=?,hairStyle=?,hairColor=?,facialStyle=?,bankSlots=?,restState=?,playerFlags=?," "map=?,instance_id=?,instance_mode_mask=?,position_x=?,position_y=?,position_z=?,orientation=?,trans_x=?,trans_y=?,trans_z=?,trans_o=?,transguid=?,taximask=?,cinematic=?,totaltime=?,leveltime=?,rest_bonus=?," "logout_time=?,is_logout_resting=?,resettalents_cost=?,resettalents_time=?,talentTree=?,extra_flags=?,stable_slots=?,at_login=?,zone=?,death_expire_time=?,taxi_path=?," "totalKills=?,todayKills=?,yesterdayKills=?,chosenTitle=?," "watchedFaction=?,drunk=?,health=?,power1=?,power2=?,power3=?,power4=?,power5=?,latency=?,talentGroupsCount=?,activeTalentGroup=?,exploredZones=?," - "equipmentCache=?,knownTitles=?,actionBars=?,grantableLevels=?,online=? WHERE guid=?", CONNECTION_ASYNC); + "equipmentCache=?,knownTitles=?,actionBars=?,grantableLevels=?,achievementPoints=?,online=? WHERE guid=?", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_ADD_AT_LOGIN_FLAG, "UPDATE characters SET at_login = at_login | ? WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_REM_AT_LOGIN_FLAG, "UPDATE characters set at_login = at_login & ~ ? WHERE guid = ?", CONNECTION_ASYNC); diff --git a/src/server/database/Database/Implementation/CharacterDatabase.h b/src/server/database/Database/Implementation/CharacterDatabase.h index 714d85e404..3414cdeb0e 100644 --- a/src/server/database/Database/Implementation/CharacterDatabase.h +++ b/src/server/database/Database/Implementation/CharacterDatabase.h @@ -182,6 +182,10 @@ enum CharacterDatabaseStatements : uint32 CHAR_UPD_GUILD_MEMBER_PNOTE, CHAR_UPD_GUILD_MEMBER_OFFNOTE, CHAR_UPD_GUILD_MEMBER_RANK, + CHAR_UPD_GUILD_MEMBER_ACTIVITY, + CHAR_UPD_GUILD_MEMBER_WEEK_REPUTATION, + CHAR_RESET_GUILD_MEMBER_WEEK_ACTIVITY, + CHAR_RESET_GUILD_MEMBER_WEEK_REPUTATION, CHAR_UPD_GUILD_MOTD, CHAR_UPD_GUILD_INFO, CHAR_UPD_GUILD_LEADER, @@ -196,6 +200,11 @@ enum CharacterDatabaseStatements : uint32 CHAR_INS_GUILD_MEMBER_WITHDRAW, CHAR_DEL_GUILD_MEMBER_WITHDRAW, CHAR_SEL_CHAR_DATA_FOR_GUILD, + CHAR_SEL_OLD_GUILD_DATA, + CHAR_INS_LEAVE_GUILD_DATA, + CHAR_RESET_OLD_GUILD_WEEK_REPUTATION, + CHAR_DEL_OLD_OLD_GUILD_MEMBER, + CHAR_DEL_OLD_GUILD_DATA, CHAR_DEL_GUILD_ACHIEVEMENT, CHAR_INS_GUILD_ACHIEVEMENT, CHAR_DEL_GUILD_ACHIEVEMENT_CRITERIA, diff --git a/src/server/game/Entities/Player/KillRewarder.cpp b/src/server/game/Entities/Player/KillRewarder.cpp index 706761a2b3..af8db3afe6 100644 --- a/src/server/game/Entities/Player/KillRewarder.cpp +++ b/src/server/game/Entities/Player/KillRewarder.cpp @@ -200,8 +200,14 @@ void KillRewarder::_RewardPlayer(Player* player, bool isDungeon) _groupRate * float(player->getLevel()) / _sumLevel : // Group rate depends on summary level. 1.0f; // Personal rate is 100%. if (_xp) + { // 4.2. Give XP. _RewardXP(player, rate); + // Give Guild XP. + if (player->GetGuild()) + if (_victim->ToCreature() && _victim->ToCreature()->IsDungeonBoss()) + _RewardGuildXP(player); + } if (!_isBattleGround) { // If killer is in dungeon then all members receive full reward at kill. @@ -249,6 +255,36 @@ void KillRewarder::_RewardGroup() } } +inline void KillRewarder::_RewardGuildXP(Player* player) +{ + Guild* guild = player->GetGuild(); + Group* group = player->GetGroup(); + if (!guild || !group) + return; + + if (!group->IsGuildGroupFor(player)) + return; + + float base = float(_xp) * sWorld->getRate(RATE_XP_BASEKILL_GUILD_MODIFIER); + + if (player->GetMap()->IsHeroic()) + { + if (player->GetMap()->IsNonRaidDungeon()) + base *= sWorld->getRate(RATE_XP_HEROIC_DUNGEON_GUILD_MODIFIER); + else if (player->GetMap()->IsRaid()) + base *= sWorld->getRate(RATE_XP_HEROIC_RAID_GUILD_MODIFIER); + } + + base *= group->GetGuildXpRateForPlayer(player); + if (!base) + return; + + guild->GiveXP(uint32(base), player); + + uint32 guildRep = std::max(uint32(1), uint32(base / sWorld->getIntConfig(CONFIG_GUILD_REPUTATION_QUEST_DIVIDER))); + guild->GiveReputation(guildRep, player); +} + void KillRewarder::Reward() { // 3. Reward killer (and group, if necessary). @@ -281,3 +317,4 @@ void KillRewarder::Reward() guild->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, victim->GetEntry(), 1, 0, victim, _killer); } } + diff --git a/src/server/game/Entities/Player/KillRewarder.h b/src/server/game/Entities/Player/KillRewarder.h index 878a5c9250..f6b6a45475 100644 --- a/src/server/game/Entities/Player/KillRewarder.h +++ b/src/server/game/Entities/Player/KillRewarder.h @@ -41,6 +41,7 @@ private: void _RewardKillCredit(Player* player); void _RewardPlayer(Player* player, bool isDungeon); void _RewardGroup(); + void _RewardGuildXP(Player* player); Player* _killer; Unit* _victim; diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 35994c8fb4..fd56635406 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -6893,6 +6893,10 @@ bool Player::RewardHonor(Unit* victim, uint32 groupsize, int32 honor, bool pvpto // add honor points ModifyCurrency(CURRENCY_TYPE_HONOR_POINTS, int32(honor)); + // Add guild XP + if (Guild *guild = GetGuild()) + guild->GiveXP(uint32(float(honor) * sWorld->getRate(RATE_XP_HONOR_EARNED_GUILD_MODIFIER)), this); + if (InBattleground() && honor > 0) { if (Battleground* bg = GetBattleground()) @@ -15290,8 +15294,13 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver, else moneyRew = int32(quest->GetRewMoneyMaxLevel() * sWorld->getRate(RATE_DROP_MONEY)); - if (Guild* guild = sGuildMgr->GetGuildById(GetGuildId())) - guild->GiveXP(uint32(quest->XPValue(this) * sWorld->getRate(RATE_XP_QUEST) * sWorld->getRate(RATE_XP_GUILD_MODIFIER)), this); + if (Guild* guild = GetGuild()) + { + uint32 _xp = quest->XPValue(this); + uint32 guildRep = std::max(uint32(1), uint32(_xp / 450)); + guild->GiveXP(uint32(_xp * sWorld->getRate(RATE_XP_QUEST) * sWorld->getRate(RATE_XP_QUEST_GUILD_MODIFIER)), this); + guild->GiveReputation(guildRep, this); + } // Give player extra money if GetRewOrReqMoney > 0 and get ReqMoney if negative // Do not reward the default reward money for max level dungeon quests @@ -19796,6 +19805,7 @@ void Player::SaveToDB(bool create /*=false*/) stmt->setString(index++, ss.str()); stmt->setUInt8(index++, GetByteValue(PLAYER_FIELD_BYTES, PLAYER_FIELD_BYTES_OFFSET_ACTION_BAR_TOGGLES)); stmt->setUInt32(index++, m_grantableLevels); + stmt->setUInt32(index++, GetAchievementPoints()); } else { @@ -19931,6 +19941,7 @@ void Player::SaveToDB(bool create /*=false*/) stmt->setString(index++, ss.str()); stmt->setUInt8(index++, GetByteValue(PLAYER_FIELD_BYTES, PLAYER_FIELD_BYTES_OFFSET_ACTION_BAR_TOGGLES)); stmt->setUInt32(index++, m_grantableLevels); + stmt->setUInt32(index++, GetAchievementPoints()); stmt->setUInt8(index++, IsInWorld() && !GetSession()->PlayerLogout() ? 1 : 0); // Index diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 3f4a62d181..a2178f71f2 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -89,6 +89,7 @@ typedef std::deque PlayerMails; #define PLAYER_MAX_SKILLS 128 #define PLAYER_MAX_DAILY_QUESTS 25 #define PLAYER_EXPLORED_ZONES_SIZE 156 +#define PLAYER_GUILD_REPUTATION 1168 // Note: SPELLMOD_* values is aura types in fact enum SpellModType : uint8 diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp index 37af43044b..3fdbf79c3c 100644 --- a/src/server/game/Groups/Group.cpp +++ b/src/server/game/Groups/Group.cpp @@ -1943,6 +1943,36 @@ uint32 Group::GetNeededMembersOfSameGuild(uint8 arenaType, Map const *map) return 0; } +float Group::GetGuildXpRateForPlayer(Player* player) +{ + if (!IsMember(player->GetGUID())) + return 0.0f; + + if (!player->GetGuildId()) + return 0.0f; + + if (!player->GetMap()->IsDungeon() && + !(player->InArena() && player->GetBattleground()->isRated())) + return 0.0f; + + if (player->GetMap()->IsNonRaidDungeon()) + { + switch (GetMembersCountOfGuild(player->GetGuildId())) + { + case 3: + return 0.5f; + case 4: + return 1.0f; + case 5: + return 1.25f; + default: + return 0.0f; + } + } + + return 1.0f; +} + void Group::UpdateGuildFor(ObjectGuid guid, uint32 guildId) { for (member_witerator itr = m_memberSlots.begin(); itr != m_memberSlots.end(); ++itr) diff --git a/src/server/game/Groups/Group.h b/src/server/game/Groups/Group.h index 8d36f23c0e..9cabc72b83 100644 --- a/src/server/game/Groups/Group.h +++ b/src/server/game/Groups/Group.h @@ -361,6 +361,7 @@ class TC_GAME_API Group uint32 GetMembersCountOfGuild(uint32 guildId); uint32 GetNeededMembersOfSameGuild(uint8 arenaType, Map const* map); bool MemberLevelIsInRange(uint32 levelMin, uint32 levelMax); + float GetGuildXpRateForPlayer(Player* player); void UpdateGuildFor(ObjectGuid guid, uint32 guildId); protected: diff --git a/src/server/game/Guilds/Guild.cpp b/src/server/game/Guilds/Guild.cpp index a74a28dbf2..1923b9f910 100644 --- a/src/server/game/Guilds/Guild.cpp +++ b/src/server/game/Guilds/Guild.cpp @@ -40,6 +40,7 @@ #include "WorldSession.h" #include "Group.h" #include "Battleground.h" +#include "ReputationMgr.h" #define MAX_GUILD_BANK_TAB_TEXT_LEN 500 #define EMBLEM_PRICE 10 * GOLD @@ -682,15 +683,17 @@ void Guild::Member::SetStats(Player* player) m_zoneId = player->GetZoneId(); m_accountId = player->GetSession()->GetAccountId(); m_achievementPoints = player->GetAchievementPoints(); + m_totalReputation = player->GetReputation(PLAYER_GUILD_REPUTATION); } -void Guild::Member::SetStats(std::string const& name, uint8 level, uint8 _class, uint32 zoneId, uint32 accountId, uint32 reputation) +void Guild::Member::SetStats(std::string const& name, uint8 level, uint8 _class, uint32 zoneId, uint32 accountId, uint32 achievementPoints, uint32 reputation) { m_name = name; m_level = level; m_class = _class; m_zoneId = zoneId; m_accountId = accountId; + m_achievementPoints = achievementPoints; m_totalReputation = reputation; } @@ -734,6 +737,18 @@ void Guild::Member::ChangeRank(SQLTransaction& trans, uint8 newRank) CharacterDatabase.ExecuteOrAppend(trans, stmt); } +void Guild::Member::AddActivity(uint64 activity) +{ + m_totalActivity += activity; + m_weekActivity += activity; + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GUILD_MEMBER_ACTIVITY); + stmt->setUInt64(0, m_totalActivity); + stmt->setUInt64(1, m_weekActivity); + stmt->setUInt32(2, m_guid.GetCounter()); + CharacterDatabase.Execute(stmt); +} + void Guild::Member::SaveToDB(SQLTransaction& trans) const { PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GUILD_MEMBER); @@ -742,6 +757,9 @@ void Guild::Member::SaveToDB(SQLTransaction& trans) const stmt->setUInt8 (2, m_rankId); stmt->setString(3, m_publicNote); stmt->setString(4, m_officerNote); + stmt->setUInt64(5, m_totalActivity); + stmt->setUInt64(6, m_weekActivity); + stmt->setUInt32(7, m_weekReputation); CharacterDatabase.ExecuteOrAppend(trans, stmt); } @@ -761,11 +779,12 @@ bool Guild::Member::LoadFromDB(Field* fields) fields[16].GetUInt8(), // characters.class fields[17].GetUInt16(), // characters.zone fields[18].GetUInt32(), // characters.account - 0); + fields[22].GetUInt32(), // characters.achievementPoint + fields[23].GetUInt32()); m_logoutTime = fields[19].GetUInt32(); // characters.logout_time - m_totalActivity = 0; - m_weekActivity = 0; - m_weekReputation = 0; + m_totalActivity = fields[20].GetUInt64(); + m_weekActivity = fields[21].GetUInt64(); + m_weekReputation = fields[24].GetUInt32(); if (!CheckStats()) return false; @@ -831,10 +850,40 @@ void Guild::Member::ResetValues(bool weekly /* = false*/) m_bankWithdraw[tabId] = 0; if (weekly) - { - m_weekActivity = 0; - m_weekReputation = 0; - } + ResetWeekActivityAndReputation(); +} + +void Guild::Member::AddReputation(uint32 rep, Player *player) +{ + rep = std::min(rep, sWorld->getIntConfig(CONFIG_GUILD_WEEKLY_REP_CAP) - m_weekReputation); + + player->GetReputationMgr().ModifyReputation(sFactionStore.LookupEntry(PLAYER_GUILD_REPUTATION), rep); + + m_weekReputation += rep; + m_totalReputation = player->GetReputation(PLAYER_GUILD_REPUTATION); + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GUILD_MEMBER_WEEK_REPUTATION); + stmt->setUInt32(0, m_weekReputation); + stmt->setUInt32(1, m_guid.GetCounter()); + CharacterDatabase.Execute(stmt); +} + +void Guild::Member::ResetWeekActivityAndReputation() +{ + m_weekActivity = 0; + m_weekReputation = 0; + + SQLTransaction trans = CharacterDatabase.BeginTransaction(); + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_RESET_GUILD_MEMBER_WEEK_ACTIVITY); + stmt->setUInt32(0, m_guid.GetCounter()); + trans->Append(stmt); + + PreparedStatement* stmt2 = CharacterDatabase.GetPreparedStatement(CHAR_RESET_GUILD_MEMBER_WEEK_REPUTATION); + stmt2->setUInt32(0, m_guid.GetCounter()); + trans->Append(stmt2); + + CharacterDatabase.CommitTransaction(trans); } // Get amount of money/slots left for today. @@ -2256,6 +2305,7 @@ void Guild::HandleGuildPartyRequest(WorldSession* session) if (Group* group = player->GetGroup()) { guildParty = group->IsGuildGroupFor(player); + xpMultiplier = group->GetGuildXpRateForPlayer(player); CurrGuildPartyMembers = group->GetMembersCountOfGuild(player->GetGuildId()); NeededGuildPartyMembers = group->GetNeededMembersOfSameGuild((player->InArena() && player->GetBattleground()->isRated()) ? player->GetBattleground()->GetArenaType() : 0, player->GetMap()); @@ -2869,8 +2919,27 @@ bool Guild::AddMember(SQLTransaction& trans, ObjectGuid guid, uint8 rankId) Member* member = new Member(m_id, guid, rankId); std::string name; + + /* Check if player can keep his guild reputation */ + bool keepGuildReputation = false; + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_OLD_GUILD_DATA); + stmt->setUInt32(0, lowguid); + if (PreparedQueryResult result = CharacterDatabase.Query(stmt)) + { + Field* fields = result->Fetch(); + if (fields[0].GetUInt32() == m_id) // old player guild was this guild + { + // Set the Week cap + member->SetWeekReputation(fields[1].GetUInt32()); + keepGuildReputation = true; + } + } + if (player) { + if (!keepGuildReputation || !player->GetReputation(PLAYER_GUILD_REPUTATION)) + player->SetReputation(PLAYER_GUILD_REPUTATION, 0); + m_members[lowguid] = member; player->SetInGuild(m_id); player->SetGuildIdInvited(0); @@ -2885,9 +2954,9 @@ bool Guild::AddMember(SQLTransaction& trans, ObjectGuid guid, uint8 rankId) bool ok = false; // Player must exist - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_DATA_FOR_GUILD); - stmt->setUInt32(0, lowguid); - if (PreparedQueryResult result = CharacterDatabase.Query(stmt)) + PreparedStatement* stmt2 = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_DATA_FOR_GUILD); + stmt2->setUInt32(0, lowguid); + if (PreparedQueryResult result = CharacterDatabase.Query(stmt2)) { Field* fields = result->Fetch(); name = fields[0].GetString(); @@ -2897,7 +2966,8 @@ bool Guild::AddMember(SQLTransaction& trans, ObjectGuid guid, uint8 rankId) fields[2].GetUInt8(), fields[3].GetUInt16(), fields[4].GetUInt32(), - 0); + fields[5].GetUInt32(), + keepGuildReputation ? fields[6].GetUInt32() : 0); ok = member->CheckStats(); } @@ -2907,10 +2977,26 @@ bool Guild::AddMember(SQLTransaction& trans, ObjectGuid guid, uint8 rankId) delete member; return false; } + + // Remove guild reputation + if (!keepGuildReputation) + { + stmt2 = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_REP_FACTION_CHANGE); + stmt2->setUInt16(0, uint16(PLAYER_GUILD_REPUTATION)); + stmt2->setInt32(1, 0); + stmt2->setUInt16(2, uint16(PLAYER_GUILD_REPUTATION)); + stmt2->setUInt32(3, lowguid); + CharacterDatabase.Execute(stmt2); + } + m_members[lowguid] = member; sCharacterCache->UpdateCharacterGuildId(guid, GetId()); } + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_OLD_GUILD_DATA); + stmt->setUInt32(0, lowguid); + CharacterDatabase.Execute(stmt); + member->SaveToDB(trans); _UpdateAccountsNumber(); @@ -2973,7 +3059,18 @@ void Guild::DeleteMember(SQLTransaction& trans, ObjectGuid guid, bool isDisbandi sScriptMgr->OnGuildRemoveMember(this, player, isDisbanding, isKicked); if (Member* member = GetMember(guid)) + { + if (!isDisbanding) + { + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_LEAVE_GUILD_DATA); + stmt->setUInt32(0, lowguid); + stmt->setUInt32(1, m_id); + stmt->setUInt32(2, member->GetWeekReputation()); + stmt->setUInt64(3, uint32(::time(nullptr))); + CharacterDatabase.Execute(stmt); + } delete member; + } m_members.erase(lowguid); // If player not online data in data field will be loaded from guild tabs no need to update it !! @@ -3793,25 +3890,32 @@ void Guild::CompleteChallenge(uint8 challengeType, Player* source) CharacterDatabase.CommitTransaction(trans); } +void Guild::GiveReputation(uint32 rep, Player* source) +{ + if (Member* member = GetMember(source->GetGUID())) + { + member->AddReputation(rep, source); + SendGuildReputationWeeklyCap(source->GetSession(), member->GetWeekReputation()); + } +} + void Guild::GiveXP(uint32 xp, Player* source, bool rewardedByChallenge) { if (!sWorld->getBoolConfig(CONFIG_GUILD_LEVELING_ENABLED)) return; - /// @todo: Award reputation and count activity for player - if (GetLevel() >= sWorld->getIntConfig(CONFIG_GUILD_MAX_LEVEL)) xp = 0; // SMSG_GUILD_XP_GAIN is always sent, even for no gains if (GetLevel() < GUILD_EXPERIENCE_UNCAPPED_LEVEL) xp = std::min(xp, sWorld->getIntConfig(CONFIG_GUILD_DAILY_XP_CAP) - uint32(_todayExperience)); + _experience += xp; + WorldPacket data(SMSG_GUILD_XP_GAIN, 8); data << uint64(xp); source->SendDirectMessage(&data); - _experience += xp; - if (!rewardedByChallenge) { _todayExperience += xp; @@ -3821,6 +3925,9 @@ void Guild::GiveXP(uint32 xp, Player* source, bool rewardedByChallenge) source->GetSession()->SendPacket(&data); } + if (Member* member = GetMember(source->GetGUID())) + member->AddActivity(xp); + if (!xp) return; @@ -3863,13 +3970,13 @@ void Guild::GiveXP(uint32 xp, Player* source, bool rewardedByChallenge) void Guild::SendGuildXP(WorldSession* session /* = nullptr */) const { - //Member const* member = GetMember(session->GetGUID().GetCounter()); + Member const* member = GetMember(session->GetPlayer()->GetGUID()); WorldPacket data(SMSG_GUILD_XP, 40); - data << uint64(/*member ? member->GetTotalActivity() :*/ 0); + data << uint64(member ? member->GetTotalActivity() : 0); data << uint64(sGuildMgr->GetXPForGuildLevel(GetLevel()) - GetExperience()); // XP missing for next level data << uint64(GetTodayExperience()); - data << uint64(/*member ? member->GetWeeklyActivity() :*/ 0); + data << uint64(member ? member->GetWeekActivity() : 0); data << uint64(GetExperience()); session->SendPacket(&data); } @@ -3903,7 +4010,7 @@ void Guild::ResetTimes(bool weekly) itr->second->ResetValues(weekly); if (Player* player = itr->second->FindPlayer()) { - //SendGuildXP(player->GetSession()); + SendGuildXP(player->GetSession()); WorldPacket data(SMSG_GUILD_MEMBER_DAILY_RESET, 0); // tells the client to request bank withdrawal limit player->SendDirectMessage(&data); } diff --git a/src/server/game/Guilds/Guild.h b/src/server/game/Guilds/Guild.h index 1b45e367fe..396e5e5e58 100644 --- a/src/server/game/Guilds/Guild.h +++ b/src/server/game/Guilds/Guild.h @@ -343,7 +343,7 @@ private: Member(ObjectGuid::LowType guildId, ObjectGuid guid, uint8 rankId); void SetStats(Player* player); - void SetStats(std::string const& name, uint8 level, uint8 _class, uint32 zoneId, uint32 accountId, uint32 reputation); + void SetStats(std::string const& name, uint8 level, uint8 _class, uint32 zoneId, uint32 accountId, uint32 achievementPoints, uint32 reputation); bool CheckStats() const; void SetPublicNote(std::string const& publicNote); @@ -351,6 +351,9 @@ private: void SetZoneId(uint32 id) { m_zoneId = id; } void SetAchievementPoints(uint32 val) { m_achievementPoints = val; } void SetLevel(uint8 var) { m_level = var; } + void AddActivity(uint64 activity); + void SetWeekReputation(uint32 reputation) { m_weekReputation = reputation; } + void AddReputation(uint32 rep, Player *player); void AddFlag(uint8 var) { m_flags |= var; } void RemFlag(uint8 var) { m_flags &= ~var; } @@ -392,6 +395,7 @@ private: void UpdateBankWithdrawValue(SQLTransaction& trans, uint8 tabId, uint32 amount); int32 GetBankWithdrawValue(uint8 tabId) const; void ResetValues(bool weekly = false); + void ResetWeekActivityAndReputation(); Player* FindPlayer() const; Player* FindConnectedPlayer() const; @@ -854,6 +858,7 @@ public: // Guild leveling uint8 GetLevel() const { return _level; } void GiveXP(uint32 xp, Player* source, bool rewardedByChallenge = false); + void GiveReputation(uint32 rep, Player* source); uint64 GetExperience() const { return _experience; } uint64 GetTodayExperience() const { return _todayExperience; } @@ -867,6 +872,12 @@ public: bool HasAchieved(uint32 achievementId) const; void UpdateAchievementCriteria(AchievementCriteriaTypes type, uint64 miscValue1, uint64 miscValue2, uint64 miscValue3, Unit* unit, Player* player); + inline void SetAchievementPointsFor(ObjectGuid guid, uint32 achievementPoint) + { + if (Member* member = GetMember(guid)) + member->SetAchievementPoints(achievementPoint); + } + protected: ObjectGuid::LowType m_id; std::string m_name; diff --git a/src/server/game/Guilds/GuildMgr.cpp b/src/server/game/Guilds/GuildMgr.cpp index 3a4d5dfb54..faa72db5d0 100644 --- a/src/server/game/Guilds/GuildMgr.cpp +++ b/src/server/game/Guilds/GuildMgr.cpp @@ -212,10 +212,13 @@ void GuildMgr::LoadGuilds() // 0 1 2 3 4 5 6 7 8 9 10 QueryResult result = CharacterDatabase.Query("SELECT gm.guildid, gm.guid, `rank`, pnote, offnote, w.tab0, w.tab1, w.tab2, w.tab3, w.tab4, w.tab5, " - // 11 12 13 14 15 16 17 18 19 - "w.tab6, w.tab7, w.money, c.name, c.level, c.class, c.zone, c.account, c.logout_time " + // 11 12 13 14 15 16 17 18 19 20 + "w.tab6, w.tab7, w.money, c.name, c.level, c.class, c.zone, c.account, c.logout_time, gm.activity, " + // 21 22 23 24 + "gm.weekActivity, c.achievementPoints, r.standing, gm.weekReputation " "FROM guild_member gm " "LEFT JOIN guild_member_withdraw w ON gm.guid = w.guid " + "LEFT JOIN character_reputation r ON gm.guid = r.guid AND r.faction = 1168 " "LEFT JOIN characters c ON c.guid = gm.guid ORDER BY gm.guildid ASC"); if (!result) @@ -582,6 +585,16 @@ void GuildMgr::ResetTimes(bool week) CharacterDatabase.Execute(CharacterDatabase.GetPreparedStatement(CHAR_UPD_GUILD_RESET_TODAY_EXPERIENCE)); CharacterDatabase.Execute(CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_MEMBER_WITHDRAW)); + // Delete too old old guild member + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_OLD_OLD_GUILD_MEMBER); + stmt->setUInt32(0, uint32(time(nullptr) - time_t(30 * DAY))); + CharacterDatabase.Execute(stmt); + + // Reset week reputation for old guild member + if (week) + CharacterDatabase.Execute(CharacterDatabase.GetPreparedStatement(CHAR_RESET_OLD_GUILD_WEEK_REPUTATION)); + + for (GuildContainer::const_iterator itr = GuildStore.begin(); itr != GuildStore.end(); ++itr) if (Guild* guild = itr->second) guild->ResetTimes(week); diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 26bc23533a..15367a2376 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -1369,7 +1369,13 @@ void World::LoadConfigSettings(bool reload) m_int_configs[CONFIG_GUILD_SAVE_INTERVAL] = sConfigMgr->GetIntDefault("Guild.SaveInterval", 15); m_int_configs[CONFIG_GUILD_MAX_LEVEL] = sConfigMgr->GetIntDefault("Guild.MaxLevel", 25); m_int_configs[CONFIG_GUILD_UNDELETABLE_LEVEL] = sConfigMgr->GetIntDefault("Guild.UndeletableLevel", 4); - rate_values[RATE_XP_GUILD_MODIFIER] = sConfigMgr->GetFloatDefault("Guild.XPModifier", 0.25f); + rate_values[RATE_XP_QUEST_GUILD_MODIFIER] = sConfigMgr->GetFloatDefault("Guild.XPQuestModifier", 0.25f); + rate_values[RATE_XP_BASEKILL_GUILD_MODIFIER] = sConfigMgr->GetFloatDefault("Guild.XPBaseKillModifier", 4.0f); + rate_values[RATE_XP_HEROIC_DUNGEON_GUILD_MODIFIER] = sConfigMgr->GetFloatDefault("Guild.XPHeroicDungeonModifier", 1.25f); + rate_values[RATE_XP_HEROIC_RAID_GUILD_MODIFIER] = sConfigMgr->GetFloatDefault("Guild.XPHeroicRaidModifier", 1.0f); + rate_values[RATE_XP_HONOR_EARNED_GUILD_MODIFIER] = sConfigMgr->GetFloatDefault("Guild.XPHonorEarnedModifier", 10.0f); + m_int_configs[CONFIG_GUILD_XP_REWARD_ARENA] = sConfigMgr->GetIntDefault("Guild.XPRewardInArena", 138800); + m_int_configs[CONFIG_GUILD_REPUTATION_QUEST_DIVIDER] = sConfigMgr->GetIntDefault("Guild.ReputationQuestDivider", 450); 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); diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h index 33be6b9b53..b5c8600a58 100644 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -384,6 +384,8 @@ enum WorldIntConfigs CONFIG_GUILD_UNDELETABLE_LEVEL, CONFIG_GUILD_DAILY_XP_CAP, CONFIG_GUILD_WEEKLY_REP_CAP, + CONFIG_GUILD_XP_REWARD_ARENA, + CONFIG_GUILD_REPUTATION_QUEST_DIVIDER, CONFIG_GUILD_CHALLENGE_DUNGEON_XP, CONFIG_GUILD_CHALLENGE_DUNGEON_GOLD, CONFIG_GUILD_CHALLENGE_DUNGEON_NEEDED, @@ -453,7 +455,11 @@ enum Rates RATE_XP_KILL, RATE_XP_BG_KILL, RATE_XP_QUEST, - RATE_XP_GUILD_MODIFIER, + RATE_XP_QUEST_GUILD_MODIFIER, + RATE_XP_BASEKILL_GUILD_MODIFIER, + RATE_XP_HEROIC_DUNGEON_GUILD_MODIFIER, + RATE_XP_HEROIC_RAID_GUILD_MODIFIER, + RATE_XP_HONOR_EARNED_GUILD_MODIFIER, RATE_XP_EXPLORE, RATE_REPAIRCOST, RATE_REPUTATION_GAIN, diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist index 29cd484428..639f28694f 100644 --- a/src/server/worldserver/worldserver.conf.dist +++ b/src/server/worldserver/worldserver.conf.dist @@ -3854,12 +3854,12 @@ Guild.MaxLevel = 25 Guild.UndeletableLevel = 4 # -# Guild.XPModifier +# Guild.XPQuestModifier # Description: Multiplier for guild experience gained from quests # Default: 0.25 # -Guild.XPModifier = 0.25 +Guild.XPQuestModifier = 0.25 # # Guild.DailyXPCap @@ -3869,6 +3869,54 @@ Guild.XPModifier = 0.25 Guild.DailyXPCap = 7807500 +# +# Guild.XPBaseKillModifier +# Description: Multiplier for guild experience gained from killing dungeon bosses +# Default: 0.25 +# + +Guild.XPBaseKillModifier = 4.0 + +# +# Guild.XPHeroicDungeonModifier +# Description: Multiplier for guild additional experience gained from killing dungeon bosses on heroic difficulty +# Default: 1.25 +# + +Guild.XPHeroicDungeonModifier = 1.25 + +# +# Guild.XPHeroicRaidModifier +# Description: Multiplier for guild additional experience gained from killing raid bosses on heroic difficulty +# Default: 1.0 +# + +Guild.XPHeroicRaidModifier = 1.0 + +# +# Guild.XPHonorEarnedModifier +# Description: Multiplier for guild experience gained from winning a battleground +# Default: 10.0 +# + +Guild.XPHonorEarnedModifier = 10.0 + +# +# Guild.XPRewardInArena +# Description: Amount of guild experiences gained from winning a arena match +# Default: 138800 +# + +Guild.XPRewardInArena = 138800 + +# +# Guild.ReputationQuestDivider +# Description: Devider for rewarded quest experience to calculate guild experience gained from rewarding quests +# Default: 450 +# + +Guild.ReputationQuestDivider = 450 + # # Guild.WeeklyReputationCap # Description: Maximum guild reputation a player can earn every week