At 331 of 1500 health the bar read as nearly full. The pack's bar sprite is light all the way through, so the EMPTY part was the brightest thing on it. Every bar now has a dark track inside its frame, scaled with the bar's height -- a fixed inset left the thin experience bar four pixels of track and six of white -- so empty reads as empty. Health carries its number inside the bar, and a damage trail: the part the last hit took stays in a darker red for a moment and then drains, so a hit reads as an amount rather than as a bar that is suddenly shorter. Two quick hits read as one, measured from where the first began. The trail was pale at first and the number vanished against it; darker fixed that. Experience flashes and shows "+N xp" on a kill, summed across a burst so it does not flicker. Every block of HUD text sits on a dark panel, since the floor art is busy enough to beat a text shadow. Centre banners for the moments that change what you should do: a level gained, a boss changing phase (not the phase it was found in), and the escape channel -- which was a second bar in the corner and is now one bar where you are looking, with the key to keep holding. Party members you cannot see get a marker at the edge of sight pointing the way to them. Empty inventory slots step back, so the blank parchment square is no longer the most prominent thing in the row. The connect screen opens on a real boss pattern behind its panel -- the bosses' own emitters, fired into a pool and drawn by the game's own bullet renderer, dimmed. It is primed with five seconds of ticks: every pattern starts at the centre of the screen, which is where the panel is, so unprimed it showed nothing for its first second or two. The title is spaced and underlined, Credits is on the screen itself, Join says Enter works and has focus, the port is validated before it can fail, and "connecting" animates so a slow attempt does not look frozen. The boss-bar logic is pulled out into track_boss() so it can be tested: it waits for the fog to light the boss, stays for the fight, has to be seen again in the next dungeon -- every dungeon's boss is actor 1, so the id alone would have carried "seen" across -- and announces only real phase changes. screenshot.tscn captures the escape banner by progress rather than by frame count, because the channel is server ticks and a completed escape teleports the player out mid-sequence. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
3d1b5da72b
commit
6e872e2cf5
8 files changed
+703
-96
No files matched your search
+55
-26
@@ -24,29 +24,32 @@ const STORE := "user://screenshot_characters.json"
|
||||
const ACCOUNT := 777001
|
||||
## Frame numbers, not seconds: the point is a deterministic sequence, and a
|
||||
## windowed client at 60fps gets there in about four seconds.
|
||||
const AT_MENU := 30
|
||||
const ENTER_GAME := 34
|
||||
const AT_GAME := 200
|
||||
const OPEN_MENU := 210
|
||||
const AT_INGAME_MENU := 240
|
||||
const OPEN_SETTINGS := 250
|
||||
const AT_SETTINGS := 280
|
||||
const OPEN_CREDITS := 290
|
||||
const AT_CREDITS := 320
|
||||
const OPEN_UPGRADES := 330
|
||||
const AT_UPGRADES := 360
|
||||
const OPEN_ROSTER := 370
|
||||
const AT_ROSTER := 400
|
||||
const ENTER_DUNGEON := 410
|
||||
const AT_DUNGEON := 480
|
||||
const TO_TUNNEL := 490
|
||||
const AT_TUNNEL := 550
|
||||
const AT_TUNNEL_DEBUG := 560
|
||||
const TO_BOSS := 570
|
||||
const AT_BOSS := 640
|
||||
const DONE := 650
|
||||
const AT_MENU := 200
|
||||
const ENTER_GAME := 204
|
||||
const AT_GAME := 370
|
||||
const OPEN_MENU := 380
|
||||
const AT_INGAME_MENU := 410
|
||||
const OPEN_SETTINGS := 420
|
||||
const AT_SETTINGS := 450
|
||||
const OPEN_CREDITS := 460
|
||||
const AT_CREDITS := 490
|
||||
const OPEN_UPGRADES := 500
|
||||
const AT_UPGRADES := 530
|
||||
const OPEN_ROSTER := 540
|
||||
const AT_ROSTER := 570
|
||||
const ENTER_DUNGEON := 580
|
||||
const AT_DUNGEON := 650
|
||||
const TO_TUNNEL := 660
|
||||
const AT_TUNNEL := 720
|
||||
const AT_TUNNEL_DEBUG := 730
|
||||
const TO_BOSS := 740
|
||||
const AT_BOSS := 810
|
||||
const ESCAPE_START := 830
|
||||
## A safety net only: the run normally ends the moment the escape shot is taken.
|
||||
const DONE := 1710
|
||||
|
||||
var _frame: int = 0
|
||||
var _left_shot: bool = false
|
||||
var _game: Node = null
|
||||
var _menu: Control = null
|
||||
var _dir: String = "user://"
|
||||
@@ -98,10 +101,30 @@ func _process(_delta: float) -> void:
|
||||
# it every frame, so one assignment lasts exactly one frame.
|
||||
if _frame > OPEN_ROSTER and _frame <= AT_ROSTER:
|
||||
_show_the_roster()
|
||||
# Held low, so the low-health edge is in the picture -- and held at all,
|
||||
# because the boss is firing and one landed ring would end the shot.
|
||||
if _frame > TO_BOSS and _frame <= AT_BOSS:
|
||||
_hold_health(0.22)
|
||||
# Held, because the boss is firing and one landed ring would end the shot.
|
||||
# High until just before the picture and low after, so the damage trail
|
||||
# -- the part of the bar the drop took -- is still draining when it is taken.
|
||||
if _frame > TO_BOSS and not _left_shot:
|
||||
_hold_health(0.62 if _frame < AT_BOSS - 10 else 0.22)
|
||||
# Captured by progress rather than by frame count. The channel is one second
|
||||
# of server ticks and frames run as fast as the display allows, so a fixed
|
||||
# frame number lands anywhere from a quarter of the way in to after it has
|
||||
# completed -- and a completed escape teleports the player out mid-sequence.
|
||||
if _frame >= ESCAPE_START and not _left_shot:
|
||||
Net.client.request_escape = true
|
||||
if Net.client.my_escape >= 0.45:
|
||||
_grab("leaving")
|
||||
Net.client.request_escape = false
|
||||
_left_shot = true
|
||||
Net.shutdown()
|
||||
get_tree().quit(0)
|
||||
return
|
||||
if _frame == AT_BOSS - 30:
|
||||
Net.server._grant_xp(Net.LOCAL_PEER, 46)
|
||||
# Frames, not seconds, and this runs as fast as the display allows -- so
|
||||
# early enough that the banner's fade-in is over even at a high frame rate.
|
||||
if _frame == AT_BOSS - 60:
|
||||
_game.get_node("HUD").banner("LEVEL 7", "a choice waits at the quartermaster")
|
||||
match _frame:
|
||||
AT_MENU:
|
||||
_grab("menu")
|
||||
@@ -266,11 +289,17 @@ func _stage_a_boss_fight() -> void:
|
||||
friend.spawn_grace = 0
|
||||
Net.server.peer_names[999] = "Wren"
|
||||
Net.server.peer_instance[999] = inst.id
|
||||
# And one out of sight, so the marker pointing the way to them shows.
|
||||
var away := inst.world.add_player(998, "Lark")
|
||||
away.pos = at + Vector2(-560.0, 260.0)
|
||||
away.colour = Color(0.55, 0.85, 1.0)
|
||||
away.spawn_grace = 0
|
||||
Net.server.peer_names[998] = "Lark"
|
||||
Net.server.peer_instance[998] = inst.id
|
||||
Net.server._broadcast_roster()
|
||||
var hud := _game.get_node("HUD")
|
||||
hud.notify("+ Health Potion", Items.get_def(Items.HEALTH_POTION).tint)
|
||||
hud.notify("Warden's Ration used", Items.get_def(Items.WARDENS_RATION).tint)
|
||||
hud.notify("LEVEL 7 -- a choice waits at the quartermaster", Color(1.0, 0.85, 0.4))
|
||||
|
||||
|
||||
## Move the player, on both sides, into the tunnel closest to where it spawned:
|
||||
|
||||
Reference in new issue
Block a user