[Feature] Implemented /shield ability and related affects (#1494)

* shield ability initial work

* updates

* update

* updates

* Update client_process.cpp

* major updates

optimized
pet support
perl support

* updates

* minor update

* fix merge error

* requested changes

* variable fix

* optimization

* minor update

* Revert "optimization"

This reverts commit 27e11e758b.

* fix

reset variables on shield_target if shielder dies or zones during shielding.

* edge case fix

Catch and fix situations where shield target doesn't have shielder variable cleared. Can occur if shielder . uses ability when target is not in combat then zones.

* combined packet and mob function

Shield now uses a common pathway through ShieldAbility, added parameters to perl function

* Addressing formatting for Kayen

* Fix function typo

Co-authored-by: Akkadius <akkadius1@gmail.com>
This commit is contained in:
KayenEQ
2021-08-15 23:59:10 -04:00
committed by GitHub
parent 9c62bf3c2f
commit d40d21121a
15 changed files with 363 additions and 191 deletions
+126 -9
View File
@@ -261,7 +261,6 @@ Mob::Mob(
MR = CR = FR = DR = PR = Corrup = PhR = 0;
ExtraHaste = 0;
bEnraged = false;
shield_target = nullptr;
current_mana = 0;
max_mana = 0;
hp_regen = in_hp_regen;
@@ -376,11 +375,13 @@ Mob::Mob(
silenced = false;
amnesiad = false;
inWater = false;
int m;
for (m = 0; m < MAX_SHIELDERS; m++) {
shielder[m].shielder_id = 0;
shielder[m].shielder_bonus = 0;
}
shield_timer.Disable();
m_shield_target_id = 0;
m_shielder_id = 0;
m_shield_target_mitigation = 0;
m_shielder_mitigation = 0;
m_shielder_max_distance = 0;
destructibleobject = false;
wandertype = 0;
@@ -3144,7 +3145,7 @@ int32 Mob::GetActSpellCasttime(uint16 spell_id, int32 casttime)
cast_reducer += cast_reducer_no_limit;
casttime = casttime * (100 - cast_reducer) / 100;
casttime -= cast_reducer_amt;
return std::max(casttime, 0);
}
@@ -4944,11 +4945,11 @@ int16 Mob::GetPositionalDmgAmt(Mob* defender)
if (back_arc_dmg_amt || front_arc_dmg_amt) {
if (BehindMob(defender, GetX(), GetY()))
total_amt = back_arc_dmg_amt;
total_amt = back_arc_dmg_amt;
else
total_amt = front_arc_dmg_amt;
}
return total_amt;
}
@@ -6196,6 +6197,122 @@ float Mob::GetDefaultRaceSize() const {
return GetRaceGenderDefaultHeight(race, gender);
}
bool Mob::ShieldAbility(uint32 target_id, int shielder_max_distance, int shield_duration, int shield_target_mitigation, int shielder_mitigation, bool use_aa, bool can_shield_npc)
{
Mob* shield_target = entity_list.GetMob(target_id);
if (!shield_target) {
return false;
}
if (!can_shield_npc && shield_target->IsNPC()) {
if (IsClient()) {
MessageString(Chat::White, SHIELD_TARGET_NPC);
}
return false;
}
if (shield_target->GetID() == GetID()) { //Client will give message "You can not shield yourself"
return false;
}
//Edge case situations. If 'Shield Target' still has Shielder set but Shielder is not in zone. Catch and fix here.
if (shield_target->GetShielderID() && !entity_list.GetMob(shield_target->GetShielderID())) {
shield_target->SetShielderID(0);
}
if (GetShielderID() && !entity_list.GetMob(GetShielderID())) {
SetShielderID(0);
}
//You have a shielder, or your 'Shield Target' already has a 'Shielder'
if (GetShielderID() || shield_target->GetShielderID()) {
if (IsClient()) {
MessageString(Chat::White, ALREADY_SHIELDED);
}
return false;
}
//You are being shielded or already have a 'Shield Target'
if (GetShieldTargetID() || shield_target->GetShieldTargetID()) {
if (IsClient()) {
MessageString(Chat::White, ALREADY_SHIELDING);
}
return false;
}
//AA to increase SPA 230 extended shielding (default live is 15 distance units)
if (use_aa) {
shielder_max_distance += aabonuses.ExtendedShielding + itembonuses.ExtendedShielding + spellbonuses.ExtendedShielding;
shielder_max_distance = std::max(shielder_max_distance, 0);
}
if (shield_target->CalculateDistance(GetX(), GetY(), GetZ()) > static_cast<float>(shielder_max_distance)) {
return false; //Live does not give a message when out of range.
}
entity_list.MessageCloseString(this, false, 100, 0, START_SHIELDING, GetCleanName(), shield_target->GetCleanName());
SetShieldTargetID(shield_target->GetID());
SetShielderMitigation(shield_target_mitigation);
SetShielderMaxDistance(shielder_max_distance);
shield_target->SetShielderID(GetID());
shield_target->SetShieldTargetMitigation(shield_target_mitigation);
//Calculate AA for adding time SPA 255 extend shield duration (Baseline ability is 12 seconds)
if (use_aa) {
shield_duration += (aabonuses.ShieldDuration + itembonuses.ShieldDuration + spellbonuses.ShieldDuration) * 1000;
shield_duration = std::max(shield_duration, 1); //Incase of negative modifiers lets just make min duration 1 ms.
}
shield_timer.Start(static_cast<uint32>(shield_duration));
return true;
}
void Mob::ShieldAbilityFinish()
{
Mob* shield_target = entity_list.GetMob(GetShieldTargetID());
if (shield_target) {
entity_list.MessageCloseString(this, false, 100, 0, END_SHIELDING, GetCleanName(), shield_target->GetCleanName());
shield_target->SetShielderID(0);
shield_target->SetShieldTargetMitigation(0);
}
SetShieldTargetID(0);
SetShielderMitigation(0);
SetShielderMaxDistance(0);
shield_timer.Disable();
}
void Mob::ShieldAbilityClearVariables()
{
//If 'shield target' dies
if (GetShielderID()){
Mob* shielder = entity_list.GetMob(GetShielderID());
if (shielder) {
shielder->SetShieldTargetID(0);
shielder->SetShielderMitigation(0);
shielder->SetShielderMaxDistance(0);
shielder->shield_timer.Disable();
}
SetShielderID(0);
SetShieldTargetMitigation(0);
}
//If 'shielder' dies
if (GetShieldTargetID()) {
Mob* shield_target = entity_list.GetMob(GetShieldTargetID());
if (shield_target) {
shield_target->SetShielderID(0);
shield_target->SetShieldTargetMitigation(0);
}
SetShieldTargetID(0);
SetShielderMitigation(0);
SetShielderMaxDistance(0);
shield_timer.Disable();
}
}
#ifdef BOTS
bool Mob::JoinHealRotationTargetPool(std::shared_ptr<HealRotation>* heal_rotation)
{