Solarus quests  1.6
Quest maker's reference
General features

sol.main contains general features and utility functions that are global to the execution of the program, no matter if a game or some menus are running.

Functions of sol.main

sol.main.get_solarus_version()

Returns the current Solarus version.

The Solarus version includes three numbers: x.y.z, where x is the major version, y is the minor version and z is the patch version.

Changes of major and minor versions may introduce some incompatibilities in the Lua API. Patch versions are only for bug fixing and never introduce incompatibilities. See the migration guide for instructions about how to upgrade your quest to the latest version.

  • Return value (string): The Solarus version.

sol.main.get_quest_version()

Returns the version of the currently running quest as specified in the Quest Properties file.

  • Return value (string): The quest version, or nil if no quest version was set the quest properties.

sol.main.get_quest_format()

Returns the Solarus compatibility format of this quest.

This corresponds to a version of Solarus with major and minor version numbers (no patch number), for example "1.5".

  • Return value (string): The format of this quest.

sol.main.load_file(script_name)

Loads a Lua file (but does not run it).

This function is a replacement to the usual Lua function loadfile(). The difference is that it looks for a file in the quest tree (which may be a directory or an archive) and also in the quest write directory. The quest write directory is tried first.

  • script_name (string): Name of the Lua file to load (with or without extension), relative to the data directory or the write directory of your quest.
  • Return value (function): A function representing the chunk loaded, or nil if the file does not exist or could not be loaded as Lua.
Remarks
Keep in mind that Lua files, as all data files of your quest, may be located inside an archive instead of being regular files. Therefore, to run them, you cannot use usual Lua functions like loadfile() or dofile(). Use sol.main.load_file() and sol.main.do_file() instead to let Solarus determine how to locate and open the file.
Note however that require() can be used normally because it is a higher-level function. Indeed, a specific loader is automatically set by the engine so that require() looks in the archive if necessary and in the quest write directory. require() is the recommended way to load code from another file, because unlike sol.main.load_file() and sol.main.do_file(), it does not parses the file again every time you call it.

sol.main.do_file(script_name)

Loads and runs a Lua file into the current context.

This function is a replacement to the usual Lua function dofile(). The difference is that it looks for a file in the quest tree (which may be a directory or an archive) and also in the quest write directory. The quest write directory is tried first. The file must exist.

Use sol.main.load_file() explicitly if you need to check the existence of the file or to use parameters and return values.

  • script_name (string): Name of the Lua file to load (with or without extension), relative to the data directory or the write directory of your quest.
Remarks
This function is equivalent to sol.main.load_file(script_name)().
require() is the recommended way to load code from another file, because unlike sol.main.load_file() and sol.main.do_file(), it does not parses the file again every time you call it.

sol.main.reset()

Resets the whole program after the current cycle. Lua will be entirely shut down and then initialized again.

sol.main.exit()

Exits the program after the current cycle.

sol.main.get_elapsed_time()

Returns the simulated time elapsed since Solarus was started.

This corresponds to real time, unless the system is too slow to play at normal speed.

  • Return value (number): The number of simulated milliseconds elapsed since the beginning of the program.
Remarks
This time is not reset when you call sol.main.reset().

sol.main.get_quest_write_dir()

Returns the subdirectory where files specific to the quest are saved, like savegames and settings. The quest write directory is specified in your quest.dat file and may be changed dynamically with sol.main.set_quest_write_dir().

  • Return value (string): The quest write directory, relative to the Solarus write directory, or nil if it was not set.

sol.main.set_quest_write_dir(quest_write_dir)

Changes the subdirectory where files specific to the quest are saved, like savegames and settings. Note that the quest write directory can already be specified in your quest.dat file. You usually don't have to call this function, unless you need to change it dynamically for some reason.

  • quest_write_dir (string): The quest write directory, relative to the Solarus write directory, or nil to unset it.

sol.main.load_settings([file_name])

Loads and applies the built-in settings from a file previously saved with sol.main.save_settings(). Settings from the file include user preferences such as the language, the video mode and the audio volume.

Note that all these settings can already be modified individually with the Lua API, so you can either use this function or implement something more fitted to your needs.

A valid quest write directory must be set (in your quest.dat file or by calling sol.main.set_quest_write_dir()), otherwise this function generates a Lua error.

  • file_name (string, optional): Settings file to read, relative to the quest write directory. The default file name is settings.dat.
  • Return value (boolean): true if settings were successfully loaded and applied.
Remarks
When you launch a quest from the Solarus GUI, user preferences that are currently set in the menus of the GUI are automatically written to settings.dat before the quest starts and are automatically applied as soon as the quest starts.

