Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve naming 4 - WalkTo, turn, hits and misc #599

Merged
merged 22 commits into from
Jan 23, 2025
Merged
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 @@ -2,8 +2,6 @@ package world.gregs.voidps.engine.client.instruction.handle

import world.gregs.voidps.engine.client.instruction.InstructionHandler
import world.gregs.voidps.engine.client.ui.closeInterfaces
import world.gregs.voidps.engine.entity.character.clearWatch
import world.gregs.voidps.engine.entity.character.move.walkTo
import world.gregs.voidps.engine.entity.character.player.Player
import world.gregs.voidps.network.client.instruction.Walk

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ class NPCUpdateTask(
sync.writeBits(1, teleporting)
sync.writeBits(5, delta.y + if (delta.y < 15) 32 else 0)
sync.writeBits(5, delta.x + if (delta.x < 15) 32 else 0)
sync.writeBits(3, (visuals.turn.direction shr 11) - 4)
sync.writeBits(3, (visuals.face.direction shr 11) - 4)
sync.writeBits(1, flag != 0)
sync.writeBits(14, npc.def.id)
encodeVisuals(updates, flag, visuals, client.index)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,9 @@ class AccountManager(

fun setup(player: Player): Boolean {
player.index = players.index() ?: return false
player.visuals = PlayerVisuals(player.index, player.body)
player.visuals.hits.self = player.index
player.interfaces = Interfaces(player, player.client, interfaceDefinitions)
player.interfaceOptions = InterfaceOptions(player, interfaceDefinitions, inventoryDefinitions)
player.options = PlayerOptions(player)
(player.variables as PlayerVariables).definitions = variableDefinitions
player.inventories.definitions = inventoryDefinitions
player.inventories.itemDefinitions = itemDefinitions
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package world.gregs.voidps.engine.entity

import world.gregs.voidps.engine.entity.character.Character
import world.gregs.voidps.engine.entity.character.size
import world.gregs.voidps.engine.entity.obj.GameObject
import world.gregs.voidps.type.Tile

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,29 @@ import world.gregs.voidps.engine.data.definition.AnimationDefinitions
import world.gregs.voidps.engine.data.definition.GraphicDefinitions
import world.gregs.voidps.engine.entity.Entity
import world.gregs.voidps.engine.entity.character.mode.Mode
import world.gregs.voidps.engine.entity.character.mode.move.Movement
import world.gregs.voidps.engine.entity.character.mode.move.Steps
import world.gregs.voidps.engine.entity.character.mode.move.target.TileTargetStrategy
import world.gregs.voidps.engine.entity.character.move.tele
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.appearance
import world.gregs.voidps.engine.entity.character.player.movementType
import world.gregs.voidps.engine.entity.character.player.skill.level.Levels
import world.gregs.voidps.engine.entity.obj.GameObject
import world.gregs.voidps.engine.entity.obj.ObjectShape
import world.gregs.voidps.engine.event.EventDispatcher
import world.gregs.voidps.engine.get
import world.gregs.voidps.engine.queue.ActionQueue
import world.gregs.voidps.engine.suspend.Suspension
import world.gregs.voidps.engine.timer.Timers
import world.gregs.voidps.network.login.protocol.visual.VisualMask
import world.gregs.voidps.network.login.protocol.visual.Visuals
import world.gregs.voidps.network.login.protocol.visual.update.Face
import world.gregs.voidps.network.login.protocol.visual.update.player.MoveType
import world.gregs.voidps.type.Delta
import world.gregs.voidps.type.Direction
import world.gregs.voidps.type.Distance
import world.gregs.voidps.type.Tile
import kotlin.coroutines.Continuation

Expand All @@ -39,6 +45,7 @@ interface Character : Entity, Variable, EventDispatcher, Comparable<Character> {
var delay: Continuation<Unit>?
override var variables: Variables
val steps: Steps
val size: Int

override fun compareTo(other: Character): Int {
return index.compareTo(other.index)
Expand Down Expand Up @@ -111,7 +118,6 @@ interface Character : Entity, Variable, EventDispatcher, Comparable<Character> {
flagSecondaryGraphic()
}


/**
* Temporarily perform animation [id] (aka sequence)
* with optional [delay] and [override]ing of the previous animation
Expand Down Expand Up @@ -154,11 +160,118 @@ interface Character : Entity, Variable, EventDispatcher, Comparable<Character> {
visuals.animation.reset()
flagAnimation()
}
}

val Entity.size: Int
get() = when (this) {
is NPC -> def.size
is Player -> appearance.size
else -> 1
}
/**
* Walks player to [target]
* Specify [noCollision] to walk through [GameObject]s and
* [forceWalk] to force walking even if the player has running active
*/
fun walkTo(target: Tile, noCollision: Boolean = false, forceWalk: Boolean = false) {
if (tile == target) {
return
}
mode = Movement(this, TileTargetStrategy(target, noCollision, forceWalk))
}

/**
* The direction the character is currently facing
*/
val direction: Direction
get() = Direction.of(visuals.face.targetX - tile.x, visuals.face.targetY - tile.y)

/**
* Turn to face a [direction]
*/
fun face(direction: Direction, update: Boolean = true) = face(direction.delta, update)

/**
* Turn to face a [tile]
*/
fun face(tile: Tile, update: Boolean = true) = face(tile.delta(this.tile), update)


/**
* Turn to face [delta]
*/
fun face(delta: Delta, update: Boolean = true): Boolean {
if (delta == Delta.EMPTY) {
clearFace()
return false
}
val turn = visuals.face
turn.targetX = tile.x + delta.x
turn.targetY = tile.y + delta.y
turn.direction = Face.getFaceDirection(delta.x, delta.y)
if (update) {
flagTurn()
}
return true
}

/**
* Turn to face [entity]
*/
fun face(entity: Entity, update: Boolean = true) {
val tile = nearestTile(entity)
if (!face(tile, update) && entity is GameObject) {
when {
ObjectShape.isWall(entity.shape) -> face(Direction.cardinal[(entity.rotation + 3) and 0x3], update)
ObjectShape.isCorner(entity.shape) -> face(Direction.ordinal[entity.rotation], update)
else -> {
val delta = tile.add(entity.width, entity.height).delta(entity.tile.add(entity.width, entity.height))
face(delta, update)
}
}
}
}

/**
* Reset character face direction
*/
fun clearFace(): Boolean {
visuals.face.reset()
return true
}

private fun nearestTile(entity: Entity): Tile {
return when (entity) {
is GameObject -> Distance.getNearest(entity.tile, entity.width, entity.height, this.tile)
is NPC -> Distance.getNearest(entity.tile, entity.def.size, entity.def.size, this.tile)
is Player -> Distance.getNearest(entity.tile, entity.appearance.size, entity.appearance.size, this.tile)
else -> entity.tile
}
}

/**
* Track facing a [character] until otherwise specified
*/
fun watch(character: Character) {
if (character is Player) {
visuals.watch.index = character.index or 0x8000
} else {
visuals.watch.index = character.index
}
visuals.face.clear()
flagWatch()
}

/**
* Check if character is currently watching [character]
*/
fun watching(character: Character): Boolean {
return if (character is Player) {
visuals.watch.index == character.index or 0x8000
} else {
visuals.watch.index == character.index
}
}

/**
* Stop watching the targeted entity
*/
fun clearWatch() {
visuals.watch.index = -1
flagWatch()
}

}
Original file line number Diff line number Diff line change
@@ -1,20 +1,7 @@
package world.gregs.voidps.engine.entity.character

import world.gregs.voidps.engine.entity.Entity
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.appearance
import world.gregs.voidps.engine.entity.character.player.skill.Skill
import world.gregs.voidps.engine.entity.obj.GameObject
import world.gregs.voidps.engine.entity.obj.ObjectShape
import world.gregs.voidps.engine.suspend.SuspendableContext
import world.gregs.voidps.network.login.protocol.visual.VisualMask
import world.gregs.voidps.network.login.protocol.visual.update.Hitsplat
import world.gregs.voidps.network.login.protocol.visual.update.Turn
import world.gregs.voidps.type.Delta
import world.gregs.voidps.type.Direction
import world.gregs.voidps.type.Distance
import world.gregs.voidps.type.Tile

fun Character.flagAnimation() = visuals.flag(if (this is Player) VisualMask.PLAYER_ANIMATION_MASK else VisualMask.NPC_ANIMATION_MASK)

Expand All @@ -26,12 +13,16 @@ fun Character.flagHits() = visuals.flag(if (this is Player) VisualMask.PLAYER_HI

fun Character.flagExactMovement() = visuals.flag(if (this is Player) VisualMask.PLAYER_EXACT_MOVEMENT_MASK else VisualMask.NPC_EXACT_MOVEMENT_MASK)

fun Character.flagTurn() = visuals.flag(if (this is Player) VisualMask.PLAYER_TURN_MASK else VisualMask.NPC_TURN_MASK)
fun Character.flagTurn() = visuals.flag(if (this is Player) VisualMask.PLAYER_FACE_MASK else VisualMask.NPC_FACE_MASK)

fun Character.flagTimeBar() = visuals.flag(if (this is Player) VisualMask.PLAYER_TIME_BAR_MASK else VisualMask.NPC_TIME_BAR_MASK)

fun Character.flagWatch() = visuals.flag(if (this is Player) VisualMask.PLAYER_WATCH_MASK else VisualMask.NPC_WATCH_MASK)

fun Character.flagPrimaryGraphic() = visuals.flag(if (this is Player) VisualMask.PLAYER_GRAPHIC_1_MASK else VisualMask.NPC_GRAPHIC_1_MASK)

fun Character.flagSecondaryGraphic() = visuals.flag(if (this is Player) VisualMask.PLAYER_GRAPHIC_2_MASK else VisualMask.NPC_GRAPHIC_2_MASK)

fun Character.colourOverlay(colour: Int, delay: Int, duration: Int) {
val overlay = visuals.colourOverlay
overlay.colour = colour
Expand All @@ -41,101 +32,11 @@ fun Character.colourOverlay(colour: Int, delay: Int, duration: Int) {
softTimers.start("colour_overlay")
}

private fun primaryGfxFlagged(character: Character) = character.visuals.flagged(if (character is Player) VisualMask.PLAYER_GRAPHIC_1_MASK else VisualMask.NPC_GRAPHIC_1_MASK)

fun Character.flagPrimaryGraphic() = visuals.flag(if (this is Player) VisualMask.PLAYER_GRAPHIC_1_MASK else VisualMask.NPC_GRAPHIC_1_MASK)

fun Character.flagSecondaryGraphic() = visuals.flag(if (this is Player) VisualMask.PLAYER_GRAPHIC_2_MASK else VisualMask.NPC_GRAPHIC_2_MASK)


fun Character.hit(source: Character, amount: Int, mark: Hitsplat.Mark, delay: Int = 0, critical: Boolean = false, soak: Int = -1) {
val after = (levels.get(Skill.Constitution) - amount).coerceAtLeast(0)
val percentage = levels.getPercent(Skill.Constitution, after, 255.0).toInt()
visuals.hits.hits.add(Hitsplat(amount, mark, percentage, delay, critical, if (source is NPC) -source.index else source.index, soak))
flagHits()
}

fun Character.setTimeBar(full: Boolean = false, exponentialDelay: Int = 0, delay: Int = 0, increment: Int = 0) {
val bar = visuals.timeBar
bar.full = full
bar.exponentialDelay = exponentialDelay
bar.delay = delay
bar.increment = increment
flagTimeBar()
}

fun Character.watch(character: Character) {
visuals.watch.index = watchIndex(character)
visuals.turn.clear()
flagWatch()
}

fun Character.watching(character: Character) = visuals.watch.index == watchIndex(character)

fun Character.clearWatch() {
visuals.watch.index = -1
flagWatch()
}

private fun watchIndex(character: Character) = if (character is Player) character.index or 0x8000 else character.index

val Character.turn: Delta
get() = Tile(visuals.turn.targetX, visuals.turn.targetY, tile.level).delta(tile)

fun Character.turn(delta: Delta, update: Boolean = true): Boolean {
if (delta == Delta.EMPTY) {
clearTurn()
return false
}
turn(delta.x, delta.y, update)
return true
}

fun Character.clearTurn(): Boolean {
visuals.turn.reset()
return true
}

fun Character.turn(deltaX: Int = 0, deltaY: Int = -1, update: Boolean = true) {
val turn = visuals.turn
turn.targetX = tile.x + deltaX
turn.targetY = tile.y + deltaY
turn.direction = Turn.getFaceDirection(deltaX, deltaY)
if (update) {
flagTurn()
}
}

val Character.facing: Direction
get() = turn.toDirection()

fun Character.face(direction: Direction, update: Boolean = true) = turn(direction.delta.x, direction.delta.y, update)

fun Character.face(tile: Tile, update: Boolean = true) = turn(tile.delta(this.tile), update)

fun Character.facing(tile: Tile) = turn == tile.delta(this.tile)

fun Character.face(entity: Entity, update: Boolean = true) {
val tile = nearestTile(entity)
if (!face(tile, update) && entity is GameObject) {
when {
ObjectShape.isWall(entity.shape) -> face(Direction.cardinal[(entity.rotation + 3) and 0x3], update)
ObjectShape.isCorner(entity.shape) -> face(Direction.ordinal[entity.rotation], update)
else -> {
val delta = tile.add(entity.width, entity.height).delta(entity.tile.add(entity.width, entity.height))
turn(delta, update)
}
}
}
}

fun Character.facing(entity: Entity) = turn == nearestTile(entity).delta(tile)

fun Character.nearestTile(entity: Entity): Tile {
return when (entity) {
is GameObject -> Distance.getNearest(entity.tile, entity.width, entity.height, this.tile)
is NPC -> Distance.getNearest(entity.tile, entity.def.size, entity.def.size, this.tile)
is Player -> Distance.getNearest(entity.tile, entity.appearance.size, entity.appearance.size, this.tile)
else -> entity.tile
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package world.gregs.voidps.engine.entity.character.mode

import world.gregs.voidps.engine.entity.character.Character
import world.gregs.voidps.engine.entity.character.clearWatch
import world.gregs.voidps.engine.entity.character.watch
import world.gregs.voidps.engine.entity.distanceTo

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
package world.gregs.voidps.engine.entity.character.mode

import world.gregs.voidps.engine.entity.character.Character
import world.gregs.voidps.engine.entity.character.clearWatch
import world.gregs.voidps.engine.entity.character.mode.move.Movement
import world.gregs.voidps.engine.entity.character.mode.move.target.FollowTargetStrategy
import world.gregs.voidps.engine.entity.character.mode.move.target.TargetStrategy
import world.gregs.voidps.engine.entity.character.move.tele
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.watch
import world.gregs.voidps.engine.entity.character.watching
import world.gregs.voidps.engine.entity.distanceTo
import world.gregs.voidps.type.Tile

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import world.gregs.voidps.engine.entity.Entity
import world.gregs.voidps.engine.entity.character.Character
import world.gregs.voidps.engine.entity.character.mode.move.Movement
import world.gregs.voidps.engine.entity.character.npc.NPC
import world.gregs.voidps.engine.entity.character.watch
import world.gregs.voidps.engine.entity.distanceTo
import world.gregs.voidps.type.Direction
import world.gregs.voidps.type.Tile
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,9 @@ import world.gregs.voidps.engine.entity.character.mode.interact.Interact
import world.gregs.voidps.engine.entity.character.mode.move.Movement
import world.gregs.voidps.engine.entity.character.mode.move.target.CharacterTargetStrategy
import world.gregs.voidps.engine.entity.character.mode.move.target.TargetStrategy
import world.gregs.voidps.engine.entity.character.move.walkTo
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.size
import world.gregs.voidps.engine.entity.character.watch
import world.gregs.voidps.engine.entity.item.Item
import world.gregs.voidps.engine.map.Overlap
import world.gregs.voidps.type.Direction
Expand Down
Loading
Loading