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.
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.
update_quest.lua
tools
The main changes in the data files are:
strings.dat
conveyor_belt
stream
shop_item
shop_treasure
custom_entity
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).
fixed8.fon
minecraftia.ttf
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.
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.
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 sol.video.get_video_mode() and sol.video.set_video_mode(). Possible video mode names are now: normal, scale2x, hq2x, hq3x and hq4x. Similarly, sol.video.switch_mode() no longer changes the fullscreen flag. Call sol.video.set_fullscreen() to set to fullscreen or windowed.
sol.video.get_video_mode()
sol.video.set_video_mode()
normal
scale2x
hq2x
hq3x
hq4x
sol.video.switch_mode()
sol.video.set_fullscreen()
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.
surface:set_transparency_color()
surface:clear()
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.
-video-acceleration=no
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).
map:create_destructible()
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:
destructible:on_looked()
-- 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. game:start_dialog("_cannot_lift_should_cut"); elseif not game:has_ability("lift") then -- No lift ability at all. game:start_dialog("_cannot_lift_too_heavy"); else -- Not enough lift ability. game:start_dialog("_cannot_lift_still_too_heavy"); end end end
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.
on_looked()
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.
enemy:set_enabled(false)
enemy:on_created()
map:on_started()
enemy:on_restarted()
It is recommended to check all bosses of your game anyway.
The remaining incompatibilities in the Solarus API are less disruptive. They should be easy to address or even have no consequence at all.
map:create_teletransporter()
map:create_shop_item()
map:create_shop_treasure()
map:create_conveyor_belt()
map:create_stream()
hero:get_state()
enemy:on_hurt_by_sword
enemy:on_hurt()
enemy:on_dying()
life_lost
hero:on_taking_damage
enemy:get/set_magic_damage()
enemy:on_attacking_hero()
hero:start_hurt()
game:remove_magic()
16*16
x=8,y=13
item:on_pickable_movement_changed()
pickable:on_movement_changed()
pickable:get_treasure()
sol.timer.start()
sol.audio.play_music("none")
sol.audio.play_music(nil)
on_key_pressed()
on_character_pressed()