[
  {
    "path": ".gitignore",
    "content": "/build/\n/.kdev4/\n/bgame.kdev4\n/build_eclipse/\n.DS_Store\nx64\nx84\n\n/RltkMaster/packages\n/RltkMaster/rltk/Debug\n/RltkMaster/rltk/SFML-2.3.2\n*.opendb\n/RltkMaster/.vs/RltkMaster/v14/.suo\n"
  },
  {
    "path": "CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.1)\nproject(\"rltk\")\n\nset(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} \"${PROJECT_SOURCE_DIR}/cmake_modules\")\nset(CMAKE_CXX_STANDARD 14)\nset(CMAKE_CXX_STANDARD_REQUIRED on)\n\nfind_package(ZLIB REQUIRED)\nfind_package(SFML 2 COMPONENTS system window graphics REQUIRED)\nfind_package(cereal REQUIRED)\n\nadd_library(rltk \trltk/rltk.cpp\n\t\t\t\t\trltk/texture_resources.cpp\n\t\t\t\t\trltk/color_t.cpp\n\t\t\t\t\trltk/virtual_terminal.cpp\n\t\t\t\t\trltk/rng.cpp\n\t\t\t\t\trltk/geometry.cpp\n\t\t\t\t\trltk/input_handler.cpp\n\t\t\t\t\trltk/font_manager.cpp\n\t\t\t\t\trltk/gui.cpp\n\t\t\t\t\trltk/layer_t.cpp\n\t\t\t\t\trltk/gui_control_t.cpp\n\t\t\t\t\trltk/virtual_terminal_sparse.cpp\n\t\t\t\t\trltk/ecs.cpp\n\t\t\t\t\trltk/xml.cpp\n\t\t\t\t\trltk/perlin_noise.cpp\n\t\t\t\t\trltk/rexspeeder.cpp\n\t\t\t\t\trltk/scaling.cpp)\ntarget_include_directories(rltk PUBLIC\n\t\t\"$<BUILD_INTERFACE:${SFML_INCLUDE_DIR}>\"\n\t\t\"$<BUILD_INTERFACE:${CEREAL_INCLUDE_DIR}>\"\n\t\t\"$<BUILD_INTERFACE:${ZLIB_INCLUDE_DIRS}>\"\n\t\t)\ntarget_link_libraries(rltk PUBLIC ${ZLIB_LIBRARIES} ${SFML_LIBRARIES})\nif(NOT MSVC) # Why was this here? I exempted the wierd linker flags\n\ttarget_compile_options(rltk PUBLIC -O3 -Wall -Wpedantic -march=native -mtune=native -g)\nelse()\n\ttarget_compile_options(rltk PUBLIC /W3 /EHsc)\nendif()\n\ninstall (TARGETS rltk\n\t\tARCHIVE DESTINATION lib\n\t\tLIBRARY DESTINATION lib\n\t\tRUNTIME DESTINATION bin)\n\nset(RLTK_HEADERS\n\t\trltk/astar.hpp\n\t\trltk/colors.hpp\n\t\trltk/color_t.hpp\n\t\trltk/ecs.hpp\n\t\trltk/ecs_impl.hpp\n\t\trltk/filesystem.hpp\n\t\trltk/font_manager.hpp\n\t\trltk/fsa.hpp\n\t\trltk/geometry.hpp\n\t\trltk/gui.hpp\n\t\trltk/gui_control_t.hpp\n\t\trltk/input_handler.hpp\n\t\trltk/layer_t.hpp\n\t\trltk/path_finding.hpp\n\t\trltk/perlin_noise.hpp\n\t\trltk/rexspeeder.hpp\n\t\trltk/rltk.hpp\n\t\trltk/rng.hpp\n\t\trltk/scaling.hpp\n\t\trltk/serialization_utils.hpp\n\t\trltk/texture.hpp\n\t\trltk/texture_resources.hpp\n\t\trltk/vchar.hpp\n\t\trltk/virtual_terminal.hpp\n\t\trltk/virtual_terminal_sparse.hpp\n\t\trltk/visibility.hpp\n\t\trltk/xml.hpp)\n\ninstall(FILES ${RLTK_HEADERS}\n\t\tDESTINATION \"include/rltk\"\n\t\t)\n\n# Examples\n\n# Add all of the example executables and their library dependency\nadd_executable(ex1 examples/ex1/main.cpp)\nadd_executable(ex2 examples/ex2/main.cpp)\nadd_executable(ex3 examples/ex3/main.cpp)\nadd_executable(ex4 examples/ex4/main.cpp)\nadd_executable(ex5 examples/ex5/main.cpp)\nadd_executable(ex6 examples/ex6/main.cpp)\nadd_executable(ex7 examples/ex7/main.cpp)\nadd_executable(ex8 examples/ex8/main.cpp)\nadd_executable(ex9 examples/ex9/main.cpp)\nadd_executable(ex10 examples/ex10/main.cpp)\nadd_executable(ex11 examples/ex11/main.cpp)\ntarget_link_libraries(ex1 rltk)\ntarget_link_libraries(ex2 rltk)\ntarget_link_libraries(ex3 rltk)\ntarget_link_libraries(ex4 rltk)\ntarget_link_libraries(ex5 rltk)\ntarget_link_libraries(ex6 rltk)\ntarget_link_libraries(ex7 rltk)\ntarget_link_libraries(ex8 rltk)\ntarget_link_libraries(ex9 rltk)\ntarget_link_libraries(ex10 rltk)\ntarget_link_libraries(ex11 rltk)\n"
  },
  {
    "path": "CMakeSettings.json",
    "content": "{\n    // See https://go.microsoft.com//fwlink//?linkid=834763 for more information about this file.\n    \"configurations\": [\n        {\n            \"name\": \"x86-Debug\",\n            \"generator\": \"Visual Studio 15 2017\",\n            \"configurationType\": \"Debug\",\n            \"buildRoot\": \"${env.LOCALAPPDATA}\\\\CMakeBuild\\\\${workspaceHash}\\\\build\\\\${name}\",\n            \"cmakeCommandArgs\": \"\",\n            \"buildCommandArgs\": \"-m -v:minimal\",\n            \"ctestCommandArgs\": \"\",\n            \"variables\": [\n                {\n                    \"name\": \"CMAKE_TOOLCHAIN_FILE\",\n                    \"value\": \"C:/Users/Herbert/Source/Repos/vcpkg/scripts/buildsystems/vcpkg.cmake\"\n                }\n            ]\n        },\n        {\n            \"name\": \"x86-Release\",\n            \"generator\": \"Visual Studio 15 2017\",\n            \"configurationType\": \"Release\",\n            \"buildRoot\": \"${env.LOCALAPPDATA}\\\\CMakeBuild\\\\${workspaceHash}\\\\build\\\\${name}\",\n            \"cmakeCommandArgs\": \"\",\n            \"buildCommandArgs\": \"-m -v:minimal\",\n            \"ctestCommandArgs\": \"\",\n            \"variables\": [\n                {\n                    \"name\": \"CMAKE_TOOLCHAIN_FILE\",\n                    \"value\": \"C:/Users/Herbert/Source/Repos/vcpkg/scripts/buildsystems/vcpkg.cmake\"\n                }\n            ]\n        },\n        {\n            \"name\": \"x64-Debug\",\n            \"generator\": \"Visual Studio 15 2017 Win64\",\n            \"configurationType\": \"Debug\",\n            \"buildRoot\": \"${env.LOCALAPPDATA}\\\\CMakeBuild\\\\${workspaceHash}\\\\build\\\\${name}\",\n            \"cmakeCommandArgs\": \"\",\n            \"buildCommandArgs\": \"-m -v:minimal\",\n            \"ctestCommandArgs\": \"\",\n            \"variables\": [\n                {\n                    \"name\": \"CMAKE_TOOLCHAIN_FILE\",\n                    \"value\": \"C:/Users/Herbert/Source/Repos/vcpkg/scripts/buildsystems/vcpkg.cmake\"\n                }\n            ]\n        },\n        {\n            \"name\": \"x64-Release\",\n            \"generator\": \"Visual Studio 15 2017 Win64\",\n            \"configurationType\": \"Release\",\n            \"buildRoot\": \"${env.LOCALAPPDATA}\\\\CMakeBuild\\\\${workspaceHash}\\\\build\\\\${name}\",\n            \"cmakeCommandArgs\": \"\",\n            \"buildCommandArgs\": \"-m -v:minimal\",\n            \"ctestCommandArgs\": \"\",\n            \"variables\": [\n                {\n                    \"name\": \"CMAKE_TOOLCHAIN_FILE\",\n                    \"value\": \"C:/Users/Herbert/Source/Repos/vcpkg/scripts/buildsystems/vcpkg.cmake\"\n                }\n            ]\n        }\n    ]\n}"
  },
  {
    "path": "LICENSE",
    "content": "Copyright (c) 2016 Bracket Productions (Herbert Wolverson)\n\nPermission 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:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE 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.\n"
  },
  {
    "path": "README.md",
    "content": "# rltk : Roguelike Toolkit - Modern (C++14) SFML-based toolkit for creating roguelikes.\n\nIt's very early days, but I hope that this can be a useful tool. Black Future was getting messy, and I needed to separate out some \nengine logic from game logic for my sanity; I realized that others might find the underlying engine code useful.\n\nRight now, it's a very fast ASCII (code-page 437) terminal renderer compatible with fonts from libtcod and Dwarf Fortress.\nEventually, it will provide assistance with a number of game-related topics including path-finding, line-plotting,\nand probably some of the entity-component-system I've been enjoying.\n\n**Credit to Pyridine for the REXPaint format code. Original located at: [https://github.com/pyridine/REXSpeeder](https://github.com/pyridine/REXSpeeder)**\n\n## Building from source\n\nYou need SFML for your platform, Boost, and cmake. Make a \"build\" folder, and use CMake to generate build files for your platform (I'll expand upon this later, when this is a more useful library).\n\n## Building on Visual Studio 2017\n\n* Setup VCPKG, following the instructions [here](https://blogs.msdn.microsoft.com/vcblog/2016/09/19/vcpkg-a-tool-to-acquire-and-build-c-open-source-libraries-on-windows/)\n* Ensure that you've integrated it, with `vcpkg integrate install` (see [here](https://github.com/Microsoft/vcpkg/blob/master/docs/examples/using-sqlite.md))\n* Install packages: `vcpkg install sfml` and `vcpkg install cereal`. These take a while.\n* Open Visual Studio 2017, and use \"Open Folder\" to open the RLTK folder to which you cloned everything. The CVPKG stuff will ensure that SFML is linked correctly.\n* If you've previously opened the project in VS2017, use the CMake menu to delete your cache and regenerate everything. You really shouldn't have to do this, but CMake integration is young.\n* You should now be able to select an output, and build/run it.\n\n## Included Examples (with lots of comments!)\n\nI'll write proper documentation as the library evolves; I don't really want to write up a lot of docs and have to revise them\nheavily as things solidify. I'm doing my best to include examples evolving towards a real roguelike. Currently, these are:\n\n### Example 1: Hello World\n![Hello World](https://raw.githubusercontent.com/thebracket/rltk/master/tutorial_images/example1.png \"Hello World\")\n\n[Example 1](https://github.com/thebracket/rltk/blob/master/examples/ex1/main.cpp): demonstrates a Hello World with frame-rate.\n\n### Example 2: Randomly moving @\n![Randomly Moving @](https://raw.githubusercontent.com/thebracket/rltk/master/tutorial_images/example2.gif \"Randomly Moving @\")\n\n[Example 2](https://github.com/thebracket/rltk/blob/master/examples/ex2/main.cpp): a randomly moving yellow @ on a field of white dots.\n\n### Example 3: Bresenham's Line Pathing\n![Bresenham Line Pathing](https://raw.githubusercontent.com/thebracket/rltk/master/tutorial_images/example3.gif \"Bresenham Line Pathing\")\n\n[Example 3](https://github.com/thebracket/rltk/blob/master/examples/ex3/main.cpp): our @ dude again, this time using Bresenham's line to find his way. It also renders additional glyphs, as Mr @ finds his way to his destination.\n\n### Example 4: A-Star Pathing\n![A Star Pathing](https://raw.githubusercontent.com/thebracket/rltk/master/tutorial_images/example4.gif \"A Star Pathing\")\n\n[Example 4](https://github.com/thebracket/rltk/blob/master/examples/ex4/main.cpp): our @ dude again, now on a defined map with obstacles and using A* to find his way to the heart. This demonstrates using templates to specialize map support - we won't force you to use a specific map representation!\n\n### Example 5: Mouse Controlled Path-Finding\n![Mouse Driven A Star Pathing](https://raw.githubusercontent.com/thebracket/rltk/master/tutorial_images/example5.gif \"Mouse Driven A Star Pathing\")\n\n[Example 5](https://github.com/thebracket/rltk/blob/master/examples/ex5/main.cpp): our @ dude again, using A* pathing to find his way to the mouse\ncursor. Click and he goes there.\n\n### Example 6: Visibility\n![Visibility](https://raw.githubusercontent.com/thebracket/rltk/master/tutorial_images/example6.gif \"Visibility\")\n\n[Example 6](https://github.com/thebracket/rltk/blob/master/examples/ex6/main.cpp): Example 5, but now we have true visibility plotted as you wander.\n\n### Example 7: Multi-font ASCII Layout\n![ComplexGui](https://raw.githubusercontent.com/thebracket/rltk/master/tutorial_images/example7.png \"Complex GUI\")\n\n[Example 7](https://github.com/thebracket/rltk/blob/master/examples/ex7/main.cpp): A complex GUI with multiple fonts and layers, dynamically resizable.\n\n### Example 8: Owner draw, and retained-mode GUI elements\n![RetainedMode](https://raw.githubusercontent.com/thebracket/rltk/master/tutorial_images/example8.gif \"Retained Mode\")\n\n[Example 8](https://github.com/thebracket/rltk/blob/master/examples/ex8/main.cpp): Demonstrates an \"owner draw\" panel (with SFML render target callback), drawing a background image. Some ASCII consoles are spawned, and one is populated with a mouse-over, a checkbox, radio-button set, a list-box and some status bars. The other panel displays the results.\n\n### Example 9: Sparse layer with effects\n![Sparse](https://raw.githubusercontent.com/thebracket/rltk/master/tutorial_images/example9.gif \"Sparse\")\n\n[Example 9](https://github.com/thebracket/rltk/blob/master/examples/ex9/main.cpp): This demo uses a regular console layer to draw the map,\nand a \"sparse\" console layer for the character and traversal path. It uses sub-character alignment to smoothly move the @ around, and\ndemonstrates rotation of the @ by leaning left or right as he travels (not an effect I recommend for a game, but it works as a demo!).\n\n### Example 10: The beginnings of a roguelike\n![Sparse](https://raw.githubusercontent.com/thebracket/rltk/master/tutorial_images/example10.gif \"RogueBeginnings\")\n\n[Example 10](https://github.com/thebracket/rltk/blob/master/examples/ex10/main.cpp): This example generates a random map, and you can move your @ around with the arrow keys. It is the first example to use the Entity-Component-System (ECS) provided by RLTK; it makes for a relatively straightforward and modern way to design a roguelike - with very little code, we have the basics of wandering around a map. Note: message passing isn't implemented yet; when it is - this example will be even smaller!\n\n### Example 11: REXPaint support (http://www.gridsagegames.com/rexpaint/)\n![RexPaint](https://raw.githubusercontent.com/thebracket/rltk/master/tutorial_images/example11.png \"RexPaint\")\n\n[Example 11](https://github.com/thebracket/rltk/blob/master/examples/ex11/main.cpp): This example is basically Hello World, but with a REX Paint image loaded (Nyan Cat) and displayed.\n\n\n## Example\nThe goal is to keep it simple from the user's point of view. The following code is enough to setup an ASCII terminal,\nand display **Hello World** with a frame-rate displayed (around 100 FPS on my workstation):\n\n```c++\n#include \"../../rltk/rltk.hpp\"\n#include <sstream>\n\nusing namespace rltk;\nusing namespace rltk::colors;\n\nvoid tick(double duration_ms) {\n\tstd::stringstream ss;\n\tss << \"Frame duration: \" << duration_ms << \" ms (\" << (1000.0/duration_ms) << \" FPS).\";\n\tconsole->print(1, 1, \"Hello World\", WHITE, BLACK);\n\tconsole->print(1, 2, ss.str(), YELLOW, BLUE);\n}\n\nint main()\n{\n\tinit(config_simple_px(\"../assets\"));\n\trun(tick);\n  return 0;\n}\n```\n"
  },
  {
    "path": "assets/fonts.txt",
    "content": "8x8,terminal8x8.png,8,8\n16x16,terminal16x16.png,16,16\n32x32,terminal32x32.png,32,32\n8x16,VGA8x16.png,8,16\n\n"
  },
  {
    "path": "cmake_modules/FindSFML.cmake",
    "content": "# This script locates the SFML library\n# ------------------------------------\n#\n# Usage\n# -----\n#\n# When you try to locate the SFML libraries, you must specify which modules you want to use (system, window, graphics, network, audio, main).\n# If none is given, the SFML_LIBRARIES variable will be empty and you'll end up linking to nothing.\n# example:\n#   find_package(SFML COMPONENTS graphics window system) # find the graphics, window and system modules\n#\n# You can enforce a specific version, either MAJOR.MINOR or only MAJOR.\n# If nothing is specified, the version won't be checked (i.e. any version will be accepted).\n# example:\n#   find_package(SFML COMPONENTS ...)     # no specific version required\n#   find_package(SFML 2 COMPONENTS ...)   # any 2.x version\n#   find_package(SFML 2.4 COMPONENTS ...) # version 2.4 or greater\n#\n# By default, the dynamic libraries of SFML will be found. To find the static ones instead,\n# you must set the SFML_STATIC_LIBRARIES variable to TRUE before calling find_package(SFML ...).\n# Since you have to link yourself all the SFML dependencies when you link it statically, the following\n# additional variables are defined: SFML_XXX_DEPENDENCIES and SFML_DEPENDENCIES (see their detailed\n# description below).\n# In case of static linking, the SFML_STATIC macro will also be defined by this script.\n# example:\n#   set(SFML_STATIC_LIBRARIES TRUE)\n#   find_package(SFML 2 COMPONENTS network system)\n#\n# On Mac OS X if SFML_STATIC_LIBRARIES is not set to TRUE then by default CMake will search for frameworks unless\n# CMAKE_FIND_FRAMEWORK is set to \"NEVER\" for example. Please refer to CMake documentation for more details.\n# Moreover, keep in mind that SFML frameworks are only available as release libraries unlike dylibs which\n# are available for both release and debug modes.\n#\n# If SFML is not installed in a standard path, you can use the SFML_ROOT CMake (or environment) variable\n# to tell CMake where SFML is.\n#\n# Output\n# ------\n#\n# This script defines the following variables:\n# - For each specified module XXX (system, window, graphics, network, audio, main):\n#   - SFML_XXX_LIBRARY_DEBUG:   the name of the debug library of the xxx module (set to SFML_XXX_LIBRARY_RELEASE is no debug version is found)\n#   - SFML_XXX_LIBRARY_RELEASE: the name of the release library of the xxx module (set to SFML_XXX_LIBRARY_DEBUG is no release version is found)\n#   - SFML_XXX_LIBRARY:         the name of the library to link to for the xxx module (includes both debug and optimized names if necessary)\n#   - SFML_XXX_FOUND:           true if either the debug or release library of the xxx module is found\n#   - SFML_XXX_DEPENDENCIES:    the list of libraries the module depends on, in case of static linking\n# - SFML_LIBRARIES:    the list of all libraries corresponding to the required modules\n# - SFML_FOUND:        true if all the required modules are found\n# - SFML_INCLUDE_DIR:  the path where SFML headers are located (the directory containing the SFML/Config.hpp file)\n# - SFML_DEPENDENCIES: the list of libraries SFML depends on, in case of static linking\n#\n# example:\n#   find_package(SFML 2 COMPONENTS system window graphics audio REQUIRED)\n#   include_directories(${SFML_INCLUDE_DIR})\n#   add_executable(myapp ...)\n#   target_link_libraries(myapp ${SFML_LIBRARIES})\n\n# define the SFML_STATIC macro if static build was chosen\nif(SFML_STATIC_LIBRARIES)\n    add_definitions(-DSFML_STATIC)\nendif()\n\n# define the list of search paths for headers and libraries\nset(FIND_SFML_PATHS\n    ${SFML_ROOT}\n    $ENV{SFML_ROOT}\n    ~/Library/Frameworks\n    /Library/Frameworks\n    /usr/local\n    /usr\n    /sw\n    /opt/local\n    /opt/csw\n    /opt)\n\n# find the SFML include directory\nfind_path(SFML_INCLUDE_DIR SFML/Config.hpp\n          PATH_SUFFIXES include\n          PATHS ${FIND_SFML_PATHS})\n\n# check the version number\nset(SFML_VERSION_OK TRUE)\nif(SFML_FIND_VERSION AND SFML_INCLUDE_DIR)\n    # extract the major and minor version numbers from SFML/Config.hpp\n    # we have to handle framework a little bit differently:\n    if(\"${SFML_INCLUDE_DIR}\" MATCHES \"SFML.framework\")\n        set(SFML_CONFIG_HPP_INPUT \"${SFML_INCLUDE_DIR}/Headers/Config.hpp\")\n    else()\n        set(SFML_CONFIG_HPP_INPUT \"${SFML_INCLUDE_DIR}/SFML/Config.hpp\")\n    endif()\n    FILE(READ \"${SFML_CONFIG_HPP_INPUT}\" SFML_CONFIG_HPP_CONTENTS)\n    STRING(REGEX REPLACE \".*#define SFML_VERSION_MAJOR ([0-9]+).*\" \"\\\\1\" SFML_VERSION_MAJOR \"${SFML_CONFIG_HPP_CONTENTS}\")\n    STRING(REGEX REPLACE \".*#define SFML_VERSION_MINOR ([0-9]+).*\" \"\\\\1\" SFML_VERSION_MINOR \"${SFML_CONFIG_HPP_CONTENTS}\")\n    STRING(REGEX REPLACE \".*#define SFML_VERSION_PATCH ([0-9]+).*\" \"\\\\1\" SFML_VERSION_PATCH \"${SFML_CONFIG_HPP_CONTENTS}\")\n    if (NOT \"${SFML_VERSION_PATCH}\" MATCHES \"^[0-9]+$\")\n        set(SFML_VERSION_PATCH 0)\n    endif()\n    math(EXPR SFML_REQUESTED_VERSION \"${SFML_FIND_VERSION_MAJOR} * 10000 + ${SFML_FIND_VERSION_MINOR} * 100 + ${SFML_FIND_VERSION_PATCH}\")\n\n    # if we could extract them, compare with the requested version number\n    if (SFML_VERSION_MAJOR)\n        # transform version numbers to an integer\n        math(EXPR SFML_VERSION \"${SFML_VERSION_MAJOR} * 10000 + ${SFML_VERSION_MINOR} * 100 + ${SFML_VERSION_PATCH}\")\n\n        # compare them\n        if(SFML_VERSION LESS SFML_REQUESTED_VERSION)\n            set(SFML_VERSION_OK FALSE)\n        endif()\n    else()\n        # SFML version is < 2.0\n        if (SFML_REQUESTED_VERSION GREATER 10900)\n            set(SFML_VERSION_OK FALSE)\n            set(SFML_VERSION_MAJOR 1)\n            set(SFML_VERSION_MINOR x)\n            set(SFML_VERSION_PATCH x)\n        endif()\n    endif()\nendif()\n\n# find the requested modules\nset(SFML_FOUND TRUE) # will be set to false if one of the required modules is not found\nforeach(FIND_SFML_COMPONENT ${SFML_FIND_COMPONENTS})\n    string(TOLOWER ${FIND_SFML_COMPONENT} FIND_SFML_COMPONENT_LOWER)\n    string(TOUPPER ${FIND_SFML_COMPONENT} FIND_SFML_COMPONENT_UPPER)\n    set(FIND_SFML_COMPONENT_NAME sfml-${FIND_SFML_COMPONENT_LOWER})\n\n    # no suffix for sfml-main, it is always a static library\n    if(FIND_SFML_COMPONENT_LOWER STREQUAL \"main\")\n        # release library\n        find_library(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE\n                     NAMES ${FIND_SFML_COMPONENT_NAME}\n                     PATH_SUFFIXES lib64 lib\n                     PATHS ${FIND_SFML_PATHS})\n\n        # debug library\n        find_library(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG\n                     NAMES ${FIND_SFML_COMPONENT_NAME}-d\n                     PATH_SUFFIXES lib64 lib\n                     PATHS ${FIND_SFML_PATHS})\n    else()\n        # static release library\n        find_library(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_STATIC_RELEASE\n                     NAMES ${FIND_SFML_COMPONENT_NAME}-s\n                     PATH_SUFFIXES lib64 lib\n                     PATHS ${FIND_SFML_PATHS})\n\n        # static debug library\n        find_library(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_STATIC_DEBUG\n                     NAMES ${FIND_SFML_COMPONENT_NAME}-s-d\n                     PATH_SUFFIXES lib64 lib\n                     PATHS ${FIND_SFML_PATHS})\n\n        # dynamic release library\n        find_library(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DYNAMIC_RELEASE\n                     NAMES ${FIND_SFML_COMPONENT_NAME}\n                     PATH_SUFFIXES lib64 lib\n                     PATHS ${FIND_SFML_PATHS})\n\n        # dynamic debug library\n        find_library(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DYNAMIC_DEBUG\n                     NAMES ${FIND_SFML_COMPONENT_NAME}-d\n                     PATH_SUFFIXES lib64 lib\n                     PATHS ${FIND_SFML_PATHS})\n\n        # choose the entries that fit the requested link type\n        if(SFML_STATIC_LIBRARIES)\n            if(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_STATIC_RELEASE)\n                set(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE ${SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_STATIC_RELEASE})\n            endif()\n            if(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_STATIC_DEBUG)\n                set(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG ${SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_STATIC_DEBUG})\n            endif()\n        else()\n            if(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DYNAMIC_RELEASE)\n                set(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE ${SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DYNAMIC_RELEASE})\n            endif()\n            if(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DYNAMIC_DEBUG)\n                set(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG ${SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DYNAMIC_DEBUG})\n            endif()\n        endif()\n    endif()\n\n    if (SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG OR SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE)\n        # library found\n        set(SFML_${FIND_SFML_COMPONENT_UPPER}_FOUND TRUE)\n\n        # if both are found, set SFML_XXX_LIBRARY to contain both\n        if (SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG AND SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE)\n            set(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY debug     ${SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG}\n                                                          optimized ${SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE})\n        endif()\n\n        # if only one debug/release variant is found, set the other to be equal to the found one\n        if (SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG AND NOT SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE)\n            # debug and not release\n            set(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE ${SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG})\n            set(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY         ${SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG})\n        endif()\n        if (SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE AND NOT SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG)\n            # release and not debug\n            set(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG ${SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE})\n            set(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY       ${SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE})\n        endif()\n    else()\n        # library not found\n        set(SFML_FOUND FALSE)\n        set(SFML_${FIND_SFML_COMPONENT_UPPER}_FOUND FALSE)\n        set(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY \"\")\n        set(FIND_SFML_MISSING \"${FIND_SFML_MISSING} SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY\")\n    endif()\n\n    # mark as advanced\n    MARK_AS_ADVANCED(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY\n                     SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE\n                     SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG\n                     SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_STATIC_RELEASE\n                     SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_STATIC_DEBUG\n                     SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DYNAMIC_RELEASE\n                     SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DYNAMIC_DEBUG)\n\n    # add to the global list of libraries\n    set(SFML_LIBRARIES ${SFML_LIBRARIES} \"${SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY}\")\nendforeach()\n\n# in case of static linking, we must also define the list of all the dependencies of SFML libraries\nif(SFML_STATIC_LIBRARIES)\n\n    # detect the OS\n    if(${CMAKE_SYSTEM_NAME} MATCHES \"Windows\")\n        set(FIND_SFML_OS_WINDOWS 1)\n    elseif(${CMAKE_SYSTEM_NAME} MATCHES \"Linux\")\n        set(FIND_SFML_OS_LINUX 1)\n    elseif(${CMAKE_SYSTEM_NAME} MATCHES \"FreeBSD\")\n        set(FIND_SFML_OS_FREEBSD 1)\n    elseif(${CMAKE_SYSTEM_NAME} MATCHES \"Darwin\")\n        set(FIND_SFML_OS_MACOSX 1)\n    endif()\n\n    # start with an empty list\n    set(SFML_DEPENDENCIES)\n    set(FIND_SFML_DEPENDENCIES_NOTFOUND)\n\n    # macro that searches for a 3rd-party library\n    macro(find_sfml_dependency output friendlyname)\n        # No lookup in environment variables (PATH on Windows), as they may contain wrong library versions\n        find_library(${output} NAMES ${ARGN} PATHS ${FIND_SFML_PATHS} PATH_SUFFIXES lib NO_SYSTEM_ENVIRONMENT_PATH)\n        if(${${output}} STREQUAL \"${output}-NOTFOUND\")\n            unset(output)\n            set(FIND_SFML_DEPENDENCIES_NOTFOUND \"${FIND_SFML_DEPENDENCIES_NOTFOUND} ${friendlyname}\")\n        endif()\n    endmacro()\n\n    # sfml-system\n    list(FIND SFML_FIND_COMPONENTS \"system\" FIND_SFML_SYSTEM_COMPONENT)\n    if(NOT ${FIND_SFML_SYSTEM_COMPONENT} EQUAL -1)\n\n        # update the list -- these are only system libraries, no need to find them\n        if(FIND_SFML_OS_LINUX OR FIND_SFML_OS_FREEBSD OR FIND_SFML_OS_MACOSX)\n            set(SFML_SYSTEM_DEPENDENCIES \"pthread\")\n        endif()\n        if(FIND_SFML_OS_LINUX)\n            set(SFML_SYSTEM_DEPENDENCIES ${SFML_SYSTEM_DEPENDENCIES} \"rt\")\n        endif()\n        if(FIND_SFML_OS_WINDOWS)\n            set(SFML_SYSTEM_DEPENDENCIES \"winmm\")\n        endif()\n        set(SFML_DEPENDENCIES ${SFML_SYSTEM_DEPENDENCIES} ${SFML_DEPENDENCIES})\n    endif()\n\n    # sfml-network\n    list(FIND SFML_FIND_COMPONENTS \"network\" FIND_SFML_NETWORK_COMPONENT)\n    if(NOT ${FIND_SFML_NETWORK_COMPONENT} EQUAL -1)\n\n        # update the list -- these are only system libraries, no need to find them\n        if(FIND_SFML_OS_WINDOWS)\n            set(SFML_NETWORK_DEPENDENCIES \"ws2_32\")\n        endif()\n        set(SFML_DEPENDENCIES ${SFML_NETWORK_DEPENDENCIES} ${SFML_DEPENDENCIES})\n    endif()\n\n    # sfml-window\n    list(FIND SFML_FIND_COMPONENTS \"window\" FIND_SFML_WINDOW_COMPONENT)\n    if(NOT ${FIND_SFML_WINDOW_COMPONENT} EQUAL -1)\n\n        # find libraries\n        if(FIND_SFML_OS_LINUX OR FIND_SFML_OS_FREEBSD)\n            find_sfml_dependency(X11_LIBRARY \"X11\" X11)\n            find_sfml_dependency(XRANDR_LIBRARY \"Xrandr\" Xrandr)\n        endif()\n\n        if(FIND_SFML_OS_LINUX)\n            find_sfml_dependency(UDEV_LIBRARIES \"UDev\" udev libudev)\n        endif()\n\n        # update the list\n        if(FIND_SFML_OS_WINDOWS)\n            set(SFML_WINDOW_DEPENDENCIES ${SFML_WINDOW_DEPENDENCIES} \"opengl32\" \"winmm\" \"gdi32\")\n        elseif(FIND_SFML_OS_LINUX)\n            set(SFML_WINDOW_DEPENDENCIES ${SFML_WINDOW_DEPENDENCIES} \"GL\" ${X11_LIBRARY} ${XRANDR_LIBRARY} ${UDEV_LIBRARIES})\n        elseif(FIND_SFML_OS_FREEBSD)\n            set(SFML_WINDOW_DEPENDENCIES ${SFML_WINDOW_DEPENDENCIES} \"GL\" ${X11_LIBRARY} ${XRANDR_LIBRARY} \"usbhid\")\n        elseif(FIND_SFML_OS_MACOSX)\n            set(SFML_WINDOW_DEPENDENCIES ${SFML_WINDOW_DEPENDENCIES} \"-framework OpenGL -framework Foundation -framework AppKit -framework IOKit -framework Carbon\")\n        endif()\n        set(SFML_DEPENDENCIES ${SFML_WINDOW_DEPENDENCIES} ${SFML_DEPENDENCIES})\n    endif()\n\n    # sfml-graphics\n    list(FIND SFML_FIND_COMPONENTS \"graphics\" FIND_SFML_GRAPHICS_COMPONENT)\n    if(NOT ${FIND_SFML_GRAPHICS_COMPONENT} EQUAL -1)\n\n        # find libraries\n        find_sfml_dependency(FREETYPE_LIBRARY \"FreeType\" freetype)\n        find_sfml_dependency(JPEG_LIBRARY \"libjpeg\" jpeg)\n\n        # update the list\n        set(SFML_GRAPHICS_DEPENDENCIES ${FREETYPE_LIBRARY} ${JPEG_LIBRARY})\n        set(SFML_DEPENDENCIES ${SFML_GRAPHICS_DEPENDENCIES} ${SFML_DEPENDENCIES})\n    endif()\n\n    # sfml-audio\n    list(FIND SFML_FIND_COMPONENTS \"audio\" FIND_SFML_AUDIO_COMPONENT)\n    if(NOT ${FIND_SFML_AUDIO_COMPONENT} EQUAL -1)\n\n        # find libraries\n        find_sfml_dependency(OPENAL_LIBRARY \"OpenAL\" openal openal32)\n        find_sfml_dependency(OGG_LIBRARY \"Ogg\" ogg)\n        find_sfml_dependency(VORBIS_LIBRARY \"Vorbis\" vorbis)\n        find_sfml_dependency(VORBISFILE_LIBRARY \"VorbisFile\" vorbisfile)\n        find_sfml_dependency(VORBISENC_LIBRARY \"VorbisEnc\" vorbisenc)\n        find_sfml_dependency(FLAC_LIBRARY \"FLAC\" FLAC)\n\n        # update the list\n        set(SFML_AUDIO_DEPENDENCIES ${OPENAL_LIBRARY} ${FLAC_LIBRARY} ${VORBISENC_LIBRARY} ${VORBISFILE_LIBRARY} ${VORBIS_LIBRARY} ${OGG_LIBRARY})\n        set(SFML_DEPENDENCIES ${SFML_DEPENDENCIES} ${SFML_AUDIO_DEPENDENCIES})\n    endif()\n\nendif()\n\n# handle errors\nif(NOT SFML_VERSION_OK)\n    # SFML version not ok\n    set(FIND_SFML_ERROR \"SFML found but version too low (requested: ${SFML_FIND_VERSION}, found: ${SFML_VERSION_MAJOR}.${SFML_VERSION_MINOR}.${SFML_VERSION_PATCH})\")\n    set(SFML_FOUND FALSE)\nelseif(SFML_STATIC_LIBRARIES AND FIND_SFML_DEPENDENCIES_NOTFOUND)\n    set(FIND_SFML_ERROR \"SFML found but some of its dependencies are missing (${FIND_SFML_DEPENDENCIES_NOTFOUND})\")\n    set(SFML_FOUND FALSE)\nelseif(NOT SFML_FOUND)\n    # include directory or library not found\n    set(FIND_SFML_ERROR \"Could NOT find SFML (missing: ${FIND_SFML_MISSING})\")\nendif()\nif (NOT SFML_FOUND)\n    if(SFML_FIND_REQUIRED)\n        # fatal error\n        message(FATAL_ERROR ${FIND_SFML_ERROR})\n    elseif(NOT SFML_FIND_QUIETLY)\n        # error but continue\n        message(\"${FIND_SFML_ERROR}\")\n    endif()\nendif()\n\n# handle success\nif(SFML_FOUND AND NOT SFML_FIND_QUIETLY)\n    message(STATUS \"Found SFML ${SFML_VERSION_MAJOR}.${SFML_VERSION_MINOR}.${SFML_VERSION_PATCH} in ${SFML_INCLUDE_DIR}\")\nendif()\n"
  },
  {
    "path": "cmake_modules/Findcereal.cmake",
    "content": "# - Try to find Cereal lib\n#\n# This sets the following variables:\n# CEREAL_FOUND - True if Cereal was found.\n# CEREAL_INCLUDE_DIRS - Directories containing the Cereal include files.\n\n\nfind_path(CEREAL_INCLUDE_DIRS cereal\n\tHINTS \"$ENV{CMAKE_SOURCE_DIR}/include\" \"/usr/include\" \"$ENV{CMAKE_BINARY_DIR}/cereal/include\")\n\nset(CEREAL_INCLUDE_DIRS ${CEREAL_INCLUDE_DIRS})\n\ninclude(FindPackageHandleStandardArgs)\nfind_package_handle_standard_args(Cereal DEFAULT_MSG CEREAL_INCLUDE_DIRS)\n\nmark_as_advanced(CEREAL_INCLUDE_DIRS)\n\nif(CEREAL_FOUND)\n  MESSAGE(STATUS \"Found Cereal: ${CEREAL_INCLUDE_DIRS}\")\nendif(CEREAL_FOUND)\n\n"
  },
  {
    "path": "examples/ex1/main.cpp",
    "content": "/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed under the MIT license - see LICENSE file.\n *\n * Example 1: A truly minimal hello world root console, demonstrating\n * how to get started with RLTK.\n */\n\n// You need to include the RLTK header\n#include \"../../rltk/rltk.hpp\"\n\n// We're using a stringstream to build the hello world message.\n#include <sstream>\n\n// For convenience, import the whole rltk namespace. You may not want to do this\n// in larger projects, to avoid naming collisions.\nusing namespace rltk;\nusing namespace rltk::colors;\n\n// Tick is called every frame. The parameter specifies how many ms have elapsed\n// since the last time it was called.\nvoid tick(double duration_ms) {\n\t// In this case, we just want to print \"Hello World\" in white on black.\n\tif (console->dirty) {\n\t\tconsole->clear();\n\t\tconsole->print(1,1,\"Hello World\", WHITE, BLACK);\n\t}\n}\n\n// Your main function\nint main()\n{\n\t// Initialize the library. Here, we are providing plenty of into so you can see what is\n\t// available. There's also the option to use config_simple_px to configure by pixels\n\t// rather than characters.\n\t// The first parameter is the path to the font files.\n\t// The second and third parameters specify the desired console size in screen characters (80x25).\n\t// The fourth parameter is the window title.\n\t// The fifth parameter says that we'd like the default console to use an 8x16 VGA font. Not so great for games, but easy to read!\n\t// The final parameter controls whether or not we want to go full screen.\n\tinit(config_simple(\"../assets\", 80, 25, \"RLTK Hello World\", \"8x16\", false));\n\n\t// Enter the main loop. \"tick\" is the function we wrote above.\n\trun(tick);\n\n    return 0;\n}\n"
  },
  {
    "path": "examples/ex10/main.cpp",
    "content": "/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed under the MIT license - see LICENSE file.\n *\n * Example 10: Not really an example yet, playing with getting the ECS working.\n */\n\n// You need to include the RLTK header\n#include \"../../rltk/rltk.hpp\"\n\n// We're using a stringstream to build the hello world message.\n#include <sstream>\n#include <algorithm>\n\n// For convenience, import the whole rltk namespace. You may not want to do this\n// in larger projects, to avoid naming collisions.\nusing namespace rltk;\nusing namespace rltk::colors;\nusing std::size_t;\n\nconstexpr int map_width = 100;\nconstexpr int map_height = 100;\nconstexpr int map_size = map_width * map_height;\nint map_idx(const int x, const int y) { return (y * map_width) + x; }\nstd::vector<int> map_tiles;\nstd::vector<uint8_t> visible;\nstd::vector<bool> revealed;\nrandom_number_generator rng;\n\nsize_t player_id;\n\nstruct position { \n\tposition() {}\n\tposition(const int X, const int Y) : x(X), y(Y) {}\n\n\tint x, y;\t\n\n\tvoid bounds_check() {\n\t\tif (x < 0) x = 0;\n\t\tif (x > map_width) x = map_width;\n\t\tif (y < 0) y = 0;\n\t\tif (y > map_height) y = map_height;\n\t}\n};\n\nstruct renderable { \n\trenderable() {}\n\trenderable(const char Glyph, const color_t foreground) : glyph(Glyph), fg(foreground) {}\n\tint glyph; \n\tcolor_t fg=colors::WHITE; \n\tcolor_t bg=colors::BLACK; \n};\n\nstruct navigator_helper {\n\tstatic int get_x(const position &loc) { return loc.x; }\n\tstatic int get_y(const position &loc) { return loc.y; }\n\tstatic position get_xy(const int &x, const int &y) { return position{x,y}; }\n};\n\n// Clipping info\nint left_x, right_x, top_y, bottom_y;\n\nstruct actor_moved_message : base_message_t {\n\tactor_moved_message() {}\n\tactor_moved_message(entity_t * ACTOR, const int fx, const int fy, const int dx, const int dy) :\n\t\tmover(ACTOR), from_x(fx), from_y(fy), destination_x(dx), destination_y(dy) {}\n\n\tentity_t * mover;\n\tint from_x, from_y, destination_x, destination_y;\n};\n\nstruct player_moved_message : base_message_t {};\n\nstruct camera_system : public base_system {\n\tvirtual void configure() override {\n\t\tsystem_name = \"Camera System\";\n\t\t// Create the player\n\t\tauto player = create_entity()\n\t\t\t->assign(position{map_width/2, map_height/2})\n\t\t\t->assign(renderable('@', colors::YELLOW));\n\t\tplayer_id = player->id;\n\t}\n\n\tvirtual void update(const double duration_ms) override {\n\t\tif (console->dirty) {\n\t\t\tconsole->clear();\n\n\t\t\t// Find the camera\n\t\t\tauto camera_loc = entity(player_id)->component<position>();\n\t\t\tleft_x = camera_loc->x - (console->term_width / 2);\n\t\t\tright_x = camera_loc->x + (console->term_width / 2);\n\t\t\ttop_y = camera_loc->y - (console->term_height/2);\n\t\t\tbottom_y = camera_loc->y + (console->term_height/2)+1;\n\n\t\t\tfor (int y=top_y; y<bottom_y; ++y) {\n\t\t\t\tfor (int x=left_x; x<right_x; ++x) {\n\t\t\t\t\tif (x >= 0 && x < map_width && y >= 0 && y < map_height) {\n\t\t\t\t\t\tvchar map_char{'.', color_t(0,0,64), colors::BLACK};\n\t\t\t\t\t\tconst int map_index = map_idx(x,y);\n\n\t\t\t\t\t\tif (revealed[map_index]) {\n\t\t\t\t\t\t\tswitch (map_tiles[map_index]) {\n\t\t\t\t\t\t\t\tcase 0 : map_char.glyph = '.'; break;\n\t\t\t\t\t\t\t\tcase 1 : map_char.glyph = '#'; break;\n\t\t\t\t\t\t\t\tdefault : map_char.glyph = 'E'; // This shouldn't happen\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tmap_char.foreground = color_t(96,96,96);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (visible[map_index] > 0) {\n\t\t\t\t\t\t\tuint8_t brightness =(visible[map_index]*16) + 127;\n\t\t\t\t\t\t\tmap_char.foreground = color_t(brightness, brightness, brightness);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tif (map_tiles[map_index] == 0) map_char.glyph = ' ';\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconsole->set_char(x-left_x, y-top_y, map_char);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\t\t\n\t}\n};\n\nstruct actor_render_system : public base_system {\n\tvirtual void configure() override {\n\t\tsystem_name = \"Actor Render System\";\n\t}\n\n\tvirtual void update(const double duration_ms) override {\n\t\teach<position, renderable>([] (entity_t &entity, position &pos, renderable &render) {\n\t\t\tconst int map_index = map_idx(pos.x, pos.y);\n\t\t\tif (visible[map_index]) {\n\t\t\t\tconsole->set_char(pos.x-left_x, pos.y-top_y, vchar{ render.glyph, render.fg, render.bg });\n\t\t\t}\n\t\t});\n\t}\n};\n\nstruct player_system : public base_system {\n\tvirtual void configure() override {\n\t\tsystem_name = \"Player System\";\n\t\tsubscribe<actor_moved_message>([this](actor_moved_message &msg) {\n\t\t\tif (map_tiles[map_idx(msg.destination_x, msg.destination_y)] == 0) {\n\t\t\t\tmsg.mover->component<position>()->x = msg.destination_x;\n\t\t\t\tmsg.mover->component<position>()->y = msg.destination_y;\n\t\t\t\tmsg.mover->component<position>()->bounds_check();\n\t\t\t\tconsole->dirty = true;\n\t\t\t\temit(player_moved_message{});\n\t\t\t}\n\t\t});\n\n\t\tsubscribe_mbox<key_pressed_t>();\n\t}\n\n\tvirtual void update(const double duration_ms) override {\n\t\tauto camera_loc = entity(player_id)->component<position>();\n\n\t\t// Loop through the keyboard input list\n\t\tstd::queue<key_pressed_t> * messages = mbox<key_pressed_t>();\n\t\twhile (!messages->empty()) {\n\t\t\tkey_pressed_t e = messages->front();\n\t\t\tmessages->pop();\n\t\t\t\n\t\t\tif (e.event.key.code == sf::Keyboard::Left) emit(actor_moved_message{ entity(player_id), camera_loc->x, camera_loc->y, camera_loc->x - 1, camera_loc->y });\n\t\t\tif (e.event.key.code == sf::Keyboard::Right) emit(actor_moved_message{ entity(player_id), camera_loc->x, camera_loc->y, camera_loc->x + 1, camera_loc->y });\n\t\t\tif (e.event.key.code == sf::Keyboard::Up) emit(actor_moved_message{ entity(player_id), camera_loc->x, camera_loc->y, camera_loc->x, camera_loc->y-1 });\n\t\t\tif (e.event.key.code == sf::Keyboard::Down) emit(actor_moved_message{ entity(player_id), camera_loc->x, camera_loc->y, camera_loc->x, camera_loc->y+1 });\n\t\t\tif (e.event.key.code == sf::Keyboard::F1) {\n\t\t\t\tstd::string timings = ecs_profile_dump();\n\t\t\t\tstd::cout << timings << \"\\n\";\n\t\t\t}\n\t\t}\n\t}\n};\n\nstruct visibility_system : public base_system {\n\tvirtual void configure() override {\n\t\tsystem_name = \"Visibility System\";\n\t\tsubscribe<player_moved_message>([this](player_moved_message &msg) {\n\t\t\tauto camera_loc = entity(player_id)->component<position>();\n\t\t\tposition camera_loc_deref = *camera_loc;\n\n\t\t\tstd::fill(visible.begin(), visible.end(), 0);\n\t\t\tvisibility_sweep_2d<position, navigator_helper>(camera_loc_deref, 10,\n\t\t\t\t[](position reveal) {\n\t\t\t\treveal.bounds_check();\n\t\t\t\tconst int idx = map_idx(reveal.x, reveal.y);\n\t\t\t\t++visible[idx];\n\t\t\t\tif (visible[idx] > 8) visible[idx] = 8;\n\t\t\t\trevealed[idx] = true;\n\t\t\t},\t[](position visibility_check) {\n\t\t\t\tvisibility_check.bounds_check();\n\t\t\t\treturn (map_tiles[map_idx(visibility_check.x, visibility_check.y)] == 0);\n\t\t\t});\n\t\t});\n\t}\n\n\tbool firstrun = true;\n\n\tvirtual void update(const double duration_ms) override {\n\t\tif (firstrun) {\n\t\t\temit(player_moved_message{});\n\t\t\tfirstrun = false;\n\t\t}\n\t}\n};\n\n// Tick is called every frame. The parameter specifies how many ms have elapsed\n// since the last time it was called.\nvoid tick(double duration_ms) {\n\tecs_tick(duration_ms);\n}\n\n// Your main function\nint main()\n{\n\t// Initialize the library. Here, we are providing plenty of into so you can see what is\n\t// available. There's also the option to use config_simple_px to configure by pixels\n\t// rather than characters.\n\t// The first parameter is the path to the font files.\n\t// The second and third parameters specify the desired console size in screen characters (80x25).\n\t// The fourth parameter is the window title.\n\t// The final parameter says that we'd like the default console to use an 8x16 VGA font. Not so great for games, but easy to read!\n\tinit(config_simple(\"../assets\", 80, 50, \"RLTK Hello World\", \"8x8\"));\n\t\n\t// Zero the map other than the edges\n\tmap_tiles.resize(map_size);\n\tvisible.resize(map_size);\n\trevealed.resize(map_size);\n\tstd::fill(map_tiles.begin(), map_tiles.end(), 0);\n\tstd::fill(visible.begin(), visible.end(), false);\n\tstd::fill(revealed.begin(), revealed.end(), false);\n\tfor (int i=0; i<map_width; ++i) {\n\t\tmap_tiles[map_idx(i, 0)] = 1;\n\t\tmap_tiles[map_idx(i, map_height-1)] = 1;\n\t}\n\tfor (int i=0; i<map_width; ++i) {\n\t\tmap_tiles[map_idx(0, i)] = 1;\n\t\tmap_tiles[map_idx(map_width-1, i)] = 1;\n\t}\n\t// Random debris\n\tfor (int y=1; y<map_height-1; ++y) {\n\t\tfor (int x=1; x<map_width-1; ++x) {\n\t\t\tif (rng.roll_dice(1,4)==1 && (x!=map_width/2 || y!=map_height/2)) map_tiles[map_idx(x,y)]=1;\n\t\t}\n\t}\n\n\t// Create our systems\n\tadd_system<player_system>();\n\tadd_system<visibility_system>();\n\tadd_system<camera_system>();\n\tadd_system<actor_render_system>();\n\n\t// Enter the main loop. \"tick\" is the function we wrote above.\n\tecs_configure();\n\trun(tick);\n\n    return 0;\n}\n"
  },
  {
    "path": "examples/ex11/main.cpp",
    "content": "/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed under the MIT license - see LICENSE file.\n *\n * Example 11: Hello World and a REX Paint object\n */\n\n// You need to include the RLTK header\n#include \"../../rltk/rltk.hpp\"\n\n// We're using a stringstream to build the hello world message.\n#include <sstream>\n\n// For convenience, import the whole rltk namespace. You may not want to do this\n// in larger projects, to avoid naming collisions.\nusing namespace rltk;\nusing namespace rltk::colors;\n\nrltk::xp::rex_sprite nyan_cat(\"../assets/nyan.xp\");\n\n// Tick is called every frame. The parameter specifies how many ms have elapsed\n// since the last time it was called.\nvoid tick(double duration_ms) {\n\t// In this case, we just want to print \"Hello World\" in white on black.\n\tif (console->dirty) {\n\t\tconsole->clear();\n\t\tconsole->print(1,1,\"Hello World\", WHITE, BLACK);\n\t\tconsole->draw_sprite(1,3,nyan_cat);\n\t}\n}\n\n// Your main function\nint main()\n{\n\t// Initialize the library. Here, we are providing plenty of into so you can see what is\n\t// available. There's also the option to use config_simple_px to configure by pixels\n\t// rather than characters.\n\t// The first parameter is the path to the font files.\n\t// The second and third parameters specify the desired console size in screen characters (80x25).\n\t// The fourth parameter is the window title.\n\t// The final parameter says that we'd like the default console to use an 8x16 VGA font. Not so great for games, but easy to read!\n\tinit(config_simple(\"../assets\", 80, 25, \"RLTK Hello World\", \"8x16\"));\n\n\t// Enter the main loop. \"tick\" is the function we wrote above.\n\trun(tick);\n\n    return 0;\n}\n"
  },
  {
    "path": "examples/ex2/main.cpp",
    "content": "/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed under the MIT license - see LICENSE file.\n *\n * Example 2: A wandering @ dude, demonstrating the random number generator,\n * character rendering, directed screen clearing, and frame-rate independent\n * tick lengths.\n */\n\n// You need to include the RLTK header\n#include \"../../rltk/rltk.hpp\"\n\n// For convenience, import the whole rltk namespace. You may not want to do this\n// in larger projects, to avoid naming collisions.\nusing namespace rltk;\nusing namespace rltk::colors;\n\n// For now, we always want our \"dude\" to be a yellow @ - so he's constexpr\nconst vchar dude{'@', YELLOW, BLACK};\n// The dude's location in X/Y terms\nint dude_x = 10;\nint dude_y = 10;\n\n// A default-defined random number generator. You can specify a seed to get\n// the same results each time, but for now we're keeping it simple.\nrandom_number_generator rng;\n\n// We want to keep the game running at a steady pace, rather than however\n// fast our super graphics card wants to go! To do this, we set a constant\n// duration for a \"tick\" and only process after that much time has elapsed.\n// Most roguelikes are turn-based and won't actually use this, but that's\n// for a later example when we get to input.\nconstexpr double tick_duration = 5.0;\ndouble tick_time = 0.0;\n\n// Tick is called every frame. The parameter specifies how many ms have elapsed\n// since the last time it was called.\nvoid tick(double duration_ms) {\n\t// Rather than clearing the screen to black, we set it to all white dots. We only want\n\t// to do this if something has forced the screen to re-render (such as re-sizing)\n\tif (console->dirty) console->clear(vchar{'.', GREY, BLACK});\n\n\t// Increase the tick time by the frame duration. If it has exceeded\n\t// the tick duration, then we move the @.\n\ttick_time += duration_ms;\n\tif (tick_time > tick_duration) {\n\n\t\t// Using the RNG's handy roll_dice function, we roll 1d4. Each option\n\t\t// represents a possible move in this case. The function is just like D&D's\n\t\t// venerable XdY system - you can roll 10d12 with roll_dice(10,12). You\n\t\t// aren't limited to dice sizes that exist or make sense.\n\t\tint direction = rng.roll_dice(1,4);\n\t\tswitch (direction) {\n\t\t\tcase 1 : --dude_x; break;\n\t\t\tcase 2 : ++dude_x; break;\n\t\t\tcase 3 : --dude_y; break;\n\t\t\tcase 4 : ++dude_y; break;\n\t\t}\n\n\t\t// Important: we clear the tick count after the update.\n\t\ttick_time = 0.0;\n\n\t\t// Clear the console, which has the nice side effect of setting the terminal\n\t\t// to dirty.\n\t\tconsole->clear(vchar{'.', GREY, BLACK});\n\t\t// Clipping: keep the dude on the screen. Why are we doing this here, and not\n\t\t// after an update? For now, we aren't handling the concept of a map that is larger\n\t\t// than the screen - so if the window resizes, the @ gets clipped to a visible area.\n\t\tif (dude_x < 0) dude_x = 0;\n\t\tif (dude_x > console->term_width) dude_x = console->term_width;\n\t\tif (dude_y < 0) dude_y = 0;\n\t\tif (dude_y > console->term_height) dude_x = console->term_height;\n\n\t\t// Finally, we render the @ symbol. dude_x and dude_y are in terminal coordinates.\n\t\tconsole->set_char(console->at(dude_x, dude_y), dude);\n\t}\n}\n\n// Your main function\nint main()\n{\n\t// Initialize with defaults.\n\tinit(config_simple_px(\"../assets\"));\n\n\t// Enter the main loop. \"tick\" is the function we wrote above.\n\trun(tick);\n\n    return 0;\n}\n"
  },
  {
    "path": "examples/ex3/main.cpp",
    "content": "/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed under the MIT license - see LICENSE file.\n *\n * Example 3: A wandering @ dude, this time using Bresenham's line functions to\n * plot his path through the world. We play around a bit, rendering the destination\n * and path as well as the simple \"world\" our little @ lives in.\n */\n\n// You need to include the RLTK header\n#include \"../../rltk/rltk.hpp\"\n\n// We're using a deque to represent our path\n#include <deque>\n\n// For convenience, import the whole rltk namespace. You may not want to do this\n// in larger projects, to avoid naming collisions.\nusing namespace rltk;\nusing namespace rltk::colors;\n\n// For now, we always want our \"dude\" to be a yellow @ - so he's constexpr\nconst vchar dude{'@', YELLOW, BLACK};\n// We're also going to render our destination as a pink heart. Aww.\nconst vchar destination{3, MAGENTA, BLACK};\n// We'll also render our planned path ahead as a series of stars\nconst vchar star{'*', GREEN, BLACK};\n// The dude's location in X/Y terms\nint dude_x = 10;\nint dude_y = 10;\n\n// Where the dude would like to go; we'll start with him being happy where he is.\nint destination_x = 10;\nint destination_y = 10;\n\n// We'll store the path to the goal as a simple queue of x/y (represented as an std::pair of ints).\n// A queue naturally represents the task - each step, in order. A deque has the added property\n// of being iteratable - so we are using it.\nstd::deque<std::pair<int,int>> path;\n\n// A default-defined random number generator. You can specify a seed to get\n// the same results each time, but for now we're keeping it simple.\nrandom_number_generator rng;\n\n// We want to keep the game running at a steady pace, rather than however\n// fast our super graphics card wants to go! To do this, we set a constant\n// duration for a \"tick\" and only process after that much time has elapsed.\n// Most roguelikes are turn-based and won't actually use this, but that's\n// for a later example when we get to input.\n// Note that this is faster than previous examples; I liked it better that way!\nconstexpr double tick_duration = 5.0;\ndouble tick_time = 0.0;\n\n// Tick is called every frame. The parameter specifies how many ms have elapsed\n// since the last time it was called.\nvoid tick(double duration_ms) {\n\t// Rather than clearing the screen to black, we set it to all white dots.\n\tconsole->clear(vchar{'.', GREY, BLACK});\n\n\t// Increase the tick time by the frame duration. If it has exceeded\n\t// the tick duration, then we move the @.\n\ttick_time += duration_ms;\n\tif (tick_time > tick_duration) {\n\n\t\t// If we're at our destination, we need a new one!\n\t\tif ((destination_x == dude_x && destination_y == dude_y) || path.empty()) {\n\t\t\t// We use the RNG to determine where we want to go\n\t\t\tdestination_x = rng.roll_dice(1, console->term_width)-1;\n\t\t\tdestination_y = rng.roll_dice(1, console->term_height)-1;\n\t\t\t\n\t\t\t// Now we use \"line_func\". The prototype for this is:\n\t\t\t// void line_func(int x1, int y1, const int x2, const int y2, std::function<void(int, int)> func);\n\t\t\t// What this means in practice is line_func(from_x, from_y, to_x, to_y, callback function for each step).\n\t\t\t// We'll use a lambda for the callback, to keep it inline and tight.\n\t\t\tline_func(dude_x, dude_y, destination_x, destination_y, [] (int nx, int ny) {\n\t\t\t\t// Simply add the next step to the path\n\t\t\t\tpath.push_back(std::make_pair(nx,ny));\n\t\t\t});\n\t\t} else {\n\t\t\t// We aren't there yet, so we follow our path. We take the first element on the list,\n\t\t\t// and then use pop_back to remove it.\n\t\t\t// std::tie is a handy way to extract two parts of an std::pair (or tuple) in one fell swoop.\n\t\t\tstd::tie(dude_x, dude_y) = path.front();\n\t\t\tpath.pop_front();\n\t\t}\n\n\n\t\t// Important: we clear the tick count after the update.\n\t\ttick_time = 0.0;\n\t}\n\n\t// Clipping: keep the dude on the screen. Why are we doing this here, and not\n\t// after an update? For now, we aren't handling the concept of a map that is larger\n\t// than the screen - so if the window resizes, the @ gets clipped to a visible area.\n\tif (dude_x < 0) dude_x = 0;\n\tif (dude_x > console->term_width) dude_x = console->term_width;\n\tif (dude_y < 0) dude_y = 0;\n\tif (dude_y > console->term_height) dude_x = console->term_height;\n\n\t// Render our planned path. We're using auto and a range-for to avoid typing all\n\t// the iterator stuff\n\tfor (auto step : path) {\n\t\tconsole->set_char(console->at(step.first, step.second), star);\n\t}\n\n\t// Render our destination\n\tconsole->set_char(console->at(destination_x, destination_y), destination);\n\t// Finally, we render the @ symbol. dude_x and dude_y are in terminal coordinates.\n\tconsole->set_char(console->at(dude_x, dude_y), dude);\n}\n\n// Your main function\nint main()\n{\n\t// Initialize with defaults.\n\tinit(config_simple_px(\"../assets\"));\n\n\t// Enter the main loop. \"tick\" is the function we wrote above.\n\trun(tick);\n\n    return 0;\n}\n"
  },
  {
    "path": "examples/ex4/main.cpp",
    "content": "#include <iostream>\n/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed under the MIT license - see LICENSE file.\n *\n * Example 4: Now we implement a basic map, and use A* to find our way around it.\n * This example is a bit more in-depth, since it demonstrates the library's ability\n * to use templates to specialize itself around your map design - we won't force a\n * map type on you!\n */\n\n// You need to include the RLTK header\n#include \"../../rltk/rltk.hpp\"\n\n// We're using a vector to represent the map\n#include <vector>\n\n// We're also going to be using a shared_ptr to a map. Why shared? Because the library\n// hands it off to you and it's up to you to use it; this provides some safety that it\n// will be disposed when you are done with it.\n#include <memory>\n\n// For convenience, import the whole rltk namespace. You may not want to do this\n// in larger projects, to avoid naming collisions.\nusing namespace rltk;\nusing namespace rltk::colors;\n\n// A default-defined random number generator. You can specify a seed to get\n// the same results each time, but for now we're keeping it simple.\nrandom_number_generator rng;\n\n// For now, we always want our \"dude\" to be a yellow @ - so he's constexpr\nconst vchar dude{'@', YELLOW, BLACK};\n// We're also going to render our destination as a pink heart. Aww.\nconst vchar destination_glyph{3, MAGENTA, BLACK};\n// We now need to represent walls and floors, too\nconst vchar wall_tile{'#', WHITE, BLACK};\nconst vchar floor_tile{'.', GREY, BLACK}; // Note that \"floor\" is taken as a name in C++!\n\n// Now we define a structure to represent a location. In this case, it's a simple\n// x/y coordinate.\nstruct location_t {\n\tint x=-1; // I like to set uninitialized values to something invalid for help with debugging\n\tint y=-1;\n\n\t// For convenience, we're overriding the quality operator. This gives a very\n\t// quick and natural looking way to say \"are these locations the same?\"\n\tbool operator==(location_t &rhs) { return (x==rhs.x && y==rhs.y); }\n\n\tlocation_t() {}\n\tlocation_t(const int X, const int Y) : x(X), y(Y) {}\n};\n\n// Now we define our basic map. Why a struct? Because a struct is just a class with\n// everything public in it!\nstruct map_t {\n\tmap_t(const int &w, const int &h) : width(w), height(h) {\n\t\t// Resize the vector to hold the whole map; this way it won't reallocate\n\t\twalkable.resize(w*h);\n\n\t\t// Set the entire map to walkable\n\t\tstd::fill(walkable.begin(), walkable.end(), true);\n\n\t\t// We want the perimeter to be solid\n\t\tfor (int x=0; x<width; ++x) { \n\t\t\twalkable[at(x,0)]=false;\n\t\t\twalkable[at(x,height-1)]=false;\n\t\t}\n\t\tfor (int y=0; y<height; ++y) {\n\t\t\twalkable[at(0,y)] = false;\n\t\t\twalkable[at(width-1,y)] = false;\n\t\t}\n\n\t\t// Every tile other than 10,10 (starting) has a 16% chance of being solid\t\t\n\t\tfor (int y=1; y<height-2; ++y) {\n\t\t\tfor (int x=1; x<width-2; ++x) {\n\t\t\t\tif ((x != 10 && y != 10) && rng.roll_dice(1,6)==1) walkable[at(x,y)] = false;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Calculate the vector offset of a grid location\n\tinline int at(const int &x, const int &y) { return (y*width)+x; }\n\n\t// The width and height of the map\n\tconst int width, height;\n\n\t// The actual walkable storage vector\n\tstd::vector<bool> walkable;\n};\n\n// The A* library returns a navigation path with a template specialization to our location_t.\n// Store the path here. Normally, you'd use \"auto\" for this type, it is a lot less typing!\nstd::shared_ptr<navigation_path<location_t>> path;\n\n// We're using 1024x768, with 8 pixel wide chars. That gives a console grid of\n// 128 x 96. We'll go with that for the map, even though in reality the screen\n// might change. Worrying about that is for a future example!\nconstexpr int MAP_WIDTH = 128;\nconstexpr int MAP_HEIGHT = 96;\nmap_t map(MAP_WIDTH, MAP_HEIGHT);\n\n// Instead of raw ints, we'll use the location structure to represent where our\n// dude is. Using C++14 initialization, it's nice and clean.\nlocation_t dude_position {10,10};\n\n// We'll also use a location_t to represent the intended destination.\nlocation_t destination {10,10};\n\n// The A* library also requires a helper class to understand your map format.\nstruct navigator {\n\t// This lets you define a distance heuristic. Manhattan distance works really well, but\n\t// for now we'll just use a simple euclidian distance squared.\n\t// The geometry system defines one for us.\n\tstatic float get_distance_estimate(location_t &pos, location_t &goal) {\n\t\tfloat d = distance2d_squared(pos.x, pos.y, goal.x, goal.y);\n\t\treturn d;\n\t}\n\n\t// Heuristic to determine if we've reached our destination? In some cases, you'd not want\n\t// this to be a simple comparison with the goal - for example, if you just want to be\n\t// adjacent to (or even a preferred distance from) the goal. In this case, \n\t// we're trying to get to the goal rather than near it.\n\tstatic bool is_goal(location_t &pos, location_t &goal) {\n\t\treturn pos == goal;\n\t}\n\n\t// This is where we calculate where you can go from a given tile. In this case, we check\n\t// all 8 directions, and if the destination is walkable return it as an option.\n\tstatic bool get_successors(location_t pos, std::vector<location_t> &successors) {\n\t\t//std::cout << pos.x << \"/\" << pos.y << \"\\n\";\n\n\t\tif (map.walkable[map.at(pos.x-1, pos.y-1)]) successors.push_back(location_t(pos.x-1, pos.y-1));\n\t\tif (map.walkable[map.at(pos.x, pos.y-1)]) successors.push_back(location_t(pos.x, pos.y-1));\n\t\tif (map.walkable[map.at(pos.x+1, pos.y-1)]) successors.push_back(location_t(pos.x+1, pos.y-1));\n\n\t\tif (map.walkable[map.at(pos.x-1, pos.y)]) successors.push_back(location_t(pos.x-1, pos.y));\n\t\tif (map.walkable[map.at(pos.x+1, pos.y)]) successors.push_back(location_t(pos.x+1, pos.y));\n\n\t\tif (map.walkable[map.at(pos.x-1, pos.y+1)]) successors.push_back(location_t(pos.x-1, pos.y+1));\n\t\tif (map.walkable[map.at(pos.x, pos.y+1)]) successors.push_back(location_t(pos.x, pos.y+1));\n\t\tif (map.walkable[map.at(pos.x+1, pos.y+1)]) successors.push_back(location_t(pos.x+1, pos.y+1));\n\t\treturn true;\n\t}\n\n\t// This function lets you set a cost on a tile transition. For now, we'll always use a cost of 1.0.\n\tstatic float get_cost(location_t &position, location_t &successor) {\n\t\treturn 1.0f;\n\t}\n\n\t// This is a simple comparison to determine if two locations are the same. It just passes\n\t// through to the location_t's equality operator in this instance (we didn't do that automatically)\n\t// because there are times you might want to behave differently.\n\tstatic bool is_same_state(location_t &lhs, location_t &rhs) {\n\t\treturn lhs == rhs;\n\t}\n};\n\n// Lets go really fast!\nconstexpr double tick_duration = 1.0;\ndouble tick_time = 0.0;\n\n// Tick is called every frame. The parameter specifies how many ms have elapsed\n// since the last time it was called.\nvoid tick(double duration_ms) {\n\t// Iterate over the whole map, rendering as appropriate\n\tfor (int y=0; y<MAP_HEIGHT; ++y) {\n\t\tfor (int x=0; x<MAP_WIDTH; ++x) {\n\t\t\tif (map.walkable[map.at(x,y)]) {\n\t\t\t\tconsole->set_char(console->at(x,y), floor_tile);\n\t\t\t} else {\n\t\t\t\tconsole->set_char(console->at(x,y), wall_tile);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Increase the tick time by the frame duration. If it has exceeded\n\t// the tick duration, then we move the @.\n\ttick_time += duration_ms;\n\tif (tick_time > tick_duration) {\n\t\t// Are we there yet?\n\t\tif (dude_position == destination) {\n\t\t\t// We are there! We need to pick a new destination.\n\t\t\tdestination.x = rng.roll_dice(1, MAP_WIDTH-1);\n\t\t\tdestination.y = rng.roll_dice(1, MAP_HEIGHT-1);\n\t\t\t\n\t\t\t// Lets make sure that the destination is walkable\n\t\t\twhile (map.walkable[map.at(destination.x,destination.y)] == false) {\n\t\t\t\tdestination.x = rng.roll_dice(1, MAP_WIDTH-1);\n\t\t\t\tdestination.y = rng.roll_dice(1, MAP_HEIGHT-1);\n\t\t\t}\n\n\t\t\t// Now determine how to get there\n\t\t\tif (path) path.reset();\n\t\t\tpath = find_path<location_t, navigator>(dude_position, destination);\n\t\t\tif (!path->success) {\n\t\t\t\tdestination = dude_position;\n\t\t\t\tstd::cout << \"RESET: THIS ISN'T MEANT TO HAPPEN!\\n\";\n\t\t\t}\n\t\t} else {\n\t\t\t// Follow the breadcrumbs!\n\t\t\tlocation_t next_step = path->steps.front();\n\t\t\tdude_position.x = next_step.x;\n\t\t\tdude_position.y = next_step.y;\n\t\t\tpath->steps.pop_front();\n\t\t}\n\n\t\t// Important: we clear the tick count after the update.\n\t\ttick_time = 0.0;\n\t}\n\n\t// Render our planned path. We're using auto and a range-for to avoid typing all\n\t// the iterator stuff\n\tif (path) {\n\t\t// We're going to show off a bit and \"lerp\" the color along the path; the red\n\t\t// lightens as it approaches the destination. This is a preview of some of the\n\t\t// color functions.\n\t\tconst float n_steps = static_cast<float>(path->steps.size());\n\t\tfloat i = 0;\n\t\tfor (auto step : path->steps) {\n\t\t\tconst float lerp_amount = i / n_steps;\n\t\t\tvchar highlight{ 177, lerp(DARK_GREEN, LIGHTEST_GREEN, lerp_amount), BLACK };\n\t\t\tconsole->set_char(console->at(step.x, step.y), highlight);\n\t\t\t++i;\n\t\t}\n\t}\n\n\t// Render our destination\n\tconsole->set_char(console->at(destination.x, destination.y), destination_glyph);\n\n\t// Finally, we render the @ symbol. dude_x and dude_y are in terminal coordinates.\n\tconsole->set_char(console->at(dude_position.x, dude_position.y), dude);\n}\n\n// Your main function\nint main()\n{\n\t// Initialize with defaults\n\tinit(config_simple_px(\"../assets\"));\n\n\t// Enter the main loop. \"tick\" is the function we wrote above.\n\trun(tick);\n\n    return 0;\n}\n"
  },
  {
    "path": "examples/ex5/main.cpp",
    "content": "#include <iostream>\n/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed under the MIT license - see LICENSE file.\n *\n * Example 5: Extend example 4 to use the mouse to guide player movement.\n */\n\n// You need to include the RLTK header\n#include \"../../rltk/rltk.hpp\"\n\n// We're using a vector to represent the map\n#include <vector>\n\n// We're also going to be using a shared_ptr to a map. Why shared? Because the library\n// hands it off to you and it's up to you to use it; this provides some safety that it\n// will be disposed when you are done with it.\n#include <memory>\n\n// For convenience, import the whole rltk namespace. You may not want to do this\n// in larger projects, to avoid naming collisions.\nusing namespace rltk;\nusing namespace rltk::colors;\n\n// A default-defined random number generator. You can specify a seed to get\n// the same results each time, but for now we're keeping it simple.\nrandom_number_generator rng;\n\n// For now, we always want our \"dude\" to be a yellow @ - so he's constexpr\nconst vchar dude{'@', YELLOW, BLACK};\n// We're also going to render our destination as a pink heart. Aww.\nconst vchar destination_glyph{3, MAGENTA, BLACK};\n// We now need to represent walls and floors, too\nconst vchar wall_tile{'#', WHITE, BLACK};\nconst vchar floor_tile{'.', GREY, BLACK}; // Note that \"floor\" is taken as a name in C++!\n\n// Now we define a structure to represent a location. In this case, it's a simple\n// x/y coordinate.\nstruct location_t {\n\tint x=-1; // I like to set uninitialized values to something invalid for help with debugging\n\tint y=-1;\n\n\t// For convenience, we're overriding the quality operator. This gives a very\n\t// quick and natural looking way to say \"are these locations the same?\"\n\tbool operator==(location_t &rhs) { return (x==rhs.x && y==rhs.y); }\n\n\tlocation_t() {}\n\tlocation_t(const int X, const int Y) : x(X), y(Y) {}\n};\n\n// Now we define our basic map. Why a struct? Because a struct is just a class with\n// everything public in it!\nstruct map_t {\n\tmap_t(const int &w, const int &h) : width(w), height(h) {\n\t\t// Resize the vector to hold the whole map; this way it won't reallocate\n\t\twalkable.resize(w*h);\n\n\t\t// Set the entire map to walkable\n\t\tstd::fill(walkable.begin(), walkable.end(), true);\n\n\t\t// We want the perimeter to be solid\n\t\tfor (int x=0; x<width; ++x) { \n\t\t\twalkable[at(x,0)]=false;\n\t\t\twalkable[at(x,height-1)]=false;\n\t\t}\n\t\tfor (int y=0; y<height; ++y) {\n\t\t\twalkable[at(0,y)] = false;\n\t\t\twalkable[at(width-1,y)] = false;\n\t\t}\n\n\t\t// Every tile other than 10,10 (starting) has a 33% chance of being solid. We've\n\t\t// made it more likely to have obstacles, since we're no longer relying on the RNG\n\t\t// to find our way.\t\n\t\tfor (int y=1; y<height-2; ++y) {\n\t\t\tfor (int x=1; x<width-2; ++x) {\n\t\t\t\tif (rng.roll_dice(1,3)==1) walkable[at(x,y)] = false;\n\t\t\t}\n\t\t}\n\t\twalkable[at(10,10)] = true;\n\t}\n\n\t// Calculate the vector offset of a grid location\n\tinline int at(const int &x, const int &y) { return (y*width)+x; }\n\n\t// The width and height of the map\n\tconst int width, height;\n\n\t// The actual walkable storage vector\n\tstd::vector<bool> walkable;\n};\n\n// The A* library returns a navigation path with a template specialization to our location_t.\n// Store the path here. Normally, you'd use \"auto\" for this type, it is a lot less typing!\nstd::shared_ptr<navigation_path<location_t>> path;\n\n// We're using 1024x768, with 8 pixel wide chars. That gives a console grid of\n// 128 x 96. We'll go with that for the map, even though in reality the screen\n// might change. Worrying about that is for a future example!\nconstexpr int MAP_WIDTH = 128;\nconstexpr int MAP_HEIGHT = 96;\nmap_t map(MAP_WIDTH, MAP_HEIGHT);\n\n// Instead of raw ints, we'll use the location structure to represent where our\n// dude is. Using C++14 initialization, it's nice and clean.\nlocation_t dude_position {10,10};\n\n// We'll also use a location_t to represent the intended destination.\nlocation_t destination {10,10};\n\n// The A* library also requires a helper class to understand your map format.\nstruct navigator {\n\t// This lets you define a distance heuristic. Manhattan distance works really well, but\n\t// for now we'll just use a simple euclidian distance squared.\n\t// The geometry system defines one for us.\n\tstatic float get_distance_estimate(location_t &pos, location_t &goal) {\n\t\tfloat d = distance2d_squared(pos.x, pos.y, goal.x, goal.y);\n\t\treturn d;\n\t}\n\n\t// Heuristic to determine if we've reached our destination? In some cases, you'd not want\n\t// this to be a simple comparison with the goal - for example, if you just want to be\n\t// adjacent to (or even a preferred distance from) the goal. In this case, \n\t// we're trying to get to the goal rather than near it.\n\tstatic bool is_goal(location_t &pos, location_t &goal) {\n\t\treturn pos == goal;\n\t}\n\n\t// This is where we calculate where you can go from a given tile. In this case, we check\n\t// all 8 directions, and if the destination is walkable return it as an option.\n\tstatic bool get_successors(location_t pos, std::vector<location_t> &successors) {\n\t\t//std::cout << pos.x << \"/\" << pos.y << \"\\n\";\n\n\t\tif (map.walkable[map.at(pos.x-1, pos.y-1)]) successors.push_back(location_t(pos.x-1, pos.y-1));\n\t\tif (map.walkable[map.at(pos.x, pos.y-1)]) successors.push_back(location_t(pos.x, pos.y-1));\n\t\tif (map.walkable[map.at(pos.x+1, pos.y-1)]) successors.push_back(location_t(pos.x+1, pos.y-1));\n\n\t\tif (map.walkable[map.at(pos.x-1, pos.y)]) successors.push_back(location_t(pos.x-1, pos.y));\n\t\tif (map.walkable[map.at(pos.x+1, pos.y)]) successors.push_back(location_t(pos.x+1, pos.y));\n\n\t\tif (map.walkable[map.at(pos.x-1, pos.y+1)]) successors.push_back(location_t(pos.x-1, pos.y+1));\n\t\tif (map.walkable[map.at(pos.x, pos.y+1)]) successors.push_back(location_t(pos.x, pos.y+1));\n\t\tif (map.walkable[map.at(pos.x+1, pos.y+1)]) successors.push_back(location_t(pos.x+1, pos.y+1));\n\t\treturn true;\n\t}\n\n\t// This function lets you set a cost on a tile transition. For now, we'll always use a cost of 1.0.\n\tstatic float get_cost(location_t &position, location_t &successor) {\n\t\treturn 1.0f;\n\t}\n\n\t// This is a simple comparison to determine if two locations are the same. It just passes\n\t// through to the location_t's equality operator in this instance (we didn't do that automatically)\n\t// because there are times you might want to behave differently.\n\tstatic bool is_same_state(location_t &lhs, location_t &rhs) {\n\t\treturn lhs == rhs;\n\t}\n};\n\n// Lets go really fast!\nconstexpr double tick_duration = 1.0;\ndouble tick_time = 0.0;\n\n// Tick is called every frame. The parameter specifies how many ms have elapsed\n// since the last time it was called.\nvoid tick(double duration_ms) {\n\t// Iterate over the whole map, rendering as appropriate\n\tfor (int y=0; y<MAP_HEIGHT; ++y) {\n\t\tfor (int x=0; x<MAP_WIDTH; ++x) {\n\t\t\tif (map.walkable[map.at(x,y)]) {\n\t\t\t\tconsole->set_char(console->at(x,y), floor_tile);\n\t\t\t} else {\n\t\t\t\tconsole->set_char(console->at(x,y), wall_tile);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Increase the tick time by the frame duration. If it has exceeded\n\t// the tick duration, then we move the @.\n\ttick_time += duration_ms;\n\tif (tick_time > tick_duration) {\n\t\t// Are we there yet?\n\t\tif (dude_position == destination) {\n\t\t\t// Now we poll the mouse to determine where we want to go\n\t\t\tint mouse_x, mouse_y;\n\t\t\tstd::tie(mouse_x, mouse_y) = get_mouse_position();\n\t\t\tconst int terminal_x = mouse_x / 8;\n\t\t\tconst int terminal_y = mouse_y / 8;\n\n\t\t\tconst bool walkable = map.walkable[map.at(terminal_x, terminal_y)]; \n\t\t\tif (walkable && get_mouse_button_state(rltk::button::LEFT)) {\n\t\t\t\tdestination.x = terminal_x;\n\t\t\t\tdestination.y = terminal_y;\n\n\t\t\t\t// Now determine how to get there\n\t\t\t\tif (path) path.reset();\n\t\t\t\tpath = find_path<location_t, navigator>(dude_position, destination);\n\t\t\t\tif (!path->success) {\n\t\t\t\t\tdestination = dude_position;\n\t\t\t\t\tstd::cout << \"RESET: THIS ISN'T MEANT TO HAPPEN!\\n\";\n\t\t\t\t}\n\t\t\t} else if (walkable) {\n\t\t\t\tif (path) path.reset();\n\t\t\t\tpath = find_path<location_t, navigator>(dude_position, location_t{terminal_x, terminal_y});\n\t\t\t}\n\t\t} else {\n\t\t\t// Follow the breadcrumbs!\n\t\t\tif (path) {\n\t\t\t\tlocation_t next_step = path->steps.front();\n\t\t\t\tdude_position.x = next_step.x;\n\t\t\t\tdude_position.y = next_step.y;\n\t\t\t\tpath->steps.pop_front();\n\t\t\t}\n\t\t}\n\n\t\t// Important: we clear the tick count after the update.\n\t\ttick_time = 0.0;\n\t}\n\n\t// Render our planned path. We're using auto and a range-for to avoid typing all\n\t// the iterator stuff\n\tif (path) {\n\t\t// We're going to show off a bit and \"lerp\" the color along the path; the red\n\t\t// lightens as it approaches the destination. This is a preview of some of the\n\t\t// color functions.\n\t\tconst float n_steps = static_cast<float>(path->steps.size());\n\t\tfloat i = 0;\n\t\tfor (auto step : path->steps) {\n\t\t\tconst float lerp_amount = i / n_steps;\n\t\t\tvchar highlight;\n\t\t\tif (dude_position == destination) {\n\t\t\t\thighlight = { 177, lerp(DARK_GREEN, LIGHTEST_GREEN, lerp_amount), BLACK };\n\t\t\t} else {\n\t\t\t\thighlight = { 177, lerp(DARK_RED, LIGHTEST_RED, lerp_amount), BLACK };\t\t\t\t\n\t\t\t}\n\t\t\tconsole->set_char(console->at(step.x, step.y), highlight);\n\t\t\t++i;\n\t\t}\n\t}\n\n\t// Render our destination\n\tconsole->set_char(console->at(destination.x, destination.y), destination_glyph);\n\n\t// Finally, we render the @ symbol. dude_x and dude_y are in terminal coordinates.\n\tconsole->set_char(console->at(dude_position.x, dude_position.y), dude);\n}\n\n// Your main function\nint main()\n{\n\t// Initialize with defaults\n\tinit(config_simple_px(\"../assets\"));\n\n\t// Enter the main loop. \"tick\" is the function we wrote above.\n\trun(tick);\n\n    return 0;\n}\n"
  },
  {
    "path": "examples/ex6/main.cpp",
    "content": "#include <iostream>\n/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed under the MIT license - see LICENSE file.\n *\n * Example 6: Extend example 5 to include visibility and map revealed status.\n */\n\n// You need to include the RLTK header\n#include \"../../rltk/rltk.hpp\"\n\n// We're using a vector to represent the map\n#include <vector>\n\n// We're also going to be using a shared_ptr to a map. Why shared? Because the library\n// hands it off to you and it's up to you to use it; this provides some safety that it\n// will be disposed when you are done with it.\n#include <memory>\n\n// For convenience, import the whole rltk namespace. You may not want to do this\n// in larger projects, to avoid naming collisions.\nusing namespace rltk;\nusing namespace rltk::colors;\n\n// A default-defined random number generator. You can specify a seed to get\n// the same results each time, but for now we're keeping it simple.\nrandom_number_generator rng;\n\n// For now, we always want our \"dude\" to be a yellow @ - so he's constexpr\nconst vchar dude{'@', YELLOW, BLACK};\n// We're also going to render our destination as a pink heart. Aww.\nconst vchar destination_glyph{3, MAGENTA, BLACK};\n\n// Now we define a structure to represent a location. In this case, it's a simple\n// x/y coordinate.\nstruct location_t {\n\tint x=-1; // I like to set uninitialized values to something invalid for help with debugging\n\tint y=-1;\n\n\t// For convenience, we're overriding the quality operator. This gives a very\n\t// quick and natural looking way to say \"are these locations the same?\"\n\tbool operator==(location_t &rhs) { return (x==rhs.x && y==rhs.y); }\n\n\tlocation_t() {}\n\tlocation_t(const int X, const int Y) : x(X), y(Y) {}\n};\n\n// Now we define our basic map. Why a struct? Because a struct is just a class with\n// everything public in it!\nstruct map_t {\n\tmap_t(const int &w, const int &h) : width(w), height(h) {\n\t\t// Resize the vectors to hold the whole map; this way it won't reallocate\n\t\twalkable.resize(w*h);\n\t\trevealed.resize(w*h);\n\t\tvisible.resize(w*h);\n\n\t\t// Set the entire map to walkable, not visible and not revealed\n\t\tstd::fill(walkable.begin(), walkable.end(), true);\n\t\tstd::fill(revealed.begin(), revealed.end(), false);\n\t\tstd::fill(visible.begin(), visible.end(), false);\n\n\t\t// We want the perimeter to be solid\n\t\tfor (int x=0; x<width; ++x) { \n\t\t\twalkable[at(x,0)]=false;\n\t\t\twalkable[at(x,height-1)]=false;\n\t\t}\n\t\tfor (int y=0; y<height; ++y) {\n\t\t\twalkable[at(0,y)] = false;\n\t\t\twalkable[at(width-1,y)] = false;\n\t\t}\n\n\t\t// Every tile other than 10,10 (starting) has a 33% chance of being solid. We've\n\t\t// made it more likely to have obstacles, since we're no longer relying on the RNG\n\t\t// to find our way.\t\n\t\tfor (int y=1; y<height-2; ++y) {\n\t\t\tfor (int x=1; x<width-2; ++x) {\n\t\t\t\tif (rng.roll_dice(1,3)==1) walkable[at(x,y)] = false;\n\t\t\t}\n\t\t}\n\t\twalkable[at(10,10)]=true;\n\t}\n\n\t// Calculate the vector offset of a grid location\n\tinline int at(const int &x, const int &y) { return (y*width)+x; }\n\n\t// The width and height of the map\n\tconst int width, height;\n\n\t// The actual walkable storage vector\n\tstd::vector<bool> walkable;\n\n\t// Revealed: has a tile been shown yet?\n\tstd::vector<bool> revealed;\n\n\t// Visible: is a tile currently visible?\n\tstd::vector<bool> visible;\n};\n\n// The A* library returns a navigation path with a template specialization to our location_t.\n// Store the path here. Normally, you'd use \"auto\" for this type, it is a lot less typing!\nstd::shared_ptr<navigation_path<location_t>> path;\n\n// We're using 1024x768, with 8 pixel wide chars. That gives a console grid of\n// 128 x 96. We'll go with that for the map, even though in reality the screen\n// might change. Worrying about that is for a future example!\nconstexpr int MAP_WIDTH = 128;\nconstexpr int MAP_HEIGHT = 96;\nmap_t map(MAP_WIDTH, MAP_HEIGHT);\n\n// Instead of raw ints, we'll use the location structure to represent where our\n// dude is. Using C++14 initialization, it's nice and clean.\nlocation_t dude_position {10,10};\n\n// We'll also use a location_t to represent the intended destination.\nlocation_t destination {10,10};\n\n// The A* library also requires a helper class to understand your map format.\nstruct navigator {\n\t// This lets you define a distance heuristic. Manhattan distance works really well, but\n\t// for now we'll just use a simple euclidian distance squared.\n\t// The geometry system defines one for us.\n\tstatic float get_distance_estimate(location_t &pos, location_t &goal) {\n\t\tfloat d = distance2d_squared(pos.x, pos.y, goal.x, goal.y);\n\t\treturn d;\n\t}\n\n\t// Heuristic to determine if we've reached our destination? In some cases, you'd not want\n\t// this to be a simple comparison with the goal - for example, if you just want to be\n\t// adjacent to (or even a preferred distance from) the goal. In this case, \n\t// we're trying to get to the goal rather than near it.\n\tstatic bool is_goal(location_t &pos, location_t &goal) {\n\t\treturn pos == goal;\n\t}\n\n\t// This is where we calculate where you can go from a given tile. In this case, we check\n\t// all 8 directions, and if the destination is walkable return it as an option.\n\tstatic bool get_successors(location_t pos, std::vector<location_t> &successors) {\n\t\t//std::cout << pos.x << \"/\" << pos.y << \"\\n\";\n\n\t\tif (map.walkable[map.at(pos.x-1, pos.y-1)]) successors.push_back(location_t(pos.x-1, pos.y-1));\n\t\tif (map.walkable[map.at(pos.x, pos.y-1)]) successors.push_back(location_t(pos.x, pos.y-1));\n\t\tif (map.walkable[map.at(pos.x+1, pos.y-1)]) successors.push_back(location_t(pos.x+1, pos.y-1));\n\n\t\tif (map.walkable[map.at(pos.x-1, pos.y)]) successors.push_back(location_t(pos.x-1, pos.y));\n\t\tif (map.walkable[map.at(pos.x+1, pos.y)]) successors.push_back(location_t(pos.x+1, pos.y));\n\n\t\tif (map.walkable[map.at(pos.x-1, pos.y+1)]) successors.push_back(location_t(pos.x-1, pos.y+1));\n\t\tif (map.walkable[map.at(pos.x, pos.y+1)]) successors.push_back(location_t(pos.x, pos.y+1));\n\t\tif (map.walkable[map.at(pos.x+1, pos.y+1)]) successors.push_back(location_t(pos.x+1, pos.y+1));\n\t\treturn true;\n\t}\n\n\t// This function lets you set a cost on a tile transition. For now, we'll always use a cost of 1.0.\n\tstatic float get_cost(location_t &position, location_t &successor) {\n\t\treturn 1.0f;\n\t}\n\n\t// This is a simple comparison to determine if two locations are the same. It just passes\n\t// through to the location_t's equality operator in this instance (we didn't do that automatically)\n\t// because there are times you might want to behave differently.\n\tstatic bool is_same_state(location_t &lhs, location_t &rhs) {\n\t\treturn lhs == rhs;\n\t}\n\n\t// We're using the Bresneham's line optimization for pathing this time, which requires a few extra\n\t// static methods. These are designed to translate between your map format and co-ordinates used by\n\t// the library (we don't want to force you to structure things a certain way).\n\tstatic int get_x(const location_t &loc) { return loc.x; }\n\tstatic int get_y(const location_t &loc) { return loc.y; }\n\tstatic location_t get_xy(const int &x, const int &y) { return location_t{x,y}; }\n\tstatic bool is_walkable(const location_t &loc) { return map.walkable[map.at(loc.x, loc.y)]; }\n};\n\n// Lets go really fast!\nconstexpr double tick_duration = 0.0;\ndouble tick_time = 0.0;\n\n// Helper function: calls the RLTK visibility sweep 2D algorithm with lambdas to\n// assist in understanding our map format.\ninline void visibility_sweep() {\n\tvisibility_sweep_2d<location_t, navigator>(dude_position, 10, \n\t\t[] (location_t reveal) { \n\t\t\tmap.revealed[map.at(reveal.x, reveal.y)] = true;\n\t\t\tmap.visible[map.at(reveal.x, reveal.y)] = true;\n\t\t},\n\t\t[] (auto test_visibility) { return map.walkable[map.at(test_visibility.x, test_visibility.y)]; }\n\t);\n}\n\n// Tick is called every frame. The parameter specifies how many ms have elapsed\n// since the last time it was called.\nvoid tick(double duration_ms) {\n\t// Iterate over the whole map, rendering as appropriate\n\tfor (int y=0; y<MAP_HEIGHT; ++y) {\n\t\tfor (int x=0; x<MAP_WIDTH; ++x) {\n\t\t\tconst int map_idx = map.at(x,y); // Caching so we don't keep doing the calculation\n\t\t\tif (map.walkable[map_idx]) {\n\t\t\t\tif (map.visible[map_idx]) {\n\t\t\t\t\t// Visible tile: render full color\n\t\t\t\t\tconsole->set_char(map_idx, vchar{'.', GREEN, BLACK});\n\t\t\t\t} else if (map.revealed[map_idx]) {\n\t\t\t\t\t// Revealed tile: render grey\n\t\t\t\t\tconsole->set_char(map_idx, vchar{'.', LIGHTER_GREY, BLACK});\n\t\t\t\t} else {\n\t\t\t\t\t// We haven't seen it yet - darkest gray\n\t\t\t\t\tconsole->set_char(map_idx, vchar{'.', DARK_GREY, BLACK});\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (map.visible[map_idx]) {\n\t\t\t\t\t// Visible tile: render full color\n\t\t\t\t\tconsole->set_char(map_idx, vchar{'#', CYAN, BLACK});\n\t\t\t\t} else if (map.revealed[map_idx]) {\n\t\t\t\t\t// Revealed tile: render grey\n\t\t\t\t\tconsole->set_char(map_idx, vchar{'#', GREY, BLACK});\n\t\t\t\t} else {\n\t\t\t\t\t// We haven't seen it yet - darkest gray\n\t\t\t\t\tconsole->set_char(map_idx, vchar{'#', DARKER_GREY, BLACK});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Increase the tick time by the frame duration. If it has exceeded\n\t// the tick duration, then we move the @.\n\ttick_time += duration_ms;\n\tif (tick_time > tick_duration) {\n\t\t// Are we there yet?\n\t\tif (dude_position == destination) {\n\t\t\t// Now we poll the mouse to determine where we want to go\n\t\t\t// This requests the mouse position in PIXELS, and ties it into our mouse_x/mouse_y variables.\n\t\t\tint mouse_x, mouse_y;\n\t\t\tstd::tie(mouse_x, mouse_y) = get_mouse_position();\n\n\t\t\t// Since we're using an 8x8, it's just a matter of dividing by 8 to find the terminal-character\n\t\t\t// coordinates. There will be a helper function for this once we get into retained GUIs.\n\t\t\tconst int terminal_x = mouse_x / 8;\n\t\t\tconst int terminal_y = mouse_y / 8;\n\n\t\t\t// If the mouse is pointing at a walkable location, and the left button is down - path to the mouse.\n\t\t\tconst bool walkable = map.walkable[map.at(terminal_x, terminal_y)]; \n\t\t\tif (walkable && get_mouse_button_state(rltk::button::LEFT)) {\n\t\t\t\tdestination.x = terminal_x;\n\t\t\t\tdestination.y = terminal_y;\n\n\t\t\t\t// Now determine how to get there\n\t\t\t\tif (path) path.reset();\n\t\t\t\tpath = find_path<location_t, navigator>(dude_position, destination);\n\t\t\t\tif (!path->success) {\n\t\t\t\t\tdestination = dude_position;\n\t\t\t\t\tstd::cout << \"RESET: THIS ISN'T MEANT TO HAPPEN!\\n\";\n\t\t\t\t}\n\t\t\t} else if (walkable) {\n\t\t\t\t// If the mouse is not clicked, then path to the mouse cursor for display only\n\t\t\t\tif (path) path.reset();\n\t\t\t\tpath = find_path_2d<location_t, navigator>(dude_position, location_t{terminal_x, terminal_y});\n\t\t\t}\n\t\t} else {\n\t\t\t// Follow the breadcrumbs!\n\t\t\tif (path) {\n\t\t\t\tlocation_t next_step = path->steps.front();\n\t\t\t\tdude_position.x = next_step.x;\n\t\t\t\tdude_position.y = next_step.y;\n\t\t\t\tpath->steps.pop_front();\n\n\t\t\t\t// Update the map visibility\n\t\t\t\tstd::fill(map.visible.begin(), map.visible.end(), false);\n\t\t\t\tvisibility_sweep();\n\t\t\t}\n\t\t}\n\n\t\t// Important: we clear the tick count after the update.\n\t\ttick_time = 0.0;\n\t}\n\n\t// Render our planned path. We're using auto and a range-for to avoid typing all\n\t// the iterator stuff\n\tif (path) {\n\t\t// We're going to show off a bit and \"lerp\" the color along the path; the red\n\t\t// lightens as it approaches the destination. This is a preview of some of the\n\t\t// color functions.\n\t\tconst float n_steps = static_cast<float>(path->steps.size());\n\t\tfloat i = 0;\n\t\tfor (auto step : path->steps) {\n\t\t\tconst float lerp_amount = i / n_steps;\n\t\t\tvchar highlight;\n\t\t\t// If we're at our destination, we are showing possible paths - highlight green;\n\t\t\t// otherwise, highlight red to indicate that we are en route.\n\t\t\tif (dude_position == destination) {\n\t\t\t\thighlight = { 177, lerp(DARK_GREEN, LIGHTEST_GREEN, lerp_amount), BLACK };\n\t\t\t} else {\n\t\t\t\thighlight = { 177, lerp(DARK_RED, LIGHTEST_RED, lerp_amount), BLACK };\t\t\t\t\n\t\t\t}\n\t\t\tconsole->set_char(console->at(step.x, step.y), highlight);\n\t\t\t++i;\n\t\t}\n\t}\n\n\t// Render our destination\n\tconsole->set_char(console->at(destination.x, destination.y), destination_glyph);\n\n\t// Finally, we render the @ symbol. dude_x and dude_y are in terminal coordinates.\n\tconsole->set_char(console->at(dude_position.x, dude_position.y), dude);\n}\n\n// Your main function\nint main()\n{\n\t// Initialize with defaults\n\tinit(config_simple_px(\"../assets\"));\n\n\t// We do a visibility sweep to start, so your starting position is revealed\n\tvisibility_sweep();\n\n\t// Enter the main loop. \"tick\" is the function we wrote above.\n\trun(tick);\n\n    return 0;\n}\n"
  },
  {
    "path": "examples/ex7/main.cpp",
    "content": "/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed under the MIT license - see LICENSE file.\n *\n * Example 7: Introduction to complex GUIs. This example demonstrates how you can create multiple layers,\n * and use call-backs to resize them as the window adjusts. It also displays a layer on top of another,\n * with alpha transparency (useful for effects).\n */\n\n// You need to include the RLTK header\n#include \"../../rltk/rltk.hpp\"\n#include <sstream>\n#include <iomanip>\n\n// For convenience, import the whole rltk namespace. You may not want to do this\n// in larger projects, to avoid naming collisions.\nusing namespace rltk;\nusing namespace rltk::colors;\n\n// For convenience, we'll define our GUI section handles here. These are just ID numbers.\nconstexpr int TITLE_LAYER = 0;\nconstexpr int MAIN_LAYER = 1;\nconstexpr int LOG_LAYER = 2;\nconstexpr int OVERLAY_LAYER = 3;\n\n// Tick is called every frame. The parameter specifies how many ms have elapsed\n// since the last time it was called.\nvoid tick(double duration_ms) {\n\tterm(TITLE_LAYER)->clear(vchar{' ', YELLOW, BLUE});\n\tterm(TITLE_LAYER)->print_center(0, \"Big 32x32 Title\", YELLOW, BLUE);\n\tterm(MAIN_LAYER)->clear(vchar{'.', GREY, BLACK});\n\tterm(MAIN_LAYER)->box(GREY, BLACK, true);\n\tterm(MAIN_LAYER)->set_char(10, 10, vchar{'@', YELLOW, BLACK});\n\tterm(LOG_LAYER)->clear(vchar{' ', WHITE, DARKEST_GREEN});\n\tterm(LOG_LAYER)->box(DARKEST_GREEN, BLACK);\n\tterm(LOG_LAYER)->print(1,1, \"Log Entry\", LIGHT_GREEN, DARKEST_GREEN);\n\tterm(LOG_LAYER)->print(1,2, \"More text!\", LIGHT_GREEN, DARKEST_GREEN);\n\tterm(LOG_LAYER)->print(1,3, \"Even more...\", LIGHT_GREEN, DARKEST_GREEN);\n\tterm(LOG_LAYER)->print(1,4, \"... goes here\", LIGHT_GREEN, DARKEST_GREEN);\n\tterm(OVERLAY_LAYER)->clear();\n\tterm(OVERLAY_LAYER)->set_char(11, 10, vchar{17, LIGHT_GREEN, BLACK}); // Draw a left arrow\n\tterm(OVERLAY_LAYER)->print(12, 10, \"Translucent Tool-tip\", LIGHT_GREEN, BLACK);\n\n\tstd::stringstream ss;\n\tss << std::setiosflags(std::ios::fixed) << std::setprecision(0) << (1000.0/duration_ms) << \" FPS\";\n\tterm(LOG_LAYER)->print(1,6, ss.str(), WHITE, DARKEST_GREEN);\n}\n\n// This is called when the screen resizes, to allow the GUI to redefine itself.\nvoid resize_title(layer_t * l, int w, int h) {\n\t// Simply set the width to the whole window width\n\tl->w = w;\n\tl->h = 32; // Not really necessary - here for clarity\n}\n\n// This is called when the screen resizes, to allow the GUI to redefine itself.\nvoid resize_main(layer_t * l, int w, int h) {\n\t// Simply set the width to the whole window width, and the whole window minus 16 pixels (for the heading)\n\tl->w = w - 160;\n\tl->h = h - 32; \n\tif (l->w < 0) l->w = 160; // If the width is too small with the log window, display anyway.\n}\n\n// This is called when the screen resizes, to allow the GUI to redefine itself.\nvoid resize_log(layer_t * l, int w, int h) {\n\t// Simply set the width to the whole window width, and the whole window minus 16 pixels (for the heading)\n\tl->w = w - 160;\n\tl->h = h - 32;\n\n\t// If the log window would take up the whole screen, hide it\n\tif (l->w < 0) {\n\t\tl->console->visible = false;\n\t} else {\n\t\tl->console->visible = true;\n\t}\n\tl->x = w - 160;\n}\n\n// Your main function\nint main()\n{\n\t// This time, we're using a full initialization: width, height, window title, and \"false\" meaning we don't\n\t// want an automatically generated root console. This is necessary when you want to use the complex layout\n\t// functions.\n\tinit(config_advanced(\"../assets\"));\n\n\tgui->add_layer(TITLE_LAYER, 0, 0, 1024, 32, \"32x32\", resize_title);\n\tgui->add_layer(MAIN_LAYER, 0, 32, 1024-160, 768-32, \"8x8\", resize_main);\n\tgui->add_layer(LOG_LAYER, 864, 32, 160, 768-32, \"8x16\", resize_log);\n\tgui->add_layer(OVERLAY_LAYER, 0, 32, 1024-160, 768-32, \"8x8\", resize_main); // We re-use resize_main, we want it over the top\n\tterm(OVERLAY_LAYER)->set_alpha(196); // Make the overlay translucent\n\n\trun(tick);\n\n    return 0;\n}\n"
  },
  {
    "path": "examples/ex8/main.cpp",
    "content": "/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed under the MIT license - see LICENSE file.\n *\n * Example 7: Advanced GUI with retained-mode GUI elements and an owner-draw background.\n */\n\n// You need to include the RLTK header\n#include \"../../rltk/rltk.hpp\"\n#include <sstream>\n#include <iomanip>\n\n// For convenience, import the whole rltk namespace. You may not want to do this\n// in larger projects, to avoid naming collisions.\nusing namespace rltk;\nusing namespace rltk::colors;\n\nrandom_number_generator rng;\n\nconstexpr int BACKDROP_LAYER = 1;\nconstexpr int LOG_LAYER = 2;\nconstexpr int RETAINED_TEST_LAYER = 3;\n\nconstexpr int TEST_BOUNDARY_BOX = 1;\nconstexpr int TEST_STATIC_TEST = 2;\nconstexpr int TEST_MOUSE_HOVER = 3;\nconstexpr int TEST_CHECKBOX = 4;\nconstexpr int TEST_RADIOSET = 5;\nconstexpr int TEST_HBAR = 6;\nconstexpr int TEST_VBAR = 7;\nconstexpr int TEST_LISTBOX = 8;\n\nvoid resize_bg(layer_t * l, int w, int h) {\n\t// Use the whole window\n\tl->w = w;\n\tl->h = h;\n}\n\nvoid draw_bg(layer_t * l, sf::RenderTexture &window) {\n\tsf::Texture * bg = get_texture(\"backdrop\");\n\tsf::Sprite backdrop(*bg);\n\twindow.draw(backdrop);\n}\n\nvoid resize_log(layer_t * l, int w, int h) {\n\t// Simply set the width to the whole window width, and the whole window minus 16 pixels (for the heading)\n\tl->w = w - 160;\n\tl->h = h - 32;\n\n\t// If the log window would take up the whole screen, hide it\n\tif (l->w < 0) {\n\t\tl->console->visible = false;\n\t} else {\n\t\tl->console->visible = true;\n\t}\n\tl->x = w - 160;\n}\n\nvoid resize_retained(layer_t * l, int w, int h) {\n\t// Do nothing - we'll just keep on rendering away.\n\tl->x = 100;\n\tl->y = 100;\n\tl->w = 400;\n\tl->h = 200;\n}\n\n// Tick is called every frame. The parameter specifies how many ms have elapsed\n// since the last time it was called.\nvoid tick(double duration_ms) {\n\tterm(LOG_LAYER)->clear(vchar{' ', WHITE, DARKEST_GREEN});\n\tterm(LOG_LAYER)->box(DARKEST_GREEN, BLACK);\n\n\tlayer_t * retained = layer(RETAINED_TEST_LAYER);\n\n\tif ( retained->control<gui_checkbox_t>(TEST_CHECKBOX)->checked ) {\n\t\tterm(LOG_LAYER)->print(1,1, \"Checked\", LIGHTEST_GREEN, DARKEST_GREEN);\n\t} else {\n\t\tterm(LOG_LAYER)->print(1,1, \"Not Checked\", DARK_GREEN, DARKEST_GREEN);\n\t}\n\n\tstd::stringstream radio_ss;\n\tradio_ss << \"Option: \" << retained->control<gui_radiobuttons_t>(TEST_RADIOSET)->selected_value;\n\tterm(LOG_LAYER)->print(1,2, radio_ss.str(), LIGHT_GREEN, DARKEST_GREEN);\n\n\tstd::stringstream list_ss;\n\tlist_ss << \"List: \" << retained->control<gui_listbox_t>(TEST_LISTBOX)->selected_value;\n\tterm(LOG_LAYER)->print(1,3, list_ss.str(), LIGHT_GREEN, DARKEST_GREEN);\n\tterm(LOG_LAYER)->print(1,4, \"... goes here\", LIGHT_GREEN, DARKEST_GREEN);\n\n\tstd::stringstream ss;\n\tss << std::setiosflags(std::ios::fixed) << std::setprecision(0) << (1000.0/duration_ms) << \" FPS\";\n\tterm(LOG_LAYER)->print(1,6, ss.str(), WHITE, DARKEST_GREEN);\n\n\tif (rng.roll_dice(1,20)==1) {\n\t\tretained->control<gui_hbar_t>(TEST_HBAR)->value = rng.roll_dice(1,100);\n\t\tretained->control<gui_vbar_t>(TEST_VBAR)->value = rng.roll_dice(1,100);\n\t}\n}\n\n// Your main function\nint main()\n{\n\t// This time, we're using a full initialization: width, height, window title, and \"false\" meaning we don't\n\t// want an automatically generated root console. This is necessary when you want to use the complex layout\n\t// functions.\n\tinit(config_advanced(\"../assets\"));\n\n\t// We're going to be using a bitmap, so we need to load it. The library makes this easy:\n\tregister_texture(\"../assets/background_image.png\", \"backdrop\");\n\n\t// Now we add an owner-draw background layer. \"Owner-draw\" means that it the library will ask it to\n\t// draw itself with a call-back function.\n\tgui->add_owner_layer(BACKDROP_LAYER, 0, 0, 1024, 768, resize_bg, draw_bg);\n\tgui->add_layer(LOG_LAYER, 864, 32, 160, 768-32, \"8x16\", resize_log);\n\tterm(LOG_LAYER)->set_alpha(196); // Make the overlay translucent\n\tgui->add_layer(RETAINED_TEST_LAYER, 100, 100, 400, 400, \"8x16\", resize_retained);\n\n\t// To reduce typing, grab a pointer to the retained layer:\n\tlayer_t * retained = layer(RETAINED_TEST_LAYER);\n\n\t// Now we build some retained-mode controls. These don't require additional work during rendering\n\t// Note that we are providing a handle to the control. That lets us access it later with \n\t// layer(layerhandle)->control(controlhandle). It's up to you to store the handles; they can be any\n\t// int.\n\tretained->add_boundary_box(TEST_BOUNDARY_BOX, true, DARK_GREY, BLACK);\n\tretained->add_static_text(TEST_STATIC_TEST, 1, 1, \"Retained Mode Static Text\", YELLOW, BLACK);\n\n\t// For this control, we'll define an on-mouse-over. We're using a lambda, but it could be any function\n\t// with that takes a gui_control_t * as a parameter. We'll also use \"on render start\" to define a function\n\t// run when the control rendering starts.\n\tretained->add_static_text(TEST_MOUSE_HOVER, 1, 2, \"Hover the mouse over me!\", WHITE, BLACK);\n\tretained->control(TEST_MOUSE_HOVER)->on_render_start = [] (gui_control_t * control) {\n\t\tauto static_text = static_cast<gui_static_text_t *>(control);\n\t\tstatic_text->background = BLACK;\n\t\tstatic_text->text = \"Hover the mouse over me!\";\n\t};\n\tretained->control(TEST_MOUSE_HOVER)->on_mouse_over = [] (gui_control_t * control, int terminal_x, int terminal_y) {\n\t\tauto static_text = static_cast<gui_static_text_t *>(control);\n\t\tstatic_text->background = RED;\n\t\tstatic_text->text = \"Why Hello There!        \";\n\t};\n\n\t// A checkbox\n\tretained->add_checkbox(TEST_CHECKBOX, 1, 3, \"I'm a checkbox - click me!\", false, LIGHT_GREEN, BLACK);\n\n\t// A radioset\n\tretained->add_radioset(TEST_RADIOSET, 1, 5, \"Test radio buttons\", CYAN, BLACK, {\n\t\t{true, \"Option A\", 0}, {false, \"Option B\", 1}, {false, \"Option C\", 2}\n\t});\n\n\t// Add a horizontal and vertical color bar (e.g. health)\n\tretained->add_hbar(TEST_HBAR, 1, 9, 46, 0, 100, 50, color_t(128,0,0), color_t(255,0,0), color_t(128,128,128), color_t(64,64,64), WHITE, \"Health: \");\n\tretained->add_vbar(TEST_VBAR, 48, 1, 20, 0, 100, 50, color_t(0,0,128), color_t(0,0,128), color_t(128,128,128), color_t(64,64,64), CYAN, \"Mana: \");\n\n\t// Listbox\n\tretained->add_listbox(TEST_LISTBOX, 1, 11, 1, { {1, \"Option 1\"}, {2, \"Option 2\"}, {3, \"Option 3\"} }, \"Listbox Options\", WHITE, BLACK, WHITE, BLACK, WHITE, BLUE);\n\n\t// Main loop - calls the 'tick' function you defined for each frame.\n\trun(tick);\n\n    return 0;\n}\n"
  },
  {
    "path": "examples/ex9/main.cpp",
    "content": "#include <iostream>\n/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed under the MIT license - see LICENSE file.\n *\n * Example 9: This is example 6, but using two consoles. One for the map, and one sparse. This allows\n * for some trickery to speed up map rendering (we're only redrawing when we need to). We also use smooth\n * movement, which many people may or may not like - but is an important feature to offer. Finally, we're\n * 'bouncing' the @ left and right to demonstrate rotation.\n */\n\n// You need to include the RLTK header\n#include \"../../rltk/rltk.hpp\"\n\n// We're using a vector to represent the map\n#include <vector>\n\n// We're also going to be using a shared_ptr to a map. Why shared? Because the library\n// hands it off to you and it's up to you to use it; this provides some safety that it\n// will be disposed when you are done with it.\n#include <memory>\n\n// For convenience, import the whole rltk namespace. You may not want to do this\n// in larger projects, to avoid naming collisions.\nusing namespace rltk;\nusing namespace rltk::colors;\n\n// A default-defined random number generator. You can specify a seed to get\n// the same results each time, but for now we're keeping it simple.\nrandom_number_generator rng;\n\n// For now, we always want our \"dude\" to be a yellow @ - so he's constexpr\nconst vchar dude{'@', YELLOW, BLACK};\n// We're also going to render our destination as a pink heart. Aww.\nconst vchar destination_glyph{3, MAGENTA, BLACK};\n\n// Now we define a structure to represent a location. In this case, it's a simple\n// x/y coordinate.\nstruct location_t {\n\tfloat x=-1.0f; // I like to set uninitialized values to something invalid for help with debugging\n\tfloat y=-1.0f;\n\n\t// For convenience, we're overriding the quality operator. This gives a very\n\t// quick and natural looking way to say \"are these locations the same?\"\n\tbool operator==(location_t &rhs) { return (std::floor(x)==std::floor(rhs.x) && std::floor(y)==std::floor(rhs.y)); }\n\n\tlocation_t() {}\n\tlocation_t(const int X, const int Y) : x(static_cast<float>(X)), y(static_cast<float>(Y)) {}\n};\n\n// Now we define our basic map. Why a struct? Because a struct is just a class with\n// everything public in it!\nstruct map_t {\n\tmap_t(const int &w, const int &h) : width(w), height(h) {\n\t\t// Resize the vectors to hold the whole map; this way it won't reallocate\n\t\twalkable.resize(w*h);\n\t\trevealed.resize(w*h);\n\t\tvisible.resize(w*h);\n\n\t\t// Set the entire map to walkable, not visible and not revealed\n\t\tstd::fill(walkable.begin(), walkable.end(), true);\n\t\tstd::fill(revealed.begin(), revealed.end(), false);\n\t\tstd::fill(visible.begin(), visible.end(), false);\n\n\t\t// We want the perimeter to be solid\n\t\tfor (int x=0; x<width; ++x) { \n\t\t\twalkable[at(x,0)]=false;\n\t\t\twalkable[at(x,height-1)]=false;\n\t\t}\n\t\tfor (int y=0; y<height; ++y) {\n\t\t\twalkable[at(0,y)] = false;\n\t\t\twalkable[at(width-1,y)] = false;\n\t\t}\n\n\t\t// Every tile other than 10,10 (starting) has a 33% chance of being solid. We've\n\t\t// made it more likely to have obstacles, since we're no longer relying on the RNG\n\t\t// to find our way.\t\n\t\tfor (int y=1; y<height-2; ++y) {\n\t\t\tfor (int x=1; x<width-2; ++x) {\n\t\t\t\tif (rng.roll_dice(1,3)==1) walkable[at(x,y)] = false;\n\t\t\t}\n\t\t}\n\t\twalkable[at(10,10)]=true;\n\t}\n\n\t// Calculate the vector offset of a grid location\n\tinline int at(const int &x, const int &y) { return (y*width)+x; }\n\n\t// The width and height of the map\n\tconst int width, height;\n\n\t// The actual walkable storage vector\n\tstd::vector<bool> walkable;\n\n\t// Revealed: has a tile been shown yet?\n\tstd::vector<bool> revealed;\n\n\t// Visible: is a tile currently visible?\n\tstd::vector<bool> visible;\n};\n\n// The A* library returns a navigation path with a template specialization to our location_t.\n// Store the path here. Normally, you'd use \"auto\" for this type, it is a lot less typing!\nstd::shared_ptr<navigation_path<location_t>> path;\n\n// We're using 1024x768, with 8 pixel wide chars. That gives a console grid of\n// 128 x 96. We'll go with that for the map, even though in reality the screen\n// might change. Worrying about that is for a future example!\nconstexpr int MAP_WIDTH = 128;\nconstexpr int MAP_HEIGHT = 96;\nmap_t map(MAP_WIDTH, MAP_HEIGHT);\n\n// Instead of raw ints, we'll use the location structure to represent where our\n// dude is. Using C++14 initialization, it's nice and clean.\nlocation_t dude_position {10,10};\n\n// We'll also use a location_t to represent the intended destination.\nlocation_t destination {10,10};\n\n// The A* library also requires a helper class to understand your map format.\nstruct navigator {\n\t// This lets you define a distance heuristic. Manhattan distance works really well, but\n\t// for now we'll just use a simple euclidian distance squared.\n\t// The geometry system defines one for us.\n\tstatic float get_distance_estimate(location_t &pos, location_t &goal) {\n\t\tfloat d = distance2d_squared(static_cast<int>(pos.x), static_cast<int>(pos.y), static_cast<int>(goal.x), static_cast<int>(goal.y));\n\t\treturn d;\n\t}\n\n\t// Heuristic to determine if we've reached our destination? In some cases, you'd not want\n\t// this to be a simple comparison with the goal - for example, if you just want to be\n\t// adjacent to (or even a preferred distance from) the goal. In this case, \n\t// we're trying to get to the goal rather than near it.\n\tstatic bool is_goal(location_t &pos, location_t &goal) {\n\t\treturn pos == goal;\n\t}\n\n\t// This is where we calculate where you can go from a given tile. In this case, we check\n\t// all 8 directions, and if the destination is walkable return it as an option.\n\tstatic bool get_successors(location_t pos, std::vector<location_t> &successors) {\n\t\t//std::cout << pos.x << \"/\" << pos.y << \"\\n\";\n\n\t\tif (map.walkable[map.at(static_cast<int>(pos.x-1), static_cast<int>(pos.y-1))]) successors.push_back(location_t(static_cast<int>(pos.x-1), static_cast<int>(pos.y-1)));\n\t\tif (map.walkable[map.at(static_cast<int>(pos.x), static_cast<int>(pos.y-1))]) successors.push_back(location_t(static_cast<int>(pos.x), static_cast<int>(pos.y-1)));\n\t\tif (map.walkable[map.at(static_cast<int>(pos.x+1), static_cast<int>(pos.y-1))]) successors.push_back(location_t(static_cast<int>(pos.x+1), static_cast<int>(pos.y-1)));\n\n\t\tif (map.walkable[map.at(static_cast<int>(pos.x-1), static_cast<int>(pos.y))]) successors.push_back(location_t(static_cast<int>(pos.x-1), static_cast<int>(pos.y)));\n\t\tif (map.walkable[map.at(static_cast<int>(pos.x+1), static_cast<int>(pos.y))]) successors.push_back(location_t(static_cast<int>(pos.x+1), static_cast<int>(pos.y)));\n\n\t\tif (map.walkable[map.at(static_cast<int>(pos.x-1), static_cast<int>(pos.y+1))]) successors.push_back(location_t(static_cast<int>(pos.x-1), static_cast<int>(pos.y+1)));\n\t\tif (map.walkable[map.at(static_cast<int>(pos.x), static_cast<int>(pos.y+1))]) successors.push_back(location_t(static_cast<int>(pos.x), static_cast<int>(pos.y+1)));\n\t\tif (map.walkable[map.at(static_cast<int>(pos.x+1), static_cast<int>(pos.y+1))]) successors.push_back(location_t(static_cast<int>(pos.x+1), static_cast<int>(pos.y+1)));\n\t\treturn true;\n\t}\n\n\t// This function lets you set a cost on a tile transition. For now, we'll always use a cost of 1.0.\n\tstatic float get_cost(location_t &position, location_t &successor) {\n\t\treturn 1.0f;\n\t}\n\n\t// This is a simple comparison to determine if two locations are the same. It just passes\n\t// through to the location_t's equality operator in this instance (we didn't do that automatically)\n\t// because there are times you might want to behave differently.\n\tstatic bool is_same_state(location_t &lhs, location_t &rhs) {\n\t\treturn lhs == rhs;\n\t}\n\n\t// We're using the Bresneham's line optimization for pathing this time, which requires a few extra\n\t// static methods. These are designed to translate between your map format and co-ordinates used by\n\t// the library (we don't want to force you to structure things a certain way).\n\tstatic int get_x(const location_t &loc) { return static_cast<int>(loc.x); }\n\tstatic int get_y(const location_t &loc) { return static_cast<int>(loc.y); }\n\tstatic location_t get_xy(const int &x, const int &y) { return location_t{x,y}; }\n\tstatic bool is_walkable(const location_t &loc) { return map.walkable[map.at(static_cast<int>(loc.x), static_cast<int>(loc.y))]; }\n};\n\n// Lets go really fast!\nconstexpr double tick_duration = 0.0;\ndouble tick_time = 0.0;\n\n// Helper function: calls the RLTK visibility sweep 2D algorithm with lambdas to\n// assist in understanding our map format.\ninline void visibility_sweep() {\n\tvisibility_sweep_2d<location_t, navigator>(dude_position, 10, \n\t\t[] (location_t reveal) { \n\t\t\tmap.revealed[map.at(static_cast<int>(reveal.x), static_cast<int>(reveal.y))] = true;\n\t\t\tmap.visible[map.at(static_cast<int>(reveal.x), static_cast<int>(reveal.y))] = true;\n\t\t},\n\t\t[] (auto test_visibility) { return map.walkable[map.at(static_cast<int>(test_visibility.x), static_cast<int>(test_visibility.y))]; }\n\t);\n}\n\n// Tick is called every frame. The parameter specifies how many ms have elapsed\n// since the last time it was called.\nvoid tick(double duration_ms) {\n\tint angle = 0;\n\n\t// Increase the tick time by the frame duration. If it has exceeded\n\t// the tick duration, then we move the @.\n\ttick_time += duration_ms;\n\tif (tick_time > tick_duration) {\n\t\t// Are we there yet?\n\t\tif (dude_position == destination) {\n\t\t\t// Now we poll the mouse to determine where we want to go\n\t\t\t// This requests the mouse position in PIXELS, and ties it into our mouse_x/mouse_y variables.\n\t\t\tint mouse_x, mouse_y;\n\t\t\tstd::tie(mouse_x, mouse_y) = get_mouse_position();\n\n\t\t\t// Since we're using an 8x8, it's just a matter of dividing by 8 to find the terminal-character\n\t\t\t// coordinates. There will be a helper function for this once we get into retained GUIs.\n\t\t\tconst int terminal_x = mouse_x / 8;\n\t\t\tconst int terminal_y = mouse_y / 8;\n\n\t\t\t// If the mouse is pointing at a walkable location, and the left button is down - path to the mouse.\n\t\t\tconst bool walkable = map.walkable[map.at(terminal_x, terminal_y)];\n\t\t\tif (walkable && get_mouse_button_state(rltk::button::LEFT)) {\n\t\t\t\tdestination.x = static_cast<float>(terminal_x);\n\t\t\t\tdestination.y = static_cast<float>(terminal_y);\n\n\t\t\t\t// Now determine how to get there\n\t\t\t\tif (path) path.reset();\n\t\t\t\tpath = find_path<location_t, navigator>(dude_position, destination);\n\t\t\t\tif (!path->success) {\n\t\t\t\t\tdestination = dude_position;\n\t\t\t\t\tstd::cout << \"RESET: THIS ISN'T MEANT TO HAPPEN!\\n\";\n\t\t\t\t}\n\t\t\t} else if (walkable) {\n\t\t\t\t// If the mouse is not clicked, then path to the mouse cursor for display only\n\t\t\t\tif (path) path.reset();\n\t\t\t\tpath = find_path_2d<location_t, navigator>(dude_position, location_t{terminal_x, terminal_y});\n\t\t\t}\n\t\t} else {\n\t\t\t// Follow the breadcrumbs!\n\t\t\tif (path) {\n\t\t\t\tlocation_t next_step = path->steps.front();\n\t\t\t\t//dude_position.x = next_step.x;\n\t\t\t\t//dude_position.y = next_step.y;\n\t\t\t\tif (dude_position.x > next_step.x) { dude_position.x -= 0.25f; angle = 315; }\n\t\t\t\tif (dude_position.x < next_step.x) { dude_position.x += 0.25f; angle = 45; }\n\t\t\t\tif (dude_position.y > next_step.y) dude_position.y -= 0.25f;\n\t\t\t\tif (dude_position.y < next_step.y) dude_position.y += 0.25f;\n\t\t\t\tif (std::floor(dude_position.x) == next_step.x && std::floor(dude_position.y) == next_step.y) path->steps.pop_front();\n\n\t\t\t\t// Update the map visibility\n\t\t\t\tstd::fill(map.visible.begin(), map.visible.end(), false);\n\t\t\t\tvisibility_sweep();\n\t\t\t\tterm(1)->dirty = true;\n\t\t\t}\n\t\t}\n\n\t\t// Important: we clear the tick count after the update.\n\t\ttick_time = 0.0;\n\t}\n\n\t// Render our planned path. We're using auto and a range-for to avoid typing all\n\t// the iterator stuff\n\tsterm(2)->clear();\n\n\tif (path) {\n\t\t// We're going to show off a bit and \"lerp\" the color along the path; the red\n\t\t// lightens as it approaches the destination. This is a preview of some of the\n\t\t// color functions.\n\t\tconst float n_steps = static_cast<float>(path->steps.size());\n\t\tfloat i = 0;\n\t\tfor (auto step : path->steps) {\n\t\t\tconst float lerp_amount = i / n_steps;\n\t\t\tvchar highlight;\n\t\t\t// If we're at our destination, we are showing possible paths - highlight green;\n\t\t\t// otherwise, highlight red to indicate that we are en route.\n\t\t\tif (dude_position == destination) {\n\t\t\t\thighlight = { 177, lerp(DARK_GREEN, LIGHTEST_GREEN, lerp_amount), BLACK };\n\t\t\t} else {\n\t\t\t\thighlight = { 177, lerp(DARK_RED, LIGHTEST_RED, lerp_amount), BLACK };\t\t\t\t\n\t\t\t}\n\t\t\tsterm(2)->add(xchar( 177, highlight.foreground, static_cast<float>(step.x), static_cast<float>(step.y) ));\n\t\t\t++i;\n\t\t}\n\t}\n\n\t// Render our destination\n\tterm(1)->set_char(term(1)->at(static_cast<int>(destination.x), static_cast<int>(destination.y)), destination_glyph);\n\n\t// Finally, we render the @ symbol. dude_x and dude_y are in terminal coordinates.\n\t//term(1)->set_char(term(1)->at(dude_position.x, dude_position.y), dude);\n\tsterm(2)->add(xchar(\n\t\t'@', YELLOW, static_cast<float>(dude_position.x), static_cast<float>(dude_position.y), angle\n\t));\n\n\t// Iterate over the whole map, rendering as appropriate\n\tif (term(1)->dirty) {\n\t\tfor (int y=0; y<MAP_HEIGHT; ++y) {\n\t\t\tfor (int x=0; x<MAP_WIDTH; ++x) {\n\t\t\t\tconst int map_idx = map.at(x,y); // Caching so we don't keep doing the calculation\n\t\t\t\tif (map.walkable[map_idx]) {\n\t\t\t\t\tif (map.visible[map_idx]) {\n\t\t\t\t\t\t// Visible tile: render full color\n\t\t\t\t\t\tterm(1)->set_char(map_idx, vchar{'.', GREEN, BLACK});\n\t\t\t\t\t} else if (map.revealed[map_idx]) {\n\t\t\t\t\t\t// Revealed tile: render grey\n\t\t\t\t\t\tterm(1)->set_char(map_idx, vchar{'.', LIGHTER_GREY, BLACK});\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// We haven't seen it yet - darkest gray\n\t\t\t\t\t\tterm(1)->set_char(map_idx, vchar{'.', DARK_GREY, BLACK});\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tif (map.visible[map_idx]) {\n\t\t\t\t\t\t// Visible tile: render full color\n\t\t\t\t\t\tterm(1)->set_char(map_idx, vchar{'#', CYAN, BLACK});\n\t\t\t\t\t} else if (map.revealed[map_idx]) {\n\t\t\t\t\t\t// Revealed tile: render grey\n\t\t\t\t\t\tterm(1)->set_char(map_idx, vchar{'#', GREY, BLACK});\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// We haven't seen it yet - darkest gray\n\t\t\t\t\t\tterm(1)->set_char(map_idx, vchar{'#', DARKER_GREY, BLACK});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\t\n}\n\nvoid resize_map(layer_t * l, int w, int h) {\n\t// Use the whole window\n\tl->w = w;\n\tl->h = h;\n}\n\n// Your main function\nint main()\n{\n\t// Initialize as a 1024x768 window with a title\n\tinit(config_advanced(\"../assets\", 1020, 768, \"RLTK - Example 9\", false));\n\t// Add a regular layer\n\tgui->add_layer(1, 0, 0, 1024, 768, \"8x8\", resize_map);\n\t// Add a spare layer so we can animate the @ symbol bending over\n\tgui->add_sparse_layer(2, 0, 0, 1024, 768, \"8x8\", resize_map); // Our sparse layer\n\n\t// We do a visibility sweep to start, so your starting position is revealed\n\tvisibility_sweep();\n\n\t// Enter the main loop. \"tick\" is the function we wrote above.\n\trun(tick);\n\n    return 0;\n}\n"
  },
  {
    "path": "rltk/astar.hpp",
    "content": "/*\n A* Algorithm Implementation using STL is\n Copyright (C)2001-2005 Justin Heyes-Jones\n\n Permission is given by the author to freely redistribute and\n include this code in any program as long as this credit is\n given where due.\n \n COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN \"AS IS\" BASIS,\n WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,\n INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE\n IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE\n OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND\n PERFORMANCE OF THE COVERED CODE IS WITH YOU. SHOULD ANY COVERED\n CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL\n DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY\n NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF\n WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE\n OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER\n THIS DISCLAIMER.\n \n Use at your own risk!\n\n */\n\n#pragma once\n\n// used for text debugging\n#include <iostream>\n#include <stdio.h>\n//#include <conio.h>\n#include <assert.h>\n\n// stl includes\n#include <algorithm>\n#include <set>\n#include <vector>\n#include <cfloat>\n\nusing std::vector;\n\n// fast fixed size memory allocator, used for fast node memory management\n#include \"fsa.hpp\"\n\n// Fixed size memory allocator can be disabled to compare performance\n// Uses std new and delete instead if you turn it off\n#define USE_FSA_MEMORY 1\n\n// disable warning that debugging information has lines that are truncated\n// occurs in stl headers\n#if defined(WIN32) && defined(_WINDOWS)\n#pragma warning( disable : 4786 )\n#endif\n\ntemplate<class T> class AStarState;\n\n// The AStar search class. UserState is the users state space type\ntemplate<class UserState> class AStarSearch\n{\n\npublic:\n\t// data\n\n\tenum\n\t{\n\t\tSEARCH_STATE_NOT_INITIALISED,\n\t\tSEARCH_STATE_SEARCHING,\n\t\tSEARCH_STATE_SUCCEEDED,\n\t\tSEARCH_STATE_FAILED,\n\t\tSEARCH_STATE_OUT_OF_MEMORY,\n\t\tSEARCH_STATE_INVALID\n\t};\n\n\t// A node represents a possible state in the search\n\t// The user provided state type is included inside this type\n\npublic:\n\n\tclass Node\n\t{\n\tpublic:\n\n\t\tNode *parent; // used during the search to record the parent of successor nodes\n\t\tNode *child; // used after the search for the application to view the search in reverse\n\n\t\tfloat g; // cost of this node + it's predecessors\n\t\tfloat h; // heuristic estimate of distance to goal\n\t\tfloat f; // sum of cumulative cost of predecessors and self and heuristic\n\n\t\tNode() :\n\t\t\t\tparent(0), child(0), g(0.0f), h(0.0f), f(0.0f)\n\t\t{\n\t\t}\n\n\t\tUserState m_UserState;\n\t};\n\n\t// For sorting the heap the STL needs compare function that lets us compare\n\t// the f value of two nodes\n\n\tclass HeapCompare_f\n\t{\n\tpublic:\n\n\t\tbool operator()(const Node *x, const Node *y) const\n\t\t{\n\t\t\treturn x->f > y->f;\n\t\t}\n\t};\n\npublic:\n\t// methods\n\n\t// constructor just initialises private data\n\tAStarSearch() : m_State(SEARCH_STATE_NOT_INITIALISED), m_CurrentSolutionNode( NULL),\n#if USE_FSA_MEMORY\n\t\t\t\t\tm_FixedSizeAllocator(10000),\n#endif\n\t\t\t\t\tm_AllocateNodeCount(0), m_CancelRequest(false)\n\t{\n\t}\n\n\tAStarSearch(int MaxNodes) :\n\t\t\tm_State(SEARCH_STATE_NOT_INITIALISED), m_CurrentSolutionNode( NULL),\n#if USE_FSA_MEMORY\n\t\t\t\t\tm_FixedSizeAllocator(MaxNodes),\n#endif\n\t\t\t\t\tm_AllocateNodeCount(0), m_CancelRequest(false)\n\t{\n\t}\n\n\t// call at any time to cancel the search and free up all the memory\n\tvoid CancelSearch()\n\t{\n\t\tm_CancelRequest = true;\n\t}\n\n\t// Set Start and goal states\n\tvoid SetStartAndGoalStates(UserState &Start, UserState &Goal)\n\t{\n\t\tm_CancelRequest = false;\n\n\t\tm_Start = AllocateNode();\n\t\tm_Goal = AllocateNode();\n\n\t\tassert((m_Start != NULL && m_Goal != NULL));\n\n\t\tm_Start->m_UserState = Start;\n\t\tm_Goal->m_UserState = Goal;\n\n\t\tm_State = SEARCH_STATE_SEARCHING;\n\n\t\t// Initialise the AStar specific parts of the Start Node\n\t\t// The user only needs fill out the state information\n\n\t\tm_Start->g = 0;\n\t\tm_Start->h = m_Start->m_UserState.GoalDistanceEstimate(\n\t\t\t\tm_Goal->m_UserState);\n\t\tm_Start->f = m_Start->g + m_Start->h;\n\t\tm_Start->parent = m_Start;\n\n\t\t// Push the start node on the Open list\n\n\t\tm_OpenList.push_back(m_Start); // heap now unsorted\n\n\t\t// Sort back element into heap\n\t\tpush_heap(m_OpenList.begin(), m_OpenList.end(), HeapCompare_f());\n\n\t\t// Initialise counter for search steps\n\t\tm_Steps = 0;\n\t}\n\n\t// Advances search one step \n\tunsigned int SearchStep()\n\t{\n\t\t// Firstly break if the user has not initialised the search\n\t\tassert((m_State > SEARCH_STATE_NOT_INITIALISED)\t&& (m_State < SEARCH_STATE_INVALID));\n\n\t\t// Next I want it to be safe to do a searchstep once the search has succeeded...\n\t\tif ((m_State == SEARCH_STATE_SUCCEEDED) || (m_State == SEARCH_STATE_FAILED))\n\t\t{\n\t\t\treturn m_State;\n\t\t}\n\n\t\t// Failure is defined as emptying the open list as there is nothing left to \n\t\t// search...\n\t\t// New: Allow user abort\n\t\tif (m_OpenList.empty() || m_CancelRequest)\n\t\t{\n\t\t\tFreeAllNodes();\n\t\t\tm_State = SEARCH_STATE_FAILED;\n\t\t\treturn m_State;\n\t\t}\n\n\t\t// Incremement step count\n\t\tm_Steps++;\n\n\t\t// Pop the best node (the one with the lowest f) \n\t\tNode *n = m_OpenList.front(); // get pointer to the node\n\n\t\tpop_heap(m_OpenList.begin(), m_OpenList.end(), HeapCompare_f());\n\t\tm_OpenList.pop_back();\n\n\t\t// Check for the goal, once we pop that we're done\n\t\tif (n->m_UserState.IsGoal(m_Goal->m_UserState))\n\t\t{\n\t\t\t// The user is going to use the Goal Node he passed in \n\t\t\t// so copy the parent pointer of n \n\t\t\tm_Goal->parent = n->parent;\n\t\t\tm_Goal->g = n->g;\n\n\t\t\t// A special case is that the goal was passed in as the start state\n\t\t\t// so handle that here\n\t\t\tif (false == n->m_UserState.IsSameState(m_Start->m_UserState))\n\t\t\t{\n\t\t\t\tFreeNode(n);\n\n\t\t\t\t// set the child pointers in each node (except Goal which has no child)\n\t\t\t\tNode *nodeChild = m_Goal;\n\t\t\t\tNode *nodeParent = m_Goal->parent;\n\n\t\t\t\tdo\n\t\t\t\t{\n\t\t\t\t\tnodeParent->child = nodeChild;\n\n\t\t\t\t\tnodeChild = nodeParent;\n\t\t\t\t\tnodeParent = nodeParent->parent;\n\n\t\t\t\t} while (nodeChild != m_Start); // Start is always the first node by definition\n\n\t\t\t}\n\n\t\t\t// delete nodes that aren't needed for the solution\n\t\t\tFreeUnusedNodes();\n\n\t\t\tm_State = SEARCH_STATE_SUCCEEDED;\n\n\t\t\treturn m_State;\n\t\t}\n\t\telse // not goal\n\t\t{\n\t\t\t// We now need to generate the successors of this node\n\t\t\t// The user helps us to do this, and we keep the new nodes in\n\t\t\t// m_Successors ...\n\n\t\t\tm_Successors.clear(); // empty vector of successor nodes to n\n\n\t\t\t// User provides this functions and uses AddSuccessor to add each successor of\n\t\t\t// node 'n' to m_Successors\n\t\t\tbool ret = n->m_UserState.GetSuccessors(this, n->parent ? &n->parent->m_UserState : NULL);\n\n\t\t\tif (!ret)\n\t\t\t{\n\n\t\t\t\ttypename vector<Node *>::iterator successor;\n\n\t\t\t\t// free the nodes that may previously have been added \n\t\t\t\tfor (successor = m_Successors.begin();\n\t\t\t\t\t\tsuccessor != m_Successors.end(); successor++)\n\t\t\t\t{\n\t\t\t\t\tFreeNode((*successor));\n\t\t\t\t}\n\n\t\t\t\tm_Successors.clear(); // empty vector of successor nodes to n\n\n\t\t\t\t// free up everything else we allocated\n\t\t\t\tFreeAllNodes();\n\n\t\t\t\tm_State = SEARCH_STATE_OUT_OF_MEMORY;\n\t\t\t\treturn m_State;\n\t\t\t}\n\n\t\t\t// Now handle each successor to the current node ...\n\t\t\tfor (typename vector<Node *>::iterator successor =\n\t\t\t\t\tm_Successors.begin(); successor != m_Successors.end();\n\t\t\t\t\tsuccessor++)\n\t\t\t{\n\n\t\t\t\t// \tThe g value for this successor ...\n\t\t\t\tfloat newg = n->g\n\t\t\t\t\t\t+ n->m_UserState.GetCost((*successor)->m_UserState);\n\n\t\t\t\t// Now we need to find whether the node is on the open or closed lists\n\t\t\t\t// If it is but the node that is already on them is better (lower g)\n\t\t\t\t// then we can forget about this successor\n\n\t\t\t\t// First linear search of open list to find node\n\n\t\t\t\ttypename vector<Node *>::iterator openlist_result;\n\n\t\t\t\tfor (openlist_result = m_OpenList.begin();\n\t\t\t\t\t\topenlist_result != m_OpenList.end(); openlist_result++)\n\t\t\t\t{\n\t\t\t\t\tif ((*openlist_result)->m_UserState.IsSameState(\n\t\t\t\t\t\t\t(*successor)->m_UserState))\n\t\t\t\t\t{\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (openlist_result != m_OpenList.end())\n\t\t\t\t{\n\n\t\t\t\t\t// we found this state on open\n\n\t\t\t\t\tif ((*openlist_result)->g <= newg)\n\t\t\t\t\t{\n\t\t\t\t\t\tFreeNode((*successor));\n\n\t\t\t\t\t\t// the one on Open is cheaper than this one\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\ttypename vector<Node *>::iterator closedlist_result;\n\n\t\t\t\tfor (closedlist_result = m_ClosedList.begin();\n\t\t\t\t\t\tclosedlist_result != m_ClosedList.end();\n\t\t\t\t\t\tclosedlist_result++)\n\t\t\t\t{\n\t\t\t\t\tif ((*closedlist_result)->m_UserState.IsSameState(\n\t\t\t\t\t\t\t(*successor)->m_UserState))\n\t\t\t\t\t{\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (closedlist_result != m_ClosedList.end())\n\t\t\t\t{\n\n\t\t\t\t\t// we found this state on closed\n\n\t\t\t\t\tif ((*closedlist_result)->g <= newg)\n\t\t\t\t\t{\n\t\t\t\t\t\t// the one on Closed is cheaper than this one\n\t\t\t\t\t\tFreeNode((*successor));\n\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// This node is the best node so far with this particular state\n\t\t\t\t// so lets keep it and set up its AStar specific data ...\n\n\t\t\t\t(*successor)->parent = n;\n\t\t\t\t(*successor)->g = newg;\n\t\t\t\t(*successor)->h =\n\t\t\t\t\t\t(*successor)->m_UserState.GoalDistanceEstimate(\n\t\t\t\t\t\t\t\tm_Goal->m_UserState);\n\t\t\t\t(*successor)->f = (*successor)->g + (*successor)->h;\n\n\t\t\t\t// Remove successor from closed if it was on it\n\n\t\t\t\tif (closedlist_result != m_ClosedList.end())\n\t\t\t\t{\n\t\t\t\t\t// remove it from Closed\n\t\t\t\t\tFreeNode((*closedlist_result));\n\t\t\t\t\tm_ClosedList.erase(closedlist_result);\n\n\t\t\t\t\t// Fix thanks to ...\n\t\t\t\t\t// Greg Douglas <gregdouglasmail@gmail.com>\n\t\t\t\t\t// who noticed that this code path was incorrect\n\t\t\t\t\t// Here we have found a new state which is already CLOSED\n\t\t\t\t\t// anus\n\n\t\t\t\t}\n\n\t\t\t\t// Update old version of this node\n\t\t\t\tif (openlist_result != m_OpenList.end())\n\t\t\t\t{\n\n\t\t\t\t\tFreeNode((*openlist_result));\n\t\t\t\t\tm_OpenList.erase(openlist_result);\n\n\t\t\t\t\t// re-make the heap \n\t\t\t\t\t// make_heap rather than sort_heap is an essential bug fix\n\t\t\t\t\t// thanks to Mike Ryynanen for pointing this out and then explaining\n\t\t\t\t\t// it in detail. sort_heap called on an invalid heap does not work\n\t\t\t\t\tmake_heap(m_OpenList.begin(), m_OpenList.end(),\n\t\t\t\t\t\t\tHeapCompare_f());\n\n\t\t\t\t}\n\n\t\t\t\t// heap now unsorted\n\t\t\t\tm_OpenList.push_back((*successor));\n\n\t\t\t\t// sort back element into heap\n\t\t\t\tpush_heap(m_OpenList.begin(), m_OpenList.end(),\n\t\t\t\t\t\tHeapCompare_f());\n\n\t\t\t}\n\n\t\t\t// push n onto Closed, as we have expanded it now\n\n\t\t\tm_ClosedList.push_back(n);\n\n\t\t} // end else (not goal so expand)\n\n\t\treturn m_State; // Succeeded bool is false at this point.\n\n\t}\n\n\t// User calls this to add a successor to a list of successors\n\t// when expanding the search frontier\n\tbool AddSuccessor(UserState &State)\n\t{\n\t\tNode *node = AllocateNode();\n\n\t\tif (node)\n\t\t{\n\t\t\tnode->m_UserState = State;\n\n\t\t\tm_Successors.push_back(node);\n\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t// Free the solution nodes\n\t// This is done to clean up all used Node memory when you are done with the\n\t// search\n\tvoid FreeSolutionNodes()\n\t{\n\t\tNode *n = m_Start;\n\n\t\tif (m_Start->child)\n\t\t{\n\t\t\tdo\n\t\t\t{\n\t\t\t\tNode *del = n;\n\t\t\t\tn = n->child;\n\t\t\t\tFreeNode(del);\n\n\t\t\t\tdel = NULL;\n\n\t\t\t} while (n != m_Goal);\n\n\t\t\tFreeNode(n); // Delete the goal\n\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// if the start node is the solution we need to just delete the start and goal\n\t\t\t// nodes\n\t\t\tFreeNode(m_Start);\n\t\t\tFreeNode(m_Goal);\n\t\t}\n\n\t}\n\n\t// Functions for traversing the solution\n\n\t// Get start node\n\tUserState *GetSolutionStart()\n\t{\n\t\tm_CurrentSolutionNode = m_Start;\n\t\tif (m_Start)\n\t\t{\n\t\t\treturn &m_Start->m_UserState;\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn NULL;\n\t\t}\n\t}\n\n\t// Get next node\n\tUserState *GetSolutionNext()\n\t{\n\t\tif (m_CurrentSolutionNode)\n\t\t{\n\t\t\tif (m_CurrentSolutionNode->child)\n\t\t\t{\n\n\t\t\t\tNode *child = m_CurrentSolutionNode->child;\n\n\t\t\t\tm_CurrentSolutionNode = m_CurrentSolutionNode->child;\n\n\t\t\t\treturn &child->m_UserState;\n\t\t\t}\n\t\t}\n\n\t\treturn NULL;\n\t}\n\n\t// Get end node\n\tUserState *GetSolutionEnd()\n\t{\n\t\tm_CurrentSolutionNode = m_Goal;\n\t\tif (m_Goal)\n\t\t{\n\t\t\treturn &m_Goal->m_UserState;\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn NULL;\n\t\t}\n\t}\n\n\t// Step solution iterator backwards\n\tUserState *GetSolutionPrev()\n\t{\n\t\tif (m_CurrentSolutionNode)\n\t\t{\n\t\t\tif (m_CurrentSolutionNode->parent)\n\t\t\t{\n\n\t\t\t\tNode *parent = m_CurrentSolutionNode->parent;\n\n\t\t\t\tm_CurrentSolutionNode = m_CurrentSolutionNode->parent;\n\n\t\t\t\treturn &parent->m_UserState;\n\t\t\t}\n\t\t}\n\n\t\treturn NULL;\n\t}\n\n\t// Get final cost of solution\n\t// Returns FLT_MAX if goal is not defined or there is no solution\n\tfloat GetSolutionCost()\n\t{\n\t\tif (m_Goal && m_State == SEARCH_STATE_SUCCEEDED)\n\t\t{\n\t\t\treturn m_Goal->g;\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn FLT_MAX;\n\t\t}\n\t}\n\n\t// For educational use and debugging it is useful to be able to view\n\t// the open and closed list at each step, here are two functions to allow that.\n\n\tUserState *GetOpenListStart()\n\t{\n\t\tfloat f, g, h;\n\t\treturn GetOpenListStart(f, g, h);\n\t}\n\n\tUserState *GetOpenListStart(float &f, float &g, float &h)\n\t{\n\t\titerDbgOpen = m_OpenList.begin();\n\t\tif (iterDbgOpen != m_OpenList.end())\n\t\t{\n\t\t\tf = (*iterDbgOpen)->f;\n\t\t\tg = (*iterDbgOpen)->g;\n\t\t\th = (*iterDbgOpen)->h;\n\t\t\treturn &(*iterDbgOpen)->m_UserState;\n\t\t}\n\n\t\treturn NULL;\n\t}\n\n\tUserState *GetOpenListNext()\n\t{\n\t\tfloat f, g, h;\n\t\treturn GetOpenListNext(f, g, h);\n\t}\n\n\tUserState *GetOpenListNext(float &f, float &g, float &h)\n\t{\n\t\titerDbgOpen++;\n\t\tif (iterDbgOpen != m_OpenList.end())\n\t\t{\n\t\t\tf = (*iterDbgOpen)->f;\n\t\t\tg = (*iterDbgOpen)->g;\n\t\t\th = (*iterDbgOpen)->h;\n\t\t\treturn &(*iterDbgOpen)->m_UserState;\n\t\t}\n\n\t\treturn NULL;\n\t}\n\n\tUserState *GetClosedListStart()\n\t{\n\t\tfloat f, g, h;\n\t\treturn GetClosedListStart(f, g, h);\n\t}\n\n\tUserState *GetClosedListStart(float &f, float &g, float &h)\n\t{\n\t\titerDbgClosed = m_ClosedList.begin();\n\t\tif (iterDbgClosed != m_ClosedList.end())\n\t\t{\n\t\t\tf = (*iterDbgClosed)->f;\n\t\t\tg = (*iterDbgClosed)->g;\n\t\t\th = (*iterDbgClosed)->h;\n\n\t\t\treturn &(*iterDbgClosed)->m_UserState;\n\t\t}\n\n\t\treturn NULL;\n\t}\n\n\tUserState *GetClosedListNext()\n\t{\n\t\tfloat f, g, h;\n\t\treturn GetClosedListNext(f, g, h);\n\t}\n\n\tUserState *GetClosedListNext(float &f, float &g, float &h)\n\t{\n\t\titerDbgClosed++;\n\t\tif (iterDbgClosed != m_ClosedList.end())\n\t\t{\n\t\t\tf = (*iterDbgClosed)->f;\n\t\t\tg = (*iterDbgClosed)->g;\n\t\t\th = (*iterDbgClosed)->h;\n\n\t\t\treturn &(*iterDbgClosed)->m_UserState;\n\t\t}\n\n\t\treturn NULL;\n\t}\n\n\t// Get the number of steps\n\n\tint GetStepCount()\n\t{\n\t\treturn m_Steps;\n\t}\n\n\tvoid EnsureMemoryFreed()\n\t{\n#if USE_FSA_MEMORY\n\t\tassert(m_AllocateNodeCount == 0);\n#endif\n\n\t}\n\nprivate:\n\t// methods\n\n\t// This is called when a search fails or is cancelled to free all used\n\t// memory \n\tvoid FreeAllNodes()\n\t{\n\t\t// iterate open list and delete all nodes\n\t\ttypename vector<Node *>::iterator iterOpen = m_OpenList.begin();\n\n\t\twhile (iterOpen != m_OpenList.end())\n\t\t{\n\t\t\tNode *n = (*iterOpen);\n\t\t\tFreeNode(n);\n\n\t\t\titerOpen++;\n\t\t}\n\n\t\tm_OpenList.clear();\n\n\t\t// iterate closed list and delete unused nodes\n\t\ttypename vector<Node *>::iterator iterClosed;\n\n\t\tfor (iterClosed = m_ClosedList.begin();\n\t\t\t\titerClosed != m_ClosedList.end(); iterClosed++)\n\t\t{\n\t\t\tNode *n = (*iterClosed);\n\t\t\tFreeNode(n);\n\t\t}\n\n\t\tm_ClosedList.clear();\n\n\t\t// delete the goal\n\n\t\tFreeNode(m_Goal);\n\t}\n\n\t// This call is made by the search class when the search ends. A lot of nodes may be\n\t// created that are still present when the search ends. They will be deleted by this \n\t// routine once the search ends\n\tvoid FreeUnusedNodes()\n\t{\n\t\t// iterate open list and delete unused nodes\n\t\ttypename vector<Node *>::iterator iterOpen = m_OpenList.begin();\n\n\t\twhile (iterOpen != m_OpenList.end())\n\t\t{\n\t\t\tNode *n = (*iterOpen);\n\n\t\t\tif (!n->child)\n\t\t\t{\n\t\t\t\tFreeNode(n);\n\n\t\t\t\tn = NULL;\n\t\t\t}\n\n\t\t\titerOpen++;\n\t\t}\n\n\t\tm_OpenList.clear();\n\n\t\t// iterate closed list and delete unused nodes\n\t\ttypename vector<Node *>::iterator iterClosed;\n\n\t\tfor (iterClosed = m_ClosedList.begin();\n\t\t\t\titerClosed != m_ClosedList.end(); iterClosed++)\n\t\t{\n\t\t\tNode *n = (*iterClosed);\n\n\t\t\tif (!n->child)\n\t\t\t{\n\t\t\t\tFreeNode(n);\n\t\t\t\tn = NULL;\n\n\t\t\t}\n\t\t}\n\n\t\tm_ClosedList.clear();\n\n\t}\n\n\t// Node memory management\n\tNode *AllocateNode()\n\t{\n\n#if !USE_FSA_MEMORY\n\t\tNode *p = new Node;\n\t\treturn p;\n#else\n\t\tNode *address = m_FixedSizeAllocator.alloc();\n\n\t\tif (!address)\n\t\t{\n\t\t\treturn NULL;\n\t\t}\n\t\tm_AllocateNodeCount++;\n\t\tNode *p = new (address) Node;\n\t\treturn p;\n#endif\n\t}\n\n\tvoid FreeNode(Node *node)\n\t{\n\n\t\tm_AllocateNodeCount--;\n\n#if !USE_FSA_MEMORY\n\t\tdelete node;\n#else\n\t\tnode->~Node();\n\t\tm_FixedSizeAllocator.free(node);\n#endif\n\t}\n\nprivate:\n\t// data\n\n\t// Heap (simple vector but used as a heap, cf. Steve Rabin's game gems article)\n\tvector<Node *> m_OpenList;\n\n\t// Closed list is a vector.\n\tvector<Node *> m_ClosedList;\n\n\t// Successors is a vector filled out by the user each type successors to a node\n\t// are generated\n\tvector<Node *> m_Successors;\n\n\t// State\n\tunsigned int m_State;\n\n\t// Counts steps\n\tint m_Steps;\n\n\t// Start and goal state pointers\n\tNode *m_Start;\n\tNode *m_Goal;\n\n\tNode *m_CurrentSolutionNode;\n\n#if USE_FSA_MEMORY\n\t// Memory\n\tFixedSizeAllocator<Node> m_FixedSizeAllocator;\n#endif\n\n\t//Debug : need to keep these two iterators around\n\t// for the user Dbg functions\n\ttypename vector<Node *>::iterator iterDbgOpen;\n\ttypename vector<Node *>::iterator iterDbgClosed;\n\n\t// debugging : count memory allocation and free's\n\tint m_AllocateNodeCount;\n\n\tbool m_CancelRequest;\n\n};\n\ntemplate<class T> class AStarState\n{\npublic:\n\tvirtual ~AStarState()\n\t{\n\t}\n\tvirtual float GoalDistanceEstimate(T &nodeGoal) = 0; // Heuristic function which computes the estimated cost to the goal node\n\tvirtual bool IsGoal(T &nodeGoal) = 0; // Returns true if this node is the goal node\n\tvirtual bool GetSuccessors(AStarSearch<T> *astarsearch, T *parent_node) = 0; // Retrieves all successors to this node and adds them via astarsearch.addSuccessor()\n\tvirtual float GetCost(T &successor) = 0; // Computes the cost of traveling from this node to the successor node\n\tvirtual bool IsSameState(T &rhs) = 0; // Returns true if this node is the same as the rhs node\n};\n\n"
  },
  {
    "path": "rltk/color_t.cpp",
    "content": "#include \"color_t.hpp\"\n#include <cmath>\n\nusing std::min;\nusing std::max;\nusing std::fmod;\n\nnamespace rltk {\n\n// Credit: https://gist.github.com/fairlight1337/4935ae72bcbcc1ba5c72\nstd::tuple<float, float, float> color_to_hsv(const color_t &col) {\n\tfloat fR = (col.r / 255.0f);\n\tfloat fG = (col.g / 255.0f);\n\tfloat fB = (col.b / 255.0f);\n\n\tfloat fH=0.0f, fS=0.0f, fV=0.0f;\n\n\tfloat fCMax = max(max(fR, fG), fB);\n\tfloat fCMin = min(min(fR, fG), fB);\n\tfloat fDelta = fCMax - fCMin;\n\n\tif(fDelta > 0) {\n\t\tif(fCMax == fR) {\n\t  \t\tfH = 60.0f * (fmodf(((fG - fB) / fDelta), 6.0f));\n\t\t} else if(fCMax == fG) {\n\t  \t\tfH = 60.0f * (((fB - fR) / fDelta) + 2.0f);\n\t\t} else if(fCMax == fB) {\n\t  \t\tfH = 60.0f * (((fR - fG) / fDelta) + 4.0f);\n\t\t}\n\n\t\tif(fCMax > 0) {\n\t  \t\tfS = fDelta / fCMax;\n\t\t} else {\n\t\t\tfS = 0;\n\t\t}\n\n\t\tfV = fCMax;\n\t} else {\n\t\tfH = 0;\n\t\tfS = 0;\n\t\tfV = fCMax;\n\t}\n\n\tif(fH < 0) {\n\t\tfH = 360 + fH;\n\t}\n\n\treturn std::make_tuple(fH, fS, fV);\n}\n\n// Credit: https://gist.github.com/fairlight1337/4935ae72bcbcc1ba5c72\nstd::tuple<uint8_t, uint8_t, uint8_t> color_from_hsv(const float hue, const float saturation, const float value) {\n\tfloat fH = hue;\n\tfloat fS = saturation;\n\tfloat fV = value;\n\n\tfloat fR, fG, fB;\n\n\tfloat fC = fV * fS; // Chroma\n\tfloat fHPrime = fmodf(fH / 60.0f, 6.0f);\n\tfloat fX = fC * (1.0f - fabsf(fmodf(fHPrime, 2.0f) - 1.0f));\n\tfloat fM = fV - fC;\n\n\tif(0 <= fHPrime && fHPrime < 1) {\n\t\tfR = fC;\n\t\tfG = fX;\n\t\tfB = 0;\n\t} else if(1 <= fHPrime && fHPrime < 2) {\n\t\tfR = fX;\n\t\tfG = fC;\n\t\tfB = 0;\n\t} else if(2 <= fHPrime && fHPrime < 3) {\n\t\tfR = 0;\n\t\tfG = fC;\n\t\tfB = fX;\n\t} else if(3 <= fHPrime && fHPrime < 4) {\n\t\tfR = 0;\n\t\tfG = fX;\n\t\tfB = fC;\n\t} else if(4 <= fHPrime && fHPrime < 5) {\n\t\tfR = fX;\n\t\tfG = 0;\n\t\tfB = fC;\n\t} else if(5 <= fHPrime && fHPrime < 6) {\n\t\tfR = fC;\n\t\tfG = 0;\n\t\tfB = fX;\n\t} else {\n\t\tfR = 0;\n\t\tfG = 0;\n\t\tfB = 0;\n\t}\n\n\tfR += fM;\n\tfG += fM;\n\tfB += fM;\n\n\treturn std::make_tuple<uint8_t, uint8_t, uint8_t>(static_cast<uint8_t>(fR*255.0), static_cast<uint8_t>(fG*255.0), static_cast<uint8_t>(fB*255.0));\n}\n\n/*\n * Calculates the luminance of a color, and converts it to grey-scale.\n */\ncolor_t greyscale(const color_t &col)\n{\n\tunsigned char red = col.r;\n\tunsigned char green = col.g;\n\tunsigned char blue = col.b;\n\n\tfloat RED = red / 255.0F;\n\tfloat GREEN = green / 255.0F;\n\tfloat BLUE = blue / 255.0F;\n\tfloat luminance = 0.299f * RED + 0.587f * GREEN + 0.114f * BLUE;\n\n\tred = static_cast<unsigned char>(luminance * 255.0F);\n\tgreen = static_cast<unsigned char>(luminance * 255.0F);\n\tblue = static_cast<unsigned char>(luminance * 255.0F);\n\n\treturn color_t(red, green, blue);\n}\n\n/*\n * Darkens a color by the specified amount.\n */\ncolor_t darken(const int &amount, const color_t &col)\n{\n\tunsigned char red = col.r;\n\tunsigned char green = col.g;\n\tunsigned char blue = col.b;\n\n\tif (red > amount)\n\t{\n\t\tred -= amount;\n\t}\n\telse\n\t{\n\t\tred = 0;\n\t}\n\tif (green > amount)\n\t{\n\t\tgreen -= amount;\n\t}\n\telse\n\t{\n\t\tgreen = 0;\n\t}\n\tif (blue > amount)\n\t{\n\t\tblue -= amount;\n\t}\n\telse\n\t{\n\t\tblue = 0;\n\t}\n\n\treturn color_t(red, green, blue);\n}\n\n/* Applies colored lighting effect; colors that don't exist remain dark. Lights are from 0.0 to 1.0. */\ncolor_t apply_colored_light(const color_t &col, const std::tuple<float,float,float> &light) {\n\tunsigned char red = col.r;\n\tunsigned char green = col.g;\n\tunsigned char blue = col.b;\n\n\tfloat RED = red / 255.0F;\n\tfloat GREEN = green / 255.0F;\n\tfloat BLUE = blue / 255.0F;\n\n\tRED *= std::get<0>(light);\n\tGREEN *= std::get<1>(light);\n\tBLUE *= std::get<2>(light);\n\n\tif (RED > 1.0) RED = 1.0;\n\tif (RED < 0.0) RED = 0.0;\n\tif (GREEN > 1.0) GREEN = 1.0;\n\tif (GREEN < 0.0) GREEN = 0.0;\n\tif (BLUE > 1.0) BLUE = 1.0;\n\tif (BLUE < 0.0) BLUE = 0.0;\n\n\tred = static_cast<unsigned char>(RED * 255.0F);\n\tgreen = static_cast<unsigned char>(GREEN * 255.0F);\n\tblue = static_cast<unsigned char>(BLUE * 255.0F);\n\n\treturn color_t(red, green, blue);\n}\n\ncolor_t lerp(const color_t &first, const color_t &second, float amount) {\n\tconst float r1 = first.r;\n\tconst float g1 = first.g;\n\tconst float b1 = first.b;\n\n\tconst float r2 = second.r;\n\tconst float g2 = second.g;\n\tconst float b2 = second.b;\n\n\tconst float rdiff = r2 - r1;\n\tconst float gdiff = g2 - g1;\n\tconst float bdiff = b2 - b1;\n\n\tfloat red = r1 + (rdiff * amount);\n\tfloat green = g1 + (gdiff * amount);\n\tfloat blue = b1 + (bdiff * amount);\n\tif (red > 255.0F) red = 255.0F;\n\tif (green > 255.0F) green = 255.0F;\n\tif (blue > 255.0F) blue = 255.0F;\n\tif (red < 0.0F) red = 0.0F;\n\tif (green < 0.0F) green = 0.0F;\n\tif (blue < 0.0F) blue = 0.0F;\n\n\tconst int r = static_cast<const int>(red);\n\tconst int g = static_cast<const int>(green);\n\tconst int b = static_cast<const int>(blue);\n\n\treturn color_t(r,g,b);\n}\n\n}"
  },
  {
    "path": "rltk/color_t.hpp",
    "content": "#pragma once\n\n/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed under the MIT license - see LICENSE file.\n *\n * Color functions\n */\n\n#include <tuple>\n#include <SFML/Graphics.hpp>\n#include <cereal/cereal.hpp>\n\nnamespace rltk {\n\n/* Converts HSV into an RGB tuple */\nextern std::tuple<uint8_t, uint8_t, uint8_t> color_from_hsv(const float hue, const float saturation, const float value);\n\nstruct color_t {\n\t/* Default empty constructor */\n\tcolor_t() {}\n\n\t/* Convenience constructor from red/green/blue; accepts ints and casts them */\n\tcolor_t(const int R, const int G, const int B) : r(static_cast<uint8_t>(R)), g(static_cast<uint8_t>(G)), b(static_cast<uint8_t>(B)) {}\n\n\t/* Construct from red/green/blue, in the range of 0-255 per component. */\n\tcolor_t(const uint8_t R, const uint8_t G, const uint8_t B) : r(R), g(G), b(B) {}\n\n\t/* Construct from HSV, in the range of 0-1.0 as floats. */\n\tcolor_t(const float hue, const float saturation, const float value) {\n\t\tstd::tie(r,g,b) = color_from_hsv(hue, saturation, value);\n\t}\n\n\t/* Construct from an RGB tuple */\n\tcolor_t(const std::tuple<uint8_t, uint8_t, uint8_t> &c) { std::tie(r,g,b) = c; }\n\n\t/* You can add colors together, for example as a quick blend/lighten */\n\tcolor_t operator+(const color_t &other) {\n\t\tint red = r + other.r;\n\t\tint green = g + other.g;\n\t\tint blue = b + other.b;\n\t\tif (red > 255) red = 255;\n\t\tif (green > 255) green = 255;\n\t\tif (blue > 255) blue = 255;\n\t\treturn color_t(red, green, blue);\n\t}\n\n\t/* You can subtract colors */\n\tcolor_t operator-(const color_t &other) {\n\t\tint red = r - other.r;\n\t\tint green = g - other.g;\n\t\tint blue = b - other.b;\n\t\tif (red < 0) red = 0;\n\t\tif (green < 0) green = 0;\n\t\tif (blue < 0) blue = 0;\n\t\treturn color_t(red, green, blue);\n\t}\n\n\t/* You can multiply colors */\n\tcolor_t operator*(const color_t &other) {\n\t\tint red = r * other.r;\n\t\tint green = g * other.g;\n\t\tint blue = b * other.b;\n\t\tif (red < 0) red = 0;\n\t\tif (green < 0) green = 0;\n\t\tif (blue < 0) blue = 0;\n\t\tif (red > 255) red = 255;\n\t\tif (green > 255) green = 255;\n\t\tif (blue > 255) blue = 255;\n\t\treturn color_t(red, green, blue);\n\t}\n\n\t/* You can compare colors */\n\tbool operator==(const color_t &other) const {\n\t\tif (other.r == r && other.g == g && other.b == b) {\n\t\t\treturn true;\n\t\t} else {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/* RGB storage */\n\tuint8_t r,g,b;\n\n\ttemplate<class Archive>\n\tvoid serialize(Archive & archive)\n\t{\n\t\tarchive( r, g, b ); // serialize things by passing them to the archive\n\t}\n};\n\n/* Converts a color_t to an SFML color */\ninline sf::Color color_to_sfml(const color_t &col) { return sf::Color(col.r, col.g, col.b); }\n\n/* Converts a color_t to an RGB tuple */\ninline std::tuple<uint8_t, uint8_t, uint8_t> color_to_rgb(const color_t &col) { return std::make_tuple(col.r, col.g, col.b); }\n\n/* Converts a color_t to an HSV tuple */\nextern std::tuple<float, float, float> color_to_hsv(const color_t &col);\n\n/* Calculates the luminance of a color, and converts it to grey-scale. */\nextern color_t greyscale(const color_t &col);\n\n/* Darkens a color by the specified amount. */\ncolor_t darken(const int &amount, const color_t &col);\n\n/* Applies colored lighting effect; colors that don't exist remain dark. Lights are from 0.0 to 1.0. */\ncolor_t apply_colored_light(const color_t &col, const std::tuple<float,float,float> &light);\n\n/* Calculates an intermediate color on a linear RGB color ramp. Amount is from 0 to 1 */\nextern color_t lerp(const color_t &first, const color_t &second, float amount);\n\n}"
  },
  {
    "path": "rltk/colors.hpp",
    "content": "#pragma once\n\n#include \"color_t.hpp\"\n\nnamespace rltk {\n\nnamespace colors {\n\nconst color_t AliceBlue(240, 248, 255);\nconst color_t AntiqueWhite(250, 235, 215);\nconst color_t Aqua(0, 255, 255);\nconst color_t Aquamarine(127, 255, 212);\nconst color_t Beige(245, 245, 220);\nconst color_t Black(0, 0, 0);\nconst color_t BlanchedAlmond(255, 235, 205);\nconst color_t Blue(0, 0, 255);\nconst color_t BlueViolet(138, 43, 226);\nconst color_t Brown(165, 42, 42);\nconst color_t BurlyWood(222, 184, 135);\nconst color_t CadetBlue(95, 158, 160);\nconst color_t Chartreuse(127, 255, 0);\nconst color_t Chocolate(210, 105, 20);\nconst color_t Coral(255, 127, 80);\nconst color_t CornflowerBlue(100, 149, 237);\nconst color_t Cornsilk(255, 248, 220);\nconst color_t Crimson(220, 20, 60);\nconst color_t Cyan(0, 0, 255);\nconst color_t DarkBlue(0, 0, 139);\nconst color_t DarkCyan(0, 139, 139);\nconst color_t DarkGoldenRod(184, 134, 11);\nconst color_t DarkGray(169, 169, 169);\nconst color_t DarkGreen(0, 100, 0);\nconst color_t DarkKhaki(189, 183, 107);\nconst color_t DarkMagenta(139, 0, 139);\nconst color_t DarkOliveGreen(85, 107, 47);\nconst color_t Darkorange(255, 140, 0);\nconst color_t DarkOrchid(255, 140, 0);\nconst color_t DarkRed(139, 0, 0);\nconst color_t DarkSalmon(233, 150, 122);\nconst color_t DarkSeaGreen(143, 188, 143);\nconst color_t DarkSlateBlue(72, 61, 139);\nconst color_t DarkSlateGray(47, 79, 79);\nconst color_t DarkTurquoise(0, 206, 209);\nconst color_t DarkViolet(148, 0, 211);\nconst color_t DeepPink(255, 20, 147);\nconst color_t DeepSkyBlue(0, 191, 255);\nconst color_t DimGray(105, 105, 105);\nconst color_t DodgerBlue(30, 144, 255);\nconst color_t FireBrick(178, 34, 34);\nconst color_t FloralWhite(255, 250, 240);\nconst color_t ForestGreen(34, 139, 34);\nconst color_t Fuchsia(255, 0, 255);\nconst color_t Gainsboro(220, 220, 220);\nconst color_t GhostWhite(248, 248, 255);\nconst color_t Gold(255, 215, 0);\nconst color_t GoldenRod(218, 165, 32);\nconst color_t Grey(128, 128, 128);\nconst color_t Green(0, 128, 0);\nconst color_t GreenYellow(173, 255, 47);\nconst color_t HoneyDew(240, 255, 240);\nconst color_t HotPink(255, 105, 180);\nconst color_t IndianRed(205, 92, 92);\nconst color_t Indigo(72, 0, 130);\nconst color_t Ivory(255, 255, 240);\nconst color_t Khaki(240, 230, 140);\nconst color_t Lavender(230, 230, 250);\nconst color_t LavenderBlush(255, 240, 245);\nconst color_t LawnGreen(124, 252, 0);\nconst color_t LemonChiffon(255, 250, 205);\nconst color_t LightBlue(173, 216, 203);\nconst color_t LightCoral(240, 128, 128);\nconst color_t LightCyan(240, 128, 128);\nconst color_t LightGoldenRodYellow(250, 250, 210);\nconst color_t LightGrey(211, 211, 211);\nconst color_t LightGreen(144, 238, 144);\nconst color_t LightPink(255, 182, 193);\nconst color_t LightSalmon(255, 160, 122);\nconst color_t LightSeaGreen(32, 178, 170);\nconst color_t LightSkyBlue(135, 206, 250);\nconst color_t LightSlateGrey(119, 136, 153);\nconst color_t LightSteelBlue(176, 196, 222);\nconst color_t LightYellow(255, 255, 224);\nconst color_t Lime(0, 255, 0);\nconst color_t LimeGreen(50, 205, 50);\nconst color_t Linen(250, 240, 230);\nconst color_t Magenta(255, 0, 255);\nconst color_t Maroon(128, 0, 0);\nconst color_t MediumAquaMarine(102, 205, 170);\nconst color_t MediumBlue(0, 0, 205);\nconst color_t MediumOrchid(186, 85, 211);\nconst color_t MediumPurple(147, 112, 219);\nconst color_t MediumSeaGreen(60, 179, 113);\nconst color_t MediumSlateBlue(123, 104, 238);\nconst color_t MediumSpringGreen(0, 250, 154);\nconst color_t MediumTurquoise(72, 209, 204);\nconst color_t MediumVioletRed(199, 21, 133);\nconst color_t MidnightBlue(25, 25, 112);\nconst color_t MintCream(245, 255, 250);\nconst color_t MistyRose(255, 228, 225);\nconst color_t Moccasin(255, 228, 181);\nconst color_t NavajoWhite(255, 222, 173);\nconst color_t Navy(0, 0, 128);\nconst color_t OldLace(253, 245, 230);\nconst color_t Olive(128, 128, 0);\nconst color_t OliveDrab(107, 142, 35);\nconst color_t Orange(255, 165, 0);\nconst color_t OrangeRed(255, 69, 0);\nconst color_t Orchid(218, 112, 214);\nconst color_t PaleGoldenRod(238, 232, 170);\nconst color_t PaleGreen(152, 251, 152);\nconst color_t PaleTurquoise(175, 238, 238);\nconst color_t PaleVioletRed(219, 112, 147);\nconst color_t PapayaWhip(225, 239, 213);\nconst color_t PeachPuff(225, 218, 185);\nconst color_t Peru(205, 133, 63);\nconst color_t Pink(255, 192, 203);\nconst color_t Plum(221, 160, 221);\nconst color_t PowderBlue(176, 224, 230);\nconst color_t Purple(128, 0, 128);\nconst color_t Red(255, 0, 0);\nconst color_t RosyBrown(188, 143, 143);\nconst color_t RoyalBlue(65, 105, 225);\nconst color_t SaddleBrown(139, 69, 19);\nconst color_t Salmon(250, 128, 114);\nconst color_t SandyBrown(244, 164, 96);\nconst color_t SeaGreen(46, 139, 87);\nconst color_t SeaShell(255, 245, 238);\nconst color_t Sienna(160, 82, 45);\nconst color_t Silver(192, 192, 192);\nconst color_t SkyBlue(135, 206, 235);\nconst color_t SlateBlue(106, 90, 205);\nconst color_t SlateGrey(112, 128, 144);\nconst color_t Snow(255, 250, 250);\nconst color_t SpringGreen(0, 255, 127);\nconst color_t SteelBlue(70, 130, 180);\nconst color_t Tan(210, 180, 140);\nconst color_t Teal(0, 128, 128);\nconst color_t Thistle(216, 191, 216);\nconst color_t Tomato(255, 99, 71);\nconst color_t Turquoise(64, 224, 208);\nconst color_t Violet(238, 130, 238);\nconst color_t Wheat(245, 222, 179);\nconst color_t White(255, 255, 255);\nconst color_t WhiteSmoke(245, 245, 245);\nconst color_t Yellow(255, 0, 0);\nconst color_t YellowGreen(154, 205, 50);\n\nconst color_t BLACK(0,0,0);\nconst color_t WHITE(255,255,255);\n\nconst color_t DESATURATED_RED(128,64,64);\nconst color_t LIGHTEST_RED(255,191,191);\nconst color_t LIGHTER_RED(255,166,166);\nconst color_t LIGHT_RED(255,115,115);\nconst color_t RED(255,0,0);\nconst color_t DARK_RED(191,0,0);\nconst color_t DARKER_RED(128,0,0);\nconst color_t DARKEST_RED(64,0,0);\nconst color_t FLAME(255,63,0);\nconst color_t ORANGE(255,127,0);\nconst color_t AMBER(255,191,0);\nconst color_t YELLOW(255,255,0);\nconst color_t LIME(191,255,0);\nconst color_t CHARTREUSE(127,255,0);\nconst color_t DESATURATED_GREEN(64,128,64);\nconst color_t LIGHTEST_GREEN(191,255,191);\nconst color_t LIGHTER_GREEN(166,255,166);\nconst color_t LIGHT_GREEN(115,255,115);\nconst color_t GREEN(0,255,0);\nconst color_t DARK_GREEN(0,191,0);\nconst color_t DARKER_GREEN(0,128,0);\nconst color_t DARKEST_GREEN(0,64,0);\nconst color_t SEA(0,255,127);\nconst color_t TURQUOISE(0,255,191);\nconst color_t CYAN(0,255,255);\nconst color_t SKY(0,191,255);\nconst color_t AZURE(0,127,255);\nconst color_t BLUE(0,0,255);\nconst color_t HAN(63,0,255);\nconst color_t VIOLET(127,0,255);\nconst color_t PURPLE(191,0,255);\nconst color_t FUCHSIA(255,0,191);\nconst color_t MAGENTA(255,0,255);\nconst color_t PINK(255,0,127);\nconst color_t CRIMSON(255,0,63);\n\nconst color_t BRASS(191,151,96);\nconst color_t COPPER(200,117,51);\nconst color_t GOLD(229,191,0);\nconst color_t SILVER(203,203,203);\n\nconst color_t CELADON(172,255,171);\nconst color_t PEACH(255,159,127);\n\nconst color_t LIGHTEST_GREY(223,223,223);\nconst color_t LIGHTER_GREY(191,191,191);\nconst color_t LIGHT_GREY(159,159,159);\nconst color_t GREY(127,127,127);\nconst color_t DARK_GREY(95,95,95);\nconst color_t DARKER_GREY(63,63,63);\nconst color_t DARKEST_GREY(31,31,31);\n\nconst color_t LIGHTEST_SEPIA(222,211,195);\nconst color_t LIGHTER_SEPIA(191,171,143);\nconst color_t LIGHT_SEPIA(158,134,100);\nconst color_t SEPIA(127,101,63);\nconst color_t DARK_SEPIA(94,75,47);\nconst color_t DARKER_SEPIA(63,50,31);\nconst color_t DARKEST_SEPIA(31,24,15);\n\n}\n}\n"
  },
  {
    "path": "rltk/ecs.cpp",
    "content": "#include \"ecs.hpp\"\n#include <cereal/types/polymorphic.hpp>\n#include <cereal/archives/binary.hpp>\n\nnamespace rltk {\n\nstd::size_t impl::base_component_t::type_counter = 1;\nstd::size_t base_message_t::type_counter = 1;\nstd::size_t entity_t::entity_counter{1}; // Not using zero since it is used as null so often\necs default_ecs;\n\nentity_t * ecs::entity(const std::size_t id) noexcept {\n\tentity_t * result = nullptr;\n\tauto finder = entity_store.find(id);\n\tif (finder == entity_store.end()) return result;\n\tif (finder->second.deleted) return result;\n\tresult = &finder->second;\n\treturn result;\n}\n\nentity_t * ecs::create_entity() {\n    entity_t new_entity;\n    while (entity_store.find(new_entity.id) != entity_store.end()) {\n        ++entity_t::entity_counter;\n        new_entity.id = entity_t::entity_counter;\n    }\n    //std::cout << \"New Entity ID#: \" << new_entity.id << \"\\n\";\n\n    entity_store.emplace(new_entity.id, new_entity);\n    return entity(new_entity.id);\n}\n\nentity_t * ecs::create_entity(const std::size_t new_id) {\n\tentity_t new_entity(new_id);\n    if (entity_store.find(new_entity.id) != entity_store.end()) {\n        throw std::runtime_error(\"WARNING: Duplicate entity ID. Odd things will happen\\n\");\n    }\n\tentity_store.emplace(new_entity.id, new_entity);\n\treturn entity(new_entity.id);\n}\n\nvoid ecs::each(std::function<void(entity_t &)> &&func) {\n\tfor (auto it=entity_store.begin(); it!=entity_store.end(); ++it) {\n\t\tif (!it->second.deleted) {\n\t\t\tfunc(it->second);\n\t\t}\n\t}\n}\n\n\nvoid ecs::delete_all_systems() {\n\tsystem_store.clear();\n\tsystem_profiling.clear();\n\tpubsub_holder.clear();\n}\n\nvoid ecs::ecs_configure() {\n\tfor (std::unique_ptr<base_system> & sys : system_store) {\n\t\tsys->configure();\n\t}\n}\n\nvoid ecs::ecs_tick(const double duration_ms) {\n\tstd::size_t count = 0;\n\tfor (std::unique_ptr<base_system> & sys : system_store) {\n\t\tstd::chrono::high_resolution_clock::time_point t1 = std::chrono::high_resolution_clock::now();\n\t\tsys->update(duration_ms);\n\t\tdeliver_messages();\n\t\tstd::chrono::high_resolution_clock::time_point t2 = std::chrono::high_resolution_clock::now();\n\t\tdouble duration = static_cast<double>(std::chrono::duration_cast<std::chrono::microseconds>( t2 - t1 ).count());\n\n\t\tsystem_profiling[count].last = duration;\n\t\tif (duration > system_profiling[count].worst) system_profiling[count].worst = duration;\n\t\tif (duration < system_profiling[count].best) system_profiling[count].best = duration;\n\t\t++count;\n\t}\n\tecs_garbage_collect();\n}\n\nvoid ecs::ecs_save(std::unique_ptr<std::ofstream> &lbfile) {\n    cereal::BinaryOutputArchive oarchive(*lbfile);\n    oarchive(*this);\n}\n\nvoid ecs::ecs_load(std::unique_ptr<std::ifstream> &lbfile) {\n\tentity_store.clear();\n\tcomponent_store.clear();\n    cereal::BinaryInputArchive iarchive(*lbfile);\n    iarchive(*this);\n    std::cout << \"Loaded \" << entity_store.size() << \" entities, and \" << component_store.size() << \" component types.\\n\";\n}\n\nstd::string ecs::ecs_profile_dump() {\n\tstd::stringstream ss;\n\tss.precision(3);\n\tss << std::fixed;\n\tss << \"SYSTEMS PERFORMANCE IN MICROSECONDS:\\n\";\n\tss << std::setw(20) << \"System\" << std::setw(20) << \"Last\" << std::setw(20) << \"Best\" << std::setw(20) << \"Worst\\n\";\n\tfor (std::size_t i=0; i<system_profiling.size(); ++i) {\n\t\tss << std::setw(20) << system_store[i]->system_name \n\t\t\t<< std::setw(20) << system_profiling[i].last \n\t\t\t<< std::setw(20) << system_profiling[i].best \n\t\t\t<< std::setw(20) << system_profiling[i].worst << \"\\n\";\n\t}\n\treturn ss.str();\n}\n\n}\n"
  },
  {
    "path": "rltk/ecs.hpp",
    "content": "#pragma once\n\n#include <bitset>\n#include <vector>\n#include <iostream>\n#include <unordered_map>\n#include <unordered_set>\n#include <memory>\n#include <functional>\n#include <algorithm>\n#include <fstream>\n#include <chrono>\n#include <sstream>\n#include <iomanip>\n#include <queue>\n#include <future>\n#include <mutex>\n#include <typeinfo>\n#include <atomic>\n#include \"serialization_utils.hpp\"\n#include \"xml.hpp\"\n#include <cereal/types/polymorphic.hpp>\n#include \"ecs_impl.hpp\"\n\nnamespace rltk {\n\n    /* Public interface to allow existing calls to continue to work */\n\n    extern ecs default_ecs;\n\n    inline entity_t * entity(ecs &ECS, const std::size_t id) noexcept {\n        return ECS.entity(id);\n    }\n\n    inline entity_t * entity(const std::size_t id) noexcept {\n        return entity(default_ecs, id);\n    }\n\n    inline entity_t * create_entity(ecs &ECS) {\n        return ECS.create_entity();\n    }\n\n    inline entity_t * create_entity() {\n        return create_entity(default_ecs);\n    }\n\n    inline entity_t * create_entity(ecs &ECS, const std::size_t new_id) {\n        return ECS.create_entity(new_id);\n    }\n\n    inline entity_t * create_entity(const std::size_t new_id) {\n        return create_entity(default_ecs, new_id);\n    }\n\n    inline void delete_entity(ecs &ECS, const std::size_t id) noexcept {\n        ECS.delete_entity(id);\n    }\n\n    inline void delete_entity(const std::size_t id) noexcept {\n        delete_entity(default_ecs, id);\n    }\n\n    inline void delete_entity(ecs &ECS, entity_t &e) noexcept {\n        ECS.delete_entity(e);\n    }\n\n    inline void delete_entity(entity_t &e) noexcept {\n        delete_entity(default_ecs, e);\n    }\n\n    inline void delete_all_entities(ecs &ECS) noexcept {\n        ECS.delete_all_entities();\n    }\n\n    inline void delete_all_entities() noexcept {\n        delete_all_entities(default_ecs);\n    }\n\n    template<class C>\n    inline void delete_component(ecs &ECS, const std::size_t entity_id, bool delete_entity_if_empty=false) noexcept {\n        ECS.delete_component<C>(entity_id, delete_entity_if_empty);\n    }\n\n    template<class C>\n    inline void delete_component(const std::size_t entity_id, bool delete_entity_if_empty=false) noexcept {\n        delete_component<C>(default_ecs, entity_id, delete_entity_if_empty);\n    }\n\n    template<class C>\n    inline std::vector<entity_t *> entities_with_component(ecs &ECS) {\n        return ECS.entities_with_component<C>();\n    }\n\n    template<class C>\n    inline std::vector<entity_t *> entities_with_component() {\n        return entities_with_component<C>(default_ecs);\n    }\n\n    template <class C>\n    inline void all_components(ecs &ECS, typename std::function<void(entity_t &, C &)> func) {\n        ECS.all_components<C>(func);\n    }\n\n    template <class C>\n    inline void all_components(typename std::function<void(entity_t &, C &)> func) {\n        all_components<C>(default_ecs, func);\n    }\n\n    template <typename... Cs, typename F>\n    inline void each(ecs &ECS, F callback) {\n        ECS.each<Cs...>(callback);\n    }\n\n    template <typename... Cs, typename F>\n    inline void each(F callback) {\n        each<Cs...>(default_ecs, callback);\n    }\n\n    template <typename... Cs, typename P, typename F>\n    inline void each_if(ecs &ECS, P&& predicate, F callback) {\n        ECS.each_if<Cs...>(predicate, callback);\n    }\n\n    template <typename... Cs, typename P, typename F>\n    inline void each_if(P&& predicate, F callback) {\n        each_if<Cs...>(default_ecs, predicate, callback);\n    }\n\n    inline void ecs_garbage_collect(ecs &ECS) {\n        ECS.ecs_garbage_collect();\n    }\n\n    inline void ecs_garbage_collect() {\n        ecs_garbage_collect(default_ecs);\n    }\n\n    template <class MSG>\n    inline void emit(ecs &ECS, MSG message) {\n        ECS.emit<MSG>(message);\n    }\n\n    template <class MSG>\n    inline void emit(MSG message) {\n        default_ecs.emit<MSG>(message);\n    }\n\n    template <class MSG>\n    inline void emit_deferred(ecs &ECS, MSG message) {\n        ECS.emit_deferred<MSG>(message);\n    }\n\n    template <class MSG>\n    inline void emit_deferred(MSG message) {\n        emit_deferred<MSG>(default_ecs, message);\n    }\n\n    template<typename S, typename ...Args>\n    inline void add_system( ecs &ECS, Args && ... args ) {\n        ECS.add_system<S, Args...>(args...);\n    }\n\n    template<typename S, typename ...Args>\n    inline void add_system( Args && ... args ) {\n        add_system<S, Args...>(default_ecs, args...);\n    }\n\n    inline void delete_all_systems(ecs &ECS) {\n        ECS.delete_all_systems();\n    }\n\n    inline void delete_all_systems() {\n        delete_all_systems(default_ecs);\n    }\n\n    inline void ecs_configure(ecs &ECS) {\n        ECS.ecs_configure();\n    }\n\n    inline void ecs_configure() {\n        ecs_configure(default_ecs);\n    }\n\n    inline void ecs_tick(ecs &ECS, const double duration_ms) {\n        ECS.ecs_tick(duration_ms);\n    }\n\n    inline void ecs_tick(const double duration_ms) {\n        ecs_tick(default_ecs, duration_ms);\n    }\n\n    inline void ecs_save(ecs &ECS, std::unique_ptr<std::ofstream> &lbfile) {\n        ECS.ecs_save(lbfile);\n    }\n\n    inline void ecs_save(std::unique_ptr<std::ofstream> &lbfile) {\n        ecs_save(default_ecs, lbfile);\n    }\n\n    inline void ecs_load(ecs &ECS, std::unique_ptr<std::ifstream> &lbfile) {\n        ECS.ecs_load(lbfile);\n    }\n\n    inline void ecs_load(std::unique_ptr<std::ifstream> &lbfile) {\n        ecs_load(default_ecs, lbfile);\n    }\n\n    inline std::string ecs_profile_dump(ecs &ECS) {\n        return ECS.ecs_profile_dump();\n    }\n\n    inline std::string ecs_profile_dump() {\n        return ecs_profile_dump(default_ecs);\n    }\n}\n"
  },
  {
    "path": "rltk/ecs_impl.hpp",
    "content": "#pragma once\n\n#include <cereal/cereal.hpp>\n#include <cereal/types/memory.hpp>\n#include <cereal/types/unordered_map.hpp>\n#include <cereal/types/bitset.hpp>\n#include <cereal/types/vector.hpp>\n\nnamespace rltk {\n\n    // Forward declarations\n    class ecs;\n    struct entity_t;\n    struct base_system;\n    extern ecs default_ecs;\n\n    namespace impl {\n\n        template<class C>\n        inline void assign(ecs &ECS, entity_t &E, C component);\n\n        template <class C>\n        inline C * component(ecs &ECS, entity_t &E) noexcept;\n\n        template<class MSG>\n        inline void subscribe(ecs &ECS, base_system &B, std::function<void(MSG &message)> destination);\n\n        template<class MSG>\n        inline void subscribe_mbox(ecs &ECS, base_system &B);\n\n        inline void unset_component_mask(ecs &ECS, const std::size_t id, const std::size_t family_id, bool delete_if_empty=false);\n    }\n\n    /*\n     * Base class from which all messages must derive.\n     */\n    struct base_message_t {\n        static std::size_t type_counter;\n    };\n\n    /* Class for storing profile data */\n    struct system_profiling_t {\n        double last = 0.0;\n        double best = 1000000.0;\n        double worst = 0.0;\n    };\n\n    struct base_system;\n\n    namespace impl {\n\n        /*\n         * Constant defining the maximum number of components to support. This sizes the bitsets,\n         * so we don't want it to be much bigger than needed.\n         */\n        constexpr std::size_t MAX_COMPONENTS = 128;\n\n        /*\n         * If the current component set does not support serialization, this will become true.\n         */\n        static bool ecs_supports_serialization = true;\n\n        /*\n         * Base type for component handles. Exists so that we can have a vector of pointers to\n         * derived classes. entity_id is included to allow a quick reference without a static cast.\n         * type_counter is used as a static member, referenced from component_t - the handle class.\n         */\n        struct base_component_t {\n            static std::size_t type_counter;\n            std::size_t entity_id;\n            bool deleted = false;\n\n            template<class Archive>\n            void serialize(Archive & archive)\n            {\n                archive( entity_id, deleted ); // serialize things by passing them to the archive\n            }\n        };\n\n        /* Extracts xml_identity from a class, or uses the RTTI name if one isn't available */\n        template< class T >\n        struct has_to_xml_identity\n        {\n            typedef char(&YesType)[1];\n            typedef char(&NoType)[2];\n            template< class, class > struct Sfinae;\n\n            template< class T2 > static YesType Test( Sfinae<T2, decltype(std::declval<T2>().xml_identity)> *);\n            template< class T2 > static NoType  Test( ... );\n            static const bool value = sizeof(Test<T>(0))==sizeof(YesType);\n        };\n\n        template <typename T>\n        struct _calc_xml_identity {\n\n            template<class Q = T>\n            typename std::enable_if< has_to_xml_identity<Q>::value, void >::type\n            test(T &data, std::string &id)\n            {\n                id = data.xml_identity;\n            }\n\n            template<class Q = T>\n            typename std::enable_if< !has_to_xml_identity<Q>::value, void >::type\n            test(T &data, std::string &id)\n            {\n                id = typeid(data).name();\n            }\n        };\n\n        template<class T>\n        struct _ecs_check_for_to_xml\n        {\n            template<class Q = T>\n            typename std::enable_if< serial::has_to_xml_method<Q>::value, void >::type\n            test(xml_node * c, T &data)\n            {\n                data.to_xml(c);\n            }\n\n            template<class Q = T>\n            typename std::enable_if< !serial::has_to_xml_method<Q>::value, void >::type\n            test(xml_node * c, T &data)\n            {\n                ecs_supports_serialization = false;\n            }\n        };\n\n        /*\n         * component_t is a handle class for components. It inherits from base_component, allowing\n         * the component store to have vectors of base_component_t *, where each type is a concrete\n         * specialized class containing the component data. It does some magic with a static type_counter\n         * to ensure that each instance with the same template type will have a unique family_id - this is\n         * then used to reference the correct component store.\n         */\n        template<class C>\n        struct component_t : public base_component_t {\n            component_t() {\n                data = C{};\n                family();\n            }\n            component_t(C comp) : data(comp) {\n                family();\n            }\n            std::size_t family_id;\n            C data;\n\n            template<class Archive>\n            void serialize(Archive & archive)\n            {\n                archive( cereal::base_class<base_component_t>(this), family_id, data ); // serialize things by passing them to the archive\n            }\n\n            inline void family() {\n                static std::size_t family_id_tmp = base_component_t::type_counter++;\n                family_id = family_id_tmp;\n            }\n\n            inline std::string xml_identity() {\n                std::string id;\n                _calc_xml_identity<C>().test(data, id);\n                return id;\n            }\n\n            inline void to_xml(xml_node * c) {\n                _ecs_check_for_to_xml<C> serial;\n                serial.test(c, data);\n            }\n        };\n\n        /*\n         * Base class for the component store. Concrete component stores derive from this.\n         */\n        struct base_component_store {\n            virtual void erase_by_entity_id(ecs &ECS, const std::size_t &id)=0;\n            virtual void really_delete()=0;\n            virtual void save(xml_node * xml)=0;\n            virtual std::size_t size()=0;\n\n            template<class Archive>\n            void serialize(Archive & archive)\n            {\n            }\n        };\n\n        /*\n         * Component stores are just a vector of type C (the component). They inherit from\n         * base_component_store, to allow for a vector of base_component_store*, with each\n         * casting to a concrete vector of that type. The types are indexed by the family_id\n         * created for a type with component_t<C>. This guarantees that each component type\n         * is stored in a big contiguous vector, with only one de-reference required to find\n         * the right store.\n         */\n        template<class C>\n        struct component_store_t : public base_component_store {\n            std::vector<C> components;\n\n            virtual void erase_by_entity_id(ecs &ECS, const std::size_t &id) override final {\n                for (auto &item : components) {\n                    if (item.entity_id == id) {\n                        item.deleted=true;\n                        impl::unset_component_mask(ECS, id, item.family_id);\n                    }\n                }\n            }\n\n            virtual void really_delete() override final {\n                components.erase(std::remove_if(components.begin(), components.end(),\n                                                [] (auto x) { return x.deleted; }),\n                                 components.end());\n            }\n\n            virtual void save(xml_node * xml) override final {\n                for (auto &item : components) {\n                    xml_node * body = xml->add_node(item.xml_identity());\n                    item.to_xml(body);\n                    body->add_value(\"entity_id\", rltk::serial::to_string(item.entity_id));\n                }\n            }\n\n            virtual std::size_t size() override final {\n                return components.size();\n            }\n\n            template<class Archive>\n            void serialize(Archive & archive)\n            {\n                archive( cereal::base_class<base_component_store>(this), components ); // serialize things by passing them to the archive\n            }\n\n        };\n\n        /*\n         * Handle class for messages\n         */\n        template<class C>\n        struct message_t : public base_message_t {\n            message_t() {\n                C empty;\n                data = empty;\n                family();\n            }\n            message_t(C comp) : data(comp) {\n                family();\n            }\n            std::size_t family_id;\n            C data;\n\n            inline void family() {\n                static std::size_t family_id_tmp = base_message_t::type_counter++;\n                family_id = family_id_tmp;\n            }\n        };\n\n        /*\n         * Base class for storing subscriptions to messages\n         */\n        struct subscription_base_t {\n            virtual void deliver_messages()=0;\n        };\n\n        /* Base class for subscription mailboxes */\n        struct subscription_mailbox_t {\n        };\n\n        /* Implementation class for mailbox subscriptions; stores a queue */\n        template <class C>\n        struct mailbox_t : subscription_mailbox_t {\n            std::queue<C> messages;\n        };\n\n        /*\n         * Class that holds subscriptions, and determines delivery mechanism.\n         */\n        template <class C>\n        struct subscription_holder_t : subscription_base_t {\n            std::queue<C> delivery_queue;\n            std::mutex delivery_mutex;\n            std::vector<std::tuple<bool,std::function<void(C& message)>,base_system *>> subscriptions;\n\n            virtual void deliver_messages() override {\n                std::lock_guard<std::mutex> guard(delivery_mutex);\n                while (!delivery_queue.empty()) {\n                    C message = delivery_queue.front();\n                    delivery_queue.pop();\n                    message_t<C> handle(message);\n\n                    for (auto &func : subscriptions) {\n                        if (std::get<0>(func) && std::get<1>(func)) {\n                            std::get<1>(func)(message);\n                        } else {\n                            // It is destined for the system's mailbox queue.\n                            auto finder = std::get<2>(func)->mailboxes.find(handle.family_id);\n                            if (finder != std::get<2>(func)->mailboxes.end()) {\n                                static_cast<mailbox_t<C> *>(finder->second.get())->messages.push(message);\n                            }\n                        }\n                    }\n                }\n            }\n        };\n\n    } // End impl namespace\n\n    /*\n     * All entities are of type entity_t. They should be created with create_entity (below).\n     */\n    struct entity_t {\n\n        /*\n         * Default constructor - use the next available entity id #.\n         */\n        entity_t() {\n            ++entity_t::entity_counter;\n            id = entity_t::entity_counter;\n        }\n\n        /*\n         * Construct with a specified entity #. Moves the next available entity # to this id+1.\n         */\n        entity_t(const std::size_t ID) {\n            entity_t::entity_counter = ID+1;\n            id = ID;\n        }\n\n        /*\n         * Static ID counter - used to ensure that entity IDs are unique. This would need to be atomic\n         * in a threaded app.\n         */\n        static std::size_t entity_counter;\n\n        /*\n         * The entities ID number. Used to identify the entity. These should be unique.\n         */\n        std::size_t id;\n\n        /*\n         * Overload == and != to allow entities to be compared for likeness.\n         */\n        bool operator == (const entity_t &other) const { return other.id == id; }\n        bool operator != (const entity_t &other) const { return other.id != id; }\n\n        bool deleted = false;\n\n        /*\n         * A bitset storing whether or not an entity has each component type. These are set with the family_id\n         * determined in the component_t system above.\n         */\n        std::bitset<impl::MAX_COMPONENTS> component_mask;\n\n        /*\n         * Assign a component to this entity. Determines the family_id of the component type, sets the bitmask to\n         * include the component, marks the component as belonging to the entity, and puts it in the appropriate\n         * component store.\n         */\n        template<class C>\n        inline entity_t * assign(ecs &ECS, C component) {\n            if (deleted) throw std::runtime_error(\"Cannot assign to a deleted entity\");\n            impl::assign<C>(ECS, *this, component);\n            return this;\n        }\n\n        template<class C>\n        inline entity_t * assign(C component) {\n            return assign<C>(default_ecs, component);\n        }\n\n        /*\n         * Find a component of the specified type that belongs to the entity.\n         */\n        template <class C>\n        inline C * component(ecs &ECS) noexcept {\n            return impl::component<C>(ECS, *this);\n        }\n\n        template <class C>\n        inline C * component() noexcept {\n            return component<C>(default_ecs);\n        }\n\n        template<class Archive>\n        void serialize(Archive & archive)\n        {\n            archive( component_mask, id, deleted ); // serialize things by passing them to the archive\n        }\n    };\n\n    /*\n     * Systems should inherit from this class.\n     */\n    struct base_system {\n        virtual void configure() {}\n        virtual void update(const double duration_ms)=0;\n        std::string system_name = \"Unnamed System\";\n        std::unordered_map<std::size_t, std::unique_ptr<impl::subscription_mailbox_t>> mailboxes;\n\n        template<class MSG>\n        void subscribe(ecs &ECS, std::function<void(MSG &message)> destination) {\n            impl::subscribe<MSG>(ECS, *this, destination);\n        }\n\n        template<class MSG>\n        void subscribe(std::function<void(MSG &message)> destination) {\n            subscribe<MSG>(default_ecs, destination);\n        }\n\n        template<class MSG>\n        void subscribe_mbox(ecs &ECS) {\n            impl::subscribe_mbox<MSG>(ECS, *this);\n        }\n\n        template<class MSG>\n        void subscribe_mbox() {\n            subscribe_mbox<MSG>(default_ecs);\n        }\n\n        template<class MSG>\n        std::queue<MSG> * mbox() {\n            impl::message_t<MSG> handle(MSG{});\n            auto finder = mailboxes.find(handle.family_id);\n            if (finder != mailboxes.end()) {\n                return &static_cast<impl::mailbox_t<MSG> *>(finder->second.get())->messages;\n            } else {\n                return nullptr;\n            }\n        }\n\n        template<class MSG>\n        void each_mbox(const std::function<void(const MSG&)> &func) {\n            std::queue<MSG> * mailbox = mbox<MSG>();\n            while (!mailbox->empty()) {\n                MSG msg = mailbox->front();\n                mailbox->pop();\n                func(msg);\n            }\n        }\n    };\n\n    /* A pre-implemented simple system for systems that only handle messages. */\n    template <class MSG>\n    struct mailbox_system : public base_system {\n        virtual void configure() override final {\n            subscribe_mbox<MSG>();\n        }\n\n        virtual void update(const double duration_ms) override final {\n            std::queue<MSG> * mailbox = base_system::mbox<MSG>();\n            while (!mailbox->empty()) {\n                MSG msg = mailbox->front();\n                mailbox->pop();\n                on_message(msg);\n            }\n        }\n\n        virtual void on_message(const MSG &msg)=0;\n    };\n\n    /*\n * Class that holds an entity-component-system. This was moved to a class to allow for multiple instances.\n */\n    class ecs {\n    public:\n        /*\n         * entity(ID) is used to reference an entity. So you can, for example, do:\n         * entity(12)->component<position_component>()->x = 3;\n         */\n        entity_t * entity(const std::size_t id) noexcept;\n\n        /*\n         * Creates an entity with a new ID #. Returns a pointer to the entity, to enable\n         * call chaining. For example create_entity()->assign(foo)->assign(bar)\n         */\n        entity_t * create_entity();\n\n        /*\n         * Creates an entity with a specified ID #. You generally only do this during loading.\n         */\n        entity_t * create_entity(const std::size_t new_id);\n\n        /*\n         * Marks an entity (specified by ID#) as deleted.\n         */\n        inline void delete_entity(const std::size_t id) noexcept {\n            auto e = entity(id);\n            if (!e) return;\n\n            e->deleted = true;\n            for (auto &store : component_store) {\n                if (store) store->erase_by_entity_id(*this, id);\n            }\n        }\n\n        /*\n         * Marks an entity as deleted.\n         */\n        inline void delete_entity(entity_t &e) noexcept {\n            delete_entity(e.id);\n        }\n\n        /*\n         * Deletes all entities\n         */\n        inline void delete_all_entities() noexcept  {\n            for (auto it=entity_store.begin(); it!=entity_store.end(); ++it) {\n                delete_entity(it->first);\n            }\n        }\n\n        /*\n         * Marks an entity's component as deleted.\n         */\n        template<class C>\n        inline void delete_component(const std::size_t entity_id, bool delete_entity_if_empty=false) noexcept {\n            auto eptr = entity(entity_id);\n            if (!eptr) return;\n            entity_t e = *entity(entity_id);\n            C empty_component;\n            impl::component_t<C> temp(empty_component);\n            if (!e.component_mask.test(temp.family_id)) return;\n            for (impl::component_t<C> &component : static_cast<impl::component_store_t<impl::component_t<C>> *>(component_store[temp.family_id].get())->components) {\n                if (component.entity_id == entity_id) {\n                    component.deleted = true;\n                    unset_component_mask(entity_id, temp.family_id, delete_entity_if_empty);\n                }\n            }\n        }\n\n        /*\n         * Finds all entities that have a component of the type specified, and returns a\n         * vector of pointers to the entities. It does not check for component deletion.\n         */\n        template<class C>\n        inline std::vector<entity_t *> entities_with_component() {\n            C empty_component;\n            std::vector<entity_t *> result;\n            impl::component_t<C> temp(empty_component);\n            for (auto it=entity_store.begin(); it!=entity_store.end(); ++it) {\n                if (!it->second.deleted && it->second.component_mask.test(temp.family_id)) {\n                    result.push_back(&it->second);\n                }\n            }\n            return result;\n        }\n\n        /*\n         * all_components takes a component type, and calls the provided function/lambda on\n         * every component, alongside it's owning entity. For example,\n         * all_components<position>([] (entity_t &e, position &p) {...}) would execute the\n         * function body (...) for every entity/component position pair.\n         */\n        template <class C>\n        inline void all_components(typename std::function<void(entity_t &, C &)> func) {\n            C empty_component;\n            impl::component_t<C> temp(empty_component);\n            for (impl::component_t<C> &component : static_cast<impl::component_store_t<impl::component_t<C>> *>(component_store[temp.family_id].get())->components) {\n                entity_t e = *entity(component.entity_id);\n                if (!e.deleted && !component.deleted) {\n                    func(e, component.data);\n                }\n            }\n        }\n\n        /*\n         * each, overloaded with a function/lambda that accepts an entity, will call the provided\n         * function on _every_ entity in the system.\n         */\n        void each(std::function<void(entity_t &)> &&func);\n\n        /*\n         * Variadic each. Use this to call a function for all entities having a discrete set of components. For example,\n         * each<position, ai>([] (entity_t &e, position &pos, ai &brain) { ... code ... });\n         */\n        template <typename... Cs, typename F>\n        inline void each(F callback) {\n            std::array<size_t, sizeof...(Cs)> family_ids{ {impl::component_t<Cs>{}.family_id...} };\n            for (auto it=entity_store.begin(); it!=entity_store.end(); ++it) {\n                if (!it->second.deleted) {\n                    bool matches = true;\n                    for (const std::size_t &compare : family_ids) {\n                        if (!it->second.component_mask.test(compare)) {\n                            matches = false;\n                            break;\n                        }\n                    }\n                    if (matches) {\n                        // Call the functor\n                        callback(it->second, *it->second.component<Cs>()...);\n                    }\n                }\n            }\n        }\n\n        /*\n         * Variadic each_if. Use this to call a function for all entities having a discrete set of components. For example,\n         * each<position, ai>([] (entity_t &e, position &pos, ai &brain) { ... code returns true if needs processing ... },\n         * [] (entity_t &e, position &pos, ai &brain) { ... code ... });\n         */\n        template <typename... Cs, typename P, typename F>\n        inline void each_if(P&& predicate, F callback) {\n            std::array<size_t, sizeof...(Cs)> family_ids{ {impl::component_t<Cs>{}.family_id...} };\n            for (auto it=entity_store.begin(); it!=entity_store.end(); ++it) {\n                if (!it->second.deleted) {\n                    bool matches = true;\n                    for (const std::size_t &compare : family_ids) {\n                        if (!it->second.component_mask.test(compare)) {\n                            matches = false;\n                            break;\n                        }\n                    }\n                    if (matches && predicate(it->second, *it->second.component<Cs>()...)) {\n                        // Call the functor\n                        callback(it->second, *it->second.component<Cs>()...);\n                    }\n                }\n            }\n        }\n\n        /*\n         * This should be called periodically to actually erase all entities and components that are marked as deleted.\n         */\n        inline void ecs_garbage_collect() {\n            std::unordered_set<std::size_t> entities_to_delete;\n\n            // Ensure that components are marked as deleted, and list out entities for erasure\n            for (auto it=entity_store.begin(); it!=entity_store.end(); ++it) {\n                if (it->second.deleted) {\n                    for (std::unique_ptr<impl::base_component_store> &store : component_store) {\n                        if (store) store->erase_by_entity_id(*this, it->second.id);\n                    }\n                    entities_to_delete.insert(it->second.id);\n                }\n            }\n\n            // Actually delete entities\n            for (const std::size_t &id : entities_to_delete) entity_store.erase(id);\n\n            // Now we erase components\n            for (std::unique_ptr<impl::base_component_store> &store : component_store) {\n                if (store) store->really_delete();\n            }\n        }\n\n        /*\n         * Submits a message for delivery. It will be delivered to every system that has issued a subscribe or subscribe_mbox\n         * call.\n         */\n        template <class MSG>\n        inline void emit(MSG message) {\n            impl::message_t<MSG> handle(message);\n            if (pubsub_holder.size() > handle.family_id) {\n                for (auto &func : static_cast<impl::subscription_holder_t<MSG> *>(pubsub_holder[handle.family_id].get())->subscriptions) {\n                    if (std::get<0>(func) && std::get<1>(func)) {\n                        std::get<1>(func)(message);\n                    } else {\n                        // It is destined for the system's mailbox queue.\n                        auto finder = std::get<2>(func)->mailboxes.find(handle.family_id);\n                        if (finder != std::get<2>(func)->mailboxes.end()) {\n                            static_cast<impl::mailbox_t<MSG> *>(finder->second.get())->messages.push(message);\n                        }\n                    }\n                }\n            }\n        }\n\n        /*\n         * Submits a message for delivery. It will be delivered to every system that has issued a subscribe or subscribe_mbox\n         * call at the end of the next system execution. This is thead-safe, so you can emit_defer from within a parallel_each.\n         */\n        template <class MSG>\n        inline void emit_deferred(MSG message) {\n            impl::message_t<MSG> handle(message);\n            if (pubsub_holder.size() > handle.family_id) {\n\n                auto * subholder = static_cast<impl::subscription_holder_t<MSG> *>(pubsub_holder[handle.family_id].get());\n                std::lock_guard<std::mutex> postlock(subholder->delivery_mutex);\n                subholder->delivery_queue.push(message);\n            }\n        }\n\n        /* Add a system to the mix */\n        template<typename S, typename ...Args>\n        inline void add_system( Args && ... args ) {\n            system_store.push_back(std::make_unique<S>( std::forward<Args>(args) ... ));\n            system_profiling.push_back(system_profiling_t{});\n        }\n\n        void delete_all_systems();\n\n        void ecs_configure();\n\n        void ecs_tick(const double duration_ms);\n\n        void ecs_save(std::unique_ptr<std::ofstream> &lbfile);\n\n        void ecs_load(std::unique_ptr<std::ifstream> &lbfile);\n\n        std::string ecs_profile_dump();\n\n        // The ECS component store\n        std::vector<std::unique_ptr<impl::base_component_store>> component_store;\n\n        // The ECS entity store\n        std::unordered_map<std::size_t, entity_t> entity_store;\n\n        // Mailbox system\n        std::vector<std::unique_ptr<impl::subscription_base_t>> pubsub_holder;\n\n        // Storage of systems\n        std::vector<std::unique_ptr<base_system>> system_store;\n\n        // Profile data storage\n        std::vector<system_profiling_t> system_profiling;\n\n        // Helpers\n        inline void unset_component_mask(const std::size_t id, const std::size_t family_id, bool delete_if_empty) {\n            auto finder = entity_store.find(id);\n            if (finder != entity_store.end()) {\n                finder->second.component_mask.reset(family_id);\n                if (delete_if_empty && finder->second.component_mask.none()) finder->second.deleted = true;\n            }\n        }\n\n        /* Delivers the queue; called at the end of each system call */\n        inline void deliver_messages() {\n            for (auto &holder : pubsub_holder) {\n                if (holder) holder->deliver_messages();\n            }\n        }\n\n        /*\n         * Cereal support for save/load\n         */\n        template<class Archive>\n        void serialize(Archive & archive)\n        {\n            archive( entity_store, component_store, entity_t::entity_counter, impl::base_component_t::type_counter ); // serialize things by passing them to the archive\n        }\n    };\n\n    namespace impl {\n        template <class C>\n        inline void assign(ecs &ECS, entity_t &E, C component) {\n            impl::component_t<C> temp(component);\n            temp.entity_id = E.id;\n            if (ECS.component_store.size() < temp.family_id+1) {\n                ECS.component_store.resize(temp.family_id+1);\n            }\n            if (!ECS.component_store[temp.family_id]) ECS.component_store[temp.family_id] = std::move(std::make_unique<impl::component_store_t<impl::component_t<C>>>());\n\n            static_cast<impl::component_store_t<impl::component_t<C>> *>(ECS.component_store[temp.family_id].get())->components.push_back(temp);\n            E.component_mask.set(temp.family_id);\n        }\n\n        template <class C>\n        inline C * component(ecs &ECS, entity_t &E) noexcept {\n            C * result = nullptr;\n            if (E.deleted) return result;\n\n            C empty_component;\n            impl::component_t<C> temp(empty_component);\n            if (!E.component_mask.test(temp.family_id)) return result;\n            for (impl::component_t<C> &component : static_cast<impl::component_store_t<impl::component_t<C>> *>(ECS.component_store[temp.family_id].get())->components) {\n                if (component.entity_id == E.id) {\n                    result = &component.data;\n                    return result;\n                }\n            }\n            return result;\n        }\n\n        template<class MSG>\n        inline void subscribe(ecs &ECS, base_system &B, std::function<void(MSG &message)> destination) {\n            MSG empty_message{};\n            impl::message_t<MSG> handle(empty_message);\n            if (ECS.pubsub_holder.size() < handle.family_id + 1) {\n                ECS.pubsub_holder.resize(handle.family_id + 1);\n            }\n            if (!ECS.pubsub_holder[handle.family_id]) {\n                ECS.pubsub_holder[handle.family_id] = std::move(std::make_unique<subscription_holder_t<MSG>>());\n            }\n            static_cast<subscription_holder_t<MSG> *>(ECS.pubsub_holder[handle.family_id].get())->subscriptions.push_back(std::make_tuple(true,destination,nullptr));\n        }\n\n        template<class MSG>\n        inline void subscribe_mbox(ecs &ECS, base_system &B) {\n            MSG empty_message{};\n            impl::message_t<MSG> handle(empty_message);\n            if (ECS.pubsub_holder.size() < handle.family_id + 1) {\n                ECS.pubsub_holder.resize(handle.family_id + 1);\n            }\n            if (!ECS.pubsub_holder[handle.family_id]) {\n                ECS.pubsub_holder[handle.family_id] = std::move(std::make_unique<subscription_holder_t<MSG>>());\n            }\n            std::function<void(MSG &message)> destination; // Deliberately empty\n            static_cast<impl::subscription_holder_t<MSG> *>(ECS.pubsub_holder[handle.family_id].get())->subscriptions.push_back(std::make_tuple(false,destination,&B));\n            B.mailboxes[handle.family_id] = std::make_unique<impl::mailbox_t<MSG>>();\n        }\n\n        inline void unset_component_mask(ecs &ECS, const std::size_t id, const std::size_t family_id, bool delete_if_empty) {\n            ECS.unset_component_mask(id, family_id, delete_if_empty);\n        }\n    }\n\n} // End RLTK namespace\n\nCEREAL_REGISTER_ARCHIVE(rltk::ecs)\n"
  },
  {
    "path": "rltk/filesystem.hpp",
    "content": "/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed under the MIT license - see LICENSE file.\n *\n * Minimal filesystem tools\n */\n#pragma once\n\n#include <string>\n#include <sys/stat.h>\n\nnamespace rltk {\n\ninline bool exists(const std::string &filename) noexcept {\n    struct stat buffer;\n    return (stat (filename.c_str(), &buffer) == 0);\n}\n\n}\n"
  },
  {
    "path": "rltk/font_manager.cpp",
    "content": "#include \"font_manager.hpp\"\n#include \"texture_resources.hpp\"\n#include <unordered_map>\n#include <stdexcept>\n#include <iostream>\n#include <sstream>\n#include <fstream>\n#include \"filesystem.hpp\"\n\nnamespace rltk {\n\nnamespace font_detail {\n\nstd::vector<std::string> split ( const std::string &str, const char &delimiter )\n{\n     std::vector<std::string> internal;\n     std::stringstream ss ( str ); // Turn the string into a stream.\n     std::string tok;\n\n     while ( getline ( ss, tok, delimiter ) ) {\n          internal.push_back ( tok );\n     }\n\n     return internal;\n}\n\nstd::unordered_map<std::string, rltk::bitmap_font> atlas;\n}\n\nbitmap_font * get_font(const std::string font_tag) {\n\tauto finder = font_detail::atlas.find(font_tag);\n\tif (finder == font_detail::atlas.end()) {\n\t\tthrow std::runtime_error(\"Unable to locate bitmap font with tag \" + font_tag);\n\t} else {\n\t\treturn &finder->second;\n\t}\n}\n\ninline void check_for_duplicate_font(const std::string &tag) {\n\tauto finder = font_detail::atlas.find(tag);\n\tif (finder != font_detail::atlas.end()) {\n\t\tthrow std::runtime_error(\"Attempting to insert duplicate font with tag \" + tag);\n\t}\n}\n\ninline void check_texture_exists(const std::string &texture_tag) {\n\tif (get_texture(texture_tag) == nullptr) {\n\t\tthrow std::runtime_error(\"No such texture resource: \" + texture_tag);\n\t}\n}\n\nvoid register_font(const std::string font_tag, const std::string filename, int width, int height) {\n\tconst std::string texture_tag = \"font_tex_\" + filename;\n\tcheck_for_duplicate_font(font_tag);\n\tregister_texture(filename, texture_tag);\n\tcheck_texture_exists(texture_tag);\t\n\tfont_detail::atlas.emplace(std::make_pair(font_tag, bitmap_font(texture_tag, width, height)));\n}\n\nvoid register_font_directory(const std::string path) {\n\tif (!exists(path)) throw std::runtime_error(\"Font directory does not exist.\");\n\tconst std::string info_file = path + \"/fonts.txt\";\n\tif (!exists(info_file)) throw std::runtime_error(\"No fonts.txt file in font directory.\");\n\n\tstd::ifstream f(info_file);\n\tstd::string line;\n\twhile (getline(f, line)) {\n\t\tauto split = font_detail::split(line, ',');\n\t\tif (split.size() == 4) {\n\t\t\tregister_font(split[0], path + \"/\" + split[1], std::stoi(split[2]), std::stoi(split[3]));\n\t\t}\n\t}\n\n\t/*\n\tptree font_tree;\n\tread_json(info_file, font_tree);\n\n\tptree::const_iterator end = font_tree.get_child(\"fonts\").end();\n    for (ptree::const_iterator it = font_tree.get_child(\"fonts\").begin(); it != end; ++it) {\n    \tconst std::string font_name = it->first;\n    \tconst std::string font_tree_path = \"fonts.\" + font_name + \".\";\n    \tconst std::string font_file = font_tree.get<std::string>(font_tree_path + \"file\");\n    \tconst int width = font_tree.get<int>(font_tree_path + \"width\");\n    \tconst int height = font_tree.get<int>(font_tree_path + \"height\");\n\n    \tregister_font(font_name, path + \"/\" + font_file, width, height);\n    }*/\n}\n\n}\n"
  },
  {
    "path": "rltk/font_manager.hpp",
    "content": "/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed under the MIT license - see LICENSE file.\n *\n * Font manager\n */\n\n#pragma once\n\n#include <string>\n#include <utility>\n\nnamespace rltk {\n\nstruct bitmap_font {\n\tbitmap_font(const std::string tag, const int width, const int height) : texture_tag(tag), character_size({width,height}) {}\n\n\tconst std::string texture_tag;\n\tconst std::pair<int,int> character_size;\n};\n\nvoid register_font_directory(const std::string path);\nbitmap_font * get_font(const std::string font_tag);\nvoid register_font(const std::string font_tag, const std::string filename, int width=8, int height=8);\n\n\n}"
  },
  {
    "path": "rltk/fsa.hpp",
    "content": "/* \n\n A* Algorithm Implementation using STL is\n Copyright (C)2001-2005 Justin Heyes-Jones\n\n Permission is given by the author to freely redistribute and \n include this code in any program as long as this credit is \n given where due.\n \n COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN \"AS IS\" BASIS, \n WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, \n INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE \n IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE\n OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND \n PERFORMANCE OF THE COVERED CODE IS WITH YOU. SHOULD ANY COVERED \n CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL \n DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY \n NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF \n WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE \n OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER\n THIS DISCLAIMER.\n \n Use at your own risk!\n\n\n\n FixedSizeAllocator class\n Copyright 2001 Justin Heyes-Jones\n\n This class is a constant time O(1) memory manager for objects of \n a specified type. The type is specified using a template class.\n\n Memory is allocated from a fixed size buffer which you can specify in the\n class constructor or use the default.\n\n Using GetFirst and GetNext it is possible to iterate through the elements\n one by one, and this would be the most common use for the class. \n\n I would suggest using this class when you want O(1) add and delete\n and you don't do much searching, which would be O(n). Structures such as binary \n trees can be used instead to get O(logn) access time.\n\n */\n\n#pragma once\n\n#include <string.h>\n#include <stdio.h>\n\ntemplate<class USER_TYPE> class FixedSizeAllocator\n{\n\npublic:\n\t// Constants\n\tenum\n\t{\n\t\tFSA_DEFAULT_SIZE = 100\n\t};\n\n\t// This class enables us to transparently manage the extra data \n\t// needed to enable the user class to form part of the double-linked\n\t// list class\n\tstruct FSA_ELEMENT\n\t{\n\t\tUSER_TYPE UserType;\n\n\t\tFSA_ELEMENT *pPrev;\n\t\tFSA_ELEMENT *pNext;\n\t};\n\npublic:\n\t// methods\n\tFixedSizeAllocator(unsigned int MaxElements = FSA_DEFAULT_SIZE) :\n\t\t\tm_pFirstUsed(NULL), m_MaxElements(MaxElements)\n\t{\n\t\t// Allocate enough memory for the maximum number of elements\n\n\t\tchar *pMem = new char[m_MaxElements * sizeof(FSA_ELEMENT)];\n\n\t\tm_pMemory = (FSA_ELEMENT *) pMem;\n\n\t\t// Set the free list first pointer\n\t\tm_pFirstFree = m_pMemory;\n\n\t\t// Clear the memory\n\t\tmemset(m_pMemory, 0, sizeof(FSA_ELEMENT) * m_MaxElements);\n\n\t\t// Point at first element\n\t\tFSA_ELEMENT *pElement = m_pFirstFree;\n\n\t\t// Set the double linked free list\n\t\tfor (unsigned int i = 0; i < m_MaxElements; i++)\n\t\t{\n\t\t\tpElement->pPrev = pElement - 1;\n\t\t\tpElement->pNext = pElement + 1;\n\n\t\t\tpElement++;\n\t\t}\n\n\t\t// first element should have a null prev\n\t\tm_pFirstFree->pPrev = NULL;\n\t\t// last element should have a null next\n\t\t(pElement - 1)->pNext = NULL;\n\n\t}\n\n\t~FixedSizeAllocator()\n\t{\n\t\t// Free up the memory\n\t\tdelete[] (char *) m_pMemory;\n\t}\n\n\t// Allocate a new USER_TYPE and return a pointer to it \n\tUSER_TYPE *alloc()\n\t{\n\n\t\tFSA_ELEMENT *pNewNode = NULL;\n\n\t\tif (!m_pFirstFree)\n\t\t{\n\t\t\treturn NULL;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tpNewNode = m_pFirstFree;\n\t\t\tm_pFirstFree = pNewNode->pNext;\n\n\t\t\t// if the new node points to another free node then\n\t\t\t// change that nodes prev free pointer...\n\t\t\tif (pNewNode->pNext)\n\t\t\t{\n\t\t\t\tpNewNode->pNext->pPrev = NULL;\n\t\t\t}\n\n\t\t\t// node is now on the used list\n\n\t\t\tpNewNode->pPrev = NULL; // the allocated node is always first in the list\n\n\t\t\tif (m_pFirstUsed == NULL)\n\t\t\t{\n\t\t\t\tpNewNode->pNext = NULL; // no other nodes\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tm_pFirstUsed->pPrev = pNewNode; // insert this at the head of the used list\n\t\t\t\tpNewNode->pNext = m_pFirstUsed;\n\t\t\t}\n\n\t\t\tm_pFirstUsed = pNewNode;\n\t\t}\n\n\t\treturn reinterpret_cast<USER_TYPE*>(pNewNode);\n\t}\n\n\t// Free the given user type\n\t// For efficiency I don't check whether the user_data is a valid\n\t// pointer that was allocated. I may add some debug only checking\n\t// (To add the debug check you'd need to make sure the pointer is in \n\t// the m_pMemory area and is pointing at the start of a node)\n\tvoid free(USER_TYPE *user_data)\n\t{\n\t\tFSA_ELEMENT *pNode = reinterpret_cast<FSA_ELEMENT*>(user_data);\n\n\t\t// manage used list, remove this node from it\n\t\tif (pNode->pPrev)\n\t\t{\n\t\t\tpNode->pPrev->pNext = pNode->pNext;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// this handles the case that we delete the first node in the used list\n\t\t\tm_pFirstUsed = pNode->pNext;\n\t\t}\n\n\t\tif (pNode->pNext)\n\t\t{\n\t\t\tpNode->pNext->pPrev = pNode->pPrev;\n\t\t}\n\n\t\t// add to free list\n\t\tif (m_pFirstFree == NULL)\n\t\t{\n\t\t\t// free list was empty\n\t\t\tm_pFirstFree = pNode;\n\t\t\tpNode->pPrev = NULL;\n\t\t\tpNode->pNext = NULL;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Add this node at the start of the free list\n\t\t\tm_pFirstFree->pPrev = pNode;\n\t\t\tpNode->pNext = m_pFirstFree;\n\t\t\tm_pFirstFree = pNode;\n\t\t}\n\n\t}\n\n\t// For debugging this displays both lists (using the prev/next list pointers)\n\tvoid Debug()\n\t{\n\t\tprintf(\"free list \");\n\n\t\tFSA_ELEMENT *p = m_pFirstFree;\n\t\twhile (p)\n\t\t{\n\t\t\tprintf(\"%x!%x \", p->pPrev, p->pNext);\n\t\t\tp = p->pNext;\n\t\t}\n\t\tprintf(\"\\n\");\n\n\t\tprintf(\"used list \");\n\n\t\tp = m_pFirstUsed;\n\t\twhile (p)\n\t\t{\n\t\t\tprintf(\"%x!%x \", p->pPrev, p->pNext);\n\t\t\tp = p->pNext;\n\t\t}\n\t\tprintf(\"\\n\");\n\t}\n\n\t// Iterators\n\n\tUSER_TYPE *GetFirst()\n\t{\n\t\treturn reinterpret_cast<USER_TYPE *>(m_pFirstUsed);\n\t}\n\n\tUSER_TYPE *GetNext(USER_TYPE *node)\n\t{\n\t\treturn reinterpret_cast<USER_TYPE *>((reinterpret_cast<FSA_ELEMENT *>(node))->pNext);\n\t}\n\npublic:\n\t// data\n\nprivate:\n\t// methods\n\nprivate:\n\t// data\n\n\tFSA_ELEMENT *m_pFirstFree;\n\tFSA_ELEMENT *m_pFirstUsed;\n\tunsigned int m_MaxElements;\n\tFSA_ELEMENT *m_pMemory;\n\n};\n"
  },
  {
    "path": "rltk/geometry.cpp",
    "content": "#include \"geometry.hpp\"\n#include <cstdlib>\n#include <cmath>\n\nnamespace rltk {\n\n/*\n * From a given point x/y, project forward radius units (generally tiles) at an angle of degrees_radians degrees\n * (in radians).\n */\nstd::pair<int, int> project_angle(const int &x, const int &y, const double &radius, const double &degrees_radians) noexcept\n{\n\treturn std::make_pair(static_cast<int>(x + radius * std::cos(degrees_radians)), static_cast<int>(y + radius * std::sin(degrees_radians)));\n}\n\n}"
  },
  {
    "path": "rltk/geometry.hpp",
    "content": "#pragma once\n\n/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed under the MIT license - see LICENSE file.\n *\n * Random number generator class.\n */\n\n#include <functional>\n#include <utility>\n#include <cmath>\n\nnamespace rltk {\n\n/*\n * From a given point x/y, project forward radius units (generally tiles) at an angle of degrees_radians degrees\n * (in radians).\n */\nstd::pair<int, int> project_angle(const int &x, const int &y, const double &radius, const double &degrees_radians) noexcept;\n\n/*\n * Provides a correct 2D distance between two points.\n */\ninline float distance2d(const int &x1, const int &y1, const int &x2, const int &y2) noexcept {\n\tconst float dx = (float)x1 - (float)x2;\n    const float dy = (float)y1 - (float)y2;\n    return std::sqrt((dx*dx) + (dy*dy));\n}\n\n/*\n * Provides a fast 2D distance between two points, omitting the square-root; compare\n * with other squared distances.\n */\ninline float distance2d_squared(const int &x1, const int &y1, const int &x2, const int &y2) noexcept {\n    const float dx = (float)x1 - (float)x2;\n    const float dy = (float)y1 - (float)y2;\n    return (dx*dx) + (dy*dy);\n}\n\n/*\n * Provides 2D Manhattan distance between two points.\n */\ninline float distance2d_manhattan(const int &x1, const int &y1, const int &x2, const int &y2) noexcept {\n    const float dx = (float)x1 - (float)x2;\n    const float dy = (float)y1 - (float)y2;\n    return std::abs(dx) + std::abs(dy);\n}\n\n/*\n * Provides a correct 3D distance between two points.\n */\ninline float distance3d(const int &x1, const int &y1, const int &z1, const int &x2, const int &y2, const int &z2) noexcept\n{\n\tconst float dx = (float)x1 - (float)x2;\n    const float dy = (float)y1 - (float)y2;\n    const float dz = (float)z1 - (float)z2;\n    return std::sqrt((dx*dx) + (dy*dy) + (dz*dz));\n}\n\n/*\n * Provides a fast 3D distance between two points, omitting the square-root; compare\n * with other squared distances.\n */\ninline float distance3d_squared(const int &x1, const int &y1, const int &z1, const int &x2, const int &y2, const int &z2) noexcept\n{\n    float dx = (float)x1 - (float)x2;\n    float dy = (float)y1 - (float)y2;\n    float dz = (float)z1 - (float)z2;\n    return (dx*dx) + (dy*dy) + (dz*dz);\n}\n\n/*\n * Provides Manhattan distance between two 3D points.\n */\ninline float distance3d_manhattan(const int &x1, const int &y1, const int &z1, const int &x2, const int &y2, const int &z2) noexcept\n{\n    const float dx = (float)x1 - (float)x2;\n    const float dy = (float)y1 - (float)y2;\n    const float dz = (float)z1 - (float)z2;\n    return std::abs(dx) + std::abs(dy) + std::abs(dz);\n}\n\n/*\n * Perform a function for each line element between x1/y1 and x2/y2. We used to use Bresenham's line,\n * but benchmarking showed a simple float-based setup to be faster.\n */\ninline void line_func(const int &x1, const int &y1, const int &x2, const int &y2, std::function<void(int, int)> &&func) noexcept\n{\n\tfloat x = static_cast<float>(x1) + 0.5F;\n    float y = static_cast<float>(y1) + 0.5F;\n    const float dest_x = static_cast<float>(x2);\n    const float dest_y = static_cast<float>(y2);\n    const float n_steps = distance2d(x1,y1,x2,y2);\n    const int steps = static_cast<const int>(std::floor(n_steps) + 1);\n    const float slope_x = (dest_x - x) / n_steps;\n    const float slope_y = (dest_y - y) / n_steps;\n\n    for (int i = 0; i < steps; ++i) {\n        func(static_cast<int>(x), static_cast<int>(y));\n        x += slope_x;\n        y += slope_y;\n    }\n}\n\n/*\n * Perform a function for each line element between x1/y1/z1 and x2/y2/z2. Uses a 3D\n * implementation of Bresenham's line algorithm.\n * https://gist.github.com/yamamushi/5823518\n */\ntemplate <typename F>\nvoid line_func_3d(const int &x1, const int &y1, const int &z1, const int &x2, const int &y2, const int &z2, F &&func) noexcept\n{\n    float x = static_cast<float>(x1)+0.5F;\n    float y = static_cast<float>(y1)+0.5F;\n    float z = static_cast<float>(z1)+0.5F;\n\n    float length = distance3d(x1, y1, z1, x2, y2, z2);\n    int steps = static_cast<int>(std::floor(length));\n    float x_step = (x - x2) / length;\n    float y_step = (y - y2) / length;\n    float z_step = (z - z2) / length;\n\n    for (int i=0; i<steps; ++i) {\n        x += x_step;\n        y += y_step;\n        z += z_step;\n        func(static_cast<int>(std::floor(x)), static_cast<int>(std::floor(y)), static_cast<int>(std::floor(z)));\n    }\n}\n\n/*\n * Perform a function for each line element between x1/y1 and x2/y2. We used to use Bresenham's algorithm,\n * but benchmarking showed that a simple float based vector was faster.\n */\ntemplate <typename F>\ninline void line_func_cancellable(const int &x1, const int &y1, const int &x2, const int &y2, F &&func) noexcept {\n    float x = static_cast<float>(x1) + 0.5F;\n    float y = static_cast<float>(y1) + 0.5F;\n    const float dest_x = static_cast<float>(x2);\n    const float dest_y = static_cast<float>(y2);\n    const float n_steps = distance2d(x1,y1,x2,y2);\n    const int steps = static_cast<const int>(std::floor(n_steps) + 1);\n    const float slope_x = (dest_x - x) / n_steps;\n    const float slope_y = (dest_y - y) / n_steps;\n\n    for (int i = 0; i < steps; ++i) {\n        if (!func(static_cast<int>(x), static_cast<int>(y))) return;\n        x += slope_x;\n        y += slope_y;\n    }\n}\n\n/*\n * Perform a function for each line element between x1/y1/z1 and x2/y2/z2. Uses a 3D\n * implementation of Bresenham's line algorithm.\n * https://gist.github.com/yamamushi/5823518\n */\ntemplate<typename F>\nvoid line_func_3d_cancellable(const int &x1, const int &y1, const int &z1, const int &x2, const int &y2, const int &z2, F &&func) noexcept\n{\n    float x = static_cast<float>(x1)+0.5F;\n    float y = static_cast<float>(y1)+0.5F;\n    float z = static_cast<float>(z1)+0.5F;\n\n    float length = distance3d(x1, y1, z1, x2, y2, z2);\n    int steps = static_cast<int>(std::floor(length));\n    float x_step = (x - x2) / length;\n    float y_step = (y - y2) / length;\n    float z_step = (z - z2) / length;\n\n    for (int i=0; i<steps; ++i) {\n        x += x_step;\n        y += y_step;\n        z += z_step;\n        const bool keep_going = func(static_cast<int>(std::floor(x)), static_cast<int>(std::floor(y)), static_cast<int>(std::floor(z)));\n        if (!keep_going) return;\n    }\n}\n}"
  },
  {
    "path": "rltk/gui.cpp",
    "content": "#include \"gui.hpp\"\n#include <stdexcept>\n#include <utility>\n#include <algorithm>\n\nnamespace rltk {\n\nnamespace gui_detail {\n\nstd::vector<std::pair<int, layer_t *>> render_order;\n\n}\n\nvoid gui_t::on_resize(const int w, const int h) {\n\tscreen_width = w;\n\tscreen_height = h;\n\n\tfor (auto it = layers.begin(); it != layers.end(); ++it) {\n\t\tit->second.on_resize(w, h);\n\t}\n}\n\nvoid gui_t::render(sf::RenderWindow &window) {\n\tfor (auto l : gui_detail::render_order) {\n\t\tl.second->render(window);\n\t}\n}\n\nvoid gui_t::add_layer(const int handle, const int X, const int Y, const int W, const int H, \n\tstd::string font_name, std::function<void(layer_t *,int,int)> resize_fun, bool has_background,\n\tint order) \n{\n\tcheck_handle_uniqueness(handle);\n\tlayers.emplace(std::make_pair(handle, layer_t(X, Y, W, H, font_name, resize_fun, has_background)));\n\tif (order == -1) {\n\t\torder = render_order;\n\t\t++render_order;\n\t}\n\tgui_detail::render_order.push_back(std::make_pair(order, get_layer(handle)));\n\tstd::sort(gui_detail::render_order.begin(), gui_detail::render_order.end(), \n\t\t[] (std::pair<int, layer_t *> a, std::pair<int, layer_t *> b) \n\t\t{\n\t\treturn a.first < b.first;\n\t\t}\n\t);\n}\n\nvoid gui_t::add_sparse_layer(const int handle, const int X, const int Y, const int W, const int H, \n\tstd::string font_name, std::function<void(layer_t *,int,int)> resize_fun, int order) \n{\n\tcheck_handle_uniqueness(handle);\n\tlayers.emplace(std::make_pair(handle, layer_t(true, X, Y, W, H, font_name, resize_fun)));\n\tif (order == -1) {\n\t\torder = render_order;\n\t\t++render_order;\n\t}\n\tgui_detail::render_order.push_back(std::make_pair(order, get_layer(handle)));\n\tstd::sort(gui_detail::render_order.begin(), gui_detail::render_order.end(), \n\t\t[] (std::pair<int, layer_t *> a, std::pair<int, layer_t *> b) \n\t\t{\n\t\treturn a.first < b.first;\n\t\t}\n\t);\n}\n\nvoid gui_t::add_owner_layer(const int handle, const int X, const int Y, const int W, const int H, \n\tstd::function<void(layer_t *,int,int)> resize_fun, std::function<void(layer_t *, sf::RenderTexture &)> owner_draw_fun, int order) \n{\n\tcheck_handle_uniqueness(handle);\n\tlayers.emplace(std::make_pair(handle, layer_t(X, Y, W, H, resize_fun, owner_draw_fun)));\n\tif (order == -1) {\n\t\torder = render_order;\n\t\t++render_order;\n\t}\n\tgui_detail::render_order.push_back(std::make_pair(order, get_layer(handle)));\n\tstd::sort(gui_detail::render_order.begin(), gui_detail::render_order.end(), \n\t\t[] (std::pair<int, layer_t *> a, std::pair<int, layer_t *> b) \n\t\t{\n\t\treturn a.first < b.first;\n\t\t}\n\t);\n}\n\n\nvoid gui_t::delete_layer(const int handle) {\n\tgui_detail::render_order.erase(std::remove_if(gui_detail::render_order.begin(), gui_detail::render_order.end(), \n\t\t[&handle, this] (std::pair<int, layer_t *> a) \n\t\t{\n\t\t\tif (a.second == this->get_layer(handle)) return true;\n\t\t\treturn false;\n\t\t}\n\t), gui_detail::render_order.end());\n\tlayers.erase(handle);\n}\n\nlayer_t * gui_t::get_layer(const int handle) {\n\tauto finder = layers.find(handle);\n\tif (finder == layers.end()) throw std::runtime_error(\"Unknown layer handle: \" + std::to_string(handle));\n\treturn &(finder->second);\n}\n\n}\n"
  },
  {
    "path": "rltk/gui.hpp",
    "content": "/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed under the MIT license - see LICENSE file.\n *\n * Provides support for complicated GUIs.\n */\n\n#pragma once\n\n#include <SFML/Graphics.hpp>\n#include <functional>\n#include <unordered_map>\n#include <memory>\n#include <vector>\n\n#include \"layer_t.hpp\"\n\nnamespace rltk {\n\n/*\n * The overall GUI - holds layers and handles render calls. Access via rltk::gui\n */\nstruct gui_t {\npublic:\n\tgui_t(const int w, const int h) : screen_width(w), screen_height(h) {}\n\tvoid on_resize(const int w, const int h);\n\tvoid render(sf::RenderWindow &window);\n\n\t// Specialization for adding console layers\n\tvoid add_layer(const int handle, const int X, const int Y, const int W, const int H, std::string font_name, std::function<void(layer_t *,int,int)> resize_fun, bool has_background=true, int order=-1);\n\t\n\t// Specialization for sparse layers\n\tvoid add_sparse_layer(const int handle, const int X, const int Y, const int W, const int H, std::string font_name, std::function<void(layer_t *,int,int)> resize_fun, int order=-1);\n\t\n\t// Specialization for adding owner-draw layers\n\tvoid add_owner_layer(const int handle, const int X, const int Y, const int W, const int H, std::function<void(layer_t *,int,int)> resize_fun, std::function<void(layer_t *, sf::RenderTexture &)> owner_draw_fun, int order=-1);\n\tvoid delete_layer(const int handle);\n\tlayer_t * get_layer(const int handle);\n\nprivate:\n\tint screen_width;\n\tint screen_height;\n\tint render_order = 0;\n\n\tstd::unordered_map<int, layer_t> layers;\n\n\tinline void check_handle_uniqueness(const int handle) {\n\t\tauto finder = layers.find(handle);\n\t\tif (finder != layers.end()) throw std::runtime_error(\"Adding a duplicate layer handle: \" + std::to_string(handle));\n\t}\n};\n\n}"
  },
  {
    "path": "rltk/gui_control_t.cpp",
    "content": "#include \"gui_control_t.hpp\"\n#include <sstream>\n#include <algorithm>\n\nnamespace rltk {\n\nvoid gui_static_text_t::render(virtual_terminal * console) {\n\tconsole->print(x, y, text, foreground, background);\n}\n\nvoid gui_border_box_t::render(virtual_terminal * console) {\n\tconsole->box(foreground, background, is_double);\n}\n\nvoid gui_checkbox_t::render(virtual_terminal * console) {\n\tconsole->set_char(x, y, vchar{'[', foreground, background});\n\tif (checked) {\n\t\tconsole->set_char(x+1, y, vchar{'X', foreground, background});\n\t} else {\n\t\tconsole->set_char(x+1, y, vchar{' ', foreground, background});\n\t}\n\tconsole->print(x+2, y, \"] \" + label, foreground, background);\n}\n\nvoid gui_radiobuttons_t::render(virtual_terminal * console) {\n\tconsole->print(x, y, caption, foreground, background);\n\tint current_y = y+1;\n\tfor (const radio &r : options) {\n\t\tconsole->set_char(x, current_y, vchar{'(', foreground, background});\n\t\tif (r.checked) {\n\t\t\tconsole->set_char(x+1, current_y, vchar{'*', foreground, background});\n\t\t} else {\n\t\t\tconsole->set_char(x+1, current_y, vchar{' ', foreground, background});\n\t\t}\n\t\tconsole->print(x+2, current_y, \") \" + r.label, foreground, background);\n\t\t++current_y;\n\t}\n}\n\nvoid gui_hbar_t::render(virtual_terminal * console) {\n\tfloat fullness = (float)(value - min) / (float)max;\n\tfloat full_w_f = fullness * (float)w;\n\tstd::size_t full_w = static_cast<std::size_t>(full_w_f);\n\n\tstd::stringstream ss;\n\tfor (std::size_t i=0; i<w; ++i) {\n\t\tss << ' ';\n\t}\n\tstd::string s = ss.str();\n\n\tstd::stringstream display;\n\tdisplay << prefix << value << \"/\" << max;\n\tstd::string tmp = display.str();\n\tconst int start = static_cast<int>((w/2) - (tmp.size() / 2));\n\tfor (std::size_t i=0; i < std::min(tmp.size(),w); ++i) {\n\t\ts[i + start] = tmp[i];\n\t}\n\n\tfor (std::size_t i=0; i<w; ++i) {\n\t\tconst float pct = (float)i / (float)w;\n\t\tif (i <= full_w) {\n\t\t\tconsole->set_char(x+i, y, vchar{s[i], text_color, lerp(full_start, full_end, pct)});\n\t\t} else {\n\t\t\tconsole->set_char(x+i, y, vchar{s[i], text_color, lerp(empty_start, empty_end, pct)});\n\t\t}\n\t}\n}\n\nvoid gui_vbar_t::render(virtual_terminal * console) {\n\tfloat fullness = (float)(value - min) / (float)max;\n\tfloat full_h_f = fullness * (float)h;\n\tstd::size_t full_h = static_cast<std::size_t>(full_h_f);\n\n\tstd::stringstream ss;\n\tfor (std::size_t i=0; i<h; ++i) {\n\t\tss << ' ';\n\t}\n\tstd::string s = ss.str();\n\t\n\tstd::stringstream display;\n\tdisplay << prefix << value << \"/\" << max;\n\tstd::string tmp = display.str();\n\tconst int start = static_cast<int>((h/2) - (tmp.size() / 2));\n\tfor (std::size_t i=0; i < std::min(tmp.size(), h); ++i) {\n\t\ts[i + start] = tmp[i];\n\t}\n\n\tfor (std::size_t i=0; i<h; ++i) {\n\t\tconst float pct = (float)i / (float)h;\n\t\tif (i <= full_h) {\n\t\t\tconsole->set_char(x, y+i, vchar{s[i], text_color, lerp(full_start, full_end, pct)});\n\t\t} else {\n\t\t\tconsole->set_char(x, y+i, vchar{s[i], text_color, lerp(empty_start, empty_end, pct)});\n\t\t}\n\t}\n}\n\nvoid gui_listbox_t::render(virtual_terminal * console) {\n\tconsole->box(x, y, w+3, static_cast<int>(items.size())+1, caption_fg, caption_bg, false);\n\tconsole->print(x+3, y, caption, caption_fg, caption_bg);\n\tconsole->set_char(x+1, y, vchar{180, caption_fg, caption_bg});\n\tconsole->set_char(x+2, y, vchar{' ', caption_fg, caption_bg});\n\tconsole->set_char(x+w, y, vchar{' ', caption_fg, caption_bg});\n\tconsole->set_char(x+w+1, y, vchar{195, caption_fg, caption_bg});\n\tint current_y = y+1;\n\tfor (const list_item &item : items) {\n\t\tif (item.value == selected_value) {\n\t\t\tconsole->print(x+2, current_y, item.label, selected_fg, selected_bg);\n\t\t} else {\n\t\t\tconsole->print(x+2, current_y, item.label, item_fg, item_bg);\t\t\t\n\t\t}\n\t\t++current_y;\n\t}\n}\n\n}"
  },
  {
    "path": "rltk/gui_control_t.hpp",
    "content": "/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed under the MIT license - see LICENSE file.\n *\n * Retained mode GUI controls\n */\n#pragma once\n\n#include \"virtual_terminal.hpp\"\n#include <string>\n#include <functional>\n#include <vector>\n#include <iostream>\n\n// TODO: Text box, display rich text, combo box, slider, spinner\n\nnamespace rltk {\n\n/*\n * Base type for retained-mode GUI controls.\n */\nstruct gui_control_t {\n\tvirtual void render(virtual_terminal * console)=0;\n\tvirtual bool mouse_in_control(const int tx, const int ty) { return false; }\n\n\t// Callbacks\n\tstd::function<void(gui_control_t *)> on_render_start = nullptr;\n\tstd::function<void(gui_control_t *, int, int)> on_mouse_over = nullptr;\n\tstd::function<void(gui_control_t *, int, int)> on_mouse_down = nullptr;\n\tstd::function<void(gui_control_t *, int, int)> on_mouse_up = nullptr;\n};\n\nstruct gui_static_text_t : public gui_control_t {\n\tgui_static_text_t(const int X, const int Y, const std::string txt, const color_t fg, const color_t bg) :\n\t\ttext(txt), x(X), y(Y), foreground(fg), background(bg) {}\n\n\tstd::string text = \"\";\n\tint x=0;\n\tint y=0;\n\tcolor_t foreground;\n\tcolor_t background;\n\n\tvirtual void render(virtual_terminal * console) override;\n\tvirtual bool mouse_in_control(const int tx, const int ty) override { return (tx >= x && tx <= x + (static_cast<int>(text.size())) && ty==y); }\n};\n\nstruct gui_border_box_t : public gui_control_t {\n\tgui_border_box_t(const bool double_lines, const color_t fg, const color_t bg) : \n\t\tis_double(double_lines), foreground(fg), background(bg) {}\n\t\n\tbool is_double = false;\n\tcolor_t foreground;\n\tcolor_t background;\n\n\tvirtual void render(virtual_terminal * console) override;\n};\n\nstruct gui_checkbox_t : public gui_control_t {\n\tgui_checkbox_t(const int X, const int Y, const bool is_checked, const std::string text, const color_t fg, const color_t bg) :\n\t\tchecked(is_checked), label(text), foreground(fg), background(bg), x(X), y(Y) {\n\t\t\ton_mouse_down = [] (gui_control_t * ctrl, int tx, int ty) {\n\t\t\t\tgui_checkbox_t * me = static_cast<gui_checkbox_t *>(ctrl);\n\t\t\t\tme->click_started = true;\n\t\t\t};\n\t\t\ton_mouse_up = [] (gui_control_t * ctrl, int tx, int ty) {\n\t\t\t\tgui_checkbox_t * me = static_cast<gui_checkbox_t *>(ctrl);\n\t\t\t\tif (me->click_started) {\n\t\t\t\t\tme->checked = !me->checked;\n\t\t\t\t}\n\t\t\t\tme->click_started = false;\n\t\t\t};\n\t\t}\n\n\tbool checked = false;\n\tstd::string label;\n\tcolor_t foreground;\n\tcolor_t background;\n\tint x=0;\n\tint y=0;\n\tbool click_started = false;\n\n\tvirtual void render(virtual_terminal * console) override;\n\tvirtual bool mouse_in_control(const int tx, const int ty) override { \n\t\treturn (tx >= x && tx <= x + (static_cast<int>(label.size())+4) && ty==y); \n\t}\n};\n\nstruct radio {\n\tbool checked;\n\tstd::string label;\n\tint value;\n};\n\nstruct gui_radiobuttons_t : public gui_control_t {\n\tgui_radiobuttons_t(const int X, const int Y, const std::string heading, const color_t fg, const color_t bg, std::vector<radio> opts) :\n\t\tcaption(heading), foreground(fg), background(bg), options(opts), x(X), y(Y)\n\t{\n\t\twidth = static_cast<int>(caption.size());\n\t\tfor (const radio &r : options) {\n\t\t\tif (width < static_cast<int>(r.label.size())) width = static_cast<int>(r.label.size());\n\t\t\tif (r.checked) selected_value = r.value;\n\t\t}\n\t\theight = static_cast<int>(options.size()) + 1;\n\n\t\ton_mouse_down = [] (gui_control_t * ctrl, int tx, int ty) {\n\t\t\tgui_radiobuttons_t * me = static_cast<gui_radiobuttons_t *>(ctrl);\n\t\t\tme->click_started = true;\n\t\t};\n\t\ton_mouse_up = [] (gui_control_t * ctrl, int tx, int ty) {\n\t\t\tgui_radiobuttons_t * me = static_cast<gui_radiobuttons_t *>(ctrl);\n\t\t\tif (me->click_started) {\n\t\t\t\tconst int option_number = (ty - me->y) -1;\n\t\t\t\tif (option_number >= 0 && option_number <= static_cast<int>(me->options.size())) {\n\t\t\t\t\tme->selected_value = me->options[option_number].value;\n\t\t\t\t\tfor (auto &r : me->options) {\n\t\t\t\t\t\tif (r.value == me->selected_value) {\n\t\t\t\t\t\t\tr.checked = true;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tr.checked = false;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tme->click_started = false;\n\t\t};\n\t}\n\n\tstd::string caption;\n\tcolor_t foreground;\n\tcolor_t background;\n\tstd::vector<radio> options;\n\tint x;\n\tint y;\n\tint width;\n\tint height;\n\tbool click_started = false;\n\tint selected_value = -1;\n\n\tvirtual void render(virtual_terminal * console) override;\n\tvirtual bool mouse_in_control(const int tx, const int ty) override { \n\t\tif (tx >= x && tx <= (x + width) && ty >= y && ty <= (y + height)) {\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n};\n\nstruct gui_hbar_t : public gui_control_t {\n\tgui_hbar_t(const int X, const int Y, const int W, const int MIN, const int MAX, const int VAL, \n\t\tconst color_t FULL_START, const color_t FULL_END, const color_t EMPTY_START, const color_t EMPTY_END,\n\t\tconst color_t TEXT_COL, std::string PREFIX = \"\") :\n\t\tx(X), y(Y), w(W), min(MIN), max(MAX), value(VAL), full_start(FULL_START), full_end(FULL_END),\n\t\tempty_start(EMPTY_START), empty_end(EMPTY_END), text_color(TEXT_COL), prefix(PREFIX)\n\t{}\n\n\tint x;\n\tint y;\n\tstd::size_t w;\n\tint min;\n\tint max;\n\tint value;\n\tcolor_t full_start;\n\tcolor_t full_end;\n\tcolor_t empty_start;\n\tcolor_t empty_end;\n\tcolor_t text_color;\n\tstd::string prefix;\n\n\tvirtual void render(virtual_terminal * console) override;\n};\n\nstruct gui_vbar_t : public gui_control_t {\n\tgui_vbar_t(const int X, const int Y, const int H, const int MIN, const int MAX, const int VAL, \n\t\tconst color_t FULL_START, const color_t FULL_END, const color_t EMPTY_START, const color_t EMPTY_END,\n\t\tconst color_t TEXT_COL, std::string PREFIX = \"\") :\n\t\tx(X), y(Y), h(H), min(MIN), max(MAX), value(VAL), full_start(FULL_START), full_end(FULL_END),\n\t\tempty_start(EMPTY_START), empty_end(EMPTY_END), text_color(TEXT_COL), prefix(PREFIX)\n\t{}\n\n\tint x;\n\tint y;\n\tstd::size_t h;\n\tint min;\n\tint max;\n\tint value;\n\tcolor_t full_start;\n\tcolor_t full_end;\n\tcolor_t empty_start;\n\tcolor_t empty_end;\n\tcolor_t text_color;\n\tstd::string prefix;\n\n\tvirtual void render(virtual_terminal * console) override;\n};\n\nstruct list_item {\n\tint value;\n\tstd::string label;\n};\n\nstruct gui_listbox_t : public gui_control_t {\n\tgui_listbox_t(const int X, const int Y, const int VAL, std::vector<list_item> options, std::string label,\n\t\tconst color_t label_fg, const color_t label_bg, const color_t ITEM_FG, const color_t ITEM_BG,\n\t\tconst color_t sel_fg, const color_t sel_bg) :\n\t\tx(X), y(Y), selected_value(VAL), items(options), caption_fg(label_fg), caption_bg(label_bg),\n\t\titem_fg(ITEM_FG), item_bg(ITEM_BG), selected_fg(sel_fg), selected_bg(sel_bg) \n\t{\n\t\tcaption = label;\n\t\tw = static_cast<int>(caption.size()) + 2;\n\t\tfor (const list_item &item : items) {\n\t\t\tif (w < static_cast<int>(item.label.size())) w = static_cast<int>(item.label.size());\n\t\t}\n\n\t\ton_mouse_down = [] (gui_control_t * ctrl, int tx, int ty) {\n\t\t\tgui_listbox_t * me = static_cast<gui_listbox_t *>(ctrl);\n\t\t\tme->click_started = true;\n\t\t};\n\t\ton_mouse_up = [] (gui_control_t * ctrl, int tx, int ty) {\n\t\t\tgui_listbox_t * me = static_cast<gui_listbox_t *>(ctrl);\n\t\t\tif (me->click_started) {\n\t\t\t\tconst int option_number = (ty - me->y) -1;\n\t\t\t\tif (option_number >= 0 && option_number <= static_cast<int>(me->items.size())) {\n\t\t\t\t\tme->selected_value = me->items[option_number].value;\n\t\t\t\t}\n\t\t\t}\n\t\t\tme->click_started = false;\n\t\t};\n\t}\n\n\tint x;\n\tint y;\n\tint selected_value;\n\tstd::vector<list_item> items;\n\tstd::string caption;\n\tcolor_t caption_fg;\n\tcolor_t caption_bg;\n\tcolor_t item_fg;\n\tcolor_t item_bg;\n\tcolor_t selected_fg;\n\tcolor_t selected_bg;\n\tint w = 0;\n\tbool click_started = false;\n\n\tvirtual void render(virtual_terminal * console) override;\n\tvirtual bool mouse_in_control(const int tx, const int ty) override { \n\t\tif (tx >= x && tx <= (x + w) && ty >= y && ty <= (y + static_cast<int>(items.size())+1)) {\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n};\n\n}\n"
  },
  {
    "path": "rltk/input_handler.cpp",
    "content": "#include \"input_handler.hpp\"\n#include \"scaling.hpp\"\n#include <array>\n#include <algorithm>\n\nnamespace rltk {\n\nnamespace state {\nbool window_focused = true;\nstd::array<bool, 7> mouse_button_pressed;\nint mouse_x = 0;\nint mouse_y = 0;\n}\n\nbool is_window_focused() {\n\treturn rltk::state::window_focused;\n}\n\nvoid set_window_focus_state(const bool &s) {\n\trltk::state::window_focused = s;\n}\n\nvoid reset_mouse_state() {\n\tstd::fill(rltk::state::mouse_button_pressed.begin(), rltk::state::mouse_button_pressed.end(), false);\n\trltk::state::mouse_x = 0;\n\trltk::state::mouse_y = 0;\n}\n\nvoid set_mouse_button_state(const int button, const bool state) {\n\trltk::state::mouse_button_pressed[button] = state;\n}\n\nbool get_mouse_button_state(const int button) {\n\treturn rltk::state::mouse_button_pressed[button];\n}\n\nvoid set_mouse_position(const int x, const int y) {\n\trltk::state::mouse_x = static_cast<int>(x / scale_factor);\n\trltk::state::mouse_y = static_cast<int>(y / scale_factor);\n}\n\nstd::pair<int,int> get_mouse_position() {\n\treturn std::make_pair(rltk::state::mouse_x, rltk::state::mouse_y);\n}\n\nvoid enqueue_key_pressed(sf::Event &event) {\n\temit(key_pressed_t{event});\n}\n\n}"
  },
  {
    "path": "rltk/input_handler.hpp",
    "content": "#pragma once\n/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed under the MIT license - see LICENSE file.\n *\n * Class for providing a simple input interface.\n * Provides functions that can be queried for the current state of\n * the input system.\n *\n */\n\n#include <utility>\n#include <SFML/Graphics.hpp>\n#include \"ecs.hpp\"\n\nnamespace rltk {\n\n/* Helper constants to represent mouse buttons */\nnamespace button {\nconstexpr int LEFT = 0;\nconstexpr int RIGHT = 1;\nconstexpr int MIDDLE = 2;\nconstexpr int SIDE1 = 3;\nconstexpr int SIDE2 = 4;\nconstexpr int WHEEL_UP = 5;\nconstexpr int WHEEL_DOWN = 6;\n}\n\n/* Does the game window currently have focus? You might want to pause if it doesn't. */\nextern bool is_window_focused();\n\n/* Setter function for window focus */\nextern void set_window_focus_state(const bool &s);\n\n/* Mouse state reset: clears all mouse state */\nextern void reset_mouse_state();\n\n/* Update the stored mouse position. Does not actually move the mouse. */\nextern void set_mouse_position(const int x, const int y);\nextern std::pair<int,int> get_mouse_position();\n\n/* Mouse button state */\nextern void set_mouse_button_state(const int button, const bool state);\nextern bool get_mouse_button_state(const int button);\n\n/* Keyboard queue */\nextern void enqueue_key_pressed(sf::Event &event);\n\nstruct key_pressed_t : base_message_t {\npublic:\n    key_pressed_t() {}\n    key_pressed_t(sf::Event ev) : event(ev) {}\n    sf::Event event;\n};\n\n}\n"
  },
  {
    "path": "rltk/layer_t.cpp",
    "content": "#include \"layer_t.hpp\"\n#include \"input_handler.hpp\"\n\nnamespace rltk {\n\nvoid layer_t::make_owner_draw_backing() {\n\tif (!backing) {\n\t\tbacking = std::make_unique<sf::RenderTexture>();\n\t}\n\tbacking->create(w, h);\n}\n\nvoid layer_t::on_resize(const int width, const int height) {\n\tresize_func(this, width, height);\n\tif (console && console->visible) {\n\t\tconsole->set_offset(x,y);\n\t\tconsole->resize_pixels(w, h);\n\t\tconsole->dirty = true;\n\t} else {\n\t\tmake_owner_draw_backing();\n\t}\n}\n\nvoid layer_t::render(sf::RenderWindow &window) {\n\tif (console) {\n\t\tif (!controls.empty()) {\n\n\t\t\t// Render start events\n\t\t\tfor (auto it=controls.begin(); it != controls.end(); ++it) {\n\t\t\t\tif (it->second->on_render_start) {\n\t\t\t\t\tauto callfunc = it->second->on_render_start;\n\t\t\t\t\tcallfunc(it->second.get());\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tint mouse_x, mouse_y;\n\t\t\tstd::tie(mouse_x, mouse_y) = get_mouse_position();\n\n\t\t\tif (mouse_x >= x && mouse_x <= (x+w) && mouse_y >= y && mouse_y <= (y+h)) {\n\t\t\t\t// Mouse over in here is possible.\n\t\t\t\tauto font_dimensions = console->get_font_size();\n\t\t\t\tconst int terminal_x = (mouse_x - x) / font_dimensions.first;\n\t\t\t\tconst int terminal_y = (mouse_y - y) / font_dimensions.second;\n\n\t\t\t\tfor (auto it=controls.begin(); it != controls.end(); ++it) {\n\t\t\t\t\t// Mouse over\n\t\t\t\t\tif (it->second->mouse_in_control(terminal_x, terminal_y)) {\n\t\t\t\t\t\tif (it->second->on_mouse_over) {\n\t\t\t\t\t\t\tauto callfunc = it->second->on_mouse_over;\n\t\t\t\t\t\t\tcallfunc(it->second.get(), terminal_x, terminal_y);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Mouse down and up\n\t\t\t\t\t\tif (get_mouse_button_state(button::LEFT) && it->second->on_mouse_down) {\n\t\t\t\t\t\t\tauto callfunc = it->second->on_mouse_down;\n\t\t\t\t\t\t\tcallfunc(it->second.get(), terminal_x, terminal_y);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (!get_mouse_button_state(button::LEFT) && it->second->on_mouse_up) {\n\t\t\t\t\t\t\tauto callfunc = it->second->on_mouse_up;\n\t\t\t\t\t\t\tcallfunc(it->second.get(), terminal_x, terminal_y);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (auto it=controls.begin(); it != controls.end(); ++it) {\n\t\t\t\tit->second->render(console.get());\n\t\t\t}\n\t\t}\n\t\tconsole->render(window);\n\t} else if (sconsole) {\n\t\tsconsole->render(window);\n\t} else {\n\t\tif (!backing) make_owner_draw_backing();\n\t\tbacking->clear(sf::Color(0,0,0,0));\n\t\towner_draw_func(this, *backing);\n\t\tbacking->display();\n\t\tsf::Sprite compositor(backing->getTexture());\n\t\tcompositor.move(static_cast<float>(x), static_cast<float>(y));\n\t\twindow.draw(sf::Sprite(compositor));\n\t}\n}\n\nvoid resize_fullscreen(rltk::layer_t * l, int w, int h) {\n    // Use the whole window\n    l->w = w;\n    l->h = h;\n}\n\n}\n"
  },
  {
    "path": "rltk/layer_t.hpp",
    "content": "/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed under the MIT license - see LICENSE file.\n *\n * Layer type used by the GUI\n */\n#pragma once\n\n#include \"virtual_terminal.hpp\"\n#include \"virtual_terminal_sparse.hpp\"\n#include \"gui_control_t.hpp\"\n#include <unordered_map>\n\nnamespace rltk {\n\n/*\n * A renderable layer. You won't use this type directly.\n */\nstruct layer_t {\n\t/* This specialization is for generic consoles */\n\tlayer_t(const int X, const int Y, const int W, const int H, std::string font_name, std::function<void(layer_t *,int,int)> resize_fun, bool render_background=true) :\n\t\tx(X), y(Y), w(W), h(H), font(font_name), resize_func(resize_fun), has_background(render_background) \n\t{\n\t\tconsole = std::make_unique<virtual_terminal>(font_name, x, y, has_background);\n\t    console->resize_pixels(w, h);\n\t}\n\n\t/* This specialization is for sparse consoles */\n\tlayer_t(bool sparse, const int X, const int Y, const int W, const int H, std::string font_name, std::function<void(layer_t *,int,int)> resize_fun) :\n\t\tx(X), y(Y), w(W), h(H), font(font_name), resize_func(resize_fun)\n\t{\n\t\t// Sparse is unusued, but is there to differentiate the signature.\n\t\tsconsole = std::make_unique<virtual_terminal_sparse>(font_name, x, y);\n\t    sconsole->resize_pixels(w, h);\n\t}\n\n\t/* This specialization is for owner-draw panels */\n\tlayer_t(const int X, const int Y, const int W, const int H, std::function<void(layer_t *,int,int)> resize_fun, std::function<void(layer_t *, sf::RenderTexture &)> owner_draw_fun) :\n\t\tx(X), y(Y), w(W), h(H), resize_func(resize_fun), owner_draw_func(owner_draw_fun)\n\t{\n\t}\n\n\t// The bounding box of the layer\n\tint x;\n\tint y;\n\tint w;\n\tint h;\n\n\t// Font tag - used only if there is a console\n\tstd::string font;\n\n\t// Callbacks:\n\t// resize_func is called when the window changes size. It receives the WINDOW dimensions - it's up to you to\n\t// determine how to lay things out.\n\tstd::function<void(layer_t *,int,int)> resize_func;\n\n\t// Passed through to virtual console; if false then no background will be rendered (helpful for text overlays)\n\tbool has_background;\n\n\t// owner_draw_func is used only for owner draw layers, and is called at render time.\n\tstd::function<void(layer_t *, sf::RenderTexture &)> owner_draw_func;\n\n\t// If a console is present, this is it.\n\tstd::unique_ptr<virtual_terminal> console;\n\n\t// If it has a sparse console, this is it.\n\tstd::unique_ptr<virtual_terminal_sparse> sconsole;\n\n\t// If retained-mode controls are present, they are in here.\n\tstd::unordered_map<int, std::unique_ptr<gui_control_t>> controls;\n\n\t// Used for owner-draw layers. We need to render to texture and then compose to:\n\t// a) permit threading, should you so wish (so there is a single composite run)\n\t// b) allow the future \"effects\" engine to run.\n\tstd::unique_ptr<sf::RenderTexture> backing;\n\n\t// Used by the owner-draw code to ensure that a texture is available for use\n\tvoid make_owner_draw_backing();\n\n\t// Called by GUI when a resize event occurs.\n\tvoid on_resize(const int width, const int height);\n\n\t// Called by GUI when a render event occurs.\n\tvoid render(sf::RenderWindow &window);\n\n\t// Retained Mode Controls\n\ttemplate<class T>\n\tT * control(const int handle) { \n\t\tauto finder = controls.find(handle);\n\t\tif (finder == controls.end()) throw std::runtime_error(\"Unknown GUI control handle: \" + std::to_string(handle));\n\t\treturn static_cast<T *>(finder->second.get());\n\t}\n\n\tgui_control_t * control(const int handle) {\n\t\tauto finder = controls.find(handle);\n\t\tif (finder == controls.end()) throw std::runtime_error(\"Unknown GUI control handle: \" + std::to_string(handle));\n\t\treturn finder->second.get();\n\t}\n\n\tinline void remove_control(const int handle) {\n\t\tcontrols.erase(handle);\n\t}\n\n\tinline void check_handle_uniqueness(const int handle) {\n\t\tauto finder = controls.find(handle);\n\t\tif (finder != controls.end()) throw std::runtime_error(\"Adding a duplicate control handle: \" + std::to_string(handle));\n\t}\n\n\tinline void add_static_text(const int handle, const int x, const int y, const std::string text, const color_t fg, const color_t bg) {\n\t\tcheck_handle_uniqueness(handle);\n\t\tcontrols.emplace(handle, std::make_unique<gui_static_text_t>(x, y, text, fg, bg));\n\t}\n\n\tinline void add_boundary_box(const int handle, const bool double_lines, const color_t fg, const color_t bg) {\n\t\tcheck_handle_uniqueness(handle);\n\t\tcontrols.emplace(handle, std::make_unique<gui_border_box_t>(double_lines, fg, bg));\n\t}\n\n\tinline void add_checkbox(const int handle, const int x, const int y, const std::string label, const bool checked, const color_t fg, const color_t bg) {\n\t\tcheck_handle_uniqueness(handle);\n\t\tcontrols.emplace(handle, std::make_unique<gui_checkbox_t>(x, y, checked, label, fg, bg));\n\t}\n\n\tinline void add_radioset(const int handle, const int x, const int y, const std::string caption, const color_t fg, const color_t bg, std::vector<radio> opts) {\n\t\tcheck_handle_uniqueness(handle);\n\t\tcontrols.emplace(handle, std::make_unique<gui_radiobuttons_t>(x, y, caption, fg, bg, opts));\n\t}\n\n\tinline void add_hbar(const int handle, const int X, const int Y, const int W, const int MIN, const int MAX, const int VAL, \n\t\tconst color_t FULL_START, const color_t FULL_END, const color_t EMPTY_START, const color_t EMPTY_END, const color_t TEXT_COL, const std::string prefix=\"\")\n\t{\n\t\tcheck_handle_uniqueness(handle);\n\t\tcontrols.emplace(handle, std::make_unique<gui_hbar_t>(X, Y, W, MIN, MAX, VAL, FULL_START, FULL_END, EMPTY_START, EMPTY_END, TEXT_COL, prefix));\n\t}\n\n\tinline void add_vbar(const int handle, const int X, const int Y, const int H, const int MIN, const int MAX, const int VAL, \n\t\tconst color_t FULL_START, const color_t FULL_END, const color_t EMPTY_START, const color_t EMPTY_END, const color_t TEXT_COL, const std::string prefix=\"\")\n\t{\n\t\tcheck_handle_uniqueness(handle);\n\t\tcontrols.emplace(handle, std::make_unique<gui_vbar_t>(X, Y, H, MIN, MAX, VAL, FULL_START, FULL_END, EMPTY_START, EMPTY_END, TEXT_COL, prefix));\n\t}\n\n\tinline void add_listbox(const int handle, const int X, const int Y, const int VAL, std::vector<list_item> options, std::string label,\n\t\tconst color_t label_fg, const color_t label_bg, const color_t ITEM_FG, const color_t ITEM_BG,\n\t\tconst color_t sel_fg, const color_t sel_bg)\n\t{\n\t\tcheck_handle_uniqueness(handle);\n\t\tcontrols.emplace(handle, std::make_unique<gui_listbox_t>(X, Y, VAL, options, label, label_fg, label_bg, ITEM_FG, ITEM_BG, sel_fg, sel_bg));\n\t}\n\n\tinline void clear_gui() {\n\t\tcontrols.clear();\n\t}\n};\n\n// Convenience: ready-made function to resize to use the whole screen.\nextern void resize_fullscreen(rltk::layer_t * l, int w, int h);\n\n}\n"
  },
  {
    "path": "rltk/path_finding.hpp",
    "content": "#pragma once\n\n/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed under the MIT license - see LICENSE file.\n *\n * Path finding - interface to the A-Star system\n */\n\n#include \"astar.hpp\"\n#include \"geometry.hpp\"\n#include <memory>\n#include <deque>\n#include <stdexcept>\n#include <type_traits>\n\nnamespace rltk {\n\n// Template class used to forward to specialize the algorithm to the user's map format and\n// and behaviors defined in navigator_t. This avoids the library mandating what your map\n// looks like.\ntemplate<class location_t, class navigator_t>\nclass map_search_node {\npublic:\n\tlocation_t pos;\n\n\tmap_search_node() {}\n\tmap_search_node(location_t loc) : pos(loc) {}\n\n\tfloat GoalDistanceEstimate(map_search_node<location_t, navigator_t> &goal) {\n\t\tfloat result = navigator_t::get_distance_estimate(pos, goal.pos);\n\t\t//std::cout << \"GoalDistanceEstimate called (\" << result << \").\\n\";\n\t\treturn result;\n\t}\n\n\tbool IsGoal(map_search_node<location_t, navigator_t> &node_goal) {\n\t\tbool result = navigator_t::is_goal(pos, node_goal.pos);\n\t\t//std::cout << \"IsGoal called (\" << result << \").\\n\";\n\t\treturn result;\n\t}\n\n\tbool GetSuccessors(AStarSearch<map_search_node<location_t, navigator_t>> * a_star_search, map_search_node<location_t, navigator_t> * parent_node) {\n\t\t//std::cout << \"GetSuccessors called.\\n\";\n\t\tstd::vector<location_t> successors;\n\n\t\tif (parent_node != nullptr) {\t\t\n\t\t\tnavigator_t::get_successors(parent_node->pos, successors);\t\t\t\n\t\t} else {\n\t\t\tthrow std::runtime_error(\"Null parent error.\");\n\t\t}\n\t\tfor (location_t loc : successors) {\n\t\t\tmap_search_node<location_t, navigator_t> tmp(loc);\n\t\t\t//std::cout << \" --> \" << loc.x << \"/\" << loc.y << \"\\n\";\n\t\t\ta_star_search->AddSuccessor( tmp );\n\t\t}\n\t\treturn true;\n\t}\n\n\n\tfloat GetCost(map_search_node<location_t, navigator_t> &successor) {\n\t\tfloat result = navigator_t::get_cost(pos, successor.pos);\n\t\t//std::cout << \"GetCost called (\" << result << \").\\n\";\n\t\treturn result;\n\t}\n\n\tbool IsSameState(map_search_node<location_t, navigator_t> &rhs) {\n\t\tbool result = navigator_t::is_same_state(pos, rhs.pos);\n\t\t//std::cout << \"IsSameState called (\" << result << \").\\n\";\n\t\treturn result;\n\t}\n};\n\n// Template class used to define what a navigation path looks like\ntemplate<class location_t>\nstruct navigation_path {\n\tbool success = false;\n\tlocation_t destination;\n\tstd::deque<location_t> steps;\n};\n\n/*\n * find_path_3d implements A*, and provides an optimization that scans a 3D Bresenham line at the beginning\n * to check for a simple line-of-sight (and paths along it). \n * \n * We jump through a few hoops to make sure that it will work with whatever map format you choose to use,\n * hence: it requires that the navigator_t class provide:\n * - get_x, get_y_, get_z - to translate X/Y/Z into whatever name the user wishes to utilize.\n * - get_xyz - returns a location_t given X/Y/Z co-ordinates.\n */\ntemplate<class location_t, class navigator_t>\nstd::shared_ptr<navigation_path<location_t>> find_path_3d(const location_t start, const location_t end) \n{\n\t{\n\t\tstd::shared_ptr<navigation_path<location_t>> result = std::shared_ptr<navigation_path<location_t>>(new navigation_path<location_t>());\n\t\tresult->success = true;\n\t\tline_func3d(navigator_t::get_x(start), navigator_t::get_y(start), navigator_t::get_z(start), navigator_t::get_x(end), navigator_t::get_y(end), navigator_t::get_z(end), [result] (int X, int Y, int Z) {\n\t\t\tlocation_t step = navigator_t::get_xyz(X,Y, Z);\n\t\t\tif (result->success and navigator_t::is_walkable(step)) {\n\t\t\t\tresult->steps.push_back(step);\n\t\t\t} else {\n\t\t\t\tresult->success = false;\n\t\t\t}\n\t\t});\n\t\tif (result->success) {\n\t\t\treturn result;\n\t\t}\n\t}\n\n\tAStarSearch<map_search_node<location_t, navigator_t>> a_star_search;\n\tmap_search_node<location_t, navigator_t> a_start(start);\n\tmap_search_node<location_t, navigator_t> a_end(end);\n\n\ta_star_search.SetStartAndGoalStates(a_start, a_end);\n\tunsigned int search_state;\n\tunsigned int search_steps = 0;\n\n\tdo {\n\t\tsearch_state = a_star_search.SearchStep();\n\t\t++search_steps;\n\t} while (search_state == AStarSearch<map_search_node<navigator_t, location_t>>::SEARCH_STATE_SEARCHING);\n\n\tif (search_state == AStarSearch<map_search_node<navigator_t, location_t>>::SEARCH_STATE_SUCCEEDED) {\n\t\tstd::shared_ptr<navigation_path<location_t>> result = std::shared_ptr<navigation_path<location_t>>(new navigation_path<location_t>());\n\t\tresult->destination = end;\n\t\tmap_search_node<location_t, navigator_t> * node = a_star_search.GetSolutionStart();\n\t\tfor (;;) {\n\t\t\tnode = a_star_search.GetSolutionNext();\n\t\t\tif (!node) break;\n\t\t\tresult->steps.push_back(node->pos);\n\t\t}\n\t\ta_star_search.FreeSolutionNodes();\n\t\ta_star_search.EnsureMemoryFreed();\n\t\tresult->success = true;\n\t\treturn result;\n\t}\n\n\tstd::shared_ptr<navigation_path<location_t>> result = std::make_shared<navigation_path<location_t>>();\n\ta_star_search.EnsureMemoryFreed();\n\treturn result;\n}\n\n/*\n * find_path_2d implements A*, and provides an optimization that scans a 2D Bresenham line at the beginning\n * to check for a simple line-of-sight (and paths along it). \n * \n * We jump through a few hoops to make sure that it will work with whatever map format you choose to use,\n * hence: it requires that the navigator_t class provide:\n * - get_x, get_y  - to translate X/Y/Z into whatever name the user wishes to utilize.\n * - get_xy - returns a location_t given X/Y/Z co-ordinates.\n */\ntemplate<class location_t, class navigator_t>\nstd::shared_ptr<navigation_path<location_t>> find_path_2d(const location_t start, const location_t end) \n{\n\t{\n\t\tstd::shared_ptr<navigation_path<location_t>> result = std::shared_ptr<navigation_path<location_t>>(new navigation_path<location_t>());\n\t\tresult->success = true;\n\t\tline_func(navigator_t::get_x(start), navigator_t::get_y(start), navigator_t::get_x(end), navigator_t::get_y(end), [result] (int X, int Y) {\n\t\t\tlocation_t step = navigator_t::get_xy(X,Y);\n\t\t\tif (result->success && navigator_t::is_walkable(step)) {\n\t\t\t\tresult->steps.push_back(step);\n\t\t\t} else {\n\t\t\t\tresult->success = false;\n\t\t\t}\n\t\t});\n\t\tif (result->success) {\n\t\t\treturn result;\n\t\t}\n\t}\n\n\tAStarSearch<map_search_node<location_t, navigator_t>> a_star_search;\n\tmap_search_node<location_t, navigator_t> a_start(start);\n\tmap_search_node<location_t, navigator_t> a_end(end);\n\n\ta_star_search.SetStartAndGoalStates(a_start, a_end);\n\tunsigned int search_state;\n\tunsigned int search_steps = 0;\n\n\tdo {\n\t\tsearch_state = a_star_search.SearchStep();\n\t\t++search_steps;\n\t} while (search_state == AStarSearch<map_search_node<navigator_t, location_t>>::SEARCH_STATE_SEARCHING);\n\n\tif (search_state == AStarSearch<map_search_node<navigator_t, location_t>>::SEARCH_STATE_SUCCEEDED) {\n\t\tstd::shared_ptr<navigation_path<location_t>> result = std::shared_ptr<navigation_path<location_t>>(new navigation_path<location_t>());\n\t\tresult->destination = end;\n\t\tmap_search_node<location_t, navigator_t> * node = a_star_search.GetSolutionStart();\n\t\tfor (;;) {\n\t\t\tnode = a_star_search.GetSolutionNext();\n\t\t\tif (!node) break;\n\t\t\tresult->steps.push_back(node->pos);\n\t\t}\n\t\ta_star_search.FreeSolutionNodes();\n\t\ta_star_search.EnsureMemoryFreed();\n\t\tresult->success = true;\n\t\treturn result;\n\t}\n\n\tstd::shared_ptr<navigation_path<location_t>> result = std::make_shared<navigation_path<location_t>>();\n\ta_star_search.EnsureMemoryFreed();\n\treturn result;\n}\n\n/*\n * Implements a simple A-Star path, with no line-search optimization. This has the benefit of avoiding\n * requiring as much additional translation between the template and your preferred map format, at the\n * expense of being potentially slower for some paths.\n */\ntemplate<class location_t, class navigator_t>\nstd::shared_ptr<navigation_path<location_t>> find_path(const location_t start, const location_t end) \n{\n\tAStarSearch<map_search_node<location_t, navigator_t>> a_star_search;\n\tmap_search_node<location_t, navigator_t> a_start(start);\n\tmap_search_node<location_t, navigator_t> a_end(end);\n\n\ta_star_search.SetStartAndGoalStates(a_start, a_end);\n\tunsigned int search_state;\n\tstd::size_t search_steps = 0;\n\n\tdo {\n\t\tsearch_state = a_star_search.SearchStep();\n\t\t++search_steps;\n\t} while (search_state == AStarSearch<map_search_node<navigator_t, location_t>>::SEARCH_STATE_SEARCHING);\n\n\tif (search_state == AStarSearch<map_search_node<navigator_t, location_t>>::SEARCH_STATE_SUCCEEDED) {\n\t\tstd::shared_ptr<navigation_path<location_t>> result = std::shared_ptr<navigation_path<location_t>>(new navigation_path<location_t>());\n\t\tresult->destination = end;\n\t\tmap_search_node<location_t, navigator_t> * node = a_star_search.GetSolutionStart();\n\t\tfor (;;) {\n\t\t\tnode = a_star_search.GetSolutionNext();\n\t\t\tif (!node) break;\n\t\t\tresult->steps.push_back(node->pos);\n\t\t}\n\t\ta_star_search.FreeSolutionNodes();\n\t\ta_star_search.EnsureMemoryFreed();\n\t\tresult->success = true;\n\t\treturn result;\n\t}\n\n\tstd::shared_ptr<navigation_path<location_t>> result = std::make_shared<navigation_path<location_t>>();\n\ta_star_search.EnsureMemoryFreed();\n\treturn result;\n}\n\n}\n"
  },
  {
    "path": "rltk/perlin_noise.cpp",
    "content": "#include \"perlin_noise.hpp\"\n#include <iostream>\n#include <cmath>\n#include <random>\n#include <numeric>\n#include <algorithm>\n\nnamespace rltk {\n\n// Initialize with the reference values for the permutation vector\nperlin_noise::perlin_noise() {\n\t\n\t// Initialize the permutation vector with the reference values\n\tp = {\n\t\t151,160,137,91,90,15,131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,\n\t\t8,99,37,240,21,10,23,190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,\n\t\t35,11,32,57,177,33,88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,\n\t\t134,139,48,27,166,77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,\n\t\t55,46,245,40,244,102,143,54, 65,25,63,161,1,216,80,73,209,76,132,187,208, 89,\n\t\t18,169,200,196,135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,\n\t\t250,124,123,5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,\n\t\t189,28,42,223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, \n\t\t43,172,9,129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,\n\t\t97,228,251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,\n\t\t107,49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,\n\t\t138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180 };\n\t// Duplicate the permutation vector\n\tp.insert(p.end(), p.begin(), p.end());\n}\n\n// Generate a new permutation vector based on the value of seed\nperlin_noise::perlin_noise(unsigned int seed) {\n\tp.resize(256);\n\n\t// Fill p with values from 0 to 255\n\tstd::iota(p.begin(), p.end(), 0);\n\n\t// Initialize a random engine with seed\n\tstd::default_random_engine engine(seed);\n\n\t// Suffle  using the above random engine\n\tstd::shuffle(p.begin(), p.end(), engine);\n\n\t// Duplicate the permutation vector\n\tp.insert(p.end(), p.begin(), p.end());\n}\n\ndouble perlin_noise::noise(double x, double y, double z) const noexcept {\n\t// Find the unit cube that contains the point\n\tint X = (int) floor(x) & 255;\n\tint Y = (int) floor(y) & 255;\n\tint Z = (int) floor(z) & 255;\n\n\t// Find relative x, y,z of point in cube\n\tx -= floor(x);\n\ty -= floor(y);\n\tz -= floor(z);\n\n\t// Compute fade curves for each of x, y, z\n\tdouble u = fade(x);\n\tdouble v = fade(y);\n\tdouble w = fade(z);\n\n\t// Hash coordinates of the 8 cube corners\n\tint A = p[X] + Y;\n\tint AA = p[A] + Z;\n\tint AB = p[A + 1] + Z;\n\tint B = p[X + 1] + Y;\n\tint BA = p[B] + Z;\n\tint BB = p[B + 1] + Z;\n\n\t// Add blended results from 8 corners of cube\n\tdouble res = lerp(w, lerp(v, lerp(u, grad(p[AA], x, y, z), grad(p[BA], x-1, y, z)), lerp(u, grad(p[AB], x, y-1, z), grad(p[BB], x-1, y-1, z))),\tlerp(v, lerp(u, grad(p[AA+1], x, y, z-1), grad(p[BA+1], x-1, y, z-1)), lerp(u, grad(p[AB+1], x, y-1, z-1),\tgrad(p[BB+1], x-1, y-1, z-1))));\n\treturn (res + 1.0)/2.0;\n}\n\ndouble perlin_noise::noise_octaves(double x, double y, double z, int octaves, double persistence, double frequency) const noexcept {\n\tdouble total = 0;\n    double amplitude = 1;\n    double maxValue = 0;  // Used for normalizing result to 0.0 - 1.0\n    for(int i=0;i<octaves;i++) {\n        total += noise(x * frequency, y * frequency, z * frequency) * amplitude;\n        \n        maxValue += amplitude;\n        \n        amplitude *= persistence;\n        frequency *= 2;\n    }\n    \n    return total/maxValue;\n}\n\ndouble perlin_noise::fade(double t) const noexcept { \n\treturn t * t * t * (t * (t * 6 - 15) + 10);\n}\n\ndouble perlin_noise::lerp(double t, double a, double b) const noexcept { \n\treturn a + t * (b - a); \n}\n\ndouble perlin_noise::grad(int hash, double x, double y, double z) const noexcept {\n\tint h = hash & 15;\n\t// Convert lower 4 bits of hash inot 12 gradient directions\n\tdouble u = h < 8 ? x : y,\n\t\t   v = h < 4 ? y : h == 12 || h == 14 ? x : z;\n\treturn ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);\n}\n\n}"
  },
  {
    "path": "rltk/perlin_noise.hpp",
    "content": "// THIS CLASS IS A TRANSLATION TO C++11 FROM THE REFERENCE\n// JAVA IMPLEMENTATION OF THE IMPROVED PERLIN FUNCTION (see http://mrl.nyu.edu/~perlin/noise/)\n// THE ORIGINAL JAVA IMPLEMENTATION IS COPYRIGHT 2002 KEN PERLIN\n\n#pragma once\n\n#include <vector>\n\nnamespace rltk {\n\nclass perlin_noise {\n\t// The permutation vector\n\tstd::vector<int> p;\npublic:\n\t// Initialize with the reference values for the permutation vector\n\tperlin_noise();\n\t// Generate a new permutation vector based on the value of seed\n\tperlin_noise(unsigned int seed);\n\t// Get a noise value, for 2D images z can have any value\n\tdouble noise(double x, double y, double z) const noexcept;\n\tdouble noise_octaves(double x, double y, double z, int octaves, double persistence, double frequency) const noexcept;\nprivate:\n\tdouble fade(double t) const noexcept;\n\tdouble lerp(double t, double a, double b) const noexcept;\n\tdouble grad(int hash, double x, double y, double z) const noexcept;\n};\n\n}"
  },
  {
    "path": "rltk/rexspeeder.cpp",
    "content": "#include \"rexspeeder.hpp\"\nextern \"C\" {\n#include <zlib.h>\n}\n#include <stdexcept>\n\nnamespace rltk {\n\n//===========================================================================================================//\n//    Safe I/O (where \"safe\" means \"will throw errors\")                                                      //\n//                                                                                                           //\n//   These functions will throw an error message from gzerror, and set errno to the error code.              //\n//===========================================================================================================//\n\ninline std::runtime_error make_rexception(gzFile g) {\n\t/*The exception creation is a bit verbose.*/\n\tint errnum = 0;\n\tconst char* errstr = gzerror(g, &errnum);\n\treturn std::runtime_error(std::to_string(errnum) + std::string(\" \") + std::string(errstr));\n}\n\nstatic void s_gzread(gzFile g, voidp buf, unsigned int len)\n{\n\tif (gzread(g, buf, len) > 0)\n\t\treturn;\n\n\t/*We expect to read past the end of the file after the last layer.*/\n\tif (gzeof(g))\n\t\treturn;\n\t\n\tthrow make_rexception(g);\n}\n\nstatic void s_gzwrite(gzFile g, voidp buf, unsigned int len)\n{\n\tif (gzwrite(g, buf, len) > 0)\n\t\treturn;\n\n\tthrow make_rexception(g);\n}\n\nstatic gzFile s_gzopen(const std::string filename, const char* permissions)\n{\n\tgzFile g = gzopen(filename.c_str(), permissions);\n\n\tif (g != Z_NULL)\n\t\treturn g;\n\n\tint err = 0;\n\tconst char* errstr = gzerror(g, &err);\n\tif (err == 0) {\n\t\t/*Assume the file simply didn't exist.*/\n\t\tstd::string s(\"File \" + filename + \" does not exist.\");\n\t\tthrow std::runtime_error(s);\n\t}\n\tthrow std::runtime_error(std::string(errstr));\n}\n\n\nnamespace xp {\n\n//===========================================================================================================//\n//    Loading an xp file                                                                                     //\n//===========================================================================================================//\n\trex_sprite::rex_sprite(std::string const & filename)\n\t{\n\t\ttypedef void* vp;\n\t\t//Number of bytes in a tile. Not equal to sizeof(RexTile) due to padding.\n\t\tconst int tileLen = 10; \n\n\t\tgzFile gz;\n\t\ttry {\n\t\t\tgz = s_gzopen(filename.c_str(), \"rb\");\n\n\t\t\ts_gzread(gz, (vp)&version, sizeof(version));\n\t\t\ts_gzread(gz, (vp)&num_layers, sizeof(num_layers));\n\t\t\ts_gzread(gz, (vp)&width, sizeof(width));\n\t\t\ts_gzread(gz, (vp)&height, sizeof(height));\n\n\t\t\tlayers.resize(num_layers);\n\n\t\t\tfor (int i = 0; i < num_layers; i++)\n\t\t\t\tlayers[i] = rex_layer(width, height);\n\n\t\t\tfor (int layer_index = 0; layer_index < num_layers; layer_index++) {\n\t\t\t\tfor (int i = 0; i < width*height; ++i)\n\t\t\t\t\ts_gzread(gz, get_tile(layer_index, i), tileLen);\n\n\t\t\t\t//The layer and height information is repeated.\n\t\t\t\t//This is expected to read off the end after the last layer.\n\t\t\t\ts_gzread(gz, (vp)&width, sizeof(width));\n\t\t\t\ts_gzread(gz, (vp)&height, sizeof(height));\n\t\t\t}\n\t\t}\n\t\tcatch (...) { throw; }\n\n\t\tgzclose(gz);\n\t}\n\n//===========================================================================================================//\n//    Saving an xp file                                                                                      //\n//===========================================================================================================//\n\tvoid rex_sprite::save(std::string const & filename)\n\t{\n\t\ttypedef void* vp;\n\t\t//Number of bytes in a tile. Not equal to sizeof(RexTile) due to padding.\n\t\tconst int tileLen = 10; \n\n\t\ttry {\n\t\t\tgzFile gz = s_gzopen(filename.c_str(), \"wb\");\n\n\t\t\ts_gzwrite(gz, (vp)&version, sizeof(version));\n\t\t\ts_gzwrite(gz, (vp)&num_layers, sizeof(num_layers));\n\n\t\t\tfor (int layer = 0; layer < num_layers; ++layer) {\n\t\t\t\ts_gzwrite(gz, (vp)&width, sizeof(width));\n\t\t\t\ts_gzwrite(gz, (vp)&height, sizeof(height));\n\n\t\t\t\tfor (int i = 0; i < width*height; ++i) \n\t\t\t\t\t//Note: not \"sizeof(RexTile)\" because of padding.\n\t\t\t\t\ts_gzwrite(gz, (vp)get_tile(layer,i), tileLen);\n\t\t\t\t\n\t\t\t}\n\n\t\t\tgzflush(gz, Z_FULL_FLUSH);\n\t\t\tgzclose(gz);\n\t\t}\n\t\tcatch (...) { throw; }\n\t}\n\n//===========================================================================================================//\n//    Constructors / Destructors                                                                             //\n//===========================================================================================================//\n\trex_sprite::rex_sprite(int _version, int _width, int _height, int _num_layers)\n\t\t:version(_version), width(_width), height(_height), num_layers(_num_layers)\n\t{\n\t\tlayers.resize(num_layers);\n\n\t\t//All layers above the first are set transparent.\n\t\tfor (int l = 1; l < num_layers; l++) {\n\t\t\tfor (int i = 0; i < width*height; ++i) {\n\t\t\t\trltk::vchar t = transparent_tile();\n\t\t\t\tset_tile(l, i, t);\n\t\t\t}\n\t\t}\n\t}\n\n//===========================================================================================================//\n//    Utility Functions                                                                                      //\n//===========================================================================================================//\n\tvoid rex_sprite::flatten() {\n\t\tif (num_layers == 1)\n\t\t\treturn;\n\n\t\t//Paint the last layer onto the second-to-last\n\t\tfor (int i = 0; i < width*height; ++i) {\n\t\t\trltk::vchar* overlay = get_tile(num_layers - 1, i);\n\t\t\tif (!is_transparent(overlay)) {\n\t\t\t\t*get_tile(num_layers - 2, i) = *overlay;\n\t\t\t}\n\t\t}\n\n\t\t//Remove the last layer\n\t\t--num_layers;\n\n\t\t//Recurse\n\t\tflatten();\n\t}\t\n\n}\n\n}\n"
  },
  {
    "path": "rltk/rexspeeder.hpp",
    "content": "#pragma once\n/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed under the MIT license - see LICENSE file.\n *\n * REXPaint 1.02 file reader. Credit to https://github.com/pyridine/REXSpeeder for the original.\n */\n\n/*For version 1.02 of REXPaint*/\n#include <iostream>\n#include <stdint.h>\n#include <array>\n#include <vector>\n#include \"vchar.hpp\"\n\nnamespace rltk {\n\nnamespace xp {\n\n\t//REXpaint identifies transparent tiles by setting their background color to 255,0,255.\n\t//You may want to check this for each tile before drawing or converting a RexFile.\n\t//(By default, no tile in the first layer is transaprent).\n\tinline bool is_transparent(const rltk::vchar * tile)\n\t{\n\t\t//This might be faster than comparing with transparentTile(), despite it being a constexpr\n\t\treturn (tile->background.r == 255 && tile->background.g == 0 && tile->background.b == 255);\n\t}\t\n\n\t//Returns a transparent tile.\n\tinline rltk::vchar transparent_tile() {\n\t\treturn rltk::vchar{0, 0, 0, 0, 255, 0, 255};\n\t}\n\n\tstruct rex_layer {\n\t\trex_layer() {}\n\t\trex_layer(int width, int height) \n\t\t{\n\t\t\ttiles.resize(width * height);\n\t\t} \n\n\t\t~rex_layer()\n\t\t{\n\t\t\ttiles.clear();\n\t\t}\n\n\t\tstd::vector<rltk::vchar> tiles;\n\t};\n\n\tclass rex_sprite {\n\tpublic:\n\t\t//Load an .xp file into a new RexFile.\n\t\t//Note: May throw a const char* error message and set errno.\n\t\t//Both the error message and the value of errno may be as gzopen or gzread set them.\n\t\t//It may also throw an error with code REXSPEEDER_FILE_DOES_NOT_EXIST.\n\t\t//Will not throw an error if the file specified by `filename` is not zlib compressed.\n\t\trex_sprite(std::string const& filename);\n\n\t\t//Save this RexFile into a valid .xp file that RexPaint can load (if the \".xp\" suffix is present).\n\t\t//Note: May throw a const char* error message and set errno.\n\t\t//Both the error message and the value of errno may be as gzopen or gzwrite set them.\n\t\tvoid save(std::string const& filename);\n\n\t\t//Create a blank RexFile with the specified attributes.\n\t\t//Layers above the first will be made of transparent tiles.\n\t\trex_sprite(int _version, int _width, int _height, int _num_layers);\n\n\t\t//Image attributes\n\t\tinline int get_version() { return version; };\n\t\tinline int get_width() { return width; };\n\t\tinline int get_height() { return height; };\n\t\tinline int get_num_layers() { return num_layers; };\n\n\t\t//Returns a pointer to a single tile specified by layer, x coordinate, y coordinate.\n\t\t//0,0 is the top-left corner.\n\t\tinline rltk::vchar* get_tile(int layer, int x, int y) { return &layers[layer].tiles[y + (x * height)]; };\n\n\t\t//Returns a pointer to a single tile specified by layer and the actual index into the array.\n\t\t//Useful for iterating through a whole layer in one go for coordinate-nonspecific tasks.\n\t\tinline rltk::vchar* get_tile(int layer, int index) { return &layers[layer].tiles[index]; };\n\n\t\t//Replaces the data for a tile. Not super necessary, but might save you a couple lines.\n\t\tinline void set_tile(int layer, int x, int y, rltk::vchar& val) { *get_tile(layer, x, y) = val; };\n\n\t\t//Replaces the data for a tile. Not super necessary, but might save you a couple lines.\n\t\tinline void set_tile(int layer, int i, rltk::vchar& val) { *get_tile(layer, i) = val; };\n\n\t\t//Combines all the layers of the image into one layer.\n\t\t//Respects transparency.\n\t\tvoid flatten();\n\n\tprivate:\n\t\t//Image properties\n\t\tint version;\n\t\tint width, height, num_layers;\n\t\tstd::vector<rex_layer> layers; //layers[0] is the first layer.\n\n\t\t//Forbid default construction.\n\t\trex_sprite();\n\t};\n}\n}"
  },
  {
    "path": "rltk/rltk.cpp",
    "content": "#include \"rltk.hpp\"\n#include \"texture.hpp\"\n#include <memory>\n\nnamespace rltk {\n\nstd::unique_ptr<sf::RenderWindow> main_window;\nstd::unique_ptr<virtual_terminal> console;\nstd::unique_ptr<gui_t> gui;\n\nnamespace main_detail {\nbool use_root_console;\nbool taking_screenshot = false;\nstd::string screenshot_filename = \"\";\n}\n\nsf::RenderWindow * get_window() {\n\treturn main_window.get();\n}\n\ngui_t * get_gui() {\n    return gui.get();\n}\n\nvoid init(const config_simple &config) {\n    register_font_directory(config.font_path);\n    bitmap_font * font = get_font(config.root_font);\n    if (!config.fullscreen) {\n        main_window = std::make_unique<sf::RenderWindow>(sf::VideoMode(config.width * font->character_size.first, \n            config.height * font->character_size.second), \n            config.window_title, sf::Style::Titlebar | sf::Style::Resize | sf::Style::Close);\n    } else {\n        sf::VideoMode desktop = sf::VideoMode::getDesktopMode();\n        main_window = std::make_unique<sf::RenderWindow>(sf::VideoMode(desktop.width, desktop.height, desktop.bitsPerPixel)\n            , config.window_title, sf::Style::Fullscreen);\n    }\n    main_window->setVerticalSyncEnabled(true);\n    main_detail::use_root_console = true;\n\n    console = std::make_unique<virtual_terminal>(config.root_font, 0, 0);\n    sf::Vector2u size_pixels = main_window->getSize();\n    console->resize_pixels(size_pixels.x, size_pixels.y);\n}\n\nvoid init(const config_simple_px &config) {\n    register_font_directory(config.font_path);\n    if (!config.fullscreen) {\n        main_window = std::make_unique<sf::RenderWindow>(sf::VideoMode(config.width_px, config.height_px), \n            config.window_title, sf::Style::Titlebar | sf::Style::Resize | sf::Style::Close);\n    } else {\n        sf::VideoMode desktop = sf::VideoMode::getDesktopMode();\n        main_window = std::make_unique<sf::RenderWindow>(sf::VideoMode(desktop.width, desktop.height, desktop.bitsPerPixel)\n            , config.window_title, sf::Style::Fullscreen);\n    }\n    main_window->setVerticalSyncEnabled(true);\n    main_detail::use_root_console = true;\n\n    console = std::make_unique<virtual_terminal>(config.root_font, 0, 0);\n    sf::Vector2u size_pixels = main_window->getSize();\n    console->resize_pixels(size_pixels.x, size_pixels.y);\n}\n\nvoid init(const config_advanced &config) {\n    register_font_directory(config.font_path);\n\n    sf::ContextSettings settings;\n    settings.antialiasingLevel = 4;\n    settings.depthBits = 32;\n    settings.stencilBits = 8;\n\n    if (!config.fullscreen) {\n        main_window = std::make_unique<sf::RenderWindow>(sf::VideoMode(config.width_px, config.height_px), \n            config.window_title, sf::Style::Titlebar | sf::Style::Resize | sf::Style::Close, settings);\n    } else {\n        sf::VideoMode desktop = sf::VideoMode::getDesktopMode();\n        main_window = std::make_unique<sf::RenderWindow>(sf::VideoMode(desktop.width, desktop.height, desktop.bitsPerPixel)\n            , config.window_title, sf::Style::Fullscreen, settings);\n    }\n    main_window->setVerticalSyncEnabled(true);\n    main_detail::use_root_console = false;\n\n    gui = std::make_unique<gui_t>(config.width_px, config.height_px);\n}\n\nstd::function<bool(sf::Event)> optional_event_hook = nullptr;\nstd::function<void()> optional_display_hook = nullptr;\n\nvoid run(std::function<void(double)> on_tick) {    \n    reset_mouse_state();\n\n    double duration_ms = 0.0;\n    while (main_window->isOpen())\n    {\n    \tclock_t start_time = clock();\n\n        sf::Event event;\n        while (main_window->pollEvent(event))\n        {\n            bool handle_events = true;\n            if (optional_event_hook) {\n                handle_events = optional_event_hook(event);\n            }\n            if (handle_events) {\n                if (event.type == sf::Event::Closed) {\n                    main_window->close();\n                } else if (event.type == sf::Event::Resized) {\n                    main_window->setView(sf::View(sf::FloatRect(0.f, 0.f, static_cast<float>(event.size.width),\n                                                                static_cast<float>(event.size.height))));\n                    if (main_detail::use_root_console) console->resize_pixels(event.size.width, event.size.height);\n                    if (gui) gui->on_resize(event.size.width, event.size.height);\n                } else if (event.type == sf::Event::LostFocus) {\n                    set_window_focus_state(false);\n                } else if (event.type == sf::Event::GainedFocus) {\n                    set_window_focus_state(true);\n                } else if (event.type == sf::Event::MouseButtonPressed) {\n                    set_mouse_button_state(event.mouseButton.button, true);\n                } else if (event.type == sf::Event::MouseButtonReleased) {\n                    set_mouse_button_state(event.mouseButton.button, false);\n                } else if (event.type == sf::Event::MouseMoved) {\n                    set_mouse_position(event.mouseMove.x, event.mouseMove.y);\n                } else if (event.type == sf::Event::KeyPressed) {\n                    enqueue_key_pressed(event);\n                } else if (event.type == sf::Event::MouseWheelMoved) {\n                    if (event.mouseWheel.delta < 0) {\n                        set_mouse_button_state(button::WHEEL_UP, true);\n                    } else if (event.mouseWheel.delta > 0) {\n                        set_mouse_button_state(button::WHEEL_DOWN, true);\n                    }\n                }\n            }\n        }\n\n        main_window->clear();\n        //if (main_detail::use_root_console) console->clear();\n\n        on_tick(duration_ms);\n\n        if (main_detail::use_root_console) {\n            console->render(*main_window);\n        } else {\n            gui->render(*main_window);\n        }\n\n        if (optional_display_hook) {\n            main_window->pushGLStates();\n            main_window->resetGLStates();\n            optional_display_hook();\n            main_window->popGLStates();\n        }\n        main_window->display();\n        if (main_detail::taking_screenshot) {\n            sf::Image screen = rltk::get_window()->capture();\n            screen.saveToFile(main_detail::screenshot_filename);\n            main_detail::screenshot_filename = \"\";\n            main_detail::taking_screenshot = false;\n        }\n\n        duration_ms = ((clock() - start_time) * 1000.0) / CLOCKS_PER_SEC;\n    }\n}\n\nvoid request_screenshot(const std::string &filename) {\n    main_detail::taking_screenshot = true;\n    main_detail::screenshot_filename = filename;\n}\n\n}\n"
  },
  {
    "path": "rltk/rltk.hpp",
    "content": "#pragma once\n/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed under the MIT license - see LICENSE file.\n */\n\n#include <string>\n#include <functional>\n#include <SFML/Graphics.hpp>\n#include \"font_manager.hpp\"\n#include \"texture_resources.hpp\"\n#include \"virtual_terminal.hpp\"\n#include \"colors.hpp\"\n#include \"rng.hpp\"\n#include \"geometry.hpp\"\n#include \"path_finding.hpp\"\n#include \"input_handler.hpp\"\n#include \"visibility.hpp\"\n#include \"gui.hpp\"\n#include \"ecs.hpp\"\n#include \"perlin_noise.hpp\"\n#include \"serialization_utils.hpp\"\n#include \"rexspeeder.hpp\"\n#include \"scaling.hpp\"\n\nnamespace rltk {\n\n/* \n * Defines a simple configuration to get most people started. 8x8 font, window size 1024x768. \n */\nstruct config_simple_px {\n\tconfig_simple_px(const std::string fontpath, const int width=1024, const int height=768, const std::string title=\"RLTK Roguelike\", \n\t\tconst std::string font=\"8x8\", bool full_screen=false) :\n\t\tfont_path(fontpath), width_px(width), height_px(height), window_title(title), root_font(font), fullscreen(full_screen) {}\n\n\tconst std::string font_path;\n\tconst int width_px;\n\tconst int height_px;\n\tconst std::string window_title;\n\tconst std::string root_font;\n\tconst bool fullscreen;\n};\n\n/* \n * Defines a simple configuration to get most people started. 8x8 font, window size 128x96 (which happens to be 1024x768) \n */\nstruct config_simple {\n\tconfig_simple(const std::string fontpath, const int width_term=128, const int height_term=96, \n\t\tconst std::string title=\"RLTK Roguelike\", const std::string font=\"8x8\", bool full_screen=false) :\n\t\tfont_path(fontpath), width(width_term), height(height_term), window_title(title), root_font(font), fullscreen(full_screen) {}\n\n\tconst std::string font_path;\n\tconst int width;\n\tconst int height;\n\tconst std::string window_title;\n\tconst std::string root_font;\n\tconst bool fullscreen;\n};\n\n/* \n * Defines an advanced configuration. No root console, so it is designed for the times you want to build your own GUI.\n */\nstruct config_advanced {\n\tconfig_advanced(const std::string fontpath, const int width=1024, const int height=768, const std::string title=\"RLTK Roguelike\",\n\t\tbool full_screen=false) :\n\t\tfont_path(fontpath), width_px(width), height_px(height), window_title(title), fullscreen(full_screen) {}\n\n\tconst std::string font_path;\n\tconst int width_px;\n\tconst int height_px;\n\tconst std::string window_title;\n\tconst bool fullscreen;\n};\n\n/*\n * Bootstrap the system with a simple configuration, specified in pixels.\n * This variant uses terminal coordinates - so specify 80x40 as size and it will scale with the terminal size.\n */\nvoid init(const config_simple &config);\n\n/*\n * Bootstrap the system with a simple configuration, specified in pixels.\n * This variant uses screen coordinates.\n */\nvoid init(const config_simple_px &config);\n\n/*\n * Bootstrap the system with a simple configuration, specified in pixels.\n * This variant doesn't set up much automatically; it's designed for the times you want to define your own GUI.\n */\nvoid init(const config_advanced &config);\n\n/*\n * The main run loop. Calls on_tick each frame. Window can be initially defined with width/height/title, but these\n * have sane defaults to get you started.\n */\nvoid run(std::function<void(double)> on_tick);\n\n/*\n * For rendering to the console\n */\nextern std::unique_ptr<virtual_terminal> console;\n\n/*\n * In case you want to do some SFML stuff yourself, this provides a pointer to the render window.\n */\nsf::RenderWindow * get_window();\n\n/*\n * For GUI manipulation\n */\nextern std::unique_ptr<gui_t> gui;\n\n/*\n * Convenience function to quickly get a GUI layer\n */\ninline layer_t * layer(const int &handle) { return gui->get_layer(handle); }\ninline virtual_terminal * term(const int &handle) { return gui->get_layer(handle)->console.get(); }\ninline virtual_terminal_sparse * sterm(const int &handle) { return gui->get_layer(handle)->sconsole.get(); }\n\n/* Request a screenshot */\nvoid request_screenshot(const std::string &filename);\n\n/* Lifecycle hooks, for example to integrate ImGui with your application. */\nextern std::function<bool(sf::Event)> optional_event_hook;\nextern std::function<void()> optional_display_hook;\n}\n"
  },
  {
    "path": "rltk/rng.cpp",
    "content": "#include \"rng.hpp\"\n\n#include <iostream>\n#include <time.h>\n\nnamespace rltk {\n\n    int random_number_generator::fastrand() {\n        g_seed = (214013 * g_seed + 2531011);\n        return (g_seed >> 16) & 0x7FFF;\n    }\n\n    random_number_generator::random_number_generator() {\n        initial_seed = time(nullptr);\n        g_seed = initial_seed;\n    }\n\n    random_number_generator::random_number_generator(const int seed) {\n        initial_seed = seed;\n        g_seed = initial_seed;\n    }\n\n    random_number_generator::random_number_generator(const std::string seed) {\n        std::hash<std::string> hash_func;\n        initial_seed = hash_func(seed);\n        g_seed = initial_seed;\n    }\n\n    int random_number_generator::roll_dice(const int &n, const int &d) {\n        int total = 0;\n        for (int i = 0; i < n; ++i) {\n            total += ((fastrand() % d)+1);\n        }\n        return total;\n    }\n\n}\n"
  },
  {
    "path": "rltk/rng.hpp",
    "content": "#pragma once\n\n/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed under the MIT license - see LICENSE file.\n *\n * Random number generator class.\n */\n\n#include <string>\n\nnamespace rltk\n{\n\nclass random_number_generator\n{\npublic:\n\trandom_number_generator();\n\trandom_number_generator(const int seed);\n\trandom_number_generator(const std::string seed);\n\n\tint roll_dice(const int &n, const int &d);\n\tint initial_seed;\nprivate:\n    int fastrand();\n    int g_seed;\n};\n\n}"
  },
  {
    "path": "rltk/scaling.cpp",
    "content": "#include \"scaling.hpp\"\n\nnamespace rltk {\n    float scale_factor = 1.0f;\n}"
  },
  {
    "path": "rltk/scaling.hpp",
    "content": "#pragma once\n\nnamespace rltk {\n    extern float scale_factor;\n}"
  },
  {
    "path": "rltk/serialization_utils.hpp",
    "content": "#pragma once\n\n#include <fstream>\n#include <string>\n#include <vector>\n#include <zlib.h>\n#include <utility>\n#include <sstream>\n#include \"color_t.hpp\"\n#include \"xml.hpp\"\n#include \"vchar.hpp\"\n\nnamespace rltk {\n\ntemplate<typename... T>\ninline void component_to_xml(xml_node * c, const T... args);\n\nnamespace serial {\n\n// Forward declarations\ntemplate<typename... T>\ninline void component_to_xml(xml_node * c, const T... args);\n\ntemplate <typename First, typename... Rest>\nvoid _component_to_xml(xml_node * c, First arg, Rest... args);\n\n// Final render to string\ntemplate <class T>\ninline std::string to_string(T val) {\n\tstd::stringstream ss;\n\tss << val;\n\treturn ss.str();\n}\ntemplate <>\ninline std::string to_string(uint8_t val) {\n\tstd::stringstream ss;\n\tss << static_cast<int>(val);\n\treturn ss.str();\n}\n\ntemplate <class T>\nvoid __component_to_xml(xml_node *c, T arg) {\n\tc->add_value(arg.first, rltk::serial::to_string(arg.second));\n}\n\ntemplate< class T >\nstruct has_to_xml_method\n{\n    typedef char(&YesType)[1];\n    typedef char(&NoType)[2];\n    template< class, class > struct Sfinae;\n\n    template< class T2 > static YesType Test( Sfinae<T2, decltype(std::declval<T2>().to_xml( std::declval<xml_node *>() ))> * );\n    template< class T2 > static NoType  Test( ... );\n    static const bool value = sizeof(Test<T>(0))==sizeof(YesType);\n};\n\n/* Uses enable_if to determine if it should call a struct's load method, or just pass through to\n * a more specific Deserialize */\ntemplate<class T>\nstruct _component_to_xml_check_for_to_xml\n{\n    template<class Q = T>\n\ttypename std::enable_if< has_to_xml_method<Q>::value, void >::type\n    test(xml_node * c, std::pair<const char *,Q> &arg)\n    {\n\t\targ.second.to_xml(c);\n    }\n\n    template<class Q = T>\n\ttypename std::enable_if< !has_to_xml_method<Q>::value, void >::type\n    test(xml_node * c, std::pair<const char *,Q> &arg)\n    {\n        __component_to_xml(c, arg);\n    }\n};\n\ntemplate <typename T>\ninline void _component_to_xml(xml_node * c, std::pair<const char *,T> arg) {\n\t_component_to_xml_check_for_to_xml<T> temp;\n\ttemp.test(c, arg);\n}\ntemplate<>\ninline void _component_to_xml(xml_node * c, std::pair<const char *,rltk::color_t> arg) {\n\t// Serialize r/g/b components\n\txml_node * ch = c->add_node(arg.first);\n\tch->add_value(\"r\", std::to_string(arg.second.r));\n\tch->add_value(\"g\", std::to_string(arg.second.g));\n\tch->add_value(\"b\", std::to_string(arg.second.b));\n}\ntemplate<>\ninline void _component_to_xml(xml_node * c, std::pair<const char *,rltk::vchar> arg) {\n\t// Serialize r/g/b components\n\txml_node * ch = c->add_node(arg.first);\n\tch->add_value(\"glyph\", std::to_string(arg.second.glyph));\n\t_component_to_xml(ch, std::make_pair(\"foreground\", arg.second.foreground));\n\t_component_to_xml(ch, std::make_pair(\"background\", arg.second.background));\n}\n\ntemplate<typename T>\ninline void _component_to_xml(xml_node *c, std::pair<const char *, std::vector<T>> arg) {\n\txml_node * vec = c->add_node(arg.first);\n\tfor (T item : arg.second) {\n\t\trltk::component_to_xml(vec, std::make_pair(arg.first, item));\n\t}\n}\n\ntemplate<typename T, typename S>\ninline void _component_to_xml(xml_node *c, std::pair<const char *, std::vector<std::pair<T,S>>> arg) {\n\txml_node * vec = c->add_node(arg.first);\n\tfor (auto item : arg.second) {\n\t\txml_node * e = vec->add_node(arg.first);\n\t\txml_node * i = e->add_node(std::string(arg.first) + std::string(\"_first\"));\n\t\trltk::component_to_xml(i, std::make_pair(arg.first, item.first));\n\t\txml_node * i2 = e->add_node(std::string(arg.first) + std::string(\"_second\"));\n\t\trltk::component_to_xml(i2, std::make_pair(arg.first, item.second));\n\t}\n}\n\ntemplate<typename T, typename S>\ninline void _component_to_xml(xml_node *c, std::pair<const char *, std::unordered_set<T,S>> arg) {\n\txml_node * set = c->add_node(arg.first);\n\tfor (auto it = arg.second.begin(); it != arg.second.end(); ++it) {\n        xml_node * key = set->add_node(\"key\");\n        rltk::component_to_xml(key, std::make_pair(\"k\", *it));\n    }\n}\n\ntemplate<typename T, typename S>\ninline void _component_to_xml(xml_node *c, std::pair<const char *, std::unordered_map<T,S>> arg) {\n    xml_node * map = c->add_node(arg.first);\n    for (auto it = arg.second.begin(); it != arg.second.end(); ++it) {\n        xml_node * entry = map->add_node(arg.first);\n        entry->add_value(\"key\", to_string(it->first));\n        rltk::component_to_xml(entry, std::make_pair(\"v\", it->second));\n    }\n}\n\ntemplate<typename T>\ninline void _component_to_xml(xml_node * c, std::pair<const char *, std::unique_ptr<T>> arg) {\n    xml_node * optional = c->add_node(arg.first);\n    if (!arg.second) {\n        optional->add_value(\"initialized\", \"no\");\n    } else {\n        optional->add_value(\"initialized\", \"yes\");\n        rltk::component_to_xml(optional, std::make_pair(arg.first, *arg.second));\n    }\n}\n\ntemplate <typename First, typename... Rest>\nvoid _component_to_xml(xml_node * c, First arg, Rest... args) {\n\t_component_to_xml(c, arg);\n\t_component_to_xml(c, args...);\n}\n\n} // End serial sub-namespace\n\ntemplate<typename... T>\ninline void component_to_xml(xml_node * c, const T... args) {\n\tserial::_component_to_xml(c, args...);\n}\n\n/* Binary file helpers */\n\ntemplate<class T>\ninline void serialize(std::ostream &lbfile, const T &target) {\n\tlbfile.write(reinterpret_cast<const char *>(&target), sizeof(target));\n}\ntemplate<>\ninline void serialize(std::ostream &lbfile, const std::string &target) {\n\tstd::size_t size = target.size();\n\tserialize<std::size_t>(lbfile, size);\n\tfor (std::size_t i = 0; i < size; ++i)\n\t{\n\t\tserialize<char>(lbfile, target[i]);\n\t}\n}\ntemplate<>\ninline void serialize(std::ostream &lbfile, const rltk::color_t &col) {\n\tserialize<uint8_t>(lbfile, col.r);\n\tserialize<uint8_t>(lbfile, col.g);\n\tserialize<uint8_t>(lbfile, col.b);\n}\n\ntemplate<class T>\ninline void serialize(std::ostream &lbfile, const std::vector<T> &vec) {\n\tstd::size_t sz = vec.size();\n\tserialize(lbfile, sz);\n\tfor (std::size_t i=0; i<sz; ++i) {\n\t\tserialize(lbfile, vec[i]);\n\t}\n}\ntemplate<>\ninline void serialize(std::ostream &lbfile, const std::vector<bool> &vec) {\n\tstd::size_t sz = vec.size();\n\tserialize(lbfile, sz);\n\tfor (std::size_t i=0; i<sz; ++i) {\n\t\tbool b = vec[i];\n\t\tserialize(lbfile, b);\n\t}\n}\n\n\ntemplate<typename T>\ninline void deserialize(std::istream &lbfile, T &target)\n{\n\tlbfile.read(reinterpret_cast<char *>(&target), sizeof(target));\n}\ntemplate<>\ninline void deserialize(std::istream &lbfile, std::string &target)\n{\n\tstd::string result;\n\tstd::size_t size = 0;\n\tdeserialize<std::size_t>(lbfile, size);\n\tfor (std::size_t i = 0; i < size; ++i)\n\t{\n\t\tchar c;\n\t\tdeserialize<char>(lbfile, c);\n\t\tresult += c;\n\t}\n\ttarget = result;\n}\ntemplate<>\ninline void deserialize(std::istream &lbfile, rltk::color_t &target) {\n\tdeserialize(lbfile, target.r);\n\tdeserialize(lbfile, target.g);\n\tdeserialize(lbfile, target.b);\n}\ntemplate<class T>\ninline void deserialize(std::istream &lbfile, std::vector<T> &vec) {\n\tstd::size_t size;\n\tdeserialize(lbfile, size);\n\tvec.resize(size);\n\tfor (std::size_t i=0; i<size; ++i) {\n\t\tT tmp;\n\t\tdeserialize(lbfile, tmp);\n\t\tvec[i] = tmp;\n\t}\n}\n\nstruct gzip_file {\n\tgzip_file(const std::string fn, const char* perms) : filename(fn), permissions(perms) {\n\t\tfile = gzopen(filename.c_str(), permissions);\n\n\t\tif (file == Z_NULL) {\n\t\t\tint err = 0;\n\t\t\tconst char* errstr = gzerror(file, &err);\n\t\t\tif (err == 0) {\n\t\t\t\t/*Assume the file simply didn't exist.*/\n\t\t\t\tstd::string s(\"File \" + filename + \" does not exist.\");\n\t\t\t\tthrow std::runtime_error(s);\n\t\t\t}\n\t\t\tthrow std::runtime_error(std::string(errstr));\n\t\t}\n\t}\n\n\t~gzip_file() {\n\t\tgzclose(file);\n\t}\n\n\tinline void throw_gzip_exception(gzFile &gzfile) {\n\t\tint errnum = 0;\n\t\tconst char* errstr = gzerror(gzfile, &errnum);\n\t\tthrow std::runtime_error(std::to_string(errnum) + std::string(\" \") + std::string(errstr));\n\t}\n\n\ttemplate<class T>\n\tinline void serialize(const T &target) {\n\t\tif (gzwrite(file, reinterpret_cast<const char *>(&target), sizeof(target))) return;\n\t\tthrow_gzip_exception(file);\n\t}\n\ttemplate<class T>\n\tinline void serialize(const std::string &target) {\n\t\tstd::size_t size = target.size();\n\t\tserialize<std::size_t>(size);\n\t\tfor (std::size_t i = 0; i < size; ++i)\n\t\t{\n\t\t\tserialize<char>(target[i]);\n\t\t}\n\t}\n\ttemplate<class T>\n\tinline void serialize(const rltk::color_t &col) {\n\t\tserialize<uint8_t>(col.r);\n\t\tserialize<uint8_t>(col.g);\n\t\tserialize<uint8_t>(col.b);\n\t}\n\tinline void serialize_vector_bool(const std::vector<bool> &vec) {\n\t\tstd::size_t sz = vec.size();\n\t\tserialize(sz);\n\t\tfor (std::size_t i=0; i<sz; ++i) {\n\t\t\tbool b = vec[i];\n\t\t\tserialize<bool>(b);\n\t\t}\n\t}\n\ttemplate<class T>\n\tinline void serialize(const std::vector<T> &vec) {\n\t\tstd::size_t sz = vec.size();\n\t\tserialize(sz);\n\t\tfor (std::size_t i=0; i<sz; ++i) {\n\t\t\tserialize(vec[i]);\n\t\t}\n\t}\n\n\ttemplate<typename T>\n\tinline void deserialize(T &target)\n\t{\n\t\tif (gzread(file, reinterpret_cast<char *>(&target), sizeof(target))) return;\n\t\tthrow_gzip_exception(file);\n\t}\n\ttemplate<typename T>\n\tinline void deserialize(std::string &target)\n\t{\n\t\tstd::string result;\n\t\tstd::size_t size = 0;\n\t\tdeserialize<std::size_t>(size);\n\t\tfor (std::size_t i = 0; i < size; ++i)\n\t\t{\n\t\t\tchar c;\n\t\t\tdeserialize<char>(c);\n\t\t\tresult += c;\n\t\t}\n\t\ttarget = result;\n\t}\n\ttemplate<typename T>\n\tinline void deserialize(rltk::color_t &target) {\n\t\tdeserialize(target.r);\n\t\tdeserialize(target.g);\n\t\tdeserialize(target.b);\n\t}\n\ttemplate<class T>\n\tinline void deserialize(std::vector<T> &vec) {\n\t\tstd::size_t size;\n\t\tdeserialize(size);\n\t\tvec.resize(size);\n\t\tfor (std::size_t i=0; i<size; ++i) {\n\t\t\tT tmp;\n\t\t\tdeserialize(tmp);\n\t\t\tvec[i] = tmp;\n\t\t}\n\t}\n\nprivate:\n\tconst std::string filename;\n\tconst char* permissions;\n\tgzFile file;\n};\n\n}\n"
  },
  {
    "path": "rltk/texture.hpp",
    "content": "#pragma once\n/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed under the MIT license - see LICENSE file.\n *\n * Provides RIAA wrapper for a texture.\n */\n\n#include <SFML/Graphics.hpp>\n#include <memory>\n#include <string>\n#include <stdexcept>\n\nnamespace rltk {\n\nstruct texture {\n\ttexture() {}\n\ttexture(const std::string &filename) {\n\t\ttex = std::make_unique<sf::Texture>();\n\t\tif (!tex->loadFromFile(filename))\n\t\t{\n\t\t    throw std::runtime_error(\"Unable to load texture from: \" + filename);\n\t\t}\n\t}\n\tstd::unique_ptr<sf::Texture> tex;\n};\n\n}\n"
  },
  {
    "path": "rltk/texture_resources.cpp",
    "content": "#include <unordered_map>\n#include <stdexcept>\n#include \"texture_resources.hpp\"\n#include \"texture.hpp\"\n\nnamespace rltk {\n\nnamespace texture_detail {\n\nstd::unordered_map<std::string,rltk::texture> atlas;\n\n}\n\nvoid register_texture(const std::string &filename, const std::string &tag) {\n\tauto finder = texture_detail::atlas.find(tag);\n\tif (finder != texture_detail::atlas.end()) {\n\t\tthrow std::runtime_error(\"Duplicate resource tag: \" + tag);\n\t}\n\n\ttexture_detail::atlas[tag] = rltk::texture(filename);\n}\n\nsf::Texture * get_texture(const std::string &tag) {\n\tauto finder = texture_detail::atlas.find(tag);\n\tif (finder == texture_detail::atlas.end()) {\n\t\tthrow std::runtime_error(\"Unable to find resource tag: \" + tag);\n\t} else {\n\t\treturn finder->second.tex.get();\n\t}\n}\n\n}\n"
  },
  {
    "path": "rltk/texture_resources.hpp",
    "content": "#pragma once\n/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed under the MIT license - see LICENSE file.\n *\n * Provides a global texture atlas.\n */\n\n#include <string>\n#include <SFML/Graphics.hpp>\n\nnamespace rltk {\n\nvoid register_texture(const std::string &filename, const std::string &tag);\nsf::Texture * get_texture(const std::string &tag);\n\n}\n"
  },
  {
    "path": "rltk/vchar.hpp",
    "content": "#pragma once\n/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed under the MIT license - see LICENSE file.\n *\n * Virtual terminal character.\n */\n\n#include \"color_t.hpp\"\n#include <cereal/cereal.hpp>\n\nnamespace rltk {\n/* \n * Represents a character on a virtual terminal. \n */\nstruct vchar {\n\tvchar() {}\n\tvchar(const uint32_t &g, const color_t &f, const color_t &b) : glyph(g), foreground(f), background(b) {}\n\tvchar(const int &g, const color_t &f, const color_t &b) : glyph(static_cast<uint32_t>(g)), foreground(f), background(b) {}\n\tvchar(const uint32_t &gly, const uint8_t &fr, const uint8_t &fg, const uint8_t &fb, const uint8_t &br, const uint8_t &bg, const uint8_t &bb) :\n\t\tglyph(gly), foreground(color_t{fr, fg, fb}), background(color_t{br, bg, bb}) {}\n\n\tuint32_t glyph;\n\tcolor_t foreground;\n\tcolor_t background;\n\n\ttemplate<class Archive>\n\tvoid serialize(Archive & archive)\n\t{\n\t\tarchive( glyph, foreground, background ); // serialize things by passing them to the archive\n\t}\n};\n}"
  },
  {
    "path": "rltk/virtual_terminal.cpp",
    "content": "#include \"virtual_terminal.hpp\"\n#include \"texture_resources.hpp\"\n#include \"scaling.hpp\"\n#include <algorithm>\n#include <stdexcept>\n#include <iostream>\n\nnamespace rltk {\n\nvoid virtual_terminal::resize_pixels(const int width, const int height) noexcept {\n\tint w = static_cast<int>(width/(font->character_size.first * scale_factor));\n\tint h = static_cast<int>(height/(font->character_size.second * scale_factor));\n\tresize_chars(w,h);\n}\n\nvoid virtual_terminal::resize_chars(const int width, const int height) noexcept {\n\tdirty = true;\n\tconst int num_chars = width*(height+1);\n\tbuffer.resize(num_chars);\n\tterm_width = width;\n\tterm_height = height;\n\tbacking.create(term_width * font->character_size.first, term_height * font->character_size.second);\n\n\t// Build the vertex buffer\n\tvertices.setPrimitiveType(sf::Quads);\n\tif (has_background) {\n\t\tvertices.resize(width * height * 8);\n\t} else {\n\t\tvertices.resize(width * height * 4);\t\t\n\t}\n\n\tif (has_background) {\n\t\tconst int idx_half = width * height * 4;\n\t\tconst int font_width = font->character_size.first;\n\t\tconst int font_height = font->character_size.second;\n\n\t\tconst int space_x = (219 % 16) * font_width;\n\t\tconst int space_y = (219 / 16) * font_height;\n\n\t\tfor (int y=0; y<height; ++y) {\n\t\t\tfor (int x=0; x<width; ++x) {\n\t\t\t\tconst int idx = ((y*width) + x)*4;\n\t\t\t\tconst int idx2 = idx + idx_half;\n\t\t\t\tvertices[idx].position = sf::Vector2f(static_cast<float>(x * font->character_size.first), static_cast<float>(y * font->character_size.second));\n\t\t\t\tvertices[idx+1].position = sf::Vector2f(static_cast<float>((x+1) * font->character_size.first), static_cast<float>(y * font->character_size.second));\n\t\t\t\tvertices[idx+2].position = sf::Vector2f(static_cast<float>((x+1) * font->character_size.first), static_cast<float>((y+1) * font->character_size.second));\n\t\t\t\tvertices[idx+3].position = sf::Vector2f(static_cast<float>(x * font->character_size.first), static_cast<float>((y+1) * font->character_size.second));\n\n\t\t\t\tvertices[idx].texCoords = sf::Vector2f(static_cast<float>(space_x), static_cast<float>(space_y) );\n\t\t\t\tvertices[idx+1].texCoords = sf::Vector2f(static_cast<float>(space_x + font_width), static_cast<float>(space_y) );\n\t\t\t\tvertices[idx+2].texCoords = sf::Vector2f(static_cast<float>(space_x + font_width), static_cast<float>(space_y + font_height) );\n\t\t\t\tvertices[idx+3].texCoords = sf::Vector2f(static_cast<float>(space_x), static_cast<float>(space_y + font_height ));\n\n\t\t\t\tvertices[idx2].position = sf::Vector2f(static_cast<float>(x * font->character_size.first), static_cast<float>(y * font->character_size.second));\n\t\t\t\tvertices[idx2+1].position = sf::Vector2f(static_cast<float>((x+1) * font->character_size.first), static_cast<float>(y * font->character_size.second));\n\t\t\t\tvertices[idx2+2].position = sf::Vector2f(static_cast<float>((x+1) * font->character_size.first), static_cast<float>((y+1) * font->character_size.second));\n\t\t\t\tvertices[idx2+3].position = sf::Vector2f(static_cast<float>(x * font->character_size.first), static_cast<float>((y+1) * font->character_size.second));\n\t\t\t}\n\t\t}\n\t} else {\n\t\tfor (int y=0; y<height; ++y) {\n\t\t\tfor (int x=0; x<width; ++x) {\n\t\t\t\tconst int idx = ((y*width) + x)*4;\n\t\t\t\tvertices[idx].position = sf::Vector2f(static_cast<float>(x * font->character_size.first), static_cast<float>(y * font->character_size.second));\n\t\t\t\tvertices[idx+1].position = sf::Vector2f(static_cast<float>((x+1) * font->character_size.first), static_cast<float>(y * font->character_size.second));\n\t\t\t\tvertices[idx+2].position = sf::Vector2f(static_cast<float>((x+1) * font->character_size.first), static_cast<float>((y+1) * font->character_size.second));\n\t\t\t\tvertices[idx+3].position = sf::Vector2f(static_cast<float>(x * font->character_size.first), static_cast<float>((y+1) * font->character_size.second));\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid virtual_terminal::clear() noexcept {\n\tdirty = true;\n\tstd::fill(buffer.begin(), buffer.end(), vchar{ 32, {255,255,255}, {0,0,0} });\n}\n\nvoid virtual_terminal::clear(const vchar &target) noexcept {\n\tdirty = true;\n\tstd::fill(buffer.begin(), buffer.end(), target);\n}\n\nvoid virtual_terminal::set_char(const int idx, const vchar &target) noexcept {\n\tdirty = true;\n\tif (!(idx < 0 || idx > static_cast<int>(buffer.size()))) {\n\t\tbuffer[idx] = target;\n\t}\n}\n\nvoid virtual_terminal::print(const int x, const int y, const std::string &s, const color_t &fg, const color_t &bg) noexcept {\n\tint idx = at(x,y);\n\tfor (std::size_t i=0; i<s.size(); ++i) {\n\t\tbuffer[idx] = { s[i], fg, bg };\n\t\t++idx;\n\t}\n}\n\nvoid virtual_terminal::print_center(const int y, const std::string &s, const color_t &fg, const color_t &bg) noexcept {\n\tprint(static_cast<int>((term_width/2) - (s.size()/2)), y, s, fg, bg);\n}\n\nvoid virtual_terminal::box(const int x, const int y, const int w, const int h, const color_t &fg, const color_t &bg, bool double_lines) noexcept {\n\t//std::cout << h << \"\\n\";\n\tfor (int i=1; i<w; ++i) {\n\t\tif (!double_lines) {\n\t\t\tset_char(x+i, y, vchar{196, fg, bg});\n\t\t\tset_char(x+i, y+h, vchar{196, fg, bg});\n\t\t} else {\n\t\t\tset_char(x+i, y, vchar{205, fg, bg});\n\t\t\tset_char(x+i, y+h, vchar{205, fg, bg});\n\t\t}\n\t}\n\t\n\tfor (int i=1; i<h; ++i) {\n\t\tif (!double_lines) {\n\t\t\tset_char(x, y+i, vchar{179, fg, bg});\n\t\t\tset_char(x+w, y+i, vchar{179, fg, bg});\n\t\t} else {\n\t\t\tset_char(x, y+i, vchar{186, fg, bg});\n\t\t\tset_char(x+w, y+i, vchar{186, fg, bg});\n\t\t}\n\t}\n\t\n\tif (!double_lines) {\n\t\tset_char(x,y, vchar{218, fg, bg});\n\t\tset_char(x+w, y, vchar{191, fg, bg});\n\t\tset_char(x, y+h, vchar{192, fg, bg});\n\t\tset_char(x+w, y+h, vchar{217, fg, bg});\n\t} else {\n\t\tset_char(x,y, vchar{201, fg, bg});\n\t\tset_char(x+w, y, vchar{187, fg, bg});\n\t\tset_char(x, y+h, vchar{200, fg, bg});\n\t\tset_char(x+w, y+h, vchar{188, fg, bg});\n\t}\n}\n\nvoid virtual_terminal::fill(const int left_x, const int top_y, const int right_x, const int bottom_y, const uint8_t glyph, const color_t &fg, const color_t &bg) noexcept {\n\tfor (int y=top_y; y<bottom_y; ++y) {\n\t\tfor (int x=left_x; x<right_x; ++x) {\n\t\t\tset_char(x, y, vchar{glyph, fg, bg});\n\t\t}\n\t}\n}\n\n\nvoid virtual_terminal::draw_sprite(const int x, const int y, xp::rex_sprite &sprite) {\n\tconst int width = sprite.get_width();\n\tconst int height = sprite.get_height();\n\n\tfor (int layer=0; layer<sprite.get_num_layers(); ++layer) {\n\t\tfor (int Y=0; Y<height; ++Y) {\n\t\t\tconst int screen_y = y+Y;\n\t\t\tfor (int X=0; X<width; ++X) {\n\t\t\t\tconst int screen_x = x+X;\n\t\t\t\tconst vchar * output = sprite.get_tile(layer,X,Y);\n\t\t\t\tif (output != nullptr && !xp::is_transparent(output)) set_char(screen_x, screen_y, *output);\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid virtual_terminal::render(sf::RenderWindow &window) {\n\tif (!visible) return;\n\n\tif (dirty) {\n\t\tif (font == nullptr) {\n\t\t\tthrow std::runtime_error(\"Font not loaded: \" + font_tag);\n\t\t}\n\t\tif (tex == nullptr) {\n\t\t\ttex = get_texture(font->texture_tag);\n\t\t}\n\t\tconst int font_width = font->character_size.first;\n\t\tconst int font_height = font->character_size.second;\n\n\t\tint vertex_idx = term_height * term_width * 4;\n\t\tif (!has_background) vertex_idx = 0;\n\t\tint bg_idx = 0;\n\t\tint idx=0;\n\t\tfor (int y=0; y<term_height; ++y) {\n\t\t\tfor (int x=0; x<term_width; ++x) {\n\t\t\t\tconst vchar target = buffer[idx];\n\t\t\t\tconst int texture_x = (target.glyph % 16) * font_width;\n\t\t\t\tconst int texture_y = (target.glyph / 16) * font_height;\n\n\t\t\t\tif (has_background) {\n\t\t\t\t\tsf::Color bgsfml = color_to_sfml(target.background);\n\t\t\t\t\tif (alpha == 0 || (target.background.r == 0 && target.background.g == 0 && target.background.b == 0)) {\n\t\t\t\t\t\tbgsfml.a = 0;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tbgsfml.a = alpha;\n\t\t\t\t\t}\n\t\t\t\t\tvertices[bg_idx].color = bgsfml;\n\t\t\t\t\tvertices[bg_idx+1].color = bgsfml;\n\t\t\t\t\tvertices[bg_idx+2].color = bgsfml;\n\t\t\t\t\tvertices[bg_idx+3].color = bgsfml;\n\t\t\t\t}\n\n\t\t\t\tvertices[vertex_idx].texCoords = sf::Vector2f(static_cast<float>(texture_x), static_cast<float>(texture_y) );\n\t\t\t\tvertices[vertex_idx+1].texCoords = sf::Vector2f(static_cast<float>(texture_x + font_width), static_cast<float>(texture_y) );\n\t\t\t\tvertices[vertex_idx+2].texCoords = sf::Vector2f(static_cast<float>(texture_x + font_width), static_cast<float>(texture_y + font_height) );\n\t\t\t\tvertices[vertex_idx+3].texCoords = sf::Vector2f(static_cast<float>(texture_x), static_cast<float>(texture_y + font_height) );\n\n\t\t\t\tsf::Color fgsfml = color_to_sfml(target.foreground);\n\t\t\t\tvertices[vertex_idx].color = fgsfml;\n\t\t\t\tvertices[vertex_idx+1].color = fgsfml;\n\t\t\t\tvertices[vertex_idx+2].color = fgsfml;\n\t\t\t\tvertices[vertex_idx+3].color = fgsfml;\n\n\t\t\t\tvertex_idx += 4;\n\t\t\t\tbg_idx += 4;\n\t\t\t\t++idx;\n\t\t\t}\n\t\t}\n\t\tbacking.clear(sf::Color(0,0,0,0));\n\t\tbacking.draw(vertices, tex);\n\t}\n\n\tbacking.display();\n\tsf::Sprite compositor(backing.getTexture());\n\tcompositor.move(static_cast<float>(offset_x), static_cast<float>(offset_y));\n\tcompositor.setColor(sf::Color(tint.r, tint.g, tint.b, alpha));\n    compositor.scale(scale_factor, scale_factor);\n\twindow.draw(sf::Sprite(compositor));\n\tdirty = false;\n}\n\n}\n"
  },
  {
    "path": "rltk/virtual_terminal.hpp",
    "content": "#pragma once\n/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed under the MIT license - see LICENSE file.\n *\n * Provides a virtual console\n */\n\n#include <vector>\n#include <string>\n#include <SFML/Graphics.hpp>\n#include \"font_manager.hpp\"\n#include \"texture.hpp\"\n#include \"color_t.hpp\"\n#include \"colors.hpp\"\n#include \"rexspeeder.hpp\"\n#include \"vchar.hpp\"\n\nnamespace rltk {\n\n/*\n * Combines the functions/data required to render a virtual terminal, either as root or\n * as a layer. This is generally initialized by the library, not the user.\n */\nstruct virtual_terminal {\npublic:\n\t/*\n\t * Constructor to create a virtual terminal. Parameters:\n\t *   fontt the tag of the bitmap font to use for the terminal.\n\t *   x (defaults to 0); an offset at which to render the terminal.\n\t *   y (defaults to 0); an offset at which to render the terminal.\n\t *   background; if true, then solid backgrounds will be rendered. If false, then no background rendered.\n\t */\n\tvirtual_terminal(const std::string fontt, const int x=0, const int y=0, const bool background=true) : font_tag(fontt), offset_x(x), offset_y(y), has_background(background) {\n\t\tfont = get_font(fontt);\n\t}\n\n\t/*\n\t * Resize the terminal to match width x height pixels.\n\t */\n\tvoid resize_pixels(const int width, const int height) noexcept;\n\n\t/*\n\t * Resize the terminal to match width x height virtual characters.\n\t */\n\tvoid resize_chars(const int width, const int height) noexcept;\n\n\t/*\n\t * Clears the virtual terminal to black spaces.\n\t */\n\tvoid clear() noexcept;\n\n\t/*\n\t * Clears the virtual terminal to a user-provided character.\n\t * vchar; the character to which the terminal should be set.\n\t */\n\tvoid clear(const vchar &target) noexcept;\n\n\t/*\n\t * Helper function that returns the index of a character location in the backing vector.\n\t */\n\tinline int at(const int x, const int y) noexcept { return ( y * term_width) + x; }\n\n\t/*\n\t * Set a character at backing-vector idx (use \"at\" to calculate) to the specified target virtual\n\t * character.\n\t */\n\tvoid set_char(const int idx, const vchar &target) noexcept;\n\n\t/*\n\t * Set a character at x/y to the specified target virtual character.\n\t */\n\tinline void set_char(const int x, const int y, vchar target) noexcept { set_char(at(x,y), target); }\n\n\t/*\n\t * Print a string to the terminal, at location x/y, string s, with foreground and background of fg and bg.\n\t * If you don't specify colors, it will do white on black.\n\t */\n\tvoid print(const int x, const int y, const std::string &s, const color_t &fg = colors::WHITE, const color_t &bg = colors::BLACK) noexcept;\n\n\t/*\n\t * Center a string (relative to the terminal size), and print it at location y.\n\t */\n\tvoid print_center(const int y, const std::string &s, const color_t &fg = colors::WHITE, const color_t &bg = colors::BLACK) noexcept;\n\n\t/*\n\t * Draw a box taht encompasses the whole terminal boundary, in color fg/bg. If double_lines is set to true, then\n\t * it will use the two-line/thick box characters.\n\t */\n\tinline void box(const color_t &fg = colors::WHITE, const color_t &bg = colors::BLACK, bool double_lines=false) noexcept {\n\t\tbox (0, 0, term_width-1, term_height-1, fg, bg, double_lines);\n\t}\n\n\t/*\n\t * Draw a box at x/y of size w/h, in color fg/bg (or black/white if not specified). If double_lines is true,\n\t * it will use the two-line/thick box characters.\n\t */\n\tvoid box(const int x, const int y, const int w, const int h, const color_t &fg = colors::WHITE, const color_t &bg = colors::BLACK, bool double_lines=false) noexcept;\n\n\t/*\n\t * Fill a region with a specified character\n\t */\n\tvoid fill(const int left_x, const int top_y, const int right_x, const int bottom_y, const uint8_t glyph, const color_t &fg = colors::WHITE, const color_t &bg = colors::BLACK) noexcept;\n\n\t/*\n\t * Draw a REX sprite at the specified location.\n\t */\n\tvoid draw_sprite(const int x, const int y, xp::rex_sprite &sprite);\n\n\t/*\n\t * Renders the terminal to the specified renderable. Don't call this directly - the toolkit will take care of it.\n\t */\n\tvoid render(sf::RenderWindow &window);\n\n\t/*\n\t * Sets the global translucency level for the console. You can use this to make a translucent console layer on top of\n\t * other items.\n\t */\n\tinline void set_alpha(const uint8_t new_alpha) noexcept { alpha = new_alpha; }\n\n\t/*\n\t * Use this to tint the entire rendering of the console.\n\t */\n\tinline void set_tint(const color_t new_tint) noexcept { tint = new_tint; }\n\n\t/*\n\t * Use this to move the terminal in x/y screen pixels.\n\t */\n\tinline void set_offset(int x, int y) noexcept { offset_x = x; offset_y = y; };\n\n\t/*\n\t * This gets the current font size in pixels, first is width, second is height.\n\t */\n\tinline std::pair<int,int> get_font_size() noexcept { return font->character_size; }\n\n\tinline std::string get_font_tag() noexcept { return font->texture_tag; }\n\n\tint term_width;\n\tint term_height;\n\tbool visible = true;\n\tbool dirty = true; // Flag for requiring a re-draw\n\nprivate:\n\tsf::RenderTexture backing;\n\tsf::VertexArray vertices;\n\tstd::string font_tag;\n\tint offset_x;\n\tint offset_y;\n\tuint8_t alpha = 255;\n\tcolor_t tint{255,255,255};\n\tbool has_background;\n\tbitmap_font * font = nullptr;\n\tsf::Texture * tex = nullptr;\n\tstd::vector<vchar> buffer;\n\n};\n\n}"
  },
  {
    "path": "rltk/virtual_terminal_sparse.cpp",
    "content": "#include \"virtual_terminal_sparse.hpp\"\n#include \"texture_resources.hpp\"\n#include \"scaling.hpp\"\n\nnamespace rltk {\n\nvoid virtual_terminal_sparse::resize_pixels(const int width, const int height) {\n    int w = static_cast<int>(width/(font->character_size.first * scale_factor));\n    int h = static_cast<int>(height/(font->character_size.second * scale_factor));\n\tresize_chars(w,h);\n}\n\nvoid virtual_terminal_sparse::resize_chars(const int width, const int height) {\n\tdirty = true;\n\tconst int num_chars = width*(height+1);\n\tbuffer.resize(num_chars);\n\tterm_width = width;\n\tterm_height = height;\n\tbacking.create(term_width * font->character_size.first, term_height * font->character_size.second);\n}\n\nvoid virtual_terminal_sparse::render(sf::RenderWindow &window) {\n\tif (!visible) return;\n\n\tif (dirty) {\n\t\tif (font == nullptr) {\n\t\t\tthrow std::runtime_error(\"Font not loaded: \" + font_tag);\n\t\t}\n\t\tif (tex == nullptr) {\n\t\t\ttex = get_texture(font->texture_tag);\n\t\t}\n\t\tconst int font_width = font->character_size.first;\n\t\tconst int font_height = font->character_size.second;\n\t\tconst float fontW = static_cast<float>(font_width);\n\t\tconst float fontH = static_cast<float>(font_height);\n\t\tconst sf::Vector2f origin(fontW/2.0f, fontH/2.0f);\n\n\t\tconst int space_x = (219 % 16) * font_width;\n\t\tconst int space_y = (219 / 16) * font_height;\n\n\t\t// We want to iterate the display vector, and put sprites on the screen for each entry\n\t\tbacking.clear(sf::Color(0,0,0,0));\n\t\tfor (const xchar &target : buffer) {\n\n\t\t\tconst int texture_x = (target.glyph % 16) * font_width;\n\t\t\tconst int texture_y = (target.glyph / 16) * font_height;\n\t\t\tsf::Vector2f position((target.x * fontW) + fontW/2.0f, (target.y * fontH) + fontH/2.0f);\n\n\t\t\tif (target.has_background) {\n\t\t\t\tsf::Color bgsfml = color_to_sfml(target.background);\n\t\t\t\tsf::Sprite sprite;\n\t\t\t\tsprite.setTexture(*tex);\n\t\t\t\tsprite.setTextureRect(sf::IntRect(space_x, space_y, font_width, font_height));\n\t\t\t\tsprite.setColor(bgsfml);\n\t\t\t\tsprite.setOrigin(origin);\n\t\t\t\tsprite.setPosition(position);\n\t\t\t\tsprite.setRotation(static_cast<float>(target.angle));\n\t\t\t\tbacking.draw(sprite);\n\t\t\t}\n\t\t\tsf::Color fgsfml = color_to_sfml(target.foreground);\n\t\t\tsf::Sprite sprite;\n\t\t\tsprite.setTexture(*tex);\n\t\t\tsprite.setTextureRect(sf::IntRect(texture_x, texture_y, font_width, font_height));\n\t\t\tsprite.setColor(fgsfml);\n\t\t\tsprite.setOrigin(origin);\n\t\t\tsprite.setPosition(position);\n\t\t\tsprite.setRotation(static_cast<float>(target.angle));\n\t\t\tbacking.draw(sprite);\n\n\t\t}\n\t}\n\n\t// Draw the backing\n\tbacking.display();\n\tsf::Sprite compositor(backing.getTexture());\n\tcompositor.move(static_cast<float>(offset_x), static_cast<float>(offset_y));\n\tcompositor.setColor(sf::Color(tint.r, tint.g, tint.b, alpha));\n    compositor.scale(scale_factor, scale_factor);\n\twindow.draw(sf::Sprite(compositor));\n\tdirty = false;\n}\n\n}\n"
  },
  {
    "path": "rltk/virtual_terminal_sparse.hpp",
    "content": "/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed under the MIT license - see LICENSE file.\n *\n * Provides a virtual console, in 'sparse' mode: it doesn't assume that you have a regular grid,\n * supports off-alignment rendering, rotation and similar. It is optimized for use with a few\n * characters, rather than a complete grid. A common usage would be as a layer for PCs/NPCs,\n * rendered over a regular console grid.\n */\n\n#pragma once\n\n#include <SFML/Graphics.hpp>\n#include <vector>\n#include \"font_manager.hpp\"\n#include \"texture.hpp\"\n#include \"color_t.hpp\"\n#include \"colors.hpp\"\n\nnamespace rltk {\n\n/* \n * Represents a character on a sparse virtual terminal. \n */\nstruct xchar {\n\txchar() {}\n\txchar(const int Glyph, const color_t fg, const float X, const float Y) : glyph(Glyph), foreground(fg), x(X), y(Y) {}\n\txchar(const int Glyph, const color_t fg, const float X, const float Y, const int ANGLE) : glyph(Glyph), foreground(fg), x(X), y(Y), angle(ANGLE) {}\n\tint glyph; // Glyph to render\n\tcolor_t foreground; // Foreground color\n\tfloat x = 0.0f; // Provided as floats to allow for partial character movement/sliding\n\tfloat y = 0.0f;\n\tint angle = 0; // Rotation angle in degrees, defaults to 0 - not rotated\n\tunsigned char opacity = 255;\n\tbool has_background = false;\n\tcolor_t background; // If provided, a background is drawn\n};\n\nstruct virtual_terminal_sparse {\n\n\tvirtual_terminal_sparse(const std::string fontt, const int x=0, const int y=0) : font_tag(fontt), offset_x(x), offset_y(y) {\n\t\tfont = get_font(fontt);\n\t}\n\n\tvoid resize_pixels(const int width, const int height);\n\tvoid resize_chars(const int width, const int height);\n\tinline void clear() {\n\t\tdirty = true;\n\t\tbuffer.clear();\n\t}\n\tinline void add(const xchar target) {\n\t\tdirty = true;\n\t\tbuffer.push_back(target);\n\t}\n\tvoid render(sf::RenderWindow &window);\n\n\tint term_width;\n\tint term_height;\n\tbool visible = true;\n\tbool dirty = true; // Flag for requiring a re-draw\n\nprivate:\n\tstd::string font_tag;\n\tint offset_x;\n\tint offset_y;\n\tuint8_t alpha = 255;\n\tcolor_t tint{255,255,255};\n\tbitmap_font * font = nullptr;\n\tsf::Texture * tex = nullptr;\n\tstd::vector<xchar> buffer;\n\tsf::RenderTexture backing;\n};\n\n}\n"
  },
  {
    "path": "rltk/visibility.hpp",
    "content": "#pragma once\n/* RLTK (RogueLike Tool Kit) 1.00\n * Copyright (c) 2016-Present, Bracket Productions.\n * Licensed under the MIT license - see LICENSE file.\n *\n * Provides a wrapper for bitmap fonts.\n */\n\n#include <functional>\n#include \"geometry.hpp\"\n\nnamespace rltk {\n\nnamespace visibility_private {\n\n/*\n * Benchmark results from example 6 (on my desktop):\n * - Using line_func, it averages 0.3625 uS per line.\n * - Using line_func_cancellable, it averages 0.25 uS per line.\n * - Using a naieve float based slope, it averages 0.2 uS per line.\n */\n\ntemplate<class location_t_, class navigator_t>\nvoid internal_2d_sweep(const location_t_ &position, const int &range, std::function<void(location_t_)> set_visible, \n\tstd::function<bool(location_t_)> is_opaque, const std::pair<int,int> offset)\n{\n\tbool blocked = false;\n\tconst int start_x = navigator_t::get_x(position);\n\tconst int start_y = navigator_t::get_y(position);\n\tconst int end_x = start_x + offset.first;\n\tconst int end_y = start_y + offset.second;\n\t\n\tline_func_cancellable(start_x, start_y, end_x, end_y, [&blocked, &is_opaque, &set_visible, &range, &position] (int X, int Y) {\n\t\tif (blocked) return false;\n\t\tfloat distance = distance2d(static_cast<int>(position.x), static_cast<int>(position.y), X, Y);\n\t\tif (distance <= range) {\n\t\t\tlocation_t_ pos = navigator_t::get_xy(X,Y);\n\t\t\tif (!blocked) set_visible(pos);\n\t\t\tif (!is_opaque(pos)) blocked = true;\n\t\t}\n\t\treturn true;\n\t});\n}\n\n}\n\n/* Simple all-direction visibility sweep in 2 dimensions. This requires that your location_t utilize an x and y\n * component. Parameters:\n * position - where you are sweeping from.\n * range - the number of tiles you can traverse.\n * set_visible - a callback (such as bool set_visible(location_t & loc)) to say \"this is visible\"\n * is_opaque - a callback to ask your map if you can see through a tile.\n *\n * You must provide a navigator_t, just like for path finding. It must support get_x, get_y, and get_xy.\n */\ntemplate<class location_t_, class navigator_t>\nvoid visibility_sweep_2d(const location_t_ &position, const int &range, std::function<void(location_t_)> set_visible, \n\tstd::function<bool(location_t_)> is_opaque)\n{\n\t// You can always see yourself\n\tset_visible(position);\n\n\t// Box-sweep\n\tfor (int i=0-range; i<range; ++i) {\n\t\tvisibility_private::internal_2d_sweep<location_t_, navigator_t>(position, range, set_visible, is_opaque, std::make_pair(i, 0-range));\n\t\tvisibility_private::internal_2d_sweep<location_t_, navigator_t>(position, range, set_visible, is_opaque, std::make_pair(i, range));\n\t\tvisibility_private::internal_2d_sweep<location_t_, navigator_t>(position, range, set_visible, is_opaque, std::make_pair(0-range, i));\n\t\tvisibility_private::internal_2d_sweep<location_t_, navigator_t>(position, range, set_visible, is_opaque, std::make_pair(range, i));\n\t}\n}\n\n}\n"
  },
  {
    "path": "rltk/xml.cpp",
    "content": "#include \"xml.hpp\"\n#include <stack>\n#include <algorithm> \n#include <functional> \n#include <cctype>\n#include <locale>\n#include <iostream>\n#include <string>\n\nusing namespace std::string_literals;\n\nnamespace rltk {\n\nxml_node * xml_node::add_node(const std::string &name) {\n    children.push_back(xml_node(name, depth+1));\n    return &children[children.size()-1];\n}\n\nvoid xml_node::add_node(xml_node x) {\n    children.push_back(x);\n}\n\nstd::string xml_node::indent() const {\n    std::string result;\n    for (int i=0; i<depth; ++i) result += ' ';\n    return result;\n}\n\nvoid xml_node::save(std::ofstream &lbfile) const {\n    lbfile << indent() << \"<\" << name << \">\\n\";\n    for (const auto & val : values) {\n        lbfile << indent() << \" <\" << val.first << \":value>\" << val.second << \"</\" << val.first << \":value>\\n\";\n    }\n    for (const xml_node &child : children) {\n        child.save(lbfile);\n    }\n    lbfile << indent() << \"</\" << name << \">\\n\";\n}\n\nvoid xml_node::dump(std::stringstream &lbfile) const {\n    lbfile << indent() << \"<\" << name << \">\\n\";\n    for (const auto & val : values) {\n        lbfile << indent() << \" <\" << val.first << \":value>\" << val.second << \"</\" << val.first << \":value>\\n\";\n    }\n    for (const xml_node &child : children) {\n        child.dump(lbfile);\n    }\n    lbfile << indent() << \"</\" << name << \">\\n\";    \n}\n\nstd::string xml_node::dump() const {\n    std::stringstream ss;\n    dump(ss);\n    return ss.str();\n}\n\nvoid xml_node::add_value(const std::string &key, const std::string &val) {\n    values.emplace_back(std::make_pair(key, val));\n}\n\nstatic inline std::string &ltrim(std::string &s) {\n    s.erase(s.begin(), std::find_if(s.begin(), s.end(),\n            std::not1(std::ptr_fun<int, int>(std::isspace))));\n    return s;\n}\n\nstatic inline void erase_all(std::string &s, const std::string &to_remove) {\n    auto pos = s.find(to_remove);\n    while (pos != std::string::npos) {\n        s.erase(pos, to_remove.size());\n\tpos = s.find(to_remove);\n    }\n}\n\nstatic inline std::string remove_xml_braces(std::string s) {\n    erase_all(s, \"<\");\n    erase_all(s, \">\");\n    return s;\n}\n\nstatic inline std::string remove_colon_value(std::string s) {\n    erase_all(s, \":value\");\n    return s;\n}\n\nvoid xml_reader::load() {\n    std::stack<xml_node> stack;\n\n    bool first_line = true;\n    std::string line;\n    while (getline(*lbfile, line)) {\n        std::string trimmed = ltrim(line);\n        erase_all(trimmed, \"\\n\");\n\n        if (first_line) {\n            root.name = remove_xml_braces(trimmed);\n            first_line = false;\n        } else if (trimmed == \"</\"s + root.name + \">\"s) {\n            // We're at the end.\n        } else if (stack.empty()) {\n            // We're at the beginning, so we need to create a node.\n            stack.push(xml_node(remove_xml_braces(trimmed)));\n        } else if (trimmed == \"</\"s + stack.top().name + \">\"s ) {\n            // We're at the end of the element\n            if (stack.size() > 1) {\n                xml_node current = stack.top();\n                stack.pop();\n                stack.top().add_node(current);\n            } else {\n                xml_node current = stack.top();\n                stack.pop();\n                root.add_node(current);\n            }\n        } else {\n            // Are we looking at a new node or a value?\n            if (trimmed.find(\":value>\")==std::string::npos) {\n                // It's a new child\n                stack.push(xml_node(remove_xml_braces(trimmed)));\n            } else {\n                // It's a value\n                std::string key = remove_colon_value(remove_xml_braces(trimmed.substr(0,trimmed.find(\">\"))));\n                std::string val = trimmed.substr(trimmed.find(\">\")+1);\n                val = val.substr(0, val.find(\"<\"));\n                stack.top().add_value(key, val);\n            }\n        }\n    }\n}\n\n}\n"
  },
  {
    "path": "rltk/xml.hpp",
    "content": "#pragma once\n\n#include <string>\n#include <fstream>\n#include <vector>\n#include <utility>\n#include <memory>\n#include <sstream>\n#include <cstdio>\n#include \"color_t.hpp\"\n#include \"vchar.hpp\"\n#include \"filesystem.hpp\"\n\nnamespace rltk {\n\ntemplate<typename T>\ninline T from_string(const std::string &val) {\n    std::stringstream ss;\n    ss << val;\n    T result;\n    ss >> result;\n    return result;\n}\ntemplate<>\ninline uint8_t from_string(const std::string &val) {\n    std::stringstream ss;\n    ss << val;\n    int result;\n    ss >> result;\n    return static_cast<uint8_t>(result);\n}\ntemplate<>\ninline std::string from_string(const std::string &val) {\n    return val;\n}\n\nstruct xml_node {\n    xml_node() {};\n    xml_node(const std::string &Name) : name(Name) {}\n    xml_node(const std::string &Name, const int Depth) : name(Name), depth(Depth) {}\n\n    xml_node * add_node(const std::string &name);\n    void add_node(xml_node x);\n    std::string indent() const;\n    void save(std::ofstream &lbfile) const;\n    void dump(std::stringstream &lbfile) const;\n    std::string dump() const;\n    void add_value(const std::string &key, const std::string &val);\n\n    std::string name = \"\";\n\n    std::size_t count() {\n        std::size_t count = 0;\n        for (xml_node &node : children) {\n            node.count(count);\n        }\n        return count;\n    }\n\n    void count(std::size_t &count) {\n        ++count;\n        for (xml_node &node : children) {\n            node.count(count);\n        }\n    }\n\n    xml_node * find(const std::string name) {\n        for (xml_node &node : children) {\n            if (node.name == name) return &node;\n        }\n        return nullptr;\n    }\n\n    template<typename T>\n    T val(const std::string &key) {\n        for (const auto &val : values) {\n            if (val.first == key) {\n                return from_string<T>(val.second);\n            }\n        }\n        throw std::runtime_error(std::string(\"Key not found:\") + key);\n    }\n\n    inline void iterate_child(const std::string &name, const std::function<void(xml_node *)> &func) {\n        xml_node * vec = find(name);\n        for (xml_node child : vec->children) {\n            func(&child);\n        }\n    }\n\n    inline color_t color(const std::string &name) {\n        xml_node * c = find(name);\n        return color_t{c->val<uint8_t>(\"r\"), c->val<uint8_t>(\"g\"), c->val<uint8_t>(\"b\")};\n    }\n\n    inline rltk::vchar vchar() {\n        rltk::vchar c;\n        c.glyph = val<uint32_t>(\"glyph\");\n        c.foreground = color(\"foreground\");\n        c.background = color(\"background\");\n        return c;\n    }\n\n    const int depth = 0;\n    std::vector<xml_node> children;\n    std::vector<std::pair<std::string, std::string>> values;\n\n};\n\nstruct xml_writer {\n    xml_writer(const std::string &fn, const std::string &root_name) : filename(fn), root(xml_node(root_name,0)) {\n        if (exists(filename)) std::remove(filename.c_str());\n\t    lbfile = std::make_unique<std::ofstream>(filename, std::ios::out | std::ios::binary);\n    }\n\n    xml_writer(std::unique_ptr<std::ofstream> &&f, const std::string &root_name) : lbfile(std::move(f)), root(xml_node(root_name,0)) {}\n\n    inline void commit() {        \n        root.save(*lbfile);\n    }\n\n    inline xml_node * add_node(const std::string &name) {\n        return root.add_node(name);\n    }\n\nprivate:\n    std::unique_ptr<std::ofstream> lbfile;\n    const std::string filename = \"\";\n    xml_node root;\n};\n\nstruct xml_reader {\n    xml_reader(const std::string &fn) : filename(fn) {\n        if (!exists(filename)) throw std::runtime_error(std::string(\"File not found: \") + filename);\n\t    lbfile = std::make_unique<std::ifstream>(filename, std::ios::in | std::ios::binary);\n        load();\n    }\n\n    xml_reader(std::unique_ptr<std::ifstream> &&f) : lbfile(std::move(f)) {\n        load();\n    }\n\n    inline xml_node * get() { return &root; }\n\nprivate:\n    std::unique_ptr<std::ifstream> lbfile;\n    const std::string filename = \"\";\n    xml_node root;\n\n    void load();\n};\n\n}\n"
  }
]