# mall_affect_system.gd —— Metin2 40250 商城常驻 Affect 增益与双倍特权系统 1:1 # 对照 40250 服务端 affect.h, char_affect.cpp 及客户端 uiaffectshower.py:647-670 class_name MallAffectSystem extends RefCounted signal affect_added(affect_type: int, data: Dictionary) signal affect_removed(affect_type: int) # 40250 官方常驻增益 Affect 常量 (uiaffectshower.py) const AFFECT_EXP_BONUS := 500 const AFFECT_ITEM_BONUS := 501 const AFFECT_SAFEBOX := 502 const AFFECT_AUTOLOOT := 503 const AFFECT_FISH_MIND := 504 const AFFECT_MARRIAGE_FAST := 505 const AFFECT_GOLD_BONUS := 506 const AFFECT_NO_DEATH_PENALTY := 507 const AFFECT_AUTO_HP_RECOVERY := 508 const AFFECT_AUTO_SP_RECOVERY := 509 # 官方图标资源映射 (uiaffectshower.py:647-670) const AFFECT_INFO: Dictionary = { AFFECT_EXP_BONUS: { "name": "经验值获取提升", "icon_sub": "d:/ymir work/ui/skill/common/affect/exp_bonus.sub", "desc": "打怪获得的经验值提升!" }, AFFECT_ITEM_BONUS: { "name": "盗贼手套掉宝增益", "icon_sub": "d:/ymir work/ui/skill/common/affect/item_bonus.sub", "desc": "击杀怪物掉落物品的概率翻倍!" }, AFFECT_SAFEBOX: { "name": "仓库空间扩展", "icon_sub": "d:/ymir work/ui/skill/common/affect/safebox.sub", "desc": "享有二号与三号高级扩展储物箱!" }, AFFECT_AUTOLOOT: { "name": "自动拾取金币", "icon_sub": "d:/ymir work/ui/skill/common/affect/autoloot.sub", "desc": "击杀怪物掉落的金币自动拾取至钱包。" }, AFFECT_FISH_MIND: { "name": "渔神专注", "icon_sub": "d:/ymir work/ui/skill/common/affect/fishmind.sub", "desc": "钓鱼成功率获得大幅提升。" }, AFFECT_MARRIAGE_FAST: { "name": "爱神羽毛", "icon_sub": "d:/ymir work/ui/skill/common/affect/marriage_fast.sub", "desc": "同伴好感度积累速度倍增。" }, AFFECT_GOLD_BONUS: { "name": "幸运金币", "icon_sub": "d:/ymir work/ui/skill/common/affect/gold_bonus.sub", "desc": "怪物掉落的金币数量翻倍!" }, AFFECT_AUTO_HP_RECOVERY: { "name": "太阳仙丹", "icon_sub": "d:/ymir work/ui/pattern/auto_hpgauge/05.dds", "desc": "生命值低于阈值时自动回复。" }, AFFECT_AUTO_SP_RECOVERY: { "name": "月亮仙丹", "icon_sub": "d:/ymir work/ui/pattern/auto_spgauge/05.dds", "desc": "法力值低于阈值时自动回复。" } } # 经典商城道具 Vnum 映射 const MALL_ITEM_TABLE: Dictionary = { 70005: {"affect": AFFECT_EXP_BONUS, "duration": 3600.0, "value": 50}, # 经验戒指 1小时 (+50%) 72001: {"affect": AFFECT_EXP_BONUS, "duration": 604800.0, "value": 100}, # 经验戒指 7天 (+100%) 70043: {"affect": AFFECT_ITEM_BONUS, "duration": 7200.0, "value": 100}, # 盗贼手套 2小时 (2x) 72004: {"affect": AFFECT_ITEM_BONUS, "duration": 604800.0, "value": 100}, # 盗贼手套 7天 (2x) 70044: {"affect": AFFECT_GOLD_BONUS, "duration": 10800.0, "value": 100}, # 幸运金币 3小时 (2x) 72007: {"affect": AFFECT_GOLD_BONUS, "duration": 604800.0, "value": 100}, # 幸运金币 7天 (2x) 72006: {"affect": AFFECT_SAFEBOX, "duration": 604800.0, "value": 1}, # 仓库扩展卷 7天 71069: {"affect": AFFECT_MARRIAGE_FAST, "duration": 604800.0, "value": 1} # 爱神羽毛 7天 } # 当前生效的增益字典: affect_type -> {name, icon_sub, value, duration, total_duration, desc} var active_affects: Dictionary = {} func use_mall_item(item: Dictionary) -> Dictionary: var vnum: int = int(item.get("vnum", 0)) if not MALL_ITEM_TABLE.has(vnum): return {"ok": false, "reason": "NOT_MALL_ITEM", "msg": "这不是商城特权道具!"} var cfg: Dictionary = MALL_ITEM_TABLE[vnum] var atype: int = int(cfg["affect"]) var dur: float = float(cfg["duration"]) var val: int = int(cfg["value"]) add_affect(atype, dur, val) var info: Dictionary = AFFECT_INFO.get(atype, {}) return { "ok": true, "affect_type": atype, "name": info.get("name", "特权增益"), "duration": dur, "value": val, "msg": "已成功激活【%s】特权!" % info.get("name", "") } func add_affect(atype: int, duration: float, value: int = 0) -> void: var info: Dictionary = AFFECT_INFO.get(atype, { "name": "未知特权", "icon_sub": "", "desc": "" }) var data: Dictionary = { "name": info["name"], "icon_sub": info["icon_sub"], "value": value, "duration": duration, "total_duration": duration, "desc": info["desc"] } active_affects[atype] = data affect_added.emit(atype, data) func remove_affect(atype: int) -> void: if active_affects.has(atype): active_affects.erase(atype) affect_removed.emit(atype) func has_affect(atype: int) -> bool: return active_affects.has(atype) func get_affect(atype: int) -> Dictionary: return active_affects.get(atype, {}) # 经验倍率加成 (char.cpp:PointChange) func get_exp_multiplier() -> float: var mult: float = 1.0 if has_affect(AFFECT_EXP_BONUS): var bonus_pct: float = float(active_affects[AFFECT_EXP_BONUS].get("value", 50)) mult += bonus_pct / 100.0 return mult # 物品掉率倍率加成 (item.cpp:Drop) func get_drop_multiplier() -> float: if has_affect(AFFECT_ITEM_BONUS): return 2.0 return 1.0 # 金币掉落倍率加成 (char_battle.cpp:GiveGold) func get_gold_multiplier() -> float: if has_affect(AFFECT_GOLD_BONUS): return 2.0 return 1.0 # 仓库扩充权限 (safebox.cpp) func has_safebox_expansion() -> bool: return has_affect(AFFECT_SAFEBOX) # 逐帧衰减更新 func update(dt: float) -> Array[int]: var expired: Array[int] = [] for atype in active_affects.keys(): var data: Dictionary = active_affects[atype] data["duration"] = maxf(0.0, float(data["duration"]) - dt) if float(data["duration"]) <= 0.0: expired.append(atype) for atype in expired: remove_affect(atype) return expired # 获取供 HUD 渲染的图标列表 func get_hud_icons() -> Array[Dictionary]: var icons: Array[Dictionary] = [] for atype in active_affects: var data: Dictionary = active_affects[atype] var total_sec := int(ceil(float(data["duration"]))) var hours := total_sec / 3600 var mins := (total_sec % 3600) / 60 var secs := total_sec % 60 var time_str := "%02d:%02d:%02d" % [hours, mins, secs] if hours > 0 else "%02d:%02d" % [mins, secs] icons.append({ "affect_type": atype, "name": data["name"], "icon_sub": data["icon_sub"], "time_remaining_str": time_str, "remaining_seconds": float(data["duration"]), "desc": data["desc"] }) return icons