This document contains the 100% IDA-verified magic damage formula for MapleStory v40, reverse engineered from sub_515307 (CalcMagicDamagePerHit).
BaseDamage = (INT × 0.5 + (Magic × 0.058)² + MagicInterp × 3.3) × EffectiveSkillMAD × 0.01
FinalDamage = Floor(BaseDamage) - DefenseSub
| 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] |
| 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 |
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% |
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; // InterpolateCalcMagicDamagePerHit 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| Hit | Acc Index | Dmg Index | Def Index |
|---|---|---|---|
| 1 | 0 | 1 | 2 |
| 2 | 3 | 4 | 5 |
Amp is integrated INTO the skill damage, not applied after defense:
EffectiveSkillMAD = SkillMAD × (AmpY / 100)
// Example: 55 × 1.35 = 74.25Important: The amp multiplier uses the skill's
yproperty (e.g., y=135 → 1.35×)
// 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);
}| 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 |
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?
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.