Skip to content

Instantly share code, notes, and snippets.

@ThatMapleDev
Last active July 14, 2026 08:14
Show Gist options
  • Select an option

  • Save ThatMapleDev/9942591daed2b6a1f524d5dcc6318a22 to your computer and use it in GitHub Desktop.

Select an option

Save ThatMapleDev/9942591daed2b6a1f524d5dcc6318a22 to your computer and use it in GitHub Desktop.

Magic Damage Formula - v40 Reverse Engineering

Overview

This document contains the 100% IDA-verified magic damage formula for MapleStory v40, reverse engineered from sub_515307 (CalcMagicDamagePerHit).


Formula

BaseDamage = (INT × 0.5 + (Magic × 0.058)² + MagicInterp × 3.3) × EffectiveSkillMAD × 0.01
FinalDamage = Floor(BaseDamage) - DefenseSub

Variables

Variable Description Source
INT Character's INT stat GetSecureValue(a4+15)
Magic INT + MATK (total magic power) GetSecureValue(a5+96) + GetSecureValue(a5+108)
MagicInterp Interpolated magic (min to max via RNG) See Mastery Interpolation
EffectiveSkillMAD SkillMAD × AmpMultiplier Amp is integrated into skill damage
DefenseSub Monster defense reduction Interpolated MDD × [0.5, 0.6]

IDA Constants

Address Name Value Usage
0x6295C8 dbl_6295C8 0.5 INT coefficient
0x62BD30 dbl_62BD30 0.058 Magic quadratic coefficient
0x62BD28 dbl_62BD28 3.3 Magic linear coefficient
0x62B6D0 dbl_62B6D0 0.01 Skill scale factor
0x62BD08 dbl_62BD08 5.0 Mastery calculation
0x62BD18 dbl_62BD18 10.0 Mastery base value
0x62BD00 dbl_62BD00 0.009 Mastery scale
0x62BC80 dbl_62BC80 99999.0 Damage cap
0x62BCE8 dbl_62BCE8 1e-7 RNG normalization

Mastery Interpolation

The mastery factor determines the minimum damage range:

// IDA Line 103
v52 = (skillMastery × 5.0 + 10.0) × 0.009
Skill Mastery v52 Result Min Damage %
0 0.09 9%
10 0.54 54%
20 0.99 99%

Interpolation Logic (Lines 220-238)

v35 = Magic;           // Start at max
v59 = Magic × v52;     // Calculate min

if (v59 < v35) {
    Swap(v35, v59);    // v35=min, v59=max
}

v35 = v35 + (v59 - v35) × rngFactor;  // Interpolate

Multi-Hit RNG Pattern (Critical)

CalcMagicDamagePerHit pre-generates 7 random values ONCE at the start, then cycles through them for all hits:

// Lines 76-84: Pre-generate 7 randoms
uint v51[7];
v62 = 0;
do {
    v51[v62++] = CRand32::Random();
} while (v62 < 7);

// In the hit loop (for each hit):
accRandom = v51[v62 % 7]; v62++;   // Accuracy
dmgRandom = v51[v62 % 7]; v62++;   // Damage
defRandom = v51[v62 % 7]; v62++;   // Defense

Multi-Hit Example (Magic Claw - 2 hits)

Hit Acc Index Dmg Index Def Index
1 0 1 2
2 3 4 5

Elemental Amplification

Amp is integrated INTO the skill damage, not applied after defense:

EffectiveSkillMAD = SkillMAD × (AmpY / 100)
// Example: 55 × 1.35 = 74.25

Important: The amp multiplier uses the skill's y property (e.g., y=135 → 1.35×)


Complete Implementation

// IDA Constants
const double INT_COEFF = 0.5;           // dbl_6295C8
const double MAGIC_QUAD_COEFF = 0.058;  // dbl_62BD30
const double MAGIC_LINEAR_COEFF = 3.3;  // dbl_62BD28
const double SKILL_SCALE = 0.01;        // dbl_62B6D0
const double MASTERY_MULT = 5.0;        // dbl_62BD08
const double MASTERY_ADD = 10.0;        // dbl_62BD18
const double MASTERY_SCALE = 0.009;     // dbl_62BD00

public int CalculateMagicDamage(
    int intStat, int matk, int skillMastery, int skillMad, 
    double ampMultiplier, double dmgRngFactor)
{
    int totalMagic = intStat + matk;
    
    // Step 1: Calculate mastery factor (IDA line 103)
    double v52 = (skillMastery * MASTERY_MULT + MASTERY_ADD) * MASTERY_SCALE;
    
    // Step 2: Interpolate Magic stat (IDA lines 220-238)
    double v35 = totalMagic;
    double v59 = v35 * v52;
    
    if (v59 < v35) {
        (v35, v59) = (v59, v35);  // Swap for min/max
    }
    
    v35 = v35 + (v59 - v35) * dmgRngFactor;  // Interpolate
    
    // Step 3: Apply formula (IDA lines 240-242)
    // Amp is integrated into skillMad
    double effectiveSkillMad = skillMad * ampMultiplier;
    
    double intTerm = intStat * INT_COEFF;
    double quadTerm = Math.Pow(totalMagic * MAGIC_QUAD_COEFF, 2);
    double linearTerm = v35 * MAGIC_LINEAR_COEFF;
    
    double damage = (intTerm + quadTerm + linearTerm) * effectiveSkillMad * SKILL_SCALE;
    
    return (int)Math.Floor(damage);
}

Key Discoveries

Finding Description
v64 = INT Initially assumed to be LUK, but GetSecureValue(a4+15) returns INT
Skill Mastery Read from skill data offset 268, not a fixed 60%
Amp Integration Applied inside formula, NOT after defense subtraction
7 Random Cycle All hits share the same 7 pre-generated randoms, cycled with modulo 7
Mastery Formula (mastery × 5 + 10) × 0.009 converts skill mastery to interpolation factor
@ShrimpManiac

ShrimpManiac commented May 8, 2026

Copy link
Copy Markdown

Amazing work there!
I'm a fellow osms lover trying to figure out the exact way damage calculation is done, and your analysis has been extremely helpful in understanding magic damage formula. However, there are still some mysteries left unanswered.

The return value of CalculateMagicDamage appears to be an intermediate value. Let's say we floor that value and apply defense reduction. Then what next?

  • since def reduction part can have non-integer part, do we floor that too? Or do we ceil that?
  • at which point do we take max(val, 99999) and min(val, 1) to ensure they are within [1, 99999]?
  • when does crit damage apply?
  • when do after-modifiers (i.e. chain lightening) apply?
  • what about elemental modifiers? (i.e. 1.5x to fire weak enemies)

I assume that there is a separate function that takes the return value of CalculateMagicDamage (or the physical equivalent) and calculate the final damage value. Unfortunately, I'm not familiar with IDA reverse engineering and can't find that out myself. If you're planning to publish more gist entries, it would be of great help to me if you can do a comprehensive analysis on damage formula.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment