Simplify exam simulations and strip the slot machine down to just the machine
Simulations no longer color-code correct/incorrect choices, retry a failed per-question autosave, or show the RZ coin/ELO badge - users move on immediately after submitting a timed block, same as a real exam. The slot machine panel now shows only the cabinet/reels/lever and a status line (title, banner, controls row, rewards list, and footer removed), the reels fill the cabinet window instead of floating in a black border, the coin-burst animation no longer starts oversized, and the toolbar button is UAT-only via Brand.is_uat_environment(). Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
@@ -23,6 +23,7 @@ var is_loading := false
|
||||
var pending_action := ""
|
||||
var request_queue: Array = []
|
||||
var request_access_token := ""
|
||||
var last_failed_action := ""
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
@@ -141,6 +142,7 @@ func _send_absolute(action: String, method: int, url: String, payload: Dictionar
|
||||
if err != OK:
|
||||
is_loading = false
|
||||
pending_action = ""
|
||||
last_failed_action = action
|
||||
request_failed.emit("The simulation request could not be started.")
|
||||
|
||||
|
||||
@@ -166,6 +168,7 @@ func _on_request_completed(result: int, response_code: int, _headers: PackedStri
|
||||
var message := "Simulation request failed with status %d." % response_code
|
||||
if not server_message.is_empty():
|
||||
message = "%s %s" % [message, server_message]
|
||||
last_failed_action = action
|
||||
request_failed.emit(message)
|
||||
return
|
||||
if response_code == 204:
|
||||
@@ -178,6 +181,7 @@ func _on_request_completed(result: int, response_code: int, _headers: PackedStri
|
||||
return
|
||||
var parsed: Variant = JSON.parse_string(body.get_string_from_utf8())
|
||||
if typeof(parsed) != TYPE_DICTIONARY:
|
||||
last_failed_action = action
|
||||
request_failed.emit("The simulation API returned an invalid response.")
|
||||
return
|
||||
if action == "readiness":
|
||||
|
||||
@@ -1193,6 +1193,11 @@ func _on_simulation_request_failed(message: String) -> void:
|
||||
if BlockSessionService.session_kind != "simulation":
|
||||
return
|
||||
simulation_submit_pending = false
|
||||
if ExamSimulationService.last_failed_action != "submit":
|
||||
# A per-question autosave failing shouldn't interrupt a timed exam with a
|
||||
# blocking "Retry" - the next answer/navigation naturally retries it, and
|
||||
# the final submit sends the complete, authoritative state regardless.
|
||||
return
|
||||
next_button.disabled = false
|
||||
next_button.text = "Retry"
|
||||
next_button.tooltip_text = message
|
||||
@@ -2389,7 +2394,9 @@ func _refresh_toolbar_state() -> void:
|
||||
if calculator_button != null:
|
||||
calculator_button.visible = true
|
||||
if slot_machine_button != null:
|
||||
slot_machine_button.visible = true
|
||||
slot_machine_button.visible = Brand.is_uat_environment()
|
||||
if credits_badge != null:
|
||||
credits_badge.visible = BlockSessionService.session_kind != "simulation"
|
||||
_apply_question_theme()
|
||||
|
||||
|
||||
@@ -3404,7 +3411,9 @@ func _style_choice_button_for_state(index: int, choice_id: String) -> void:
|
||||
var dark: bool = true if theme_service == null else theme_service.is_dark_mode()
|
||||
var state := "default"
|
||||
var correct_id := str(BlockSessionService.get_current_question().get("correct_choice_id", ""))
|
||||
var reviewing := pending_correct_advance or not current_answer.is_empty()
|
||||
# Exam simulations don't reveal right/wrong - you move on after submitting,
|
||||
# same as a real exam - so only "selected"/"eliminated" styling applies here.
|
||||
var reviewing := BlockSessionService.session_kind != "simulation" and (pending_correct_advance or not current_answer.is_empty())
|
||||
if reviewing and choice_id == correct_id:
|
||||
state = "correct"
|
||||
elif locked_wrong_choice_ids.has(choice_id) or (reviewing and choice_id != "" and choice_id != correct_id):
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
extends PanelContainer
|
||||
|
||||
const Brand := preload("res://scripts/ui/medmind_style.gd")
|
||||
const STAR_ICON := preload("res://assets/icons/lucide/star.svg")
|
||||
const CLOCK_ICON := preload("res://assets/icons/lucide/clock-3.svg")
|
||||
const CABINET_FRAME := preload("res://assets/slot_machine/cabinet_frame.png")
|
||||
const LEVER_TEXTURE := preload("res://assets/slot_machine/lever.png")
|
||||
const SLOT_COIN := preload("res://assets/slot_machine/slot_coin.png")
|
||||
@@ -11,6 +9,7 @@ const SLOT_POTION := preload("res://assets/slot_machine/slot_potion.png")
|
||||
const SLOT_SHIELD := preload("res://assets/slot_machine/slot_shield.png")
|
||||
const SLOT_COIN_STACK := preload("res://assets/slot_machine/slot_coin_stack.png")
|
||||
const SLOT_GIFT := preload("res://assets/slot_machine/slot_gift.png")
|
||||
const CLOCK_ICON := preload("res://assets/icons/lucide/clock-3.svg")
|
||||
const REEL_SYMBOLS := [SLOT_COIN, SLOT_GEM, SLOT_POTION, SLOT_SHIELD, SLOT_COIN_STACK, SLOT_GIFT]
|
||||
# fraction-of-image rect of the cabinet's empty reel window, measured against cabinet_frame.png
|
||||
const WINDOW_RECT := Rect2(0.203, 0.246, 0.591, 0.604)
|
||||
@@ -24,7 +23,8 @@ const REWARD_ICONS := {
|
||||
"good_luck": {"texture": SLOT_COIN, "modulate": false, "tint": true},
|
||||
}
|
||||
const MACHINE_SIZE := 380.0
|
||||
const CELL := 44.0
|
||||
const CELL := 71.0
|
||||
const REEL_SEPARATION := 4
|
||||
|
||||
var main: Control
|
||||
|
||||
@@ -32,24 +32,10 @@ var drag_active := false
|
||||
var drag_offset := Vector2.ZERO
|
||||
var has_been_positioned := false
|
||||
|
||||
var subtitle_label: Label
|
||||
var machine_root: Control
|
||||
var lever_button: TextureButton
|
||||
var reel_states: 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
|
||||
var rewards_list: VBoxContainer
|
||||
var footer_card: PanelContainer
|
||||
var footer_icon_panel: PanelContainer
|
||||
var footer_icon: TextureRect
|
||||
var footer_heading: Label
|
||||
var footer_description: Label
|
||||
|
||||
var _spinning := false
|
||||
|
||||
@@ -59,7 +45,7 @@ func _ready() -> void:
|
||||
visible = false
|
||||
top_level = true
|
||||
mouse_filter = Control.MOUSE_FILTER_STOP
|
||||
custom_minimum_size = Vector2(460, 680)
|
||||
custom_minimum_size = Vector2(440, 470)
|
||||
size = custom_minimum_size
|
||||
|
||||
_build_ui()
|
||||
@@ -69,10 +55,8 @@ func _ready() -> void:
|
||||
_on_viewport_size_changed()
|
||||
|
||||
CreditsService.credits_changed.connect(_refresh_spin_button)
|
||||
CreditsService.spin_config_loaded.connect(_refresh_rewards)
|
||||
UIThemeService.theme_changed.connect(func(_dark: bool): refresh_theme_controls())
|
||||
refresh_theme_controls()
|
||||
_refresh_rewards()
|
||||
_refresh_spin_button()
|
||||
|
||||
|
||||
@@ -86,7 +70,6 @@ func open_panel() -> void:
|
||||
_clamp_to_viewport()
|
||||
CreditsService.refresh()
|
||||
CreditsService.fetch_spin_config()
|
||||
_refresh_rewards()
|
||||
_refresh_spin_button()
|
||||
|
||||
|
||||
@@ -115,34 +98,13 @@ func _build_ui() -> void:
|
||||
margin.add_child(content)
|
||||
|
||||
_build_title_bar(content)
|
||||
|
||||
var scroll := ScrollContainer.new()
|
||||
scroll.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||||
scroll.horizontal_scroll_mode = ScrollContainer.SCROLL_MODE_DISABLED
|
||||
content.add_child(scroll)
|
||||
|
||||
var scroll_content := VBoxContainer.new()
|
||||
scroll_content.add_theme_constant_override("separation", 14)
|
||||
scroll_content.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
scroll.add_child(scroll_content)
|
||||
|
||||
subtitle_label = Label.new()
|
||||
subtitle_label.text = "Test your luck and win exciting rewards!"
|
||||
subtitle_label.add_theme_font_override("font", Brand.font)
|
||||
subtitle_label.add_theme_font_size_override("font_size", 13)
|
||||
subtitle_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
scroll_content.add_child(subtitle_label)
|
||||
|
||||
_build_machine(scroll_content)
|
||||
_build_controls(scroll_content)
|
||||
_build_rewards_section(scroll_content)
|
||||
_build_footer(scroll_content)
|
||||
_build_machine(content)
|
||||
|
||||
status_label = Label.new()
|
||||
status_label.add_theme_font_override("font", Brand.font)
|
||||
status_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
||||
status_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
scroll_content.add_child(status_label)
|
||||
content.add_child(status_label)
|
||||
|
||||
|
||||
func _build_title_bar(content: VBoxContainer) -> void:
|
||||
@@ -153,13 +115,10 @@ func _build_title_bar(content: VBoxContainer) -> void:
|
||||
title_bar.gui_input.connect(_on_title_bar_gui_input)
|
||||
content.add_child(title_bar)
|
||||
|
||||
var title := Label.new()
|
||||
title.text = "RZ Slot Machine"
|
||||
title.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
title.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
title.add_theme_font_override("font", Brand.font)
|
||||
title.add_theme_font_size_override("font_size", 18)
|
||||
title_bar.add_child(title)
|
||||
var spacer := Control.new()
|
||||
spacer.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
spacer.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
title_bar.add_child(spacer)
|
||||
|
||||
var close := Button.new()
|
||||
close.name = "SlotMachineClose"
|
||||
@@ -200,7 +159,7 @@ func _build_machine(parent: Control) -> void:
|
||||
window.add_child(reel_center)
|
||||
|
||||
var reels_grid := HBoxContainer.new()
|
||||
reels_grid.add_theme_constant_override("separation", 10)
|
||||
reels_grid.add_theme_constant_override("separation", REEL_SEPARATION)
|
||||
reel_center.add_child(reels_grid)
|
||||
|
||||
reel_states.clear()
|
||||
@@ -251,282 +210,15 @@ func _build_machine(parent: Control) -> void:
|
||||
machine_root.add_child(lever_button)
|
||||
|
||||
|
||||
func _build_controls(parent: Control) -> void:
|
||||
var dark := UIThemeService.is_dark_mode()
|
||||
|
||||
win_up_to_card = PanelContainer.new()
|
||||
win_up_to_card.add_theme_stylebox_override("panel", Brand.content_card_box(dark, false))
|
||||
parent.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", 14)
|
||||
win_up_to_label.add_theme_color_override("font_color", Brand.text_color(dark))
|
||||
win_margin.add_child(win_up_to_label)
|
||||
|
||||
var controls_row := HBoxContainer.new()
|
||||
controls_row.add_theme_constant_override("separation", 10)
|
||||
parent.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", 10)
|
||||
cost_margin.add_theme_constant_override("margin_right", 10)
|
||||
cost_margin.add_theme_constant_override("margin_top", 6)
|
||||
cost_margin.add_theme_constant_override("margin_bottom", 6)
|
||||
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)
|
||||
cost_caption.add_theme_font_size_override("font_size", 10)
|
||||
cost_caption.add_theme_color_override("font_color", Brand.muted_color(dark))
|
||||
cost_box.add_child(cost_caption)
|
||||
cost_value_label = Label.new()
|
||||
cost_value_label.add_theme_font_override("font", Brand.font)
|
||||
cost_value_label.add_theme_font_size_override("font_size", 14)
|
||||
cost_value_label.add_theme_color_override("font_color", Brand.text_color(dark))
|
||||
cost_box.add_child(cost_value_label)
|
||||
|
||||
spin_button = Button.new()
|
||||
spin_button.text = "Spin"
|
||||
spin_button.custom_minimum_size = Vector2(110, 52)
|
||||
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", 16)
|
||||
_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", 10)
|
||||
auto_margin.add_theme_constant_override("margin_right", 10)
|
||||
auto_margin.add_theme_constant_override("margin_top", 6)
|
||||
auto_margin.add_theme_constant_override("margin_bottom", 6)
|
||||
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)
|
||||
auto_box.add_child(auto_spin_toggle)
|
||||
var auto_caption := Label.new()
|
||||
auto_caption.text = "10 spins"
|
||||
auto_caption.add_theme_font_override("font", Brand.font)
|
||||
auto_caption.add_theme_font_size_override("font_size", 10)
|
||||
auto_caption.add_theme_color_override("font_color", Brand.muted_color(dark))
|
||||
auto_box.add_child(auto_caption)
|
||||
|
||||
var info_label := Label.new()
|
||||
info_label.text = "All rewards are instant and sent to your account."
|
||||
info_label.add_theme_font_override("font", Brand.font)
|
||||
info_label.add_theme_font_size_override("font_size", 10)
|
||||
info_label.add_theme_color_override("font_color", Brand.muted_color(dark))
|
||||
info_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
parent.add_child(info_label)
|
||||
|
||||
|
||||
func _build_rewards_section(parent: Control) -> void:
|
||||
var dark := UIThemeService.is_dark_mode()
|
||||
var panel := PanelContainer.new()
|
||||
panel.add_theme_stylebox_override("panel", Brand.content_card_box(dark, false))
|
||||
parent.add_child(panel)
|
||||
|
||||
var margin := MarginContainer.new()
|
||||
margin.add_theme_constant_override("margin_left", 14)
|
||||
margin.add_theme_constant_override("margin_right", 14)
|
||||
margin.add_theme_constant_override("margin_top", 12)
|
||||
margin.add_theme_constant_override("margin_bottom", 12)
|
||||
panel.add_child(margin)
|
||||
|
||||
var column := VBoxContainer.new()
|
||||
column.add_theme_constant_override("separation", 10)
|
||||
margin.add_child(column)
|
||||
|
||||
var heading := Label.new()
|
||||
heading.text = "Possible Rewards"
|
||||
heading.add_theme_font_override("font", Brand.font)
|
||||
heading.add_theme_font_size_override("font_size", 15)
|
||||
heading.add_theme_color_override("font_color", Brand.text_color(dark))
|
||||
column.add_child(heading)
|
||||
|
||||
rewards_list = VBoxContainer.new()
|
||||
rewards_list.add_theme_constant_override("separation", 8)
|
||||
column.add_child(rewards_list)
|
||||
|
||||
|
||||
func _build_footer(parent: Control) -> void:
|
||||
var dark := UIThemeService.is_dark_mode()
|
||||
footer_card = PanelContainer.new()
|
||||
footer_card.add_theme_stylebox_override("panel", Brand.content_card_box(dark, false))
|
||||
parent.add_child(footer_card)
|
||||
|
||||
var margin := MarginContainer.new()
|
||||
margin.add_theme_constant_override("margin_left", 14)
|
||||
margin.add_theme_constant_override("margin_right", 14)
|
||||
margin.add_theme_constant_override("margin_top", 10)
|
||||
margin.add_theme_constant_override("margin_bottom", 10)
|
||||
footer_card.add_child(margin)
|
||||
|
||||
var row := HBoxContainer.new()
|
||||
row.add_theme_constant_override("separation", 12)
|
||||
margin.add_child(row)
|
||||
|
||||
footer_icon_panel = PanelContainer.new()
|
||||
footer_icon_panel.custom_minimum_size = Vector2(32, 32)
|
||||
footer_icon_panel.size_flags_vertical = Control.SIZE_SHRINK_CENTER
|
||||
footer_icon_panel.add_theme_stylebox_override("panel", Brand.icon_circle_box(dark, Brand.ROYAL_BLUE, 16))
|
||||
footer_icon = TextureRect.new()
|
||||
footer_icon.texture = STAR_ICON
|
||||
footer_icon.custom_minimum_size = Vector2(16, 16)
|
||||
footer_icon.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
||||
footer_icon.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
||||
footer_icon.modulate = Brand.ROYAL_BLUE
|
||||
footer_icon_panel.add_child(footer_icon)
|
||||
row.add_child(footer_icon_panel)
|
||||
|
||||
var copy := VBoxContainer.new()
|
||||
copy.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
copy.size_flags_vertical = Control.SIZE_SHRINK_CENTER
|
||||
copy.add_theme_constant_override("separation", 2)
|
||||
footer_heading = Label.new()
|
||||
footer_heading.text = "How it works"
|
||||
footer_heading.add_theme_font_override("font", Brand.font)
|
||||
footer_heading.add_theme_font_size_override("font_size", 14)
|
||||
footer_heading.add_theme_color_override("font_color", Brand.text_color(dark))
|
||||
copy.add_child(footer_heading)
|
||||
footer_description = Label.new()
|
||||
footer_description.text = "Spend RZ Coins to spin the slot machine. Win coins, boosts, tokens, and more!"
|
||||
footer_description.add_theme_font_override("font", Brand.font)
|
||||
footer_description.add_theme_font_size_override("font_size", 11)
|
||||
footer_description.add_theme_color_override("font_color", Brand.muted_color(dark))
|
||||
footer_description.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
||||
copy.add_child(footer_description)
|
||||
row.add_child(copy)
|
||||
|
||||
|
||||
func refresh_theme_controls() -> void:
|
||||
var dark := UIThemeService.is_dark_mode()
|
||||
add_theme_stylebox_override("panel", Brand.content_card_box(dark, true, Brand.ROYAL_BLUE))
|
||||
subtitle_label.add_theme_color_override("font_color", Brand.muted_color(dark))
|
||||
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, 16))
|
||||
footer_heading.add_theme_color_override("font_color", Brand.text_color(dark))
|
||||
footer_description.add_theme_color_override("font_color", Brand.muted_color(dark))
|
||||
_refresh_rewards()
|
||||
|
||||
|
||||
func _reward_color(key: String) -> Color:
|
||||
match key:
|
||||
"jackpot": return Brand.AMBER
|
||||
"epic": return Brand.PURPLE
|
||||
"great": return Brand.ROYAL_BLUE
|
||||
"exam_token": return Brand.ROYAL_BLUE
|
||||
"qbank_reset": return Brand.SUCCESS
|
||||
"nice": return Brand.SKY_BLUE
|
||||
"good_luck": return Brand.SLATE
|
||||
_: return Brand.ROYAL_BLUE
|
||||
|
||||
|
||||
func _refresh_rewards() -> void:
|
||||
if cost_value_label == null:
|
||||
return
|
||||
var dark := UIThemeService.is_dark_mode()
|
||||
cost_value_label.text = "%d RZ Coins" % CreditsService.spin_cost
|
||||
|
||||
var max_coins := 0
|
||||
for reward_variant in CreditsService.spin_rewards:
|
||||
if typeof(reward_variant) != TYPE_DICTIONARY:
|
||||
continue
|
||||
max_coins = maxi(max_coins, int((reward_variant as Dictionary).get("coinAmount", 0)))
|
||||
win_up_to_label.text = "Win up to %s RZ Coins!" % _format_thousands(max_coins) if max_coins > 0 else ""
|
||||
|
||||
for child in rewards_list.get_children():
|
||||
child.queue_free()
|
||||
for reward_variant in CreditsService.spin_rewards:
|
||||
if typeof(reward_variant) != TYPE_DICTIONARY:
|
||||
continue
|
||||
var reward: Dictionary = reward_variant
|
||||
rewards_list.add_child(_build_reward_row(dark, reward))
|
||||
|
||||
|
||||
func _build_reward_row(dark: bool, reward: Dictionary) -> HBoxContainer:
|
||||
var key := str(reward.get("key", ""))
|
||||
var accent := _reward_color(key)
|
||||
var row := HBoxContainer.new()
|
||||
row.add_theme_constant_override("separation", 10)
|
||||
|
||||
var icon_panel := PanelContainer.new()
|
||||
icon_panel.custom_minimum_size = Vector2(34, 34)
|
||||
icon_panel.size_flags_vertical = Control.SIZE_SHRINK_CENTER
|
||||
icon_panel.add_theme_stylebox_override("panel", Brand.icon_circle_box(dark, accent, 17))
|
||||
var icon := TextureRect.new()
|
||||
var spec: Dictionary = REWARD_ICONS.get(key, {"texture": SLOT_COIN, "modulate": false})
|
||||
icon.texture = spec.get("texture")
|
||||
icon.custom_minimum_size = Vector2(20, 20)
|
||||
icon.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
||||
icon.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
||||
if spec.get("modulate", false):
|
||||
icon.modulate = accent
|
||||
elif spec.get("tint", false):
|
||||
icon.modulate = Color("94a3b8")
|
||||
icon_panel.add_child(icon)
|
||||
row.add_child(icon_panel)
|
||||
|
||||
var copy := VBoxContainer.new()
|
||||
copy.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
copy.size_flags_vertical = Control.SIZE_SHRINK_CENTER
|
||||
copy.add_theme_constant_override("separation", 0)
|
||||
var label := Label.new()
|
||||
label.text = str(reward.get("label", ""))
|
||||
label.add_theme_font_override("font", Brand.font)
|
||||
label.add_theme_font_size_override("font_size", 12)
|
||||
label.add_theme_color_override("font_color", Brand.text_color(dark))
|
||||
copy.add_child(label)
|
||||
var description := Label.new()
|
||||
description.text = str(reward.get("description", ""))
|
||||
description.add_theme_font_override("font", Brand.font)
|
||||
description.add_theme_font_size_override("font_size", 10)
|
||||
description.add_theme_color_override("font_color", Brand.muted_color(dark))
|
||||
copy.add_child(description)
|
||||
row.add_child(copy)
|
||||
|
||||
var percent_label := Label.new()
|
||||
percent_label.text = "%s%%" % _format_percent(float(reward.get("probability", 0.0)) * 100.0)
|
||||
percent_label.add_theme_font_override("font", Brand.font)
|
||||
percent_label.add_theme_font_size_override("font_size", 12)
|
||||
percent_label.add_theme_color_override("font_color", accent)
|
||||
row.add_child(percent_label)
|
||||
|
||||
return row
|
||||
|
||||
|
||||
func _refresh_spin_button() -> void:
|
||||
if spin_button == null:
|
||||
if lever_button == null:
|
||||
return
|
||||
var disabled := _spinning or CreditsService.credits < CreditsService.spin_cost
|
||||
spin_button.disabled = disabled
|
||||
lever_button.disabled = disabled
|
||||
lever_button.disabled = _spinning or CreditsService.credits < CreditsService.spin_cost
|
||||
|
||||
|
||||
func _on_lever_pulled() -> void:
|
||||
@@ -545,13 +237,7 @@ func _on_spin_pressed() -> void:
|
||||
return
|
||||
_spinning = true
|
||||
_refresh_spin_button()
|
||||
var spin_count := 10 if auto_spin_toggle.button_pressed else 1
|
||||
for _i in range(spin_count):
|
||||
if CreditsService.credits < CreditsService.spin_cost:
|
||||
break
|
||||
var should_continue := await _do_one_spin()
|
||||
if not should_continue:
|
||||
break
|
||||
await _do_one_spin()
|
||||
_spinning = false
|
||||
_refresh_spin_button()
|
||||
|
||||
@@ -679,6 +365,8 @@ func _play_coin_burst(coins_won: int) -> void:
|
||||
for index in range(coin_count):
|
||||
var coin := TextureRect.new()
|
||||
coin.texture = SLOT_COIN
|
||||
coin.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
||||
coin.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
||||
coin.custom_minimum_size = Vector2(16, 16)
|
||||
coin.size = Vector2(16, 16)
|
||||
coin.top_level = true
|
||||
@@ -700,25 +388,6 @@ func _play_coin_burst(coins_won: int) -> void:
|
||||
credits_badge.bump())
|
||||
|
||||
|
||||
func _style_spin_button() -> void:
|
||||
var normal := StyleBoxFlat.new()
|
||||
normal.bg_color = Brand.ROYAL_BLUE
|
||||
normal.set_corner_radius_all(8)
|
||||
var hover := StyleBoxFlat.new()
|
||||
hover.bg_color = Brand.SKY_BLUE
|
||||
hover.set_corner_radius_all(8)
|
||||
var disabled := StyleBoxFlat.new()
|
||||
disabled.bg_color = Color(Brand.ROYAL_BLUE, 0.35)
|
||||
disabled.set_corner_radius_all(8)
|
||||
spin_button.add_theme_stylebox_override("normal", normal)
|
||||
spin_button.add_theme_stylebox_override("hover", hover)
|
||||
spin_button.add_theme_stylebox_override("pressed", normal)
|
||||
spin_button.add_theme_stylebox_override("disabled", disabled)
|
||||
spin_button.add_theme_color_override("font_color", Brand.DARK_TEXT)
|
||||
spin_button.add_theme_color_override("font_hover_color", Brand.DARK_TEXT)
|
||||
spin_button.add_theme_color_override("font_disabled_color", Color(Brand.DARK_TEXT, 0.7))
|
||||
|
||||
|
||||
func _on_title_bar_gui_input(event: InputEvent) -> void:
|
||||
var touch_event := event as InputEventScreenTouch
|
||||
if touch_event != null:
|
||||
@@ -757,21 +426,3 @@ func _clamp_to_viewport() -> void:
|
||||
var viewport_size := get_viewport_rect().size
|
||||
position.x = clampf(position.x, 12.0, maxf(12.0, viewport_size.x - size.x - 12.0))
|
||||
position.y = clampf(position.y, 12.0, maxf(12.0, viewport_size.y - size.y - 12.0))
|
||||
|
||||
|
||||
func _format_thousands(value: int) -> String:
|
||||
var digits := str(absi(value))
|
||||
var grouped := ""
|
||||
var count := 0
|
||||
for index in range(digits.length() - 1, -1, -1):
|
||||
grouped = digits[index] + grouped
|
||||
count += 1
|
||||
if count % 3 == 0 and index != 0:
|
||||
grouped = "," + grouped
|
||||
return ("-" if value < 0 else "") + grouped
|
||||
|
||||
|
||||
func _format_percent(value: float) -> String:
|
||||
if absf(value - roundf(value)) < 0.001:
|
||||
return str(int(roundf(value)))
|
||||
return "%.1f" % value
|
||||
|
||||
Reference in New Issue
Block a user