|
@@ -0,0 +1,459 @@
|
|
|
|
+// quantumde1 developed software, licensed under BSD-0-Clause license.
|
|
|
|
+module scripts.lua;
|
|
|
|
+
|
|
|
|
+import bindbc.lua;
|
|
|
|
+import raylib;
|
|
|
|
+import variables;
|
|
|
|
+import graphics.effects;
|
|
|
|
+import std.conv;
|
|
|
|
+import system.abstraction;
|
|
|
|
+import system.config;
|
|
|
|
+import std.string;
|
|
|
|
+import graphics.engine;
|
|
|
|
+import graphics.playback;
|
|
|
|
+import std.file;
|
|
|
|
+import std.array;
|
|
|
|
+import std.algorithm;
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * This module provides Lua bindings for various engine functionalities.
|
|
|
|
+ * Functions are built on top of engine built-in functions for execution from scripts.
|
|
|
|
+ * Not all engine functions usable for scripting are yet implemented.
|
|
|
|
+*/
|
|
|
|
+
|
|
|
|
+string hint;
|
|
|
|
+
|
|
|
|
+extern (C) nothrow int luaL_showHint(lua_State* L)
|
|
|
|
+{
|
|
|
|
+ hint = "" ~ to!string(luaL_checkstring(L, 1));
|
|
|
|
+ hintNeeded = true;
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/* text window */
|
|
|
|
+
|
|
|
|
+extern (C) nothrow int luaL_dialogBox(lua_State* L)
|
|
|
|
+{
|
|
|
|
+ showDialog = true;
|
|
|
|
+ luaL_checktype(L, 2, LUA_TTABLE);
|
|
|
|
+ choicePage = cast(int)luaL_checkinteger(L, 4);
|
|
|
|
+
|
|
|
|
+ int textTableLength = cast(int) lua_objlen(L, 2);
|
|
|
|
+ messageGlobal = new string[](textTableLength);
|
|
|
|
+
|
|
|
|
+ for (int i = 0; i < textTableLength; i++) {
|
|
|
|
+ lua_rawgeti(L, 2, i + 1);
|
|
|
|
+ messageGlobal[i] = luaL_checkstring(L, -1).to!string;
|
|
|
|
+ lua_pop(L, 1);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ luaL_checktype(L, 5, LUA_TTABLE);
|
|
|
|
+ int choicesLength = cast(int) lua_objlen(L, 5);
|
|
|
|
+ choices = new string[choicesLength];
|
|
|
|
+ for (int i = 0; i < choicesLength; i++)
|
|
|
|
+ {
|
|
|
|
+ lua_rawgeti(L, 5, i + 1);
|
|
|
|
+ choices[i] = luaL_checkstring(L, -1).to!string;
|
|
|
|
+ lua_pop(L, 1);
|
|
|
|
+ }
|
|
|
|
+ if (lua_gettop(L) == 7)
|
|
|
|
+ {
|
|
|
|
+ typingSpeed = cast(float) luaL_checknumber(L, 7);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+extern (C) nothrow int luaL_getAnswerValue(lua_State* L)
|
|
|
|
+{
|
|
|
|
+ lua_pushinteger(L, selectedChoice);
|
|
|
|
+ return 1;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+extern (C) nothrow int luaL_isDialogExecuted(lua_State *L) {
|
|
|
|
+ lua_pushboolean(L, showDialog);
|
|
|
|
+ return 1;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+extern (C) nothrow int luaL_dialogAnswerValue(lua_State* L)
|
|
|
|
+{
|
|
|
|
+ lua_pushinteger(L, selectedChoice);
|
|
|
|
+ return 1;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/* background drawing and loading */
|
|
|
|
+
|
|
|
|
+extern (C) nothrow int luaL_load2Dbackground(lua_State* L)
|
|
|
|
+{
|
|
|
|
+ try
|
|
|
|
+ {
|
|
|
|
+ int index = cast(int) luaL_checkinteger(L, 2);
|
|
|
|
+ //if index too big, extending array
|
|
|
|
+ if (index >= backgrounds.length)
|
|
|
|
+ {
|
|
|
|
+ backgrounds.length = index + 1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // if texture with same Index already loaded, unloading it
|
|
|
|
+ if (index < backgrounds.length && backgrounds[index].id != 0)
|
|
|
|
+ {
|
|
|
|
+ UnloadTexture(backgrounds[index]);
|
|
|
|
+ }
|
|
|
|
+ backgrounds[index] = LoadTexture(luaL_checkstring(L, 1));
|
|
|
|
+ }
|
|
|
|
+ catch (Exception e)
|
|
|
|
+ {
|
|
|
|
+ }
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+extern (C) nothrow int luaL_draw2Dbackground(lua_State* L)
|
|
|
|
+{
|
|
|
|
+ try
|
|
|
|
+ {
|
|
|
|
+ backgroundTexture = backgrounds[luaL_checkinteger(L, 1)];
|
|
|
|
+ neededDraw2D = true;
|
|
|
|
+ }
|
|
|
|
+ catch (Exception e)
|
|
|
|
+ {
|
|
|
|
+ }
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+extern (C) nothrow int luaL_unload2Dbackground(lua_State* L)
|
|
|
|
+{
|
|
|
|
+ UnloadTexture(backgrounds[cast(int) luaL_checkinteger(L, 1)]);
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/* character textures */
|
|
|
|
+
|
|
|
|
+extern (C) nothrow int luaL_load2Dcharacter(lua_State *L) {
|
|
|
|
+ try
|
|
|
|
+ {
|
|
|
|
+ int count = cast(int) luaL_checkinteger(L, 2);
|
|
|
|
+
|
|
|
|
+ if (count >= characterTextures.length)
|
|
|
|
+ {
|
|
|
|
+ characterTextures.length = count + 1;
|
|
|
|
+ }
|
|
|
|
+ characterTextures[count].texture = LoadTexture(luaL_checkstring(L, 1));
|
|
|
|
+ characterTextures[count].width = characterTextures[count].texture.width;
|
|
|
|
+ characterTextures[count].height = characterTextures[count].texture.height;
|
|
|
|
+ characterTextures[count].drawTexture = false;
|
|
|
|
+ }
|
|
|
|
+ catch (Exception e) {
|
|
|
|
+ }
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+extern (C) nothrow int luaL_draw2Dcharacter(lua_State* L)
|
|
|
|
+{
|
|
|
|
+ try {
|
|
|
|
+ int count = to!int(luaL_checkinteger(L, 4));
|
|
|
|
+ characterTextures[count].scale = luaL_checknumber(L, 3);
|
|
|
|
+ characterTextures[count].y = cast(int) luaL_checkinteger(L, 2);
|
|
|
|
+ characterTextures[count].x = cast(int) luaL_checkinteger(L, 1);
|
|
|
|
+ characterTextures[count].drawTexture = true;
|
|
|
|
+ debugWriteln("Count: ", count, " drawTexture cond: ", characterTextures[count].drawTexture);
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+extern (C) nothrow int luaL_stopDraw2Dcharacter(lua_State* L)
|
|
|
|
+{
|
|
|
|
+ int count = cast(int) luaL_checkinteger(L, 1);
|
|
|
|
+ characterTextures[count].drawTexture = false;
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+extern (C) nothrow int luaL_unload2Dcharacter(lua_State *L) {
|
|
|
|
+ int count = cast(int) luaL_checkinteger(L, 1);
|
|
|
|
+ UnloadTexture(characterTextures[count].texture);
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/* music and video */
|
|
|
|
+
|
|
|
|
+extern (C) nothrow int luaL_LoadMusic(lua_State* L)
|
|
|
|
+{
|
|
|
|
+ try
|
|
|
|
+ {
|
|
|
|
+ musicPath = cast(char*) luaL_checkstring(L, 1);
|
|
|
|
+ music = LoadMusicStream(musicPath);
|
|
|
|
+ }
|
|
|
|
+ catch (Exception e)
|
|
|
|
+ {
|
|
|
|
+ }
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+extern (C) nothrow int luaL_PlayMusic(lua_State* L)
|
|
|
|
+{
|
|
|
|
+ PlayMusicStream(music);
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+extern (C) nothrow int luaL_StopMusic(lua_State* L)
|
|
|
|
+{
|
|
|
|
+ StopMusicStream(music);
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+extern (C) nothrow int luaL_playSfx(lua_State *L) {
|
|
|
|
+ try {
|
|
|
|
+ playSfx(to!string(luaL_checkstring(L, 1)));
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+extern (C) nothrow int luaL_stopSfx(lua_State *L) {
|
|
|
|
+ StopSound(sfx);
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+extern (C) nothrow int luaL_playVideo(lua_State* L)
|
|
|
|
+{
|
|
|
|
+ try
|
|
|
|
+ {
|
|
|
|
+ videoFinished = false;
|
|
|
|
+ playVideo(luaL_checkstring(L, 1).to!string);
|
|
|
|
+ }
|
|
|
|
+ catch (Exception e)
|
|
|
|
+ {
|
|
|
|
+ }
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/* ui animations */
|
|
|
|
+
|
|
|
|
+extern (C) nothrow int luaL_moveCamera(lua_State *L) {
|
|
|
|
+ try {
|
|
|
|
+ float targetX = cast(float) luaL_checknumber(L, 1);
|
|
|
|
+ float targetY = cast(float) luaL_checknumber(L, 2);
|
|
|
|
+ float zoom = cast(float) luaL_optnumber(L, 3, 1.0f);
|
|
|
|
+ float speed = cast(float) luaL_optnumber(L, 4, 5.0f);
|
|
|
|
+ cameraTargetX = targetX;
|
|
|
|
+ cameraTargetY = targetY;
|
|
|
|
+ cameraTargetZoom = zoom;
|
|
|
|
+ cameraMoveSpeed = speed;
|
|
|
|
+ isCameraMoving = true;
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
+ }
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+extern (C) nothrow int luaL_isCameraMoving(lua_State *L) {
|
|
|
|
+ lua_pushboolean(L, isCameraMoving);
|
|
|
|
+ return 1;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+extern (C) nothrow int luaL_loadUIAnimation(lua_State *L) {
|
|
|
|
+ try {
|
|
|
|
+ framesUI = loadAnimationFramesUI("res/uifx/"~to!string(luaL_checkstring(L, 1)), to!string(luaL_checkstring(L, 2)));
|
|
|
|
+ if (lua_gettop(L) == 3) {
|
|
|
|
+ frameDuration = luaL_checknumber(L, 3);
|
|
|
|
+ debug debugWriteln("frameDuration: ", frameDuration);
|
|
|
|
+ }
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+extern (C) nothrow int luaL_playUIAnimation(lua_State *L) {
|
|
|
|
+ debug debugWriteln("Animation UI start");
|
|
|
|
+ try {
|
|
|
|
+ playAnimation = true;
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+extern (C) nothrow int luaL_stopUIAnimation(lua_State *L) {
|
|
|
|
+ playAnimation = false;
|
|
|
|
+ debug debugWriteln("Animation UI stop");
|
|
|
|
+ frameDuration = 0.016f;
|
|
|
|
+ currentFrame = 0;
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+extern (C) nothrow int luaL_unloadUIAnimation(lua_State *L) {
|
|
|
|
+ try {
|
|
|
|
+ for (int i = 0; i < framesUI.length; i++) {
|
|
|
|
+ UnloadTexture(framesUI[i]);
|
|
|
|
+ }
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/* system */
|
|
|
|
+
|
|
|
|
+extern (C) nothrow int luaL_getScreenWidth(lua_State* L)
|
|
|
|
+{
|
|
|
|
+ lua_pushinteger(L, GetScreenWidth());
|
|
|
|
+ return 1;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+extern (C) nothrow int luaL_getScreenHeight(lua_State* L)
|
|
|
|
+{
|
|
|
|
+ lua_pushinteger(L, GetScreenHeight());
|
|
|
|
+ return 1;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+extern (C) nothrow int luaL_getUsedLanguage(lua_State* L)
|
|
|
|
+{
|
|
|
|
+ lua_pushstring(L, usedLang.toStringz());
|
|
|
|
+ return 1;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+extern (C) nothrow int luaL_2dModeEnable(lua_State* L)
|
|
|
|
+{
|
|
|
|
+ neededDraw2D = true;
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+extern (C) nothrow int luaL_2dModeDisable(lua_State* L)
|
|
|
|
+{
|
|
|
|
+ neededDraw2D = false;
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+extern (C) nothrow int luaL_setGameFont(lua_State* L)
|
|
|
|
+{
|
|
|
|
+ const char* x = luaL_checkstring(L, 1);
|
|
|
|
+ debugWriteln("Setting custom font: ", x.to!string);
|
|
|
|
+ int[512] codepoints = 0;
|
|
|
|
+ foreach (i; 0 .. 95)
|
|
|
|
+ {
|
|
|
|
+ codepoints[i] = 32 + i;
|
|
|
|
+ }
|
|
|
|
+ foreach (i; 0 .. 255)
|
|
|
|
+ {
|
|
|
|
+ codepoints[96 + i] = 0x400 + i;
|
|
|
|
+ }
|
|
|
|
+ textFont = LoadFontEx(x, 40, codepoints.ptr, codepoints.length);
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+extern (C) nothrow int luaL_getTime(lua_State* L)
|
|
|
|
+{
|
|
|
|
+ lua_pushnumber(L, GetTime());
|
|
|
|
+ return 1;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+extern (C) nothrow int luaL_isKeyPressed(lua_State* L)
|
|
|
|
+{
|
|
|
|
+ try
|
|
|
|
+ {
|
|
|
|
+ if (IsKeyPressed(cast(int)(luaL_checkinteger(L, 1))))
|
|
|
|
+ {
|
|
|
|
+ lua_pushboolean(L, true);
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ lua_pushboolean(L, false);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ catch (Exception e)
|
|
|
|
+ {
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ return 1;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+extern (C) nothrow int luaL_loadScript(lua_State* L)
|
|
|
|
+{
|
|
|
|
+ for (int i = cast(int) characterTextures.length; i < characterTextures.length; i++)
|
|
|
|
+ {
|
|
|
|
+ UnloadTexture(characterTextures[i].texture);
|
|
|
|
+ }
|
|
|
|
+ for (int i = cast(int) backgrounds.length; i < backgrounds.length; i++)
|
|
|
|
+ {
|
|
|
|
+ UnloadTexture(backgrounds[i]);
|
|
|
|
+ }
|
|
|
|
+ try
|
|
|
|
+ {
|
|
|
|
+ luaExec = to!string(luaL_checkstring(L, 1));
|
|
|
|
+ resetAllScriptValues();
|
|
|
|
+ }
|
|
|
|
+ catch (Exception e)
|
|
|
|
+ {
|
|
|
|
+ }
|
|
|
|
+ luaReload = true;
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/* Register functions */
|
|
|
|
+
|
|
|
|
+extern (C) nothrow void luaL_loader(lua_State* L)
|
|
|
|
+{
|
|
|
|
+ lua_register(L, "dialogBox", &luaL_dialogBox);
|
|
|
|
+ lua_register(L, "dialogAnswerValue", &luaL_dialogAnswerValue);
|
|
|
|
+ lua_register(L, "isDialogExecuted", &luaL_isDialogExecuted);
|
|
|
|
+ lua_register(L, "getAnswerValue", &luaL_getAnswerValue);
|
|
|
|
+ lua_register(L, "loadAnimationUI", &luaL_loadUIAnimation);
|
|
|
|
+ lua_register(L, "playAnimationUI", &luaL_playUIAnimation);
|
|
|
|
+ lua_register(L, "stopAnimationUI", &luaL_stopUIAnimation);
|
|
|
|
+ lua_register(L, "unloadAnimationUI", &luaL_unloadUIAnimation);
|
|
|
|
+ lua_register(L, "moveCamera", &luaL_moveCamera);
|
|
|
|
+ lua_register(L, "isCameraMoving", &luaL_isCameraMoving);
|
|
|
|
+ lua_register(L, "playVideo", &luaL_playVideo);
|
|
|
|
+ lua_register(L, "loadMusic", &luaL_LoadMusic);
|
|
|
|
+ lua_register(L, "playMusic", &luaL_PlayMusic);
|
|
|
|
+ lua_register(L, "stopMusic", &luaL_StopMusic);
|
|
|
|
+ lua_register(L, "playSfx", &luaL_playSfx);
|
|
|
|
+ lua_register(L, "stopSfx", &luaL_stopSfx);
|
|
|
|
+ lua_register(L, "Begin2D", &luaL_2dModeEnable);
|
|
|
|
+ lua_register(L, "End2D", &luaL_2dModeDisable);
|
|
|
|
+ lua_register(L, "load2Dcharacter", &luaL_load2Dcharacter);
|
|
|
|
+ lua_register(L, "draw2Dcharacter", &luaL_draw2Dcharacter);
|
|
|
|
+ lua_register(L, "stopDraw2Dcharacter", &luaL_stopDraw2Dcharacter);
|
|
|
|
+ lua_register(L, "unload2Dcharacter", &luaL_unload2Dcharacter);
|
|
|
|
+ lua_register(L, "load2Dtexture", &luaL_load2Dbackground);
|
|
|
|
+ lua_register(L, "draw2Dtexture", &luaL_draw2Dbackground);
|
|
|
|
+ lua_register(L, "unload2Dtexture", &luaL_unload2Dbackground);
|
|
|
|
+ lua_register(L, "getTime", &luaL_getTime);
|
|
|
|
+ lua_register(L, "loadScript", &luaL_loadScript);
|
|
|
|
+ lua_register(L, "setFont", &luaL_setGameFont);
|
|
|
|
+ lua_register(L, "getScreenHeight", &luaL_getScreenHeight);
|
|
|
|
+ lua_register(L, "getScreenWidth", &luaL_getScreenWidth);
|
|
|
|
+ lua_register(L, "isKeyPressed", &luaL_isKeyPressed);
|
|
|
|
+ lua_register(L, "getLanguage", &luaL_getUsedLanguage);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+int luaInit(string luaExec)
|
|
|
|
+{
|
|
|
|
+ debugWriteln("loading Lua");
|
|
|
|
+ L = luaL_newstate();
|
|
|
|
+ luaL_openlibs(L);
|
|
|
|
+ luaL_loader(L);
|
|
|
|
+ debugWriteln("Executing next Lua file: ", luaExec);
|
|
|
|
+ if (std.file.exists(luaExec) == false) {
|
|
|
|
+ debugWriteln("Script file not found! Exiting.");
|
|
|
|
+ return EngineExitCodes.EXIT_FILE_NOT_FOUND;
|
|
|
|
+ }
|
|
|
|
+ if (luaL_dofile(L, toStringz(luaExec)) != LUA_OK) {
|
|
|
|
+ debugWriteln("Lua error: ", to!string(lua_tostring(L, -1)));
|
|
|
|
+ return EngineExitCodes.EXIT_SCRIPT_ERROR;
|
|
|
|
+ }
|
|
|
|
+ return EngineExitCodes.EXIT_OK;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void luaEventLoop()
|
|
|
|
+{
|
|
|
|
+ lua_getglobal(L, "EventLoop");
|
|
|
|
+ if (lua_pcall(L, 0, 0, 0) != LUA_OK)
|
|
|
|
+ {
|
|
|
|
+ debug debugWriteln("Error in EventLoop: ", to!string(lua_tostring(L, -1)));
|
|
|
|
+ }
|
|
|
|
+ lua_pop(L, 0);
|
|
|
|
+}
|