MAD
Adventure Game Engine Documentation

Last Updated: July 23rd, 2002





Introduction

    MAD is an adventure game engine which runs on multiple platforms and relies heavily on scripts (*.lua) for power and customization. It loads *.mad files (MAD's proprietary archive format) and runs a game based on the information placed inside. MAD is designed to be very flexible in creating adventure games, consequently it requires more work from the creators/scripters for a better customized experience. We tried to avoid hard-coding as much as possible, but some parts required it, otherwise it would require an even greater efforts from the scripter.

    MAD archive files (*.mad) are created using a utility called mfile. The MAD engine searches your primary archive file for two scripts; 'stdmad.lua', and 'main.lua'. The first file, 'stdmad.lua', contains standard defines for various functions and is included in a standard MAD distribution. The second file, 'main.lua', is called after the engine is initialized and 'stdmad.lua' has been read, it is used for you to initialize your game.

    To make it easier for you, a scripted support library (will be) built to encapsulate engine functions, perform high-level tasks (combat, spellcasting, etc...) which may be desired in your adventure game, and clean up your script files.

    MAD runs in 320x240 video mode (by default) and selects a high color resolution (16, 24, 32bpp) based on what your video card supports. MAD loads proprietary animation files (MADANM, *.anm) and proprietary image files (MADIMG, *.img) for most graphics functions, but also relies upon graphical 'Scene' files (*.scn) for displaying individual rooms and specifying some information about it. MAD utilizes some of the information from these scene files for performing built-in A* pathfinding on character objects. Objects are used to handle characters/sprites that can walk around the screen and interact with the user, Mask Objects (MaskObjs) are simplified versions for pieces of the background scenery the sprites can walk behind or look at, but don't actually move.

    Some kernel functions are provided for gathering input from the user and among other things, audio output. MAD can load and play *.wav and *.voc files for digital sound effects, and *.mid and *.mp3 files for background music. MAD features a moderately sophisticated GUI tailored for the needs of an adventure game, and customizeable for a completely different look between MAD games. Custom fonts are also supported. For more information, feedback or questions go to the MAD homepage.

The Official MAD homepage is: http://mad-project.sourceforge.net


Tools

    MAD relies on many utilities to put together graphics and data into a single resource file read by the mad engine. Here are the utilities included with MAD:

mfile
  • "MAD File Archive Manager" compiles seperate game resources into a single compressed data file. For information on how to use mfile, click here.

    scengen
  • "Scene Generator" takes a background image, a mask image and a wasc image and puts them all together. A tutorial on how to use scengen and making mask/wasc images is here. There is a "Scene Viewer" program called "scenview," for instructions on how to use it click here.

    anmgen
  • "Animation Generator" creates animations (.anm) with multiple states used by sprites and other structures in MAD. Using anmgen is documented here. To view the contents of an animation file use anmview.

    imgconv
  • "Image Converter" converts regular .bmp's to MAD's image format (.img) and vice-versa. Click here for information on how to use it.

    The 'mad.cfg' config file
    While this isn't exactly a tool like the others, chances are you'll use one. The config file is currently used to determine what file the primary archive is, what screen size to set the display to, and might have more options in the future. The config file looks just like a standard windows *.ini file, where names are followed by equal signs and a value. Here is an example of what could be in a mad.cfg file:

    [mad]
    archive="game.mad"
    width=320
    height=240
    safevideo=1
    window=1


    Here is a list of all variables in mad.cfg:
    Only use standard resolution sizes (320x240, 640x480, 800x600, etc...) or chances are it won't be supported by the video card. MAD attempts to run at a color depth of 15/16bit and will try others if it fails (in the following order: 15,16,24,32). The '[mad]' is there for reference but necessary in order for MAD to beable to find the variables.




    The Scripting Language

        Most of the scripting is accomplished with a nice extension language called lua. This section is sort of a primer of the language, it is very brief, if you want to learn more about lua feel free to get their much more in depth (and more accurate) manual from their site. The language itself is very similar to C/C++ mixed with a little BASIC. Each line can be optionally ended with a semicolon and full line comments are denoted by two dashes "--" at the beginning of the line.

    Variables and Tables
  • LUA is a little peculiar in its manipulation of variables. It isn't necessary to declare variables in lua, in fact you can't declare global variables, only locals. To use a global variable just assign it a value and your ready to go.

    variablename = 0

    To declare local variables:

    local variablename

  • Tables are tough to explain, they are like arrays that are indexed by strings or numbers. But I wont get into detail with them here. Just be aware that using a period (".") in a variable name will cause it to be a local variable in a table. For example:

    table = {}
    --tell lua that this is a table table.name = 0
    --here name is a local variable in the table 'table'



    Operators
  • Arithmetic and logical operators are pretty intuitive from other languages.

    Logical
    "==" : equivalent
    "~=" : not equals
    ">=" : greater than or equal to
    "<=" : less than or equal to
    ">" : greater than
    "<" : less than

    Arithmetic
    "+" : addition, "-" : subtraction, "*" : multiplication, "/" : division

    Assignment
    Lua allows multiple assignment. This means you can assign more than one variable at a time.

    x, y = player_x, player_y


    Control Structures
  • This section refers to how if-then statements and while loops are performed in lua.

    If...then

    if (variable==1) then
       variable=2
    elseif (variable==2) then
       variable=1
    else
      variable=1
    end


    This is your basic if-then-else statement. If variable is set to 1 then it will perform the code after it, if it is not one then it will check the elseif and perform the code if variable is set to 2, if neither of the two above conditions are true then it will before the code after "else". The whole thing is ended with "end".

    While loop

    while (variable < 50) do
      variable = variable + 1
    end


    A while loop continues to execute code as long as the condition is true. Here the condition is "variable < 50" and the code to be executed is variable = variable + 1. Assuming that 'variable' has been initialized to 0, this loop will execute the code 50 times until it stops.


    Kernel Functions

         These serve as a part of the script's API to perform miscellaneous system/engine related tasks. They are used to gather input from the mouse or the keyboard, to play sounds or music, or do other system tasks such as refresh the screen.


    Keyboard Input
    Keyboard input is handled by the functions: GetKey, GetKeyState, and GetKeyWait.

  • GetKeyState(key)
    GetKeyState returns the current state of the KEY constant passed to it, (the KEY_ constants are defined in 'stdmad.lua'). Example:

       variable = GetKeyState(KEY_A)

  • GetKey()
    GetKey returns the code of the current or last key pressed. Example:

       variable = GetKey()

  • GetKeyWait()
    GetKeyWait returns the code of the current key pressed, if there is no key currently pressed then it will wait until a key is pressed and return its code. Example:

       variable = GetKeyWait()


    Mouse Input
    Mouse input is handled by the functions: GetMouseX, GetMouseY, and GetMouseBtn.

  • GetMouseX and GetMouseY
    GetMouseX and GetMouseY return the mouse's x and y position in pixels from the top-left corner of the screen. Example:

       mousex = GetMouseX()
       mousey = GetMouseY()


  • GetMouseBtn(button)
    GetMouseBtn returns (1 if pressed down, 0 if not pressed) the state of the button specified. If button is 1 then it will return the state of the left button, 2 is for the right button, and 3 is for the middle button. Example:

       isleftbuttondown = GetMouseBtn(1)
       if (isleftbuttondown) then
        -- yes, the left mouse button is down
       end



    Sound and Music Output
    Sound and Music handling is object oriented. This means you will have to initialize music and sound objects, and do various things with them before you can play the sound.

  • Changing the Volume
    This function is provided to change volume:

       SetMasterVolume(digital, midi, mp3)

    Volumes are from 0 to 255 (quiet to loud) and a value of -1 won't change that type of volume. Digital volume refers to any sound thats not coming from a midi file. Midi volume is the volume of midi music. Mp3 volume is the volume of mp3 files. However, because mp3s are a form of digital output, if you reduce the digital volume then the mp3's actual loudness will also be reduced (mp3 volume doesn't affect the loudness of a sound effect though). The mp3 volume option is provided as a way to separate the volume of wav's from the volume of mp3 music; for example if you wanted to lower the music to emphasize some sound effects.

  • Playing a Sound
    To play a sound you must initialize the sound object, load the sound file, play it, then delete it when your done. MAD can play standard *.wav files but, as is the case with all file loading in mad, the sound file you load has to be in the currently loaded archive file. Example:

       chirp = NewSound()
       chirp:LoadWav("chirp.wav")
        -- or for MP3's use chirp:LoadMp3("chirp.mp3")
        -- or for Streaming Mp3's use chirp:LoadMp3Stream("chirp.mp3")
       chirp:Play(0)
       DeleteSound("chirp")


    As you can see, you use NewSound() to load a new sound structure in memory. Then you use sound:LoadWav(filename) to load the wav "chirp.wav" in the sound chirp. Finally, you play the sound using sound:Play(loop). The loop parameter is used to determine whether or not to loop the sound so that it replays itself when its done, (set it to 1 to loop, 0 to not loop). Then call DeleteSound("sound") to unload the wav file from memory, only when your completely done with it of course. It's necessary to put the sound variable made with NewSound in quotes. Note: As is you probably wouldn't hear anything because the script kills the sound too fast to hear it.

  • Playing Music
    Playing music works almost identically the same as sounds. MAD can play *.mid files and *.mp3 files, of course mp3 files will take more cpu usage though. Example:

       theme = NewMusic()
       theme:LoadMidi("theme.mid")
        -- or for MP3's use theme:LoadMp3("theme.mp3")
        -- or for Streaming Mp3's use theme:LoadMp3Stream("theme.mp3")
       theme:Play(0)
       DeleteMusic("theme")


    As you can see, you use NewMusic() to load a new music structure in memory. Then you use music:LoadMidi(filename) to load "theme.mid" in the music object theme. To load an mp3 file simply use the function music:LoadMp3(filename), this method loads the entire file in RAM, to stream small chunks of the mp3 file from disk into RAM (this is usually better for >1mb files) use theme:LoadMp3Stream(filename). Finally, you play the music using music:Play(loop). The loop parameter works the same as for sounds. Use DeleteMusic("theme") to unload the file from memory, only when completely done with it. Notice the quotes around 'theme' are needed.

    Multiple archive management
    MAD allows you to use more than one file archive to store game files in groups related to their purpose. You can specify a separate archive for files using the following functions:

    SetSceneArchive(filename)
    SetObjectArchive(filename)
    SetGUIArchive(filename)
    SetMusicArchive(filename)
    SetSoundArchive(filename)

    Scenes are loaded from the Scene archive. Object's graphics and animation files are loaded from the Object Archive. GUI graphics and animations, including the gui skin and cursor, are loaded from the GUI Archive. Music is loaded from the music archive, and sound effects from the sound archive. If an archive is left unspecified MAD will default to the main archive loaded at startup.


    Saving and Loading Data
    These functions are available to save and load various data, intended for saved-game files, but capable of saving other settings as well to external files.

    SaveGlobals(filename, global1, global2, global3, ...)
    Use this function to save any global variables (including tables) to the specified file.

    LoadGlobals(filename)
    Use this function to load any global variables (including tables) saved in the specified file.


    Custom Actions / Cursors
    This section will describe how it is possible to use add/use your own custom actions/cursors in Mad. For example, instead of sticking with LOOK, USE, and TALK, you could bind actions to and have your own cursor for any type of action you want (POKE,EAT,OPEN,etc...).

    There aren't any functions that you call to accomplish this, you simply need to modify 'stdmad.lua': Find OBJACTION_CUSTOM1 and CURSOR_CUSTOM1 and change them from CUSTOM1 to whatever you want. That's it. The cursor will be loaded as sub-animation #10 from the same file you use for the other cursors, and simply use OBJACTION_YOURACTION like you would any other OBJACTION_* constant.


    Miscellaneous

    RunScript(filename)
    This is a very useful function to help in modularization of mad games. If you are familiar with C++ you can consider this akin to the '#include' statement. Calling RunScript(filename) will cause the interpreter to run through the script you passed and thus add any functions or variables defined in that file to appear in the global environment ready for use. You can, for example, store a set of functions (like for a combat engine, a mini-game, dialogs, description strings, etc..) in the file, then RunScript it and have full access to those functions as if they were defined directly in 'main.lua.'

    SetMadSpeed(speed)
    This function will specify the update speed attenuation. A 'speed' value of 1 will cause Mad to run at maximum speed (10ms wait between frames or 100fps).
    The formula to determine the FPS is:
       FPS = 1000 / ( 10ms * speed )

    SetUpdateMode(flags)
    This function will change what can happen in a normal mad engine update. Passing 0 will using the default behavior, the other flags are:

    UPDMODE_NOOBJECTUPDATE
    If this flag is used, MAD will not update any objects but will continue to draw them.
    UPDMODE_NOMOREWINDOWS
    This flag will prevent MAD's GUI system from creating any new windows.
    UPDMODE_NOGUIUPDATE
    This flag will cause MAD not to allow the GUI system to update.
    number = Random(lo, hi)
    This function will return a random number between 'lo' and 'hi.' count = GetTickCount()
    This function will return the time since mad has started in milliseconds. You can use this function to keep better track of time, and ensure sequences run in the same time frame on all systems.

    Wait(wait_time)
    This function will wait for the specified time in ms before continuing to execute the script. The accuracy of the provided wait_time changes based the speed set by "SetMadSpeed".

    SetScreenFX(GFXFILTER_FLAG, red, green, blue, alpha)
    This function specifies a filter to apply to the screen after the drawing of sprites but before the drawing of gui objects and the cursor. The first parameter is a flag which specifies the filter used (if the flag is 0 then it will turn the filter off), all the flags are listed in stdmad.lua but only one currently will do anything useful for SetScreenFX:
    GFXFILTER_TINT
    This flag will tint the screen a certain color (specified with the values red, green and blue), the opacity of the tint is specified with the alpha parameter (values 0 - 255, 0 being no tint, 255 being 100% tint). It is quite possible to use this function to create a fade in/out effect for scene transitions by calling it in a loop.



    Scenes

         Any game-related events in MAD occur within scenes, therefore you'll spend a lot of time creating scene files while developing your game. Each scene file is composed of 3 bitmaps, the 24-bit background bitmap, the 8-bit mask bitmap and the 8-bit walk/scale bitmap. For more information on creating scene files see the scengen section.

  • Creating Scenes in the Script
    The code to do this is pretty understandable and straight-forward:

       scenename = NewScene()
       scenename:SetScript("scenename.lua")
       scenename:Load("scenename.scn")
       scenename:Run()


    Following the previously established pattern, here you must make a New Scene first before you can do anything else. SetScript(filename) is used to assign a particular script to the scene to run when the scene's Run() gets called. Load(filename) is used to load the actual scene file used for this scene into RAM, and Run() causes 'scenename.lua' to start executing and 'scenename.scn" to be drawn.

  • Switching Scenes
    To switch to a different scene, simply call the Run() function of the scene you want to switch to. Keep in mind objects are only drawn on the scene that they belong, so you'll have to move the hero and any other objects over to the new scene yourself via object:SetScene().

  • Other Functions
    Other functions exist to aid in the handling of a large number of scenes, though they can be used in conjunction with any number of scenes. These are here so that its not necessary to load all the scenes in memory at once. The functions are:
       scenename:SetFilename("scenename.scn")
       value = scenename:GetWascValue(x,y)
       x,y = scenename:GetWalkablePosition()
       scenename:Load()
       scenename:Load()
       scenename:Unload()
       ret = scenename:IsLoaded()


    The SetFilename(filename) function will set the scenes filename as filename, but will not actually Load the file in memory. If you specify a scene's filename, then Run() it, it will load the file from disk automatically (of course this will take more time than if it were already loaded in ram).

    The GetWascValue(x,y) function will return a value from 0 to 255 representing the value at that x,y in the Wa/Sc layer.

    The GetWalkablePosition() function will return a random position in the scene that is walkable (a Wa/Sc value that is not 0).

    The Load() function without a filename parameter will load a scene from disk using the filename specified from a previous SetFilename(filename) call.

    The Unload() function will free the Scene's bitmaps from memory. This is function is to be used if you don't want a specific scene to stay resident in memory, good for scenes that are only seen once or for when you've already got a lot loaded. Note: each scene takes up approximately width*height*5 bytes of memory (384k for 340x240 scenes).

    The IsLoaded() function is available to check whether or not the bitmaps for a function have been loaded in RAM. It will return either FALSE or TRUE.


    Objects and Mask Objects

         Objects in MAD are anything that you can interact with. There are two types of objects in MAD, Objects and MaskObj's. The primary difference is that Objects can move and are independent from the background, while MaskObj's are stationary and their graphics are taken from the scene file's bkg and mask layer. Most of the code used to manipulate them are the same.

    Object/Mask Coordinates
         The coordinates for objects are stored differently for different types of objects. The coordinates for mask objects and objects without graphics are stored top-left, this means the x and y for these types of objects refer to the top - left corner of the object. Objects with graphics (animations or still images) have coordinates which refer to the bottom - middle edge of the object. This is because MAD uses this information to determine which order to draw the objects, and these types of coordinates are generally more convenient to use with characters since the bottom-middle edge would refer to their feet.

    Setting up Objects
    Here is some code that could be used to setup the main character in a game:

       hero = NewObj()
       hero:LoadAnimation("hero.anm", "southstill", 0)
       hero:SetScene(albion_s5, 100, 200)
       hero:SetSize(48, 64)
       hero:SetSpeed(3, 1)
       hero:SetFlags(OBJFLAG_ISCHARACTER + OBJFLAG_ISEGO + OBJFLAG_8WAYANIM)
       hero:Show()


    object = NewObj()
    This allocates memory for a new object, just like with scenes, you must do this prior to attempting to do anything else to an object. When your done with the object, you can manually deallocate the memory by calling object:Kill()

    object:LoadAnimation(filename, initialsubanm, loop)
    This funciton loads a MAD anm file into the object. In our example we load the file "hero.anm", set the sub-animation to "southstill" (this means the character will face south when he is loaded, see below for more about subanm names), and set loop to 0.

    object:SetScene(scene, x, y)
    This function sets the scene that the object belongs to, and places him at a specific position. If you assign an object to any scene other than the current one, it will be hidden. The x, y position specified is (in this case) NOT the top-left coordinates of the hero's anm, but the center-bottom coordinates of the animation. It is more convenient this way so you can simply enter the x,y position of where you want the hero's feet to be.

    scene = object:GetScene()
    Returns the scene that the object is on.

    object:SetSize(width, height)
    This specifies the size of the object. It's probably not neccessary to specify the width and height of an object that you will load an animation into, but its safer to do it anyways.

    object:SetSpeed(horizontalspeed, verticalspeed)
    This specifies the speed of an object at 100% scale. Keep in mind most resolutions are wider than they are tall so you'll probably want to make the horizontal speed more than the vertical speed.

    object:SetFlags(flag1 + flag2 + flag3 + ... flagN)
    Flags are a convenient means of setting certain information about an object. All possible flags that can be used as an object flag are listed in stdmad.lua and have the prefix "OBJFLAG_".

    Object Flags (OBJFLAG_*)
    OBJFLAG_ISCHARACTER
    If this flag is set, then MAD treats this object as a "character." Characters must have animations loaded with the following sub-animations: northstill, northwalk, southstill, southwalk, weststill, westwalk, eaststill, eastwalk.
    OBJFLAG_ISEGO
    This flag sets the object as the player-controlled character and must be used in conjunction with OBJFLAG_ISCHARACTER. Many adventure game engines refer to the main character as EGO, following a precedent set by Sierra a long time ago.
    OBJFLAG_8WAYANIM
    This flag tells MAD that this objects animation contains subanms for 8 directional movement. In addition to the subanm's listed under OBJFLAG_ISCHARACTER, this flag requires: nestill, newalk, nwstill, nwwalk, sestill, sewalk, swstill, swwalk.
    OBJFLAG_NOSCALE
    This flag tells MAD not to scale/resize this object's graphics to fit the scene's wasc. Useful for things that don't actually touch the ground (ie a bird, or a fireball) and wouldn't look right scaled.
    OBJFLAG_DRAWASBKG
    This flag tells MAD to draw this as part of the background, or before the normal ones are drawn. If more than one object has this flag set and they intersect, the one created first would be drawn first.
    OBJFLAG_DRAWASFRG
    This flag tells MAD to draw this as part of the foreground, or after the normal ones are drawn. If more than one object has this flag set and they intersect, the one created first would be drawn first.


    object:SetGFXFilter(GFXFILTER_*, red, green, blue, alpha)
    This function activates a graphics filter to be applied to the object when it is drawn on the screen in real-time. To disable a graphics filter effect simply pass '0' as the first param. The flags are defined in stdmad.lua.

    GFXFILTER_ Flags
    GFXFILTER_TINT
    This filter will tint the color of the object. It makes the color out of the red, green and blue parameters given. The range of values for the color components are from 0 to 255, the alpha parameter is discarded.
    GFXFILTER_BLEND
    This filter will blend the objects graphic in with whatever is behind it. It uses the alpha parameter to determine the opacity of the object (0 is invisible, 255 is solid)

    object:Show()
    Objects are initially invisible. So to make them visible you must call object:Show(), to hide them again you must call object:Hide().

    Object Movement and Pathfinding
    There are two ways to move an object. You could just set it's x,y directly (object:SetPosition), or you can give it a point to go to and it will use MAD's built-in pathfinding to find a way to walk to the point (object:WalkTo). There are also a variety of other functions in addition to these that help deal with object movement.

    object:WalkTo(x, y)
    This will cause an object (not neccessarily a character object) to walk to the specified x,y point, while moving around obstacles (i.e. non-walkable areas in the scene file).

    object:SetPosition(x, y)
    This will set the objects position to the specified coordinates. Of course object:SetScene does the same thing but also specifies the object's scene.

    object:SetPositionTL(x, y)
    This will set the object's Top-Left position to the specified coordinates. It will convert the Top Left coordinates to the necessary ones the specific object uses (ie. Mid-bottom). Make sure you call SetSize before calling this function or it might not work right. This function is useful for objects that need to be lined up precisely. See the note about object coordinates for more info how object coordinates are handled.

    x, y = object:GetPosition()
    This will return the current coordinates (bottom-x, middle-y) of the object.

    dx, dy = object:GetPositionChange()
    This will return the change in position of the object since the last frame. A negative 'dx' value would imply the object moved to the left, and a negative 'dy' means the object moved up.

    w, h = object:GetSize()
    This will return the size of the object (width and height).

    object:SetSpeed(speedx, speedy)
    SetSpeed defined here.

    speedx, speedy = object:GetSpeed()
    This will return the horizontal and vertical speed of the object per frame. Note: these values are never negative, speed is independent from direction.

    distance = object:GetDistance(object2)
    This function will calculate the distance between object and object2 (in pixels) using the distance formula.

    distance = object:GetMaskObjDistance(maskobject)
    This function will calculate the distance between object and maskobject (in pixels) using the distance formula. Its the same as above but uses a Mask Object.

    Look, Use, and Talk to Objects.
    Interacting with objects is accomplished through script functions that are "Binded" to certain actions of the object. Here is an example of binding a function to an object's action:

       function f_hero_look()
         MsgBox("Looks like a hero!")
       end
       
       hero:BindAction(OBJACTION_LOOK, "f_hero_look")


    This code will cause the message "Looks like a hero!" to appear when you click on the hero with the "LOOK" cursor. To specify what action you want to use you must use the OBJACTION_* flags. The second parameter is the name of the function in quotes, it must be a global function.

    To bind a default function to call when the event is not called for an object, use the 'BindDefaultAction' function.

    BindDefaultAction(OBJACTION_*,"function")

    Object Action Flags (OBJACTION_*)
    OBJACTION_LOOK
    The function will be called when the object is clicked on with LOOK cursor.
    OBJACTION_TALK
    The function will be called when the object is clicked on with TALK cursor.
    OBJACTION_USE
    The function will be called when the object is clicked on with USE cursor.
    OBJACTION_CURITEM
    The function will be called when the object is clicked on with CURITEM cursor, the currently selected inventory item.
    OBJACTION_UPDATE
    The function will be called on every frame update.
    OBJACTION_EGOWALKOVER
    The function will be called when ever the EGO object is walking over top of this one.

    Object Graphics and Animation
    MAD has several functions for loading and handling graphics and animations.

    object:LoadImage(filename, source_x, source_y)
    This function will load a MAD image (those made with the imgconv utility) into the object. Source_x and source_y specify an offset position in the bitmap of where to load the image for the object at.

    object:LoadAnimation(filename, subanm, loop)
    This function is documented here.

    object:SwitchAnim(subanm, loop)
    Changes the currently playing sub-animation to the one specified, and changes the loop flag to the 'loop' parameter. The current sub-animation doesn't change if 'subanm' doesn't exist.

    object:PauseAnim()
    object:ResumeAnim()

    Pauses and Resumes the object's currently playing animation.

    object:LockAnim(lock, ["subanm_name", loop])
    Prevent MAD from changing this objects sub-animation (ie. if its a walking CHARACTER) for lock=1 otherwise it will unlock the sub-animation. If the optional parameters are omitted the current sub-animation is used. 'loop' can be used like the parameter in 'object:SwitchAnim.'

    animstate = object:GetAnimState()
    Returns '0' if the animation has stopped, '1' if the animation is still running. It will always be 1 if you set loop to 1.

    animframe = object:GetAnimFrame()
    Returns the current position of the subanm playing. For example, if a subanm has 8 frames, and the 7th frame of the subanm is being displayed this function will return '7'.


    Mask Objects
    As stated before, mask objects operate similarly to regular objects. However because the graphics of a mask object are based on the mask and bkg layer of a scene file, there are some apparent limitations. Here is a list of the functions supported by Mask Obj's:

    mask = NewMaskObj(scene, x, y, width, height, colorindex)
    mask:BindAction(Object Action Flag, "function_name")
    mx, my = mask:GetPosition()
    mask:Show()
    mask:Hide()
    mask:Kill()

    These all work the same as normal objects except NewMaskObj contains some different parameters. When creating the mask you must specify where it is (x, y) in the specified scene and how big it is (width, height), also you must specify what color index in the mask bitmap is the mask for this object, since different masks of different colors might overlap.

    mask:SetFlags(flag1 + flag2 + flag3 + ... flagN)
    Flags are a convenient means of setting certain information about an object. All possible flags that can be used as a mask flag are listed in stdmad.lua and have the prefix "MASKOBJFLAG_".

    Mask Flags (MASKOBJFLAG_*)
    MASKOBJFLAG_NODRAW
    If this flag is set, then MAD doesn't draw this mask at all. It will still appear as part of the background image but wont overlap any objects. This enables you to bind functions to areas in the mask screen but without drawing anything.





    Graphical User Interface (GUI)

         The GUI refers to any graphical means by which the user can interact with the game. This typically embodies buttons, cursors, dialogs/windows, etc. MAD's GUI consists of dialog-windows, buttonbars, and "floating" labels and inputboxes.

    Cursor
    The MAD engine allows for customization of the mouse cursor icons. MAD loads the cursor graphics from an animation file as sub-animations, they must be in the same numerical order as the CURSOR_* constants defined in stdmad.lua. Sub-anims in the cursor animation file are animated in MAD, depending upon the number of frames in a sub-anim.

    LoadCursor(filename)
    This function specifies the MAD animation file to load cursors from.

    cursor_state = GetCursor()
    This function returns the cursor_state, which is the currently selected cursor and corresponds to the CURSOR_* constants in the stdmad.lua.

    SetCursor(CURSOR_*)
    This function sets the selected cursor to the one specified.

    SetCursorFocus(CURSOR_*, x, y)
    This function sets the focus point for a specific cursor. In short, the focus point is the point in the cursor graphic you want to click on the screen with. If your not too sure, just use a 0,0 for x, y.

    SetCursorCycling(value)
    This function can enable or disable right-click cycling through the cursors (from CURSOR_LOOK to CURSOR_CURITEM) by passing TRUE or FALSE as the value (1 or 0 will work also).

    SetCursorCycling(CURSOR_1, CURSOR_2, ...)
    This function will specify the order in which to cycle between cursors. Simply list them in order as the parameters ("CURSOR_LOOK, CURSOR_TALK, CURSOR_WALK" etc). When the cursor is on the last listed state it will cycle to the first one. This list can hold up to 40 entries.

    The GUI Skin
    To enable further customization of the pre-defined Standard GUI Boxes, MAD requires you to come up with your own "gui skin." The "gui skin" is basically just an animation file with certain graphics in specified sub-animations that MAD loads as the default graphics for all windows. Here is a table of what parts of the gui you need to put in what sub-anim:

    Sub-Anim NumberGraphic's Description
    0background texture for the windows
    1top window border
    2bottom window border
    3left window border
    4right window border
    5top-left window corner
    6top-right window corner
    7bottom-left window corner
    8bottom-right window corner
    Hierarchy of an Animation file to be used as the Gui Skin.

    NOTE: These graphics are all tiled and repeated in the area they are used (aka textures), except for the corner graphics.

    Setting the Font
    MAD allows you to change the system font to whatever you choose. The types of fonts you can load (thanks to FreeType2 and the AllegroFont lib) are:
  • TrueType fonts (and collections)
  • Type 1 fonts
  • CID-keyed Type 1 fonts
  • CFF fonts
  • OpenType fonts (both TrueType and CFF variants)
  • SFNT-based bitmap fonts
  • X11 PCF fonts
  • Windows FNT fonts
    In order to change the font, you must call the following function:

    SetSystemFont("fontfile", antialias, red, green, blue, character_height, [shadow])
    This function loads "fontfile" as the system font and will be used for all game text. The 'antialias' parameter specifies whether or not to draw the font anti-aliased (a value of 1 will use anti-aliasing, 0 will not use anti-aliasing). Anti-aliasing will make the text look better, but is many times slower than regular drawing. The red, green, and blue parameters are used to specify the color to draw the font in. Character_height is used determine the size of the characters of the font. Shadow is on by default, pass 0 if you want it off.
    (Note: If you get segmentation faults when trying to load a font, try adding the font to the archive uncompressed (using c0 and c1 in the mfile list).

    Standard GUI Boxes
    MAD has several standard, "hard-coded", gui boxes for general purposes that would be too difficult to recreate on ones own in a script.

    MsgBox("Hello World")
    MsgBox(x, y, "Hello World")

    This function displays the message specified on screen in a window until the mouse is clicked, and pauses all background animation. If x and y aren't specified the window will be centered.

    choice = ChoiceBox(x, y, question, option1, option2)
    This function displays the question on screen and the two options in buttons horizontally and pauses the game until one of the options is selected. The selected option# is returned. If x or y is -1 then the box will be centered along that axis.

    choice = MenuBox(x, y, message, option_1, option_2 ... option_n)
    This function displays the message on screen, and lists the options in buttons vertically. You can pass as many options you want as long as the buttons fit on screen of course. The selected option# is returned. If x or y is -1 then the box will be centered along that axis.

    "option" = MenuBox2(x, y, message, option_1, ... option_n)
    Similar to MenuBox, this function will instead return a string with the option picked in it as opposed to the number of the option picked.

    SetObjectUpdateInGuiBox(updateobj)
    This function sets a flag which will turn on (if updateobj is 1) or off (if updateobj is 0) object animations in the background of standard gui boxes.

    SetTextButtonOutlines(outlines)
    This function sets a flag which will turn on (1) or off (0) text button outlines, for text buttons mostly in MenuBox and ChoiceBox.

    Floating Boxes
    Floating boxes were creating so that you could put information on the screen and not interrupt the game (as opposed to using MsgBox()).

    floatingtext = AddFloatingText(x, y, width, height, variable, function)
    This function creates a new FloatingText object and returns it. The top-left corner of the text label is created at x, y with the dimensions width by height. 'variable' is the message or value to display in the label. If you pass a variable it must be global. 'function' is the name of the global function to call when the mouse clicks on the floating text. You can pass nil as the function if you don't want to use one.

    MoveFloatingText(floatingtext, x, y)
    This function moves the specified floatingtext object to the specified position.

    RemoveFloatingText(floatingtext)
    This function removes the specified floatingtext object.

    floatinginputbox = AddFloatingInput(x, y, width, height, variable, texture)
    This function creates a floating input box. 'variable' is a lua variable that will get set with the contents of what the user enters in the box. 'texture' is the filename of a graphic to display as the "input box."

    MoveFloatingInputBox(floatinginputbox, x, y)
    This function moves the specified floatinginputbox object to the specified position.

    RemoveFloatingInputBox(floatinginputbox)
    This function removes the specified floatinginputbox object.

    Buttons and ButtonBars
    ButtonBars are objects that contain Buttons. First you must create the ButtonBar then add the Buttons. ButtonBars attach buttons horizontally, and are designed to be versatile enough for many applications (mainly the toolbar).

    buttonbar = NewButtonBar(x, y, width, height)
    buttonbar = NewButtonBar(x, y, width, height, "background.img")
    buttonbar = NewButtonBar(x, y, width, height, r, g, b)

    This creates a buttonbar, without any buttons, at x,y with the specified size. Optionally, you can specify either a background image (in the mad format) or the color of the background in rgb components (by default the background is transparent: RGB(255, 0, 255)).

    buttonbar:Show()
    This function shows the buttonbar and all of it's buttons

    buttonbar:Hide()
    This function hides the buttonbar and all of it's buttons

    buttonbar:Kill()
    Delete a buttonbar/remove it from memory.

    button1 = buttonbar:NewButton(width, height)
    This function creates a button inside 'buttonbar' with the specified size.

    button1 = buttonbar:NewButton(ox, oy, width, height)
    button1 = buttonbar:NewButton(ox, oy, width, height, "function")
    button1 = buttonbar:NewButton(ox, oy, width, height, "function", "label")

    This function creates a button inside 'buttonbar' with the specified size, and places it at the offset x and y provided. Optionally, you can specify the function to be called when it's clicked, by giving it the function's name in quotes. If a 6th parameter is passed it will be printed as a label, centered across the button, this can also be a variable with a string in it.

    buttonbar:Button_SetText(button1, "label")
    Use this to specify the label after a button is created.

    buttonbar:Button_Show(button1)
    Use this to show the specified button in the buttonbar.

    buttonbar:Button_Hide(button1)
    Use this to hide the specified button in the buttonbar.

    buttonbar:Button_SetSize(btn, w, h)
    Specify the size of the button.

    buttonbar:Button_LoadAnim(button1, filename)
    This function will load the specified animation (filename) into the button (button1). The following subanimations are used: 'mouse_on', 'mouse_off', 'mouse_click.' These are used if the mouse is over the button, outside of the button, or is over the button and clicking on it, respectively.

    buttonbar:Button_LoadBmp(button1, filename)
    This function will load the specified MAD Image file (filename) into the button (button1). This file must be in the MAD format, ie. converted using imgconv.

    buttonbar:Button_BindAction(button1, "functionname")
    This function will bind the specified function (functionname) to the button (button1), so that when the button is clicked on it will call the function. Just like other 'Bind' style functions in MAD, the function must be global, and you have to pass the name of it in quotes to the BindAction function

    buttonbar:Button_SetFlags(button1, flags)
    This function will set the buttons flags to the ones specified. These flags are denoted as BUTTON_* in the stdmad.lua file, and currently there is only one; 'BUTTON_DRAW_CURITEM' -- this will display the currently selected inventory item on top of the button.




    Player Info

        MAD has various functions to handle and display information about the main player (ego). This includes: inventory, spell book, abilities, and combat. Not all of this is handled within the MAD Core and some of this relies upon using scripted functions.

    Items and Inventory
    The methods for handling Items and Spells are very similar, and are indeed almost identical from inside the MAD engine. However the engine only considers Items and Spells as ID numbers, it is meant for the scripter to program the actions of an item/spell once the engine retrieves the ID number.

    ShowInventory(x, y, "bkgtexture.img", window_width, window_height, itembox_ox, itembox_oy, itembox_width, itembox_height, itemicon_width, itemicon_height, "sliderimage.img")
    This is really confusing at first, but all the options allow for more customization of what your inventory box will look like. The parameters, x and y, specify the position to display the box at, values of -1 will center the box. The third parameter ("bkgtexture.img") is the texture to be placed in the back of the window. Window_width and window_height specify the total size of the window. Note that the inventory display consists of an inventory window and an itembox. The itembox is the box that all the inventory items will be drawn in, you will probably want the inventory window larger than the itembox to allow for a border in the bkg texture. Itembox_ox and itembox_oy is the offset position of the itembox from the corner of the inventory window. Itembox_width and itembox_height is the size of the itembox inside of the inventory window. The last parameter "sliderimage.img" is for a picture of a slider nodule that is on the right side of the inventory. The slider isn't implemented yet, but if you specify it, it will show up.

    HideInventory()
    This function will hide the inventory window if it is showing.

    item_DBslot = AddItemToInvDB("item.img", "item.anm", "item name", itemid, weight, quantity, "f_look_item", "f_use_item", "f_combine_item")
    This function will add an item to the inventory database. Items in the Inventory can either be displayed as bitmaps or animations. The first parameter is the filename of an image to use for the item, if you don't want to use a MAD image for the item, use 'nil' for the first parameter. The second parameter is an animation to display of the item, if you don't want to use an animation; specify a MAD image filename in the first parameter and use 'nil' for the second. "item name" is simply the name of an item. Weight is how much the item weighs (in the imaginary unit of quarks), and quantity is how many items of this same type/itemid you want to add. Each item type only takes up one slot, regardless of quantity. "f_look_item" is the function that will run when you look at the item in the inventory. "f_use_item" is the name of a global function to call when the item gets used. "f_combine_item" is the name of a function to call when an item is to be combined with this one (MAD doesn't actually combine them, its up to you to check for validity, remove and then add new items).

    slot = AddItemToInv(item_id,[qty])
    This will take an item with the specified id from the database and put it in the player's inventory 'qty' times. If the quantity is not specified it will be added once. The slot the item is placed in is returned.

    RemoveItemFromInv(slot, quantity)
    This function will remove aka "drop" quantity number of item specified.

    RemoveItemFromInvDB(item_id)
    Remove the item with the specified id from the database.

    SetCurInvItem(slot)
    This function specifies the currently selected item as 'item'.

    slot = GetCurInvItem()
    This function retrieves the slot of the currently selected item.

    item_id = GetCurInvItemID()
    This function retrieves the currently selected item's id.

    qty = GetInvItemQty(item_id)
    Returns the number of items you have with the speicifed id.

    weight = GetInvTotalWeight()
    Returns the weight of all inventory items (So you can check if the hero is carrying too much, etc).

    Spells and SpellBook


    ShowSpells(x, y, "bkgtexture.img", window_width, window_height, itembox_ox, itembox_oy, itembox_width, itembox_height, itemicon_width, itemicon_height, "sliderimage.img")
    This function shows the spell book dialog. See ShowInventory(...) for a description of the parameters, as they are exactly the same.

    spell = AddSpellToBookDB("spell.img", "spell.anm", "spell name", spellid, "description", "f_cast_spell")
    This function adds a spell to the spell book database. The first two parameters are for displaying the spell icon in the spell book. The spell id is used in the script to identify what spell it is. "f_look_spell" is the name of the function called when you look at the spell. "f_cast_spell" is a global function that is called when the spell is cast.

    slot = AddSpellToBook(spell_id)
    Adds the spell with specified id from the DB to the player's Spell Book.

    RemoveFromSpellBookDB(spell_id)
    This function removes the spell with specified id from the spell book.

    RemoveFromSpellBook(spell_slot)
    Remove a spell from the player's spell book. Practical use of this isn't really known, unless you have an evil villain that removes spells from the hero...

    spell_slot = GetCurSpell()
    This will return the currently used spell's slot so that you know what spell was cast, and how code for it in the script.

    spell_id = GetCurSpellID()
    This will return the currently used spell's id, alternative to one above.

    Player Skills and Attributes
    The player's skills and attributes are handled entirely within the script. This allows you to make whatever skills you want, and modify them however you like. I would suggest putting them all in a table like so:

    heroinfo = {name = "unknown hero", class = "fighter", hp=150, mhp=150, mp=0, str=50, int=10, agi=10, luck=10, gold=10, silver=10 }

    Then you can access each element of the table by name, 'heroinfo.name' or 'heroinfo.hp' etc...

    Combat Engine
    There currently is no pre-made combat engine. It would be difficult to script one generic enough to apply to more than one type of game. If you want combat you must then script your own.


    2001,2002 Nunzio Hayslip, Javier Gonzalez, et al.