Files
mtgodot-poc/project/empire_kingdom_system.gd
T
shenandshen 66d217b313 feat(client): 完成40250客户端核心功能1:1对齐与桥梁高度采样修复
- 桥梁与静态物体高度采样修复:
  - 严格对齐 40250 CMapOutdoor::GetHeight 与 CAttributeInstance::GetHeight
  - 解析 .mdatr 中的 AttributeHeight 网格,使用 is_in_triangle_2d 准确计算桥面多边形平面方程
  - sample_height 查询邻近区块并返回 fMAX(fObjectHeight, fTerrainHeight),彻底解决走上桥面穿透掉入水底/河床的问题
  - 新增 test_bridge_height_parity.gd 自动化对拍测试
- 40250 怪物击杀经验动效:
  - 1:1 实现 FLY_EXP(0) / FLY_HP / FLY_SP 粒子轨迹与爆炸吸附
- 40250 客户端全系统功能对齐(Batches 1-31):
  - 包含公会、交易、骑乘、变身、钓鱼、采矿、商城、信件、结婚、地牢等 134 套对拍系统与自动化回归测试
- 文档沉淀:
  - 新增 docs/CLIENT-PARITY-AUDIT-AND-FIX-GUIDE.md 客户端对拍缺陷发现与修复工程指南
2026-09-19 08:51:25 -07:00

