Add a free-costs sandbox tool

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019AJMdB7iuHuLFZM1aBu3GD
This commit is contained in:
Loïc Wisniewski 2026-09-04 22:34:36 +02:00
commit 571f01dc31
5 changed files with 136 additions and 18 deletions

View file

@ -190,11 +190,17 @@ var research_points: int = 0
# place to set it - assigning dev_mode anywhere, tests included, reaches
# world generation.
var dev_unlimited_resources: bool = false
# #202: every research and production price answers zero while this is on.
# A separate switch from the one above rather than a stronger version of it -
# unlimited resources tests whether a price can be PAID, and this tests what
# happens when there is no price at all, which is a different play-test.
var dev_free_costs: bool = false
var dev_mode: bool = false:
set(value):
dev_mode = value
if not value:
dev_unlimited_resources = false
dev_free_costs = false
WORLD_GEN.dev_planets_enabled = value
# Explored-chunk history for the world map's fog-of-war reveal. Lives
@ -676,7 +682,7 @@ func prerequisite_met(id: String) -> bool:
# ever compared two nodes by price - keeps working on a plain number.
func skill_costs(id: String) -> Dictionary:
var node: Dictionary = skill_node(id)
if node.is_empty():
if node.is_empty() or costs_are_free():
return {}
var costs: Dictionary = node.get("costs", {})
if not costs.is_empty():
@ -692,7 +698,7 @@ func can_unlock(id: String, payment_position: Variant = null) -> bool:
func skill_research_point_cost(id: String) -> int:
return int(skill_node(id).get("research_points", 0))
return 0 if costs_are_free() else int(skill_node(id).get("research_points", 0))
func unlock(id: String, payment_position: Variant = null) -> bool:
@ -792,6 +798,7 @@ func reset_new_game() -> void:
boost_depleted_notice = false
research_points = 0
dev_unlimited_resources = false
dev_free_costs = false
dev_mode = false
explored_chunks.clear()
scanner_target.clear()
@ -954,6 +961,21 @@ func set_dev_unlimited_resources(enabled: bool) -> bool:
return true
func set_dev_free_costs(enabled: bool) -> bool:
if enabled and not dev_mode:
return false
dev_free_costs = enabled
return true
# Asked by every price below, and by the menus that display them. The dev_mode
# term is not redundant: the setter refuses outside a dev game and the dev_mode
# setter clears the flag, so this is the third guard rather than the first, and
# it is the one that holds if a save or a test sets the field directly.
func costs_are_free() -> bool:
return dev_mode and dev_free_costs
func _refill_dev_resources() -> void:
for resource_type in resource_types():
if bank_inventory.amount(resource_type) < DEV_UNLIMITED_AMOUNT:
@ -1052,7 +1074,7 @@ func find_building(id: int) -> Dictionary:
# there is one question with one answer whatever is being bought.
func building_costs(type: String) -> Dictionary:
var definition: Resource = building_definition(type)
if definition == null:
if definition == null or costs_are_free():
return {}
if not definition.build_resource_costs.is_empty():
return definition.build_resource_costs.duplicate()
@ -1494,7 +1516,10 @@ func unlock_vessel(vessel: String, payment_position: Variant = null) -> bool:
if definition == null or definition.unlock_id == "" or vessel_is_unlocked(vessel) or not has_ship_lab():
return false
var costs: Dictionary = research_costs(definition.unlock_id)
var points_needed: int = int(definition.research_point_cost)
# Through the accessor, not off the definition: this used to be the one
# place a research price was read straight from its file, which #202's
# free-costs switch would have left charging full price here alone.
var points_needed: int = research_point_cost(definition.unlock_id)
if research_points < points_needed or not spend_resources(costs, payment_position):
return false
if points_needed > 0:
@ -1540,7 +1565,7 @@ func upgrade_maxed(id: String) -> bool:
func upgrade_cost(id: String) -> int:
var d: Dictionary = upgrade_def(id)
if d.is_empty():
if d.is_empty() or costs_are_free():
return 0
return int(d.cost) * (upgrade_level(id) + 1)
@ -1631,7 +1656,7 @@ func product_cost(product: String) -> int:
func product_costs(product: String) -> Dictionary:
var definition: Resource = vessel_definition(product)
if definition == null:
if definition == null or costs_are_free():
return {}
if not definition.build_resource_costs.is_empty():
return definition.build_resource_costs.duplicate()
@ -2332,6 +2357,8 @@ func research_cost(id: String) -> int:
func research_point_cost(id: String) -> int:
if costs_are_free():
return 0
var unlock_definition: Resource = vessel_for_unlock(id)
if unlock_definition != null:
return int(unlock_definition.research_point_cost)
@ -2340,6 +2367,8 @@ func research_point_cost(id: String) -> int:
func research_costs(id: String) -> Dictionary:
if costs_are_free():
return {}
var unlock_definition: Resource = vessel_for_unlock(id)
if unlock_definition != null:
if not unlock_definition.unlock_resource_costs.is_empty():