Merge pull request #684 from daerath/feature/Dae-ModernAAXP

Feature/dae modern aaxp
This commit is contained in:
Michael Cook (mackal) 2018-01-15 22:27:20 -05:00 committed by GitHub
commit 42d3a7e4f6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 305 additions and 142 deletions

View File

@ -676,6 +676,12 @@ RULE_CATEGORY_END()
RULE_CATEGORY(AA) RULE_CATEGORY(AA)
RULE_INT(AA, ExpPerPoint, 23976503) //Amount of exp per AA. Is the same as the amount of exp to go from level 51 to level 52. RULE_INT(AA, ExpPerPoint, 23976503) //Amount of exp per AA. Is the same as the amount of exp to go from level 51 to level 52.
RULE_BOOL(AA, Stacking, true) //Allow AA that belong to the same group to stack on SOF+ clients. RULE_BOOL(AA, Stacking, true) //Allow AA that belong to the same group to stack on SOF+ clients.
RULE_BOOL(AA, NormalizedAAEnabled, false) // TSS+ change to AA that normalizes AA XP to a fixed # of white con kills independent of level.
RULE_INT(AA, NormalizedAANumberOfWhiteConPerAA, 25) // The number of white con kills per AA point.
RULE_BOOL(AA, ModernAAScalingEnabled, false) // Are we linearly scaling AA XP based on total # of earned AA?
RULE_REAL(AA, ModernAAScalingStartPercent, 1000) // 1000% or 10x AA XP at the start of the scaling range
RULE_INT(AA, ModernAAScalingAAMinimum, 0) // The minimum number of earned AA before AA XP scaling begins.
RULE_INT(AA, ModernAAScalingAALimit, 4000) // The number of earned AA when AA XP scaling ends
RULE_CATEGORY_END() RULE_CATEGORY_END()
RULE_CATEGORY(Console) RULE_CATEGORY(Console)

View File

@ -606,6 +606,10 @@ public:
uint32 GetExperienceForKill(Mob *against); uint32 GetExperienceForKill(Mob *against);
void AddEXP(uint32 in_add_exp, uint8 conlevel = 0xFF, bool resexp = false); void AddEXP(uint32 in_add_exp, uint8 conlevel = 0xFF, bool resexp = false);
uint32 CalcEXP(uint8 conlevel = 0xFF); uint32 CalcEXP(uint8 conlevel = 0xFF);
void CalculateNormalizedAAExp(uint32 &add_aaxp, uint8 conlevel, bool resexp);
void CalculateStandardAAExp(uint32 &add_aaxp, uint8 conlevel, bool resexp);
void CalculateLeadershipExp(uint32 &add_exp, uint8 conlevel);
void CalculateExp(uint32 in_add_exp, uint32 &add_exp, uint32 &add_aaxp, uint8 conlevel, bool resexp);
void SetEXP(uint32 set_exp, uint32 set_aaxp, bool resexp=false); void SetEXP(uint32 set_exp, uint32 set_aaxp, bool resexp=false);
void AddLevelBasedExp(uint8 exp_percentage, uint8 max_level=0); void AddLevelBasedExp(uint8 exp_percentage, uint8 max_level=0);
void SetLeadershipEXP(uint32 group_exp, uint32 raid_exp); void SetLeadershipEXP(uint32 group_exp, uint32 raid_exp);

View File

