From 3aa723d3861cf36aefde993f15ea09100014b11a Mon Sep 17 00:00:00 2001 From: Saffron <263493777+itsmiso-ai@users.noreply.github.com> Date: Wed, 8 Jul 2026 00:09:42 +0000 Subject: [PATCH] Expand WORKER_NAMES pool and add badge colors for all workers Expand WORKER_NAMES from 2 entries (Jun, Mara) to 10 entries (Jun, Mara, Kai, Lia, Ren, Sia, Nia, Tao, Yun, Zoe) to prevent name collisions when recruiting multiple workers. Add corresponding WORKER_BADGE_COLORS entries for each new name. Update tests to verify the expanded pool and add regression tests ensuring every worker name has a badge color entry and that recruited workers have unique names. Fixes #227 Signed-off-by: Saffron <263493777+itsmiso-ai@users.noreply.github.com> --- scripts/constants.gd | 10 ++++++- tests/test_constants.gd | 58 +++++++++++++++++++++++++++++++++--- tests/test_recruit_worker.gd | 27 +++++++++++++++-- 3 files changed, 87 insertions(+), 8 deletions(-) diff --git a/scripts/constants.gd b/scripts/constants.gd index 5246562..5bc0784 100644 --- a/scripts/constants.gd +++ b/scripts/constants.gd @@ -2,7 +2,7 @@ ## Extracted from scripts/main.gd to reduce its blast radius. ## All values are immutable const dictionaries/arrays — safe to preload anywhere. -const WORKER_NAMES := ["Jun", "Mara"] +const WORKER_NAMES := ["Jun", "Mara", "Kai", "Lia", "Ren", "Sia", "Nia", "Tao", "Yun", "Zoe"] const BASE_TICK_SECONDS := 0.9 const EVENT_INTERVAL_TICKS := 66 @@ -40,6 +40,14 @@ const TILE_BACKDROPS := { const WORKER_BADGE_COLORS := { "Jun": Color("#f58f6c"), "Mara": Color("#75c7ff"), + "Kai": Color("#a3e635"), + "Lia": Color("#f472b6"), + "Ren": Color("#facc15"), + "Sia": Color("#c084fc"), + "Nia": Color("#fb923c"), + "Tao": Color("#34d399"), + "Yun": Color("#60a5fa"), + "Zoe": Color("#f87171"), } const BUILD_COSTS := { diff --git a/tests/test_constants.gd b/tests/test_constants.gd index 70c8c1d..1b5a1df 100644 --- a/tests/test_constants.gd +++ b/tests/test_constants.gd @@ -15,9 +15,10 @@ func _initialize() -> void: var test_count := 0 # --- Worker names --- - test_count += 1; pass_count += test("WORKER_NAMES has exactly 2 entries", _test_worker_names_count) + test_count += 1; pass_count += test("WORKER_NAMES has exactly 10 entries", _test_worker_names_count) test_count += 1; pass_count += test("WORKER_NAMES[0] is Jun", _test_worker_names_first) test_count += 1; pass_count += test("WORKER_NAMES[1] is Mara", _test_worker_names_second) + test_count += 1; pass_count += test("WORKER_NAMES contains all expected names", _test_worker_names_all) # --- Timing constants --- test_count += 1; pass_count += test("BASE_TICK_SECONDS is 0.9", _test_base_tick_seconds) @@ -47,7 +48,8 @@ func _initialize() -> void: # --- Worker badge colors --- test_count += 1; pass_count += test("WORKER_BADGE_COLORS has Jun", _test_badge_color_jun) test_count += 1; pass_count += test("WORKER_BADGE_COLORS has Mara", _test_badge_color_mara) - test_count += 1; pass_count += test("WORKER_BADGE_COLORS has exactly 2 entries", _test_badge_color_count) + test_count += 1; pass_count += test("WORKER_BADGE_COLORS has exactly 10 entries", _test_badge_color_count) + test_count += 1; pass_count += test("Every WORKER_NAMES entry has a badge color", _test_badge_colors_complete) # --- Build costs --- test_count += 1; pass_count += test("BUILD_COSTS hut: 6 wood, 2 stone", _test_build_cost_hut) @@ -106,120 +108,168 @@ func test(name: String, fn: Callable) -> int: # --- Individual tests --- func _test_worker_names_count() -> bool: - return C.WORKER_NAMES.size() == 2 + return C.WORKER_NAMES.size() == 10 + func _test_worker_names_first() -> bool: return C.WORKER_NAMES[0] == "Jun" + func _test_worker_names_second() -> bool: return C.WORKER_NAMES[1] == "Mara" + +func _test_worker_names_all() -> bool: + var expected := ["Jun", "Mara", "Kai", "Lia", "Ren", "Sia", "Nia", "Tao", "Yun", "Zoe"] + return C.WORKER_NAMES == expected + + func _test_base_tick_seconds() -> bool: return is_equal_approx(C.BASE_TICK_SECONDS, 0.9) + func _test_event_interval_ticks() -> bool: return C.EVENT_INTERVAL_TICKS == 66 + func _test_resource_color_wood() -> bool: return C.RESOURCE_COLORS.has("wood") + func _test_resource_color_stone() -> bool: return C.RESOURCE_COLORS.has("stone") + func _test_resource_color_food() -> bool: return C.RESOURCE_COLORS.has("food") + func _test_resource_color_count() -> bool: return C.RESOURCE_COLORS.size() == 3 + func _test_structure_color_hut() -> bool: return C.STRUCTURE_COLORS.has("hut") + func _test_structure_color_workshop() -> bool: return C.STRUCTURE_COLORS.has("workshop") + func _test_structure_color_garden() -> bool: return C.STRUCTURE_COLORS.has("garden") + func _test_structure_color_count() -> bool: return C.STRUCTURE_COLORS.size() == 3 + func _test_tile_backdrop_ground() -> bool: return C.TILE_BACKDROPS.has("ground") + func _test_tile_backdrop_tree() -> bool: return C.TILE_BACKDROPS.has("tree") + func _test_tile_backdrop_rock() -> bool: return C.TILE_BACKDROPS.has("rock") + func _test_tile_backdrop_berries() -> bool: return C.TILE_BACKDROPS.has("berries") + func _test_tile_backdrop_foundation() -> bool: return C.TILE_BACKDROPS.has("foundation") + func _test_tile_backdrop_stockpile() -> bool: return C.TILE_BACKDROPS.has("stockpile") + func _test_tile_backdrop_count() -> bool: return C.TILE_BACKDROPS.size() == 9 + func _test_badge_color_jun() -> bool: return C.WORKER_BADGE_COLORS.has("Jun") + func _test_badge_color_mara() -> bool: return C.WORKER_BADGE_COLORS.has("Mara") + func _test_badge_color_count() -> bool: - return C.WORKER_BADGE_COLORS.size() == 2 + return C.WORKER_BADGE_COLORS.size() == 10 + + +func _test_badge_colors_complete() -> bool: + for name in C.WORKER_NAMES: + if not C.WORKER_BADGE_COLORS.has(name): + return false + return true + func _test_build_cost_hut() -> bool: var c = C.BUILD_COSTS.get("hut", {}) return c.get("wood", -1) == 6 and c.get("stone", -1) == 2 + func _test_build_cost_workshop() -> bool: var c = C.BUILD_COSTS.get("workshop", {}) return c.get("wood", -1) == 4 and c.get("stone", -1) == 6 + func _test_build_cost_garden() -> bool: var c = C.BUILD_COSTS.get("garden", {}) return c.get("wood", -1) == 3 and c.get("stone", -1) == 1 + func _test_build_cost_count() -> bool: return C.BUILD_COSTS.size() == 3 + func _test_build_effect_hut() -> bool: return String(C.BUILD_EFFECTS.get("hut", "")).find("Housing") >= 0 + func _test_build_effect_workshop() -> bool: var effect := String(C.BUILD_EFFECTS.get("workshop", "")) return effect.find("build speed") >= 0 and effect.find("garden") >= 0 + func _test_build_effect_garden() -> bool: return String(C.BUILD_EFFECTS.get("garden", "")).find("food") >= 0 + func _test_build_effect_count() -> bool: return C.BUILD_EFFECTS.size() == 3 + func _test_unlock_hut() -> bool: return C.BUILD_UNLOCKS.get("hut") == true + func _test_unlock_workshop() -> bool: return C.BUILD_UNLOCKS.get("workshop") == "hut" + func _test_unlock_garden() -> bool: return C.BUILD_UNLOCKS.get("garden") == "workshop" + func _test_unlock_count() -> bool: return C.BUILD_UNLOCKS.size() == 3 + func _test_build_costs_complete() -> bool: for kind in C.BUILD_COSTS.keys(): if not C.BUILD_COSTS[kind].has("wood") or not C.BUILD_COSTS[kind].has("stone"): return false return true + func _test_build_effects_complete() -> bool: for kind in C.BUILD_COSTS.keys(): if not C.BUILD_EFFECTS.has(kind) or String(C.BUILD_EFFECTS[kind]).is_empty(): diff --git a/tests/test_recruit_worker.gd b/tests/test_recruit_worker.gd index 6a53424..46d455c 100644 --- a/tests/test_recruit_worker.gd +++ b/tests/test_recruit_worker.gd @@ -15,6 +15,7 @@ func _initialize() -> void: test_cannot_recruit_at_cap(main) test_recruit_adds_worker_to_state(main) test_recruit_cycles_through_names(main) + test_recruit_unique_names(main) test_recruit_with_no_workers_returns_true(main) test_food_impact_messaging_for_extra_workers(main) test_food_impact_no_upkeep_when_under_threshold(main) @@ -99,12 +100,32 @@ func test_recruit_cycles_through_names(main: Control) -> void: main.recruit_worker() _assert_eq(main.state.workers[1].name, "Mara", "second recruit gets second name 'Mara'") - # Third recruit should wrap to index 0 again ("Jun") + # Third recruit should pick index 2 ("Kai") main.recruit_worker() - _assert_eq(main.state.workers[2].name, "Jun", "third recruit wraps to first name 'Jun'") + _assert_eq(main.state.workers[2].name, "Kai", "third recruit gets third name 'Kai'") -# ── Test 5: can_recruit returns true when no workers exist yet ── +# ── Test 5: unique names across all workers ── +func test_recruit_unique_names(main: Control) -\u003e void: + print("") + print("--- unique worker names ---") + var builds = [ + {"id": 1, "kind": "hut", "pos": {"x": 2, "y": 2}, "complete": true, "delivered": {"wood": 6, "stone": 2}, "progress": 1.0}, + ] + _setup_state(main, builds, []) + # Cap is 4 (base 2 + hut bonus 2), recruit all 4 workers + for i in range(4): + main.recruit_worker() + var names: Array[String] = [] + for w in main.state.workers: + names.append(w.name) + var unique_names := names.duplicate() + unique_names.sort() + unique_names.erase_dups() + _assert_eq(unique_names.size(), names.size(), "all recruited workers have unique names") + + +# ── Test 6: can_recruit returns true when no workers exist yet ── func test_recruit_with_no_workers_returns_true(main: Control) -> void: print("") print("--- recruit with no workers ---")