Implemented ::calcdefence command

Implemented passive combat buffs for the following familiars:
Geyser Titan (ranged offence +1 +3% of player level rounded up)
Wolpertinger (magic defence +5%)
Iron Titan (melee defence +10%)
Steel Titan (melee defence +15%)
This commit is contained in:
Bishop
2026-04-01 14:53:58 +00:00
committed by Ryan
parent 4eebfd0c7e
commit 643cd6c359
4 changed files with 109 additions and 0 deletions
@@ -1,6 +1,7 @@
package core.game.node.entity.combat
import content.global.skill.skillcapeperks.SkillcapePerks
import content.global.skill.summoning.SummoningPouch
import core.game.node.entity.Entity
import core.game.node.entity.combat.equipment.ArmourSet
import core.game.node.entity.combat.spell.SpellType
@@ -200,6 +201,7 @@ open class MagicSwingHandler (vararg flags: SwingHandlerFlag)
effectiveMagicLevel = floor(effectiveMagicLevel + (victim.prayer.getSkillBonus(Skills.MAGIC) * effectiveMagicLevel))
effectiveDefenceLevel = effectiveDefenceLevel * 0.3 + effectiveMagicLevel * 0.7 + 8
effectiveDefenceLevel *= familiarDefenceBonus(victim)
return effectiveDefenceLevel.toInt() * styleDefenceBonus
}
is NPC -> {
@@ -220,6 +222,20 @@ open class MagicSwingHandler (vararg flags: SwingHandlerFlag)
return 1.0
}
/**
* Check to see whether the player is receiving a defensive bonus from an active familiar.
* - Wolpertinger => +5%
*/
private fun familiarDefenceBonus(e: Entity?): Double {
if (e !is Player) return 1.0
val fam = try {
e.familiarManager?.familiar
} catch (ex: Exception) {
null
} ?: return 1.0
return if (fam.pouchId == SummoningPouch.WOLPERTINGER_POUCH.pouchId) 1.05 else 1.0
}
override fun addExperience(entity: Entity?, victim: Entity?, state: BattleState?) {
if (state?.spell != null && entity is Player) {
state.spell.addExperience(entity, state.totalDamage)
@@ -4,6 +4,7 @@ import content.global.skill.skillcapeperks.SkillcapePerks
import content.global.skill.slayer.SlayerEquipmentFlags
import content.global.skill.slayer.SlayerManager
import content.global.skill.slayer.Tasks
import content.global.skill.summoning.SummoningPouch
import core.api.*
import core.api.EquipmentSlot
import core.game.container.impl.EquipmentContainer
@@ -235,6 +236,7 @@ open class MeleeSwingHandler (vararg flags: SwingHandlerFlag)
else if (victim.properties.attackStyle.style == WeaponInterface.STYLE_CONTROLLED) effectiveDefenceLevel += 1
effectiveDefenceLevel += 8
effectiveDefenceLevel *= getSetMultiplier(victim, Skills.DEFENCE)
effectiveDefenceLevel *= familiarDefenceBonus(victim)
return effectiveDefenceLevel.toInt() * styleDefenceBonus
}
is NPC -> {
@@ -282,6 +284,25 @@ open class MeleeSwingHandler (vararg flags: SwingHandlerFlag)
|| name == "Skeleton" || name == "Zogre" || name == "Spiritual Mage")
}
/**
* Check to see whether the player is receiving a defensive bonus from an active familiar.
* - Iron Titan => +10%
* - Steel Titan => +15%
*/
private fun familiarDefenceBonus(e: Entity?): Double {
if (e !is Player) return 1.0
val fam = try {
e.familiarManager?.familiar
} catch (ex: Exception) {
null
} ?: return 1.0
return when (fam.pouchId) {
SummoningPouch.IRON_TITAN_POUCH.pouchId -> 1.10
SummoningPouch.STEEL_TITAN_POUCH.pouchId -> 1.15
else -> 1.0
}
}
companion object {
/**
* Checks if the entity is using a halberd.
@@ -1,6 +1,7 @@
package core.game.node.entity.combat
import content.global.skill.skillcapeperks.SkillcapePerks
import content.global.skill.summoning.SummoningPouch
import core.api.*
import core.game.container.impl.EquipmentContainer
import core.game.node.entity.Entity
@@ -207,6 +208,7 @@ open class RangeSwingHandler (vararg flags: SwingHandlerFlag) : CombatSwingHandl
effectiveRangedLevel = floor(effectiveRangedLevel + (entity.prayer.getSkillBonus(Skills.RANGE) * effectiveRangedLevel))
if(entity.properties.attackStyle.style == WeaponInterface.STYLE_RANGE_ACCURATE) effectiveRangedLevel += 3
effectiveRangedLevel += 8
effectiveRangedLevel += familiarOffenceBonus(entity)
effectiveRangedLevel *= getSetMultiplier(entity, Skills.RANGE)
if(SkillcapePerks.isActive(SkillcapePerks.ACCURATE_MARKSMAN,entity)) effectiveRangedLevel *= 1.1
@@ -245,6 +247,7 @@ open class RangeSwingHandler (vararg flags: SwingHandlerFlag) : CombatSwingHandl
effectiveStrengthLevel = floor(effectiveStrengthLevel + (entity.prayer.getSkillBonus(Skills.RANGE) * effectiveStrengthLevel))
if(entity.properties.attackStyle.style == WeaponInterface.STYLE_RANGE_ACCURATE) effectiveStrengthLevel += 3
effectiveStrengthLevel += 8
effectiveStrengthLevel += familiarOffenceBonus(entity)
effectiveStrengthLevel *= getSetMultiplier(entity, Skills.RANGE)
effectiveStrengthLevel = floor(effectiveStrengthLevel)
if (!flags.contains(SwingHandlerFlag.IGNORE_STAT_BOOSTS_DAMAGE))
@@ -301,6 +304,22 @@ open class RangeSwingHandler (vararg flags: SwingHandlerFlag) : CombatSwingHandl
} else super.getArmourSet(e)
}
/**
* Check to see whether the player is receiving an offensive bonus from an active familiar.
* - Geyser Titan => 1 + 3% of ranged level
*/
private fun familiarOffenceBonus(e: Entity?): Double {
if (e !is Player) return 0.0
val fam = try {
e.familiarManager?.familiar
} catch (ex: Exception) {
null
} ?: return 0.0
return if (fam.pouchId == SummoningPouch.GEYSER_TITAN_POUCH.pouchId) {
1.0 + ceil(e.skills.getLevel(Skills.RANGE) * 0.03)
} else 0.0
}
companion object {
/**
* Checks if the entity has the ammunition needed to proceed.
@@ -27,6 +27,7 @@ import core.game.system.communication.CommunicationInfo
import core.game.world.map.RegionManager
import core.game.world.map.build.DynamicRegion
import core.game.world.repository.Repository
import core.game.node.entity.combat.equipment.WeaponInterface
import core.plugin.Initializable
import core.tools.Log
import core.tools.StringUtils
@@ -131,6 +132,58 @@ class MiscCommandSet : CommandSet(Privilege.ADMIN){
notify(player, "max hit: ${hit} (${(swingHandler as Object).getClass().getName()})")
}
define("calcdefence", Privilege.STANDARD, "::calcdefence <lt>NPC ID<gt>", "Calculates and prints your current raw defence values for Melee, Ranged and Magic against a given NPC.") { player, args ->
val meleeHandler = core.game.node.entity.combat.MeleeSwingHandler()
val rangeHandler = core.game.node.entity.combat.RangeSwingHandler()
val magicHandler = core.game.node.entity.combat.MagicSwingHandler()
var attacker: core.game.node.entity.Entity = player
if (args.size > 1) {
val npcId = args[1].toInt()
val npc = NPC(npcId)
npc.initConfig()
attacker = npc
notify(player, "Calculating defence against NPC: ${npc.name} (ID=$npcId)")
val bonuses = npc.properties.bonuses
var maxBonus = Int.MIN_VALUE
var maxIndex = 0
for (i in 0..4) {
if (i in bonuses.indices) {
val v = bonuses[i]
if (v > maxBonus) {
maxBonus = v
maxIndex = i
}
}
}
if (maxBonus == Int.MIN_VALUE) {
maxBonus = 0
maxIndex = 0
}
npc.properties.attackStyle = WeaponInterface.AttackStyle(WeaponInterface.STYLE_CONTROLLED,maxIndex)
} else {
notify(player, "Calculating defence against yourself (no NPC specified).")
}
fun hitChance(accuracy: Int, defence: Int): Double {
return if (accuracy > defence) {
1.0 - ((defence + 2.0) / (2.0 * (accuracy + 1.0)))
} else {
accuracy / (2.0 * (defence + 1.0))
}
}
val meleeAccuracy = meleeHandler.calculateAccuracy(attacker)
val meleeDefence = meleeHandler.calculateDefence(player, attacker)
val meleeChance = hitChance(meleeAccuracy, meleeDefence)
notify(player, "Your melee defence: $meleeDefence; Attacker accuracy: $meleeAccuracy; Chance to be hit: $meleeChance")
val rangeAccuracy = rangeHandler.calculateAccuracy(attacker)
val rangeDefence = rangeHandler.calculateDefence(player, attacker)
val rangeChance = hitChance(rangeAccuracy, rangeDefence)
notify(player, "Your range defence: $rangeDefence; Attacker accuracy: $rangeAccuracy; Chance to be hit: $rangeChance")
val magicAccuracy = magicHandler.calculateAccuracy(attacker)
val magicDefence = magicHandler.calculateDefence(player, attacker)
val magicChance = hitChance(magicAccuracy, magicDefence)
notify(player, "Your magic defence: $magicDefence; Attacker accuracy: $magicAccuracy; Chance to be hit: $magicChance")
}
/**
* Empty a player's inventory
* ADMIN only (for obvious reasons)