mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-17 03:08:26 +00:00
Merge branch 'master' into lsid
This commit is contained in:
+1
-1
@@ -253,7 +253,7 @@ bool Mob::CheckWillAggro(Mob *mob) {
|
||||
//sometimes if a client has some lag while zoning into a dangerous place while either invis or a GM
|
||||
//they will aggro mobs even though it's supposed to be impossible, to lets make sure we've finished connecting
|
||||
if (mob->IsClient()) {
|
||||
if (!mob->CastToClient()->ClientFinishedLoading() || mob->CastToClient()->IsHoveringForRespawn() || mob->CastToClient()->zoning)
|
||||
if (!mob->CastToClient()->ClientFinishedLoading() || mob->CastToClient()->IsHoveringForRespawn() || mob->CastToClient()->bZoning)
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
+10
-1
@@ -1728,6 +1728,15 @@ bool Client::Death(Mob* killerMob, int32 damage, uint16 spell, EQEmu::skills::Sk
|
||||
if (!RuleB(Character, UseDeathExpLossMult)) {
|
||||
exploss = (int)(GetLevel() * (GetLevel() / 18.0) * 12000);
|
||||
}
|
||||
|
||||
if (RuleB(Zone, LevelBasedEXPMods)) {
|
||||
// Death in levels with xp_mod (such as hell levels) was resulting
|
||||
// in losing more that appropriate since the loss was the same but
|
||||
// getting it back would take way longer. This makes the death the
|
||||
// same amount of time to recover. Will also lose more if level is
|
||||
// granting a bonus.
|
||||
exploss *= zone->level_exp_mod[GetLevel()].ExpMod;
|
||||
}
|
||||
|
||||
if ((GetLevel() < RuleI(Character, DeathExpLossLevel)) || (GetLevel() > RuleI(Character, DeathExpLossMaxLevel)) || IsBecomeNPC())
|
||||
{
|
||||
@@ -2675,7 +2684,7 @@ void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, b
|
||||
|
||||
hate_list.AddEntToHateList(other, hate, damage, bFrenzy, !iBuffTic);
|
||||
|
||||
if (other->IsClient() && !on_hatelist)
|
||||
if (other->IsClient() && !on_hatelist && !IsOnFeignMemory(other->CastToClient()))
|
||||
other->CastToClient()->AddAutoXTarget(this);
|
||||
|
||||
#ifdef BOTS
|
||||
|
||||
+2
-2
@@ -215,7 +215,7 @@ Client::Client(EQStreamInterface* ieqs)
|
||||
linkdead_timer.Disable();
|
||||
zonesummon_id = 0;
|
||||
zonesummon_ignorerestrictions = 0;
|
||||
zoning = false;
|
||||
bZoning = false;
|
||||
zone_mode = ZoneUnsolicited;
|
||||
casting_spell_id = 0;
|
||||
npcflag = false;
|
||||
@@ -395,7 +395,7 @@ Client::~Client() {
|
||||
GetTarget()->IsTargeted(-1);
|
||||
|
||||
//if we are in a group and we are not zoning, force leave the group
|
||||
if(isgrouped && !zoning && is_zone_loaded)
|
||||
if(isgrouped && !bZoning && is_zone_loaded)
|
||||
LeaveGroup();
|
||||
|
||||
UpdateWho(2);
|
||||
|
||||
+6
-1
@@ -606,6 +606,10 @@ public:
|
||||
uint32 GetExperienceForKill(Mob *against);
|
||||
void AddEXP(uint32 in_add_exp, uint8 conlevel = 0xFF, bool resexp = false);
|
||||
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 AddLevelBasedExp(uint8 exp_percentage, uint8 max_level=0);
|
||||
void SetLeadershipEXP(uint32 group_exp, uint32 raid_exp);
|
||||
@@ -651,6 +655,7 @@ public:
|
||||
void Sacrifice(Client* caster);
|
||||
void GoToDeath();
|
||||
inline const int32 GetInstanceID() const { return zone->GetInstanceID(); }
|
||||
void SetZoning(bool in) { bZoning = in; }
|
||||
|
||||
FACTION_VALUE GetReverseFactionCon(Mob* iOther);
|
||||
FACTION_VALUE GetFactionLevel(uint32 char_id, uint32 npc_id, uint32 p_race, uint32 p_class, uint32 p_deity, int32 pFaction, Mob* tnpc);
|
||||
@@ -1542,7 +1547,7 @@ private:
|
||||
bool npcflag;
|
||||
uint8 npclevel;
|
||||
bool feigned;
|
||||
bool zoning;
|
||||
bool bZoning;
|
||||
bool tgb;
|
||||
bool instalog;
|
||||
int32 last_reported_mana;
|
||||
|
||||
@@ -264,7 +264,7 @@ bool Client::Process() {
|
||||
if (distance <= scan_range) {
|
||||
close_mobs.insert(std::pair<Mob *, float>(mob, distance));
|
||||
}
|
||||
else if (mob->GetAggroRange() > scan_range) {
|
||||
else if ((mob->GetAggroRange() * mob->GetAggroRange()) > scan_range) {
|
||||
close_mobs.insert(std::pair<Mob *, float>(mob, distance));
|
||||
}
|
||||
}
|
||||
@@ -655,17 +655,17 @@ bool Client::Process() {
|
||||
{
|
||||
//client logged out or errored out
|
||||
//ResetTrade();
|
||||
if (client_state != CLIENT_KICKED && !zoning && !instalog) {
|
||||
if (client_state != CLIENT_KICKED && !bZoning && !instalog) {
|
||||
Save();
|
||||
}
|
||||
|
||||
client_state = CLIENT_LINKDEAD;
|
||||
if (zoning || instalog || GetGM())
|
||||
if (bZoning || instalog || GetGM())
|
||||
{
|
||||
Group *mygroup = GetGroup();
|
||||
if (mygroup)
|
||||
{
|
||||
if (!zoning)
|
||||
if (!bZoning)
|
||||
{
|
||||
entity_list.MessageGroup(this, true, 15, "%s logged out.", GetName());
|
||||
LeaveGroup();
|
||||
@@ -684,7 +684,7 @@ bool Client::Process() {
|
||||
Raid *myraid = entity_list.GetRaidByClient(this);
|
||||
if (myraid)
|
||||
{
|
||||
if (!zoning)
|
||||
if (!bZoning)
|
||||
{
|
||||
//entity_list.MessageGroup(this,true,15,"%s logged out.",GetName());
|
||||
myraid->MemberZoned(this);
|
||||
|
||||
+400
-398
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -3257,7 +3257,7 @@ void EntityList::AddHealAggro(Mob *target, Mob *caster, uint16 hate)
|
||||
|
||||
for (auto &e : npc_list) {
|
||||
auto &npc = e.second;
|
||||
if (!npc->CheckAggro(target) || npc->IsFeared())
|
||||
if (!npc->CheckAggro(target) || npc->IsFeared() || npc->IsPet())
|
||||
continue;
|
||||
|
||||
if (zone->random.Roll(50)) // witness check -- place holder
|
||||
|
||||
+295
-142
@@ -37,6 +37,49 @@
|
||||
|
||||
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)
|
||||
{
|
||||
@@ -174,192 +217,302 @@ uint32 Client::GetExperienceForKill(Mob *against)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Client::AddEXP(uint32 in_add_exp, uint8 conlevel, bool resexp) {
|
||||
float static GetConLevelModifierPercent(uint8 conlevel)
|
||||
{
|
||||
switch (conlevel)
|
||||
{
|
||||
case CON_GREEN:
|
||||
return (float)RuleI(Character, GreenModifier) / 100;
|
||||
break;
|
||||
case CON_LIGHTBLUE:
|
||||
return (float)RuleI(Character, LightBlueModifier) / 100;
|
||||
break;
|
||||
case CON_BLUE:
|
||||
return (float)RuleI(Character, BlueModifier) / 100;
|
||||
break;
|
||||
case CON_WHITE:
|
||||
return (float)RuleI(Character, WhiteModifier) / 100;
|
||||
break;
|
||||
case CON_YELLOW:
|
||||
return (float)RuleI(Character, YellowModifier) / 100;
|
||||
break;
|
||||
case CON_RED:
|
||||
return (float)RuleI(Character, RedModifier) / 100;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
void Client::CalculateNormalizedAAExp(uint32 &add_aaxp, uint8 conlevel, bool resexp)
|
||||
{
|
||||
// Functionally this is the same as having the case in the switch, but this is
|
||||
// cleaner to read.
|
||||
if (CON_GRAY == conlevel || resexp)
|
||||
{
|
||||
add_aaxp = 0;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
float aatotalmod = 1.0;
|
||||
if (zone->newzone_data.zone_exp_multiplier >= 0) {
|
||||
aatotalmod *= zone->newzone_data.zone_exp_multiplier;
|
||||
}
|
||||
|
||||
// Shouldn't race not affect AA XP?
|
||||
if (RuleB(Character, UseRaceClassExpBonuses))
|
||||
{
|
||||
if (GetBaseRace() == HALFLING) {
|
||||
aatotalmod *= 1.05;
|
||||
}
|
||||
|
||||
if (GetClass() == ROGUE || GetClass() == WARRIOR) {
|
||||
aatotalmod *= 1.05;
|
||||
}
|
||||
}
|
||||
|
||||
// why wasn't this here? Where should it be?
|
||||
if (zone->IsHotzone())
|
||||
{
|
||||
aatotalmod += RuleR(Zone, HotZoneBonus);
|
||||
}
|
||||
|
||||
if (RuleB(Zone, LevelBasedEXPMods)) {
|
||||
if (zone->level_exp_mod[GetLevel()].ExpMod) {
|
||||
add_aaxp *= zone->level_exp_mod[GetLevel()].AAExpMod;
|
||||
}
|
||||
}
|
||||
|
||||
add_aaxp = (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){
|
||||
if (RuleR(Character, ExpMultiplier) >= 0) {
|
||||
totalmod *= RuleR(Character, ExpMultiplier);
|
||||
}
|
||||
|
||||
if(zone->newzone_data.zone_exp_multiplier >= 0){
|
||||
//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 (RuleB(Character, UseRaceClassExpBonuses))
|
||||
{
|
||||
if(GetBaseRace() == HALFLING){
|
||||
if (GetBaseRace() == HALFLING) {
|
||||
totalmod *= 1.05;
|
||||
}
|
||||
|
||||
if(GetClass() == ROGUE || GetClass() == WARRIOR){
|
||||
if (GetClass() == ROGUE || GetClass() == WARRIOR) {
|
||||
totalmod *= 1.05;
|
||||
}
|
||||
}
|
||||
|
||||
if(zone->IsHotzone())
|
||||
//add hotzone modifier if one has been set.
|
||||
if (zone->IsHotzone())
|
||||
{
|
||||
totalmod += RuleR(Zone, HotZoneBonus);
|
||||
}
|
||||
|
||||
add_exp = uint32(float(add_exp) * totalmod * zemmod);
|
||||
|
||||
if(RuleB(Character,UseXPConScaling))
|
||||
//if XP scaling is based on the con of a monster, do that now.
|
||||
if (RuleB(Character, UseXPConScaling))
|
||||
{
|
||||
if (conlevel != 0xFF && !resexp) {
|
||||
switch (conlevel)
|
||||
{
|
||||
case CON_GRAY:
|
||||
add_exp = 0;
|
||||
add_aaxp = 0;
|
||||
return;
|
||||
case CON_GREEN:
|
||||
add_exp = add_exp * RuleI(Character, GreenModifier) / 100;
|
||||
add_aaxp = add_aaxp * RuleI(Character, GreenModifier) / 100;
|
||||
break;
|
||||
case CON_LIGHTBLUE:
|
||||
add_exp = add_exp * RuleI(Character, LightBlueModifier)/100;
|
||||
add_aaxp = add_aaxp * RuleI(Character, LightBlueModifier)/100;
|
||||
break;
|
||||
case CON_BLUE:
|
||||
add_exp = add_exp * RuleI(Character, BlueModifier)/100;
|
||||
add_aaxp = add_aaxp * RuleI(Character, BlueModifier)/100;
|
||||
break;
|
||||
case CON_WHITE:
|
||||
add_exp = add_exp * RuleI(Character, WhiteModifier)/100;
|
||||
add_aaxp = add_aaxp * RuleI(Character, WhiteModifier)/100;
|
||||
break;
|
||||
case CON_YELLOW:
|
||||
add_exp = add_exp * RuleI(Character, YellowModifier)/100;
|
||||
add_aaxp = add_aaxp * RuleI(Character, YellowModifier)/100;
|
||||
break;
|
||||
case CON_RED:
|
||||
add_exp = add_exp * RuleI(Character, RedModifier)/100;
|
||||
add_aaxp = add_aaxp * RuleI(Character, RedModifier)/100;
|
||||
break;
|
||||
}
|
||||
if (conlevel != 0xFF && !resexp)
|
||||
{
|
||||
add_exp = add_exp * GetConLevelModifierPercent(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Calculate any changes to leadership experience.
|
||||
CalculateLeadershipExp(add_exp, conlevel);
|
||||
} //end !resexp
|
||||
|
||||
float aatotalmod = 1.0;
|
||||
if(zone->newzone_data.zone_exp_multiplier >= 0){
|
||||
aatotalmod *= zone->newzone_data.zone_exp_multiplier;
|
||||
}
|
||||
|
||||
// Shouldn't race not affect AA XP?
|
||||
if(RuleB(Character,UseRaceClassExpBonuses))
|
||||
{
|
||||
if(GetBaseRace() == HALFLING){
|
||||
aatotalmod *= 1.05;
|
||||
}
|
||||
|
||||
if(GetClass() == ROGUE || GetClass() == WARRIOR){
|
||||
aatotalmod *= 1.05;
|
||||
}
|
||||
}
|
||||
|
||||
// why wasn't this here? Where should it be?
|
||||
if(zone->IsHotzone())
|
||||
{
|
||||
aatotalmod += RuleR(Zone, HotZoneBonus);
|
||||
}
|
||||
|
||||
if(RuleB(Zone, LevelBasedEXPMods)){
|
||||
if(zone->level_exp_mod[GetLevel()].ExpMod){
|
||||
if (RuleB(Zone, LevelBasedEXPMods)) {
|
||||
if (zone->level_exp_mod[GetLevel()].ExpMod) {
|
||||
add_exp *= zone->level_exp_mod[GetLevel()].ExpMod;
|
||||
add_aaxp *= zone->level_exp_mod[GetLevel()].AAExpMod;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 exp = GetEXP() + add_exp;
|
||||
add_exp = GetEXP() + add_exp;
|
||||
}
|
||||
|
||||
uint32 aaexp = (uint32)(RuleR(Character, AAExpMultiplier) * add_aaxp * aatotalmod);
|
||||
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();
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -336,7 +336,8 @@ void NPC::AddLootDrop(const EQEmu::ItemData *item2, ItemList* itemlist, int16 ch
|
||||
eslot = EQEmu::textures::weaponPrimary;
|
||||
if (item2->Damage > 0) {
|
||||
SendAddPlayerState(PlayerState::PrimaryWeaponEquipped);
|
||||
SetFacestab(true);
|
||||
if (!RuleB(Combat, ClassicNPCBackstab))
|
||||
SetFacestab(true);
|
||||
}
|
||||
if (item2->IsType2HWeapon())
|
||||
SetTwoHanderEquipped(true);
|
||||
|
||||
+24
-4
@@ -127,7 +127,7 @@ bool NPC::AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes) {
|
||||
}
|
||||
case SpellType_Root: {
|
||||
Mob *rootee = GetHateRandom();
|
||||
if (rootee && !rootee->IsRooted() && zone->random.Roll(50)
|
||||
if (rootee && !rootee->IsRooted() && !rootee->IsFeared() && zone->random.Roll(50)
|
||||
&& rootee->DontRootMeBefore() < Timer::GetCurrentTime()
|
||||
&& rootee->CanBuffStack(AIspells[i].spellid, GetLevel(), true) >= 0
|
||||
) {
|
||||
@@ -1391,19 +1391,33 @@ void Mob::AI_Process() {
|
||||
//if(owner->IsClient())
|
||||
// printf("Pet start pos: (%f, %f, %f)\n", GetX(), GetY(), GetZ());
|
||||
|
||||
float dist = DistanceSquared(m_Position, owner->GetPosition());
|
||||
if (dist >= 400)
|
||||
glm::vec4 ownerPos = owner->GetPosition();
|
||||
float dist = DistanceSquared(m_Position, ownerPos);
|
||||
float distz = ownerPos.z - m_Position.z;
|
||||
|
||||
if (dist >= 400 || distz > 100)
|
||||
{
|
||||
int speed = GetWalkspeed();
|
||||
if (dist >= 5625)
|
||||
speed = GetRunspeed();
|
||||
|
||||
CalculateNewPosition2(owner->GetX(), owner->GetY(), owner->GetZ(), speed);
|
||||
if (distz > 100)
|
||||
{
|
||||
m_Position = ownerPos;
|
||||
SendPositionUpdate();
|
||||
moved = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
CalculateNewPosition2(owner->GetX(),
|
||||
owner->GetY(), owner->GetZ(), speed);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(moved)
|
||||
{
|
||||
this->FixZ();
|
||||
SetCurrentSpeed(0);
|
||||
moved = false;
|
||||
}
|
||||
@@ -1748,6 +1762,12 @@ void Mob::AI_Event_Engaged(Mob* attacker, bool iYellForHelp) {
|
||||
|
||||
SetAppearance(eaStanding);
|
||||
|
||||
/*
|
||||
Kick off auto cast timer
|
||||
*/
|
||||
if (this->IsNPC())
|
||||
this->CastToNPC()->AIautocastspell_timer->Start(300, false);
|
||||
|
||||
if (iYellForHelp) {
|
||||
if(IsPet()) {
|
||||
GetOwner()->AI_Event_Engaged(attacker, iYellForHelp);
|
||||
|
||||
+3
-1
@@ -420,6 +420,8 @@ public:
|
||||
|
||||
bool IgnoreDespawn() { return ignore_despawn; }
|
||||
|
||||
std::unique_ptr<Timer> AIautocastspell_timer;
|
||||
|
||||
protected:
|
||||
|
||||
const NPCType* NPCTypedata;
|
||||
@@ -453,7 +455,7 @@ protected:
|
||||
|
||||
uint32 npc_spells_id;
|
||||
uint8 casting_spell_AIindex;
|
||||
std::unique_ptr<Timer> AIautocastspell_timer;
|
||||
|
||||
uint32* pDontCastBefore_casting_spell;
|
||||
std::vector<AISpells_Struct> AIspells;
|
||||
bool HasAISpell;
|
||||
|
||||
+9
-4
@@ -655,10 +655,15 @@ void NPC::SetPetState(SpellBuff_Struct *pet_buffs, uint32 *items) {
|
||||
continue;
|
||||
|
||||
const EQEmu::ItemData* item2 = database.GetItem(items[i]);
|
||||
if (item2 && item2->NoDrop != 0) {
|
||||
//dont bother saving item charges for now, NPCs never use them
|
||||
//and nobody should be able to get them off the corpse..?
|
||||
AddLootDrop(item2, &itemlist, 0, 1, 255, true, true);
|
||||
|
||||
if (item2) {
|
||||
bool noDrop=(item2->NoDrop == 0); // Field is reverse logic
|
||||
bool petCanHaveNoDrop = (RuleB(Pets, CanTakeNoDrop) &&
|
||||
_CLIENTPET(this) && GetPetType() <= petOther);
|
||||
|
||||
if (!noDrop || petCanHaveNoDrop) {
|
||||
AddLootDrop(item2, &itemlist, 0, 1, 255, true, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1796,8 +1796,12 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
||||
Message_StringID(4, CORPSE_CANT_SENSE);
|
||||
}
|
||||
}
|
||||
else if (caster)
|
||||
caster->Message_StringID(MT_SpellFailure, SPELL_LEVEL_REQ);
|
||||
else if (caster) {
|
||||
char level[4];
|
||||
ConvertArray(effect_value, level);
|
||||
caster->Message_StringID(MT_SpellFailure,
|
||||
SPELL_LEVEL_REQ, level);
|
||||
}
|
||||
}
|
||||
else {
|
||||
Message_StringID(4, TARGET_NOT_FOUND);
|
||||
|
||||
+5
-3
@@ -523,7 +523,6 @@ void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, st
|
||||
else
|
||||
qs_audit->char1_count += detail->charges;
|
||||
|
||||
//for (uint8 sub_slot = SUB_BEGIN; ((sub_slot < inst->GetItem()->BagSlots) && (sub_slot < EmuConstants::ITEM_CONTAINER_SIZE)); ++sub_slot) {
|
||||
for (uint8 sub_slot = EQEmu::inventory::containerBegin; (sub_slot < EQEmu::inventory::ContainerCount); ++sub_slot) { // this is to catch ALL items
|
||||
const EQEmu::ItemInstance* bag_inst = inst->GetItem(sub_slot);
|
||||
|
||||
@@ -743,7 +742,6 @@ void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, st
|
||||
qs_audit->char1_count += detail->charges;
|
||||
|
||||
// 'step 3' should never really see containers..but, just in case...
|
||||
//for (uint8 sub_slot = SUB_BEGIN; ((sub_slot < inst->GetItem()->BagSlots) && (sub_slot < EmuConstants::ITEM_CONTAINER_SIZE)); ++sub_slot) {
|
||||
for (uint8 sub_slot = EQEmu::inventory::containerBegin; (sub_slot < EQEmu::inventory::ContainerCount); ++sub_slot) { // this is to catch ALL items
|
||||
const EQEmu::ItemInstance* bag_inst = inst->GetItem(sub_slot);
|
||||
|
||||
@@ -888,8 +886,12 @@ void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, st
|
||||
|
||||
const EQEmu::ItemData* item = inst->GetItem();
|
||||
if(item && quest_npc == false) {
|
||||
bool isPetAndCanHaveNoDrop = (RuleB(Pets, CanTakeNoDrop) &&
|
||||
_CLIENTPET(tradingWith) &&
|
||||
tradingWith->GetPetType()<=petOther);
|
||||
// if it was not a NO DROP or Attuned item (or if a GM is trading), let the NPC have it
|
||||
if(GetGM() || (item->NoDrop != 0 && inst->IsAttuned() == false)) {
|
||||
if(GetGM() || (inst->IsAttuned() == false &&
|
||||
(item->NoDrop != 0 || isPetAndCanHaveNoDrop))) {
|
||||
// pets need to look inside bags and try to equip items found there
|
||||
if (item->IsClassBag() && item->BagSlots > 0) {
|
||||
for (int16 bslot = EQEmu::inventory::containerBegin; bslot < item->BagSlots; bslot++) {
|
||||
|
||||
+1
-1
@@ -884,7 +884,7 @@ void Mob::FixZ(int32 z_find_offset /*= 5*/)
|
||||
glm::vec3 current_loc(m_Position);
|
||||
float new_z = GetFixedZ(current_loc, z_find_offset);
|
||||
|
||||
if (new_z != m_Position.z)
|
||||
if (!IsClient() && new_z != m_Position.z)
|
||||
{
|
||||
if ((new_z > -2000) && new_z != BEST_Z_INVALID) {
|
||||
if (RuleB(Map, MobZVisualDebug))
|
||||
|
||||
@@ -338,6 +338,7 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
|
||||
if (ztz->response <= 0) {
|
||||
zc2->success = ZONE_ERROR_NOTREADY;
|
||||
entity->CastToMob()->SetZone(ztz->current_zone_id, ztz->current_instance_id);
|
||||
entity->CastToClient()->SetZoning(false);
|
||||
}
|
||||
else {
|
||||
entity->CastToClient()->UpdateWho(1);
|
||||
|
||||
+1
-1
@@ -1515,7 +1515,7 @@ void Zone::Repop(uint32 delay) {
|
||||
void Zone::GetTimeSync()
|
||||
{
|
||||
if (worldserver.Connected() && !zone_has_current_time) {
|
||||
auto pack = new ServerPacket(ServerOP_GetWorldTime, 0);
|
||||
auto pack = new ServerPacket(ServerOP_GetWorldTime, 1);
|
||||
worldserver.SendPacket(pack);
|
||||
safe_delete(pack);
|
||||
}
|
||||
|
||||
+1
-1
@@ -49,7 +49,7 @@ class ZoneConfig : public EQEmuConfig {
|
||||
_zone_config=new ZoneConfig;
|
||||
_config=_zone_config;
|
||||
|
||||
return _config->ParseFile(EQEmuConfig::ConfigFile.c_str(),"server");
|
||||
return _config->parseFile();
|
||||
}
|
||||
|
||||
// Accessors for the static private object
|
||||
|
||||
+5
-1
@@ -42,7 +42,7 @@ void Client::Handle_OP_ZoneChange(const EQApplicationPacket *app) {
|
||||
Bot::ProcessClientZoneChange(this);
|
||||
#endif
|
||||
|
||||
zoning = true;
|
||||
bZoning = true;
|
||||
if (app->size != sizeof(ZoneChange_Struct)) {
|
||||
Log(Logs::General, Logs::None, "Wrong size: OP_ZoneChange, size=%d, expected %d", app->size, sizeof(ZoneChange_Struct));
|
||||
return;
|
||||
@@ -308,6 +308,8 @@ void Client::SendZoneCancel(ZoneChange_Struct *zc) {
|
||||
|
||||
//reset to unsolicited.
|
||||
zone_mode = ZoneUnsolicited;
|
||||
// reset since we're not zoning anymore
|
||||
bZoning = false;
|
||||
}
|
||||
|
||||
void Client::SendZoneError(ZoneChange_Struct *zc, int8 err)
|
||||
@@ -327,6 +329,8 @@ void Client::SendZoneError(ZoneChange_Struct *zc, int8 err)
|
||||
|
||||
//reset to unsolicited.
|
||||
zone_mode = ZoneUnsolicited;
|
||||
// reset since we're not zoning anymore
|
||||
bZoning = false;
|
||||
}
|
||||
|
||||
void Client::DoZoneSuccess(ZoneChange_Struct *zc, uint16 zone_id, uint32 instance_id, float dest_x, float dest_y, float dest_z, float dest_h, int8 ignore_r) {
|
||||
|
||||
Reference in New Issue
Block a user