da03ba11c0
- Introduced `quantity_math.gd` for arithmetic operations including allocation, normalization, and accumulation of quantities without scene tree dependencies. - Created `entity_catalog.gd` to manage entity definitions, groups, and event indexes, ensuring separation from simulation state and UI. - Implemented `item_presentation.gd` for read-only projections of simulation state, handling amounts and unlock conditions for UI elements. - Updated `civilization_evolution.gd` and `civilization_state.gd` to utilize new quantity math functions, improving code clarity and maintainability. - Enhanced tests in `test_quantity_catalog.gd` to validate new functionality and ensure correctness of mathematical operations. - Revised documentation to reflect changes in module structure and functionality.
102 lines
5.1 KiB
GDScript
102 lines
5.1 KiB
GDScript
extends RefCounted
|
||
|
||
const GREEN = "#40cc40"
|
||
const RED = "#ff6060"
|
||
const GREY = "#888888"
|
||
const Parameters = preload("res://world/owniverse/world_parameters.gd")
|
||
|
||
static func number(value: float, digits: int = 0) -> String:
|
||
if not is_finite(value):
|
||
return "—"
|
||
if absf(value) >= 1e5:
|
||
var exponent: int = int(floor(log(absf(value)) / log(10.0)))
|
||
return "%.4fE%+d" % [value / pow(10.0, exponent), exponent]
|
||
return "%.*f" % [digits, value]
|
||
|
||
static func colored(text: String, color: String) -> String:
|
||
return "[color=" + color + "]" + text + "[/color]"
|
||
|
||
static func matches(world, id: String) -> Array:
|
||
var result: Array = []
|
||
for key in world.entities:
|
||
var entity = world.entities[key]
|
||
if key == id or entity.count_as == id or entity.group_as == id:
|
||
if not world.catalog.is_group(key):
|
||
result.append(key)
|
||
return result
|
||
|
||
static func quantities(world, id: String) -> Dictionary:
|
||
var free: float = 0.0
|
||
var total: float = 0.0
|
||
var physical: Dictionary = world._physical_amounts(world.state)
|
||
for key in matches(world, id):
|
||
free += world.state.amount.get(key, 0.0)
|
||
total += physical.get(key, 0.0)
|
||
if id == "SMBH":
|
||
free = world.state.amount.get(id, 0.0)
|
||
total = free
|
||
return {"free": free, "total": total}
|
||
|
||
static func costs(world, global: Node, id: String) -> String:
|
||
if not world.entities.has(id):
|
||
return ""
|
||
var lines: PackedStringArray = []
|
||
for requirements in [world.entities[id].cost, world.entities[id].bind]:
|
||
for resource in requirements:
|
||
var required: float = requirements[resource]
|
||
if required < 0.0:
|
||
continue
|
||
var available: float = floorf(world._available(world.state, resource))
|
||
var name: String = str(global.get_template(resource, "Entity", "Name").get("text", resource))
|
||
lines.append(colored(name + ": " + number(required) + " (" + number(available) + ")", GREEN if available >= required else RED))
|
||
return "\n".join(lines)
|
||
|
||
static func variables(world, global: Node, id: String, rate: float = 0.0) -> Dictionary:
|
||
var counts: Dictionary = quantities(world, id)
|
||
var show_total: bool = false
|
||
for key in matches(world, id):
|
||
show_total = show_total or world.entities[key].group_as == "Planet"
|
||
var amount: String = number(counts.total if show_total else counts.free) if world.entities.has(id) else "—"
|
||
if not show_total and counts.total > counts.free:
|
||
amount += " " + colored("(" + number(counts.total) + ")", GREY)
|
||
if rate != 0.0:
|
||
amount += " | " + colored(("−" if rate < 0.0 else "+") + number(absf(rate), 1), RED if rate < 0.0 else GREEN)
|
||
var physical: Dictionary = world._physical_amounts(world.state)
|
||
var voids: float = 0.0
|
||
for key in physical:
|
||
voids += physical[key] * world.entities[key].voids
|
||
var he: float = world.state.amount.get("He", 0.0)
|
||
var h: float = world.state.amount.get("H", 0.0)
|
||
var mixture: String = "—"
|
||
if he + h > 0.0:
|
||
mixture = "He: " + number(100.0 * he / (he + h), 2) + "% / H: " + number(100.0 * h / (he + h), 2) + "%"
|
||
var environment: Dictionary = world.stellar_environment(world.state)
|
||
return {
|
||
"amount": amount, "colored costs": costs(world, global, id),
|
||
"lifespan": number(world.entities[id].lifespan) if world.entities.has(id) else "—",
|
||
"voids": number(voids), "he / h": "\n" + mixture,
|
||
"metallicity": number(environment.metallicity * 100.0, 2) + "%",
|
||
"энергия": number(world.state.energy), "плотность": number(environment.density, 6),
|
||
"лет в секунду": number(world.state.speed_in_year),
|
||
"amount1": "—", "amount2": "—", "amount3": "—", "amount4": "—",
|
||
}
|
||
|
||
static func render(world, global: Node, id: String, category: String = "Entity", rate: float = 0.0) -> String:
|
||
var values: Dictionary = variables(world, global, id, rate)
|
||
if category == "Indicator":
|
||
if id == "Density":
|
||
id = Parameters.density_display(world.stellar_environment(world.state).density).mode
|
||
var scales: Dictionary = {"Burnability": "Bur", "Explosiveness": "Exp", "Aggression": "Agg"}
|
||
if scales.has(id):
|
||
var level: float = Parameters.value(world.state, scales[id])
|
||
values.amount = number(level, 1 if level != floorf(level) else 0)
|
||
values.scale = global.render_template(global.get_template("Scale" + str(clampi(roundi(level), 1, 19)), "Indicator", "Scale"), {})
|
||
if id == "Trends":
|
||
for trend in Parameters.TRENDS:
|
||
values[trend.to_lower()] = number(world.state.get("trends", {}).get(trend, 0.0) * 100.0, 2) + "%"
|
||
if id == "Energy":
|
||
values["энергия"] = number(world.state.energy) + " (" + number(clampf(world.state.energy / Parameters.INITIAL_ENERGY, 0.0, 1.0) * 100.0, 2) + "%)"
|
||
var title: String = global.render_template(global.get_template(id, category, "Name"), values)
|
||
var body: String = global.render_template(global.get_template(id, category, "Description"), values)
|
||
return "[b]" + (title if title != "" else id) + "[/b]\n" + body
|