Make the slot machine its own sidebar entry; rework its visuals
Moves Slot Machine into the sidebar's account section (alongside RZ Shop/Settings/Log out) instead of being reachable only from the shop - removes the shop's promo banner and the screen's "Back to Shop" link accordingly. Also closes a chunk of the visual gap against the mockup: a proper cabinet-style panel (arched top corners, glowing border), a light "screen" panel holding a real 3x3 reel grid instead of 3 single icons, a decorative lever, an "RZ" marquee, and the cost/spin/auto-spin controls each in their own bordered box. Added two new vendored icons (gem, flask-conical) for reel variety and reward-list icons.
This commit is contained in:
@@ -5,11 +5,13 @@ const STAR_ICON := preload("res://assets/icons/lucide/star.svg")
|
||||
const SHIELD_ICON := preload("res://assets/icons/lucide/shield.svg")
|
||||
const CLOCK_ICON := preload("res://assets/icons/lucide/clock-3.svg")
|
||||
const RESET_ICON := preload("res://assets/icons/lucide/rotate-ccw.svg")
|
||||
const REEL_SYMBOLS := [STAR_ICON, SHIELD_ICON, CLOCK_ICON, RESET_ICON]
|
||||
const GEM_ICON := preload("res://assets/icons/lucide/gem.svg")
|
||||
const FLASK_ICON := preload("res://assets/icons/lucide/flask-conical.svg")
|
||||
const REEL_SYMBOLS := [STAR_ICON, SHIELD_ICON, CLOCK_ICON, RESET_ICON, GEM_ICON, FLASK_ICON]
|
||||
const ICON_BY_REWARD_KEY := {
|
||||
"jackpot": "star",
|
||||
"epic": "star",
|
||||
"great": "star",
|
||||
"epic": "gem",
|
||||
"great": "shield",
|
||||
"exam_token": "clock-3",
|
||||
"qbank_reset": "rotate-ccw",
|
||||
"nice": "star",
|
||||
@@ -19,11 +21,13 @@ const ICON_BY_REWARD_KEY := {
|
||||
var main: Control
|
||||
|
||||
var subtitle_label: Label
|
||||
var back_button: Button
|
||||
var machine_panel: PanelContainer
|
||||
var reel_icons: Array = []
|
||||
var reel_columns: Array = []
|
||||
var win_up_to_card: PanelContainer
|
||||
var win_up_to_label: Label
|
||||
var cost_card: PanelContainer
|
||||
var cost_value_label: Label
|
||||
var auto_card: PanelContainer
|
||||
var spin_button: Button
|
||||
var auto_spin_toggle: CheckButton
|
||||
var status_label: Label
|
||||
@@ -74,14 +78,6 @@ func on_show(_payload: Variant = null) -> void:
|
||||
|
||||
|
||||
func _build_header() -> void:
|
||||
back_button = Button.new()
|
||||
back_button.text = "← Back to Shop"
|
||||
back_button.add_theme_font_override("font", Brand.font)
|
||||
back_button.flat = true
|
||||
back_button.size_flags_horizontal = Control.SIZE_SHRINK_BEGIN
|
||||
back_button.pressed.connect(func(): main.show_screen("rz_store"))
|
||||
add_child(back_button)
|
||||
|
||||
var title := Label.new()
|
||||
title.text = "RZ Coin Slot Machine"
|
||||
title.add_theme_font_override("font", Brand.font)
|
||||
@@ -99,55 +95,93 @@ func _build_machine(parent: Control) -> void:
|
||||
var dark := UIThemeService.is_dark_mode()
|
||||
machine_panel = PanelContainer.new()
|
||||
machine_panel.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
machine_panel.add_theme_stylebox_override("panel", Brand.content_card_box(dark, true, Brand.ROYAL_BLUE))
|
||||
machine_panel.add_theme_stylebox_override("panel", _cabinet_box())
|
||||
parent.add_child(machine_panel)
|
||||
|
||||
var margin := MarginContainer.new()
|
||||
margin.add_theme_constant_override("margin_left", 20)
|
||||
margin.add_theme_constant_override("margin_right", 20)
|
||||
margin.add_theme_constant_override("margin_top", 18)
|
||||
margin.add_theme_constant_override("margin_bottom", 18)
|
||||
margin.add_theme_constant_override("margin_left", 24)
|
||||
margin.add_theme_constant_override("margin_right", 24)
|
||||
margin.add_theme_constant_override("margin_top", 22)
|
||||
margin.add_theme_constant_override("margin_bottom", 22)
|
||||
machine_panel.add_child(margin)
|
||||
|
||||
var column := VBoxContainer.new()
|
||||
column.add_theme_constant_override("separation", 14)
|
||||
column.add_theme_constant_override("separation", 16)
|
||||
margin.add_child(column)
|
||||
|
||||
var reels_row := HBoxContainer.new()
|
||||
reels_row.add_theme_constant_override("separation", 12)
|
||||
reels_row.alignment = BoxContainer.ALIGNMENT_CENTER
|
||||
column.add_child(reels_row)
|
||||
_build_marquee(column)
|
||||
|
||||
reel_icons.clear()
|
||||
for _i in range(3):
|
||||
var reel_panel := PanelContainer.new()
|
||||
reel_panel.custom_minimum_size = Vector2(84, 84)
|
||||
reel_panel.add_theme_stylebox_override("panel", Brand.icon_circle_box(dark, Brand.ROYAL_BLUE, 12))
|
||||
var icon := TextureRect.new()
|
||||
icon.texture = STAR_ICON
|
||||
icon.modulate = Brand.AMBER
|
||||
icon.custom_minimum_size = Vector2(40, 40)
|
||||
icon.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
||||
icon.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
||||
icon.size_flags_horizontal = Control.SIZE_SHRINK_CENTER
|
||||
icon.size_flags_vertical = Control.SIZE_SHRINK_CENTER
|
||||
reel_panel.add_child(icon)
|
||||
reels_row.add_child(reel_panel)
|
||||
reel_icons.append(icon)
|
||||
var reel_row := HBoxContainer.new()
|
||||
reel_row.add_theme_constant_override("separation", 16)
|
||||
reel_row.alignment = BoxContainer.ALIGNMENT_CENTER
|
||||
column.add_child(reel_row)
|
||||
|
||||
var reel_screen := PanelContainer.new()
|
||||
reel_screen.add_theme_stylebox_override("panel", _reel_screen_box())
|
||||
reel_row.add_child(reel_screen)
|
||||
|
||||
var reel_margin := MarginContainer.new()
|
||||
reel_margin.add_theme_constant_override("margin_left", 16)
|
||||
reel_margin.add_theme_constant_override("margin_right", 16)
|
||||
reel_margin.add_theme_constant_override("margin_top", 14)
|
||||
reel_margin.add_theme_constant_override("margin_bottom", 14)
|
||||
reel_screen.add_child(reel_margin)
|
||||
|
||||
var reels_grid := HBoxContainer.new()
|
||||
reels_grid.add_theme_constant_override("separation", 12)
|
||||
reel_margin.add_child(reels_grid)
|
||||
|
||||
reel_columns.clear()
|
||||
for _column_index in range(3):
|
||||
var reel_col := VBoxContainer.new()
|
||||
reel_col.add_theme_constant_override("separation", 8)
|
||||
reels_grid.add_child(reel_col)
|
||||
var cells: Array = []
|
||||
for _row_index in range(3):
|
||||
var icon := TextureRect.new()
|
||||
icon.texture = STAR_ICON
|
||||
icon.modulate = Brand.AMBER
|
||||
icon.custom_minimum_size = Vector2(34, 34)
|
||||
icon.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
||||
icon.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
||||
reel_col.add_child(icon)
|
||||
cells.append(icon)
|
||||
reel_columns.append(cells)
|
||||
|
||||
reel_row.add_child(_build_lever())
|
||||
|
||||
win_up_to_card = PanelContainer.new()
|
||||
win_up_to_card.add_theme_stylebox_override("panel", Brand.content_card_box(dark, false))
|
||||
column.add_child(win_up_to_card)
|
||||
var win_margin := MarginContainer.new()
|
||||
win_margin.add_theme_constant_override("margin_left", 14)
|
||||
win_margin.add_theme_constant_override("margin_right", 14)
|
||||
win_margin.add_theme_constant_override("margin_top", 10)
|
||||
win_margin.add_theme_constant_override("margin_bottom", 10)
|
||||
win_up_to_card.add_child(win_margin)
|
||||
win_up_to_label = Label.new()
|
||||
win_up_to_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
win_up_to_label.add_theme_font_override("font", Brand.font)
|
||||
win_up_to_label.add_theme_font_size_override("font_size", 15)
|
||||
win_up_to_label.add_theme_color_override("font_color", Brand.text_color(dark))
|
||||
column.add_child(win_up_to_label)
|
||||
win_margin.add_child(win_up_to_label)
|
||||
|
||||
var controls_row := HBoxContainer.new()
|
||||
controls_row.add_theme_constant_override("separation", 14)
|
||||
controls_row.add_theme_constant_override("separation", 12)
|
||||
column.add_child(controls_row)
|
||||
|
||||
cost_card = PanelContainer.new()
|
||||
cost_card.add_theme_stylebox_override("panel", Brand.content_card_box(dark, false))
|
||||
controls_row.add_child(cost_card)
|
||||
var cost_margin := MarginContainer.new()
|
||||
cost_margin.add_theme_constant_override("margin_left", 14)
|
||||
cost_margin.add_theme_constant_override("margin_right", 14)
|
||||
cost_margin.add_theme_constant_override("margin_top", 8)
|
||||
cost_margin.add_theme_constant_override("margin_bottom", 8)
|
||||
cost_card.add_child(cost_margin)
|
||||
var cost_box := VBoxContainer.new()
|
||||
cost_box.add_theme_constant_override("separation", 0)
|
||||
cost_margin.add_child(cost_box)
|
||||
var cost_caption := Label.new()
|
||||
cost_caption.text = "Cost per spin"
|
||||
cost_caption.add_theme_font_override("font", Brand.font)
|
||||
@@ -159,19 +193,30 @@ func _build_machine(parent: Control) -> void:
|
||||
cost_value_label.add_theme_font_size_override("font_size", 15)
|
||||
cost_value_label.add_theme_color_override("font_color", Brand.text_color(dark))
|
||||
cost_box.add_child(cost_value_label)
|
||||
controls_row.add_child(cost_box)
|
||||
|
||||
spin_button = Button.new()
|
||||
spin_button.text = "Spin"
|
||||
spin_button.custom_minimum_size = Vector2(120, 44)
|
||||
spin_button.custom_minimum_size = Vector2(140, 58)
|
||||
spin_button.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
spin_button.size_flags_vertical = Control.SIZE_SHRINK_CENTER
|
||||
spin_button.add_theme_font_override("font", Brand.font)
|
||||
spin_button.add_theme_font_size_override("font_size", 17)
|
||||
_style_spin_button()
|
||||
spin_button.pressed.connect(_on_spin_pressed)
|
||||
controls_row.add_child(spin_button)
|
||||
|
||||
auto_card = PanelContainer.new()
|
||||
auto_card.add_theme_stylebox_override("panel", Brand.content_card_box(dark, false))
|
||||
controls_row.add_child(auto_card)
|
||||
var auto_margin := MarginContainer.new()
|
||||
auto_margin.add_theme_constant_override("margin_left", 14)
|
||||
auto_margin.add_theme_constant_override("margin_right", 14)
|
||||
auto_margin.add_theme_constant_override("margin_top", 8)
|
||||
auto_margin.add_theme_constant_override("margin_bottom", 8)
|
||||
auto_card.add_child(auto_margin)
|
||||
var auto_box := VBoxContainer.new()
|
||||
auto_box.add_theme_constant_override("separation", 0)
|
||||
auto_margin.add_child(auto_box)
|
||||
auto_spin_toggle = CheckButton.new()
|
||||
auto_spin_toggle.text = "Auto Spin"
|
||||
auto_spin_toggle.add_theme_font_override("font", Brand.font)
|
||||
@@ -182,7 +227,6 @@ func _build_machine(parent: Control) -> void:
|
||||
auto_caption.add_theme_font_size_override("font_size", 11)
|
||||
auto_caption.add_theme_color_override("font_color", Brand.muted_color(dark))
|
||||
auto_box.add_child(auto_caption)
|
||||
controls_row.add_child(auto_box)
|
||||
|
||||
var info_label := Label.new()
|
||||
info_label.text = "All rewards are instant and sent to your account."
|
||||
@@ -193,6 +237,80 @@ func _build_machine(parent: Control) -> void:
|
||||
column.add_child(info_label)
|
||||
|
||||
|
||||
func _build_marquee(column: VBoxContainer) -> void:
|
||||
var row := HBoxContainer.new()
|
||||
row.alignment = BoxContainer.ALIGNMENT_CENTER
|
||||
row.add_theme_constant_override("separation", 12)
|
||||
column.add_child(row)
|
||||
row.add_child(_marquee_star())
|
||||
var mark := Label.new()
|
||||
mark.text = "RZ"
|
||||
mark.add_theme_font_override("font", Brand.font)
|
||||
mark.add_theme_font_size_override("font_size", 34)
|
||||
mark.add_theme_color_override("font_color", Brand.SKY_BLUE)
|
||||
row.add_child(mark)
|
||||
row.add_child(_marquee_star())
|
||||
|
||||
|
||||
func _marquee_star() -> TextureRect:
|
||||
var star := TextureRect.new()
|
||||
star.texture = STAR_ICON
|
||||
star.modulate = Brand.SKY_BLUE
|
||||
star.custom_minimum_size = Vector2(16, 16)
|
||||
star.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
||||
star.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
||||
return star
|
||||
|
||||
|
||||
func _build_lever() -> Control:
|
||||
var wrap := VBoxContainer.new()
|
||||
wrap.alignment = BoxContainer.ALIGNMENT_BEGIN
|
||||
wrap.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||||
wrap.add_theme_constant_override("separation", 0)
|
||||
|
||||
var knob := PanelContainer.new()
|
||||
knob.custom_minimum_size = Vector2(22, 22)
|
||||
knob.size_flags_horizontal = Control.SIZE_SHRINK_CENTER
|
||||
var knob_box := StyleBoxFlat.new()
|
||||
knob_box.bg_color = Brand.ROYAL_BLUE
|
||||
knob_box.set_corner_radius_all(11)
|
||||
knob_box.corner_detail = 20
|
||||
knob_box.anti_aliasing = false
|
||||
knob.add_theme_stylebox_override("panel", knob_box)
|
||||
wrap.add_child(knob)
|
||||
|
||||
var rod := ColorRect.new()
|
||||
rod.color = Color("64748b")
|
||||
rod.custom_minimum_size = Vector2(5, 90)
|
||||
rod.size_flags_horizontal = Control.SIZE_SHRINK_CENTER
|
||||
wrap.add_child(rod)
|
||||
|
||||
return wrap
|
||||
|
||||
|
||||
func _cabinet_box() -> StyleBoxFlat:
|
||||
var box := StyleBoxFlat.new()
|
||||
box.bg_color = Color("0b1220")
|
||||
box.border_color = Brand.SKY_BLUE
|
||||
box.set_border_width_all(3)
|
||||
box.corner_radius_top_left = 48
|
||||
box.corner_radius_top_right = 48
|
||||
box.corner_radius_bottom_left = 16
|
||||
box.corner_radius_bottom_right = 16
|
||||
box.shadow_color = Color(Brand.SKY_BLUE, 0.35)
|
||||
box.shadow_size = 10
|
||||
return box
|
||||
|
||||
|
||||
func _reel_screen_box() -> StyleBoxFlat:
|
||||
var box := StyleBoxFlat.new()
|
||||
box.bg_color = Color("e2e8f0")
|
||||
box.border_color = Color("94a3b8")
|
||||
box.set_border_width_all(2)
|
||||
box.set_corner_radius_all(10)
|
||||
return box
|
||||
|
||||
|
||||
func _build_rewards_panel(parent: Control) -> void:
|
||||
var dark := UIThemeService.is_dark_mode()
|
||||
var panel := PanelContainer.new()
|
||||
@@ -276,9 +394,11 @@ func _build_footer() -> void:
|
||||
func _refresh_theme_controls() -> void:
|
||||
var dark := UIThemeService.is_dark_mode()
|
||||
subtitle_label.add_theme_color_override("font_color", Brand.muted_color(dark))
|
||||
machine_panel.add_theme_stylebox_override("panel", Brand.content_card_box(dark, true, Brand.ROYAL_BLUE))
|
||||
win_up_to_card.add_theme_stylebox_override("panel", Brand.content_card_box(dark, false))
|
||||
win_up_to_label.add_theme_color_override("font_color", Brand.text_color(dark))
|
||||
cost_card.add_theme_stylebox_override("panel", Brand.content_card_box(dark, false))
|
||||
cost_value_label.add_theme_color_override("font_color", Brand.text_color(dark))
|
||||
auto_card.add_theme_stylebox_override("panel", Brand.content_card_box(dark, false))
|
||||
footer_card.add_theme_stylebox_override("panel", Brand.content_card_box(dark, false))
|
||||
footer_icon_panel.add_theme_stylebox_override("panel", Brand.icon_circle_box(dark, Brand.ROYAL_BLUE, 18))
|
||||
footer_heading.add_theme_color_override("font_color", Brand.text_color(dark))
|
||||
@@ -428,20 +548,23 @@ func _await_spin_result() -> Dictionary:
|
||||
|
||||
|
||||
func _animate_reels() -> void:
|
||||
for index in range(reel_icons.size()):
|
||||
_spin_one_reel(reel_icons[index], 0.9 + index * 0.25)
|
||||
for index in range(reel_columns.size()):
|
||||
_spin_one_reel(reel_columns[index], 0.9 + index * 0.25)
|
||||
|
||||
|
||||
func _spin_one_reel(icon: TextureRect, duration: float) -> void:
|
||||
func _spin_one_reel(cells: Array, duration: float) -> void:
|
||||
var elapsed := 0.0
|
||||
var interval := 0.06
|
||||
while elapsed < duration:
|
||||
icon.texture = REEL_SYMBOLS[randi() % REEL_SYMBOLS.size()]
|
||||
var symbol: Texture2D = REEL_SYMBOLS[randi() % REEL_SYMBOLS.size()]
|
||||
for cell in cells:
|
||||
cell.texture = symbol
|
||||
await get_tree().create_timer(interval).timeout
|
||||
elapsed += interval
|
||||
interval = minf(interval * 1.18, 0.22)
|
||||
icon.texture = STAR_ICON
|
||||
icon.modulate = Brand.AMBER
|
||||
for cell in cells:
|
||||
cell.texture = STAR_ICON
|
||||
cell.modulate = Brand.AMBER
|
||||
|
||||
|
||||
func _play_coin_burst(coins_won: int) -> void:
|
||||
|
||||
Reference in New Issue
Block a user