Measured inventory first: the market modules authored their labels at raw token sizes while the view uses the canvas text scale, leaving module labels near 6.5 physical pixels at 760, and the card, trait and cost surfaces were drawn in fixed pixels against proportional label slots. Every module now takes the view's canvas type scale; the card band and price strip are fractions of the card size that cover their slots; the trait chip and cost strip are proportional chrome with the coin anchored in the authored socket; ledger labels move to ink on parchment and the ledger keeps the full availability string while the card row carries only the amount.
241 lines
13 KiB
GDScript
241 lines
13 KiB
GDScript
class_name ABGMarketChrome
|
|
extends Control
|
|
|
|
## Shared Q-style market chrome. This is deliberately asset-light: the
|
|
## authored background and character sprites remain independent, while this
|
|
## control owns the reusable paper/wood/ribbon material language. Text and
|
|
## values are always rendered by the engine above it.
|
|
|
|
const INK := Color("#3b2b22")
|
|
const INK_SOFT := Color("#6d5038")
|
|
const PAPER := Color("#f7e9c7")
|
|
const PAPER_LIGHT := Color("#fff5dc")
|
|
const PAPER_SHADE := Color("#e4c990")
|
|
const WOOD := Color("#74472d")
|
|
const WOOD_LIGHT := Color("#a56c3e")
|
|
const TEAL := Color("#2f6b73")
|
|
const TEAL_LIGHT := Color("#74aeb0")
|
|
const BRASS := Color("#d9a848")
|
|
const RED := Color("#ad4d4c")
|
|
const BLUE := Color("#3d7390")
|
|
const SHADOW := Color(0.10, 0.07, 0.05, 0.34)
|
|
|
|
var variant := "card"
|
|
var accent := "blue"
|
|
|
|
func configure(next_variant: String, next_accent := "blue") -> ABGMarketChrome:
|
|
variant = next_variant
|
|
accent = next_accent
|
|
return self
|
|
|
|
func _ready() -> void:
|
|
mouse_filter = Control.MOUSE_FILTER_IGNORE
|
|
queue_redraw()
|
|
|
|
func _draw() -> void:
|
|
if size.x < 2.0 or size.y < 2.0:
|
|
return
|
|
match variant:
|
|
"title":
|
|
_draw_title()
|
|
"resource":
|
|
_draw_resource()
|
|
"ledger":
|
|
_draw_ledger()
|
|
"wood_button":
|
|
_draw_wood_button()
|
|
"ledger_action":
|
|
_draw_ledger_action()
|
|
"ledger_cost":
|
|
_draw_ledger_cost()
|
|
"compact_label":
|
|
_draw_compact_label()
|
|
"compact_cost":
|
|
_draw_compact_cost()
|
|
"trait_chip":
|
|
_draw_trait_chip()
|
|
"cost_strip":
|
|
_draw_cost_strip()
|
|
_:
|
|
_draw_card()
|
|
|
|
func _draw_title() -> void:
|
|
var rect := Rect2(5.0, 7.0, size.x - 10.0, size.y - 12.0)
|
|
_draw_round(Rect2(rect.position + Vector2(4.0, 5.0), rect.size), 15.0, SHADOW)
|
|
_draw_round(rect, 15.0, PAPER)
|
|
_draw_round(rect.grow(-3.0), 12.0, Color(PAPER_LIGHT, 0.18), INK, 2.0)
|
|
# cloth header and brass corner stitches
|
|
var band := Rect2(rect.position + Vector2(18.0, 7.0), Vector2(rect.size.x - 36.0, 13.0))
|
|
_draw_round(band, 6.0, TEAL)
|
|
_draw_round(Rect2(band.position + Vector2(7.0, 3.0), Vector2(band.size.x - 14.0, 3.0)), 2.0, TEAL_LIGHT)
|
|
for point in [Vector2(rect.position.x + 12.0, rect.position.y + 16.0), Vector2(rect.end.x - 12.0, rect.position.y + 16.0), Vector2(rect.position.x + 12.0, rect.end.y - 13.0), Vector2(rect.end.x - 12.0, rect.end.y - 13.0)]:
|
|
_draw_diamond(point, 4.0, BRASS)
|
|
# little hanging tabs make the title read as a physical sign
|
|
draw_line(Vector2(rect.position.x + 24.0, rect.position.y), Vector2(rect.position.x + 24.0, rect.position.y - 7.0), INK_SOFT, 2.0, true)
|
|
draw_line(Vector2(rect.end.x - 24.0, rect.position.y), Vector2(rect.end.x - 24.0, rect.position.y - 7.0), INK_SOFT, 2.0, true)
|
|
|
|
func _draw_resource() -> void:
|
|
var rect := Rect2(3.0, 4.0, size.x - 6.0, size.y - 8.0)
|
|
_draw_round(Rect2(rect.position + Vector2(3.0, 4.0), rect.size), 10.0, SHADOW)
|
|
_draw_round(rect, 10.0, PAPER_LIGHT)
|
|
_draw_round(rect.grow(-2.0), 8.0, Color(PAPER, 0.3), INK_SOFT, 1.5)
|
|
_draw_diamond(Vector2(rect.position.x + 11.0, rect.get_center().y), 4.0, BRASS)
|
|
_draw_diamond(Vector2(rect.end.x - 11.0, rect.get_center().y), 4.0, BRASS)
|
|
|
|
func _draw_card() -> void:
|
|
# Card geometry is expressed as fractions of the card size so the drawn
|
|
# ribbon band and price strip always cover the same proportions as the
|
|
# label slots in m52_market_slots.gd (profession 0.055..0.155, price
|
|
# 0.88..0.96). Fixed pixel insets drifted away from those slots and left
|
|
# the profession label straddling the band and the parchment face.
|
|
var inset_x := size.x * 0.024
|
|
var inset_top := size.y * 0.035
|
|
var inset_bottom := size.y * 0.045
|
|
var rect := Rect2(inset_x, inset_top, size.x - inset_x * 2.0, size.y - inset_top - inset_bottom)
|
|
var radius := maxf(6.0, size.y * 0.032)
|
|
_draw_round(Rect2(rect.position + Vector2(size.x * 0.019, size.y * 0.016), rect.size), radius, SHADOW)
|
|
_draw_round(rect, radius, PAPER)
|
|
_draw_round(rect.grow(-radius * 0.25), radius * 0.75, Color(PAPER_LIGHT, 0.10), INK_SOFT, 1.5)
|
|
# Rope and hanging knot
|
|
var rope_x := rect.position.x + rect.size.x * 0.5
|
|
var knot_y := rect.position.y - size.y * 0.008
|
|
draw_line(Vector2(rope_x - size.x * 0.049, 0.0), Vector2(rope_x - size.x * 0.034, knot_y + size.y * 0.024), WOOD_LIGHT, 2.0, true)
|
|
draw_line(Vector2(rope_x + size.x * 0.049, 0.0), Vector2(rope_x + size.x * 0.034, knot_y + size.y * 0.024), WOOD_LIGHT, 2.0, true)
|
|
draw_circle(Vector2(rope_x, knot_y + size.y * 0.027), size.x * 0.024, WOOD)
|
|
# Profession ribbon: spans the card's profession slot (0.055..0.155 of the
|
|
# card height) with a small overlap so the label sits fully on the band.
|
|
var ribbon_color := BLUE if accent == "blue" else RED if accent == "red" else BRASS
|
|
var ribbon_top := size.y * 0.052
|
|
var ribbon_bottom := size.y * 0.150
|
|
var ribbon := Rect2(rect.position.x + size.x * 0.049, ribbon_top, rect.size.x - size.x * 0.098, ribbon_bottom - ribbon_top)
|
|
_draw_round(ribbon, maxf(3.0, size.y * 0.012), ribbon_color)
|
|
draw_line(Vector2(ribbon.position.x + size.x * 0.024, ribbon.position.y + 1.0), Vector2(ribbon.end.x - size.x * 0.024, ribbon.position.y + 1.0), Color(PAPER_LIGHT, 0.64), 1.0, true)
|
|
# Bottom price strip: spans the card's price slot (0.88..0.96).
|
|
var price_top := size.y * 0.872
|
|
var price_bottom := size.y * 0.968
|
|
var price := Rect2(rect.position.x + size.x * 0.044, price_top, rect.size.x - size.x * 0.088, price_bottom - price_top)
|
|
_draw_round(price, maxf(4.0, size.y * 0.016), PAPER_SHADE)
|
|
draw_line(Vector2(price.position.x + size.x * 0.020, price.position.y + size.y * 0.005), Vector2(price.end.x - size.x * 0.020, price.position.y + size.y * 0.005), Color(PAPER_LIGHT, 0.64), 1.0, true)
|
|
# seal marker
|
|
var seal_center := Vector2(rect.end.x - size.x * 0.083, rect.position.y + size.y * 0.205)
|
|
draw_circle(seal_center, size.x * 0.049, Color(ribbon_color, 0.92))
|
|
draw_arc(seal_center, size.x * 0.039, 0.0, TAU, 18, PAPER_LIGHT, 1.2, true)
|
|
_draw_diamond(seal_center, size.x * 0.015, PAPER_LIGHT)
|
|
|
|
func _draw_ledger() -> void:
|
|
var rect := Rect2(5.0, 6.0, size.x - 10.0, size.y - 12.0)
|
|
_draw_round(Rect2(rect.position + Vector2(5.0, 7.0), rect.size), 16.0, SHADOW)
|
|
_draw_round(rect, 16.0, PAPER)
|
|
_draw_round(rect.grow(-4.0), 12.0, Color(PAPER_LIGHT, 0.10), INK_SOFT, 2.0)
|
|
var header := Rect2(rect.position.x + 10.0, rect.position.y + 10.0, rect.size.x - 20.0, minf(36.0, rect.size.y * 0.18))
|
|
_draw_round(header, 9.0, TEAL)
|
|
draw_line(Vector2(header.position.x + 9.0, header.end.y - 6.0), Vector2(header.end.x - 9.0, header.end.y - 6.0), Color(TEAL_LIGHT, 0.8), 2.0, true)
|
|
# portrait frame and lower action dock
|
|
var portrait := Rect2(rect.position.x + 14.0, header.end.y + 10.0, rect.size.x - 28.0, rect.size.y * 0.35)
|
|
_draw_round(portrait, 11.0, Color(PAPER_SHADE, 0.52), INK_SOFT, 1.2)
|
|
var dock := Rect2(rect.position.x + 14.0, rect.end.y - 58.0, rect.size.x - 28.0, 42.0)
|
|
_draw_round(dock, 10.0, Color(TEAL, 0.92), INK, 2.0)
|
|
draw_line(Vector2(dock.position.x + 8.0, dock.position.y + 6.0), Vector2(dock.end.x - 8.0, dock.position.y + 6.0), Color(TEAL_LIGHT, 0.8), 1.0, true)
|
|
for point in [Vector2(rect.position.x + 12.0, rect.position.y + 18.0), Vector2(rect.end.x - 12.0, rect.position.y + 18.0), Vector2(rect.position.x + 12.0, rect.end.y - 18.0), Vector2(rect.end.x - 12.0, rect.end.y - 18.0)]:
|
|
_draw_diamond(point, 4.0, BRASS)
|
|
|
|
func _draw_wood_button() -> void:
|
|
var rect := Rect2(3.0, 4.0, size.x - 6.0, size.y - 8.0)
|
|
var cut := minf(10.0, rect.size.y * 0.24)
|
|
var points := PackedVector2Array([Vector2(rect.position.x + cut, rect.position.y), Vector2(rect.end.x - cut, rect.position.y), Vector2(rect.end.x, rect.position.y + cut), Vector2(rect.end.x, rect.end.y - cut), Vector2(rect.end.x - cut, rect.end.y), Vector2(rect.position.x + cut, rect.end.y), Vector2(rect.position.x, rect.end.y - cut), Vector2(rect.position.x, rect.position.y + cut)])
|
|
var shadow := PackedVector2Array()
|
|
for point in points:
|
|
shadow.append(point + Vector2(3.0, 5.0))
|
|
draw_colored_polygon(shadow, SHADOW)
|
|
draw_colored_polygon(points, WOOD)
|
|
draw_polyline(PackedVector2Array([points[0], points[1], points[2], points[3], points[4], points[5], points[6], points[7], points[0]]), WOOD_LIGHT, 2.0, true)
|
|
draw_line(Vector2(rect.position.x + cut + 8.0, rect.position.y + 6.0), Vector2(rect.end.x - cut - 8.0, rect.position.y + 6.0), Color(PAPER_LIGHT, 0.34), 1.5, true)
|
|
_draw_diamond(Vector2(rect.position.x + cut + 5.0, rect.get_center().y), 3.0, BRASS)
|
|
_draw_diamond(Vector2(rect.end.x - cut - 5.0, rect.get_center().y), 3.0, BRASS)
|
|
|
|
func _draw_ledger_action() -> void:
|
|
var rect := Rect2(3.0, 4.0, size.x - 6.0, size.y - 8.0)
|
|
_draw_round(Rect2(rect.position + Vector2(3.0, 5.0), rect.size), 10.0, SHADOW)
|
|
_draw_round(rect, 10.0, TEAL, INK, 2.0)
|
|
_draw_round(rect.grow(-4.0), 7.0, Color(TEAL_LIGHT, 0.18), Color(TEAL_LIGHT, 0.64), 1.0)
|
|
draw_line(Vector2(rect.position.x + 10.0, rect.position.y + 6.0), Vector2(rect.end.x - 10.0, rect.position.y + 6.0), Color(PAPER_LIGHT, 0.66), 1.2, true)
|
|
_draw_diamond(Vector2(rect.position.x + 10.0, rect.get_center().y), 3.0, BRASS)
|
|
_draw_diamond(Vector2(rect.end.x - 10.0, rect.get_center().y), 3.0, BRASS)
|
|
|
|
func _draw_ledger_cost() -> void:
|
|
# Fill the module so the availability and amount labels sit on the strip
|
|
# instead of overflowing onto the parchment behind it.
|
|
var rect := Rect2(size.x * 0.008, size.y * 0.06, size.x * 0.984, size.y * 0.88)
|
|
var radius := maxf(5.0, size.y * 0.20)
|
|
_draw_round(Rect2(rect.position + Vector2(size.x * 0.006, size.y * 0.07), rect.size), radius, SHADOW)
|
|
_draw_round(rect, radius, PAPER_SHADE, INK_SOFT, 1.0)
|
|
_draw_round(rect.grow(-radius * 0.4), radius * 0.7, Color(PAPER_LIGHT, 0.20), Color(PAPER_LIGHT, 0.70), 1.0)
|
|
draw_line(Vector2(rect.position.x + size.x * 0.025, rect.position.y + size.y * 0.16), Vector2(rect.end.x - size.x * 0.025, rect.position.y + size.y * 0.16), Color(PAPER_LIGHT, 0.75), 1.0, true)
|
|
_draw_diamond(Vector2(rect.position.x + size.x * 0.022, rect.get_center().y), maxf(2.0, size.y * 0.09), BRASS)
|
|
_draw_diamond(Vector2(rect.end.x - size.x * 0.022, rect.get_center().y), maxf(2.0, size.y * 0.09), BRASS)
|
|
|
|
func _draw_trait_chip() -> void:
|
|
# Proportional label chip: teal caps scale with the chip so the text strip
|
|
# is always the middle band and no cap can cover a glyph.
|
|
var cap := size.x * 0.14
|
|
var middle_top := size.y * 0.06
|
|
var middle_bottom := size.y * 0.94
|
|
var body := Rect2(cap * 0.55, middle_top, size.x - cap * 1.1, middle_bottom - middle_top)
|
|
_draw_round(Rect2(body.position + Vector2(0.0, size.y * 0.09), body.size), maxf(3.0, size.y * 0.22), SHADOW)
|
|
_draw_round(body, maxf(3.0, size.y * 0.20), PAPER_LIGHT, INK_SOFT, 1.0)
|
|
draw_line(Vector2(body.position.x + size.x * 0.02, body.position.y + 1.0), Vector2(body.end.x - size.x * 0.02, body.position.y + 1.0), Color(PAPER_SHADE, 0.9), 1.0, true)
|
|
for side in [0.0, 1.0]:
|
|
var center_x := cap * 0.5 if side == 0.0 else size.x - cap * 0.5
|
|
var points := PackedVector2Array([
|
|
Vector2(center_x - cap * 0.5, middle_top),
|
|
Vector2(center_x + cap * 0.5, middle_top + size.y * 0.16),
|
|
Vector2(center_x + cap * 0.5, middle_bottom - size.y * 0.16),
|
|
Vector2(center_x - cap * 0.5, middle_bottom)])
|
|
draw_colored_polygon(points, TEAL)
|
|
draw_polyline(points + PackedVector2Array([points[0]]), Color(TEAL_LIGHT, 0.8), 1.2, true)
|
|
_draw_diamond(Vector2(center_x, size.y * 0.5), maxf(1.5, size.y * 0.10), BRASS)
|
|
|
|
|
|
func _draw_cost_strip() -> void:
|
|
# Proportional cost row: the coin socket is the leftmost fraction and the
|
|
# labels own the band to its right.
|
|
var socket := size.x * 0.19
|
|
var band := Rect2(socket, size.y * 0.10, size.x - socket - size.x * 0.02, size.y * 0.80)
|
|
_draw_round(Rect2(band.position + Vector2(0.0, size.y * 0.08), band.size), maxf(3.0, size.y * 0.24), SHADOW)
|
|
_draw_round(band, maxf(3.0, size.y * 0.22), PAPER_SHADE, INK_SOFT, 1.0)
|
|
draw_line(Vector2(band.position.x + size.x * 0.015, band.position.y + 1.5), Vector2(band.end.x - size.x * 0.015, band.position.y + 1.5), Color(PAPER_LIGHT, 0.75), 1.0, true)
|
|
var coin := Vector2(socket * 0.5, size.y * 0.5)
|
|
draw_circle(coin, minf(socket, size.y) * 0.44, Color(BRASS, 0.95))
|
|
draw_arc(coin, minf(socket, size.y) * 0.36, 0.0, TAU, 20, PAPER_LIGHT, 1.2, true)
|
|
_draw_diamond(coin, minf(socket, size.y) * 0.16, PAPER_LIGHT)
|
|
|
|
|
|
func _draw_compact_label() -> void:
|
|
var rect := Rect2(2.0, 2.0, size.x - 4.0, size.y - 4.0)
|
|
_draw_round(Rect2(rect.position + Vector2(2.0, 2.0), rect.size), 5.0, SHADOW)
|
|
_draw_round(rect, 5.0, PAPER_LIGHT, INK_SOFT, 1.0)
|
|
_draw_round(rect.grow(-2.0), 3.0, Color(PAPER, 0.18), Color(PAPER_SHADE, 0.75), 1.0)
|
|
|
|
func _draw_compact_cost() -> void:
|
|
var rect := Rect2(2.0, 2.0, size.x - 4.0, size.y - 4.0)
|
|
_draw_round(Rect2(rect.position + Vector2(2.0, 2.0), rect.size), 5.0, SHADOW)
|
|
_draw_round(rect, 5.0, PAPER_SHADE, INK_SOFT, 1.0)
|
|
_draw_round(rect.grow(-2.0), 3.0, Color(PAPER_LIGHT, 0.26), Color(PAPER_LIGHT, 0.76), 1.0)
|
|
_draw_diamond(Vector2(rect.position.x + 7.0, rect.get_center().y), 2.5, BRASS)
|
|
_draw_diamond(Vector2(rect.end.x - 7.0, rect.get_center().y), 2.5, BRASS)
|
|
|
|
func _draw_round(rect: Rect2, radius: float, fill: Color, border := Color(0, 0, 0, 0), width := 0.0) -> void:
|
|
var style := StyleBoxFlat.new()
|
|
style.bg_color = fill
|
|
style.corner_radius_top_left = int(radius)
|
|
style.corner_radius_top_right = int(radius)
|
|
style.corner_radius_bottom_left = int(radius)
|
|
style.corner_radius_bottom_right = int(radius)
|
|
if width > 0.0:
|
|
style.border_color = border
|
|
style.set_border_width_all(int(width))
|
|
draw_style_box(style, rect)
|
|
|
|
func _draw_diamond(center: Vector2, radius: float, color: Color) -> void:
|
|
draw_colored_polygon(PackedVector2Array([center + Vector2(0.0, -radius), center + Vector2(radius, 0.0), center + Vector2(0.0, radius), center + Vector2(-radius, 0.0)]), color)
|