Character and movement pass
NPC characters - Articulated rig (hips/knees, shoulders/elbows/hands) replaces rigid capsules; the walk cycle bends knees and elbows and flees with a longer stride. - Layered outfits (jacket/vest/coat/dress), extended accessories and hand items (bag, umbrella, phone, camera, clipboard, cup), face details and five hair silhouettes, all deterministic per profile seed. - Idle behaviour layers (phone, clipboard, crossed arms, look-around), breathing and weight shift; escalation raises hands or points, and noticed NPCs turn toward the guard. - Reaction symbols above the head (!!, ?!, !, ?), door-queue offsets assigned by GameManager, three LOD tiers with hysteresis and a billboard impostor. - smoke_npc_budget.gd: 16 avatars = 534 meshes, ~6.9 ms average (50 ms budget). Player movement - Separate accel/decel, step-up assist for kerbs and the entrance steps, and a forward-axis fix: W was inverted (get_axis(forward, back) is negative). - Head bob, landing dip and precision-walk FOV, gated by persisted head-bob and invert-Y settings; precision chip and tick; surface-aware footsteps and a landing cue forwarded to AudioFeedback. - Gamepad support (sticks, deadzone, face buttons, bumpers), a control legend that follows the active device, and named actions for the remaining keys. - Key/button remapping in Settings, persisted as input_bindings and applied by InputBindings (mouse and gamepad axes are never removed). - smoke_movement.gd (windowed): climbs the steps, checks precision speed, chip, footsteps and landing; new 11-precision-walk capture and catalogue entry. Verification: headless 208/208, Python tooling 56/56, all 11 smokes pass, compare 11 good / 0 bad, movement judge match. Version 0.5.0. Only optional Future ideas remain in TODO.
This commit is contained in:
1 parent
2a4e0d1998
commit
a27e8cb74c
35 files changed
+1608
-185
No files matched your search
@@ -0,0 +1,53 @@
|
||||
extends RefCounted
|
||||
## Headless tests for the key/button remap helper.
|
||||
|
||||
const InputBindings := preload("res://src/core/input_bindings.gd")
|
||||
|
||||
func test_descriptor_from_events() -> bool:
|
||||
var key := InputEventKey.new()
|
||||
key.physical_keycode = KEY_Z
|
||||
var a := TestUtils.check_eq(InputBindings.descriptor_from_event(key),
|
||||
{"type": "key", "code": int(KEY_Z)}, "keys store a code")
|
||||
var button := InputEventJoypadButton.new()
|
||||
button.button_index = JOY_BUTTON_Y
|
||||
var b := TestUtils.check_eq(InputBindings.descriptor_from_event(button),
|
||||
{"type": "joy", "button": int(JOY_BUTTON_Y)}, "pad buttons store an index")
|
||||
var c := TestUtils.check(
|
||||
InputBindings.descriptor_from_event(InputEventMouseButton.new()).is_empty(),
|
||||
"mouse buttons are not remappable")
|
||||
return a and b and c
|
||||
|
||||
func test_apply_rebinds_and_keeps_mouse_events() -> bool:
|
||||
var old := InputBindings.current_descriptor("inspect")
|
||||
var remap := {"inspect": {"type": "key", "code": int(KEY_Z)}}
|
||||
InputBindings.apply(remap)
|
||||
var rebound := InputBindings.current_descriptor("inspect")
|
||||
var a := TestUtils.check_eq(rebound, {"type": "key", "code": int(KEY_Z)},
|
||||
"inspect now uses the new key")
|
||||
var action_menu_mouse := 0
|
||||
for event in InputMap.action_get_events("action_menu"):
|
||||
if event is InputEventMouseButton:
|
||||
action_menu_mouse += 1
|
||||
var b := TestUtils.check(action_menu_mouse > 0,
|
||||
"remapping leaves mouse events alone")
|
||||
# Restore the original binding for later tests.
|
||||
if not old.is_empty():
|
||||
InputBindings.apply({"inspect": old})
|
||||
return a and b
|
||||
|
||||
func test_apply_accepts_pad_buttons() -> bool:
|
||||
var remap := {"wand": {"type": "joy", "button": int(JOY_BUTTON_RIGHT_SHOULDER)}}
|
||||
InputBindings.apply(remap)
|
||||
var a := TestUtils.check_eq(InputBindings.current_descriptor("wand"),
|
||||
{"type": "joy", "button": int(JOY_BUTTON_RIGHT_SHOULDER)},
|
||||
"actions can be rebound to a pad button")
|
||||
InputBindings.apply({"wand": {"type": "key", "code": int(KEY_C)}})
|
||||
return a
|
||||
|
||||
func test_labels_are_human_readable() -> bool:
|
||||
var a := TestUtils.check(InputBindings.label_for(
|
||||
{"type": "key", "code": int(KEY_W)}) == "W", "key label")
|
||||
var b := TestUtils.check(InputBindings.label_for(
|
||||
{"type": "joy", "button": 3}) == "Pad 3", "pad label")
|
||||
var c := TestUtils.check_eq(InputBindings.label_for({}), "", "empty label")
|
||||
return a and b and c
|
||||
Reference in new issue
Block a user