@ -37,6 +37,49 @@
extern QueryServ* QServ; extern QueryServ* QServ;
static uint32 ScaleAAXPBasedOnCurrentAATotal(int earnedAA, uint32 add_aaxp)
{
float baseModifier = RuleR(AA, ModernAAScalingStartPercent);
int aaMinimum = RuleI(AA, ModernAAScalingAAMinimum);
int aaLimit = RuleI(AA, ModernAAScalingAALimit);
// Are we within the scaling window?
if (earnedAA >= aaLimit || earnedAA < aaMinimum)
{
Log(Logs::Detail, Logs::None, "Not within AA scaling window.");
// At or past the limit. We're done.
return add_aaxp;
}
// We're not at the limit yet. How close are we?
int remainingAA = aaLimit - earnedAA;
// We might not always be X - 0
int scaleRange = aaLimit - aaMinimum;
// Normalize and get the effectiveness based on the range and the character's
// current spent AA.
float normalizedScale = (float)remainingAA / scaleRange;
// Scale.
uint32 totalWithExpMod = add_aaxp * (baseModifier / 100) * normalizedScale;
// Are we so close to the scale limit that we're earning more XP without scaling? This
// will happen when we get very close to the limit. In this case, just grant the unscaled
// amount.
if (totalWithExpMod < add_aaxp)
{
return add_aaxp;
}
Log(Logs::Detail,
Logs::None,
"Total before the modifier %d :: NewTotal %d :: ScaleRange: %d, SpentAA: %d, RemainingAA: %d, normalizedScale: %0.3f",
add_aaxp, totalWithExpMod, scaleRange, earnedAA, remainingAA, normalizedScale);
return totalWithExpMod;
}
static uint32 MaxBankedGroupLeadershipPoints(int Level) static uint32 MaxBankedGroupLeadershipPoints(int Level)
{ {
@ -174,152 +217,69 @@ uint32 Client::GetExperienceForKill(Mob *against)
return 0; return 0;
} }
void Client::AddEXP(uint32 in_add_exp, uint8 conlevel, bool resexp) { float static GetConLevelModifierPercent(uint8 conlevel)
this->EVENT_ITEM_ScriptStopReturn();
uint32 add_exp = in_add_exp;
if(!resexp && (XPRate != 0))
add_exp = static_cast<uint32>(in_add_exp * (static_cast<float>(XPRate) / 100.0f));
if (m_epp.perAA<0 || m_epp.perAA>100)
m_epp.perAA=0; // stop exploit with sanity check
uint32 add_aaxp;
if(resexp) {
add_aaxp = 0;
} else {
//figure out how much of this goes to AAs
add_aaxp = add_exp * m_epp.perAA / 100;
//take that amount away from regular exp
add_exp -= add_aaxp;
float totalmod = 1.0;
float zemmod = 1.0;
//get modifiers
if(RuleR(Character, ExpMultiplier) >= 0){
totalmod *= RuleR(Character, ExpMultiplier);
}
if(zone->newzone_data.zone_exp_multiplier >= 0){
zemmod *= zone->newzone_data.zone_exp_multiplier;
}
if(RuleB(Character,UseRaceClassExpBonuses))
{ {
if(GetBaseRace() == HALFLING){
totalmod *= 1.05;
}
if(GetClass() == ROGUE || GetClass() == WARRIOR){
totalmod *= 1.05;
}
}
if(zone->IsHotzone())
{
totalmod += RuleR(Zone, HotZoneBonus);
}
add_exp = uint32(float(add_exp) * totalmod * zemmod);
if(RuleB(Character,UseXPConScaling))
{
if (conlevel != 0xFF && !resexp) {
switch (conlevel) switch (conlevel)
{ {
case CON_GRAY:
add_exp = 0;
add_aaxp = 0;
return;
case CON_GREEN: case CON_GREEN:
add_exp = add_exp * RuleI(Character, GreenModifier) / 100; return (float)RuleI(Character, GreenModifier) / 100;
add_aaxp = add_aaxp * RuleI(Character, GreenModifier) / 100;
break; break;
case CON_LIGHTBLUE: case CON_LIGHTBLUE:
add_exp = add_exp * RuleI(Character, LightBlueModifier)/100; return (float)RuleI(Character, LightBlueModifier) / 100;
add_aaxp = add_aaxp * RuleI(Character, LightBlueModifier)/100;
break; break;
case CON_BLUE: case CON_BLUE:
add_exp = add_exp * RuleI(Character, BlueModifier)/100; return (float)RuleI(Character, BlueModifier) / 100;
add_aaxp = add_aaxp * RuleI(Character, BlueModifier)/100;
break; break;
case CON_WHITE: case CON_WHITE:
add_exp = add_exp * RuleI(Character, WhiteModifier)/100; return (float)RuleI(Character, WhiteModifier) / 100;
add_aaxp = add_aaxp * RuleI(Character, WhiteModifier)/100;
break; break;
case CON_YELLOW: case CON_YELLOW:
add_exp = add_exp * RuleI(Character, YellowModifier)/100; return (float)RuleI(Character, YellowModifier) / 100;
add_aaxp = add_aaxp * RuleI(Character, YellowModifier)/100;
break; break;
case CON_RED: case CON_RED:
add_exp = add_exp * RuleI(Character, RedModifier)/100; return (float)RuleI(Character, RedModifier) / 100;
add_aaxp = add_aaxp * RuleI(Character, RedModifier)/100;
break; break;
} default:
return 0;
} }
} }
if (IsLeadershipEXPOn() && (conlevel == CON_BLUE || conlevel == CON_WHITE || conlevel == CON_YELLOW || conlevel == CON_RED)) { void Client::CalculateNormalizedAAExp(uint32 &add_aaxp, uint8 conlevel, bool resexp)
add_exp = static_cast<uint32>(static_cast<float>(add_exp) * 0.8f); {
// Functionally this is the same as having the case in the switch, but this is
if (GetGroup()) { // cleaner to read.
if (m_pp.group_leadership_points < MaxBankedGroupLeadershipPoints(GetLevel()) if (CON_GRAY == conlevel || resexp)
&& RuleI(Character, KillsPerGroupLeadershipAA) > 0) { {
uint32 exp = GROUP_EXP_PER_POINT / RuleI(Character, KillsPerGroupLeadershipAA); add_aaxp = 0;
Client *mentoree = GetGroup()->GetMentoree(); return;
if (GetGroup()->GetMentorPercent() && mentoree &&
mentoree->GetGroupPoints() < MaxBankedGroupLeadershipPoints(mentoree->GetLevel())) {
uint32 mentor_exp = exp * (GetGroup()->GetMentorPercent() / 100.0f);
exp -= mentor_exp;
mentoree->AddLeadershipEXP(mentor_exp, 0); // ends up rounded down
mentoree->Message_StringID(MT_Leadership, GAIN_GROUP_LEADERSHIP_EXP);
}
if (exp > 0) { // possible if you mentor 100% to the other client
AddLeadershipEXP(exp, 0); // ends up rounded up if mentored, no idea how live actually does it
Message_StringID(MT_Leadership, GAIN_GROUP_LEADERSHIP_EXP);
}
} else {
Message_StringID(MT_Leadership, MAX_GROUP_LEADERSHIP_POINTS);
}
} else {
Raid *raid = GetRaid();
// Raid leaders CAN NOT gain group AA XP, other group leaders can though!
if (raid->IsLeader(this)) {
if (m_pp.raid_leadership_points < MaxBankedRaidLeadershipPoints(GetLevel())
&& RuleI(Character, KillsPerRaidLeadershipAA) > 0) {
AddLeadershipEXP(0, RAID_EXP_PER_POINT / RuleI(Character, KillsPerRaidLeadershipAA));
Message_StringID(MT_Leadership, GAIN_RAID_LEADERSHIP_EXP);
} else {
Message_StringID(MT_Leadership, MAX_RAID_LEADERSHIP_POINTS);
}
} else {
if (m_pp.group_leadership_points < MaxBankedGroupLeadershipPoints(GetLevel())
&& RuleI(Character, KillsPerGroupLeadershipAA) > 0) {
uint32 group_id = raid->GetGroup(this);
uint32 exp = GROUP_EXP_PER_POINT / RuleI(Character, KillsPerGroupLeadershipAA);
Client *mentoree = raid->GetMentoree(group_id);
if (raid->GetMentorPercent(group_id) && mentoree &&
mentoree->GetGroupPoints() < MaxBankedGroupLeadershipPoints(mentoree->GetLevel())) {
uint32 mentor_exp = exp * (raid->GetMentorPercent(group_id) / 100.0f);
exp -= mentor_exp;
mentoree->AddLeadershipEXP(mentor_exp, 0);
mentoree->Message_StringID(MT_Leadership, GAIN_GROUP_LEADERSHIP_EXP);
}
if (exp > 0) {
AddLeadershipEXP(exp, 0);
Message_StringID(MT_Leadership, GAIN_GROUP_LEADERSHIP_EXP);
}
} else {
Message_StringID(MT_Leadership, MAX_GROUP_LEADERSHIP_POINTS);
}
}
} }
// For this, we ignore the provided value of add_aaxp because it doesn't
// apply. XP per AA is normalized such that there are X white con kills
// per AA.
uint32 whiteConKillsPerAA = RuleI(AA, NormalizedAANumberOfWhiteConPerAA);
uint32 xpPerAA = RuleI(AA, ExpPerPoint);
float colorModifier = GetConLevelModifierPercent(conlevel);
float percentToAAXp = (float)m_epp.perAA / 100;
// Normalize the amount of AA XP we earned for this kill.
add_aaxp = percentToAAXp * (xpPerAA / (whiteConKillsPerAA / colorModifier));
} }
void Client::CalculateStandardAAExp(uint32 &add_aaxp, uint8 conlevel, bool resexp)
{
if (!resexp)
{
//if XP scaling is based on the con of a monster, do that now.
if (RuleB(Character, UseXPConScaling))
{
if (conlevel != 0xFF && !resexp)
{
add_aaxp *= GetConLevelModifierPercent(conlevel);
}
}
} //end !resexp } //end !resexp
float aatotalmod = 1.0; float aatotalmod = 1.0;
@ -347,19 +307,212 @@ void Client::AddEXP(uint32 in_add_exp, uint8 conlevel, bool resexp) {
if (RuleB(Zone, LevelBasedEXPMods)) { if (RuleB(Zone, LevelBasedEXPMods)) {
if (zone->level_exp_mod[GetLevel()].ExpMod) { if (zone->level_exp_mod[GetLevel()].ExpMod) {
add_exp *= zone->level_exp_mod[GetLevel()].ExpMod;
add_aaxp *= zone->level_exp_mod[GetLevel()].AAExpMod; add_aaxp *= zone->level_exp_mod[GetLevel()].AAExpMod;
} }
} }
uint32 exp = GetEXP() + add_exp; add_aaxp = (uint32)(RuleR(Character, AAExpMultiplier) * add_aaxp * aatotalmod);
}
uint32 aaexp = (uint32)(RuleR(Character, AAExpMultiplier) * add_aaxp * aatotalmod); void Client::CalculateLeadershipExp(uint32 &add_exp, uint8 conlevel)
{
if (IsLeadershipEXPOn() && (conlevel == CON_BLUE || conlevel == CON_WHITE || conlevel == CON_YELLOW || conlevel == CON_RED))
{
add_exp = static_cast<uint32>(static_cast<float>(add_exp) * 0.8f);
if (GetGroup())
{
if (m_pp.group_leadership_points < MaxBankedGroupLeadershipPoints(GetLevel())
&& RuleI(Character, KillsPerGroupLeadershipAA) > 0)
{
uint32 exp = GROUP_EXP_PER_POINT / RuleI(Character, KillsPerGroupLeadershipAA);
Client *mentoree = GetGroup()->GetMentoree();
if (GetGroup()->GetMentorPercent() && mentoree &&
mentoree->GetGroupPoints() < MaxBankedGroupLeadershipPoints(mentoree->GetLevel()))
{
uint32 mentor_exp = exp * (GetGroup()->GetMentorPercent() / 100.0f);
exp -= mentor_exp;
mentoree->AddLeadershipEXP(mentor_exp, 0); // ends up rounded down
mentoree->Message_StringID(MT_Leadership, GAIN_GROUP_LEADERSHIP_EXP);
}
if (exp > 0)
{
// possible if you mentor 100% to the other client
AddLeadershipEXP(exp, 0); // ends up rounded up if mentored, no idea how live actually does it
Message_StringID(MT_Leadership, GAIN_GROUP_LEADERSHIP_EXP);
}
}
else
{
Message_StringID(MT_Leadership, MAX_GROUP_LEADERSHIP_POINTS);
}
}
else
{
Raid *raid = GetRaid();
// Raid leaders CAN NOT gain group AA XP, other group leaders can though!
if (raid->IsLeader(this))
{
if (m_pp.raid_leadership_points < MaxBankedRaidLeadershipPoints(GetLevel())
&& RuleI(Character, KillsPerRaidLeadershipAA) > 0)
{
AddLeadershipEXP(0, RAID_EXP_PER_POINT / RuleI(Character, KillsPerRaidLeadershipAA));
Message_StringID(MT_Leadership, GAIN_RAID_LEADERSHIP_EXP);
}
else
{
Message_StringID(MT_Leadership, MAX_RAID_LEADERSHIP_POINTS);
}
}
else
{
if (m_pp.group_leadership_points < MaxBankedGroupLeadershipPoints(GetLevel())
&& RuleI(Character, KillsPerGroupLeadershipAA) > 0)
{
uint32 group_id = raid->GetGroup(this);
uint32 exp = GROUP_EXP_PER_POINT / RuleI(Character, KillsPerGroupLeadershipAA);
Client *mentoree = raid->GetMentoree(group_id);
if (raid->GetMentorPercent(group_id) && mentoree &&
mentoree->GetGroupPoints() < MaxBankedGroupLeadershipPoints(mentoree->GetLevel()))
{
uint32 mentor_exp = exp * (raid->GetMentorPercent(group_id) / 100.0f);
exp -= mentor_exp;
mentoree->AddLeadershipEXP(mentor_exp, 0);
mentoree->Message_StringID(MT_Leadership, GAIN_GROUP_LEADERSHIP_EXP);
}
if (exp > 0)
{
AddLeadershipEXP(exp, 0);
Message_StringID(MT_Leadership, GAIN_GROUP_LEADERSHIP_EXP);
}
}
else
{
Message_StringID(MT_Leadership, MAX_GROUP_LEADERSHIP_POINTS);
}
}
}
}
}
void Client::CalculateExp(uint32 in_add_exp, uint32 &add_exp, uint32 &add_aaxp, uint8 conlevel, bool resexp)
{
add_exp = in_add_exp;
if (!resexp && (XPRate != 0))
{
add_exp = static_cast<uint32>(in_add_exp * (static_cast<float>(XPRate) / 100.0f));
}
// Make sure it was initialized.
add_aaxp = 0;
if (!resexp)
{
//figure out how much of this goes to AAs
add_aaxp = add_exp * m_epp.perAA / 100;
//take that amount away from regular exp
add_exp -= add_aaxp;
float totalmod = 1.0;
float zemmod = 1.0;
//get modifiers
if (RuleR(Character, ExpMultiplier) >= 0) {
totalmod *= RuleR(Character, ExpMultiplier);
}
//add the zone exp modifier.
if (zone->newzone_data.zone_exp_multiplier >= 0) {
zemmod *= zone->newzone_data.zone_exp_multiplier;
}
if (RuleB(Character, UseRaceClassExpBonuses))
{
if (GetBaseRace() == HALFLING) {
totalmod *= 1.05;
}
if (GetClass() == ROGUE || GetClass() == WARRIOR) {
totalmod *= 1.05;
}
}
//add hotzone modifier if one has been set.
if (zone->IsHotzone())
{
totalmod += RuleR(Zone, HotZoneBonus);
}
add_exp = uint32(float(add_exp) * totalmod * zemmod);
//if XP scaling is based on the con of a monster, do that now.
if (RuleB(Character, UseXPConScaling))
{
if (conlevel != 0xFF && !resexp)
{
add_exp = add_exp * GetConLevelModifierPercent(conlevel);
}
}
// Calculate any changes to leadership experience.
CalculateLeadershipExp(add_exp, conlevel);
} //end !resexp
if (RuleB(Zone, LevelBasedEXPMods)) {
if (zone->level_exp_mod[GetLevel()].ExpMod) {
add_exp *= zone->level_exp_mod[GetLevel()].ExpMod;
}
}
add_exp = GetEXP() + add_exp;
}
void Client::AddEXP(uint32 in_add_exp, uint8 conlevel, bool resexp) {
this->EVENT_ITEM_ScriptStopReturn();
uint32 exp = 0;
uint32 aaexp = 0;
if (m_epp.perAA<0 || m_epp.perAA>100)
m_epp.perAA=0; // stop exploit with sanity check
// Calculate regular XP
CalculateExp(in_add_exp, exp, aaexp, conlevel, resexp);
// Calculate regular AA XP
if (!RuleB(AA, NormalizedAAEnabled))
{
CalculateStandardAAExp(aaexp, conlevel, resexp);
}
else
{
CalculateNormalizedAAExp(aaexp, conlevel, resexp);
}
// Are we also doing linear AA acceleration?
if (RuleB(AA, ModernAAScalingEnabled) && aaexp > 0)
{
aaexp = ScaleAAXPBasedOnCurrentAATotal(GetAAPoints(), aaexp);
}
// Get current AA XP total
uint32 had_aaexp = GetAAXP(); uint32 had_aaexp = GetAAXP();
aaexp += had_aaexp;
if(aaexp < had_aaexp)
aaexp = had_aaexp; //watch for wrap
// Add it to the XP we just earned.
aaexp += had_aaexp;
// Make sure our new total (existing + just earned) isn't lower than the
// existing total. If it is, we overflowed the bounds of uint32 and wrapped.
// Reset to the existing total.
if (aaexp < had_aaexp)
{
aaexp = had_aaexp; //watch for wrap
}
// Now update our character's normal and AA xp
SetEXP(exp, aaexp, resexp); SetEXP(exp, aaexp, resexp);
} }