Initial import of HEROLL source and design documents
This commit is contained in:
@@ -0,0 +1,372 @@
|
||||
from pathlib import Path
|
||||
import csv, json, re, hashlib, shutil, io
|
||||
from collections import Counter, defaultdict
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[3]
|
||||
OUT = ROOT / 'HEROLL_OUTGAME_2.0.1'
|
||||
CORE = ROOT / 'HEROLL_APK_REVERSE_ONLY/01_core_reverse_archive'
|
||||
SRC = CORE / 'resource-tables/extracted/csv'
|
||||
AUDIT = OUT / '99-审计与证据'
|
||||
|
||||
# 编号、模块、表清单、职责、配置关系、需要原生/实机补证的边界、元数据检索词。
|
||||
SPECS = '''01|账号大厅与功能解锁|tutorial newbieguide modesortingorder localpush communitydata permanentkeyremoveschedule|负责大厅入口、新手引导、功能开放和持久化键清理。|tutorial 用 unlockContentKey 描述解锁内容;newbieguide 同时记录 clearStage、跳转目标和奖励;modesortingorder 决定模式展示排序。gameconfig 中的 UnlockStage、UnlockDay、Block 是入口检查候选配置,阶段索引不能直接改成玩家看到的关卡编号。|关卡门槛使用已通关还是当前关卡、离线保存和失败踢出实际分支、邮件服务端领取状态尚未闭合。|Lobby,UserData,Save,Mail,Tutorial,Unlock,Account
|
||||
02|资源背包与体力|item itemgroup itemsource lobbyticket outgamereward|统一道具类型、礼包内容、资源来源以及大厅到局内的资源映射。|item 用 ERewardType/refStringId 描述奖励语义,itemgroup 存放并列 itemIds/itemCounts/weights;itemsource 记录来源跳转与 unlockKey。lobbyticket 将 ELobbyAsset 映射到 EAsset,并区分 defaultValue/boostValue。|itemgroup 是否有放回、容量溢出补偿和资源扣除顺序必须查消费者;负值、空值、0均保留,不能自行当成默认1。chargeEnergy 数组的单位和索引需调用点确认。|Asset,Item,Reward,Inventory,Energy,Ticket
|
||||
03|永久装备与合成|equipment equipmentdata equipmentdefaultstatdata equipmentugradelevel equipmenttype equipskill mainequipmentscore|负责局外装备身份、装备位、品质星级、升级消耗和基础属性配置。|equipment 是装备目录;equipmentdata 用 level/starCount/grade 表达品质星级阶段,记录 maxUpgradeLevel 和合成材料要求;equipmentugradelevel 给出强化级别的 needMaterial/needGold;equipmentdefaultstatdata 区分普通与特殊装备基础值和升级增量。原表拼写 ugrade 保留。|不能把局外装备 level 与局内武器等级合并;基础值和升级增量如何组合、材料是否包含目标本体、升级返还和替换顺序仍需原生逻辑。equipmentdata 的材料备注明确带星级者不可作为材料。|Equipment,EquipMeta,EquipmentMerge,EquipmentUpgrade
|
||||
04|槽位强化与永久属性|slotupgrade slotupgradekey bonusstatus|管理装备槽位强化及永久属性升级。|slotupgrade 按 slotNum/level 分档,独立列出 needItemID/needCount/needGold、upgradeValue 和 specialKey/specialValue;slotupgradekey 提供属性与主属性槽映射;bonusstatus 单独给出 maxLevel、upgradeValue、isPercent。|不同属性增量不可统一套一个倍率;槽位加成作用于基础属性还是最终值、升级开关与强化重置未闭合。|SlotUpgrade,BonusStatus
|
||||
05|遗物与合成|relic relicdata|负责遗物目录、装备槽、属性技能和品质星级合成。|relic 保存 slotNum/baseStatus/statusValue/isPercent 以及 skill/skillValue/extraValue;relicdata 分离等级星级与 materialLevel/materialCount/sameGradeAnyRelicCount。普通、稀有、史诗行的 materialCount 为2。|数字2仅是字段原值,不能直接宣称总共消耗2件或3件;技能叠加、材料校验和解锁数组 relicContentsUnlockStage 的索引解释需要消费者。|Relic
|
||||
06|宠物与成长|pet petskill petgrowthdata petgrowthevent petgrowthlevel|负责宠物获取、重复转化、碎片升级、技能开放与限时成长活动。|pet 给出 needPiece/needGold 数组、解锁价格、重复转化字段和战斗基础/增量参数;petskill 按 petId 与 skillUnlockLevel 配置技能;成长活动用 eventKey 关联事件权重、经验和等级奖励。pet 的 needPiece 注释指出数组首项为未使用值。|不得从数组长度直接推断可用等级数;ifOwnAutoConvert、满级碎片转钻、技能生效和选择概率的实际执行顺序待确认。|Pet,PetGrowth
|
||||
07|坐骑与觉醒|mount mountlevel mountawaken mountskilldesc mountskilleffectgroup mounteventcount mounteventseasonitem|管理坐骑解锁、升级、觉醒、技能和活动材料兑换。|mount 同时记录 unlockPiece/unlockDia/unlockProductId 与溢出碎片返还;mountlevel 用 isOwnEffect 区分持有效果;mountawaken 按 grade/level 配置碎片与技能等级;mountskilleffectgroup 定义触发事件、概率、持续和叠加上限。|解锁路径是并列选项还是组合条件需要界面/调用验证;持有与出战效果叠加方式、觉醒是否重置和活动材料回收触发时间待确认。|Mount
|
||||
08|命运属性|destinystat|管理命运词条的启用、品质、属性、特殊效果和候选权重。|destinystat 每行同时带 normalWeight/rareWeight 两套权重、isEnabled、isPercent、addValue 和 EDestinySpecialEffect。gameconfig 保存 destinyUnlockStages 与 destinySummonNeedCost 两个数组。|两组权重对应按钮和消费资源尚未映射;保留停用词条但不计作必定可抽取;锁定、替换及属性合成公式待查。|Destiny
|
||||
09|收藏与图鉴|collection|按装备组合条件提供收藏属性。|collection 给出并列 equipmentIds/equipmentLevels/equipmentGrades,目标属性由 EMonoStatus/value 指定,isEnabled 控制配置启用。CollectionUnlockStage 原值为6。|条件是否要求同时持有、装备消耗与自动激活、value 的百分比单位不能只根据列名确认。|Collection
|
||||
10|外观头像与称号|skin profile profileframe prefixtitle|管理皮肤、头像、头像框和称号展示及部分属性加成。|skin 包含 additionalStatus/additionalValue 与 maxSetCount/setAdditionalValueList,表明皮肤并非只有展示配置;profile/profileframe 用 unlockKey 表达解锁键;prefixtitle 描述展示顺序和颜色。|穿戴还是拥有即生效、套装阈值索引和称号获取来源需调用补证;未提取的本地化文本不翻译成虚构名称。|Skin,Profile,PrefixTitle
|
||||
11|领地地块与研究|outgametile outgametileskill outgametileresearch outgametileresearchexp outgametileresearchstatus outgametileafkconfig|负责局外地块收集配置、地块技能、研究和地块包挂机。|outgametile 经 refNewTileId 连接局内事件,包含 defaultEquip、unlockStage、needPiece 和 skillUnlockLevel;研究用 totalUpgradeCount 映射 researchLevel/weaponPlusLevel,研究属性按 needResearchLevel/index 配置 needCost。地块包使用独立 afkTime/maxPackCount 及里程奖励。|研究经验如何累计、装备容量与更换约束、概率池过滤和里程重置需执行证据;地块包挂机不能与巡逻挂机共用计时参数。|OutGameTile,OutgameTile,TileResearch
|
||||
12|巡逻挂机|afkconfig afkreward|按已通关进度配置离线巡逻与快速巡逻奖励。|afkreward 以 lastClearStage 区分 goldPerHour、rewards、amountPerCheckTime、maxAmount、dropPercent;afkconfig 注释明确时间单位为分钟,并分离普通巡逻、快速巡逻和广告次数。|不足一个检查周期如何舍入、超时结算、随机倍数是否作用于所有奖励、每日重置时区未闭合。|Afk,AFK,Patrol
|
||||
13|抽卡与保底|gachatype gacha gachaceildata|统一抽卡按钮、消费、候选奖励、权重和保底配置。|gachatype 按 type/buttonNum 定义 gachaCount、免费或广告、消耗和替代道具;gacha 同 type 行组成配置候选池;gachaceildata 按 type 配 ceilCount/isResetBeforeCeil/ceilRewardString。rewardID=-1 注释表示指定类型中的全池。|prob 是未归一化字段,真实概率依赖运行时筛选和保底优先级;券抵扣、十连计数、跨池累计及动态池内容需实机或原生验证。|Gacha
|
||||
14|商店礼包与广告|shopproductlist dailyshoplist relaypackagedata d3package pigbank dailypurchasereward groupbmshop groupexchangeshop promotioninfo triggerinfo interstitialexeptionregion|管理常驻商品、每日商店、连续礼包、存钱罐、兑换和触发式促销。|shopproductlist 分离 BuyPrice/Dollar、平台产品ID、ECostType、次数重置和每日发放;triggerinfo 给出触发条件、时段、重复开启及开关;dailyshoplist 用 Prob 描述刷新候选。|包内价格是历史配置,不代表当前支付平台报价;触发优先级、订单校验、服务端限购和广告可用性无法由静态表证明。|Shop,Purchase,Product,Package,PigBank,Advert,Ads,Promotion
|
||||
15|任务与成就|questdata groupquestlist achievement|统一任务语义、任务组、累计条件、领取方式和成就前置链。|questdata 定义 questType/questKey/subValue 与跳转;groupquestlist 通过 questDataStringId 关联目标数量、锁定时是否计数、EClaimType 和奖励;achievement 包含 prerequisiteId、isPerGameReset、isHidden 和 goalCount。|事件实际计数时机、前置链激活、隐藏成就曝光以及服务端重复领取防护待确认。|Quest,Achievement
|
||||
16|签到新人与回归|attendance attendanceconfig comebackconfig newbiebuffconfig|配置签到日历、补签、新人加成和回归福利。|attendance 用 EAttendanceType/day 组织奖励与补签方式价格;attendanceconfig 保留普通与 prod 日期字段;comebackconfig 注释以分钟定义离线门槛与buff时长,另外给出奖励/加速次数。|签到漏天处理、补签可用日期、时区和回归状态重置未闭合;历史排期不是当前在线活动。|Attendance,Comeback,NewbieBuff
|
||||
17|通行证与赛季|passdata passquestlist passrewarddata passseasondata|负责通行证经验、任务、奖励轨道和赛季开放。|passdata 区分日常/每周/挑战任务数量、dailyXP、playMaxXP 和 primiumPlayMaxXP;passrewarddata 区分普通、高级及高级Plus奖励;passseasondata 连接商品组、兑换组、任务组、抽卡和排行榜。|经验上限重置、补领奖励、重复等级、付费生效和赛季切换执行顺序仍需确认。不能把不同 passID 的参数合并。|Pass,SeasonPass
|
||||
18|主线进度与星级挑战|stageinfo stagerewardinfo loopreward starchallenge starchallengereward|管理局外选关、进度奖励和星级挑战;关内战斗只保留衔接配置。|stageinfo 的 stage/EPlayMode/isEnabled 定义关卡目录;stagerewardinfo 以 stage/loop/isClear 等字段分支发奖;starchallenge 描述挑战值,starchallengereward 按 starCount 配置奖励档。|首通与重复通关判定、星级条件评估和奖励领取幂等性需消费者;本模块保留整张stageinfo以防丢失入口字段,不重写局内战斗。|StageSelect,StarChallenge,StageReward,ClearReward
|
||||
19|每日副本与探索副本|dayoftheweekdungeon dayoftheweekdungeonconfig weekdungeonboard idledungeon idledungeonconfig idledungeondrop idledungeonequipmentsalvage idledungeonequipmentstatus idledungeonplayerdefaultstat idledungeonstageinfo|管理曜日副本以及 IdleDungeon 探索玩法的入口、票券、成长与掉落回收。|曜日表按 day/difficulty 给奖励;IdleDungeon 单独定义票券恢复、背包容量、关卡、掉落权重与装备分解表。保留战斗衔接表以保证子系统数据完整。|两个模式并非同一个挂机系统;星期枚举、票券单位和满票停止恢复、掉落保护算法以及分解是否受等级约束待查。|WeekDungeon,DayOfWeek,IdleDungeon
|
||||
20|无限模式|infiniteconfig infiniteseason infiniteboard infinitemodefevertiles|管理无限模式入场成本、赛季、奖励限制和独立难度配置。|infiniteconfig 给出 playAssetId/playAssetCount、excludeReward、maxGold、shopIncrease;infiniteseason 记录赛季Boss;infiniteboard 保留难度/层数成长;fever地块表带 isEnabled/weight。|maxGold 的限制周期、shopIncrease 计算公式、赛季切换与结算扣费时间待查。|Infinite,Infinity
|
||||
21|Raid讨伐|raidconfig raidtier raidreward raidhighscorereward raidseasonpetlist raidseasonpreset raidboard raidaugmentoverride|管理讨伐门票、赛季预设、试用宠物、分数奖励与最高分档。|raidconfig 独立定义初始票、上限、恢复时间和入场成本;raidreward 按 tierId/season/minScore/maxScore 给出奖励;raidhighscorereward 为独立最高分门槛;seasonpetlist 用 deckIndex/trialLevel 配阵容。|分数端点包含关系、票券消耗时点和最高分奖励是否仅一次待查;不能把重复结算表与最高分表合并。|Raid
|
||||
22|药水竞技与段位|battlepotion battleplayerdefaultstat potionbattleconfig potionbattlebonus potionbattlebonuskey rankbasedata rankmmradjust ranktier|管理竞技药水养成、匹配门票、段位MMR和竞技加成。|battlepotion 定义重量/冷却/效果基础值与增量、needPiece/needCost;potionbattleconfig 定义匹配范围与门票;ranktier 给出MMR区间和阶梯;rankmmradjust 存储多段修正参数,rankbasedata 关联通行证和赛季重置调整。|匹配服务器算法、MMR修正顺序、药水重量组装规则以及旧gameconfig票券字段与专表的优先级待查。|PotionBattle,RankTier,Matchmaking,BattlePotion,MMR
|
||||
23|排行榜与赛季奖励|rankingdata rankingreferencedata rankingrewarddata|配置排行分组、环境排期、业务引用和名次奖励。|rankingdata 分别记录QA/Dev/Prod分组和赛季字段;rankingreferencedata 通过 RankKey/ERefType/referenceKey 关联业务;rankingrewarddata 以 minRank/maxRank 关联奖励。|名次区间端点、同分排序、跨服分组、结算时刻和发奖服务端逻辑未闭合。|Ranking,Leaderboard
|
||||
24|赛季活动与超级球|seasonevent seasoneventroulette seasonquestlist superballschedule|管理活动排期、活动任务、兑换时段、转盘及超级球奖池。|seasonevent 独立记录活动结束与兑换结束以及prod日期;seasonquestlist 连接任务/通行证经验;seasoneventroulette 存储weight与奖励;superballschedule 给出参与人数相关奖励字段、赛季组、开奖计时和gachaType。|排期仅包内历史快照;不能根据字段名断言超级球奖池计算公式,真实参与人数与结算由运行时/服务器决定。|SeasonEvent,SuperBall
|
||||
25|活动小游戏与奖励池|seasoneventminigamedata bubbleshooterminigame cardunpackingeventgame clawcraneminigame dicebeteventgame dicemachine herobodyminigame plinko plinkoad plinkolevel roulettedata spitoeventdailyreward spitoeventreward|归档活动小游戏入场资源、玩法模板、概率奖励和广告增益。|seasoneventminigamedata 描述 gamePackIndex 与 playItemUseCount;Plinko 独立配置球上限/恢复和广告buff;抓娃娃、拆卡包、刮奖、转盘等分别保留自己的概率字段和模板,不能混成统一抽卡池。|部分小游戏也可能出现在局内事件,作为交叉模块完整保留;胜负判定、概率归一化范围、广告叠加与奖励结算顺序待查。|Minigame,MiniGame,Plinko,Roulette,Spito,ClawCrane,CardUnpacking,DiceMachine
|
||||
26|NPC好感与特殊养成商店|deoksun deoksunattendance deokjashop|保留NPC好感档位、签到轮次和特殊属性商店。|deoksun 按 likePoint 配置 slotRarity、goldUP、diaUP、服饰对话与 ingameDiscount;deoksunattendance 以 groupKey/round/day 发奖;deokjashop 包含属性、权重、基础与增量、maxLevel。|deokjashop 的金币字段原注释标注不使用,不能据其数值写实际价格公式;NPC中文正式名称、好感获取和商店解锁消费逻辑尚待本地化/消费者补证。|Deoksun,Deokja
|
||||
'''
|
||||
MODULES = [dict(zip(['id','name','tables','role','flow','unknown','terms'], l.split('|'))) for l in SPECS.strip().splitlines()]
|
||||
for m in MODULES:
|
||||
m['folder'] = m['id']+'-'+m['name']
|
||||
m['tables'] = m['tables'].split()
|
||||
|
||||
# 原作功能还原口径:只保留影响玩法解释的待考证项。
|
||||
DETAILS = {
|
||||
'01':'解锁阶段使用已通关阶段还是当前阶段、开放日序从0还是1起算,现有配置尚不能确定。',
|
||||
'14':'商品触发条件的先后关系、每日商店的候选筛选与权重计算方式尚需补充。价格按原作包内配置保留。',
|
||||
'15':'任务事件的计数时机、前置成就完成后的激活时机、隐藏成就的展示条件尚需补充。',
|
||||
'22':'MMR多段修正顺序、药水重量组合规则以及全局配置与竞技专表参数的使用关系尚需补充。',
|
||||
'23':'名次区间端点是否包含、同分排序和奖励结算时刻尚需补充。',
|
||||
'24':'超级球参与人数奖励的累计公式尚未确定;保留初始奖池、每人增加范围、名次分配与统计时间原值。'
|
||||
}
|
||||
FLOWS = {
|
||||
'01':'达到进度条件 → 开放对应大厅入口 → 按引导进入功能 → 领取引导奖励',
|
||||
'02':'获得道具或资源 → 查看用途与来源 → 使用、开启道具组或兑换 → 形成奖励或带入局内的资源',
|
||||
'03':'获得装备 → 选择对应槽位 → 强化提升属性 → 按品质星级材料要求合成 → 提高强化上限',
|
||||
'04':'选择装备槽位或永久属性 → 查看当前等级与下级消耗 → 升级 → 获得属性增量或特殊效果',
|
||||
'05':'获得遗物 → 选择遗物槽位 → 按品质星级配置合成 → 获得属性和技能收益',
|
||||
'06':'解锁宠物 → 收集碎片与金币 → 升级 → 开放等级技能;成长活动另按事件获得经验和阶段奖励',
|
||||
'07':'解锁坐骑 → 消耗养成材料升级 → 使用碎片觉醒 → 提升持有效果、属性或被动技能等级',
|
||||
'08':'开放命运功能 → 从对应权重组取得词条 → 形成属性或特殊效果;保留两组权重和召唤成本配置',
|
||||
'09':'查看收藏组合 → 满足指定装备、等级、品质要求 → 获得对应收藏属性',
|
||||
'10':'解锁外观 → 选择皮肤、头像、头像框或称号 → 展示外观;皮肤另有单件属性与套装协同配置',
|
||||
'11':'获得地块包与碎片 → 解锁或升级地块 → 配置地块与开放技能 → 累积研究进度 → 提升研究属性',
|
||||
'12':'积累巡逻时长 → 按通关进度确定奖励档 → 领取巡逻收益;快速巡逻按固定时长、体力与次数配置提供收益',
|
||||
'13':'选择抽卡池与按钮 → 按抽数及资源配置消费 → 从奖励池取得奖励 → 按对应池的保底配置处理保底',
|
||||
'14':'展示满足条件的商品 → 查看成本、限购与奖励 → 购买或兑换 → 获得即时奖励或每日奖励;部分礼包按顺序开放',
|
||||
'15':'开放任务或成就 → 按条件累计目标进度 → 满足目标数量 → 按领取方式取得奖励 → 连接后续任务或前置链',
|
||||
'16':'进入签到或满足新人、回归条件 → 按日序和状态开放福利 → 领取道具或限时加成 → 按次数与时长结束加成',
|
||||
'17':'开放通行证赛季 → 通过任务与游玩积累经验 → 提升通行证等级 → 领取所属奖励轨道的等级奖励',
|
||||
'18':'选择已开放关卡或挑战 → 进行局内玩法 → 更新通关或星级进度 → 领取对应关卡、层数或星数奖励',
|
||||
'19':'选择曜日或探索副本 → 按模式使用入场资源 → 推进关卡 → 获取模式奖励;探索装备另按品质等级分解回收',
|
||||
'20':'选择无限模式 → 消耗入场资源 → 推进对应难度层数 → 按模式的奖励排除与金币上限配置取得收益',
|
||||
'21':'取得讨伐门票 → 进入赛季预设与宠物阵容 → 击败目标累积分数 → 获得分数档奖励并追求最高分奖励',
|
||||
'22':'养成竞技药水 → 配置竞技效果与重量 → 使用门票参加竞技 → 按MMR与段位配置形成竞技进度和奖励',
|
||||
'23':'玩法成绩关联对应排行 → 形成名次 → 按名次区间确定奖励 → 随关联赛季进入下一周期',
|
||||
'24':'进入排期活动 → 完成活动任务或参与转盘、超级球 → 获得活动奖励 → 在兑换期使用活动资源',
|
||||
'25':'进入对应活动小游戏 → 消耗指定资源或等待恢复 → 按游戏模板参与 → 获得对应奖励池收益;部分功能可获得广告增益',
|
||||
'26':'提升NPC好感 → 变化对话、服饰与收益档位 → 参与签到或特殊商店养成 → 获得道具或属性增益'
|
||||
}
|
||||
for m in MODULES:
|
||||
m['unknown'] = DETAILS.get(m['id'], m['unknown'])
|
||||
|
||||
EDITORIAL = {
|
||||
'不采用《一骰登天》MVP主动改造值。覆盖全部提取CSV的范围判定;“配置已收录”不表示运行时规则全部闭合。未运行游戏、未查询服务器、未重新反编译原生方法体。':'以原作功能设计、玩法规则和完整数值为主线。设计文档说明功能关系,规则文档解释条件与消耗,表格保存全量等级、奖励和参数。',
|
||||
'原作配置快照,不混入MVP数值。配置和元数据检索已归档;未恢复的执行规则逐模块明确列出。':'以原作HEROLL 2.0.1为唯一还原对象。每个模块按功能设计、规则说明和数值表组织,来源索引集中保留在审计目录。',
|
||||
'运行时筛选、服务端状态、动态内容、数组索引和单位等证据不足。':'少量规则的筛选顺序、数组索引或单位尚待原作资料补充。',
|
||||
'out_of_scope:新项目MVP改造、在线服务器请求、原APK执行、重新原生逆向。':'交付口径:还原原作功能、规则及数值,来源与检索过程作为附录。',
|
||||
'本次“所有”指现有提取表的全量检索与范围分配,不意味着服务端规则或全部方法实现可由静态数据恢复。':'全部提取表均已进行范围分配。无法确定的原作玩法细节简短列入补充项。',
|
||||
'没有读取原生方法实现、没有动态运行或服务器访问;不能据此声称所有局外运行规则已经还原。':'本包依据现有配置、注释和元数据整理;无法确定的原作玩法细节保留补充标记。'
|
||||
}
|
||||
|
||||
def write(path, text):
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
for old,new in EDITORIAL.items(): text=text.replace(old,new)
|
||||
path.write_text(text, encoding='utf-8')
|
||||
|
||||
def csvwrite(path, rows, fields=None):
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
if fields is None: fields = list(rows[0]) if rows else ['说明']
|
||||
with path.open('w', encoding='utf-8-sig', newline='') as f:
|
||||
w=csv.DictWriter(f, fields); w.writeheader(); w.writerows(rows)
|
||||
|
||||
def readtable(path):
|
||||
with path.open(encoding='utf-8-sig', newline='') as f: raw=list(csv.reader(f))
|
||||
hi=next(i for i,r in enumerate(raw) if 'Id' in r and 'StringId' in r)
|
||||
headers=raw[hi]; types=raw[hi+1]; comments=raw[hi-1] if hi else []
|
||||
records=[]
|
||||
for ri,r in enumerate(raw[hi+2:], hi+3):
|
||||
if not any(r): continue
|
||||
assert len(r)==len(headers), (path.name,ri,len(r),len(headers))
|
||||
records.append((ri,dict(zip(headers,r))))
|
||||
return headers,types,comments,records
|
||||
|
||||
TABLES={p.stem:readtable(p) for p in sorted(SRC.glob('*.csv'))}
|
||||
owner={}
|
||||
for m in MODULES:
|
||||
for t in m['tables']:
|
||||
assert t in TABLES,t
|
||||
assert t not in owner,t
|
||||
owner[t]=m['folder']
|
||||
metadata=json.loads((CORE/'metadata/assembly-csharp.json').read_text(encoding='utf-8'))
|
||||
gconfig=TABLES['gameconfig'][3]
|
||||
|
||||
def escape(v): return str(v).replace('|','\\|').replace('\n','<br>').replace('\r','')
|
||||
def table(headers, rows):
|
||||
return '| '+' | '.join(headers)+' |\n| '+' | '.join(['---']*len(headers))+' |\n'+''.join('| '+' | '.join(escape(v) for v in r)+' |\n' for r in rows)
|
||||
def sha(p): return hashlib.sha256(p.read_bytes()).hexdigest()
|
||||
|
||||
# 总纲先于模块生成,保持阅读及生成顺序一致。
|
||||
overview='# HEROLL 2.0.1 局外系统模块总纲\n\n版本:原版APK逆向数据整理 v1;整理日期:2026-09-06。\n\n本包检索现有原版逆向归档,恢复配置规则与结构证据,不采用《一骰登天》MVP主动改造值。覆盖全部提取CSV的范围判定;“配置已收录”不表示运行时规则全部闭合。未运行游戏、未查询服务器、未重新反编译原生方法体。\n\n## 模块总纲\n\n'
|
||||
overview+=table(['模块','职责','数据表数'],[(f"[{m['folder']}](./{m['folder']}/01-模块设计文档.md)",m['role'],len(m['tables'])) for m in MODULES])
|
||||
overview+='\n## 模块交付结构\n\n每个模块含 `01-模块设计文档.md`、`02-规则说明.md`、`03-表格/`。表格中保留原始CSV(含注释和类型)、规范化CSV(标准首行字段名)、字段字典、数值范围、元数据符号与规则证据。原始表的全部行均保留,包括停用和历史内容。\n\n## 系统关系\n\n账号与进度 → 功能解锁 → 资源获取 → 抽卡/商店/奖励 → 装备、宠物、坐骑、遗物、地块等长期养成 → 局内初始属性及模式配置 → 通关与活动奖励 → 长期养成。此关系是按配置用途整理的设计阅读路径,不是已经恢复的原生调用栈。\n\n## 证据等级\n\n- A 配置事实:原始CSV值、类型及注释。行定位使用CSV记录序号(含注释/表头/类型行),不等同含多行单元格文件的物理行号。\n- B 结构事实:Assembly-CSharp元数据的类型、字段、方法名称;可能含混淆或损坏名称,不证明方法实现。\n- C 条件推导:只在所列前提成立时有效,不能作为已确认运行规则。\n- U 未闭合:运行时筛选、服务端状态、动态内容、数组索引和单位等证据不足。\n\n## 审计入口\n\n[全表范围清单](./99-审计与证据/全表范围清单.csv) · [源文件哈希](./99-审计与证据/源文件清单.csv) · [全局配置](./00-共享配置/gameconfig.csv) · [检索与验证报告](./99-审计与证据/2026-09-06_逆向-HEROLL局外系统-report.md)\n'
|
||||
write(OUT/'00-局外系统模块总纲.md',overview)
|
||||
write(OUT/'README.md','# HEROLL 2.0.1 局外系统规则与数值\n\n先读[模块总纲](./00-局外系统模块总纲.md),再按26个模块阅读设计、规则和完整CSV表。\n\n原作配置快照,不混入MVP数值。配置和元数据检索已归档;未恢复的执行规则逐模块明确列出。\n')
|
||||
|
||||
GROUTES = {
|
||||
'01':r'Unlock|Block|Save|autoUnlock', '02':r'Energy|dailyIngameDiaLimit|ingameDiaAdj|vip',
|
||||
'03':r'calcCp|autoEquip', '04':r'Rune', '05':r'relic', '06':r'pet', '07':r'mount',
|
||||
'08':r'destiny', '09':r'Collection', '10':r'skin|profile', '11':r'outgameTile|BaseTile|MultiplyTile',
|
||||
'12':r'afk', '13':r'Gacha', '14':r'Shop|vip', '15':r'quest', '16':r'newbie|comeback',
|
||||
'17':r'pass', '18':r'starChallenge|needEnergy', '19':r'weekDungeon|dayOfWeek|idleDungeon',
|
||||
'20':r'infinite|infinity', '21':r'raid', '22':r'potionBattle|pvp', '23':r'rank',
|
||||
'24':r'SeasonEvent|Summer|SuperBall', '25':r'Roulette|Spito', '26':r'Deokja|Deoksun'
|
||||
}
|
||||
FIELD_ZH={
|
||||
'Id':'数值主键','StringId':'字符串主键','isEnabled':'配置启用标志','IsUse':'使用标志','isUse':'使用标志',
|
||||
'level':'等级/阶段索引(具体语义按表)','grade':'品质枚举','starCount':'星数','maxUpgradeLevel':'强化等级上限',
|
||||
'materialLevel':'合成材料等级','materialCount':'合成材料数量字段','sameGradeAnyEquipmentCount':'同品质任意装备材料数量',
|
||||
'sameGradeAnyRelicCount':'同品质任意遗物材料数量','needMaterial':'所需材料数量','needGold':'所需金币(数组按原索引)',
|
||||
'needPiece':'所需碎片数组','slotNum':'槽位编号','maxLevel':'等级上限(负值语义需消费者)',
|
||||
'needItemID':'消耗道具ID','needCount':'消耗数量','itemID':'道具ID','itemId':'道具ID','itemCount':'道具数量',
|
||||
'rewardId':'奖励ID(按奖励类型解析)','rewardID':'奖励ID(按奖励类型解析)','rewardCount':'奖励数量',
|
||||
'prob':'概率/权重原值(未归一化)','Prob':'概率/权重原值(未归一化)','weight':'权重原值','weights':'权重数组',
|
||||
'isPercent':'是否百分比标记(存储缩放需消费者)','isOwnEffect':'持有效果标记','isFree':'免费标记',
|
||||
'isAD':'广告按钮标记','gachaCount':'抽取次数','ceilCount':'保底次数','isResetBeforeCeil':'保底前命中是否重置标记',
|
||||
'ceilRewardString':'保底奖励Gacha字符串键','ADcooldown':'广告重置周期枚举','alterCount':'单个替代道具抵扣量',
|
||||
'alterItemID':'替代道具ID','isAlterBtn':'替代按钮标记','type':'类型/分组','buttonNum':'按钮编号',
|
||||
'checkTime':'巡逻检查间隔(分钟,原注释)','maxAfkTime':'巡逻累计上限(分钟)',
|
||||
'quickAfkTime':'快速巡逻奖励时长(分钟)','dailyMaxQuickAfkCount':'每日快速巡逻上限',
|
||||
'quickAfkEnergy':'快速巡逻体力消耗','dailyMaxQuickAfkAdCount':'每日广告快速巡逻上限',
|
||||
'multipleValue':'奖励倍数数组','multipleWeight':'奖励倍数权重数组','lastClearStage':'最后通关阶段',
|
||||
'goldPerHour':'每小时金币','amountPerCheckTime':'每检查周期奖励数量','maxAmount':'奖励数量上限',
|
||||
'dropPercent':'掉落百分数字段(缩放待消费者)','afkTime':'每包累计时间(分钟)','maxPackCount':'最多累计包数',
|
||||
'startAddPack':'内容解锁初始包数','needMileage':'里程奖励需求','getMileage':'每类包里程数组',
|
||||
'mileageRewardId':'里程奖励道具ID','mileageRewardCount':'里程奖励数量','packList':'实际地块包ID数组',
|
||||
'packAfkList':'挂机奖励用包ID数组','probList':'概率/权重列表原值','totalUpgradeCount':'总升级次数',
|
||||
'researchLevel':'研究等级','weaponPlusLevel':'武器额外等级','needResearchLevel':'研究等级需求',
|
||||
'needCost':'消耗字段(资源类别看消费者)','refNewTileId':'关联局内newtile主键','unlockStage':'解锁阶段',
|
||||
'defaultEquip':'默认装备标记','skillUnlockLevel':'技能解锁等级','baseAdditionalStatus':'基础附加属性',
|
||||
'plusAdditionalStatus':'附加属性增量','unlockPiece':'解锁碎片数量','unlockDia':'解锁钻石字段',
|
||||
'unlockProductId':'解锁商品键','refundItemId':'溢出返还道具ID','refundItemCount':'溢出返还数量',
|
||||
'normalWeight':'普通权重','rareWeight':'稀有权重','addValue':'增加值','value':'数值(单位按表)',
|
||||
'baseValue':'基础值','upgradeValue':'升级增量字段','specialValue':'特殊数值',
|
||||
'maxTicketCount':'门票上限','startTicketCount':'初始门票数','ticketChargeTime':'门票恢复时间(单位按表注释)',
|
||||
'playAssetId':'入场资源ID','playAssetCount':'入场消耗数量','goalCount':'目标次数',
|
||||
'isCanCountWhenLock':'锁定期间是否计数','prerequisiteId':'前置成就ID','isHidden':'隐藏标记',
|
||||
'isPerGameReset':'每局重置标记','day':'日序/星期枚举(按表)','price':'价格字段',
|
||||
'comebackTime':'回归离线门槛(分钟)','buffTime':'加成持续分钟(以注释为准)',
|
||||
'rewardBuffPercent':'额外奖励百分数','rewardBuffCount':'奖励加成次数','playSpeedBuffCount':'加速次数',
|
||||
'passID':'通行证ID','needXP':'经验需求','dailyXP':'每日经验','playMaxXP':'每日游玩经验上限',
|
||||
'primiumPlayMaxXP':'高级通行证游玩经验上限(原拼写)','loopClearXP':'每层通关经验',
|
||||
'season':'赛季编号','seasonStartDay':'赛季起日','seasonEndDay':'赛季止日','exchangeEndDay':'兑换截止日',
|
||||
'minRank':'名次区间下界','maxRank':'名次区间上界','minScore':'分数下界','maxScore':'分数上界',
|
||||
'minMMR':'MMR下界','maxMMR':'MMR上界','stepMMR':'MMR步长','BuyPrice':'包内购买价格字段',
|
||||
'Dollar':'包内美元价格字段','ECostType':'消费类型枚举','buyCount':'限购数量','buyResetCooldown':'限购重置周期',
|
||||
'dailyObtainDay':'每日奖励持续天数','isSpecial':'特殊标记','isMaterial':'材料标记',
|
||||
'baseCoolTime':'基础冷却','plusCoolTime':'冷却增量','baseDamageValue':'基础伤害字段',
|
||||
'plusDamageValue':'伤害增量','baseExtraValue':'基础额外值','plusExtraVaue':'额外值增量(原拼写)',
|
||||
'EMonoStatus':'属性枚举','ERewardType':'奖励类型枚举','EPlayMode':'玩法模式枚举',
|
||||
'Values':'全局配置原数组(单位/索引不得自行推定)'
|
||||
}
|
||||
|
||||
# 经原注释和记录核对的中文规则。值从源行读取,避免手工转录漂移。
|
||||
FACTS = {
|
||||
'01': [('gameconfig','modeSelectUnlockStage','模式选择解锁门槛配置','Values'),('gameconfig','IsOfflineSaveBlock','离线保存阻止开关原值;不等同已确认运行行为','Values'),('gameconfig','mountUnlockDay','坐骑开放日序配置;首日索引未闭合','Values')],
|
||||
'02': [('gameconfig','needEnergy','入场体力需求配置','Values'),('gameconfig','maxEnergy','基础体力上限配置','Values'),('gameconfig','chargeEnergy','体力恢复配置数组;计时单位及数组位置需消费函数','Values'),('gameconfig','vipAddMaxEnergy','VIP额外体力上限配置','Values')],
|
||||
'03': [('equipmentdata','equipment_NORMAL_0','普通0星:品质阶段与强化上限、合成字段','level starCount maxUpgradeLevel materialLevel materialCount'),('equipmentdata','equipment_LEGEND_2','传说2星:强化上限及材料字段','level starCount maxUpgradeLevel materialLevel materialCount'),('equipmentdata','equipment_ETERNITY_3','永恒3星:表中最高阶段记录,空材料不自动代表可继续合成','level starCount maxUpgradeLevel materialLevel materialCount sameGradeAnyEquipmentCount')],
|
||||
'04': [('slotupgrade','slot0_lv_0','槽0当前level=0到下一级的消耗(原注释明确“到下一级”)','level needItemID needCount needGold upgradeValue'),('slotupgrade','slot0_lv_1','槽0当前level=1到下一级的消耗','level needItemID needCount needGold upgradeValue'),('bonusstatus','ATTACK_POWER','永久攻击属性配置','isPercent upgradeValue maxLevel')],
|
||||
'05': [('relicdata','relic_NORMAL_0','普通遗物合成材料字段','level starCount grade materialLevel materialCount'),('relicdata','relic_LEGEND_0','传说遗物材料分支','level starCount grade sameGradeAnyRelicCount'),('gameconfig','relicContentsUnlockStage','遗物开放条件原数组','Values')],
|
||||
'06': [('pet','pet01','pet01升级、重复转化与冷却原值;needPiece首项为未使用值','needPiece needGold ifOwnAutoConvert convertItemId convertCount baseCoolTime plusCoolTime'),('gameconfig','petMaxConvertDia','宠物满级转钻配置数组;品质映射待查','Values')],
|
||||
'07': [('mountlevel','mount_level_1','坐骑等级1升阶材料字段;原注释exp为坐骑粉末,不直接称角色经验','level exp isOwnEffect'),('mountlevel','mount_level_2','坐骑等级2升阶材料字段','level exp isOwnEffect'),('mountawaken','mount_awaken_RARE_0','稀有觉醒0阶段的碎片、持有效果和技能等级','grade level piece isOwnEffect baseStatus0 value0 passiveSkill1Level')],
|
||||
'08': [('destinystat','attack_power_s','S攻击词条启用、数值与两种权重','isEnabled isPercent addValue normalWeight rareWeight'),('destinystat','aim_s','S命中词条明确停用且两种权重为0','isEnabled addValue normalWeight rareWeight'),('gameconfig','destinySummonNeedCost','命运召唤消费原数组;各项资源尚未映射','Values')],
|
||||
'09': [('collection','collection_001','收藏001的装备组合、级别品质与属性值','equipmentIds equipmentLevels equipmentGrades EMonoStatus value'),('gameconfig','CollectionUnlockStage','收藏开放阶段配置','Values')],
|
||||
'10': [('skin','sword_pumpkin','南瓜剑皮肤:攻击附加值5、套装上限4,1/2/3/4件协同数组按原注释为0/50/100/150;数值缩放待消费者','isEnabled EEquipmentSlot additionalStatus additionalValue maxSetCount setAdditionalValueList')],
|
||||
'11': [('outgametileafkconfig','DefaultConfig','地块包独立挂机:每包分钟数、容量、初始包和里程','afkTime maxPackCount startAddPack probList getMileage needMileage mileageRewardId mileageRewardCount'),('outgametileresearch','101','总升级次数24对应研究1和鞋类武器加级配置','totalUpgradeCount researchLevel weaponPlusLevel EMonoWeapon'),('outgametileresearchstatus','ATTACK_POWER_0_0','研究0的首条攻击属性与消耗','needResearchLevel index EMonoStatus value needCost')],
|
||||
'12': [('afkconfig','DefaultConfig','巡逻分钟、快速巡逻消耗和次数上限;普通倍数使用独立权重','checkTime maxAfkTime quickAfkTime dailyMaxQuickAfkCount quickAfkEnergy dailyMaxQuickAfkAdCount multipleValue multipleWeight')],
|
||||
'13': [('gachatype','shopGacha_1_1','shopGacha单抽:道具101消耗30,存在替代道具204','gachaCount needItemID needCount isAlterBtn alterItemID alterCount'),('gachatype','shopGacha_2_10','shopGacha十连:道具101消耗300;抵扣值并非已确认券消耗数','gachaCount needItemID needCount alterItemID alterCount'),('gachaceildata','advancedEquipmentGacha20','高级装备保底次数及提前命中重置标记','type ceilCount isResetBeforeCeil ceilRewardString'),('gachaceildata','enhancedEquipmentGacha50','增强装备保底次数及提前命中重置标记','type ceilCount isResetBeforeCeil ceilRewardString'),('gachaceildata','mount_00_Gacha50','坐骑保底必须读取ceilCount=400;StringId尾部50不是实际次数','type ceilCount isResetBeforeCeil ceilRewardString')],
|
||||
'14': [('pigbank','pigbank_1','存钱罐档1起止值、胜败增加和购买窗口分钟数','startValue endValue winUpValue loseUpValue purchaseAvailableMinutes cooldownMinutes'),('gameconfig','dailyShopRerollCount','每日商店重掷次数配置','Values')],
|
||||
'15': [('achievement','ingameEquip4Normal','普通装备收集成就:目标4、每局开始重置进度标记True,奖励ITEM 52000×1','conditionType goalCount isPerGameReset rewardType rewardId rewardValue')],
|
||||
'16': [('comebackconfig','DefaultConfig','回归:离线20160分钟(14天),buff4320分钟(3天),加成和次数另列','comebackTime buffTime rewardBuffPercent rewardBuffCount playSpeedBuffCount'),('newbiebuffconfig','DefaultConfig','新人:buff4320分钟,加速50、奖励20;次数-1的哨兵语义未闭合','buffTime additionalSpeed rewardBuffPercent playSpeedBuffCount rewardBuffCount')],
|
||||
'17': [('passdata','normalPass','普通通行证:日任务6、周任务9、挑战3;普通/高级每日游玩经验上限200/400','dailyQuestCount weeklyQuestCount challengeQuestCount playMaxXP primiumPlayMaxXP dailyQuestRerollCount loopClearXP')],
|
||||
'18': [('gameconfig','starChallengeUnlockStage','星级挑战开放阶段配置','Values'),('starchallengereward','0','星数1对应道具101×50;其他奖励ID=-1保留哨兵值','starCount rewardID1 value1 rewardID2 rewardID3')],
|
||||
'19': [('idledungeonconfig','DefaultConfig','探索副本票券每14400秒(4小时)恢复,初始6、上限12;背包30不含已装备物','ticketChargeTime maxTicket startTicket maxInvSize'),('gameconfig','dayOfWeekDungeonUnlockStage','曜日副本解锁阶段配置','Values'),('gameconfig','weekDungeonADRewardPercent','曜日广告奖励百分数配置','Values')],
|
||||
'20': [('infiniteconfig','DefaultConfig','无限入场消耗道具109×5;按难度金币上限100000/150000;每层商店涨价百分数1/2,最终价格小数舍去(原注释)','playAssetId playAssetCount excludeReward maxGold shopIncrease')],
|
||||
'21': [('raidconfig','DefaultConfig','讨伐门票初始2、上限10,每43200秒(12小时)恢复,入场道具155×1','startTicketCount maxTicketCount ticketChargeTime playAssetId playAssetCount'),('gameconfig','raidADRewardPercent','讨伐广告奖励百分数配置','Values')],
|
||||
'22': [('potionbattleconfig','setting2','竞技setting2配置:10张上限、3600秒恢复;限定targetSeason列表','targetSeason searchMmrRange searchRange maxTicketCount ticketChargeTime isRelayProduct'),('rankbasedata','potionBattle','竞技跟随potionBattlePass赛季;重置调整字段=-5,不直接解释为MMR减少5','followingPassId mmrKey resetSeasonAdjustTier')],
|
||||
'23': [('rankingrewarddata','halloween2025Event1-1_rankReward','历史万圣节活动第1名档:道具101×100、100×10000;奖励数组须按位置配对','rankingDataKey minRank maxRank rewardId rewardCount')],
|
||||
'24': [('superballschedule','2026-001-SuperBall','历史超级球赛季1:初始奖励10000、名次比例30/30/40;日期注释为UTC零点,统计时间30分钟','rewardPerParticipant startReward RewardPercent superBallStartDay superBallEndDay countingTime')],
|
||||
'25': [('plinkolevel','level0','Plinko初始球容量15、恢复900秒;level=-1保留原值','maxBallCount chargeSecond adKey level'),('plinkoad','adGoldPin','Plinko广告金钉:每日3次、buff180秒、升级效果数组','maxADPerDay buffSecond values')],
|
||||
'26': [('deoksun','likePoint1','NPC好感1:金币倍率字段1.1、钻石获得概率字段5;缩放及生效时机仍需消费者','likePoint goldUP diaUP slotRarity ingameDiscount'),('deokjashop','attackUpgrade','特殊商店攻击升级:权重30、基础与增量1;maxLevel=-1不自动解释无限','isEnabled probabilityWeight baseAdditionalValue additionalValue maxLevel')]
|
||||
}
|
||||
TABLE_ZH = {'equipment':'永久装备目录','equipmentdata':'装备品质星级与合成','equipmentdefaultstatdata':'装备基础和强化属性','equipmentugradelevel':'装备强化成本','slotupgrade':'槽位逐级成本与增益','bonusstatus':'永久属性上限','relic':'遗物目录','relicdata':'遗物品质合成','pet':'宠物养成参数','petskill':'宠物技能','mount':'坐骑目录','mountlevel':'坐骑逐级材料与增益','mountawaken':'坐骑觉醒','destinystat':'命运候选词条','collection':'收藏组合与收益','outgametile':'地块收集养成','outgametileresearch':'地块研究进度','outgametileresearchstatus':'研究属性与成本','afkconfig':'巡逻参数','afkreward':'巡逻进度奖励','gachatype':'抽卡按钮与成本','gacha':'抽卡奖励权重','gachaceildata':'抽卡保底','shopproductlist':'商品价格与发放','triggerinfo':'商品触发与入口','questdata':'任务条件定义','groupquestlist':'任务组目标与奖励','achievement':'成就条件奖励','attendance':'签到逐日奖励','passrewarddata':'通行证逐级奖励','ranktier':'竞技段位区间','rankingrewarddata':'排行榜名次奖励'}
|
||||
|
||||
catalog=[]; manifest=[]; allrules=[]; allsymbols=[]; dictionary=[]; invalid=[]
|
||||
for t,(headers,types,comments,records) in TABLES.items():
|
||||
disposition='局外模块' if t in owner else ('跨模块共享' if t=='gameconfig' else '局内或展示共享支持表')
|
||||
catalog.append(dict(表=t,模块=owner.get(t,'00-共享配置' if t=='gameconfig' else '99-审计与证据/范围补充'),范围判定=disposition,记录数=len(records),说明='完整保留,含未启用行'))
|
||||
manifest.append(dict(证据ID='E-'+t,源文件=str((SRC/(t+'.csv')).relative_to(ROOT)).replace('\\','/'),SHA256=sha(SRC/(t+'.csv')),记录数=len(records)))
|
||||
ids=Counter(r.get('Id') for _,r in records)
|
||||
invalid += [dict(表=t,问题='重复Id',值=k) for k,v in ids.items() if v>1]
|
||||
for i,h in enumerate(headers):
|
||||
dictionary.append(dict(表=t,字段=h,类型=types[i] if i<len(types) else '',中文含义=FIELD_ZH.get(h,'原字段;结合原注释与模块规则阅读,精确定义未翻译确认'),原始注释=comments[i] if i<len(comments) else '',空值条数=sum(r[h]=='' for _,r in records)))
|
||||
|
||||
def copytable(t, directory):
|
||||
headers,types,comments,records=TABLES[t]
|
||||
raw=directory/'原始表'/(t+'.csv'); raw.parent.mkdir(parents=True,exist_ok=True)
|
||||
shutil.copyfile(SRC/(t+'.csv'),raw)
|
||||
csvwrite(directory/(t+'.csv'),[r for _,r in records],headers)
|
||||
|
||||
write(AUDIT/'scope.md','# 范围\n\nauth:用户要求从已有逆向数据检索所有局外系统规则数值。\nnetwork_profile:offline。\nin_scope:HEROLL_APK_REVERSE_ONLY 的提取CSV、Assembly-CSharp元数据与直接派生商业化表。\nout_of_scope:新项目MVP改造、在线服务器请求、原APK执行、重新原生逆向。\n\n本次“所有”指现有提取表的全量检索与范围分配,不意味着服务端规则或全部方法实现可由静态数据恢复。\n')
|
||||
write(AUDIT/'timeline.md','# 工作记录\n\n2026-09-06:定位原作净化归档,核对局内包结构。\n2026-09-06:全量扫描提取CSV,先输出26模块总纲。\n2026-09-06:逐模块导出设计、规则、全量数据、字段与符号证据。\n2026-09-06:检查原始文件哈希、规范化逐单元格一致性、范围覆盖及文档相对链接。\n')
|
||||
|
||||
for m in MODULES:
|
||||
d=OUT/m['folder']; td=d/'03-表格'; td.mkdir(parents=True,exist_ok=True)
|
||||
rules=[]; summaries=[]; numeric=[]; facts=[]; arrays=[]
|
||||
for t,key,desc,fields in FACTS[m['id']]:
|
||||
matches=[(ri,r) for ri,r in TABLES[t][3] if r['StringId']==key]
|
||||
assert len(matches)==1,(t,key)
|
||||
ri,r=matches[0]
|
||||
vals=';'.join(h+'='+r[h] for h in fields.split())
|
||||
facts.append((desc,vals,f'E-{t} / StringId={key} / CSV记录{ri}'))
|
||||
rules.append(dict(规则ID=f"R-{m['id']}-{len(rules)+1:03}",等级='A',规则=desc+';'+vals,证据='E-'+t,定位=f'StringId={key};CSV记录{ri}',边界='字段原值及原注释;尚未验证运行时消费者'))
|
||||
for t in m['tables']:
|
||||
copytable(t,td)
|
||||
headers,types,comments,records=TABLES[t]
|
||||
rules.append(dict(规则ID=f"R-{m['id']}-{len(rules)+1:03}",等级='A',规则=f'{t} 配置含 {len(records)} 条数据;字段及所有原值见同名表',证据='E-'+t,定位='全表',边界='表存在不证明运行时全部启用'))
|
||||
for i,h in enumerate(headers):
|
||||
typ=types[i] if i<len(types) else ''
|
||||
if typ.endswith('[]'):
|
||||
for ri,r in records:
|
||||
if not r[h]: continue
|
||||
for ai,value in enumerate(r[h].split(',')):
|
||||
arrays.append(dict(表=t,Id=r['Id'],StringId=r['StringId'],字段=h,零基数组索引=ai,原值=value,类型=typ,来源记录=ri,说明='按逗号展开原序列;不是玩家等级,保留空格和哨兵'))
|
||||
if typ not in ('int','float','double','long'): continue
|
||||
vals=[]
|
||||
for _,r in records:
|
||||
try: vals.append(float(r[h]))
|
||||
except ValueError: pass
|
||||
if vals: numeric.append(dict(表=t,字段=h,类型=typ,有效数值数=len(vals),最小值=min(vals),最大值=max(vals),说明='全配置范围,含停用/历史行;不是玩家可达区间'))
|
||||
flags=[h for h in headers if h in ('isEnabled','isUse','IsUse','isEnable')]
|
||||
flagtxt=';'.join(h+'='+str(dict(Counter(r[h] for _,r in records))) for h in flags) or '无统一启用字段'
|
||||
examplekeys=[h for h in headers if h not in ('Id','StringId') and not re.search(r'icon|prefab|title|desc|animation|sound|feedback|text|color',h,re.I)]
|
||||
samples=[]
|
||||
for ri,r in records[:3]:
|
||||
samples.append((r['Id'],r.get('StringId',''),'; '.join(h+'='+r[h] for h in examplekeys[:10]),'E-'+t+f' / CSV记录{ri}'))
|
||||
summaries.append(f"### {TABLE_ZH.get(t,t)}({t})\n\n数据条数:{len(records)};{flagtxt}。完整数据:[标准CSV](./03-表格/{t}.csv);[原始表](./03-表格/原始表/{t}.csv)。\n\n"+table(['Id','StringId','配置原值示例(非完整字段)','来源'],samples))
|
||||
config=[dict(证据='E-gameconfig',记录序号=ri,**r) for ri,r in gconfig if re.search(GROUTES[m['id']],r['StringId'],re.I)]
|
||||
csvwrite(td/'关联全局配置.csv',config,['证据','记录序号','Id','StringId','Values'])
|
||||
symbols=[]
|
||||
terms=m['terms'].split(',')
|
||||
for ty in metadata['types']:
|
||||
if not any(term.lower() in ty['name'].lower() for term in terms): continue
|
||||
for kind in ['fields','methods']:
|
||||
for member in ty.get(kind) or []:
|
||||
symbols.append(dict(类型索引=ty['index'],命名空间=ty.get('namespace',''),类型=ty['name'],成员类别=kind,成员索引=member['index'],成员=member['name'],证据='E-metadata',说明='名称检索命中,仅结构证据;非原生实现'))
|
||||
csvwrite(td/'元数据符号.csv',symbols,['类型索引','命名空间','类型','成员类别','成员索引','成员','证据','说明'])
|
||||
allsymbols += [dict(模块=m['folder'],**s) for s in symbols]
|
||||
csvwrite(td/'字段字典.csv',[r for r in dictionary if r['表'] in m['tables']])
|
||||
csvwrite(td/'数值范围.csv',numeric,['表','字段','类型','有效数值数','最小值','最大值','说明'])
|
||||
csvwrite(td/'规则证据.csv',rules)
|
||||
csvwrite(td/'数组逐项明细.csv',arrays,['表','Id','StringId','字段','零基数组索引','原值','类型','来源记录','说明'])
|
||||
allrules += [dict(模块=m['folder'],**r) for r in rules]
|
||||
design=f"# {m['id']} {m['name']}:原作模块设计\n\n## 功能定位\n\n{m['role']}\n\n## 功能流程\n\n{FLOWS[m['id']]}。\n\n以上按原作配置关系整理功能步骤,具体条件与数值见下文及规则说明。\n\n## 功能构成与规则关系\n\n{m['flow']}\n\n"
|
||||
if facts: design+='## 关键规则与数值\n\n'+table(['原作规则','数值','来源'],facts)+'\n'
|
||||
design+='## 完整数值表\n\n'+table(['配置表','记录数','完整数据'],[(t,len(TABLES[t][3]),f'[CSV](./03-表格/{t}.csv)') for t in m['tables']])
|
||||
design+=f"\n[规则说明](./02-规则说明.md) · [字段字典](./03-表格/字段字典.csv) · [数组逐项明细](./03-表格/数组逐项明细.csv)\n\n[返回总纲](../00-局外系统模块总纲.md)\n"
|
||||
write(d/'01-模块设计文档.md',design)
|
||||
rule=f"# {m['id']} {m['name']}:规则与数值\n\n## 已恢复的配置关系\n\n{m['flow']}\n\n证据等级A仅确认字段原值;下列示例不是全量表,所有等级、成本、奖励、参数见所链接CSV。\n\n"
|
||||
if facts: rule+='## 核心规则核对\n\n'+table(['规则解读','源字段原值','证据定位'],facts)+'\n'
|
||||
rule+='## 表级规则及原值\n\n'+'\n'.join(summaries)
|
||||
rule+='\n## 关联全局配置\n\n'
|
||||
rule+=table(['键','原值','CSV记录序号'],[(r['StringId'],r['Values'],r['记录序号']) for r in config]) if config else '未按本模块关键字命中gameconfig;不代表没有硬编码参数。\n'
|
||||
rule+=f"\n[完整全局配置](../00-共享配置/gameconfig.csv) · [规则来源](./03-表格/规则证据.csv) · [原作符号索引](./03-表格/元数据符号.csv)\n\n## 尚待补充的原作细节\n\n{m['unknown']}\n"
|
||||
write(d/'02-规则说明.md',rule)
|
||||
write(d/'README.md',f"# {m['folder']}\n\n{m['role']}\n\n[模块设计](./01-模块设计文档.md) · [规则说明](./02-规则说明.md) · [字段字典](./03-表格/字段字典.csv)\n")
|
||||
|
||||
# 未分入局外主模块的表仍完整保留,并给出明确范围,防止检索遗漏。
|
||||
for t in TABLES:
|
||||
if t not in owner:
|
||||
copytable(t,OUT/'00-共享配置' if t=='gameconfig' else AUDIT/'范围补充')
|
||||
csvwrite(OUT/'00-共享配置/字段字典.csv',[r for r in dictionary if r['表']=='gameconfig'])
|
||||
csvwrite(AUDIT/'全表范围清单.csv',catalog)
|
||||
manifest.append(dict(证据ID='E-metadata',源文件=str((CORE/'metadata/assembly-csharp.json').relative_to(ROOT)).replace('\\','/'),SHA256=sha(CORE/'metadata/assembly-csharp.json'),记录数=len(metadata['types'])))
|
||||
csvwrite(AUDIT/'源文件清单.csv',manifest)
|
||||
csvwrite(AUDIT/'规则索引.csv',allrules)
|
||||
csvwrite(AUDIT/'字段总字典.csv',dictionary)
|
||||
csvwrite(AUDIT/'数据异常.csv',invalid,['表','问题','值'])
|
||||
csvwrite(AUDIT/'未闭合规则.csv',[dict(模块=m['folder'],等级='U',问题=m['unknown'],下一步='定位元数据对应原生消费者,或用原版实机记录操作前后状态') for m in MODULES])
|
||||
|
||||
# 按池计算条件概率,明确不是运行时真实概率。
|
||||
pool=defaultdict(list)
|
||||
for ri,r in TABLES['gacha'][3]: pool[r['type']].append((ri,r))
|
||||
probabilities=[]
|
||||
for key, rows in pool.items():
|
||||
total=sum(float(r['prob']) for _,r in rows)
|
||||
for ri,r in rows:
|
||||
probabilities.append(dict(池=key,Id=r['Id'],StringId=r['StringId'],权重=r['prob'],池权重和=total,配置归一化百分比=float(r['prob'])/total*100 if total else '',奖励类型=r['rewardType'],奖励ID=r['rewardID'],奖励数量=r['rewardCount'],等级='C',前提='同type所有行均参与且按prob线性加权;未计保底和运行时过滤',证据=f'E-gacha/CSV记录{ri}'))
|
||||
csvwrite(OUT/'13-抽卡与保底/03-表格/条件概率推导.csv',probabilities)
|
||||
|
||||
# 显式Id引用的可核验映射,只解析明确道具字段;奖励类型ID不一概当道具。
|
||||
items={r['Id']:r for _,r in TABLES['item'][3]}
|
||||
refs=[]
|
||||
for t in owner:
|
||||
for ri,r in TABLES[t][3]:
|
||||
for h in ('needItemID','alterItemID','convertItemId','refundItemId','exchangeItemId','playAssetId','useItemId'):
|
||||
if h not in r or not r[h]: continue
|
||||
target=items.get(r[h])
|
||||
refs.append(dict(表=t,Id=r['Id'],字段=h,值=r[h],道具StringId=target['StringId'] if target else '',匹配='item.Id匹配' if target else '未匹配;可能为枚举/占位/跨类型ID,需查消费者',来源记录=ri))
|
||||
csvwrite(AUDIT/'消耗道具关联.csv',refs)
|
||||
|
||||
from organize_module_docs import organize
|
||||
document_counts = organize(globals())
|
||||
|
||||
# 验证:全量原表字节哈希、规范表逐单元格、文档相对链接。
|
||||
checks=[]
|
||||
for t in TABLES:
|
||||
d=(OUT/owner[t]/'03-表格') if t in owner else (OUT/'00-共享配置' if t=='gameconfig' else AUDIT/'范围补充')
|
||||
assert sha(SRC/(t+'.csv'))==sha(d/'原始表'/(t+'.csv')),t
|
||||
with (d/(t+'.csv')).open(encoding='utf-8-sig',newline='') as f: got=list(csv.DictReader(f))
|
||||
assert got==[r for _,r in TABLES[t][3]],t
|
||||
checks.append('全部源CSV哈希与原始副本一致;全部规范化CSV逐单元格一致')
|
||||
for p in OUT.rglob('*.md'):
|
||||
for link in re.findall(r'\]\(([^)]+)\)',p.read_text(encoding='utf-8')):
|
||||
if link.startswith(('http','#')): continue
|
||||
target=(p.parent/link.split('#')[0])
|
||||
if target.name=='2026-09-06_逆向-HEROLL局外系统-report.md': continue # 下方统计汇总后生成
|
||||
assert target.exists(),(p,link)
|
||||
checks.append('Markdown相对链接全部可解析')
|
||||
summary=dict(模块数=len(MODULES),源表数=len(TABLES),局外主模块表数=len(owner),共享和补充表数=len(TABLES)-len(owner),全表数据行数=sum(len(v[3]) for v in TABLES.values()),局外主模块数据行数=sum(len(TABLES[t][3]) for t in owner),字段数=len(dictionary),元数据命中记录数=len(allsymbols),抽卡配置池数=len(pool),重复主键问题数=len(invalid),验证=checks)
|
||||
summary.update(document_counts)
|
||||
write(AUDIT/'验证结果.json',json.dumps(summary,ensure_ascii=False,indent=2))
|
||||
write(AUDIT/'2026-09-06_逆向-HEROLL局外系统-report.md','# HEROLL局外系统检索与验证报告\n\n## 范围和结果\n\n见[scope](./scope.md)和[timeline](./timeline.md)。原版HEROLL 2.0.1配置与元数据归档已分为26模块。\n\n'+table(['指标','结果'],[(k,v) for k,v in summary.items() if k!='验证'])+'\n## Evidence → Finding → Path\n\nEvidence:E-表名对应[源文件SHA256清单](./源文件清单.csv),E-metadata为Assembly-CSharp元数据。\n\nFinding:[规则索引](./规则索引.csv)记录模块配置事实,等级A;元数据名称为B;抽卡条件归一化为C;执行缺口列入[未闭合规则](./未闭合规则.csv),等级U,severity=n/a_re。状态:配置与结构整理完成,原生/动态规则未闭合。\n\nPath P-001(solve/资料复现):原始CSV → 识别Id/StringId表头 → 排除注释和类型记录 → 保留所有数据行与空值 → 模块映射 → 文档和CSV → 哈希及逐单元格校验。\n\n## 验证\n\n'+'\n'.join('- '+x for x in checks)+'\n\n## 复现\n\n在项目根目录用Python 3执行 `HEROLL_OUTGAME_2.0.1/99-审计与证据/工具/build_outgame.py`。仅需标准库,重建本包,不改动源归档。生成器会覆盖本包中的同名自动生成文件。\n\n## 限制\n\n没有读取原生方法实现、没有动态运行或服务器访问;不能据此声称所有局外运行规则已经还原。源数据韩文注释原样保留;未明确翻译的字段直接标明未知。表中排期、价格和开关只代表包内快照。\n\n## 工作流自检\n\n- Triage:核对原作净化归档、表目录与局内结构。\n- Static:完成所有CSV扫描与元数据名称检索。\n- Dynamic:本次已有数据检索范围不执行;缺口保持U,不冒称验证。\n- Synthesis:设计、规则、完整表、证据、复现与校验已输出。\n- 工具:使用本机PowerShell、rg和已发现的捆绑Python;技能tool-index.md缺失,未依赖虚构工具路径。\n')
|
||||
print(json.dumps(summary,ensure_ascii=False,indent=2))
|
||||
|
||||
# 报告写完后重新核验所有链接,不豁免任何目标。
|
||||
for p in OUT.rglob('*.md'):
|
||||
for link in re.findall(r'\]\(([^)]+)\)',p.read_text(encoding='utf-8')):
|
||||
if not link.startswith(('http','#')):
|
||||
assert (p.parent/link.split('#')[0]).exists(),(p,link)
|
||||
files=[dict(文件=str(p.relative_to(OUT)).replace('\\','/'),字节数=p.stat().st_size,SHA256=sha(p)) for p in sorted(OUT.rglob('*')) if p.is_file() and p.name!='文件索引.csv']
|
||||
csvwrite(OUT/'文件索引.csv',files)
|
||||
@@ -0,0 +1,317 @@
|
||||
"""原作模块文档编排;由build_outgame.py传入已校验的原表数据。"""
|
||||
import re
|
||||
|
||||
# 每张原表对应一个可阅读的子功能,描述只采用原表字段可支持的关系。
|
||||
NOTES = '''tutorial|新手引导步骤|引导类型和漏斗标识区分步骤;等待时长、遮罩和触摸推进字段描述交互,unlockContentKey记录该步关联的功能开放键。
|
||||
newbieguide|引导目标与奖励|clearStage区分进度条件,moveTab/customTab/moveOpenView描述跳转目标,rewardID/rewardCount记录奖励。
|
||||
modesortingorder|模式入口排序|按bannerName识别模式入口,以sortingOrder配置显示顺序。
|
||||
localpush|通知内容|MailType和MailValue区分通知场景,TitleKeys/TextKeys保存可选标题及正文文本键。
|
||||
communitydata|社区入口|以language区分语言版本,标题、图标与url共同描述社区入口。
|
||||
permanentkeyremoveschedule|持久标记清理排期|removeDate给出计划日期,targetKeyList列出此次清理涉及的持久标记。
|
||||
item|道具与资源定义|每种道具以Id/StringId识别。ERewardType和refStringId说明内容类型与引用;isStackable、selectCount和useRandom分别描述堆叠、选择数量及随机使用标记。
|
||||
itemgroup|道具包内容|itemIds、itemCounts和weights按位置记录道具、数量与权重;sameItem作为独立配置保留,不能省略权重为0的项。
|
||||
itemsource|资源获取途径|itemID/itemGroup指向目标资源,跳转字段和unlockKey描述获取入口与开放条件。
|
||||
lobbyticket|局外资源带入映射|ELobbyAsset与EAsset构成大厅资源到使用资源的映射,defaultValue与boostValue是两种效果档。
|
||||
outgamereward|局外事件奖励|when区分触发场景,itemID、itemCount和prob保存奖励候选及对应数量、概率参数。
|
||||
equipment|装备身份与槽位|slotNum决定装备槽位,equipType/tagType描述类型与标签,baseStatus和skill/skillValue/extraValue描述属性与技能。isSpecial和isMaterial分别标识特殊装备及材料。
|
||||
equipmentdata|品质星级与合成要求|level是品质星级阶段索引,与强化等级分开。各阶段由grade/starCount标识,maxUpgradeLevel规定强化上限;合成要求分指定材料等级数量和同品质任意装备数量两类字段。
|
||||
equipmentdefaultstatdata|装备基础与强化属性|按level和baseStatus读取基础值及强化增量;specialBaseValue/specialUpgradeValue单列特殊装备数值,不与普通值混用。
|
||||
equipmentugradelevel|装备逐级强化消耗|每个level分别给出needMaterial和needGold。135行逐级成本全部保留,累计成本需先明确起止等级与消费行的对应关系。
|
||||
equipmenttype|装备类型修正|每种类型记录slotNum及两组correctionStatus/correctionValue,用于区分该类型的属性修正配置。
|
||||
equipskill|装备技能类型|EEquipSkill是技能枚举,skillDesc和feedbackDesKey是描述引用。具体效果参数需与装备目录中的技能字段共同阅读。
|
||||
mainequipmentscore|主装备评分档|按level配置score;这里只给出评分档,不把score当作最终战力公式。
|
||||
slotupgrade|槽位升级|同一slotNum下按level排列。原注释明确needCount描述到下一级的需求,needItemID和needGold列出资源;specialKey/specialValue与upgradeValue分别保存特殊和常规效果。
|
||||
slotupgradekey|槽位特殊属性|status与mainStatSlot描述属性和主属性槽的对应关系,文字及图标字段负责效果展示。
|
||||
bonusstatus|永久属性成长|每项EMonoStatus独立配置isPercent、upgradeValue和maxLevel,不同属性不能共用同一个升级增量。
|
||||
relic|遗物属性与技能|slotNum标识槽位,baseStatus/statusValue/isPercent配置属性,skill/skillValue/extraValue配置技能;isMaterial区分材料条目。
|
||||
relicdata|遗物品质星级与合成|grade/starCount/level构成成长档,材料需求分materialLevel/materialCount与sameGradeAnyRelicCount。原注释限制带星级材料的使用。
|
||||
pet|宠物解锁与成长|品质、启用与重复转化字段描述获取状态;needPiece和needGold分别保存成长消耗数组,冷却、伤害及附加属性各有基础与增量字段。needPiece首项在原注释中标为未使用。
|
||||
petskill|宠物等级技能|petId关联宠物,isUse与skillUnlockLevel描述启用和开放等级;EPetSkill与skillValue/subValues/extraValues共同定义技能参数。
|
||||
petgrowthdata|宠物成长活动入口|petId标识目标宠物,useItemId/useItemCount描述活动消费,seasonStartDay/seasonDay/seasonEndDay保留活动时间配置。
|
||||
petgrowthevent|宠物成长事件|eventId/eventKey组织事件,类型、权重、品质和事件参数构成候选;选择结果文本、选择概率及奖励经验分别配置。
|
||||
petgrowthlevel|宠物成长等级奖励|按eventKey/level记录needXp、repeatMaxCount和奖励,不同成长活动不合并经验需求。
|
||||
mount|坐骑解锁与基础属性|unlockPiece、unlockDia和unlockProductId记录解锁相关成本;refundItemId/refundItemCount记录溢出返还;基础和成长属性与passiveSkill单列。
|
||||
mountlevel|坐骑升级材料与收益|level区分成长档,exp原注释指坐骑粉末;isOwnEffect区分持有效果,四个品质值字段按品质读取。
|
||||
mountawaken|坐骑觉醒|按grade/level配置piece,isOwnEffect区分效果类别;两组属性及三个被动技能等级描述本档效果。
|
||||
mountskilldesc|坐骑技能等级描述|group和level组织技能文案,value0/value1/value2保存描述使用的等级参数。
|
||||
mountskilleffectgroup|坐骑技能触发与叠加|group及等级范围标识技能,activeEvent/activeEventValue记录触发条件,skillEffect/target及技能参数记录效果,duration/prob/stackLimit分别描述持续、概率与层数上限。
|
||||
mounteventcount|坐骑活动累计奖励|season/index定位奖励档,needCount是累计数量需求,rewardId/rewardCount为对应奖励。
|
||||
mounteventseasonitem|坐骑活动材料回收|seasonStringId区分赛季,两套资源文字和图标分别对应抽取与兑换资源;两个ExchangeGoldValue字段保存兑换金币值。
|
||||
destinystat|命运词条候选|每行记录启用、品质、属性或特殊效果及addValue。normalWeight与rareWeight是分开的权重组,不能相加后当作唯一池。
|
||||
collection|收藏组合条件|equipmentIds、equipmentLevels和equipmentGrades共同描述组合要求,EMonoStatus/value给出收益。并列数组保留原顺序。
|
||||
skin|皮肤及套装加成|EEquipmentSlot区分外观槽位,additionalStatus/additionalValue描述单件属性;套装名、maxSetCount及setAdditionalValueList描述协同配置。
|
||||
profile|头像|type与unlockKey记录类别和开放键,isEnabled及order记录启用和展示顺序。
|
||||
profileframe|头像框|unlockKey关联解锁标记,frameName定位展示资源,isEnabled/order分别控制配置启用和展示顺序。
|
||||
prefixtitle|称号前缀|order、titleKey、colorHex记录称号的展示顺序、文案与颜色。
|
||||
outgametile|地块收集与养成|refNewTileId连接局内地块;grade、needPiece和unlockStage描述获取成长条件;defaultEquip与skillUnlockLevel/ETileSkill描述默认装备及技能开放。
|
||||
outgametileskill|地块技能|refNewTileId标识作用地块,ETileSkill/skillValue配置技能类型及数值,标题和描述键用于展示。
|
||||
outgametileresearch|地块研究阶段|totalUpgradeCount对应researchLevel,weaponPlusLevel与EMonoWeapon保存该研究阶段的武器成长配置。
|
||||
outgametileresearchexp|地块成长研究收益|按EMonoTileGrade和level区分reward;与研究阶段表分开保存,不能把reward直接当researchLevel。
|
||||
outgametileresearchstatus|研究属性节点|needResearchLevel是研究阶段要求,index是节点序号,EMonoStatus/value与needCost给出收益及消耗。
|
||||
outgametileafkconfig|地块包挂机与里程|afkTime按分钟定义每包时间,maxPackCount为累计容量,startAddPack为初始包;包列表、权重与里程数组分开配置,needMileage与里程奖励描述累计奖励档。
|
||||
afkconfig|巡逻计时与快速巡逻|checkTime、maxAfkTime和quickAfkTime单位为分钟。普通巡逻倍数权重、快速巡逻体力次数与广告次数分别配置。
|
||||
afkreward|巡逻进度奖励|lastClearStage区分奖励档,goldPerHour给金币产率;其他奖励由rewards、amountPerCheckTime、maxAmount和dropPercent描述。
|
||||
gachatype|抽卡操作与成本|按type/buttonNum区分按钮,gachaCount为抽数;isFree/isAD与ADcooldown描述免费广告档,needItemID/needCount与替代资源字段描述消费。
|
||||
gacha|抽卡候选奖励|同type下记录候选奖励、品质、权重、特殊标记和数量;rewardType必须与rewardID一起解释,-1按原注释指特定类型中的全池。
|
||||
gachaceildata|抽卡保底|type关联抽卡池,ceilCount是保底次数,isResetBeforeCeil标记提前获得时的重置配置,ceilRewardString明确对应奖励行。
|
||||
shopproductlist|商品与持续发放|价格、消费类型、购买次数、重置周期和平台商品标识分开保存;ItemId/ItemValue是商品内容,dailyItemId/dailyItemValue/dailyObtainDay描述每日发放内容。
|
||||
dailyshoplist|每日商店候选与售价|Prob是候选权重参数,ItemID/ItemValue描述内容,ECostType/buyPrice描述消费,Sale保存折扣标记或值。
|
||||
relaypackagedata|接力礼包顺序|relayPackageId分组,order定义档位顺序;isFree与freeItemId/freeItemCount区分免费档,productKey连接商品。
|
||||
d3package|分组礼包内容|groupKey/index组织礼包档,各组itemID0至2与itemCount0至2记录礼包内的三组奖励位置。
|
||||
pigbank|存钱罐|每档有startValue/endValue以及winUpValue/loseUpValue;purchaseAvailableMinutes和cooldownMinutes分别给出购买窗口与冷却分钟数。
|
||||
dailypurchasereward|购买积分奖励|needPoint为积分门槛,rewardID/rewardCount给对应档奖励。
|
||||
groupbmshop|活动商品分组|ERefType/groupKey/targetStringId表示分组引用,shopProductStringId连接具体商品。
|
||||
groupexchangeshop|分组兑换|ECoolTimeType/exchangeCount描述次数配置,exchangeItemId/exchangeItemCount与rewardId/rewardCount分别描述兑换投入和产出。
|
||||
promotioninfo|促销入口排期|起止时间和clearStage描述展示条件,位置及排序控制入口布局,跳转字段描述目标功能。
|
||||
triggerinfo|商品触发条件|TriggerType、GoalString/GoalValue等字段保存触发条件;起止时间、持续时间、重开次数和重开间隔分别配置,ProductKey连接商品,IsUse标记配置使用。
|
||||
interstitialexeptionregion|插屏展示例外配置|showDay与exeptionRegions记录展示日序和区域例外原值,原字段拼写保留。
|
||||
questdata|任务条件定义|questType/questKey定义事件类型,useSubValue/subValue细化目标;ERewardType和跳转字段保留任务对象与前往入口的信息。
|
||||
groupquestlist|任务组目标与奖励|groupKey组织任务,questDataStringId连接条件定义;goalCount设目标,isCanCountWhenLock保留锁定时计数标记,领取类型及奖励独立配置。
|
||||
achievement|成就链|prerequisiteId是前置成就;原注释说明前置未完成时不显示。goalCount为目标,isPerGameReset指每次局内开始重置进度,isHidden与奖励字段分别记录隐藏和收益。
|
||||
attendance|逐日签到与补签|EAttendanceType和day确定签到档;EAttendanceRecovery/price是补签相关配置,itemId/itemCount为当日奖励。
|
||||
attendanceconfig|签到排期|EAttendanceType与签到表关联,普通排期和prod排期字段分开保存,eventDay记录活动天数。
|
||||
comebackconfig|回归资格与福利|comebackTime为距上次登录的分钟门槛,buffTime为加成分钟数;奖励加成与玩法加速分别有次数字段,questKey连接回归任务。
|
||||
newbiebuffconfig|新人加速与奖励|buffTime按分钟记录持续时长,additionalSpeed/rewardBuffPercent记录额外加速及奖励百分数,两类使用次数分开记录。
|
||||
passdata|通行证经验规则|passID区分通行证,日周挑战任务数、每日经验、普通高级游玩经验上限、重掷次数与每层经验分别配置。
|
||||
passquestlist|通行证任务|usePassID连接通行证,questDataStringId连接条件;goalCount、unlockDay、xpCount与奖励字段描述目标、开放和收益。
|
||||
passrewarddata|通行证等级奖励|passID、season和level标识奖励档,needXP与repeatCount记录经验和重复配置;普通、高级、高级Plus各保留完整奖励ID、数量和键。
|
||||
passseasondata|通行证赛季与关联活动|clearStage、赛季起止、游玩结束与购买阻止时间记录不同阶段;商品、兑换、任务、抽卡及排行引用连接赛季内容。
|
||||
stageinfo|关卡入口及模式|stage/EPlayMode/isEnabled定义关卡目录,标题、场景和Boss字段描述关卡内容;局内衔接字段完整保留。
|
||||
stagerewardinfo|关卡结算奖励|EPlayMode、stage、loop、diceGauge与isClear共同区分奖励条件,rewardID/rewardCount给出奖励。
|
||||
loopreward|层数奖励|Type和Loop定位奖励档,itemID/itemCount记录收益,isSack是独立奖励标记。
|
||||
starchallenge|星级挑战条件参数|challengeText连接挑战描述,value是条件参数;没有正文时不根据数值猜测挑战语义。
|
||||
starchallengereward|星数奖励档|starCount定位累计星数档,三组rewardID/value保留对应奖励,-1奖励ID作为原始哨兵保存。
|
||||
dayoftheweekdungeon|曜日副本奖励|day与difficulty共同确定奖励档,对应itemId/itemCount。
|
||||
dayoftheweekdungeonconfig|曜日副本难度推荐|difficultyPreferStage保存难度与推荐进度的配置数组。
|
||||
weekdungeonboard|曜日副本层数属性|按EDayOfWeekDifficulty和loop组织怪物组及战斗属性,为入口难度与奖励提供对应玩法配置。
|
||||
idledungeon|探索区域内容|graphID定位区域,宝藏数量和百分数、敌群数量及战斗属性共同描述探索内容。
|
||||
idledungeonconfig|探索门票与背包|ticketChargeTime原注释为秒,maxTicket/startTicket是门票上限和初始量,maxInvSize是不含已装备物的背包容量。
|
||||
idledungeondrop|探索掉落权重|currentDropItemCount区分已掉落数量档,各品质及失败权重数组独立保存,不直接相加推定掉落保护算法。
|
||||
idledungeonequipmentsalvage|探索装备分解|level下每种品质单列回收奖励ID和数量,salvage字段与salvage_count字段按品质配对。
|
||||
idledungeonequipmentstatus|探索装备等级属性|按level/type读取不同品质的value,不与永久装备的属性表混用。
|
||||
idledungeonplayerdefaultstat|探索角色基础属性|EMonoStatus对应value,形成此模式单独的角色基础数值。
|
||||
idledungeonstageinfo|探索章节与奖励|stage/chapter及stageConcept组织章节,rewardId/rewardCount描述对应奖励。
|
||||
infiniteconfig|无限入场与收益限制|playAssetId/playAssetCount是入场消耗,excludeReward排除指定奖励,maxGold按难度配置;shopIncrease原注释为每层商店价格增加百分数,最终价格舍去小数。
|
||||
infiniteseason|无限赛季Boss|season标识赛季,bossObj/bossID/bossProfile描述Boss与展示。
|
||||
infiniteboard|无限难度层数属性|EInfinityDifficulty和loop区分配置,怪物组与属性随难度层数分别保存。
|
||||
infinitemodefevertiles|无限特殊地块权重|ETileEvent标识地块事件,isEnabled控制配置启用,weight保存候选权重。
|
||||
raidconfig|讨伐门票与入场|初始票、票上限和恢复秒数分开配置,playAssetId/playAssetCount描述每次入场投入,targetSeason指定适用赛季。
|
||||
raidtier|讨伐档位展示|visualText与两个图标字段描述档位展示,对应奖励表的tierId。
|
||||
raidreward|讨伐分数段奖励|tierId和season区分档位赛季,minScore/maxScore是分数段,rewardId/rewardCount为对应收益。
|
||||
raidhighscorereward|讨伐最高分奖励|以tierId/season/highScore定位最高分目标,与普通分数段奖励分别保留。
|
||||
raidseasonpetlist|讨伐赛季试用阵容|season、deckIndex、petId和trialLevel描述每套阵容的宠物及试用等级。
|
||||
raidseasonpreset|讨伐赛季预设|season区分预设,bonus和overrideAugmentIdList保存增益及覆盖的强化项,presetTitleKey为名称引用。
|
||||
raidboard|讨伐击杀计分与属性|bossKillCount对应killScore及后续战斗属性配置。
|
||||
raidaugmentoverride|讨伐强化覆盖|itemType/itemID/fixedKey标识覆盖对象,count、overrideValue及overrideExtraValue记录替换参数。
|
||||
battlepotion|竞技药水成长|重量、冷却、主效果和额外效果各有基础与增量字段;needPiece和needCost保留升级投入,isBuff/isPercent区分效果类别和数值标记。
|
||||
battleplayerdefaultstat|竞技角色基础属性|以EMonoStatus读取value,形成竞技模式独立基础属性。
|
||||
potionbattleconfig|竞技赛季与门票|targetSeason决定适用赛季,searchMmrRange/searchRange记录匹配范围参数,门票上限、恢复秒数及商品顺序另列。
|
||||
potionbattlebonus|竞技加成条件|EPotionBattleBonus/value描述效果,mmrBonus、disapplyTier和bonusKey保存关联条件,isPercent标记百分比属性。
|
||||
potionbattlebonuskey|竞技加成名称|StringId连接加成键,titleKey为展示名称引用。
|
||||
rankbasedata|段位赛季关联|gameMode与followingPassId关联模式及通行证,mmrKey选择评分键,resetSeasonAdjustTier保存赛季调整量。
|
||||
rankmmradjust|竞技积分修正参数|cpGap及关联键描述战力差档,baseWinMMR/baseLoseMMR给基础变化,gapCorrection/extraCorrection/finalCorrection是分开的修正字段。
|
||||
ranktier|段位阶梯与奖励|gameMode和tier定位段位,minMMR/maxMMR/stepMMR配置评分档,properCp、stepPassXP保存对应战力与通行证经验参数。
|
||||
rankingdata|排行榜赛季配置|isSeasonRanking/isAutoSeason描述周期类型,不同环境下的赛季、分组天数和键分别记录。
|
||||
rankingreferencedata|玩法与排行榜关联|RankKey连接排行,ERefType/referenceKey描述来源玩法或活动引用。
|
||||
rankingrewarddata|名次区间奖励|rankingDataKey定位榜单,minRank/maxRank确定名次范围,rewardId/rewardCount数组按位置记录奖励。
|
||||
seasonevent|活动开放与兑换期|活动起止和兑换结束分开配置;签到类型、转盘键、商品组、兑换组和小游戏键连接具体内容,firstRewardId/firstRewardCount给初次奖励。
|
||||
seasoneventroulette|活动转盘候选|seasonEventStringId关联活动,reward/rewardValues描述奖励,tier/weight保存档位与权重。
|
||||
seasonquestlist|活动任务|活动键和questDataStringId分别关联活动及条件,unlockDay、goalCount、relativePassID、xpAmount及奖励描述开放目标与收益。
|
||||
superballschedule|超级球排期与奖池|按赛季及group区分活动,起止日期原注释使用UTC零点,countingTime为统计分钟数;初始奖池、参与人数增量范围和名次分配比例分别配置。
|
||||
seasoneventminigamedata|小游戏资源与活动入口|gamePackIndex定位玩法包,初始资源、游玩资源和消费量分别记录;兑换资源、排行榜及商品兑换组连接活动外围。
|
||||
bubbleshooterminigame|泡泡小游戏关卡模板|templateKey分组,isUse标记模板使用,rowOrder与bubbles描述关卡行序和布局。
|
||||
cardunpackingeventgame|拆卡包成本与奖励|packIndex区分包档,cost记录消耗,spriteTier描述展示档,rewardCount/prob保存奖励数量和概率参数。
|
||||
clawcraneminigame|抓娃娃奖励配置|goodProb/Prob保存概率参数,capsuleTier和grade区分胶囊品质,rewardType/rewardValue记录奖励,minSize/maxSize保留尺寸范围。
|
||||
dicebeteventgame|骰子投注档|setNumber、rewardCount和gap记录每档骰子目标、收益数量和间隔参数,胜负语义不从字段名补造。
|
||||
dicemachine|骰子机器奖励组合|diceValues定义骰子组合,itemKey与rewardKey/rewardValue关联资源和奖励,value保存附加配置。
|
||||
herobodyminigame|拼形小游戏模板|shapeName、ColumnSort和shapeRow记录形状及列行布局,imageName为图形资源引用。
|
||||
plinko|弹珠落点奖励|ratio保存奖励权重参数,itemID/itemCount记录落点收益。
|
||||
plinkoad|弹珠广告增益|maxADPerDay和buffSecond记录每日次数与持续秒数,values数组描述该增益不同档参数。
|
||||
plinkolevel|弹珠容量与恢复|maxBallCount和chargeSecond记录球容量与恢复秒数,adKey连接广告增益,level保存原等级索引。
|
||||
roulettedata|通用转盘奖励池|rouletteKey分组,itemID/itemCount给奖励,tier和weight描述档位及候选权重。
|
||||
spitoeventdailyreward|刮奖活动日奖励|day定义奖励日序,rewardID/rewardCount给对应道具及数量。
|
||||
spitoeventreward|刮奖候选奖励|itemIDList与itemCountList为并列奖励数组,percent为概率字段原值。
|
||||
deoksun|NPC好感档|likePoint定位档位,slotRarity记录槽位品质配置,goldUP/diaUP分别记录金币收益与钻石获得概率字段,对话、服饰及折扣随档保存。
|
||||
deoksunattendance|NPC签到轮次|groupKey/round及startDay/day组织签到轮次与日序,itemID/itemCount为奖励。
|
||||
deokjashop|特殊养成商店|每项保存启用、品质、权重、基础增益、成长增量和等级上限;两个金币字段原注释标为不使用,不能据其推定售价。
|
||||
'''
|
||||
|
||||
def organize(ctx):
|
||||
out, modules, tables = ctx['OUT'], ctx['MODULES'], ctx['TABLES']
|
||||
write, mdtable, csvwrite = ctx['write'], ctx['table'], ctx['csvwrite']
|
||||
notes={line.split('|')[0]:line.split('|')[1:] for line in NOTES.strip().splitlines()}
|
||||
assert set(notes)==set(ctx['owner']), (set(ctx['owner'])-set(notes),set(notes)-set(ctx['owner']))
|
||||
zh=dict(ctx['FIELD_ZH'])
|
||||
zh.update(dict(x.split('=',1) for x in '''order=展示顺序
|
||||
index=档位或节点序号
|
||||
baseStatus=基础属性类型
|
||||
skill=技能引用
|
||||
skillValue=技能数值
|
||||
extraValue=额外参数
|
||||
slotNum=槽位编号
|
||||
type=类型或分组
|
||||
groupKey=分组键
|
||||
petId=宠物ID
|
||||
level=等级或阶段索引
|
||||
exp=成长消耗字段
|
||||
needXp=所需经验
|
||||
rewardXp=奖励经验
|
||||
repeatMaxCount=重复次数上限
|
||||
targetSeason=适用赛季
|
||||
itemCounts=道具数量数组
|
||||
itemIds=道具ID数组
|
||||
rewardID1=奖励1道具ID
|
||||
rewardID2=奖励2道具ID
|
||||
rewardID3=奖励3道具ID
|
||||
value1=参数1
|
||||
value2=参数2
|
||||
value3=参数3
|
||||
ItemId=商品道具ID
|
||||
ItemValue=商品道具数量
|
||||
buyPrice=购买价格
|
||||
probabilityWeight=候选权重
|
||||
ECoolTimeType=周期类型枚举
|
||||
EClaimType=领取类型枚举
|
||||
EQuestGroup=任务分组枚举
|
||||
dailyQuestCount=每日任务数量
|
||||
weeklyQuestCount=每周任务数量
|
||||
challengeQuestCount=挑战任务数量
|
||||
dailyQuestRerollCount=每日任务重掷次数
|
||||
normalRewardID=普通轨奖励ID
|
||||
normalRewardCount=普通轨奖励数量
|
||||
premiumRewardID=高级轨奖励ID
|
||||
premiumRewardCount=高级轨奖励数量
|
||||
premiumPlusRewardID=高级Plus轨奖励ID
|
||||
premiumPlusRewardCount=高级Plus轨奖励数量
|
||||
piece=碎片需求
|
||||
isOwnEffect=持有效果标记
|
||||
RareValue=稀有品质数值
|
||||
EpicValue=史诗品质数值
|
||||
LegendValue=传说品质数值
|
||||
MythValue=神话品质数值
|
||||
baseWeight=基础重量
|
||||
plusWeight=重量增量
|
||||
plusValue=数值增量
|
||||
maxInvSize=背包容量
|
||||
maxTicket=门票上限
|
||||
startTicket=初始门票
|
||||
maxBallCount=弹珠容量
|
||||
chargeSecond=恢复秒数
|
||||
maxADPerDay=每日广告次数
|
||||
buffSecond=增益持续秒数
|
||||
starCount=星数
|
||||
startValue=起始值
|
||||
endValue=目标值
|
||||
winUpValue=胜利增加值
|
||||
loseUpValue=失败增加值
|
||||
purchaseAvailableMinutes=购买窗口分钟数
|
||||
cooldownMinutes=冷却分钟数
|
||||
likePoint=好感档
|
||||
goldUP=金币收益参数
|
||||
diaUP=钻石获得概率参数
|
||||
ingameDiscount=局内折扣参数
|
||||
isResetBeforeCeil=保底前命中重置标记
|
||||
clearStage=通关阶段条件
|
||||
loop=层数
|
||||
Loop=层数
|
||||
stage=阶段
|
||||
chapter=章节
|
||||
score=评分
|
||||
highScore=最高分门槛
|
||||
killScore=击杀分数
|
||||
bossKillCount=Boss击杀数量
|
||||
stepMMR=MMR步长
|
||||
baseWinMMR=胜利基础MMR
|
||||
baseLoseMMR=失败基础MMR
|
||||
resetSeasonAdjustTier=赛季段位调整量
|
||||
countingTime=统计分钟数
|
||||
startReward=初始奖池
|
||||
RewardPercent=名次分配百分数
|
||||
rewardPerParticipant=每参与者增加奖励范围
|
||||
playItemUseCount=每次游玩消耗
|
||||
maxGold=金币上限数组
|
||||
shopIncrease=每层商店涨价百分数
|
||||
maxUpgradeLevel=强化等级上限
|
||||
conditionType=成就条件类型
|
||||
prerequisiteId=前置成就键
|
||||
isPerGameReset=每局开始重置进度
|
||||
'''.strip().splitlines()))
|
||||
# 读者数值视图不展示美术路径与文案;其他字段全部保存并按6列拆分。
|
||||
display=re.compile(r'icon|prefab|sprite|animation|animKey|title|desc|text|feedback|sound|sfx|color|image|banner|url',re.I)
|
||||
allcatalog=[]; expected=0; delivered=0
|
||||
categories=[('01-大厅与基础资源',['01','02']),('02-长期养成',['03','04','05','06','07','08','09','10','11','26']),('03-资源获取与商业化',['12','13','14']),('04-目标与周期成长',['15','16','17']),('05-挑战与竞技',['18','19','20','21','22','23']),('06-活动与小游戏',['24','25'])]
|
||||
related={'01':'02 18','02':'12 13 14','03':'04 09 13','04':'02 03','05':'02 13','06':'13 21','07':'13 24','08':'02 18','09':'03','10':'03 14','11':'02 18','12':'02 18','13':'02 03 05 06 07','14':'02 17 24','15':'16 17 24','16':'02 15','17':'14 15 23','18':'01 02 03 11','19':'02 18','20':'02 18 23','21':'02 06 23','22':'02 17 23','23':'17 21 22 24','24':'14 15 23 25','25':'02 23 24','26':'02 14'}
|
||||
nav='# 原作局外功能分类导航\n\n按功能查找模块,再依次阅读设计、规则和数值。所有数值保持原作配置原值。\n\n'
|
||||
for group, ids in categories:
|
||||
nav+='## '+group+'\n\n'+mdtable(['模块','功能设计','规则','数值'],[(m['name'],f"[设计](./{m['folder']}/01-模块设计文档.md)",f"[规则](./{m['folder']}/02-规则说明.md)",f"[数值](./{m['folder']}/03-数值说明.md)") for m in modules if m['id'] in ids])+'\n'
|
||||
write(out/'01-功能分类导航.md',nav)
|
||||
for m in modules:
|
||||
d=out/m['folder']; tc=[]; rule_sections=[]; value_sections=[]
|
||||
for t in m['tables']:
|
||||
title,desc=notes[t]
|
||||
headers,types,comments,records=tables[t]
|
||||
expected+=len(records)
|
||||
visible=[h for h in headers if h not in ('Id','StringId') and not display.search(h)]
|
||||
# 无参数的展示表仍提供所有行的主键及原CSV入口。
|
||||
groups=[visible[i:i+6] for i in range(0,len(visible),6)] or [[]]
|
||||
src=f'../03-表格/{t}.csv'
|
||||
detail=f'# {title}:原作数值明细\n\n{desc}\n\n源表:`{t}`,共{len(records)}条记录。[完整CSV]({src}) · [原始表](../03-表格/原始表/{t}.csv) · [模块数值说明](../03-数值说明.md)。\n\n保留全部配置记录,包括停用项;数值视图略去文案与美术资源字段,完整字段见CSV。空单元格代表原表空值,-1和0均按原值保留。每张表中的“等级”只适用于该表自己的成长阶段。\n\n'
|
||||
fieldrows=[]
|
||||
for h in visible:
|
||||
i=headers.index(h)
|
||||
label=zh.get(h,'枚举原名' if h.startswith('E') else '原字段名,含义见功能规则及原注释')
|
||||
fieldrows.append((h,label,types[i],comments[i] if i<len(comments) else ''))
|
||||
detail+='## 字段说明\n\n'+mdtable(['字段','含义','原类型','原注释'],fieldrows)+'\n'
|
||||
for part,cols in enumerate(groups,1):
|
||||
detail+=f'## 数值组{part}\n\n'
|
||||
for start in range(0,len(records),120):
|
||||
batch=records[start:start+120]
|
||||
detail+=f'### 记录{start+1}—{start+len(batch)}\n\n'
|
||||
labels=['Id','StringId']+[f'{zh.get(h,h)}({h})' if h in zh else h for h in cols]
|
||||
detail+=mdtable(labels,[(r['Id'],r['StringId'],*[r[h] for h in cols]) for _,r in batch])+'\n'
|
||||
write(d/'04-数值明细'/(t+'.md'),detail)
|
||||
delivered+=len(records)
|
||||
link=f'./04-数值明细/{t}.md'
|
||||
tc.append((title,len(records),f'[数值明细]({link})',f'[CSV](./03-表格/{t}.csv)'))
|
||||
allcatalog.append(dict(模块=m['folder'],子功能=title,原表=t,记录数=len(records),设计文档=f"{m['folder']}/01-模块设计文档.md",规则文档=f"{m['folder']}/02-规则说明.md",数值文档=f"{m['folder']}/04-数值明细/{t}.md"))
|
||||
rule_sections.append(f'### {title}\n\n{desc}\n\n对应原表:`{t}`,{len(records)}条。[完整数值]({link})。\n')
|
||||
numeric=[]
|
||||
for i,h in enumerate(headers):
|
||||
if types[i] not in ('int','float','double','long') or h=='Id': continue
|
||||
values=[]
|
||||
for _,r in records:
|
||||
try: values.append(float(r[h]))
|
||||
except ValueError: pass
|
||||
if values:
|
||||
fmt=lambda v: str(int(v)) if v.is_integer() else str(v)
|
||||
numeric.append((zh.get(h,h),h,len(values),fmt(min(values)),fmt(max(values))))
|
||||
if numeric:
|
||||
value_sections.append(f'### {title}\n\n原表记录{len(records)}条。以下为全配置数值范围,包含停用与历史档,不等同于可达上限。[逐档数值]({link})。\n\n'+mdtable(['参数','原字段','有效数值数','最小值','最大值'],numeric)+'\n')
|
||||
# 将规则按子功能组织,保留先前已核对的具体规则与补充项。
|
||||
p=d/'02-规则说明.md'; content=p.read_text(encoding='utf-8')
|
||||
begin=content.index('## 表级规则及原值')
|
||||
end=content.index('## 关联全局配置',begin)
|
||||
content=content[:begin]+'## 子功能规则\n\n'+'\n'.join(rule_sections)+'\n'+content[end:]
|
||||
write(p,content)
|
||||
p=d/'01-模块设计文档.md'; content=p.read_text(encoding='utf-8')
|
||||
pos=content.index('## 功能构成与规则关系')
|
||||
functional='## 子功能构成\n\n'+mdtable(['子功能','设计内容'],[(notes[t][0],notes[t][1]) for t in m['tables']])+'\n'
|
||||
content=content[:pos]+functional+content[pos:]
|
||||
linked=[x for x in modules if x['id'] in related[m['id']].split()]
|
||||
content+='\n## 相关功能模块\n\n'+mdtable(['模块','关联内容'],[(f"[{x['name']}](../{x['folder']}/01-模块设计文档.md)",x['role']) for x in linked])+'\n'
|
||||
content=content.replace('[规则说明](./02-规则说明.md) ·','[规则说明](./02-规则说明.md) · [数值说明](./03-数值说明.md) ·')
|
||||
write(p,content)
|
||||
numericdoc=f"# {m['name']}:数值说明\n\n本模块按{len(m['tables'])}项子功能整理数值。成长等级、消费资源、奖励数量、权重和周期分别保留,点击数值明细可阅读全部配置档。\n\n## 数值目录\n\n"+mdtable(['子功能','记录数','可读文档','配置表'],tc)
|
||||
numericdoc+='\n## 数值读取约定\n\n- 等级、星级、品质和节点序号是不同维度,不互相替代。\n- 数组明细使用零基索引;索引不是默认的玩家等级。\n- 只有原注释或类型能确定单位时才写出单位;权重不直接改成百分比。\n- 奖励ID与奖励类型一起阅读,消耗和奖励中的空值、0、-1保持原样。\n\n[数组逐项明细](./03-表格/数组逐项明细.csv) · [关联全局配置](./03-表格/关联全局配置.csv)\n\n## 主要数值范围\n\n'+'\n'.join(value_sections)
|
||||
if m['id']=='13': numericdoc+='\n## 奖励池条件概率\n\n[条件概率推导](./03-表格/条件概率推导.csv)使用同type池的原权重归一化,仅在该池所有记录均参与且按权重抽取时成立,未加入保底。\n'
|
||||
numericdoc+='\n[模块设计](./01-模块设计文档.md) · [规则说明](./02-规则说明.md) · [功能分类](../01-功能分类导航.md)\n'
|
||||
write(d/'03-数值说明.md',numericdoc)
|
||||
write(d/'README.md',f"# {m['folder']}\n\n{m['role']}\n\n1. [模块设计](./01-模块设计文档.md):功能定位、步骤和子功能。\n2. [规则说明](./02-规则说明.md):条件、成长、投入产出及模块关联。\n3. [数值说明](./03-数值说明.md):完整数值目录、范围和逐档明细。\n\n"+mdtable(['子功能','记录数','数值文档','CSV'],tc)+'\n[返回分类导航](../01-功能分类导航.md)\n')
|
||||
csvwrite(out/'02-功能文档索引.csv',allcatalog)
|
||||
overview=(out/'00-局外系统模块总纲.md').read_text(encoding='utf-8')
|
||||
overview=overview.replace('## 模块总纲','[按六大功能分类阅读](./01-功能分类导航.md) · [子功能文档索引](./02-功能文档索引.csv)\n\n## 模块总纲',1)
|
||||
overview=overview.replace('每个模块含 `01-模块设计文档.md`、`02-规则说明.md`、`03-表格/`。','每个模块含 `01-模块设计文档.md`、`02-规则说明.md`、`03-数值说明.md`、`03-表格/`和`04-数值明细/`。')
|
||||
write(out/'00-局外系统模块总纲.md',overview)
|
||||
write(out/'README.md','# HEROLL 2.0.1 原作局外系统\n\n[模块总纲](./00-局外系统模块总纲.md) · [六大功能分类](./01-功能分类导航.md) · [子功能文档索引](./02-功能文档索引.csv)\n\n26个模块按“设计 → 规则 → 数值”阅读。132项表级子功能均有中文规则解读和可读数值明细,保留完整原CSV。\n\n具体公式或条件没有足够原作资料时,在对应规则末尾简短标明。\n')
|
||||
assert expected==delivered
|
||||
return dict(设计文档=len(modules),规则文档=len(modules),数值说明=len(modules),数值明细=len(allcatalog),数值明细覆盖源记录=delivered)
|
||||
Reference in New Issue
Block a user