package combat import "math/rand" func PlayerEffective(level, styleBonus int) int { return level + styleBonus + 8 } func NPCEffective(level int) int { return level + 9 } // ScienceEffective is the effective-level formula for science attacks. It is // intentionally the same as NPCEffective (level + 9) and is applied to BOTH the // attacker and defender of a science-mod exchange (see scienceAttack), giving a // symmetric science-vs-science model with no attack styles. It is kept as a // distinct function to document that intent independently of NPCEffective. func ScienceEffective(level int) int { return level + 9 } func AttackRoll(effective, equipBonus int) int { return effective * (equipBonus + 64) } func HitChance(attackRoll, defenseRoll int) float64 { a := float64(attackRoll) d := float64(defenseRoll) if a > d { return 1.0 - (d+2.0)/(2.0*(a+1.0)) } return a / (2.0 * (d + 1.0)) } func HitCheck(attackRoll, defenseRoll int) bool { return rand.Float64() < HitChance(attackRoll, defenseRoll) } func MaxHit(effective, equipStrBonus int) int { hit := (effective*(equipStrBonus+64) + 320) / 640 if hit < 1 { hit = 1 } return hit } func RollDamage(maxHit int) int { if maxHit <= 0 { return 0 } d := rand.Intn(maxHit + 1) if d < 1 { d = 1 } return d } func AttackStyleBonus(style string) (attack, strength, defense int) { switch style { case "accurate": return 3, 0, 0 case "aggressive": return 0, 3, 0 case "defensive": return 0, 0, 3 case "balanced": return 1, 1, 1 default: return 0, 0, 0 } } func RangedStyleBonus(style string) (ranged, defense int) { switch style { case "accurate": return 3, 0 case "aggressive": return 3, 0 case "defensive": return 0, 3 case "balanced": return 1, 1 default: return 0, 0 } } func SelectBonus(attackType string, stab, slash, crush, science, ranged int) int { switch attackType { case AttackStab: return stab case AttackSlash: return slash case AttackCrush: return crush case AttackScience: return science case AttackRanged: return ranged default: return crush } }