Wolfenstein Modloader Buy me a coffeeKaffee spendieren

Wiki / The New OrderThe New Order

Modding Surface: Wolfenstein — The New Order

ReferenceNachschlagewerk Original page in the GitHub wikiOriginalseite im GitHub-Wiki

In plain wordsIn einfachen Worten

This page surveys all 105 asset types in Wolfenstein: The New Order to find modding options nobody has used yet. Most text-based definitions (sounds, ammo, AI behaviour, factions, starting weapons) use a known format and can be edited safely. Some bigger ideas, like cheat modes through game-mode files or changing maps and scripts, look promising but were not tested in the game. A few things, such as particle effects and the missing map xa01, are shown to be impossible.

  • 203,843 index entries, 76,364 unique assets; all 25,559 readable text assets parse without error.
  • 73 text definition types are still unused, e.g. sound (9,445), ammo (94) and aiBehavior (36).
  • Probable but untested: 999 health or unlimited ammo via gamemode files, unlocking bonus modes via enigma, editing enemy and weapon placement in map files.
  • Proven impossible: editing particle effects, virtual texture pixels, the missing map xa01, and adding brand-new assets.
  • The game was not started for this survey; nothing here was tested in play.

Diese Seite geht alle 105 Asset-Typen von Wolfenstein: The New Order durch, um noch ungenutzte Modding-Möglichkeiten zu finden. Die meisten textbasierten Definitionen (Sounds, Munition, KI-Verhalten, Fraktionen, Startwaffen) haben ein bekanntes Format und lassen sich sicher ändern. Größere Ideen wie Cheat-Modi über Spielmodus-Dateien oder Änderungen an Karten und Skripten wirken vielversprechend, wurden aber nicht im Spiel getestet. Einiges, etwa Partikeleffekte und die fehlende Karte xa01, ist nachweislich unmöglich.

  • 203.843 Indexeinträge, 76.364 eindeutige Assets; alle 25.559 lesbaren Text-Assets lassen sich fehlerfrei einlesen.
  • 73 Text-Definitionstypen sind noch ungenutzt, z. B. sound (9.445), ammo (94) und aiBehavior (36).
  • Wahrscheinlich, aber ungetestet: 999 Gesundheit oder unendlich Munition über Spielmodus-Dateien, Bonusmodi über enigma freischalten, Gegner- und Waffenplatzierung in Kartendateien ändern.
  • Nachweislich unmöglich: Partikeleffekte ändern, Virtual-Texture-Pixel, die fehlende Karte xa01 und ganz neue Assets hinzufügen.
  • Das Spiel wurde für diese Übersicht nicht gestartet; nichts davon ist im Spiel getestet.

Technical detailsTechnische Details

Der technische Teil ist auf Englisch – so, wie er im Wiki steht. Unterstrichene Begriffe haben eine Erklärung auf Deutsch.

A map of what has not yet been touched in the game. All numbers and field names originate from the Original Data located under base_wolfsdk_backup\ (the installation is patched—those reading from base\ are measuring their own Mods). Reproducible with:

python tools/survey_modding_surface.py            # full report
python tools/survey_modding_surface.py --probes   # only the four probes
python tools/survey_modding_surface.py --type ammo --samples 3

Status: 105 Asset Types, 203,843 Index Entries, of which 76,364 unique (Type, Name) pairs (the remainder are duplicate slots of the same asset in different chunks—apply patches all copies).

The types here split into 84 Text / 21 Binary—according to the counting rule in tools/survey_modding_surface.py, which checks one sample per type (is_text(): over 95% printable characters in the first 4096 bytes) and knows only two classes. Engine-Modding-Surface.md counts the same 105 types as 80 Text / 5 Mixed / 20 Binary; the four mixed types whose sample was text land here on the Text side. Same measurement, different rules.

25,887 unique Assets in Text Types (not Index Entries—the number 60,233 in Home.md and File-Formats.md §4 counts entries including duplicates and thus is not contradictory to this). 25,559 of these are valid UTF-8, and 100% of these 25,559 parse wolfsdk/decl.py without error—each one was sent through Decl(), no single DeclError. The 328 outliers are 327 embedded binary files under file: (PS4 Save Icons, e.g., ../submission/orbis/gmc/save_data_icon.png) and a renderProg (brokenwindshieldspecular) with non-UTF-8 bytes in the shader text.


0. Executive Summary

