Go Back   EQEmulator Home > EQEmulator Forums > Development > Development::Development

Development::Development Forum for development topics and for those interested in EQEMu development. (Not a support forum)

 
 
Thread Tools Display Modes
Prev Previous Post   Next Post Next
  #14  
Old 06-05-2025, 04:25 AM
Torven
Sarnak
 
Join Date: Aug 2014
Posts: 76
Default

Code:
// CheckResistSpell() from November 29 2000 client.  Decompiled with Ghidra
// Note that many of the subclass references and NULL checks were removed for readability
// Also note that the compiler reuses variables.  I have renamed some variables with multiple names for readability
// A return of 100 means full resist.  0 means full hit

uint __thiscall CheckResistSpell(int this,int spell,byte caster_level,int no_resist_floor,int caster,int spell_id)
{
  byte *first_effect;
  char cVar2;
  ushort race;
  char *spell_slot;
  int iVar5;		// renamed to roll in some places
  int iVar6;
  uint roll;
  short sVar8;
  int iVar9;		// renamed to success_pct, slot and resist_pct depending on use
  bool bVar10;
  byte bVar11;		// renamed to this_level, charm_limit and spell_effect depending on use
  uint resist;
  int local_1c;
  int local_18;
  short level_diff;
  int temp_resist;
  uint final_resist;
  
  final_resist = 0;
  this_level = this->GetLevel();
  local_1c = -1;
  local_18 = -1;
  level_diff = this_level - caster_level;
  if (spell_id == 982) {	// Cazic Touch
    return 0;
  }
  if (spell == 0) {
    return 100;
  }
  if ((*(int *)(caster + 0xf4) == 27)) {	// we think this is body type but not 100% sure.  body type 27 is elementals, so this may be for pets
    caster_level = caster_level + 5;
  }
  
  // Guaranteed resist if spell is a fear and target has discipline 31 active.  This was added in the Nov 15 2000 client
  iVar9 = *(int *)(*(int *)(this + 0xa0) + 0x70);
  if (iVar9 != 0 && *(int *)(iVar9 + 0x2a4) == 31) {	// Fearless disc
    spell_slot = (char *)(spell + 0x1fa);
    do {
      if (*spell_slot != -2 && *spell_slot == SE_23_FEAR) {	// SE -2 seems to denote blank but SE_10_CHARISMA with value 0 is also used to denote blank
        return 100;
      }
      spell_slot = spell_slot + 1;
    } while ((int)(spell_slot + (-0x1fa - spell)) < 4);	// check 4 slots; return 100 if fear is one of the SEs
  }
  
  // Check for mez immunity.  This was moved here from HitBySpell() in the Nov 15 2000 client
  if (caster != NULL) {
    spell_slot = (char *)(spell + 0x1fa);	// first slot
    do {
      if (*spell_slot != -2 && *spell_slot == SE_31_MEZ) {		// -2 means blank
        if (caster->GetClass() == CLASS_8_BARD) {
          if (spell->type_number == 5) {						// single target
            if (spell_id == SPELL_1753_SONG_OF_TWILIGHT) {
              success_pct = 101;
            }
            else if (this_level < 25) {
              success_pct = 95;
            }
            else if (this_level < 30) {
              success_pct = 90;
            }
            else if (this_level < 40) {
              success_pct = 85;
            }
            else if (this_level < 45) {
              success_pct = 75;
            }
            else {
              success_pct = (-(uint)(this_level < 50) & 25) + 40;		// if level < 50 then value is 65, else value is 40
            }
          }
		  // AoE Mez
          else if (this_level < 25) {
            success_pct = 66;
          }
          else if (this_level < 30) {
            success_pct = 50;
          }
          else if (this_level < 40) {
            success_pct = 33;
          }
          else {
            success_pct = (-(uint)(this_level < 45) & 4) + 18;		// if level < 45 then value is 22, else value is 18
          }
          roll = Roll0(0,99);
          if (success_pct <= roll) {
            return 100;
          }
        }
		
		// HitBySpell() still does something like this, oddly, which would theoretically result in duplicate messages.  it does the StunMe() call
        DAT_005a82f4 = 0;
        if (spell_id == SPELL_1692_RAPTURE) {
          DAT_005a82f4 = 1;
        }
        else if (spell_id == SPELL_1691_GLAMOUR_OF_KINTAZ) {
          DAT_005a82f4 = 2;
        }
        iVar9 = IsStunImmune(this);
        if (iVar9 != 0 || (cVar2 = this->GetBodyType(), cVar2 == BODY_29_DRAGON2) || cVar2 == BODY_4_GIANT || cVar2 == BODY_26_DRAGON)
		{
          if (caster->IsNPC() == 0 && caster->IsClient()) {
            if (DAT_005a82f4 == 1) {
              spell_slot = "Your target cannot be mesmerized.";
            }
            else {
              spell_slot = "Your target cannot be mesmerized (with this spell)."
            }
            StringToClient(*(int *)(caster + 0x74),spell_slot,0x121);
          }
          DAT_005a82f4 = 0;
          return 100;
        }
        DAT_005a82f4 = 0;
        break;
      }
      spell_slot = spell_slot + 1;
    } while ((int)(spell_slot + (-0x1fa - spell)) < 4);
  }
  
  // Check for NPC fear immunity and resist all spells under Sancitification disc
  iVar9 = *(int *)(this + 0xa0);
  if (iVar9 != NULL) {
    if (this->IsNPC() == 1 && (*(char *)(this + 0x9eb) == 1)) {		// seems to be some kind of NPC fear immunity flag?
      spell_slot = (char *)(spell + 0x1fa);
      do {
        if (*spell_slot != -2 && *spell_slot == SE_23_FEAR) {
          return 100;
        }
        spell_slot = spell_slot + 1;
      } while ((int)(spell_slot + (-0x1fa - spell)) < 4);
    }
    if (iVar9 != NULL && *(int *)(iVar9 + 0x70) != NULL &&
       *(int *)(*(int *)(iVar9 + 0x70) + 0x2a4) == 23 &&		// Sanctification discipline
       spell->resist_type != 0 && spell->resist_type < 6)		// checking to make sure spell is MR FR CR PR DR
	{
      return 100;
    }
  }
  
  // check for valid spell effects in the first four spell slots (this era is probably limited to 4)
  slot = 0;
  do {
    if (local_1c == -1) {
      iVar5 = IsValidSpellSlot(spell,slot);
      if (iVar5 != 0) {
        local_1c = slot;
      }
    }
    else {
      iVar6 = IsValidSpellSlot(spell,slot);
      iVar5 = slot;
      if (iVar6 != 0) break;		// exit loop as soon as we have found two valid spell slots
    }
    slot = slot + 1;
    iVar5 = -1;				// I changed local_18 to -1 here for readability because local_18 is always -1 here
  } while (slot < 4);
  local_18 = iVar5;			// if iVar5 is -1 here that means the spell has only one effect in it
  if (local_1c == -1) {		// resist spell if no valid spell effects found
    return 100;
  }
  
  cVar2 = spell->resist_type;
  if (cVar2 == SPELL_TYPE_1_MAGIC) {
    temp_resist = GetMR(caster_level);
    if (34 < caster_level && caster->GetClass() == CLASS_12_WIZARD) {	// wizard class resist modifier; added January 20 2000
      if (*(char *)(spell + 0x1fa) != SE_0_HP) {
        bVar10 = *(char *)(spell + 0x1fa) == SE_79_INSTANTHP;		// these are checking the first slot for DD effects
        goto LAB_WIZ_CONTINUE;
      }
LAB_WIZ_DO_REDUCTION:
      temp_resist = temp_resist - 10;
    }
  }
  else {
    if (cVar2 == SPELL_TYPE_2_FIRE) {
      temp_resist = GetFR(caster_level);
    }
    else {
      if (cVar2 != SPELL_TYPE_3_COLD) {
        if (cVar2 == SPELL_TYPE_4_POISON) {
          temp_resist = GetPR(caster_level);
        }
        else {
          if (cVar2 != SPELL_TYPE_5_DISEASE) {
            return 0;							// if type is not 1-5 then spell just lands
          }
          temp_resist = GetDR(caster_level);
        }
        goto LAB_CHECK_LURE;
      }
      temp_resist = GetCR(caster_level);
    }
    if (34 < caster_level) {
      bVar10 = caster->GetClass() == CLASS_12_WIZARD;
LAB_WIZ_CONTINUE:
      if (bVar10) goto LAB_WIZ_DO_REDUCTION;
    }
  }

LAB_CHECK_LURE:
  iVar9 = IsStrongLureSpell(spell,spell_id);		// CHA -5 and -6
  if (iVar9 != 0) {
    if (temp_resist < 100) {
      return 0;
    }
    resist_pct = (temp_resist + -100) / 2 + 5;
    if (45 < resist_pct) {
      resist_pct = 45;
    }
LAB_DO_LURE_ROLL:
    roll = Roll0(1,100);
    return (resist_pct <= roll) - 1 & 100;		// if resist_pct >= roll then return 0 else 100
  }
  iVar9 = IsWeakerLureSpell(spell,spell_id);		// CHA -4
  if (iVar9 != 0) {
    if (temp_resist < 50) {
      return 0;
    }
    resist_pct = (temp_resist + -50) / 2 + 5;
    if (75 < resist_pct) {
      resist_pct = 75;
    }
    goto LAB_DO_LURE_ROLL;
  }
  iVar9 = IsWeakestLureSpell(spell,spell_id);		// CHA -3
  if (iVar9 != 0) {
    if (temp_resist < 25) {
      return 0;
    }
    resist_pct = (temp_resist + -25) / 2 + 5;
    if (85 < resist_pct) {
      resist_pct = 85;
    }
    goto LAB_DO_LURE_ROLL;
  }
  
  first_effect = (byte *)(local_1c + 0x1fa + spell);
  if (*first_effect == SE_23_FEAR && this->IsNPC() == true && this->GetLevel() > 52)
  {
    return 100;
  }
  
  if (*first_effect == SE_22_CHARM && caster->IsNPC() == false)
  {
    if (this->GetClass() == CLASS_15_MERCHANT) {		// 15 is beastlord in newer clients but back then was merchants
      return 100;
    }
    if (this->GetBodyType() == BODY_6_EXTRAPLANAR) {
      return 100;
    }
    race = *(ushort *)(this + 0x34);
    if (race < 89) {
      if (race == RACE_88_CLOCKWORK_GNOME) {
        return 100;
      }
      if (race == RACE_44_FREEPORT_GUARD) {
        return 100;
      }
      if (race == RACE_67_HIGHPASS_CITIZEN) {
        return 100;
      }
      if (race == RACE_71_QEYNOS_CITIZEN) {
        return 100;
      }
      if (76 < race) {
        if (race < 79) {
          return 100;
        }
        bVar10 = race == RACE_81_RIVERVALE_CITIZEN;
LAB_CHECK_RACE:
        if (bVar10) {
          return 100;
        }
      }
    }
    else {
      if (race == RACE_90_HALAS_CITIIZEN) {
        return 100;
      }
      if (91 < race) {
        if (race < 95) {
          return 100;
        }
        if (race == RACE_106_FELGUARD) {
          return 100;
        }
        if (race == RACE_112_FAYGUARD) {
          return 100;
        }
        bVar10 = race == RACE_139_IKSAR_CITIZEN;
        goto LAB_CHECK_RACE;
      }
    }
    if (spell_id < 726) {
      if (spell_id == SPELL_725_SOLONS_SONG_OF_THE_SIRENS) {
LAB_SET_CHARM_LIMIT_37:
        charm_limit = 37;
      }
      else {
        if (spell_id < SPELL_185_TEPID_DEEDS) {
          if (spell_id != SPELL_184_ALLURE) {
            if (spell_id == SPELL_141_BEGUILE_ANIMALS) {
              charm_limit = 43;
              goto LAB_CHECK_CHARM_LIMIT;
            }
            if (spell_id != SPELL_142_ALLURE_OF_THE_WILD) {
              if (spell_id != SPELL_182_BEGUILE) {
                if (spell_id != SPELL_183_CAJOLING_WHISPERS) goto LAB_SET_CHARM_LIMIT_25;
                goto LAB_SET_CHARM_LIMIT_46;
              }
              goto LAB_SET_CHARM_LIMIT_37;
            }
          }
          goto LAB_SET_CHARM_LIMIT_51;
        }
        if (spell_id == SPELL_196_DOMINATE_UNDEAD) {
          charm_limit = 32;
        }
        else if (spell_id == SPELL_197_BEGUILE_UNDEAD) {
LAB_SET_CHARM_LIMIT_46:
          charm_limit = 46;
        }
        else {
          if (spell_id == SPELL_198_CAJOLE_UNDEAD) goto LAB_SET_CHARM_LIMIT_51;
          if (spell_id != SPELL_260_CHARM_ANIMALS) goto LAB_SET_CHARM_LIMIT_25;
          charm_limit = 33;
        }
      }
    }
    else {
      if (spell_id < 1630) {
        if (spell_id == SPELL_1629_ENSLAVE_DEATH) {
LAB_SET_CHARM_LIMIT_52:
          charm_limit = 52;
          goto LAB_CHECK_CHARM_LIMIT;
        }
        if (spell_id != SPELL_750_SOLONS_BEWITCHING_BRAVURA && spell_id != SPELL_1553_CALL_OF_KARANA) {
          if (spell_id == SPELL_1556_TUNARES_REQUEST) goto LAB_SET_CHARM_LIMIT_35;
          if (spell_id != SPELL_1624_THRALL_OF_BONES) {
LAB_SET_CHARM_LIMIT_25:
            charm_limit = 25;
            goto LAB_CHECK_CHARM_LIMIT;
          }
        }
      }
      else if (spell_id != SPELL_1705_BOLTRANS_AGACERIE) {
        if (spell_id != SPELL_1707_DICTATE) {
          if (spell_id == SPELL_1817_ALLURING_WHISPERS) {
            charm_limit = 49;
            goto LAB_CHECK_CHARM_LIMIT;
          }
          if (spell_id != SPELL_1822_PERSUADE) goto LAB_SET_CHARM_LIMIT_25;
LAB_SET_CHARM_LIMIT_35:
          charm_limit = 35;
          goto LAB_CHECK_CHARM_LIMIT;
        }
        goto LAB_SET_CHARM_LIMIT_52;
      }
LAB_SET_CHARM_LIMIT_51:
      charm_limit = 51;
    }
LAB_CHECK_CHARM_LIMIT:
    if (caster->GetClass() == CLASS_8_BARD && caster->GetLevel() < this->GetLevel() && 37 < caster->GetLevel()) {
      return 100;							// bards prevented from charming yellows and reds
    }
    if (charm_limit < this->GetLevel()) {
      if (*(int *)(caster + 0x74) == 0) {	// checking if we're an NPC
        return 100;
      }
      StringToClient(*(int *)(caster + 0x74),s_Target_Too_High_level_for_your_c_0054f770,0x121);
      return 100;
    }
  }
  
  if (this->IsNPC() == 0) {
    if (temp_resist > 99) {
      temp_resist = 99;		// players/clients are capped at 99 here
    }
  }
  else if (temp_resist > 150) {
    return 100;				// an effective resist of 151+ will make everything resist, including lifetaps
  }
  
  if ( spell_id == SPELL_127_INVOKE_FEAR) || spell_id == SPELL_59_PANIC_THE_DEAD || spell_id == SPELL_514_TERRORIZE_ANIMAL )
  {
    if (caster_level < this->GetLevel()) {
      iVar9 = -5;
    }
    else {
      iVar9 = -(caster_level / 2);
    }
    temp_resist = temp_resist + iVar9;
    if (temp_resist < 5) {
      temp_resist = 5;
    }
  }
  if ( spell_id == SPELL_1527_TREPIDATION || spell_id == SPELL_1550_REPULSE_ANIMAL || spell_id == SPELL_1532_DREAD_OF_NIGHT )
  {
    if (caster_level < this->GetLevel()) {
      iVar9 = -15;
    }
    else {
      iVar9 = -5 - (caster_level / 2);
    }
    temp_resist = temp_resist + iVar9;
    if (temp_resist < 5) {
      temp_resist = 5;			// fear has a resist floor of 5 like charm
    }
  }
  
  sVar8 = temp_resist;
  if ( spell_id == SPELL_1544_ENFORCED_REVERENCE ||
    spell_id == SPELL_1553_CALL_OF_KARANA ||
    spell_id == SPELL_1624_THRALL_OF_BONES ||
    spell_id == SPELL_1690_FASCINATION ||
    spell_id == SPELL_1691_GLAMOUR_OF_KINTAZ ||
    spell_id == SPELL_1705_BOLTRANS_AGACERIE
  ) {
    sVar8 = sVar8 - 10;		// these spells get a resist bonus/reduction
  }
  iVar9 = IsUnresistableSpell(spell,spell_id);	// this returns true for Dictate, Rapture, Enslave Death
  if (iVar9 != 0) {
    return 0;
  }
  if (spell->type_number == 13) {	// type 13 is lifetap.  lifetaps land at this point.  they never did partial damage until Sept 4 2002
    return 0;
  }
  final_resist = final_resist + sVar8;
  spell_effect = *first_effect;
  if (spell_effect < 32) {
    if (spell_effect != SE_31_MEZ) {
      if (spell_effect == SE_0_HP) {
LAB_YELLOW_RED_DD_MOD:
        if (*(int *)(this + 0xa0) == NULL || this->IsNPC() != 1 || level_diff < 1 || this->GetLevel() < 17) goto LAB_TASH_SPELLS;
        resist = final_resist + level_diff * 2;		// this is adding +2 resist value for each level the target is above the player caster
      }
      else {
        if (spell_effect != SE_3_MOVEMENTSPEED && spell_effect != SE_20_BLIND) {
          if (spell_effect == SE_22_CHARM) {
            CharismaMod(&final_resist,caster);		// modify the resist value by the charisma bonus, which is -1 for every 8 CHA above 75
          }
          else if (spell_effect != SE_23_FEAR) goto LAB_TASH_SPELLS;
        }
        if (no_resist_floor != 0 || (resist = 5, 4 < final_resist)) goto LAB_TASH_SPELLS;
      }
      final_resist = resist;	// Charm, Root, Blind, Fear have a resist floor of 5 which is set here but the function has an override parameter
      goto LAB_TASH_SPELLS;
    }
  }
  else if (spell_effect != SE_34_CONFUSE) {
    if (spell_effect == SE_44_LYCANTHROPY) {
      final_resist = final_resist + 30;
      goto LAB_TASH_SPELLS;
    }
    if (spell_effect != SE_63_BLUR) {
      if (spell_effect != SE_79_CURRENT_HP_ONCE) goto LAB_TASH_SPELLS;
      goto LAB_YELLOW_RED_DD_MOD;
    }
  }
  CharismaMod(&final_resist,caster);		// Mez, Confuse and Blur spells call this.  They get the same CHA bonus charm does
  
