普通与冠军怪初始经验和声望
后续:当前奖励池生命周期与直接死亡交接已补当前池操作与交接顺序,正式奖励接收器/致死事务仍继续。
本批接通出生时奖励计算和v33保存。InitialRewards不是当前剩余奖励池,不得在死亡、复活或读旧存档时用初始结果重新填池。
初始化路径
普通怪 56D380 @56D697 读取 DAT XP(默认0)。55CEE0 @55D3EB 的重算先检查已有+0x5A0:为0便跳过,不重填;非0重读DAT,再计算普通经验。
522BE0是首次冠军化路径,不是所有怪的通用初始化;+0x7D8已为真便不重新执行。冠军XP在523012重读,声望通过41E850独立生成,不受XP为0的门影响。普通新实例fame从构造器0开始。
精确公式
以下存储点不可省略,中间值按x87 PC精度运算:
普通经验:
factor = f32(int(XP) * 0.01f)
experience = ftol2(f32(ceil(f64(EXPERIENCE_MONSTER(level) * factor))))
冠军经验:
experience = ftol2(EXPERIENCE_CHAMPIONMONSTER(level) * int(XP) * 0.01f)
冠军声望:
fame = ftol2(f32(ceil(f64(FAME_CHAMPIONMONSTER(level) * 1.0f))))各曲线按难度加 _EASY/空串/_HARD/_VERYHARD。XP=0跳过经验图表;冠军仍查询声望。普通声望初值0。
PC=53、图表值20、XP=100时:普通经验20,冠军经验19。普通先把百分比存成float,再ceil;冠军不做这两步,不能用同一条近似算法。
原 84A7F0 (__ftol2_sse) 的SSE2分支先将ST(0)存成double再CVTTSD2SI,另一分支截断保留的x87值。PC=64的整数邻域可能不同,已显式验证;当前CoreSim生产计算使用PC=53。超出整数可表示范围的输入被拒绝,并未宣称移植CRT所有溢出/NaN语义。
数据与保存
现有F2 JSON已包含XP及继承来源;本批让C# MonsterDefinition.ExperiencePercent 消费它。null表示未导入/旧数据,0表示已知无经验。
SpawnMonster 在HP随机化和分配身份之前验证奖励图表,写入实例的 InitialRewards。v33保存出生结果;旧存档缺失时保持未知,不按现在的等级重建一个可能已被消费的池。
验证
固定EXE SHA256:186472c3057b38f4cdff4696959a943c396ae6166995f7418997b5ea853e8a5e。
原55D437/52312A算术片段、完整41E440/41E850 helper及84A7F0转换共1956组对照,三精度/两转换路径均一致;图表、wstring和CRT ceil是显式边界。全部2284个怪物形态×三个等级×四难度,共27408组真实数据初始化通过。
1524条核心断言、310项相关Python回归及Godot C#构建通过,含真实生成、v33保存重放和旧数据未知状态。
当前未结算池仍待衔接
直接死亡53D5A0和持续死亡53C2F0都会清池,且回调顺序不同;53BC80的复活相关分支还会清XP。初始结果不能代替这些可变状态。
剩余池生命周期、实际XP/fame接收器和持续死亡分派的事务接线仍未完成;TYPE52准入保护保持,武器构造仍为1053/1419。