This guide breaks down how damage is calculated in Star Savior, how the turn speed system works, and how to optimize your stat investments. All formulas are verified from the game's decompiled source code (NKM.decompiled.cs, TurnSpeedCalculator.cs).
Damage Formula Overview
The damage calculation happens in multiple steps. Here is the simplified pipeline:
// Step 1: Raw Damage (from skill templet factors)
RawDamage = (ATK * AtkFactor% + HP * HpFactor% + DEF * DefFactor%)
* SkillMultiplier / HitCount
// Step 2: Defense Reduction
DefReduction = DEF_target / (DEF_target + Constant)
EffectiveDefReduction = DefReduction * (1 - Penetration% + PenResist%)
// Step 3: Apply DEF to Raw Damage
PostDef = RawDamage * (1 - EffectiveDefReduction)
// Step 4: Damage Up/Down modifiers (additive)
DamageUp = AttributeAdvantage + DamageUp% + SkillPhaseUp%
+ AttackTagUp% + BuffCountUp% + DebuffCountUp% + BreakUp%
DamageDown = AttributeDisadvantage + DamageReduce%
+ NonCritReduce% + RoleReduce% + ElementReduce%
+ BreakReduce% + AttackTagReduce%
// Step 5: Critical Hit (applied after modifiers)
if CriticalHit:
CritDMG_applied = CritDamage% - CritDamageReduce% (floor 0)
PostDef += PostDef * CritDMG_applied
// Step 6: Random Variance (+/-5%)
FinalDamage = PostDef * Random.Range(0.95, 1.05)
// Step 7: Hard Caps
if FinalDamage > TargetHP * DamageLimitByHP%:
FinalDamage = TargetHP * DamageLimitByHP%
if TotalReduction > DamageReduceTotalLimit:
TotalReduction = DamageReduceTotalLimit
Attribute Advantage (Verified from Code)
private static double CalcAttributeAdvantage(Unit attacker, Unit defender)
{
double result = 0.0;
if (attacker is BattleUnit unit)
{
// Check if attacker has advantage
if (IsAttributeAdvantage(unit.Element, defender.Element))
{
result = 0.05; // +5% base advantage
result += unit.GetStat(RATE_DAMAGE_UP_ADJUST); // + extra from buffs
}
// Check if attacker has disadvantage
if (IsAttributeDisadvantage(unit.Element, defender.Element))
{
result = -0.05; // -5% base disadvantage
}
}
return result;
}
// Advantage relationships (OBF_11522):
// Sun > Star, Moon > Sun, Star > Moon
// Order > Chaos, Chaos > Order
Attribute advantage gives +5% damage and disadvantage gives -5% damage. This is a flat modifier applied during the damage up/down phase, not a multiplier on raw damage.
Defense Reduction Formula
private static double CalcDefReduction(BattleState host,
Unit attacker, Unit defender, bool isDodge, DamageLog log)
{
double defStat = defender.GetStat(NST_DEF);
double hpGrownDefRate = defender.GetStat(RATE_HP_GROWN_DEF);
hpGrownDefRate *= (1 - defender.GetBreakPercent());
defStat += defStat * hpGrownDefRate;
// Diminishing returns formula
double defReduction = defStat / (defStat + Constant);
// Constant differs between PVP and PVE modes
// Apply penetration
double penetration = attacker.GetStat(RATE_PENETRATE_DEF);
double penResist = defender.GetStat(RATE_PENETRATE_DEF_RESIST);
double effectivePen = penetration - penResist;
defReduction -= defReduction * effectivePen;
return Math.Max(defReduction, 0.0);
}
The defence constant is loaded at runtime from the game's const templet data. The actual values are:
- PVE DefenceConst = 3,000 (from CLIENT_CONST_TEMPLET.json, field "DefenceConst")
- PVP DefenceConst = 300 (from the same file, field "PvpDefenceConst")
"DefenceConst": 3000, // PVE defense constant
"PvpDefenceConst": 300, // PVP defense constant (much lower)
"RATE_DAMAGE_REDUCE_TOTAL_LIMIT": 5000 // 50% cap on total damage reduction
Key takeaways about defense:
- DEF has diminishing returns -- the formula is DEF / (DEF + 3000), so each additional point provides less reduction
- The sweet spot is around 2,500-3,000 DEF -- at DEF = Constant you hit 50% reduction, past which returns drop sharply
- DEF barely matters in PVP -- with a constant of only 300, even 1000 DEF gives 77% reduction, so PVP damage is mostly unmitigated
- Penetration directly reduces the DEF reduction -- it's a percentage subtracted from the total reduction, not from the DEF stat itself
- Penetration Resist on the defender counters the attacker's penetration
- Total damage reduction is hard-capped at 50% (RATE_DAMAGE_REDUCE_TOTAL_LIMIT = 5000 basis points)
Defense Reduction Examples (PVE)
Critical Hit System
private static double CalcCritDamageModifier(HitType hitType,
ref DamageContext ctx)
{
if (hitType != HitType.CriticalHit)
return 0.0;
// Crit DMG = attacker's CritDamage - defender's CritDamageReduce
int critDMG = (attacker.GetStat(RATE_CRITICAL_DAMAGE)
- defender.GetStat(RATE_CRITICAL_DAMAGE_REDUCE));
if (critDMG < 0) critDMG = 0;
double result = critDMG / 10000.0; // basis points to decimal
return result;
}
Important details:
- Crit Damage is applied after defense reduction and damage up/down modifiers
- Crit Damage Reduce (on the defender) can partially or fully negate the attacker's Crit Damage bonus
- Non-critical hits can have additional NST_RATE_NONCRITICAL_DAMAGE_REDUCE applied to the defender
- Effect RES triggers +50% damage reduction on the attacker's output (half damage on evade)
Random Variance
// Final damage has +/-5% random variance
double variance = RandomGenerator.Range(9500, 10500) / 10000.0;
finalDamage *= variance;
Every hit has a +/-5% random variance applied at the very end. This means even identical attacks will deal slightly different damage each time. Over many hits this averages out, but on any single attack the damage can vary by up to 10% (from 95% to 105% of the calculated value).
Turn Speed System
Star Savior uses an action gauge system (similar to Final Fantasy X). Every unit has a gauge that fills up over time, and whoever reaches 10000 first gets to act.
// Action gauge calculation
double speed = unit.GetStat(NST_TURN_SPEED);
// Apply +/-5% random variance to speed (in certain battle modes)
if (applyRandomVariance)
{
double variance = RandomGenerator.Range(9500, 10500) / 10000.0;
speed *= variance;
}
// Slow debuff cuts speed to 30%
if (isSlowed)
{
speed *= 0.3;
}
// Ticks until this unit acts:
// ticksRemaining = (10000 - currentGauge) / speed
How it works:
- Each "tick", every unit's gauge fills by their speed value
- The unit whose gauge reaches 10,000 first gets the next turn
- After acting, the gauge resets (but retains leftover fill)
- Speed has +/-5% random variance per tick, making close speed values unreliable
- The slow debuff (IsLowTurnSpeed) reduces speed to 30%
Speed and Turns
Speed and Enemy Turn Denial
In a battle that ends after 7 of your turns, your speed determines how many times the enemy acts:
| Your SPD | Enemy Turns (120 SPD enemy) | Enemy Turns (140 SPD enemy) |
|---|---|---|
| 120 | 7 (equal) | 8 |
| 140 | 6 | 7 (equal) |
| 170 | 5 | 6 |
| 200 | 4 | 5 |
Stat Optimization Guide
Expected Damage Formula
The expected damage per hit (accounting for crit probability) is:
Expected Damage = ATK * [1 + CritRate * CritDamage]
This means Crit Rate and Crit Damage multiply each other. If one is zero, the other does nothing. They must be built together.
ATK vs Crit Damage -- The Breakeven
Given typical endgame values (ATK ~6000, base Crit Damage 50-68% bonus):
| Your Crit Rate | +200 ATK Damage | +10% CD Damage | +12% CD Damage | Winner |
|---|---|---|---|---|
| 5% | +219 | +86 | +104 | ATK (2.5x) |
| 20% | +230 | +360 | +432 | CD |
| 30% | +234 | +540 | +648 | CD (2.8x) |
| 45% | +240 | +810 | +972 | CD (4x) |
| 50% | +242 | +900 | +1,080 | CD (4.5x) |
The breakeven point: +200 ATK = +10% CD at ~42% Crit Rate, and +200 ATK = +12% CD at ~33% Crit Rate.
20% ATK Set vs 40% CD Set
// 20% ATK set: always +20% damage
// 40% CD set: only works on crits
// Effective bonus per hit:
// ATK set: +20% guaranteed
// CD set: CR * 40% average (and RNG-dependent)
// CD set only wins when Crit Rate > 76%
// Example at 45% CR:
// ATK set: 1.20 * multiplier
// CD set: 1 + 0.45 * 0.40 = 1.18 * multiplier (ATK wins)
Result: 20% ATK set always beats 40% CD set unless you have unrealistically high Crit Rate (76%+). The ATK set gives more average damage AND perfect consistency.
30 SPD vs 12% ATK
// In a battle lasting 1000 ticks:
// 120 SPD: 12 turns * 1.00 = 12.0x damage
// 150 SPD: 15 turns * 1.00 = 15.0x damage (+25%)
// vs
// 120 SPD: 12 turns * 1.12 = 13.44x damage (+12%)
30 SPD wins in any battle lasting 3+ turns. In a 7-10 turn fight, 30 SPD also denies 1-2 enemy turns, which is often more valuable than the raw damage difference.
Build Recommendations
For character-specific gear and stat recommendations, see the Character Builds page.
General Priority
- Speed first -- get to 140-170 SPD to outspeed enemies and deny turns (check the Equipment Database for SPD gear options)
- ATK as foundation -- maximize ATK through affection, tactics, resonance, and gear main stats (these are "free" and don't compete with substats)
- Crit Rate to 40-50% -- this is the minimum threshold where CD investment becomes worthwhile
- Crit Damage as high as possible -- at 40%+ CR, CD is the highest-value stat per point
- Effect Hit -- essential for debuff-reliant characters
Set Bonus Recommendations
| Playstyle | 4-Piece Set | Why |
|---|---|---|
| General / Safe | Attack Set (+20% ATK) | Always works, no RNG, beats CD set at realistic crit rates |
| Crit Build (40%+ CR) | Destruction Set (+40% CD) | Best ceiling damage if you can maintain high CR |
| Speed Control | Speed Set (+15 SPD) | Turn denial is extremely valuable in 7-10 turn fights |
| Debuffer | Hit Set (+20% Effect Hit) | Essential for landing debuffs consistently |
The Golden Rule
ATK is your foundation, CD is your multiplier. You need a strong foundation before the multiplier matters. Get ATK high from free sources (affection, tactics, resonance), then decide: if your Crit Rate is below 30%, prioritize ATK substats. If it's 40%+ from buffs and gear, stack CD as your primary substat investment.
Battle Power Formula
The game uses a Battle Power score for unit ranking. This is separate from actual combat damage:
double atkFactor = ATK / 10.0 * ATK_WEIGHT * (
(1 - critRate) + critRate * (1 + critDamage) );
double hpFactor = HP / 55.0 * HP_WEIGHT;
double defFactor = DEF / 5.0 * DEF_WEIGHT;
double spdFactor = (100 + (SPD - 100) / SPD_NORMALIZE) / 100.0;
double potenFactor = 1.0 + totalPotentialPoints * POTEN_SCALE;
double hitFactor = max(1.0,
1 + (effectHit - 10000 + effectEvade) / 10.0);
double rawScore = (atkFactor + hpFactor + defFactor)
* spdFactor * hitFactor;
double bonusFromLB = limitBreakGrade * 0.02;
double bonusFromSkills = totalSkillLevels * 0.01;
double multiplier = 1.0 + bonusFromLB + bonusFromSkills;
int battlePower = (int)(rawScore * multiplier);
Key points about Battle Power:
- ATK has the highest weight (divided by 10 vs HP/55 and DEF/5)
- Crit interactions are baked into the ATK factor
- Limit Break grades add 2% per grade
- Total skill levels add 1% per level
- Potential points add a small bonus per point
Source Code References
All formulas in this guide are extracted from the game's decompiled C# source code. The key files are:
- NKM.decompiled.cs -- Game model/logic (UnitStatManager, damage calculation, stat builder)
- NKC.decompiled.cs -- Client UI code (stat display, tooltips)
- Star.Templets.decompiled.cs -- Damage templet data structures (AtkFactor, HpFactor, DefFactor fields)
The decompiled and deobfuscated source code is publicly available at github.com/boring877/star-savior-decompiled.