# damage_effect —— §8.8 / §5.4 头顶伤害飘字「是否 / 如何显示」1:1: # CInstanceBase::AddDamageEffect + ProcessDamage 的分类(DODGE|BLOCK -> MISS、 # self -> "damage_"、nontarget -> 不渲染、target -> "target_")+ 数字逐位拆分 + # CPythonSystem::IsShowDamage / SetShowDamageFlag 门。 # (与 name_color.gd / text_tail.gd / chat_tail.gd / name_show.gd 同一套纯静态镜像套路。) # # REF(40250 ClientVS22 source/ 为唯一基线): # UserInterface/InstanceBase.h:300 enum DamageFlag { NORMAL 1<<0, POISON 1<<1, DODGE 1<<2, BLOCK 1<<3, PENETRATE 1<<4, CRITICAL 1<<5 } # UserInterface/Packet.h:1943 TPacketGCDamageInfo { BYTE header; DWORD dwVID; BYTE flag; int damage; } # UserInterface/PythonNetworkStreamPhaseGame.cpp:2401 RecvDamageInfoPacket: # pInstTarget = GetInstancePtr(dwVID);bSelf = (pInstTarget == MainInstance); # bTarget = (pInstTarget == m_pInstTarget);damage >= 0 才 AddDamageEffect(< 0 记 TraceError) # UserInterface/InstanceBaseEffect.cpp:87 AddDamageEffect:仅当 IsShowDamage() 才 push m_DamageQueue({bSelf,bTarget,damage,flag}) # UserInterface/InstanceBaseEffect.cpp:100 ProcessDamage(InstanceBase.cpp:1910 每帧调一次): # 每帧 pop_front 一条; # (flag & DODGE) || (flag & BLOCK) -> bSelf ? EFFECT_DAMAGE_MISS : EFFECT_DAMAGE_TARGETMISS,return # (flag & CRITICAL) -> 该 build CreateEffect 被注释掉,落到普通数字(无独立暴击视觉) # POISON 分支整段注释掉 # bSelf -> strDamageType="damage_",EFFECT_DAMAGE_SELFDAMAGE / SELFDAMAGE2 交替(m_bDamageEffectType 每次取反) # !bTarget -> strDamageType="nontarget_",EFFECT_DAMAGE_NOT_TARGET 后 **return(不渲染)** # else -> strDamageType="target_",EFFECT_DAMAGE_TARGET # while(damage>0):num=damage%10; damage/=10; index 0..7(>7 TraceError break); # 贴图 "d:/ymir work/effect/affect/damagevalue/.dds", # 水平偏移 FONT_WIDTH(30)*index(相机右方向,matTrans._41 = -(FONT_WIDTH*index)) # UserInterface/PythonSystem.cpp:308 m_Config.bShowDamage = true(默认) # UserInterface/PythonSystem.cpp:337 IsShowDamage() -> m_Config.bShowDamage # UserInterface/PythonSystem.cpp:342 SetShowDamageFlag(iFlag) -> bShowDamage = (iFlag == 1) # UserInterface/PythonSystem.cpp:451 config "SHOW_DAMAGE" -> atoi(value) == 1 # UserInterface/PythonSystem.cpp:537 save "SHOW_DAMAGE %d"(仅当 == 0,即非默认时落盘) # UserInterface/PythonSystemModule.cpp:192/219 systemSetShowDamageFlag / systemIsShowDamage # root/uigameoption.py __OnClickShowDamageOn/OffButton -> systemSetting.SetShowDamageFlag(...) # # seam ⑪:参考端每位数字是一张 damagevalue/.dds 贴图做的 CEffectManager 特效, # 在相机右方向按 FONT_WIDTH*index 像素铺开;本移植 net_world 用一块 billboard Label3D 直接写 # str(amount)(无 damagevalue dds 图集 / 无逐位特效 / 无相机右向像素铺排),MISS 写 "MISS"。 # self 的 SELFDAMAGE/SELFDAMAGE2 交替本移植退化成落字水平抖动符号交替(仅存在感,无双特效资源)。 # 暴击在该 40250 build 参考端本就无独立视觉,这里也不再放大 / 变色(与 <=112 的占位实现相比是回归对齐)。 # 另:参考端 m_DamageQueue 是「每个实例一条」,ProcessDamage 每帧每实例 pop 一条;本移植是 # net_world 一条全局队列每帧 pop 一条 —— 同一帧多个 VID 同时受击时会分帧显示。 extends RefCounted # CInstanceBase::DamageFlag const DAMAGE_NORMAL := 1 << 0 const DAMAGE_POISON := 1 << 1 const DAMAGE_DODGE := 1 << 2 const DAMAGE_BLOCK := 1 << 3 const DAMAGE_PENETRATE := 1 << 4 const DAMAGE_CRITICAL := 1 << 5 const SHOW_DAMAGE_DEFAULT := true # m_Config.bShowDamage 默认 const CFG_KEY := "SHOW_DAMAGE" # PythonSystem 配置行 / 存盘键 const FONT_WIDTH := 30 # ProcessDamage 逐位水平像素步进 const MAX_DIGITS := 8 # index > 7 -> break enum Kind { MISS, DIGITS } # AddDamageEffect:仅当 IsShowDamage() 才入队 static func should_queue(show_damage: bool) -> bool: return show_damage # SetShowDamageFlag(int iFlag): m_Config.bShowDamage = iFlag == 1 static func show_damage_from_flag(flag: int) -> bool: return flag == 1 # config "SHOW_DAMAGE" 行:atoi(value) == 1 static func show_damage_from_cfg(value: Variant) -> bool: return int(value) == 1 # RecvDamageInfoPacket:bSelf = 目标实例是主角 static func is_self(vid: int, main_vid: int) -> bool: return vid != 0 and vid == main_vid # RecvDamageInfoPacket:bTarget = 目标实例是当前目标框 VID static func is_target(vid: int, target_vid: int) -> bool: return vid != 0 and vid == target_vid # RecvDamageInfoPacket:damage < 0 记 TraceError 不处理 static func valid_amount(amount: int) -> bool: return amount >= 0 # ProcessDamage 分类。返回: # {"kind": Kind, "type": String("damage_"/"target_"/"nontarget_"), "show": bool, "self": bool} # show == false 只有一种来源:非 self 且非 target 的数字伤害(ProcessDamage 里 return,不渲染)。 static func classify(flag: int, b_self: bool, b_target: bool) -> Dictionary: if (flag & DAMAGE_DODGE) != 0 or (flag & DAMAGE_BLOCK) != 0: # EFFECT_DAMAGE_MISS(self)/ EFFECT_DAMAGE_TARGETMISS(其它) return {"kind": Kind.MISS, "type": "damage_" if b_self else "target_", "show": true, "self": b_self} if b_self: return {"kind": Kind.DIGITS, "type": "damage_", "show": true, "self": true} if not b_target: return {"kind": Kind.DIGITS, "type": "nontarget_", "show": false, "self": false} return {"kind": Kind.DIGITS, "type": "target_", "show": true, "self": false} # while(damage>0){ num=damage%10; damage/=10; } —— 低位在前,最多 8 位(index>7 break)。 # damage <= 0 不产出任何位(与参考 while 一致)。 static func digits(damage: int) -> Array: var out: Array = [] var d := damage if d <= 0: return out var index := 0 while d > 0: if index > MAX_DIGITS - 1: break out.append(d % 10) d = d / 10 index += 1 return out # 第 index 位数字相对锚点的水平像素偏移(相机右方向)。 static func digit_offset_px(index: int) -> float: return float(FONT_WIDTH * index) # ProcessDamage 的 self 特效交替:m_bDamageEffectType==false -> SELFDAMAGE(0),否则 SELFDAMAGE2(1), # 每次自伤后取反。返回本次用的槽位(0/1)。 static func self_damage_slot(toggle_state: bool) -> int: return 1 if toggle_state else 0