summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteph Enders <smenders@gmail.com>2022-06-15 23:36:43 -0400
committerSteph Enders <smenders@gmail.com>2022-06-21 15:20:33 -0400
commit09615be926efb7302bc348aa66feccb694b23ba8 (patch)
tree0adf5eeb39312649c4adc288e051d5251428a2c2
v0.1.0 - Initial Commit
Create dng - a maze/puzzle game enging using Lua and SFML --- Initial setup commit This setups up the project for messing around with C++ and Lua bindings. So far this project just prints the defined dng map and lets you move the character around. What this fails to do is actually provide any reason to use Lua at the moment. So I need to figure out some way of enabling logic on the processing side of things. Fixup warning from IntelliJ Added onUpdate logic to move the enemies etc Created some algorithm logic for enemy movement Allowed for default overrides Made shortest path alg more efficent In the previous commit this algo waited until the "success" step came up in the queue. Now we have the check during the push - and if an hits we return true from the push_moves fn. Since we're only interested in the initial move (since we check moves every frame) we can only return true and then use the current step as the origin position to diff against the start to get the dx,dy Add scene controls and win/loss scenarios Setup ability to check collisions and transition game scene Remove SFML for now Create level 2 Fixup - Can now have levels without a proc.lua Checked existence of wrong file for loading defaults Add readme and ignore build files Setup so it can build on debian Reformat bill merge Make installable You can now do: `sudo make install` and have it publish and distribute the dng lua files to the share dir Bump version to 0.3.1 Opps forgot to unignore dng folder Force local version if in current dir This should allow development to ALWAYS prefer the local version of the lib - so if you have an installed version it won't override local changes Set version to 0.3.2 Bump version to 0.3.3 Update to use SFML (for gameplay) Intro/Win/Loss not supported yet Remove install logic for now + make mov overrides Allow for restart on win/loss Add scroll viewport and max window sizes Display win/loss (need restart view fix) Fix recenter view on restart v0.4.0 - SFML Dynamic text rescale This isn't the best since we rescale it every frame we render it on, we should render all the text once and remember it. If we want to support "resizing" we can do that in its own logic loop MessageBox + Filesystem lookups for files Created MessageBox which is a helper class to allow for printing any dialog in a scalable way. Added path overrides for lua files as well as the ability to seek the filesystem for specific paths for the fonts and such. Set version to 0.4.2 Creating submodules? Added SFML as third party lib Use git submodules for dependencies Set license to zlib/png Add thirdparty licenses and include in package Set version to 0.1.0
-rw-r--r--.clang-format178
-rw-r--r--.copyright_headers/C_HEADER.txt25
-rw-r--r--.copyright_headers/LUA_HEADER.txt25
-rw-r--r--.gitignore8
-rw-r--r--.gitmodules8
-rw-r--r--CMakeLists.txt96
-rw-r--r--CONTRIBUTING.md3
-rw-r--r--LICENSE17
-rw-r--r--README.md134
-rw-r--r--dnglib/algs.lua151
-rw-r--r--dnglib/constants.lua90
-rw-r--r--dnglib/defaults.lua178
-rw-r--r--dnglib/queue.lua55
-rw-r--r--maps/lvl1/dng.map10
-rw-r--r--maps/lvl1/proc.lua7
-rw-r--r--maps/lvl2/dng.map18
-rw-r--r--maps/lvl2/proc.lua0
-rw-r--r--maps/lvl3/dng.map40
-rw-r--r--res/LiberationMono-Regular.ttfbin0 -> 319508 bytes
-rw-r--r--res/PressStart2P-vaV7.ttfbin0 -> 82480 bytes
-rw-r--r--src/CApi.h235
-rw-r--r--src/Level.cpp161
-rw-r--r--src/Level.h84
-rw-r--r--src/LuaApi.h120
-rw-r--r--src/MessageBox.h98
-rw-r--r--src/Scene.h31
-rw-r--r--src/SfmlUtils.h110
-rw-r--r--src/linux/res.h77
-rw-r--r--src/lua.hpp8
-rw-r--r--src/main.cpp278
-rw-r--r--thirdparty/.clang-format4
m---------thirdparty/SFML0
m---------thirdparty/lua0
-rw-r--r--thirdparty/thirdparty-licenses.txt250
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.
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..8cf10c3
--- /dev/null
+++ b/LICENSE
@@ -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
new file mode 100644
index 0000000..a1d70ed
--- /dev/null
+++ b/res/LiberationMono-Regular.ttf
Binary files differ
diff --git a/res/PressStart2P-vaV7.ttf b/res/PressStart2P-vaV7.ttf
new file mode 100644
index 0000000..98044e9
--- /dev/null
+++ b/res/PressStart2P-vaV7.ttf
Binary files differ
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.
+-------------------------------------------------------------------------------
+-------------------------------------------------------------------------------
+