Health survives a run now, so a character sitting on the select screen can be nearly dead -- and the screen was still printing only the ceiling. "level 11, 2000 hp" for a character on 160 is a lie told at the exact moment it matters most, because the next thing that happens is the player walks it into a dungeon under permadeath. The roster message carries current hit points alongside the maximum, and the screen shows a fraction only when it means something: a healthy character still reads "1300 hp" rather than "1300/1300". The field is inserted mid-record, which shifts every field after it, so the protocol version goes to 10 -- a mismatched client would read the active flag out of the middle of a health value. tools/screenshot.gd had no capture for this screen, which is how a UI change to it could have shipped unlooked-at. It now shows a made-up roster of three characters -- whole, badly hurt, nearly dead -- for the same reason the upgrade screen is fed a made-up offer: the point is the layout, not a dungeon run. Getting there needs the player walked off the quartermaster first, or the game scene re-opens the upgrade screen over the top of it every frame. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
4aeb6d229d
commit
a6084c1a8d
5 files changed
+110
-7
No files matched your search
+57
-1
@@ -27,7 +27,9 @@ const OPEN_CREDITS := 290
|
||||
const AT_CREDITS := 320
|
||||
const OPEN_UPGRADES := 330
|
||||
const AT_UPGRADES := 360
|
||||
const DONE := 370
|
||||
const OPEN_ROSTER := 370
|
||||
const AT_ROSTER := 400
|
||||
const DONE := 410
|
||||
|
||||
var _frame: int = 0
|
||||
var _game: Node = null
|
||||
@@ -67,6 +69,10 @@ func _process(_delta: float) -> void:
|
||||
# Held until the shot is taken; one frame of it is not enough.
|
||||
if _frame > OPEN_UPGRADES and _frame <= AT_UPGRADES:
|
||||
_stand_at_the_npc()
|
||||
# Same reason: the game scene owns this screen's visibility too and decides
|
||||
# it every frame, so one assignment lasts exactly one frame.
|
||||
if _frame > OPEN_ROSTER and _frame <= AT_ROSTER:
|
||||
_show_the_roster()
|
||||
match _frame:
|
||||
AT_MENU:
|
||||
_grab("menu")
|
||||
@@ -108,11 +114,61 @@ func _process(_delta: float) -> void:
|
||||
_game.get_node("UpgradeScreen").refresh(2, offer, taken)
|
||||
AT_UPGRADES:
|
||||
_grab("upgrades")
|
||||
OPEN_ROSTER:
|
||||
_show_the_roster()
|
||||
AT_ROSTER:
|
||||
_grab("roster")
|
||||
DONE:
|
||||
Net.shutdown()
|
||||
get_tree().quit(0)
|
||||
|
||||
|
||||
## Put the roster on screen with a made-up set of characters.
|
||||
##
|
||||
## Made up for the same reason the upgrade offer is: the point is the layout,
|
||||
## and earning three characters at three different health levels first would
|
||||
## make the shot depend on a dungeon run. One whole, one badly hurt, one barely
|
||||
## alive -- health survives a run now, so the wounded rows are the reason this
|
||||
## screen is worth a picture at all.
|
||||
##
|
||||
## Walking off the quartermaster first is not optional: the game scene re-opens
|
||||
## the upgrade screen every frame the player is standing on the NPC, and it
|
||||
## draws over this one.
|
||||
func _show_the_roster() -> void:
|
||||
var away: Vector2 = Net.client.upgrade_npc + Vector2(600.0, 0.0)
|
||||
Net.client.predicted_pos = away
|
||||
var inst := Net.server.instance_of(Net.LOCAL_PEER)
|
||||
if inst != null:
|
||||
var p: SimPlayer = inst.world.players.get(Net.LOCAL_PEER)
|
||||
if p != null:
|
||||
p.pos = away
|
||||
_game.set("_upgrades_open", false)
|
||||
_game.set("_roster_open", true)
|
||||
var roster: Array[Dictionary] = [
|
||||
_roster_entry("Whole", 4, 1300, 1300, Color(0.5, 0.9, 1.0)),
|
||||
_roster_entry("Bruised", 7, 1600, 940, Color(1.0, 0.8, 0.4)),
|
||||
_roster_entry("Nearly", 11, 2000, 160, Color(1.0, 0.5, 0.5)),
|
||||
]
|
||||
_game.get_node("CharacterSelect").refresh(roster, "c4")
|
||||
|
||||
|
||||
## One roster row in the shape decode_characters produces.
|
||||
func _roster_entry(who: String, level: int, ceiling: int, current: int,
|
||||
tint: Color) -> Dictionary:
|
||||
return {
|
||||
"id": "c%d" % level,
|
||||
"name": who,
|
||||
"level": level,
|
||||
"xp": 0,
|
||||
"progress": 0.4,
|
||||
"max_hp": ceiling,
|
||||
"hp": current,
|
||||
"active": true,
|
||||
"colour": tint,
|
||||
"inventory": [0, 0, 0, 0] as Array[int],
|
||||
}
|
||||
|
||||
|
||||
func _grab(shot_name: String) -> void:
|
||||
var path := "%s/shot_%s.png" % [_dir, shot_name]
|
||||
var err := get_viewport().get_texture().get_image().save_png(path)
|
||||
|
||||
Reference in new issue
Block a user