Teardown

Created: 2021-11-27 Updated: 2021-12-04

I immediately fell in love with the game Teardown. It features a per-voxel destruction model that are the sort of thing I dreamed about being able to play as a child. Though the timed levels are a bit too challenging for my casual gaming these days, I’m really impressed with the way Teardown turns destruction into a puzzle.

screenshot of a sweet explosion from teardown game

The photo mode is super cool for capturing images like the above.

Even better, you can create new levels with MagicaVoxel, the free voxel art editor. I expect big things to come out of the community around this.

My kids prefer to play it in Sandbox mode, so we needed an easy way to unlock the levels.

Hackin' the game:

Props to Tuxedo Labs for making this game so friendly to examine!

First off, the completed missions in your save game seem to determine which levels are unlocked in Sandbox mode.

I’m strictly a Linux guy these days, but still keep a Windows box for gaming, so on my install, the savegame.xml file can be found here:

Windows: C:\Users\<username>\AppData\Local\Teardown\savegame.xml

The <mission> tag contains the individual mission progress (score, timeleft, etc) in a separate container tag for each mission:

<registry version="0.9.0">
	<savegame>
		...
		<mission>
			<mall_intro value="1">
				<score value="3"/>
				<timeleft value="-1.0"/>
				<missiontime value="2.3"/>
			</mall_intro>
				<mall_foodcourt value="1">
				<score value="3"/>
				<timeleft value="-1.0"/>
				<missiontime value="2.3"/>
			</mall_foodcourt>
			...
		</mission>
		...
	</savegame>
</registry>

As near as I can tell, the value attribute on each individual mission itself determines whether or not the mission is complete.

I tested it, and sure enough, just a list of missions with values set to 1 will open up a level for the sandbox. So, how do we get a list of the missions? A simple search for the game files (as installed by Steam) reveals this path on my installation:

C:\Program Files (x86)\Steam\steamapps\common\Teardown\

<RANT> By the way, how stupid is the default Windows display of search results where the full path to the results is buried. On what planet would I not want to see the path of the result by default? Who thought these defaults were a good idea? What on Earth is going on in Redmond? Holy crap. There’s no way it would have been like this in the Win 95 days, let alone back in Win 3.1 when they put serious research into UI/UX standards. </RANT>

Anyway, it didn’t take much digging to find data/missions.lua in the game directory tree. And inside that, every mission name exists in a line of Lua like so:

gMissions["marina_demolish"] =
{
	level="marina",
	file = "marina.xml",
	layers="marina_demolish secrets",
	...

}

gMissions["marina_gps"] =
{
	level="marina",
	file = "marina.xml",
	layers="marina_gps secrets",
	...
}

If I were on a UNIX system, I would use an existing tool like grep, awk, sed, or Perl to extract these mission names and turn them into XML entries in savegame.xml. But I’ve got gVim on this Windows box, and that’s gotta be more than enough on its own.

Yup, a quick search reveals this awesome stackoverflow answer:

:g/^match/yank A

Where ^match is a regex to match the lines we want to yank, and everything else is verbatim ready to go. What it performs is a (g)lobal command to match the regex and yank each full line of the result. The register to yank to is capitalized "A", which tells Vim to append to the register rather than overwriting it. What we end up with is a grep-like result in our a register. I’m at the "writing plugins" level in Vim and I always feel like I’ve only scratched the very surface of what’s available…​

At any rate, now it’s a "simple matter" of block selection (Ctrl-v), find/replace (:'<,'>s///), or recording macros (qx…​.q, @x, etc.) to turn the gMissions lines into XML entries. I ended up doing all three.

And here’s the final result, which gives you all of the levels in Sandbox mode as of today (check the Updated date at the top of this article).

Here it is. You can replace your current <mission> values with this or add missions piecemeal:

        <mission>
            <mall_intro value="1"/>
            <mall_foodcourt value="1"/>
            <lee_computers value="1"/>
            <lee_login value="1"/>
            <lee_safe value="1"/>
            <lee_tower value="1"/>
            <lee_powerplant value="1"/>
            <lee_flooding value="1"/>
            <marina_demolish value="1"/>
            <marina_gps value="1"/>
            <marina_cars value="1"/>
            <marina_tools value="1"/>
            <marina_art_back value="1"/>
            <mansion_pool value="1"/>
            <mansion_art value="1"/>
            <mansion_fraud value="1"/>
            <mansion_safe value="1"/>
            <mansion_race value="1"/>
            <caveisland_computers value="1"/>
            <caveisland_propane value="1"/>
            <caveisland_dishes value="1"/>
            <frustrum_chase value="1"/>
            <factory_espionage value="1"/>
            <caveisland_ingredients value="1"/>
            <mall_shipping value="1"/>
            <frustrum_tornado value="1"/>
            <carib_alarm value="1"/>
            <carib_barrels value="1"/>
            <carib_destroy value="1"/>
            <carib_yacht value="1"/>
            <mall_decorations value="1"/>
            <frustrum_vehicle value="1"/>
            <factory_tools value="1"/>
            <mall_radiolink value="1"/>
            <frustrum_pawnshop value="1"/>
            <factory_robot value="1"/>
            <lee_woonderland value="1"/>
            <factory_explosive value="1"/>
            <caveisland_roboclear value="1"/>
            <cullington_bomb value="1"/>
        </mission>

Enjoy!