This is the unfinished documentation for Madness Interactive Reloaded 0.48.2. It aims to describe the public API of the game and help people contribute to the project and make mods.
The game and engine are written in C#. To understand the programming parts, you are expected to have a basic grasp of C# specifically (if you understand C, C++, or Java, this should be no problem). Other information should be understandable by most people.
Note that all the content on this site is written assuming you are on Windows unless explicitly stated otherwise. No need to worry though, as almost all software used here can be used on Linux the same as on Windows. The differences probably won't be greater than seeing executables end with
.exe
and directory separators facing the wrong way.
This wiki is a work in progress!
Getting started
Building the game
-
Assert you have these requirements
- Windows 10 or 11 or Linux
- git
- .NET 8 SDK
- NuGet
-
Clone this repository
-
Open a terminal inside the repository directory
-
Initialise the submodules
git submodule init git submodule update --remote
-
If you DON'T have Visual Studio
- Navigate to the
src\MadnessInteractiveReloaded
directory and build:cd src\MadnessInteractiveReloaded dotnet build
- Debug the game by typing
dotnet run
into the terminal
- Navigate to the
-
If you DO have Visual Studio
- Navigate to
src\MadnessInteractiveReloaded
directory and open theMIR.sln
solution using VS2022 - Press F5 (or press the ▶ button)
- Navigate to
Console commands
The game engine console can be opened and closed by pressing F12 at any point. It will drop down from the top and show recent output. Just start typing and press Enter to submit. This article will explain every command that can be entered.
Entering any command and providing a question mark (?) as the first and only parameter will print a short description of the command.
Console command names are case-insensitive. However, parameters are case-sensitive.
Command | Description |
---|---|
DebugDrawFloor | Draws the floorline |
DebugDrawWalls | Draws all walls |
DrawAnimationInfo | Draws animation information |
GameMode | Force the game mode of the current level. If no input is given, the current gamemode will be returned |
ListDisks | List all improbability disks |
UnlockDisk | Unlock the improbability disk with the given ID, or "all" to unlock all disks. |
LockDisk | Lock the improbability disk with the given ID |
CurrentLevel | Returns the current level name |
Convar | Set or get a gameplay configuration variable by key. Pass ?? as an argument to print every available key. |
ExportCommandList | Writes all commands and their descriptions to "cmd_list.md" as a Markdown table. Intended for the documentation. |
Crash | Crash the game |
GameVersion | Print the game version |
PhysicsDebug | Toggle physics debug |
WinLevel | Set the body count to the target body count |
Levels | Lists all levels |
SetLevel | Sets the level to the given level name. Enter 'SetLevel ??' to see a list of available level names |
DisableAI | Disables the enemy AI |
EnableAI | Enables the enemy AI |
Benchmark | Start the benchmark sequence |
DevMode | Sets development mode |
God | Set God mode for the player |
StopSound | Stops all playing sounds |
Autospawn | Sets autospawn |
RefillMotives | Refill ammo, health, and dodge |
Volume | Sets or gets the current game master volume, ranging from 0.0 to 1.0 |
Revive | Revives the player |
InfiniteAmmo | Set infinite ammo for the player |
Give | Gives the player the weapon of their choice by codename. Enter 'Give ??' to see a list of available weapon names |
LevelEditor | Opens the level editor scene where developers can edit and create levels |
WeaponEditor | Opens the weapon editor scene where developers can edit and create weapons. Takes an optional filename argument to start editing an existing weapon. |
ArmourEditor | Opens the armour editor. |
ClearDrawCache | Clear the immediate mode drawing cache |
Debug | Opens the given debug scene. Enter '??' as a parameter to see a list of available debug scenes |
Demo | Opens the given demo scene. Enter '??' as a parameter to see a list of available demo scenes |
Timescale | Sets or gets the global time scale. This determines the speed of time-dependent operations |
MainMenu | Set the scene to the main menu |
OnionDebug | Set the Onion UI debug mode. E.g 'GuiDebug DrawBounds RaycastHit' |
ShowStats | Shows some performance stats in the top left corner of the screen. Expects true or false |
Echo | Returns the input string |
Cls | Clears the console |
Quit | Quits the game |
GetFilter | Get the console filter |
SetFilter | Set the console filter. E.g 'SetFilter Error Warn' |
UpsRate | Sets the update rate. Expects an integer. If a number smaller than 0 is given, this will just print the current rate. |
FupsRate | Sets the fixed update rate. Expects an integer. If a number smaller than 0 is given, this will just print the current rate. |
ListSystems | Lists all systems in the scene |
RemoveSystem | Remove the system with the given name |
ListEntities | List all entities in the scene |
ListComponents | List all components in an entity. Expects an integer |
RemoveComponent | Remove a component from an entity. Expects an integer and a string |
RemoveEntity | Remove and entity. Expects an integer |
List | List all commands |
Compositor | Provides some control over the compositor at runtime |
Version | Prints the game and engine versions |
OnionSnap | |
OnionClear | Clears the Onion UI cache, effectively resetting the UI scene |
OnionScale | Sets or gets the global Onion UI scale |
Core concepts and terms
Creating a mod
- Requirements
- Creating a mod template
- Attempt to build and run
- The assets folder
- Scripts
- Mod metadata
- Sharing with others
- Troubleshooting
Requirements
- Visual Studio 2022
- If you don't want to install Visual Studio, dotnet by itself is sufficient (comes with the SDK)
- .NET 8.0 SDK
- Madness Interactive Reloaded
Creating a mod template
Your mod starts with a generated mod template. Mod templates provide scaffolding, allowing you to immediately start programming/drawing your ideas. Open the mod template generator.
You should see these inputs. Your thumbnail is optional, and you can always set it later. Mod name is the name visible to players. Author should be your own name. Mod ID should be similar to your mod name, but as short as possible to make things easier for yourself later. The default values are valid.
Press the download button and save the zip file in your game's mods
folder. If there isn't one, create it. Unzip the archive to its own folder, such that the structure looks similar to this:
- 📁 MIR root directory
- 📁
mods/
- 📁
Your.Mod/
meta.json
Your.Mod.csproj
- etc.
- 📁
- 📁
It is now safe to delete the original zip archive.
Attempt to build and run
Open the .csproj
file using Visual Studio 2022.
It should look something like this. To make sure everything is set up correctly, press F5 to start debugging. This should open Madness Interactive Reloaded and your mod should be visible in the mod menu. If this does not happen, refer to the Troubleshooting section. You should build your mod whenever you change anything. Building is done whenever you start debugging or manually by pressing Ctrl + B, or via the Build menu at the top of the window (Build -> Build Project).
The assets folder
You may have noticed an assets/
folder in your mod. It should be full of more empty folders. This folder structure is a "shadow" of the base game asset folder. This means it contains no actual content, just the scaffolding. When you build the project, the assets folder is "packaged" into an asset package (assets.waa
). This package will appear in your mod folder when you first build.
Most asset types can be created in a text editor like Visual Studio or a bitmap editor like Paint.NET. For more information on how specific assets work, refer to the Assets section. An important mechanic to remember is that, in general, the game will consider the last loaded asset package to be the deciding package. If you add an asset to your asset folder at the same address of an existing base asset, you are effectively replacing the original asset.
For example, if you create a file at assets/textures/main_menu_background.qoi
, it'll be displayed as the main menu background because it also exists in the game's base folder. This "override" mechanic is useful for asset replacement mods. If you create a file that doesn't overlap a base asset, it won't replace anything and simply be added as a new asset.
Most game assets like textures, sounds, etc. have no designated location. You can put them basically anywhere. However, other assets will only be properly registered if they're put in a specific folder. These include:
- Weapons (
data/weapons/*.json
) - Campaigns (
data/campaigns/*.json
) - Levels (
data/levels/*.json
) - Cutscenes (
data/cutscenes/*.json
) - Melee sequences (
data/melee_sequences/*.seq
) - Character stats (
data/stats/*.stats
) - Character looks (
data/looks/*.look
) - Character animations (
data/animations/*.anim
) - Factions (
data/factions/*.json
) - Language tables (
locale/*.json
) - Head armour/skin (
data/armour/head_armour/*.armour
) - Body armour/skin (
data/armour/body_armour/*.armour
) - Hand armour/skin (
data/armour/glove_armour/*.hand
)
When the game launches, these locations are scanned and all valid files are registered.
Scripts
Scripts are written in C#, and your entry point is located in ModEntry.cs
. This file contains comments, so I won't get into it much. For examples, look at WIP.
Mod metadata
The mod folder contains a meta.json
file, which contains basic metadata for your mod. Most of this is already set up by the mod template generator, but you might want to add a proper description as well. The id
field contains your mod ID, which you really shouldn't change unless you absolutely know what you're doing. This ID will be important if you're ever using an in-game editor and want to reference your custom assets.
Your thumbnail file should be either PNG or QOI, square, non-transparent, and ideally somewhere around 256x256 in size. However, these are not enforced and you could technically put a 2000x9000 JPEG in there, although you might encounter issues and I recommend sticking with the guidelines.
Sharing with others
To package and share your mod, you could technically just zip up the whole folder and send it to others. However, it might be desirable to clean up a bit before you do so. Lots of files are actually safe to remove before distribution, because they are only necessary during mod development. Make a backup to continue development later, and you may safely delete:
- The
obj
folder - The
bin
folder - The
.vs
folder - Even the
assets
folder - The
.config
folder ModEntry.cs
- The
.csproj
file
These are not required for the mod to function. In fact, if your mod contains no script at all, you can even delete the .dll
file and remove the binaryPath
line from the meta.json
. This lowers the size of your mod on disk and in memory.
Troubleshooting
ERROR: The command dotnet tool restore
...
It is likely that the tool manifest has been blocked by Windows. Navigate to your mod folder and open the .config
folder. You should see a file called dotnet-tools.json
. Right click it, open Properties, and select "Unblock". Try to build again.
MIR.exe not found
Double check that your mod project is at this address: [mir game folder]/mods/Your.ModName/Your.ModName.csproj
. This is absolutely necessary.
Creating a character animation
Requirements
How to animate MIR animations
In this document, I will explain the contents of the Blender file, how to use it to create proper in-game MIR animations, and finally, how to export those animations into the game. I’m assuming you already know the basics of Blender and its controls, so I won’t go into detail on that unless there are controls that are outside the norm.
If something is explained poorly let me know in the comments below and subsricve ring it beL. 🔔
What is this Blender file?
This is the Blender file I use to animate all of the in-game animations for MIR. Some examples of in-game animations include death animations, melee animations, and jumping animations. Note that in-game animations exclude cutscenes, which are MP4 files. You can animate these in any program as long as they are exported in MP4 format.
When you open the file, you should see this:
What is what
In the viewport, you're currently in the camera view. In the center, you’ll see our little grunt. As you can see, they don't have feet. You don’t need to animate the feet ever, these will be added and procedurally animated in the game. The pose they're in right now is the default pose, like a T-pose but not a T-pose.
Beneath the grunt is a blue line, which represents the floor for death animations. When animating, remember that the Y-axis is up and down movement, while the X-axis is left to right.
To the right of the viewport, you'll see a text editor that seems to contain some hacking-like text. You don’t need to worry about programming, this will be used later when exporting. I'll explain later.
Animating with weird origin points
The grunt in the middle has very specific origin points, do not change these points as they are used in this way in the game. The center of the head is in the bottom left and is marked by a red cross on the texture. The head is parented to the body, do not change this either. The body's origin point is all the way at the bottom, since this is extremely weird to animate with I added an empty called Use for body as pivot point
at the center of the body. This empty can be used to rotate the body at that point.
To do this, first select the body, then the empty. By selecting the empty last, it becomes the "Active Element". Next, go to the "Transform Pivot Point" setting and select "Active Element". Now, when you rotate the body and the empty, it will rotate around the correct pivot point.
There are several empties hidden as you can see in the outliner, these empties exist and are hidden for a very good reason. Do not move, rotate or scale these. Every visible object is very specifically placed relative to these empties.
When you want to create another animation, you can just copy the empty
collection. (This will create an exact copy of the meshes used in the collection, which isn't very clean. To keep things tidy, simply replace the new mesh with the old one and then purge the unused data.)
Exporting to anim files
The game interpolates animation frames linearly, so when you're ready to export, make sure you know what the animation will look like with linear interpolation. Also, the game interpolates only between integer keyframes. While Blender allows keyframes to be placed between frames, this is not possible in the game. So, when you're done animating, ensure that all keyframes are placed directly on the frames.
When you've finished your animation, you'll need to export it into the game. This process is weird but straightforward. To do this, you'll need to use Blender's console. You can open the console by going to the Window
menu and selecting the Toggle System Console
option.
To the right of the viewport, you should see a text editor. At the top of that editor, there's a small play button. If you select a body part and press the play button, text will be generated in the console. This text contains the animation data for the selected body part in MIR.
The console would look something like this:
WARNING, IF TEXT IS SELECTED AND THE PLAY BUTTON IS PRESSED, BLENDER WILL CRASH IMMEDIATELY
.anim
files are animation files for MIR that look like this:
At the top, you'll see some variables. There’s an FPS setting that should match the FPS of the animation in the Blender file, the default is set to 24 FPS. Then there’s the scale, which should absolutely stay at 1, even if you’re animating a mag agent. Speed is self-explanatory.
Below those variables are the body parts and their corresponding animation data. These start with the name of the body part. The first column is the frame number, and the remaining columns represent the XY positions in pixels and the rotation in degrees.
So, all you have to do is copy the generated text from the console into the .anim
file in the correct spot. You’ll notice that HAND shows up twice. To differentiate them, in the Blender file, the hands are named Hand First
and Hand Second
. It should be pretty clear which one goes where.
Animation constraints and hand poses
You might have noticed that it's impossible to animate the hands in Blender, this is because it needs to be done in the .anim
file.
All of the possible hand poses are: fist
, open
, pistol
, point
, rifle
, stock
, and finally underside
. If you want a hand to change to a pose, just write the specific pose into the frame of the hand you want to change. For example, if you want the hand to change to an open
pose at frame 10, you write the word open
into that frame in the .anim file, after the position and rotation.
The default hand pose, if no other pose is specified, is fist
.
Some animations like jumping animations, must prevent the actor from performing certain actions. For example, a jumping animation needs to prevent the actor from punching, since these animation will interrupt each other. This is why animation constraints exist. You need to add the correct animation constraint depending on the specific action the actor is perfoming when your animation is played. These constraints can be placed at any body part in the .anim
file.
Here are all of the animation constraints that you can use:
AllowAll
Character can do anything.
PreventAll
Character can't do anything.
PreventDying
Makes the character immortal.
PreventWalking
Prevents the character from walking in any direction.
PreventAiming
Prevents the character from aiming their weapon around. The aiming direction will stay as it was before the constraint was set.
PreventDodge
Prevents the character from dodging.
PreventShooting
Prevents the character from shooting their weapon.
PreventMelee
Prevents the character from performing a melee attack.
PreventBeingShot
Prevents the character from being shot.
PreventBeingMeleed
Prevents the character from being hit with a melee attack.
PreventRagdoll
If this character was about to ragdoll, it'll simply not do so.
PreventWorldInteraction
Character cannot pick anything up or interact with the environment.
PreventThrowing
Character can't throw.
PreventIronSight
Character can't look through their iron sights / block. Identical to PreventBlock
.
PreventBlock
Character can't block / look through their iron sights. Identical to PreventIronSight
.
PreventMixTransition
The animation should blend between ANIMATED and NON-ANIMATED states immediately, without a transition.
Used for looping animations, entrance animations, and exit animations.
PreventFlip
Prevent the character from flipping around. flipping it!!
FaceForwards
Force the character to look forwards. This is different from PreventAiming in that it doesn't "freeze" the aiming direction to what it was prior to setting the constraint, it simply forces a certain aiming direction.
PreventDeathAnimation
This character can die but they will not perform a death animation.
COMBO TIME
PreventAllAttacking
= PreventMelee
| PreventShooting
| PreventThrowing
PreventAllMovement
= PreventWalking
| PreventAiming
| PreventFlip
PreventAllDamage
= PreventBeingShot
| PreventBeingMeleed
Melee sequences
Melee sequences are stored as .seq
files, which define a series of animations to be played in order. Each sequence contains both right and left variants of the animations, along with two important frame types: transition frames and hit frames.
A transition frame is the specific frame within an animation where the next animation in the sequence should begin. A hit frame marks the point where the actor lands a hit during the melee attack. These melee sequences are responsible for the animations flowing smoothly from one to the next, and that hits are registered at the correct moment during combat.
Here's an example of the blunt melee sequence file:
THE END!!
Tank you for listeing to my presentation are there any quesiotn?s make sure to land them bolow the hut button.
Data
Levels
Animations
Armour
Character look
Character stats
Character presets
Factions
Melee sequences
Campaigns
Cutscenes
dj.json
convars.txt
Fonts
Fonts are located in the fonts
directory in the base asset folder. They're stored as Walgelijk Fonts, or "wf" files. These are technically just zip files with an MSDF bitmap font in them.
The included fonts are Oxanium, Toxigenesis, and Impact, and only support extended ASCII.
Custom fonts
You need to use Walgelijk.FontGenerator (wfont), installable as a dotnet tool:
dotnet tool install Walgelijk.FontGenerator -g
After this, in a terminal, navigate to a folder containing your font files (otf/ttf). Then run wfont
without any parameters. Wait for a while, and you'll find a .wf file has been generated for each font file in the folder.
If you want to include characters outside the standard charset, you need to create a charset file (charset.txt) in this folder. This is a text file with every character you would like to be included in the font. Instead of passing no parameters, you run
wfont --charset "charset.txt"
to include the charset. Make sure the font files you're using support all characters in this set.
Drag these wf files into your mod asset folder and use them like this:
// provide path to your font inside your mod asset folder
var font = Asset.Load<Font>("fonts/papyrus.wf");
Draw.Font = font;
Draw.Text("Hello everyone!", Window.Size * 0.5f, Vector2.One);