aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsilinoron <none@none>2010-08-17 19:18:09 -0700
committersilinoron <none@none>2010-08-17 19:18:09 -0700
commitd6fe4b23e94f2d44d4b5161260e29aa56184e4ca (patch)
treec1b2bb0e96d4b439f84b916c74db3ebd9c751b07
parent8c4c5aef8bbb1c985ffac68535f9d1050ed22d6f (diff)
Add support for recruit-a-friend XP and reputation multipliers.
More research needs to be done to implement summoning and granting levels. --HG-- branch : trunk
-rw-r--r--sql/base/auth_database.sql1
-rw-r--r--sql/updates/9444_auth_account.sql1
-rw-r--r--src/server/game/Entities/Player/Player.cpp138
-rw-r--r--src/server/game/Entities/Player/Player.h7
-rw-r--r--src/server/game/Server/WorldSession.cpp8
-rw-r--r--src/server/game/Server/WorldSession.h5
-rw-r--r--src/server/game/Server/WorldSocket.cpp7
-rw-r--r--src/server/game/World/World.cpp19
-rw-r--r--src/server/game/World/World.h4
-rw-r--r--src/server/worldserver/worldserver.conf.dist24
10 files changed, 169 insertions, 45 deletions
diff --git a/sql/base/auth_database.sql b/sql/base/auth_database.sql
index 459b3fa1468..a0fc7f2f6b5 100644
--- a/sql/base/auth_database.sql
+++ b/sql/base/auth_database.sql
@@ -63,6 +63,7 @@ CREATE TABLE `account` (
`expansion` tinyint(3) unsigned NOT NULL default '2',
`mutetime` bigint(40) unsigned NOT NULL default '0',
`locale` tinyint(3) unsigned NOT NULL default '0',
+ `recruiter` int(11) NOT NULL default '0',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_username` (`username`)
) ENGINE=MyISAM AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci ROW_FORMAT=DYNAMIC COMMENT='Account System';
diff --git a/sql/updates/9444_auth_account.sql b/sql/updates/9444_auth_account.sql
new file mode 100644
index 00000000000..e4ec2c61cd6
--- /dev/null
+++ b/sql/updates/9444_auth_account.sql
@@ -0,0 +1 @@
+ALTER TABLE `account` ADD COLUMN `recruiter` int(11) NOT NULL default '0' AFTER `locale`;
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index ade749671e8..cb67ceef630 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -2586,22 +2586,26 @@ void Player::RemoveFromGroup(Group* group, uint64 guid)
}
}
-void Player::SendLogXPGain(uint32 GivenXP, Unit* victim, uint32 RestXP)
+void Player::SendLogXPGain(uint32 GivenXP, Unit* victim, uint32 BonusXP, bool recruitAFriend, float group_rate)
{
- WorldPacket data(SMSG_LOG_XPGAIN, 21);
+ WorldPacket data(SMSG_LOG_XPGAIN, 21); // guess size?
data << uint64(victim ? victim->GetGUID() : 0); // guid
- data << uint32(GivenXP+RestXP); // given experience
+ data << uint32(GivenXP + BonusXP); // given experience
data << uint8(victim ? 0 : 1); // 00-kill_xp type, 01-non_kill_xp type
+
if (victim)
{
- data << uint32(GivenXP); // experience without rested bonus
+ data << uint32(GivenXP); // experience without bonus
+
+ // should use group_rate here but can't figure out how
data << float(1); // 1 - none 0 - 100% group bonus output
}
- data << uint8(0); // new 2.4.0
+
+ data << uint8(recruitAFriend ? 1 : 0); // does the GivenXP include a RaF bonus?
GetSession()->SendPacket(&data);
}
-void Player::GiveXP(uint32 xp, Unit* victim)
+void Player::GiveXP(uint32 xp, Unit *victim, float group_rate)
{
if (xp < 1)
return;
@@ -2619,7 +2623,8 @@ void Player::GiveXP(uint32 xp, Unit* victim)
// Favored experience increase START
uint32 zone = GetZoneId();
float favored_exp_mult = 0;
- if ((HasAura(32096) || HasAura(32098)) && (zone == 3483 || zone == 3562 || zone == 3836 || zone == 3713 || zone == 3714)) favored_exp_mult = 0.05; // Thrallmar's Favor and Honor Hold's Favor
+ if ((HasAura(32096) || HasAura(32098)) && (zone == 3483 || zone == 3562 || zone == 3836 || zone == 3713 || zone == 3714))
+ favored_exp_mult = 0.05; // Thrallmar's Favor and Honor Hold's Favor
xp *= (1 + favored_exp_mult);
// Favored experience increase END
@@ -2627,14 +2632,20 @@ void Player::GiveXP(uint32 xp, Unit* victim)
if (level >= sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
return;
- // XP resting bonus for kill
- uint32 rested_bonus_xp = victim ? GetXPRestBonus(xp) : 0;
+ uint32 bonus_xp = 0;
+ bool recruitAFriend = GetsRecruitAFriendBonus(true);
+
+ // RaF does NOT stack with rested experience
+ if (recruitAFriend)
+ bonus_xp = 2 * xp; // xp + bonus_xp must add up to 3 * xp for RaF; calculation for quests done client-side
+ else
+ bonus_xp = victim ? GetXPRestBonus(xp) : 0; // XP resting bonus
- SendLogXPGain(xp,victim,rested_bonus_xp);
+ SendLogXPGain(xp, victim, bonus_xp, recruitAFriend, group_rate);
uint32 curXP = GetUInt32Value(PLAYER_XP);
uint32 nextLvlXP = GetUInt32Value(PLAYER_NEXT_LEVEL_XP);
- uint32 newXP = curXP + xp + rested_bonus_xp;
+ uint32 newXP = curXP + xp + bonus_xp;
while (newXP >= nextLvlXP && level < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
{
@@ -6567,46 +6578,42 @@ void Player::RewardReputation(Unit *pVictim, float rate)
if (favored_rep_mult > 0) favored_rep_mult *= 2; // Multiplied by 2 because the reputation is divided by 2 for some reason (See "donerep1 / 2" and "donerep2 / 2") -- if you know why this is done, please update/explain :)
// Favored reputation increase END
+ bool recruitAFriend = GetsRecruitAFriendBonus(false);
+
if (Rep->repfaction1 && (!Rep->team_dependent || team == ALLIANCE))
{
int32 donerep1 = CalculateReputationGain(pVictim->getLevel(), Rep->repvalue1, ChampioningFaction ? ChampioningFaction : Rep->repfaction1, false);
donerep1 = int32(donerep1*(rate + favored_rep_mult));
+
+ if (recruitAFriend)
+ donerep1 = int32(donerep1 * (1 + sWorld.getRate(RATE_REPUTATION_RECRUIT_A_FRIEND_BONUS)));
+
FactionEntry const *factionEntry1 = sFactionStore.LookupEntry(ChampioningFaction ? ChampioningFaction : Rep->repfaction1);
uint32 current_reputation_rank1 = GetReputationMgr().GetRank(factionEntry1);
if (factionEntry1 && current_reputation_rank1 <= Rep->reputation_max_cap1)
GetReputationMgr().ModifyReputation(factionEntry1, donerep1);
-
- // Wiki: Team factions value divided by 2 -- Deprecated, see ModifyReputation
- /*if (factionEntry1 && Rep->is_teamaward1)
- {
- FactionEntry const *team1_factionEntry = sFactionStore.LookupEntry(factionEntry1->team);
- if (team1_factionEntry)
- GetReputationMgr().ModifyReputation(team1_factionEntry, donerep1 / 2);
- }*/
}
if (Rep->repfaction2 && (!Rep->team_dependent || team == HORDE))
{
int32 donerep2 = CalculateReputationGain(pVictim->getLevel(), Rep->repvalue2, ChampioningFaction ? ChampioningFaction : Rep->repfaction2, false);
donerep2 = int32(donerep2*(rate + favored_rep_mult));
+
+ if (recruitAFriend)
+ donerep2 = int32(donerep2 * (1 + sWorld.getRate(RATE_REPUTATION_RECRUIT_A_FRIEND_BONUS)));
+
FactionEntry const *factionEntry2 = sFactionStore.LookupEntry(ChampioningFaction ? ChampioningFaction : Rep->repfaction2);
uint32 current_reputation_rank2 = GetReputationMgr().GetRank(factionEntry2);
if (factionEntry2 && current_reputation_rank2 <= Rep->reputation_max_cap2)
GetReputationMgr().ModifyReputation(factionEntry2, donerep2);
-
- // Wiki: Team factions value divided by 2 -- Deprecated, see ModifyReputation
- /*if (factionEntry2 && Rep->is_teamaward2)
- {
- FactionEntry const *team2_factionEntry = sFactionStore.LookupEntry(factionEntry2->team);
- if (team2_factionEntry)
- GetReputationMgr().ModifyReputation(team2_factionEntry, donerep2 / 2);
- }*/
}
}
//Calculate how many reputation points player gain with the quest
void Player::RewardReputation(Quest const *pQuest)
{
+ bool recruitAFriend = GetsRecruitAFriendBonus(false);
+
// quest reputation reward/loss
for (uint8 i = 0; i < QUEST_REPUTATIONS_COUNT; ++i)
{
@@ -6615,6 +6622,10 @@ void Player::RewardReputation(Quest const *pQuest)
if (pQuest->RewRepValue[i])
{
int32 rep = CalculateReputationGain(GetQuestLevel(pQuest), pQuest->RewRepValue[i]/100, pQuest->RewRepFaction[i], true, true);
+
+ if (recruitAFriend)
+ rep = int32(rep * (1 + sWorld.getRate(RATE_REPUTATION_RECRUIT_A_FRIEND_BONUS)));
+
if (FactionEntry const* factionEntry = sFactionStore.LookupEntry(pQuest->RewRepFaction[i]))
GetReputationMgr().ModifyReputation(factionEntry, rep);
}
@@ -6625,19 +6636,21 @@ void Player::RewardReputation(Quest const *pQuest)
if (const QuestFactionRewEntry *pRow = sQuestFactionRewardStore.LookupEntry(row))
{
- int32 repPoints = pRow->QuestRewFactionValue[field];
+ int32 repPoints = pRow->QuestRewFactionValue[field];
+
+ if (!repPoints)
+ continue;
+
+ repPoints = CalculateReputationGain(GetQuestLevel(pQuest), repPoints, pQuest->RewRepFaction[i], true);
- if (!repPoints)
- continue;
+ if (recruitAFriend)
+ repPoints = int32(repPoints * (1 + sWorld.getRate(RATE_REPUTATION_RECRUIT_A_FRIEND_BONUS)));
- repPoints = CalculateReputationGain(GetQuestLevel(pQuest), repPoints, pQuest->RewRepFaction[i], true);
- if (const FactionEntry* factionEntry = sFactionStore.LookupEntry(pQuest->RewRepFaction[i]))
+ if (const FactionEntry* factionEntry = sFactionStore.LookupEntry(pQuest->RewRepFaction[i]))
GetReputationMgr().ModifyReputation(factionEntry, repPoints);
}
}
}
-
- // TODO: implement reputation spillover
}
void Player::UpdateHonorFields()
@@ -21665,6 +21678,47 @@ bool Player::isHonorOrXPTarget(Unit* pVictim)
return true;
}
+bool Player::GetsRecruitAFriendBonus(bool forXP)
+{
+ bool recruitAFriend = false;
+ if (getLevel() <= sWorld.getConfig(CONFIG_MAX_RECRUIT_A_FRIEND_BONUS_PLAYER_LEVEL) || !forXP)
+ {
+ if (Group *group = this->GetGroup())
+ {
+ for (GroupReference *itr = group->GetFirstMember(); itr != NULL; itr = itr->next())
+ {
+ Player* pGroupGuy = itr->getSource();
+ if (!pGroupGuy)
+ continue;
+
+ if (!pGroupGuy->IsAtRecruitAFriendDistance(this))
+ continue; // member (alive or dead) or his corpse at req. distance
+
+ if (forXP)
+ {
+ // level must be allowed to get RaF bonus
+ if (pGroupGuy->getLevel() > sWorld.getConfig(CONFIG_MAX_RECRUIT_A_FRIEND_BONUS_PLAYER_LEVEL))
+ continue;
+
+ // level difference must be small enough to get RaF bonus, UNLESS we are lower level
+ if (pGroupGuy->getLevel() < getLevel())
+ if ((getLevel() - pGroupGuy->getLevel()) > sWorld.getConfig(CONFIG_MAX_RECRUIT_A_FRIEND_BONUS_PLAYER_LEVEL_DIFFERENCE))
+ continue;
+ }
+
+ bool ARecruitedB = (pGroupGuy->GetSession()->GetRecruiterId() == GetSession()->GetAccountId());
+ bool BRecruitedA = (GetSession()->GetRecruiterId() == pGroupGuy->GetSession()->GetAccountId());
+ if (ARecruitedB || BRecruitedA)
+ {
+ recruitAFriend = true;
+ break;
+ }
+ }
+ }
+ }
+ return recruitAFriend;
+}
+
bool Player::RewardPlayerAndGroupAtKill(Unit* pVictim)
{
bool PvP = pVictim->isCharmedOwnedByPlayerOrPlayer();
@@ -21726,7 +21780,7 @@ bool Player::RewardPlayerAndGroupAtKill(Unit* pVictim)
for (Unit::AuraEffectList::const_iterator i = ModXPPctAuras.begin(); i != ModXPPctAuras.end(); ++i)
itr_xp = uint32(itr_xp*(1.0f + (*i)->GetAmount() / 100.0f));
- pGroupGuy->GiveXP(itr_xp, pVictim);
+ pGroupGuy->GiveXP(itr_xp, pVictim, group_rate);
if (Pet* pet = pGroupGuy->GetPet())
pet->GivePetXP(itr_xp/2);
}
@@ -21814,6 +21868,20 @@ bool Player::IsAtGroupRewardDistance(WorldObject const* pRewardSource) const
return pRewardSource->GetDistance(player) <= sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE);
}
+bool Player::IsAtRecruitAFriendDistance(WorldObject const* pOther) const
+{
+ if (!pOther)
+ return false;
+ const WorldObject* player = GetCorpse();
+ if (!player || isAlive())
+ player = this;
+
+ if (player->GetMapId() != pOther->GetMapId() || player->GetInstanceId() != pOther->GetInstanceId())
+ return false;
+
+ return pOther->GetDistance(player) <= sWorld.getConfig(CONFIG_MAX_RECRUIT_A_FRIEND_DISTANCE);
+}
+
uint32 Player::GetBaseWeaponSkillValue (WeaponAttackType attType) const
{
Item* item = GetWeaponForAttack(attType,true);
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index 002e1314365..24233681a23 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -1069,7 +1069,7 @@ class Player : public Unit, public GridObject<Player>
void SetHas310Flyer(bool on) { if (on) m_ExtraFlags |= PLAYER_EXTRA_HAS_310_FLYER; else m_ExtraFlags &= ~PLAYER_EXTRA_HAS_310_FLYER; }
void SetPvPDeath(bool on) { if (on) m_ExtraFlags |= PLAYER_EXTRA_PVP_DEATH; else m_ExtraFlags &= ~PLAYER_EXTRA_PVP_DEATH; }
- void GiveXP(uint32 xp, Unit* victim);
+ void GiveXP(uint32 xp, Unit* victim, float group_rate=1.0f);
void GiveLevel(uint8 level);
void InitStatsForLevel(bool reapplyMods = false);
@@ -1804,7 +1804,7 @@ class Player : public Unit, public GridObject<Player>
void BuildCreateUpdateBlockForPlayer(UpdateData *data, Player *target) const;
void DestroyForPlayer(Player *target, bool anim = false) const;
- void SendLogXPGain(uint32 GivenXP,Unit* victim,uint32 RestXP);
+ void SendLogXPGain(uint32 GivenXP, Unit* victim, uint32 BonusXP, bool recruitAFriend = false, float group_rate=1.0f);
// notifiers
void SendAttackSwingCantAttack();
@@ -1903,10 +1903,13 @@ class Player : public Unit, public GridObject<Player>
void InitDisplayIds();
bool IsAtGroupRewardDistance(WorldObject const* pRewardSource) const;
+ bool IsAtRecruitAFriendDistance(WorldObject const* pOther) const;
bool RewardPlayerAndGroupAtKill(Unit* pVictim);
void RewardPlayerAndGroupAtEvent(uint32 creature_id,WorldObject* pRewardSource);
bool isHonorOrXPTarget(Unit* pVictim);
+ bool GetsRecruitAFriendBonus(bool forXP);
+
ReputationMgr& GetReputationMgr() { return m_reputationMgr; }
ReputationMgr const& GetReputationMgr() const { return m_reputationMgr; }
ReputationRank GetReputationRank(uint32 faction_id) const;
diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp
index 7e34afe09f8..fc63e2b6e75 100644
--- a/src/server/game/Server/WorldSession.cpp
+++ b/src/server/game/Server/WorldSession.cpp
@@ -46,16 +46,16 @@
#include "Transport.h"
/// WorldSession constructor
-WorldSession::WorldSession(uint32 id, WorldSocket *sock, AccountTypes sec, uint8 expansion, time_t mute_time, LocaleConstant locale) :
+WorldSession::WorldSession(uint32 id, WorldSocket *sock, AccountTypes sec, uint8 expansion, time_t mute_time, LocaleConstant locale, uint32 recruiter) :
m_muteTime(mute_time), _player(NULL), m_Socket(sock),_security(sec), _accountId(id), m_expansion(expansion),
m_sessionDbcLocale(sWorld.GetAvailableDbcLocale(locale)), m_sessionDbLocaleIndex(sObjectMgr.GetIndexForLocale(locale)),
_logoutTime(0), m_inQueue(false), m_playerLoading(false), m_playerLogout(false), m_playerRecentlyLogout(false), m_playerSave(false),
-m_latency(0), m_TutorialsChanged(false), m_timeOutTime(0)
+m_latency(0), m_TutorialsChanged(false), m_timeOutTime(0), recruiterId(recruiter)
{
if (sock)
{
- m_Address = sock->GetRemoteAddress ();
- sock->AddReference ();
+ m_Address = sock->GetRemoteAddress();
+ sock->AddReference();
ResetTimeOutTime();
LoginDatabase.PExecute("UPDATE account SET online = 1 WHERE id = %u;", GetAccountId());
}
diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h
index 9c6dd70831f..7251e900ae0 100644
--- a/src/server/game/Server/WorldSession.h
+++ b/src/server/game/Server/WorldSession.h
@@ -129,7 +129,7 @@ class WorldSession
{
friend class CharacterHandler;
public:
- WorldSession(uint32 id, WorldSocket *sock, AccountTypes sec, uint8 expansion, time_t mute_time, LocaleConstant locale);
+ WorldSession(uint32 id, WorldSocket *sock, AccountTypes sec, uint8 expansion, time_t mute_time, LocaleConstant locale, uint32 recruiter);
~WorldSession();
bool PlayerLoading() const { return m_playerLoading; }
@@ -306,6 +306,8 @@ class WorldSession
return false;
}
+ // Recruit-A-Friend Handling
+ uint32 GetRecruiterId() { return recruiterId; }
public: // opcodes handlers
@@ -826,6 +828,7 @@ class WorldSession
uint32 m_Tutorials[8];
bool m_TutorialsChanged;
AddonsList m_addonsList;
+ uint32 recruiterId;
ACE_Based::LockedQueue<WorldPacket*, ACE_Thread_Mutex> _recvQueue;
};
#endif
diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp
index 09d2199b3ff..146595ff910 100644
--- a/src/server/game/Server/WorldSocket.cpp
+++ b/src/server/game/Server/WorldSocket.cpp
@@ -829,7 +829,8 @@ int WorldSocket::HandleAuthSession (WorldPacket& recvPacket)
"s, " //5
"expansion, " //6
"mutetime, " //7
- "locale " //8
+ "locale, " //8
+ "recruiter " //9
"FROM account "
"WHERE username = '%s'",
safe_account.c_str());
@@ -898,6 +899,8 @@ int WorldSocket::HandleAuthSession (WorldPacket& recvPacket)
if (locale >= MAX_LOCALE)
locale = LOCALE_enUS;
+ uint32 recruiter = fields[9].GetUInt32();
+
// Checks gmlevel per Realm
result =
LoginDatabase.PQuery ("SELECT "
@@ -989,7 +992,7 @@ int WorldSocket::HandleAuthSession (WorldPacket& recvPacket)
safe_account.c_str());
// NOTE ATM the socket is single-threaded, have this in mind ...
- ACE_NEW_RETURN (m_Session, WorldSession (id, this, AccountTypes(security), expansion, mutetime, locale), -1);
+ ACE_NEW_RETURN (m_Session, WorldSession (id, this, AccountTypes(security), expansion, mutetime, locale, recruiter), -1);
m_Crypt.Init(&K);
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index 15794718491..a52d2a7d48e 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -482,6 +482,7 @@ void World::LoadConfigSettings(bool reload)
rate_values[RATE_REPUTATION_GAIN] = sConfig.GetFloatDefault("Rate.Reputation.Gain", 1.0f);
rate_values[RATE_REPUTATION_LOWLEVEL_KILL] = sConfig.GetFloatDefault("Rate.Reputation.LowLevel.Kill", 1.0f);
rate_values[RATE_REPUTATION_LOWLEVEL_QUEST] = sConfig.GetFloatDefault("Rate.Reputation.LowLevel.Quest", 1.0f);
+ rate_values[RATE_REPUTATION_RECRUIT_A_FRIEND_BONUS] = sConfig.GetFloatDefault("Rate.Reputation.RecruitAFriendBonus", 0.1f);
rate_values[RATE_CREATURE_NORMAL_DAMAGE] = sConfig.GetFloatDefault("Rate.Creature.Normal.Damage", 1.0f);
rate_values[RATE_CREATURE_ELITE_ELITE_DAMAGE] = sConfig.GetFloatDefault("Rate.Creature.Elite.Elite.Damage", 1.0f);
rate_values[RATE_CREATURE_ELITE_RAREELITE_DAMAGE] = sConfig.GetFloatDefault("Rate.Creature.Elite.RAREELITE.Damage", 1.0f);
@@ -648,6 +649,8 @@ void World::LoadConfigSettings(bool reload)
m_configs[CONFIG_SESSION_ADD_DELAY] = sConfig.GetIntDefault("SessionAddDelay", 10000);
m_configs[CONFIG_GROUP_XP_DISTANCE] = sConfig.GetIntDefault("MaxGroupXPDistance", 74);
+ m_configs[CONFIG_MAX_RECRUIT_A_FRIEND_DISTANCE] = sConfig.GetIntDefault("MaxRecruitAFriendBonusDistance", 100);
+
/// \todo Add MonsterSight and GuarderSight (with meaning) in worldserver.conf or put them as define
m_configs[CONFIG_SIGHT_MONSTER] = sConfig.GetIntDefault("MonsterSight", 50);
m_configs[CONFIG_SIGHT_GUARDER] = sConfig.GetIntDefault("GuarderSight", 50);
@@ -836,6 +839,22 @@ void World::LoadConfigSettings(bool reload)
m_configs[CONFIG_START_ARENA_POINTS] = m_configs[CONFIG_MAX_ARENA_POINTS];
}
+ m_configs[CONFIG_MAX_RECRUIT_A_FRIEND_BONUS_PLAYER_LEVEL] = sConfig.GetIntDefault("RecruitAFriend.MaxLevel", 60);
+ if (m_configs[CONFIG_MAX_RECRUIT_A_FRIEND_BONUS_PLAYER_LEVEL] < 0 || m_configs[CONFIG_MAX_RECRUIT_A_FRIEND_BONUS_PLAYER_LEVEL] > m_configs[CONFIG_MAX_PLAYER_LEVEL])
+ {
+ sLog.outError("RecruitAFriend.MaxLevel (%i) must be in the range 0..MaxLevel(%u). Set to %u.",
+ m_configs[CONFIG_MAX_RECRUIT_A_FRIEND_BONUS_PLAYER_LEVEL],m_configs[CONFIG_MAX_PLAYER_LEVEL],60);
+ m_configs[CONFIG_MAX_RECRUIT_A_FRIEND_BONUS_PLAYER_LEVEL] = 60;
+ }
+
+ m_configs[CONFIG_MAX_RECRUIT_A_FRIEND_BONUS_PLAYER_LEVEL_DIFFERENCE] = sConfig.GetIntDefault("RecruitAFriend.MaxDifference", 3);
+ if (m_configs[CONFIG_MAX_RECRUIT_A_FRIEND_BONUS_PLAYER_LEVEL_DIFFERENCE] < 0)
+ {
+ sLog.outError("RecruitAFriend.MaxLevel (%i) must be greater than or equal to 0. Set to %u.",
+ m_configs[CONFIG_MAX_RECRUIT_A_FRIEND_BONUS_PLAYER_LEVEL_DIFFERENCE],3);
+ m_configs[CONFIG_MAX_RECRUIT_A_FRIEND_BONUS_PLAYER_LEVEL_DIFFERENCE] = 3;
+ }
+
m_configs[CONFIG_ALL_TAXI_PATHS] = sConfig.GetBoolDefault("AllFlightPaths", false);
m_configs[CONFIG_INSTANT_TAXI] = sConfig.GetBoolDefault("InstantFlightPaths", false);
diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h
index 8a480d0ccc6..2ade43c26a9 100644
--- a/src/server/game/World/World.h
+++ b/src/server/game/World/World.h
@@ -102,6 +102,7 @@ enum WorldConfigs
CONFIG_SOCKET_TIMEOUTTIME,
CONFIG_SESSION_ADD_DELAY,
CONFIG_GROUP_XP_DISTANCE,
+ CONFIG_MAX_RECRUIT_A_FRIEND_DISTANCE,
CONFIG_SIGHT_MONSTER,
CONFIG_SIGHT_GUARDER,
CONFIG_GAME_TYPE,
@@ -137,6 +138,8 @@ enum WorldConfigs
CONFIG_START_HONOR_POINTS,
CONFIG_MAX_ARENA_POINTS,
CONFIG_START_ARENA_POINTS,
+ CONFIG_MAX_RECRUIT_A_FRIEND_BONUS_PLAYER_LEVEL,
+ CONFIG_MAX_RECRUIT_A_FRIEND_BONUS_PLAYER_LEVEL_DIFFERENCE,
CONFIG_INSTANCE_IGNORE_LEVEL,
CONFIG_INSTANCE_IGNORE_RAID,
CONFIG_INSTANCE_RESET_TIME_HOUR,
@@ -319,6 +322,7 @@ enum Rates
RATE_REPUTATION_GAIN,
RATE_REPUTATION_LOWLEVEL_KILL,
RATE_REPUTATION_LOWLEVEL_QUEST,
+ RATE_REPUTATION_RECRUIT_A_FRIEND_BONUS,
RATE_CREATURE_NORMAL_HP,
RATE_CREATURE_ELITE_ELITE_HP,
RATE_CREATURE_ELITE_RAREELITE_HP,
diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist
index d847a7c0467..8090352f464 100644
--- a/src/server/worldserver/worldserver.conf.dist
+++ b/src/server/worldserver/worldserver.conf.dist
@@ -780,6 +780,16 @@ ChatLogTimestamp = 0
# Amount of arena points that new players will start with
# Default: 0
#
+# RecruitAFriend.MaxLevel
+# Highest level at which a player can benefit from the Recruit-A-Friend
+# XP multiplier
+# Default: 60
+#
+# RecruitAFriend.MaxDifference = 3
+# Highest level difference between linked players for both players to
+# benefit from the Recruit-A-Friend XP multiplier
+# Default: 3
+#
# InstantLogout
# Enable or disable instant logout for security level (0..4) or higher
# (NOT in combat/while dueling/while falling)
@@ -885,6 +895,10 @@ ChatLogTimestamp = 0
# Max distance to creature for group member to get XP at creature death.
# Default: 74
#
+# MaxRecruitAFriendBonusDistance
+# Max distance to player for group member to get RaF bonus for XP.
+# Default: 100
+#
# MailDeliveryDelay
# Mail delivery delay time for item sending
# Default: 3600 sec (1 hour)
@@ -960,6 +974,8 @@ MaxHonorPoints = 75000
StartHonorPoints = 0
MaxArenaPoints = 5000
StartArenaPoints = 0
+RecruitAFriend.MaxLevel = 60
+RecruitAFriend.MaxDifference = 3
InstantLogout = 1
DisableWaterBreath = 4
AllFlightPaths = 0
@@ -979,6 +995,7 @@ Guild.BankEventLogRecordsCount = 25
MaxPrimaryTradeSkill = 2
MinPetitionSigns = 9
MaxGroupXPDistance = 74
+MaxRecruitAFriendBonusDistance = 100
MailDeliveryDelay = 3600
SkillChance.Prospecting = 0
SkillChance.Milling = 0
@@ -1492,13 +1509,17 @@ Visibility.Notify.Period.InBGArenas = 1000
# Default: 1
#
# Rate.Reputation.LowLevel.Kill
-# Reputation Gain from low level kill (grey creture)
+# Reputation Gain from low level kill (grey creature)
# Default: 1
#
# Rate.Reputation.LowLevel.Quest
# Reputation Gain rate
# Default: 1
#
+# Rate.Reputation.RecruitAFriendBonus
+# Reputation bonus amount for recruit-a-friend. 0.1 = 10% bonus.
+# Default: 0.1 (blizzlike)
+#
# Rate.MoveSpeed
# Multiply the default movement speed for players
# and whatever they're controlling.
@@ -1628,6 +1649,7 @@ Rate.Talent = 1
Rate.Reputation.Gain = 1
Rate.Reputation.LowLevel.Kill = 1
Rate.Reputation.LowLevel.Quest = 1
+Rate.Reputation.RecruitAFriendBonus = 0.1
Rate.MoveSpeed = 1
Rate.InstanceResetTime = 1
SkillGain.Crafting = 1