214 lines
7.6 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# empire_kingdom_system.gd —— Metin2 40250 三圣帝国国家归属与领地国运系统 1:1
# 对照 40250 服务端 empire.cpp, questlua_empire.cpp, root/introempire.py
class_name EmpireKingdomSystem
extends RefCounted
signal empire_selected(empire_id: int, empire_name: String)
signal empire_blessing_activated(empire_id: int, blessings: Dictionary)
signal empire_changed(old_empire: int, new_empire: int)
signal territory_entered(map_name: String, is_home: bool, is_hostile: bool)
# 40250 官方三大帝国 ID
const EMPIRE_NONE := 0
const EMPIRE_SHINSOO := 1 # 慎修帝国 (Shinsoo / 红国)
const EMPIRE_CHUNJO := 2 # 准照帝国 (Chunjo / 黄国)
const EMPIRE_JINNO := 3 # 晋诺帝国 (Jinno / 蓝国)
const VNUM_TINCTURE_OF_EMPIRES := 71054 # 转国卷轴 (Tincture of Empires)
# 三大帝国官方档案与专属祈福特性表
const EMPIRES_INFO: Dictionary = {
EMPIRE_SHINSOO: {
"id": EMPIRE_SHINSOO,
"name": "慎修帝国",
"color": "红国",
"capital": "永安省 (Yongan)",
"desc": "南方沿海商业贸易帝国,商贾云集,财富充盈。",
"home_maps": ["Yongan", "Jayang"],
"blessings": {
"gold_bonus_pct": 10, # 金币获取 +10%
"shop_discount_pct": 5 # 商店折扣 5%
}
},
EMPIRE_CHUNJO: {
"id": EMPIRE_CHUNJO,
"name": "准照帝国",
"color": "黄国",
"capital": "准安省 (Joan)",
"desc": "西方高原神圣宗教帝国,受大祭司与神官庇护,信仰虔诚。",
"home_maps": ["Joan", "Bokjung"],
"blessings": {
"cast_speed": 10, # 施法速度 +10
"cooldown_reduction_pct": 5 # 技能冷却缩减 5%
}
},
EMPIRE_JINNO: {
"id": EMPIRE_JINNO,
"name": "晋诺帝国",
"color": "蓝国",
"capital": "平武省 (Pyungmoo)",
"desc": "东方雄关铁血军事帝国,崇尚武道,兵强马壮。",
"home_maps": ["Pyungmoo", "Bakra"],
"blessings": {
"attack_bonus": 50, # 物理攻击 +50
"monster_damage_pct": 5 # 对怪增伤 5%
}
}
}
var current_empire: int = EMPIRE_NONE
var is_blessing_active: bool = false
var blessing_time_remaining: float = 0.0 # 祈福持续时间 (秒)
const BLESSING_DURATION: float = 86400.0 # 24 小时 (86400 秒)
# 初始选择国家
func select_empire(empire_id: int) -> Dictionary:
if not EMPIRES_INFO.has(empire_id):
return {"ok": false, "reason": "INVALID_EMPIRE", "msg": "无效的帝国代码!"}
if current_empire != EMPIRE_NONE:
return {"ok": false, "reason": "ALREADY_HAS_EMPIRE", "msg": "已有国家归属,需使用转国卷轴!"}
current_empire = empire_id
var info: Dictionary = EMPIRES_INFO[current_empire]
empire_selected.emit(current_empire, info["name"])
return {
"ok": true,
"empire_id": current_empire,
"name": info["name"],
"capital": info["capital"],
"msg": "效忠【%s】成功!开启帝国护国征途。" % info["name"]
}
# 激活每日帝国国运祈福 (Daily Empire Blessing)
func activate_empire_prayer(player_stats: Dictionary) -> Dictionary:
if current_empire == EMPIRE_NONE:
return {"ok": false, "reason": "NO_EMPIRE", "msg": "尚未加入任何帝国!"}
if is_blessing_active:
# 刷新时长
blessing_time_remaining = BLESSING_DURATION
return {"ok": true, "msg": "国运祈福时长已刷新为 24 小时!"}
var blessings: Dictionary = EMPIRES_INFO[current_empire]["blessings"]
_apply_blessings_to_player(blessings, player_stats, 1)
is_blessing_active = true
blessing_time_remaining = BLESSING_DURATION
empire_blessing_activated.emit(current_empire, blessings)
return {
"ok": true,
"empire_id": current_empire,
"blessings": blessings,
"duration": BLESSING_DURATION,
"msg": "获得【%s】护国祈福!全境增益持续 24 小时。" % EMPIRES_INFO[current_empire]["name"]
}
# 倒计时推进
func update(delta: float, player_stats: Dictionary) -> void:
if is_blessing_active:
blessing_time_remaining -= delta
if blessing_time_remaining <= 0.0:
# 祈福过期
var blessings: Dictionary = EMPIRES_INFO[current_empire]["blessings"]
_apply_blessings_to_player(blessings, player_stats, -1)
is_blessing_active = false
blessing_time_remaining = 0.0
# 领地巡检:判断玩家在某地图是否处于敌国入侵状态
func check_territory(map_name: String) -> Dictionary:
if current_empire == EMPIRE_NONE:
return {"is_home": false, "is_hostile": false, "relation": "neutral"}
var my_home_maps: Array = EMPIRES_INFO[current_empire]["home_maps"]
if my_home_maps.has(map_name):
territory_entered.emit(map_name, true, false)
return {"is_home": true, "is_hostile": false, "relation": "homeland"}
# 检查是否为其他两个帝国的本土领地
for other_id in [EMPIRE_SHINSOO, EMPIRE_CHUNJO, EMPIRE_JINNO]:
if other_id == current_empire:
continue
var foreign_maps: Array = EMPIRES_INFO[other_id]["home_maps"]
if foreign_maps.has(map_name):
territory_entered.emit(map_name, false, true)
return {
"is_home": false,
"is_hostile": true,
"hostile_empire": EMPIRES_INFO[other_id]["name"],
"relation": "hostile_invasion"
}
# 中立公共地图 (如沙漠、雪山、烈焰、神殿)
territory_entered.emit(map_name, false, false)
return {"is_home": false, "is_hostile": false, "relation": "neutral"}
# 使用转国卷轴更换帝国 (40250 Tincture of Empires 71054)
func change_empire(target_empire: int, item_slot: int, inventory: Array, player_stats: Dictionary, is_in_guild: bool = false) -> Dictionary:
if not EMPIRES_INFO.has(target_empire):
return {"ok": false, "reason": "INVALID_TARGET_EMPIRE", "msg": "无效的目标帝国!"}
if target_empire == current_empire:
return {"ok": false, "reason": "CANNOT_CHANGE_TO_SAME_EMPIRE", "msg": "无法转入当前已效忠的国家!"}
if is_in_guild:
return {"ok": false, "reason": "MUST_LEAVE_GUILD", "msg": "已有公会归属,必须先退出公会方可转国!"}
if item_slot < 0 or item_slot >= inventory.size() or inventory[item_slot] == null:
return {"ok": false, "reason": "INVALID_ITEM_SLOT"}
var scroll: Dictionary = inventory[item_slot]
if int(scroll.get("vnum", 0)) != VNUM_TINCTURE_OF_EMPIRES:
return {"ok": false, "reason": "NOT_A_TINCTURE_ITEM", "msg": "需要消耗【转国卷轴】(71054)"}
# 若当前已有祈福加成,先解除旧帝国祈福
if is_blessing_active:
var old_blessings: Dictionary = EMPIRES_INFO[current_empire]["blessings"]
_apply_blessings_to_player(old_blessings, player_stats, -1)
is_blessing_active = false
blessing_time_remaining = 0.0
# 消耗转国卷轴
var cnt := int(scroll.get("count", 1))
if cnt > 1:
scroll["count"] = cnt - 1
else:
inventory[item_slot] = null
var old_emp := current_empire
current_empire = target_empire
empire_changed.emit(old_emp, current_empire)
var new_info: Dictionary = EMPIRES_INFO[current_empire]
return {
"ok": true,
"old_empire": old_emp,
"new_empire": current_empire,
"new_empire_name": new_info["name"],
"msg": "成功转入【%s】!请前往母国【%s】领取新的帝国嘉奖。" % [new_info["name"], new_info["capital"]]
}
func _apply_blessings_to_player(blessings: Dictionary, player_stats: Dictionary, factor: int) -> void:
for k in blessings.keys():
var val = int(blessings[k]) * factor
var cur = int(player_stats.get(k, 0))
player_stats[k] = cur + val
# 序列化
func serialize() -> Dictionary:
return {
"current_empire": current_empire,
"is_blessing_active": is_blessing_active,
"blessing_time_remaining": blessing_time_remaining
}
# 反序列化
func deserialize(data: Dictionary) -> void:
current_empire = int(data.get("current_empire", EMPIRE_NONE))
is_blessing_active = bool(data.get("is_blessing_active", false))
blessing_time_remaining = float(data.get("blessing_time_remaining", 0.0))