Skip to content

Commit

Permalink
Clean-up damage/attack roll calculations and bonus builders
Browse files Browse the repository at this point in the history
  • Loading branch information
garyttierney committed Jan 28, 2018
1 parent d392913 commit 547ef90
Show file tree
Hide file tree
Showing 7 changed files with 150 additions and 108 deletions.
66 changes: 3 additions & 63 deletions game/plugin/entity/combat/src/framework/attack/attack.kt
Original file line number Diff line number Diff line change
@@ -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(
Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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)
}
}
14 changes: 7 additions & 7 deletions game/plugin/entity/combat/src/framework/attack/attack_type.kt
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down
74 changes: 74 additions & 0 deletions game/plugin/entity/combat/src/framework/attack/attack_utils.kt
Original file line number Diff line number Diff line change
@@ -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()
}
96 changes: 62 additions & 34 deletions game/plugin/entity/combat/src/framework/combat_bonuses.kt
Original file line number Diff line number Diff line change
@@ -1,46 +1,74 @@
data class DamageBonuses(val stab: Int, val slash: Int, val crush: Int, val magic: Int, val range: Int)
enum class CombatBonus {
MeleeStrength,
RangedStrength,
Prayer
}

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: DamageBonuses,
val defence: DamageBonuses,
val meleeStrength: Int,
val rangedStrength: Int,
val prayer: Int
)
val attack: AttackBonuses,
val defence: AttackBonuses,
private val combatBonuses: Map<CombatBonus, Int>
) {
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 = DamageBonuses(0, 0, 0, 0, 0)
var defenceBonuses = DamageBonuses(0, 0, 0, 0, 0)
var meleeStrength = 0
var rangedStrength = 0
var prayer = 0
var attackBonuses = AttackBonuses.default()
var defenceBonuses = AttackBonuses.default()

fun attack(configurer: DamageBonusesBuilder.() -> Unit) {
val builder = DamageBonusesBuilder()
builder.configurer()
fun attack(configurer: AttackBonusesBuilder.() -> Unit) {
val builder = AttackBonusesBuilder()
builder.configurer()

attackBonuses = builder.build()
}
attackBonuses = builder.build()
}

fun defence(configurer: DamageBonusesBuilder.() -> Unit) {
val builder = DamageBonusesBuilder()
builder.configurer()
fun defence(configurer: AttackBonusesBuilder.() -> Unit) {
val builder = AttackBonusesBuilder()
builder.configurer()

defenceBonuses = builder.build()
}
defenceBonuses = builder.build()
}

fun build(): CombatBonuses {
return CombatBonuses(attackBonuses, defenceBonuses, meleeStrength, rangedStrength, prayer)
}
fun build(): CombatBonuses {
return CombatBonuses(attackBonuses, defenceBonuses, mapOf(
CombatBonus.MeleeStrength to meleeStrength,
CombatBonus.RangedStrength to rangedStrength,
CombatBonus.Prayer to prayer
))
}
}

class DamageBonusesBuilder(
var stab: Int = 0,
var slash: Int = 0,
var crush: Int = 0,
var magic: Int = 0,
var range: Int = 0
class AttackBonusesBuilder(
var stab: Int = 0,
var slash: Int = 0,
var crush: Int = 0,
var magic: Int = 0,
var range: Int = 0
) {
fun build(): DamageBonuses {
return DamageBonuses(stab, slash, crush, magic, range)
}

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
))
}
}
1 change: 1 addition & 0 deletions game/plugin/entity/combat/src/framework/combat_state.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions game/plugin/entity/combat/src/framework/equipment/weapon.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -75,7 +75,6 @@ class WeaponClassStyleBuilder(val attackStyle: AttackStyle) {

return WeaponClassStyle(
button ?: throw IllegalStateException("Combat style button is required"),
0,
attackStyle,
attack,
blockAnimation
Expand Down

0 comments on commit 547ef90

Please sign in to comment.