/* * Interpreter.cs - Callback and control functions of the Level 9 interpreter. * * Copyright (C) 2004 - 2011 Andreas Scherrer * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this software; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ using System; using System.Collections; using System.IO; using System.Runtime.InteropServices; using System.Text; namespace Level9 { /// /// Callback and control functions of the Level 9 interpreter. /// public unsafe class Interpreter { // -- Constants ------------------------------------------------------ /// /// The number of characters until os_flush() is called in dictionary /// output mode. /// const int DICTIONARY_FLUSH = 256; // -- Delegates ------------------------------------------------------ /// /// Represents the method that handles calls to os_printchar(). /// See for details. /// delegate void OS_PRINTCHAR(char c); /// /// Represents the method that handles calls to os_input(). /// See for details. /// delegate bool OS_INPUT(byte *ibuff, int size); /// /// Represents the method that handles calls to os_readchar(). /// See for details. /// delegate byte OS_READCHAR(int millis); /// /// Represents the method that handles calls to os_flush(). /// See for details. /// delegate void OS_FLUSH(); /// /// Represents the method that handles calls to os_save_file(). /// See for details. /// delegate bool OS_SAVE_FILE(byte *Ptr, int Bytes); /// /// Represents the method that handles calls to os_load_file(). /// See for details. /// delegate bool OS_LOAD_FILE(byte *Ptr, int *Bytes, int Max); /// /// Represents the method that handles calls to os_get_game_file(). /// See for details. /// delegate bool OS_GET_GAME_FILE(byte *NewName, int Size); /// /// Represents the method that handles calls to os_set_filenumber(). /// See for details. /// delegate void OS_SET_FILENUMBER(byte *NewName, int Size, int n); /// /// Represents the method that handles calls to os_graphics(). /// See for details. /// delegate void OS_GRAPHICS(int mode); /// /// Represents the method that handles calls to os_cleargraphics(). /// See for details. /// delegate void OS_CLEARGRAPHICS(); /// /// Represents the method that handles calls to os_setcolour(). /// See for details. /// delegate void OS_SETCOLOUR(int colour, int index); /// /// Represents the method that handles calls to os_fill(). /// See for details. /// delegate void OS_FILL(int x, int y, byte colour1, byte colour2); /// /// Represents the method that handles calls to os_show_bitmap(). /// See for details. /// delegate void OS_SHOW_BITMAP(int pic, int x, int y); /// /// Represents the method that handles calls to os_drawline(). /// See for details. /// delegate void OS_DRAWLINE(int x1, int y1, int x2, int y2, byte colour1, byte colour2); // -- Imports -------------------------------------------------------- /// /// Import declaration of the L9_LoadGame method. /// See for details. /// [DllImport(Config.LEVEL9_DLL)] static extern bool L9_LoadGame(string filename, string picname); /// /// Import declaration of the L9_RunGame method. /// See for details. /// [DllImport(Config.LEVEL9_DLL)] static extern bool L9_RunGame(); /// /// Import declaration of the L9_StopGame method. /// See for details. /// [DllImport(Config.LEVEL9_DLL)] static extern void L9_StopGame(); /// /// Import declaration of the L9_RestoreGame method. /// See for details. /// [DllImport(Config.LEVEL9_DLL)] static extern void L9_RestoreGame(string inFile); /// /// Import declaration of the L9_FreeMemory method. /// See for details. /// [DllImport(Config.LEVEL9_DLL)] static extern void L9_FreeMemory(); /// /// Import declaration of the L9_GetPictureSize method. /// See for details. /// [DllImport(Config.LEVEL9_DLL)] static extern void L9_GetPictureSize(ref int width, ref int height); /// /// Import declaration of the L9_RunGraphics method. /// See for details. /// [DllImport(Config.LEVEL9_DLL)] static extern bool L9_RunGraphics(); /// /// Import declaration of the L9_DetectBitmaps method. /// See for details. /// [DllImport(Config.LEVEL9_DLL)] static extern bool L9_DetectBitmaps(string path); /// /// Import declaration of the L9_DecodeBitmap method. /// See for details. /// [DllImport(Config.LEVEL9_DLL)] static extern IntPtr L9_DecodeBitmap(int n); /// /// Import declaration of the L9_SetCallbackFunctions method. /// Sets the callback functions for the Level 9 interpreter. /// /// /// the os_printchar callback function /// /// /// the os_input callback function /// /// /// the os_readchar callback function /// /// /// the os_flush callback function /// /// /// the os_save_file callback function /// /// /// the os_load_file callback function /// /// /// the os_get_game_file callback function /// /// /// the os_set_filenumber callback function /// /// /// the os_graphics callback function /// /// /// the os_cleargraphics callback function /// /// /// the os_setcolour callback function /// /// /// the os_drawline callback function /// /// /// the os_fill callback function /// /// /// the os_show_bitmap callback function /// [DllImport(Config.LEVEL9_DLL)] static extern void L9_SetCallbackFunctions( OS_PRINTCHAR os_printchar, OS_INPUT os_input, OS_READCHAR os_readchar, OS_FLUSH os_flush, OS_SAVE_FILE os_save_file, OS_LOAD_FILE os_load_file, OS_GET_GAME_FILE os_get_game_file, OS_SET_FILENUMBER os_set_filenumber, OS_GRAPHICS os_graphics, OS_CLEARGRAPHICS os_cleargraphics, OS_SETCOLOUR os_setcolour, OS_DRAWLINE os_drawline, OS_FILL os_fill, OS_SHOW_BITMAP os_show_bitmap ); // -- Structs, Enums, Inner Classes ---------------------------------- /// /// An enumeration of special interpreter commands. /// public enum Commands : int { /// /// No command. /// None = -1, /// /// Saves position file directly (bypasses any disk change prompts). /// Save = 0, /// /// Restores position file directly (bypasses any protection code). /// Restore, /// /// Terminates current game, RunGame() will return false. /// Quit, /// /// Tries to bypass restore protection on v3,4 games (can be slow). /// Cheat, /// /// Lists the game dictionary. /// Dictionary }; /// /// The bitmap structure used in games with bitmap graphics. /// [StructLayout(LayoutKind.Sequential)] public class L9BITMAP { /// /// The bitmap width. /// public short width; /// /// The bitmap height. /// public short height; /// /// A pointer to the bitmap pixels. /// public IntPtr bitmap; /// /// The bitmap palette. Each entry consists of three bytes /// (red, green, blue). /// [MarshalAs(UnmanagedType.ByValArray, SizeConst=96)] public byte[] palette; /// /// The number of palette entries. /// public short npalette; } // -- Attributes ----------------------------------------------------- /// /// An array that stores the interpreter callback functions. /// static Delegate[] callbacks = new Delegate[] { new OS_PRINTCHAR(os_printchar), new OS_INPUT(os_input), new OS_READCHAR(os_readchar), new OS_FLUSH(os_flush), new OS_SAVE_FILE(os_save_file), new OS_LOAD_FILE(os_load_file), new OS_GET_GAME_FILE(os_get_game_file), new OS_SET_FILENUMBER(os_set_filenumber), new OS_GRAPHICS(os_graphics), new OS_CLEARGRAPHICS(os_cleargraphics), new OS_SETCOLOUR(os_setcolour), new OS_DRAWLINE(os_drawline), new OS_FILL(os_fill), new OS_SHOW_BITMAP(os_show_bitmap) }; /// /// The interpreter commands that correspond to the /// enumeration. /// static string[] commands = new string[] { "#save", "#restore", "#quit", "#cheat", "#dictionary", }; /// /// The current interpreter command. /// static Commands currentCommand = Commands.None; /// /// Stores interpreter commands that were added with /// . Those commands /// are executed in calls to . /// static ArrayList inputRequests = new ArrayList(); /// /// A text buffer used in calls to os_printchar. /// static StringBuilder outputBuffer = new StringBuilder(); /// /// The current game file's path. /// static string gameFilePath; /// /// The current game's title. /// static string gameTitle; /// /// /// static OsReadcharEventArgs readcharArgs = new OsReadcharEventArgs(0); // -- Events --------------------------------------------------------- /// /// Occurs when the interpreter flushes a portion of text. /// public static event OsFlushEventHandler OsFlush; /// /// Occurs when a running game waits for user input. /// public static event OsInputEventHandler OsInput; /// /// Occurs when a running game waits for a key press. /// public static event OsReadcharEventHandler OsReadchar; /// /// Occurs when the interpreter requests to save a file. /// public static event OsSaveFileEventHandler OsSaveFile; /// /// Occurs when the interpreter requests to load a file. /// public static event OsLoadFileEventHandler OsLoadFile; /// /// Occurs when the interpreter requests for a game file. /// public static event OsGetGameFileEventHandler OsGetGameFile; /// /// Occurs when graphics are turned on or off in a running game. /// public static event OsGraphicsEventHandler OsGraphics; /// /// Occurs when the graphics area must be cleared in a running game. /// public static event OsClearGraphicsEventHandler OsClearGraphics; /// /// Occurs when a line must be drawn in a running game. /// public static event OsDrawLineEventHandler OsDrawLine; /// /// Occurs when an area must be filled in a running game. /// public static event OsFillEventHandler OsFill; /// /// Occurs when a palette color must be set in a running game. /// public static event OsSetColourEventHandler OsSetColour; /// /// Occurs when a bitmap must be displayed in a running game. /// public static event OsShowBitmapEventHandler OsShowBitmap; /// /// Occurs when a new game has been loaded. /// public static event NewGameFileEventHandler NewGameFile; /// /// Occurs when the interpreter detects a game file error. /// public static event GameFileErrorEventHandler GameFileError; /// /// Occurs when the user has finished an input line. /// public static event InputFinishedEventHandler InputFinished; // -- Constructors --------------------------------------------------- /// /// Initializes static members of the Interpreter class. /// static Interpreter() { L9_SetCallbackFunctions( (OS_PRINTCHAR) callbacks[0], (OS_INPUT) callbacks[1], (OS_READCHAR) callbacks[2], (OS_FLUSH) callbacks[3], (OS_SAVE_FILE) callbacks[4], (OS_LOAD_FILE) callbacks[5], (OS_GET_GAME_FILE) callbacks[6], (OS_SET_FILENUMBER)callbacks[7], (OS_GRAPHICS) callbacks[8], (OS_CLEARGRAPHICS) callbacks[9], (OS_SETCOLOUR) callbacks[10], (OS_DRAWLINE) callbacks[11], (OS_FILL) callbacks[12], (OS_SHOW_BITMAP) callbacks[13] ); } // -- Methods -------------------------------------------------------- /// /// os_printchar() prints a character to the output. The interface /// can either buffer this character or print it immediately, but /// if buffering is used then the characters must all be sent to the /// output when the interpreter calls os_flush(). A paragraph of /// text is output as one long stream of characters, without line /// breaks, so the interface must provide its own word wrapping and /// any other features that are desired, such as justification or a /// [More] prompt. The carriage return character is always '\\r', /// rather than '\\n'. /// /// the character to print public static void os_printchar(char c) { outputBuffer.Append(c); if (currentCommand == Commands.Dictionary && outputBuffer.Length >= DICTIONARY_FLUSH && c == ' ') { OsFlushEventArgs args = new OsFlushEventArgs(outputBuffer.ToString()); args.Command = currentCommand; OsFlush(args); outputBuffer.Remove(0, outputBuffer.Length); } } /// /// os_input() reads a line of text from the user, usually to accept /// the next command to be sent to the game. The text input must be /// stored in ibuff with a terminating zero, and be no longer than /// size characters. Normally os_input() should return true, but may /// return false to cause the entire input so far to be discarded. /// /// the zero terminated input line /// the maximum length of an input line /// false if the entire input should be discarded public static bool os_input(byte *ibuff, int size) { Logger.Log(typeof(Interpreter), "os_input: Start"); OsInputEventArgs args = new OsInputEventArgs(); OsInput(args); // // Notify listeners that user input finished // if (InputFinished != null) { InputFinishedEventArgs ifArgs = new InputFinishedEventArgs(args.Input); InputFinished(ifArgs); } // // Remove input request, if one exists // if (inputRequests.Count > 0) { args.Input = commands[(int)inputRequests[0]]; currentCommand = (Commands)inputRequests[0]; inputRequests.RemoveAt(0); } Logger.Log(typeof(Interpreter), "os_input: '" + args.Input + "'"); StringToBytes(args.Input, ibuff, size); return true; } /// /// os_readchar() looks to see if a key has been pressed if one has, /// returns the character to the interpreter immediately. If no key /// has been pressed the interpreter should wait for a key for at /// least the number of milliseconds given in the argument. If after /// this period no key has been pressed, 0 should be returned. This /// is most commonly used when a game is exited, causing it to print /// "Press SPACE to play again" and then call os_readchar(). /// /// /// the number of milliseconds to wait for a keystroke /// /// /// 0 if no key has been pressed; otherwise a character /// public static byte os_readchar(int millis) { readcharArgs.Character = 0; readcharArgs.Millis = millis; OsReadchar(readcharArgs); if (readcharArgs.Character != 0) { Logger.Log(typeof(Interpreter), "os_readchar: '" + readcharArgs.Character + "'"); } return readcharArgs.Character; } /// /// If the calls to os_printchar() are being buffered by the /// interface then the buffered text must be printed when os_flush() /// is called. /// public static void os_flush() { if (outputBuffer.Length == 0 && currentCommand != Commands.Dictionary) { return; } Logger.Log(typeof(Interpreter), "os_flush: '" + outputBuffer.ToString().Replace("\r", "\\r") + "'"); if (currentCommand == Commands.Dictionary) { outputBuffer.Append("\0"); } OsFlushEventArgs args = new OsFlushEventArgs(outputBuffer.ToString()); args.Command = currentCommand; OsFlush(args); outputBuffer.Remove(0, outputBuffer.Length); currentCommand = Commands.None; } /// /// os_save_file() should prompt the user in some way (with either /// text or a file requester) for a filename to save the area of /// memory of size Bytes pointed to by Ptr. true or false should be /// returned depending on whether or not the operation was successful. /// /// the area of memory to save /// the number of bytes to save /// /// true if the operation was successful; otherwise false /// public static bool os_save_file(byte *Ptr, int Bytes) { Logger.Log(typeof(Interpreter), "os_save_file"); byte[] bytes = new byte[Bytes]; for (int i = 0; i < Bytes; i++) { bytes[i] = Ptr[i]; } OsSaveFileEventArgs args = new OsSaveFileEventArgs(bytes); OsSaveFile(args); return args.Success; } /// /// os_load_file() should prompt the user for the name of a file to /// load. At most Max bytes should be loaded into the memory pointed /// to by Ptr, and the number of bytes read should be placed into the /// variable pointed to by Bytes. /// /// an area of memory to write the data to /// the number of bytes read /// the maximum number of bytes to read /// /// true if the operation was successful; otherwise false /// public static bool os_load_file(byte *Ptr, int *Bytes, int Max) { Logger.Log(typeof(Interpreter), "os_load_file"); OsLoadFileEventArgs args = new OsLoadFileEventArgs(Max); OsLoadFile(args); if (args.Bytes != null) { for (int i = 0; i < args.Bytes.Length; i++) { Ptr[i] = args.Bytes[i]; } *Bytes = args.Bytes.Length; } else { *Bytes = 0; } return args.Success; } /// /// os_get_game_file() should prompt the user for a new game file, to /// be stored in NewName, which can take a maximum name of Size /// characters. When this function is called the NewName array /// contains the name of the currently loaded game, which can be used /// to derive a name to prompt the user with. /// This is used by at least the Adrian Mole games, which load in the /// next part of the game after the part currently being played has /// been completed. These games were originally written for tape-based /// systems where the call was simply "load the next game from the /// tape". /// /// the name of a game file /// the maximum length of NewName /// /// true if the operation was successful; otherwise false /// public static bool os_get_game_file(byte *NewName, int Size) { string currentFile = BytesToString(NewName, Size); OsGetGameFileEventArgs args = new OsGetGameFileEventArgs(currentFile); OsGetGameFile(args); Logger.Log(typeof(Interpreter), "os_get_game_file: " + args.Filename); StringToBytes(args.Filename, NewName, Size); if (args.Success) { SetGameFile(args.Filename); } return args.Success; } /// /// os_set_filenumber() is for multi-part games originally written for /// disk-based systems, which used game filenames such as /// /// gamedat1.dat /// gamedat2.dat /// gamedat3.dat /// /// etc. The routine should take the full filename in NewName (of /// maximum size Size) and modify it to reflect the number n, e.g. /// os_set_filename("gamedat1.dat", 2) should leave "gamedat2.dat" /// in NewName. /// /// the name of the new game file /// the maximum length of NewName /// the number of the new game file public static void os_set_filenumber(byte *NewName, int Size, int n) { StringBuilder path = new StringBuilder(BytesToString(NewName, Size)); int i = path.Length; while (!Char.IsDigit(path[--i]) && i > 0); path.Replace(path[i], (char)('0' + n), i, 1); string newPath = path.ToString(); if (File.Exists(newPath)) { StringToBytes(newPath, NewName, Size); SetGameFile(newPath); } Logger.Log(typeof(Interpreter), "os_set_filenumber: '" + newPath + "', n: " + n); } /// /// Called when graphics are turned on or off, either by the game or /// by the user entering "graphics" or "text" as a command. If mode /// is 0 graphics should be turned off, else they should be turned on. /// After a os_graphics(0) call all the other graphics functions /// should do nothing. /// Typically, if mode is not 0 the code will allocate some suitable /// bitmap for drawing graphics into. To determine the size of the /// bitmap, the code should call GetPictureSize(). The graphics /// routines should draw in a bitmap of the size returned by this /// function, and then scale the bitmap appropriately for display. /// If instead the graphics code tries to scale the co-ordinates /// passed to os_drawline() and os_fill() then problems occur with /// fill colours "leaking" into other areas of the picture. The /// values returned by GetPictureSize() will not change unless a new /// game is loaded. /// The graphis bitmap is always 4 colour. The 4 colours are chosen /// from a possible 8 by calls to os_setcolour. Note that /// calls to os_setcolour() must affect the colour of pixels already /// drawn on the bitmap. For example, suppose a pixel in the bitmap /// is set to the first colour in the palette during drawing, which at /// that moment is red. If later the first colour in the palette is /// set to blue, at the end the pixel should be shown blue. /// In order to actually draw graphics, the input routines os_input() /// and os_readchar() should call RunGraphics(). /// /// the graphics mode public static void os_graphics(int mode) { Logger.Log(typeof(Interpreter), "os_graphics: " + mode); OsGraphics(new OsGraphicsEventArgs(mode)); } /// /// Clear the current graphics bitmap by filling the entire bitmap /// with colour 0. /// public static void os_cleargraphics() { Logger.Log(typeof(Interpreter), "os_cleargraphics"); OsClearGraphics(new OsClearGraphicsEventArgs()); } /// /// Set the given colour in the graphics bitmap's palette to the /// colour at the given index in the interpreter's table of colours. /// The actual table of colours in the interpreters provided by /// Level 9 vary across different machines. An acceptable palette /// that matches reasonably closely to the Amiga releases is as /// follows (all colours are 8 bit R,G,B): /// /// 0x00,0x00,0x00 (black) /// 0xFF,0x00,0x00 (red) /// 0x30,0xE8,0x30 (green) /// 0xFF,0xFF,0x00 (yellow) /// 0x00,0x00,0xFF (blue) /// 0xA0,0x68,0x00 (brown) /// 0x00,0xFF,0xFF (cyan) /// 0xFF,0xFF,0xFF (white) /// /// /// /// the colour in the graphics bitmap's palette /// /// /// the index in the interpreter's table of colours /// public static void os_setcolour(int colour, int index) { OsSetColour(new OsSetColourEventArgs(colour, index)); } /// /// Draw a line on the graphics bitmap between (x1,y1) and (x2,y2). /// Note that either point may lie outside of the bitmap, and that it /// is the responsibility of the routine to clip to the appropriate /// coordinates. /// For each point on the line, if the colour at that point is equal /// to colour2 the pixel's colour should be changed to colour1, else /// it should not be modified. /// /// the x coordinate of (x1,y1) /// the y coordinate of (x1,y1) /// the x coordinate of (x2,y2) /// the y coordinate of (x2,y2) /// the index of colour 1 /// the index of colour 2 public static void os_drawline(int x1, int y1, int x2, int y2, byte colour1, byte colour2) { OsDrawLineEventArgs args = new OsDrawLineEventArgs( x1, y1, x2, y2, colour1, colour2); OsDrawLine(args); } /// /// If the pixel's colour at (x,y) is equal to colour2, fill the /// region containing (x,y) with colour1. The boundaries of the /// region are defined as those areas of the bitmap with a colour /// other than colour2. /// /// the x coordinate of pixel (x,y) /// the y coordinate of pixel (x,y) /// the index of colour 1 /// the index of colour 2 public static void os_fill(int x, int y, byte colour1, byte colour2) { OsFillEventArgs args = new OsFillEventArgs(x, y, colour1, colour2); OsFill(args); } /// /// Show the bitmap given by the number pic at the coordinates (x,y). /// Note that the game can request the same picture several times /// in a row: it is a good idea for ports to record the last picture /// number and check it against any new requests. /// /// the bitmap's number /// the x coordinate /// the y coordinate public static void os_show_bitmap(int pic, int x, int y) { Logger.Log(typeof(Interpreter), "os_show_bitmap: " + pic + ", x: " + x + ", y: " + y); OsShowBitmap(new OsShowBitmapEventArgs(pic, x, y)); } /// /// LoadGame() attempts to load a filename and then searches it for /// a valid Level 9 game. If it is successful true is returned, else /// false. The previous game in memory will be overwritten if the /// file filename can be loaded, even if it does not contain a Level9 /// game, so even if LoadGame() returns false it must be assumed that /// the game memory has changed. /// The second argument is the name of the file containing picture /// data, and may be NULL. Ports should usually ask the user for just /// the filename and derive picname from it in some way. The /// recommended approach is to first try the filename with an extension /// of ".pic" and then try replacing the filename with "picture.dat". /// /// the file to load /// the file containing picture data /// /// true if successful, else false /// public static bool LoadGame(string filename, string picname) { Logger.Log(typeof(Interpreter), "LoadGame: " + filename); bool success = L9_LoadGame(filename, picname); if (success) { SetGameFile(filename); } else { GameFileError(new GameFileErrorEventArgs()); os_flush(); } return success; } /// /// If LoadGame() has been successful, RunGame() can be called to run /// the Level 9 game. Each call to RunGame() executes a single opcode /// of the game. In pre-emptive multitasking systems or systems without /// any multitasking it is enough to sit in a loop calling RunGame(), /// e.g. /// /// while (RunGame()); /// /// RunGame() returns true if an opcode code was executed and false if /// the game is stopped, either by an error or by calls to StopGame(). /// /// /// true if an opcode code was executed and false if the game is /// stopped. /// public static bool RunGame() { return L9_RunGame(); } /// /// StopGame() stops the current game from playing. /// public static void StopGame() { L9_StopGame(); } /// /// RestoreGame() attempts to restore the currently running game to /// the position stored in the inFile saved game file. This gives /// interface code a means to restore a game position. /// /// the saved game file public static void RestoreGame(string inFile) { L9_RestoreGame(inFile); } /// /// FreeMemory() frees memory used to store the game. This routine /// should be called when exiting the interpreter. /// public static void FreeMemory() { L9_FreeMemory(); } /// /// Returns the width and height of the bitmap that graphics should /// be drawn into. This is constant for any particular game. /// /// the bitmap's width /// the bitmap's height public static void GetPictureSize(ref int width, ref int height) { L9_GetPictureSize(ref width, ref height); } /// /// Runs an opcode of the graphics routines. The simplest way to /// display graphics. If a graphics opcode was run true is returned, /// otherwise false. /// The simplest way to get graphics to display is to add a loop to /// repeatedly call RunGraphics() to os_input() and os_readchar(): /// /// while (RunGraphics()); /// // Now draw graphics bitmap on display... /// /// Optionally, the code can provide a more "atmospheric" recreation /// of the games by drawing the graphics slowly, as was the case on /// the old 8-bit computers. This is achieved by calling RunGraphics() /// several times then waiting for a while before calling it again. /// Note that when waiting the code should still respond to user /// input. /// /// /// true if a graphics opcode was run; otherwise false /// public static bool RunGraphics() { return L9_RunGraphics(); } /// /// This function must be called first to initialize the decoder. /// It tries to determine which format of bitmap pictures is /// available in the given directory. /// /// the game directory /// true if supported pictures are found public static bool DetectBitmaps(string path) { return L9_DetectBitmaps(path); } /// /// Decode and return picture with the given number. /// /// the picture's number /// /// IntPtr.Zero if decoding fails; otherwise IntPtr is a reference to /// a L9Bitmap structure /// public static IntPtr DecodeBitmap(int n) { return L9_DecodeBitmap(n); } /// /// Adds an input request. Typically used by the application to /// execute special interpreter commands. See /// for details. /// /// an input command public static void AddInputRequest(Commands command) { Logger.Log(typeof(Interpreter), "AddInputRequest: " + command); inputRequests.Add(command); } /// /// Sets a new game file and notifies the listeners. /// /// the game file's path public static void SetGameFile(string filePath) { gameFilePath = filePath; gameTitle = L9Cut.GetGameTitle(filePath); NewGameFile(new NewGameFileEventArgs()); } /// /// Converts a byte array into a string. /// /// a byte array /// the maximum number of bytes to convert /// a string representation of the byte array static string BytesToString(byte *source, int size) { StringBuilder builder = new StringBuilder(); for (int i = 0; (source[i] != 0 && i < size); i++) { builder.Append(Convert.ToChar(source[i])); } return builder.ToString(); } /// /// Converts a string into a byte array. /// /// the source string /// a byte array /// /// the maximum number of characters to convert /// static void StringToBytes(String source, byte *target, int max) { int i = 0; if (source == null || source.Length > max) { return; } for (i = 0; (i < source.Length) && (i < max - 1); i++) { target[i] = Convert.ToByte(source[i]); } target[i] = 0; } // -- Accessors ------------------------------------------------------ /// /// Gets the current game file's path. /// public static string GameFilePath { get { return gameFilePath; } } /// /// Gets the current game's title. /// public static string GameTitle { get { return gameTitle; } } } /// /// Represents the method that handles a OsFlush event. /// public delegate void OsFlushEventHandler(OsFlushEventArgs e); /// /// Provides data for the OsFlush event. /// public class OsFlushEventArgs : EventArgs { // -- Attributes ----------------------------------------------------- /// /// The text to flush. /// string text = null; /// /// The current interpreter command. /// See for details. /// Interpreter.Commands command = Interpreter.Commands.None; // -- Constructors --------------------------------------------------- /// /// Initializes a new instance of the OsFlushEventArgs class. /// /// the text to flush public OsFlushEventArgs(string text) { this.text = text; } // -- Accessors ------------------------------------------------------ /// /// Gets or sets the current interpreter command. /// public Interpreter.Commands Command { get { return command; } set { command = value; } } /// /// Gets or sets the text to flush. /// public string Text { get { return text; } set { text = value; } } } /// /// Represents the method that handles a OsInput event. /// public delegate void OsInputEventHandler(OsInputEventArgs e); /// /// Provides data for the OsInput event. /// public class OsInputEventArgs : EventArgs { // -- Attributes ----------------------------------------------------- /// /// The input line. /// string input = null; // -- Accessors ------------------------------------------------------ /// Gets or sets the input line. public string Input { get { return input; } set { input = value; } } } /// /// Represents the method that handles a OsReadchar event. /// public delegate void OsReadcharEventHandler(OsReadcharEventArgs e); /// /// Provides data for the OsReadchar event. /// public class OsReadcharEventArgs : EventArgs { // -- Attributes ----------------------------------------------------- /// /// The input character. /// byte character = 0; /// /// The number of milliseconds to wait for a keystroke. /// int millis = 0; // -- Constructors --------------------------------------------------- /// /// Initializes a new instance of the OsReadcharEventArgs class. /// /// /// the number of milliseconds to wait for a keystroke /// public OsReadcharEventArgs(int millis) { this.millis = millis; } // -- Accessors ------------------------------------------------------ /// /// Gets or sets the input character. /// public byte Character { get { return character; } set { character = value; } } /// /// Gets or sets the number of milliseconds to wait for a keystroke. /// public int Millis { get { return millis; } set { millis = value; } } } /// /// Represents the method that handles a OsSaveFile event. /// public delegate void OsSaveFileEventHandler(OsSaveFileEventArgs e); /// /// Provides data for the OsSaveFile event. /// public class OsSaveFileEventArgs : EventArgs { // -- Attributes ----------------------------------------------------- /// /// The portion of bytes to save. /// byte[] bytes; /// /// This property indicates whether the operation was successful. /// bool success = false; // -- Constructors --------------------------------------------------- /// /// Initializes a new instance of the OsSaveFileEventArgs class. /// /// the portion of bytes to save public OsSaveFileEventArgs(byte[] bytes) { this.bytes = bytes; } // -- Accessors ------------------------------------------------------ /// /// Gets or sets the portion of bytes to save. /// public byte[] Bytes { get { return bytes; } set { bytes = value; } } /// /// Gets or sets a value that indicates whether the operation was /// successful. /// public bool Success { get { return success; } set { success = value; } } } /// /// Represents the method that handles a OsLoadFile event. /// public delegate void OsLoadFileEventHandler(OsLoadFileEventArgs e); /// /// Provides data for the OsLoadFile event. /// public class OsLoadFileEventArgs : EventArgs { // -- Attributes ----------------------------------------------------- /// /// The number of bytes loaded. /// byte[] bytes; /// /// The maximum number of bytes to load. /// int maxBytes; /// /// This property indicates whether the operation was successful. /// bool success = false; // -- Constructors --------------------------------------------------- /// /// Initializes a new instance of the OsLoadFileEventArgs class. /// /// the maximum number of bytes to load public OsLoadFileEventArgs(int maxBytes) { this.maxBytes = maxBytes; } // -- Accessors ------------------------------------------------------ /// /// Gets or sets the number of bytes loaded. /// public byte[] Bytes { get { return bytes; } set { bytes = value; } } /// /// Gets or sets a value that indicates whether the operation was /// successful. /// public bool Success { get { return success; } set { success = value; } } /// /// Gets or sets the maximum number of bytes to load. /// public int MaxBytes { get { return maxBytes; } set { maxBytes = value; } } } /// /// Represents the method that handles a OsGetGameFile event. /// public delegate void OsGetGameFileEventHandler(OsGetGameFileEventArgs e); /// /// Provides data for the OsGetGameFile event. /// public class OsGetGameFileEventArgs : EventArgs { // -- Attributes ----------------------------------------------------- /// /// The game file name. /// string filename = null; /// /// This property indicates whether the operation was successful. /// bool success = false; // -- Constructors --------------------------------------------------- /// /// Initializes a new instance of the OsGetGameFileEventArgs class. /// /// the game file name public OsGetGameFileEventArgs(string filename) { this.filename = filename; } // -- Accessors ------------------------------------------------------ /// /// Gets or sets the game file name. /// public string Filename { get { return filename; } set { filename = value; } } /// /// Gets or sets a value that indicates whether the operation was /// successful. /// public bool Success { get { return success; } set { success = value; } } } /// /// Represents the method that handles a NewGameFile event. /// public delegate void NewGameFileEventHandler(NewGameFileEventArgs e); /// /// Provides data for the NewGameFile event. /// public class NewGameFileEventArgs : EventArgs { // -- Constructors --------------------------------------------------- /// /// Initializes a new instance of the NewGameFileEventArgs class. /// public NewGameFileEventArgs() { } } /// /// Represents the method that handles a OsGraphics event. /// public delegate void OsGraphicsEventHandler(OsGraphicsEventArgs e); /// /// Provides data for the OsGraphics event. /// public class OsGraphicsEventArgs : EventArgs { // -- Attributes ----------------------------------------------------- /// /// The graphics mode. /// See for details. /// int mode = 0; // -- Constructors --------------------------------------------------- /// /// Initializes a new instance of the OsGraphicsEventArgs class. /// /// the graphics mode public OsGraphicsEventArgs(int mode) { this.mode = mode; } // -- Accessors ------------------------------------------------------ /// /// Gets or sets the graphics mode. /// public int Mode { get { return mode; } set { mode = value; } } } /// /// Represents the method that handles a OsClearGraphics event. /// public delegate void OsClearGraphicsEventHandler( OsClearGraphicsEventArgs e); /// /// Provides data for the OsClearGraphics event. /// public class OsClearGraphicsEventArgs : EventArgs { // -- Constructors --------------------------------------------------- /// /// Initializes a new instance of the OsClearGraphicsEventArgs class. /// public OsClearGraphicsEventArgs() { } } /// /// Delegate declaration of the OsDrawLine event handler. /// public delegate void OsDrawLineEventHandler(OsDrawLineEventArgs e); /// /// Provides data for the OsDrawLine event. /// public class OsDrawLineEventArgs : EventArgs { // -- Attributes ----------------------------------------------------- /// /// The x coordinate of pixel (x1,y1). /// int x1 = 0; /// /// The y coordinate of pixel (x1,y1). /// int y1 = 0; /// /// The x coordinate of pixel (x2,y2). /// int x2 = 0; /// /// The y coordinate of pixel (x2,y2). /// int y2 = 0; /// /// The index of colour 1. /// byte colour1 = 0; /// /// The index of colour 2. /// byte colour2 = 0; // -- Constructors --------------------------------------------------- /// /// Initializes a new instance of the OsDrawLineEventArgs class. /// /// the x coordinate of pixel (x1,y1) /// the y coordinate of pixel (x1,y1) /// the x coordinate of pixel (x2,y2) /// the y coordinate of pixel (x2,y2) /// the index of colour 1 /// the index of colour 2 public OsDrawLineEventArgs(int x1, int y1, int x2, int y2, byte colour1, byte colour2) { this.x1 = x1; this.y1 = y1; this.x2 = x2; this.y2 = y2; this.colour1 = colour1; this.colour2 = colour2; } // -- Accessors ------------------------------------------------------ /// /// Gets or sets the x coordinate of pixel (x1,y1). /// public int X1 { get { return x1; } set { x1 = value; } } /// /// Gets or sets the y coordinate of pixel (x1,y1). /// public int Y1 { get { return y1; } set { y1 = value; } } /// /// Gets or sets the x coordinate of pixel (x2,y2). /// public int X2 { get { return x2; } set { x2 = value; } } /// /// Gets or sets the y coordinate of pixel (x2,y2). /// public int Y2 { get { return y2; } set { y2 = value; } } /// /// Gets or sets the index of colour 1. /// public byte Colour1 { get { return colour1; } set { colour1 = value; } } /// /// Gets or sets the index of colour 2. /// public byte Colour2 { get { return colour2; } set { colour2 = value; } } } /// /// Represents the method that handles a OsFill event. /// public delegate void OsFillEventHandler(OsFillEventArgs e); /// /// Provides data for the OsFill event. /// public class OsFillEventArgs : EventArgs { // -- Attributes ----------------------------------------------------- /// /// The x coordinate of pixel (x,y). /// int x = 0; /// /// The y coordinate of pixel (x,y). /// int y = 0; /// /// The index of colour 1. /// byte colour1 = 0; /// /// The index of colour 2. /// byte colour2 = 0; // -- Constructors --------------------------------------------------- /// /// Initializes a new instance of the OsFillEventArgs class. /// /// the x coordinate of pixel (x,y) /// the y coordinate of pixel (x,y) /// the index of colour 1 /// the index of colour 2 public OsFillEventArgs(int x, int y, byte colour1, byte colour2) { this.x = x; this.y = y; this.colour1 = colour1; this.colour2 = colour2; } // -- Accessors ------------------------------------------------------ /// /// Gets or sets the x coordinate of pixel (x,y). /// public int X { get { return x; } set { x = value; } } /// /// Gets or sets the y coordinate of pixel (x,y). /// public int Y { get { return y; } set { y = value; } } /// /// Gets or sets the index of colour 1. /// public byte Colour1 { get { return colour1; } set { colour1 = value; } } /// /// Gets or sets the index of colour 2. /// public byte Colour2 { get { return colour2; } set { colour2 = value; } } } /// /// Represents the method that handles a OsSetColour event. /// public delegate void OsSetColourEventHandler(OsSetColourEventArgs e); /// /// Provides data for the OsSetColour event. /// public class OsSetColourEventArgs : EventArgs { // -- Attributes ----------------------------------------------------- /// /// The colour in the graphics bitmap's palette. /// int colour = 0; /// /// The index in the interpreter's table of colours. /// int index = 0; // -- Constructors --------------------------------------------------- /// /// Initializes a new instance of the OsSetColourEventArgs class. /// /// /// the colour in the graphics bitmap's palette /// /// /// the index in the interpreter's table of colours /// public OsSetColourEventArgs(int colour, int index) { this.colour = colour; this.index = index; } // -- Accessors ------------------------------------------------------ /// /// Gets or sets the colour in the graphics bitmap's palette. /// public int Colour { get { return colour; } set { colour = value; } } /// /// Gets or sets the index in the interpreter's table of colours. /// public int Index { get { return index; } set { index = value; } } } /// /// Represents the method that handles a OsShowBitmap event. /// public delegate void OsShowBitmapEventHandler(OsShowBitmapEventArgs e); /// /// Provides data for the OsShowBitmap event. /// public class OsShowBitmapEventArgs : EventArgs { // -- Attributes ----------------------------------------------------- /// /// The bitmap's number. /// int number = 0; /// /// The bitmap's x offset. /// int x = 0; /// /// The bitmap's y offset. /// int y = 0; // -- Constructors --------------------------------------------------- /// /// Initializes a new instance of the OsShowBitmapEventArgs class. /// /// the bitmap's number /// the bitmap's x offset /// the bitmap's y offset public OsShowBitmapEventArgs(int number, int x, int y) { this.number = number; this.x = x; this.y = y; } // -- Accessors ------------------------------------------------------ /// /// Gets or sets the bitmap's number. /// public int Number { get { return number; } set { number = value; } } /// /// Gets or sets the bitmap's x offset. /// public int X { get { return x; } set { x = value; } } /// /// Gets or sets the bitmap's y offset. /// public int Y { get { return y; } set { y = value; } } } /// /// Represents the method that handles a GameFileError event. /// public delegate void GameFileErrorEventHandler(GameFileErrorEventArgs e); /// /// Provides data for the GameFileError event. /// public class GameFileErrorEventArgs : EventArgs { // -- Constructors --------------------------------------------------- /// /// Initializes a new instance of the GameFileErrorEventArgs class. /// public GameFileErrorEventArgs() { } } /// /// Represents the method that handles a InputFinished event. /// public delegate void InputFinishedEventHandler(InputFinishedEventArgs e); /// /// Provides data for the InputFinished event. /// public class InputFinishedEventArgs : EventArgs { // -- Attributes ----------------------------------------------------- /// /// The input line. /// string input = null; // -- Constructors --------------------------------------------------- /// /// Initializes a new instance of the InputFinishedEventArgs class. /// /// the input line public InputFinishedEventArgs(string input) { this.input = input; } // -- Accessors ------------------------------------------------------ /// /// Gets or sets the input line. /// public string Input { get { return input; } set { input = value; } } } }