2026-09-16 19:54:47 +03:00
extends SceneTree
2026-09-30 08:08:27 +03:00
const E = preload ( "res://world/owniverse/math/exact.gd" )
2026-09-16 19:54:47 +03:00
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 :
2026-09-30 08:08:27 +03:00
checks = E . add ( checks , 1 )
if ( not condition ):
failures = E . add ( failures , 1 )
2026-09-16 19:54:47 +03:00
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-30 08:08:27 +03:00
world . state . amount [ id ] = 0
world . state . stats . total_amount [ id ] = 0
if E . ne ( entity . group_as , "" ):
world . state . amount [ entity . group_as ] = 0
world . state . stats . total_amount [ entity . group_as ] = 0
2026-09-29 20:23:20 +03:00
world . catalog . entities [ "N" ] . life_product = {}
world . catalog . entities [ "N" ] . product_per_year_type = "H"
2026-09-30 08:08:27 +03:00
world . catalog . entities [ "N" ] . product_per_year_amount = 10
world . catalog . entities [ "N" ] . auto = 0
world . state . amount . N = 1
2026-09-16 19:54:47 +03:00
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 ()
2026-09-30 08:08:27 +03:00
func seed_population ( world , id : String , count : Variant , time : Variant = 1.0 ) -> void :
world . state . amount . N = 0
2026-09-16 19:54:47 +03:00
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
2026-09-30 08:08:27 +03:00
func sum_ethics ( world , id : String ) -> Variant :
var result : Variant = 0
for n in world . state . ethics . get ( id , {}) . values (): result = E . add ( result , n )
2026-09-16 19:54:47 +03:00
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 :
2026-09-30 08:08:27 +03:00
check ( E . eq ( sum_ethics ( world , id ), physical . get ( id , 0 )), E . add ( "Ethics equal physical population for " , id ))
2026-09-16 19:54:47 +03:00
for n in world . state . ethics [ id ] . values ():
2026-09-30 08:08:27 +03:00
if ( E . lt ( n , 0 ) or E . ne ( n , E . floor_value ( n ))): check ( false , "Invalid ethic amount" )
2026-10-01 23:43:34 +03:00
check ( E . eq ( root . get_node ( "SaveManager" ) . validate_data ({ "format_version" : 5 , "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 ()
2026-09-30 08:08:27 +03:00
seed_population ( world , "C0.2" , 60000 )
world . evolution . evolve_batches ( world . state , 1 )
check ( E . gt ( world . state . amount [ "C0.3" ], 0 ), "C0.2 actually progresses" )
check ( E . gt ( world . state . amount [ "C0.1" ], 0 ), "C0.2 actually degrades" )
check ( E . eq ( world . state . civilization_stats . get ( "wars" , 0 ), 0 ), "Table disables early wars" )
check ( E . eq ( E . add ( E . add ( world . state . amount [ "C0.2" ], world . state . amount [ "C0.3" ]), world . state . amount [ "C0.1" ]), 60000 ), "Ordinary evolution conserves population" )
check ( E . eq ( world . state . stats . total_amount [ "C0.2" ], 0 ), "Survivors do not count as new civilizations" )
check ( E . gt ( world . state . civilization_stats . worship , 0 ), "Worship derived from surviving ethics" )
2026-09-16 19:54:47 +03:00
invariants ( world )
var restored = fixture ()
2026-09-30 08:08:27 +03:00
restored . state = E . decode ( bytes_to_var ( var_to_bytes ( E . encode ( world . state ))))
world . evolution . evolve_batches ( world . state , 2100 )
restored . evolution . evolve_batches ( restored . state , 2100 )
check ( E . eq ( world . state , restored . state ), "Save resumes deterministic ethical evolution" )
2026-09-16 19:54:47 +03:00
invariants ( world )
dispose ( restored )
dispose ( world )
world = fixture ()
2026-09-30 08:08:27 +03:00
world . state . amount . RD = 100000000
seed_population ( world , "C2.0" , 60000 )
world . state . amount [ "C1.9" ] = 10000
2026-09-29 20:23:20 +03:00
world . evolution . initialize_life_batches ()
2026-09-30 08:08:27 +03:00
world . evolution . evolve_batches ( world . state , 1 )
check ( E . gt ( world . state . civilization_stats . wars , 0 ), "Wars execute when enabled" )
check ( E . gt ( world . state . civilization_stats . collateral , 0 ), "Wars affect previous-stage populations" )
check ( E . gt ( world . state . amount [ "C2.1" ], 0 ), "Winners and peaceful progress reach next stage" )
2026-09-16 19:54:47 +03:00
invariants ( world )
dispose ( world )
world = fixture ()
2026-09-30 08:08:27 +03:00
world . state . amount . RD = 1
world . state . binds . RD = { "HP" : 5 , "GG" : 5 , "AB" : 5 , "RP" : 5 }
seed_population ( world , "C1.6" , 60000 )
for row : Dictionary in global . CivilizationRules [ "C1.6" ] . ethics . values (): row . degradation = "0"
world . evolution . evolve_batches ( world . state , 1 )
2026-09-29 20:23:20 +03:00
var after : Dictionary = world . ledger . physical_amounts ( world . state )
2026-09-30 08:08:27 +03:00
check ( E . eq ( world . state . civilization_stats . colonies , 20 ), "Colonization limited to real targets" )
check ( E . eq ( E . add ( E . add ( E . add ( after . HP , after . GG ), after . AB ), after . RP ), 0 ), "Colonized objects consumed once" )
check ( E . eq ( world . state . binds . RD . get ( "C1.4" , 0 ), 20 ), "Colonies retain target host and use two-stages-earlier level" )
var totals : Variant = 0
2026-09-16 19:54:47 +03:00
for id in after :
2026-09-30 08:08:27 +03:00
if E . eq ( world . catalog . entities [ id ] . group_as , "Planet" ): totals = E . add ( totals , after [ id ])
check ( E . eq ( totals , 60020 ), "Colonization replaces planets, does not create extra worlds" )
2026-09-16 19:54:47 +03:00
invariants ( world )
dispose ( world )
global . CivilizationRules = baseline . duplicate ( true )
world = fixture ()
2026-09-30 08:08:27 +03:00
world . state . amount . RD = E . of ( "1e25" )
world . state . amount . BG = E . of ( "1e25" )
world . state . amount . TWD = E . of ( "1e25" )
world . state . amount . SNS = E . of ( "1e25" )
world . state . amount . MGT = E . of ( "1e25" )
world . state . amount . BH25 = E . of ( "1e25" )
world . state . amount . SMBH = E . of ( "1e26" )
2026-09-29 20:23:20 +03:00
for id in world . catalog . entities :
2026-09-30 08:08:27 +03:00
if E . ne ( world . catalog . entities [ id ] . claim , "" ): world . state . amount [ id ] = E . of ( "1e12" )
2026-09-16 19:54:47 +03:00
# Accelerated deterministic fixture traverses every enabled stage, including Ct.
for id in global . CivilizationRules :
2026-09-30 08:08:27 +03:00
if E . eq ( id , "Ct" ): continue
2026-09-16 19:54:47 +03:00
global . CivilizationRules [ id ] . fights = false
global . CivilizationRules [ id ] . colonizes = false
global . CivilizationRules [ id ] . diplomacy = false
2026-09-30 08:08:27 +03:00
for row : Dictionary in global . CivilizationRules [ id ] . ethics . values ():
2026-09-16 19:54:47 +03:00
row . progress = "1"
row . degradation = "0"
2026-09-30 08:08:27 +03:00
world . catalog . entities [ id ] . lifespan = 1
world . catalog . entities [ id ] . lifespan_delta = 1
global . CivilizationRules [ id ] . span = 1
seed_population ( world , "C0.2" , 6 )
world . evolution . evolve_batches ( world . state , 1000 )
check ( E . eq ( world . state . amount . Ct , 6 ), "Complete C0.2 -> C4.4 -> Ct chain runs" )
check (( not world . state . batches . has ( "Ct" )), "Transcendence is terminal" )
2026-09-16 19:54:47 +03:00
invariants ( world )
dispose ( world )
global . CivilizationRules = baseline
world = fixture ()
2026-09-30 08:08:27 +03:00
world . state . amount . RD = 10000
world . state . amount . SCS = 1
world . state . amount [ "C2.4" ] = 1
2026-09-29 20:23:20 +03:00
world . evolution . initialize_life_batches ()
2026-09-30 08:08:27 +03:00
var span : Variant = world . state . batches [ "C2.4" ][ 0 ] . start_year
check ( E . near ( span , E . divide ( 20000 , E . of ( "3.6" ))), "Structure bonus shortens newly registered lifespan" )
2026-09-16 19:54:47 +03:00
dispose ( world )
var evolution = load ( "res://world/owniverse/civilization_evolution.gd" )
2026-09-30 08:08:27 +03:00
var balanced : Dictionary = { "m" : 10000 , "l" : 10000 , "w" : 10000 , "d" : 10000 , "c" : 10000 , "b" : 10000 }
2026-09-16 19:54:47 +03:00
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 )
2026-09-30 08:08:27 +03:00
check ( E . eq ( neutral , balanced ), "Ordinary drift preserves balanced ethics" )
check ( E . gt ( diplomatic . d , diplomatic . w ), "Diplomacy uses per-ethic influence" )
check ( E . eq ( evolution . total ( diplomatic ), 60000 ), "Diplomacy conserves population" )
2026-09-16 19:54:47 +03:00
world = fixture ()
2026-09-30 08:08:27 +03:00
world . state . amount . RD = E . of ( "1e15" )
world . state . amount . BG = E . of ( "1e15" )
world . state . amount [ "C3.0" ] = 6
2026-09-29 20:23:20 +03:00
world . evolution . initialize_life_batches ()
2026-09-30 08:08:27 +03:00
check (( E . eq ( world . state . amount [ "C3.0" ], 0 ) and E . eq ( world . state . amount [ "C2.9" ], 6 )), "Missing mandatory structures degrade existing civilizations" )
2026-09-16 19:54:47 +03:00
invariants ( world )
dispose ( world )
2026-09-30 08:08:27 +03:00
print (( "Civilization evolution: %d checks, %d failures" % [ checks , failures ]))
quit (( 0 if E . eq ( failures , 0 ) else 1 ))