sol.main.save_settings([file_name])

Saves the current built-in settings into a file. This file can be reloaded later with sol.main.load_settings() to restore the saved settings. Settings saved include user preferences such as the current language, the current video mode and the current audio volume.

Note that all these settings can already be modified individually with the Lua API, so you can either use this function or implement something more fitted to your needs.

A valid quest write directory must be set (in your quest.dat file or by calling sol.main.set_quest_write_dir()), otherwise this function generates a Lua error.

  • file_name (string, optional): Settings file to read, relative to the quest write directory. The default file name is settings.dat.
  • Return value (boolean): true if settings were successfully saved.
Remarks
When you launch a quest from the Solarus GUI, user preferences that are currently set in the menus of the GUI are automatically written to settings.dat before the quest starts and are automatically applied as soon as the quest starts.

sol.main.get_distance(x1, y1, x2, y2)

Utility function that computes the distance in pixels between two points.

  • x1 (number): X coordinate of the first point.
  • y1 (number): Y coordinate of the first point.
  • x2 (number): X coordinate of the second point.
  • y2 (number): Y coordinate of the second point.
  • Return value (number): The distance in pixels.

sol.main.get_angle(x1, y1, x2, y2)

Utility function that computes the angle in radians between the X axis and the specified vector.

  • x1 (number): X coordinate of the first point.
  • y1 (number): Y coordinate of the first point.
  • x2 (number): X coordinate of the second point.
  • y2 (number): Y coordinate of the second point.
  • Return value (number): The angle in radians between the x axis and this vector.

sol.main.get_resource_ids(resource_type)

Returns an array of all resource elements ids of the given type declared in the quest database.

  • resource_type (string): Name of a resource type. Must be one of:
    • "enemy",
    • "entity",
    • "font",
    • "item",
    • "language",
    • "map",
    • "music",
    • "shader",
    • "sound",
    • "sprite",
    • "tileset".
  • Return value (table): An array of all elements of this resource type declared in the quest. This is a standard Lua array (the first index is 1), and values are all strings.

sol.main.resource_exists(resource_type, id)

Returns whether a resource element with the specified id is declared in the quest database. This does not check if the corresponding files can be found and are actually valid: it only tells whether the element is declared in the quest database.

  • resource_type (string): Name of a resource type. See sol.main.get_resource_ids() for the possible values.
  • Return value (boolean): true if such an element is declared in the quest database.

sol.main.get_resource_description(resource_type, id)

Returns the description of a resource element as declared in the quest database.

  • resource_type (string): Name of a resource type. See sol.main.get_resource_ids() for the possible values.
  • id (string): Id of the element to get.
  • Return value (string): The description of this element or nil if the element has no description.

sol.main.add_resource(resource_type, id, [description])

Adds the declaration of a new resource element in the quest database.

This does not create any file but just registers an element in the quest database.

  • resource_type (string): Name of a resource type. See sol.main.get_resource_ids() for the possible values.
  • id (string): Id of the element to add.
  • description (string, optional): Description to set.
Remarks
Usually, resource elements are already declared in the quest database file generated by the quest editor. You only need this function if you want to modify the quest database dynamically, for example if you generate content dynamically.

sol.main.remove_resource(resource_type, id)

Removes the declaration of a resource element in the quest database.

This does not delete any file but just unregisters an element in the quest database.

  • resource_type (string): Name of a resource type. See sol.main.get_resource_ids() for the possible values.
  • id (string): Id of the element to remove.
Remarks
Usually, resource elements are already declared in the quest database file generated by the quest editor. This function is only useful if you need to modify the quest database dynamically, for advanced uses like dynamically generated content.

sol.main.get_type(value)

Returns the type name of a value.

This function is similar to the standard Lua function type(), except that for userdata known by Solarus, it returns the exact Solarus type name.

  • value (any type): Any value or nil.
  • Return value (string): The name of the type. Can of one of standard Lua type names: "nil" (a string, not the value nil), "number", "string", "boolean", "table", "function", "thread". If it is a userdata unknown to Solarus, returns "userdata". If it is a Solarus userdata, returns one of: "game", "map", "item", "surface", "text_surface", "sprite", "shader", "timer", "movement", "straight_movement", "target_movement", "random_movement", "path_movement", "random_path_movement", "path_finding_movement", "circle_movement", "jump_movement", "pixel_movement", "state", "hero", "dynamic_tile", "teletransporter", "destination", "pickable", "destructible", "carried_object", "chest", "shop_treasure", "enemy", "npc", "block", "jumper", "switch", "sensor", "separator", "wall", "crystal", "crystal_block", "stream", "door", "stairs", "bomb", "explosion", "fire", "arrow", "hookshot", "boomerang", "camera", "custom_entity".

