feat(client): ConsideringIndicator — rotates think-lines on a Timer
This commit is contained in:
44
client/scripts/ui/considering_indicator.gd
Normal file
44
client/scripts/ui/considering_indicator.gd
Normal file
@@ -0,0 +1,44 @@
|
||||
class_name ConsideringIndicator
|
||||
extends Node
|
||||
## Thin node shim (charter §13). While a call is in flight it rotates an authored
|
||||
## ConsideringPhrases line onto a Label every ROTATE_SECONDS, reframing the wait
|
||||
## as the GM thinking. The phrase logic is the pure, tested ConsideringPhrases;
|
||||
## the Timer/tree wiring here is the untested shim (verified by running the
|
||||
## harness). One instance persists on the harness so the rotation index is not
|
||||
## reset per call (spec decision 4).
|
||||
|
||||
const ROTATE_SECONDS := 2.0
|
||||
|
||||
var _phrases: ConsideringPhrases
|
||||
var _timer: Timer
|
||||
var _label: Label
|
||||
|
||||
|
||||
func _init(phrases: ConsideringPhrases = null) -> void:
|
||||
_phrases = phrases if phrases != null else ConsideringPhrases.new()
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
_timer = Timer.new()
|
||||
_timer.wait_time = ROTATE_SECONDS
|
||||
_timer.one_shot = false
|
||||
_timer.timeout.connect(_advance)
|
||||
add_child(_timer)
|
||||
|
||||
|
||||
func start(label: Label) -> void:
|
||||
_label = label
|
||||
_advance() # show a phrase immediately, don't wait ROTATE_SECONDS
|
||||
_timer.start()
|
||||
|
||||
|
||||
func stop() -> void:
|
||||
_timer.stop()
|
||||
if _label != null:
|
||||
_label.text = ""
|
||||
_label = null
|
||||
|
||||
|
||||
func _advance() -> void:
|
||||
if _label != null:
|
||||
_label.text = _phrases.next()
|
||||
19
client/tests/unit/test_considering_indicator.gd
Normal file
19
client/tests/unit/test_considering_indicator.gd
Normal file
@@ -0,0 +1,19 @@
|
||||
extends "res://addons/gut/test.gd"
|
||||
|
||||
const ConsideringIndicator = preload("res://scripts/ui/considering_indicator.gd")
|
||||
const ConsideringPhrases = preload("res://scripts/ui/considering_phrases.gd")
|
||||
|
||||
|
||||
func test_start_shows_first_phrase_and_stop_clears():
|
||||
# Point phrases at a missing file so next() is deterministically LAST_RESORT.
|
||||
var phrases = ConsideringPhrases.new("res://content/does_not_exist.json")
|
||||
var ind = ConsideringIndicator.new(phrases)
|
||||
add_child_autofree(ind) # _ready() creates the Timer child
|
||||
var label := Label.new()
|
||||
add_child_autofree(label)
|
||||
|
||||
ind.start(label)
|
||||
assert_eq(label.text, ConsideringPhrases.LAST_RESORT) # first phrase shown at once
|
||||
|
||||
ind.stop()
|
||||
assert_eq(label.text, "") # cleared on stop
|
||||
Reference in New Issue
Block a user