2026-09-28 22:19:13 +03:00
extends SceneTree
2026-09-29 20:23:20 +03:00
const CivilizationState = preload ( "res://world/owniverse/civilization_state.gd" )
const CivilizationEvolution = preload ( "res://world/owniverse/civilization_evolution.gd" )
2026-09-28 22:19:13 +03:00
const Parameters = preload ( "res://world/owniverse/world_parameters.gd" )
const Descriptions = preload ( "res://world/owniverse/item_description.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 ()
for id in root . get_node ( "Global" ) . OwniverseEntities :
var entity = load ( "res://world/owniverse/owniverse_entity.gd" ) . new ( root . get_node ( "Global" ) . OwniverseEntities [ id ])
2026-09-29 20:23:20 +03:00
world . catalog . entities [ id ] = entity
2026-09-28 22:19:13 +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
return world
func dispose ( world ) -> void :
2026-09-29 20:23:20 +03:00
for entity in world . catalog . entities . values (): entity . free ()
2026-09-28 22:19:13 +03:00
world . free ()
func run () -> void :
var global : Node = root . get_node ( "Global" )
var world = fixture ()
world . state . amount . RD = 400.0
2026-09-29 20:23:20 +03:00
world . batches . append_batch ( world . state , "RD" , 400.0 , 0.0 , 0.0 )
2026-09-28 22:19:13 +03:00
var end : float = world . state . batches . RD [ 0 ] . end_year
2026-09-29 20:23:20 +03:00
world . environment . modify_world_parameter ( "Bur" , 9.0 )
2026-09-28 22:19:13 +03:00
check ( is_equal_approx ( world . state . batches . RD [ 0 ] . end_year , end / 10.0 ), "Burnability accelerates existing cohorts" )
var count : float = world . state . batches . RD [ 0 ] . amount
2026-09-29 20:23:20 +03:00
world . environment . modify_world_parameter ( "Bur" , - 9.0 )
2026-09-28 22:19:13 +03:00
check ( is_equal_approx ( world . state . batches . RD [ 0 ] . end_year , end ) and world . state . batches . RD [ 0 ] . amount == count , "Changing burnability back preserves population and lifetime" )
2026-09-29 20:23:20 +03:00
world . environment . modify_world_parameter ( "Bur" , 9.0 )
world . batches . append_batch ( world . state , "YD" , 10.0 , 0.0 , 0.0 )
check ( is_equal_approx ( world . state . batches . YD [ 0 ] . start_year , world . catalog . entities . YD . lifespan / 10.0 ), "New stars use the same burnability" )
2026-09-28 22:19:13 +03:00
world . state . time = { "datetime" : end / 10.0 - 0.1 , "year" : end / 10.0 - 0.1 }
2026-09-29 20:23:20 +03:00
world . batches . withdraw_batches ( world . state , "RD" , world . state . time . year )
world . environment . modify_world_parameter ( "Bur" , - 18.0 )
2026-09-28 22:19:13 +03:00
check ( world . state . batches . RD [ 0 ] . end_year >= world . state . time . year , "Slowing a partially evolved cohort keeps its remaining window in the future" )
2026-09-29 20:23:20 +03:00
world . environment . modify_world_parameter ( "Exp" , 9.0 )
check ( world . stellar . evolution_products ( world . state , world . catalog . entities . SN , 2.0 ) . blast == 180.0 , "Explosion power includes world explosiveness" )
var products : Dictionary = world . stellar . evolution_products ( world . state , world . catalog . entities . HRG , 1000.0 )
2026-09-28 22:19:13 +03:00
check ( products . get ( "GRB" , 0.0 ) == 100.0 and products . get ( "SN" , 0.0 ) == 900.0 , "Explosiveness raises rare-event probability without duplicating stars" )
2026-09-29 20:23:20 +03:00
world . catalog . entities . HRG . output_or . chance = 50.0
products = world . stellar . evolution_products ( world . state , world . catalog . entities . HRG , 100.0 )
2026-09-28 22:19:13 +03:00
check ( products . get ( "GRB" , 0.0 ) == 100.0 and products . get ( "SN" , 0.0 ) == 0.0 , "Rare-event probability is bounded at one" )
dispose ( world )
world = fixture ()
2026-09-29 20:23:20 +03:00
var ordinary : Dictionary = world . life . life_products ( world . state , world . catalog . entities . HP , 1000000.0 )
2026-09-28 22:19:13 +03:00
world . state . life_remainders . clear ()
2026-09-29 20:23:20 +03:00
world . environment . modify_world_parameter ( "Agg" , 9.0 )
var aggressive : Dictionary = world . life . life_products ( world . state , world . catalog . entities . HP , 1000000.0 )
2026-09-28 22:19:13 +03:00
check ( aggressive . EON1 > ordinary . EON1 , "Aggression accelerates primitive evolution" )
world . state . life_remainders . clear ()
world . state . world_parameters . Order = 10.0
2026-09-29 20:23:20 +03:00
var orderly : Dictionary = world . life . life_products ( world . state , world . catalog . entities . HP , 1000000.0 )
2026-09-28 22:19:13 +03:00
check ( orderly . RP < aggressive . RP , "Order reduces degradation" )
world . state . life_remainders . clear ()
world . state . world_parameters . Enlightenment = 10.0
2026-09-29 20:23:20 +03:00
var enlightened : Dictionary = world . life . life_products ( world . state , world . catalog . entities . HP , 1000000.0 )
2026-09-28 22:19:13 +03:00
check ( enlightened . EON1 > orderly . EON1 , "Enlightenment increases primitive progress" )
dispose ( world )
world = fixture ()
var hotter = fixture ()
for simulation in [ world , hotter ]:
simulation . state . amount . RD = 1000000.0
2026-09-29 20:23:20 +03:00
simulation . batches . append_batch ( simulation . state , "RD" , 1000000.0 , 0.0 , 0.0 )
hotter . environment . modify_world_parameter ( "Bur" , 9.0 )
2026-09-28 22:19:13 +03:00
world . evolute ( 1000.0 )
hotter . evolute ( 1000.0 )
check ( hotter . state . amount . S > world . state . amount . S , "Burnability changes actual space production" )
check ( hotter . state . energy + hotter . state . amount . S == Parameters . INITIAL_ENERGY , "Enhanced production still spends the GI energy budget" )
dispose ( world )
dispose ( hotter )
world = fixture ()
world . state . amount [ "C0.2" ] = 1000000.0
world . state . ethics [ "C0.2" ] = { "m" : 1000000.0 }
var baseline : Dictionary = world . state . duplicate ( true )
var advanced : Dictionary = baseline . duplicate ( true )
advanced . world_parameters . Agg = 19.0
var next_stage : String = global . CivilizationRules [ "C0.2" ] . next
var outcomes : Array = []
for target in [ baseline , advanced ]:
var expired : Dictionary = { "C0.2" : [{ "amount" : 1000000.0 , "from" : 0.0 , "to" : 1.0 }]}
2026-09-29 20:23:20 +03:00
var budget : Dictionary = CivilizationState . stellar_budget ( world , target , global . CivilizationRules )
CivilizationEvolution . prepare ( world , target , expired , 1.0 , budget , global . CivilizationRules )
2026-09-28 22:19:13 +03:00
outcomes . append ( expired [ "C0.2" ][ 0 ] . products . get ( next_stage , 0.0 ))
check ( outcomes [ 1 ] > outcomes [ 0 ], "Aggression changes actual ethical civilization transitions" )
dispose ( world )
# Trends use ethical proportions and stage weights, not population magnitude.
world = fixture ()
var rules : Dictionary = { "C2.0" : { "home" : "DwStar" }, "C2.1" : { "home" : "DwStar" }}
world . state . ethics = { "C2.0" : { "d" : 100.0 }, "C2.1" : { "d" : 100.0 }}
var source : Dictionary = world . state . duplicate ( true )
var single : Dictionary = source . duplicate ( true )
var split : Dictionary = source . duplicate ( true )
Parameters . advance ( source , single , rules , 1.0e6 )
for i in 10 : Parameters . advance ( source , split , rules , 1.0e5 )
check ( is_equal_approx ( single . trends . Integration , 0.018 ), "Trend integrates elapsed years and doubled stage weights" )
for key in Parameters . TRENDS :
check ( is_equal_approx ( single . trends [ key ], split . trends [ key ]), "Trend is independent of frame partition: " + key )
source . ethics [ "C2.0" ] . d = 1000000.0
var larger : Dictionary = world . state . duplicate ( true )
Parameters . advance ( source , larger , rules , 1.0e6 )
check ( is_equal_approx ( larger . trends . Integration , single . trends . Integration ), "Population proportions determine trend influence" )
world . state . trends . Integration = 0.99
Parameters . advance ( source , world . state , rules , 1.0e8 )
check ( world . state . civilization_stats [ "trend:Integration" ] == 2.0 , "Long steps process every crossed threshold" )
check ( is_equal_approx ( world . state . trends . Integration , 0.79 ), "Threshold crossing preserves the fractional remainder" )
check ( world . state . world_parameters . Federation > 1.0 or world . state . world_parameters . Enlightenment > 1.0 or world . state . world_parameters . Order > 1.0 , "Integration events change the world" )
var restored : Dictionary = bytes_to_var ( var_to_bytes ( world . state ))
Parameters . advance ( source , world . state , rules , 1.0e8 )
Parameters . advance ( source , restored , rules , 1.0e8 )
check ( world . state == restored , "Trend events resume identically after serialization" )
Parameters . advance ( source , world . state , rules , 1.0e12 )
check ( world . state . trends . Integration >= 0.0 and world . state . trends . Integration < 1.0 , "Very large intervals finish with a valid trend fraction" )
check ( world . state . world_parameters . Agg >= 1.0 , "Repeated integration events cannot reduce aggression below the scale" )
var payload : Dictionary = { "format_version" : 2 , "app_version" : "test" , "ui" : { "current_page" : 1 }, "state" : world . state }
var manager : Node = root . get_node ( "SaveManager" )
check ( manager . validate_data ( payload ) == "" , "New parameters and trends pass save validation" )
var old : Dictionary = payload . duplicate ( true )
old . state . erase ( "world_parameters" )
old . state . erase ( "trends" )
check ( manager . validate_data ( old ) == "" , "Existing current-format saves remain readable" )
payload . state . world_parameters . Agg = 20.0
check ( manager . validate_data ( payload ) != "" , "Out-of-range scales are rejected" )
dispose ( world )
for sample in [[ 1e-7 , 0.0 ], [ 1e-6 , 0.5 ], [ 1e-5 , 1.0 ], [ 0.9 , 0.0 ], [ 0.95 , 0.5 ], [ 1.0 , 1.0 ]]:
check ( is_equal_approx ( Parameters . density_display ( sample [ 0 ]) . position , sample [ 1 ]), "Density boundary " + str ( sample [ 0 ]))
# The fixture overrides saving/loading; the player's save is never accessed.
var scene = load ( "res://world/world.tscn" ) . instantiate ()
var stage = scene . get_node ( "Stage" )
stage . owniverse . free ()
stage . set_script ( load ( "res://tests/fixtures/ui_stage.gd" ))
root . add_child ( scene )
await process_frame
await process_frame
stage . owniverse . state . energy = Parameters . INITIAL_ENERGY / 4.0
stage . owniverse . state . world_parameters . Bur = 19.0
stage . owniverse . state . trends . Integration = 0.75
stage . world_indicators . update ( stage . owniverse )
2026-09-28 22:32:52 +03:00
var warning : TextureRect = scene . get_node ( "Background/WarningBorder" )
check ( warning . mouse_filter == Control . MOUSE_FILTER_IGNORE , "Warning overlay does not block input" )
var environments : Array = [
[ 1.0e-7 , "ff0000ff" ], [ 1.0e-6 , "df2020bf" ], [ 1.0e-5 , "c040407f" ],
[ 0.1 , "00000000" ], [ 0.9 , "40a0c07f" ], [ 0.97 , "20b0dfbf" ], [ 1.0 , "00c0ffff" ],
[ 0.1 , "00000000" ],
]
for sample in environments :
check ( Parameters . density_warning_color ( sample [ 0 ]) . is_equal_approx ( Color . html ( sample [ 1 ])), "Unity warning threshold: " + str ( sample [ 0 ]))
stage . owniverse . state . amount . H = 1e14
stage . world_indicators . update ( stage . owniverse )
check ( warning . self_modulate . is_equal_approx ( Color . html ( "00c0ffff" )), "Compression warning uses current universe density" )
stage . owniverse . state . amount . H = 0.0
stage . owniverse . state . amount . S = 1e24
stage . world_indicators . update ( stage . owniverse )
check ( warning . self_modulate . is_equal_approx ( Color . html ( "ff0000ff" )), "Rip warning replaces compression warning" )
stage . owniverse . state . amount . S = 0.0
stage . world_indicators . update ( stage . owniverse )
check ( warning . self_modulate . a == 0.0 , "Warning clears when density returns to normal" )
2026-09-28 22:19:13 +03:00
for bar in stage . world_indicators . energy_bars :
check ( bar . scale . x == 0.25 , "Energy fill is synchronized on both pages" )
var pointer : Control = stage . world_indicators . pointers . Bur
check ( is_equal_approx ( pointer . position . x + pointer . size . x / 2.0 , 304.0 ), "Burnability pointer reaches the correct scale endpoint" )
check ( stage . world_indicators . trend_bars [ 1 ] . scale . y == 0.75 , "Trend bar displays its stored level" )
for locale in [ "en" , "ru" ]:
global . Locale = locale
for id in [ "Energy" , "Density" , "Burnability" , "Explosiveness" , "Aggression" , "Trends" ]:
var description : String = Descriptions . render ( stage . owniverse , global , id , "Indicator" )
check ( not description . contains ( "—" ) and not description . contains ( "%value" ), "Resolved indicator description: " + locale + "/" + id )
dispose ( stage . owniverse )
scene . free ()
print ( "World indicators: %d checks, %d failures" % [ checks , failures ])
quit ( 0 if failures == 0 else 1 )