Add research lab planets and research points (#63)
This commit is contained in:
parent
651f8b787e
commit
3f3a22227d
43 changed files with 459 additions and 30 deletions
143
tests/test_research_points.gd
Normal file
143
tests/test_research_points.gd
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
extends SceneTree
|
||||
|
||||
# Headless gameplay test: run with
|
||||
# godot --headless -s res://tests/test_research_points.gd
|
||||
# Forgejo #63: a rare enemy planet type that yields no resources but grants
|
||||
# one research point when conquered - a required currency for mid/late
|
||||
# skill-tree nodes and vessel/lab research, gated alongside their existing
|
||||
# ore/resource costs.
|
||||
#
|
||||
# Covers:
|
||||
# A. research labs generate deterministically and are rare
|
||||
# (structural) the definition yields no resources and its surface has no
|
||||
# resource provider at all
|
||||
# F. a fresh game can still reach a ship crafter and an extractor with
|
||||
# zero research points
|
||||
# D. a research-point-gated skill node is refused while unaffordable, and
|
||||
# explains why
|
||||
# E. conquering a research_lab awards exactly one point, once (guarded
|
||||
# even against a redundant re-mark), emits the signal once, and a
|
||||
# non-research_lab planet's conquest never awards one
|
||||
# D continued: unlocking spends the points and the balance updates
|
||||
# G. the ship-lab research path gates and spends research points the
|
||||
# same way, independent of the skill tree
|
||||
|
||||
var game_state: Node
|
||||
|
||||
|
||||
func _initialize() -> void:
|
||||
game_state = root.get_node("GameState")
|
||||
|
||||
# --- A. deterministic and rare -------------------------------------------
|
||||
var lab_count: int = 0
|
||||
var total_planets: int = 0
|
||||
for x in range(-40, 40):
|
||||
for y in range(-40, 40):
|
||||
var chunk: Vector2i = Vector2i(x, y)
|
||||
if not WorldGen.has_planet_at_chunk(chunk):
|
||||
continue
|
||||
total_planets += 1
|
||||
var first: Dictionary = WorldGen.planet_data_at_chunk(chunk)
|
||||
var second: Dictionary = WorldGen.planet_data_at_chunk(chunk)
|
||||
if first.definition_id != second.definition_id or first.local_pos != second.local_pos:
|
||||
return _fail("planet_data_at_chunk(%s) is not deterministic" % chunk)
|
||||
if first.definition_id == "research_lab":
|
||||
lab_count += 1
|
||||
print("scanned %d planet chunks: %d research labs" % [total_planets, lab_count])
|
||||
if lab_count == 0:
|
||||
return _fail("no research labs generated across a wide scan - the rare outcome never fires")
|
||||
if lab_count * 3 >= total_planets:
|
||||
return _fail("research labs (%d of %d) are not rare" % [lab_count, total_planets])
|
||||
print("research labs are deterministic and rare (%d of %d planet chunks)" % [lab_count, total_planets])
|
||||
|
||||
# --- structural: yields nothing at all ------------------------------------
|
||||
var lab_def: Resource = load("res://PlanetDefinitions.gd").get_definition("research_lab")
|
||||
if String(lab_def.resource_id) != "":
|
||||
return _fail("research_lab planet's resource_id is '%s', expected empty" % lab_def.resource_id)
|
||||
var profile: Resource = load("res://PlanetSurfaceProfiles.gd").get_profile("research_lab")
|
||||
if profile.features_scene != null:
|
||||
return _fail("research_lab surface profile has a features_scene - it must yield nothing")
|
||||
print("research_lab yields no resource id and no surface feature provider")
|
||||
|
||||
# --- F. a fresh game still reaches a crafter and an extractor -------------
|
||||
game_state.reset_new_game()
|
||||
if not game_state.can_unlock("shipyards"):
|
||||
return _fail("shipyards is not reachable with 0 research points")
|
||||
game_state.unlock("shipyards")
|
||||
if not game_state.can_unlock("logistics"):
|
||||
return _fail("logistics is not reachable with 0 research points after shipyards")
|
||||
game_state.unlock("logistics")
|
||||
print("fresh game reaches a ship crafter (shipyards) and an extractor (logistics) at 0 research points")
|
||||
|
||||
# --- D. a points-gated node is refused and explains why -------------------
|
||||
if game_state.can_unlock("coordination"):
|
||||
return _fail("coordination (costs research points) was unlockable with 0 research points")
|
||||
print("a research-point-gated node (coordination) correctly refused at 0 points")
|
||||
|
||||
# --- E. earning exactly one point, once, with the signal ------------------
|
||||
var totals_seen: Array = []
|
||||
game_state.research_points_changed.connect(func(total): totals_seen.append(total))
|
||||
game_state.planet_capture.clear()
|
||||
game_state.register_capture_points("test_lab_planet", 2, "research_lab")
|
||||
if game_state.is_planet_conquered("test_lab_planet"):
|
||||
return _fail("a lab with 2 real capture points started conquered")
|
||||
game_state.mark_point_captured("test_lab_planet", 0)
|
||||
if game_state.research_points != 0:
|
||||
return _fail("a research point was awarded before every point was captured")
|
||||
game_state.mark_point_captured("test_lab_planet", 1)
|
||||
if game_state.research_points != 1:
|
||||
return _fail("conquering a research_lab did not award exactly 1 point: %d" % game_state.research_points)
|
||||
if totals_seen != [1]:
|
||||
return _fail("research_points_changed did not fire exactly once with the new total: %s" % [totals_seen])
|
||||
print("conquering a research_lab awarded exactly 1 point and fired the signal once")
|
||||
|
||||
game_state.mark_point_captured("test_lab_planet", 0) # already captured - redundant re-mark
|
||||
if game_state.research_points != 1:
|
||||
return _fail("re-marking an already-captured point re-awarded a research point: %d" % game_state.research_points)
|
||||
print("double-award guarded against")
|
||||
|
||||
game_state.register_capture_points("test_rocky_planet", 1, "rocky")
|
||||
game_state.mark_point_captured("test_rocky_planet", 0)
|
||||
if game_state.research_points != 1:
|
||||
return _fail("conquering a non-research_lab planet awarded a research point: %d" % game_state.research_points)
|
||||
print("a non-research_lab planet's conquest never awards a point")
|
||||
|
||||
# --- D continued: unlocking spends the points, balance updates ------------
|
||||
if not game_state.can_unlock("coordination"):
|
||||
return _fail("coordination is still not unlockable with 1 research point and enough ore")
|
||||
if not game_state.unlock("coordination"):
|
||||
return _fail("unlock(coordination) failed despite can_unlock() being true")
|
||||
if game_state.research_points != 0:
|
||||
return _fail("unlocking a 1-point node did not spend the point: %d remaining" % game_state.research_points)
|
||||
print("unlocking a research-point-gated skill node spent the point, balance now 0")
|
||||
|
||||
# --- G. the ship-lab research path gates and spends the same currency -----
|
||||
var carrier_def: Resource = game_state.vessel_definition(GameState.VESSEL_CARRIER)
|
||||
var point_cost: int = int(carrier_def.research_point_cost)
|
||||
if point_cost <= 0:
|
||||
return _fail("carrier production data has no research-point cost")
|
||||
game_state.vessel_levels.erase(carrier_def.unlock_id)
|
||||
var lab_id: int = game_state.add_building(GameState.BUILDING_SHIP_LAB, Vector2.ZERO)
|
||||
if not game_state.queue_lab_research(lab_id, carrier_def.unlock_id):
|
||||
return _fail("could not queue carrier research")
|
||||
game_state.deposit_resource_to_building(lab_id, GameState.RESOURCE_ORE, 1000)
|
||||
game_state._advance_lab_research(100.0)
|
||||
if game_state.vessel_is_unlocked(GameState.VESSEL_CARRIER):
|
||||
return _fail("carrier research completed despite 0 research points")
|
||||
print("lab research correctly stalled on a research-point shortfall")
|
||||
|
||||
game_state.research_points = point_cost
|
||||
game_state._advance_lab_research(100.0)
|
||||
if not game_state.vessel_is_unlocked(GameState.VESSEL_CARRIER):
|
||||
return _fail("carrier research did not complete once research points were available")
|
||||
if game_state.research_points != 0:
|
||||
return _fail("lab research did not spend the research points: %d remaining" % game_state.research_points)
|
||||
print("lab research spent the research points once affordable, and completed")
|
||||
|
||||
print("TEST_RESEARCH_POINTS: PASS")
|
||||
quit(0)
|
||||
|
||||
|
||||
func _fail(message: String) -> void:
|
||||
print("TEST_RESEARCH_POINTS: FAIL (%s)" % message)
|
||||
quit(1)
|
||||
Loading…
Reference in a new issue