feat: 由AI辅助进行游戏内容编写
This commit is contained in:
+1106
-64
File diff suppressed because it is too large
Load Diff
+405
-11
@@ -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
@@ -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)
|
||||
Reference in New Issue
Block a user