update
This commit is contained in:
1 parent
1d563b9eec
commit
04fe9716e8
22 files changed
+764
-151
No files matched your search
@@ -113,7 +113,7 @@ func _ready() -> void:
|
||||
## Eigener Stapel und Kartenstufen und das eigene Merkmal (nach Kapitel 1).
|
||||
func own_rules() -> Dictionary:
|
||||
var p: Profile = app.profile
|
||||
var rules := {"looks": p.looks(), "deck": p.deck_cards()}
|
||||
var rules := {"looks": p.looks(), "deck": p.deck_cards(), "bonus_attack": p.skill("stark"), "bonus_health": p.skill("zaeh"), "cheap_from": Skills.cheap_from(p.skill("sparsam"))}
|
||||
var perks := p.battle_perks()
|
||||
if not perks.is_empty():
|
||||
rules["human_perks"] = perks
|
||||
|
||||
@@ -12,7 +12,7 @@ var node_buttons: Array = []
|
||||
|
||||
func _ready() -> void:
|
||||
var p: Profile = app.profile
|
||||
chapter = mini(Campaign.chapter(p.campaign_stage), Campaign.CHAPTER_ELEMENTS.size())
|
||||
chapter = mini(Campaign.chapter(p.campaign_stage), Campaign.chapters())
|
||||
selected = mini(p.campaign_stage, Campaign.total() - 1)
|
||||
build()
|
||||
|
||||
@@ -24,16 +24,18 @@ func build() -> void:
|
||||
Style.header(self, "Kampagne", func(): app.show_screen(MenuScreen.new()))
|
||||
var n := Campaign.STAGES_PER_CHAPTER
|
||||
var x := 40
|
||||
for c in Campaign.CHAPTER_ELEMENTS.size():
|
||||
var b := Style.button(self, "Kapitel %d" % (c + 1), Rect2(x, 88, 130, 38), set_chapter.bind(c + 1), Style.PRIMARY if chapter == c + 1 else null)
|
||||
for c in Campaign.chapters():
|
||||
var b := Style.button(self, "Kapitel %d" % (c + 1), Rect2(x, 88, 96, 38), set_chapter.bind(c + 1), Style.PRIMARY if chapter == c + 1 else null)
|
||||
b.add_theme_font_size_override("font_size", 14)
|
||||
b.disabled = p.campaign_stage < c * n
|
||||
x += 138
|
||||
x += 104
|
||||
var element := Campaign.element_of(chapter)
|
||||
Style.label(self, tr(element), 20, Cards.ELEMENT_COLORS[element], Rect2(0, 136, 1280, 30), "center", true)
|
||||
var round_text := tr(element) if chapter <= Campaign.CHAPTER_ELEMENTS.size() else tr("%s mit Effektkarten") % tr(element)
|
||||
Style.label(self, round_text, 20, Cards.ELEMENT_COLORS[element], Rect2(0, 136, 700, 30), "center", true)
|
||||
if p.perk_unlocked():
|
||||
Style.label(self, "Dein Merkmal:", 15, Style.MUTED, Rect2(740, 96, 150, 24), "right")
|
||||
Style.label(self, "Dein Merkmal:", 15, Style.MUTED, Rect2(740, 140, 150, 24), "right")
|
||||
perk_box = OptionButton.new()
|
||||
perk_box.position = Vector2(900, 88)
|
||||
perk_box.position = Vector2(900, 132)
|
||||
perk_box.size = Vector2(340, 38)
|
||||
perk_box.add_item("keins")
|
||||
var keys: Array = Game.PERKS.keys()
|
||||
|
||||
@@ -24,6 +24,7 @@ func _ready() -> void:
|
||||
["Kapitel 3 frei", func(): app.profile.campaign_stage = maxi(app.profile.campaign_stage, 20)],
|
||||
["Kapitel 4 frei", func(): app.profile.campaign_stage = maxi(app.profile.campaign_stage, 30)],
|
||||
["Kapitel 5 frei", func(): app.profile.campaign_stage = maxi(app.profile.campaign_stage, 40)],
|
||||
["Werkstatt frei", func(): app.profile.campaign_stage = maxi(app.profile.campaign_stage, 50)],
|
||||
["Kampagne zurücksetzen", func(): app.profile.campaign_stage = 0]]],
|
||||
["Sammlung", [["Alle Karten (Common)", func(): _give_all(0)], ["Alle Karten Ultimate Rare", func(): _give_all(4)],
|
||||
["Eigene Karten +1 Stufe", func():
|
||||
@@ -36,9 +37,9 @@ func _ready() -> void:
|
||||
Style.label(self, g[0], 18, Style.TEXT, Rect2(40, y, 200, 30), "left", true)
|
||||
var x := 250
|
||||
for entry in g[1]:
|
||||
var b := Style.button(self, entry[0], Rect2(x, y - 4, 190, 40), _apply.bind(entry[1]))
|
||||
b.add_theme_font_size_override("font_size", 14)
|
||||
x += 198
|
||||
var b := Style.button(self, entry[0], Rect2(x, y - 4, 160, 40), _apply.bind(entry[1]))
|
||||
b.add_theme_font_size_override("font_size", 13)
|
||||
x += 168
|
||||
y += 70
|
||||
msg_label = Style.label(self, "", 15, Style.GREEN, Rect2(40, y + 10, 1200, 24), "left")
|
||||
refresh()
|
||||
|
||||
@@ -11,7 +11,7 @@ const MAX_COST := 10
|
||||
|
||||
var app
|
||||
var filter := "" # Element oder ""
|
||||
var cost_filter := -1 # Kosten 0 bis 10 oder -1
|
||||
var cost_filter := -1 # Kosten 0 bis 9, MAX_COST für 10 und mehr, oder -1
|
||||
var grid: CardGrid
|
||||
var all_button: Button
|
||||
var element_buttons := {} # Element -> Knopf mit Symbol
|
||||
@@ -37,7 +37,7 @@ class ElementButton extends Button:
|
||||
Style.element_icon(self, element, size / 2, size.y * 0.6, Style.lighter(Cards.ELEMENT_COLORS[element], 0.4))
|
||||
|
||||
|
||||
## Manakurve: ein Balken je Kosten 0 bis 10 mit der Zahl der Stapelkarten.
|
||||
## Manakurve: ein Balken je Kosten 0 bis 9 und einer für 10 und mehr, mit der Zahl der Stapelkarten.
|
||||
class CurveView extends Control:
|
||||
var counts: Array = []
|
||||
|
||||
@@ -67,7 +67,7 @@ class CurveView extends Control:
|
||||
if v > 0:
|
||||
draw_rect(Rect2(x, base - h, bw, h), Style.BLUE)
|
||||
Style.text(self, str(v), 11, Style.TEXT, Vector2(x + bw / 2, base - h - 8), "center", true)
|
||||
Style.text(self, str(i), 11, Style.MUTED, Vector2(x + bw / 2, base + 8), "center")
|
||||
Style.text(self, str(i) if i < n - 1 else str(i) + "+", 11, Style.MUTED, Vector2(x + bw / 2, base + 8), "center")
|
||||
|
||||
|
||||
## Elementanteile des Stapels: je Element eine farbige Kachel mit der Kartenzahl.
|
||||
@@ -113,7 +113,7 @@ func _ready() -> void:
|
||||
add_child(fb)
|
||||
element_buttons[e] = fb
|
||||
for c in MAX_COST + 1:
|
||||
var cb := Style.button(self, str(c), Rect2(330 + c * 40, 86, 36, 34), set_cost.bind(c))
|
||||
var cb := Style.button(self, str(c) if c < MAX_COST else str(c) + "+", Rect2(330 + c * 40, 86, 36, 34), set_cost.bind(c))
|
||||
cb.add_theme_font_size_override("font_size", 14)
|
||||
cost_buttons.append(cb)
|
||||
grid = CardGrid.new(Rect2(40, 132, CardGrid.COLS * (CardGrid.CW + CardGrid.GAP) + 10, 650))
|
||||
@@ -205,7 +205,7 @@ func cards() -> Array:
|
||||
if filter != "":
|
||||
out = out.filter(func(c): return filter in c.elements)
|
||||
if cost_filter >= 0:
|
||||
out = out.filter(func(c): return c.cost == cost_filter)
|
||||
out = out.filter(func(c): return c.cost == cost_filter or (cost_filter == MAX_COST and c.cost > MAX_COST))
|
||||
out.sort_custom(func(a, b): return sort_key(a) < sort_key(b))
|
||||
return out
|
||||
|
||||
@@ -242,7 +242,7 @@ func refresh() -> void:
|
||||
var per_element := {}
|
||||
for id in p.deck:
|
||||
var c := Cards.by_id(id)
|
||||
counts[clampi(c.cost, 0, 10)] += 1
|
||||
counts[mini(c.cost, MAX_COST)] += 1
|
||||
per_element[c.elements[0]] = int(per_element.get(c.elements[0], 0)) + 1
|
||||
curve.set_counts(counts)
|
||||
share.set_counts(per_element)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
class_name MenuScreen
|
||||
extends Control
|
||||
## Hauptmenü: links Titel und Spielarten (darunter Booster, Sammlung, Skilltree, dann Einstellungen und
|
||||
## Beenden), rechts drei Karten der eigenen Sammlung als Schaufenster, unten rechts die Cheats.
|
||||
## Hauptmenü: links Titel und Spielarten (darunter Booster, Sammlung, Skilltree, nach Kapitel 5 die
|
||||
## Werkstatt, dann Einstellungen und Beenden), rechts drei Karten der eigenen Sammlung als Schaufenster, unten rechts die Cheats.
|
||||
|
||||
var app
|
||||
var coins_label: Label
|
||||
@@ -29,6 +29,8 @@ func _ready() -> void:
|
||||
["Skilltree", func(): app.show_screen(SkillScreen.new())]]:
|
||||
Style.button(self, entry[0], Rect2(x, y, 166, 44), entry[1])
|
||||
x += 176
|
||||
if p.workshop_unlocked():
|
||||
Style.button(self, "Werkstatt", Rect2(x, y, 166, 44), func(): app.show_screen(WorkshopScreen.new()), Color("5a4628"))
|
||||
y += 56
|
||||
x = 80
|
||||
for entry in [["Einstellungen", func(): app.show_screen(SettingsScreen.new())],
|
||||
|
||||
+95
-26
@@ -1,43 +1,92 @@
|
||||
class_name SkillScreen
|
||||
extends Control
|
||||
## Skilltree: oben Level, Erfahrung bis zum nächsten Level und freie Skillpunkte; darunter drei
|
||||
## Äste (Skills.BRANCHES) mit ihren Skills als Karten: Name, Wirkung, aktuelle und nächste Stufe
|
||||
## in Zahlen (Skills.effect), Stufe und „Lernen“.
|
||||
## Skilltree: oben Level, Erfahrungsbalken bis zum nächsten Level und freie Skillpunkte; darunter
|
||||
## vier Äste (Skills.BRANCHES) als senkrechte Pfade: Knoten mit Name, Wirkung, Rangpunkten, „Jetzt“
|
||||
## und „Nächste“ in Zahlen (Skills.effect), durch Linien verbunden. Der nächste Knoten öffnet, sobald
|
||||
## der davor eine Stufe hat; „Lernen“ steht nur, wenn lernbar, fertige Knoten zeigen „Gelernt“.
|
||||
|
||||
const COL_W := 285
|
||||
const COL_STEP := 300
|
||||
const NODE_TOP := 218
|
||||
const NODE_H := 150
|
||||
const NODE_STEP := 172
|
||||
|
||||
var app
|
||||
var level_label: Label
|
||||
var xp_bar: ProgressBar
|
||||
var xp_label: Label
|
||||
var points_label: Label
|
||||
var msg_label: Label
|
||||
var nodes := {} # Skill-ID -> SkillNode
|
||||
var learn_buttons := {} # Skill-ID -> Knopf
|
||||
var rank_labels := {} # Skill-ID -> Label
|
||||
var now_labels := {} # Skill-ID -> Wirkung jetzt
|
||||
var next_labels := {} # Skill-ID -> Wirkung der nächsten Stufe
|
||||
var state_labels := {} # Skill-ID -> „Gelernt“, „Erst … lernen“ oder „Kein Skillpunkt frei“
|
||||
var links := {} # Skill-ID -> Linie zum Knoten davor
|
||||
|
||||
|
||||
## Ein Knoten des Baums: Rahmen und Rangpunkte zeichnet er selbst, Texte und Knopf sind Kinder.
|
||||
class SkillNode extends Control:
|
||||
var rank := 0
|
||||
var max_rank := 1
|
||||
var open := true # der Skill davor hat eine Stufe (oder es gibt keinen)
|
||||
|
||||
func _init(rect: Rect2, mx: int) -> void:
|
||||
max_rank = mx
|
||||
position = rect.position
|
||||
size = rect.size
|
||||
|
||||
func _draw() -> void:
|
||||
var done := rank >= max_rank
|
||||
var bg: Color = Style.PANEL_LIGHT if open else Style.darker(Style.PANEL, 0.9)
|
||||
var border: Color = Style.GREEN if done else (Style.GOLD if rank > 0 else (Style.MUTED if open else Style.darker(Style.MUTED, 0.5)))
|
||||
draw_style_box(Style.box(bg, 8, border, 2), Rect2(Vector2.ZERO, size))
|
||||
for i in max_rank: # Rangpunkte oben rechts
|
||||
var c := Vector2(size.x - 16 - (max_rank - 1 - i) * 18, 21)
|
||||
draw_circle(c, 6, Style.GOLD if i < rank else Style.darker(Style.MUTED, 0.6))
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
Style.header(self, "Skilltree", func(): app.show_screen(MenuScreen.new()))
|
||||
level_label = Style.chip(self, "", Rect2(40, 86, 220, 38))
|
||||
xp_label = Style.chip(self, "", Rect2(276, 86, 400, 38), Style.BLUE)
|
||||
points_label = Style.chip(self, "", Rect2(692, 86, 300, 38), Style.GREEN)
|
||||
Style.label(self, "Erfahrung sind deine verdienten Münzen. Jedes Level bringt einen Skillpunkt.", 14, Style.MUTED, Rect2(40, 134, 1200, 22), "left")
|
||||
level_label = Style.chip(self, "", Rect2(40, 86, 160, 38))
|
||||
xp_bar = ProgressBar.new()
|
||||
xp_bar.position = Vector2(216, 86)
|
||||
xp_bar.size = Vector2(520, 38)
|
||||
xp_bar.show_percentage = false
|
||||
xp_bar.add_theme_stylebox_override("background", Style.box(Style.PANEL_LIGHT, 19))
|
||||
xp_bar.add_theme_stylebox_override("fill", Style.box(Style.darker(Style.BLUE, 0.7), 19))
|
||||
add_child(xp_bar)
|
||||
xp_label = Style.label(self, "", 16, Style.TEXT, Rect2(216, 86, 520, 38), "center", true)
|
||||
points_label = Style.chip(self, "", Rect2(752, 86, 260, 38), Style.GREEN)
|
||||
Style.label(self, "Erfahrung sind deine verdienten Münzen. Jedes Level bringt einen Skillpunkt. Jeder Ast öffnet sich von oben nach unten.", 14, Style.MUTED, Rect2(40, 134, 1200, 22), "left")
|
||||
for b in Skills.BRANCHES.size():
|
||||
var branch: String = Skills.BRANCHES[b]
|
||||
var x := 40 + b * 410
|
||||
Style.panel(self, Rect2(x, 170, 390, 580))
|
||||
Style.label(self, branch, 22, Style.GOLD, Rect2(x, 184, 390, 32), "center", true)
|
||||
var y := 236
|
||||
for id in Skills.in_branch(branch):
|
||||
var x := 40 + b * COL_STEP
|
||||
Style.panel(self, Rect2(x, 166, COL_W, 600))
|
||||
Style.label(self, branch, 20, Style.GOLD, Rect2(x, 178, COL_W, 30), "center", true)
|
||||
var path: Array = Skills.in_branch(branch)
|
||||
for i in path.size():
|
||||
var id: String = path[i]
|
||||
var sk: Dictionary = Skills.SKILLS[id]
|
||||
Style.panel(self, Rect2(x + 16, y, 358, 176), Style.PANEL_LIGHT, 8)
|
||||
Style.label(self, sk.name, 18, Style.TEXT, Rect2(x + 32, y + 10, 326, 26), "left", true)
|
||||
Style.label(self, sk.text, 14, Style.MUTED, Rect2(x + 32, y + 38, 326, 22), "left")
|
||||
now_labels[id] = Style.label(self, "", 14, Style.TEXT, Rect2(x + 32, y + 64, 326, 22), "left")
|
||||
next_labels[id] = Style.label(self, "", 14, Style.GREEN, Rect2(x + 32, y + 86, 326, 22), "left")
|
||||
rank_labels[id] = Style.label(self, "", 15, Style.GOLD, Rect2(x + 32, y + 126, 150, 30), "left", true)
|
||||
learn_buttons[id] = Style.button(self, "Lernen", Rect2(x + 214, y + 122, 144, 40), learn.bind(id), Style.PRIMARY)
|
||||
y += 192
|
||||
msg_label = Style.label(self, "", 15, Style.RED, Rect2(0, 760, 1280, 24), "center")
|
||||
var y := NODE_TOP + i * NODE_STEP
|
||||
if i > 0:
|
||||
var line := ColorRect.new()
|
||||
line.position = Vector2(x + COL_W / 2.0 - 2, y - NODE_STEP + NODE_H)
|
||||
line.size = Vector2(4, NODE_STEP - NODE_H)
|
||||
add_child(line)
|
||||
links[id] = line
|
||||
var node := SkillNode.new(Rect2(x + 14, y, COL_W - 28, NODE_H), int(sk.max))
|
||||
add_child(node)
|
||||
nodes[id] = node
|
||||
var w := COL_W - 28 - 28
|
||||
Style.label(node, sk.name, 17, Style.TEXT, Rect2(14, 8, w - 60, 26), "left", true)
|
||||
var text := Style.label(node, sk.text, 12, Style.MUTED, Rect2(14, 34, w, 34), "left")
|
||||
text.autowrap_mode = TextServer.AUTOWRAP_WORD
|
||||
now_labels[id] = Style.label(node, "", 12, Style.TEXT, Rect2(14, 70, w, 20), "left")
|
||||
next_labels[id] = Style.label(node, "", 12, Style.GREEN, Rect2(14, 88, w, 20), "left")
|
||||
learn_buttons[id] = Style.button(node, "Lernen", Rect2(14, 110, w, 32), learn.bind(id), Style.PRIMARY)
|
||||
state_labels[id] = Style.label(node, "", 14, Style.MUTED, Rect2(14, 112, w, 28), "center", true)
|
||||
msg_label = Style.label(self, "", 15, Style.RED, Rect2(0, 770, 1280, 24), "center")
|
||||
refresh()
|
||||
|
||||
|
||||
@@ -60,11 +109,31 @@ func refresh() -> void:
|
||||
var lvl := p.player_level()
|
||||
var base := Skills.xp_for_level(lvl)
|
||||
level_label.text = tr("Level %d") % lvl
|
||||
xp_bar.max_value = Skills.xp_for_level(lvl + 1) - base
|
||||
xp_bar.value = p.xp - base
|
||||
xp_label.text = tr("%d / %d EP bis Level %d") % [p.xp - base, Skills.xp_for_level(lvl + 1) - base, lvl + 1]
|
||||
points_label.text = tr("Skillpunkte: %d") % p.skill_points()
|
||||
for id in Skills.SKILLS:
|
||||
var sk: Dictionary = Skills.SKILLS[id]
|
||||
rank_labels[id].text = tr("Stufe %d / %d") % [p.skill(id), int(sk.max)]
|
||||
now_labels[id].text = tr("Jetzt: %s") % Skills.effect(id, p.skill(id))
|
||||
next_labels[id].text = tr("Nächste Stufe: %s") % Skills.effect(id, p.skill(id) + 1) if p.skill(id) < int(sk.max) else tr("Höchste Stufe erreicht")
|
||||
learn_buttons[id].disabled = p.skill_points() <= 0 or p.skill(id) >= int(sk.max)
|
||||
var node: SkillNode = nodes[id]
|
||||
var prev := Skills.previous(id)
|
||||
node.rank = p.skill(id)
|
||||
node.open = prev == "" or p.skill(prev) > 0
|
||||
node.modulate = Color(1, 1, 1, 1 if node.open else 0.55)
|
||||
node.queue_redraw()
|
||||
var done := node.rank >= int(sk.max)
|
||||
now_labels[id].text = tr("Jetzt: %s") % Skills.effect(id, node.rank)
|
||||
next_labels[id].text = "" if done else tr("Nächste: %s") % Skills.effect(id, node.rank + 1)
|
||||
var learnable := node.open and not done and p.skill_points() > 0
|
||||
learn_buttons[id].visible = learnable
|
||||
var state := ""
|
||||
if done:
|
||||
state = tr("Gelernt")
|
||||
elif not node.open:
|
||||
state = tr("Erst %s lernen") % tr(Skills.SKILLS[prev].name)
|
||||
elif not learnable:
|
||||
state = tr("Kein Skillpunkt frei")
|
||||
state_labels[id].text = state
|
||||
state_labels[id].add_theme_color_override("font_color", Style.GREEN if done else Style.MUTED)
|
||||
if links.has(id):
|
||||
links[id].color = Style.GOLD if node.open else Style.darker(Style.MUTED, 0.5)
|
||||
+4
-15
@@ -534,7 +534,7 @@ static func fill_elements(ci: CanvasItem, rect: Rect2, elements: Array, radius:
|
||||
## bei Ultimate Rare golden und als Relief.
|
||||
static func picture(ci: CanvasItem, card, c: Vector2, r: float, rar: String, seed: int) -> void:
|
||||
var src = card.art_card()
|
||||
var ring := lighter(Cards.ELEMENT_COLORS[src.elements[0]], 0.3)
|
||||
var ring := lighter(Cards.ELEMENT_COLORS[Cards.strongest_element(src.elements, hash(src.id))], 0.3)
|
||||
ci.draw_circle(c, r + 3, Color(0.05, 0.05, 0.08, 0.8))
|
||||
ci.draw_circle(c, r, Color(0.09, 0.09, 0.13, 0.9))
|
||||
glyph(ci, src, c, r * 1.3, 0.95, rarity_relief(rar))
|
||||
@@ -616,23 +616,12 @@ static func glyph(ci: CanvasItem, card, center: Vector2, size: float, alpha: flo
|
||||
## Symbol in einer festen Farbe (Relief) oder, bei durchsichtigem tint, in Elementfarben.
|
||||
static func _glyph_plain(ci: CanvasItem, card, center: Vector2, size: float, tint: Color, alpha: float = 0.95) -> void:
|
||||
var variant := absi(hash(card.id)) % 3
|
||||
var col := lighter(Cards.ELEMENT_COLORS[card.elements[0]], 0.38)
|
||||
var e := Cards.strongest_element(card.elements, hash(card.id)) # mehrere Elemente: nur das stärkste
|
||||
var col := lighter(Cards.ELEMENT_COLORS[e], 0.38)
|
||||
col.a = alpha
|
||||
if tint.a > 0:
|
||||
col = tint
|
||||
var elems: Array = card.elements
|
||||
if elems.size() == 1:
|
||||
_element_glyph(ci, elems[0], center, size, variant, col)
|
||||
return
|
||||
# Verschmolzen: die ersten beiden Elemente nebeneinander, ab dem dritten ein Ring
|
||||
_element_glyph(ci, elems[0], center + Vector2(-size * 0.28, 0), size * 0.62, variant, col)
|
||||
var col2 := lighter(Cards.ELEMENT_COLORS[elems[1]], 0.38)
|
||||
col2.a = alpha
|
||||
if tint.a > 0:
|
||||
col2 = tint
|
||||
_element_glyph(ci, elems[1], center + Vector2(size * 0.28, 0), size * 0.62, variant, col2)
|
||||
if elems.size() >= 3:
|
||||
ci.draw_arc(center, size * 0.72, 0, TAU, 40, Color(col, 0.5), 2)
|
||||
_element_glyph(ci, e, center, size, variant, col)
|
||||
|
||||
|
||||
## Elementsymbol in einer Farbe (Filterknöpfe, Listen), Grundvariante.
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
class_name WorkshopScreen
|
||||
extends Control
|
||||
## Werkstatt (nach Kapitel 5): eigene Karten aus Staub bauen. Links Elemente (beliebig viele),
|
||||
## Angriff, Leben, Eigenschaften (beliebig viele) und der Name; rechts die Vorschau mit Kosten
|
||||
## (Cards.cost_with), Wert und Preis (Profile.build_price). „Bauen“ legt die Karte als Common in
|
||||
## Sammlung und Stapel.
|
||||
|
||||
var app
|
||||
var elements: Array = []
|
||||
var keywords: Array = []
|
||||
var attack_slider: HSlider
|
||||
var health_slider: HSlider
|
||||
var attack_label: Label
|
||||
var health_label: Label
|
||||
var element_buttons := {}
|
||||
var keyword_boxes := {}
|
||||
var name_box: LineEdit
|
||||
var info_label: Label
|
||||
var msg_label: Label
|
||||
var dust_label: Label
|
||||
var preview_holder: Control
|
||||
var built := 0 # für den Vorschlagsnamen
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
Style.header(self, "Werkstatt", func(): app.show_screen(MenuScreen.new()))
|
||||
dust_label = Style.chip(self, "", Rect2(860, 26, 240, 38), Style.BLUE)
|
||||
Style.panel(self, Rect2(40, 86, 700, 696))
|
||||
Style.label(self, "Baue eigene Karten aus Staub: so viele Elemente und Eigenschaften du willst, jede kostet Mana.", 14, Style.MUTED, Rect2(60, 98, 660, 22), "left")
|
||||
Style.label(self, "Elemente", 16, Style.TEXT, Rect2(60, 134, 140, 30), "left", true)
|
||||
var all_elements: Array = Cards.ELEMENTS + [Cards.NEUTRAL]
|
||||
for i in all_elements.size():
|
||||
var e: String = all_elements[i]
|
||||
var b := DeckScreen.ElementButton.new(e)
|
||||
b.position = Vector2(200 + i * 48, 130)
|
||||
b.size = Vector2(40, 40)
|
||||
b.pressed.connect(toggle_element.bind(e))
|
||||
Style.juice(b)
|
||||
add_child(b)
|
||||
element_buttons[e] = b
|
||||
Style.label(self, "Angriff", 16, Style.TEXT, Rect2(60, 194, 140, 30), "left", true)
|
||||
attack_slider = _slider(Rect2(200, 198, 400, 24), 0, 10, 3)
|
||||
attack_label = Style.label(self, "", 18, Style.AMBER, Rect2(620, 192, 60, 30), "center", true)
|
||||
Style.label(self, "Leben", 16, Style.TEXT, Rect2(60, 244, 140, 30), "left", true)
|
||||
health_slider = _slider(Rect2(200, 248, 400, 24), 1, 10, 3)
|
||||
health_label = Style.label(self, "", 18, Style.LIFE, Rect2(620, 242, 60, 30), "center", true)
|
||||
Style.label(self, "Eigenschaften", 16, Style.TEXT, Rect2(60, 300, 200, 30), "left", true)
|
||||
for k in Cards.KEYWORDS.size():
|
||||
var kw: String = Cards.KEYWORDS[k]
|
||||
var cb := CheckButton.new()
|
||||
cb.text = tr(kw)
|
||||
cb.position = Vector2(200, 300 + k * 44)
|
||||
cb.size = Vector2(220, 36)
|
||||
cb.toggled.connect(func(on: bool): toggle_keyword(kw, on))
|
||||
add_child(cb)
|
||||
keyword_boxes[kw] = cb
|
||||
Style.label(self, tr(Cards.KEYWORD_TEXT[kw]), 13, Style.MUTED, Rect2(430, 306 + k * 44, 300, 24), "left")
|
||||
Style.label(self, "Name", 16, Style.TEXT, Rect2(60, 490, 140, 30), "left", true)
|
||||
name_box = LineEdit.new()
|
||||
name_box.position = Vector2(200, 486)
|
||||
name_box.size = Vector2(400, 36)
|
||||
name_box.max_length = 24
|
||||
name_box.text_changed.connect(func(_t: String): refresh())
|
||||
add_child(name_box)
|
||||
info_label = Style.label(self, "", 16, Style.GOLD, Rect2(60, 546, 660, 30), "left", true)
|
||||
Style.button(self, "Bauen", Rect2(60, 600, 300, 50), build, Style.PRIMARY)
|
||||
msg_label = Style.label(self, "", 15, Style.RED, Rect2(60, 666, 660, 48), "left")
|
||||
msg_label.autowrap_mode = TextServer.AUTOWRAP_WORD
|
||||
Style.panel(self, Rect2(760, 86, 480, 696))
|
||||
preview_holder = Control.new()
|
||||
preview_holder.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
add_child(preview_holder)
|
||||
_suggest_name()
|
||||
refresh()
|
||||
|
||||
|
||||
func _slider(rect: Rect2, lo: int, hi: int, value: int) -> HSlider:
|
||||
var s := HSlider.new()
|
||||
s.position = rect.position
|
||||
s.size = rect.size
|
||||
s.min_value = lo
|
||||
s.max_value = hi
|
||||
s.step = 1
|
||||
s.value = value
|
||||
s.value_changed.connect(func(_v: float): refresh())
|
||||
add_child(s)
|
||||
return s
|
||||
|
||||
|
||||
func _input(event: InputEvent) -> void:
|
||||
if event.is_action_pressed("ui_cancel") and not name_box.has_focus():
|
||||
app.show_screen(MenuScreen.new())
|
||||
|
||||
|
||||
func _suggest_name() -> void:
|
||||
name_box.text = tr("Eigenbau %d") % (app.profile.customs.size() + 1)
|
||||
|
||||
|
||||
## Ein Element an- oder abwählen.
|
||||
func toggle_element(e: String) -> void:
|
||||
if e in elements:
|
||||
elements.erase(e)
|
||||
else:
|
||||
elements.append(e)
|
||||
say("")
|
||||
refresh()
|
||||
|
||||
|
||||
func toggle_keyword(kw: String, on: bool) -> void:
|
||||
if on and not (kw in keywords):
|
||||
keywords.append(kw)
|
||||
elif not on:
|
||||
keywords.erase(kw)
|
||||
keywords = Cards.KEYWORDS.filter(func(k): return k in keywords)
|
||||
refresh()
|
||||
|
||||
|
||||
func say(m: String, ok: bool = false) -> void:
|
||||
msg_label.text = m
|
||||
msg_label.add_theme_color_override("font_color", Style.GREEN if ok else Style.RED)
|
||||
|
||||
|
||||
## Die Karte, wie sie gebaut würde (für die Vorschau ohne Element neutral).
|
||||
func preview_card() -> Cards.Card:
|
||||
var els := elements if not elements.is_empty() else [Cards.NEUTRAL]
|
||||
return Cards.custom("c_vorschau", name_box.text.strip_edges(), els, int(attack_slider.value), int(health_slider.value), keywords)
|
||||
|
||||
|
||||
func build() -> void:
|
||||
var p: Profile = app.profile
|
||||
var err: String = p.build_card(name_box.text, elements, int(attack_slider.value), int(health_slider.value), keywords)
|
||||
if err != "":
|
||||
say(tr(err))
|
||||
return
|
||||
app.save()
|
||||
app.sfx.play("combo")
|
||||
say(tr("Gebaut: %s") % name_box.text.strip_edges(), true)
|
||||
_suggest_name()
|
||||
refresh()
|
||||
|
||||
|
||||
func refresh() -> void:
|
||||
var p: Profile = app.profile
|
||||
dust_label.text = "Staub: %d" % p.dust
|
||||
attack_label.text = str(int(attack_slider.value))
|
||||
health_label.text = str(int(health_slider.value))
|
||||
for e in element_buttons:
|
||||
var active: bool = e in elements
|
||||
var base: Color = Style.darker(Cards.ELEMENT_COLORS[e], 0.8)
|
||||
element_buttons[e].add_theme_stylebox_override("normal", Style.box(Style.lighter(base) if active else base, 8, Style.GOLD if active else Style.MUTED, 2 if active else 1))
|
||||
var c := preview_card()
|
||||
info_label.text = tr("Kosten %d Mana · Wert %d · Preis %d Staub") % [c.cost, c.value(), p.build_price(c)]
|
||||
Style.clear(preview_holder)
|
||||
var v := CardView.new(c, Vector2(240, 336), false, "Common")
|
||||
v.position = Vector2(880, 160)
|
||||
v.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
preview_holder.add_child(v)
|
||||
Style.label(preview_holder, c.text(), 15, Style.MUTED, Rect2(780, 520, 440, 30), "center")
|
||||
@@ -0,0 +1 @@
|
||||
uid://cwy4h3joivrfr
|
||||
Reference in new issue
Block a user