2026-09-16 19:54:47 +03:00
extends SceneTree
const Clock = preload ( "res://world/owniverse/simulation_time.gd" )
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-16 19:54:47 +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-16 19:54:47 +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-16 19:54:47 +03:00
entity . free ()
world . free ()
func seed_population ( world , id : String , count : float , time : float = 1.0 ) -> void :
world . state . amount . N = 0.0
world . state . amount [ id ] = count
world . state . batches [ id ] = [{ "amount" : count , "start_year" : time , "end_year" : time }]
2026-09-29 20:23:20 +03:00
world . evolution . initialize_life_batches ()
2026-09-16 19:54:47 +03:00
func sum_ethics ( world , id : String ) -> float :
var result : float = 0.0
for n in world . state . ethics . get ( id , {}) . values (): result += n
return result
func invariants ( world ) -> void :
2026-09-29 20:23:20 +03:00
var physical : Dictionary = world . ledger . physical_amounts ( world . state )
2026-09-16 19:54:47 +03:00
for id in world . state . ethics :
check ( sum_ethics ( world , id ) == physical . get ( id , 0.0 ), "Ethics equal physical population for " + id )
for n in world . state . ethics [ id ] . values ():
if n < 0.0 or n != floorf ( n ): check ( false , "Invalid ethic amount" )
2026-09-20 20:56:15 +03:00
check ( root . get_node ( "SaveManager" ) . validate_data ({ "format_version" : 2 , "app_version" : "" , "ui" : { "current_page" : 0 }, "state" : world . state }) == "" , "Civilization state validates" )
2026-09-16 19:54:47 +03:00
func run () -> void :
var global : Node = root . get_node ( "Global" )
var baseline : Dictionary = global . CivilizationRules . duplicate ( true )
var world = fixture ()
seed_population ( world , "C0.2" , 60000.0 )
2026-09-29 20:23:20 +03:00
world . evolution . evolve_batches ( world . state , 1.0 )
2026-09-16 19:54:47 +03:00
check ( world . state . amount [ "C0.3" ] > 0.0 , "C0.2 actually progresses" )
check ( world . state . amount [ "C0.1" ] > 0.0 , "C0.2 actually degrades" )
check ( world . state . civilization_stats . get ( "wars" , 0.0 ) == 0.0 , "Table disables early wars" )
check ( world . state . amount [ "C0.2" ] + world . state . amount [ "C0.3" ] + world . state . amount [ "C0.1" ] == 60000.0 , "Ordinary evolution conserves population" )
check ( world . state . stats . total_amount [ "C0.2" ] == 0.0 , "Survivors do not count as new civilizations" )
check ( world . state . civilization_stats . worship > 0.0 , "Worship derived from surviving ethics" )
invariants ( world )
var restored = fixture ()
restored . state = bytes_to_var ( var_to_bytes ( world . state ))
2026-09-29 20:23:20 +03:00
world . evolution . evolve_batches ( world . state , 2100.0 )
restored . evolution . evolve_batches ( restored . state , 2100.0 )
2026-09-16 19:54:47 +03:00
check ( world . state == restored . state , "Save resumes deterministic ethical evolution" )
invariants ( world )
dispose ( restored )
dispose ( world )
world = fixture ()
world . state . amount . RD = 1e8
seed_population ( world , "C2.0" , 60000.0 )
world . state . amount [ "C1.9" ] = 10000.0
2026-09-29 20:23:20 +03:00
world . evolution . initialize_life_batches ()
world . evolution . evolve_batches ( world . state , 1.0 )
2026-09-16 19:54:47 +03:00
check ( world . state . civilization_stats . wars > 0.0 , "Wars execute when enabled" )
check ( world . state . civilization_stats . collateral > 0.0 , "Wars affect previous-stage populations" )
check ( world . state . amount [ "C2.1" ] > 0.0 , "Winners and peaceful progress reach next stage" )
invariants ( world )
dispose ( world )
world = fixture ()
world . state . amount . RD = 1.0
world . state . binds . RD = { "HP" : 5.0 , "GG" : 5.0 , "AB" : 5.0 , "RP" : 5.0 }
seed_population ( world , "C1.6" , 60000.0 )
for row : Dictionary in global . CivilizationRules [ "C1.6" ] . ethics . values (): row . degradation = "0"
2026-09-29 20:23:20 +03:00
world . evolution . evolve_batches ( world . state , 1.0 )
var after : Dictionary = world . ledger . physical_amounts ( world . state )
2026-09-16 19:54:47 +03:00
check ( world . state . civilization_stats . colonies == 20.0 , "Colonization limited to real targets" )
check ( after . HP + after . GG + after . AB + after . RP == 0.0 , "Colonized objects consumed once" )
check ( world . state . binds . RD . get ( "C1.4" , 0.0 ) == 20.0 , "Colonies retain target host and use two-stages-earlier level" )
var totals : float = 0.0
for id in after :
2026-09-29 20:23:20 +03:00
if world . catalog . entities [ id ] . group_as == "Planet" : totals += after [ id ]
2026-09-16 19:54:47 +03:00
check ( totals == 60020.0 , "Colonization replaces planets, does not create extra worlds" )
invariants ( world )
dispose ( world )
global . CivilizationRules = baseline . duplicate ( true )
world = fixture ()
world . state . amount . RD = 1e25
world . state . amount . BG = 1e25
world . state . amount . TWD = 1e25
world . state . amount . SNS = 1e25
world . state . amount . MGT = 1e25
world . state . amount . BH25 = 1e25
world . state . amount . SMBH = 1e26
2026-09-29 20:23:20 +03:00
for id in world . catalog . entities :
if world . catalog . entities [ id ] . claim != "" : world . state . amount [ id ] = 1e12
2026-09-16 19:54:47 +03:00
# Accelerated deterministic fixture traverses every enabled stage, including Ct.
for id in global . CivilizationRules :
if id == "Ct" : continue
global . CivilizationRules [ id ] . fights = false
global . CivilizationRules [ id ] . colonizes = false
global . CivilizationRules [ id ] . diplomacy = false
for row : Dictionary in global . CivilizationRules [ id ] . ethics . values ():
row . progress = "1"
row . degradation = "0"
2026-09-29 20:23:20 +03:00
world . catalog . entities [ id ] . lifespan = 1.0
world . catalog . entities [ id ] . lifespan_delta = 1.0
2026-09-16 19:54:47 +03:00
global . CivilizationRules [ id ] . span = 1.0
seed_population ( world , "C0.2" , 6.0 )
2026-09-29 20:23:20 +03:00
world . evolution . evolve_batches ( world . state , 1000.0 )
2026-09-16 19:54:47 +03:00
check ( world . state . amount . Ct == 6.0 , "Complete C0.2 -> C4.4 -> Ct chain runs" )
check ( not world . state . batches . has ( "Ct" ), "Transcendence is terminal" )
invariants ( world )
dispose ( world )
global . CivilizationRules = baseline
world = fixture ()
world . state . amount . RD = 10000.0
world . state . amount . SCS = 1.0
world . state . amount [ "C2.4" ] = 1.0
2026-09-29 20:23:20 +03:00
world . evolution . initialize_life_batches ()
2026-09-16 19:54:47 +03:00
var span : float = world . state . batches [ "C2.4" ][ 0 ] . start_year
check ( is_equal_approx ( span , 20000.0 / 3.6 ), "Structure bonus shortens newly registered lifespan" )
dispose ( world )
var evolution = load ( "res://world/owniverse/civilization_evolution.gd" )
var balanced : Dictionary = { "m" : 10000.0 , "l" : 10000.0 , "w" : 10000.0 , "d" : 10000.0 , "c" : 10000.0 , "b" : 10000.0 }
var neutral : Dictionary = evolution . drift ({}, "test" , balanced , global . CivilizationRules [ "C2.0" ] . ethics )
var diplomatic : Dictionary = evolution . drift ({}, "test" , balanced , global . CivilizationRules [ "C2.0" ] . ethics , true )
check ( neutral == balanced , "Ordinary drift preserves balanced ethics" )
check ( diplomatic . d > diplomatic . w , "Diplomacy uses per-ethic influence" )
check ( evolution . total ( diplomatic ) == 60000.0 , "Diplomacy conserves population" )
world = fixture ()
world . state . amount . RD = 1e15
world . state . amount . BG = 1e15
world . state . amount [ "C3.0" ] = 6.0
2026-09-29 20:23:20 +03:00
world . evolution . initialize_life_batches ()
2026-09-16 19:54:47 +03:00
check ( world . state . amount [ "C3.0" ] == 0.0 and world . state . amount [ "C2.9" ] == 6.0 , "Missing mandatory structures degrade existing civilizations" )
invariants ( world )
dispose ( world )
print ( "Civilization evolution: %d checks, %d failures" % [ checks , failures ])
quit ( 0 if failures == 0 else 1 )