Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,7 @@ import world.gregs.voidps.engine.entity.character.player.chat.cantReach
import world.gregs.voidps.engine.entity.item.Item
import world.gregs.voidps.engine.get
import world.gregs.voidps.engine.map.Overlap
import world.gregs.voidps.type.Direction
import world.gregs.voidps.type.Tile
import world.gregs.voidps.type.random
import kotlin.math.abs

/**
Expand Down Expand Up @@ -60,7 +58,6 @@ class CombatMovement(
if (!attack()) {
var skip: Boolean
if (Overlap.isUnder(character.tile, character.size, target.tile, target.size)) {
stepOut()
skip = true
} else {
val wasEmpty = character.steps.isEmpty()
Expand All @@ -81,17 +78,8 @@ class CombatMovement(
}
}

private fun stepOut() {
clearSteps()
if (target.mode is CombatMovement || target.mode is Interact) {
return
}
val direction = Direction.cardinal.random(random)
if (!canStep(direction.delta.x, direction.delta.y)) {
return
}
character.steps.queueStep(strategy.tile.add(direction))
}
override fun shouldQueueStepOut(): Boolean =
target.mode !is CombatMovement && target.mode !is Interact

private fun attack(): Boolean {
val attackRange = attackRange()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,14 @@ import world.gregs.voidps.engine.entity.character.Character
import world.gregs.voidps.engine.entity.character.mode.EmptyMode
import world.gregs.voidps.engine.entity.character.mode.move.Movement
import world.gregs.voidps.engine.entity.character.mode.move.target.TargetStrategy
import world.gregs.voidps.engine.entity.character.npc.NPC
import world.gregs.voidps.engine.entity.character.player.Player
import world.gregs.voidps.engine.entity.character.player.chat.cantReach
import world.gregs.voidps.engine.entity.character.player.chat.noInterest
import world.gregs.voidps.engine.map.Overlap
import world.gregs.voidps.engine.suspend.resumeSuspension
import world.gregs.voidps.type.Direction
import world.gregs.voidps.type.random

/**
* Moves a player within interact distance of [target]
Expand Down Expand Up @@ -86,6 +90,18 @@ open class Interact(
return
}
updateRange = false
val target = target
val npc = character as? NPC
if (npc != null && !npc.def["allowed_under", false] && target is Character &&
Overlap.isUnder(npc.tile, npc.size, target.tile, target.size)) {
clearSteps()
val direction = Direction.cardinal.random(random)
if (canStep(direction.delta.x, direction.delta.y)) {
character.steps.queueStep(npc.tile.add(direction))
}
super.tick()
return
}
calculate()
val interacted = processInteraction()
if (interacted && interactionFinished()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import world.gregs.voidps.type.Delta
import world.gregs.voidps.type.Direction
import world.gregs.voidps.type.Tile
import world.gregs.voidps.type.equals
import world.gregs.voidps.type.random
import kotlin.math.sign

open class Movement(
Expand Down Expand Up @@ -53,6 +54,30 @@ open class Movement(
needsCalculation = false
}

/**
* Clears steps and queues a random cardinal step when an NPC overlaps its character target and isn't permitted to stand there.
*/
protected open fun stepOut(): Boolean {
val strategy = strategy ?: return false
if (strategy.shape != -2) return false
val npc = character as? NPC ?: return false
if (npc.def["allowed_under", false]) return false
if (!Overlap.isUnder(npc.tile, npc.size, npc.size, strategy.tile, strategy.width, strategy.height)) return false
clearSteps()
if (shouldQueueStepOut()) {
val direction = Direction.cardinal.random(random)
if (canStep(direction.delta.x, direction.delta.y)) {
character.steps.queueStep(npc.tile.add(direction))
}
}
return true
}

/**
* Whether [stepOut] should queue a random step after clearing, or let normal recalculation handle repositioning.
*/
protected open fun shouldQueueStepOut(): Boolean = true

override fun tick() {
val character = character
if (character is Player && character.viewport?.loaded == false) {
Expand All @@ -61,7 +86,9 @@ open class Movement(
if (hasDelay() && !canMove() && !character.steps.destination.noCollision) {
return
}
calculate()
if (!stepOut()) {
calculate()
}
if (step(runStep = false) && character.running) {
if (character.steps.isNotEmpty()) {
step(runStep = true)
Expand Down
10 changes: 10 additions & 0 deletions game/src/test/kotlin/content/entity/combat/CombatMovementTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,16 @@ internal class CombatMovementTest : WorldTest() {
assertTrue(npc.mode is CombatMovement)
}

@Test
fun `Npc spawned under player steps out to attack`() {
val player = createPlayer(emptyTile)
val npc = createNPC("guard_falador", emptyTile)
npc.interactPlayer(player, "Attack")
tick(2)
assertTrue(npc.tile != emptyTile)
assertTrue(npc.mode is CombatMovement)
}

companion object {
private const val MAX_EXP = 14000000.0
}
Expand Down