Rating What
Guaranteed 73 unused Text Decl Types, identical format to already used ones; sound (9,445), ammo (94), aiBehavior (36), inventoryItem (47), footstepEvents, playerUpgradeAmmo, weaponUpgrade …
Probable gamemodesp as a Cheat path around the CVar lock; enigma to unlock Bonus Modes; .entities Maps (switch Enemies/Pickups); .script Maps (full Script VM)
Provenly Impossible particle (measured), Virtual-Texture Pixel, chapter17/Map xa01 (Map missing in Archive), Changes to renderProg without Shader-Recompile proof

1. All Asset Types

Full list: python tools/survey_modding_surface.py (first section). The brief classification—Count = unique (Type, Name):

Binary, uninteresting for Decl-Modding (21 types, 50,477 unique Assets): sample 19,545, cm 8,403, anim 7,490, voicetrack 5,115, model 2,294, image 2,272, prtMeshDist 1,484, discreteAnimation 1,204, cg 565, cuttableResource 565, baseModel 463, atlas 371, skeleton 368, jointconversion 251, aas 37, glassModel 25, foliageModel 10, font 6, staticParticleModel 4, video 4, morphVertices 1.

image is used despite being Binary (BIM replacement, wolfsdk/bim.py).

Text, already used (10 types): material 3,781, entityDef 1,173, damage 153, weapon 86, projectileImpactEffect 112, projectile 102, aiBehaviorVo 14, goreBehavior 9, articulatedFigure 9, difficultysetting 5.

Text, provenly impossible: particle 1,563.

Text, unused: 73 types. The following sections go through the top 20 and those with high leverage.


2. The 20 Largest Unused Decl Types

Each with real field names from real Assets.

2.1 sound — 9,445 Decls · guaranteed

Example sound:vo/english/commander/commander2_ai_paalarmresponse_indoor_05:

{
    inherit = "inheritences/vo/vo_battle_alarmresponses";
    edit = { soundFiles = { num = 1; item[0] = "sound/vo/.../..._05.wav"; } }
}

Real fields over the inventory: soundFiles.item[N] (up to item[11]+), volume.min / volume.max (1,955 / 1,877 occurrences), minDistance (1,000), maxDistance (1,316), offset (652), falloff (346, e.g., "sound/falloffs/impacts"), rmsTable (557), groups (383, e.g., "SSG_IMPACTS"), soundChannel (278, e.g., "SND_CHANNEL_DAMAGE"), soundShaderFlags (1,716, e.g., "SSF_DISTANCE_BASED_STEREO SSF_PASS_HDR").

Editable: complete remix. Make enemies louder/quieter (maxDistance), make weapons punchier (volume.max), swap sound sources (soundFiles.item[0] to point to another .wav in the archive). This is pure set on existing paths — no risk.

2.2 voiceover — 2,058 Decls · safe

Only one field: tracks.num + tracks.item[N] → voicetrack/... names. Example voiceover:vo/ai/efforts/eff_soldier_meleehit, num = 33. aiBehaviorVo (already used) points to these Decls; this is the level below — which specific tracks an event may draw from. A voiceover with num = 1 makes a voice monotone, swapping item[N] places foreign audio recordings on an event.

2.3 md6Def — 1,243 Decls · safe, but deep

The most interesting type after entityDef. This is the animation-event table per model. Measured frequencies: 44,667× event/frame/row/locked, 26,160× sound, 18,132× anim, 8,307× projectileImpactEffect, 1,049× voiceover, 767× particle, 1,609× tag/trans/rot (Muzzle points etc.), 659× hitTestGroup (e.g., "neck").

Example assets: md6Def:weapons/german_knife.md6, md6Def:items/cigarette.md6.

Editable: Hang or shift sounds/effects on animation frames (frame = 12; event = "ae_leftFoot"), change hit zone assignments (hitTestGroup), move Muzzle offsets (tag = "muzzle"; trans = (0 0 0)). Warning: particle references here are only names — they point to impossible particle Decls, but the reference itself is changeable (to another existing particle).

2.4 breakable — 1,205 Decls · safe

Rigid field schema, identical in all 1,205 Decls: model, linearFriction 0.1, angularFriction 0.1, contactFriction 0.2, linearFrictionWater 1.0, angularFrictionWater 1.0, bouncyness 0.35, gravity 0 0 -750.0, maxSimulationTime 4, clipMask solid, ikclip, shotclip, worldCollisionOnly 1.

27 Decls additionally have an explosion block with radius 5000, impulse 325000, falloff 0.05, angular 1500, duration 0.25. 12 have particleTrail + trailSpacing.

Example: breakable:breakable/rifle, breakable:breakable/shotgunshell.

