A UI pass: prompts that tell the truth, and a HUD that does not collide
ci / verify (push) Successful in 53s
ci / verify (push) Successful in 53s
Prompts named the default keys whatever was bound. Every action is rebindable, but the HUD said "WASD move", "LMB fire", "hold F" and "1-4 use", the quartermaster said "E talk" and the upgrade screen "Close (E)". All of them now go through Settings.short_label(), and a test rebinds fire, escape, interact and a slot key and checks each prompt follows. The HUD's top-left was a developer's status line -- name, instance id, health as text, frame rate -- with the boss bar drawn over its right end and the level-up notice sharing a row with the escape bar. It is now name and level, where you are, health with its numbers, experience, escape and level-ups, stacked by a running cursor so nothing has a fixed row to collide on. Instance and fps moved behind F1, which is who they were for. Arrival protection is a centred banner rather than a note beside the health bar, because it is the one moment the rules change. A hit used to tint the whole screen red, which in a bullet hell dims the bullets at exactly the moment you are among them. It is an edge now, and the same edge pulses below a third of your health. New: a message feed above the inventory for what the server just confirmed -- items taken, used and dropped, levels gained -- and party health top-right in a dungeon, where the hub shows who is online. The pickup prompt now also names the dungeon under your feet when you stand on its ring, in the same order the server resolves that key: loot first, then the entrance. The boss bar used to announce the boss to anyone within the actor interest radius -- which passes through walls -- so a player in the entrance room was told the Warden was near. It waits until the fog has actually lit the boss once, then stays for the fight. Permadeath was announced only by the roster screen appearing. The client records its own death from the server's event and the roster says who fell, at what level, and where. The connect screen lost a name field that did nothing for a person -- it only named the characters bots create -- gained a proper panel, remembers the last server, and shows the protocol number a mismatch refusal will quote. And screenshot.tscn ran as the player's real account against their real character store, walking their character into dungeons for pictures -- with health now carried between runs, a stray hit would have stuck. It has its own store and account now, like every diagnostic, and a seeded character. The real store was checked: nothing it carries changed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
069abdb3fa
commit
19d2295bec
14 files changed
+903
-229
No files matched your search
@@ -254,3 +254,89 @@ func test_saving_writes_to_the_configured_path() -> void:
|
||||
var cfg := ConfigFile.new()
|
||||
assert_eq(cfg.load(_scratch), OK)
|
||||
assert_almost_eq(float(cfg.get_value("audio", "master")), 0.33, 0.001)
|
||||
|
||||
|
||||
# --- The connect screen remembers ---------------------------------------------
|
||||
|
||||
func test_the_last_server_survives_a_save_and_reload() -> void:
|
||||
var saved_address := Settings.last_address
|
||||
var saved_port := Settings.last_port
|
||||
Settings.remember_server(" play.example.net ", 27020)
|
||||
Settings.last_address = ""
|
||||
Settings.last_port = 0
|
||||
Settings.load_and_apply()
|
||||
assert_eq(Settings.last_address, "play.example.net", "trimmed, and back again")
|
||||
assert_eq(Settings.last_port, 27020)
|
||||
Settings.last_address = saved_address
|
||||
Settings.last_port = saved_port
|
||||
|
||||
|
||||
func test_nonsense_is_not_remembered() -> void:
|
||||
var saved_address := Settings.last_address
|
||||
Settings.last_address = "kept.example.net"
|
||||
Settings.remember_server(" ", 27020)
|
||||
Settings.remember_server("x.example.net", 0)
|
||||
Settings.remember_server("x.example.net", 70000)
|
||||
assert_eq(Settings.last_address, "kept.example.net",
|
||||
"a blank address or an impossible port must not replace a good one")
|
||||
Settings.last_address = saved_address
|
||||
|
||||
|
||||
# --- The HUD says what the keys actually are ----------------------------------
|
||||
# Every hint on screen used to be a literal -- "WASD move", "LMB fire", "hold F"
|
||||
# -- while every one of those actions is rebindable. Rebind fire and the HUD
|
||||
# kept telling you to click.
|
||||
|
||||
const HUD := preload("res://src/ui/hud.gd")
|
||||
|
||||
|
||||
func test_the_hints_name_the_default_keys() -> void:
|
||||
assert_eq(HUD.move_keys(), "WASD")
|
||||
assert_eq(HUD.key("fire"), "LMB")
|
||||
assert_eq(HUD.slot_keys(4), "1-4")
|
||||
assert_string_contains(HUD.controls_hint(false), "hold F")
|
||||
assert_string_contains(HUD.controls_hint(false), "Esc menu",
|
||||
"spelled the way a keycap spells it, not the way the OS names it")
|
||||
|
||||
|
||||
func test_the_hints_follow_a_rebind() -> void:
|
||||
var click := InputEventMouseButton.new()
|
||||
click.button_index = MOUSE_BUTTON_RIGHT
|
||||
click.device = -1
|
||||
assert_eq(Settings.rebind("fire", click), "")
|
||||
assert_eq(Settings.rebind("emergency_escape", _key_event(KEY_G)), "")
|
||||
var hint := HUD.controls_hint(false)
|
||||
assert_string_contains(hint, "RMB fire")
|
||||
assert_string_contains(hint, "hold G")
|
||||
assert_false(hint.contains("LMB"), "the old key is not mentioned anywhere")
|
||||
|
||||
|
||||
func test_movement_spelled_out_when_it_is_not_four_letters() -> void:
|
||||
assert_eq(Settings.rebind("move_up", _key_event(KEY_UP)), "")
|
||||
var keys := HUD.move_keys()
|
||||
assert_true(keys.begins_with("Up/"), "arrow keys read as words, got %s" % keys)
|
||||
|
||||
|
||||
func test_slot_keys_are_listed_when_they_are_not_one_to_four() -> void:
|
||||
assert_eq(Settings.rebind("use_slot_3", _key_event(KEY_Z)), "")
|
||||
assert_eq(HUD.slot_keys(4), "1 2 Z 4")
|
||||
|
||||
|
||||
func test_the_upgrade_screen_names_the_key_that_closes_it() -> void:
|
||||
assert_eq(Settings.rebind("interact", _key_event(KEY_G)), "")
|
||||
var screen: CanvasLayer = preload("res://src/ui/upgrade_screen.gd").new()
|
||||
add_child_autofree(screen)
|
||||
var none: Array[StringName] = []
|
||||
screen.refresh(0, none, none)
|
||||
assert_eq(screen._close.text, "Close (G)",
|
||||
"it used to say (E) whatever interact was bound to")
|
||||
|
||||
|
||||
func test_short_labels_are_what_a_keycap_says() -> void:
|
||||
var click := InputEventMouseButton.new()
|
||||
click.button_index = MOUSE_BUTTON_LEFT
|
||||
click.device = -1
|
||||
assert_eq(Settings.rebind("interact", click), "fire",
|
||||
"left click is fire's, and the clash is named")
|
||||
assert_eq(Settings.short_label("fire"), "LMB")
|
||||
assert_eq(Settings.short_label("system_menu"), "Esc")
|
||||
Reference in new issue
Block a user