class_name LotteryPanel extends PanelModule # 幸运转盘面板: # - 负责转盘奖励格、抽奖接口、旋转动画和结果落账。 # - 动画完成前不允许重复点击,避免同一轮抽奖产生多次本地奖励。 # - 奖励展示和发放都走统一 reward/cost 格式,方便对齐原 H5 配置。 const NumberFormatterScript := preload("res://scripts/core/number_formatter.gd") var _pay_bg_path := "" var _light: TextureRect var _button: Control var _panel: Control func setup(options: Dictionary) -> void: super.setup(options) _pay_bg_path = str(options.get("pay_bg_path", _pay_bg_path)) func open() -> void: _close_modal(false) _panel = _ui.create_legacy_panel_shell("LotteryPanel", Vector2(20.0, 191.0), Vector2(600.0, 578.0), _texture_provider.frame(_texture_provider.atlas_path("lottery"), "panel_icon_lottery_png"), _texture_provider.frame(_texture_provider.atlas_path("lottery"), "panel_title_lottery_png"), Vector2(75.0, 160.0), Vector2(210.0, 160.0), Vector2(220.0, 709.0)) _ui.add_scale9_patch(_panel, "PayBg", _texture_provider.standalone(_pay_bg_path), Vector2(45.0, 261.0), Vector2(550.0, 458.0), Rect2(65.0, 200.0, 392.0, 11.0)) _ui.add_texture(_panel, "DecorLeft", _texture_provider.standalone("res://assets/egret/assets/game/pay/pay_zhuangshi.png"), Vector2(7.0, 246.0), Vector2(167.0, 269.0)) var decor_right: TextureRect = _ui.add_texture(_panel, "DecorRight", _texture_provider.standalone("res://assets/egret/assets/game/pay/pay_zhuangshi.png"), Vector2(467.0, 246.0), Vector2(167.0, 269.0)) decor_right.flip_h = true _light = _ui.add_texture(_panel, "LotteryLight", _texture_provider.frame(_texture_provider.atlas_path("lottery"), "lottery_light_png"), Vector2(68.0, 304.0), Vector2(120.0, 120.0)) _light.visible = false _add_lottery_dots() _ui.add_texture(_panel, "CirLight", _texture_provider.frame(_texture_provider.atlas_path("lottery"), "lottery_l2_png"), Vector2(186.0, 417.0), Vector2(275.0, 180.0), TextureRect.STRETCH_KEEP_ASPECT_CENTERED) var card_positions := [ Vector2(83.0, 319.0), Vector2(180.0, 319.0), Vector2(276.0, 319.0), Vector2(373.0, 319.0), Vector2(469.0, 319.0), Vector2(469.0, 414.0), Vector2(469.0, 510.0), Vector2(469.0, 605.0), Vector2(373.0, 605.0), Vector2(276.0, 605.0), Vector2(180.0, 605.0), Vector2(83.0, 605.0), Vector2(83.0, 510.0), Vector2(83.0, 414.0) ] var lottery_rows: Array[Dictionary] = _game_config.get_lottery_config() for index in range(mini(lottery_rows.size(), 14)): var card := Control.new() card.name = "LotteryCard%s" % index card.position = card_positions[index] card.size = Vector2(90.0, 90.0) _panel.add_child(card) _ui.add_texture(card, "Bg", _texture_provider.common("item_bg"), Vector2.ZERO, Vector2(90.0, 90.0)) var item_id := int(lottery_rows[index].get("item_id", lottery_rows[index].get("value", 0))) var count := int(lottery_rows[index].get("count", lottery_rows[index].get("value", 0))) _ui.add_texture(card, "Icon", _get_item_icon_texture(_game_config.get_item_icon_id(item_id)), Vector2(8.0, 5.0), Vector2(74.0, 68.0), TextureRect.STRETCH_KEEP_ASPECT_CENTERED) _ui.add_panel_label(card, "Count", "x%s" % NumberFormatterScript.compact(count), Vector2(8.0, 64.0), Vector2(74.0, 22.0), 22, Color.html("#b36011"), 1, Color.html("#ffe59d"), HORIZONTAL_ALIGNMENT_RIGHT) _button = _ui.add_texture_button(_panel, "LotteryGo", _texture_provider.frame(_texture_provider.atlas_path("lottery"), "lottery_btn_go_png"), Vector2(254.0, 484.0), Vector2(133.0, 52.0), "", Callable(self, "_go"), 20) _ui.add_panel_label(_panel, "LotteryPrice", _price_text(), Vector2(285.0, 552.0), Vector2(155.0, 24.0), 20, Color.html("#7bff6d"), 0, Color.TRANSPARENT, HORIZONTAL_ALIGNMENT_LEFT) _ui.add_texture(_panel, "GoldIcon", _get_item_icon_texture(3002), Vector2(257.0, 541.0), Vector2(35.0, 35.0), TextureRect.STRETCH_KEEP_ASPECT_CENTERED) var close := _panel.get_node_or_null("PanelClose") if close != null: _panel.move_child(close, _panel.get_child_count() - 1) _open_modal(_panel) func _add_lottery_dots() -> void: var dot_positions := [ ["lottery_dot1_png", Vector2(213.0, 446.0)], ["lottery_dot1_png", Vector2(207.0, 552.0)], ["lottery_dot1_png", Vector2(307.0, 450.0)], ["lottery_dot1_png", Vector2(373.0, 552.0)], ["lottery_dot2_png", Vector2(405.0, 458.0)], ["lottery_dot2_png", Vector2(354.0, 437.0)], ["lottery_dot2_png", Vector2(406.0, 550.0)], ["lottery_dot2_png", Vector2(220.0, 507.0)], ["lottery_dot2_png", Vector2(268.0, 540.0)], ["lottery_dot2_png", Vector2(419.0, 516.0)] ] for index in range(dot_positions.size()): var entry: Array = dot_positions[index] _ui.add_texture(_panel, "LotteryDot%s" % index, _texture_provider.frame(_texture_provider.atlas_path("lottery"), str(entry[0])), entry[1], Vector2(12.0, 12.0), TextureRect.STRETCH_KEEP_ASPECT_CENTERED) func _price_text() -> String: return "(本次免费)" if int(_player_data().get("lottery_count", 0)) == 0 else "x%s" % int(_game_config.get_common_config(15).get("min", 0)) func _go() -> void: if _is_busy(): return var player := _player_data() var cost := 0 if int(player.get("lottery_count", 0)) == 0 else int(_game_config.get_common_config(15).get("min", 0)) if cost > int(player.get("gold", 0)): _show_toast("金豆不足") return _set_busy(true) _set_texture_button_enabled(_button, false) var result: Dictionary = await _activity_api.lottery(_token()) _set_busy(false) if not result.get("ok", false): _set_texture_button_enabled(_button, true) _show_toast(_response_status_text(result, "抽奖失败")) return var data = _response_data(result, {}) var reward_id := int(data.get("id", 1)) if data is Dictionary else 1 if data is Dictionary: player["lottery_count"] = int(data.get("count", int(player.get("lottery_count", 0)) + 1)) player["gold"] = maxi(int(player.get("gold", 0)) - cost, 0) _render_player() await _play_effect(reward_id - 1) var reward_config := _find_config_by_id(_game_config.get_lottery_config(), reward_id) if not reward_config.is_empty(): var reward_text := "%s:%s" % [int(reward_config.get("item_id", reward_config.get("value", 0))), int(reward_config.get("count", 1))] _add_reward_items(reward_text) _show_toast("抽中 %s" % _format_reward_text(reward_text)) _set_texture_button_enabled(_button, true) func _play_effect(target_index: int) -> void: if _panel == null: return var cards: Array[Control] = [] for index in range(14): var card := _panel.get_node_or_null("LotteryCard%s" % index) as Control if card != null: cards.append(card) if cards.is_empty(): return for round_index in range(34 + target_index): var selected := round_index % cards.size() for index in range(cards.size()): cards[index].modulate = Color(1.25, 1.25, 1.25, 1.0) if index == selected else Color.WHITE if _light != null: _light.visible = true _light.position = cards[selected].position - Vector2(18.0, 18.0) if _owner != null: await _owner.get_tree().create_timer(0.035 + minf(float(round_index) * 0.002, 0.06)).timeout