/*
* 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;
}
}
}
}