Merge branch 'npc-diagonal-melee-fix' into 'master'

Check for validity of a moving entitys melee attack

Closes #1952

See merge request 2009scape/2009scape!2204
This commit is contained in:
dam 2025-11-28 17:00:11 +02:00
commit 0c989a4349
3 changed files with 46 additions and 31 deletions

View file

@ -247,7 +247,7 @@ abstract class CombatSwingHandler(var type: CombatStyle?) {
return InteractionType.STILL_INTERACT
}
private fun canStepTowards(entity: Entity, victim: Entity): InteractionType {
protected fun canStepTowards(entity: Entity, victim: Entity): InteractionType {
val closestVictimTile = victim.getClosestOccupiedTile(entity.location)
val closestEntityTile = entity.getClosestOccupiedTile(closestVictimTile)
val dir = closestEntityTile.deriveDirection(closestVictimTile)

View file

@ -30,34 +30,34 @@ open class MeleeSwingHandler (vararg flags: SwingHandlerFlag)
* Constructs a new `MeleeSwingHandler` {@Code Object}.
*/
: 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
var type = InteractionType.STILL_INTERACT
var goodRange = canMelee(entity, victim, distance)
if (!goodRange && victim.properties.combatPulse.getVictim() !== entity && victim.walkingQueue.isMoving && entity.size() == 1) {
type = InteractionType.MOVE_INTERACT
distance += if (entity.walkingQueue.isRunningBoth) 2 else 1
goodRange = canMelee(entity, victim, distance)
}
if (!isProjectileClipped(entity, victim, !usingHalberd(entity))) {
return InteractionType.NO_INTERACT
}
val isRunning = entity.walkingQueue.runDir != -1
val enemyRunning = victim.walkingQueue.runDir != -1
// THX 4 fix tom <333.
if (super.canSwing(entity, victim) != InteractionType.NO_INTERACT) {
val maxDistance = if (isRunning) if (enemyRunning) 3 else 4 else 2
if (entity.walkingQueue.isMoving
&& entity.location.getDistance(victim.location) <= maxDistance) {
return type
} else if (goodRange) {
if (type == InteractionType.STILL_INTERACT) entity.walkingQueue.reset()
return type
}
}
return InteractionType.NO_INTERACT
}
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
var type = InteractionType.STILL_INTERACT
var goodRange = canMelee(entity, victim, distance)
if (!goodRange && victim.properties.combatPulse.getVictim() !== entity && victim.walkingQueue.isMoving && entity.size() == 1) {
type = InteractionType.MOVE_INTERACT
distance += if (entity.walkingQueue.isRunningBoth) 2 else 1
goodRange = canMelee(entity, victim, distance)
}
if (!isProjectileClipped(entity, victim, !usingHalberd(entity))) {
return InteractionType.NO_INTERACT
}
val isRunning = entity.walkingQueue.runDir != -1
val enemyRunning = victim.walkingQueue.runDir != -1
// THX 4 fix tom <333.
if (super.canSwing(entity, victim) != InteractionType.NO_INTERACT) {
val maxDistance = if (isRunning) if (enemyRunning) 3 else 4 else 2
if (entity.walkingQueue.isMoving && entity.location.getDistance(victim.location) <= maxDistance && goodRange) {
return type
} else if (goodRange) {
if (canStepTowards(entity, victim) == InteractionType.NO_INTERACT) return InteractionType.NO_INTERACT
if (type == InteractionType.STILL_INTERACT) entity.walkingQueue.reset()
return type
}
}
return InteractionType.NO_INTERACT
}
override fun swing(entity: Entity?, victim: Entity?, state: BattleState?): Int {
var hit = 0

View file

@ -522,8 +522,23 @@ public final class Location extends Node {
int stepX = dir.getStepX();
int stepY = dir.getStepY();
if (stepX != 0) output.add(transform(stepX, 0, 0));
if (stepY != 0) output.add(transform(0, stepY, 0));
// alright ill break it down real simple
//
// we can move diagonally but theres no melee attacking diagonally. its gotta be from N, W, S or E.
// if we are moving diagonally, we then need to check if we can attack from one of the valid directions.
// in other words we need to check the two tiles that share a corner with our destination and make sure they can be attacked from
//
// picture this: you are at (0,0). im at (1,1). you want to strangle my head off so you gotta check
// 1. to the west of destination: (1,1) + (-1,0) = (0,1) or north from where you started
// 2. to the south of the destination: (1,1) + (0,-1) = (1,0) or east from where you started
// this function is used only by CombatSwingHandler.kt and assumes that we return the X tiles, west or east, FIRST
// and then the Y tiles South and North.
//
// idk what else to say, if youre reading this youre either crazy or crazy good at weird ass shit like this
// and dont even need letters to understand, theres just numbers and arrows and fking formulas or something in ur head (and a lot of work to do here)
if (stepX != 0) output.add(transform(-stepX, 0, 0)); // Ive never dealt with coordinate systems at this level, but it feels like Im in a cold, damp, deep and dark cave with fking goblins etc
if (stepY != 0) output.add(transform(0, -stepY, 0)); // and minotaurs
return output;
}