Add planet scanner and octopus biome
This commit is contained in:
parent
2ecd61de98
commit
8fbcc340ce
21 changed files with 784 additions and 30 deletions
|
|
@ -203,6 +203,13 @@ var dev_mode: bool = false:
|
|||
# player lands on and leaves a planet.
|
||||
var explored_chunks: Dictionary = {}
|
||||
|
||||
# The four ordinary destinations teach the scanner enough signatures to
|
||||
# identify the hostile boss world. Kept explicit so adding a sixth authored
|
||||
# planet later cannot silently move the progression gate.
|
||||
const SCANNER_SURVEY_TYPES: PackedStringArray = [PLANET_DEFINITIONS.ROCKY_ID,
|
||||
PLANET_DEFINITIONS.GAS_GIANT_ID, PLANET_DEFINITIONS.BLACK_HOLE_ID,
|
||||
PLANET_DEFINITIONS.RESEARCH_LAB_ID]
|
||||
|
||||
# --- Resources -------------------------------------------------------------
|
||||
|
||||
const RESOURCE_ORE: String = RESOURCE_DEFINITIONS.ORE_ID
|
||||
|
|
@ -430,6 +437,9 @@ const BUILDING_SHIP_LAB: String = "ship_lab"
|
|||
# Converts gas into energy, both stored/moved through the building's own
|
||||
# inventory exactly like every other building (#54).
|
||||
const BUILDING_GAS_BURNER: String = "gas_burner"
|
||||
# A map-revealing structure, not a passive sensor bonus. Its menu searches
|
||||
# the same deterministic WorldGen catalogue that PlanetField spawns from.
|
||||
const BUILDING_PLANET_SCANNER: String = "planet_scanner"
|
||||
|
||||
|
||||
var buildings: Array = []
|
||||
|
|
@ -532,6 +542,13 @@ const SKILL_TREE: Array = [
|
|||
"x": 0.82, "unlocks": BUILDING_SHIP_LAB, "research_points": 1,
|
||||
"desc": "Build ship labs, where each vessel type is upgraded and new ones unlocked.",
|
||||
},
|
||||
{
|
||||
"id": "deep_space_scanning", "name": "Deep-Space Scanning", "cost": 50,
|
||||
"costs": {"ore": 50, "gas": 15},
|
||||
"requires": "coordination", "x": 0.34,
|
||||
"unlocks": BUILDING_PLANET_SCANNER, "research_points": 1,
|
||||
"desc": "Build a planet scanner and reveal the nearest world of a chosen type.",
|
||||
},
|
||||
{
|
||||
"id": "freight_yards", "name": "Freight Yards", "cost": 80, "requires": "freight",
|
||||
"costs": {"ore": 80, "gas": 30},
|
||||
|
|
@ -791,6 +808,70 @@ func reset_new_game() -> void:
|
|||
reset_formation()
|
||||
|
||||
|
||||
func scanner_can_find_boss() -> bool:
|
||||
for definition_id in SCANNER_SURVEY_TYPES:
|
||||
if not visited_planet_kinds.has(definition_id):
|
||||
return false
|
||||
return true
|
||||
|
||||
|
||||
func scanner_available_planet_types() -> PackedStringArray:
|
||||
var available: PackedStringArray = SCANNER_SURVEY_TYPES.duplicate()
|
||||
if scanner_can_find_boss():
|
||||
available.append(PLANET_DEFINITIONS.BOSS_ID)
|
||||
return available
|
||||
|
||||
|
||||
# Finds the nearest generated planet of this type, reveals its neighbourhood
|
||||
# on the persistent map, and returns the same identity PlanetField will spawn.
|
||||
# The search is ring-shaped, so the first hit is nearest in chunk distance and
|
||||
# results do not depend on dictionary iteration order.
|
||||
func scan_for_planet(definition_id: String, origin_world_position: Vector2) -> Dictionary:
|
||||
if not structure_exists(BUILDING_PLANET_SCANNER) \
|
||||
or definition_id not in scanner_available_planet_types():
|
||||
return {}
|
||||
var origin: Vector2i = WORLD_GEN.chunk_coords(origin_world_position)
|
||||
for radius in range(0, 257):
|
||||
if radius == 0:
|
||||
var center_match: Dictionary = _scanner_match_at(origin,
|
||||
definition_id, radius)
|
||||
if not center_match.is_empty():
|
||||
return center_match
|
||||
continue
|
||||
# Only the perimeter is new at each radius. The old square-with-a-
|
||||
# condition loop revisited every inner chunk for every radius, turning
|
||||
# a wide scan cubic precisely when the phone had the most work to do.
|
||||
for x in range(-radius, radius + 1):
|
||||
for y in [-radius, radius]:
|
||||
var horizontal: Dictionary = _scanner_match_at(
|
||||
origin + Vector2i(x, y), definition_id, radius)
|
||||
if not horizontal.is_empty():
|
||||
return horizontal
|
||||
for y in range(-radius + 1, radius):
|
||||
for x in [-radius, radius]:
|
||||
var vertical: Dictionary = _scanner_match_at(
|
||||
origin + Vector2i(x, y), definition_id, radius)
|
||||
if not vertical.is_empty():
|
||||
return vertical
|
||||
return {}
|
||||
|
||||
|
||||
func _scanner_match_at(chunk: Vector2i, definition_id: String,
|
||||
distance_chunks: int) -> Dictionary:
|
||||
if not WORLD_GEN.has_planet_at_chunk(chunk):
|
||||
return {}
|
||||
var data: Dictionary = WORLD_GEN.planet_data_at_chunk(chunk)
|
||||
if String(data.get("definition_id", "")) != definition_id:
|
||||
return {}
|
||||
for reveal_y in range(-1, 2):
|
||||
for reveal_x in range(-1, 2):
|
||||
explored_chunks[chunk + Vector2i(reveal_x, reveal_y)] = true
|
||||
data["chunk"] = chunk
|
||||
data["world_position"] = WORLD_GEN.chunk_origin(chunk) + Vector2(data.local_pos)
|
||||
data["distance_chunks"] = distance_chunks
|
||||
return data
|
||||
|
||||
|
||||
# Amounts a dev game opens with: enough of everything to reach any part of
|
||||
# the game immediately, without being so large that costs stop registering.
|
||||
const DEV_RESOURCE_AMOUNT: int = 2000
|
||||
|
|
|
|||
|
|
@ -233,13 +233,21 @@ const CHAIN: Array = [
|
|||
"brief": "An empty outpost is only a building. Open its hangar and station a ship there. It will hold that ground whether we are there or not.",
|
||||
"done": "The outpost has a crew. It watches that approach now, so we do not have to.",
|
||||
},
|
||||
{
|
||||
"id": "planet_scanner",
|
||||
"title": "LISTENING POST",
|
||||
"objective": "Build a planet scanner",
|
||||
"goal": {"kind": GOAL_BUILDING, "building": "planet_scanner"},
|
||||
"brief": "Blind searching is wasting our reach. Research Deep-Space Scanning at the mothership, then build a planet scanner. Give it a world signature and it will put the nearest match on our map.",
|
||||
"done": "The scanner is listening. Now we can choose where the search goes next.",
|
||||
},
|
||||
{
|
||||
"id": "worlds",
|
||||
"title": "THE SURVEY",
|
||||
"objective": "Land on three different kinds of world",
|
||||
"goal": {"kind": GOAL_PLANET_KINDS, "count": 3},
|
||||
"brief": "Rock, gas, and whatever else is out here. Land on three different kinds of world. If the World Ship came this way, it passed something.",
|
||||
"done": "Three kinds of world surveyed. Not one of them holds any sign of the convoy.",
|
||||
"objective": "Land on four different kinds of world",
|
||||
"goal": {"kind": GOAL_PLANET_KINDS, "count": 4},
|
||||
"brief": "Rock, gas, the abandoned labs, and the lightless wells. Use the scanner and land on all four kinds of world. If the World Ship came this way, it passed something.",
|
||||
"done": "Four kinds of world surveyed. No convoy—but their signatures resolve a fifth signal, hidden inside something alive.",
|
||||
"important": true,
|
||||
},
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in a new issue