diff src/common/lua-engine.cpp @ 19:5e8e5083da94

brought in common and gba, fixed problems with outdated Makefile.am files in both of these packages
author Robert McIntyre <rlm@mit.edu>
date Sun, 04 Mar 2012 14:33:52 -0600
parents f9f4f1b99eed
children bf9169ad4222
line wrap: on
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/common/lua-engine.cpp	Sun Mar 04 14:33:52 2012 -0600
     1.3 @@ -0,0 +1,5102 @@
     1.4 +#include <cstdio>
     1.5 +#include <cstdlib>
     1.6 +#include <malloc.h>
     1.7 +#include <string>
     1.8 +#include <cassert>
     1.9 +#include <cctype>
    1.10 +#include <cmath>
    1.11 +#include <ctime>
    1.12 +
    1.13 +#include <vector>
    1.14 +#include <map>
    1.15 +#include <string>
    1.16 +#include <algorithm>
    1.17 +
    1.18 +using namespace std;
    1.19 +
    1.20 +#ifdef __linux
    1.21 +	#include <unistd.h> // for unlink
    1.22 +	#include <sys/types.h>
    1.23 +	#include <sys/wait.h>
    1.24 +#endif
    1.25 +#if (defined(WIN32) && !defined(SDL))
    1.26 +	#include <direct.h>
    1.27 +	#include "../win32/stdafx.h"
    1.28 +	#include "../win32/Input.h"
    1.29 +	#include "../win32/MainWnd.h"
    1.30 +	#include "../win32/VBA.h"
    1.31 +	#include "../win32/LuaOpenDialog.h"
    1.32 +#else
    1.33 +	#define stricmp strcasecmp
    1.34 +	#define strnicmp strncasecmp
    1.35 +#endif
    1.36 +
    1.37 +#include "../Port.h"
    1.38 +#include "System.h"
    1.39 +#include "movie.h"
    1.40 +#include "../gba/GBA.h"
    1.41 +#include "../gba/GBAGlobals.h"
    1.42 +#include "../gb/GB.h"
    1.43 +#include "../gb/gbGlobals.h"
    1.44 +#include "../gba/GBASound.h"
    1.45 +
    1.46 +#ifdef _WIN32
    1.47 +#include "../win32/Sound.h"
    1.48 +//#include "../win32/WinMiscUtil.h"
    1.49 +extern CString winGetSavestateFilename(const CString &LogicalRomName, int nID);
    1.50 +#else
    1.51 +#endif
    1.52 +
    1.53 +extern "C"
    1.54 +{
    1.55 +#include "../lua/src/lua.h"
    1.56 +#include "../lua/src/lauxlib.h"
    1.57 +#include "../lua/src/lualib.h"
    1.58 +#include "../lua/src/lstate.h"
    1.59 +}
    1.60 +#include "vbalua.h"
    1.61 +
    1.62 +#include "../SFMT/SFMT.c"
    1.63 +
    1.64 +static void (*info_print)(int uid, const char *str);
    1.65 +static void (*info_onstart)(int uid);
    1.66 +static void (*info_onstop)(int uid);
    1.67 +static int	info_uid;
    1.68 +
    1.69 +#ifndef countof
    1.70 +	#define countof(a)  (sizeof(a) / sizeof(a[0]))
    1.71 +#endif
    1.72 +
    1.73 +static lua_State *LUA;
    1.74 +
    1.75 +// Are we running any code right now?
    1.76 +static char *luaScriptName = NULL;
    1.77 +
    1.78 +// Are we running any code right now?
    1.79 +static bool8 luaRunning = false;
    1.80 +
    1.81 +// True at the frame boundary, false otherwise.
    1.82 +static bool8 frameBoundary = false;
    1.83 +
    1.84 +// The execution speed we're running at.
    1.85 +static enum { SPEED_NORMAL, SPEED_NOTHROTTLE, SPEED_TURBO, SPEED_MAXIMUM } speedmode = SPEED_NORMAL;
    1.86 +
    1.87 +// Rerecord count skip mode
    1.88 +static bool8 skipRerecords = false;
    1.89 +
    1.90 +// Used by the registry to find our functions
    1.91 +static const char *frameAdvanceThread = "VBA.FrameAdvance";
    1.92 +static const char *guiCallbackTable	  = "VBA.GUI";
    1.93 +
    1.94 +// True if there's a thread waiting to run after a run of frame-advance.
    1.95 +static bool8 frameAdvanceWaiting = false;
    1.96 +
    1.97 +// We save our pause status in the case of a natural death.
    1.98 +//static bool8 wasPaused = false;
    1.99 +
   1.100 +// Transparency strength. 255=opaque, 0=so transparent it's invisible
   1.101 +static int transparencyModifier = 255;
   1.102 +
   1.103 +// Our joypads.
   1.104 +static uint32 lua_joypads[4];
   1.105 +static uint8  lua_joypads_used = 0;
   1.106 +
   1.107 +static bool8  gui_used = false;
   1.108 +static uint8 *gui_data = NULL;          // BGRA
   1.109 +
   1.110 +// Protects Lua calls from going nuts.
   1.111 +// We set this to a big number like 1000 and decrement it
   1.112 +// over time. The script gets knifed once this reaches zero.
   1.113 +static int numTries;
   1.114 +
   1.115 +// number of registered memory functions (1 per hooked byte)
   1.116 +static unsigned int numMemHooks;
   1.117 +
   1.118 +// Look in inputglobal.h for macros named like BUTTON_MASK_UP to determine the order.
   1.119 +static const char *button_mappings[] = {
   1.120 +	"A", "B", "select", "start", "right", "left", "up", "down", "R", "L"
   1.121 +};
   1.122 +
   1.123 +#ifdef _MSC_VER
   1.124 +	#define snprintf _snprintf
   1.125 +	#define vscprintf _vscprintf
   1.126 +#else
   1.127 +	#define stricmp strcasecmp
   1.128 +	#define strnicmp strncasecmp
   1.129 +	#define __forceinline __attribute__((always_inline))
   1.130 +#endif
   1.131 +
   1.132 +static const char *luaCallIDStrings[] =
   1.133 +{
   1.134 +	"CALL_BEFOREEMULATION",
   1.135 +	"CALL_AFTEREMULATION",
   1.136 +	"CALL_BEFOREEXIT"
   1.137 +};
   1.138 +
   1.139 +//make sure we have the right number of strings
   1.140 +CTASSERT(sizeof(luaCallIDStrings) / sizeof(*luaCallIDStrings) == LUACALL_COUNT)
   1.141 +
   1.142 +static const char *luaMemHookTypeStrings [] =
   1.143 +{
   1.144 +	"MEMHOOK_WRITE",
   1.145 +	"MEMHOOK_READ",
   1.146 +	"MEMHOOK_EXEC",
   1.147 +
   1.148 +	"MEMHOOK_WRITE_SUB",
   1.149 +	"MEMHOOK_READ_SUB",
   1.150 +	"MEMHOOK_EXEC_SUB",
   1.151 +};
   1.152 +
   1.153 +//make sure we have the right number of strings
   1.154 +CTASSERT(sizeof(luaMemHookTypeStrings) / sizeof(*luaMemHookTypeStrings) ==  LUAMEMHOOK_COUNT)
   1.155 +
   1.156 +static char *rawToCString(lua_State * L, int idx = 0);
   1.157 +static const char *toCString(lua_State *L, int idx = 0);
   1.158 +
   1.159 +// GBA memory I/O functions copied from win32/MemoryViewerDlg.cpp
   1.160 +static inline u8 CPUReadByteQuick(u32 addr)
   1.161 +{
   1.162 +	return ::map[addr >> 24].address[addr & ::map[addr >> 24].mask];
   1.163 +}
   1.164 +
   1.165 +static inline void CPUWriteByteQuick(u32 addr, u8 b)
   1.166 +{
   1.167 +	::map[addr >> 24].address[addr & ::map[addr >> 24].mask] = b;
   1.168 +}
   1.169 +
   1.170 +static inline u16 CPUReadHalfWordQuick(u32 addr)
   1.171 +{
   1.172 +	return *((u16 *) &::map[addr >> 24].address[addr & ::map[addr >> 24].mask]);
   1.173 +}
   1.174 +
   1.175 +static inline void CPUWriteHalfWordQuick(u32 addr, u16 b)
   1.176 +{
   1.177 +	*((u16 *) &::map[addr >> 24].address[addr & ::map[addr >> 24].mask]) = b;
   1.178 +}
   1.179 +
   1.180 +static inline u32 CPUReadMemoryQuick(u32 addr)
   1.181 +{
   1.182 +	return *((u32 *) &::map[addr >> 24].address[addr & ::map[addr >> 24].mask]);
   1.183 +}
   1.184 +
   1.185 +static inline void CPUWriteMemoryQuick(u32 addr, u32 b)
   1.186 +{
   1.187 +	*((u32 *) &::map[addr >> 24].address[addr & ::map[addr >> 24].mask]) = b;
   1.188 +}
   1.189 +
   1.190 +// GB
   1.191 +static inline u8 gbReadMemoryQuick8(u16 addr)
   1.192 +{
   1.193 +	return gbReadMemoryQuick(addr);
   1.194 +}
   1.195 +
   1.196 +static inline void gbWriteMemoryQuick8(u16 addr, u8 b)
   1.197 +{
   1.198 +	gbWriteMemoryQuick(addr, b);
   1.199 +}
   1.200 +
   1.201 +static inline u16 gbReadMemoryQuick16(u16 addr)
   1.202 +{
   1.203 +	return (gbReadMemoryQuick(addr + 1) << 8) | gbReadMemoryQuick(addr);
   1.204 +}
   1.205 +
   1.206 +static inline void gbWriteMemoryQuick16(u16 addr, u16 b)
   1.207 +{
   1.208 +	gbWriteMemoryQuick(addr, b & 0xff);
   1.209 +	gbWriteMemoryQuick(addr + 1, (b >> 8) & 0xff);
   1.210 +}
   1.211 +
   1.212 +static inline u32 gbReadMemoryQuick32(u16 addr)
   1.213 +{
   1.214 +	return (gbReadMemoryQuick(addr + 3) << 24) |
   1.215 +	       (gbReadMemoryQuick(addr + 2) << 16) |
   1.216 +	       (gbReadMemoryQuick(addr + 1) << 8) |
   1.217 +	       gbReadMemoryQuick(addr);
   1.218 +}
   1.219 +
   1.220 +static inline void gbWriteMemoryQuick32(u16 addr, u32 b)
   1.221 +{
   1.222 +	gbWriteMemoryQuick(addr, b & 0xff);
   1.223 +	gbWriteMemoryQuick(addr + 1, (b >> 8) & 0xff);
   1.224 +	gbWriteMemoryQuick(addr + 2, (b >> 16) & 0xff);
   1.225 +	gbWriteMemoryQuick(addr + 1, (b >> 24) & 0xff);
   1.226 +}
   1.227 +
   1.228 +static inline u8 gbReadROMQuick8(u32 addr)
   1.229 +{
   1.230 +	return gbReadROMQuick(addr & gbRomSizeMask);
   1.231 +}
   1.232 +
   1.233 +static inline u8 gbReadROMQuick16(u32 addr)
   1.234 +{
   1.235 +	return (gbReadROMQuick(addr+1 & gbRomSizeMask) << 8) | gbReadROMQuick(addr & gbRomSizeMask);
   1.236 +}
   1.237 +
   1.238 +static inline u8 gbReadROMQuick32(u32 addr)
   1.239 +{
   1.240 +	return (gbReadROMQuick(addr+3 & gbRomSizeMask) << 24) |
   1.241 +	       (gbReadROMQuick(addr+2 & gbRomSizeMask) << 16) |
   1.242 +	       (gbReadROMQuick(addr+1 & gbRomSizeMask) << 8) |
   1.243 +	       gbReadROMQuick(addr & gbRomSizeMask);
   1.244 +}
   1.245 +
   1.246 +typedef void (*GetColorFunc)(const uint8 *, uint8 *, uint8 *, uint8 *);
   1.247 +typedef void (*SetColorFunc)(uint8 *, uint8, uint8, uint8);
   1.248 +
   1.249 +static void getColor16(const uint8 *s, uint8 *r, uint8 *g, uint8 *b)
   1.250 +{
   1.251 +	u16 v = *(const uint16 *)s;
   1.252 +	*r = ((v >> systemBlueShift) & 0x001f) << 3;
   1.253 +	*g = ((v >> systemGreenShift) & 0x001f) << 3;
   1.254 +	*b = ((v >> systemRedShift) & 0x001f) << 3;
   1.255 +}
   1.256 +
   1.257 +static void getColor24(const uint8 *s, uint8 *r, uint8 *g, uint8 *b)
   1.258 +{
   1.259 +	if (systemRedShift > systemBlueShift)
   1.260 +		*b = s[0], *g = s[1], *r = s[2];
   1.261 +	else
   1.262 +		*r = s[0], *g = s[1], *b = s[2];
   1.263 +}
   1.264 +
   1.265 +static void getColor32(const uint8 *s, uint8 *r, uint8 *g, uint8 *b)
   1.266 +{
   1.267 +	u32 v = *(const uint32 *)s;
   1.268 +	*b = ((v >> systemBlueShift) & 0x001f) << 3;
   1.269 +	*g = ((v >> systemGreenShift) & 0x001f) << 3;
   1.270 +	*r = ((v >> systemRedShift) & 0x001f) << 3;
   1.271 +}
   1.272 +
   1.273 +static void setColor16(uint8 *s, uint8 r, uint8 g, uint8 b)
   1.274 +{
   1.275 +	*(uint16 *)s = ((b >> 3) & 0x01f) <<
   1.276 +	               systemBlueShift |
   1.277 +	               ((g >> 3) & 0x01f) <<
   1.278 +	               systemGreenShift |
   1.279 +	               ((r >> 3) & 0x01f) <<
   1.280 +	               systemRedShift;
   1.281 +}
   1.282 +
   1.283 +static void setColor24(uint8 *s, uint8 r, uint8 g, uint8 b)
   1.284 +{
   1.285 +	if (systemRedShift > systemBlueShift)
   1.286 +		s[0] = b, s[1] = g, s[2] = r;
   1.287 +	else
   1.288 +		s[0] = r, s[1] = g, s[2] = b;
   1.289 +}
   1.290 +
   1.291 +static void setColor32(uint8 *s, uint8 r, uint8 g, uint8 b)
   1.292 +{
   1.293 +	*(uint32 *)s = ((b >> 3) & 0x01f) <<
   1.294 +	               systemBlueShift |
   1.295 +	               ((g >> 3) & 0x01f) <<
   1.296 +	               systemGreenShift |
   1.297 +	               ((r >> 3) & 0x01f) <<
   1.298 +	               systemRedShift;
   1.299 +}
   1.300 +
   1.301 +static bool getColorIOFunc(int depth, GetColorFunc *getColor, SetColorFunc *setColor)
   1.302 +{
   1.303 +	switch (depth)
   1.304 +	{
   1.305 +	case 16:
   1.306 +		if (getColor)
   1.307 +			*getColor = getColor16;
   1.308 +		if (setColor)
   1.309 +			*setColor = setColor16;
   1.310 +		return true;
   1.311 +	case 24:
   1.312 +		if (getColor)
   1.313 +			*getColor = getColor24;
   1.314 +		if (setColor)
   1.315 +			*setColor = setColor24;
   1.316 +		return true;
   1.317 +	case 32:
   1.318 +		if (getColor)
   1.319 +			*getColor = getColor32;
   1.320 +		if (setColor)
   1.321 +			*setColor = setColor32;
   1.322 +		return true;
   1.323 +	default:
   1.324 +		return false;
   1.325 +	}
   1.326 +}
   1.327 +
   1.328 +/**
   1.329 + * Resets emulator speed / pause states after script exit.
   1.330 + */
   1.331 +static void VBALuaOnStop(void)
   1.332 +{
   1.333 +	luaRunning		 = false;
   1.334 +	lua_joypads_used = 0;
   1.335 +	gui_used		 = false;
   1.336 +	//if (wasPaused)
   1.337 +	//	systemSetPause(true);
   1.338 +}
   1.339 +
   1.340 +/**
   1.341 + * Asks Lua if it wants control of the emulator's speed.
   1.342 + * Returns 0 if no, 1 if yes. If yes, we also tamper with the
   1.343 + * IPPU's settings for speed ourselves, so the calling code
   1.344 + * need not do anything.
   1.345 + */
   1.346 +int VBALuaSpeed(void)
   1.347 +{
   1.348 +	if (!LUA || !luaRunning)
   1.349 +		return 0;
   1.350 +
   1.351 +	//printf("%d\n", speedmode);
   1.352 +	switch (speedmode)
   1.353 +	{
   1.354 +	/*
   1.355 +	   case SPEED_NORMAL:
   1.356 +	    return 0;
   1.357 +	   case SPEED_NOTHROTTLE:
   1.358 +	    IPPU.RenderThisFrame = true;
   1.359 +	    return 1;
   1.360 +
   1.361 +	   case SPEED_TURBO:
   1.362 +	    IPPU.SkippedFrames++;
   1.363 +	    if (IPPU.SkippedFrames >= 40) {
   1.364 +	        IPPU.SkippedFrames = 0;
   1.365 +	        IPPU.RenderThisFrame = true;
   1.366 +	    }
   1.367 +	    else
   1.368 +	        IPPU.RenderThisFrame = false;
   1.369 +	    return 1;
   1.370 +
   1.371 +	   // In mode 3, SkippedFrames is set to zero so that the frame
   1.372 +	   // skipping code doesn't try anything funny.
   1.373 +	   case SPEED_MAXIMUM:
   1.374 +	    IPPU.SkippedFrames=0;
   1.375 +	    IPPU.RenderThisFrame = false;
   1.376 +	    return 1;
   1.377 +	 */
   1.378 +	case 0: // FIXME: to get rid of the warning
   1.379 +	default:
   1.380 +		assert(false);
   1.381 +		return 0;
   1.382 +	}
   1.383 +}
   1.384 +
   1.385 +///////////////////////////
   1.386 +// vba.speedmode(string mode)
   1.387 +//
   1.388 +//   Takes control of the emulation speed
   1.389 +//   of the system. Normal is normal speed (60fps, 50 for PAL),
   1.390 +//   nothrottle disables speed control but renders every frame,
   1.391 +//   turbo renders only a few frames in order to speed up emulation,
   1.392 +
   1.393 +//   maximum renders no frames
   1.394 +static int vba_speedmode(lua_State *L)
   1.395 +{
   1.396 +	const char *mode = luaL_checkstring(L, 1);
   1.397 +
   1.398 +	if (strcasecmp(mode, "normal") == 0)
   1.399 +	{
   1.400 +		speedmode = SPEED_NORMAL;
   1.401 +	}
   1.402 +	else if (strcasecmp(mode, "nothrottle") == 0)
   1.403 +	{
   1.404 +		speedmode = SPEED_NOTHROTTLE;
   1.405 +	}
   1.406 +	else if (strcasecmp(mode, "turbo") == 0)
   1.407 +	{
   1.408 +		speedmode = SPEED_TURBO;
   1.409 +	}
   1.410 +	else if (strcasecmp(mode, "maximum") == 0)
   1.411 +	{
   1.412 +		speedmode = SPEED_MAXIMUM;
   1.413 +	}
   1.414 +	else
   1.415 +		luaL_error(L, "Invalid mode %s to vba.speedmode", mode);
   1.416 +
   1.417 +	//printf("new speed mode:  %d\n", speedmode);
   1.418 +	return 0;
   1.419 +}
   1.420 +
   1.421 +// vba.frameadvnace()
   1.422 +//
   1.423 +//  Executes a frame advance. Occurs by yielding the coroutine, then re-running
   1.424 +
   1.425 +//  when we break out.
   1.426 +static int vba_frameadvance(lua_State *L)
   1.427 +{
   1.428 +	// We're going to sleep for a frame-advance. Take notes.
   1.429 +	if (frameAdvanceWaiting)
   1.430 +		return luaL_error(L, "can't call vba.frameadvance() from here");
   1.431 +
   1.432 +	frameAdvanceWaiting = true;
   1.433 +
   1.434 +	// Don't do this! The user won't like us sending their emulator out of control!
   1.435 +	//	Settings.FrameAdvance = true;
   1.436 +	// Now we can yield to the main
   1.437 +	return lua_yield(L, 0);
   1.438 +
   1.439 +	// It's actually rather disappointing...
   1.440 +}
   1.441 +
   1.442 +// vba.pause()
   1.443 +//
   1.444 +//  Pauses the emulator, function "waits" until the user unpauses.
   1.445 +//  This function MAY be called from a non-frame boundary, but the frame
   1.446 +
   1.447 +//  finishes executing anwyays. In this case, the function returns immediately.
   1.448 +static int vba_pause(lua_State *L)
   1.449 +{
   1.450 +	systemSetPause(true);
   1.451 +	speedmode = SPEED_NORMAL;
   1.452 +
   1.453 +	// Return control if we're midway through a frame. We can't pause here.
   1.454 +	if (frameAdvanceWaiting)
   1.455 +	{
   1.456 +		return 0;
   1.457 +	}
   1.458 +
   1.459 +	// If it's on a frame boundary, we also yield.
   1.460 +	frameAdvanceWaiting = true;
   1.461 +	return lua_yield(L, 0);
   1.462 +}
   1.463 +
   1.464 +static int vba_registerbefore(lua_State *L)
   1.465 +{
   1.466 +	if (!lua_isnil(L, 1))
   1.467 +		luaL_checktype(L, 1, LUA_TFUNCTION);
   1.468 +	lua_settop(L, 1);
   1.469 +	lua_getfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_BEFOREEMULATION]);
   1.470 +	lua_insert(L, 1);
   1.471 +	lua_setfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_BEFOREEMULATION]);
   1.472 +
   1.473 +	//StopScriptIfFinished(luaStateToUIDMap[L]);
   1.474 +	return 1;
   1.475 +}
   1.476 +
   1.477 +static int vba_registerafter(lua_State *L)
   1.478 +{
   1.479 +	if (!lua_isnil(L, 1))
   1.480 +		luaL_checktype(L, 1, LUA_TFUNCTION);
   1.481 +	lua_settop(L, 1);
   1.482 +	lua_getfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_AFTEREMULATION]);
   1.483 +	lua_insert(L, 1);
   1.484 +	lua_setfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_AFTEREMULATION]);
   1.485 +
   1.486 +	//StopScriptIfFinished(luaStateToUIDMap[L]);
   1.487 +	return 1;
   1.488 +}
   1.489 +
   1.490 +static int vba_registerexit(lua_State *L)
   1.491 +{
   1.492 +	if (!lua_isnil(L, 1))
   1.493 +		luaL_checktype(L, 1, LUA_TFUNCTION);
   1.494 +	lua_settop(L, 1);
   1.495 +	lua_getfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_BEFOREEXIT]);
   1.496 +	lua_insert(L, 1);
   1.497 +	lua_setfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_BEFOREEXIT]);
   1.498 +
   1.499 +	//StopScriptIfFinished(luaStateToUIDMap[L]);
   1.500 +	return 1;
   1.501 +}
   1.502 +
   1.503 +static inline bool isalphaorunderscore(char c)
   1.504 +{
   1.505 +	return isalpha(c) || c == '_';
   1.506 +}
   1.507 +
   1.508 +static std::vector<const void *> s_tableAddressStack; // prevents infinite recursion of a table within a table (when cycle is
   1.509 +                                                      // found, print something like table:parent)
   1.510 +static std::vector<const void *> s_metacallStack; // prevents infinite recursion if something's __tostring returns another table
   1.511 +                                                  // that contains that something (when cycle is found, print the inner result
   1.512 +                                                  // without using __tostring)
   1.513 +
   1.514 +#define APPENDPRINT { int _n = snprintf(ptr, remaining,
   1.515 +#define END ); if (_n >= 0) { ptr += _n; remaining -= _n; } else { remaining = 0; } }
   1.516 +static void toCStringConverter(lua_State *L, int i, char * &ptr, int &remaining)
   1.517 +{
   1.518 +    if (remaining <= 0)
   1.519 +		return;
   1.520 +
   1.521 +    const char *str = ptr; // for debugging
   1.522 +
   1.523 +    // if there is a __tostring metamethod then call it
   1.524 +    int usedMeta = luaL_callmeta(L, i, "__tostring");
   1.525 +    if (usedMeta)
   1.526 +    {
   1.527 +        std::vector<const void *>::const_iterator foundCycleIter = std::find(s_metacallStack.begin(), s_metacallStack.end(), lua_topointer(L, i));
   1.528 +        if (foundCycleIter != s_metacallStack.end())
   1.529 +        {
   1.530 +            lua_pop(L, 1);
   1.531 +            usedMeta = false;
   1.532 +		}
   1.533 +        else
   1.534 +        {
   1.535 +            s_metacallStack.push_back(lua_topointer(L, i));
   1.536 +            i = lua_gettop(L);
   1.537 +		}
   1.538 +	}
   1.539 +
   1.540 +    switch (lua_type(L, i))
   1.541 +    {
   1.542 +	case LUA_TNONE:
   1.543 +		break;
   1.544 +	case LUA_TNIL:
   1.545 +		APPENDPRINT "nil" END break;
   1.546 +	case LUA_TBOOLEAN:
   1.547 +		APPENDPRINT lua_toboolean(L, i) ? "true" : "false" END break;
   1.548 +	case LUA_TSTRING : APPENDPRINT "%s", lua_tostring(L, i) END break;
   1.549 +	case LUA_TNUMBER:
   1.550 +		APPENDPRINT "%.12Lg", lua_tonumber(L, i) END break;
   1.551 +	case LUA_TFUNCTION:
   1.552 +		if ((L->base + i - 1)->value.gc->cl.c.isC)
   1.553 +		{
   1.554 +		    //lua_CFunction func = lua_tocfunction(L, i);
   1.555 +		    //std::map<lua_CFunction, const char*>::iterator iter = s_cFuncInfoMap.find(func);
   1.556 +		    //if(iter == s_cFuncInfoMap.end())
   1.557 +		    goto defcase;
   1.558 +		    //APPENDPRINT "function(%s)", iter->second END
   1.559 +		}
   1.560 +		else
   1.561 +		{
   1.562 +		    APPENDPRINT "function(" END
   1.563 +		    Proto * p = (L->base + i - 1)->value.gc->cl.l.p;
   1.564 +		    int numParams = p->numparams + (p->is_vararg ? 1 : 0);
   1.565 +		    for (int n = 0; n < p->numparams; n++)
   1.566 +		    {
   1.567 +		        APPENDPRINT "%s", getstr(p->locvars[n].varname) END
   1.568 +		        if (n != numParams - 1)
   1.569 +					APPENDPRINT "," END
   1.570 +					}
   1.571 +					if (p->is_vararg)
   1.572 +						APPENDPRINT "..." END
   1.573 +						APPENDPRINT ")" END
   1.574 +						}
   1.575 +						break;
   1.576 +defcase: default:
   1.577 +				APPENDPRINT "%s:%p", luaL_typename(L, i), lua_topointer(L, i) END break;
   1.578 +			case LUA_TTABLE:
   1.579 +				{
   1.580 +				    // first make sure there's enough stack space
   1.581 +				    if (!lua_checkstack(L, 4))
   1.582 +				    {
   1.583 +				        // note that even if lua_checkstack never returns false,
   1.584 +				        // that doesn't mean we didn't need to call it,
   1.585 +				        // because calling it retrieves stack space past LUA_MINSTACK
   1.586 +				        goto defcase;
   1.587 +					}
   1.588 +
   1.589 +				    std::vector<const void *>::const_iterator foundCycleIter =
   1.590 +				        std::find(s_tableAddressStack.begin(), s_tableAddressStack.end(), lua_topointer(L, i));
   1.591 +				    if (foundCycleIter != s_tableAddressStack.end())
   1.592 +				    {
   1.593 +				        int parentNum = s_tableAddressStack.end() - foundCycleIter;
   1.594 +				        if (parentNum > 1)
   1.595 +							APPENDPRINT "%s:parent^%d", luaL_typename(L, i), parentNum END
   1.596 +							else
   1.597 +								APPENDPRINT "%s:parent", luaL_typename(L, i) END
   1.598 +								}
   1.599 +								else
   1.600 +								{
   1.601 +								    s_tableAddressStack.push_back(lua_topointer(L, i));
   1.602 +								    struct Scope { ~Scope(){ s_tableAddressStack. pop_back(); } } scope;
   1.603 +
   1.604 +								    APPENDPRINT "{" END
   1.605 +
   1.606 +								               lua_pushnil(L); // first key
   1.607 +								    int		   keyIndex = lua_gettop(L);
   1.608 +								    int		   valueIndex = keyIndex + 1;
   1.609 +								    bool	   first = true;
   1.610 +								    bool	   skipKey = true; // true if we're still in the "array part" of the table
   1.611 +								    lua_Number arrayIndex = (lua_Number)0;
   1.612 +								    while (lua_next(L, i))
   1.613 +								    {
   1.614 +								        if (first)
   1.615 +											first = false;
   1.616 +								        else
   1.617 +											APPENDPRINT ", " END
   1.618 +											if (skipKey)
   1.619 +											{
   1.620 +											    arrayIndex += (lua_Number)1;
   1.621 +											    bool keyIsNumber = (lua_type(L, keyIndex) == LUA_TNUMBER);
   1.622 +											    skipKey = keyIsNumber && (lua_tonumber(L, keyIndex) == arrayIndex);
   1.623 +											}
   1.624 +								        if (!skipKey)
   1.625 +								        {
   1.626 +								            bool keyIsString = (lua_type(L, keyIndex) == LUA_TSTRING);
   1.627 +								            bool invalidLuaIdentifier = (!keyIsString || !isalphaorunderscore(*lua_tostring(L, keyIndex)));
   1.628 +								            if (invalidLuaIdentifier)
   1.629 +												if (keyIsString)
   1.630 +													APPENDPRINT "['" END
   1.631 +													else
   1.632 +														APPENDPRINT "[" END
   1.633 +
   1.634 +														toCStringConverter(L, keyIndex, ptr, remaining);
   1.635 +								            // key
   1.636 +
   1.637 +								            if (invalidLuaIdentifier)
   1.638 +												if (keyIsString)
   1.639 +													APPENDPRINT "']=" END
   1.640 +													else
   1.641 +														APPENDPRINT "]=" END
   1.642 +														else
   1.643 +															APPENDPRINT "=" END
   1.644 +															}
   1.645 +
   1.646 +															bool valueIsString = (lua_type(L, valueIndex) == LUA_TSTRING);
   1.647 +								            if (valueIsString)
   1.648 +												APPENDPRINT "'" END
   1.649 +
   1.650 +												toCStringConverter(L, valueIndex, ptr, remaining);  // value
   1.651 +
   1.652 +								            if (valueIsString)
   1.653 +												APPENDPRINT "'" END
   1.654 +
   1.655 +												lua_pop(L, 1);
   1.656 +
   1.657 +								            if (remaining <= 0)
   1.658 +								            {
   1.659 +								                lua_settop(L, keyIndex - 1); // stack might not be clean yet if we're breaking
   1.660 +								                                             // early
   1.661 +								                break;
   1.662 +											}
   1.663 +										}
   1.664 +								        APPENDPRINT "}" END
   1.665 +									}
   1.666 +								}
   1.667 +				        break;
   1.668 +					}
   1.669 +
   1.670 +				    if (usedMeta)
   1.671 +				    {
   1.672 +				        s_metacallStack.pop_back();
   1.673 +				        lua_pop(L, 1);
   1.674 +					}
   1.675 +				}
   1.676 +
   1.677 +				static const int s_tempStrMaxLen = 64 * 1024;
   1.678 +				static char s_tempStr [s_tempStrMaxLen];
   1.679 +
   1.680 +				static char *rawToCString(lua_State *L, int idx)
   1.681 +				{
   1.682 +				    int a = idx > 0 ? idx : 1;
   1.683 +				    int n = idx > 0 ? idx : lua_gettop(L);
   1.684 +
   1.685 +				    char *ptr = s_tempStr;
   1.686 +				    *ptr = 0;
   1.687 +
   1.688 +				    int remaining = s_tempStrMaxLen;
   1.689 +				    for (int i = a; i <= n; i++)
   1.690 +				    {
   1.691 +				        toCStringConverter(L, i, ptr, remaining);
   1.692 +				        if (i != n)
   1.693 +							APPENDPRINT " " END
   1.694 +							}
   1.695 +
   1.696 +							if (remaining < 3)
   1.697 +							{
   1.698 +							    while (remaining < 6)
   1.699 +									remaining++, ptr--;
   1.700 +							    APPENDPRINT "..." END
   1.701 +							}
   1.702 +				        APPENDPRINT "\r\n" END
   1.703 +				        // the trailing newline is so print() can avoid having to do wasteful things to print its newline
   1.704 +				        // (string copying would be wasteful and calling info.print() twice can be extremely slow)
   1.705 +				        // at the cost of functions that don't want the newline needing to trim off the last two characters
   1.706 +				        // (which is a very fast operation and thus acceptable in this case)
   1.707 +
   1.708 +				        return s_tempStr;
   1.709 +					}
   1.710 +#undef APPENDPRINT
   1.711 +#undef END
   1.712 +
   1.713 +// replacement for luaB_tostring() that is able to show the contents of tables (and formats numbers better, and show function
   1.714 +// prototypes)
   1.715 +// can be called directly from lua via tostring(), assuming tostring hasn't been reassigned
   1.716 +				    static int tostring(lua_State *L)
   1.717 +				    {
   1.718 +				        char *str = rawToCString(L);
   1.719 +				        str[strlen(str) - 2] = 0; // hack: trim off the \r\n (which is there to simplify the print function's
   1.720 +				                                  // task)
   1.721 +				        lua_pushstring(L, str);
   1.722 +				        return 1;
   1.723 +					}
   1.724 +
   1.725 +// like rawToCString, but will check if the global Lua function tostring()
   1.726 +// has been replaced with a custom function, and call that instead if so
   1.727 +				    static const char *toCString(lua_State *L, int idx)
   1.728 +				    {
   1.729 +				        int a = idx > 0 ? idx : 1;
   1.730 +				        int n = idx > 0 ? idx : lua_gettop(L);
   1.731 +				        lua_getglobal(L, "tostring");
   1.732 +				        lua_CFunction cf = lua_tocfunction(L, -1);
   1.733 +				        if (cf == tostring || lua_isnil(L, -1)) // optimization: if using our own C tostring function, we can
   1.734 +				                                                // bypass the call through Lua and all the string object
   1.735 +				                                                // allocation that would entail
   1.736 +				        {
   1.737 +				            lua_pop(L, 1);
   1.738 +				            return rawToCString(L, idx);
   1.739 +						}
   1.740 +				        else // if the user overrided the tostring function, we have to actually call it and store the
   1.741 +				             // temporarily allocated string it returns
   1.742 +				        {
   1.743 +				            lua_pushstring(L, "");
   1.744 +				            for (int i = a; i <= n; i++)
   1.745 +				            {
   1.746 +				                lua_pushvalue(L, -2); // function to be called
   1.747 +				                lua_pushvalue(L, i); // value to print
   1.748 +				                lua_call(L, 1, 1);
   1.749 +				                if (lua_tostring(L, -1) == NULL)
   1.750 +									luaL_error(L, LUA_QL("tostring") " must return a string to " LUA_QL("print"));
   1.751 +				                lua_pushstring(L, (i < n) ? " " : "\r\n");
   1.752 +				                lua_concat(L, 3);
   1.753 +							}
   1.754 +				            const char *str = lua_tostring(L, -1);
   1.755 +				            strncpy(s_tempStr, str, s_tempStrMaxLen);
   1.756 +				            s_tempStr[s_tempStrMaxLen - 1] = 0;
   1.757 +				            lua_pop(L, 2);
   1.758 +				            return s_tempStr;
   1.759 +						}
   1.760 +					}
   1.761 +
   1.762 +// replacement for luaB_print() that goes to the appropriate textbox instead of stdout
   1.763 +				    static int print(lua_State *L)
   1.764 +				    {
   1.765 +				        const char *str = toCString(L);
   1.766 +
   1.767 +				        int uid = info_uid; //luaStateToUIDMap[L->l_G->mainthread];
   1.768 +				        //LuaContextInfo& info = GetCurrentInfo();
   1.769 +
   1.770 +				        if (info_print)
   1.771 +							info_print(uid, str);
   1.772 +				        else
   1.773 +							puts(str);
   1.774 +
   1.775 +				        //worry(L, 100);
   1.776 +				        return 0;
   1.777 +					}
   1.778 +
   1.779 +				    static int printerror(lua_State *L, int idx)
   1.780 +				    {
   1.781 +				        lua_checkstack(L, lua_gettop(L) + 4);
   1.782 +
   1.783 +				        if (idx < 0)
   1.784 +							idx = lua_gettop(L) + 1 + idx;
   1.785 +
   1.786 +				        const char *str = rawToCString(L, idx);
   1.787 +
   1.788 +				        int uid = info_uid; //luaStateToUIDMap[L->l_G->mainthread];
   1.789 +				        //LuaContextInfo& info = GetCurrentInfo();
   1.790 +
   1.791 +				        if (info_print)
   1.792 +							info_print(uid, str);
   1.793 +				        else
   1.794 +							fputs(str, stderr);
   1.795 +
   1.796 +				        //worry(L, 100);
   1.797 +				        return 0;
   1.798 +					}
   1.799 +
   1.800 +// vba.message(string msg)
   1.801 +//
   1.802 +//  Displays the given message on the screen.
   1.803 +				    static int vba_message(lua_State *L)
   1.804 +				    {
   1.805 +				        const char *msg = luaL_checkstring(L, 1);
   1.806 +				        systemScreenMessage(msg);
   1.807 +
   1.808 +				        return 0;
   1.809 +					}
   1.810 +
   1.811 +// provides an easy way to copy a table from Lua
   1.812 +// (simple assignment only makes an alias, but sometimes an independent table is desired)
   1.813 +// currently this function only performs a shallow copy,
   1.814 +// but I think it should be changed to do a deep copy (possibly of configurable depth?)
   1.815 +// that maintains the internal table reference structure
   1.816 +				    static int copytable(lua_State *L)
   1.817 +				    {
   1.818 +				        int origIndex = 1; // we only care about the first argument
   1.819 +				        int origType = lua_type(L, origIndex);
   1.820 +				        if (origType == LUA_TNIL)
   1.821 +				        {
   1.822 +				            lua_pushnil(L);
   1.823 +				            return 1;
   1.824 +						}
   1.825 +				        if (origType != LUA_TTABLE)
   1.826 +				        {
   1.827 +				            luaL_typerror(L, 1, lua_typename(L, LUA_TTABLE));
   1.828 +				            lua_pushnil(L);
   1.829 +				            return 1;
   1.830 +						}
   1.831 +
   1.832 +				        lua_createtable(L, lua_objlen(L, 1), 0);
   1.833 +				        int copyIndex = lua_gettop(L);
   1.834 +
   1.835 +				        lua_pushnil(L); // first key
   1.836 +				        int keyIndex = lua_gettop(L);
   1.837 +				        int valueIndex = keyIndex + 1;
   1.838 +
   1.839 +				        while (lua_next(L, origIndex))
   1.840 +				        {
   1.841 +				            lua_pushvalue(L, keyIndex);
   1.842 +				            lua_pushvalue(L, valueIndex);
   1.843 +				            lua_rawset(L, copyIndex); // copytable[key] = value
   1.844 +				            lua_pop(L, 1);
   1.845 +						}
   1.846 +
   1.847 +				        // copy the reference to the metatable as well, if any
   1.848 +				        if (lua_getmetatable(L, origIndex))
   1.849 +							lua_setmetatable(L, copyIndex);
   1.850 +
   1.851 +				        return 1; // return the new table
   1.852 +					}
   1.853 +
   1.854 +// because print traditionally shows the address of tables,
   1.855 +// and the print function I provide instead shows the contents of tables,
   1.856 +// I also provide this function
   1.857 +// (otherwise there would be no way to see a table's address, AFAICT)
   1.858 +				    static int addressof(lua_State *L)
   1.859 +				    {
   1.860 +				        const void *ptr = lua_topointer(L, -1);
   1.861 +				        lua_pushinteger(L, (lua_Integer)ptr);
   1.862 +				        return 1;
   1.863 +					}
   1.864 +
   1.865 +				    struct registerPointerMap
   1.866 +				    {
   1.867 +				        const char *  registerName;
   1.868 +				        unsigned int *pointer;
   1.869 +				        int dataSize;
   1.870 +					};
   1.871 +
   1.872 +#define RPM_ENTRY(name, var) \
   1.873 +	{ name, (unsigned int *)&var, sizeof(var) \
   1.874 +	} \
   1.875 +	,
   1.876 +
   1.877 +				    extern gbRegister AF;
   1.878 +				    extern gbRegister BC;
   1.879 +				    extern gbRegister DE;
   1.880 +				    extern gbRegister HL;
   1.881 +				    extern gbRegister SP;
   1.882 +				    extern gbRegister PC;
   1.883 +				    extern u16 IFF;
   1.884 +
   1.885 +				    registerPointerMap regPointerMap [] = {
   1.886 +				        // gba registers
   1.887 +				        RPM_ENTRY("r0",	  reg[0].I)
   1.888 +				        RPM_ENTRY("r1",	  reg[1].I)
   1.889 +				        RPM_ENTRY("r2",	  reg[2].I)
   1.890 +				        RPM_ENTRY("r3",	  reg[3].I)
   1.891 +				        RPM_ENTRY("r4",	  reg[4].I)
   1.892 +				        RPM_ENTRY("r5",	  reg[5].I)
   1.893 +				        RPM_ENTRY("r6",	  reg[6].I)
   1.894 +				        RPM_ENTRY("r7",	  reg[7].I)
   1.895 +				        RPM_ENTRY("r8",	  reg[8].I)
   1.896 +				        RPM_ENTRY("r9",	  reg[9].I)
   1.897 +				        RPM_ENTRY("r10",  reg[10].I)
   1.898 +				        RPM_ENTRY("r11",  reg[11].I)
   1.899 +				        RPM_ENTRY("r12",  reg[12].I)
   1.900 +				        RPM_ENTRY("r13",  reg[13].I)
   1.901 +				        RPM_ENTRY("r14",  reg[14].I)
   1.902 +				        RPM_ENTRY("r15",  reg[15].I)
   1.903 +				        RPM_ENTRY("cpsr", reg[16].I)
   1.904 +				        RPM_ENTRY("spsr", reg[17].I)
   1.905 +				        // gb registers
   1.906 +				        RPM_ENTRY("a",	  AF.B.B1)
   1.907 +				        RPM_ENTRY("f",	  AF.B.B0)
   1.908 +				        RPM_ENTRY("b",	  BC.B.B1)
   1.909 +				        RPM_ENTRY("c",	  BC.B.B0)
   1.910 +				        RPM_ENTRY("d",	  DE.B.B1)
   1.911 +				        RPM_ENTRY("e",	  DE.B.B0)
   1.912 +				        RPM_ENTRY("h",	  HL.B.B1)
   1.913 +				        RPM_ENTRY("l",	  HL.B.B0)
   1.914 +				        RPM_ENTRY("af",	  AF.W)
   1.915 +				        RPM_ENTRY("bc",	  BC.W)
   1.916 +				        RPM_ENTRY("de",	  DE.W)
   1.917 +				        RPM_ENTRY("hl",	  HL.W)
   1.918 +				        RPM_ENTRY("sp",	  SP.W)
   1.919 +				        RPM_ENTRY("pc",	  PC.W)
   1.920 +				        {}
   1.921 +					};
   1.922 +
   1.923 +				    struct cpuToRegisterMap
   1.924 +				    {
   1.925 +				        const char *cpuName;
   1.926 +				        registerPointerMap *rpmap;
   1.927 +					}
   1.928 +				    cpuToRegisterMaps [] =
   1.929 +				    {
   1.930 +				        { "", regPointerMap },
   1.931 +					};
   1.932 +
   1.933 +//DEFINE_LUA_FUNCTION(memory_getregister, "cpu_dot_registername_string")
   1.934 +				    static int memory_getregister(lua_State *L)
   1.935 +				    {
   1.936 +				        const char *qualifiedRegisterName = luaL_checkstring(L, 1);
   1.937 +				        lua_settop(L, 0);
   1.938 +				        for (int cpu = 0; cpu < sizeof(cpuToRegisterMaps) / sizeof(*cpuToRegisterMaps); cpu++)
   1.939 +				        {
   1.940 +				            cpuToRegisterMap ctrm = cpuToRegisterMaps[cpu];
   1.941 +				            int cpuNameLen		  = strlen(ctrm.cpuName);
   1.942 +				            if (!strnicmp(qualifiedRegisterName, ctrm.cpuName, cpuNameLen))
   1.943 +				            {
   1.944 +				                qualifiedRegisterName += cpuNameLen;
   1.945 +				                for (int reg = 0; ctrm.rpmap[reg].dataSize; reg++)
   1.946 +				                {
   1.947 +				                    registerPointerMap rpm = ctrm.rpmap[reg];
   1.948 +				                    if (!stricmp(qualifiedRegisterName, rpm.registerName))
   1.949 +				                    {
   1.950 +				                        switch (rpm.dataSize)
   1.951 +				                        {
   1.952 +										default:
   1.953 +										case 1:
   1.954 +											lua_pushinteger(L, *(unsigned char *)rpm.pointer); break;
   1.955 +										case 2:
   1.956 +											lua_pushinteger(L, *(unsigned short *)rpm.pointer); break;
   1.957 +										case 4:
   1.958 +											lua_pushinteger(L, *(unsigned long *)rpm.pointer); break;
   1.959 +										}
   1.960 +				                        return 1;
   1.961 +									}
   1.962 +								}
   1.963 +				                lua_pushnil(L);
   1.964 +				                return 1;
   1.965 +							}
   1.966 +						}
   1.967 +				        lua_pushnil(L);
   1.968 +				        return 1;
   1.969 +					}
   1.970 +
   1.971 +//DEFINE_LUA_FUNCTION(memory_setregister, "cpu_dot_registername_string,value")
   1.972 +				    static int memory_setregister(lua_State *L)
   1.973 +				    {
   1.974 +				        const char *  qualifiedRegisterName = luaL_checkstring(L, 1);
   1.975 +				        unsigned long value = (unsigned long)(luaL_checkinteger(L, 2));
   1.976 +				        lua_settop(L, 0);
   1.977 +				        for (int cpu = 0; cpu < sizeof(cpuToRegisterMaps) / sizeof(*cpuToRegisterMaps); cpu++)
   1.978 +				        {
   1.979 +				            cpuToRegisterMap ctrm = cpuToRegisterMaps[cpu];
   1.980 +				            int cpuNameLen		  = strlen(ctrm.cpuName);
   1.981 +				            if (!strnicmp(qualifiedRegisterName, ctrm.cpuName, cpuNameLen))
   1.982 +				            {
   1.983 +				                qualifiedRegisterName += cpuNameLen;
   1.984 +				                for (int reg = 0; ctrm.rpmap[reg].dataSize; reg++)
   1.985 +				                {
   1.986 +				                    registerPointerMap rpm = ctrm.rpmap[reg];
   1.987 +				                    if (!stricmp(qualifiedRegisterName, rpm.registerName))
   1.988 +				                    {
   1.989 +				                        switch (rpm.dataSize)
   1.990 +				                        {
   1.991 +										default:
   1.992 +										case 1:
   1.993 +											*(unsigned char *)rpm.pointer = (unsigned char)(value & 0xFF); break;
   1.994 +										case 2:
   1.995 +											*(unsigned short *)rpm.pointer = (unsigned short)(value & 0xFFFF); break;
   1.996 +										case 4:
   1.997 +											*(unsigned long *)rpm.pointer = value; break;
   1.998 +										}
   1.999 +				                        return 0;
  1.1000 +									}
  1.1001 +								}
  1.1002 +				                return 0;
  1.1003 +							}
  1.1004 +						}
  1.1005 +				        return 0;
  1.1006 +					}
  1.1007 +
  1.1008 +				    void HandleCallbackError(lua_State *L)
  1.1009 +				    {
  1.1010 +				        if (L->errfunc || L->errorJmp)
  1.1011 +							luaL_error(L, "%s", lua_tostring(L, -1));
  1.1012 +				        else
  1.1013 +				        {
  1.1014 +				            lua_pushnil(LUA);
  1.1015 +				            lua_setfield(LUA, LUA_REGISTRYINDEX, guiCallbackTable);
  1.1016 +
  1.1017 +				            // Error?
  1.1018 +//#if (defined(WIN32) && !defined(SDL))
  1.1019 +//		info_print(info_uid, lua_tostring(LUA, -1)); //Clear_Sound_Buffer();
  1.1020 +// AfxGetApp()->m_pMainWnd->MessageBox(lua_tostring(LUA, -1), "Lua run error", MB_OK | MB_ICONSTOP);
  1.1021 +//#else
  1.1022 +//		fprintf(stderr, "Lua thread bombed out: %s\n", lua_tostring(LUA, -1));
  1.1023 +//#endif
  1.1024 +				            printerror(LUA, -1);
  1.1025 +				            VBALuaStop();
  1.1026 +						}
  1.1027 +					}
  1.1028 +
  1.1029 +				    void CallRegisteredLuaFunctions(LuaCallID calltype)
  1.1030 +				    {
  1.1031 +				        assert((unsigned int)calltype < (unsigned int)LUACALL_COUNT);
  1.1032 +
  1.1033 +				        const char *idstring = luaCallIDStrings[calltype];
  1.1034 +
  1.1035 +				        if (!LUA)
  1.1036 +							return;
  1.1037 +
  1.1038 +				        lua_settop(LUA, 0);
  1.1039 +				        lua_getfield(LUA, LUA_REGISTRYINDEX, idstring);
  1.1040 +
  1.1041 +				        int errorcode = 0;
  1.1042 +				        if (lua_isfunction(LUA, -1))
  1.1043 +				        {
  1.1044 +				            errorcode = lua_pcall(LUA, 0, 0, 0);
  1.1045 +				            if (errorcode)
  1.1046 +								HandleCallbackError(LUA);
  1.1047 +						}
  1.1048 +				        else
  1.1049 +				        {
  1.1050 +				            lua_pop(LUA, 1);
  1.1051 +						}
  1.1052 +					}
  1.1053 +
  1.1054 +// the purpose of this structure is to provide a way of
  1.1055 +// QUICKLY determining whether a memory address range has a hook associated with it,
  1.1056 +// with a bias toward fast rejection because the majority of addresses will not be hooked.
  1.1057 +// (it must not use any part of Lua or perform any per-script operations,
  1.1058 +//  otherwise it would definitely be too slow.)
  1.1059 +// calculating the regions when a hook is added/removed may be slow,
  1.1060 +// but this is an intentional tradeoff to obtain a high speed of checking during later execution
  1.1061 +				    struct TieredRegion
  1.1062 +				    {
  1.1063 +				        template<unsigned int maxGap>
  1.1064 +				        struct Region
  1.1065 +				        {
  1.1066 +				            struct Island
  1.1067 +				            {
  1.1068 +				                unsigned int	   start;
  1.1069 +				                unsigned int	   end;
  1.1070 +				                __forceinline bool Contains(unsigned int address, int size) const { return address < end && address + size > start; }
  1.1071 +							};
  1.1072 +				            std::vector<Island> islands;
  1.1073 +
  1.1074 +				            void Calculate(const std::vector<unsigned int> &bytes)
  1.1075 +				            {
  1.1076 +				                islands. clear();
  1.1077 +
  1.1078 +				                unsigned int lastEnd = ~0;
  1.1079 +
  1.1080 +				                std::vector<unsigned int>::const_iterator iter = bytes.begin();
  1.1081 +				                std::vector<unsigned int>::const_iterator end  = bytes.end();
  1.1082 +				                for (; iter != end; ++iter)
  1.1083 +				                {
  1.1084 +				                    unsigned int addr = *iter;
  1.1085 +				                    if (addr < lastEnd || addr > lastEnd + (long long)maxGap)
  1.1086 +				                    {
  1.1087 +				                        islands. push_back(Island());
  1.1088 +				                        islands. back().start = addr;
  1.1089 +									}
  1.1090 +				                    islands.back(). end = addr + 1;
  1.1091 +				                    lastEnd = addr + 1;
  1.1092 +								}
  1.1093 +							}
  1.1094 +
  1.1095 +				            bool Contains(unsigned int address, int size) const
  1.1096 +				            {
  1.1097 +				                for (size_t i = 0; i != islands.size(); ++i)
  1.1098 +				                {
  1.1099 +				                    if (islands[i].Contains(address, size))
  1.1100 +										return true;
  1.1101 +								}
  1.1102 +				                return false;
  1.1103 +							}
  1.1104 +						};
  1.1105 +
  1.1106 +				        Region<0xFFFFFFFF> broad;
  1.1107 +				        Region<0x1000>	   mid;
  1.1108 +				        Region<0>		   narrow;
  1.1109 +
  1.1110 +				        void Calculate(std::vector<unsigned int> &bytes)
  1.1111 +				        {
  1.1112 +				            std:: sort(bytes.begin(), bytes.end());
  1.1113 +
  1.1114 +				            broad.	Calculate(bytes);
  1.1115 +				            mid.	Calculate(bytes);
  1.1116 +				            narrow. Calculate(bytes);
  1.1117 +						}
  1.1118 +
  1.1119 +				        TieredRegion()
  1.1120 +				        {
  1.1121 +				            std::vector <unsigned int> temp;
  1.1122 +				            Calculate(temp);
  1.1123 +						}
  1.1124 +
  1.1125 +				        __forceinline int NotEmpty()
  1.1126 +				        {
  1.1127 +				            return broad.islands.size();
  1.1128 +						}
  1.1129 +
  1.1130 +				        // note: it is illegal to call this if NotEmpty() returns 0
  1.1131 +				        __forceinline bool Contains(unsigned int address, int size)
  1.1132 +				        {
  1.1133 +				            return broad.islands[0].Contains(address, size) &&
  1.1134 +				                   mid.Contains(address, size) &&
  1.1135 +				                   narrow.Contains(address, size);
  1.1136 +						}
  1.1137 +					};
  1.1138 +				    TieredRegion hookedRegions [LUAMEMHOOK_COUNT];
  1.1139 +
  1.1140 +				    static void CalculateMemHookRegions(LuaMemHookType hookType)
  1.1141 +				    {
  1.1142 +				        std::vector<unsigned int> hookedBytes;
  1.1143 +//	std::map<int, LuaContextInfo*>::iterator iter = luaContextInfo.begin();
  1.1144 +//	std::map<int, LuaContextInfo*>::iterator end = luaContextInfo.end();
  1.1145 +//	while(iter != end)
  1.1146 +//	{
  1.1147 +//		LuaContextInfo& info = *iter->second;
  1.1148 +				        if (/*info.*/ numMemHooks)
  1.1149 +				        {
  1.1150 +				            lua_State *L = LUA /*info.L*/;
  1.1151 +				            if (L)
  1.1152 +				            {
  1.1153 +				                lua_settop(L, 0);
  1.1154 +				                lua_getfield(L, LUA_REGISTRYINDEX, luaMemHookTypeStrings[hookType]);
  1.1155 +				                lua_pushnil(L);
  1.1156 +				                while (lua_next(L, -2))
  1.1157 +				                {
  1.1158 +				                    if (lua_isfunction(L, -1))
  1.1159 +				                    {
  1.1160 +				                        unsigned int addr = lua_tointeger(L, -2);
  1.1161 +				                        hookedBytes.push_back(addr);
  1.1162 +									}
  1.1163 +				                    lua_pop(L, 1);
  1.1164 +								}
  1.1165 +				                lua_settop(L, 0);
  1.1166 +							}
  1.1167 +						}
  1.1168 +//		++iter;
  1.1169 +//	}
  1.1170 +				        hookedRegions[hookType].Calculate(hookedBytes);
  1.1171 +					}
  1.1172 +
  1.1173 +				    static void CallRegisteredLuaMemHook_LuaMatch(unsigned int address, int size, unsigned int value, LuaMemHookType hookType)
  1.1174 +				    {
  1.1175 +//	std::map<int, LuaContextInfo*>::iterator iter = luaContextInfo.begin();
  1.1176 +//	std::map<int, LuaContextInfo*>::iterator end = luaContextInfo.end();
  1.1177 +//	while(iter != end)
  1.1178 +//	{
  1.1179 +//		LuaContextInfo& info = *iter->second;
  1.1180 +				        if (/*info.*/ numMemHooks)
  1.1181 +				        {
  1.1182 +				            lua_State *L = LUA /*info.L*/;
  1.1183 +				            if (L /* && !info.panic*/)
  1.1184 +				            {
  1.1185 +#ifdef USE_INFO_STACK
  1.1186 +				                infoStack.insert(infoStack.begin(), &info);
  1.1187 +				                struct Scope { ~Scope(){ infoStack. erase(infoStack.begin()); } } scope;
  1.1188 +#endif
  1.1189 +				                lua_settop(L, 0);
  1.1190 +				                lua_getfield(L, LUA_REGISTRYINDEX, luaMemHookTypeStrings[hookType]);
  1.1191 +				                for (int i = address; i != address + size; i++)
  1.1192 +				                {
  1.1193 +				                    lua_rawgeti(L, -1, i);
  1.1194 +				                    if (lua_isfunction(L, -1))
  1.1195 +				                    {
  1.1196 +				                        bool wasRunning = (luaRunning != 0) /*info.running*/;
  1.1197 +				                        luaRunning /*info.running*/ = true;
  1.1198 +				                        //RefreshScriptSpeedStatus();
  1.1199 +				                        lua_pushinteger(L, address);
  1.1200 +				                        lua_pushinteger(L, size);
  1.1201 +				                        int errorcode = lua_pcall(L, 2, 0, 0);
  1.1202 +				                        luaRunning /*info.running*/ = wasRunning;
  1.1203 +				                        //RefreshScriptSpeedStatus();
  1.1204 +				                        if (errorcode)
  1.1205 +				                        {
  1.1206 +				                            HandleCallbackError(L);
  1.1207 +				                            //int uid = iter->first;
  1.1208 +				                            //HandleCallbackError(L,info,uid,true);
  1.1209 +										}
  1.1210 +				                        break;
  1.1211 +									}
  1.1212 +				                    else
  1.1213 +				                    {
  1.1214 +				                        lua_pop(L, 1);
  1.1215 +									}
  1.1216 +								}
  1.1217 +				                lua_settop(L, 0);
  1.1218 +							}
  1.1219 +						}
  1.1220 +//		++iter;
  1.1221 +//	}
  1.1222 +					}
  1.1223 +
  1.1224 +				    void CallRegisteredLuaMemHook(unsigned int address, int size, unsigned int value, LuaMemHookType hookType)
  1.1225 +				    {
  1.1226 +				        // performance critical! (called VERY frequently)
  1.1227 +				        // I suggest timing a large number of calls to this function in Release if you change anything in here,
  1.1228 +				        // before and after, because even the most innocent change can make it become 30% to 400% slower.
  1.1229 +				        // a good amount to test is: 100000000 calls with no hook set, and another 100000000 with a hook set.
  1.1230 +				        // (on my system that consistently took 200 ms total in the former case and 350 ms total in the latter
  1.1231 +				        // case)
  1.1232 +				        if (hookedRegions[hookType].NotEmpty())
  1.1233 +				        {
  1.1234 +				            //if((hookType <= LUAMEMHOOK_EXEC) && (address >= 0xE00000))
  1.1235 +				            //	address |= 0xFF0000; // account for mirroring of RAM
  1.1236 +				            if (hookedRegions[hookType].Contains(address, size))
  1.1237 +								CallRegisteredLuaMemHook_LuaMatch(address, size, value, hookType);  // something has hooked this
  1.1238 +				                                                                                    // specific address
  1.1239 +						}
  1.1240 +					}
  1.1241 +
  1.1242 +				    static int memory_registerHook(lua_State *L, LuaMemHookType hookType, int defaultSize)
  1.1243 +				    {
  1.1244 +				        // get first argument: address
  1.1245 +				        unsigned int addr = luaL_checkinteger(L, 1);
  1.1246 +				        //if((addr & ~0xFFFFFF) == ~0xFFFFFF)
  1.1247 +				        //	addr &= 0xFFFFFF;
  1.1248 +
  1.1249 +				        // get optional second argument: size
  1.1250 +				        int size	= defaultSize;
  1.1251 +				        int funcIdx = 2;
  1.1252 +				        if (lua_isnumber(L, 2))
  1.1253 +				        {
  1.1254 +				            size = luaL_checkinteger(L, 2);
  1.1255 +				            if (size < 0)
  1.1256 +				            {
  1.1257 +				                size  = -size;
  1.1258 +				                addr -= size;
  1.1259 +							}
  1.1260 +				            funcIdx++;
  1.1261 +						}
  1.1262 +
  1.1263 +				        // check last argument: callback function
  1.1264 +				        bool clearing = lua_isnil(L, funcIdx);
  1.1265 +				        if (!clearing)
  1.1266 +							luaL_checktype(L, funcIdx, LUA_TFUNCTION);
  1.1267 +				        lua_settop(L, funcIdx);
  1.1268 +
  1.1269 +				        // get the address-to-callback table for this hook type of the current script
  1.1270 +				        lua_getfield(L, LUA_REGISTRYINDEX, luaMemHookTypeStrings[hookType]);
  1.1271 +
  1.1272 +				        // count how many callback functions we'll be displacing
  1.1273 +				        int numFuncsAfter  = clearing ? 0 : size;
  1.1274 +				        int numFuncsBefore = 0;
  1.1275 +				        for (unsigned int i = addr; i != addr + size; i++)
  1.1276 +				        {
  1.1277 +				            lua_rawgeti(L, -1, i);
  1.1278 +				            if (lua_isfunction(L, -1))
  1.1279 +								numFuncsBefore++;
  1.1280 +				            lua_pop(L, 1);
  1.1281 +						}
  1.1282 +
  1.1283 +				        // put the callback function in the address slots
  1.1284 +				        for (unsigned int i = addr; i != addr + size; i++)
  1.1285 +				        {
  1.1286 +				            lua_pushvalue(L, -2);
  1.1287 +				            lua_rawseti(L, -2, i);
  1.1288 +						}
  1.1289 +
  1.1290 +				        // adjust the count of active hooks
  1.1291 +				        //LuaContextInfo& info = GetCurrentInfo();
  1.1292 +				        /*info.*/ numMemHooks += numFuncsAfter - numFuncsBefore;
  1.1293 +
  1.1294 +				        // re-cache regions of hooked memory across all scripts
  1.1295 +				        CalculateMemHookRegions(hookType);
  1.1296 +
  1.1297 +				        //StopScriptIfFinished(luaStateToUIDMap[L]);
  1.1298 +				        return 0;
  1.1299 +					}
  1.1300 +
  1.1301 +				    LuaMemHookType MatchHookTypeToCPU(lua_State *L, LuaMemHookType hookType)
  1.1302 +				    {
  1.1303 +				        int cpuID = 0;
  1.1304 +
  1.1305 +				        int cpunameIndex = 0;
  1.1306 +				        if (lua_type(L, 2) == LUA_TSTRING)
  1.1307 +							cpunameIndex = 2;
  1.1308 +				        else if (lua_type(L, 3) == LUA_TSTRING)
  1.1309 +							cpunameIndex = 3;
  1.1310 +
  1.1311 +				        if (cpunameIndex)
  1.1312 +				        {
  1.1313 +				            const char *cpuName = lua_tostring(L, cpunameIndex);
  1.1314 +				            if (!stricmp(cpuName, "sub"))
  1.1315 +								cpuID = 1;
  1.1316 +				            lua_remove(L, cpunameIndex);
  1.1317 +						}
  1.1318 +
  1.1319 +				        switch (cpuID)
  1.1320 +				        {
  1.1321 +						case 0:
  1.1322 +							return hookType;
  1.1323 +
  1.1324 +						case 1:
  1.1325 +							switch (hookType)
  1.1326 +							{
  1.1327 +							case LUAMEMHOOK_WRITE:
  1.1328 +								return LUAMEMHOOK_WRITE_SUB;
  1.1329 +							case LUAMEMHOOK_READ:
  1.1330 +								return LUAMEMHOOK_READ_SUB;
  1.1331 +							case LUAMEMHOOK_EXEC:
  1.1332 +								return LUAMEMHOOK_EXEC_SUB;
  1.1333 +							}
  1.1334 +						}
  1.1335 +				        return hookType;
  1.1336 +					}
  1.1337 +
  1.1338 +				    static int memory_registerwrite(lua_State *L)
  1.1339 +				    {
  1.1340 +				        return memory_registerHook(L, MatchHookTypeToCPU(L, LUAMEMHOOK_WRITE), 1);
  1.1341 +					}
  1.1342 +
  1.1343 +				    static int memory_registerread(lua_State *L)
  1.1344 +				    {
  1.1345 +				        return memory_registerHook(L, MatchHookTypeToCPU(L, LUAMEMHOOK_READ), 1);
  1.1346 +					}
  1.1347 +
  1.1348 +				    static int memory_registerexec(lua_State *L)
  1.1349 +				    {
  1.1350 +				        return memory_registerHook(L, MatchHookTypeToCPU(L, LUAMEMHOOK_EXEC), 1);
  1.1351 +					}
  1.1352 +
  1.1353 +//int vba.lagcount
  1.1354 +//
  1.1355 +
  1.1356 +//Returns the lagcounter variable
  1.1357 +				    static int vba_getlagcount(lua_State *L)
  1.1358 +				    {
  1.1359 +				        lua_pushinteger(L, systemCounters.lagCount);
  1.1360 +				        return 1;
  1.1361 +					}
  1.1362 +
  1.1363 +//int vba.lagged
  1.1364 +//
  1.1365 +//Returns true if the current frame is a lag frame
  1.1366 +				    static int vba_lagged(lua_State *L)
  1.1367 +				    {
  1.1368 +				        lua_pushboolean(L, systemCounters.laggedLast);
  1.1369 +				        return 1;
  1.1370 +					}
  1.1371 +
  1.1372 +// boolean vba.emulating()
  1.1373 +				    int vba_emulating(lua_State *L)
  1.1374 +				    {
  1.1375 +				        lua_pushboolean(L, systemIsEmulating());
  1.1376 +				        return 1;
  1.1377 +					}
  1.1378 +
  1.1379 +				    int movie_isactive(lua_State *L)
  1.1380 +				    {
  1.1381 +				        lua_pushboolean(L, VBAMovieActive());
  1.1382 +				        return 1;
  1.1383 +					}
  1.1384 +
  1.1385 +				    int movie_isrecording(lua_State *L)
  1.1386 +				    {
  1.1387 +				        lua_pushboolean(L, VBAMovieRecording());
  1.1388 +				        return 1;
  1.1389 +					}
  1.1390 +
  1.1391 +				    int movie_isplaying(lua_State *L)
  1.1392 +				    {
  1.1393 +				        lua_pushboolean(L, VBAMoviePlaying());
  1.1394 +				        return 1;
  1.1395 +					}
  1.1396 +
  1.1397 +				    int movie_getlength(lua_State *L)
  1.1398 +				    {
  1.1399 +				        if (VBAMovieActive())
  1.1400 +							lua_pushinteger(L, VBAMovieGetLength());
  1.1401 +				        else
  1.1402 +							lua_pushinteger(L, 0);
  1.1403 +				        return 1;
  1.1404 +					}
  1.1405 +
  1.1406 +				    static int memory_readbyte(lua_State *L)
  1.1407 +				    {
  1.1408 +				        u32 addr;
  1.1409 +				        u8	val;
  1.1410 +
  1.1411 +				        addr = luaL_checkinteger(L, 1);
  1.1412 +				        if (systemIsRunningGBA())
  1.1413 +				        {
  1.1414 +				            val = CPUReadByteQuick(addr);
  1.1415 +						}
  1.1416 +				        else
  1.1417 +				        {
  1.1418 +				            val = gbReadMemoryQuick8(addr);
  1.1419 +						}
  1.1420 +
  1.1421 +				        lua_pushinteger(L, val);
  1.1422 +				        return 1;
  1.1423 +					}
  1.1424 +
  1.1425 +				    static int memory_readbytesigned(lua_State *L)
  1.1426 +				    {
  1.1427 +				        u32 addr;
  1.1428 +				        s8	val;
  1.1429 +
  1.1430 +				        addr = luaL_checkinteger(L, 1);
  1.1431 +				        if (systemIsRunningGBA())
  1.1432 +				        {
  1.1433 +				            val = (s8) CPUReadByteQuick(addr);
  1.1434 +						}
  1.1435 +				        else
  1.1436 +				        {
  1.1437 +				            val = (s8) gbReadMemoryQuick8(addr);
  1.1438 +						}
  1.1439 +
  1.1440 +				        lua_pushinteger(L, val);
  1.1441 +				        return 1;
  1.1442 +					}
  1.1443 +
  1.1444 +				    static int memory_readword(lua_State *L)
  1.1445 +				    {
  1.1446 +				        u32 addr;
  1.1447 +				        u16 val;
  1.1448 +
  1.1449 +				        addr = luaL_checkinteger(L, 1);
  1.1450 +				        if (systemIsRunningGBA())
  1.1451 +				        {
  1.1452 +				            val = CPUReadHalfWordQuick(addr);
  1.1453 +						}
  1.1454 +				        else
  1.1455 +				        {
  1.1456 +				            val = gbReadMemoryQuick16(addr & 0x0000FFFF);
  1.1457 +						}
  1.1458 +
  1.1459 +				        lua_pushinteger(L, val);
  1.1460 +				        return 1;
  1.1461 +					}
  1.1462 +
  1.1463 +				    static int memory_readwordsigned(lua_State *L)
  1.1464 +				    {
  1.1465 +				        u32 addr;
  1.1466 +				        s16 val;
  1.1467 +
  1.1468 +				        addr = luaL_checkinteger(L, 1);
  1.1469 +				        if (systemIsRunningGBA())
  1.1470 +				        {
  1.1471 +				            val = (s16) CPUReadHalfWordQuick(addr);
  1.1472 +						}
  1.1473 +				        else
  1.1474 +				        {
  1.1475 +				            val = (s16) gbReadMemoryQuick16(addr);
  1.1476 +						}
  1.1477 +
  1.1478 +				        lua_pushinteger(L, val);
  1.1479 +				        return 1;
  1.1480 +					}
  1.1481 +
  1.1482 +				    static int memory_readdword(lua_State *L)
  1.1483 +				    {
  1.1484 +				        u32 addr;
  1.1485 +				        u32 val;
  1.1486 +
  1.1487 +				        addr = luaL_checkinteger(L, 1);
  1.1488 +				        if (systemIsRunningGBA())
  1.1489 +				        {
  1.1490 +				            val = CPUReadMemoryQuick(addr);
  1.1491 +						}
  1.1492 +				        else
  1.1493 +				        {
  1.1494 +				            val = gbReadMemoryQuick32(addr & 0x0000FFFF);
  1.1495 +						}
  1.1496 +
  1.1497 +				        // lua_pushinteger doesn't work properly for 32bit system, does it?
  1.1498 +				        if (val >= 0x80000000 && sizeof(int) <= 4)
  1.1499 +							lua_pushnumber(L, val);
  1.1500 +				        else
  1.1501 +							lua_pushinteger(L, val);
  1.1502 +				        return 1;
  1.1503 +					}
  1.1504 +
  1.1505 +				    static int memory_readdwordsigned(lua_State *L)
  1.1506 +				    {
  1.1507 +				        u32 addr;
  1.1508 +				        s32 val;
  1.1509 +
  1.1510 +				        addr = luaL_checkinteger(L, 1);
  1.1511 +				        if (systemIsRunningGBA())
  1.1512 +				        {
  1.1513 +				            val = (s32) CPUReadMemoryQuick(addr);
  1.1514 +						}
  1.1515 +				        else
  1.1516 +				        {
  1.1517 +				            val = (s32) gbReadMemoryQuick32(addr);
  1.1518 +						}
  1.1519 +
  1.1520 +				        lua_pushinteger(L, val);
  1.1521 +				        return 1;
  1.1522 +					}
  1.1523 +
  1.1524 +				    static int memory_readbyterange(lua_State *L)
  1.1525 +				    {
  1.1526 +				        uint32 address = luaL_checkinteger(L, 1);
  1.1527 +				        int	   length  = luaL_checkinteger(L, 2);
  1.1528 +
  1.1529 +				        if (length < 0)
  1.1530 +				        {
  1.1531 +				            address += length;
  1.1532 +				            length	 = -length;
  1.1533 +						}
  1.1534 +
  1.1535 +				        // push the array
  1.1536 +				        lua_createtable(L, abs(length), 0);
  1.1537 +
  1.1538 +				        // put all the values into the (1-based) array
  1.1539 +				        for (int a = address, n = 1; n <= length; a++, n++)
  1.1540 +				        {
  1.1541 +				            unsigned char value;
  1.1542 +
  1.1543 +				            if (systemIsRunningGBA())
  1.1544 +				            {
  1.1545 +				                value = CPUReadByteQuick(a);
  1.1546 +							}
  1.1547 +				            else
  1.1548 +				            {
  1.1549 +				                value = gbReadMemoryQuick8(a);
  1.1550 +							}
  1.1551 +
  1.1552 +				            lua_pushinteger(L, value);
  1.1553 +				            lua_rawseti(L, -2, n);
  1.1554 +						}
  1.1555 +
  1.1556 +				        return 1;
  1.1557 +					}
  1.1558 +
  1.1559 +				    static int memory_writebyte(lua_State *L)
  1.1560 +				    {
  1.1561 +				        u32 addr;
  1.1562 +				        int val;
  1.1563 +
  1.1564 +				        addr = luaL_checkinteger(L, 1);
  1.1565 +				        val	 = luaL_checkinteger(L, 2);
  1.1566 +				        if (systemIsRunningGBA())
  1.1567 +				        {
  1.1568 +				            CPUWriteByteQuick(addr, val);
  1.1569 +						}
  1.1570 +				        else
  1.1571 +				        {
  1.1572 +				            gbWriteMemoryQuick8(addr, val);
  1.1573 +						}
  1.1574 +
  1.1575 +				        CallRegisteredLuaMemHook(addr, 1, val, LUAMEMHOOK_WRITE);
  1.1576 +				        return 0;
  1.1577 +					}
  1.1578 +
  1.1579 +				    static int memory_writeword(lua_State *L)
  1.1580 +				    {
  1.1581 +				        u32 addr;
  1.1582 +				        int val;
  1.1583 +
  1.1584 +				        addr = luaL_checkinteger(L, 1);
  1.1585 +				        val	 = luaL_checkinteger(L, 2);
  1.1586 +				        if (systemIsRunningGBA())
  1.1587 +				        {
  1.1588 +				            CPUWriteHalfWordQuick(addr, val);
  1.1589 +						}
  1.1590 +				        else
  1.1591 +				        {
  1.1592 +				            gbWriteMemoryQuick16(addr, val);
  1.1593 +						}
  1.1594 +
  1.1595 +				        CallRegisteredLuaMemHook(addr, 2, val, LUAMEMHOOK_WRITE);
  1.1596 +				        return 0;
  1.1597 +					}
  1.1598 +
  1.1599 +				    static int memory_writedword(lua_State *L)
  1.1600 +				    {
  1.1601 +				        u32 addr;
  1.1602 +				        int val;
  1.1603 +
  1.1604 +				        addr = luaL_checkinteger(L, 1);
  1.1605 +				        val	 = luaL_checkinteger(L, 2);
  1.1606 +				        if (systemIsRunningGBA())
  1.1607 +				        {
  1.1608 +				            CPUWriteMemoryQuick(addr, val);
  1.1609 +						}
  1.1610 +				        else
  1.1611 +				        {
  1.1612 +				            gbWriteMemoryQuick32(addr, val);
  1.1613 +						}
  1.1614 +
  1.1615 +				        CallRegisteredLuaMemHook(addr, 4, val, LUAMEMHOOK_WRITE);
  1.1616 +				        return 0;
  1.1617 +					}
  1.1618 +
  1.1619 +				    static int memory_gbromreadbyte(lua_State *L)
  1.1620 +				    {
  1.1621 +				        u32 addr;
  1.1622 +				        u8	val;
  1.1623 +
  1.1624 +				        addr = luaL_checkinteger(L, 1);
  1.1625 +				        if (systemIsRunningGBA())
  1.1626 +				        {
  1.1627 +							lua_pushnil(L);
  1.1628 +							return 1;
  1.1629 +						}
  1.1630 +				        else
  1.1631 +				        {
  1.1632 +				            val = gbReadROMQuick8(addr);
  1.1633 +						}
  1.1634 +
  1.1635 +				        lua_pushinteger(L, val);
  1.1636 +				        return 1;
  1.1637 +					}
  1.1638 +
  1.1639 +				    static int memory_gbromreadbytesigned(lua_State *L)
  1.1640 +				    {
  1.1641 +				        u32 addr;
  1.1642 +				        s8	val;
  1.1643 +
  1.1644 +				        addr = luaL_checkinteger(L, 1);
  1.1645 +				        if (systemIsRunningGBA())
  1.1646 +				        {
  1.1647 +				            lua_pushnil(L);
  1.1648 +							return 1;
  1.1649 +						}
  1.1650 +				        else
  1.1651 +				        {
  1.1652 +				            val = (s8) gbReadROMQuick8(addr);
  1.1653 +						}
  1.1654 +
  1.1655 +				        lua_pushinteger(L, val);
  1.1656 +				        return 1;
  1.1657 +					}
  1.1658 +
  1.1659 +				    static int memory_gbromreadword(lua_State *L)
  1.1660 +				    {
  1.1661 +				        u32 addr;
  1.1662 +				        u16 val;
  1.1663 +
  1.1664 +				        addr = luaL_checkinteger(L, 1);
  1.1665 +				        if (systemIsRunningGBA())
  1.1666 +				        {
  1.1667 +				            lua_pushnil(L);
  1.1668 +							return 1;
  1.1669 +						}
  1.1670 +				        else
  1.1671 +				        {
  1.1672 +				            val = gbReadROMQuick16(addr);
  1.1673 +						}
  1.1674 +
  1.1675 +				        lua_pushinteger(L, val);
  1.1676 +				        return 1;
  1.1677 +					}
  1.1678 +
  1.1679 +				    static int memory_gbromreadwordsigned(lua_State *L)
  1.1680 +				    {
  1.1681 +				        u32 addr;
  1.1682 +				        s16 val;
  1.1683 +
  1.1684 +				        addr = luaL_checkinteger(L, 1);
  1.1685 +				        if (systemIsRunningGBA())
  1.1686 +				        {
  1.1687 +				            lua_pushnil(L);
  1.1688 +							return 1;
  1.1689 +						}
  1.1690 +				        else
  1.1691 +				        {
  1.1692 +				            val = (s16) gbReadROMQuick16(addr);
  1.1693 +						}
  1.1694 +
  1.1695 +				        lua_pushinteger(L, val);
  1.1696 +				        return 1;
  1.1697 +					}
  1.1698 +
  1.1699 +				    static int memory_gbromreaddword(lua_State *L)
  1.1700 +				    {
  1.1701 +				        u32 addr;
  1.1702 +				        u32 val;
  1.1703 +
  1.1704 +				        addr = luaL_checkinteger(L, 1);
  1.1705 +				        if (systemIsRunningGBA())
  1.1706 +				        {
  1.1707 +				            lua_pushnil(L);
  1.1708 +							return 1;
  1.1709 +						}
  1.1710 +				        else
  1.1711 +				        {
  1.1712 +				            val = gbReadROMQuick32(addr);
  1.1713 +						}
  1.1714 +
  1.1715 +				        // lua_pushinteger doesn't work properly for 32bit system, does it?
  1.1716 +				        if (val >= 0x80000000 && sizeof(int) <= 4)
  1.1717 +							lua_pushnumber(L, val);
  1.1718 +				        else
  1.1719 +							lua_pushinteger(L, val);
  1.1720 +				        return 1;
  1.1721 +					}
  1.1722 +
  1.1723 +				    static int memory_gbromreaddwordsigned(lua_State *L)
  1.1724 +				    {
  1.1725 +				        u32 addr;
  1.1726 +				        s32 val;
  1.1727 +
  1.1728 +				        addr = luaL_checkinteger(L, 1);
  1.1729 +				        if (systemIsRunningGBA())
  1.1730 +				        {
  1.1731 +				            lua_pushnil(L);
  1.1732 +							return 1;
  1.1733 +						}
  1.1734 +				        else
  1.1735 +				        {
  1.1736 +				            val = (s32) gbReadROMQuick32(addr);
  1.1737 +						}
  1.1738 +
  1.1739 +				        lua_pushinteger(L, val);
  1.1740 +				        return 1;
  1.1741 +					}
  1.1742 +
  1.1743 +				    static int memory_gbromreadbyterange(lua_State *L)
  1.1744 +				    {
  1.1745 +				        uint32 address = luaL_checkinteger(L, 1);
  1.1746 +				        int	   length  = luaL_checkinteger(L, 2);
  1.1747 +
  1.1748 +				        if (length < 0)
  1.1749 +				        {
  1.1750 +				            address += length;
  1.1751 +				            length	 = -length;
  1.1752 +						}
  1.1753 +
  1.1754 +				        // push the array
  1.1755 +				        lua_createtable(L, abs(length), 0);
  1.1756 +
  1.1757 +				        // put all the values into the (1-based) array
  1.1758 +				        for (int a = address, n = 1; n <= length; a++, n++)
  1.1759 +				        {
  1.1760 +				            unsigned char value;
  1.1761 +
  1.1762 +				            if (systemIsRunningGBA())
  1.1763 +				            {
  1.1764 +				                lua_pushnil(L);
  1.1765 +								return 1;
  1.1766 +							}
  1.1767 +				            else
  1.1768 +				            {
  1.1769 +				                value = gbReadROMQuick8(a);
  1.1770 +							}
  1.1771 +
  1.1772 +				            lua_pushinteger(L, value);
  1.1773 +				            lua_rawseti(L, -2, n);
  1.1774 +						}
  1.1775 +
  1.1776 +				        return 1;
  1.1777 +					}
  1.1778 +
  1.1779 +// table joypad.get(int which = 1)
  1.1780 +//
  1.1781 +//  Reads the joypads as inputted by the user.
  1.1782 +				    static int joy_get_internal(lua_State *L, bool reportUp, bool reportDown)
  1.1783 +				    {
  1.1784 +				        // Reads the joypads as inputted by the user
  1.1785 +				        int which = luaL_checkinteger(L, 1);
  1.1786 +
  1.1787 +				        if (which < 0 || which > 4)
  1.1788 +				        {
  1.1789 +				            luaL_error(L, "Invalid input port (valid range 0-4, specified %d)", which);
  1.1790 +						}
  1.1791 +
  1.1792 +				        uint32 buttons = systemGetOriginalJoypad(which - 1, false);
  1.1793 +
  1.1794 +				        lua_newtable(L);
  1.1795 +
  1.1796 +				        int i;
  1.1797 +				        for (i = 0; i < 10; i++)
  1.1798 +				        {
  1.1799 +				            bool pressed = (buttons & (1 << i)) != 0;
  1.1800 +				            if ((pressed && reportDown) || (!pressed && reportUp))
  1.1801 +				            {
  1.1802 +				                lua_pushboolean(L, pressed);
  1.1803 +				                lua_setfield(L, -2, button_mappings[i]);
  1.1804 +							}
  1.1805 +						}
  1.1806 +
  1.1807 +				        return 1;
  1.1808 +					}
  1.1809 +
  1.1810 +// joypad.get(which)
  1.1811 +// returns a table of every game button,
  1.1812 +// true meaning currently-held and false meaning not-currently-held
  1.1813 +// (as of last frame boundary)
  1.1814 +// this WILL read input from a currently-playing movie
  1.1815 +				    static int joypad_get(lua_State *L)
  1.1816 +				    {
  1.1817 +				        return joy_get_internal(L, true, true);
  1.1818 +					}
  1.1819 +
  1.1820 +// joypad.getdown(which)
  1.1821 +// returns a table of every game button that is currently held
  1.1822 +				    static int joypad_getdown(lua_State *L)
  1.1823 +				    {
  1.1824 +				        return joy_get_internal(L, false, true);
  1.1825 +					}
  1.1826 +
  1.1827 +// joypad.getup(which)
  1.1828 +// returns a table of every game button that is not currently held
  1.1829 +				    static int joypad_getup(lua_State *L)
  1.1830 +				    {
  1.1831 +				        return joy_get_internal(L, true, false);
  1.1832 +					}
  1.1833 +
  1.1834 +// joypad.set(int which, table buttons)
  1.1835 +//
  1.1836 +//   Sets the given buttons to be pressed during the next
  1.1837 +//   frame advance. The table should have the right
  1.1838 +
  1.1839 +//   keys (no pun intended) set.
  1.1840 +				    static int joypad_set(lua_State *L)
  1.1841 +				    {
  1.1842 +				        // Which joypad we're tampering with
  1.1843 +				        int which = luaL_checkinteger(L, 1);
  1.1844 +				        if (which < 0 || which > 4)
  1.1845 +				        {
  1.1846 +				            luaL_error(L, "Invalid output port (valid range 0-4, specified %d)", which);
  1.1847 +						}
  1.1848 +
  1.1849 +				        if (which == 0)
  1.1850 +							which = systemGetDefaultJoypad();
  1.1851 +
  1.1852 +				        // And the table of buttons.
  1.1853 +				        luaL_checktype(L, 2, LUA_TTABLE);
  1.1854 +
  1.1855 +				        // Set up for taking control of the indicated controller
  1.1856 +				        lua_joypads_used	  |= 1 << (which - 1);
  1.1857 +				        lua_joypads[which - 1] = 0;
  1.1858 +
  1.1859 +				        for (int i = 0; i < 10; i++)
  1.1860 +				        {
  1.1861 +				            const char *name = button_mappings[i];
  1.1862 +				            lua_getfield(L, 2, name);
  1.1863 +				            if (!lua_isnil(L, -1))
  1.1864 +				            {
  1.1865 +				                bool pressed = lua_toboolean(L, -1) != 0;
  1.1866 +				                if (pressed)
  1.1867 +									lua_joypads[which - 1] |= 1 << i;
  1.1868 +				                else
  1.1869 +									lua_joypads[which - 1] &= ~(1 << i);
  1.1870 +							}
  1.1871 +				            lua_pop(L, 1);
  1.1872 +						}
  1.1873 +
  1.1874 +				        return 0;
  1.1875 +					}
  1.1876 +
  1.1877 +// Helper function to convert a savestate object to the filename it represents.
  1.1878 +				    static const char *savestateobj2filename(lua_State *L, int offset)
  1.1879 +				    {
  1.1880 +				        // First we get the metatable of the indicated object
  1.1881 +				        int result = lua_getmetatable(L, offset);
  1.1882 +
  1.1883 +				        if (!result)
  1.1884 +							luaL_error(L, "object not a savestate object");
  1.1885 +
  1.1886 +				        // Also check that the type entry is set
  1.1887 +				        lua_getfield(L, -1, "__metatable");
  1.1888 +				        if (strcmp(lua_tostring(L, -1), "vba Savestate") != 0)
  1.1889 +							luaL_error(L, "object not a savestate object");
  1.1890 +				        lua_pop(L, 1);
  1.1891 +
  1.1892 +				        // Now, get the field we want
  1.1893 +				        lua_getfield(L, -1, "filename");
  1.1894 +
  1.1895 +				        // Return it
  1.1896 +				        return lua_tostring(L, -1);
  1.1897 +					}
  1.1898 +
  1.1899 +// Helper function for garbage collection.
  1.1900 +				    static int savestate_gc(lua_State *L)
  1.1901 +				    {
  1.1902 +				        // The object we're collecting is on top of the stack
  1.1903 +				        lua_getmetatable(L, 1);
  1.1904 +
  1.1905 +				        // Get the filename
  1.1906 +				        const char *filename;
  1.1907 +				        lua_getfield(L, -1, "filename");
  1.1908 +				        filename = lua_tostring(L, -1);
  1.1909 +
  1.1910 +				        // Delete the file
  1.1911 +				        remove(filename);
  1.1912 +
  1.1913 +				        // We exit, and the garbage collector takes care of the rest.
  1.1914 +				        // Edit: Visual Studio needs a return value anyway, so returns 0.
  1.1915 +				        return 0;
  1.1916 +					}
  1.1917 +
  1.1918 +// object savestate.create(int which = nil)
  1.1919 +//
  1.1920 +//  Creates an object used for savestates.
  1.1921 +//  The object can be associated with a player-accessible savestate
  1.1922 +
  1.1923 +//  ("which" between 1 and 12) or not (which == nil).
  1.1924 +				    static int savestate_create(lua_State *L)
  1.1925 +				    {
  1.1926 +				        int which = -1;
  1.1927 +				        if (lua_gettop(L) >= 1)
  1.1928 +				        {
  1.1929 +				            which = luaL_checkinteger(L, 1);
  1.1930 +				            if (which < 1 || which > 12)
  1.1931 +				            {
  1.1932 +				                luaL_error(L, "invalid player's savestate %d", which);
  1.1933 +							}
  1.1934 +						}
  1.1935 +
  1.1936 +				        char stateName[2048];
  1.1937 +
  1.1938 +				        if (which > 0)
  1.1939 +				        {
  1.1940 +				            // Find an appropriate filename. This is OS specific, unfortunately.
  1.1941 +#if (defined(WIN32) && !defined(SDL))
  1.1942 +				            CString stateName = winGetSavestateFilename(theApp.gameFilename, which);
  1.1943 +#else
  1.1944 +				            extern char saveDir[2048];
  1.1945 +				            extern char filename[2048];
  1.1946 +				            extern char *sdlGetFilename(char *name);
  1.1947 +
  1.1948 +				            if (saveDir[0])
  1.1949 +								sprintf(stateName, "%s/%s%d.sgm", saveDir, sdlGetFilename(filename), which);
  1.1950 +				            else
  1.1951 +								sprintf(stateName, "%s%d.sgm", filename, which);
  1.1952 +#endif
  1.1953 +						}
  1.1954 +				        else
  1.1955 +				        {
  1.1956 +				            char *stateNameTemp = tempnam(NULL, "snlua");
  1.1957 +				            strcpy(stateName, stateNameTemp);
  1.1958 +				            if (stateNameTemp)
  1.1959 +								free(stateNameTemp);
  1.1960 +						}
  1.1961 +
  1.1962 +				        // Our "object". We don't care about the type, we just need the memory and GC services.
  1.1963 +				        lua_newuserdata(L, 1);
  1.1964 +
  1.1965 +				        // The metatable we use, protected from Lua and contains garbage collection info and stuff.
  1.1966 +				        lua_newtable(L);
  1.1967 +
  1.1968 +				        // First, we must protect it
  1.1969 +				        lua_pushstring(L, "vba Savestate");
  1.1970 +				        lua_setfield(L, -2, "__metatable");
  1.1971 +
  1.1972 +				        // Now we need to save the file itself.
  1.1973 +				        lua_pushstring(L, stateName);
  1.1974 +				        lua_setfield(L, -2, "filename");
  1.1975 +
  1.1976 +				        // If it's an anonymous savestate, we must delete the file from disk should it be gargage collected
  1.1977 +				        if (which < 0)
  1.1978 +				        {
  1.1979 +				            lua_pushcfunction(L, savestate_gc);
  1.1980 +				            lua_setfield(L, -2, "__gc");
  1.1981 +						}
  1.1982 +
  1.1983 +				        // Set the metatable
  1.1984 +				        lua_setmetatable(L, -2);
  1.1985 +
  1.1986 +				        // Awesome. Return the object
  1.1987 +				        return 1;
  1.1988 +					}
  1.1989 +
  1.1990 +// savestate.save(object state)
  1.1991 +//
  1.1992 +
  1.1993 +//   Saves a state to the given object.
  1.1994 +				    static int savestate_save(lua_State *L)
  1.1995 +				    {
  1.1996 +				        const char *filename = savestateobj2filename(L, 1);
  1.1997 +
  1.1998 +				        //	printf("saving %s\n", filename);
  1.1999 +				        // Save states are very expensive. They take time.
  1.2000 +				        numTries--;
  1.2001 +
  1.2002 +				        bool8 retvalue = theEmulator.emuWriteState ? theEmulator.emuWriteState(filename) : false;
  1.2003 +				        if (!retvalue)
  1.2004 +				        {
  1.2005 +				            // Uh oh
  1.2006 +				            luaL_error(L, "savestate failed");
  1.2007 +						}
  1.2008 +
  1.2009 +				        return 0;
  1.2010 +					}
  1.2011 +
  1.2012 +// savestate.load(object state)
  1.2013 +//
  1.2014 +
  1.2015 +//   Loads the given state
  1.2016 +				    static int savestate_load(lua_State *L)
  1.2017 +				    {
  1.2018 +				        const char *filename = savestateobj2filename(L, 1);
  1.2019 +
  1.2020 +				        numTries--;
  1.2021 +
  1.2022 +				        //	printf("loading %s\n", filename);
  1.2023 +				        bool8 retvalue = theEmulator.emuReadState ? theEmulator.emuReadState(filename) : false;
  1.2024 +				        if (!retvalue)
  1.2025 +				        {
  1.2026 +				            // Uh oh
  1.2027 +				            luaL_error(L, "loadstate failed");
  1.2028 +						}
  1.2029 +
  1.2030 +				        return 0;
  1.2031 +					}
  1.2032 +
  1.2033 +// int vba.framecount()
  1.2034 +//
  1.2035 +
  1.2036 +//   Gets the frame counter for the movie, or the number of frames since last reset.
  1.2037 +				    int vba_framecount(lua_State *L)
  1.2038 +				    {
  1.2039 +				        if (!VBAMovieActive())
  1.2040 +				        {
  1.2041 +				            lua_pushinteger(L, systemCounters.frameCount);
  1.2042 +						}
  1.2043 +				        else
  1.2044 +				        {
  1.2045 +				            lua_pushinteger(L, VBAMovieGetFrameCounter());
  1.2046 +						}
  1.2047 +
  1.2048 +				        return 1;
  1.2049 +					}
  1.2050 +
  1.2051 +//string movie.getauthor
  1.2052 +//
  1.2053 +
  1.2054 +// returns author info field of .vbm file
  1.2055 +				    int movie_getauthor(lua_State *L)
  1.2056 +				    {
  1.2057 +				        if (!VBAMovieActive())
  1.2058 +				        {
  1.2059 +				            //lua_pushnil(L);
  1.2060 +				            lua_pushstring(L, "");
  1.2061 +				            return 1;
  1.2062 +						}
  1.2063 +
  1.2064 +				        lua_pushstring(L, VBAMovieGetAuthorInfo().c_str());
  1.2065 +				        return 1;
  1.2066 +					}
  1.2067 +
  1.2068 +//string movie.filename
  1.2069 +				    int movie_getfilename(lua_State *L)
  1.2070 +				    {
  1.2071 +				        if (!VBAMovieActive())
  1.2072 +				        {
  1.2073 +				            //lua_pushnil(L);
  1.2074 +				            lua_pushstring(L, "");
  1.2075 +				            return 1;
  1.2076 +						}
  1.2077 +
  1.2078 +				        lua_pushstring(L, VBAMovieGetFilename().c_str());
  1.2079 +				        return 1;
  1.2080 +					}
  1.2081 +
  1.2082 +// string movie.mode()
  1.2083 +//
  1.2084 +
  1.2085 +//   "record", "playback" or nil
  1.2086 +				    int movie_getmode(lua_State *L)
  1.2087 +				    {
  1.2088 +				        assert(!VBAMovieLoading());
  1.2089 +				        if (!VBAMovieActive())
  1.2090 +				        {
  1.2091 +				            lua_pushnil(L);
  1.2092 +				            return 1;
  1.2093 +						}
  1.2094 +
  1.2095 +				        if (VBAMovieRecording())
  1.2096 +							lua_pushstring(L, "record");
  1.2097 +				        else
  1.2098 +							lua_pushstring(L, "playback");
  1.2099 +				        return 1;
  1.2100 +					}
  1.2101 +
  1.2102 +				    static int movie_rerecordcount(lua_State *L)
  1.2103 +				    {
  1.2104 +				        if (VBAMovieActive())
  1.2105 +							lua_pushinteger(L, VBAMovieGetRerecordCount());
  1.2106 +				        else
  1.2107 +							lua_pushinteger(L, 0);
  1.2108 +				        return 1;
  1.2109 +					}
  1.2110 +
  1.2111 +				    static int movie_setrerecordcount(lua_State *L)
  1.2112 +				    {
  1.2113 +				        if (VBAMovieActive())
  1.2114 +							VBAMovieSetRerecordCount(luaL_checkinteger(L, 1));
  1.2115 +				        return 0;
  1.2116 +					}
  1.2117 +
  1.2118 +				    static int movie_rerecordcounting(lua_State *L)
  1.2119 +				    {
  1.2120 +				        if (lua_gettop(L) == 0)
  1.2121 +							luaL_error(L, "no parameters specified");
  1.2122 +
  1.2123 +				        skipRerecords = lua_toboolean(L, 1);
  1.2124 +				        return 0;
  1.2125 +					}
  1.2126 +
  1.2127 +// movie.stop()
  1.2128 +//
  1.2129 +
  1.2130 +//   Stops movie playback/recording. Bombs out if movie is not running.
  1.2131 +				    static int movie_stop(lua_State *L)
  1.2132 +				    {
  1.2133 +				        if (!VBAMovieActive())
  1.2134 +							luaL_error(L, "no movie");
  1.2135 +
  1.2136 +				        VBAMovieStop(false);
  1.2137 +				        return 0;
  1.2138 +					}
  1.2139 +
  1.2140 +#define LUA_SCREEN_WIDTH    256
  1.2141 +#define LUA_SCREEN_HEIGHT   239
  1.2142 +
  1.2143 +// Common code by the gui library: make sure the screen array is ready
  1.2144 +				    static void gui_prepare(void)
  1.2145 +				    {
  1.2146 +				        if (!gui_data)
  1.2147 +							gui_data = (uint8 *)malloc(LUA_SCREEN_WIDTH * LUA_SCREEN_HEIGHT * 4);
  1.2148 +				        if (!gui_used)
  1.2149 +							memset(gui_data, 0, LUA_SCREEN_WIDTH * LUA_SCREEN_HEIGHT * 4);
  1.2150 +				        gui_used = true;
  1.2151 +					}
  1.2152 +
  1.2153 +// pixform for lua graphics
  1.2154 +#define BUILD_PIXEL_ARGB8888(A, R, G, B)    (((int)(A) << 24) | ((int)(R) << 16) | ((int)(G) << 8) | (int)(B))
  1.2155 +#define DECOMPOSE_PIXEL_ARGB8888(PIX, A, R, G, B) \
  1.2156 +	{                                             \
  1.2157 +		(A) = ((PIX) >> 24) & 0xff;               \
  1.2158 +		(R) = ((PIX) >> 16) & 0xff;               \
  1.2159 +		(G) = ((PIX) >> 8) & 0xff;                \
  1.2160 +		(B) = (PIX) & 0xff;                       \
  1.2161 +	}
  1.2162 +#define LUA_BUILD_PIXEL     BUILD_PIXEL_ARGB8888
  1.2163 +#define LUA_DECOMPOSE_PIXEL DECOMPOSE_PIXEL_ARGB8888
  1.2164 +#define LUA_PIXEL_A(PIX) (((PIX) >> 24) & 0xff)
  1.2165 +#define LUA_PIXEL_R(PIX) (((PIX) >> 16) & 0xff)
  1.2166 +#define LUA_PIXEL_G(PIX) (((PIX) >> 8) & 0xff)
  1.2167 +#define LUA_PIXEL_B(PIX) ((PIX) & 0xff)
  1.2168 +
  1.2169 +				    template<class T>
  1.2170 +				    static void swap(T &one, T &two)
  1.2171 +				    {
  1.2172 +				        T temp = one;
  1.2173 +				        one = two;
  1.2174 +				        two = temp;
  1.2175 +					}
  1.2176 +
  1.2177 +// write a pixel to buffer
  1.2178 +				    static inline void blend32(uint32 *dstPixel, uint32 colour)
  1.2179 +				    {
  1.2180 +				        uint8 *dst = (uint8 *)dstPixel;
  1.2181 +				        int	   a, r, g, b;
  1.2182 +				        LUA_DECOMPOSE_PIXEL(colour, a, r, g, b);
  1.2183 +
  1.2184 +				        if (a == 255 || dst[3] == 0)
  1.2185 +				        {
  1.2186 +				            // direct copy
  1.2187 +				            *(uint32 *) (dst) = colour;
  1.2188 +						}
  1.2189 +				        else if (a == 0)
  1.2190 +				        {
  1.2191 +				            // do not copy
  1.2192 +						}
  1.2193 +				        else
  1.2194 +				        {
  1.2195 +				            // alpha-blending
  1.2196 +				            int a_dst = ((255 - a) * dst[3] + 128) / 255;
  1.2197 +				            int a_new = a + a_dst;
  1.2198 +
  1.2199 +				            dst[0] = (uint8) (((dst[0] * a_dst + b * a) + (a_new / 2)) / a_new);
  1.2200 +				            dst[1] = (uint8) (((dst[1] * a_dst + g * a) + (a_new / 2)) / a_new);
  1.2201 +				            dst[2] = (uint8) (((dst[2] * a_dst + r * a) + (a_new / 2)) / a_new);
  1.2202 +				            dst[3] = (uint8) a_new;
  1.2203 +						}
  1.2204 +					}
  1.2205 +
  1.2206 +// check if a pixel is in the lua canvas
  1.2207 +				    static inline bool gui_check_boundary(int x, int y)
  1.2208 +				    {
  1.2209 +				        return !(x < 0 || x >= LUA_SCREEN_WIDTH || y < 0 || y >= LUA_SCREEN_HEIGHT);
  1.2210 +					}
  1.2211 +
  1.2212 +// check if any part of a box is in the lua canvas
  1.2213 +				    static inline bool gui_checkbox(int x1, int y1, int x2, int y2)
  1.2214 +				    {
  1.2215 +				        if ((x1 <  0 && x2 <  0)
  1.2216 +				            || (x1 >= LUA_SCREEN_WIDTH && x2 >= LUA_SCREEN_WIDTH)
  1.2217 +				            || (y1 <  0 && y2 <  0)
  1.2218 +				            || (y1 >= LUA_SCREEN_HEIGHT && y2 >= LUA_SCREEN_HEIGHT))
  1.2219 +							return false;
  1.2220 +				        return true;
  1.2221 +					}
  1.2222 +
  1.2223 +// write a pixel to gui_data (do not check boundaries for speedup)
  1.2224 +				    static inline void gui_drawpixel_fast(int x, int y, uint32 colour)
  1.2225 +				    {
  1.2226 +				        //gui_prepare();
  1.2227 +				        blend32((uint32 *) &gui_data[(y * LUA_SCREEN_WIDTH + x) * 4], colour);
  1.2228 +					}
  1.2229 +
  1.2230 +// write a pixel to gui_data (check boundaries)
  1.2231 +				    static inline void gui_drawpixel_internal(int x, int y, uint32 colour)
  1.2232 +				    {
  1.2233 +				        //gui_prepare();
  1.2234 +				        if (gui_check_boundary(x, y))
  1.2235 +							gui_drawpixel_fast(x, y, colour);
  1.2236 +					}
  1.2237 +
  1.2238 +// draw a line on gui_data (checks boundaries)
  1.2239 +				    static void gui_drawline_internal(int x1, int y1, int x2, int y2, bool lastPixel, uint32 colour)
  1.2240 +				    {
  1.2241 +				        //gui_prepare();
  1.2242 +				        // Note: New version of Bresenham's Line Algorithm
  1.2243 +				        //
  1.2244 +				        //
  1.2245 +				        // http://groups.google.co.jp/group/rec.games.roguelike.development/browse_thread/thread/345f4c42c3b25858/29e07a3af3a450e6?show_docid=29e07a3af3a450e6
  1.2246 +				        int swappedx = 0;
  1.2247 +				        int swappedy = 0;
  1.2248 +
  1.2249 +				        int xtemp = x1 - x2;
  1.2250 +				        int ytemp = y1 - y2;
  1.2251 +				        if (xtemp == 0 && ytemp == 0)
  1.2252 +				        {
  1.2253 +				            gui_drawpixel_internal(x1, y1, colour);
  1.2254 +				            return;
  1.2255 +						}
  1.2256 +
  1.2257 +				        if (xtemp < 0)
  1.2258 +				        {
  1.2259 +				            xtemp	 = -xtemp;
  1.2260 +				            swappedx = 1;
  1.2261 +						}
  1.2262 +
  1.2263 +				        if (ytemp < 0)
  1.2264 +				        {
  1.2265 +				            ytemp	 = -ytemp;
  1.2266 +				            swappedy = 1;
  1.2267 +						}
  1.2268 +
  1.2269 +				        int delta_x = xtemp << 1;
  1.2270 +				        int delta_y = ytemp << 1;
  1.2271 +
  1.2272 +				        signed char ix = x1 > x2 ? 1 : -1;
  1.2273 +				        signed char iy = y1 > y2 ? 1 : -1;
  1.2274 +
  1.2275 +				        if (lastPixel)
  1.2276 +							gui_drawpixel_internal(x2, y2, colour);
  1.2277 +
  1.2278 +				        if (delta_x >= delta_y)
  1.2279 +				        {
  1.2280 +				            int error = delta_y - (delta_x >> 1);
  1.2281 +
  1.2282 +				            while (x2 != x1)
  1.2283 +				            {
  1.2284 +				                if (error == 0 && !swappedx)
  1.2285 +									gui_drawpixel_internal(x2 + ix, y2, colour);
  1.2286 +				                if (error >= 0)
  1.2287 +				                {
  1.2288 +				                    if (error || (ix > 0))
  1.2289 +				                    {
  1.2290 +				                        y2	  += iy;
  1.2291 +				                        error -= delta_x;
  1.2292 +									}
  1.2293 +								}
  1.2294 +
  1.2295 +				                x2 += ix;
  1.2296 +				                gui_drawpixel_internal(x2, y2, colour);
  1.2297 +				                if (error == 0 && swappedx)
  1.2298 +									gui_drawpixel_internal(x2, y2 + iy, colour);
  1.2299 +				                error += delta_y;
  1.2300 +							}
  1.2301 +						}
  1.2302 +				        else
  1.2303 +				        {
  1.2304 +				            int error = delta_x - (delta_y >> 1);
  1.2305 +
  1.2306 +				            while (y2 != y1)
  1.2307 +				            {
  1.2308 +				                if (error == 0 && !swappedy)
  1.2309 +									gui_drawpixel_internal(x2, y2 + iy, colour);
  1.2310 +				                if (error >= 0)
  1.2311 +				                {
  1.2312 +				                    if (error || (iy > 0))
  1.2313 +				                    {
  1.2314 +				                        x2	  += ix;
  1.2315 +				                        error -= delta_y;
  1.2316 +									}
  1.2317 +								}
  1.2318 +
  1.2319 +				                y2 += iy;
  1.2320 +				                gui_drawpixel_internal(x2, y2, colour);
  1.2321 +				                if (error == 0 && swappedy)
  1.2322 +									gui_drawpixel_internal(x2 + ix, y2, colour);
  1.2323 +				                error += delta_x;
  1.2324 +							}
  1.2325 +						}
  1.2326 +					}
  1.2327 +
  1.2328 +// draw a rect on gui_data
  1.2329 +				    static void gui_drawbox_internal(int x1, int y1, int x2, int y2, uint32 colour)
  1.2330 +				    {
  1.2331 +				        if (x1 > x2)
  1.2332 +							std::swap(x1, x2);
  1.2333 +				        if (y1 > y2)
  1.2334 +							std::swap(y1, y2);
  1.2335 +				        if (x1 < 0)
  1.2336 +							x1 = -1;
  1.2337 +				        if (y1 < 0)
  1.2338 +							y1 = -1;
  1.2339 +				        if (x2 >= LUA_SCREEN_WIDTH)
  1.2340 +							x2 = LUA_SCREEN_WIDTH;
  1.2341 +				        if (y2 >= LUA_SCREEN_HEIGHT)
  1.2342 +							y2 = LUA_SCREEN_HEIGHT;
  1.2343 +
  1.2344 +				        if (!gui_checkbox(x1, y1, x2, y2))
  1.2345 +							return;
  1.2346 +
  1.2347 +				        //gui_prepare();
  1.2348 +				        gui_drawline_internal(x1, y1, x2, y1, true, colour);
  1.2349 +				        gui_drawline_internal(x1, y2, x2, y2, true, colour);
  1.2350 +				        gui_drawline_internal(x1, y1, x1, y2, true, colour);
  1.2351 +				        gui_drawline_internal(x2, y1, x2, y2, true, colour);
  1.2352 +					}
  1.2353 +
  1.2354 +// draw a circle on gui_data
  1.2355 +				    static void gui_drawcircle_internal(int x0, int y0, int radius, uint32 colour)
  1.2356 +				    {
  1.2357 +				        //gui_prepare();
  1.2358 +				        if (radius < 0)
  1.2359 +							radius = -radius;
  1.2360 +				        if (radius == 0)
  1.2361 +							return;
  1.2362 +				        if (radius == 1)
  1.2363 +				        {
  1.2364 +				            gui_drawpixel_internal(x0, y0, colour);
  1.2365 +				            return;
  1.2366 +						}
  1.2367 +
  1.2368 +				        // http://en.wikipedia.org/wiki/Midpoint_circle_algorithm
  1.2369 +				        int f	  = 1 - radius;
  1.2370 +				        int ddF_x = 1;
  1.2371 +				        int ddF_y = -2 * radius;
  1.2372 +				        int x	  = 0;
  1.2373 +				        int y	  = radius;
  1.2374 +
  1.2375 +				        if (!gui_checkbox(x0 - radius, y0 - radius, x0 + radius, y0 + radius))
  1.2376 +							return;
  1.2377 +
  1.2378 +				        gui_drawpixel_internal(x0, y0 + radius, colour);
  1.2379 +				        gui_drawpixel_internal(x0, y0 - radius, colour);
  1.2380 +				        gui_drawpixel_internal(x0 + radius, y0, colour);
  1.2381 +				        gui_drawpixel_internal(x0 - radius, y0, colour);
  1.2382 +
  1.2383 +				        // same pixel shouldn't be drawed twice,
  1.2384 +				        // because each pixel has opacity.
  1.2385 +				        // so now the routine gets ugly.
  1.2386 +				        while (true)
  1.2387 +				        {
  1.2388 +				            assert(ddF_x == 2 * x + 1);
  1.2389 +				            assert(ddF_y == -2 * y);
  1.2390 +				            assert(f == x * x + y * y - radius * radius + 2 * x - y + 1);
  1.2391 +				            if (f >= 0)
  1.2392 +				            {
  1.2393 +				                y--;
  1.2394 +				                ddF_y += 2;
  1.2395 +				                f	  += ddF_y;
  1.2396 +							}
  1.2397 +
  1.2398 +				            x++;
  1.2399 +				            ddF_x += 2;
  1.2400 +				            f	  += ddF_x;
  1.2401 +				            if (x < y)
  1.2402 +				            {
  1.2403 +				                gui_drawpixel_internal(x0 + x, y0 + y, colour);
  1.2404 +				                gui_drawpixel_internal(x0 - x, y0 + y, colour);
  1.2405 +				                gui_drawpixel_internal(x0 + x, y0 - y, colour);
  1.2406 +				                gui_drawpixel_internal(x0 - x, y0 - y, colour);
  1.2407 +				                gui_drawpixel_internal(x0 + y, y0 + x, colour);
  1.2408 +				                gui_drawpixel_internal(x0 - y, y0 + x, colour);
  1.2409 +				                gui_drawpixel_internal(x0 + y, y0 - x, colour);
  1.2410 +				                gui_drawpixel_internal(x0 - y, y0 - x, colour);
  1.2411 +							}
  1.2412 +				            else if (x == y)
  1.2413 +				            {
  1.2414 +				                gui_drawpixel_internal(x0 + x, y0 + y, colour);
  1.2415 +				                gui_drawpixel_internal(x0 - x, y0 + y, colour);
  1.2416 +				                gui_drawpixel_internal(x0 + x, y0 - y, colour);
  1.2417 +				                gui_drawpixel_internal(x0 - x, y0 - y, colour);
  1.2418 +				                break;
  1.2419 +							}
  1.2420 +				            else
  1.2421 +								break;
  1.2422 +						}
  1.2423 +					}
  1.2424 +
  1.2425 +// draw fill rect on gui_data
  1.2426 +				    static void gui_fillbox_internal(int x1, int y1, int x2, int y2, uint32 colour)
  1.2427 +				    {
  1.2428 +				        if (x1 > x2)
  1.2429 +							std::swap(x1, x2);
  1.2430 +				        if (y1 > y2)
  1.2431 +							std::swap(y1, y2);
  1.2432 +				        if (x1 < 0)
  1.2433 +							x1 = 0;
  1.2434 +				        if (y1 < 0)
  1.2435 +							y1 = 0;
  1.2436 +				        if (x2 >= LUA_SCREEN_WIDTH)
  1.2437 +							x2 = LUA_SCREEN_WIDTH - 1;
  1.2438 +				        if (y2 >= LUA_SCREEN_HEIGHT)
  1.2439 +							y2 = LUA_SCREEN_HEIGHT - 1;
  1.2440 +
  1.2441 +				        //gui_prepare();
  1.2442 +				        int ix, iy;
  1.2443 +				        for (iy = y1; iy <= y2; iy++)
  1.2444 +				        {
  1.2445 +				            for (ix = x1; ix <= x2; ix++)
  1.2446 +				            {
  1.2447 +				                gui_drawpixel_fast(ix, iy, colour);
  1.2448 +							}
  1.2449 +						}
  1.2450 +					}
  1.2451 +
  1.2452 +// fill a circle on gui_data
  1.2453 +				    static void gui_fillcircle_internal(int x0, int y0, int radius, uint32 colour)
  1.2454 +				    {
  1.2455 +				        //gui_prepare();
  1.2456 +				        if (radius < 0)
  1.2457 +							radius = -radius;
  1.2458 +				        if (radius == 0)
  1.2459 +							return;
  1.2460 +				        if (radius == 1)
  1.2461 +				        {
  1.2462 +				            gui_drawpixel_internal(x0, y0, colour);
  1.2463 +				            return;
  1.2464 +						}
  1.2465 +
  1.2466 +				        // http://en.wikipedia.org/wiki/Midpoint_circle_algorithm
  1.2467 +				        int f	  = 1 - radius;
  1.2468 +				        int ddF_x = 1;
  1.2469 +				        int ddF_y = -2 * radius;
  1.2470 +				        int x	  = 0;
  1.2471 +				        int y	  = radius;
  1.2472 +
  1.2473 +				        if (!gui_checkbox(x0 - radius, y0 - radius, x0 + radius, y0 + radius))
  1.2474 +							return;
  1.2475 +
  1.2476 +				        gui_drawline_internal(x0, y0 - radius, x0, y0 + radius, true, colour);
  1.2477 +
  1.2478 +				        while (true)
  1.2479 +				        {
  1.2480 +				            assert(ddF_x == 2 * x + 1);
  1.2481 +				            assert(ddF_y == -2 * y);
  1.2482 +				            assert(f == x * x + y * y - radius * radius + 2 * x - y + 1);
  1.2483 +				            if (f >= 0)
  1.2484 +				            {
  1.2485 +				                y--;
  1.2486 +				                ddF_y += 2;
  1.2487 +				                f	  += ddF_y;
  1.2488 +							}
  1.2489 +
  1.2490 +				            x++;
  1.2491 +				            ddF_x += 2;
  1.2492 +				            f	  += ddF_x;
  1.2493 +
  1.2494 +				            if (x < y)
  1.2495 +				            {
  1.2496 +				                gui_drawline_internal(x0 + x, y0 - y, x0 + x, y0 + y, true, colour);
  1.2497 +				                gui_drawline_internal(x0 - x, y0 - y, x0 - x, y0 + y, true, colour);
  1.2498 +				                if (f >= 0)
  1.2499 +				                {
  1.2500 +				                    gui_drawline_internal(x0 + y, y0 - x, x0 + y, y0 + x, true, colour);
  1.2501 +				                    gui_drawline_internal(x0 - y, y0 - x, x0 - y, y0 + x, true, colour);
  1.2502 +								}
  1.2503 +							}
  1.2504 +				            else if (x == y)
  1.2505 +				            {
  1.2506 +				                gui_drawline_internal(x0 + x, y0 - y, x0 + x, y0 + y, true, colour);
  1.2507 +				                gui_drawline_internal(x0 - x, y0 - y, x0 - x, y0 + y, true, colour);
  1.2508 +				                break;
  1.2509 +							}
  1.2510 +				            else
  1.2511 +								break;
  1.2512 +						}
  1.2513 +					}
  1.2514 +
  1.2515 +// Helper for a simple hex parser
  1.2516 +				    static int hex2int(lua_State *L, char c)
  1.2517 +				    {
  1.2518 +				        if (c >= '0' && c <= '9')
  1.2519 +							return c - '0';
  1.2520 +				        if (c >= 'a' && c <= 'f')
  1.2521 +							return c - 'a' + 10;
  1.2522 +				        if (c >= 'A' && c <= 'F')
  1.2523 +							return c - 'A' + 10;
  1.2524 +				        return luaL_error(L, "invalid hex in colour");
  1.2525 +					}
  1.2526 +
  1.2527 +				    static const struct ColorMapping
  1.2528 +				    {
  1.2529 +				        const char *name;
  1.2530 +				        int			value;
  1.2531 +					}
  1.2532 +				    s_colorMapping[] =
  1.2533 +				    {
  1.2534 +				        { "white",		0xFFFFFFFF		  },
  1.2535 +				        { "black",		0x000000FF		  },
  1.2536 +				        { "clear",		0x00000000		  },
  1.2537 +				        { "gray",		0x7F7F7FFF		  },
  1.2538 +				        { "grey",		0x7F7F7FFF		  },
  1.2539 +				        { "red",		0xFF0000FF		  },
  1.2540 +				        { "orange",		0xFF7F00FF		  },
  1.2541 +				        { "yellow",		0xFFFF00FF		  },
  1.2542 +				        { "chartreuse", 0x7FFF00FF		  },
  1.2543 +				        { "green",		0x00FF00FF		  },
  1.2544 +				        { "teal",		0x00FF7FFF		  },
  1.2545 +				        { "cyan",		0x00FFFFFF		  },
  1.2546 +				        { "blue",		0x0000FFFF		  },
  1.2547 +				        { "purple",		0x7F00FFFF		  },
  1.2548 +				        { "magenta",	0xFF00FFFF		  },
  1.2549 +					};
  1.2550 +
  1.2551 +/**
  1.2552 + * Converts an integer or a string on the stack at the given
  1.2553 + * offset to a RGB32 colour. Several encodings are supported.
  1.2554 + * The user may construct their own RGB value, given a simple colour name,
  1.2555 + * or an HTML-style "#09abcd" colour. 16 bit reduction doesn't occur at this time.
  1.2556 + */
  1.2557 +				    static inline bool str2colour(uint32 *colour, lua_State *L, const char *str)
  1.2558 +				    {
  1.2559 +				        if (str[0] == '#')
  1.2560 +				        {
  1.2561 +				            int color;
  1.2562 +				            sscanf(str + 1, "%X", &color);
  1.2563 +
  1.2564 +				            int len		= strlen(str + 1);
  1.2565 +				            int missing = max(0, 8 - len);
  1.2566 +				            color <<= missing << 2;
  1.2567 +				            if (missing >= 2)
  1.2568 +								color |= 0xFF;
  1.2569 +				            *colour = color;
  1.2570 +				            return true;
  1.2571 +						}
  1.2572 +				        else
  1.2573 +				        {
  1.2574 +				            if (!strnicmp(str, "rand", 4))
  1.2575 +				            {
  1.2576 +				                *colour = gen_rand32() | 0xFF; //((rand()*255/RAND_MAX) << 8) | ((rand()*255/RAND_MAX) << 16) |
  1.2577 +				                                               // ((rand()*255/RAND_MAX) << 24) | 0xFF;
  1.2578 +				                return true;
  1.2579 +							}
  1.2580 +
  1.2581 +				            for (int i = 0; i < sizeof(s_colorMapping) / sizeof(*s_colorMapping); i++)
  1.2582 +				            {
  1.2583 +				                if (!stricmp(str, s_colorMapping[i].name))
  1.2584 +				                {
  1.2585 +				                    *colour = s_colorMapping[i].value;
  1.2586 +				                    return true;
  1.2587 +								}
  1.2588 +							}
  1.2589 +						}
  1.2590 +
  1.2591 +				        return false;
  1.2592 +					}
  1.2593 +
  1.2594 +				    static inline uint32 gui_getcolour_wrapped(lua_State *L, int offset, bool hasDefaultValue, uint32 defaultColour)
  1.2595 +				    {
  1.2596 +				        switch (lua_type(L, offset))
  1.2597 +				        {
  1.2598 +						case LUA_TSTRING:
  1.2599 +							{
  1.2600 +							    const char *str = lua_tostring(L, offset);
  1.2601 +							    uint32		colour;
  1.2602 +
  1.2603 +							    if (str2colour(&colour, L, str))
  1.2604 +									return colour;
  1.2605 +							    else
  1.2606 +							    {
  1.2607 +							        if (hasDefaultValue)
  1.2608 +										return defaultColour;
  1.2609 +							        else
  1.2610 +										return luaL_error(L, "unknown colour %s", str);
  1.2611 +								}
  1.2612 +							}
  1.2613 +
  1.2614 +						case LUA_TNUMBER:
  1.2615 +							{
  1.2616 +							    uint32 colour = (uint32) lua_tointeger(L, offset);
  1.2617 +							    return colour;
  1.2618 +							}
  1.2619 +
  1.2620 +						case LUA_TTABLE:
  1.2621 +							{
  1.2622 +							    int color = 0xFF;
  1.2623 +							    lua_pushnil(L); // first key
  1.2624 +							    int	 keyIndex	= lua_gettop(L);
  1.2625 +							    int	 valueIndex = keyIndex + 1;
  1.2626 +							    bool first		= true;
  1.2627 +							    while (lua_next(L, offset))
  1.2628 +							    {
  1.2629 +							        bool keyIsString = (lua_type(L, keyIndex) == LUA_TSTRING);
  1.2630 +							        bool keyIsNumber = (lua_type(L, keyIndex) == LUA_TNUMBER);
  1.2631 +							        int	 key		 = keyIsString ? tolower(*lua_tostring(L, keyIndex)) : (keyIsNumber ? lua_tointeger(L, keyIndex) : 0);
  1.2632 +							        int	 value		 = lua_tointeger(L, valueIndex);
  1.2633 +							        if (value < 0) value = 0;
  1.2634 +							        if (value > 255) value = 255;
  1.2635 +							        switch (key)
  1.2636 +							        {
  1.2637 +									case 1:
  1.2638 +									case 'r':
  1.2639 +										color |= value << 24; break;
  1.2640 +									case 2:
  1.2641 +									case 'g':
  1.2642 +										color |= value << 16; break;
  1.2643 +									case 3:
  1.2644 +									case 'b':
  1.2645 +										color |= value << 8; break;
  1.2646 +									case 4:
  1.2647 +									case 'a':
  1.2648 +										color = (color & ~0xFF) | value; break;
  1.2649 +									}
  1.2650 +							        lua_pop(L, 1);
  1.2651 +								}
  1.2652 +							    return color;
  1.2653 +							}   break;
  1.2654 +
  1.2655 +						case LUA_TFUNCTION:
  1.2656 +							luaL_error(L, "invalid colour"); // NYI
  1.2657 +							return 0;
  1.2658 +
  1.2659 +						default:
  1.2660 +							if (hasDefaultValue)
  1.2661 +								return defaultColour;
  1.2662 +							else
  1.2663 +								return luaL_error(L, "invalid colour");
  1.2664 +						}
  1.2665 +					}
  1.2666 +
  1.2667 +				    static uint32 gui_getcolour(lua_State *L, int offset)
  1.2668 +				    {
  1.2669 +				        uint32 colour;
  1.2670 +				        int	   a, r, g, b;
  1.2671 +
  1.2672 +				        colour = gui_getcolour_wrapped(L, offset, false, 0);
  1.2673 +				        a	   = ((colour & 0xff) * transparencyModifier) / 255;
  1.2674 +				        if (a > 255)
  1.2675 +							a = 255;
  1.2676 +				        b = (colour >> 8) & 0xff;
  1.2677 +				        g = (colour >> 16) & 0xff;
  1.2678 +				        r = (colour >> 24) & 0xff;
  1.2679 +				        return LUA_BUILD_PIXEL(a, r, g, b);
  1.2680 +					}
  1.2681 +
  1.2682 +				    static uint32 gui_optcolour(lua_State *L, int offset, uint32 defaultColour)
  1.2683 +				    {
  1.2684 +				        uint32 colour;
  1.2685 +				        int	   a, r, g, b;
  1.2686 +				        uint8  defA, defB, defG, defR;
  1.2687 +
  1.2688 +				        LUA_DECOMPOSE_PIXEL(defaultColour, defA, defR, defG, defB);
  1.2689 +				        defaultColour = (defR << 24) | (defG << 16) | (defB << 8) | defA;
  1.2690 +
  1.2691 +				        colour = gui_getcolour_wrapped(L, offset, true, defaultColour);
  1.2692 +				        a	   = ((colour & 0xff) * transparencyModifier) / 255;
  1.2693 +				        if (a > 255)
  1.2694 +							a = 255;
  1.2695 +				        b = (colour >> 8) & 0xff;
  1.2696 +				        g = (colour >> 16) & 0xff;
  1.2697 +				        r = (colour >> 24) & 0xff;
  1.2698 +				        return LUA_BUILD_PIXEL(a, r, g, b);
  1.2699 +					}
  1.2700 +
  1.2701 +// gui.drawpixel(x,y,colour)
  1.2702 +				    static int gui_drawpixel(lua_State *L)
  1.2703 +				    {
  1.2704 +				        int x = luaL_checkinteger(L, 1);
  1.2705 +				        int y = luaL_checkinteger(L, 2);
  1.2706 +
  1.2707 +				        uint32 colour = gui_getcolour(L, 3);
  1.2708 +
  1.2709 +				        //	if (!gui_check_boundary(x, y))
  1.2710 +				        //		luaL_error(L,"bad coordinates");
  1.2711 +				        gui_prepare();
  1.2712 +
  1.2713 +				        gui_drawpixel_internal(x, y, colour);
  1.2714 +
  1.2715 +				        return 0;
  1.2716 +					}
  1.2717 +
  1.2718 +// gui.drawline(x1,y1,x2,y2,color,skipFirst)
  1.2719 +				    static int gui_drawline(lua_State *L)
  1.2720 +				    {
  1.2721 +				        int	   x1, y1, x2, y2;
  1.2722 +				        uint32 color;
  1.2723 +				        x1	  = luaL_checkinteger(L, 1);
  1.2724 +				        y1	  = luaL_checkinteger(L, 2);
  1.2725 +				        x2	  = luaL_checkinteger(L, 3);
  1.2726 +				        y2	  = luaL_checkinteger(L, 4);
  1.2727 +				        color = gui_optcolour(L, 5, LUA_BUILD_PIXEL(255, 255, 255, 255));
  1.2728 +				        int skipFirst = lua_toboolean(L, 6);
  1.2729 +
  1.2730 +				        gui_prepare();
  1.2731 +
  1.2732 +				        gui_drawline_internal(x2, y2, x1, y1, !skipFirst, color);
  1.2733 +
  1.2734 +				        return 0;
  1.2735 +					}
  1.2736 +
  1.2737 +// gui.drawbox(x1, y1, x2, y2, fillcolor, outlinecolor)
  1.2738 +				    static int gui_drawbox(lua_State *L)
  1.2739 +				    {
  1.2740 +				        int	   x1, y1, x2, y2;
  1.2741 +				        uint32 fillcolor;
  1.2742 +				        uint32 outlinecolor;
  1.2743 +
  1.2744 +				        x1 = luaL_checkinteger(L, 1);
  1.2745 +				        y1 = luaL_checkinteger(L, 2);
  1.2746 +				        x2 = luaL_checkinteger(L, 3);
  1.2747 +				        y2 = luaL_checkinteger(L, 4);
  1.2748 +				        fillcolor	 = gui_optcolour(L, 5, LUA_BUILD_PIXEL(63, 255, 255, 255));
  1.2749 +				        outlinecolor = gui_optcolour(L, 6, LUA_BUILD_PIXEL(255, LUA_PIXEL_R(fillcolor), LUA_PIXEL_G(fillcolor), LUA_PIXEL_B(fillcolor)));
  1.2750 +
  1.2751 +				        if (x1 > x2)
  1.2752 +							std::swap(x1, x2);
  1.2753 +				        if (y1 > y2)
  1.2754 +							std::swap(y1, y2);
  1.2755 +
  1.2756 +				        gui_prepare();
  1.2757 +
  1.2758 +				        gui_drawbox_internal(x1, y1, x2, y2, outlinecolor);
  1.2759 +				        if ((x2 - x1) >= 2 && (y2 - y1) >= 2)
  1.2760 +							gui_fillbox_internal(x1 + 1, y1 + 1, x2 - 1, y2 - 1, fillcolor);
  1.2761 +
  1.2762 +				        return 0;
  1.2763 +					}
  1.2764 +
  1.2765 +// gui.drawcircle(x0, y0, radius, colour)
  1.2766 +				    static int gui_drawcircle(lua_State *L)
  1.2767 +				    {
  1.2768 +				        int	   x, y, r;
  1.2769 +				        uint32 colour;
  1.2770 +
  1.2771 +				        x	   = luaL_checkinteger(L, 1);
  1.2772 +				        y	   = luaL_checkinteger(L, 2);
  1.2773 +				        r	   = luaL_checkinteger(L, 3);
  1.2774 +				        colour = gui_getcolour(L, 4);
  1.2775 +
  1.2776 +				        gui_prepare();
  1.2777 +
  1.2778 +				        gui_drawcircle_internal(x, y, r, colour);
  1.2779 +
  1.2780 +				        return 0;
  1.2781 +					}
  1.2782 +
  1.2783 +// gui.fillbox(x1, y1, x2, y2, colour)
  1.2784 +				    static int gui_fillbox(lua_State *L)
  1.2785 +				    {
  1.2786 +				        int	   x1, y1, x2, y2;
  1.2787 +				        uint32 colour;
  1.2788 +
  1.2789 +				        x1	   = luaL_checkinteger(L, 1);
  1.2790 +				        y1	   = luaL_checkinteger(L, 2);
  1.2791 +				        x2	   = luaL_checkinteger(L, 3);
  1.2792 +				        y2	   = luaL_checkinteger(L, 4);
  1.2793 +				        colour = gui_getcolour(L, 5);
  1.2794 +
  1.2795 +				        //	if (!gui_check_boundary(x1, y1))
  1.2796 +				        //		luaL_error(L,"bad coordinates");
  1.2797 +				        //
  1.2798 +				        //	if (!gui_check_boundary(x2, y2))
  1.2799 +				        //		luaL_error(L,"bad coordinates");
  1.2800 +				        gui_prepare();
  1.2801 +
  1.2802 +				        if (!gui_checkbox(x1, y1, x2, y2))
  1.2803 +							return 0;
  1.2804 +
  1.2805 +				        gui_fillbox_internal(x1, y1, x2, y2, colour);
  1.2806 +
  1.2807 +				        return 0;
  1.2808 +					}
  1.2809 +
  1.2810 +// gui.fillcircle(x0, y0, radius, colour)
  1.2811 +				    static int gui_fillcircle(lua_State *L)
  1.2812 +				    {
  1.2813 +				        int	   x, y, r;
  1.2814 +				        uint32 colour;
  1.2815 +
  1.2816 +				        x	   = luaL_checkinteger(L, 1);
  1.2817 +				        y	   = luaL_checkinteger(L, 2);
  1.2818 +				        r	   = luaL_checkinteger(L, 3);
  1.2819 +				        colour = gui_getcolour(L, 4);
  1.2820 +
  1.2821 +				        gui_prepare();
  1.2822 +
  1.2823 +				        gui_fillcircle_internal(x, y, r, colour);
  1.2824 +
  1.2825 +				        return 0;
  1.2826 +					}
  1.2827 +
  1.2828 +				    static int gui_getpixel(lua_State *L)
  1.2829 +				    {
  1.2830 +				        int x = luaL_checkinteger(L, 1);
  1.2831 +				        int y = luaL_checkinteger(L, 2);
  1.2832 +
  1.2833 +				        int pixWidth   = 240, pixHeight = 160;
  1.2834 +				        int scrWidth   = 240, scrHeight = 160;
  1.2835 +				        int scrOffsetX = 0, scrOffsetY = 0;
  1.2836 +				        int pitch;
  1.2837 +				        if (!systemIsRunningGBA())
  1.2838 +				        {
  1.2839 +				            if (gbBorderOn)
  1.2840 +				            {
  1.2841 +				                pixWidth   = 256, pixHeight = 224;
  1.2842 +				                scrOffsetX = 48, scrOffsetY = 40;
  1.2843 +							}
  1.2844 +				            else
  1.2845 +				            {
  1.2846 +				                pixWidth = 160, pixHeight = 144;
  1.2847 +							}
  1.2848 +				            scrWidth = 160, scrHeight = 144;
  1.2849 +						}
  1.2850 +				        pitch = pixWidth * (systemColorDepth / 8) + (systemColorDepth == 24 ? 0 : 4);
  1.2851 +				        scrOffsetY++; // don't know why it's needed
  1.2852 +
  1.2853 +				        if (!(x >= 0 && y >= 0 && x < scrWidth && y < scrHeight) /*!gui_check_boundary(x,y)*/)
  1.2854 +				        {
  1.2855 +				            lua_pushinteger(L, 0);
  1.2856 +				            lua_pushinteger(L, 0);
  1.2857 +				            lua_pushinteger(L, 0);
  1.2858 +						}
  1.2859 +				        else
  1.2860 +				        {
  1.2861 +				            switch (systemColorDepth)
  1.2862 +				            {
  1.2863 +							case 16:
  1.2864 +								{
  1.2865 +								    uint16 *screen	 = (uint16 *) (&pix[scrOffsetY * pitch + scrOffsetX * 2]);
  1.2866 +								    uint16	pixColor = screen[y * pitch / 2 + x];
  1.2867 +								    lua_pushinteger(L, (pixColor >> 8) & 0xF8); // red
  1.2868 +								    lua_pushinteger(L, (pixColor >> 3) & 0xFC); // green
  1.2869 +								    lua_pushinteger(L, (pixColor << 3) & 0xF8); // blue
  1.2870 +								}
  1.2871 +								break;
  1.2872 +							case 24:
  1.2873 +								{
  1.2874 +								    uint8 *screen = &pix[scrOffsetY * pitch + scrOffsetX * 3];
  1.2875 +								    lua_pushinteger(L, screen[y * pitch + x * 3 + 2]); // red
  1.2876 +								    lua_pushinteger(L, screen[y * pitch + x * 3 + 1]); // green
  1.2877 +								    lua_pushinteger(L, screen[y * pitch + x * 3 + 0]); // blue
  1.2878 +								}
  1.2879 +								break;
  1.2880 +							case 32:
  1.2881 +								{
  1.2882 +								    uint8 *screen = &pix[scrOffsetY * pitch + scrOffsetX * 4];
  1.2883 +								    lua_pushinteger(L, screen[y * pitch + x * 4 + 2]); // red
  1.2884 +								    lua_pushinteger(L, screen[y * pitch + x * 4 + 1]); // green
  1.2885 +								    lua_pushinteger(L, screen[y * pitch + x * 4 + 0]); // blue
  1.2886 +								}
  1.2887 +								break;
  1.2888 +							default:
  1.2889 +								lua_pushinteger(L, 0);
  1.2890 +								lua_pushinteger(L, 0);
  1.2891 +								lua_pushinteger(L, 0);
  1.2892 +								break;
  1.2893 +							}
  1.2894 +						}
  1.2895 +				        return 3;
  1.2896 +					}
  1.2897 +
  1.2898 +				    static int gui_parsecolor(lua_State *L)
  1.2899 +				    {
  1.2900 +				        int	   r, g, b, a;
  1.2901 +				        uint32 color = gui_getcolour(L, 1);
  1.2902 +				        LUA_DECOMPOSE_PIXEL(color, a, r, g, b);
  1.2903 +				        lua_pushinteger(L, r);
  1.2904 +				        lua_pushinteger(L, g);
  1.2905 +				        lua_pushinteger(L, b);
  1.2906 +				        lua_pushinteger(L, a);
  1.2907 +				        return 4;
  1.2908 +					}
  1.2909 +
  1.2910 +// gui.gdscreenshot()
  1.2911 +//
  1.2912 +//  Returns a screen shot as a string in gd's v1 file format.
  1.2913 +//  This allows us to make screen shots available without gd installed locally.
  1.2914 +//  Users can also just grab pixels via substring selection.
  1.2915 +//
  1.2916 +//  I think...  Does lua support grabbing byte values from a string? // yes, string.byte(str,offset)
  1.2917 +//  Well, either way, just install gd and do what you like with it.
  1.2918 +//  It really is easier that way.
  1.2919 +
  1.2920 +// example: gd.createFromGdStr(gui.gdscreenshot()):png("outputimage.png")
  1.2921 +				    static int gui_gdscreenshot(lua_State *L)
  1.2922 +				    {
  1.2923 +				        int xofs = 0, yofs = 0, ppl = 240, width = 240, height = 160;
  1.2924 +				        if (!systemIsRunningGBA())
  1.2925 +				        {
  1.2926 +				            if (gbBorderOn)
  1.2927 +								xofs = 48, yofs = 40, ppl = 256;
  1.2928 +				            else
  1.2929 +								ppl = 160;
  1.2930 +				            width = 160, height = 144;
  1.2931 +						}
  1.2932 +
  1.2933 +				        yofs++;
  1.2934 +
  1.2935 +				        //int pitch = (((ppl * systemColorDepth + 7)>>3)+3)&~3;
  1.2936 +				        int	   pitch  = ppl * (systemColorDepth / 8) + (systemColorDepth == 24 ? 0 : 4);
  1.2937 +				        uint8 *screen = &pix[yofs * pitch + xofs * (systemColorDepth / 8)];
  1.2938 +
  1.2939 +				        int	  size = 11 + width * height * 4;
  1.2940 +				        char *str  = new char[size + 1];
  1.2941 +				        str[size] = 0;
  1.2942 +
  1.2943 +				        unsigned char *ptr = (unsigned char *)str;
  1.2944 +
  1.2945 +				        // GD format header for truecolor image (11 bytes)
  1.2946 +				        *ptr++ = (65534 >> 8) & 0xFF;
  1.2947 +				        *ptr++ = (65534) & 0xFF;
  1.2948 +				        *ptr++ = (width >> 8) & 0xFF;
  1.2949 +				        *ptr++ = (width) & 0xFF;
  1.2950 +				        *ptr++ = (height >> 8) & 0xFF;
  1.2951 +				        *ptr++ = (height) & 0xFF;
  1.2952 +				        *ptr++ = 1;
  1.2953 +				        *ptr++ = 255;
  1.2954 +				        *ptr++ = 255;
  1.2955 +				        *ptr++ = 255;
  1.2956 +				        *ptr++ = 255;
  1.2957 +
  1.2958 +				        GetColorFunc getColor;
  1.2959 +				        getColorIOFunc(systemColorDepth, &getColor, NULL);
  1.2960 +
  1.2961 +				        int x, y;
  1.2962 +				        for (y = 0; y < height; y++)
  1.2963 +				        {
  1.2964 +				            uint8 *s = &screen[y * pitch];
  1.2965 +				            for (x = 0; x < width; x++, s += systemColorDepth / 8)
  1.2966 +				            {
  1.2967 +				                uint8 r, g, b;
  1.2968 +				                getColor(s, &r, &g, &b);
  1.2969 +
  1.2970 +				                *ptr++ = 0;
  1.2971 +				                *ptr++ = r;
  1.2972 +				                *ptr++ = g;
  1.2973 +				                *ptr++ = b;
  1.2974 +							}
  1.2975 +						}
  1.2976 +
  1.2977 +				        lua_pushlstring(L, str, size);
  1.2978 +				        delete[] str;
  1.2979 +				        return 1;
  1.2980 +					}
  1.2981 +
  1.2982 +// gui.opacity(number alphaValue)
  1.2983 +// sets the transparency of subsequent draw calls
  1.2984 +// 0.0 is completely transparent, 1.0 is completely opaque
  1.2985 +// non-integer values are supported and meaningful, as are values greater than 1.0
  1.2986 +// it is not necessary to use this function to get transparency (or the less-recommended gui.transparency() either),
  1.2987 +// because you can provide an alpha value in the color argument of each draw call.
  1.2988 +
  1.2989 +// however, it can be convenient to be able to globally modify the drawing transparency
  1.2990 +				    static int gui_setopacity(lua_State *L)
  1.2991 +				    {
  1.2992 +				        double opacF = luaL_checknumber(L, 1);
  1.2993 +				        transparencyModifier = (int)(opacF * 255);
  1.2994 +				        if (transparencyModifier < 0)
  1.2995 +							transparencyModifier = 0;
  1.2996 +				        return 0;
  1.2997 +					}
  1.2998 +
  1.2999 +// gui.transparency(int strength)
  1.3000 +//
  1.3001 +
  1.3002 +//  0 = solid,
  1.3003 +				    static int gui_transparency(lua_State *L)
  1.3004 +				    {
  1.3005 +				        double trans = luaL_checknumber(L, 1);
  1.3006 +				        transparencyModifier = (int)((4.0 - trans) / 4.0 * 255);
  1.3007 +				        if (transparencyModifier < 0)
  1.3008 +							transparencyModifier = 0;
  1.3009 +				        return 0;
  1.3010 +					}
  1.3011 +
  1.3012 +				    static const uint32 Small_Font_Data[] =
  1.3013 +				    {
  1.3014 +				        0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // 32
  1.3015 +				        0x00000000, 0x00000300, 0x00000400, 0x00000500, 0x00000000, 0x00000700, 0x00000000, // 33	!
  1.3016 +				        0x00000000, 0x00040002, 0x00050003, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // 34	"
  1.3017 +				        0x00000000, 0x00040002, 0x00050403, 0x00060004, 0x00070605, 0x00080006, 0x00000000, // 35	#
  1.3018 +				        0x00000000, 0x00040300, 0x00000403, 0x00000500, 0x00070600, 0x00000706, 0x00000000, // 36	$
  1.3019 +				        0x00000000, 0x00000002, 0x00050000, 0x00000500, 0x00000005, 0x00080000, 0x00000000, // 37	%
  1.3020 +				        0x00000000, 0x00000300, 0x00050003, 0x00000500, 0x00070005, 0x00080700, 0x00000000, // 38	&
  1.3021 +				        0x00000000, 0x00000300, 0x00000400, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // 39	'
  1.3022 +				        0x00000000, 0x00000300, 0x00000003, 0x00000004, 0x00000005, 0x00000700, 0x00000000, // 40	(
  1.3023 +				        0x00000000, 0x00000300, 0x00050000, 0x00060000, 0x00070000, 0x00000700, 0x00000000, // 41	)
  1.3024 +				        0x00000000, 0x00000000, 0x00000400, 0x00060504, 0x00000600, 0x00080006, 0x00000000, // 42	*
  1.3025 +				        0x00000000, 0x00000000, 0x00000400, 0x00060504, 0x00000600, 0x00000000, 0x00000000, // 43	+
  1.3026 +				        0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000600, 0x00000700, 0x00000007, // 44	,
  1.3027 +				        0x00000000, 0x00000000, 0x00000000, 0x00060504, 0x00000000, 0x00000000, 0x00000000, // 45	-
  1.3028 +				        0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000700, 0x00000000, // 46	.
  1.3029 +				        0x00030000, 0x00040000, 0x00000400, 0x00000500, 0x00000005, 0x00000006, 0x00000000, // 47	/
  1.3030 +				        0x00000000, 0x00000300, 0x00050003, 0x00060004, 0x00070005, 0x00000700, 0x00000000, // 48	0
  1.3031 +				        0x00000000, 0x00000300, 0x00000403, 0x00000500, 0x00000600, 0x00000700, 0x00000000, // 49	1
  1.3032 +				        0x00000000, 0x00000302, 0x00050000, 0x00000500, 0x00000005, 0x00080706, 0x00000000, // 50	2
  1.3033 +				        0x00000000, 0x00000302, 0x00050000, 0x00000504, 0x00070000, 0x00000706, 0x00000000, // 51	3
  1.3034 +				        0x00000000, 0x00000300, 0x00000003, 0x00060004, 0x00070605, 0x00080000, 0x00000000, // 52	4
  1.3035 +				        0x00000000, 0x00040302, 0x00000003, 0x00000504, 0x00070000, 0x00000706, 0x00000000, // 53	5
  1.3036 +				        0x00000000, 0x00000300, 0x00000003, 0x00000504, 0x00070005, 0x00000700, 0x00000000, // 54	6
  1.3037 +				        0x00000000, 0x00040302, 0x00050000, 0x00000500, 0x00000600, 0x00000700, 0x00000000, // 55	7
  1.3038 +				        0x00000000, 0x00000300, 0x00050003, 0x00000500, 0x00070005, 0x00000700, 0x00000000, // 56	8
  1.3039 +				        0x00000000, 0x00000300, 0x00050003, 0x00060500, 0x00070000, 0x00000700, 0x00000000, // 57	9
  1.3040 +				        0x00000000, 0x00000000, 0x00000400, 0x00000000, 0x00000000, 0x00000700, 0x00000000, // 58	:
  1.3041 +				        0x00000000, 0x00000000, 0x00000000, 0x00000500, 0x00000000, 0x00000700, 0x00000007, // 59	;
  1.3042 +				        0x00000000, 0x00040000, 0x00000400, 0x00000004, 0x00000600, 0x00080000, 0x00000000, // 60	<
  1.3043 +				        0x00000000, 0x00000000, 0x00050403, 0x00000000, 0x00070605, 0x00000000, 0x00000000, // 61	=
  1.3044 +				        0x00000000, 0x00000002, 0x00000400, 0x00060000, 0x00000600, 0x00000006, 0x00000000, // 62	>
  1.3045 +				        0x00000000, 0x00000302, 0x00050000, 0x00000500, 0x00000000, 0x00000700, 0x00000000, // 63	?
  1.3046 +				        0x00000000, 0x00000300, 0x00050400, 0x00060004, 0x00070600, 0x00000000, 0x00000000, // 64	@
  1.3047 +				        0x00000000, 0x00000300, 0x00050003, 0x00060504, 0x00070005, 0x00080006, 0x00000000, // 65	A
  1.3048 +				        0x00000000, 0x00000302, 0x00050003, 0x00000504, 0x00070005, 0x00000706, 0x00000000, // 66	B
  1.3049 +				        0x00000000, 0x00040300, 0x00000003, 0x00000004, 0x00000005, 0x00080700, 0x00000000, // 67	C
  1.3050 +				        0x00000000, 0x00000302, 0x00050003, 0x00060004, 0x00070005, 0x00000706, 0x00000000, // 68	D
  1.3051 +				        0x00000000, 0x00040302, 0x00000003, 0x00000504, 0x00000005, 0x00080706, 0x00000000, // 69	E
  1.3052 +				        0x00000000, 0x00040302, 0x00000003, 0x00000504, 0x00000005, 0x00000006, 0x00000000, // 70	F
  1.3053 +				        0x00000000, 0x00040300, 0x00000003, 0x00060004, 0x00070005, 0x00080700, 0x00000000, // 71	G
  1.3054 +				        0x00000000, 0x00040002, 0x00050003, 0x00060504, 0x00070005, 0x00080006, 0x00000000, // 72	H
  1.3055 +				        0x00000000, 0x00000300, 0x00000400, 0x00000500, 0x00000600, 0x00000700, 0x00000000, // 73	I
  1.3056 +				        0x00000000, 0x00040000, 0x00050000, 0x00060000, 0x00070005, 0x00000700, 0x00000000, // 74	J
  1.3057 +				        0x00000000, 0x00040002, 0x00050003, 0x00000504, 0x00070005, 0x00080006, 0x00000000, // 75	K
  1.3058 +				        0x00000000, 0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00080706, 0x00000000, // 76	l
  1.3059 +				        0x00000000, 0x00040002, 0x00050403, 0x00060004, 0x00070005, 0x00080006, 0x00000000, // 77	M
  1.3060 +				        0x00000000, 0x00000302, 0x00050003, 0x00060004, 0x00070005, 0x00080006, 0x00000000, // 78	N
  1.3061 +				        0x00000000, 0x00040302, 0x00050003, 0x00060004, 0x00070005, 0x00080706, 0x00000000, // 79	O
  1.3062 +				        0x00000000, 0x00000302, 0x00050003, 0x00000504, 0x00000005, 0x00000006, 0x00000000, // 80	P
  1.3063 +				        0x00000000, 0x00040302, 0x00050003, 0x00060004, 0x00070005, 0x00080706, 0x00090000, // 81	Q
  1.3064 +				        0x00000000, 0x00000302, 0x00050003, 0x00000504, 0x00070005, 0x00080006, 0x00000000, // 82	R
  1.3065 +				        0x00000000, 0x00040300, 0x00000003, 0x00000500, 0x00070000, 0x00000706, 0x00000000, // 83	S
  1.3066 +				        0x00000000, 0x00040302, 0x00000400, 0x00000500, 0x00000600, 0x00000700, 0x00000000, // 84	T
  1.3067 +				        0x00000000, 0x00040002, 0x00050003, 0x00060004, 0x00070005, 0x00080706, 0x00000000, // 85	U
  1.3068 +				        0x00000000, 0x00040002, 0x00050003, 0x00060004, 0x00000600, 0x00000700, 0x00000000, // 86	V
  1.3069 +				        0x00000000, 0x00040002, 0x00050003, 0x00060004, 0x00070605, 0x00080006, 0x00000000, // 87	W
  1.3070 +				        0x00000000, 0x00040002, 0x00050003, 0x00000500, 0x00070005, 0x00080006, 0x00000000, // 88	X
  1.3071 +				        0x00000000, 0x00040002, 0x00050003, 0x00000500, 0x00000600, 0x00000700, 0x00000000, // 89	Y
  1.3072 +				        0x00000000, 0x00040302, 0x00050000, 0x00000500, 0x00000005, 0x00080706, 0x00000000, // 90	Z
  1.3073 +				        0x00000000, 0x00040300, 0x00000400, 0x00000500, 0x00000600, 0x00080700, 0x00000000, // 91	[
  1.3074 +				        0x00000000, 0x00000002, 0x00000400, 0x00000500, 0x00070000, 0x00080000, 0x00000000, // 92	'\'
  1.3075 +				        0x00000000, 0x00000302, 0x00000400, 0x00000500, 0x00000600, 0x00000706, 0x00000000, // 93	]
  1.3076 +				        0x00000000, 0x00000300, 0x00050003, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // 94	^
  1.3077 +				        0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00080706, 0x00000000, // 95	_
  1.3078 +				        0x00000000, 0x00000002, 0x00000400, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // 96	`
  1.3079 +				        0x00000000, 0x00000000, 0x00050400, 0x00060004, 0x00070005, 0x00080700, 0x00000000, // 97	a
  1.3080 +				        0x00000000, 0x00000002, 0x00000003, 0x00000504, 0x00070005, 0x00000706, 0x00000000, // 98	b
  1.3081 +				        0x00000000, 0x00000000, 0x00050400, 0x00000004, 0x00000005, 0x00080700, 0x00000000, // 99	c
  1.3082 +				        0x00000000, 0x00040000, 0x00050000, 0x00060500, 0x00070005, 0x00080700, 0x00000000, // 100	d
  1.3083 +				        0x00000000, 0x00000000, 0x00050400, 0x00060504, 0x00000005, 0x00080700, 0x00000000, // 101	e
  1.3084 +				        0x00000000, 0x00040300, 0x00000003, 0x00000504, 0x00000005, 0x00000006, 0x00000000, // 102	f
  1.3085 +				        0x00000000, 0x00000000, 0x00050400, 0x00060004, 0x00070600, 0x00080000, 0x00000807, // 103	g
  1.3086 +				        0x00000000, 0x00000002, 0x00000003, 0x00000504, 0x00070005, 0x00080006, 0x00000000, // 104	h
  1.3087 +				        0x00000000, 0x00000300, 0x00000000, 0x00000500, 0x00000600, 0x00000700, 0x00000000, // 105	i
  1.3088 +				        0x00000000, 0x00000300, 0x00000000, 0x00000500, 0x00000600, 0x00000700, 0x00000007, // 106	j
  1.3089 +				        0x00000000, 0x00000002, 0x00000003, 0x00060004, 0x00000605, 0x00080006, 0x00000000, // 107	k
  1.3090 +				        0x00000000, 0x00000300, 0x00000400, 0x00000500, 0x00000600, 0x00080000, 0x00000000, // 108	l
  1.3091 +				        0x00000000, 0x00000000, 0x00050003, 0x00060504, 0x00070005, 0x00080006, 0x00000000, // 109	m
  1.3092 +				        0x00000000, 0x00000000, 0x00000403, 0x00060004, 0x00070005, 0x00080006, 0x00000000, // 110	n
  1.3093 +				        0x00000000, 0x00000000, 0x00000400, 0x00060004, 0x00070005, 0x00000700, 0x00000000, // 111	o
  1.3094 +				        0x00000000, 0x00000000, 0x00000400, 0x00060004, 0x00000605, 0x00000006, 0x00000007, // 112	p
  1.3095 +				        0x00000000, 0x00000000, 0x00000400, 0x00060004, 0x00070600, 0x00080000, 0x00090000, // 113	q
  1.3096 +				        0x00000000, 0x00000000, 0x00050003, 0x00000504, 0x00000005, 0x00000006, 0x00000000, // 114	r
  1.3097 +				        0x00000000, 0x00000000, 0x00050400, 0x00000004, 0x00070600, 0x00000706, 0x00000000, // 115	s
  1.3098 +				        0x00000000, 0x00000300, 0x00050403, 0x00000500, 0x00000600, 0x00080000, 0x00000000, // 116	t
  1.3099 +				        0x00000000, 0x00000000, 0x00050003, 0x00060004, 0x00070005, 0x00080700, 0x00000000, // 117	u
  1.3100 +				        0x00000000, 0x00000000, 0x00050003, 0x00060004, 0x00070005, 0x00000700, 0x00000000, // 118	v
  1.3101 +				        0x00000000, 0x00000000, 0x00050003, 0x00060004, 0x00070605, 0x00080006, 0x00000000, // 119	w
  1.3102 +				        0x00000000, 0x00000000, 0x00050003, 0x00000500, 0x00070005, 0x00080006, 0x00000000, // 120	x
  1.3103 +				        0x00000000, 0x00000000, 0x00050003, 0x00060004, 0x00000600, 0x00000700, 0x00000007, // 121	y
  1.3104 +				        0x00000000, 0x00000000, 0x00050403, 0x00000500, 0x00000005, 0x00080706, 0x00000000, // 122	z
  1.3105 +				        0x00000000, 0x00040300, 0x00000400, 0x00000504, 0x00000600, 0x00080700, 0x00000000, // 123	{
  1.3106 +				        0x00000000, 0x00000300, 0x00000400, 0x00000000, 0x00000600, 0x00000700, 0x00000000, // 124	|
  1.3107 +				        0x00000000, 0x00000302, 0x00000400, 0x00060500, 0x00000600, 0x00000706, 0x00000000, // 125	}
  1.3108 +				        0x00000000, 0x00000302, 0x00050000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // 126	~
  1.3109 +				        0x00000000, 0x00000000, 0x00000400, 0x00060004, 0x00070605, 0x00000000, 0x00000000, // 127	
  1.3110 +				        0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
  1.3111 +					};
  1.3112 +
  1.3113 +				    static void PutTextInternal(const char *str, int len, short x, short y, int color, int backcolor)
  1.3114 +				    {
  1.3115 +				        int Opac	 = (color >> 24) & 0xFF;
  1.3116 +				        int backOpac = (backcolor >> 24) & 0xFF;
  1.3117 +				        int origX	 = x;
  1.3118 +
  1.3119 +				        if (!Opac && !backOpac)
  1.3120 +							return;
  1.3121 +
  1.3122 +				        while (*str && len && y < LUA_SCREEN_HEIGHT)
  1.3123 +				        {
  1.3124 +				            int c = *str++;
  1.3125 +				            while (x > LUA_SCREEN_WIDTH && c != '\n')
  1.3126 +				            {
  1.3127 +				                c = *str;
  1.3128 +				                if (c == '\0')
  1.3129 +									break;
  1.3130 +				                str++;
  1.3131 +							}
  1.3132 +
  1.3133 +				            if (c == '\n')
  1.3134 +				            {
  1.3135 +				                x  = origX;
  1.3136 +				                y += 8;
  1.3137 +				                continue;
  1.3138 +							}
  1.3139 +				            else if (c == '\t') // just in case
  1.3140 +				            {
  1.3141 +				                const int tabSpace = 8;
  1.3142 +				                x += (tabSpace - (((x - origX) / 4) % tabSpace)) * 4;
  1.3143 +				                continue;
  1.3144 +							}
  1.3145 +
  1.3146 +				            if ((unsigned int)(c - 32) >= 96)
  1.3147 +								continue;
  1.3148 +
  1.3149 +				            const unsigned char *Cur_Glyph = (const unsigned char *) &Small_Font_Data + (c - 32) * 7 * 4;
  1.3150 +
  1.3151 +				            for (int y2 = 0; y2 < 8; y2++)
  1.3152 +				            {
  1.3153 +				                unsigned int glyphLine = *((unsigned int *)Cur_Glyph + y2);
  1.3154 +				                for (int x2 = -1; x2 < 4; x2++)
  1.3155 +				                {
  1.3156 +				                    int shift	  = x2 << 3;
  1.3157 +				                    int mask	  = 0xFF << shift;
  1.3158 +				                    int intensity = (glyphLine & mask) >> shift;
  1.3159 +
  1.3160 +				                    if (intensity && x2 >= 0 && y2 < 7)
  1.3161 +				                    {
  1.3162 +				                        //int xdraw = max(0,min(LUA_SCREEN_WIDTH - 1,x+x2));
  1.3163 +				                        //int ydraw = max(0,min(LUA_SCREEN_HEIGHT - 1,y+y2));
  1.3164 +				                        //gui_drawpixel_fast(xdraw, ydraw, color);
  1.3165 +				                        gui_drawpixel_internal(x + x2, y + y2, color);
  1.3166 +									}
  1.3167 +				                    else if (backOpac)
  1.3168 +				                    {
  1.3169 +				                        for (int y3 = max(0, y2 - 1); y3 <= min(6, y2 + 1); y3++)
  1.3170 +				                        {
  1.3171 +				                            unsigned int glyphLine = *((unsigned int *)Cur_Glyph + y3);
  1.3172 +				                            for (int x3 = max(0, x2 - 1); x3 <= min(3, x2 + 1); x3++)
  1.3173 +				                            {
  1.3174 +				                                int shift = x3 << 3;
  1.3175 +				                                int mask  = 0xFF << shift;
  1.3176 +				                                intensity |= (glyphLine & mask) >> shift;
  1.3177 +				                                if (intensity)
  1.3178 +													goto draw_outline;  // speedup?
  1.3179 +											}
  1.3180 +										}
  1.3181 +
  1.3182 +draw_outline:
  1.3183 +				                        if (intensity)
  1.3184 +				                        {
  1.3185 +				                            //int xdraw = max(0,min(LUA_SCREEN_WIDTH - 1,x+x2));
  1.3186 +				                            //int ydraw = max(0,min(LUA_SCREEN_HEIGHT - 1,y+y2));
  1.3187 +				                            //gui_drawpixel_fast(xdraw, ydraw, backcolor);
  1.3188 +				                            gui_drawpixel_internal(x + x2, y + y2, backcolor);
  1.3189 +										}
  1.3190 +									}
  1.3191 +								}
  1.3192 +							}
  1.3193 +
  1.3194 +				            x += 4;
  1.3195 +				            len--;
  1.3196 +						}
  1.3197 +					}
  1.3198 +
  1.3199 +				    static int strlinelen(const char *string)
  1.3200 +				    {
  1.3201 +				        const char *s = string;
  1.3202 +				        while (*s && *s != '\n')
  1.3203 +							s++;
  1.3204 +				        if (*s)
  1.3205 +							s++;
  1.3206 +				        return s - string;
  1.3207 +					}
  1.3208 +
  1.3209 +				    static void LuaDisplayString(const char *string, int y, int x, uint32 color, uint32 outlineColor)
  1.3210 +				    {
  1.3211 +				        if (!string)
  1.3212 +							return;
  1.3213 +
  1.3214 +				        gui_prepare();
  1.3215 +
  1.3216 +				        PutTextInternal(string, strlen(string), x, y, color, outlineColor);
  1.3217 +
  1.3218 +				        /*
  1.3219 +				           const char* ptr = string;
  1.3220 +				           while(*ptr && y < LUA_SCREEN_HEIGHT)
  1.3221 +				           {
  1.3222 +				            int len = strlinelen(ptr);
  1.3223 +				            int skip = 0;
  1.3224 +				            if(len < 1) len = 1;
  1.3225 +
  1.3226 +				            // break up the line if it's too long to display otherwise
  1.3227 +				            if(len > 63)
  1.3228 +				            {
  1.3229 +				                len = 63;
  1.3230 +				                const char* ptr2 = ptr + len-1;
  1.3231 +				                for(int j = len-1; j; j--, ptr2--)
  1.3232 +				                {
  1.3233 +				                    if(*ptr2 == ' ' || *ptr2 == '\t')
  1.3234 +				                    {
  1.3235 +				                        len = j;
  1.3236 +				                        skip = 1;
  1.3237 +				                        break;
  1.3238 +				                    }
  1.3239 +				                }
  1.3240 +				            }
  1.3241 +
  1.3242 +				            int xl = 0;
  1.3243 +				            int yl = 0;
  1.3244 +				            int xh = (LUA_SCREEN_WIDTH - 1 - 1) - 4*len;
  1.3245 +				            int yh = LUA_SCREEN_HEIGHT - 1;
  1.3246 +				            int x2 = min(max(x,xl),xh);
  1.3247 +				            int y2 = min(max(y,yl),yh);
  1.3248 +
  1.3249 +				            PutTextInternal(ptr,len,x2,y2,color,outlineColor);
  1.3250 +
  1.3251 +				            ptr += len + skip;
  1.3252 +				            y += 8;
  1.3253 +				           }
  1.3254 +				         */
  1.3255 +					}
  1.3256 +
  1.3257 +// gui.text(int x, int y, string msg)
  1.3258 +//
  1.3259 +//  Displays the given text on the screen, using the same font and techniques as the
  1.3260 +
  1.3261 +//  main HUD.
  1.3262 +				    static int gui_text(lua_State *L)
  1.3263 +				    {
  1.3264 +				        //extern int font_height;
  1.3265 +				        const char *msg;
  1.3266 +				        int			x, y;
  1.3267 +				        uint32		colour, borderColour;
  1.3268 +
  1.3269 +				        x = luaL_checkinteger(L, 1);
  1.3270 +				        y = luaL_checkinteger(L, 2);
  1.3271 +				        //msg = luaL_checkstring(L, 3);
  1.3272 +				        msg = toCString(L, 3);
  1.3273 +
  1.3274 +				        //	if (x < 0 || x >= LUA_SCREEN_WIDTH || y < 0 || y >= (LUA_SCREEN_HEIGHT - font_height))
  1.3275 +				        //		luaL_error(L,"bad coordinates");
  1.3276 +				        colour		 = gui_optcolour(L, 4, LUA_BUILD_PIXEL(255, 255, 255, 255));
  1.3277 +				        borderColour = gui_optcolour(L, 5, LUA_BUILD_PIXEL(255, 0, 0, 0));
  1.3278 +
  1.3279 +				        gui_prepare();
  1.3280 +
  1.3281 +				        LuaDisplayString(msg, y, x, colour, borderColour);
  1.3282 +
  1.3283 +				        return 0;
  1.3284 +					}
  1.3285 +
  1.3286 +// gui.gdoverlay([int dx=0, int dy=0,] string str [, sx=0, sy=0, sw, sh] [, float alphamul=1.0])
  1.3287 +//
  1.3288 +//  Overlays the given image on the screen.
  1.3289 +
  1.3290 +// example: gui.gdoverlay(gd.createFromPng("myimage.png"):gdStr())
  1.3291 +				    static int gui_gdoverlay(lua_State *L)
  1.3292 +				    {
  1.3293 +				        int argCount = lua_gettop(L);
  1.3294 +
  1.3295 +				        int xStartDst = 0;
  1.3296 +				        int yStartDst = 0;
  1.3297 +				        int xStartSrc = 0;
  1.3298 +				        int yStartSrc = 0;
  1.3299 +
  1.3300 +				        int index = 1;
  1.3301 +				        if (lua_type(L, index) == LUA_TNUMBER)
  1.3302 +				        {
  1.3303 +				            xStartDst = lua_tointeger(L, index++);
  1.3304 +				            if (lua_type(L, index) == LUA_TNUMBER)
  1.3305 +								yStartDst = lua_tointeger(L, index++);
  1.3306 +						}
  1.3307 +
  1.3308 +				        luaL_checktype(L, index, LUA_TSTRING);
  1.3309 +
  1.3310 +				        const unsigned char *ptr = (const unsigned char *)lua_tostring(L, index++);
  1.3311 +
  1.3312 +				        if (ptr[0] != 255 || (ptr[1] != 254 && ptr[1] != 255))
  1.3313 +							luaL_error(L, "bad image data");
  1.3314 +
  1.3315 +				        bool trueColor = (ptr[1] == 254);
  1.3316 +				        ptr += 2;
  1.3317 +
  1.3318 +				        int imgwidth = *ptr++ << 8;
  1.3319 +				        imgwidth |= *ptr++;
  1.3320 +
  1.3321 +				        int width	  = imgwidth;
  1.3322 +				        int imgheight = *ptr++ << 8;
  1.3323 +				        imgheight |= *ptr++;
  1.3324 +
  1.3325 +				        int height = imgheight;
  1.3326 +				        if ((!trueColor && *ptr) || (trueColor && !*ptr))
  1.3327 +							luaL_error(L, "bad image data");
  1.3328 +				        ptr++;
  1.3329 +
  1.3330 +				        int pitch = imgwidth * (trueColor ? 4 : 1);
  1.3331 +
  1.3332 +				        if ((argCount - index + 1) >= 4)
  1.3333 +				        {
  1.3334 +				            xStartSrc = luaL_checkinteger(L, index++);
  1.3335 +				            yStartSrc = luaL_checkinteger(L, index++);
  1.3336 +				            width	  = luaL_checkinteger(L, index++);
  1.3337 +				            height	  = luaL_checkinteger(L, index++);
  1.3338 +						}
  1.3339 +
  1.3340 +				        int alphaMul = transparencyModifier;
  1.3341 +				        if (lua_isnumber(L, index))
  1.3342 +							alphaMul = (int)(alphaMul * lua_tonumber(L, index++));
  1.3343 +				        if (alphaMul <= 0)
  1.3344 +							return 0;
  1.3345 +
  1.3346 +				        // since there aren't that many possible opacity levels,
  1.3347 +				        // do the opacity modification calculations beforehand instead of per pixel
  1.3348 +				        int opacMap[256];
  1.3349 +				        for (int i = 0; i < 128; i++)
  1.3350 +				        {
  1.3351 +				            int opac = 255 - ((i << 1) | (i & 1)); // gdAlphaMax = 127, not 255
  1.3352 +				            opac = (opac * alphaMul) / 255;
  1.3353 +				            if (opac < 0)
  1.3354 +								opac = 0;
  1.3355 +				            if (opac > 255)
  1.3356 +								opac = 255;
  1.3357 +				            opacMap[i] = opac;
  1.3358 +						}
  1.3359 +
  1.3360 +				        for (int i = 128; i < 256; i++)
  1.3361 +							opacMap[i] = 0;  // what should we do for them, actually?
  1.3362 +				        int colorsTotal = 0;
  1.3363 +				        if (!trueColor)
  1.3364 +				        {
  1.3365 +				            colorsTotal	 = *ptr++ << 8;
  1.3366 +				            colorsTotal |= *ptr++;
  1.3367 +						}
  1.3368 +
  1.3369 +				        int transparent = *ptr++ << 24;
  1.3370 +				        transparent |= *ptr++ << 16;
  1.3371 +				        transparent |= *ptr++ << 8;
  1.3372 +				        transparent |= *ptr++;
  1.3373 +				        struct
  1.3374 +				        {
  1.3375 +				            uint8 r, g, b, a;
  1.3376 +						} pal[256];
  1.3377 +				        if (!trueColor)
  1.3378 +							for (int i = 0; i < 256; i++)
  1.3379 +							{
  1.3380 +							    pal[i].r = *ptr++;
  1.3381 +							    pal[i].g = *ptr++;
  1.3382 +							    pal[i].b = *ptr++;
  1.3383 +							    pal[i].a = opacMap[*ptr++];
  1.3384 +							}
  1.3385 +
  1.3386 +				        // some of clippings
  1.3387 +				        if (xStartSrc < 0)
  1.3388 +				        {
  1.3389 +				            width	  += xStartSrc;
  1.3390 +				            xStartDst -= xStartSrc;
  1.3391 +				            xStartSrc  = 0;
  1.3392 +						}
  1.3393 +
  1.3394 +				        if (yStartSrc < 0)
  1.3395 +				        {
  1.3396 +				            height	  += yStartSrc;
  1.3397 +				            yStartDst -= yStartSrc;
  1.3398 +				            yStartSrc  = 0;
  1.3399 +						}
  1.3400 +
  1.3401 +				        if (xStartSrc + width >= imgwidth)
  1.3402 +							width = imgwidth - xStartSrc;
  1.3403 +				        if (yStartSrc + height >= imgheight)
  1.3404 +							height = imgheight - yStartSrc;
  1.3405 +				        if (xStartDst < 0)
  1.3406 +				        {
  1.3407 +				            width += xStartDst;
  1.3408 +				            if (width <= 0)
  1.3409 +								return 0;
  1.3410 +				            xStartSrc = -xStartDst;
  1.3411 +				            xStartDst = 0;
  1.3412 +						}
  1.3413 +
  1.3414 +				        if (yStartDst < 0)
  1.3415 +				        {
  1.3416 +				            height += yStartDst;
  1.3417 +				            if (height <= 0)
  1.3418 +								return 0;
  1.3419 +				            yStartSrc = -yStartDst;
  1.3420 +				            yStartDst = 0;
  1.3421 +						}
  1.3422 +
  1.3423 +				        if (xStartDst + width >= LUA_SCREEN_WIDTH)
  1.3424 +							width = LUA_SCREEN_WIDTH - xStartDst;
  1.3425 +				        if (yStartDst + height >= LUA_SCREEN_HEIGHT)
  1.3426 +							height = LUA_SCREEN_HEIGHT - yStartDst;
  1.3427 +				        if (width <= 0 || height <= 0)
  1.3428 +							return 0;  // out of screen or invalid size
  1.3429 +				        gui_prepare();
  1.3430 +
  1.3431 +				        const uint8 *pix = (const uint8 *)(&ptr[yStartSrc * pitch + (xStartSrc * (trueColor ? 4 : 1))]);
  1.3432 +				        int			 bytesToNextLine = pitch - (width * (trueColor ? 4 : 1));
  1.3433 +				        if (trueColor)
  1.3434 +				        {
  1.3435 +				            for (int y = yStartDst; y < height + yStartDst && y < LUA_SCREEN_HEIGHT; y++, pix += bytesToNextLine)
  1.3436 +				            {
  1.3437 +				                for (int x = xStartDst; x < width + xStartDst && x < LUA_SCREEN_WIDTH; x++, pix += 4)
  1.3438 +				                {
  1.3439 +				                    gui_drawpixel_fast(x, y, LUA_BUILD_PIXEL(opacMap[pix[0]], pix[1], pix[2], pix[3]));
  1.3440 +								}
  1.3441 +							}
  1.3442 +						}
  1.3443 +				        else
  1.3444 +				        {
  1.3445 +				            for (int y = yStartDst; y < height + yStartDst && y < LUA_SCREEN_HEIGHT; y++, pix += bytesToNextLine)
  1.3446 +				            {
  1.3447 +				                for (int x = xStartDst; x < width + xStartDst && x < LUA_SCREEN_WIDTH; x++, pix++)
  1.3448 +				                {
  1.3449 +				                    gui_drawpixel_fast(x, y, LUA_BUILD_PIXEL(pal[*pix].a, pal[*pix].r, pal[*pix].g, pal[*pix].b));
  1.3450 +								}
  1.3451 +							}
  1.3452 +						}
  1.3453 +
  1.3454 +				        return 0;
  1.3455 +					}
  1.3456 +
  1.3457 +// function gui.register(function f)
  1.3458 +//
  1.3459 +//  This function will be called just before a graphical update.
  1.3460 +//  More complicated, but doesn't suffer any frame delays.
  1.3461 +//  Nil will be accepted in place of a function to erase
  1.3462 +//  a previously registered function, and the previous function
  1.3463 +
  1.3464 +//  (if any) is returned, or nil if none.
  1.3465 +				    static int gui_register(lua_State *L)
  1.3466 +				    {
  1.3467 +				        // We'll do this straight up.
  1.3468 +				        // First set up the stack.
  1.3469 +				        lua_settop(L, 1);
  1.3470 +
  1.3471 +				        // Verify the validity of the entry
  1.3472 +				        if (!lua_isnil(L, 1))
  1.3473 +							luaL_checktype(L, 1, LUA_TFUNCTION);
  1.3474 +
  1.3475 +				        // Get the old value
  1.3476 +				        lua_getfield(L, LUA_REGISTRYINDEX, guiCallbackTable);
  1.3477 +
  1.3478 +				        // Save the new value
  1.3479 +				        lua_pushvalue(L, 1);
  1.3480 +				        lua_setfield(L, LUA_REGISTRYINDEX, guiCallbackTable);
  1.3481 +
  1.3482 +				        // The old value is on top of the stack. Return it.
  1.3483 +				        return 1;
  1.3484 +					}
  1.3485 +
  1.3486 +// string gui.popup(string message, [string type = "ok"])
  1.3487 +//
  1.3488 +
  1.3489 +//  Popup dialog!
  1.3490 +				    int gui_popup(lua_State *L)
  1.3491 +				    {
  1.3492 +				        const char *message = luaL_checkstring(L, 1);
  1.3493 +				        const char *type	= luaL_optstring(L, 2, "ok");
  1.3494 +
  1.3495 +#if (defined(WIN32) && !defined(SDL))
  1.3496 +				        int t;
  1.3497 +				        if (strcmp(type, "ok") == 0)
  1.3498 +							t = MB_OK;
  1.3499 +				        else if (strcmp(type, "yesno") == 0)
  1.3500 +							t = MB_YESNO;
  1.3501 +				        else if (strcmp(type, "yesnocancel") == 0)
  1.3502 +							t = MB_YESNOCANCEL;
  1.3503 +				        else
  1.3504 +							return luaL_error(L, "invalid popup type \"%s\"", type);
  1.3505 +
  1.3506 +				        theApp.winCheckFullscreen();
  1.3507 +				        systemSoundClearBuffer();
  1.3508 +				        int result = AfxGetApp()->m_pMainWnd->MessageBox(message, "Lua Script Pop-up", t);
  1.3509 +
  1.3510 +				        lua_settop(L, 1);
  1.3511 +
  1.3512 +				        if (t != MB_OK)
  1.3513 +				        {
  1.3514 +				            if (result == IDYES)
  1.3515 +								lua_pushstring(L, "yes");
  1.3516 +				            else if (result == IDNO)
  1.3517 +								lua_pushstring(L, "no");
  1.3518 +				            else if (result == IDCANCEL)
  1.3519 +								lua_pushstring(L, "cancel");
  1.3520 +				            else
  1.3521 +								luaL_error(L, "win32 unrecognized return value %d", result);
  1.3522 +				            return 1;
  1.3523 +						}
  1.3524 +
  1.3525 +				        // else, we don't care.
  1.3526 +				        return 0;
  1.3527 +#else
  1.3528 +				        char *t;
  1.3529 +	#ifdef __linux
  1.3530 +				        // The Linux backend has a "FromPause" variable.
  1.3531 +				        // If set to 1, assume some known external event has screwed with the flow of time.
  1.3532 +				        // Since this pauses the emulator waiting for a response, we set it to 1.
  1.3533 +// FIXME: Well, actually it doesn't
  1.3534 +//	extern int FromPause;
  1.3535 +//	FromPause = 1;
  1.3536 +
  1.3537 +				        int pid; // appease compiler
  1.3538 +
  1.3539 +				        // Before doing any work, verify the correctness of the parameters.
  1.3540 +				        if (strcmp(type, "ok") == 0)
  1.3541 +							t = "OK:100";
  1.3542 +				        else if (strcmp(type, "yesno") == 0)
  1.3543 +							t = "Yes:100,No:101";
  1.3544 +				        else if (strcmp(type, "yesnocancel") == 0)
  1.3545 +							t = "Yes:100,No:101,Cancel:102";
  1.3546 +				        else
  1.3547 +							return luaL_error(L, "invalid popup type \"%s\"", type);
  1.3548 +
  1.3549 +				        // Can we find a copy of xmessage? Search the path.
  1.3550 +				        char *path = strdup(getenv("PATH"));
  1.3551 +
  1.3552 +				        char *current = path;
  1.3553 +
  1.3554 +				        char *colon;
  1.3555 +
  1.3556 +				        int found = 0;
  1.3557 +
  1.3558 +				        while (current)
  1.3559 +				        {
  1.3560 +				            colon = strchr(current, ':');
  1.3561 +
  1.3562 +				            // Clip off the colon.
  1.3563 +				            *colon++ = 0;
  1.3564 +
  1.3565 +				            int	  len	   = strlen(current);
  1.3566 +				            char *filename = (char *)malloc(len + 12); // always give excess
  1.3567 +				            snprintf(filename, len + 12, "%s/xmessage", current);
  1.3568 +
  1.3569 +				            if (access(filename, X_OK) == 0)
  1.3570 +				            {
  1.3571 +				                free(filename);
  1.3572 +				                found = 1;
  1.3573 +				                break;
  1.3574 +							}
  1.3575 +
  1.3576 +				            // Failed, move on.
  1.3577 +				            current = colon;
  1.3578 +				            free(filename);
  1.3579 +						}
  1.3580 +
  1.3581 +				        free(path);
  1.3582 +
  1.3583 +				        // We've found it?
  1.3584 +				        if (!found)
  1.3585 +							goto use_console;
  1.3586 +
  1.3587 +				        pid = fork();
  1.3588 +				        if (pid == 0)
  1.3589 +				        { // I'm the virgin sacrifice
  1.3590 +				          // I'm gonna be dead in a matter of microseconds anyways, so wasted memory doesn't matter to me.
  1.3591 +				          // Go ahead and abuse strdup.
  1.3592 +				            char *parameters[] = { "xmessage", "-buttons", t, strdup(message), NULL };
  1.3593 +
  1.3594 +				            execvp("xmessage", parameters);
  1.3595 +
  1.3596 +				            // Aw shitty
  1.3597 +				            perror("exec xmessage");
  1.3598 +				            exit(1);
  1.3599 +						}
  1.3600 +				        else if (pid < 0) // something went wrong!!! Oh hell... use the console
  1.3601 +							goto use_console;
  1.3602 +				        else
  1.3603 +				        {
  1.3604 +				            // We're the parent. Watch for the child.
  1.3605 +				            int r;
  1.3606 +				            int res = waitpid(pid, &r, 0);
  1.3607 +				            if (res < 0) // wtf?
  1.3608 +								goto use_console;
  1.3609 +
  1.3610 +				            // The return value gets copmlicated...
  1.3611 +				            if (!WIFEXITED(r))
  1.3612 +				            {
  1.3613 +				                luaL_error(L, "don't screw with my xmessage process!");
  1.3614 +							}
  1.3615 +
  1.3616 +				            r = WEXITSTATUS(r);
  1.3617 +
  1.3618 +				            // We assume it's worked.
  1.3619 +				            if (r == 0)
  1.3620 +				            {
  1.3621 +				                return 0; // no parameters for an OK
  1.3622 +							}
  1.3623 +
  1.3624 +				            if (r == 100)
  1.3625 +				            {
  1.3626 +				                lua_pushstring(L, "yes");
  1.3627 +				                return 1;
  1.3628 +							}
  1.3629 +
  1.3630 +				            if (r == 101)
  1.3631 +				            {
  1.3632 +				                lua_pushstring(L, "no");
  1.3633 +				                return 1;
  1.3634 +							}
  1.3635 +
  1.3636 +				            if (r == 102)
  1.3637 +				            {
  1.3638 +				                lua_pushstring(L, "cancel");
  1.3639 +				                return 1;
  1.3640 +							}
  1.3641 +
  1.3642 +				            // Wtf?
  1.3643 +				            return luaL_error(L, "popup failed due to unknown results involving xmessage (%d)", r);
  1.3644 +						}
  1.3645 +
  1.3646 +use_console:
  1.3647 +	#endif
  1.3648 +
  1.3649 +				        // All else has failed
  1.3650 +				        if (strcmp(type, "ok") == 0)
  1.3651 +							t = "";
  1.3652 +				        else if (strcmp(type, "yesno") == 0)
  1.3653 +							t = "yn";
  1.3654 +				        else if (strcmp(type, "yesnocancel") == 0)
  1.3655 +							t = "ync";
  1.3656 +				        else
  1.3657 +							return luaL_error(L, "invalid popup type \"%s\"", type);
  1.3658 +
  1.3659 +				        fprintf(stderr, "Lua Message: %s\n", message);
  1.3660 +
  1.3661 +				        while (true)
  1.3662 +				        {
  1.3663 +				            char buffer[64];
  1.3664 +
  1.3665 +				            // We don't want parameters
  1.3666 +				            if (!t[0])
  1.3667 +				            {
  1.3668 +				                fprintf(stderr, "[Press Enter]");
  1.3669 +				                fgets(buffer, sizeof(buffer), stdin);
  1.3670 +
  1.3671 +				                // We're done
  1.3672 +				                return 0;
  1.3673 +							}
  1.3674 +
  1.3675 +				            fprintf(stderr, "(%s): ", t);
  1.3676 +				            fgets(buffer, sizeof(buffer), stdin);
  1.3677 +
  1.3678 +				            // Check if the option is in the list
  1.3679 +				            if (strchr(t, tolower(buffer[0])))
  1.3680 +				            {
  1.3681 +				                switch (tolower(buffer[0]))
  1.3682 +				                {
  1.3683 +								case 'y':
  1.3684 +									lua_pushstring(L, "yes");
  1.3685 +									return 1;
  1.3686 +								case 'n':
  1.3687 +									lua_pushstring(L, "no");
  1.3688 +									return 1;
  1.3689 +								case 'c':
  1.3690 +									lua_pushstring(L, "cancel");
  1.3691 +									return 1;
  1.3692 +								default:
  1.3693 +									luaL_error(L, "internal logic error in console based prompts for gui.popup");
  1.3694 +								}
  1.3695 +							}
  1.3696 +
  1.3697 +				            // We fell through, so we assume the user answered wrong and prompt again.
  1.3698 +						}
  1.3699 +
  1.3700 +				        // Nothing here, since the only way out is in the loop.
  1.3701 +#endif
  1.3702 +					}
  1.3703 +
  1.3704 +#if (defined(WIN32) && !defined(SDL))
  1.3705 +				    const char  *s_keyToName[256] =
  1.3706 +				    {
  1.3707 +				        NULL,
  1.3708 +				        "leftclick",
  1.3709 +				        "rightclick",
  1.3710 +				        NULL,
  1.3711 +				        "middleclick",
  1.3712 +				        NULL,
  1.3713 +				        NULL,
  1.3714 +				        NULL,
  1.3715 +				        "backspace",
  1.3716 +				        "tab",
  1.3717 +				        NULL,
  1.3718 +				        NULL,
  1.3719 +				        NULL,
  1.3720 +				        "enter",
  1.3721 +				        NULL,
  1.3722 +				        NULL,
  1.3723 +				        "shift",       // 0x10
  1.3724 +				        "control",
  1.3725 +				        "alt",
  1.3726 +				        "pause",
  1.3727 +				        "capslock",
  1.3728 +				        NULL,
  1.3729 +				        NULL,
  1.3730 +				        NULL,
  1.3731 +				        NULL,
  1.3732 +				        NULL,
  1.3733 +				        NULL,
  1.3734 +				        "escape",
  1.3735 +				        NULL,
  1.3736 +				        NULL,
  1.3737 +				        NULL,
  1.3738 +				        NULL,
  1.3739 +				        "space",       // 0x20
  1.3740 +				        "pageup",
  1.3741 +				        "pagedown",
  1.3742 +				        "end",
  1.3743 +				        "home",
  1.3744 +				        "left",
  1.3745 +				        "up",
  1.3746 +				        "right",
  1.3747 +				        "down",
  1.3748 +				        NULL,
  1.3749 +				        NULL,
  1.3750 +				        NULL,
  1.3751 +				        NULL,
  1.3752 +				        "insert",
  1.3753 +				        "delete",
  1.3754 +				        NULL,
  1.3755 +				        "0",		   "1",			   "2",			   "3",			   "4",		   "5",		  "6",		 "7",		"8",	   "9",
  1.3756 +				        NULL,		   NULL,		   NULL,		   NULL,		   NULL,	   NULL,	  NULL,
  1.3757 +				        "A",		   "B",			   "C",			   "D",			   "E",		   "F",		  "G",		 "H",		"I",	   "J",
  1.3758 +				        "K",		   "L",			   "M",			   "N",			   "O",		   "P",		  "Q",		 "R",		"S",	   "T",
  1.3759 +				        "U",		   "V",			   "W",			   "X",			   "Y",		   "Z",
  1.3760 +				        NULL,
  1.3761 +				        NULL,
  1.3762 +				        NULL,
  1.3763 +				        NULL,
  1.3764 +				        NULL,
  1.3765 +				        "numpad0",	   "numpad1",	   "numpad2",	   "numpad3",	   "numpad4",  "numpad5", "numpad6", "numpad7", "numpad8", "numpad9",
  1.3766 +				        "numpad*",	   "numpad+",
  1.3767 +				        NULL,
  1.3768 +				        "numpad-",	   "numpad.",	   "numpad/",
  1.3769 +				        "F1",		   "F2",		   "F3",		   "F4",		   "F5",	   "F6",	  "F7",		 "F8",		"F9",	   "F10",	  "F11",
  1.3770 +				        "F12",
  1.3771 +				        "F13",		   "F14",		   "F15",		   "F16",		   "F17",	   "F18",	  "F19",	 "F20",		"F21",	   "F22",	  "F23",
  1.3772 +				        "F24",
  1.3773 +				        NULL,
  1.3774 +				        NULL,
  1.3775 +				        NULL,
  1.3776 +				        NULL,
  1.3777 +				        NULL,
  1.3778 +				        NULL,
  1.3779 +				        NULL,
  1.3780 +				        NULL,
  1.3781 +				        "numlock",
  1.3782 +				        "scrolllock",
  1.3783 +				        NULL,          // 0x92
  1.3784 +				        NULL,		   NULL,		   NULL,		   NULL,		   NULL,	   NULL,	  NULL,		 NULL,		NULL,	   NULL,	  NULL,
  1.3785 +				        NULL,		   NULL,		   NULL,		   NULL,		   NULL,	   NULL,	  NULL,		 NULL,		NULL,	   NULL,
  1.3786 +				        NULL,		   NULL,		   NULL,		   NULL,		   NULL,	   NULL,	  NULL,		 NULL,		NULL,
  1.3787 +				        NULL,		   NULL,		   NULL,		   NULL,		   NULL,	   NULL,	  NULL,		 NULL,
  1.3788 +				        NULL,          // 0xB9
  1.3789 +				        "semicolon",
  1.3790 +				        "plus",
  1.3791 +				        "comma",
  1.3792 +				        "minus",
  1.3793 +				        "period",
  1.3794 +				        "slash",
  1.3795 +				        "tilde",
  1.3796 +				        NULL,          // 0xC1
  1.3797 +				        NULL,		   NULL,		   NULL,		   NULL,		   NULL,	   NULL,	  NULL,		 NULL,		NULL,
  1.3798 +				        NULL,		   NULL,		   NULL,		   NULL,		   NULL,	   NULL,	  NULL,		 NULL,
  1.3799 +				        NULL,		   NULL,		   NULL,		   NULL,		   NULL,	   NULL,	  NULL,
  1.3800 +				        NULL,          // 0xDA
  1.3801 +				        "leftbracket",
  1.3802 +				        "backslash",
  1.3803 +				        "rightbracket",
  1.3804 +				        "quote",
  1.3805 +					};
  1.3806 +#endif
  1.3807 +
  1.3808 +// input.get()
  1.3809 +// takes no input, returns a lua table of entries representing the current input state,
  1.3810 +// independent of the joypad buttons the emulated game thinks are pressed
  1.3811 +// for example:
  1.3812 +//   if the user is holding the W key and the left mouse button
  1.3813 +//   and has the mouse at the bottom-right corner of the game screen,
  1.3814 +
  1.3815 +//   then this would return {W=true, leftclick=true, xmouse=255, ymouse=223}
  1.3816 +				    static int input_getcurrentinputstatus(lua_State *L)
  1.3817 +				    {
  1.3818 +				        lua_newtable(L);
  1.3819 +
  1.3820 +#if (defined(WIN32) && !defined(SDL))
  1.3821 +				        // keyboard and mouse button status
  1.3822 +				        {
  1.3823 +				            unsigned char keys[256];
  1.3824 +				            if (true /*!GUI.BackgroundInput*/) // TODO: background input
  1.3825 +				            {
  1.3826 +				                if (GetKeyboardState(keys))
  1.3827 +				                {
  1.3828 +				                    for (int i = 1; i < 255; i++)
  1.3829 +				                    {
  1.3830 +				                        int mask = (i == VK_CAPITAL || i == VK_NUMLOCK || i == VK_SCROLL) ? 0x01 : 0x80;
  1.3831 +				                        if (keys[i] & mask)
  1.3832 +				                        {
  1.3833 +				                            const char *name = s_keyToName[i];
  1.3834 +				                            if (name)
  1.3835 +				                            {
  1.3836 +				                                lua_pushboolean(L, true);
  1.3837 +				                                lua_setfield(L, -2, name);
  1.3838 +											}
  1.3839 +										}
  1.3840 +									}
  1.3841 +								}
  1.3842 +							}
  1.3843 +				            else // use a slightly different method that will detect background input:
  1.3844 +				            {
  1.3845 +				                for (int i = 1; i < 255; i++)
  1.3846 +				                {
  1.3847 +				                    const char *name = s_keyToName[i];
  1.3848 +				                    if (name)
  1.3849 +				                    {
  1.3850 +				                        int active;
  1.3851 +				                        if (i == VK_CAPITAL || i == VK_NUMLOCK || i == VK_SCROLL)
  1.3852 +											active = GetKeyState(i) & 0x01;
  1.3853 +				                        else
  1.3854 +											active = GetAsyncKeyState(i) & 0x8000;
  1.3855 +				                        if (active)
  1.3856 +				                        {
  1.3857 +				                            lua_pushboolean(L, true);
  1.3858 +				                            lua_setfield(L, -2, name);
  1.3859 +										}
  1.3860 +									}
  1.3861 +								}
  1.3862 +							}
  1.3863 +						}
  1.3864 +
  1.3865 +				        // mouse position in game screen pixel coordinates
  1.3866 +				        {
  1.3867 +				            POINT mouse;
  1.3868 +
  1.3869 +				            int xofs = 0, yofs = 0, width = 240, height = 160;
  1.3870 +				            if (!systemIsRunningGBA())
  1.3871 +				            {
  1.3872 +				                if (gbBorderOn)
  1.3873 +									width = 256, height = 224, xofs = 48, yofs = 40;
  1.3874 +				                else
  1.3875 +									width = 160, height = 144;
  1.3876 +							}
  1.3877 +
  1.3878 +				            GetCursorPos(&mouse);
  1.3879 +				            AfxGetApp()->m_pMainWnd->ScreenToClient(&mouse);
  1.3880 +
  1.3881 +				            // game screen is always fully stretched to window size,
  1.3882 +				            // with no aspect rate correction, or something like that.
  1.3883 +				            RECT clientRect;
  1.3884 +				            AfxGetApp()->m_pMainWnd->GetClientRect(&clientRect);
  1.3885 +
  1.3886 +				            int wndWidth  = clientRect.right - clientRect.left;
  1.3887 +				            int wndHeight = clientRect.bottom - clientRect.top;
  1.3888 +				            mouse.x = (LONG) (mouse.x * ((float)width / wndWidth)) - xofs;
  1.3889 +				            mouse.y = (LONG) (mouse.y * ((float)height / wndHeight)) - yofs;
  1.3890 +
  1.3891 +				            lua_pushinteger(L, mouse.x);
  1.3892 +				            lua_setfield(L, -2, "xmouse");
  1.3893 +				            lua_pushinteger(L, mouse.y);
  1.3894 +				            lua_setfield(L, -2, "ymouse");
  1.3895 +						}
  1.3896 +
  1.3897 +#else
  1.3898 +				        // NYI (well, return an empty table)
  1.3899 +#endif
  1.3900 +				        return 1;
  1.3901 +					}
  1.3902 +
  1.3903 +				    static int avi_framecount(lua_State *L)
  1.3904 +				    {
  1.3905 +	#ifdef WIN32
  1.3906 +				        if (theApp.aviRecorder != NULL)
  1.3907 +				        {
  1.3908 +				            lua_pushinteger(L, theApp.aviRecorder->videoFrames());
  1.3909 +						}
  1.3910 +				        else
  1.3911 +	#endif
  1.3912 +				        {
  1.3913 +				            lua_pushinteger(L, 0);
  1.3914 +						}
  1.3915 +				        return 1;
  1.3916 +					}
  1.3917 +
  1.3918 +				    static int avi_pause(lua_State *L)
  1.3919 +				    {
  1.3920 +	#ifdef WIN32
  1.3921 +				        if (theApp.aviRecorder != NULL)
  1.3922 +							theApp.aviRecorder->Pause(true);
  1.3923 +	#endif
  1.3924 +				        return 1;
  1.3925 +					}
  1.3926 +
  1.3927 +				    static int avi_resume(lua_State *L)
  1.3928 +				    {
  1.3929 +	#ifdef WIN32
  1.3930 +				        if (theApp.aviRecorder != NULL)
  1.3931 +							theApp.aviRecorder->Pause(false);
  1.3932 +	#endif
  1.3933 +				        return 1;
  1.3934 +					}
  1.3935 +
  1.3936 +					static int sound_get(lua_State *L)
  1.3937 +					{
  1.3938 +						extern int32 soundLevel1;
  1.3939 +						extern int32 soundLevel2;
  1.3940 +						extern int32 soundBalance;
  1.3941 +						extern int32 soundMasterOn;
  1.3942 +						extern int32 soundVIN;
  1.3943 +						extern int32 sound1On;
  1.3944 +						extern int32 sound1EnvelopeVolume;
  1.3945 +						extern int32 sound2On;
  1.3946 +						extern int32 sound2EnvelopeVolume;
  1.3947 +						extern int32 sound3On;
  1.3948 +						extern int32 sound3OutputLevel;
  1.3949 +						extern int32 sound3Bank;
  1.3950 +						extern int32 sound3DataSize;
  1.3951 +						extern int32 sound3ForcedOutput;
  1.3952 +						extern int32 sound4On;
  1.3953 +						extern int32 sound4EnvelopeVolume;
  1.3954 +						extern u8 sound3WaveRam[0x20];
  1.3955 +
  1.3956 +						int freqReg;
  1.3957 +						double freq;
  1.3958 +						double leftvolscale;
  1.3959 +						double rightvolscale;
  1.3960 +						double panpot;
  1.3961 +						bool gba = systemIsRunningGBA();
  1.3962 +						u8* gbMem = gba ? ioMem : gbMemory;
  1.3963 +						const int rNR10 = gba ? 0x60 : 0xff10;
  1.3964 +						const int rNR11 = gba ? 0x62 : 0xff11;
  1.3965 +						const int rNR12 = gba ? 0x63 : 0xff12;
  1.3966 +						const int rNR13 = gba ? 0x64 : 0xff13;
  1.3967 +						const int rNR14 = gba ? 0x65 : 0xff14;
  1.3968 +						const int rNR21 = gba ? 0x68 : 0xff16;
  1.3969 +						const int rNR22 = gba ? 0x69 : 0xff17;
  1.3970 +						const int rNR23 = gba ? 0x6c : 0xff18;
  1.3971 +						const int rNR24 = gba ? 0x6d : 0xff19;
  1.3972 +						const int rNR30 = gba ? 0x70 : 0xff1a;
  1.3973 +						const int rNR31 = gba ? 0x72 : 0xff1b;
  1.3974 +						const int rNR32 = gba ? 0x73 : 0xff1c;
  1.3975 +						const int rNR33 = gba ? 0x74 : 0xff1d;
  1.3976 +						const int rNR34 = gba ? 0x75 : 0xff1e;
  1.3977 +						const int rNR41 = gba ? 0x78 : 0xff20;
  1.3978 +						const int rNR42 = gba ? 0x79 : 0xff21;
  1.3979 +						const int rNR43 = gba ? 0x7c : 0xff22;
  1.3980 +						const int rNR44 = gba ? 0x7d : 0xff23;
  1.3981 +						const int rNR50 = gba ? 0x80 : 0xff24;
  1.3982 +						const int rNR51 = gba ? 0x81 : 0xff25;
  1.3983 +						const int rNR52 = gba ? 0x84 : 0xff26;
  1.3984 +						const int rWAVE_RAM = gba ? 0x90 : 0xff30;
  1.3985 +
  1.3986 +						const int32 _soundVIN = 0x88; // gba ? 0x88 : soundVIN;
  1.3987 +						const bool soundVINLeft = ((_soundVIN & 0x80) != 0);
  1.3988 +						const bool soundVINRight = ((_soundVIN & 0x08) != 0);
  1.3989 +
  1.3990 +						lua_newtable(L);
  1.3991 +
  1.3992 +						// square1
  1.3993 +						lua_newtable(L);
  1.3994 +						if(sound1On == 0 || soundMasterOn == 0)
  1.3995 +						{
  1.3996 +							lua_pushnumber(L, 0.0);
  1.3997 +							panpot = 0.5;
  1.3998 +						}
  1.3999 +						else
  1.4000 +						{
  1.4001 +							double envVolume = sound1EnvelopeVolume / 15.0;
  1.4002 +							if (soundVINLeft && (soundBalance & 0x10) != 0)
  1.4003 +								leftvolscale = ((soundLevel2 / 7.0) * envVolume);
  1.4004 +							else
  1.4005 +								leftvolscale = 0.0;
  1.4006 +							if (soundVINRight && (soundBalance & 0x01) != 0)
  1.4007 +								rightvolscale = ((soundLevel1 / 7.0) * envVolume);
  1.4008 +							else
  1.4009 +								rightvolscale = 0.0;
  1.4010 +							if ((leftvolscale + rightvolscale) != 0)
  1.4011 +								panpot = rightvolscale / (leftvolscale + rightvolscale);
  1.4012 +							else
  1.4013 +								panpot = 0.5;
  1.4014 +							lua_pushnumber(L, (leftvolscale + rightvolscale) / 2.0);
  1.4015 +						}
  1.4016 +						lua_setfield(L, -2, "volume");
  1.4017 +						lua_pushnumber(L, panpot);
  1.4018 +						lua_setfield(L, -2, "panpot");
  1.4019 +						freqReg = (((int)(gbMem[rNR14] & 7) << 8) | gbMem[rNR13]);
  1.4020 +						freq = 131072.0 / (2048 - freqReg);
  1.4021 +						lua_pushnumber(L, freq);
  1.4022 +						lua_setfield(L, -2, "frequency");
  1.4023 +						lua_pushnumber(L, (log(freq / 440.0) * 12 / log(2.0)) + 69);
  1.4024 +						lua_setfield(L, -2, "midikey");
  1.4025 +						lua_pushinteger(L, (gbMem[rNR11] & 0xC0) >> 6);
  1.4026 +						lua_setfield(L, -2, "duty");
  1.4027 +						lua_newtable(L);
  1.4028 +						lua_pushinteger(L, freqReg);
  1.4029 +						lua_setfield(L, -2, "frequency");
  1.4030 +						lua_setfield(L, -2, "regs");
  1.4031 +						lua_setfield(L, -2, "square1");
  1.4032 +						// square2
  1.4033 +						lua_newtable(L);
  1.4034 +						if(sound2On == 0 || soundMasterOn == 0)
  1.4035 +						{
  1.4036 +							lua_pushnumber(L, 0.0);
  1.4037 +							panpot = 0.5;
  1.4038 +						}
  1.4039 +						else
  1.4040 +						{
  1.4041 +							double envVolume = sound2EnvelopeVolume / 15.0;
  1.4042 +							if (soundVINLeft && (soundBalance & 0x20) != 0)
  1.4043 +								leftvolscale = ((soundLevel2 / 7.0) * envVolume);
  1.4044 +							else
  1.4045 +								leftvolscale = 0.0;
  1.4046 +							if (soundVINRight && (soundBalance & 0x02) != 0)
  1.4047 +								rightvolscale = ((soundLevel1 / 7.0) * envVolume);
  1.4048 +							else
  1.4049 +								rightvolscale = 0.0;
  1.4050 +							if ((leftvolscale + rightvolscale) != 0)
  1.4051 +								panpot = rightvolscale / (leftvolscale + rightvolscale);
  1.4052 +							else
  1.4053 +								panpot = 0.5;
  1.4054 +							lua_pushnumber(L, (leftvolscale + rightvolscale) / 2.0);
  1.4055 +						}
  1.4056 +						lua_setfield(L, -2, "volume");
  1.4057 +						lua_pushnumber(L, panpot);
  1.4058 +						lua_setfield(L, -2, "panpot");
  1.4059 +						freqReg = (((int)(gbMem[rNR24] & 7) << 8) | gbMem[rNR23]);
  1.4060 +						freq = 131072.0 / (2048 - freqReg);
  1.4061 +						lua_pushnumber(L, freq);
  1.4062 +						lua_setfield(L, -2, "frequency");
  1.4063 +						lua_pushnumber(L, (log(freq / 440.0) * 12 / log(2.0)) + 69);
  1.4064 +						lua_setfield(L, -2, "midikey");
  1.4065 +						lua_pushinteger(L, (gbMem[rNR21] & 0xC0) >> 6);
  1.4066 +						lua_setfield(L, -2, "duty");
  1.4067 +						lua_newtable(L);
  1.4068 +						lua_pushinteger(L, freqReg);
  1.4069 +						lua_setfield(L, -2, "frequency");
  1.4070 +						lua_setfield(L, -2, "regs");
  1.4071 +						lua_setfield(L, -2, "square2");
  1.4072 +						// wavememory
  1.4073 +						lua_newtable(L);
  1.4074 +						if(sound3On == 0 || soundMasterOn == 0)
  1.4075 +						{
  1.4076 +							lua_pushnumber(L, 0.0);
  1.4077 +							panpot = 0.5;
  1.4078 +						}
  1.4079 +						else
  1.4080 +						{
  1.4081 +							double envVolume;
  1.4082 +							if (gba && sound3ForcedOutput != 0)
  1.4083 +								envVolume = 0.75;
  1.4084 +							else
  1.4085 +							{
  1.4086 +								double volTable[4] = { 0.0, 1.0, 0.5, 0.25 };
  1.4087 +								envVolume = volTable[sound3OutputLevel & 3];
  1.4088 +							}
  1.4089 +
  1.4090 +							if (soundVINLeft && (soundBalance & 0x40) != 0)
  1.4091 +								leftvolscale = ((soundLevel2 / 7.0) * envVolume);
  1.4092 +							else
  1.4093 +								leftvolscale = 0.0;
  1.4094 +							if (soundVINRight && (soundBalance & 0x04) != 0)
  1.4095 +								rightvolscale = ((soundLevel1 / 7.0) * envVolume);
  1.4096 +							else
  1.4097 +								rightvolscale = 0.0;
  1.4098 +							if ((leftvolscale + rightvolscale) != 0)
  1.4099 +								panpot = rightvolscale / (leftvolscale + rightvolscale);
  1.4100 +							else
  1.4101 +								panpot = 0.5;
  1.4102 +							lua_pushnumber(L, (leftvolscale + rightvolscale) / 2.0);
  1.4103 +						}
  1.4104 +						lua_setfield(L, -2, "volume");
  1.4105 +						lua_pushnumber(L, panpot);
  1.4106 +						lua_setfield(L, -2, "panpot");
  1.4107 +						int waveMemSamples = 32;
  1.4108 +						if (gba)
  1.4109 +						{
  1.4110 +							lua_pushlstring(L, (const char *) &sound3WaveRam[sound3Bank * 0x10], sound3DataSize ? 0x20 : 0x10);
  1.4111 +							waveMemSamples = sound3DataSize ? 64 : 32;
  1.4112 +						}
  1.4113 +						else
  1.4114 +						{
  1.4115 +							lua_pushlstring(L, (const char *) &gbMem[rWAVE_RAM], 0x10);
  1.4116 +						}
  1.4117 +						lua_setfield(L, -2, "waveform");
  1.4118 +						freqReg = (((int)(gbMem[rNR34] & 7) << 8) | gbMem[rNR33]);
  1.4119 +						freq = 2097152.0 / (waveMemSamples * (2048 - freqReg));
  1.4120 +						lua_pushnumber(L, freq);
  1.4121 +						lua_setfield(L, -2, "frequency");
  1.4122 +						lua_pushnumber(L, (log(freq / 440.0) * 12 / log(2.0)) + 69);
  1.4123 +						lua_setfield(L, -2, "midikey");
  1.4124 +						lua_newtable(L);
  1.4125 +						lua_pushinteger(L, freqReg);
  1.4126 +						lua_setfield(L, -2, "frequency");
  1.4127 +						lua_setfield(L, -2, "regs");
  1.4128 +						lua_setfield(L, -2, "wavememory");
  1.4129 +						// noise
  1.4130 +						lua_newtable(L);
  1.4131 +						if(sound4On == 0 || soundMasterOn == 0)
  1.4132 +						{
  1.4133 +							lua_pushnumber(L, 0.0);
  1.4134 +							panpot = 0.5;
  1.4135 +						}
  1.4136 +						else
  1.4137 +						{
  1.4138 +							double envVolume = sound4EnvelopeVolume / 15.0;
  1.4139 +							if (soundVINLeft && (soundBalance & 0x80) != 0)
  1.4140 +								leftvolscale = ((soundLevel2 / 7.0) * envVolume);
  1.4141 +							else
  1.4142 +								leftvolscale = 0.0;
  1.4143 +							if (soundVINRight && (soundBalance & 0x08) != 0)
  1.4144 +								rightvolscale = ((soundLevel1 / 7.0) * envVolume);
  1.4145 +							else
  1.4146 +								rightvolscale = 0.0;
  1.4147 +							if ((leftvolscale + rightvolscale) != 0)
  1.4148 +								panpot = rightvolscale / (leftvolscale + rightvolscale);
  1.4149 +							else
  1.4150 +								panpot = 0.5;
  1.4151 +							lua_pushnumber(L, (leftvolscale + rightvolscale) / 2.0);
  1.4152 +						}
  1.4153 +						lua_setfield(L, -2, "volume");
  1.4154 +						lua_pushnumber(L, panpot);
  1.4155 +						lua_setfield(L, -2, "panpot");
  1.4156 +						const int gbNoiseFreqTable[8] = { 1, 2, 4, 6, 8, 10, 12, 14 };
  1.4157 +						freqReg = gbNoiseFreqTable[gbMem[rNR43] & 7] << (1 + (gbMem[rNR43] >> 4));
  1.4158 +						lua_pushboolean(L, (gbMem[rNR43] & 8) != 0);
  1.4159 +						lua_setfield(L, -2, "short");
  1.4160 +						freq = 1048576.0 / freqReg;
  1.4161 +						lua_pushnumber(L, freq);
  1.4162 +						lua_setfield(L, -2, "frequency");
  1.4163 +						lua_pushnumber(L, (log(freq / 440.0) * 12 / log(2.0)) + 69);
  1.4164 +						lua_setfield(L, -2, "midikey");
  1.4165 +						lua_newtable(L);
  1.4166 +						lua_pushinteger(L, freqReg);
  1.4167 +						lua_setfield(L, -2, "frequency");
  1.4168 +						lua_setfield(L, -2, "regs");
  1.4169 +						lua_setfield(L, -2, "noise");
  1.4170 +
  1.4171 +						return 1;
  1.4172 +					}
  1.4173 +
  1.4174 +// same as math.random, but uses SFMT instead of C rand()
  1.4175 +// FIXME: this function doesn't care multi-instance,
  1.4176 +
  1.4177 +//        original math.random either though (Lua 5.1)
  1.4178 +				    static int sfmt_random(lua_State *L)
  1.4179 +				    {
  1.4180 +				        lua_Number r = (lua_Number) genrand_real2();
  1.4181 +				        switch (lua_gettop(L))
  1.4182 +				        { // check number of arguments
  1.4183 +						case 0:
  1.4184 +							{ // no arguments
  1.4185 +							    lua_pushnumber(L, r); // Number between 0 and 1
  1.4186 +							    break;
  1.4187 +							}
  1.4188 +
  1.4189 +						case 1:
  1.4190 +							{ // only upper limit
  1.4191 +							    int u = luaL_checkint(L, 1);
  1.4192 +							    luaL_argcheck(L, 1 <= u, 1, "interval is empty");
  1.4193 +							    lua_pushnumber(L, floor(r * u) + 1); // int between 1 and `u'
  1.4194 +							    break;
  1.4195 +							}
  1.4196 +
  1.4197 +						case 2:
  1.4198 +							{ // lower and upper limits
  1.4199 +							    int l = luaL_checkint(L, 1);
  1.4200 +							    int u = luaL_checkint(L, 2);
  1.4201 +							    luaL_argcheck(L, l <= u, 2, "interval is empty");
  1.4202 +							    lua_pushnumber(L, floor(r * (u - l + 1)) + l); // int between `l' and `u'
  1.4203 +							    break;
  1.4204 +							}
  1.4205 +
  1.4206 +						default:
  1.4207 +							return luaL_error(L, "wrong number of arguments");
  1.4208 +						}
  1.4209 +
  1.4210 +				        return 1;
  1.4211 +					}
  1.4212 +
  1.4213 +// same as math.randomseed, but uses SFMT instead of C srand()
  1.4214 +// FIXME: this function doesn't care multi-instance,
  1.4215 +
  1.4216 +//        original math.randomseed either though (Lua 5.1)
  1.4217 +				    static int sfmt_randomseed(lua_State *L)
  1.4218 +				    {
  1.4219 +				        init_gen_rand(luaL_checkint(L, 1));
  1.4220 +				        return 0;
  1.4221 +					}
  1.4222 +
  1.4223 +// the following bit operations are ported from LuaBitOp 1.0.1,
  1.4224 +// because it can handle the sign bit (bit 31) correctly.
  1.4225 +
  1.4226 +/*
  1.4227 +** Lua BitOp -- a bit operations library for Lua 5.1.
  1.4228 +** http://bitop.luajit.org/
  1.4229 +**
  1.4230 +** Copyright (C) 2008-2009 Mike Pall. All rights reserved.
  1.4231 +**
  1.4232 +** Permission is hereby granted, free of charge, to any person obtaining
  1.4233 +** a copy of this software and associated documentation files (the
  1.4234 +** "Software"), to deal in the Software without restriction, including
  1.4235 +** without limitation the rights to use, copy, modify, merge, publish,
  1.4236 +** distribute, sublicense, and/or sell copies of the Software, and to
  1.4237 +** permit persons to whom the Software is furnished to do so, subject to
  1.4238 +** the following conditions:
  1.4239 +**
  1.4240 +** The above copyright notice and this permission notice shall be
  1.4241 +** included in all copies or substantial portions of the Software.
  1.4242 +**
  1.4243 +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  1.4244 +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  1.4245 +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  1.4246 +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
  1.4247 +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  1.4248 +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  1.4249 +** SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  1.4250 +**
  1.4251 +** [ MIT license: http://www.opensource.org/licenses/mit-license.php ]
  1.4252 +*/
  1.4253 +
  1.4254 +#ifdef _MSC_VER
  1.4255 +/* MSVC is stuck in the last century and doesn't have C99's stdint.h. */
  1.4256 +				    typedef __int32			 int32_t;
  1.4257 +				    typedef unsigned __int32 uint32_t;
  1.4258 +				    typedef unsigned __int64 uint64_t;
  1.4259 +#else
  1.4260 +#include <stdint.h>
  1.4261 +#endif
  1.4262 +
  1.4263 +				    typedef int32_t	 SBits;
  1.4264 +				    typedef uint32_t UBits;
  1.4265 +
  1.4266 +				    typedef union
  1.4267 +				    {
  1.4268 +				        lua_Number n;
  1.4269 +#ifdef LUA_NUMBER_DOUBLE
  1.4270 +				        uint64_t b;
  1.4271 +#else
  1.4272 +				        UBits b;
  1.4273 +#endif
  1.4274 +					} BitNum;
  1.4275 +
  1.4276 +/* Convert argument to bit type. */
  1.4277 +				    static UBits barg(lua_State *L, int idx)
  1.4278 +				    {
  1.4279 +				        BitNum bn;
  1.4280 +				        UBits  b;
  1.4281 +				        bn.n = lua_tonumber(L, idx);
  1.4282 +#if defined(LUA_NUMBER_DOUBLE)
  1.4283 +				        bn.n += 6755399441055744.0; /* 2^52+2^51 */
  1.4284 +#ifdef SWAPPED_DOUBLE
  1.4285 +				        b = (UBits)(bn.b >> 32);
  1.4286 +#else
  1.4287 +				        b = (UBits)(bn.b & 0xffffffff);
  1.4288 +#endif
  1.4289 +#elif defined(LUA_NUMBER_INT) || defined(LUA_NUMBER_LONG) || \
  1.4290 +				        defined(LUA_NUMBER_LONGLONG) || defined(LUA_NUMBER_LONG_LONG) || \
  1.4291 +				        defined(LUA_NUMBER_LLONG)
  1.4292 +				        if (sizeof(UBits) == sizeof(lua_Number))
  1.4293 +							b = bn.b;
  1.4294 +				        else
  1.4295 +							b = (UBits)(SBits)bn.n;
  1.4296 +#elif defined(LUA_NUMBER_FLOAT)
  1.4297 +#error "A 'float' lua_Number type is incompatible with this library"
  1.4298 +#else
  1.4299 +#error "Unknown number type, check LUA_NUMBER_* in luaconf.h"
  1.4300 +#endif
  1.4301 +				        if (b == 0 && !lua_isnumber(L, idx))
  1.4302 +							luaL_typerror(L, idx, "number");
  1.4303 +				        return b;
  1.4304 +					}
  1.4305 +
  1.4306 +/* Return bit type. */
  1.4307 +#define BRET(b)  lua_pushnumber(L, (lua_Number)(SBits)(b)); return 1;
  1.4308 +
  1.4309 +				    static int bit_tobit(lua_State *L) { BRET(barg(L, 1)) }
  1.4310 +				    static int bit_bnot(lua_State *L) { BRET(~barg(L, 1)) }
  1.4311 +
  1.4312 +#define BIT_OP(func, opr) \
  1.4313 +	static int func(lua_State * L) { int i; UBits b = barg(L, 1); \
  1.4314 +				                     for (i = lua_gettop(L); i > 1; i--) \
  1.4315 +										 b opr barg(L, i); BRET(b) }
  1.4316 +				    BIT_OP(bit_band, &= )
  1.4317 +				    BIT_OP(bit_bor, |= )
  1.4318 +				    BIT_OP(bit_bxor, ^= )
  1.4319 +
  1.4320 +#define bshl(b, n)  (b << n)
  1.4321 +#define bshr(b, n)  (b >> n)
  1.4322 +#define bsar(b, n)  ((SBits)b >> n)
  1.4323 +#define brol(b, n)  ((b << n) | (b >> (32 - n)))
  1.4324 +#define bror(b, n)  ((b << (32 - n)) | (b >> n))
  1.4325 +#define BIT_SH(func, fn) \
  1.4326 +	static int func(lua_State * L) { \
  1.4327 +		UBits b = barg(L, 1); UBits n = barg(L, 2) & 31; BRET(fn(b, n)) }
  1.4328 +				    BIT_SH(bit_lshift, bshl)
  1.4329 +				    BIT_SH(bit_rshift, bshr)
  1.4330 +				    BIT_SH(bit_arshift, bsar)
  1.4331 +				    BIT_SH(bit_rol, brol)
  1.4332 +				    BIT_SH(bit_ror, bror)
  1.4333 +
  1.4334 +				    static int bit_bswap(lua_State *L)
  1.4335 +				    {
  1.4336 +				        UBits b = barg(L, 1);
  1.4337 +				        b = (b >> 24) | ((b >> 8) & 0xff00) | ((b & 0xff00) << 8) | (b << 24);
  1.4338 +				        BRET(b)
  1.4339 +					}
  1.4340 +
  1.4341 +				    static int bit_tohex(lua_State *L)
  1.4342 +				    {
  1.4343 +				        UBits		b		  = barg(L, 1);
  1.4344 +				        SBits		n		  = lua_isnone(L, 2) ? 8 : (SBits)barg(L, 2);
  1.4345 +				        const char *hexdigits = "0123456789abcdef";
  1.4346 +				        char		buf[8];
  1.4347 +				        int			i;
  1.4348 +				        if (n < 0) { n = -n; hexdigits = "0123456789ABCDEF"; }
  1.4349 +				        if (n > 8) n = 8;
  1.4350 +				        for (i = (int)n; --i >= 0; )
  1.4351 +				        {
  1.4352 +				            buf[i] = hexdigits[b & 15]; b >>= 4;
  1.4353 +						}
  1.4354 +				        lua_pushlstring(L, buf, (size_t)n);
  1.4355 +				        return 1;
  1.4356 +					}
  1.4357 +
  1.4358 +				    static const struct luaL_Reg bit_funcs[] = {
  1.4359 +				        { "tobit",	 bit_tobit	 },
  1.4360 +				        { "bnot",	 bit_bnot	 },
  1.4361 +				        { "band",	 bit_band	 },
  1.4362 +				        { "bor",	 bit_bor	 },
  1.4363 +				        { "bxor",	 bit_bxor	 },
  1.4364 +				        { "lshift",	 bit_lshift	 },
  1.4365 +				        { "rshift",	 bit_rshift	 },
  1.4366 +				        { "arshift", bit_arshift },
  1.4367 +				        { "rol",	 bit_rol	 },
  1.4368 +				        { "ror",	 bit_ror	 },
  1.4369 +				        { "bswap",	 bit_bswap	 },
  1.4370 +				        { "tohex",	 bit_tohex	 },
  1.4371 +				        { NULL,		 NULL		 }
  1.4372 +					};
  1.4373 +
  1.4374 +/* Signed right-shifts are implementation-defined per C89/C99.
  1.4375 +** But the de facto standard are arithmetic right-shifts on two's
  1.4376 +** complement CPUs. This behaviour is required here, so test for it.
  1.4377 +*/
  1.4378 +#define BAD_SAR     (bsar(-8, 2) != (SBits) - 2)
  1.4379 +
  1.4380 +				    bool luabitop_validate(lua_State *L) // originally named as luaopen_bit
  1.4381 +				    {
  1.4382 +				        UBits b;
  1.4383 +				        lua_pushnumber(L, (lua_Number)1437217655L);
  1.4384 +				        b = barg(L, -1);
  1.4385 +				        if (b != (UBits)1437217655L || BAD_SAR) /* Perform a simple self-test. */
  1.4386 +				        {
  1.4387 +				            const char *msg = "compiled with incompatible luaconf.h";
  1.4388 +#ifdef LUA_NUMBER_DOUBLE
  1.4389 +#ifdef WIN32
  1.4390 +				            if (b == (UBits)1610612736L)
  1.4391 +								msg = "use D3DCREATE_FPU_PRESERVE with DirectX";
  1.4392 +#endif
  1.4393 +				            if (b == (UBits)1127743488L)
  1.4394 +								msg = "not compiled with SWAPPED_DOUBLE";
  1.4395 +#endif
  1.4396 +				            if (BAD_SAR)
  1.4397 +								msg = "arithmetic right-shift broken";
  1.4398 +				            luaL_error(L, "bit library self-test failed (%s)", msg);
  1.4399 +				            return false;
  1.4400 +						}
  1.4401 +				        return true;
  1.4402 +					}
  1.4403 +
  1.4404 +// LuaBitOp ends here
  1.4405 +
  1.4406 +				    static int bit_bshift_emulua(lua_State *L)
  1.4407 +				    {
  1.4408 +				        int shift = luaL_checkinteger(L, 2);
  1.4409 +				        if (shift < 0)
  1.4410 +				        {
  1.4411 +				            lua_pushinteger(L, -shift);
  1.4412 +				            lua_replace(L, 2);
  1.4413 +				            return bit_lshift(L);
  1.4414 +						}
  1.4415 +				        else
  1.4416 +							return bit_rshift(L);
  1.4417 +					}
  1.4418 +
  1.4419 +				    static int bitbit(lua_State *L)
  1.4420 +				    {
  1.4421 +				        int rv		= 0;
  1.4422 +				        int numArgs = lua_gettop(L);
  1.4423 +				        for (int i = 1; i <= numArgs; i++)
  1.4424 +				        {
  1.4425 +				            int where = luaL_checkinteger(L, i);
  1.4426 +				            if (where >= 0 && where < 32)
  1.4427 +								rv |= (1 << where);
  1.4428 +						}
  1.4429 +				        lua_settop(L, 0);
  1.4430 +				        BRET(rv);
  1.4431 +					}
  1.4432 +
  1.4433 +// The function called periodically to ensure Lua doesn't run amok.
  1.4434 +				    static void VBALuaHookFunction(lua_State *L, lua_Debug *dbg)
  1.4435 +				    {
  1.4436 +				        if (numTries-- == 0)
  1.4437 +				        {
  1.4438 +				            int kill = 0;
  1.4439 +
  1.4440 +#if (defined(WIN32) && !defined(SDL))
  1.4441 +				            // Uh oh
  1.4442 +				            theApp.winCheckFullscreen();
  1.4443 +				            systemSoundClearBuffer();
  1.4444 +				            int ret = AfxGetApp()->m_pMainWnd->MessageBox(
  1.4445 +				                "The Lua script running has been running a long time. It may have gone crazy. Kill it?\n\n(No = don't check anymore either)",
  1.4446 +				                "Lua Script Gone Nuts?",
  1.4447 +				                MB_YESNO);
  1.4448 +
  1.4449 +				            if (ret == IDYES)
  1.4450 +				            {
  1.4451 +				                kill = 1;
  1.4452 +							}
  1.4453 +
  1.4454 +#else
  1.4455 +				            fprintf(
  1.4456 +				                stderr,
  1.4457 +				                "The Lua script running has been running a long time.\nIt may have gone crazy. Kill it? (I won't ask again if you say No)\n");
  1.4458 +
  1.4459 +				            char buffer[64];
  1.4460 +				            while (true)
  1.4461 +				            {
  1.4462 +				                fprintf(stderr, "(y/n): ");
  1.4463 +				                fgets(buffer, sizeof(buffer), stdin);
  1.4464 +				                if (buffer[0] == 'y' || buffer[0] == 'Y')
  1.4465 +				                {
  1.4466 +				                    kill = 1;
  1.4467 +				                    break;
  1.4468 +								}
  1.4469 +
  1.4470 +				                if (buffer[0] == 'n' || buffer[0] == 'N')
  1.4471 +									break;
  1.4472 +							}
  1.4473 +#endif
  1.4474 +				            if (kill)
  1.4475 +				            {
  1.4476 +				                luaL_error(L, "Killed by user request.");
  1.4477 +				                VBALuaOnStop();
  1.4478 +							}
  1.4479 +
  1.4480 +				            // else, kill the debug hook.
  1.4481 +				            lua_sethook(L, NULL, 0, 0);
  1.4482 +						}
  1.4483 +					}
  1.4484 +
  1.4485 +				    static const struct luaL_reg vbalib[] = {
  1.4486 +				        //	{"speedmode", vba_speedmode},	// TODO: NYI
  1.4487 +				        { "frameadvance",	vba_frameadvance	  },
  1.4488 +				        { "pause",			vba_pause			  },
  1.4489 +				        { "framecount",		vba_framecount		  },
  1.4490 +				        { "lagcount",		vba_getlagcount		  },
  1.4491 +				        { "lagged",			vba_lagged			  },
  1.4492 +				        { "emulating",		vba_emulating		  },
  1.4493 +				        { "registerbefore", vba_registerbefore	  },
  1.4494 +				        { "registerafter",	vba_registerafter	  },
  1.4495 +				        { "registerexit",	vba_registerexit	  },
  1.4496 +				        { "message",		vba_message			  },
  1.4497 +				        { "print",			print				  }, // sure, why not
  1.4498 +				        { NULL,				NULL				  }
  1.4499 +					};
  1.4500 +
  1.4501 +				    static const struct luaL_reg memorylib[] = {
  1.4502 +				        { "readbyte",				memory_readbyte				},
  1.4503 +				        { "readbytesigned",			memory_readbytesigned		},
  1.4504 +				        { "readword",				memory_readword				},
  1.4505 +				        { "readwordsigned",			memory_readwordsigned		},
  1.4506 +				        { "readdword",				memory_readdword			},
  1.4507 +				        { "readdwordsigned",		memory_readdwordsigned		},
  1.4508 +				        { "readbyterange",			memory_readbyterange		},
  1.4509 +				        { "writebyte",				memory_writebyte			},
  1.4510 +				        { "writeword",				memory_writeword			},
  1.4511 +				        { "writedword",				memory_writedword			},
  1.4512 +				        { "getregister",			memory_getregister			},
  1.4513 +				        { "setregister",			memory_setregister			},
  1.4514 +						{ "gbromreadbyte",			memory_gbromreadbyte		},
  1.4515 +						{ "gbromreadbytesigned",	memory_gbromreadbytesigned	},
  1.4516 +						{ "gbromreadword",			memory_gbromreadword		},
  1.4517 +						{ "gbromreadwordsigned",	memory_gbromreadwordsigned	},
  1.4518 +						{ "gbromreaddword",			memory_gbromreaddword		},
  1.4519 +						{ "gbromreaddwordsigned",	memory_gbromreaddwordsigned	},
  1.4520 +						{ "gbromreadbyterange",		memory_gbromreadbyterange	},
  1.4521 +
  1.4522 +				        // alternate naming scheme for word and double-word and unsigned
  1.4523 +				        { "readbyteunsigned",		memory_readbyte				},
  1.4524 +				        { "readwordunsigned",		memory_readword				},
  1.4525 +				        { "readdwordunsigned",		memory_readdword			},
  1.4526 +				        { "readshort",				memory_readword				},
  1.4527 +				        { "readshortunsigned",		memory_readword				},
  1.4528 +				        { "readshortsigned",		memory_readwordsigned		},
  1.4529 +				        { "readlong",				memory_readdword			},
  1.4530 +				        { "readlongunsigned",		memory_readdword			},
  1.4531 +						{ "readlongsigned",			memory_readdwordsigned		},
  1.4532 +				        { "writeshort",				memory_writeword			},
  1.4533 +				        { "writelong",				memory_writedword			},
  1.4534 +						{ "gbromreadbyteunsigned",	memory_gbromreadbyte		},
  1.4535 +						{ "gbromreadwordunsigned",	memory_gbromreadword		},
  1.4536 +						{ "gbromreaddwordunsigned",	memory_gbromreaddword		},
  1.4537 +						{ "gbromreadshort",			memory_gbromreadword		},
  1.4538 +						{ "gbromreadshortunsigned",	memory_gbromreadword		},
  1.4539 +						{ "gbromreadshortsigned",	memory_gbromreadwordsigned	},
  1.4540 +						{ "gbromreadlong",			memory_gbromreaddword		},
  1.4541 +						{ "gbromreadlongunsigned",	memory_gbromreaddword		},
  1.4542 +						{ "gbromreadlongsigned",	memory_gbromreaddwordsigned	},
  1.4543 +
  1.4544 +				        // memory hooks
  1.4545 +				        { "registerwrite",	   memory_registerwrite			 },
  1.4546 +				        //{"registerread", memory_registerread},
  1.4547 +				        { "registerexec",	   memory_registerexec			 },
  1.4548 +				        // alternate names
  1.4549 +				        { "register",		   memory_registerwrite			 },
  1.4550 +				        { "registerrun",	   memory_registerexec			 },
  1.4551 +				        { "registerexecute",   memory_registerexec			 },
  1.4552 +
  1.4553 +				        { NULL,				   NULL							 }
  1.4554 +					};
  1.4555 +
  1.4556 +				    static const struct luaL_reg joypadlib[] = {
  1.4557 +				        { "get",	  joypad_get	  },
  1.4558 +				        { "getdown",  joypad_getdown  },
  1.4559 +				        { "getup",	  joypad_getup	  },
  1.4560 +				        { "set",	  joypad_set	  },
  1.4561 +
  1.4562 +				        // alternative names
  1.4563 +				        { "read",	  joypad_get	  },
  1.4564 +				        { "write",	  joypad_set	  },
  1.4565 +				        { "readdown", joypad_getdown  },
  1.4566 +				        { "readup",	  joypad_getup	  },
  1.4567 +				        { NULL,		  NULL			  }
  1.4568 +					};
  1.4569 +
  1.4570 +				    static const struct luaL_reg savestatelib[] = {
  1.4571 +				        { "create", savestate_create },
  1.4572 +				        { "save",	savestate_save	 },
  1.4573 +				        { "load",	savestate_load	 },
  1.4574 +
  1.4575 +				        { NULL,		NULL			 }
  1.4576 +					};
  1.4577 +
  1.4578 +				    static const struct luaL_reg movielib[] = {
  1.4579 +				        { "active",			  movie_isactive				},
  1.4580 +				        { "recording",		  movie_isrecording				},
  1.4581 +				        { "playing",		  movie_isplaying				},
  1.4582 +				        { "mode",			  movie_getmode					},
  1.4583 +
  1.4584 +				        { "length",			  movie_getlength				},
  1.4585 +				        { "author",			  movie_getauthor				},
  1.4586 +				        { "name",			  movie_getfilename				},
  1.4587 +				        { "rerecordcount",	  movie_rerecordcount			},
  1.4588 +				        { "setrerecordcount", movie_setrerecordcount		},
  1.4589 +
  1.4590 +				        { "rerecordcounting", movie_rerecordcounting		},
  1.4591 +				        { "framecount",		  vba_framecount				}, // for those familiar with
  1.4592 +				                                                              // other emulators that have
  1.4593 +				                                                              // movie.framecount()
  1.4594 +				                                                              // instead of
  1.4595 +				                                                              // emulatorname.framecount()
  1.4596 +
  1.4597 +				        { "stop",			  movie_stop					},
  1.4598 +
  1.4599 +				        // alternative names
  1.4600 +				        { "close",			  movie_stop					},
  1.4601 +				        { "getauthor",		  movie_getauthor				},
  1.4602 +				        { "getname",		  movie_getfilename				},
  1.4603 +				        { NULL,				  NULL							}
  1.4604 +					};
  1.4605 +
  1.4606 +				    static const struct luaL_reg guilib[] = {
  1.4607 +				        { "register",	  gui_register		   },
  1.4608 +				        { "text",		  gui_text			   },
  1.4609 +				        { "box",		  gui_drawbox		   },
  1.4610 +				        { "line",		  gui_drawline		   },
  1.4611 +				        { "pixel",		  gui_drawpixel		   },
  1.4612 +				        { "opacity",	  gui_setopacity	   },
  1.4613 +				        { "transparency", gui_transparency	   },
  1.4614 +				        { "popup",		  gui_popup			   },
  1.4615 +				        { "parsecolor",	  gui_parsecolor	   },
  1.4616 +				        { "gdscreenshot", gui_gdscreenshot	   },
  1.4617 +				        { "gdoverlay",	  gui_gdoverlay		   },
  1.4618 +				        { "getpixel",	  gui_getpixel		   },
  1.4619 +
  1.4620 +				        // alternative names
  1.4621 +				        { "drawtext",	  gui_text			   },
  1.4622 +				        { "drawbox",	  gui_drawbox		   },
  1.4623 +				        { "drawline",	  gui_drawline		   },
  1.4624 +				        { "drawpixel",	  gui_drawpixel		   },
  1.4625 +				        { "setpixel",	  gui_drawpixel		   },
  1.4626 +				        { "writepixel",	  gui_drawpixel		   },
  1.4627 +				        { "rect",		  gui_drawbox		   },
  1.4628 +				        { "drawrect",	  gui_drawbox		   },
  1.4629 +				        { "drawimage",	  gui_gdoverlay		   },
  1.4630 +				        { "image",		  gui_gdoverlay		   },
  1.4631 +				        { "readpixel",	  gui_getpixel		   },
  1.4632 +				        { NULL,			  NULL				   }
  1.4633 +					};
  1.4634 +
  1.4635 +				    static const struct luaL_reg inputlib[] = {
  1.4636 +				        { "get",  input_getcurrentinputstatus  },
  1.4637 +
  1.4638 +				        // alternative names
  1.4639 +				        { "read", input_getcurrentinputstatus  },
  1.4640 +				        { NULL,	  NULL						   }
  1.4641 +					};
  1.4642 +
  1.4643 +				    static const struct luaL_reg soundlib[] = {
  1.4644 +				        { "get",  sound_get                    },
  1.4645 +
  1.4646 +				        // alternative names
  1.4647 +				        { NULL,	  NULL						   }
  1.4648 +					};
  1.4649 +
  1.4650 +// gocha: since vba dumps avi so badly,
  1.4651 +// I add avilib as a workaround for enhanced video encoding.
  1.4652 +				    static const struct luaL_reg avilib[] = {
  1.4653 +				        { "framecount", avi_framecount },
  1.4654 +				        { "pause",		avi_pause	   },
  1.4655 +				        { "resume",		avi_resume	   },
  1.4656 +				        { NULL,			NULL		   }
  1.4657 +					};
  1.4658 +
  1.4659 +				    void CallExitFunction(void)
  1.4660 +				    {
  1.4661 +				        if (!LUA)
  1.4662 +							return;
  1.4663 +
  1.4664 +				        lua_settop(LUA, 0);
  1.4665 +				        lua_getfield(LUA, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_BEFOREEXIT]);
  1.4666 +
  1.4667 +				        int errorcode = 0;
  1.4668 +				        if (lua_isfunction(LUA, -1))
  1.4669 +				        {
  1.4670 +				            errorcode = lua_pcall(LUA, 0, 0, 0);
  1.4671 +						}
  1.4672 +
  1.4673 +				        if (errorcode)
  1.4674 +							HandleCallbackError(LUA);
  1.4675 +					}
  1.4676 +
  1.4677 +				    void VBALuaFrameBoundary(void)
  1.4678 +				    {
  1.4679 +				        //	printf("Lua Frame\n");
  1.4680 +
  1.4681 +				        lua_joypads_used = 0;
  1.4682 +
  1.4683 +				        // HA!
  1.4684 +				        if (!LUA || !luaRunning)
  1.4685 +							return;
  1.4686 +
  1.4687 +				        // Our function needs calling
  1.4688 +				        lua_settop(LUA, 0);
  1.4689 +				        lua_getfield(LUA, LUA_REGISTRYINDEX, frameAdvanceThread);
  1.4690 +
  1.4691 +				        lua_State *thread = lua_tothread(LUA, 1);
  1.4692 +
  1.4693 +				        // Lua calling C must know that we're busy inside a frame boundary
  1.4694 +				        frameBoundary		= true;
  1.4695 +				        frameAdvanceWaiting = false;
  1.4696 +
  1.4697 +				        numTries = 1000;
  1.4698 +
  1.4699 +				        int result = lua_resume(thread, 0);
  1.4700 +
  1.4701 +				        if (result == LUA_YIELD)
  1.4702 +				        {
  1.4703 +				            // Okay, we're fine with that.
  1.4704 +						}
  1.4705 +				        else if (result != 0)
  1.4706 +				        {
  1.4707 +				            // Done execution by bad causes
  1.4708 +				            VBALuaOnStop();
  1.4709 +				            lua_pushnil(LUA);
  1.4710 +				            lua_setfield(LUA, LUA_REGISTRYINDEX, frameAdvanceThread);
  1.4711 +				            lua_pushnil(LUA);
  1.4712 +				            lua_setfield(LUA, LUA_REGISTRYINDEX, guiCallbackTable);
  1.4713 +
  1.4714 +				            // Error?
  1.4715 +//#if (defined(WIN32) && !defined(SDL))
  1.4716 +//		info_print(info_uid, lua_tostring(thread, -1)); //Clear_Sound_Buffer();
  1.4717 +// AfxGetApp()->m_pMainWnd->MessageBox(lua_tostring(thread, -1), "Lua run error", MB_OK | MB_ICONSTOP);
  1.4718 +//#else
  1.4719 +//		fprintf(stderr, "Lua thread bombed out: %s\n", lua_tostring(thread, -1));
  1.4720 +//#endif
  1.4721 +				            printerror(thread, -1);
  1.4722 +						}
  1.4723 +				        else
  1.4724 +				        {
  1.4725 +				            VBALuaOnStop();
  1.4726 +				            printf("Script died of natural causes.\n");
  1.4727 +						}
  1.4728 +
  1.4729 +				        // Past here, VBA actually runs, so any Lua code is called mid-frame. We must
  1.4730 +				        // not do anything too stupid, so let ourselves know.
  1.4731 +				        frameBoundary = false;
  1.4732 +
  1.4733 +				        if (!frameAdvanceWaiting)
  1.4734 +				        {
  1.4735 +				            VBALuaOnStop();
  1.4736 +						}
  1.4737 +					}
  1.4738 +
  1.4739 +/**
  1.4740 + * Loads and runs the given Lua script.
  1.4741 + * The emulator MUST be paused for this function to be
  1.4742 + * called. Otherwise, all frame boundary assumptions go out the window.
  1.4743 + *
  1.4744 + * Returns true on success, false on failure.
  1.4745 + */
  1.4746 +				    int VBALoadLuaCode(const char *filename)
  1.4747 +				    {
  1.4748 +				        static bool sfmtInitialized = false;
  1.4749 +				        if (!sfmtInitialized)
  1.4750 +				        {
  1.4751 +				            init_gen_rand((unsigned)time(NULL));
  1.4752 +				            sfmtInitialized = true;
  1.4753 +						}
  1.4754 +
  1.4755 +				        if (filename != luaScriptName)
  1.4756 +				        {
  1.4757 +				            if (luaScriptName)
  1.4758 +								free(luaScriptName);
  1.4759 +				            luaScriptName = strdup(filename);
  1.4760 +						}
  1.4761 +
  1.4762 +				        //stop any lua we might already have had running
  1.4763 +				        VBALuaStop();
  1.4764 +
  1.4765 +				        // Set current directory from filename (for dofile)
  1.4766 +				        char  dir[_MAX_PATH];
  1.4767 +				        char *slash, *backslash;
  1.4768 +				        strcpy(dir, filename);
  1.4769 +				        slash	  = strrchr(dir, '/');
  1.4770 +				        backslash = strrchr(dir, '\\');
  1.4771 +				        if (!slash || (backslash && backslash < slash))
  1.4772 +							slash = backslash;
  1.4773 +				        if (slash)
  1.4774 +				        {
  1.4775 +				            slash[1] = '\0'; // keep slash itself for some reasons
  1.4776 +				            chdir(dir);
  1.4777 +						}
  1.4778 +
  1.4779 +				        if (!LUA)
  1.4780 +				        {
  1.4781 +				            LUA = lua_open();
  1.4782 +				            luaL_openlibs(LUA);
  1.4783 +
  1.4784 +				            luaL_register(LUA, "emu", vbalib); // added for better cross-emulator compatibility
  1.4785 +				            luaL_register(LUA, "vba", vbalib); // kept for backward compatibility
  1.4786 +				            luaL_register(LUA, "memory", memorylib);
  1.4787 +				            luaL_register(LUA, "joypad", joypadlib);
  1.4788 +				            luaL_register(LUA, "savestate", savestatelib);
  1.4789 +				            luaL_register(LUA, "movie", movielib);
  1.4790 +				            luaL_register(LUA, "gui", guilib);
  1.4791 +				            luaL_register(LUA, "input", inputlib);
  1.4792 +				            luaL_register(LUA, "sound", soundlib);
  1.4793 +				            luaL_register(LUA, "bit", bit_funcs); // LuaBitOp library
  1.4794 +				            luaL_register(LUA, "avi", avilib); // workaround for enhanced video encoding
  1.4795 +				            lua_settop(LUA, 0); // clean the stack, because each call to luaL_register leaves a table on top
  1.4796 +
  1.4797 +				            // register a few utility functions outside of libraries (in the global namespace)
  1.4798 +				            lua_register(LUA, "print", print);
  1.4799 +				            lua_register(LUA, "tostring", tostring);
  1.4800 +				            lua_register(LUA, "addressof", addressof);
  1.4801 +				            lua_register(LUA, "copytable", copytable);
  1.4802 +
  1.4803 +				            // old bit operation functions
  1.4804 +				            lua_register(LUA, "AND", bit_band);
  1.4805 +				            lua_register(LUA, "OR", bit_bor);
  1.4806 +				            lua_register(LUA, "XOR", bit_bxor);
  1.4807 +				            lua_register(LUA, "SHIFT", bit_bshift_emulua);
  1.4808 +				            lua_register(LUA, "BIT", bitbit);
  1.4809 +
  1.4810 +				            luabitop_validate(LUA);
  1.4811 +
  1.4812 +				            lua_pushstring(LUA, "math");
  1.4813 +				            lua_gettable(LUA, LUA_GLOBALSINDEX);
  1.4814 +				            lua_pushcfunction(LUA, sfmt_random);
  1.4815 +				            lua_setfield(LUA, -2, "random");
  1.4816 +				            lua_pushcfunction(LUA, sfmt_randomseed);
  1.4817 +				            lua_setfield(LUA, -2, "randomseed");
  1.4818 +				            lua_settop(LUA, 0);
  1.4819 +
  1.4820 +				            // push arrays for storing hook functions in
  1.4821 +				            for (int i = 0; i < LUAMEMHOOK_COUNT; i++)
  1.4822 +				            {
  1.4823 +				                lua_newtable(LUA);
  1.4824 +				                lua_setfield(LUA, LUA_REGISTRYINDEX, luaMemHookTypeStrings[i]);
  1.4825 +							}
  1.4826 +						}
  1.4827 +
  1.4828 +				        // We make our thread NOW because we want it at the bottom of the stack.
  1.4829 +				        // If all goes wrong, we let the garbage collector remove it.
  1.4830 +				        lua_State *thread = lua_newthread(LUA);
  1.4831 +
  1.4832 +				        // Load the data
  1.4833 +				        int result = luaL_loadfile(LUA, filename);
  1.4834 +
  1.4835 +				        if (result)
  1.4836 +				        {
  1.4837 +//#if (defined(WIN32) && !defined(SDL))
  1.4838 +//		info_print(info_uid, lua_tostring(LUA, -1)); //Clear_Sound_Buffer();
  1.4839 +// AfxGetApp()->m_pMainWnd->MessageBox(lua_tostring(LUA, -1), "Lua load error", MB_OK | MB_ICONSTOP);
  1.4840 +//#else
  1.4841 +//		fprintf(stderr, "Failed to compile file: %s\n", lua_tostring(LUA, -1));
  1.4842 +//#endif
  1.4843 +				            printerror(LUA, -1);
  1.4844 +
  1.4845 +				            // Wipe the stack. Our thread
  1.4846 +				            lua_settop(LUA, 0);
  1.4847 +				            return 0; // Oh shit.
  1.4848 +						}
  1.4849 +
  1.4850 +				        // Get our function into it
  1.4851 +				        lua_xmove(LUA, thread, 1);
  1.4852 +
  1.4853 +				        // Save the thread to the registry. This is why I make the thread FIRST.
  1.4854 +				        lua_setfield(LUA, LUA_REGISTRYINDEX, frameAdvanceThread);
  1.4855 +
  1.4856 +				        // Initialize settings
  1.4857 +				        luaRunning = true;
  1.4858 +				        skipRerecords		 = false;
  1.4859 +				        numMemHooks			 = 0;
  1.4860 +				        transparencyModifier = 255; // opaque
  1.4861 +				        lua_joypads_used	 = 0; // not used
  1.4862 +				        //wasPaused = systemIsPaused();
  1.4863 +				        //systemSetPause(false);
  1.4864 +
  1.4865 +				        // Set up our protection hook to be executed once every 10,000 bytecode instructions.
  1.4866 +				        lua_sethook(thread, VBALuaHookFunction, LUA_MASKCOUNT, 10000);
  1.4867 +
  1.4868 +#ifdef WIN32
  1.4869 +				        info_print	 = PrintToWindowConsole;
  1.4870 +				        info_onstart = WinLuaOnStart;
  1.4871 +				        info_onstop	 = WinLuaOnStop;
  1.4872 +				        if (!LuaConsoleHWnd)
  1.4873 +							LuaConsoleHWnd = CreateDialog(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDD_LUA),
  1.4874 +							                              AfxGetMainWnd()->GetSafeHwnd(), (DLGPROC) DlgLuaScriptDialog);
  1.4875 +				        info_uid = (int)LuaConsoleHWnd;
  1.4876 +#else
  1.4877 +				        info_print	 = NULL;
  1.4878 +				        info_onstart = NULL;
  1.4879 +				        info_onstop	 = NULL;
  1.4880 +#endif
  1.4881 +				        if (info_onstart)
  1.4882 +							info_onstart(info_uid);
  1.4883 +
  1.4884 +				        // And run it right now. :)
  1.4885 +				        VBALuaFrameBoundary();
  1.4886 +				        systemRenderFrame();
  1.4887 +
  1.4888 +				        // We're done.
  1.4889 +				        return 1;
  1.4890 +					}
  1.4891 +
  1.4892 +/**
  1.4893 + * Equivalent to repeating the last VBALoadLuaCode() call.
  1.4894 + */
  1.4895 +				    int VBAReloadLuaCode(void)
  1.4896 +				    {
  1.4897 +				        if (!luaScriptName)
  1.4898 +				        {
  1.4899 +				            systemScreenMessage("There's no script to reload.");
  1.4900 +				            return 0;
  1.4901 +						}
  1.4902 +				        else
  1.4903 +							return VBALoadLuaCode(luaScriptName);
  1.4904 +					}
  1.4905 +
  1.4906 +/**
  1.4907 + * Terminates a running Lua script by killing the whole Lua engine.
  1.4908 + *
  1.4909 + * Always safe to call, except from within a lua call itself (duh).
  1.4910 + *
  1.4911 + */
  1.4912 +				    void VBALuaStop(void)
  1.4913 +				    {
  1.4914 +				        //already killed
  1.4915 +				        if (!LUA)
  1.4916 +							return;
  1.4917 +
  1.4918 +				        //execute the user's shutdown callbacks
  1.4919 +				        CallExitFunction();
  1.4920 +
  1.4921 +				        /*info.*/ numMemHooks = 0;
  1.4922 +				        for (int i = 0; i < LUAMEMHOOK_COUNT; i++)
  1.4923 +							CalculateMemHookRegions((LuaMemHookType)i);
  1.4924 +
  1.4925 +				        //sometimes iup uninitializes com
  1.4926 +				        //MBG TODO - test whether this is really necessary. i dont think it is
  1.4927 +#if (defined(WIN32) && !defined(SDL))
  1.4928 +				        CoInitialize(0);
  1.4929 +#endif
  1.4930 +
  1.4931 +				        if (info_onstop)
  1.4932 +							info_onstop(info_uid);
  1.4933 +
  1.4934 +				        //lua_gc(LUA,LUA_GCCOLLECT,0);
  1.4935 +				        lua_close(LUA); // this invokes our garbage collectors for us
  1.4936 +				        LUA = NULL;
  1.4937 +				        VBALuaOnStop();
  1.4938 +					}
  1.4939 +
  1.4940 +/**
  1.4941 + * Returns true if there is a Lua script running.
  1.4942 + *
  1.4943 + */
  1.4944 +				    int VBALuaRunning(void)
  1.4945 +				    {
  1.4946 +				        // FIXME: return false when no callback functions are registered.
  1.4947 +				        return (int) (LUA != NULL); // should return true if callback functions are active.
  1.4948 +					}
  1.4949 +
  1.4950 +/**
  1.4951 + * Returns true if Lua would like to steal the given joypad control.
  1.4952 + *
  1.4953 + * Range is 0 through 3
  1.4954 + */
  1.4955 +				    int VBALuaUsingJoypad(int which)
  1.4956 +				    {
  1.4957 +				        if (which < 0 || which > 3)
  1.4958 +							which = systemGetDefaultJoypad();
  1.4959 +				        return lua_joypads_used & (1 << which);
  1.4960 +					}
  1.4961 +
  1.4962 +/**
  1.4963 + * Reads the buttons Lua is feeding for the given joypad, in the same
  1.4964 + * format as the OS-specific code.
  1.4965 + *
  1.4966 + * <del>This function must not be called more than once per frame. </del>Ideally exactly once
  1.4967 + * per frame (if VBALuaUsingJoypad says it's safe to do so)
  1.4968 + */
  1.4969 +				    int VBALuaReadJoypad(int which)
  1.4970 +				    {
  1.4971 +				        if (which < 0 || which > 3)
  1.4972 +							which = systemGetDefaultJoypad();
  1.4973 +
  1.4974 +				        //lua_joypads_used &= ~(1 << which);
  1.4975 +				        return lua_joypads[which];
  1.4976 +					}
  1.4977 +
  1.4978 +/**
  1.4979 + * If this function returns true, the movie code should NOT increment
  1.4980 + * the rerecord count for a load-state.
  1.4981 + *
  1.4982 + * This function will not return true if a script is not running.
  1.4983 + */
  1.4984 +				    bool8 VBALuaRerecordCountSkip(void)
  1.4985 +				    {
  1.4986 +				        // FIXME: return true if (there are any active callback functions && skipRerecords)
  1.4987 +				        return LUA && luaRunning && skipRerecords;
  1.4988 +					}
  1.4989 +
  1.4990 +/**
  1.4991 + * Given a screen with the indicated resolution,
  1.4992 + * draw the current GUI onto it.
  1.4993 + */
  1.4994 +				    void VBALuaGui(uint8 *screen, int ppl, int width, int height)
  1.4995 +				    {
  1.4996 +				        if (!LUA /* || !luaRunning*/)
  1.4997 +							return;
  1.4998 +
  1.4999 +				        // First, check if we're being called by anybody
  1.5000 +				        lua_getfield(LUA, LUA_REGISTRYINDEX, guiCallbackTable);
  1.5001 +
  1.5002 +				        if (lua_isfunction(LUA, -1))
  1.5003 +				        {
  1.5004 +				            // We call it now
  1.5005 +				            numTries = 1000;
  1.5006 +
  1.5007 +				            int ret = lua_pcall(LUA, 0, 0, 0);
  1.5008 +				            if (ret != 0)
  1.5009 +				            {
  1.5010 +				                // This is grounds for trashing the function
  1.5011 +				                // Note: This must be done before the messagebox pops up,
  1.5012 +				                //       otherwise the messagebox will cause a paint event which causes a weird
  1.5013 +				                //       infinite call sequence that makes Snes9x silently exit with error code 3,
  1.5014 +				                //       if a Lua GUI function crashes. (nitsuja)
  1.5015 +				                lua_pushnil(LUA);
  1.5016 +				                lua_setfield(LUA, LUA_REGISTRYINDEX, guiCallbackTable);
  1.5017 +
  1.5018 +//#if (defined(WIN32) && !defined(SDL))
  1.5019 +//			info_print(info_uid, lua_tostring(LUA, -1)); //AfxGetApp()->m_pMainWnd->MessageBox(lua_tostring(LUA, -1), "Lua Error
  1.5020 +// in GUI function", MB_OK);
  1.5021 +//#else
  1.5022 +//			fprintf(stderr, "Lua error in gui.register function: %s\n", lua_tostring(LUA, -1));
  1.5023 +//#endif
  1.5024 +				                printerror(LUA, -1);
  1.5025 +							}
  1.5026 +						}
  1.5027 +
  1.5028 +				        // And wreak the stack
  1.5029 +				        lua_settop(LUA, 0);
  1.5030 +
  1.5031 +				        if (!gui_used)
  1.5032 +							return;
  1.5033 +
  1.5034 +				        gui_used = false;
  1.5035 +
  1.5036 +				        int x, y;
  1.5037 +
  1.5038 +				        //int pitch = (((ppl * systemColorDepth + 7)>>3)+3)&~3;
  1.5039 +				        int pitch = ppl * (systemColorDepth / 8) + (systemColorDepth == 24 ? 0 : 4);
  1.5040 +
  1.5041 +				        if (width > LUA_SCREEN_WIDTH)
  1.5042 +							width = LUA_SCREEN_WIDTH;
  1.5043 +				        if (height > LUA_SCREEN_HEIGHT)
  1.5044 +							height = LUA_SCREEN_HEIGHT;
  1.5045 +
  1.5046 +				        GetColorFunc getColor;
  1.5047 +				        SetColorFunc setColor;
  1.5048 +				        getColorIOFunc(systemColorDepth, &getColor, &setColor);
  1.5049 +
  1.5050 +				        for (y = 0; y < height; y++)
  1.5051 +				        {
  1.5052 +				            uint8 *scr = &screen[y * pitch];
  1.5053 +				            for (x = 0; x < width; x++, scr += systemColorDepth / 8)
  1.5054 +				            {
  1.5055 +				                const uint8 gui_alpha = gui_data[(y * LUA_SCREEN_WIDTH + x) * 4 + 3];
  1.5056 +				                if (gui_alpha == 0)
  1.5057 +				                {
  1.5058 +				                    // do nothing
  1.5059 +				                    continue;
  1.5060 +								}
  1.5061 +
  1.5062 +				                const uint8 gui_red	  = gui_data[(y * LUA_SCREEN_WIDTH + x) * 4 + 2];
  1.5063 +				                const uint8 gui_green = gui_data[(y * LUA_SCREEN_WIDTH + x) * 4 + 1];
  1.5064 +				                const uint8 gui_blue  = gui_data[(y * LUA_SCREEN_WIDTH + x) * 4];
  1.5065 +				                int			red, green, blue;
  1.5066 +
  1.5067 +				                if (gui_alpha == 255)
  1.5068 +				                {
  1.5069 +				                    // direct copy
  1.5070 +				                    red	  = gui_red;
  1.5071 +				                    green = gui_green;
  1.5072 +				                    blue  = gui_blue;
  1.5073 +								}
  1.5074 +				                else
  1.5075 +				                {
  1.5076 +				                    // alpha-blending
  1.5077 +				                    uint8 scr_red, scr_green, scr_blue;
  1.5078 +				                    getColor(scr, &scr_red, &scr_green, &scr_blue);
  1.5079 +				                    red	  = (((int)gui_red - scr_red) * gui_alpha / 255 + scr_red) & 255;
  1.5080 +				                    green = (((int)gui_green - scr_green) * gui_alpha / 255 + scr_green) & 255;
  1.5081 +				                    blue  = (((int)gui_blue - scr_blue) * gui_alpha / 255 + scr_blue) & 255;
  1.5082 +								}
  1.5083 +
  1.5084 +				                setColor(scr, (uint8) red, (uint8) green, (uint8) blue);
  1.5085 +							}
  1.5086 +						}
  1.5087 +
  1.5088 +				        return;
  1.5089 +					}
  1.5090 +
  1.5091 +				    void VBALuaClearGui(void)
  1.5092 +				    {
  1.5093 +				        gui_used = false;
  1.5094 +					}
  1.5095 +
  1.5096 +				    lua_State *VBAGetLuaState()
  1.5097 +				    {
  1.5098 +				        return LUA;
  1.5099 +					}
  1.5100 +
  1.5101 +				    char *VBAGetLuaScriptName()
  1.5102 +				    {
  1.5103 +				        return luaScriptName;
  1.5104 +					}
  1.5105 +