Files
owniverse/world/owniverse/world_parameters.gd
T

113 lines
5.2 KiB
GDScript

extends RefCounted
const INITIAL_ENERGY = 1.0e27
const TRENDS = ["Antitheism", "Integration", "Xenocide", "Reconstruction", "Spirituality"]
const WEIGHTS = {
"m": [0, 2, 2, 0, 6], "l": [6, 1, 1, 2, 0],
"w": [2, 0, 6, 0, 2], "d": [0, 6, 0, 1, 3],
"c": [1, 3, 3, 3, 0], "b": [3, 0, 0, 6, 1],
}
static func defaults() -> Dictionary:
return {"Bur": 10.0, "Exp": 10.0, "Agg": 10.0,
"Federation": 1.0, "Enlightenment": 1.0, "Order": 1.0}
static func trend_defaults() -> Dictionary:
return {"Antitheism": 0.0, "Integration": 0.0, "Xenocide": 0.0,
"Reconstruction": 0.0, "Spirituality": 0.0}
static func value(source: Dictionary, key: String) -> float:
return source.get("world_parameters", {}).get(key, defaults().get(key, 1.0))
static func effective(source: Dictionary, key: String) -> float:
return pow(10.0, (clampf(value(source, key), 1.0, 19.0) - 10.0) / 9.0)
static func life_modifiers(source: Dictionary) -> Dictionary:
var aggression: float = effective(source, "Agg")
return {"progress": aggression,
"degradation": (1.0 - (1.0 - aggression) / 20.0) / value(source, "Order"),
"war": 1.0 - (1.0 - aggression) / 5.0,
"colonization": 1.0 - (1.0 - aggression) / 2.0}
static func production(source: Dictionary, entity) -> float:
if entity.event_group == "SNGRBB":
return effective(source, "Exp")
if entity.group_as == "Star":
var burn: float = effective(source, "Bur")
return sqrt(burn) if burn > 1.0 else burn
return 1.0
static func density_display(density: float) -> Dictionary:
if density <= 1.0e-5:
# Unity had log10(density) - 7 here; +7 maps 1e-7..1e-5 to 0..1.
return {"mode": "DensityRip", "position": clampf((log(maxf(density, 1e-7)) / log(10.0) + 7.0) / 2.0, 0.0, 1.0)}
if density >= 0.9:
return {"mode": "DensityCrunch", "position": clampf((density - 0.9) * 10.0, 0.0, 1.0)}
return {"mode": "Density", "position": clampf(log(density * 1.0e5) / log(9.0e4), 0.0, 1.0)}
## Unity ApocalypseCheck thresholds and WarningUI colors; visual warning only.
static func density_warning_color(density: float) -> Color:
if density >= 1.0: return Color.html("00c0ffff")
if density >= 0.97: return Color.html("20b0dfbf")
if density >= 0.9: return Color.html("40a0c07f")
if density <= 1.0e-7: return Color.html("ff0000ff")
if density <= 1.0e-6: return Color.html("df2020bf")
if density <= 1.0e-5: return Color.html("c040407f")
return Color(0.0, 0.0, 0.0, 0.0)
## Integrate the population present at the start of the simulation interval.
## Thresholds use whole event counts; no per-year loop at high speeds.
static func advance(previous: Dictionary, target: Dictionary, rules: Dictionary, years: float) -> void:
if years <= 0.0: return
if not target.has("world_parameters"): target.world_parameters = defaults()
if not target.has("trends"): target.trends = trend_defaults()
var rates: Array = [0.0, 0.0, 0.0, 0.0, 0.0]
var stages: Array = []
for id in rules:
if str(rules[id].home) != "": stages.append(id)
stages.sort()
var weight: float = 1.0
for id in stages:
var population: Dictionary = previous.get("ethics", {}).get(id, {})
var count: float = 0.0
for n in population.values(): count += n
if count > 0.0:
for ethic in population:
for i in TRENDS.size():
rates[i] += population[ethic] / count * WEIGHTS[ethic][i] * weight
weight *= 2.0
for i in TRENDS.size():
var name: String = TRENDS[i]
var accumulated: float = target.trends[name] + rates[i] * years * 1.0e-9
var events: float = floorf(snappedf(accumulated, 1.0e-12))
target.trends[name] = maxf(0.0, accumulated - events)
if events <= 0.0: continue
var key: String = "trend:" + name
target.civilization_stats[key] = target.civilization_stats.get(key, 0.0) + events
if name == "Integration": _integration(target, events)
static func _integration(target: Dictionary, events: float) -> void:
# Equal-probability outcomes in Unity. Use a saved RNG and bounded aggregate
# sampling for large steps, so thousands of triggers do not stall a frame.
var rng := RandomNumberGenerator.new()
rng.seed = 76123
if target.civilization_stats.has("trend_rng"):
rng.state = int(target.civilization_stats.trend_rng)
var counts: Array = [0.0, 0.0, 0.0]
if events <= 256.0:
for i in int(events): counts[rng.randi_range(0, 2)] += 1.0
else:
counts[0] = clampf(roundf(rng.randfn(events / 3.0, sqrt(events * 2.0 / 9.0))), 0.0, events)
var rest: float = events - counts[0]
counts[1] = clampf(roundf(rng.randfn(rest / 2.0, sqrt(rest / 4.0))), 0.0, rest)
counts[2] = rest - counts[1]
target.civilization_stats.trend_rng = rng.state
var parameters: Dictionary = target.world_parameters
parameters.Agg = maxf(1.0, parameters.Agg - counts[0] - counts[1])
parameters.Federation += counts[0] * 0.1
parameters.Enlightenment += counts[1] * 0.2
parameters.Order += counts[2] * 0.1
for i in 3:
var key: String = ["Federation", "Enlightenment", "Order"][i]
target.civilization_stats[key] = target.civilization_stats.get(key, 0.0) + counts[i]