- 桥梁与静态物体高度采样修复: - 严格对齐 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 客户端对拍缺陷发现与修复工程指南
112 lines
3.8 KiB
GDScript
112 lines
3.8 KiB
GDScript
# marriage_system.gd —— Metin2 40250 结婚戒指与伴侣瞬移传送系统 1:1
|
||
# 对照 40250 服务端 wedding.cpp, char_item.cpp (Wedding Ring 70301, NPC 20017 Musician)
|
||
class_name MarriageSystem
|
||
extends RefCounted
|
||
|
||
signal couple_warped(target_map: String, target_pos: Vector3)
|
||
|
||
const NPC_MUSICIAN := 20017 # 月下老人 / 乐师
|
||
const ITEM_WEDDING_RING := 70301 # 结婚戒指
|
||
const WARP_SP_COST := 50 # 每次传送消耗 50 SP
|
||
const WARP_COOLDOWN := 180.0 # 3 分钟传送冷却
|
||
|
||
# 禁止传送进入的特殊副本/区域
|
||
const FORBIDDEN_MAPS := ["deviltower_f7", "deviltower_f8", "deviltower_f9", "oxevent"]
|
||
|
||
var is_married: bool = false
|
||
var spouse_name: String = ""
|
||
var love_points: int = 0 # 0 ~ 100%
|
||
var warp_cooldown: float = 0.0
|
||
|
||
# 在月下老人处登记结婚 (wedding.cpp)
|
||
func marry(player_name: String, partner_name: String, ring_item: Dictionary, player_level: int) -> Dictionary:
|
||
if is_married:
|
||
return {"ok": false, "reason": "ALREADY_MARRIED", "msg": "你已经结过婚了!"}
|
||
if player_level < 25:
|
||
return {"ok": false, "reason": "LEVEL_TOO_LOW", "msg": "角色等级未满 25 级,无法缔结婚约!"}
|
||
|
||
var vnum: int = int(ring_item.get("vnum", 0))
|
||
if vnum != ITEM_WEDDING_RING:
|
||
return {"ok": false, "reason": "NO_WEDDING_RING", "msg": "缔结婚约必须携带结婚戒指!"}
|
||
|
||
is_married = true
|
||
spouse_name = partner_name
|
||
love_points = 50 # 初始爱意值 50%
|
||
warp_cooldown = 0.0
|
||
|
||
# 戒指上刻录伴侣名字
|
||
ring_item["inscribed_name"] = partner_name
|
||
ring_item["is_bound"] = true
|
||
|
||
return {
|
||
"ok": true,
|
||
"spouse_name": spouse_name,
|
||
"love_points": love_points,
|
||
"msg": "恭喜!你与【%s】在月下老人的见证下正式结为夫妻!" % spouse_name
|
||
}
|
||
|
||
# 离婚解除婚约
|
||
func divorce() -> Dictionary:
|
||
if not is_married:
|
||
return {"ok": false, "reason": "NOT_MARRIED"}
|
||
|
||
var old_spouse = spouse_name
|
||
is_married = false
|
||
spouse_name = ""
|
||
love_points = 0
|
||
warp_cooldown = 0.0
|
||
|
||
return {"ok": true, "msg": "已与【%s】解除婚姻关系。" % old_spouse}
|
||
|
||
# 增加爱意值
|
||
func add_love_points(amount: int) -> int:
|
||
if is_married:
|
||
love_points = clampi(love_points + amount, 0, 100)
|
||
return love_points
|
||
|
||
# 夫妻瞬移传送 (char_item.cpp:UseItemEx 70301)
|
||
func warp_to_spouse(current_sp: int, spouse_location: Dictionary, is_dead: bool) -> Dictionary:
|
||
if not is_married:
|
||
return {"ok": false, "reason": "NOT_MARRIED", "msg": "你尚未结婚,无法使用夫妻传送!"}
|
||
if is_dead:
|
||
return {"ok": false, "reason": "PLAYER_DEAD", "msg": "死亡状态下无法进行传送!"}
|
||
if warp_cooldown > 0.0:
|
||
return {"ok": false, "reason": "COOLDOWN_ACTIVE", "remaining": warp_cooldown, "msg": "结婚戒指传送冷却中!"}
|
||
if current_sp < WARP_SP_COST:
|
||
return {"ok": false, "reason": "NOT_ENOUGH_SP", "msg": "传送所需内力值不足 (需要 %d SP)!" % WARP_SP_COST}
|
||
|
||
if spouse_location.is_empty() or not bool(spouse_location.get("is_online", false)):
|
||
return {"ok": false, "reason": "SPOUSE_OFFLINE", "msg": "伴侣当前不在线!"}
|
||
|
||
var map_id: String = String(spouse_location.get("map", ""))
|
||
if map_id in FORBIDDEN_MAPS:
|
||
return {"ok": false, "reason": "FORBIDDEN_ZONE", "msg": "伴侣当前处于特殊封闭区域,无法瞬移传送到其身边!"}
|
||
|
||
var pos: Vector3 = spouse_location.get("pos", Vector3.ZERO)
|
||
|
||
# 扣除 SP 并进入冷却
|
||
warp_cooldown = WARP_COOLDOWN
|
||
couple_warped.emit(map_id, pos)
|
||
|
||
return {
|
||
"ok": true,
|
||
"target_map": map_id,
|
||
"target_pos": pos,
|
||
"sp_cost": WARP_SP_COST,
|
||
"cooldown": WARP_COOLDOWN,
|
||
"msg": "心有灵犀!正在瞬间传送到伴侣身边..."
|
||
}
|
||
|
||
# 逐帧更新冷却
|
||
func update(dt: float) -> void:
|
||
if warp_cooldown > 0.0:
|
||
warp_cooldown = maxf(0.0, warp_cooldown - dt)
|
||
|
||
func get_info() -> Dictionary:
|
||
return {
|
||
"is_married": is_married,
|
||
"spouse_name": spouse_name,
|
||
"love_points": love_points,
|
||
"warp_cooldown": warp_cooldown
|
||
}
|