feat: 由AI辅助进行游戏内容编写

This commit is contained in:
2026-06-22 11:40:53 +08:00
parent 2d6bf19a10
commit 70bd359f8a
9 changed files with 1992 additions and 455 deletions
File diff suppressed because it is too large Load Diff
+405 -11
View File
@@ -1,24 +1,418 @@
extends Node2D
var description: String
var type: String
var card_name: String
## ============================================================
## 纸片化学 - 卡牌脚本
## card.gd - 单张卡牌的显示、交互和数据管理
## ============================================================
# ---- 信号 ----
signal card_clicked(card: Node2D)
signal card_hovered(card: Node2D)
signal card_unhovered(card: Node2D)
signal card_drag_started(card: Node2D)
signal card_drag_ended(card: Node2D, position: Vector2)
signal card_double_clicked(card: Node2D)
# ---- 卡牌数据 ----
var card_id: String = ""
var card_name: String = ""
var description: String = ""
var card_type: int = 0
var element_symbol: String = ""
var atom_group_formula: String = ""
var condition_effect_primary: int = -1
var condition_effect_secondary: int = -1
var card_kind: String = ""
# ---- 显示状态 ----
var is_face_up: bool = true
var is_selected: bool = false
var is_dragging: bool = false
var is_highlighted: bool = false
var is_in_hand: bool = true
var is_in_reaction_area: bool = false
var is_in_element_area: bool = false
var original_position: Vector2 = Vector2.ZERO
var card_owner_id: int = -1
# ---- 显示参数 ----
var card_width: float = 120.0
var card_height: float = 180.0
var card_scale_normal: float = 1.0
var card_scale_hover: float = 1.1
var card_scale_selected: float = 1.15
var card_scale_dragging: float = 1.2
# ---- 颜色配置 ----
var color_atom_metal: Color = Color(0.75, 0.75, 0.82, 1.0)
var color_atom_nonmetal: Color = Color(0.2, 0.6, 0.8, 1.0)
var color_atom_group: Color = Color(0.9, 0.7, 0.2, 1.0)
var color_condition: Color = Color(0.85, 0.45, 0.2, 1.0)
var color_sequence: Color = Color(0.6, 0.3, 0.7, 1.0)
var color_count: Color = Color(0.5, 0.5, 0.5, 1.0)
var color_selected: Color = Color(1.0, 1.0, 0.3, 0.5)
var color_highlight: Color = Color(0.3, 1.0, 0.3, 0.3)
var color_back: Color = Color(0.15, 0.15, 0.25, 1.0)
func set_texture(pic: String) -> void:
var image: Image = Image.new()
image.load(pic)
$Sprite.texture = ImageTexture.create_from_image(image)
func _ready() -> void:
_setup_clickable_area()
visible = false
func _setup_clickable_area() -> void:
if not has_node("ClickableArea"):
var area: Area2D = Area2D.new()
area.name = "ClickableArea"
add_child(area)
var collision: CollisionShape2D = CollisionShape2D.new()
var shape: RectangleShape2D = RectangleShape2D.new()
shape.size = Vector2(card_width, card_height)
collision.shape = shape
collision.position = Vector2(card_width / 2.0, card_height / 2.0)
area.add_child(collision)
area.input_event.connect(_on_clickable_area_input_event)
area.mouse_entered.connect(_on_mouse_entered)
area.mouse_exited.connect(_on_mouse_exited)
func set_card(cname: String) -> void:
card_id = cname
card_name = cname
set_texture("user://download/sources/%s/assets/pics/%s" % [DownloadManager.uuid, GameManager.pic_list[card_name]])
if GameManager.card_list.has(cname) and GameManager.card_list[cname] is Dictionary:
var data: Dictionary = GameManager.card_list[cname]
description = data.get("description", "")
card_type = data.get("type", GameLoopManager.CardType.ATOM)
element_symbol = data.get("element", "")
atom_group_formula = data.get("formula", "")
condition_effect_primary = data.get("condition_effect_primary", -1)
condition_effect_secondary = data.get("condition_effect_secondary", -1)
card_kind = data.get("kind", "")
else:
_infer_card_type(cname)
set_texture("user://download/sources/%s/assets/pics/%s" % [DownloadManager.uuid, GameManager.pic_list.get(cname, "")])
update_display()
visible = true
func set_pos(x: int, y: int) -> void:
$Sprite.position = Vector2(x, y)
func _infer_card_type(cname: String) -> void:
if cname.find("点燃") != -1 or cname.find("升温") != -1 or cname.find("降温") != -1 or cname.find("溶解") != -1 or cname.find("过滤") != -1 or cname.find("集气") != -1 or cname.find("提取") != -1 or cname.find("结晶") != -1:
card_type = GameLoopManager.CardType.CONDITION
card_kind = "condition"
elif cname in ["", "", "", "", "", ""]:
card_type = GameLoopManager.CardType.SEQUENCE
elif cname.find("^") != -1 or (cname.find("-") != -1 and cname.find("·") == -1):
card_type = GameLoopManager.CardType.ATOM_GROUP
card_kind = "atom_group"
else:
card_type = GameLoopManager.CardType.ATOM
element_symbol = cname
var metals: Array = ["Li", "Na", "K", "Ca", "Ba", "Mg", "Al", "Zn", "Fe", "Cu", "Ag", "Au", "Sn", "Pb", "Mn", "Cr", "Ni", "Co", "Hg", "Ti"]
if cname in metals:
card_kind = "metal"
else:
card_kind = "nonmetal"
func update_display() -> void:
_update_card_color()
_update_labels()
_update_selection_display()
func _update_card_color() -> void:
if not is_face_up:
_set_background_color(color_back)
return
match card_type:
GameLoopManager.CardType.ATOM:
if card_kind == "metal":
_set_background_color(color_atom_metal)
else:
_set_background_color(color_atom_nonmetal)
GameLoopManager.CardType.ATOM_GROUP:
_set_background_color(color_atom_group)
GameLoopManager.CardType.CONDITION:
_set_background_color(color_condition)
GameLoopManager.CardType.SEQUENCE:
_set_background_color(color_sequence)
GameLoopManager.CardType.COUNT:
_set_background_color(color_count)
_:
_set_background_color(Color.WHITE)
func _set_background_color(color: Color) -> void:
if has_node("Background"):
get_node("Background").color = color
func _update_labels() -> void:
if not is_face_up:
if has_node("NameLabel"):
get_node("NameLabel").text = ""
if has_node("DescriptionLabel"):
get_node("DescriptionLabel").text = ""
return
if has_node("NameLabel"):
var name_label: Label = get_node("NameLabel")
name_label.text = card_name
name_label.visible = true
if has_node("DescriptionLabel"):
var desc_label: Label = get_node("DescriptionLabel")
desc_label.text = description
desc_label.visible = description != ""
if has_node("ElementLabel") and card_type == GameLoopManager.CardType.ATOM:
var elem_label: Label = get_node("ElementLabel")
elem_label.text = element_symbol
elem_label.visible = element_symbol != ""
if has_node("FormulaLabel") and card_type == GameLoopManager.CardType.ATOM_GROUP:
var formula_label: Label = get_node("FormulaLabel")
formula_label.text = atom_group_formula
formula_label.visible = atom_group_formula != ""
if has_node("EffectLabel") and card_type == GameLoopManager.CardType.CONDITION:
var effect_label: Label = get_node("EffectLabel")
var effects: Array = []
if condition_effect_primary != -1:
effects.append(GameLoopManager.ConditionEffect.keys()[condition_effect_primary])
if condition_effect_secondary != -1:
effects.append(GameLoopManager.ConditionEffect.keys()[condition_effect_secondary])
effect_label.text = "·".join(effects)
effect_label.visible = effects.size() > 0
func _update_selection_display() -> void:
if is_selected:
scale = Vector2(card_scale_selected, card_scale_selected)
if has_node("SelectionHighlight"):
get_node("SelectionHighlight").visible = true
elif is_dragging:
scale = Vector2(card_scale_dragging, card_scale_dragging)
if has_node("SelectionHighlight"):
get_node("SelectionHighlight").visible = false
elif is_highlighted:
scale = Vector2(card_scale_hover, card_scale_hover)
if has_node("HighlightOverlay"):
get_node("HighlightOverlay").visible = true
else:
scale = Vector2(card_scale_normal, card_scale_normal)
if has_node("SelectionHighlight"):
get_node("SelectionHighlight").visible = false
if has_node("HighlightOverlay"):
get_node("HighlightOverlay").visible = false
func set_texture(pic: String) -> void:
if pic == "" or pic == null: return
var image: Image = Image.new()
if image.load(pic) == OK:
if has_node("Sprite"):
$Sprite.texture = ImageTexture.create_from_image(image)
$Sprite.position = Vector2(card_width / 2.0, card_height / 2.0)
else:
if has_node("NameLabel"):
get_node("NameLabel").text = card_name
func set_pos(x: float, y: float) -> void:
position = Vector2(x, y)
func get_pos() -> Vector2:
return $Sprite.position
return position
func set_center_pos(x: float, y: float) -> void:
position = Vector2(x - card_width / 2.0, y - card_height / 2.0)
func get_center_pos() -> Vector2:
return position + Vector2(card_width / 2.0, card_height / 2.0)
func set_face_up(face_up: bool) -> void:
is_face_up = face_up
update_display()
func set_selected(selected: bool) -> void:
is_selected = selected
_update_selection_display()
if selected:
card_clicked.emit(self)
func set_highlighted(highlighted: bool) -> void:
is_highlighted = highlighted
_update_selection_display()
func _on_clickable_area_input_event(_viewport: Node, event: InputEvent, _shape_idx: int) -> void:
if not visible or not is_face_up: return
if event is InputEventMouseButton:
if event.button_index == MOUSE_BUTTON_LEFT:
if event.pressed:
if event.double_click:
card_double_clicked.emit(self)
else:
_start_drag(event)
set_selected(not is_selected)
else:
_end_drag(event)
elif event is InputEventMouseMotion:
if is_dragging:
_update_drag_position(event)
func _on_mouse_entered() -> void:
if not visible: return
card_hovered.emit(self)
if not is_selected and not is_dragging:
scale = Vector2(card_scale_hover, card_scale_hover)
if is_in_hand:
position.y -= 20.0
func _on_mouse_exited() -> void:
if not visible: return
card_unhovered.emit(self)
if not is_selected and not is_dragging:
scale = Vector2(card_scale_normal, card_scale_normal)
if is_in_hand and not is_dragging:
position.y += 20.0
func _start_drag(event: InputEvent) -> void:
if not is_in_hand: return
is_dragging = true
original_position = position
card_drag_started.emit(self)
z_index = 100
_update_selection_display()
func _update_drag_position(event: InputEvent) -> void:
if not is_dragging: return
var global_mouse: Vector2 = event.global_position
position = get_parent().get_global_transform().affine_inverse() * global_mouse - Vector2(card_width / 2.0, card_height / 2.0)
func _end_drag(event: InputEvent) -> void:
if not is_dragging: return
is_dragging = false
z_index = 0
_update_selection_display()
card_drag_ended.emit(self, position)
func return_to_original_position() -> void:
position = original_position
scale = Vector2(card_scale_normal, card_scale_normal)
func is_metal_atom() -> bool:
return card_type == GameLoopManager.CardType.ATOM and card_kind == "metal"
func is_nonmetal_atom() -> bool:
return card_type == GameLoopManager.CardType.ATOM and card_kind == "nonmetal"
func is_atom_group() -> bool:
return card_type == GameLoopManager.CardType.ATOM_GROUP
func is_condition() -> bool:
return card_type == GameLoopManager.CardType.CONDITION
func is_sequence() -> bool:
return card_type == GameLoopManager.CardType.SEQUENCE
func is_count() -> bool:
return card_type == GameLoopManager.CardType.COUNT
func is_illegal_attack_substance() -> bool:
var no_defend_metals: Array = ["Li", "Na", "K", "Ca", "Ba"]
if card_type == GameLoopManager.CardType.ATOM and element_symbol in no_defend_metals:
return true
return false
func get_card_kind() -> String:
return card_kind
func get_card_info() -> Dictionary:
return {
"card_id": card_id,
"card_name": card_name,
"description": description,
"card_type": card_type,
"element_symbol": element_symbol,
"atom_group_formula": atom_group_formula,
"condition_effect_primary": condition_effect_primary,
"condition_effect_secondary": condition_effect_secondary,
"card_kind": card_kind,
"is_face_up": is_face_up,
"is_selected": is_selected,
"card_owner_id": card_owner_id,
}
func get_display_name() -> String:
if not is_face_up:
return "???"
return card_name
func flip_card(to_face_up: bool, duration: float = 0.3) -> void:
var tween: Tween = create_tween()
tween.tween_property(self, "scale:x", 0.0, duration / 2.0)
tween.tween_callback(func(): set_face_up(to_face_up))
tween.tween_property(self, "scale:x", card_scale_normal, duration / 2.0)
func animate_to_position(target_pos: Vector2, duration: float = 0.3) -> void:
var tween: Tween = create_tween()
tween.tween_property(self, "position", target_pos, duration).set_trans(Tween.TRANS_QUAD).set_ease(Tween.EASE_OUT)
func fade_in(duration: float = 0.3) -> void:
modulate.a = 0.0
visible = true
var tween: Tween = create_tween()
tween.tween_property(self, "modulate:a", 1.0, duration)
func fade_out(duration: float = 0.3) -> void:
var tween: Tween = create_tween()
tween.tween_property(self, "modulate:a", 0.0, duration)
tween.tween_callback(func(): visible = false)
func bounce_effect() -> void:
var tween: Tween = create_tween()
tween.tween_property(self, "scale", Vector2(card_scale_hover, card_scale_hover), 0.1)
tween.tween_property(self, "scale", Vector2(card_scale_normal, card_scale_normal), 0.15)
func shake_effect() -> void:
var original_pos: Vector2 = position
var tween: Tween = create_tween()
for i in range(3):
tween.tween_property(self, "position", original_pos + Vector2(5.0, 0.0), 0.05)
tween.tween_property(self, "position", original_pos + Vector2(-5.0, 0.0), 0.05)
tween.tween_property(self, "position", original_pos, 0.05)
+309 -9
View File
@@ -1,18 +1,34 @@
extends Node2D
var card_list: Array
## ============================================================
## 纸片化学 - 游戏场景脚本
## game.gd - 管理游戏UI、卡牌显示、玩家交互
## ============================================================
var card_list: Array = []
var hand_card_nodes: Array = []
var reaction_card_nodes: Dictionary = {}
var element_card_nodes: Dictionary = {}
var hand_card_spacing: float = 130.0
var hand_card_y: float = 1250.0
var hand_card_start_x: float = 530.0
var reaction_card_spacing: float = 130.0
var element_card_spacing: float = 130.0
var selected_cards: Array = []
var is_waiting_for_target: bool = false
var current_operation: int = -1
func _ready() -> void:
init()
GameLoopManager.start_game()
var card = create_card("Oxygen")
card.show()
card.set_pos(300, 300)
print(card.get_pos())
_connect_signals()
if GameLoopManager.game_started:
_refresh_all_ui()
func init() -> void:
# 设置 UI 展示文本
if multiplayer.is_server():
$IsServerLabel.text = "GAMEUI_URHOST"
else:
@@ -25,11 +41,295 @@ func init() -> void:
break
$IPLabel.text = ipaddress
$Player1/Username.text = GameManager.username
$EndPhaseButton.visible = false
$PhaseLabel.text = ""
$RoundLabel.text = ""
func create_card(card_name: String):
var card = SceneManager.Card.instantiate()
func _connect_signals() -> void:
GameLoopManager.game_phase_changed.connect(_on_game_phase_changed)
GameLoopManager.player_data_updated.connect(_on_player_data_updated)
GameLoopManager.player_eliminated.connect(_on_player_eliminated)
GameLoopManager.player_dying_entered.connect(_on_player_dying_entered)
GameLoopManager.player_dying_resolved.connect(_on_player_dying_resolved)
GameLoopManager.hand_updated.connect(_on_hand_updated)
GameLoopManager.reaction_area_updated.connect(_on_reaction_area_updated)
GameLoopManager.element_area_updated.connect(_on_element_area_updated)
GameLoopManager.game_ended.connect(_on_game_ended)
GameLoopManager.turn_order_determined.connect(_on_turn_order_determined)
GameLoopManager.settlement_damage_applied.connect(_on_settlement_damage_applied)
$EndPhaseButton.pressed.connect(_on_end_phase_button_pressed)
func create_card(card_name: String) -> Node2D:
var card: Node2D = SceneManager.Card.instantiate()
add_child(card)
card.set_card(card_name)
card_list.append(card)
return card
func create_card_at(card_name: String, x: float, y: float) -> Node2D:
var card: Node2D = create_card(card_name)
card.set_pos(x, y)
return card
func _refresh_all_ui() -> void:
_refresh_phase_display()
_refresh_round_display()
_refresh_all_player_data()
_refresh_hand_cards()
_refresh_all_reaction_areas()
_refresh_all_element_areas()
func _refresh_phase_display() -> void:
var phase: int = GameLoopManager.get_current_phase()
var phase_names: Dictionary = {
GameLoopManager.GamePhase.PREPARATION: "准备阶段",
GameLoopManager.GamePhase.ACTION1: "行动阶段一",
GameLoopManager.GamePhase.SETTLEMENT1: "结算阶段一",
GameLoopManager.GamePhase.DRAW: "摸牌阶段",
GameLoopManager.GamePhase.ACTION2: "行动阶段二",
GameLoopManager.GamePhase.SETTLEMENT2: "结算阶段二",
GameLoopManager.GamePhase.DYING_ENTER: "进入濒死",
GameLoopManager.GamePhase.DYING_REPLY: "濒死回复",
GameLoopManager.GamePhase.DYING_SETTLE: "濒死结算",
GameLoopManager.GamePhase.ELIMINATION: "出局流程",
GameLoopManager.GamePhase.GAME_END: "游戏结束",
}
$PhaseLabel.text = phase_names.get(phase, "未知阶段")
var show_end: bool = phase in [GameLoopManager.GamePhase.ACTION1, GameLoopManager.GamePhase.ACTION2, GameLoopManager.GamePhase.DYING_REPLY]
$EndPhaseButton.visible = show_end
if phase == GameLoopManager.GamePhase.ACTION1:
$EndPhaseButton.text = "结束行动一 → 结算"
elif phase == GameLoopManager.GamePhase.ACTION2:
$EndPhaseButton.text = "结束行动二 → 结算"
elif phase == GameLoopManager.GamePhase.DYING_REPLY:
$EndPhaseButton.text = "宣布不再出牌"
func _refresh_round_display() -> void:
$RoundLabel.text = "回合: %d" % GameLoopManager.get_game_round()
func _refresh_all_player_data() -> void:
var my_id: int = multiplayer.get_unique_id()
var turn_order: Array = GameLoopManager.get_turn_order()
var my_data: Dictionary = GameLoopManager.get_player_data(my_id)
if not my_data.is_empty():
$Player1/Username.text = my_data.get("nickname", "Player1")
var el: int = my_data.get("electron_layers", 0)
var max_el: int = my_data.get("max_electron_layers", 0)
$Player1/ElectronLabel.text = "电子层: %d/%d" % [el, max_el]
if my_id == GameLoopManager.get_current_player():
$Player1/Username.add_theme_color_override("font_color", Color.YELLOW)
else:
$Player1/Username.add_theme_color_override("font_color", Color.WHITE)
if el <= 1:
$Player1/ElectronLabel.add_theme_color_override("font_color", Color.RED)
else:
$Player1/ElectronLabel.add_theme_color_override("font_color", Color.WHITE)
var other_players: Array = []
for pid in turn_order:
if pid != my_id:
other_players.append(pid)
if other_players.size() >= 1 and has_node("Player2"):
var p2d: Dictionary = GameLoopManager.get_player_data(other_players[0])
if not p2d.is_empty():
$Player2/Username.text = p2d.get("nickname", "Player2")
$Player2/ElectronLabel.text = "电子层: %d/%d" % [p2d.get("electron_layers", 0), p2d.get("max_electron_layers", 0)]
if other_players.size() >= 2 and has_node("Player3"):
var p3d: Dictionary = GameLoopManager.get_player_data(other_players[1])
if not p3d.is_empty():
$Player3/Username.text = p3d.get("nickname", "Player3")
$Player3/ElectronLabel.text = "电子层: %d" % p3d.get("electron_layers", 0)
if other_players.size() >= 3 and has_node("Player4"):
var p4d: Dictionary = GameLoopManager.get_player_data(other_players[2])
if not p4d.is_empty():
$Player4/Username.text = p4d.get("nickname", "Player4")
$Player4/ElectronLabel.text = "电子层: %d" % p4d.get("electron_layers", 0)
func _refresh_hand_cards() -> void:
var my_id: int = multiplayer.get_unique_id()
var data: Dictionary = GameLoopManager.get_player_data(my_id)
if data.is_empty(): return
var hand: Array = data.get("hand", [])
for cn in hand_card_nodes:
if is_instance_valid(cn): cn.queue_free()
hand_card_nodes.clear()
for i in range(hand.size()):
var card_node: Node2D = create_card(hand[i])
card_node.set_pos(hand_card_start_x + i * hand_card_spacing, hand_card_y)
card_node.is_in_hand = true
card_node.card_owner_id = my_id
card_node.is_face_up = true
card_node.show()
hand_card_nodes.append(card_node)
card_node.card_clicked.connect(_on_hand_card_clicked)
card_node.card_double_clicked.connect(_on_hand_card_double_clicked)
card_node.card_drag_ended.connect(_on_hand_card_drag_ended)
func _refresh_reaction_area(player_id: int) -> void:
var data: Dictionary = GameLoopManager.get_player_data(player_id)
if data.is_empty(): return
var area: Array = data.get("reaction_area", [])
if reaction_card_nodes.has(player_id):
for cn in reaction_card_nodes[player_id]:
if is_instance_valid(cn): cn.queue_free()
reaction_card_nodes[player_id].clear()
else:
reaction_card_nodes[player_id] = []
var panel: PanelContainer = _get_reaction_panel(player_id)
if panel == null: return
var bx: float = panel.position.x + 10.0
var by: float = panel.position.y + 10.0
for i in range(area.size()):
var sub: Dictionary = area[i]
var cn: Node2D = create_card(sub.get("formula", "???"))
cn.set_pos(bx + i * reaction_card_spacing, by)
cn.is_in_reaction_area = true
cn.is_face_up = true
cn.show()
reaction_card_nodes[player_id].append(cn)
func _refresh_all_reaction_areas() -> void:
for pid in GameLoopManager.get_turn_order():
_refresh_reaction_area(pid)
func _refresh_element_area(player_id: int) -> void:
var data: Dictionary = GameLoopManager.get_player_data(player_id)
if data.is_empty(): return
var area: Array = data.get("element_area", [])
if element_card_nodes.has(player_id):
for cn in element_card_nodes[player_id]:
if is_instance_valid(cn): cn.queue_free()
element_card_nodes[player_id].clear()
else:
element_card_nodes[player_id] = []
var panel: PanelContainer = _get_element_panel(player_id)
if panel == null: return
var bx: float = panel.position.x + 10.0
var by: float = panel.position.y + 10.0
for i in range(area.size()):
var cn: Node2D = create_card(area[i])
cn.set_pos(bx + i * element_card_spacing, by)
cn.is_in_element_area = true
cn.is_face_up = true
cn.show()
element_card_nodes[player_id].append(cn)
func _refresh_all_element_areas() -> void:
for pid in GameLoopManager.get_turn_order():
_refresh_element_area(pid)
func _get_reaction_panel(player_id: int) -> PanelContainer:
var my_id: int = multiplayer.get_unique_id()
if player_id == my_id: return $Player1/ReactionAreaPanel
var turn_order: Array = GameLoopManager.get_turn_order()
var idx: int = 0
for pid in turn_order:
if pid != my_id:
idx += 1
if pid == player_id:
if idx == 1 and has_node("Player2/ReactionAreaPanel"): return $Player2/ReactionAreaPanel
if idx == 2 and has_node("Player3/ReactionAreaPanel"): return $Player3/ReactionAreaPanel
if idx == 3 and has_node("Player4/ReactionAreaPanel"): return $Player4/ReactionAreaPanel
return null
func _get_element_panel(player_id: int) -> PanelContainer:
var my_id: int = multiplayer.get_unique_id()
if player_id == my_id:
if has_node("Player1/ElementAreaPanel"): return $Player1/ElementAreaPanel
return null
var turn_order: Array = GameLoopManager.get_turn_order()
var idx: int = 0
for pid in turn_order:
if pid != my_id:
idx += 1
if pid == player_id:
if idx == 1 and has_node("Player2/ElementAreaPanel"): return $Player2/ElementAreaPanel
if idx == 2 and has_node("Player3/ElementAreaPanel"): return $Player3/ElementAreaPanel
if idx == 3 and has_node("Player4/ElementAreaPanel"): return $Player4/ElementAreaPanel
return null
func _on_game_phase_changed(phase: int, player_id: int) -> void:
_refresh_phase_display()
_refresh_round_display()
_refresh_all_player_data()
if phase == GameLoopManager.GamePhase.DRAW: _refresh_hand_cards()
if phase in [GameLoopManager.GamePhase.SETTLEMENT1, GameLoopManager.GamePhase.SETTLEMENT2]:
_refresh_all_reaction_areas()
_refresh_all_player_data()
func _on_player_data_updated(player_id: int) -> void: _refresh_all_player_data()
func _on_player_eliminated(player_id: int, _attacker_id: int) -> void:
_refresh_all_player_data()
_refresh_all_reaction_areas()
_refresh_all_element_areas()
_refresh_hand_cards()
var d: Dictionary = GameLoopManager.get_player_data(player_id)
_show_notification("%s 已出局!" % d.get("nickname", "Player"))
func _on_player_dying_entered(player_id: int) -> void:
var d: Dictionary = GameLoopManager.get_player_data(player_id)
_show_notification("%s 进入濒死!" % d.get("nickname", "Player"))
_refresh_all_player_data()
func _on_player_dying_resolved(player_id: int, survived: bool) -> void:
var d: Dictionary = GameLoopManager.get_player_data(player_id)
_show_notification("%s %s" % [d.get("nickname", "Player"), "回复成功" if survived else "回复失败"])
_refresh_all_player_data()
func _on_hand_updated(player_id: int, _cards: Array) -> void:
if player_id == multiplayer.get_unique_id(): _refresh_hand_cards()
func _on_reaction_area_updated(player_id: int, _substances: Array) -> void: _refresh_reaction_area(player_id)
func _on_element_area_updated(player_id: int, _elements: Array) -> void: _refresh_element_area(player_id)
func _on_game_ended(winner_ids: Array) -> void:
$EndPhaseButton.visible = false
if winner_ids.size() == 1:
var d: Dictionary = GameLoopManager.get_player_data(winner_ids[0])
_show_notification("游戏结束! %s 获胜!" % d.get("nickname", "Player"))
else:
_show_notification("游戏结束! 平局!")
func _on_turn_order_determined(_order: Array) -> void:
_refresh_all_player_data()
_show_notification("出牌顺序已确定!")
func _on_settlement_damage_applied(player_id: int, damage_type: int, amount: int) -> void:
var d: Dictionary = GameLoopManager.get_player_data(player_id)
var tn: Dictionary = {GameLoopManager.DamageType.CORROSION: "腐蚀", GameLoopManager.DamageType.POISONING: "中毒", GameLoopManager.DamageType.GENERAL: "一般"}
_show_notification("%s 受到%d%s伤害!" % [d.get("nickname", "Player"), amount, tn.get(damage_type, "未知")])
func _on_hand_card_clicked(card: Node2D) -> void:
if card.is_selected: selected_cards.append(card)
else: selected_cards.erase(card)
func _on_hand_card_double_clicked(card: Node2D) -> void:
print("Double clicked: ", card.card_name)
func _on_hand_card_drag_ended(card: Node2D, _position: Vector2) -> void:
card.return_to_original_position()
func _on_end_phase_button_pressed() -> void:
GameLoopManager.end_current_phase.rpc()
func _show_notification(text: String) -> void:
$NotificationLabel.text = text
$NotificationLabel.visible = true
var tween: Tween = create_tween()
tween.tween_interval(3.0)
tween.tween_callback(func(): $NotificationLabel.visible = false)