Files
mtgodot-poc/project/wardrobe_transmog_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

147 lines
5.4 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.
# wardrobe_transmog_system.gd —— Metin2 40250 装备外观幻化重塑与试衣间系统 1:1
# 对照 40250 服务端 item_transmutation.cpp, char_item.cpp
class_name WardrobeTransmogSystem
extends RefCounted
signal item_transmuted(target_slot: int, target_name: String, new_look_vnum: int, new_look_name: String)
signal transmutation_reverted(target_slot: int, item_name: String)
const VNUM_TRANSMOG_SCROLL := 72301 # 幻化秘籍
const VNUM_REVERT_SCROLL := 72302 # 幻化还原秘籍
const TRANSMOG_COST_GOLD := 10000000 # 1000 万金币
# 装备大类
const TYPE_WEAPON := 1
const TYPE_ARMOR := 2
const TYPE_COSTUME := 28
# 试衣间预览外观效果 (不消耗物品)
func preview_transmog(target_item: Dictionary, skin_item: Dictionary) -> Dictionary:
var val = _validate_compatibility(target_item, skin_item)
if not val["ok"]:
return val
return {
"ok": true,
"base_vnum": target_item.get("vnum", 0),
"base_name": target_item.get("name", "神装"),
"preview_vnum": skin_item.get("vnum", 0),
"preview_name": skin_item.get("name", "幻化外观"),
"msg": "试衣间预览生成完毕!"
}
# 执行幻化外观重塑
func apply_transmutation(scroll_slot: int, target_slot: int, skin_slot: int, inventory: Array, player_data: Dictionary) -> Dictionary:
if scroll_slot < 0 or scroll_slot >= inventory.size() or inventory[scroll_slot] == null:
return {"ok": false, "reason": "INVALID_SCROLL_SLOT"}
if target_slot < 0 or target_slot >= inventory.size() or inventory[target_slot] == null:
return {"ok": false, "reason": "INVALID_TARGET_SLOT"}
if skin_slot < 0 or skin_slot >= inventory.size() or inventory[skin_slot] == null:
return {"ok": false, "reason": "INVALID_SKIN_SLOT"}
if target_slot == skin_slot:
return {"ok": false, "reason": "SAME_SLOT", "msg": "目标装备与外观装备不能为同一格子!"}
var scroll = inventory[scroll_slot]
if int(scroll.get("vnum", 0)) != VNUM_TRANSMOG_SCROLL:
return {"ok": false, "reason": "NOT_A_TRANSMOG_SCROLL", "msg": "需要使用【幻化秘籍】(72301)"}
var target = inventory[target_slot]
var skin = inventory[skin_slot]
var comp_check = _validate_compatibility(target, skin)
if not comp_check["ok"]:
return comp_check
var gold = int(player_data.get("gold", 0))
if gold < TRANSMOG_COST_GOLD:
return {"ok": false, "reason": "NOT_ENOUGH_GOLD", "msg": "幻化所需金币不足!需要 10,000,000 金币。"}
# 扣除金币与卷轴
player_data["gold"] = gold - TRANSMOG_COST_GOLD
var sc_cnt = int(scroll.get("count", 1))
if sc_cnt > 1:
scroll["count"] = sc_cnt - 1
else:
inventory[scroll_slot] = null
# 消耗外观材料装备
var skin_vnum = int(skin.get("vnum", 0))
var skin_name = skin.get("name", "外观")
var sk_cnt = int(skin.get("count", 1))
if sk_cnt > 1:
skin["count"] = sk_cnt - 1
else:
inventory[skin_slot] = null
# 赋予目标装备幻化外观 (所有基础属性、强化与灵石 100% 保留)
target["transmog_vnum"] = skin_vnum
target["transmog_name"] = skin_name
var tname: String = target.get("name", "装备")
item_transmuted.emit(target_slot, tname, skin_vnum, skin_name)
return {
"ok": true,
"target_slot": target_slot,
"target_name": tname,
"transmog_vnum": skin_vnum,
"transmog_name": skin_name,
"msg": "幻化成功!【%s】披上了【%s】的华丽外观!" % [tname, skin_name]
}
# 还原装备原生外观
func revert_transmutation(scroll_slot: int, target_slot: int, inventory: Array) -> Dictionary:
if scroll_slot < 0 or scroll_slot >= inventory.size() or inventory[scroll_slot] == null:
return {"ok": false, "reason": "INVALID_SCROLL_SLOT"}
if target_slot < 0 or target_slot >= inventory.size() or inventory[target_slot] == null:
return {"ok": false, "reason": "INVALID_TARGET_SLOT"}
var scroll = inventory[scroll_slot]
if int(scroll.get("vnum", 0)) != VNUM_REVERT_SCROLL:
return {"ok": false, "reason": "NOT_A_REVERT_SCROLL", "msg": "需要使用【幻化还原秘籍】(72302)!"}
var target = inventory[target_slot]
if not target.has("transmog_vnum") or int(target.get("transmog_vnum", 0)) == 0:
return {"ok": false, "reason": "NOT_TRANSMUTED", "msg": "该装备未曾幻化,无需还原!"}
# 消耗还原卷轴
var cnt = int(scroll.get("count", 1))
if cnt > 1:
scroll["count"] = cnt - 1
else:
inventory[scroll_slot] = null
target.erase("transmog_vnum")
target.erase("transmog_name")
var tname: String = target.get("name", "装备")
transmutation_reverted.emit(target_slot, tname)
return {
"ok": true,
"target_slot": target_slot,
"item_name": tname,
"msg": "幻化已抹除!【%s】恢复为原生经典外观。" % tname
}
# 校验外观类型兼容性
func _validate_compatibility(target: Dictionary, skin: Dictionary) -> Dictionary:
if target.is_empty() or skin.is_empty():
return {"ok": false, "reason": "EMPTY_DATA"}
var t_type = int(target.get("type", 1))
var s_type = int(skin.get("type", 1))
# 武器只能幻化武器或时装武器外观;防具只能幻化防具或时装衣服
if t_type == TYPE_WEAPON:
if s_type != TYPE_WEAPON and s_type != TYPE_COSTUME:
return {"ok": false, "reason": "TYPE_MISMATCH", "msg": "武器只能幻化武器或时装外观!"}
elif t_type == TYPE_ARMOR:
if s_type != TYPE_ARMOR and s_type != TYPE_COSTUME:
return {"ok": false, "reason": "TYPE_MISMATCH", "msg": "防具衣服只能幻化衣服防具外观!"}
else:
return {"ok": false, "reason": "UNSUPPORTED_TYPE", "msg": "该装备部位暂不支持幻化外观。"}
return {"ok": true}