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]) world.entities[id] = entity 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 world.entities["N"].life_product = {} world.entities["N"].product_per_year_type = "H" world.entities["N"].product_per_year_amount = 10.0 world.entities["N"].auto = 0.0 world.state.amount.N = 1.0 return world func dispose(world) -> void: for entity in world.entities.values(): entity.free() world.free() func run() -> void: var world = fixture() var rd = world.entities.RD 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"]: check(world.entities[id].blastability, "Blast vulnerable: " + id) for id in ["RP", "GG", "AB", "C1.3", "C1.4", "C1.5"]: check(not world.entities[id].blastability, "Blast protected: " + id) # Actual GI table: HRG -> SN, with 1% GRB; no random rounding. var totals: Dictionary = {} for i in 100: var products: Dictionary = world._evolution_products(world.state, world.entities.HRG, 1.0) 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)) check(world._evolution_products(world.state, world.entities.HRG, 37.0) == restored._evolution_products(restored.state, restored.entities.HRG, 37.0), "Evolution carry survives serialization") 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 world._append_batch(world.state, "RD", 4.0, 0.0, 0.0) var lifespan: float = rd.lifespan var width: float = rd.lifespan_delta world._evolve_batches(world.state, lifespan) check(world.state.amount.RD == 4.0, "Window start does not kill the whole batch") world._evolve_batches(world.state, lifespan + width / 4.0) check(world.state.amount.RD == 3.0 and world.state.amount.TWD == 1.0, "One quarter of a batch evolves") world._evolve_batches(world.state, lifespan + width / 2.0) check(world.state.amount.RD == 2.0 and world.state.amount.TWD == 2.0, "Half the batch evolves") world._evolve_batches(world.state, lifespan + width) 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: world._create_planets(world.state, "RD", 1.0, 0.0, 0.0, 1.0) 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") check(saves.validate_data({"format_version": 2, "app_version": "", "ui": {"current_page": 0}, "state": world.state}) == "", "Planet carry save validates") restored = fixture() restored.state = bytes_to_var(var_to_bytes(world.state)) world._create_planets(world.state, "RD", 37.0, 0.0, 0.0, 0.7) restored._create_planets(restored.state, "RD", 37.0, 0.0, 0.0, 0.7) 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} world._append_batch(world.state, "RD", 4.0, 0.0, 0.0) world._evolve_batches(world.state, lifespan + width / 2.0) 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") world._evolve_batches(world.state, lifespan + width) 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") check(saves.validate_data({"format_version": 2, "app_version": "", "ui": {"current_page": 0}, "state": world.state}) == "", "Inherited state validates") 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} world._append_batch(world.state, "WS", 2.0, 0.0, 0.0) world._evolve_batches(world.state, world.entities.WS.lifespan + world.entities.WS.lifespan_delta) var physical: Dictionary = world._physical_amounts(world.state) 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} world._apply_blast(world.state, 5.0, {"blast": 1.0, "density": 1.0}) 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") world._apply_blast(world.state, 1e6, {"blast": 1.0, "density": 1.0}) 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: world._apply_blast(world.state, 1.0, {"blast": 1.0, "density": 0.1}) 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 world._append_batch(world.state, "SN", 1.0, 0.0, 0.0) world._evolve_batches(world.state, 2.0) 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") check(saves.validate_data({"format_version": 2, "app_version": "", "ui": {"current_page": 0}, "state": world.state}) == "", "Blast state validates") dispose(world) world = fixture() world.state.amount.H = 1000.0 world.state.amount.Met = 100.0 check(world.produce("RD", 100.0) == 100.0, "Manual star creation succeeds") 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) # Two simultaneous successors share surviving planets in the same 99:1 ratio. world = fixture() world.entities.HRG.destroy_level = 0 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}] world._evolve_batches(world.state, 0.1) 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)