2314 lines
59 KiB
C
2314 lines
59 KiB
C
/*
|
|
*
|
|
* Singe 2
|
|
* Copyright (C) 2006-2020 Scott Duensing <scott@kangaroopunch.com>
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
*/
|
|
|
|
|
|
#include <string.h>
|
|
|
|
#include <SDL2/SDL.h>
|
|
#include <SDL2/SDL_image.h>
|
|
#include <SDL2/SDL_mixer.h>
|
|
#include <SDL2/SDL_ttf.h>
|
|
#include <lua.h>
|
|
#include <lualib.h>
|
|
#include <lauxlib.h>
|
|
|
|
#include "thirdparty/uthash.h"
|
|
#include "thirdparty/manymouse/manymouse.h"
|
|
|
|
#include "util.h"
|
|
#include "videoPlayer.h"
|
|
#include "singe.h"
|
|
#include "font.h"
|
|
|
|
|
|
#define AUDIO_MAX_VOLUME 63
|
|
#define MAX_TITLE_LENGTH 1024
|
|
#define MAX_MICE 128
|
|
#define SCROLLWHEEL_DISPLAY_TICKS 100
|
|
#define NOMOUSE -1
|
|
#define KEYBD_ARRAY_SIZE 15
|
|
#define MOUSE_ARRAY_SIZE 6
|
|
|
|
|
|
typedef struct MouseS {
|
|
int x;
|
|
int y;
|
|
int relx;
|
|
int rely;
|
|
char name[64];
|
|
bool connected;
|
|
#pragma GCC diagnostic push
|
|
#pragma GCC diagnostic ignored "-Wpadded"
|
|
Uint32 buttons;
|
|
#pragma GCC diagnostic pop
|
|
Uint32 scrolluptick;
|
|
Uint32 scrolldowntick;
|
|
Uint32 scrolllefttick;
|
|
Uint32 scrollrighttick;
|
|
} MouseT;
|
|
|
|
typedef struct SpriteS {
|
|
int id;
|
|
#pragma GCC diagnostic push
|
|
#pragma GCC diagnostic ignored "-Wpadded"
|
|
SDL_Surface *surface;
|
|
#pragma GCC diagnostic pop
|
|
UT_hash_handle hh;
|
|
} SpriteT;
|
|
|
|
typedef struct SoundS {
|
|
int id;
|
|
#pragma GCC diagnostic push
|
|
#pragma GCC diagnostic ignored "-Wpadded"
|
|
Mix_Chunk *chunk;
|
|
#pragma GCC diagnostic pop
|
|
UT_hash_handle hh;
|
|
} SoundT;
|
|
|
|
typedef struct FontS {
|
|
int id;
|
|
#pragma GCC diagnostic push
|
|
#pragma GCC diagnostic ignored "-Wpadded"
|
|
TTF_Font *font;
|
|
#pragma GCC diagnostic pop
|
|
UT_hash_handle hh;
|
|
} FontT;
|
|
|
|
|
|
enum {
|
|
SWITCH_UP,
|
|
SWITCH_LEFT,
|
|
SWITCH_DOWN,
|
|
SWITCH_RIGHT,
|
|
SWITCH_START1,
|
|
SWITCH_START2,
|
|
SWITCH_BUTTON1,
|
|
SWITCH_BUTTON2,
|
|
SWITCH_BUTTON3,
|
|
SWITCH_COIN1,
|
|
SWITCH_COIN2,
|
|
SWITCH_SKILL1,
|
|
SWITCH_SKILL2,
|
|
SWITCH_SKILL3,
|
|
SWITCH_SERVICE,
|
|
SWITCH_TEST,
|
|
SWITCH_RESET,
|
|
SWITCH_SCREENSHOT,
|
|
SWITCH_QUIT,
|
|
SWITCH_PAUSE,
|
|
SWITCH_CONSOLE,
|
|
SWITCH_TILT,
|
|
SWITCH_MOUSE_SCROLL_UP,
|
|
SWITCH_MOUSE_SCROLL_DOWN,
|
|
SWITCH_MOUSE_DISCONNECT,
|
|
SWITCH_COUNT
|
|
};
|
|
|
|
enum {
|
|
KEYBD_NORMAL = 0,
|
|
KEYBD_FULL
|
|
};
|
|
|
|
enum {
|
|
MOUSE_SINGLE = 100,
|
|
MOUSE_MANY = 200
|
|
};
|
|
|
|
enum {
|
|
LDP_ERROR = 0,
|
|
LDP_SEARCHING,
|
|
LDP_STOPPED,
|
|
LDP_PLAYING,
|
|
LDP_PAUSE,
|
|
};
|
|
|
|
|
|
// Command line options
|
|
char *_confVideoFile = NULL;
|
|
char *_confScriptFile = NULL;
|
|
char *_confDataDir = NULL;
|
|
bool _confStretchVideo = false;
|
|
bool _confNoMouse = false;
|
|
bool _confNoStats = false;
|
|
bool _confNoSound = false;
|
|
bool _confFullScreen = false;
|
|
bool _confFullScreenWindow = false;
|
|
int _confVolumeVldp = 100;
|
|
int _confVolumeNonVldp = 100;
|
|
int _confScaleFactor = 100;
|
|
int _confXResolution = -1;
|
|
int _confYResolution = -1;
|
|
|
|
|
|
// Other globals
|
|
static MouseT _mice[MAX_MICE];
|
|
static lua_State *_luaContext = NULL;
|
|
static SDL_Color _colorForeground = { 255, 255, 255, 255 };
|
|
static SDL_Color _colorBackground = { 0, 0, 0, 0 };
|
|
static SDL_Surface *_overlay = NULL;
|
|
static SDL_Window *_window = NULL;
|
|
static SDL_Renderer *_renderer = NULL;
|
|
static SDL_Texture *_videoTexture = NULL;
|
|
static SDL_Surface *_consoleFontSurface = NULL;
|
|
static int _consoleFontWidth = 0;
|
|
static int _consoleFontHeight = 0;
|
|
static int _nextSpriteId = 0;
|
|
static int _nextSoundId = 0;
|
|
static int _nextFontId = 0;
|
|
static int _effectsVolume = AUDIO_MAX_VOLUME;
|
|
static int _keyboardMode = KEYBD_NORMAL;
|
|
static int _videoHandle = -1;
|
|
static int _fontQuality = 1;
|
|
static int _mouseMode = MOUSE_SINGLE;
|
|
static int _mouseCount = 0;
|
|
static double _overlayScaleX = 1; // Difference between overlay and video
|
|
static double _overlayScaleY = 1; // Difference between overlay and video
|
|
static bool _pauseState = false; // by RDG2010
|
|
static bool _pauseEnabled = true; // by RDG2010
|
|
static bool _refreshDisplay = false;
|
|
static bool _running = true;
|
|
static bool _discStopped = true;
|
|
static bool _mouseEnabled = true;
|
|
static SpriteT *_spriteList = NULL;
|
|
static SoundT *_soundList = NULL;
|
|
static FontT *_fontList = NULL;
|
|
static FontT *_fontCurrent = NULL;
|
|
|
|
|
|
static int _keyDefs[SWITCH_COUNT][2] = {
|
|
{ SDLK_UP, SDLK_KP_8 }, // Up
|
|
{ SDLK_LEFT, SDLK_KP_4 }, // Left
|
|
{ SDLK_DOWN, SDLK_KP_2 }, // Down
|
|
{ SDLK_RIGHT, SDLK_KP_6 }, // Right
|
|
{ SDLK_1, 0 }, // 1 player start
|
|
{ SDLK_2, 0 }, // 2 player start
|
|
{ SDLK_SPACE, SDLK_LCTRL }, // Action button 1
|
|
{ SDLK_LALT, 0 }, // Action button 2
|
|
{ SDLK_LSHIFT, 0 }, // Action button 3
|
|
{ SDLK_5, SDLK_c }, // Coin chute left
|
|
{ SDLK_6, 0 }, // Coin chute right
|
|
{ SDLK_KP_DIVIDE, 0 }, // Skill easy
|
|
{ SDLK_KP_MULTIPLY, 0 }, // Skill medium
|
|
{ SDLK_KP_MINUS, 0 }, // Skill hard
|
|
{ SDLK_9, 0 }, // Service coin
|
|
{ SDLK_F2, 0 }, // Test mode
|
|
{ SDLK_F3, 0 }, // Reset cpu
|
|
{ SDLK_F12, SDLK_F11 }, // Take screenshot
|
|
{ SDLK_ESCAPE, SDLK_q }, // Quit
|
|
{ SDLK_p, 0 }, // Pause game
|
|
{ SDLK_BACKQUOTE, 0 }, // Toggle console
|
|
{ SDLK_t, 0 } // Tilt/Slam switch
|
|
};
|
|
|
|
static int _fullKeybdDefs[] = {
|
|
SDLK_BACKSPACE,
|
|
SDLK_TAB,
|
|
SDLK_RETURN,
|
|
SDLK_PAUSE,
|
|
SDLK_SPACE,
|
|
SDLK_QUOTE,
|
|
SDLK_COMMA,
|
|
SDLK_SEMICOLON,
|
|
SDLK_EQUALS,
|
|
SDLK_LEFTBRACKET,
|
|
SDLK_RIGHTBRACKET,
|
|
SDLK_BACKSLASH,
|
|
SDLK_SLASH,
|
|
SDLK_DELETE,
|
|
SDLK_PERIOD
|
|
};
|
|
|
|
|
|
int apiColorBackground(lua_State *L);
|
|
int apiColorForeground(lua_State *L);
|
|
int apiDaphneGetHeight(lua_State *L);
|
|
int apiDaphneGetWidth(lua_State *L);
|
|
int apiDaphneScreenshot(lua_State *L);
|
|
int apiDebugPrint(lua_State *L);
|
|
int apiDiscAudio(lua_State *L);
|
|
int apiDiscChangeSpeed(lua_State *L);
|
|
int apiDiscGetFrame(lua_State *L);
|
|
int apiDiscPause(lua_State *L);
|
|
int apiDiscPauseAtFrame(lua_State *L);
|
|
int apiDiscPlay(lua_State *L);
|
|
int apiDiscSearch(lua_State *L);
|
|
int apiDiscSearchBlanking(lua_State *L);
|
|
int apiDiscSetFps(lua_State *L);
|
|
int apiDiscSkipBackward(lua_State *L);
|
|
int apiDiscSkipBlanking(lua_State *L);
|
|
int apiDiscSkipForward(lua_State *L);
|
|
int apiDiscSkipToFrame(lua_State *L);
|
|
int apiDiscStepBackward(lua_State *L);
|
|
int apiDiscStepForward(lua_State *L);
|
|
int apiDiscStop(lua_State *L);
|
|
int apiFontLoad(lua_State *L);
|
|
int apiFontPrint(lua_State *L);
|
|
int apiFontQuality(lua_State *L);
|
|
int apiFontSelect(lua_State *L);
|
|
int apiFontToSprite(lua_State *L);
|
|
int apiOverlayClear(lua_State *L);
|
|
int apiOverlayGetHeight(lua_State *L);
|
|
int apiOverlayGetWidth(lua_State *L);
|
|
int apiOverlayPrint(lua_State *L);
|
|
int apiSoundLoad(lua_State *L);
|
|
int apiSoundPlay(lua_State *L);
|
|
int apiSoundPause(lua_State *L);
|
|
int apiSoundResume(lua_State *L);
|
|
int apiSoundIsPlaying(lua_State *L);
|
|
int apiSoundStop(lua_State *L);
|
|
int apiSoundSetVolume(lua_State *L);
|
|
int apiSoundGetVolume(lua_State *L);
|
|
int apiSoundFullStop(lua_State *L);
|
|
int apiSpriteDraw(lua_State *L);
|
|
int apiSpriteGetHeight(lua_State *L);
|
|
int apiSpriteGetWidth(lua_State *L);
|
|
int apiSpriteLoad(lua_State *L);
|
|
int apiVldpGetHeight(lua_State *L);
|
|
int apiVldpGetPixel(lua_State *L);
|
|
int apiVldpGetWidth(lua_State *L);
|
|
int apiVldpVerbose(lua_State *L);
|
|
int apiKeyboardGetMode(lua_State *L);
|
|
int apiKeyboardSetMode(lua_State *L);
|
|
int apiMouseEnable(lua_State *L);
|
|
int apiMouseDisable(lua_State *L);
|
|
int apiMouseSetMode(lua_State *L);
|
|
int apiMouseHowMany(lua_State *L);
|
|
int apiDiscGetState(lua_State *L);
|
|
int apiSingeGetPauseFlag(lua_State *L);
|
|
int apiSingeSetPauseFlag(lua_State *L);
|
|
int apiSingeEnablePauseKey(lua_State *L);
|
|
int apiSingeDisablePauseKey(lua_State *L);
|
|
int apiSingeQuit(lua_State *L);
|
|
int apiSingeVersion(lua_State *L);
|
|
int apiSingeSetGameName(lua_State *L);
|
|
int apiSingeGetScriptPath(lua_State *L);
|
|
void callLua(const char *func, const char *sig, ...);
|
|
void channelFinished(int channel);
|
|
void luaDie(lua_State *L, char *method, char *fmt, ...);
|
|
int luaError(lua_State *L);
|
|
void luaTrace(lua_State *L, char *method, char *fmt, ...);
|
|
void processKey(bool down, int keysym);
|
|
|
|
|
|
int apiColorBackground(lua_State *L) {
|
|
int n = lua_gettop(L);
|
|
double d = 0;
|
|
bool result = false;
|
|
|
|
if ((n == 3) || (n == 4)) {
|
|
if (lua_isnumber(L, 1)) {
|
|
if (lua_isnumber(L, 2)) {
|
|
if (lua_isnumber(L, 3)) {
|
|
d = lua_tonumber(L, 1); _colorBackground.r = (byte)d;
|
|
d = lua_tonumber(L, 2); _colorBackground.g = (byte)d;
|
|
d = lua_tonumber(L, 3); _colorBackground.b = (byte)d;
|
|
if (n == 3) {
|
|
_colorBackground.a = (byte)255;
|
|
} else {
|
|
if (lua_isnumber(L, 4)) {
|
|
d = lua_tonumber(L, 4); _colorBackground.a = (byte)d;
|
|
} else {
|
|
_colorBackground.a = (byte)255;
|
|
}
|
|
}
|
|
result = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (result) {
|
|
luaTrace(L, "colorBackground", "%d %d %d %d", _colorBackground.r, _colorBackground.g, _colorBackground.b, _colorBackground.a);
|
|
} else {
|
|
luaTrace(L, "colorBackground", "Failed!");
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int apiColorForeground(lua_State *L) {
|
|
int n = lua_gettop(L);
|
|
bool result = false;
|
|
double d = 0;
|
|
|
|
if ((n == 3) || (n == 4)) {
|
|
if (lua_isnumber(L, 1)) {
|
|
if (lua_isnumber(L, 2)) {
|
|
if (lua_isnumber(L, 3)) {
|
|
d = lua_tonumber(L, 1); _colorForeground.r = (byte)d;
|
|
d = lua_tonumber(L, 2); _colorForeground.g = (byte)d;
|
|
d = lua_tonumber(L, 3); _colorForeground.b = (byte)d;
|
|
if (n == 3) {
|
|
_colorForeground.a = (byte)255;
|
|
} else {
|
|
if (lua_isnumber(L, 4)) {
|
|
d = lua_tonumber(L, 4); _colorForeground.a = (byte)d;
|
|
} else {
|
|
_colorForeground.a = (byte)255;
|
|
}
|
|
}
|
|
result = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (result) {
|
|
luaTrace(L, "colorForeground", "%d %d %d %d", _colorForeground.r, _colorForeground.g, _colorForeground.b, _colorForeground.a);
|
|
} else {
|
|
luaTrace(L, "colorForeground", "Failed!");
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int apiDaphneGetHeight(lua_State *L) {
|
|
int y;
|
|
SDL_GetWindowSize(_window, NULL, &y);
|
|
luaTrace(L, "daphneGetHeight", "%d", y);
|
|
lua_pushinteger(L, y);
|
|
return 1;
|
|
}
|
|
|
|
|
|
int apiDaphneGetWidth(lua_State *L) {
|
|
int x;
|
|
SDL_GetWindowSize(_window, &x, NULL);
|
|
luaTrace(L, "daphneGetWidth", "%d", x);
|
|
lua_pushinteger(L, x);
|
|
return 1;
|
|
}
|
|
|
|
|
|
int apiDaphneScreenshot(lua_State *L) {
|
|
int x = 0;
|
|
int y = 0;
|
|
Uint32 format = 0;
|
|
char filename[128];
|
|
void *pixels = NULL;
|
|
SDL_Surface *surface = NULL;
|
|
SDL_Texture *texture = NULL;
|
|
|
|
(void)L;
|
|
|
|
while (x <= 999) {
|
|
snprintf(filename, 128, "singe%03d", x);
|
|
if (!utilFileExists(filename)) break;
|
|
x++;
|
|
}
|
|
if (x > 999) luaDie(L, "daphneScreenshot", "Seriously? You have 1000 screenshots in this folder? Remove some.");
|
|
|
|
luaTrace(L, "daphneScreenshot", "%s", filename);
|
|
|
|
texture = SDL_GetRenderTarget(_renderer);
|
|
if (SDL_QueryTexture(texture, &format, NULL, &x, &y) < 0) luaDie(L, "daphneScreenshot", "%s", SDL_GetError());
|
|
pixels = malloc((size_t)x * (size_t)y * SDL_BYTESPERPIXEL(format));
|
|
if (!pixels) luaDie(L, "daphneScreenshot", "Unable to allocate screenshot.");
|
|
if (SDL_RenderReadPixels(_renderer, NULL, format, pixels, (Uint16)x * SDL_BYTESPERPIXEL(format)) < 0) luaDie(L, "daphneScreenshot", "%s", SDL_GetError());
|
|
surface = SDL_CreateRGBSurfaceWithFormatFrom(pixels, x, y, SDL_BITSPERPIXEL(format), (Uint16)x * SDL_BYTESPERPIXEL(format), format);
|
|
if (!surface) luaDie(L, "daphneScreenshot", "%s", SDL_GetError());
|
|
if (IMG_SavePNG(surface, filename) < 0) luaDie(L, "daphneScreenshot", "%s", IMG_GetError());
|
|
SDL_FreeSurface(surface);
|
|
free(pixels);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int apiDebugPrint(lua_State *L) {
|
|
int n = lua_gettop(L);
|
|
|
|
if (n == 1) {
|
|
if (lua_isstring(L, 1)) {
|
|
luaTrace(L, "DebugPrint", "%s", lua_tostring(L, 1));
|
|
utilSay("%s", lua_tostring(L, 1));
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int apiDiscAudio(lua_State *L) {
|
|
int n = lua_gettop(L);
|
|
int channel = 0;
|
|
int left = 0;
|
|
int right = 0;
|
|
bool onOff = false;
|
|
bool result = false;
|
|
double d = 0;
|
|
|
|
if (n == 2) {
|
|
if (lua_isnumber(L, 1)) {
|
|
if (lua_isboolean(L, 2)) {
|
|
d = lua_tonumber(L, 1); channel = (int)d;
|
|
d = lua_toboolean(L, 2); onOff = (bool)d;
|
|
videoGetVolume(_videoHandle, &left, &right);
|
|
if (channel == 1) left = (onOff ? _confVolumeVldp : 0);
|
|
if (channel == 2) right = (onOff ? _confVolumeVldp : 0);
|
|
videoSetVolume(_videoHandle, left, right);
|
|
result = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (result) {
|
|
luaTrace(L, "discAudio", "%d %d", left, right);
|
|
} else {
|
|
luaTrace(L, "discAudio", "Failed!");
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int apiDiscChangeSpeed(lua_State *L) {
|
|
(void)L;
|
|
//***REMOVED***
|
|
luaTrace(L, "discChangeSpeed", "Unimplemented");
|
|
return 0;
|
|
}
|
|
|
|
|
|
int apiDiscGetFrame(lua_State *L) {
|
|
int frame = 0;
|
|
|
|
if (!_discStopped) {
|
|
frame = videoGetFrame(_videoHandle);
|
|
}
|
|
|
|
luaTrace(L, "discGetFrame", "%d", frame);
|
|
lua_pushinteger(L, frame);
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
int apiDiscPause(lua_State *L) {
|
|
(void)L;
|
|
if (!_discStopped) {
|
|
videoPause(_videoHandle);
|
|
luaTrace(L, "discPause", "");
|
|
} else {
|
|
luaTrace(L, "discPause", "Failed! Disc is stopped.");
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
int apiDiscPauseAtFrame(lua_State *L) {
|
|
// More RDG oddness. This appears to be identical to discSearch.
|
|
return apiDiscSearch(L);
|
|
}
|
|
|
|
|
|
int apiDiscPlay(lua_State *L) {
|
|
(void)L;
|
|
videoPlay(_videoHandle);
|
|
_discStopped = false;
|
|
luaTrace(L, "discPlay", "");
|
|
return 0;
|
|
}
|
|
|
|
|
|
int apiDiscSearch(lua_State *L) {
|
|
int n = lua_gettop(L);
|
|
int frame = 0;
|
|
bool result = false;
|
|
double d = 0;
|
|
|
|
// No matter the disc state, seek to the frame, display it, and pause.
|
|
|
|
if (n == 1) {
|
|
if (lua_isnumber(L, 1)) {
|
|
d = lua_tonumber(L, 1); frame = (int)d;
|
|
videoSeek(_videoHandle, frame);
|
|
videoPause(_videoHandle);
|
|
_discStopped = false;
|
|
result = true;
|
|
}
|
|
}
|
|
|
|
if (result) {
|
|
luaTrace(L, "discSearch", "%d", frame);
|
|
} else {
|
|
luaTrace(L, "discSearch", "Failed!");
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int apiDiscSearchBlanking(lua_State *L) {
|
|
(void)L;
|
|
//***REMOVED***
|
|
luaTrace(L, "discSearchBlanking", "Unimplemented");
|
|
return 0;
|
|
}
|
|
|
|
|
|
int apiDiscSetFps(lua_State *L) {
|
|
(void)L;
|
|
//***REMOVED***
|
|
luaTrace(L, "discSetFPS", "Unimplemented");
|
|
return 0;
|
|
}
|
|
|
|
|
|
int apiDiscSkipBackward(lua_State *L) {
|
|
int n = lua_gettop(L);
|
|
int frame = 0;
|
|
bool result = false;
|
|
double d = 0;
|
|
|
|
// If disc is not stopped, seek backwards to given frame. Do not change play/pause state.
|
|
|
|
if (!_discStopped) {
|
|
if (n == 1) {
|
|
if (lua_isnumber(L, 1)) {
|
|
d = lua_tonumber(L, 1); frame = videoGetFrame(_videoHandle) - (int)d;
|
|
videoSeek(_videoHandle, frame);
|
|
result = true;
|
|
}
|
|
}
|
|
} else {
|
|
luaTrace(L, "discSkipBackward", "Failed! Disc is stopped.");
|
|
return 0;
|
|
}
|
|
|
|
if (result) {
|
|
luaTrace(L, "discSkipBackward", "%d", frame);
|
|
} else {
|
|
luaTrace(L, "discSkipBackward", "Failed!");
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int apiDiscSkipBlanking(lua_State *L) {
|
|
(void)L;
|
|
//***REMOVED***
|
|
luaTrace(L, "discSkipBlanking", "Unimplemented");
|
|
return 0;
|
|
}
|
|
|
|
|
|
int apiDiscSkipForward(lua_State *L) {
|
|
int n = lua_gettop(L);
|
|
int frame = 0;
|
|
bool result = false;
|
|
double d = 0;
|
|
|
|
// If disc is not stopped, seek ahead to given frame. Do not change play/pause state.
|
|
|
|
if (!_discStopped) {
|
|
if (n == 1) {
|
|
if (lua_isnumber(L, 1)) {
|
|
d = lua_tonumber(L, 1); frame = videoGetFrame(_videoHandle) + (int)d;
|
|
videoSeek(_videoHandle, frame);
|
|
result = true;
|
|
}
|
|
}
|
|
} else {
|
|
luaTrace(L, "discSkipForward", "Failed! Disc is stopped.");
|
|
return 0;
|
|
}
|
|
|
|
if (result) {
|
|
luaTrace(L, "discSkipForward", "%d", frame);
|
|
} else {
|
|
luaTrace(L, "discSkipForward", "Failed!");
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int apiDiscSkipToFrame(lua_State *L) {
|
|
int n = lua_gettop(L);
|
|
int frame = 0;
|
|
bool result = false;
|
|
double d = 0;
|
|
|
|
// No matter disc state, seek to given frame and play.
|
|
|
|
if (n == 1) {
|
|
if (lua_isnumber(L, 1)) {
|
|
d = lua_tonumber(L, 1); frame = (int)d;
|
|
videoSeek(_videoHandle, frame);
|
|
videoPlay(_videoHandle);
|
|
_discStopped = false;
|
|
result = true;
|
|
}
|
|
}
|
|
|
|
if (result) {
|
|
luaTrace(L, "discSkipToFrame", "%d", frame);
|
|
} else {
|
|
luaTrace(L, "discSkipToFrame", "Failed!");
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int apiDiscStepBackward(lua_State *L) {
|
|
int frame = 0;
|
|
|
|
(void)L;
|
|
|
|
// No matter disc state, go back a frame. If playing, pause.
|
|
|
|
frame = videoGetFrame(_videoHandle) - 1;
|
|
videoSeek(_videoHandle, frame);
|
|
videoPause(_videoHandle);
|
|
luaTrace(L, "discStepBackward", "%d", frame);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int apiDiscStepForward(lua_State *L) {
|
|
int frame = 0;
|
|
|
|
(void)L;
|
|
|
|
// No matter disc state, go forward a frame. If playing, pause.
|
|
|
|
frame = videoGetFrame(_videoHandle) + 1;
|
|
videoSeek(_videoHandle, frame);
|
|
videoPause(_videoHandle);
|
|
luaTrace(L, "discStepForward", "%d", frame);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int apiDiscStop(lua_State *L) {
|
|
(void)L;
|
|
if (!_discStopped) {
|
|
videoPause(_videoHandle);
|
|
_discStopped = true;
|
|
_refreshDisplay = true;
|
|
luaTrace(L, "discStop", "");
|
|
} else {
|
|
luaTrace(L, "discStop", "Failed! Disc is stopped.");
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
int apiFontLoad(lua_State *L) {
|
|
int n = lua_gettop(L);
|
|
int result = -1;
|
|
int points = 0;
|
|
const char *name = NULL;
|
|
double d = 0;
|
|
FontT *font = NULL;
|
|
|
|
if (n == 2) {
|
|
if (lua_isstring(L, 1)) {
|
|
if (lua_isnumber(L, 2)) {
|
|
name = lua_tostring(L, 1);
|
|
d = lua_tonumber(L, 2); points = (int)d;
|
|
font = (FontT *)calloc(1, sizeof(FontT));
|
|
if (!font) luaDie(L, "fontLoad", "Unable to allocate new font.");
|
|
// Load this font.
|
|
font->font = TTF_OpenFont(name, points);
|
|
if (!font->font) luaDie(L, "fontLoad", "%s", TTF_GetError());
|
|
// Make it the current font and mark it as loaded.
|
|
font->id = _nextFontId;
|
|
result = _nextFontId++;
|
|
_fontCurrent = font;
|
|
HASH_ADD_INT(_fontList, id, font);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (result >= 0) {
|
|
luaTrace(L, "fontLoad", "%s %d", name, result);
|
|
} else {
|
|
luaTrace(L, "fontLoad", "Failed!");
|
|
}
|
|
|
|
lua_pushnumber(L, result);
|
|
return 1;
|
|
}
|
|
|
|
|
|
int apiFontPrint(lua_State *L) {
|
|
int n = lua_gettop(L);
|
|
const char *message = NULL;
|
|
double d = 0;
|
|
SDL_Surface *textSurface = NULL;
|
|
SDL_Rect dest;
|
|
|
|
if (n == 3) {
|
|
if (lua_isnumber(L, 1)) {
|
|
if (lua_isnumber(L, 2)) {
|
|
if (lua_isstring(L, 3)) {
|
|
if (_fontCurrent) {
|
|
d = lua_tonumber(L, 1); dest.x = (int)d;
|
|
d = lua_tonumber(L, 2); dest.y = (int)d;
|
|
textSurface = NULL;
|
|
message = lua_tostring(L, 3);
|
|
switch (_fontQuality) {
|
|
case 1:
|
|
textSurface = TTF_RenderText_Solid(_fontCurrent->font, message, _colorForeground);
|
|
break;
|
|
|
|
case 2:
|
|
textSurface = TTF_RenderText_Shaded(_fontCurrent->font, message, _colorForeground, _colorBackground);
|
|
break;
|
|
|
|
case 3:
|
|
textSurface = TTF_RenderText_Blended(_fontCurrent->font, message, _colorForeground);
|
|
break;
|
|
}
|
|
if (!textSurface) {
|
|
luaDie(L, "fontPrint", "Font surface is null!");
|
|
} else {
|
|
SDL_SetSurfaceBlendMode(textSurface, SDL_BLENDMODE_BLEND);
|
|
// Transparent index is 0
|
|
SDL_SetColorKey(textSurface, true, 0);
|
|
dest.w = textSurface->w;
|
|
dest.h = textSurface->h;
|
|
SDL_BlitSurface(textSurface, NULL, _overlay, &dest);
|
|
SDL_FreeSurface(textSurface);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (textSurface) {
|
|
luaTrace(L, "fontPrint", "%s", message);
|
|
} else {
|
|
luaTrace(L, "fontPrint", "Failed!");
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int apiFontQuality(lua_State *L) {
|
|
int n = lua_gettop(L);
|
|
bool result = false;
|
|
double d = 0;
|
|
|
|
if (n == 1) {
|
|
if (lua_isnumber(L, 1)) {
|
|
d = lua_tonumber(L, 1); _fontQuality = (int)d;
|
|
result = true;
|
|
}
|
|
}
|
|
|
|
if (result) {
|
|
luaTrace(L, "fontQuality", "%d", _fontQuality);
|
|
} else {
|
|
luaTrace(L, "fontQuality", "Failed!");
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int apiFontSelect(lua_State *L) {
|
|
int n = lua_gettop(L);
|
|
int id = -1;
|
|
double d = 0;
|
|
bool result = false;
|
|
FontT *font = NULL;
|
|
|
|
if (n == 1) {
|
|
if (lua_isnumber(L, 1)) {
|
|
d = lua_tonumber(L, 1);
|
|
id = (int)d;
|
|
HASH_FIND_INT(_fontList, &id, font);
|
|
if (!font) luaDie(L, "fontSelect", "No font at index %d in apiSpriteGetWidth.", id);
|
|
_fontCurrent = font;
|
|
result = true;
|
|
}
|
|
}
|
|
|
|
if (result) {
|
|
luaTrace(L, "fontSelect", "%d", _fontCurrent->id);
|
|
} else {
|
|
luaTrace(L, "fontSelect", "Failed!");
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int apiFontToSprite(lua_State *L) {
|
|
int n = lua_gettop(L);
|
|
int result = -1;
|
|
const char *message = NULL;
|
|
SpriteT *sprite = NULL;
|
|
|
|
if (n == 1) {
|
|
if (lua_isstring(L, 1)) {
|
|
if (_fontCurrent) {
|
|
// Create spirte
|
|
sprite = (SpriteT *)calloc(1, sizeof(SpriteT));
|
|
if (!sprite) luaDie(L, "fontToSprite", "Unable to allocate new text sprite.");
|
|
message = lua_tostring(L, 1);
|
|
switch (_fontQuality) {
|
|
case 1:
|
|
sprite->surface = TTF_RenderText_Solid(_fontCurrent->font, message, _colorForeground);
|
|
break;
|
|
|
|
case 2:
|
|
sprite->surface = TTF_RenderText_Shaded(_fontCurrent->font, message, _colorForeground, _colorBackground);
|
|
break;
|
|
|
|
case 3:
|
|
sprite->surface = TTF_RenderText_Blended(_fontCurrent->font, message, _colorForeground);
|
|
break;
|
|
}
|
|
|
|
if (!sprite->surface) {
|
|
luaDie(L, "fontToSprite", "Font surface is null!");
|
|
} else {
|
|
SDL_SetColorKey(sprite->surface, true, 0);
|
|
sprite->id = _nextSpriteId;
|
|
result = _nextSpriteId++;
|
|
HASH_ADD_INT(_spriteList, id, sprite);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (sprite->surface) {
|
|
luaTrace(L, "fontToSprite", "%d %s", result, message);
|
|
} else {
|
|
luaTrace(L, "fontToSprite", "Failed!");
|
|
}
|
|
|
|
lua_pushinteger(L, result);
|
|
return 1;
|
|
}
|
|
|
|
|
|
int apiOverlayClear(lua_State *L) {
|
|
(void)L;
|
|
SDL_FillRect(_overlay, NULL, SDL_MapRGBA(_overlay->format, _colorBackground.r, _colorBackground.g, _colorBackground.b, _colorBackground.a));
|
|
luaTrace(L, "overlayClear", "");
|
|
return 0;
|
|
}
|
|
|
|
|
|
int apiOverlayGetHeight(lua_State *L) {
|
|
luaTrace(L, "overlayGetWidth", "%d", _overlay->h);
|
|
lua_pushinteger(L, _overlay->h);
|
|
return 1;
|
|
}
|
|
|
|
|
|
int apiOverlayGetWidth(lua_State *L) {
|
|
luaTrace(L, "overlayGetWidth", "%d", _overlay->w);
|
|
lua_pushinteger(L, _overlay->w);
|
|
return 1;
|
|
}
|
|
|
|
|
|
int apiOverlayPrint(lua_State *L) {
|
|
int n = lua_gettop(L);
|
|
int i = 0;
|
|
char *s = NULL;
|
|
int length = 0;
|
|
SDL_Rect src;
|
|
SDL_Rect dst;
|
|
|
|
if (n == 3) {
|
|
if (lua_isnumber(L, 1)) {
|
|
if (lua_isnumber(L, 2)) {
|
|
if (lua_isstring(L, 3)) {
|
|
src.y = 0;
|
|
src.w = _consoleFontWidth;
|
|
src.h = _consoleFontHeight;
|
|
dst.x = lua_tonumber(L, 1);
|
|
dst.y = lua_tonumber(L, 2);
|
|
dst.w = _consoleFontWidth;
|
|
dst.h = _consoleFontHeight;
|
|
s = (char *)lua_tostring(L, 3);
|
|
if (strlen(s) < (unsigned int)((_overlay->w - dst.x) / _consoleFontWidth)) {
|
|
length = strlen(s);
|
|
} else {
|
|
length = (_overlay->w - dst.x) / _consoleFontWidth;
|
|
}
|
|
for (i=0; i<length; i++) {
|
|
src.x = s[i] * _consoleFontWidth;
|
|
SDL_BlitSurface(_consoleFontSurface, &src, _overlay, &dst);
|
|
dst.x += _consoleFontWidth;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int apiSoundLoad(lua_State *L) {
|
|
int n = lua_gettop(L);
|
|
int result = -1;
|
|
const char *name = NULL;
|
|
SoundT *sound = NULL;
|
|
|
|
if (n == 1) {
|
|
if (lua_isstring(L, 1)) {
|
|
sound = (SoundT *)calloc(1, sizeof(SoundT));
|
|
if (!sound) luaDie(L, "soundLoad", "Unable to allocate new sound.");
|
|
name = lua_tostring(L, 1);
|
|
sound->chunk = Mix_LoadWAV(name);
|
|
if (!sound->chunk) luaDie(L, "soundLoad", "%s", Mix_GetError());
|
|
sound->id = _nextSoundId;
|
|
result = _nextSoundId++;
|
|
HASH_ADD_INT(_soundList, id, sound);
|
|
}
|
|
}
|
|
|
|
if (sound) {
|
|
luaTrace(L, "soundLoad", "%d %s", result, name);
|
|
} else {
|
|
luaTrace(L, "soundLoad", "Failed!");
|
|
}
|
|
|
|
lua_pushnumber(L, result);
|
|
return 1;
|
|
}
|
|
|
|
|
|
int apiSoundPlay(lua_State *L) {
|
|
int n = lua_gettop(L);
|
|
int result = -1;
|
|
int id = -1;
|
|
double d = 0;
|
|
SoundT *sound = NULL;
|
|
|
|
if (n == 1) {
|
|
if (lua_isnumber(L, 1)) {
|
|
d = lua_tonumber(L, 1); id = (int)d;
|
|
// Get our sound structure
|
|
HASH_FIND_INT(_soundList, &id, sound);
|
|
if (!sound) luaDie(L, "soundPlay", "No sound at index %d in apiSoundPlay.", id);
|
|
// Play it
|
|
result = Mix_PlayChannel(-1, sound->chunk, 0);
|
|
Mix_Volume(result, _effectsVolume * 2);
|
|
}
|
|
}
|
|
|
|
if (sound) {
|
|
luaTrace(L, "soundPlay", "%d", result);
|
|
} else {
|
|
luaTrace(L, "soundPlay", "Failed!");
|
|
}
|
|
|
|
lua_pushnumber(L, result);
|
|
return 1;
|
|
}
|
|
|
|
|
|
int apiSoundPause(lua_State *L) {
|
|
// Instructs Daphne to pause a given sample from playing.
|
|
// User must feed the sound handle on the lua side.
|
|
// e.g. lua code,
|
|
//
|
|
// thisHandle = soundPlay(mySound)
|
|
// soundPause(thisHandle)
|
|
//
|
|
// Function returns true if sample was paused, false otherwise.
|
|
//
|
|
// --rdg
|
|
|
|
int n = lua_gettop(L);
|
|
int channel = -1;
|
|
double d = 0;
|
|
bool result = false;
|
|
|
|
if (n == 1) {
|
|
if (lua_isnumber(L, 1)) {
|
|
d = lua_tonumber(L, 1); channel = (int)d;
|
|
Mix_Pause(channel);
|
|
result = true;
|
|
}
|
|
}
|
|
|
|
if (result) {
|
|
luaTrace(L, "soundPause", "%d", channel);
|
|
} else {
|
|
luaTrace(L, "soundPause", "Failed!");
|
|
}
|
|
|
|
lua_pushboolean(L, result);
|
|
return 1;
|
|
}
|
|
|
|
|
|
int apiSoundResume(lua_State *L) {
|
|
// Instructs Daphne to unpause a sound that was previously paused.
|
|
// User must feed the sound handle on the lua side.
|
|
// e.g. lua code,
|
|
//
|
|
// thisHandle = soundPlay(mySound)
|
|
// soundPause(thisHandle)
|
|
// soundResume(thisHandle)
|
|
//
|
|
// Function returns true if sample was unpaused, false otherwise.
|
|
//
|
|
// --rdg
|
|
|
|
int n = lua_gettop(L);
|
|
int channel = -1;
|
|
double d = 0;
|
|
bool result = false;
|
|
|
|
if (n == 1) {
|
|
if (lua_isnumber(L, 1)) {
|
|
d = lua_tonumber(L, 1); channel = (int)d;
|
|
Mix_Resume(channel);
|
|
result = true;
|
|
}
|
|
}
|
|
|
|
if (result) {
|
|
luaTrace(L, "soundResume", "%d", channel);
|
|
} else {
|
|
luaTrace(L, "soundResume", "Failed!");
|
|
}
|
|
|
|
lua_pushboolean(L, result);
|
|
return 1;
|
|
}
|
|
|
|
|
|
int apiSoundIsPlaying(lua_State *L) {
|
|
// Checks to see if a certain sound has finished playing.
|
|
// User must feed the sound handle on the lua side.
|
|
// e.g. lua code,
|
|
//
|
|
// thisHandle = soundPlay(mySound)
|
|
// if (soundIsPlaying(thisSound)) then do something ... end
|
|
//
|
|
// Function returns true if sample is still playing, false otherwise.
|
|
//
|
|
// --rdg
|
|
|
|
int n = lua_gettop(L);
|
|
int channel = -1;
|
|
double d = 0;
|
|
bool result = false;
|
|
|
|
if (n == 1) {
|
|
if (lua_isnumber(L, 1)) {
|
|
d = lua_tonumber(L, 1); channel = (int)d;
|
|
result = (bool)Mix_Playing(channel);
|
|
}
|
|
}
|
|
|
|
if (result) {
|
|
luaTrace(L, "soundIsPlaying", "%d %d", channel, result);
|
|
} else {
|
|
luaTrace(L, "soundIsPlaying", "Failed!");
|
|
}
|
|
|
|
lua_pushboolean(L, result);
|
|
return 1;
|
|
}
|
|
|
|
|
|
int apiSoundStop(lua_State *L) {
|
|
// Instructs Daphne to end a sound early.
|
|
// User must feed the sound handle on the lua side.
|
|
// e.g. lua code,
|
|
//
|
|
// thisHandle = soundPlay(mySound)
|
|
// soundStop(thisHandle)
|
|
//
|
|
// Function returns true if sample was stopped, false otherwise.
|
|
// NOTE: thisHandle will be invalidated as a result of this function.
|
|
// Lua doesn't do variables by reference, so it is
|
|
// up to the user to keep track of sound handles on the lua script.
|
|
//
|
|
// --rdg
|
|
|
|
int n = lua_gettop(L);
|
|
int channel = -1;
|
|
double d = 0;
|
|
bool result = false;
|
|
|
|
if (n == 1) {
|
|
if (lua_isnumber(L, 1)) {
|
|
d = lua_tonumber(L, 1); channel = (int)d;
|
|
Mix_HaltChannel(channel);
|
|
result = true;
|
|
}
|
|
}
|
|
|
|
if (result) {
|
|
luaTrace(L, "soundStop", "%d", channel);
|
|
} else {
|
|
luaTrace(L, "soundStop", "Failed!");
|
|
}
|
|
|
|
lua_pushboolean(L, result);
|
|
return 1;
|
|
}
|
|
|
|
|
|
int apiSoundSetVolume(lua_State *L) {
|
|
// Allows manipulation of sample volume.
|
|
// Valid values range from 0 to 63
|
|
// e.g. lua code,
|
|
//
|
|
// soundSetVolume(32)
|
|
//
|
|
// Function returns nothing.
|
|
//
|
|
// --rdg
|
|
|
|
int n = lua_gettop(L);
|
|
int thisValue = 0;
|
|
double d = 0;
|
|
bool result = false;
|
|
|
|
if (n == 1) {
|
|
if (lua_isnumber(L, 1)) {
|
|
d = lua_tonumber(L, 1); thisValue = (int)d;
|
|
if (thisValue >= 0 && thisValue <= AUDIO_MAX_VOLUME) {
|
|
_effectsVolume = thisValue;
|
|
Mix_Volume(-1, _effectsVolume * 2);
|
|
} else {
|
|
luaDie(L, "soundSetVolume", "Invalid sound volume value.");
|
|
}
|
|
}
|
|
}
|
|
|
|
if (result) {
|
|
luaTrace(L, "soundSetVolume", "%d", _effectsVolume);
|
|
} else {
|
|
luaTrace(L, "soundSetVolume", "Failed!");
|
|
}
|
|
|
|
lua_pushboolean(L, result);
|
|
return 0;
|
|
}
|
|
|
|
|
|
int apiSoundGetVolume(lua_State *L) {
|
|
// Returns the current sample volume value.
|
|
// e.g. lua code,
|
|
//
|
|
// local iVolume = soundGetVolume()
|
|
//
|
|
// Function returns an integer value ranging from 0 to 63.
|
|
//
|
|
// --rdg
|
|
|
|
luaTrace(L, "soundGetVolume", "%d", _effectsVolume);
|
|
|
|
lua_pushinteger(L, _effectsVolume);
|
|
return 1;
|
|
}
|
|
|
|
|
|
int apiSoundFullStop(lua_State *L) {
|
|
// Clears the audio queue of any samples actively playing.
|
|
// No parameters needed. Function returns nothing.
|
|
// e.g. lua code,
|
|
//
|
|
// soundFullStop()
|
|
|
|
(void)L;
|
|
|
|
luaTrace(L, "soundFullStop", "");
|
|
|
|
Mix_HaltChannel(-1);
|
|
return 0;
|
|
}
|
|
|
|
|
|
int apiSpriteDraw(lua_State *L) {
|
|
int n = lua_gettop(L);
|
|
int id = -1;
|
|
double d = 0;
|
|
SpriteT *sprite = NULL;
|
|
SDL_Rect dest;
|
|
|
|
if (n == 3) {
|
|
if (lua_isnumber(L, 1)) {
|
|
if (lua_isnumber(L, 2)) {
|
|
if (lua_isnumber(L, 3)) {
|
|
d = lua_tonumber(L, 1); dest.x = (int)d;
|
|
d = lua_tonumber(L, 2); dest.y = (int)d;
|
|
d = lua_tonumber(L, 3); id = (int)d;
|
|
HASH_FIND_INT(_spriteList, &id, sprite);
|
|
if (!sprite) luaDie(L, "spriteDraw", "No sprite at index %d in apiSpriteGetWidth.", id);
|
|
dest.w = sprite->surface->w;
|
|
dest.h = sprite->surface->h;
|
|
SDL_BlitSurface(sprite->surface, NULL, _overlay, &dest);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (id >= 0) {
|
|
luaTrace(L, "spriteDraw", "%d %d %d %d %d", id, dest.x, dest.y, dest.w, dest.h);
|
|
} else {
|
|
luaTrace(L, "spriteDraw", "Failed!");
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int apiSpriteGetHeight(lua_State *L) {
|
|
int n = lua_gettop(L);
|
|
int result = -1;
|
|
int id = -1;
|
|
double d;
|
|
SpriteT *sprite = NULL;
|
|
|
|
if (n == 1) {
|
|
if (lua_isstring(L, 1)) {
|
|
d = lua_tonumber(L, 1); id = (int)d;
|
|
// Get our sprite structure
|
|
HASH_FIND_INT(_spriteList, &id, sprite);
|
|
if (!sprite) luaDie(L, "spriteGetHeight", "No sprite at index %d in apiSpriteGetWidth.", id);
|
|
result = sprite->surface->h;
|
|
}
|
|
}
|
|
|
|
if (result >= 0) {
|
|
luaTrace(L, "spriteGetHeight", "%d", result);
|
|
} else {
|
|
luaTrace(L, "spriteGetHeight", "Failed!");
|
|
}
|
|
|
|
lua_pushinteger(L, result);
|
|
return 1;
|
|
}
|
|
|
|
|
|
int apiSpriteGetWidth(lua_State *L) {
|
|
int n = lua_gettop(L);
|
|
int result = -1;
|
|
int id = -1;
|
|
double d;
|
|
SpriteT *sprite = NULL;
|
|
|
|
lua_Debug ar;
|
|
lua_getstack(L, 1, &ar);
|
|
lua_getinfo(L, "nSl", &ar);
|
|
|
|
if (n == 1) {
|
|
if (lua_isstring(L, 1)) {
|
|
d = lua_tonumber(L, 1); id = (int)d;
|
|
// Get our sprite structure
|
|
HASH_FIND_INT(_spriteList, &id, sprite);
|
|
if (!sprite) luaDie(L, "spriteGetWidth", "No sprite at index %d in apiSpriteGetWidth.", id);
|
|
result = sprite->surface->w;
|
|
}
|
|
}
|
|
|
|
if (result >= 0) {
|
|
luaTrace(L, "spriteGetWidth", "%d", result);
|
|
} else {
|
|
luaTrace(L, "spriteGetWidth", "Failed!");
|
|
}
|
|
|
|
lua_pushinteger(L, result);
|
|
return 1;
|
|
}
|
|
|
|
|
|
int apiSpriteLoad(lua_State *L) {
|
|
int n = lua_gettop(L);
|
|
int result = -1;
|
|
const char *name = NULL;
|
|
SpriteT *sprite = NULL;
|
|
|
|
if (n == 1) {
|
|
if (lua_isstring(L, 1)) {
|
|
sprite = (SpriteT *)calloc(1, sizeof(SpriteT));
|
|
if (!sprite) luaDie(L, "spriteLoad", "Unable to allocate new sprite.");
|
|
name = lua_tostring(L, 1);
|
|
sprite->surface = IMG_Load(name);
|
|
if (!sprite->surface) luaDie(L, "spriteLoad", "%s", IMG_GetError());
|
|
SDL_SetColorKey(sprite->surface, true, 0);
|
|
sprite->id = _nextSpriteId;
|
|
result = _nextSpriteId++;
|
|
HASH_ADD_INT(_spriteList, id, sprite);
|
|
}
|
|
}
|
|
|
|
if (sprite->surface) {
|
|
luaTrace(L, "spriteLoad", "%d %s", result, name);
|
|
} else {
|
|
luaTrace(L, "spriteLoad", "Failed!");
|
|
}
|
|
|
|
lua_pushnumber(L, result);
|
|
return 1;
|
|
}
|
|
|
|
|
|
int apiVldpGetHeight(lua_State *L) {
|
|
int height = videoGetHeight(_videoHandle);
|
|
luaTrace(L, "vldpGetHeight", "%d", height);
|
|
lua_pushinteger(L, height);
|
|
return 1;
|
|
}
|
|
|
|
|
|
int apiVldpGetPixel(lua_State *L) {
|
|
int n = lua_gettop(L);
|
|
double d = 0;
|
|
bool result = false;
|
|
byte pixel[SDL_BYTESPERPIXEL(SDL_PIXELFORMAT_BGRA32)];
|
|
SDL_Rect rect;
|
|
|
|
if (n == 2) {
|
|
if (lua_isnumber(L, 1)) {
|
|
if (lua_isnumber(L, 2)) {
|
|
rect.h = 1;
|
|
rect.w = 1;
|
|
d = lua_tonumber(L, 1); rect.x = (int)(d / _overlayScaleX);
|
|
d = lua_tonumber(L, 2); rect.y = (int)(d / _overlayScaleY);
|
|
if (SDL_SetRenderTarget(_renderer, _videoTexture) < 0) luaDie(L, "vldpGetPixel", "%s", SDL_GetError());
|
|
if (SDL_RenderReadPixels(_renderer, &rect, SDL_PIXELFORMAT_BGRA32, pixel, SDL_BYTESPERPIXEL(SDL_PIXELFORMAT_BGRA32) * videoGetWidth(_videoHandle)) < 0) luaDie(L, "vldpGetPixel", "%s", SDL_GetError());
|
|
if (SDL_SetRenderTarget(_renderer, NULL) < 0) luaDie(L, "vldpGetPixel", "%s", SDL_GetError());
|
|
result = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (result) {
|
|
luaTrace(L, "vldpGetPixel", "%d %d %d %d %d", rect.x, rect.y, pixel[2], pixel[1], pixel[0]);
|
|
lua_pushinteger(L, (int)pixel[2]); // R
|
|
lua_pushinteger(L, (int)pixel[1]); // G
|
|
lua_pushinteger(L, (int)pixel[0]); // B
|
|
} else {
|
|
luaTrace(L, "vldpGetPixel", "Failed!");
|
|
lua_pushinteger(L, -1);
|
|
lua_pushinteger(L, -1);
|
|
lua_pushinteger(L, -1);
|
|
}
|
|
|
|
return 3;
|
|
}
|
|
|
|
|
|
int apiVldpGetWidth(lua_State *L) {
|
|
int width = videoGetWidth(_videoHandle);
|
|
luaTrace(L, "vldpGetHeight", "%d", width);
|
|
lua_pushinteger(L, width);
|
|
return 1;
|
|
}
|
|
|
|
|
|
int apiVldpVerbose(lua_State *L) {
|
|
/*
|
|
* Enables/Disables writing of VLDP playback activity to daphne_log.txt
|
|
* Enabled by default.
|
|
*/
|
|
(void)L;
|
|
|
|
//***REMOVED***
|
|
luaTrace(L, "vldpVerbose", "Unimplemented");
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int apiKeyboardGetMode(lua_State *L) {
|
|
luaTrace(L, "keyboardGetMode", "%d", _keyboardMode);
|
|
lua_pushinteger(L, _keyboardMode);
|
|
return 1;
|
|
}
|
|
|
|
|
|
int apiKeyboardSetMode(lua_State *L) {
|
|
|
|
bool result = false;
|
|
|
|
/*
|
|
* Singe can scan keyboard input in two ways:
|
|
*
|
|
* MODE_NORMAL - Singe will only check for keys defined
|
|
* in daphne.ini. This is the default behavior.
|
|
*
|
|
* MODE_FULL - Singe will scan the keyboard for most keypresses.
|
|
*
|
|
*/
|
|
|
|
int n = lua_gettop(L);
|
|
double d = 0;
|
|
|
|
if (n == 1) {
|
|
if (lua_isnumber(L, 1)) {
|
|
d = lua_tonumber(L, 1); _keyboardMode = (int)d;
|
|
result = true;
|
|
}
|
|
}
|
|
|
|
if (result) {
|
|
luaTrace(L, "keyboardSetMode", "%d", _keyboardMode);
|
|
} else {
|
|
luaTrace(L, "keyboardSetMode", "Failed!");
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int apiMouseEnable(lua_State *L) {
|
|
// Enables mouse monitoring
|
|
(void)L;
|
|
luaTrace(L, "mouseEnable", "%d", _confNoMouse);
|
|
_mouseEnabled = (bool)!_confNoMouse;
|
|
return 0;
|
|
}
|
|
|
|
|
|
int apiMouseDisable(lua_State *L) {
|
|
// Disables mouse monitoring
|
|
(void)L;
|
|
luaTrace(L, "mouseDisable", "");
|
|
_mouseEnabled = false;
|
|
return 0;
|
|
}
|
|
|
|
|
|
int apiMouseSetMode(lua_State *L) {
|
|
// Sets the scanning mode for mouse input.
|
|
// Can be one of two values:
|
|
//
|
|
// SINGLE_MOUSE = 100
|
|
// MANY_MOUSE = 200
|
|
//
|
|
// Be sure to add these constant declarations to your framework.singe
|
|
// By default Singe starts in single mouse mode.
|
|
// Use this command if you need to scan multiple mice.
|
|
// e.g. lua code,
|
|
//
|
|
// mouseSetMode(MANY_MOUSE)
|
|
//
|
|
// Function returns TRUE is mode set was successful, FALSE otherwise.
|
|
//
|
|
// --rdg
|
|
|
|
int n = lua_gettop(L);
|
|
double d = 0;
|
|
bool result = false;
|
|
|
|
if (n == 1) {
|
|
if (lua_isnumber(L, 1)) {
|
|
d = lua_tonumber(L, 1); _mouseMode = (int)d;
|
|
result = true;
|
|
}
|
|
}
|
|
|
|
if (result) {
|
|
luaTrace(L, "mouseSetMode", "%d", _mouseMode);
|
|
} else {
|
|
luaTrace(L, "mouseSetMode", "Failed!");
|
|
}
|
|
|
|
lua_pushboolean(L, result);
|
|
return 1;
|
|
}
|
|
|
|
|
|
int apiMouseHowMany(lua_State *L) {
|
|
luaTrace(L, "mouseHowMany", "%d", _mouseCount);
|
|
lua_pushinteger(L, _mouseCount);
|
|
return 1;
|
|
}
|
|
|
|
|
|
int apiDiscGetState(lua_State *L) {
|
|
int isPlaying = -1;
|
|
|
|
/*
|
|
* Returns the status of the vldp
|
|
* Values returned are
|
|
* based on the following enumeration (found in ldp.h).
|
|
*
|
|
* LDP_ERROR = 0
|
|
* LDP_SEARCHING = 1
|
|
* LDP_STOPPED = 2
|
|
* LDP_PLAYING = 3
|
|
* LDP_PAUSE = 4
|
|
*
|
|
*/
|
|
|
|
// Our player isn't as sophisticated as the one in Daphne
|
|
isPlaying = videoIsPlaying(_videoHandle);
|
|
luaTrace(L, "discGetState", "%s", _discStopped ? "Stopped" : (isPlaying ? "Playing" : "Paused"));
|
|
lua_pushinteger(L, _discStopped ? LDP_STOPPED : (isPlaying ? LDP_PLAYING : LDP_PAUSE));
|
|
return 1;
|
|
}
|
|
|
|
|
|
int apiSingeGetPauseFlag(lua_State *L) {
|
|
/*
|
|
* This function returns g_pause_state's value to the lua script.
|
|
*
|
|
* Sometimes game logic pauses the game (which implies pausing video playback).
|
|
* When implementing a pause state it is possible for the player
|
|
* to resume playblack at moments where the game is not intended to.
|
|
* Boolean g_pause state is an internal variable that keeps track
|
|
* of this. It's set to true whenever sep_pre_pause is called.
|
|
* It's set to false whenever sep_pre_play or sep_skip_to_frame is called.
|
|
*
|
|
* A lua programmer can use this to prevent resuming playback accidentally.
|
|
*/
|
|
luaTrace(L, "singeGetPauseFlag", "%d", _pauseState);
|
|
lua_pushboolean(L, _pauseState);
|
|
return 1;
|
|
}
|
|
|
|
|
|
int apiSingeSetPauseFlag(lua_State *L) {
|
|
int n = lua_gettop(L);
|
|
bool result = false;
|
|
|
|
if (n == 1) {
|
|
if (lua_isboolean(L, 1)) {
|
|
_pauseState = (bool)lua_toboolean(L, 1);
|
|
result = true;
|
|
}
|
|
}
|
|
|
|
if (result) {
|
|
luaTrace(L, "singeSetPauseFlag", "%d", _pauseState);
|
|
} else {
|
|
luaTrace(L, "singeSetPauseFlag", "Failed!");
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int apiSingeEnablePauseKey(lua_State *L) {
|
|
(void)L;
|
|
luaTrace(L, "singeEnablePauseKey", "");
|
|
_pauseEnabled = true;
|
|
return 0;
|
|
}
|
|
|
|
|
|
int apiSingeDisablePauseKey(lua_State *L) {
|
|
(void)L;
|
|
luaTrace(L, "singeDisablePauseKey", "");
|
|
_pauseEnabled = false;
|
|
return 0;
|
|
}
|
|
|
|
|
|
int apiSingeQuit(lua_State *L) {
|
|
(void)L;
|
|
luaTrace(L, "singeQuit", "");
|
|
_running = false;
|
|
return 0;
|
|
}
|
|
|
|
|
|
int apiSingeVersion(lua_State *L) {
|
|
luaTrace(L, "singeVersion", "%f", SINGE_VERSION);
|
|
lua_pushnumber(L, SINGE_VERSION);
|
|
return 1;
|
|
}
|
|
|
|
|
|
int apiSingeSetGameName(lua_State *L) {
|
|
// Adds the name of the singe game to the window's title bar.
|
|
// Valid value is a string no longer than 25 characters.
|
|
// e.g. lua code,
|
|
//
|
|
// singeSetGameName("My FMV game")
|
|
//
|
|
// Function returns nothing.
|
|
//
|
|
// --rdg
|
|
|
|
int n = lua_gettop(L);
|
|
bool result = false;
|
|
char thisName[MAX_TITLE_LENGTH];
|
|
|
|
if (n == 1) {
|
|
if (lua_isstring(L, 1)) {
|
|
sprintf(thisName,"%.40s", lua_tostring(L, 1)); // Need a better way to do this...
|
|
SDL_SetWindowTitle(_window, thisName);
|
|
result = true;
|
|
}
|
|
}
|
|
|
|
if (result) {
|
|
luaTrace(L, "singeSetGameName", "%s", thisName);
|
|
} else {
|
|
luaTrace(L, "singeSetGameName", "Failed!");
|
|
}
|
|
|
|
lua_pushboolean(L, result);
|
|
return 0;
|
|
}
|
|
|
|
|
|
int apiSingeGetScriptPath(lua_State *L) {
|
|
// Returns the path to the singe script.
|
|
// e.g. lua code,
|
|
//
|
|
// sGameDirectory = singeGetScriptPath()
|
|
//
|
|
|
|
luaTrace(L, "singeSetScriptPath", "%s", _confScriptFile);
|
|
lua_pushstring(L, _confScriptFile);
|
|
return 1;
|
|
}
|
|
|
|
|
|
void callLua(const char *func, const char *sig, ...) {
|
|
va_list vl;
|
|
bool done = false;
|
|
int narg;
|
|
int nres;
|
|
int popCount;
|
|
double d;
|
|
const int top = lua_gettop(_luaContext);
|
|
|
|
va_start(vl, sig);
|
|
|
|
// Get Function
|
|
lua_getglobal(_luaContext, func);
|
|
if (!lua_isfunction(_luaContext, -1)) {
|
|
// Function does not exist. Bail.
|
|
lua_settop(_luaContext, top);
|
|
return;
|
|
}
|
|
|
|
utilTrace("%s", func);
|
|
|
|
// Push Arguments
|
|
narg = 0;
|
|
while ((*sig) && (!done)) {
|
|
switch (*sig++) {
|
|
|
|
case 'd': // Double
|
|
lua_pushnumber(_luaContext, va_arg(vl, double));
|
|
break;
|
|
|
|
case 'i': // Int
|
|
lua_pushinteger(_luaContext, va_arg(vl, int));
|
|
break;
|
|
|
|
case 's': // String
|
|
lua_pushstring(_luaContext, va_arg(vl, char *));
|
|
break;
|
|
|
|
case '>':
|
|
done = true;
|
|
break;
|
|
|
|
default:
|
|
utilDie("Invalid argument option (%c)", *(sig - 1));
|
|
}
|
|
if (!done) {
|
|
narg++;
|
|
luaL_checkstack(_luaContext, 1, "Too many arguments");
|
|
}
|
|
}
|
|
|
|
// Do the call
|
|
popCount = nres = (int)strlen(sig); // Number of expected results
|
|
if (lua_pcall(_luaContext, narg, nres, 0) != 0) {
|
|
utilDie("Error executing function '%s': %s", func, lua_tostring(_luaContext, -1));
|
|
}
|
|
|
|
// Retrieve results
|
|
nres = -nres; // Stack index of first result
|
|
while (*sig) {
|
|
switch (*sig++) {
|
|
|
|
case 'd': // Double
|
|
if (!lua_isnumber(_luaContext, nres)) {
|
|
utilDie("Wrong result type");
|
|
}
|
|
*va_arg(vl, double *) = lua_tonumber(_luaContext, nres);
|
|
break;
|
|
|
|
case 'i': // Int
|
|
if (!lua_isnumber(_luaContext, nres)) {
|
|
utilDie("Wrong result type");
|
|
}
|
|
d = lua_tonumber(_luaContext, nres); *va_arg(vl, int *) = (int)d;
|
|
break;
|
|
|
|
case 's': // String
|
|
if (!lua_isstring(_luaContext, nres)) {
|
|
utilDie("Wrong result type");
|
|
}
|
|
*va_arg(vl, const char **) = lua_tostring(_luaContext, nres);
|
|
break;
|
|
|
|
default:
|
|
utilDie("Invalid option (%c)", *(sig - 1));
|
|
}
|
|
nres++;
|
|
}
|
|
va_end(vl);
|
|
|
|
if (popCount > 0) {
|
|
lua_pop(_luaContext, popCount);
|
|
}
|
|
}
|
|
|
|
|
|
void channelFinished(int channel) {
|
|
callLua("onSoundCompleted", "i", channel);
|
|
}
|
|
|
|
|
|
void luaDie(lua_State *L, char *method, char *fmt, ...) {
|
|
va_list args;
|
|
lua_Debug ar;
|
|
char *string1 = NULL;
|
|
char *string2 = NULL;
|
|
|
|
lua_getstack(L, 1, &ar);
|
|
lua_getinfo(L, "nSl", &ar);
|
|
string1 = utilCreateString("%d:%s: ", ar.currentline, method);
|
|
if (!string1) utilDie("Unable to allocate first trace string.");
|
|
va_start(args, fmt);
|
|
string2 = utilCreateStringVArgs(fmt, args);
|
|
if (!string2) utilDie("Unable to allocate second trace string.");
|
|
va_end(args);
|
|
utilTrace("%s%s", string1, string2);
|
|
utilDie("%s%s", string1, string2);
|
|
// Can't free strings - we never get here.
|
|
}
|
|
|
|
|
|
int luaError(lua_State *L) {
|
|
lua_Debug ar;
|
|
int level = 0;
|
|
|
|
utilSay("Singe has panicked! Very bad!");
|
|
utilSay("Error: %s", lua_tostring(L, -1));
|
|
|
|
utilSay("Stack trace:");
|
|
while (lua_getstack(L, level, &ar) != 0) {
|
|
lua_getinfo(L, "nSl", &ar);
|
|
utilSay(" %d: function `%s' at line %d %s", level, ar.name, ar.currentline, ar.short_src);
|
|
level++;
|
|
}
|
|
utilSay("Trace complete.");
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
void luaTrace(lua_State *L, char *method, char *fmt, ...) {
|
|
va_list args;
|
|
lua_Debug ar;
|
|
char *string1 = NULL;
|
|
char *string2 = NULL;
|
|
|
|
if (utilTraceFile) {
|
|
lua_getstack(L, 1, &ar);
|
|
lua_getinfo(L, "nSl", &ar);
|
|
string1 = utilCreateString("%d:%s: ", ar.currentline, method);
|
|
if (!string1) utilDie("Unable to allocate first trace string.");
|
|
va_start(args, fmt);
|
|
string2 = utilCreateStringVArgs(fmt, args);
|
|
if (!string2) utilDie("Unable to allocate second trace string.");
|
|
va_end(args);
|
|
utilSay("%s%s", string1, string2);
|
|
utilTrace("%s%s", string1, string2);
|
|
free(string2);
|
|
free(string1);
|
|
}
|
|
}
|
|
|
|
|
|
void processKey(bool down, int keysym) {
|
|
int move;
|
|
|
|
if (_keyboardMode == KEYBD_NORMAL) {
|
|
// Daphne keys
|
|
for (move=0; move<SWITCH_COUNT; move++) {
|
|
if ((keysym == _keyDefs[move][0]) || (keysym == _keyDefs[move][1])) {
|
|
if (!down) {
|
|
if ((move == SWITCH_PAUSE) && (_pauseEnabled)) {
|
|
//***TODO*** g_game->toggle_game_pause();
|
|
}
|
|
if ((move == SWITCH_QUIT) || (keysym == SDLK_ESCAPE)) {
|
|
_running = false;
|
|
}
|
|
if (move == SWITCH_SCREENSHOT) {
|
|
//***TODO*** g_ldp->request_screenshot();
|
|
}
|
|
}
|
|
if (move != SWITCH_PAUSE) {
|
|
callLua(down ? "onInputPressed" : "onInputReleased", "ii", move, NOMOUSE);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
//***TODO*** Why is RDG filtering keys?
|
|
// Full keyboard
|
|
if (keysym >= SDLK_a && keysym <= SDLK_z)
|
|
callLua(down ? "onInputPressed" : "onInputReleased", "ii", keysym, NOMOUSE);
|
|
// check to see if key is a number on the top row of the keyboard (not keypad)
|
|
else if (keysym >= SDLK_MINUS && keysym <= SDLK_9)
|
|
callLua(down ? "onInputPressed" : "onInputReleased", "ii", keysym, NOMOUSE);
|
|
// numeric keypad keys
|
|
else if (keysym >= SDLK_KP_0 && keysym <= SDLK_KP_EQUALS)
|
|
callLua(down ? "onInputPressed" : "onInputReleased", "ii", keysym, NOMOUSE);
|
|
// arrow keys and insert, delete, home, end, pgup, pgdown
|
|
else if (keysym >= SDLK_UP && keysym <= SDLK_PAGEDOWN)
|
|
callLua(down ? "onInputPressed" : "onInputReleased", "ii", keysym, NOMOUSE);
|
|
// function keys
|
|
else if (keysym >= SDLK_F1 && keysym <= SDLK_F15)
|
|
callLua(down ? "onInputPressed" : "onInputReleased", "ii", keysym, NOMOUSE);
|
|
// Key state modifier keys (left and right ctrls, alts)
|
|
else if (keysym >= SDLK_NUMLOCKCLEAR && keysym <= SDLK_LGUI)
|
|
callLua(down ? "onInputPressed" : "onInputReleased", "ii", keysym, NOMOUSE);
|
|
// International keys
|
|
/*
|
|
else if (keysym >= SDLK_WORLD_0 && keysym <= SDLK_WORLD_95)
|
|
callLua(down ? "onInputPressed" : "onInputReleased", "ii", keysym, NOMOUSE);
|
|
*/
|
|
else {
|
|
/*
|
|
* SDLK_BACKSPACE, SDLK_TAB, SDLK_RETURN, SDLK_PAUSE,
|
|
* SDLK_SPACE, SDLK_QUOTE, SDLK_COMMA, SDLK_SEMICOLON,
|
|
* SDLK_EQUALS, SDLK_LEFTBRACKET, SDLK_RIGHTBRACKET,
|
|
* SDLK_BACKSLASH, SDLK_SLASH, SDLK_DELETE, SDLK_PERIOD };
|
|
*/
|
|
for (move=0; move<KEYBD_ARRAY_SIZE; move++) {
|
|
if (keysym == _fullKeybdDefs[move]) {
|
|
callLua(down ? "onInputPressed" : "onInputReleased", "ii", keysym, NOMOUSE);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void singe(SDL_Window *window, SDL_Renderer *renderer) {
|
|
int x = 0;
|
|
int y = 0;
|
|
int xr = 0;
|
|
int yr = 0;
|
|
int thisFrame = -1;
|
|
int lastFrame = -1;
|
|
int intReturn = 0;
|
|
SDL_Texture *overlayTexture = NULL;
|
|
SpriteT *sprite = NULL;
|
|
SpriteT *spriteTemp = NULL;
|
|
SoundT *sound = NULL;
|
|
SoundT *soundTemp = NULL;
|
|
FontT *font = NULL;
|
|
FontT *fontTemp = NULL;
|
|
SDL_Event event;
|
|
ManyMouseEvent mouseEvent;
|
|
MouseT *mouse = NULL;
|
|
int mouseButtonMap[] = {
|
|
SWITCH_BUTTON1, // Left
|
|
SWITCH_BUTTON3, // Middle
|
|
SWITCH_BUTTON2, // Right
|
|
SWITCH_BUTTON1, // Wheel Up
|
|
SWITCH_BUTTON2, // Wheel Down
|
|
SWITCH_MOUSE_DISCONNECT
|
|
};
|
|
|
|
// Hang on to some SDL stuff
|
|
_window = window;
|
|
_renderer = renderer;
|
|
|
|
// Start Lua
|
|
_luaContext = luaL_newstate();
|
|
luaL_openlibs(_luaContext);
|
|
lua_atpanic(_luaContext, luaError);
|
|
|
|
// Lua API for Singe
|
|
lua_register(_luaContext, "colorBackground", apiColorBackground);
|
|
lua_register(_luaContext, "colorForeground", apiColorForeground);
|
|
|
|
lua_register(_luaContext, "daphneGetHeight", apiDaphneGetHeight);
|
|
lua_register(_luaContext, "daphneGetWidth", apiDaphneGetWidth);
|
|
lua_register(_luaContext, "daphneScreenshot", apiDaphneScreenshot);
|
|
|
|
lua_register(_luaContext, "debugPrint", apiDebugPrint);
|
|
|
|
lua_register(_luaContext, "discAudio", apiDiscAudio);
|
|
lua_register(_luaContext, "discChangeSpeed", apiDiscChangeSpeed);
|
|
lua_register(_luaContext, "discGetFrame", apiDiscGetFrame);
|
|
lua_register(_luaContext, "discPause", apiDiscPause);
|
|
lua_register(_luaContext, "discPauseAtFrame", apiDiscPauseAtFrame);
|
|
lua_register(_luaContext, "discPlay", apiDiscPlay);
|
|
lua_register(_luaContext, "discSearch", apiDiscSearch);
|
|
lua_register(_luaContext, "discSearchBlanking", apiDiscSearchBlanking);
|
|
lua_register(_luaContext, "discSetFPS", apiDiscSetFps);
|
|
lua_register(_luaContext, "discSkipBackward", apiDiscSkipBackward);
|
|
lua_register(_luaContext, "discSkipBlanking", apiDiscSkipBlanking);
|
|
lua_register(_luaContext, "discSkipForward", apiDiscSkipForward);
|
|
lua_register(_luaContext, "discSkipToFrame", apiDiscSkipToFrame);
|
|
lua_register(_luaContext, "discStepBackward", apiDiscStepBackward);
|
|
lua_register(_luaContext, "discStepForward", apiDiscStepForward);
|
|
lua_register(_luaContext, "discStop", apiDiscStop);
|
|
|
|
lua_register(_luaContext, "fontLoad", apiFontLoad);
|
|
lua_register(_luaContext, "fontPrint", apiFontPrint);
|
|
lua_register(_luaContext, "fontQuality", apiFontQuality);
|
|
lua_register(_luaContext, "fontSelect", apiFontSelect);
|
|
lua_register(_luaContext, "fontToSprite", apiFontToSprite);
|
|
|
|
lua_register(_luaContext, "overlayClear", apiOverlayClear);
|
|
lua_register(_luaContext, "overlayGetHeight", apiOverlayGetHeight);
|
|
lua_register(_luaContext, "overlayGetWidth", apiOverlayGetWidth);
|
|
lua_register(_luaContext, "overlayPrint", apiOverlayPrint);
|
|
|
|
lua_register(_luaContext, "soundLoad", apiSoundLoad);
|
|
lua_register(_luaContext, "soundPlay", apiSoundPlay);
|
|
lua_register(_luaContext, "soundPause", apiSoundPause); // rdg
|
|
lua_register(_luaContext, "soundResume", apiSoundResume); //
|
|
lua_register(_luaContext, "soundIsPlaying", apiSoundIsPlaying); //
|
|
lua_register(_luaContext, "soundStop", apiSoundStop); //
|
|
lua_register(_luaContext, "soundSetVolume", apiSoundSetVolume);
|
|
lua_register(_luaContext, "soundGetVolume", apiSoundGetVolume);
|
|
lua_register(_luaContext, "soundFullStop", apiSoundFullStop);
|
|
|
|
lua_register(_luaContext, "spriteDraw", apiSpriteDraw);
|
|
lua_register(_luaContext, "spriteGetHeight", apiSpriteGetHeight);
|
|
lua_register(_luaContext, "spriteGetWidth", apiSpriteGetWidth);
|
|
lua_register(_luaContext, "spriteLoad", apiSpriteLoad);
|
|
|
|
lua_register(_luaContext, "vldpGetHeight", apiVldpGetHeight);
|
|
lua_register(_luaContext, "vldpGetPixel", apiVldpGetPixel);
|
|
lua_register(_luaContext, "vldpGetWidth", apiVldpGetWidth);
|
|
lua_register(_luaContext, "vldpSetVerbose", apiVldpVerbose);
|
|
|
|
// by RDG2010
|
|
lua_register(_luaContext, "keyboardGetMode", apiKeyboardGetMode);
|
|
lua_register(_luaContext, "keyboardSetMode", apiKeyboardSetMode);
|
|
lua_register(_luaContext, "mouseEnable", apiMouseEnable);
|
|
lua_register(_luaContext, "mouseDisable", apiMouseDisable);
|
|
lua_register(_luaContext, "mouseSetMode", apiMouseSetMode);
|
|
lua_register(_luaContext, "mouseHowMany", apiMouseHowMany);
|
|
lua_register(_luaContext, "discGetState", apiDiscGetState);
|
|
lua_register(_luaContext, "singeGetPauseFlag", apiSingeGetPauseFlag);
|
|
lua_register(_luaContext, "singeSetPauseFlag", apiSingeSetPauseFlag);
|
|
lua_register(_luaContext, "singeEnablePauseKey", apiSingeEnablePauseKey);
|
|
lua_register(_luaContext, "singeDisablePauseKey", apiSingeDisablePauseKey);
|
|
lua_register(_luaContext, "singeQuit", apiSingeQuit);
|
|
lua_register(_luaContext, "singeVersion", apiSingeVersion);
|
|
lua_register(_luaContext, "singeSetGameName", apiSingeSetGameName);
|
|
lua_register(_luaContext, "singeGetScriptPath", apiSingeGetScriptPath);
|
|
|
|
// Open main video file
|
|
_videoHandle = videoLoad(_confVideoFile, _confDataDir, (bool)_confStretchVideo, _renderer);
|
|
if (_videoHandle < 0) utilDie("Unable to load video file: %s", _confVideoFile);
|
|
videoSetVolume(_videoHandle, _confVolumeVldp, _confVolumeVldp);
|
|
|
|
// Should we resize the window?
|
|
//***TODO***
|
|
|
|
// Create overlay surface
|
|
_overlayScaleX = 0.5;
|
|
_overlayScaleY = 0.5;
|
|
x = (int)(videoGetWidth(_videoHandle) * _overlayScaleX);
|
|
y = (int)(videoGetHeight(_videoHandle) * _overlayScaleY);
|
|
_overlay = SDL_CreateRGBSurfaceWithFormat(0, x, y, 32, SDL_PIXELFORMAT_BGRA32);
|
|
if (_overlay == NULL) utilDie("%s", SDL_GetError());
|
|
SDL_SetColorKey(_overlay, true, 0);
|
|
|
|
// Mouse setup
|
|
_mouseCount = ManyMouse_Init();
|
|
if (_mouseCount < 1) utilDie("No mice detected.");
|
|
if (_mouseCount > MAX_MICE) {
|
|
_mouseCount = MAX_MICE;
|
|
}
|
|
memset(_mice, 0, sizeof(_mice));
|
|
_mouseEnabled = (bool)!_confNoMouse;
|
|
for (x=0; x<_mouseCount; x++) {
|
|
strncpy(_mice[x].name, ManyMouse_DeviceName((unsigned)x), sizeof(_mice[x].name));
|
|
_mice[x].name[sizeof(_mice[x].name) - 1] = 0;
|
|
_mice[x].x = (int)(videoGetWidth(_videoHandle) * _overlayScaleX);
|
|
_mice[x].y = (int)(videoGetHeight(_videoHandle) * _overlayScaleY);
|
|
}
|
|
SDL_SetWindowGrab(_window, SDL_TRUE);
|
|
SDL_ShowCursor(SDL_DISABLE);
|
|
|
|
// Set volume
|
|
_effectsVolume = (int)((float)AUDIO_MAX_VOLUME * (float)_confVolumeNonVldp * (float)0.01);
|
|
Mix_Volume(-1, _effectsVolume * 2);
|
|
|
|
// Let us know when sounds end
|
|
Mix_ChannelFinished(channelFinished);
|
|
|
|
// Load overlay font
|
|
_consoleFontSurface = IMG_LoadPNG_RW(SDL_RWFromMem(font_png, font_png_len));
|
|
if (_consoleFontSurface == NULL) utilDie("%s", SDL_GetError());
|
|
_consoleFontWidth = _consoleFontSurface->w / 256;
|
|
_consoleFontHeight = _consoleFontSurface->h;
|
|
SDL_SetColorKey(_consoleFontSurface, true, _consoleFontSurface->format->Rmask | _consoleFontSurface->format->Bmask);
|
|
|
|
// Start video
|
|
videoPlay(_videoHandle);
|
|
_discStopped = false;
|
|
|
|
// Start script
|
|
if (luaL_dofile(_luaContext, _confScriptFile) != 0) utilDie("Error compiling script: %s", lua_tostring(_luaContext, -1));
|
|
|
|
// Game Loop
|
|
while (_running) {
|
|
|
|
// SDL Event Loop
|
|
while (SDL_PollEvent(&event)) {
|
|
switch (event.type) {
|
|
case SDL_KEYDOWN:
|
|
processKey(true, event.key.keysym.sym);
|
|
//***TODO*** RDG used "g" to re-grab/re-scan for mice
|
|
break;
|
|
|
|
case SDL_KEYUP:
|
|
processKey(false, event.key.keysym.sym);
|
|
break;
|
|
|
|
case SDL_MOUSEMOTION:
|
|
if ((_mouseEnabled) && (_mouseMode == MOUSE_SINGLE)) {
|
|
x = (int)(event.motion.x * _overlayScaleX);
|
|
y = (int)(event.motion.y * _overlayScaleY);
|
|
xr = (int)(event.motion.xrel * _overlayScaleX);
|
|
yr = (int)(event.motion.yrel * _overlayScaleY);
|
|
callLua("onMouseMoved", "iiiii", x, y, xr, yr, NOMOUSE);
|
|
}
|
|
break;
|
|
|
|
case SDL_MOUSEBUTTONDOWN:
|
|
for (x=0; x<MOUSE_ARRAY_SIZE; x++) {
|
|
if (event.button.button == x) {
|
|
callLua("onInputPressed", "ii", mouseButtonMap[x], NOMOUSE);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SDL_MOUSEBUTTONUP:
|
|
for (x=0; x<MOUSE_ARRAY_SIZE; x++) {
|
|
if (event.button.button == x) {
|
|
callLua("onInputReleased", "ii", mouseButtonMap[x], NOMOUSE);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SDL_QUIT:
|
|
_running = 0;
|
|
break;
|
|
}
|
|
|
|
// Mouse Event Loop
|
|
while (ManyMouse_PollEvent(&mouseEvent)) {
|
|
|
|
// Just run out the event queue if we're not using ManyMouse
|
|
if ((!_mouseEnabled) || (_mouseMode == MOUSE_SINGLE)) continue;
|
|
|
|
// Has this one been unplugged?
|
|
if (mouseEvent.device >= (unsigned)_mouseCount) continue;
|
|
mouse = &_mice[mouseEvent.device];
|
|
|
|
switch (mouseEvent.type) {
|
|
case MANYMOUSE_EVENT_RELMOTION:
|
|
switch (mouseEvent.item) {
|
|
case 0:
|
|
mouse->relx += mouseEvent.value;
|
|
break;
|
|
|
|
case 1:
|
|
mouse->rely += mouseEvent.value;
|
|
break;
|
|
}
|
|
// Clamp to video size
|
|
x = videoGetWidth(_videoHandle);
|
|
y = videoGetHeight(_videoHandle);
|
|
if (mouse->relx < 0) mouse->relx = 0;
|
|
if (mouse->relx >= x) mouse->relx = x - 1;
|
|
if (mouse->rely < 0) mouse->rely = 0;
|
|
if (mouse->rely >= y) mouse->rely = y - 1;
|
|
x = (int)(mouse->x * _overlayScaleX);
|
|
y = (int)(mouse->y * _overlayScaleY);
|
|
xr = (int)(mouse->relx * _overlayScaleX);
|
|
yr = (int)(mouse->relx * _overlayScaleY);
|
|
callLua("onMouseMoved", "iiiii", x, y, xr, yr, mouseEvent.device);
|
|
break;
|
|
|
|
case MANYMOUSE_EVENT_ABSMOTION:
|
|
switch (mouseEvent.item) {
|
|
case 0:
|
|
mouse->x += mouseEvent.value;
|
|
break;
|
|
|
|
case 1:
|
|
mouse->y += mouseEvent.value;
|
|
break;
|
|
}
|
|
x = (int)(mouse->x * _overlayScaleX);
|
|
y = (int)(mouse->y * _overlayScaleY);
|
|
xr = (int)(mouse->relx * _overlayScaleX);
|
|
yr = (int)(mouse->relx * _overlayScaleY);
|
|
utilSay("Mouse %d: Absolute %d, %d", mouseEvent.device, x, y);
|
|
callLua("onMouseMoved", "iiiii", x, y, xr, yr, mouseEvent.device);
|
|
break;
|
|
|
|
case MANYMOUSE_EVENT_BUTTON:
|
|
if (mouseEvent.item < 32) {
|
|
if (mouseEvent.value == 1) {
|
|
// Button pressed
|
|
callLua("onInputPressed", "ii", mouseButtonMap[mouseEvent.item], mouseEvent.device);
|
|
mouse->buttons |= (1 << mouseEvent.item);
|
|
} else {
|
|
// Button released
|
|
callLua("onInputReleased", "ii", mouseButtonMap[mouseEvent.item], mouseEvent.device);
|
|
mouse->buttons &= ~(1 << mouseEvent.item);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case MANYMOUSE_EVENT_SCROLL:
|
|
if (mouseEvent.item == 0) {
|
|
if (mouseEvent.value > 0) {
|
|
// Scroll up
|
|
callLua("onInputPressed", "ii", SWITCH_MOUSE_SCROLL_UP, mouseEvent.device);
|
|
callLua("onInputReleased", "ii", SWITCH_MOUSE_SCROLL_UP, mouseEvent.device);
|
|
} else {
|
|
// Scroll down
|
|
callLua("onInputPressed", "ii", SWITCH_MOUSE_SCROLL_DOWN, mouseEvent.device);
|
|
callLua("onInputReleased", "ii", SWITCH_MOUSE_SCROLL_DOWN, mouseEvent.device);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case MANYMOUSE_EVENT_DISCONNECT:
|
|
mouse->connected = false;
|
|
callLua("onInputPressed", "ii", SWITCH_MOUSE_DISCONNECT, mouseEvent.device);
|
|
callLua("onInputReleased", "ii", SWITCH_MOUSE_DISCONNECT, mouseEvent.device);
|
|
break;
|
|
|
|
case MANYMOUSE_EVENT_MAX:
|
|
// We don't use this
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Call game code
|
|
callLua("onOverlayUpdate", ">i", &intReturn);
|
|
if (intReturn == 1) {
|
|
_refreshDisplay = true;
|
|
}
|
|
|
|
// Update video
|
|
thisFrame = videoUpdate(_videoHandle, &_videoTexture);
|
|
if ((thisFrame != lastFrame) && (thisFrame>= 0)) {
|
|
lastFrame = thisFrame;
|
|
_refreshDisplay = true;
|
|
}
|
|
|
|
// Update display
|
|
if (_refreshDisplay) {
|
|
//***TODO*** Handle overlay and blank disk frames
|
|
SDL_RenderCopy(_renderer, _videoTexture, NULL, NULL);
|
|
overlayTexture = SDL_CreateTextureFromSurface(_renderer, _overlay);
|
|
if (!overlayTexture) utilDie("%s", SDL_GetError());
|
|
if (!_confStretchVideo) {
|
|
SDL_RenderSetLogicalSize(renderer, videoGetWidth(_videoHandle), videoGetHeight(_videoHandle));
|
|
}
|
|
SDL_RenderCopy(_renderer, overlayTexture, NULL, NULL);
|
|
SDL_DestroyTexture(overlayTexture);
|
|
overlayTexture = NULL;
|
|
SDL_RenderPresent(_renderer);
|
|
_refreshDisplay = false;
|
|
}
|
|
}
|
|
|
|
// End game
|
|
callLua("onShutdown", "");
|
|
|
|
// Stop all sounds
|
|
Mix_HaltChannel(-1);
|
|
Mix_ChannelFinished(NULL);
|
|
|
|
// Stop Lua
|
|
lua_close(_luaContext);
|
|
|
|
// Free overlay & overlay font
|
|
SDL_FreeSurface(_overlay);
|
|
SDL_FreeSurface(_consoleFontSurface);
|
|
|
|
// Unload fonts
|
|
HASH_ITER(hh, _fontList, font, fontTemp) {
|
|
#pragma GCC diagnostic push
|
|
#pragma GCC diagnostic ignored "-Wcast-align"
|
|
HASH_DEL(_fontList, font);
|
|
#pragma GCC diagnostic pop
|
|
TTF_CloseFont(font->font);
|
|
free(font);
|
|
}
|
|
|
|
// Unload sounds
|
|
HASH_ITER(hh, _soundList, sound, soundTemp) {
|
|
#pragma GCC diagnostic push
|
|
#pragma GCC diagnostic ignored "-Wcast-align"
|
|
HASH_DEL(_soundList, sound);
|
|
#pragma GCC diagnostic pop
|
|
Mix_FreeChunk(sound->chunk);
|
|
free(sound);
|
|
}
|
|
|
|
// Unload sprites
|
|
HASH_ITER(hh, _spriteList, sprite, spriteTemp) {
|
|
#pragma GCC diagnostic push
|
|
#pragma GCC diagnostic ignored "-Wcast-align"
|
|
HASH_DEL(_spriteList, sprite);
|
|
#pragma GCC diagnostic pop
|
|
SDL_FreeSurface(sprite->surface);
|
|
free(sprite);
|
|
}
|
|
|
|
// Unload video
|
|
videoUnload(_videoHandle);
|
|
|
|
// Stop mice
|
|
SDL_ShowCursor(SDL_ENABLE);
|
|
ManyMouse_Quit();
|
|
}
|