Class LevelClass
LevelClass exposes it’s sole instance through the Level singleton, which always points to the currently active level. It is a mostly informational object allowing you to access a level’s global settings, but does not permit you to change them, because this either wouldn’t make much sense in the first place (why change the author name from within the script?) or could even cause severe confusion for the game (such as changing the filename).
This class allows you to register handlers for a very special event: The save_load event. This event is not fired during regular gameplay, but instead when the player creates a new savegame or restores an existing one. By filling a special object (SaveSerializer) from the event handler, you can advertise TSC to store arbitrary data in the savegame; later, when the user loads this savegame again, the data is deserialised from the savegame and passed back as an argument to the event handler of the save_load event. This way you can store information on your level from within the scripting API that will persist between saves and loads of a level.
There only is a single save_load event which is used for both saving and loading a savegame. The event handler gets passed an argument that is true on a save, and false on a load operation. This way the API ensures that it cannot accidentally happen that there is an unbalanced amount of save/load event handlers, which would cause problems.
Consider this example:
# Say, you have a number of switches in your # level. Their state is stored inside this # global table. switches = { :blue => false, :red => false, :green => false } # The player may activate your switches, # causing the respective entry in the # global `switches' table to change. UIDS[114].on_touch do |collidor| switches[:red] = true if collidor.player? end # Now, if the player jumps on your switch and # then saves and reloads, the switches’ states # get lost. To prevent this, we define a handler # for the `save_load' event that persists # the state of the global `switches' table on saving, # and restores it on loading. See below for why # strings are used as keys on the `store'. Level.on_save_load do |store, is_save| if is_save store["blue"] = switches[:blue] store["red"] = switches[:red] store["green"] = switches[:green] else switches["blue"] = store[:blue] switches["red"] = store[:red] switches["green"] = store[:green] end end # This way the switches will remain in their # respective state even after saving/reloading # a game. If you change graphics for pressed # switches, you still have to do this manually # in your event handlers, though.
The storage object passed to the save_load event handler is an instance of SaveSerializer, which wraps an underlying C++ structure that allows serialisaton of the data stored into XML format. It's a consequence of this design that it is not possible to persist arbitrary mruby objects. It is only supported to store strings, symbols, nil, true and false, and numerics (both fixnums and floats) in the storage object. The attempt to store anything else is going to raise a TypeError mruby exception.
Keys used with the storage object have to be strings. Using any other object as a key results in an exception. Keys starting with the string "__" (two consecutive underscores) are reserved for TSC's internal use and may not be used by level authors.
When writing a save_load event handler, it is recommended to extensively test it. Any exceptions raised during save and load operations will be printed to the game console (which can be made visible by pressing [F7] in a level).
Handlers for the save_load event must not be defined in a conditional clause of any kind. To comply with this restriction, simply define any handlers on the level script's toplevel. If you need conditional saving/loading, place the conditional inside the save_load event handler.
The reason for this restriction is that the game assumes that one entry in the savegame's script data section corresponds to exactly one save_load handler. On savegame loading, it deconstructs the savegame's script data entries one by one and passes each deserialised entry to the next event handler defined. If save_load handlers are defined under a condition, the assumption breaks and it is not foreseeable which event handler receives which storage entry.
It is recommended to not register more than one event handler for the save_load event. It is possible, but complicates compliance with the above restrictions. Registration of additional event handlers for save_load is mostly useful for scripts that are part of the SSL.
Internal note
You will most likely neither notice nor need it, but the mruby Level singleton actually doesn’t wrap TSC’s notion of the currently running level, pActive_Level, but rather the pointer to the savegame mechanism, pSavegame. This facilitates the handling of the event table for levels. Also, it is more intuitively to have the Save and Load events defined on the Level rather than on a separate Savegame object.
Events
- save_load
-
Called when the user saves or loads a savegame containing this level. The event handler gets passed a storage object (SaveSerializer) and a boolean indicator that indicates whether a save (true) or load (false) operation is in progress. Do not assume your level is active when this is called, the player may be in a sublevel. However, usually this has no impact on what you want to restore, but don’t execute actions on the level player (like warping it) or on any object managed by the HUD (game timer, amount of collected jewels, etc.), it will result in undefined behaviour probably leading TSC to crash.
See Also
Instance Methods
author
author() → a_string
Returns the content of the level’s Author info field.
boundaries
boundaries() → a_rect
Returns the level's boundaries as a Rect instance (struct with x, y, width, height members). X and Y will always be zero; note that towards the upper edge the coordinates are lower, which is why you usually have a negative height in a level.
clear_return
clear_return()
Empties the level return stack.
See LevelExit for explanations on the return stack.
description
description() → a_string
Returns the content of the level’s Description info field.
difficulty
difficulty() → an_integer
Returns the content of the level’s Difficulty info field. This reaches from 0 (undefined) over 1 (very easy) to 100 ((mostly) uncompletable),
display_info_message
display_info_message( message )
Shows a short, informative message on the screen. This is achieved by displaying a prominent sprite covering the full width of the game window containing your message for a few seconds, before the entire construction (i.e. sprite plus message) is then slowly faded out to invisibility.
This method is not meant to display larger passages of text to the user; use the Message class from the SSL for that. No line breaking is done (and only a single line of text is supported).
This method is intended for displaying merely optional pieces of information; for instance, if you built a large tower level, you may use this method to display the floor the player just entered to give him more orientation.
Do not overuse this method. If you use it, stick to one usage scheme; don’t use it for too many different kinds of information, that would confuse the player probably.
Parameters
- message
-
The message to display. A short oneliner.
Example
# Say the object with UID 14 is a warp point that # warps you to the tower’s 3rd floor when touched. # To make the player aware, write your code like this: UIDS[14].on_touch do |collidor| next unless collidor.player? # Only react on the player Level.display_info_message("3rd floor") collidor.warp(400, -620) d
engine_version
engine_version() → an_integer
Returns the TSC engine version used to create the level.
filename
filename() → a_string
Returns the level’s filename.
finish
finish( [ win_music ] )
The player immediately wins the level and the game resumes to the world overview, advancing to the next level point. If the level was loaded using the level menu directly (and hence there is no overworld), returns to the level menu.
Parameters
- win_music (false)
-
If set, plays the level win music.
- exit_name ("")
-
Name of the level exit taken (used in the overworld to determine which path to take).
fixed_horizontal_velocity
fixed_horizontal_velocity() → a_number
Returns the fixed horizontal scrolling velocity. This is usually 0, as the feature is only used by a handful of levels (it makes the camera move horizontally automatically and kills Alex if he falls behind too much).
music_filename
music_filename( [ format [, with_ext ] ] ) → a_string
Returns the default level music’s filename, relative to the music/ directory.
next_level_filename
next_level_filename() → a_string
If a new level shall automatically be loaded when this level completes, this returns the filename of the target level. Otherwise the return value is undefined, but most likely an empty string.
pop_entry
pop_entry() → a_stackentry or nil
Pops the next available Level::StackEntry object from the level return stack and returns it. If there is none, returns nil.
See LevelExit for explanations on the return stack.
push_return
push_return( stackentry )
Push a Level::StackEntry onto the return level stack.
See LevelExit for explanations on the return stack.
return_stack
return_stack() → an_array
Returns the current return stack as an array of Level::StackEntry instances.
See LevelExit for explanations on the return stack.
script
script() → a_string
Returns the MRuby code associated with this level.
start_position
start_position() → a_point
Returns the position Alex starts when the level is entered either from the world map or from the level menu (not via a sublevel entry). Return value is a Point instance (struct with members x and y).