The queued item (the 29-object resource manifest) turned out to be already settled by challenge-mission-gate.md and stage-mission-tables.md, so the iteration moved to the open question those docs make answerable. Hashing EVERY string that appears in any IDXD object on the disc resolves all 24: StageParameter_S01..S16 (story), S24..S29 (challenge), StageParameter_ Tutorial shared by all six tutorials, and StageParameter_Test. 16+6+1+1 = 24, which is exactly why the settings family is 24 against 29 stage records. IsBoss16Enable confirmed independently: that object is StageParameter_S16. GravityFactor is non-zero in S10 (700), S11 (400), S03 (250), S27 (250); the three unscored objects are S24, S27, S28; the one without SplinterCell is _Test. Refuted on the way: TOC order is not stage order (the TOC is hash-sorted and the Boss16 object is 17th, not 16th), and neither the StageResource template nor a real 19-field record names the settings table. The AUTO_SETTINGS filenames are a different scheme -- none of the 28 hashes to any of these 24. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PMRJjbxLqZtsb5Vb7KunPE
79 lines
4.0 KiB
Markdown
79 lines
4.0 KiB
Markdown
# Mission scoring and the S/A/B/C/D rank thresholds
|
||
|
||
**✅ Settled 2026-08-27** (static; regenerator
|
||
`tools/re-capture/mission_scoring.py`, artefact
|
||
[`data/mission-scoring.txt`](../data/mission-scoring.txt)).
|
||
|
||
Found by following `sub_8230D1F8` — the loader that the `AA_`/`AV_` investigation
|
||
turned up as a *contaminant*, because it stores at the same object offsets the
|
||
unit definition uses. Reading its field names instead of its offsets identified
|
||
it as the **stage-settings loader**, and the scoring block is the part of it the
|
||
corpus did not have.
|
||
|
||
**Docs checked:** `isl-condition-builtins.md` owns `AUTO_SETTINGS` — the 28
|
||
`stageNN_settings.tbl` / `tutorialNN` / `challengeNN` **filenames**;
|
||
`unit-datasheet-static.md` and `unit-struct-runtime.md` own the *per-unit*
|
||
`ScorePoint` / `DamageScore` / `MassScore` fields. **What none of them says is how
|
||
a mission score is assembled or what earns a rank** — `RankScore`, `TimeBonus`,
|
||
`KillBonus`, `FFPenalty`, `Difficulty_*` appear nowhere in `docs/re/`.
|
||
|
||
## The tables
|
||
|
||
**24 IDXD objects per language pack × 6 packs = 144.** Each holds exactly three
|
||
records — `Score_Easy`, `Score_Normal`, `Score_Hard` — so **72 scoring records
|
||
per pack**, and they share **one** 22-field schema with no variants.
|
||
|
||
| group | fields |
|
||
|---|---|
|
||
| rank thresholds | `RankScore_S` `_A` `_B` `_C` `_D` |
|
||
| score multipliers | `CraftScore_Adjustment`, `VesselScore_Adjustment`, `OtherScore_Adjustment` |
|
||
| objective bonus | `MainMissionCount`, `MainMissionBonus` |
|
||
| time bonus | `TimeBonus_Maximun` (sic), `TimeBonus_Basis_Minimum`, `TimeBonus_Basis_Maximum` |
|
||
| kill / escort bonus | `KillBonus_Maximum`, `FriendlyVesselDamageBonus`, `GettingScoreBasis_Minimum`, `GettingScoreBasis_Maximum` |
|
||
| penalties | `LostWingmanPenalty`, `FFPenalty_Craft_Basis`, `FFPenalty_Craft_Maximum`, `FFPenalty_Vessel_Basis`, `FFPenalty_Zessel_Maximum` (sic — "Vessel") |
|
||
|
||
Two of the game's own misspellings are load-bearing as join keys:
|
||
**`TimeBonus_Maximun`** and **`FFPenalty_Zessel_Maximum`**.
|
||
|
||
## ✅ Difficulty changes the earning rate, not the bar
|
||
|
||
Comparing the three difficulty records inside each object, **10 of the 22 fields
|
||
move and 12 never do** — and the ones that never move include **all five
|
||
`RankScore_*` thresholds**:
|
||
|
||
```
|
||
differ between Easy/Normal/Hard CraftScore_Adjustment 21 VesselScore_Adjustment 21
|
||
(count = objects out of 24) OtherScore_Adjustment 21 LostWingmanPenalty 21
|
||
FFPenalty_Craft_Maximum 21 FFPenalty_Zessel_Maximum 21
|
||
KillBonus_Maximum 18 MainMissionBonus 18
|
||
TimeBonus_Maximun 18 FriendlyVesselDamageBonus 13
|
||
never differ RankScore_S/A/B/C/D, MainMissionCount,
|
||
GettingScoreBasis_*, TimeBonus_Basis_*,
|
||
FFPenalty_*_Basis
|
||
```
|
||
|
||
So a rank bar is **per stage**, identical on every difficulty; what difficulty
|
||
changes is how fast you earn against it (`×0.5` / `×1.0` / `×2.0` on the three
|
||
`*Score_Adjustment` multipliers) and how hard the penalties bite. That is a
|
||
design statement a port has to reproduce exactly, and it is measured, not read
|
||
off the names.
|
||
|
||
## Per-stage variation
|
||
|
||
**23 of the 24 objects differ from the commonest `Score_Normal` record**, almost
|
||
always in the `RankScore_*` thresholds and the objective count/bonus — as
|
||
expected for per-mission tuning. Nine of the 72 records (three objects × three
|
||
difficulties) zero the multipliers, the penalties and `TimeBonus_Maximun`
|
||
outright: missions that are not scored. Full per-object diffs are in the
|
||
artefact.
|
||
|
||
## ✅ Which object is which stage — settled
|
||
|
||
All 24 are named `stage\StageParameter_S<NN>.tbl`, plus `_Tutorial` (shared by
|
||
all six tutorials) and `_Test`. See
|
||
[`stage-settings-table.md`](stage-settings-table.md); that also explains 24
|
||
against the 29 stage records, and confirms the `IsBoss16Enable` object is S16.
|
||
|
||
⚠️ The names are **not** `AUTO_SETTINGS`'s `stageNN_settings.tbl`; none of those
|
||
28 hashes to any of these objects.
|