SL2 Analyzer
Read a FromSoftware .sl2 save and report what is in it
Loading...
Searching...
No Matches
gen_from_paramdex Namespace Reference

Functions

 read_names (paramdex, game, stem)
 
 ds1_spells (i, _n)
 
 ds1_goods (i, _n)
 
 ds3_goods (i, _n)
 
 ds3_weapons (i, _n)
 
 ds3_armors (i, _n)
 
 ds3_rings (i, _n)
 

Variables

 W
 
 P
 
 A
 
 G
 
 GEM
 
 JUNK
 
 DEVNAME = re.compile(r" -- ")
 
dict NAME_FIXUPS
 Hand corrections applied last, after the merge.
 
tuple DS3_ESTUS = ((150, 171), (190, 211))
 DS3 flask ids, in level pairs (full, drained).
 
dict STRICT = {"db_ds3/rings"}
 
dict PRUNE_EXISTING = {"db_ds1/Consumables", "db_ds1/Spells", "db_ds3/rings"}
 Tables whose gate also applies to what is ALREADY shipped.
 

Detailed Description

Regenerate the DS1 and DS3 id->name tables in db_*/ from soulsmods/Paramdex.

Elden Ring and Sekiro are NOT here: both are read out of the installed game instead,
which beat this source measurably in both cases. See the notes in PLAN below.

Pinned source: soulsmods/Paramdex @ ff7245e524329bc3eab00036723d2bd53384cedf
(2026-03-06) -- the commit that carries Elden Ring through Shadow of the Erdtree.

It is idempotent and non-destructive: an existing hand-disambiguated name always wins
on an id collision, so running it can add rows and can never silently rewrite a
name a human decided on.

    git clone --depth 1 --filter=blob:none --sparse \
        https://github.com/soulsmods/Paramdex.git /tmp/Paramdex
    cd /tmp/Paramdex && git sparse-checkout set DS1 DS1R DS3
    python3 tools/gen_from_paramdex.py --paramdex /tmp/Paramdex

    --dry-run   report the delta, write nothing
    --only ds1  restrict to one game key (ds1, ds3)

DS2 is deliberately absent: its ids are little-endian save bytes, not param ids,
and its tables are already complete from the SOTFS Hex Code Compendium. Paramdex
DS2S cannot be mapped onto them and must not be imported.

Function Documentation

◆ read_names()

gen_from_paramdex.read_names (   paramdex,
  game,
  stem 
)
Paramdex Names/*.txt -> {int id: name}. Files are '<id> <name>' per line.

Definition at line 60 of file gen_from_paramdex.py.

◆ ds1_spells()

gen_from_paramdex.ds1_spells (   i,
  _n 
)
DS1 stores sorceries/miracles/pyromancies as ordinary goods, 3000-8999.
9000-9014 is the gesture block, which is a good and stays one — filing a
gesture under a "Spells" heading would be a worse lie than no heading.

Definition at line 99 of file gen_from_paramdex.py.

Referenced by ds1_goods().

Here is the caller graph for this function:

◆ ds1_goods()

gen_from_paramdex.ds1_goods (   i,
  _n 
)

Definition at line 106 of file gen_from_paramdex.py.

References ds1_spells().

Here is the call graph for this function:

◆ ds3_goods()

gen_from_paramdex.ds3_goods (   i,
  _n 
)
Goods and spells both sit behind 0x40000000 in a DS3 save, so anything at
or above the Magic id floor belongs to db_ds3/spells.json, not here. 9000-
9099 is the gesture block: gestures are not reported (they scatter off-grid
flag hits and cost real items to acquire).

Definition at line 116 of file gen_from_paramdex.py.

◆ ds3_weapons()

gen_from_paramdex.ds3_weapons (   i,
  _n 
)
DS3's inventory is found by scanning every byte of the slot for a known id,
so a junk row is not free: a dev id matching off the 16-byte record grid splits
a run and takes real items with it (a mule lost four items to exactly this).
Ammunition sits at 400000-409999 and real armaments at 1000000-29999999;
everything Paramdex lists outside those is (Debug)/Test-/Ghost scaffolding, or
the sub-10000 thrown-item rows whose small ids match constantly.

Definition at line 126 of file gen_from_paramdex.py.

◆ ds3_armors()

gen_from_paramdex.ds3_armors (   i,
  _n 
)
Real DS3 protector ids start at 19000000. Everything below 10^7 in
Paramdex is the cut DS1-legacy block (Armor of Favor, Stone Armor) that no
DS3 save can hold.

Definition at line 136 of file gen_from_paramdex.py.

◆ ds3_rings()

gen_from_paramdex.ds3_rings (   i,
  _n 
)
EquipParamAccessory 10000-19999 is the covenant-badge block, which is
rendered from db_ds3/covenants.json. Real rings start at 20000.

Definition at line 143 of file gen_from_paramdex.py.

Variable Documentation

◆ W

gen_from_paramdex.W

Definition at line 36 of file gen_from_paramdex.py.

◆ P

gen_from_paramdex.P

Definition at line 36 of file gen_from_paramdex.py.

◆ A

gen_from_paramdex.A

Definition at line 36 of file gen_from_paramdex.py.

◆ G

gen_from_paramdex.G

Definition at line 36 of file gen_from_paramdex.py.

◆ GEM

gen_from_paramdex.GEM

Definition at line 36 of file gen_from_paramdex.py.

◆ JUNK

gen_from_paramdex.JUNK
Initial value:
1= re.compile(
2 r"^\s*$"
3 r"|\[Unused\]|%null%|^Dummy|^dummy"
4 r"|^test |^Test |test gem|TestData|ID Monitoring|ID monitoring"
5 r"|^Type \d+$|^Unarmed$"
6 r"|^\{|^-$|^NoName|^\‍(dummy",
7)

Definition at line 41 of file gen_from_paramdex.py.

◆ DEVNAME

gen_from_paramdex.DEVNAME = re.compile(r" -- ")

Definition at line 50 of file gen_from_paramdex.py.

◆ NAME_FIXUPS

dict gen_from_paramdex.NAME_FIXUPS
Initial value:
1= {
2 "Havel's ring +3": "Havel's Ring+3", # lowercase/space drift on one variant
3}

Hand corrections applied last, after the merge.

Small by design: if this map grows past a dozen entries the upstream table is the thing to fix.

Definition at line 55 of file gen_from_paramdex.py.

◆ DS3_ESTUS

tuple gen_from_paramdex.DS3_ESTUS = ((150, 171), (190, 211))

DS3 flask ids, in level pairs (full, drained).

ds3_resolve_estus computes the level from the id, so a table row would only ever disagree with it about the spelling — and would shadow it, since a direct hit wins.

Definition at line 113 of file gen_from_paramdex.py.

◆ STRICT

dict gen_from_paramdex.STRICT = {"db_ds3/rings"}

Definition at line 149 of file gen_from_paramdex.py.

◆ PRUNE_EXISTING

dict gen_from_paramdex.PRUNE_EXISTING = {"db_ds1/Consumables", "db_ds1/Spells", "db_ds3/rings"}

Tables whose gate also applies to what is ALREADY shipped.

Everywhere else a gate filters Paramdex only, because a shipped id is one a real save was seen to hold — db_ds3/weapons carries Torch (90000) and Fists (110000), which the weapon gate rejects and which the equipped-weapon read depends on. Pruning is for the DS1 goods/spells split (rows must MOVE, not duplicate) and the ring eviction.

Definition at line 156 of file gen_from_paramdex.py.