sol.main.get_metatable(type_name)

Returns the metatable of a Solarus userdata type.

This function is very powerful and should be used with care.

All userdata objects of a type share the same metatable. So there is a metatable for maps, a metatable for games, a metatable for enemies, etc.

The metatable of a type stores what is common to all instances of this type. For example, the metatable of the "enemy" type has a field "get_life" that is the Solarus function enemy:get_life() shared by all enemies.

Note that you can already get the metatable of any object with the standard Lua function getmetatable(object). This function does the same thing, except that you don't have to provide an existing object: you just provide a type name. This allows you do manipulate the metatable of a type before objects of this type start to exist, typically to set up things before a game is started.

You can use the metatable to add a function to all instances of a type. Thus, you can extend the Solarus API with your own functions. This also works for events (functions that the engine automatically calls when they exist). For example, you can easily provide a function add_overlay() to all your maps by defining it only once in the map metatable:

-- Somewhere in your main script, at initialization time:

local map_metatable = sol.main.get_metatable("map")
function map_metatable:add_overlay(image_file_name)
  -- Here, self is the map.
  self.overlay = sol.surface.create(image_file_name)
end

function map_metatable:on_draw(dst_surface)
  if self.overlay ~= nil then
    self.overlay:draw(dst_surface)
  end
end

-- Now, all your maps will have a function map:add_overlay() and an event
-- map:on_draw() that allows to draw an additional image above the map!

When you define a field in a metatable, everything acts like if you defined it in all existing and future instances of the type. However, an individual instance is still able to define a field with the same name. In this case, the instance has the priority: the field from the metatable is overridden.

Similarly, you can even remove (by assigning nil) or modify (by assigning a new value) any function of the Solarus API. We don't recommend to do this because introducing differences with the official API changes the global behavior. It would be unexpected for other people who contribute to your game, and for people you share your scripts with.

  • type_name (string): Name of a Solarus userdata Lua type (see the list of types in sol.main.get_type() above).
  • Return value (table): The metatable of this type, or nil if there is no such Solarus type.
Remarks
If you are a Lua expert, you know that metatables are a very powerful mechanism. They are where the magic happens. Solarus uses metatables internally to do a lot of things, like allowing you to access userdata as tables. Therefore, you should never touch any metamethod (fields whose name starts with two underscores) in the metatable of a userdata type, in particular __index, __newindex and __gc.

sol.main.get_os()

Returns the name of the running OS. Possible values are : "Windows", "Mac OS X", "Linux", "iOS", "Android". If the correct OS name is not available, returns a string beginning with the text "Unknown".

  • Return value (string): The name of the running OS.

sol.main.get_game()

Returns the current game if a game is running.

  • Return value (game): The game currently running, or nil if no game is running.

Events of sol.main

Events are callback methods automatically called by the engine if you define them.

sol.main:on_started()

Called at the beginning of the program.

This function is called when Lua starts. In other words, the function is called when the program begins or after it was reset. In this function, you will typically start an initial menu like a title screen or a language selection screen. If you prefer, you can also start immediately a game.

sol.main:on_finished()

Called at the end of the program.

This function is called when Lua is about to be shut down, i.e., just before the program stops or is reset.

sol.main:on_update()

Called at each cycle of the program's main loop.

Remarks
This event is very powerful (because it is called at global level of the program) but it may be costly if you do heavy operations. Keep in mind that it is called at each cycle. You can usually use other callbacks instead to get notified of when an event happens. You can also use timers if you want to regularly check something.

sol.main:on_draw(dst_surface)

Called when the program's screen is redrawn.

At this point, the engine has already drawn the game (if a game is running) and has not drawn yet the menus of sol.main (if you have created menus on sol.main). Use this event if you want to draw some additional content.

  • dst_surface (surface): The surface where the screen is drawn.

sol.main:on_key_pressed(key, modifiers)

Called when the user presses a keyboard key.

  • key (string): Name of the raw key that was pressed.
  • modifiers (table): A table whose keys indicate what modifiers were down during the event. Possible table keys are "shift", "control" and "alt". Table values are true.
  • Return value (boolean): Indicates whether the event was handled. If you return true, the event won't be propagated to other objects (like the game). However, if the key corresponds to a character, another event sol.main:on_character_pressed() will also be called.