LAB_TASH_SPELLS:
  if ( spell_id == SPELL_676_TASHAN || spell_id == SPELL_677_TASHANI || spell_id == SPELL_678_TASHANIA ) {
    final_resist = (final_resist * 2) / 3;	// this is weird since these spells are unresistable.  vestigial?
  }
  
  // Level based resist floor
  if (this->IsNPC() == 1) {
    if (level_diff > -11 && this->GetLevel() > 14 && final_resist < 10) {	// ten levels under the caster or higher unless it's a newbie mob
      final_resist = 10;
    }
    if (level_diff < -20 || this->GetLevel() < 15) {		// deep greens and newbie mobs
      resist = 2;
    }
    else {
      resist = 5;		// everything in between
    }
  }
  else {
    resist = 1;		// on players the floor is always 1
  }
  
  if (final_resist < resist) {
    final_resist = resist;
  }
  if (final_resist > 100) {		// this will cap players and NPCs but players were already capped at 99 before this
    final_resist = 100;
  }
  
  iVar9 = IsLullSpell(spell_id);
  if (iVar9 != 0) {
    if (spell_id == SPELL_728_KELINS_LUGUBRIOUS_LAMENT) {		// bard lull was good because it's only 3 ticks I guess
      resist = 5;
      final_resist = final_resist / 2;		// bard lull gets a big resist bonus here
      if (final_resist < 5) {
        final_resist = 5;
      }
    }
    else {					// lull/pacify resist floors; lull spells were bad apparently, except bard
      this_level = this->GetLevel();
      if (this_level < 15) {
        resist = 10;
      }
      else if (this_level < 25) {
        resist = 20;
      }
      else if (this_level < 35) {
        resist = 33;
      }
      else if (this_level < 40) {
        resist = 42;
      }
      else {
        resist = (-(uint)(this_level < 50) & 0xffffffd2) + 100;	// if level < 50 then value = 54 else value is 100.  50+ mobs were immune to non-bard lull
      }
    }
    if (final_resist < resist) {
      final_resist = resist;
    }
  }
  
  // our class list has necro GM as 30.  Sony's Kunark list had enchanter GM as 30
  if (caster->IsNPC() == 1 
    && (caster->GetClass() == CLASS_14_ENCHANTER || caster->GetClass() == CLASS_30_ENCHANTER_GM)
    && caster->GetLevel() > 24)
  {
    if (this->GetLevel() < final_resist) {
      final_resist = this->GetLevel();
    }
    if (final_resist > 40) {
      final_resist = 40;			// enchanter NPCs basically ignored your resists for the most part
    }
  }
  
  resist = final_resist;
  roll = Roll0(0,100);				// the 2nd number is really n - 1, so random range would be 0 to 99
  if (roll > 98 || resist < roll) {	// the attacker is doing the roll; a 99 and attacker auto-wins; roll a 0 or 1 and resist
    return 0;	// full hit
  }
  if (local_18 != -1									// two or more spell effects?
     && (*first_effect == 0 || *first_effect == 79) 			// first slot is DD effect
     && (12 < *(byte *)(spell + 0x212))					// enchanter minimum spell level > 12
     && ((cVar2 = *(char *)(local_18 + 0x1fa + spell), cVar2 != 27 && cVar2 != 92)))	// first effect is not SE 27 and not SE 92 (cancel magic, insta hate)
  {
    return 100;		// full resist
  }
  if (*first_effect == 0 || *first_effect == 79)
  {
    resist = (resist * 100 + roll * -100) / resist;
    if (this->IsNPC())
	{
      if (level_diff > 0 && 16 < this->GetLevel()) {
        resist = resist + 5;
      }
      this_level = this->GetLevel();
      if (this_level > 29) {
        resist = (resist - 25) + this_level;
      }
      if (this_level < 15) {
        resist = resist - 5;
      }
    }
    if (spell_id == 88) {		// Harm Touch
      resist = resist - 45;
    }
    if (resist < 0) {
      resist = 0;
    }
    if (resist < 101) {
      return resist;
    }
  }
  return 100;
}
Reply With Quote
 


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump

   

All times are GMT -4. The time now is 12:03 PM.


 

Everquest is a registered trademark of Daybreak Game Company LLC.
EQEmulator is not associated or affiliated in any way with Daybreak Game Company LLC.
Except where otherwise noted, this site is licensed under a Creative Commons License.
       
Powered by vBulletin®, Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
Template by Bluepearl Design and vBulletin Templates - Ver3.3