logo

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

  • 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
  • If you DO have Visual Studio

    • Navigate to src\MadnessInteractiveReloaded directory and open the MIR.sln solution using VS2022
    • Press F5 (or press the ▶ button)

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.

CommandDescription
DebugDrawFloorDraws the floorline
DebugDrawWallsDraws all walls
DrawAnimationInfoDraws animation information
GameModeForce the game mode of the current level. If no input is given, the current gamemode will be returned
ListDisksList all improbability disks
UnlockDiskUnlock the improbability disk with the given ID, or "all" to unlock all disks.
LockDiskLock the improbability disk with the given ID
CurrentLevelReturns the current level name
ConvarSet or get a gameplay configuration variable by key. Pass ?? as an argument to print every available key.
ExportCommandListWrites all commands and their descriptions to "cmd_list.md" as a Markdown table. Intended for the documentation.
CrashCrash the game
GameVersionPrint the game version
PhysicsDebugToggle physics debug
WinLevelSet the body count to the target body count
LevelsLists all levels
SetLevelSets the level to the given level name. Enter 'SetLevel ??' to see a list of available level names
DisableAIDisables the enemy AI
EnableAIEnables the enemy AI
BenchmarkStart the benchmark sequence
DevModeSets development mode
GodSet God mode for the player
StopSoundStops all playing sounds
AutospawnSets autospawn
RefillMotivesRefill ammo, health, and dodge
VolumeSets or gets the current game master volume, ranging from 0.0 to 1.0
ReviveRevives the player
InfiniteAmmoSet infinite ammo for the player
GiveGives the player the weapon of their choice by codename. Enter 'Give ??' to see a list of available weapon names
LevelEditorOpens the level editor scene where developers can edit and create levels
WeaponEditorOpens the weapon editor scene where developers can edit and create weapons. Takes an optional filename argument to start editing an existing weapon.
ArmourEditorOpens the armour editor.
ClearDrawCacheClear the immediate mode drawing cache
DebugOpens the given debug scene. Enter '??' as a parameter to see a list of available debug scenes
DemoOpens the given demo scene. Enter '??' as a parameter to see a list of available demo scenes
TimescaleSets or gets the global time scale. This determines the speed of time-dependent operations
MainMenuSet the scene to the main menu
OnionDebugSet the Onion UI debug mode. E.g 'GuiDebug DrawBounds RaycastHit'
ShowStatsShows some performance stats in the top left corner of the screen. Expects true or false
EchoReturns the input string
ClsClears the console
QuitQuits the game
GetFilterGet the console filter
SetFilterSet the console filter. E.g 'SetFilter Error Warn'
UpsRateSets the update rate. Expects an integer. If a number smaller than 0 is given, this will just print the current rate.
FupsRateSets the fixed update rate. Expects an integer. If a number smaller than 0 is given, this will just print the current rate.
ListSystemsLists all systems in the scene
RemoveSystemRemove the system with the given name
ListEntitiesList all entities in the scene
ListComponentsList all components in an entity. Expects an integer
RemoveComponentRemove a component from an entity. Expects an integer and a string
RemoveEntityRemove and entity. Expects an integer
ListList all commands
CompositorProvides some control over the compositor at runtime
VersionPrints the game and engine versions
OnionSnap
OnionClearClears the Onion UI cache, effectively resetting the UI scene
OnionScaleSets or gets the global Onion UI scale

Core concepts and terms

Creating a mod

Requirements

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.

fields

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.

csproj opening

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: screensnot_1

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.

screensnot_2

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.

screensnot_3

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.

screensnot_4

The console would look something like this:

screensnot_5

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:

screensnot_5

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: blunt.seq

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);

Locale

Shaders

Sounds

Textures

Video

Character abilities

Improbability disks