From 87a53f2a09a204ca9bcdde9c73db414c79075326 Mon Sep 17 00:00:00 2001 From: Steph Enders Date: Fri, 17 Jun 2022 11:19:51 -0400 Subject: Add scene controls and win/loss scenarios Setup ability to check collisions and transition game scene --- CMakeLists.txt | 2 +- include/algs.lua | 2 +- include/constants.lua | 5 ++ include/defaults.lua | 97 ++++++++++++++++++++---- src/Api.h | 114 ---------------------------- src/CApi.h | 203 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/LuaApi.h | 89 ++++++++++++++++++++++ src/Scene.h | 5 ++ src/main.cpp | 80 +++++++++----------- 9 files changed, 420 insertions(+), 177 deletions(-) delete mode 100644 src/Api.h create mode 100644 src/CApi.h create mode 100644 src/LuaApi.h create mode 100644 src/Scene.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 3dcce6a..bb5735d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,5 +17,5 @@ find_package(SFML 2.5 REQUIRED COMPONENTS system window graphics) #file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/maps DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) #file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/include DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) -add_executable(${PROJECT_NAME} src/main.cpp src/Level.cpp src/Level.h src/Api.h) +add_executable(${PROJECT_NAME} src/main.cpp src/Level.cpp src/Level.h src/CApi.h src/Scene.h src/LuaApi.h) target_link_libraries(${PROJECT_NAME} ${LUA_LIBRARIES} ${SFML_LIBRARIES}) diff --git a/include/algs.lua b/include/algs.lua index 2541102..c9e6438 100644 --- a/include/algs.lua +++ b/include/algs.lua @@ -104,7 +104,7 @@ local function pathfind(start_pos, target_pos, map) end if (push_moves(start_pos.x, start_pos.y, nil, visit_map, queue, target_pos)) then - return { dx = start_pos.x - target_pos.x, dy = start_pos.y - target_pos.y } + return { dx = target_pos.x - start_pos.x, dy = target_pos.y - start_pos.y } end while queue:empty() ~= true do diff --git a/include/constants.lua b/include/constants.lua index 922a35b..ab5fcf1 100644 --- a/include/constants.lua +++ b/include/constants.lua @@ -8,3 +8,8 @@ KEY_SPACE = ' ' MAP_WALL = 1 MAP_SPACE = 0 MAP_VISITED = -1 + +SCENE_INTRO = 0 +SCENE_LEVEL = 1 +SCENE_WIN = 2 +SCENE_LOSS = 3 \ No newline at end of file diff --git a/include/defaults.lua b/include/defaults.lua index a6cefe5..3651060 100644 --- a/include/defaults.lua +++ b/include/defaults.lua @@ -16,33 +16,44 @@ c_fatal(msg) --]] require "include.constants"; local algs = require "include.algs"; +local hasLost = false; +local hasWon = false; +local hasIntro = false; --- setup random --math.randomseed(os.time()) ---@param pressedKey number function onKeyPress(pressedKey) + scene = c_get_scene() + assert(type(scene) == "number", "scene is not a number") + if scene == SCENE_INTRO then + if pressedKey == KEY_S then + print("Lua start"); + c_trigger_level_start(); + end + elseif scene == SCENE_LEVEL then + dx = 0 + dy = 0 + if (pressedKey == KEY_W) then + dy = -1 + elseif pressedKey == KEY_A then + dx = -1 + elseif pressedKey == KEY_S then + dy = 1 + elseif pressedKey == KEY_D then + dx = 1 + end - dx = 0 - dy = 0 - if (pressedKey == KEY_W) then - dy = -1 - elseif pressedKey == KEY_A then - dx = -1 - elseif pressedKey == KEY_S then - dy = 1 - elseif pressedKey == KEY_D then - dx = 1 + c_move_player(dx, dy) end - - c_move_player(dx, dy) end function onUpdate() - enemies = c_get_enemies() -- external + enemies = c_get_enemies() assert(type(enemies) == "table", "Enemies not a table") - player = c_get_player_position() -- external + player = c_get_player_position() assert(type(player) == "table", "Player is not a table") map = c_get_map(); @@ -50,7 +61,58 @@ function onUpdate() for _, v in ipairs(enemies) do local next = algs.pathfind(v, player, map) - c_move_enemy(v.id, next.dx, next.dy) + new_pos = c_move_enemy(v.id, next.dx, next.dy) + assert(type(new_pos) == "table", "new_pos is not a table") + if new_pos.x == player.x and new_pos.y == player.y then + c_trigger_loss() + end + end + treasures = c_get_treasures() + assert(type(treasures) == "table", "treasures is not a table") + + for _, t in ipairs(treasures) do + if t.x == player.x and t.y == player.y then + c_score_treasure(t.id) + if #treasures == 1 then + c_trigger_win() + end + end + end +end + +function onWin() + if hasWon == false then + hasWon = true + print("You WIN!!!!!!!!!") + end +end + +function onLoss() + if hasLost == false then + hasLost = true + print("Oh no! You lost!") + end +end + +function onIntro() + if hasIntro == false then + hasIntro = true + print([[ +................... +.. dng .. +................... +.. controls .. +................... +.. start -- s .. +.. move -- wasd .. +.. quit -- q .. +................... +.. goal .. +................... +.. Find treasure .. +.. Avoid enemies .. +................... + ]]) end end @@ -58,4 +120,7 @@ end return { onKeyPress = onKeyPress, onUpdate = onUpdate, -} \ No newline at end of file + onWin = onWin, + onLoss = onLoss, + onIntro = onIntro, +} diff --git a/src/Api.h b/src/Api.h deleted file mode 100644 index f9e7e8d..0000000 --- a/src/Api.h +++ /dev/null @@ -1,114 +0,0 @@ -#ifndef DNG_API_H -#define DNG_API_H - -#include "Level.h" -#include -#include - -extern std::shared_ptr lvl; - -static int c_get_player_position(lua_State *L) { - lua_createtable(L, 0, 2); - lua_pushnumber(L, lvl->player.y + 1); - lua_setfield(L, -2, "y"); - lua_pushnumber(L, lvl->player.x + 1); - lua_setfield(L, -2, "x"); - - return 1; -} - -static int c_move_player(lua_State *L) { - // stack ordering - int dy = static_cast(lua_tonumber(L, -1)); - int dx = static_cast(lua_tonumber(L, -2)); - - bool res = false; - - if (lvl->playerCanStep(dx, dy)) { - lvl->player.x += dx; - lvl->player.y += dy; - res = true; - } - - lua_pushboolean(L, res); - - return 1; -} - -static int c_move_enemy(lua_State *L) { - // stack ordering - int dy = static_cast(lua_tonumber(L, -1)); - int dx = static_cast(lua_tonumber(L, -2)); - int id = static_cast(lua_tonumber(L, -3)); - - int i = lvl->getEnemyIndex(id); - // guard against enemy not found - if (i == -1) { - lua_pushboolean(L, false); - return 1; - } - - bool res = false; - if (lvl->enemyCanStep(lvl->enemyPositions[i], dx, dy)) { - lvl->enemyPositions[i].x += dx; - lvl->enemyPositions[i].y += dy; - res = true; - } - - lua_pushboolean(L, res); - - return 1; -} - -static int c_get_enemies(lua_State *L) { - lua_createtable(L, int(lvl->enemyPositions.size()), 0); - - int idx = 0; - - for (auto &pos : lvl->enemyPositions) { - lua_pushnumber(L, ++idx); - lua_createtable(L, 0, 3); - lua_pushnumber(L, pos.id); - lua_setfield(L, -2, "id"); - lua_pushnumber(L, pos.x + 1); - lua_setfield(L, -2, "x"); - lua_pushnumber(L, pos.y + 1); - lua_setfield(L, -2, "y"); - lua_settable(L, -3); - } - - return 1; -} - -static int c_spawn_enemy(lua_State *L) { return 1; } - -static int c_destroy_enemy(lua_State *L) { return 1; } - -static int c_get_map(lua_State *L) { - lua_createtable(L, int(lvl->map.size()), 0); - int idx = 0; - for (auto &vec : lvl->map) { - lua_pushnumber(L, ++idx); - lua_createtable(L, int(vec.size()), 0); - int inner_idx = 0; - for (auto &c : vec) { - lua_pushnumber(L, ++inner_idx); - lua_pushnumber(L, c == WALL_SPACE ? 1 : 0); - lua_rawset(L, -3); - } - lua_rawset(L, -3); - } - return 1; -} - -static void init_c_api(lua_State *L) { - lua_register(L, "c_move_player", c_move_player); - lua_register(L, "c_move_enemy", c_move_enemy); - lua_register(L, "c_spawn_enemy", c_spawn_enemy); - lua_register(L, "c_destroy_enemy", c_destroy_enemy); - lua_register(L, "c_get_enemies", c_get_enemies); - lua_register(L, "c_get_player_position", c_get_player_position); - lua_register(L, "c_get_map", c_get_map); -} - -#endif // DNG_API_H \ No newline at end of file diff --git a/src/CApi.h b/src/CApi.h new file mode 100644 index 0000000..651cc13 --- /dev/null +++ b/src/CApi.h @@ -0,0 +1,203 @@ +#ifndef DNG_CAPI_H +#define DNG_CAPI_H + +#include "Level.h" +#include "Scene.h" +#include +#include + +extern std::shared_ptr lvl; +extern Scene scene; + +/* + * c_get_player_position(int x, int y) + */ +static int c_get_player_position(lua_State *L) { + lua_createtable(L, 0, 2); + lua_pushnumber(L, lvl->player.y + 1); + lua_setfield(L, -2, "y"); + lua_pushnumber(L, lvl->player.x + 1); + lua_setfield(L, -2, "x"); + + return 1; +} + +/* + * c_move_player(int dx, int dy) + */ +static int c_move_player(lua_State *L) { + // stack ordering + int dy = static_cast(lua_tonumber(L, -1)); + int dx = static_cast(lua_tonumber(L, -2)); + + if (lvl->playerCanStep(dx, dy)) { + lvl->player.x += dx; + lvl->player.y += dy; + } + + lua_createtable(L, 0, 2); + lua_pushnumber(L, lvl->player.y + 1); + lua_setfield(L, -2, "y"); + lua_pushnumber(L, lvl->player.x + 1); + lua_setfield(L, -2, "x"); + + return 1; +} + +/* + * c_move_enemy(int id, int dx, int dy) + */ +static int c_move_enemy(lua_State *L) { + // stack ordering + int dy = static_cast(lua_tonumber(L, -1)); + int dx = static_cast(lua_tonumber(L, -2)); + int id = static_cast(lua_tonumber(L, -3)); + + int i = lvl->getEnemyIndex(id); + // guard against enemy not found + if (i == -1) { + return 1; + } + + if (lvl->enemyCanStep(lvl->enemyPositions[i], dx, dy)) { + lvl->enemyPositions[i].x += dx; + lvl->enemyPositions[i].y += dy; + } + lua_createtable(L, 0, 3); + lua_pushnumber(L, lvl->enemyPositions[i].y + 1); + lua_setfield(L, -2, "y"); + lua_pushnumber(L, lvl->enemyPositions[i].x + 1); + lua_setfield(L, -2, "x"); + lua_pushnumber(L, lvl->enemyPositions[i].id); + lua_setfield(L, -2, "id"); + + return 1; +} + +/* + * c_get_enemies() + */ +static int c_get_enemies(lua_State *L) { + lua_createtable(L, int(lvl->enemyPositions.size()), 0); + + int idx = 0; + + for (auto &pos : lvl->enemyPositions) { + lua_pushnumber(L, ++idx); + lua_createtable(L, 0, 3); + lua_pushnumber(L, pos.id); + lua_setfield(L, -2, "id"); + lua_pushnumber(L, pos.x + 1); + lua_setfield(L, -2, "x"); + lua_pushnumber(L, pos.y + 1); + lua_setfield(L, -2, "y"); + lua_settable(L, -3); + } + + return 1; +} + +/* + * c_spawn_enemy(int x, int y) + */ +static int c_spawn_enemy(lua_State *L) { return 1; } + +/* + * c_destroy_enemy(int id) + */ +static int c_destroy_enemy(lua_State *L) { return 1; } + +/* + * c_get_map() + */ +static int c_get_map(lua_State *L) { + lua_createtable(L, int(lvl->map.size()), 0); + int idx = 0; + for (auto &vec : lvl->map) { + lua_pushnumber(L, ++idx); + lua_createtable(L, int(vec.size()), 0); + int inner_idx = 0; + for (auto &c : vec) { + lua_pushnumber(L, ++inner_idx); + lua_pushnumber(L, c == WALL_SPACE ? 1 : 0); + lua_rawset(L, -3); + } + lua_rawset(L, -3); + } + return 1; +} + +/* + * c_trigger_level_start() + */ +static int c_trigger_level_start(lua_State *L) { + scene = Scene::LEVEL; + lua_pushboolean(L, true); + return 1; +} +/* + * c_trigger_win() + */ +static int c_trigger_win(lua_State *L) { + scene = Scene::WIN; + lua_pushboolean(L, true); + return 1; +} + +/* + * c_trigger_loss() + */ +static int c_trigger_loss(lua_State *L) { + scene = Scene::LOSS; + lua_pushboolean(L, true); + return 1; +} + +static int c_get_scene(lua_State *L) { + lua_pushnumber(L, scene); + return 1; +} + +static int c_get_treasures(lua_State *L) { + lua_createtable(L, static_cast(lvl->treasurePositions.size()), 0); + int idx = 0; + for (auto &t : lvl->treasurePositions) { + lua_pushnumber(L, ++idx); + lua_createtable(L, 0, 3); + lua_pushnumber(L, t.y + 1); + lua_setfield(L, -2, "y"); + lua_pushnumber(L, t.x + 1); + lua_setfield(L, -2, "x"); + lua_pushnumber(L, t.id); + lua_setfield(L, -2, "id"); + lua_settable(L, -3); + } + return 1; +} + +static int c_score_treasure(lua_State *L) { + int id = static_cast(lua_tonumber(L, -1)); + + erase_if(lvl->treasurePositions, [id](Pos t) { return t.id == id; }); + + return 1; +} + +// not for lua use +void init_c_api(lua_State *L) { + lua_register(L, "c_move_player", c_move_player); + lua_register(L, "c_move_enemy", c_move_enemy); + lua_register(L, "c_spawn_enemy", c_spawn_enemy); + lua_register(L, "c_destroy_enemy", c_destroy_enemy); + lua_register(L, "c_get_enemies", c_get_enemies); + lua_register(L, "c_get_player_position", c_get_player_position); + lua_register(L, "c_get_map", c_get_map); + lua_register(L, "c_trigger_level_start", c_trigger_level_start); + lua_register(L, "c_trigger_win", c_trigger_win); + lua_register(L, "c_trigger_loss", c_trigger_loss); + lua_register(L, "c_get_scene", c_get_scene); + lua_register(L, "c_score_treasure", c_score_treasure); + lua_register(L, "c_get_treasures", c_get_treasures); +} + +#endif // DNG_CAPI_H \ No newline at end of file diff --git a/src/LuaApi.h b/src/LuaApi.h new file mode 100644 index 0000000..cb68e36 --- /dev/null +++ b/src/LuaApi.h @@ -0,0 +1,89 @@ +#ifndef DNG_LUA_API_H +#define DNG_LUA_API_H + +#include +#include + +struct LState { + lua_State *onkeypress; + lua_State *onupdate; + lua_State *onintro; + lua_State *onwin; + lua_State *onloss; +} typedef LState; + +const char *ON_KEYPRESS = "onKeypress"; +const char *ON_UPDATE = "onUpdate"; +const char *ON_INTRO = "onIntro"; +const char *ON_WIN = "onWin"; +const char *ON_LOSS = "onLoss"; + +LState *init_default(lua_State *L) { + auto *state = static_cast(malloc(sizeof(LState))); + + state->onkeypress = L; + state->onupdate = L; + state->onintro = L; + state->onwin = L; + state->onloss = L; + + return state; +} + +bool check_fn(lua_State *L, const char *fn) { + lua_getglobal(L, fn); + return lua_isfunction(L, -1); +} + +void override_file_fns(lua_State *L, LState *state) { + if (check_fn(L, ON_KEYPRESS)) { + state->onkeypress = L; + } + if (check_fn(L, ON_UPDATE)) { + state->onupdate = L; + } + if (check_fn(L, ON_INTRO)) { + state->onintro = L; + } + if (check_fn(L, ON_WIN)) { + state->onwin = L; + } + if (check_fn(L, ON_LOSS)) { + state->onloss = L; + } +} + +bool lua_dofn(lua_State *L, const char *fn) { + lua_getglobal(L, fn); + if (!lua_isfunction(L, -1)) { + std::cout << "[C] Error " << fn << " not function | not found" << std::endl; + return false; + } + lua_pcall(L, 0, 1, 0); + return true; +} + +bool lua_dofn_with_key(lua_State *L, const char *fn, char pressedKey) { + lua_getglobal(L, fn); + if (!lua_isfunction(L, -1)) { + std::cout << "[C] Error " << fn << " not function | not found" << std::endl; + return false; + } + lua_pushinteger(L, pressedKey); + lua_pcall(L, 1, 1, 0); + return true; +} + +bool lua_onkeypress(lua_State *L, char pressedKey) { + return lua_dofn_with_key(L, "onKeyPress", pressedKey); +} + +bool lua_onupdate(lua_State *L) { return lua_dofn(L, "onUpdate"); } + +bool lua_onintro(lua_State *L) { return lua_dofn(L, "onIntro"); } + +bool lua_onwin(lua_State *L) { return lua_dofn(L, "onWin"); } + +bool lua_onloss(lua_State *L) { return lua_dofn(L, "onLoss"); } + +#endif // DNG_LUA_API_H \ No newline at end of file diff --git a/src/Scene.h b/src/Scene.h new file mode 100644 index 0000000..dab51c5 --- /dev/null +++ b/src/Scene.h @@ -0,0 +1,5 @@ +#ifndef DNG_SCENE_H +#define DNG_SCENE_H +/* sync with constants.lua */ +enum Scene { INTRO, LEVEL, WIN, LOSS }; +#endif // DNG_SCENE_H diff --git a/src/main.cpp b/src/main.cpp index eef9777..a9b5d3b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,20 +1,16 @@ -#include "Api.h" +#include "CApi.h" #include "Level.h" +#include "LuaApi.h" #include #include #include #include const char *DEFAULT_PROC = "include/defaults.lua"; -std::shared_ptr lvl; -struct LState { - lua_State *onkeypress; - lua_State *onupdate; -} typedef LState; +std::shared_ptr lvl; -bool call_onkeypress(lua_State *L, char pressedKey); -bool call_onupdate(lua_State *L); +Scene scene; int main(int argc, char **argv) { @@ -28,6 +24,7 @@ int main(int argc, char **argv) { std::filesystem::path luaFile{lvl_pfx + "/proc.lua"}; lvl = std::make_shared(); + scene = Scene::INTRO; lvl->loadLevelFromFile(mapFile.c_str()); @@ -47,20 +44,11 @@ int main(int argc, char **argv) { } // Initialize to default - LState l_state = {.onkeypress = L_default, .onupdate = L_default}; + LState *l_state = init_default(L_default); if (std::filesystem::exists(luaFile) && luaL_dofile(L_lvl, luaFile.c_str()) == LUA_OK) { - - // overwrite defaults - lua_getglobal(L_lvl, "onKeyPress"); - if (lua_isfunction(L_lvl, -1)) { - l_state.onkeypress = L_lvl; - } - lua_getglobal(L_lvl, "onUpdate"); - if (lua_isfunction(L_lvl, -1)) { - l_state.onupdate = L_lvl; - } + override_file_fns(L_lvl, l_state); } else if (std::filesystem::exists(luaFile)) { std::cout << "[C] No Good" << std::endl; luaL_error(L_lvl, "Error: %s\n", lua_tostring(L_lvl, -1)); @@ -72,12 +60,35 @@ int main(int argc, char **argv) { char in; do { - lvl->print(); - std::cin >> in; - if (!call_onkeypress(l_state.onkeypress, in)) { + if (scene == Scene::INTRO) { + if (!lua_onintro(l_state->onintro)) { + quit = true; + } + std::cin >> in; + if (!lua_onkeypress(l_state->onkeypress, in)) { + quit = true; + } + } else if (scene == Scene::LEVEL) { + lvl->print(); + + std::cin >> in; + if (!lua_onkeypress(l_state->onkeypress, in)) { + quit = true; + } + if (!lua_onupdate(l_state->onupdate)) { + quit = true; + } + } else if (scene == Scene::WIN) { + lvl->player.x = -1; // hide + lvl->player.y = -1; // hide + lvl->print(); + lua_onwin(l_state->onwin); quit = true; - } - if (!call_onupdate(l_state.onupdate)) { + } else if (scene == Scene::LOSS) { + lvl->player.x = -1; // hide + lvl->player.y = -1; // hide + lvl->print(); + lua_onloss(l_state->onloss); quit = true; } if (!quit && in == 'q') { @@ -89,24 +100,3 @@ int main(int argc, char **argv) { return EXIT_SUCCESS; } - -bool call_onkeypress(lua_State *L, char pressedKey) { - lua_getglobal(L, "onKeyPress"); - if (!lua_isfunction(L, -1)) { - std::cout << "[C] Error onKeyPress not function | not found" << std::endl; - return false; - } - lua_pushinteger(L, pressedKey); - lua_pcall(L, 1, 1, 0); - return true; -} - -bool call_onupdate(lua_State *L) { - lua_getglobal(L, "onUpdate"); - if (!lua_isfunction(L, -1)) { - std::cout << "[C] Error onUpdate not function | not found" << std::endl; - return false; - } - lua_pcall(L, 0, 1, 0); - return true; -} \ No newline at end of file -- cgit v1.2.3-54-g00ecf