|
|
|
@@ -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:
|
|
|
|
|