Sharpen upgrades, mark the convoy's destination, and give the world sound
#204 the Beam Collimator widens the beam instead of adding range to one that already crosses the screen; beam width becomes a per-shot vessel stat. #205 the Energy Propulser gains three upgrades - dash recharge, dash reach, and boosted-cruise drain - which turns three constants into vessel stats. #206 three further doctrines carry the fleet from ten to twenty. #207 the prologue's World Ship gets a marker, through the scanner's own guidance arrow rather than a second one. #208 #210 #213 #214 four new synthesised sounds: the breach opening, cargo reaching the hold, a rock breaking, and a gas bomb blooming. #215 building health bars are larger, plated and framed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019AJMdB7iuHuLFZM1aBu3GD
This commit is contained in:
parent
2239235993
commit
78836882af
33 changed files with 716 additions and 52 deletions
|
|
@ -211,6 +211,11 @@ var explored_chunks: Dictionary = {}
|
|||
# The scanner's latest unconquered destination. Unlike explored_chunks this
|
||||
# is one intentional navigation target, shared by the map and flight HUD.
|
||||
var scanner_target: Dictionary = {}
|
||||
# #207: where the prologue's convoy is headed. Set by IntroDirector while the
|
||||
# World Ship is still something to fly TOWARD, and cleared the moment the
|
||||
# breach takes that away. Kept beside the scanner's target because the HUD
|
||||
# asks one question - "where am I going" - and only ever wants one answer.
|
||||
var intro_destination: Dictionary = {}
|
||||
|
||||
# The four ordinary destinations teach the scanner enough signatures to
|
||||
# identify the hostile boss world. Kept explicit so adding a sixth authored
|
||||
|
|
@ -300,8 +305,29 @@ func withdraw_fleet_resource(resource_type: String, amount: int) -> int:
|
|||
# deposits into the building's OWN per-record inventory, not bank_inventory
|
||||
# itself (only building_resource()/building_inventory() special-case "bank"
|
||||
# capability to redirect there).
|
||||
# #210: anything that reaches the fleet's own hold is heard - a mined rock, a
|
||||
# transporter's delivery, a load lifted off a planet. The bank is deliberately
|
||||
# silent: that is a number moving in a building the player is not standing in.
|
||||
const PICKUP_SOUND_INTERVAL_MS: int = 90
|
||||
var _pickup_sound_at: int = 0
|
||||
|
||||
|
||||
func deposit_fleet_resource(resource_type: String, amount: int) -> int:
|
||||
return fleet_inventory.deposit(resource_type, amount)
|
||||
var accepted: int = fleet_inventory.deposit(resource_type, amount)
|
||||
if accepted > 0:
|
||||
_play_pickup_sound()
|
||||
return accepted
|
||||
|
||||
|
||||
# One unit at a time is how mining arrives, so a blip per unit would be a
|
||||
# machine-gun. A burst inside the window is heard once; anything slower than
|
||||
# it stays a separate sound.
|
||||
func _play_pickup_sound() -> void:
|
||||
var now: int = Time.get_ticks_msec()
|
||||
if now - _pickup_sound_at < PICKUP_SOUND_INTERVAL_MS:
|
||||
return
|
||||
_pickup_sound_at = now
|
||||
Sfx.play(get_tree(), Sfx.PICKUP)
|
||||
|
||||
|
||||
func deposit_bank_resource(resource_type: String, amount: int) -> int:
|
||||
|
|
@ -620,6 +646,32 @@ const SKILL_TREE: Array = [
|
|||
"icon": 2,
|
||||
"desc": "Permanent: +2 vessels in the fleet.",
|
||||
},
|
||||
{
|
||||
# #206 carries the branch on to twenty. The step size keeps growing
|
||||
# for the reason the +2 tiers were introduced: ten more single-vessel
|
||||
# nodes would be a very long chain for a lane that only ever does one
|
||||
# thing. These three cost late-game money and are meant to be the
|
||||
# thing a finished economy is finally FOR.
|
||||
"id": "task_force", "name": "Task Force Doctrine", "cost": 520, "requires": "grand_fleet",
|
||||
"costs": {"ore": 520, "gas": 180, "energy": 130, "dark_matter": 35},
|
||||
"x": 0.82, "fleet_bonus": 3, "research_points": 8,
|
||||
"icon": 2,
|
||||
"desc": "Permanent: +3 vessels in the fleet.",
|
||||
},
|
||||
{
|
||||
"id": "star_legion", "name": "Star Legion Doctrine", "cost": 820, "requires": "task_force",
|
||||
"costs": {"ore": 820, "gas": 280, "energy": 200, "dark_matter": 60},
|
||||
"x": 0.82, "fleet_bonus": 3, "research_points": 10,
|
||||
"icon": 2,
|
||||
"desc": "Permanent: +3 vessels in the fleet.",
|
||||
},
|
||||
{
|
||||
"id": "void_armada", "name": "Void Armada Doctrine", "cost": 1300, "requires": "star_legion",
|
||||
"costs": {"ore": 1300, "gas": 440, "energy": 320, "dark_matter": 100},
|
||||
"x": 0.82, "fleet_bonus": 4, "research_points": 14,
|
||||
"icon": 2,
|
||||
"desc": "Permanent: +4 vessels in the fleet. The fleet reaches twenty.",
|
||||
},
|
||||
]
|
||||
|
||||
# How many SLOTS the fleet has before any doctrine is researched. Distinct
|
||||
|
|
@ -802,6 +854,7 @@ func reset_new_game() -> void:
|
|||
dev_mode = false
|
||||
explored_chunks.clear()
|
||||
scanner_target.clear()
|
||||
intro_destination.clear()
|
||||
bank_inventory = INVENTORY.new()
|
||||
fleet_inventory = INVENTORY.new()
|
||||
buildings.clear()
|
||||
|
|
@ -915,6 +968,15 @@ func _accept_scanner_target(data: Dictionary) -> Dictionary:
|
|||
return data
|
||||
|
||||
|
||||
# What the flight HUD should point at. The prologue's destination wins while
|
||||
# it exists: during those beats the fleet has no scanner and exactly one place
|
||||
# to be, and afterwards there is no World Ship left to point at.
|
||||
func active_guidance_target() -> Dictionary:
|
||||
if intro_active:
|
||||
return intro_destination
|
||||
return active_scanner_target()
|
||||
|
||||
|
||||
func active_scanner_target() -> Dictionary:
|
||||
if scanner_target.is_empty() \
|
||||
or is_planet_conquered(String(scanner_target.get("planet_id", ""))):
|
||||
|
|
@ -2505,13 +2567,18 @@ func get_mothership_position() -> Variant:
|
|||
# capacity upgrade is researched, but they are defined up front so the wedge
|
||||
# keeps a deliberate shape as it grows rather than having positions invented
|
||||
# at unlock time.
|
||||
# Ten slots, because max_fleet_size() caps itself on this array's length -
|
||||
# Twenty slots, because max_fleet_size() caps itself on this array's length -
|
||||
# so the wedge has to be long enough for every doctrine to be worth buying.
|
||||
# The last pair continues the V rather than starting a new shape.
|
||||
# Each further pair continues the same V rather than starting a new shape:
|
||||
# the rows step 30 out and 40 back, which is the rule the first ten already
|
||||
# followed, so the wedge that arrives at twenty is the one that left at three.
|
||||
const DEFAULT_FORMATION: Array = [
|
||||
Vector2(0, -48), Vector2(-30, -8), Vector2(30, -8), Vector2(-60, 32), Vector2(60, 32),
|
||||
Vector2(-90, 72), Vector2(90, 72), Vector2(0, 56),
|
||||
Vector2(-120, 112), Vector2(120, 112),
|
||||
Vector2(-150, 152), Vector2(150, 152), Vector2(-180, 192), Vector2(180, 192),
|
||||
Vector2(-210, 232), Vector2(210, 232), Vector2(-240, 272), Vector2(240, 272),
|
||||
Vector2(-270, 312), Vector2(270, 312),
|
||||
]
|
||||
|
||||
var formation: Array = DEFAULT_FORMATION.duplicate()
|
||||
|
|
@ -2727,8 +2794,11 @@ func _advance_distorder_drain(delta: float, boost_in_use: bool = true) -> void:
|
|||
# Normalized against the CURRENT ceiling, so "full boost" always costs
|
||||
# ENERGY_DRAIN_PER_SECOND however many distorder vessels widened it -
|
||||
# a bigger fleet buys more speed, not cheaper speed.
|
||||
# #205: the per-second figure is the Propulser's own stat now, so a Flux
|
||||
# Regulator makes sustained boost cheaper. ENERGY_DRAIN_PER_SECOND remains
|
||||
# what the definition declares, and what this falls back to.
|
||||
var rate: float = (fleet_speed_multiplier - 1.0) / maxf(max_fleet_speed_multiplier - 1.0, 0.001) \
|
||||
* ENERGY_DRAIN_PER_SECOND
|
||||
* vessel_stat(VESSEL_DISTORDER, "boost_drain")
|
||||
_distorder_drain_progress += rate * delta
|
||||
var whole: int = int(floor(_distorder_drain_progress))
|
||||
if whole <= 0:
|
||||
|
|
|
|||
Loading…
Reference in a new issue