2026-09-15 08:27:04 +03:00
extends SceneTree
var checks : int = 0
var failures : int = 0
func _initialize () -> void :
call_deferred ( "run" )
func check ( condition : bool , message : String ) -> void :
checks += 1
if not condition :
failures += 1
push_error ( message )
func fixture ():
var world = load ( "res://world/owniverse/owniverse.gd" ) . new ()
var global : Node = root . get_node ( "Global" )
for id in global . OwniverseEntities :
var entity = load ( "res://world/owniverse/owniverse_entity.gd" ) . new ( global . OwniverseEntities [ id ])
2026-09-29 20:23:20 +03:00
world . catalog . entities [ id ] = entity
2026-09-15 08:27:04 +03:00
world . state . amount [ id ] = 0.0
world . state . stats . total_amount [ id ] = 0.0
if entity . group_as != "" :
world . state . amount [ entity . group_as ] = 0.0
world . state . stats . total_amount [ entity . group_as ] = 0.0
2026-09-29 20:23:20 +03:00
world . catalog . entities [ "N" ] . life_product = {}
world . catalog . entities [ "N" ] . product_per_year_type = "H"
world . catalog . entities [ "N" ] . product_per_year_amount = 10.0
world . catalog . entities [ "N" ] . auto = 0.0
2026-09-15 08:27:04 +03:00
world . state . amount . N = 1.0
return world
func dispose ( world ) -> void :
2026-09-29 20:23:20 +03:00
for entity in world . catalog . entities . values ():
2026-09-15 08:27:04 +03:00
entity . free ()
world . free ()
func run () -> void :
var world = fixture ()
2026-09-22 22:50:54 +03:00
for id in [ "DSN" , "SN" , "BSN" , "HN" , "SGRB" , "GRB" , "LGRB" , "HGRB" ]:
2026-09-29 20:23:20 +03:00
check ( world . stellar . evolution_products ( world . state , world . catalog . entities [ id ], 3.0 ) . blast == 3.0 * world . catalog . entities [ id ] . blast , "Entity blast determines power: " + id )
world . catalog . entities . SN . output_and . blast = 999.0
world . catalog . entities . SN . blast = 4
check ( world . stellar . evolution_products ( world . state , world . catalog . entities . SN , 2.0 ) . blast == 8.0 , "Imported output cannot override or double blast power" )
world . catalog . entities . SN . blast = 0
check ( not world . stellar . evolution_products ( world . state , world . catalog . entities . SN , 2.0 ) . has ( "blast" ), "Zero entity blast disables external event" )
world . catalog . entities . SN . output_or = { "positive" : "blast:999" , "negative" : "blast:999" , "chance" : 50.0 }
check ( not world . stellar . evolution_products ( world . state , world . catalog . entities . SN , 2.0 ) . has ( "blast" ), "Alternative output cannot restore disabled blast" )
2026-09-22 22:50:54 +03:00
dispose ( world )
world = fixture ()
2026-09-29 20:23:20 +03:00
var rd = world . catalog . entities . RD
2026-09-15 08:27:04 +03:00
check ( rd . planets . HP . chance == 0.01 , "Preserve fractional planet probability" )
check ( rd . planets . GG . amount == 2.0 and rd . planets . GG . chance == 0.08 , "Read count and chance separately" )
check ( rd . _parse_planet_string ( "HP:1:0.01" ) == { "HP" : { "amount" : 1.0 , "chance" : 0.01 }}, "Accept a single planet term" )
check ( rd . _parse_planet_string ( "" ) . is_empty (), "Empty planet definitions stay empty" )
for id in [ "HP" , "EON1" , "C0.9" , "C1.2" ]:
2026-09-29 20:23:20 +03:00
check ( world . catalog . entities [ id ] . blastability , "Blast vulnerable: " + id )
2026-09-15 08:27:04 +03:00
for id in [ "RP" , "GG" , "AB" , "C1.3" , "C1.4" , "C1.5" ]:
2026-09-29 20:23:20 +03:00
check ( not world . catalog . entities [ id ] . blastability , "Blast protected: " + id )
2026-09-15 08:27:04 +03:00
# Actual GI table: HRG -> SN, with 1% GRB; no random rounding.
var totals : Dictionary = {}
for i in 100 :
2026-09-29 20:23:20 +03:00
var products : Dictionary = world . stellar . evolution_products ( world . state , world . catalog . entities . HRG , 1.0 )
2026-09-15 08:27:04 +03:00
for id in products :
totals [ id ] = totals . get ( id , 0.0 ) + products [ id ]
check ( totals . get ( "SN" ) == 99.0 and totals . get ( "GRB" ) == 1.0 , "GI rare outcomes accumulate deterministically" )
var restored = fixture ()
restored . state = bytes_to_var ( var_to_bytes ( world . state ))
2026-09-29 20:23:20 +03:00
check ( world . stellar . evolution_products ( world . state , world . catalog . entities . HRG , 37.0 ) == restored . stellar . evolution_products ( restored . state , restored . catalog . entities . HRG , 37.0 ), "Evolution carry survives serialization" )
2026-09-15 08:27:04 +03:00
dispose ( restored )
# Real RD lifespan, four stars spread over the existing lifespan/40 window.
world . state . amount . N = 0.0
world . state . amount . RD = 4.0
2026-09-29 20:23:20 +03:00
world . batches . append_batch ( world . state , "RD" , 4.0 , 0.0 , 0.0 )
2026-09-15 08:27:04 +03:00
var lifespan : float = rd . lifespan
var width : float = rd . lifespan_delta
2026-09-29 20:23:20 +03:00
world . evolution . evolve_batches ( world . state , lifespan )
2026-09-15 08:27:04 +03:00
check ( world . state . amount . RD == 4.0 , "Window start does not kill the whole batch" )
2026-09-29 20:23:20 +03:00
world . evolution . evolve_batches ( world . state , lifespan + width / 4.0 )
2026-09-15 08:27:04 +03:00
check ( world . state . amount . RD == 3.0 and world . state . amount . TWD == 1.0 , "One quarter of a batch evolves" )
2026-09-29 20:23:20 +03:00
world . evolution . evolve_batches ( world . state , lifespan + width / 2.0 )
2026-09-15 08:27:04 +03:00
check ( world . state . amount . RD == 2.0 and world . state . amount . TWD == 2.0 , "Half the batch evolves" )
2026-09-29 20:23:20 +03:00
world . evolution . evolve_batches ( world . state , lifespan + width )
2026-09-15 08:27:04 +03:00
check ( world . state . amount . RD == 0.0 and world . state . amount . TWD == 4.0 , "Window end completes evolution" )
check ( world . state . batches . RD . is_empty (), "Completed batch removed" )
dispose ( world )
# Creation accumulates independently for each star/planet pair.
world = fixture ()
world . state . amount . RD = 100.0
for i in 100 :
2026-09-29 20:23:20 +03:00
world . stellar . create_planets ( world . state , "RD" , 1.0 , 0.0 , 0.0 , 1.0 )
2026-09-15 08:27:04 +03:00
check ( world . state . binds . RD . HP == 1.0 , "100 RD at metallicity 1 produce one HP" )
check ( world . state . binds . RD . RP == 21.0 , "Rocky planet probability retains fractions" )
check ( world . state . binds . RD . GG == 16.0 and world . state . binds . RD . AB == 120.0 , "Planet multiplicity applied" )
check ( world . state . amount . HP == 0.0 and world . state . stats . total_amount . HP == 1.0 , "Created planets are bound, counted once" )
var saves : Node = root . get_node ( "SaveManager" )
2026-09-20 20:56:15 +03:00
check ( saves . validate_data ({ "format_version" : 2 , "app_version" : "" , "ui" : { "current_page" : 0 }, "state" : world . state }) == "" , "Planet carry save validates" )
2026-09-15 08:27:04 +03:00
restored = fixture ()
restored . state = bytes_to_var ( var_to_bytes ( world . state ))
2026-09-29 20:23:20 +03:00
world . stellar . create_planets ( world . state , "RD" , 37.0 , 0.0 , 0.0 , 0.7 )
restored . stellar . create_planets ( restored . state , "RD" , 37.0 , 0.0 , 0.0 , 0.7 )
2026-09-15 08:27:04 +03:00
check ( world . state == restored . state , "Planet carry continues after save" )
dispose ( restored )
dispose ( world )
# A partially dying dwarf sterilizes HP; survivors and RP move to its heir.
world = fixture ()
world . state . amount . RD = 4.0
world . state . binds . RD = { "HP" : 8.0 , "RP" : 4.0 , "C1.2" : 4.0 , "C1.3" : 4.0 , "GG" : 4.0 }
2026-09-29 20:23:20 +03:00
world . batches . append_batch ( world . state , "RD" , 4.0 , 0.0 , 0.0 )
world . evolution . evolve_batches ( world . state , lifespan + width / 2.0 )
2026-09-15 08:27:04 +03:00
check ( world . state . amount . RD == 2.0 and world . state . amount . TWD == 2.0 , "Partial star transition with planets" )
check ( world . state . binds . RD . HP + world . state . binds . TWD . HP == 4.0 , "Half of HP sterilized" )
check ( world . state . binds . RD [ "C1.3" ] == 2.0 and world . state . binds . TWD [ "C1.3" ] == 2.0 , "Protected civilization splits between parent and heir" )
check ( world . state . binds . RD . RP + world . state . binds . TWD . RP == 10.0 , "Sterilized planets become RP without loss" )
check ( world . state . amount . RP == 0.0 and world . state . amount [ "C1.3" ] == 0.0 , "Inherited planets never become free" )
2026-09-29 20:23:20 +03:00
world . evolution . evolve_batches ( world . state , lifespan + width )
2026-09-15 08:27:04 +03:00
check ( world . state . binds . RD [ "C1.3" ] == 0.0 and world . state . binds . TWD [ "C1.3" ] == 4.0 , "No planets left at extinct parent type" )
2026-09-20 20:56:15 +03:00
check ( saves . validate_data ({ "format_version" : 2 , "app_version" : "" , "ui" : { "current_page" : 0 }, "state" : world . state }) == "" , "Inherited state validates" )
2026-09-15 08:27:04 +03:00
dispose ( world )
world = fixture ()
world . state . amount . WS = 2.0
world . state . binds . WS = { "HP" : 4.0 , "C1.3" : 4.0 , "RP" : 4.0 , "GG" : 4.0 }
2026-09-29 20:23:20 +03:00
world . batches . append_batch ( world . state , "WS" , 2.0 , 0.0 , 0.0 )
world . evolution . evolve_batches ( world . state , world . catalog . entities . WS . lifespan + world . catalog . entities . WS . lifespan_delta )
var physical : Dictionary = world . ledger . physical_amounts ( world . state )
2026-09-15 08:27:04 +03:00
check ( physical . HP == 0.0 and physical [ "C1.3" ] == 0.0 and physical . RP == 0.0 and physical . GG == 0.0 , "Level 2 removes all planets, including protected civilization" )
check ( world . state . amount . LRG == 2.0 , "Giant evolves after local destruction" )
dispose ( world )
world = fixture ()
world . state . amount . RD = 10.0
world . state . binds . RD = { "HP" : 10.0 , "C1.2" : 10.0 , "C1.3" : 10.0 , "RP" : 0.0 }
2026-09-29 20:23:20 +03:00
world . stellar . apply_blast ( world . state , 5.0 , { "blast" : 1.0 , "density" : 1.0 })
2026-09-15 08:27:04 +03:00
check ( world . state . binds . RD . HP == 5.0 and world . state . binds . RD [ "C1.2" ] == 5.0 , "Blast damages vulnerable worlds proportionally" )
check ( world . state . binds . RD [ "C1.3" ] == 10.0 and world . state . binds . RD . RP == 10.0 , "Blast protects C1.3 and creates RP" )
2026-09-29 20:23:20 +03:00
world . stellar . apply_blast ( world . state , 1e6 , { "blast" : 1.0 , "density" : 1.0 })
2026-09-15 08:27:04 +03:00
check ( world . state . binds . RD . HP == 0.0 and world . state . binds . RD . RP == 20.0 , "Overwhelming blast is capped at available planets" )
check ( not world . state . amount . has ( "blast" ), "Blast is not a resource" )
dispose ( world )
world = fixture ()
world . state . amount . RD = 1.0
world . state . binds . RD = { "HP" : 1.0 }
for i in 10 :
2026-09-29 20:23:20 +03:00
world . stellar . apply_blast ( world . state , 1.0 , { "blast" : 1.0 , "density" : 0.1 })
2026-09-15 08:27:04 +03:00
check ( world . state . binds . RD . HP == 0.0 and world . state . binds . RD . RP == 1.0 , "Small blast effects accumulate across cycles" )
dispose ( world )
# Actual supernova output: one SN gives a neutron star, resources, and an event.
world = fixture ()
world . state . amount . SN = 1.0
2026-09-29 20:23:20 +03:00
world . batches . append_batch ( world . state , "SN" , 1.0 , 0.0 , 0.0 )
world . evolution . evolve_batches ( world . state , 2.0 )
2026-09-15 08:27:04 +03:00
check ( world . state . amount . SN == 0.0 and world . state . amount . LNS == 1.0 , "Supernova produces a remnant" )
check ( world . state . amount . H == 8.0 and world . state . amount . He == 50.0 and world . state . amount . Met == 11.0 , "Supernova returns table resources" )
check ( not world . state . amount . has ( "blast" ), "Supernova dispatches blast output" )
2026-09-20 20:56:15 +03:00
check ( saves . validate_data ({ "format_version" : 2 , "app_version" : "" , "ui" : { "current_page" : 0 }, "state" : world . state }) == "" , "Blast state validates" )
2026-09-15 08:27:04 +03:00
dispose ( world )
world = fixture ()
world . state . amount . H = 1000.0
world . state . amount . Met = 100.0
2026-09-29 20:23:20 +03:00
check ( world . production . produce ( "RD" , 100.0 ) == 100.0 , "Manual star creation succeeds" )
2026-09-15 08:27:04 +03:00
check ( world . state . binds . RD . HP >= 1.0 , "Manual creation dispatches planet formation" )
check ( world . state . amount . H == 900.0 , "Planet creation does not duplicate or spend stellar fuel" )
dispose ( world )
world = fixture ()
world . state . amount . N = 0.0
world . state . amount . RD = 1.0
world . state . amount . H = 100.0
world . state . amount . Met = 100.0
world . state . auto_resources . H = 100.0
world . evolute ( 0.1 )
check ( world . state . amount . RD == 101.0 and world . state . amount . H == 0.0 , "Automatic formation uses its resource budget" )
check ( world . state . binds . RD . HP >= 1.0 , "Automatic formation also creates planets" )
dispose ( world )
2026-09-21 20:42:40 +03:00
world = fixture ()
2026-09-29 20:23:20 +03:00
world . catalog . entities . N . auto = 1.0
2026-09-21 20:42:40 +03:00
# 1000 newly produced automatic H reserve 1 H, enough for 10 HBD.
world . evolute ( 100.0 )
check ( world . state . amount . HBD == 10.0 , "Brown dwarfs form without existing ordinary stars" )
check ( world . state . amount . H == 999.0 and world . state . auto_resources . H == 999.0 , "Brown dwarfs consume exactly their reserved hydrogen" )
2026-09-29 20:23:20 +03:00
check ( world . presentation . amounts ( world . state , world . catalog ) . BD == 10.0 and world . state . batches . HBD . size () > 0 , "Brown dwarfs appear in counter and evolution batches" )
world . catalog . entities . N . product_per_year_amount = 0.0
2026-09-21 20:42:40 +03:00
world . evolute ( 100.0 )
check ( world . state . amount . HBD == 10.0 , "Stored automatic budget is not taxed repeatedly" )
dispose ( world )
world = fixture ()
2026-09-29 20:23:20 +03:00
world . catalog . entities . N . auto = 1.0
2026-09-21 20:42:40 +03:00
world . state . amount . RD = 1.0
world . evolute ( 50.0 )
check ( world . state . amount . HBD == 5.0 and is_equal_approx ( world . state . auto_star_deficits . HBD_fuel , 0.5 ), "Individual dwarfs retain prepaid fractional fuel" )
check ( world . state . amount . H == 0.0 , "Prepaid fuel is not available to ordinary stars" )
var resumed = fixture ()
2026-09-29 20:23:20 +03:00
resumed . catalog . entities . N . auto = 1.0
2026-09-21 20:42:40 +03:00
resumed . state = bytes_to_var ( var_to_bytes ( world . state ))
world . evolute ( 50.0 )
resumed . evolute ( 50.0 )
check ( world . state . amount . HBD == 10.0 , "Accumulated quota eventually creates a whole batch" )
check ( world . state == resumed . state , "Brown dwarf quota survives serialization deterministically" )
check ( world . state . amount . RD == 1000.0 and world . state . amount . H == 0.0 , "Shared automatic hydrogen is spent once" )
world . state . batches . HBD = [{ "amount" : 10.0 , "start_year" : 101.0 , "end_year" : 101.0 }]
2026-09-29 20:23:20 +03:00
world . evolution . evolve_batches ( world . state , 101.0 )
check ( world . state . amount . HBD == 0.0 and world . state . amount . CBD == 10.0 and world . presentation . amounts ( world . state , world . catalog ) . BD == 10.0 , "Cooling preserves aggregate brown dwarf count" )
2026-09-21 20:42:40 +03:00
dispose ( resumed )
dispose ( world )
world = fixture ()
var saw_individual : bool = false
for i in range ( 250 ):
world . state . amount . H += 1.0
world . state . auto_resources . H = world . state . auto_resources . get ( "H" , 0.0 ) + 1.0
var before : float = world . state . amount . HBD
2026-09-29 20:23:20 +03:00
world . automatic . produce_brown_dwarfs ( world . state , 1.0 , float ( i ), float ( i + 1 ))
2026-09-21 20:42:40 +03:00
var born : float = world . state . amount . HBD - before
check ( born == 0.0 or born == 1.0 , "Small fuel increments produce individual dwarfs" )
saw_individual = saw_individual or born == 1.0
check ( saw_individual , "Random rounding does not wait for ten dwarfs" )
resumed = fixture ()
resumed . state = bytes_to_var ( var_to_bytes ( world . state ))
for i in range ( 250 , 500 ):
for simulation in [ world , resumed ]:
simulation . state . amount . H += 1.0
simulation . state . auto_resources . H += 1.0
2026-09-29 20:23:20 +03:00
simulation . automatic . produce_brown_dwarfs ( simulation . state , 1.0 , float ( i ), float ( i + 1 ))
2026-09-21 20:42:40 +03:00
check ( world . state == resumed . state , "Random sequence and prepaid fuel survive saving" )
check ( is_equal_approx ( world . state . amount . H + world . state . amount . HBD * 0.1 + world . state . auto_star_deficits . HBD_fuel , 500.0 ), "Individual production conserves fuel including prepaid reserve" )
check ( is_equal_approx ( world . state . amount . HBD + world . state . auto_star_deficits . HBD , 5.0 ), "Signed remainder preserves the 0.1 percent allocation" )
var paused_count : float = world . state . amount . HBD
2026-09-29 20:23:20 +03:00
for i in 10 : world . automatic . produce_brown_dwarfs ( world . state , 0.0 , 500.0 , 501.0 )
2026-09-21 20:42:40 +03:00
check ( world . state . amount . HBD == paused_count , "No repeated random attempts without new fuel" )
dispose ( resumed )
dispose ( world )
2026-09-15 08:27:04 +03:00
# Two simultaneous successors share surviving planets in the same 99:1 ratio.
world = fixture ()
2026-09-29 20:23:20 +03:00
world . catalog . entities . HRG . destroy_level = 0
2026-09-15 08:27:04 +03:00
world . state . amount . HRG = 100.0
world . state . binds . HRG = { "C1.3" : 100.0 }
world . state . batches . HRG = [{ "start_year" : 0.1 , "end_year" : 0.1 , "amount" : 100.0 }]
2026-09-29 20:23:20 +03:00
world . evolution . evolve_batches ( world . state , 0.1 )
2026-09-15 08:27:04 +03:00
check ( world . state . binds . SN [ "C1.3" ] == 99.0 and world . state . binds . GRB [ "C1.3" ] == 1.0 , "Planets split among actual alternative successors" )
check ( world . state . binds . HRG [ "C1.3" ] == 0.0 , "Alternative evolution leaves no orphan bindings" )
dispose ( world )
world = fixture ()
world . state . amount . N = 0.0
world . state . amount . HRG = 1.0
world . state . batches . HRG = [{ "start_year" : 0.1 , "end_year" : 0.1 , "amount" : 1.0 }]
world . evolute ( 3.0 )
check ( world . state . amount . LNS == 1.0 and world . state . amount . SN == 0.0 , "Long step follows multiple stellar generations" )
check ( world . state . amount . S >= 99.0 , "Short-lived newborn supernova emits S before disappearing" )
dispose ( world )
print ( "Stellar rules: %d checks, %d failures" % [ checks , failures ])
quit ( 0 if failures == 0 else 1 )