From e00492214438711c3af7fcad75505539d41e2285 Mon Sep 17 00:00:00 2001 From: metamuffin Date: Tue, 24 Sep 2024 00:38:16 +0200 Subject: pinned orders --- test-client/main.ts | 27 +++++++++++++++++------- test-client/protocol.ts | 5 +++-- test-client/visual.ts | 55 +++++++++++++++++++++++++++++++------------------ 3 files changed, 57 insertions(+), 30 deletions(-) (limited to 'test-client') diff --git a/test-client/main.ts b/test-client/main.ts index a3bf0105..5d3a6d11 100644 --- a/test-client/main.ts +++ b/test-client/main.ts @@ -88,6 +88,7 @@ export interface PlayerData extends MovementBase { character: number, anim_position: V2, message_persist?: MessageData, + message_pinned?: MessageData, message?: MessageData, } @@ -97,8 +98,9 @@ export interface TileData { kind: TileIndex item?: ItemData } +export type MessageStyle = "hint" | "normal" | "error" | "pinned" export interface MessageData { - style: "hint" | "normal" | "error" + style: MessageStyle inner: Message anim_position: V2, anim_size: number, @@ -120,7 +122,7 @@ export let camera_scale = 0.05; export const interact_target_anim: V2 = { x: 0, y: 0 } export let interact_possible_anim: number = 0 export let interact_active_anim: number = 0 -export let nametag_scale_anim: number = 0 +export let overlay_vis_anim: number = 0 export let is_lobby = false let interacting: V2 | undefined; let last_server_sent_position: V2 = { x: 0, y: 0 } @@ -226,11 +228,18 @@ function packet(p: PacketC) { inner: p.message, anim_size: 0., anim_position: player.anim_position, - timeout: p.timeout ?? { initial: 5, remaining: 5 }, + timeout: p.timeout ?? { initial: 5, remaining: 5, pinned: false }, style: "normal" as const }; if (p.timeout === undefined) player.message = message else player.message_persist = message + if (p.timeout?.pinned) player.message_pinned = { + inner: p.message, + anim_size: 0, + anim_position: { x: 20, y: 0 }, + style: "pinned", + timeout: p.timeout + } } else if (p.timeout !== undefined) { delete player.message_persist } @@ -248,7 +257,7 @@ function packet(p: PacketC) { style: p.error ? "error" : "normal", anim_size: 0., anim_position: { x: 0, y: 0 }, - timeout: { initial: 5, remaining: 5 } + timeout: { initial: 5, remaining: 5, pinned: false } } break; case "set_ingame": @@ -286,7 +295,7 @@ function packet(p: PacketC) { case "book": open("https://s.metamuffin.org/static/hurrycurry/book.pdf"); break case "score": global_message = { - timeout: { initial: 5, remaining: 5 }, + timeout: { initial: 5, remaining: 5, pinned: false }, inner: { text: `Score: ${JSON.stringify(p.data, null, 4)}` }, anim_position: { x: 0, y: 0 }, anim_size: 0, @@ -391,16 +400,18 @@ function frame_update(dt: number) { if (item.active) item.active.position += item.active.speed * dt } + let pin_xo = 0 for (const [pid, player] of players) { if (pid == my_id) player.anim_position.x = player.position.x, player.anim_position.y = player.position.y else lerp_exp_v2_mut(player.anim_position, player.position, dt * 15) if (player.item !== undefined && player.item !== null) update_item(player.item) if (player.message && tick_message(player.message, dt)) delete player.message if (player.message_persist && tick_message(player.message_persist, dt)) delete player.message_persist + if (player.message_pinned && tick_message(player.message_pinned, dt)) delete player.message_pinned + if (player.message_pinned) lerp_exp_v2_mut(player.message_pinned.anim_position, { x: pin_xo++, y: 0 }, dt * 5) } - for (const [_, tile] of tiles) { + for (const [_, tile] of tiles) if (tile.item !== undefined && tile.item !== null) update_item(tile.item) - } const remove: ItemData[] = [] for (const item of items_removed) { @@ -426,7 +437,7 @@ function frame_update(dt: number) { const zoom_target = Math.min(canvas.width, canvas.height) * (keys_down.has("KeyL") ? 0.05 : 0.1) camera_scale = lerp_exp(camera_scale, zoom_target, dt * 5) - nametag_scale_anim = lerp_exp(nametag_scale_anim, +keys_down.has("KeyL"), dt * 10) + overlay_vis_anim = lerp_exp(overlay_vis_anim, +keys_down.has("KeyL"), dt * 10) tick_particles(dt) } diff --git a/test-client/protocol.ts b/test-client/protocol.ts index c8c59ed2..64d740c3 100644 --- a/test-client/protocol.ts +++ b/test-client/protocol.ts @@ -40,7 +40,7 @@ export type PacketS = | { type: "leave", player: PlayerID } // Despawns a character | { type: "movement", player: PlayerID, pos: Vec2, dir: Vec2, boost: boolean } | { type: "interact", player: PlayerID, pos?: Vec2 } // Interact with some tile. pos is a position when pressing and null when releasing interact button - | { type: "communicate", player: PlayerID, message?: Message, timeout?: number } // Sends a message + | { type: "communicate", player: PlayerID, message?: Message, timeout?: number, pin?: boolean } // Sends a message | { type: "effect", player: PlayerID, name: string } // Sends an effect | { type: "replay_tick", dt: number } // Steps forward in replay. @@ -73,7 +73,8 @@ export type Menu = export interface MessageTimeout { initial: number, - remaining: number + remaining: number, + pinned: boolean, } export interface Score { diff --git a/test-client/visual.ts b/test-client/visual.ts index 9a267da0..784a36a3 100644 --- a/test-client/visual.ts +++ b/test-client/visual.ts @@ -16,7 +16,7 @@ */ import { tr } from "./locale.ts"; -import { ItemData, MessageData, PlayerData, TileData, camera, camera_scale, canvas, ctx, data, get_interact_target, global_message, interact_active_anim, interact_possible_anim, interact_target_anim, is_lobby, items_removed, keys_down, my_id, nametag_scale_anim, players, score, server_hints, tiles } from "./main.ts"; +import { ItemData, MessageData, MessageStyle, PlayerData, TileData, camera, camera_scale, canvas, ctx, data, get_interact_target, global_message, interact_active_anim, interact_possible_anim, interact_target_anim, is_lobby, items_removed, keys_down, my_id, overlay_vis_anim, players, score, server_hints, tiles } from "./main.ts"; import { PLAYER_SIZE } from "./movement.ts"; import { draw_item_sprite, draw_tile_sprite, ItemName, TileName } from "./tiles.ts"; import { V2, ceil_v2, floor_v2 } from "./util.ts"; @@ -67,16 +67,24 @@ export function draw_ingame() { draw_interact_target() for (const [_, player] of players) - if (player.message) draw_message(player.message) + if (player.message) draw_message(player.message, true) for (const [_, player] of players) - if (player.message_persist) draw_message(player.message_persist) + if (player.message_persist) draw_message(player.message_persist, true) for (const [_, player] of players) draw_player_nametag(player) for (const [_, message] of server_hints) - draw_message(message) + draw_message(message, true) + + ctx.restore() + ctx.save() + ctx.translate(50, 50) + ctx.scale(80, 80) + + for (const [_, player] of players) + if (player.message_pinned) draw_message(player.message_pinned, false) ctx.restore() @@ -143,13 +151,13 @@ function draw_player(player: PlayerData) { } function draw_player_nametag(player: PlayerData) { - if (nametag_scale_anim > 0.01) { + if (overlay_vis_anim > 0.01) { ctx.save() ctx.translate(player.anim_position.x, player.anim_position.y) ctx.translate(0, -1) ctx.textAlign = "center" ctx.font = "15px sans-serif" - ctx.scale(nametag_scale_anim / camera_scale, nametag_scale_anim / camera_scale) + ctx.scale(overlay_vis_anim / camera_scale, overlay_vis_anim / camera_scale) const w = ctx.measureText(player.name).width + 20 ctx.fillStyle = "#fffa" ctx.beginPath() @@ -221,20 +229,27 @@ function message_str(m: Message): string { return "[unknown message type]" } -const MESSAGE_BG = { "normal": "#fff", "hint": "#111", "error": "#fff" } -const MESSAGE_FG = { "normal": "#000", "hint": "#fff", "error": "#a00" } -function draw_message(m: MessageData, server?: boolean) { +const MESSAGE_BG: { [key in MessageStyle]: string } = { normal: "#fff", hint: "#111", error: "#fff", pinned: "rgb(4, 32, 0)" } +const MESSAGE_FG: { [key in MessageStyle]: string } = { normal: "#000", hint: "#fff", error: "#a00", pinned: "#000" } +function draw_message(m: MessageData, world: boolean) { ctx.save() ctx.translate(m.anim_position.x, m.anim_position.y) - const scale = Math.min(m.anim_size, 1 - nametag_scale_anim); + const scale = Math.min(m.anim_size, 1 - overlay_vis_anim); ctx.scale(scale, scale) if ("item" in m.inner) { - ctx.fillStyle = "#fffa" - ctx.beginPath() - ctx.moveTo(0, -0.3) - ctx.arc(0, -1, 0.5, Math.PI / 4, Math.PI - Math.PI / 4, true) - ctx.closePath() - ctx.fill() + ctx.fillStyle = MESSAGE_BG[m.style] + if (m.style == "pinned") { + ctx.translate(0, 1) + ctx.beginPath() + ctx.arc(0, -1, 0.5, 0, Math.PI * 2) + ctx.fill() + } else { + ctx.beginPath() + ctx.moveTo(0, -0.3) + ctx.arc(0, -1, 0.5, Math.PI / 4, Math.PI - Math.PI / 4, true) + ctx.closePath() + ctx.fill() + } if (m.timeout) { const t = m.timeout.remaining / m.timeout.initial; @@ -253,13 +268,13 @@ function draw_message(m: MessageData, server?: boolean) { ctx.translate(0, -1) ctx.textAlign = "center" - ctx.font = "15px " + (server ? "monospace" : "sans-serif") - if (!server) ctx.scale(2 / camera_scale, 2 / camera_scale) + ctx.font = "15px " + (world ? "sans-serif" : "monospace") + if (world) ctx.scale(2 / camera_scale, 2 / camera_scale) const lines = message_str(m.inner).split("\n") const w = lines.reduce((a, v) => Math.max(a, ctx.measureText(v).width), 0) + 10 - if (!server) ctx.translate(0, -lines.length * 15 / 2) + if (world) ctx.translate(0, -lines.length * 15 / 2) ctx.fillStyle = MESSAGE_BG[m.style] ctx.beginPath() @@ -282,7 +297,7 @@ function draw_global_message() { ctx.save() ctx.translate(canvas.width / 2, canvas.height / 6) ctx.scale(2, 2) - draw_message(global_message, true) + draw_message(global_message, false) ctx.restore() } -- cgit v1.2.3-70-g09d2