From 98ee32bdacd145aac54ba5ea06c350c53fc56e6b Mon Sep 17 00:00:00 2001 From: JessJess Date: Sat, 7 Mar 2026 12:00:00 +0000 Subject: [PATCH] add stepping stones for my client dug around the codebase a bit for this one and wired up the hop + sfx. --- src/controllers/movement-controller.ts | 13 ++++++- src/handlers/walk.ts | 26 +++++++------ src/map.ts | 53 +++++++++++++++++++------- src/utils/index.ts | 1 + src/utils/is-stepping-stone.ts | 18 +++++++++ 5 files changed, 84 insertions(+), 27 deletions(-) create mode 100644 src/utils/is-stepping-stone.ts diff --git a/src/controllers/movement-controller.ts b/src/controllers/movement-controller.ts index 6a754394..c5b1f551 100644 --- a/src/controllers/movement-controller.ts +++ b/src/controllers/movement-controller.ts @@ -21,7 +21,7 @@ import { Emote, } from '@/render'; import { playSfxById, SfxId } from '@/sfx'; -import { randomRange } from '@/utils'; +import { getPrevCoords, isSteppingStoneWalk, randomRange } from '@/utils'; import type { Vector2 } from '@/vector'; export class MovementController { @@ -52,6 +52,17 @@ export class MovementController { .map!.tileSpecRows.find((r) => r.y === coords.y) ?.tiles.find((t) => t.x === coords.x); + const from = getPrevCoords( + coords, + direction, + this.client.map.width, + this.client.map.height, + ); + + if (isSteppingStoneWalk(this.client.map, from, coords)) { + playSfxById(SfxId.JumpStone); + } + if (spec && spec.tileSpec === MapTileSpec.Water) { const metadata = this.client.getEffectMetadata(9); playSfxById(metadata.sfx); diff --git a/src/handlers/walk.ts b/src/handlers/walk.ts index 31d20e28..0c54fc30 100644 --- a/src/handlers/walk.ts +++ b/src/handlers/walk.ts @@ -13,8 +13,8 @@ import { EffectAnimation, EffectTargetCharacter, } from '@/render'; -import { playSfxById } from '@/sfx'; -import { getPrevCoords } from '@/utils'; +import { playSfxById, SfxId } from '@/sfx'; +import { getPrevCoords, isSteppingStoneWalk } from '@/utils'; function handleWalkPlayer(client: Client, reader: EoReader) { const packet = WalkPlayerServerPacket.deserialize(reader); @@ -26,24 +26,26 @@ function handleWalkPlayer(client: Client, reader: EoReader) { return; } + const from = getPrevCoords( + packet.coords, + packet.direction, + client.map.width, + client.map.height, + ); + client.animationController.pendingCharacterAnimations.set( packet.playerId, - new CharacterWalkAnimation( - getPrevCoords( - packet.coords, - packet.direction, - client.map.width, - client.map.height, - ), - packet.coords, - packet.direction, - ), + new CharacterWalkAnimation(from, packet.coords, packet.direction), ); if (character.invisible && client.admin === AdminLevel.Player) { return; } + if (isSteppingStoneWalk(client.map, from, packet.coords)) { + playSfxById(SfxId.JumpStone); + } + const spec = client! .map!.tileSpecRows.find((r) => r.y === packet.coords.y) ?.tiles.find((t) => t.x === packet.coords.x); diff --git a/src/map.ts b/src/map.ts index 84960884..9a18354b 100644 --- a/src/map.ts +++ b/src/map.ts @@ -165,6 +165,8 @@ const WALK_OFFSETS = [ [Direction.Left]: { x: -WALK_WIDTH_FACTOR * 4, y: -WALK_HEIGHT_FACTOR * 4 }, }, ]; +// Wasn't sure where best to place this yet, so it's beside WALK_OFFSETS for now. +const STEPPING_STONE_Y_OFFSETS = [-8, -16, -16, -8]; export class MapRenderer { client: Client; @@ -470,6 +472,35 @@ export class MapRenderer { }; } + private getCharacterWalkState( + animation: CharacterWalkAnimation, + dying: boolean, + ): { frame: number; offset: Vector2 } { + const steppingStone = + this.getTileSpec(animation.from.x, animation.from.y) === + MapTileSpec.Jump || + this.getTileSpec(animation.to.x, animation.to.y) === MapTileSpec.Jump; + const offset = dying + ? WALK_OFFSETS[animation.animationFrame][animation.direction] + : this.interpolateWalkOffset( + animation.animationFrame, + animation.direction, + ); + + return { + frame: + steppingStone && animation.animationFrame > 0 + ? 0 + : animation.animationFrame, + offset: steppingStone + ? { + x: offset.x, + y: offset.y + STEPPING_STONE_Y_OFFSETS[animation.animationFrame], + } + : offset, + }; + } + update(interpolation: number) { if (!this.client.map || this.buildingCache) { return; @@ -954,16 +985,12 @@ export class MapRenderer { let coords: Vector2 = character.coords; switch (true) { case animation instanceof CharacterWalkAnimation: { - walkOffset = dying - ? WALK_OFFSETS[animation.animationFrame][animation.direction] - : this.interpolateWalkOffset( - animation.animationFrame, - animation.direction, - ); + const walkState = this.getCharacterWalkState(animation, dying); + walkOffset = walkState.offset; coords = animation.from; characterFrame = downRight - ? CharacterFrame.WalkingDownRight1 + animation.animationFrame - : CharacterFrame.WalkingUpLeft1 + animation.animationFrame; + ? CharacterFrame.WalkingDownRight1 + walkState.frame + : CharacterFrame.WalkingUpLeft1 + walkState.frame; break; } case animation instanceof CharacterAttackAnimation: @@ -1760,12 +1787,10 @@ export class MapRenderer { } if (animation instanceof CharacterWalkAnimation) { - const walkOffset = dying - ? WALK_OFFSETS[animation.animationFrame][animation.direction] - : this.interpolateWalkOffset( - animation.animationFrame, - animation.direction, - ); + const walkOffset = this.getCharacterWalkState( + animation, + dying, + ).offset; offset.x += walkOffset.x; offset.y += walkOffset.y; coords.x = animation.from.x; diff --git a/src/utils/index.ts b/src/utils/index.ts index 82ecd91c..04d97faf 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -16,6 +16,7 @@ export { getPrevCoords } from './get-prev-coords'; export { getShieldMetaData, ShieldMetadata } from './get-shield-metadata'; export { getVolumeFromDistance } from './get-volume-from-distance'; export { getWeaponMetaData, WeaponMetadata } from './get-weapon-metadata'; +export { isSteppingStoneWalk } from './is-stepping-stone'; export { isoToScreen } from './iso-to-screen'; export { makeDrunk } from './make-drunk'; export { padWithZeros } from './pad-with-zeros'; diff --git a/src/utils/is-stepping-stone.ts b/src/utils/is-stepping-stone.ts new file mode 100644 index 00000000..e8d8d93e --- /dev/null +++ b/src/utils/is-stepping-stone.ts @@ -0,0 +1,18 @@ +import { type Emf, MapTileSpec } from 'eolib'; +import type { Vector2 } from '@/vector'; + +function getTileSpec(map: Emf, coords: Vector2): MapTileSpec | null { + const row = map.tileSpecRows.find((r) => r.y === coords.y); + return row?.tiles.find((t) => t.x === coords.x)?.tileSpec ?? null; +} + +export function isSteppingStoneWalk( + map: Emf, + from: Vector2, + to: Vector2, +): boolean { + return ( + getTileSpec(map, from) === MapTileSpec.Jump || + getTileSpec(map, to) === MapTileSpec.Jump + ); +}