diff options
34 files changed, 2499 insertions, 0 deletions
diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..b806607 --- /dev/null +++ b/.clang-format @@ -0,0 +1,178 @@ +--- +Language: Cpp +# BasedOnStyle: LLVM +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: true +AllowShortEnumsOnASingleLine: true +AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: All +AllowShortLambdasOnASingleLine: All +AllowShortIfStatementsOnASingleLine: Never +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: MultiLine +AttributeMacros: + - __capability +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: Never + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + BeforeLambdaBody: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: None +BreakBeforeConceptDeclarations: true +BreakBeforeBraces: Attach +BreakBeforeInheritanceComma: false +BreakInheritanceList: BeforeColon +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 80 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DeriveLineEnding: true +DerivePointerAlignment: false +DisableFormat: false +EmptyLineAfterAccessModifier: Never +EmptyLineBeforeAccessModifier: LogicalBlock +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +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: false +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: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +PenaltyIndentedWhitespace: 0 +PointerAlignment: Right +PPIndentWidth: -1 +ReferenceAlignment: Pointer +ReflowComments: true +ShortNamespaceLines: 1 +SortIncludes: CaseSensitive +SortJavaStaticImport: Before +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: true +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/.copyright_headers/C_HEADER.txt b/.copyright_headers/C_HEADER.txt new file mode 100644 index 0000000..f51ad28 --- /dev/null +++ b/.copyright_headers/C_HEADER.txt @@ -0,0 +1,25 @@ +//======================================================================== +// dng +//------------------------------------------------------------------------ +// Copyright (c) 2022 Steph Enders <steph@senders.io> +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== diff --git a/.copyright_headers/LUA_HEADER.txt b/.copyright_headers/LUA_HEADER.txt new file mode 100644 index 0000000..4204e33 --- /dev/null +++ b/.copyright_headers/LUA_HEADER.txt @@ -0,0 +1,25 @@ +-- ----------------------------------------------------------------------- +-- dng +-- ------------------------------------------------------------------------ +-- Copyright (c) 2022 Steph Enders <steph@senders.io> +-- +-- This software is provided 'as-is', without any express or implied +-- warranty. In no event will the authors be held liable for any damages +-- arising from the use of this software. +-- +-- Permission is granted to anyone to use this software for any purpose, +-- including commercial applications, and to alter it and redistribute it +-- freely, subject to the following restrictions: +-- +-- 1. The origin of this software must not be misrepresented; you must not +-- claim that you wrote the original software. If you use this software +-- in a product, an acknowledgment in the product documentation would +-- be appreciated but is not required. +-- +-- 2. Altered source versions must be plainly marked as such, and must not +-- be misrepresented as being the original software. +-- +-- 3. This notice may not be removed or altered from any source +-- distribution. +-- +-- ----------------------------------------------------------------------- diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..810508e --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +.idea +cmake-build* +build +Makefile +.cmake +CMakeFiles +cmake_install.cmake +CMakeCache.txt diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..93b742b --- /dev/null +++ b/.gitmodules @@ -0,0 +1,8 @@ +[submodule "thirdparty/SFML"] + path = thirdparty/SFML + url = https://github.com/SFML/SFML + branch = 2.5.x +[submodule "thirdparty/lua"] + path = thirdparty/lua + url = https://github.com/lua/lua + branch = v5.4.0-patch diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..69cd9b2 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,96 @@ +cmake_minimum_required(VERSION 3.16) +project(dng + VERSION 0.1.0) +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_INSTALL_PREFIX ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-${PROJECT_VERSION}) + +# Setup Lua Libraries +# To determine which files look at the lua/makefile to see how the targets are built +set(LUA_SRC ${PROJECT_SOURCE_DIR}/thirdparty/lua) +add_library(lua STATIC + ${LUA_SRC}/lapi.c + ${LUA_SRC}/lcode.c + ${LUA_SRC}/lctype.c + ${LUA_SRC}/ldebug.c + ${LUA_SRC}/ldo.c + ${LUA_SRC}/ldump.c + ${LUA_SRC}/lfunc.c + ${LUA_SRC}/lgc.c + ${LUA_SRC}/llex.c + ${LUA_SRC}/lmem.c + ${LUA_SRC}/lobject.c + ${LUA_SRC}/lopcodes.c + ${LUA_SRC}/lparser.c + ${LUA_SRC}/lstate.c + ${LUA_SRC}/lstring.c + ${LUA_SRC}/ltable.c + ${LUA_SRC}/ltm.c + ${LUA_SRC}/lundump.c + ${LUA_SRC}/lvm.c + ${LUA_SRC}/lzio.c + ${LUA_SRC}/ltests.c) +add_library(lauxlib STATIC ${LUA_SRC}/lauxlib.c) +add_library(lualib STATIC + ${LUA_SRC}/lbaselib.c + ${LUA_SRC}/lcorolib.c + ${LUA_SRC}/ldblib.c + ${LUA_SRC}/linit.c + ${LUA_SRC}/liolib.c + ${LUA_SRC}/lmathlib.c + ${LUA_SRC}/loadlib.c + ${LUA_SRC}/loslib.c + ${LUA_SRC}/lstrlib.c + ${LUA_SRC}/ltablib.c + ${LUA_SRC}/lutf8lib.c) +target_compile_definitions(lualib PRIVATE -DLUA_USE_POSIX=1) # to properly use mkstemp +target_include_directories(lua PUBLIC lua) +target_include_directories(lauxlib PUBLIC lua) +target_include_directories(lualib PUBLIC lua) +target_link_libraries(lauxlib lua) +set(LUA_LIBRARIES lua lualib lauxlib) +include_directories(${PROJECT_SOURCE_DIR}/thirdparty/lua) + +# System specific includes +if (UNIX) + set(RES_LIB src/linux/res.h) +endif () + +add_executable(${PROJECT_NAME} src/main.cpp src/Level.cpp src/Level.h src/CApi.h src/Scene.h src/LuaApi.h src/MessageBox.h ${RES_LIB}) +target_link_libraries(${PROJECT_NAME} PUBLIC ${LUA_LIBRARIES}) + +# configure and link SFML +set(BUILD_SHARED_LIBS FALSE) +set(SFML_LIBRARIES sfml-system sfml-window sfml-graphics) +if (WIN32) + set(SFML_USE_STATIC_STD_LIBS TRUE) +endif () +set(SFML_USE_SYSTEM_DEPS ON) +set(CMAKE_SUPPRESS_DEVELOPER_WARNINGS ON) +add_subdirectory(${PROJECT_SOURCE_DIR}/thirdparty/SFML EXCLUDE_FROM_ALL) +target_link_libraries(${PROJECT_NAME} PUBLIC ${SFML_LIBRARIES} ${LUA_LIBRARIES}) + + +# Install Directives + +if (UNIX) + set(SFML_INSTALL_PKGCONFIG_FILES FALSE) +endif () +install(TARGETS ${PROJECT_NAME} DESTINATION .) +install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/res DESTINATION .) +install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/maps DESTINATION .) +install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/dnglib DESTINATION .) +install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/LICENSE DESTINATION .) +install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/thirdparty-licenses.txt DESTINATION .) + + +# Package Directives +set(CPACK_GEN TGZ) +if (WIN32) + set(CPACK_GEN ZIP) +endif () + +set(CPACK_GENERATOR ${CPACK_GEN}) +set(CPACK_SOURCE_GENERATOR ${CPACK_GEN}) +set(CPACK_RESOURCE_FILE_README ${CMAKE_CURRENT_SOURCE_DIR}/README.md) +set(CPACK_RESOURCE_FILE_LICENSE ${CMAKE_CURRENT_SOURCE_DIR}/LICENSE) +include(CPack)
\ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..fbfcd48 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,3 @@ +# Contributing + +Pull requests welcome, but I do not monitor the repositories often. @@ -0,0 +1,17 @@ +Copyright (c) 2022 Steph Enders <steph@senders.io> + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. diff --git a/README.md b/README.md new file mode 100644 index 0000000..72c7c9f --- /dev/null +++ b/README.md @@ -0,0 +1,134 @@ +# dng + +dng is a maze/puzzle game + engine! Design and work your way through your own maze avoiding enemies and finding +treasure! + +## How to run + +You can run the game by `dng path/to/map/lvl` + +To run the first level: + +`dng maps/lvl1` + +## Create your own level! + +Levels use the following directory structure: + +```shell +level-name/ + dng.map # required -the map file + proc.lua # optional - custom lua overrides +``` + +### Map Format + +The map format is just a text file with the following key tokens: + +| Token | Description | +|:------|:-------------------------| +| w | Wall | +| p | The player (must have 1) | +| e | Enemies (0 or more) | +| t | Treasure (0 or more) | +| 0 | Empty space | + +#### Tips + +Space your map out using whitespace between every token (`w w w w` instead of `wwww`) for better readability. +Use a monospace font to help things align + +### Custom Lua Code + +Create a `proc.lua` in your level folder. +You can override anything found in `dnglib` using standard lua scoping rules. +If you wish to call the original defaults you can include `dnglib.defaults` in your file: +`local defaults = require('dnglib.defaults')` and call the functions: + +```lua +package.path = '[' +function onKeyPress(key) + -- Set your own overrides + defaults.onKeyPress(key) +end +``` + +## Develop + +dng uses git-submodules: + +```shell +git clone https://github.com/s3nd3r5/dng +git submodules init +git submodules update +``` + +### Dependencies + +Current build process is setup for a *nix like environment. + +| Dependency | Version | +|:-----------|:--------| +| c++ | 20+ | +| g++ | 8+ | +| CMake | 3.16+ | +| Lua | 5.4.* | +| SFML | 2.5.* | + +_Note: with some CMake modifications we could probably leverage lower versions_ + +### Build + +dng uses CMake + +```shell +# use a build dir to ensure we ignore build props +cmake -B cmake-build +``` + +_Developed with CLion using CMake and g++ on Linux_ + +### Enforcing local lua files + +To ensure you're always loading the local files make sure you include: + +`package.path = "./?.lua;" .. package.path` at the top of your `proc.lua` + +If you're experiencing issues loading the proper files you can always set in your local development environment: + +`export LUA_PATH=/path/to/dng/?.lua;` (replacing `/path/to/dng` with your actual local development path) + +this will allow you to run `dng` from anywhere + +### Licensing in files + +You can find a copy of the notice in `.copyright_headers`. + +Note `dnglib/constants.lua` and `src/lua.hpp` which have custom licensing information. + +## Run + +Once you build the project you can execute it by: + +```shell +# use your build dir and select a map! +./cmake-build/dng ./path/to/map/lvl +``` + +To launch level 1 for example: + +```shell +./cmake-build/dng ./maps/lvl1 +``` + +Note: You need to use the working directory containing the `include` folder! + +## External Libraries and Resources used by dng + +* [SFML](https://github.com/SFML/SFML) licensed + under [zlib/png license](https://www.sfml-dev.org/license.php) +* [Lua](https://github.com/lua/luat) licensed under [MIT license](https://www.lua.org/license.html) +* [Press Start 2P Font](https://fonts.google.com/specimen/Press+Start+2P#glyphs) licensed + under [SIL Open Font License](https://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL) +* [Liberation Fonts](https://github.com/liberationfonts/liberation-fonts) licensed + under [SIL Open Font License](https://github.com/liberationfonts/liberation-fonts/blob/main/LICENSE) diff --git a/dnglib/algs.lua b/dnglib/algs.lua new file mode 100644 index 0000000..9bb2542 --- /dev/null +++ b/dnglib/algs.lua @@ -0,0 +1,151 @@ +-- ----------------------------------------------------------------------- +-- dng +-- ------------------------------------------------------------------------ +-- Copyright (c) 2022 Steph Enders <steph@senders.io> +-- +-- This software is provided 'as-is', without any express or implied +-- warranty. In no event will the authors be held liable for any damages +-- arising from the use of this software. +-- +-- Permission is granted to anyone to use this software for any purpose, +-- including commercial applications, and to alter it and redistribute it +-- freely, subject to the following restrictions: +-- +-- 1. The origin of this software must not be misrepresented; you must not +-- claim that you wrote the original software. If you use this software +-- in a product, an acknowledgment in the product documentation would +-- be appreciated but is not required. +-- +-- 2. Altered source versions must be plainly marked as such, and must not +-- be misrepresented as being the original software. +-- +-- 3. This notice may not be removed or altered from any source +-- distribution. +-- +-- ----------------------------------------------------------------------- + +package.path="./?.lua;" .. package.path +require "dnglib.constants" +local Queue = require "dnglib.queue" + +---@param map table +local function print_map(map) + for i = 1, #map do + row = map[i] + line = "" + for j = 1, #row do + if row[j] == MAP_WALL then + line = line .. "# " + elseif row[j] == MAP_VISITED then + line = line .. "x " + else + line = line .. " " + end + end + print(line) + end +end + +local function can_move(x, y, map) + return map[y][x] == MAP_SPACE +end + +---@param x number +---@param y number +---@param origin table +---@param map table +---@param queue table +---@return boolean found goal +local function push_moves(x, y, origin, map, queue, target_pos) + map[y][x] = MAP_VISITED -- should be but just in case + -- UP + if can_move(x, y - 1, map) then + pos = { + x = x, + y = y - 1, + origin = origin + } + map[pos.y][pos.x] = MAP_VISITED + if (pos.x == target_pos.x and pos.y == target_pos.y) then + return true + end + queue:push(pos) + end + -- DOWN + if can_move(x, y + 1, map) then + pos = { + x = x, + y = y + 1, + origin = origin + } + map[pos.y][pos.x] = MAP_VISITED + if (pos.x == target_pos.x and pos.y == target_pos.y) then + return true + end + queue:push(pos) + end + -- LEFT + if can_move(x - 1, y, map) then + pos = { + x = x - 1, + y = y, + origin = origin + } + map[pos.y][pos.x] = MAP_VISITED + if (pos.x == target_pos.x and pos.y == target_pos.y) then + return true + end + queue:push(pos) + end + -- RIGHT + if can_move(x + 1, y, map) then + pos = { + x = x + 1, + y = y, + origin = origin + } + map[pos.y][pos.x] = MAP_VISITED + if (pos.x == target_pos.x and pos.y == target_pos.y) then + return true + end + queue:push(pos) + end + return false +end + +--- +---@param start_pos table [x, y] +---@param target_pos table [x, y] +---@param map table 2D map array +---@return table best move to target [x, y] +--- +local function pathfind(start_pos, target_pos, map) + local queue = Queue:new() + local visit_map = {} + for k, v in ipairs(map) do + row = {} + for ik, iv in ipairs(v) do + row[ik] = iv + end + visit_map[k] = row + end + + if (push_moves(start_pos.x, start_pos.y, nil, visit_map, queue, target_pos)) then + return { dx = target_pos.x - start_pos.x, dy = target_pos.y - start_pos.y } + end + + while queue:empty() ~= true do + local pos = queue:pop() + origin = pos.origin or { x = pos.x, y = pos.y } + hit_target = push_moves(pos.x, pos.y, origin, visit_map, queue, target_pos) + if hit_target then + return { dx = origin.x - start_pos.x, dy = origin.y - start_pos.y } + end + end + return { dx = 0, dy = 0 } +end + +return { + pathfind = pathfind, + print_map = print_map, +} diff --git a/dnglib/constants.lua b/dnglib/constants.lua new file mode 100644 index 0000000..df0c37a --- /dev/null +++ b/dnglib/constants.lua @@ -0,0 +1,90 @@ +-- ----------------------------------------------------------------------- +-- dng +-- ------------------------------------------------------------------------ +-- Copyright (c) 2022 Steph Enders <steph@senders.io> +-- +-- This software is provided 'as-is', without any express or implied +-- warranty. In no event will the authors be held liable for any damages +-- arising from the use of this software. +-- +-- Permission is granted to anyone to use this software for any purpose, +-- including commercial applications, and to alter it and redistribute it +-- freely, subject to the following restrictions: +-- +-- 1. The origin of this software must not be misrepresented; you must not +-- claim that you wrote the original software. If you use this software +-- in a product, an acknowledgment in the product documentation would +-- be appreciated but is not required. +-- +-- 2. Altered source versions must be plainly marked as such, and must not +-- be misrepresented as being the original software. +-- +-- 3. This notice may not be removed or altered from any source +-- distribution. +-- +-- ----------------------------------------------------------------------- +-- NOTICE +-- Keyboard enumeration values derived from: +-- https://github.com/SFML/SFML/blob/master/include/SFML/Window/Keyboard.hpp#L48 +-- Licensed under zlib/png license Copyright (C) 2007-2022 Laurent Gomila (laurent@sfml-dev.org) +-- ------------------------------------------------------------------------ +KEY_A = 0 +KEY_B = 1 +KEY_C = 2 +KEY_D = 3 +KEY_E = 4 +KEY_F = 5 +KEY_G = 6 +KEY_H = 7 +KEY_I = 8 +KEY_J = 9 +KEY_L = 10 +KEY_M = 11 +KEY_N = 12 +KEY_M = 13 +KEY_O = 14 +KEY_P = 15 +KEY_Q = 16 +KEY_R = 17 +KEY_S = 18 +KEY_T = 19 +KEY_U = 20 +KEY_V = 21 +KEY_W = 22 +KEY_X = 23 +KEY_Y = 24 +KEY_Z = 25 + +-- control keys +KEY_ESCAPE = 36 +KEY_LCONTROL = 37 +KEY_LSHIFT = 38 +KEY_LALT = 39 +KEY_LSYSTEM = 40 +KEY_RCONTROL = 41 +KEY_RSHIFT = 42 +KEY_RALT = 43 +KEY_RSYSTEM = 44 +KEY_MENU = 45 + +KEY_SPACE = 57 +KEY_ENTER = 58 + +-- directional keys +KEY_LEFT = 71 +KEY_RIGHT = 72 +KEY_UP = 73 +KEY_DOWN = 74 + +-- map values +MAP_WALL = 1 +MAP_SPACE = 0 +MAP_VISITED = -1 + +-- scene values +SCENE_INTRO = 0 +SCENE_LEVEL = 1 +SCENE_WIN = 2 +SCENE_LOSS = 3 + +MOV_TIME = 0.5
\ No newline at end of file diff --git a/dnglib/defaults.lua b/dnglib/defaults.lua new file mode 100644 index 0000000..77f688c --- /dev/null +++ b/dnglib/defaults.lua @@ -0,0 +1,178 @@ +-- ----------------------------------------------------------------------- +-- dng +-- ------------------------------------------------------------------------ +-- Copyright (c) 2022 Steph Enders <steph@senders.io> +-- +-- This software is provided 'as-is', without any express or implied +-- warranty. In no event will the authors be held liable for any damages +-- arising from the use of this software. +-- +-- Permission is granted to anyone to use this software for any purpose, +-- including commercial applications, and to alter it and redistribute it +-- freely, subject to the following restrictions: +-- +-- 1. The origin of this software must not be misrepresented; you must not +-- claim that you wrote the original software. If you use this software +-- in a product, an acknowledgment in the product documentation would +-- be appreciated but is not required. +-- +-- 2. Altered source versions must be plainly marked as such, and must not +-- be misrepresented as being the original software. +-- +-- 3. This notice may not be removed or altered from any source +-- distribution. +-- +-- ----------------------------------------------------------------------- + +--[[ +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) + +--]] +package.path = "./?.lua;" .. package.path +require "dnglib.constants"; +local algs = require "dnglib.algs"; +local hasLost = false; +local hasWon = false; +local hasIntro = false; + +keys = { + up = KEY_UP, + down = KEY_DOWN, + left = KEY_LEFT, + right = KEY_RIGHT, + quit = KEY_ESCAPE, + start = KEY_SPACE, + restart = KEY_SPACE, +} + +--- 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 == keys.start then + c_trigger_level_start(); + end + elseif scene == SCENE_LEVEL then + dx = 0 + dy = 0 + if pressedKey == keys.up then + dy = -1 + elseif pressedKey == keys.left then + dx = -1 + elseif pressedKey == keys.down then + dy = 1 + elseif pressedKey == keys.right then + dx = 1 + end + + c_move_player(dx, dy) + elseif scene == SCENE_WIN or scene == SCENE_LOSS then + if pressedKey == keys.restart then + c_trigger_restart() + end + end +end + +local diff_time = 0 +---@param dt number +function onUpdate(dt) + diff_time = diff_time + dt + enemies = c_get_enemies() + assert(type(enemies) == "table", "Enemies not a table") + + player = c_get_player_position() + assert(type(player) == "table", "Player is not a table") + + map = c_get_map(); + assert(type(map) == "table", "map is not a table") + + for _, v in ipairs(enemies) do + local next; + if diff_time >= MOV_TIME then + next = algs.pathfind(v, player, map) + else + next = { dx = 0, dy = 0 } + end + 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 + if diff_time > MOV_TIME then + diff_time = 0 + 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 -- space.. +.. move -- wasd .. +.. quit -- q .. +................... +.. goal .. +................... +.. Find treasure .. +.. Avoid enemies .. +................... + ]]) + end +end + +--- allow for requiring in other files for usage +return { + onKeyPress = onKeyPress, + onUpdate = onUpdate, + onWin = onWin, + onLoss = onLoss, + onIntro = onIntro, + keys = keys, +} diff --git a/dnglib/queue.lua b/dnglib/queue.lua new file mode 100644 index 0000000..a3470e5 --- /dev/null +++ b/dnglib/queue.lua @@ -0,0 +1,55 @@ +-- ----------------------------------------------------------------------- +-- dng +-- ------------------------------------------------------------------------ +-- Copyright (c) 2022 Steph Enders <steph@senders.io> +-- +-- This software is provided 'as-is', without any express or implied +-- warranty. In no event will the authors be held liable for any damages +-- arising from the use of this software. +-- +-- Permission is granted to anyone to use this software for any purpose, +-- including commercial applications, and to alter it and redistribute it +-- freely, subject to the following restrictions: +-- +-- 1. The origin of this software must not be misrepresented; you must not +-- claim that you wrote the original software. If you use this software +-- in a product, an acknowledgment in the product documentation would +-- be appreciated but is not required. +-- +-- 2. Altered source versions must be plainly marked as such, and must not +-- be misrepresented as being the original software. +-- +-- 3. This notice may not be removed or altered from any source +-- distribution. +-- +-- ----------------------------------------------------------------------- + +Queue = {} + +function Queue:new() + o = { first = 1, top = 0, data = {} } + self.__index = self + return setmetatable(o, self) +end + +function Queue:push(val) + local top = self.top + 1 + self.top = top + self.data[top] = val +end + +function Queue:pop() + if self:empty() then + return nil + end + local val = self.data[self.first] + self.data[self.first] = nil + self.first = self.first + 1 + return val +end + +function Queue:empty() + return self.top < self.first +end + +return Queue 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..29d4e46 --- /dev/null +++ b/maps/lvl1/proc.lua @@ -0,0 +1,7 @@ +package.path = "./?.lua;" .. package.path +require "dnglib.constants"; +local default = require "dnglib.defaults" + +function onKeyPress(key) + default.onKeyPress(key) +end diff --git a/maps/lvl2/dng.map b/maps/lvl2/dng.map new file mode 100644 index 0000000..26467e0 --- /dev/null +++ b/maps/lvl2/dng.map @@ -0,0 +1,18 @@ +w w w w w w w w w w w w w w w w w +w 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 w +w e 0 0 0 t 0 0 0 0 0 0 w 0 0 0 w +w 0 0 0 0 0 0 0 0 0 0 0 w t 0 0 w +w 0 w w w w w w w w 0 w w w w 0 w +w 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 w +w 0 w w w w w w w w 0 w w 0 0 0 w +w e 0 0 0 0 0 0 0 0 0 w 0 0 0 0 w +w w 0 w w w w w w w 0 w w w w w w +w t 0 w 0 0 w 0 0 0 0 w w w w 0 w +w 0 w w 0 0 0 0 0 0 0 w e w w 0 w +w 0 0 0 0 w w w w 0 w w w w w 0 w +w t w w w 0 0 0 0 0 0 0 0 0 0 0 w +w w w w w 0 w 0 0 0 0 0 w 0 w w w +w 0 0 0 0 0 0 0 0 0 0 0 w 0 0 0 w +w p w w w w w w w w w w w w w 0 w +w 0 0 0 0 0 0 0 t 0 0 0 0 0 0 0 w +w w w w w w w w w w w w w w w w w
\ No newline at end of file diff --git a/maps/lvl2/proc.lua b/maps/lvl2/proc.lua new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/maps/lvl2/proc.lua diff --git a/maps/lvl3/dng.map b/maps/lvl3/dng.map new file mode 100644 index 0000000..b13ad83 --- /dev/null +++ b/maps/lvl3/dng.map @@ -0,0 +1,40 @@ +w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w +w p t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 w +w 0 t 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 t 0 w +w 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 w +w 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 w +w 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 w +w 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 w +w 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 w +w 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 w +w 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 w +w 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 w +w 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 w +w 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 w +w 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 w +w 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 e t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 w +w 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 w +w 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 w +w 0 t 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 t 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 w +w 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 w +w 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 w +w 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 w +w 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 w +w 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 w +w 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 w +w 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 w +w 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 w +w 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 w +w 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 w +w 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 w +w 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 w +w 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 w +w 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 w +w 0 w w w 0 w 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 w 0 w w w 0 w +w 0 t 0 w 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 0 w 0 t 0 w +w 0 t 0 w w w 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 w w w 0 t 0 w +w 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 w +w 0 w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w 0 w +w 0 t 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 t 0 w +w 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 t 0 0 w +w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w
\ No newline at end of file diff --git a/res/LiberationMono-Regular.ttf b/res/LiberationMono-Regular.ttf Binary files differnew file mode 100644 index 0000000..a1d70ed --- /dev/null +++ b/res/LiberationMono-Regular.ttf diff --git a/res/PressStart2P-vaV7.ttf b/res/PressStart2P-vaV7.ttf Binary files differnew file mode 100644 index 0000000..98044e9 --- /dev/null +++ b/res/PressStart2P-vaV7.ttf diff --git a/src/CApi.h b/src/CApi.h new file mode 100644 index 0000000..21ad9eb --- /dev/null +++ b/src/CApi.h @@ -0,0 +1,235 @@ +//======================================================================== +// dng +//------------------------------------------------------------------------ +// Copyright (c) 2022 Steph Enders <steph@senders.io> +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#ifndef DNG_CAPI_H +#define DNG_CAPI_H + +#include "Level.h" +#include "Scene.h" +#include "lua.hpp" +#include <memory> + +extern std::shared_ptr<Level> 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<int>(lua_tonumber(L, -1)); + int dx = static_cast<int>(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<int>(lua_tonumber(L, -1)); + int dx = static_cast<int>(lua_tonumber(L, -2)); + int id = static_cast<int>(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<int>(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<int>(lua_tonumber(L, -1)); + + erase_if(lvl->treasurePositions, [id](Pos t) { return t.id == id; }); + + return 1; +} + +static int c_trigger_restart(lua_State *L) { + lvl->reset(); + scene = Scene::INTRO; + 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); + lua_register(L, "c_trigger_restart", c_trigger_restart); +} + +#endif // DNG_CAPI_H diff --git a/src/Level.cpp b/src/Level.cpp new file mode 100644 index 0000000..6db4b4e --- /dev/null +++ b/src/Level.cpp @@ -0,0 +1,161 @@ +//======================================================================== +// dng +//------------------------------------------------------------------------ +// Copyright (c) 2022 Steph Enders <steph@senders.io> +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "Level.h" +#include "SfmlUtils.h" +#include <fstream> +#include <iostream> +#include <string> + +bool canStep(Pos pos, int dx, int dy, std::vector<std::vector<char>> map) { + return map[pos.y + dy][pos.x + dx] != WALL_SPACE; +} + +void Level::loadLevelFromFile(const char *filePath) { + std::ifstream mapFile(filePath); + if (mapFile.is_open()) { + this->file = filePath; + // 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); + auto w = create_wall(x, y); + this->displayMap.push_back(w); + } else if (c == EMPTY_TKN) { + this->map[y].push_back(BLANK_SPACE); + // no display info + } else if (c == ENEMY_TKN) { + auto e = create_enemy(x, y); + this->enemyPositions.push_back( + {.id = this->nextId(), .x = x, .y = y, .sprite = e}); + this->map[y].push_back(BLANK_SPACE); + } else if (c == PLAYER_TKN) { + auto p = create_player(x, y); + this->player = {.id = playerId, .x = x, .y = y, .sprite = p}; + this->map[y].push_back(BLANK_SPACE); + } else if (c == TREASURE_TKN) { + auto t = create_treasure(x, y); + this->treasurePositions.push_back( + {.id = this->nextId(), .x = x, .y = y, .sprite = t}); + this->map[y].push_back(BLANK_SPACE); + } else { + continue; + } + ++x; + } + ++y; + } + + unsigned long max_width = 0; + for (auto &rows : this->map) { + if (max_width < rows.size()) { + max_width = rows.size(); + } + } + this->width = static_cast<int>(max_width); + this->height = static_cast<int>(this->map.size()); + } + mapFile.close(); +} + +void Level::reset() { + this->map.clear(); + this->treasurePositions.clear(); + this->displayMap.clear(); + this->enemyPositions.clear(); + this->loadLevelFromFile(this->file); +} + +bool Level::isEmpty(int x, int y) { return map[y][x] == BLANK_SPACE; } + +bool Level::playerCanStep(int dx, int dy) { + return canStep(player, dx, dy, map); +} + +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++; } + +int Level::getEnemyIndex(int id) { + for (int i = 0; i < enemyPositions.size(); i++) { + if (enemyPositions[i].id == id) { + return i; + } + } + + return -1; +} +bool Level::enemyCanStep(Pos pos, int dx, int dy) { + return canStep(pos, dx, dy, map); +} +int Level::getWidth() { return this->width; } +int Level::getHeight() { return this->height; } diff --git a/src/Level.h b/src/Level.h new file mode 100644 index 0000000..f0cec68 --- /dev/null +++ b/src/Level.h @@ -0,0 +1,84 @@ +//======================================================================== +// dng +//------------------------------------------------------------------------ +// Copyright (c) 2022 Steph Enders <steph@senders.io> +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#ifndef DNG_LEVEL_H +#define DNG_LEVEL_H + +#include "SFML/Graphics/RectangleShape.hpp" +#include <memory> +#include <vector> + +// tokens from map file +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 = '#'; + +struct Pos { + int id; + int x; + int y; + sf::RectangleShape sprite; +} typedef Pos; + +class Level { + +public: + void loadLevelFromFile(const char *filePath); + + bool isEmpty(int x, int y); + + bool playerCanStep(int dx, int dy); + + int getEnemyIndex(int id); + + bool enemyCanStep(Pos pos, int dx, int dy); + + void reset(); + /* deprecate*/ + void print(); + + int nextId(); + int getWidth(); + int getHeight(); + + std::vector<std::vector<char>> map; // source copy of map + std::vector<sf::RectangleShape> displayMap; + Pos player; + std::vector<Pos> enemyPositions; + std::vector<Pos> treasurePositions; + +private: + int idCounter = 1; // defaults at 1 (player always 0) + int width; + int height; + const char *file; +}; + +#endif // DNG_LEVEL_H diff --git a/src/LuaApi.h b/src/LuaApi.h new file mode 100644 index 0000000..43bd50f --- /dev/null +++ b/src/LuaApi.h @@ -0,0 +1,120 @@ +//======================================================================== +// dng +//------------------------------------------------------------------------ +// Copyright (c) 2022 Steph Enders <steph@senders.io> +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#ifndef DNG_LUA_API_H +#define DNG_LUA_API_H + +#include "lua.hpp" +#include <iostream> + +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<LState *>(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_number(lua_State *L, const char *fn, lua_Number num) { + lua_getglobal(L, fn); + if (!lua_isfunction(L, -1)) { + std::cout << "[C] Error " << fn << " not function | not found" << std::endl; + return false; + } + lua_pushnumber(L, num); + lua_pcall(L, 1, 1, 0); + return true; +} + +bool lua_onkeypress(lua_State *L, int pressedKey) { + if (pressedKey == -1) { + return true; + } + return lua_dofn_with_number(L, "onKeyPress", pressedKey); +} + +bool lua_onupdate(lua_State *L, float dt) { + return lua_dofn_with_number(L, "onUpdate", dt); +} + +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 diff --git a/src/MessageBox.h b/src/MessageBox.h new file mode 100644 index 0000000..0e1fa8f --- /dev/null +++ b/src/MessageBox.h @@ -0,0 +1,98 @@ +//======================================================================== +// dng +//------------------------------------------------------------------------ +// Copyright (c) 2022 Steph Enders <steph@senders.io> +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#ifndef DNG_MESSAGE_BOX_H +#define DNG_MESSAGE_BOX_H + +#include "SFML/Graphics/RectangleShape.hpp" +#include "SFML/Graphics/Text.hpp" +#include "SfmlUtils.h" +#include <vector> + +const int LARGE_TEXT = 54; +const int MEDIUM_TEXT = 36; +const int SMALL_TEXT = 24; +const float PADDING = 16.f; +const float LINE_HEIGHT = 1.2f; +struct MessageBox { + + std::vector<sf::Text> msgs; + sf::RectangleShape box; + +} typedef MessageBox; + +struct DisplayText { + std::string msg; + int textSize; +} typedef DisplayText; + +inline MessageBox initializeMessageBox(const std::vector<DisplayText> &strs, + const sf::Font &font, + sf::Vector2u windowSize) { + + std::vector<sf::Text> messages; + sf::RectangleShape box; + float width = 0.f; + float height = 0.f; + float left = MAXFLOAT; + sf::Text prev; + for (const auto &str : strs) { + sf::Text text = write_text(str.msg.c_str(), str.textSize, LINE_HEIGHT, font, + windowSize); + // move below previous + if (!prev.getString().isEmpty()) { + text.move(0.f, prev.getLocalBounds().height * prev.getLineSpacing()); + } + // add to vector + messages.push_back(text); + + // find widest + if (text.getGlobalBounds().width > width) { + width = text.getGlobalBounds().width; + } + // find leftmost + if (text.getGlobalBounds().left < left) { + left = text.getGlobalBounds().left; + } + // heights added together + line height + height += (text.getLocalBounds().height * text.getLineSpacing()); + prev = text; + } + box = sf::RectangleShape(sf::Vector2f(width + PADDING, height + PADDING)); + box.setOutlineColor(sf::Color::Black); + box.setOutlineThickness(4.f); + box.setFillColor(sf::Color(128, 128, 128, 128)); + box.setPosition(left - (PADDING / 2.f), + // Top will always be the first message + messages[0].getGlobalBounds().top - (PADDING / 2.f)); + + return { + .msgs = messages, + .box = box, + }; +} + +#endif // DNG_MESSAGE_BOX_H
\ No newline at end of file diff --git a/src/Scene.h b/src/Scene.h new file mode 100644 index 0000000..0db80cd --- /dev/null +++ b/src/Scene.h @@ -0,0 +1,31 @@ +//======================================================================== +// dng +//------------------------------------------------------------------------ +// Copyright (c) 2022 Steph Enders <steph@senders.io> +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#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/SfmlUtils.h b/src/SfmlUtils.h new file mode 100644 index 0000000..dd63cd6 --- /dev/null +++ b/src/SfmlUtils.h @@ -0,0 +1,110 @@ +//======================================================================== +// dng +//------------------------------------------------------------------------ +// Copyright (c) 2022 Steph Enders <steph@senders.io> +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#ifndef DNG_SFML_UTILS_H +#define DNG_SFML_UTILS_H + +#include "SFML/Graphics/RectangleShape.hpp" +#include "SFML/Graphics/Text.hpp" +#include "SFML/Window/Event.hpp" +#include "SFML/Window/Keyboard.hpp" +#include <cmath> +#include <iostream> + +const float SPRITE_SIZE = 16.f; // squares +const sf::Color WALL_COLOR = sf::Color(150, 150, 150, 255); +const sf::Color BLANK_COLOR = sf::Color(216, 216, 216, 255); + +inline sf::Keyboard::Key get_key(sf::Event event) { + if (event.type == sf::Event::KeyPressed || + sf::Keyboard::isKeyPressed(event.key.code)) { + return event.key.code; + } + return sf::Keyboard::Unknown; +} + +inline sf::Vector2f to_position_xy(int x, int y) { + return {static_cast<float>(x) * SPRITE_SIZE, + static_cast<float>(y) * SPRITE_SIZE}; +} +inline sf::Vector2f to_position(const Pos &pos) { + return to_position_xy(pos.x, pos.y); +} + +inline sf::RectangleShape create_square(sf::Color color, int x, int y) { + sf::RectangleShape rect({SPRITE_SIZE - 1.f, SPRITE_SIZE - 1.f}); + rect.setFillColor(color); + rect.setOutlineColor(sf::Color::Black); + rect.setOutlineThickness(1.f); + rect.setPosition(to_position_xy(x, y)); + return rect; +} + +inline sf::RectangleShape create_wall(int x, int y) { + return create_square(WALL_COLOR, x, y); +} + +inline sf::RectangleShape create_enemy(int x, int y) { + return create_square(sf::Color::Magenta, x, y); +} + +inline sf::RectangleShape create_player(int x, int y) { + return create_square(sf::Color::Cyan, x, y); +} + +inline sf::RectangleShape create_treasure(int x, int y) { + return create_square(sf::Color::Yellow, x, y); +} + +inline sf::Vector2f round(const sf::Vector2f vector) { + return sf::Vector2f{std::round(vector.x), std::round(vector.y)}; +} + +inline sf::Text write_text(const char *msg, unsigned int fontSize, + float lineSpacing, const sf::Font &font, + const sf::Vector2u windowSize) { + sf::Text text(msg, font, fontSize); + text.setOutlineThickness(4.f); + text.setOrigin(round(sf::Vector2f{text.getLocalBounds().width / 2, + text.getLocalBounds().height / 2})); + text.setPosition(sf::Vector2f(windowSize / 2u)); + text.setLineSpacing(lineSpacing); + while (text.getGlobalBounds().top < 0 || text.getGlobalBounds().left < 0 || + static_cast<unsigned int>( + (text.getGlobalBounds().width + text.getGlobalBounds().left) * + text.getLineSpacing()) > windowSize.x || + static_cast<unsigned int>( + (text.getGlobalBounds().height + text.getGlobalBounds().top) * + text.getLineSpacing()) > windowSize.y) { + text.setCharacterSize(text.getCharacterSize() - 1); + text.setOrigin(round(sf::Vector2f{text.getLocalBounds().width / 2, + text.getLocalBounds().height / 2})); + text.setPosition(sf::Vector2f(windowSize / 2u)); + } + return text; +} + +#endif // DNG_SFML_UTILS_H
\ No newline at end of file diff --git a/src/linux/res.h b/src/linux/res.h new file mode 100644 index 0000000..9e3b8c5 --- /dev/null +++ b/src/linux/res.h @@ -0,0 +1,77 @@ +//======================================================================== +// dng +//------------------------------------------------------------------------ +// Copyright (c) 2022 Steph Enders <steph@senders.io> +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#ifndef DNG_RES_H +#define DNG_RES_H + +#include <filesystem> + +const std::filesystem::path DEFAULT_PROC{"dnglib/defaults.lua"}; +const std::filesystem::path DEFAULT_FONT{"res/PressStart2P-vaV7.ttf"}; +// TODO setup to allow switching to monospace instead of game font +// const std::filesystem::path DEFAULT_MONOSPACE_FONT{ +// "res/LiberationMono-Regular.ttf"}; + +struct Res { + + std::filesystem::path defaultsFile; + std::filesystem::path fontFile; + +} typedef Res; + +inline Res get_resources() { + using namespace std::filesystem; + + auto current_dir = current_path(); + auto exe_dir = canonical("/proc/self/exe").remove_filename(); + auto install_dir = path{"/usr/local/share/dng/"}; + + Res res; + if (exists(current_dir / DEFAULT_PROC)) { + res.defaultsFile = current_dir / DEFAULT_PROC; + } else if (exists(exe_dir / DEFAULT_PROC)) { + res.defaultsFile = exe_dir / DEFAULT_PROC; + } else if (exists(install_dir / DEFAULT_PROC)) { + res.defaultsFile = install_dir / DEFAULT_PROC; + } else { + res.defaultsFile = DEFAULT_PROC; // just return w/ no path info + } + // TODO make configurable + path fontp = DEFAULT_FONT; + if (exists(current_dir / fontp)) { + res.fontFile = current_dir / fontp; + } else if (exists(exe_dir / fontp)) { + res.fontFile = exe_dir / fontp; + } else if (exists(install_dir / fontp)) { + res.fontFile = install_dir / fontp; + } else { + res.fontFile = fontp; // just return w/ no path info + } + + return res; +} + +#endif // DNG_RES_H
\ No newline at end of file diff --git a/src/lua.hpp b/src/lua.hpp new file mode 100644 index 0000000..4cf79d2 --- /dev/null +++ b/src/lua.hpp @@ -0,0 +1,8 @@ +// Included locally +// Building from sources doesn't include this by default +// See Copyright Notice in thirdparty/lua/lua.h +extern "C" { +#include "lauxlib.h" +#include "lua.h" +#include "lualib.h" +} diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..99f8603 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,278 @@ +//======================================================================== +// dng +//------------------------------------------------------------------------ +// Copyright (c) 2022 Steph Enders <steph@senders.io> +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "CApi.h" +#include "Level.h" +#include "LuaApi.h" +#include "MessageBox.h" +#include "SfmlUtils.h" +#ifdef __linux__ +#include "linux/res.h" +#endif +#include "lua.hpp" +#include <SFML/Graphics.hpp> +#include <cmath> +#include <filesystem> +#include <iostream> + +std::shared_ptr<Level> lvl; + +Scene scene; +const int MAX_WIDTH = static_cast<int>(SPRITE_SIZE) * 20 * 4; +const int MAX_HEIGHT = static_cast<int>(SPRITE_SIZE) * 20 * 3; + +int main(int argc, char **argv) { + + if (argc <= 1) { + std::cerr << "Must pass in path to level directory" << std::endl; + return -1; + } + + auto res = get_resources(); + + std::string lvl_pfx = argv[1]; + + std::filesystem::path mapFile{lvl_pfx + "/dng.map"}; + std::filesystem::path luaFile{lvl_pfx + "/proc.lua"}; + + lvl = std::make_shared<Level>(); + scene = Scene::INTRO; + + 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(res.defaultsFile) && + luaL_dofile(L_default, res.defaultsFile.c_str()) != 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; + } + + // Initialize to default + LState *l_state = init_default(L_default); + + if (std::filesystem::exists(luaFile) && + luaL_dofile(L_lvl, luaFile.c_str()) == LUA_OK) { + 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)); + return EXIT_FAILURE; + } + + float ZOOM = 0.5f; + sf::Vector2f mapBounds = {static_cast<float>(lvl->getWidth()) * SPRITE_SIZE, + static_cast<float>(lvl->getHeight()) * SPRITE_SIZE}; + int width = static_cast<int>(static_cast<float>(lvl->getWidth()) / ZOOM * + SPRITE_SIZE / ZOOM); + int height = static_cast<int>(static_cast<float>(lvl->getHeight()) / ZOOM * + SPRITE_SIZE / ZOOM); + bool useViewport = false; + if (width > MAX_WIDTH) { + width = MAX_WIDTH; + useViewport = true; + } + if (height > MAX_HEIGHT) { + height = MAX_HEIGHT; + useViewport = true; + } + + sf::RenderWindow window(sf::VideoMode(width, height), "dng"); + window.setMouseCursorVisible(false); + window.setFramerateLimit(30); + sf::View view(window.getDefaultView()); + view.zoom(ZOOM); + view.setSize(view.getSize() * ZOOM); + view.setViewport(sf::FloatRect(0.f, 0.f, 1.f, 1.f)); + if (useViewport) { + view.setCenter(to_position(lvl->player) + + sf::Vector2f(SPRITE_SIZE / 2.f, SPRITE_SIZE / 2.f)); + } else { + view.setCenter(view.getSize() / 2.f); + } + + window.setView(view); + sf::Clock deltaClock; + sf::Font font; + font.loadFromFile(res.fontFile); + + MessageBox intro; + MessageBox win; + MessageBox loss; + + do { + sf::Event event{}; + float dt = deltaClock.restart().asSeconds(); + + while (window.pollEvent(event)) { + if (event.type == sf::Event::Closed || + sf::Keyboard::isKeyPressed(sf::Keyboard::Q)) { + window.close(); + } + if (!lua_onkeypress(l_state->onkeypress, get_key(event))) { + window.close(); + } + } + + if (scene == Scene::INTRO) { + if (!lua_onintro(l_state->onintro)) { + window.close(); + } + } else if (scene == Scene::LEVEL) { + if (!lua_onupdate(l_state->onupdate, dt)) { + window.close(); + } + } else if (scene == Scene::WIN) { + lua_onwin(l_state->onwin); + // window.close(); + } else if (scene == Scene::LOSS) { + lua_onloss(l_state->onloss); + } + + // Render + if (useViewport) { + // Reinitialize center view + if (scene == INTRO) { + if (useViewport) { + view.setCenter(to_position(lvl->player) + + sf::Vector2f(SPRITE_SIZE / 2.f, SPRITE_SIZE / 2.f)); + } else { + view.setCenter(view.getSize() / 2.f); + } + } + sf::Vector2f newPos = to_position(lvl->player) + // center + sf::Vector2f(SPRITE_SIZE / 2.f, SPRITE_SIZE / 2.f); + sf::Vector2f diff = + newPos - (lvl->player.sprite.getPosition() + + sf::Vector2f(SPRITE_SIZE / 2.f, SPRITE_SIZE / 2.f)); + + if (diff.x > 0.f && newPos.x > view.getSize().x / 2.f) { + view.move({diff.x, 0.f}); + } + if (diff.y > 0.f && newPos.y > view.getSize().y / 2.f) { + view.move({0.f, diff.y}); + } + if (diff.x < 0.f && newPos.x < view.getCenter().x) { + view.move({diff.x, 0.f}); + } + if (diff.y < 0.f && newPos.y < view.getCenter().y) { + view.move({0.f, diff.y}); + } + // readjust for OB + if (view.getCenter().x - view.getSize().x / 2.f < 0.f) { + view.move({(view.getCenter().x - view.getSize().x / 2.f) * -1.f, 0.f}); + } + if (view.getCenter().y - view.getSize().y / 2.f < 0.f) { + view.move({0.f, (view.getCenter().y - view.getSize().y / 2.f) * -1.f}); + } + if (view.getCenter().x + view.getSize().x / 2.f > mapBounds.x) { + view.move( + {-1 * ((view.getCenter().x + view.getSize().x / 2.f) - mapBounds.x), + 0.f}); + } + if (view.getCenter().y + view.getSize().y / 2.f > mapBounds.y) { + view.move({0.f, -1 * ((view.getCenter().y + view.getSize().y / 2.f) - + mapBounds.y)}); + } + } + + window.clear(BLANK_COLOR); + window.setView(view); + for (auto &rect : lvl->displayMap) { + window.draw(rect); + } + if (scene == Scene::LEVEL) { + for (auto &enemy : lvl->enemyPositions) { + enemy.sprite.setPosition(to_position(enemy)); + window.draw(enemy.sprite); + } + for (auto &treasure : lvl->treasurePositions) { + treasure.sprite.setPosition(to_position(treasure)); + window.draw(treasure.sprite); + } + } + + if (scene != Scene::LOSS) { + lvl->player.sprite.setPosition(to_position(lvl->player)); + window.draw(lvl->player.sprite); + } + if (scene == Scene::WIN) { + window.setView(window.getDefaultView()); + if (win.msgs.empty()) { + win = initializeMessageBox({{"You Win!", LARGE_TEXT}, + {"press [space] to restart", SMALL_TEXT}}, + font, window.getSize()); + } + + window.draw(win.box); + for (auto &msg : win.msgs) { + window.draw(msg); + } + window.setView(view); + } + if (scene == Scene::LOSS) { + window.setView(window.getDefaultView()); + if (loss.msgs.empty()) { + loss = initializeMessageBox({{"You Lose!", LARGE_TEXT}, + {"press [space] to restart", SMALL_TEXT}}, + font, window.getSize()); + } + + window.draw(loss.box); + for (auto &msg : loss.msgs) { + window.draw(msg); + } + window.setView(view); + } + if (scene == INTRO) { + window.setView(window.getDefaultView()); + if (intro.msgs.empty()) { + intro = initializeMessageBox( + {{"Start!", LARGE_TEXT}, {"press [space]", SMALL_TEXT}}, font, + window.getSize()); + } + + window.draw(intro.box); + for (auto &msg : intro.msgs) { + window.draw(msg); + } + window.setView(view); + } + window.setView(view); + window.display(); + } while (window.isOpen()); + + std::cout << "[C] Quit" << std::endl; + + return EXIT_SUCCESS; +} diff --git a/thirdparty/.clang-format b/thirdparty/.clang-format new file mode 100644 index 0000000..bdc824e --- /dev/null +++ b/thirdparty/.clang-format @@ -0,0 +1,4 @@ +{ + "DisableFormat": true, + "SortIncludes": "Never" +} diff --git a/thirdparty/SFML b/thirdparty/SFML new file mode 160000 +Subproject 2f11710abc5aa478503a7ff3f9e654bd2078eba diff --git a/thirdparty/lua b/thirdparty/lua new file mode 160000 +Subproject e37b96db04b373f79661357e18a061186ceb8e5 diff --git a/thirdparty/thirdparty-licenses.txt b/thirdparty/thirdparty-licenses.txt new file mode 100644 index 0000000..5e1adac --- /dev/null +++ b/thirdparty/thirdparty-licenses.txt @@ -0,0 +1,250 @@ +------------------------------------------------------------------------------- +dng uses SFML - licensed under the zlib/png license +------------------------------------------------------------------------------- +SFML - Copyright (C) 2007-2018 Laurent Gomila - laurent@sfml-dev.org + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. + +------------------------------------------------------------------------------- +------------------------------------------------------------------------------- +dng uses LUA - licensed under the MIT license +------------------------------------------------------------------------------- +Copyright (C) 1994-2020 Lua.org, PUC-Rio. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------- +------------------------------------------------------------------------------- +dng uses PressStart2P-vaV7 font - licensed under SIL Open Font license +------------------------------------------------------------------------------- +Copyright 2012 The Press Start 2P Project Authors (cody@zone38.net), with Reserved Font Name "Press Start 2P". + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. +------------------------------------------------------------------------------- +------------------------------------------------------------------------------- +dng uses Liberation Fonts - licensed under SIL Open Font license +------------------------------------------------------------------------------- +Digitized data copyright (c) 2010 Google Corporation + with Reserved Font Arimo, Tinos and Cousine. +Copyright (c) 2012 Red Hat, Inc. + with Reserved Font Name Liberation. + +This Font Software is licensed under the SIL Open Font License, +Version 1.1. + +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 + +PREAMBLE The goals of the Open Font License (OFL) are to stimulate +worldwide development of collaborative font projects, to support the font +creation efforts of academic and linguistic communities, and to provide +a free and open framework in which fonts may be shared and improved in +partnership with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. +The fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply to +any document created using the fonts or their derivatives. + + + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. +This may include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components +as distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting ? in part or in whole ? +any of the components of the Original Version, by changing formats or +by porting the Font Software to a new environment. + +"Author" refers to any designer, engineer, programmer, technical writer +or other person who contributed to the Font Software. + + +PERMISSION & CONDITIONS + +Permission is hereby granted, free of charge, to any person obtaining a +copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components,in + Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, + redistributed and/or sold with any software, provided that each copy + contains the above copyright notice and this license. These can be + included either as stand-alone text files, human-readable headers or + in the appropriate machine-readable metadata fields within text or + binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font + Name(s) unless explicit written permission is granted by the + corresponding Copyright Holder. This restriction only applies to the + primary font name as presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font + Software shall not be used to promote, endorse or advertise any + Modified Version, except to acknowledge the contribution(s) of the + Copyright Holder(s) and the Author(s) or with their explicit written + permission. + +5) The Font Software, modified or unmodified, in part or in whole, must + be distributed entirely under this license, and must not be distributed + under any other license. The requirement for fonts to remain under + this license does not apply to any document created using the Font + Software. + + + +TERMINATION +This license becomes null and void if any of the above conditions are not met. + + + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER +DEALINGS IN THE FONT SOFTWARE. +------------------------------------------------------------------------------- +------------------------------------------------------------------------------- + |