- 桥梁与静态物体高度采样修复: - 严格对齐 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 客户端对拍缺陷发现与修复工程指南
214 lines
7.6 KiB
GDScript
214 lines
7.6 KiB
GDScript
# 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))
|