class_name CreatureView extends Control ## Zeichnet ein Wesen auf dem Feld. Bleibt über Zustandsänderungen bestehen (für Animationen). signal pressed(view: CreatureView, pos: Vector2) # linke Maustaste gedrückt; der Kampf macht daraus Klick oder Ziehen signal double_clicked(view: CreatureView) # Doppelklick: eigenes Wesen greift das Leben des Gegners an signal hover(card: Cards.Card, entered: bool) var creature: Game.Creature var border = null var width := 2 var flash := false # kurz rot: wurde gerade angegriffen var slot: Vector2 # Zielposition im Raster var busy := false # wird gerade animiert (kein Neupositionieren) var matchup := 0 # Elementvorteil des gewählten Angreifers gegen dieses fremde Wesen (+1/-1); die Werte zeigen dann, was ihn erwartet var attack_shift := 0 # eigener Angreifer: Elementvorteil gegen das Ziel unter der Maus var doomed := false # stirbt bei dem Angriff, der gerade unter der Maus liegt var secret := false # verdecktes fremdes Wesen: nur der Rücken ist zu sehen var hold := 0.0 # Fortschritt des Verschmelzens, wenn eine Karte darüber gehalten wird (0..1) func _init(cr: Game.Creature, sz: Vector2, b = null, w: int = 2) -> void: creature = cr border = b width = w custom_minimum_size = sz size = sz pivot_offset = sz / 2 set_process(Style.rarity_animated(rarity())) # bewegter Glanz mouse_filter = Control.MOUSE_FILTER_STOP mouse_entered.connect(func(): hover.emit(creature.card, true)) mouse_exited.connect(func(): hover.emit(creature.card, false)) func _process(_delta: float) -> void: queue_redraw() func _gui_input(event: InputEvent) -> void: if event is InputEventMouseButton and event.pressed and event.button_index == MOUSE_BUTTON_LEFT: accept_event() if event.double_click: double_clicked.emit(self) else: pressed.emit(self, event.global_position) func rarity() -> String: var owner = creature.owner() return creature.card.rarity_in(owner.looks if owner != null else {}) func _draw() -> void: var rect := Rect2(Vector2.ZERO, size) if secret: _draw_back(rect) _draw_hold() return var small := size.x < 100 var rar := rarity() var seed := hash(creature.card.id) + creature.uid if rar != "Common": Style.glow(self, rect, Style.rarity_color(rar, seed), 6, 6) Style.fill_elements(self, rect, creature.card.elements, 6) var gc := Vector2(size.x / 2, size.y * 0.5) if creature.card.is_combo(): Style.element_medallion(self, gc, size.x * 0.42, creature.card.elements) Style.glyph(self, creature.card, gc, size.x * 0.75, 0.3, Style.rarity_relief(rar)) Style.rarity_sheen(self, rect, rar, seed, rect) var bcol: Color = border if border != null else Style.rarity_frame(rar, seed) if flash: bcol = Style.RED Style.border(self, rect, bcol, 4 if flash else width, 6) var fs := 11 if small else 13 var name_w: float = size.x - 6 var nf := Style.fit_size(creature.card.title(), true, fs, name_w) draw_rect(Rect2(2, 2, size.x - 4, Style.fs(fs) + 8), Color(0.05, 0.05, 0.08, 0.7)) Style.text(self, Style.fit(creature.card.title(), true, Style.fs(nf), name_w), nf, Style.rarity_name_color(rar, seed), Vector2(3 + name_w / 2, 6), "midtop", true) # Elementbonus als ein Abzeichen rechts unter dem Namen; die Symbole rücken dafür nach links var badge := "" var bw := 0.0 if creature.aura != 0: badge = "+%d" % creature.aura if creature.aura > 0 else "−%d" % -creature.aura bw = Style.FONT_BOLD.get_string_size(badge, HORIZONTAL_ALIGNMENT_LEFT, -1, Style.fs(10)).x + 8 var by := Style.fs(fs) + 13 draw_rect(Rect2(size.x - bw - 4, by, bw, 16), Color(0.05, 0.05, 0.08, 0.75)) Style.text(self, badge, 10, Style.GREEN if creature.aura > 0 else Style.RED, Vector2(size.x - 4 - bw / 2, by + 8), "center", true) # Eigenschaften als Symbole in der Farbe des Elements, das sie gibt var icon := 7.0 if small else 9.0 var kws := creature.keywords() var avail := size.x - (bw + 8 if badge != "" else 0.0) var x := avail / 2 - (kws.size() * (icon * 2 + 6) - 6) / 2.0 var y := Style.fs(fs) + 14 + icon for k in kws: var col := Color("f2f2f6") for e in creature.card.elements: if Cards.ELEMENT_KEYWORD.get(e, "") == k: col = Style.lighter(Cards.ELEMENT_COLORS[e], 0.45) Style.keyword_icon(self, k, Vector2(x + icon, y), icon, col) x += icon * 2 + 6 _draw_stats(15 if small else 17, 12.0 if small else 14.0) Style.rarity_gem(self, rar, Vector2(size.x / 2, size.y - 9), 5, seed) if creature.hidden: draw_rect(rect, Color(0.05, 0.05, 0.1, 0.55)) Style.text_outlined(self, tr("verdeckt"), 12, Style.TEXT, Vector2(size.x / 2, size.y / 2), "center", 3) if doomed: draw_rect(Rect2(0, size.y * 0.5 - 12, size.x, 24), Color(0.05, 0.02, 0.02, 0.8)) Style.text_outlined(self, tr("stirbt"), 14, Style.RED, Vector2(size.x / 2, size.y * 0.5), "center", 3) Style.rarity_sparkle(self, rect, rar, seed) _draw_hold() ## Ring, der sich füllt, solange eine Karte zum Verschmelzen darüber gehalten wird. func _draw_hold() -> void: if hold <= 0.0: return var c := size / 2 var r := minf(size.x, size.y) * 0.3 draw_circle(c, r + 6, Color(0, 0, 0, 0.55)) draw_arc(c, r, -PI / 2, -PI / 2 + TAU * hold, 40, Style.GOLD, 5.0, true) ## Verdecktes fremdes Wesen: ein Kartenrücken. func _draw_back(rect: Rect2) -> void: var bcol: Color = border if border != null else Style.GOLD if flash: bcol = Style.RED draw_style_box(Style.box(Color("3c285a"), 6, bcol, 4 if flash else maxi(width, 2)), rect) Style.border(self, rect.grow(-10), Color("5a3c82"), 2, 6) Style.text(self, "?", 36, Style.GOLD, size / 2, "center", true) ## Angriff und Leben für den Angriff, der gerade vorbereitet wird. Fremdes Wesen bei gewähltem ## Angreifer: sein Konter gegen ihn (im Nachteil 1 weniger, im Vorteil 1 mehr, auch bei 0 Angriff), ## das Leben bleibt echt. Eigener Angreifer über einem Ziel: sein Angriff mit Elementvorteil. func shown_stats() -> Array: if matchup != 0: var atk := maxi(0, creature.power() - matchup) return [atk, creature.health] if attack_shift != 0: return [maxi(0, creature.power() + attack_shift), creature.health] return [creature.power(), creature.health] ## Angriff gelb, Leben blau; die Zahl wird grün, wenn sie für den aktuellen Angriff steigt, rot, wenn sie sinkt. func _draw_stats(f: int, r: float) -> void: var shown := shown_stats() var atk: int = shown[0] var hp: int = shown[1] var atk_text := Style.GREEN if atk > creature.power() else (Style.RED if atk < creature.power() else Color.WHITE) var hp_text := Style.GREEN if hp > creature.health else (Style.RED if hp < creature.health else Color.WHITE) Style.stat_circle(self, Vector2(r - 1, size.y - r + 1), r, str(atk), Style.AMBER, f, atk_text) Style.stat_circle(self, Vector2(size.x - r + 1, size.y - r + 1), r, str(hp), Style.LIFE, f, hp_text)