View Single Post
  #12  
Old 06-05-2025, 04:20 AM
Torven
Sarnak
 
Join Date: Aug 2014
Posts: 76
Default

I will paste my translations of several resist function decompiles here for convenience. These and more are found on my public Google Drive.

Code:
// CheckResistSpell() from February 16 1999 client. (original launch CD)  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

// param_1 = spell_data
// param_2 = caster level
// param_3 = no_resist_floor
// param_4 = caster_object
// param_5 = spell ID
// this + 0x38 = level
// uVar5 = roll
// uVar6 = final_resist
// sVar7 = level_diff
// 0x94 = IsNPC()
// iVar10 = start_resist


uint __thiscall
FUN_00416fd0(int this, int spell_data, byte caster_level, int no_resist_floor, undefined4 caster_object, int spell_id)
{
  char cVar1;
  byte level;
  int iVar3;
  int iVar4;
  uint roll;
  uint final_resist;
  short level_diff;
  int iVar8;
  int iVar9;
  int start_resist;
  int local_4;
  
  level = caster_level;
  start_resist = 0;
  level_diff = this->GetLevel() - caster_level;
  temp_resist = 0;
  local_4 = -1;
  if (spell_data == nullptr) {
    return 100;
  }
  iVar8 = -1;
  if (*(int *)(this + 0xa0) == nullptr) {
    return 100;
  }
  do {
    if (((iVar8 != -1) ||
        ((iVar3 = FUN_00416f50(spell_data,start_resist), iVar9 = start_resist, iVar3 == 0 && (iVar9 = iVar8, false)
         ))) && (iVar4 = FUN_00416f50(spell_data,start_resist), iVar9 = iVar8, iVar3 = start_resist, iVar4 != 0))
    break;
    start_resist = start_resist + 1;		// compiler optimizer reusing variables; this is basically 'i' for this loop
    iVar8 = iVar9;
    iVar3 = local_4;				// -1
  } while (start_resist < 4);		// only 4 spell slots max in this era
  local_4 = iVar3;
  if (iVar9 == -1) {
    return 100;			// no valid spell slots
  }
  switch(*(undefined *)(spell_data + 0x1f9)) {		// spell resist type
  case SPELL_RESIST_TYPE_1_MAGIC:
    start_resist = GetMR(level);	// attacker's level; needed to modify resist by level difference
    break;
  case SPELL_RESIST_TYPE_2_FIRE:
    start_resist = GetFR(level);
    break;
  case SPELL_RESIST_TYPE_3_COLD:
    start_resist = GetCR(level);
    break;
  case SPELL_RESIST_TYPE_4_POISON:
    start_resist = GetPR(level);
    break;
  case SPELL_RESIST_TYPE_5_DISEASE:
    start_resist = GetDR(level);
    break;
  default:
    goto LAB_LAND_SPELL;
  }
  iVar8 = *(int *)(this + 0xa0);	// used in IsNPC() lines that I removed for readability
  if (!IsNPC()) {
    if (start_resist > 99) {
      start_resist = 99;		// players capped at 99
    }
  }
  else if (start_resist > 150) {
    return 100; // guaranteed full resist if resist > 150
  }
  temp_resist = temp_resist + start_resist;
  if (true) {
    switch(*(undefined *)(iVar9 + 0x1fa + spell_data)) {		// first spell slot effect
    case SE_0_CURRENTHP:
    case SE_79_CURRENT_HP_ONCE:
      if (IsNPC() && level_diff > 0 && this->GetLevel() > 16) {
        temp_resist = temp_resist + level_diff * 2;
      }
      break;
    case SE_22_CHARM:
      ModResistCHA(&temp_resist,caster_object);
    case SE_3_MOVEMENTSPEED:
    case SE_20_BLIND:
    case SE_23_FEAR:
      if (no_resist_floor == 0 && temp_resist < 5) {
        temp_resist = 5;
      }
      break;
    case SE_31_MEZ:
    case SE_34_CONFUSE:
    case SE_63_BLUR:
      ModResistCHA(&temp_resist,caster_object);
      break;
    case SE_44_LYCANTHROPY:
      temp_resist = temp_resist + 30;
    }
  }
  
  // NPC target resist floors
  if (IsNPC()) {
    if (level_diff > -11 && this->GetLevel() > 14 && temp_resist < 10) {
      temp_resist = 10;
    }
    if ((level_diff < -20) || this->GetLevel() < 15)) {
      if (temp_resist < 2) {
        temp_resist = 2;
      }
    }
    else if (temp_resist < 5) {
      temp_resist = 5;
    }
  }
  else if (temp_resist < 1) {
    temp_resist = 1;				// player targets floor at 1
  }
  if (temp_resist > 100) {
    temp_resist = 100;				// resist capped at 100 here for everything
  }
  final_resist = temp_resist;
  roll = RandNum(0,100);			// roll a number from 0 to 99 inclusive
  if (roll < 99 && roll <= final_resist)
  {
    if (local_4 != -1 &&	// -1 means there is only one valid spell effect
       (cVar1 = *(char *)(iVar9 + 0x1fa + spell_data), cVar1 == SE_0_CURRENTHP || cVar1 == SE_79_CURRENT_HP_ONCE))
	{
      return 100;	// if there are multiple effects in the spell, and the first effect is damage, then full resist
    }
    cVar1 = *(char *)(iVar9 + 0x1fa + spell_data);						// get first spell effect
    if (cVar1 == SE_0_CURRENTHP || cVar1 == SE_79_CURRENT_HP_ONCE)		// only pure DD spells may partial hit
	{
	  // calculate possible partial damage; still may full resist.  Only single effect spells with SE 0 or 79 end up here
	
      final_resist = (final_resist * 100 + roll * -100) / final_resist;
      if (IsNPC())
	  {
        if (level_diff > 0 && this->GetLevel() > 16) {
          final_resist = final_resist + 5;				// yellows and reds resist more
        }
        level = this->GetLevel();		// target's level
        if (level > 29) {
          final_resist = (final_resist - 25) + level;	// level 30+ mobs resist more; the higher the level the more it resists
        }
        if (level < 15) {
          final_resist = final_resist - 5;				// newbie mobs resist less
        }
      }
      if (spell_id == SPELL_88_HARM_TOUCH) {
        final_resist = final_resist - 15;
      }
      if (final_resist < 0) {
        final_resist = 0;
      }
      if (final_resist < 101) {
        return final_resist;
      }
    }
    return 100;		// 100 means zero damage/full resist
  }
LAB_LAND_SPELL:
  return 0;		// 0 means full damage
}
Reply With Quote