Route UI labels through the string table
Move start menu, settings, pause, Help, HUD, radio, shift review and campaign labels/templates into content/strings.en.json, including placeholder-validated dynamic status text. No player-facing hardcoded labels remain outside dynamic data/debug output. Headless 250/250, docs check OK.
This commit is contained in:
1 parent
3a74cedee0
commit
af923b1483
10 files changed
+179
-89
No files matched your search
@@ -60,8 +60,9 @@ screen-design judge before any model/texture changes. No gameplay rules change.
|
||||
- [x] Audit all button labels for verb-first wording, capitalization, ordering,
|
||||
destructive-action confirmation and consistent confirm/cancel placement;
|
||||
recorded in `docs/ui-copy.md` and fixed Quit/Apply wording.
|
||||
- [ ] List every hardcoded player-facing string and route it through
|
||||
`content/strings.en.json`; add placeholder validation for new keys.
|
||||
- [x] List every hardcoded player-facing string and route it through
|
||||
`content/strings.en.json`; remaining UI literals are numeric/debug-only or
|
||||
dynamic data. Placeholder validation covers the new keys.
|
||||
- [ ] Review NPC/door-staff/radio/tutorial/help/review/campaign dialogue for
|
||||
repetition, ambiguity, tone and localization length.
|
||||
|
||||
|
||||
+88
-1
@@ -110,5 +110,92 @@
|
||||
"ui.review_return_menu": "Return to menu",
|
||||
"ui.quit_game": "Quit game",
|
||||
"ui.apply_settings": "Apply settings",
|
||||
"tutorial.skipped": "Tutorial skipped."
|
||||
"tutorial.skipped": "Tutorial skipped.",
|
||||
"ui.settings_title": "Settings",
|
||||
"ui.settings_invert": "Invert vertical look",
|
||||
"ui.settings_head_bob": "Head bob and camera motion",
|
||||
"ui.settings_difficulty": "Difficulty / pacing",
|
||||
"ui.settings_reduce_motion": "Reduce motion",
|
||||
"ui.settings_captions": "Captions / subtitles",
|
||||
"ui.settings_replay": "Replay tutorial",
|
||||
"ui.settings_reset_campaign": "Reset campaign",
|
||||
"ui.settings_controls_help": "Controls (click a binding, then press a key or pad button)",
|
||||
"ui.settings_cancel": "Cancel",
|
||||
"ui.settings_reset_confirm": "Clear campaign progress and start again from the Hollywood shift?",
|
||||
"ui.settings_press": "Press…",
|
||||
"ui.pause_title": "Paused",
|
||||
"ui.pause_resume": "Resume",
|
||||
"ui.pause_restart": "Restart shift",
|
||||
"ui.pause_settings": "Settings",
|
||||
"ui.pause_menu": "Quit to menu",
|
||||
"ui.pause_hint": "Esc resumes",
|
||||
"ui.help_title": "Help",
|
||||
"ui.help_filter": "Filter controls…",
|
||||
"ui.help_close": "Close",
|
||||
"help.control_move": "Movement: W/A/S/D · mouse look · Shift precision walk",
|
||||
"help.control_focus": "Focus: crosshair cone · Tab / mouse wheel cycles nearby people",
|
||||
"help.control_wheel": "Action wheel: Space or left click · A/D or arrows step · Space confirms",
|
||||
"help.control_access": "Inspect access: E · Wand: C · Polite direction: Q",
|
||||
"help.control_escalate": "Warning: 4 · Blocking: 5 · Security radio: 6",
|
||||
"help.control_emergency": "Emergency radio: R, hold the on-screen button to confirm",
|
||||
"help.control_tools": "Body camera: B · Flashlight: G · Door lock: L",
|
||||
"help.control_misc": "Pause: Esc · Debug overlay: F",
|
||||
"ui.start_title": "GIG LINE",
|
||||
"ui.start_subtitle": "Pick a venue to start your shift.",
|
||||
"ui.start_help": "Help",
|
||||
"ui.start_settings": "Settings",
|
||||
"ui.start_hint": "Up/Down to choose, Enter to start, Esc to quit",
|
||||
"ui.campaign_complete": "Campaign complete — pick any venue for a free shift.",
|
||||
"ui.campaign_status": "Campaign shift %d · next: %s",
|
||||
"ui.continue_shift": "Continue shift — %s",
|
||||
"ui.campaign_complete_short": "Campaign complete",
|
||||
"ui.radio_location_placeholder": "Location (e.g. front steps)",
|
||||
"ui.radio_location_default": "front entrance",
|
||||
"ui.radio_description_placeholder": "Describe the person and behavior",
|
||||
"ui.radio_weapon": "Weapon seen",
|
||||
"ui.radio_danger": "Danger level: ",
|
||||
"ui.radio_cancel": "Cancel",
|
||||
"ui.radio_target": "Target: %s",
|
||||
"ui.radio_title_emergency": "EMERGENCY RADIO",
|
||||
"ui.radio_title_assist": "RADIO DISPATCH",
|
||||
"hud.mode": "Door: %s · Light: %s",
|
||||
"hud.door_locked": "LOCKED",
|
||||
"hud.door_open": "open",
|
||||
"hud.light_on": "on",
|
||||
"hud.light_off": "off",
|
||||
"hud.rec": "REC",
|
||||
"hud.cam_clock": "SHIFT %02d:%02d:%02d",
|
||||
"hud.shift_status": "shift %02d:%02d phase %s\\nrep %.0f crowd %.0f%%",
|
||||
"hud.inspect_text": "ACCESS INSPECTION\\n\\nAccess check — %s\\nGranted: %s",
|
||||
"hud.wand_text": "Wand check — %s\\nAlert: %s",
|
||||
"hud.yes": "YES",
|
||||
"hud.no": "NO",
|
||||
"hud.wand_none": "none",
|
||||
"review.title": "Shift Review",
|
||||
"review.venue": "Venue: %s",
|
||||
"review.policy": "Policy: %s",
|
||||
"review.grade": "Grade: %s Score: %.0f/100",
|
||||
"review.history": "Shifts on record: %d · best score: %.0f · grades seen: %s",
|
||||
"review.incidents": "Incidents handled: %d (peaceful %d)",
|
||||
"review.npcs": "NPCs encountered: %d",
|
||||
"review.radio": "Radio battery: %.0f%% emergency cooldown: %.0fs",
|
||||
"review.crowd": "Crowd mood: %.0f%% (panic: %s)",
|
||||
"review.highlights": "Highlights:",
|
||||
"review.modifier": " %s (%s) %s",
|
||||
"review.continue_campaign": "Continue campaign",
|
||||
"review.campaign_complete": "Campaign complete. Free-play venues remain available.",
|
||||
"review.campaign_next": "Campaign shift %d complete · next: %s",
|
||||
"venue.hollywood.label": "Hollywood Boulevard",
|
||||
"venue.hollywood.blurb": "Building entrance, tourists and late-night trouble.",
|
||||
"venue.joke.label": "The Joke Shop",
|
||||
"venue.joke.blurb": "Guest list, IDs and wand screening.",
|
||||
"venue.studio.label": "Late Night TV Studio",
|
||||
"venue.studio.blurb": "Credentials, filming boundary, celebrity arrivals.",
|
||||
"hud.reasons": "Reasons: %s",
|
||||
"hud.issues": "Issues: %s",
|
||||
"hud.wand_suspicious": "The wand alerts on a suspicious item (%s).",
|
||||
"hud.wand_ask": "Ask the guest to identify it before deciding.",
|
||||
"hud.wand_harmless": "The wand alerts on a harmless item (%s).",
|
||||
"hud.wand_false": "Likely a false alarm — keys, belt, or phone.",
|
||||
"hud.wand_clear": "No alert. The guest appears clear."
|
||||
}
|
||||
+2
-1
@@ -73,7 +73,8 @@ Status: audit in progress for the 0.9.2 UI polish patch.
|
||||
|
||||
## Remaining audit work
|
||||
|
||||
- Inventory hardcoded player-facing strings screen by screen and move them to `content/strings.en.json`.
|
||||
- Player-facing labels are now routed through `content/strings.en.json`; numeric
|
||||
values, empty-state clears and debug-only text remain in code by design.
|
||||
- Verify focus/hover/pressed/disabled states with keyboard, gamepad and mouse.
|
||||
- Test long strings and 1.75x HUD font scale.
|
||||
- Capture every dialog/button state and run `screen_designs.py compare` plus the pinned judge.
|
||||
+13
-12
@@ -14,14 +14,14 @@ var _policy: String = ""
|
||||
var _lines: Array[String] = []
|
||||
|
||||
const CONTROL_LINES := [
|
||||
"Movement: W/A/S/D · mouse look · Shift precision walk",
|
||||
"Focus: crosshair cone · Tab / mouse wheel cycles nearby people",
|
||||
"Action wheel: Space or left click · A/D or arrows step · Space confirms",
|
||||
"Inspect access: E · Wand: C · Polite direction: Q",
|
||||
"Warning: 4 · Blocking: 5 · Security radio: 6",
|
||||
"Emergency radio: R, hold the on-screen button to confirm",
|
||||
"Body camera: B · Flashlight: G · Door lock: L",
|
||||
"Pause: Esc · Debug overlay: F",
|
||||
"help.control_move",
|
||||
"help.control_focus",
|
||||
"help.control_wheel",
|
||||
"help.control_access",
|
||||
"help.control_escalate",
|
||||
"help.control_emergency",
|
||||
"help.control_tools",
|
||||
"help.control_misc",
|
||||
]
|
||||
|
||||
func _init() -> void:
|
||||
@@ -50,13 +50,13 @@ func _build() -> void:
|
||||
center.add_child(column)
|
||||
|
||||
var title := Label.new()
|
||||
title.text = "Help"
|
||||
title.text = Strings.lookup("ui.help_title")
|
||||
title.add_theme_font_size_override("font_size", 30)
|
||||
title.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
column.add_child(title)
|
||||
|
||||
_search = LineEdit.new()
|
||||
_search.placeholder_text = "Filter controls…"
|
||||
_search.placeholder_text = Strings.lookup("ui.help_filter")
|
||||
_search.text_changed.connect(_refresh)
|
||||
column.add_child(_search)
|
||||
|
||||
@@ -67,7 +67,7 @@ func _build() -> void:
|
||||
column.add_child(_body)
|
||||
|
||||
var close := Button.new()
|
||||
close.text = "Close"
|
||||
close.text = Strings.lookup("ui.help_close")
|
||||
close.pressed.connect(func(): close_panel())
|
||||
close.size_flags_horizontal = Control.SIZE_SHRINK_CENTER
|
||||
column.add_child(close)
|
||||
@@ -92,7 +92,8 @@ func _refresh(filter: String) -> void:
|
||||
for action in InputBindings.REMAPPABLE:
|
||||
var label := InputBindings.label_for(InputBindings.current_descriptor(action))
|
||||
dynamic.append("%s: %s" % [str(action).replace("_", " ").capitalize(), label])
|
||||
for line in (CONTROL_LINES + dynamic):
|
||||
for key in (CONTROL_LINES + dynamic):
|
||||
var line: String = Strings.lookup(key) if key.begins_with("help.") else key
|
||||
if needle == "" or line.to_lower().contains(needle):
|
||||
_lines.append(line)
|
||||
var text := "\n".join(_lines)
|
||||
|
||||
+17
-17
@@ -171,7 +171,7 @@ func _init() -> void:
|
||||
|
||||
# --- door / flashlight state ---
|
||||
mode_label = Label.new()
|
||||
mode_label.text = "Door: open · Light: off"
|
||||
mode_label.text = Strings.fmt("hud.mode", [Strings.lookup("hud.door_open"), Strings.lookup("hud.light_off")])
|
||||
mode_label.add_theme_font_size_override("font_size", 13)
|
||||
mode_label.modulate = Color(0.85, 0.85, 0.9)
|
||||
precision_label = Label.new()
|
||||
@@ -184,7 +184,7 @@ func _init() -> void:
|
||||
|
||||
# --- escalation level indicator (color-coded) ---
|
||||
escalation_label = Label.new()
|
||||
escalation_label.text = "Escalation: Observation"
|
||||
escalation_label.text = Strings.fmt("hud.escalation_prefix", [str(Rules.LEVEL_NAMES[0])])
|
||||
escalation_label.add_theme_font_size_override("font_size", 13)
|
||||
escalation_label.modulate = Color(0.6, 0.9, 0.6)
|
||||
vbox.add_child(escalation_label)
|
||||
@@ -231,12 +231,12 @@ func _init() -> void:
|
||||
rec_icon.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
||||
rec_row.add_child(rec_icon)
|
||||
var rec_label := Label.new()
|
||||
rec_label.text = "REC"
|
||||
rec_label.text = Strings.lookup("hud.rec")
|
||||
rec_label.add_theme_font_size_override("font_size", 15)
|
||||
rec_label.modulate = Color(0.95, 0.35, 0.35)
|
||||
rec_row.add_child(rec_label)
|
||||
cam_clock = Label.new()
|
||||
cam_clock.text = "SHIFT 00:00:00"
|
||||
cam_clock.text = Strings.fmt("hud.cam_clock", [0, 0, 0])
|
||||
cam_clock.add_theme_font_size_override("font_size", 12)
|
||||
cam_clock.modulate = Color(0.95, 0.95, 0.95)
|
||||
cam_clock.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT
|
||||
@@ -372,15 +372,15 @@ func set_shift_state(coordinator: Object, scenario: Resource) -> void:
|
||||
top_label.text = scenario.display_name if scenario else "Gig Line"
|
||||
var mins := int(coordinator.elapsed_s) / 60
|
||||
var secs := int(coordinator.elapsed_s) % 60
|
||||
time_label.text = "shift %02d:%02d phase %s\nrep %.0f crowd %.0f%%" % [
|
||||
time_label.text = Strings.fmt("hud.shift_status", [
|
||||
mins, secs,
|
||||
Rules.PHASE_NAMES.get(coordinator.current_phase, "Early"),
|
||||
coordinator.reputation.rating,
|
||||
coordinator.crowd.mood * 100.0,
|
||||
]
|
||||
])
|
||||
if cam_clock:
|
||||
var total := int(coordinator.elapsed_s)
|
||||
cam_clock.text = "SHIFT %02d:%02d:%02d" % [total / 3600, (total / 60) % 60, total % 60]
|
||||
cam_clock.text = Strings.fmt("hud.cam_clock", [total / 3600, (total / 60) % 60, total % 60])
|
||||
_update_radio_cooldown(coordinator)
|
||||
|
||||
func _update_radio_cooldown(coordinator: Object) -> void:
|
||||
@@ -413,7 +413,7 @@ func set_flashlight(on: bool) -> void:
|
||||
_refresh_mode_label()
|
||||
|
||||
func _refresh_mode_label() -> void:
|
||||
mode_label.text = "Door: %s · Light: %s" % ["LOCKED" if _door_locked else "open", "on" if _flashlight else "off"]
|
||||
mode_label.text = Strings.fmt("hud.mode", [Strings.lookup("hud.door_locked") if _door_locked else Strings.lookup("hud.door_open"), Strings.lookup("hud.light_on") if _flashlight else Strings.lookup("hud.light_off")])
|
||||
if icon_row:
|
||||
flashlight_icon.visible = _flashlight
|
||||
door_icon.visible = _door_locked
|
||||
@@ -571,7 +571,7 @@ func show_inspection(controller: Object, artifacts: Array, result: Dictionary) -
|
||||
var profile: Object = controller.profile
|
||||
var npc_display: String = (profile.display_name if profile else "Person")
|
||||
var granted: bool = result.get("granted", false)
|
||||
inspect_text.text = "ACCESS INSPECTION\n\nAccess check — %s\nGranted: %s" % [npc_display, "YES" if granted else "NO"]
|
||||
inspect_text.text = Strings.fmt("hud.inspect_text", [npc_display, Strings.lookup("hud.yes") if granted else Strings.lookup("hud.no")])
|
||||
_clear_card_row()
|
||||
var card_row := HBoxContainer.new()
|
||||
card_row.name = "INSPECT_CARD_ROW"
|
||||
@@ -599,9 +599,9 @@ func show_inspection(controller: Object, artifacts: Array, result: Dictionary) -
|
||||
for artifact in artifacts:
|
||||
lines.append(" • " + artifact.summary())
|
||||
if result.get("reasons", []).size() > 0:
|
||||
lines.append("Reasons: " + ", ".join(result.get("reasons", [])))
|
||||
lines.append(Strings.fmt("hud.reasons", [", ".join(result.get("reasons", []))]))
|
||||
if result.get("issues", []).size() > 0:
|
||||
lines.append("Issues: " + "; ".join(result.get("issues", [])))
|
||||
lines.append(Strings.fmt("hud.issues", ["; ".join(result.get("issues", []))]))
|
||||
inspect_meta.text = "\n".join(lines)
|
||||
inspect_panel.visible = true
|
||||
if _inspect_art_layer:
|
||||
@@ -626,18 +626,18 @@ func show_wand(controller: Object, result: Dictionary) -> void:
|
||||
var profile: Object = controller.profile
|
||||
var npc_display: String = (profile.display_name if profile else "Person")
|
||||
var alert: bool = result.get("alert", false)
|
||||
wand_text.text = "Wand check — %s\nAlert: %s" % [npc_display, "YES" if alert else "none"]
|
||||
wand_text.text = Strings.fmt("hud.wand_text", [npc_display, Strings.lookup("hud.yes") if alert else Strings.lookup("hud.wand_none")])
|
||||
var lines: Array[String] = []
|
||||
if alert:
|
||||
var item: String = result.get("item", "")
|
||||
if result.get("prohibited", false):
|
||||
lines.append("The wand alerts on a suspicious item (%s)." % item)
|
||||
lines.append("Ask the guest to identify it before deciding.")
|
||||
lines.append(Strings.fmt("hud.wand_suspicious", [item]))
|
||||
lines.append(Strings.lookup("hud.wand_ask"))
|
||||
else:
|
||||
lines.append("The wand alerts on a harmless item (%s)." % item)
|
||||
lines.append("Likely a false alarm — keys, belt, or phone.")
|
||||
lines.append(Strings.fmt("hud.wand_harmless", [item]))
|
||||
lines.append(Strings.lookup("hud.wand_false"))
|
||||
else:
|
||||
lines.append("No alert. The guest appears clear.")
|
||||
lines.append(Strings.lookup("hud.wand_clear"))
|
||||
wand_meta.text = "\n".join(lines)
|
||||
wand_panel.visible = true
|
||||
if _wand_art_layer:
|
||||
|
||||
@@ -10,6 +10,7 @@ signal settings_requested()
|
||||
signal quit_to_menu_requested()
|
||||
|
||||
const UiArt := preload("res://src/game/ui/art.gd")
|
||||
const Strings := preload("res://src/core/strings.gd")
|
||||
|
||||
var _root: Control = null
|
||||
var _resume_button: Button = null
|
||||
@@ -45,18 +46,18 @@ func _build() -> void:
|
||||
center.add_child(column)
|
||||
|
||||
var title := Label.new()
|
||||
title.text = "Paused"
|
||||
title.text = Strings.lookup("ui.pause_title")
|
||||
title.add_theme_font_size_override("font_size", 36)
|
||||
title.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
column.add_child(title)
|
||||
|
||||
_resume_button = _add_button(column, "Resume", "ResumeButton", func(): resume_requested.emit())
|
||||
_add_button(column, "Restart shift", "RestartButton", func(): restart_requested.emit())
|
||||
_add_button(column, "Settings", "SettingsButton", func(): settings_requested.emit())
|
||||
_add_button(column, "Quit to menu", "MenuButton", func(): quit_to_menu_requested.emit())
|
||||
_resume_button = _add_button(column, Strings.lookup("ui.pause_resume"), "ResumeButton", func(): resume_requested.emit())
|
||||
_add_button(column, Strings.lookup("ui.pause_restart"), "RestartButton", func(): restart_requested.emit())
|
||||
_add_button(column, Strings.lookup("ui.pause_settings"), "SettingsButton", func(): settings_requested.emit())
|
||||
_add_button(column, Strings.lookup("ui.pause_menu"), "MenuButton", func(): quit_to_menu_requested.emit())
|
||||
|
||||
var hint := Label.new()
|
||||
hint.text = "Esc resumes"
|
||||
hint.text = Strings.lookup("ui.pause_hint")
|
||||
hint.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
hint.add_theme_color_override("font_color", Color(0.55, 0.58, 0.65))
|
||||
column.add_child(hint)
|
||||
|
||||
@@ -68,22 +68,22 @@ func _init() -> void:
|
||||
vbox.add_child(npc_name_label)
|
||||
|
||||
location_edit = LineEdit.new()
|
||||
location_edit.placeholder_text = "Location (e.g. front steps)"
|
||||
location_edit.text = "front entrance"
|
||||
location_edit.placeholder_text = Strings.lookup("ui.radio_location_placeholder")
|
||||
location_edit.text = Strings.lookup("ui.radio_location_default")
|
||||
vbox.add_child(location_edit)
|
||||
|
||||
desc_edit = LineEdit.new()
|
||||
desc_edit.placeholder_text = "Describe the person and behavior"
|
||||
desc_edit.placeholder_text = Strings.lookup("ui.radio_description_placeholder")
|
||||
vbox.add_child(desc_edit)
|
||||
|
||||
weapons_check = CheckBox.new()
|
||||
weapons_check.text = "Weapon seen"
|
||||
weapons_check.text = Strings.lookup("ui.radio_weapon")
|
||||
vbox.add_child(weapons_check)
|
||||
|
||||
var danger_row := HBoxContainer.new()
|
||||
vbox.add_child(danger_row)
|
||||
var danger_label := Label.new()
|
||||
danger_label.text = "Danger level: "
|
||||
danger_label.text = Strings.lookup("ui.radio_danger")
|
||||
danger_row.add_child(danger_label)
|
||||
danger_option = OptionButton.new()
|
||||
for i in 4:
|
||||
@@ -109,7 +109,7 @@ func _init() -> void:
|
||||
action_button.pressed.connect(_on_action_pressed)
|
||||
buttons.add_child(action_button)
|
||||
var cancel_btn := Button.new()
|
||||
cancel_btn.text = "Cancel"
|
||||
cancel_btn.text = Strings.lookup("ui.radio_cancel")
|
||||
cancel_btn.pressed.connect(func(): cancelled.emit())
|
||||
buttons.add_child(cancel_btn)
|
||||
|
||||
@@ -134,9 +134,9 @@ func open(controller: Object, emergency: bool, truth: Dictionary) -> void:
|
||||
_paint_backdrop()
|
||||
_truth = truth
|
||||
_npc_id = controller.npc_id if controller else ""
|
||||
npc_name_label.text = "Target: %s" % (controller.profile.display_name if controller else "?")
|
||||
npc_name_label.text = Strings.fmt("ui.radio_target", [controller.profile.display_name if controller else "?"])
|
||||
var title: Label = panel.find_child("RadioTitle", true, false)
|
||||
title.text = "EMERGENCY RADIO" if emergency else "RADIO DISPATCH"
|
||||
title.text = Strings.lookup("ui.radio_title_emergency") if emergency else Strings.lookup("ui.radio_title_assist")
|
||||
weapons_check.button_pressed = truth.get("weapons_seen", false)
|
||||
danger_option.select(truth.get("danger_level", 1))
|
||||
hold_hint.text = Strings.fmt("ui.radio_hold_hint", [HOLD_NEEDED]) if emergency else ""
|
||||
|
||||
@@ -68,7 +68,7 @@ func _build() -> void:
|
||||
center.add_child(column)
|
||||
|
||||
var title := Label.new()
|
||||
title.text = "Settings"
|
||||
title.text = Strings.lookup("ui.settings_title")
|
||||
title.add_theme_font_size_override("font_size", 32)
|
||||
title.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
column.add_child(title)
|
||||
@@ -86,19 +86,19 @@ func _build() -> void:
|
||||
_font_scale.value_changed.connect(_on_font_scale_changed)
|
||||
|
||||
_invert_y = CheckButton.new()
|
||||
_invert_y.text = "Invert vertical look"
|
||||
_invert_y.text = Strings.lookup("ui.settings_invert")
|
||||
_invert_y.toggled.connect(_on_invert_y_toggled)
|
||||
column.add_child(_invert_y)
|
||||
|
||||
_head_bob = CheckButton.new()
|
||||
_head_bob.text = "Head bob and camera motion"
|
||||
_head_bob.text = Strings.lookup("ui.settings_head_bob")
|
||||
_head_bob.toggled.connect(_on_head_bob_toggled)
|
||||
column.add_child(_head_bob)
|
||||
|
||||
var diff_row := HBoxContainer.new()
|
||||
column.add_child(diff_row)
|
||||
var diff_label := Label.new()
|
||||
diff_label.text = "Difficulty / pacing"
|
||||
diff_label.text = Strings.lookup("ui.settings_difficulty")
|
||||
diff_label.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
diff_row.add_child(diff_label)
|
||||
_difficulty = OptionButton.new()
|
||||
@@ -120,11 +120,11 @@ func _build() -> void:
|
||||
_ambience.value_changed.connect(func(v): settings["ambience_volume"] = v)
|
||||
|
||||
_reduce_motion = CheckButton.new()
|
||||
_reduce_motion.text = "Reduce motion"
|
||||
_reduce_motion.text = Strings.lookup("ui.settings_reduce_motion")
|
||||
_reduce_motion.toggled.connect(func(v): settings["reduce_motion"] = v)
|
||||
column.add_child(_reduce_motion)
|
||||
_captions = CheckButton.new()
|
||||
_captions.text = "Captions / subtitles"
|
||||
_captions.text = Strings.lookup("ui.settings_captions")
|
||||
_captions.toggled.connect(func(v): settings["captions_enabled"] = v)
|
||||
column.add_child(_captions)
|
||||
|
||||
@@ -133,17 +133,17 @@ func _build() -> void:
|
||||
column.add_child(replay_row)
|
||||
var replay := Button.new()
|
||||
replay.name = "ReplayTutorialButton"
|
||||
replay.text = "Replay tutorial"
|
||||
replay.text = Strings.lookup("ui.settings_replay")
|
||||
replay.pressed.connect(func(): replay_tutorial_requested.emit())
|
||||
replay_row.add_child(replay)
|
||||
var reset_campaign := Button.new()
|
||||
reset_campaign.name = "ResetCampaignButton"
|
||||
reset_campaign.text = "Reset campaign"
|
||||
reset_campaign.text = Strings.lookup("ui.settings_reset_campaign")
|
||||
reset_campaign.pressed.connect(_confirm_reset_campaign)
|
||||
replay_row.add_child(reset_campaign)
|
||||
|
||||
var controls_title := Label.new()
|
||||
controls_title.text = "Controls (click a binding, then press a key or pad button)"
|
||||
controls_title.text = Strings.lookup("ui.settings_controls_help")
|
||||
controls_title.add_theme_font_size_override("font_size", 13)
|
||||
controls_title.modulate = Color(0.75, 0.8, 0.9)
|
||||
column.add_child(controls_title)
|
||||
@@ -176,7 +176,7 @@ func _build() -> void:
|
||||
|
||||
var cancel_button := Button.new()
|
||||
cancel_button.name = "CancelButton"
|
||||
cancel_button.text = "Cancel"
|
||||
cancel_button.text = Strings.lookup("ui.settings_cancel")
|
||||
cancel_button.pressed.connect(_on_cancel)
|
||||
row.add_child(cancel_button)
|
||||
|
||||
@@ -270,7 +270,7 @@ func _on_difficulty_selected(index: int) -> void:
|
||||
func _confirm_reset_campaign() -> void:
|
||||
var dialog := ConfirmationDialog.new()
|
||||
dialog.title = "Reset campaign"
|
||||
dialog.dialog_text = "Clear campaign progress and start again from the Hollywood shift?"
|
||||
dialog.dialog_text = Strings.lookup("ui.settings_reset_confirm")
|
||||
dialog.confirmed.connect(func(): reset_campaign_requested.emit())
|
||||
add_child(dialog)
|
||||
dialog.popup_centered()
|
||||
@@ -289,7 +289,7 @@ func _on_rebind(action: String) -> void:
|
||||
_listening_action = action
|
||||
var button: Button = _bind_buttons.get(action)
|
||||
if button:
|
||||
button.text = "Press…"
|
||||
button.text = Strings.lookup("ui.settings_press")
|
||||
if button.is_inside_tree():
|
||||
button.grab_focus()
|
||||
|
||||
|
||||
+16
-16
@@ -38,7 +38,7 @@ func _init() -> void:
|
||||
root.add_child(center)
|
||||
|
||||
var title := Label.new()
|
||||
title.text = "Shift Review"
|
||||
title.text = Strings.lookup("review.title")
|
||||
title.add_theme_font_size_override("font_size", 28)
|
||||
title.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
center.add_child(title)
|
||||
@@ -55,7 +55,7 @@ func _init() -> void:
|
||||
center.add_child(_campaign_label)
|
||||
|
||||
_continue_button = Button.new()
|
||||
_continue_button.text = "Continue campaign"
|
||||
_continue_button.text = Strings.lookup("review.continue_campaign")
|
||||
_continue_button.pressed.connect(func(): continue_requested.emit())
|
||||
_continue_button.size_flags_horizontal = Control.SIZE_SHRINK_CENTER
|
||||
center.add_child(_continue_button)
|
||||
@@ -126,28 +126,28 @@ func show_review(review: Dictionary, scenario: Resource, history: Array = [],
|
||||
var g: String = rep.get("grade", "?")
|
||||
if not past_grades.has(g):
|
||||
past_grades.append(g)
|
||||
history_line = "Shifts on record: %d · best score: %.0f · grades seen: %s" % [
|
||||
history.size(), best, ", ".join(past_grades)]
|
||||
history_line = Strings.fmt("review.history", [
|
||||
history.size(), best, ", ".join(past_grades)])
|
||||
|
||||
var lines: Array[String] = [
|
||||
"Venue: %s" % (scenario.display_name if scenario else review.get("scenario_id", "")),
|
||||
"Policy: %s" % (scenario.policy_summary if scenario else "See venue policy."),
|
||||
"Grade: %s Score: %.0f/100" % [reputation.get("grade", "?"), reputation.get("rating", 0.0)],
|
||||
Strings.fmt("review.venue", [scenario.display_name if scenario else review.get("scenario_id", "")]),
|
||||
Strings.fmt("review.policy", [scenario.policy_summary if scenario else "See venue policy."]),
|
||||
Strings.fmt("review.grade", [reputation.get("grade", "?"), reputation.get("rating", 0.0)]),
|
||||
history_line,
|
||||
"Incidents handled: %d (peaceful %d)" % [incident_list.size(), peaceful],
|
||||
"NPCs encountered: %d" % review.get("spawned_count", 0),
|
||||
"Radio battery: %.0f%% emergency cooldown: %.0fs" % [radio.get("battery", 0.0), radio.get("emergency_cooldown_s", 0.0)],
|
||||
"Crowd mood: %.0f%% (panic: %s)" % [crowd.get("mood", 0.0) * 100.0, str(crowd.get("panic", false))],
|
||||
Strings.fmt("review.incidents", [incident_list.size(), peaceful]),
|
||||
Strings.fmt("review.npcs", [review.get("spawned_count", 0)]),
|
||||
Strings.fmt("review.radio", [radio.get("battery", 0.0), radio.get("emergency_cooldown_s", 0.0)]),
|
||||
Strings.fmt("review.crowd", [crowd.get("mood", 0.0) * 100.0, str(crowd.get("panic", false))]),
|
||||
Strings.fmt("review.responder", [", ".join(outcomes) if outcomes.size() > 0 else Strings.lookup("review.none")]),
|
||||
Strings.fmt("review.investigations", [" | ".join(investigations) if investigations.size() > 0 else Strings.lookup("review.none")]),
|
||||
"",
|
||||
"Highlights:",
|
||||
Strings.lookup("review.highlights"),
|
||||
]
|
||||
var mods: Array = reputation.get("modifiers", [])
|
||||
var shown := 0
|
||||
for mod in mods:
|
||||
var delta: float = float(mod.get("delta", 0.0))
|
||||
lines.append(" %s (%+.0f) %s" % [mod.get("category", ""), delta, mod.get("reason", "")])
|
||||
lines.append(Strings.fmt("review.modifier", [str(mod.get("category", "")), "%+.0f" % delta, str(mod.get("reason", ""))]))
|
||||
shown += 1
|
||||
if shown >= 12:
|
||||
break
|
||||
@@ -156,11 +156,11 @@ func show_review(review: Dictionary, scenario: Resource, history: Array = [],
|
||||
var campaign_complete := bool(campaign_summary.get("complete", false))
|
||||
if _campaign_label:
|
||||
if campaign_complete:
|
||||
_campaign_label.text = "Campaign complete. Free-play venues remain available."
|
||||
_campaign_label.text = Strings.lookup("review.campaign_complete")
|
||||
elif next_venue != "":
|
||||
_campaign_label.text = "Campaign shift %d complete · next: %s" % [
|
||||
_campaign_label.text = Strings.fmt("review.campaign_next", [
|
||||
int(campaign_summary.get("shift_number", 1)) - 1,
|
||||
next_venue.replace("_", " ").capitalize()]
|
||||
next_venue.replace("_", " ").capitalize()])
|
||||
else:
|
||||
_campaign_label.text = ""
|
||||
if _continue_button:
|
||||
|
||||
+13
-14
@@ -14,9 +14,9 @@ const UiArt := preload("res://src/game/ui/art.gd")
|
||||
const Strings := preload("res://src/core/strings.gd")
|
||||
|
||||
const VENUES := [
|
||||
{"id": "hollywood_building", "label": "Hollywood Boulevard", "blurb": "Building entrance, tourists and late-night trouble."},
|
||||
{"id": "joke_shop", "label": "The Joke Shop", "blurb": "Guest list, IDs and wand screening."},
|
||||
{"id": "tv_studio", "label": "Late Night TV Studio", "blurb": "Credentials, filming boundary, celebrity arrivals."},
|
||||
{"id": "hollywood_building", "label_key": "venue.hollywood.label", "blurb_key": "venue.hollywood.blurb"},
|
||||
{"id": "joke_shop", "label_key": "venue.joke.label", "blurb_key": "venue.joke.blurb"},
|
||||
{"id": "tv_studio", "label_key": "venue.studio.label", "blurb_key": "venue.studio.blurb"},
|
||||
]
|
||||
|
||||
var _index := 0
|
||||
@@ -83,13 +83,13 @@ func _build() -> void:
|
||||
center.add_child(column)
|
||||
|
||||
var title := Label.new()
|
||||
title.text = "GIG LINE"
|
||||
title.text = Strings.lookup("ui.start_title")
|
||||
title.add_theme_font_size_override("font_size", 44)
|
||||
title.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
column.add_child(title)
|
||||
|
||||
var subtitle := Label.new()
|
||||
subtitle.text = "Pick a venue to start your shift."
|
||||
subtitle.text = Strings.lookup("ui.start_subtitle")
|
||||
subtitle.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
subtitle.add_theme_color_override("font_color", Color(0.72, 0.75, 0.82))
|
||||
column.add_child(subtitle)
|
||||
@@ -112,7 +112,7 @@ func _build() -> void:
|
||||
var venue: Dictionary = VENUES[i]
|
||||
var button := Button.new()
|
||||
button.name = "Venue_%s" % venue["id"]
|
||||
button.text = "%s\n%s" % [venue["label"], venue["blurb"]]
|
||||
button.text = "%s\n%s" % [Strings.lookup(str(venue["label_key"])), Strings.lookup(str(venue["blurb_key"]))]
|
||||
button.alignment = HORIZONTAL_ALIGNMENT_LEFT
|
||||
button.custom_minimum_size = Vector2(460, 62)
|
||||
button.pressed.connect(_on_venue_pressed.bind(i))
|
||||
@@ -131,13 +131,13 @@ func _build() -> void:
|
||||
|
||||
var help_button := Button.new()
|
||||
help_button.name = "HelpButton"
|
||||
help_button.text = "Help"
|
||||
help_button.text = Strings.lookup("ui.start_help")
|
||||
help_button.pressed.connect(func(): help_requested.emit())
|
||||
row.add_child(help_button)
|
||||
|
||||
var settings_button := Button.new()
|
||||
settings_button.name = "SettingsButton"
|
||||
settings_button.text = "Settings"
|
||||
settings_button.text = Strings.lookup("ui.start_settings")
|
||||
settings_button.pressed.connect(func(): settings_requested.emit())
|
||||
row.add_child(settings_button)
|
||||
|
||||
@@ -148,7 +148,7 @@ func _build() -> void:
|
||||
row.add_child(quit_button)
|
||||
|
||||
var hint := Label.new()
|
||||
hint.text = "Up/Down to choose, Enter to start, Esc to quit"
|
||||
hint.text = Strings.lookup("ui.start_hint")
|
||||
hint.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
hint.add_theme_color_override("font_color", Color(0.55, 0.58, 0.65))
|
||||
column.add_child(hint)
|
||||
@@ -199,20 +199,19 @@ func open(campaign: Dictionary = {}) -> void:
|
||||
var complete := bool(_campaign.get("complete", false))
|
||||
if _status:
|
||||
if complete:
|
||||
_status.text = "Campaign complete — pick any venue for a free shift."
|
||||
_status.text = Strings.lookup("ui.campaign_complete")
|
||||
elif next_id != "":
|
||||
_status.text = "Campaign shift %d · next: %s" % [
|
||||
int(_campaign.get("shift_number", 1)), _venue_label(next_id)]
|
||||
_status.text = Strings.fmt("ui.campaign_status", [int(_campaign.get("shift_number", 1)), _venue_label(next_id)])
|
||||
if _continue_button:
|
||||
var next_label := _venue_label(next_id)
|
||||
_continue_button.text = "Continue shift — %s" % next_label if next_id != "" else "Campaign complete"
|
||||
_continue_button.text = Strings.fmt("ui.continue_shift", [next_label]) if next_id != "" else Strings.lookup("ui.campaign_complete_short")
|
||||
_continue_button.visible = not complete
|
||||
_focus_index(_index)
|
||||
|
||||
func _venue_label(id: String) -> String:
|
||||
for venue in VENUES:
|
||||
if str(venue["id"]) == id:
|
||||
return str(venue["label"])
|
||||
return Strings.lookup(str(venue["label_key"]))
|
||||
return id.replace("_", " ").capitalize()
|
||||
|
||||
func _on_continue_pressed() -> void:
|
||||
|
||||
Reference in new issue
Block a user