DAT/EMBLEM (13 files, 5.2 MB, plus CVS/) is folder id 8 in the
game's file manager (PRELOAD_DIR.md). It holds what
the club editor builds the player's crest and flag from: the part
textures, the tables of presets and samples, and the editor's colour
palette. The finished crests of the real clubs are in
0SYSTEM/EMBLEM_TEXTURE.PAC instead (0SYSTEM_DIR.md).
The folder also holds the player editor's tables (EDIT_PLAYER.TBB) and
an empty DUMMY.DAT.
python SRC/emblem.py info DAT/EMBLEM checks the layouts described here.
python SRC/emblem.py colors DAT/EMBLEM lists the palette, and
python SRC/emblem.py crests DAT/EMBLEM the crests.
| File | Kind | Read by | Contents |
|---|---|---|---|
COLOR_TABLE.TBB |
TBB, 7 tables | EDIT::CColor |
96 colours and the maps to a 32- and a 16-colour palette. confirmed |
EDIT_EMBLEM.TBB |
TBB, 144 tables | EDIT::CEmblemData |
masks, patterns, accessories, presets, sample crests and their layers. confirmed |
EDIT_EMBLEM_M.PAC / .HED |
BINPAC, 214 SVR | the crest editor | masks (the crest's outline), in 50 groups. confirmed |
EDIT_EMBLEM_P.PAC / .HED |
BINPAC, 22 SVR | the same | patterns (the fill). confirmed |
EDIT_EMBLEM_A.PAC / .HED |
BINPAC, 217 SVR | the same | accessories (the emblems on top). confirmed |
EDIT_FLAG.TBB |
TBB, 3 tables | EDIT::CFlagData |
flag bases, flag patterns, crest placements. confirmed |
EDIT_FLAG.PAC / .HED |
BINPAC, 49 SVR | the flag editor | flag bases. confirmed |
EDIT_PLAYER.TBB |
TBB, 32 tables | PLAYEREDIT_MODULE (YRSTPRG.REL) |
the player editor's tables: base abilities by position and nation, personality and growth ranges, the editor's choices (below) |
DUMMY.DAT |
0 bytes | nothing | a placeholder |
The 4 part packs hold 128×128 textures at 4 bits per pixel with an
external palette (data format 0x62, SVR_FORMAT.md):
the colours come from the palette the player picks, not from the file.
Each .HED is a byte-for-byte copy of its pack's header (empirical).
COLOR_TABLE.TBB has copies in PRELOAD/GAMEFILE0–6 (the match). No
other file here is in a PRELOAD pack. TEST3D/EDIT.PAC holds older
.svm versions of the same 502 part textures
(TEST3D_DIR.md).
Addresses are in DLL/SIMPRG.REL unless marked. Function bounds in this
overlay come from the exported symbols, so code between two exports is
given by address.
| Address | Symbol | What it shows |
|---|---|---|
0x107174–0x107230 |
(crest editor, after CEmblemEditor::GetPresetLayerAccessaryColor) |
loads edit_emblem_m.hed, _a.hed and _p.hed with CLoader::loadFileRequest, folder 8 |
0x10738c–0x107418, 0x107bc8, 0x107cc0, 0x107db8 |
the same | load single entries of edit_emblem_m/a/p.pac (masks, accessories, patterns) |
0x107b08 |
the same | loads edit_emblem.tbb |
0x108b54–0x108ed0 |
(flag editor, after CFlagEditor::GetPresetData) |
loads edit_flag.hed, entries of edit_flag.pac, and edit_flag.tbb |
0x109330 |
EDIT::CEditLoader::GetEditColor |
loads color_table.tbb |
0x1039f0–0x104310 |
EDIT::CEmblemData getters |
read EDIT_EMBLEM.TBB by table number (below) |
0x104578–0x1045e8 |
EDIT::CFlagData getters |
read EDIT_FLAG.TBB tables 0, 1, 2 |
SLES 0x2b99f8–0x2b9bf4 |
EDIT::CColor::GetColorFromId96, GetId16FromId32, ... |
read COLOR_TABLE.TBB tables 0–6 (below) |
SLES 0x2b9bf8 |
EDIT::CColor::GetColor16 |
turns a colour word into a PS2 16-bit colour: red from bits 24–31, green 16–23, blue 8–15, and bit 15 set when bits 0–7 aren't 0 |
CEDITPRG.REL 0x13dc–0x1414 |
(SELECTTEAMCOLOR_MODULE) |
names color_table.tbb, edit_emblem.tbb and edit_flag.tbb |
SIMPRG.REL 0x223ab0, 0x225638, 0x225928 |
load lists | color_table.tbb (folder 8) with message categories 1080/1085, 550 and 551 |
SIMPRG.REL 0x40208, 0x10fb20 |
(uniform editor, COPerson::makeInitParam) |
more color_table.tbb loads |
GAMEPRG.REL 0x56d4 |
(GAME_MODULE) |
color_table.tbb for the match |
YRSTPRG.REL 0x31430, 0x331d0 |
load lists of PLAYEREDIT_MODULE |
edit_player.tbb (folder 8) with message category 2000 |
TESTPRG.REL 0x2d110 |
the Uniform Viewer's load list | edit_emblem.tbb and color_table.tbb |
TESTPRG.REL 0xb428 |
SUGIO_TEST::CEditTextureTestTask |
color_table.tbb and edit_emblem_p.hed/.pac |
Seven TBL1 tables. Table 0 is the palette; the others map an id in one
palette to the nearest id in another (confirmed, EDIT::CColor, each
getter clamps the id to the table's size):
| Table | Rows × bytes | Getter | Maps |
|---|---|---|---|
| 0 | 96 × 4 | GetColorFromId96 |
id96 → colour word (u32) |
| 1 | 32 × 1 | GetId16FromId32 |
id32 → id16 |
| 2 | 96 × 1 | GetId16FromId96 |
id96 → id16 |
| 3 | 16 × 1 | GetId32FromId16 |
id16 → id32 |
| 4 | 96 × 1 | GetId32FromId96 |
id96 → id32 |
| 5 | 16 × 1 | GetId96FromId16 |
id16 → id96 |
| 6 | 32 × 1 | GetId96FromId32 |
id32 → id96 |
GetColorFromId32 and GetColorFromId16 go through table 6 or 5 to table
0. A colour word holds red in its top byte, so in the file the bytes run
alpha, blue, green, red. All 96 alphas are ff.
The 96 colours form 12 rows of 8 (empirical): seven shades of one hue
from light to dark, then a grey (row 0 is #ffbfbf ... #3f0000, then
white). The 32 and 16 palettes are subsets: table 6 and table 5 list
which of the 96 they are, and going up and back (32 → 96 → 32, 16 → 96 →
16, 16 → 32 → 16) returns the same id for every colour (empirical,
checked by emblem.py info).
This is a different table from 0SYSTEM/COLORDATATABLE.TBB, the 77 UI
colours, which stores R, G, B, A in byte order. Its near twin is
PARAM/PLRESOURCESIM.PAC entry 9, which the same EDIT::CColor wraps for
the season-mode screens
(PLRESOURCESIM_FORMAT.md):
the same size and the same 96 colours, but 10 bytes of the maps differ
(8 in table 1, one each in tables 3 and 5; empirical). Which screens
use which copy is listed in each doc; a palette edit has to reach both.
144 TBL1 tables. The record size comes from each getter's multiplier
(confirmed, EDIT::CEmblemData):
| Table | Records | Getter | Contents |
|---|---|---|---|
| 0 | 214 × 12 | 0x103e78, GetMaskData |
masks. Each starts with its own index as a u16 |
| 1 | 50 × 4 | 0x103e48, GetMaskData |
mask groups: {u16 first mask, u16 count}. GetMaskData(group, n) returns mask first + n, or first when n is past the count |
| 2 | 22 × 4 | 0x103f20 |
patterns: u32 0–21, the entry in EDIT_EMBLEM_P |
| 3 | 217 × 4 | GetAccessaryData |
accessories: u32 0–216, the entry in EDIT_EMBLEM_A |
| 4 | 50 × 10 | GetPresetBaseData |
base presets {u16 mask group, Trs} (below) |
| 5 | 44 × 10 | 0x103fb8 |
area pattern presets {u16 pattern, Trs} |
| 6 | 1 × 10 | 0x103ff0 |
area accessory presets {u16 accessory, Trs}; the one row is all 0 |
| 7 | 29 × 110 | GetSampleData |
sample crests (Param::PlEmblemPreset, below). Ids 0–31; 8, 21 and 24 are absent. They are Edit Emblem's Sample list: 29 crests over three pages of 10, 10 and 9 (Nexxus's report, 2026-10-31) |
| 8 | 32 × 110 | GetInitializeData |
the crests a new club can start with |
| 9 | 32 × 110 | GetRivalData |
rival clubs' crests: 32 copies of one crest |
| 10 | 32 × 1 | GetSampleIndexFromInitializeIndex |
the sample row of each starting crest (values 0–28) |
| 11 | 32 × 3 | GetFirstColorIdSet |
three signed bytes per starting crest. In the data: the row's own index, then two ids in the 32-colour palette |
| 12–143 | 12 bytes each | GetSampleLayerAcceData |
layer accessories {u16 key, u16 accessory, Trs}, table 12 + 4 × sample + layer (below) |
The mask groups are the mask pack (empirical, all 214): group g
holds _mask_GGG_NN for GGG = g + 1, in order, so table 1's counts
are the number of masks in each group, and the groups follow each other
without gaps. Table 0 has one row per mask, table 2 one per pattern and
table 3 one per accessory, matching the three packs.
Confirmed. The developers' field table
(PBDATA_FORMAT.md;
here SLES 0x53cd08–0x53d3c8) names every member of the crest. Its
parser in sles_disasm.py fields skips members that are themselves
structures but whose names don't start with _, so these were read from
the raw rows:
| Structure | Size | Members |
|---|---|---|
Trs |
8 | tx s8 +0, ty s8 +1, rot s16 +2, rev u8 +4, sx u8 +5, sy u8 +6, a pad byte |
Acce |
0x12 |
trs +0, texture_id +8, texture_num +0xa, aColor 3 × u16 +0xc |
Pattern |
0x10 |
trs +0, texture_id +8, texture_num +0xa, aColor 2 × u16 +0xc |
Area |
0x22 |
an Acce +0, a Pattern +0x12 |
Mask |
0xac |
mask_num u16 +0, aArea 5 × Area +2 |
Base |
0xb6 |
trs +0, base_num u16 +8, mask +0xa |
PlEmblem |
0x168 |
chunk u32 +0, base +4, aAcce 9 × Acce +0xba, aLayer 10 × u8 +0x15c |
PlEmblemPresetNumber |
0x22 |
sample, base, mask +0–+4, aAreaPattern 5 × +6, aAreaAcce 5 × +0x10, aLayerAcce 4 × +0x1a (all u16) |
PlEmblemPresetColor |
0x4a |
aAreaPattern 5 × 2 +0, aAreaAcce 5 × 3 +0x14, aLayerAcce 4 × 3 +0x32 (all u16) |
PlEmblemPreset |
0x6e |
preset u16 +0, number +2, color +0x24 |
The next structure holds a club's crest: emblem (PlEmblem) +0,
emblempreset +0x168 and main_color_id +0x1d6. A club's crest is
read and written with pwkTeam_GetEmblemSet/SetEmblemSet.
The 110-byte crests of tables 7–9 are PlEmblemPresets (confirmed,
EDIT::CEmblemData::Initialize, 0x103a50). It builds a PlEmblem
from one, and the club's three colours:
| Preset offset | Field | What Initialize does |
|---|---|---|
+0x00 |
preset |
the crest's id; not read |
+0x02 |
sample |
the sample whose layer tables the layer keys search (0–32) |
+0x04 |
base |
a row of table 4: its part goes to base_num, its Trs to the base's |
+0x06 |
mask |
copied to mask_num |
+0x08 |
aAreaPattern ×5 |
rows of table 5: each area's pattern texture and Trs |
+0x12 |
aAreaAcce ×5 |
rows of table 6: each area's accessory texture and Trs |
+0x1c |
aLayerAcce ×4 |
the key searched for in each layer table (below) |
+0x24 |
colours, 5 × 2 | each area's pattern colours |
+0x38 |
colours, 5 × 3 | each area's accessory colours |
+0x56 |
colours, 4 × 3 | the colours of each layer's accessories |
A colour is a 32-colour id, turned into a 96-colour id
(GetId96FromId32), or −1, −2 or −3 for the club's first, second or
third colour (0x103b78). The layer part (0x103cb8–0x103e10) asks
GetSampleLayerAcceData for each layer's records with that key and
appends each as an accessory at PlEmblem +0xba + 0x12 × n, at most
9 in all.
The 10-byte records of tables 4–6 are a part number and a Trs; sx
and sy are a scale in percent (100 = full size) and rot an angle
(table 5 uses 0, 45, 90 and 295). Table 6 has one row, all 0, and every
crest names it for every area (empirical), so the area accessories
start empty and a crest's accessories come from its layers.
Empirical, over the 93 crests (python SRC/emblem.py info):
sampleandbaseare always equal.maskis an index inside the mask group named by the base preset's part (table 1): all 90 crests with a base fit, and the 3 whose base preset has part 65535 (4 of the 50 base presets: no base) have mask 0.- Each starting crest (table 8) has exactly the parts of the sample row table 10 names; only the colours differ.
- Area accessory colours are all 31. Layer keys are 0 or 1.
- A layer record with accessory 65535 fills a slot with nothing. The crests get 72 (samples), 94 (starting) and 64 (rival) real layer accessories.
- The rival table is one crest, id 25 with sample 32, repeated 32 times.
python SRC/emblem.py crests DAT/EMBLEM 8 prints every crest field by
field with its layer accessories.
GetSampleLayerAcceData(out, max, sample, layer, key) (0x104180) reads
table 12 + 4 × sample + layer, so the 132 tables are 33 samples × 4
layers. It walks GetDataTableCount records of 12 bytes, and for each
whose u16 at +0 equals key it copies the u16 at +2 and the 8 bytes at
+4 into a 10-byte output record. 0x104268 counts the records whose
+0 matches. 838 records in all (empirical).
Tables 93, 101 and 105 are a byte short. These are the three tables
TBB_FORMAT.md
describes: 143 bytes, where record 4 lacks its 04 00 key. The reader
above settles what the game does with them (confirmed): it reads 11
records of 12 bytes, so record 4 comes out with key 141 (or 160 in
table 93) instead of 4, records 5–10 are read one byte late with keys
like 0x9500, and record 11 is never reached. A lookup for keys 4–11 in
sample 20, 22 or 23, layer 1, therefore finds nothing. Whether that shows
in the crest editor hasn't been checked.
| Table | Records | Getter | Contents |
|---|---|---|---|
| 0 | 49 × 4 | 0x104578 |
flag bases: u32 0–48, the entry in EDIT_FLAG.PAC |
| 1 | 71 × 2 | GetPresetFlagPatternData |
flag patterns: low byte a base (0–48), high byte its rev (0–3) |
| 2 | 27 × 4 | GetPresetEmblemTs |
where the crest sits on the flag (Param::PlFlagEmblemTs) |
Confirmed (EDIT::CFlagData::Initialize, 0x1044b0, and the field
table at SLES 0x53cac8–0x53ccdc). A flag preset (PlFlagPreset, 8
bytes) is flag_pattern u16 +0 (a row of table 1), emblem_position
u16 +2 (a row of table 2) and aColor 2 × u16 +4 (32-colour ids). It
becomes a PlFlag (0x1c bytes: flag 0x14, then the
flagpreset), whose flag part is:
| Offset | Member | From |
|---|---|---|
+0x00 |
chunk u32 |
– |
+0x04 |
pattern.trs.rev u8 |
table 1's high byte |
+0x06 |
pattern.texture_num u16 |
table 1's low byte: the base in EDIT_FLAG.PAC |
+0x08 |
pattern.aColor 2 × u16 |
the preset's colours, as 96-colour ids |
+0x0c |
emblem {pos_x, pos_y, size_x, size_y} |
table 2's 4 bytes |
+0x10 |
disp_emblem u8 |
– |
So the 4 variants of a base are 4 values of its rev byte, the same
member a crest part's Trs has; what each looks like (mirrored one way
or the other is the likely reading) hasn't been checked in the game.
Table 2 holds 9 positions (x −34, 0, 34 and so on) at three sizes,
0x36/0x44, 0x27/0x32 and 0x1e/0x26: three sizes × a 3 × 3
grid (empirical).
32 tables, loaded by the two lists of PLAYEREDIT_MODULE in
YRSTPRG.REL together with message category 2000. That module is
sequencer module 63 (PlayerEdit), started from events
(SNR2_FORMAT.md), and module 115 in the developer
launcher, where it hangs (SQB_FORMAT.md). It is the
player editor that brings a Virtua Pro Football edit player into a
career
(SAVE_FORMAT.md).
How the tables are read (confirmed, YRSTPRG.REL, 2026-10-30). Each
table has its own accessor (0x1d128–0x1d418, tables 9–31, through the
row getter 0x1d438, row × line size; tables 0–8 through 0x1cf98). All
but three are called from the code after WP::CPlayerEditFrameResult
that makes the finished player, in two drivers: 0x1a9c8 (tables 0–18
and 26–28) and 0x1aa70 (19–25). The player is the edit work's
PlPbase (decoded, 0x1d4f8 returns work +4; field offsets as in
PBDATA_FORMAT.md), written through small setters:
0x1d700 an ability (index < 64, capped at 99), 0x1d7e0 a
dissatisfaction weight (< 8), 0x1d850/0x1d870 a tendency (< 11, set
or added, 0–4), 0x1d8c0 a skill (< 16), 0x1d928 a play-style slot
(< 5, style < 23), 0x1d6d8 a position (< 3, apos < 14).
| Table | Rows × bytes | Read by | What it holds |
|---|---|---|---|
| 0–8 | 14 × 33 | 0x1ae98 |
the base abilities 0–32: the table by the main position's cell (plMisc_Apos2Epos, 9 cells), the row by the nation (0x1d040: rows 0–5 England, France, Germany, Italy, Spain, the Netherlands; 6 the rest of the first scouting region; 7–13 the other regions by plMisc_Nati2DRegion, several sharing a row) |
| 9 | 4 × 13 | WP::CPlayerEditWindowPositionSettingTask (0x128e8, 0x12f58) |
which of the 13 positions (GK, LSB, RSB, CB, LWB, RWB, DM, LSM, RSM, OM, LWG, RWG, FW) belong to each of 4 groups: GK; LSB–CB; LWB–OM; LWG–FW (empirical reading of the 0/1 grid) |
| 10 | 9 × 9 | 0x1af68 |
the 9 position aptitudes (abilities 33–41) by the cell of each of the player's positions (+0x1c–+0x24), 50 on its own cell; with two or three positions the rows are blended through 0x1cde8 (weights 3; 2 and 0; 1 and 1) |
| 11 | 3 × 3 | 0x1b2d0 |
the same for the 3 side aptitudes (42–44), by plMisc_Apos2Side |
| 12 | 8 × 2 | 0x1b5d8 |
the 8 dissatisfaction weights: {min, max}, min + rand(max − min + 1) (all 0–1) |
| 13 | 21 × 2 | 0x1b660 (0x1cea0) |
{min, max} of single fields, in this order: tone, professionalism, pressure, loyalty, star, the first explodetype, moti_type, cond_type, potential, three unused rows (the growth types come from table 28), travel, injury_res, recovery, foul_avoid, weak_foot, policy, adapt, ball_touch, dribble_style |
| 14 | 146 × 26 | 0x1b7e0 (0x1cc70) |
the player's policy (+0x52) by nation: each row a cumulative weighting, a random number below its last value picks the first entry at or above it |
| 15 | 19 × 2 | 0x1b828 |
{min, max} of abilities 45–63 (all 51–80) |
| 16 | 11 × 2 | 0x1b8b8 |
{min, max} of the 11 tendencies (all 0–1) |
| 17 | 16 × 1 | 0x1b940 |
the 16 skills (all 0) |
| 18 | 22 × 1 | 0x1b9b8 |
the 22 play styles, for the 5 style slots (all 0) |
| 19 | 319 × 144 | 0x1c078 |
the effects of the editor's choices: the row is one of up to 8 choices the task keeps at +0x38; its bytes override the fields in table 13's order (byte 1 tone, 5 star, 6 explodetype, 7 moti_type, 9 the growth types …) and further fields, 0xff leaving a field as it is (0x1cef0) |
| 20, 21 | 28 × 16, 28 × 116 | 0x1c5d0 |
the same kind of overrides for another set of 28 choices |
| 22 | 13 × 11 | 0x1cb18 |
added to the 11 tendencies by the player's position (13 positions), clamped to 0–4 |
| 23 | 13 × 16 | 0x1cb88 (0x1cda0) |
the 16 skills by position |
| 24 | 22 × 16 | none | its accessor (0x1d320) has no caller |
| 25 | 32 × 1 | 0x1cc08 |
a factor (byte ÷ 100, 94–100, 11 rows at 94) that scales abilities 0–32 (0x1d780); the row is the task's +0x64 |
| 26 | 100 × 151 | 0x1ade0, 0x1ae38, 0x1ba58 |
100 player templates: byte 0 a nation and byte 6 a position, checked against the player's (0x1ade0, 0x1ae38); the row is the task's +0x60, and 0x1a9c8 stores the result at +0x58 |
| 27 | 1 × 2 | 0x1ae98 |
the spread of the base abilities: each gets rand(5) − 2 |
| 28 | 3 × 16 | 0x1cd08 |
the three growth types (physical, skill, mental, +0x4a–+0x4c), 0–15, drawn from cumulative weights like table 14 |
| 29 | 8 × 10 | 0x1cde8 |
used by the position aptitude blend (+4 100–160 and +6 3–6 in steps); not traced further |
| 30, 31 | 13 × 16, 13 × 19 | WP::CPlayerEditWindowHexagonGraphTask (0x13a98, 0x13ce8) |
data for the editor's hexagon graph, one row per position; not traced further |
So the editor makes a player from his nation and position (tables 0–11,
14, 22, 23), personality and growth ranges (12, 13, 15–18, 28), and the
choices made in the editor (19–21, 25, 26), with ±2 randomness (27).
Whether this runs for a player brought in from Virtua Pro Football
(whose import fills the same edit work,
PMPLAYER_FORMAT.md)
or only for one made in the editor isn't traced. Which screen choices fill the
task's +0x38, +0x60 and +0x64, and so which rows of 19–21, 25 and
26 a player gets, isn't traced. python SRC/emblem.py info DAT/EMBLEM
checks every table's shape, that the {min, max} rows (12, 13, 15, 16)
are in order and that the cumulative rows (14, 28) never fall, on both
releases. Every cell is an unsigned byte (lbu at 0x1aef8,
0x1cb54). Nothing here has been checked in the game. emblem.py set
edits the tables (below).
emblem.py set edits EDIT_EMBLEM.TBB, EDIT_FLAG.TBB and
EDIT_PLAYER.TBB field by field into a new file of the same size, which
patch_disc.py can put on a disc. It changes bytes in place, so the three short layer tables keep
their odd tails. Each field takes the values the game's readers above
use:
| Target | Fields | Values |
|---|---|---|
crest:<table>:<row>:<field> (tables 7–9) |
sample, base, mask, pattern.<area>, acce.<area>, layer_key.<layer> |
a sample with layer tables (0–32), a row of table 4, an index in that base's mask group, a row of table 5, a row of table 6, a key |
| the same | pattern_color.<area × 2 + n>, acce_color.<area × 3 + n>, layer_color.<layer × 3 + n> |
0–31, or −1, −2, −3 for the club's colours |
preset:<table>:<row>:<field> (tables 4–6) |
part; tx, ty, rot, rev, sx, sy |
a mask group (or 65535, no base), a pattern or an accessory; the Trs |
layer:<sample>:<layer>:<record>:<field> |
key, acce; the Trs fields |
any key, an accessory or 65535 (empty). In the short tables only records 0–3, the ones the game reads correctly |
start:<row>:<field> |
sample (table 10), color1, color2 (table 11) |
a row of table 7; 32-colour ids |
flag:pattern:<row>:<field> |
base, rev |
0–48; 0–3 |
flag:place:<row>:<field> |
pos_x, pos_y, size_x, size_y |
−128–127; 0–255 |
player:<table>:<row>:<column> |
one byte of EDIT_PLAYER.TBB |
0–99 in the ability tables (0–8, 10, 11, 15; the setter 0x1d700 caps at 99), 0–4 in the tendency tables (16, 22; clamped by 0x1d870), 0–255 elsewhere |
rev is limited to 0–3, the values the flag patterns use, as long as
what it does is unchecked. Nexxus's report (2026-10-31): flag patterns
2–5, which are base 1 with rev 0, 1, 2 and 3 (EDIT_FLAG.TBB table 1
rows 1–4), looked the same in the flag editor.
Which starting crest a new club gets (confirmed). The club
set-up (CEDITPRG.REL 0x20b0) takes one index, 0–31, for the starting
design the player picks: it sets the club's kits from the 32 at
CEDITPRG.REL 0x150a0 and copies table 8's row of that index as the
crest (GetInitializeData, 0x21a0), with table 10's sample and table
11's colours. The starting crest follows the club's colour (Nexxus's
report), and table 11's first byte in each row is the row's own index,
so the index is most likely the club's main colour, an id in the
32-colour palette: row 0 goes with colour 0, the first, a light pink
(#ffbfbf). So an edit to table 8 row n shows only for a new club of
colour n. Tested in PCSX2 (Nexxus's report, 2026-10-31,
LMAST-test-season2.iso, crest:8:0:mask=1 crest:8:0:base=15): a
club of another colour showed no change, as expected, and a new light
pink club started with row 0's crest on the edited base, a flat-topped
shield (mask _mask_012_02) instead of retail's notched top
(_mask_031_03), its accessories and layers as before.
Changing a crest's base is refused when its mask is past the new
base's group; set the mask first. In EDIT_PLAYER.TBB a {min, max} row
(tables 12, 13, 15, 16) must keep min at or below max, and a cumulative
row (14, 28) must not fall; edit both ends of a row in one command. After
the edits the file is checked as info checks it, and written only if
that finds nothing.
python SRC/emblem.py set DAT/EMBLEM/EDIT_EMBLEM.TBB out.TBB crest:8:0:base=15 crest:8:0:mask=1 start:0:color1=5
python SRC/emblem.py set DAT/EMBLEM/EDIT_FLAG.TBB out.TBB flag:place:0:pos_x=-20
python SRC/emblem.py set DAT/EMBLEM/EDIT_PLAYER.TBB out.TBB player:15:0:1=90 player:25:0:0=100
python SRC/emblem.py roundtrip DAT/EMBLEMroundtrip decodes every preset, crest, starting-crest, layer and flag
record and every row of EDIT_PLAYER.TBB, encodes each again and
rebuilds the file: all three files come out identical, on the PAL and
the Japanese disc. Of the edits set makes, the starting crest's
(above) is tested in the game; the presets, layer records, flag records
and EDIT_PLAYER.TBB aren't yet.
The mod editor's Player editor tab
(USAGE.md) edits EDIT_PLAYER.TBB one row
at a time through set's functions, with the rows, labels and allowed
values from emblem.player_records, player_fields and
player_value. It refuses an edit at once when the {min, max} or
cumulative check fails. Tested through its widgets off-screen: four
edits in tables 0, 15, 19 and 25 saved, and three refused (an ability of
100, a min above its max, a falling growth row); the logged command
rebuilt the saved file byte for byte, and a second session read the
edits back.
The mod editor's Crests tab (USAGE.md)
edits the same records through set's functions. It takes the records,
fields and allowed values from emblem.records, edit_fields and
get_value, and logs each save as the emblem.py set commands that
make the same files. Tested through its widgets off-screen: nine edits
across both files, and a base change refused because the crest's mask
didn't fit the new base; the logged commands rebuilt both saved files
byte for byte, and a second session read the edits back from the mod
folder.
- What a
Trs'srevvalues 1–3 do (a flag's fourrevvariants look the same in the flag editor, Nexxus's report), whatchunk,texture_idandaLayerhold, and which code readsmask_num(its match with the mask groups is empirical). - Whether the three short layer tables lose visible parts in the editor.
- What the 33rd sample (32, the rival crest's) is, given table 7 has 29 rows.
EDIT_PLAYER.TBB: which editor choices pick the rows of tables 19–21, 25 and 26 (task+0x38,+0x60,+0x64), the rest of table 19's 144 bytes, and tables 29–31 (EDIT_PLAYER.TBB).- Why the 4bpp part textures' palette indices map to the chosen colours (the palette build wasn't traced).