Editable immediately: Shell casings that bounce (bouncyness), stay longer (maxSimulationTime 4 → 60), fall in slow motion (gravity). Explosive barrels with larger radius. A 10-line generator over all 1,205 Decls is an afternoon's work.

2.5 renderParm — 810 Decls · safe, but blind

Single lines: renderParm:sortlight = { Vec 400 }, renderParm:adaptiveglareblurstep = { Vec 1 }. Only name + number(s), no semantics in the asset. What a parameter does is stated only in the shader that reads it. Unclear which ones visibly affect — here one would have to try individually.

2.6 table — 638 Decls · safe

Curve data. table:sound/falloffs/impacts:

{ clamp min 0 max 1 left 0 right 1 {0:1, 0.0576923:1, 0.102885:0.913725,
  0.552885:0.843137, 0.797115:0.611765, 0.914423:0.423529, 0.969231:0.235294,
  0.997791:0} }

These tables are referenced by sound, playerProps (worldFadeTable, framescale, lowhealthpulse) and Render code. Whoever wants to rebuild the health pulse effect, sound falloff, or damage feedback curves does it here. table:console_add_small_lights_3 = { snap {0}} shows the minimal form.

2.7 env — 592 Decls · safe

env:maps/game/wolf/c06/c06p2/area4:

{ inherit { wolf/c6/c6p2_hangar }
  renderParms { userEnvMap env/game/wolf/c06/c06p2_hangar_bottomroom_px } }

Pro area-specific render parameters set on a map. This allows changing the lighting/atmosphere mood per area without modifying the map itself.

2.8 file — 447 Decls · the largest find, see Section 4