Remarks
This event indicates the raw key pressed. If you want to know the corresponding character instead (if any), see sol.main:on_character_pressed().

sol.main:on_key_released(key)

Called when the user releases a keyboard key.

  • key (string): Name of the raw key that was released.
  • Return value (boolean): Indicates whether the event was handled. If you return true, the event won't be propagated to other objects (like the game).

sol.main:on_character_pressed(character)

Called when the user enters text.

  • character (string): A utf-8 string representing the character that was entered.
  • Return value (boolean): Indicates whether the event was handled. If you return true, the event won't be propagated to other objects (like the game).
Remarks
When a character key is pressed, two events are called: sol.main:on_key_pressed() (indicating the raw key) and sol.main:on_character_pressed() (indicating the utf-8 character). If you need to input text from the user, sol.main:on_character_pressed() is what you want because it considers the keyboard's layout and gives you international utf-8 strings.

sol.main:on_joypad_button_pressed(button)

Called when the user presses a joypad button.

  • button (number): Index of the button that was pressed.
  • Return value (boolean): Indicates whether the event was handled. If you return true, the event won't be propagated to other objects (like the game).

sol.main:on_joypad_button_released(button)

Called when the user releases a joypad button.

  • button (number): Index of the button that was released.
  • Return value (boolean): Indicates whether the event was handled. If you return true, the event won't be propagated to other objects (like the game).

sol.main:on_joypad_axis_moved(axis, state)

Called when the user moves a joypad axis.

  • axis (number): Index of the axis that was moved. Usually, 0 is an horizontal axis and 1 is a vertical axis.
  • state (number): The new state of the axis that was moved. -1 means left or up, 0 means centered and 1 means right or down.
  • Return value (boolean): Indicates whether the event was handled. If you return true, the event won't be propagated to other objects (like the game).

sol.main:on_joypad_hat_moved(hat, direction8)

Called when the user moves a joypad hat.

  • hat (number): Index of the hat that was moved.
  • direction8 (number): The new direction of the hat. -1 means that the hat is centered. 0 to 7 indicates that the hat is in one of the eight main directions.
  • Return value (boolean): Indicates whether the event was handled. If you return true, the event won't be propagated to other objects (like the game).

sol.main:on_mouse_pressed(button, x, y)

Called when the user presses a mouse button.

  • button (string): Name of the mouse button that was pressed. Possible values are "left", "middle", "right", "x1" and "x2".
  • x (integer): The x position of the mouse in quest size coordinates.
  • y (integer): The y position of the mouse in quest size coordinates.
  • Return value (boolean): Indicates whether the event was handled. If you return true, the event won't be propagated to other objects.

sol.main:on_mouse_released(button, x, y)

Called when the user releases a mouse button.

  • button (string): Name of the mouse button that was released. Possible values are "left", "middle", "right", "x1" and "x2".
  • x (integer): The x position of the mouse in quest size coordinates.
  • y (integer): The y position of the mouse in quest size coordinates.
  • Return value (boolean): Indicates whether the event was handled. If you return true, the event won't be propagated to other objects.

sol.main:on_finger_pressed(finger, x, y, pressure)

Called when the user presses a finger.

  • finger (integer): ID of the finger that was pressed.
  • x (integer): The x position of the finger in quest size coordinates.
  • y (integer): The y position of the finger in quest size coordinates.
  • pressure (number): The pressure of the finger, normalized between 0 and 1.
  • Return value (boolean): Indicates whether the event was handled. If you return true, the event won't be propagated to other objects.

sol.main:on_finger_released(finger, x, y, pressure)

Called when the user releases a finger.

  • finger (integer): ID of the finger that was pressed.
  • x (integer): The x position of the finger in quest size coordinates.
  • y (integer): The y position of the finger in quest size coordinates.
  • pressure (number): The pressure of the finger, normalized between 0 and 1.
  • Return value (boolean): Indicates whether the event was handled. If you return true, the event won't be propagated to other objects.

sol.main:on_finger_moved(finger, x, y, dx, dy, pressure)

Called when the user moves a finger.

  • finger (integer): ID of the finger that was pressed.
  • x (integer): The x position of the finger in quest size coordinates.
  • y (integer): The y position of the finger in quest size coordinates.
  • dx (integer): The horizontal distance moved by finger in quest size coordinates.
  • dy (integer): The vertical distance moved by finger in quest size coordinates.
  • pressure (number): The pressure of the finger, normalized between 0 and 1.
  • Return value (boolean): Indicates whether the event was handled. If you return true, the event won't be propagated to other objects.