mirror of
https://github.com/2006-Scape/apollo.git
synced 2026-07-03 00:38:21 +00:00
Clean-up damage/attack roll calculations and bonus builders
This commit is contained in:
@@ -1,12 +1,6 @@
|
||||
import AttackStyle.*
|
||||
import AttackType.Ranged
|
||||
import org.apollo.game.model.Animation
|
||||
import org.apollo.game.model.entity.Mob
|
||||
import org.apollo.game.model.entity.Player
|
||||
import org.apollo.game.model.entity.Skill
|
||||
import org.apollo.game.plugins.api.attack
|
||||
import org.apollo.game.plugins.api.defence
|
||||
import org.apollo.game.plugins.api.skills
|
||||
|
||||
|
||||
abstract class Attack(
|
||||
@@ -37,39 +31,8 @@ abstract class Attack(
|
||||
}
|
||||
}
|
||||
|
||||
// @todo - refactor this out somewhere, all rolls are the same calculations
|
||||
// (damage, hit + defence)
|
||||
|
||||
val effectiveAttackBase = source.skills.attack.currentLevel
|
||||
|
||||
//@todo - attack prayers
|
||||
val effectiveAttackModifier = 1.0
|
||||
val attackStyleBonus = when (style) {
|
||||
Accurate -> 3
|
||||
Controlled -> 1
|
||||
LongRanged -> 1
|
||||
else -> 0
|
||||
}
|
||||
|
||||
val effectiveAttack = effectiveAttackBase * effectiveAttackModifier + attackStyleBonus + 8
|
||||
//@todo - get attack bonus from stats
|
||||
val attackEquipmentBonus = 0
|
||||
val maxHitRoll = effectiveAttack * (attackEquipmentBonus + 64)
|
||||
|
||||
val effectiveDefenceBase = target.skills.defence.currentLevel
|
||||
|
||||
//@todo - defence prayers
|
||||
val effectiveDefenceModifier = 1.0
|
||||
val defenceStyleBonus = when (style) {
|
||||
Defensive, LongRanged -> 3
|
||||
Controlled -> 1
|
||||
else -> 0
|
||||
}
|
||||
|
||||
val effectiveDefence = effectiveDefenceBase * effectiveDefenceModifier + defenceStyleBonus + 8
|
||||
//@todo - get defence bonus from stats
|
||||
val defenceEquipmentBonus = 0
|
||||
val maxDefenceRoll = effectiveDefence * (defenceEquipmentBonus + 64)
|
||||
val maxHitRoll = calculateBasicMaxRoll(RollType.Attack, source)
|
||||
val maxDefenceRoll = calculateBasicMaxRoll(RollType.Defence, target)
|
||||
|
||||
val accuracy = if (maxHitRoll > maxDefenceRoll) {
|
||||
1 - (maxDefenceRoll + 2) / (2 * (maxHitRoll + 1))
|
||||
@@ -113,29 +76,6 @@ abstract class BasicAttack(
|
||||
requirements: MutableList<AttackRequirement>
|
||||
) : Attack(speed, range, type, style, attackAnimation, requirements) {
|
||||
override fun maxDamage(source: Mob): Int {
|
||||
|
||||
val effectiveStrengthBase = when (type) {
|
||||
Ranged -> source.skillSet.getCurrentLevel(Skill.RANGED)
|
||||
else -> source.skillSet.getCurrentLevel(Skill.STRENGTH)
|
||||
}
|
||||
|
||||
// @todo - prayer + others (?)
|
||||
val effectiveStrengthModifier = 1.0
|
||||
|
||||
val hitStyleBonus = when (style) {
|
||||
Aggressive -> 3
|
||||
LongRanged, Controlled -> 1
|
||||
Defensive -> 0
|
||||
Accurate -> if (type == Ranged) 3 else 0
|
||||
else -> 0
|
||||
}
|
||||
|
||||
val effectiveStrength = Math.floor(effectiveStrengthBase * effectiveStrengthModifier) + hitStyleBonus + 8
|
||||
//@todo - get from combat bonuses
|
||||
val strengthBonus = 0
|
||||
|
||||
val baseDamage = 0.5 + effectiveStrength * (strengthBonus + 64) / 640
|
||||
|
||||
return Math.floor(baseDamage).toInt()
|
||||
return calculateBasicMaxRoll(RollType.Damage, source)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
enum class AttackStyle {
|
||||
Accurate,
|
||||
Aggressive,
|
||||
Defensive,
|
||||
Controlled,
|
||||
AltAggressive,
|
||||
enum class AttackStyle(val attackBonus: Int = 0, val defenceBonus: Int = 0, val strengthBonus: Int = 0) {
|
||||
Accurate(attackBonus = 3, strengthBonus = 3),
|
||||
Aggressive(strengthBonus = 3),
|
||||
Defensive(defenceBonus = 3),
|
||||
Controlled(attackBonus = 1, strengthBonus = 1, defenceBonus = 1),
|
||||
AltAggressive(strengthBonus = 3),
|
||||
Rapid,
|
||||
LongRanged
|
||||
LongRanged(attackBonus = 1,strengthBonus = 1, defenceBonus = 3)
|
||||
}
|
||||
|
||||
enum class AttackType {
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
import AttackType.Magic
|
||||
import AttackType.Ranged
|
||||
import CombatBonus.MeleeStrength
|
||||
import CombatBonus.RangedStrength
|
||||
import org.apollo.game.model.entity.Mob
|
||||
import org.apollo.game.plugins.api.*
|
||||
|
||||
enum class RollType {
|
||||
Attack,
|
||||
Defence,
|
||||
Damage
|
||||
}
|
||||
|
||||
fun calculateBasicMaxRoll(rollType: RollType, mob: Mob, modifiers: List<Double> = emptyList()): Int {
|
||||
val style = mob.combatState.attack.style
|
||||
val attackType = mob.combatState.attack.type
|
||||
|
||||
if (attackType == Magic) {
|
||||
throw IllegalStateException("Basic roll calculator called for a magic attack. Unsupported")
|
||||
}
|
||||
|
||||
val styleBonus = when (rollType) {
|
||||
RollType.Attack -> style.attackBonus
|
||||
RollType.Defence -> style.defenceBonus
|
||||
RollType.Damage -> {
|
||||
if (style == AttackStyle.Accurate && attackType != Ranged) {
|
||||
0
|
||||
} else {
|
||||
style.strengthBonus
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val baseSkill = when (rollType) {
|
||||
RollType.Attack -> {
|
||||
if (attackType == Ranged) {
|
||||
mob.skills.ranged
|
||||
} else {
|
||||
mob.skills.attack
|
||||
}
|
||||
}
|
||||
RollType.Defence -> mob.skills.defence
|
||||
RollType.Damage -> {
|
||||
if (attackType == Ranged) {
|
||||
mob.skills.ranged
|
||||
} else {
|
||||
mob.skills.strength
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val equipmentBonuses = mob.combatState.bonuses
|
||||
val equipmentBonus = when (rollType) {
|
||||
RollType.Attack -> equipmentBonuses.attack[attackType]
|
||||
RollType.Defence -> equipmentBonuses.defence[attackType]
|
||||
RollType.Damage -> {
|
||||
if (attackType == Ranged) {
|
||||
equipmentBonuses[RangedStrength]
|
||||
} else {
|
||||
equipmentBonuses[MeleeStrength]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val modifier = modifiers.reduce { a, b -> a + b }
|
||||
val effectiveLevel = baseSkill.currentLevel * modifier + styleBonus + 8
|
||||
val maxRoll = if (rollType == RollType.Damage) {
|
||||
0.5 + effectiveLevel * (equipmentBonus + 64) / 640
|
||||
} else {
|
||||
effectiveLevel * (equipmentBonus + 64)
|
||||
}
|
||||
|
||||
return maxRoll.toInt()
|
||||
}
|
||||
@@ -1,46 +1,74 @@
|
||||
data class DamageBonuses(val stab: Int, val slash: Int, val crush: Int, val magic: Int, val range: Int)
|
||||
data class CombatBonuses(
|
||||
val attack: DamageBonuses,
|
||||
val defence: DamageBonuses,
|
||||
val meleeStrength: Int,
|
||||
val rangedStrength: Int,
|
||||
val prayer: Int
|
||||
)
|
||||
|
||||
class CombatBonusesBuilder {
|
||||
var meleeStrength = 0
|
||||
var rangedStrength = 0
|
||||
var prayer = 0
|
||||
var attackBonuses = DamageBonuses(0, 0, 0, 0, 0)
|
||||
var defenceBonuses = DamageBonuses(0, 0, 0, 0, 0)
|
||||
|
||||
fun attack(configurer: DamageBonusesBuilder.() -> Unit) {
|
||||
val builder = DamageBonusesBuilder()
|
||||
builder.configurer()
|
||||
|
||||
attackBonuses = builder.build()
|
||||
}
|
||||
|
||||
fun defence(configurer: DamageBonusesBuilder.() -> Unit) {
|
||||
val builder = DamageBonusesBuilder()
|
||||
builder.configurer()
|
||||
|
||||
defenceBonuses = builder.build()
|
||||
}
|
||||
|
||||
fun build(): CombatBonuses {
|
||||
return CombatBonuses(attackBonuses, defenceBonuses, meleeStrength, rangedStrength, prayer)
|
||||
}
|
||||
enum class CombatBonus {
|
||||
MeleeStrength,
|
||||
RangedStrength,
|
||||
Prayer
|
||||
}
|
||||
|
||||
class DamageBonusesBuilder(
|
||||
var stab: Int = 0,
|
||||
var slash: Int = 0,
|
||||
var crush: Int = 0,
|
||||
var magic: Int = 0,
|
||||
var range: Int = 0
|
||||
data class AttackBonuses(private val bonuses: Map<AttackType, Int>) {
|
||||
companion object {
|
||||
fun default() = AttackBonusesBuilder().build()
|
||||
}
|
||||
|
||||
operator fun get(key: AttackType): Int = bonuses[key]!!
|
||||
}
|
||||
|
||||
data class CombatBonuses(
|
||||
val attack: AttackBonuses,
|
||||
val defence: AttackBonuses,
|
||||
private val combatBonuses: Map<CombatBonus, Int>
|
||||
) {
|
||||
fun build(): DamageBonuses {
|
||||
return DamageBonuses(stab, slash, crush, magic, range)
|
||||
}
|
||||
companion object {
|
||||
fun default() = CombatBonusesBuilder().build()
|
||||
}
|
||||
|
||||
operator fun get(key: CombatBonus): Int = combatBonuses[key]!!
|
||||
}
|
||||
|
||||
class CombatBonusesBuilder {
|
||||
var meleeStrength = 0
|
||||
var rangedStrength = 0
|
||||
var prayer = 0
|
||||
var attackBonuses = AttackBonuses.default()
|
||||
var defenceBonuses = AttackBonuses.default()
|
||||
|
||||
fun attack(configurer: AttackBonusesBuilder.() -> Unit) {
|
||||
val builder = AttackBonusesBuilder()
|
||||
builder.configurer()
|
||||
|
||||
attackBonuses = builder.build()
|
||||
}
|
||||
|
||||
fun defence(configurer: AttackBonusesBuilder.() -> Unit) {
|
||||
val builder = AttackBonusesBuilder()
|
||||
builder.configurer()
|
||||
|
||||
defenceBonuses = builder.build()
|
||||
}
|
||||
|
||||
fun build(): CombatBonuses {
|
||||
return CombatBonuses(attackBonuses, defenceBonuses, mapOf(
|
||||
CombatBonus.MeleeStrength to meleeStrength,
|
||||
CombatBonus.RangedStrength to rangedStrength,
|
||||
CombatBonus.Prayer to prayer
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
class AttackBonusesBuilder(
|
||||
var stab: Int = 0,
|
||||
var slash: Int = 0,
|
||||
var crush: Int = 0,
|
||||
var magic: Int = 0,
|
||||
var range: Int = 0
|
||||
) {
|
||||
|
||||
fun build(): AttackBonuses {
|
||||
return AttackBonuses(mapOf(
|
||||
AttackType.Stab to stab,
|
||||
AttackType.Slash to slash,
|
||||
AttackType.Crush to crush,
|
||||
AttackType.Magic to magic,
|
||||
AttackType.Ranged to range
|
||||
))
|
||||
}
|
||||
}
|
||||
@@ -32,6 +32,7 @@ var Mob.combatAttackTick: Long by attribute("combat_attack_tick", 0)
|
||||
|
||||
class CombatState(private val mob: Mob, var attack: Attack) {
|
||||
var target: Mob? by WeakRefHolder()
|
||||
var bonuses = CombatBonuses.default()
|
||||
|
||||
fun ticksSinceAttack(): Long {
|
||||
return mob.world.tick() - mob.combatAttackTick
|
||||
|
||||
@@ -72,8 +72,8 @@ class WeaponBuilder(private val weaponClass: WeaponClass) {
|
||||
combatBonusesBuilder.prayer = value
|
||||
}
|
||||
|
||||
fun attackBonuses(configurer: DamageBonusesBuilder.() -> Unit) = this.combatBonusesBuilder.attack(configurer)
|
||||
fun defenceBonuses(configurer: DamageBonusesBuilder.() -> Unit) = this.combatBonusesBuilder.defence(configurer)
|
||||
fun attackBonuses(configurer: AttackBonusesBuilder.() -> Unit) = this.combatBonusesBuilder.attack(configurer)
|
||||
fun defenceBonuses(configurer: AttackBonusesBuilder.() -> Unit) = this.combatBonusesBuilder.defence(configurer)
|
||||
|
||||
fun build() = Weapon(weaponClass, combatBonusesBuilder.build(), specialAttack)
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import org.apollo.game.model.Animation
|
||||
|
||||
data class SpecialBar(val button: Int, val configId: Int)
|
||||
data class WeaponClassDetails(val widget: Int, val specialBar: SpecialBar?, val styles: List<WeaponClassStyle>)
|
||||
data class WeaponClassStyle(val button: Int, val configId: Int, val attackStyle: AttackStyle, val attack: Attack, val blockAnimation: Animation?)
|
||||
data class WeaponClassStyle(val button: Int, val attackStyle: AttackStyle, val attack: Attack, val blockAnimation: Animation?)
|
||||
|
||||
typealias WeaponClassConfigurer = WeaponClassDetailsBuilder.() -> Unit
|
||||
|
||||
@@ -75,7 +75,6 @@ class WeaponClassStyleBuilder(val attackStyle: AttackStyle) {
|
||||
|
||||
return WeaponClassStyle(
|
||||
button ?: throw IllegalStateException("Combat style button is required"),
|
||||
0,
|
||||
attackStyle,
|
||||
attack,
|
||||
blockAnimation
|
||||
|
||||
Reference in New Issue
Block a user