120 unique filenames: 25 .entities maps, 37 .script files, 6 strings/*.lang, debugmenu.txt, .proc/.envareas (binary-adjacent).

2.9 fx — 443 Decls · safe

fx:fx/maps/c01p2/dynamitedoor contains editEvents.item[N] with type = "FX_PARTICLE" / "FX_SOUND" / "FX_SCREEN_SHAKE", each with duration, startCondition/stopCondition ("FX_NONE"), as well as particleParms.declPrt and soundParms.sound.

Editable: Add screenshake on every hit, swap explosion sounds, extend effect durations. Important: particles are only referenced here — swapping them for another already existing particle is allowed, but changing the particle itself is not (Section 6).

2.10 renderProg — 423 Decls · likely, unverified

Contains HLSL source text. renderProg:softparticleblendmodst:

{ inherit particleBlend
  state { blend GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA depthmask twosided }
  hlsl_vp { #define VP_UNITTEXCOORD  #include "softparticle_vp.inc" ... }
  hlsl_fp { ... color.xyz = lerp( $fogColor.xyz, color.xyz, fogVal ); ... } }

Evidence from WolfNewOrder_x64.exe: the strings Failed to compile render prog %s from %s, While compiling %s program %s from %s, Compiled '%s': %.1f ms and the Cvars r_loadPrecompiledShaders ("If true, cache compiled shaders to generated directory.") and r_dumpGeneratedGLSL. The engine can therefore translate at runtime. Unclear remains whether the Retail build does this as well or if a precompiled cache takes precedence — base\generated\ currently contains only decls/particle/*.bin, md6/, and world/, no shader cache. This speaks in favor of runtime translation, but is not proof. The first test would be a harmless color change in a single hlsl_fp.

2.11 job — 168 Decls · safe

job:chapter_12/obj/find_and_enter_car_number_6: jobNameId, jobSummaryId, jobType = "JOBTYPE_REQUIRED", jobParent, jobMaterial. Mission objectives: Text, Symbol, Main/Sub-objective classification, Hierarchy. Cosmetic but cleanly moddable.

2.12 animWeb — 148 Decls · safe, unusual format

animWeb:ai/tungsten/robot/composite/c08/p1 carries a props block with Editor state (gridSize, showGrid) as well as the content fields models { "characters/robot/base.md6" } and composite { "ai/tungsten/robot/base", }. The large ones (up to 125 kB, subWeb:player/fp_hands/assaultrifle1960) contain the actual state machines. This is the animation state machine for weapons and enemies — powerful but difficult to meaningfully change without an editor.

2.13 modelLOD — 147 Decls · safe, boring

modelLOD:maps/game/wolf/c02/c02p0/megalod_foliage_bush_bush_02_nolod_2.decl: fade = 4, LODs.item[0].distance = 600000, dimShadows = "DIMSHADOW_ON". Practically only vegetation. Visibility/shadows per object.

2.14 tutorialEvent — 127 Decls · safe

tutorialEvent:location/c15: inherit = "location/general", headingText, bodyText (both #str_ references). Together with strings/english.lang (Section 4.3), any tutorial and location overlay can be rewritten.

2.15 ammo — 94 Decls · safe, high utility

ammo:ammo/rocketlauncher — real fields and values:

lowAmmoInClip = 2; lowAmmoInPocket = 3; minRandomCount = 1; maxRandomCount = 2; maxCount = 10; count = 8; itemType = "ITEMTYPE_ROCKETS"; ammoType = "AMMOTYPE_ROCKETS"; projectileDecl = "projectile/rocketlauncher"; weapon = "weapon/assaultrifle1960"; extraFireInterval = 666; initialBurstModeOverride = "BURSTMODE_SINGLE"; burstCountsOverride[0] = 1; giveable = true; secondaryAmmo = true;

Immediately: Maximum ammo per type (maxCount), how much can be collected (minRandomCount/maxRandomCount/count), which projectile fires a specific ammo type (projectileDecl), fire mode overrides. This is the lever for "more ammo" without Cheat-Cvars.

2.16 secrets — 78 Decls · safe

secrets:secrets/c11p2/wyatt:

map = "game/wolf/c11/c11p2";
layers = { num = 1; item[0] = "layer/tungsten/timeline/wyatt"; }
secrets = { num = 0; // remember to increase this
  // item[  0 ] = { id = 1157; type = "SECRETYPE"; entityName = "YOUR_ENTITY";
  //                name = "#str_empty"; desc = "#str_empty"; }
}

The commented-out template in the original shows the schema: id (number), type, entityName (name of an Entity from the .entities file), name, desc. The id values reappear in enigma (Section 3.3).

2.17 skins — 66 Decls · safe

skins:md6/models/items/paper/paper_01: names { "models/items/paper/paper_01" "models/items/paper/paper_01_2" } — Material replacement pairs. Combined with the already used material swap, this allows skinning entire models instead of individual materials.

2.18 flare — 66 Decls · safe

flare:tl/simple03: subflares.item[0] with width, height, color.w = 0.4, mtr = "textures/w_lensflares/blobexppos2". Lensflares enlarge, desaturate, or disable.

2.19 achievement — 50 Decls · safe but pointless

achievement:achievement_08: achievementName, description, id = "GAME_ACHIEVEMENT_08", trigger.item[0] = "TAID_RELEASE_FRIEND". The trigger name is changeable, but Steam achievements are server-side validated — worthless as a modding target, useful as a reference guide.

2.20 inventoryItem — 47 Decls · safe

inventoryItem:inventory/items/c11/mysteriousorb: internalName, icon, needIcon, haveIcon, usable, giveable, dropable, stackable, price, sellPrice, playerCanSell, playerCanSeeInInventory. Simpler: itemUse = "INVENTORY_USE_NONE" and giveItemsOnReceive. This allows quest items to be collectible or drop-able.


3. The three concrete traces

3.1 gamemodesp — the way around the Cvar ban · likely, untested

All 5 Decls, measured:

Decl startingHealth startingArmor gameModeFlags
gamemode/campaign 100 0 Field missing
gamemode/999 999 0 FLAG_AMMOUNLIMITED FLAG_NOOVERCHARGE
gamemode/walkinthepark 100 0 FLAG_HIDEHUD
gamemode/hardcore 100 0 FLAG_HEALTHARMORREMOVED
gamemode/ironman 100 0 FLAG_ONELIFE

The four bonus modes additionally carry gameModeType, gameDifficulty (DIFFICULTY_NIGHTMARE or DIFFICULTY_HARD), displayName, description, menuHelp, menuUnlockMaterial.

The complete Flag Enum — from WolfNewOrder_x64.exe, qualified names idDeclGameModeSP::FLAG_*, contiguous in the string pool at 0xdefa.. directly after the GAMEMODE_* enum:

FLAG_NONE  FLAG_AMMOUNLIMITED  FLAG_HIDEHUD  FLAG_ONELIFE
FLAG_NOOVERCHARGE  FLAG_HEALTHARMORREMOVED

There is nothing more. Five effective flags. The field schema of the Decl type stands as a Reflection table in the binary (0xce6127):

idStrId displayName · idStrId description · idStrId menuHelp ·
GameModeSP gameModeType · gameDificulty_t gameDifficulty ·
int startingHealth · int startingArmor · int enigmaIndex ·
idDeclGameModeSP::GameModeSpFlags gameModeFlags · idMaterial menuUnlockMaterial

Notable: enigmaIndex exists as a field but is not present in any single released Decl.

The fact that flags are read at runtime is verifiable: idGameLocal leads, according to the reflection table (0xcaa737), to an array idDeclGameModeSP *[5] gameModesSP as well as the fields currentGameMode and currentGameModeFlags. The five Decl names appear as a static table in the Binary (0xffba67) in Enum order: gamemode/campaign, gamemode/999, gamemode/walkinthepark, gamemode/hardcore, gamemode/ironman. Index 0 is the normal campaign. The debug output block at 0xf54968 prints StartingHealth and AmmoUnlimited alongside GameModeSP/gameDificulty_t.

What the flags mean is stated by the game itself in file:strings/english.lang, #str_menu_gamemode_1_description:

"Play Wolfenstein in 999 mode. \n- 999% more action \n- start with 999 health \n- unlimited ammo \n- ÜBER difficulty"

Two buildable paths:

  1. gamemodesp:gamemode/campaign receives startingHealth = 999 and a gameModeFlags = "FLAG_AMMOUNLIMITED". Since the field is missing from campaign, this can only be done as a full replacement ("file"), not as a set — set requires an existing path. The field belongs to the Decl type (four other Decls carry it), so the risk is low.
  2. Set startingHealth in gamemode/campaign to a high value using set — a single line that should work immediately.

The Cvar g_infiniteAmmo is listed in wolfsdk/cvars.py::RETAIL_BLOCKED (measured: WARNING: g_infiniteAmmo CANNOT be set in retail!). The Decl path completely bypasses this restriction because it does not touch any Cvar.

Untested. The game was not started for this investigation.

3.2 faction — Fomenting conflict between factions · probable

All 5 Decls, complete:

Decl Relationships Other
faction/auth faction/player → ATTITUDE_HATE, faction/resistance → ATTITUDE_HATE factionNameId = "#str_people_with_radical_political_views"
faction/player faction/auth → ATTITUDE_HATE
faction/resistance faction/player → ATTITUDE_LIKE, faction/auth → ATTITUDE_HATE
faction/neutral none
faction/auth/panzerhund none parentFaction = "faction/auth"

Structure: edit.relationships.relationships.num + item[N].otherFaction / item[N].attitude. Nesting is truly double (relationships twice) — this is not a typo.

The complete Attitude Enum from the Binary: ATTITUDE_UNKNOWN, ATTITUDE_IDOLIZE, ATTITUDE_LOVE, ATTITUDE_LIKE, ATTITUDE_NEUTRAL, ATTITUDE_DISLIKE, ATTITUDE_DESPISE, ATTITUDE_HATE, ATTITUDE_MAX. Eight usable levels; the game uses only three.

Who belongs to which faction is stored in entityDef as faction.myFaction. Measured across all 1,173 entityDefs — 288 hits:

faction/auth              237
faction/player             31
faction/resistance         14
faction/auth/panzerhund     6

Buildable: The Panzerhund has its own faction with parentFaction, but no relationships of its own. If one were to assign a relationships block to faction/auth/panzerhund with faction/auth → ATTITUDE_HATE, Panzerhounds would attack the guards. This is the cleanest lever: a faction that already exists, is already tracked separately, and already has six entityDefs.

Alternatively: assign a new faction to one of the 237 faction/auth enemies. Unclear whether the engine accepts a faction not present as a name in the Binary — searching for faction/ in the Exe yields zero hits, so factions are resolved purely via Decl names. This suggests that new faction names will work, though it does not prove it (a new faction asset cannot be created with the current patcher anyway, only existing ones can be replaced).

Both changes are full replacements, not set — they add fields.

3.3 enigma — Unlock bonus modes · probable

Four Decls, each:

enigma:tab0 → gameMode = "gamemode/999"
enigma:tab1 → gameMode = "gamemode/walkinthepark"
enigma:tab2 → gameMode = "gamemode/hardcore"
enigma:tab3 → gameMode = "gamemode/ironman"

Each with codes.num = 2 and per code requiredSecrets.num = 9 plus nine numeric IDs (tab0 requires, for example, 120, 121, 122, 140, 141, 142, 160, 202, 320). Total: 4 × 2 × 9 = 72 secrets for all four bonus modes.

The IDs are the same ones assigned by the secrets Decls (Section 2.16).

Buildable: requiredSecrets.num = 0 in all four — this would be a pure set on existing paths (8 values). Whether the engine considers "0 required secrets" as "fulfilled" or "never fulfillable" is unclear. Alternatively: set all 9 IDs per code to an ID obtained early in the game. This is also a pure set and semantically unambiguous.

This is the more elegant cheat path than 3.1: instead of bending the campaign, you unlock the 999 mode, which the game itself provides.


4. Weapon Locations, Starting Equipment, Enemy Placement

The direct answer to the third question — and the largest unexplored area overall.

4.1 .entities — 25 Maps, 69 952 Entity Blocks · presumed

As file assets in the archive, plain text in Decl dialect:

entity {
    entityDef foliage_bush_bush_02_nolod_1 {
    inherit = "foliage/bush/bush_02_nolod";
    class = "idEntityTree";
    expandInheritance = false;
    edit = {
        renderModelInfo { model = "..."; megatexturedModel = true; traceGroup = 10; }
        spawnPosition = { x = -224; y = 968; z = -384; }
    }
}
}

Measured across all 25 maps (inherit targets):

Category Count
ai/… (Enemy Spawns) 1 167
prop/weapon/… 467
prop/health/… 569
prop/ammo/… 333
prop/secret/… 284
player/start 235
prop/armor/… 176
triggers/trigger 1 529
target/… total 21 269
func/… total 18 566

Concrete examples: prop/weapon/assaultrifle1960 62×, prop/weapon/knife 55×, prop/weapon/shotgun 43×, prop/health/medpacks/small 193×, prop/ammo/heavy/small 89×, prop/secret/enigmacode 65×, prop/secret/gold 50×. Enemy examples: ai/tungsten/c13/part_01/rifle/spacemarine 71×, ai/tungsten/c06/part_01/rifle/blackguard_elite 51×, ai/tungsten/kamphund/kamphund46 20×.

With this, everything can be changed: place a weapon earlier (change the inherit of a prop/weapon entry), swap an enemy (change the inherit of an ai/… entry), shift position (spawnPosition), remove an enemy, double ammo.

The limitation, measured: In-Place patching practically always fails. maps/game/wolf/c01/c01p1.entities is 2 356 914 B uncompressed at csize = 159 750; our own Deflate of the same original yields 159 322 B — 428 Byte headroom. For c02p0.entities and c02p0.script: 0 Bytes. Any real change thus forces a complete archive rebuild (Installation.apply can do this, rebuilds path in wolfsdk/patch.py), meaning: rewrite the entire chunk file. c01p1.entities resides in chunk1 (73 MB), c01p2.entities in chunk2 (368 MB). Feasible, but slow — and revert must then replay the full copy.

4.2 .script — the Script VM · presumed, unverified

37 script files as file assets (32 map scripts + 5 global), also plain text. file:maps/game/wolf/c02/c02p0.script (415 B):

void main() { }

void call_freelook( entity activatedEntity, entity activator )
{
    $thirdPersonHands_0.setViewAnglesFromCamera();
    $thirdPersonHands_0.attachLimitViewCamera( "camera", 5, 1, 10.0f, 0.0f );
}

file:script/script_events.script (246 921 B) declares 913 scriptEvent signatures. Among them:

giveInventoryItem removeInventoryItem removeAllInventoryItems itemInInventory numOfItemTypeInInventory setHealth getHealth increaseHealth decreaseHealth resetHealth spawn getLastSpawned teleport respawn respawnWithFade kill killAI killByType radiusDamage damage setTakesDamage equipBestWeapon dropWeapons enableWeapon disableWeapon inhibitWeapon spawnLootBox startDreamMode endDreamMode

The Engine translates at runtime: idCompiler, Compile failed in file %s., ---------- Compile stats ----------, Exceeded maximum allowed number of functions (%d), the Opcode set (OP_PUSH_ENT, OP_GOTO, …), and the Cvar script_scriptEventsPath ("If set, tells engine to load script_events.script from specified location"). There is no bytecode cache in the archive — only the .script source texts.

This is by far the most powerful unused lever: a single line $player.giveInventoryItem("weapon/laserkraftwerk"); in main() of a map would be a Loadout Cheat without any Cvar. Unverified — neither built nor started.

Practical note: the five global scripts (script/script_main.script, script_util.script, script_defs.script, script_events.script, debug_drawtext.script) lie in all 13 Chunks — a patch to them would rewrite all 13 archives (~2.7 GB). The map scripts lie each in exactly one Chunk. So always change the map script, never the globals.

4.3 strings/*.lang — all texts · safe

file:strings/english.lang (868 273 B), UTF-8 with BOM, CRLF:

{
    "#str_achievement_00_name"  "Wolfenstein master"
    "#str_menu_gamemode_1_title"    "999"
}

Every #str_ reference from every Decl lands here. Complete renaming of weapons, missions, subtitles, and menus. Six languages available (English, French, Italian, Polish, Russian, Spanish).

Another reservation than 4.1, not the same. .lang lies in all 6 entries raw in the archive (csize == usize), although Deflate would compress it to 28% — measured in UI-Assets.md §3. Thus the Deflate headroom calculation from 4.1 does not apply, but rather the raw write path in resources.plan_in_place(): It places the bytes unchanged at the offset, demanding for this exactly the same length. Practically this means byte-length-true replacement — "CONTINUE" can become "WEITER ", not "WEITERSPIELEN". No rebuild needed. Whoever instead runs a rebuild converts the entry from raw to Deflate, and whether the Engine tolerates it is not measured.

4.4 Starting equipment: entityDef:player/game/wolf/… · safe

31 player*-entityDefs carry startingInventory — one per chapter section plus player, chapter_common_default, and chapter_start_default as base. Measured num distribution:

num Number of Decls
0 3
1 17
2 5
3 1
4 1
5 2
6 2

Minimal form, entityDef:player/game/wolf/c01/c01p1:

startingInventory = { num = 1; item[0] = {
    startSlot = "EQUIPPED"; inventoryDecl = "weapon/knife46cutonly"; } }

Full form, entityDef:player/game/wolf/c16/c16p0 — delivered, not constructed:

startingInventory = { num = 6;
  item[0] = { startSlot = "BACKPACK"; inventoryDecl = "weapon/knife"; }
  item[1] = { startSlot = "BACKPACK"; inventoryDecl = "weapon/laserkraftwerk"; }
  item[2] = { startSlot = "EQUIPPED"; inventoryDecl = "weapon/assaultrifle1960"; }
  item[3] = { startSlot = "BACKPACK"; inventoryDecl = "weapon/shotgun"; }
  item[4] = { startSlot = "BACKPACK"; inventoryDecl = "weapon/ar60marksman"; }
  item[5] = { startSlot = "BACKPACK"; inventoryDecl = "weapon/handgun"; } }

entityDef:player/game/wolf/c11/c11p1 (num = 5) additionally shows that non-weapons can also be placed there: item[3].inventoryDecl = "weaponupgrades/shotgun_shrapnel".

This definitively answers the question regarding starting equipment: startSlot knows at least "EQUIPPED" and "BACKPACK", while inventoryDecl accepts any weapon/ or weaponupgrades/ name, with multiple entries being populated.

Additional measured starting weapons: c01p2/c01p3 → weapon/knife46, c02p0/c02p1 → weapon/kitchenknife, c03p1/c03p2 → weapon/knife, c03p3 → weapon/specialweapon/teatray.

The existing mod wolfsdk.widerstand already utilizes this field — but only on the AI side (entityDef:ai/tungsten/c06/part_01/rifle/airforce → edit.startingInventory.item[0].inventoryDecl = weapon/ai/shotgun).

The player side remains unused. Two approaches:

  • Surgical (set) on a chapter that already has enough slots: Change edit.startingInventory.item[4].inventoryDecl from c11p1 or c16p0 to another weapon. Immediately executable, single line.
  • Full replacement for the early chapters: copy the startingInventory block from c16p0 to c01p1 = play with a laser power plant from minute one. Player Decls are ~28 kB, so rather than manual work, a generated full replacement (build_*.py) is more appropriate.

Also on the player Decl and unused: playerHealth.components.components[1].cur (used by example mod example.dev_loadloadout), maxTimeUnderwater.value = 50000, sprintAirReductionScale = 1, suffocationDamage = "damage/base/suffocation".

4.5 playerUpgradeAmmo — 12 Decls · safe

playerUpgradeAmmo:upgrade1:

{ inherit = "upgrade0"; edit = { slots = {
    slots[ 1 ] = { type = "AMMOTYPE_LIGHT"; amount = 10; }
    slots[ 2 ] = { type = "AMMOTYPE_HEAVY"; amount = 20; } } } }

Perk tiers for ammo capacity. Increasing amount means carrying more ammo, without cheating.

4.6 weaponUpgrade / laserCutterUpgrade — 17 Decls · safe

weaponUpgrade:weaponupgrades/shotgun_shrapnel: internalName, entityDef = "prop/inventory/upgrades/shotgun_shrapnel", weaponToUpgrade = "weapon/shotgun", lockUpgrade = "UPGRADES_SHRAPNEL", giveable, dropable, removeOnUse, usable, singular, useOnReceive, upgradeWeaponMode.

Reloading weaponToUpgrade means: applying an upgrade to a different weapon. playerProps:player/default lists all 17 Upgrade Decls under upgradeData — there the mapping resides.


5. Small Types with Disproportionate Leverage

Type Count Description Assessment
footstepEvents 1 sneakEventDecl = NULL with comment "We set all but landEventDecl to NULL as we don't want the AI to hear anything but landings". Set to "base/footsteps/walk" → Enemies hear the player sneaking. safe, single line, immediately noticeable
aiBehavior 36 dodging.gunfireDodgeCoverChance, painDiveCoverChance, gunfireFlinchChance, usesSearch, usesAvoid, hasCrouches, closeMeleeDist, minChargeDistance, aimOffset, rolePreferenceOrder, forwardCoverCaps.rifleCoverCaps.crouchCaps.{fireOver,blindfireLeft,peekOver,hide} safe, the actual AI lever
aiEvent 39 aiEvent:base/misc/body: eventClass = "AIEVENT_BODY", priority = "AIPRIORITY_VERY_LOW", radius = 256, duration = -1, attached, instigatorStimulus safe — Perception radii for corpses, gunfire, alarms
aiTurnParms 6 maxAngle = 1.3 safe, trivial
trackingParms 6 kickScale, rate.value = 50.0, acceleration, deceleration, springMaxLength = 128.0 safe — Tower/drone target tracking
twitchPain 4 damageDirectionGroups.item[N].damageDir = "DAMAGEDIR_FRONT" + jointGroups.item[N].aliasName safe, supplements gore work
globalflag 1 17 named progress flags with saveID, e.g., flag_c04_lasercutter_upgrade, flag_c04_secret_locker safe to read, effect of change unclear
health / playerArmor 18 / 11 itemType = "ITEMTYPE_HEALTH", armorAmount = 5 safe
gore 12 only inherit chains (soldier_generic_heavy ← soldier_generic), empty edit safe, but empty — content sits in goreBehavior (used)
specialEvent 1 specialEventType = "SPECIAL_EVENT_VAPORIZE" safe, a value
lootPool 1 { } — completely empty nothing to retrieve
destructiblePiece 22 default = { }, many empty likely nothing to retrieve
credits 1 creditList.item[N].{entryType,localizedStr,entry0} safe, cosmetic

6. What is demonstrably impossible

  1. particle (1,563 Decls). Known and measured: the engine streams particles as named resource blocks with pre-calculated size; every change is rejected (idFile_RingBuffer file '<name>.bin' skipping <n> bytes), measured at 35 skips against 0 in the original. Confirmed by the filesystem side: base\generated\decls\particle\*.bin contains the written streams (e.g., wolf/blood/takedownblood01.bin). Identical usize is insufficient; csize must also match. Replacing remains the reference to a particle (in fx, md6Def, breakable, entityDef) — not the particle itself.

  2. Virtual-Texture-Pixel. Materials with usevirtualmapping 1 retrieve their image data from virtualtextures/*.pages, not from the archive. The material Decl is changeable, but the pixels behind it are not.

  3. chapter17 / Map xa01. chapter:chapter17 is CHAPTERTYPE_SIDEMISSION with map = "game/wolf/xa01/xa01". Searched across all 25,559 text assets: xa01 appears in exactly three locations — chapter:chapter17, mapInfo:game/wolf/xa01/xa01 (Content: { edit = { } }), and the six .lang files. There is no maps/game/wolf/xa01/xa01.entities. The map is not in the game. No Decl intervention retrieves it back.

  4. Creating new assets. Installation.apply replaces existing entries; there is no path that inserts a new (type, name) entry into the index. Everything following applies only to existing assets. A new enemy type, a new weapon, a new faction: not without patcher extension.

  5. In-Place-Patch of large text assets. Measured (Section 4.1): the Deflate playroom is 0–428 bytes. .entities, .script, and .lang always enforce a chunk rebuild.


7. Where Uncertainty Remains

Explicitly marked as unclear and not glossed over:

  • Whether the Retail renderProg HLSL is translated at runtime (2.10).
  • Whether requiredSecrets.num = 0 counts as "fulfilled" (3.3).
  • Whether a faction name works that the Binary does not know (3.2).
  • Whether script_scriptEventsPath can be set in Retail — the CVar is not listed in the measured RETAIL_BLOCKED list, but this list was derived from a limited sample.
  • Which of the 810 renderParm values appear visible (2.5).

None of these were tested during an actual game session. For this survey, the game was not launched and no mod was applied.