|
SL2 Analyzer
Read a FromSoftware .sl2 save and report what is in it
|
Functions | |
| addressing () | |
| Load the group-base and area-index tables out of the addressing CSV. | |
| address (fid, groups, areas) | |
| Byte offset of a flag's uint32 and the bit mask inside it, or None. | |
| clean (name, fid, category) | |
| Tidy a display name: drop the trailing id and the category echo. | |
| main () | |
Variables | |
| BASE = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) | |
| ADDRESSING | |
| KNOWN = os.path.join(BASE, "test", "flag_data", "files2", "ds1_known_event_flags.csv") | |
| OUT = os.path.join(BASE, "db_ds1", "known_flags.json") | |
| list | CATEGORY_ORDER |
| The order categories are printed in — roughly the order they matter to a reader, rather than alphabetical. | |
| dict | EXCLUDE_CATEGORIES = {"Boss Fight"} |
| Categories dropped on evidence, not taste. | |
| dict | PREFIX_STRIP |
| Leading text that only repeats the category it is printed under. | |
Build `db_ds1/known_flags.json` — Dark Souls 1 world state, by event flag.
WHAT THIS UNLOCKS
The repo has read DS1's event-flag region since the boss-flag work
(`DS1_FLAG_BASE`, found by search because DS1's published group bases are MEMORY
offsets). It has only ever read twelve boss flags out of it. There are fifty-two
more named flags sitting in `test/flag_data/files2/ds1_known_event_flags.csv` — the
Bells of Awakening, the Lordvessel, the shortcut doors and levers, the non-boss fog
gates, NPC states, covenants joined — and every one is addressable with machinery
that already exists. This turns them into a readable section instead of a file
nobody opened.
THE ADDRESSING, AND WHY IT IS TRUSTWORTHY HERE
An 8-digit DS1 flag is `G AAA S NNN`: a group digit, a three-digit area, a section
digit and the flag number. From `ds1_flag_addressing.csv`:
offset = group_base[G] + area_index[AAA]*0x500 + S*128 + (NNN - NNN%32)/8
mask = 0x80000000 >> (NNN % 32)
That is not taken on faith. Run over the twelve boss ids this repo already ships as
hand-checked `(offset, mask)` pairs in `db_ds1/boss_flags.json`, it reproduces all
twelve exactly. A formula that regenerates an independently-derived table is a
formula worth pointing at new ids.
WHAT IS DELIBERATELY DROPPED
A flag whose group or area is not in the addressing table is skipped rather than
guessed — the same rule the DS3 pickup groups follow. Anything not 8 digits is an
enum index rather than an event flag (the boss CSV is full of them) and is skipped
too. The counts printed at the end say how many of each, so a shrinking table is
visible rather than silent.
Run from the repo root:
python3 tools/gen_ds1_known_flags.py
| gen_ds1_known_flags.addressing | ( | ) |
Load the group-base and area-index tables out of the addressing CSV.
Definition at line 79 of file gen_ds1_known_flags.py.
Referenced by main().
| gen_ds1_known_flags.address | ( | fid, | |
| groups, | |||
| areas | |||
| ) |
Byte offset of a flag's uint32 and the bit mask inside it, or None.
MSB-first within the word, which is the same rule DS3 and Sekiro use — DS1 just expresses it as a whole-word mask rather than a byte and a bit.
| fid | The 8-digit event flag id. |
Definition at line 100 of file gen_ds1_known_flags.py.
Referenced by main().
| gen_ds1_known_flags.clean | ( | name, | |
| fid, | |||
| category | |||
| ) |
Tidy a display name: drop the trailing id and the category echo.
The CSV writes "Bell of Awakening, Undead Parish 11010700". The id is already the key, so repeating it in the printed name is noise.
Definition at line 137 of file gen_ds1_known_flags.py.
Referenced by main().
| gen_ds1_known_flags.main | ( | ) |
Definition at line 147 of file gen_ds1_known_flags.py.
References address(), addressing(), clean(), and main().
Referenced by main().
| gen_ds1_known_flags.BASE = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) |
Definition at line 45 of file gen_ds1_known_flags.py.
| gen_ds1_known_flags.ADDRESSING |
Definition at line 46 of file gen_ds1_known_flags.py.
| gen_ds1_known_flags.KNOWN = os.path.join(BASE, "test", "flag_data", "files2", "ds1_known_event_flags.csv") |
Definition at line 49 of file gen_ds1_known_flags.py.
| gen_ds1_known_flags.OUT = os.path.join(BASE, "db_ds1", "known_flags.json") |
Definition at line 50 of file gen_ds1_known_flags.py.
| list gen_ds1_known_flags.CATEGORY_ORDER |
The order categories are printed in — roughly the order they matter to a reader, rather than alphabetical.
Anything not listed sorts to the end by name.
Definition at line 54 of file gen_ds1_known_flags.py.
| dict gen_ds1_known_flags.EXCLUDE_CATEGORIES = {"Boss Fight"} |
Categories dropped on evidence, not taste.
"Boss Fight" is eight rows of "Boss Arena Entered" and "Cutscene Skipped", and every one reads CLEAR on the NG+2 all-bonfires mule that has 23 bosses dead. A flag that must be true there and is not is transient — set while you are in the arena, not after you win — so printing "Boss Fight 0 of 8" on a finished run would tell a reader those bosses were never fought. The kills are already reported properly from db_ds1/boss_flags.json and the soul floor.
Definition at line 75 of file gen_ds1_known_flags.py.
| dict gen_ds1_known_flags.PREFIX_STRIP |
Leading text that only repeats the category it is printed under.
The source writes "Covenant Joined, Chaos Servant" and files it under "Join Covenants". Printed as a bullet beneath that heading the lead is pure noise, so it comes off. Area leads ("Sen's Fortress, Fog Gate 1") are NOT stripped — those say where, which is the useful half.
Definition at line 125 of file gen_ds1_known_flags.py.