extends SceneTree # Forgejo #216, the workshop half. A spacial workshop used to conjure its own # repair drones, free and permanent. They are built at a ship crafter now, # flown out from the mothership hangar to whichever workshop asked for them, # and spent by the repairs they make. # # test_transporter_supply.gd covers the same rules on the hub side. The two # share a model but not their wear paths - a transporter spends a run getting # home, a drone spends a repair getting home - so the drone's own path is # exercised here rather than assumed from the transporter's. # # Covers: # A. a new workshop stands empty, and takes nothing until it is asked to # B. the crafter accepts a repair drone order, which it used to refuse # C. an assigned workshop is sent one from the hangar # D. it repairs a damaged structure and is worn by doing so # E. its last repair uses it up, and the workshop is short again var state: Node var workshop_id: int var damaged_id: int var elapsed: float = 0.0 var stage: int = 0 func _initialize() -> void: state = root.get_node("GameState") state.buildings.clear() state.extractors.clear() state.transporters.clear() state.repair_drones.clear() state.stored_vessels.clear() state.vessel_deliveries.clear() state.reset_progression() state.rocks = 600 state.unlocked = ["shipyards", "logistics"] state.add_building(state.BUILDING_MOTHERSHIP, Vector2.ZERO) workshop_id = state.add_building(GameState.BUILDING_WORKSHOP, Vector2(700.0, 0.0)) damaged_id = state.add_building(state.BUILDING_SHIP_CRAFTER, Vector2(900.0, 200.0)) state.deposit_resource_to_building(workshop_id, GameState.RESOURCE_ORE, 400) func _drones() -> int: return state.station_crew(workshop_id) func _process(delta: float) -> bool: elapsed += delta match stage: 0: # --- A. nothing comes with the structure --------------------- if not state.repair_drones.is_empty(): return _fail("a new workshop arrived with %d drones" % state.repair_drones.size()) state.stored_vessels.append(GameState.REPAIR_DRONE) state._advance_station_dispatch() if _drones() != 0: return _fail("a workshop that asked for nothing took a drone anyway") print("a new workshop stands empty, and takes nothing unasked") # --- B. the crafter takes the order -------------------------- var crafter_id: int = state.add_building(state.BUILDING_SHIP_CRAFTER, Vector2(-900.0, 0.0)) if not state.queue_order(crafter_id, GameState.REPAIR_DRONE): return _fail("the crafter refused a repair drone order") state.find_building(crafter_id).orders.clear() # --- C. assigned, then sent ---------------------------------- if state.set_station_desired(workshop_id, 1) != 1: return _fail("the workshop refused an order for one drone") state._advance_station_dispatch() if state.vessel_deliveries.is_empty(): return _fail("nothing was sent to the workshop") elapsed = 0.0 stage = 1 return false 1: if _drones() < 1: if elapsed > 25.0: return _fail("the drone never reached the workshop") return false var fresh: Array = state.station_condition(workshop_id) if fresh.size() != 1 or int(fresh[0]) != GameState.DRONE_REPAIRS: return _fail("the arrived drone reports %s, expected [%d]" \ % [fresh, GameState.DRONE_REPAIRS]) print("ordered and flown out: 1 drone with %d repairs in it" % GameState.DRONE_REPAIRS) # --- D. it does the work, and is worn by it ------------------ state.damage_building(damaged_id, state.building_max_hp(state.BUILDING_SHIP_CRAFTER) / 2) elapsed = 0.0 stage = 2 return false 2: if state.building_health_fraction(damaged_id) >= 0.999: print("the workshop's own drone repaired the structure") elapsed = 0.0 stage = 3 return false if elapsed > 40.0: return _fail("the drone never repaired the damaged structure") return false 3: # Spent on getting HOME, so this waits for it to be idle again. if state.repair_drones.is_empty(): return _fail("the drone vanished mid-run") if String(state.repair_drones[0].state) != GameState.DRONE_IDLE: if elapsed > 25.0: return _fail("the drone never got home") return false var worn: Array = state.station_condition(workshop_id) if worn.is_empty() or int(worn[0]) >= GameState.DRONE_REPAIRS: return _fail("a drone that ran a repair is still unworn (%s)" % [worn]) print("a completed repair wore it to %d" % int(worn[0])) # --- E. and its last one uses it up -------------------------- state.repair_drones[0].repairs_left = 1 state.damage_building(damaged_id, state.building_max_hp(state.BUILDING_SHIP_CRAFTER) / 2) elapsed = 0.0 stage = 4 return false 4: if not state.repair_drones.is_empty(): if elapsed > 40.0: return _fail("a drone on its last repair was never retired") return false if state.stored_vessels.has(GameState.REPAIR_DRONE): return _fail("a spent drone went back to the hangar instead of being used up") if _drones() != 0: return _fail("the workshop still counts a retired drone") print("spent after its last repair: gone, and the workshop is short again") print("TEST_WORKSHOP_STAFFING: PASS") quit(0) return true return false func _fail(message: String) -> bool: print("TEST_WORKSHOP_STAFFING: FAIL (%s)" % message) quit(1) return true