mirror of
https://gitlab.com/2009scape/2009scape.git
synced 2025-12-09 16:45:44 -07:00
Swing handler flags to ignore modifiers + fix issue with chins
This commit is contained in:
parent
9b163cea32
commit
691220c8d1
6 changed files with 170 additions and 22 deletions
|
|
@ -1,9 +1,7 @@
|
|||
package content.global.handlers.item.equipment.special;
|
||||
|
||||
import core.game.node.entity.Entity;
|
||||
import core.game.node.entity.combat.BattleState;
|
||||
import core.game.node.entity.combat.CombatStyle;
|
||||
import core.game.node.entity.combat.InteractionType;
|
||||
import core.game.node.entity.combat.*;
|
||||
import core.game.node.entity.combat.equipment.Ammunition;
|
||||
import core.game.node.entity.combat.equipment.RangeWeapon;
|
||||
import core.game.node.entity.combat.equipment.Weapon;
|
||||
|
|
@ -14,7 +12,6 @@ import core.game.node.entity.skill.Skills;
|
|||
import core.game.world.map.RegionManager;
|
||||
import core.game.world.update.flag.context.Graphics;
|
||||
import core.tools.RandomFunction;
|
||||
import core.game.node.entity.combat.RangeSwingHandler;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
|
@ -37,8 +34,8 @@ public final class ChinchompaSwingHandler extends RangeSwingHandler {
|
|||
/**
|
||||
* Constructs a new {@code ChinchompaSwingHandler} {@code Object}.
|
||||
*/
|
||||
private ChinchompaSwingHandler() {
|
||||
super();
|
||||
public ChinchompaSwingHandler() {
|
||||
super(SwingHandlerFlag.IGNORE_STAT_BOOSTS_DAMAGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ import kotlin.math.floor
|
|||
* @author Emperor
|
||||
* @author Ceikry - Kotlin refactoring, general cleanup
|
||||
*/
|
||||
abstract class CombatSwingHandler(var type: CombatStyle?) {
|
||||
abstract class CombatSwingHandler(var type: CombatStyle?, vararg val flags: SwingHandlerFlag) {
|
||||
/**
|
||||
* The mapping of the special attack handlers.
|
||||
*/
|
||||
|
|
@ -660,3 +660,10 @@ abstract class CombatSwingHandler(var type: CombatStyle?) {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
enum class SwingHandlerFlag {
|
||||
IGNORE_STAT_BOOSTS_DAMAGE,
|
||||
IGNORE_STAT_BOOSTS_ACCURACY,
|
||||
IGNORE_PRAYER_BOOSTS_DAMAGE,
|
||||
IGNORE_PRAYER_BOOSTS_ACCURACY
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ import kotlin.math.floor
|
|||
* @author Emperor
|
||||
* @author Ceikry, Kotlin conversion + cleanup
|
||||
*/
|
||||
open class MagicSwingHandler
|
||||
: CombatSwingHandler(CombatStyle.MAGIC) {
|
||||
open class MagicSwingHandler (vararg flags: SwingHandlerFlag)
|
||||
: CombatSwingHandler(CombatStyle.MAGIC, *flags) {
|
||||
|
||||
override fun canSwing(entity: Entity, victim: Entity): InteractionType? {
|
||||
if (!isProjectileClipped(entity, victim, false)) {
|
||||
|
|
@ -151,12 +151,15 @@ open class MagicSwingHandler
|
|||
}
|
||||
val level = entity.skills.getLevel(Skills.MAGIC, true)
|
||||
var prayer = 1.0
|
||||
if (entity is Player) {
|
||||
if (entity is Player && !flags.contains(SwingHandlerFlag.IGNORE_PRAYER_BOOSTS_ACCURACY)) {
|
||||
prayer += entity.prayer.getSkillBonus(Skills.MAGIC)
|
||||
}
|
||||
val additional = getSetMultiplier(entity, Skills.MAGIC);
|
||||
val effective = floor(level * prayer * additional + spellBonus)
|
||||
val bonus = entity.properties.bonuses[WeaponInterface.BONUS_MAGIC]
|
||||
val bonus =
|
||||
if (!flags.contains(SwingHandlerFlag.IGNORE_STAT_BOOSTS_ACCURACY))
|
||||
entity.properties.bonuses[WeaponInterface.BONUS_MAGIC]
|
||||
else 0
|
||||
return floor((effective + 8) * (bonus + 64) / 10).toInt()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,11 +24,11 @@ import kotlin.math.floor
|
|||
* @author Emperor
|
||||
* @author Ceikry, Kotlin conversion + cleanup
|
||||
*/
|
||||
open class MeleeSwingHandler
|
||||
open class MeleeSwingHandler (vararg flags: SwingHandlerFlag)
|
||||
/**
|
||||
* Constructs a new `MeleeSwingHandler` {@Code Object}.
|
||||
*/
|
||||
: CombatSwingHandler(CombatStyle.MELEE) {
|
||||
: CombatSwingHandler(CombatStyle.MELEE, *flags) {
|
||||
override fun canSwing(entity: Entity, victim: Entity): InteractionType? {
|
||||
//Credits wolfenzi, https://www.rune-server.ee/2009scape-development/rs2-server/snippets/608720-arios-hybridding-improve.html
|
||||
var distance = if (usingHalberd(entity)) 2 else 1
|
||||
|
|
@ -129,7 +129,8 @@ open class MeleeSwingHandler
|
|||
//formula taken from wiki: https://oldschool.runescape.wiki/w/Damage_per_second/Melee#Step_six:_Calculate_the_hit_chance Yes I know it's old school. It's the best resource we have for potentially authentic formulae.
|
||||
entity ?: return 0
|
||||
var effectiveAttackLevel = entity.skills.getLevel(Skills.ATTACK).toDouble()
|
||||
if(entity is Player) effectiveAttackLevel = floor(effectiveAttackLevel + (entity.prayer.getSkillBonus(Skills.ATTACK) * effectiveAttackLevel))
|
||||
if(entity is Player && !flags.contains(SwingHandlerFlag.IGNORE_PRAYER_BOOSTS_ACCURACY))
|
||||
effectiveAttackLevel = floor(effectiveAttackLevel + (entity.prayer.getSkillBonus(Skills.ATTACK) * effectiveAttackLevel))
|
||||
if(entity.properties.attackStyle.style == WeaponInterface.STYLE_ACCURATE) effectiveAttackLevel += 3
|
||||
else if(entity.properties.attackStyle.style == WeaponInterface.STYLE_CONTROLLED) effectiveAttackLevel += 1
|
||||
effectiveAttackLevel += 8
|
||||
|
|
@ -138,7 +139,10 @@ open class MeleeSwingHandler
|
|||
}
|
||||
effectiveAttackLevel *= getSetMultiplier(entity, Skills.ATTACK);
|
||||
effectiveAttackLevel = floor(effectiveAttackLevel)
|
||||
|
||||
if (!flags.contains(SwingHandlerFlag.IGNORE_STAT_BOOSTS_ACCURACY))
|
||||
effectiveAttackLevel *= (entity.properties.bonuses[entity.properties.attackStyle.bonusType] + 64)
|
||||
else effectiveAttackLevel *= 64
|
||||
|
||||
val victimName = entity.properties.combatPulse.getVictim()?.name ?: "none"
|
||||
|
||||
|
|
@ -161,7 +165,7 @@ open class MeleeSwingHandler
|
|||
val level = entity!!.skills.getLevel(Skills.STRENGTH)
|
||||
var bonus = entity.properties.bonuses[11]
|
||||
var prayer = 1.0
|
||||
if (entity is Player) {
|
||||
if (entity is Player && !flags.contains(SwingHandlerFlag.IGNORE_PRAYER_BOOSTS_DAMAGE)) {
|
||||
prayer += entity.prayer.getSkillBonus(Skills.STRENGTH)
|
||||
}
|
||||
var cumulativeStr = floor(level * prayer)
|
||||
|
|
@ -175,6 +179,9 @@ open class MeleeSwingHandler
|
|||
if(entity is Player && SkillcapePerks.isActive(SkillcapePerks.FINE_ATTUNEMENT, entity) && getItemFromEquipment(entity, EquipmentSlot.WEAPON)?.definition?.getRequirement(Skills.STRENGTH) != 0)
|
||||
bonus = ceil(bonus * 1.20).toInt()
|
||||
|
||||
if (flags.contains(SwingHandlerFlag.IGNORE_STAT_BOOSTS_DAMAGE))
|
||||
bonus = 0
|
||||
|
||||
cumulativeStr *= getSetMultiplier(entity, Skills.STRENGTH)
|
||||
|
||||
if(entity is Player && getSlayerTask(entity)?.ids?.contains((entity.properties.combatPulse?.getVictim()?.id ?: 0)) == true)
|
||||
|
|
|
|||
|
|
@ -30,11 +30,11 @@ import kotlin.math.floor
|
|||
* @author Emperor
|
||||
* @author Ceikry, conversion to Kotlin + cleanup
|
||||
*/
|
||||
open class RangeSwingHandler
|
||||
open class RangeSwingHandler (vararg flags: SwingHandlerFlag)
|
||||
/**
|
||||
* Constructs a new `RangeSwingHandler` {@Code Object}.
|
||||
*/
|
||||
: CombatSwingHandler(CombatStyle.RANGE) {
|
||||
: CombatSwingHandler(CombatStyle.RANGE, *flags) {
|
||||
override fun canSwing(entity: Entity, victim: Entity): InteractionType? {
|
||||
if (!isProjectileClipped(entity, victim, false)) {
|
||||
return InteractionType.NO_INTERACT
|
||||
|
|
@ -184,14 +184,17 @@ open class RangeSwingHandler
|
|||
override fun calculateAccuracy(entity: Entity?): Int {
|
||||
entity ?: return 0
|
||||
var effectiveRangedLevel = entity.skills.getLevel(Skills.RANGE).toDouble()
|
||||
if(entity is Player) effectiveRangedLevel = floor(effectiveRangedLevel + (entity.prayer.getSkillBonus(Skills.RANGE) * effectiveRangedLevel))
|
||||
if(entity is Player && !flags.contains(SwingHandlerFlag.IGNORE_PRAYER_BOOSTS_ACCURACY))
|
||||
effectiveRangedLevel = floor(effectiveRangedLevel + (entity.prayer.getSkillBonus(Skills.RANGE) * effectiveRangedLevel))
|
||||
if(entity.properties.attackStyle.style == WeaponInterface.STYLE_RANGE_ACCURATE) effectiveRangedLevel += 3
|
||||
effectiveRangedLevel += 8
|
||||
effectiveRangedLevel *= getSetMultiplier(entity, Skills.RANGE)
|
||||
if(entity is Player && SkillcapePerks.isActive(SkillcapePerks.ACCURATE_MARKSMAN,entity)) effectiveRangedLevel *= 1.1
|
||||
|
||||
effectiveRangedLevel = floor(effectiveRangedLevel)
|
||||
if (!flags.contains(SwingHandlerFlag.IGNORE_STAT_BOOSTS_ACCURACY))
|
||||
effectiveRangedLevel *= (entity.properties.bonuses[entity.properties.attackStyle.bonusType] + 64)
|
||||
else effectiveRangedLevel *= 64
|
||||
|
||||
return floor(effectiveRangedLevel).toInt()
|
||||
}
|
||||
|
|
@ -200,7 +203,7 @@ open class RangeSwingHandler
|
|||
val level = entity!!.skills.getLevel(Skills.RANGE)
|
||||
val bonus = entity.properties.bonuses[14]
|
||||
var prayer = 1.0
|
||||
if (entity is Player) {
|
||||
if (entity is Player && !flags.contains(SwingHandlerFlag.IGNORE_PRAYER_BOOSTS_DAMAGE)) {
|
||||
prayer += entity.prayer.getSkillBonus(Skills.RANGE)
|
||||
}
|
||||
var cumulativeStr = floor(level * prayer)
|
||||
|
|
@ -208,7 +211,11 @@ open class RangeSwingHandler
|
|||
cumulativeStr += 3.0
|
||||
}
|
||||
cumulativeStr *= getSetMultiplier(entity, Skills.RANGE)
|
||||
|
||||
if (!flags.contains(SwingHandlerFlag.IGNORE_STAT_BOOSTS_DAMAGE))
|
||||
cumulativeStr *= (bonus + 64)
|
||||
else cumulativeStr *= 64
|
||||
|
||||
return floor((1.5 + (ceil(cumulativeStr) / 640.0)) * modifier).toInt()
|
||||
//return ((14 + cumulativeStr + bonus / 8 + cumulativeStr * bonus * 0.016865) * modifier).toInt() / 10 + 1
|
||||
}
|
||||
|
|
|
|||
127
Server/src/test/kotlin/content/CombatTests.kt
Normal file
127
Server/src/test/kotlin/content/CombatTests.kt
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
package content
|
||||
|
||||
import TestUtils
|
||||
import content.global.handlers.item.equipment.special.ChinchompaSwingHandler
|
||||
import core.game.node.entity.combat.MagicSwingHandler
|
||||
import core.game.node.entity.combat.MeleeSwingHandler
|
||||
import core.game.node.entity.combat.RangeSwingHandler
|
||||
import core.game.node.entity.combat.SwingHandlerFlag
|
||||
import core.game.node.entity.combat.equipment.WeaponInterface
|
||||
import core.game.node.entity.player.link.prayer.PrayerType
|
||||
import core.game.node.entity.skill.Skills
|
||||
import org.junit.jupiter.api.Assertions
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
class CombatTests {
|
||||
init {
|
||||
TestUtils.preTestSetup()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun swingHandlersFlaggedAsIgnoreStatsShouldNotInfluenceDamage() {
|
||||
val testRangeHandler = RangeSwingHandler(SwingHandlerFlag.IGNORE_STAT_BOOSTS_DAMAGE)
|
||||
val testMeleeHandler = MeleeSwingHandler(SwingHandlerFlag.IGNORE_STAT_BOOSTS_DAMAGE)
|
||||
|
||||
TestUtils.getMockPlayer("ignorestatdamage").use { p ->
|
||||
p.skills.setLevel(Skills.RANGE, 99)
|
||||
val baselineRanged = testRangeHandler.calculateHit(p, p, 1.0)
|
||||
p.properties.bonuses[14] = 250
|
||||
Assertions.assertEquals(baselineRanged, testRangeHandler.calculateHit(p, p, 1.0))
|
||||
|
||||
p.skills.setLevel(Skills.STRENGTH, 99)
|
||||
val baselineMelee = testMeleeHandler.calculateHit(p, p, 1.0)
|
||||
p.properties.bonuses[11] = 250
|
||||
Assertions.assertEquals(baselineMelee, testMeleeHandler.calculateHit(p, p, 1.0))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun swingHandlersFlaggedAsIgnoreStatsShouldNotInfluenceAccuracy() {
|
||||
val testRangeHandler = RangeSwingHandler(SwingHandlerFlag.IGNORE_STAT_BOOSTS_ACCURACY)
|
||||
val testMeleeHandler = MeleeSwingHandler(SwingHandlerFlag.IGNORE_STAT_BOOSTS_ACCURACY)
|
||||
val testMagicHandler = MagicSwingHandler(SwingHandlerFlag.IGNORE_STAT_BOOSTS_ACCURACY)
|
||||
|
||||
TestUtils.getMockPlayer("ignorestataccuracy").use { p ->
|
||||
p.properties.attackStyle = WeaponInterface.AttackStyle(0, WeaponInterface.BONUS_RANGE)
|
||||
p.skills.setLevel(Skills.RANGE, 99)
|
||||
val baselineRanged = testRangeHandler.calculateAccuracy(p)
|
||||
p.properties.bonuses[WeaponInterface.BONUS_RANGE] = 250
|
||||
Assertions.assertEquals(baselineRanged, testRangeHandler.calculateAccuracy(p))
|
||||
|
||||
p.properties.attackStyle = WeaponInterface.AttackStyle(0, WeaponInterface.BONUS_STAB)
|
||||
p.skills.setLevel(Skills.STRENGTH, 99)
|
||||
val baselineMelee = testMeleeHandler.calculateAccuracy(p)
|
||||
p.properties.bonuses[WeaponInterface.BONUS_STAB] = 250
|
||||
Assertions.assertEquals(baselineMelee, testMeleeHandler.calculateAccuracy(p))
|
||||
|
||||
p.properties.attackStyle = WeaponInterface.AttackStyle(0, WeaponInterface.BONUS_MAGIC)
|
||||
p.skills.setLevel(Skills.MAGIC, 99)
|
||||
val baselineMagic = testMagicHandler.calculateAccuracy(p)
|
||||
p.properties.bonuses[WeaponInterface.BONUS_MAGIC] = 250
|
||||
Assertions.assertEquals(baselineMagic, testMagicHandler.calculateAccuracy(p))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun swingHandlersFlaggedAsIgnorePrayerShouldNotInfluenceDamage() {
|
||||
val testRangeHandler = RangeSwingHandler(SwingHandlerFlag.IGNORE_PRAYER_BOOSTS_DAMAGE)
|
||||
val testMeleeHandler = MeleeSwingHandler(SwingHandlerFlag.IGNORE_PRAYER_BOOSTS_DAMAGE)
|
||||
|
||||
TestUtils.getMockPlayer("ignoreprayerdamage").use { p ->
|
||||
p.skills.setStaticLevel(Skills.PRAYER, 99)
|
||||
p.skills.prayerPoints = 1000.0
|
||||
|
||||
p.skills.setLevel(Skills.RANGE, 99)
|
||||
val baselineRanged = testRangeHandler.calculateHit(p, p, 1.0)
|
||||
p.prayer.toggle(PrayerType.EAGLE_EYE)
|
||||
Assertions.assertEquals(baselineRanged, testRangeHandler.calculateHit(p, p, 1.0))
|
||||
p.prayer.toggle(PrayerType.EAGLE_EYE)
|
||||
|
||||
p.skills.setLevel(Skills.STRENGTH, 99)
|
||||
val baselineMelee = testMeleeHandler.calculateHit(p, p, 1.0)
|
||||
p.prayer.toggle(PrayerType.SUPERHUMAN_STRENGTH)
|
||||
Assertions.assertEquals(baselineMelee, testMeleeHandler.calculateHit(p, p, 1.0))
|
||||
p.prayer.toggle(PrayerType.SUPERHUMAN_STRENGTH)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun swingHandlersFlaggedAsIgnorePrayerShouldNotInfluenceAccuracy() {
|
||||
val testRangeHandler = RangeSwingHandler(SwingHandlerFlag.IGNORE_PRAYER_BOOSTS_ACCURACY)
|
||||
val testMeleeHandler = MeleeSwingHandler(SwingHandlerFlag.IGNORE_PRAYER_BOOSTS_ACCURACY)
|
||||
val testMagicHandler = MagicSwingHandler(SwingHandlerFlag.IGNORE_PRAYER_BOOSTS_ACCURACY)
|
||||
|
||||
TestUtils.getMockPlayer("ignoreprayeraccuracy").use { p ->
|
||||
p.skills.setStaticLevel(Skills.PRAYER, 99)
|
||||
p.skills.prayerPoints = 1000.0
|
||||
|
||||
p.skills.setLevel(Skills.RANGE, 99)
|
||||
val baselineRanged = testRangeHandler.calculateAccuracy(p)
|
||||
p.prayer.toggle(PrayerType.EAGLE_EYE)
|
||||
Assertions.assertEquals(baselineRanged, testRangeHandler.calculateAccuracy(p))
|
||||
p.prayer.toggle(PrayerType.EAGLE_EYE)
|
||||
|
||||
p.skills.setLevel(Skills.ATTACK, 99)
|
||||
val baselineMelee = testMeleeHandler.calculateAccuracy(p)
|
||||
p.prayer.toggle(PrayerType.INCREDIBLE_REFLEXES)
|
||||
Assertions.assertEquals(baselineMelee, testMeleeHandler.calculateAccuracy(p))
|
||||
p.prayer.toggle(PrayerType.INCREDIBLE_REFLEXES)
|
||||
|
||||
p.skills.setLevel(Skills.MAGIC, 99)
|
||||
val baselineMagic = testMagicHandler.calculateAccuracy(p)
|
||||
p.prayer.toggle(PrayerType.MYSTIC_MIGHT)
|
||||
Assertions.assertEquals(baselineMagic, testMagicHandler.calculateAccuracy(p))
|
||||
p.prayer.toggle(PrayerType.MYSTIC_MIGHT)
|
||||
}
|
||||
}
|
||||
|
||||
@Test fun chinchompaSwingHandlerIgnoresStatsForDamage() {
|
||||
val handler = ChinchompaSwingHandler()
|
||||
|
||||
TestUtils.getMockPlayer("chinchompaStatTest").use { p ->
|
||||
val damageBaseline = handler.calculateHit(p, p, 1.0)
|
||||
p.properties.bonuses[14] = 250
|
||||
Assertions.assertEquals(damageBaseline, handler.calculateHit(p, p, 1.0))
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue