re: mission scoring and the S/A/B/C/D rank thresholds

sub_8230D1F8 -- the loader that contaminated the AA_/AV_ offset search -- is the
stage-settings loader.  Reading its 122 field NAMES instead of its offsets found
the scoring block, which nothing in docs/re owned.

24 IDXD objects per language pack x 6 = 144, each holding Score_Easy /
Score_Normal / Score_Hard: 72 records per pack on one 22-field schema, no
variants.  Difficulty moves 10 of the 22 fields and never the five RankScore_*
thresholds -- the rank bar is per stage, difficulty scales the earning rate
(x0.5 / x1.0 / x2.0) and the penalties.  23 of 24 objects differ from the
commonest Normal record; 9 of 72 records zero the scoring entirely.

Not settled: which object is which stage.  None of AUTO_SETTINGS's 28 filenames
resolves to any of the 24 under 19 prefixes, and 24 vs 28 is unexplained.

New doc structures/mission-scoring.md, regenerator mission_scoring.py, artefact
data/mission-scoring.txt.  Twelve artefacts now.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PMRJjbxLqZtsb5Vb7KunPE
This commit is contained in:
Claude (auto)
2026-08-27 18:22:36 +00:00
parent 1a1a8d98d9
commit 192d3bf67f
5 changed files with 312 additions and 0 deletions

View File

@@ -0,0 +1,80 @@
# 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
Not settled. `AUTO_SETTINGS` names 28 files (`stage01…16`, `tutorial01…06`,
`challenge01…06`, tags 116/1823/2429 — tag 17 absent, the cut S17), but
**none of those 28 names resolves to any of the 24 objects** under 19 prefixes
(bare, `stage\`, `Stage\`, `message\`, `settings\`, `2d\`, `ui\`, `system\`,
`dat\`, `prt\`, `view\`, `language\`, `eng\`, `script\`, `Script\`, `mission\`,
`Mission\`, `param\`, `Param\`). So either the settings files are loaded outside
the pak namespace, or the scoring objects are keyed by something else entirely.
**24 objects against 28 declared files is itself unexplained** — do not assume
the missing four are the tutorials without checking.