🎯 Complete Damage Calculation
Full damage pipeline dengan step-by-step calculation dan contoh implementasi.
📋 Damage Pipeline Overview
🔧 Implementation Ready
Dokumentasi ini berisi complete damage formula yang bisa langsung diimplementasikan ke dalam game code.
┌─────────────────────────────────────────────────────────────────┐
│ DAMAGE CALCULATION PIPELINE │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 1. HIT CHECK → Miss / Hit / Critical │
│ ↓ │
│ 2. BASE DAMAGE → GATK + ATK (PATK or MATK) │
│ ↓ │
│ 3. SKILL MODIFIER → Skill multiplier & flat bonus │
│ ↓ │
│ 4. CRITICAL MODIFIER → Apply CDMG if critical │
│ ↓ │
│ 5. DEFENSE REDUCTION → Apply DEF with penetration │
│ ↓ │
│ 6. ELEMENT MODIFIER → Elemental weakness/resistance │
│ ↓ │
│ 7. PVE DAMAGE MOD → Monster type damage bonus (if vs mob) │
│ ↓ │
│ 8. DAMAGE MODIFIERS → Buffs, Debuffs, PvP reduction │
│ ↓ │
│ 9. BLOCK CHECK → Reduce if blocked │
│ ↓ │
│ 10. FINAL DAMAGE → Apply to target HP │
│ │
└─────────────────────────────────────────────────────────────────┘
Step 1: Hit Check
function checkHit(attacker, defender) {
// Calculate hit chance
let hitChance = 100 - calculateEvasionChance(attacker, defender);
// Apply minimum/maximum
hitChance = Math.max(5, Math.min(95, hitChance));
let roll = random(0, 100);
if (roll > hitChance) {
return "MISS";
}
// Check for critical
let critChance = calculateCritChance(attacker, defender);
if (random(0, 100) < critChance) {
return "CRITICAL";
}
return "HIT";
}
function calculateEvasionChance(attacker, defender) {
let evasion = defender.EVA;
let accuracy = attacker.ACC;
let levelDiff = defender.level - attacker.level;
// Level modifier
let levelMod = 1 + (levelDiff * 0.05);
levelMod = Math.max(0.5, Math.min(1.5, levelMod));
let evaChance = (evasion / (evasion + accuracy)) * 100 * levelMod;
// Apply caps
return Math.min(50, evaChance); // Hard cap 50%
}
Step 2: Base Damage Calculation
function calculateBaseDamage(attacker, damageType) {
let GATK = randomRange(attacker.weapon.minDmg, attacker.weapon.maxDmg);
// Apply weapon enhancement
GATK *= (1 + attacker.weapon.enhancement * 0.03);
// Apply weapon quality
GATK *= getQualityMultiplier(attacker.weapon.quality);
let ATK;
if (damageType === "PHYSICAL") {
ATK = attacker.PATK;
} else if (damageType === "MAGIC") {
ATK = attacker.MATK;
}
return GATK + ATK;
}
function getQualityMultiplier(quality) {
const multipliers = {
"NORMAL": 1.0,
"MAGIC": 1.1,
"RARE": 1.25,
"EPIC": 1.4,
"LEGENDARY": 1.6
};
return multipliers[quality] || 1.0;
}
Step 3: Skill Modifier
function applySkillModifier(baseDamage, skill, attacker) {
// Skill has: multiplier (%), flatBonus, scalingStat
let skillDamage = baseDamage * (skill.multiplier / 100);
// Add flat bonus
skillDamage += skill.flatBonus;
// Add stat scaling if any
if (skill.scalingStat === "STR") {
skillDamage += attacker.STR * skill.statScaling;
} else if (skill.scalingStat === "INT") {
skillDamage += attacker.INT * skill.statScaling;
} else if (skill.scalingStat === "DEX") {
skillDamage += attacker.DEX * skill.statScaling;
}
return skillDamage;
}
// Example skill definition
const powerStrike = {
name: "Power Strike",
multiplier: 150, // 150% of base damage
flatBonus: 50, // +50 flat damage
scalingStat: "STR",
statScaling: 2.0, // +2 damage per STR
damageType: "PHYSICAL"
};
Step 4: Critical Damage Modifier
function applyCriticalModifier(damage, attacker, hitResult) {
if (hitResult !== "CRITICAL") {
return damage;
}
let critDamage = attacker.CDMG; // Percentage, e.g., 200 = 200%
// Apply caps (soft cap handling)
if (critDamage > 250) {
let overCap = critDamage - 250;
let diminished = overCap * 0.5;
critDamage = Math.min(350, 250 + diminished);
}
return damage * (critDamage / 100);
}
function calculateCritChance(attacker, defender) {
let baseCrit = 3; // Base 3% for all
let dexBonus = attacker.DEX * 0.05;
let equipBonus = attacker.critBonus || 0;
let potionBonus = attacker.critPotion || 0;
let totalCrit = baseCrit + dexBonus + equipBonus + potionBonus;
// Level difference penalty
let levelDiff = defender.level - attacker.level;
if (levelDiff > 0) {
totalCrit -= levelDiff * 4; // -4% per level
} else if (levelDiff < 0) {
totalCrit += Math.abs(levelDiff) * 2; // +2% per level
totalCrit = Math.min(totalCrit, baseCrit + 10); // Cap bonus at +10%
}
// Apply soft cap
if (totalCrit > 35) {
let overCap = totalCrit - 35;
let diminished = overCap * 0.5;
totalCrit = Math.min(55, 35 + diminished);
}
return Math.max(0, totalCrit);
}
Step 5: Defense Reduction
function applyDefenseReduction(damage, attacker, defender, damageType) {
let defense;
let penetration;
if (damageType === "PHYSICAL") {
defense = defender.PDEF;
penetration = attacker.physicalPEN || 0;
} else {
defense = defender.MDEF;
penetration = attacker.magicPEN || 0;
}
// Apply flat penetration first
let flatPen = attacker.flatPEN || 0;
defense = Math.max(0, defense - flatPen);
// Apply percentage penetration
penetration = Math.min(50, penetration); // Cap at 50%
let effectiveDefense = defense * (1 - penetration / 100);
// Calculate damage reduction
const DEFENSE_CONSTANT = 350;
let levelComponent = attacker.level * 10;
let damageReduction = effectiveDefense /
(effectiveDefense + DEFENSE_CONSTANT + levelComponent);
// Cap damage reduction
damageReduction = Math.min(0.75, damageReduction); // Max 75% reduction
return damage * (1 - damageReduction);
}
Defense Calculation Table
| Defense | vs Lv50 (no PEN) | vs Lv50 (30% PEN) |
|---|---|---|
| 300 | 27.3% reduction | 20.2% reduction |
| 500 | 38.5% reduction | 29.8% reduction |
| 700 | 46.7% reduction | 37.5% reduction |
| 1000 | 55.6% reduction | 46.7% reduction |
| 1500 | 65.2% reduction | 56.8% reduction |
Step 6: Elemental Modifier (Value Scale 0-100)
📖 New Elemental System
Uses affinity (0-100) and resistance (0-100) for dynamic scaling. Elemental Affinity scales with gear, skills, and leveling.
ELEMENT RELATIONSHIPS (Rock-Paper-Scissors):
Water STRONG vs Fire
Fire STRONG vs Earth
Earth STRONG vs Wind
Wind STRONG vs Water
Damage Formula:
Step 6a: Apply Attacker Affinity
Elemental DMG = Base Damage × (1 + Affinity / 100)
Step 6b: Apply Defender Resistance
DMG After Resist = Elemental DMG × (1 - Resistance / 100)
(Resistance soft cap: 40%, hard cap: 80%)
Step 6c: Apply Element Relationship
IF Strong vs Weak:
Bonus = 1 + (Affinity / 100) × 0.25
Final = DMG After Resist × Bonus
IF Weak vs Strong:
Penalty = 1 - (Affinity / 100) × 0.25
Final = DMG After Resist × Math.max(0.75, Penalty)
IF Neutral:
Final = DMG After Resist (no modifier)
Affinity Range: 0-100 (Soft Cap: 50, Hard Cap: 100)
Resistance Range: 0-100 (Soft Cap: 40, Hard Cap: 80)
Min Damage (Weak): 75% (cannot be reduced below 75%)
function applyElementalModifier_NEW(damage, skill, attacker, defender) {
// If no elemental damage, return as-is
if (!skill.element || skill.element === "NONE") {
return damage;
}
let attackElement = skill.element;
let attackerAffinity = attacker.elementalAffinity[attackElement] || 0;
let defenderElement = defender.element;
let defenderResistance = defender.elementalResistance[attackElement] || 0;
// Step 6a: Apply Attacker's Elemental Affinity
let elementalDamage = damage * (1 + attackerAffinity / 100);
// Step 6b: Apply Defender's Elemental Resistance
// Cap resistance: soft cap at 40%, hard cap at 80%
let cappedResistance = Math.min(80, defenderResistance);
let damageAfterResist = elementalDamage * (1 - cappedResistance / 100);
// Step 6c: Apply Element Relationship (Strong/Weak)
let relationshipBonus = getElementRelationshipBonus(
attackElement,
defenderElement,
attackerAffinity
);
let finalDamage = damageAfterResist * relationshipBonus;
return finalDamage;
}
function getElementRelationshipBonus(attackElement, defenderElement, affinity) {
// Define strong relationships
const strongAgainst = {
"WATER": "FIRE",
"FIRE": "EARTH",
"EARTH": "WIND",
"WIND": "WATER"
};
const weakAgainst = {
"WATER": "WIND",
"FIRE": "WATER",
"EARTH": "FIRE",
"WIND": "EARTH"
};
// Check if attacker is strong vs defender
if (strongAgainst[attackElement] === defenderElement) {
// Strong vs Weak: Scale bonus based on affinity
// Range: 1.0x (0 affinity) to 1.25x (100 affinity)
let strongBonus = 1 + (affinity / 100) * 0.25;
return strongBonus;
}
// Check if attacker is weak vs defender
if (weakAgainst[attackElement] === defenderElement) {
// Weak vs Strong: Scale penalty based on affinity
// Range: 1.0x (0 affinity) to 0.75x (100 affinity) minimum
let weakPenalty = 1 - (affinity / 100) * 0.25;
// Cannot go below 0.75x (25% max damage reduction)
return Math.max(0.75, weakPenalty);
}
// Neutral relationship
return 1.0;
}
Elemental Affinity & Resistance Table
| Fire Affinity | vs Water (Strong) | vs Water Resist 30% | Final DMG (1000 base) |
|---|---|---|---|
| 0 (No Affinity) | 1.00x | 700 | 700 |
| 25 | 1.0625x | 788 | 838 |
| 50 | 1.125x | 875 | 984 |
| 75 | 1.1875x | 963 | 1145 |
| 100 (Max) | 1.25x | 1050 | 1312 |
Elemental Affinity Sources (INT-Based)
Base Affinity from INT (Primary):
- Affinity% = INT / 4
- Example: INT 120 = 30% base affinity
- Example: INT 100 = 25% base affinity
Class Capability:
✨ SPIRITUALIST: INT 14-24+ (3.5-6% base, can reach 100% with gear)
→ PRIMARY elemental damage user
🔧 SPECIALIST: INT 10-20 (2.5-5% base, can reach 60-70% with gear)
→ SECONDARY elemental user
→ Built-in +5-10% all element resistance (UNIQUE!)
⚔️ WARRIOR: INT 6-14 (1.5-3.5% base - NOT viable)
🏹 RANGER: INT 4-10 (1-2.5% base - NOT viable)
🔫 LAUNCHER: INT 6-12 (1.5-3% base - NOT viable)
Equipment (Additional):
- Element-specific gear: +5-15% Affinity
- Elemental Stone: +10-25% Affinity
- Ancient Relic: +20-40% Affinity
- Element Ring: +10% Affinity
- Element Amulet: +12-15% Affinity
Skills & Passives (Per-Skill):
- Element Mastery: +10-15% Affinity (when using that element)
- Element Attunement: +5-10% Affinity
- Temporary buffs: +15-25% Affinity (duration)
Total Affinity Formula:
Affinity% = (INT / 4) + Equipment + Skills + Buffs
Soft Cap: 50% | Hard Cap: 100%
NOTE: NO class passive bonus needed. INT bonus already reflects design.
Elemental Resistance Sources
Equipment (Primary Source):
- Element Armor Set: +20% Resistance
- Element Ring: +10% Resistance
- Element Pendant: +12% Resistance
- Element Cape: +15% Resistance
Class Bonus (Specialist Only):
- Specialist: +5-10% ALL element resistance (UNIQUE!)
Temporary Buffs:
- Elemental Shield: +20-30% specific resistance
- Protection Potion: +15-25% all resistances
Total Resistance Formula:
Resistance% = Equipment + ClassBonus + Buffs
Soft Cap: 40% | Hard Cap: 80%
IMPORTANT: SEPARATE FROM MDEF
- MDEF (Step 5): Reduces all magic damage (general)
- Resistance (Step 6c): Reduces specific element (specialized)
- Both apply multiplicatively to elemental spells
Step 7: Damage Modifiers (Buffs/Debuffs)
function applyDamageModifiers(damage, attacker, defender, context) {
let modifier = 1.0;
// Attacker's damage increase buffs
if (attacker.buffs.damageIncrease) {
modifier *= (1 + attacker.buffs.damageIncrease / 100);
}
// Defender's damage taken increase (debuffs)
if (defender.debuffs.damageTakenIncrease) {
modifier *= (1 + defender.debuffs.damageTakenIncrease / 100);
}
// Defender's damage reduction buffs
if (defender.buffs.damageReduction) {
modifier *= (1 - defender.buffs.damageReduction / 100);
}
// PvP damage reduction
if (context.isPvP) {
modifier *= 0.7; // 30% reduction in PvP
}
// Race-specific modifiers
modifier *= getRaceModifier(attacker.race, defender.race);
// Chip War modifiers
if (context.isChipWar) {
if (attacker.isArchon) {
modifier *= 1.2; // Archon deals 20% more
}
if (defender.hasArchonDebuff) {
modifier *= 1.1; // Takes 10% more if archon died
}
}
return damage * modifier;
}
function getRaceModifier(attackerRace, defenderRace) {
// Rock-paper-scissors slight advantage
const advantages = {
"ACCRETIA": "CORA", // Accretia > Cora
"BELLATO": "ACCRETIA", // Bellato > Accretia
"CORA": "BELLATO" // Cora > Bellato
};
if (advantages[attackerRace] === defenderRace) {
return 1.05; // 5% bonus damage
}
return 1.0;
}
Step 8: Block Check
function checkAndApplyBlock(damage, defender, damageType) {
// Only physical damage can be blocked
if (damageType !== "PHYSICAL") {
return { damage: damage, blocked: false };
}
// Must have shield equipped
if (!defender.hasShield) {
return { damage: damage, blocked: false };
}
let blockChance = defender.blockRate;
// Apply caps
blockChance = Math.min(20, blockChance); // Hard cap 20% (Shield +10 max)
if (random(0, 100) < blockChance) {
// Block successful
let blockValue = defender.shield.blockValue; // e.g., 50%
let blockedDamage = damage * (1 - blockValue / 100);
return {
damage: blockedDamage,
blocked: true,
amountBlocked: damage - blockedDamage
};
}
return { damage: damage, blocked: false };
}
Step 9: Final Damage Application
function applyFinalDamage(damage, defender) {
// Apply minimum damage (1)
damage = Math.max(1, Math.floor(damage));
// Apply damage variance (±5%)
let variance = 0.95 + random(0, 0.10);
damage = Math.floor(damage * variance);
// Subtract from HP
defender.currentHP -= damage;
// Check for death
if (defender.currentHP <= 0) {
defender.currentHP = 0;
handleDeath(defender);
}
return damage;
}
📊 Complete Calculation Example
📖 Scenario
Level 50 Striker (Bellato) attacks Level 50 Guardian (Accretia) with Power Strike skill.
=== ATTACKER (Striker) ===
Level: 50
Race: Bellato
Weapon: Epic Dual Blades (+7)
- Min Damage: 60
- Max Damage: 90
- Enhancement: +21% (7 × 3%)
- Quality: Epic (×1.4)
PATK: 280
Crit Rate: 30%
Crit Damage: 205%
Physical PEN: 25%
Skill: Power Strike
- Multiplier: 150%
- Flat Bonus: 50
- STR Scaling: 2.0 × 70 STR = 140
=== DEFENDER (Guardian) ===
Level: 50
Race: Accretia
PDEF: 600
Evasion: 150
Block Rate: 45%
Block Value: 55%
HP: 5000
=== CALCULATION ===
Step 1: Hit Check
- Evasion Chance: (150 - 350) × 0.1 + 30% = 10%
- Roll: 45 → HIT (not evaded)
- Crit Check: 30% chance, Roll: 20 → CRITICAL!
Step 2: Base Damage
- GATK Roll: 75 (between 60-90)
- With Enhancement: 75 × 1.21 = 90.75
- With Quality: 90.75 × 1.4 = 127.05
- Total Base: 127.05 + 280 (PATK) = 407.05
Step 3: Skill Modifier
- Skill Damage: 407.05 × 1.5 = 610.58
- Flat Bonus: +50 = 660.58
- STR Scaling: +140 = 800.58
Step 4: Critical Modifier
- CDMG: 205%
- Crit Damage: 800.58 × 2.05 = 1641.19
Step 5: Defense Reduction
- Defender PDEF: 600
- Attacker PEN: 25%
- Effective DEF: 600 × 0.75 = 450
- DR%: 450 / (450 + 350 + 500) = 34.6%
- After Defense: 1641.19 × 0.654 = 1073.34
Step 6: Elemental Modifier
- No element on attack
- Modifier: ×1.0
- Damage: 1127.22
Step 7: Damage Modifiers
- Race Advantage (Bellato vs Accretia): ×1.05
- PvP Reduction: ×0.7
- Final Modifier: 0.735
- Damage: 1073.34 × 0.735 = 788.91
Step 8: Block Check
- Block Rate: 17% (Shield +7)
- Roll: 60 → NOT BLOCKED
Step 9: Final Damage
- Variance: ×0.97 (random)
- Final: 788.91 × 0.97 = 765.24 → 765 damage
=== RESULT ===
Striker deals 765 CRITICAL damage to Guardian!
Guardian HP: 5000 → 4235
🔧 Complete Damage Function
function calculateDamage(attacker, defender, skill, context) {
// Step 1: Hit Check
let hitResult = checkHit(attacker, defender);
if (hitResult === "MISS") {
return { damage: 0, result: "MISS" };
}
// Step 2: Base Damage
let damage = calculateBaseDamage(attacker, skill.damageType);
// Step 3: Skill Modifier
damage = applySkillModifier(damage, skill, attacker);
// Step 4: Critical Modifier
damage = applyCriticalModifier(damage, attacker, hitResult);
// Step 5: Defense Reduction
damage = applyDefenseReduction(damage, attacker, defender, skill.damageType);
// Step 6: Elemental Modifier
damage = applyElementalModifier(damage, skill.element, defender);
// Step 7: Damage Modifiers
damage = applyDamageModifiers(damage, attacker, defender, context);
// Step 8: Block Check
let blockResult = checkAndApplyBlock(damage, defender, skill.damageType);
damage = blockResult.damage;
// Step 9: Final Damage
let finalDamage = applyFinalDamage(damage, defender);
return {
damage: finalDamage,
result: hitResult,
blocked: blockResult.blocked,
blockedAmount: blockResult.amountBlocked || 0
};
}
📑 Quick Reference Card
⚔️ Offensive Formulas
- PATK = STR × 2 + Equipment
- MATK = INT × 3 + Equipment
- Global ATK = +% to PATK & MATK
- Crit Rate = 3% + DEX × 0.05
- Crit DMG = 150% base
- Soft Cap Crit: 35%
🛡️ Defensive Formulas
- PDEF = Armor + STA × 0.3
- MDEF = Armor + INT × 0.4
- Global DEF = +% to PDEF & MDEF
- DR = DEF / (DEF + 350 + Lv×10)
- Evasion Max: 48%
- Block Max: 20%
📊 Constants
- DEFENSE_CONSTANT = 350
- PVP_REDUCTION = 30%
- MIN_HIT_CHANCE = 5%
- MAX_HIT_CHANCE = 95%
- DAMAGE_VARIANCE = ±5%
🔥 Element Bonus
- Strong vs Weak: +25%
- Max Resist: 75%
- Min Resist: -50%