135 lines
5.9 KiB
GDScript3
135 lines
5.9 KiB
GDScript3
|
|
extends SceneTree
|
||
|
|
|
||
|
|
# Forgejo #224: a structure may not be built on top of one that is already
|
||
|
|
# there.
|
||
|
|
#
|
||
|
|
# It matters beyond the look of it. BuildingField decides which structure the
|
||
|
|
# fleet is standing on by testing the centroid against interact_radius and
|
||
|
|
# returning the FIRST match, so two structures inside one another make that a
|
||
|
|
# question of list order rather than of where the player flew - you would fly
|
||
|
|
# to your workshop and open the crafter.
|
||
|
|
#
|
||
|
|
# Covers:
|
||
|
|
# A. the spot a structure already occupies is refused
|
||
|
|
# B. clear of it, the same build goes through
|
||
|
|
# C. a unique structure can still be rebuilt where the old one stands,
|
||
|
|
# because the old one is what is being replaced
|
||
|
|
# D. and a REFUSED rebuild does not demolish the existing one first
|
||
|
|
|
||
|
|
var game_state: Node
|
||
|
|
var scene: Node
|
||
|
|
var controller: Node
|
||
|
|
var fleet: Node2D
|
||
|
|
var elapsed: float = 0.0
|
||
|
|
var stage: int = 0
|
||
|
|
|
||
|
|
|
||
|
|
func _initialize() -> void:
|
||
|
|
game_state = root.get_node("GameState")
|
||
|
|
game_state.buildings.clear()
|
||
|
|
game_state.extractors.clear()
|
||
|
|
game_state.reset_progression()
|
||
|
|
game_state.reset_new_game()
|
||
|
|
game_state.intro_active = false
|
||
|
|
game_state.reset_quests()
|
||
|
|
game_state.rocks = 100000
|
||
|
|
game_state.bank_inventory.set_amount(GameState.RESOURCE_GAS, 100000)
|
||
|
|
game_state.bank_inventory.set_amount(GameState.RESOURCE_ENERGY, 100000)
|
||
|
|
scene = load("res://world/Main.tscn").instantiate()
|
||
|
|
root.add_child(scene)
|
||
|
|
current_scene = scene
|
||
|
|
controller = scene.get_node("BuildController")
|
||
|
|
fleet = scene.get_node("Fleet")
|
||
|
|
|
||
|
|
|
||
|
|
func _process(delta: float) -> bool:
|
||
|
|
elapsed += delta
|
||
|
|
if elapsed < 0.4:
|
||
|
|
return false
|
||
|
|
|
||
|
|
var sep: float = GameState.MIN_BUILDING_SEPARATION
|
||
|
|
|
||
|
|
# _confirm_build() returns SILENTLY on a locked structure, which would
|
||
|
|
# make every refusal below look like the separation rule working when it
|
||
|
|
# was only the unlock gate. Unlock what this test builds, and assert it.
|
||
|
|
for type in [GameState.BUILDING_COMMAND_CENTER, GameState.BUILDING_MOTHERSHIP,
|
||
|
|
GameState.BUILDING_SHIP_CRAFTER]:
|
||
|
|
var node_id: String = game_state.research_node_for_building(type)
|
||
|
|
if node_id != "" and not game_state.is_unlocked(node_id):
|
||
|
|
game_state.unlocked.append(node_id)
|
||
|
|
if not game_state.is_building_unlocked(type):
|
||
|
|
return _fail("'%s' is still locked, so a refusal would prove nothing" % type)
|
||
|
|
|
||
|
|
# --- A. the occupied spot is refused --------------------------------
|
||
|
|
game_state.buildings.clear()
|
||
|
|
game_state.add_building(GameState.BUILDING_SHIP_CRAFTER, Vector2.ZERO)
|
||
|
|
|
||
|
|
if game_state.building_blocking(Vector2.ZERO).is_empty():
|
||
|
|
return _fail("a structure's own position reads as a clear spot")
|
||
|
|
# Just inside the separation, and just outside it.
|
||
|
|
if game_state.building_blocking(Vector2(sep - 1.0, 0.0)).is_empty():
|
||
|
|
return _fail("a spot %.0f units away is not blocked, but the rule is %.0f" % [sep - 1.0, sep])
|
||
|
|
if not game_state.building_blocking(Vector2(sep + 1.0, 0.0)).is_empty():
|
||
|
|
return _fail("a spot %.0f units away is blocked, but the rule is %.0f" % [sep + 1.0, sep])
|
||
|
|
var blocker: Dictionary = game_state.building_blocking(Vector2.ZERO)
|
||
|
|
if String(blocker.get("type", "")) != GameState.BUILDING_SHIP_CRAFTER:
|
||
|
|
return _fail("the blocking structure is reported as '%s'" % blocker.get("type", ""))
|
||
|
|
print("a spot inside %.0f units of a structure is refused, outside it is clear" % sep)
|
||
|
|
|
||
|
|
# --- B. and the whole build path agrees -----------------------------
|
||
|
|
# On top of the crafter: refused, and nothing is built or spent.
|
||
|
|
fleet.teleport_to(Vector2.ZERO)
|
||
|
|
var before: int = game_state.buildings.size()
|
||
|
|
controller.pending_build_type = GameState.BUILDING_COMMAND_CENTER
|
||
|
|
controller._confirm_build()
|
||
|
|
if game_state.buildings.size() != before:
|
||
|
|
return _fail("a structure was built on top of the crafter")
|
||
|
|
print("the build path refuses it too: %s" % controller.build_menu.status.text)
|
||
|
|
|
||
|
|
# Clear of it: the same build goes through.
|
||
|
|
fleet.teleport_to(Vector2(sep * 3.0, 0.0))
|
||
|
|
controller.pending_build_type = GameState.BUILDING_COMMAND_CENTER
|
||
|
|
controller._confirm_build()
|
||
|
|
if game_state.buildings.size() != before + 1:
|
||
|
|
return _fail("the same build was refused on a clear spot")
|
||
|
|
print("clear of it, the same build goes through")
|
||
|
|
|
||
|
|
# --- C. a unique structure replaces itself in place -----------------
|
||
|
|
game_state.buildings.clear()
|
||
|
|
game_state.add_building(GameState.BUILDING_MOTHERSHIP, Vector2.ZERO)
|
||
|
|
fleet.teleport_to(Vector2.ZERO)
|
||
|
|
if not game_state.building_blocking(Vector2.ZERO, GameState.BUILDING_MOTHERSHIP).is_empty():
|
||
|
|
return _fail("a unique structure blocks its own replacement")
|
||
|
|
controller.pending_build_type = GameState.BUILDING_MOTHERSHIP
|
||
|
|
controller._confirm_build()
|
||
|
|
if game_state.buildings.size() != 1:
|
||
|
|
return _fail("rebuilding the mothership in place left %d structures" % game_state.buildings.size())
|
||
|
|
if String(game_state.buildings[0].type) != GameState.BUILDING_MOTHERSHIP:
|
||
|
|
return _fail("the rebuilt structure is not a mothership")
|
||
|
|
print("a unique structure can still be rebuilt where the old one stood")
|
||
|
|
|
||
|
|
# --- D. a refused rebuild demolishes nothing ------------------------
|
||
|
|
# The mothership is unique and is removed before the new one is placed.
|
||
|
|
# Something ELSE in the way has to be caught before that demolition, or
|
||
|
|
# the player is left with neither.
|
||
|
|
game_state.buildings.clear()
|
||
|
|
var keep: int = game_state.add_building(GameState.BUILDING_MOTHERSHIP, Vector2.ZERO)
|
||
|
|
game_state.add_building(GameState.BUILDING_SHIP_CRAFTER, Vector2(sep * 4.0, 0.0))
|
||
|
|
fleet.teleport_to(Vector2(sep * 4.0, 0.0))
|
||
|
|
controller.pending_build_type = GameState.BUILDING_MOTHERSHIP
|
||
|
|
controller._confirm_build()
|
||
|
|
if game_state.find_building(keep).is_empty():
|
||
|
|
return _fail("a refused rebuild demolished the existing mothership - the player is left with neither")
|
||
|
|
if game_state.buildings.size() != 2:
|
||
|
|
return _fail("a refused rebuild changed the structure count to %d" % game_state.buildings.size())
|
||
|
|
print("a refused rebuild leaves the existing structure standing")
|
||
|
|
|
||
|
|
print("TEST_BUILDING_SEPARATION: PASS")
|
||
|
|
quit(0)
|
||
|
|
return true
|
||
|
|
|
||
|
|
|
||
|
|
func _fail(message: String) -> bool:
|
||
|
|
print("TEST_BUILDING_SEPARATION: FAIL (%s)" % message)
|
||
|
|
quit(1)
|
||
|
|
return true
|