2025-07-09 16:07:36 +00:00
|
|
|
|
extends CanvasLayer
|
|
|
|
|
|
|
|
|
|
signal exit(arg)
|
|
|
|
|
|
|
|
|
|
@onready var bg = $BG as TextureRect
|
2025-07-10 09:13:31 +00:00
|
|
|
|
@onready var front_lay = $MahjongsFrontLay as CanvasItem
|
2025-07-10 16:29:46 +00:00
|
|
|
|
@onready var hand = $Hand as CanvasItem
|
|
|
|
|
@onready var stand_root = $Stand as CanvasItem
|
2025-07-10 09:13:31 +00:00
|
|
|
|
@onready var grid = $Stand/MahjongGrid as GridContainer
|
|
|
|
|
|
|
|
|
|
var mahjongs = {
|
2025-07-10 16:29:46 +00:00
|
|
|
|
# [type][number]
|
|
|
|
|
"风南": preload("uid://6hdekasuabnm"),
|
|
|
|
|
"万2": preload("uid://c6xcefh4x2t5h"),
|
|
|
|
|
"万3": preload("uid://dc6sj2holh1gn"),
|
|
|
|
|
"万5": preload("uid://bd12rrssmrdbs"),
|
|
|
|
|
"条1": preload("uid://batbu02i8svf6"),
|
|
|
|
|
"条2": preload("uid://cbn74yc8j72v6"),
|
|
|
|
|
"条3": preload("uid://b66kqhy1mmhc5"),
|
|
|
|
|
"筒1": preload("uid://ccpexjd64s5nn"),
|
|
|
|
|
"筒2": preload("uid://djefka3gyhxsv"),
|
|
|
|
|
"筒4": preload("uid://da50cog64b0tb"),
|
|
|
|
|
"筒7": preload("uid://c7tea8ostqbiu"),
|
|
|
|
|
"筒8": preload("uid://cr6404ghilc7u"),
|
|
|
|
|
"筒9": preload("uid://iovhne3h5dqe"),
|
2025-07-10 09:13:31 +00:00
|
|
|
|
}
|
|
|
|
|
|
2025-07-10 16:29:46 +00:00
|
|
|
|
@onready var standing_mahjongs_btn: Array[TextureButton] = [%"0", %"1", %"2", %"3", %"4", %"5", %"6", %"7", %"8", %"9", %"10", %"11", %"12", %"13"]
|
|
|
|
|
# 替换后会从数组中移除
|
|
|
|
|
@onready var holding_mahjongs_btn_dict: Dictionary[int, TextureButton] = {14: %"14", 15: %"15", 16: %"16"}
|
|
|
|
|
|
2025-07-10 09:13:31 +00:00
|
|
|
|
|
2025-07-10 16:29:46 +00:00
|
|
|
|
var current_round := 0
|
|
|
|
|
# 回合1-4摸牌:3万、2万、1条、2筒(胜利)
|
|
|
|
|
var dispatched_card_per_round: Array[String] = ["万3", "万2", "条1", "筒2"]
|
|
|
|
|
# 回合1-3自动打出的牌+3个密码(共六张):2万、3万、1条、南风、4筒、1筒
|
|
|
|
|
var useless_cards: Array[String] = ["万2", "万3", "条1", "风南", "筒4", "筒1"]
|
|
|
|
|
# 玩家初始牌型(13张):78筒x1 南风x1 12条x1 4筒x1 5万x2 2筒x2 9筒x2 1筒
|
|
|
|
|
# 胜利牌型:2筒x3、9筒x2、5万x3、123条x1、789筒x1
|
|
|
|
|
var standing_cards: Array[String] = ["筒7", "筒8", "风南", "条1", "条2", "筒4", "万5", "万5", "筒2", "筒2", "筒9", "筒9", "筒1", ""]
|
|
|
|
|
# 赖子手在左下角桌子下,手中为三个麻将,5万、3条、9筒
|
|
|
|
|
var holding_cards_dict: Dictionary[int, String] = {14: "万5", 15: "条3", 16: "筒9"}
|
2025-07-10 09:13:31 +00:00
|
|
|
|
|
2025-07-10 16:29:46 +00:00
|
|
|
|
var freezing = true:
|
|
|
|
|
set(val):
|
|
|
|
|
if freezing != val:
|
|
|
|
|
freezing = val
|
|
|
|
|
if freezing and selected_btn:
|
|
|
|
|
_toggle_selected(selected_btn, false)
|
2025-07-10 09:13:31 +00:00
|
|
|
|
var success = false
|
|
|
|
|
var selected_btn: TextureButton
|
2025-07-09 16:07:36 +00:00
|
|
|
|
|
2025-07-10 16:29:46 +00:00
|
|
|
|
var c03_dialog = preload("uid://b66v5hsf3tdox")
|
|
|
|
|
|
2025-07-09 16:07:36 +00:00
|
|
|
|
func _ready() -> void:
|
|
|
|
|
layer = GlobalConfig.CANVAS_LAYER_LITTLE_GAME
|
2025-07-10 16:29:46 +00:00
|
|
|
|
stand_root.hide()
|
|
|
|
|
hand.hide()
|
2025-07-10 09:13:31 +00:00
|
|
|
|
_toggle_hightlight_for_all(false)
|
2025-07-10 16:29:46 +00:00
|
|
|
|
for b in standing_mahjongs_btn:
|
2025-07-10 09:13:31 +00:00
|
|
|
|
b.mouse_entered.connect(_toggel_hover.bind(b, true))
|
|
|
|
|
b.mouse_exited.connect(_toggel_hover.bind(b, false))
|
|
|
|
|
b.pressed.connect(_on_btn_pressed.bind(b))
|
2025-07-10 16:29:46 +00:00
|
|
|
|
for b in holding_mahjongs_btn_dict.values():
|
2025-07-10 09:13:31 +00:00
|
|
|
|
b.mouse_entered.connect(_toggel_hover.bind(b, true))
|
|
|
|
|
b.mouse_exited.connect(_toggel_hover.bind(b, false))
|
|
|
|
|
b.pressed.connect(_on_btn_pressed.bind(b))
|
|
|
|
|
|
2025-07-10 16:29:46 +00:00
|
|
|
|
# 检查是否从整理麻将游戏中跳转过来
|
|
|
|
|
var transition_time = ArchiveManager.runtime_get("c03_mahjong_game_black_transition_time", 0.0)
|
|
|
|
|
if transition_time > 0:
|
|
|
|
|
await Util.wait(transition_time)
|
|
|
|
|
_play_dialogue_with_update_stage(0)
|
|
|
|
|
await _await_dialog(0)
|
|
|
|
|
_start_game()
|
|
|
|
|
|
2025-07-10 09:13:31 +00:00
|
|
|
|
|
|
|
|
|
func _toggel_hover(btn: TextureButton, hovering: bool) -> void:
|
|
|
|
|
if freezing:
|
|
|
|
|
return
|
2025-07-10 16:29:46 +00:00
|
|
|
|
if btn.disabled:
|
|
|
|
|
hovering = false
|
2025-07-10 09:13:31 +00:00
|
|
|
|
_toggle_hightlight(btn, hovering)
|
|
|
|
|
|
2025-07-10 16:29:46 +00:00
|
|
|
|
|
2025-07-10 09:13:31 +00:00
|
|
|
|
func _on_btn_pressed(btn: TextureButton) -> void:
|
|
|
|
|
if freezing:
|
|
|
|
|
return
|
|
|
|
|
if btn != selected_btn:
|
|
|
|
|
if selected_btn:
|
|
|
|
|
_toggle_selected(selected_btn, false)
|
2025-07-10 16:29:46 +00:00
|
|
|
|
_exchange_texture_and_card(btn, selected_btn)
|
2025-07-10 09:13:31 +00:00
|
|
|
|
selected_btn = null
|
|
|
|
|
else:
|
|
|
|
|
$SfxSelect.play()
|
|
|
|
|
_toggle_selected(btn, true)
|
|
|
|
|
selected_btn = btn
|
|
|
|
|
else:
|
|
|
|
|
$SfxSelect.play()
|
|
|
|
|
_toggle_selected(btn, false)
|
|
|
|
|
selected_btn = null
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func _toggle_selected(btn:TextureButton, selected: bool) -> void:
|
2025-07-10 16:29:46 +00:00
|
|
|
|
# 0-13 push up. 14-16 in hand, push down.
|
|
|
|
|
var front := int(btn.name) <= 13
|
2025-07-10 09:13:31 +00:00
|
|
|
|
if (front and selected) or (not front and not selected):
|
|
|
|
|
btn.size_flags_vertical = Control.SIZE_SHRINK_BEGIN
|
|
|
|
|
else:
|
|
|
|
|
btn.size_flags_vertical = Control.SIZE_SHRINK_END
|
|
|
|
|
|
|
|
|
|
|
2025-07-10 16:29:46 +00:00
|
|
|
|
func _align_card_textures() -> void:
|
|
|
|
|
# holding_mahjongs_btn 长度会变
|
|
|
|
|
for k in holding_mahjongs_btn_dict:
|
|
|
|
|
holding_mahjongs_btn_dict[k].texture_normal = mahjongs[holding_cards_dict[k]]
|
|
|
|
|
# standing_mahjongs_btn 长度不变
|
|
|
|
|
for i in 14:
|
|
|
|
|
if standing_cards[i]:
|
|
|
|
|
standing_mahjongs_btn[i].texture_normal = mahjongs[standing_cards[i]]
|
|
|
|
|
standing_mahjongs_btn[i].modulate = Color.WHITE
|
|
|
|
|
standing_mahjongs_btn[i].show()
|
|
|
|
|
else:
|
|
|
|
|
standing_mahjongs_btn[i].hide()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 发牌
|
|
|
|
|
func _start_game() -> void:
|
|
|
|
|
# show_hand 结束时会自动 hand_swing
|
|
|
|
|
$AnimationPlayer.play("show_hand")
|
|
|
|
|
_play_dialogue_with_update_stage(1)
|
|
|
|
|
$SfxStart.play()
|
|
|
|
|
stand_root.show()
|
|
|
|
|
hand.show()
|
|
|
|
|
front_lay.hide()
|
|
|
|
|
# dispatch and shuffle
|
|
|
|
|
standing_cards[13] = dispatched_card_per_round[current_round]
|
|
|
|
|
standing_cards.shuffle()
|
|
|
|
|
_align_card_textures()
|
|
|
|
|
# shuffle all cards
|
|
|
|
|
for b in standing_mahjongs_btn:
|
|
|
|
|
_toggle_selected(b, true)
|
|
|
|
|
var tween = create_tween()
|
|
|
|
|
tween.tween_interval(1.0)
|
|
|
|
|
var sfx = $SfxPlace
|
|
|
|
|
for b in standing_mahjongs_btn:
|
|
|
|
|
tween.tween_interval(0.15)
|
|
|
|
|
tween.tween_callback(sfx.play.bind(0.15))
|
|
|
|
|
tween.tween_callback(_toggle_selected.bind(b, false))
|
|
|
|
|
tween.tween_interval(1.5)
|
|
|
|
|
tween.tween_callback(standing_cards.sort)
|
|
|
|
|
tween.tween_callback(_align_card_textures)
|
|
|
|
|
tween.tween_callback($SfxShuffle.play)
|
|
|
|
|
await _await_dialog(1)
|
|
|
|
|
if tween and tween.is_running():
|
|
|
|
|
await tween.finished
|
|
|
|
|
freezing = false
|
|
|
|
|
_play_dialogue_with_update_stage(2)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func _play_dialogue_with_update_stage(stage: int):
|
|
|
|
|
DialogueManager.show_dialogue_balloon(c03_dialog, "c03_s04_打麻将游戏" + str(stage))
|
|
|
|
|
if DialogueManager.dialogue_ended.is_connected(_update_last_dialog):
|
|
|
|
|
DialogueManager.dialogue_ended.disconnect(_update_last_dialog)
|
|
|
|
|
DialogueManager.dialogue_ended.connect(_update_last_dialog.bind(stage), CONNECT_ONE_SHOT)
|
|
|
|
|
|
|
|
|
|
var _last_dialog_stage := -1
|
|
|
|
|
signal _last_dialog_updated
|
|
|
|
|
|
|
|
|
|
func _update_last_dialog(_res, id: int) -> void:
|
|
|
|
|
if id > _last_dialog_stage:
|
|
|
|
|
_last_dialog_stage = id
|
|
|
|
|
_last_dialog_updated.emit()
|
|
|
|
|
|
|
|
|
|
func _await_dialog(id: int) -> void:
|
|
|
|
|
if _last_dialog_stage >= id:
|
|
|
|
|
return
|
|
|
|
|
await _last_dialog_updated
|
|
|
|
|
await _await_dialog(id)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func _exchange_texture_and_card(btn1: TextureButton, btn2: TextureButton) -> void:
|
2025-07-10 09:13:31 +00:00
|
|
|
|
if btn1 and btn2:
|
|
|
|
|
$SfxSwitch.play()
|
2025-07-10 16:29:46 +00:00
|
|
|
|
# exchange texture
|
2025-07-10 09:13:31 +00:00
|
|
|
|
var texture = btn1.texture_normal
|
|
|
|
|
btn1.texture_normal = btn2.texture_normal
|
|
|
|
|
btn2.texture_normal = texture
|
2025-07-10 16:29:46 +00:00
|
|
|
|
# exchange card name
|
|
|
|
|
var id1 := int(btn1.name)
|
|
|
|
|
var id2 := int(btn2.name)
|
|
|
|
|
var card_name1 = standing_cards[id1] if id1 <= 13 else holding_cards_dict[id1]
|
|
|
|
|
var card_name2 = standing_cards[id2] if id2 <= 13 else holding_cards_dict[id2]
|
|
|
|
|
if id1 <= 13:
|
|
|
|
|
standing_cards[id1] = card_name2
|
|
|
|
|
else:
|
|
|
|
|
holding_cards_dict[id1] = card_name2
|
|
|
|
|
if id2 <= 13:
|
|
|
|
|
standing_cards[id2] = card_name1
|
|
|
|
|
else:
|
|
|
|
|
holding_cards_dict[id2] = card_name1
|
|
|
|
|
# 判断回合是否成功
|
|
|
|
|
# 要求: 1、standing 区域有 auto_deal_card 2、holding 区域有 should_be_replaced_card
|
|
|
|
|
# 查找手牌 id 与区域 id
|
|
|
|
|
# 优先先从手里着,再从桌面找不重复的
|
|
|
|
|
var require_replacing_card = intersect(useless_cards, holding_cards_dict)
|
|
|
|
|
var require_dealing_card = intersect(useless_cards, standing_cards, require_replacing_card)
|
|
|
|
|
if require_replacing_card and require_dealing_card:
|
|
|
|
|
useless_cards.erase(require_replacing_card)
|
|
|
|
|
useless_cards.erase(require_dealing_card)
|
|
|
|
|
_toggle_hightlight_for_all(false)
|
|
|
|
|
# 开始执行替换
|
|
|
|
|
freezing = true
|
|
|
|
|
await Util.wait(2.0)
|
|
|
|
|
# 重新排序
|
|
|
|
|
standing_cards.sort()
|
|
|
|
|
$SfxShuffle.play()
|
|
|
|
|
_align_card_textures()
|
|
|
|
|
var standing_id = standing_cards.find(require_dealing_card)
|
|
|
|
|
standing_cards.remove_at(standing_id)
|
|
|
|
|
standing_cards.append("")
|
|
|
|
|
# 替换到手牌后消失
|
|
|
|
|
var holding_id = holding_cards_dict.find_key(require_replacing_card)
|
|
|
|
|
var holding_btn = holding_mahjongs_btn_dict[holding_id]
|
|
|
|
|
holding_mahjongs_btn_dict.erase(holding_id)
|
|
|
|
|
holding_cards_dict.erase(holding_id)
|
|
|
|
|
var tween = create_tween()
|
|
|
|
|
# 渐隐,表示打出
|
|
|
|
|
tween.tween_property(standing_mahjongs_btn[standing_id], "modulate:a", 0.0, 3.0)
|
|
|
|
|
# tween.parallel().tween_property(holding_btn, "modulate:a", 0.0, 3.0)
|
|
|
|
|
# tween.tween_callback(holding_btn.queue_free)
|
|
|
|
|
tween.tween_callback(func(): holding_btn.disabled = true)
|
|
|
|
|
tween.tween_callback(_align_card_textures)
|
|
|
|
|
tween.tween_callback($SfxShuffle.play)
|
|
|
|
|
# 下一回合 unfreeze
|
|
|
|
|
tween.tween_interval(2.0)
|
|
|
|
|
tween.tween_callback(_next_round)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func intersect(arr:Array, b, except := ""):
|
|
|
|
|
var first_intersection = ""
|
|
|
|
|
if b is Dictionary:
|
|
|
|
|
for item in b.values():
|
|
|
|
|
if except and item == except:
|
|
|
|
|
continue
|
|
|
|
|
if arr.has(item):
|
|
|
|
|
first_intersection = item
|
|
|
|
|
break
|
|
|
|
|
elif b is Array:
|
|
|
|
|
for item in arr:
|
|
|
|
|
if except and item == except:
|
|
|
|
|
continue
|
|
|
|
|
if b.has(item):
|
|
|
|
|
first_intersection = item
|
|
|
|
|
break
|
|
|
|
|
return first_intersection
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func _next_round() -> void:
|
|
|
|
|
freezing = true
|
|
|
|
|
current_round += 1
|
|
|
|
|
if current_round == 1:
|
|
|
|
|
# 第一回合结束
|
|
|
|
|
await _await_dialog(2)
|
|
|
|
|
_play_dialogue_with_update_stage(3)
|
|
|
|
|
# 对话结束后,开始第二回合
|
|
|
|
|
await _await_dialog(3)
|
|
|
|
|
_play_dialogue_with_update_stage(4)
|
|
|
|
|
elif current_round == 2:
|
|
|
|
|
# 第二回合结束
|
|
|
|
|
await _await_dialog(4)
|
|
|
|
|
_play_dialogue_with_update_stage(5)
|
|
|
|
|
# 对话结束后,开始第三回合
|
|
|
|
|
await _await_dialog(5)
|
|
|
|
|
_play_dialogue_with_update_stage(6)
|
|
|
|
|
elif current_round == 3:
|
|
|
|
|
# 第三回合结束
|
|
|
|
|
await _await_dialog(6)
|
|
|
|
|
_play_dialogue_with_update_stage(7)
|
|
|
|
|
await _await_dialog(7)
|
|
|
|
|
# 开始第四回合,自摸后成功
|
|
|
|
|
_play_dialogue_with_update_stage(8)
|
|
|
|
|
standing_cards[13] = dispatched_card_per_round[current_round]
|
|
|
|
|
$SfxPlace.play()
|
|
|
|
|
_align_card_textures()
|
|
|
|
|
await Util.wait(1.0)
|
|
|
|
|
standing_cards.sort()
|
|
|
|
|
$SfxShuffle.play()
|
|
|
|
|
_align_card_textures()
|
|
|
|
|
# 第四回合胜利
|
|
|
|
|
if current_round == 3:
|
|
|
|
|
await Util.wait(1.0)
|
|
|
|
|
$SfxSuccess.play()
|
|
|
|
|
print("success")
|
|
|
|
|
await _await_dialog(8)
|
|
|
|
|
exit.emit(true)
|
|
|
|
|
else:
|
|
|
|
|
freezing = false
|
|
|
|
|
|
2025-07-10 09:13:31 +00:00
|
|
|
|
|
|
|
|
|
func _toggle_hightlight(btn: TextureButton, hightlight: bool) -> void:
|
|
|
|
|
if null == btn:
|
|
|
|
|
return
|
|
|
|
|
btn.get_node("光束").enabled = hightlight
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func _toggle_hightlight_for_all(hightlighted: bool) -> void:
|
2025-07-10 16:29:46 +00:00
|
|
|
|
for b in standing_mahjongs_btn:
|
2025-07-10 09:13:31 +00:00
|
|
|
|
_toggle_hightlight(b, hightlighted)
|
2025-07-10 16:29:46 +00:00
|
|
|
|
for b in holding_mahjongs_btn_dict.values():
|
2025-07-10 09:13:31 +00:00
|
|
|
|
_toggle_hightlight(b, hightlighted)
|