Skip to content

Player stats

Allofich edited this page Apr 15, 2020 · 21 revisions

Health on generation

Health for the player is rolled in character generation as follows. 25 is then added to this value.

void GetStartingHealth(NPCDATA* npcData)
{
  unsigned int health = Roll(HealthDice[npcData->Class] & ID_MASK)); // Get a value between min and max
  health = health + npcData->BonusHealth;
  if (health == 0)
  {
    health = 1;
  }
  npcData->currentHealth = health;
  npcData->maxHealth = health;
  return;
}

Maximum spell points

Maximum spell points for the player and NPCs is obtained as follows:

unsigned int GetMaxSpellPoints(NPCDATA* npcData, uint currentIntelligence)
{
    // See the wiki page on "Save File Formats" for the NPCDATA structure
    unsigned char class = npcData->class; // Get the character class

    // Default of 0 spell points. (For non-spellcasters)
    int spellPoints = 0;

    // If class is a spellcaster and not a sorcerer
    if ((class & SPELLCASTER_MASK != 0) && (class != 0x23))
    {
        spellPoints = currentIntelligence; // 1x intelligence spell points (Bard)
 
        // If not a bard
        if (class != 0xe6)
        {
            uint spellPointBonus = currentIntelligence; // 2x intelligence spell points

            // From here, a byte array in the executable file is used.
            // The array has 6 values, ordered by class ID.
            // If the value gotten is 2, then the total will stay 2x intelligence as was set above. (Mage, Healer).
            // If the value gotten is 0, then the total will become 1.5x intelligence. (Spellsword, Nightblade)
            // For any other value, the total will become 1.75x intelligence. (Battlemage)
            if (SpellPointModifiers[class & ID_MASK] != 2)
            {
                if (SpellPointModifiers[class & ID_MASK] != 0)
                {
                    spellPoints = currentIntelligence + (currentIntelligence >> 2); // Add 0.25x intelligence
                }
                spellPointBonus = currentIntelligence >> 1; // Add 0.5x intelligence
            }

            // Calculate the total
            spellPoints = spellPoints + spellPointBonus;
        }
    }

    // If class is a sorcerer
    if (class == 0x23)
    {
        spellPoints = currentIntelligence * 3;
    }
    
    return spellPoints;
}

The "SpellPointModifiers" array location is 0x3C3E0.

SpellPointModifiers
      02 Mage
      00 Spellsword
      01 Battlemage // "1" here, but any value other than 2 or 0 has the same effect
      FF Sorcerer // Unused
      02 Healer
      00 Nightblade
      FF Bard // Unused

Maximum stamina

Maximum stamina for the player and NPCs (as stored internally) is obtained as follows:

npcStats->Stamina = (npcStats->CurrentStrength + npcStats->CurrentEndurance) * 64;

Home city ID

Home city ID for the player and NPC humanoids is obtained as follows:

void SetHomeCity(NPCSTATS* npcStats)
{
  int maximum = 32;
  if (npcStats->Race == 7) { // Argonian
    maximum = 31;
  }
  int random = GetRandomBetween0AndMaximum(maximum); // Gets a random value between 0 and "maximum"
  npcStats->HomeCityID = npc->Race * 32 + random;
  return;
}

Derived stats

Derived stats for the player and NPCs are obtained as follows:

void DeriveStats(NPCSTATS* npcStats)
{
  // Strength-related
  npcStats->DamageBonus = (npcStats->CurrentStrength - 0x7a) / 0xd;
  npcStats->CarryLimit = npcStats->CurrentStrength * 2;

  // Intelligence-related
  int intelligence = Convert256Valueto100Value(npcStats->CurrentIntelligence);
  int spellPoints = GetSpellPoints(npcStats, intelligence);
  npcStats->MaxSpellPoints = spellPoints;
  *(short *)(npcStats + 0x3d) = spellPoints; // Unknown
  *(short *)(npcStats + 0x3f) = npcStats->CurrentIntelligence - 0x80; // Unknown
  
  // Willpower-related
  int willpowerMod = npcStats->CurrentWillpower - 0x80;
  npcStats->MagicDefense = -(willpowerMod);
  *(short *)(npcStats + 0x45) = willpowerMod >> 1; // Unknown

  // Agility-related
  int agilityMod = npcStats->CurrentAgility - 0x80;
  npcStats->AttackBonus = agilityMod;
  npcStats->DefenseBonus = agilityMod;
  npcStats->BonusAC = agilityMod;

  // Speed-related
  *(short *)(npcStats + 0x4d) = (0x10c - npcStats->CurrentSpeed) / 0x19; // Unknown

  // Endurance-related
  int enduranceMod = (npcStats->CurrentEndurance - 0x74) / 0x19;
  npcStats->BonusHealth = enduranceMod;
  npcStats->BonusHealing = enduranceMod;
  *(short *)(npcStats + 0x51) = npcStats->CurrentEndurance * 2; // Unknown

  // Personality-related
  npcStats->Charisma = npcStats->CurrentPersonality - 0x74;

  // Luck-related
  npcStats->Bonus Luck = ((npcStats->CurrentLuck - 0x74) / 0x19) * 2;

  // Other
  *(char *)(npcStats + 0x5f) = (npcStats->CurrentWillpower + npcStats->CurrentEndurance + 0x200) / 0x400; // Unknown
  *(char *)(npcStats + 0x6a) = (npcStats->CurrentStrength + npcStats->CurrentIntelligence + 0x400) / 0x800; // Unknown
  npcStats->PoisonSavingThrow = npcStats->CurrentEndurance >> 2; // npcStats + 0x62
  npcStats->MagicSavingThrow = (char)npcStats->MagicDefense; // npcStats + 0x64

  return;
}
Clone this wiki locally