summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Api.h71
-rw-r--r--src/Level.cpp108
-rw-r--r--src/Level.h45
-rw-r--r--src/main.cpp83
4 files changed, 307 insertions, 0 deletions
diff --git a/src/Api.h b/src/Api.h
new file mode 100644
index 0000000..da763c2
--- /dev/null
+++ b/src/Api.h
@@ -0,0 +1,71 @@
+#ifndef DNG_API_H
+#define DNG_API_H
+
+#include "Level.h"
+#include <lua.hpp>
+#include <memory>
+
+extern std::shared_ptr<Level> lvl;
+
+static int
+c_update_player_pos(lua_State* L)
+{
+ // stack ordering
+ int dy = static_cast<int>(lua_tonumber(L, -1));
+ int dx = static_cast<int>(lua_tonumber(L, -2));
+
+ bool res = false;
+
+ if (lvl->canStep(dx, dy)) {
+ lvl->player.x += dx;
+ lvl->player.y += dy;
+ res = true;
+ }
+
+ lua_pushboolean(L, res);
+
+ return 1;
+}
+
+static int
+c_player_can_move(lua_State* L)
+{
+ // stack ordering
+ int dy = static_cast<int>(lua_tonumber(L, -1));
+ int dx = static_cast<int>(lua_tonumber(L, -2));
+
+ bool res = lvl->canStep(dx, dy);
+ lua_pushboolean(L, res);
+
+ return 1;
+}
+
+static int
+c_enemy_can_move(lua_State* L)
+{
+ return 1;
+}
+
+static int
+c_spawn_enemy(lua_State* L)
+{
+ return 1;
+}
+
+static int
+c_destroy_enemy(lua_State* L)
+{
+ return 1;
+}
+
+static void
+init_c_api(lua_State* L)
+{
+ lua_register(L, "c_update_player_pos", c_update_player_pos);
+ lua_register(L, "c_player_can_move", c_player_can_move);
+ lua_register(L, "c_enemy_can_move", c_enemy_can_move);
+ lua_register(L, "c_spawn_enemy", c_spawn_enemy);
+ lua_register(L, "c_destroy_enemy", c_destroy_enemy);
+}
+
+#endif // DNG_API_H \ No newline at end of file
diff --git a/src/Level.cpp b/src/Level.cpp
new file mode 100644
index 0000000..013c2a1
--- /dev/null
+++ b/src/Level.cpp
@@ -0,0 +1,108 @@
+#include "Level.h"
+#include <fstream>
+#include <iostream>
+#include <string>
+
+void
+Level::loadLevelFromFile(const char* filePath)
+{
+ std::ifstream mapFile(filePath);
+ if (mapFile.is_open()) {
+
+ // each element in the map has a unique ID
+ // some magic but player is always 0
+ const int playerId = 0;
+ // from 1 -> N each enemy and treasure has its own unique ID
+ // IDs are unique entirely, not just per enemy or treasure
+
+
+ std::string line;
+ int y = 0;
+ while (std::getline(mapFile, line)) {
+ this->map.emplace_back();
+ int x = 0;
+ for (char c : line) {
+ if (c == WALL_TKN) {
+ this->map[y].push_back(WALL_SPACE);
+ } else if (c == EMPTY_TKN) {
+ this->map[y].push_back(BLANK_SPACE);
+ } else if (c == ENEMY_TKN) {
+ this->enemyPositions.push_back(
+ { .id = this->nextId(), .x = x, .y = y });
+ this->map[y].push_back(BLANK_SPACE);
+ } else if (c == PLAYER_TKN) {
+ this->player = { .id = playerId, .x = x, .y = y };
+ this->map[y].push_back(BLANK_SPACE);
+ } else if (c == TREASURE_TKN) {
+ this->treasurePositions.push_back(
+ { .id = this->nextId(), .x = x, .y = y });
+ this->map[y].push_back(BLANK_SPACE);
+ } else {
+ continue;
+ }
+ ++x;
+ }
+ ++y;
+ }
+ }
+ mapFile.close();
+}
+
+bool
+Level::isEmpty(int x, int y)
+{
+ return map[y][x] == BLANK_SPACE;
+}
+
+bool
+Level::canStep(int dx, int dy)
+{
+ bool res = map[player.y + dy][player.x + dx] != WALL_SPACE;
+ return res;
+}
+
+void
+Level::print()
+{
+ int x = 0;
+ int y = 0;
+ for (auto& row : map) {
+ for (auto& tile : row) {
+ bool printed = false;
+ if (player.x == x && player.y == y) {
+ std::cout << "p";
+ printed = true;
+ }
+ for (auto pos : enemyPositions) {
+ if (pos.x == x && pos.y == y) {
+ std::cout << "e";
+ printed = true;
+ }
+ }
+ for (auto pos : treasurePositions) {
+ if (pos.x == x && pos.y == y) {
+ std::cout << "t";
+ printed = true;
+ }
+ }
+ if (tile == WALL_SPACE) {
+ std::cout << tile;
+ printed = true;
+ }
+ if (!printed) {
+ std::cout << " ";
+ }
+ std::cout << " ";
+ ++x;
+ }
+ std::cout << "\n";
+ ++y;
+ x = 0;
+ }
+}
+
+int
+Level::nextId()
+{
+ return idCounter++;
+} \ No newline at end of file
diff --git a/src/Level.h b/src/Level.h
new file mode 100644
index 0000000..1607f0c
--- /dev/null
+++ b/src/Level.h
@@ -0,0 +1,45 @@
+#ifndef DNG_LEVEL_H
+#define DNG_LEVEL_H
+
+static const char PLAYER_TKN = 'p';
+static const char WALL_TKN = 'w';
+static const char EMPTY_TKN = '0';
+static const char TREASURE_TKN = 't';
+static const char ENEMY_TKN = 'e';
+static const char BLANK_SPACE = '\0';
+static const char WALL_SPACE = '#';
+
+#include <memory>
+#include <vector>
+
+struct Pos
+{
+ int id;
+ int x;
+ int y;
+} typedef Coord;
+
+class Level
+{
+
+public:
+ void loadLevelFromFile(const char* filePath);
+
+ bool isEmpty(int x, int y);
+
+ bool canStep(int dx, int dy);
+
+ void print();
+
+ int nextId();
+
+ std::vector<std::vector<char>> map;
+ Pos player;
+ std::vector<Pos> enemyPositions;
+ std::vector<Pos> treasurePositions;
+
+private:
+ int idCounter = 1; // defaults at 1 (player always 0)
+};
+
+#endif // DNG_LEVEL_H
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100644
index 0000000..fb61369
--- /dev/null
+++ b/src/main.cpp
@@ -0,0 +1,83 @@
+#include "Api.h"
+#include "Level.h"
+#include <SFML/Graphics.hpp>
+#include <filesystem>
+#include <iostream>
+#include <lua.hpp>
+#include <memory>
+
+const char* DEFAULT_PROC = "include/default_proc.lua";
+std::shared_ptr<Level> lvl = std::make_shared<Level>();
+
+bool
+call_onkeypress(lua_State* L, char pressedKey);
+
+int
+main(int argc, char** argv)
+{
+
+ if (argc <= 1) {
+ return -1;
+ }
+
+ std::string lvl_pfx = argv[1];
+
+ std::filesystem::path mapFile{ lvl_pfx + "/dng.map" };
+ std::filesystem::path luaFile{ lvl_pfx + "/proc.lua" };
+
+ lvl->loadLevelFromFile(mapFile.c_str());
+
+ lua_State* L_lvl = luaL_newstate();
+ luaL_openlibs(L_lvl);
+ init_c_api(L_lvl);
+
+ lua_State* L_default = luaL_newstate();
+ luaL_openlibs(L_default);
+ init_c_api(L_default);
+
+ if (std::filesystem::exists(luaFile) &&
+ luaL_dofile(L_default, DEFAULT_PROC) != LUA_OK) {
+ std::cout << "Failed to load default proc" << std::endl;
+ luaL_error(L_default, "Error: %s", lua_tostring(L_default, -1));
+ return EXIT_FAILURE;
+ }
+
+ if (std::filesystem::exists(luaFile) &&
+ luaL_dofile(L_lvl, luaFile.c_str()) != LUA_OK) {
+ std::cout << "[C] No Good" << std::endl;
+ luaL_error(L_lvl, "Error: %s\n", lua_tostring(L_lvl, -1));
+ return EXIT_FAILURE;
+ }
+
+ bool quit = false;
+
+ char in;
+
+ do {
+ lvl->print();
+ std::cin >> in;
+ if (!call_onkeypress(L_default, in)) {
+ quit = true;
+ }
+ if (!quit && in == 'q') {
+ quit = true;
+ }
+ } while (!quit);
+
+ std::cout << "[C] Quit" << std::endl;
+
+ 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;
+} \ No newline at end of file