Modding

Revision as of 00:53, 5 July 2026 by 172.17.0.1 (talk) (Add the original guide's 57 screenshots (hosted as extension assets))

Downwell is a GameMaker game, and nearly everything about it — sprites, code, sounds — lives in a single data.win file that can be edited with UndertaleModTool. This page is adapted from VirtuaVirtue's Downwell Modding Documentation, with additions from this wiki's own decompilation notes.

Tools required

  • UndertaleModTool — the only tool you strictly need. Download a Stable release ("Bleeding Edge" is newer but less stable).
img00.png
img01.png
  • Any pixel-precise image editor — Paint.NET, Aseprite, even MS Paint.
img02.png

The game data lives at:

C:\Program Files (x86)\Steam\steamapps\common\Downwell\data.win

Make a backup of data.win before editing — you are modifying the game itself.

Tutorial: new upgrades

Upgrades are the items offered at the end of every level. They are the best starting point for modding: little to no coding knowledge required.

Sprites

Each upgrade is one sprite with two frames:

  • Frame 0 — the selection icon shown on the end-of-level choice screen. 24×24 pixels.
  • Frame 1 — the inventory icon shown in the corner once taken. 12×12 pixels.
img03.png
img04.png

Upgrade sprites use at most three colors: red #FF0000, white #FFFFFF and black #000000. The game's palette shaders automatically remap them to the player's chosen palette.

Naming scheme

Name the files as frames of one sprite, e.g. for a "Knuckle Sandwich" upgrade:

sUgSandwich_0.png   (large icon)
sUgSandwich_1.png   (small icon)

UndertaleModTool imports numbered files as frames of the same sprite. Put them alone in a folder.

Importing

  1. Open data.win in UndertaleModTool.
img05.png
  1. Run Scripts → Resource Repackers → ImportGraphics.csx and select your folder.
img06.png
img07.png
  1. Check that a new UndertaleEmbeddedTexture exists (a texture-loading warning at this stage can be ignored, or save and reload).
img08.png
img09.png
  1. Find your sprite in the Sprites section and check its properties — most importantly the origin must be 12×12 so the icons align in the menu and inventory.
img10.png
img11.png
img12.png
img13.png

language.ini

All of the game's text lives in language.ini next to data.win. Add your upgrade's name to the ugName section — the last vanilla entry is ugName22. Entries for the other languages are optional, but without them those languages show a blank name and description.

img14.png
img15.png
img16.png

The upgrade table

Search for upgrades in UndertaleModTool and open gml_Script_scrUpgrades under Code.

img17.png
img18.png
img19.png

This script is the upgrade database: every upgrade in the game is a block of global.ug assignments, with i += 1 between blocks (the index — without the increment you overwrite the previous entry).

Field Meaning
ug[i][0] Name (shown on the choice screen)
ug[i][1] Copies currently owned — the game resets it; leave at 0
ug[i][2] Sprite index. The first sprite a mod imports lands at index 741; add 1 per additional sprite
ug[i][3] Description; # is a line break
ug[i][4] Maximum copies obtainable. The pickers only offer an upgrade while ug[i][1] < ug[i][4] — vanilla entries with 0 here (Dumbbell, Super Charge, Sudden Fortune) are cut content that can never appear. Leave at 1
ug[i][5] Price in gems — only read for the shop consumables (indexes 100–105); dead data for regular upgrades. Leave at 200
ug[i][6] Japanese name
ug[i][7] Japanese description

Copy an existing block to the end of the list, keep the i += 1 above it, and fill in your values.

img20.png
img21.png

Functionality

Search for pug (Player UpGrade) and open gml_Script_scrIncrementPug.

img22.png
img23.png
img24.png
img25.png

It is one large switch over the upgrade index, run when an upgrade is taken. Add a case for your index at the bottom (the 24th item is case 23 — indexes start at 0) and put your effect there.

Tutorial: new styles

Styles are the characters chosen at the start of a run.

Sprites

A style needs a run cycle of 8 frames and an idle animation of 4 frames, at 15×15 pixels, using the same three-color rule as upgrades. Name them so they don't collide with existing sprites, e.g.:

sprPlayerIdleCart_0.png … sprPlayerIdleCart_3.png
sprPlayerRunCart_0.png … sprPlayerRunCart_7.png
img26.png
img27.png

Import exactly as in the upgrade tutorial, then check the sprite properties — here the origin must be 6×6.

img28.png

language.ini

Add the style's name to the styleName section — the last vanilla entry is styleName4.

img29.png
img30.png
img31.png

Wiring it up

Four scripts, all found by searching style:

  1. gml_GlobalScript_styleInit — declares each style's name and animation sprite indexes (index variable s, incremented per style like the upgrade table). Point the animation fields at your imported sprite indexes (double-click a sprite; its index is shown at the bottom right).
img32.png
img33.png
img34.png
img35.png
img36.png
img37.png
img38.png
  1. gml_GlobalScript_styleUpdate — runs when a style is selected and sets the player's stats. Copy an existing case to the end and adjust. Vanilla gunType values are 0–6 (see the weapon table).
img39.png
img40.png
img41.png
img42.png
  1. gml_GlobalScript_styleSet — declares the animations again; possibly never called, but add your style for good practice.
img43.png
img44.png
img45.png
img46.png
  1. gml_Object_PlayMenu_Create_0 (search playmenu) — increment styleMax by 1 so the menu shows your style.
img47.png
img48.png
img49.png
img50.png

Unlocking

A new style starts locked with no unlock condition. Either:

  • add it to the unlock tables — an entry in gml_GlobalScript_unlockGoalNum (shifting the later indexes) and a case in gml_GlobalScript_unlockNotice — or
img51.png
img52.png
img53.png
  • cheat it open: in save.ini (at C:\Users\<you>\AppData\Local\Downwell_v1_0_5) set the gems field, your progress toward all unlockables, to something absurd.
img54.png
img55.png

Reference: weapon stats

New weapons are added in gml_GlobalScript_bStatInitLevel1 by copying an existing weapon's block. Increment gunnum (gunnum += 1) above every new weapon.

img56.png

Most stats are arrays of two values: [gunnum][0] applies without gem high, [gunnum][1] with gem high (typically slightly stronger).

Stat Meaning
bStatName Pickup name, quoted, usually capitalised — e.g. "NOPPY"
bStatGunSprite Letter shown on the collectible: position in the alphabet minus one (11 = "L")
bStatObject Bullet object index — 261 for MACHINEGUN/SHOTGUN/TRIPLE/PUNCHER/BURST/NOPPY, 260 for LASER
bStatBulletSprite Bullet sprite index (LASER: 466 normal, 465 gem high)
bStatSound Firing sound index (LASER: 20 normal, 21 gem high)
bStatMuzzle Muzzle-flash sprite index (SHOTGUN: 603 normal, 602 gem high)
bStatConRate Charge consumed per shot
bStatRof Rate of fire — lower is faster; negatives appear to disable it
bStatRecoil Vertical speed lost when firing
bStatScreenShake / bStatScreenShakeDur Screen-shake strength / duration
bStatDelayKill Unclear; rapid-fire weapons set 1
bStatBurst Burst-fire flag; only SHOTGUN and BURST set 1
bStatBurstRate Delay between burst bullets — lower is faster
bStatBurstAmount Bullets per trigger pull
bStatDamage Damage per bullet (MACHINEGUN: 9 normal, 15 gem high)
bStatSpeed Bullet speed
bStatAccuracy Random spread
bStatPierce 1 = bullets pass through enemies/objects while damaging them (LASER)
bStatWave Unused
bStatExplode Unused by vanilla — set 1 and every bullet explodes; balance accordingly
bStatRangeRandom / bStatRangeTimer Bullet lifetime and its randomisation (how SHOTGUN pellets vanish unevenly)
bStatSpType Appears to control TRIPLE's three-bullet spawn
bStatSpTy13 Undetermined; copy from the closest vanilla weapon
bStatAimAngleAccl / Dccl / Limit Aim rotation speed/deceleration/max angle — only NOPPY aims (limit 25)