Zombie Outbreak Simulator (3DS)
Zombie Outbreak Simulator
Sobre el proyecto
Zombie Outbreak Simulator es un videojuego de simulaci�n publicado por Fan game para Other, lanzado en 2013.
Información oficial del proyecto
ZOS-3DS
An unofficial port of Zombie Outbreak Simulator (Binary Space, Android) to the Nintendo 3DS, built with devkitARM, libctru and citro3d.
It runs the real game. The Android build's C++ was decompiled and ported class by class, and its art, sound and maps are converted from the APK. It is not a remake.
The game's art, sound and maps are not in this repository, apart from the HOME Menu icon, banner and banner sound made from them. To build the port yourself you need your own copy of the Android game; see Getting the assets.
Features
- The whole game on the bottom screen: the 5 built-in maps, the outbreak settings, every action (bombs, soldiers, helicopters and the rest), the tutorial and the credits. Everything the Android version sold or unlocked with ads is unlocked.
- The stats on the top screen: the counters, the population graph and a minimap.
- The 15 online city maps with satellite imagery from Esri World Imagery. A map downloads whole in the background the first time it is played, and is then kept on the SD card.
- Player maps of anywhere. The game's own map server is gone, so the port
makes them on the 3DS:
- browse the imagery, press New map and place the square;
- the collision (buildings, roads, water) comes from OpenStreetMap;
- the map's imagery downloads with it, so it plays without the network;
- Search (X) finds a place by name. The top screen shows how much of the imagery in view has loaded.
- Saving: the game saves on START, HOME and sleep, and goes back to the saved game the next time it starts.
- Positional sound (optional): SELECT pans each sound effect towards where it happens on the map. It is off by default, as in the original, and the setting is remembered.
- New 3DS: the game runs in the 178 MB memory mode at 804 MHz.
Left out, because they are Android services: ads, in-app purchases, video unlocks and sharing.
Tested on a New 3DS XL and on the Azahar emulator. An Old 3DS gets a smaller memory mode and has not been tested.
Controls
| Input | In game |
|---|---|
| Stylus | Menus and buttons; drag to pan the map; tap to use the chosen action |
| Circle Pad / D-pad | Pan |
| R / L | Zoom in / out |
| B | Cancel the chosen action |
| Y | Evacuate the waiting helicopter |
| SELECT | Positional sound on or off |
| START | Save and quit |
On the map select screen:
- X searches for a place.
- While you place a new player map, A downloads it and B cancels.
Installing a release
You need a 3DS with custom firmware (Luma3DS), and either FBI (or another CIA installer) or the Homebrew Launcher.
- Install
ZOS-3DS.ciawith FBI. Or copyZOS-3DS.3dsxtosdmc:/3ds/and start it from the Homebrew Launcher. The.ciais the better choice: it gets the New 3DS's large memory mode, and it has a HOME Menu icon. - For sound, the SD card needs
sdmc:/3ds/dspfirm.cdc. If it isn't there, dump it once with DSP1. - The online maps and player maps need Wi-Fi the first time they load. After that they are on the card.
What the game writes to the SD card:
- saves and map imagery in
sdmc:/ZombieOutbreakSim/(it makes the folder); - its log in
sdmc:/zos_debug.txt.
Updating from 1.0.0: install the new CIA over the old one; saves and player
maps carry over. 1.0.0 kept its imagery as one small file per tile in
sdmc:/ZombieOutbreakSim/cache/imagery/. 1.1.0 keeps one file per map, and
copies a map's tiles across from the old folder the first time the map is
opened. Once you have opened your maps, you can delete the old folder from a
PC to free the space; it is optional.
On a New 3DS, the system restarts into the 178 MB mode when the game starts and back to the HOME Menu when it ends.
Building from source
Requirements
-
Windows. The build script is PowerShell. To build by hand on another system, see Building without the script.
-
devkitPro, installed to
C:\devkitPro, with the 3DS packages and the port libraries. From devkitPro's MSYS2 shell, run:pacman -S 3ds-dev 3ds-curl 3ds-mbedtls 3ds-zlib3ds-devbrings devkitARM, libctru, citro3d, picasso, tex3ds and mkbcfnt. -
Python 3 with Pillow.
certifiis optional: pip's own copy is used without it.pip install pillow -
ffmpeg on
PATH, to convert the audio. -
makerom and bannertool, which aren't in devkitPro's packages. Put their Windows builds in
tools/3ds-bin/:makerom.exefrom Project_CTR's releases (makerom v0.18.4 or later);bannertool.exefrom bannertool's releases (v1.2.2 or later).
Getting the assets
-
Get the APK. Copy the game's APK from an Android device it is installed on, to
APK and Source/Zombie Outbreak Simulator.apkin this repository. With adb:adb shell pm path com.binaryspacegames.zombieoutbreaksimulatoradb pull /data/app/<the path it printed>/base.apk "APK and Source/Zombie Outbreak Simulator.apk"The port was made from version 1.6.4. That APK is about 70 MB, and its SHA-256 is
8005c00823422574c0951d84b1d3a1ce97992b698e38c5feb7bb2173d8cc67a0. Other versions may differ.- A split install keeps the game's
assets/inbase.apk, which is all the build needs. - The reverse-engineering tools also read
lib/armeabi-v7a/libZombieOutbreakSimulator.so. A split install keeps that in its ownsplit_config.armeabi_v7a.apk.
- A split install keeps the game's
-
Convert the data into
out/ZombieOutbreakSim/:python tools/prepare_data.py- The first run takes about 20 minutes and writes about 126 MB. Later runs only redo what changed.
- The textures become
.t3x, the sounds.wav, and the font.bcfnt. docs/data.md says what is converted, and why. --azaharalso copies the result onto the Azahar emulator's SD card.
-
The HOME Menu icon, banner and banner sound are already in
3DS Files/meta, made from the game's launcher icon, its home screen's logo and one of its zombie moans. To remake them from your APK:python tools/make_meta.pypython tools/banner_sound.py
Building
powershell -ExecutionPolicy Bypass -File tools/build_cia.ps1
This builds 3DS Files/ZOS-3DS.cia and ZOS-3DS.3dsx (about 124 MB each).
The game's data is in their RomFS, so they contain Binary Space's art and
sound.
powershell -ExecutionPolicy Bypass -File tools/build_cia.ps1 -NoData
This builds the engine alone, about 1 MB. It reads the data from the SD card
instead, so copy out/ZombieOutbreakSim/ to the card's root, as
sdmc:/ZombieOutbreakSim/. If the data is missing, the game says which file
it looked for and waits for START.
-DriveLetter Y: picks the temporary drive letter (see below).
Building without the script
The Makefile can't run from a path with a space in it, and the project folder
is 3DS Files. The script works around that:
- It maps a temporary drive letter onto the folder with
subst. - It links
3DS Files/romfstoout/ZombieOutbreakSim(a junction). - It runs
make ciain devkitPro's MSYS2 shell.
By hand, on Windows, map the drive first:
subst Z: "C:\path\to\ZOS-3DS\3DS Files"
Then link the data, so 3DS Files/romfs points to out/ZombieOutbreakSim:
mklink /J "C:\path\to\ZOS-3DS\3DS Files\romfs" "C:\path\to\ZOS-3DS\out\ZombieOutbreakSim"
Then, in devkitPro's MSYS2 shell:
cd /z && make cia ROMFS=romfs
Leave out ROMFS=romfs for the build without data. Afterwards, remove the
drive mapping:
subst Z: /D
On Linux or macOS:
- Build from a path without spaces, for example through a symlink.
- Use native builds of
makerom and
bannertool, passed as
make cia MAKEROM=... BANNERTOOL=.... - The Python tools look for devkitPro's tools under
$DEVKITPRO.
Running on Azahar
- Open
ZOS-3DS.3dsxin Azahar (File > Load File). - A
-NoDatabuild needs the data on the emulator's SD card:python tools/prepare_data.py --azaharputs it there.
To boot it and check it automatically, run:
powershell -ExecutionPolicy Bypass -File tools/run_azahar_test.ps1
The script boots the build, saves screenshots to %TEMP%\zos_azahar, and
judges the run from the game's log.
How the port works
The Android game is cocos2d-x 3.x, with its game logic in C++ compiled into
lib/armeabi-v7a/libZombieOutbreakSimulator.so. The .so keeps its dynamic
symbol table, so Ghidra names every method (Simulation::updatePolice,
ZombieWave::addZombie, and so on).
The port has three layers:
- The game logic, ported from the decompilation as faithfully as
possible:
Simulation,PersonType,ZombieWave,GameOptions, the collision layers, the bombs, the soldiers and the helicopters. Where the game kept data in tables (person types, maps, credits),tools/gen_*.pygenerate the port's source from the.soitself. - A small cocos2d-x subset on the port's own citro3d renderer, so the game's scene and UI classes port with few changes.
- The 3DS platform: streaming the map tiles, touch and buttons, ndsp
audio, the data in RomFS or on the card, HTTPS (libcurl and Mbed TLS),
and the top screen. The downloads, the tile decoding and the player
maps' builder run on a CPU core of their own (the New 3DS's core 2, or a
share of core 1 on an Old 3DS), so they never cost the game a frame. Each
online map's imagery is one pack file, written half a megabyte at a time
(
source/game/tilepack.h).
The decompilation needed some setup:
- Android's armeabi-v7a passes floats in core registers (softfp), and
tools/ghidra_scripts/UseSoftFloatABI.javatells Ghidra so. tools/vtables.pyandtools/signatures.pyrecover the virtual calls and the methods' real signatures.
Comments in the source name the game's code each part was ported from, as
decomp/classes/<Class>.c and Ghidra's addresses. The decompilation itself is
not in this repository: the
reverse-engineering tools make it from your own
copy of the game.
Repository layout
| Path | Contents |
|---|---|
3DS Files/ | The devkitARM project |
3DS Files/source/cocos/ | The cocos2d-x subset (Node, Director, Label, audio, …) |
3DS Files/source/game/ | The game's classes, one file per class, plus the port's (player maps, satellite tiles, top screen) |
3DS Files/source/gfx/ | The citro3d renderer and its shaders |
3DS Files/source/net/ | HTTPS and a JPEG reader for the satellite tiles |
3DS Files/meta/ | app.rsf (the CIA's settings), the icon, the banner and the banner sound |
tools/ | The asset pipeline (prepare_data.py, make_meta.py, banner_sound.py, apk.py), the build script, the .3dsx check, the Azahar runner and the reverse-engineering tools |
tools/ghidra_scripts/ | The Ghidra scripts that tools/ghidra.py runs |
docs/ | The data and its file formats |
These are made locally and are not in git:
APK and Source/(your APK);extracted/(the APK unzipped);out/(the converted data);decomp/(the decompilation, made by the reverse-engineering tools);tools/3ds-bin/(makerom and bannertool);- the build's output.
Reverse-engineering tools
You don't need these to build the port; they are for working on it.
Ghidra setup:
-
Install Ghidra.
tools/ghidra.pylooks for it inGHIDRA_HOME, or by default in a folderghidrabeside this repository.- It looks for projects in
GHIDRA_PROJECTS, or by default in a folderGhidraProjectsbeside this repository.
-
In that projects folder, make a project named
ZombieOutbreakSim. Import the APK'slib/armeabi-v7a/libZombieOutbreakSimulator.so, keep Ghidra's default image base (0x10000), and let it analyse. -
Set the calling convention:
python tools/ghidra.py run UseSoftFloatABI.java --write
| Tool | What it does |
|---|---|
tools/list_game_classes.py | Lists the game's own classes from the .so's symbols (decomp/classes.txt) |
tools/ghidra.py export | Decompiles those classes into decomp/classes/ |
tools/ghidra.py decompile NAME... | Decompiles single functions, by name or address |
tools/ghidra.py collect, tools/layouts.py | Collect every field access to the game's classes, and summarise it per class |
tools/ghidra.py functions, tools/signatures.py | Recover static vs. instance methods and their return types |
tools/vtables.py | The vtables and base classes, from the .so's RTTI |
tools/sodata.py | Reads strings, words and floats at a Ghidra address |
tools/disasm.py | Disassembles at an address or symbol |
tools/collision.py | Draws a map's collision layer over its image |
tools/gen_persontypes.py, gen_mapconfigs.py, gen_credits.py | Generate the port's tables from the game's code |
tools/check_3dsx.py | Rejects a .3dsx that Azahar's loader would refuse (the build runs it) |
Credits
- Zombie Outbreak Simulator is by Binary Space. This is an unofficial fan port, not made or endorsed by Binary Space or Nintendo. If you like it, buy the game.
- Satellite imagery: Source: Esri, Vantor, Earthstar Geographics, and the GIS User Community (Esri World Imagery).
- Map data: © OpenStreetMap contributors (ODbL), through the Overpass API, and Nominatim for the search.
- Libraries: libctru and citro3d (devkitPro, zlib licence), libcurl (curl licence), Mbed TLS (Apache License 2.0) and zlib.
Claude was used to help make this decompilation possible. Specifically, I gave it the APK and it decompiled the game in full, converted it over to 3DS in C++ and I did debugging along with Claude using Azahar, and I did live hardware testing by myself on my New Nintendo 3DS XL. I also did minor Old 3DS testing by tweaking Azahar's settings however otherwise it does not have Old 3DS testing.
The game's art, sound and maps, the data tools/prepare_data.py makes from
them, and the icon, banner and banner sound in 3DS Files/meta, belong to
Binary Space.
License
The port's own code is under the MIT License. The game, and the libraries and services the port uses, keep their own terms: see THIRD-PARTY-NOTICES.md.