class_name LuneStats extends RefCounted ## Display figures taken from the real unit definitions and combat rules: damage per hit, ## one attack per second times the attack tempo bonus, range, armour and damage type with ## the damage matrix (LuneUnit.DAMAGE_MATRIX). Nothing is invented; values are only formatted. const ROLE_NAMES: Dictionary = {"front": "Tank", "melee": "Nahkampf", "ranged": "Fernkampf", "splash": "Flächenschaden", "support": "Support"} const ROLE_GLYPHS: Dictionary = {"front": "tank", "melee": "melee", "ranged": "ranged", "splash": "splash", "support": "support"} static func role_name(role: String) -> String: return ROLE_NAMES.get(role, role) static func role_glyph(role: String) -> String: return ROLE_GLYPHS.get(role, "melee") ## Armour class the damage type hits for 130 % / 75 % (DAMAGE_MATRIX). static func strong_against(attack_type: int) -> String: var row: Array = LuneUnit.DAMAGE_MATRIX[clampi(attack_type, 0, 2)] return DataCatalog.ARMOR_NAMES[row.find(1.30)] static func weak_against(attack_type: int) -> String: var row: Array = LuneUnit.DAMAGE_MATRIX[clampi(attack_type, 0, 2)] return DataCatalog.ARMOR_NAMES[row.find(0.75)] static func hit_damage(definition: Dictionary) -> float: return float(definition.get("damage", 0.0)) * (1.0 + float(definition.get("damage_bonus", 0.0))) static func attacks_per_second(definition: Dictionary) -> float: return 1.0 + clampf(float(definition.get("attack_speed_bonus", 0.0)), -.25, .5) ## Stat rows [glyph, name, value] for tooltips and detail panels. static func rows(definition: Dictionary, with_move: bool = false) -> Array: var attack_type: int = int(definition.get("attack_type", 0)) var armor_type: int = int(definition.get("armor_type", 0)) var reduction: float = float(definition.get("reduction_bonus", 0.0)) var result: Array = [ ["heart", "Leben", LuneUiTheme.number(float(definition.get("max_hp", 0.0)))], ["sword", "Schaden/Treffer", LuneUiTheme.decimal(hit_damage(definition))], ["tempo", "Angriffstempo", "%s /s" % LuneUiTheme.decimal(attacks_per_second(definition), 2)], ["range", "Reichweite", "%s m" % LuneUiTheme.decimal(float(definition.get("attack_range", 0.0)))], ["armor", "Rüstung", DataCatalog.ARMOR_NAMES[clampi(armor_type, 0, 2)] + (" · −%d %% Schaden" % int(round(reduction * 100.0)) if reduction > 0.0 else "")], ["splash", "Angriffsart", "%s · stark gegen %s" % [DataCatalog.DAMAGE_NAMES[clampi(attack_type, 0, 2)], strong_against(attack_type)]], ] if with_move: result.append(["move", "Lauftempo", "%s m/s" % LuneUiTheme.decimal(float(definition.get("speed", 0.0)))]) var regen: float = float(definition.get("regen", 0.0)) if regen > 0.0: result.append(["heart", "Regeneration", "%s %% Leben/s" % LuneUiTheme.decimal(regen * 100.0)]) var splash: float = float(definition.get("item_splash", 0.0)) if splash > 0.0: result.append(["splash", "Splitter", "%d %% an bis zu 2 Gegner" % int(round(splash * 100.0))]) return result ## Compact pairs [glyph, "Name Wert"] for narrow panels (two per row). static func short_rows(definition: Dictionary) -> Array: var attack_type: int = clampi(int(definition.get("attack_type", 0)), 0, 2) return [ ["heart", "Leben %s" % LuneUiTheme.number(float(definition.get("max_hp", 0.0)))], ["sword", "Schaden %s" % LuneUiTheme.decimal(hit_damage(definition))], ["tempo", "Tempo %s/s" % LuneUiTheme.decimal(attacks_per_second(definition), 2)], ["range", "Reichweite %s m" % LuneUiTheme.decimal(float(definition.get("attack_range", 0.0)))], ["armor", "Rüstung %s" % DataCatalog.ARMOR_NAMES[clampi(int(definition.get("armor_type", 0)), 0, 2)]], ["splash", "%s › %s" % [DataCatalog.DAMAGE_NAMES[attack_type], strong_against(attack_type)]], ] ## "Schaden pro Sekunde" from hit damage and tempo, without abilities or type modifiers. static func dps(definition: Dictionary) -> float: return hit_damage(definition) * attacks_per_second(definition) ## Tooltip content for a troop type (shop cards, army chips). static func troop_tip(type_id: String, role: String, extra: String = "") -> Dictionary: var data: Dictionary = DataCatalog.get_unit(type_id) var upgrade: String = str(data.get("upgrade_id", "")) var note: String = "" if not upgrade.is_empty(): var next: Dictionary = DataCatalog.get_unit(upgrade) note = "Aufwertung: %s für %d Gold (Leben %s → %s, Schaden %s → %s)" % [next.display_name, int(next.cost), LuneUiTheme.number(data.max_hp), LuneUiTheme.number(next.max_hp), LuneUiTheme.decimal(data.damage), LuneUiTheme.decimal(next.damage)] else: note = "Höchste Stufe." return {"title": str(data.display_name), "glyph": role_glyph(role), "subtitle": "%s · Stufe %s · %d Gold" % [role_name(role), "II" if int(type_id.substr(1)) % 2 == 0 else "I", int(data.cost)], "stats": rows(data), "text": str(data.get("ability_description", "")), "note": note, "warn": extra}