summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.clang-format178
-rw-r--r--.gitignore2
-rw-r--r--CMakeLists.txt21
-rw-r--r--include/constants.lua10
-rw-r--r--include/default_proc.lua42
-rw-r--r--maps/lvl1/dng.map10
-rw-r--r--maps/lvl1/proc.lua4
-rw-r--r--src/Api.h71
-rw-r--r--src/Level.cpp108
-rw-r--r--src/Level.h45
-rw-r--r--src/main.cpp83
11 files changed, 574 insertions, 0 deletions
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000..c0d69d8
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,178 @@
+---
+Language: Cpp
+# BasedOnStyle: Mozilla
+AccessModifierOffset: -2
+AlignAfterOpenBracket: Align
+AlignArrayOfStructures: None
+AlignConsecutiveMacros: None
+AlignConsecutiveAssignments: None
+AlignConsecutiveBitFields: None
+AlignConsecutiveDeclarations: None
+AlignEscapedNewlines: Right
+AlignOperands: Align
+AlignTrailingComments: true
+AllowAllArgumentsOnNextLine: true
+AllowAllConstructorInitializersOnNextLine: true
+AllowAllParametersOfDeclarationOnNextLine: false
+AllowShortEnumsOnASingleLine: true
+AllowShortBlocksOnASingleLine: Never
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: Inline
+AllowShortLambdasOnASingleLine: All
+AllowShortIfStatementsOnASingleLine: Never
+AllowShortLoopsOnASingleLine: false
+AlwaysBreakAfterDefinitionReturnType: TopLevel
+AlwaysBreakAfterReturnType: TopLevel
+AlwaysBreakBeforeMultilineStrings: false
+AlwaysBreakTemplateDeclarations: Yes
+AttributeMacros:
+ - __capability
+BinPackArguments: false
+BinPackParameters: false
+BraceWrapping:
+ AfterCaseLabel: false
+ AfterClass: true
+ AfterControlStatement: Never
+ AfterEnum: true
+ AfterFunction: true
+ AfterNamespace: false
+ AfterObjCDeclaration: false
+ AfterStruct: true
+ AfterUnion: true
+ AfterExternBlock: true
+ BeforeCatch: false
+ BeforeElse: false
+ BeforeLambdaBody: false
+ BeforeWhile: false
+ IndentBraces: false
+ SplitEmptyFunction: true
+ SplitEmptyRecord: false
+ SplitEmptyNamespace: true
+BreakBeforeBinaryOperators: None
+BreakBeforeConceptDeclarations: true
+BreakBeforeBraces: Mozilla
+BreakBeforeInheritanceComma: false
+BreakInheritanceList: BeforeComma
+BreakBeforeTernaryOperators: true
+BreakConstructorInitializersBeforeComma: false
+BreakConstructorInitializers: BeforeComma
+BreakAfterJavaFieldAnnotations: false
+BreakStringLiterals: true
+ColumnLimit: 80
+CommentPragmas: '^ IWYU pragma:'
+CompactNamespaces: false
+ConstructorInitializerAllOnOneLineOrOnePerLine: false
+ConstructorInitializerIndentWidth: 2
+ContinuationIndentWidth: 2
+Cpp11BracedListStyle: false
+DeriveLineEnding: true
+DerivePointerAlignment: false
+DisableFormat: false
+EmptyLineAfterAccessModifier: Never
+EmptyLineBeforeAccessModifier: LogicalBlock
+ExperimentalAutoDetectBinPacking: false
+FixNamespaceComments: false
+ForEachMacros:
+ - foreach
+ - Q_FOREACH
+ - BOOST_FOREACH
+IfMacros:
+ - KJ_IF_MAYBE
+IncludeBlocks: Preserve
+IncludeCategories:
+ - Regex: '^"(llvm|llvm-c|clang|clang-c)/'
+ Priority: 2
+ SortPriority: 0
+ CaseSensitive: false
+ - Regex: '^(<|"(gtest|gmock|isl|json)/)'
+ Priority: 3
+ SortPriority: 0
+ CaseSensitive: false
+ - Regex: '.*'
+ Priority: 1
+ SortPriority: 0
+ CaseSensitive: false
+IncludeIsMainRegex: '(Test)?$'
+IncludeIsMainSourceRegex: ''
+IndentAccessModifiers: false
+IndentCaseLabels: true
+IndentCaseBlocks: false
+IndentGotoLabels: true
+IndentPPDirectives: None
+IndentExternBlock: AfterExternBlock
+IndentRequires: false
+IndentWidth: 2
+IndentWrappedFunctionNames: false
+InsertTrailingCommas: None
+JavaScriptQuotes: Leave
+JavaScriptWrapImports: true
+KeepEmptyLinesAtTheStartOfBlocks: true
+LambdaBodyIndentation: Signature
+MacroBlockBegin: ''
+MacroBlockEnd: ''
+MaxEmptyLinesToKeep: 1
+NamespaceIndentation: None
+ObjCBinPackProtocolList: Auto
+ObjCBlockIndentWidth: 2
+ObjCBreakBeforeNestedBlockParam: true
+ObjCSpaceAfterProperty: true
+ObjCSpaceBeforeProtocolList: false
+PenaltyBreakAssignment: 2
+PenaltyBreakBeforeFirstCallParameter: 19
+PenaltyBreakComment: 300
+PenaltyBreakFirstLessLess: 120
+PenaltyBreakString: 1000
+PenaltyBreakTemplateDeclaration: 10
+PenaltyExcessCharacter: 1000000
+PenaltyReturnTypeOnItsOwnLine: 200
+PenaltyIndentedWhitespace: 0
+PointerAlignment: Left
+PPIndentWidth: -1
+ReferenceAlignment: Pointer
+ReflowComments: true
+ShortNamespaceLines: 1
+SortIncludes: CaseSensitive
+SortJavaStaticImport: Before
+SortUsingDeclarations: true
+SpaceAfterCStyleCast: false
+SpaceAfterLogicalNot: false
+SpaceAfterTemplateKeyword: false
+SpaceBeforeAssignmentOperators: true
+SpaceBeforeCaseColon: false
+SpaceBeforeCpp11BracedList: false
+SpaceBeforeCtorInitializerColon: true
+SpaceBeforeInheritanceColon: true
+SpaceBeforeParens: ControlStatements
+SpaceAroundPointerQualifiers: Default
+SpaceBeforeRangeBasedForLoopColon: true
+SpaceInEmptyBlock: false
+SpaceInEmptyParentheses: false
+SpacesBeforeTrailingComments: 1
+SpacesInAngles: Never
+SpacesInConditionalStatement: false
+SpacesInContainerLiterals: true
+SpacesInCStyleCastParentheses: false
+SpacesInLineCommentPrefix:
+ Minimum: 1
+ Maximum: -1
+SpacesInParentheses: false
+SpacesInSquareBrackets: false
+SpaceBeforeSquareBrackets: false
+BitFieldColonSpacing: Both
+Standard: Latest
+StatementAttributeLikeMacros:
+ - Q_EMIT
+StatementMacros:
+ - Q_UNUSED
+ - QT_REQUIRE_VERSION
+TabWidth: 8
+UseCRLF: false
+UseTab: Never
+WhitespaceSensitiveMacros:
+ - STRINGIZE
+ - PP_STRINGIZE
+ - BOOST_PP_STRINGIZE
+ - NS_SWIFT_NAME
+ - CF_SWIFT_NAME
+...
+
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..8e24b65
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+.idea
+cmake-build-debug
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..3dcce6a
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,21 @@
+cmake_minimum_required(VERSION 3.23)
+project(dng)
+
+set(CMAKE_CXX_STANDARD 23)
+
+find_package(Lua REQUIRED)
+
+# check what features I use and assert minimum
+if (LUA_VERSION_STRING VERSION_LESS "5.4")
+ message(FATAL_ERROR "Invalid Lau version: ${LUA_VERSION_STRING} - must be >= 5.4")
+endif()
+
+set(SFML_LIBRARIES sfml-system sfml-window sfml-graphics)
+find_package(SFML 2.5 REQUIRED COMPONENTS system window graphics)
+
+#file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/res DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
+#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)
+target_link_libraries(${PROJECT_NAME} ${LUA_LIBRARIES} ${SFML_LIBRARIES})
diff --git a/include/constants.lua b/include/constants.lua
new file mode 100644
index 0000000..5d8e860
--- /dev/null
+++ b/include/constants.lua
@@ -0,0 +1,10 @@
+KEY_W = 119
+KEY_A = 97
+KEY_S = 115
+KEY_D = 100
+KEY_SPACE = ' '
+
+
+TILE_WALL = 'w'
+TILE_SPACE = ' '
+TILE_ENEMY = 'e' \ No newline at end of file
diff --git a/include/default_proc.lua b/include/default_proc.lua
new file mode 100644
index 0000000..13ef15d
--- /dev/null
+++ b/include/default_proc.lua
@@ -0,0 +1,42 @@
+--[[
+These are the default implementations of the override actions.
+If you want to add custom logic into your game you can define a "proc.lua" in your map dir.
+
+The following functions are also available via our C library:
+
+void c_update_player_pos (dx, dy)
+boolean c_player_can_move (dx, dy)
+boolean c_enemy_can_move (id, dx, dy)
+c_spawn_enemy (x, y)
+c_destroy_enemy (id)
+c_trigger_win()
+c_trigger_loss(msg)
+c_fatal(msg)
+
+--]]
+
+require "include.constants";
+
+---@param pressedKey number
+function onKeyPress(pressedKey)
+
+ 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
+
+ if c_player_can_move(dx, dy) then
+ c_update_player_pos(dx, dy)
+ end
+end
+
+function onUpdate()
+
+end \ No newline at end of file
diff --git a/maps/lvl1/dng.map b/maps/lvl1/dng.map
new file mode 100644
index 0000000..fb9ceb1
--- /dev/null
+++ b/maps/lvl1/dng.map
@@ -0,0 +1,10 @@
+w w w w w w w w w w
+w 0 0 0 0 0 0 0 0 w
+w 0 w w 0 w w 0 0 w
+w p 0 0 0 e 0 w 0 w
+w 0 w w w 0 w w 0 w
+w 0 w w w 0 w w w w
+w 0 w t w 0 0 0 0 w
+w 0 w 0 w w w w 0 w
+w 0 0 0 w 0 0 0 0 w
+w w w w w w w w w w
diff --git a/maps/lvl1/proc.lua b/maps/lvl1/proc.lua
new file mode 100644
index 0000000..fec9ed5
--- /dev/null
+++ b/maps/lvl1/proc.lua
@@ -0,0 +1,4 @@
+require "include.constants";
+
+function onKeyPress(key)
+end \ No newline at end of file
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