extends RefCounted const GREEN = "#40cc40" const RED = "#ff6060" const GREY = "#888888" 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._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) 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