int Client::GroupLeadershipAAHealthRegeneration() { if (IsRaidGrouped()) { int bonus = 0; Raid *raid = GetRaid(); if (!raid) return 0; uint32 group_id = raid->GetGroup(this); if (group_id < 12 && raid->GroupCount(group_id) >= 3) { switch (raid->GetLeadershipAA(groupAAHealthRegeneration, group_id)) { case 1: bonus = 4; break; case 2: bonus = 6; break; case 3: bonus = 8; break; } } if (raid->RaidCount() >= 18) { switch (raid->GetLeadershipAA(raidAAHealthRegeneration)) { case 1: bonus += 4; break; case 2: bonus += 6; break; case 3: bonus += 8; break; } } return bonus; } Group *g = GetGroup(); if(!g || (g->GroupCount() < 3)) return 0; switch(g->GetLeadershipAA(groupAAHealthRegeneration)) { case 0: return 0; case 1: return 4; case 2: return 6; case 3: return 8; } return 0; }
int Client::GroupLeadershipAAManaEnhancement() { if (IsRaidGrouped()) { int bonus = 0; Raid *raid = GetRaid(); if (!raid) return 0; uint32 group_id = raid->GetGroup(this); if (group_id < 12 && raid->GroupCount(group_id) >= 3) { switch (raid->GetLeadershipAA(groupAAManaEnhancement, group_id)) { case 1: bonus = 30; break; case 2: bonus = 60; break; case 3: bonus = 100; break; } } if (raid->RaidCount() >= 18) { switch (raid->GetLeadershipAA(raidAAManaEnhancement)) { case 1: bonus += 30; break; case 2: bonus += 60; break; case 3: bonus += 100; break; } } return bonus; } Group *g = GetGroup(); if(!g || (g->GroupCount() < 3)) return 0; switch(g->GetLeadershipAA(groupAAManaEnhancement)) { case 0: return 0; case 1: return 30; case 2: return 60; case 3: return 100; } return 0; }
bool Aura::ShouldISpawnFor(Client *c) { if (spawn_type == AuraSpawns::Noone) return false; if (spawn_type == AuraSpawns::Everyone) return true; // hey, it's our owner! if (c->GetID() == m_owner) return true; // so this one is a bit trickier auto owner = GetOwner(); if (owner == nullptr) return false; // hmm owner = owner->GetOwnerOrSelf(); // pet auras we need the pet's owner if (owner == nullptr) // shouldn't really be needed return false; // gotta check again for pet aura case -.- if (owner == c) return true; if (owner->IsRaidGrouped() && owner->IsClient()) { auto raid = owner->GetRaid(); if (raid == nullptr) return false; // hmm auto group_id = raid->GetGroup(owner->CastToClient()); if (group_id == 0xFFFFFFFF) // owner handled above, and they're in a raid and groupless return false; auto idx = raid->GetPlayerIndex(c); if (idx == 0xFFFFFFFF) // they're not in our raid! return false; if (raid->members[idx].GroupNumber != group_id) // in our raid, but not our group return false; return true; // we got here so we know that 1 they're in our raid and 2 they're in our group! } else if (owner->IsGrouped()) { auto group = owner->GetGroup(); if (group == nullptr) return false; // hmm // easy, in our group return group->IsGroupMember(c); } // our owner is not raided or grouped, and they're handled above so we don't spawn! return false; }
void Aura::ProcessOnGroupMembersPets(Mob *owner) { auto &mob_list = entity_list.GetMobList(); // read only reference so we can do it all inline std::set<int> delayed_remove; bool is_buff = IsBuffSpell(spell_id); // non-buff spells don't cast on enter // This type can either live on the pet (level 55/70 MAG aura) or on the pet owner (level 85 MAG aura) auto group_member = owner->GetOwnerOrSelf(); if (group_member->IsRaidGrouped() && group_member->IsClient()) { // currently raids are just client, but safety check auto raid = group_member->GetRaid(); if (raid == nullptr) { // well shit owner->RemoveAura(GetID(), false, true); return; } auto group_id = raid->GetGroup(group_member->CastToClient()); // some lambdas so the for loop is less horrible ... auto verify_raid_client_pet = [&raid, &group_id, &group_member, this](Mob *m) { auto idx = raid->GetPlayerIndex(m->GetOwner()->CastToClient()); if (m->GetOwner()->GetID() == group_member->GetID()) { return DistanceSquared(GetPosition(), m->GetPosition()) <= distance; } else if (idx == 0xFFFFFFFF || raid->members[idx].GroupNumber != group_id || raid->members[idx].GroupNumber == 0xFFFFFFFF) { return false; } else if (DistanceSquared(GetPosition(), m->GetPosition()) > distance) { return false; } return true; }; auto verify_raid_client_swarm = [&raid, &group_id, &group_member, this](NPC *n) { auto owner = entity_list.GetMob(n->GetSwarmOwner()); if (owner == nullptr) return false; auto idx = raid->GetPlayerIndex(owner->CastToClient()); if (owner->GetID() == group_member->GetID()) { return DistanceSquared(GetPosition(), n->GetPosition()) <= distance; } else if (idx == 0xFFFFFFFF || raid->members[idx].GroupNumber != group_id || raid->members[idx].GroupNumber == 0xFFFFFFFF) { return false; } else if (DistanceSquared(GetPosition(), n->GetPosition()) > distance) { return false; } return true; }; for (auto &e : mob_list) { auto mob = e.second; // step 1: check if we're already managing this NPC's buff auto it = casted_on.find(mob->GetID()); if (it != casted_on.end()) { // verify still good! if (mob->IsPet() && mob->IsPetOwnerClient() && mob->GetOwner()) { if (!verify_raid_client_pet(mob)) delayed_remove.insert(mob->GetID()); } else if (mob->IsNPC() && mob->IsPetOwnerClient()) { auto npc = mob->CastToNPC(); if (!verify_raid_client_swarm(npc)) delayed_remove.insert(mob->GetID()); } } else { // we're not on it! if (mob->IsClient()) { continue; // never hit client } else if (mob->IsPet() && mob->IsPetOwnerClient() && mob->GetOwner() && verify_raid_client_pet(mob)) { casted_on.insert(mob->GetID()); if (is_buff) SpellFinished(spell_id, mob); } else if (mob->IsNPC() && mob->IsPetOwnerClient()) { auto npc = mob->CastToNPC(); if (verify_raid_client_swarm(npc)) { casted_on.insert(mob->GetID()); if (is_buff) SpellFinished(spell_id, mob); } } } } } else if (group_member->IsGrouped()) { auto group = group_member->GetGroup(); if (group == nullptr) { // uh oh owner->RemoveAura(GetID(), false, true); return; } // lambdas to make for loop less ugly auto verify_group_pet = [&group, this](Mob *m) { auto owner = m->GetOwner(); if (owner != nullptr && group->IsGroupMember(owner) && DistanceSquared(GetPosition(), m->GetPosition()) <= distance) return true; return false; }; auto verify_group_swarm = [&group, this](NPC *n) { auto owner = entity_list.GetMob(n->GetSwarmOwner()); if (owner != nullptr && group->IsGroupMember(owner) && DistanceSquared(GetPosition(), n->GetPosition()) <= distance) return true; return false; }; for (auto &e : mob_list) { auto mob = e.second; auto it = casted_on.find(mob->GetID()); if (it != casted_on.end()) { // make sure we're still valid if (mob->IsPet()) { if (!verify_group_pet(mob)) delayed_remove.insert(mob->GetID()); } else if (mob->IsNPC() && mob->CastToNPC()->GetSwarmInfo()) { if (!verify_group_swarm(mob->CastToNPC())) delayed_remove.insert(mob->GetID()); } } else { // not on, check if we should be! if (mob->IsClient()) { continue; } else if (mob->IsPet() && verify_group_pet(mob)) { casted_on.insert(mob->GetID()); if (is_buff) SpellFinished(spell_id, mob); } else if (mob->IsNPC() && mob->CastToNPC()->GetSwarmInfo() && verify_group_swarm(mob->CastToNPC())) { casted_on.insert(mob->GetID()); if (is_buff) SpellFinished(spell_id, mob); } } } } else { auto verify_solo = [&group_member, this](Mob *m) { if (m->IsPet() && m->GetOwnerID() == group_member->GetID()) return true; else if (m->IsNPC() && m->CastToNPC()->GetSwarmOwner() == group_member->GetID()) return true; else return false; }; for (auto &e : mob_list) { auto mob = e.second; auto it = casted_on.find(mob->GetID()); bool good = verify_solo(mob); if (it != casted_on.end()) { // make sure still valid if (!good || DistanceSquared(GetPosition(), mob->GetPosition()) > distance) { delayed_remove.insert(mob->GetID()); } } else if (good && DistanceSquared(GetPosition(), mob->GetPosition()) <= distance) { casted_on.insert(mob->GetID()); if (is_buff) SpellFinished(spell_id, mob); } } } for (auto &e : delayed_remove) { auto mob = entity_list.GetMob(e); if (mob != nullptr && is_buff) // some auras cast instant spells so no need to remove mob->BuffFadeBySpellIDAndCaster(spell_id, GetID()); casted_on.erase(e); } // so if we have a cast timer and our set isn't empty and timer is disabled we need to enable it if (cast_timer.GetDuration() > 0 && !cast_timer.Enabled() && !casted_on.empty()) cast_timer.Start(); if (!cast_timer.Enabled() || !cast_timer.Check()) return; // some auras have to recast (DRU for example, non-buff too) for (auto &e : casted_on) { auto mob = entity_list.GetMob(e); if (mob != nullptr) SpellFinished(spell_id, mob); } }
void Client::AddEXP(uint32 in_add_exp, uint8 conlevel, bool resexp) { 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 ammount 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) { case CON_GREEN: add_exp = 0; add_aaxp = 0; return; 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 (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); } } } } } //end !resexp float aatotalmod = 1.0; if(zone->newzone_data.zone_exp_multiplier >= 0){ aatotalmod *= zone->newzone_data.zone_exp_multiplier; } if(RuleB(Character,UseRaceClassExpBonuses)) { if(GetBaseRace() == HALFLING){ aatotalmod *= 1.05; } if(GetClass() == ROGUE || GetClass() == WARRIOR){ aatotalmod *= 1.05; } } 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; uint32 aaexp = (uint32)(RuleR(Character, AAExpMultiplier) * add_aaxp * aatotalmod); uint32 had_aaexp = GetAAXP(); aaexp += had_aaexp; if(aaexp < had_aaexp) aaexp = had_aaexp; //watch for wrap SetEXP(exp, aaexp, resexp); }