Skip to content

How to add custom Python code to a game mode

The easiest and most common way to add custom Python code into your MPF game is to add a code module to a mode folder. That lets you run code when that mode is active and helps you break up any custom code you write per mode.

This “mode code” (as we call it) has access to the full MPF API. You can post events, register event handlers which run custom things when events are posted, access device state and control devices, read and set player variables, post slides… really anything MPF can do, you can do.

Here’s how you get started with custom mode code.

Create the module (file) to hold you code

First, go into the mode folder where you want to create your custom code, and add a “code” folder to that mode folder. Then inside that folder, create a file (we usually give this file the same name as the mode) with a .py extension.

For example, if you wanted to create custom code for your base mode, it might look like this:

<mpf-game-folder>
├── config
└── modes
    ├── attract
    └── base
        ├── config
        │   └── base.yaml
        └── code
            └── base.py

Open up the new Python file you just created

Next, open the new mode code Python file you just created and add the bare minimum, which would look like this:

from mpf.core.mode import Mode

class Base(Mode):
    pass

MPF includes a Mode class which acts as the base class for every mode that runs in a game. That base class lives in the MPF package at mpf.core.mode. You can see it online in GitHub here.

Notice that we named our custom class Base. You can name it whatever you want.

Update your mode config file to use the custom code

Once you create your custom mode code, you need to tell MPF that this mode uses custom code instead of just the built-in code.

To do this, add a code: entry into the mode config file for the mode where you’re adding custom code. So in this case, that would be in the /modes/base/config/base.yaml file, like this:

mode:
  start_events: ball_starting
  priority: 100
  code: base.Base

Note that the value for the code: section is the name of the Python module (the file), then a dot, then the name of the class from that file. So in this case, that’s base.Base.

Run your game!

At this point you should be able to run your game and nothing should happen. This is good, because if it doesn’t crash, that means you did everything right. Of course nothing special happens because you didn’t actually add any code to your custom mode code, so you won’t see anything different.

Add some custom methods to do things

You can look at the Mode base class (the link from GitHub from earlier) to see what the base Mode class does. However, we have created a few “convenience” methods that you can use. They are:

  • mode_init: Called once when MPF is starting up

  • mode_start: Called every time the mode starts, just after the mode__started event is posted.

  • add_mode_event_handler: This is the same as the main add_event_handler() method from the Event Manager, except since it’s mode-specific it will also automatically remove any event handlers that you registered when the mode stops. (If you want to register event handlers that are always watching for events even when the mode is not running, you can use the regular self.machine.mode.add_handler() method.

You don’t have to use all of these if you don’t want to.

Also, modes have additional convenience attributes you can use within your mode code:

  • self.config: A link to the config dictionary for the mode’s config file.

  • self.priority: The priority the mode is running at. (Don’t change this. Just read it.)

  • self.delay: An instance of the delay manager you can use to set delayed callbacks for this mode. Any active ones will be automatically removed when the mode ends.

  • self.player: A link to the current player object that’s automatically updated when the player changes. This will be None if the mode is running outside of a game.

  • self.active: A boolean (True/False) value you can query to see if the mode is running.

Example usage

Here’s an example of some mode code in use. This example is just a bunch of random things, but again, since you’re writing code here, the sky’s the limit! Seriously you could do all your game logic in mode code and not use the MPF configs at all if you wanted to.

from mpf.core.mode import Mode


class Base(Mode):

    def mode_init(self):
        self.machine.log.info("My custom mode code is being initialized")
        #Technically the Python print command works as well, but make it a habit to log properly

    def mode_start(self, **kwargs):
        # The mode_start method needs **kwargs because some events that
        # start modes pass additional parameters

        self.machine.log.info("My custom mode code is starting")

        # Set a delay to call self.my_callback() in 5 seconds
        self.delay.add(5000, self.my_callback)

        # what player are we?
        self.machine.log.info(self.player.number)

        # what's the player's score?
        self.machine.log.info('Score: {}'.format(self.player.score))

        self.add_mode_event_handler('player_score', self.player_score_change)

        # turn LED "led01" red
        self.machine.leds.led01.color('red')

    def my_callback(self):
        self.machine.log.info("My delayed call was just called!")

    def player_score_change(self, **kwargs):
        #Option 1 to log the score using kwargs
        self.machine.log.info("Player score went up by %s, was %s and is now %s", kwargs['change'], kwargs['prev_value'], kwargs['value'])
        #Option 2 to log the score using the player variable
        self.machine.log.info("The new player's score is {}".format(self.player.score))

    def mode_stop(self, **kwargs):
        # The mode_stop method needs **kwargs because some events that
        # stop modes pass additional parameters

        self.machine.log.info("My custom mode code is stopping")

You can use the API reference (or just look at the source code) to see what options exist. Really you can do anything you want.


Something missing or wrong? You can fix it!

This website is edited by people like you! Is something wrong or missing? Is something out of date, or can you explain it better?

Please help us! You can fix it yourself and be an official "open source" contributor!

It's easy! See our Beginner's guide to editing the docs.

Page navigation via the keyboard: < >

You can navigate this site via the keyboard. There are two modes:

General navigation, when search is not focused:

  • F , S , / : open search dialog
  • P , , : go to previous page
  • N , . : go to next page

While using the search function:

  • Down , Up : select next / previous result
  • Esc , Tab : close search
  • Enter : go to highlighted page in the results