Skip to content

Upgrade your quest from Solarus 1.1 to Solarus 1.2

Solarus 1.2 brings a lot of new features (custom entities, SDL2, metatables and more), a lot of new functions in the Lua API, and improves the format of some data files (most notably strings.dat). Some entities are more customizable, like destructibles and streams (formely known as conveyor belts).

As always, you should make a backup before any upgrade.

In this page, we only focus on the incompatibilities. See the changelog to know more about the new features.

Upgrading data files

Data files other than scripts can be upgraded automatically with the editor. Open your quest with Solarus Quest Editor 1.2 and a dialog will let you to perform the upgrade.

Note that the operation can also be done from the command line, by running the script update_quest.lua in the tools directory of the git repository. Internally, the editor actually calls this script.

The main changes in the data files are:

  • The language-specific strings file strings.dat has a new syntax easier to read and parse.
  • Sprite data files are more carefully checked. You will have an error if a frame is outside its source image. This was not detected before.
  • There are minor changes in the syntax of map data files. Indeed, some type of entities were renamed (conveyor_belt becomes stream, shop_item becomes shop_treasure), added (custom_entity) or have new properties.

Due to an SDL2 bug, the font fixed8.fon that we used in Zelda Mystery of Solarus DX no longer works. If you also use this font, you will have an error message "Cannot load font from file 'text/fixed8.fon': Couldn't set font size". Also, the license of this font was unclear. For these two reasons, we changed it for another one (minecraftia.ttf, in size 8).

Engine behavior changes

Some improvements slightly change the specific behavior of some entities in some situations. If you have puzzles that rely on the old behavior, make sure to update them.

  • Enemies no longer stay stuck on blocks or crystal blocks.
  • The shield no longer protects the hero while using the sword or carrying.
  • Thrown entities (pots, bombs...) now fall to the lower layer if the hero throw them from above.
  • Running into a crystal or a solid switch now activates it.
  • If the player has the ability to jump, then he can now jump between distant crystal blocks.
  • The collision rules of streams (the new name of conveyor belts) have changed. If there is a space, say of 8 pixels, between a stream and the walls of the room, the hero can now walk on this space without activating the streams. This behavior is coherent with all special grounds like water, holes, prickles, etc.
  • Diagonal jumper collisions have been fixed. Jumpers oriented to North-East or South-West were shifted of 8 pixels in the engine and also in the editor. Also, they did not block the hero enough, and some configurations of ### $1 jumpers were traversable when they should not. You might want to check the position of diagonal jumpers in your existing maps.

Upgrading Lua scripts

The Lua scripting API of Solarus 1.2 introduces a lot of slight incompabilities. Luckily, most of them are very simple or will not impact you. Yet, we give below the exhaustive list of potential problems you may encounter.

Video API

With the port to SDL2, the video API is more simple and more powerful. Switching to fullscreen is faster and no longer changes the resolution of your screen. You can now get and set independently the size of the window, the scaling algorithm and the fullscreen option. "Wide" video modes no longer exist because we don't need them anymore: SDL2 now correctly fits the quest image in the screen without deformation.

These improvements change the API of and Possible video mode names are now: normal, scale2x, hq2x, hq3x and hq4x. Similarly, no longer changes the fullscreen flag. Call to set to fullscreen or windowed.


surface:set_transparency_color() no longer exists. Surfaces are all in a 32-bit format with an alpha channel and there is no special pixel value. Use the new method surface:clear() to erase the content of a surface (this will make it fully transparent). Use the alpha channel of colors to make transparent or semi-transparent pixels.

This is the only incompatible change with surfaces. With SDL2, if video acceleration is available, drawing on surfaces is faster because some blits that were done in memory before are now performed by the GPU. Your FPS should be improved.

Video acceleration can be disabled at runtime with the command-line option -video-acceleration=no.

Destructible entities

Destructible objects (pots, bushes...) are now fully customizable. There are no longer built-in subtypes of destructibles. In map:create_destructible(), each property is now set separetely (the sprite, the sound, the weight, etc).

Also, the engine no longer shows a built-in dialog when trying to lift something that should be cut or something too heavy. There is a new event destructible:on_looked() that you can define to do whatever you want when this happens. To show dialogs like in Solarus 1.1, you can use the following code:

-- Initializes the behavior of destructible entities.
local function initialize_destructibles()

  local destructible_meta = sol.main.get_metatable("destructible")
  -- destructible_meta represents the shared behavior of all destructible objects.

  -- Show a dialog when the player cannot lift them.
  function destructible_meta:on_looked()

    local game = self:get_game()
    if self:get_can_be_cut()
        and not self:get_can_explode()
        and not game:has_ability("sword") then
      -- The destructible can be cut, but the player has no cut ability.
    elseif not game:has_ability("lift") then
      -- No lift ability at all.
      -- Not enough lift ability.

Call this function only once in your quest, even before starting a game. This will define a default on_looked() event for all future destructible objects, thanks to the new (and very powerful) mechanism of metatables.


There should not be special differences between bosses and other enemies. In 1.1 and before, bosses were automatically disabled when starting the map. This is no longer the case. Therefore, to keep the same behavior you have to call enemy:set_enabled(false) from the enemy:on_created() event of your boss if you were not doing it before. You can also do it in the map:on_started() event of the map, but remember that enemy:on_created() and enemy:on_restarted() are already called at this point.

It is recommended to check all bosses of your game anyway.

Minor incompatibilities

The remaining incompatibilities in the Solarus API are less disruptive. They should be easy to address or even have no consequence at all.

Last update: December 10, 2022