# guild_war_system.gd —— Metin2 40250 官方公会战备宣战与积分决斗裁定系统 1:1 # 对照 40250 服务端 guild_war.cpp, guild_manager.cpp, guild.h class_name GuildWarSystem extends RefCounted signal war_declared(opp_guild_name: String, war_type: int, target_score: int) signal war_started(war_type: int, duration: float) signal score_updated(score_a: int, score_b: int) signal war_ended(winner_side: String, score_a: int, score_b: int, reward: Dictionary) # 40250 官方公会战模式类型 const WAR_TYPE_FIELD := 0 # 野外遭遇战 (Field War) const WAR_TYPE_ARENA := 1 # 竞技场擂台战 (Arena War, Map 110/111) const WAR_TYPE_FLAG := 2 # 夺旗战 (Flag War) # 公会战状态机 const STATE_NONE := 0 const STATE_DECLARED := 1 # 宣战中 const STATE_PREPARING := 2 # 备战中 const STATE_FIGHTING := 3 # 激战中 const STATE_FINISHED := 4 # 战役结束 # 单机竞争公会预设库 const RIVAL_GUILDS: Dictionary = { 101: {"id": 101, "name": "暗影刺客团", "master": "夜刃", "level": 20, "ladder_points": 1200}, 102: {"id": 102, "name": "赤血狂战盟", "master": "狂屠", "level": 20, "ladder_points": 1350}, 103: {"id": 103, "name": "青云修罗殿", "master": "冥火", "level": 20, "ladder_points": 1400} } var war_state: int = STATE_NONE var active_war_type: int = WAR_TYPE_ARENA var active_opp_guild: Dictionary = {} var target_score: int = 50 # 目标获胜积分 (50分/100分) var time_remaining: float = 1800.0 # 30 分钟 (1800 秒) var total_duration: float = 1800.0 var score_a: int = 0 # 玩家公会得分 var score_b: int = 0 # 敌方公会得分 var player_guild_ladder: int = 1000 # 玩家公会天梯积分 var total_wars_won: int = 0 # 发起公会宣战 (40250 CGuild::GuildWarPacket / UnderDeclaration) func declare_war(opp_guild_id: int, war_type: int = WAR_TYPE_ARENA, win_score: int = 50, duration: float = 1800.0) -> Dictionary: if war_state == STATE_FIGHTING or war_state == STATE_PREPARING: return {"ok": false, "reason": "ALREADY_IN_WAR", "msg": "当前公会已处于战役交锋中!"} if not RIVAL_GUILDS.has(opp_guild_id): return {"ok": false, "reason": "INVALID_OPP_GUILD", "msg": "未知的敌对公会!"} active_opp_guild = RIVAL_GUILDS[opp_guild_id].duplicate(true) active_war_type = war_type target_score = win_score time_remaining = duration total_duration = duration score_a = 0 score_b = 0 war_state = STATE_DECLARED war_declared.emit(active_opp_guild["name"], active_war_type, target_score) return { "ok": true, "opp_name": active_opp_guild["name"], "war_type": active_war_type, "target_score": target_score, "msg": "战书已下达!向【%s】发起公会宣战。" % active_opp_guild["name"] } # 响应接受战书开启战场 func start_war() -> Dictionary: if war_state != STATE_DECLARED: return {"ok": false, "reason": "NOT_IN_DECLARED_STATE"} war_state = STATE_FIGHTING war_started.emit(active_war_type, total_duration) return { "ok": true, "war_type": active_war_type, "duration": total_duration, "msg": "战役正式打响!双方公会成员进入战场拼杀。" } # 记录战场击杀或占旗得分 func record_score(side: String, points: int = 1) -> Dictionary: if war_state != STATE_FIGHTING: return {"ok": false, "reason": "WAR_NOT_ACTIVE"} if side == "A": score_a += points elif side == "B": score_b += points score_updated.emit(score_a, score_b) # 检查是否率先达到目标胜分 if score_a >= target_score or score_b >= target_score: var winner := "A" if score_a >= target_score else "B" return end_war(winner) return { "ok": true, "score_a": score_a, "score_b": score_b, "target_score": target_score } # 结束战役与结算奖励 func end_war(winner: String) -> Dictionary: war_state = STATE_FINISHED var reward: Dictionary = {} if winner == "A": total_wars_won += 1 player_guild_ladder += 30 reward = { "guild_exp": 5000, "guild_gold": 1000000, "ladder_change": 30, "new_ladder": player_guild_ladder } elif winner == "B": player_guild_ladder = maxi(0, player_guild_ladder - 20) reward = { "guild_exp": 1000, "guild_gold": 200000, "ladder_change": -20, "new_ladder": player_guild_ladder } else: reward = { "guild_exp": 2000, "guild_gold": 500000, "ladder_change": 0, "new_ladder": player_guild_ladder } war_ended.emit(winner, score_a, score_b, reward) var msg_title := "大获全胜" if winner == "A" else ("虽败犹荣" if winner == "B" else "战局握手言和") return { "ok": true, "winner": winner, "score_a": score_a, "score_b": score_b, "reward": reward, "msg": "公会战结束【%s】!比分:%d - %d。" % [msg_title, score_a, score_b] } # 战役时钟心跳 func update(delta: float) -> void: if war_state != STATE_FIGHTING: return time_remaining -= delta if time_remaining <= 0.0: # 时间耗尽,按现有比分决出 var winner := "A" if score_a > score_b else ("B" if score_b > score_a else "DRAW") end_war(winner) # 序列化 func serialize() -> Dictionary: return { "war_state": war_state, "active_war_type": active_war_type, "active_opp_guild": active_opp_guild.duplicate(true), "target_score": target_score, "time_remaining": time_remaining, "score_a": score_a, "score_b": score_b, "player_guild_ladder": player_guild_ladder, "total_wars_won": total_wars_won } # 反序列化 func deserialize(data: Dictionary) -> void: war_state = int(data.get("war_state", STATE_NONE)) active_war_type = int(data.get("active_war_type", WAR_TYPE_ARENA)) active_opp_guild = data.get("active_opp_guild", {}).duplicate(true) target_score = int(data.get("target_score", 50)) time_remaining = float(data.get("time_remaining", 1800.0)) score_a = int(data.get("score_a", 0)) score_b = int(data.get("score_b", 0)) player_guild_ladder = int(data.get("player_guild_ladder", 1000)) total_wars_won = int(data.get("total_wars_won", 0))