[
  {
    "path": ".gitattributes",
    "content": "# Auto detect text files and perform LF normalization\n* text=auto\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Describe the bug**\nA clear and concise description of what the bug is.\n\n**To Reproduce**\nSteps to reproduce the behavior:\n1. Go to '...'\n2. Click on '....'\n3. See error\n\n**Expected behavior**\nA clear and concise description of what you expected to happen.\n\n**Screenshots**\nIf applicable, add screenshots to help explain your problem.\n\n**Desktop (please complete the following information):**\n - OS: [e.g. macOS]\n - Version [e.g. Mojave 10.14.1]\n\n**Additional context**\nAdd any other context about the problem here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Is your feature request related to a problem? Please describe.**\nA clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n\n**Describe the solution you'd like**\nA clear and concise description of what you want to happen.\n\n**Describe alternatives you've considered**\nA clear and concise description of any alternative solutions or features you've considered.\n\n**Additional context**\nAdd any other context or screenshots about the feature request here.\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "# Pull Request Template\n\n## Description\n\nPlease include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change.\n\nFixes #(issue)\n\n## Type of change\n\nPlease delete options that are not relevant.\n\n- [ ] Bug fix (non-breaking change which fixes an issue)\n- [ ] New feature (non-breaking change which adds functionality)\n- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)\n- [ ] This change requires a documentation update\n\n## How Has This Been Tested?\n\nPlease describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration\n\n- [ ] Test A\n- [ ] Test B\n\n**Test Configuration**:\n* Operating system:\n\n## Checklist:\n\n- [ ] My code follows the style guidelines of this project\n- [ ] I have performed a self-review of my own code\n- [ ] I have commented my code, particularly in hard-to-understand areas\n- [ ] My changes generate no new warnings\n- [ ] I have added tests that prove my fix is effective or that my feature works\n- [ ] Any dependent changes have been merged and published in downstream modules\n"
  },
  {
    "path": ".github/workflows/Build.yml",
    "content": "name: Build\n\non:\n  push:\n  pull_request:\n\nenv:\n  BUILD_TYPE: Release\n\njobs:\n  linux:\n    runs-on: ubuntu-20.04\n    name: 🐧 Ubuntu 20.04\n    steps:\n      - name: 🧰 Checkout\n        uses: actions/checkout@v2\n        with:\n          fetch-depth: 0\n          submodules: true\n\n      - name: ⬇️ Install dependencies\n        run: |\n          sudo apt-get update\n          sudo apt-get install -y \\\n            build-essential       \\\n            gcc-10                \\\n            g++-10                \\\n            libglew-dev           \\\n            libsdl2-dev           \\\n            libsdl2-mixer-dev     \\\n            libglm-dev\n\n      - name: Create Build Environment\n        run: cmake -E make_directory ${{runner.workspace}}/build\n\n      - name: Configure CMake\n        shell: bash\n        env:\n          CC: gcc-10\n          CXX: g++-10\n        working-directory: ${{runner.workspace}}/build\n        run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE\n\n      - name: Build\n        working-directory: ${{runner.workspace}}/build\n        shell: bash\n        env:\n          CC: gcc-10\n          CXX: g++-10\n        run: cmake --build . --config $BUILD_TYPE --target package\n\n      - name: 📦 Upload Ubuntu package to release\n        uses: svenstaro/upload-release-action@v2\n        if: startsWith(github.ref, 'refs/tags/v')\n        with:\n          repo_token: ${{ secrets.GITHUB_TOKEN }}\n          file: ${{runner.workspace}}/build/*.zip\n          tag: ${{ github.ref }}\n          overwrite: true\n          file_glob: true\n\n      - name: 📦 Upload Ubuntu package\n        uses: actions/upload-artifact@v2\n        with:\n          name: engge-linux\n          path: ${{runner.workspace}}/build/*.zip\n\n  win:\n    runs-on: windows-latest\n    name: 🟦 Windows x64\n    steps:\n\n      - name: 🧰 Checkout\n        uses: actions/checkout@v2\n        with:\n          fetch-depth: 0\n          submodules: true\n\n      - name: ⬇️ Install dependencies\n        run: vcpkg install freetype:x64-windows glew:x64-windows sdl2:x64-windows sdl2-mixer:x64-windows glm:x64-windows\n\n      - name: Create Build Environment\n        run: cmake -E make_directory ${{runner.workspace}}/build\n\n      - name: Configure CMake Windows\n        shell: bash\n        working-directory: ${{runner.workspace}}/build\n        run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_TOOLCHAIN_FILE=\"C:/vcpkg/scripts/buildsystems/vcpkg.cmake\" -DVCPKG_BIN_DIR=\"c:/vcpkg/installed/x64-windows/bin\"\n\n      - name: Build\n        working-directory: ${{runner.workspace}}/build\n        shell: bash\n        run: cmake --build . --config $BUILD_TYPE --target package\n\n      - name: 📦 Upload Windows package to release\n        uses: svenstaro/upload-release-action@v2\n        if: startsWith(github.ref, 'refs/tags/v')\n        with:\n          repo_token: ${{ secrets.GITHUB_TOKEN }}\n          file: ${{runner.workspace}}/build/*.zip\n          tag: ${{ github.ref }}\n          overwrite: true\n          file_glob: true\n\n      - name: 📦 Upload Portable ZIP\n        uses: actions/upload-artifact@v2\n        with:\n          name: engge-win\n          path: ${{runner.workspace}}/build/*.zip\n\n  macos-build:\n    runs-on: macos-11.0\n    name: 🍎 macOS 11.0\n    steps:\n\n      - name: 🧰 Checkout\n        uses: actions/checkout@v2\n        with:\n          fetch-depth: 0\n          submodules: true\n\n      - name: ⬇️ Install dependencies\n        run: brew install glew sdl2 sdl2_mixer glm\n\n      - name: Create Build Environment\n        run: cmake -E make_directory ${{runner.workspace}}/build\n\n      - name: Configure CMake\n        shell: bash\n        working-directory: ${{runner.workspace}}/build\n        run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE\n\n      - name: Build\n        working-directory: ${{runner.workspace}}/build\n        shell: bash\n        run: |\n          cmake --build . --config $BUILD_TYPE --target package\n\n      - name: 📦 Upload macOS package to release\n        uses: svenstaro/upload-release-action@v2\n        if: startsWith(github.ref, 'refs/tags/v')\n        with:\n          repo_token: ${{ secrets.GITHUB_TOKEN }}\n          file: ${{runner.workspace}}/build/*.zip\n          tag: ${{ github.ref }}\n          overwrite: true\n          file_glob: true\n\n      - name: 📦 Upload Portable ZIP\n        uses: actions/upload-artifact@v2\n        with:\n          name: engge-macOS\n          path: ${{runner.workspace}}/build/*.zip\n"
  },
  {
    "path": ".gitignore",
    "content": "# Prerequisites\n*.d\n\n# Compiled Object files\n*.slo\n*.lo\n*.o\n*.obj\n\n# Precompiled Headers\n*.gch\n*.pch\n\n# Compiled Dynamic libraries\n*.so\n*.dylib\n*.dll\n\n# Fortran module files\n*.mod\n*.smod\n\n# Compiled Static libraries\n*.lai\n*.la\n*.a\n*.lib\n\n# Executables\n*.exe\n*.out\n*.app\n\n\n.idea/*\n.vscode/*\nbuild/**\ncmake-build-*/**\nresources/**\nextlibs/squirrel/build/**\n\nThimbleweedPark.ggpack1\nThimbleweedPark.ggpack2\nlog.txt\nimgui.ini\n.DS_Store\n\nextlibs/ngf/**\n"
  },
  {
    "path": ".gitmodules",
    "content": "[submodule \"extlibs/ngf\"]\n\tpath = extlibs/ngf\n\turl = https://github.com/scemino/EnggeFramework\n"
  },
  {
    "path": "CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.5)\n\ninclude(appInfo.cmake)\n\nproject(\"${appName}\" LANGUAGES CXX)\n\n# Compiler flags\nset (SQ_DISABLE_INSTALLER ON)\nset (NGF_BUILD_DEMOS OFF)\nset (NGF_BUILD_EXAMPLES OFF)\nset (NGF_BUILD_TESTS OFF)\nset (NGF_BUILD_DOCUMENTATION OFF)\n\n# Sources\nadd_subdirectory(src)\nadd_subdirectory(extlibs/squirrel)\nadd_subdirectory(extlibs/ngf/)\n\n# Install misc. files\ninstall(FILES LICENSE DESTINATION .)\n\n# Copy dependencies\nif (\"${CMAKE_SYSTEM_NAME}\" STREQUAL \"Linux\")\nelseif (\"${CMAKE_SYSTEM_NAME}\" STREQUAL \"Windows\")\n\tinstall(FILES \"${VCPKG_BIN_DIR}/glew32.dll\" DESTINATION \"bin/\")\n\tinstall(FILES \"${VCPKG_BIN_DIR}/SDL2.dll\" DESTINATION \"bin/\")\nendif()\n\ntarget_compile_features(\"${appName}\" PRIVATE cxx_std_17)\nset_target_properties(\"${appName}\" PROPERTIES CXX_EXTENSIONS OFF)\n\nif (MSVC)\n    # TODO: warning level 4 and all warnings as errors\n    # target_compile_options(\"${appName}\" PRIVATE /W4 /WX)\nelse()\n    # lots of warnings and all warnings as errors\n    # TODO: treat warnings as errors: -Werror\n    # -pedantic-errors reports error library {fmt}\n    target_compile_options(\"${appName}\" PRIVATE -Wall -Wextra)\nendif()\n\n# Configure CPack\nfunction(get_short_system_name variable)\n\tif (\"${CMAKE_SYSTEM_NAME}\" STREQUAL \"Darwin\")\n\t\tset(${variable} \"OSX\" PARENT_SCOPE)\n\telseif(\"${CMAKE_SYSTEM_NAME}\" STREQUAL \"Windows\")\n\t\tset(${variable} \"Win64\" PARENT_SCOPE)\n\telse()\n\t\tset(${variable} \"${CMAKE_SYSTEM_NAME}\" PARENT_SCOPE)\n\tendif()\nendfunction()\n\nset(CPACK_PACKAGE_NAME ${appName})\nstring(REPLACE \" \" \"-\" CPACK_PACKAGE_NAME \"${CPACK_PACKAGE_NAME}\")\nget_short_system_name(CPACK_SYSTEM_NAME)\nset(CPACK_PACKAGE_VERSION_MAJOR ${appVersionMajor})\nset(CPACK_PACKAGE_VERSION_MINOR ${appVersionMinor})\nset(CPACK_PACKAGE_VERSION_PATCH ${appVersionPatch})\nset(CPACK_PACKAGE_VERSION ${appVersion})\nset(CPACK_PACKAGE_FILE_NAME \"${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-${CPACK_SYSTEM_NAME}\")\nstring(TOLOWER \"${CPACK_PACKAGE_FILE_NAME}\" CPACK_PACKAGE_FILE_NAME)\nset(CPACK_GENERATOR ZIP)\n\n# Run CPack\ninclude(CPack)\n\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as\ncontributors and maintainers pledge to making participation in our project and\nour community a harassment-free experience for everyone, regardless of age, body\nsize, disability, ethnicity, sex characteristics, gender identity and expression,\nlevel of experience, education, socio-economic status, nationality, personal\nappearance, race, religion, or sexual identity and orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment\ninclude:\n\n* Using welcoming and inclusive language\n* Being respectful of differing viewpoints and experiences\n* Gracefully accepting constructive criticism\n* Focusing on what is best for the community\n* Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n* The use of sexualized language or imagery and unwelcome sexual attention or\n advances\n* Trolling, insulting/derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or electronic\n address, without explicit permission\n* Other conduct which could reasonably be considered inappropriate in a\n professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable\nbehavior and are expected to take appropriate and fair corrective action in\nresponse to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or\nreject comments, commits, code, wiki edits, issues, and other contributions\nthat are not aligned to this Code of Conduct, or to ban temporarily or\npermanently any contributor for other behaviors that they deem inappropriate,\nthreatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces\nwhen an individual is representing the project or its community. Examples of\nrepresenting a project or community include using an official project e-mail\naddress, posting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event. Representation of a project may be\nfurther defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported by contacting the project team at scemino74@gmail.com. All\ncomplaints will be reviewed and investigated and will result in a response that\nis deemed necessary and appropriate to the circumstances. The project team is\nobligated to maintain confidentiality with regard to the reporter of an incident.\nFurther details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good\nfaith may face temporary or permanent repercussions as determined by other\nmembers of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,\navailable at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html\n\n[homepage]: https://www.contributor-covenant.org\n\nFor answers to common questions about this code of conduct, see\nhttps://www.contributor-covenant.org/faq\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing\n\nI really appreciate every contribution and suggestion, it can be code, documentation.\nBy the way, if anyone is interested to propose me a logo, don't hesitate to contact me.\nFeel free to ask questions as well.\n\n## Issues and suggestions\n\nIf you experience an issue or want to suggest a feature, [create an issue](https://github.com/scemino/engge/issues/new/choose)\nto let others know. If you want to fix the issue by yourself, open a pull request instead.\n\n## Contributing code\n\nTry to match the coding style that's already present. I will try to create a .clang-format file that respect the current coding style.\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2018 scemino\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE."
  },
  {
    "path": "README.MD",
    "content": "# engge\n\n[![Build](https://github.com/scemino/engge/workflows/Build/badge.svg)](https://github.com/scemino/engge/actions)\n[![CodeFactor](https://www.codefactor.io/repository/github/scemino/engge/badge)](https://www.codefactor.io/repository/github/scemino/engge)\n[![Twitter URL](https://img.shields.io/twitter/url?style=social&url=https%3A%2F%2Ftwitter.com%2Fengge_the_game)](https://twitter.com/engge_the_game)\n\n:warning: This project is not supported anymore, but no worries I created a new project [engge2](https://github.com/scemino/engge2) :warning:\n\nengge is an adventure game engine able to run Thimbleweed Park.\n\nIt's an open source remake of Thimbleweed Park's engine.\n\nThe game is playable. What does it mean? Yes, it means you can play the game and you should be able to finish it. No, it doesn't mean that you won't face any bug.\nIt's still a project in active development, and there are a lot of issues, don't hesitate to contribute or to fill out a [bug report](https://github.com/scemino/engge/issues/new/choose).\n\n\n[![https://i.imgur.com/En75Mzx.png](https://i.imgur.com/En75Mzx.png)](https://www.youtube.com/watch?v=09VEPoX5SZk&t=1s)\n\n## Download\n\nYou can download the prebuilt binaries for Window, Linux and macOS [here](https://github.com/scemino/engge/releases).\n\nLook at the assets 😉\n\n## Prerequisites\n\n* Buy [Thimbleweed park](https://thimbleweedpark.com)\n* Go to your installation folder and copy these files:  **ThimbleweedPark.ggpack1** and **ThimbleweedPark.ggpack2** to **engge** directory\n* **engge** has these following dependencies\n  * [ngf](https://github.com/scemino/EnggeFramework/): Engge Framework is a C++ framework based on **SDL2**.\n  * [squirrel](http://www.squirrel-lang.org/): programming language Squirrel, this repository contains a modified version of the official squirrel library in *extlibs/squirrel*\n  * [spdlog](https://github.com/gabime/spdlog): Fast C++ logging library.\n\n## Building\n\nHave a look to this [page](https://github.com/scemino/engge/wiki/Build-instructions).\n\n## Running\n\nJust type `./build/src/engge`, don't forget the prerequisites.\n\n---\n\n![CLion](https://github.com/JetBrains/logos/blob/master/web/clion/clion.svg)\n\n[JetBrains](https://www.jetbrains.com/) have been kind enough to supply me with a free Open Source license of [CLion](https://www.jetbrains.com/clion).\n"
  },
  {
    "path": "appInfo.cmake",
    "content": "set(appName \"engge\")\nset(appVersionMajor 0)\nset(appVersionMinor 8)\nset(appVersionPatch 0)\nset(appVersionSuffix \"beta\")\nset(appVersion \"${appVersionMajor}.${appVersionMinor}.${appVersionPatch}-${appVersionSuffix}\")\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/async.h",
    "content": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n#pragma once\n\n//\n// Async logging using global thread pool\n// All loggers created here share same global thread pool.\n// Each log message is pushed to a queue along withe a shared pointer to the\n// logger.\n// If a logger deleted while having pending messages in the queue, it's actual\n// destruction will defer\n// until all its messages are processed by the thread pool.\n// This is because each message in the queue holds a shared_ptr to the\n// originating logger.\n\n#include \"spdlog/async_logger.h\"\n#include \"spdlog/details/registry.h\"\n#include \"spdlog/details/thread_pool.h\"\n\n#include <memory>\n#include <mutex>\n#include <functional>\n\nnamespace spdlog {\n\nnamespace details {\nstatic const size_t default_async_q_size = 8192;\n}\n\n// async logger factory - creates async loggers backed with thread pool.\n// if a global thread pool doesn't already exist, create it with default queue\n// size of 8192 items and single thread.\ntemplate<async_overflow_policy OverflowPolicy = async_overflow_policy::block>\nstruct async_factory_impl\n{\n    template<typename Sink, typename... SinkArgs>\n    static std::shared_ptr<async_logger> create(std::string logger_name, SinkArgs &&... args)\n    {\n        auto &registry_inst = details::registry::instance();\n\n        // create global thread pool if not already exists..\n        std::lock_guard<std::recursive_mutex> tp_lock(registry_inst.tp_mutex());\n        auto tp = registry_inst.get_tp();\n        if (tp == nullptr)\n        {\n            tp = std::make_shared<details::thread_pool>(details::default_async_q_size, 1);\n            registry_inst.set_tp(tp);\n        }\n\n        auto sink = std::make_shared<Sink>(std::forward<SinkArgs>(args)...);\n        auto new_logger = std::make_shared<async_logger>(std::move(logger_name), std::move(sink), std::move(tp), OverflowPolicy);\n        registry_inst.initialize_logger(new_logger);\n        return new_logger;\n    }\n};\n\nusing async_factory = async_factory_impl<async_overflow_policy::block>;\nusing async_factory_nonblock = async_factory_impl<async_overflow_policy::overrun_oldest>;\n\ntemplate<typename Sink, typename... SinkArgs>\ninline std::shared_ptr<spdlog::logger> create_async(std::string logger_name, SinkArgs &&... sink_args)\n{\n    return async_factory::create<Sink>(std::move(logger_name), std::forward<SinkArgs>(sink_args)...);\n}\n\ntemplate<typename Sink, typename... SinkArgs>\ninline std::shared_ptr<spdlog::logger> create_async_nb(std::string logger_name, SinkArgs &&... sink_args)\n{\n    return async_factory_nonblock::create<Sink>(std::move(logger_name), std::forward<SinkArgs>(sink_args)...);\n}\n\n// set global thread pool.\ninline void init_thread_pool(size_t q_size, size_t thread_count, std::function<void()> on_thread_start)\n{\n    auto tp = std::make_shared<details::thread_pool>(q_size, thread_count, on_thread_start);\n    details::registry::instance().set_tp(std::move(tp));\n}\n\n// set global thread pool.\ninline void init_thread_pool(size_t q_size, size_t thread_count)\n{\n    init_thread_pool(q_size, thread_count, [] {});\n}\n\n// get the global thread pool.\ninline std::shared_ptr<spdlog::details::thread_pool> thread_pool()\n{\n    return details::registry::instance().get_tp();\n}\n} // namespace spdlog\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/async_logger-inl.h",
    "content": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n#pragma once\n\n#ifndef SPDLOG_HEADER_ONLY\n#include \"spdlog/async_logger.h\"\n#endif\n\n#include \"spdlog/sinks/sink.h\"\n#include \"spdlog/details/thread_pool.h\"\n\n#include <chrono>\n#include <memory>\n#include <string>\n\nSPDLOG_INLINE spdlog::async_logger::async_logger(\n    std::string logger_name, sinks_init_list sinks_list, std::weak_ptr<details::thread_pool> tp, async_overflow_policy overflow_policy)\n    : async_logger(std::move(logger_name), sinks_list.begin(), sinks_list.end(), std::move(tp), overflow_policy)\n{}\n\nSPDLOG_INLINE spdlog::async_logger::async_logger(\n    std::string logger_name, sink_ptr single_sink, std::weak_ptr<details::thread_pool> tp, async_overflow_policy overflow_policy)\n    : async_logger(std::move(logger_name), {std::move(single_sink)}, std::move(tp), overflow_policy)\n{}\n\n// send the log message to the thread pool\nSPDLOG_INLINE void spdlog::async_logger::sink_it_(details::log_msg &msg)\n{\n    if (auto pool_ptr = thread_pool_.lock())\n    {\n        pool_ptr->post_log(shared_from_this(), msg, overflow_policy_);\n    }\n    else\n    {\n        throw spdlog_ex(\"async log: thread pool doesn't exist anymore\");\n    }\n}\n\n// send flush request to the thread pool\nSPDLOG_INLINE void spdlog::async_logger::flush_()\n{\n    if (auto pool_ptr = thread_pool_.lock())\n    {\n        pool_ptr->post_flush(shared_from_this(), overflow_policy_);\n    }\n    else\n    {\n        throw spdlog_ex(\"async flush: thread pool doesn't exist anymore\");\n    }\n}\n\n//\n// backend functions - called from the thread pool to do the actual job\n//\nSPDLOG_INLINE void spdlog::async_logger::backend_log_(const details::log_msg &incoming_log_msg)\n{\n    try\n    {\n        for (auto &s : sinks_)\n        {\n            if (s->should_log(incoming_log_msg.level))\n            {\n                s->log(incoming_log_msg);\n            }\n        }\n    }\n    SPDLOG_LOGGER_CATCH()\n\n    if (should_flush_(incoming_log_msg))\n    {\n        backend_flush_();\n    }\n}\n\nSPDLOG_INLINE void spdlog::async_logger::backend_flush_()\n{\n    try\n    {\n        for (auto &sink : sinks_)\n        {\n            sink->flush();\n        }\n    }\n    SPDLOG_LOGGER_CATCH()\n}\n\nSPDLOG_INLINE std::shared_ptr<spdlog::logger> spdlog::async_logger::clone(std::string new_name)\n{\n    auto cloned = std::make_shared<spdlog::async_logger>(std::move(new_name), sinks_.begin(), sinks_.end(), thread_pool_, overflow_policy_);\n\n    cloned->set_level(this->level());\n    cloned->flush_on(this->flush_level());\n    cloned->set_error_handler(this->custom_err_handler_);\n    return cloned;\n}\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/async_logger.h",
    "content": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n#pragma once\n\n// Fast asynchronous logger.\n// Uses pre allocated queue.\n// Creates a single back thread to pop messages from the queue and log them.\n//\n// Upon each log write the logger:\n//    1. Checks if its log level is enough to log the message\n//    2. Push a new copy of the message to a queue (or block the caller until\n//    space is available in the queue)\n// Upon destruction, logs all remaining messages in the queue before\n// destructing..\n\n#include \"spdlog/logger.h\"\n\nnamespace spdlog {\n\n// Async overflow policy - block by default.\nenum class async_overflow_policy\n{\n    block,         // Block until message can be enqueued\n    overrun_oldest // Discard oldest message in the queue if full when trying to\n                   // add new item.\n};\n\nnamespace details {\nclass thread_pool;\n}\n\nclass async_logger final : public std::enable_shared_from_this<async_logger>, public logger\n{\n    friend class details::thread_pool;\n\npublic:\n    template<typename It>\n    async_logger(std::string logger_name, It begin, It end, std::weak_ptr<details::thread_pool> tp,\n        async_overflow_policy overflow_policy = async_overflow_policy::block)\n        : logger(std::move(logger_name), begin, end)\n        , thread_pool_(std::move(tp))\n        , overflow_policy_(overflow_policy)\n    {}\n\n    async_logger(std::string logger_name, sinks_init_list sinks_list, std::weak_ptr<details::thread_pool> tp,\n        async_overflow_policy overflow_policy = async_overflow_policy::block);\n\n    async_logger(std::string logger_name, sink_ptr single_sink, std::weak_ptr<details::thread_pool> tp,\n        async_overflow_policy overflow_policy = async_overflow_policy::block);\n\n    std::shared_ptr<logger> clone(std::string new_name) override;\n\nprotected:\n    void sink_it_(details::log_msg &msg) override;\n    void flush_() override;\n\n    void backend_log_(const details::log_msg &incoming_log_msg);\n    void backend_flush_();\n\nprivate:\n    std::weak_ptr<details::thread_pool> thread_pool_;\n    async_overflow_policy overflow_policy_;\n};\n} // namespace spdlog\n\n#ifdef SPDLOG_HEADER_ONLY\n#include \"async_logger-inl.h\"\n#endif\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/common-inl.h",
    "content": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n#pragma once\n\n#ifndef SPDLOG_HEADER_ONLY\n#include \"spdlog/common.h\"\n#endif\n\nnamespace spdlog {\nnamespace level {\nstatic string_view_t level_string_views[] SPDLOG_LEVEL_NAMES;\n\nstatic const char *short_level_names[] SPDLOG_SHORT_LEVEL_NAMES;\n\nSPDLOG_INLINE string_view_t &to_string_view(spdlog::level::level_enum l) SPDLOG_NOEXCEPT\n{\n    return level_string_views[l];\n}\n\nSPDLOG_INLINE const char *to_short_c_str(spdlog::level::level_enum l) SPDLOG_NOEXCEPT\n{\n    return short_level_names[l];\n}\n\nSPDLOG_INLINE spdlog::level::level_enum from_str(const std::string &name) SPDLOG_NOEXCEPT\n{\n    int level = 0;\n    for (const auto &level_str : level_string_views)\n    {\n        if (level_str == name)\n        {\n            return static_cast<level::level_enum>(level);\n        }\n        level++;\n    }\n    return level::off;\n}\n} // namespace level\n\nSPDLOG_INLINE spdlog_ex::spdlog_ex(std::string msg)\n    : msg_(std::move(msg))\n{}\n\nSPDLOG_INLINE spdlog_ex::spdlog_ex(const std::string &msg, int last_errno)\n{\n    fmt::memory_buffer outbuf;\n    fmt::format_system_error(outbuf, last_errno, msg);\n    msg_ = fmt::to_string(outbuf);\n}\n\nSPDLOG_INLINE const char *spdlog_ex::what() const SPDLOG_NOEXCEPT\n{\n    return msg_.c_str();\n}\n\n} // namespace spdlog\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/common.h",
    "content": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n#pragma once\n\n#include \"spdlog/tweakme.h\"\n\n#include <atomic>\n#include <chrono>\n#include <initializer_list>\n#include <memory>\n#include <exception>\n#include <string>\n#include <type_traits>\n#include <functional>\n\n#ifdef _WIN32\n#ifndef NOMINMAX\n#define NOMINMAX // prevent windows redefining min/max\n#endif\n\n#ifndef WIN32_LEAN_AND_MEAN\n#define WIN32_LEAN_AND_MEAN\n#endif\n\n#include <windows.h>\n#endif //_WIN32\n\n#ifdef SPDLOG_COMPILED_LIB\n#undef SPDLOG_HEADER_ONLY\n#define SPDLOG_INLINE\n#else\n#define SPDLOG_HEADER_ONLY\n#define SPDLOG_INLINE inline\n#endif\n\n#include \"spdlog/fmt/fmt.h\"\n\n// visual studio upto 2013 does not support noexcept nor constexpr\n#if defined(_MSC_VER) && (_MSC_VER < 1900)\n#define SPDLOG_NOEXCEPT throw()\n#define SPDLOG_CONSTEXPR\n#else\n#define SPDLOG_NOEXCEPT noexcept\n#define SPDLOG_CONSTEXPR constexpr\n#endif\n\n#if defined(__GNUC__) || defined(__clang__)\n#define SPDLOG_DEPRECATED __attribute__((deprecated))\n#elif defined(_MSC_VER)\n#define SPDLOG_DEPRECATED __declspec(deprecated)\n#else\n#define SPDLOG_DEPRECATED\n#endif\n\n// disable thread local on msvc 2013\n#ifndef SPDLOG_NO_TLS\n#if (defined(_MSC_VER) && (_MSC_VER < 1900)) || defined(__cplusplus_winrt)\n#define SPDLOG_NO_TLS 1\n#endif\n#endif\n\n#ifndef SPDLOG_FUNCTION\n#define SPDLOG_FUNCTION __FUNCTION__\n#endif\n\nnamespace spdlog {\n\nclass formatter;\n\nnamespace sinks {\nclass sink;\n}\n\n#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)\nusing filename_t = std::wstring;\n#define SPDLOG_FILENAME_T(s) L##s\n#else\nusing filename_t = std::string;\n#define SPDLOG_FILENAME_T(s) s\n#endif\n\nusing log_clock = std::chrono::system_clock;\nusing sink_ptr = std::shared_ptr<sinks::sink>;\nusing sinks_init_list = std::initializer_list<sink_ptr>;\nusing err_handler = std::function<void(const std::string &err_msg)>;\n\ntemplate<typename T>\nusing basic_string_view_t = fmt::basic_string_view<T>;\n\nusing string_view_t = basic_string_view_t<char>;\n\n#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT\n#ifndef _WIN32\n#error SPDLOG_WCHAR_TO_UTF8_SUPPORT only supported on windows\n#else\nusing wstring_view_t = basic_string_view_t<wchar_t>;\n\ntemplate<typename T>\nstruct is_convertible_to_wstring_view : std::is_convertible<T, wstring_view_t> { };\n#endif // _WIN32\n#else\ntemplate<typename>\nstruct is_convertible_to_wstring_view : std::false_type { };\n#endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT\n\n#if defined(SPDLOG_NO_ATOMIC_LEVELS)\nusing level_t = details::null_atomic_int;\n#else\nusing level_t = std::atomic<int>;\n#endif\n\n#define SPDLOG_LEVEL_TRACE 0\n#define SPDLOG_LEVEL_DEBUG 1\n#define SPDLOG_LEVEL_INFO 2\n#define SPDLOG_LEVEL_WARN 3\n#define SPDLOG_LEVEL_ERROR 4\n#define SPDLOG_LEVEL_CRITICAL 5\n#define SPDLOG_LEVEL_OFF 6\n\n#if !defined(SPDLOG_ACTIVE_LEVEL)\n#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_INFO\n#endif\n\n// Log level enum\nnamespace level {\nenum level_enum\n{\n    trace = SPDLOG_LEVEL_TRACE,\n    debug = SPDLOG_LEVEL_DEBUG,\n    info = SPDLOG_LEVEL_INFO,\n    warn = SPDLOG_LEVEL_WARN,\n    err = SPDLOG_LEVEL_ERROR,\n    critical = SPDLOG_LEVEL_CRITICAL,\n    off = SPDLOG_LEVEL_OFF,\n};\n\n#if !defined(SPDLOG_LEVEL_NAMES)\n#define SPDLOG_LEVEL_NAMES                                                                                                                 \\\n    {                                                                                                                                      \\\n        \"trace\", \"debug\", \"info\", \"warning\", \"error\", \"critical\", \"off\"                                                                    \\\n    }\n#endif\n\n#if !defined(SPDLOG_SHORT_LEVEL_NAMES)\n\n#define SPDLOG_SHORT_LEVEL_NAMES                                                                                                           \\\n    {                                                                                                                                      \\\n        \"T\", \"D\", \"I\", \"W\", \"E\", \"C\", \"O\"                                                                                                  \\\n    }\n#endif\n\nstring_view_t &to_string_view(spdlog::level::level_enum l) SPDLOG_NOEXCEPT;\nconst char *to_short_c_str(spdlog::level::level_enum l) SPDLOG_NOEXCEPT;\nspdlog::level::level_enum from_str(const std::string &name) SPDLOG_NOEXCEPT;\n\nusing level_hasher = std::hash<int>;\n} // namespace level\n\n//\n// Color mode used by sinks with color support.\n//\nenum class color_mode\n{\n    always,\n    automatic,\n    never\n};\n\n//\n// Pattern time - specific time getting to use for pattern_formatter.\n// local time by default\n//\nenum class pattern_time_type\n{\n    local, // log localtime\n    utc    // log utc\n};\n\n//\n// Log exception\n//\nclass spdlog_ex : public std::exception\n{\npublic:\n    explicit spdlog_ex(std::string msg);\n    spdlog_ex(const std::string &msg, int last_errno);\n    const char *what() const SPDLOG_NOEXCEPT override;\n\nprivate:\n    std::string msg_;\n};\n\nstruct source_loc\n{\n    SPDLOG_CONSTEXPR source_loc() = default;\n    SPDLOG_CONSTEXPR source_loc(const char *filename_in, int line_in, const char *funcname_in)\n        : filename{filename_in}\n        , line{line_in}\n        , funcname{funcname_in}\n    {}\n\n    SPDLOG_CONSTEXPR bool empty() const SPDLOG_NOEXCEPT\n    {\n        return line == 0;\n    }\n    const char *filename{nullptr};\n    int line{0};\n    const char *funcname{nullptr};\n};\n\nnamespace details {\n// make_unique support for pre c++14\n\n#if __cplusplus >= 201402L // C++14 and beyond\nusing std::make_unique;\n#else\ntemplate<typename T, typename... Args>\nstd::unique_ptr<T> make_unique(Args &&... args)\n{\n    static_assert(!std::is_array<T>::value, \"arrays not supported\");\n    return std::unique_ptr<T>(new T(std::forward<Args>(args)...));\n}\n#endif\n} // namespace details\n\n} // namespace spdlog\n\n#ifdef SPDLOG_HEADER_ONLY\n#include \"common-inl.h\"\n#endif\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/details/circular_q.h",
    "content": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n// cirucal q view of std::vector.\n#pragma once\n\n#include <vector>\n\nnamespace spdlog {\nnamespace details {\ntemplate<typename T>\nclass circular_q\n{\npublic:\n    using item_type = T;\n\n    explicit circular_q(size_t max_items)\n        : max_items_(max_items + 1) // one item is reserved as marker for full q\n        , v_(max_items_)\n    {}\n\n    // push back, overrun (oldest) item if no room left\n    void push_back(T &&item)\n    {\n        v_[tail_] = std::move(item);\n        tail_ = (tail_ + 1) % max_items_;\n\n        if (tail_ == head_) // overrun last item if full\n        {\n            head_ = (head_ + 1) % max_items_;\n            ++overrun_counter_;\n        }\n    }\n\n    // Pop item from front.\n    // If there are no elements in the container, the behavior is undefined.\n    void pop_front(T &popped_item)\n    {\n        popped_item = std::move(v_[head_]);\n        head_ = (head_ + 1) % max_items_;\n    }\n\n    bool empty()\n    {\n        return tail_ == head_;\n    }\n\n    bool full()\n    {\n        // head is ahead of the tail by 1\n        return ((tail_ + 1) % max_items_) == head_;\n    }\n\n    size_t overrun_counter() const\n    {\n        return overrun_counter_;\n    }\n\nprivate:\n    size_t max_items_;\n    typename std::vector<T>::size_type head_ = 0;\n    typename std::vector<T>::size_type tail_ = 0;\n\n    std::vector<T> v_;\n\n    size_t overrun_counter_ = 0;\n};\n} // namespace details\n} // namespace spdlog\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/details/console_globals.h",
    "content": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n#pragma once\n\n#include \"spdlog/details/null_mutex.h\"\n#include <mutex>\n\nnamespace spdlog {\nnamespace details {\n\nstruct console_mutex\n{\n    using mutex_t = std::mutex;\n    static mutex_t &mutex()\n    {\n        static mutex_t s_mutex;\n        return s_mutex;\n    }\n};\n\nstruct console_nullmutex\n{\n    using mutex_t = null_mutex;\n    static mutex_t &mutex()\n    {\n        static mutex_t s_mutex;\n        return s_mutex;\n    }\n};\n} // namespace details\n} // namespace spdlog\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/details/file_helper-inl.h",
    "content": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n#pragma once\n\n#ifndef SPDLOG_HEADER_ONLY\n#include \"spdlog/details/file_helper.h\"\n#endif\n\n#include \"spdlog/details/os.h\"\n\n#include <cerrno>\n#include <chrono>\n#include <cstdio>\n#include <string>\n#include <thread>\n#include <tuple>\n\nnamespace spdlog {\nnamespace details {\n\nSPDLOG_INLINE file_helper::~file_helper()\n{\n    close();\n}\n\nSPDLOG_INLINE void file_helper::open(const filename_t &fname, bool truncate)\n{\n    close();\n    auto *mode = truncate ? SPDLOG_FILENAME_T(\"wb\") : SPDLOG_FILENAME_T(\"ab\");\n    _filename = fname;\n    for (int tries = 0; tries < open_tries; ++tries)\n    {\n        if (!os::fopen_s(&fd_, fname, mode))\n        {\n            return;\n        }\n\n        details::os::sleep_for_millis(open_interval);\n    }\n\n    throw spdlog_ex(\"Failed opening file \" + os::filename_to_str(_filename) + \" for writing\", errno);\n}\n\nSPDLOG_INLINE void file_helper::reopen(bool truncate)\n{\n    if (_filename.empty())\n    {\n        throw spdlog_ex(\"Failed re opening file - was not opened before\");\n    }\n    open(_filename, truncate);\n}\n\nSPDLOG_INLINE void file_helper::flush()\n{\n    std::fflush(fd_);\n}\n\nSPDLOG_INLINE void file_helper::close()\n{\n    if (fd_ != nullptr)\n    {\n        std::fclose(fd_);\n        fd_ = nullptr;\n    }\n}\n\nSPDLOG_INLINE void file_helper::write(const fmt::memory_buffer &buf)\n{\n    size_t msg_size = buf.size();\n    auto data = buf.data();\n    if (std::fwrite(data, 1, msg_size, fd_) != msg_size)\n    {\n        throw spdlog_ex(\"Failed writing to file \" + os::filename_to_str(_filename), errno);\n    }\n}\n\nSPDLOG_INLINE size_t file_helper::size() const\n{\n    if (fd_ == nullptr)\n    {\n        throw spdlog_ex(\"Cannot use size() on closed file \" + os::filename_to_str(_filename));\n    }\n    return os::filesize(fd_);\n}\n\nSPDLOG_INLINE const filename_t &file_helper::filename() const\n{\n    return _filename;\n}\n\nSPDLOG_INLINE bool file_helper::file_exists(const filename_t &fname)\n{\n    return os::file_exists(fname);\n}\n\n//\n// return file path and its extension:\n//\n// \"mylog.txt\" => (\"mylog\", \".txt\")\n// \"mylog\" => (\"mylog\", \"\")\n// \"mylog.\" => (\"mylog.\", \"\")\n// \"/dir1/dir2/mylog.txt\" => (\"/dir1/dir2/mylog\", \".txt\")\n//\n// the starting dot in filenames is ignored (hidden files):\n//\n// \".mylog\" => (\".mylog\". \"\")\n// \"my_folder/.mylog\" => (\"my_folder/.mylog\", \"\")\n// \"my_folder/.mylog.txt\" => (\"my_folder/.mylog\", \".txt\")\nSPDLOG_INLINE std::tuple<filename_t, filename_t> file_helper::split_by_extension(const filename_t &fname)\n{\n    auto ext_index = fname.rfind('.');\n\n    // no valid extension found - return whole path and empty string as\n    // extension\n    if (ext_index == filename_t::npos || ext_index == 0 || ext_index == fname.size() - 1)\n    {\n        return std::make_tuple(fname, filename_t());\n    }\n\n    // treat casese like \"/etc/rc.d/somelogfile or \"/abc/.hiddenfile\"\n    auto folder_index = fname.rfind(details::os::folder_sep);\n    if (folder_index != filename_t::npos && folder_index >= ext_index - 1)\n    {\n        return std::make_tuple(fname, filename_t());\n    }\n\n    // finally - return a valid base and extension tuple\n    return std::make_tuple(fname.substr(0, ext_index), fname.substr(ext_index));\n}\n} // namespace details\n} // namespace spdlog\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/details/file_helper.h",
    "content": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n#pragma once\n\n#include \"spdlog/common.h\"\n#include <tuple>\n\nnamespace spdlog {\nnamespace details {\n\n// Helper class for file sinks.\n// When failing to open a file, retry several times(5) with a delay interval(10 ms).\n// Throw spdlog_ex exception on errors.\n\nclass file_helper\n{\npublic:\n    explicit file_helper() = default;\n\n    file_helper(const file_helper &) = delete;\n    file_helper &operator=(const file_helper &) = delete;\n    ~file_helper();\n\n    void open(const filename_t &fname, bool truncate = false);\n    void reopen(bool truncate);\n    void flush();\n    void close();\n    void write(const fmt::memory_buffer &buf);\n    size_t size() const;\n    const filename_t &filename() const;\n    static bool file_exists(const filename_t &fname);\n\n    //\n    // return file path and its extension:\n    //\n    // \"mylog.txt\" => (\"mylog\", \".txt\")\n    // \"mylog\" => (\"mylog\", \"\")\n    // \"mylog.\" => (\"mylog.\", \"\")\n    // \"/dir1/dir2/mylog.txt\" => (\"/dir1/dir2/mylog\", \".txt\")\n    //\n    // the starting dot in filenames is ignored (hidden files):\n    //\n    // \".mylog\" => (\".mylog\". \"\")\n    // \"my_folder/.mylog\" => (\"my_folder/.mylog\", \"\")\n    // \"my_folder/.mylog.txt\" => (\"my_folder/.mylog\", \".txt\")\n    static std::tuple<filename_t, filename_t> split_by_extension(const filename_t &fname);\n\nprivate:\n    const int open_tries = 5;\n    const int open_interval = 10;\n    std::FILE *fd_{nullptr};\n    filename_t _filename;\n};\n} // namespace details\n} // namespace spdlog\n\n#ifdef SPDLOG_HEADER_ONLY\n#include \"file_helper-inl.h\"\n#endif\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/details/fmt_helper.h",
    "content": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n#pragma once\n\n#include <chrono>\n#include <type_traits>\n#include \"spdlog/fmt/fmt.h\"\n#include \"spdlog/common.h\"\n\n// Some fmt helpers to efficiently format and pad ints and strings\nnamespace spdlog {\nnamespace details {\nnamespace fmt_helper {\n\ntemplate<size_t Buffer_Size>\ninline spdlog::string_view_t to_string_view(const fmt::basic_memory_buffer<char, Buffer_Size> &buf) SPDLOG_NOEXCEPT\n{\n    return spdlog::string_view_t(buf.data(), buf.size());\n}\n\ntemplate<size_t Buffer_Size1, size_t Buffer_Size2>\ninline void append_buf(const fmt::basic_memory_buffer<char, Buffer_Size1> &buf, fmt::basic_memory_buffer<char, Buffer_Size2> &dest)\n{\n    auto *buf_ptr = buf.data();\n    dest.append(buf_ptr, buf_ptr + buf.size());\n}\n\ntemplate<size_t Buffer_Size>\ninline void append_string_view(spdlog::string_view_t view, fmt::basic_memory_buffer<char, Buffer_Size> &dest)\n{\n    auto *buf_ptr = view.data();\n    if (buf_ptr != nullptr)\n    {\n        dest.append(buf_ptr, buf_ptr + view.size());\n    }\n}\n\ntemplate<typename T, size_t Buffer_Size>\ninline void append_int(T n, fmt::basic_memory_buffer<char, Buffer_Size> &dest)\n{\n    fmt::format_int i(n);\n    dest.append(i.data(), i.data() + i.size());\n}\n\ntemplate<typename T>\ninline unsigned count_digits(T n)\n{\n    using count_type = typename std::conditional<(sizeof(T) > sizeof(uint32_t)), uint64_t, uint32_t>::type;\n    return static_cast<unsigned>(fmt::internal::count_digits(static_cast<count_type>(n)));\n}\n\ntemplate<size_t Buffer_Size>\ninline void pad2(int n, fmt::basic_memory_buffer<char, Buffer_Size> &dest)\n{\n    if (n > 99)\n    {\n        append_int(n, dest);\n    }\n    else if (n > 9) // 10-99\n    {\n        dest.push_back(static_cast<char>('0' + n / 10));\n        dest.push_back(static_cast<char>('0' + n % 10));\n    }\n    else if (n >= 0) // 0-9\n    {\n        dest.push_back('0');\n        dest.push_back(static_cast<char>('0' + n));\n    }\n    else // negatives (unlikely, but just in case, let fmt deal with it)\n    {\n        fmt::format_to(dest, \"{:02}\", n);\n    }\n}\n\ntemplate<typename T, size_t Buffer_Size>\ninline void pad_uint(T n, unsigned int width, fmt::basic_memory_buffer<char, Buffer_Size> &dest)\n{\n    static_assert(std::is_unsigned<T>::value, \"pad_uint must get unsigned T\");\n    auto digits = count_digits(n);\n    if (width > digits)\n    {\n        const char *zeroes = \"0000000000000000000\";\n        dest.append(zeroes, zeroes + width - digits);\n    }\n    append_int(n, dest);\n}\n\ntemplate<typename T, size_t Buffer_Size>\ninline void pad3(T n, fmt::basic_memory_buffer<char, Buffer_Size> &dest)\n{\n    pad_uint(n, 3, dest);\n}\n\ntemplate<typename T, size_t Buffer_Size>\ninline void pad6(T n, fmt::basic_memory_buffer<char, Buffer_Size> &dest)\n{\n    pad_uint(n, 6, dest);\n}\n\ntemplate<typename T, size_t Buffer_Size>\ninline void pad9(T n, fmt::basic_memory_buffer<char, Buffer_Size> &dest)\n{\n    pad_uint(n, 9, dest);\n}\n\n// return fraction of a second of the given time_point.\n// e.g.\n// fraction<std::milliseconds>(tp) -> will return the millis part of the second\ntemplate<typename ToDuration>\ninline ToDuration time_fraction(log_clock::time_point tp)\n{\n    using std::chrono::duration_cast;\n    using std::chrono::seconds;\n    auto duration = tp.time_since_epoch();\n    auto secs = duration_cast<seconds>(duration);\n    return duration_cast<ToDuration>(duration) - duration_cast<ToDuration>(secs);\n}\n\n} // namespace fmt_helper\n} // namespace details\n} // namespace spdlog\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/details/log_msg-inl.h",
    "content": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n#pragma once\n\n#ifndef SPDLOG_HEADER_ONLY\n#include \"spdlog/details/log_msg.h\"\n#endif\n\n#include \"spdlog/details/os.h\"\n\nnamespace spdlog {\nnamespace details {\n\nSPDLOG_INLINE log_msg::log_msg(spdlog::source_loc loc, string_view_t logger_name, spdlog::level::level_enum lvl, spdlog::string_view_t msg)\n    : logger_name(logger_name)\n    , level(lvl)\n#ifndef SPDLOG_NO_DATETIME\n    , time(os::now())\n#endif\n\n#ifndef SPDLOG_NO_THREAD_ID\n    , thread_id(os::thread_id())\n#endif\n    , source(loc)\n    , payload(msg)\n{}\n\nSPDLOG_INLINE log_msg::log_msg(string_view_t logger_name, spdlog::level::level_enum lvl, spdlog::string_view_t msg)\n    : log_msg(source_loc{}, logger_name, lvl, msg)\n{}\n\n} // namespace details\n} // namespace spdlog\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/details/log_msg.h",
    "content": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n#pragma once\n\n#include \"spdlog/common.h\"\n#include <string>\n\nnamespace spdlog {\nnamespace details {\nstruct log_msg\n{\n    log_msg(source_loc loc, string_view_t logger_name, level::level_enum lvl, string_view_t msg);\n    log_msg(string_view_t logger_name, level::level_enum lvl, string_view_t msg);\n    log_msg(const log_msg &other) = default;\n\n    const string_view_t logger_name;\n    level::level_enum level{level::off};\n    log_clock::time_point time;\n    size_t thread_id{0};\n\n    // wrapping the formatted text with color (updated by pattern_formatter).\n    mutable size_t color_range_start{0};\n    mutable size_t color_range_end{0};\n\n    source_loc source;\n    const string_view_t payload;\n};\n} // namespace details\n} // namespace spdlog\n\n#ifdef SPDLOG_HEADER_ONLY\n#include \"log_msg-inl.h\"\n#endif\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/details/mpmc_blocking_q.h",
    "content": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n#pragma once\n\n// multi producer-multi consumer blocking queue.\n// enqueue(..) - will block until room found to put the new message.\n// enqueue_nowait(..) - will return immediately with false if no room left in\n// the queue.\n// dequeue_for(..) - will block until the queue is not empty or timeout have\n// passed.\n\n#include \"spdlog/details/circular_q.h\"\n\n#include <condition_variable>\n#include <mutex>\n\nnamespace spdlog {\nnamespace details {\n\ntemplate<typename T>\nclass mpmc_blocking_queue\n{\npublic:\n    using item_type = T;\n    explicit mpmc_blocking_queue(size_t max_items)\n        : q_(max_items)\n    {}\n\n#ifndef __MINGW32__\n    // try to enqueue and block if no room left\n    void enqueue(T &&item)\n    {\n        {\n            std::unique_lock<std::mutex> lock(queue_mutex_);\n            pop_cv_.wait(lock, [this] { return !this->q_.full(); });\n            q_.push_back(std::move(item));\n        }\n        push_cv_.notify_one();\n    }\n\n    // enqueue immediately. overrun oldest message in the queue if no room left.\n    void enqueue_nowait(T &&item)\n    {\n        {\n            std::unique_lock<std::mutex> lock(queue_mutex_);\n            q_.push_back(std::move(item));\n        }\n        push_cv_.notify_one();\n    }\n\n    // try to dequeue item. if no item found. wait upto timeout and try again\n    // Return true, if succeeded dequeue item, false otherwise\n    bool dequeue_for(T &popped_item, std::chrono::milliseconds wait_duration)\n    {\n        {\n            std::unique_lock<std::mutex> lock(queue_mutex_);\n            if (!push_cv_.wait_for(lock, wait_duration, [this] { return !this->q_.empty(); }))\n            {\n                return false;\n            }\n            q_.pop_front(popped_item);\n        }\n        pop_cv_.notify_one();\n        return true;\n    }\n\n#else\n    // apparently mingw deadlocks if the mutex is released before cv.notify_one(),\n    // so release the mutex at the very end each function.\n\n    // try to enqueue and block if no room left\n    void enqueue(T &&item)\n    {\n        std::unique_lock<std::mutex> lock(queue_mutex_);\n        pop_cv_.wait(lock, [this] { return !this->q_.full(); });\n        q_.push_back(std::move(item));\n        push_cv_.notify_one();\n    }\n\n    // enqueue immediately. overrun oldest message in the queue if no room left.\n    void enqueue_nowait(T &&item)\n    {\n        std::unique_lock<std::mutex> lock(queue_mutex_);\n        q_.push_back(std::move(item));\n        push_cv_.notify_one();\n    }\n\n    // try to dequeue item. if no item found. wait upto timeout and try again\n    // Return true, if succeeded dequeue item, false otherwise\n    bool dequeue_for(T &popped_item, std::chrono::milliseconds wait_duration)\n    {\n        std::unique_lock<std::mutex> lock(queue_mutex_);\n        if (!push_cv_.wait_for(lock, wait_duration, [this] { return !this->q_.empty(); }))\n        {\n            return false;\n        }\n        q_.pop_front(popped_item);\n        pop_cv_.notify_one();\n        return true;\n    }\n\n#endif\n\n    size_t overrun_counter()\n    {\n        std::unique_lock<std::mutex> lock(queue_mutex_);\n        return q_.overrun_counter();\n    }\n\nprivate:\n    std::mutex queue_mutex_;\n    std::condition_variable push_cv_;\n    std::condition_variable pop_cv_;\n    spdlog::details::circular_q<T> q_;\n};\n} // namespace details\n} // namespace spdlog\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/details/null_mutex.h",
    "content": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n#pragma once\n\n#include <atomic>\n// null, no cost dummy \"mutex\" and dummy \"atomic\" int\n\nnamespace spdlog {\nnamespace details {\nstruct null_mutex\n{\n    void lock() {}\n    void unlock() {}\n    bool try_lock()\n    {\n        return true;\n    }\n};\n\nstruct null_atomic_int\n{\n    int value;\n    null_atomic_int() = default;\n\n    explicit null_atomic_int(int val)\n        : value(val)\n    {}\n\n    int load(std::memory_order) const\n    {\n        return value;\n    }\n\n    void store(int val)\n    {\n        value = val;\n    }\n};\n\n} // namespace details\n} // namespace spdlog\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/details/os-inl.h",
    "content": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n#pragma once\n\n#ifndef SPDLOG_HEADER_ONLY\n#include \"spdlog/details/os.h\"\n#endif\n\n#include <algorithm>\n#include <chrono>\n#include <cstdio>\n#include <cstdlib>\n#include <cstring>\n#include <ctime>\n#include <string>\n#include <thread>\n#include <array>\n#include <sys/stat.h>\n#include <sys/types.h>\n\n#ifdef _WIN32\n\n#ifndef NOMINMAX\n#define NOMINMAX // prevent windows redefining min/max\n#endif\n\n#ifndef WIN32_LEAN_AND_MEAN\n#define WIN32_LEAN_AND_MEAN\n#endif\n#include <io.h>      // _get_osfhandle and _isatty support\n#include <process.h> //  _get_pid support\n#include <windows.h>\n\n#ifdef __MINGW32__\n#include <share.h>\n#endif\n\n#if defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)\n#include <limits>\n#endif\n\n#else // unix\n\n#include <fcntl.h>\n#include <unistd.h>\n\n#ifdef __linux__\n#include <sys/syscall.h> //Use gettid() syscall under linux to get thread id\n\n#elif __FreeBSD__\n#include <sys/thr.h> //Use thr_self() syscall under FreeBSD to get thread id\n#endif\n\n#endif // unix\n\n#ifndef __has_feature      // Clang - feature checking macros.\n#define __has_feature(x) 0 // Compatibility with non-clang compilers.\n#endif\n\nnamespace spdlog {\nnamespace details {\nnamespace os {\n\nSPDLOG_INLINE spdlog::log_clock::time_point now() SPDLOG_NOEXCEPT\n{\n\n#if defined __linux__ && defined SPDLOG_CLOCK_COARSE\n    timespec ts;\n    ::clock_gettime(CLOCK_REALTIME_COARSE, &ts);\n    return std::chrono::time_point<log_clock, typename log_clock::duration>(\n        std::chrono::duration_cast<typename log_clock::duration>(std::chrono::seconds(ts.tv_sec) + std::chrono::nanoseconds(ts.tv_nsec)));\n\n#else\n    return log_clock::now();\n#endif\n}\nSPDLOG_INLINE std::tm localtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT\n{\n\n#ifdef _WIN32\n    std::tm tm;\n    localtime_s(&tm, &time_tt);\n#else\n    std::tm tm;\n    localtime_r(&time_tt, &tm);\n#endif\n    return tm;\n}\n\nSPDLOG_INLINE std::tm localtime() SPDLOG_NOEXCEPT\n{\n    std::time_t now_t = time(nullptr);\n    return localtime(now_t);\n}\n\nSPDLOG_INLINE std::tm gmtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT\n{\n\n#ifdef _WIN32\n    std::tm tm;\n    gmtime_s(&tm, &time_tt);\n#else\n    std::tm tm;\n    gmtime_r(&time_tt, &tm);\n#endif\n    return tm;\n}\n\nSPDLOG_INLINE std::tm gmtime() SPDLOG_NOEXCEPT\n{\n    std::time_t now_t = time(nullptr);\n    return gmtime(now_t);\n}\n\nSPDLOG_INLINE void prevent_child_fd(FILE *f)\n{\n\n#ifdef _WIN32\n#if !defined(__cplusplus_winrt)\n    auto file_handle = reinterpret_cast<HANDLE>(_get_osfhandle(_fileno(f)));\n    if (!::SetHandleInformation(file_handle, HANDLE_FLAG_INHERIT, 0))\n        throw spdlog_ex(\"SetHandleInformation failed\", errno);\n#endif\n#else\n    auto fd = fileno(f);\n    if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)\n    {\n        throw spdlog_ex(\"fcntl with FD_CLOEXEC failed\", errno);\n    }\n#endif\n}\n\n// fopen_s on non windows for writing\nSPDLOG_INLINE bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode)\n{\n#ifdef _WIN32\n#ifdef SPDLOG_WCHAR_FILENAMES\n    *fp = _wfsopen((filename.c_str()), mode.c_str(), _SH_DENYNO);\n#else\n    *fp = _fsopen((filename.c_str()), mode.c_str(), _SH_DENYNO);\n#endif\n#else // unix\n    *fp = fopen((filename.c_str()), mode.c_str());\n#endif\n\n#ifdef SPDLOG_PREVENT_CHILD_FD\n    if (*fp != nullptr)\n    {\n        prevent_child_fd(*fp);\n    }\n#endif\n    return *fp == nullptr;\n}\n\nSPDLOG_INLINE int remove(const filename_t &filename) SPDLOG_NOEXCEPT\n{\n#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)\n    return _wremove(filename.c_str());\n#else\n    return std::remove(filename.c_str());\n#endif\n}\n\nSPDLOG_INLINE int rename(const filename_t &filename1, const filename_t &filename2) SPDLOG_NOEXCEPT\n{\n#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)\n    return _wrename(filename1.c_str(), filename2.c_str());\n#else\n    return std::rename(filename1.c_str(), filename2.c_str());\n#endif\n}\n\n// Return if file exists\nSPDLOG_INLINE bool file_exists(const filename_t &filename) SPDLOG_NOEXCEPT\n{\n#ifdef _WIN32\n#ifdef SPDLOG_WCHAR_FILENAMES\n    auto attribs = GetFileAttributesW(filename.c_str());\n#else\n    auto attribs = GetFileAttributesA(filename.c_str());\n#endif\n    return (attribs != INVALID_FILE_ATTRIBUTES && !(attribs & FILE_ATTRIBUTE_DIRECTORY));\n#else // common linux/unix all have the stat system call\n    struct stat buffer;\n    return (::stat(filename.c_str(), &buffer) == 0);\n#endif\n}\n\n// Return file size according to open FILE* object\nSPDLOG_INLINE size_t filesize(FILE *f)\n{\n    if (f == nullptr)\n    {\n        throw spdlog_ex(\"Failed getting file size. fd is null\");\n    }\n#if defined(_WIN32) && !defined(__CYGWIN__)\n    int fd = _fileno(f);\n#if _WIN64 // 64 bits\n    __int64 ret = _filelengthi64(fd);\n    if (ret >= 0)\n    {\n        return static_cast<size_t>(ret);\n    }\n\n#else // windows 32 bits\n    long ret = _filelength(fd);\n    if (ret >= 0)\n    {\n        return static_cast<size_t>(ret);\n    }\n#endif\n\n#else // unix\n    int fd = fileno(f);\n// 64 bits(but not in osx or cygwin, where fstat64 is deprecated)\n#if !defined(__FreeBSD__) && !defined(__APPLE__) && (defined(__x86_64__) || defined(__ppc64__)) && !defined(__CYGWIN__)\n    struct stat64 st;\n    if (fstat64(fd, &st) == 0)\n    {\n        return static_cast<size_t>(st.st_size);\n    }\n#else // unix 32 bits or cygwin\n    struct stat st;\n\n    if (::fstat(fd, &st) == 0)\n    {\n        return static_cast<size_t>(st.st_size);\n    }\n#endif\n#endif\n    throw spdlog_ex(\"Failed getting file size from fd\", errno);\n}\n\n// Return utc offset in minutes or throw spdlog_ex on failure\nSPDLOG_INLINE int utc_minutes_offset(const std::tm &tm)\n{\n\n#ifdef _WIN32\n#if _WIN32_WINNT < _WIN32_WINNT_WS08\n    TIME_ZONE_INFORMATION tzinfo;\n    auto rv = GetTimeZoneInformation(&tzinfo);\n#else\n    DYNAMIC_TIME_ZONE_INFORMATION tzinfo;\n    auto rv = GetDynamicTimeZoneInformation(&tzinfo);\n#endif\n    if (rv == TIME_ZONE_ID_INVALID)\n        throw spdlog::spdlog_ex(\"Failed getting timezone info. \", errno);\n\n    int offset = -tzinfo.Bias;\n    if (tm.tm_isdst)\n    {\n        offset -= tzinfo.DaylightBias;\n    }\n    else\n    {\n        offset -= tzinfo.StandardBias;\n    }\n    return offset;\n#else\n\n#if defined(sun) || defined(__sun) || defined(_AIX)\n    // 'tm_gmtoff' field is BSD extension and it's missing on SunOS/Solaris\n    struct helper\n    {\n        static long int calculate_gmt_offset(const std::tm &localtm = details::os::localtime(), const std::tm &gmtm = details::os::gmtime())\n        {\n            int local_year = localtm.tm_year + (1900 - 1);\n            int gmt_year = gmtm.tm_year + (1900 - 1);\n\n            long int days = (\n                // difference in day of year\n                localtm.tm_yday -\n                gmtm.tm_yday\n\n                // + intervening leap days\n                + ((local_year >> 2) - (gmt_year >> 2)) - (local_year / 100 - gmt_year / 100) +\n                ((local_year / 100 >> 2) - (gmt_year / 100 >> 2))\n\n                // + difference in years * 365 */\n                + (long int)(local_year - gmt_year) * 365);\n\n            long int hours = (24 * days) + (localtm.tm_hour - gmtm.tm_hour);\n            long int mins = (60 * hours) + (localtm.tm_min - gmtm.tm_min);\n            long int secs = (60 * mins) + (localtm.tm_sec - gmtm.tm_sec);\n\n            return secs;\n        }\n    };\n\n    auto offset_seconds = helper::calculate_gmt_offset(tm);\n#else\n    auto offset_seconds = tm.tm_gmtoff;\n#endif\n\n    return static_cast<int>(offset_seconds / 60);\n#endif\n}\n\n// Return current thread id as size_t\n// It exists because the std::this_thread::get_id() is much slower(especially\n// under VS 2013)\nSPDLOG_INLINE size_t _thread_id() SPDLOG_NOEXCEPT\n{\n#ifdef _WIN32\n    return static_cast<size_t>(::GetCurrentThreadId());\n#elif __linux__\n#if defined(__ANDROID__) && defined(__ANDROID_API__) && (__ANDROID_API__ < 21)\n#define SYS_gettid __NR_gettid\n#endif\n    return static_cast<size_t>(syscall(SYS_gettid));\n#elif __FreeBSD__\n    long tid;\n    thr_self(&tid);\n    return static_cast<size_t>(tid);\n#elif __APPLE__\n    uint64_t tid;\n    pthread_threadid_np(nullptr, &tid);\n    return static_cast<size_t>(tid);\n#else // Default to standard C++11 (other Unix)\n    return static_cast<size_t>(std::hash<std::thread::id>()(std::this_thread::get_id()));\n#endif\n}\n\n// Return current thread id as size_t (from thread local storage)\nSPDLOG_INLINE size_t thread_id() SPDLOG_NOEXCEPT\n{\n#if defined(SPDLOG_NO_TLS)\n    return _thread_id();\n#else // cache thread id in tls\n    static thread_local const size_t tid = _thread_id();\n    return tid;\n#endif\n}\n\n// This is avoid msvc issue in sleep_for that happens if the clock changes.\n// See https://github.com/gabime/spdlog/issues/609\nSPDLOG_INLINE void sleep_for_millis(int milliseconds) SPDLOG_NOEXCEPT\n{\n#if defined(_WIN32)\n    ::Sleep(milliseconds);\n#else\n    std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));\n#endif\n}\n\n// wchar support for windows file names (SPDLOG_WCHAR_FILENAMES must be defined)\n#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)\nSPDLOG_INLINE std::string filename_to_str(const filename_t &filename)\n{\n    fmt::memory_buffer buf;\n    wstr_to_utf8buf(filename, buf);\n    return fmt::to_string(buf);\n}\n#else\nSPDLOG_INLINE std::string filename_to_str(const filename_t &filename)\n{\n    return filename;\n}\n#endif\n\nSPDLOG_INLINE int pid() SPDLOG_NOEXCEPT\n{\n\n#ifdef _WIN32\n    return static_cast<int>(::GetCurrentProcessId());\n#else\n    return static_cast<int>(::getpid());\n#endif\n}\n\n// Determine if the terminal supports colors\n// Source: https://github.com/agauniyal/rang/\nSPDLOG_INLINE bool is_color_terminal() SPDLOG_NOEXCEPT\n{\n#ifdef _WIN32\n    return true;\n#else\n    static constexpr std::array<const char *, 14> Terms = {\n        \"ansi\", \"color\", \"console\", \"cygwin\", \"gnome\", \"konsole\", \"kterm\", \"linux\", \"msys\", \"putty\", \"rxvt\", \"screen\", \"vt100\", \"xterm\"};\n\n    const char *env_p = std::getenv(\"TERM\");\n    if (env_p == nullptr)\n    {\n        return false;\n    }\n\n    static const bool result =\n        std::any_of(std::begin(Terms), std::end(Terms), [&](const char *term) { return std::strstr(env_p, term) != nullptr; });\n    return result;\n#endif\n}\n\n// Detrmine if the terminal attached\n// Source: https://github.com/agauniyal/rang/\nSPDLOG_INLINE bool in_terminal(FILE *file) SPDLOG_NOEXCEPT\n{\n\n#ifdef _WIN32\n    return _isatty(_fileno(file)) != 0;\n#else\n    return isatty(fileno(file)) != 0;\n#endif\n}\n\n#if (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32)\nSPDLOG_INLINE void wstr_to_utf8buf(basic_string_view_t<wchar_t> wstr, fmt::memory_buffer &target)\n{\n    if (wstr.size() > static_cast<size_t>(std::numeric_limits<int>::max()))\n    {\n        throw spdlog::spdlog_ex(\"UTF-16 string is too big to be converted to UTF-8\");\n    }\n\n    int wstr_size = static_cast<int>(wstr.size());\n    if (wstr_size == 0)\n    {\n        target.resize(0);\n        return;\n    }\n\n    int result_size = static_cast<int>(target.capacity());\n    if ((wstr_size + 1) * 2 > result_size)\n    {\n        result_size = ::WideCharToMultiByte(CP_UTF8, 0, wstr.data(), wstr_size, NULL, 0, NULL, NULL);\n    }\n\n    if (result_size > 0)\n    {\n        target.resize(result_size);\n        result_size = ::WideCharToMultiByte(CP_UTF8, 0, wstr.data(), wstr_size, target.data(), result_size, NULL, NULL);\n\n        if (result_size > 0)\n        {\n            target.resize(result_size);\n            return;\n        }\n    }\n\n    throw spdlog::spdlog_ex(fmt::format(\"WideCharToMultiByte failed. Last error: {}\", ::GetLastError()));\n}\n#endif // (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32)\n\n} // namespace os\n} // namespace details\n} // namespace spdlog\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/details/os.h",
    "content": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n#pragma once\n\n#include \"spdlog/common.h\"\n#include <ctime> // std::time_t\n\nnamespace spdlog {\nnamespace details {\nnamespace os {\n\nspdlog::log_clock::time_point now() SPDLOG_NOEXCEPT;\n\nstd::tm localtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT;\n\nstd::tm localtime() SPDLOG_NOEXCEPT;\n\nstd::tm gmtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT;\n\nstd::tm gmtime() SPDLOG_NOEXCEPT;\n\n// eol definition\n#if !defined(SPDLOG_EOL)\n#ifdef _WIN32\n#define SPDLOG_EOL \"\\r\\n\"\n#else\n#define SPDLOG_EOL \"\\n\"\n#endif\n#endif\n\nSPDLOG_CONSTEXPR static const char *default_eol = SPDLOG_EOL;\n\n// folder separator\n#ifdef _WIN32\nconst char folder_sep = '\\\\';\n#else\nSPDLOG_CONSTEXPR static const char folder_sep = '/';\n#endif\n\nvoid prevent_child_fd(FILE *f);\n\n// fopen_s on non windows for writing\nbool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode);\n\nint remove(const filename_t &filename) SPDLOG_NOEXCEPT;\n\nint rename(const filename_t &filename1, const filename_t &filename2) SPDLOG_NOEXCEPT;\n\n// Return if file exists\nbool file_exists(const filename_t &filename) SPDLOG_NOEXCEPT;\n\n// Return file size according to open FILE* object\nsize_t filesize(FILE *f);\n\n// Return utc offset in minutes or throw spdlog_ex on failure\nint utc_minutes_offset(const std::tm &tm = details::os::localtime());\n\n// Return current thread id as size_t\n// It exists because the std::this_thread::get_id() is much slower(especially\n// under VS 2013)\nsize_t _thread_id() SPDLOG_NOEXCEPT;\n\n// Return current thread id as size_t (from thread local storage)\nsize_t thread_id() SPDLOG_NOEXCEPT;\n\n// This is avoid msvc issue in sleep_for that happens if the clock changes.\n// See https://github.com/gabime/spdlog/issues/609\nvoid sleep_for_millis(int milliseconds) SPDLOG_NOEXCEPT;\n\nstd::string filename_to_str(const filename_t &filename);\n\nint pid() SPDLOG_NOEXCEPT;\n\n// Determine if the terminal supports colors\n// Source: https://github.com/agauniyal/rang/\nbool is_color_terminal() SPDLOG_NOEXCEPT;\n\n// Detrmine if the terminal attached\n// Source: https://github.com/agauniyal/rang/\nbool in_terminal(FILE *file) SPDLOG_NOEXCEPT;\n\n#if (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32)\nvoid wstr_to_utf8buf(basic_string_view_t<wchar_t> wstr, fmt::memory_buffer &target);\n#endif\n\n} // namespace os\n} // namespace details\n} // namespace spdlog\n\n#ifdef SPDLOG_HEADER_ONLY\n#include \"os-inl.h\"\n#endif\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/details/pattern_formatter-inl.h",
    "content": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n#pragma once\n\n#ifndef SPDLOG_HEADER_ONLY\n#include \"spdlog/details/pattern_formatter.h\"\n#endif\n\n#include \"spdlog/details/fmt_helper.h\"\n#include \"spdlog/details/log_msg.h\"\n#include \"spdlog/details/os.h\"\n#include \"spdlog/fmt/fmt.h\"\n#include \"spdlog/formatter.h\"\n\n#include <array>\n#include <chrono>\n#include <ctime>\n#include <cctype>\n#include <cstring>\n#include <memory>\n#include <mutex>\n#include <string>\n#include <thread>\n#include <utility>\n#include <vector>\n\nnamespace spdlog {\nnamespace details {\n\n///////////////////////////////////////////////////////////////////////\n// name & level pattern appender\n///////////////////////////////////////////////////////////////////////\n\nclass scoped_padder\n{\npublic:\n    scoped_padder(size_t wrapped_size, const padding_info &padinfo, fmt::memory_buffer &dest)\n        : padinfo_(padinfo)\n        , dest_(dest)\n    {\n\n        if (padinfo_.width_ <= wrapped_size)\n        {\n            total_pad_ = 0;\n            return;\n        }\n\n        total_pad_ = padinfo.width_ - wrapped_size;\n        if (padinfo_.side_ == padding_info::left)\n        {\n            pad_it(total_pad_);\n            total_pad_ = 0;\n        }\n        else if (padinfo_.side_ == padding_info::center)\n        {\n            auto half_pad = total_pad_ / 2;\n            auto reminder = total_pad_ & 1;\n            pad_it(half_pad);\n            total_pad_ = half_pad + reminder; // for the right side\n        }\n    }\n\n    ~scoped_padder()\n    {\n        if (total_pad_)\n        {\n            pad_it(total_pad_);\n        }\n    }\n\nprivate:\n    void pad_it(size_t count)\n    {\n        // count = std::min(count, spaces_.size());\n        assert(count <= spaces_.size());\n        fmt_helper::append_string_view(string_view_t(spaces_.data(), count), dest_);\n    }\n\n    const padding_info &padinfo_;\n    fmt::memory_buffer &dest_;\n    size_t total_pad_;\n    string_view_t spaces_{\"                                                                \", 64};\n};\n\nstruct null_scoped_padder\n{\n    null_scoped_padder(size_t /*wrapped_size*/, const padding_info & /*padinfo*/, fmt::memory_buffer & /*dest*/) {}\n};\n\ntemplate<typename ScopedPadder>\nclass name_formatter : public flag_formatter\n{\npublic:\n    explicit name_formatter(padding_info padinfo)\n        : flag_formatter(padinfo)\n    {}\n\n    void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override\n    {\n        ScopedPadder p(msg.logger_name.size(), padinfo_, dest);\n        fmt_helper::append_string_view(msg.logger_name, dest);\n    }\n};\n\n// log level appender\ntemplate<typename ScopedPadder>\nclass level_formatter : public flag_formatter\n{\npublic:\n    explicit level_formatter(padding_info padinfo)\n        : flag_formatter(padinfo)\n    {}\n\n    void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override\n    {\n        string_view_t &level_name = level::to_string_view(msg.level);\n        ScopedPadder p(level_name.size(), padinfo_, dest);\n        fmt_helper::append_string_view(level_name, dest);\n    }\n};\n\n// short log level appender\ntemplate<typename ScopedPadder>\nclass short_level_formatter : public flag_formatter\n{\npublic:\n    explicit short_level_formatter(padding_info padinfo)\n        : flag_formatter(padinfo)\n    {}\n\n    void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override\n    {\n        string_view_t level_name{level::to_short_c_str(msg.level)};\n        ScopedPadder p(level_name.size(), padinfo_, dest);\n        fmt_helper::append_string_view(level_name, dest);\n    }\n};\n\n///////////////////////////////////////////////////////////////////////\n// Date time pattern appenders\n///////////////////////////////////////////////////////////////////////\n\nstatic const char *ampm(const tm &t)\n{\n    return t.tm_hour >= 12 ? \"PM\" : \"AM\";\n}\n\nstatic int to12h(const tm &t)\n{\n    return t.tm_hour > 12 ? t.tm_hour - 12 : t.tm_hour;\n}\n\n// Abbreviated weekday name\nstatic std::array<const char *, 7> days{\"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\"};\n\ntemplate<typename ScopedPadder>\nclass a_formatter : public flag_formatter\n{\npublic:\n    explicit a_formatter(padding_info padinfo)\n        : flag_formatter(padinfo)\n    {}\n\n    void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override\n    {\n        string_view_t field_value{days[static_cast<size_t>(tm_time.tm_wday)]};\n        ScopedPadder p(field_value.size(), padinfo_, dest);\n        fmt_helper::append_string_view(field_value, dest);\n    }\n};\n\n// Full weekday name\nstatic std::array<const char *, 7> full_days{\"Sunday\", \"Monday\", \"Tuesday\", \"Wednesday\", \"Thursday\", \"Friday\", \"Saturday\"};\n\ntemplate<typename ScopedPadder>\nclass A_formatter : public flag_formatter\n{\npublic:\n    explicit A_formatter(padding_info padinfo)\n        : flag_formatter(padinfo)\n    {}\n\n    void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override\n    {\n        string_view_t field_value{full_days[static_cast<size_t>(tm_time.tm_wday)]};\n        ScopedPadder p(field_value.size(), padinfo_, dest);\n        fmt_helper::append_string_view(field_value, dest);\n    }\n};\n\n// Abbreviated month\nstatic const std::array<const char *, 12> months{\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\", \"Jul\", \"Aug\", \"Sept\", \"Oct\", \"Nov\", \"Dec\"};\n\ntemplate<typename ScopedPadder>\nclass b_formatter : public flag_formatter\n{\npublic:\n    explicit b_formatter(padding_info padinfo)\n        : flag_formatter(padinfo)\n    {}\n\n    void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override\n    {\n        string_view_t field_value{months[static_cast<size_t>(tm_time.tm_mon)]};\n        ScopedPadder p(field_value.size(), padinfo_, dest);\n        fmt_helper::append_string_view(field_value, dest);\n    }\n};\n\n// Full month name\nstatic const std::array<const char *, 12> full_months{\n    \"January\", \"February\", \"March\", \"April\", \"May\", \"June\", \"July\", \"August\", \"September\", \"October\", \"November\", \"December\"};\n\ntemplate<typename ScopedPadder>\nclass B_formatter : public flag_formatter\n{\npublic:\n    explicit B_formatter(padding_info padinfo)\n        : flag_formatter(padinfo)\n    {}\n\n    void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override\n    {\n        string_view_t field_value{full_months[static_cast<size_t>(tm_time.tm_mon)]};\n        ScopedPadder p(field_value.size(), padinfo_, dest);\n        fmt_helper::append_string_view(field_value, dest);\n    }\n};\n\n// Date and time representation (Thu Aug 23 15:35:46 2014)\ntemplate<typename ScopedPadder>\nclass c_formatter final : public flag_formatter\n{\npublic:\n    explicit c_formatter(padding_info padinfo)\n        : flag_formatter(padinfo)\n    {}\n\n    void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override\n    {\n        const size_t field_size = 24;\n        ScopedPadder p(field_size, padinfo_, dest);\n\n        fmt_helper::append_string_view(days[static_cast<size_t>(tm_time.tm_wday)], dest);\n        dest.push_back(' ');\n        fmt_helper::append_string_view(months[static_cast<size_t>(tm_time.tm_mon)], dest);\n        dest.push_back(' ');\n        fmt_helper::append_int(tm_time.tm_mday, dest);\n        dest.push_back(' ');\n        // time\n\n        fmt_helper::pad2(tm_time.tm_hour, dest);\n        dest.push_back(':');\n        fmt_helper::pad2(tm_time.tm_min, dest);\n        dest.push_back(':');\n        fmt_helper::pad2(tm_time.tm_sec, dest);\n        dest.push_back(' ');\n        fmt_helper::append_int(tm_time.tm_year + 1900, dest);\n    }\n};\n\n// year - 2 digit\ntemplate<typename ScopedPadder>\nclass C_formatter final : public flag_formatter\n{\npublic:\n    explicit C_formatter(padding_info padinfo)\n        : flag_formatter(padinfo)\n    {}\n\n    void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override\n    {\n        const size_t field_size = 2;\n        ScopedPadder p(field_size, padinfo_, dest);\n        fmt_helper::pad2(tm_time.tm_year % 100, dest);\n    }\n};\n\n// Short MM/DD/YY date, equivalent to %m/%d/%y 08/23/01\ntemplate<typename ScopedPadder>\nclass D_formatter final : public flag_formatter\n{\npublic:\n    explicit D_formatter(padding_info padinfo)\n        : flag_formatter(padinfo)\n    {}\n\n    void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override\n    {\n        const size_t field_size = 10;\n        ScopedPadder p(field_size, padinfo_, dest);\n\n        fmt_helper::pad2(tm_time.tm_mon + 1, dest);\n        dest.push_back('/');\n        fmt_helper::pad2(tm_time.tm_mday, dest);\n        dest.push_back('/');\n        fmt_helper::pad2(tm_time.tm_year % 100, dest);\n    }\n};\n\n// year - 4 digit\ntemplate<typename ScopedPadder>\nclass Y_formatter final : public flag_formatter\n{\npublic:\n    explicit Y_formatter(padding_info padinfo)\n        : flag_formatter(padinfo)\n    {}\n\n    void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override\n    {\n        const size_t field_size = 4;\n        ScopedPadder p(field_size, padinfo_, dest);\n        fmt_helper::append_int(tm_time.tm_year + 1900, dest);\n    }\n};\n\n// month 1-12\ntemplate<typename ScopedPadder>\nclass m_formatter final : public flag_formatter\n{\npublic:\n    explicit m_formatter(padding_info padinfo)\n        : flag_formatter(padinfo)\n    {}\n\n    void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override\n    {\n        const size_t field_size = 2;\n        ScopedPadder p(field_size, padinfo_, dest);\n        fmt_helper::pad2(tm_time.tm_mon + 1, dest);\n    }\n};\n\n// day of month 1-31\ntemplate<typename ScopedPadder>\nclass d_formatter final : public flag_formatter\n{\npublic:\n    explicit d_formatter(padding_info padinfo)\n        : flag_formatter(padinfo)\n    {}\n\n    void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override\n    {\n        const size_t field_size = 2;\n        ScopedPadder p(field_size, padinfo_, dest);\n        fmt_helper::pad2(tm_time.tm_mday, dest);\n    }\n};\n\n// hours in 24 format 0-23\ntemplate<typename ScopedPadder>\nclass H_formatter final : public flag_formatter\n{\npublic:\n    explicit H_formatter(padding_info padinfo)\n        : flag_formatter(padinfo)\n    {}\n\n    void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override\n    {\n        const size_t field_size = 2;\n        ScopedPadder p(field_size, padinfo_, dest);\n        fmt_helper::pad2(tm_time.tm_hour, dest);\n    }\n};\n\n// hours in 12 format 1-12\ntemplate<typename ScopedPadder>\nclass I_formatter final : public flag_formatter\n{\npublic:\n    explicit I_formatter(padding_info padinfo)\n        : flag_formatter(padinfo)\n    {}\n\n    void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override\n    {\n        const size_t field_size = 2;\n        ScopedPadder p(field_size, padinfo_, dest);\n        fmt_helper::pad2(to12h(tm_time), dest);\n    }\n};\n\n// minutes 0-59\ntemplate<typename ScopedPadder>\nclass M_formatter final : public flag_formatter\n{\npublic:\n    explicit M_formatter(padding_info padinfo)\n        : flag_formatter(padinfo)\n    {}\n\n    void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override\n    {\n        const size_t field_size = 2;\n        ScopedPadder p(field_size, padinfo_, dest);\n        fmt_helper::pad2(tm_time.tm_min, dest);\n    }\n};\n\n// seconds 0-59\ntemplate<typename ScopedPadder>\nclass S_formatter final : public flag_formatter\n{\npublic:\n    explicit S_formatter(padding_info padinfo)\n        : flag_formatter(padinfo)\n    {}\n\n    void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override\n    {\n        const size_t field_size = 2;\n        ScopedPadder p(field_size, padinfo_, dest);\n        fmt_helper::pad2(tm_time.tm_sec, dest);\n    }\n};\n\n// milliseconds\ntemplate<typename ScopedPadder>\nclass e_formatter final : public flag_formatter\n{\npublic:\n    explicit e_formatter(padding_info padinfo)\n        : flag_formatter(padinfo)\n    {}\n\n    void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override\n    {\n        auto millis = fmt_helper::time_fraction<std::chrono::milliseconds>(msg.time);\n        const size_t field_size = 3;\n        ScopedPadder p(field_size, padinfo_, dest);\n        fmt_helper::pad3(static_cast<uint32_t>(millis.count()), dest);\n    }\n};\n\n// microseconds\ntemplate<typename ScopedPadder>\nclass f_formatter final : public flag_formatter\n{\npublic:\n    explicit f_formatter(padding_info padinfo)\n        : flag_formatter(padinfo)\n    {}\n\n    void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override\n    {\n        auto micros = fmt_helper::time_fraction<std::chrono::microseconds>(msg.time);\n\n        const size_t field_size = 6;\n        ScopedPadder p(field_size, padinfo_, dest);\n        fmt_helper::pad6(static_cast<size_t>(micros.count()), dest);\n    }\n};\n\n// nanoseconds\ntemplate<typename ScopedPadder>\nclass F_formatter final : public flag_formatter\n{\npublic:\n    explicit F_formatter(padding_info padinfo)\n        : flag_formatter(padinfo)\n    {}\n\n    void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override\n    {\n        auto ns = fmt_helper::time_fraction<std::chrono::nanoseconds>(msg.time);\n        const size_t field_size = 9;\n        ScopedPadder p(field_size, padinfo_, dest);\n        fmt_helper::pad9(static_cast<size_t>(ns.count()), dest);\n    }\n};\n\n// seconds since epoch\ntemplate<typename ScopedPadder>\nclass E_formatter final : public flag_formatter\n{\npublic:\n    explicit E_formatter(padding_info padinfo)\n        : flag_formatter(padinfo)\n    {}\n\n    void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override\n    {\n        const size_t field_size = 10;\n        ScopedPadder p(field_size, padinfo_, dest);\n        auto duration = msg.time.time_since_epoch();\n        auto seconds = std::chrono::duration_cast<std::chrono::seconds>(duration).count();\n        fmt_helper::append_int(seconds, dest);\n    }\n};\n\n// AM/PM\ntemplate<typename ScopedPadder>\nclass p_formatter final : public flag_formatter\n{\npublic:\n    explicit p_formatter(padding_info padinfo)\n        : flag_formatter(padinfo)\n    {}\n\n    void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override\n    {\n        const size_t field_size = 2;\n        ScopedPadder p(field_size, padinfo_, dest);\n        fmt_helper::append_string_view(ampm(tm_time), dest);\n    }\n};\n\n// 12 hour clock 02:55:02 pm\ntemplate<typename ScopedPadder>\nclass r_formatter final : public flag_formatter\n{\npublic:\n    explicit r_formatter(padding_info padinfo)\n        : flag_formatter(padinfo)\n    {}\n\n    void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override\n    {\n        const size_t field_size = 11;\n        ScopedPadder p(field_size, padinfo_, dest);\n\n        fmt_helper::pad2(to12h(tm_time), dest);\n        dest.push_back(':');\n        fmt_helper::pad2(tm_time.tm_min, dest);\n        dest.push_back(':');\n        fmt_helper::pad2(tm_time.tm_sec, dest);\n        dest.push_back(' ');\n        fmt_helper::append_string_view(ampm(tm_time), dest);\n    }\n};\n\n// 24-hour HH:MM time, equivalent to %H:%M\ntemplate<typename ScopedPadder>\nclass R_formatter final : public flag_formatter\n{\npublic:\n    explicit R_formatter(padding_info padinfo)\n        : flag_formatter(padinfo)\n    {}\n\n    void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override\n    {\n        const size_t field_size = 5;\n        ScopedPadder p(field_size, padinfo_, dest);\n\n        fmt_helper::pad2(tm_time.tm_hour, dest);\n        dest.push_back(':');\n        fmt_helper::pad2(tm_time.tm_min, dest);\n    }\n};\n\n// ISO 8601 time format (HH:MM:SS), equivalent to %H:%M:%S\ntemplate<typename ScopedPadder>\nclass T_formatter final : public flag_formatter\n{\npublic:\n    explicit T_formatter(padding_info padinfo)\n        : flag_formatter(padinfo)\n    {}\n\n    void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override\n    {\n        const size_t field_size = 8;\n        ScopedPadder p(field_size, padinfo_, dest);\n\n        fmt_helper::pad2(tm_time.tm_hour, dest);\n        dest.push_back(':');\n        fmt_helper::pad2(tm_time.tm_min, dest);\n        dest.push_back(':');\n        fmt_helper::pad2(tm_time.tm_sec, dest);\n    }\n};\n\n// ISO 8601 offset from UTC in timezone (+-HH:MM)\ntemplate<typename ScopedPadder>\nclass z_formatter final : public flag_formatter\n{\npublic:\n    explicit z_formatter(padding_info padinfo)\n        : flag_formatter(padinfo)\n    {}\n\n    z_formatter() = default;\n    z_formatter(const z_formatter &) = delete;\n    z_formatter &operator=(const z_formatter &) = delete;\n\n    void format(const details::log_msg &msg, const std::tm &tm_time, fmt::memory_buffer &dest) override\n    {\n        const size_t field_size = 6;\n        ScopedPadder p(field_size, padinfo_, dest);\n\n#ifdef _WIN32\n        int total_minutes = get_cached_offset(msg, tm_time);\n#else\n        // No need to chache under gcc,\n        // it is very fast (already stored in tm.tm_gmtoff)\n        (void)(msg);\n        int total_minutes = os::utc_minutes_offset(tm_time);\n#endif\n        bool is_negative = total_minutes < 0;\n        if (is_negative)\n        {\n            total_minutes = -total_minutes;\n            dest.push_back('-');\n        }\n        else\n        {\n            dest.push_back('+');\n        }\n\n        fmt_helper::pad2(total_minutes / 60, dest); // hours\n        dest.push_back(':');\n        fmt_helper::pad2(total_minutes % 60, dest); // minutes\n    }\n\nprivate:\n    log_clock::time_point last_update_{std::chrono::seconds(0)};\n#ifdef _WIN32\n    int offset_minutes_{0};\n\n    int get_cached_offset(const log_msg &msg, const std::tm &tm_time)\n    {\n        // refresh every 10 seconds\n        if (msg.time - last_update_ >= std::chrono::seconds(10))\n        {\n            offset_minutes_ = os::utc_minutes_offset(tm_time);\n            last_update_ = msg.time;\n        }\n        return offset_minutes_;\n    }\n#endif\n};\n\n// Thread id\ntemplate<typename ScopedPadder>\nclass t_formatter final : public flag_formatter\n{\npublic:\n    explicit t_formatter(padding_info padinfo)\n        : flag_formatter(padinfo)\n    {}\n\n    void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override\n    {\n        const auto field_size = fmt_helper::count_digits(msg.thread_id);\n        ScopedPadder p(field_size, padinfo_, dest);\n        fmt_helper::append_int(msg.thread_id, dest);\n    }\n};\n\n// Current pid\ntemplate<typename ScopedPadder>\nclass pid_formatter final : public flag_formatter\n{\npublic:\n    explicit pid_formatter(padding_info padinfo)\n        : flag_formatter(padinfo)\n    {}\n\n    void format(const details::log_msg &, const std::tm &, fmt::memory_buffer &dest) override\n    {\n        const auto pid = static_cast<uint32_t>(details::os::pid());\n        auto field_size = fmt_helper::count_digits(pid);\n        ScopedPadder p(field_size, padinfo_, dest);\n        fmt_helper::append_int(pid, dest);\n    }\n};\n\ntemplate<typename ScopedPadder>\nclass v_formatter final : public flag_formatter\n{\npublic:\n    explicit v_formatter(padding_info padinfo)\n        : flag_formatter(padinfo)\n    {}\n\n    void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override\n    {\n        ScopedPadder p(msg.payload.size(), padinfo_, dest);\n        fmt_helper::append_string_view(msg.payload, dest);\n    }\n};\n\nclass ch_formatter final : public flag_formatter\n{\npublic:\n    explicit ch_formatter(char ch)\n        : ch_(ch)\n    {}\n\n    void format(const details::log_msg &, const std::tm &, fmt::memory_buffer &dest) override\n    {\n        dest.push_back(ch_);\n    }\n\nprivate:\n    char ch_;\n};\n\n// aggregate user chars to display as is\nclass aggregate_formatter final : public flag_formatter\n{\npublic:\n    aggregate_formatter() = default;\n\n    void add_ch(char ch)\n    {\n        str_ += ch;\n    }\n    void format(const details::log_msg &, const std::tm &, fmt::memory_buffer &dest) override\n    {\n        fmt_helper::append_string_view(str_, dest);\n    }\n\nprivate:\n    std::string str_;\n};\n\n// mark the color range. expect it to be in the form of \"%^colored text%$\"\nclass color_start_formatter final : public flag_formatter\n{\npublic:\n    explicit color_start_formatter(padding_info padinfo)\n        : flag_formatter(padinfo)\n    {}\n\n    void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override\n    {\n        msg.color_range_start = dest.size();\n    }\n};\n\nclass color_stop_formatter final : public flag_formatter\n{\npublic:\n    explicit color_stop_formatter(padding_info padinfo)\n        : flag_formatter(padinfo)\n    {}\n\n    void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override\n    {\n        msg.color_range_end = dest.size();\n    }\n};\n\n// print source location\ntemplate<typename ScopedPadder>\nclass source_location_formatter final : public flag_formatter\n{\npublic:\n    explicit source_location_formatter(padding_info padinfo)\n        : flag_formatter(padinfo)\n    {}\n\n    void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override\n    {\n        if (msg.source.empty())\n        {\n            return;\n        }\n\n        size_t text_size =\n            padinfo_.enabled() ? std::char_traits<char>::length(msg.source.filename) + fmt_helper::count_digits(msg.source.line) + 1 : 0;\n\n        ScopedPadder p(text_size, padinfo_, dest);\n        fmt_helper::append_string_view(msg.source.filename, dest);\n        dest.push_back(':');\n        fmt_helper::append_int(msg.source.line, dest);\n    }\n};\n\n// print source filename\ntemplate<typename ScopedPadder>\nclass source_filename_formatter final : public flag_formatter\n{\npublic:\n    explicit source_filename_formatter(padding_info padinfo)\n        : flag_formatter(padinfo)\n    {}\n\n    void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override\n    {\n        if (msg.source.empty())\n        {\n            return;\n        }\n        size_t text_size = padinfo_.enabled() ? std::char_traits<char>::length(msg.source.filename) : 0;\n        ScopedPadder p(text_size, padinfo_, dest);\n        fmt_helper::append_string_view(msg.source.filename, dest);\n    }\n};\n\ntemplate<typename ScopedPadder>\nclass short_filename_formatter final : public flag_formatter\n{\npublic:\n    explicit short_filename_formatter(padding_info padinfo)\n        : flag_formatter(padinfo)\n    {}\n\n    static const char *basename(const char *filename)\n    {\n        const char *rv = std::strrchr(filename, os::folder_sep);\n        return rv != nullptr ? rv + 1 : filename;\n    }\n\n    void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override\n    {\n        if (msg.source.empty())\n        {\n            return;\n        }\n        auto filename = basename(msg.source.filename);\n        size_t text_size = padinfo_.enabled() ? std::char_traits<char>::length(filename) : 0;\n        ScopedPadder p(text_size, padinfo_, dest);\n        fmt_helper::append_string_view(filename, dest);\n    }\n};\n\ntemplate<typename ScopedPadder>\nclass source_linenum_formatter final : public flag_formatter\n{\npublic:\n    explicit source_linenum_formatter(padding_info padinfo)\n        : flag_formatter(padinfo)\n    {}\n\n    void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override\n    {\n        if (msg.source.empty())\n        {\n            return;\n        }\n\n        auto field_size = fmt_helper::count_digits(msg.source.line);\n        ScopedPadder p(field_size, padinfo_, dest);\n        fmt_helper::append_int(msg.source.line, dest);\n    }\n};\n\n// print source funcname\ntemplate<typename ScopedPadder>\nclass source_funcname_formatter final : public flag_formatter\n{\npublic:\n    explicit source_funcname_formatter(padding_info padinfo)\n        : flag_formatter(padinfo)\n    {}\n\n    void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override\n    {\n        if (msg.source.empty())\n        {\n            return;\n        }\n        size_t text_size = padinfo_.enabled() ? std::char_traits<char>::length(msg.source.funcname) : 0;\n        ScopedPadder p(text_size, padinfo_, dest);\n        fmt_helper::append_string_view(msg.source.funcname, dest);\n    }\n};\n\n// print elapsed time since last message\ntemplate<typename ScopedPadder, typename Units>\n\nclass elapsed_formatter final : public flag_formatter\n{\npublic:\n    using DurationUnits = Units;\n\n    explicit elapsed_formatter(padding_info padinfo)\n        : flag_formatter(padinfo)\n        , last_message_time_(log_clock::now())\n    {}\n\n    void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override\n    {\n        auto delta = msg.time - last_message_time_;\n        auto delta_units = std::chrono::duration_cast<DurationUnits>(delta);\n        last_message_time_ = msg.time;\n        ScopedPadder p(6, padinfo_, dest);\n        fmt_helper::pad6(static_cast<size_t>(delta_units.count()), dest);\n    }\n\nprotected:\n    log_clock::time_point last_message_time_;\n};\n\n// Full info formatter\n// pattern: [%Y-%m-%d %H:%M:%S.%e] [%n] [%l] %v\nclass full_formatter final : public flag_formatter\n{\npublic:\n    explicit full_formatter(padding_info padinfo)\n        : flag_formatter(padinfo)\n    {}\n\n    void format(const details::log_msg &msg, const std::tm &tm_time, fmt::memory_buffer &dest) override\n    {\n        using std::chrono::duration_cast;\n        using std::chrono::milliseconds;\n        using std::chrono::seconds;\n\n#ifndef SPDLOG_NO_DATETIME\n\n        // cache the date/time part for the next second.\n        auto duration = msg.time.time_since_epoch();\n        auto secs = duration_cast<seconds>(duration);\n\n        if (cache_timestamp_ != secs || cached_datetime_.size() == 0)\n        {\n            cached_datetime_.clear();\n            cached_datetime_.push_back('[');\n            fmt_helper::append_int(tm_time.tm_year + 1900, cached_datetime_);\n            cached_datetime_.push_back('-');\n\n            fmt_helper::pad2(tm_time.tm_mon + 1, cached_datetime_);\n            cached_datetime_.push_back('-');\n\n            fmt_helper::pad2(tm_time.tm_mday, cached_datetime_);\n            cached_datetime_.push_back(' ');\n\n            fmt_helper::pad2(tm_time.tm_hour, cached_datetime_);\n            cached_datetime_.push_back(':');\n\n            fmt_helper::pad2(tm_time.tm_min, cached_datetime_);\n            cached_datetime_.push_back(':');\n\n            fmt_helper::pad2(tm_time.tm_sec, cached_datetime_);\n            cached_datetime_.push_back('.');\n\n            cache_timestamp_ = secs;\n        }\n        fmt_helper::append_buf(cached_datetime_, dest);\n\n        auto millis = fmt_helper::time_fraction<milliseconds>(msg.time);\n        fmt_helper::pad3(static_cast<uint32_t>(millis.count()), dest);\n        dest.push_back(']');\n        dest.push_back(' ');\n\n#else // no datetime needed\n        (void)tm_time;\n#endif\n\n#ifndef SPDLOG_NO_NAME\n        if (msg.logger_name.size() > 0)\n        {\n            dest.push_back('[');\n            // fmt_helper::append_str(*msg.logger_name, dest);\n            fmt_helper::append_string_view(msg.logger_name, dest);\n            dest.push_back(']');\n            dest.push_back(' ');\n        }\n#endif\n        dest.push_back('[');\n        // wrap the level name with color\n        msg.color_range_start = dest.size();\n        // fmt_helper::append_string_view(level::to_c_str(msg.level), dest);\n        fmt_helper::append_string_view(level::to_string_view(msg.level), dest);\n        msg.color_range_end = dest.size();\n        dest.push_back(']');\n        dest.push_back(' ');\n\n        // add source location if present\n        if (!msg.source.empty())\n        {\n            dest.push_back('[');\n            const char *filename = details::short_filename_formatter<details::null_scoped_padder>::basename(msg.source.filename);\n            fmt_helper::append_string_view(filename, dest);\n            dest.push_back(':');\n            fmt_helper::append_int(msg.source.line, dest);\n            dest.push_back(']');\n            dest.push_back(' ');\n        }\n        // fmt_helper::append_string_view(msg.msg(), dest);\n        fmt_helper::append_string_view(msg.payload, dest);\n    }\n\nprivate:\n    std::chrono::seconds cache_timestamp_{0};\n    fmt::basic_memory_buffer<char, 128> cached_datetime_;\n};\n\n} // namespace details\n\nSPDLOG_INLINE pattern_formatter::pattern_formatter(std::string pattern, pattern_time_type time_type, std::string eol)\n    : pattern_(std::move(pattern))\n    , eol_(std::move(eol))\n    , pattern_time_type_(time_type)\n    , last_log_secs_(0)\n{\n    std::memset(&cached_tm_, 0, sizeof(cached_tm_));\n    compile_pattern_(pattern_);\n}\n\n// use by default full formatter for if pattern is not given\nSPDLOG_INLINE pattern_formatter::pattern_formatter(pattern_time_type time_type, std::string eol)\n    : pattern_(\"%+\")\n    , eol_(std::move(eol))\n    , pattern_time_type_(time_type)\n    , last_log_secs_(0)\n{\n    std::memset(&cached_tm_, 0, sizeof(cached_tm_));\n    formatters_.push_back(details::make_unique<details::full_formatter>(details::padding_info{}));\n}\n\nSPDLOG_INLINE std::unique_ptr<formatter> pattern_formatter::clone() const\n{\n    return details::make_unique<pattern_formatter>(pattern_, pattern_time_type_, eol_);\n}\n\nSPDLOG_INLINE void pattern_formatter::format(const details::log_msg &msg, fmt::memory_buffer &dest)\n{\n#ifndef SPDLOG_NO_DATETIME\n    auto secs = std::chrono::duration_cast<std::chrono::seconds>(msg.time.time_since_epoch());\n    if (secs != last_log_secs_)\n    {\n        cached_tm_ = get_time_(msg);\n        last_log_secs_ = secs;\n    }\n#endif\n    for (auto &f : formatters_)\n    {\n        f->format(msg, cached_tm_, dest);\n    }\n    // write eol\n    details::fmt_helper::append_string_view(eol_, dest);\n}\n\nSPDLOG_INLINE std::tm pattern_formatter::get_time_(const details::log_msg &msg)\n{\n    if (pattern_time_type_ == pattern_time_type::local)\n    {\n        return details::os::localtime(log_clock::to_time_t(msg.time));\n    }\n    return details::os::gmtime(log_clock::to_time_t(msg.time));\n}\n\ntemplate<typename Padder>\nSPDLOG_INLINE void pattern_formatter::handle_flag_(char flag, details::padding_info padding)\n{\n    switch (flag)\n    {\n\n    case ('+'): // default formatter\n        formatters_.push_back(details::make_unique<details::full_formatter>(padding));\n        break;\n\n    case 'n': // logger name\n        formatters_.push_back(details::make_unique<details::name_formatter<Padder>>(padding));\n        break;\n\n    case 'l': // level\n        formatters_.push_back(details::make_unique<details::level_formatter<Padder>>(padding));\n        break;\n\n    case 'L': // short level\n        formatters_.push_back(details::make_unique<details::short_level_formatter<Padder>>(padding));\n        break;\n\n    case ('t'): // thread id\n        formatters_.push_back(details::make_unique<details::t_formatter<Padder>>(padding));\n        break;\n\n    case ('v'): // the message text\n        formatters_.push_back(details::make_unique<details::v_formatter<Padder>>(padding));\n        break;\n\n    case ('a'): // weekday\n        formatters_.push_back(details::make_unique<details::a_formatter<Padder>>(padding));\n        break;\n\n    case ('A'): // short weekday\n        formatters_.push_back(details::make_unique<details::A_formatter<Padder>>(padding));\n        break;\n\n    case ('b'):\n    case ('h'): // month\n        formatters_.push_back(details::make_unique<details::b_formatter<Padder>>(padding));\n        break;\n\n    case ('B'): // short month\n        formatters_.push_back(details::make_unique<details::B_formatter<Padder>>(padding));\n        break;\n\n    case ('c'): // datetime\n        formatters_.push_back(details::make_unique<details::c_formatter<Padder>>(padding));\n        break;\n\n    case ('C'): // year 2 digits\n        formatters_.push_back(details::make_unique<details::C_formatter<Padder>>(padding));\n        break;\n\n    case ('Y'): // year 4 digits\n        formatters_.push_back(details::make_unique<details::Y_formatter<Padder>>(padding));\n        break;\n\n    case ('D'):\n    case ('x'): // datetime MM/DD/YY\n        formatters_.push_back(details::make_unique<details::D_formatter<Padder>>(padding));\n        break;\n\n    case ('m'): // month 1-12\n        formatters_.push_back(details::make_unique<details::m_formatter<Padder>>(padding));\n        break;\n\n    case ('d'): // day of month 1-31\n        formatters_.push_back(details::make_unique<details::d_formatter<Padder>>(padding));\n        break;\n\n    case ('H'): // hours 24\n        formatters_.push_back(details::make_unique<details::H_formatter<Padder>>(padding));\n        break;\n\n    case ('I'): // hours 12\n        formatters_.push_back(details::make_unique<details::I_formatter<Padder>>(padding));\n        break;\n\n    case ('M'): // minutes\n        formatters_.push_back(details::make_unique<details::M_formatter<Padder>>(padding));\n        break;\n\n    case ('S'): // seconds\n        formatters_.push_back(details::make_unique<details::S_formatter<Padder>>(padding));\n        break;\n\n    case ('e'): // milliseconds\n        formatters_.push_back(details::make_unique<details::e_formatter<Padder>>(padding));\n        break;\n\n    case ('f'): // microseconds\n        formatters_.push_back(details::make_unique<details::f_formatter<Padder>>(padding));\n        break;\n\n    case ('F'): // nanoseconds\n        formatters_.push_back(details::make_unique<details::F_formatter<Padder>>(padding));\n        break;\n\n    case ('E'): // seconds since epoch\n        formatters_.push_back(details::make_unique<details::E_formatter<Padder>>(padding));\n        break;\n\n    case ('p'): // am/pm\n        formatters_.push_back(details::make_unique<details::p_formatter<Padder>>(padding));\n        break;\n\n    case ('r'): // 12 hour clock 02:55:02 pm\n        formatters_.push_back(details::make_unique<details::r_formatter<Padder>>(padding));\n        break;\n\n    case ('R'): // 24-hour HH:MM time\n        formatters_.push_back(details::make_unique<details::R_formatter<Padder>>(padding));\n        break;\n\n    case ('T'):\n    case ('X'): // ISO 8601 time format (HH:MM:SS)\n        formatters_.push_back(details::make_unique<details::T_formatter<Padder>>(padding));\n        break;\n\n    case ('z'): // timezone\n        formatters_.push_back(details::make_unique<details::z_formatter<Padder>>(padding));\n        break;\n\n    case ('P'): // pid\n        formatters_.push_back(details::make_unique<details::pid_formatter<Padder>>(padding));\n        break;\n\n    case ('^'): // color range start\n        formatters_.push_back(details::make_unique<details::color_start_formatter>(padding));\n        break;\n\n    case ('$'): // color range end\n        formatters_.push_back(details::make_unique<details::color_stop_formatter>(padding));\n        break;\n\n    case ('@'): // source location (filename:filenumber)\n        formatters_.push_back(details::make_unique<details::source_location_formatter<Padder>>(padding));\n        break;\n\n    case ('s'): // short source filename - without directory name\n        formatters_.push_back(details::make_unique<details::short_filename_formatter<Padder>>(padding));\n        break;\n\n    case ('g'): // full source filename\n        formatters_.push_back(details::make_unique<details::source_filename_formatter<Padder>>(padding));\n        break;\n\n    case ('#'): // source line number\n        formatters_.push_back(details::make_unique<details::source_linenum_formatter<Padder>>(padding));\n        break;\n\n    case ('!'): // source funcname\n        formatters_.push_back(details::make_unique<details::source_funcname_formatter<Padder>>(padding));\n        break;\n\n    case ('%'): // % char\n        formatters_.push_back(details::make_unique<details::ch_formatter>('%'));\n        break;\n\n    case ('u'): // elapsed time since last log message in nanos\n        formatters_.push_back(details::make_unique<details::elapsed_formatter<Padder, std::chrono::nanoseconds>>(padding));\n        break;\n\n    case ('i'): // elapsed time since last log message in micros\n        formatters_.push_back(details::make_unique<details::elapsed_formatter<Padder, std::chrono::microseconds>>(padding));\n        break;\n\n    case ('o'): // elapsed time since last log message in millis\n        formatters_.push_back(details::make_unique<details::elapsed_formatter<Padder, std::chrono::milliseconds>>(padding));\n        break;\n\n    case ('O'): // elapsed time since last log message in seconds\n        formatters_.push_back(details::make_unique<details::elapsed_formatter<Padder, std::chrono::seconds>>(padding));\n        break;\n\n    default: // Unknown flag appears as is\n        auto unknown_flag = details::make_unique<details::aggregate_formatter>();\n        unknown_flag->add_ch('%');\n        unknown_flag->add_ch(flag);\n        formatters_.push_back((std::move(unknown_flag)));\n        break;\n    }\n}\n\n// Extract given pad spec (e.g. %8X)\n// Advance the given it pass the end of the padding spec found (if any)\n// Return padding.\nSPDLOG_INLINE details::padding_info pattern_formatter::handle_padspec_(std::string::const_iterator &it, std::string::const_iterator end)\n{\n    using details::padding_info;\n    using details::scoped_padder;\n    const size_t max_width = 64;\n    if (it == end)\n    {\n        return padding_info{};\n    }\n\n    padding_info::pad_side side;\n    switch (*it)\n    {\n    case '-':\n        side = padding_info::right;\n        ++it;\n        break;\n    case '=':\n        side = padding_info::center;\n        ++it;\n        break;\n    default:\n        side = details::padding_info::left;\n        break;\n    }\n\n    if (it == end || !std::isdigit(static_cast<unsigned char>(*it)))\n    {\n        return padding_info{0, side};\n    }\n\n    auto width = static_cast<size_t>(*it - '0');\n    for (++it; it != end && std::isdigit(static_cast<unsigned char>(*it)); ++it)\n    {\n        auto digit = static_cast<size_t>(*it - '0');\n        width = width * 10 + digit;\n    }\n    return details::padding_info{std::min<size_t>(width, max_width), side};\n}\n\nSPDLOG_INLINE void pattern_formatter::compile_pattern_(const std::string &pattern)\n{\n    auto end = pattern.end();\n    std::unique_ptr<details::aggregate_formatter> user_chars;\n    formatters_.clear();\n    for (auto it = pattern.begin(); it != end; ++it)\n    {\n        if (*it == '%')\n        {\n            if (user_chars) // append user chars found so far\n            {\n                formatters_.push_back(std::move(user_chars));\n            }\n\n            auto padding = handle_padspec_(++it, end);\n\n            if (it != end)\n            {\n                if (padding.enabled())\n                {\n                    handle_flag_<details::scoped_padder>(*it, padding);\n                }\n                else\n                {\n                    handle_flag_<details::null_scoped_padder>(*it, padding);\n                }\n            }\n            else\n            {\n                break;\n            }\n        }\n        else // chars not following the % sign should be displayed as is\n        {\n            if (!user_chars)\n            {\n                user_chars = details::make_unique<details::aggregate_formatter>();\n            }\n            user_chars->add_ch(*it);\n        }\n    }\n    if (user_chars) // append raw chars found so far\n    {\n        formatters_.push_back(std::move(user_chars));\n    }\n}\n} // namespace spdlog\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/details/pattern_formatter.h",
    "content": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n#pragma once\n\n#include \"spdlog/common.h\"\n#include \"spdlog/details/log_msg.h\"\n#include \"spdlog/details/os.h\"\n#include \"spdlog/formatter.h\"\n\n#include <chrono>\n#include <ctime>\n#include <memory>\n\n#include <string>\n#include <vector>\n\nnamespace spdlog {\nnamespace details {\n\n// padding information.\nstruct padding_info\n{\n    enum pad_side\n    {\n        left,\n        right,\n        center\n    };\n\n    padding_info() = default;\n    padding_info(size_t width, padding_info::pad_side side)\n        : width_(width)\n        , side_(side)\n    {}\n\n    bool enabled() const\n    {\n        return width_ != 0;\n    }\n    const size_t width_ = 0;\n    const pad_side side_ = left;\n};\n\nclass flag_formatter\n{\npublic:\n    explicit flag_formatter(padding_info padinfo)\n        : padinfo_(padinfo)\n    {}\n    flag_formatter() = default;\n    virtual ~flag_formatter() = default;\n    virtual void format(const details::log_msg &msg, const std::tm &tm_time, fmt::memory_buffer &dest) = 0;\n\nprotected:\n    padding_info padinfo_;\n};\n\n} // namespace details\n\nclass pattern_formatter final : public formatter\n{\npublic:\n    explicit pattern_formatter(\n        std::string pattern, pattern_time_type time_type = pattern_time_type::local, std::string eol = spdlog::details::os::default_eol);\n\n    // use default pattern is not given\n    explicit pattern_formatter(pattern_time_type time_type = pattern_time_type::local, std::string eol = spdlog::details::os::default_eol);\n\n    pattern_formatter(const pattern_formatter &other) = delete;\n    pattern_formatter &operator=(const pattern_formatter &other) = delete;\n\n    std::unique_ptr<formatter> clone() const override;\n    void format(const details::log_msg &msg, fmt::memory_buffer &dest) override;\n\nprivate:\n    std::string pattern_;\n    std::string eol_;\n    pattern_time_type pattern_time_type_;\n    std::tm cached_tm_;\n    std::chrono::seconds last_log_secs_;\n    std::vector<std::unique_ptr<details::flag_formatter>> formatters_;\n\n    std::tm get_time_(const details::log_msg &msg);\n    template<typename Padder>\n    void handle_flag_(char flag, details::padding_info padding);\n\n    // Extract given pad spec (e.g. %8X)\n    // Advance the given it pass the end of the padding spec found (if any)\n    // Return padding.\n    details::padding_info handle_padspec_(std::string::const_iterator &it, std::string::const_iterator end);\n\n    void compile_pattern_(const std::string &pattern);\n};\n} // namespace spdlog\n\n#ifdef SPDLOG_HEADER_ONLY\n#include \"pattern_formatter-inl.h\"\n#endif\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/details/periodic_worker-inl.h",
    "content": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n#pragma once\n\n#ifndef SPDLOG_HEADER_ONLY\n#include \"spdlog/details/periodic_worker.h\"\n#endif\n\nnamespace spdlog {\nnamespace details {\n\nSPDLOG_INLINE periodic_worker::periodic_worker(const std::function<void()> &callback_fun, std::chrono::seconds interval)\n{\n    active_ = (interval > std::chrono::seconds::zero());\n    if (!active_)\n    {\n        return;\n    }\n\n    worker_thread_ = std::thread([this, callback_fun, interval]() {\n        for (;;)\n        {\n            std::unique_lock<std::mutex> lock(this->mutex_);\n            if (this->cv_.wait_for(lock, interval, [this] { return !this->active_; }))\n            {\n                return; // active_ == false, so exit this thread\n            }\n            callback_fun();\n        }\n    });\n}\n\n// stop the worker thread and join it\nSPDLOG_INLINE periodic_worker::~periodic_worker()\n{\n    if (worker_thread_.joinable())\n    {\n        {\n            std::lock_guard<std::mutex> lock(mutex_);\n            active_ = false;\n        }\n        cv_.notify_one();\n        worker_thread_.join();\n    }\n}\n\n} // namespace details\n} // namespace spdlog\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/details/periodic_worker.h",
    "content": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n#pragma once\n\n// periodic worker thread - periodically executes the given callback function.\n//\n// RAII over the owned thread:\n//    creates the thread on construction.\n//    stops and joins the thread on destruction (if the thread is executing a callback, wait for it to finish first).\n\n#include <chrono>\n#include <condition_variable>\n#include <functional>\n#include <mutex>\n#include <thread>\nnamespace spdlog {\nnamespace details {\n\nclass periodic_worker\n{\npublic:\n    periodic_worker(const std::function<void()> &callback_fun, std::chrono::seconds interval);\n    periodic_worker(const periodic_worker &) = delete;\n    periodic_worker &operator=(const periodic_worker &) = delete;\n    // stop the worker thread and join it\n    ~periodic_worker();\n\nprivate:\n    bool active_;\n    std::thread worker_thread_;\n    std::mutex mutex_;\n    std::condition_variable cv_;\n};\n} // namespace details\n} // namespace spdlog\n\n#ifdef SPDLOG_HEADER_ONLY\n#include \"periodic_worker-inl.h\"\n#endif\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/details/registry-inl.h",
    "content": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n#pragma once\n\n#ifndef SPDLOG_HEADER_ONLY\n#include \"spdlog/details/registry.h\"\n#endif\n\n#include \"spdlog/common.h\"\n#include \"spdlog/details/periodic_worker.h\"\n#include \"spdlog/logger.h\"\n#include \"spdlog/details/pattern_formatter.h\"\n\n#ifndef SPDLOG_DISABLE_DEFAULT_LOGGER\n// support for the default stdout color logger\n#ifdef _WIN32\n#include \"spdlog/sinks/wincolor_sink.h\"\n#else\n#include \"spdlog/sinks/ansicolor_sink.h\"\n#endif\n#endif // SPDLOG_DISABLE_DEFAULT_LOGGER\n\n#include <chrono>\n#include <functional>\n#include <memory>\n#include <string>\n#include <unordered_map>\n\nnamespace spdlog {\nnamespace details {\n\nSPDLOG_INLINE registry::registry()\n    : formatter_(new pattern_formatter())\n    , level_(spdlog::logger::default_level())\n{\n\n#ifndef SPDLOG_DISABLE_DEFAULT_LOGGER\n    // create default logger (ansicolor_stdout_sink_mt or wincolor_stdout_sink_mt in windows).\n#ifdef _WIN32\n    auto color_sink = std::make_shared<sinks::wincolor_stdout_sink_mt>();\n#else\n    auto color_sink = std::make_shared<sinks::ansicolor_stdout_sink_mt>();\n#endif\n\n    const char *default_logger_name = \"\";\n    default_logger_ = std::make_shared<spdlog::logger>(default_logger_name, std::move(color_sink));\n    loggers_[default_logger_name] = default_logger_;\n\n#endif // SPDLOG_DISABLE_DEFAULT_LOGGER\n}\nSPDLOG_INLINE void registry::register_logger(std::shared_ptr<logger> new_logger)\n{\n    std::lock_guard<std::mutex> lock(logger_map_mutex_);\n    register_logger_(std::move(new_logger));\n}\n\nSPDLOG_INLINE void registry::initialize_logger(std::shared_ptr<logger> new_logger)\n{\n    std::lock_guard<std::mutex> lock(logger_map_mutex_);\n    new_logger->set_formatter(formatter_->clone());\n\n    if (err_handler_)\n    {\n        new_logger->set_error_handler(err_handler_);\n    }\n\n    new_logger->set_level(level_);\n    new_logger->flush_on(flush_level_);\n\n    if (automatic_registration_)\n    {\n        register_logger_(std::move(new_logger));\n    }\n}\n\nSPDLOG_INLINE std::shared_ptr<logger> registry::get(const std::string &logger_name)\n{\n    std::lock_guard<std::mutex> lock(logger_map_mutex_);\n    auto found = loggers_.find(logger_name);\n    return found == loggers_.end() ? nullptr : found->second;\n}\n\nSPDLOG_INLINE std::shared_ptr<logger> registry::default_logger()\n{\n    std::lock_guard<std::mutex> lock(logger_map_mutex_);\n    return default_logger_;\n}\n\n// Return raw ptr to the default logger.\n// To be used directly by the spdlog default api (e.g. spdlog::info)\n// This make the default API faster, but cannot be used concurrently with set_default_logger().\n// e.g do not call set_default_logger() from one thread while calling spdlog::info() from another.\nSPDLOG_INLINE logger *registry::get_default_raw()\n{\n    return default_logger_.get();\n}\n\n// set default logger.\n// default logger is stored in default_logger_ (for faster retrieval) and in the loggers_ map.\nSPDLOG_INLINE void registry::set_default_logger(std::shared_ptr<logger> new_default_logger)\n{\n    std::lock_guard<std::mutex> lock(logger_map_mutex_);\n    // remove previous default logger from the map\n    if (default_logger_ != nullptr)\n    {\n        loggers_.erase(default_logger_->name());\n    }\n    if (new_default_logger != nullptr)\n    {\n        loggers_[new_default_logger->name()] = new_default_logger;\n    }\n    default_logger_ = std::move(new_default_logger);\n}\n\nSPDLOG_INLINE void registry::set_tp(std::shared_ptr<thread_pool> tp)\n{\n    std::lock_guard<std::recursive_mutex> lock(tp_mutex_);\n    tp_ = std::move(tp);\n}\n\nSPDLOG_INLINE std::shared_ptr<thread_pool> registry::get_tp()\n{\n    std::lock_guard<std::recursive_mutex> lock(tp_mutex_);\n    return tp_;\n}\n\n// Set global formatter. Each sink in each logger will get a clone of this object\nSPDLOG_INLINE void registry::set_formatter(std::unique_ptr<formatter> formatter)\n{\n    std::lock_guard<std::mutex> lock(logger_map_mutex_);\n    formatter_ = std::move(formatter);\n    for (auto &l : loggers_)\n    {\n        l.second->set_formatter(formatter_->clone());\n    }\n}\n\nSPDLOG_INLINE void registry::set_level(level::level_enum log_level)\n{\n    std::lock_guard<std::mutex> lock(logger_map_mutex_);\n    for (auto &l : loggers_)\n    {\n        l.second->set_level(log_level);\n    }\n    level_ = log_level;\n}\n\nSPDLOG_INLINE void registry::flush_on(level::level_enum log_level)\n{\n    std::lock_guard<std::mutex> lock(logger_map_mutex_);\n    for (auto &l : loggers_)\n    {\n        l.second->flush_on(log_level);\n    }\n    flush_level_ = log_level;\n}\n\nSPDLOG_INLINE void registry::flush_every(std::chrono::seconds interval)\n{\n    std::lock_guard<std::mutex> lock(flusher_mutex_);\n    std::function<void()> clbk = std::bind(&registry::flush_all, this);\n    periodic_flusher_ = details::make_unique<periodic_worker>(clbk, interval);\n}\n\nSPDLOG_INLINE void registry::set_error_handler(void (*handler)(const std::string &msg))\n{\n    std::lock_guard<std::mutex> lock(logger_map_mutex_);\n    for (auto &l : loggers_)\n    {\n        l.second->set_error_handler(handler);\n    }\n    err_handler_ = handler;\n}\n\nSPDLOG_INLINE void registry::apply_all(const std::function<void(const std::shared_ptr<logger>)> &fun)\n{\n    std::lock_guard<std::mutex> lock(logger_map_mutex_);\n    for (auto &l : loggers_)\n    {\n        fun(l.second);\n    }\n}\n\nSPDLOG_INLINE void registry::flush_all()\n{\n    std::lock_guard<std::mutex> lock(logger_map_mutex_);\n    for (auto &l : loggers_)\n    {\n        l.second->flush();\n    }\n}\n\nSPDLOG_INLINE void registry::drop(const std::string &logger_name)\n{\n    std::lock_guard<std::mutex> lock(logger_map_mutex_);\n    loggers_.erase(logger_name);\n    if (default_logger_ && default_logger_->name() == logger_name)\n    {\n        default_logger_.reset();\n    }\n}\n\nSPDLOG_INLINE void registry::drop_all()\n{\n    std::lock_guard<std::mutex> lock(logger_map_mutex_);\n    loggers_.clear();\n    default_logger_.reset();\n}\n\n// clean all resources and threads started by the registry\nSPDLOG_INLINE void registry::shutdown()\n{\n    {\n        std::lock_guard<std::mutex> lock(flusher_mutex_);\n        periodic_flusher_.reset();\n    }\n\n    drop_all();\n\n    {\n        std::lock_guard<std::recursive_mutex> lock(tp_mutex_);\n        tp_.reset();\n    }\n}\n\nSPDLOG_INLINE std::recursive_mutex &registry::tp_mutex()\n{\n    return tp_mutex_;\n}\n\nSPDLOG_INLINE void registry::set_automatic_registration(bool automatic_regsistration)\n{\n    std::lock_guard<std::mutex> lock(logger_map_mutex_);\n    automatic_registration_ = automatic_regsistration;\n}\n\nSPDLOG_INLINE registry &registry::instance()\n{\n    static registry s_instance;\n    return s_instance;\n}\n\nSPDLOG_INLINE void registry::throw_if_exists_(const std::string &logger_name)\n{\n    if (loggers_.find(logger_name) != loggers_.end())\n    {\n        throw spdlog_ex(\"logger with name '\" + logger_name + \"' already exists\");\n    }\n}\n\nSPDLOG_INLINE void registry::register_logger_(std::shared_ptr<logger> new_logger)\n{\n    auto logger_name = new_logger->name();\n    throw_if_exists_(logger_name);\n    loggers_[logger_name] = std::move(new_logger);\n}\n} // namespace details\n} // namespace spdlog\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/details/registry.h",
    "content": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n#pragma once\n\n// Loggers registry of unique name->logger pointer\n// An attempt to create a logger with an already existing name will result with spdlog_ex exception.\n// If user requests a non existing logger, nullptr will be returned\n// This class is thread safe\n\n#include \"spdlog/common.h\"\n\n#include <chrono>\n#include <functional>\n#include <memory>\n#include <string>\n#include <unordered_map>\n#include <mutex>\n\nnamespace spdlog {\nclass logger;\n\nnamespace details {\nclass thread_pool;\nclass periodic_worker;\n\nclass registry\n{\npublic:\n    registry(const registry &) = delete;\n    registry &operator=(const registry &) = delete;\n\n    void register_logger(std::shared_ptr<logger> new_logger);\n    void initialize_logger(std::shared_ptr<logger> new_logger);\n    std::shared_ptr<logger> get(const std::string &logger_name);\n    std::shared_ptr<logger> default_logger();\n\n    // Return raw ptr to the default logger.\n    // To be used directly by the spdlog default api (e.g. spdlog::info)\n    // This make the default API faster, but cannot be used concurrently with set_default_logger().\n    // e.g do not call set_default_logger() from one thread while calling spdlog::info() from another.\n    logger *get_default_raw();\n\n    // set default logger.\n    // default logger is stored in default_logger_ (for faster retrieval) and in the loggers_ map.\n    void set_default_logger(std::shared_ptr<logger> new_default_logger);\n\n    void set_tp(std::shared_ptr<thread_pool> tp);\n\n    std::shared_ptr<thread_pool> get_tp();\n\n    // Set global formatter. Each sink in each logger will get a clone of this object\n    void set_formatter(std::unique_ptr<formatter> formatter);\n\n    void set_level(level::level_enum log_level);\n\n    void flush_on(level::level_enum log_level);\n\n    void flush_every(std::chrono::seconds interval);\n\n    void set_error_handler(void (*handler)(const std::string &msg));\n\n    void apply_all(const std::function<void(const std::shared_ptr<logger>)> &fun);\n\n    void flush_all();\n\n    void drop(const std::string &logger_name);\n\n    void drop_all();\n\n    // clean all resources and threads started by the registry\n    void shutdown();\n\n    std::recursive_mutex &tp_mutex();\n\n    void set_automatic_registration(bool automatic_regsistration);\n\n    static registry &instance();\n\nprivate:\n    registry();\n    ~registry() = default;\n\n    void throw_if_exists_(const std::string &logger_name);\n    void register_logger_(std::shared_ptr<logger> new_logger);\n    std::mutex logger_map_mutex_, flusher_mutex_;\n    std::recursive_mutex tp_mutex_;\n    std::unordered_map<std::string, std::shared_ptr<logger>> loggers_;\n    std::unique_ptr<formatter> formatter_;\n    level::level_enum level_ = level::info;\n    level::level_enum flush_level_ = level::off;\n    void (*err_handler_)(const std::string &msg);\n    std::shared_ptr<thread_pool> tp_;\n    std::unique_ptr<periodic_worker> periodic_flusher_;\n    std::shared_ptr<logger> default_logger_;\n    bool automatic_registration_ = true;\n};\n\n} // namespace details\n} // namespace spdlog\n\n#ifdef SPDLOG_HEADER_ONLY\n#include \"registry-inl.h\"\n#endif\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/details/synchronous_factory.h",
    "content": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n#pragma once\n\n#include \"registry.h\"\n\nnamespace spdlog {\n\n// Default logger factory-  creates synchronous loggers\nclass logger;\n\nstruct synchronous_factory\n{\n    template<typename Sink, typename... SinkArgs>\n    static std::shared_ptr<spdlog::logger> create(std::string logger_name, SinkArgs &&... args)\n    {\n        auto sink = std::make_shared<Sink>(std::forward<SinkArgs>(args)...);\n        auto new_logger = std::make_shared<spdlog::logger>(std::move(logger_name), std::move(sink));\n        details::registry::instance().initialize_logger(new_logger);\n        return new_logger;\n    }\n};\n} // namespace spdlog"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/details/thread_pool-inl.h",
    "content": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n#pragma once\n\n#ifndef SPDLOG_HEADER_ONLY\n#include \"spdlog/details/thread_pool.h\"\n#endif\n\n#include \"spdlog/common.h\"\n\nnamespace spdlog {\nnamespace details {\n\nSPDLOG_INLINE thread_pool::thread_pool(size_t q_max_items, size_t threads_n, std::function<void()> on_thread_start)\n    : q_(q_max_items)\n{\n    if (threads_n == 0 || threads_n > 1000)\n    {\n        throw spdlog_ex(\"spdlog::thread_pool(): invalid threads_n param (valid \"\n                        \"range is 1-1000)\");\n    }\n    for (size_t i = 0; i < threads_n; i++)\n    {\n        threads_.emplace_back([this, on_thread_start] {\n            on_thread_start();\n            this->thread_pool::worker_loop_();\n        });\n    }\n}\n\nSPDLOG_INLINE thread_pool::thread_pool(size_t q_max_items, size_t threads_n)\n    : thread_pool(q_max_items, threads_n, [] {})\n{}\n\n// message all threads to terminate gracefully join them\nSPDLOG_INLINE thread_pool::~thread_pool()\n{\n    try\n    {\n        for (size_t i = 0; i < threads_.size(); i++)\n        {\n            post_async_msg_(async_msg(async_msg_type::terminate), async_overflow_policy::block);\n        }\n\n        for (auto &t : threads_)\n        {\n            t.join();\n        }\n    }\n    catch (...)\n    {}\n}\n\nvoid SPDLOG_INLINE thread_pool::post_log(async_logger_ptr &&worker_ptr, details::log_msg &msg, async_overflow_policy overflow_policy)\n{\n    async_msg async_m(std::move(worker_ptr), async_msg_type::log, msg);\n    post_async_msg_(std::move(async_m), overflow_policy);\n}\n\nvoid SPDLOG_INLINE thread_pool::post_flush(async_logger_ptr &&worker_ptr, async_overflow_policy overflow_policy)\n{\n    post_async_msg_(async_msg(std::move(worker_ptr), async_msg_type::flush), overflow_policy);\n}\n\nsize_t SPDLOG_INLINE thread_pool::overrun_counter()\n{\n    return q_.overrun_counter();\n}\n\nvoid SPDLOG_INLINE thread_pool::post_async_msg_(async_msg &&new_msg, async_overflow_policy overflow_policy)\n{\n    if (overflow_policy == async_overflow_policy::block)\n    {\n        q_.enqueue(std::move(new_msg));\n    }\n    else\n    {\n        q_.enqueue_nowait(std::move(new_msg));\n    }\n}\n\nvoid SPDLOG_INLINE thread_pool::worker_loop_()\n{\n    while (process_next_msg_()) {};\n}\n\n// process next message in the queue\n// return true if this thread should still be active (while no terminate msg\n// was received)\nbool SPDLOG_INLINE thread_pool::process_next_msg_()\n{\n    async_msg incoming_async_msg;\n    bool dequeued = q_.dequeue_for(incoming_async_msg, std::chrono::seconds(10));\n    if (!dequeued)\n    {\n        return true;\n    }\n\n    switch (incoming_async_msg.msg_type)\n    {\n    case async_msg_type::log:\n    {\n        auto msg = incoming_async_msg.to_log_msg();\n        incoming_async_msg.worker_ptr->backend_log_(msg);\n        return true;\n    }\n    case async_msg_type::flush:\n    {\n        incoming_async_msg.worker_ptr->backend_flush_();\n        return true;\n    }\n\n    case async_msg_type::terminate:\n    {\n        return false;\n    }\n    }\n    assert(false && \"Unexpected async_msg_type\");\n    return true;\n}\n\n} // namespace details\n} // namespace spdlog\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/details/thread_pool.h",
    "content": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n#pragma once\n\n#include \"spdlog/details/log_msg.h\"\n#include \"spdlog/details/mpmc_blocking_q.h\"\n#include \"spdlog/details/os.h\"\n\n#include <chrono>\n#include <memory>\n#include <thread>\n#include <vector>\n#include <functional>\n\nnamespace spdlog {\nclass async_logger;\n\nnamespace details {\n\nusing async_logger_ptr = std::shared_ptr<spdlog::async_logger>;\n\nenum class async_msg_type\n{\n    log,\n    flush,\n    terminate\n};\n\n// Async msg to move to/from the queue\n// Movable only. should never be copied\nstruct async_msg\n{\n    async_msg_type msg_type;\n    level::level_enum level;\n    log_clock::time_point time;\n    size_t thread_id;\n    fmt::basic_memory_buffer<char, 176> raw;\n\n    source_loc source;\n    async_logger_ptr worker_ptr;\n\n    async_msg() = default;\n    ~async_msg() = default;\n\n    // should only be moved in or out of the queue..\n    async_msg(const async_msg &) = delete;\n\n// support for vs2013 move\n#if defined(_MSC_VER) && _MSC_VER <= 1800\n    async_msg(async_msg &&other) SPDLOG_NOEXCEPT : msg_type(other.msg_type),\n                                                   level(other.level),\n                                                   time(other.time),\n                                                   thread_id(other.thread_id),\n                                                   raw(move(other.raw)),\n                                                   msg_id(other.msg_id),\n                                                   source(other.source),\n                                                   worker_ptr(std::move(other.worker_ptr))\n    {}\n\n    async_msg &operator=(async_msg &&other) SPDLOG_NOEXCEPT\n    {\n        msg_type = other.msg_type;\n        level = other.level;\n        time = other.time;\n        thread_id = other.thread_id;\n        raw = std::move(other.raw);\n        msg_id = other.msg_id;\n        source = other.source;\n        worker_ptr = std::move(other.worker_ptr);\n        return *this;\n    }\n#else // (_MSC_VER) && _MSC_VER <= 1800\n    async_msg(async_msg &&) = default;\n    async_msg &operator=(async_msg &&) = default;\n#endif\n\n    // construct from log_msg with given type\n    async_msg(async_logger_ptr &&worker, async_msg_type the_type, details::log_msg &m)\n        : msg_type(the_type)\n        , level(m.level)\n        , time(m.time)\n        , thread_id(m.thread_id)\n        , source(m.source)\n        , worker_ptr(std::move(worker))\n    {\n        raw.append(m.payload.data(), m.payload.data() + m.payload.size());\n    }\n\n    async_msg(async_logger_ptr &&worker, async_msg_type the_type)\n        : msg_type(the_type)\n        , level(level::off)\n        , time()\n        , thread_id(0)\n        , source()\n        , worker_ptr(std::move(worker))\n    {}\n\n    explicit async_msg(async_msg_type the_type)\n        : async_msg(nullptr, the_type)\n    {}\n\n    // copy into log_msg\n    log_msg to_log_msg()\n    {\n        log_msg msg(string_view_t(worker_ptr->name()), level, string_view_t(raw.data(), raw.size()));\n        msg.time = time;\n        msg.thread_id = thread_id;\n        msg.source = source;\n        msg.color_range_start = 0;\n        msg.color_range_end = 0;\n        return msg;\n    }\n};\n\nclass thread_pool\n{\npublic:\n    using item_type = async_msg;\n    using q_type = details::mpmc_blocking_queue<item_type>;\n\n    thread_pool(size_t q_max_items, size_t threads_n, std::function<void()> on_thread_start);\n    thread_pool(size_t q_max_items, size_t threads_n);\n\n    // message all threads to terminate gracefully join them\n    ~thread_pool();\n\n    thread_pool(const thread_pool &) = delete;\n    thread_pool &operator=(thread_pool &&) = delete;\n\n    void post_log(async_logger_ptr &&worker_ptr, details::log_msg &msg, async_overflow_policy overflow_policy);\n    void post_flush(async_logger_ptr &&worker_ptr, async_overflow_policy overflow_policy);\n    size_t overrun_counter();\n\nprivate:\n    q_type q_;\n\n    std::vector<std::thread> threads_;\n\n    void post_async_msg_(async_msg &&new_msg, async_overflow_policy overflow_policy);\n    void worker_loop_();\n\n    // process next message in the queue\n    // return true if this thread should still be active (while no terminate msg\n    // was received)\n    bool process_next_msg_();\n};\n\n} // namespace details\n} // namespace spdlog\n\n#ifdef SPDLOG_HEADER_ONLY\n#include \"thread_pool-inl.h\"\n#endif"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/fmt/bin_to_hex.h",
    "content": "//\n// Copyright(c) 2015 Gabi Melman.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n//\n\n#pragma once\n\n//\n// Support for logging binary data as hex\n// format flags:\n// {:X} - print in uppercase.\n// {:s} - don't separate each byte with space.\n// {:p} - don't print the position on each line start.\n// {:n} - don't split the output to lines.\n\n//\n// Examples:\n//\n// std::vector<char> v(200, 0x0b);\n// logger->info(\"Some buffer {}\", spdlog::to_hex(v));\n// char buf[128];\n// logger->info(\"Some buffer {:X}\", spdlog::to_hex(std::begin(buf), std::end(buf)));\n\nnamespace spdlog {\nnamespace details {\n\ntemplate<typename It>\nclass bytes_range\n{\npublic:\n    bytes_range(It range_begin, It range_end)\n        : begin_(range_begin)\n        , end_(range_end)\n    {}\n\n    It begin() const\n    {\n        return begin_;\n    }\n    It end() const\n    {\n        return end_;\n    }\n\nprivate:\n    It begin_, end_;\n};\n} // namespace details\n\n// create a bytes_range that wraps the given container\ntemplate<typename Container>\ninline details::bytes_range<typename Container::const_iterator> to_hex(const Container &container)\n{\n    static_assert(sizeof(typename Container::value_type) == 1, \"sizeof(Container::value_type) != 1\");\n    using Iter = typename Container::const_iterator;\n    return details::bytes_range<Iter>(std::begin(container), std::end(container));\n}\n\n// create bytes_range from ranges\ntemplate<typename It>\ninline details::bytes_range<It> to_hex(const It range_begin, const It range_end)\n{\n    return details::bytes_range<It>(range_begin, range_end);\n}\n\n} // namespace spdlog\n\nnamespace fmt {\n\ntemplate<typename T>\nstruct formatter<spdlog::details::bytes_range<T>>\n{\n    const std::size_t line_size = 100;\n    const char delimiter = ' ';\n\n    bool put_newlines = true;\n    bool put_delimiters = true;\n    bool use_uppercase = false;\n    bool put_positions = true; // position on start of each line\n\n    // parse the format string flags\n    template<typename ParseContext>\n    auto parse(ParseContext &ctx) -> decltype(ctx.begin())\n    {\n        auto it = ctx.begin();\n        while (*it && *it != '}')\n        {\n            switch (*it)\n            {\n            case 'X':\n                use_uppercase = true;\n                break;\n            case 's':\n                put_delimiters = false;\n                break;\n            case 'p':\n                put_positions = false;\n                break;\n            case 'n':\n                put_newlines = false;\n                break;\n            }\n\n            ++it;\n        }\n        return it;\n    }\n\n    // format the given bytes range as hex\n    template<typename FormatContext, typename Container>\n    auto format(const spdlog::details::bytes_range<Container> &the_range, FormatContext &ctx) -> decltype(ctx.out())\n    {\n        SPDLOG_CONSTEXPR const char *hex_upper = \"0123456789ABCDEF\";\n        SPDLOG_CONSTEXPR const char *hex_lower = \"0123456789abcdef\";\n        const char *hex_chars = use_uppercase ? hex_upper : hex_lower;\n\n        std::size_t pos = 0;\n        std::size_t column = line_size;\n        auto inserter = ctx.begin();\n\n        for (auto &item : the_range)\n        {\n            auto ch = static_cast<unsigned char>(item);\n            pos++;\n\n            if (put_newlines && column >= line_size)\n            {\n                column = put_newline(inserter, pos);\n\n                // put first byte without delimiter in front of it\n                *inserter++ = hex_chars[(ch >> 4) & 0x0f];\n                *inserter++ = hex_chars[ch & 0x0f];\n                column += 2;\n                continue;\n            }\n\n            if (put_delimiters)\n            {\n                *inserter++ = delimiter;\n                ++column;\n            }\n\n            *inserter++ = hex_chars[(ch >> 4) & 0x0f];\n            *inserter++ = hex_chars[ch & 0x0f];\n            column += 2;\n        }\n        return inserter;\n    }\n\n    // put newline(and position header)\n    // return the next column\n    template<typename It>\n    std::size_t put_newline(It inserter, std::size_t pos)\n    {\n#ifdef _WIN32\n        *inserter++ = '\\r';\n#endif\n        *inserter++ = '\\n';\n\n        if (put_positions)\n        {\n            fmt::format_to(inserter, \"{:<04X}: \", pos - 1);\n            return 7;\n        }\n        else\n        {\n            return 1;\n        }\n    }\n};\n} // namespace fmt\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/fmt/bundled/LICENSE.rst",
    "content": "Copyright (c) 2012 - 2016, Victor Zverovich\n\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this\n   list of conditions and the following disclaimer.\n2. Redistributions in binary form must reproduce the above copyright notice,\n   this list of conditions and the following disclaimer in the documentation\n   and/or other materials provided with the distribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR\nANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\nON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/fmt/bundled/chrono.h",
    "content": "// Formatting library for C++ - chrono support\n//\n// Copyright (c) 2012 - present, Victor Zverovich\n// All rights reserved.\n//\n// For the license information refer to format.h.\n\n#ifndef FMT_CHRONO_H_\n#define FMT_CHRONO_H_\n\n#include \"format.h\"\n#include \"locale.h\"\n\n#include <chrono>\n#include <ctime>\n#include <locale>\n#include <sstream>\n\nFMT_BEGIN_NAMESPACE\n\nnamespace internal{\n\nenum class numeric_system {\n  standard,\n  // Alternative numeric system, e.g. 十二 instead of 12 in ja_JP locale.\n  alternative\n};\n\n// Parses a put_time-like format string and invokes handler actions.\ntemplate <typename Char, typename Handler>\nFMT_CONSTEXPR const Char *parse_chrono_format(\n    const Char *begin, const Char *end, Handler &&handler) {\n  auto ptr = begin;\n  while (ptr != end) {\n    auto c = *ptr;\n    if (c == '}') break;\n    if (c != '%') {\n      ++ptr;\n      continue;\n    }\n    if (begin != ptr)\n      handler.on_text(begin, ptr);\n    ++ptr; // consume '%'\n    if (ptr == end)\n      throw format_error(\"invalid format\");\n    c = *ptr++;\n    switch (c) {\n    case '%':\n      handler.on_text(ptr - 1, ptr);\n      break;\n    case 'n': {\n      const char newline[] = \"\\n\";\n      handler.on_text(newline, newline + 1);\n      break;\n    }\n    case 't': {\n      const char tab[] = \"\\t\";\n      handler.on_text(tab, tab + 1);\n      break;\n    }\n    // Day of the week:\n    case 'a':\n      handler.on_abbr_weekday();\n      break;\n    case 'A':\n      handler.on_full_weekday();\n      break;\n    case 'w':\n      handler.on_dec0_weekday(numeric_system::standard);\n      break;\n    case 'u':\n      handler.on_dec1_weekday(numeric_system::standard);\n      break;\n    // Month:\n    case 'b':\n      handler.on_abbr_month();\n      break;\n    case 'B':\n      handler.on_full_month();\n      break;\n    // Hour, minute, second:\n    case 'H':\n      handler.on_24_hour(numeric_system::standard);\n      break;\n    case 'I':\n      handler.on_12_hour(numeric_system::standard);\n      break;\n    case 'M':\n      handler.on_minute(numeric_system::standard);\n      break;\n    case 'S':\n      handler.on_second(numeric_system::standard);\n      break;\n    // Other:\n    case 'c':\n      handler.on_datetime(numeric_system::standard);\n      break;\n    case 'x':\n      handler.on_loc_date(numeric_system::standard);\n      break;\n    case 'X':\n      handler.on_loc_time(numeric_system::standard);\n      break;\n    case 'D':\n      handler.on_us_date();\n      break;\n    case 'F':\n      handler.on_iso_date();\n      break;\n    case 'r':\n      handler.on_12_hour_time();\n      break;\n    case 'R':\n      handler.on_24_hour_time();\n      break;\n    case 'T':\n      handler.on_iso_time();\n      break;\n    case 'p':\n      handler.on_am_pm();\n      break;\n    case 'z':\n      handler.on_utc_offset();\n      break;\n    case 'Z':\n      handler.on_tz_name();\n      break;\n    // Alternative representation:\n    case 'E': {\n      if (ptr == end)\n        throw format_error(\"invalid format\");\n      c = *ptr++;\n      switch (c) {\n      case 'c':\n        handler.on_datetime(numeric_system::alternative);\n        break;\n      case 'x':\n        handler.on_loc_date(numeric_system::alternative);\n        break;\n      case 'X':\n        handler.on_loc_time(numeric_system::alternative);\n        break;\n      default:\n        throw format_error(\"invalid format\");\n      }\n      break;\n    }\n    case 'O':\n      if (ptr == end)\n        throw format_error(\"invalid format\");\n      c = *ptr++;\n      switch (c) {\n      case 'w':\n        handler.on_dec0_weekday(numeric_system::alternative);\n        break;\n      case 'u':\n        handler.on_dec1_weekday(numeric_system::alternative);\n        break;\n      case 'H':\n        handler.on_24_hour(numeric_system::alternative);\n        break;\n      case 'I':\n        handler.on_12_hour(numeric_system::alternative);\n        break;\n      case 'M':\n        handler.on_minute(numeric_system::alternative);\n        break;\n      case 'S':\n        handler.on_second(numeric_system::alternative);\n        break;\n      default:\n        throw format_error(\"invalid format\");\n      }\n      break;\n    default:\n      throw format_error(\"invalid format\");\n    }\n    begin = ptr;\n  }\n  if (begin != ptr)\n    handler.on_text(begin, ptr);\n  return ptr;\n}\n\nstruct chrono_format_checker {\n  void report_no_date() { throw format_error(\"no date\"); }\n\n  template <typename Char>\n  void on_text(const Char *, const Char *) {}\n  void on_abbr_weekday() { report_no_date(); }\n  void on_full_weekday() { report_no_date(); }\n  void on_dec0_weekday(numeric_system) { report_no_date(); }\n  void on_dec1_weekday(numeric_system) { report_no_date(); }\n  void on_abbr_month() { report_no_date(); }\n  void on_full_month() { report_no_date(); }\n  void on_24_hour(numeric_system) {}\n  void on_12_hour(numeric_system) {}\n  void on_minute(numeric_system) {}\n  void on_second(numeric_system) {}\n  void on_datetime(numeric_system) { report_no_date(); }\n  void on_loc_date(numeric_system) { report_no_date(); }\n  void on_loc_time(numeric_system) { report_no_date(); }\n  void on_us_date() { report_no_date(); }\n  void on_iso_date() { report_no_date(); }\n  void on_12_hour_time() {}\n  void on_24_hour_time() {}\n  void on_iso_time() {}\n  void on_am_pm() {}\n  void on_utc_offset() { report_no_date(); }\n  void on_tz_name() { report_no_date(); }\n};\n\ntemplate <typename Int>\ninline int to_int(Int value) {\n  FMT_ASSERT(value >= (std::numeric_limits<int>::min)() &&\n             value <= (std::numeric_limits<int>::max)(), \"invalid value\");\n  return static_cast<int>(value);\n}\n\ntemplate <typename FormatContext, typename OutputIt>\nstruct chrono_formatter {\n  FormatContext &context;\n  OutputIt out;\n  std::chrono::seconds s;\n  std::chrono::milliseconds ms;\n\n  typedef typename FormatContext::char_type char_type;\n\n  explicit chrono_formatter(FormatContext &ctx, OutputIt o)\n    : context(ctx), out(o) {}\n\n  int hour() const { return to_int((s.count() / 3600) % 24); }\n\n  int hour12() const {\n    auto hour = to_int((s.count() / 3600) % 12);\n    return hour > 0 ? hour : 12;\n  }\n\n  int minute() const { return to_int((s.count() / 60) % 60); }\n  int second() const { return to_int(s.count() % 60); }\n\n  std::tm time() const {\n    auto time = std::tm();\n    time.tm_hour = hour();\n    time.tm_min = minute();\n    time.tm_sec = second();\n    return time;\n  }\n\n  void write(int value, int width) {\n    typedef typename int_traits<int>::main_type main_type;\n    main_type n = to_unsigned(value);\n    int num_digits = internal::count_digits(n);\n    if (width > num_digits)\n      out = std::fill_n(out, width - num_digits, '0');\n    out = format_decimal<char_type>(out, n, num_digits);\n  }\n\n  void format_localized(const tm &time, const char *format) {\n    auto locale = context.locale().template get<std::locale>();\n    auto &facet = std::use_facet<std::time_put<char_type>>(locale);\n    std::basic_ostringstream<char_type> os;\n    os.imbue(locale);\n    facet.put(os, os, ' ', &time, format, format + std::strlen(format));\n    auto str = os.str();\n    std::copy(str.begin(), str.end(), out);\n  }\n\n  void on_text(const char_type *begin, const char_type *end) {\n    std::copy(begin, end, out);\n  }\n\n  // These are not implemented because durations don't have date information.\n  void on_abbr_weekday() {}\n  void on_full_weekday() {}\n  void on_dec0_weekday(numeric_system) {}\n  void on_dec1_weekday(numeric_system) {}\n  void on_abbr_month() {}\n  void on_full_month() {}\n  void on_datetime(numeric_system) {}\n  void on_loc_date(numeric_system) {}\n  void on_loc_time(numeric_system) {}\n  void on_us_date() {}\n  void on_iso_date() {}\n  void on_utc_offset() {}\n  void on_tz_name() {}\n\n  void on_24_hour(numeric_system ns) {\n    if (ns == numeric_system::standard)\n      return write(hour(), 2);\n    auto time = tm();\n    time.tm_hour = hour();\n    format_localized(time, \"%OH\");\n  }\n\n  void on_12_hour(numeric_system ns) {\n    if (ns == numeric_system::standard)\n      return write(hour12(), 2);\n    auto time = tm();\n    time.tm_hour = hour();\n    format_localized(time, \"%OI\");\n  }\n\n  void on_minute(numeric_system ns) {\n    if (ns == numeric_system::standard)\n      return write(minute(), 2);\n    auto time = tm();\n    time.tm_min = minute();\n    format_localized(time, \"%OM\");\n  }\n\n  void on_second(numeric_system ns) {\n    if (ns == numeric_system::standard) {\n      write(second(), 2);\n      if (ms != std::chrono::milliseconds(0)) {\n        *out++ = '.';\n        write(to_int(ms.count()), 3);\n      }\n      return;\n    }\n    auto time = tm();\n    time.tm_sec = second();\n    format_localized(time, \"%OS\");\n  }\n\n  void on_12_hour_time() { format_localized(time(), \"%r\"); }\n\n  void on_24_hour_time() {\n    write(hour(), 2);\n    *out++ = ':';\n    write(minute(), 2);\n  }\n\n  void on_iso_time() {\n    on_24_hour_time();\n    *out++ = ':';\n    write(second(), 2);\n  }\n\n  void on_am_pm() { format_localized(time(), \"%p\"); }\n};\n}  // namespace internal\n\ntemplate <typename Period> FMT_CONSTEXPR const char *get_units() {\n  return FMT_NULL;\n}\ntemplate <> FMT_CONSTEXPR const char *get_units<std::atto>() { return \"as\"; }\ntemplate <> FMT_CONSTEXPR const char *get_units<std::femto>() { return \"fs\"; }\ntemplate <> FMT_CONSTEXPR const char *get_units<std::pico>() { return \"ps\"; }\ntemplate <> FMT_CONSTEXPR const char *get_units<std::nano>() { return \"ns\"; }\ntemplate <> FMT_CONSTEXPR const char *get_units<std::micro>() { return \"µs\"; }\ntemplate <> FMT_CONSTEXPR const char *get_units<std::milli>() { return \"ms\"; }\ntemplate <> FMT_CONSTEXPR const char *get_units<std::centi>() { return \"cs\"; }\ntemplate <> FMT_CONSTEXPR const char *get_units<std::deci>() { return \"ds\"; }\ntemplate <> FMT_CONSTEXPR const char *get_units<std::ratio<1>>() { return \"s\"; }\ntemplate <> FMT_CONSTEXPR const char *get_units<std::deca>() { return \"das\"; }\ntemplate <> FMT_CONSTEXPR const char *get_units<std::hecto>() { return \"hs\"; }\ntemplate <> FMT_CONSTEXPR const char *get_units<std::kilo>() { return \"ks\"; }\ntemplate <> FMT_CONSTEXPR const char *get_units<std::mega>() { return \"Ms\"; }\ntemplate <> FMT_CONSTEXPR const char *get_units<std::giga>() { return \"Gs\"; }\ntemplate <> FMT_CONSTEXPR const char *get_units<std::tera>() { return \"Ts\"; }\ntemplate <> FMT_CONSTEXPR const char *get_units<std::peta>() { return \"Ps\"; }\ntemplate <> FMT_CONSTEXPR const char *get_units<std::exa>() { return \"Es\"; }\ntemplate <> FMT_CONSTEXPR const char *get_units<std::ratio<60>>() {\n  return \"m\";\n}\ntemplate <> FMT_CONSTEXPR const char *get_units<std::ratio<3600>>() {\n  return \"h\";\n}\n\ntemplate <typename Rep, typename Period, typename Char>\nstruct formatter<std::chrono::duration<Rep, Period>, Char> {\n private:\n  align_spec spec;\n  internal::arg_ref<Char> width_ref;\n  mutable basic_string_view<Char> format_str;\n  typedef std::chrono::duration<Rep, Period> duration;\n\n  struct spec_handler {\n    formatter &f;\n    basic_parse_context<Char> &context;\n\n    typedef internal::arg_ref<Char> arg_ref_type;\n\n    template <typename Id>\n    FMT_CONSTEXPR arg_ref_type make_arg_ref(Id arg_id) {\n      context.check_arg_id(arg_id);\n      return arg_ref_type(arg_id);\n    }\n\n    FMT_CONSTEXPR arg_ref_type make_arg_ref(internal::auto_id) {\n      return arg_ref_type(context.next_arg_id());\n    }\n\n    void on_error(const char *msg) { throw format_error(msg); }\n    void on_fill(Char fill) { f.spec.fill_ = fill; }\n    void on_align(alignment align) { f.spec.align_ = align; }\n    void on_width(unsigned width) { f.spec.width_ = width; }\n\n    template <typename Id>\n    void on_dynamic_width(Id arg_id) {\n      f.width_ref = make_arg_ref(arg_id);\n    }\n  };\n\n public:\n  formatter() : spec() {}\n\n  FMT_CONSTEXPR auto parse(basic_parse_context<Char> &ctx)\n      -> decltype(ctx.begin()) {\n    auto begin = ctx.begin(), end = ctx.end();\n    if (begin == end) return begin;\n    spec_handler handler{*this, ctx};\n    begin = internal::parse_align(begin, end, handler);\n    if (begin == end) return begin;\n    begin = internal::parse_width(begin, end, handler);\n    end = parse_chrono_format(begin, end, internal::chrono_format_checker());\n    format_str = basic_string_view<Char>(&*begin, internal::to_unsigned(end - begin));\n    return end;\n  }\n\n  template <typename FormatContext>\n  auto format(const duration &d, FormatContext &ctx)\n      -> decltype(ctx.out()) {\n    auto begin = format_str.begin(), end = format_str.end();\n    memory_buffer buf;\n    typedef output_range<decltype(ctx.out()), Char> range;\n    basic_writer<range> w(range(ctx.out()));\n    if (begin == end || *begin == '}') {\n      if (const char *unit = get_units<Period>())\n        format_to(buf, \"{}{}\", d.count(), unit);\n      else if (Period::den == 1)\n        format_to(buf, \"{}[{}]s\", d.count(), Period::num);\n      else\n        format_to(buf, \"{}[{}/{}]s\", d.count(), Period::num, Period::den);\n      internal::handle_dynamic_spec<internal::width_checker>(\n        spec.width_, width_ref, ctx);\n    } else {\n      auto out = std::back_inserter(buf);\n      internal::chrono_formatter<FormatContext, decltype(out)> f(ctx, out);\n      f.s = std::chrono::duration_cast<std::chrono::seconds>(d);\n      f.ms = std::chrono::duration_cast<std::chrono::milliseconds>(d - f.s);\n      parse_chrono_format(begin, end, f);\n    }\n    w.write(buf.data(), buf.size(), spec);\n    return w.out();\n  }\n};\n\nFMT_END_NAMESPACE\n\n#endif  // FMT_CHRONO_H_\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/fmt/bundled/color.h",
    "content": "// Formatting library for C++ - color support\n//\n// Copyright (c) 2018 - present, Victor Zverovich and fmt contributors\n// All rights reserved.\n//\n// For the license information refer to format.h.\n\n#ifndef FMT_COLOR_H_\n#define FMT_COLOR_H_\n\n#include \"format.h\"\n\nFMT_BEGIN_NAMESPACE\n\n#ifdef FMT_DEPRECATED_COLORS\n\n// color and (v)print_colored are deprecated.\nenum color { black, red, green, yellow, blue, magenta, cyan, white };\nFMT_API void vprint_colored(color c, string_view format, format_args args);\nFMT_API void vprint_colored(color c, wstring_view format, wformat_args args);\ntemplate <typename... Args>\ninline void print_colored(color c, string_view format_str,\n                          const Args & ... args) {\n  vprint_colored(c, format_str, make_format_args(args...));\n}\ntemplate <typename... Args>\ninline void print_colored(color c, wstring_view format_str,\n                          const Args & ... args) {\n  vprint_colored(c, format_str, make_format_args<wformat_context>(args...));\n}\n\ninline void vprint_colored(color c, string_view format, format_args args) {\n  char escape[] = \"\\x1b[30m\";\n  escape[3] = static_cast<char>('0' + c);\n  std::fputs(escape, stdout);\n  vprint(format, args);\n  std::fputs(internal::data::RESET_COLOR, stdout);\n}\n\ninline void vprint_colored(color c, wstring_view format, wformat_args args) {\n  wchar_t escape[] = L\"\\x1b[30m\";\n  escape[3] = static_cast<wchar_t>('0' + c);\n  std::fputws(escape, stdout);\n  vprint(format, args);\n  std::fputws(internal::data::WRESET_COLOR, stdout);\n}\n\n#else\n\nenum class color : uint32_t {\n  alice_blue              = 0xF0F8FF, // rgb(240,248,255)\n  antique_white           = 0xFAEBD7, // rgb(250,235,215)\n  aqua                    = 0x00FFFF, // rgb(0,255,255)\n  aquamarine              = 0x7FFFD4, // rgb(127,255,212)\n  azure                   = 0xF0FFFF, // rgb(240,255,255)\n  beige                   = 0xF5F5DC, // rgb(245,245,220)\n  bisque                  = 0xFFE4C4, // rgb(255,228,196)\n  black                   = 0x000000, // rgb(0,0,0)\n  blanched_almond         = 0xFFEBCD, // rgb(255,235,205)\n  blue                    = 0x0000FF, // rgb(0,0,255)\n  blue_violet             = 0x8A2BE2, // rgb(138,43,226)\n  brown                   = 0xA52A2A, // rgb(165,42,42)\n  burly_wood              = 0xDEB887, // rgb(222,184,135)\n  cadet_blue              = 0x5F9EA0, // rgb(95,158,160)\n  chartreuse              = 0x7FFF00, // rgb(127,255,0)\n  chocolate               = 0xD2691E, // rgb(210,105,30)\n  coral                   = 0xFF7F50, // rgb(255,127,80)\n  cornflower_blue         = 0x6495ED, // rgb(100,149,237)\n  cornsilk                = 0xFFF8DC, // rgb(255,248,220)\n  crimson                 = 0xDC143C, // rgb(220,20,60)\n  cyan                    = 0x00FFFF, // rgb(0,255,255)\n  dark_blue               = 0x00008B, // rgb(0,0,139)\n  dark_cyan               = 0x008B8B, // rgb(0,139,139)\n  dark_golden_rod         = 0xB8860B, // rgb(184,134,11)\n  dark_gray               = 0xA9A9A9, // rgb(169,169,169)\n  dark_green              = 0x006400, // rgb(0,100,0)\n  dark_khaki              = 0xBDB76B, // rgb(189,183,107)\n  dark_magenta            = 0x8B008B, // rgb(139,0,139)\n  dark_olive_green        = 0x556B2F, // rgb(85,107,47)\n  dark_orange             = 0xFF8C00, // rgb(255,140,0)\n  dark_orchid             = 0x9932CC, // rgb(153,50,204)\n  dark_red                = 0x8B0000, // rgb(139,0,0)\n  dark_salmon             = 0xE9967A, // rgb(233,150,122)\n  dark_sea_green          = 0x8FBC8F, // rgb(143,188,143)\n  dark_slate_blue         = 0x483D8B, // rgb(72,61,139)\n  dark_slate_gray         = 0x2F4F4F, // rgb(47,79,79)\n  dark_turquoise          = 0x00CED1, // rgb(0,206,209)\n  dark_violet             = 0x9400D3, // rgb(148,0,211)\n  deep_pink               = 0xFF1493, // rgb(255,20,147)\n  deep_sky_blue           = 0x00BFFF, // rgb(0,191,255)\n  dim_gray                = 0x696969, // rgb(105,105,105)\n  dodger_blue             = 0x1E90FF, // rgb(30,144,255)\n  fire_brick              = 0xB22222, // rgb(178,34,34)\n  floral_white            = 0xFFFAF0, // rgb(255,250,240)\n  forest_green            = 0x228B22, // rgb(34,139,34)\n  fuchsia                 = 0xFF00FF, // rgb(255,0,255)\n  gainsboro               = 0xDCDCDC, // rgb(220,220,220)\n  ghost_white             = 0xF8F8FF, // rgb(248,248,255)\n  gold                    = 0xFFD700, // rgb(255,215,0)\n  golden_rod              = 0xDAA520, // rgb(218,165,32)\n  gray                    = 0x808080, // rgb(128,128,128)\n  green                   = 0x008000, // rgb(0,128,0)\n  green_yellow            = 0xADFF2F, // rgb(173,255,47)\n  honey_dew               = 0xF0FFF0, // rgb(240,255,240)\n  hot_pink                = 0xFF69B4, // rgb(255,105,180)\n  indian_red              = 0xCD5C5C, // rgb(205,92,92)\n  indigo                  = 0x4B0082, // rgb(75,0,130)\n  ivory                   = 0xFFFFF0, // rgb(255,255,240)\n  khaki                   = 0xF0E68C, // rgb(240,230,140)\n  lavender                = 0xE6E6FA, // rgb(230,230,250)\n  lavender_blush          = 0xFFF0F5, // rgb(255,240,245)\n  lawn_green              = 0x7CFC00, // rgb(124,252,0)\n  lemon_chiffon           = 0xFFFACD, // rgb(255,250,205)\n  light_blue              = 0xADD8E6, // rgb(173,216,230)\n  light_coral             = 0xF08080, // rgb(240,128,128)\n  light_cyan              = 0xE0FFFF, // rgb(224,255,255)\n  light_golden_rod_yellow = 0xFAFAD2, // rgb(250,250,210)\n  light_gray              = 0xD3D3D3, // rgb(211,211,211)\n  light_green             = 0x90EE90, // rgb(144,238,144)\n  light_pink              = 0xFFB6C1, // rgb(255,182,193)\n  light_salmon            = 0xFFA07A, // rgb(255,160,122)\n  light_sea_green         = 0x20B2AA, // rgb(32,178,170)\n  light_sky_blue          = 0x87CEFA, // rgb(135,206,250)\n  light_slate_gray        = 0x778899, // rgb(119,136,153)\n  light_steel_blue        = 0xB0C4DE, // rgb(176,196,222)\n  light_yellow            = 0xFFFFE0, // rgb(255,255,224)\n  lime                    = 0x00FF00, // rgb(0,255,0)\n  lime_green              = 0x32CD32, // rgb(50,205,50)\n  linen                   = 0xFAF0E6, // rgb(250,240,230)\n  magenta                 = 0xFF00FF, // rgb(255,0,255)\n  maroon                  = 0x800000, // rgb(128,0,0)\n  medium_aquamarine       = 0x66CDAA, // rgb(102,205,170)\n  medium_blue             = 0x0000CD, // rgb(0,0,205)\n  medium_orchid           = 0xBA55D3, // rgb(186,85,211)\n  medium_purple           = 0x9370DB, // rgb(147,112,219)\n  medium_sea_green        = 0x3CB371, // rgb(60,179,113)\n  medium_slate_blue       = 0x7B68EE, // rgb(123,104,238)\n  medium_spring_green     = 0x00FA9A, // rgb(0,250,154)\n  medium_turquoise        = 0x48D1CC, // rgb(72,209,204)\n  medium_violet_red       = 0xC71585, // rgb(199,21,133)\n  midnight_blue           = 0x191970, // rgb(25,25,112)\n  mint_cream              = 0xF5FFFA, // rgb(245,255,250)\n  misty_rose              = 0xFFE4E1, // rgb(255,228,225)\n  moccasin                = 0xFFE4B5, // rgb(255,228,181)\n  navajo_white            = 0xFFDEAD, // rgb(255,222,173)\n  navy                    = 0x000080, // rgb(0,0,128)\n  old_lace                = 0xFDF5E6, // rgb(253,245,230)\n  olive                   = 0x808000, // rgb(128,128,0)\n  olive_drab              = 0x6B8E23, // rgb(107,142,35)\n  orange                  = 0xFFA500, // rgb(255,165,0)\n  orange_red              = 0xFF4500, // rgb(255,69,0)\n  orchid                  = 0xDA70D6, // rgb(218,112,214)\n  pale_golden_rod         = 0xEEE8AA, // rgb(238,232,170)\n  pale_green              = 0x98FB98, // rgb(152,251,152)\n  pale_turquoise          = 0xAFEEEE, // rgb(175,238,238)\n  pale_violet_red         = 0xDB7093, // rgb(219,112,147)\n  papaya_whip             = 0xFFEFD5, // rgb(255,239,213)\n  peach_puff              = 0xFFDAB9, // rgb(255,218,185)\n  peru                    = 0xCD853F, // rgb(205,133,63)\n  pink                    = 0xFFC0CB, // rgb(255,192,203)\n  plum                    = 0xDDA0DD, // rgb(221,160,221)\n  powder_blue             = 0xB0E0E6, // rgb(176,224,230)\n  purple                  = 0x800080, // rgb(128,0,128)\n  rebecca_purple          = 0x663399, // rgb(102,51,153)\n  red                     = 0xFF0000, // rgb(255,0,0)\n  rosy_brown              = 0xBC8F8F, // rgb(188,143,143)\n  royal_blue              = 0x4169E1, // rgb(65,105,225)\n  saddle_brown            = 0x8B4513, // rgb(139,69,19)\n  salmon                  = 0xFA8072, // rgb(250,128,114)\n  sandy_brown             = 0xF4A460, // rgb(244,164,96)\n  sea_green               = 0x2E8B57, // rgb(46,139,87)\n  sea_shell               = 0xFFF5EE, // rgb(255,245,238)\n  sienna                  = 0xA0522D, // rgb(160,82,45)\n  silver                  = 0xC0C0C0, // rgb(192,192,192)\n  sky_blue                = 0x87CEEB, // rgb(135,206,235)\n  slate_blue              = 0x6A5ACD, // rgb(106,90,205)\n  slate_gray              = 0x708090, // rgb(112,128,144)\n  snow                    = 0xFFFAFA, // rgb(255,250,250)\n  spring_green            = 0x00FF7F, // rgb(0,255,127)\n  steel_blue              = 0x4682B4, // rgb(70,130,180)\n  tan                     = 0xD2B48C, // rgb(210,180,140)\n  teal                    = 0x008080, // rgb(0,128,128)\n  thistle                 = 0xD8BFD8, // rgb(216,191,216)\n  tomato                  = 0xFF6347, // rgb(255,99,71)\n  turquoise               = 0x40E0D0, // rgb(64,224,208)\n  violet                  = 0xEE82EE, // rgb(238,130,238)\n  wheat                   = 0xF5DEB3, // rgb(245,222,179)\n  white                   = 0xFFFFFF, // rgb(255,255,255)\n  white_smoke             = 0xF5F5F5, // rgb(245,245,245)\n  yellow                  = 0xFFFF00, // rgb(255,255,0)\n  yellow_green            = 0x9ACD32  // rgb(154,205,50)\n};  // enum class color\n\nenum class terminal_color : uint8_t {\n  black = 30,\n  red,\n  green,\n  yellow,\n  blue,\n  magenta,\n  cyan,\n  white,\n  bright_black = 90,\n  bright_red,\n  bright_green,\n  bright_yellow,\n  bright_blue,\n  bright_magenta,\n  bright_cyan,\n  bright_white\n};  // enum class terminal_color\n\nenum class emphasis : uint8_t {\n  bold = 1,\n  italic = 1 << 1,\n  underline = 1 << 2,\n  strikethrough = 1 << 3\n};  // enum class emphasis\n\n// rgb is a struct for red, green and blue colors.\n// We use rgb as name because some editors will show it as color direct in the\n// editor.\nstruct rgb {\n  FMT_CONSTEXPR_DECL rgb() : r(0), g(0), b(0) {}\n  FMT_CONSTEXPR_DECL rgb(uint8_t r_, uint8_t g_, uint8_t b_)\n    : r(r_), g(g_), b(b_) {}\n  FMT_CONSTEXPR_DECL rgb(uint32_t hex)\n    : r((hex >> 16) & 0xFF), g((hex >> 8) & 0xFF), b((hex) & 0xFF) {}\n  FMT_CONSTEXPR_DECL rgb(color hex)\n    : r((uint32_t(hex) >> 16) & 0xFF), g((uint32_t(hex) >> 8) & 0xFF),\n      b(uint32_t(hex) & 0xFF) {}\n  uint8_t r;\n  uint8_t g;\n  uint8_t b;\n};\n\nnamespace internal {\n\n// color is a struct of either a rgb color or a terminal color.\nstruct color_type {\n  FMT_CONSTEXPR color_type() FMT_NOEXCEPT\n    : is_rgb(), value{} {}\n  FMT_CONSTEXPR color_type(color rgb_color) FMT_NOEXCEPT\n    : is_rgb(true), value{} {\n    value.rgb_color = static_cast<uint32_t>(rgb_color);\n  }\n  FMT_CONSTEXPR color_type(rgb rgb_color) FMT_NOEXCEPT\n    : is_rgb(true), value{} {\n    value.rgb_color = (static_cast<uint32_t>(rgb_color.r) << 16)\n       | (static_cast<uint32_t>(rgb_color.g) << 8) | rgb_color.b;\n  }\n  FMT_CONSTEXPR color_type(terminal_color term_color) FMT_NOEXCEPT\n    : is_rgb(), value{} {\n    value.term_color = static_cast<uint8_t>(term_color);\n  }\n  bool is_rgb;\n  union color_union {\n    uint8_t term_color;\n    uint32_t rgb_color;\n  } value;\n};\n} // namespace internal\n\n// Experimental text formatting support.\nclass text_style {\n public:\n  FMT_CONSTEXPR text_style(emphasis em = emphasis()) FMT_NOEXCEPT\n      : set_foreground_color(), set_background_color(), ems(em) {}\n\n  FMT_CONSTEXPR text_style &operator|=(const text_style &rhs) {\n    if (!set_foreground_color) {\n      set_foreground_color = rhs.set_foreground_color;\n      foreground_color = rhs.foreground_color;\n    } else if (rhs.set_foreground_color) {\n      if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb)\n        throw format_error(\"can't OR a terminal color\");\n      foreground_color.value.rgb_color |= rhs.foreground_color.value.rgb_color;\n    }\n\n    if (!set_background_color) {\n      set_background_color = rhs.set_background_color;\n      background_color = rhs.background_color;\n    } else if (rhs.set_background_color) {\n      if (!background_color.is_rgb || !rhs.background_color.is_rgb)\n        throw format_error(\"can't OR a terminal color\");\n      background_color.value.rgb_color |= rhs.background_color.value.rgb_color;\n    }\n\n    ems = static_cast<emphasis>(static_cast<uint8_t>(ems) |\n                                static_cast<uint8_t>(rhs.ems));\n    return *this;\n  }\n\n  friend FMT_CONSTEXPR\n  text_style operator|(text_style lhs, const text_style &rhs) {\n    return lhs |= rhs;\n  }\n\n  FMT_CONSTEXPR text_style &operator&=(const text_style &rhs) {\n    if (!set_foreground_color) {\n      set_foreground_color = rhs.set_foreground_color;\n      foreground_color = rhs.foreground_color;\n    } else if (rhs.set_foreground_color) {\n      if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb)\n        throw format_error(\"can't AND a terminal color\");\n      foreground_color.value.rgb_color &= rhs.foreground_color.value.rgb_color;\n    }\n\n    if (!set_background_color) {\n      set_background_color = rhs.set_background_color;\n      background_color = rhs.background_color;\n    } else if (rhs.set_background_color) {\n      if (!background_color.is_rgb || !rhs.background_color.is_rgb)\n        throw format_error(\"can't AND a terminal color\");\n      background_color.value.rgb_color &= rhs.background_color.value.rgb_color;\n    }\n\n    ems = static_cast<emphasis>(static_cast<uint8_t>(ems) &\n                                static_cast<uint8_t>(rhs.ems));\n    return *this;\n  }\n\n  friend FMT_CONSTEXPR\n  text_style operator&(text_style lhs, const text_style &rhs) {\n    return lhs &= rhs;\n  }\n\n  FMT_CONSTEXPR bool has_foreground() const FMT_NOEXCEPT {\n    return set_foreground_color;\n  }\n  FMT_CONSTEXPR bool has_background() const FMT_NOEXCEPT {\n    return set_background_color;\n  }\n  FMT_CONSTEXPR bool has_emphasis() const FMT_NOEXCEPT {\n    return static_cast<uint8_t>(ems) != 0;\n  }\n  FMT_CONSTEXPR internal::color_type get_foreground() const FMT_NOEXCEPT {\n    assert(has_foreground() && \"no foreground specified for this style\");\n    return foreground_color;\n  }\n  FMT_CONSTEXPR internal::color_type get_background() const FMT_NOEXCEPT {\n    assert(has_background() && \"no background specified for this style\");\n    return background_color;\n  }\n  FMT_CONSTEXPR emphasis get_emphasis() const FMT_NOEXCEPT {\n    assert(has_emphasis() && \"no emphasis specified for this style\");\n    return ems;\n  }\n\nprivate:\n FMT_CONSTEXPR text_style(bool is_foreground,\n                          internal::color_type text_color) FMT_NOEXCEPT\n     : set_foreground_color(),\n       set_background_color(),\n       ems() {\n   if (is_foreground) {\n     foreground_color = text_color;\n     set_foreground_color = true;\n   } else {\n     background_color = text_color;\n     set_background_color = true;\n   }\n }\n\n  friend FMT_CONSTEXPR_DECL text_style fg(internal::color_type foreground)\n      FMT_NOEXCEPT;\n  friend FMT_CONSTEXPR_DECL text_style bg(internal::color_type background)\n      FMT_NOEXCEPT;\n\n  internal::color_type foreground_color;\n  internal::color_type background_color;\n  bool set_foreground_color;\n  bool set_background_color;\n  emphasis ems;\n};\n\nFMT_CONSTEXPR text_style fg(internal::color_type foreground) FMT_NOEXCEPT {\n  return text_style(/*is_foreground=*/true, foreground);\n}\n\nFMT_CONSTEXPR text_style bg(internal::color_type background) FMT_NOEXCEPT {\n  return text_style(/*is_foreground=*/false, background);\n}\n\nFMT_CONSTEXPR text_style operator|(emphasis lhs, emphasis rhs) FMT_NOEXCEPT {\n  return text_style(lhs) | rhs;\n}\n\nnamespace internal {\n\ntemplate <typename Char>\nstruct ansi_color_escape {\n  FMT_CONSTEXPR ansi_color_escape(internal::color_type text_color,\n                                  const char * esc) FMT_NOEXCEPT {\n    // If we have a terminal color, we need to output another escape code\n    // sequence.\n    if (!text_color.is_rgb) {\n      bool is_background = esc == internal::data::BACKGROUND_COLOR;\n      uint32_t value = text_color.value.term_color;\n      // Background ASCII codes are the same as the foreground ones but with\n      // 10 more.\n      if (is_background)\n        value += 10u;\n\n      std::size_t index = 0;\n      buffer[index++] = static_cast<Char>('\\x1b');\n      buffer[index++] = static_cast<Char>('[');\n\n      if (value >= 100u) {\n        buffer[index++] = static_cast<Char>('1');\n        value %= 100u;\n      }\n      buffer[index++] = static_cast<Char>('0' + value / 10u);\n      buffer[index++] = static_cast<Char>('0' + value % 10u);\n\n      buffer[index++] = static_cast<Char>('m');\n      buffer[index++] = static_cast<Char>('\\0');\n      return;\n    }\n\n    for (int i = 0; i < 7; i++) {\n      buffer[i] = static_cast<Char>(esc[i]);\n    }\n    rgb color(text_color.value.rgb_color);\n    to_esc(color.r, buffer +  7, ';');\n    to_esc(color.g, buffer + 11, ';');\n    to_esc(color.b, buffer + 15, 'm');\n    buffer[19] = static_cast<Char>(0);\n  }\n  FMT_CONSTEXPR ansi_color_escape(emphasis em) FMT_NOEXCEPT {\n    uint8_t em_codes[4] = {};\n    uint8_t em_bits = static_cast<uint8_t>(em);\n    if (em_bits & static_cast<uint8_t>(emphasis::bold))\n      em_codes[0] = 1;\n    if (em_bits & static_cast<uint8_t>(emphasis::italic))\n      em_codes[1] = 3;\n    if (em_bits & static_cast<uint8_t>(emphasis::underline))\n      em_codes[2] = 4;\n    if (em_bits & static_cast<uint8_t>(emphasis::strikethrough))\n      em_codes[3] = 9;\n\n    std::size_t index = 0;\n    for (int i = 0; i < 4; ++i) {\n      if (!em_codes[i])\n        continue;\n      buffer[index++] = static_cast<Char>('\\x1b');\n      buffer[index++] = static_cast<Char>('[');\n      buffer[index++] = static_cast<Char>('0' + em_codes[i]);\n      buffer[index++] = static_cast<Char>('m');\n    }\n    buffer[index++] = static_cast<Char>(0);\n  }\n  FMT_CONSTEXPR operator const Char *() const FMT_NOEXCEPT { return buffer; }\n\nprivate:\n  Char buffer[7u + 3u * 4u + 1u];\n\n  static FMT_CONSTEXPR void to_esc(uint8_t c, Char *out,\n                                   char delimiter) FMT_NOEXCEPT {\n    out[0] = static_cast<Char>('0' + c / 100);\n    out[1] = static_cast<Char>('0' + c / 10 % 10);\n    out[2] = static_cast<Char>('0' + c % 10);\n    out[3] = static_cast<Char>(delimiter);\n  }\n};\n\ntemplate <typename Char>\nFMT_CONSTEXPR ansi_color_escape<Char>\nmake_foreground_color(internal::color_type foreground) FMT_NOEXCEPT {\n  return ansi_color_escape<Char>(foreground, internal::data::FOREGROUND_COLOR);\n}\n\ntemplate <typename Char>\nFMT_CONSTEXPR ansi_color_escape<Char>\nmake_background_color(internal::color_type background) FMT_NOEXCEPT {\n  return ansi_color_escape<Char>(background, internal::data::BACKGROUND_COLOR);\n}\n\ntemplate <typename Char>\nFMT_CONSTEXPR ansi_color_escape<Char>\nmake_emphasis(emphasis em) FMT_NOEXCEPT {\n  return ansi_color_escape<Char>(em);\n}\n\ntemplate <typename Char>\ninline void fputs(const Char *chars, FILE *stream) FMT_NOEXCEPT {\n  std::fputs(chars, stream);\n}\n\ntemplate <>\ninline void fputs<wchar_t>(const wchar_t *chars, FILE *stream) FMT_NOEXCEPT {\n  std::fputws(chars, stream);\n}\n\ntemplate <typename Char>\ninline void reset_color(FILE *stream) FMT_NOEXCEPT {\n  fputs(internal::data::RESET_COLOR, stream);\n}\n\ntemplate <>\ninline void reset_color<wchar_t>(FILE *stream) FMT_NOEXCEPT {\n  fputs(internal::data::WRESET_COLOR, stream);\n}\n\n// The following specialiazation disables using std::FILE as a character type,\n// which is needed because or else\n//   fmt::print(stderr, fmt::emphasis::bold, \"\");\n// would take stderr (a std::FILE *) as the format string.\ntemplate <>\nstruct is_string<std::FILE *> : std::false_type {};\ntemplate <>\nstruct is_string<const std::FILE *> : std::false_type {};\n} // namespace internal\n\ntemplate <\n  typename S, typename Char = typename internal::char_t<S>::type>\nvoid vprint(std::FILE *f, const text_style &ts, const S &format,\n            basic_format_args<typename buffer_context<Char>::type> args) {\n  bool has_style = false;\n  if (ts.has_emphasis()) {\n    has_style = true;\n    internal::fputs<Char>(\n          internal::make_emphasis<Char>(ts.get_emphasis()), f);\n  }\n  if (ts.has_foreground()) {\n    has_style = true;\n    internal::fputs<Char>(\n          internal::make_foreground_color<Char>(ts.get_foreground()), f);\n  }\n  if (ts.has_background()) {\n    has_style = true;\n    internal::fputs<Char>(\n        internal::make_background_color<Char>(ts.get_background()), f);\n  }\n  vprint(f, format, args);\n  if (has_style) {\n    internal::reset_color<Char>(f);\n  }\n}\n\n/**\n  Formats a string and prints it to the specified file stream using ANSI\n  escape sequences to specify text formatting.\n  Example:\n    fmt::print(fmt::emphasis::bold | fg(fmt::color::red),\n               \"Elapsed time: {0:.2f} seconds\", 1.23);\n */\ntemplate <typename String, typename... Args>\ntypename std::enable_if<internal::is_string<String>::value>::type print(\n    std::FILE *f, const text_style &ts, const String &format_str,\n    const Args &... args) {\n  internal::check_format_string<Args...>(format_str);\n  typedef typename internal::char_t<String>::type char_t;\n  typedef typename buffer_context<char_t>::type context_t;\n  format_arg_store<context_t, Args...> as{args...};\n  vprint(f, ts, format_str, basic_format_args<context_t>(as));\n}\n\n/**\n  Formats a string and prints it to stdout using ANSI escape sequences to\n  specify text formatting.\n  Example:\n    fmt::print(fmt::emphasis::bold | fg(fmt::color::red),\n               \"Elapsed time: {0:.2f} seconds\", 1.23);\n */\ntemplate <typename String, typename... Args>\ntypename std::enable_if<internal::is_string<String>::value>::type print(\n    const text_style &ts, const String &format_str,\n    const Args &... args) {\n  return print(stdout, ts, format_str, args...);\n}\n\n#endif\n\nFMT_END_NAMESPACE\n\n#endif  // FMT_COLOR_H_\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/fmt/bundled/core.h",
    "content": "// Formatting library for C++ - the core API\n//\n// Copyright (c) 2012 - present, Victor Zverovich\n// All rights reserved.\n//\n// For the license information refer to format.h.\n\n#ifndef FMT_CORE_H_\n#define FMT_CORE_H_\n\n#include <cassert>\n#include <cstdio>  // std::FILE\n#include <cstring>\n#include <iterator>\n#include <string>\n#include <type_traits>\n\n// The fmt library version in the form major * 10000 + minor * 100 + patch.\n#define FMT_VERSION 50300\n\n#ifdef __has_feature\n# define FMT_HAS_FEATURE(x) __has_feature(x)\n#else\n# define FMT_HAS_FEATURE(x) 0\n#endif\n\n#if defined(__has_include) && !defined(__INTELLISENSE__) && \\\n    !(defined(__INTEL_COMPILER) && __INTEL_COMPILER < 1600)\n# define FMT_HAS_INCLUDE(x) __has_include(x)\n#else\n# define FMT_HAS_INCLUDE(x) 0\n#endif\n\n#ifdef __has_cpp_attribute\n# define FMT_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)\n#else\n# define FMT_HAS_CPP_ATTRIBUTE(x) 0\n#endif\n\n#if defined(__GNUC__) && !defined(__clang__)\n# define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)\n#else\n# define FMT_GCC_VERSION 0\n#endif\n\n#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)\n# define FMT_HAS_GXX_CXX11 FMT_GCC_VERSION\n#else\n# define FMT_HAS_GXX_CXX11 0\n#endif\n\n#ifdef _MSC_VER\n# define FMT_MSC_VER _MSC_VER\n#else\n# define FMT_MSC_VER 0\n#endif\n\n// Check if relaxed C++14 constexpr is supported.\n// GCC doesn't allow throw in constexpr until version 6 (bug 67371).\n#ifndef FMT_USE_CONSTEXPR\n# define FMT_USE_CONSTEXPR \\\n  (FMT_HAS_FEATURE(cxx_relaxed_constexpr) || FMT_MSC_VER >= 1910 || \\\n   (FMT_GCC_VERSION >= 600 && __cplusplus >= 201402L))\n#endif\n#if FMT_USE_CONSTEXPR\n# define FMT_CONSTEXPR constexpr\n# define FMT_CONSTEXPR_DECL constexpr\n#else\n# define FMT_CONSTEXPR inline\n# define FMT_CONSTEXPR_DECL\n#endif\n\n#ifndef FMT_USE_CONSTEXPR11\n# define FMT_USE_CONSTEXPR11 \\\n    (FMT_USE_CONSTEXPR || FMT_GCC_VERSION >= 406 || FMT_MSC_VER >= 1900)\n#endif\n#if FMT_USE_CONSTEXPR11\n# define FMT_CONSTEXPR11 constexpr\n#else\n# define FMT_CONSTEXPR11\n#endif\n\n#ifndef FMT_OVERRIDE\n# if FMT_HAS_FEATURE(cxx_override) || \\\n     (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900\n#  define FMT_OVERRIDE override\n# else\n#  define FMT_OVERRIDE\n# endif\n#endif\n\n#if FMT_HAS_FEATURE(cxx_explicit_conversions) || \\\n    FMT_GCC_VERSION >= 405 || FMT_MSC_VER >= 1800\n# define FMT_USE_EXPLICIT 1\n# define FMT_EXPLICIT explicit\n#else\n# define FMT_USE_EXPLICIT 0\n# define FMT_EXPLICIT\n#endif\n\n#ifndef FMT_NULL\n# if FMT_HAS_FEATURE(cxx_nullptr) || \\\n   (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1600\n#  define FMT_NULL nullptr\n#  define FMT_USE_NULLPTR 1\n# else\n#  define FMT_NULL NULL\n# endif\n#endif\n#ifndef FMT_USE_NULLPTR\n# define FMT_USE_NULLPTR 0\n#endif\n\n// Check if exceptions are disabled.\n#ifndef FMT_EXCEPTIONS\n# if (defined(__GNUC__) && !defined(__EXCEPTIONS)) || \\\n     FMT_MSC_VER && !_HAS_EXCEPTIONS\n#  define FMT_EXCEPTIONS 0\n# else\n#  define FMT_EXCEPTIONS 1\n# endif\n#endif\n\n// Define FMT_USE_NOEXCEPT to make fmt use noexcept (C++11 feature).\n#ifndef FMT_USE_NOEXCEPT\n# define FMT_USE_NOEXCEPT 0\n#endif\n\n#if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \\\n    (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900\n# define FMT_DETECTED_NOEXCEPT noexcept\n# define FMT_HAS_CXX11_NOEXCEPT 1\n#else\n# define FMT_DETECTED_NOEXCEPT throw()\n# define FMT_HAS_CXX11_NOEXCEPT 0\n#endif\n\n#ifndef FMT_NOEXCEPT\n# if FMT_EXCEPTIONS || FMT_HAS_CXX11_NOEXCEPT\n#  define FMT_NOEXCEPT FMT_DETECTED_NOEXCEPT\n# else\n#  define FMT_NOEXCEPT\n# endif\n#endif\n\n#ifndef FMT_BEGIN_NAMESPACE\n# if FMT_HAS_FEATURE(cxx_inline_namespaces) || FMT_GCC_VERSION >= 404 || \\\n     FMT_MSC_VER >= 1900\n#  define FMT_INLINE_NAMESPACE inline namespace\n#  define FMT_END_NAMESPACE }}\n# else\n#  define FMT_INLINE_NAMESPACE namespace\n#  define FMT_END_NAMESPACE } using namespace v5; }\n# endif\n# define FMT_BEGIN_NAMESPACE namespace fmt { FMT_INLINE_NAMESPACE v5 {\n#endif\n\n#if !defined(FMT_HEADER_ONLY) && defined(_WIN32)\n# ifdef FMT_EXPORT\n#  define FMT_API __declspec(dllexport)\n# elif defined(FMT_SHARED)\n#  define FMT_API __declspec(dllimport)\n# endif\n#endif\n#ifndef FMT_API\n# define FMT_API\n#endif\n\n#ifndef FMT_ASSERT\n# define FMT_ASSERT(condition, message) assert((condition) && message)\n#endif\n\n// libc++ supports string_view in pre-c++17.\n#if (FMT_HAS_INCLUDE(<string_view>) && \\\n      (__cplusplus > 201402L || defined(_LIBCPP_VERSION))) || \\\n    (defined(_MSVC_LANG) && _MSVC_LANG > 201402L && _MSC_VER >= 1910)\n# include <string_view>\n# define FMT_STRING_VIEW std::basic_string_view\n#elif FMT_HAS_INCLUDE(<experimental/string_view>) && __cplusplus >= 201402L\n# include <experimental/string_view>\n# define FMT_STRING_VIEW std::experimental::basic_string_view\n#endif\n\n// std::result_of is defined in <functional> in gcc 4.4.\n#if FMT_GCC_VERSION && FMT_GCC_VERSION <= 404\n# include <functional>\n#endif\n\nFMT_BEGIN_NAMESPACE\nnamespace internal {\n\n// An implementation of declval for pre-C++11 compilers such as gcc 4.\ntemplate <typename T>\ntypename std::add_rvalue_reference<T>::type declval() FMT_NOEXCEPT;\n\ntemplate <typename>\nstruct result_of;\n\ntemplate <typename F, typename... Args>\nstruct result_of<F(Args...)> {\n  // A workaround for gcc 4.4 that doesn't allow F to be a reference.\n  typedef typename std::result_of<\n    typename std::remove_reference<F>::type(Args...)>::type type;\n};\n\n// Casts nonnegative integer to unsigned.\ntemplate <typename Int>\nFMT_CONSTEXPR typename std::make_unsigned<Int>::type to_unsigned(Int value) {\n  FMT_ASSERT(value >= 0, \"negative value\");\n  return static_cast<typename std::make_unsigned<Int>::type>(value);\n}\n\n/** A contiguous memory buffer with an optional growing ability. */\ntemplate <typename T>\nclass basic_buffer {\n private:\n  basic_buffer(const basic_buffer &) = delete;\n  void operator=(const basic_buffer &) = delete;\n\n  T *ptr_;\n  std::size_t size_;\n  std::size_t capacity_;\n\n protected:\n  // Don't initialize ptr_ since it is not accessed to save a few cycles.\n  basic_buffer(std::size_t sz) FMT_NOEXCEPT: size_(sz), capacity_(sz) {}\n\n  basic_buffer(T *p = FMT_NULL, std::size_t sz = 0, std::size_t cap = 0)\n    FMT_NOEXCEPT: ptr_(p), size_(sz), capacity_(cap) {}\n\n  /** Sets the buffer data and capacity. */\n  void set(T *buf_data, std::size_t buf_capacity) FMT_NOEXCEPT {\n    ptr_ = buf_data;\n    capacity_ = buf_capacity;\n  }\n\n  /** Increases the buffer capacity to hold at least *capacity* elements. */\n  virtual void grow(std::size_t capacity) = 0;\n\n public:\n  typedef T value_type;\n  typedef const T &const_reference;\n\n  virtual ~basic_buffer() {}\n\n  T *begin() FMT_NOEXCEPT { return ptr_; }\n  T *end() FMT_NOEXCEPT { return ptr_ + size_; }\n\n  /** Returns the size of this buffer. */\n  std::size_t size() const FMT_NOEXCEPT { return size_; }\n\n  /** Returns the capacity of this buffer. */\n  std::size_t capacity() const FMT_NOEXCEPT { return capacity_; }\n\n  /** Returns a pointer to the buffer data. */\n  T *data() FMT_NOEXCEPT { return ptr_; }\n\n  /** Returns a pointer to the buffer data. */\n  const T *data() const FMT_NOEXCEPT { return ptr_; }\n\n  /**\n    Resizes the buffer. If T is a POD type new elements may not be initialized.\n   */\n  void resize(std::size_t new_size) {\n    reserve(new_size);\n    size_ = new_size;\n  }\n\n  /** Clears this buffer. */\n  void clear() { size_ = 0; }\n\n  /** Reserves space to store at least *capacity* elements. */\n  void reserve(std::size_t new_capacity) {\n    if (new_capacity > capacity_)\n      grow(new_capacity);\n  }\n\n  void push_back(const T &value) {\n    reserve(size_ + 1);\n    ptr_[size_++] = value;\n  }\n\n  /** Appends data to the end of the buffer. */\n  template <typename U>\n  void append(const U *begin, const U *end);\n\n  T &operator[](std::size_t index) { return ptr_[index]; }\n  const T &operator[](std::size_t index) const { return ptr_[index]; }\n};\n\ntypedef basic_buffer<char> buffer;\ntypedef basic_buffer<wchar_t> wbuffer;\n\n// A container-backed buffer.\ntemplate <typename Container>\nclass container_buffer : public basic_buffer<typename Container::value_type> {\n private:\n  Container &container_;\n\n protected:\n  void grow(std::size_t capacity) FMT_OVERRIDE {\n    container_.resize(capacity);\n    this->set(&container_[0], capacity);\n  }\n\n public:\n  explicit container_buffer(Container &c)\n    : basic_buffer<typename Container::value_type>(c.size()), container_(c) {}\n};\n\n// Extracts a reference to the container from back_insert_iterator.\ntemplate <typename Container>\ninline Container &get_container(std::back_insert_iterator<Container> it) {\n  typedef std::back_insert_iterator<Container> bi_iterator;\n  struct accessor: bi_iterator {\n    accessor(bi_iterator iter) : bi_iterator(iter) {}\n    using bi_iterator::container;\n  };\n  return *accessor(it).container;\n}\n\nstruct error_handler {\n  FMT_CONSTEXPR error_handler() {}\n  FMT_CONSTEXPR error_handler(const error_handler &) {}\n\n  // This function is intentionally not constexpr to give a compile-time error.\n  FMT_API void on_error(const char *message);\n};\n\ntemplate <typename T>\nstruct no_formatter_error : std::false_type {};\n}  // namespace internal\n\n#if FMT_GCC_VERSION && FMT_GCC_VERSION < 405\ntemplate <typename... T>\nstruct is_constructible: std::false_type {};\n#else\ntemplate <typename... T>\nstruct is_constructible : std::is_constructible<T...> {};\n#endif\n\n/**\n  An implementation of ``std::basic_string_view`` for pre-C++17. It provides a\n  subset of the API. ``fmt::basic_string_view`` is used for format strings even\n  if ``std::string_view`` is available to prevent issues when a library is\n  compiled with a different ``-std`` option than the client code (which is not\n  recommended).\n */\ntemplate <typename Char>\nclass basic_string_view {\n private:\n  const Char *data_;\n  size_t size_;\n\n public:\n  typedef Char char_type;\n  typedef const Char *iterator;\n\n  FMT_CONSTEXPR basic_string_view() FMT_NOEXCEPT : data_(FMT_NULL), size_(0) {}\n\n  /** Constructs a string reference object from a C string and a size. */\n  FMT_CONSTEXPR basic_string_view(const Char *s, size_t count) FMT_NOEXCEPT\n    : data_(s), size_(count) {}\n\n  /**\n    \\rst\n    Constructs a string reference object from a C string computing\n    the size with ``std::char_traits<Char>::length``.\n    \\endrst\n   */\n  basic_string_view(const Char *s)\n    : data_(s), size_(std::char_traits<Char>::length(s)) {}\n\n  /** Constructs a string reference from a ``std::basic_string`` object. */\n  template <typename Alloc>\n  FMT_CONSTEXPR basic_string_view(\n      const std::basic_string<Char, Alloc> &s) FMT_NOEXCEPT\n  : data_(s.data()), size_(s.size()) {}\n\n#ifdef FMT_STRING_VIEW\n  FMT_CONSTEXPR basic_string_view(FMT_STRING_VIEW<Char> s) FMT_NOEXCEPT\n  : data_(s.data()), size_(s.size()) {}\n#endif\n\n  /** Returns a pointer to the string data. */\n  FMT_CONSTEXPR const Char *data() const { return data_; }\n\n  /** Returns the string size. */\n  FMT_CONSTEXPR size_t size() const { return size_; }\n\n  FMT_CONSTEXPR iterator begin() const { return data_; }\n  FMT_CONSTEXPR iterator end() const { return data_ + size_; }\n\n  FMT_CONSTEXPR void remove_prefix(size_t n) {\n    data_ += n;\n    size_ -= n;\n  }\n\n  // Lexicographically compare this string reference to other.\n  int compare(basic_string_view other) const {\n    size_t str_size = size_ < other.size_ ? size_ : other.size_;\n    int result = std::char_traits<Char>::compare(data_, other.data_, str_size);\n    if (result == 0)\n      result = size_ == other.size_ ? 0 : (size_ < other.size_ ? -1 : 1);\n    return result;\n  }\n\n  friend bool operator==(basic_string_view lhs, basic_string_view rhs) {\n    return lhs.compare(rhs) == 0;\n  }\n  friend bool operator!=(basic_string_view lhs, basic_string_view rhs) {\n    return lhs.compare(rhs) != 0;\n  }\n  friend bool operator<(basic_string_view lhs, basic_string_view rhs) {\n    return lhs.compare(rhs) < 0;\n  }\n  friend bool operator<=(basic_string_view lhs, basic_string_view rhs) {\n    return lhs.compare(rhs) <= 0;\n  }\n  friend bool operator>(basic_string_view lhs, basic_string_view rhs) {\n    return lhs.compare(rhs) > 0;\n  }\n  friend bool operator>=(basic_string_view lhs, basic_string_view rhs) {\n    return lhs.compare(rhs) >= 0;\n  }\n};\n\ntypedef basic_string_view<char> string_view;\ntypedef basic_string_view<wchar_t> wstring_view;\n\n/**\n  \\rst\n  The function ``to_string_view`` adapts non-intrusively any kind of string or\n  string-like type if the user provides a (possibly templated) overload of\n  ``to_string_view`` which takes an instance of the string class\n  ``StringType<Char>`` and returns a ``fmt::basic_string_view<Char>``.\n  The conversion function must live in the very same namespace as\n  ``StringType<Char>`` to be picked up by ADL. Non-templated string types\n  like f.e. QString must return a ``basic_string_view`` with a fixed matching\n  char type.\n\n  **Example**::\n\n    namespace my_ns {\n    inline string_view to_string_view(const my_string &s) {\n      return {s.data(), s.length()};\n    }\n    }\n\n    std::string message = fmt::format(my_string(\"The answer is {}\"), 42);\n  \\endrst\n */\ntemplate <typename Char>\ninline basic_string_view<Char>\n  to_string_view(basic_string_view<Char> s) { return s; }\n\ntemplate <typename Char>\ninline basic_string_view<Char>\n  to_string_view(const std::basic_string<Char> &s) { return s; }\n\ntemplate <typename Char>\ninline basic_string_view<Char> to_string_view(const Char *s) { return s; }\n\n#ifdef FMT_STRING_VIEW\ntemplate <typename Char>\ninline basic_string_view<Char>\n  to_string_view(FMT_STRING_VIEW<Char> s) { return s; }\n#endif\n\n// A base class for compile-time strings. It is defined in the fmt namespace to\n// make formatting functions visible via ADL, e.g. format(fmt(\"{}\"), 42).\nstruct compile_string {};\n\ntemplate <typename S>\nstruct is_compile_string : std::is_base_of<compile_string, S> {};\n\ntemplate <\n  typename S,\n  typename Enable = typename std::enable_if<is_compile_string<S>::value>::type>\nFMT_CONSTEXPR basic_string_view<typename S::char_type>\n  to_string_view(const S &s) { return s; }\n\ntemplate <typename Context>\nclass basic_format_arg;\n\ntemplate <typename Context>\nclass basic_format_args;\n\n// A formatter for objects of type T.\ntemplate <typename T, typename Char = char, typename Enable = void>\nstruct formatter {\n  static_assert(internal::no_formatter_error<T>::value,\n    \"don't know how to format the type, include fmt/ostream.h if it provides \"\n    \"an operator<< that should be used\");\n\n  // The following functions are not defined intentionally.\n  template <typename ParseContext>\n  typename ParseContext::iterator parse(ParseContext &);\n  template <typename FormatContext>\n  auto format(const T &val, FormatContext &ctx) -> decltype(ctx.out());\n};\n\ntemplate <typename T, typename Char, typename Enable = void>\nstruct convert_to_int: std::integral_constant<\n  bool, !std::is_arithmetic<T>::value && std::is_convertible<T, int>::value> {};\n\nnamespace internal {\n\nstruct dummy_string_view { typedef void char_type; };\ndummy_string_view to_string_view(...);\nusing fmt::v5::to_string_view;\n\n// Specifies whether S is a string type convertible to fmt::basic_string_view.\ntemplate <typename S>\nstruct is_string : std::integral_constant<bool, !std::is_same<\n    dummy_string_view, decltype(to_string_view(declval<S>()))>::value> {};\n\ntemplate <typename S>\nstruct char_t {\n  typedef decltype(to_string_view(declval<S>())) result;\n  typedef typename result::char_type type;\n};\n\ntemplate <typename Char>\nstruct named_arg_base;\n\ntemplate <typename T, typename Char>\nstruct named_arg;\n\nenum type {\n  none_type, named_arg_type,\n  // Integer types should go first,\n  int_type, uint_type, long_long_type, ulong_long_type, bool_type, char_type,\n  last_integer_type = char_type,\n  // followed by floating-point types.\n  double_type, long_double_type, last_numeric_type = long_double_type,\n  cstring_type, string_type, pointer_type, custom_type\n};\n\nFMT_CONSTEXPR bool is_integral(type t) {\n  FMT_ASSERT(t != internal::named_arg_type, \"invalid argument type\");\n  return t > internal::none_type && t <= internal::last_integer_type;\n}\n\nFMT_CONSTEXPR bool is_arithmetic(type t) {\n  FMT_ASSERT(t != internal::named_arg_type, \"invalid argument type\");\n  return t > internal::none_type && t <= internal::last_numeric_type;\n}\n\ntemplate <typename Char>\nstruct string_value {\n  const Char *value;\n  std::size_t size;\n};\n\ntemplate <typename Context>\nstruct custom_value {\n  const void *value;\n  void (*format)(const void *arg, Context &ctx);\n};\n\n// A formatting argument value.\ntemplate <typename Context>\nclass value {\n public:\n  typedef typename Context::char_type char_type;\n\n  union {\n    int int_value;\n    unsigned uint_value;\n    long long long_long_value;\n    unsigned long long ulong_long_value;\n    double double_value;\n    long double long_double_value;\n    const void *pointer;\n    string_value<char_type> string;\n    string_value<signed char> sstring;\n    string_value<unsigned char> ustring;\n    custom_value<Context> custom;\n  };\n\n  FMT_CONSTEXPR value(int val = 0) : int_value(val) {}\n  value(unsigned val) { uint_value = val; }\n  value(long long val) { long_long_value = val; }\n  value(unsigned long long val) { ulong_long_value = val; }\n  value(double val) { double_value = val; }\n  value(long double val) { long_double_value = val; }\n  value(const char_type *val) { string.value = val; }\n  value(const signed char *val) {\n    static_assert(std::is_same<char, char_type>::value,\n                  \"incompatible string types\");\n    sstring.value = val;\n  }\n  value(const unsigned char *val) {\n    static_assert(std::is_same<char, char_type>::value,\n                  \"incompatible string types\");\n    ustring.value = val;\n  }\n  value(basic_string_view<char_type> val) {\n    string.value = val.data();\n    string.size = val.size();\n  }\n  value(const void *val) { pointer = val; }\n\n  template <typename T>\n  explicit value(const T &val) {\n    custom.value = &val;\n    custom.format = &format_custom_arg<T>;\n  }\n\n  const named_arg_base<char_type> &as_named_arg() {\n    return *static_cast<const named_arg_base<char_type>*>(pointer);\n  }\n\n private:\n  // Formats an argument of a custom type, such as a user-defined class.\n  template <typename T>\n  static void format_custom_arg(const void *arg, Context &ctx) {\n    // Get the formatter type through the context to allow different contexts\n    // have different extension points, e.g. `formatter<T>` for `format` and\n    // `printf_formatter<T>` for `printf`.\n    typename Context::template formatter_type<T>::type f;\n    auto &&parse_ctx = ctx.parse_context();\n    parse_ctx.advance_to(f.parse(parse_ctx));\n    ctx.advance_to(f.format(*static_cast<const T*>(arg), ctx));\n  }\n};\n\n// Value initializer used to delay conversion to value and reduce memory churn.\ntemplate <typename Context, typename T, type TYPE>\nstruct init {\n  T val;\n  static const type type_tag = TYPE;\n\n  FMT_CONSTEXPR init(const T &v) : val(v) {}\n  FMT_CONSTEXPR operator value<Context>() const { return value<Context>(val); }\n};\n\ntemplate <typename Context, typename T>\nFMT_CONSTEXPR basic_format_arg<Context> make_arg(const T &value);\n\n#define FMT_MAKE_VALUE(TAG, ArgType, ValueType) \\\n  template <typename C> \\\n  FMT_CONSTEXPR init<C, ValueType, TAG> make_value(ArgType val) { \\\n    return static_cast<ValueType>(val); \\\n  }\n\n#define FMT_MAKE_VALUE_SAME(TAG, Type) \\\n  template <typename C> \\\n  FMT_CONSTEXPR init<C, Type, TAG> make_value(Type val) { return val; }\n\nFMT_MAKE_VALUE(bool_type, bool, int)\nFMT_MAKE_VALUE(int_type, short, int)\nFMT_MAKE_VALUE(uint_type, unsigned short, unsigned)\nFMT_MAKE_VALUE_SAME(int_type, int)\nFMT_MAKE_VALUE_SAME(uint_type, unsigned)\n\n// To minimize the number of types we need to deal with, long is translated\n// either to int or to long long depending on its size.\ntypedef std::conditional<sizeof(long) == sizeof(int), int, long long>::type\n        long_type;\nFMT_MAKE_VALUE(\n    (sizeof(long) == sizeof(int) ? int_type : long_long_type), long, long_type)\ntypedef std::conditional<sizeof(unsigned long) == sizeof(unsigned),\n                         unsigned, unsigned long long>::type ulong_type;\nFMT_MAKE_VALUE(\n    (sizeof(unsigned long) == sizeof(unsigned) ? uint_type : ulong_long_type),\n    unsigned long, ulong_type)\n\nFMT_MAKE_VALUE_SAME(long_long_type, long long)\nFMT_MAKE_VALUE_SAME(ulong_long_type, unsigned long long)\nFMT_MAKE_VALUE(int_type, signed char, int)\nFMT_MAKE_VALUE(uint_type, unsigned char, unsigned)\n\n// This doesn't use FMT_MAKE_VALUE because of ambiguity in gcc 4.4.\ntemplate <typename C, typename Char>\nFMT_CONSTEXPR typename std::enable_if<\n  std::is_same<typename C::char_type, Char>::value,\n  init<C, int, char_type>>::type make_value(Char val) { return val; }\n\ntemplate <typename C>\nFMT_CONSTEXPR typename std::enable_if<\n  !std::is_same<typename C::char_type, char>::value,\n  init<C, int, char_type>>::type make_value(char val) { return val; }\n\nFMT_MAKE_VALUE(double_type, float, double)\nFMT_MAKE_VALUE_SAME(double_type, double)\nFMT_MAKE_VALUE_SAME(long_double_type, long double)\n\n// Formatting of wide strings into a narrow buffer and multibyte strings\n// into a wide buffer is disallowed (https://github.com/fmtlib/fmt/pull/606).\nFMT_MAKE_VALUE(cstring_type, typename C::char_type*,\n               const typename C::char_type*)\nFMT_MAKE_VALUE(cstring_type, const typename C::char_type*,\n               const typename C::char_type*)\n\nFMT_MAKE_VALUE(cstring_type, signed char*, const signed char*)\nFMT_MAKE_VALUE_SAME(cstring_type, const signed char*)\nFMT_MAKE_VALUE(cstring_type, unsigned char*, const unsigned char*)\nFMT_MAKE_VALUE_SAME(cstring_type, const unsigned char*)\nFMT_MAKE_VALUE_SAME(string_type, basic_string_view<typename C::char_type>)\nFMT_MAKE_VALUE(string_type,\n               typename basic_string_view<typename C::char_type>::type,\n               basic_string_view<typename C::char_type>)\nFMT_MAKE_VALUE(string_type, const std::basic_string<typename C::char_type>&,\n               basic_string_view<typename C::char_type>)\nFMT_MAKE_VALUE(pointer_type, void*, const void*)\nFMT_MAKE_VALUE_SAME(pointer_type, const void*)\n\n#if FMT_USE_NULLPTR\nFMT_MAKE_VALUE(pointer_type, std::nullptr_t, const void*)\n#endif\n\n// Formatting of arbitrary pointers is disallowed. If you want to output a\n// pointer cast it to \"void *\" or \"const void *\". In particular, this forbids\n// formatting of \"[const] volatile char *\" which is printed as bool by\n// iostreams.\ntemplate <typename C, typename T>\ntypename std::enable_if<!std::is_same<T, typename C::char_type>::value>::type\n    make_value(const T *) {\n  static_assert(!sizeof(T), \"formatting of non-void pointers is disallowed\");\n}\n\ntemplate <typename C, typename T>\ninline typename std::enable_if<\n    std::is_enum<T>::value && convert_to_int<T, typename C::char_type>::value,\n    init<C, int, int_type>>::type\n  make_value(const T &val) { return static_cast<int>(val); }\n\ntemplate <typename C, typename T, typename Char = typename C::char_type>\ninline typename std::enable_if<\n    is_constructible<basic_string_view<Char>, T>::value &&\n    !internal::is_string<T>::value,\n    init<C, basic_string_view<Char>, string_type>>::type\n  make_value(const T &val) { return basic_string_view<Char>(val); }\n\ntemplate <typename C, typename T, typename Char = typename C::char_type>\ninline typename std::enable_if<\n    !convert_to_int<T, Char>::value && !std::is_same<T, Char>::value &&\n    !std::is_convertible<T, basic_string_view<Char>>::value &&\n    !is_constructible<basic_string_view<Char>, T>::value &&\n    !internal::is_string<T>::value,\n    // Implicit conversion to std::string is not handled here because it's\n    // unsafe: https://github.com/fmtlib/fmt/issues/729\n    init<C, const T &, custom_type>>::type\n  make_value(const T &val) { return val; }\n\ntemplate <typename C, typename T>\ninit<C, const void*, named_arg_type>\n    make_value(const named_arg<T, typename C::char_type> &val) {\n  basic_format_arg<C> arg = make_arg<C>(val.value);\n  std::memcpy(val.data, &arg, sizeof(arg));\n  return static_cast<const void*>(&val);\n}\n\ntemplate <typename C, typename S>\nFMT_CONSTEXPR11 typename std::enable_if<\n  internal::is_string<S>::value,\n  init<C, basic_string_view<typename C::char_type>, string_type>>::type\n    make_value(const S &val) {\n  // Handle adapted strings.\n  static_assert(std::is_same<\n    typename C::char_type, typename internal::char_t<S>::type>::value,\n    \"mismatch between char-types of context and argument\");\n  return to_string_view(val);\n}\n\n// Maximum number of arguments with packed types.\nenum { max_packed_args = 15 };\nenum : unsigned long long { is_unpacked_bit = 1ull << 63 };\n\ntemplate <typename Context>\nclass arg_map;\n}  // namespace internal\n\n// A formatting argument. It is a trivially copyable/constructible type to\n// allow storage in basic_memory_buffer.\ntemplate <typename Context>\nclass basic_format_arg {\n private:\n  internal::value<Context> value_;\n  internal::type type_;\n\n  template <typename ContextType, typename T>\n  friend FMT_CONSTEXPR basic_format_arg<ContextType>\n    internal::make_arg(const T &value);\n\n  template <typename Visitor, typename Ctx>\n  friend FMT_CONSTEXPR typename internal::result_of<Visitor(int)>::type\n    visit_format_arg(Visitor &&vis, const basic_format_arg<Ctx> &arg);\n\n  friend class basic_format_args<Context>;\n  friend class internal::arg_map<Context>;\n\n  typedef typename Context::char_type char_type;\n\n public:\n  class handle {\n   public:\n    explicit handle(internal::custom_value<Context> custom): custom_(custom) {}\n\n    void format(Context &ctx) const { custom_.format(custom_.value, ctx); }\n\n   private:\n    internal::custom_value<Context> custom_;\n  };\n\n  FMT_CONSTEXPR basic_format_arg() : type_(internal::none_type) {}\n\n  FMT_EXPLICIT operator bool() const FMT_NOEXCEPT {\n    return type_ != internal::none_type;\n  }\n\n  internal::type type() const { return type_; }\n\n  bool is_integral() const { return internal::is_integral(type_); }\n  bool is_arithmetic() const { return internal::is_arithmetic(type_); }\n};\n\nstruct monostate {};\n\n/**\n  \\rst\n  Visits an argument dispatching to the appropriate visit method based on\n  the argument type. For example, if the argument type is ``double`` then\n  ``vis(value)`` will be called with the value of type ``double``.\n  \\endrst\n */\ntemplate <typename Visitor, typename Context>\nFMT_CONSTEXPR typename internal::result_of<Visitor(int)>::type\n    visit_format_arg(Visitor &&vis, const basic_format_arg<Context> &arg) {\n  typedef typename Context::char_type char_type;\n  switch (arg.type_) {\n  case internal::none_type:\n    break;\n  case internal::named_arg_type:\n    FMT_ASSERT(false, \"invalid argument type\");\n    break;\n  case internal::int_type:\n    return vis(arg.value_.int_value);\n  case internal::uint_type:\n    return vis(arg.value_.uint_value);\n  case internal::long_long_type:\n    return vis(arg.value_.long_long_value);\n  case internal::ulong_long_type:\n    return vis(arg.value_.ulong_long_value);\n  case internal::bool_type:\n    return vis(arg.value_.int_value != 0);\n  case internal::char_type:\n    return vis(static_cast<char_type>(arg.value_.int_value));\n  case internal::double_type:\n    return vis(arg.value_.double_value);\n  case internal::long_double_type:\n    return vis(arg.value_.long_double_value);\n  case internal::cstring_type:\n    return vis(arg.value_.string.value);\n  case internal::string_type:\n    return vis(basic_string_view<char_type>(\n                 arg.value_.string.value, arg.value_.string.size));\n  case internal::pointer_type:\n    return vis(arg.value_.pointer);\n  case internal::custom_type:\n    return vis(typename basic_format_arg<Context>::handle(arg.value_.custom));\n  }\n  return vis(monostate());\n}\n\n// DEPRECATED!\ntemplate <typename Visitor, typename Context>\nFMT_CONSTEXPR typename internal::result_of<Visitor(int)>::type\n    visit(Visitor &&vis, const basic_format_arg<Context> &arg) {\n  return visit_format_arg(std::forward<Visitor>(vis), arg);\n}\n\n// Parsing context consisting of a format string range being parsed and an\n// argument counter for automatic indexing.\ntemplate <typename Char, typename ErrorHandler = internal::error_handler>\nclass basic_parse_context : private ErrorHandler {\n private:\n  basic_string_view<Char> format_str_;\n  int next_arg_id_;\n\n public:\n  typedef Char char_type;\n  typedef typename basic_string_view<Char>::iterator iterator;\n\n  explicit FMT_CONSTEXPR basic_parse_context(\n      basic_string_view<Char> format_str, ErrorHandler eh = ErrorHandler())\n    : ErrorHandler(eh), format_str_(format_str), next_arg_id_(0) {}\n\n  // Returns an iterator to the beginning of the format string range being\n  // parsed.\n  FMT_CONSTEXPR iterator begin() const FMT_NOEXCEPT {\n    return format_str_.begin();\n  }\n\n  // Returns an iterator past the end of the format string range being parsed.\n  FMT_CONSTEXPR iterator end() const FMT_NOEXCEPT { return format_str_.end(); }\n\n  // Advances the begin iterator to ``it``.\n  FMT_CONSTEXPR void advance_to(iterator it) {\n    format_str_.remove_prefix(internal::to_unsigned(it - begin()));\n  }\n\n  // Returns the next argument index.\n  FMT_CONSTEXPR unsigned next_arg_id();\n\n  FMT_CONSTEXPR bool check_arg_id(unsigned) {\n    if (next_arg_id_ > 0) {\n      on_error(\"cannot switch from automatic to manual argument indexing\");\n      return false;\n    }\n    next_arg_id_ = -1;\n    return true;\n  }\n  void check_arg_id(basic_string_view<Char>) {}\n\n  FMT_CONSTEXPR void on_error(const char *message) {\n    ErrorHandler::on_error(message);\n  }\n\n  FMT_CONSTEXPR ErrorHandler error_handler() const { return *this; }\n};\n\ntypedef basic_parse_context<char> format_parse_context;\ntypedef basic_parse_context<wchar_t> wformat_parse_context;\n\n// DEPRECATED!\ntypedef basic_parse_context<char> parse_context;\ntypedef basic_parse_context<wchar_t> wparse_context;\n\nnamespace internal {\n// A map from argument names to their values for named arguments.\ntemplate <typename Context>\nclass arg_map {\n private:\n  arg_map(const arg_map &) = delete;\n  void operator=(const arg_map &) = delete;\n\n  typedef typename Context::char_type char_type;\n\n  struct entry {\n    basic_string_view<char_type> name;\n    basic_format_arg<Context> arg;\n  };\n\n  entry *map_;\n  unsigned size_;\n\n  void push_back(value<Context> val) {\n    const internal::named_arg_base<char_type> &named = val.as_named_arg();\n    map_[size_] = entry{named.name, named.template deserialize<Context>()};\n    ++size_;\n  }\n\n public:\n  arg_map() : map_(FMT_NULL), size_(0) {}\n  void init(const basic_format_args<Context> &args);\n  ~arg_map() { delete [] map_; }\n\n  basic_format_arg<Context> find(basic_string_view<char_type> name) const {\n    // The list is unsorted, so just return the first matching name.\n    for (entry *it = map_, *end = map_ + size_; it != end; ++it) {\n      if (it->name == name)\n        return it->arg;\n    }\n    return {};\n  }\n};\n\n// A type-erased reference to an std::locale to avoid heavy <locale> include.\nclass locale_ref {\n private:\n  const void *locale_;  // A type-erased pointer to std::locale.\n  friend class locale;\n\n public:\n  locale_ref() : locale_(FMT_NULL) {}\n\n  template <typename Locale>\n  explicit locale_ref(const Locale &loc);\n\n  template <typename Locale>\n  Locale get() const;\n};\n\ntemplate <typename OutputIt, typename Context, typename Char>\nclass context_base {\n public:\n  typedef OutputIt iterator;\n\n private:\n  basic_parse_context<Char> parse_context_;\n  iterator out_;\n  basic_format_args<Context> args_;\n  locale_ref loc_;\n\n protected:\n  typedef Char char_type;\n  typedef basic_format_arg<Context> format_arg;\n\n  context_base(OutputIt out, basic_string_view<char_type> format_str,\n               basic_format_args<Context> ctx_args,\n               locale_ref loc = locale_ref())\n  : parse_context_(format_str), out_(out), args_(ctx_args), loc_(loc) {}\n\n  // Returns the argument with specified index.\n  format_arg do_get_arg(unsigned arg_id) {\n    format_arg arg = args_.get(arg_id);\n    if (!arg)\n      parse_context_.on_error(\"argument index out of range\");\n    return arg;\n  }\n\n  // Checks if manual indexing is used and returns the argument with\n  // specified index.\n  format_arg get_arg(unsigned arg_id) {\n    return this->parse_context().check_arg_id(arg_id) ?\n      this->do_get_arg(arg_id) : format_arg();\n  }\n\n public:\n  basic_parse_context<char_type> &parse_context() { return parse_context_; }\n  basic_format_args<Context> args() const { return args_; } // DEPRECATED!\n  basic_format_arg<Context> arg(unsigned id) const { return args_.get(id); }\n\n  internal::error_handler error_handler() {\n    return parse_context_.error_handler();\n  }\n\n  void on_error(const char *message) { parse_context_.on_error(message); }\n\n  // Returns an iterator to the beginning of the output range.\n  iterator out() { return out_; }\n  iterator begin() { return out_; }  // deprecated\n\n  // Advances the begin iterator to ``it``.\n  void advance_to(iterator it) { out_ = it; }\n\n  locale_ref locale() { return loc_; }\n};\n\ntemplate <typename Context, typename T>\nstruct get_type {\n  typedef decltype(make_value<Context>(\n        declval<typename std::decay<T>::type&>())) value_type;\n  static const type value = value_type::type_tag;\n};\n\ntemplate <typename Context>\nFMT_CONSTEXPR11 unsigned long long get_types() { return 0; }\n\ntemplate <typename Context, typename Arg, typename... Args>\nFMT_CONSTEXPR11 unsigned long long get_types() {\n  return get_type<Context, Arg>::value | (get_types<Context, Args...>() << 4);\n}\n\ntemplate <typename Context, typename T>\nFMT_CONSTEXPR basic_format_arg<Context> make_arg(const T &value) {\n  basic_format_arg<Context> arg;\n  arg.type_ = get_type<Context, T>::value;\n  arg.value_ = make_value<Context>(value);\n  return arg;\n}\n\ntemplate <bool IS_PACKED, typename Context, typename T>\ninline typename std::enable_if<IS_PACKED, value<Context>>::type\n    make_arg(const T &value) {\n  return make_value<Context>(value);\n}\n\ntemplate <bool IS_PACKED, typename Context, typename T>\ninline typename std::enable_if<!IS_PACKED, basic_format_arg<Context>>::type\n    make_arg(const T &value) {\n  return make_arg<Context>(value);\n}\n}  // namespace internal\n\n// Formatting context.\ntemplate <typename OutputIt, typename Char>\nclass basic_format_context :\n  public internal::context_base<\n    OutputIt, basic_format_context<OutputIt, Char>, Char> {\n public:\n  /** The character type for the output. */\n  typedef Char char_type;\n\n  // using formatter_type = formatter<T, char_type>;\n  template <typename T>\n  struct formatter_type { typedef formatter<T, char_type> type; };\n\n private:\n  internal::arg_map<basic_format_context> map_;\n\n  basic_format_context(const basic_format_context &) = delete;\n  void operator=(const basic_format_context &) = delete;\n\n  typedef internal::context_base<OutputIt, basic_format_context, Char> base;\n  typedef typename base::format_arg format_arg;\n  using base::get_arg;\n\n public:\n  using typename base::iterator;\n\n  /**\n   Constructs a ``basic_format_context`` object. References to the arguments are\n   stored in the object so make sure they have appropriate lifetimes.\n   */\n  basic_format_context(OutputIt out, basic_string_view<char_type> format_str,\n                       basic_format_args<basic_format_context> ctx_args,\n                       internal::locale_ref loc = internal::locale_ref())\n    : base(out, format_str, ctx_args, loc) {}\n\n  format_arg next_arg() {\n    return this->do_get_arg(this->parse_context().next_arg_id());\n  }\n  format_arg get_arg(unsigned arg_id) { return this->do_get_arg(arg_id); }\n\n  // Checks if manual indexing is used and returns the argument with the\n  // specified name.\n  format_arg get_arg(basic_string_view<char_type> name);\n};\n\ntemplate <typename Char>\nstruct buffer_context {\n  typedef basic_format_context<\n    std::back_insert_iterator<internal::basic_buffer<Char>>, Char> type;\n};\ntypedef buffer_context<char>::type format_context;\ntypedef buffer_context<wchar_t>::type wformat_context;\n\n/**\n  \\rst\n  An array of references to arguments. It can be implicitly converted into\n  `~fmt::basic_format_args` for passing into type-erased formatting functions\n  such as `~fmt::vformat`.\n  \\endrst\n */\ntemplate <typename Context, typename ...Args>\nclass format_arg_store {\n private:\n  static const size_t NUM_ARGS = sizeof...(Args);\n\n  // Packed is a macro on MinGW so use IS_PACKED instead.\n  static const bool IS_PACKED = NUM_ARGS < internal::max_packed_args;\n\n  typedef typename std::conditional<IS_PACKED,\n    internal::value<Context>, basic_format_arg<Context>>::type value_type;\n\n  // If the arguments are not packed, add one more element to mark the end.\n  static const size_t DATA_SIZE =\n          NUM_ARGS + (IS_PACKED && NUM_ARGS != 0 ? 0 : 1);\n  value_type data_[DATA_SIZE];\n\n  friend class basic_format_args<Context>;\n\n  static FMT_CONSTEXPR11 unsigned long long get_types() {\n    return IS_PACKED ?\n      internal::get_types<Context, Args...>() :\n      internal::is_unpacked_bit | NUM_ARGS;\n  }\n\n public:\n#if FMT_USE_CONSTEXPR11\n  static FMT_CONSTEXPR11 unsigned long long TYPES = get_types();\n#else\n  static const unsigned long long TYPES;\n#endif\n\n#if (FMT_GCC_VERSION && FMT_GCC_VERSION <= 405) || \\\n    (FMT_MSC_VER && FMT_MSC_VER <= 1800)\n  // Workaround array initialization issues in gcc <= 4.5 and MSVC <= 2013.\n  format_arg_store(const Args &... args) {\n    value_type init[DATA_SIZE] =\n      {internal::make_arg<IS_PACKED, Context>(args)...};\n    std::memcpy(data_, init, sizeof(init));\n  }\n#else\n  format_arg_store(const Args &... args)\n    : data_{internal::make_arg<IS_PACKED, Context>(args)...} {}\n#endif\n};\n\n#if !FMT_USE_CONSTEXPR11\ntemplate <typename Context, typename ...Args>\nconst unsigned long long format_arg_store<Context, Args...>::TYPES =\n    get_types();\n#endif\n\n/**\n  \\rst\n  Constructs an `~fmt::format_arg_store` object that contains references to\n  arguments and can be implicitly converted to `~fmt::format_args`. `Context`\n  can be omitted in which case it defaults to `~fmt::context`.\n  \\endrst\n */\ntemplate <typename Context = format_context, typename ...Args>\ninline format_arg_store<Context, Args...>\n  make_format_args(const Args &... args) { return {args...}; }\n\n/** Formatting arguments. */\ntemplate <typename Context>\nclass basic_format_args {\n public:\n  typedef unsigned size_type;\n  typedef basic_format_arg<Context>  format_arg;\n\n private:\n  // To reduce compiled code size per formatting function call, types of first\n  // max_packed_args arguments are passed in the types_ field.\n  unsigned long long types_;\n  union {\n    // If the number of arguments is less than max_packed_args, the argument\n    // values are stored in values_, otherwise they are stored in args_.\n    // This is done to reduce compiled code size as storing larger objects\n    // may require more code (at least on x86-64) even if the same amount of\n    // data is actually copied to stack. It saves ~10% on the bloat test.\n    const internal::value<Context> *values_;\n    const format_arg *args_;\n  };\n\n  bool is_packed() const { return (types_ & internal::is_unpacked_bit) == 0; }\n\n  typename internal::type type(unsigned index) const {\n    unsigned shift = index * 4;\n    return static_cast<typename internal::type>(\n      (types_ & (0xfull << shift)) >> shift);\n  }\n\n  friend class internal::arg_map<Context>;\n\n  void set_data(const internal::value<Context> *values) { values_ = values; }\n  void set_data(const format_arg *args) { args_ = args; }\n\n  format_arg do_get(size_type index) const {\n    format_arg arg;\n    if (!is_packed()) {\n      auto num_args = max_size();\n      if (index < num_args)\n        arg = args_[index];\n      return arg;\n    }\n    if (index > internal::max_packed_args)\n      return arg;\n    arg.type_ = type(index);\n    if (arg.type_ == internal::none_type)\n      return arg;\n    internal::value<Context> &val = arg.value_;\n    val = values_[index];\n    return arg;\n  }\n\n public:\n  basic_format_args() : types_(0) {}\n\n  /**\n   \\rst\n   Constructs a `basic_format_args` object from `~fmt::format_arg_store`.\n   \\endrst\n   */\n  template <typename... Args>\n  basic_format_args(const format_arg_store<Context, Args...> &store)\n  : types_(static_cast<unsigned long long>(store.TYPES)) {\n    set_data(store.data_);\n  }\n\n  /**\n   \\rst\n   Constructs a `basic_format_args` object from a dynamic set of arguments.\n   \\endrst\n   */\n  basic_format_args(const format_arg *args, size_type count)\n    : types_(internal::is_unpacked_bit | count) {\n    set_data(args);\n  }\n\n  /** Returns the argument at specified index. */\n  format_arg get(size_type index) const {\n    format_arg arg = do_get(index);\n    if (arg.type_ == internal::named_arg_type)\n      arg = arg.value_.as_named_arg().template deserialize<Context>();\n    return arg;\n  }\n\n  size_type max_size() const {\n    unsigned long long max_packed = internal::max_packed_args;\n    return static_cast<size_type>(\n      is_packed() ? max_packed : types_ & ~internal::is_unpacked_bit);\n  }\n};\n\n/** An alias to ``basic_format_args<context>``. */\n// It is a separate type rather than a typedef to make symbols readable.\nstruct format_args : basic_format_args<format_context> {\n  template <typename ...Args>\n  format_args(Args &&... arg)\n  : basic_format_args<format_context>(std::forward<Args>(arg)...) {}\n};\nstruct wformat_args : basic_format_args<wformat_context> {\n  template <typename ...Args>\n  wformat_args(Args &&... arg)\n  : basic_format_args<wformat_context>(std::forward<Args>(arg)...) {}\n};\n\n#define FMT_ENABLE_IF_T(B, T) typename std::enable_if<B, T>::type\n\n#ifndef FMT_USE_ALIAS_TEMPLATES\n# define FMT_USE_ALIAS_TEMPLATES FMT_HAS_FEATURE(cxx_alias_templates)\n#endif\n#if FMT_USE_ALIAS_TEMPLATES\n/** String's character type. */\ntemplate <typename S>\nusing char_t = FMT_ENABLE_IF_T(\n  internal::is_string<S>::value, typename internal::char_t<S>::type);\n#define FMT_CHAR(S) fmt::char_t<S>\n#else\ntemplate <typename S>\nstruct char_t : std::enable_if<\n    internal::is_string<S>::value, typename internal::char_t<S>::type> {};\n#define FMT_CHAR(S) typename char_t<S>::type\n#endif\n\nnamespace internal {\ntemplate <typename Char>\nstruct named_arg_base {\n  basic_string_view<Char> name;\n\n  // Serialized value<context>.\n  mutable char data[\n    sizeof(basic_format_arg<typename buffer_context<Char>::type>)];\n\n  named_arg_base(basic_string_view<Char> nm) : name(nm) {}\n\n  template <typename Context>\n  basic_format_arg<Context> deserialize() const {\n    basic_format_arg<Context> arg;\n    std::memcpy(&arg, data, sizeof(basic_format_arg<Context>));\n    return arg;\n  }\n};\n\ntemplate <typename T, typename Char>\nstruct named_arg : named_arg_base<Char> {\n  const T &value;\n\n  named_arg(basic_string_view<Char> name, const T &val)\n    : named_arg_base<Char>(name), value(val) {}\n};\n\ntemplate <typename... Args, typename S>\ninline typename std::enable_if<!is_compile_string<S>::value>::type\n  check_format_string(const S &) {}\ntemplate <typename... Args, typename S>\ntypename std::enable_if<is_compile_string<S>::value>::type\n  check_format_string(S);\n\ntemplate <typename S, typename... Args>\nstruct checked_args : format_arg_store<\n  typename buffer_context<FMT_CHAR(S)>::type, Args...> {\n  typedef typename buffer_context<FMT_CHAR(S)>::type context;\n\n  checked_args(const S &format_str, const Args &... args):\n    format_arg_store<context, Args...>(args...) {\n    internal::check_format_string<Args...>(format_str);\n  }\n\n  basic_format_args<context> operator*() const { return *this; }\n};\n\ntemplate <typename Char>\nstd::basic_string<Char> vformat(\n  basic_string_view<Char> format_str,\n  basic_format_args<typename buffer_context<Char>::type> args);\n\ntemplate <typename Char>\ntypename buffer_context<Char>::type::iterator vformat_to(\n  internal::basic_buffer<Char> &buf, basic_string_view<Char> format_str,\n  basic_format_args<typename buffer_context<Char>::type> args);\n}\n\n/**\n  \\rst\n  Returns a named argument to be used in a formatting function.\n\n  **Example**::\n\n    fmt::print(\"Elapsed time: {s:.2f} seconds\", fmt::arg(\"s\", 1.23));\n  \\endrst\n */\ntemplate <typename T>\ninline internal::named_arg<T, char> arg(string_view name, const T &arg) {\n  return {name, arg};\n}\n\ntemplate <typename T>\ninline internal::named_arg<T, wchar_t> arg(wstring_view name, const T &arg) {\n  return {name, arg};\n}\n\n// Disable nested named arguments, e.g. ``arg(\"a\", arg(\"b\", 42))``.\ntemplate <typename S, typename T, typename Char>\nvoid arg(S, internal::named_arg<T, Char>) = delete;\n\ntemplate <typename Container>\nstruct is_contiguous: std::false_type {};\n\ntemplate <typename Char>\nstruct is_contiguous<std::basic_string<Char> >: std::true_type {};\n\ntemplate <typename Char>\nstruct is_contiguous<internal::basic_buffer<Char> >: std::true_type {};\n\n/** Formats a string and writes the output to ``out``. */\ntemplate <typename Container, typename S>\ntypename std::enable_if<\n    is_contiguous<Container>::value, std::back_insert_iterator<Container>>::type\n  vformat_to(\n    std::back_insert_iterator<Container> out,\n    const S &format_str,\n    basic_format_args<typename buffer_context<FMT_CHAR(S)>::type> args) {\n  internal::container_buffer<Container> buf(internal::get_container(out));\n  internal::vformat_to(buf, to_string_view(format_str), args);\n  return out;\n}\n\ntemplate <typename Container, typename S, typename... Args>\ninline typename std::enable_if<\n  is_contiguous<Container>::value && internal::is_string<S>::value,\n  std::back_insert_iterator<Container>>::type\n    format_to(std::back_insert_iterator<Container> out, const S &format_str,\n              const Args &... args) {\n  internal::checked_args<S, Args...> ca(format_str, args...);\n  return vformat_to(out, to_string_view(format_str), *ca);\n}\n\ntemplate <typename S, typename Char = FMT_CHAR(S)>\ninline std::basic_string<Char> vformat(\n    const S &format_str,\n    basic_format_args<typename buffer_context<Char>::type> args) {\n  return internal::vformat(to_string_view(format_str), args);\n}\n\n/**\n  \\rst\n  Formats arguments and returns the result as a string.\n\n  **Example**::\n\n    #include <fmt/core.h>\n    std::string message = fmt::format(\"The answer is {}\", 42);\n  \\endrst\n*/\ntemplate <typename S, typename... Args>\ninline std::basic_string<FMT_CHAR(S)> format(\n    const S &format_str, const Args &... args) {\n  return internal::vformat(\n    to_string_view(format_str),\n    *internal::checked_args<S, Args...>(format_str, args...));\n}\n\nFMT_API void vprint(std::FILE *f, string_view format_str, format_args args);\nFMT_API void vprint(std::FILE *f, wstring_view format_str, wformat_args args);\n\n/**\n  \\rst\n  Prints formatted data to the file *f*. For wide format strings,\n  *f* should be in wide-oriented mode set via ``fwide(f, 1)`` or\n  ``_setmode(_fileno(f), _O_U8TEXT)`` on Windows.\n\n  **Example**::\n\n    fmt::print(stderr, \"Don't {}!\", \"panic\");\n  \\endrst\n */\ntemplate <typename S, typename... Args>\ninline FMT_ENABLE_IF_T(internal::is_string<S>::value, void)\n    print(std::FILE *f, const S &format_str, const Args &... args) {\n  vprint(f, to_string_view(format_str),\n         internal::checked_args<S, Args...>(format_str, args...));\n}\n\nFMT_API void vprint(string_view format_str, format_args args);\nFMT_API void vprint(wstring_view format_str, wformat_args args);\n\n/**\n  \\rst\n  Prints formatted data to ``stdout``.\n\n  **Example**::\n\n    fmt::print(\"Elapsed time: {0:.2f} seconds\", 1.23);\n  \\endrst\n */\ntemplate <typename S, typename... Args>\ninline FMT_ENABLE_IF_T(internal::is_string<S>::value, void)\n    print(const S &format_str, const Args &... args) {\n  vprint(to_string_view(format_str),\n         internal::checked_args<S, Args...>(format_str, args...));\n}\nFMT_END_NAMESPACE\n\n#endif  // FMT_CORE_H_\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/fmt/bundled/format-inl.h",
    "content": "// Formatting library for C++\n//\n// Copyright (c) 2012 - 2016, Victor Zverovich\n// All rights reserved.\n//\n// For the license information refer to format.h.\n\n#ifndef FMT_FORMAT_INL_H_\n#define FMT_FORMAT_INL_H_\n\n#include \"format.h\"\n\n#include <string.h>\n\n#include <cctype>\n#include <cerrno>\n#include <climits>\n#include <cmath>\n#include <cstdarg>\n#include <cstddef>  // for std::ptrdiff_t\n#include <cstring>  // for std::memmove\n#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)\n# include <locale>\n#endif\n\n#if FMT_USE_WINDOWS_H\n# if !defined(FMT_HEADER_ONLY) && !defined(WIN32_LEAN_AND_MEAN)\n#  define WIN32_LEAN_AND_MEAN\n# endif\n# if defined(NOMINMAX) || defined(FMT_WIN_MINMAX)\n#  include <windows.h>\n# else\n#  define NOMINMAX\n#  include <windows.h>\n#  undef NOMINMAX\n# endif\n#endif\n\n#if FMT_EXCEPTIONS\n# define FMT_TRY try\n# define FMT_CATCH(x) catch (x)\n#else\n# define FMT_TRY if (true)\n# define FMT_CATCH(x) if (false)\n#endif\n\n#ifdef _MSC_VER\n# pragma warning(push)\n# pragma warning(disable: 4127)  // conditional expression is constant\n# pragma warning(disable: 4702)  // unreachable code\n// Disable deprecation warning for strerror. The latter is not called but\n// MSVC fails to detect it.\n# pragma warning(disable: 4996)\n#endif\n\n// Dummy implementations of strerror_r and strerror_s called if corresponding\n// system functions are not available.\ninline fmt::internal::null<> strerror_r(int, char *, ...) {\n  return fmt::internal::null<>();\n}\ninline fmt::internal::null<> strerror_s(char *, std::size_t, ...) {\n  return fmt::internal::null<>();\n}\n\nFMT_BEGIN_NAMESPACE\n\nnamespace {\n\n#ifndef _MSC_VER\n# define FMT_SNPRINTF snprintf\n#else  // _MSC_VER\ninline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) {\n  va_list args;\n  va_start(args, format);\n  int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args);\n  va_end(args);\n  return result;\n}\n# define FMT_SNPRINTF fmt_snprintf\n#endif  // _MSC_VER\n\n#if defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)\n# define FMT_SWPRINTF snwprintf\n#else\n# define FMT_SWPRINTF swprintf\n#endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)\n\ntypedef void (*FormatFunc)(internal::buffer &, int, string_view);\n\n// Portable thread-safe version of strerror.\n// Sets buffer to point to a string describing the error code.\n// This can be either a pointer to a string stored in buffer,\n// or a pointer to some static immutable string.\n// Returns one of the following values:\n//   0      - success\n//   ERANGE - buffer is not large enough to store the error message\n//   other  - failure\n// Buffer should be at least of size 1.\nint safe_strerror(\n    int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT {\n  FMT_ASSERT(buffer != FMT_NULL && buffer_size != 0, \"invalid buffer\");\n\n  class dispatcher {\n   private:\n    int error_code_;\n    char *&buffer_;\n    std::size_t buffer_size_;\n\n    // A noop assignment operator to avoid bogus warnings.\n    void operator=(const dispatcher &) {}\n\n    // Handle the result of XSI-compliant version of strerror_r.\n    int handle(int result) {\n      // glibc versions before 2.13 return result in errno.\n      return result == -1 ? errno : result;\n    }\n\n    // Handle the result of GNU-specific version of strerror_r.\n    int handle(char *message) {\n      // If the buffer is full then the message is probably truncated.\n      if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1)\n        return ERANGE;\n      buffer_ = message;\n      return 0;\n    }\n\n    // Handle the case when strerror_r is not available.\n    int handle(internal::null<>) {\n      return fallback(strerror_s(buffer_, buffer_size_, error_code_));\n    }\n\n    // Fallback to strerror_s when strerror_r is not available.\n    int fallback(int result) {\n      // If the buffer is full then the message is probably truncated.\n      return result == 0 && strlen(buffer_) == buffer_size_ - 1 ?\n            ERANGE : result;\n    }\n\n#if !FMT_MSC_VER\n    // Fallback to strerror if strerror_r and strerror_s are not available.\n    int fallback(internal::null<>) {\n      errno = 0;\n      buffer_ = strerror(error_code_);\n      return errno;\n    }\n#endif\n\n   public:\n    dispatcher(int err_code, char *&buf, std::size_t buf_size)\n      : error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {}\n\n    int run() {\n      return handle(strerror_r(error_code_, buffer_, buffer_size_));\n    }\n  };\n  return dispatcher(error_code, buffer, buffer_size).run();\n}\n\nvoid format_error_code(internal::buffer &out, int error_code,\n                       string_view message) FMT_NOEXCEPT {\n  // Report error code making sure that the output fits into\n  // inline_buffer_size to avoid dynamic memory allocation and potential\n  // bad_alloc.\n  out.resize(0);\n  static const char SEP[] = \": \";\n  static const char ERROR_STR[] = \"error \";\n  // Subtract 2 to account for terminating null characters in SEP and ERROR_STR.\n  std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2;\n  typedef internal::int_traits<int>::main_type main_type;\n  main_type abs_value = static_cast<main_type>(error_code);\n  if (internal::is_negative(error_code)) {\n    abs_value = 0 - abs_value;\n    ++error_code_size;\n  }\n  error_code_size += internal::to_unsigned(internal::count_digits(abs_value));\n  writer w(out);\n  if (message.size() <= inline_buffer_size - error_code_size) {\n    w.write(message);\n    w.write(SEP);\n  }\n  w.write(ERROR_STR);\n  w.write(error_code);\n  assert(out.size() <= inline_buffer_size);\n}\n\nvoid report_error(FormatFunc func, int error_code,\n                  string_view message) FMT_NOEXCEPT {\n  memory_buffer full_message;\n  func(full_message, error_code, message);\n  // Use Writer::data instead of Writer::c_str to avoid potential memory\n  // allocation.\n  std::fwrite(full_message.data(), full_message.size(), 1, stderr);\n  std::fputc('\\n', stderr);\n}\n}  // namespace\n\nFMT_FUNC size_t internal::count_code_points(basic_string_view<char8_t> s) {\n  const char8_t *data = s.data();\n  size_t num_code_points = 0;\n  for (size_t i = 0, size = s.size(); i != size; ++i) {\n    if ((data[i] & 0xc0) != 0x80)\n      ++num_code_points;\n  }\n  return num_code_points;\n}\n\n#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)\nnamespace internal {\n\ntemplate <typename Locale>\nlocale_ref::locale_ref(const Locale &loc) : locale_(&loc) {\n  static_assert(std::is_same<Locale, std::locale>::value, \"\");\n}\n\ntemplate <typename Locale>\nLocale locale_ref::get() const {\n  static_assert(std::is_same<Locale, std::locale>::value, \"\");\n  return locale_ ? *static_cast<const std::locale*>(locale_) : std::locale();\n}\n\ntemplate <typename Char>\nFMT_FUNC Char thousands_sep_impl(locale_ref loc) {\n  return std::use_facet<std::numpunct<Char> >(\n    loc.get<std::locale>()).thousands_sep();\n}\n}\n#else\ntemplate <typename Char>\nFMT_FUNC Char internal::thousands_sep_impl(locale_ref) {\n  return FMT_STATIC_THOUSANDS_SEPARATOR;\n}\n#endif\n\nFMT_FUNC void system_error::init(\n    int err_code, string_view format_str, format_args args) {\n  error_code_ = err_code;\n  memory_buffer buffer;\n  format_system_error(buffer, err_code, vformat(format_str, args));\n  std::runtime_error &base = *this;\n  base = std::runtime_error(to_string(buffer));\n}\n\nnamespace internal {\ntemplate <typename T>\nint char_traits<char>::format_float(\n    char *buf, std::size_t size, const char *format, int precision, T value) {\n  return precision < 0 ?\n      FMT_SNPRINTF(buf, size, format, value) :\n      FMT_SNPRINTF(buf, size, format, precision, value);\n}\n\ntemplate <typename T>\nint char_traits<wchar_t>::format_float(\n    wchar_t *buf, std::size_t size, const wchar_t *format, int precision,\n    T value) {\n  return precision < 0 ?\n      FMT_SWPRINTF(buf, size, format, value) :\n      FMT_SWPRINTF(buf, size, format, precision, value);\n}\n\ntemplate <typename T>\nconst char basic_data<T>::DIGITS[] =\n    \"0001020304050607080910111213141516171819\"\n    \"2021222324252627282930313233343536373839\"\n    \"4041424344454647484950515253545556575859\"\n    \"6061626364656667686970717273747576777879\"\n    \"8081828384858687888990919293949596979899\";\n\n#define FMT_POWERS_OF_10(factor) \\\n  factor * 10, \\\n  factor * 100, \\\n  factor * 1000, \\\n  factor * 10000, \\\n  factor * 100000, \\\n  factor * 1000000, \\\n  factor * 10000000, \\\n  factor * 100000000, \\\n  factor * 1000000000\n\ntemplate <typename T>\nconst uint32_t basic_data<T>::POWERS_OF_10_32[] = {\n  1, FMT_POWERS_OF_10(1)\n};\n\ntemplate <typename T>\nconst uint32_t basic_data<T>::ZERO_OR_POWERS_OF_10_32[] = {\n  0, FMT_POWERS_OF_10(1)\n};\n\ntemplate <typename T>\nconst uint64_t basic_data<T>::ZERO_OR_POWERS_OF_10_64[] = {\n  0,\n  FMT_POWERS_OF_10(1),\n  FMT_POWERS_OF_10(1000000000ull),\n  10000000000000000000ull\n};\n\n// Normalized 64-bit significands of pow(10, k), for k = -348, -340, ..., 340.\n// These are generated by support/compute-powers.py.\ntemplate <typename T>\nconst uint64_t basic_data<T>::POW10_SIGNIFICANDS[] = {\n  0xfa8fd5a0081c0288, 0xbaaee17fa23ebf76, 0x8b16fb203055ac76,\n  0xcf42894a5dce35ea, 0x9a6bb0aa55653b2d, 0xe61acf033d1a45df,\n  0xab70fe17c79ac6ca, 0xff77b1fcbebcdc4f, 0xbe5691ef416bd60c,\n  0x8dd01fad907ffc3c, 0xd3515c2831559a83, 0x9d71ac8fada6c9b5,\n  0xea9c227723ee8bcb, 0xaecc49914078536d, 0x823c12795db6ce57,\n  0xc21094364dfb5637, 0x9096ea6f3848984f, 0xd77485cb25823ac7,\n  0xa086cfcd97bf97f4, 0xef340a98172aace5, 0xb23867fb2a35b28e,\n  0x84c8d4dfd2c63f3b, 0xc5dd44271ad3cdba, 0x936b9fcebb25c996,\n  0xdbac6c247d62a584, 0xa3ab66580d5fdaf6, 0xf3e2f893dec3f126,\n  0xb5b5ada8aaff80b8, 0x87625f056c7c4a8b, 0xc9bcff6034c13053,\n  0x964e858c91ba2655, 0xdff9772470297ebd, 0xa6dfbd9fb8e5b88f,\n  0xf8a95fcf88747d94, 0xb94470938fa89bcf, 0x8a08f0f8bf0f156b,\n  0xcdb02555653131b6, 0x993fe2c6d07b7fac, 0xe45c10c42a2b3b06,\n  0xaa242499697392d3, 0xfd87b5f28300ca0e, 0xbce5086492111aeb,\n  0x8cbccc096f5088cc, 0xd1b71758e219652c, 0x9c40000000000000,\n  0xe8d4a51000000000, 0xad78ebc5ac620000, 0x813f3978f8940984,\n  0xc097ce7bc90715b3, 0x8f7e32ce7bea5c70, 0xd5d238a4abe98068,\n  0x9f4f2726179a2245, 0xed63a231d4c4fb27, 0xb0de65388cc8ada8,\n  0x83c7088e1aab65db, 0xc45d1df942711d9a, 0x924d692ca61be758,\n  0xda01ee641a708dea, 0xa26da3999aef774a, 0xf209787bb47d6b85,\n  0xb454e4a179dd1877, 0x865b86925b9bc5c2, 0xc83553c5c8965d3d,\n  0x952ab45cfa97a0b3, 0xde469fbd99a05fe3, 0xa59bc234db398c25,\n  0xf6c69a72a3989f5c, 0xb7dcbf5354e9bece, 0x88fcf317f22241e2,\n  0xcc20ce9bd35c78a5, 0x98165af37b2153df, 0xe2a0b5dc971f303a,\n  0xa8d9d1535ce3b396, 0xfb9b7cd9a4a7443c, 0xbb764c4ca7a44410,\n  0x8bab8eefb6409c1a, 0xd01fef10a657842c, 0x9b10a4e5e9913129,\n  0xe7109bfba19c0c9d, 0xac2820d9623bf429, 0x80444b5e7aa7cf85,\n  0xbf21e44003acdd2d, 0x8e679c2f5e44ff8f, 0xd433179d9c8cb841,\n  0x9e19db92b4e31ba9, 0xeb96bf6ebadf77d9, 0xaf87023b9bf0ee6b,\n};\n\n// Binary exponents of pow(10, k), for k = -348, -340, ..., 340, corresponding\n// to significands above.\ntemplate <typename T>\nconst int16_t basic_data<T>::POW10_EXPONENTS[] = {\n  -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007,  -980,  -954,\n   -927,  -901,  -874,  -847,  -821,  -794,  -768,  -741,  -715,  -688,  -661,\n   -635,  -608,  -582,  -555,  -529,  -502,  -475,  -449,  -422,  -396,  -369,\n   -343,  -316,  -289,  -263,  -236,  -210,  -183,  -157,  -130,  -103,   -77,\n    -50,   -24,     3,    30,    56,    83,   109,   136,   162,   189,   216,\n    242,   269,   295,   322,   348,   375,   402,   428,   455,   481,   508,\n    534,   561,   588,   614,   641,   667,   694,   720,   747,   774,   800,\n    827,   853,   880,   907,   933,   960,   986,  1013,  1039,  1066\n};\n\ntemplate <typename T> const char basic_data<T>::FOREGROUND_COLOR[] = \"\\x1b[38;2;\";\ntemplate <typename T> const char basic_data<T>::BACKGROUND_COLOR[] = \"\\x1b[48;2;\";\ntemplate <typename T> const char basic_data<T>::RESET_COLOR[] = \"\\x1b[0m\";\ntemplate <typename T> const wchar_t basic_data<T>::WRESET_COLOR[] = L\"\\x1b[0m\";\n\n// A handmade floating-point number f * pow(2, e).\nclass fp {\n private:\n  typedef uint64_t significand_type;\n\n  // All sizes are in bits.\n  static FMT_CONSTEXPR_DECL const int char_size =\n    std::numeric_limits<unsigned char>::digits;\n  // Subtract 1 to account for an implicit most significant bit in the\n  // normalized form.\n  static FMT_CONSTEXPR_DECL const int double_significand_size =\n    std::numeric_limits<double>::digits - 1;\n  static FMT_CONSTEXPR_DECL const uint64_t implicit_bit =\n    1ull << double_significand_size;\n\n public:\n  significand_type f;\n  int e;\n\n  static FMT_CONSTEXPR_DECL const int significand_size =\n    sizeof(significand_type) * char_size;\n\n  fp(): f(0), e(0) {}\n  fp(uint64_t f_val, int e_val): f(f_val), e(e_val) {}\n\n  // Constructs fp from an IEEE754 double. It is a template to prevent compile\n  // errors on platforms where double is not IEEE754.\n  template <typename Double>\n  explicit fp(Double d) {\n    // Assume double is in the format [sign][exponent][significand].\n    typedef std::numeric_limits<Double> limits;\n    const int double_size = static_cast<int>(sizeof(Double) * char_size);\n    const int exponent_size =\n      double_size - double_significand_size - 1;  // -1 for sign\n    const uint64_t significand_mask = implicit_bit - 1;\n    const uint64_t exponent_mask = (~0ull >> 1) & ~significand_mask;\n    const int exponent_bias = (1 << exponent_size) - limits::max_exponent - 1;\n    auto u = bit_cast<uint64_t>(d);\n    auto biased_e = (u & exponent_mask) >> double_significand_size;\n    f = u & significand_mask;\n    if (biased_e != 0)\n      f += implicit_bit;\n    else\n      biased_e = 1;  // Subnormals use biased exponent 1 (min exponent).\n    e = static_cast<int>(biased_e - exponent_bias - double_significand_size);\n  }\n\n  // Normalizes the value converted from double and multiplied by (1 << SHIFT).\n  template <int SHIFT = 0>\n  void normalize() {\n    // Handle subnormals.\n    auto shifted_implicit_bit = implicit_bit << SHIFT;\n    while ((f & shifted_implicit_bit) == 0) {\n      f <<= 1;\n      --e;\n    }\n    // Subtract 1 to account for hidden bit.\n    auto offset = significand_size - double_significand_size - SHIFT - 1;\n    f <<= offset;\n    e -= offset;\n  }\n\n  // Compute lower and upper boundaries (m^- and m^+ in the Grisu paper), where\n  // a boundary is a value half way between the number and its predecessor\n  // (lower) or successor (upper). The upper boundary is normalized and lower\n  // has the same exponent but may be not normalized.\n  void compute_boundaries(fp &lower, fp &upper) const {\n    lower = f == implicit_bit ?\n          fp((f << 2) - 1, e - 2) : fp((f << 1) - 1, e - 1);\n    upper = fp((f << 1) + 1, e - 1);\n    upper.normalize<1>();  // 1 is to account for the exponent shift above.\n    lower.f <<= lower.e - upper.e;\n    lower.e = upper.e;\n  }\n};\n\n// Returns an fp number representing x - y. Result may not be normalized.\ninline fp operator-(fp x, fp y) {\n  FMT_ASSERT(x.f >= y.f && x.e == y.e, \"invalid operands\");\n  return fp(x.f - y.f, x.e);\n}\n\n// Computes an fp number r with r.f = x.f * y.f / pow(2, 64) rounded to nearest\n// with half-up tie breaking, r.e = x.e + y.e + 64. Result may not be normalized.\nFMT_API fp operator*(fp x, fp y);\n\n// Returns cached power (of 10) c_k = c_k.f * pow(2, c_k.e) such that its\n// (binary) exponent satisfies min_exponent <= c_k.e <= min_exponent + 3.\nFMT_API fp get_cached_power(int min_exponent, int &pow10_exponent);\n\nFMT_FUNC fp operator*(fp x, fp y) {\n  // Multiply 32-bit parts of significands.\n  uint64_t mask = (1ULL << 32) - 1;\n  uint64_t a = x.f >> 32, b = x.f & mask;\n  uint64_t c = y.f >> 32, d = y.f & mask;\n  uint64_t ac = a * c, bc = b * c, ad = a * d, bd = b * d;\n  // Compute mid 64-bit of result and round.\n  uint64_t mid = (bd >> 32) + (ad & mask) + (bc & mask) + (1U << 31);\n  return fp(ac + (ad >> 32) + (bc >> 32) + (mid >> 32), x.e + y.e + 64);\n}\n\nFMT_FUNC fp get_cached_power(int min_exponent, int &pow10_exponent) {\n  const double one_over_log2_10 = 0.30102999566398114;  // 1 / log2(10)\n  int index = static_cast<int>(std::ceil(\n        (min_exponent + fp::significand_size - 1) * one_over_log2_10));\n  // Decimal exponent of the first (smallest) cached power of 10.\n  const int first_dec_exp = -348;\n  // Difference between 2 consecutive decimal exponents in cached powers of 10.\n  const int dec_exp_step = 8;\n  index = (index - first_dec_exp - 1) / dec_exp_step + 1;\n  pow10_exponent = first_dec_exp + index * dec_exp_step;\n  return fp(data::POW10_SIGNIFICANDS[index], data::POW10_EXPONENTS[index]);\n}\n\nFMT_FUNC bool grisu2_round(\n    char *buf, int &size, int max_digits, uint64_t delta,\n    uint64_t remainder, uint64_t exp, uint64_t diff, int &exp10) {\n  while (remainder < diff && delta - remainder >= exp &&\n        (remainder + exp < diff || diff - remainder > remainder + exp - diff)) {\n    --buf[size - 1];\n    remainder += exp;\n  }\n  if (size > max_digits) {\n    --size;\n    ++exp10;\n    if (buf[size] >= '5')\n      return false;\n  }\n  return true;\n}\n\n// Generates output using Grisu2 digit-gen algorithm.\nFMT_FUNC bool grisu2_gen_digits(\n    char *buf, int &size, uint32_t hi, uint64_t lo, int &exp,\n    uint64_t delta, const fp &one, const fp &diff, int max_digits) {\n  // Generate digits for the most significant part (hi).\n  while (exp > 0) {\n    uint32_t digit = 0;\n    // This optimization by miloyip reduces the number of integer divisions by\n    // one per iteration.\n    switch (exp) {\n    case 10: digit = hi / 1000000000; hi %= 1000000000; break;\n    case  9: digit = hi /  100000000; hi %=  100000000; break;\n    case  8: digit = hi /   10000000; hi %=   10000000; break;\n    case  7: digit = hi /    1000000; hi %=    1000000; break;\n    case  6: digit = hi /     100000; hi %=     100000; break;\n    case  5: digit = hi /      10000; hi %=      10000; break;\n    case  4: digit = hi /       1000; hi %=       1000; break;\n    case  3: digit = hi /        100; hi %=        100; break;\n    case  2: digit = hi /         10; hi %=         10; break;\n    case  1: digit = hi;              hi =           0; break;\n    default:\n      FMT_ASSERT(false, \"invalid number of digits\");\n    }\n    if (digit != 0 || size != 0)\n      buf[size++] = static_cast<char>('0' + digit);\n    --exp;\n    uint64_t remainder = (static_cast<uint64_t>(hi) << -one.e) + lo;\n    if (remainder <= delta || size > max_digits) {\n      return grisu2_round(\n            buf, size, max_digits, delta, remainder,\n            static_cast<uint64_t>(data::POWERS_OF_10_32[exp]) << -one.e,\n            diff.f, exp);\n    }\n  }\n  // Generate digits for the least significant part (lo).\n  for (;;) {\n    lo *= 10;\n    delta *= 10;\n    char digit = static_cast<char>(lo >> -one.e);\n    if (digit != 0 || size != 0)\n      buf[size++] = static_cast<char>('0' + digit);\n    lo &= one.f - 1;\n    --exp;\n    if (lo < delta || size > max_digits) {\n      return grisu2_round(buf, size, max_digits, delta, lo, one.f,\n                          diff.f * data::POWERS_OF_10_32[-exp], exp);\n    }\n  }\n}\n\n#if FMT_CLANG_VERSION\n# define FMT_FALLTHROUGH [[clang::fallthrough]];\n#elif FMT_GCC_VERSION >= 700\n# define FMT_FALLTHROUGH [[gnu::fallthrough]];\n#else\n# define FMT_FALLTHROUGH\n#endif\n\nstruct gen_digits_params {\n  int num_digits;\n  bool fixed;\n  bool upper;\n  bool trailing_zeros;\n};\n\nstruct prettify_handler {\n  char *data;\n  ptrdiff_t size;\n  buffer &buf;\n\n  explicit prettify_handler(buffer &b, ptrdiff_t n)\n    : data(b.data()), size(n), buf(b) {}\n  ~prettify_handler() {\n    assert(buf.size() >= to_unsigned(size));\n    buf.resize(to_unsigned(size));\n  }\n\n  template <typename F>\n  void insert(ptrdiff_t pos, ptrdiff_t n, F f) {\n    std::memmove(data + pos + n, data + pos, to_unsigned(size - pos));\n    f(data + pos);\n    size += n;\n  }\n\n  void insert(ptrdiff_t pos, char c) {\n    std::memmove(data + pos + 1, data + pos, to_unsigned(size - pos));\n    data[pos] = c;\n    ++size;\n  }\n\n  void append(ptrdiff_t n, char c) {\n    std::uninitialized_fill_n(data + size, n, c);\n    size += n;\n  }\n\n  void append(char c) { data[size++] = c; }\n\n  void remove_trailing(char c) {\n    while (data[size - 1] == c) --size;\n  }\n};\n\n// Writes the exponent exp in the form \"[+-]d{2,3}\" to buffer.\ntemplate <typename Handler>\nFMT_FUNC void write_exponent(int exp, Handler &&h) {\n  FMT_ASSERT(-1000 < exp && exp < 1000, \"exponent out of range\");\n  if (exp < 0) {\n    h.append('-');\n    exp = -exp;\n  } else {\n    h.append('+');\n  }\n  if (exp >= 100) {\n    h.append(static_cast<char>('0' + exp / 100));\n    exp %= 100;\n    const char *d = data::DIGITS + exp * 2;\n    h.append(d[0]);\n    h.append(d[1]);\n  } else {\n    const char *d = data::DIGITS + exp * 2;\n    h.append(d[0]);\n    h.append(d[1]);\n  }\n}\n\nstruct fill {\n  size_t n;\n  void operator()(char *buf) const {\n    buf[0] = '0';\n    buf[1] = '.';\n    std::uninitialized_fill_n(buf + 2, n, '0');\n  }\n};\n\n// The number is given as v = f * pow(10, exp), where f has size digits.\ntemplate <typename Handler>\nFMT_FUNC void grisu2_prettify(const gen_digits_params &params,\n                              int size, int exp, Handler &&handler) {\n  if (!params.fixed) {\n    // Insert a decimal point after the first digit and add an exponent.\n    handler.insert(1, '.');\n    exp += size - 1;\n    if (size < params.num_digits)\n      handler.append(params.num_digits - size, '0');\n    handler.append(params.upper ? 'E' : 'e');\n    write_exponent(exp, handler);\n    return;\n  }\n  // pow(10, full_exp - 1) <= v <= pow(10, full_exp).\n  int full_exp = size + exp;\n  const int exp_threshold = 21;\n  if (size <= full_exp && full_exp <= exp_threshold) {\n    // 1234e7 -> 12340000000[.0+]\n    handler.append(full_exp - size, '0');\n    int num_zeros = params.num_digits - full_exp;\n    if (num_zeros > 0 && params.trailing_zeros) {\n      handler.append('.');\n      handler.append(num_zeros, '0');\n    }\n  } else if (full_exp > 0) {\n    // 1234e-2 -> 12.34[0+]\n    handler.insert(full_exp, '.');\n    if (!params.trailing_zeros) {\n      // Remove trailing zeros.\n      handler.remove_trailing('0');\n    } else if (params.num_digits > size) {\n      // Add trailing zeros.\n      ptrdiff_t num_zeros = params.num_digits - size;\n      handler.append(num_zeros, '0');\n    }\n  } else {\n    // 1234e-6 -> 0.001234\n    handler.insert(0, 2 - full_exp, fill{to_unsigned(-full_exp)});\n  }\n}\n\nstruct char_counter {\n  ptrdiff_t size;\n\n  template <typename F>\n  void insert(ptrdiff_t, ptrdiff_t n, F) { size += n; }\n  void insert(ptrdiff_t, char) { ++size; }\n  void append(ptrdiff_t n, char) { size += n; }\n  void append(char) { ++size; }\n  void remove_trailing(char) {}\n};\n\n// Converts format specifiers into parameters for digit generation and computes\n// output buffer size for a number in the range [pow(10, exp - 1), pow(10, exp)\n// or 0 if exp == 1.\nFMT_FUNC gen_digits_params process_specs(const core_format_specs &specs,\n                                         int exp, buffer &buf) {\n  auto params = gen_digits_params();\n  int num_digits = specs.precision >= 0 ? specs.precision : 6;\n  switch (specs.type) {\n  case 'G':\n    params.upper = true;\n    FMT_FALLTHROUGH\n  case '\\0': case 'g':\n    params.trailing_zeros = (specs.flags & HASH_FLAG) != 0;\n    if (-4 <= exp && exp < num_digits + 1) {\n      params.fixed = true;\n      if (!specs.type && params.trailing_zeros && exp >= 0)\n        num_digits = exp + 1;\n    }\n    break;\n  case 'F':\n    params.upper = true;\n    FMT_FALLTHROUGH\n  case 'f': {\n    params.fixed = true;\n    params.trailing_zeros = true;\n    int adjusted_min_digits = num_digits + exp;\n    if (adjusted_min_digits > 0)\n      num_digits = adjusted_min_digits;\n    break;\n  }\n  case 'E':\n    params.upper = true;\n    FMT_FALLTHROUGH\n  case 'e':\n    ++num_digits;\n    break;\n  }\n  params.num_digits = num_digits;\n  char_counter counter{num_digits};\n  grisu2_prettify(params, params.num_digits, exp - num_digits, counter);\n  buf.resize(to_unsigned(counter.size));\n  return params;\n}\n\ntemplate <typename Double>\nFMT_FUNC typename std::enable_if<sizeof(Double) == sizeof(uint64_t), bool>::type\n    grisu2_format(Double value, buffer &buf, core_format_specs specs) {\n  FMT_ASSERT(value >= 0, \"value is negative\");\n  if (value == 0) {\n    gen_digits_params params = process_specs(specs, 1, buf);\n    const size_t size = 1;\n    buf[0] = '0';\n    grisu2_prettify(params, size, 0, prettify_handler(buf, size));\n    return true;\n  }\n\n  fp fp_value(value);\n  fp lower, upper;  // w^- and w^+ in the Grisu paper.\n  fp_value.compute_boundaries(lower, upper);\n\n  // Find a cached power of 10 close to 1 / upper and use it to scale upper.\n  const int min_exp = -60;  // alpha in Grisu.\n  int cached_exp = 0;  // K in Grisu.\n  auto cached_pow = get_cached_power(  // \\tilde{c}_{-k} in Grisu.\n      min_exp - (upper.e + fp::significand_size), cached_exp);\n  cached_exp = -cached_exp;\n  upper = upper * cached_pow;  // \\tilde{M}^+ in Grisu.\n  --upper.f;  // \\tilde{M}^+ - 1 ulp -> M^+_{\\downarrow}.\n  fp one(1ull << -upper.e, upper.e);\n  // hi (p1 in Grisu) contains the most significant digits of scaled_upper.\n  // hi = floor(upper / one).\n  uint32_t hi = static_cast<uint32_t>(upper.f >> -one.e);\n  int exp = count_digits(hi);  // kappa in Grisu.\n  gen_digits_params params = process_specs(specs, cached_exp + exp, buf);\n  fp_value.normalize();\n  fp scaled_value = fp_value * cached_pow;\n  lower = lower * cached_pow;  // \\tilde{M}^- in Grisu.\n  ++lower.f;  // \\tilde{M}^- + 1 ulp -> M^-_{\\uparrow}.\n  uint64_t delta = upper.f - lower.f;\n  fp diff = upper - scaled_value; // wp_w in Grisu.\n  // lo (p2 in Grisu) contains the least significants digits of scaled_upper.\n  // lo = supper % one.\n  uint64_t lo = upper.f & (one.f - 1);\n  int size = 0;\n  if (!grisu2_gen_digits(buf.data(), size, hi, lo, exp, delta, one, diff,\n                         params.num_digits)) {\n    buf.clear();\n    return false;\n  }\n  grisu2_prettify(params, size, cached_exp + exp, prettify_handler(buf, size));\n  return true;\n}\n\ntemplate <typename Double>\nvoid sprintf_format(Double value, internal::buffer &buf,\n                    core_format_specs spec) {\n  // Buffer capacity must be non-zero, otherwise MSVC's vsnprintf_s will fail.\n  FMT_ASSERT(buf.capacity() != 0, \"empty buffer\");\n\n  // Build format string.\n  enum { MAX_FORMAT_SIZE = 10}; // longest format: %#-*.*Lg\n  char format[MAX_FORMAT_SIZE];\n  char *format_ptr = format;\n  *format_ptr++ = '%';\n  if (spec.has(HASH_FLAG))\n    *format_ptr++ = '#';\n  if (spec.precision >= 0) {\n    *format_ptr++ = '.';\n    *format_ptr++ = '*';\n  }\n  if (std::is_same<Double, long double>::value)\n    *format_ptr++ = 'L';\n  *format_ptr++ = spec.type;\n  *format_ptr = '\\0';\n\n  // Format using snprintf.\n  char *start = FMT_NULL;\n  for (;;) {\n    std::size_t buffer_size = buf.capacity();\n    start = &buf[0];\n    int result = internal::char_traits<char>::format_float(\n        start, buffer_size, format, spec.precision, value);\n    if (result >= 0) {\n      unsigned n = internal::to_unsigned(result);\n      if (n < buf.capacity()) {\n        buf.resize(n);\n        break;  // The buffer is large enough - continue with formatting.\n      }\n      buf.reserve(n + 1);\n    } else {\n      // If result is negative we ask to increase the capacity by at least 1,\n      // but as std::vector, the buffer grows exponentially.\n      buf.reserve(buf.capacity() + 1);\n    }\n  }\n}\n}  // namespace internal\n\n#if FMT_USE_WINDOWS_H\n\nFMT_FUNC internal::utf8_to_utf16::utf8_to_utf16(string_view s) {\n  static const char ERROR_MSG[] = \"cannot convert string from UTF-8 to UTF-16\";\n  if (s.size() > INT_MAX)\n    FMT_THROW(windows_error(ERROR_INVALID_PARAMETER, ERROR_MSG));\n  int s_size = static_cast<int>(s.size());\n  if (s_size == 0) {\n    // MultiByteToWideChar does not support zero length, handle separately.\n    buffer_.resize(1);\n    buffer_[0] = 0;\n    return;\n  }\n\n  int length = MultiByteToWideChar(\n      CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, FMT_NULL, 0);\n  if (length == 0)\n    FMT_THROW(windows_error(GetLastError(), ERROR_MSG));\n  buffer_.resize(length + 1);\n  length = MultiByteToWideChar(\n    CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, &buffer_[0], length);\n  if (length == 0)\n    FMT_THROW(windows_error(GetLastError(), ERROR_MSG));\n  buffer_[length] = 0;\n}\n\nFMT_FUNC internal::utf16_to_utf8::utf16_to_utf8(wstring_view s) {\n  if (int error_code = convert(s)) {\n    FMT_THROW(windows_error(error_code,\n        \"cannot convert string from UTF-16 to UTF-8\"));\n  }\n}\n\nFMT_FUNC int internal::utf16_to_utf8::convert(wstring_view s) {\n  if (s.size() > INT_MAX)\n    return ERROR_INVALID_PARAMETER;\n  int s_size = static_cast<int>(s.size());\n  if (s_size == 0) {\n    // WideCharToMultiByte does not support zero length, handle separately.\n    buffer_.resize(1);\n    buffer_[0] = 0;\n    return 0;\n  }\n\n  int length = WideCharToMultiByte(\n        CP_UTF8, 0, s.data(), s_size, FMT_NULL, 0, FMT_NULL, FMT_NULL);\n  if (length == 0)\n    return GetLastError();\n  buffer_.resize(length + 1);\n  length = WideCharToMultiByte(\n    CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, FMT_NULL, FMT_NULL);\n  if (length == 0)\n    return GetLastError();\n  buffer_[length] = 0;\n  return 0;\n}\n\nFMT_FUNC void windows_error::init(\n    int err_code, string_view format_str, format_args args) {\n  error_code_ = err_code;\n  memory_buffer buffer;\n  internal::format_windows_error(buffer, err_code, vformat(format_str, args));\n  std::runtime_error &base = *this;\n  base = std::runtime_error(to_string(buffer));\n}\n\nFMT_FUNC void internal::format_windows_error(\n    internal::buffer &out, int error_code, string_view message) FMT_NOEXCEPT {\n  FMT_TRY {\n    wmemory_buffer buf;\n    buf.resize(inline_buffer_size);\n    for (;;) {\n      wchar_t *system_message = &buf[0];\n      int result = FormatMessageW(\n          FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,\n          FMT_NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),\n          system_message, static_cast<uint32_t>(buf.size()), FMT_NULL);\n      if (result != 0) {\n        utf16_to_utf8 utf8_message;\n        if (utf8_message.convert(system_message) == ERROR_SUCCESS) {\n          writer w(out);\n          w.write(message);\n          w.write(\": \");\n          w.write(utf8_message);\n          return;\n        }\n        break;\n      }\n      if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)\n        break;  // Can't get error message, report error code instead.\n      buf.resize(buf.size() * 2);\n    }\n  } FMT_CATCH(...) {}\n  format_error_code(out, error_code, message);\n}\n\n#endif  // FMT_USE_WINDOWS_H\n\nFMT_FUNC void format_system_error(\n    internal::buffer &out, int error_code, string_view message) FMT_NOEXCEPT {\n  FMT_TRY {\n    memory_buffer buf;\n    buf.resize(inline_buffer_size);\n    for (;;) {\n      char *system_message = &buf[0];\n      int result = safe_strerror(error_code, system_message, buf.size());\n      if (result == 0) {\n        writer w(out);\n        w.write(message);\n        w.write(\": \");\n        w.write(system_message);\n        return;\n      }\n      if (result != ERANGE)\n        break;  // Can't get error message, report error code instead.\n      buf.resize(buf.size() * 2);\n    }\n  } FMT_CATCH(...) {}\n  format_error_code(out, error_code, message);\n}\n\nFMT_FUNC void internal::error_handler::on_error(const char *message) {\n  FMT_THROW(format_error(message));\n}\n\nFMT_FUNC void report_system_error(\n    int error_code, fmt::string_view message) FMT_NOEXCEPT {\n  report_error(format_system_error, error_code, message);\n}\n\n#if FMT_USE_WINDOWS_H\nFMT_FUNC void report_windows_error(\n    int error_code, fmt::string_view message) FMT_NOEXCEPT {\n  report_error(internal::format_windows_error, error_code, message);\n}\n#endif\n\nFMT_FUNC void vprint(std::FILE *f, string_view format_str, format_args args) {\n  memory_buffer buffer;\n  internal::vformat_to(buffer, format_str,\n                       basic_format_args<buffer_context<char>::type>(args));\n  std::fwrite(buffer.data(), 1, buffer.size(), f);\n}\n\nFMT_FUNC void vprint(std::FILE *f, wstring_view format_str, wformat_args args) {\n  wmemory_buffer buffer;\n  internal::vformat_to(buffer, format_str, args);\n  std::fwrite(buffer.data(), sizeof(wchar_t), buffer.size(), f);\n}\n\nFMT_FUNC void vprint(string_view format_str, format_args args) {\n  vprint(stdout, format_str, args);\n}\n\nFMT_FUNC void vprint(wstring_view format_str, wformat_args args) {\n  vprint(stdout, format_str, args);\n}\n\nFMT_END_NAMESPACE\n\n#ifdef _MSC_VER\n# pragma warning(pop)\n#endif\n\n#endif  // FMT_FORMAT_INL_H_\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/fmt/bundled/format.h",
    "content": "/*\n Formatting library for C++\n\n Copyright (c) 2012 - present, Victor Zverovich\n All rights reserved.\n\n Redistribution and use in source and binary forms, with or without\n modification, are permitted provided that the following conditions are met:\n\n 1. Redistributions of source code must retain the above copyright notice, this\n    list of conditions and the following disclaimer.\n 2. Redistributions in binary form must reproduce the above copyright notice,\n    this list of conditions and the following disclaimer in the documentation\n    and/or other materials provided with the distribution.\n\n THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR\n ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n#ifndef FMT_FORMAT_H_\n#define FMT_FORMAT_H_\n\n#include <algorithm>\n#include <cassert>\n#include <cmath>\n#include <cstring>\n#include <limits>\n#include <memory>\n#include <stdexcept>\n#include <stdint.h>\n\n#ifdef __clang__\n# define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__)\n#else\n# define FMT_CLANG_VERSION 0\n#endif\n\n#ifdef __INTEL_COMPILER\n# define FMT_ICC_VERSION __INTEL_COMPILER\n#elif defined(__ICL)\n# define FMT_ICC_VERSION __ICL\n#else\n# define FMT_ICC_VERSION 0\n#endif\n\n#ifdef __NVCC__\n# define FMT_CUDA_VERSION (__CUDACC_VER_MAJOR__ * 100 + __CUDACC_VER_MINOR__)\n#else\n# define FMT_CUDA_VERSION 0\n#endif\n\n#include \"core.h\"\n\n#if FMT_GCC_VERSION >= 406 || FMT_CLANG_VERSION\n# pragma GCC diagnostic push\n\n// Disable the warning about declaration shadowing because it affects too\n// many valid cases.\n# pragma GCC diagnostic ignored \"-Wshadow\"\n\n// Disable the warning about nonliteral format strings because we construct\n// them dynamically when falling back to snprintf for FP formatting.\n# pragma GCC diagnostic ignored \"-Wformat-nonliteral\"\n#endif\n\n# if FMT_CLANG_VERSION\n#  pragma GCC diagnostic ignored \"-Wgnu-string-literal-operator-template\"\n# endif\n\n#ifdef _SECURE_SCL\n# define FMT_SECURE_SCL _SECURE_SCL\n#else\n# define FMT_SECURE_SCL 0\n#endif\n\n#if FMT_SECURE_SCL\n# include <iterator>\n#endif\n\n#ifdef __has_builtin\n# define FMT_HAS_BUILTIN(x) __has_builtin(x)\n#else\n# define FMT_HAS_BUILTIN(x) 0\n#endif\n\n#ifdef __GNUC_LIBSTD__\n# define FMT_GNUC_LIBSTD_VERSION (__GNUC_LIBSTD__ * 100 + __GNUC_LIBSTD_MINOR__)\n#endif\n\n#ifndef FMT_THROW\n# if FMT_EXCEPTIONS\n#  if FMT_MSC_VER\nFMT_BEGIN_NAMESPACE\nnamespace internal {\ntemplate <typename Exception>\ninline void do_throw(const Exception &x) {\n  // Silence unreachable code warnings in MSVC because these are nearly\n  // impossible to fix in a generic code.\n  volatile bool b = true;\n  if (b)\n    throw x;\n}\n}\nFMT_END_NAMESPACE\n#   define FMT_THROW(x) fmt::internal::do_throw(x)\n#  else\n#   define FMT_THROW(x) throw x\n#  endif\n# else\n#  define FMT_THROW(x) do { static_cast<void>(sizeof(x)); assert(false); } while(false);\n# endif\n#endif\n\n#ifndef FMT_USE_USER_DEFINED_LITERALS\n// For Intel's compiler and NVIDIA's compiler both it and the system gcc/msc\n// must support UDLs.\n# if (FMT_HAS_FEATURE(cxx_user_literals) || \\\n      FMT_GCC_VERSION >= 407 || FMT_MSC_VER >= 1900) && \\\n      (!(FMT_ICC_VERSION || FMT_CUDA_VERSION) || \\\n       FMT_ICC_VERSION >= 1500 || FMT_CUDA_VERSION >= 700)\n#  define FMT_USE_USER_DEFINED_LITERALS 1\n# else\n#  define FMT_USE_USER_DEFINED_LITERALS 0\n# endif\n#endif\n\n// EDG C++ Front End based compilers (icc, nvcc) do not currently support UDL\n// templates.\n#if FMT_USE_USER_DEFINED_LITERALS && \\\n    FMT_ICC_VERSION == 0 && \\\n    FMT_CUDA_VERSION == 0 && \\\n    ((FMT_GCC_VERSION >= 600 && __cplusplus >= 201402L) || \\\n    (defined(FMT_CLANG_VERSION) && FMT_CLANG_VERSION >= 304))\n# define FMT_UDL_TEMPLATE 1\n#else\n# define FMT_UDL_TEMPLATE 0\n#endif\n\n#ifndef FMT_USE_EXTERN_TEMPLATES\n# ifndef FMT_HEADER_ONLY\n#  define FMT_USE_EXTERN_TEMPLATES \\\n     ((FMT_CLANG_VERSION >= 209 && __cplusplus >= 201103L) || \\\n      (FMT_GCC_VERSION >= 303 && FMT_HAS_GXX_CXX11))\n# else\n#  define FMT_USE_EXTERN_TEMPLATES 0\n# endif\n#endif\n\n#if FMT_HAS_GXX_CXX11 || FMT_HAS_FEATURE(cxx_trailing_return) || \\\n    FMT_MSC_VER >= 1600\n# define FMT_USE_TRAILING_RETURN 1\n#else\n# define FMT_USE_TRAILING_RETURN 0\n#endif\n\n#ifndef FMT_USE_GRISU\n# define FMT_USE_GRISU 0\n//# define FMT_USE_GRISU std::numeric_limits<double>::is_iec559\n#endif\n\n// __builtin_clz is broken in clang with Microsoft CodeGen:\n// https://github.com/fmtlib/fmt/issues/519\n#ifndef _MSC_VER\n# if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clz)\n#  define FMT_BUILTIN_CLZ(n) __builtin_clz(n)\n# endif\n\n# if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clzll)\n#  define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n)\n# endif\n#endif\n\n// Some compilers masquerade as both MSVC and GCC-likes or otherwise support\n// __builtin_clz and __builtin_clzll, so only define FMT_BUILTIN_CLZ using the\n// MSVC intrinsics if the clz and clzll builtins are not available.\n#if FMT_MSC_VER && !defined(FMT_BUILTIN_CLZLL) && !defined(_MANAGED)\n# include <intrin.h>  // _BitScanReverse, _BitScanReverse64\n\nFMT_BEGIN_NAMESPACE\nnamespace internal {\n// Avoid Clang with Microsoft CodeGen's -Wunknown-pragmas warning.\n# ifndef __clang__\n#  pragma intrinsic(_BitScanReverse)\n# endif\ninline uint32_t clz(uint32_t x) {\n  unsigned long r = 0;\n  _BitScanReverse(&r, x);\n\n  assert(x != 0);\n  // Static analysis complains about using uninitialized data\n  // \"r\", but the only way that can happen is if \"x\" is 0,\n  // which the callers guarantee to not happen.\n# pragma warning(suppress: 6102)\n  return 31 - r;\n}\n# define FMT_BUILTIN_CLZ(n) fmt::internal::clz(n)\n\n# if defined(_WIN64) && !defined(__clang__)\n#  pragma intrinsic(_BitScanReverse64)\n# endif\n\ninline uint32_t clzll(uint64_t x) {\n  unsigned long r = 0;\n# ifdef _WIN64\n  _BitScanReverse64(&r, x);\n# else\n  // Scan the high 32 bits.\n  if (_BitScanReverse(&r, static_cast<uint32_t>(x >> 32)))\n    return 63 - (r + 32);\n\n  // Scan the low 32 bits.\n  _BitScanReverse(&r, static_cast<uint32_t>(x));\n# endif\n\n  assert(x != 0);\n  // Static analysis complains about using uninitialized data\n  // \"r\", but the only way that can happen is if \"x\" is 0,\n  // which the callers guarantee to not happen.\n# pragma warning(suppress: 6102)\n  return 63 - r;\n}\n# define FMT_BUILTIN_CLZLL(n) fmt::internal::clzll(n)\n}\nFMT_END_NAMESPACE\n#endif\n\nFMT_BEGIN_NAMESPACE\nnamespace internal {\n\n// An equivalent of `*reinterpret_cast<Dest*>(&source)` that doesn't produce\n// undefined behavior (e.g. due to type aliasing).\n// Example: uint64_t d = bit_cast<uint64_t>(2.718);\ntemplate <typename Dest, typename Source>\ninline Dest bit_cast(const Source& source) {\n  static_assert(sizeof(Dest) == sizeof(Source), \"size mismatch\");\n  Dest dest;\n  std::memcpy(&dest, &source, sizeof(dest));\n  return dest;\n}\n\n// An implementation of begin and end for pre-C++11 compilers such as gcc 4.\ntemplate <typename C>\nFMT_CONSTEXPR auto begin(const C &c) -> decltype(c.begin()) {\n  return c.begin();\n}\ntemplate <typename T, std::size_t N>\nFMT_CONSTEXPR T *begin(T (&array)[N]) FMT_NOEXCEPT { return array; }\ntemplate <typename C>\nFMT_CONSTEXPR auto end(const C &c) -> decltype(c.end()) { return c.end(); }\ntemplate <typename T, std::size_t N>\nFMT_CONSTEXPR T *end(T (&array)[N]) FMT_NOEXCEPT { return array + N; }\n\n// For std::result_of in gcc 4.4.\ntemplate <typename Result>\nstruct function {\n  template <typename T>\n  struct result { typedef Result type; };\n};\n\nstruct dummy_int {\n  int data[2];\n  operator int() const { return 0; }\n};\ntypedef std::numeric_limits<internal::dummy_int> fputil;\n\n// Dummy implementations of system functions called if the latter are not\n// available.\ninline dummy_int isinf(...) { return dummy_int(); }\ninline dummy_int _finite(...) { return dummy_int(); }\ninline dummy_int isnan(...) { return dummy_int(); }\ninline dummy_int _isnan(...) { return dummy_int(); }\n\ntemplate <typename Allocator>\ntypename Allocator::value_type *allocate(Allocator& alloc, std::size_t n) {\n#if __cplusplus >= 201103L || FMT_MSC_VER >= 1700\n  return std::allocator_traits<Allocator>::allocate(alloc, n);\n#else\n  return alloc.allocate(n);\n#endif\n}\n\n// A helper function to suppress bogus \"conditional expression is constant\"\n// warnings.\ntemplate <typename T>\ninline T const_check(T value) { return value; }\n}  // namespace internal\nFMT_END_NAMESPACE\n\nnamespace std {\n// Standard permits specialization of std::numeric_limits. This specialization\n// is used to resolve ambiguity between isinf and std::isinf in glibc:\n// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=48891\n// and the same for isnan.\ntemplate <>\nclass numeric_limits<fmt::internal::dummy_int> :\n    public std::numeric_limits<int> {\n public:\n  // Portable version of isinf.\n  template <typename T>\n  static bool isinfinity(T x) {\n    using namespace fmt::internal;\n    // The resolution \"priority\" is:\n    // isinf macro > std::isinf > ::isinf > fmt::internal::isinf\n    if (const_check(sizeof(isinf(x)) != sizeof(fmt::internal::dummy_int)))\n      return isinf(x) != 0;\n    return !_finite(static_cast<double>(x));\n  }\n\n  // Portable version of isnan.\n  template <typename T>\n  static bool isnotanumber(T x) {\n    using namespace fmt::internal;\n    if (const_check(sizeof(isnan(x)) != sizeof(fmt::internal::dummy_int)))\n      return isnan(x) != 0;\n    return _isnan(static_cast<double>(x)) != 0;\n  }\n};\n}  // namespace std\n\nFMT_BEGIN_NAMESPACE\ntemplate <typename Range>\nclass basic_writer;\n\ntemplate <typename OutputIt, typename T = typename OutputIt::value_type>\nclass output_range {\n private:\n  OutputIt it_;\n\n  // Unused yet.\n  typedef void sentinel;\n  sentinel end() const;\n\n public:\n  typedef OutputIt iterator;\n  typedef T value_type;\n\n  explicit output_range(OutputIt it): it_(it) {}\n  OutputIt begin() const { return it_; }\n};\n\n// A range where begin() returns back_insert_iterator.\ntemplate <typename Container>\nclass back_insert_range:\n    public output_range<std::back_insert_iterator<Container>> {\n  typedef output_range<std::back_insert_iterator<Container>> base;\n public:\n  typedef typename Container::value_type value_type;\n\n  back_insert_range(Container &c): base(std::back_inserter(c)) {}\n  back_insert_range(typename base::iterator it): base(it) {}\n};\n\ntypedef basic_writer<back_insert_range<internal::buffer>> writer;\ntypedef basic_writer<back_insert_range<internal::wbuffer>> wwriter;\n\n/** A formatting error such as invalid format string. */\nclass format_error : public std::runtime_error {\n public:\n  explicit format_error(const char *message)\n  : std::runtime_error(message) {}\n\n  explicit format_error(const std::string &message)\n  : std::runtime_error(message) {}\n};\n\nnamespace internal {\n\n#if FMT_SECURE_SCL\ntemplate <typename T>\nstruct checked { typedef stdext::checked_array_iterator<T*> type; };\n\n// Make a checked iterator to avoid warnings on MSVC.\ntemplate <typename T>\ninline stdext::checked_array_iterator<T*> make_checked(T *p, std::size_t size) {\n  return {p, size};\n}\n#else\ntemplate <typename T>\nstruct checked { typedef T *type; };\ntemplate <typename T>\ninline T *make_checked(T *p, std::size_t) { return p; }\n#endif\n\ntemplate <typename T>\ntemplate <typename U>\nvoid basic_buffer<T>::append(const U *begin, const U *end) {\n  std::size_t new_size = size_ + internal::to_unsigned(end - begin);\n  reserve(new_size);\n  std::uninitialized_copy(begin, end,\n                          internal::make_checked(ptr_, capacity_) + size_);\n  size_ = new_size;\n}\n}  // namespace internal\n\n// C++20 feature test, since r346892 Clang considers char8_t a fundamental\n// type in this mode. If this is the case __cpp_char8_t will be defined.\n#if !defined(__cpp_char8_t)\n// A UTF-8 code unit type.\nenum char8_t: unsigned char {};\n#endif\n\n// A UTF-8 string view.\nclass u8string_view : public basic_string_view<char8_t> {\n public:\n  typedef char8_t char_type;\n\n  u8string_view(const char *s):\n    basic_string_view<char8_t>(reinterpret_cast<const char8_t*>(s)) {}\n  u8string_view(const char *s, size_t count) FMT_NOEXCEPT:\n    basic_string_view<char8_t>(reinterpret_cast<const char8_t*>(s), count) {}\n};\n\n#if FMT_USE_USER_DEFINED_LITERALS\ninline namespace literals {\ninline u8string_view operator\"\" _u(const char *s, std::size_t n) {\n  return {s, n};\n}\n}\n#endif\n\n// The number of characters to store in the basic_memory_buffer object itself\n// to avoid dynamic memory allocation.\nenum { inline_buffer_size = 500 };\n\n/**\n  \\rst\n  A dynamically growing memory buffer for trivially copyable/constructible types\n  with the first ``SIZE`` elements stored in the object itself.\n\n  You can use one of the following typedefs for common character types:\n\n  +----------------+------------------------------+\n  | Type           | Definition                   |\n  +================+==============================+\n  | memory_buffer  | basic_memory_buffer<char>    |\n  +----------------+------------------------------+\n  | wmemory_buffer | basic_memory_buffer<wchar_t> |\n  +----------------+------------------------------+\n\n  **Example**::\n\n     fmt::memory_buffer out;\n     format_to(out, \"The answer is {}.\", 42);\n\n  This will append the following output to the ``out`` object:\n\n  .. code-block:: none\n\n     The answer is 42.\n\n  The output can be converted to an ``std::string`` with ``to_string(out)``.\n  \\endrst\n */\ntemplate <typename T, std::size_t SIZE = inline_buffer_size,\n          typename Allocator = std::allocator<T> >\nclass basic_memory_buffer: private Allocator, public internal::basic_buffer<T> {\n private:\n  T store_[SIZE];\n\n  // Deallocate memory allocated by the buffer.\n  void deallocate() {\n    T* data = this->data();\n    if (data != store_) Allocator::deallocate(data, this->capacity());\n  }\n\n protected:\n  void grow(std::size_t size) FMT_OVERRIDE;\n\n public:\n  typedef T value_type;\n  typedef const T &const_reference;\n\n  explicit basic_memory_buffer(const Allocator &alloc = Allocator())\n      : Allocator(alloc) {\n    this->set(store_, SIZE);\n  }\n  ~basic_memory_buffer() { deallocate(); }\n\n private:\n  // Move data from other to this buffer.\n  void move(basic_memory_buffer &other) {\n    Allocator &this_alloc = *this, &other_alloc = other;\n    this_alloc = std::move(other_alloc);\n    T* data = other.data();\n    std::size_t size = other.size(), capacity = other.capacity();\n    if (data == other.store_) {\n      this->set(store_, capacity);\n      std::uninitialized_copy(other.store_, other.store_ + size,\n                              internal::make_checked(store_, capacity));\n    } else {\n      this->set(data, capacity);\n      // Set pointer to the inline array so that delete is not called\n      // when deallocating.\n      other.set(other.store_, 0);\n    }\n    this->resize(size);\n  }\n\n public:\n  /**\n    \\rst\n    Constructs a :class:`fmt::basic_memory_buffer` object moving the content\n    of the other object to it.\n    \\endrst\n   */\n  basic_memory_buffer(basic_memory_buffer &&other) {\n    move(other);\n  }\n\n  /**\n    \\rst\n    Moves the content of the other ``basic_memory_buffer`` object to this one.\n    \\endrst\n   */\n  basic_memory_buffer &operator=(basic_memory_buffer &&other) {\n    assert(this != &other);\n    deallocate();\n    move(other);\n    return *this;\n  }\n\n  // Returns a copy of the allocator associated with this buffer.\n  Allocator get_allocator() const { return *this; }\n};\n\ntemplate <typename T, std::size_t SIZE, typename Allocator>\nvoid basic_memory_buffer<T, SIZE, Allocator>::grow(std::size_t size) {\n  std::size_t old_capacity = this->capacity();\n  std::size_t new_capacity = old_capacity + old_capacity / 2;\n  if (size > new_capacity)\n      new_capacity = size;\n  T *old_data = this->data();\n  T *new_data = internal::allocate<Allocator>(*this, new_capacity);\n  // The following code doesn't throw, so the raw pointer above doesn't leak.\n  std::uninitialized_copy(old_data, old_data + this->size(),\n                          internal::make_checked(new_data, new_capacity));\n  this->set(new_data, new_capacity);\n  // deallocate must not throw according to the standard, but even if it does,\n  // the buffer already uses the new storage and will deallocate it in\n  // destructor.\n  if (old_data != store_)\n    Allocator::deallocate(old_data, old_capacity);\n}\n\ntypedef basic_memory_buffer<char> memory_buffer;\ntypedef basic_memory_buffer<wchar_t> wmemory_buffer;\n\nnamespace internal {\n\ntemplate <typename Char>\nstruct char_traits;\n\ntemplate <>\nstruct char_traits<char> {\n  // Formats a floating-point number.\n  template <typename T>\n  FMT_API static int format_float(char *buffer, std::size_t size,\n      const char *format, int precision, T value);\n};\n\ntemplate <>\nstruct char_traits<wchar_t> {\n  template <typename T>\n  FMT_API static int format_float(wchar_t *buffer, std::size_t size,\n      const wchar_t *format, int precision, T value);\n};\n\n#if FMT_USE_EXTERN_TEMPLATES\nextern template int char_traits<char>::format_float<double>(\n    char *buffer, std::size_t size, const char* format, int precision,\n    double value);\nextern template int char_traits<char>::format_float<long double>(\n    char *buffer, std::size_t size, const char* format, int precision,\n    long double value);\n\nextern template int char_traits<wchar_t>::format_float<double>(\n    wchar_t *buffer, std::size_t size, const wchar_t* format, int precision,\n    double value);\nextern template int char_traits<wchar_t>::format_float<long double>(\n    wchar_t *buffer, std::size_t size, const wchar_t* format, int precision,\n    long double value);\n#endif\n\ntemplate <typename Container>\ninline typename std::enable_if<\n  is_contiguous<Container>::value,\n  typename checked<typename Container::value_type>::type>::type\n    reserve(std::back_insert_iterator<Container> &it, std::size_t n) {\n  Container &c = internal::get_container(it);\n  std::size_t size = c.size();\n  c.resize(size + n);\n  return make_checked(&c[size], n);\n}\n\ntemplate <typename Iterator>\ninline Iterator &reserve(Iterator &it, std::size_t) { return it; }\n\ntemplate <typename Char>\nclass null_terminating_iterator;\n\ntemplate <typename Char>\nFMT_CONSTEXPR_DECL const Char *pointer_from(null_terminating_iterator<Char> it);\n\n// An output iterator that counts the number of objects written to it and\n// discards them.\ntemplate <typename T>\nclass counting_iterator {\n private:\n  std::size_t count_;\n  mutable T blackhole_;\n\n public:\n  typedef std::output_iterator_tag iterator_category;\n  typedef T value_type;\n  typedef std::ptrdiff_t difference_type;\n  typedef T* pointer;\n  typedef T& reference;\n  typedef counting_iterator _Unchecked_type;  // Mark iterator as checked.\n\n  counting_iterator(): count_(0) {}\n\n  std::size_t count() const { return count_; }\n\n  counting_iterator& operator++() {\n    ++count_;\n    return *this;\n  }\n\n  counting_iterator operator++(int) {\n    auto it = *this;\n    ++*this;\n    return it;\n  }\n\n  T &operator*() const { return blackhole_; }\n};\n\ntemplate <typename OutputIt>\nclass truncating_iterator_base {\n protected:\n  OutputIt out_;\n  std::size_t limit_;\n  std::size_t count_;\n\n  truncating_iterator_base(OutputIt out, std::size_t limit)\n    : out_(out), limit_(limit), count_(0) {}\n\n public:\n  typedef std::output_iterator_tag iterator_category;\n  typedef void difference_type;\n  typedef void pointer;\n  typedef void reference;\n  typedef truncating_iterator_base _Unchecked_type; // Mark iterator as checked.\n\n  OutputIt base() const { return out_; }\n  std::size_t count() const { return count_; }\n};\n\n// An output iterator that truncates the output and counts the number of objects\n// written to it.\ntemplate <typename OutputIt, typename Enable = typename std::is_void<\n    typename std::iterator_traits<OutputIt>::value_type>::type>\nclass truncating_iterator;\n\ntemplate <typename OutputIt>\nclass truncating_iterator<OutputIt, std::false_type>:\n  public truncating_iterator_base<OutputIt> {\n  typedef std::iterator_traits<OutputIt> traits;\n\n  mutable typename traits::value_type blackhole_;\n\n public:\n  typedef typename traits::value_type value_type;\n\n  truncating_iterator(OutputIt out, std::size_t limit)\n    : truncating_iterator_base<OutputIt>(out, limit) {}\n\n  truncating_iterator& operator++() {\n    if (this->count_++ < this->limit_)\n      ++this->out_;\n    return *this;\n  }\n\n  truncating_iterator operator++(int) {\n    auto it = *this;\n    ++*this;\n    return it;\n  }\n\n  value_type& operator*() const {\n    return this->count_ < this->limit_ ? *this->out_ : blackhole_;\n  }\n};\n\ntemplate <typename OutputIt>\nclass truncating_iterator<OutputIt, std::true_type>:\n  public truncating_iterator_base<OutputIt> {\n public:\n  typedef typename OutputIt::container_type::value_type value_type;\n\n  truncating_iterator(OutputIt out, std::size_t limit)\n    : truncating_iterator_base<OutputIt>(out, limit) {}\n\n  truncating_iterator& operator=(value_type val) {\n    if (this->count_++ < this->limit_)\n      this->out_ = val;\n    return *this;\n  }\n\n  truncating_iterator& operator++() { return *this; }\n  truncating_iterator& operator++(int) { return *this; }\n  truncating_iterator& operator*() { return *this; }\n};\n\n// Returns true if value is negative, false otherwise.\n// Same as (value < 0) but doesn't produce warnings if T is an unsigned type.\ntemplate <typename T>\nFMT_CONSTEXPR typename std::enable_if<\n    std::numeric_limits<T>::is_signed, bool>::type is_negative(T value) {\n  return value < 0;\n}\ntemplate <typename T>\nFMT_CONSTEXPR typename std::enable_if<\n    !std::numeric_limits<T>::is_signed, bool>::type is_negative(T) {\n  return false;\n}\n\ntemplate <typename T>\nstruct int_traits {\n  // Smallest of uint32_t and uint64_t that is large enough to represent\n  // all values of T.\n  typedef typename std::conditional<\n    std::numeric_limits<T>::digits <= 32, uint32_t, uint64_t>::type main_type;\n};\n\n// Static data is placed in this class template to allow header-only\n// configuration.\ntemplate <typename T = void>\nstruct FMT_API basic_data {\n  static const uint32_t POWERS_OF_10_32[];\n  static const uint32_t ZERO_OR_POWERS_OF_10_32[];\n  static const uint64_t ZERO_OR_POWERS_OF_10_64[];\n  static const uint64_t POW10_SIGNIFICANDS[];\n  static const int16_t POW10_EXPONENTS[];\n  static const char DIGITS[];\n  static const char FOREGROUND_COLOR[];\n  static const char BACKGROUND_COLOR[];\n  static const char RESET_COLOR[];\n  static const wchar_t WRESET_COLOR[];\n};\n\n#if FMT_USE_EXTERN_TEMPLATES\nextern template struct basic_data<void>;\n#endif\n\ntypedef basic_data<> data;\n\n#ifdef FMT_BUILTIN_CLZLL\n// Returns the number of decimal digits in n. Leading zeros are not counted\n// except for n == 0 in which case count_digits returns 1.\ninline int count_digits(uint64_t n) {\n  // Based on http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10\n  // and the benchmark https://github.com/localvoid/cxx-benchmark-count-digits.\n  int t = (64 - FMT_BUILTIN_CLZLL(n | 1)) * 1233 >> 12;\n  return t - (n < data::ZERO_OR_POWERS_OF_10_64[t]) + 1;\n}\n#else\n// Fallback version of count_digits used when __builtin_clz is not available.\ninline int count_digits(uint64_t n) {\n  int count = 1;\n  for (;;) {\n    // Integer division is slow so do it for a group of four digits instead\n    // of for every digit. The idea comes from the talk by Alexandrescu\n    // \"Three Optimization Tips for C++\". See speed-test for a comparison.\n    if (n < 10) return count;\n    if (n < 100) return count + 1;\n    if (n < 1000) return count + 2;\n    if (n < 10000) return count + 3;\n    n /= 10000u;\n    count += 4;\n  }\n}\n#endif\n\ntemplate <typename Char>\ninline size_t count_code_points(basic_string_view<Char> s) { return s.size(); }\n\n// Counts the number of code points in a UTF-8 string.\nFMT_API size_t count_code_points(basic_string_view<char8_t> s);\n\ninline char8_t to_char8_t(char c) { return static_cast<char8_t>(c); }\n\ntemplate <typename InputIt, typename OutChar>\nstruct needs_conversion: std::integral_constant<bool,\n  std::is_same<\n    typename std::iterator_traits<InputIt>::value_type, char>::value &&\n  std::is_same<OutChar, char8_t>::value> {};\n\ntemplate <typename OutChar, typename InputIt, typename OutputIt>\ntypename std::enable_if<\n  !needs_conversion<InputIt, OutChar>::value, OutputIt>::type\n    copy_str(InputIt begin, InputIt end, OutputIt it) {\n  return std::copy(begin, end, it);\n}\n\ntemplate <typename OutChar, typename InputIt, typename OutputIt>\ntypename std::enable_if<\n  needs_conversion<InputIt, OutChar>::value, OutputIt>::type\n    copy_str(InputIt begin, InputIt end, OutputIt it) {\n  return std::transform(begin, end, it, to_char8_t);\n}\n\n#if FMT_HAS_CPP_ATTRIBUTE(always_inline)\n# define FMT_ALWAYS_INLINE __attribute__((always_inline))\n#else\n# define FMT_ALWAYS_INLINE\n#endif\n\ntemplate <typename Handler>\ninline char *lg(uint32_t n, Handler h) FMT_ALWAYS_INLINE;\n\n// Computes g = floor(log10(n)) and calls h.on<g>(n);\ntemplate <typename Handler>\ninline char *lg(uint32_t n, Handler h) {\n  return n < 100 ? n < 10 ? h.template on<0>(n) : h.template on<1>(n)\n                 : n < 1000000\n                       ? n < 10000 ? n < 1000 ? h.template on<2>(n)\n                                              : h.template on<3>(n)\n                                   : n < 100000 ? h.template on<4>(n)\n                                                : h.template on<5>(n)\n                       : n < 100000000 ? n < 10000000 ? h.template on<6>(n)\n                                                      : h.template on<7>(n)\n                                       : n < 1000000000 ? h.template on<8>(n)\n                                                        : h.template on<9>(n);\n}\n\n// An lg handler that formats a decimal number.\n// Usage: lg(n, decimal_formatter(buffer));\nclass decimal_formatter {\n private:\n  char *buffer_;\n\n  void write_pair(unsigned N, uint32_t index) {\n    std::memcpy(buffer_ + N, data::DIGITS + index * 2, 2);\n  }\n\n public:\n  explicit decimal_formatter(char *buf) : buffer_(buf) {}\n\n  template <unsigned N> char *on(uint32_t u) {\n    if (N == 0) {\n      *buffer_ = static_cast<char>(u) + '0';\n    } else if (N == 1) {\n      write_pair(0, u);\n    } else {\n      // The idea of using 4.32 fixed-point numbers is based on\n      // https://github.com/jeaiii/itoa\n      unsigned n = N - 1;\n      unsigned a = n / 5 * n * 53 / 16;\n      uint64_t t = ((1ULL << (32 + a)) /\n                   data::ZERO_OR_POWERS_OF_10_32[n] + 1 - n / 9);\n      t = ((t * u) >> a) + n / 5 * 4;\n      write_pair(0, t >> 32);\n      for (unsigned i = 2; i < N; i += 2) {\n        t = 100ULL * static_cast<uint32_t>(t);\n        write_pair(i, t >> 32);\n      }\n      if (N % 2 == 0) {\n        buffer_[N] = static_cast<char>(\n          (10ULL * static_cast<uint32_t>(t)) >> 32) + '0';\n      }\n    }\n    return buffer_ += N + 1;\n  }\n};\n\n// An lg handler that formats a decimal number with a terminating null.\nclass decimal_formatter_null : public decimal_formatter {\n public:\n  explicit decimal_formatter_null(char *buf) : decimal_formatter(buf) {}\n\n  template <unsigned N> char *on(uint32_t u) {\n    char *buf = decimal_formatter::on<N>(u);\n    *buf = '\\0';\n    return buf;\n  }\n};\n\n#ifdef FMT_BUILTIN_CLZ\n// Optional version of count_digits for better performance on 32-bit platforms.\ninline int count_digits(uint32_t n) {\n  int t = (32 - FMT_BUILTIN_CLZ(n | 1)) * 1233 >> 12;\n  return t - (n < data::ZERO_OR_POWERS_OF_10_32[t]) + 1;\n}\n#endif\n\n// A functor that doesn't add a thousands separator.\nstruct no_thousands_sep {\n  typedef char char_type;\n\n  template <typename Char>\n  void operator()(Char *) {}\n\n  enum { size = 0 };\n};\n\n// A functor that adds a thousands separator.\ntemplate <typename Char>\nclass add_thousands_sep {\n private:\n  basic_string_view<Char> sep_;\n\n  // Index of a decimal digit with the least significant digit having index 0.\n  unsigned digit_index_;\n\n public:\n  typedef Char char_type;\n\n  explicit add_thousands_sep(basic_string_view<Char> sep)\n    : sep_(sep), digit_index_(0) {}\n\n  void operator()(Char *&buffer) {\n    if (++digit_index_ % 3 != 0)\n      return;\n    buffer -= sep_.size();\n    std::uninitialized_copy(sep_.data(), sep_.data() + sep_.size(),\n                            internal::make_checked(buffer, sep_.size()));\n  }\n\n  enum { size = 1 };\n};\n\ntemplate <typename Char>\nFMT_API Char thousands_sep_impl(locale_ref loc);\n\ntemplate <typename Char>\ninline Char thousands_sep(locale_ref loc) {\n  return Char(thousands_sep_impl<char>(loc));\n}\n\ntemplate <>\ninline wchar_t thousands_sep(locale_ref loc) {\n  return thousands_sep_impl<wchar_t>(loc);\n}\n\n// Formats a decimal unsigned integer value writing into buffer.\n// thousands_sep is a functor that is called after writing each char to\n// add a thousands separator if necessary.\ntemplate <typename UInt, typename Char, typename ThousandsSep>\ninline Char *format_decimal(Char *buffer, UInt value, int num_digits,\n                            ThousandsSep thousands_sep) {\n  FMT_ASSERT(num_digits >= 0, \"invalid digit count\");\n  buffer += num_digits;\n  Char *end = buffer;\n  while (value >= 100) {\n    // Integer division is slow so do it for a group of two digits instead\n    // of for every digit. The idea comes from the talk by Alexandrescu\n    // \"Three Optimization Tips for C++\". See speed-test for a comparison.\n    unsigned index = static_cast<unsigned>((value % 100) * 2);\n    value /= 100;\n    *--buffer = static_cast<Char>(data::DIGITS[index + 1]);\n    thousands_sep(buffer);\n    *--buffer = static_cast<Char>(data::DIGITS[index]);\n    thousands_sep(buffer);\n  }\n  if (value < 10) {\n    *--buffer = static_cast<Char>('0' + value);\n    return end;\n  }\n  unsigned index = static_cast<unsigned>(value * 2);\n  *--buffer = static_cast<Char>(data::DIGITS[index + 1]);\n  thousands_sep(buffer);\n  *--buffer = static_cast<Char>(data::DIGITS[index]);\n  return end;\n}\n\ntemplate <typename OutChar, typename UInt, typename Iterator,\n          typename ThousandsSep>\ninline Iterator format_decimal(\n    Iterator out, UInt value, int num_digits, ThousandsSep sep) {\n  FMT_ASSERT(num_digits >= 0, \"invalid digit count\");\n  typedef typename ThousandsSep::char_type char_type;\n  // Buffer should be large enough to hold all digits (<= digits10 + 1).\n  enum { max_size = std::numeric_limits<UInt>::digits10 + 1 };\n  FMT_ASSERT(ThousandsSep::size <= 1, \"invalid separator\");\n  char_type buffer[max_size + max_size / 3];\n  auto end = format_decimal(buffer, value, num_digits, sep);\n  return internal::copy_str<OutChar>(buffer, end, out);\n}\n\ntemplate <typename OutChar, typename It, typename UInt>\ninline It format_decimal(It out, UInt value, int num_digits) {\n  return format_decimal<OutChar>(out, value, num_digits, no_thousands_sep());\n}\n\ntemplate <unsigned BASE_BITS, typename Char, typename UInt>\ninline Char *format_uint(Char *buffer, UInt value, int num_digits,\n                         bool upper = false) {\n  buffer += num_digits;\n  Char *end = buffer;\n  do {\n    const char *digits = upper ? \"0123456789ABCDEF\" : \"0123456789abcdef\";\n    unsigned digit = (value & ((1 << BASE_BITS) - 1));\n    *--buffer = static_cast<Char>(BASE_BITS < 4 ? static_cast<char>('0' + digit)\n                                                : digits[digit]);\n  } while ((value >>= BASE_BITS) != 0);\n  return end;\n}\n\ntemplate <unsigned BASE_BITS, typename Char, typename It, typename UInt>\ninline It format_uint(It out, UInt value, int num_digits,\n                      bool upper = false) {\n  // Buffer should be large enough to hold all digits (digits / BASE_BITS + 1)\n  // and null.\n  char buffer[std::numeric_limits<UInt>::digits / BASE_BITS + 2];\n  format_uint<BASE_BITS>(buffer, value, num_digits, upper);\n  return internal::copy_str<Char>(buffer, buffer + num_digits, out);\n}\n\n#ifndef _WIN32\n# define FMT_USE_WINDOWS_H 0\n#elif !defined(FMT_USE_WINDOWS_H)\n# define FMT_USE_WINDOWS_H 1\n#endif\n\n// Define FMT_USE_WINDOWS_H to 0 to disable use of windows.h.\n// All the functionality that relies on it will be disabled too.\n#if FMT_USE_WINDOWS_H\n// A converter from UTF-8 to UTF-16.\n// It is only provided for Windows since other systems support UTF-8 natively.\nclass utf8_to_utf16 {\n private:\n  wmemory_buffer buffer_;\n\n public:\n  FMT_API explicit utf8_to_utf16(string_view s);\n  operator wstring_view() const { return wstring_view(&buffer_[0], size()); }\n  size_t size() const { return buffer_.size() - 1; }\n  const wchar_t *c_str() const { return &buffer_[0]; }\n  std::wstring str() const { return std::wstring(&buffer_[0], size()); }\n};\n\n// A converter from UTF-16 to UTF-8.\n// It is only provided for Windows since other systems support UTF-8 natively.\nclass utf16_to_utf8 {\n private:\n  memory_buffer buffer_;\n\n public:\n  utf16_to_utf8() {}\n  FMT_API explicit utf16_to_utf8(wstring_view s);\n  operator string_view() const { return string_view(&buffer_[0], size()); }\n  size_t size() const { return buffer_.size() - 1; }\n  const char *c_str() const { return &buffer_[0]; }\n  std::string str() const { return std::string(&buffer_[0], size()); }\n\n  // Performs conversion returning a system error code instead of\n  // throwing exception on conversion error. This method may still throw\n  // in case of memory allocation error.\n  FMT_API int convert(wstring_view s);\n};\n\nFMT_API void format_windows_error(fmt::internal::buffer &out, int error_code,\n                                  fmt::string_view message) FMT_NOEXCEPT;\n#endif\n\ntemplate <typename T = void>\nstruct null {};\n}  // namespace internal\n\nenum alignment {\n  ALIGN_DEFAULT, ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTER, ALIGN_NUMERIC\n};\n\n// Flags.\nenum { SIGN_FLAG = 1, PLUS_FLAG = 2, MINUS_FLAG = 4, HASH_FLAG = 8 };\n\n// An alignment specifier.\nstruct align_spec {\n  unsigned width_;\n  // Fill is always wchar_t and cast to char if necessary to avoid having\n  // two specialization of AlignSpec and its subclasses.\n  wchar_t fill_;\n  alignment align_;\n\n  FMT_CONSTEXPR align_spec() : width_(0), fill_(' '), align_(ALIGN_DEFAULT) {}\n  FMT_CONSTEXPR unsigned width() const { return width_; }\n  FMT_CONSTEXPR wchar_t fill() const { return fill_; }\n  FMT_CONSTEXPR alignment align() const { return align_; }\n};\n\nstruct core_format_specs {\n  int precision;\n  uint_least8_t flags;\n  char type;\n\n  FMT_CONSTEXPR core_format_specs() : precision(-1), flags(0), type(0) {}\n  FMT_CONSTEXPR bool has(unsigned f) const { return (flags & f) != 0; }\n};\n\n// Format specifiers.\ntemplate <typename Char>\nstruct basic_format_specs : align_spec, core_format_specs {\n  FMT_CONSTEXPR basic_format_specs() {}\n};\n\ntypedef basic_format_specs<char> format_specs;\n\ntemplate <typename Char, typename ErrorHandler>\nFMT_CONSTEXPR unsigned basic_parse_context<Char, ErrorHandler>::next_arg_id() {\n  if (next_arg_id_ >= 0)\n    return internal::to_unsigned(next_arg_id_++);\n  on_error(\"cannot switch from manual to automatic argument indexing\");\n  return 0;\n}\n\nnamespace internal {\n\n// Formats value using Grisu2 algorithm:\n// https://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/printf.pdf\ntemplate <typename Double>\nFMT_API typename std::enable_if<sizeof(Double) == sizeof(uint64_t), bool>::type\n  grisu2_format(Double value, buffer &buf, core_format_specs);\ntemplate <typename Double>\ninline typename std::enable_if<sizeof(Double) != sizeof(uint64_t), bool>::type\n  grisu2_format(Double, buffer &, core_format_specs) { return false; }\n\ntemplate <typename Double>\nvoid sprintf_format(Double, internal::buffer &, core_format_specs);\n\ntemplate <typename Handler>\nFMT_CONSTEXPR void handle_int_type_spec(char spec, Handler &&handler) {\n  switch (spec) {\n  case 0: case 'd':\n    handler.on_dec();\n    break;\n  case 'x': case 'X':\n    handler.on_hex();\n    break;\n  case 'b': case 'B':\n    handler.on_bin();\n    break;\n  case 'o':\n    handler.on_oct();\n    break;\n  case 'n':\n    handler.on_num();\n    break;\n  default:\n    handler.on_error();\n  }\n}\n\ntemplate <typename Handler>\nFMT_CONSTEXPR void handle_float_type_spec(char spec, Handler &&handler) {\n  switch (spec) {\n  case 0: case 'g': case 'G':\n    handler.on_general();\n    break;\n  case 'e': case 'E':\n    handler.on_exp();\n    break;\n  case 'f': case 'F':\n    handler.on_fixed();\n    break;\n   case 'a': case 'A':\n    handler.on_hex();\n    break;\n  default:\n    handler.on_error();\n    break;\n  }\n}\n\ntemplate <typename Char, typename Handler>\nFMT_CONSTEXPR void handle_char_specs(\n    const basic_format_specs<Char> *specs, Handler &&handler) {\n  if (!specs) return handler.on_char();\n  if (specs->type && specs->type != 'c') return handler.on_int();\n  if (specs->align() == ALIGN_NUMERIC || specs->flags != 0)\n    handler.on_error(\"invalid format specifier for char\");\n  handler.on_char();\n}\n\ntemplate <typename Char, typename Handler>\nFMT_CONSTEXPR void handle_cstring_type_spec(Char spec, Handler &&handler) {\n  if (spec == 0 || spec == 's')\n    handler.on_string();\n  else if (spec == 'p')\n    handler.on_pointer();\n  else\n    handler.on_error(\"invalid type specifier\");\n}\n\ntemplate <typename Char, typename ErrorHandler>\nFMT_CONSTEXPR void check_string_type_spec(Char spec, ErrorHandler &&eh) {\n  if (spec != 0 && spec != 's')\n    eh.on_error(\"invalid type specifier\");\n}\n\ntemplate <typename Char, typename ErrorHandler>\nFMT_CONSTEXPR void check_pointer_type_spec(Char spec, ErrorHandler &&eh) {\n  if (spec != 0 && spec != 'p')\n    eh.on_error(\"invalid type specifier\");\n}\n\ntemplate <typename ErrorHandler>\nclass int_type_checker : private ErrorHandler {\n public:\n  FMT_CONSTEXPR explicit int_type_checker(ErrorHandler eh) : ErrorHandler(eh) {}\n\n  FMT_CONSTEXPR void on_dec() {}\n  FMT_CONSTEXPR void on_hex() {}\n  FMT_CONSTEXPR void on_bin() {}\n  FMT_CONSTEXPR void on_oct() {}\n  FMT_CONSTEXPR void on_num() {}\n\n  FMT_CONSTEXPR void on_error() {\n    ErrorHandler::on_error(\"invalid type specifier\");\n  }\n};\n\ntemplate <typename ErrorHandler>\nclass float_type_checker : private ErrorHandler {\n public:\n  FMT_CONSTEXPR explicit float_type_checker(ErrorHandler eh)\n    : ErrorHandler(eh) {}\n\n  FMT_CONSTEXPR void on_general() {}\n  FMT_CONSTEXPR void on_exp() {}\n  FMT_CONSTEXPR void on_fixed() {}\n  FMT_CONSTEXPR void on_hex() {}\n\n  FMT_CONSTEXPR void on_error() {\n    ErrorHandler::on_error(\"invalid type specifier\");\n  }\n};\n\ntemplate <typename ErrorHandler>\nclass char_specs_checker : public ErrorHandler {\n private:\n  char type_;\n\n public:\n  FMT_CONSTEXPR char_specs_checker(char type, ErrorHandler eh)\n    : ErrorHandler(eh), type_(type) {}\n\n  FMT_CONSTEXPR void on_int() {\n    handle_int_type_spec(type_, int_type_checker<ErrorHandler>(*this));\n  }\n  FMT_CONSTEXPR void on_char() {}\n};\n\ntemplate <typename ErrorHandler>\nclass cstring_type_checker : public ErrorHandler {\n public:\n  FMT_CONSTEXPR explicit cstring_type_checker(ErrorHandler eh)\n    : ErrorHandler(eh) {}\n\n  FMT_CONSTEXPR void on_string() {}\n  FMT_CONSTEXPR void on_pointer() {}\n};\n\ntemplate <typename Context>\nvoid arg_map<Context>::init(const basic_format_args<Context> &args) {\n  if (map_)\n    return;\n  map_ = new entry[args.max_size()];\n  if (args.is_packed()) {\n    for (unsigned i = 0;/*nothing*/; ++i) {\n      internal::type arg_type = args.type(i);\n      switch (arg_type) {\n        case internal::none_type:\n          return;\n        case internal::named_arg_type:\n          push_back(args.values_[i]);\n          break;\n        default:\n          break; // Do nothing.\n      }\n    }\n  }\n  for (unsigned i = 0; ; ++i) {\n    switch (args.args_[i].type_) {\n      case internal::none_type:\n        return;\n      case internal::named_arg_type:\n        push_back(args.args_[i].value_);\n        break;\n      default:\n        break; // Do nothing.\n    }\n  }\n}\n\ntemplate <typename Range>\nclass arg_formatter_base {\n public:\n  typedef typename Range::value_type char_type;\n  typedef decltype(internal::declval<Range>().begin()) iterator;\n  typedef basic_format_specs<char_type> format_specs;\n\n private:\n  typedef basic_writer<Range> writer_type;\n  writer_type writer_;\n  format_specs *specs_;\n\n  struct char_writer {\n    char_type value;\n\n    size_t size() const { return 1; }\n    size_t width() const { return 1; }\n\n    template <typename It>\n    void operator()(It &&it) const { *it++ = value; }\n  };\n\n  void write_char(char_type value) {\n    if (specs_)\n      writer_.write_padded(*specs_, char_writer{value});\n    else\n      writer_.write(value);\n  }\n\n  void write_pointer(const void *p) {\n    format_specs specs = specs_ ? *specs_ : format_specs();\n    specs.flags = HASH_FLAG;\n    specs.type = 'x';\n    writer_.write_int(reinterpret_cast<uintptr_t>(p), specs);\n  }\n\n protected:\n  writer_type &writer() { return writer_; }\n  format_specs *spec() { return specs_; }\n  iterator out() { return writer_.out(); }\n\n  void write(bool value) {\n    string_view sv(value ? \"true\" : \"false\");\n    specs_ ? writer_.write(sv, *specs_) : writer_.write(sv);\n  }\n\n  void write(const char_type *value) {\n    if (!value)\n      FMT_THROW(format_error(\"string pointer is null\"));\n    auto length = std::char_traits<char_type>::length(value);\n    basic_string_view<char_type> sv(value, length);\n    specs_ ? writer_.write(sv, *specs_) : writer_.write(sv);\n  }\n\n public:\n  arg_formatter_base(Range r, format_specs *s, locale_ref loc)\n    : writer_(r, loc), specs_(s) {}\n\n  iterator operator()(monostate) {\n    FMT_ASSERT(false, \"invalid argument type\");\n    return out();\n  }\n\n  template <typename T>\n  typename std::enable_if<\n    std::is_integral<T>::value || std::is_same<T, char_type>::value,\n    iterator>::type operator()(T value) {\n    // MSVC2013 fails to compile separate overloads for bool and char_type so\n    // use std::is_same instead.\n    if (std::is_same<T, bool>::value) {\n      if (specs_ && specs_->type)\n        return (*this)(value ? 1 : 0);\n      write(value != 0);\n    } else if (std::is_same<T, char_type>::value) {\n      internal::handle_char_specs(\n        specs_, char_spec_handler(*this, static_cast<char_type>(value)));\n    } else {\n      specs_ ? writer_.write_int(value, *specs_) : writer_.write(value);\n    }\n    return out();\n  }\n\n  template <typename T>\n  typename std::enable_if<std::is_floating_point<T>::value, iterator>::type\n      operator()(T value) {\n    writer_.write_double(value, specs_ ? *specs_ : format_specs());\n    return out();\n  }\n\n  struct char_spec_handler : internal::error_handler {\n    arg_formatter_base &formatter;\n    char_type value;\n\n    char_spec_handler(arg_formatter_base& f, char_type val)\n      : formatter(f), value(val) {}\n\n    void on_int() {\n      if (formatter.specs_)\n        formatter.writer_.write_int(value, *formatter.specs_);\n      else\n        formatter.writer_.write(value);\n    }\n    void on_char() { formatter.write_char(value); }\n  };\n\n  struct cstring_spec_handler : internal::error_handler {\n    arg_formatter_base &formatter;\n    const char_type *value;\n\n    cstring_spec_handler(arg_formatter_base &f, const char_type *val)\n      : formatter(f), value(val) {}\n\n    void on_string() { formatter.write(value); }\n    void on_pointer() { formatter.write_pointer(value); }\n  };\n\n  iterator operator()(const char_type *value) {\n    if (!specs_) return write(value), out();\n    internal::handle_cstring_type_spec(\n          specs_->type, cstring_spec_handler(*this, value));\n    return out();\n  }\n\n  iterator operator()(basic_string_view<char_type> value) {\n    if (specs_) {\n      internal::check_string_type_spec(\n            specs_->type, internal::error_handler());\n      writer_.write(value, *specs_);\n    } else {\n      writer_.write(value);\n    }\n    return out();\n  }\n\n  iterator operator()(const void *value) {\n    if (specs_)\n      check_pointer_type_spec(specs_->type, internal::error_handler());\n    write_pointer(value);\n    return out();\n  }\n};\n\ntemplate <typename Char>\nFMT_CONSTEXPR bool is_name_start(Char c) {\n  return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || '_' == c;\n}\n\n// Parses the range [begin, end) as an unsigned integer. This function assumes\n// that the range is non-empty and the first character is a digit.\ntemplate <typename Char, typename ErrorHandler>\nFMT_CONSTEXPR unsigned parse_nonnegative_int(\n    const Char *&begin, const Char *end, ErrorHandler &&eh) {\n  assert(begin != end && '0' <= *begin && *begin <= '9');\n  if (*begin == '0') {\n    ++begin;\n    return 0;\n  }\n  unsigned value = 0;\n  // Convert to unsigned to prevent a warning.\n  unsigned max_int = (std::numeric_limits<int>::max)();\n  unsigned big = max_int / 10;\n  do {\n    // Check for overflow.\n    if (value > big) {\n      value = max_int + 1;\n      break;\n    }\n    value = value * 10 + unsigned(*begin - '0');\n    ++begin;\n  } while (begin != end && '0' <= *begin && *begin <= '9');\n  if (value > max_int)\n    eh.on_error(\"number is too big\");\n  return value;\n}\n\ntemplate <typename Char, typename Context>\nclass custom_formatter: public function<bool> {\n private:\n  Context &ctx_;\n\n public:\n  explicit custom_formatter(Context &ctx): ctx_(ctx) {}\n\n  bool operator()(typename basic_format_arg<Context>::handle h) const {\n    h.format(ctx_);\n    return true;\n  }\n\n  template <typename T>\n  bool operator()(T) const { return false; }\n};\n\ntemplate <typename T>\nstruct is_integer {\n  enum {\n    value = std::is_integral<T>::value && !std::is_same<T, bool>::value &&\n            !std::is_same<T, char>::value && !std::is_same<T, wchar_t>::value\n  };\n};\n\ntemplate <typename ErrorHandler>\nclass width_checker: public function<unsigned long long> {\n public:\n  explicit FMT_CONSTEXPR width_checker(ErrorHandler &eh) : handler_(eh) {}\n\n  template <typename T>\n  FMT_CONSTEXPR\n  typename std::enable_if<\n      is_integer<T>::value, unsigned long long>::type operator()(T value) {\n    if (is_negative(value))\n      handler_.on_error(\"negative width\");\n    return static_cast<unsigned long long>(value);\n  }\n\n  template <typename T>\n  FMT_CONSTEXPR typename std::enable_if<\n      !is_integer<T>::value, unsigned long long>::type operator()(T) {\n    handler_.on_error(\"width is not integer\");\n    return 0;\n  }\n\n private:\n  ErrorHandler &handler_;\n};\n\ntemplate <typename ErrorHandler>\nclass precision_checker: public function<unsigned long long> {\n public:\n  explicit FMT_CONSTEXPR precision_checker(ErrorHandler &eh) : handler_(eh) {}\n\n  template <typename T>\n  FMT_CONSTEXPR typename std::enable_if<\n      is_integer<T>::value, unsigned long long>::type operator()(T value) {\n    if (is_negative(value))\n      handler_.on_error(\"negative precision\");\n    return static_cast<unsigned long long>(value);\n  }\n\n  template <typename T>\n  FMT_CONSTEXPR typename std::enable_if<\n      !is_integer<T>::value, unsigned long long>::type operator()(T) {\n    handler_.on_error(\"precision is not integer\");\n    return 0;\n  }\n\n private:\n  ErrorHandler &handler_;\n};\n\n// A format specifier handler that sets fields in basic_format_specs.\ntemplate <typename Char>\nclass specs_setter {\n public:\n  explicit FMT_CONSTEXPR specs_setter(basic_format_specs<Char> &specs):\n    specs_(specs) {}\n\n  FMT_CONSTEXPR specs_setter(const specs_setter &other): specs_(other.specs_) {}\n\n  FMT_CONSTEXPR void on_align(alignment align) { specs_.align_ = align; }\n  FMT_CONSTEXPR void on_fill(Char fill) { specs_.fill_ = fill; }\n  FMT_CONSTEXPR void on_plus() { specs_.flags |= SIGN_FLAG | PLUS_FLAG; }\n  FMT_CONSTEXPR void on_minus() { specs_.flags |= MINUS_FLAG; }\n  FMT_CONSTEXPR void on_space() { specs_.flags |= SIGN_FLAG; }\n  FMT_CONSTEXPR void on_hash() { specs_.flags |= HASH_FLAG; }\n\n  FMT_CONSTEXPR void on_zero() {\n    specs_.align_ = ALIGN_NUMERIC;\n    specs_.fill_ = '0';\n  }\n\n  FMT_CONSTEXPR void on_width(unsigned width) { specs_.width_ = width; }\n  FMT_CONSTEXPR void on_precision(unsigned precision) {\n    specs_.precision = static_cast<int>(precision);\n  }\n  FMT_CONSTEXPR void end_precision() {}\n\n  FMT_CONSTEXPR void on_type(Char type) {\n    specs_.type = static_cast<char>(type);\n  }\n\n protected:\n  basic_format_specs<Char> &specs_;\n};\n\n// A format specifier handler that checks if specifiers are consistent with the\n// argument type.\ntemplate <typename Handler>\nclass specs_checker : public Handler {\n public:\n  FMT_CONSTEXPR specs_checker(const Handler& handler, internal::type arg_type)\n    : Handler(handler), arg_type_(arg_type) {}\n\n  FMT_CONSTEXPR specs_checker(const specs_checker &other)\n    : Handler(other), arg_type_(other.arg_type_) {}\n\n  FMT_CONSTEXPR void on_align(alignment align) {\n    if (align == ALIGN_NUMERIC)\n      require_numeric_argument();\n    Handler::on_align(align);\n  }\n\n  FMT_CONSTEXPR void on_plus() {\n    check_sign();\n    Handler::on_plus();\n  }\n\n  FMT_CONSTEXPR void on_minus() {\n    check_sign();\n    Handler::on_minus();\n  }\n\n  FMT_CONSTEXPR void on_space() {\n    check_sign();\n    Handler::on_space();\n  }\n\n  FMT_CONSTEXPR void on_hash() {\n    require_numeric_argument();\n    Handler::on_hash();\n  }\n\n  FMT_CONSTEXPR void on_zero() {\n    require_numeric_argument();\n    Handler::on_zero();\n  }\n\n  FMT_CONSTEXPR void end_precision() {\n    if (is_integral(arg_type_) || arg_type_ == pointer_type)\n      this->on_error(\"precision not allowed for this argument type\");\n  }\n\n private:\n  FMT_CONSTEXPR void require_numeric_argument() {\n    if (!is_arithmetic(arg_type_))\n      this->on_error(\"format specifier requires numeric argument\");\n  }\n\n  FMT_CONSTEXPR void check_sign() {\n    require_numeric_argument();\n    if (is_integral(arg_type_) && arg_type_ != int_type &&\n        arg_type_ != long_long_type && arg_type_ != internal::char_type) {\n      this->on_error(\"format specifier requires signed argument\");\n    }\n  }\n\n  internal::type arg_type_;\n};\n\ntemplate <template <typename> class Handler, typename T,\n          typename Context, typename ErrorHandler>\nFMT_CONSTEXPR void set_dynamic_spec(\n    T &value, basic_format_arg<Context> arg, ErrorHandler eh) {\n  unsigned long long big_value =\n      visit_format_arg(Handler<ErrorHandler>(eh), arg);\n  if (big_value > to_unsigned((std::numeric_limits<int>::max)()))\n    eh.on_error(\"number is too big\");\n  value = static_cast<T>(big_value);\n}\n\nstruct auto_id {};\n\n// The standard format specifier handler with checking.\ntemplate <typename Context>\nclass specs_handler: public specs_setter<typename Context::char_type> {\n public:\n  typedef typename Context::char_type char_type;\n\n  FMT_CONSTEXPR specs_handler(\n      basic_format_specs<char_type> &specs, Context &ctx)\n    : specs_setter<char_type>(specs), context_(ctx) {}\n\n  template <typename Id>\n  FMT_CONSTEXPR void on_dynamic_width(Id arg_id) {\n    set_dynamic_spec<width_checker>(\n          this->specs_.width_, get_arg(arg_id), context_.error_handler());\n  }\n\n  template <typename Id>\n  FMT_CONSTEXPR void on_dynamic_precision(Id arg_id) {\n    set_dynamic_spec<precision_checker>(\n          this->specs_.precision, get_arg(arg_id), context_.error_handler());\n  }\n\n  void on_error(const char *message) {\n    context_.on_error(message);\n  }\n\n private:\n  FMT_CONSTEXPR basic_format_arg<Context> get_arg(auto_id) {\n    return context_.next_arg();\n  }\n\n  template <typename Id>\n  FMT_CONSTEXPR basic_format_arg<Context> get_arg(Id arg_id) {\n    context_.parse_context().check_arg_id(arg_id);\n    return context_.get_arg(arg_id);\n  }\n\n  Context &context_;\n};\n\n// An argument reference.\ntemplate <typename Char>\nstruct arg_ref {\n  enum Kind { NONE, INDEX, NAME };\n\n  FMT_CONSTEXPR arg_ref() : kind(NONE), index(0) {}\n  FMT_CONSTEXPR explicit arg_ref(unsigned index) : kind(INDEX), index(index) {}\n  explicit arg_ref(basic_string_view<Char> nm) : kind(NAME) {\n    name = {nm.data(), nm.size()};\n  }\n\n  FMT_CONSTEXPR arg_ref &operator=(unsigned idx) {\n    kind = INDEX;\n    index = idx;\n    return *this;\n  }\n\n  Kind kind;\n  union {\n    unsigned index;\n    string_value<Char> name;  // This is not string_view because of gcc 4.4.\n  };\n};\n\n// Format specifiers with width and precision resolved at formatting rather\n// than parsing time to allow re-using the same parsed specifiers with\n// differents sets of arguments (precompilation of format strings).\ntemplate <typename Char>\nstruct dynamic_format_specs : basic_format_specs<Char> {\n  arg_ref<Char> width_ref;\n  arg_ref<Char> precision_ref;\n};\n\n// Format spec handler that saves references to arguments representing dynamic\n// width and precision to be resolved at formatting time.\ntemplate <typename ParseContext>\nclass dynamic_specs_handler :\n    public specs_setter<typename ParseContext::char_type> {\n public:\n  typedef typename ParseContext::char_type char_type;\n\n  FMT_CONSTEXPR dynamic_specs_handler(\n      dynamic_format_specs<char_type> &specs, ParseContext &ctx)\n    : specs_setter<char_type>(specs), specs_(specs), context_(ctx) {}\n\n  FMT_CONSTEXPR dynamic_specs_handler(const dynamic_specs_handler &other)\n    : specs_setter<char_type>(other),\n      specs_(other.specs_), context_(other.context_) {}\n\n  template <typename Id>\n  FMT_CONSTEXPR void on_dynamic_width(Id arg_id) {\n    specs_.width_ref = make_arg_ref(arg_id);\n  }\n\n  template <typename Id>\n  FMT_CONSTEXPR void on_dynamic_precision(Id arg_id) {\n    specs_.precision_ref = make_arg_ref(arg_id);\n  }\n\n  FMT_CONSTEXPR void on_error(const char *message) {\n    context_.on_error(message);\n  }\n\n private:\n  typedef arg_ref<char_type> arg_ref_type;\n\n  template <typename Id>\n  FMT_CONSTEXPR arg_ref_type make_arg_ref(Id arg_id) {\n    context_.check_arg_id(arg_id);\n    return arg_ref_type(arg_id);\n  }\n\n  FMT_CONSTEXPR arg_ref_type make_arg_ref(auto_id) {\n    return arg_ref_type(context_.next_arg_id());\n  }\n\n  dynamic_format_specs<char_type> &specs_;\n  ParseContext &context_;\n};\n\ntemplate <typename Char, typename IDHandler>\nFMT_CONSTEXPR const Char *parse_arg_id(\n    const Char *begin, const Char *end, IDHandler &&handler) {\n  assert(begin != end);\n  Char c = *begin;\n  if (c == '}' || c == ':')\n    return handler(), begin;\n  if (c >= '0' && c <= '9') {\n    unsigned index = parse_nonnegative_int(begin, end, handler);\n    if (begin == end || (*begin != '}' && *begin != ':'))\n      return handler.on_error(\"invalid format string\"), begin;\n    handler(index);\n    return begin;\n  }\n  if (!is_name_start(c))\n    return handler.on_error(\"invalid format string\"), begin;\n  auto it = begin;\n  do {\n    ++it;\n  } while (it != end && (is_name_start(c = *it) || ('0' <= c && c <= '9')));\n  handler(basic_string_view<Char>(begin, to_unsigned(it - begin)));\n  return it;\n}\n\n// Adapts SpecHandler to IDHandler API for dynamic width.\ntemplate <typename SpecHandler, typename Char>\nstruct width_adapter {\n  explicit FMT_CONSTEXPR width_adapter(SpecHandler &h) : handler(h) {}\n\n  FMT_CONSTEXPR void operator()() { handler.on_dynamic_width(auto_id()); }\n  FMT_CONSTEXPR void operator()(unsigned id) { handler.on_dynamic_width(id); }\n  FMT_CONSTEXPR void operator()(basic_string_view<Char> id) {\n    handler.on_dynamic_width(id);\n  }\n\n  FMT_CONSTEXPR void on_error(const char *message) {\n    handler.on_error(message);\n  }\n\n  SpecHandler &handler;\n};\n\n// Adapts SpecHandler to IDHandler API for dynamic precision.\ntemplate <typename SpecHandler, typename Char>\nstruct precision_adapter {\n  explicit FMT_CONSTEXPR precision_adapter(SpecHandler &h) : handler(h) {}\n\n  FMT_CONSTEXPR void operator()() { handler.on_dynamic_precision(auto_id()); }\n  FMT_CONSTEXPR void operator()(unsigned id) {\n    handler.on_dynamic_precision(id);\n  }\n  FMT_CONSTEXPR void operator()(basic_string_view<Char> id) {\n    handler.on_dynamic_precision(id);\n  }\n\n  FMT_CONSTEXPR void on_error(const char *message) { handler.on_error(message); }\n\n  SpecHandler &handler;\n};\n\n// Parses fill and alignment.\ntemplate <typename Char, typename Handler>\nFMT_CONSTEXPR const Char *parse_align(\n    const Char *begin, const Char *end, Handler &&handler) {\n  FMT_ASSERT(begin != end, \"\");\n  alignment align = ALIGN_DEFAULT;\n  int i = 0;\n  if (begin + 1 != end) ++i;\n  do {\n    switch (static_cast<char>(begin[i])) {\n    case '<':\n      align = ALIGN_LEFT;\n      break;\n    case '>':\n      align = ALIGN_RIGHT;\n      break;\n    case '=':\n      align = ALIGN_NUMERIC;\n      break;\n    case '^':\n      align = ALIGN_CENTER;\n      break;\n    }\n    if (align != ALIGN_DEFAULT) {\n      if (i > 0) {\n        auto c = *begin;\n        if (c == '{')\n          return handler.on_error(\"invalid fill character '{'\"), begin;\n        begin += 2;\n        handler.on_fill(c);\n      } else ++begin;\n      handler.on_align(align);\n      break;\n    }\n  } while (i-- > 0);\n  return begin;\n}\n\ntemplate <typename Char, typename Handler>\nFMT_CONSTEXPR const Char *parse_width(\n    const Char *begin, const Char *end, Handler &&handler) {\n  FMT_ASSERT(begin != end, \"\");\n  if ('0' <= *begin && *begin <= '9') {\n    handler.on_width(parse_nonnegative_int(begin, end, handler));\n  } else if (*begin == '{') {\n    ++begin;\n    if (begin != end)\n      begin = parse_arg_id(begin, end, width_adapter<Handler, Char>(handler));\n    if (begin == end || *begin != '}')\n      return handler.on_error(\"invalid format string\"), begin;\n    ++begin;\n  }\n  return begin;\n}\n\n// Parses standard format specifiers and sends notifications about parsed\n// components to handler.\ntemplate <typename Char, typename SpecHandler>\nFMT_CONSTEXPR const Char *parse_format_specs(\n    const Char *begin, const Char *end, SpecHandler &&handler) {\n  if (begin == end || *begin == '}')\n    return begin;\n\n  begin = parse_align(begin, end, handler);\n  if (begin == end) return begin;\n\n  // Parse sign.\n  switch (static_cast<char>(*begin)) {\n  case '+':\n    handler.on_plus();\n    ++begin;\n    break;\n  case '-':\n    handler.on_minus();\n    ++begin;\n    break;\n  case ' ':\n    handler.on_space();\n    ++begin;\n    break;\n  }\n  if (begin == end) return begin;\n\n  if (*begin == '#') {\n    handler.on_hash();\n    if (++begin == end) return begin;\n  }\n\n  // Parse zero flag.\n  if (*begin == '0') {\n    handler.on_zero();\n    if (++begin == end) return begin;\n  }\n\n  begin = parse_width(begin, end, handler);\n  if (begin == end) return begin;\n\n  // Parse precision.\n  if (*begin == '.') {\n    ++begin;\n    auto c = begin != end ? *begin : 0;\n    if ('0' <= c && c <= '9') {\n      handler.on_precision(parse_nonnegative_int(begin, end, handler));\n    } else if (c == '{') {\n      ++begin;\n      if (begin != end) {\n        begin = parse_arg_id(\n              begin, end, precision_adapter<SpecHandler, Char>(handler));\n      }\n      if (begin == end || *begin++ != '}')\n        return handler.on_error(\"invalid format string\"), begin;\n    } else {\n      return handler.on_error(\"missing precision specifier\"), begin;\n    }\n    handler.end_precision();\n  }\n\n  // Parse type.\n  if (begin != end && *begin != '}')\n    handler.on_type(*begin++);\n  return begin;\n}\n\n// Return the result via the out param to workaround gcc bug 77539.\ntemplate <bool IS_CONSTEXPR, typename T, typename Ptr = const T*>\nFMT_CONSTEXPR bool find(Ptr first, Ptr last, T value, Ptr &out) {\n  for (out = first; out != last; ++out) {\n    if (*out == value)\n      return true;\n  }\n  return false;\n}\n\ntemplate <>\ninline bool find<false, char>(\n    const char *first, const char *last, char value, const char *&out) {\n  out = static_cast<const char*>(std::memchr(first, value, internal::to_unsigned(last - first)));\n  return out != FMT_NULL;\n}\n\ntemplate <typename Handler, typename Char>\nstruct id_adapter {\n  FMT_CONSTEXPR void operator()() { handler.on_arg_id(); }\n  FMT_CONSTEXPR void operator()(unsigned id) { handler.on_arg_id(id); }\n  FMT_CONSTEXPR void operator()(basic_string_view<Char> id) {\n    handler.on_arg_id(id);\n  }\n  FMT_CONSTEXPR void on_error(const char *message) {\n    handler.on_error(message);\n  }\n  Handler &handler;\n};\n\ntemplate <bool IS_CONSTEXPR, typename Char, typename Handler>\nFMT_CONSTEXPR void parse_format_string(\n        basic_string_view<Char> format_str, Handler &&handler) {\n  struct writer {\n    FMT_CONSTEXPR void operator()(const Char *begin, const Char *end) {\n      if (begin == end) return;\n      for (;;) {\n        const Char *p = FMT_NULL;\n        if (!find<IS_CONSTEXPR>(begin, end, '}', p))\n          return handler_.on_text(begin, end);\n        ++p;\n        if (p == end || *p != '}')\n          return handler_.on_error(\"unmatched '}' in format string\");\n        handler_.on_text(begin, p);\n        begin = p + 1;\n      }\n    }\n    Handler &handler_;\n  } write{handler};\n  auto begin = format_str.data();\n  auto end = begin + format_str.size();\n  while (begin != end) {\n    // Doing two passes with memchr (one for '{' and another for '}') is up to\n    // 2.5x faster than the naive one-pass implementation on big format strings.\n    const Char *p = begin;\n    if (*begin != '{' && !find<IS_CONSTEXPR>(begin, end, '{', p))\n      return write(begin, end);\n    write(begin, p);\n    ++p;\n    if (p == end)\n      return handler.on_error(\"invalid format string\");\n    if (static_cast<char>(*p) == '}') {\n      handler.on_arg_id();\n      handler.on_replacement_field(p);\n    } else if (*p == '{') {\n      handler.on_text(p, p + 1);\n    } else {\n      p = parse_arg_id(p, end, id_adapter<Handler, Char>{handler});\n      Char c = p != end ? *p : Char();\n      if (c == '}') {\n        handler.on_replacement_field(p);\n      } else if (c == ':') {\n        p = handler.on_format_specs(p + 1, end);\n        if (p == end || *p != '}')\n          return handler.on_error(\"unknown format specifier\");\n      } else {\n        return handler.on_error(\"missing '}' in format string\");\n      }\n    }\n    begin = p + 1;\n  }\n}\n\ntemplate <typename T, typename ParseContext>\nFMT_CONSTEXPR const typename ParseContext::char_type *\n    parse_format_specs(ParseContext &ctx) {\n  // GCC 7.2 requires initializer.\n  formatter<T, typename ParseContext::char_type> f{};\n  return f.parse(ctx);\n}\n\ntemplate <typename Char, typename ErrorHandler, typename... Args>\nclass format_string_checker {\n public:\n  explicit FMT_CONSTEXPR format_string_checker(\n      basic_string_view<Char> format_str, ErrorHandler eh)\n    : arg_id_((std::numeric_limits<unsigned>::max)()), context_(format_str, eh),\n      parse_funcs_{&parse_format_specs<Args, parse_context_type>...} {}\n\n  FMT_CONSTEXPR void on_text(const Char *, const Char *) {}\n\n  FMT_CONSTEXPR void on_arg_id() {\n    arg_id_ = context_.next_arg_id();\n    check_arg_id();\n  }\n  FMT_CONSTEXPR void on_arg_id(unsigned id) {\n    arg_id_ = id;\n    context_.check_arg_id(id);\n    check_arg_id();\n  }\n  FMT_CONSTEXPR void on_arg_id(basic_string_view<Char>) {}\n\n  FMT_CONSTEXPR void on_replacement_field(const Char *) {}\n\n  FMT_CONSTEXPR const Char *on_format_specs(const Char *begin, const Char *) {\n    context_.advance_to(begin);\n    return arg_id_ < NUM_ARGS ?\n          parse_funcs_[arg_id_](context_) : begin;\n  }\n\n  FMT_CONSTEXPR void on_error(const char *message) {\n    context_.on_error(message);\n  }\n\n private:\n  typedef basic_parse_context<Char, ErrorHandler> parse_context_type;\n  enum { NUM_ARGS = sizeof...(Args) };\n\n  FMT_CONSTEXPR void check_arg_id() {\n    if (arg_id_ >= NUM_ARGS)\n      context_.on_error(\"argument index out of range\");\n  }\n\n  // Format specifier parsing function.\n  typedef const Char *(*parse_func)(parse_context_type &);\n\n  unsigned arg_id_;\n  parse_context_type context_;\n  parse_func parse_funcs_[NUM_ARGS > 0 ? NUM_ARGS : 1];\n};\n\ntemplate <typename Char, typename ErrorHandler, typename... Args>\nFMT_CONSTEXPR bool do_check_format_string(\n    basic_string_view<Char> s, ErrorHandler eh = ErrorHandler()) {\n  format_string_checker<Char, ErrorHandler, Args...> checker(s, eh);\n  parse_format_string<true>(s, checker);\n  return true;\n}\n\ntemplate <typename... Args, typename S>\ntypename std::enable_if<is_compile_string<S>::value>::type\n    check_format_string(S format_str) {\n  typedef typename S::char_type char_t;\n  FMT_CONSTEXPR_DECL bool invalid_format = internal::do_check_format_string<\n      char_t, internal::error_handler, Args...>(to_string_view(format_str));\n  (void)invalid_format;\n}\n\n// Specifies whether to format T using the standard formatter.\n// It is not possible to use get_type in formatter specialization directly\n// because of a bug in MSVC.\ntemplate <typename Context, typename T>\nstruct format_type :\n  std::integral_constant<bool, get_type<Context, T>::value != custom_type> {};\n\ntemplate <template <typename> class Handler, typename Spec, typename Context>\nvoid handle_dynamic_spec(\n    Spec &value, arg_ref<typename Context::char_type> ref, Context &ctx) {\n  typedef typename Context::char_type char_type;\n  switch (ref.kind) {\n  case arg_ref<char_type>::NONE:\n    break;\n  case arg_ref<char_type>::INDEX:\n    internal::set_dynamic_spec<Handler>(\n          value, ctx.get_arg(ref.index), ctx.error_handler());\n    break;\n  case arg_ref<char_type>::NAME:\n    internal::set_dynamic_spec<Handler>(\n          value, ctx.get_arg({ref.name.value, ref.name.size}),\n          ctx.error_handler());\n    break;\n  }\n}\n}  // namespace internal\n\n/** The default argument formatter. */\ntemplate <typename Range>\nclass arg_formatter:\n  public internal::function<\n    typename internal::arg_formatter_base<Range>::iterator>,\n  public internal::arg_formatter_base<Range> {\n private:\n  typedef typename Range::value_type char_type;\n  typedef internal::arg_formatter_base<Range> base;\n  typedef basic_format_context<typename base::iterator, char_type> context_type;\n\n  context_type &ctx_;\n\n public:\n  typedef Range range;\n  typedef typename base::iterator iterator;\n  typedef typename base::format_specs format_specs;\n\n  /**\n    \\rst\n    Constructs an argument formatter object.\n    *ctx* is a reference to the formatting context,\n    *spec* contains format specifier information for standard argument types.\n    \\endrst\n   */\n  explicit arg_formatter(context_type &ctx, format_specs *spec = FMT_NULL)\n  : base(Range(ctx.out()), spec, ctx.locale()), ctx_(ctx) {}\n\n  // Deprecated.\n  arg_formatter(context_type &ctx, format_specs &spec)\n  : base(Range(ctx.out()), &spec), ctx_(ctx) {}\n\n  using base::operator();\n\n  /** Formats an argument of a user-defined type. */\n  iterator operator()(typename basic_format_arg<context_type>::handle handle) {\n    handle.format(ctx_);\n    return this->out();\n  }\n};\n\n/**\n An error returned by an operating system or a language runtime,\n for example a file opening error.\n*/\nclass system_error : public std::runtime_error {\n private:\n  FMT_API void init(int err_code, string_view format_str, format_args args);\n\n protected:\n  int error_code_;\n\n  system_error() : std::runtime_error(\"\") {}\n\n public:\n  /**\n   \\rst\n   Constructs a :class:`fmt::system_error` object with a description\n   formatted with `fmt::format_system_error`. *message* and additional\n   arguments passed into the constructor are formatted similarly to\n   `fmt::format`.\n\n   **Example**::\n\n     // This throws a system_error with the description\n     //   cannot open file 'madeup': No such file or directory\n     // or similar (system message may vary).\n     const char *filename = \"madeup\";\n     std::FILE *file = std::fopen(filename, \"r\");\n     if (!file)\n       throw fmt::system_error(errno, \"cannot open file '{}'\", filename);\n   \\endrst\n  */\n  template <typename... Args>\n  system_error(int error_code, string_view message, const Args &... args)\n    : std::runtime_error(\"\") {\n    init(error_code, message, make_format_args(args...));\n  }\n\n  int error_code() const { return error_code_; }\n};\n\n/**\n  \\rst\n  Formats an error returned by an operating system or a language runtime,\n  for example a file opening error, and writes it to *out* in the following\n  form:\n\n  .. parsed-literal::\n     *<message>*: *<system-message>*\n\n  where *<message>* is the passed message and *<system-message>* is\n  the system message corresponding to the error code.\n  *error_code* is a system error code as given by ``errno``.\n  If *error_code* is not a valid error code such as -1, the system message\n  may look like \"Unknown error -1\" and is platform-dependent.\n  \\endrst\n */\nFMT_API void format_system_error(internal::buffer &out, int error_code,\n                                 fmt::string_view message) FMT_NOEXCEPT;\n\n/**\n  This template provides operations for formatting and writing data into a\n  character range.\n */\ntemplate <typename Range>\nclass basic_writer {\n public:\n  typedef typename Range::value_type char_type;\n  typedef decltype(internal::declval<Range>().begin()) iterator;\n  typedef basic_format_specs<char_type> format_specs;\n\n private:\n  iterator out_;  // Output iterator.\n  internal::locale_ref locale_;\n\n  // Attempts to reserve space for n extra characters in the output range.\n  // Returns a pointer to the reserved range or a reference to out_.\n  auto reserve(std::size_t n) -> decltype(internal::reserve(out_, n)) {\n    return internal::reserve(out_, n);\n  }\n\n  // Writes a value in the format\n  //   <left-padding><value><right-padding>\n  // where <value> is written by f(it).\n  template <typename F>\n  void write_padded(const align_spec &spec, F &&f) {\n    unsigned width = spec.width(); // User-perceived width (in code points).\n    size_t size = f.size(); // The number of code units.\n    size_t num_code_points = width != 0 ? f.width() : size;\n    if (width <= num_code_points)\n      return f(reserve(size));\n    auto &&it = reserve(width + (size - num_code_points));\n    char_type fill = static_cast<char_type>(spec.fill());\n    std::size_t padding = width - num_code_points;\n    if (spec.align() == ALIGN_RIGHT) {\n      it = std::fill_n(it, padding, fill);\n      f(it);\n    } else if (spec.align() == ALIGN_CENTER) {\n      std::size_t left_padding = padding / 2;\n      it = std::fill_n(it, left_padding, fill);\n      f(it);\n      it = std::fill_n(it, padding - left_padding, fill);\n    } else {\n      f(it);\n      it = std::fill_n(it, padding, fill);\n    }\n  }\n\n  template <typename F>\n  struct padded_int_writer {\n    size_t size_;\n    string_view prefix;\n    char_type fill;\n    std::size_t padding;\n    F f;\n\n    size_t size() const { return size_; }\n    size_t width() const { return size_; }\n\n    template <typename It>\n    void operator()(It &&it) const {\n      if (prefix.size() != 0)\n        it = internal::copy_str<char_type>(prefix.begin(), prefix.end(), it);\n      it = std::fill_n(it, padding, fill);\n      f(it);\n    }\n  };\n\n  // Writes an integer in the format\n  //   <left-padding><prefix><numeric-padding><digits><right-padding>\n  // where <digits> are written by f(it).\n  template <typename Spec, typename F>\n  void write_int(int num_digits, string_view prefix,\n                 const Spec &spec, F f) {\n    std::size_t size = prefix.size() + internal::to_unsigned(num_digits);\n    char_type fill = static_cast<char_type>(spec.fill());\n    std::size_t padding = 0;\n    if (spec.align() == ALIGN_NUMERIC) {\n      if (spec.width() > size) {\n        padding = spec.width() - size;\n        size = spec.width();\n      }\n    } else if (spec.precision > num_digits) {\n      size = prefix.size() + internal::to_unsigned(spec.precision);\n      padding = internal::to_unsigned(spec.precision - num_digits);\n      fill = static_cast<char_type>('0');\n    }\n    align_spec as = spec;\n    if (spec.align() == ALIGN_DEFAULT)\n      as.align_ = ALIGN_RIGHT;\n    write_padded(as, padded_int_writer<F>{size, prefix, fill, padding, f});\n  }\n\n  // Writes a decimal integer.\n  template <typename Int>\n  void write_decimal(Int value) {\n    typedef typename internal::int_traits<Int>::main_type main_type;\n    main_type abs_value = static_cast<main_type>(value);\n    bool is_negative = internal::is_negative(value);\n    if (is_negative)\n      abs_value = 0 - abs_value;\n    int num_digits = internal::count_digits(abs_value);\n    auto &&it = reserve((is_negative ? 1 : 0) + static_cast<size_t>(num_digits));\n    if (is_negative)\n      *it++ = static_cast<char_type>('-');\n    it = internal::format_decimal<char_type>(it, abs_value, num_digits);\n  }\n\n  // The handle_int_type_spec handler that writes an integer.\n  template <typename Int, typename Spec>\n  struct int_writer {\n    typedef typename internal::int_traits<Int>::main_type unsigned_type;\n\n    basic_writer<Range> &writer;\n    const Spec &spec;\n    unsigned_type abs_value;\n    char prefix[4];\n    unsigned prefix_size;\n\n    string_view get_prefix() const { return string_view(prefix, prefix_size); }\n\n    // Counts the number of digits in abs_value. BITS = log2(radix).\n    template <unsigned BITS>\n    int count_digits() const {\n      unsigned_type n = abs_value;\n      int num_digits = 0;\n      do {\n        ++num_digits;\n      } while ((n >>= BITS) != 0);\n      return num_digits;\n    }\n\n    int_writer(basic_writer<Range> &w, Int value, const Spec &s)\n      : writer(w), spec(s), abs_value(static_cast<unsigned_type>(value)),\n        prefix_size(0) {\n      if (internal::is_negative(value)) {\n        prefix[0] = '-';\n        ++prefix_size;\n        abs_value = 0 - abs_value;\n      } else if (spec.has(SIGN_FLAG)) {\n        prefix[0] = spec.has(PLUS_FLAG) ? '+' : ' ';\n        ++prefix_size;\n      }\n    }\n\n    struct dec_writer {\n      unsigned_type abs_value;\n      int num_digits;\n\n      template <typename It>\n      void operator()(It &&it) const {\n        it = internal::format_decimal<char_type>(it, abs_value, num_digits);\n      }\n    };\n\n    void on_dec() {\n      int num_digits = internal::count_digits(abs_value);\n      writer.write_int(num_digits, get_prefix(), spec,\n                       dec_writer{abs_value, num_digits});\n    }\n\n    struct hex_writer {\n      int_writer &self;\n      int num_digits;\n\n      template <typename It>\n      void operator()(It &&it) const {\n        it = internal::format_uint<4, char_type>(\n              it, self.abs_value, num_digits, self.spec.type != 'x');\n      }\n    };\n\n    void on_hex() {\n      if (spec.has(HASH_FLAG)) {\n        prefix[prefix_size++] = '0';\n        prefix[prefix_size++] = static_cast<char>(spec.type);\n      }\n      int num_digits = count_digits<4>();\n      writer.write_int(num_digits, get_prefix(), spec,\n                       hex_writer{*this, num_digits});\n    }\n\n    template <int BITS>\n    struct bin_writer {\n      unsigned_type abs_value;\n      int num_digits;\n\n      template <typename It>\n      void operator()(It &&it) const {\n        it = internal::format_uint<BITS, char_type>(it, abs_value, num_digits);\n      }\n    };\n\n    void on_bin() {\n      if (spec.has(HASH_FLAG)) {\n        prefix[prefix_size++] = '0';\n        prefix[prefix_size++] = static_cast<char>(spec.type);\n      }\n      int num_digits = count_digits<1>();\n      writer.write_int(num_digits, get_prefix(), spec,\n                       bin_writer<1>{abs_value, num_digits});\n    }\n\n    void on_oct() {\n      int num_digits = count_digits<3>();\n      if (spec.has(HASH_FLAG) &&\n          spec.precision <= num_digits) {\n        // Octal prefix '0' is counted as a digit, so only add it if precision\n        // is not greater than the number of digits.\n        prefix[prefix_size++] = '0';\n      }\n      writer.write_int(num_digits, get_prefix(), spec,\n                       bin_writer<3>{abs_value, num_digits});\n    }\n\n    enum { SEP_SIZE = 1 };\n\n    struct num_writer {\n      unsigned_type abs_value;\n      int size;\n      char_type sep;\n\n      template <typename It>\n      void operator()(It &&it) const {\n        basic_string_view<char_type> s(&sep, SEP_SIZE);\n        it = internal::format_decimal<char_type>(\n              it, abs_value, size, internal::add_thousands_sep<char_type>(s));\n      }\n    };\n\n    void on_num() {\n      int num_digits = internal::count_digits(abs_value);\n      char_type sep = internal::thousands_sep<char_type>(writer.locale_);\n      int size = num_digits + SEP_SIZE * ((num_digits - 1) / 3);\n      writer.write_int(size, get_prefix(), spec,\n                       num_writer{abs_value, size, sep});\n    }\n\n    void on_error() {\n      FMT_THROW(format_error(\"invalid type specifier\"));\n    }\n  };\n\n  // Writes a formatted integer.\n  template <typename T, typename Spec>\n  void write_int(T value, const Spec &spec) {\n    internal::handle_int_type_spec(spec.type,\n                                   int_writer<T, Spec>(*this, value, spec));\n  }\n\n  enum {INF_SIZE = 3}; // This is an enum to workaround a bug in MSVC.\n\n  struct inf_or_nan_writer {\n    char sign;\n    const char *str;\n\n    size_t size() const {\n      return static_cast<std::size_t>(INF_SIZE + (sign ? 1 : 0));\n    }\n    size_t width() const { return size(); }\n\n    template <typename It>\n    void operator()(It &&it) const {\n      if (sign)\n        *it++ = static_cast<char_type>(sign);\n      it = internal::copy_str<char_type>(\n            str, str + static_cast<std::size_t>(INF_SIZE), it);\n    }\n  };\n\n  struct double_writer {\n    size_t n;\n    char sign;\n    internal::buffer &buffer;\n\n    size_t size() const { return buffer.size() + (sign ? 1 : 0); }\n    size_t width() const { return size(); }\n\n    template <typename It>\n    void operator()(It &&it) {\n      if (sign) {\n        *it++ = static_cast<char_type>(sign);\n        --n;\n      }\n      it = internal::copy_str<char_type>(buffer.begin(), buffer.end(), it);\n    }\n  };\n\n  // Formats a floating-point number (double or long double).\n  template <typename T>\n  void write_double(T value, const format_specs &spec);\n\n  template <typename Char>\n  struct str_writer {\n    const Char *s;\n    size_t size_;\n\n    size_t size() const { return size_; }\n    size_t width() const {\n      return internal::count_code_points(basic_string_view<Char>(s, size_));\n    }\n\n    template <typename It>\n    void operator()(It &&it) const {\n      it = internal::copy_str<char_type>(s, s + size_, it);\n    }\n  };\n\n  template <typename Char>\n  friend class internal::arg_formatter_base;\n\n public:\n  /** Constructs a ``basic_writer`` object. */\n  explicit basic_writer(\n      Range out, internal::locale_ref loc = internal::locale_ref())\n    : out_(out.begin()), locale_(loc) {}\n\n  iterator out() const { return out_; }\n\n  void write(int value) { write_decimal(value); }\n  void write(long value) { write_decimal(value); }\n  void write(long long value) { write_decimal(value); }\n\n  void write(unsigned value) { write_decimal(value); }\n  void write(unsigned long value) { write_decimal(value); }\n  void write(unsigned long long value) { write_decimal(value); }\n\n  /**\n    \\rst\n    Formats *value* and writes it to the buffer.\n    \\endrst\n   */\n  template <typename T, typename FormatSpec, typename... FormatSpecs>\n  typename std::enable_if<std::is_integral<T>::value, void>::type\n      write(T value, FormatSpec spec, FormatSpecs... specs) {\n    format_specs s(spec, specs...);\n    s.align_ = ALIGN_RIGHT;\n    write_int(value, s);\n  }\n\n  void write(double value) {\n    write_double(value, format_specs());\n  }\n\n  /**\n    \\rst\n    Formats *value* using the general format for floating-point numbers\n    (``'g'``) and writes it to the buffer.\n    \\endrst\n   */\n  void write(long double value) {\n    write_double(value, format_specs());\n  }\n\n  /** Writes a character to the buffer. */\n  void write(char value) {\n    *reserve(1) = value;\n  }\n  void write(wchar_t value) {\n    static_assert(std::is_same<char_type, wchar_t>::value, \"\");\n    *reserve(1) = value;\n  }\n\n  /**\n    \\rst\n    Writes *value* to the buffer.\n    \\endrst\n   */\n  void write(string_view value) {\n    auto &&it = reserve(value.size());\n    it = internal::copy_str<char_type>(value.begin(), value.end(), it);\n  }\n  void write(wstring_view value) {\n    static_assert(std::is_same<char_type, wchar_t>::value, \"\");\n    auto &&it = reserve(value.size());\n    it = std::copy(value.begin(), value.end(), it);\n  }\n\n  // Writes a formatted string.\n  template <typename Char>\n  void write(const Char *s, std::size_t size, const align_spec &spec) {\n    write_padded(spec, str_writer<Char>{s, size});\n  }\n\n  template <typename Char>\n  void write(basic_string_view<Char> s,\n             const format_specs &spec = format_specs()) {\n    const Char *data = s.data();\n    std::size_t size = s.size();\n    if (spec.precision >= 0 && internal::to_unsigned(spec.precision) < size)\n      size = internal::to_unsigned(spec.precision);\n    write(data, size, spec);\n  }\n\n  template <typename T>\n  typename std::enable_if<std::is_same<T, void>::value>::type\n      write(const T *p) {\n    format_specs specs;\n    specs.flags = HASH_FLAG;\n    specs.type = 'x';\n    write_int(reinterpret_cast<uintptr_t>(p), specs);\n  }\n};\n\nstruct float_spec_handler {\n  char type;\n  bool upper;\n\n  explicit float_spec_handler(char t) : type(t), upper(false) {}\n\n  void on_general() {\n    if (type == 'G')\n      upper = true;\n    else\n      type = 'g';\n  }\n\n  void on_exp() {\n    if (type == 'E')\n      upper = true;\n  }\n\n  void on_fixed() {\n    if (type == 'F') {\n      upper = true;\n#if FMT_MSC_VER\n      // MSVC's printf doesn't support 'F'.\n      type = 'f';\n#endif\n    }\n  }\n\n  void on_hex() {\n    if (type == 'A')\n      upper = true;\n  }\n\n  void on_error() {\n    FMT_THROW(format_error(\"invalid type specifier\"));\n  }\n};\n\ntemplate <typename Range>\ntemplate <typename T>\nvoid basic_writer<Range>::write_double(T value, const format_specs &spec) {\n  // Check type.\n  float_spec_handler handler(static_cast<char>(spec.type));\n  internal::handle_float_type_spec(handler.type, handler);\n\n  char sign = 0;\n  // Use signbit instead of value < 0 because the latter is always\n  // false for NaN.\n  if (std::signbit(value)) {\n    sign = '-';\n    value = -value;\n  } else if (spec.has(SIGN_FLAG)) {\n    sign = spec.has(PLUS_FLAG) ? '+' : ' ';\n  }\n\n  struct write_inf_or_nan_t {\n    basic_writer &writer;\n    format_specs spec;\n    char sign;\n    void operator()(const char *str) const {\n      writer.write_padded(spec, inf_or_nan_writer{sign, str});\n    }\n  } write_inf_or_nan = {*this, spec, sign};\n\n  // Format NaN and ininity ourselves because sprintf's output is not consistent\n  // across platforms.\n  if (internal::fputil::isnotanumber(value))\n    return write_inf_or_nan(handler.upper ? \"NAN\" : \"nan\");\n  if (internal::fputil::isinfinity(value))\n    return write_inf_or_nan(handler.upper ? \"INF\" : \"inf\");\n\n  memory_buffer buffer;\n  bool use_grisu = FMT_USE_GRISU && sizeof(T) <= sizeof(double) &&\n      spec.type != 'a' && spec.type != 'A' &&\n      internal::grisu2_format(static_cast<double>(value), buffer, spec);\n  if (!use_grisu) {\n    format_specs normalized_spec(spec);\n    normalized_spec.type = handler.type;\n    internal::sprintf_format(value, buffer, normalized_spec);\n  }\n  size_t n = buffer.size();\n  align_spec as = spec;\n  if (spec.align() == ALIGN_NUMERIC) {\n    if (sign) {\n      auto &&it = reserve(1);\n      *it++ = static_cast<char_type>(sign);\n      sign = 0;\n      if (as.width_)\n        --as.width_;\n    }\n    as.align_ = ALIGN_RIGHT;\n  } else {\n    if (spec.align() == ALIGN_DEFAULT)\n      as.align_ = ALIGN_RIGHT;\n    if (sign)\n      ++n;\n  }\n  write_padded(as, double_writer{n, sign, buffer});\n}\n\n// Reports a system error without throwing an exception.\n// Can be used to report errors from destructors.\nFMT_API void report_system_error(int error_code,\n                                 string_view message) FMT_NOEXCEPT;\n\n#if FMT_USE_WINDOWS_H\n\n/** A Windows error. */\nclass windows_error : public system_error {\n private:\n  FMT_API void init(int error_code, string_view format_str, format_args args);\n\n public:\n  /**\n   \\rst\n   Constructs a :class:`fmt::windows_error` object with the description\n   of the form\n\n   .. parsed-literal::\n     *<message>*: *<system-message>*\n\n   where *<message>* is the formatted message and *<system-message>* is the\n   system message corresponding to the error code.\n   *error_code* is a Windows error code as given by ``GetLastError``.\n   If *error_code* is not a valid error code such as -1, the system message\n   will look like \"error -1\".\n\n   **Example**::\n\n     // This throws a windows_error with the description\n     //   cannot open file 'madeup': The system cannot find the file specified.\n     // or similar (system message may vary).\n     const char *filename = \"madeup\";\n     LPOFSTRUCT of = LPOFSTRUCT();\n     HFILE file = OpenFile(filename, &of, OF_READ);\n     if (file == HFILE_ERROR) {\n       throw fmt::windows_error(GetLastError(),\n                                \"cannot open file '{}'\", filename);\n     }\n   \\endrst\n  */\n  template <typename... Args>\n  windows_error(int error_code, string_view message, const Args &... args) {\n    init(error_code, message, make_format_args(args...));\n  }\n};\n\n// Reports a Windows error without throwing an exception.\n// Can be used to report errors from destructors.\nFMT_API void report_windows_error(int error_code,\n                                  string_view message) FMT_NOEXCEPT;\n\n#endif\n\n/** Fast integer formatter. */\nclass format_int {\n private:\n  // Buffer should be large enough to hold all digits (digits10 + 1),\n  // a sign and a null character.\n  enum {BUFFER_SIZE = std::numeric_limits<unsigned long long>::digits10 + 3};\n  mutable char buffer_[BUFFER_SIZE];\n  char *str_;\n\n  // Formats value in reverse and returns a pointer to the beginning.\n  char *format_decimal(unsigned long long value) {\n    char *ptr = buffer_ + (BUFFER_SIZE - 1);  // Parens to workaround MSVC bug.\n    while (value >= 100) {\n      // Integer division is slow so do it for a group of two digits instead\n      // of for every digit. The idea comes from the talk by Alexandrescu\n      // \"Three Optimization Tips for C++\". See speed-test for a comparison.\n      unsigned index = static_cast<unsigned>((value % 100) * 2);\n      value /= 100;\n      *--ptr = internal::data::DIGITS[index + 1];\n      *--ptr = internal::data::DIGITS[index];\n    }\n    if (value < 10) {\n      *--ptr = static_cast<char>('0' + value);\n      return ptr;\n    }\n    unsigned index = static_cast<unsigned>(value * 2);\n    *--ptr = internal::data::DIGITS[index + 1];\n    *--ptr = internal::data::DIGITS[index];\n    return ptr;\n  }\n\n  void format_signed(long long value) {\n    unsigned long long abs_value = static_cast<unsigned long long>(value);\n    bool negative = value < 0;\n    if (negative)\n      abs_value = 0 - abs_value;\n    str_ = format_decimal(abs_value);\n    if (negative)\n      *--str_ = '-';\n  }\n\n public:\n  explicit format_int(int value) { format_signed(value); }\n  explicit format_int(long value) { format_signed(value); }\n  explicit format_int(long long value) { format_signed(value); }\n  explicit format_int(unsigned value) : str_(format_decimal(value)) {}\n  explicit format_int(unsigned long value) : str_(format_decimal(value)) {}\n  explicit format_int(unsigned long long value) : str_(format_decimal(value)) {}\n\n  /** Returns the number of characters written to the output buffer. */\n  std::size_t size() const {\n    return internal::to_unsigned(buffer_ - str_ + BUFFER_SIZE - 1);\n  }\n\n  /**\n    Returns a pointer to the output buffer content. No terminating null\n    character is appended.\n   */\n  const char *data() const { return str_; }\n\n  /**\n    Returns a pointer to the output buffer content with terminating null\n    character appended.\n   */\n  const char *c_str() const {\n    buffer_[BUFFER_SIZE - 1] = '\\0';\n    return str_;\n  }\n\n  /**\n    \\rst\n    Returns the content of the output buffer as an ``std::string``.\n    \\endrst\n   */\n  std::string str() const { return std::string(str_, size()); }\n};\n\n// DEPRECATED!\n// Formats a decimal integer value writing into buffer and returns\n// a pointer to the end of the formatted string. This function doesn't\n// write a terminating null character.\ntemplate <typename T>\ninline void format_decimal(char *&buffer, T value) {\n  typedef typename internal::int_traits<T>::main_type main_type;\n  main_type abs_value = static_cast<main_type>(value);\n  if (internal::is_negative(value)) {\n    *buffer++ = '-';\n    abs_value = 0 - abs_value;\n  }\n  if (abs_value < 100) {\n    if (abs_value < 10) {\n      *buffer++ = static_cast<char>('0' + abs_value);\n      return;\n    }\n    unsigned index = static_cast<unsigned>(abs_value * 2);\n    *buffer++ = internal::data::DIGITS[index];\n    *buffer++ = internal::data::DIGITS[index + 1];\n    return;\n  }\n  int num_digits = internal::count_digits(abs_value);\n  internal::format_decimal<char>(\n        internal::make_checked(buffer, internal::to_unsigned(num_digits)), abs_value, num_digits);\n  buffer += num_digits;\n}\n\n// Formatter of objects of type T.\ntemplate <typename T, typename Char>\nstruct formatter<\n    T, Char,\n    typename std::enable_if<internal::format_type<\n        typename buffer_context<Char>::type, T>::value>::type> {\n\n  // Parses format specifiers stopping either at the end of the range or at the\n  // terminating '}'.\n  template <typename ParseContext>\n  FMT_CONSTEXPR typename ParseContext::iterator parse(ParseContext &ctx) {\n    typedef internal::dynamic_specs_handler<ParseContext> handler_type;\n    auto type = internal::get_type<\n      typename buffer_context<Char>::type, T>::value;\n    internal::specs_checker<handler_type>\n        handler(handler_type(specs_, ctx), type);\n    auto it = parse_format_specs(ctx.begin(), ctx.end(), handler);\n    auto type_spec = specs_.type;\n    auto eh = ctx.error_handler();\n    switch (type) {\n    case internal::none_type:\n    case internal::named_arg_type:\n      FMT_ASSERT(false, \"invalid argument type\");\n      break;\n    case internal::int_type:\n    case internal::uint_type:\n    case internal::long_long_type:\n    case internal::ulong_long_type:\n    case internal::bool_type:\n      handle_int_type_spec(\n            type_spec, internal::int_type_checker<decltype(eh)>(eh));\n      break;\n    case internal::char_type:\n      handle_char_specs(\n          &specs_,\n          internal::char_specs_checker<decltype(eh)>(type_spec, eh));\n      break;\n    case internal::double_type:\n    case internal::long_double_type:\n      handle_float_type_spec(\n            type_spec, internal::float_type_checker<decltype(eh)>(eh));\n      break;\n    case internal::cstring_type:\n      internal::handle_cstring_type_spec(\n            type_spec, internal::cstring_type_checker<decltype(eh)>(eh));\n      break;\n    case internal::string_type:\n      internal::check_string_type_spec(type_spec, eh);\n      break;\n    case internal::pointer_type:\n      internal::check_pointer_type_spec(type_spec, eh);\n      break;\n    case internal::custom_type:\n      // Custom format specifiers should be checked in parse functions of\n      // formatter specializations.\n      break;\n    }\n    return it;\n  }\n\n  template <typename FormatContext>\n  auto format(const T &val, FormatContext &ctx) -> decltype(ctx.out()) {\n    internal::handle_dynamic_spec<internal::width_checker>(\n      specs_.width_, specs_.width_ref, ctx);\n    internal::handle_dynamic_spec<internal::precision_checker>(\n      specs_.precision, specs_.precision_ref, ctx);\n    typedef output_range<typename FormatContext::iterator,\n                         typename FormatContext::char_type> range_type;\n    return visit_format_arg(arg_formatter<range_type>(ctx, &specs_),\n                      internal::make_arg<FormatContext>(val));\n  }\n\n private:\n  internal::dynamic_format_specs<Char> specs_;\n};\n\n// A formatter for types known only at run time such as variant alternatives.\n//\n// Usage:\n//   typedef std::variant<int, std::string> variant;\n//   template <>\n//   struct formatter<variant>: dynamic_formatter<> {\n//     void format(buffer &buf, const variant &v, context &ctx) {\n//       visit([&](const auto &val) { format(buf, val, ctx); }, v);\n//     }\n//   };\ntemplate <typename Char = char>\nclass dynamic_formatter {\n private:\n  struct null_handler: internal::error_handler {\n    void on_align(alignment) {}\n    void on_plus() {}\n    void on_minus() {}\n    void on_space() {}\n    void on_hash() {}\n  };\n\n public:\n  template <typename ParseContext>\n  auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {\n    // Checks are deferred to formatting time when the argument type is known.\n    internal::dynamic_specs_handler<ParseContext> handler(specs_, ctx);\n    return parse_format_specs(ctx.begin(), ctx.end(), handler);\n  }\n\n  template <typename T, typename FormatContext>\n  auto format(const T &val, FormatContext &ctx) -> decltype(ctx.out()) {\n    handle_specs(ctx);\n    internal::specs_checker<null_handler>\n        checker(null_handler(), internal::get_type<FormatContext, T>::value);\n    checker.on_align(specs_.align());\n    if (specs_.flags == 0);  // Do nothing.\n    else if (specs_.has(SIGN_FLAG))\n      specs_.has(PLUS_FLAG) ? checker.on_plus() : checker.on_space();\n    else if (specs_.has(MINUS_FLAG))\n      checker.on_minus();\n    else if (specs_.has(HASH_FLAG))\n      checker.on_hash();\n    if (specs_.precision != -1)\n      checker.end_precision();\n    typedef output_range<typename FormatContext::iterator,\n                         typename FormatContext::char_type> range;\n    visit_format_arg(arg_formatter<range>(ctx, &specs_),\n               internal::make_arg<FormatContext>(val));\n    return ctx.out();\n  }\n\n private:\n  template <typename Context>\n  void handle_specs(Context &ctx) {\n    internal::handle_dynamic_spec<internal::width_checker>(\n      specs_.width_, specs_.width_ref, ctx);\n    internal::handle_dynamic_spec<internal::precision_checker>(\n      specs_.precision, specs_.precision_ref, ctx);\n  }\n\n  internal::dynamic_format_specs<Char> specs_;\n};\n\ntemplate <typename Range, typename Char>\ntypename basic_format_context<Range, Char>::format_arg\n  basic_format_context<Range, Char>::get_arg(\n    basic_string_view<char_type> name) {\n  map_.init(this->args());\n  format_arg arg = map_.find(name);\n  if (arg.type() == internal::none_type)\n    this->on_error(\"argument not found\");\n  return arg;\n}\n\ntemplate <typename ArgFormatter, typename Char, typename Context>\nstruct format_handler : internal::error_handler {\n  typedef typename ArgFormatter::range range;\n\n  format_handler(range r, basic_string_view<Char> str,\n                 basic_format_args<Context> format_args,\n                 internal::locale_ref loc)\n    : context(r.begin(), str, format_args, loc) {}\n\n  void on_text(const Char *begin, const Char *end) {\n    auto size = internal::to_unsigned(end - begin);\n    auto out = context.out();\n    auto &&it = internal::reserve(out, size);\n    it = std::copy_n(begin, size, it);\n    context.advance_to(out);\n  }\n\n  void on_arg_id() { arg = context.next_arg(); }\n  void on_arg_id(unsigned id) {\n    context.parse_context().check_arg_id(id);\n    arg = context.get_arg(id);\n  }\n  void on_arg_id(basic_string_view<Char> id) {\n    arg = context.get_arg(id);\n  }\n\n  void on_replacement_field(const Char *p) {\n    context.parse_context().advance_to(p);\n    internal::custom_formatter<Char, Context> f(context);\n    if (!visit_format_arg(f, arg))\n      context.advance_to(visit_format_arg(ArgFormatter(context), arg));\n  }\n\n  const Char *on_format_specs(const Char *begin, const Char *end) {\n    auto &parse_ctx = context.parse_context();\n    parse_ctx.advance_to(begin);\n    internal::custom_formatter<Char, Context> f(context);\n    if (visit_format_arg(f, arg))\n      return parse_ctx.begin();\n    basic_format_specs<Char> specs;\n    using internal::specs_handler;\n    internal::specs_checker<specs_handler<Context>>\n        handler(specs_handler<Context>(specs, context), arg.type());\n    begin = parse_format_specs(begin, end, handler);\n    if (begin == end || *begin != '}')\n      on_error(\"missing '}' in format string\");\n    parse_ctx.advance_to(begin);\n    context.advance_to(visit_format_arg(ArgFormatter(context, &specs), arg));\n    return begin;\n  }\n\n  Context context;\n  basic_format_arg<Context> arg;\n};\n\n/** Formats arguments and writes the output to the range. */\ntemplate <typename ArgFormatter, typename Char, typename Context>\ntypename Context::iterator vformat_to(\n    typename ArgFormatter::range out,\n    basic_string_view<Char> format_str,\n    basic_format_args<Context> args,\n    internal::locale_ref loc = internal::locale_ref()) {\n  format_handler<ArgFormatter, Char, Context> h(out, format_str, args, loc);\n  internal::parse_format_string<false>(format_str, h);\n  return h.context.out();\n}\n\n// Casts ``p`` to ``const void*`` for pointer formatting.\n// Example:\n//   auto s = format(\"{}\", ptr(p));\ntemplate <typename T>\ninline const void *ptr(const T *p) { return p; }\n\ntemplate <typename It, typename Char>\nstruct arg_join {\n  It begin;\n  It end;\n  basic_string_view<Char> sep;\n\n  arg_join(It begin, It end, basic_string_view<Char> sep)\n    : begin(begin), end(end), sep(sep) {}\n};\n\ntemplate <typename It, typename Char>\nstruct formatter<arg_join<It, Char>, Char>:\n    formatter<typename std::iterator_traits<It>::value_type, Char> {\n  template <typename FormatContext>\n  auto format(const arg_join<It, Char> &value, FormatContext &ctx)\n      -> decltype(ctx.out()) {\n    typedef formatter<typename std::iterator_traits<It>::value_type, Char> base;\n    auto it = value.begin;\n    auto out = ctx.out();\n    if (it != value.end) {\n      out = base::format(*it++, ctx);\n      while (it != value.end) {\n        out = std::copy(value.sep.begin(), value.sep.end(), out);\n        ctx.advance_to(out);\n        out = base::format(*it++, ctx);\n      }\n    }\n    return out;\n  }\n};\n\ntemplate <typename It>\narg_join<It, char> join(It begin, It end, string_view sep) {\n  return arg_join<It, char>(begin, end, sep);\n}\n\ntemplate <typename It>\narg_join<It, wchar_t> join(It begin, It end, wstring_view sep) {\n  return arg_join<It, wchar_t>(begin, end, sep);\n}\n\n// The following causes ICE in gcc 4.4.\n#if FMT_USE_TRAILING_RETURN && (!FMT_GCC_VERSION || FMT_GCC_VERSION >= 405)\ntemplate <typename Range>\nauto join(const Range &range, string_view sep)\n    -> arg_join<decltype(internal::begin(range)), char> {\n  return join(internal::begin(range), internal::end(range), sep);\n}\n\ntemplate <typename Range>\nauto join(const Range &range, wstring_view sep)\n    -> arg_join<decltype(internal::begin(range)), wchar_t> {\n  return join(internal::begin(range), internal::end(range), sep);\n}\n#endif\n\n/**\n  \\rst\n  Converts *value* to ``std::string`` using the default format for type *T*.\n  It doesn't support user-defined types with custom formatters.\n\n  **Example**::\n\n    #include <fmt/format.h>\n\n    std::string answer = fmt::to_string(42);\n  \\endrst\n */\ntemplate <typename T>\nstd::string to_string(const T &value) {\n  std::string str;\n  internal::container_buffer<std::string> buf(str);\n  writer(buf).write(value);\n  return str;\n}\n\n/**\n  Converts *value* to ``std::wstring`` using the default format for type *T*.\n */\ntemplate <typename T>\nstd::wstring to_wstring(const T &value) {\n  std::wstring str;\n  internal::container_buffer<std::wstring> buf(str);\n  wwriter(buf).write(value);\n  return str;\n}\n\ntemplate <typename Char, std::size_t SIZE>\nstd::basic_string<Char> to_string(const basic_memory_buffer<Char, SIZE> &buf) {\n  return std::basic_string<Char>(buf.data(), buf.size());\n}\n\ntemplate <typename Char>\ntypename buffer_context<Char>::type::iterator internal::vformat_to(\n    internal::basic_buffer<Char> &buf, basic_string_view<Char> format_str,\n    basic_format_args<typename buffer_context<Char>::type> args) {\n  typedef back_insert_range<internal::basic_buffer<Char> > range;\n  return vformat_to<arg_formatter<range>>(\n    buf, to_string_view(format_str), args);\n}\n\ntemplate <typename S, typename Char = FMT_CHAR(S)>\ninline typename buffer_context<Char>::type::iterator vformat_to(\n    internal::basic_buffer<Char> &buf, const S &format_str,\n    basic_format_args<typename buffer_context<Char>::type> args) {\n  return internal::vformat_to(buf, to_string_view(format_str), args);\n}\n\ntemplate <\n    typename S, typename... Args,\n    std::size_t SIZE = inline_buffer_size,\n    typename Char = typename internal::char_t<S>::type>\ninline typename buffer_context<Char>::type::iterator format_to(\n    basic_memory_buffer<Char, SIZE> &buf, const S &format_str,\n    const Args &... args) {\n  internal::check_format_string<Args...>(format_str);\n  typedef typename buffer_context<Char>::type context;\n  format_arg_store<context, Args...> as{args...};\n  return internal::vformat_to(buf, to_string_view(format_str),\n                              basic_format_args<context>(as));\n}\n\nnamespace internal {\n\n// Detect the iterator category of *any* given type in a SFINAE-friendly way.\n// Unfortunately, older implementations of std::iterator_traits are not safe\n// for use in a SFINAE-context.\n\n// the gist of C++17's void_t magic\ntemplate<typename... Ts>\nstruct void_ { typedef void type; };\n\ntemplate <typename T, typename Enable = void>\nstruct it_category : std::false_type {};\n\ntemplate <typename T>\nstruct it_category<T*> { typedef std::random_access_iterator_tag type; };\n\ntemplate <typename T>\nstruct it_category<T, typename void_<typename T::iterator_category>::type> {\n  typedef typename T::iterator_category type;\n};\n\n// Detect if *any* given type models the OutputIterator concept.\ntemplate <typename It>\nclass is_output_iterator {\n  // Check for mutability because all iterator categories derived from\n  // std::input_iterator_tag *may* also meet the requirements of an\n  // OutputIterator, thereby falling into the category of 'mutable iterators'\n  // [iterator.requirements.general] clause 4.\n  // The compiler reveals this property only at the point of *actually\n  // dereferencing* the iterator!\n  template <typename U>\n  static decltype(*(internal::declval<U>())) test(std::input_iterator_tag);\n  template <typename U>\n  static char& test(std::output_iterator_tag);\n  template <typename U>\n  static const char& test(...);\n\n  typedef decltype(test<It>(typename it_category<It>::type{})) type;\n  typedef typename std::remove_reference<type>::type result;\n public:\n  static const bool value = !std::is_const<result>::value;\n};\n} // internal\n\ntemplate <typename OutputIt, typename Char = char>\n//using format_context_t = basic_format_context<OutputIt, Char>;\nstruct format_context_t { typedef basic_format_context<OutputIt, Char> type; };\n\ntemplate <typename OutputIt, typename Char = char>\n//using format_args_t = basic_format_args<format_context_t<OutputIt, Char>>;\nstruct format_args_t {\n  typedef basic_format_args<\n    typename format_context_t<OutputIt, Char>::type> type;\n};\n\ntemplate <typename String, typename OutputIt, typename... Args>\ninline typename std::enable_if<internal::is_output_iterator<OutputIt>::value,\n                               OutputIt>::type\n    vformat_to(OutputIt out, const String &format_str,\n               typename format_args_t<OutputIt, FMT_CHAR(String)>::type args) {\n  typedef output_range<OutputIt, FMT_CHAR(String)> range;\n  return vformat_to<arg_formatter<range>>(range(out),\n                                          to_string_view(format_str), args);\n}\n\n/**\n \\rst\n Formats arguments, writes the result to the output iterator ``out`` and returns\n the iterator past the end of the output range.\n\n **Example**::\n\n   std::vector<char> out;\n   fmt::format_to(std::back_inserter(out), \"{}\", 42);\n \\endrst\n */\ntemplate <typename OutputIt, typename S, typename... Args>\ninline FMT_ENABLE_IF_T(\n    internal::is_string<S>::value &&\n    internal::is_output_iterator<OutputIt>::value, OutputIt)\n    format_to(OutputIt out, const S &format_str, const Args &... args) {\n  internal::check_format_string<Args...>(format_str);\n  typedef typename format_context_t<OutputIt, FMT_CHAR(S)>::type context;\n  format_arg_store<context, Args...> as{args...};\n  return vformat_to(out, to_string_view(format_str),\n                    basic_format_args<context>(as));\n}\n\ntemplate <typename OutputIt>\nstruct format_to_n_result {\n  /** Iterator past the end of the output range. */\n  OutputIt out;\n  /** Total (not truncated) output size. */\n  std::size_t size;\n};\n\ntemplate <typename OutputIt, typename Char = typename OutputIt::value_type>\nstruct format_to_n_context :\n  format_context_t<fmt::internal::truncating_iterator<OutputIt>, Char> {};\n\ntemplate <typename OutputIt, typename Char = typename OutputIt::value_type>\nstruct format_to_n_args {\n  typedef basic_format_args<\n    typename format_to_n_context<OutputIt, Char>::type> type;\n};\n\ntemplate <typename OutputIt, typename Char, typename ...Args>\ninline format_arg_store<\n  typename format_to_n_context<OutputIt, Char>::type, Args...>\n    make_format_to_n_args(const Args &... args) {\n  return format_arg_store<\n    typename format_to_n_context<OutputIt, Char>::type, Args...>(args...);\n}\n\ntemplate <typename OutputIt, typename Char, typename... Args>\ninline typename std::enable_if<\n    internal::is_output_iterator<OutputIt>::value,\n    format_to_n_result<OutputIt>>::type vformat_to_n(\n    OutputIt out, std::size_t n, basic_string_view<Char> format_str,\n    typename format_to_n_args<OutputIt, Char>::type args) {\n  typedef internal::truncating_iterator<OutputIt> It;\n  auto it = vformat_to(It(out, n), format_str, args);\n  return {it.base(), it.count()};\n}\n\n/**\n \\rst\n Formats arguments, writes up to ``n`` characters of the result to the output\n iterator ``out`` and returns the total output size and the iterator past the\n end of the output range.\n \\endrst\n */\ntemplate <typename OutputIt, typename S, typename... Args>\ninline FMT_ENABLE_IF_T(\n    internal::is_string<S>::value &&\n    internal::is_output_iterator<OutputIt>::value,\n    format_to_n_result<OutputIt>)\n    format_to_n(OutputIt out, std::size_t n, const S &format_str,\n                const Args &... args) {\n  internal::check_format_string<Args...>(format_str);\n  typedef FMT_CHAR(S) Char;\n  format_arg_store<\n      typename format_to_n_context<OutputIt, Char>::type, Args...> as(args...);\n  return vformat_to_n(out, n, to_string_view(format_str),\n                      typename format_to_n_args<OutputIt, Char>::type(as));\n}\n\ntemplate <typename Char>\ninline std::basic_string<Char> internal::vformat(\n    basic_string_view<Char> format_str,\n    basic_format_args<typename buffer_context<Char>::type> args) {\n  basic_memory_buffer<Char> buffer;\n  internal::vformat_to(buffer, format_str, args);\n  return fmt::to_string(buffer);\n}\n\n/**\n  Returns the number of characters in the output of\n  ``format(format_str, args...)``.\n */\ntemplate <typename... Args>\ninline std::size_t formatted_size(string_view format_str,\n                                  const Args &... args) {\n  auto it = format_to(internal::counting_iterator<char>(), format_str, args...);\n  return it.count();\n}\n\n#if FMT_USE_USER_DEFINED_LITERALS\nnamespace internal {\n\n# if FMT_UDL_TEMPLATE\ntemplate <typename Char, Char... CHARS>\nclass udl_formatter {\n public:\n  template <typename... Args>\n  std::basic_string<Char> operator()(const Args &... args) const {\n    FMT_CONSTEXPR_DECL Char s[] = {CHARS..., '\\0'};\n    FMT_CONSTEXPR_DECL bool invalid_format =\n        do_check_format_string<Char, error_handler, Args...>(\n          basic_string_view<Char>(s, sizeof...(CHARS)));\n    (void)invalid_format;\n    return format(s, args...);\n  }\n};\n# else\ntemplate <typename Char>\nstruct udl_formatter {\n  const Char *str;\n\n  template <typename... Args>\n  auto operator()(Args &&... args) const\n                  -> decltype(format(str, std::forward<Args>(args)...)) {\n    return format(str, std::forward<Args>(args)...);\n  }\n};\n# endif // FMT_UDL_TEMPLATE\n\ntemplate <typename Char>\nstruct udl_arg {\n  const Char *str;\n\n  template <typename T>\n  named_arg<T, Char> operator=(T &&value) const {\n    return {str, std::forward<T>(value)};\n  }\n};\n\n} // namespace internal\n\ninline namespace literals {\n\n# if FMT_UDL_TEMPLATE\ntemplate <typename Char, Char... CHARS>\nFMT_CONSTEXPR internal::udl_formatter<Char, CHARS...> operator\"\"_format() {\n  return {};\n}\n# else\n/**\n  \\rst\n  User-defined literal equivalent of :func:`fmt::format`.\n\n  **Example**::\n\n    using namespace fmt::literals;\n    std::string message = \"The answer is {}\"_format(42);\n  \\endrst\n */\ninline internal::udl_formatter<char>\noperator\"\" _format(const char *s, std::size_t) { return {s}; }\ninline internal::udl_formatter<wchar_t>\noperator\"\" _format(const wchar_t *s, std::size_t) { return {s}; }\n# endif // FMT_UDL_TEMPLATE\n\n/**\n  \\rst\n  User-defined literal equivalent of :func:`fmt::arg`.\n\n  **Example**::\n\n    using namespace fmt::literals;\n    fmt::print(\"Elapsed time: {s:.2f} seconds\", \"s\"_a=1.23);\n  \\endrst\n */\ninline internal::udl_arg<char>\noperator\"\" _a(const char *s, std::size_t) { return {s}; }\ninline internal::udl_arg<wchar_t>\noperator\"\" _a(const wchar_t *s, std::size_t) { return {s}; }\n} // inline namespace literals\n#endif // FMT_USE_USER_DEFINED_LITERALS\nFMT_END_NAMESPACE\n\n#define FMT_STRING(s) [] { \\\n    typedef typename std::remove_cv<std::remove_pointer< \\\n      typename std::decay<decltype(s)>::type>::type>::type ct; \\\n    struct str : fmt::compile_string { \\\n      typedef ct char_type; \\\n      FMT_CONSTEXPR operator fmt::basic_string_view<ct>() const { \\\n        return {s, sizeof(s) / sizeof(ct) - 1}; \\\n      } \\\n    }; \\\n    return str{}; \\\n  }()\n\n#if defined(FMT_STRING_ALIAS) && FMT_STRING_ALIAS\n/**\n  \\rst\n  Constructs a compile-time format string. This macro is disabled by default to\n  prevent potential name collisions. To enable it define ``FMT_STRING_ALIAS`` to\n  1 before including ``fmt/format.h``.\n\n  **Example**::\n\n    #define FMT_STRING_ALIAS 1\n    #include <fmt/format.h>\n    // A compile-time error because 'd' is an invalid specifier for strings.\n    std::string s = format(fmt(\"{:d}\"), \"foo\");\n  \\endrst\n */\n# define fmt(s) FMT_STRING(s)\n#endif\n\n#ifdef FMT_HEADER_ONLY\n# define FMT_FUNC inline\n# include \"format-inl.h\"\n#else\n# define FMT_FUNC\n#endif\n\n// Restore warnings.\n#if FMT_GCC_VERSION >= 406 || FMT_CLANG_VERSION\n# pragma GCC diagnostic pop\n#endif\n\n#endif  // FMT_FORMAT_H_\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/fmt/bundled/locale.h",
    "content": "// Formatting library for C++ - std::locale support\n//\n// Copyright (c) 2012 - present, Victor Zverovich\n// All rights reserved.\n//\n// For the license information refer to format.h.\n\n#ifndef FMT_LOCALE_H_\n#define FMT_LOCALE_H_\n\n#include \"format.h\"\n#include <locale>\n\nFMT_BEGIN_NAMESPACE\n\nnamespace internal {\ntemplate <typename Char>\ntypename buffer_context<Char>::type::iterator vformat_to(\n    const std::locale &loc, basic_buffer<Char> &buf,\n    basic_string_view<Char> format_str,\n    basic_format_args<typename buffer_context<Char>::type> args) {\n  typedef back_insert_range<basic_buffer<Char> > range;\n  return vformat_to<arg_formatter<range>>(\n    buf, to_string_view(format_str), args, internal::locale_ref(loc));\n}\n\ntemplate <typename Char>\nstd::basic_string<Char> vformat(\n    const std::locale &loc, basic_string_view<Char> format_str,\n    basic_format_args<typename buffer_context<Char>::type> args) {\n  basic_memory_buffer<Char> buffer;\n  internal::vformat_to(loc, buffer, format_str, args);\n  return fmt::to_string(buffer);\n}\n}\n\ntemplate <typename S, typename Char = FMT_CHAR(S)>\ninline std::basic_string<Char> vformat(\n    const std::locale &loc, const S &format_str,\n    basic_format_args<typename buffer_context<Char>::type> args) {\n  return internal::vformat(loc, to_string_view(format_str), args);\n}\n\ntemplate <typename S, typename... Args>\ninline std::basic_string<FMT_CHAR(S)> format(\n    const std::locale &loc, const S &format_str, const Args &... args) {\n  return internal::vformat(\n    loc, to_string_view(format_str),\n    *internal::checked_args<S, Args...>(format_str, args...));\n}\n\ntemplate <typename String, typename OutputIt, typename... Args>\ninline typename std::enable_if<internal::is_output_iterator<OutputIt>::value,\n                               OutputIt>::type\n    vformat_to(OutputIt out, const std::locale &loc, const String &format_str,\n               typename format_args_t<OutputIt, FMT_CHAR(String)>::type args) {\n  typedef output_range<OutputIt, FMT_CHAR(String)> range;\n  return vformat_to<arg_formatter<range>>(\n    range(out), to_string_view(format_str), args, internal::locale_ref(loc));\n}\n\ntemplate <typename OutputIt, typename S, typename... Args>\ninline typename std::enable_if<\n    internal::is_string<S>::value &&\n    internal::is_output_iterator<OutputIt>::value, OutputIt>::type\n    format_to(OutputIt out, const std::locale &loc, const S &format_str,\n              const Args &... args) {\n  internal::check_format_string<Args...>(format_str);\n  typedef typename format_context_t<OutputIt, FMT_CHAR(S)>::type context;\n  format_arg_store<context, Args...> as{args...};\n  return vformat_to(out, loc, to_string_view(format_str),\n                    basic_format_args<context>(as));\n}\n\nFMT_END_NAMESPACE\n\n#endif  // FMT_LOCALE_H_\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/fmt/bundled/ostream.h",
    "content": "// Formatting library for C++ - std::ostream support\n//\n// Copyright (c) 2012 - present, Victor Zverovich\n// All rights reserved.\n//\n// For the license information refer to format.h.\n\n#ifndef FMT_OSTREAM_H_\n#define FMT_OSTREAM_H_\n\n#include \"format.h\"\n#include <ostream>\n\nFMT_BEGIN_NAMESPACE\nnamespace internal {\n\ntemplate <class Char>\nclass formatbuf : public std::basic_streambuf<Char> {\n private:\n  typedef typename std::basic_streambuf<Char>::int_type int_type;\n  typedef typename std::basic_streambuf<Char>::traits_type traits_type;\n\n  basic_buffer<Char> &buffer_;\n\n public:\n  formatbuf(basic_buffer<Char> &buffer) : buffer_(buffer) {}\n\n protected:\n  // The put-area is actually always empty. This makes the implementation\n  // simpler and has the advantage that the streambuf and the buffer are always\n  // in sync and sputc never writes into uninitialized memory. The obvious\n  // disadvantage is that each call to sputc always results in a (virtual) call\n  // to overflow. There is no disadvantage here for sputn since this always\n  // results in a call to xsputn.\n\n  int_type overflow(int_type ch = traits_type::eof()) FMT_OVERRIDE {\n    if (!traits_type::eq_int_type(ch, traits_type::eof()))\n      buffer_.push_back(static_cast<Char>(ch));\n    return ch;\n  }\n\n  std::streamsize xsputn(const Char *s, std::streamsize count) FMT_OVERRIDE {\n    buffer_.append(s, s + count);\n    return count;\n  }\n};\n\ntemplate <typename Char>\nstruct test_stream : std::basic_ostream<Char> {\n private:\n  struct null;\n  // Hide all operator<< from std::basic_ostream<Char>.\n  void operator<<(null);\n};\n\n// Checks if T has a user-defined operator<< (e.g. not a member of std::ostream).\ntemplate <typename T, typename Char>\nclass is_streamable {\n private:\n  template <typename U>\n  static decltype(\n    internal::declval<test_stream<Char>&>()\n      << internal::declval<U>(), std::true_type()) test(int);\n\n  template <typename>\n  static std::false_type test(...);\n\n  typedef decltype(test<T>(0)) result;\n\n public:\n  static const bool value = result::value;\n};\n\n// Write the content of buf to os.\ntemplate <typename Char>\nvoid write(std::basic_ostream<Char> &os, basic_buffer<Char> &buf) {\n  const Char *data = buf.data();\n  typedef std::make_unsigned<std::streamsize>::type UnsignedStreamSize;\n  UnsignedStreamSize size = buf.size();\n  UnsignedStreamSize max_size =\n      internal::to_unsigned((std::numeric_limits<std::streamsize>::max)());\n  do {\n    UnsignedStreamSize n = size <= max_size ? size : max_size;\n    os.write(data, static_cast<std::streamsize>(n));\n    data += n;\n    size -= n;\n  } while (size != 0);\n}\n\ntemplate <typename Char, typename T>\nvoid format_value(basic_buffer<Char> &buffer, const T &value) {\n  internal::formatbuf<Char> format_buf(buffer);\n  std::basic_ostream<Char> output(&format_buf);\n  output.exceptions(std::ios_base::failbit | std::ios_base::badbit);\n  output << value;\n  buffer.resize(buffer.size());\n}\n}  // namespace internal\n\n// Disable conversion to int if T has an overloaded operator<< which is a free\n// function (not a member of std::ostream).\ntemplate <typename T, typename Char>\nstruct convert_to_int<T, Char, void> {\n  static const bool value =\n    convert_to_int<T, Char, int>::value &&\n    !internal::is_streamable<T, Char>::value;\n};\n\n// Formats an object of type T that has an overloaded ostream operator<<.\ntemplate <typename T, typename Char>\nstruct formatter<T, Char,\n    typename std::enable_if<\n      internal::is_streamable<T, Char>::value &&\n      !internal::format_type<\n        typename buffer_context<Char>::type, T>::value>::type>\n    : formatter<basic_string_view<Char>, Char> {\n\n  template <typename Context>\n  auto format(const T &value, Context &ctx) -> decltype(ctx.out()) {\n    basic_memory_buffer<Char> buffer;\n    internal::format_value(buffer, value);\n    basic_string_view<Char> str(buffer.data(), buffer.size());\n    return formatter<basic_string_view<Char>, Char>::format(str, ctx);\n  }\n};\n\ntemplate <typename Char>\ninline void vprint(std::basic_ostream<Char> &os,\n                   basic_string_view<Char> format_str,\n                   basic_format_args<typename buffer_context<Char>::type> args) {\n  basic_memory_buffer<Char> buffer;\n  internal::vformat_to(buffer, format_str, args);\n  internal::write(os, buffer);\n}\n/**\n  \\rst\n  Prints formatted data to the stream *os*.\n\n  **Example**::\n\n    fmt::print(cerr, \"Don't {}!\", \"panic\");\n  \\endrst\n */\ntemplate <typename S, typename... Args>\ninline typename std::enable_if<internal::is_string<S>::value>::type\nprint(std::basic_ostream<FMT_CHAR(S)> &os, const S &format_str,\n      const Args & ... args) {\n  internal::checked_args<S, Args...> ca(format_str, args...);\n  vprint(os, to_string_view(format_str), *ca);\n}\nFMT_END_NAMESPACE\n\n#endif  // FMT_OSTREAM_H_\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/fmt/bundled/posix.h",
    "content": "// A C++ interface to POSIX functions.\n//\n// Copyright (c) 2012 - 2016, Victor Zverovich\n// All rights reserved.\n//\n// For the license information refer to format.h.\n\n#ifndef FMT_POSIX_H_\n#define FMT_POSIX_H_\n\n#if defined(__MINGW32__) || defined(__CYGWIN__)\n// Workaround MinGW bug https://sourceforge.net/p/mingw/bugs/2024/.\n# undef __STRICT_ANSI__\n#endif\n\n#include <errno.h>\n#include <fcntl.h>   // for O_RDONLY\n#include <locale.h>  // for locale_t\n#include <stdio.h>\n#include <stdlib.h>  // for strtod_l\n\n#include <cstddef>\n\n#if defined __APPLE__ || defined(__FreeBSD__)\n# include <xlocale.h>  // for LC_NUMERIC_MASK on OS X\n#endif\n\n#include \"format.h\"\n\n#ifndef FMT_POSIX\n# if defined(_WIN32) && !defined(__MINGW32__)\n// Fix warnings about deprecated symbols.\n#  define FMT_POSIX(call) _##call\n# else\n#  define FMT_POSIX(call) call\n# endif\n#endif\n\n// Calls to system functions are wrapped in FMT_SYSTEM for testability.\n#ifdef FMT_SYSTEM\n# define FMT_POSIX_CALL(call) FMT_SYSTEM(call)\n#else\n# define FMT_SYSTEM(call) call\n# ifdef _WIN32\n// Fix warnings about deprecated symbols.\n#  define FMT_POSIX_CALL(call) ::_##call\n# else\n#  define FMT_POSIX_CALL(call) ::call\n# endif\n#endif\n\n// Retries the expression while it evaluates to error_result and errno\n// equals to EINTR.\n#ifndef _WIN32\n# define FMT_RETRY_VAL(result, expression, error_result) \\\n  do { \\\n    result = (expression); \\\n  } while (result == error_result && errno == EINTR)\n#else\n# define FMT_RETRY_VAL(result, expression, error_result) result = (expression)\n#endif\n\n#define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1)\n\nFMT_BEGIN_NAMESPACE\n\n/**\n  \\rst\n  A reference to a null-terminated string. It can be constructed from a C\n  string or ``std::string``.\n\n  You can use one of the following typedefs for common character types:\n\n  +---------------+-----------------------------+\n  | Type          | Definition                  |\n  +===============+=============================+\n  | cstring_view  | basic_cstring_view<char>    |\n  +---------------+-----------------------------+\n  | wcstring_view | basic_cstring_view<wchar_t> |\n  +---------------+-----------------------------+\n\n  This class is most useful as a parameter type to allow passing\n  different types of strings to a function, for example::\n\n    template <typename... Args>\n    std::string format(cstring_view format_str, const Args & ... args);\n\n    format(\"{}\", 42);\n    format(std::string(\"{}\"), 42);\n  \\endrst\n */\ntemplate <typename Char>\nclass basic_cstring_view {\n private:\n  const Char *data_;\n\n public:\n  /** Constructs a string reference object from a C string. */\n  basic_cstring_view(const Char *s) : data_(s) {}\n\n  /**\n    \\rst\n    Constructs a string reference from an ``std::string`` object.\n    \\endrst\n   */\n  basic_cstring_view(const std::basic_string<Char> &s) : data_(s.c_str()) {}\n\n  /** Returns the pointer to a C string. */\n  const Char *c_str() const { return data_; }\n};\n\ntypedef basic_cstring_view<char> cstring_view;\ntypedef basic_cstring_view<wchar_t> wcstring_view;\n\n// An error code.\nclass error_code {\n private:\n  int value_;\n\n public:\n  explicit error_code(int value = 0) FMT_NOEXCEPT : value_(value) {}\n\n  int get() const FMT_NOEXCEPT { return value_; }\n};\n\n// A buffered file.\nclass buffered_file {\n private:\n  FILE *file_;\n\n  friend class file;\n\n  explicit buffered_file(FILE *f) : file_(f) {}\n\n public:\n  // Constructs a buffered_file object which doesn't represent any file.\n  buffered_file() FMT_NOEXCEPT : file_(FMT_NULL) {}\n\n  // Destroys the object closing the file it represents if any.\n  FMT_API ~buffered_file() FMT_NOEXCEPT;\n\n private:\n  buffered_file(const buffered_file &) = delete;\n  void operator=(const buffered_file &) = delete;\n\n\n public:\n  buffered_file(buffered_file &&other) FMT_NOEXCEPT : file_(other.file_) {\n    other.file_ = FMT_NULL;\n  }\n\n  buffered_file& operator=(buffered_file &&other) {\n    close();\n    file_ = other.file_;\n    other.file_ = FMT_NULL;\n    return *this;\n  }\n\n  // Opens a file.\n  FMT_API buffered_file(cstring_view filename, cstring_view mode);\n\n  // Closes the file.\n  FMT_API void close();\n\n  // Returns the pointer to a FILE object representing this file.\n  FILE *get() const FMT_NOEXCEPT { return file_; }\n\n  // We place parentheses around fileno to workaround a bug in some versions\n  // of MinGW that define fileno as a macro.\n  FMT_API int (fileno)() const;\n\n  void vprint(string_view format_str, format_args args) {\n    fmt::vprint(file_, format_str, args);\n  }\n\n  template <typename... Args>\n  inline void print(string_view format_str, const Args & ... args) {\n    vprint(format_str, make_format_args(args...));\n  }\n};\n\n// A file. Closed file is represented by a file object with descriptor -1.\n// Methods that are not declared with FMT_NOEXCEPT may throw\n// fmt::system_error in case of failure. Note that some errors such as\n// closing the file multiple times will cause a crash on Windows rather\n// than an exception. You can get standard behavior by overriding the\n// invalid parameter handler with _set_invalid_parameter_handler.\nclass file {\n private:\n  int fd_;  // File descriptor.\n\n  // Constructs a file object with a given descriptor.\n  explicit file(int fd) : fd_(fd) {}\n\n public:\n  // Possible values for the oflag argument to the constructor.\n  enum {\n    RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only.\n    WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only.\n    RDWR   = FMT_POSIX(O_RDWR)    // Open for reading and writing.\n  };\n\n  // Constructs a file object which doesn't represent any file.\n  file() FMT_NOEXCEPT : fd_(-1) {}\n\n  // Opens a file and constructs a file object representing this file.\n  FMT_API file(cstring_view path, int oflag);\n\n private:\n  file(const file &) = delete;\n  void operator=(const file &) = delete;\n\n public:\n  file(file &&other) FMT_NOEXCEPT : fd_(other.fd_) {\n    other.fd_ = -1;\n  }\n\n  file& operator=(file &&other) {\n    close();\n    fd_ = other.fd_;\n    other.fd_ = -1;\n    return *this;\n  }\n\n  // Destroys the object closing the file it represents if any.\n  FMT_API ~file() FMT_NOEXCEPT;\n\n  // Returns the file descriptor.\n  int descriptor() const FMT_NOEXCEPT { return fd_; }\n\n  // Closes the file.\n  FMT_API void close();\n\n  // Returns the file size. The size has signed type for consistency with\n  // stat::st_size.\n  FMT_API long long size() const;\n\n  // Attempts to read count bytes from the file into the specified buffer.\n  FMT_API std::size_t read(void *buffer, std::size_t count);\n\n  // Attempts to write count bytes from the specified buffer to the file.\n  FMT_API std::size_t write(const void *buffer, std::size_t count);\n\n  // Duplicates a file descriptor with the dup function and returns\n  // the duplicate as a file object.\n  FMT_API static file dup(int fd);\n\n  // Makes fd be the copy of this file descriptor, closing fd first if\n  // necessary.\n  FMT_API void dup2(int fd);\n\n  // Makes fd be the copy of this file descriptor, closing fd first if\n  // necessary.\n  FMT_API void dup2(int fd, error_code &ec) FMT_NOEXCEPT;\n\n  // Creates a pipe setting up read_end and write_end file objects for reading\n  // and writing respectively.\n  FMT_API static void pipe(file &read_end, file &write_end);\n\n  // Creates a buffered_file object associated with this file and detaches\n  // this file object from the file.\n  FMT_API buffered_file fdopen(const char *mode);\n};\n\n// Returns the memory page size.\nlong getpagesize();\n\n#if (defined(LC_NUMERIC_MASK) || defined(_MSC_VER)) && \\\n    !defined(__ANDROID__) && !defined(__CYGWIN__) && !defined(__OpenBSD__) && \\\n    !defined(__NEWLIB_H__)\n# define FMT_LOCALE\n#endif\n\n#ifdef FMT_LOCALE\n// A \"C\" numeric locale.\nclass Locale {\n private:\n# ifdef _MSC_VER\n  typedef _locale_t locale_t;\n\n  enum { LC_NUMERIC_MASK = LC_NUMERIC };\n\n  static locale_t newlocale(int category_mask, const char *locale, locale_t) {\n    return _create_locale(category_mask, locale);\n  }\n\n  static void freelocale(locale_t locale) {\n    _free_locale(locale);\n  }\n\n  static double strtod_l(const char *nptr, char **endptr, _locale_t locale) {\n    return _strtod_l(nptr, endptr, locale);\n  }\n# endif\n\n  locale_t locale_;\n\n  Locale(const Locale &) = delete;\n  void operator=(const Locale &) = delete;\n\n public:\n  typedef locale_t Type;\n\n  Locale() : locale_(newlocale(LC_NUMERIC_MASK, \"C\", FMT_NULL)) {\n    if (!locale_)\n      FMT_THROW(system_error(errno, \"cannot create locale\"));\n  }\n  ~Locale() { freelocale(locale_); }\n\n  Type get() const { return locale_; }\n\n  // Converts string to floating-point number and advances str past the end\n  // of the parsed input.\n  double strtod(const char *&str) const {\n    char *end = FMT_NULL;\n    double result = strtod_l(str, &end, locale_);\n    str = end;\n    return result;\n  }\n};\n#endif  // FMT_LOCALE\nFMT_END_NAMESPACE\n\n#endif  // FMT_POSIX_H_\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/fmt/bundled/printf.h",
    "content": "// Formatting library for C++\n//\n// Copyright (c) 2012 - 2016, Victor Zverovich\n// All rights reserved.\n//\n// For the license information refer to format.h.\n\n#ifndef FMT_PRINTF_H_\n#define FMT_PRINTF_H_\n\n#include <algorithm>  // std::fill_n\n#include <limits>     // std::numeric_limits\n\n#include \"ostream.h\"\n\nFMT_BEGIN_NAMESPACE\nnamespace internal {\n\n// An iterator that produces a null terminator on *end. This simplifies parsing\n// and allows comparing the performance of processing a null-terminated string\n// vs string_view.\ntemplate <typename Char>\nclass null_terminating_iterator {\n public:\n  typedef std::ptrdiff_t difference_type;\n  typedef Char value_type;\n  typedef const Char* pointer;\n  typedef const Char& reference;\n  typedef std::random_access_iterator_tag iterator_category;\n\n  null_terminating_iterator() : ptr_(0), end_(0) {}\n\n  FMT_CONSTEXPR null_terminating_iterator(const Char *ptr, const Char *end)\n    : ptr_(ptr), end_(end) {}\n\n  template <typename Range>\n  FMT_CONSTEXPR explicit null_terminating_iterator(const Range &r)\n    : ptr_(r.begin()), end_(r.end()) {}\n\n  FMT_CONSTEXPR null_terminating_iterator &operator=(const Char *ptr) {\n    assert(ptr <= end_);\n    ptr_ = ptr;\n    return *this;\n  }\n\n  FMT_CONSTEXPR Char operator*() const {\n    return ptr_ != end_ ? *ptr_ : Char();\n  }\n\n  FMT_CONSTEXPR null_terminating_iterator operator++() {\n    ++ptr_;\n    return *this;\n  }\n\n  FMT_CONSTEXPR null_terminating_iterator operator++(int) {\n    null_terminating_iterator result(*this);\n    ++ptr_;\n    return result;\n  }\n\n  FMT_CONSTEXPR null_terminating_iterator operator--() {\n    --ptr_;\n    return *this;\n  }\n\n  FMT_CONSTEXPR null_terminating_iterator operator+(difference_type n) {\n    return null_terminating_iterator(ptr_ + n, end_);\n  }\n\n  FMT_CONSTEXPR null_terminating_iterator operator-(difference_type n) {\n    return null_terminating_iterator(ptr_ - n, end_);\n  }\n\n  FMT_CONSTEXPR null_terminating_iterator operator+=(difference_type n) {\n    ptr_ += n;\n    return *this;\n  }\n\n  FMT_CONSTEXPR difference_type operator-(\n      null_terminating_iterator other) const {\n    return ptr_ - other.ptr_;\n  }\n\n  FMT_CONSTEXPR bool operator!=(null_terminating_iterator other) const {\n    return ptr_ != other.ptr_;\n  }\n\n  bool operator>=(null_terminating_iterator other) const {\n    return ptr_ >= other.ptr_;\n  }\n\n  // This should be a friend specialization pointer_from<Char> but the latter\n  // doesn't compile by gcc 5.1 due to a compiler bug.\n  template <typename CharT>\n  friend FMT_CONSTEXPR_DECL const CharT *pointer_from(\n      null_terminating_iterator<CharT> it);\n\n private:\n  const Char *ptr_;\n  const Char *end_;\n};\n\ntemplate <typename T>\nFMT_CONSTEXPR const T *pointer_from(const T *p) { return p; }\n\ntemplate <typename Char>\nFMT_CONSTEXPR const Char *pointer_from(null_terminating_iterator<Char> it) {\n  return it.ptr_;\n}\n\n// DEPRECATED: Parses the input as an unsigned integer. This function assumes\n// that the first character is a digit and presence of a non-digit character at\n// the end.\n// it: an iterator pointing to the beginning of the input range.\ntemplate <typename Iterator, typename ErrorHandler>\nFMT_CONSTEXPR unsigned parse_nonnegative_int(Iterator &it, ErrorHandler &&eh) {\n  assert('0' <= *it && *it <= '9');\n  if (*it == '0') {\n    ++it;\n    return 0;\n  }\n  unsigned value = 0;\n  // Convert to unsigned to prevent a warning.\n  unsigned max_int = (std::numeric_limits<int>::max)();\n  unsigned big = max_int / 10;\n  do {\n    // Check for overflow.\n    if (value > big) {\n      value = max_int + 1;\n      break;\n    }\n    value = value * 10 + unsigned(*it - '0');\n    // Workaround for MSVC \"setup_exception stack overflow\" error:\n    auto next = it;\n    ++next;\n    it = next;\n  } while ('0' <= *it && *it <= '9');\n  if (value > max_int)\n    eh.on_error(\"number is too big\");\n  return value;\n}\n\n// Checks if a value fits in int - used to avoid warnings about comparing\n// signed and unsigned integers.\ntemplate <bool IsSigned>\nstruct int_checker {\n  template <typename T>\n  static bool fits_in_int(T value) {\n    unsigned max = std::numeric_limits<int>::max();\n    return value <= max;\n  }\n  static bool fits_in_int(bool) { return true; }\n};\n\ntemplate <>\nstruct int_checker<true> {\n  template <typename T>\n  static bool fits_in_int(T value) {\n    return value >= std::numeric_limits<int>::min() &&\n           value <= std::numeric_limits<int>::max();\n  }\n  static bool fits_in_int(int) { return true; }\n};\n\nclass printf_precision_handler: public function<int> {\n public:\n  template <typename T>\n  typename std::enable_if<std::is_integral<T>::value, int>::type\n      operator()(T value) {\n    if (!int_checker<std::numeric_limits<T>::is_signed>::fits_in_int(value))\n      FMT_THROW(format_error(\"number is too big\"));\n    return static_cast<int>(value);\n  }\n\n  template <typename T>\n  typename std::enable_if<!std::is_integral<T>::value, int>::type operator()(T) {\n    FMT_THROW(format_error(\"precision is not integer\"));\n    return 0;\n  }\n};\n\n// An argument visitor that returns true iff arg is a zero integer.\nclass is_zero_int: public function<bool> {\n public:\n  template <typename T>\n  typename std::enable_if<std::is_integral<T>::value, bool>::type\n      operator()(T value) { return value == 0; }\n\n  template <typename T>\n  typename std::enable_if<!std::is_integral<T>::value, bool>::type\n      operator()(T) { return false; }\n};\n\ntemplate <typename T>\nstruct make_unsigned_or_bool : std::make_unsigned<T> {};\n\ntemplate <>\nstruct make_unsigned_or_bool<bool> {\n  typedef bool type;\n};\n\ntemplate <typename T, typename Context>\nclass arg_converter: public function<void> {\n private:\n  typedef typename Context::char_type Char;\n\n  basic_format_arg<Context> &arg_;\n  typename Context::char_type type_;\n\n public:\n  arg_converter(basic_format_arg<Context> &arg, Char type)\n    : arg_(arg), type_(type) {}\n\n  void operator()(bool value) {\n    if (type_ != 's')\n      operator()<bool>(value);\n  }\n\n  template <typename U>\n  typename std::enable_if<std::is_integral<U>::value>::type\n      operator()(U value) {\n    bool is_signed = type_ == 'd' || type_ == 'i';\n    typedef typename std::conditional<\n        std::is_same<T, void>::value, U, T>::type TargetType;\n    if (const_check(sizeof(TargetType) <= sizeof(int))) {\n      // Extra casts are used to silence warnings.\n      if (is_signed) {\n        arg_ = internal::make_arg<Context>(\n          static_cast<int>(static_cast<TargetType>(value)));\n      } else {\n        typedef typename make_unsigned_or_bool<TargetType>::type Unsigned;\n        arg_ = internal::make_arg<Context>(\n          static_cast<unsigned>(static_cast<Unsigned>(value)));\n      }\n    } else {\n      if (is_signed) {\n        // glibc's printf doesn't sign extend arguments of smaller types:\n        //   std::printf(\"%lld\", -42);  // prints \"4294967254\"\n        // but we don't have to do the same because it's a UB.\n        arg_ = internal::make_arg<Context>(static_cast<long long>(value));\n      } else {\n        arg_ = internal::make_arg<Context>(\n          static_cast<typename make_unsigned_or_bool<U>::type>(value));\n      }\n    }\n  }\n\n  template <typename U>\n  typename std::enable_if<!std::is_integral<U>::value>::type operator()(U) {\n    // No coversion needed for non-integral types.\n  }\n};\n\n// Converts an integer argument to T for printf, if T is an integral type.\n// If T is void, the argument is converted to corresponding signed or unsigned\n// type depending on the type specifier: 'd' and 'i' - signed, other -\n// unsigned).\ntemplate <typename T, typename Context, typename Char>\nvoid convert_arg(basic_format_arg<Context> &arg, Char type) {\n  visit_format_arg(arg_converter<T, Context>(arg, type), arg);\n}\n\n// Converts an integer argument to char for printf.\ntemplate <typename Context>\nclass char_converter: public function<void> {\n private:\n  basic_format_arg<Context> &arg_;\n\n public:\n  explicit char_converter(basic_format_arg<Context> &arg) : arg_(arg) {}\n\n  template <typename T>\n  typename std::enable_if<std::is_integral<T>::value>::type\n      operator()(T value) {\n    typedef typename Context::char_type Char;\n    arg_ = internal::make_arg<Context>(static_cast<Char>(value));\n  }\n\n  template <typename T>\n  typename std::enable_if<!std::is_integral<T>::value>::type operator()(T) {\n    // No coversion needed for non-integral types.\n  }\n};\n\n// Checks if an argument is a valid printf width specifier and sets\n// left alignment if it is negative.\ntemplate <typename Char>\nclass printf_width_handler: public function<unsigned> {\n private:\n  typedef basic_format_specs<Char> format_specs;\n\n  format_specs &spec_;\n\n public:\n  explicit printf_width_handler(format_specs &spec) : spec_(spec) {}\n\n  template <typename T>\n  typename std::enable_if<std::is_integral<T>::value, unsigned>::type\n      operator()(T value) {\n    typedef typename internal::int_traits<T>::main_type UnsignedType;\n    UnsignedType width = static_cast<UnsignedType>(value);\n    if (internal::is_negative(value)) {\n      spec_.align_ = ALIGN_LEFT;\n      width = 0 - width;\n    }\n    unsigned int_max = std::numeric_limits<int>::max();\n    if (width > int_max)\n      FMT_THROW(format_error(\"number is too big\"));\n    return static_cast<unsigned>(width);\n  }\n\n  template <typename T>\n  typename std::enable_if<!std::is_integral<T>::value, unsigned>::type\n      operator()(T) {\n    FMT_THROW(format_error(\"width is not integer\"));\n    return 0;\n  }\n};\n\ntemplate <typename Char, typename Context>\nvoid printf(basic_buffer<Char> &buf, basic_string_view<Char> format,\n            basic_format_args<Context> args) {\n  Context(std::back_inserter(buf), format, args).format();\n}\n}  // namespace internal\n\nusing internal::printf;  // For printing into memory_buffer.\n\ntemplate <typename Range>\nclass printf_arg_formatter;\n\ntemplate <\n    typename OutputIt, typename Char,\n    typename ArgFormatter =\n      printf_arg_formatter<back_insert_range<internal::basic_buffer<Char>>>>\nclass basic_printf_context;\n\n/**\n  \\rst\n  The ``printf`` argument formatter.\n  \\endrst\n */\ntemplate <typename Range>\nclass printf_arg_formatter:\n  public internal::function<\n    typename internal::arg_formatter_base<Range>::iterator>,\n  public internal::arg_formatter_base<Range> {\n private:\n  typedef typename Range::value_type char_type;\n  typedef decltype(internal::declval<Range>().begin()) iterator;\n  typedef internal::arg_formatter_base<Range> base;\n  typedef basic_printf_context<iterator, char_type> context_type;\n\n  context_type &context_;\n\n  void write_null_pointer(char) {\n    this->spec()->type = 0;\n    this->write(\"(nil)\");\n  }\n\n  void write_null_pointer(wchar_t) {\n    this->spec()->type = 0;\n    this->write(L\"(nil)\");\n  }\n\n public:\n  typedef typename base::format_specs format_specs;\n\n  /**\n    \\rst\n    Constructs an argument formatter object.\n    *buffer* is a reference to the output buffer and *spec* contains format\n    specifier information for standard argument types.\n    \\endrst\n   */\n  printf_arg_formatter(internal::basic_buffer<char_type> &buffer,\n                       format_specs &spec, context_type &ctx)\n    : base(back_insert_range<internal::basic_buffer<char_type>>(buffer), &spec,\n           ctx.locale()),\n      context_(ctx) {}\n\n  template <typename T>\n  typename std::enable_if<std::is_integral<T>::value, iterator>::type\n      operator()(T value) {\n    // MSVC2013 fails to compile separate overloads for bool and char_type so\n    // use std::is_same instead.\n    if (std::is_same<T, bool>::value) {\n      format_specs &fmt_spec = *this->spec();\n      if (fmt_spec.type != 's')\n        return base::operator()(value ? 1 : 0);\n      fmt_spec.type = 0;\n      this->write(value != 0);\n    } else if (std::is_same<T, char_type>::value) {\n      format_specs &fmt_spec = *this->spec();\n      if (fmt_spec.type && fmt_spec.type != 'c')\n        return (*this)(static_cast<int>(value));\n      fmt_spec.flags = 0;\n      fmt_spec.align_ = ALIGN_RIGHT;\n      return base::operator()(value);\n    } else {\n      return base::operator()(value);\n    }\n    return this->out();\n  }\n\n  template <typename T>\n  typename std::enable_if<std::is_floating_point<T>::value, iterator>::type\n      operator()(T value) {\n    return base::operator()(value);\n  }\n\n  /** Formats a null-terminated C string. */\n  iterator operator()(const char *value) {\n    if (value)\n      base::operator()(value);\n    else if (this->spec()->type == 'p')\n      write_null_pointer(char_type());\n    else\n      this->write(\"(null)\");\n    return this->out();\n  }\n\n  /** Formats a null-terminated wide C string. */\n  iterator operator()(const wchar_t *value) {\n    if (value)\n      base::operator()(value);\n    else if (this->spec()->type == 'p')\n      write_null_pointer(char_type());\n    else\n      this->write(L\"(null)\");\n    return this->out();\n  }\n\n  iterator operator()(basic_string_view<char_type> value) {\n    return base::operator()(value);\n  }\n\n  iterator operator()(monostate value) {\n    return base::operator()(value);\n  }\n\n  /** Formats a pointer. */\n  iterator operator()(const void *value) {\n    if (value)\n      return base::operator()(value);\n    this->spec()->type = 0;\n    write_null_pointer(char_type());\n    return this->out();\n  }\n\n  /** Formats an argument of a custom (user-defined) type. */\n  iterator operator()(typename basic_format_arg<context_type>::handle handle) {\n    handle.format(context_);\n    return this->out();\n  }\n};\n\ntemplate <typename T>\nstruct printf_formatter {\n  template <typename ParseContext>\n  auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { return ctx.begin(); }\n\n  template <typename FormatContext>\n  auto format(const T &value, FormatContext &ctx) -> decltype(ctx.out()) {\n    internal::format_value(internal::get_container(ctx.out()), value);\n    return ctx.out();\n  }\n};\n\n/** This template formats data and writes the output to a writer. */\ntemplate <typename OutputIt, typename Char, typename ArgFormatter>\nclass basic_printf_context :\n  // Inherit publicly as a workaround for the icc bug\n  // https://software.intel.com/en-us/forums/intel-c-compiler/topic/783476.\n  public internal::context_base<\n    OutputIt, basic_printf_context<OutputIt, Char, ArgFormatter>, Char> {\n public:\n  /** The character type for the output. */\n  typedef Char char_type;\n\n  template <typename T>\n  struct formatter_type { typedef printf_formatter<T> type; };\n\n private:\n  typedef internal::context_base<OutputIt, basic_printf_context, Char> base;\n  typedef typename base::format_arg format_arg;\n  typedef basic_format_specs<char_type> format_specs;\n  typedef internal::null_terminating_iterator<char_type> iterator;\n\n  void parse_flags(format_specs &spec, iterator &it);\n\n  // Returns the argument with specified index or, if arg_index is equal\n  // to the maximum unsigned value, the next argument.\n  format_arg get_arg(\n      iterator it,\n      unsigned arg_index = (std::numeric_limits<unsigned>::max)());\n\n  // Parses argument index, flags and width and returns the argument index.\n  unsigned parse_header(iterator &it, format_specs &spec);\n\n public:\n  /**\n   \\rst\n   Constructs a ``printf_context`` object. References to the arguments and\n   the writer are stored in the context object so make sure they have\n   appropriate lifetimes.\n   \\endrst\n   */\n  basic_printf_context(OutputIt out, basic_string_view<char_type> format_str,\n                       basic_format_args<basic_printf_context> args)\n    : base(out, format_str, args) {}\n\n  using base::parse_context;\n  using base::out;\n  using base::advance_to;\n\n  /** Formats stored arguments and writes the output to the range. */\n  void format();\n};\n\ntemplate <typename OutputIt, typename Char, typename AF>\nvoid basic_printf_context<OutputIt, Char, AF>::parse_flags(\n    format_specs &spec, iterator &it) {\n  for (;;) {\n    switch (*it++) {\n      case '-':\n        spec.align_ = ALIGN_LEFT;\n        break;\n      case '+':\n        spec.flags |= SIGN_FLAG | PLUS_FLAG;\n        break;\n      case '0':\n        spec.fill_ = '0';\n        break;\n      case ' ':\n        spec.flags |= SIGN_FLAG;\n        break;\n      case '#':\n        spec.flags |= HASH_FLAG;\n        break;\n      default:\n        --it;\n        return;\n    }\n  }\n}\n\ntemplate <typename OutputIt, typename Char, typename AF>\ntypename basic_printf_context<OutputIt, Char, AF>::format_arg\n  basic_printf_context<OutputIt, Char, AF>::get_arg(\n    iterator it, unsigned arg_index) {\n  (void)it;\n  if (arg_index == std::numeric_limits<unsigned>::max())\n    return this->do_get_arg(this->parse_context().next_arg_id());\n  return base::get_arg(arg_index - 1);\n}\n\ntemplate <typename OutputIt, typename Char, typename AF>\nunsigned basic_printf_context<OutputIt, Char, AF>::parse_header(\n  iterator &it, format_specs &spec) {\n  unsigned arg_index = std::numeric_limits<unsigned>::max();\n  char_type c = *it;\n  if (c >= '0' && c <= '9') {\n    // Parse an argument index (if followed by '$') or a width possibly\n    // preceded with '0' flag(s).\n    internal::error_handler eh;\n    unsigned value = parse_nonnegative_int(it, eh);\n    if (*it == '$') {  // value is an argument index\n      ++it;\n      arg_index = value;\n    } else {\n      if (c == '0')\n        spec.fill_ = '0';\n      if (value != 0) {\n        // Nonzero value means that we parsed width and don't need to\n        // parse it or flags again, so return now.\n        spec.width_ = value;\n        return arg_index;\n      }\n    }\n  }\n  parse_flags(spec, it);\n  // Parse width.\n  if (*it >= '0' && *it <= '9') {\n    internal::error_handler eh;\n    spec.width_ = parse_nonnegative_int(it, eh);\n  } else if (*it == '*') {\n    ++it;\n    spec.width_ = visit_format_arg(\n          internal::printf_width_handler<char_type>(spec), get_arg(it));\n  }\n  return arg_index;\n}\n\ntemplate <typename OutputIt, typename Char, typename AF>\nvoid basic_printf_context<OutputIt, Char, AF>::format() {\n  auto &buffer = internal::get_container(this->out());\n  auto start = iterator(this->parse_context());\n  auto it = start;\n  using internal::pointer_from;\n  while (*it) {\n    char_type c = *it++;\n    if (c != '%') continue;\n    if (*it == c) {\n      buffer.append(pointer_from(start), pointer_from(it));\n      start = ++it;\n      continue;\n    }\n    buffer.append(pointer_from(start), pointer_from(it) - 1);\n\n    format_specs spec;\n    spec.align_ = ALIGN_RIGHT;\n\n    // Parse argument index, flags and width.\n    unsigned arg_index = parse_header(it, spec);\n\n    // Parse precision.\n    if (*it == '.') {\n      ++it;\n      if ('0' <= *it && *it <= '9') {\n        internal::error_handler eh;\n        spec.precision = static_cast<int>(parse_nonnegative_int(it, eh));\n      } else if (*it == '*') {\n        ++it;\n        spec.precision =\n            visit_format_arg(internal::printf_precision_handler(), get_arg(it));\n      } else {\n        spec.precision = 0;\n      }\n    }\n\n    format_arg arg = get_arg(it, arg_index);\n    if (spec.has(HASH_FLAG) && visit_format_arg(internal::is_zero_int(), arg))\n      spec.flags = static_cast<uint_least8_t>(spec.flags & (~internal::to_unsigned<int>(HASH_FLAG)));\n    if (spec.fill_ == '0') {\n      if (arg.is_arithmetic())\n        spec.align_ = ALIGN_NUMERIC;\n      else\n        spec.fill_ = ' ';  // Ignore '0' flag for non-numeric types.\n    }\n\n    // Parse length and convert the argument to the required type.\n    using internal::convert_arg;\n    switch (*it++) {\n    case 'h':\n      if (*it == 'h')\n        convert_arg<signed char>(arg, *++it);\n      else\n        convert_arg<short>(arg, *it);\n      break;\n    case 'l':\n      if (*it == 'l')\n        convert_arg<long long>(arg, *++it);\n      else\n        convert_arg<long>(arg, *it);\n      break;\n    case 'j':\n      convert_arg<intmax_t>(arg, *it);\n      break;\n    case 'z':\n      convert_arg<std::size_t>(arg, *it);\n      break;\n    case 't':\n      convert_arg<std::ptrdiff_t>(arg, *it);\n      break;\n    case 'L':\n      // printf produces garbage when 'L' is omitted for long double, no\n      // need to do the same.\n      break;\n    default:\n      --it;\n      convert_arg<void>(arg, *it);\n    }\n\n    // Parse type.\n    if (!*it)\n      FMT_THROW(format_error(\"invalid format string\"));\n    spec.type = static_cast<char>(*it++);\n    if (arg.is_integral()) {\n      // Normalize type.\n      switch (spec.type) {\n      case 'i': case 'u':\n        spec.type = 'd';\n        break;\n      case 'c':\n        // TODO: handle wchar_t better?\n        visit_format_arg(\n              internal::char_converter<basic_printf_context>(arg), arg);\n        break;\n      }\n    }\n\n    start = it;\n\n    // Format argument.\n    visit_format_arg(AF(buffer, spec, *this), arg);\n  }\n  buffer.append(pointer_from(start), pointer_from(it));\n}\n\ntemplate <typename Buffer>\nstruct basic_printf_context_t {\n  typedef basic_printf_context<\n    std::back_insert_iterator<Buffer>, typename Buffer::value_type> type;\n};\n\ntypedef basic_printf_context_t<internal::buffer>::type printf_context;\ntypedef basic_printf_context_t<internal::wbuffer>::type wprintf_context;\n\ntypedef basic_format_args<printf_context> printf_args;\ntypedef basic_format_args<wprintf_context> wprintf_args;\n\n/**\n  \\rst\n  Constructs an `~fmt::format_arg_store` object that contains references to\n  arguments and can be implicitly converted to `~fmt::printf_args`. \n  \\endrst\n */\ntemplate<typename... Args>\ninline format_arg_store<printf_context, Args...>\n  make_printf_args(const Args &... args) { return {args...}; }\n\n/**\n  \\rst\n  Constructs an `~fmt::format_arg_store` object that contains references to\n  arguments and can be implicitly converted to `~fmt::wprintf_args`. \n  \\endrst\n */\ntemplate<typename... Args>\ninline format_arg_store<wprintf_context, Args...>\n  make_wprintf_args(const Args &... args) { return {args...}; }\n\ntemplate <typename S, typename Char = FMT_CHAR(S)>\ninline std::basic_string<Char>\nvsprintf(const S &format,\n         basic_format_args<typename basic_printf_context_t<\n           internal::basic_buffer<Char>>::type> args) {\n  basic_memory_buffer<Char> buffer;\n  printf(buffer, to_string_view(format), args);\n  return to_string(buffer);\n}\n\n/**\n  \\rst\n  Formats arguments and returns the result as a string.\n\n  **Example**::\n\n    std::string message = fmt::sprintf(\"The answer is %d\", 42);\n  \\endrst\n*/\ntemplate <typename S, typename... Args>\ninline FMT_ENABLE_IF_T(\n    internal::is_string<S>::value, std::basic_string<FMT_CHAR(S)>)\n    sprintf(const S &format, const Args & ... args) {\n  internal::check_format_string<Args...>(format);\n  typedef internal::basic_buffer<FMT_CHAR(S)> buffer;\n  typedef typename basic_printf_context_t<buffer>::type context;\n  format_arg_store<context, Args...> as{ args... };\n  return vsprintf(to_string_view(format),\n                  basic_format_args<context>(as));\n}\n\ntemplate <typename S, typename Char = FMT_CHAR(S)>\ninline int vfprintf(std::FILE *f, const S &format,\n                    basic_format_args<typename basic_printf_context_t<\n                      internal::basic_buffer<Char>>::type> args) {\n  basic_memory_buffer<Char> buffer;\n  printf(buffer, to_string_view(format), args);\n  std::size_t size = buffer.size();\n  return std::fwrite(\n    buffer.data(), sizeof(Char), size, f) < size ? -1 : static_cast<int>(size);\n}\n\n/**\n  \\rst\n  Prints formatted data to the file *f*.\n\n  **Example**::\n\n    fmt::fprintf(stderr, \"Don't %s!\", \"panic\");\n  \\endrst\n */\ntemplate <typename S, typename... Args>\ninline FMT_ENABLE_IF_T(internal::is_string<S>::value, int)\n    fprintf(std::FILE *f, const S &format, const Args & ... args) {\n  internal::check_format_string<Args...>(format);\n  typedef internal::basic_buffer<FMT_CHAR(S)> buffer;\n  typedef typename basic_printf_context_t<buffer>::type context;\n  format_arg_store<context, Args...> as{ args... };\n  return vfprintf(f, to_string_view(format),\n                  basic_format_args<context>(as));\n}\n\ntemplate <typename S, typename Char = FMT_CHAR(S)>\ninline int vprintf(const S &format,\n                   basic_format_args<typename basic_printf_context_t<\n                    internal::basic_buffer<Char>>::type> args) {\n  return vfprintf(stdout, to_string_view(format), args);\n}\n\n/**\n  \\rst\n  Prints formatted data to ``stdout``.\n\n  **Example**::\n\n    fmt::printf(\"Elapsed time: %.2f seconds\", 1.23);\n  \\endrst\n */\ntemplate <typename S, typename... Args>\ninline FMT_ENABLE_IF_T(internal::is_string<S>::value, int)\n    printf(const S &format_str, const Args & ... args) {\n  internal::check_format_string<Args...>(format_str);\n  typedef internal::basic_buffer<FMT_CHAR(S)> buffer;\n  typedef typename basic_printf_context_t<buffer>::type context;\n  format_arg_store<context, Args...> as{ args... };\n  return vprintf(to_string_view(format_str),\n                 basic_format_args<context>(as));\n}\n\ntemplate <typename S, typename Char = FMT_CHAR(S)>\ninline int vfprintf(std::basic_ostream<Char> &os,\n                    const S &format,\n                    basic_format_args<typename basic_printf_context_t<\n                      internal::basic_buffer<Char>>::type> args) {\n  basic_memory_buffer<Char> buffer;\n  printf(buffer, to_string_view(format), args);\n  internal::write(os, buffer);\n  return static_cast<int>(buffer.size());\n}\n\n/**\n  \\rst\n  Prints formatted data to the stream *os*.\n\n  **Example**::\n\n    fmt::fprintf(cerr, \"Don't %s!\", \"panic\");\n  \\endrst\n */\ntemplate <typename S, typename... Args>\ninline FMT_ENABLE_IF_T(internal::is_string<S>::value, int)\n    fprintf(std::basic_ostream<FMT_CHAR(S)> &os,\n            const S &format_str, const Args & ... args) {\n  internal::check_format_string<Args...>(format_str);\n  typedef internal::basic_buffer<FMT_CHAR(S)> buffer;\n  typedef typename basic_printf_context_t<buffer>::type context;\n  format_arg_store<context, Args...> as{ args... };\n  return vfprintf(os, to_string_view(format_str),\n                  basic_format_args<context>(as));\n}\nFMT_END_NAMESPACE\n\n#endif  // FMT_PRINTF_H_\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/fmt/bundled/ranges.h",
    "content": "// Formatting library for C++ - the core API\n//\n// Copyright (c) 2012 - present, Victor Zverovich\n// All rights reserved.\n//\n// For the license information refer to format.h.\n//\n// Copyright (c) 2018 - present, Remotion (Igor Schulz)\n// All Rights Reserved\n// {fmt} support for ranges, containers and types tuple interface.\n\n#ifndef FMT_RANGES_H_\n#define FMT_RANGES_H_\n\n#include \"format.h\"\n#include <type_traits>\n\n// output only up to N items from the range.\n#ifndef FMT_RANGE_OUTPUT_LENGTH_LIMIT\n# define FMT_RANGE_OUTPUT_LENGTH_LIMIT 256\n#endif\n\nFMT_BEGIN_NAMESPACE\n\ntemplate <typename Char>\nstruct formatting_base {\n  template <typename ParseContext>\n  FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {\n    return ctx.begin();\n  }\n};\n\ntemplate <typename Char, typename Enable = void>\nstruct formatting_range : formatting_base<Char> {\n  static FMT_CONSTEXPR_DECL const std::size_t range_length_limit =\n      FMT_RANGE_OUTPUT_LENGTH_LIMIT; // output only up to N items from the range.\n  Char prefix;\n  Char delimiter;\n  Char postfix;\n  formatting_range() : prefix('{'), delimiter(','), postfix('}') {}\n  static FMT_CONSTEXPR_DECL const bool add_delimiter_spaces = true;\n  static FMT_CONSTEXPR_DECL const bool add_prepostfix_space = false;\n};\n\ntemplate <typename Char, typename Enable = void>\nstruct formatting_tuple : formatting_base<Char> {\n  Char prefix;\n  Char delimiter;\n  Char postfix;\n  formatting_tuple() : prefix('('), delimiter(','), postfix(')') {}\n  static FMT_CONSTEXPR_DECL const bool add_delimiter_spaces = true;\n  static FMT_CONSTEXPR_DECL const bool add_prepostfix_space = false;\n};\n\nnamespace internal {\n\ntemplate <typename RangeT, typename OutputIterator>\nvoid copy(const RangeT &range, OutputIterator out) {\n  for (auto it = range.begin(), end = range.end(); it != end; ++it)\n    *out++ = *it;\n}\n\ntemplate <typename OutputIterator>\nvoid copy(const char *str, OutputIterator out) {\n  const char *p_curr = str;\n  while (*p_curr) {\n    *out++ = *p_curr++;\n  }\n}\n\ntemplate <typename OutputIterator>\nvoid copy(char ch, OutputIterator out) {\n  *out++ = ch;\n}\n\n/// Return true value if T has std::string interface, like std::string_view.\ntemplate <typename T>\nclass is_like_std_string {\n  template <typename U>\n  static auto check(U *p) ->\n    decltype(p->find('a'), p->length(), p->data(), int());\n  template <typename>\n  static void check(...);\n\n public:\n  static FMT_CONSTEXPR_DECL const bool value =\n    !std::is_void<decltype(check<T>(FMT_NULL))>::value;\n};\n\ntemplate <typename Char>\nstruct is_like_std_string<fmt::basic_string_view<Char>> : std::true_type {};\n\ntemplate <typename... Ts>\nstruct conditional_helper {};\n\ntemplate <typename T, typename _ = void>\nstruct is_range_ : std::false_type {};\n\n#if !FMT_MSC_VER || FMT_MSC_VER > 1800\ntemplate <typename T>\nstruct is_range_<T, typename std::conditional<\n                    false,\n                    conditional_helper<decltype(internal::declval<T>().begin()),\n                                       decltype(internal::declval<T>().end())>,\n                    void>::type> : std::true_type {};\n#endif\n\n/// tuple_size and tuple_element check.\ntemplate <typename T>\nclass is_tuple_like_ {\n  template <typename U>\n  static auto check(U *p) ->\n    decltype(std::tuple_size<U>::value,\n      internal::declval<typename std::tuple_element<0, U>::type>(), int());\n  template <typename>\n  static void check(...);\n\n public:\n  static FMT_CONSTEXPR_DECL const bool value =\n    !std::is_void<decltype(check<T>(FMT_NULL))>::value;\n};\n\n// Check for integer_sequence\n#if defined(__cpp_lib_integer_sequence) || FMT_MSC_VER >= 1900\ntemplate <typename T, T... N>\nusing integer_sequence = std::integer_sequence<T, N...>;\ntemplate <std::size_t... N>\nusing index_sequence = std::index_sequence<N...>;\ntemplate <std::size_t N>\nusing make_index_sequence = std::make_index_sequence<N>;\n#else\ntemplate <typename T, T... N>\nstruct integer_sequence {\n  typedef T value_type;\n\n  static FMT_CONSTEXPR std::size_t size() {\n    return sizeof...(N);\n  }\n};\n\ntemplate <std::size_t... N>\nusing index_sequence = integer_sequence<std::size_t, N...>;\n\ntemplate <typename T, std::size_t N, T... Ns>\nstruct make_integer_sequence : make_integer_sequence<T, N - 1, N - 1, Ns...> {};\ntemplate <typename T, T... Ns>\nstruct make_integer_sequence<T, 0, Ns...> : integer_sequence<T, Ns...> {};\n\ntemplate <std::size_t N>\nusing make_index_sequence = make_integer_sequence<std::size_t, N>;\n#endif\n\ntemplate <class Tuple, class F, size_t... Is>\nvoid for_each(index_sequence<Is...>, Tuple &&tup, F &&f) FMT_NOEXCEPT {\n  using std::get;\n  // using free function get<I>(T) now.\n  const int _[] = {0, ((void)f(get<Is>(tup)), 0)...};\n  (void)_;  // blocks warnings\n}\n\ntemplate <class T>\nFMT_CONSTEXPR make_index_sequence<std::tuple_size<T>::value> \nget_indexes(T const &) { return {}; }\n\ntemplate <class Tuple, class F>\nvoid for_each(Tuple &&tup, F &&f) {\n  const auto indexes = get_indexes(tup);\n  for_each(indexes, std::forward<Tuple>(tup), std::forward<F>(f));\n}\n\ntemplate<typename Arg>\nFMT_CONSTEXPR const char* format_str_quoted(bool add_space, const Arg&, \n  typename std::enable_if<\n    !is_like_std_string<typename std::decay<Arg>::type>::value>::type* = nullptr) {\n  return add_space ? \" {}\" : \"{}\";\n}\n\ntemplate<typename Arg>\nFMT_CONSTEXPR const char* format_str_quoted(bool add_space, const Arg&, \n  typename std::enable_if<\n    is_like_std_string<typename std::decay<Arg>::type>::value>::type* = nullptr) {\n  return add_space ? \" \\\"{}\\\"\" : \"\\\"{}\\\"\";\n}\n\nFMT_CONSTEXPR const char* format_str_quoted(bool add_space, const char*) {\n  return add_space ? \" \\\"{}\\\"\" : \"\\\"{}\\\"\";\n}\nFMT_CONSTEXPR const wchar_t* format_str_quoted(bool add_space, const wchar_t*) {\n    return add_space ? L\" \\\"{}\\\"\" : L\"\\\"{}\\\"\";\n}\n\nFMT_CONSTEXPR const char* format_str_quoted(bool add_space, const char) {\n    return add_space ? \" '{}'\" : \"'{}'\";\n}\nFMT_CONSTEXPR const wchar_t* format_str_quoted(bool add_space, const wchar_t) {\n    return add_space ? L\" '{}'\" : L\"'{}'\";\n}\n\n}  // namespace internal\n\ntemplate <typename T>\nstruct is_tuple_like {\n  static FMT_CONSTEXPR_DECL const bool value =\n    internal::is_tuple_like_<T>::value && !internal::is_range_<T>::value;\n};\n\ntemplate <typename TupleT, typename Char>\nstruct formatter<TupleT, Char, \n    typename std::enable_if<fmt::is_tuple_like<TupleT>::value>::type> {\nprivate:\n  // C++11 generic lambda for format()\n  template <typename FormatContext>\n  struct format_each {\n    template <typename T>\n    void operator()(const T& v) {\n      if (i > 0) {\n        if (formatting.add_prepostfix_space) {\n          *out++ = ' ';\n        }\n        internal::copy(formatting.delimiter, out);\n      }\n      format_to(out,\n                internal::format_str_quoted(\n                    (formatting.add_delimiter_spaces && i > 0), v),\n                v);\n      ++i;\n    }\n\n    formatting_tuple<Char>& formatting;\n    std::size_t& i;\n    typename std::add_lvalue_reference<decltype(std::declval<FormatContext>().out())>::type out;\n  };\n\npublic:\n  formatting_tuple<Char> formatting;\n\n  template <typename ParseContext>\n  FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {\n    return formatting.parse(ctx);\n  }\n\n  template <typename FormatContext = format_context>\n  auto format(const TupleT &values, FormatContext &ctx) -> decltype(ctx.out()) {\n    auto out = ctx.out();\n    std::size_t i = 0;\n    internal::copy(formatting.prefix, out);\n\n    internal::for_each(values, format_each<FormatContext>{formatting, i, out});\n    if (formatting.add_prepostfix_space) {\n      *out++ = ' ';\n    }\n    internal::copy(formatting.postfix, out);\n\n    return ctx.out();\n  }\n};\n\ntemplate <typename T>\nstruct is_range {\n  static FMT_CONSTEXPR_DECL const bool value =\n    internal::is_range_<T>::value && !internal::is_like_std_string<T>::value;\n};\n\ntemplate <typename RangeT, typename Char>\nstruct formatter<RangeT, Char,\n    typename std::enable_if<fmt::is_range<RangeT>::value>::type> {\n\n  formatting_range<Char> formatting;\n\n  template <typename ParseContext>\n  FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {\n    return formatting.parse(ctx);\n  }\n\n  template <typename FormatContext>\n  typename FormatContext::iterator format(\n      const RangeT &values, FormatContext &ctx) {\n    auto out = ctx.out();\n    internal::copy(formatting.prefix, out);\n    std::size_t i = 0;\n    for (auto it = values.begin(), end = values.end(); it != end; ++it) {\n      if (i > 0) {\n        if (formatting.add_prepostfix_space) {\n          *out++ = ' ';\n        }\n        internal::copy(formatting.delimiter, out);\n      }\n      format_to(out,\n                internal::format_str_quoted(\n                    (formatting.add_delimiter_spaces && i > 0), *it),\n                *it);\n      if (++i > formatting.range_length_limit) {\n        format_to(out, \" ... <other elements>\");\n        break;\n      }\n    }\n    if (formatting.add_prepostfix_space) {\n      *out++ = ' ';\n    }\n    internal::copy(formatting.postfix, out);\n    return ctx.out();\n  }\n};\n\nFMT_END_NAMESPACE\n\n#endif // FMT_RANGES_H_\n\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/fmt/bundled/time.h",
    "content": "// Formatting library for C++ - time formatting\n//\n// Copyright (c) 2012 - present, Victor Zverovich\n// All rights reserved.\n//\n// For the license information refer to format.h.\n\n#ifndef FMT_TIME_H_\n#define FMT_TIME_H_\n\n#include \"format.h\"\n#include <ctime>\n#include <locale>\n\nFMT_BEGIN_NAMESPACE\n\n// Prevents expansion of a preceding token as a function-style macro.\n// Usage: f FMT_NOMACRO()\n#define FMT_NOMACRO\n\nnamespace internal{\ninline null<> localtime_r FMT_NOMACRO(...) { return null<>(); }\ninline null<> localtime_s(...) { return null<>(); }\ninline null<> gmtime_r(...) { return null<>(); }\ninline null<> gmtime_s(...) { return null<>(); }\n}  // namespace internal\n\n// Thread-safe replacement for std::localtime\ninline std::tm localtime(std::time_t time) {\n  struct dispatcher {\n    std::time_t time_;\n    std::tm tm_;\n\n    dispatcher(std::time_t t): time_(t) {}\n\n    bool run() {\n      using namespace fmt::internal;\n      return handle(localtime_r(&time_, &tm_));\n    }\n\n    bool handle(std::tm *tm) { return tm != FMT_NULL; }\n\n    bool handle(internal::null<>) {\n      using namespace fmt::internal;\n      return fallback(localtime_s(&tm_, &time_));\n    }\n\n    bool fallback(int res) { return res == 0; }\n\n#if !FMT_MSC_VER\n    bool fallback(internal::null<>) {\n      using namespace fmt::internal;\n      std::tm *tm = std::localtime(&time_);\n      if (tm) tm_ = *tm;\n      return tm != FMT_NULL;\n    }\n#endif\n  };\n  dispatcher lt(time);\n  // Too big time values may be unsupported.\n  if (!lt.run())\n    FMT_THROW(format_error(\"time_t value out of range\"));\n  return lt.tm_;\n}\n\n// Thread-safe replacement for std::gmtime\ninline std::tm gmtime(std::time_t time) {\n  struct dispatcher {\n    std::time_t time_;\n    std::tm tm_;\n\n    dispatcher(std::time_t t): time_(t) {}\n\n    bool run() {\n      using namespace fmt::internal;\n      return handle(gmtime_r(&time_, &tm_));\n    }\n\n    bool handle(std::tm *tm) { return tm != FMT_NULL; }\n\n    bool handle(internal::null<>) {\n      using namespace fmt::internal;\n      return fallback(gmtime_s(&tm_, &time_));\n    }\n\n    bool fallback(int res) { return res == 0; }\n\n#if !FMT_MSC_VER\n    bool fallback(internal::null<>) {\n      std::tm *tm = std::gmtime(&time_);\n      if (tm) tm_ = *tm;\n      return tm != FMT_NULL;\n    }\n#endif\n  };\n  dispatcher gt(time);\n  // Too big time values may be unsupported.\n  if (!gt.run())\n    FMT_THROW(format_error(\"time_t value out of range\"));\n  return gt.tm_;\n}\n\nnamespace internal {\ninline std::size_t strftime(char *str, std::size_t count, const char *format,\n                            const std::tm *time) {\n  return std::strftime(str, count, format, time);\n}\n\ninline std::size_t strftime(wchar_t *str, std::size_t count,\n                            const wchar_t *format, const std::tm *time) {\n  return std::wcsftime(str, count, format, time);\n}\n}\n\ntemplate <typename Char>\nstruct formatter<std::tm, Char> {\n  template <typename ParseContext>\n  auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {\n    auto it = ctx.begin();\n    if (it != ctx.end() && *it == ':')\n      ++it;\n    auto end = it;\n    while (end != ctx.end() && *end != '}')\n      ++end;\n    tm_format.reserve(internal::to_unsigned(end - it + 1));\n    tm_format.append(it, end);\n    tm_format.push_back('\\0');\n    return end;\n  }\n\n  template <typename FormatContext>\n  auto format(const std::tm &tm, FormatContext &ctx) -> decltype(ctx.out()) {\n    basic_memory_buffer<Char> buf;\n    std::size_t start = buf.size();\n    for (;;) {\n      std::size_t size = buf.capacity() - start;\n      std::size_t count =\n        internal::strftime(&buf[start], size, &tm_format[0], &tm);\n      if (count != 0) {\n        buf.resize(start + count);\n        break;\n      }\n      if (size >= tm_format.size() * 256) {\n        // If the buffer is 256 times larger than the format string, assume\n        // that `strftime` gives an empty result. There doesn't seem to be a\n        // better way to distinguish the two cases:\n        // https://github.com/fmtlib/fmt/issues/367\n        break;\n      }\n      const std::size_t MIN_GROWTH = 10;\n      buf.reserve(buf.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH));\n    }\n    return std::copy(buf.begin(), buf.end(), ctx.out());\n  }\n\n  basic_memory_buffer<Char> tm_format;\n};\nFMT_END_NAMESPACE\n\n#endif  // FMT_TIME_H_\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/fmt/fmt.h",
    "content": "//\n// Copyright(c) 2016-2018 Gabi Melman.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n//\n\n#pragma once\n\n//\n// Include a bundled header-only copy of fmtlib or an external one.\n// By default spdlog include its own copy.\n//\n\n#if !defined(SPDLOG_FMT_EXTERNAL)\n#ifdef SPDLOG_HEADER_ONLY\n#ifndef FMT_HEADER_ONLY\n#define FMT_HEADER_ONLY\n#endif\n#endif\n#ifndef FMT_USE_WINDOWS_H\n#define FMT_USE_WINDOWS_H 0\n#endif\n#include \"bundled/core.h\"\n#include \"bundled/format.h\"\n#else // SPDLOG_FMT_EXTERNAL is defined - use external fmtlib\n#include \"fmt/core.h\"\n#include \"fmt/format.h\"\n#endif\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/fmt/ostr.h",
    "content": "//\n// Copyright(c) 2016 Gabi Melman.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n//\n\n#pragma once\n//\n// include bundled or external copy of fmtlib's ostream support\n//\n#if !defined(SPDLOG_FMT_EXTERNAL)\n#ifndef FMT_HEADER_ONLY\n#define FMT_HEADER_ONLY\n#endif\n#include \"bundled/ostream.h\"\n#include \"fmt.h\"\n#else\n#include <fmt/ostream.h>\n#endif\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/formatter.h",
    "content": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n#pragma once\n\n#include \"fmt/fmt.h\"\n#include \"spdlog/details/log_msg.h\"\n\nnamespace spdlog {\n\nclass formatter\n{\npublic:\n    virtual ~formatter() = default;\n    virtual void format(const details::log_msg &msg, fmt::memory_buffer &dest) = 0;\n    virtual std::unique_ptr<formatter> clone() const = 0;\n};\n} // namespace spdlog\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/logger-inl.h",
    "content": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n#pragma once\n\n#ifndef SPDLOG_HEADER_ONLY\n#include \"spdlog/logger.h\"\n#endif\n\n#include \"spdlog/sinks/sink.h\"\n#include \"spdlog/details/pattern_formatter.h\"\n\n#include <cstdio>\n\nnamespace spdlog {\n\n// public methods\nSPDLOG_INLINE logger::logger(const logger &other)\n    : name_(other.name_)\n    , sinks_(other.sinks_)\n    , level_(other.level_.load(std::memory_order_relaxed))\n    , flush_level_(other.flush_level_.load(std::memory_order_relaxed))\n    , custom_err_handler_(other.custom_err_handler_)\n{}\n\nSPDLOG_INLINE logger::logger(logger &&other)\n    : name_(std::move(other.name_))\n    , sinks_(std::move(other.sinks_))\n    , level_(other.level_.load(std::memory_order_relaxed))\n    , flush_level_(other.flush_level_.load(std::memory_order_relaxed))\n    , custom_err_handler_(std::move(other.custom_err_handler_))\n{}\n\nSPDLOG_INLINE logger &logger::operator=(logger other)\n{\n    this->swap(other);\n    return *this;\n}\n\nSPDLOG_INLINE void logger::swap(spdlog::logger &other)\n{\n    name_.swap(other.name_);\n    sinks_.swap(other.sinks_);\n\n    // swap level_\n    auto tmp = other.level_.load();\n    tmp = level_.exchange(tmp);\n    other.level_.store(tmp);\n\n    // swap flush level_\n    tmp = other.flush_level_.load();\n    tmp = flush_level_.exchange(tmp);\n    other.flush_level_.store(tmp);\n\n    custom_err_handler_.swap(other.custom_err_handler_);\n}\n\nSPDLOG_INLINE void swap(logger &a, logger &b)\n{\n    a.swap(b);\n}\n\nSPDLOG_INLINE void logger::log(source_loc loc, level::level_enum lvl, string_view_t msg)\n{\n    if (!should_log(lvl))\n    {\n        return;\n    }\n\n    details::log_msg log_msg(loc, string_view_t(name_), lvl, msg);\n    sink_it_(log_msg);\n}\n\nSPDLOG_INLINE void logger::log(level::level_enum lvl, string_view_t msg)\n{\n    log(source_loc{}, lvl, msg);\n}\n\nSPDLOG_INLINE bool logger::should_log(level::level_enum msg_level) const\n{\n    return msg_level >= level_.load(std::memory_order_relaxed);\n}\n\nSPDLOG_INLINE void logger::set_level(level::level_enum log_level)\n{\n    level_.store(log_level);\n}\n\nSPDLOG_INLINE level::level_enum logger::default_level()\n{\n    return static_cast<level::level_enum>(SPDLOG_ACTIVE_LEVEL);\n}\n\nSPDLOG_INLINE level::level_enum logger::level() const\n{\n    return static_cast<level::level_enum>(level_.load(std::memory_order_relaxed));\n}\n\nSPDLOG_INLINE const std::string &logger::name() const\n{\n    return name_;\n}\n\n// set formatting for the sinks in this logger.\n// each sink will get a seperate instance of the formatter object.\nSPDLOG_INLINE void logger::set_formatter(std::unique_ptr<formatter> f)\n{\n    for (auto it = sinks_.begin(); it != sinks_.end(); ++it)\n    {\n        if (std::next(it) == sinks_.end())\n        {\n            // last element - we can be move it.\n            (*it)->set_formatter(std::move(f));\n        }\n        else\n        {\n            (*it)->set_formatter(f->clone());\n        }\n    }\n}\n\nSPDLOG_INLINE void logger::set_pattern(std::string pattern, pattern_time_type time_type)\n{\n    auto new_formatter = details::make_unique<pattern_formatter>(std::move(pattern), time_type);\n    set_formatter(std::move(new_formatter));\n}\n\n// flush functions\nSPDLOG_INLINE void logger::flush()\n{\n    flush_();\n}\n\nSPDLOG_INLINE void logger::flush_on(level::level_enum log_level)\n{\n    flush_level_.store(log_level);\n}\n\nSPDLOG_INLINE level::level_enum logger::flush_level() const\n{\n    return static_cast<level::level_enum>(flush_level_.load(std::memory_order_relaxed));\n}\n\n// sinks\nSPDLOG_INLINE const std::vector<sink_ptr> &logger::sinks() const\n{\n    return sinks_;\n}\n\nSPDLOG_INLINE std::vector<sink_ptr> &logger::sinks()\n{\n    return sinks_;\n}\n\n// error handler\nSPDLOG_INLINE void logger::set_error_handler(err_handler handler)\n{\n    custom_err_handler_ = handler;\n}\n\n// create new logger with same sinks and configuration.\nSPDLOG_INLINE std::shared_ptr<logger> logger::clone(std::string logger_name)\n{\n    auto cloned = std::make_shared<logger>(*this);\n    cloned->name_ = std::move(logger_name);\n    return cloned;\n}\n\n// protected methods\nSPDLOG_INLINE void logger::sink_it_(details::log_msg &msg)\n{\n    for (auto &sink : sinks_)\n    {\n        if (sink->should_log(msg.level))\n        {\n            try\n            {\n                sink->log(msg);\n            }\n            SPDLOG_LOGGER_CATCH()\n        }\n    }\n\n    if (should_flush_(msg))\n    {\n        flush_();\n    }\n}\n\nSPDLOG_INLINE void logger::flush_()\n{\n    for (auto &sink : sinks_)\n    {\n        try\n        {\n            sink->flush();\n        }\n        SPDLOG_LOGGER_CATCH()\n    }\n}\n\nSPDLOG_INLINE bool logger::should_flush_(const details::log_msg &msg)\n{\n    auto flush_level = flush_level_.load(std::memory_order_relaxed);\n    return (msg.level >= flush_level) && (msg.level != level::off);\n}\n\nSPDLOG_INLINE void logger::err_handler_(const std::string &msg)\n{\n\n    if (custom_err_handler_)\n    {\n        custom_err_handler_(msg);\n    }\n    else\n    {\n        using std::chrono::system_clock;\n        static std::mutex mutex;\n        static std::chrono::system_clock::time_point last_report_time;\n        static size_t err_counter = 0;\n        std::lock_guard<std::mutex> lk{mutex};\n        auto now = system_clock::now();\n        err_counter++;\n        if (now - last_report_time < std::chrono::seconds(1))\n        {\n            return;\n        }\n        last_report_time = now;\n        auto tm_time = details::os::localtime(system_clock::to_time_t(now));\n        char date_buf[64];\n        std::strftime(date_buf, sizeof(date_buf), \"%Y-%m-%d %H:%M:%S\", &tm_time);\n        fprintf(stderr, \"[*** LOG ERROR #%04zu ***] [%s] [%s] {%s}\\n\", err_counter, date_buf, name().c_str(), msg.c_str());\n    }\n}\n} // namespace spdlog\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/logger.h",
    "content": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n#pragma once\n\n// Thread safe logger (except for set_pattern(..), set_formatter(..) and\n// set_error_handler())\n// Has name, log level, vector of std::shared sink pointers and formatter\n// Upon each log write the logger:\n// 1. Checks if its log level is enough to log the message and if yes:\n// 2. Call the underlying sinks to do the job.\n// 3. Each sink use its own private copy of a formatter to format the message\n// and send to its destination.\n//\n// The use of private formatter per sink provides the opportunity to cache some\n// formatted data, and support for different format per sink.\n\n#include \"spdlog/common.h\"\n#include \"spdlog/details/log_msg.h\"\n\n#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT\n#include \"spdlog/details/os.h\"\n#endif\n\n#include <vector>\n\n#define SPDLOG_LOGGER_CATCH()                                                                                                              \\\n    catch (const std::exception &ex)                                                                                                       \\\n    {                                                                                                                                      \\\n        err_handler_(ex.what());                                                                                                           \\\n    }                                                                                                                                      \\\n    catch (...)                                                                                                                            \\\n    {                                                                                                                                      \\\n        err_handler_(\"Unknown exception in logger\");                                                                                       \\\n    }\n\nnamespace spdlog {\nclass logger\n{\npublic:\n    // Empty logger\n    explicit logger(std::string name)\n        : name_(std::move(name))\n        , sinks_()\n    {}\n\n    // Logger with range on sinks\n    template<typename It>\n    logger(std::string name, It begin, It end)\n        : name_(std::move(name))\n        , sinks_(begin, end)\n    {}\n\n    // Logger with single sink\n    logger(std::string name, sink_ptr single_sink)\n        : logger(std::move(name), {std::move(single_sink)})\n    {}\n\n    // Logger with sinks init list\n    logger(std::string name, sinks_init_list sinks)\n        : logger(std::move(name), sinks.begin(), sinks.end())\n    {}\n\n    virtual ~logger() = default;\n\n    logger(const logger &other);\n    logger(logger &&other);\n    logger &operator=(logger other);\n\n    void swap(spdlog::logger &other);\n\n    template<typename... Args>\n    void force_log(source_loc loc, level::level_enum lvl, string_view_t fmt, const Args &... args)\n    {\n        try\n        {\n            fmt::memory_buffer buf;\n            fmt::format_to(buf, fmt, args...);\n            details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size()));\n            sink_it_(log_msg);\n        }\n        SPDLOG_LOGGER_CATCH()\n    }\n\n    template<typename... Args>\n    void log(source_loc loc, level::level_enum lvl, string_view_t fmt, const Args &... args)\n    {\n        if (should_log(lvl))\n        {\n            force_log(loc, lvl, fmt, args...);\n        }\n    }\n\n    template<typename... Args>\n    void log(level::level_enum lvl, string_view_t fmt, const Args &... args)\n    {\n        log(source_loc{}, lvl, fmt, args...);\n    }\n\n    void log(source_loc loc, level::level_enum lvl, const string_view_t msg);\n    void log(level::level_enum lvl, string_view_t msg);\n\n    template<typename... Args>\n    void trace(string_view_t fmt, const Args &... args)\n    {\n        log(level::trace, fmt, args...);\n    }\n\n    template<typename... Args>\n    void debug(string_view_t fmt, const Args &... args)\n    {\n        log(level::debug, fmt, args...);\n    }\n\n    template<typename... Args>\n    void info(string_view_t fmt, const Args &... args)\n    {\n        log(level::info, fmt, args...);\n    }\n\n    template<typename... Args>\n    void warn(string_view_t fmt, const Args &... args)\n    {\n        log(level::warn, fmt, args...);\n    }\n\n    template<typename... Args>\n    void error(string_view_t fmt, const Args &... args)\n    {\n        log(level::err, fmt, args...);\n    }\n\n    template<typename... Args>\n    void critical(string_view_t fmt, const Args &... args)\n    {\n        log(level::critical, fmt, args...);\n    }\n\n    template<typename T>\n    void log(level::level_enum lvl, const T &msg)\n    {\n        log(source_loc{}, lvl, msg);\n    }\n\n    // T can be statically converted to string_view\n    template<class T, typename std::enable_if<std::is_convertible<const T &, spdlog::string_view_t>::value, T>::type * = nullptr>\n    void log(source_loc loc, level::level_enum lvl, const T &msg)\n    {\n        if (!should_log(lvl))\n        {\n            return;\n        }\n\n        details::log_msg log_msg(loc, name_, lvl, msg);\n        sink_it_(log_msg);\n    }\n\n    // T cannot be statically converted to string_view or wstring_view\n    template<class T, typename std::enable_if<!std::is_convertible<const T &, spdlog::string_view_t>::value && !is_convertible_to_wstring_view<const T &>::value, T>::type * = nullptr>\n    void log(source_loc loc, level::level_enum lvl, const T &msg)\n    {\n        if (!should_log(lvl))\n        {\n            return;\n        }\n        try\n        {\n            fmt::memory_buffer buf;\n            fmt::format_to(buf, \"{}\", msg);\n            details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size()));\n            sink_it_(log_msg);\n        }\n        SPDLOG_LOGGER_CATCH()\n    }\n\n    template<typename T>\n    void trace(const T &msg)\n    {\n        log(level::trace, msg);\n    }\n\n    template<typename T>\n    void debug(const T &msg)\n    {\n        log(level::debug, msg);\n    }\n\n    template<typename T>\n    void info(const T &msg)\n    {\n        log(level::info, msg);\n    }\n\n    template<typename T>\n    void warn(const T &msg)\n    {\n        log(level::warn, msg);\n    }\n\n    template<typename T>\n    void error(const T &msg)\n    {\n        log(level::err, msg);\n    }\n\n    template<typename T>\n    void critical(const T &msg)\n    {\n        log(level::critical, msg);\n    }\n\n#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT\n#ifndef _WIN32\n#error SPDLOG_WCHAR_TO_UTF8_SUPPORT only supported on windows\n#else\n    template<typename... Args>\n    void log(source_loc source, level::level_enum lvl, wstring_view_t fmt, const Args &... args)\n    {\n        if (!should_log(lvl))\n        {\n            return;\n        }\n\n        try\n        {\n            // format to wmemory_buffer and convert to utf8\n            fmt::wmemory_buffer wbuf;\n            fmt::format_to(wbuf, fmt, args...);\n\n            fmt::memory_buffer buf;\n            details::os::wstr_to_utf8buf(wstring_view_t(wbuf.data(), wbuf.size()), buf);\n\n            details::log_msg log_msg(source, name_, lvl, string_view_t(buf.data(), buf.size()));\n            sink_it_(log_msg);\n        }\n        SPDLOG_LOGGER_CATCH()\n    }\n\n    template<typename... Args>\n    void log(level::level_enum lvl, wstring_view_t fmt, const Args &... args)\n    {\n        log(source_loc{}, lvl, fmt, args...);\n    }\n\n    template<typename... Args>\n    void trace(wstring_view_t fmt, const Args &... args)\n    {\n        log(level::trace, fmt, args...);\n    }\n\n    template<typename... Args>\n    void debug(wstring_view_t fmt, const Args &... args)\n    {\n        log(level::debug, fmt, args...);\n    }\n\n    template<typename... Args>\n    void info(wstring_view_t fmt, const Args &... args)\n    {\n        log(level::info, fmt, args...);\n    }\n\n    template<typename... Args>\n    void warn(wstring_view_t fmt, const Args &... args)\n    {\n        log(level::warn, fmt, args...);\n    }\n\n    template<typename... Args>\n    void error(wstring_view_t fmt, const Args &... args)\n    {\n        log(level::err, fmt, args...);\n    }\n\n    template<typename... Args>\n    void critical(wstring_view_t fmt, const Args &... args)\n    {\n        log(level::critical, fmt, args...);\n    }\n\n    // T can be statically converted to wstring_view\n    template<class T, typename std::enable_if<is_convertible_to_wstring_view<const T &>::value, T>::type * = nullptr>\n    void log(source_loc loc, level::level_enum lvl, const T &msg)\n    {\n        if (!should_log(lvl))\n        {\n            return;\n        }\n\n        try\n        {\n            fmt::memory_buffer buf;\n            details::os::wstr_to_utf8buf(msg, buf);\n\n            details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size()));\n            sink_it_(log_msg);\n        }\n        SPDLOG_LOGGER_CATCH()\n    }\n#endif // _WIN32\n#endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT\n\n    bool should_log(level::level_enum msg_level) const;\n\n    void set_level(level::level_enum log_level);\n\n    static level::level_enum default_level();\n\n    level::level_enum level() const;\n\n    const std::string &name() const;\n\n    // set formatting for the sinks in this logger.\n    // each sink will get a seperate instance of the formatter object.\n    void set_formatter(std::unique_ptr<formatter> f);\n\n    void set_pattern(std::string pattern, pattern_time_type time_type = pattern_time_type::local);\n\n    // flush functions\n    void flush();\n    void flush_on(level::level_enum log_level);\n    level::level_enum flush_level() const;\n\n    // sinks\n    const std::vector<sink_ptr> &sinks() const;\n\n    std::vector<sink_ptr> &sinks();\n\n    // error handler\n    void set_error_handler(err_handler);\n\n    // create new logger with same sinks and configuration.\n    virtual std::shared_ptr<logger> clone(std::string logger_name);\n\nprotected:\n    std::string name_;\n    std::vector<sink_ptr> sinks_;\n    spdlog::level_t level_{spdlog::logger::default_level()};\n    spdlog::level_t flush_level_{level::off};\n    err_handler custom_err_handler_{nullptr};\n\n    virtual void sink_it_(details::log_msg &msg);\n    virtual void flush_();\n    bool should_flush_(const details::log_msg &msg);\n\n    // handle errors during logging.\n    // default handler prints the error to stderr at max rate of 1 message/sec.\n    void err_handler_(const std::string &msg);\n};\n\nvoid swap(logger &a, logger &b);\n\n} // namespace spdlog\n\n#ifdef SPDLOG_HEADER_ONLY\n#include \"logger-inl.h\"\n#endif\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/sinks/android_sink.h",
    "content": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n#pragma once\n\n#ifdef __ANDROID__\n\n#include \"spdlog/details/fmt_helper.h\"\n#include \"spdlog/details/null_mutex.h\"\n#include \"spdlog/details/os.h\"\n#include \"spdlog/sinks/base_sink.h\"\n#include \"spdlog/details/synchronous_factory.h\"\n\n#include <android/log.h>\n#include <chrono>\n#include <mutex>\n#include <string>\n#include <thread>\n\n#if !defined(SPDLOG_ANDROID_RETRIES)\n#define SPDLOG_ANDROID_RETRIES 2\n#endif\n\nnamespace spdlog {\nnamespace sinks {\n\n/*\n * Android sink (logging using __android_log_write)\n */\ntemplate<typename Mutex>\nclass android_sink final : public base_sink<Mutex>\n{\npublic:\n    explicit android_sink(std::string tag = \"spdlog\", bool use_raw_msg = false)\n        : tag_(std::move(tag))\n        , use_raw_msg_(use_raw_msg)\n    {}\n\nprotected:\n    void sink_it_(const details::log_msg &msg) override\n    {\n        const android_LogPriority priority = convert_to_android_(msg.level);\n        fmt::memory_buffer formatted;\n        if (use_raw_msg_)\n        {\n            details::fmt_helper::append_string_view(msg.payload, formatted);\n        }\n        else\n        {\n            base_sink<Mutex>::formatter_->format(msg, formatted);\n        }\n        formatted.push_back('\\0');\n        const char *msg_output = formatted.data();\n\n        // See system/core/liblog/logger_write.c for explanation of return value\n        int ret = __android_log_write(priority, tag_.c_str(), msg_output);\n        int retry_count = 0;\n        while ((ret == -11 /*EAGAIN*/) && (retry_count < SPDLOG_ANDROID_RETRIES))\n        {\n            details::os::sleep_for_millis(5);\n            ret = __android_log_write(priority, tag_.c_str(), msg_output);\n            retry_count++;\n        }\n\n        if (ret < 0)\n        {\n            throw spdlog_ex(\"__android_log_write() failed\", ret);\n        }\n    }\n\n    void flush_() override {}\n\nprivate:\n    static android_LogPriority convert_to_android_(spdlog::level::level_enum level)\n    {\n        switch (level)\n        {\n        case spdlog::level::trace:\n            return ANDROID_LOG_VERBOSE;\n        case spdlog::level::debug:\n            return ANDROID_LOG_DEBUG;\n        case spdlog::level::info:\n            return ANDROID_LOG_INFO;\n        case spdlog::level::warn:\n            return ANDROID_LOG_WARN;\n        case spdlog::level::err:\n            return ANDROID_LOG_ERROR;\n        case spdlog::level::critical:\n            return ANDROID_LOG_FATAL;\n        default:\n            return ANDROID_LOG_DEFAULT;\n        }\n    }\n\n    std::string tag_;\n    bool use_raw_msg_;\n};\n\nusing android_sink_mt = android_sink<std::mutex>;\nusing android_sink_st = android_sink<details::null_mutex>;\n} // namespace sinks\n\n// Create and register android syslog logger\n\ntemplate<typename Factory = spdlog::synchronous_factory>\ninline std::shared_ptr<logger> android_logger_mt(const std::string &logger_name, const std::string &tag = \"spdlog\")\n{\n    return Factory::template create<sinks::android_sink_mt>(logger_name, tag);\n}\n\ntemplate<typename Factory = spdlog::synchronous_factory>\ninline std::shared_ptr<logger> android_logger_st(const std::string &logger_name, const std::string &tag = \"spdlog\")\n{\n    return Factory::template create<sinks::android_sink_st>(logger_name, tag);\n}\n\n} // namespace spdlog\n\n#endif // __ANDROID__"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/sinks/ansicolor_sink-inl.h",
    "content": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n#pragma once\n\n#ifndef SPDLOG_HEADER_ONLY\n#include \"spdlog/sinks/ansicolor_sink.h\"\n#endif\n\n#include \"spdlog/details/pattern_formatter.h\"\n#include \"spdlog/details/os.h\"\n\nnamespace spdlog {\nnamespace sinks {\n\ntemplate<typename ConsoleMutex>\nSPDLOG_INLINE ansicolor_sink<ConsoleMutex>::ansicolor_sink(FILE *target_file, color_mode mode)\n    : target_file_(target_file)\n    , mutex_(ConsoleMutex::mutex())\n    , formatter_(details::make_unique<spdlog::pattern_formatter>())\n\n{\n    set_color_mode(mode);\n    colors_[level::trace] = white;\n    colors_[level::debug] = cyan;\n    colors_[level::info] = green;\n    colors_[level::warn] = yellow_bold;\n    colors_[level::err] = red_bold;\n    colors_[level::critical] = bold_on_red;\n    colors_[level::off] = reset;\n}\n\ntemplate<typename ConsoleMutex>\nSPDLOG_INLINE void ansicolor_sink<ConsoleMutex>::set_color(level::level_enum color_level, string_view_t color)\n{\n    std::lock_guard<mutex_t> lock(mutex_);\n    colors_[color_level] = color;\n}\n\ntemplate<typename ConsoleMutex>\nSPDLOG_INLINE void ansicolor_sink<ConsoleMutex>::log(const details::log_msg &msg)\n{\n    // Wrap the originally formatted message in color codes.\n    // If color is not supported in the terminal, log as is instead.\n    std::lock_guard<mutex_t> lock(mutex_);\n\n    fmt::memory_buffer formatted;\n    formatter_->format(msg, formatted);\n    if (should_do_colors_ && msg.color_range_end > msg.color_range_start)\n    {\n        // before color range\n        print_range_(formatted, 0, msg.color_range_start);\n        // in color range\n        print_ccode_(colors_[msg.level]);\n        print_range_(formatted, msg.color_range_start, msg.color_range_end);\n        print_ccode_(reset);\n        // after color range\n        print_range_(formatted, msg.color_range_end, formatted.size());\n    }\n    else // no color\n    {\n        print_range_(formatted, 0, formatted.size());\n    }\n    fflush(target_file_);\n}\n\ntemplate<typename ConsoleMutex>\nSPDLOG_INLINE void ansicolor_sink<ConsoleMutex>::flush()\n{\n    std::lock_guard<mutex_t> lock(mutex_);\n    fflush(target_file_);\n}\n\ntemplate<typename ConsoleMutex>\nSPDLOG_INLINE void ansicolor_sink<ConsoleMutex>::set_pattern(const std::string &pattern)\n{\n    std::lock_guard<mutex_t> lock(mutex_);\n    formatter_ = std::unique_ptr<spdlog::formatter>(new pattern_formatter(pattern));\n}\n\ntemplate<typename ConsoleMutex>\nSPDLOG_INLINE void ansicolor_sink<ConsoleMutex>::set_formatter(std::unique_ptr<spdlog::formatter> sink_formatter)\n{\n    std::lock_guard<mutex_t> lock(mutex_);\n    formatter_ = std::move(sink_formatter);\n}\n\ntemplate<typename ConsoleMutex>\nSPDLOG_INLINE bool ansicolor_sink<ConsoleMutex>::should_color()\n{\n    return should_do_colors_;\n}\n\ntemplate<typename ConsoleMutex>\nSPDLOG_INLINE void ansicolor_sink<ConsoleMutex>::set_color_mode(color_mode mode)\n{\n    switch (mode)\n    {\n    case color_mode::always:\n        should_do_colors_ = true;\n        return;\n    case color_mode::automatic:\n        should_do_colors_ = details::os::in_terminal(target_file_) && details::os::is_color_terminal();\n        return;\n    case color_mode::never:\n        should_do_colors_ = false;\n        return;\n    }\n}\n\ntemplate<typename ConsoleMutex>\nSPDLOG_INLINE void ansicolor_sink<ConsoleMutex>::print_ccode_(const string_view_t &color_code)\n{\n    fwrite(color_code.data(), sizeof(string_view_t::char_type), color_code.size(), target_file_);\n}\n\ntemplate<typename ConsoleMutex>\nSPDLOG_INLINE void ansicolor_sink<ConsoleMutex>::print_range_(const fmt::memory_buffer &formatted, size_t start, size_t end)\n{\n    fwrite(formatted.data() + start, sizeof(char), end - start, target_file_);\n}\n\n// ansicolor_stdout_sink\ntemplate<typename ConsoleMutex>\nSPDLOG_INLINE ansicolor_stdout_sink<ConsoleMutex>::ansicolor_stdout_sink(color_mode mode)\n    : ansicolor_sink<ConsoleMutex>(stdout, mode)\n{}\n\n// ansicolor_stderr_sink\ntemplate<typename ConsoleMutex>\nSPDLOG_INLINE ansicolor_stderr_sink<ConsoleMutex>::ansicolor_stderr_sink(color_mode mode)\n    : ansicolor_sink<ConsoleMutex>(stderr, mode)\n{}\n\n} // namespace sinks\n} // namespace spdlog\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/sinks/ansicolor_sink.h",
    "content": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n#pragma once\n\n#include \"spdlog/details/console_globals.h\"\n#include \"spdlog/details/null_mutex.h\"\n#include \"spdlog/sinks/sink.h\"\n#include <memory>\n#include <mutex>\n#include <string>\n#include <unordered_map>\n\nnamespace spdlog {\nnamespace sinks {\n\n/**\n * This sink prefixes the output with an ANSI escape sequence color code\n * depending on the severity\n * of the message.\n * If no color terminal detected, omit the escape codes.\n */\n\ntemplate<typename ConsoleMutex>\nclass ansicolor_sink : public sink\n{\npublic:\n    using mutex_t = typename ConsoleMutex::mutex_t;\n    ansicolor_sink(FILE *target_file, color_mode mode);\n    ~ansicolor_sink() override = default;\n\n    ansicolor_sink(const ansicolor_sink &other) = delete;\n    ansicolor_sink &operator=(const ansicolor_sink &other) = delete;\n    void set_color(level::level_enum color_level, string_view_t color);\n    void set_color_mode(color_mode mode);\n    bool should_color();\n\n    void log(const details::log_msg &msg) override;\n    void flush() override;\n    void set_pattern(const std::string &pattern) final;\n    void set_formatter(std::unique_ptr<spdlog::formatter> sink_formatter) override;\n\n    // Formatting codes\n    const string_view_t reset = \"\\033[m\";\n    const string_view_t bold = \"\\033[1m\";\n    const string_view_t dark = \"\\033[2m\";\n    const string_view_t underline = \"\\033[4m\";\n    const string_view_t blink = \"\\033[5m\";\n    const string_view_t reverse = \"\\033[7m\";\n    const string_view_t concealed = \"\\033[8m\";\n    const string_view_t clear_line = \"\\033[K\";\n\n    // Foreground colors\n    const string_view_t black = \"\\033[30m\";\n    const string_view_t red = \"\\033[31m\";\n    const string_view_t green = \"\\033[32m\";\n    const string_view_t yellow = \"\\033[33m\";\n    const string_view_t blue = \"\\033[34m\";\n    const string_view_t magenta = \"\\033[35m\";\n    const string_view_t cyan = \"\\033[36m\";\n    const string_view_t white = \"\\033[37m\";\n\n    /// Background colors\n    const string_view_t on_black = \"\\033[40m\";\n    const string_view_t on_red = \"\\033[41m\";\n    const string_view_t on_green = \"\\033[42m\";\n    const string_view_t on_yellow = \"\\033[43m\";\n    const string_view_t on_blue = \"\\033[44m\";\n    const string_view_t on_magenta = \"\\033[45m\";\n    const string_view_t on_cyan = \"\\033[46m\";\n    const string_view_t on_white = \"\\033[47m\";\n\n    /// Bold colors\n    const string_view_t yellow_bold = \"\\033[33m\\033[1m\";\n    const string_view_t red_bold = \"\\033[31m\\033[1m\";\n    const string_view_t bold_on_red = \"\\033[1m\\033[41m\";\n\nprivate:\n    FILE *target_file_;\n    mutex_t &mutex_;\n    bool should_do_colors_;\n    std::unique_ptr<spdlog::formatter> formatter_;\n    std::unordered_map<level::level_enum, string_view_t, level::level_hasher> colors_;\n    void print_ccode_(const string_view_t &color_code);\n    void print_range_(const fmt::memory_buffer &formatted, size_t start, size_t end);\n};\n\ntemplate<typename ConsoleMutex>\nclass ansicolor_stdout_sink : public ansicolor_sink<ConsoleMutex>\n{\npublic:\n    explicit ansicolor_stdout_sink(color_mode mode = color_mode::automatic);\n};\n\ntemplate<typename ConsoleMutex>\nclass ansicolor_stderr_sink : public ansicolor_sink<ConsoleMutex>\n{\npublic:\n    explicit ansicolor_stderr_sink(color_mode mode = color_mode::automatic);\n};\n\nusing ansicolor_stdout_sink_mt = ansicolor_stdout_sink<details::console_mutex>;\nusing ansicolor_stdout_sink_st = ansicolor_stdout_sink<details::console_nullmutex>;\n\nusing ansicolor_stderr_sink_mt = ansicolor_stderr_sink<details::console_mutex>;\nusing ansicolor_stderr_sink_st = ansicolor_stderr_sink<details::console_nullmutex>;\n\n} // namespace sinks\n} // namespace spdlog\n\n#ifdef SPDLOG_HEADER_ONLY\n#include \"ansicolor_sink-inl.h\"\n#endif\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/sinks/base_sink-inl.h",
    "content": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n#pragma once\n\n#ifndef SPDLOG_HEADER_ONLY\n#include \"spdlog/sinks/base_sink.h\"\n#endif\n\n#include \"spdlog/common.h\"\n#include \"spdlog/details/pattern_formatter.h\"\n\n#include <memory>\n\ntemplate<typename Mutex>\nSPDLOG_INLINE spdlog::sinks::base_sink<Mutex>::base_sink()\n    : formatter_{details::make_unique<spdlog::pattern_formatter>()}\n{}\n\ntemplate<typename Mutex>\nSPDLOG_INLINE spdlog::sinks::base_sink<Mutex>::base_sink(std::unique_ptr<spdlog::formatter> formatter)\n    : formatter_{std::move(formatter)}\n{}\n\ntemplate<typename Mutex>\nvoid SPDLOG_INLINE spdlog::sinks::base_sink<Mutex>::log(const details::log_msg &msg)\n{\n    std::lock_guard<Mutex> lock(mutex_);\n    sink_it_(msg);\n}\n\ntemplate<typename Mutex>\nvoid SPDLOG_INLINE spdlog::sinks::base_sink<Mutex>::flush()\n{\n    std::lock_guard<Mutex> lock(mutex_);\n    flush_();\n}\n\ntemplate<typename Mutex>\nvoid SPDLOG_INLINE spdlog::sinks::base_sink<Mutex>::set_pattern(const std::string &pattern)\n{\n    std::lock_guard<Mutex> lock(mutex_);\n    set_pattern_(pattern);\n}\n\ntemplate<typename Mutex>\nvoid SPDLOG_INLINE spdlog::sinks::base_sink<Mutex>::set_formatter(std::unique_ptr<spdlog::formatter> sink_formatter)\n{\n    std::lock_guard<Mutex> lock(mutex_);\n    set_formatter_(std::move(sink_formatter));\n}\n\ntemplate<typename Mutex>\nvoid SPDLOG_INLINE spdlog::sinks::base_sink<Mutex>::set_pattern_(const std::string &pattern)\n{\n    set_formatter_(details::make_unique<spdlog::pattern_formatter>(pattern));\n}\n\ntemplate<typename Mutex>\nvoid SPDLOG_INLINE spdlog::sinks::base_sink<Mutex>::set_formatter_(std::unique_ptr<spdlog::formatter> sink_formatter)\n{\n    formatter_ = std::move(sink_formatter);\n}\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/sinks/base_sink.h",
    "content": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n#pragma once\n//\n// base sink templated over a mutex (either dummy or real)\n// concrete implementation should override the sink_it_() and flush_()  methods.\n// locking is taken care of in this class - no locking needed by the\n// implementers..\n//\n\n#include \"spdlog/common.h\"\n#include \"spdlog/details/log_msg.h\"\n#include \"spdlog/sinks/sink.h\"\n\nnamespace spdlog {\nnamespace sinks {\ntemplate<typename Mutex>\nclass base_sink : public sink\n{\npublic:\n    base_sink();\n    explicit base_sink(std::unique_ptr<spdlog::formatter> formatter);\n    base_sink(const base_sink &) = delete;\n    base_sink &operator=(const base_sink &) = delete;\n    void log(const details::log_msg &msg) final;\n    void flush() final;\n    void set_pattern(const std::string &pattern) final;\n    void set_formatter(std::unique_ptr<spdlog::formatter> sink_formatter) final;\n\nprotected:\n    // sink formatter\n    std::unique_ptr<spdlog::formatter> formatter_;\n    Mutex mutex_;\n\n    virtual void sink_it_(const details::log_msg &msg) = 0;\n    virtual void flush_() = 0;\n    virtual void set_pattern_(const std::string &pattern);\n    virtual void set_formatter_(std::unique_ptr<spdlog::formatter> sink_formatter);\n};\n} // namespace sinks\n} // namespace spdlog\n\n#ifdef SPDLOG_HEADER_ONLY\n#include \"base_sink-inl.h\"\n#endif\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/sinks/basic_file_sink-inl.h",
    "content": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n#pragma once\n\n#ifndef SPDLOG_HEADER_ONLY\n#include \"spdlog/sinks/basic_file_sink.h\"\n#endif\n\n#include \"spdlog/common.h\"\n#include \"spdlog/details/os.h\"\n\nnamespace spdlog {\nnamespace sinks {\n\ntemplate<typename Mutex>\nSPDLOG_INLINE basic_file_sink<Mutex>::basic_file_sink(const filename_t &filename, bool truncate)\n{\n    file_helper_.open(filename, truncate);\n}\n\ntemplate<typename Mutex>\nSPDLOG_INLINE const filename_t &basic_file_sink<Mutex>::filename() const\n{\n    return file_helper_.filename();\n}\n\ntemplate<typename Mutex>\nSPDLOG_INLINE void basic_file_sink<Mutex>::sink_it_(const details::log_msg &msg)\n{\n    fmt::memory_buffer formatted;\n    base_sink<Mutex>::formatter_->format(msg, formatted);\n    file_helper_.write(formatted);\n}\n\ntemplate<typename Mutex>\nSPDLOG_INLINE void basic_file_sink<Mutex>::flush_()\n{\n    file_helper_.flush();\n}\n\n} // namespace sinks\n} // namespace spdlog\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/sinks/basic_file_sink.h",
    "content": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n#pragma once\n\n#include \"spdlog/details/file_helper.h\"\n#include \"spdlog/details/null_mutex.h\"\n#include \"spdlog/sinks/base_sink.h\"\n#include \"spdlog/details/synchronous_factory.h\"\n\n#include <mutex>\n#include <string>\n\nnamespace spdlog {\nnamespace sinks {\n/*\n * Trivial file sink with single file as target\n */\ntemplate<typename Mutex>\nclass basic_file_sink final : public base_sink<Mutex>\n{\npublic:\n    explicit basic_file_sink(const filename_t &filename, bool truncate = false);\n    const filename_t &filename() const;\n\nprotected:\n    void sink_it_(const details::log_msg &msg) override;\n    void flush_() override;\n\nprivate:\n    details::file_helper file_helper_;\n};\n\nusing basic_file_sink_mt = basic_file_sink<std::mutex>;\nusing basic_file_sink_st = basic_file_sink<details::null_mutex>;\n\n} // namespace sinks\n\n//\n// factory functions\n//\ntemplate<typename Factory = spdlog::synchronous_factory>\ninline std::shared_ptr<logger> basic_logger_mt(const std::string &logger_name, const filename_t &filename, bool truncate = false)\n{\n    return Factory::template create<sinks::basic_file_sink_mt>(logger_name, filename, truncate);\n}\n\ntemplate<typename Factory = spdlog::synchronous_factory>\ninline std::shared_ptr<logger> basic_logger_st(const std::string &logger_name, const filename_t &filename, bool truncate = false)\n{\n    return Factory::template create<sinks::basic_file_sink_st>(logger_name, filename, truncate);\n}\n\n} // namespace spdlog\n\n#ifdef SPDLOG_HEADER_ONLY\n#include \"basic_file_sink-inl.h\"\n#endif"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/sinks/daily_file_sink.h",
    "content": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n#pragma once\n\n#include \"spdlog/details/file_helper.h\"\n#include \"spdlog/details/null_mutex.h\"\n#include \"spdlog/fmt/fmt.h\"\n#include \"spdlog/sinks/base_sink.h\"\n#include \"spdlog/details/os.h\"\n#include \"spdlog/details/synchronous_factory.h\"\n\n#include <chrono>\n#include <cstdio>\n#include <ctime>\n#include <mutex>\n#include <string>\n\nnamespace spdlog {\nnamespace sinks {\n\n/*\n * Generator of daily log file names in format basename.YYYY-MM-DD.ext\n */\nstruct daily_filename_calculator\n{\n    // Create filename for the form basename.YYYY-MM-DD\n    static filename_t calc_filename(const filename_t &filename, const tm &now_tm)\n    {\n        filename_t basename, ext;\n        std::tie(basename, ext) = details::file_helper::split_by_extension(filename);\n        std::conditional<std::is_same<filename_t::value_type, char>::value, fmt::memory_buffer, fmt::wmemory_buffer>::type w;\n        fmt::format_to(\n            w, SPDLOG_FILENAME_T(\"{}_{:04d}-{:02d}-{:02d}{}\"), basename, now_tm.tm_year + 1900, now_tm.tm_mon + 1, now_tm.tm_mday, ext);\n        return fmt::to_string(w);\n    }\n};\n\n/*\n * Rotating file sink based on date. rotates at midnight\n */\ntemplate<typename Mutex, typename FileNameCalc = daily_filename_calculator>\nclass daily_file_sink final : public base_sink<Mutex>\n{\npublic:\n    // create daily file sink which rotates on given time\n    daily_file_sink(filename_t base_filename, int rotation_hour, int rotation_minute, bool truncate = false)\n        : base_filename_(std::move(base_filename))\n        , rotation_h_(rotation_hour)\n        , rotation_m_(rotation_minute)\n        , truncate_(truncate)\n    {\n        if (rotation_hour < 0 || rotation_hour > 23 || rotation_minute < 0 || rotation_minute > 59)\n        {\n            throw spdlog_ex(\"daily_file_sink: Invalid rotation time in ctor\");\n        }\n        auto now = log_clock::now();\n        file_helper_.open(FileNameCalc::calc_filename(base_filename_, now_tm(now)), truncate_);\n        rotation_tp_ = next_rotation_tp_();\n    }\n\n    const filename_t &filename() const\n    {\n        return file_helper_.filename();\n    }\n\nprotected:\n    void sink_it_(const details::log_msg &msg) override\n    {\n#ifdef SPDLOG_NO_DATETIME\n        auto time = log_clock::now();\n#else\n        auto time = msg.time;\n#endif\n        if (time >= rotation_tp_)\n        {\n            file_helper_.open(FileNameCalc::calc_filename(base_filename_, now_tm(time)), truncate_);\n            rotation_tp_ = next_rotation_tp_();\n        }\n        fmt::memory_buffer formatted;\n        base_sink<Mutex>::formatter_->format(msg, formatted);\n        file_helper_.write(formatted);\n    }\n\n    void flush_() override\n    {\n        file_helper_.flush();\n    }\n\nprivate:\n    tm now_tm(log_clock::time_point tp)\n    {\n        time_t tnow = log_clock::to_time_t(tp);\n        return spdlog::details::os::localtime(tnow);\n    }\n\n    log_clock::time_point next_rotation_tp_()\n    {\n        auto now = log_clock::now();\n        tm date = now_tm(now);\n        date.tm_hour = rotation_h_;\n        date.tm_min = rotation_m_;\n        date.tm_sec = 0;\n        auto rotation_time = log_clock::from_time_t(std::mktime(&date));\n        if (rotation_time > now)\n        {\n            return rotation_time;\n        }\n        return {rotation_time + std::chrono::hours(24)};\n    }\n\n    filename_t base_filename_;\n    int rotation_h_;\n    int rotation_m_;\n    log_clock::time_point rotation_tp_;\n    details::file_helper file_helper_;\n    bool truncate_;\n};\n\nusing daily_file_sink_mt = daily_file_sink<std::mutex>;\nusing daily_file_sink_st = daily_file_sink<details::null_mutex>;\n\n} // namespace sinks\n\n//\n// factory functions\n//\ntemplate<typename Factory = spdlog::synchronous_factory>\ninline std::shared_ptr<logger> daily_logger_mt(\n    const std::string &logger_name, const filename_t &filename, int hour = 0, int minute = 0, bool truncate = false)\n{\n    return Factory::template create<sinks::daily_file_sink_mt>(logger_name, filename, hour, minute, truncate);\n}\n\ntemplate<typename Factory = spdlog::synchronous_factory>\ninline std::shared_ptr<logger> daily_logger_st(\n    const std::string &logger_name, const filename_t &filename, int hour = 0, int minute = 0, bool truncate = false)\n{\n    return Factory::template create<sinks::daily_file_sink_st>(logger_name, filename, hour, minute, truncate);\n}\n} // namespace spdlog\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/sinks/dist_sink.h",
    "content": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n#pragma once\n\n#include \"base_sink.h\"\n#include \"spdlog/details/log_msg.h\"\n#include \"spdlog/details/null_mutex.h\"\n#include \"spdlog/details/pattern_formatter.h\"\n\n#include <algorithm>\n#include <memory>\n#include <mutex>\n#include <vector>\n\n// Distribution sink (mux). Stores a vector of sinks which get called when log\n// is called\n\nnamespace spdlog {\nnamespace sinks {\n\ntemplate<typename Mutex>\nclass dist_sink : public base_sink<Mutex>\n{\npublic:\n    dist_sink() = default;\n    dist_sink(const dist_sink &) = delete;\n    dist_sink &operator=(const dist_sink &) = delete;\n\n    void add_sink(std::shared_ptr<sink> sink)\n    {\n        std::lock_guard<Mutex> lock(base_sink<Mutex>::mutex_);\n        sinks_.push_back(sink);\n    }\n\n    void remove_sink(std::shared_ptr<sink> sink)\n    {\n        std::lock_guard<Mutex> lock(base_sink<Mutex>::mutex_);\n        sinks_.erase(std::remove(sinks_.begin(), sinks_.end(), sink), sinks_.end());\n    }\n\n    void set_sinks(std::vector<std::shared_ptr<sink>> sinks)\n    {\n        std::lock_guard<Mutex> lock(base_sink<Mutex>::mutex_);\n        sinks_ = std::move(sinks);\n    }\n\nprotected:\n    void sink_it_(const details::log_msg &msg) override\n    {\n        for (auto &sink : sinks_)\n        {\n            if (sink->should_log(msg.level))\n            {\n                sink->log(msg);\n            }\n        }\n    }\n\n    void flush_() override\n    {\n        for (auto &sink : sinks_)\n        {\n            sink->flush();\n        }\n    }\n\n    void set_pattern_(const std::string &pattern) override\n    {\n        set_formatter_(details::make_unique<spdlog::pattern_formatter>(pattern));\n    }\n\n    void set_formatter_(std::unique_ptr<spdlog::formatter> sink_formatter) override\n    {\n        base_sink<Mutex>::formatter_ = std::move(sink_formatter);\n        for (auto &sink : sinks_)\n        {\n            sink->set_formatter(base_sink<Mutex>::formatter_->clone());\n        }\n    }\n    std::vector<std::shared_ptr<sink>> sinks_;\n};\n\nusing dist_sink_mt = dist_sink<std::mutex>;\nusing dist_sink_st = dist_sink<details::null_mutex>;\n\n} // namespace sinks\n} // namespace spdlog\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/sinks/dup_filter_sink.h",
    "content": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n#pragma once\n\n#include \"dist_sink.h\"\n#include \"spdlog/details/null_mutex.h\"\n#include \"spdlog/details/log_msg.h\"\n\n#include <mutex>\n#include <string>\n#include <chrono>\n\n// Duplicate message removal sink.\n// Skip the message if previous one is identical and less than \"max_skip_duration\" have passed\n//\n// Example:\n//\n//     #include \"spdlog/sinks/dup_filter_sink.h\"\n//\n//     int main() {\n//         auto dup_filter = std::make_shared<dup_filter_sink_st>(std::chrono::seconds(5));\n//         dup_filter->add_sink(std::make_shared<stdout_color_sink_mt>());\n//         spdlog::logger l(\"logger\", dup_filter);\n//         l.info(\"Hello\");\n//         l.info(\"Hello\");\n//         l.info(\"Hello\");\n//         l.info(\"Different Hello\");\n//     }\n//\n// Will produce:\n//       [2019-06-25 17:50:56.511] [logger] [info] Hello\n//       [2019-06-25 17:50:56.512] [logger] [info] Skipped 3 duplicate messages..\n//       [2019-06-25 17:50:56.512] [logger] [info] Different Hello\n\n#ifdef SPDLOG_NO_DATETIME\n#error \"spdlog::sinks::dup_filter_sink: cannot work when SPDLOG_NO_DATETIME is defined\"\n#endif\n\nnamespace spdlog {\nnamespace sinks {\ntemplate<typename Mutex>\nclass dup_filter_sink : public dist_sink<Mutex>\n{\npublic:\n    template<class Rep, class Period>\n    explicit dup_filter_sink(std::chrono::duration<Rep, Period> max_skip_duration)\n        : max_skip_duration_{max_skip_duration}\n    {}\n\nprotected:\n    std::chrono::microseconds max_skip_duration_;\n    log_clock::time_point last_msg_time_;\n    std::string last_msg_payload_;\n    size_t skip_counter_ = 0;\n\n    void sink_it_(const details::log_msg &msg) override\n    {\n        bool filtered = filter_(msg);\n        if (!filtered)\n        {\n            skip_counter_ += 1;\n            return;\n        }\n\n        // log the \"skipped..\" message\n        if (skip_counter_ > 0)\n        {\n            fmt::basic_memory_buffer<char, 64> buf;\n            fmt::format_to(buf, \"Skipped {} duplicate messages..\", skip_counter_);\n            details::log_msg skipped_msg{msg.logger_name, msg.level, string_view_t{buf.data(), buf.size()}};\n            dist_sink<Mutex>::sink_it_(skipped_msg);\n        }\n\n        // log current message\n        dist_sink<Mutex>::sink_it_(msg);\n        last_msg_time_ = msg.time;\n        skip_counter_ = 0;\n        last_msg_payload_.assign(msg.payload.data(), msg.payload.data() + msg.payload.size());\n    }\n\n    // return whether the log msg should be displayed (true) or skipped (false)\n    bool filter_(const details::log_msg &msg)\n    {\n        auto filter_duration = msg.time - last_msg_time_;\n        return (filter_duration > max_skip_duration_) || (msg.payload != last_msg_payload_);\n    }\n};\n\nusing dup_filter_sink_mt = dup_filter_sink<std::mutex>;\nusing dup_filter_sink_st = dup_filter_sink<details::null_mutex>;\n\n} // namespace sinks\n} // namespace spdlog\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/sinks/msvc_sink.h",
    "content": "// Copyright(c) 2016 Alexander Dalshov.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n#pragma once\n\n#if defined(_WIN32)\n\n#include \"spdlog/details/null_mutex.h\"\n#include \"spdlog/sinks/base_sink.h\"\n\n#include <winbase.h>\n\n#include <mutex>\n#include <string>\n\nnamespace spdlog {\nnamespace sinks {\n/*\n * MSVC sink (logging using OutputDebugStringA)\n */\ntemplate<typename Mutex>\nclass msvc_sink : public base_sink<Mutex>\n{\npublic:\n    explicit msvc_sink() {}\n\nprotected:\n    void sink_it_(const details::log_msg &msg) override\n    {\n\n        fmt::memory_buffer formatted;\n        base_sink<Mutex>::formatter_->format(msg, formatted);\n        OutputDebugStringA(fmt::to_string(formatted).c_str());\n    }\n\n    void flush_() override {}\n};\n\nusing msvc_sink_mt = msvc_sink<std::mutex>;\nusing msvc_sink_st = msvc_sink<details::null_mutex>;\n\nusing windebug_sink_mt = msvc_sink_mt;\nusing windebug_sink_st = msvc_sink_st;\n\n} // namespace sinks\n} // namespace spdlog\n\n#endif\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/sinks/null_sink.h",
    "content": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n#pragma once\n\n#include \"spdlog/details/null_mutex.h\"\n#include \"spdlog/sinks/base_sink.h\"\n#include \"spdlog/details/synchronous_factory.h\"\n\n#include <mutex>\n\nnamespace spdlog {\nnamespace sinks {\n\ntemplate<typename Mutex>\nclass null_sink : public base_sink<Mutex>\n{\nprotected:\n    void sink_it_(const details::log_msg &) override {}\n    void flush_() override {}\n};\n\nusing null_sink_mt = null_sink<details::null_mutex>;\nusing null_sink_st = null_sink<details::null_mutex>;\n\n} // namespace sinks\n\ntemplate<typename Factory = spdlog::synchronous_factory>\ninline std::shared_ptr<logger> null_logger_mt(const std::string &logger_name)\n{\n    auto null_logger = Factory::template create<sinks::null_sink_mt>(logger_name);\n    null_logger->set_level(level::off);\n    return null_logger;\n}\n\ntemplate<typename Factory = spdlog::synchronous_factory>\ninline std::shared_ptr<logger> null_logger_st(const std::string &logger_name)\n{\n    auto null_logger = Factory::template create<sinks::null_sink_st>(logger_name);\n    null_logger->set_level(level::off);\n    return null_logger;\n}\n\n} // namespace spdlog\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/sinks/ostream_sink.h",
    "content": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n#pragma once\n\n#include \"spdlog/details/null_mutex.h\"\n#include \"spdlog/sinks/base_sink.h\"\n\n#include <mutex>\n#include <ostream>\n\nnamespace spdlog {\nnamespace sinks {\ntemplate<typename Mutex>\nclass ostream_sink final : public base_sink<Mutex>\n{\npublic:\n    explicit ostream_sink(std::ostream &os, bool force_flush = false)\n        : ostream_(os)\n        , force_flush_(force_flush)\n    {}\n    ostream_sink(const ostream_sink &) = delete;\n    ostream_sink &operator=(const ostream_sink &) = delete;\n\nprotected:\n    void sink_it_(const details::log_msg &msg) override\n    {\n        fmt::memory_buffer formatted;\n        base_sink<Mutex>::formatter_->format(msg, formatted);\n        ostream_.write(formatted.data(), static_cast<std::streamsize>(formatted.size()));\n        if (force_flush_)\n        {\n            ostream_.flush();\n        }\n    }\n\n    void flush_() override\n    {\n        ostream_.flush();\n    }\n\n    std::ostream &ostream_;\n    bool force_flush_;\n};\n\nusing ostream_sink_mt = ostream_sink<std::mutex>;\nusing ostream_sink_st = ostream_sink<details::null_mutex>;\n\n} // namespace sinks\n} // namespace spdlog\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/sinks/rotating_file_sink-inl.h",
    "content": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n#pragma once\n\n#ifndef SPDLOG_HEADER_ONLY\n#include \"spdlog/sinks/rotating_file_sink.h\"\n#endif\n\n#include \"spdlog/common.h\"\n\n#include \"spdlog/details/file_helper.h\"\n#include \"spdlog/details/null_mutex.h\"\n#include \"spdlog/fmt/fmt.h\"\n\n#include <cerrno>\n#include <chrono>\n#include <ctime>\n#include <mutex>\n#include <string>\n#include <tuple>\n\nnamespace spdlog {\nnamespace sinks {\n\ntemplate<typename Mutex>\nSPDLOG_INLINE rotating_file_sink<Mutex>::rotating_file_sink(\n    filename_t base_filename, std::size_t max_size, std::size_t max_files, bool rotate_on_open)\n    : base_filename_(std::move(base_filename))\n    , max_size_(max_size)\n    , max_files_(max_files)\n{\n    file_helper_.open(calc_filename(base_filename_, 0));\n    current_size_ = file_helper_.size(); // expensive. called only once\n    if (rotate_on_open && current_size_ > 0)\n    {\n        rotate_();\n    }\n}\n\n// calc filename according to index and file extension if exists.\n// e.g. calc_filename(\"logs/mylog.txt, 3) => \"logs/mylog.3.txt\".\ntemplate<typename Mutex>\nSPDLOG_INLINE filename_t rotating_file_sink<Mutex>::calc_filename(const filename_t &filename, std::size_t index)\n{\n    typename std::conditional<std::is_same<filename_t::value_type, char>::value, fmt::memory_buffer, fmt::wmemory_buffer>::type w;\n    if (index != 0u)\n    {\n        filename_t basename, ext;\n        std::tie(basename, ext) = details::file_helper::split_by_extension(filename);\n        fmt::format_to(w, SPDLOG_FILENAME_T(\"{}.{}{}\"), basename, index, ext);\n    }\n    else\n    {\n        fmt::format_to(w, SPDLOG_FILENAME_T(\"{}\"), filename);\n    }\n    return fmt::to_string(w);\n}\n\ntemplate<typename Mutex>\nSPDLOG_INLINE const filename_t &rotating_file_sink<Mutex>::filename() const\n{\n    return file_helper_.filename();\n}\n\ntemplate<typename Mutex>\nSPDLOG_INLINE void rotating_file_sink<Mutex>::sink_it_(const details::log_msg &msg)\n{\n    fmt::memory_buffer formatted;\n    base_sink<Mutex>::formatter_->format(msg, formatted);\n    current_size_ += formatted.size();\n    if (current_size_ > max_size_)\n    {\n        rotate_();\n        current_size_ = formatted.size();\n    }\n    file_helper_.write(formatted);\n}\n\ntemplate<typename Mutex>\nSPDLOG_INLINE void rotating_file_sink<Mutex>::flush_()\n{\n    file_helper_.flush();\n}\n\n// Rotate files:\n// log.txt -> log.1.txt\n// log.1.txt -> log.2.txt\n// log.2.txt -> log.3.txt\n// log.3.txt -> delete\ntemplate<typename Mutex>\nSPDLOG_INLINE void rotating_file_sink<Mutex>::rotate_()\n{\n    using details::os::filename_to_str;\n    file_helper_.close();\n    for (auto i = max_files_; i > 0; --i)\n    {\n        filename_t src = calc_filename(base_filename_, i - 1);\n        if (!details::file_helper::file_exists(src))\n        {\n            continue;\n        }\n        filename_t target = calc_filename(base_filename_, i);\n\n        if (!rename_file(src, target))\n        {\n            // if failed try again after a small delay.\n            // this is a workaround to a windows issue, where very high rotation\n            // rates can cause the rename to fail with permission denied (because of antivirus?).\n            details::os::sleep_for_millis(100);\n            if (!rename_file(src, target))\n            {\n                file_helper_.reopen(true); // truncate the log file anyway to prevent it to grow beyond its limit!\n                current_size_ = 0;\n                throw spdlog_ex(\"rotating_file_sink: failed renaming \" + filename_to_str(src) + \" to \" + filename_to_str(target), errno);\n            }\n        }\n    }\n    file_helper_.reopen(true);\n}\n\n// delete the target if exists, and rename the src file  to target\n// return true on success, false otherwise.\ntemplate<typename Mutex>\nSPDLOG_INLINE bool rotating_file_sink<Mutex>::rename_file(const filename_t &src_filename, const filename_t &target_filename)\n{\n    // try to delete the target file in case it already exists.\n    (void)details::os::remove(target_filename);\n    return details::os::rename(src_filename, target_filename) == 0;\n}\n\n} // namespace sinks\n} // namespace spdlog\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/sinks/rotating_file_sink.h",
    "content": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n#pragma once\n\n#include \"spdlog/sinks/base_sink.h\"\n#include \"spdlog/details/file_helper.h\"\n#include \"spdlog/details/null_mutex.h\"\n#include \"spdlog/details/synchronous_factory.h\"\n\n#include <chrono>\n#include <mutex>\n#include <string>\n\nnamespace spdlog {\nnamespace sinks {\n\n//\n// Rotating file sink based on size\n//\ntemplate<typename Mutex>\nclass rotating_file_sink final : public base_sink<Mutex>\n{\npublic:\n    rotating_file_sink(filename_t base_filename, std::size_t max_size, std::size_t max_files, bool rotate_on_open = false);\n    static filename_t calc_filename(const filename_t &filename, std::size_t index);\n    const filename_t &filename() const;\n\nprotected:\n    void sink_it_(const details::log_msg &msg) override;\n    void flush_() override;\n\nprivate:\n    // Rotate files:\n    // log.txt -> log.1.txt\n    // log.1.txt -> log.2.txt\n    // log.2.txt -> log.3.txt\n    // log.3.txt -> delete\n    void rotate_();\n\n    // delete the target if exists, and rename the src file  to target\n    // return true on success, false otherwise.\n    bool rename_file(const filename_t &src_filename, const filename_t &target_filename);\n\n    filename_t base_filename_;\n    std::size_t max_size_;\n    std::size_t max_files_;\n    std::size_t current_size_;\n    details::file_helper file_helper_;\n};\n\nusing rotating_file_sink_mt = rotating_file_sink<std::mutex>;\nusing rotating_file_sink_st = rotating_file_sink<details::null_mutex>;\n\n} // namespace sinks\n\n//\n// factory functions\n//\n\ntemplate<typename Factory = spdlog::synchronous_factory>\ninline std::shared_ptr<logger> rotating_logger_mt(\n    const std::string &logger_name, const filename_t &filename, size_t max_file_size, size_t max_files, bool rotate_on_open = false)\n{\n    return Factory::template create<sinks::rotating_file_sink_mt>(logger_name, filename, max_file_size, max_files, rotate_on_open);\n}\n\ntemplate<typename Factory = spdlog::synchronous_factory>\ninline std::shared_ptr<logger> rotating_logger_st(\n    const std::string &logger_name, const filename_t &filename, size_t max_file_size, size_t max_files, bool rotate_on_open = false)\n{\n    return Factory::template create<sinks::rotating_file_sink_st>(logger_name, filename, max_file_size, max_files, rotate_on_open);\n}\n} // namespace spdlog\n\n#ifdef SPDLOG_HEADER_ONLY\n#include \"rotating_file_sink-inl.h\"\n#endif"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/sinks/sink-inl.h",
    "content": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n#pragma once\n\n#ifndef SPDLOG_HEADER_ONLY\n#include \"spdlog/sinks/sink.h\"\n#endif\n\n#include \"spdlog/common.h\"\n\nSPDLOG_INLINE bool spdlog::sinks::sink::should_log(spdlog::level::level_enum msg_level) const\n{\n    return msg_level >= level_.load(std::memory_order_relaxed);\n}\n\nSPDLOG_INLINE void spdlog::sinks::sink::set_level(level::level_enum log_level)\n{\n    level_.store(log_level, std::memory_order_relaxed);\n}\n\nSPDLOG_INLINE spdlog::level::level_enum spdlog::sinks::sink::level() const\n{\n    return static_cast<spdlog::level::level_enum>(level_.load(std::memory_order_relaxed));\n}\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/sinks/sink.h",
    "content": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n#pragma once\n\n#include \"spdlog/details/log_msg.h\"\n#include \"spdlog/formatter.h\"\n\nnamespace spdlog {\n\nnamespace sinks {\nclass sink\n{\npublic:\n    virtual ~sink() = default;\n    virtual void log(const details::log_msg &msg) = 0;\n    virtual void flush() = 0;\n    virtual void set_pattern(const std::string &pattern) = 0;\n    virtual void set_formatter(std::unique_ptr<spdlog::formatter> sink_formatter) = 0;\n\n    void set_level(level::level_enum log_level);\n    level::level_enum level() const;\n    bool should_log(level::level_enum msg_level) const;\n\nprotected:\n    // sink log level - default is all\n    level_t level_{level::trace};\n};\n\n} // namespace sinks\n} // namespace spdlog\n\n#ifdef SPDLOG_HEADER_ONLY\n#include \"sink-inl.h\"\n#endif\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/sinks/stdout_color_sinks-inl.h",
    "content": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n#pragma once\n\n#ifndef SPDLOG_HEADER_ONLY\n#include \"spdlog/sinks/stdout_color_sinks.h\"\n#endif\n\n#include \"spdlog/logger.h\"\n#include \"spdlog/common.h\"\n\nnamespace spdlog {\n\ntemplate<typename Factory>\nSPDLOG_INLINE std::shared_ptr<logger> stdout_color_mt(const std::string &logger_name, color_mode mode)\n{\n    return Factory::template create<sinks::stdout_color_sink_mt>(logger_name, mode);\n}\n\ntemplate<typename Factory>\nSPDLOG_INLINE std::shared_ptr<logger> stdout_color_st(const std::string &logger_name, color_mode mode)\n{\n    return Factory::template create<sinks::stdout_color_sink_st>(logger_name, mode);\n}\n\ntemplate<typename Factory>\nSPDLOG_INLINE std::shared_ptr<logger> stderr_color_mt(const std::string &logger_name, color_mode mode)\n{\n    return Factory::template create<sinks::stderr_color_sink_mt>(logger_name, mode);\n}\n\ntemplate<typename Factory>\nSPDLOG_INLINE std::shared_ptr<logger> stderr_color_st(const std::string &logger_name, color_mode mode)\n{\n    return Factory::template create<sinks::stderr_color_sink_st>(logger_name, mode);\n}\n} // namespace spdlog"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/sinks/stdout_color_sinks.h",
    "content": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n#pragma once\n\n#ifdef _WIN32\n#include \"spdlog/sinks/wincolor_sink.h\"\n#else\n#include \"spdlog/sinks/ansicolor_sink.h\"\n#endif\n\n#include \"spdlog/details/synchronous_factory.h\"\n\nnamespace spdlog {\nnamespace sinks {\n#ifdef _WIN32\nusing stdout_color_sink_mt = wincolor_stdout_sink_mt;\nusing stdout_color_sink_st = wincolor_stdout_sink_st;\nusing stderr_color_sink_mt = wincolor_stderr_sink_mt;\nusing stderr_color_sink_st = wincolor_stderr_sink_st;\n#else\nusing stdout_color_sink_mt = ansicolor_stdout_sink_mt;\nusing stdout_color_sink_st = ansicolor_stdout_sink_st;\nusing stderr_color_sink_mt = ansicolor_stderr_sink_mt;\nusing stderr_color_sink_st = ansicolor_stderr_sink_st;\n#endif\n} // namespace sinks\n\ntemplate<typename Factory = spdlog::synchronous_factory>\nstd::shared_ptr<logger> stdout_color_mt(const std::string &logger_name, color_mode mode = color_mode::automatic);\n\ntemplate<typename Factory = spdlog::synchronous_factory>\nstd::shared_ptr<logger> stdout_color_st(const std::string &logger_name, color_mode mode = color_mode::automatic);\n\ntemplate<typename Factory = spdlog::synchronous_factory>\nstd::shared_ptr<logger> stderr_color_mt(const std::string &logger_name, color_mode mode = color_mode::automatic);\n\ntemplate<typename Factory = spdlog::synchronous_factory>\nstd::shared_ptr<logger> stderr_color_st(const std::string &logger_name, color_mode mode = color_mode::automatic);\n\n} // namespace spdlog\n\n#ifdef SPDLOG_HEADER_ONLY\n#include \"stdout_color_sinks-inl.h\"\n#endif\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/sinks/stdout_sinks-inl.h",
    "content": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n#pragma once\n\n#ifndef SPDLOG_HEADER_ONLY\n#include \"spdlog/sinks/stdout_sinks.h\"\n#endif\n\n#include \"spdlog/details/console_globals.h\"\n#include \"spdlog/details/pattern_formatter.h\"\n#include <memory>\n\nnamespace spdlog {\n\nnamespace sinks {\n\ntemplate<typename ConsoleMutex>\nSPDLOG_INLINE stdout_sink_base<ConsoleMutex>::stdout_sink_base(FILE *file)\n    : mutex_(ConsoleMutex::mutex())\n    , file_(file)\n    , formatter_(details::make_unique<spdlog::pattern_formatter>())\n{}\n\ntemplate<typename ConsoleMutex>\nSPDLOG_INLINE void stdout_sink_base<ConsoleMutex>::log(const details::log_msg &msg)\n{\n    std::lock_guard<mutex_t> lock(mutex_);\n    fmt::memory_buffer formatted;\n    formatter_->format(msg, formatted);\n    fwrite(formatted.data(), sizeof(char), formatted.size(), file_);\n    fflush(file_); // flush every line to terminal\n}\n\ntemplate<typename ConsoleMutex>\nSPDLOG_INLINE void stdout_sink_base<ConsoleMutex>::flush()\n{\n    std::lock_guard<mutex_t> lock(mutex_);\n    fflush(file_);\n}\n\ntemplate<typename ConsoleMutex>\nSPDLOG_INLINE void stdout_sink_base<ConsoleMutex>::set_pattern(const std::string &pattern)\n{\n    std::lock_guard<mutex_t> lock(mutex_);\n    formatter_ = std::unique_ptr<spdlog::formatter>(new pattern_formatter(pattern));\n}\n\ntemplate<typename ConsoleMutex>\nSPDLOG_INLINE void stdout_sink_base<ConsoleMutex>::set_formatter(std::unique_ptr<spdlog::formatter> sink_formatter)\n{\n    std::lock_guard<mutex_t> lock(mutex_);\n    formatter_ = std::move(sink_formatter);\n}\n\n// stdout sink\ntemplate<typename ConsoleMutex>\nSPDLOG_INLINE stdout_sink<ConsoleMutex>::stdout_sink()\n    : stdout_sink_base<ConsoleMutex>(stdout)\n{}\n\n// stderr sink\ntemplate<typename ConsoleMutex>\nSPDLOG_INLINE stderr_sink<ConsoleMutex>::stderr_sink()\n    : stdout_sink_base<ConsoleMutex>(stderr)\n{}\n\n} // namespace sinks\n\n// factory methods\ntemplate<typename Factory>\nSPDLOG_INLINE std::shared_ptr<logger> stdout_logger_mt(const std::string &logger_name)\n{\n    return Factory::template create<sinks::stdout_sink_mt>(logger_name);\n}\n\ntemplate<typename Factory>\nSPDLOG_INLINE std::shared_ptr<logger> stdout_logger_st(const std::string &logger_name)\n{\n    return Factory::template create<sinks::stdout_sink_st>(logger_name);\n}\n\ntemplate<typename Factory>\nSPDLOG_INLINE std::shared_ptr<logger> stderr_logger_mt(const std::string &logger_name)\n{\n    return Factory::template create<sinks::stderr_sink_mt>(logger_name);\n}\n\ntemplate<typename Factory>\nSPDLOG_INLINE std::shared_ptr<logger> stderr_logger_st(const std::string &logger_name)\n{\n    return Factory::template create<sinks::stderr_sink_st>(logger_name);\n}\n} // namespace spdlog\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/sinks/stdout_sinks.h",
    "content": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n#pragma once\n\n#include \"spdlog/details/console_globals.h\"\n#include \"spdlog/details/synchronous_factory.h\"\n#include \"spdlog/sinks/sink.h\"\n#include <cstdio>\n\nnamespace spdlog {\n\nnamespace sinks {\n\ntemplate<typename ConsoleMutex>\nclass stdout_sink_base : public sink\n{\npublic:\n    using mutex_t = typename ConsoleMutex::mutex_t;\n    explicit stdout_sink_base(FILE *file);\n    ~stdout_sink_base() override = default;\n    stdout_sink_base(const stdout_sink_base &other) = delete;\n    stdout_sink_base &operator=(const stdout_sink_base &other) = delete;\n\n    void log(const details::log_msg &msg) override;\n    void flush() override;\n    void set_pattern(const std::string &pattern) override;\n\n    void set_formatter(std::unique_ptr<spdlog::formatter> sink_formatter) override;\n\nprotected:\n    mutex_t &mutex_;\n    FILE *file_;\n    std::unique_ptr<spdlog::formatter> formatter_;\n};\n\ntemplate<typename ConsoleMutex>\nclass stdout_sink : public stdout_sink_base<ConsoleMutex>\n{\npublic:\n    stdout_sink();\n};\n\ntemplate<typename ConsoleMutex>\nclass stderr_sink : public stdout_sink_base<ConsoleMutex>\n{\npublic:\n    stderr_sink();\n};\n\nusing stdout_sink_mt = stdout_sink<details::console_mutex>;\nusing stdout_sink_st = stdout_sink<details::console_nullmutex>;\n\nusing stderr_sink_mt = stderr_sink<details::console_mutex>;\nusing stderr_sink_st = stderr_sink<details::console_nullmutex>;\n\n} // namespace sinks\n\n// factory methods\ntemplate<typename Factory = spdlog::synchronous_factory>\nstd::shared_ptr<logger> stdout_logger_mt(const std::string &logger_name);\n\ntemplate<typename Factory = spdlog::synchronous_factory>\nstd::shared_ptr<logger> stdout_logger_st(const std::string &logger_name);\n\ntemplate<typename Factory = spdlog::synchronous_factory>\nstd::shared_ptr<logger> stderr_logger_mt(const std::string &logger_name);\n\ntemplate<typename Factory = spdlog::synchronous_factory>\nstd::shared_ptr<logger> stderr_logger_st(const std::string &logger_name);\n\n} // namespace spdlog\n\n#ifdef SPDLOG_HEADER_ONLY\n#include \"stdout_sinks-inl.h\"\n#endif\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/sinks/syslog_sink.h",
    "content": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n#pragma once\n\n#include \"spdlog/sinks/base_sink.h\"\n#include \"spdlog/details/null_mutex.h\"\n\n#include <array>\n#include <string>\n#include <syslog.h>\n\nnamespace spdlog {\nnamespace sinks {\n/**\n * Sink that write to syslog using the `syscall()` library call.\n */\ntemplate<typename Mutex>\nclass syslog_sink : public base_sink<Mutex>\n{\n\npublic:\n    syslog_sink(std::string ident, int syslog_option, int syslog_facility, bool enable_formatting)\n        : enable_formatting_{enable_formatting}\n        , syslog_levels_{/* spdlog::level::trace      */ LOG_DEBUG,\n              /* spdlog::level::debug      */ LOG_DEBUG,\n              /* spdlog::level::info       */ LOG_INFO,\n              /* spdlog::level::warn       */ LOG_WARNING,\n              /* spdlog::level::err        */ LOG_ERR,\n              /* spdlog::level::critical   */ LOG_CRIT,\n              /* spdlog::level::off        */ LOG_INFO}\n        , ident_{std::move(ident)}\n    {\n        // set ident to be program name if empty\n        ::openlog(ident_.empty() ? nullptr : ident_.c_str(), syslog_option, syslog_facility);\n    }\n\n    ~syslog_sink() override\n    {\n        ::closelog();\n    }\n\n    syslog_sink(const syslog_sink &) = delete;\n    syslog_sink &operator=(const syslog_sink &) = delete;\n\nprotected:\n    void sink_it_(const details::log_msg &msg) override\n    {\n        string_view_t payload;\n\n        if (enable_formatting_)\n        {\n            fmt::memory_buffer formatted;\n            base_sink<Mutex>::formatter_->format(msg, formatted);\n            payload = string_view_t(formatted.data(), formatted.size());\n        }\n        else\n        {\n            payload = msg.payload;\n        }\n\n        size_t length = payload.size();\n        // limit to max int\n        if (length > static_cast<size_t>(std::numeric_limits<int>::max()))\n        {\n            length = static_cast<size_t>(std::numeric_limits<int>::max());\n        }\n\n        ::syslog(syslog_prio_from_level(msg), \"%.*s\", static_cast<int>(length), payload.data());\n    }\n\n    void flush_() override {}\n    bool enable_formatting_ = false;\n\nprivate:\n    std::array<int, 7> syslog_levels_;\n    // must store the ident because the man says openlog might use the pointer as\n    // is and not a string copy\n    const std::string ident_;\n\n    //\n    // Simply maps spdlog's log level to syslog priority level.\n    //\n    int syslog_prio_from_level(const details::log_msg &msg) const\n    {\n        return syslog_levels_.at(static_cast<int>(msg.level));\n    }\n};\n\nusing syslog_sink_mt = syslog_sink<std::mutex>;\nusing syslog_sink_st = syslog_sink<details::null_mutex>;\n} // namespace sinks\n\n// Create and register a syslog logger\ntemplate<typename Factory = default_factory>\ninline std::shared_ptr<logger> syslog_logger_mt(const std::string &logger_name, const std::string &syslog_ident = \"\", int syslog_option = 0,\n    int syslog_facility = LOG_USER, bool enable_formatting = false)\n{\n    return Factory::template create<sinks::syslog_sink_mt>(logger_name, syslog_ident, syslog_option, syslog_facility, enable_formatting);\n}\n\ntemplate<typename Factory = default_factory>\ninline std::shared_ptr<logger> syslog_logger_st(const std::string &logger_name, const std::string &syslog_ident = \"\", int syslog_option = 0,\n    int syslog_facility = LOG_USER, bool enable_formatting = false)\n{\n    return Factory::template create<sinks::syslog_sink_st>(logger_name, syslog_ident, syslog_option, syslog_facility, enable_formatting);\n}\n} // namespace spdlog\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/sinks/systemd_sink.h",
    "content": "// Copyright(c) 2019 ZVYAGIN.Alexander@gmail.com\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n#pragma once\n\n#include \"spdlog/sinks/base_sink.h\"\n#include \"spdlog/details/null_mutex.h\"\n#include \"spdlog/details/synchronous_factory.h\"\n\n#include <systemd/sd-journal.h>\n\nnamespace spdlog {\nnamespace sinks {\n\n/**\n * Sink that write to systemd journal using the `sd_journal_send()` library call.\n *\n * Locking is not needed, as `sd_journal_send()` itself is thread-safe.\n */\ntemplate<typename Mutex>\nclass systemd_sink : public base_sink<Mutex>\n{\npublic:\n    //\n    systemd_sink()\n        : syslog_levels_{/* spdlog::level::trace      */ LOG_DEBUG,\n              /* spdlog::level::debug      */ LOG_DEBUG,\n              /* spdlog::level::info       */ LOG_INFO,\n              /* spdlog::level::warn       */ LOG_WARNING,\n              /* spdlog::level::err        */ LOG_ERR,\n              /* spdlog::level::critical   */ LOG_CRIT,\n              /* spdlog::level::off        */ LOG_INFO}\n    {}\n\n    ~systemd_sink() override {}\n\n    systemd_sink(const systemd_sink &) = delete;\n    systemd_sink &operator=(const systemd_sink &) = delete;\n\nprotected:\n    std::array<int, 7> syslog_levels_;\n\n    void sink_it_(const details::log_msg &msg) override\n    {\n        int err;\n\n        size_t length = msg.payload.size();\n        // limit to max int\n        if (length > static_cast<size_t>(std::numeric_limits<int>::max()))\n        {\n            length = static_cast<size_t>(std::numeric_limits<int>::max());\n        }\n\n        // Do not send source location if not available\n        if (msg.source.empty())\n        {\n            // Note: function call inside '()' to avoid macro expansion\n            err = (sd_journal_send)(\n                \"MESSAGE=%.*s\", static_cast<int>(length), msg.payload.data(), \"PRIORITY=%d\", syslog_level(msg.level), nullptr);\n        }\n        else\n        {\n            err = (sd_journal_send)(\"MESSAGE=%.*s\", static_cast<int>(length), msg.payload.data(), \"PRIORITY=%d\", syslog_level(msg.level),\n                \"SOURCE_FILE=%s\", msg.source.filename, \"SOURCE_LINE=%d\", msg.source.line, \"SOURCE_FUNC=%s\", msg.source.funcname, nullptr);\n        }\n\n        if (err)\n        {\n            throw spdlog_ex(\"Failed writing to systemd\", errno);\n        }\n    }\n\n    int syslog_level(level::level_enum l)\n    {\n        return syslog_levels_.at(static_cast<int>(l));\n    }\n\n    void flush_() override {}\n};\n\nusing systemd_sink_mt = systemd_sink<std::mutex>;\nusing systemd_sink_st = systemd_sink<details::null_mutex>;\n} // namespace sinks\n\n// Create and register a syslog logger\ntemplate<typename Factory = spdlog::synchronous_factory>\ninline std::shared_ptr<logger> systemd_logger_mt(const std::string &logger_name)\n{\n    return Factory::template create<sinks::systemd_sink_mt>(logger_name);\n}\n\ntemplate<typename Factory = spdlog::synchronous_factory>\ninline std::shared_ptr<logger> systemd_logger_st(const std::string &logger_name)\n{\n    return Factory::template create<sinks::systemd_sink_st>(logger_name);\n}\n} // namespace spdlog\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/sinks/wincolor_sink-inl.h",
    "content": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n#pragma once\n\n#ifndef SPDLOG_HEADER_ONLY\n#include \"spdlog/sinks/wincolor_sink.h\"\n#endif\n\n#include \"spdlog/common.h\"\n#include \"spdlog/details/pattern_formatter.h\"\n\nnamespace spdlog {\nnamespace sinks {\n\ntemplate<typename ConsoleMutex>\nSPDLOG_INLINE wincolor_sink<ConsoleMutex>::wincolor_sink(HANDLE out_handle, color_mode mode)\n    : out_handle_(out_handle)\n    , mutex_(ConsoleMutex::mutex())\n    , formatter_(details::make_unique<spdlog::pattern_formatter>())\n{\n    // check if out_handle is points to the actual console.\n    // ::GetConsoleMode() should return 0 if it is redirected or not valid console handle.\n    DWORD console_mode;\n    in_console_ = ::GetConsoleMode(out_handle, &console_mode) != 0;\n\n    set_color_mode(mode);\n    colors_[level::trace] = WHITE;\n    colors_[level::debug] = CYAN;\n    colors_[level::info] = GREEN;\n    colors_[level::warn] = YELLOW | BOLD;\n    colors_[level::err] = RED | BOLD;                         // red bold\n    colors_[level::critical] = BACKGROUND_RED | WHITE | BOLD; // white bold on red background\n    colors_[level::off] = 0;\n}\n\ntemplate<typename ConsoleMutex>\nSPDLOG_INLINE wincolor_sink<ConsoleMutex>::~wincolor_sink()\n{\n    this->flush();\n}\n\n// change the color for the given level\ntemplate<typename ConsoleMutex>\nvoid SPDLOG_INLINE wincolor_sink<ConsoleMutex>::set_color(level::level_enum level, WORD color)\n{\n    std::lock_guard<mutex_t> lock(mutex_);\n    colors_[level] = color;\n}\n\ntemplate<typename ConsoleMutex>\nvoid SPDLOG_INLINE wincolor_sink<ConsoleMutex>::log(const details::log_msg &msg)\n{\n    std::lock_guard<mutex_t> lock(mutex_);\n    fmt::memory_buffer formatted;\n    formatter_->format(msg, formatted);\n    if (!in_console_)\n    {\n        write_to_file_(formatted);\n        return;\n    }\n\n    if (should_do_colors_ && msg.color_range_end > msg.color_range_start)\n    {\n        // before color range\n        print_range_(formatted, 0, msg.color_range_start);\n\n        // in color range\n        auto orig_attribs = set_foreground_color_(colors_[msg.level]);\n        print_range_(formatted, msg.color_range_start, msg.color_range_end);\n        // reset to orig colors\n        ::SetConsoleTextAttribute(out_handle_, orig_attribs);\n        print_range_(formatted, msg.color_range_end, formatted.size());\n    }\n    else // print without colors if color range is invalid (or color is disabled)\n    {\n        print_range_(formatted, 0, formatted.size());\n    }\n}\n\ntemplate<typename ConsoleMutex>\nvoid SPDLOG_INLINE wincolor_sink<ConsoleMutex>::flush()\n{\n    // windows console always flushed?\n}\n\ntemplate<typename ConsoleMutex>\nvoid SPDLOG_INLINE wincolor_sink<ConsoleMutex>::set_pattern(const std::string &pattern)\n{\n    std::lock_guard<mutex_t> lock(mutex_);\n    formatter_ = std::unique_ptr<spdlog::formatter>(new pattern_formatter(pattern));\n}\n\ntemplate<typename ConsoleMutex>\nvoid SPDLOG_INLINE wincolor_sink<ConsoleMutex>::set_formatter(std::unique_ptr<spdlog::formatter> sink_formatter)\n{\n    std::lock_guard<mutex_t> lock(mutex_);\n    formatter_ = std::move(sink_formatter);\n}\n\ntemplate<typename ConsoleMutex>\nvoid SPDLOG_INLINE wincolor_sink<ConsoleMutex>::set_color_mode(color_mode mode)\n{\n    switch (mode)\n    {\n    case color_mode::always:\n    case color_mode::automatic:\n        should_do_colors_ = true;\n        break;\n    case color_mode::never:\n        should_do_colors_ = false;\n        break;\n    default:\n        should_do_colors_ = true;\n    }\n}\n\n// set foreground color and return the orig console attributes (for resetting later)\ntemplate<typename ConsoleMutex>\nWORD SPDLOG_INLINE wincolor_sink<ConsoleMutex>::set_foreground_color_(WORD attribs)\n{\n    CONSOLE_SCREEN_BUFFER_INFO orig_buffer_info;\n    ::GetConsoleScreenBufferInfo(out_handle_, &orig_buffer_info);\n    WORD back_color = orig_buffer_info.wAttributes;\n    // retrieve the current background color\n    back_color &= static_cast<WORD>(~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY));\n    // keep the background color unchanged\n    ::SetConsoleTextAttribute(out_handle_, attribs | back_color);\n    return orig_buffer_info.wAttributes; // return orig attribs\n}\n\n// print a range of formatted message to console\ntemplate<typename ConsoleMutex>\nvoid SPDLOG_INLINE wincolor_sink<ConsoleMutex>::print_range_(const fmt::memory_buffer &formatted, size_t start, size_t end)\n{\n    auto size = static_cast<DWORD>(end - start);\n    ::WriteConsoleA(out_handle_, formatted.data() + start, size, nullptr, nullptr);\n}\n\ntemplate<typename ConsoleMutex>\nvoid SPDLOG_INLINE wincolor_sink<ConsoleMutex>::write_to_file_(const fmt::memory_buffer &formatted)\n{\n    auto size = static_cast<DWORD>(formatted.size());\n    if (size == 0)\n    {\n        return;\n    }\n\n    DWORD total_written = 0;\n    do\n    {\n        DWORD bytes_written = 0;\n        bool ok = ::WriteFile(out_handle_, formatted.data() + total_written, size - total_written, &bytes_written, nullptr) != 0;\n        if (!ok || bytes_written == 0)\n        {\n            throw spdlog_ex(\"wincolor_sink: write_to_file_ failed. GetLastError(): \" + std::to_string(::GetLastError()));\n        }\n        total_written += bytes_written;\n    } while (total_written < size);\n}\n\n// wincolor_stdout_sink\ntemplate<typename ConsoleMutex>\nSPDLOG_INLINE wincolor_stdout_sink<ConsoleMutex>::wincolor_stdout_sink(color_mode mode)\n    : wincolor_sink<ConsoleMutex>(::GetStdHandle(STD_OUTPUT_HANDLE), mode)\n{}\n\n// wincolor_stderr_sink\ntemplate<typename ConsoleMutex>\nSPDLOG_INLINE wincolor_stderr_sink<ConsoleMutex>::wincolor_stderr_sink(color_mode mode)\n    : wincolor_sink<ConsoleMutex>(::GetStdHandle(STD_ERROR_HANDLE), mode)\n{}\n\n} // namespace sinks\n} // namespace spdlog\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/sinks/wincolor_sink.h",
    "content": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n#pragma once\n\n#include \"spdlog/common.h\"\n#include \"spdlog/details/console_globals.h\"\n#include \"spdlog/details/null_mutex.h\"\n#include \"spdlog/sinks/sink.h\"\n\n#include <memory>\n#include <mutex>\n#include <string>\n#include <unordered_map>\n#include <wincon.h>\n\nnamespace spdlog {\nnamespace sinks {\n/*\n * Windows color console sink. Uses WriteConsoleA to write to the console with\n * colors\n */\ntemplate<typename ConsoleMutex>\nclass wincolor_sink : public sink\n{\npublic:\n    const WORD BOLD = FOREGROUND_INTENSITY;\n    const WORD RED = FOREGROUND_RED;\n    const WORD GREEN = FOREGROUND_GREEN;\n    const WORD CYAN = FOREGROUND_GREEN | FOREGROUND_BLUE;\n    const WORD WHITE = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;\n    const WORD YELLOW = FOREGROUND_RED | FOREGROUND_GREEN;\n\n    wincolor_sink(HANDLE out_handle, color_mode mode);\n    ~wincolor_sink() override;\n\n    wincolor_sink(const wincolor_sink &other) = delete;\n    wincolor_sink &operator=(const wincolor_sink &other) = delete;\n\n    // change the color for the given level\n    void set_color(level::level_enum level, WORD color);\n    void log(const details::log_msg &msg) final override;\n    void flush() final override;\n    void set_pattern(const std::string &pattern) override final;\n    void set_formatter(std::unique_ptr<spdlog::formatter> sink_formatter) override final;\n    void set_color_mode(color_mode mode);\n\nprotected:\n    using mutex_t = typename ConsoleMutex::mutex_t;\n    HANDLE out_handle_;\n    mutex_t &mutex_;\n    bool in_console_;\n    bool should_do_colors_;\n    std::unique_ptr<spdlog::formatter> formatter_;\n    std::unordered_map<level::level_enum, WORD, level::level_hasher> colors_;\n\n    // set foreground color and return the orig console attributes (for resetting later)\n    WORD set_foreground_color_(WORD attribs);\n\n    // print a range of formatted message to console\n    void print_range_(const fmt::memory_buffer &formatted, size_t start, size_t end);\n\n    // in case we are redirected to file (not in console mode)\n    void write_to_file_(const fmt::memory_buffer &formatted);\n};\n\ntemplate<typename ConsoleMutex>\nclass wincolor_stdout_sink : public wincolor_sink<ConsoleMutex>\n{\npublic:\n    explicit wincolor_stdout_sink(color_mode mode = color_mode::automatic);\n};\n\ntemplate<typename ConsoleMutex>\nclass wincolor_stderr_sink : public wincolor_sink<ConsoleMutex>\n{\npublic:\n    explicit wincolor_stderr_sink(color_mode mode = color_mode::automatic);\n};\n\nusing wincolor_stdout_sink_mt = wincolor_stdout_sink<details::console_mutex>;\nusing wincolor_stdout_sink_st = wincolor_stdout_sink<details::console_nullmutex>;\n\nusing wincolor_stderr_sink_mt = wincolor_stderr_sink<details::console_mutex>;\nusing wincolor_stderr_sink_st = wincolor_stderr_sink<details::console_nullmutex>;\n\n} // namespace sinks\n} // namespace spdlog\n\n#ifdef SPDLOG_HEADER_ONLY\n#include \"wincolor_sink-inl.h\"\n#endif\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/spdlog-inl.h",
    "content": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n#pragma once\n\n#ifndef SPDLOG_HEADER_ONLY\n#include \"spdlog/spdlog.h\"\n#endif\n\n#include \"spdlog/common.h\"\n#include \"spdlog/details/pattern_formatter.h\"\n\nnamespace spdlog {\n\nSPDLOG_INLINE void initialize_logger(std::shared_ptr<logger> logger)\n{\n    details::registry::instance().initialize_logger(std::move(logger));\n}\n\nSPDLOG_INLINE std::shared_ptr<logger> get(const std::string &name)\n{\n    return details::registry::instance().get(name);\n}\n\nSPDLOG_INLINE void set_formatter(std::unique_ptr<spdlog::formatter> formatter)\n{\n    details::registry::instance().set_formatter(std::move(formatter));\n}\n\nSPDLOG_INLINE void set_pattern(std::string pattern, pattern_time_type time_type)\n{\n    set_formatter(std::unique_ptr<spdlog::formatter>(new pattern_formatter(std::move(pattern), time_type)));\n}\n\nSPDLOG_INLINE void set_level(level::level_enum log_level)\n{\n    details::registry::instance().set_level(log_level);\n}\n\nSPDLOG_INLINE void flush_on(level::level_enum log_level)\n{\n    details::registry::instance().flush_on(log_level);\n}\n\nSPDLOG_INLINE void flush_every(std::chrono::seconds interval)\n{\n    details::registry::instance().flush_every(interval);\n}\n\nSPDLOG_INLINE void set_error_handler(void (*handler)(const std::string &msg))\n{\n    details::registry::instance().set_error_handler(handler);\n}\n\nSPDLOG_INLINE void register_logger(std::shared_ptr<logger> logger)\n{\n    details::registry::instance().register_logger(std::move(logger));\n}\n\nSPDLOG_INLINE void apply_all(const std::function<void(std::shared_ptr<logger>)> &fun)\n{\n    details::registry::instance().apply_all(fun);\n}\n\nSPDLOG_INLINE void drop(const std::string &name)\n{\n    details::registry::instance().drop(name);\n}\n\nSPDLOG_INLINE void drop_all()\n{\n    details::registry::instance().drop_all();\n}\n\nSPDLOG_INLINE void shutdown()\n{\n    details::registry::instance().shutdown();\n}\n\nSPDLOG_INLINE void set_automatic_registration(bool automatic_registation)\n{\n    details::registry::instance().set_automatic_registration(automatic_registation);\n}\n\nSPDLOG_INLINE std::shared_ptr<spdlog::logger> default_logger()\n{\n    return details::registry::instance().default_logger();\n}\n\nSPDLOG_INLINE spdlog::logger *default_logger_raw()\n{\n    return details::registry::instance().get_default_raw();\n}\n\nSPDLOG_INLINE void set_default_logger(std::shared_ptr<spdlog::logger> default_logger)\n{\n    details::registry::instance().set_default_logger(std::move(default_logger));\n}\n\n} // namespace spdlog"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/spdlog.h",
    "content": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n// spdlog main header file.\n// see example.cpp for usage example\n\n#ifndef SPDLOG_H\n#define SPDLOG_H\n\n#pragma once\n\n#include \"spdlog/common.h\"\n#include \"spdlog/details/registry.h\"\n#include \"spdlog/logger.h\"\n#include \"spdlog/version.h\"\n#include \"spdlog/details/synchronous_factory.h\"\n\n#include <chrono>\n#include <functional>\n#include <memory>\n#include <string>\n\nnamespace spdlog {\n\nusing default_factory = synchronous_factory;\n\n// Create and register a logger with a templated sink type\n// The logger's level, formatter and flush level will be set according the\n// global settings.\n//\n// Example:\n//   spdlog::create<daily_file_sink_st>(\"logger_name\", \"dailylog_filename\", 11, 59);\ntemplate<typename Sink, typename... SinkArgs>\ninline std::shared_ptr<spdlog::logger> create(std::string logger_name, SinkArgs &&... sink_args)\n{\n    return default_factory::create<Sink>(std::move(logger_name), std::forward<SinkArgs>(sink_args)...);\n}\n\n// Initialize and register a logger,\n// formatter and flush level will be set according the global settings.\n//\n// NOTE:\n// Use this function when creating loggers manually.\n//\n// Example:\n//   auto console_sink = std::make_shared<spdlog::sinks::stdout_sink_mt>();\n//   auto console_logger = std::make_shared<spdlog::logger>(\"console_logger\", console_sink);\n//   spdlog::initialize_logger(console_logger);\nvoid initialize_logger(std::shared_ptr<logger> logger);\n\n// Return an existing logger or nullptr if a logger with such name doesn't\n// exist.\n// example: spdlog::get(\"my_logger\")->info(\"hello {}\", \"world\");\nstd::shared_ptr<logger> get(const std::string &name);\n\n// Set global formatter. Each sink in each logger will get a clone of this object\nvoid set_formatter(std::unique_ptr<spdlog::formatter> formatter);\n\n// Set global format string.\n// example: spdlog::set_pattern(\"%Y-%m-%d %H:%M:%S.%e %l : %v\");\nvoid set_pattern(std::string pattern, pattern_time_type time_type = pattern_time_type::local);\n\n// Set global logging level\nvoid set_level(level::level_enum log_level);\n\n// Set global flush level\nvoid flush_on(level::level_enum log_level);\n\n// Start/Restart a periodic flusher thread\n// Warning: Use only if all your loggers are thread safe!\nvoid flush_every(std::chrono::seconds interval);\n\n// Set global error handler\nvoid set_error_handler(void (*handler)(const std::string &msg));\n\n// Register the given logger with the given name\nvoid register_logger(std::shared_ptr<logger> logger);\n\n// Apply a user defined function on all registered loggers\n// Example:\n// spdlog::apply_all([&](std::shared_ptr<spdlog::logger> l) {l->flush();});\nvoid apply_all(const std::function<void(std::shared_ptr<logger>)> &fun);\n\n// Drop the reference to the given logger\nvoid drop(const std::string &name);\n\n// Drop all references from the registry\nvoid drop_all();\n\n// stop any running threads started by spdlog and clean registry loggers\nvoid shutdown();\n\n// Automatic registration of loggers when using spdlog::create() or spdlog::create_async\nvoid set_automatic_registration(bool automatic_registation);\n\n// API for using default logger (stdout_color_mt),\n// e.g: spdlog::info(\"Message {}\", 1);\n//\n// The default logger object can be accessed using the spdlog::default_logger():\n// For example, to add another sink to it:\n// spdlog::default_logger()->sinks()->push_back(some_sink);\n//\n// The default logger can replaced using spdlog::set_default_logger(new_logger).\n// For example, to replace it with a file logger.\n//\n// IMPORTANT:\n// The default API is thread safe (for _mt loggers), but:\n// set_default_logger() *should not* be used concurrently with the default API.\n// e.g do not call set_default_logger() from one thread while calling spdlog::info() from another.\n\nstd::shared_ptr<spdlog::logger> default_logger();\n\nspdlog::logger *default_logger_raw();\n\nvoid set_default_logger(std::shared_ptr<spdlog::logger> default_logger);\n\ntemplate<typename... Args>\ninline void log(source_loc source, level::level_enum lvl, string_view_t fmt, const Args &... args)\n{\n    default_logger_raw()->log(source, lvl, fmt, args...);\n}\n\ntemplate<typename... Args>\ninline void log(level::level_enum lvl, string_view_t fmt, const Args &... args)\n{\n    default_logger_raw()->log(source_loc{}, lvl, fmt, args...);\n}\n\ntemplate<typename... Args>\ninline void trace(string_view_t fmt, const Args &... args)\n{\n    default_logger_raw()->trace(fmt, args...);\n}\n\ntemplate<typename... Args>\ninline void debug(string_view_t fmt, const Args &... args)\n{\n    default_logger_raw()->debug(fmt, args...);\n}\n\ntemplate<typename... Args>\ninline void info(string_view_t fmt, const Args &... args)\n{\n    default_logger_raw()->info(fmt, args...);\n}\n\ntemplate<typename... Args>\ninline void warn(string_view_t fmt, const Args &... args)\n{\n    default_logger_raw()->warn(fmt, args...);\n}\n\ntemplate<typename... Args>\ninline void error(string_view_t fmt, const Args &... args)\n{\n    default_logger_raw()->error(fmt, args...);\n}\n\ntemplate<typename... Args>\ninline void critical(string_view_t fmt, const Args &... args)\n{\n    default_logger_raw()->critical(fmt, args...);\n}\n\ntemplate<typename T>\ninline void log(source_loc source, level::level_enum lvl, const T &msg)\n{\n    default_logger_raw()->log(source, lvl, msg);\n}\n\ntemplate<typename T>\ninline void log(level::level_enum lvl, const T &msg)\n{\n    default_logger_raw()->log(lvl, msg);\n}\n\ntemplate<typename T>\ninline void trace(const T &msg)\n{\n    default_logger_raw()->trace(msg);\n}\n\ntemplate<typename T>\ninline void debug(const T &msg)\n{\n    default_logger_raw()->debug(msg);\n}\n\ntemplate<typename T>\ninline void info(const T &msg)\n{\n    default_logger_raw()->info(msg);\n}\n\ntemplate<typename T>\ninline void warn(const T &msg)\n{\n    default_logger_raw()->warn(msg);\n}\n\ntemplate<typename T>\ninline void error(const T &msg)\n{\n    default_logger_raw()->error(msg);\n}\n\ntemplate<typename T>\ninline void critical(const T &msg)\n{\n    default_logger_raw()->critical(msg);\n}\n\n#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT\ntemplate<typename... Args>\ninline void log(source_loc source, level::level_enum lvl, wstring_view_t fmt, const Args &... args)\n{\n    default_logger_raw()->log(source, lvl, fmt, args...);\n}\n\ntemplate<typename... Args>\ninline void log(level::level_enum lvl, wstring_view_t fmt, const Args &... args)\n{\n    default_logger_raw()->log(lvl, fmt, args...);\n}\n\ntemplate<typename... Args>\ninline void trace(wstring_view_t fmt, const Args &... args)\n{\n    default_logger_raw()->trace(fmt, args...);\n}\n\ntemplate<typename... Args>\ninline void debug(wstring_view_t fmt, const Args &... args)\n{\n    default_logger_raw()->debug(fmt, args...);\n}\n\ntemplate<typename... Args>\ninline void info(wstring_view_t fmt, const Args &... args)\n{\n    default_logger_raw()->info(fmt, args...);\n}\n\ntemplate<typename... Args>\ninline void warn(wstring_view_t fmt, const Args &... args)\n{\n    default_logger_raw()->warn(fmt, args...);\n}\n\ntemplate<typename... Args>\ninline void error(wstring_view_t fmt, const Args &... args)\n{\n    default_logger_raw()->error(fmt, args...);\n}\n\ntemplate<typename... Args>\ninline void critical(wstring_view_t fmt, const Args &... args)\n{\n    default_logger_raw()->critical(fmt, args...);\n}\n\n#endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT\n\n} // namespace spdlog\n\n//\n// enable/disable log calls at compile time according to global level.\n//\n// define SPDLOG_ACTIVE_LEVEL to one of those (before including spdlog.h):\n// SPDLOG_LEVEL_TRACE,\n// SPDLOG_LEVEL_DEBUG,\n// SPDLOG_LEVEL_INFO,\n// SPDLOG_LEVEL_WARN,\n// SPDLOG_LEVEL_ERROR,\n// SPDLOG_LEVEL_CRITICAL,\n// SPDLOG_LEVEL_OFF\n//\n\n#define SPDLOG_LOGGER_CALL(logger, level, ...)                                                                                             \\\n    do                                                                                                                                     \\\n    {                                                                                                                                      \\\n        if (logger->should_log(level))                                                                                                     \\\n            logger->force_log(spdlog::source_loc{__FILE__, __LINE__, SPDLOG_FUNCTION}, level, __VA_ARGS__);                                \\\n    } while (0)\n\n#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_TRACE\n#define SPDLOG_LOGGER_TRACE(logger, ...) SPDLOG_LOGGER_CALL(logger, spdlog::level::trace, __VA_ARGS__)\n#define SPDLOG_TRACE(...) SPDLOG_LOGGER_TRACE(spdlog::default_logger_raw(), __VA_ARGS__)\n#else\n#define SPDLOG_LOGGER_TRACE(logger, ...) (void)0\n#define SPDLOG_TRACE(...) (void)0\n#endif\n\n#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_DEBUG\n#define SPDLOG_LOGGER_DEBUG(logger, ...) SPDLOG_LOGGER_CALL(logger, spdlog::level::debug, __VA_ARGS__)\n#define SPDLOG_DEBUG(...) SPDLOG_LOGGER_DEBUG(spdlog::default_logger_raw(), __VA_ARGS__)\n#else\n#define SPDLOG_LOGGER_DEBUG(logger, ...) (void)0\n#define SPDLOG_DEBUG(...) (void)0\n#endif\n\n#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_INFO\n#define SPDLOG_LOGGER_INFO(logger, ...) SPDLOG_LOGGER_CALL(logger, spdlog::level::info, __VA_ARGS__)\n#define SPDLOG_INFO(...) SPDLOG_LOGGER_INFO(spdlog::default_logger_raw(), __VA_ARGS__)\n#else\n#define SPDLOG_LOGGER_INFO(logger, ...) (void)0\n#define SPDLOG_INFO(...) (void)0\n#endif\n\n#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_WARN\n#define SPDLOG_LOGGER_WARN(logger, ...) SPDLOG_LOGGER_CALL(logger, spdlog::level::warn, __VA_ARGS__)\n#define SPDLOG_WARN(...) SPDLOG_LOGGER_WARN(spdlog::default_logger_raw(), __VA_ARGS__)\n#else\n#define SPDLOG_LOGGER_WARN(logger, ...) (void)0\n#define SPDLOG_WARN(...) (void)0\n#endif\n\n#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_ERROR\n#define SPDLOG_LOGGER_ERROR(logger, ...) SPDLOG_LOGGER_CALL(logger, spdlog::level::err, __VA_ARGS__)\n#define SPDLOG_ERROR(...) SPDLOG_LOGGER_ERROR(spdlog::default_logger_raw(), __VA_ARGS__)\n#else\n#define SPDLOG_LOGGER_ERROR(logger, ...) (void)0\n#define SPDLOG_ERROR(...) (void)0\n#endif\n\n#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_CRITICAL\n#define SPDLOG_LOGGER_CRITICAL(logger, ...) SPDLOG_LOGGER_CALL(logger, spdlog::level::critical, __VA_ARGS__)\n#define SPDLOG_CRITICAL(...) SPDLOG_LOGGER_CRITICAL(spdlog::default_logger_raw(), __VA_ARGS__)\n#else\n#define SPDLOG_LOGGER_CRITICAL(logger, ...) (void)0\n#define SPDLOG_CRITICAL(...) (void)0\n#endif\n\n#ifdef SPDLOG_HEADER_ONLY\n#include \"spdlog-inl.h\"\n#endif\n\n#endif // SPDLOG_H\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/tweakme.h",
    "content": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n#pragma once\n\n///////////////////////////////////////////////////////////////////////////////\n//\n// Edit this file to squeeze more performance, and to customize supported\n// features\n//\n///////////////////////////////////////////////////////////////////////////////\n\n///////////////////////////////////////////////////////////////////////////////\n// Under Linux, the much faster CLOCK_REALTIME_COARSE clock can be used.\n// This clock is less accurate - can be off by dozens of millis - depending on\n// the kernel HZ.\n// Uncomment to use it instead of the regular clock.\n//\n// #define SPDLOG_CLOCK_COARSE\n///////////////////////////////////////////////////////////////////////////////\n\n///////////////////////////////////////////////////////////////////////////////\n// Uncomment if date/time logging is not needed and never appear in the log\n// pattern.\n// This will prevent spdlog from querying the clock on each log call.\n//\n// WARNING: If the log pattern contains any date/time while this flag is on, the\n// result is undefined.\n//          You must set new pattern(spdlog::set_pattern(..\") without any\n//          date/time in it\n//\n// #define SPDLOG_NO_DATETIME\n///////////////////////////////////////////////////////////////////////////////\n\n///////////////////////////////////////////////////////////////////////////////\n// Uncomment if thread id logging is not needed (i.e. no %t in the log pattern).\n// This will prevent spdlog from querying the thread id on each log call.\n//\n// WARNING: If the log pattern contains thread id (i.e, %t) while this flag is\n// on, the result is undefined.\n//\n// #define SPDLOG_NO_THREAD_ID\n///////////////////////////////////////////////////////////////////////////////\n\n///////////////////////////////////////////////////////////////////////////////\n// Uncomment to prevent spdlog from using thread local storage.\n//\n// WARNING: if your program forks, UNCOMMENT this flag to prevent undefined\n// thread ids in the children logs.\n//\n// #define SPDLOG_NO_TLS\n///////////////////////////////////////////////////////////////////////////////\n\n///////////////////////////////////////////////////////////////////////////////\n// Uncomment if logger name logging is not needed.\n// This will prevent spdlog from copying the logger name on each log call.\n//\n// #define SPDLOG_NO_NAME\n///////////////////////////////////////////////////////////////////////////////\n\n///////////////////////////////////////////////////////////////////////////////\n// Uncomment to avoid spdlog's usage of atomic log levels\n// Use only if your code never modifies a logger's log levels concurrently by\n// different threads.\n//\n// #define SPDLOG_NO_ATOMIC_LEVELS\n///////////////////////////////////////////////////////////////////////////////\n\n///////////////////////////////////////////////////////////////////////////////\n// Uncomment to enable usage of wchar_t for file names on Windows.\n//\n// #define SPDLOG_WCHAR_FILENAMES\n///////////////////////////////////////////////////////////////////////////////\n\n///////////////////////////////////////////////////////////////////////////////\n// Uncomment to override default eol (\"\\n\" or \"\\r\\n\" under Linux/Windows)\n//\n// #define SPDLOG_EOL \";-)\\n\"\n///////////////////////////////////////////////////////////////////////////////\n\n///////////////////////////////////////////////////////////////////////////////\n// Uncomment to use your own copy of the fmt library instead of spdlog's copy.\n// In this case spdlog will try to include <fmt/format.h> so set your -I flag\n// accordingly.\n//\n// #define SPDLOG_FMT_EXTERNAL\n///////////////////////////////////////////////////////////////////////////////\n\n///////////////////////////////////////////////////////////////////////////////\n// Uncomment to enable wchar_t support (convert to utf8)\n//\n// #define SPDLOG_WCHAR_TO_UTF8_SUPPORT\n///////////////////////////////////////////////////////////////////////////////\n\n///////////////////////////////////////////////////////////////////////////////\n// Uncomment to prevent child processes from inheriting log file descriptors\n//\n// #define SPDLOG_PREVENT_CHILD_FD\n///////////////////////////////////////////////////////////////////////////////\n\n///////////////////////////////////////////////////////////////////////////////\n// Uncomment to customize level names (e.g. \"MT TRACE\")\n//\n// #define SPDLOG_LEVEL_NAMES { \"MY TRACE\", \"MY DEBUG\", \"MY INFO\", \"MY WARNING\",\n// \"MY ERROR\", \"MY CRITICAL\", \"OFF\" }\n///////////////////////////////////////////////////////////////////////////////\n\n///////////////////////////////////////////////////////////////////////////////\n// Uncomment to customize short level names (e.g. \"MT\")\n// These can be longer than one character.\n//\n// #define SPDLOG_SHORT_LEVEL_NAMES { \"T\", \"D\", \"I\", \"W\", \"E\", \"C\", \"O\" }\n///////////////////////////////////////////////////////////////////////////////\n\n///////////////////////////////////////////////////////////////////////////////\n// Uncomment to disable default logger creation.\n// This might save some (very) small initialization time if no default logger is needed.\n//\n// #define SPDLOG_DISABLE_DEFAULT_LOGGER\n///////////////////////////////////////////////////////////////////////////////\n\n///////////////////////////////////////////////////////////////////////////////\n// Uncomment and set to compile time level with zero cost (default is INFO).\n// Macros like SPDLOG_DEBUG(..), SPDLOG_INFO(..)  will expand to empty statements if not enabled\n//\n// #define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_INFO\n///////////////////////////////////////////////////////////////////////////////\n\n///////////////////////////////////////////////////////////////////////////////\n// Uncomment (and change if desired) macro to use for function names.\n// This is compiler dependent.\n// __PRETTY_FUNCTION__ might be nicer in clang/gcc, and __FUNCTION__ in msvc.\n// Defaults to __FUNCTION__ (should work on all compilers) if not defined.\n//\n// #define SPDLOG_FUNCTION __PRETTY_FUNCTION__\n///////////////////////////////////////////////////////////////////////////////\n"
  },
  {
    "path": "extlibs/spdlog/include/spdlog/version.h",
    "content": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n#pragma once\n\n#define SPDLOG_VER_MAJOR 1\n#define SPDLOG_VER_MINOR 4\n#define SPDLOG_VER_PATCH 0\n\n#define SPDLOG_VERSION (SPDLOG_VER_MAJOR * 10000 + SPDLOG_VER_MINOR * 100 + SPDLOG_VER_PATCH)\n"
  },
  {
    "path": "extlibs/spdlog/src/spdlog.cpp",
    "content": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n#ifndef SPDLOG_COMPILED_LIB\n#error Please define SPDLOG_COMPILED_LIB to compile this file.\n#endif\n\n#include <mutex>\n#include <chrono>\n\n#include \"spdlog/details/null_mutex.h\"\n#include \"spdlog/async.h\"\n\n#include \"spdlog/spdlog-inl.h\"\n#include \"spdlog/common-inl.h\"\n\n#include \"spdlog/logger-inl.h\"\ntemplate spdlog::logger::logger(std::string name, sinks_init_list::iterator begin, sinks_init_list::iterator end);\n\n#include \"spdlog/async_logger-inl.h\"\n#include \"spdlog/details/log_msg-inl.h\"\n#include \"spdlog/sinks/sink-inl.h\"\n\n#include \"spdlog/sinks/base_sink-inl.h\"\ntemplate class spdlog::sinks::base_sink<std::mutex>;\ntemplate class spdlog::sinks::base_sink<spdlog::details::null_mutex>;\n\n#include \"spdlog/sinks/basic_file_sink-inl.h\"\ntemplate class spdlog::sinks::basic_file_sink<std::mutex>;\ntemplate class spdlog::sinks::basic_file_sink<spdlog::details::null_mutex>;\n\n#include \"spdlog/sinks/rotating_file_sink-inl.h\"\ntemplate class spdlog::sinks::rotating_file_sink<std::mutex>;\ntemplate class spdlog::sinks::rotating_file_sink<spdlog::details::null_mutex>;\n\n#include \"spdlog/details/registry-inl.h\"\n\n#include \"spdlog/details/os-inl.h\"\n#include \"spdlog/details/periodic_worker-inl.h\"\n#include \"spdlog/details/file_helper-inl.h\"\n#include \"spdlog/details/pattern_formatter-inl.h\"\n\n#include \"spdlog/details/thread_pool-inl.h\"\ntemplate class spdlog::details::mpmc_blocking_queue<spdlog::details::async_msg>;\n\n//\n// color sinks\n//\n#ifdef _WIN32\n#include \"spdlog/sinks/wincolor_sink-inl.h\"\ntemplate class spdlog::sinks::wincolor_sink<spdlog::details::console_mutex>;\ntemplate class spdlog::sinks::wincolor_sink<spdlog::details::console_nullmutex>;\ntemplate class spdlog::sinks::wincolor_stdout_sink<spdlog::details::console_mutex>;\ntemplate class spdlog::sinks::wincolor_stdout_sink<spdlog::details::console_nullmutex>;\ntemplate class spdlog::sinks::wincolor_stderr_sink<spdlog::details::console_mutex>;\ntemplate class spdlog::sinks::wincolor_stderr_sink<spdlog::details::console_nullmutex>;\n#else\n#include \"spdlog/sinks/ansicolor_sink-inl.h\"\ntemplate class spdlog::sinks::ansicolor_sink<spdlog::details::console_mutex>;\ntemplate class spdlog::sinks::ansicolor_sink<spdlog::details::console_nullmutex>;\ntemplate class spdlog::sinks::ansicolor_stdout_sink<spdlog::details::console_mutex>;\ntemplate class spdlog::sinks::ansicolor_stdout_sink<spdlog::details::console_nullmutex>;\ntemplate class spdlog::sinks::ansicolor_stderr_sink<spdlog::details::console_mutex>;\ntemplate class spdlog::sinks::ansicolor_stderr_sink<spdlog::details::console_nullmutex>;\n#endif\n\n// factory methods for color loggers\n#include \"spdlog/sinks/stdout_color_sinks-inl.h\"\ntemplate std::shared_ptr<spdlog::logger> spdlog::stdout_color_mt<spdlog::synchronous_factory>(\n    const std::string &logger_name, color_mode mode);\ntemplate std::shared_ptr<spdlog::logger> spdlog::stdout_color_st<spdlog::synchronous_factory>(\n    const std::string &logger_name, color_mode mode);\ntemplate std::shared_ptr<spdlog::logger> spdlog::stderr_color_mt<spdlog::synchronous_factory>(\n    const std::string &logger_name, color_mode mode);\ntemplate std::shared_ptr<spdlog::logger> spdlog::stderr_color_st<spdlog::synchronous_factory>(\n    const std::string &logger_name, color_mode mode);\n\ntemplate std::shared_ptr<spdlog::logger> spdlog::stdout_color_mt<spdlog::async_factory>(const std::string &logger_name, color_mode mode);\ntemplate std::shared_ptr<spdlog::logger> spdlog::stdout_color_st<spdlog::async_factory>(const std::string &logger_name, color_mode mode);\ntemplate std::shared_ptr<spdlog::logger> spdlog::stderr_color_mt<spdlog::async_factory>(const std::string &logger_name, color_mode mode);\ntemplate std::shared_ptr<spdlog::logger> spdlog::stderr_color_st<spdlog::async_factory>(const std::string &logger_name, color_mode mode);\n\n#include \"spdlog/sinks/stdout_sinks-inl.h\"\n\ntemplate class spdlog::sinks::stdout_sink_base<spdlog::details::console_mutex>;\ntemplate class spdlog::sinks::stdout_sink_base<spdlog::details::console_nullmutex>;\ntemplate class spdlog::sinks::stdout_sink<spdlog::details::console_mutex>;\ntemplate class spdlog::sinks::stdout_sink<spdlog::details::console_nullmutex>;\ntemplate class spdlog::sinks::stderr_sink<spdlog::details::console_mutex>;\ntemplate class spdlog::sinks::stderr_sink<spdlog::details::console_nullmutex>;\n\ntemplate std::shared_ptr<spdlog::logger> spdlog::stdout_logger_mt<spdlog::synchronous_factory>(const std::string &logger_name);\ntemplate std::shared_ptr<spdlog::logger> spdlog::stdout_logger_st<spdlog::synchronous_factory>(const std::string &logger_name);\ntemplate std::shared_ptr<spdlog::logger> spdlog::stderr_logger_mt<spdlog::synchronous_factory>(const std::string &logger_name);\ntemplate std::shared_ptr<spdlog::logger> spdlog::stderr_logger_st<spdlog::synchronous_factory>(const std::string &logger_name);\n\ntemplate std::shared_ptr<spdlog::logger> spdlog::stdout_logger_mt<spdlog::async_factory>(const std::string &logger_name);\ntemplate std::shared_ptr<spdlog::logger> spdlog::stdout_logger_st<spdlog::async_factory>(const std::string &logger_name);\ntemplate std::shared_ptr<spdlog::logger> spdlog::stderr_logger_mt<spdlog::async_factory>(const std::string &logger_name);\ntemplate std::shared_ptr<spdlog::logger> spdlog::stderr_logger_st<spdlog::async_factory>(const std::string &logger_name);\n\n// Slightly modified version of fmt lib's format.cc source file.\n// Copyright (c) 2012 - 2016, Victor Zverovich\n// All rights reserved.\n\n#if !defined(SPDLOG_FMT_EXTERNAL)\n#include \"spdlog/fmt/bundled/format-inl.h\"\n\nFMT_BEGIN_NAMESPACE\ntemplate struct internal::basic_data<void>;\ntemplate FMT_API internal::locale_ref::locale_ref(const std::locale &loc);\ntemplate FMT_API std::locale internal::locale_ref::get<std::locale>() const;\n\n// Explicit instantiations for char.\ntemplate FMT_API char internal::thousands_sep_impl(locale_ref);\ntemplate FMT_API void internal::basic_buffer<char>::append(const char *, const char *);\ntemplate FMT_API void internal::arg_map<format_context>::init(const basic_format_args<format_context> &args);\ntemplate FMT_API int internal::char_traits<char>::format_float(char *, std::size_t, const char *, int, double);\ntemplate FMT_API int internal::char_traits<char>::format_float(char *, std::size_t, const char *, int, long double);\ntemplate FMT_API std::string internal::vformat<char>(string_view, basic_format_args<format_context>);\ntemplate FMT_API format_context::iterator internal::vformat_to(internal::buffer &, string_view, basic_format_args<format_context>);\ntemplate FMT_API void internal::sprintf_format(double, internal::buffer &, core_format_specs);\ntemplate FMT_API void internal::sprintf_format(long double, internal::buffer &, core_format_specs);\n\n// Explicit instantiations for wchar_t.\ntemplate FMT_API wchar_t internal::thousands_sep_impl(locale_ref);\ntemplate FMT_API void internal::basic_buffer<wchar_t>::append(const wchar_t *, const wchar_t *);\ntemplate FMT_API void internal::arg_map<wformat_context>::init(const basic_format_args<wformat_context> &);\ntemplate FMT_API int internal::char_traits<wchar_t>::format_float(wchar_t *, std::size_t, const wchar_t *, int, double);\ntemplate FMT_API int internal::char_traits<wchar_t>::format_float(wchar_t *, std::size_t, const wchar_t *, int, long double);\ntemplate FMT_API std::wstring internal::vformat<wchar_t>(wstring_view, basic_format_args<wformat_context>);\nFMT_END_NAMESPACE\n\n#endif\n"
  },
  {
    "path": "extlibs/squirrel/.gitignore",
    "content": "# Folders created at compilation\nbin/\nlib/\n\n# Folders created at documentation generation\ndoc/build/\n"
  },
  {
    "path": "extlibs/squirrel/.travis.yml",
    "content": "language: cpp\ncompiler:\n  - gcc\n  - clang\n\n# Travis VMs are 64-bit but we compile both for 32 and 64 bit. To enable the\n# 32-bit builds to work, we need gcc-multilib.\naddons:\n  apt:\n    packages:\n    - gcc-multilib\n    - g++-multilib\n\n# Enable container-based builds.\nsudo: false\n\nscript: mkdir build && cd build && cmake .. && make -j2\n"
  },
  {
    "path": "extlibs/squirrel/CMakeLists.txt",
    "content": "if(MSVC)\n  cmake_minimum_required(VERSION 3.4)\nelse()\n  cmake_minimum_required(VERSION 2.8)\nendif()\n\noption(DISABLE_STATIC \"Avoid building/installing static libraries.\")\noption(LONG_OUTPUT_NAMES \"Use longer names for binaries and libraries: squirrel3 (not sq).\")\n\nset(CMAKE_INSTALL_PREFIX \"${CMAKE_SOURCE_DIR}\" CACHE PATH \"\")\nif (NOT CMAKE_BUILD_TYPE)\n  set(CMAKE_BUILD_TYPE \"Release\")\nendif ()\n\nproject(squirrel C CXX)\n\ninclude_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)\n\nif(CMAKE_COMPILER_IS_GNUCXX)\n  set(SQ_FLAGS -fexceptions -fno-strict-aliasing -Wall -Wextra -pedantic -Wcast-qual)\n\n  if(CMAKE_BUILD_TYPE STREQUAL \"Release\")\n    set(SQ_FLAGS ${SQ_FLAGS} -O3)\n  elseif(CMAKE_BUILD_TYPE STREQUAL \"RelWithDebInfo\")\n    set(SQ_FLAGS ${SQ_FLAGS} -O3 -g)\n  elseif(CMAKE_BUILD_TYPE STREQUAL \"MinSizeRel\")\n    set(SQ_FLAGS ${SQ_FLAGS} -Os)\n  elseif(CMAKE_BUILD_TYPE STREQUAL \"Debug\")\n    set(SQ_FLAGS ${SQ_FLAGS} -pg -pie -gstabs -g3 -Og)\n  endif()\n\n  if(CMAKE_VERSION VERSION_GREATER 3)\n    add_compile_options(${SQ_FLAGS})\n  else()\n    add_definitions(${SQ_FLAGS})\n  endif()\n\n  set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -frtti -std=c++0x\")\nelseif(MSVC)\n  set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)\n  add_definitions(-D_CRT_SECURE_NO_WARNINGS)\nendif()\n\nif(CMAKE_SIZEOF_VOID_P EQUAL 8)\n  add_definitions(-D_SQ64)\nendif()\n\nif(NOT SQ_DISABLE_INSTALLER)\n  if(NOT INSTALL_BIN_DIR)\n    set(INSTALL_BIN_DIR bin)\n  endif()\n\n  if(NOT INSTALL_LIB_DIR)\n    set(INSTALL_LIB_DIR lib)\n  endif()\nendif()\n\nadd_subdirectory(squirrel)\nadd_subdirectory(sqstdlib)\nadd_subdirectory(sq)\n\nif(NOT WIN32 AND NOT DISABLE_DYNAMIC)\n  set_target_properties(squirrel sqstdlib PROPERTIES SOVERSION 0 VERSION 0.0.0)\nendif()\n\nif(INSTALL_INC_DIR)\n  set(SQ_PUB_HEADERS include/sqconfig.h\n                     include/sqstdaux.h\n                     include/sqstdblob.h\n                     include/sqstdio.h\n                     include/sqstdmath.h\n                     include/sqstdstring.h\n                     include/sqstdsystem.h\n                     include/squirrel.h)\n  install(FILES ${SQ_PUB_HEADERS} DESTINATION ${INSTALL_INC_DIR})\nendif()\n"
  },
  {
    "path": "extlibs/squirrel/COMPILE",
    "content": "Squirrel 3.1 stable\n--------------------------------------------------------\nWhat is in this distribution?\n\nsquirrel\n    static library implementing the compiler and interpreter of the language\n\nsqstdlib\n    the standard utility libraries\n\nsq\n    stand alone interpreter\n\ndoc\n    The manual\n\netc\n    a minimalistic embedding sample\n\nsamples\n    samples programs\n\n\nHOW TO COMPILE\n---------------------------------------------------------\nCMAKE USERS\n.........................................................\nIf you want to build the shared libraries under Windows using Visual\nStudio, you will have to use CMake version 3.4 or newer. If not, an\nearlier version will suffice. For a traditional out-of-source build\nunder Linux, type something like\n\n $ mkdir build # Create temporary build directory\n $ cd build\n $ cmake .. # CMake will determine all the necessary information,\n            # including the platform (32- vs. 64-bit)\n $ make\n $ make install\n $ cd ..; rm -r build\n\nThe default installation directory will be the top source directory,\ni. e. the binaries will go into bin/ and the libraries into lib/. You\ncan change this behavior by calling CMake like this:\n\n $ cmake .. -DCMAKE_INSTALL_PREFIX=/some/path/on/your/system\n\nWith the INSTALL_BIN_DIR and INSTALL_LIB_DIR options, the directories\nthe binaries & libraries will go in (relative to CMAKE_INSTALL_PREFIX)\ncan be specified. For instance,\n\n $ cmake .. -DINSTALL_LIB_DIR=lib64\n\nwill install the libraries into a 'lib64' subdirectory in the top\nsource directory. If INSTALL_INC_DIR is set, the public header files\nwill be installed into the directory the value of INSTALL_INC_DIR\npoints to. There is no default directory - if you want only the\nbinaries and no headers, just don't specify INSTALL_INC_DIR, and no\nheader files will be installed.\n\nUnder Windows, it is probably easiest to use the CMake GUI interface,\nalthough invoking CMake from the command line as explained above\nshould work as well.\n\nGCC USERS\n.........................................................\nThere is a very simple makefile that compiles all libraries and exes\nfrom the root of the project run 'make'\n\nfor 32 bits systems\n\n $ make\n\nfor 64 bits systems\n\n $ make sq64\n\nVISUAL C++ USERS\n.........................................................\nOpen squirrel.dsw from the root project directory and build(dho!)\n\nDOCUMENTATION GENERATION\n.........................................................\nTo be able to compile the documentation, make sure that you have Python\ninstalled and the packages sphinx and sphinx_rtd_theme. Browse into doc/\nand use either the Makefile for GCC-based platforms or make.bat for\nWindows platforms.\n"
  },
  {
    "path": "extlibs/squirrel/COPYRIGHT",
    "content": "Copyright (c) 2003-2017 Alberto Demichelis\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n-----------------------------------------------------\nEND OF COPYRIGHT\n"
  },
  {
    "path": "extlibs/squirrel/HISTORY",
    "content": "***version 3.1.1 stable***\n-sq_gettypetag doesn't set last error(it's treated as SQBool function but keeps a SQRESULT for backward compatibility)\n-fixed _set method in userdata deelegates\n-fixed some warnings\n\n***version 3.1 stable***\n-added slice range for tolower and toupper\n-added startswith() and endswith() in string lib\n-added SQ_EXCLUDE_DEFAULT_MEMFUNCTIONS to exclude default mem fuction from compilation\n-added sq_getreleasehook\n-added thread.wakeupthrow()\n-added sq_pushthread\n-added \\u and \\U escape sequence for UTF8,UTF16 or UCS4 characters\n-added CMake scripts(thx Fabian Wolff)\n-the escape character \\x is based on sizeof(SQChar)\n-fixed several warnings(thx Markus Oberhumer)\n-fixed optimizer bug in compound arith oprators(+=,-= etc...)\n-fixed sq_getrefvmcount() (thx Gerrit)\n-fixed sq_getrefcount() when no references were added with sq_addref() (thx Gerrit)\n-fixed bug in string.tointeger() (thx Domingo)\n-fixed weakref comparison in 32bit builds using doubles(thx Domingo)\n-fixed compiler bug(thx Peter)\n-fixed some error in the documentation(thx Alexander)\n-fixed some error reporting in compiler(thx Alexander)\n-fixed incorrect optional semicolon after \"if block\"(thx Alexander)\n-fixed crash bug in compiler related to compound arith operators(+=,-= etc...) (thx Jeff1)\n\n***2015-01-10      ***\n***version 3.1 RC 1***\n-added new header sqconfig.h for all optional type declarations(unicode, 64bits etc..)\n-added sq_setsharedforeignptr sq_getsharedforeignptr\n-added sq_setsharedreleasehook sq_getsharedreleasehook\n-added escape() in sqstd string library\n-added __LINE__ and __FILE__ (thx mingodad)\n-widechar support on gcc builds\n-now boolean can be used in constants\n-reduced dependencies on C runtime library\n-newthread and sq_newthread() no longer reinitialize the root table on friend VMs(thx Lucas Cardellini)\n-exceptions in the _inherited metamethod are propagated(thx Lucas Cardellini)\n-'in' operator performance improvement(thx unagipai and mingodad)\n-fixes crash in compiler when trying to write 'base'\n-fixed bug in switch statement when using locals as case values (thx mingodad)\n-fixed bug in print()(thx Lucas Cardellini)\n\n***2013-08-30          ***\n***version 3.1 beta 1***\n-added new scoping rule(root attached to closures)\n-added closure.setroot() closure.getroot()\n-added sq_setclosureroot() and sq_getclosureroot()\n-added sq_setvmreleasehook() and sq_getvmreleasehook()\n-added documentaion for sq_getbase()\n-now string.tointeger() accepts an optional parameter 'base'\n-now format accepts zeroes in the format string (thx mingodad)\n-fixed bug in sqstd_createfile() (thx mingodad)\n-minor buxfixes\n\n***2012-11-10          ***\n***version 3.0.4 stable***\n-sq_deleteslot slot now pops the key in case of failure\n-fixed bug when _get metamethod throws null\n-fixed a bug in rstrip\n-added some error handling\n-minor bugfixes\n\n***2012-06-19          ***\n***version 3.1.0 alpha 1***\n-changed in and instanceof operator precendence\n-root object in closures\n-added closure.setroot closure.getroot\n-added sq_setclosureroot and sq_getclosureroot\n\n***version 3.0.3 stable***\n-improved error messages for _cmp(when a non integer value is returned) (thx Yexo)\n-added class.newmember() built in method (thx Nam)\n-added class.rawnewmember()  built in method (thx Nam)\n-added sq_rawnewmember() (thx Nam)\n-added sq_getversion()\n-added sq_typeof()\n-added sq_getclosurename()\n-added file.close() in stdlib\n-documented closure.getinfos() built-in method\n-fixed string iteration doesn't return negative numbers for characters > 127\n-fixed bug in tofloat() when converting a string with scientific notation without a decimal point (thx wr2)\n-fixed potential infinite loop in array.sort() when the _cmp function is inconsistent (thx Yexo)\n-fixed obscure bug in the compiler(thx yishin)\n-fixed some minor bug\n\n***2011-11-28          ***\n***version 3.0.2 stable***\n-added sq_gethash API\n-now array.sort() is implemented with heapsort\n-now floats in scientific notation also accept numbers with no '.' (eg. 1e+6 or 1e6)\n-fixed some warning\n-fixed some documentation\n-fixed bug in GC\n\n***2011-09-08          ***\n***version 3.0.1 stable***\n-added # as alternative symbol for \"line comment\"(mostly useful for shell scripts)\n-added sq_throwobject() to throw an arbitrary object from the C API\n-added alignement flag for userdata types, SQ_ALIGNMENT (thx Shigemasa)\n-added rawset() and rawget() to class and instance default delegate\n-changed bytecode format now ensures matching integer size and float size\n-now inherited classes also inherit userdatasize\n-added SQUIRREL_VERSION_NUMBER in squirrel.h and _versionnumber_ global symbol\n-fixed sq_getmemberhandle\n-fixed sq_getrefcount\n-refactored some sqstdio code\n-refactored some clone code\n-refactored some stuff in the string lib\n-added -s and -fno-exceptions in GCC makefile(better performance when using GCC)\n\n***2011-03-13        ***\n***version 3.0 stable***\n-added sq_getcallee()\n-sq_getfreevariable() also works for native closures\n-minior optimizations\n-removed several warning when compiling with GCC 4.x\n-fixed some errors in the documentation\n-fixed bug when using SQUSEDOUBLE and 32bits intengers\n-fixed bug when invoking generators with closure.call() (thx huntercool)\n\n***2010-12-19                           ***\n***version 3.0 release candidate 1(RC 1)***\n-improved metamethods error handling\n-added parameter 'isstatic' to _newmember metamethod(thx G.Meyer)\n-added sq_getrefcount() to return number of refences from C++(thx G.Meyer)\n\n***2010-11-07        ***\n***version 3.0 beta 3***\n-license changed to \"MIT license\"\n-added sq_resurrectunreachable() and resurrectunreachable()\n-added callee() built in function, returns the current running closure\n-added thread.getstackinfos()\n-added sq_objtouserpointer()\n-added sq_newtableex()\n-various refactoring and optimizations\n-fixed several 64bits issues regarding integer to string conversions\n-fixed some bugs when SQUSEDOUBLE is used in 32bits systems\n\n***2010-08-18          ***\n***version 3.0 beta 2.1***\n-fixed bug in class constructor\n-fixed bug in compound arith\n\n***2010-08-12        ***\n***version 3.0 beta 2***\n-class methods can be added or replaced after the class as been instantiated\n-JSON compliant table syntax, this is currently an experimental feature (thx atai)\n-sq_getsize() now returns userdatasize for classes and instances\n-now setroottable() and setconsttable() return the previous value of the respective table\n-fixed bug in compound arith operators when used on a free variable (thx ellon)\n-fixed some x64 minor bugs\n-fixed minor bug in the compiler\n-refactored some VM internals\n-documented sq_getmemberhandle, sq_getbyhandle, sq_setbyhandle to set and get value from classes\n\n***2009-11-15        ***\n***version 3.0 beta 1***\n-various refactoring and optimizations\n-fixed bug in free variables (thx mokehehe)\n-fixed bug in functions with default parameters (thx ara & Yexo)\n-fixed bug in exception handling\n-improved error propagation in _set and _get metamethods ( and 'throw null' for clean failure)\n-added sq_getmemberhandle, sq_getbyhandle, sq_setbyhandle to set and get value from classes\n\n***2009-06-30         ***\n***version 3.0 alpha 2***\n-added real free variables(thx Paul Ruizendaal)\n-added refactored function call implementation and compiler(thx Paul Ruizendaal)\n-added sq_getfunctioninfo\n-added compile time flag SQUSEDOUBLE to use double precision floats\n-added global slot _floatsize_ int the base lib to recognize single precision and double precision builds\n-sq_wakeupvm can now resume the vm with an exception\n-added sqstd_format\n-now blobs can be cloned\n-generators can now be instantiated by calling sq_call() or closure.call()\n-fixed debughook bug\n-fixed cooroutine error propagation\n\n***2008-07-23         ***\n***version 3.0 alpha 1***\n-first branch from 2.x source tree\n-added 'base' keyword\n-removed 'delegate' keyword\n-now compiled scripts are vararg functions\n-added setdelegate() and getdelegate() table builtin methods\n-added <=> 3 ways compare operator\n-added lambda expression @(a,b) a + b\n-added local function statement\n-added array built-in map(),reduce(),apply(),filter() and find()\n-generators hold only a weak reference of the enviroment object\n-removed 'vargv' and 'vargc' keywords\n-now var args are passed as an array called vargv(as a paramter)\n-removed 'parent' keyword\n-added class getbase() built in method\n-instanceof doesn't throw an exception if the left expression is not a class\n-lexical scoping for free variables(free variables are no longer in the second parameter list)\n-sq_setprintfunc accept error func\n-sq_geterrorfunc()\n-added sq_arrayremove() and sq_arrayinsert()\n-error() built in function(works like print but prints using the errorfunc)\n-added native debug hook\n\n***2008-02-17        ***\n***version 2.2 stable***\n-added _newslot metamethod in classes\n-added enums added constants\n-added sq_pushconsttable, sq_setconsttable\n-added default param\n-added octal literals(thx Dinosaur)\n-fixed debug hook, 'calls' and 'returns' are properly notified in the same number.\n-fixed a coroutine bug\n\n***2007-07-29          ***\n***version 2.1.2 stable***\n-new behaviour for generators iteration using foreach\nnow when a generator is iterated by foreach the value returned by a 'return val' statement\nwill terminate the iteration but will not be returned as foreach iteration\n-added sq_setclassudsize()\n-added sq_clear()\n-added table.clear(), array.clear()\n-fixed sq_cmp() (thx jyuill)\n-fixed minor bugs\n\n***2006-08-21          ***\n***version 2.1.1 stable***\n-vm refactoring\n-optimized internal function memory layout\n-new global symbol _version_ (is the version string)\n-code size optimization for float literals(on 32bits float builts)\n-now the raw ref API(sq_addref etc...) is fully reentrant.\n-fixed a bug in sq_getdelegate() now pushes null if the object doesn't have a delegate(thx MatzeB)\n-improved C reference performances in NO_GARBAGE_COLLECTOR builds\n-sq_getlocal() now enumerates also outer values.\n-fixed regexp library for GCC users.\n\n***2006-03-19        ***\n***version 2.1 stable***\n-added static class fields, new keyword static\n-added 64bits architecture support\n-added global slot _intsize_ int the base lib to recognize 32bits and 64bits builds\n-added functions with fixed environment, closure.bindenv() built-in function\n-all types except userdata and null implement the tostring() method\n-string concatenation now invokes metamethod _tostring\n-new metamethods for class objects _newmember and _inherited\n-sq_call() sq_resume() sq_wakeupvm() have a new signature\n-new C referencing implementation(scales more with the amount of references)\n-refactored hash table\n-new api functions sq_newslot(),sq_tobool(),sq_getbase(), sq_instanceof(), sq_bindenv()\n-the api func sq_createslot was deprecated but still supported in form of C macro on top of sq_newslot\n-sq_setreleasehook() now also works for classes\n-stream.readstr() and stream.writestr() have been deprecated(this affects file and blob)\n-fixed squirrel.h undeclared api calls\n-fixed few minor bugs\n-SQChar is now defined as wchar_t\n-removed warning when building with -Wall -pedantic for GCC users\n-added new std io function writeclosuretofile()\n-added new std string functions strip(),rstrip(),lstrip() and split()\n-regular expressions operators (+,*) now have more POSIX greedyness behaviour\n-class constructors are now invoked as normal functions\n\n***2005-10-02          ***\n***version 2.0.5 stable***\n-fixed some 64bits incompatibilities (thx sarge)\n-fixed minor bug in the stdlib format() function (thx Rick)\n-fixed a bug in dofile() that was preventing to compile empty files\n-added new API sq_poptop() & sq_getfreevariable()\n-some performance improvements\n\n***2005-08-14          ***\n***version 2.0.4 stable***\n-weak references and related API calls\n-added sq_objtobool()\n-class instances memory policies improved(1 mem allocation for the whole instance)\n-typetags are now declared as SQUserPointer instead of unsigned int\n-first pass for 64bits compatibility\n-fixed minor bug in the stdio stream\n-fixed a bug in format()\n-fixed bug in string.tointeger() and string.tofloat()\n\n***2005-06-24          ***\n***version 2.0.3 stable***\n-dofile() and loadfile() in the iolib now can decode ASCII, UTF8 files UCS2 big-endian and little-endian\n-sq_setparamscheck() : now typemesk can check for null\n-added string escape sequence \\xhhhh\n-fixed some C++ standard incompatibilities\n\n***2005-05-15          ***\n***version 2.0.2 stable***\n-performances improvements (expecially for GCC users)\n-removed all dependencies from C++ exception handling\n-various bugfixes\n\n***2005-04-12        ***\n***version 2.0.1 stable***\n-various bugfixes\n-sq_setparamscheck() now allows spaces in the typemask\n\n***2005-04-03        ***\n***version 2.0 stable***\n-added API sq_gettypetag()\n-added built-in function to the bool type(tointeger, tostring etc...)\n\n***2005-02-27                           ***\n***version 2.0 release candidate 1(RC 1)***\n-added API sq_reseterror()\n-modified sq_release()\n-now class instances can be cloned\n-various bufixes\n\n***2005-01-26        ***\n***version 2.0 beta 1***\n-added bool type\n-class properties can be redefined in a derived class\n-added ops *= /= and %=\n-new syntax for class attributes declaration </ and /> instead of ( and )\n-increased the max number of literals per function from 65535 to 16777215\n-now free variables have proper lexical scoping\n-added API sq_createinstance(), sq_pushbool(), sq_getbool()\n-added built-in function type()\n-added built-in function obj.rawin(key) in table,class and instance\n-sq_rawget() and sq_rawset() now work also on classes and instances\n-the VM no longer uses C++ exception handling (more suitable for embedded devices)\n-various bufixes\n\n***2004-12-21         ***\n***version 2.0 alpha 2***\n-globals scoping changed, now if :: is omitted the VM automatically falls back on the root table\n-various bufixes\n-added class level attributes\n\n***2004-12-12         ***\n***version 2.0 alpha 1***\n-codebase branch from version 1.x\n-added classes\n-added functions with variable number of parameters(vargc & vargv and the ...)\n-0 and 0.0 are now considered 'false' by all conditional statements(if,while,for,?,do-while)\n-added new api functions sq_newclass() sq_setinstanceup() sq_getinstanceup() sq_getattributes() sq_setattributes()\n-modified api sq_settypetag()\n\n***2004-11-01        ***\n***version 1.0 stable***\n-fixed some minor bug\n-improved operator 'delete' performances\n-added scientific notation for float numbers( eg. 2.e16 or 2.e-2)\n\n***2004-08-30        ***\n***version 1.0 release candidate 2(RC 2)***\n-fixed bug in the vm(thx Pierre Renaux)\n-fixed bug in the optimizer(thx Pierre Renaux)\n-fixed some bug in the documentation(thx JD)\n-added new api functions for raw object handling\n-removed nested multiline comments\n-reduced memory footprint in C references\n\n***2004-08-23        ***\n***version 1.0 release candidate 1(RC 1)***\n-fixed division by zero\n-the 'in' operator and obj.rawget() do not query the default delegate anymore\n-added function sq_getprintfunc()\n-added new standard library 'auxlib'(implements default error handlers)\n\n***2004-07-12        ***\n***version 1.0 beta 4***\n-fixed a bug in the integer.tochar() built-in method\n-fixed unary minus operator\n-fixed bug in dofile()\n-fixed inconsistency between != and == operators(on float/integer comparison)\n-added javascript style unsigned right shift operator '>>>'\n-added array(size) constructor built-in function\n-array.resize(size,[fill]) built-in function accepts an optional 'fill' value\n-improved debug API, added sq_getclosureinfo() and sq_setnativeclosurename()\n\n***2004-05-23        ***\n***version 1.0 beta 3***\n-minor vm bug fixes\n-string allocation is now faster\n-tables and array memory usage is now less conservative(they shrink)\n-added regular expression routines in the standard library\n-The 'c' expression now accepts only 1 character(thx irbrian)\n-multiline strings <[ ]> have been substituted with C# style verbatim strings (eg. @\"string\")\n-added new keyword 'parent' for accessing the delegate of tables and unserdata\n-The metamethod '_clone' has been renamed '_cloned'\n-the _delslot metamethod's behaviour and prototype have been changed\n-new default function in the integer and float object 'tochar()'\n-the built-in function chcode2string has been removed\n-the default method [table].getdelegate() has been removed\n-new api sq_rawdeleteslot()\n-new table built-in method rawdelete(key)\n-the dynamic mudule loading has been removed from the standard distribution\n-some optimizations in the VM\n\n***2004-04-21        ***\n***version 1.0 beta 2***\n-minor compiler/parser bug fixes\n-sq_newclosure has a different prototype, the \"paramscheck\" of paramter has been moved to the new function sq_setparamscheck()\n-sq_setparamscheck allows to add automatic parameters type checking in native closures\n-sq_compile() lost the lineinfo parameter\n-new api sq_enabledebuginfo() globally sets compiler's debug info generation\n-added consistency check on bytecode serialization\n-fixed += operator, now works on strings like +\n-added global slot in the base lib _charsize_ to recognize unicode builds from ascii builds runtime\n-added registry table\n-new api call sq_pushregistrytable()\n-added type tag to the userdata type sq_settypetag()\n-sq_getuserdata now queries the userdata typetag\n-the built in function collect_garbage() as been renamed collectgarbage() for consistency reasons\n-new standard libraries(sqlibs are now obsolete)\n\n***2004-02-20        ***\n***version 1.0 beta 1***\n-fixed a bug in the compiler (thanks Martin Kofler)\n-fixed bug in the switch case statement\n-fixed the _unm metamethod\n-fixed minor bugs in the API\n-fixed automatic stack resizing\n-first beta version\n    first pass code clean up in the VM and base lib\n    first pass code coverege test has been done on VM and built-in lib\n-new VM creation API sq_open() sq_close() (sq_newvm and sq_releasevm are now obsolete)\n-new api allows to specifiy a \"print\" function to output text(sq_printfunc)\n-added some small optimizations\n-new cooperative multi-threading capabilities in the base library(coroutines), VMs are now a built in type(\"thread\")\n-new built in functions have been added for manipulating the new \"thread\" type\n-friend virtual machines share the same root table, error handler and debug hook by default\n-new compile time options\n\n***2004-01-19       ***\n***version 0.9 alpha***\n-fixed a garbage collection bug\n-fixed some API bugs(thanks to Joshua Jensen)\n-fixed tail calls (in the version 0.8 the tail call optimization was erroneously disabled)\n-new function parameters semantic, now passing a wrong number of parameters generates an exception\n-native closures have now a built in parameter number checking\n-sq_rawget and sq_rawset now work also on arrays\n-sq_getsize now woks also on userdata\n-the userdata release hook prototype is changed(now passes the size of the userdata)\n-the lexer reader function now returns an integer instead of a char that allows better error checking on the input(thx Joshua Jensen)\n-faster compiler\n-try/catch blocks do not cause any runtime memory allocation anymore\n\n***2003-12-06       ***\n***version 0.8 alpha***\n-fixed a bug that was preventing to have callable userdata throught the metamethod _call\n-fixed a garbage collection bug\n-fixed == operator now can compare correctly different types\n-new built in method getstackinfos(level)\n-improved line informations precision for the debug hook\n-new api call sq_compilebuffer()\n-new built-in api function compilestring()\n-new syntactic sugar for function declarations inside tables\n-the debug API has been finalized\n\n***2003-11-17       ***\n***version 0.7 alpha***\n-fixed critical bug SQInteger the tail call system\n-fixed bug in the continue statement code generation\n-fixed func call param issue(thanks to Rewoonenco Andrew)\n-added _delslot metamethod(thanks to Rewoonenco Andrew)\n-new multiline string expression ( delimited by <[ and ]> )\n-normal strings (\"\") do not allow embedded new line anymore\n-reduced vm memory footprint(C refs are shared between friend VMs)\n-new api method sq_deleteslot()\n-new debug hook event 'r' is triggered when a function returns\n\n***2003-11-04       ***\n***version 0.6 alpha***\n-fixed switch statement(was executing the default case after a break)\n-sq_call() doesn't pop the closure (just the params)\n-the vm execution can be suspended from the C API anytime (micro-threads)\n-new api calls sq_suspendvm() sq_wakeupvm() sq_getvmstate() and sq_reservestack()\n\n***2003-10-13       ***\n***version 0.5 alpha***\n-fixed some minor bug\n-tested with non ASCII identifiers in unicode mode(I've tried chinese chars)\n-added built-in function string.find()\n-the built-in function array.sort() optionally accepts a cmp(a,b) function\n-the debug hook function now has a new prototype debug_hook(event_type,sourcefile,line,functionname)\n-fixed some debug info imprecision\n\n***2003-10-01       ***\n***version 0.4 alpha***\n-faster VM\n-sq_call will pop arguments and closure also in case of failure\n-fixed a bug in sq_remove\n-now the VM detects delegation cycles(and throws an exception)\n-new operators ++ and --\n-new operator ',' comma operator\n-fixed some expression precedence issue\n-fixed bug in sq_arraypop\n\n***2003-09-15       ***\n***version 0.3 alpha***\n-fixed a bug in array::insert()\n-optional Unicode core(define SQUNICODE or _UNICODE on Win32)\n-sq_compiler uses a new reader function SQLEXREADFUNC\n-the debug hook passes 'l' instead of 'line' for line callbacks\n    and 'c' instead of 'call' for call callbacks\n-new array.extend() bulit-in function\n-new API sq_clone()\n\n***2003-09-10           ***\n***version 0.2 pre-alpha***\n-new completely reentrant VM (sq_open and sq_close are now obsolete)\n-sq_newvm() has a new prototype\n-allocators are now global and linked in the VM\n-_newslot meta method added\n-rawset creates a slot if doesn't exists\n-the compiler error callback pass the vm handle(thanks Pierre Renaux)\n-sq_setforeignptr() sq_getforeingptr() are now public\n-sq_resume() now is possible to resume generators from C\n-sq_getlasterror() retrieve the last thrown error\n-improved docs\n\n***2003-09-06           ***\n***version 0.1 pre-alpha***\nfirst release\n"
  },
  {
    "path": "extlibs/squirrel/Makefile",
    "content": "\nSQUIRREL=.\nMAKE=make\n\nsq32: folders\n\tcd squirrel; $(MAKE)\n\tcd sqstdlib; $(MAKE)\n\tcd sq; $(MAKE)\n\nsqprof: folders\n\tcd squirrel; $(MAKE) sqprof\n\tcd sqstdlib; $(MAKE) sqprof\n\tcd sq; $(MAKE) sqprof\n\nsq64: folders\n\tcd squirrel; $(MAKE) sq64\n\tcd sqstdlib; $(MAKE) sq64\n\tcd sq; $(MAKE) sq64\n\nfolders:\n\tmkdir -p lib\n\tmkdir -p bin\n"
  },
  {
    "path": "extlibs/squirrel/README",
    "content": "The programming language SQUIRREL 3.1 stable\n\n--------------------------------------------------\nThis project has successfully been compiled and run on\n * Windows (x86 and amd64)\n * Linux (x86, amd64 and ARM)\n * Illumos (x86 and amd64)\n\nThe following compilers have been confirmed to be working:\n    MS Visual C++  6.0 (all on x86 and amd64)\n                   7.0   |\n                   7.1   v\n                   8.0\n                   9.0\n                  10.0\n                  12.0  ---\n    MinGW gcc 3.2 (mingw special 20020817-1)\n    Cygnus gcc 3.2\n    Linux gcc 3.2.3\n              4.0.0 (x86 and amd64)\n              5.3.1 (amd64)\n    Illumos gcc 4.0.0 (x86 and amd64)\n    ARM Linux gcc 4.6.3 (Raspberry Pi Model B)\n\n\nFeedback and suggestions are appreciated\nproject page - http://www.squirrel-lang.org\ncommunity forums - http://forum.squirrel-lang.org\nwiki - http://wiki.squirrel-lang.org\nauthor - alberto@demichelis.net\n\nEND OF README\n"
  },
  {
    "path": "extlibs/squirrel/appveyor.yml",
    "content": "version: 0.0.{build}\n\nplatform:\n - x86\n - x64\n\nconfiguration:\n - Debug\n - Release\n\nclone_folder: c:\\sq\n\nbefore_build:\n - mkdir build\n - cd build\n - call \"C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\vcvarsall.bat\" %platform%\n - echo %platform%\n - if %platform%==X64 (cmake .. -G \"Visual Studio 14 2015 Win64\")\n - if %platform%==x86 (cmake .. -G \"Visual Studio 14 2015\")\n\nbuild_script:\n - cmake --build . --config %configuration% -- /logger:\"C:\\Program Files\\AppVeyor\\BuildAgent\\Appveyor.MSBuildLogger.dll\"\n\nartifacts:\n - path: build\\*\\%configuration%\\*.exe\n - path: build\\*\\%configuration%\\*.dll\n\ntest: off\n"
  },
  {
    "path": "extlibs/squirrel/doc/Makefile",
    "content": "# Makefile for Sphinx documentation\n#\n\n# You can set these variables from the command line.\nSPHINXOPTS    =\nSPHINXBUILD   = sphinx-build\nPAPER         =\nBUILDDIR      = build\n\n# User-friendly check for sphinx-build\nifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)\n$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)\nendif\n\n# Internal variables.\nPAPEROPT_a4     = -D latex_paper_size=a4\nPAPEROPT_letter = -D latex_paper_size=letter\nALLSPHINXOPTS   = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source\n# the i18n builder cannot share the environment and doctrees with the others\nI18NSPHINXOPTS  = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source\n\n.PHONY: help\nhelp:\n\t@echo \"Please use \\`make <target>' where <target> is one of\"\n\t@echo \"  html       to make standalone HTML files\"\n\t@echo \"  dirhtml    to make HTML files named index.html in directories\"\n\t@echo \"  singlehtml to make a single large HTML file\"\n\t@echo \"  pickle     to make pickle files\"\n\t@echo \"  json       to make JSON files\"\n\t@echo \"  htmlhelp   to make HTML files and a HTML help project\"\n\t@echo \"  qthelp     to make HTML files and a qthelp project\"\n\t@echo \"  applehelp  to make an Apple Help Book\"\n\t@echo \"  devhelp    to make HTML files and a Devhelp project\"\n\t@echo \"  epub       to make an epub\"\n\t@echo \"  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter\"\n\t@echo \"  latexpdf   to make LaTeX files and run them through pdflatex\"\n\t@echo \"  latexpdfja to make LaTeX files and run them through platex/dvipdfmx\"\n\t@echo \"  text       to make text files\"\n\t@echo \"  man        to make manual pages\"\n\t@echo \"  texinfo    to make Texinfo files\"\n\t@echo \"  info       to make Texinfo files and run them through makeinfo\"\n\t@echo \"  gettext    to make PO message catalogs\"\n\t@echo \"  changes    to make an overview of all changed/added/deprecated items\"\n\t@echo \"  xml        to make Docutils-native XML files\"\n\t@echo \"  pseudoxml  to make pseudoxml-XML files for display purposes\"\n\t@echo \"  linkcheck  to check all external links for integrity\"\n\t@echo \"  doctest    to run all doctests embedded in the documentation (if enabled)\"\n\t@echo \"  coverage   to run coverage check of the documentation (if enabled)\"\n\n.PHONY: clean\nclean:\n\trm -rf $(BUILDDIR)/*\n\n.PHONY: html\nhtml:\n\t$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html\n\t@echo\n\t@echo \"Build finished. The HTML pages are in $(BUILDDIR)/html.\"\n\n.PHONY: dirhtml\ndirhtml:\n\t$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml\n\t@echo\n\t@echo \"Build finished. The HTML pages are in $(BUILDDIR)/dirhtml.\"\n\n.PHONY: singlehtml\nsinglehtml:\n\t$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml\n\t@echo\n\t@echo \"Build finished. The HTML page is in $(BUILDDIR)/singlehtml.\"\n\n.PHONY: pickle\npickle:\n\t$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle\n\t@echo\n\t@echo \"Build finished; now you can process the pickle files.\"\n\n.PHONY: json\njson:\n\t$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json\n\t@echo\n\t@echo \"Build finished; now you can process the JSON files.\"\n\n.PHONY: htmlhelp\nhtmlhelp:\n\t$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp\n\t@echo\n\t@echo \"Build finished; now you can run HTML Help Workshop with the\" \\\n\t      \".hhp project file in $(BUILDDIR)/htmlhelp.\"\n\n.PHONY: qthelp\nqthelp:\n\t$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp\n\t@echo\n\t@echo \"Build finished; now you can run \"qcollectiongenerator\" with the\" \\\n\t      \".qhcp project file in $(BUILDDIR)/qthelp, like this:\"\n\t@echo \"# qcollectiongenerator $(BUILDDIR)/qthelp/testy_sphinxy.qhcp\"\n\t@echo \"To view the help file:\"\n\t@echo \"# assistant -collectionFile $(BUILDDIR)/qthelp/testy_sphinxy.qhc\"\n\n.PHONY: applehelp\napplehelp:\n\t$(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp\n\t@echo\n\t@echo \"Build finished. The help book is in $(BUILDDIR)/applehelp.\"\n\t@echo \"N.B. You won't be able to view it unless you put it in\" \\\n\t      \"~/Library/Documentation/Help or install it in your application\" \\\n\t      \"bundle.\"\n\n.PHONY: devhelp\ndevhelp:\n\t$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp\n\t@echo\n\t@echo \"Build finished.\"\n\t@echo \"To view the help file:\"\n\t@echo \"# mkdir -p $$HOME/.local/share/devhelp/testy_sphinxy\"\n\t@echo \"# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/testy_sphinxy\"\n\t@echo \"# devhelp\"\n\n.PHONY: epub\nepub:\n\t$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub\n\t@echo\n\t@echo \"Build finished. The epub file is in $(BUILDDIR)/epub.\"\n\n.PHONY: latex\nlatex:\n\t$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex\n\t@echo\n\t@echo \"Build finished; the LaTeX files are in $(BUILDDIR)/latex.\"\n\t@echo \"Run \\`make' in that directory to run these through (pdf)latex\" \\\n\t      \"(use \\`make latexpdf' here to do that automatically).\"\n\n.PHONY: latexpdf\nlatexpdf:\n\t$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex\n\t@echo \"Running LaTeX files through pdflatex...\"\n\t$(MAKE) -C $(BUILDDIR)/latex all-pdf\n\t@echo \"pdflatex finished; the PDF files are in $(BUILDDIR)/latex.\"\n\n.PHONY: latexpdfja\nlatexpdfja:\n\t$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex\n\t@echo \"Running LaTeX files through platex and dvipdfmx...\"\n\t$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja\n\t@echo \"pdflatex finished; the PDF files are in $(BUILDDIR)/latex.\"\n\n.PHONY: text\ntext:\n\t$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text\n\t@echo\n\t@echo \"Build finished. The text files are in $(BUILDDIR)/text.\"\n\n.PHONY: man\nman:\n\t$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man\n\t@echo\n\t@echo \"Build finished. The manual pages are in $(BUILDDIR)/man.\"\n\n.PHONY: texinfo\ntexinfo:\n\t$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo\n\t@echo\n\t@echo \"Build finished. The Texinfo files are in $(BUILDDIR)/texinfo.\"\n\t@echo \"Run \\`make' in that directory to run these through makeinfo\" \\\n\t      \"(use \\`make info' here to do that automatically).\"\n\n.PHONY: info\ninfo:\n\t$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo\n\t@echo \"Running Texinfo files through makeinfo...\"\n\tmake -C $(BUILDDIR)/texinfo info\n\t@echo \"makeinfo finished; the Info files are in $(BUILDDIR)/texinfo.\"\n\n.PHONY: gettext\ngettext:\n\t$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale\n\t@echo\n\t@echo \"Build finished. The message catalogs are in $(BUILDDIR)/locale.\"\n\n.PHONY: changes\nchanges:\n\t$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes\n\t@echo\n\t@echo \"The overview file is in $(BUILDDIR)/changes.\"\n\n.PHONY: linkcheck\nlinkcheck:\n\t$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck\n\t@echo\n\t@echo \"Link check complete; look for any errors in the above output \" \\\n\t      \"or in $(BUILDDIR)/linkcheck/output.txt.\"\n\n.PHONY: doctest\ndoctest:\n\t$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest\n\t@echo \"Testing of doctests in the sources finished, look at the \" \\\n\t      \"results in $(BUILDDIR)/doctest/output.txt.\"\n\n.PHONY: coverage\ncoverage:\n\t$(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage\n\t@echo \"Testing of coverage in the sources finished, look at the \" \\\n\t      \"results in $(BUILDDIR)/coverage/python.txt.\"\n\n.PHONY: xml\nxml:\n\t$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml\n\t@echo\n\t@echo \"Build finished. The XML files are in $(BUILDDIR)/xml.\"\n\n.PHONY: pseudoxml\npseudoxml:\n\t$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml\n\t@echo\n\t@echo \"Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml.\"\n"
  },
  {
    "path": "extlibs/squirrel/doc/make.bat",
    "content": "@ECHO OFF\n\nREM Command file for Sphinx documentation\n\nif \"%SPHINXBUILD%\" == \"\" (\n    set SPHINXBUILD=sphinx-build\n)\nset BUILDDIR=build\nset ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source\nset I18NSPHINXOPTS=%SPHINXOPTS% source\nif NOT \"%PAPER%\" == \"\" (\n    set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%\n    set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%\n)\n\nif \"%1\" == \"\" goto help\n\nif \"%1\" == \"help\" (\n    :help\n    echo.Please use `make ^<target^>` where ^<target^> is one of\n    echo.  html       to make standalone HTML files\n    echo.  dirhtml    to make HTML files named index.html in directories\n    echo.  singlehtml to make a single large HTML file\n    echo.  pickle     to make pickle files\n    echo.  json       to make JSON files\n    echo.  htmlhelp   to make HTML files and a HTML help project\n    echo.  qthelp     to make HTML files and a qthelp project\n    echo.  devhelp    to make HTML files and a Devhelp project\n    echo.  epub       to make an epub\n    echo.  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter\n    echo.  text       to make text files\n    echo.  man        to make manual pages\n    echo.  texinfo    to make Texinfo files\n    echo.  gettext    to make PO message catalogs\n    echo.  changes    to make an overview over all changed/added/deprecated items\n    echo.  xml        to make Docutils-native XML files\n    echo.  pseudoxml  to make pseudoxml-XML files for display purposes\n    echo.  linkcheck  to check all external links for integrity\n    echo.  doctest    to run all doctests embedded in the documentation if enabled\n    echo.  coverage   to run coverage check of the documentation if enabled\n    goto end\n)\n\nif \"%1\" == \"clean\" (\n    for /d %%i in (%BUILDDIR%\\*) do rmdir /q /s %%i\n    del /q /s %BUILDDIR%\\*\n    goto end\n)\n\n\nREM Check if sphinx-build is available and fallback to Python version if any\n%SPHINXBUILD% 1>NUL 2>NUL\nif errorlevel 9009 goto sphinx_python\ngoto sphinx_ok\n\n:sphinx_python\n\nset SPHINXBUILD=python -m sphinx.__init__\n%SPHINXBUILD% 2> nul\nif errorlevel 9009 (\n    echo.\n    echo.The 'sphinx-build' command was not found. Make sure you have Sphinx\n    echo.installed, then set the SPHINXBUILD environment variable to point\n    echo.to the full path of the 'sphinx-build' executable. Alternatively you\n    echo.may add the Sphinx directory to PATH.\n    echo.\n    echo.If you don't have Sphinx installed, grab it from\n    echo.http://sphinx-doc.org/\n    exit /b 1\n)\n\n:sphinx_ok\n\n\nif \"%1\" == \"html\" (\n    %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html\n    if errorlevel 1 exit /b 1\n    echo.\n    echo.Build finished. The HTML pages are in %BUILDDIR%/html.\n    goto end\n)\n\nif \"%1\" == \"dirhtml\" (\n    %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml\n    if errorlevel 1 exit /b 1\n    echo.\n    echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.\n    goto end\n)\n\nif \"%1\" == \"singlehtml\" (\n    %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml\n    if errorlevel 1 exit /b 1\n    echo.\n    echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.\n    goto end\n)\n\nif \"%1\" == \"pickle\" (\n    %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle\n    if errorlevel 1 exit /b 1\n    echo.\n    echo.Build finished; now you can process the pickle files.\n    goto end\n)\n\nif \"%1\" == \"json\" (\n    %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json\n    if errorlevel 1 exit /b 1\n    echo.\n    echo.Build finished; now you can process the JSON files.\n    goto end\n)\n\nif \"%1\" == \"htmlhelp\" (\n    %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp\n    if errorlevel 1 exit /b 1\n    echo.\n    echo.Build finished; now you can run HTML Help Workshop with the ^\n.hhp project file in %BUILDDIR%/htmlhelp.\n    goto end\n)\n\nif \"%1\" == \"qthelp\" (\n    %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp\n    if errorlevel 1 exit /b 1\n    echo.\n    echo.Build finished; now you can run \"qcollectiongenerator\" with the ^\n.qhcp project file in %BUILDDIR%/qthelp, like this:\n    echo.^> qcollectiongenerator %BUILDDIR%\\qthelp\\testy_sphinxy.qhcp\n    echo.To view the help file:\n    echo.^> assistant -collectionFile %BUILDDIR%\\qthelp\\testy_sphinxy.ghc\n    goto end\n)\n\nif \"%1\" == \"devhelp\" (\n    %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp\n    if errorlevel 1 exit /b 1\n    echo.\n    echo.Build finished.\n    goto end\n)\n\nif \"%1\" == \"epub\" (\n    %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub\n    if errorlevel 1 exit /b 1\n    echo.\n    echo.Build finished. The epub file is in %BUILDDIR%/epub.\n    goto end\n)\n\nif \"%1\" == \"latex\" (\n    %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex\n    if errorlevel 1 exit /b 1\n    echo.\n    echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.\n    goto end\n)\n\nif \"%1\" == \"latexpdf\" (\n    %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex\n    cd %BUILDDIR%/latex\n    make all-pdf\n    cd %~dp0\n    echo.\n    echo.Build finished; the PDF files are in %BUILDDIR%/latex.\n    goto end\n)\n\nif \"%1\" == \"latexpdfja\" (\n    %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex\n    cd %BUILDDIR%/latex\n    make all-pdf-ja\n    cd %~dp0\n    echo.\n    echo.Build finished; the PDF files are in %BUILDDIR%/latex.\n    goto end\n)\n\nif \"%1\" == \"text\" (\n    %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text\n    if errorlevel 1 exit /b 1\n    echo.\n    echo.Build finished. The text files are in %BUILDDIR%/text.\n    goto end\n)\n\nif \"%1\" == \"man\" (\n    %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man\n    if errorlevel 1 exit /b 1\n    echo.\n    echo.Build finished. The manual pages are in %BUILDDIR%/man.\n    goto end\n)\n\nif \"%1\" == \"texinfo\" (\n    %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo\n    if errorlevel 1 exit /b 1\n    echo.\n    echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.\n    goto end\n)\n\nif \"%1\" == \"gettext\" (\n    %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale\n    if errorlevel 1 exit /b 1\n    echo.\n    echo.Build finished. The message catalogs are in %BUILDDIR%/locale.\n    goto end\n)\n\nif \"%1\" == \"changes\" (\n    %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes\n    if errorlevel 1 exit /b 1\n    echo.\n    echo.The overview file is in %BUILDDIR%/changes.\n    goto end\n)\n\nif \"%1\" == \"linkcheck\" (\n    %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck\n    if errorlevel 1 exit /b 1\n    echo.\n    echo.Link check complete; look for any errors in the above output ^\nor in %BUILDDIR%/linkcheck/output.txt.\n    goto end\n)\n\nif \"%1\" == \"doctest\" (\n    %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest\n    if errorlevel 1 exit /b 1\n    echo.\n    echo.Testing of doctests in the sources finished, look at the ^\nresults in %BUILDDIR%/doctest/output.txt.\n    goto end\n)\n\nif \"%1\" == \"coverage\" (\n    %SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage\n    if errorlevel 1 exit /b 1\n    echo.\n    echo.Testing of coverage in the sources finished, look at the ^\nresults in %BUILDDIR%/coverage/python.txt.\n    goto end\n)\n\nif \"%1\" == \"xml\" (\n    %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml\n    if errorlevel 1 exit /b 1\n    echo.\n    echo.Build finished. The XML files are in %BUILDDIR%/xml.\n    goto end\n)\n\nif \"%1\" == \"pseudoxml\" (\n    %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml\n    if errorlevel 1 exit /b 1\n    echo.\n    echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml.\n    goto end\n)\n\n:end\n"
  },
  {
    "path": "extlibs/squirrel/doc/source/conf.py",
    "content": "# -*- coding: utf-8 -*-\n#\n# Squirrel documentation build configuration file, created by\n# sphinx-quickstart on Sun Jan 31 00:26:52 2016.\n#\n# This file is execfile()d with the current directory set to its\n# containing dir.\n#\n# Note that not all possible configuration values are present in this\n# autogenerated file.\n#\n# All configuration values have a default; values that are commented out\n# serve to show the default.\n\nimport sys\nimport os\nimport time\n\n# If extensions (or modules to document with autodoc) are in another directory,\n# add these directories to sys.path here. If the directory is relative to the\n# documentation root, use os.path.abspath to make it absolute, like shown here.\n#sys.path.insert(0, os.path.abspath('.'))\n\n# -- General configuration ------------------------------------------------\n\n# If your documentation needs a minimal Sphinx version, state it here.\n#needs_sphinx = '1.0'\n\n# Add any Sphinx extension module names here, as strings. They can be\n# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom\n# ones.\nextensions = [\n    'sphinx.ext.pngmath',\n]\n\n# Add any paths that contain templates here, relative to this directory.\ntemplates_path = ['_templates']\n\n# The suffix(es) of source filenames.\n# You can specify multiple suffix as a list of string:\n# source_suffix = ['.rst', '.md']\nsource_suffix = '.rst'\n\n# The encoding of source files.\n#source_encoding = 'utf-8-sig'\n\n# The master toctree document.\nmaster_doc = 'index'\n\n# General information about the project.\nproject = u'Squirrel documentation'\ncopyright = '2003-%s, Alberto Demichelis' % time.strftime('%Y')\nauthor = u'Alberto Demichelis'\n\n# The version info for the project you're documenting, acts as replacement for\n# |version| and |release|, also used in various other places throughout the\n# built documents.\n#\n# The short X.Y version.\nversion = u'3.1'\n# The full version, including alpha/beta/rc tags.\nrelease = u'3.1 stable'\n\n# The language for content autogenerated by Sphinx. Refer to documentation\n# for a list of supported languages.\n#\n# This is also used if you do content translation via gettext catalogs.\n# Usually you set \"language\" from the command line for these cases.\nlanguage = None\n\n# There are two options for replacing |today|: either, you set today to some\n# non-false value, then it is used:\n#today = ''\n# Else, today_fmt is used as the format for a strftime call.\n#today_fmt = '%B %d, %Y'\n\n# List of patterns, relative to source directory, that match files and\n# directories to ignore when looking for source files.\nexclude_patterns = []\n\n# The reST default role (used for this markup: `text`) to use for all\n# documents.\n#default_role = None\n\n# If true, '()' will be appended to :func: etc. cross-reference text.\n#add_function_parentheses = True\n\n# If true, the current module name will be prepended to all description\n# unit titles (such as .. function::).\n#add_module_names = True\n\n# If true, sectionauthor and moduleauthor directives will be shown in the\n# output. They are ignored by default.\n#show_authors = False\n\n# The name of the Pygments (syntax highlighting) style to use.\npygments_style = 'sphinx'\n\n# A list of ignored prefixes for module index sorting.\n#modindex_common_prefix = []\n\n# If true, keep warnings as \"system message\" paragraphs in the built documents.\n#keep_warnings = False\n\n# If true, `todo` and `todoList` produce output, else they produce nothing.\ntodo_include_todos = False\n\n\n# -- Options for HTML output ----------------------------------------------\n\n# The theme to use for HTML and HTML Help pages.  See the documentation for\n# a list of builtin themes.\nhtml_theme = 'sphinx_rtd_theme'\n\n# Theme options are theme-specific and customize the look and feel of a theme\n# further.  For a list of options available for each theme, see the\n# documentation.\n#html_theme_options = {}\n\n# Add any paths that contain custom themes here, relative to this directory.\n#html_theme_path = []\n\n# The name for this set of Sphinx documents.  If None, it defaults to\n# \"<project> v<release> documentation\".\n#html_title = None\n\n# A shorter title for the navigation bar.  Default is the same as html_title.\n#html_short_title = None\n\n# The name of an image file (relative to this directory) to place at the top\n# of the sidebar.\nhtml_logo = 'simple_nut.png'\n\n# The name of an image file (within the static path) to use as favicon of the\n# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32\n# pixels large.\nhtml_favicon = 'nut.ico'\n\n# Add any paths that contain custom static files (such as style sheets) here,\n# relative to this directory. They are copied after the builtin static files,\n# so a file named \"default.css\" will overwrite the builtin \"default.css\".\nhtml_static_path = ['_static']\n\n# Add any extra paths that contain custom files (such as robots.txt or\n# .htaccess) here, relative to this directory. These files are copied\n# directly to the root of the documentation.\n#html_extra_path = []\n\n# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,\n# using the given strftime format.\n#html_last_updated_fmt = '%b %d, %Y'\n\n# If true, SmartyPants will be used to convert quotes and dashes to\n# typographically correct entities.\n#html_use_smartypants = True\n\n# Custom sidebar templates, maps document names to template names.\n#html_sidebars = {}\n\n# Additional templates that should be rendered to pages, maps page names to\n# template names.\n#html_additional_pages = {}\n\n# If false, no module index is generated.\n#html_domain_indices = True\n\n# If false, no index is generated.\n#html_use_index = True\n\n# If true, the index is split into individual pages for each letter.\n#html_split_index = False\n\n# If true, links to the reST sources are added to the pages.\n#html_show_sourcelink = True\n\n# If true, \"Created using Sphinx\" is shown in the HTML footer. Default is True.\n#html_show_sphinx = True\n\n# If true, \"(C) Copyright ...\" is shown in the HTML footer. Default is True.\n#html_show_copyright = True\n\n# If true, an OpenSearch description file will be output, and all pages will\n# contain a <link> tag referring to it.  The value of this option must be the\n# base URL from which the finished HTML is served.\n#html_use_opensearch = ''\n\n# This is the file name suffix for HTML files (e.g. \".xhtml\").\n#html_file_suffix = None\n\n# Language to be used for generating the HTML full-text search index.\n# Sphinx supports the following languages:\n#   'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja'\n#   'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr'\n#html_search_language = 'en'\n\n# A dictionary with options for the search language support, empty by default.\n# Now only 'ja' uses this config value\n#html_search_options = {'type': 'default'}\n\n# The name of a javascript file (relative to the configuration directory) that\n# implements a search results scorer. If empty, the default will be used.\n#html_search_scorer = 'scorer.js'\n\n# Output file base name for HTML help builder.\nhtmlhelp_basename = 'squirrel_doc'\n\n# -- Options for LaTeX output ---------------------------------------------\n\nlatex_elements = {\n# The paper size ('letterpaper' or 'a4paper').\n#'papersize': 'letterpaper',\n\n# The font size ('10pt', '11pt' or '12pt').\n#'pointsize': '10pt',\n\n# Additional stuff for the LaTeX preamble.\n#'preamble': '',\n\n# Latex figure (float) alignment\n#'figure_align': 'htbp',\n}\n\n# Grouping the document tree into LaTeX files. List of tuples\n# (source start file, target name, title,\n#  author, documentclass [howto, manual, or own class]).\n_stdauthor = r'Alberto Demichelis'\nlatex_documents = [\n    ('reference/index', 'reference.tex',\n     'Squirrel Reference Manual', _stdauthor, 'manual'),\n     ('stdlib/index', 'stdlib.tex',\n     'Squirrel Standard Library', _stdauthor, 'manual'),\n]\n\n# The name of an image file (relative to this directory) to place at the top of\n# the title page.\n#latex_logo = None\n\n# For \"manual\" documents, if this is true, then toplevel headings are parts,\n# not chapters.\n#latex_use_parts = False\n\n# If true, show page references after internal links.\n#latex_show_pagerefs = False\n\n# If true, show URL addresses after external links.\n#latex_show_urls = False\n\n# Documents to append as an appendix to all manuals.\n#latex_appendices = []\n\n# If false, no module index is generated.\n#latex_domain_indices = True\n\n\n# -- Options for manual page output ---------------------------------------\n\n# One entry per manual page. List of tuples\n# (source start file, name, description, authors, manual section).\nman_pages = [\n    (master_doc, 'Squirrel', u'Squirrel Documentation',\n     [author], 1)\n]\n\n# If true, show URL addresses after external links.\n#man_show_urls = False\n\n\n# -- Options for Texinfo output -------------------------------------------\n\n# Grouping the document tree into Texinfo files. List of tuples\n# (source start file, target name, title, author,\n#  dir menu entry, description, category)\ntexinfo_documents = [\n    (master_doc, 'Squirrel', u'Squirrel Documentation',\n     author, 'Squirrel', 'The Programming Language.',\n     'Miscellaneous'),\n]\n\n# Documents to append as an appendix to all manuals.\n#texinfo_appendices = []\n\n# If false, no module index is generated.\n#texinfo_domain_indices = True\n\n# How to display URL addresses: 'footnote', 'no', or 'inline'.\n#texinfo_show_urls = 'footnote'\n\n# If true, do not generate a @detailmenu in the \"Top\" node's menu.\n#texinfo_no_detailmenu = False\n"
  },
  {
    "path": "extlibs/squirrel/doc/source/index.rst",
    "content": ".. Squirrel documentation master file, created by\n   sphinx-quickstart on Sun Jan 31 00:26:52 2016.\n   You can adapt this file completely to your liking, but it should at least\n   contain the root `toctree` directive.\n\nSquirrel's documentation\n=========================================\n\nContents:\n\n.. toctree::\n   :maxdepth: 1\n\n   reference/index.rst\n   stdlib/index.rst\n\n\nIndices and tables\n==================\n\n* :ref:`genindex`\n* :ref:`search`\n\n\n"
  },
  {
    "path": "extlibs/squirrel/doc/source/reference/api/bytecode_serialization.rst",
    "content": ".. _api_ref_bytecode_serialization:\n\n======================\nBytecode serialization\n======================\n\n.. _sq_readclosure:\n\n.. c:function:: SQRESULT sq_readclosure(HSQUIRRELVM v, SQREADFUNC readf, SQUserPointer up)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQREADFUNC readf: pointer to a read function that will be invoked by the vm during the serialization.\n    :param SQUserPointer up: pointer that will be passed to each call to the read function\n    :returns: a SQRESULT\n\nserialize (read) a closure and pushes it on top of the stack, the source is user defined through a read callback.\n\n\n\n\n\n.. _sq_writeclosure:\n\n.. c:function:: SQRESULT sq_writeclosure(HSQUIRRELVM v, SQWRITEFUNC writef, SQUserPointer up)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQWRITEFUNC writef: pointer to a write function that will be invoked by the vm during the serialization.\n    :param SQUserPointer up: pointer that will be passed to each call to the write function\n    :returns: a SQRESULT\n    :remarks: closures with free variables cannot be serialized\n\nserializes(writes) the closure on top of the stack, the destination is user defined through a write callback.\n"
  },
  {
    "path": "extlibs/squirrel/doc/source/reference/api/calls.rst",
    "content": ".. _api_ref_calls:\n\n=====\nCalls\n=====\n\n.. _sq_call:\n\n.. c:function:: SQRESULT sq_call(HSQUIRRELVM v, SQInteger params, SQBool retval, SQBool raiseerror)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger params: number of parameters of the function\n    :param SQBool retval: if true the function will push the return value in the stack\n    :param SQBool raiseerror: if true, if a runtime error occurs during the execution of the call, the vm will invoke the error handler.\n    :returns: a SQRESULT\n\ncalls a closure or a native closure. The function pops all the parameters and leave the closure in the stack; if retval is true the return value of the closure is pushed. If the execution of the function is suspended through sq_suspendvm(), the closure and the arguments will not be automatically popped from the stack.\n\nWhen using to create an instance, push a dummy parameter to be filled with the newly-created instance for the constructor's 'this' parameter.\n\n\n\n.. _sq_getcallee:\n\n.. c:function:: SQRESULT sq_getcallee(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n    :returns: a SQRESULT\n\npush in the stack the currently running closure.\n\n\n\n\n\n.. _sq_getlasterror:\n\n.. c:function:: SQRESULT sq_getlasterror(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n    :returns: a SQRESULT\n    :remarks: the pushed error descriptor can be any valid squirrel type.\n\npushes the last error in the stack.\n\n\n\n\n\n.. _sq_getlocal:\n\n.. c:function:: const SQChar * sq_getlocal(HSQUIRRELVM v, SQUnsignedInteger level, SQUnsignedInteger nseq)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQUnsignedInteger level: the function index in the calls stack, 0 is the current function\n    :param SQUnsignedInteger nseq: the index of the local variable in the stack frame (0 is 'this')\n    :returns: the name of the local variable if a variable exists at the given level/seq otherwise NULL.\n\nReturns the name of a local variable given stackframe and sequence in the stack and pushes is current value. Free variables are treated as local variables, by sq_getlocal(), and will be returned as they would be at the base of the stack, just before the real local variables.\n\n\n\n\n\n.. _sq_reseterror:\n\n.. c:function:: void sq_reseterror(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n\nreset the last error in the virtual machine to null\n\n\n\n\n\n.. _sq_resume:\n\n.. c:function:: SQRESULT sq_resume(HSQUIRRELVM v, SQBool retval, SQBool raiseerror)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQBool retval: if true the function will push the return value in the stack\n    :param SQBool raiseerror: if true, if a runtime error occurs during the execution of the call, the vm will invoke the error handler.\n    :returns: a SQRESULT\n    :remarks: if retval != 0 the return value of the generator is pushed.\n\nresumes the generator at the top position of the stack.\n\n\n.. _sq_tailcall:\n\n.. c:function:: SQRESULT sq_tailcall(HSQUIRRELVM v, SQInteger nparams)\n\n\t:param HSQUIRRELVM v: the target VM\n    :param SQInteger params: number of parameters of the function\n\n\tCalls a closure and removes the caller function from the call stack.\n\tThis function must be invoke from a native closure and \n\the return value of sq_tailcall must be returned by the caller function(see example).\n\t\n*.eg*\n\n::\n\n    SQInteger tailcall_something_example(HSQUIRRELVM v)\n    {\n\t\t//push closure and parameters here\n\t\t... \n        return sq_tailcall(v,2);\n    }\n\t\n.. _sq_throwerror:\n\n.. c:function:: SQRESULT sq_throwerror(HSQUIRRELVM v, const SQChar * err)\n\n    :param HSQUIRRELVM v: the target VM\n    :param const SQChar * err: the description of the error that has to be thrown\n    :returns: the value that has to be returned by a native closure in order to throw an exception in the virtual machine.\n\nsets the last error in the virtual machine and returns the value that has to be returned by a native closure in order to trigger an exception in the virtual machine.\n\n\n.. _sq_throwobject:\n\n.. c:function:: SQRESULT sq_throwobject(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n    :returns: the value that has to be returned by a native closure in order to throw an exception in the virtual machine.\n\npops a value from the stack sets it as the last error in the virtual machine. Returns the value that has to be returned by a native closure in order to trigger an exception in the virtual machine (aka SQ_ERROR).\n"
  },
  {
    "path": "extlibs/squirrel/doc/source/reference/api/compiler.rst",
    "content": ".. _api_ref_compiler:\n\n========\nCompiler\n========\n\n.. _sq_compile:\n\n.. c:function:: SQRESULT sq_compile(HSQUIRRELVM v, HSQLEXREADFUNC read, SQUserPointer p, const SQChar * sourcename, SQBool raiseerror)\n\n    :param HSQUIRRELVM v: the target VM\n    :param HSQLEXREADFUNC read: a pointer to a read function that will feed the compiler with the program.\n    :param SQUserPointer p: a user defined pointer that will be passed by the compiler to the read function at each invocation.\n    :param const SQChar * sourcename: the symbolic name of the program (used only for more meaningful runtime errors)\n    :param SQBool raiseerror: if this value is true the compiler error handler will be called in case of an error\n    :returns: a SQRESULT. If the sq_compile fails nothing is pushed in the stack.\n    :remarks: in case of an error the function will call the function set by sq_setcompilererrorhandler().\n\ncompiles a squirrel program; if it succeeds, push the compiled script as function in the stack.\n\n\n\n\n\n.. _sq_compilebuffer:\n\n.. c:function:: SQRESULT sq_compilebuffer(HSQUIRRELVM v, const SQChar* s, SQInteger size, const SQChar * sourcename, SQBool raiseerror)\n\n    :param HSQUIRRELVM v: the target VM\n    :param const SQChar* s: a pointer to the buffer that has to be compiled.\n    :param SQInteger size: size in characters of the buffer passed in the parameter 's'.\n    :param const SQChar * sourcename: the symbolic name of the program (used only for more meaningful runtime errors)\n    :param SQBool raiseerror: if this value true the compiler error handler will be called in case of an error\n    :returns: a SQRESULT. If the sq_compilebuffer fails nothing is pushed in the stack.\n    :remarks: in case of an error the function will call the function set by sq_setcompilererrorhandler().\n\ncompiles a squirrel program from a memory buffer; if it succeeds, push the compiled script as function in the stack.\n\n\n\n\n\n.. _sq_enabledebuginfo:\n\n.. c:function:: void sq_enabledebuginfo(HSQUIRRELVM v, SQBool enable)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQBool enable: if true enables the debug info generation, if == 0 disables it.\n    :remarks: The function affects all threads as well.\n\nenable/disable the debug line information generation at compile time.\n\n\n\n\n\n.. _sq_notifyallexceptions:\n\n.. c:function:: void sq_notifyallexceptions(HSQUIRRELVM v, SQBool enable)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQBool enable: if true enables the error callback notification of handled exceptions.\n    :remarks: By default the VM will invoke the error callback only if an exception is not handled (no try/catch traps are present in the call stack). If notifyallexceptions is enabled, the VM will call the error callback for any exception even if between try/catch blocks. This feature is useful for implementing debuggers.\n\nenable/disable the error callback notification of handled exceptions.\n\n\n\n\n\n.. _sq_setcompilererrorhandler:\n\n.. c:function:: void sq_setcompilererrorhandler(HSQUIRRELVM v, SQCOMPILERERROR f)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQCOMPILERERROR f: A pointer to the error handler function\n    :remarks: if the parameter f is NULL no function will be called when a compiler error occurs. The compiler error handler is shared between friend VMs.\n\nsets the compiler error handler function\n"
  },
  {
    "path": "extlibs/squirrel/doc/source/reference/api/debug_interface.rst",
    "content": ".. _api_ref_debug_interface:\n\n===============\nDebug interface\n===============\n\n.. _sq_getfunctioninfo:\n\n.. c:function:: SQRESULT sq_getfunctioninfo(HSQUIRRELVM v, SQInteger level, SQFunctionInfo * fi)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger level: calls stack level\n    :param SQFunctionInfo * fi: pointer to the SQFunctionInfo structure that will store the closure informations\n    :returns: a SQRESULT.\n    :remarks: the member 'funcid' of the returned SQFunctionInfo structure is a unique identifier of the function; this can be useful to identify a specific piece of squirrel code in an application like for instance a profiler. this method will fail if the closure in the stack is a native C closure.\n\n\n\n*.eg*\n\n::\n\n\n    typedef struct tagSQFunctionInfo {\n        SQUserPointer funcid; //unique idetifier for a function (all it's closures will share the same funcid)\n        const SQChar *name; //function name\n        const SQChar *source; //function source file name\n    }SQFunctionInfo;\n\n\n\n\n\n\n\n.. _sq_setdebughook:\n\n.. c:function:: void sq_setdebughook(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n    :remarks: In order to receive a 'per line' callback, is necessary to compile the scripts with the line informations. Without line informations activated, only the 'call/return' callbacks will be invoked.\n\npops a closure from the stack an sets it as debug hook. When a debug hook is set it overrides any previously set native or non native hooks. if the hook is null the debug hook will be disabled.\n\n\n\n\n\n.. _sq_setnativedebughook:\n\n.. c:function:: void sq_setnativedebughook(HSQUIRRELVM v, SQDEBUGHOOK hook)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQDEBUGHOOK hook: the native hook function\n    :remarks: In order to receive a 'per line' callback, is necessary to compile the scripts with the line informations. Without line informations activated, only the 'call/return' callbacks will be invoked.\n\nsets the native debug hook. When a native hook is set it overrides any previously set native or non native hooks. if the hook is NULL the debug hook will be disabled.\n\n\n\n\n\n.. _sq_stackinfos:\n\n.. c:function:: SQRESULT sq_stackinfos(HSQUIRRELVM v, SQInteger level, SQStackInfos * si)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger level: calls stack level\n    :param SQStackInfos * si: pointer to the SQStackInfos structure that will store the stack informations\n    :returns: a SQRESULT.\n\nretrieve the calls stack informations of a ceratain level in the calls stack.\n"
  },
  {
    "path": "extlibs/squirrel/doc/source/reference/api/garbage_collector.rst",
    "content": ".. _api_ref_garbage_collector:\n\n=================\nGarbage Collector\n=================\n\n.. _sq_collectgarbage:\n\n.. c:function:: SQInteger sq_collectgarbage(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n    :remarks: this api only works with garbage collector builds (NO_GARBAGE_COLLECTOR is not defined)\n\nruns the garbage collector and returns the number of reference cycles found (and deleted)\n\n\n\n\n\n.. _sq_resurrectunreachable:\n\n.. c:function:: SQRESULT sq_resurrectunreachable(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n    :remarks: this api only works with garbage collector builds (NO_GARBAGE_COLLECTOR is not defined)\n\nruns the garbage collector and pushes an array in the stack containing all unreachable object found. If no unreachable object is found, null is pushed instead. This function is meant to help debug reference cycles.\n"
  },
  {
    "path": "extlibs/squirrel/doc/source/reference/api/object_creation_and_handling.rst",
    "content": ".. _api_ref_object_creation_and_handling:\n\n============================\nObject creation and handling\n============================\n\n.. _sq_bindenv:\n\n.. c:function:: SQRESULT sq_bindenv(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target closure\n    :returns: a SQRESULT\n    :remarks: the cloned closure holds the environment object as weak reference\n\npops an object from the stack (must be a table, instance, or class); clones the closure at position idx in the stack and sets the popped object as environment of the cloned closure. Then pushes the new cloned closure on top of the stack.\n\n\n\n\n\n.. _sq_createinstance:\n\n.. c:function:: SQRESULT sq_createinstance(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target class\n    :returns: a SQRESULT\n    :remarks: the function doesn't invoke the instance contructor. To create an instance and automatically invoke its contructor, sq_call must be used instead.\n\ncreates an instance of the class at 'idx' position in the stack. The new class instance is pushed on top of the stack.\n\n\n\n\n\n.. _sq_getbool:\n\n.. c:function:: SQRESULT sq_getbool(HSQUIRRELVM v, SQInteger idx, SQBool * b)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: an index in the stack\n    :param SQBool * b: A pointer to the bool that will store the value\n    :returns: a SQRESULT\n\ngets the value of the bool at the idx position in the stack.\n\n\n\n\n\n.. _sq_getbyhandle:\n\n.. c:function:: SQRESULT sq_getbyhandle(HSQUIRRELVM v, SQInteger idx, HSQMEMBERHANDLE* handle)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: an index in the stack pointing to the class or instance\n    :param HSQMEMBERHANDLE* handle: a pointer to the member handle\n    :returns: a SQRESULT\n\npushes the value of a class or instance member using a member handle (see sq_getmemberhandle)\n\n\n\n\n\n.. _sq_getclosureinfo:\n\n.. c:function:: SQRESULT sq_getclosureinfo(HSQUIRRELVM v, SQInteger idx, SQInteger * nparams, SQInteger * nfreevars)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target closure\n    :param SQInteger * nparams: a pointer to an integer that will store the number of parameters\n    :param SQInteger * nfreevars: a pointer to an integer that will store the number of free variables\n    :returns: an SQRESULT\n\nretrieves number of parameters and number of freevariables from a squirrel closure.\n\n\n\n\n\n.. _sq_getclosurename:\n\n.. c:function:: SQRESULT sq_getclosurename(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target closure\n    :returns: an SQRESULT\n\npushes the name of the closure at position idx in the stack. Note that the name can be a string or null if the closure is anonymous or a native closure with no name assigned to it.\n\n\n\n\n\n.. _sq_getclosureroot:\n\n.. c:function:: SQRESULT sq_getclosureroot(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target closure\n    :returns: an SQRESULT\n\npushes the root table of the closure at position idx in the stack\n\n\n\n\n\n.. _sq_getfloat:\n\n.. c:function:: SQRESULT sq_getfloat(HSQUIRRELVM v, SQInteger idx, SQFloat * f)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: an index in the stack\n    :param SQFloat * f: A pointer to the float that will store the value\n    :returns: a SQRESULT\n\ngets the value of the float at the idx position in the stack.\n\n\n\n\n\n.. _sq_gethash:\n\n.. c:function:: SQHash sq_gethash(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: an index in the stack\n    :returns: the hash key of the value at the position idx in the stack\n    :remarks: the hash value function is the same used by the VM.\n\nreturns the hash key of a value at the idx position in the stack.\n\n\n\n\n\n.. _sq_getinstanceup:\n\n.. c:function:: SQRESULT sq_getinstanceup(HSQUIRRELVM v, SQInteger idx, SQUserPointer * up, SQUSerPointer typetag)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: an index in the stack\n    :param SQUserPointer * up: a pointer to the userpointer that will store the result\n    :param SQUSerPointer typetag: the typetag that has to be checked, if this value is set to 0 the typetag is ignored.\n    :returns: a SQRESULT\n\ngets the userpointer of the class instance at position idx in the stack. if the parameter 'typetag' is different than 0, the function checks that the class or a base class of the instance is tagged with the specified tag; if not the function fails. If 'typetag' is 0 the function will ignore the tag check.\n\n\n\n\n\n.. _sq_getinteger:\n\n.. c:function:: SQRESULT sq_getinteger(HSQUIRRELVM v, SQInteger idx, SQInteger * i)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: an index in the stack\n    :param SQInteger * i: A pointer to the integer that will store the value\n    :returns: a SQRESULT\n\ngets the value of the integer at the idx position in the stack.\n\n\n\n\n\n.. _sq_getmemberhandle:\n\n.. c:function:: SQRESULT sq_getmemberhandle(HSQUIRRELVM v, SQInteger idx, HSQMEMBERHANDLE* handle)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: an index in the stack pointing to the class\n    :param HSQMEMBERHANDLE* handle: a pointer to the variable that will store the handle\n    :returns: a SQRESULT\n    :remarks: This method works only with classes. A handle retrieved through a class can be later used to set or get values from one of the class instances. Handles retrieved from base classes are still valid in derived classes and respect inheritance rules.\n\npops a value from the stack and uses it as index to fetch the handle of a class member. The handle can be later used to set or get the member value using sq_getbyhandle(), sq_setbyhandle().\n\n\n\n\n\n.. _sq_getreleasehook:\n\n.. c:function:: SQRELEASEHOOK sq_getreleasehook(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: an index in the stack\n    :remarks: if the object that position idx is not an userdata, class instance or class the function returns NULL.\n\ngets the release hook of the userdata, class instance or class at position idx in the stack.\n\n\n\n\n\n.. _sq_getscratchpad:\n\n.. c:function:: SQChar * sq_getscratchpad(HSQUIRRELVM v, SQInteger minsize)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger minsize: the requested size for the scratchpad buffer\n    :remarks: the buffer is valid until the next call to sq_getscratchpad\n\nreturns a pointer to a memory buffer that is at least as big as minsize.\n\n\n\n\n\n.. _sq_getsize:\n\n.. c:function:: SQObjectType sq_getsize(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: an index in the stack\n    :returns: the size of the value at the position idx in the stack\n    :remarks: this function only works with strings, arrays, tables, classes, instances, and userdata if the value is not a valid type, the function will return -1.\n\nreturns the size of a value at the idx position in the stack. If the value is a class or a class instance the size returned is the size of the userdata buffer (see sq_setclassudsize).\n\n\n\n\n\n.. _sq_getstring:\n\n.. c:function:: SQRESULT sq_getstring(HSQUIRRELVM v, SQInteger idx, const SQChar ** c)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: an index in the stack\n    :param const SQChar ** c: a pointer to the pointer that will point to the string\n    :returns: a SQRESULT\n\ngets a pointer to the string at the idx position in the stack.\n\n\n\n\n\n.. _sq_getstringandsize:\n\n.. c:function:: SQRESULT sq_getstringandsize(HSQUIRRELVM v, SQInteger idx, const SQChar ** c, SQInteger* size)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: an index in the stack\n    :param const SQChar ** c: a pointer to the pointer that will point to the string\n    :param SQInteger * size: a pointer to a SQInteger which will receive the size of the string\n    :returns: a SQRESULT\n\ngets a pointer to the string at the idx position in the stack; additionally retrieves its size.\n\n\n\n\n.. _sq_getthread:\n\n.. c:function:: SQRESULT sq_getthread(HSQUIRRELVM v, SQInteger idx, HSQUIRRELVM* v)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: an index in the stack\n    :param HSQUIRRELVM* v: A pointer to the variable that will store the thread pointer\n    :returns: a SQRESULT\n\ngets a pointer to the thread the idx position in the stack.\n\n\n\n\n\n.. _sq_gettype:\n\n.. c:function:: SQObjectType sq_gettype(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: an index in the stack\n    :returns: the type of the value at the position idx in the stack\n\nreturns the type of the value at the position idx in the stack\n\n\n\n\n\n.. _sq_gettypetag:\n\n.. c:function:: SQRESULT sq_gettypetag(HSQUIRRELVM v, SQInteger idx, SQUserPointer * typetag)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: an index in the stack\n    :param SQUserPointer * typetag: a pointer to the variable that will store the tag\n    :returns: a SQRESULT\n    :remarks: the function works also with instances. if the taget object is an instance, the typetag of it's base class is fetched.\n\ngets the typetag of the object (userdata or class) at position idx in the stack.\n\n\n\n\n\n.. _sq_getuserdata:\n\n.. c:function:: SQRESULT sq_getuserdata(HSQUIRRELVM v, SQInteger idx, SQUserPointer * p, SQUserPointer * typetag)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: an index in the stack\n    :param SQUserPointer * p: A pointer to the userpointer that will point to the userdata's payload\n    :param SQUserPointer * typetag: A pointer to a SQUserPointer that will store the userdata tag(see sq_settypetag). The parameter can be NULL.\n    :returns: a SQRESULT\n\ngets a pointer to the value of the userdata at the idx position in the stack.\n\n\n\n\n\n.. _sq_getuserpointer:\n\n.. c:function:: SQRESULT sq_getuserpointer(HSQUIRRELVM v, SQInteger idx, SQUserPointer * p)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: an index in the stack\n    :param SQUserPointer * p: A pointer to the userpointer that will store the value\n    :returns: a SQRESULT\n\ngets the value of the userpointer at the idx position in the stack.\n\n\n\n\n\n.. _sq_newarray:\n\n.. c:function:: void sq_newarray(HSQUIRRELVM v, SQInteger size)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger size: the size of the array that as to be created\n\ncreates a new array and pushes it in the stack\n\n\n\n\n\n.. _sq_newclass:\n\n.. c:function:: SQRESULT sq_newclass(HSQUIRRELVM v, SQBool hasbase)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQBool hasbase: if the parameter is true the function expects a base class on top of the stack.\n    :returns: a SQRESULT\n\ncreates a new class object. If the parameter 'hasbase' is different than 0, the function pops a class from the stack and inherits the new created class from it. The new class is pushed in the stack.\n\n\n\n\n\n.. _sq_newclosure:\n\n.. c:function:: void sq_newclosure(HSQUIRRELVM v, HSQFUNCTION func, SQInteger nfreevars)\n\n    :param HSQUIRRELVM v: the target VM\n    :param HSQFUNCTION func: a pointer to a native-function\n    :param SQInteger nfreevars: number of free variables(can be 0)\n\ncreate a new native closure, pops n values set those as free variables of the new closure, and push the new closure in the stack.\n\n\n\n\n\n.. _sq_newtable:\n\n.. c:function:: void sq_newtable(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n\ncreates a new table and pushes it in the stack\n\n\n\n\n\n.. _sq_newtableex:\n\n.. c:function:: void sq_newtableex(HSQUIRRELVM v, SQInteger initialcapacity)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger initialcapacity: number of key/value pairs to preallocate\n\ncreates a new table and pushes it in the stack. This function allows you to specify the initial capacity of the table to prevent unnecessary rehashing when the number of slots required is known at creation-time.\n\n\n\n\n\n.. _sq_newuserdata:\n\n.. c:function:: SQUserPointer sq_newuserdata(HSQUIRRELVM v, SQUnsignedInteger size)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQUnsignedInteger size: the size of the userdata that as to be created in bytes\n\ncreates a new userdata and pushes it in the stack\n\n\n\n\n\n.. _sq_pushbool:\n\n.. c:function:: void sq_pushbool(HSQUIRRELVM v, SQBool b)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQBool b: the bool that has to be pushed(SQTrue or SQFalse)\n\npushes a bool into the stack\n\n\n\n\n\n.. _sq_pushfloat:\n\n.. c:function:: void sq_pushfloat(HSQUIRRELVM v, SQFloat f)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQFloat f: the float that has to be pushed\n\npushes a float into the stack\n\n\n\n\n\n.. _sq_pushinteger:\n\n.. c:function:: void sq_pushinteger(HSQUIRRELVM v, SQInteger n)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger n: the integer that has to be pushed\n\npushes an integer into the stack\n\n\n\n\n\n.. _sq_pushnull:\n\n.. c:function:: void sq_pushnull(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n\npushes a null value into the stack\n\n\n\n\n\n.. _sq_pushstring:\n\n.. c:function:: void sq_pushstring(HSQUIRRELVM v, const SQChar * s, SQInteger len)\n\n    :param HSQUIRRELVM v: the target VM\n    :param const SQChar * s: pointer to the string that has to be pushed\n    :param SQInteger len: length of the string pointed by s\n    :remarks: if the parameter len is less than 0 the VM will calculate the length using strlen(s)\n\npushes a string in the stack\n\n\n\n\n\n.. _sq_pushuserpointer:\n\n.. c:function:: void sq_pushuserpointer(HSQUIRRELVM v, SQUserPointer p)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQUserPointer p: the pointer that as to be pushed\n\npushes a userpointer into the stack\n\n\n\n\n\n.. _sq_setbyhandle:\n\n.. c:function:: SQRESULT sq_setbyhandle(HSQUIRRELVM v, SQInteger idx, HSQMEMBERHANDLE* handle)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: an index in the stack pointing to the class\n    :param HSQMEMBERHANDLE* handle: a pointer the member handle\n    :returns: a SQRESULT\n\npops a value from the stack and sets it to a class or instance member using a member handle (see sq_getmemberhandle)\n\n\n\n\n\n.. _sq_setclassudsize:\n\n.. c:function:: SQRESULT sq_setclassudsize(HSQUIRRELVM v, SQInteger idx, SQInteger udsize)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: an index in the stack pointing to the class\n    :param SQInteger udsize: size in bytes reserved for user data\n    :returns: a SQRESULT\n\nSets the user data size of a class. If a class 'user data size' is greater than 0. When an instance of the class is created additional space will be reserved at the end of the memory chunk where the instance is stored. The userpointer of the instance will also be automatically set to this memory area. This allows you to minimize allocations in applications that have to carry data along with the class instance.\n\n\n\n\n\n.. _sq_setclosureroot:\n\n.. c:function:: SQRESULT sq_setclosureroot(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target closure\n    :returns: an SQRESULT\n\npops a table from the stack and sets it as root of the closure at position idx in the stack\n\n\n\n\n\n.. _sq_setinstanceup:\n\n.. c:function:: SQRESULT sq_setinstanceup(HSQUIRRELVM v, SQInteger idx, SQUserPointer up)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: an index in the stack\n    :param SQUserPointer up: an arbitrary user pointer\n    :returns: a SQRESULT\n\nsets the userpointer of the class instance at position idx in the stack.\n\n\n\n\n\n.. _sq_setnativeclosurename:\n\n.. c:function:: SQRESULT sq_setnativeclosurename(HSQUIRRELVM v, SQInteger idx, const SQChar * name)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target native closure\n    :param const SQChar * name: the name that has to be set\n    :returns: an SQRESULT\n\nsets the name of the native closure at the position idx in the stack. The name of a native closure is purely for debug purposes. The name is retrieved trough the function sq_stackinfos() while the closure is in the call stack.\n\n\n\n\n\n.. _sq_setparamscheck:\n\n.. c:function:: SQRESULT sq_setparamscheck(HSQUIRRELVM v, SQInteger nparamscheck, const SQChar * typemask)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger nparamscheck: defines the parameters number check policy (0 disables the param checking). If nparamscheck is greater than 0, the VM ensures that the number of parameters is exactly the number specified in nparamscheck (eg. if nparamscheck == 3 the function can only be called with 3 parameters). If nparamscheck is less than 0 the VM ensures that the closure is called with at least the absolute value of the number specified in nparamcheck (eg. nparamscheck == -3 will check that the function is called with at least 3 parameters). The hidden parameter 'this' is included in this number; free variables aren't. If SQ_MATCHTYPEMASKSTRING is passed instead of the number of parameters, the function will automatically infer the number of parameters to check from the typemask (eg. if the typemask is \".sn\", it is like passing 3).\n    :param const SQChar * typemask: defines a mask to validate the parametes types passed to the function. If the parameter is NULL, no typechecking is applied (default).\n    :remarks: The typemask consists in a zero terminated string that represent the expected parameter type. The types are expressed as follows: 'o' null, 'i' integer, 'f' float, 'n' integer or float, 's' string, 't' table, 'a' array, 'u' userdata, 'c' closure and nativeclosure, 'g' generator, 'p' userpointer, 'v' thread, 'x' instance(class instance), 'y' class, 'b' bool. and '.' any type. The symbol '|' can be used as 'or' to accept multiple types on the same parameter. There isn't any limit on the number of 'or' that can be used. Spaces are ignored so can be inserted between types to increase readability. For instance to check a function that expect a table as 'this' a string as first parameter and a number or a userpointer as second parameter, the string would be \"tsn|p\" (table,string,number or userpointer). If the parameters mask is contains fewer parameters than 'nparamscheck', the remaining parameters will not be typechecked.\n\nSets the parameter validation scheme for the native closure at the top position in the stack. Allows you to validate the number of parameters accepted by the function and optionally their types. If the function call does not comply with the parameter schema set by sq_setparamscheck, an exception is thrown.\n\n*.eg*\n\n::\n\n    //example\n    SQInteger testy(HSQUIRRELVM v)\n    {\n        SQUserPointer p;\n        const SQChar *s;\n        SQInteger i;\n        //no type checking, if the call complies with the mask\n        //surely the functions will succeed.\n        sq_getuserdata(v,1,&p,NULL);\n        sq_getstring(v,2,&s);\n        sq_getinteger(v,3,&i);\n        //... do something\n        return 0;\n    }\n\n    //the reg code\n\n    //....stuff\n    sq_newclosure(v,testy,0);\n    //expects exactly 3 parameters(userdata,string,number)\n    sq_setparamscheck(v,3,_SC(\"usn\"));\n    //....stuff\n\n\n\n\n\n\n.. _sq_setreleasehook:\n\n.. c:function:: void sq_setreleasehook(HSQUIRRELVM v, SQInteger idx, SQRELEASEHOOK hook)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: an index in the stack\n    :param SQRELEASEHOOK hook: a function pointer to the hook(see sample below)\n    :remarks: the function hook is called by the VM before the userdata memory is deleted.\n\nsets the release hook of the userdata, class instance, or class at position idx in the stack.\n\n*.eg*\n\n::\n\n\n    /* tyedef SQInteger (*SQRELEASEHOOK)(SQUserPointer,SQInteger size); */\n\n    SQInteger my_release_hook(SQUserPointer p,SQInteger size)\n    {\n        /* do something here */\n        return 1;\n    }\n\n\n\n\n\n\n.. _sq_settypetag:\n\n.. c:function:: SQRESULT sq_settypetag(HSQUIRRELVM v, SQInteger idx, SQUserPointer typetag)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: an index in the stack\n    :param SQUserPointer typetag: an arbitrary SQUserPointer\n    :returns: a SQRESULT\n\nsets the typetag of the object (userdata or class) at position idx in the stack.\n\n\n\n\n\n.. _sq_tobool:\n\n.. c:function:: void sq_tobool(HSQUIRRELVM v, SQInteger idx, SQBool * b)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: an index in the stack\n    :param SQBool * b: A pointer to the bool that will store the value\n    :remarks: if the object is not a bool the function converts the value to bool according to squirrel's rules. For instance the number 1 will result in true, and the number 0 in false.\n\ngets the value at position idx in the stack as bool.\n\n\n\n\n\n.. _sq_tostring:\n\n.. c:function:: void sq_tostring(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: an index in the stack\n\nconverts the object at position idx in the stack to string and pushes the resulting string in the stack.\n\n\n\n\n\n.. _sq_typeof:\n\n.. c:function:: SQObjectType sq_typeof(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: an index in the stack\n    :returns: a SQRESULT\n\npushes the type name of the value at the position idx in the stack. It also invokes the _typeof metamethod for tables and class instances that implement it; in that case the pushed object could be something other than a string (is up to the _typeof implementation).\n\n\n\n"
  },
  {
    "path": "extlibs/squirrel/doc/source/reference/api/object_manipulation.rst",
    "content": ".. _api_ref_object_manipulation:\n\n====================\nObject manipulation\n====================\n\n.. _sq_arrayappend:\n\n.. c:function:: SQRESULT sq_arrayappend(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target array in the stack\n    :returns: a SQRESULT\n    :remarks: Only works on arrays.\n\npops a value from the stack and pushes it in the back of the array at the position idx in the stack.\n\n\n\n\n\n.. _sq_arrayinsert:\n\n.. c:function:: SQRESULT sq_arrayinsert(HSQUIRRELVM v, SQInteger idx, SQInteger destpos)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target array in the stack\n    :param SQInteger destpos: the position in the array where the item has to be inserted\n    :returns: a SQRESULT\n    :remarks: Only works on arrays.\n\npops a value from the stack and inserts it in an array at the specified position\n\n\n\n\n\n.. _sq_arraypop:\n\n.. c:function:: SQRESULT sq_arraypop(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target array in the stack\n    :returns: a SQRESULT\n    :remarks: Only works on arrays.\n\npops a value from the back of the array at the position idx in the stack.\n\n\n\n\n\n.. _sq_arrayremove:\n\n.. c:function:: SQRESULT sq_arrayremove(HSQUIRRELVM v, SQInteger idx, SQInteger itemidx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target array in the stack\n    :param SQInteger itemidx: the index of the item in the array that has to be removed\n    :returns: a SQRESULT\n    :remarks: Only works on arrays.\n\nremoves an item from an array\n\n\n\n\n\n.. _sq_arrayresize:\n\n.. c:function:: SQRESULT sq_arrayresize(HSQUIRRELVM v, SQInteger idx, SQInteger newsize)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target array in the stack\n    :param SQInteger newsize: requested size of the array\n    :returns: a SQRESULT\n    :remarks: Only works on arrays. If newsize if greater than the current size the new array slots will be filled with nulls.\n\nresizes the array at the position idx in the stack.\n\n\n\n\n\n.. _sq_arrayreverse:\n\n.. c:function:: SQRESULT sq_arrayreverse(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target array in the stack\n    :returns: a SQRESULT\n    :remarks: Only works on arrays.\n\nreverses an array in place.\n\n\n\n\n\n.. _sq_clear:\n\n.. c:function:: SQRESULT sq_clear(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target object in the stack\n    :returns: a SQRESULT\n    :remarks: Only works on tables and arrays.\n\nclears all the elements of the table/array at position idx in the stack.\n\n\n\n\n\n.. _sq_clone:\n\n.. c:function:: SQRESULT sq_clone(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target object in the stack\n    :returns: a SQRESULT\n\npushes a clone of the table, array, or class instance at the position idx.\n\n\n\n\n\n.. _sq_createslot:\n\n.. c:function:: SQRESULT sq_createslot(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target table in the stack\n    :returns: a SQRESULT\n    :remarks: invoke the _newslot metamethod in the table delegate. it only works on tables. [this function is deperecated since version 2.0.5 use sq_newslot() instead]\n\npops a key and a value from the stack and performs a set operation on the table or class that is at position idx in the stack; if the slot does not exist, it will be created.\n\n\n\n\n\n.. _sq_deleteslot:\n\n.. c:function:: SQRESULT sq_deleteslot(HSQUIRRELVM v, SQInteger idx, SQBool pushval)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target table in the stack\n    :param SQBool pushval: if this param is true the function will push the value of the deleted slot.\n    :returns: a SQRESULT\n    :remarks: invoke the _delslot metamethod in the table delegate. it only works on tables.\n\npops a key from the stack and delete the slot indexed by it from the table at position idx in the stack; if the slot does not exist, nothing happens.\n\n\n\n\n\n.. _sq_get:\n\n.. c:function:: SQRESULT sq_get(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target object in the stack\n    :returns: a SQRESULT\n    :remarks: this call will invokes the delegation system like a normal dereference it only works on tables, arrays, classes, instances and userdata; if the function fails, nothing will be pushed in the stack.\n\npops a key from the stack and performs a get operation on the object at the position idx in the stack; and pushes the result in the stack.\n\n\n\n\n\n.. _sq_getattributes:\n\n.. c:function:: SQRESULT sq_getattributes(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target class in the stack\n    :returns: a SQRESULT\n\nGets the attribute of a class member. The function pops a key from the stack and pushes the attribute of the class member indexed by they key from a class at position idx in the stack. If key is null the function gets the class level attribute.\n\n\n\n\n\n.. _sq_getbase:\n\n.. c:function:: SQRESULT sq_getbase(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target class in the stack\n    :returns: a SQRESULT\n\npushes the base class of the 'class' at stored position idx in the stack.\n\n\n\n\n\n.. _sq_getclass:\n\n.. c:function:: SQRESULT sq_getclass(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target class instance in the stack\n    :returns: a SQRESULT\n\npushes the class of the 'class instance' at stored position idx in the stack.\n\n\n\n\n\n.. _sq_getdelegate:\n\n.. c:function:: SQRESULT sq_getdelegate(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target object in the stack\n    :returns: a SQRESULT\n\npushes the current delegate of the object at the position idx in the stack.\n\n\n\n\n\n.. _sq_getfreevariable:\n\n.. c:function:: const SQChar * sq_getfreevariable(HSQUIRRELVM v, SQInteger idx, SQInteger nval)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target object in the stack(closure)\n    :param SQInteger nval: 0 based index of the free variable(relative to the closure).\n    :returns: the name of the free variable for pure squirrel closures. NULL in case of error or if the index of the variable is out of range. In case the target closure is a native closure, the return name is always \"@NATIVE\".\n    :remarks: The function works for both squirrel closure and native closure.\n\ngets the value of the free variable of the closure at the position idx in the stack.\n\n\n\n\n\n.. _sq_getweakrefval:\n\n.. c:function:: SQRESULT sq_getweakrefval(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target weak reference\n    :returns: a SQRESULT\n    :remarks: if the function fails, nothing is pushed in the stack.\n\npushes the object pointed by the weak reference at position idx in the stack.\n\n\n\n\n\n.. _sq_instanceof:\n\n.. c:function:: SQBool sq_instanceof(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n    :returns: SQTrue if the instance at position -2 in the stack is an instance of the class object at position -1 in the stack.\n    :remarks: The function doesn't pop any object from the stack.\n\nDetermines if an object is an instance of a certain class. Expects an instance and a class in the stack.\n\n\n\n\n\n.. _sq_newmember:\n\n.. c:function:: SQRESULT sq_newmember(HSQUIRRELVM v, SQInteger idx, SQBool bstatic)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target table in the stack\n    :param SQBool bstatic: if SQTrue creates a static member.\n    :returns: a SQRESULT\n    :remarks: Invokes the _newmember metamethod in the class. it only works on classes.\n\npops a key, a value and an object (which will be set as attribute of the member) from the stack and performs a new slot operation on the class that is at position idx in the stack; if the slot does not exist, it will be created.\n\n\n\n\n\n.. _sq_newslot:\n\n.. c:function:: SQRESULT sq_newslot(HSQUIRRELVM v, SQInteger idx, SQBool bstatic)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target table in the stack\n    :param SQBool bstatic: if SQTrue creates a static member. This parameter is only used if the target object is a class.\n    :returns: a SQRESULT\n    :remarks: Invokes the _newslot metamethod in the table delegate. it only works on tables and classes.\n\npops a key and a value from the stack and performs a set operation on the table or class that is at position idx in the stack, if the slot does not exist it will be created.\n\n\n\n\n\n.. _sq_next:\n\n.. c:function:: SQRESULT sq_next(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target object in the stack\n    :returns: a SQRESULT\n\nPushes in the stack the next key and value of an array, table, or class slot. To start the iteration this function expects a null value on top of the stack; at every call the function will substitute the null value with an iterator and push key and value of the container slot. Every iteration the application has to pop the previous key and value but leave the iterator(that is used as reference point for the next iteration). The function will fail when all slots have been iterated(see Tables and arrays manipulation).\n\n\n\n\n\n.. _sq_rawdeleteslot:\n\n.. c:function:: SQRESULT sq_rawdeleteslot(HSQUIRRELVM v, SQInteger idx, SQBool pushval)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target table in the stack\n    :param SQBool pushval: if this param is true the function will push the value of the deleted slot.\n    :returns: a SQRESULT\n\nDeletes a slot from a table without employing the _delslot metamethod. Pops a key from the stack and delete the slot indexed by it from the table at position idx in the stack; if the slot does not exist nothing happens.\n\n\n\n\n\n.. _sq_rawget:\n\n.. c:function:: SQRESULT sq_rawget(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target object in the stack\n    :returns: a SQRESULT\n    :remarks: Only works on tables and arrays.\n\npops a key from the stack and performs a get operation on the object at position idx in the stack, without employing delegation or metamethods.\n\n\n\n\n\n.. _sq_rawnewmember:\n\n.. c:function:: SQRESULT sq_rawnewmember(HSQUIRRELVM v, SQInteger idx, SQBool bstatic)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target table in the stack\n    :param SQBool bstatic: if SQTrue creates a static member.\n    :returns: a SQRESULT\n    :remarks: it only works on classes.\n\npops a key, a value and an object(that will be set as attribute of the member) from the stack and performs a new slot operation on the class that is at position idx in the stack; if the slot does not exist it will be created.\n\n\n\n\n\n.. _sq_rawset:\n\n.. c:function:: SQRESULT sq_rawset(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target object in the stack\n    :returns: a SQRESULT\n    :remarks: it only works on tables and arrays. if the function fails nothing will be pushed in the stack.\n\npops a key and a value from the stack and performs a set operation on the object at position idx in the stack, without employing delegation or metamethods.\n\n\n\n\n\n.. _sq_set:\n\n.. c:function:: SQRESULT sq_set(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target object in the stack\n    :returns: a SQRESULT\n    :remarks: this call will invoke the delegation system like a normal assignment, it only works on tables, arrays and userdata.\n\npops a key and a value from the stack and performs a set operation on the object at position idx in the stack.\n\n\n\n\n\n.. _sq_setattributes:\n\n.. c:function:: SQRESULT sq_setattributes(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target class in the stack.\n    :returns: a SQRESULT\n\nSets the attribute of a class member. The function pops a key and a value from the stack and sets the attribute (indexed by the key) on the class at position idx in the stack. If key is null the function sets the class level attribute. If the function succeed, the old attribute value is pushed in the stack.\n\n\n\n\n\n.. _sq_setdelegate:\n\n.. c:function:: SQRESULT sq_setdelegate(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target object in the stack\n    :returns: a SQRESULT\n    :remarks: to remove the delegate from an object, set a null value.\n\npops a table from the stack and sets it as the delegate of the object at the position idx in the stack.\n\n\n\n\n\n.. _sq_setfreevariable:\n\n.. c:function:: SQRESULT sq_setfreevariable(HSQUIRRELVM v, SQInteger idx, SQInteger nval)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target object in the stack\n    :param SQInteger nval: 0 based index of the free variable(relative to the closure).\n    :returns: a SQRESULT\n\npops a value from the stack and sets it as a free variable of the closure at the position idx in the stack.\n\n\n\n\n\n.. _sq_weakref:\n\n.. c:function:: void sq_weakref(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index to the target object in the stack\n    :returns: a SQRESULT\n    :remarks: if the object at idx position is one of (integer, float, bool, null), the object itself is pushed instead of a weak ref.\n\npushes a weak reference to the object at position idx in the stack.\n"
  },
  {
    "path": "extlibs/squirrel/doc/source/reference/api/raw_object_handling.rst",
    "content": ".. _api_ref_raw_object_handling:\n\n===================\nRaw object handling\n===================\n\n.. _sq_addref:\n\n.. c:function:: void sq_addref(HSQUIRRELVM v, HSQOBJECT* po)\n\n    :param HSQUIRRELVM v: the target VM\n    :param HSQOBJECT* po: pointer to an object handler\n\nadds a reference to an object handler.\n\n\n\n\n\n.. _sq_getobjtypetag:\n\n.. c:function:: SQRESULT sq_getobjtypetag(HSQOBJECT* o, SQUserPointer* typetag)\n\n    :param HSQOBJECT* o: pointer to an object handler\n    :param SQUserPointer* typetag: a pointer to the variable that will store the tag\n    :returns: a SQRESULT\n    :remarks: the function works also with instances. if the target object is an instance, the typetag of it's base class is fetched.\n\ngets the typetag of a raw object reference(userdata or class).\n\n\n\n\n\n.. _sq_getrefcount:\n\n.. c:function:: SQUnsignedInteger sq_getrefcount(HSQUIRRELVM v, HSQOBJECT* po)\n\n    :param HSQUIRRELVM v: the target VM\n    :param HSQOBJECT* po: object handler\n\nreturns the number of references of a given object.\n\n\n\n\n\n.. _sq_getstackobj:\n\n.. c:function:: SQRESULT sq_getstackobj(HSQUIRRELVM v, SQInteger idx, HSQOBJECT* po)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target object in the stack\n    :param HSQOBJECT* po: pointer to an object handler\n    :returns: a SQRESULT\n\ngets an object from the stack and stores it in a object handler.\n\n\n\n\n\n.. _sq_objtobool:\n\n.. c:function:: SQBool sq_objtobool(HSQOBJECT* po)\n\n    :param HSQOBJECT* po: pointer to an object handler\n    :remarks: If the object is not a bool will always return false.\n\nreturn the bool value of a raw object reference.\n\n\n\n\n\n.. _sq_objtofloat:\n\n.. c:function:: SQFloat sq_objtofloat(HSQOBJECT* po)\n\n    :param HSQOBJECT* po: pointer to an object handler\n    :remarks: If the object is an integer will convert it to float. If the object is not a number will always return 0.\n\nreturn the float value of a raw object reference.\n\n\n\n\n\n.. _sq_objtointeger:\n\n.. c:function:: SQInteger sq_objtointeger(HSQOBJECT* po)\n\n    :param HSQOBJECT* po: pointer to an object handler\n    :remarks: If the object is a float will convert it to integer. If the object is not a number will always return 0.\n\nreturn the integer value of a raw object reference.\n\n\n\n\n\n.. _sq_objtostring:\n\n.. c:function:: const SQChar* sq_objtostring(HSQOBJECT* po)\n\n    :param HSQOBJECT* po: pointer to an object handler\n    :remarks: If the object doesn't reference a string it returns NULL.\n\nreturn the string value of a raw object reference.\n\n\n\n\n\n.. _sq_objtouserpointer:\n\n.. c:function:: SQUserPointer sq_objtouserpointer(HSQOBJECT* po)\n\n    :param HSQOBJECT* po: pointer to an object handler\n    :remarks: If the object doesn't reference a userpointer it returns NULL.\n\nreturn the userpointer value of a raw object reference.\n\n\n\n\n\n.. _sq_pushobject:\n\n.. c:function:: void sq_pushobject(HSQUIRRELVM v, HSQOBJECT obj)\n\n    :param HSQUIRRELVM v: the target VM\n    :param HSQOBJECT obj: object handler\n\npush an object referenced by an object handler into the stack.\n\n\n\n\n\n.. _sq_release:\n\n.. c:function:: SQBool sq_release(HSQUIRRELVM v, HSQOBJECT* po)\n\n    :param HSQUIRRELVM v: the target VM\n    :param HSQOBJECT* po: pointer to an object handler\n    :returns: SQTrue if the object handler released has lost all is references(the ones added with sq_addref). SQFalse otherwise.\n    :remarks: the function will reset the object handler to null when it loses all references.\n\nremove a reference from an object handler.\n\n\n\n\n\n.. _sq_resetobject:\n\n.. c:function:: void sq_resetobject(HSQOBJECT* po)\n\n    :param HSQOBJECT* po: pointer to an object handler\n    :remarks: Every object handler has to be initialized with this function.\n\nresets(initialize) an object handler.\n"
  },
  {
    "path": "extlibs/squirrel/doc/source/reference/api/stack_operations.rst",
    "content": ".. _api_ref_stack_operations:\n\n================\nStack Operations\n================\n\n.. _sq_cmp:\n\n.. c:function:: SQInteger sq_cmp(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n    :returns: > 0 if obj1>obj2\n    :returns: == 0 if obj1==obj2\n    :returns: < 0 if obj1<obj2\n\ncompares 2 object from the top of the stack. obj2 should be pushed before obj1.\n\n\n\n\n\n.. _sq_gettop:\n\n.. c:function:: SQInteger sq_gettop(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n    :returns: an integer representing the index of the top of the stack\n\nreturns the index of the top of the stack\n\n\n\n\n\n.. _sq_pop:\n\n.. c:function:: void sq_pop(HSQUIRRELVM v, SQInteger nelementstopop)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger nelementstopop: the number of elements to pop\n\npops n elements from the stack\n\n\n\n\n\n.. _sq_poptop:\n\n.. c:function:: void sq_poptop(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n\npops 1 object from the stack\n\n\n\n\n\n.. _sq_push:\n\n.. c:function:: void sq_push(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: the index in the stack of the value that has to be pushed\n\npushes in the stack the value at the index idx\n\n\n\n\n\n.. _sq_remove:\n\n.. c:function:: void sq_remove(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the element that has to be removed\n\nremoves an element from an arbitrary position in the stack\n\n\n\n\n\n.. _sq_reservestack:\n\n.. c:function:: SQRESULT sq_reservestack(HSQUIRRELVM v, SQInteger nsize)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger nsize: required stack size\n    :returns: a SQRESULT\n\nensure that the stack space left is at least of a specified size.If the stack is smaller it will automatically grow. If there's a metamethod currently running the function will fail and the stack will not be resized, this situation has to be considered a \"stack overflow\".\n\n\n\n\n\n.. _sq_settop:\n\n.. c:function:: void sq_settop(HSQUIRRELVM v, SQInteger v)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger v: the new top index\n\nresize the stack. If new top is bigger then the current top the function will push nulls.\n"
  },
  {
    "path": "extlibs/squirrel/doc/source/reference/api/virtual_machine.rst",
    "content": ".. _api_ref_virtual_machine:\n\n===============\nVirtual Machine\n===============\n\n\n.. _sq_close:\n\n.. c:function:: void sq_close(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n\nreleases a squirrel VM and all related friend VMs\n\n\n\n\n\n.. _sq_geterrorfunc:\n\n.. c:function:: SQPRINTFUNCTION sq_geterrorfunc(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n    :returns: a pointer to a SQPRINTFUNCTION, or NULL if no function has been set.\n\nreturns the current error function of the given Virtual machine. (see sq_setprintfunc())\n\n\n\n\n\n.. _sq_getforeignptr:\n\n.. c:function:: SQUserPointer sq_getforeignptr(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n    :returns: the current VMs foreign pointer.\n\nReturns the foreign pointer of a VM instance.\n\n\n\n\n\n.. _sq_getprintfunc:\n\n.. c:function:: SQPRINTFUNCTION sq_getprintfunc(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n    :returns: a pointer to a SQPRINTFUNCTION, or NULL if no function has been set.\n\nreturns the current print function of the given Virtual machine. (see sq_setprintfunc())\n\n\n\n\n\n.. _sq_getsharedforeignptr:\n\n.. c:function:: SQUserPointer sq_getsharedforeignptr(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n    :returns: the current VMs shared foreign pointer\n\nReturns the shared foreign pointer of a group of friend VMs\n\n\n\n\n\n.. _sq_getsharedreleasehook:\n\n.. c:function:: SQUserPointer sq_getsharedreleasehook(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n    :returns: the current VMs release hook.\n\nReturns the shared release hook of a group of friend VMs\n\n\n\n\n\n.. _sq_getversion:\n\n.. c:function:: SQInteger sq_getversion()\n\n    :returns: version number of the vm(as in SQUIRREL_VERSION_NUMBER).\n\nreturns the version number of the vm\n\n\n\n\n\n.. _sq_getvmreleasehook:\n\n.. c:function:: SQUserPointer sq_getvmreleasehook(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n    :returns: the current VMs release hook.\n\nReturns the release hook of a VM instance\n\n\n\n\n\n.. _sq_getvmstate:\n\n.. c:function:: SQInteger sq_getvmstate(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n    :returns: the state of the vm encoded as integer value. The following constants are defined: SQ_VMSTATE_IDLE, SQ_VMSTATE_RUNNING, SQ_VMSTATE_SUSPENDED.\n\nreturns the execution state of a virtual machine\n\n\n\n\n\n.. _sq_move:\n\n.. c:function:: void sq_move(HSQUIRRELVM dest, HSQUIRRELVM src, SQInteger idx)\n\n    :param HSQUIRRELVM dest: the destination VM\n    :param HSQUIRRELVM src: the source VM\n    :param SQInteger idx: the index in the source stack of the value that has to be moved\n\npushes the object at the position 'idx' of the source vm stack in the destination vm stack\n\n\n\n\n\n.. _sq_newthread:\n\n.. c:function:: HSQUIRRELVM sq_newthread(HSQUIRRELVM friendvm, SQInteger initialstacksize)\n\n    :param HSQUIRRELVM friendvm: a friend VM\n    :param SQInteger initialstacksize: the size of the stack in slots(number of objects)\n    :returns: a pointer to the new VM.\n    :remarks: By default the roottable is shared with the VM passed as first parameter. The new VM lifetime is bound to the \"thread\" object pushed in the stack and behave like a normal squirrel object.\n\ncreates a new vm friendvm of the one passed as first parmeter and pushes it in its stack as \"thread\" object.\n\n\n\n\n\n.. _sq_open:\n\n.. c:function:: HSQUIRRELVM sq_open(SQInteger initialstacksize)\n\n    :param SQInteger initialstacksize: the size of the stack in slots(number of objects)\n    :returns: an handle to a squirrel vm\n    :remarks: the returned VM has to be released with sq_releasevm\n\ncreates a new instance of a squirrel VM that consists in a new execution stack.\n\n\n\n\n\n.. _sq_pushconsttable:\n\n.. c:function:: void sq_pushconsttable(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n\npushes the current const table in the stack\n\n\n\n\n\n.. _sq_pushregistrytable:\n\n.. c:function:: void sq_pushregistrytable(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n\npushes the registry table in the stack\n\n\n\n\n\n.. _sq_pushroottable:\n\n.. c:function:: void sq_pushroottable(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n\npushes the current root table in the stack\n\n\n\n\n\n.. _sq_setconsttable:\n\n.. c:function:: void sq_setconsttable(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n\npops a table from the stack and set it as const table\n\n\n\n\n\n.. _sq_seterrorhandler:\n\n.. c:function:: void sq_seterrorhandler(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n    :remarks: the error handler is shared by friend VMs\n\npops from the stack a closure or native closure an sets it as runtime-error handler.\n\n\n\n\n\n.. _sq_setforeignptr:\n\n.. c:function:: void sq_setforeignptr(HSQUIRRELVM v, SQUserPointer p)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQUserPointer p: The pointer that has to be set\n\nSets the foreign pointer of a certain VM instance. The foreign pointer is an arbitrary user defined pointer associated to a VM (by default is value id 0). This pointer is ignored by the VM.\n\n\n\n\n\n.. _sq_setprintfunc:\n\n.. c:function:: void sq_setprintfunc(HSQUIRRELVM v, SQPRINTFUNCTION printfunc, SQPRINTFUNCTION errorfunc)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQPRINTFUNCTION printfunc: a pointer to the print func or NULL to disable the output.\n    :param SQPRINTFUNCTION errorfunc: a pointer to the error func or NULL to disable the output.\n    :remarks: the print func has the following prototype: void printfunc(HSQUIRRELVM v,const SQChar \\*s,...)\n\nsets the print function of the virtual machine. This function is used by the built-in function '::print()' to output text.\n\n\n\n\n\n.. _sq_setroottable:\n\n.. c:function:: void sq_setroottable(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n\npops a table from the stack and set it as root table\n\n\n\n\n\n.. _sq_setsharedforeignptr:\n\n.. c:function:: void sq_setsharedforeignptr(HSQUIRRELVM v, SQUserPointer p)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQUserPointer p: The pointer that has to be set\n\nSets the shared foreign pointer. The foreign pointer is an arbitrary user defined pointer associated to a group of friend VMs (by default is value id 0). After a \"main\" VM is created using sq_open() all friend VMs created with sq_newthread share the same shared pointer.\n\n\n\n\n\n.. _sq_setsharedreleasehook:\n\n.. c:function:: void sq_setsharedreleasehook(HSQUIRRELVM v, SQRELESEHOOK hook)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQRELESEHOOK hook: The hook that has to be set\n\nSets the release hook of a certain VM group. The release hook is invoked when the last vm of the group vm is destroyed (usually when sq_close() is invoked). The userpointer passed to the function is the shared foreignpointer(see sq_getsharedforeignptr()). After a \"main\" VM is created using sq_open() all friend VMs created with sq_newthread() share the same shared release hook.\n\n\n\n\n\n.. _sq_setvmreleasehook:\n\n.. c:function:: void sq_setvmreleasehook(HSQUIRRELVM v, SQRELESEHOOK hook)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQRELESEHOOK hook: The hook that has to be set\n\nSets the release hook of a certain VM instance. The release hook is invoked when the vm is destroyed. The userpointer passed to the function is the vm foreignpointer (see sq_setforeignpointer())\n\n\n\n\n\n.. _sq_suspendvm:\n\n.. c:function:: HRESULT sq_suspendvm(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n    :returns: an SQRESULT(that has to be returned by a C function)\n    :remarks: sq_result can only be called as return expression of a C function. The function will fail is the suspension is done through more C calls or in a metamethod.\n\nSuspends the execution of the specified vm.\n\n*.eg*\n\n::\n\n    SQInteger suspend_vm_example(HSQUIRRELVM v)\n    {\n        return sq_suspendvm(v);\n    }\n\n\n\n\n\n\n.. _sq_wakeupvm:\n\n.. c:function:: HRESULT sq_wakeupvm(HSQUIRRELVM v, SQBool resumedret, SQBool retval, SQBool raiseerror, SQBool throwerror)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQBool resumedret: if true the function will pop a value from the stack and use it as return value for the function that has previously suspended the virtual machine.\n    :param SQBool retval: if true the function will push the return value of the function that suspend the excution or the main function one.\n    :param SQBool raiseerror: if true, if a runtime error occurs during the execution of the call, the vm will invoke the error handler.\n    :param SQBool throwerror: if true, the vm will thow an exception as soon as is resumed. the exception payload must be set beforehand invoking sq_thowerror().\n    :returns: an HRESULT.\n\nwake up the execution a previously suspended virtual machine\n"
  },
  {
    "path": "extlibs/squirrel/doc/source/reference/api_reference.rst",
    "content": ".. _api_reference:\n\n\n*************\nAPI Reference\n*************\n\n.. toctree::\n   api/virtual_machine.rst\n   api/compiler.rst\n   api/stack_operations.rst\n   api/object_creation_and_handling.rst\n   api/calls.rst\n   api/object_manipulation.rst\n   api/bytecode_serialization.rst\n   api/raw_object_handling.rst\n   api/garbage_collector.rst\n   api/debug_interface.rst\n"
  },
  {
    "path": "extlibs/squirrel/doc/source/reference/embedding/build_configuration.rst",
    "content": ".. _embedding_build_configuration:\n\n========================\nBuild Configuration\n========================\n\n.. _unicode:\n\n----------\nUnicode\n----------\n\n.. index:: single: Unicode\n\nBy default Squirrel strings are plain 8-bits ASCII characters; however if the symbol\n'SQUNICODE' is defined the VM, compiler and API will use 16-bit characters (UCS2).\n\n.. _squirrel_64bits:\n\n--------------------------------\nSquirrel on 64-bit architectures\n--------------------------------\n\n.. index::\n    single: Squirrel on 64-bit architectures\n    single: 64 bits\n\nSquirrel can be compiled on 64-bit architectures by defining '_SQ64' in the C++\npreprocessor. This flag should be defined in any project that includes 'squirrel.h'.\n\n.. _userdata_alignment:\n\n------------------\nUserdata Alignment\n------------------\n\n.. index:: single: Userdata Alignment\n\nBoth class instances and userdatas can have a buffer associated to them.\nSquirrel specifies the alignment(in bytes) through the preprocessor defining 'SQ_ALIGNMENT'.\nBy default SQ_ALIGNMENT is defined as 4 for 32-bit builds and 8 for 64-bit builds and builds that use 64-bit floats.\nIt is possible to override the value of SQ_ALIGNMENT respecting the following rules.\nSQ_ALIGNMENT shall be less than or equal to SQ_MALLOC alignments, and it shall be power of 2.\n\n.. note:: This only applies for userdata allocated by the VM, specified via sq_setclassudsize() or belonging to a userdata object.\n        userpointers specified by the user are not affected by alignment rules.\n\n.. _standalone_vm:\n\n------------------------------------\nStand-alone VM without compiler\n------------------------------------\n\n.. index:: single: Stand-alone VM without compiler\n\nSquirrel's VM can be compiled without its compiler by defining 'NO_COMPILER' in the C++ preprocessor.\nWhen 'NO_COMPILER' is defined all function related to the compiler (eg. sq_compile) will fail. Other functions\nthat conditionally load precompiled bytecode or compile a file (eg. sqstd_dofile) will only work with\nprecompiled bytecode.\n"
  },
  {
    "path": "extlibs/squirrel/doc/source/reference/embedding/calling_a_function.rst",
    "content": ".. _embedding_calling_a_function:\n\n==================\nCalling a function\n==================\n\nTo call a squirrel function it is necessary to push the function in the stack followed by the\nparameters and then call the function sq_call.\nThe function will pop the parameters and push the return value if the last sq_call\nparameter is > 0. ::\n\n    sq_pushroottable(v);\n    sq_pushstring(v,\"foo\",-1);\n    sq_get(v,-2); //get the function from the root table\n    sq_pushroottable(v); //'this' (function environment object)\n    sq_pushinteger(v,1);\n    sq_pushfloat(v,2.0);\n    sq_pushstring(v,\"three\",-1);\n    sq_call(v,4,SQFalse,SQFalse);\n    sq_pop(v,2); //pops the roottable and the function\n\nthis is equivalent to the following Squirrel code::\n\n    foo(1,2.0,\"three\");\n\nIf a runtime error occurs (or a exception is thrown) during the squirrel code execution\nthe sq_call will fail.\n"
  },
  {
    "path": "extlibs/squirrel/doc/source/reference/embedding/compiling_a_script.rst",
    "content": ".. embedding_compiling_a_script:\n\n==================\nCompiling a script\n==================\n\nYou can compile a Squirrel script with the function *sq_compile*.::\n\n    typedef SQInteger (*SQLEXREADFUNC)(SQUserPointer userdata);\n\n    SQRESULT sq_compile(HSQUIRRELVM v,SQLEXREADFUNC read,SQUserPointer p,\n                const SQChar *sourcename,SQBool raiseerror);\n\nIn order to compile a script is necessary for the host application to implement a reader\nfunction (SQLEXREADFUNC); this function is used to feed the compiler with the script\ndata.\nThe function is called every time the compiler needs a character; It has to return a\ncharacter code if succeed or 0 if the source is finished.\n\nIf sq_compile succeeds, the compiled script will be pushed as Squirrel function in the\nstack.\n\n.. :note::\n    In order to execute the script, the function generated by *sq_compile()* has\n    to be called through *sq_call()*\n\nHere an example of a 'read' function that read from a file: ::\n\n    SQInteger file_lexfeedASCII(SQUserPointer file)\n    {\n        int ret;\n        char c;\n        if( ( ret=fread(&c,sizeof(c),1,(FILE *)file )>0) )\n            return c;\n        return 0;\n    }\n\n    int compile_file(HSQUIRRELVM v,const char *filename)\n    {\n        FILE *f=fopen(filename,\"rb\");\n        if(f)\n        {\n             sq_compile(v,file_lexfeedASCII,f,filename,1);\n             fclose(f);\n             return 1;\n        }\n        return 0;\n    }\n\nWhen the compiler fails for a syntax error it will try to call the 'compiler error handler';\nthis function must be declared as follow: ::\n\n    typedef void (*SQCOMPILERERROR)(HSQUIRRELVM /*v*/,const SQChar * /*desc*/,const SQChar * /*source*/,\n                            SQInteger /*line*/,SQInteger /*column*/);\n\nand can be set with the following API call::\n\n    void sq_setcompilererrorhandler(HSQUIRRELVM v,SQCOMPILERERROR f);\n"
  },
  {
    "path": "extlibs/squirrel/doc/source/reference/embedding/creating_a_c_function.rst",
    "content": ".. _embedding_creating_a_c_function:\n\n===================\nCreate a C function\n===================\n\nA native C function must have the following prototype: ::\n\n    typedef SQInteger (*SQFUNCTION)(HSQUIRRELVM);\n\nThe parameters is an handle to the calling VM and the return value is an integer\nrespecting the following rules:\n\n* 1 if the function returns a value\n* 0 if the function does not return a value\n* SQ_ERROR runtime error is thrown\n\nIn order to obtain a new callable squirrel function from a C function pointer, is necessary\nto call sq_newclosure() passing the C function to it; the new Squirrel function will be\npushed in the stack.\n\nWhen the function is called, the stackbase is the first parameter of the function and the\ntop is the last. In order to return a value the function has to push it in the stack and\nreturn 1.\n\nFunction parameters are in the stack from position 1 ('this') to *n*.\n*sq_gettop()* can be used to determinate the number of parameters.\n\nIf the function has free variables, those will be in the stack after the explicit parameters\nan can be handled as normal parameters. Note also that the value returned by *sq_gettop()* will be\naffected by free variables. *sq_gettop()* will return the number of parameters plus\nnumber of free variables.\n\nHere an example, the following function print the value of each argument and return the\nnumber of arguments. ::\n\n    SQInteger print_args(HSQUIRRELVM v)\n    {\n        SQInteger nargs = sq_gettop(v); //number of arguments\n        for(SQInteger n=1;n<=nargs;n++)\n        {\n            printf(\"arg %d is \",n);\n            switch(sq_gettype(v,n))\n            {\n                case OT_NULL:\n                    printf(\"null\");\n                    break;\n                case OT_INTEGER:\n                    printf(\"integer\");\n                    break;\n                case OT_FLOAT:\n                    printf(\"float\");\n                    break;\n                case OT_STRING:\n                    printf(\"string\");\n                    break;\n                case OT_TABLE:\n                    printf(\"table\");\n                    break;\n                case OT_ARRAY:\n                    printf(\"array\");\n                    break;\n                case OT_USERDATA:\n                    printf(\"userdata\");\n                    break;\n                case OT_CLOSURE:\n                    printf(\"closure(function)\");\n                    break;\n                case OT_NATIVECLOSURE:\n                    printf(\"native closure(C function)\");\n                    break;\n                case OT_GENERATOR:\n                    printf(\"generator\");\n                    break;\n                case OT_USERPOINTER:\n                    printf(\"userpointer\");\n                    break;\n                case OT_CLASS:\n                    printf(\"class\");\n                    break;\n                case OT_INSTANCE:\n                    printf(\"instance\");\n                    break;\n                case OT_WEAKREF:\n                    printf(\"weak reference\");\n                    break;\n                default:\n                    return sq_throwerror(v,\"invalid param\"); //throws an exception\n            }\n        }\n        printf(\"\\n\");\n        sq_pushinteger(v,nargs); //push the number of arguments as return value\n        return 1; //1 because 1 value is returned\n    }\n\nHere an example of how to register a function::\n\n    SQInteger register_global_func(HSQUIRRELVM v,SQFUNCTION f,const char *fname)\n    {\n        sq_pushroottable(v);\n        sq_pushstring(v,fname,-1);\n        sq_newclosure(v,f,0); //create a new function\n        sq_newslot(v,-3,SQFalse);\n        sq_pop(v,1); //pops the root table\n        return 0;\n    }\n"
  },
  {
    "path": "extlibs/squirrel/doc/source/reference/embedding/debug_interface.rst",
    "content": ".. _embedding_debug_interface:\n\n===============\nDebug Interface\n===============\n\nThe squirrel VM exposes a very simple debug interface that allows to easily built a full\nfeatured debugger.\nThrough the functions sq_setdebughook and sq_setnativedebughook is possible in fact to set a callback function that\nwill be called every time the VM executes an new line of a script or if a function get\ncalled/returns. The callback will pass as argument the current line the current source and the\ncurrent function name (if any).::\n\n    SQUIRREL_API void sq_setdebughook(HSQUIRRELVM v);\n\nor ::\n\n    SQUIRREL_API void sq_setnativedebughook(HSQUIRRELVM v,SQDEBUGHOOK hook);\n\nThe following code shows how a debug hook could look like(obviously is possible to\nimplement this function in C as well). ::\n\n    function debughook(event_type,sourcefile,line,funcname)\n    {\n        local fname=funcname?funcname:\"unknown\";\n        local srcfile=sourcefile?sourcefile:\"unknown\"\n        switch (event_type) {\n        case 'l': //called every line(that contains some code)\n            ::print(\"LINE line [\" + line + \"] func [\" + fname + \"]\");\n            ::print(\"file [\" + srcfile + \"]\\n\");\n            break;\n        case 'c': //called when a function has been called\n            ::print(\"LINE line [\" + line + \"] func [\" + fname + \"]\");\n            ::print(\"file [\" + srcfile + \"]\\n\");\n            break;\n        case 'r': //called when a function returns\n            ::print(\"LINE line [\" + line + \"] func [\" + fname + \"]\");\n            ::print(\"file [\" + srcfile + \"]\\n\");\n            break;\n        }\n    }\n\nThe parameter *event_type* can be 'l' ,'c' or 'r' ; a hook with a 'l' event is called for each line that\ngets executed, 'c' every time a function gets called and 'r' every time a function returns.\n\nA full-featured debugger always allows displaying local variables and calls stack.\nThe call stack information are retrieved through sq_getstackinfos()::\n\n    SQInteger sq_stackinfos(HSQUIRRELVM v,SQInteger level,SQStackInfos *si);\n\nWhile the local variables info through sq_getlocal()::\n\n    SQInteger sq_getlocal(HSQUIRRELVM v,SQUnsignedInteger level,SQUnsignedInteger nseq);\n\nIn order to receive line callbacks the scripts have to be compiled with debug infos enabled\nthis is done through sq_enabledebuginfo(); ::\n\n    void sq_enabledebuginfo(HSQUIRRELVM v, SQInteger debuginfo);\n"
  },
  {
    "path": "extlibs/squirrel/doc/source/reference/embedding/error_conventions.rst",
    "content": ".. _embedding_error_convetions:\n\n\n========================\nError Conventions\n========================\n\n.. index::\n    single: Error Conventions\n\nMost of the functions in the API return a SQRESULT value; SQRESULT indicates if a\nfunction completed successfully or not.\nThe macros SQ_SUCCEEDED() and SQ_FAILED() are used to test the result of a function.::\n\n    if(SQ_FAILED(sq_getstring(v,-1,&s)))\n        printf(\"getstring failed\");\n"
  },
  {
    "path": "extlibs/squirrel/doc/source/reference/embedding/memory_management.rst",
    "content": ".. _embedding_memory_management:\n\n========================\nMemory Management\n========================\n\n.. index:: single: Memory Management\n\nSquirrel uses reference counting (RC) as primary system for memory management;\nhowever, the virtual machine (VM) has an auxiliary\nmark and sweep garbage collector that can be invoked on demand.\n\nThere are 2 possible compile time options:\n\n    * The default configuration consists in RC plus a mark and sweep garbage collector.\n      The host program can call the function sq_collectgarbage() and perform a garbage collection cycle\n      during the program execution. The garbage collector isn't invoked by the VM and has to\n      be explicitly called by the host program.\n\n    * The second a situation consists in RC only(define NO_GARBAGE_COLLECTOR); in this case is impossible for\n      the VM to detect reference cycles, so is the programmer that has to solve them explicitly in order to\n      avoid memory leaks.\n\nThe only advantage introduced by the second option is that saves 2 additional\npointers that have to be stored for each object in the default configuration with\ngarbage collector(8 bytes for 32 bits systems).\nThe types involved are: tables, arrays, functions, threads, userdata and generators; all other\ntypes are untouched. These options do not affect execution speed.\n"
  },
  {
    "path": "extlibs/squirrel/doc/source/reference/embedding/references_from_c.rst",
    "content": ".. embedding_references_from_c:\n\n========================================================\nMantaining references to Squirrel values from the C API\n========================================================\n\nSquirrel allows to reference values through the C API; the function sq_getstackobj() gets\na handle to a squirrel object(any type). The object handle can be used to control the lifetime\nof an object by adding or removing references to it( see sq_addref() and sq_release()).\nThe object can be also re-pushed in the VM stack using sq_pushobject().::\n\n    HSQOBJECT obj;\n\n    sq_resetobject(&obj); //initialize the handle\n    sq_getstackobj(v,-2,&obj); //retrieve an object handle from the pos -2\n    sq_addref(v,&obj); //adds a reference to the object\n\n    ... //do stuff\n\n    sq_pushobject(v,obj); //push the object in the stack\n    sq_release(v,&obj); //relese the object\n"
  },
  {
    "path": "extlibs/squirrel/doc/source/reference/embedding/runtime_error_handling.rst",
    "content": ".. _embedding_runtime_error_handling:\n\n======================\nRuntime error handling\n======================\n\nWhen an exception is not handled by Squirrel code with a try/catch statement, a runtime\nerror is raised and the execution of the current program is interrupted. It is possible to\nset a call back function to intercept the runtime error from the host program; this is\nuseful to show meaningful errors to the script writer and for implementing visual\ndebuggers.\nThe following API call pops a Squirrel function from the stack and sets it as error handler.::\n\n    SQUIRREL_API void sq_seterrorhandler(HSQUIRRELVM v);\n\nThe error handler is called with 2 parameters, an environment object (this) and a object.\nThe object can be any squirrel type.\n"
  },
  {
    "path": "extlibs/squirrel/doc/source/reference/embedding/tables_and_arrays_manipulation.rst",
    "content": ".. _embedding_tables_and_arrays_manipulation:\n\n==============================\nTables and arrays manipulation\n==============================\n\nA new table is created calling sq_newtable, this function pushes a new table in the stack.::\n\n    void sq_newtable(HSQUIRRELVM v);\n\nTo create a new slot::\n\n    SQRESULT sq_newslot(HSQUIRRELVM v,SQInteger idx,SQBool bstatic);\n\nTo set or get the table delegate::\n\n    SQRESULT sq_setdelegate(HSQUIRRELVM v,SQInteger idx);\n    SQRESULT sq_getdelegate(HSQUIRRELVM v,SQInteger idx);\n\n\nA new array is created calling sq_newarray, the function pushes a new array in the\nstack; if the parameters size is bigger than 0 the elements are initialized to null.::\n\n    void sq_newarray (HSQUIRRELVM v,SQInteger size);\n\nTo append a value to the back of the array::\n\n    SQRESULT sq_arrayappend(HSQUIRRELVM v,SQInteger idx);\n\nTo remove a value from the back of the array::\n\n    SQRESULT sq_arraypop(HSQUIRRELVM v,SQInteger idx,SQInteger pushval);\n\nTo resize the array::\n\n    SQRESULT sq_arrayresize(HSQUIRRELVM v,SQInteger idx,SQInteger newsize);\n\nTo retrieve the size of a table or an array you must use sq_getsize()::\n\n    SQInteger sq_getsize(HSQUIRRELVM v,SQInteger idx);\n\nTo set a value in an array or table::\n\n    SQRESULT sq_set(HSQUIRRELVM v,SQInteger idx);\n\nTo get a value from an array or table::\n\n    SQRESULT sq_get(HSQUIRRELVM v,SQInteger idx);\n\nTo get or set a value from a table without employing delegation::\n\n    SQRESULT sq_rawget(HSQUIRRELVM v,SQInteger idx);\n    SQRESULT sq_rawset(HSQUIRRELVM v,SQInteger idx);\n\nTo iterate a table or an array::\n\n    SQRESULT sq_next(HSQUIRRELVM v,SQInteger idx);\n\nHere an example of how to perform an iteration: ::\n\n    //push your table/array here\n    sq_pushnull(v)  //null iterator\n    while(SQ_SUCCEEDED(sq_next(v,-2)))\n    {\n        //here -1 is the value and -2 is the key\n\n        sq_pop(v,2); //pops key and val before the nex iteration\n    }\n\n    sq_pop(v,1); //pops the null iterator\n"
  },
  {
    "path": "extlibs/squirrel/doc/source/reference/embedding/the_registry_table.rst",
    "content": ".. _embedding_the_registry_table:\n\n==================\nThe registry table\n==================\n\nThe registry table is an hidden table shared between vm and all his thread(friend vms).\nThis table is accessible only through the C API and is meant to be an utility structure\nfor native C library implementation.\nFor instance the sqstdlib(squirrel standard library)uses it to store configuration and shared objects\ndelegates.\nThe registry is accessible through the API call *sq_pushregistrytable()*.::\n\n    void sq_pushregistrytable(HSQUIRRELVM v);\n"
  },
  {
    "path": "extlibs/squirrel/doc/source/reference/embedding/the_stack.rst",
    "content": ".. _embedding_the_stack:\n\n\n==========\nThe Stack\n==========\n\nSquirrel exchanges values with the virtual machine through a stack. This mechanism has\nbeen inherited from the language Lua.\nFor instance to call a Squirrel function from C it is necessary to push the function and the\narguments in the stack and then invoke the function; also when Squirrel calls a C\nfunction the parameters will be in the stack as well.\n\n-------------\nStack indexes\n-------------\n\nMany API functions can arbitrarily refer to any element in the stack through an index.\nThe stack indexes follow those conventions:\n\n* 1 is the stack base\n* Negative indexes are considered an offset from top of the stack. For instance -1 isthe top of the stack.\n* 0 is an invalid index\n\nHere an example (let's pretend that this table is the VM stack)\n\n+------------+--------------------+--------------------+\n| **STACK**  | **positive index** | **negative index** |\n+============+====================+====================+\n| \"test\"     | 4                  | -1(top)            |\n+------------+--------------------+--------------------+\n| 1          | 3                  | -2                 |\n+------------+--------------------+--------------------+\n| 0.5        | 2                  | -3                 |\n+------------+--------------------+--------------------+\n| \"foo\"      | 1(base)            | -4                 |\n+------------+--------------------+--------------------+\n\nIn this case, the function *sq_gettop* would return 4;\n\n------------------\nStack manipulation\n------------------\n\nThe API offers several functions to push and retrieve data from the Squirrel stack.\n\nTo push a value that is already present in the stack in the top position::\n\n    void sq_push(HSQUIRRELVM v,SQInteger idx);\n\nTo pop an arbitrary number of elements::\n\n    void sq_pop(HSQUIRRELVM v,SQInteger nelemstopop);\n\nTo remove an element from the stack::\n\n    void sq_remove(HSQUIRRELVM v,SQInteger idx);\n\nTo retrieve the top index (and size) of the current\nvirtual stack you must call *sq_gettop* ::\n\n    SQInteger sq_gettop(HSQUIRRELVM v);\n\nTo force the stack to a certain size you can call *sq_settop* ::\n\n    void sq_settop(HSQUIRRELVM v,SQInteger newtop);\n\nIf the newtop is bigger than the previous one, the new positions in the stack will be\nfilled with null values.\n\nThe following function pushes a C value into the stack::\n\n    void sq_pushstring(HSQUIRRELVM v,const SQChar *s,SQInteger len);\n    void sq_pushfloat(HSQUIRRELVM v,SQFloat f);\n    void sq_pushinteger(HSQUIRRELVM v,SQInteger n);\n    void sq_pushuserpointer(HSQUIRRELVM v,SQUserPointer p);\n    void sq_pushbool(HSQUIRRELVM v,SQBool b);\n\nthis function pushes a null into the stack::\n\n    void sq_pushnull(HSQUIRRELVM v);\n\nreturns the type of the value in a arbitrary position in the stack::\n\n    SQObjectType sq_gettype(HSQUIRRELVM v,SQInteger idx);\n\nthe result can be one of the following values: ::\n\n    OT_NULL,OT_INTEGER,OT_FLOAT,OT_STRING,OT_TABLE,OT_ARRAY,OT_USERDATA,\n    OT_CLOSURE,OT_NATIVECLOSURE,OT_GENERATOR,OT_USERPOINTER,OT_BOOL,OT_INSTANCE,OT_CLASS,OT_WEAKREF\n\nThe following functions convert a squirrel value in the stack to a C value::\n\n    SQRESULT sq_getstring(HSQUIRRELVM v,SQInteger idx,const SQChar **c);\n    SQRESULT sq_getstringandsize(HSQUIRRELVM v,SQInteger idx,const SQChar **c,SQInteger size);\n    SQRESULT sq_getinteger(HSQUIRRELVM v,SQInteger idx,SQInteger *i);\n    SQRESULT sq_getfloat(HSQUIRRELVM v,SQInteger idx,SQFloat *f);\n    SQRESULT sq_getuserpointer(HSQUIRRELVM v,SQInteger idx,SQUserPointer *p);\n    SQRESULT sq_getuserdata(HSQUIRRELVM v,SQInteger idx,SQUserPointer *p,SQUserPointer *typetag);\n    SQRESULT sq_getbool(HSQUIRRELVM v,SQInteger idx,SQBool *p);\n\nThe function sq_cmp compares 2 values from the stack and returns their relation (like strcmp() in ANSI C).::\n\n    SQInteger sq_cmp(HSQUIRRELVM v);\n"
  },
  {
    "path": "extlibs/squirrel/doc/source/reference/embedding/userdata_and_userpointers.rst",
    "content": ".. _embedding_userdata_and_userpointers:\n\n=========================\nUserdata and UserPointers\n=========================\n\nSquirrel allows the host application put arbitrary data chunks into a Squirrel value, this is\npossible through the data type userdata.::\n\n    SQUserPointer sq_newuserdata(HSQUIRRELVM v,SQUnsignedInteger size);\n\nWhen the function *sq_newuserdata* is called, Squirrel allocates a new userdata with the\nspecified size, returns a pointer to his payload buffer and push the object in the stack; at\nthis point the application can do whatever it want with this memory chunk, the VM will\nautomatically take cake of the memory deallocation like for every other built-in type.\nA userdata can be passed to a function or stored in a table slot. By default Squirrel\ncannot manipulate directly userdata; however is possible to assign a delegate to it and\ndefine a behavior like it would be a table.\nBecause the application would want to do something with the data stored in a userdata\nobject when it get deleted, is possible to assign a callback that will be called by the VM\njust before deleting a certain userdata.\nThis is done through the API call *sq_setreleasehook*.::\n\n    typedef SQInteger (*SQRELEASEHOOK)(SQUserPointer,SQInteger size);\n\n    void sq_setreleasehook(HSQUIRRELVM v,SQInteger idx,SQRELEASEHOOK hook);\n\nAnother kind of userdata is the userpointer; this type is not a memory chunk like the\nnormal userdata, but just a 'void*' pointer. It cannot have a delegate and is passed by\nvalue, so pushing a userpointer doesn't cause any memory allocation.::\n\n    void sq_pushuserpointer(HSQUIRRELVM v,SQUserPointer p);\n\n"
  },
  {
    "path": "extlibs/squirrel/doc/source/reference/embedding/vm_initialization.rst",
    "content": ".. _embedding_vm_initialization:\n\n==============================\nVirtual Machine Initialization\n==============================\n\nThe first thing that a host application has to do, is create a virtual machine.\nThe host application can create any number of virtual machines through the function\n*sq_open()*.\nEvery single VM that was created using *sq_open()* has to be released with the function *sq_close()* when it is no\nlonger needed.::\n\n    int main(int argc, char* argv[])\n    {\n        HSQUIRRELVM v;\n        v = sq_open(1024); //creates a VM with initial stack size 1024\n\n        //do some stuff with squirrel here\n\n        sq_close(v);\n    }\n"
  },
  {
    "path": "extlibs/squirrel/doc/source/reference/embedding_squirrel.rst",
    "content": ".. _embedding_squirrel:\n\n***************************\n  Embedding Squirrel\n***************************\n\n*This section describes how to embed Squirrel in a host application,\nC language knowledge is required to understand this part of the manual.*\n\nBecause of his nature of extension language, Squirrel's compiler and virtual machine\nare implemented as C library. The library exposes a set of functions to compile scripts,\ncall functions, manipulate data and extend the virtual machine.\nAll declarations needed for embedding the language in an application are in the header file 'squirrel.h'.\n\n.. toctree::\n    embedding/memory_management.rst\n    embedding/build_configuration.rst\n    embedding/error_conventions.rst\n    embedding/vm_initialization.rst\n    embedding/the_stack.rst\n    embedding/runtime_error_handling.rst\n    embedding/compiling_a_script.rst\n    embedding/calling_a_function.rst\n    embedding/creating_a_c_function.rst\n    embedding/tables_and_arrays_manipulation.rst\n    embedding/userdata_and_userpointers.rst\n    embedding/the_registry_table.rst\n    embedding/references_from_c.rst\n    embedding/debug_interface.rst\n"
  },
  {
    "path": "extlibs/squirrel/doc/source/reference/index.rst",
    "content": ".. _reference:\n\n#################################\n  Squirrel 3.1 Reference Manual\n#################################\n\nCopyright (c) 2003-2016 Alberto Demichelis\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n\n.. toctree::\n   :maxdepth: 3\n   :numbered:\n\n   introduction.rst\n   language.rst\n   embedding_squirrel.rst\n   api_reference.rst\n"
  },
  {
    "path": "extlibs/squirrel/doc/source/reference/introduction.rst",
    "content": ".. _introduction:\n\n************\nIntroduction\n************\n\n.. index::\n    single: introduction\n\nSquirrel is a high-level, imperative-OO programming language, designed to be a powerful\nscripting tool that fits within the size, memory bandwidth, and real-time requirements of\napplications like games.\nSquirrel offers a wide range of features like dynamic typing, delegation, higher\norder functions, generators, tail recursion, exception handling, automatic memory\nmanagement while fitting both compiler and virtual machine into about 6k lines of C++\ncode.\n"
  },
  {
    "path": "extlibs/squirrel/doc/source/reference/language/arrays.rst",
    "content": ".. _arrays:\n\n\n=================\nArrays\n=================\n\n.. index::\n    single: Arrays\n\nAn array is a sequence of values indexed by a integer number from 0 to the size of the\narray minus 1. Arrays elements can be obtained through their index.::\n\n    local a=[\"I'm a string\", 123]\n    print(typeof a[0]) //prints \"string\"\n    print(typeof a[1]) //prints \"integer\"\n\nResizing, insertion, deletion of arrays and arrays elements is done through a set of\nstandard functions (see :ref:`built-in functions <builtin_functions>`).\n"
  },
  {
    "path": "extlibs/squirrel/doc/source/reference/language/builtin_functions.rst",
    "content": ".. _builtin_functions:\n\n\n==================\nBuilt-in Functions\n==================\n\n.. index::\n    single: Built-in Functions\n    pair: Global Symbols; Built-in Functions\n\n\n^^^^^^^^^^^^^^\nGlobal Symbols\n^^^^^^^^^^^^^^\n\n.. js:function:: array(size,[fill])\n\ncreates and returns array of a specified size. If the optional parameter fill is specified its value will be used to fill the new array's slots. If the fill parameter is omitted, null is used instead.\n\n.. js:function:: seterrorhandler(func)\n\n\nsets the runtime error handler\n\n.. js:function:: callee()\n\n\nreturns the currently running closure\n\n.. js:function:: setdebughook(hook_func)\n\n\nsets the debug hook\n\n.. js:function:: enabledebuginfo(enable)\n\nenable/disable the debug line information generation at compile time. enable != null enables. enable == null disables.\n\n.. js:function:: getroottable()\n\nreturns the root table of the VM.\n\n.. js:function:: setroottable(table)\n\nsets the root table of the VM. And returns the previous root table.\n\n.. js:function:: getconsttable()\n\nreturns the const table of the VM.\n\n.. js:function:: setconsttable(table)\n\nsets the const table of the VM; returns the previous const table.\n\n.. js:function:: assert(exp, [message])\n\nthrows an exception if exp is null or false. Throws \"assertion failed\" string by default, or message if specified.\n\n.. js:function:: print(x)\n\nprints x to the standard output\n\n.. js:function:: error(x)\n\nprints x in the standard error output\n\n.. js:function:: compilestring(string,[buffername])\n\ncompiles a string containing a squirrel script into a function and returns it::\n\n    local compiledscript=compilestring(\"::print(\\\"ciao\\\")\");\n    //run the script\n    compiledscript();\n\n.. js:function:: collectgarbage()\n\n    Runs the garbage collector and returns the number of reference cycles found (and deleted). This function only works on garbage collector builds.\n\n.. js:function:: resurrectunreachable()\n\nRuns the garbage collector and returns an array containing all unreachable object found. If no unreachable object is found, null is returned instead. This function is meant to help debugging reference cycles. This function only works on garbage collector builds.\n\n.. js:function:: type(obj)\n\nreturn the 'raw' type of an object without invoking the metamethod '_typeof'.\n\n.. js:function:: getstackinfos(level)\n\nreturns the stack informations of a given call stack level. returns a table formatted as follow: ::\n\n    {\n        func=\"DoStuff\", //function name\n\n        src=\"test.nut\", //source file\n\n        line=10,        //line number\n\n        locals = {      //a table containing the local variables\n\n            a=10,\n\n            testy=\"I'm a string\"\n        }\n    }\n\nlevel = 0 is getstackinfos() itself! level = 1 is the current function, level = 2 is the caller of the current function, and so on. If the stack level doesn't exist the function returns null.\n\n.. js:function:: newthread(threadfunc)\n\ncreates a new cooperative thread object(coroutine) and returns it\n\n.. js:data:: _versionnumber_\n\ninteger values describing the version of VM and compiler. e.g. for Squirrel 3.0.1 this value will be 301\n\n.. js:data:: _version_\n\nstring values describing the version of VM and compiler.\n\n.. js:data:: _charsize_\n\nsize in bytes of the internal VM representation for characters(1 for ASCII builds 2 for UNICODE builds).\n\n.. js:data:: _intsize_\n\nsize in bytes of the internal VM representation for integers(4 for 32bits builds 8 for 64bits builds).\n\n.. js:data:: _floatsize_\n\nsize in bytes of the internal VM representation for floats(4 for single precision builds 8 for double precision builds).\n\n-----------------\nDefault delegates\n-----------------\n\nExcept null and userdata every squirrel object has a default delegate containing a set of functions to manipulate and retrieve information from the object itself.\n\n^^^^^^^^\nInteger\n^^^^^^^^\n\n.. js:function:: integer.tofloat()\n\nconvert the number to float and returns it\n\n\n.. js:function:: integer.tostring()\n\nconverts the number to string and returns it\n\n\n.. js:function:: integer.tointeger()\n\ndummy function; returns the value of the integer.\n\n\n.. js:function:: integer.tochar()\n\nreturns a string containing a single character represented by the integer.\n\n\n.. js:function:: integer.weakref()\n\ndummy function; returns the integer itself.\n\n^^^^^\nFloat\n^^^^^\n\n.. js:function:: float.tofloat()\n\nreturns the value of the float(dummy function)\n\n\n.. js:function:: float.tointeger()\n\nconverts the number to integer and returns it\n\n\n.. js:function:: float.tostring()\n\nconverts the number to string and returns it\n\n\n.. js:function:: float.tochar()\n\nreturns a string containing a single character represented by the integer part of the float.\n\n\n.. js:function:: float.weakref()\n\ndummy function; returns the float itself.\n\n^^^^\nBool\n^^^^\n\n.. js:function:: bool.tofloat()\n\nreturns 1.0 for true 0.0 for false\n\n\n.. js:function:: bool.tointeger()\n\nreturns 1 for true 0 for false\n\n\n.. js:function:: bool.tostring()\n\nreturns \"true\" for true and \"false\" for false\n\n\n.. js:function:: bool.weakref()\n\ndummy function; returns the bool itself.\n\n^^^^^^\nString\n^^^^^^\n\n.. js:function:: string.len()\n\nreturns the string length\n\n\n.. js:function:: string.tointeger([base])\n\nConverts the string to integer and returns it. An optional parameter base can be specified--if a base is not specified, it defaults to base 10.\n\n\n.. js:function:: string.tofloat()\n\nconverts the string to float and returns it\n\n\n.. js:function:: string.tostring()\n\nreturns the string (really, a dummy function)\n\n\n.. js:function:: string.slice(start,[end])\n\nreturns a section of the string as new string. Copies from start to the end (not included). If start is negative the index is calculated as length + start, if end is negative the index is calculated as length + end. If end is omitted end is equal to the string length.\n\n\n.. js:function:: string.find(substr,[startidx])\n\nSearches a sub string (substr) starting from the index startidx and returns the index of its first occurrence. If startidx is omitted the search operation starts from the beginning of the string. The function returns null if substr is not found.\n\n\n.. js:function:: string.tolower()\n\nreturns a lowercase copy of the string.\n\n\n.. js:function:: string.toupper()\n\nreturns a uppercase copy of the string.\n\n\n.. js:function:: string.weakref()\n\nreturns a weak reference to the object.\n\n^^^^^\nTable\n^^^^^\n\n.. js:function:: table.len()\n\nreturns the number of slots contained in a table\n\n\n.. js:function:: table.rawget(key)\n\ntries to get a value from the slot 'key' without employing delegation\n\n\n.. js:function:: table.rawset(key,val)\n\nSets the slot 'key' with the value 'val' without employing delegation. If the slot does not exists, it will be created. Returns table itself.\n\n\n.. js:function:: table.rawdelete()\n\nDeletes the slot key without employing delegation and returns its value. If the slot does not exists, returns null.\n\n\n.. js:function:: table.rawin(key)\n\nreturns true if the slot 'key' exists. the function has the same effect as the operator 'in' but does not employ delegation.\n\n\n.. js:function:: table.weakref()\n\nreturns a weak reference to the object.\n\n\n.. js:function:: table.tostring()\n\nTries to invoke the _tostring metamethod. If that fails, it returns \"(table : pointer)\".\n\n\n.. js:function:: table.clear()\n\nremoves all the slots from the table. Returns table itself.\n\n\n.. js:function:: table.setdelegate(table)\n\nSets the delegate of the table. To remove a delegate, 'null' must be passed to the function. The function returns the table itself (e.g. a.setdelegate(b) -- in this case 'a' is the return value).\n\n\n.. js:function:: table.getdelegate()\n\nreturns the table's delegate or null if no delegate was set.\n\n\n.. js:function:: table.filter(func(key,val))\n\nCreates a new table with all values that pass the test implemented by the provided function. In detail, it creates a new table, invokes the specified function for each key-value pair in the original table; if the function returns 'true', then the value is added to the newly created table at the same key.\n\n^^^^^^\nArray\n^^^^^^\n\n.. js:function:: array.len()\n\nreturns the length of the array\n\n\n.. js:function:: array.append(val)\n\nappends the value 'val' at the end of the array. Returns array itself.\n\n\n.. js:function:: array.push(val)\n\nappends the value 'val' at the end of the array. Returns array itself.\n\n\n.. js:function:: array.extend(array)\n\nExtends the array by appending all the items in the given array. Returns array itself.\n\n\n.. js:function:: array.pop()\n\nremoves a value from the back of the array and returns it.\n\n\n.. js:function:: array.top()\n\nreturns the value of the array with the higher index\n\n\n.. js:function:: array.insert(idx,val)\n\ninserts the value 'val' at the position 'idx' in the array. Returns array itself.\n\n\n.. js:function:: array.remove(idx)\n\nremoves the value at the position 'idx' in the array and returns its value.\n\n\n.. js:function:: array.resize(size,[fill])\n\nResizes the array. If the optional parameter 'fill' is specified, its value will be used to fill the new array's slots when the size specified is bigger than the previous size. If the fill parameter is omitted, null is used instead. Returns array itself.\n\n\n.. js:function:: array.sort([compare_func])\n\nSorts the array in-place. A custom compare function can be optionally passed. The function prototype as to be the following.::\n\n    function custom_compare(a,b)\n    {\n        if(a>b) return 1\n        else if(a<b) return -1\n        return 0;\n    }\n\na more compact version of a custom compare can be written using a lambda expression and the operator <=> ::\n\n    arr.sort(@(a,b) a <=> b);\n\nReturns array itself.\n\n.. js:function:: array.reverse()\n\nreverse the elements of the array in place. Returns array itself.\n\n\n.. js:function:: array.slice(start,[end])\n\nReturns a section of the array as new array. Copies from start to the end (not included). If start is negative the index is calculated as length + start, if end is negative the index is calculated as length + end. If end is omitted end is equal to the array length.\n\n\n.. js:function:: array.weakref()\n\nreturns a weak reference to the object.\n\n\n.. js:function:: array.tostring()\n\nreturns the string \"(array : pointer)\".\n\n\n.. js:function:: array.clear()\n\nremoves all the items from the array\n\n\n.. js:function:: array.map(func(item_value, [item_index], [array_ref]))\n\nCreates a new array of the same size. For each element in the original array invokes the function 'func' and assigns the return value of the function to the corresponding element of the newly created array.\nProvided func can accept up to 3 arguments: array item value (required), array item index (optional), reference to array itself (optional).\n\n\n.. js:function:: array.apply(func([item_value, [item_index], [array_ref]))\n\nfor each element in the array invokes the function 'func' and replace the original value of the element with the return value of the function.\n\n\n.. js:function:: array.reduce(func(prevval,curval), [initializer])\n\nReduces an array to a single value. For each element in the array invokes the function 'func' passing\nthe initial value (or value from the previous callback call) and the value of the current element.\nThe return value of the function is then used as 'prevval' for the next element.\nIf the optional initializer is present, it is placed before the items of the array in the calculation,\nand serves as a default when the sequence is empty.\nIf initializer is not given then for sequence contains only one item, reduce() returns the first item,\nand for empty sequence returns null.\n\nGiven an sequence with 2 or more elements (including initializer) calls the function with the first two elements as the parameters,\ngets that result, then calls the function with that result and the third element, gets that result,\ncalls the function with that result and the fourth parameter and so on until all element have been processed.\nFinally, returns the return value of the last invocation of func.\n\n\n.. js:function:: array.filter(func(index,val))\n\nCreates a new array with all elements that pass the test implemented by the provided function. In detail, it creates a new array, for each element in the original array invokes the specified function passing the index of the element and it's value; if the function returns 'true', then the value of the corresponding element is added on the newly created array.\n\n\n.. js:function:: array.find(value)\n\nPerforms a linear search for the value in the array. Returns the index of the value if it was found null otherwise.\n\n^^^^^^^^\nFunction\n^^^^^^^^\n\n.. js:function:: function.call(_this,args...)\n\ncalls the function with the specified environment object('this') and parameters\n\n\n.. js:function:: function.pcall(_this,args...)\n\ncalls the function with the specified environment object('this') and parameters, this function will not invoke the error callback in case of failure(pcall stays for 'protected call')\n\n\n.. js:function:: function.acall(array_args)\n\ncalls the function with the specified environment object('this') and parameters. The function accepts an array containing the parameters that will be passed to the called function.Where array_args has to contain the required 'this' object at the [0] position.\n\n\n.. js:function:: function.pacall(array_args)\n\ncalls the function with the specified environment object('this') and parameters. The function accepts an array containing the parameters that will be passed to the called function.Where array_args has to contain the required 'this' object at the [0] position. This function will not invoke the error callback in case of failure(pacall stays for 'protected array call')\n\n\n.. js:function:: function.weakref()\n\nreturns a weak reference to the object.\n\n\n.. js:function:: function.tostring()\n\nreturns the string \"(closure : pointer)\".\n\n\n.. js:function:: function.setroot(table)\n\nsets the root table of a closure\n\n\n.. js:function:: function.getroot()\n\nreturns the root table of the closure\n\n\n.. js:function:: function.bindenv(env)\n\nclones the function(aka closure) and bind the environment object to it(table,class or instance). the this parameter of the newly create function will always be set to env. Note that the created function holds a weak reference to its environment object so cannot be used to control its lifetime.\n\n\n.. js:function:: function.getinfos()\n\nreturns a table containing informations about the function, like parameters, name and source name; ::\n\n    //the data is returned as a table is in form\n    //pure squirrel function\n    {\n      native = false\n      name = \"zefuncname\"\n      src = \"/somthing/something.nut\"\n      parameters = [\"a\",\"b\",\"c\"]\n      defparams = [1,\"def\"]\n      varargs = 2\n    }\n    //native C function\n    {\n      native = true\n      name = \"zefuncname\"\n      paramscheck = 2\n      typecheck = [83886082,83886384] //this is the typemask (see C defines OT_INTEGER,OT_FLOAT etc...)\n    }\n\n\n\n^^^^^\nClass\n^^^^^\n\n.. js:function:: class.instance()\n\nreturns a new instance of the class. this function does not invoke the instance constructor. The constructor must be explicitly called (eg. class_inst.constructor(class_inst) ).\n\n\n.. js:function:: class.getattributes(membername)\n\nreturns the attributes of the specified member. if the parameter member is null the function returns the class level attributes.\n\n\n.. js:function:: class.setattributes(membername,attr)\n\nsets the attribute of the specified member and returns the previous attribute value. if the parameter member is null the function sets the class level attributes.\n\n\n.. js:function:: class.rawin(key)\n\nreturns true if the slot 'key' exists. the function has the same effect as the operator 'in' but does not employ delegation.\n\n\n.. js:function:: class.weakref()\n\nreturns a weak reference to the object.\n\n\n.. js:function:: class.tostring()\n\nreturns the string \"(class : pointer)\".\n\n\n.. js:function:: class.rawget(key)\n\ntries to get a value from the slot 'key' without employing delegation\n\n\n.. js:function:: class.rawset(key,val)\n\nsets the slot 'key' with the value 'val' without employing delegation. If the slot does not exists, it will be created.\n\n\n.. js:function:: class.newmember(key,val,[attrs],[bstatic])\n\nsets/adds the slot 'key' with the value 'val' and attributes 'attrs' and if present invokes the _newmember metamethod. If bstatic is true the slot will be added as static. If the slot does not exists , it will be created.\n\n\n.. js:function:: class.rawnewmember(key,val,[attrs],[bstatic])\n\nsets/adds the slot 'key' with the value 'val' and attributes 'attrs'. If bstatic is true the slot will be added as static. If the slot does not exist, it will be created. It doesn't invoke any metamethod.\n\n^^^^^^^^^^^^^^\nClass Instance\n^^^^^^^^^^^^^^\n\n.. js:function:: instance.getclass()\n\nreturns the class that created the instance.\n\n\n.. js:function:: instance.rawin(key)\n\n    :param key: ze key\n\nreturns true if the slot 'key' exists. the function has the same effect as the operator 'in' but does not employ delegation.\n\n\n.. js:function:: instance.weakref()\n\nreturns a weak reference to the object.\n\n\n.. js:function:: instance.tostring()\n\ntries to invoke the _tostring metamethod, if failed. returns \"(instance : pointer)\".\n\n\n.. js:function:: instance.rawget(key)\n\ntries to get a value from the slot 'key' without employing delegation\n\n\n.. js:function:: instance.rawset(key,val)\n\nsets the slot 'key' with the value 'val' without employing delegation. If the slot does not exists, it will be created.\n\n^^^^^^^^^^^^^^\nGenerator\n^^^^^^^^^^^^^^\n\n\n.. js:function:: generator.getstatus()\n\nreturns the status of the generator as string : \"running\", \"dead\" or \"suspended\".\n\n\n.. js:function:: generator.weakref()\n\nreturns a weak reference to the object.\n\n\n.. js:function:: generator.tostring()\n\nreturns the string \"(generator : pointer)\".\n\n^^^^^^^^^^^^^^\nThread\n^^^^^^^^^^^^^^\n\n.. js:function:: thread.call(...)\n\nstarts the thread with the specified parameters\n\n\n.. js:function:: thread.wakeup([wakeupval])\n\nwakes up a suspended thread, accepts a optional parameter that will be used as return value for the function that suspended the thread(usually suspend())\n\n\n.. js:function:: thread.wakeupthrow(objtothrow,[propagateerror = true])\n\nwakes up a suspended thread, throwing an exception in the awaken thread, throwing the object 'objtothrow'.\n\n\n.. js:function:: thread.getstatus()\n\nreturns the status of the thread (\"idle\",\"running\",\"suspended\")\n\n\n.. js:function:: thread.weakref()\n\nreturns a weak reference to the object.\n\n\n.. js:function:: thread.tostring()\n\nreturns the string \"(thread : pointer)\".\n\n\n.. js:function:: thread.getstackinfos(stacklevel)\n\nreturns the stack frame informations at the given stack level (0 is the current function 1 is the caller and so on).\n\n^^^^^^^^^^^^^^\nWeak Reference\n^^^^^^^^^^^^^^\n\n.. js:function:: weakreference.ref()\n\nreturns the object that the weak reference is pointing at; null if the object that was point at was destroyed.\n\n\n.. js:function:: weakreference.weakref()\n\nreturns a weak reference to the object.\n\n\n.. js:function:: weakreference.tostring()\n\nreturns the string \"(weakref : pointer)\".\n"
  },
  {
    "path": "extlibs/squirrel/doc/source/reference/language/classes.rst",
    "content": ".. _classes:\n\n\n=================\nClasses\n=================\n\n.. index::\n    single: Classes\n\nSquirrel implements a class mechanism similar to languages like Java/C++/etc...\nhowever because of its dynamic nature it differs in several aspects.\nClasses are first class objects like integer or strings and can be stored in\ntable slots local variables, arrays and passed as function parameters.\n\n-----------------\nClass Declaration\n-----------------\n\n.. index::\n    pair: declaration; Class\n    single: Class Declaration\n\nA class object is created through the keyword 'class' . The class object follows\nthe same declaration syntax of a table(see :ref:`Tables <tables>`) with the only difference\nof using ';' as optional separator rather than ','.\n\nFor instance: ::\n\n    class Foo {\n        //constructor\n        constructor(a)\n        {\n            testy = [\"stuff\",1,2,3,a];\n        }\n        //member function\n        function PrintTesty()\n        {\n            foreach(i,val in testy)\n            {\n                ::print(\"idx = \"+i+\" = \"+val+\" \\n\");\n            }\n        }\n        //property\n        testy = null;\n\n    }\n\nthe previous code example is a syntactic sugar for: ::\n\n    Foo <- class {\n        //constructor\n        constructor(a)\n        {\n            testy = [\"stuff\",1,2,3,a];\n        }\n        //member function\n        function PrintTesty()\n        {\n            foreach(i,val in testy)\n            {\n                ::print(\"idx = \"+i+\" = \"+val+\" \\n\");\n            }\n        }\n        //property\n        testy = null;\n\n    }\n\nin order to emulate namespaces, it is also possible to declare something like this::\n\n    //just 2 regular nested tables\n    FakeNamespace <- {\n        Utils = {}\n    }\n\n    class FakeNamespace.Utils.SuperClass {\n        constructor()\n        {\n            ::print(\"FakeNamespace.Utils.SuperClass\")\n        }\n        function DoSomething()\n        {\n            ::print(\"DoSomething()\")\n        }\n    }\n\n    function FakeNamespace::Utils::SuperClass::DoSomethingElse()\n    {\n        ::print(\"FakeNamespace::Utils::SuperClass::DoSomethingElse()\")\n    }\n\n    local testy = FakeNamespace.Utils.SuperClass();\n    testy.DoSomething();\n    testy.DoSomethingElse();\n\nAfter its declaration, methods or properties can be added or modified by following\nthe same rules that apply to a table(operator ``<-``).::\n\n    //adds a new property\n    Foo.stuff <- 10;\n\n    //modifies the default value of an existing property\n    Foo.testy <- \"I'm a string\";\n\n    //adds a new method\n    function Foo::DoSomething(a,b)\n    {\n        return a+b;\n    }\n\nAfter a class is instantiated is no longer possible to add new properties however is possible to add or replace methods.\n\n^^^^^^^^^^^^^^^^\nStatic variables\n^^^^^^^^^^^^^^^^\n\n.. index::\n    pair: static variables; Class\n    single: Static variables\n\nSquirrel's classes support static member variables. A static variable shares its value\nbetween all instances of the class. Statics are declared by prefixing the variable declaration\nwith the keyword ``static``; the declaration must be in the class body.\n\n.. note:: Statics are read-only.\n\n::\n\n    class Foo {\n        constructor()\n        {\n            //..stuff\n        }\n        name = \"normal variable\";\n        //static variable\n        static classname = \"The class name is foo\";\n    };\n\n^^^^^^^^^^^^^^^^\nClass Attributes\n^^^^^^^^^^^^^^^^\n\n.. index::\n    pair: attributes; Class\n    single: Class Attributes\n\nClasses allow to associate attributes to it's members. Attributes are a form of metadata\nthat can be used to store application specific informations, like documentations\nstrings, properties for IDEs, code generators etc...\nClass attributes are declared in the class body by preceding the member declaration and\nare delimited by the symbol ``</`` and ``/>``.\nHere an example: ::\n\n    class Foo </ test = \"I'm a class level attribute\" />{\n        </ test = \"freakin attribute\" /> //attributes of PrintTesty\n        function PrintTesty()\n        {\n            foreach(i,val in testy)\n            {\n                ::print(\"idx = \"+i+\" = \"+val+\" \\n\");\n            }\n        }\n        </ flippy = 10 , second = [1,2,3] /> //attributes of testy\n        testy = null;\n    }\n\nAttributes are, matter of fact, a table. Squirrel uses ``</ />`` syntax\ninstead of curly brackets ``{}`` for the attribute declaration to increase readability.\n\nThis means that all rules that apply to tables apply to attributes.\n\nAttributes can be retrieved through the built-in function ``classobj.getattributes(membername)`` (see <link linkend=\"builtin\">built-in functions</link>).\nand can be modified/added through the built-in function ``classobj.setattributes(membername,val)``.\n\nthe following code iterates through the attributes of all Foo members.::\n\n    foreach(member,val in Foo)\n    {\n        ::print(member+\"\\n\");\n        local attr;\n        if((attr = Foo.getattributes(member)) != null) {\n            foreach(i,v in attr)\n            {\n                ::print(\"\\t\"+i+\" = \"+(typeof v)+\"\\n\");\n            }\n        }\n        else {\n            ::print(\"\\t<no attributes>\\n\")\n        }\n    }\n\n-----------------\nClass Instances\n-----------------\n\n.. index::\n    pair: instances; Class\n    single: Class Instances\n\nThe class objects inherits several of the table's feature with the difference that multiple instances of the\nsame class can be created.\nA class instance is an object that share the same structure of the table that created it but\nholds is own values.\nClass *instantiation* uses function notation.\nA class instance is created by calling a class object. Can be useful to imagine a class like a function\nthat returns a class instance.::\n\n    //creates a new instance of Foo\n    local inst = Foo();\n\nWhen a class instance is created its member are initialized *with the same value* specified in the\nclass declaration. The values are copied verbatim, *no cloning is performed* even if the value is a container or a class instances.\n\n.. note:: FOR C# and Java programmers:\n\n            Squirrel doesn't clone member's default values nor executes the member declaration for each instance(as C# or java).\n\n            So consider this example: ::\n\n                class Foo {\n                  myarray = [1,2,3]\n                  mytable = {}\n                }\n\n                local a = Foo();\n                local b = Foo();\n\n            In the snippet above both instances will refer to the same array and same table.To achieve what a C# or Java programmer would\n            expect, the following approach should be taken. ::\n\n                class Foo {\n                  myarray = null\n                  mytable = null\n                  constructor()\n                  {\n                    myarray = [1,2,3]\n                    mytable = {}\n                  }\n                }\n\n                local a = Foo();\n                local b = Foo();\n\nWhen a class defines a method called 'constructor', the class instantiation operation will\nautomatically invoke it for the newly created instance.\nThe constructor method can have parameters, this will impact on the number of parameters\nthat the *instantiation operation* will require.\nConstructors, as normal functions, can have variable number of parameters (using the parameter ``...``).::\n\n    class Rect {\n        constructor(w,h)\n        {\n            width = w;\n            height = h;\n        }\n        x = 0;\n        y = 0;\n        width = null;\n        height = null;\n    }\n\n    //Rect's constructor has 2 parameters so the class has to be 'called'\n    //with 2 parameters\n    local rc = Rect(100,100);\n\nAfter an instance is created, its properties can be set or fetched following the\nsame rules that apply to tables. Methods cannot be set.\n\nInstance members cannot be removed.\n\nThe class object that created a certain instance can be retrieved through the built-in function\n``instance.getclass()`` (see :ref:`built-in functions <builtin_functions>`)\n\nThe operator ``instanceof`` tests if a class instance is an instance of a certain class.::\n\n    local rc = Rect(100,100);\n    if(rc instanceof ::Rect) {\n        ::print(\"It's a rect\");\n    }\n    else {\n        ::print(\"It isn't a rect\");\n    }\n\n.. note:: Since Squirrel 3.x instanceof doesn't throw an exception if the left expression is not a class, it simply fails\n\n--------------\nInheritance\n--------------\n\n.. index::\n    pair: inheritance; Class\n    single: Inheritance\n\nSquirrel's classes support single inheritance by adding the keyword ``extends``, followed\nby an expression, in the class declaration.\nThe syntax for a derived class is the following: ::\n\n    class SuperFoo extends Foo {\n        function DoSomething() {\n            ::print(\"I'm doing something\");\n        }\n    }\n\nWhen a derived class is declared, Squirrel first copies all base's members in the\nnew class then proceeds with evaluating the rest of the declaration.\n\nA derived class inherit all members and properties of it's base, if the derived class\noverrides a base function the base implementation is shadowed.\nIt's possible to access a overridden method of the base class by fetching the method from\nthrough the 'base' keyword.\n\nHere an example: ::\n\n    class Foo {\n        function DoSomething() {\n            ::print(\"I'm the base\");\n        }\n    };\n\n    class SuperFoo extends Foo {\n        //overridden method\n        function DoSomething() {\n            //calls the base method\n            base.DoSomething();\n            ::print(\"I'm doing something\");\n        }\n    }\n\nSame rule apply to the constructor. The constructor is a regular function (apart from being automatically invoked on construction).::\n\n    class BaseClass {\n        constructor()\n        {\n            ::print(\"Base constructor\\n\");\n        }\n    }\n\n    class ChildClass extends BaseClass {\n        constructor()\n        {\n            base.constructor();\n            ::print(\"Child constructor\\n\");\n        }\n    }\n\n    local test = ChildClass();\n\nThe base class of a derived class can be retrieved through the built-in method ``getbase()``.::\n\n    local thebaseclass = SuperFoo.getbase();\n\nNote that because methods do not have special protection policies when calling methods of the same\nobjects, a method of a base class that calls a method of the same class can end up calling a overridden method of the derived class.\n\nA method of a base class can be explicitly invoked by a method of a derived class though the keyword ``base`` (as in base.MyMethod() ).::\n\n    class Foo {\n        function DoSomething() {\n            ::print(\"I'm the base\");\n        }\n        function DoIt()\n        {\n            DoSomething();\n        }\n    };\n\n    class SuperFoo extends Foo {\n        //overridden method\n        function DoSomething() {\n            ::print(\"I'm the derived\");\n\n        }\n        function DoIt() {\n            base.DoIt();\n        }\n    }\n\n    //creates a new instance of SuperFoo\n    local inst = SuperFoo();\n\n    //prints \"I'm the derived\"\n    inst.DoIt();\n\n----------------------\nMetamethods\n----------------------\n\n.. index::\n    pair: metamethods; Class\n    single: Class metamethods\n\nClass instances allow the customization of certain aspects of the\ntheir semantics through metamethods(see see :ref:`Metamethods <metamethods>`).\nFor C++ programmers: \"metamethods behave roughly like overloaded operators\".\nThe metamethods supported by classes are ``_add, _sub, _mul, _div, _unm, _modulo,\n_set, _get, _typeof, _nexti, _cmp, _call, _delslot, _tostring``\n\nClass objects instead support only 2 metamethods : ``_newmember`` and ``_inherited``\n\nthe following example show how to create a class that implements the metamethod ``_add``.::\n\n    class Vector3 {\n        constructor(...)\n        {\n            if(vargv.len() >= 3) {\n                x = vargv[0];\n                y = vargv[1];\n                z = vargv[2];\n            }\n        }\n        function _add(other)\n        {\n            return ::Vector3(x+other.x,y+other.y,z+other.z);\n        }\n\n        x = 0;\n        y = 0;\n        z = 0;\n    }\n\n    local v0 = Vector3(1,2,3)\n    local v1 = Vector3(11,12,13)\n    local v2 = v0 + v1;\n    ::print(v2.x+\",\"+v2.y+\",\"+v2.z+\"\\n\");\n\nSince version 2.1, classes support 2 metamethods ``_inherited`` and ``_newmember``.\n``_inherited`` is invoked when a class inherits from the one that implements ``_inherited``.\n``_newmember`` is invoked for each member that is added to the class(at declaration time).\n"
  },
  {
    "path": "extlibs/squirrel/doc/source/reference/language/constants_and_enumerations.rst",
    "content": ".. _constants_and_enumerations:\n\n\n========================\nConstants & Enumerations\n========================\n\n.. index::\n    single: Constants & Enumerations\n\n\n\nSquirrel allows to bind constant values to an identifier that will be evaluated compile-time.\nThis is achieved though constants and Enumerations.\n\n---------------\nConstants\n---------------\n\n.. index::\n    single: Constants\n\nConstants bind a specific value to an identifier. Constants are similar to\nglobal values, except that they are evaluated compile time and their value cannot be changed.\n\nconstants values can only be integers, floats or string literals. No expression are allowed.\nare declared with the following syntax.::\n\n    const foobar = 100;\n    const floatbar = 1.2;\n    const stringbar = \"I'm a constant string\";\n\nconstants are always globally scoped, from the moment they are declared, any following code\ncan reference them.\nConstants will shadow any global slot with the same name( the global slot will remain visible by using the ``::`` syntax).::\n\n    local x = foobar * 2;\n\n---------------\nEnumerations\n---------------\n\n.. index::\n    single: Enumerations\n\nAs Constants, Enumerations bind a specific value to a name. Enumerations are also evaluated at compile time\nand their value cannot be changed.\n\nAn enum declaration introduces a new enumeration into the program.\nEnumeration values can only be integers, floats or string literals. No expression are allowed.::\n\n    enum Stuff {\n      first, //this will be 0\n      second, //this will be 1\n      third //this will be 2\n    }\n\nor::\n\n    enum Stuff {\n      first = 10\n      second = \"string\"\n      third = 1.2\n    }\n\nAn enum value is accessed in a manner that's similar to accessing a static class member.\nThe name of the member must be qualified with the name of the enumeration, for example ``Stuff.second``\nEnumerations will shadow any global slot with the same name( the global slot will remain visible by using the ``::`` syntax).::\n\n    local x = Stuff.first * 2;\n\n--------------------\nImplementation notes\n--------------------\n\nEnumerations and Constants are a compile-time feature. Only integers, string and floats can be declared as const/enum;\nNo expressions are allowed(because they would have to be evaluated compile time).\nWhen a const or an enum is declared, it is added compile time to the ``consttable``. This table is stored in the VM shared state\nand is shared by the VM and all its threads.\nThe ``consttable`` is a regular squirrel table; In the same way as the ``roottable``\nit can be modified runtime.\nYou can access the ``consttable`` through the built-in function ``getconsttable()``\nand also change it through the built-in function ``setconsttable()``\n\nhere some example: ::\n\n    //creates a constant\n    getconsttable()[\"something\"] <- 10\"\n    //creates an enumeration\n    getconsttable()[\"somethingelse\"] <- { a = \"10\", c = \"20\", d = \"200\"};\n    //deletes the constant\n    delete getconsttable()[\"something\"]\n    //deletes the enumeration\n    delete getconsttable()[\"somethingelse\"]\n\nThis system allows to procedurally declare constants and enumerations, it is also possible to assign any squirrel type\nto a constant/enumeration(function,classes etc...). However this will make serialization of a code chunk impossible.\n"
  },
  {
    "path": "extlibs/squirrel/doc/source/reference/language/datatypes.rst",
    "content": ".. _datatypes_and_values:\n\n=====================\nValues and Data types\n=====================\n\nWhile Squirrel is a dynamically typed language and variables do not\nhave a type, different operations may interpret the variable as\ncontaining a type.  Squirrel's basic types are integer, float, string,\nnull, table, array, function, generator, class, instance, bool, thread\nand userdata.\n\n.. _userdata-index:\n\n--------\nInteger\n--------\n\nAn Integer represents a 32 bit (or better) signed number.::\n\n    local a = 123 //decimal\n    local b = 0x0012 //hexadecimal\n    local c = 075 //octal\n    local d = 'w' //char code\n\n--------\nFloat\n--------\n\nA float represents a 32 bit (or better) floating point number.::\n\n    local a=1.0\n    local b=0.234\n\n--------\nString\n--------\n\nStrings are an immutable sequence of characters. In order to modify a\nstring is it necessary create a new one.\n\nSquirrel's strings are similar to strings in C or C++.  They are\ndelimited by quotation marks(``\"``) and can contain escape\nsequences (``\\t``, ``\\a``, ``\\b``, ``\\n``, ``\\r``, ``\\v``, ``\\f``,\n``\\\\``, ``\\\"``, ``\\'``, ``\\0``, ``\\x<hh>``, ``\\u<hhhh>`` and\n``\\U<hhhhhhhh>``).\n\nVerbatim string literals do not interpret escape sequences. They begin\nwith ``@\"`` and end with the matching quote.  Verbatim string literals\nalso can extend over a line break. If they do, they include any white\nspace characters between the quotes: ::\n\n    local a = \"I'm a wonderful string\\n\"\n    // has a newline at the end of the string\n    local x = @\"I'm a verbatim string\\n\"\n    // the \\n is literal, similar to \"\\\\n\" in a regular string.\n\nHowever, a doubled quotation mark within a verbatim string is replaced\nby a single quotation mark: ::\n\n    local multiline = @\"\n        this is a multiline string\n        it will \"\"embed\"\" all the new line\n        characters\n    \"\n\n--------\nNull\n--------\n\nThe null value is a primitive value that represents the null, empty, or non-existent\nreference. The type Null has exactly one value, called null.::\n\n    local a = null\n\n--------\nBool\n--------\n\nBool is a double-valued (Boolean) data type. Its literals are ``true``\nand ``false``. A bool value expresses the validity of a condition\n(tells whether the condition is true or false).::\n\n    local a = true;\n\n--------\nTable\n--------\n\nTables are associative containers implemented as a set of key/value pairs\ncalled slots.::\n\n    local t={}\n    local test=\n    {\n        a=10\n        b=function(a) { return a+1; }\n    }\n\n--------\nArray\n--------\n\nArrays are simple sequence of objects. Their size is dynamic and their index always starts from 0.::\n\n    local a  = [\"I'm\",\"an\",\"array\"]\n    local b = [null]\n    b[0] = a[2];\n\n--------\nFunction\n--------\n\nFunctions are similar to those in other C-like languages with a few key differences (see below).\n\n--------\nClass\n--------\n\nClasses are associative containers implemented as sets of key/value\npairs. Classes are created through a 'class expression' or a 'class\nstatement'. class members can be inherited from another class object\nat creation time. After creation, members can be added until an\ninstance of the class is created.\n\n--------------\nClass Instance\n--------------\n\nClass instances are created by calling a *class object*. Instances, as\ntables, are implemented as sets of key/value pairs. Instance members\ncannot be dynamically added or removed; however the value of the\nmembers can be changed.\n\n---------\nGenerator\n---------\n\nGenerators are functions that can be suspended with the statement\n'yield' and resumed later (see :ref:`Generators <generators>`).\n\n---------\nUserdata\n---------\n\nUserdata objects are blobs of memory or pointers defined by the host\napplication but stored within Squirrel variables (See :ref:`Userdata\nand UserPointers <embedding_userdata_and_userpointers>`).\n\n---------\nThread\n---------\n\nThreads are objects representing a cooperative thread of execution,\nalso known as coroutines.\n\n--------------\nWeak Reference\n--------------\n\nWeak References are objects that point to another (non-scalar) object but do not own a strong reference to it.\n(See :ref:`Weak References <weak_references>`).\n"
  },
  {
    "path": "extlibs/squirrel/doc/source/reference/language/delegation.rst",
    "content": ".. _delegation:\n\n\n========================\nDelegation\n========================\n\n.. index::\n    single: Delegation\n\nSquirrel supports implicit delegation. Every table or userdata can have a parent table\n(delegate). A parent table is a normal table that allows the definition of special behaviors\nfor his child.\nWhen a table (or userdata) is indexed with a key that doesn't correspond to one of its\nslots, the interpreter automatically delegates the get (or set) operation to its parent.::\n\n    Entity <- {\n    }\n\n    function Entity::DoStuff()\n    {\n        ::print(_name);\n    }\n\n    local newentity = {\n        _name=\"I'm the new entity\"\n    }\n    newentity.setdelegate(Entity)\n\n    newentity.DoStuff(); //prints \"I'm the new entity\"\n\nThe delegate of a table can be retreived through built-in method ``table.getdelegate()``.::\n\n    local thedelegate = newentity.getdelegate();\n\n"
  },
  {
    "path": "extlibs/squirrel/doc/source/reference/language/execution_context.rst",
    "content": ".. _executioncontext:\n\n=======================\nExecution Context\n=======================\n\n.. index::\n    single: execution context\n\nThe execution context is the union of the function stack frame and the function\nenvironment object(this) and the function root(root table).\nThe stack frame is the portion of stack where the local variables declared in its body are\nstored.\nThe environment object is an implicit parameter that is automatically passed by the\nfunction caller (see see :ref:`functions <functions>`).\nThe root table is a table associated to the function during its creation.\nThe root table value of a function is the root table of the VM at the function creation.\nThe root table of function can also be changed after creation with closure.setroot().\nDuring the execution, the body of a function can only transparently refer to his execution\ncontext.\nThis mean that a single identifier can refer to a local variable, to an environment object slot\nor to the slot of the closure root table;\nThe environment object can be explicitly accessed by the keyword ``this``.\nThe closure root table can be explicitly accessed through the operator ``::`` (see :ref:`Variables <variables>`).\n\n.. _variables:\n\n-----------------\nVariables\n-----------------\n\nThere are two types of variables in Squirrel, local variables and tables/arrays slots.\nBecause global variables(variables stored in the root of a closure) are stored in a table, they are table slots.\n\nA single identifier refers to a local variable or a slot in the environment object.::\n\n    derefexp := id;\n\n::\n\n    _table[\"foo\"]\n    _array[10]\n\nwith tables we can also use the '.' syntax::\n\n    derefexp := exp '.' id\n\n::\n\n    _table.foo\n\nSquirrel first checks if an identifier is a local variable (function arguments are local\nvariables) if not looks up the environment object (this) and finally looks up\nto the closure root.\n\nFor instance:::\n\n    function testy(arg)\n    {\n        local a=10;\n        print(a);\n        return arg;\n    }\n\nin this case 'foo' will be equivalent to 'this.foo' or this[\"foo\"].\n\nGlobal variables are stored in a table called the root table. Usually in the global scope the\nenvironment object is the root table, but to explicitly access the closure root of the function from\nanother scope, the slot name must be prefixed with ``'::'`` (``::foo``).\n\nFor instance:::\n\n    function testy(arg)\n    {\n        local a=10;\n        return arg+::foo;\n    }\n\naccesses the variable 'foo' in the closure root table.\n\nSince Squirrel 3.1 each function has a weak reference to a specific root table, this can differ from the current VM root table.::\n\n    function test() {\n        foo = 10;\n    }\n\nis equivalent to write::\n\n    function test() {\n        if(\"foo\" in this) {\n            this.foo = 10;\n        }else {\n            ::foo = 10;\n        }\n    }\n"
  },
  {
    "path": "extlibs/squirrel/doc/source/reference/language/expressions.rst",
    "content": ".. _expressions:\n\n\n=================\nExpressions\n=================\n\n.. index::\n    single: Expressions\n\n----------------\nAssignment\n----------------\n\n.. index::\n    single: assignment(=)\n    single: new slot(<-)\n\n::\n\n    exp := derefexp '=' exp\n    exp:= derefexp '<-' exp\n\nsquirrel implements 2 kind of assignment: the normal assignment(=)::\n\n    a = 10;\n\nand the \"new slot\" assignment.::\n\n    a <- 10;\n\nThe new slot expression allows to add a new slot into a table(see :ref:`Tables <tables>`). If the slot\nalready exists in the table it behaves like a normal assignment.\n\n----------------\nOperators\n----------------\n\n.. index::\n    single: Operators\n\n^^^^^^^^^^^^^\n?: Operator\n^^^^^^^^^^^^^\n\n.. index::\n    pair: ?: Operator; Operators\n\n::\n\n    exp := exp_cond '?' exp1 ':' exp2\n\nconditionally evaluate an expression depending on the result of an expression.\n\n^^^^^^^^^^^^^\nArithmetic\n^^^^^^^^^^^^^\n\n.. index::\n    pair: Arithmetic Operators; Operators\n\n::\n\n    exp:= 'exp' op 'exp'\n\nSquirrel supports the standard arithmetic operators ``+, -, *, / and %``.\nOther than that is also supports compact operators (``+=,-=,*=,/=,%=``) and\nincrement and decrement operators(++ and --);::\n\n    a += 2;\n    //is the same as writing\n    a = a + 2;\n    x++\n    //is the same as writing\n    x = x + 1\n\nAll operators work normally with integers and floats; if one operand is an integer and one\nis a float the result of the expression will be float.\nThe + operator has a special behavior with strings; if one of the operands is a string the\noperator + will try to convert the other operand to string as well and concatenate both\ntogether. For instances and tables, ``_tostring`` is invoked.\n\n^^^^^^^^^^^^^\nRelational\n^^^^^^^^^^^^^\n\n.. index::\n    pair: Relational Operators; Operators\n\n::\n\n    exp:= 'exp' op 'exp'\n\nRelational operators in Squirrel are : ``==, <, <=, <, <=, !=``\n\nThese operators return true if the expression is false and a value different than true if the\nexpression is true. Internally the VM uses the integer 1 as true but this could change in\nthe future.\n\n^^^^^^^^^^^^^^\n3 ways compare\n^^^^^^^^^^^^^^\n\n.. index::\n    pair: 3 ways compare operator; Operators\n\n::\n\n    exp:= 'exp' <=> 'exp'\n\nthe 3 ways compare operator <=> compares 2 values A and B and returns an integer less than 0\nif A < B, 0 if A == B and an integer greater than 0 if A > B.\n\n^^^^^^^^^^^^^^\nLogical\n^^^^^^^^^^^^^^\n\n.. index::\n    pair: Logical operators; Operators\n\n::\n\n    exp := exp op exp\n    exp := '!' exp\n\nLogical operators in Squirrel are : ``&&, ||, !``\n\nThe operator ``&&`` (logical and) returns null if its first argument is null, otherwise returns\nits second argument.\nThe operator ``||`` (logical or) returns its first argument if is different than null, otherwise\nreturns the second argument.\n\nThe '!' operator will return null if the given value to negate was different than null, or a\nvalue different than null if the given value was null.\n\n^^^^^^^^^^^^^^^\nin operator\n^^^^^^^^^^^^^^^\n\n.. index::\n    pair: in operator; Operators\n\n::\n\n    exp:= keyexp 'in' tableexp\n\nTests the existence of a slot in a table.\nReturns true if *keyexp* is a valid key in *tableexp* ::\n\n    local t=\n    {\n        foo=\"I'm foo\",\n        [123]=\"I'm not foo\"\n    }\n\n    if(\"foo\" in t) dostuff(\"yep\");\n    if(123 in t) dostuff();\n\n^^^^^^^^^^^^^^^^^^^\ninstanceof operator\n^^^^^^^^^^^^^^^^^^^\n\n.. index::\n    pair: instanceof operator; Operators\n\n::\n\n    exp:= instanceexp 'instanceof' classexp\n\nTests if a class instance is an instance of a certain class.\nReturns true if *instanceexp* is an instance of *classexp*.\n\n^^^^^^^^^^^^^^^^^^^\ntypeof operator\n^^^^^^^^^^^^^^^^^^^\n\n.. index::\n    pair: typeof operator; Operators\n\n::\n\n    exp:= 'typeof' exp\n\nreturns the type name of a value as string.::\n\n    local a={},b=\"squirrel\"\n    print(typeof a); //will print \"table\"\n    print(typeof b); //will print \"string\"\n\n^^^^^^^^^^^^^^^^^^^\nComma operator\n^^^^^^^^^^^^^^^^^^^\n\n.. index::\n    pair: Comma operator; Operators\n\n::\n\n    exp:= exp ',' exp\n\nThe comma operator evaluates two expression left to right, the result of the operator is\nthe result of the expression on the right; the result of the left expression is discarded.::\n\n    local j=0,k=0;\n    for(local i=0; i<10; i++ , j++)\n    {\n        k = i + j;\n    }\n    local a,k;\n    a = (k=1,k+2); //a becomes 3\n\n^^^^^^^^^^^^^^^^^^^\nBitwise Operators\n^^^^^^^^^^^^^^^^^^^\n\n.. index::\n    pair: Bitwise Operators; Operators\n\n::\n\n    exp:= 'exp' op 'exp'\n    exp := '~' exp\n\nSquirrel supports the standard C-like bitwise operators ``&, |, ^, ~, <<, >>`` plus the unsigned\nright shift operator ``>>>``. The unsigned right shift works exactly like the normal right shift operator(``>>``)\nexcept for treating the left operand as an unsigned integer, so is not affected by the sign. Those operators\nonly work on integer values; passing of any other operand type to these operators will\ncause an exception.\n\n^^^^^^^^^^^^^^^^^^^^^\nOperators precedence\n^^^^^^^^^^^^^^^^^^^^^\n\n.. index::\n    pair: Operators precedence; Operators\n\n+---------------------------------------+-----------+\n| ``-, ~, !, typeof , ++, --``          | highest   |\n+---------------------------------------+-----------+\n| ``/, *, %``                           | ...       |\n+---------------------------------------+-----------+\n| ``+, -``                              |           |\n+---------------------------------------+-----------+\n| ``<<, >>, >>>``                       |           |\n+---------------------------------------+-----------+\n| ``<, <=, >, >=, instanceof``          |           |\n+---------------------------------------+-----------+\n| ``==, !=, <=>``                       |           |\n+---------------------------------------+-----------+\n| ``&``                                 |           |\n+---------------------------------------+-----------+\n| ``^``                                 |           |\n+---------------------------------------+-----------+\n| ``&&, in``                            |           |\n+---------------------------------------+-----------+\n| ``+=, =, -=, /=, *=, %=``             | ...       |\n+---------------------------------------+-----------+\n| ``, (comma operator)``                | lowest    |\n+---------------------------------------+-----------+\n\n.. _table_contructor:\n\n-----------------\nTable Constructor\n-----------------\n\n.. index::\n    single: Table Contructor\n\n::\n\n    tslots := ( 'id' '=' exp | '[' exp ']' '=' exp ) [',']\n    exp := '{' [tslots] '}'\n\nCreates a new table.::\n\n    local a = {} //create an empty table\n\nA table constructor can also contain slots declaration; With the syntax: ::\n\n    local a = {\n        slot1 = \"I'm the slot value\"\n    }\n\nAn alternative syntax can be::\n\n    '[' exp1 ']' = exp2 [',']\n\nA new slot with exp1 as key and exp2 as value is created::\n\n    local a=\n    {\n        [1]=\"I'm the value\"\n    }\n\nBoth syntaxes can be mixed::\n\n    local table=\n    {\n        a=10,\n        b=\"string\",\n        [10]={},\n        function bau(a,b)\n        {\n            return a+b;\n        }\n    }\n\nThe comma between slots is optional.\n\n^^^^^^^^^^^^^^^^^^^^^^\nTable with JSON syntax\n^^^^^^^^^^^^^^^^^^^^^^\n\n.. index::\n    single: Table with JSON syntax\n\nSince Squirrel 3.0 is possible to declare a table using JSON syntax(see http://www.wikipedia.org/wiki/JSON).\n\nthe following JSON snippet: ::\n\n    local x = {\n      \"id\": 1,\n      \"name\": \"Foo\",\n      \"price\": 123,\n      \"tags\": [\"Bar\",\"Eek\"]\n    }\n\nis equivalent to the following squirrel code: ::\n\n    local x = {\n      id = 1,\n      name = \"Foo\",\n      price = 123,\n      tags = [\"Bar\",\"Eek\"]\n    }\n\n-----------------\nclone\n-----------------\n\n.. index::\n    single: clone\n\n::\n\n    exp:= 'clone' exp\n\nClone performs shallow copy of a table, array or class instance (copies all slots in the new object without\nrecursion). If the source table has a delegate, the same delegate will be assigned as\ndelegate (not copied) to the new table (see :ref:`Delegation <delegation>`).\n\nAfter the new object is ready the \"_cloned\" meta method is called (see :ref:`Metamethods <metamethods>`).\n\nWhen a class instance is cloned the constructor is not invoked(initializations must rely on ```_cloned``` instead\n\n-----------------\nArray contructor\n-----------------\n\n.. index::\n    single: Array constructor\n\n::\n\n    exp := '[' [explist] ']'\n\nCreates a new array.::\n\n    a <- [] //creates an empty array\n\nArrays can be initialized with values during the construction::\n\n    a <- [1,\"string!\",[],{}] //creates an array with 4 elements\n"
  },
  {
    "path": "extlibs/squirrel/doc/source/reference/language/functions.rst",
    "content": ".. _functions:\n\n\n=================\nFunctions\n=================\n\n.. index::\n    single: Functions\n\nFunctions are first class values like integer or strings and can be stored in table slots,\nlocal variables, arrays and passed as function parameters.\nFunctions can be implemented in Squirrel or in a native language with calling conventions\ncompatible with ANSI C.\n\n--------------------\nFunction declaration\n--------------------\n\n.. index::\n    single: Function Declaration\n\nFunctions are declared through the function expression::\n\n    local a = function(a, b, c) { return a + b - c; }\n\nor with the syntactic sugar::\n\n    function ciao(a,b,c)\n    {\n        return a+b-c;\n    }\n\nthat is equivalent to::\n\n    this.ciao <- function(a,b,c)\n    {\n        return a+b-c;\n    }\n\na local function can be declared with this syntactic sugar::\n\n    local function tuna(a,b,c)\n    {\n        return a+b-c;\n    }\n\nthat is equivalent to::\n\n    local tuna = function(a,b,c)\n    {\n        return a+b-c;\n    }\n\nis also possible to declare something like::\n\n    T <- {}\n    function T::ciao(a,b,c)\n    {\n        return a+b-c;\n    }\n\n    //that is equivalent to write\n\n    T.ciao <- function(a,b,c)\n    {\n        return a+b-c;\n    }\n\n    //or\n\n    T <- {\n        function ciao(a,b,c)\n        {\n            return a+b-c;\n        }\n    }\n\n^^^^^^^^^^^^^^^^^^\nDefault Paramaters\n^^^^^^^^^^^^^^^^^^\n\n.. index::\n    single: Function Default Paramaters\n\nSquirrel's functions can have default parameters.\n\nA function with default parameters is declared as follows: ::\n\n    function test(a,b,c = 10, d = 20)\n    {\n        ....\n    }\n\nwhen the function *test* is invoked and the parameter c or d are not specified,\nthe VM autometically assigns the default value to the unspecified parameter. A default parameter can be\nany valid squirrel expression. The expression is evaluated at runtime.\n\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nFunction with variable number of paramaters\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n.. index::\n    single: Function with variable number of paramaters\n\nSquirrel's functions can have variable number of parameters(varargs functions).\n\nA vararg function is declared by adding three dots (`...`) at the end of its parameter list.\n\nWhen the function is called all the extra parameters will be accessible through the *array*\ncalled ``vargv``, that is passed as implicit parameter.\n\n``vargv`` is a regular squirrel array and can be used accordingly.::\n\n    function test(a,b,...)\n    {\n        for(local i = 0; i< vargv.len(); i++)\n        {\n            ::print(\"varparam \"+i+\" = \"+vargv[i]+\"\\n\");\n        }\n      foreach(i,val in vargv)\n        {\n            ::print(\"varparam \"+i+\" = \"+val+\"\\n\");\n        }\n    }\n\n    test(\"goes in a\",\"goes in b\",0,1,2,3,4,5,6,7,8);\n\n---------------\nFunction calls\n---------------\n\n.. index::\n    single: Function calls\n\n::\n\n    exp:= derefexp '(' explist ')'\n\nThe expression is evaluated in this order: derefexp after the explist (arguments) and at\nthe end the call.\n\nA function call in Squirrel passes the current environment object *this* as a hidden parameter.\nBut when the function was immediately indexed from an object, *this* shall be the object\nwhich was indexed, instead.\n\nIf we call a function with the syntax::\n\n    mytable.foo(x,y)\n\nthe environment object passed to 'foo' as *this* will be 'mytable' (since 'foo' was immediately indexed from 'mytable')\n\nWhereas with the syntax::\n\n    foo(x,y) // implicitly equivalent to this.foo(x,y)\n\nthe environment object will be the current *this* (that is, propagated from the caller's *this*).\n\nIt may help to remember the rules in the following way:\n\n    foo(x,y) ---> this.foo(x,y)\n    table.foo(x,y) ---> call foo with (table,x,y)\n\nIt may also help to consider why it works this way: it's designed to assist with object-oriented style.\nWhen calling 'foo(x,y)' it's assumed you're calling another member of the object (or of the file) and\nso should operate on the same object.\nWhen calling 'mytable.foo(x,y)' it's written plainly that you're calling a member of a different object.\n\n---------------------------------------------\nBinding an environment to a function\n---------------------------------------------\n\n.. index::\n    single: Binding an environment to a function\n\nwhile by default a squirrel function call passes as environment object 'this', the object\nwhere the function was indexed from. However, is also possible to statically bind an evironment to a\nclosure using the built-in method ``closure.bindenv(env_obj)``.\nThe method bindenv() returns a new instance of a closure with the environment bound to it.\nWhen an environment object is bound to a function, every time the function is invoked, its\n'this' parameter will always be the previously bound environent.\nThis mechanism is useful to implement callbacks systems similar to C# delegates.\n\n.. note:: The closure keeps a weak reference to the bound environmet object, because of this if\n          the object is deleted, the next call to the closure will result in a ``null``\n          environment object.\n\n---------------------------------------------\nLambda Expressions\n---------------------------------------------\n\n.. index::\n    single: Lambda Expressions\n\n::\n\n    exp := '@' '(' paramlist ')' exp\n\nLambda expressions are a syntactic sugar to quickly define a function that consists of a single expression.\nThis feature comes handy when functional programming patterns are applied, like map/reduce or passing a compare method to\narray.sort().\n\nhere a lambda expression::\n\n    local myexp = @(a,b) a + b\n\nthat is equivalent to::\n\n    local myexp = function(a,b) { return a + b; }\n\na more useful usage could be::\n\n    local arr = [2,3,5,8,3,5,1,2,6];\n    arr.sort(@(a,b) a <=> b);\n    arr.sort(@(a,b) -(a <=> b));\n\nthat could have been written as::\n\n    local arr = [2,3,5,8,3,5,1,2,6];\n    arr.sort(function(a,b) { return a <=> b; } );\n    arr.sort(function(a,b) { return -(a <=> b); } );\n\nother than being limited to a single expression lambdas support all features of regular functions.\nin fact are implemented as a compile time feature.\n\n---------------------------------------------\nFree Variables\n---------------------------------------------\n\n.. index::\n    single: Free Variables\n\nA free variable is a variable external from the function scope as is not a local variable\nor parameter of the function.\nFree variables reference a local variable from a outer scope.\nIn the following example the variables 'testy', 'x' and 'y' are bound to the function 'foo'.::\n\n    local x=10,y=20\n    local testy=\"I'm testy\"\n\n    function foo(a,b)\n    {\n        ::print(testy);\n        return a+b+x+y;\n    }\n\nA program can read or write a free variable.\n\n---------------------------------------------\nTail Recursion\n---------------------------------------------\n\n.. index::\n    single: Tail Recursion\n\nTail recursion is a method for partially transforming a recursion in a program into an\niteration: it applies when the recursive calls in a function are the last executed\nstatements in that function (just before the return).\nIf this happenes the squirrel interpreter collapses the caller stack frame before the\nrecursive call; because of that very deep recursions are possible without risk of a stack\noverflow.::\n\n    function loopy(n)\n    {\n        if(n>0){\n            ::print(\"n=\"+n+\"\\n\");\n            return loopy(n-1);\n        }\n    }\n\n    loopy(1000);\n\n"
  },
  {
    "path": "extlibs/squirrel/doc/source/reference/language/generators.rst",
    "content": ".. _generators:\n\n\n=================\nGenerators\n=================\n\n.. index::\n    single: Generators\n\nA function that contains a ``yield`` statement is called *'generator function'* .\nWhen a generator function is called, it does not execute the function body, instead it\nreturns a new suspended generator.\nThe returned generator can be resumed through the resume statement while it is alive.\nThe yield keyword, suspends the execution of a generator and optionally returns the\nresult of an expression to the function that resumed the generator.\nThe generator dies when it returns, this can happen through an explicit return\nstatement or by exiting the function body; If an unhandled exception (or runtime error)\noccurs while a generator is running, the generator will automatically die. A dead\ngenerator cannot be resumed anymore.::\n\n    function geny(n)\n    {\n        for(local i=1;i<=n;i+=1)\n            yield i;\n        return null;\n    }\n\n    local gtor=geny(10);\n    local x;\n    while(x=resume gtor) print(x+\"\\n\");\n\nthe output of this program will be::\n\n    1\n    2\n    3\n    4\n    5\n    6\n    7\n    8\n    9\n    10\n\ngenerators can also be iterated using the foreach statement. When a generator is evaluated\nby ``foreach``, the generator will be resumed for each iteration until it returns. The value\nreturned by the ``return`` statement will be ignored.\n\n.. note:: A suspended generator will hold a strong reference to all the values stored in it's local variables except the ``this``\n        object that is only a weak reference. A running generator hold a strong reference also to the ``this`` object.\n"
  },
  {
    "path": "extlibs/squirrel/doc/source/reference/language/lexical_structure.rst",
    "content": ".. _lexical_structure:\n\n\n=================\nLexical Structure\n=================\n\n.. index:: single: lexical structure\n\n-----------\nIdentifiers\n-----------\n\n.. index:: single: identifiers\n\nIdentifiers start with an alphabetic character or the symbol '_' followed by any number\nof alphabetic characters, '_' or digits ([0-9]). Squirrel is a case sensitive language\nmeaning that the lowercase and uppercase representation of the same alphabetic\ncharacter are considered different characters. For instance, \"foo\", \"Foo\" and \"fOo\" are\ntreated as 3 distinct identifiers.\n\n-----------\nKeywords\n-----------\n\n.. index:: single: keywords\n\nThe following words are reserved and cannot be used as identifiers:\n\n+------------+------------+-----------+------------+------------+-------------+\n| base       | break      | case      | catch      | class      | clone       |\n+------------+------------+-----------+------------+------------+-------------+\n| continue   | const      | default   | delete     | else       | enum        |\n+------------+------------+-----------+------------+------------+-------------+\n| extends    | for        | foreach   | function   | if         | in          |\n+------------+------------+-----------+------------+------------+-------------+\n| local      | null       | resume    | return     | switch     | this        |\n+------------+------------+-----------+------------+------------+-------------+\n| throw      | try        | typeof    | while      | yield      | constructor |\n+------------+------------+-----------+------------+------------+-------------+\n| instanceof | true       | false     | static     | __LINE__   | __FILE__    |\n+------------+------------+-----------+------------+------------+-------------+\n\nKeywords are covered in detail later in this document.\n\n-----------\nOperators\n-----------\n\n.. index:: single: operators\n\nSquirrel recognizes the following operators:\n\n+----------+----------+----------+----------+----------+----------+----------+----------+\n| ``!``    | ``!=``   | ``||``   | ``==``   | ``&&``   | ``>=``   | ``<=``   | ``>``    |\n+----------+----------+----------+----------+----------+----------+----------+----------+\n| ``<=>``  | ``+``    | ``+=``   | ``-``    | ``-=``   | ``/``    | ``/=``   | ``*``    |\n+----------+----------+----------+----------+----------+----------+----------+----------+\n| ``*=``   | ``%``    | ``%=``   | ``++``   | ``--``   | ``<-``   | ``=``    | ``&``    |\n+----------+----------+----------+----------+----------+----------+----------+----------+\n| ``^``    | ``|``    | ``~``    | ``>>``   | ``<<``   | ``>>>``  |          |          |\n+----------+----------+----------+----------+----------+----------+----------+----------+\n\n------------\nOther tokens\n------------\n\n.. index::\n    single: delimiters\n    single: other tokens\n\nOther significant tokens are:\n\n+----------+----------+----------+----------+----------+----------+\n| ``{``    | ``}``    | ``[``    | ``]``    | ``.``    | ``:``    |\n+----------+----------+----------+----------+----------+----------+\n| ``::``   | ``'``    | ``;``    | ``\"``    | ``@\"``   |          |\n+----------+----------+----------+----------+----------+----------+\n\n-----------\nLiterals\n-----------\n\n.. index::\n    single: literals\n    single: string literals\n    single: numeric literals\n\nSquirrel accepts integer numbers, floating point numbers and string literals.\n\n+-------------------------------+------------------------------------------+\n| ``34``                        | Integer number(base 10)                  |\n+-------------------------------+------------------------------------------+\n| ``0xFF00A120``                | Integer number(base 16)                  |\n+-------------------------------+------------------------------------------+\n| ``0753``                      | Integer number(base 8)                   |\n+-------------------------------+------------------------------------------+\n| ``'a'``                       | Integer number                           |\n+-------------------------------+------------------------------------------+\n| ``1.52``                      | Floating point number                    |\n+-------------------------------+------------------------------------------+\n| ``1.e2``                      | Floating point number                    |\n+-------------------------------+------------------------------------------+\n| ``1.e-2``                     | Floating point number                    |\n+-------------------------------+------------------------------------------+\n| ``\"I'm a string\"``            | String                                   |\n+-------------------------------+------------------------------------------+\n| ``@\"I'm a verbatim string\"``  | String                                   |\n+-------------------------------+------------------------------------------+\n| ``@\" I'm a``                  |                                          |\n| ``multiline verbatim string`` |                                          |\n| ``\"``                         | String                                   |\n+-------------------------------+------------------------------------------+\n\nPesudo BNF\n\n.. productionlist::\n    IntegerLiteral : [1-9][0-9]* | '0x' [0-9A-Fa-f]+ | ''' [.]+ ''' | 0[0-7]+\n    FloatLiteral : [0-9]+ '.' [0-9]+\n    FloatLiteral : [0-9]+ '.' 'e'|'E' '+'|'-' [0-9]+\n    StringLiteral: '\"'[.]* '\"'\n    VerbatimStringLiteral: '@''\"'[.]* '\"'\n\n-----------\nComments\n-----------\n\n.. index:: single: comments\n\nA comment is text that the compiler ignores but that is useful for programmers.\nComments are normally used to embed annotations in the code. The compiler\ntreats them as white space.\n\nA comment can be ``/*`` (slash, asterisk) characters, followed by any\nsequence of characters (including new lines),\nfollowed by the ``*/`` characters. This syntax is the same as ANSI C.::\n\n    /*\n    this is\n    a multiline comment.\n    this lines will be ignored by the compiler\n    */\n\nA comment can also be ``//`` (two slashes) characters, followed by any sequence of\ncharacters.  A new line not immediately preceded by a backslash terminates this form of\ncomment.  It is commonly called a *\"single-line comment.\"*::\n\n    //this is a single line comment. this line will be ignored by the compiler\n\nThe character ``#`` is an alternative syntax for single line comment.::\n\n    # this is also a single line comment.\n\nThis to facilitate the use of squirrel in UNIX-style shell scripts.\n"
  },
  {
    "path": "extlibs/squirrel/doc/source/reference/language/metamethods.rst",
    "content": ".. _metamethods:\n\n-----------\nMetamethods\n-----------\n\nMetamethods are a mechanism that allows the customization of certain aspects of the\nlanguage semantics. Those methods are normal functions placed in a table\nparent(delegate) or class declaration; It is possible to change many aspects of a table/class instance behavior by just defining\na metamethod. Class objects (not instances) support only 2 metamethods ``_newmember, _inherited`` .\n\nFor example when we use relational operators other than '==' on 2 tables, the VM will\ncheck if the table has a method in his parent called '_cmp'; if so it will call it to determine\nthe relation between the tables.::\n\n    local comparable={\n        _cmp = function (other)\n        {\n            if(name<other.name)return -1;\n            if(name>other.name)return 1;\n            return 0;\n        }\n    }\n\n    local a={ name=\"Alberto\" }.setdelegate(comparable);\n    local b={ name=\"Wouter\" }.setdelegate(comparable);\n\n    if(a>b)\n        print(\"a>b\")\n    else\n        print(\"b<=a\");\n\nfor classes the previous code become: ::\n\n    class Comparable {\n        constructor(n)\n        {\n            name = n;\n        }\n        function _cmp(other)\n        {\n            if(name<other.name) return -1;\n            if(name>other.name) return 1;\n            return 0;\n        }\n        name = null;\n    }\n\n    local a = Comparable(\"Alberto\");\n    local b = Comparable(\"Wouter\");\n\n    if(a>b)\n        print(\"a>b\")\n    else\n        print(\"b<=a\");\n\n^^^^^\n_set\n^^^^^\n\n::\n\n    _set(idx,val)\n\ninvoked when the index idx is not present in the object or in its delegate chain.\n``_set`` must 'throw null' to notify that a key wasn't found but the there were not runtime errors (clean failure).\nThis allows the program to differentiate between a runtime error and a 'index not found'.\n\n^^^^^\n_get\n^^^^^\n\n::\n\n    _get(idx)\n\ninvoked when the index idx is not present in the object or in its delegate chain.\n_get must 'throw null' to notify that a key wasn't found but the there were not runtime errors (clean failure).\nThis allows the program to differentiate between a runtime error and a 'index not found'.\n\n^^^^^^^^^\n_newslot\n^^^^^^^^^\n\n::\n\n    _newslot(key,value)\n\ninvoked when a script tries to add a new slot in a table.\n\nif the slot already exists in the target table the method will not be invoked also if the\n\"new slot\" operator is used.\n\n^^^^^^^^^\n_delslot\n^^^^^^^^^\n\n::\n\n    _delslot(key)\n\ninvoked when a script deletes a slot from a table.\nif the method is invoked squirrel will not try to delete the slot himself\n\n^^^^^^^^\n_add\n^^^^^^^^\n\n::\n\n    _add(other)\n\nthe + operator\n\nreturns this + other\n\n^^^^^^^^^^^^^^^^^^^^^^^^\n_sub\n^^^^^^^^^^^^^^^^^^^^^^^^\n\n::\n\n    _sub(other)\n\nthe - operator (like _add)\n\n^^^^^^^^^^^^^^^^^^^^^^^^\n_mul\n^^^^^^^^^^^^^^^^^^^^^^^^\n\n::\n\n    _mul(other)\n\nthe ``*`` operator (like _add)\n\n^^^^^^^^^^^^^^^^^^^^^^^^\n_div\n^^^^^^^^^^^^^^^^^^^^^^^^\n\n::\n\n    _div(other)\n\nthe ``/`` operator (like _add)\n\n^^^^^^^^^^^^^^^^^^^^^^^^\n_modulo\n^^^^^^^^^^^^^^^^^^^^^^^^\n\n::\n\n    _modulo(other)\n\nthe ``%`` operator (like _add)\n\n^^^^^^^^^\n_unm\n^^^^^^^^^\n\n::\n\n    _unm()\n\nthe unary minus operator\n\n^^^^^^^^^^^^^^^^^^^^^^^^\n_typeof\n^^^^^^^^^^^^^^^^^^^^^^^^\n\n::\n\n    _typeof()\n\ninvoked by the typeof operator on tables, userdata, and class instances.\n\nReturns the type of ``this`` as string\n\n^^^^^^^^^^^^^^^^^^^^^^^^\n_cmp\n^^^^^^^^^^^^^^^^^^^^^^^^\n\n::\n\n    _cmp(other)\n\ninvoked to emulate the ``< > <= >=`` and ``<=>`` operators\n\nreturns an integer as follow:\n\n+-----------+----------------------------+\n| returns   | relationship               |\n+===========+============================+\n|  > 0      | if ``this`` > ``other``    |\n+-----------+----------------------------+\n|  0        | if ``this`` == ``other``   |\n+-----------+----------------------------+\n|  < 0      | if ``this`` < ``other``    |\n+-----------+----------------------------+\n\n^^^^^^^^^^^^^^^^^^^^^^^^\n_call\n^^^^^^^^^^^^^^^^^^^^^^^^\n\n::\n\n    _call(other)\n\ninvoked when a table, userdata, or class instance is called\n\n^^^^^^^^^^^^^^^^^^^^^^^^\n_cloned\n^^^^^^^^^^^^^^^^^^^^^^^^\n\n::\n\n    _cloned(original)\n\ninvoked when a table or class instance is cloned(in the cloned table)\n\n^^^^^^^^^^^^^^^^^^^^^^^^\n_nexti\n^^^^^^^^^^^^^^^^^^^^^^^^\n\n::\n\n    _nexti(previdx)\n\ninvoked when a userdata or class instance is iterated by a foreach loop.\n\nIf previdx==null it means that it is the first iteration.\nThe function has to return the index of the 'next' value.\n\n^^^^^^^^^^^^^^^^^^^^^^^^\n_tostring\n^^^^^^^^^^^^^^^^^^^^^^^^\n\n::\n\n    _tostring()\n\nInvoked when during string concatenation or when the ``print`` function prints a table, instance, or userdata.\nThe method is also invoked by the sq_tostring() API.\n\nMust return a string representation of the object.\n\n^^^^^^^^^^^^^^^^^^^^^^^^\n_inherited\n^^^^^^^^^^^^^^^^^^^^^^^^\n\n::\n\n    _inherited(attributes)\n\ninvoked when a class object inherits from the class implementing ``_inherited``.\nThe ``this`` contains the new class.\n\nReturn value is ignored.\n\n^^^^^^^^^^^^^^^^^^^^^^^^\n_newmember\n^^^^^^^^^^^^^^^^^^^^^^^^\n\n::\n\n    _newmember(index,value,attributes,isstatic)\n\ninvoked for each member declared in a class body (at declaration time).\n\nIf the function is implemented, members will not be added to the class.\n"
  },
  {
    "path": "extlibs/squirrel/doc/source/reference/language/statements.rst",
    "content": ".. _statements:\n\n\n=================\nStatements\n=================\n\n.. index::\n    single: statements\n\nA squirrel program is a simple sequence of statements.::\n\n    stats := stat [';'|'\\n'] stats\n\nStatements in squirrel are comparable to the C-Family languages (C/C++, Java, C#\netc...): assignment, function calls, program flow control structures etc.. plus some\ncustom statement like yield, table and array constructors (All those will be covered in detail\nlater in this document).\nStatements can be separated with a new line or ';' (or with the keywords case or default if\ninside a switch/case statement), both symbols are not required if the statement is\nfollowed by '}'.\n\n------\nBlock\n------\n\n.. index::\n    pair: block; statement\n\n::\n\n    stat := '{' stats '}'\n\nA sequence of statements delimited by curly brackets ({ }) is called block;\na block is a statement itself.\n\n-----------------------\nControl Flow Statements\n-----------------------\n\n.. index::\n    single: control flow statements\n\nsquirrel implements the most common control flow statements: ``if, while, do-while, switch-case, for, foreach``\n\n^^^^^^^^^^^^^^\ntrue and false\n^^^^^^^^^^^^^^\n\n.. index::\n    single: true and false\n    single: true\n    single: false\n\nSquirrel has a boolean type (bool) however like C++ it considers null, 0(integer) and 0.0(float)\nas *false*, any other value is considered *true*.\n\n^^^^^^^^^^^^^^^^^\nif/else statement\n^^^^^^^^^^^^^^^^^\n\n.. index::\n    pair: if/else; statement\n    pair: if; statement\n    pair: else; statement\n\n::\n\n    stat:= 'if' '(' exp ')' stat ['else' stat]\n\nConditionally execute a statement depending on the result of an expression.::\n\n    if(a>b)\n        a=b;\n    else\n        b=a;\n    ////\n    if(a==10)\n    {\n        b=a+b;\n        return a;\n    }\n\n^^^^^^^^^^^^^^^^^\nwhile statement\n^^^^^^^^^^^^^^^^^\n\n.. index::\n    pair: while; statement\n\n::\n\n    stat:= 'while' '(' exp ')' stat\n\nExecutes a statement while the condition is true.::\n\n    function testy(n)\n    {\n        local a=0;\n        while(a<n) a+=1;\n\n        while(1)\n        {\n            if(a<0) break;\n            a-=1;\n        }\n    }\n\n^^^^^^^^^^^^^^^^^^\ndo/while statement\n^^^^^^^^^^^^^^^^^^\n\n.. index::\n    pair: do/while; statement\n\n::\n\n    stat:= 'do' stat 'while' '(' expression ')'\n\nExecutes a statement once, and then repeats execution of the statement until a condition\nexpression evaluates to false.::\n\n    local a=0;\n    do\n    {\n        print(a+\"\\n\");\n        a+=1;\n    } while(a>100)\n\n^^^^^^^^^^^^^^^^^\nswitch statement\n^^^^^^^^^^^^^^^^^\n\n.. index::\n    pair: switch; statement\n\n::\n\n    stat := 'switch' ''( exp ')' '{'\n    'case' case_exp ':'\n        stats\n    ['default' ':'\n        stats]\n    '}'\n\nSwitch is a control statement allows multiple selections of code by passing control to one of the\ncase statements within its body.\nThe control is transferred to the case label whose case_exp matches with exp if none of\nthe case match will jump to the default label (if present).\nA switch statement can contain any number if case instances, if 2 case have the same\nexpression result the first one will be taken in account first. The default label is only\nallowed once and must be the last one.\nA break statement will jump outside the switch block.\n\n-----\nLoops\n-----\n\n.. index::\n    single: Loops\n\n^^^^^^^^\nfor\n^^^^^^^^\n\n.. index::\n    pair: for; statement\n\n::\n\n    stat:= 'for' '(' [initexp] ';' [condexp] ';' [incexp] ')' statement\n\nExecutes a statement as long as a condition is different than false.::\n\n    for(local a=0;a<10;a+=1)\n        print(a+\"\\n\");\n    //or\n    glob <- null\n    for(glob=0;glob<10;glob+=1){\n        print(glob+\"\\n\");\n    }\n    //or\n    for(;;){\n        print(loops forever+\"\\n\");\n    }\n\n^^^^^^^^\nforeach\n^^^^^^^^\n\n.. index::\n    pair: foreach; statement\n\n::\n\n    'foreach' '(' [index_id','] value_id 'in' exp ')' stat\n\nExecutes a statement for every element contained in an array, table, class, string or generator.\nIf exp is a generator it will be resumed every iteration as long as it is alive; the value will\nbe the result of 'resume' and the index the sequence number of the iteration starting\nfrom 0.::\n\n    local a=[10,23,33,41,589,56]\n    foreach(idx,val in a)\n        print(\"index=\"+idx+\" value=\"+val+\"\\n\");\n    //or\n    foreach(val in a)\n        print(\"value=\"+val+\"\\n\");\n\n-------\nbreak\n-------\n\n.. index::\n    pair: break; statement\n\n::\n\n    stat := 'break'\n\nThe break statement terminates the execution of a loop (for, foreach, while or do/while)\nor jumps out of switch statement;\n\n---------\ncontinue\n---------\n\n.. index::\n    pair: continue; statement\n\n::\n\n    stat := 'continue'\n\nThe continue operator jumps to the next iteration of the loop skipping the execution of\nthe following statements.\n\n---------\nreturn\n---------\n\n.. index::\n    pair: return; statement\n\n::\n\n    stat:= return [exp]\n\nThe return statement terminates the execution of the current function/generator and\noptionally returns the result of an expression. If the expression is omitted the function\nwill return null. If the return statement is used inside a generator, the generator will not\nbe resumable anymore.\n\n---------\nyield\n---------\n\n.. index::\n    pair: yield; statement\n\n::\n\n    stat := yield [exp]\n\n(see :ref:`Generators <generators>`).\n\n\n---------------------------\nLocal variables declaration\n---------------------------\n\n.. index::\n    pair: Local variables declaration; statement\n\n::\n\n    initz := id [= exp][',' initz]\n    stat := 'local' initz\n\nLocal variables can be declared at any point in the program; they exist between their\ndeclaration to the end of the block where they have been declared.\n*EXCEPTION:* a local declaration statement is allowed as first expression in a for loop.::\n\n    for(local a=0;a<10;a+=1)\n        print(a);\n\n--------------------\nFunction declaration\n--------------------\n\n.. index::\n    pair: Function declaration; statement\n\n::\n\n    funcname := id ['::' id]\n    stat:= 'function' id ['::' id]+ '(' args ')' stat\n\ncreates a new function.\n\n-----------------\nClass declaration\n-----------------\n\n.. index::\n    pair: Class declaration; statement\n\n::\n\n    memberdecl := id '=' exp [';'] |    '[' exp ']' '=' exp [';'] | functionstat | 'constructor' functionexp\n    stat:= 'class' derefexp ['extends' derefexp] '{'\n            [memberdecl]\n        '}'\n\ncreates a new class.\n\n-----------\ntry/catch\n-----------\n\n.. index::\n    pair: try/catch; statement\n\n::\n\n    stat:= 'try' stat 'catch' '(' id ')' stat\n\nThe try statement encloses a block of code in which an exceptional condition can occur,\nsuch as a runtime error or a throw statement. The catch clause provides the exception-handling\ncode. When a catch clause catches an exception, its id is bound to that\nexception.\n\n-----------\nthrow\n-----------\n\n.. index::\n    pair: throw; statement\n\n::\n\n    stat:= 'throw' exp\n\nThrows an exception. Any value can be thrown.\n\n--------------\nconst\n--------------\n\n.. index::\n    pair: const; statement\n\n::\n\n    stat:= 'const' id '=' 'Integer | Float | StringLiteral\n\nDeclares a constant (see :ref:`Constants & Enumerations <constants_and_enumerations>`).\n\n--------------\nenum\n--------------\n\n.. index::\n    pair: enum; statement\n\n::\n\n    enumerations := ( 'id' '=' Integer | Float | StringLiteral ) [',']\n    stat:= 'enum' id '{' enumerations '}'\n\nDeclares an enumeration (see :ref:`Constants & Enumerations <constants_and_enumerations>`).\n\n--------------------\nExpression statement\n--------------------\n\n.. index::\n    pair: Expression statement; statement\n\n::\n\n    stat := exp\n\nIn Squirrel every expression is also allowed as statement, if so, the result of the\nexpression is thrown away.\n\n"
  },
  {
    "path": "extlibs/squirrel/doc/source/reference/language/tables.rst",
    "content": ".. _tables:\n\n\n=================\nTables\n=================\n\n.. index::\n    single: Tables\n\nTables are associative containers implemented as pairs of key/value (called slot); values\ncan be any possible type and keys any type except 'null'.\nTables are squirrel's skeleton, delegation and many other features are all implemented\nthrough this type; even the environment, where \"global\" variables are stored, is a table\n(known as root table).\n\n------------------\nConstruction\n------------------\n\nTables are created through the table constructor (see :ref:`Table constructor <table_constructor>`)\n\n------------------\nSlot creation\n------------------\n\n.. index::\n    single: Slot Creation(table)\n\nAdding a new slot in a existing table is done through the \"new slot\" operator ``<-``; this\noperator behaves like a normal assignment except that if the slot does not exists it will\nbe created.::\n\n    local a = {}\n\nThe following line will cause an exception because the slot named 'newslot' does not exist\nin the table 'a'::\n\n    a.newslot = 1234\n\nthis will succeed: ::\n\n    a.newslot <- 1234;\n\nor::\n\n    a[1] <- \"I'm the value of the new slot\";\n\n-----------------\nSlot deletion\n-----------------\n\n.. index::\n    single: Slot Deletion(table)\n\n\n::\n\n    exp:= delete derefexp\n\nDeletion of a slot is done through the keyword delete; the result of this expression will be\nthe value of the deleted slot.::\n\n    a <- {\n        test1=1234\n        deleteme=\"now\"\n    }\n\n    delete a.test1\n    print(delete a.deleteme); //this will print the string \"now\"\n\n"
  },
  {
    "path": "extlibs/squirrel/doc/source/reference/language/threads.rst",
    "content": ".. _threads:\n\n\n========================\nThreads\n========================\n\n.. index::\n    single: Threads\n\nSquirrel supports cooperative threads(also known as coroutines).\nA cooperative thread is a subroutine that can suspended in mid-execution and provide a value to the\ncaller without returning program flow, then its execution can be resumed later from the same\npoint where it was suspended.\nAt first look a Squirrel thread can be confused with a generator, in fact their behaviour is quite similar.\nHowever while a generator runs in the caller stack and can suspend only the local routine stack a thread\nhas its own execution stack, global table and error handler; This allows a thread to suspend nested calls and\nhave it's own error policies.\n\n------------------\nUsing threads\n------------------\n\n.. index::\n    single: Using Threads\n\nThreads are created through the built-in function 'newthread(func)'; this function\ngets as parameter a squirrel function and bind it to the new thread objects (will be the thread body).\nThe returned thread object is initially in 'idle' state. the thread can be started with the function\n'threadobj.call()'; the parameters passed to 'call' are passed to the thread function.\n\nA thread can be be suspended calling the function suspend(), when this happens the function\nthat wokeup(or started) the thread returns (If a parameter is passed to suspend() it will\nbe the return value of the wakeup function , if no parameter is passed the return value will be null).\nA suspended thread can be resumed calling the function 'threadobj.wakeup', when this happens\nthe function that suspended the thread will return(if a parameter is passed to wakeup it will\nbe the return value of the suspend function, if no parameter is passed the return value will be null).\n\nA thread terminates when its main function returns or when an unhandled exception occurs during its execution.::\n\n    function coroutine_test(a,b)\n    {\n        ::print(a+\" \"+b+\"\\n\");\n        local ret = ::suspend(\"suspend 1\");\n        ::print(\"the coroutine says \"+ret+\"\\n\");\n        ret = ::suspend(\"suspend 2\");\n        ::print(\"the coroutine says \"+ret+\"\\n\");\n        ret = ::suspend(\"suspend 3\");\n        ::print(\"the coroutine says \"+ret+\"\\n\");\n        return \"I'm done\"\n    }\n\n    local coro = ::newthread(coroutine_test);\n\n    local susparam = coro.call(\"test\",\"coroutine\"); //starts the coroutine\n\n    local i = 1;\n    do\n    {\n        ::print(\"suspend passed (\"+susparam+\")\\n\")\n        susparam = coro.wakeup(\"ciao \"+i);\n        ++i;\n    }while(coro.getstatus()==\"suspended\")\n\n    ::print(\"return passed (\"+susparam+\")\\n\")\n\nthe result of this program will be::\n\n    test coroutine\n    suspend passed (suspend 1)\n    the coroutine says ciao 1\n    suspend passed (suspend 2)\n    the coroutine says ciao 2\n    suspend passed (suspend 3)\n    the coroutine says ciao 3\n    return passed (I'm done).\n\n\nthe following is an interesting example of how threads and tail recursion\ncan be combined.::\n\n    function state1()\n    {\n        ::suspend(\"state1\");\n        return state2(); //tail call\n    }\n\n    function state2()\n    {\n        ::suspend(\"state2\");\n        return state3(); //tail call\n    }\n\n    function state3()\n    {\n        ::suspend(\"state3\");\n        return state1(); //tail call\n    }\n\n    local statethread = ::newthread(state1)\n\n    ::print(statethread.call()+\"\\n\");\n\n    for(local i = 0; i < 10000; i++)\n        ::print(statethread.wakeup()+\"\\n\");\n\n"
  },
  {
    "path": "extlibs/squirrel/doc/source/reference/language/weak_references.rst",
    "content": ".. _weak_references:\n\n\n========================\nWeak References\n========================\n\n.. index::\n    single: Weak References\n\n\nThe weak references allows the programmers to create references to objects without\ninfluencing the lifetime of the object itself.\nIn squirrel Weak references are first-class objects created through the built-in method obj.weakref().\nAll types except null implement the weakref() method; however in bools, integers, and floats the method\nsimply returns the object itself(this because this types are always passed by value).\nWhen a weak references is assigned to a container (table slot,array,class or\ninstance) is treated differently than other objects; When a container slot that hold a weak\nreference is fetched, it always returns the value pointed by the weak reference instead of the weak\nreference object. This allow the programmer to ignore the fact that the value handled is weak.\nWhen the object pointed by weak reference is destroyed, the weak reference is automatically set to null.::\n\n    local t = {}\n    local a = [\"first\",\"second\",\"third\"]\n    //creates a weakref to the array and assigns it to a table slot\n    t.thearray <- a.weakref();\n\nThe table slot 'thearray' contains a weak reference to an array.\nThe following line prints \"first\", because tables(and all other containers) always return\nthe object pointed by a weak ref::\n\n    print(t.thearray[0]);\n\nthe only strong reference to the array is owned by the local variable 'a', so\nbecause the following line assigns a integer to 'a' the array is destroyed.::\n\n    a = 123;\n\nWhen an object pointed by a weak ref is destroyed the weak ref is automatically set to null,\nso the following line will print \"null\".::\n\n    ::print(typeof(t.thearray))\n\n-----------------------------------\nHandling weak references explicitly\n-----------------------------------\n\nIf a weak reference is assigned to a local variable, then is treated as any other value.::\n\n    local t = {}\n    local weakobj = t.weakref();\n\nthe following line prints \"weakref\".::\n\n    ::print(typeof(weakobj))\n\nthe object pointed by the weakref can be obtained through the built-in method weakref.ref().\n\nThe following line prints \"table\".::\n\n    ::print(typeof(weakobj.ref()))\n"
  },
  {
    "path": "extlibs/squirrel/doc/source/reference/language.rst",
    "content": ".. _thelanguage:\n\n***************************\n  The language\n***************************\n\n.. toctree::\n   language/lexical_structure.rst\n   language/datatypes.rst\n   language/execution_context.rst\n   language/statements.rst\n   language/expressions.rst\n   language/tables.rst\n   language/arrays.rst\n   language/functions.rst\n   language/classes.rst\n   language/generators.rst\n   language/constants_and_enumerations.rst\n   language/threads.rst\n   language/weak_references.rst\n   language/delegation.rst\n   language/metamethods.rst\n   language/builtin_functions.rst\n"
  },
  {
    "path": "extlibs/squirrel/doc/source/stdlib/index.rst",
    "content": ".. _stdlib:\n\n#################################\n  Squirrel Standard Library 3.1\n#################################\n\nCopyright (c) 2003-2016 Alberto Demichelis\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n\n\n.. toctree::\n   :maxdepth: 1\n   :numbered:\n\n   introduction.rst\n   stdiolib.rst\n   stdbloblib.rst\n   stdmathlib.rst\n   stdsystemlib.rst\n   stdstringlib.rst\n   stdauxlib.rst\n\n"
  },
  {
    "path": "extlibs/squirrel/doc/source/stdlib/introduction.rst",
    "content": ".. _stdlib_introduction:\n\n============\nIntroduction\n============\n\nThe squirrel standard libraries consist in a set of modules implemented in C++.\nWhile are not essential for the language, they provide a set of useful services that are\ncommonly used by a wide range of applications(file I/O, regular expressions, etc...),\nplus they offer a foundation for developing additional libraries.\n\nAll libraries are implemented through the squirrel API and the ANSI C runtime library.\nThe modules are organized in the following way:\n\n* I/O : input and output\n* blob : binary buffers manipilation\n* math : basic mathematical routines\n* system : system access function\n* string : string formatting and manipulation\n* aux : auxiliary functions\n\nThe libraries can be registered independently,except for the IO library that depends from the bloblib.\n"
  },
  {
    "path": "extlibs/squirrel/doc/source/stdlib/stdauxlib.rst",
    "content": ".. _stdlib_stdauxlib:\n\n===============\nThe Aux library\n===============\n\nThe aux library implements default handlers for compiler and runtime errors and a stack dumping.\n\n+++++++++++\nC API\n+++++++++++\n\n.. _sqstd_seterrorhandlers:\n\n.. c:function:: void sqstd_seterrorhandlers(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n\n    initialize compiler and runtime error handlers, the handlers\n    use the print function set through(:ref:`sq_setprintfunc <sq_setprintfunc>`) to output\n    the error.\n\n.. _sqstd_printcallstack:\n\n.. c:function:: void sqstd_printcallstack(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n\n    prints the call stack and stack contents. the function\n    uses the print function set through(:ref:`sq_setprintfunc <sq_setprintfunc>`) to output\n    the stack dump.\n"
  },
  {
    "path": "extlibs/squirrel/doc/source/stdlib/stdbloblib.rst",
    "content": ".. _stdlib_stdbloblib:\n\n==================\nThe Blob library\n==================\nThe blob library implements binary data manipulations routines. The library is\nbased on `blob objects` that represent a buffer of arbitrary\nbinary data.\n\n---------------\nSquirrel API\n---------------\n\n+++++++++++++++\nGlobal symbols\n+++++++++++++++\n\n.. js:function:: castf2i(f)\n\n    casts a float to a int\n\n.. js:function:: casti2f(n)\n\n    casts a int to a float\n\n.. js:function:: swap2(n)\n\n    swap the byte order of a number (like it would be a 16bits integer)\n\n.. js:function:: swap4(n)\n\n    swap the byte order of an integer\n\n.. js:function:: swapfloat(n)\n\n    swaps the byteorder of a float\n\n++++++++++++++++++\nThe blob class\n++++++++++++++++++\n\nThe blob object is a buffer of arbitrary binary data. The object behaves like\na file stream, it has a read/write pointer and it automatically grows if data\nis written out of his boundary.\nA blob can also be accessed byte by byte through the `[]` operator.\n\n.. js:class:: blob(size)\n\n    :param int size: initial size of the blob\n\n    returns a new instance of a blob class of the specified size in bytes\n\n.. js:function:: blob.eos()\n\n    returns a non null value if the read/write pointer is at the end of the stream.\n\n.. js:function:: blob.flush()\n\n    flushes the stream.return a value != null if succeded, otherwise returns null\n\n.. js:function:: blob.len()\n\n    returns the length of the stream\n\n.. js:function:: blob.readblob(size)\n\n    :param int size: number of bytes to read\n\n    read n bytes from the stream and returns them as blob\n\n.. js:function:: blob.readn(type)\n\n    :param int type: type of the number to read\n\n    reads a number from the stream according to the type parameter.\n\n    `type` can have the following values:\n\n+--------------+--------------------------------------------------------------------------------+----------------------+\n| parameter    | return description                                                             |  return type         |\n+==============+================================================================================+======================+\n| 'l'          | processor dependent, 32bits on 32bits processors, 64bits on 64bits processors  |  integer             |\n+--------------+--------------------------------------------------------------------------------+----------------------+\n| 'i'          | 32bits number                                                                  |  integer             |\n+--------------+--------------------------------------------------------------------------------+----------------------+\n| 's'          | 16bits signed integer                                                          |  integer             |\n+--------------+--------------------------------------------------------------------------------+----------------------+\n| 'w'          | 16bits unsigned integer                                                        |  integer             |\n+--------------+--------------------------------------------------------------------------------+----------------------+\n| 'c'          | 8bits signed integer                                                           |  integer             |\n+--------------+--------------------------------------------------------------------------------+----------------------+\n| 'b'          | 8bits unsigned integer                                                         |  integer             |\n+--------------+--------------------------------------------------------------------------------+----------------------+\n| 'f'          | 32bits float                                                                   |  float               |\n+--------------+--------------------------------------------------------------------------------+----------------------+\n| 'd'          | 64bits float                                                                   |  float               |\n+--------------+--------------------------------------------------------------------------------+----------------------+\n\n.. js:function:: blob.resize(size)\n\n    :param int size: the new size of the blob in bytes\n\n    resizes the blob to the specified `size`\n\n.. js:function:: blob.seek(offset [,origin])\n\n    :param int offset: indicates the number of bytes from `origin`.\n    :param int origin: origin of the seek\n\n                        +--------------+-------------------------------------------+\n                        |  'b'         |  beginning of the stream                  |\n                        +--------------+-------------------------------------------+\n                        |  'c'         |  current location                         |\n                        +--------------+-------------------------------------------+\n                        |  'e'         |  end of the stream                        |\n                        +--------------+-------------------------------------------+\n\n    Moves the read/write pointer to a specified location.\n\n.. note:: If origin is omitted the parameter is defaulted as 'b'(beginning of the stream).\n\n.. js:function:: blob.swap2()\n\n    swaps the byte order of the blob content as it would be an array of `16bits integers`\n\n.. js:function:: blob.swap4()\n\n    swaps the byte order of the blob content as it would be an array of `32bits integers`\n\n.. js:function:: blob.tell()\n\n    returns the read/write pointer absolute position\n\n.. js:function:: blob.writeblob(src)\n\n    :param blob src: the source blob containing the data to be written\n\n    writes a blob in the stream\n\n.. js:function:: blob.writen(n, type)\n\n    :param number n: the value to be written\n    :param int type: type of the number to write\n\n    writes a number in the stream formatted according to the `type` parameter\n\n    `type` can have the following values:\n\n+--------------+--------------------------------------------------------------------------------+\n| parameter    | return description                                                             |\n+==============+================================================================================+\n| 'i'          | 32bits number                                                                  |\n+--------------+--------------------------------------------------------------------------------+\n| 's'          | 16bits signed integer                                                          |\n+--------------+--------------------------------------------------------------------------------+\n| 'w'          | 16bits unsigned integer                                                        |\n+--------------+--------------------------------------------------------------------------------+\n| 'c'          | 8bits signed integer                                                           |\n+--------------+--------------------------------------------------------------------------------+\n| 'b'          | 8bits unsigned integer                                                         |\n+--------------+--------------------------------------------------------------------------------+\n| 'f'          | 32bits float                                                                   |\n+--------------+--------------------------------------------------------------------------------+\n| 'd'          | 64bits float                                                                   |\n+--------------+--------------------------------------------------------------------------------+\n\n\n------\nC API\n------\n\n.. _sqstd_register_bloblib:\n\n.. c:function:: SQRESULT sqstd_register_bloblib(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n    :returns: an SQRESULT\n    :remarks: The function aspects a table on top of the stack where to register the global library functions.\n\n    initializes and registers the blob library in the given VM.\n\n.. _sqstd_getblob:\n\n.. c:function:: SQRESULT sqstd_getblob(HSQUIRRELVM v, SQInteger idx, SQUserPointer* ptr)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: and index in the stack\n    :param SQUserPointer* ptr: A pointer to the userpointer that will point to the blob's payload\n    :returns: an SQRESULT\n\n    retrieve the pointer of a blob's payload from an arbitrary\n    position in the stack.\n\n.. _sqstd_getblobsize:\n\n.. c:function:: SQInteger sqstd_getblobsize(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: and index in the stack\n    :returns: the size of the blob at `idx` position\n\n    retrieves the size of a blob's payload from an arbitrary\n    position in the stack.\n\n.. _sqstd_createblob:\n\n.. c:function:: SQUserPointer sqstd_createblob(HSQUIRRELVM v, SQInteger size)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger size:  the size of the blob payload that has to be created\n    :returns: a pointer to the newly created blob payload\n\n    creates a blob with the given payload size and pushes it in the stack.\n"
  },
  {
    "path": "extlibs/squirrel/doc/source/stdlib/stdiolib.rst",
    "content": ".. _stdlib_stdiolib:\n\n========================\nThe Input/Output library\n========================\n\nthe i/o library implements basic input/output routines.\n\n--------------\nSquirrel API\n--------------\n\n++++++++++++++\nGlobal Symbols\n++++++++++++++\n\n\n.. js:function:: dofile(path, [raiseerror])\n\n    compiles a squirrel script or loads a precompiled one and executes it.\n    returns the value returned by the script or null if no value is returned.\n    if the optional parameter 'raiseerror' is true, the compiler error handler is invoked\n    in case of a syntax error. If raiseerror is omitted or set to false, the compiler\n    error handler is not invoked.\n    When squirrel is compiled in Unicode mode the function can handle different character encodings,\n    UTF8 with and without prefix and UCS-2 prefixed(both big endian an little endian).\n    If the source stream is not prefixed UTF8 encoding is used as default.\n\n.. js:function:: loadfile(path, [raiseerror])\n\n    compiles a squirrel script or loads a precompiled one an returns it as as function.\n    if the optional parameter 'raiseerror' is true, the compiler error handler is invoked\n    in case of a syntax error. If raiseerror is omitted or set to false, the compiler\n    error handler is not invoked.\n    When squirrel is compiled in Unicode mode the function can handle different character encodings,\n    UTF8 with and without prefix and UCS-2 prefixed(both big endian an little endian).\n    If the source stream is not prefixed UTF8 encoding is used as default.\n\n.. js:function:: writeclosuretofile(destpath, closure)\n\n    serializes a closure to a bytecode file (destpath). The serialized file can be loaded\n    using loadfile() and dofile().\n\n\n.. js:data:: stderr\n\n    File object bound on the os *standard error* stream\n\n.. js:data:: stdin\n\n    File object bound on the os *standard input* stream\n\n.. js:data:: stdout\n\n    File object bound on the os *standard output* stream\n\n\n++++++++++++++\nThe file class\n++++++++++++++\n\n    The file object implements a stream on a operating system file.\n\n.. js:class:: file(path, patten)\n\n    It's constructor imitates the behaviour of the C runtime function fopen for eg. ::\n\n        local myfile = file(\"test.xxx\",\"wb+\");\n\n    creates a file with read/write access in the current directory.\n\n.. js:function:: file.close()\n\n    closes the file.\n\n.. js:function:: file.eos()\n\n    returns a non null value if the read/write pointer is at the end of the stream.\n\n.. js:function:: file.flush()\n\n    flushes the stream.return a value != null if succeeded, otherwise returns null\n\n.. js:function:: file.len()\n\n    returns the length of the stream\n\n.. js:function:: file.readblob(size)\n\n    :param int size: number of bytes to read\n\n    read n bytes from the stream and returns them as blob\n\n.. js:function:: file.readn(type)\n\n    :param int type: type of the number to read\n\n    reads a number from the stream according to the type parameter.\n\n    `type` can have the following values:\n\n+--------------+--------------------------------------------------------------------------------+----------------------+\n| parameter    | return description                                                             |  return type         |\n+==============+================================================================================+======================+\n| 'l'          | processor dependent, 32bits on 32bits processors, 64bits on 64bits processors  |  integer             |\n+--------------+--------------------------------------------------------------------------------+----------------------+\n| 'i'          | 32bits number                                                                  |  integer             |\n+--------------+--------------------------------------------------------------------------------+----------------------+\n| 's'          | 16bits signed integer                                                          |  integer             |\n+--------------+--------------------------------------------------------------------------------+----------------------+\n| 'w'          | 16bits unsigned integer                                                        |  integer             |\n+--------------+--------------------------------------------------------------------------------+----------------------+\n| 'c'          | 8bits signed integer                                                           |  integer             |\n+--------------+--------------------------------------------------------------------------------+----------------------+\n| 'b'          | 8bits unsigned integer                                                         |  integer             |\n+--------------+--------------------------------------------------------------------------------+----------------------+\n| 'f'          | 32bits float                                                                   |  float               |\n+--------------+--------------------------------------------------------------------------------+----------------------+\n| 'd'          | 64bits float                                                                   |  float               |\n+--------------+--------------------------------------------------------------------------------+----------------------+\n\n.. js:function:: file.resize(size)\n\n    :param int size: the new size of the blob in bytes\n\n    resizes the blob to the specified `size`\n\n.. js:function:: file.seek(offset [,origin])\n\n    :param int offset: indicates the number of bytes from `origin`.\n    :param int origin: origin of the seek\n\n                        +--------------+-------------------------------------------+\n                        |  'b'         |  beginning of the stream                  |\n                        +--------------+-------------------------------------------+\n                        |  'c'         |  current location                         |\n                        +--------------+-------------------------------------------+\n                        |  'e'         |  end of the stream                        |\n                        +--------------+-------------------------------------------+\n\n    Moves the read/write pointer to a specified location.\n\n.. note:: If origin is omitted the parameter is defaulted as 'b'(beginning of the stream).\n\n.. js:function:: file.tell()\n\n    returns the read/write pointer absolute position\n\n.. js:function:: file.writeblob(src)\n\n    :param blob src: the source blob containing the data to be written\n\n    writes a blob in the stream\n\n.. js:function:: file.writen(n, type)\n\n    :param number n: the value to be written\n    :param int type: type of the number to write\n\n    writes a number in the stream formatted according to the `type` pamraeter\n\n    `type` can have the following values:\n\n+--------------+--------------------------------------------------------------------------------+\n| parameter    | return description                                                             |\n+==============+================================================================================+\n| 'i'          | 32bits number                                                                  |\n+--------------+--------------------------------------------------------------------------------+\n| 's'          | 16bits signed integer                                                          |\n+--------------+--------------------------------------------------------------------------------+\n| 'w'          | 16bits unsigned integer                                                        |\n+--------------+--------------------------------------------------------------------------------+\n| 'c'          | 8bits signed integer                                                           |\n+--------------+--------------------------------------------------------------------------------+\n| 'b'          | 8bits unsigned integer                                                         |\n+--------------+--------------------------------------------------------------------------------+\n| 'f'          | 32bits float                                                                   |\n+--------------+--------------------------------------------------------------------------------+\n| 'd'          | 64bits float                                                                   |\n+--------------+--------------------------------------------------------------------------------+\n\n\n--------------\nC API\n--------------\n\n.. _sqstd_register_iolib:\n\n.. c:function:: SQRESULT sqstd_register_iolib(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n    :returns: an SQRESULT\n    :remarks: The function aspects a table on top of the stack where to register the global library functions.\n\n    initialize and register the io library in the given VM.\n\n++++++++++++++\nFile Object\n++++++++++++++\n\n.. c:function:: SQRESULT sqstd_createfile(HSQUIRRELVM v, SQFILE file, SQBool owns)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQFILE file: the stream that will be rapresented by the file object\n    :param SQBool owns: if different true the stream will be automatically closed when the newly create file object is destroyed.\n    :returns: an SQRESULT\n\n    creates a file object bound to the SQFILE passed as parameter\n    and pushes it in the stack\n\n.. c:function:: SQRESULT sqstd_getfile(HSQUIRRELVM v, SQInteger idx, SQFILE* file)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: and index in the stack\n    :param SQFILE* file: A pointer to a SQFILE handle that will store the result\n    :returns: an SQRESULT\n\n    retrieve the pointer of a stream handle from an arbitrary\n    position in the stack.\n\n++++++++++++++++++++++++++++++++\nScript loading and serialization\n++++++++++++++++++++++++++++++++\n\n.. c:function:: SQRESULT sqstd_loadfile(HSQUIRRELVM v, const SQChar* filename, SQBool printerror)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQChar* filename: path of the script that has to be loaded\n    :param SQBool printerror: if true the compiler error handler will be called if a error occurs\n    :returns: an SQRESULT\n\n    Compiles a squirrel script or loads a precompiled one an pushes it as closure in the stack.\n    When squirrel is compiled in Unicode mode the function can handle different character encodings,\n    UTF8 with and without prefix and UCS-2 prefixed(both big endian an little endian).\n    If the source stream is not prefixed UTF8 encoding is used as default.\n\n.. c:function:: SQRESULT sqstd_dofile(HSQUIRRELVM v, const SQChar* filename, SQBool retval, SQBool printerror)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQChar* filename: path of the script that has to be loaded\n    :param SQBool retval: if true the function will push the return value of the executed script in the stack.\n    :param SQBool printerror: if true the compiler error handler will be called if a error occurs\n    :returns: an SQRESULT\n    :remarks: the function expects a table on top of the stack that will be used as 'this' for the execution of the script. The 'this' parameter is left untouched in the stack.\n\n    Compiles a squirrel script or loads a precompiled one and executes it.\n    Optionally pushes the return value of the executed script in the stack.\n    When squirrel is compiled in unicode mode the function can handle different character encodings,\n    UTF8 with and without prefix and UCS-2 prefixed(both big endian an little endian).\n    If the source stream is not prefixed, UTF8 encoding is used as default. ::\n\n        sq_pushroottable(v); //push the root table(were the globals of the script will are stored)\n        sqstd_dofile(v, _SC(\"test.nut\"), SQFalse, SQTrue);// also prints syntax errors if any\n\n.. c:function:: SQRESULT sqstd_writeclosuretofile(HSQUIRRELVM v, const SQChar* filename)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQChar* filename: destination path of serialized closure\n    :returns: an SQRESULT\n\n    serializes the closure at the top position in the stack as bytecode in\n    the file specified by the parameter filename. If a file with the\n    same name already exists, it will be overwritten.\n\n"
  },
  {
    "path": "extlibs/squirrel/doc/source/stdlib/stdmathlib.rst",
    "content": ".. _stdlib_stdmathlib:\n\n================\nThe Math library\n================\n\nthe math lib provides basic mathematic routines. The library mimics the\nC runtime library implementation.\n\n------------\nSquirrel API\n------------\n\n+++++++++++++++\nGlobal Symbols\n+++++++++++++++\n\n.. js:function:: abs(x)\n\n    returns the absolute value of `x` as an integer\n\n.. js:function:: acos(x)\n\n    returns the arccosine of `x`\n\n.. js:function:: asin(x)\n\n    returns the arcsine of `x`\n\n.. js:function:: atan(x)\n\n    returns the arctangent of `x`\n\n.. js:function:: atan2(x,y)\n\n    returns the arctangent of  `x/y`\n\n.. js:function:: ceil(x)\n\n    returns a float value representing the smallest integer that is greater than or equal to `x`\n\n.. js:function:: cos(x)\n\n    returns the cosine of `x`\n\n.. js:function:: exp(x)\n\n    returns the exponential value of the float parameter `x`\n\n.. js:function:: fabs(x)\n\n    returns the absolute value of `x` as a float\n\n.. js:function:: floor(x)\n\n    returns a float value representing the largest integer that is less than or equal to `x`\n\n.. js:function:: log(x)\n\n    returns the natural logarithm of `x`\n\n.. js:function:: log10(x)\n\n    returns the logarithm base-10 of `x`\n\n.. js:function:: pow(x,y)\n\n    returns `x` raised to the power of `y`\n\n.. js:function:: rand()\n\n    returns a pseudorandom integer in the range 0 to `RAND_MAX`\n\n.. js:function:: sin(x)\n\n    rreturns the sine of `x`\n\n.. js:function:: sqrt(x)\n\n    returns the square root of `x`\n\n.. js:function:: srand(seed)\n\n    sets the starting point for generating a series of pseudorandom integers\n\n.. js:function:: tan(x)\n\n    returns the tangent of `x`\n\n.. js:data:: RAND_MAX\n\n    the maximum value that can be returned by the `rand()` function\n\n.. js:data:: PI\n\n    The numeric constant pi (3.141592) is the ratio of the circumference of a circle to its diameter\n\n------------\nC API\n------------\n\n.. _sqstd_register_mathlib:\n\n.. c:function:: SQRESULT sqstd_register_mathlib(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n    :returns: an SQRESULT\n    :remarks: The function aspects a table on top of the stack where to register the global library functions.\n\n    initializes and register the math library in the given VM.\n\n"
  },
  {
    "path": "extlibs/squirrel/doc/source/stdlib/stdstringlib.rst",
    "content": ".. _stdlib_stdstringlib:\n\n==================\nThe String library\n==================\n\nthe string lib implements string formatting and regular expression matching routines.\n\n--------------\nSquirrel API\n--------------\n\n++++++++++++++\nGlobal Symbols\n++++++++++++++\n\n.. js:function:: endswith(str, cmp)\n\n    returns `true` if the end of the string `str`  matches a the string `cmp` otherwise returns `false`\n\n.. js:function:: escape(str)\n\n    Returns a string with backslashes before characters that need to be escaped(`\\\",\\a,\\b,\\t,\\n,\\v,\\f,\\r,\\\\,\\\",\\',\\0,\\xnn`).\n\n.. js:function:: format(formatstr, ...)\n\n    Returns a string formatted according `formatstr` and the optional parameters following it.\n    The format string follows the same rules as the `printf` family of\n    standard C functions( the \"*\" is not supported). ::\n\n        e.g.\n        sq> print(format(\"%s %d 0x%02X\\n\",\"this is a test :\",123,10));\n        this is a test : 123 0x0A\n\n.. js:function:: printf(formatstr, ...)\n\n    Just like calling `print(format(formatstr` as in the example above, but is more convenient AND more efficient. ::\n\n        e.g.\n        sq> printf(\"%s %d 0x%02X\\n\",\"this is a test :\",123,10);\n        this is a test : 123 0x0A\n\n.. js:function:: lstrip(str)\n\n    Strips white-space-only characters that might appear at the beginning of the given string\n    and returns the new stripped string.\n\n.. js:function:: rstrip(str)\n\n    Strips white-space-only characters that might appear at the end of the given string\n    and returns the new stripped string.\n\n.. js:function:: split(str, separators)\n\n    returns an array of strings split at each point where a separator character occurs in `str`.\n    The separator is not returned as part of any array element.\n    The parameter `separators` is a string that specifies the characters as to be used for the splitting.\n\n    ::\n\n        eg.\n        local a = split(\"1.2-3;4/5\",\".-/;\");\n        // the result will be  [1,2,3,4,5]\n\n\n.. js:function:: startswith(str, cmp)\n\n    returns `true` if the beginning of the string `str` matches the string `cmp`; otherwise returns `false`\n\n.. js:function:: strip(str)\n\n    Strips white-space-only characters that might appear at the beginning or end of the given string and returns the new stripped string.\n\n++++++++++++++++++\nThe regexp class\n++++++++++++++++++\n\n.. js:class:: regexp(pattern)\n\n    The regexp object represents a precompiled regular expression pattern. The object is created\n    through `regexp(pattern)`.\n\n\n+---------------------+--------------------------------------+\n|      `\\\\`           |  Quote the next metacharacter        |\n+---------------------+--------------------------------------+\n|      `^`            |  Match the beginning of the string   |\n+---------------------+--------------------------------------+\n|      `.`            |  Match any character                 |\n+---------------------+--------------------------------------+\n|      `$`            |  Match the end of the string         |\n+---------------------+--------------------------------------+\n|      `|`            |  Alternation                         |\n+---------------------+--------------------------------------+\n|      `(subexp)`     |  Grouping (creates a capture)        |\n+---------------------+--------------------------------------+\n|      `(?:subexp)`   |  No Capture Grouping (no capture)    |\n+---------------------+--------------------------------------+\n|      `[]`           |  Character class                     |\n+---------------------+--------------------------------------+\n\n**GREEDY CLOSURES**\n\n+---------------------+---------------------------------------------+\n|      `*`            |  Match 0 or more times                      |\n+---------------------+---------------------------------------------+\n|      `+`            |  Match 1 or more times                      |\n+---------------------+---------------------------------------------+\n|      `?`            |  Match 1 or 0 times                         |\n+---------------------+---------------------------------------------+\n|      `{n}`          |  Match exactly n times                      |\n+---------------------+---------------------------------------------+\n|      `{n,}`         |  Match at least n times                     |\n+---------------------+---------------------------------------------+\n|      `{n,m}`        |  Match at least n but not more than m times |\n+---------------------+---------------------------------------------+\n\n**ESCAPE CHARACTERS**\n\n+---------------------+--------------------------------------+\n|      `\\\\t`          |  tab (HT, TAB)                       |\n+---------------------+--------------------------------------+\n|      `\\\\n`          |  newline (LF, NL)                    |\n+---------------------+--------------------------------------+\n|      `\\\\r`          | return (CR)                          |\n+---------------------+--------------------------------------+\n|      `\\\\f`          |  form feed (FF)                      |\n+---------------------+--------------------------------------+\n\n**PREDEFINED CLASSES**\n\n+---------------------+--------------------------------------+\n|      `\\\\l`          |  lowercase next char                 |\n+---------------------+--------------------------------------+\n|      `\\\\u`          |  uppercase next char                 |\n+---------------------+--------------------------------------+\n|      `\\\\a`          |  letters                             |\n+---------------------+--------------------------------------+\n|      `\\\\A`          |  non letters                         |\n+---------------------+--------------------------------------+\n|      `\\\\w`          |  alphanumeric `[_0-9a-zA-Z]`         |\n+---------------------+--------------------------------------+\n|      `\\\\W`          |  non alphanumeric `[^_0-9a-zA-Z]`    |\n+---------------------+--------------------------------------+\n|      `\\\\s`          |  space                               |\n+---------------------+--------------------------------------+\n|      `\\\\S`          |  non space                           |\n+---------------------+--------------------------------------+\n|      `\\\\d`          |  digits                              |\n+---------------------+--------------------------------------+\n|      `\\\\D`          |  non digits                          |\n+---------------------+--------------------------------------+\n|      `\\\\x`          |  hexadecimal digits                  |\n+---------------------+--------------------------------------+\n|      `\\\\X`          |  non hexadecimal digits              |\n+---------------------+--------------------------------------+\n|      `\\\\c`          |  control characters                  |\n+---------------------+--------------------------------------+\n|      `\\\\C`          |  non control characters              |\n+---------------------+--------------------------------------+\n|      `\\\\p`          |  punctuation                         |\n+---------------------+--------------------------------------+\n|      `\\\\P`          |  non punctuation                     |\n+---------------------+--------------------------------------+\n|      `\\\\b`          |  word boundary                       |\n+---------------------+--------------------------------------+\n|      `\\\\B`          |  non word boundary                   |\n+---------------------+--------------------------------------+\n\n\n.. js:function:: regexp.capture(str [, start])\n\n    returns an array of tables containing two indexes (\"begin\" and \"end\") of\n    the first match of the regular expression in the string `str`.\n    An array entry is created for each captured sub expressions. If no match occurs returns null.\n    The search starts from the index `start`\n    of the string; if `start` is omitted the search starts from the beginning of the string.\n\n    The first element of the returned array(index 0) always contains the complete match.\n\n    ::\n\n        local ex = regexp(@\"(\\d+) ([a-zA-Z]+)(\\p)\");\n        local string = \"stuff 123 Test;\";\n        local res = ex.capture(string);\n        foreach(i,val in res)\n        {\n            print(format(\"match number[%02d] %s\\n\",\n                    i,string.slice(val.begin,val.end))); //prints \"Test\"\n        }\n\n        ...\n        will print\n        match number[00] 123 Test;\n        match number[01] 123\n        match number[02] Test\n        match number[03] ;\n\n.. js:function:: regexp.match(str)\n\n    returns a true if the regular expression matches the string\n    `str`, otherwise returns false.\n\n.. js:function:: regexp.search(str [, start])\n\n    returns a table containing two indexes (\"begin\" and \"end\") of the first match of the regular expression in\n    the string `str`, otherwise if no match occurs returns null. The search starts from the index `start`\n    of the string; if `start` is omitted the search starts from the beginning of the string.\n\n    ::\n\n        local ex = regexp(\"[a-zA-Z]+\");\n        local string = \"123 Test;\";\n        local res = ex.search(string);\n        print(string.slice(res.begin,res.end)); //prints \"Test\"\n\n-------------\nC API\n-------------\n\n.. _sqstd_register_stringlib:\n\n.. c:function:: SQRESULT sqstd_register_stringlib(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n    :returns: an SQRESULT\n    :remarks: The function aspects a table on top of the stack where to register the global library functions.\n\n    initialize and register the string library in the given VM.\n\n+++++++++++++\nFormatting\n+++++++++++++\n\n.. c:function:: SQRESULT sqstd_format(HSQUIRRELVM v, SQInteger nformatstringidx, SQInteger* outlen, SQChar** output)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger nformatstringidx: index in the stack of the format string\n    :param SQInteger* outlen: a pointer to an integer that will be filled with the length of the newly created string\n    :param SQChar** output: a pointer to a string pointer that will receive the newly created string\n    :returns: an SQRESULT\n    :remarks: the newly created string is allocated in the scratchpad memory.\n\n\n    creates a new string formatted according to the object at position `nformatstringidx` and the optional parameters following it.\n    The format string follows the same rules as the `printf` family of\n    standard C functions( the \"*\" is not supported).\n\n++++++++++++++++++\nRegular Expessions\n++++++++++++++++++\n\n.. c:function:: SQRex* sqstd_rex_compile(const SQChar *pattern, const SQChar ** error)\n\n    :param SQChar* pattern: a pointer to a zero terminated string containing the pattern that has to be compiled.\n    :param SQChar** error: a pointer to a string pointer that will be set with an error string in case of failure.\n    :returns: a pointer to the compiled pattern\n\n    compiles an expression and returns a pointer to the compiled version.\n    in case of failure returns NULL.The returned object has to be deleted\n    through the function sqstd_rex_free().\n\n.. c:function:: void sqstd_rex_free(SQRex * exp)\n\n    :param SQRex* exp: the expression structure that has to be deleted.\n\n    deletes a expression structure created with sqstd_rex_compile()\n\n.. c:function:: SQBool sqstd_rex_match(SQRex * exp,const SQChar * text)\n\n    :param SQRex* exp: a compiled expression\n    :param SQChar* text: the string that has to be tested\n    :returns: SQTrue if successful otherwise SQFalse\n\n    returns SQTrue if the string specified in the parameter text is an\n    exact match of the expression, otherwise returns SQFalse.\n\n.. c:function:: SQBool sqstd_rex_search(SQRex * exp, const SQChar * text, const SQChar ** out_begin, const SQChar ** out_end)\n\n    :param SQRex* exp: a compiled expression\n    :param SQChar* text: the string that has to be tested\n    :param SQChar** out_begin: a pointer to a string pointer that will be set with the beginning of the match\n    :param SQChar** out_end: a pointer to a string pointer that will be set with the end of the match\n    :returns: SQTrue if successful otherwise SQFalse\n\n    searches the first match of the expression in the string specified in the parameter text.\n    if the match is found returns SQTrue and the sets out_begin to the beginning of the\n    match and out_end at the end of the match; otherwise returns SQFalse.\n\n.. c:function:: SQBool sqstd_rex_searchrange(SQRex * exp, const SQChar * text_begin, const SQChar * text_end, const SQChar ** out_begin, const SQChar ** out_end)\n\n    :param SQRex* exp: a compiled expression\n    :param SQChar* text_begin:  a pointer to the beginnning of the string that has to be tested\n    :param SQChar* text_end: a pointer to the end of the string that has to be tested\n    :param SQChar** out_begin: a pointer to a string pointer that will be set with the beginning of the match\n    :param SQChar** out_end: a pointer to a string pointer that will be set with the end of the match\n    :returns: SQTrue if successful otherwise SQFalse\n\n    searches the first match of the expression in the string delimited\n    by the parameter text_begin and text_end.\n    if the match is found returns SQTrue and sets out_begin to the beginning of the\n    match and out_end at the end of the match; otherwise returns SQFalse.\n\n.. c:function:: SQInteger sqstd_rex_getsubexpcount(SQRex * exp)\n\n    :param SQRex* exp: a compiled expression\n    :returns: the number of sub expressions matched by the expression\n\n    returns the number of sub expressions matched by the expression\n\n.. c:function:: SQBool sqstd_rex_getsubexp(SQRex * exp, SQInteger n, SQRexMatch *subexp)\n\n    :param SQRex* exp: a compiled expression\n    :param SQInteger n: the index of the submatch(0 is the complete match)\n    :param SQRexMatch* a: pointer to structure that will store the result\n    :returns: the function returns SQTrue if n is a valid index; otherwise SQFalse.\n\n    retrieve the begin and and pointer to the length of the sub expression indexed\n    by n. The result is passed through the struct SQRexMatch.\n"
  },
  {
    "path": "extlibs/squirrel/doc/source/stdlib/stdsystemlib.rst",
    "content": ".. _stdlib_stdsystemlib:\n\n==================\nThe System library\n==================\n\nThe system library exposes operating system facilities like environment variables,\ndate time manipulation etc..\n\n--------------\nSquirrel API\n--------------\n\n++++++++++++++\nGlobal Symbols\n++++++++++++++\n\n.. js:function:: clock()\n\n    returns a float representing the number of seconds elapsed since the start of the process\n\n.. js:function:: date([time [, format]])\n\n    returns a table containing a date/time split into the slots:\n\n+-------------+----------------------------------------+\n| sec         | Seconds after minute (0 - 59).         |\n+-------------+----------------------------------------+\n| min         | Minutes after hour (0 - 59).           |\n+-------------+----------------------------------------+\n| hour        | Hours since midnight (0 - 23).         |\n+-------------+----------------------------------------+\n| day         | Day of month (1 - 31).                 |\n+-------------+----------------------------------------+\n| month       | Month (0 - 11; January = 0).           |\n+-------------+----------------------------------------+\n| year        | Year (current year).                   |\n+-------------+----------------------------------------+\n| wday        | Day of week (0 - 6; Sunday = 0).       |\n+-------------+----------------------------------------+\n| yday        | Day of year (0 - 365; January 1 = 0).  |\n+-------------+----------------------------------------+\n\nif `time` is omitted the current time is used.\n\nif `format` can be 'l' local time or 'u' UTC time, if omitted is defaulted as 'l'(local time).\n\n.. js:function:: getenv(varaname)\n\n    Returns a string containing the value of the environment variable `varname`\n\n.. js:function:: remove(path)\n\n    deletes the file specified by `path`\n\n.. js:function:: rename(oldname, newname)\n\n    renames the file or directory specified by `oldname` to the name given by `newname`\n\n.. js:function:: system(cmd)\n\n    xecutes the string `cmd` through the os command interpreter.\n\n.. js:function:: time()\n\n    returns the number of seconds elapsed since midnight 00:00:00, January 1, 1970.\n\n    the result of this function can be formatted through the function `date()`\n\n--------------\nC API\n--------------\n\n.. _sqstd_register_systemlib:\n\n.. c:function:: SQRESULT sqstd_register_systemlib(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n    :returns: an SQRESULT\n    :remarks: The function aspects a table on top of the stack where to register the global library functions.\n\n    initialize and register the system library in the given VM.\n"
  },
  {
    "path": "extlibs/squirrel/etc/minimal.c",
    "content": "#include <stdarg.h>\n#include <stdio.h>\n\n#include <squirrel.h>\n#include <sqstdio.h>\n#include <sqstdaux.h>\n\n#ifdef _MSC_VER\n#pragma comment (lib ,\"squirrel.lib\")\n#pragma comment (lib ,\"sqstdlib.lib\")\n#endif\n\n#ifdef SQUNICODE\n\n#define scvprintf vfwprintf\n#else\n\n#define scvprintf vfprintf\n#endif\n\nvoid printfunc(HSQUIRRELVM v,const SQChar *s,...)\n{\n    va_list vl;\n    va_start(vl, s);\n    scvprintf(stdout, s, vl);\n    va_end(vl);\n}\n\nvoid errorfunc(HSQUIRRELVM v,const SQChar *s,...)\n{\n    va_list vl;\n    va_start(vl, s);\n    scvprintf(stderr, s, vl);\n    va_end(vl);\n}\n\nvoid call_foo(HSQUIRRELVM v, int n,float f,const SQChar *s)\n{\n    SQInteger top = sq_gettop(v); //saves the stack size before the call\n    sq_pushroottable(v); //pushes the global table\n    sq_pushstring(v,_SC(\"foo\"),-1);\n    if(SQ_SUCCEEDED(sq_get(v,-2))) { //gets the field 'foo' from the global table\n        sq_pushroottable(v); //push the 'this' (in this case is the global table)\n        sq_pushinteger(v,n);\n        sq_pushfloat(v,f);\n        sq_pushstring(v,s,-1);\n        sq_call(v,4,SQFalse,SQTrue); //calls the function\n    }\n    sq_settop(v,top); //restores the original stack size\n}\n\nint main(int argc, char* argv[])\n{\n    HSQUIRRELVM v;\n    v = sq_open(1024); // creates a VM with initial stack size 1024\n\n    //REGISTRATION OF STDLIB\n    //sq_pushroottable(v); //push the root table where the std function will be registered\n    //sqstd_register_iolib(v);  //registers a library\n    // ... call here other stdlibs string,math etc...\n    //sq_pop(v,1); //pops the root table\n    //END REGISTRATION OF STDLIB\n\n    sqstd_seterrorhandlers(v); //registers the default error handlers\n\n    sq_setprintfunc(v, printfunc,errorfunc); //sets the print function\n\n    sq_pushroottable(v); //push the root table(were the globals of the script will be stored)\n    if(SQ_SUCCEEDED(sqstd_dofile(v, _SC(\"test.nut\"), SQFalse, SQTrue))) // also prints syntax errors if any\n    {\n        call_foo(v,1,2.5,_SC(\"teststring\"));\n    }\n\n    sq_pop(v,1); //pops the root table\n    sq_close(v);\n\n    return 0;\n}\n"
  },
  {
    "path": "extlibs/squirrel/etc/test.nut",
    "content": "function foo(i, f, s)\n{\n    print(\"Called foo(), i=\"+i+\", f=\"+f+\", s='\"+s+\"'\\n\");\n}\n"
  },
  {
    "path": "extlibs/squirrel/include/sqconfig.h",
    "content": "\n#ifdef _SQ64\n\n#ifdef _MSC_VER\ntypedef __int64 SQInteger;\ntypedef unsigned __int64 SQUnsignedInteger;\ntypedef unsigned __int64 SQHash; /*should be the same size of a pointer*/\n#else\ntypedef long long SQInteger;\ntypedef unsigned long long SQUnsignedInteger;\ntypedef unsigned long long SQHash; /*should be the same size of a pointer*/\n#endif\ntypedef int SQInt32;\ntypedef unsigned int SQUnsignedInteger32;\n#else\ntypedef int SQInteger;\ntypedef int SQInt32; /*must be 32 bits(also on 64bits processors)*/\ntypedef unsigned int SQUnsignedInteger32; /*must be 32 bits(also on 64bits processors)*/\ntypedef unsigned int SQUnsignedInteger;\ntypedef unsigned int SQHash; /*should be the same size of a pointer*/\n#endif\n\n\n#ifdef SQUSEDOUBLE\ntypedef double SQFloat;\n#else\ntypedef float SQFloat;\n#endif\n\n#if defined(SQUSEDOUBLE) && !defined(_SQ64) || !defined(SQUSEDOUBLE) && defined(_SQ64)\n#ifdef _MSC_VER\ntypedef __int64 SQRawObjectVal; //must be 64bits\n#else\ntypedef long long SQRawObjectVal; //must be 64bits\n#endif\n#define SQ_OBJECT_RAWINIT() { _unVal.raw = 0; }\n#else\ntypedef SQUnsignedInteger SQRawObjectVal; //is 32 bits on 32 bits builds and 64 bits otherwise\n#define SQ_OBJECT_RAWINIT()\n#endif\n\n#ifndef SQ_ALIGNMENT // SQ_ALIGNMENT shall be less than or equal to SQ_MALLOC alignments, and its value shall be power of 2.\n#if defined(SQUSEDOUBLE) || defined(_SQ64)\n#define SQ_ALIGNMENT 8\n#else\n#define SQ_ALIGNMENT 4\n#endif\n#endif\n\ntypedef void* SQUserPointer;\ntypedef SQUnsignedInteger SQBool;\ntypedef SQInteger SQRESULT;\n\n#ifdef SQUNICODE\n#include <wchar.h>\n#include <wctype.h>\n\n\ntypedef wchar_t SQChar;\n\n\n#define scstrcmp    wcscmp\n#ifdef _WIN32\n#define scsprintf   _snwprintf\n#else\n#define scsprintf   swprintf\n#endif\n#define scstrlen    wcslen\n#define scstrtod    wcstod\n#ifdef _SQ64\n#define scstrtol    wcstoll\n#else\n#define scstrtol    wcstol\n#endif\n#define scstrtoul   wcstoul\n#define scvsprintf  vswprintf\n#define scstrstr    wcsstr\n#define scprintf    wprintf\n\n#ifdef _WIN32\n#define WCHAR_SIZE 2\n#define WCHAR_SHIFT_MUL 1\n#define MAX_CHAR 0xFFFF\n#else\n#define WCHAR_SIZE 4\n#define WCHAR_SHIFT_MUL 2\n#define MAX_CHAR 0xFFFFFFFF\n#endif\n\n#define _SC(a) L##a\n\n\n#define scisspace   iswspace\n#define scisdigit   iswdigit\n#define scisprint   iswprint\n#define scisxdigit  iswxdigit\n#define scisalpha   iswalpha\n#define sciscntrl   iswcntrl\n#define scisalnum   iswalnum\n\n\n#define sq_rsl(l) ((l)<<WCHAR_SHIFT_MUL)\n\n#else\ntypedef char SQChar;\n#define _SC(a) a\n#define scstrcmp    strcmp\n#ifdef _MSC_VER\n#define scsprintf   _snprintf\n#else\n#define scsprintf   snprintf\n#endif\n#define scstrlen    strlen\n#define scstrtod    strtod\n#ifdef _SQ64\n#ifdef _MSC_VER\n#define scstrtol    _strtoi64\n#else\n#define scstrtol    strtoll\n#endif\n#else\n#define scstrtol    strtol\n#endif\n#define scstrtoul   strtoul\n#define scvsprintf  vsnprintf\n#define scstrstr    strstr\n#define scisspace   isspace\n#define scisdigit   isdigit\n#define scisprint   isprint\n#define scisxdigit  isxdigit\n#define sciscntrl   iscntrl\n#define scisalpha   isalpha\n#define scisalnum   isalnum\n#define scprintf    printf\n#define MAX_CHAR 0xFF\n\n#define sq_rsl(l) (l)\n\n#endif\n\n#ifdef _SQ64\n#define _PRINT_INT_PREC _SC(\"ll\")\n#define _PRINT_INT_FMT _SC(\"%lld\")\n#else\n#define _PRINT_INT_FMT _SC(\"%d\")\n#endif\n"
  },
  {
    "path": "extlibs/squirrel/include/sqstdaux.h",
    "content": "/*  see copyright notice in squirrel.h */\n#ifndef _SQSTD_AUXLIB_H_\n#define _SQSTD_AUXLIB_H_\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nSQUIRREL_API void sqstd_seterrorhandlers(HSQUIRRELVM v);\nSQUIRREL_API void sqstd_printcallstack(HSQUIRRELVM v);\n\n#ifdef __cplusplus\n} /*extern \"C\"*/\n#endif\n\n#endif /* _SQSTD_AUXLIB_H_ */\n"
  },
  {
    "path": "extlibs/squirrel/include/sqstdblob.h",
    "content": "/*  see copyright notice in squirrel.h */\n#ifndef _SQSTDBLOB_H_\n#define _SQSTDBLOB_H_\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nSQUIRREL_API SQUserPointer sqstd_createblob(HSQUIRRELVM v, SQInteger size);\nSQUIRREL_API SQRESULT sqstd_getblob(HSQUIRRELVM v,SQInteger idx,SQUserPointer *ptr);\nSQUIRREL_API SQInteger sqstd_getblobsize(HSQUIRRELVM v,SQInteger idx);\n\nSQUIRREL_API SQRESULT sqstd_register_bloblib(HSQUIRRELVM v);\n\n#ifdef __cplusplus\n} /*extern \"C\"*/\n#endif\n\n#endif /*_SQSTDBLOB_H_*/\n\n"
  },
  {
    "path": "extlibs/squirrel/include/sqstdio.h",
    "content": "/*  see copyright notice in squirrel.h */\n#ifndef _SQSTDIO_H_\n#define _SQSTDIO_H_\n\n#ifdef __cplusplus\n\n#define SQSTD_STREAM_TYPE_TAG 0x80000000\n\nstruct SQStream {\n    virtual ~SQStream() {}\n    virtual SQInteger Read(void *buffer, SQInteger size) = 0;\n    virtual SQInteger Write(void *buffer, SQInteger size) = 0;\n    virtual SQInteger Flush() = 0;\n    virtual SQInteger Tell() = 0;\n    virtual SQInteger Len() = 0;\n    virtual SQInteger Seek(SQInteger offset, SQInteger origin) = 0;\n    virtual bool IsValid() = 0;\n    virtual bool EOS() = 0;\n};\n\nextern \"C\" {\n#endif\n\n#define SQ_SEEK_CUR 0\n#define SQ_SEEK_END 1\n#define SQ_SEEK_SET 2\n\ntypedef void* SQFILE;\n\nSQUIRREL_API SQFILE sqstd_fopen(const SQChar *,const SQChar *);\nSQUIRREL_API SQInteger sqstd_fread(SQUserPointer, SQInteger, SQInteger, SQFILE);\nSQUIRREL_API SQInteger sqstd_fwrite(const SQUserPointer, SQInteger, SQInteger, SQFILE);\nSQUIRREL_API SQInteger sqstd_fseek(SQFILE , SQInteger , SQInteger);\nSQUIRREL_API SQInteger sqstd_ftell(SQFILE);\nSQUIRREL_API SQInteger sqstd_fflush(SQFILE);\nSQUIRREL_API SQInteger sqstd_fclose(SQFILE);\nSQUIRREL_API SQInteger sqstd_feof(SQFILE);\n\nSQUIRREL_API SQRESULT sqstd_createfile(HSQUIRRELVM v, SQFILE file,SQBool own);\nSQUIRREL_API SQRESULT sqstd_getfile(HSQUIRRELVM v, SQInteger idx, SQFILE *file);\n\n//compiler helpers\nSQUIRREL_API SQRESULT sqstd_loadfile(HSQUIRRELVM v,const SQChar *filename,SQBool printerror);\nSQUIRREL_API SQRESULT sqstd_dofile(HSQUIRRELVM v,const SQChar *filename,SQBool retval,SQBool printerror);\nSQUIRREL_API SQRESULT sqstd_writeclosuretofile(HSQUIRRELVM v,const SQChar *filename);\n\nSQUIRREL_API SQRESULT sqstd_register_iolib(HSQUIRRELVM v);\n\n#ifdef __cplusplus\n} /*extern \"C\"*/\n#endif\n\n#endif /*_SQSTDIO_H_*/\n\n"
  },
  {
    "path": "extlibs/squirrel/include/sqstdmath.h",
    "content": "/*  see copyright notice in squirrel.h */\n#ifndef _SQSTD_MATH_H_\n#define _SQSTD_MATH_H_\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nSQUIRREL_API SQRESULT sqstd_register_mathlib(HSQUIRRELVM v);\n\n#ifdef __cplusplus\n} /*extern \"C\"*/\n#endif\n\n#endif /*_SQSTD_MATH_H_*/\n"
  },
  {
    "path": "extlibs/squirrel/include/sqstdstring.h",
    "content": "/*  see copyright notice in squirrel.h */\n#ifndef _SQSTD_STRING_H_\n#define _SQSTD_STRING_H_\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef unsigned int SQRexBool;\ntypedef struct SQRex SQRex;\n\ntypedef struct {\n    const SQChar *begin;\n    SQInteger len;\n} SQRexMatch;\n\nSQUIRREL_API SQRex *sqstd_rex_compile(const SQChar *pattern,const SQChar **error);\nSQUIRREL_API void sqstd_rex_free(SQRex *exp);\nSQUIRREL_API SQBool sqstd_rex_match(SQRex* exp,const SQChar* text);\nSQUIRREL_API SQBool sqstd_rex_search(SQRex* exp,const SQChar* text, const SQChar** out_begin, const SQChar** out_end);\nSQUIRREL_API SQBool sqstd_rex_searchrange(SQRex* exp,const SQChar* text_begin,const SQChar* text_end,const SQChar** out_begin, const SQChar** out_end);\nSQUIRREL_API SQInteger sqstd_rex_getsubexpcount(SQRex* exp);\nSQUIRREL_API SQBool sqstd_rex_getsubexp(SQRex* exp, SQInteger n, SQRexMatch *subexp);\n\nSQUIRREL_API SQRESULT sqstd_format(HSQUIRRELVM v,SQInteger nformatstringidx,SQInteger *outlen,SQChar **output);\n\nSQUIRREL_API SQRESULT sqstd_register_stringlib(HSQUIRRELVM v);\n\n#ifdef __cplusplus\n} /*extern \"C\"*/\n#endif\n\n#endif /*_SQSTD_STRING_H_*/\n"
  },
  {
    "path": "extlibs/squirrel/include/sqstdsystem.h",
    "content": "/*  see copyright notice in squirrel.h */\n#ifndef _SQSTD_SYSTEMLIB_H_\n#define _SQSTD_SYSTEMLIB_H_\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nSQUIRREL_API SQInteger sqstd_register_systemlib(HSQUIRRELVM v);\n\n#ifdef __cplusplus\n} /*extern \"C\"*/\n#endif\n\n#endif /* _SQSTD_SYSTEMLIB_H_ */\n"
  },
  {
    "path": "extlibs/squirrel/include/squirrel.h",
    "content": "/*\nCopyright (c) 2003-2017 Alberto Demichelis\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n*/\n#ifndef _SQUIRREL_H_\n#define _SQUIRREL_H_\n\n#ifdef _SQ_CONFIG_INCLUDE\n#include _SQ_CONFIG_INCLUDE\n#endif\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#ifndef SQUIRREL_API\n#define SQUIRREL_API extern\n#endif\n\n#if (defined(_WIN64) || defined(_LP64))\n#ifndef _SQ64\n#define _SQ64\n#endif\n#endif\n\n\n#define SQTrue  (1)\n#define SQFalse (0)\n\nstruct SQVM;\nstruct SQTable;\nstruct SQArray;\nstruct SQString;\nstruct SQClosure;\nstruct SQGenerator;\nstruct SQNativeClosure;\nstruct SQUserData;\nstruct SQFunctionProto;\nstruct SQRefCounted;\nstruct SQClass;\nstruct SQInstance;\nstruct SQDelegable;\nstruct SQOuter;\n\n#ifdef _UNICODE\n#define SQUNICODE\n#endif\n\n#include \"sqconfig.h\"\n\n#define SQUIRREL_VERSION    _SC(\"Squirrel 3.1 stable\")\n#define SQUIRREL_COPYRIGHT  _SC(\"Copyright (C) 2003-2017 Alberto Demichelis\")\n#define SQUIRREL_AUTHOR     _SC(\"Alberto Demichelis\")\n#define SQUIRREL_VERSION_NUMBER 310\n\n#define SQ_VMSTATE_IDLE         0\n#define SQ_VMSTATE_RUNNING      1\n#define SQ_VMSTATE_SUSPENDED    2\n\n#define SQUIRREL_EOB 0\n#define SQ_BYTECODE_STREAM_TAG  0xFAFA\n\n#define SQOBJECT_REF_COUNTED    0x08000000\n#define SQOBJECT_NUMERIC        0x04000000\n#define SQOBJECT_DELEGABLE      0x02000000\n#define SQOBJECT_CANBEFALSE     0x01000000\n\n#define SQ_MATCHTYPEMASKSTRING (-99999)\n\n#define _RT_MASK 0x00FFFFFF\n#define _RAW_TYPE(type) (type&_RT_MASK)\n\n#define _RT_NULL            0x00000001\n#define _RT_INTEGER         0x00000002\n#define _RT_FLOAT           0x00000004\n#define _RT_BOOL            0x00000008\n#define _RT_STRING          0x00000010\n#define _RT_TABLE           0x00000020\n#define _RT_ARRAY           0x00000040\n#define _RT_USERDATA        0x00000080\n#define _RT_CLOSURE         0x00000100\n#define _RT_NATIVECLOSURE   0x00000200\n#define _RT_GENERATOR       0x00000400\n#define _RT_USERPOINTER     0x00000800\n#define _RT_THREAD          0x00001000\n#define _RT_FUNCPROTO       0x00002000\n#define _RT_CLASS           0x00004000\n#define _RT_INSTANCE        0x00008000\n#define _RT_WEAKREF         0x00010000\n#define _RT_OUTER           0x00020000\n\ntypedef enum tagSQObjectType{\n    OT_NULL =           (_RT_NULL|SQOBJECT_NUMERIC|SQOBJECT_CANBEFALSE),\n    OT_INTEGER =        (_RT_INTEGER|SQOBJECT_NUMERIC|SQOBJECT_CANBEFALSE),\n    OT_FLOAT =          (_RT_FLOAT|SQOBJECT_NUMERIC|SQOBJECT_CANBEFALSE),\n    OT_BOOL =           (_RT_BOOL|SQOBJECT_NUMERIC|SQOBJECT_CANBEFALSE),\n    OT_STRING =         (_RT_STRING|SQOBJECT_REF_COUNTED),\n    OT_TABLE =          (_RT_TABLE|SQOBJECT_REF_COUNTED|SQOBJECT_DELEGABLE),\n    OT_ARRAY =          (_RT_ARRAY|SQOBJECT_REF_COUNTED),\n    OT_USERDATA =       (_RT_USERDATA|SQOBJECT_REF_COUNTED|SQOBJECT_DELEGABLE),\n    OT_CLOSURE =        (_RT_CLOSURE|SQOBJECT_REF_COUNTED),\n    OT_NATIVECLOSURE =  (_RT_NATIVECLOSURE|SQOBJECT_REF_COUNTED),\n    OT_GENERATOR =      (_RT_GENERATOR|SQOBJECT_REF_COUNTED),\n    OT_USERPOINTER =    _RT_USERPOINTER,\n    OT_THREAD =         (_RT_THREAD|SQOBJECT_REF_COUNTED) ,\n    OT_FUNCPROTO =      (_RT_FUNCPROTO|SQOBJECT_REF_COUNTED), //internal usage only\n    OT_CLASS =          (_RT_CLASS|SQOBJECT_REF_COUNTED),\n    OT_INSTANCE =       (_RT_INSTANCE|SQOBJECT_REF_COUNTED|SQOBJECT_DELEGABLE),\n    OT_WEAKREF =        (_RT_WEAKREF|SQOBJECT_REF_COUNTED),\n    OT_OUTER =          (_RT_OUTER|SQOBJECT_REF_COUNTED) //internal usage only\n}SQObjectType;\n\n#define ISREFCOUNTED(t) (t&SQOBJECT_REF_COUNTED)\n\n\ntypedef union tagSQObjectValue\n{\n    struct SQTable *pTable;\n    struct SQArray *pArray;\n    struct SQClosure *pClosure;\n    struct SQOuter *pOuter;\n    struct SQGenerator *pGenerator;\n    struct SQNativeClosure *pNativeClosure;\n    struct SQString *pString;\n    struct SQUserData *pUserData;\n    SQInteger nInteger;\n    SQFloat fFloat;\n    SQUserPointer pUserPointer;\n    struct SQFunctionProto *pFunctionProto;\n    struct SQRefCounted *pRefCounted;\n    struct SQDelegable *pDelegable;\n    struct SQVM *pThread;\n    struct SQClass *pClass;\n    struct SQInstance *pInstance;\n    struct SQWeakRef *pWeakRef;\n    SQRawObjectVal raw;\n}SQObjectValue;\n\n\ntypedef struct tagSQObject\n{\n    SQObjectType _type;\n    SQObjectValue _unVal;\n}SQObject;\n\ntypedef struct  tagSQMemberHandle{\n    SQBool _static;\n    SQInteger _index;\n}SQMemberHandle;\n\ntypedef struct tagSQStackInfos{\n    const SQChar* funcname;\n    const SQChar* source;\n    SQInteger line;\n}SQStackInfos;\n\ntypedef struct SQVM* HSQUIRRELVM;\ntypedef SQObject HSQOBJECT;\ntypedef SQMemberHandle HSQMEMBERHANDLE;\ntypedef SQInteger (*SQFUNCTION)(HSQUIRRELVM);\ntypedef SQInteger (*SQRELEASEHOOK)(SQUserPointer,SQInteger size);\ntypedef void (*SQCOMPILERERROR)(HSQUIRRELVM,const SQChar * /*desc*/,const SQChar * /*source*/,SQInteger /*line*/,SQInteger /*column*/);\ntypedef void (*SQPRINTFUNCTION)(HSQUIRRELVM,const SQChar * ,...);\ntypedef void (*SQDEBUGHOOK)(HSQUIRRELVM /*v*/, SQInteger /*type*/, const SQChar * /*sourcename*/, SQInteger /*line*/, const SQChar * /*funcname*/);\ntypedef SQInteger (*SQWRITEFUNC)(SQUserPointer,SQUserPointer,SQInteger);\ntypedef SQInteger (*SQREADFUNC)(SQUserPointer,SQUserPointer,SQInteger);\n\ntypedef SQInteger (*SQLEXREADFUNC)(SQUserPointer);\n\ntypedef struct tagSQRegFunction{\n    const SQChar *name;\n    SQFUNCTION f;\n    SQInteger nparamscheck;\n    const SQChar *typemask;\n}SQRegFunction;\n\ntypedef struct tagSQFunctionInfo {\n    SQUserPointer funcid;\n    const SQChar *name;\n    const SQChar *source;\n    SQInteger line;\n}SQFunctionInfo;\n\n/*vm*/\nSQUIRREL_API HSQUIRRELVM sq_open(SQInteger initialstacksize);\nSQUIRREL_API HSQUIRRELVM sq_newthread(HSQUIRRELVM friendvm, SQInteger initialstacksize);\nSQUIRREL_API void sq_seterrorhandler(HSQUIRRELVM v);\nSQUIRREL_API void sq_close(HSQUIRRELVM v);\nSQUIRREL_API void sq_setforeignptr(HSQUIRRELVM v,SQUserPointer p);\nSQUIRREL_API SQUserPointer sq_getforeignptr(HSQUIRRELVM v);\nSQUIRREL_API void sq_setsharedforeignptr(HSQUIRRELVM v,SQUserPointer p);\nSQUIRREL_API SQUserPointer sq_getsharedforeignptr(HSQUIRRELVM v);\nSQUIRREL_API void sq_setvmreleasehook(HSQUIRRELVM v,SQRELEASEHOOK hook);\nSQUIRREL_API SQRELEASEHOOK sq_getvmreleasehook(HSQUIRRELVM v);\nSQUIRREL_API void sq_setsharedreleasehook(HSQUIRRELVM v,SQRELEASEHOOK hook);\nSQUIRREL_API SQRELEASEHOOK sq_getsharedreleasehook(HSQUIRRELVM v);\nSQUIRREL_API void sq_setprintfunc(HSQUIRRELVM v, SQPRINTFUNCTION printfunc,SQPRINTFUNCTION errfunc);\nSQUIRREL_API SQPRINTFUNCTION sq_getprintfunc(HSQUIRRELVM v);\nSQUIRREL_API SQPRINTFUNCTION sq_geterrorfunc(HSQUIRRELVM v);\nSQUIRREL_API SQRESULT sq_suspendvm(HSQUIRRELVM v);\nSQUIRREL_API SQRESULT sq_wakeupvm(HSQUIRRELVM v,SQBool resumedret,SQBool retval,SQBool raiseerror,SQBool throwerror);\nSQUIRREL_API SQInteger sq_getvmstate(HSQUIRRELVM v);\nSQUIRREL_API SQInteger sq_getversion();\n\n/*compiler*/\nSQUIRREL_API SQRESULT sq_compile(HSQUIRRELVM v,SQLEXREADFUNC read,SQUserPointer p,const SQChar *sourcename,SQBool raiseerror);\nSQUIRREL_API SQRESULT sq_compilebuffer(HSQUIRRELVM v,const SQChar *s,SQInteger size,const SQChar *sourcename,SQBool raiseerror);\nSQUIRREL_API void sq_enabledebuginfo(HSQUIRRELVM v, SQBool enable);\nSQUIRREL_API void sq_notifyallexceptions(HSQUIRRELVM v, SQBool enable);\nSQUIRREL_API void sq_setcompilererrorhandler(HSQUIRRELVM v,SQCOMPILERERROR f);\n\n/*stack operations*/\nSQUIRREL_API void sq_push(HSQUIRRELVM v,SQInteger idx);\nSQUIRREL_API void sq_pop(HSQUIRRELVM v,SQInteger nelemstopop);\nSQUIRREL_API void sq_poptop(HSQUIRRELVM v);\nSQUIRREL_API void sq_remove(HSQUIRRELVM v,SQInteger idx);\nSQUIRREL_API SQInteger sq_gettop(HSQUIRRELVM v);\nSQUIRREL_API void sq_settop(HSQUIRRELVM v,SQInteger newtop);\nSQUIRREL_API SQRESULT sq_reservestack(HSQUIRRELVM v,SQInteger nsize);\nSQUIRREL_API SQInteger sq_cmp(HSQUIRRELVM v);\nSQUIRREL_API void sq_move(HSQUIRRELVM dest,HSQUIRRELVM src,SQInteger idx);\n\n/*object creation handling*/\nSQUIRREL_API SQUserPointer sq_newuserdata(HSQUIRRELVM v,SQUnsignedInteger size);\nSQUIRREL_API void sq_newtable(HSQUIRRELVM v);\nSQUIRREL_API void sq_newtableex(HSQUIRRELVM v,SQInteger initialcapacity);\nSQUIRREL_API void sq_newarray(HSQUIRRELVM v,SQInteger size);\nSQUIRREL_API void sq_newclosure(HSQUIRRELVM v,SQFUNCTION func,SQUnsignedInteger nfreevars);\nSQUIRREL_API SQRESULT sq_setparamscheck(HSQUIRRELVM v,SQInteger nparamscheck,const SQChar *typemask);\nSQUIRREL_API SQRESULT sq_bindenv(HSQUIRRELVM v,SQInteger idx);\nSQUIRREL_API SQRESULT sq_setclosureroot(HSQUIRRELVM v,SQInteger idx);\nSQUIRREL_API SQRESULT sq_getclosureroot(HSQUIRRELVM v,SQInteger idx);\nSQUIRREL_API void sq_pushstring(HSQUIRRELVM v,const SQChar *s,SQInteger len);\nSQUIRREL_API void sq_pushfloat(HSQUIRRELVM v,SQFloat f);\nSQUIRREL_API void sq_pushinteger(HSQUIRRELVM v,SQInteger n);\nSQUIRREL_API void sq_pushbool(HSQUIRRELVM v,SQBool b);\nSQUIRREL_API void sq_pushuserpointer(HSQUIRRELVM v,SQUserPointer p);\nSQUIRREL_API void sq_pushnull(HSQUIRRELVM v);\nSQUIRREL_API void sq_pushthread(HSQUIRRELVM v, HSQUIRRELVM thread);\nSQUIRREL_API SQObjectType sq_gettype(HSQUIRRELVM v,SQInteger idx);\nSQUIRREL_API SQRESULT sq_typeof(HSQUIRRELVM v,SQInteger idx);\nSQUIRREL_API SQInteger sq_getsize(HSQUIRRELVM v,SQInteger idx);\nSQUIRREL_API SQHash sq_gethash(HSQUIRRELVM v, SQInteger idx);\nSQUIRREL_API SQRESULT sq_getbase(HSQUIRRELVM v,SQInteger idx);\nSQUIRREL_API SQBool sq_instanceof(HSQUIRRELVM v);\nSQUIRREL_API SQRESULT sq_tostring(HSQUIRRELVM v,SQInteger idx);\nSQUIRREL_API void sq_tobool(HSQUIRRELVM v, SQInteger idx, SQBool *b);\nSQUIRREL_API SQRESULT sq_getstringandsize(HSQUIRRELVM v,SQInteger idx,const SQChar **c,SQInteger *size);\nSQUIRREL_API SQRESULT sq_getstring(HSQUIRRELVM v,SQInteger idx,const SQChar **c);\nSQUIRREL_API SQRESULT sq_getinteger(HSQUIRRELVM v,SQInteger idx,SQInteger *i);\nSQUIRREL_API SQRESULT sq_getfloat(HSQUIRRELVM v,SQInteger idx,SQFloat *f);\nSQUIRREL_API SQRESULT sq_getbool(HSQUIRRELVM v,SQInteger idx,SQBool *b);\nSQUIRREL_API SQRESULT sq_getthread(HSQUIRRELVM v,SQInteger idx,HSQUIRRELVM *thread);\nSQUIRREL_API SQRESULT sq_getuserpointer(HSQUIRRELVM v,SQInteger idx,SQUserPointer *p);\nSQUIRREL_API SQRESULT sq_getuserdata(HSQUIRRELVM v,SQInteger idx,SQUserPointer *p,SQUserPointer *typetag);\nSQUIRREL_API SQRESULT sq_settypetag(HSQUIRRELVM v,SQInteger idx,SQUserPointer typetag);\nSQUIRREL_API SQRESULT sq_gettypetag(HSQUIRRELVM v,SQInteger idx,SQUserPointer *typetag);\nSQUIRREL_API void sq_setreleasehook(HSQUIRRELVM v,SQInteger idx,SQRELEASEHOOK hook);\nSQUIRREL_API SQRELEASEHOOK sq_getreleasehook(HSQUIRRELVM v,SQInteger idx);\nSQUIRREL_API SQChar *sq_getscratchpad(HSQUIRRELVM v,SQInteger minsize);\nSQUIRREL_API SQRESULT sq_getfunctioninfo(HSQUIRRELVM v,SQInteger level,SQFunctionInfo *fi);\nSQUIRREL_API SQRESULT sq_getclosureinfo(HSQUIRRELVM v,SQInteger idx,SQInteger *nparams,SQInteger *nfreevars);\nSQUIRREL_API SQRESULT sq_getclosurename(HSQUIRRELVM v,SQInteger idx);\nSQUIRREL_API SQRESULT sq_setnativeclosurename(HSQUIRRELVM v,SQInteger idx,const SQChar *name);\nSQUIRREL_API SQRESULT sq_setinstanceup(HSQUIRRELVM v, SQInteger idx, SQUserPointer p);\nSQUIRREL_API SQRESULT sq_getinstanceup(HSQUIRRELVM v, SQInteger idx, SQUserPointer *p,SQUserPointer typetag);\nSQUIRREL_API SQRESULT sq_setclassudsize(HSQUIRRELVM v, SQInteger idx, SQInteger udsize);\nSQUIRREL_API SQRESULT sq_newclass(HSQUIRRELVM v,SQBool hasbase);\nSQUIRREL_API SQRESULT sq_createinstance(HSQUIRRELVM v,SQInteger idx);\nSQUIRREL_API SQRESULT sq_setattributes(HSQUIRRELVM v,SQInteger idx);\nSQUIRREL_API SQRESULT sq_getattributes(HSQUIRRELVM v,SQInteger idx);\nSQUIRREL_API SQRESULT sq_getclass(HSQUIRRELVM v,SQInteger idx);\nSQUIRREL_API void sq_weakref(HSQUIRRELVM v,SQInteger idx);\nSQUIRREL_API SQRESULT sq_getdefaultdelegate(HSQUIRRELVM v,SQObjectType t);\nSQUIRREL_API SQRESULT sq_getmemberhandle(HSQUIRRELVM v,SQInteger idx,HSQMEMBERHANDLE *handle);\nSQUIRREL_API SQRESULT sq_getbyhandle(HSQUIRRELVM v,SQInteger idx,const HSQMEMBERHANDLE *handle);\nSQUIRREL_API SQRESULT sq_setbyhandle(HSQUIRRELVM v,SQInteger idx,const HSQMEMBERHANDLE *handle);\n\n/*object manipulation*/\nSQUIRREL_API void sq_pushroottable(HSQUIRRELVM v);\nSQUIRREL_API void sq_pushregistrytable(HSQUIRRELVM v);\nSQUIRREL_API void sq_pushconsttable(HSQUIRRELVM v);\nSQUIRREL_API SQRESULT sq_setroottable(HSQUIRRELVM v);\nSQUIRREL_API SQRESULT sq_setconsttable(HSQUIRRELVM v);\nSQUIRREL_API SQRESULT sq_newslot(HSQUIRRELVM v, SQInteger idx, SQBool bstatic);\nSQUIRREL_API SQRESULT sq_deleteslot(HSQUIRRELVM v,SQInteger idx,SQBool pushval);\nSQUIRREL_API SQRESULT sq_set(HSQUIRRELVM v,SQInteger idx);\nSQUIRREL_API SQRESULT sq_get(HSQUIRRELVM v,SQInteger idx);\nSQUIRREL_API SQRESULT sq_rawget(HSQUIRRELVM v,SQInteger idx);\nSQUIRREL_API SQRESULT sq_rawset(HSQUIRRELVM v,SQInteger idx);\nSQUIRREL_API SQRESULT sq_rawdeleteslot(HSQUIRRELVM v,SQInteger idx,SQBool pushval);\nSQUIRREL_API SQRESULT sq_newmember(HSQUIRRELVM v,SQInteger idx,SQBool bstatic);\nSQUIRREL_API SQRESULT sq_rawnewmember(HSQUIRRELVM v,SQInteger idx,SQBool bstatic);\nSQUIRREL_API SQRESULT sq_arrayappend(HSQUIRRELVM v,SQInteger idx);\nSQUIRREL_API SQRESULT sq_arraypop(HSQUIRRELVM v,SQInteger idx,SQBool pushval);\nSQUIRREL_API SQRESULT sq_arrayresize(HSQUIRRELVM v,SQInteger idx,SQInteger newsize);\nSQUIRREL_API SQRESULT sq_arrayreverse(HSQUIRRELVM v,SQInteger idx);\nSQUIRREL_API SQRESULT sq_arrayremove(HSQUIRRELVM v,SQInteger idx,SQInteger itemidx);\nSQUIRREL_API SQRESULT sq_arrayinsert(HSQUIRRELVM v,SQInteger idx,SQInteger destpos);\nSQUIRREL_API SQRESULT sq_setdelegate(HSQUIRRELVM v,SQInteger idx);\nSQUIRREL_API SQRESULT sq_getdelegate(HSQUIRRELVM v,SQInteger idx);\nSQUIRREL_API SQRESULT sq_clone(HSQUIRRELVM v,SQInteger idx);\nSQUIRREL_API SQRESULT sq_setfreevariable(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger nval);\nSQUIRREL_API SQRESULT sq_next(HSQUIRRELVM v,SQInteger idx);\nSQUIRREL_API SQRESULT sq_getweakrefval(HSQUIRRELVM v,SQInteger idx);\nSQUIRREL_API SQRESULT sq_clear(HSQUIRRELVM v,SQInteger idx);\n\n/*calls*/\nSQUIRREL_API SQRESULT sq_call(HSQUIRRELVM v,SQInteger params,SQBool retval,SQBool raiseerror);\nSQUIRREL_API SQRESULT sq_resume(HSQUIRRELVM v,SQBool retval,SQBool raiseerror);\nSQUIRREL_API const SQChar *sq_getlocal(HSQUIRRELVM v,SQUnsignedInteger level,SQUnsignedInteger idx);\nSQUIRREL_API SQRESULT sq_getcallee(HSQUIRRELVM v);\nSQUIRREL_API const SQChar *sq_getfreevariable(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger nval);\nSQUIRREL_API SQRESULT sq_throwerror(HSQUIRRELVM v,const SQChar *err);\nSQUIRREL_API SQRESULT sq_throwobject(HSQUIRRELVM v);\nSQUIRREL_API void sq_reseterror(HSQUIRRELVM v);\nSQUIRREL_API void sq_getlasterror(HSQUIRRELVM v);\nSQUIRREL_API SQRESULT sq_tailcall(HSQUIRRELVM v, SQInteger nparams);\n\n/*raw object handling*/\nSQUIRREL_API SQRESULT sq_getstackobj(HSQUIRRELVM v,SQInteger idx,HSQOBJECT *po);\nSQUIRREL_API void sq_pushobject(HSQUIRRELVM v,HSQOBJECT obj);\nSQUIRREL_API void sq_addref(HSQUIRRELVM v,HSQOBJECT *po);\nSQUIRREL_API SQBool sq_release(HSQUIRRELVM v,HSQOBJECT *po);\nSQUIRREL_API SQUnsignedInteger sq_getrefcount(HSQUIRRELVM v,HSQOBJECT *po);\nSQUIRREL_API void sq_resetobject(HSQOBJECT *po);\nSQUIRREL_API const SQChar *sq_objtostring(const HSQOBJECT *o);\nSQUIRREL_API SQBool sq_objtobool(const HSQOBJECT *o);\nSQUIRREL_API SQInteger sq_objtointeger(const HSQOBJECT *o);\nSQUIRREL_API SQFloat sq_objtofloat(const HSQOBJECT *o);\nSQUIRREL_API SQUserPointer sq_objtouserpointer(const HSQOBJECT *o);\nSQUIRREL_API SQRESULT sq_getobjtypetag(const HSQOBJECT *o,SQUserPointer * typetag);\nSQUIRREL_API SQUnsignedInteger sq_getvmrefcount(HSQUIRRELVM v, const HSQOBJECT *po);\n\n\n/*GC*/\nSQUIRREL_API SQInteger sq_collectgarbage(HSQUIRRELVM v);\nSQUIRREL_API SQRESULT sq_resurrectunreachable(HSQUIRRELVM v);\n\n/*serialization*/\nSQUIRREL_API SQRESULT sq_writeclosure(HSQUIRRELVM vm,SQWRITEFUNC writef,SQUserPointer up);\nSQUIRREL_API SQRESULT sq_readclosure(HSQUIRRELVM vm,SQREADFUNC readf,SQUserPointer up);\n\n/*mem allocation*/\nSQUIRREL_API void *sq_malloc(SQUnsignedInteger size);\nSQUIRREL_API void *sq_realloc(void* p,SQUnsignedInteger oldsize,SQUnsignedInteger newsize);\nSQUIRREL_API void sq_free(void *p,SQUnsignedInteger size);\n\n/*debug*/\nSQUIRREL_API SQRESULT sq_stackinfos(HSQUIRRELVM v,SQInteger level,SQStackInfos *si);\nSQUIRREL_API void sq_setdebughook(HSQUIRRELVM v);\nSQUIRREL_API void sq_setnativedebughook(HSQUIRRELVM v,SQDEBUGHOOK hook);\n\n/*UTILITY MACRO*/\n#define sq_isnumeric(o) ((o)._type&SQOBJECT_NUMERIC)\n#define sq_istable(o) ((o)._type==OT_TABLE)\n#define sq_isarray(o) ((o)._type==OT_ARRAY)\n#define sq_isfunction(o) ((o)._type==OT_FUNCPROTO)\n#define sq_isclosure(o) ((o)._type==OT_CLOSURE)\n#define sq_isgenerator(o) ((o)._type==OT_GENERATOR)\n#define sq_isnativeclosure(o) ((o)._type==OT_NATIVECLOSURE)\n#define sq_isstring(o) ((o)._type==OT_STRING)\n#define sq_isinteger(o) ((o)._type==OT_INTEGER)\n#define sq_isfloat(o) ((o)._type==OT_FLOAT)\n#define sq_isuserpointer(o) ((o)._type==OT_USERPOINTER)\n#define sq_isuserdata(o) ((o)._type==OT_USERDATA)\n#define sq_isthread(o) ((o)._type==OT_THREAD)\n#define sq_isnull(o) ((o)._type==OT_NULL)\n#define sq_isclass(o) ((o)._type==OT_CLASS)\n#define sq_isinstance(o) ((o)._type==OT_INSTANCE)\n#define sq_isbool(o) ((o)._type==OT_BOOL)\n#define sq_isweakref(o) ((o)._type==OT_WEAKREF)\n#define sq_type(o) ((o)._type)\n\n/* deprecated */\n#define sq_createslot(v,n) sq_newslot(v,n,SQFalse)\n\n#define SQ_OK (0)\n#define SQ_ERROR (-1)\n\n#define SQ_FAILED(res) (res<0)\n#define SQ_SUCCEEDED(res) (res>=0)\n\n#ifdef __GNUC__\n# define SQ_UNUSED_ARG(x) x __attribute__((__unused__))\n#else\n# define SQ_UNUSED_ARG(x) x\n#endif\n\n#ifdef __cplusplus\n} /*extern \"C\"*/\n#endif\n\n#endif /*_SQUIRREL_H_*/\n"
  },
  {
    "path": "extlibs/squirrel/samples/ackermann.nut",
    "content": "/*\n*\n* Original Javascript version by David Hedbor(http://www.bagley.org/~doug/shootout/)\n*\n*/\n\nfunction Ack(M, N) {\n    if (M == 0) return( N + 1 );\n    if (N == 0) return( Ack(M - 1, 1) );\n    return( Ack(M - 1, Ack(M, (N - 1))) );\n}\n\nlocal n;\n\nif(vargv.len()!=0) {\n   n = vargv[0].tointeger();\n  if(n < 1) n = 1;\n} else {\n  n = 1;\n}\nprint(\"n=\"+n+\"\\n\");\nprint(\"Ack(3,\"+ n+ \"):\"+ Ack(3, n));\n\n"
  },
  {
    "path": "extlibs/squirrel/samples/array.nut",
    "content": "/*\n*\n* Original Javascript version by David Hedbor(http://www.bagley.org/~doug/shootout/)\n*\n*/\nlocal n, i, k;\n\nif(vargv.len()!=0) {\n   n = vargv[0].tointeger();\n  if(n < 1) n = 1;\n} else {\n  n = 1;\n}\n\nlocal x = []; x.resize(n);\nlocal y = []; y.resize(n);\n\nfor (i = 0; i < n; i+=1) {\n  x[i] = i + 1;\n  y[i] = 0;\n}\n\nfor (k = 0 ; k < n; k+=1) {\n  for (i = n-1; i >= 0; i-=1) {\n    y[i] = y[i]+ x[i];\n  }\n}\nprint(y[0].tostring()+\" \"+y[n-1]);\n\n"
  },
  {
    "path": "extlibs/squirrel/samples/class.nut",
    "content": "//////////////////////////////////////////////////////////////////////////////////\n//////////////////////////////////////////////////////////////////////////////////\nclass BaseVector {\n    constructor(...)\n    {\n        if(vargv.len() >= 3) {\n            x = vargv[0];\n            y = vargv[1];\n            z = vargv[2];\n        }\n    }\n\n\n    x = 0;\n    y = 0;\n    z = 0;\n}\n\nclass Vector3 extends BaseVector {\n    function _add(other)\n    {\n        if(other instanceof this.getclass())\n            return ::Vector3(x+other.x,y+other.y,z+other.z);\n        else\n            throw \"wrong parameter\";\n    }\n    function Print()\n    {\n        ::print(x+\",\"+y+\",\"+z+\"\\n\");\n    }\n}\n\nlocal v0 = Vector3(1,2,3)\nlocal v1 = Vector3(11,12,13)\nlocal v2 = v0 + v1;\nv2.Print();\n\nFakeNamespace <- {\n    Utils = {}\n}\n\nclass FakeNamespace.Utils.SuperClass {\n    constructor()\n    {\n        ::print(\"FakeNamespace.Utils.SuperClass\")\n    }\n}\n\nlocal testy = FakeNamespace.Utils.SuperClass();\n"
  },
  {
    "path": "extlibs/squirrel/samples/classattributes.nut",
    "content": "class Foo {\n    //constructor\n    constructor(a)\n    {\n        testy = [\"stuff\",1,2,3];\n    }\n    //attributes of PrintTesty\n    </ test = \"freakin attribute\"/>\n    function PrintTesty()\n    {\n        foreach(i,val in testy)\n        {\n            ::print(\"idx = \"+i+\" = \"+val+\" \\n\");\n        }\n    }\n    //attributes of testy\n    </ flippy = 10 , second = [1,2,3] />\n    testy = null;\n\n}\n\nforeach(member,val in Foo)\n{\n    ::print(member+\"\\n\");\n    local attr;\n    if((attr = Foo.getattributes(member)) != null) {\n        foreach(i,v in attr)\n        {\n            ::print(\"\\t\"+i+\" = \"+(typeof v)+\"\\n\");\n        }\n    }\n    else {\n        ::print(\"\\t<no attributes>\\n\")\n    }\n}\n"
  },
  {
    "path": "extlibs/squirrel/samples/coroutines.nut",
    "content": "function coroutine_test(a,b)\n{\n    ::print(a+\" \"+b+\"\\n\");\n    local ret = ::suspend(\"suspend 1\");\n    ::print(\"the coroutine says \"+ret+\"\\n\");\n    ret = ::suspend(\"suspend 2\");\n    ::print(\"the coroutine says \"+ret+\"\\n\");\n    ret = ::suspend(\"suspend 3\");\n    ::print(\"the coroutine says \"+ret+\"\\n\");\n    return \"I'm done\"\n}\n\nlocal coro = ::newthread(coroutine_test);\n\nlocal susparam = coro.call(\"test\",\"coroutine\"); //starts the coroutine\n\nlocal i = 1;\ndo\n{\n    ::print(\"suspend passed [\"+susparam+\"]\\n\")\n    susparam = coro.wakeup(\"ciao \"+i);\n    ++i;\n}while(coro.getstatus()==\"suspended\")\n\n::print(\"return passed [\"+susparam+\"]\\n\")\n"
  },
  {
    "path": "extlibs/squirrel/samples/delegation.nut",
    "content": "\nPEntity <- {\n    name=\"noname\"\n    pos={x=0,y=0,z=0}\n    type=\"entity\"\n    //methamethod\n    _typeof=function()\n    {\n        return type;\n    }\n}\n\nfunction PEntity::PrintPos()\n{\n    ::print(\"x=\"+pos.x+\" y=\"+pos.y+\" z=\"+pos.z+\"\\n\");\n}\n\nfunction PEntity::new(name,pos)\n{\n    local newentity=clone ::PEntity;\n    if(name)\n        newentity.name=name;\n    if(pos)\n        newentity.pos=pos;\n    return newentity;\n}\n\nPPlayer <- {\n    model=\"warrior.mdl\"\n    weapon=\"fist\"\n    health=100\n    armor=0\n    //overrides the parent type\n    type=\"player\"\n}\n\nfunction PPlayer::new(name,pos)\n{\n    local p = clone ::PPlayer;\n    local newplayer = ::PEntity.new(name,pos);\n    newplayer.setdelegate(p);\n    return newplayer;\n}\n\nlocal player=PPlayer.new(\"godzilla\",{x=10,y=20,z=30});\n\n::print(\"PLAYER NAME\"+player.name+\"\\n\");\n::print(\"ENTITY TYPE\"+typeof player+\"\\n\");\n\nplayer.PrintPos();\n\nplayer.pos.x=123;\n\nplayer.PrintPos();\n"
  },
  {
    "path": "extlibs/squirrel/samples/fibonacci.nut",
    "content": "/*\n*\n* Original Javascript version by David Hedbor(http://www.bagley.org/~doug/shootout/)\n*\n*/\n\nfunction fib(n)\n{\n    if (n < 2) return 1\n    return fib(n-2) + fib(n-1)\n}\n\nlocal n = vargv.len()!=0?vargv[0].tointeger():1\n\nprint(fib(n)+\"\\n\")\n"
  },
  {
    "path": "extlibs/squirrel/samples/flow.nut",
    "content": "function min(x,y)\n    return x<y?x:y;\n\nfunction max(x,y)\n    return x>y?x:y;\n\nif(min(100,200)>max(50,20))\n    print(\"I'm useless statement just to show up the if/else\\n\");\nelse\n    print(\"squirrel!!\\n\");\n\nprint(\"\\n\")\n\nfunction typy(obj)\n{\n    switch(typeof obj)\n    {\n        case \"integer\":\n        case \"float\":\n            return \"is a number\";\n        case \"table\":\n        case \"array\":\n            return \"is a container\";\n        default:\n            return \"is other stuff\"\n    }\n}\n\nlocal a=1,b={},c=function(a,b){return a+b;}\n\nprint(\"a \"+typy(a)+\"\\n\");\nprint(\"b \"+typy(b)+\"\\n\");\nprint(\"c \"+typy(c)+\"\\n\");\n"
  },
  {
    "path": "extlibs/squirrel/samples/generators.nut",
    "content": "/*\n*Random number function from The Great Computer Language shootout\n*converted to a generator func\n*/\n\nfunction gen_random(max) {\n    local last=42\n    local IM = 139968;\n    local IA = 3877;\n    local IC = 29573;\n    for(;;){  //loops forever\n        yield (max * (last = (last * IA + IC) % IM) / IM);\n    }\n}\n\nlocal randtor=gen_random(100);\n\nprint(\"RAND NUMBERS \\n\")\n\nfor(local i=0;i<10;i+=1)\n    print(\">\"+resume randtor+\"\\n\");\n\nprint(\"FIBONACCI \\n\")\nfunction fiboz(n)\n{\n    local prev=0;\n    local curr=1;\n    yield 1;\n\n    for(local i=0;i<n-1;i+=1)\n    {\n        local res=prev+curr;\n        prev=curr;\n        yield curr=res;\n    }\n    return prev+curr;\n}\n\nforeach(val in fiboz(10))\n{\n    ::print(\">\"+val+\"\\n\");\n}\n"
  },
  {
    "path": "extlibs/squirrel/samples/hello.nut",
    "content": "print(\"Hello World!\")\n"
  },
  {
    "path": "extlibs/squirrel/samples/list.nut",
    "content": "/*translation of the list test from The Great Computer Language Shootout\n*/\n\nfunction compare_arr(a1,a2)\n{\n    foreach(i,val in a1)\n        if(val!=a2[i])return null;\n    return 1;\n}\n\nfunction test()\n{\n    local size=10000\n    local l1=[]; l1.resize(size);\n    for(local i=0;i<size;i+=1) l1[i]=i;\n    local l2=clone l1;\n    local l3=[]\n\n    l2.reverse();\n    while(l2.len()>0)\n        l3.append(l2.pop());\n    while(l3.len()>0)\n        l2.append(l3.pop());\n    l1.reverse();\n\n    if(compare_arr(l1,l2))\n        return l1.len();\n    return null;\n}\n\nlocal n = vargv.len()!=0?vargv[0].tointeger():1\nfor(local i=0;i<n;i+=1)\n    if(!test())\n    {\n        print(\"failed\");\n        return;\n    }\n\nprint(\"oki doki\");\n\n"
  },
  {
    "path": "extlibs/squirrel/samples/loops.nut",
    "content": "local arr=[\"one\",\"two\",\"three\"]\n\n::print(\"FOREACH\\n\");\n\nforeach(i,val in arr)\n{\n    ::print(\"index [\"+i+\"]=\"+val+\"\\n\");\n}\n\n::print(\"FOR\\n\");\n\nfor(local i=0;i<arr.len();i+=1)\n{\n    ::print(\"index [\"+i+\"]=\"+arr[i]+\"\\n\");\n}\n\n::print(\"WHILE\\n\");\n\nlocal i=0;\nwhile(i<arr.len())\n{\n    ::print(\"index [\"+i+\"]=\"+arr[i]+\"\\n\");\n    i+=1;\n}\n::print(\"DO WHILE\\n\");\n\nlocal i=0;\ndo\n{\n    ::print(\"index [\"+i+\"]=\"+arr[i]+\"\\n\");\n    i+=1;\n}while(i<arr.len());\n"
  },
  {
    "path": "extlibs/squirrel/samples/matrix.nut",
    "content": "/*\n*\n* Original Javascript version by David Hedbor(http://www.bagley.org/~doug/shootout/)\n*\n*/\nlocal SIZE=30;\n\nfunction mkmatrix(rows, cols) {\n  local i, j, count = 1;\n  local m = []; m.resize(rows);\n  for (i = 0; i < rows; i+=1) {\n    m[i] = [];m[i].resize(cols)\n    for (j = 0; j < cols; j+=1) {\n      m[i][j] = count+=1;\n    }\n  }\n  return m;\n}\n\nfunction mmult(rows, cols,  m1, m2, m3) {\n  local i, j, k, val;\n  for (i = 0; i < rows; i+=1) {\n    for (j = 0; j < cols; j+=1) {\n      val = 0;\n      for (k = 0; k < cols; k+=1) {\n    val += m1[i][k] * m2[k][j];\n      }\n      m3[i][j] = val;\n    }\n  }\n  return m3;\n}\n\nlocal n = vargv.len()!=0?vargv[0].tointeger():1\n\nlocal m1 = mkmatrix(SIZE, SIZE);\nlocal m2 = mkmatrix(SIZE, SIZE);\nlocal mm = mkmatrix(SIZE, SIZE);\n\nfor (local i = 0; i < n; i+=1) {\n  mmult(SIZE, SIZE, m1, m2, mm);\n}\n\nprint(mm[0][0]+\" \"+mm[2][3]+\" \"+mm[3][2]+\" \"+mm[4][4]);\n"
  },
  {
    "path": "extlibs/squirrel/samples/metamethods.nut",
    "content": "\nlocal base_vec={\n    function _add(n)\n    {\n        return {\n            x=x+n.x,\n            y=y+n.y,\n            z=z+n.z,\n        }\n    }\n    function _sub(n)\n    {\n        return {\n            x=x-n.x,\n            y=y-n.y,\n            z=z-n.z,\n        }\n    }\n    function _div(n)\n    {\n        return {\n            x=x/n.x,\n            y=y/n.y,\n            z=z/n.z,\n        }\n    }\n    function _mul(n)\n    {\n        return {\n            x=x*n.x,\n            y=y*n.y,\n            z=z*n.z,\n        }\n    }\n    function _modulo(n)\n    {\n        return {\n            x=x%n,\n            y=y%n,\n            z=z%n,\n        }\n    }\n    function _typeof() {return \"vector\";}\n    function _get(key)\n    {\n        if(key==100)\n        {\n            return test_field;\n        }\n    },\n    function _set(key,val)\n    {\n        ::print(\"key = \"+key+\"\\n\");\n        ::print(\"val = \"+val+\"\\n\")\n        if(key==100)\n        {\n            return test_field=val;\n        }\n    }\n    test_field=\"nothing\"\n}\n\nfunction vector(_x,_y,_z)\n{\n    return {x=_x,y=_y,z=_z }.setdelegate(base_vec);\n}\n////////////////////////////////////////////////////////////\n\nlocal v1=vector(1.5,2.5,3.5);\nlocal v2=vector(1.5,2.5,3.5);\n\nlocal r=v1+v2;\n\n\nforeach(i,val in r)\n{\n    print(i+\" = \"+val+\"\\n\");\n}\n\nr=v1*v2;\n\nforeach(i,val in r)\n{\n    print(i+\" = \"+val+\"\\n\");\n}\n\nr=v1/v2;\n\nforeach(i,val in r)\n{\n    print(i+\" = \"+val+\"\\n\");\n}\n\nr=v1-v2;\n\nforeach(i,val in r)\n{\n    print(i+\" = \"+val+\"\\n\");\n}\n\nr=v1%2;\n\nforeach(i,val in r)\n{\n    print(i+\" = \"+val+\"\\n\");\n}\n\nprint(v1[100]+\"\\n\");\nv1[100]=\"set SUCCEEDED\";\nprint(v1[100]+\"\\n\");\n\nif(typeof v1==\"vector\")\n    print(\"<SUCCEEDED>\\n\");\nelse\n    print(\"<FAILED>\\n\");\n"
  },
  {
    "path": "extlibs/squirrel/samples/methcall.nut",
    "content": "/*translation of the methcall test from The Great Computer Language Shootout\n*/\n\nclass Toggle {\n    bool=null\n}\n\nfunction Toggle::constructor(startstate) {\n    bool = startstate\n}\n\nfunction Toggle::value() {\n    return bool;\n}\n\nfunction Toggle::activate() {\n    bool = !bool;\n    return this;\n}\n\nclass NthToggle extends Toggle {\n    count_max=null\n    count=0\n}\n\nfunction NthToggle::constructor(start_state,max_counter)\n{\n    base.constructor(start_state);\n    count_max = max_counter\n}\n\nfunction NthToggle::activate ()\n{\n    ++count;\n    if (count >= count_max ) {\n      base.activate();\n      count = 0;\n    }\n    return this;\n}\n\n\nfunction main() {\n    local n = vargv.len()!=0?vargv[0].tointeger():1\n\n\n\n    local val = 1;\n    local toggle = Toggle(val);\n    local i = n;\n    while(i--) {\n      val = toggle.activate().value();\n\n    }\n    print(toggle.value() ? \"true\\n\" : \"false\\n\");\n\n    val = 1;\n    local ntoggle = NthToggle(val, 3);\n    i = n;\n    while(i--) {\n      val = ntoggle.activate().value();\n    }\n    print(ntoggle.value() ? \"true\\n\" : \"false\\n\");\n\n}\nlocal start=clock();\nmain();\nprint(\"TIME=\"+(clock()-start)+\"\\n\");\n"
  },
  {
    "path": "extlibs/squirrel/samples/regex.nut",
    "content": "local ex = regexp(\"[a-zA-Z]+\");\nlocal string = \"123 Test; strlen(str);\";\nlocal res = ex.search(string);\nprint(string.slice(res.begin,res.end)); //prints \"Test\"\nprint(\"\\n\");\nex = regexp(@\"\\m()\");\nstring = \"123 Test; doSomething(str, getTemp(), (a+(b/c)));\";\nres = ex.search(string);\nprint(string.slice(res.begin,res.end)); //prints \"(...)\"\nprint(\"\\n\");\n"
  },
  {
    "path": "extlibs/squirrel/samples/tailstate.nut",
    "content": "function state1()\n{\n    ::suspend(\"state1\");\n    return state2();\n}\n\nfunction state2()\n{\n    ::suspend(\"state2\");\n    return state3();\n}\n\nfunction state3()\n{\n    ::suspend(\"state3\");\n    return state1();\n}\n\nlocal statethread = ::newthread(state1)\n\n::print(statethread.call()+\"\\n\");\n\nfor(local i = 0; i < 10000; i++)\n    ::print(statethread.wakeup()+\"\\n\");\n"
  },
  {
    "path": "extlibs/squirrel/sq/CMakeLists.txt",
    "content": "if(NOT DISABLE_DYNAMIC)\n  if(CMAKE_COMPILER_IS_GNUCXX)\n    set_source_files_properties(sq.c PROPERTIES COMPILE_FLAGS -std=c99)\n  endif()\n  add_executable(sq sq.c)\n  set_target_properties(sq PROPERTIES LINKER_LANGUAGE C)\n  target_link_libraries(sq squirrel sqstdlib)\n  if(NOT SQ_DISABLE_INSTALLER)\n    install(TARGETS sq RUNTIME DESTINATION ${INSTALL_BIN_DIR})\n  endif()\nendif()\n\nif(NOT DISABLE_STATIC)\n  add_executable(sq_static sq.c)\n  set_target_properties(sq_static PROPERTIES LINKER_LANGUAGE C)\n  target_link_libraries(sq_static squirrel_static sqstdlib_static)\n  if(NOT SQ_DISABLE_INSTALLER)\n    install(TARGETS sq_static RUNTIME DESTINATION ${INSTALL_BIN_DIR})\n  endif()\nendif()\n\nif(LONG_OUTPUT_NAMES)\n  if(NOT DISABLE_DYNAMIC)\n    set_target_properties(sq PROPERTIES OUTPUT_NAME squirrel3)\n  endif()\n\n  if(NOT DISABLE_STATIC)\n    set_target_properties(sq_static PROPERTIES OUTPUT_NAME squirrel3_static)\n  endif()\nendif()\n\nif(CMAKE_COMPILER_IS_GNUCXX AND NOT DISABLE_STATIC)\n  set_target_properties(sq_static PROPERTIES COMPILE_FLAGS \"-static -Wl,-static\")\nendif()\n"
  },
  {
    "path": "extlibs/squirrel/sq/Makefile",
    "content": "SQUIRREL= ..\n\n\nOUT= $(SQUIRREL)/bin/sq\nINCZ= -I$(SQUIRREL)/include -I. -I$(SQUIRREL)/sqlibs\nLIBZ= -L$(SQUIRREL)/lib\nLIB= -lsquirrel -lsqstdlib\n\nOBJS= sq.o\n\nSRCS= sq.c\n\n\nsq32:\n\tg++ -O2 -fno-exceptions -fno-rtti -o $(OUT) $(SRCS) $(INCZ) $(LIBZ) $(LIB)\n\nsqprof:\n\tg++ -O2 -pg -fno-exceptions -fno-rtti -pie -gstabs -g3 -o $(OUT) $(SRCS) $(INCZ) $(LIBZ) $(LIB)\n\nsq64:\n\tg++ -O2 -m64 -fno-exceptions -fno-rtti -D_SQ64 -o $(OUT) $(SRCS) $(INCZ) $(LIBZ) $(LIB)\n"
  },
  {
    "path": "extlibs/squirrel/sq/sq.c",
    "content": "/*  see copyright notice in squirrel.h */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <stdarg.h>\n\n#if defined(_MSC_VER) && defined(_DEBUG)\n#include <crtdbg.h>\n#include <conio.h>\n#endif\n#include <squirrel.h>\n#include <sqstdblob.h>\n#include <sqstdsystem.h>\n#include <sqstdio.h>\n#include <sqstdmath.h>\n#include <sqstdstring.h>\n#include <sqstdaux.h>\n\n#ifdef SQUNICODE\n#define scfprintf fwprintf\n#define scvprintf vfwprintf\n#else\n#define scfprintf fprintf\n#define scvprintf vfprintf\n#endif\n\n\nvoid PrintVersionInfos();\n\n#if defined(_MSC_VER) && defined(_DEBUG)\nint MemAllocHook( int allocType, void *userData, size_t size, int blockType,\n   long requestNumber, const unsigned char *filename, int lineNumber)\n{\n    //if(requestNumber==769)_asm int 3;\n    return 1;\n}\n#endif\n\n\nSQInteger quit(HSQUIRRELVM v)\n{\n    int *done;\n    sq_getuserpointer(v,-1,(SQUserPointer*)&done);\n    *done=1;\n    return 0;\n}\n\nvoid printfunc(HSQUIRRELVM SQ_UNUSED_ARG(v),const SQChar *s,...)\n{\n    va_list vl;\n    va_start(vl, s);\n    scvprintf(stdout, s, vl);\n    va_end(vl);\n}\n\nvoid errorfunc(HSQUIRRELVM SQ_UNUSED_ARG(v),const SQChar *s,...)\n{\n    va_list vl;\n    va_start(vl, s);\n    scvprintf(stderr, s, vl);\n    va_end(vl);\n}\n\nvoid PrintVersionInfos()\n{\n    scfprintf(stdout,_SC(\"%s %s (%d bits)\\n\"),SQUIRREL_VERSION,SQUIRREL_COPYRIGHT,((int)(sizeof(SQInteger)*8)));\n}\n\nvoid PrintUsage()\n{\n    scfprintf(stderr,_SC(\"usage: sq <options> <scriptpath [args]>.\\n\")\n        _SC(\"Available options are:\\n\")\n        _SC(\"   -c              compiles the file to bytecode(default output 'out.cnut')\\n\")\n        _SC(\"   -o              specifies output file for the -c option\\n\")\n        _SC(\"   -c              compiles only\\n\")\n        _SC(\"   -d              generates debug infos\\n\")\n        _SC(\"   -v              displays version infos\\n\")\n        _SC(\"   -h              prints help\\n\"));\n}\n\n#define _INTERACTIVE 0\n#define _DONE 2\n#define _ERROR 3\n//<<FIXME>> this func is a mess\nint getargs(HSQUIRRELVM v,int argc, char* argv[],SQInteger *retval)\n{\n    int i;\n    int compiles_only = 0;\n#ifdef SQUNICODE\n    static SQChar temp[500];\n#endif\n    char * output = NULL;\n    *retval = 0;\n    if(argc>1)\n    {\n        int arg=1,exitloop=0;\n\n        while(arg < argc && !exitloop)\n        {\n\n            if(argv[arg][0]=='-')\n            {\n                switch(argv[arg][1])\n                {\n                case 'd': //DEBUG(debug infos)\n                    sq_enabledebuginfo(v,1);\n                    break;\n                case 'c':\n                    compiles_only = 1;\n                    break;\n                case 'o':\n                    if(arg < argc) {\n                        arg++;\n                        output = argv[arg];\n                    }\n                    break;\n                case 'v':\n                    PrintVersionInfos();\n                    return _DONE;\n\n                case 'h':\n                    PrintVersionInfos();\n                    PrintUsage();\n                    return _DONE;\n                default:\n                    PrintVersionInfos();\n                    scprintf(_SC(\"unknown prameter '-%c'\\n\"),argv[arg][1]);\n                    PrintUsage();\n                    *retval = -1;\n                    return _ERROR;\n                }\n            }else break;\n            arg++;\n        }\n\n        // src file\n\n        if(arg<argc) {\n            const SQChar *filename=NULL;\n#ifdef SQUNICODE\n            mbstowcs(temp,argv[arg],strlen(argv[arg]));\n            filename=temp;\n#else\n            filename=argv[arg];\n#endif\n\n            arg++;\n\n            //sq_pushstring(v,_SC(\"ARGS\"),-1);\n            //sq_newarray(v,0);\n\n            //sq_createslot(v,-3);\n            //sq_pop(v,1);\n            if(compiles_only) {\n                if(SQ_SUCCEEDED(sqstd_loadfile(v,filename,SQTrue))){\n                    const SQChar *outfile = _SC(\"out.cnut\");\n                    if(output) {\n#ifdef SQUNICODE\n                        int len = (int)(strlen(output)+1);\n                        mbstowcs(sq_getscratchpad(v,len*sizeof(SQChar)),output,len);\n                        outfile = sq_getscratchpad(v,-1);\n#else\n                        outfile = output;\n#endif\n                    }\n                    if(SQ_SUCCEEDED(sqstd_writeclosuretofile(v,outfile)))\n                        return _DONE;\n                }\n            }\n            else {\n                //if(SQ_SUCCEEDED(sqstd_dofile(v,filename,SQFalse,SQTrue))) {\n                    //return _DONE;\n                //}\n                if(SQ_SUCCEEDED(sqstd_loadfile(v,filename,SQTrue))) {\n                    int callargs = 1;\n                    sq_pushroottable(v);\n                    for(i=arg;i<argc;i++)\n                    {\n                        const SQChar *a;\n#ifdef SQUNICODE\n                        int alen=(int)strlen(argv[i]);\n                        a=sq_getscratchpad(v,(int)(alen*sizeof(SQChar)));\n                        mbstowcs(sq_getscratchpad(v,-1),argv[i],alen);\n                        sq_getscratchpad(v,-1)[alen] = _SC('\\0');\n#else\n                        a=argv[i];\n#endif\n                        sq_pushstring(v,a,-1);\n                        callargs++;\n                        //sq_arrayappend(v,-2);\n                    }\n                    if(SQ_SUCCEEDED(sq_call(v,callargs,SQTrue,SQTrue))) {\n                        SQObjectType type = sq_gettype(v,-1);\n                        if(type == OT_INTEGER) {\n                            *retval = type;\n                            sq_getinteger(v,-1,retval);\n                        }\n                        return _DONE;\n                    }\n                    else{\n                        return _ERROR;\n                    }\n\n                }\n            }\n            //if this point is reached an error occurred\n            {\n                const SQChar *err;\n                sq_getlasterror(v);\n                if(SQ_SUCCEEDED(sq_getstring(v,-1,&err))) {\n                    scprintf(_SC(\"Error [%s]\\n\"),err);\n                    *retval = -2;\n                    return _ERROR;\n                }\n            }\n\n        }\n    }\n\n    return _INTERACTIVE;\n}\n\nvoid Interactive(HSQUIRRELVM v)\n{\n\n#define MAXINPUT 1024\n    SQChar buffer[MAXINPUT];\n    SQInteger blocks =0;\n    SQInteger string=0;\n    SQInteger retval=0;\n    SQInteger done=0;\n    PrintVersionInfos();\n\n    sq_pushroottable(v);\n    sq_pushstring(v,_SC(\"quit\"),-1);\n    sq_pushuserpointer(v,&done);\n    sq_newclosure(v,quit,1);\n    sq_setparamscheck(v,1,NULL);\n    sq_newslot(v,-3,SQFalse);\n    sq_pop(v,1);\n\n    while (!done)\n    {\n        SQInteger i = 0;\n        scprintf(_SC(\"\\nsq>\"));\n        for(;;) {\n            int c;\n            if(done)return;\n            c = getchar();\n            if (c == _SC('\\n')) {\n                if (i>0 && buffer[i-1] == _SC('\\\\'))\n                {\n                    buffer[i-1] = _SC('\\n');\n                }\n                else if(blocks==0)break;\n                buffer[i++] = _SC('\\n');\n            }\n            else if (c==_SC('}')) {blocks--; buffer[i++] = (SQChar)c;}\n            else if(c==_SC('{') && !string){\n                    blocks++;\n                    buffer[i++] = (SQChar)c;\n            }\n            else if(c==_SC('\"') || c==_SC('\\'')){\n                    string=!string;\n                    buffer[i++] = (SQChar)c;\n            }\n            else if (i >= MAXINPUT-1) {\n                scfprintf(stderr, _SC(\"sq : input line too long\\n\"));\n                break;\n            }\n            else{\n                buffer[i++] = (SQChar)c;\n            }\n        }\n        buffer[i] = _SC('\\0');\n\n        if(buffer[0]==_SC('=')){\n            scsprintf(sq_getscratchpad(v,MAXINPUT),(size_t)MAXINPUT,_SC(\"return (%s)\"),&buffer[1]);\n            memcpy(buffer,sq_getscratchpad(v,-1),(scstrlen(sq_getscratchpad(v,-1))+1)*sizeof(SQChar));\n            retval=1;\n        }\n        i=scstrlen(buffer);\n        if(i>0){\n            SQInteger oldtop=sq_gettop(v);\n            if(SQ_SUCCEEDED(sq_compilebuffer(v,buffer,i,_SC(\"interactive console\"),SQTrue))){\n                sq_pushroottable(v);\n                if(SQ_SUCCEEDED(sq_call(v,1,retval,SQTrue)) &&  retval){\n                    scprintf(_SC(\"\\n\"));\n                    sq_pushroottable(v);\n                    sq_pushstring(v,_SC(\"print\"),-1);\n                    sq_get(v,-2);\n                    sq_pushroottable(v);\n                    sq_push(v,-4);\n                    sq_call(v,2,SQFalse,SQTrue);\n                    retval=0;\n                    scprintf(_SC(\"\\n\"));\n                }\n            }\n\n            sq_settop(v,oldtop);\n        }\n    }\n}\n\nint main(int argc, char* argv[])\n{\n    HSQUIRRELVM v;\n    SQInteger retval = 0;\n#if defined(_MSC_VER) && defined(_DEBUG)\n    _CrtSetAllocHook(MemAllocHook);\n#endif\n\n    v=sq_open(1024);\n    sq_setprintfunc(v,printfunc,errorfunc);\n\n    sq_pushroottable(v);\n\n    sqstd_register_bloblib(v);\n    sqstd_register_iolib(v);\n    sqstd_register_systemlib(v);\n    sqstd_register_mathlib(v);\n    sqstd_register_stringlib(v);\n\n    //aux library\n    //sets error handlers\n    sqstd_seterrorhandlers(v);\n\n    //gets arguments\n    switch(getargs(v,argc,argv,&retval))\n    {\n    case _INTERACTIVE:\n        Interactive(v);\n        break;\n    case _DONE:\n    case _ERROR:\n    default:\n        break;\n    }\n\n    sq_close(v);\n\n#if defined(_MSC_VER) && defined(_DEBUG)\n    _getch();\n    _CrtMemDumpAllObjectsSince( NULL );\n#endif\n    return retval;\n}\n\n"
  },
  {
    "path": "extlibs/squirrel/sq/sq.dsp",
    "content": "# Microsoft Developer Studio Project File - Name=\"sq\" - Package Owner=<4>\n# Microsoft Developer Studio Generated Build File, Format Version 6.00\n# ** DO NOT EDIT **\n\n# TARGTYPE \"Win32 (x86) Console Application\" 0x0103\n\nCFG=sq - Win32 Debug\n!MESSAGE This is not a valid makefile. To build this project using NMAKE,\n!MESSAGE use the Export Makefile command and run\n!MESSAGE \n!MESSAGE NMAKE /f \"sq.mak\".\n!MESSAGE \n!MESSAGE You can specify a configuration when running NMAKE\n!MESSAGE by defining the macro CFG on the command line. For example:\n!MESSAGE \n!MESSAGE NMAKE /f \"sq.mak\" CFG=\"sq - Win32 Debug\"\n!MESSAGE \n!MESSAGE Possible choices for configuration are:\n!MESSAGE \n!MESSAGE \"sq - Win32 Release\" (based on \"Win32 (x86) Console Application\")\n!MESSAGE \"sq - Win32 Debug\" (based on \"Win32 (x86) Console Application\")\n!MESSAGE \n\n# Begin Project\n# PROP AllowPerConfigDependencies 0\n# PROP Scc_LocalPath \"..\"\nCPP=cl.exe\nRSC=rc.exe\n\n!IF  \"$(CFG)\" == \"sq - Win32 Release\"\n\n# PROP BASE Use_MFC 0\n# PROP BASE Use_Debug_Libraries 0\n# PROP BASE Output_Dir \"Release\"\n# PROP BASE Intermediate_Dir \"Release\"\n# PROP BASE Target_Dir \"\"\n# PROP Use_MFC 0\n# PROP Use_Debug_Libraries 0\n# PROP Output_Dir \"Release\"\n# PROP Intermediate_Dir \"Release\"\n# PROP Ignore_Export_Lib 0\n# PROP Target_Dir \"\"\n# ADD BASE CPP /nologo /W3 /GX /O2 /D \"WIN32\" /D \"NDEBUG\" /D \"_CONSOLE\" /D \"_MBCS\" /YX /FD /c\n# ADD CPP /nologo /W3 /GX /O2 /I \"..\\include\" /I \"..\\sqstdlib\" /D \"WIN32\" /D \"NDEBUG\" /D \"_CONSOLE\" /D \"_MBCS\" /YX /FD /c\n# ADD BASE RSC /l 0x410 /d \"NDEBUG\"\n# ADD RSC /l 0x410 /d \"NDEBUG\"\nBSC32=bscmake.exe\n# ADD BASE BSC32 /nologo\n# ADD BSC32 /nologo\nLINK32=link.exe\n# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\n# ADD LINK32 squirrel.lib sqstdlib.lib /nologo /subsystem:console /machine:I386 /out:\"../bin/sq.exe\" /libpath:\"../lib\"\n\n!ELSEIF  \"$(CFG)\" == \"sq - Win32 Debug\"\n\n# PROP BASE Use_MFC 0\n# PROP BASE Use_Debug_Libraries 1\n# PROP BASE Output_Dir \"Debug\"\n# PROP BASE Intermediate_Dir \"Debug\"\n# PROP BASE Target_Dir \"\"\n# PROP Use_MFC 0\n# PROP Use_Debug_Libraries 1\n# PROP Output_Dir \"Debug\"\n# PROP Intermediate_Dir \"Debug\"\n# PROP Ignore_Export_Lib 0\n# PROP Target_Dir \"\"\n# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D \"WIN32\" /D \"_DEBUG\" /D \"_CONSOLE\" /D \"_MBCS\" /YX /FD /GZ /c\n# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I \"..\\include\" /I \"..\\sqstdlib\" /D \"WIN32\" /D \"_DEBUG\" /D \"_CONSOLE\" /D \"_MBCS\" /YX /FD /GZ /c\n# ADD BASE RSC /l 0x410 /d \"_DEBUG\"\n# ADD RSC /l 0x410 /d \"_DEBUG\"\nBSC32=bscmake.exe\n# ADD BASE BSC32 /nologo\n# ADD BSC32 /nologo\nLINK32=link.exe\n# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\n# ADD LINK32 squirrel.lib sqstdlib.lib /nologo /subsystem:console /debug /machine:I386 /out:\"../bin/sq.exe\" /pdbtype:sept /libpath:\"../lib\"\n\n!ENDIF \n\n# Begin Target\n\n# Name \"sq - Win32 Release\"\n# Name \"sq - Win32 Debug\"\n# Begin Group \"Source Files\"\n\n# PROP Default_Filter \"cpp;c;cxx;rc;def;r;odl;idl;hpj;bat\"\n# Begin Source File\n\nSOURCE=.\\sq.c\n# End Source File\n# End Group\n# Begin Group \"Header Files\"\n\n# PROP Default_Filter \"h;hpp;hxx;hm;inl\"\n# End Group\n# Begin Group \"Resource Files\"\n\n# PROP Default_Filter \"ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe\"\n# End Group\n# End Target\n# End Project\n"
  },
  {
    "path": "extlibs/squirrel/sqstdlib/CMakeLists.txt",
    "content": "set(SQSTDLIB_SRC sqstdaux.cpp\n                 sqstdblob.cpp\n                 sqstdio.cpp\n                 sqstdmath.cpp\n                 sqstdrex.cpp\n                 sqstdstream.cpp\n                 sqstdstring.cpp\n                 sqstdsystem.cpp)\n\nif(NOT DISABLE_DYNAMIC)\n  add_library(sqstdlib SHARED ${SQSTDLIB_SRC})\n  target_link_libraries(sqstdlib squirrel)\n  if(NOT SQ_DISABLE_INSTALLER)\n    install(TARGETS sqstdlib RUNTIME DESTINATION ${INSTALL_BIN_DIR}\n                             LIBRARY DESTINATION ${INSTALL_LIB_DIR}\n                             ARCHIVE DESTINATION ${INSTALL_LIB_DIR})\n  endif()\nendif()\n\nif(NOT DISABLE_STATIC)\n  add_library(sqstdlib_static STATIC ${SQSTDLIB_SRC})\n  if(NOT SQ_DISABLE_INSTALLER)\n    install(TARGETS sqstdlib_static ARCHIVE DESTINATION ${INSTALL_LIB_DIR})\n  endif()\nendif()\n\nif(LONG_OUTPUT_NAMES)\n  if(NOT DISABLE_DYNAMIC)\n    set_target_properties(sqstdlib PROPERTIES OUTPUT_NAME sqstdlib3)\n  endif()\n\n  if(NOT DISABLE_STATIC)\n    set_target_properties(sqstdlib_static PROPERTIES OUTPUT_NAME sqstdlib3_static)\n  endif()\nendif()\n"
  },
  {
    "path": "extlibs/squirrel/sqstdlib/Makefile",
    "content": "SQUIRREL= ..\n\n\nCC?= gcc\nOUT?= $(SQUIRREL)/lib/libsqstdlib.a\nINCZ?= -I$(SQUIRREL)/include -I. -Iinclude\nDEFS= $(CC_EXTRA_FLAGS)\nLIB=\n\nOBJS= \\\n\tsqstdblob.o \\\n\tsqstdio.o \\\n\tsqstdstream.o \\\n\tsqstdmath.o \\\n\tsqstdsystem.o \\\n\tsqstdstring.o \\\n\tsqstdaux.o \\\n\tsqstdrex.o\n\nSRCS= \\\n\tsqstdblob.cpp \\\n\tsqstdio.cpp \\\n\tsqstdstream.cpp \\\n\tsqstdmath.cpp \\\n\tsqstdsystem.cpp \\\n\tsqstdstring.cpp \\\n\tsqstdaux.cpp \\\n\tsqstdrex.cpp\n\n\nsq32:\n\t$(CC) -O2 -fno-exceptions -fno-rtti -Wall -fno-strict-aliasing -c $(SRCS) $(INCZ) $(DEFS)\n\tar rc $(OUT) *.o\n\trm *.o\n\nsqprof:\n\t$(CC) -O2 -pg -fno-exceptions -fno-rtti -pie -gstabs -g3 -Wall -fno-strict-aliasing -c $(SRCS) $(INCZ) $(DEFS)\n\tar rc $(OUT) *.o\n\trm *.o\n\nsq64:\n\t$(CC) -O2 -m64 -fno-exceptions -D_SQ64 -fno-rtti -Wall -fno-strict-aliasing -c $(SRCS) $(INCZ) $(DEFS)\n\tar rc $(OUT) *.o\n\trm *.o\n"
  },
  {
    "path": "extlibs/squirrel/sqstdlib/sqstdaux.cpp",
    "content": "/* see copyright notice in squirrel.h */\n#include <squirrel.h>\n#include <sqstdaux.h>\n#include <assert.h>\n\nvoid sqstd_printcallstack(HSQUIRRELVM v)\n{\n    SQPRINTFUNCTION pf = sq_geterrorfunc(v);\n    if(pf) {\n        SQStackInfos si;\n        SQInteger i;\n        SQFloat f;\n        const SQChar *s;\n        SQInteger level=1; //1 is to skip this function that is level 0\n        const SQChar *name=0;\n        SQInteger seq=0;\n        pf(v,_SC(\"\\nCALLSTACK\\n\"));\n        while(SQ_SUCCEEDED(sq_stackinfos(v,level,&si)))\n        {\n            const SQChar *fn=_SC(\"unknown\");\n            const SQChar *src=_SC(\"unknown\");\n            if(si.funcname)fn=si.funcname;\n            if(si.source)src=si.source;\n            pf(v,_SC(\"*FUNCTION [%s()] %s line [%d]\\n\"),fn,src,si.line);\n            level++;\n        }\n        level=0;\n        pf(v,_SC(\"\\nLOCALS\\n\"));\n\n        for(level=0;level<10;level++){\n            seq=0;\n            while((name = sq_getlocal(v,level,seq)))\n            {\n                seq++;\n                switch(sq_gettype(v,-1))\n                {\n                case OT_NULL:\n                    pf(v,_SC(\"[%s] NULL\\n\"),name);\n                    break;\n                case OT_INTEGER:\n                    sq_getinteger(v,-1,&i);\n                    pf(v,_SC(\"[%s] %d\\n\"),name,i);\n                    break;\n                case OT_FLOAT:\n                    sq_getfloat(v,-1,&f);\n                    pf(v,_SC(\"[%s] %.14g\\n\"),name,f);\n                    break;\n                case OT_USERPOINTER:\n                    pf(v,_SC(\"[%s] USERPOINTER\\n\"),name);\n                    break;\n                case OT_STRING:\n                    sq_getstring(v,-1,&s);\n                    pf(v,_SC(\"[%s] \\\"%s\\\"\\n\"),name,s);\n                    break;\n                case OT_TABLE:\n                    pf(v,_SC(\"[%s] TABLE\\n\"),name);\n                    break;\n                case OT_ARRAY:\n                    pf(v,_SC(\"[%s] ARRAY\\n\"),name);\n                    break;\n                case OT_CLOSURE:\n                    pf(v,_SC(\"[%s] CLOSURE\\n\"),name);\n                    break;\n                case OT_NATIVECLOSURE:\n                    pf(v,_SC(\"[%s] NATIVECLOSURE\\n\"),name);\n                    break;\n                case OT_GENERATOR:\n                    pf(v,_SC(\"[%s] GENERATOR\\n\"),name);\n                    break;\n                case OT_USERDATA:\n                    pf(v,_SC(\"[%s] USERDATA\\n\"),name);\n                    break;\n                case OT_THREAD:\n                    pf(v,_SC(\"[%s] THREAD\\n\"),name);\n                    break;\n                case OT_CLASS:\n                    pf(v,_SC(\"[%s] CLASS\\n\"),name);\n                    break;\n                case OT_INSTANCE:\n                    pf(v,_SC(\"[%s] INSTANCE\\n\"),name);\n                    break;\n                case OT_WEAKREF:\n                    pf(v,_SC(\"[%s] WEAKREF\\n\"),name);\n                    break;\n                case OT_BOOL:{\n                    SQBool bval;\n                    sq_getbool(v,-1,&bval);\n                    pf(v,_SC(\"[%s] %s\\n\"),name,bval == SQTrue ? _SC(\"true\"):_SC(\"false\"));\n                             }\n                    break;\n                default: assert(0); break;\n                }\n                sq_pop(v,1);\n            }\n        }\n    }\n}\n\nstatic SQInteger _sqstd_aux_printerror(HSQUIRRELVM v)\n{\n    SQPRINTFUNCTION pf = sq_geterrorfunc(v);\n    if(pf) {\n        const SQChar *sErr = 0;\n        if(sq_gettop(v)>=1) {\n            if(SQ_SUCCEEDED(sq_getstring(v,2,&sErr)))   {\n                pf(v,_SC(\"\\nAN ERROR HAS OCCURRED [%s]\\n\"),sErr);\n            }\n            else{\n                pf(v,_SC(\"\\nAN ERROR HAS OCCURRED [unknown]\\n\"));\n            }\n            sqstd_printcallstack(v);\n        }\n    }\n    return 0;\n}\n\nvoid _sqstd_compiler_error(HSQUIRRELVM v,const SQChar *sErr,const SQChar *sSource,SQInteger line,SQInteger column)\n{\n    SQPRINTFUNCTION pf = sq_geterrorfunc(v);\n    if(pf) {\n        pf(v,_SC(\"%s line = (%d) column = (%d) : error %s\\n\"),sSource,line,column,sErr);\n    }\n}\n\nvoid sqstd_seterrorhandlers(HSQUIRRELVM v)\n{\n    sq_setcompilererrorhandler(v,_sqstd_compiler_error);\n    sq_newclosure(v,_sqstd_aux_printerror,0);\n    sq_seterrorhandler(v);\n}\n"
  },
  {
    "path": "extlibs/squirrel/sqstdlib/sqstdblob.cpp",
    "content": "/* see copyright notice in squirrel.h */\n#include <new>\n#include <squirrel.h>\n#include <sqstdio.h>\n#include <string.h>\n#include <sqstdblob.h>\n#include \"sqstdstream.h\"\n#include \"sqstdblobimpl.h\"\n\n#define SQSTD_BLOB_TYPE_TAG ((SQUnsignedInteger)(SQSTD_STREAM_TYPE_TAG | 0x00000002))\n\n//Blob\n\n\n#define SETUP_BLOB(v) \\\n    SQBlob *self = NULL; \\\n    { if(SQ_FAILED(sq_getinstanceup(v,1,(SQUserPointer*)&self,(SQUserPointer)SQSTD_BLOB_TYPE_TAG))) \\\n        return sq_throwerror(v,_SC(\"invalid type tag\"));  } \\\n    if(!self || !self->IsValid())  \\\n        return sq_throwerror(v,_SC(\"the blob is invalid\"));\n\n\nstatic SQInteger _blob_resize(HSQUIRRELVM v)\n{\n    SETUP_BLOB(v);\n    SQInteger size;\n    sq_getinteger(v,2,&size);\n    if(!self->Resize(size))\n        return sq_throwerror(v,_SC(\"resize failed\"));\n    return 0;\n}\n\nstatic void __swap_dword(unsigned int *n)\n{\n    *n=(unsigned int)(((*n&0xFF000000)>>24)  |\n            ((*n&0x00FF0000)>>8)  |\n            ((*n&0x0000FF00)<<8)  |\n            ((*n&0x000000FF)<<24));\n}\n\nstatic void __swap_word(unsigned short *n)\n{\n    *n=(unsigned short)((*n>>8)&0x00FF)| ((*n<<8)&0xFF00);\n}\n\nstatic SQInteger _blob_swap4(HSQUIRRELVM v)\n{\n    SETUP_BLOB(v);\n    SQInteger num=(self->Len()-(self->Len()%4))>>2;\n    unsigned int *t=(unsigned int *)self->GetBuf();\n    for(SQInteger i = 0; i < num; i++) {\n        __swap_dword(&t[i]);\n    }\n    return 0;\n}\n\nstatic SQInteger _blob_swap2(HSQUIRRELVM v)\n{\n    SETUP_BLOB(v);\n    SQInteger num=(self->Len()-(self->Len()%2))>>1;\n    unsigned short *t = (unsigned short *)self->GetBuf();\n    for(SQInteger i = 0; i < num; i++) {\n        __swap_word(&t[i]);\n    }\n    return 0;\n}\n\nstatic SQInteger _blob__set(HSQUIRRELVM v)\n{\n    SETUP_BLOB(v);\n    SQInteger idx,val;\n    sq_getinteger(v,2,&idx);\n    sq_getinteger(v,3,&val);\n    if(idx < 0 || idx >= self->Len())\n        return sq_throwerror(v,_SC(\"index out of range\"));\n    ((unsigned char *)self->GetBuf())[idx] = (unsigned char) val;\n    sq_push(v,3);\n    return 1;\n}\n\nstatic SQInteger _blob__get(HSQUIRRELVM v)\n{\n    SETUP_BLOB(v);\n    SQInteger idx;\n\t\n\tif ((sq_gettype(v, 2) & SQOBJECT_NUMERIC) == 0)\n\t{\n\t\tsq_pushnull(v);\n\t\treturn sq_throwobject(v);\n\t}\n    sq_getinteger(v,2,&idx);\n    if(idx < 0 || idx >= self->Len())\n        return sq_throwerror(v,_SC(\"index out of range\"));\n    sq_pushinteger(v,((unsigned char *)self->GetBuf())[idx]);\n    return 1;\n}\n\nstatic SQInteger _blob__nexti(HSQUIRRELVM v)\n{\n    SETUP_BLOB(v);\n    if(sq_gettype(v,2) == OT_NULL) {\n        sq_pushinteger(v, 0);\n        return 1;\n    }\n    SQInteger idx;\n    if(SQ_SUCCEEDED(sq_getinteger(v, 2, &idx))) {\n        if(idx+1 < self->Len()) {\n            sq_pushinteger(v, idx+1);\n            return 1;\n        }\n        sq_pushnull(v);\n        return 1;\n    }\n    return sq_throwerror(v,_SC(\"internal error (_nexti) wrong argument type\"));\n}\n\nstatic SQInteger _blob__typeof(HSQUIRRELVM v)\n{\n    sq_pushstring(v,_SC(\"blob\"),-1);\n    return 1;\n}\n\nstatic SQInteger _blob_releasehook(SQUserPointer p, SQInteger SQ_UNUSED_ARG(size))\n{\n    SQBlob *self = (SQBlob*)p;\n    self->~SQBlob();\n    sq_free(self,sizeof(SQBlob));\n    return 1;\n}\n\nstatic SQInteger _blob_constructor(HSQUIRRELVM v)\n{\n    SQInteger nparam = sq_gettop(v);\n    SQInteger size = 0;\n    if(nparam == 2) {\n        sq_getinteger(v, 2, &size);\n    }\n    if(size < 0) return sq_throwerror(v, _SC(\"cannot create blob with negative size\"));\n    //SQBlob *b = new SQBlob(size);\n\n    SQBlob *b = new (sq_malloc(sizeof(SQBlob)))SQBlob(size);\n    if(SQ_FAILED(sq_setinstanceup(v,1,b))) {\n        b->~SQBlob();\n        sq_free(b,sizeof(SQBlob));\n        return sq_throwerror(v, _SC(\"cannot create blob\"));\n    }\n    sq_setreleasehook(v,1,_blob_releasehook);\n    return 0;\n}\n\nstatic SQInteger _blob__cloned(HSQUIRRELVM v)\n{\n    SQBlob *other = NULL;\n    {\n        if(SQ_FAILED(sq_getinstanceup(v,2,(SQUserPointer*)&other,(SQUserPointer)SQSTD_BLOB_TYPE_TAG)))\n            return SQ_ERROR;\n    }\n    //SQBlob *thisone = new SQBlob(other->Len());\n    SQBlob *thisone = new (sq_malloc(sizeof(SQBlob)))SQBlob(other->Len());\n    memcpy(thisone->GetBuf(),other->GetBuf(),thisone->Len());\n    if(SQ_FAILED(sq_setinstanceup(v,1,thisone))) {\n        thisone->~SQBlob();\n        sq_free(thisone,sizeof(SQBlob));\n        return sq_throwerror(v, _SC(\"cannot clone blob\"));\n    }\n    sq_setreleasehook(v,1,_blob_releasehook);\n    return 0;\n}\n\n#define _DECL_BLOB_FUNC(name,nparams,typecheck) {_SC(#name),_blob_##name,nparams,typecheck}\nstatic const SQRegFunction _blob_methods[] = {\n    _DECL_BLOB_FUNC(constructor,-1,_SC(\"xn\")),\n    _DECL_BLOB_FUNC(resize,2,_SC(\"xn\")),\n    _DECL_BLOB_FUNC(swap2,1,_SC(\"x\")),\n    _DECL_BLOB_FUNC(swap4,1,_SC(\"x\")),\n    _DECL_BLOB_FUNC(_set,3,_SC(\"xnn\")),\n    _DECL_BLOB_FUNC(_get,2,_SC(\"x.\")),\n    _DECL_BLOB_FUNC(_typeof,1,_SC(\"x\")),\n    _DECL_BLOB_FUNC(_nexti,2,_SC(\"x\")),\n    _DECL_BLOB_FUNC(_cloned,2,_SC(\"xx\")),\n    {NULL,(SQFUNCTION)0,0,NULL}\n};\n\n\n\n//GLOBAL FUNCTIONS\n\nstatic SQInteger _g_blob_casti2f(HSQUIRRELVM v)\n{\n    SQInteger i;\n    sq_getinteger(v,2,&i);\n    sq_pushfloat(v,*((const SQFloat *)&i));\n    return 1;\n}\n\nstatic SQInteger _g_blob_castf2i(HSQUIRRELVM v)\n{\n    SQFloat f;\n    sq_getfloat(v,2,&f);\n    sq_pushinteger(v,*((const SQInteger *)&f));\n    return 1;\n}\n\nstatic SQInteger _g_blob_swap2(HSQUIRRELVM v)\n{\n    SQInteger i;\n    sq_getinteger(v,2,&i);\n    short s=(short)i;\n    sq_pushinteger(v,(s<<8)|((s>>8)&0x00FF));\n    return 1;\n}\n\nstatic SQInteger _g_blob_swap4(HSQUIRRELVM v)\n{\n    SQInteger i;\n    sq_getinteger(v,2,&i);\n    unsigned int t4 = (unsigned int)i;\n    __swap_dword(&t4);\n    sq_pushinteger(v,(SQInteger)t4);\n    return 1;\n}\n\nstatic SQInteger _g_blob_swapfloat(HSQUIRRELVM v)\n{\n    SQFloat f;\n    sq_getfloat(v,2,&f);\n    __swap_dword((unsigned int *)&f);\n    sq_pushfloat(v,f);\n    return 1;\n}\n\n#define _DECL_GLOBALBLOB_FUNC(name,nparams,typecheck) {_SC(#name),_g_blob_##name,nparams,typecheck}\nstatic const SQRegFunction bloblib_funcs[]={\n    _DECL_GLOBALBLOB_FUNC(casti2f,2,_SC(\".n\")),\n    _DECL_GLOBALBLOB_FUNC(castf2i,2,_SC(\".n\")),\n    _DECL_GLOBALBLOB_FUNC(swap2,2,_SC(\".n\")),\n    _DECL_GLOBALBLOB_FUNC(swap4,2,_SC(\".n\")),\n    _DECL_GLOBALBLOB_FUNC(swapfloat,2,_SC(\".n\")),\n    {NULL,(SQFUNCTION)0,0,NULL}\n};\n\nSQRESULT sqstd_getblob(HSQUIRRELVM v,SQInteger idx,SQUserPointer *ptr)\n{\n    SQBlob *blob;\n    if(SQ_FAILED(sq_getinstanceup(v,idx,(SQUserPointer *)&blob,(SQUserPointer)SQSTD_BLOB_TYPE_TAG)))\n        return -1;\n    *ptr = blob->GetBuf();\n    return SQ_OK;\n}\n\nSQInteger sqstd_getblobsize(HSQUIRRELVM v,SQInteger idx)\n{\n    SQBlob *blob;\n    if(SQ_FAILED(sq_getinstanceup(v,idx,(SQUserPointer *)&blob,(SQUserPointer)SQSTD_BLOB_TYPE_TAG)))\n        return -1;\n    return blob->Len();\n}\n\nSQUserPointer sqstd_createblob(HSQUIRRELVM v, SQInteger size)\n{\n    SQInteger top = sq_gettop(v);\n    sq_pushregistrytable(v);\n    sq_pushstring(v,_SC(\"std_blob\"),-1);\n    if(SQ_SUCCEEDED(sq_get(v,-2))) {\n        sq_remove(v,-2); //removes the registry\n        sq_push(v,1); // push the this\n        sq_pushinteger(v,size); //size\n        SQBlob *blob = NULL;\n        if(SQ_SUCCEEDED(sq_call(v,2,SQTrue,SQFalse))\n            && SQ_SUCCEEDED(sq_getinstanceup(v,-1,(SQUserPointer *)&blob,(SQUserPointer)SQSTD_BLOB_TYPE_TAG))) {\n            sq_remove(v,-2);\n            return blob->GetBuf();\n        }\n    }\n    sq_settop(v,top);\n    return NULL;\n}\n\nSQRESULT sqstd_register_bloblib(HSQUIRRELVM v)\n{\n    return declare_stream(v,_SC(\"blob\"),(SQUserPointer)SQSTD_BLOB_TYPE_TAG,_SC(\"std_blob\"),_blob_methods,bloblib_funcs);\n}\n\n"
  },
  {
    "path": "extlibs/squirrel/sqstdlib/sqstdblobimpl.h",
    "content": "/*  see copyright notice in squirrel.h */\n#ifndef _SQSTD_BLOBIMPL_H_\n#define _SQSTD_BLOBIMPL_H_\n\nstruct SQBlob : public SQStream\n{\n    SQBlob(SQInteger size) {\n        _size = size;\n        _allocated = size;\n        _buf = (unsigned char *)sq_malloc(size);\n        memset(_buf, 0, _size);\n        _ptr = 0;\n        _owns = true;\n    }\n    virtual ~SQBlob() {\n        sq_free(_buf, _allocated);\n    }\n    SQInteger Write(void *buffer, SQInteger size) {\n        if(!CanAdvance(size)) {\n            GrowBufOf(_ptr + size - _size);\n        }\n        memcpy(&_buf[_ptr], buffer, size);\n        _ptr += size;\n        return size;\n    }\n    SQInteger Read(void *buffer,SQInteger size) {\n        SQInteger n = size;\n        if(!CanAdvance(size)) {\n            if((_size - _ptr) > 0)\n                n = _size - _ptr;\n            else return 0;\n        }\n        memcpy(buffer, &_buf[_ptr], n);\n        _ptr += n;\n        return n;\n    }\n    bool Resize(SQInteger n) {\n        if(!_owns) return false;\n        if(n != _allocated) {\n            unsigned char *newbuf = (unsigned char *)sq_malloc(n);\n            memset(newbuf,0,n);\n            if(_size > n)\n                memcpy(newbuf,_buf,n);\n            else\n                memcpy(newbuf,_buf,_size);\n            sq_free(_buf,_allocated);\n            _buf=newbuf;\n            _allocated = n;\n            if(_size > _allocated)\n                _size = _allocated;\n            if(_ptr > _allocated)\n                _ptr = _allocated;\n        }\n        return true;\n    }\n    bool GrowBufOf(SQInteger n)\n    {\n        bool ret = true;\n        if(_size + n > _allocated) {\n            if(_size + n > _size * 2)\n                ret = Resize(_size + n);\n            else\n                ret = Resize(_size * 2);\n        }\n        _size = _size + n;\n        return ret;\n    }\n    bool CanAdvance(SQInteger n) {\n        if(_ptr+n>_size)return false;\n        return true;\n    }\n    SQInteger Seek(SQInteger offset, SQInteger origin) {\n        switch(origin) {\n            case SQ_SEEK_SET:\n                if(offset > _size || offset < 0) return -1;\n                _ptr = offset;\n                break;\n            case SQ_SEEK_CUR:\n                if(_ptr + offset > _size || _ptr + offset < 0) return -1;\n                _ptr += offset;\n                break;\n            case SQ_SEEK_END:\n                if(_size + offset > _size || _size + offset < 0) return -1;\n                _ptr = _size + offset;\n                break;\n            default: return -1;\n        }\n        return 0;\n    }\n    bool IsValid() {\n        return _size == 0 || _buf?true:false;\n    }\n    bool EOS() {\n        return _ptr == _size;\n    }\n    SQInteger Flush() { return 0; }\n    SQInteger Tell() { return _ptr; }\n    SQInteger Len() { return _size; }\n    SQUserPointer GetBuf(){ return _buf; }\nprivate:\n    SQInteger _size;\n    SQInteger _allocated;\n    SQInteger _ptr;\n    unsigned char *_buf;\n    bool _owns;\n};\n\n#endif //_SQSTD_BLOBIMPL_H_\n"
  },
  {
    "path": "extlibs/squirrel/sqstdlib/sqstdio.cpp",
    "content": "/* see copyright notice in squirrel.h */\n#include <new>\n#include <stdio.h>\n#include <squirrel.h>\n#include <sqstdio.h>\n#include \"sqstdstream.h\"\n\n#define SQSTD_FILE_TYPE_TAG ((SQUnsignedInteger)(SQSTD_STREAM_TYPE_TAG | 0x00000001))\n//basic API\nSQFILE sqstd_fopen(const SQChar *filename ,const SQChar *mode)\n{\n#ifndef SQUNICODE\n    return (SQFILE)fopen(filename,mode);\n#else\n    return (SQFILE)_wfopen(filename,mode);\n#endif\n}\n\nSQInteger sqstd_fread(void* buffer, SQInteger size, SQInteger count, SQFILE file)\n{\n    SQInteger ret = (SQInteger)fread(buffer,size,count,(FILE *)file);\n    return ret;\n}\n\nSQInteger sqstd_fwrite(const SQUserPointer buffer, SQInteger size, SQInteger count, SQFILE file)\n{\n    return (SQInteger)fwrite(buffer,size,count,(FILE *)file);\n}\n\nSQInteger sqstd_fseek(SQFILE file, SQInteger offset, SQInteger origin)\n{\n    SQInteger realorigin;\n    switch(origin) {\n        case SQ_SEEK_CUR: realorigin = SEEK_CUR; break;\n        case SQ_SEEK_END: realorigin = SEEK_END; break;\n        case SQ_SEEK_SET: realorigin = SEEK_SET; break;\n        default: return -1; //failed\n    }\n    return fseek((FILE *)file,(long)offset,(int)realorigin);\n}\n\nSQInteger sqstd_ftell(SQFILE file)\n{\n    return ftell((FILE *)file);\n}\n\nSQInteger sqstd_fflush(SQFILE file)\n{\n    return fflush((FILE *)file);\n}\n\nSQInteger sqstd_fclose(SQFILE file)\n{\n    return fclose((FILE *)file);\n}\n\nSQInteger sqstd_feof(SQFILE file)\n{\n    return feof((FILE *)file);\n}\n\n//File\nstruct SQFile : public SQStream {\n    SQFile() { _handle = NULL; _owns = false;}\n    SQFile(SQFILE file, bool owns) { _handle = file; _owns = owns;}\n    virtual ~SQFile() { Close(); }\n    bool Open(const SQChar *filename ,const SQChar *mode) {\n        Close();\n        if( (_handle = sqstd_fopen(filename,mode)) ) {\n            _owns = true;\n            return true;\n        }\n        return false;\n    }\n    void Close() {\n        if(_handle && _owns) {\n            sqstd_fclose(_handle);\n            _handle = NULL;\n            _owns = false;\n        }\n    }\n    SQInteger Read(void *buffer,SQInteger size) {\n        return sqstd_fread(buffer,1,size,_handle);\n    }\n    SQInteger Write(void *buffer,SQInteger size) {\n        return sqstd_fwrite(buffer,1,size,_handle);\n    }\n    SQInteger Flush() {\n        return sqstd_fflush(_handle);\n    }\n    SQInteger Tell() {\n        return sqstd_ftell(_handle);\n    }\n    SQInteger Len() {\n        SQInteger prevpos=Tell();\n        Seek(0,SQ_SEEK_END);\n        SQInteger size=Tell();\n        Seek(prevpos,SQ_SEEK_SET);\n        return size;\n    }\n    SQInteger Seek(SQInteger offset, SQInteger origin)  {\n        return sqstd_fseek(_handle,offset,origin);\n    }\n    bool IsValid() { return _handle?true:false; }\n    bool EOS() { return Tell()==Len()?true:false;}\n    SQFILE GetHandle() {return _handle;}\nprivate:\n    SQFILE _handle;\n    bool _owns;\n};\n\nstatic SQInteger _file__typeof(HSQUIRRELVM v)\n{\n    sq_pushstring(v,_SC(\"file\"),-1);\n    return 1;\n}\n\nstatic SQInteger _file_releasehook(SQUserPointer p, SQInteger SQ_UNUSED_ARG(size))\n{\n    SQFile *self = (SQFile*)p;\n    self->~SQFile();\n    sq_free(self,sizeof(SQFile));\n    return 1;\n}\n\nstatic SQInteger _file_constructor(HSQUIRRELVM v)\n{\n    const SQChar *filename,*mode;\n    bool owns = true;\n    SQFile *f;\n    SQFILE newf;\n    if(sq_gettype(v,2) == OT_STRING && sq_gettype(v,3) == OT_STRING) {\n        sq_getstring(v, 2, &filename);\n        sq_getstring(v, 3, &mode);\n        newf = sqstd_fopen(filename, mode);\n        if(!newf) return sq_throwerror(v, _SC(\"cannot open file\"));\n    } else if(sq_gettype(v,2) == OT_USERPOINTER) {\n        owns = !(sq_gettype(v,3) == OT_NULL);\n        sq_getuserpointer(v,2,&newf);\n    } else {\n        return sq_throwerror(v,_SC(\"wrong parameter\"));\n    }\n\n    f = new (sq_malloc(sizeof(SQFile)))SQFile(newf,owns);\n    if(SQ_FAILED(sq_setinstanceup(v,1,f))) {\n        f->~SQFile();\n        sq_free(f,sizeof(SQFile));\n        return sq_throwerror(v, _SC(\"cannot create blob with negative size\"));\n    }\n    sq_setreleasehook(v,1,_file_releasehook);\n    return 0;\n}\n\nstatic SQInteger _file_close(HSQUIRRELVM v)\n{\n    SQFile *self = NULL;\n    if(SQ_SUCCEEDED(sq_getinstanceup(v,1,(SQUserPointer*)&self,(SQUserPointer)SQSTD_FILE_TYPE_TAG))\n        && self != NULL)\n    {\n        self->Close();\n    }\n    return 0;\n}\n\n//bindings\n#define _DECL_FILE_FUNC(name,nparams,typecheck) {_SC(#name),_file_##name,nparams,typecheck}\nstatic const SQRegFunction _file_methods[] = {\n    _DECL_FILE_FUNC(constructor,3,_SC(\"x\")),\n    _DECL_FILE_FUNC(_typeof,1,_SC(\"x\")),\n    _DECL_FILE_FUNC(close,1,_SC(\"x\")),\n    {NULL,(SQFUNCTION)0,0,NULL}\n};\n\n\n\nSQRESULT sqstd_createfile(HSQUIRRELVM v, SQFILE file,SQBool own)\n{\n    SQInteger top = sq_gettop(v);\n    sq_pushregistrytable(v);\n    sq_pushstring(v,_SC(\"std_file\"),-1);\n    if(SQ_SUCCEEDED(sq_get(v,-2))) {\n        sq_remove(v,-2); //removes the registry\n        sq_pushroottable(v); // push the this\n        sq_pushuserpointer(v,file); //file\n        if(own){\n            sq_pushinteger(v,1); //true\n        }\n        else{\n            sq_pushnull(v); //false\n        }\n        if(SQ_SUCCEEDED( sq_call(v,3,SQTrue,SQFalse) )) {\n            sq_remove(v,-2);\n            return SQ_OK;\n        }\n    }\n    sq_settop(v,top);\n    return SQ_ERROR;\n}\n\nSQRESULT sqstd_getfile(HSQUIRRELVM v, SQInteger idx, SQFILE *file)\n{\n    SQFile *fileobj = NULL;\n    if(SQ_SUCCEEDED(sq_getinstanceup(v,idx,(SQUserPointer*)&fileobj,(SQUserPointer)SQSTD_FILE_TYPE_TAG))) {\n        *file = fileobj->GetHandle();\n        return SQ_OK;\n    }\n    return sq_throwerror(v,_SC(\"not a file\"));\n}\n\n\n\n#define IO_BUFFER_SIZE 2048\nstruct IOBuffer {\n    unsigned char buffer[IO_BUFFER_SIZE];\n    SQInteger size;\n    SQInteger ptr;\n    SQFILE file;\n};\n\nSQInteger _read_byte(IOBuffer *iobuffer)\n{\n    if(iobuffer->ptr < iobuffer->size) {\n\n        SQInteger ret = iobuffer->buffer[iobuffer->ptr];\n        iobuffer->ptr++;\n        return ret;\n    }\n    else {\n        if( (iobuffer->size = sqstd_fread(iobuffer->buffer,1,IO_BUFFER_SIZE,iobuffer->file )) > 0 )\n        {\n            SQInteger ret = iobuffer->buffer[0];\n            iobuffer->ptr = 1;\n            return ret;\n        }\n    }\n\n    return 0;\n}\n\nSQInteger _read_two_bytes(IOBuffer *iobuffer)\n{\n    if(iobuffer->ptr < iobuffer->size) {\n        if(iobuffer->size < 2) return 0;\n        SQInteger ret = *((const wchar_t*)&iobuffer->buffer[iobuffer->ptr]);\n        iobuffer->ptr += 2;\n        return ret;\n    }\n    else {\n        if( (iobuffer->size = sqstd_fread(iobuffer->buffer,1,IO_BUFFER_SIZE,iobuffer->file )) > 0 )\n        {\n            if(iobuffer->size < 2) return 0;\n            SQInteger ret = *((const wchar_t*)&iobuffer->buffer[0]);\n            iobuffer->ptr = 2;\n            return ret;\n        }\n    }\n\n    return 0;\n}\n\nstatic SQInteger _io_file_lexfeed_PLAIN(SQUserPointer iobuf)\n{\n    IOBuffer *iobuffer = (IOBuffer *)iobuf;\n    return _read_byte(iobuffer);\n\n}\n\n#ifdef SQUNICODE\nstatic SQInteger _io_file_lexfeed_UTF8(SQUserPointer iobuf)\n{\n    IOBuffer *iobuffer = (IOBuffer *)iobuf;\n#define READ(iobuf) \\\n    if((inchar = (unsigned char)_read_byte(iobuf)) == 0) \\\n        return 0;\n\n    static const SQInteger utf8_lengths[16] =\n    {\n        1,1,1,1,1,1,1,1,        /* 0000 to 0111 : 1 byte (plain ASCII) */\n        0,0,0,0,                /* 1000 to 1011 : not valid */\n        2,2,                    /* 1100, 1101 : 2 bytes */\n        3,                      /* 1110 : 3 bytes */\n        4                       /* 1111 :4 bytes */\n    };\n    static const unsigned char byte_masks[5] = {0,0,0x1f,0x0f,0x07};\n    unsigned char inchar;\n    SQInteger c = 0;\n    READ(iobuffer);\n    c = inchar;\n    //\n    if(c >= 0x80) {\n        SQInteger tmp;\n        SQInteger codelen = utf8_lengths[c>>4];\n        if(codelen == 0)\n            return 0;\n            //\"invalid UTF-8 stream\";\n        tmp = c&byte_masks[codelen];\n        for(SQInteger n = 0; n < codelen-1; n++) {\n            tmp<<=6;\n            READ(iobuffer);\n            tmp |= inchar & 0x3F;\n        }\n        c = tmp;\n    }\n    return c;\n}\n#endif\n\nstatic SQInteger _io_file_lexfeed_UCS2_LE(SQUserPointer iobuf)\n{\n    SQInteger ret;\n    IOBuffer *iobuffer = (IOBuffer *)iobuf;\n    if( (ret = _read_two_bytes(iobuffer)) > 0 )\n        return ret;\n    return 0;\n}\n\nstatic SQInteger _io_file_lexfeed_UCS2_BE(SQUserPointer iobuf)\n{\n    SQInteger c;\n    IOBuffer *iobuffer = (IOBuffer *)iobuf;\n    if( (c = _read_two_bytes(iobuffer)) > 0 ) {\n        c = ((c>>8)&0x00FF)| ((c<<8)&0xFF00);\n        return c;\n    }\n    return 0;\n}\n\nSQInteger file_read(SQUserPointer file,SQUserPointer buf,SQInteger size)\n{\n    SQInteger ret;\n    if( ( ret = sqstd_fread(buf,1,size,(SQFILE)file ))!=0 )return ret;\n    return -1;\n}\n\nSQInteger file_write(SQUserPointer file,SQUserPointer p,SQInteger size)\n{\n    return sqstd_fwrite(p,1,size,(SQFILE)file);\n}\n\nSQRESULT sqstd_loadfile(HSQUIRRELVM v,const SQChar *filename,SQBool printerror)\n{\n    SQFILE file = sqstd_fopen(filename,_SC(\"rb\"));\n\n    SQInteger ret;\n    unsigned short us;\n    unsigned char uc;\n    SQLEXREADFUNC func = _io_file_lexfeed_PLAIN;\n    if(file){\n        ret = sqstd_fread(&us,1,2,file);\n        if(ret != 2) {\n            //probably an empty file\n            us = 0;\n        }\n        if(us == SQ_BYTECODE_STREAM_TAG) { //BYTECODE\n            sqstd_fseek(file,0,SQ_SEEK_SET);\n            if(SQ_SUCCEEDED(sq_readclosure(v,file_read,file))) {\n                sqstd_fclose(file);\n                return SQ_OK;\n            }\n        }\n        else { //SCRIPT\n\n            switch(us)\n            {\n                //gotta swap the next 2 lines on BIG endian machines\n                case 0xFFFE: func = _io_file_lexfeed_UCS2_BE; break;//UTF-16 little endian;\n                case 0xFEFF: func = _io_file_lexfeed_UCS2_LE; break;//UTF-16 big endian;\n                case 0xBBEF:\n                    if(sqstd_fread(&uc,1,sizeof(uc),file) == 0) {\n                        sqstd_fclose(file);\n                        return sq_throwerror(v,_SC(\"io error\"));\n                    }\n                    if(uc != 0xBF) {\n                        sqstd_fclose(file);\n                        return sq_throwerror(v,_SC(\"Unrecognized encoding\"));\n                    }\n#ifdef SQUNICODE\n                    func = _io_file_lexfeed_UTF8;\n#else\n                    func = _io_file_lexfeed_PLAIN;\n#endif\n                    break;//UTF-8 ;\n                default: sqstd_fseek(file,0,SQ_SEEK_SET); break; // ascii\n            }\n            IOBuffer buffer;\n            buffer.ptr = 0;\n            buffer.size = 0;\n            buffer.file = file;\n            if(SQ_SUCCEEDED(sq_compile(v,func,&buffer,filename,printerror))){\n                sqstd_fclose(file);\n                return SQ_OK;\n            }\n        }\n        sqstd_fclose(file);\n        return SQ_ERROR;\n    }\n    return sq_throwerror(v,_SC(\"cannot open the file\"));\n}\n\nSQRESULT sqstd_dofile(HSQUIRRELVM v,const SQChar *filename,SQBool retval,SQBool printerror)\n{\n    //at least one entry must exist in order for us to push it as the environment\n    if(sq_gettop(v) == 0)\n        return sq_throwerror(v,_SC(\"environment table expected\"));\n\n    if(SQ_SUCCEEDED(sqstd_loadfile(v,filename,printerror))) {\n        sq_push(v,-2);\n        if(SQ_SUCCEEDED(sq_call(v,1,retval,SQTrue))) {\n            sq_remove(v,retval?-2:-1); //removes the closure\n            return 1;\n        }\n        sq_pop(v,1); //removes the closure\n    }\n    return SQ_ERROR;\n}\n\nSQRESULT sqstd_writeclosuretofile(HSQUIRRELVM v,const SQChar *filename)\n{\n    SQFILE file = sqstd_fopen(filename,_SC(\"wb+\"));\n    if(!file) return sq_throwerror(v,_SC(\"cannot open the file\"));\n    if(SQ_SUCCEEDED(sq_writeclosure(v,file_write,file))) {\n        sqstd_fclose(file);\n        return SQ_OK;\n    }\n    sqstd_fclose(file);\n    return SQ_ERROR; //forward the error\n}\n\nSQInteger _g_io_loadfile(HSQUIRRELVM v)\n{\n    const SQChar *filename;\n    SQBool printerror = SQFalse;\n    sq_getstring(v,2,&filename);\n    if(sq_gettop(v) >= 3) {\n        sq_getbool(v,3,&printerror);\n    }\n    if(SQ_SUCCEEDED(sqstd_loadfile(v,filename,printerror)))\n        return 1;\n    return SQ_ERROR; //propagates the error\n}\n\nSQInteger _g_io_writeclosuretofile(HSQUIRRELVM v)\n{\n    const SQChar *filename;\n    sq_getstring(v,2,&filename);\n    if(SQ_SUCCEEDED(sqstd_writeclosuretofile(v,filename)))\n        return 1;\n    return SQ_ERROR; //propagates the error\n}\n\nSQInteger _g_io_dofile(HSQUIRRELVM v)\n{\n    const SQChar *filename;\n    SQBool printerror = SQFalse;\n    sq_getstring(v,2,&filename);\n    if(sq_gettop(v) >= 3) {\n        sq_getbool(v,3,&printerror);\n    }\n    sq_push(v,1); //repush the this\n    if(SQ_SUCCEEDED(sqstd_dofile(v,filename,SQTrue,printerror)))\n        return 1;\n    return SQ_ERROR; //propagates the error\n}\n\n#define _DECL_GLOBALIO_FUNC(name,nparams,typecheck) {_SC(#name),_g_io_##name,nparams,typecheck}\nstatic const SQRegFunction iolib_funcs[]={\n    _DECL_GLOBALIO_FUNC(loadfile,-2,_SC(\".sb\")),\n    _DECL_GLOBALIO_FUNC(dofile,-2,_SC(\".sb\")),\n    _DECL_GLOBALIO_FUNC(writeclosuretofile,3,_SC(\".sc\")),\n    {NULL,(SQFUNCTION)0,0,NULL}\n};\n\nSQRESULT sqstd_register_iolib(HSQUIRRELVM v)\n{\n    SQInteger top = sq_gettop(v);\n    //create delegate\n    declare_stream(v,_SC(\"file\"),(SQUserPointer)SQSTD_FILE_TYPE_TAG,_SC(\"std_file\"),_file_methods,iolib_funcs);\n    sq_pushstring(v,_SC(\"stdout\"),-1);\n    sqstd_createfile(v,stdout,SQFalse);\n    sq_newslot(v,-3,SQFalse);\n    sq_pushstring(v,_SC(\"stdin\"),-1);\n    sqstd_createfile(v,stdin,SQFalse);\n    sq_newslot(v,-3,SQFalse);\n    sq_pushstring(v,_SC(\"stderr\"),-1);\n    sqstd_createfile(v,stderr,SQFalse);\n    sq_newslot(v,-3,SQFalse);\n    sq_settop(v,top);\n    return SQ_OK;\n}\n"
  },
  {
    "path": "extlibs/squirrel/sqstdlib/sqstdlib.dsp",
    "content": "# Microsoft Developer Studio Project File - Name=\"sqstdlib\" - Package Owner=<4>\n# Microsoft Developer Studio Generated Build File, Format Version 6.00\n# ** DO NOT EDIT **\n\n# TARGTYPE \"Win32 (x86) Static Library\" 0x0104\n\nCFG=sqstdlib - Win32 Release\n!MESSAGE This is not a valid makefile. To build this project using NMAKE,\n!MESSAGE use the Export Makefile command and run\n!MESSAGE \n!MESSAGE NMAKE /f \"sqstdlib.mak\".\n!MESSAGE \n!MESSAGE You can specify a configuration when running NMAKE\n!MESSAGE by defining the macro CFG on the command line. For example:\n!MESSAGE \n!MESSAGE NMAKE /f \"sqstdlib.mak\" CFG=\"sqstdlib - Win32 Release\"\n!MESSAGE \n!MESSAGE Possible choices for configuration are:\n!MESSAGE \n!MESSAGE \"sqstdlib - Win32 Release\" (based on \"Win32 (x86) Static Library\")\n!MESSAGE \"sqstdlib - Win32 Debug\" (based on \"Win32 (x86) Static Library\")\n!MESSAGE \n\n# Begin Project\n# PROP AllowPerConfigDependencies 0\n# PROP Scc_LocalPath \"..\"\nCPP=cl.exe\nRSC=rc.exe\n\n!IF  \"$(CFG)\" == \"sqstdlib - Win32 Release\"\n\n# PROP BASE Use_MFC 0\n# PROP BASE Use_Debug_Libraries 0\n# PROP BASE Output_Dir \"Release\"\n# PROP BASE Intermediate_Dir \"Release\"\n# PROP BASE Target_Dir \"\"\n# PROP Use_MFC 0\n# PROP Use_Debug_Libraries 0\n# PROP Output_Dir \"Release\"\n# PROP Intermediate_Dir \"Release\"\n# PROP Target_Dir \"\"\n# ADD BASE CPP /nologo /W3 /GX /O2 /D \"WIN32\" /D \"NDEBUG\" /D \"_MBCS\" /D \"_LIB\" /YX /FD /c\n# ADD CPP /nologo /W3 /GX /O2 /I \"..\\include\" /D \"WIN32\" /D \"NDEBUG\" /D \"_MBCS\" /D \"_LIB\" /YX /FD /c\n# ADD BASE RSC /l 0x410 /d \"NDEBUG\"\n# ADD RSC /l 0x410 /d \"NDEBUG\"\nBSC32=bscmake.exe\n# ADD BASE BSC32 /nologo\n# ADD BSC32 /nologo\nLIB32=link.exe -lib\n# ADD BASE LIB32 /nologo\n# ADD LIB32 /nologo /out:\"..\\lib\\sqstdlib.lib\"\n\n!ELSEIF  \"$(CFG)\" == \"sqstdlib - Win32 Debug\"\n\n# PROP BASE Use_MFC 0\n# PROP BASE Use_Debug_Libraries 1\n# PROP BASE Output_Dir \"Debug\"\n# PROP BASE Intermediate_Dir \"Debug\"\n# PROP BASE Target_Dir \"\"\n# PROP Use_MFC 0\n# PROP Use_Debug_Libraries 1\n# PROP Output_Dir \"Debug\"\n# PROP Intermediate_Dir \"Debug\"\n# PROP Target_Dir \"\"\n# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D \"WIN32\" /D \"_DEBUG\" /D \"_MBCS\" /D \"_LIB\" /YX /FD /GZ /c\n# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I \"..\\include\" /D \"WIN32\" /D \"_DEBUG\" /D \"_MBCS\" /D \"_LIB\" /YX /FD /GZ /c\n# ADD BASE RSC /l 0x410 /d \"_DEBUG\"\n# ADD RSC /l 0x410 /d \"_DEBUG\"\nBSC32=bscmake.exe\n# ADD BASE BSC32 /nologo\n# ADD BSC32 /nologo\nLIB32=link.exe -lib\n# ADD BASE LIB32 /nologo\n# ADD LIB32 /nologo /out:\"..\\lib\\sqstdlib.lib\"\n\n!ENDIF \n\n# Begin Target\n\n# Name \"sqstdlib - Win32 Release\"\n# Name \"sqstdlib - Win32 Debug\"\n# Begin Group \"Source Files\"\n\n# PROP Default_Filter \"cpp;c;cxx;rc;def;r;odl;idl;hpj;bat\"\n# Begin Source File\n\nSOURCE=.\\sqstdblob.cpp\n# End Source File\n# Begin Source File\n\nSOURCE=.\\sqstdio.cpp\n# End Source File\n# Begin Source File\n\nSOURCE=.\\sqstdmath.cpp\n# End Source File\n# Begin Source File\n\nSOURCE=.\\sqstdrex.cpp\n# End Source File\n# Begin Source File\n\nSOURCE=.\\sqstdstream.cpp\n# End Source File\n# Begin Source File\n\nSOURCE=.\\sqstdstring.cpp\n# End Source File\n# Begin Source File\n\nSOURCE=.\\sqstdaux.cpp\n# End Source File\n# Begin Source File\n\nSOURCE=.\\sqstdsystem.cpp\n# End Source File\n# End Group\n# Begin Group \"Header Files\"\n\n# PROP Default_Filter \"h;hpp;hxx;hm;inl\"\n# Begin Source File\n\nSOURCE=.\\sqstdblobimpl.h\n# End Source File\n# Begin Source File\n\nSOURCE=.\\sqstdstream.h\n# End Source File\n# End Group\n# End Target\n# End Project\n"
  },
  {
    "path": "extlibs/squirrel/sqstdlib/sqstdmath.cpp",
    "content": "/* see copyright notice in squirrel.h */\n#include <squirrel.h>\n#include <math.h>\n#include <stdlib.h>\n#include <sqstdmath.h>\n\n#define SINGLE_ARG_FUNC(_funcname) static SQInteger math_##_funcname(HSQUIRRELVM v){ \\\n    SQFloat f; \\\n    sq_getfloat(v,2,&f); \\\n    sq_pushfloat(v,(SQFloat)_funcname(f)); \\\n    return 1; \\\n}\n\n#define TWO_ARGS_FUNC(_funcname) static SQInteger math_##_funcname(HSQUIRRELVM v){ \\\n    SQFloat p1,p2; \\\n    sq_getfloat(v,2,&p1); \\\n    sq_getfloat(v,3,&p2); \\\n    sq_pushfloat(v,(SQFloat)_funcname(p1,p2)); \\\n    return 1; \\\n}\n\nstatic SQInteger math_srand(HSQUIRRELVM v)\n{\n    SQInteger i;\n    if(SQ_FAILED(sq_getinteger(v,2,&i)))\n        return sq_throwerror(v,_SC(\"invalid param\"));\n    srand((unsigned int)i);\n    return 0;\n}\n\nstatic SQInteger math_rand(HSQUIRRELVM v)\n{\n    sq_pushinteger(v,rand());\n    return 1;\n}\n\nstatic SQInteger math_abs(HSQUIRRELVM v)\n{\n    SQInteger n;\n    sq_getinteger(v,2,&n);\n    sq_pushinteger(v,(SQInteger)abs((int)n));\n    return 1;\n}\n\nSINGLE_ARG_FUNC(sqrt)\nSINGLE_ARG_FUNC(fabs)\nSINGLE_ARG_FUNC(sin)\nSINGLE_ARG_FUNC(cos)\nSINGLE_ARG_FUNC(asin)\nSINGLE_ARG_FUNC(acos)\nSINGLE_ARG_FUNC(log)\nSINGLE_ARG_FUNC(log10)\nSINGLE_ARG_FUNC(tan)\nSINGLE_ARG_FUNC(atan)\nTWO_ARGS_FUNC(atan2)\nTWO_ARGS_FUNC(pow)\nSINGLE_ARG_FUNC(floor)\nSINGLE_ARG_FUNC(ceil)\nSINGLE_ARG_FUNC(exp)\n\n#define _DECL_FUNC(name,nparams,tycheck) {_SC(#name),math_##name,nparams,tycheck}\nstatic const SQRegFunction mathlib_funcs[] = {\n    _DECL_FUNC(sqrt,2,_SC(\".n\")),\n    _DECL_FUNC(sin,2,_SC(\".n\")),\n    _DECL_FUNC(cos,2,_SC(\".n\")),\n    _DECL_FUNC(asin,2,_SC(\".n\")),\n    _DECL_FUNC(acos,2,_SC(\".n\")),\n    _DECL_FUNC(log,2,_SC(\".n\")),\n    _DECL_FUNC(log10,2,_SC(\".n\")),\n    _DECL_FUNC(tan,2,_SC(\".n\")),\n    _DECL_FUNC(atan,2,_SC(\".n\")),\n    _DECL_FUNC(atan2,3,_SC(\".nn\")),\n    _DECL_FUNC(pow,3,_SC(\".nn\")),\n    _DECL_FUNC(floor,2,_SC(\".n\")),\n    _DECL_FUNC(ceil,2,_SC(\".n\")),\n    _DECL_FUNC(exp,2,_SC(\".n\")),\n    _DECL_FUNC(srand,2,_SC(\".n\")),\n    _DECL_FUNC(rand,1,NULL),\n    _DECL_FUNC(fabs,2,_SC(\".n\")),\n    _DECL_FUNC(abs,2,_SC(\".n\")),\n    {NULL,(SQFUNCTION)0,0,NULL}\n};\n#undef _DECL_FUNC\n\n#ifndef M_PI\n#define M_PI (3.14159265358979323846)\n#endif\n\nSQRESULT sqstd_register_mathlib(HSQUIRRELVM v)\n{\n    SQInteger i=0;\n    while(mathlib_funcs[i].name!=0) {\n        sq_pushstring(v,mathlib_funcs[i].name,-1);\n        sq_newclosure(v,mathlib_funcs[i].f,0);\n        sq_setparamscheck(v,mathlib_funcs[i].nparamscheck,mathlib_funcs[i].typemask);\n        sq_setnativeclosurename(v,-1,mathlib_funcs[i].name);\n        sq_newslot(v,-3,SQFalse);\n        i++;\n    }\n    sq_pushstring(v,_SC(\"RAND_MAX\"),-1);\n    sq_pushinteger(v,RAND_MAX);\n    sq_newslot(v,-3,SQFalse);\n    sq_pushstring(v,_SC(\"PI\"),-1);\n    sq_pushfloat(v,(SQFloat)M_PI);\n    sq_newslot(v,-3,SQFalse);\n    return SQ_OK;\n}\n"
  },
  {
    "path": "extlibs/squirrel/sqstdlib/sqstdrex.cpp",
    "content": "/* see copyright notice in squirrel.h */\n#include <squirrel.h>\n#include <string.h>\n#include <ctype.h>\n#include <setjmp.h>\n#include <sqstdstring.h>\n\n#ifdef _DEBUG\n#include <stdio.h>\n\nstatic const SQChar *g_nnames[] =\n{\n    _SC(\"NONE\"),_SC(\"OP_GREEDY\"),   _SC(\"OP_OR\"),\n    _SC(\"OP_EXPR\"),_SC(\"OP_NOCAPEXPR\"),_SC(\"OP_DOT\"),   _SC(\"OP_CLASS\"),\n    _SC(\"OP_CCLASS\"),_SC(\"OP_NCLASS\"),_SC(\"OP_RANGE\"),_SC(\"OP_CHAR\"),\n    _SC(\"OP_EOL\"),_SC(\"OP_BOL\"),_SC(\"OP_WB\"),_SC(\"OP_MB\")\n};\n\n#endif\n\n#define OP_GREEDY       (MAX_CHAR+1) // * + ? {n}\n#define OP_OR           (MAX_CHAR+2)\n#define OP_EXPR         (MAX_CHAR+3) //parentesis ()\n#define OP_NOCAPEXPR    (MAX_CHAR+4) //parentesis (?:)\n#define OP_DOT          (MAX_CHAR+5)\n#define OP_CLASS        (MAX_CHAR+6)\n#define OP_CCLASS       (MAX_CHAR+7)\n#define OP_NCLASS       (MAX_CHAR+8) //negates class the [^\n#define OP_RANGE        (MAX_CHAR+9)\n#define OP_CHAR         (MAX_CHAR+10)\n#define OP_EOL          (MAX_CHAR+11)\n#define OP_BOL          (MAX_CHAR+12)\n#define OP_WB           (MAX_CHAR+13)\n#define OP_MB           (MAX_CHAR+14) //match balanced\n\n#define SQREX_SYMBOL_ANY_CHAR ('.')\n#define SQREX_SYMBOL_GREEDY_ONE_OR_MORE ('+')\n#define SQREX_SYMBOL_GREEDY_ZERO_OR_MORE ('*')\n#define SQREX_SYMBOL_GREEDY_ZERO_OR_ONE ('?')\n#define SQREX_SYMBOL_BRANCH ('|')\n#define SQREX_SYMBOL_END_OF_STRING ('$')\n#define SQREX_SYMBOL_BEGINNING_OF_STRING ('^')\n#define SQREX_SYMBOL_ESCAPE_CHAR ('\\\\')\n\n\ntypedef int SQRexNodeType;\n\ntypedef struct tagSQRexNode{\n    SQRexNodeType type;\n    SQInteger left;\n    SQInteger right;\n    SQInteger next;\n}SQRexNode;\n\nstruct SQRex{\n    const SQChar *_eol;\n    const SQChar *_bol;\n    const SQChar *_p;\n    SQInteger _first;\n    SQInteger _op;\n    SQRexNode *_nodes;\n    SQInteger _nallocated;\n    SQInteger _nsize;\n    SQInteger _nsubexpr;\n    SQRexMatch *_matches;\n    SQInteger _currsubexp;\n    void *_jmpbuf;\n    const SQChar **_error;\n};\n\nstatic SQInteger sqstd_rex_list(SQRex *exp);\n\nstatic SQInteger sqstd_rex_newnode(SQRex *exp, SQRexNodeType type)\n{\n    SQRexNode n;\n    n.type = type;\n    n.next = n.right = n.left = -1;\n    if(type == OP_EXPR)\n        n.right = exp->_nsubexpr++;\n    if(exp->_nallocated < (exp->_nsize + 1)) {\n        SQInteger oldsize = exp->_nallocated;\n        exp->_nallocated *= 2;\n        exp->_nodes = (SQRexNode *)sq_realloc(exp->_nodes, oldsize * sizeof(SQRexNode) ,exp->_nallocated * sizeof(SQRexNode));\n    }\n    exp->_nodes[exp->_nsize++] = n;\n    SQInteger newid = exp->_nsize - 1;\n    return (SQInteger)newid;\n}\n\nstatic void sqstd_rex_error(SQRex *exp,const SQChar *error)\n{\n    if(exp->_error) *exp->_error = error;\n    longjmp(*((jmp_buf*)exp->_jmpbuf),-1);\n}\n\nstatic void sqstd_rex_expect(SQRex *exp, SQInteger n){\n    if((*exp->_p) != n)\n        sqstd_rex_error(exp, _SC(\"expected paren\"));\n    exp->_p++;\n}\n\nstatic SQChar sqstd_rex_escapechar(SQRex *exp)\n{\n    if(*exp->_p == SQREX_SYMBOL_ESCAPE_CHAR){\n        exp->_p++;\n        switch(*exp->_p) {\n        case 'v': exp->_p++; return '\\v';\n        case 'n': exp->_p++; return '\\n';\n        case 't': exp->_p++; return '\\t';\n        case 'r': exp->_p++; return '\\r';\n        case 'f': exp->_p++; return '\\f';\n        default: return (*exp->_p++);\n        }\n    } else if(!scisprint(*exp->_p)) sqstd_rex_error(exp,_SC(\"letter expected\"));\n    return (*exp->_p++);\n}\n\nstatic SQInteger sqstd_rex_charclass(SQRex *exp,SQInteger classid)\n{\n    SQInteger n = sqstd_rex_newnode(exp,OP_CCLASS);\n    exp->_nodes[n].left = classid;\n    return n;\n}\n\nstatic SQInteger sqstd_rex_charnode(SQRex *exp,SQBool isclass)\n{\n    SQChar t;\n    if(*exp->_p == SQREX_SYMBOL_ESCAPE_CHAR) {\n        exp->_p++;\n        switch(*exp->_p) {\n            case 'n': exp->_p++; return sqstd_rex_newnode(exp,'\\n');\n            case 't': exp->_p++; return sqstd_rex_newnode(exp,'\\t');\n            case 'r': exp->_p++; return sqstd_rex_newnode(exp,'\\r');\n            case 'f': exp->_p++; return sqstd_rex_newnode(exp,'\\f');\n            case 'v': exp->_p++; return sqstd_rex_newnode(exp,'\\v');\n            case 'a': case 'A': case 'w': case 'W': case 's': case 'S':\n            case 'd': case 'D': case 'x': case 'X': case 'c': case 'C':\n            case 'p': case 'P': case 'l': case 'u':\n                {\n                t = *exp->_p; exp->_p++;\n                return sqstd_rex_charclass(exp,t);\n                }\n            case 'm':\n                {\n                     SQChar cb, ce; //cb = character begin match ce = character end match\n                     cb = *++exp->_p; //skip 'm'\n                     ce = *++exp->_p;\n                     exp->_p++; //points to the next char to be parsed\n                     if ((!cb) || (!ce)) sqstd_rex_error(exp,_SC(\"balanced chars expected\"));\n                     if ( cb == ce ) sqstd_rex_error(exp,_SC(\"open/close char can't be the same\"));\n                     SQInteger node =  sqstd_rex_newnode(exp,OP_MB);\n                     exp->_nodes[node].left = cb;\n                     exp->_nodes[node].right = ce;\n                     return node;\n                }\n            case 0:\n                sqstd_rex_error(exp,_SC(\"letter expected for argument of escape sequence\"));\n                break;\n            case 'b':\n            case 'B':\n                if(!isclass) {\n                    SQInteger node = sqstd_rex_newnode(exp,OP_WB);\n                    exp->_nodes[node].left = *exp->_p;\n                    exp->_p++;\n                    return node;\n                } //else default\n            default:\n                t = *exp->_p; exp->_p++;\n                return sqstd_rex_newnode(exp,t);\n        }\n    }\n    else if(!scisprint(*exp->_p)) {\n\n        sqstd_rex_error(exp,_SC(\"letter expected\"));\n    }\n    t = *exp->_p; exp->_p++;\n    return sqstd_rex_newnode(exp,t);\n}\nstatic SQInteger sqstd_rex_class(SQRex *exp)\n{\n    SQInteger ret = -1;\n    SQInteger first = -1,chain;\n    if(*exp->_p == SQREX_SYMBOL_BEGINNING_OF_STRING){\n        ret = sqstd_rex_newnode(exp,OP_NCLASS);\n        exp->_p++;\n    }else ret = sqstd_rex_newnode(exp,OP_CLASS);\n\n    if(*exp->_p == ']') sqstd_rex_error(exp,_SC(\"empty class\"));\n    chain = ret;\n    while(*exp->_p != ']' && exp->_p != exp->_eol) {\n        if(*exp->_p == '-' && first != -1){\n            SQInteger r;\n            if(*exp->_p++ == ']') sqstd_rex_error(exp,_SC(\"unfinished range\"));\n            r = sqstd_rex_newnode(exp,OP_RANGE);\n            if(exp->_nodes[first].type>*exp->_p) sqstd_rex_error(exp,_SC(\"invalid range\"));\n            if(exp->_nodes[first].type == OP_CCLASS) sqstd_rex_error(exp,_SC(\"cannot use character classes in ranges\"));\n            exp->_nodes[r].left = exp->_nodes[first].type;\n            SQInteger t = sqstd_rex_escapechar(exp);\n            exp->_nodes[r].right = t;\n            exp->_nodes[chain].next = r;\n            chain = r;\n            first = -1;\n        }\n        else{\n            if(first!=-1){\n                SQInteger c = first;\n                exp->_nodes[chain].next = c;\n                chain = c;\n                first = sqstd_rex_charnode(exp,SQTrue);\n            }\n            else{\n                first = sqstd_rex_charnode(exp,SQTrue);\n            }\n        }\n    }\n    if(first!=-1){\n        SQInteger c = first;\n        exp->_nodes[chain].next = c;\n    }\n    /* hack? */\n    exp->_nodes[ret].left = exp->_nodes[ret].next;\n    exp->_nodes[ret].next = -1;\n    return ret;\n}\n\nstatic SQInteger sqstd_rex_parsenumber(SQRex *exp)\n{\n    SQInteger ret = *exp->_p-'0';\n    SQInteger positions = 10;\n    exp->_p++;\n    while(isdigit(*exp->_p)) {\n        ret = ret*10+(*exp->_p++-'0');\n        if(positions==1000000000) sqstd_rex_error(exp,_SC(\"overflow in numeric constant\"));\n        positions *= 10;\n    };\n    return ret;\n}\n\nstatic SQInteger sqstd_rex_element(SQRex *exp)\n{\n    SQInteger ret = -1;\n    switch(*exp->_p)\n    {\n    case '(': {\n        SQInteger expr;\n        exp->_p++;\n\n\n        if(*exp->_p =='?') {\n            exp->_p++;\n            sqstd_rex_expect(exp,':');\n            expr = sqstd_rex_newnode(exp,OP_NOCAPEXPR);\n        }\n        else\n            expr = sqstd_rex_newnode(exp,OP_EXPR);\n        SQInteger newn = sqstd_rex_list(exp);\n        exp->_nodes[expr].left = newn;\n        ret = expr;\n        sqstd_rex_expect(exp,')');\n              }\n              break;\n    case '[':\n        exp->_p++;\n        ret = sqstd_rex_class(exp);\n        sqstd_rex_expect(exp,']');\n        break;\n    case SQREX_SYMBOL_END_OF_STRING: exp->_p++; ret = sqstd_rex_newnode(exp,OP_EOL);break;\n    case SQREX_SYMBOL_ANY_CHAR: exp->_p++; ret = sqstd_rex_newnode(exp,OP_DOT);break;\n    default:\n        ret = sqstd_rex_charnode(exp,SQFalse);\n        break;\n    }\n\n\n    SQBool isgreedy = SQFalse;\n    unsigned short p0 = 0, p1 = 0;\n    switch(*exp->_p){\n        case SQREX_SYMBOL_GREEDY_ZERO_OR_MORE: p0 = 0; p1 = 0xFFFF; exp->_p++; isgreedy = SQTrue; break;\n        case SQREX_SYMBOL_GREEDY_ONE_OR_MORE: p0 = 1; p1 = 0xFFFF; exp->_p++; isgreedy = SQTrue; break;\n        case SQREX_SYMBOL_GREEDY_ZERO_OR_ONE: p0 = 0; p1 = 1; exp->_p++; isgreedy = SQTrue; break;\n        case '{':\n            exp->_p++;\n            if(!isdigit(*exp->_p)) sqstd_rex_error(exp,_SC(\"number expected\"));\n            p0 = (unsigned short)sqstd_rex_parsenumber(exp);\n            /*******************************/\n            switch(*exp->_p) {\n        case '}':\n            p1 = p0; exp->_p++;\n            break;\n        case ',':\n            exp->_p++;\n            p1 = 0xFFFF;\n            if(isdigit(*exp->_p)){\n                p1 = (unsigned short)sqstd_rex_parsenumber(exp);\n            }\n            sqstd_rex_expect(exp,'}');\n            break;\n        default:\n            sqstd_rex_error(exp,_SC(\", or } expected\"));\n            }\n            /*******************************/\n            isgreedy = SQTrue;\n            break;\n\n    }\n    if(isgreedy) {\n        SQInteger nnode = sqstd_rex_newnode(exp,OP_GREEDY);\n        exp->_nodes[nnode].left = ret;\n        exp->_nodes[nnode].right = ((p0)<<16)|p1;\n        ret = nnode;\n    }\n\n    if((*exp->_p != SQREX_SYMBOL_BRANCH) && (*exp->_p != ')') && (*exp->_p != SQREX_SYMBOL_GREEDY_ZERO_OR_MORE) && (*exp->_p != SQREX_SYMBOL_GREEDY_ONE_OR_MORE) && (*exp->_p != '\\0')) {\n        SQInteger nnode = sqstd_rex_element(exp);\n        exp->_nodes[ret].next = nnode;\n    }\n\n    return ret;\n}\n\nstatic SQInteger sqstd_rex_list(SQRex *exp)\n{\n    SQInteger ret=-1,e;\n    if(*exp->_p == SQREX_SYMBOL_BEGINNING_OF_STRING) {\n        exp->_p++;\n        ret = sqstd_rex_newnode(exp,OP_BOL);\n    }\n    e = sqstd_rex_element(exp);\n    if(ret != -1) {\n        exp->_nodes[ret].next = e;\n    }\n    else ret = e;\n\n    if(*exp->_p == SQREX_SYMBOL_BRANCH) {\n        SQInteger temp,tright;\n        exp->_p++;\n        temp = sqstd_rex_newnode(exp,OP_OR);\n        exp->_nodes[temp].left = ret;\n        tright = sqstd_rex_list(exp);\n        exp->_nodes[temp].right = tright;\n        ret = temp;\n    }\n    return ret;\n}\n\nstatic SQBool sqstd_rex_matchcclass(SQInteger cclass,SQChar c)\n{\n    switch(cclass) {\n    case 'a': return isalpha(c)?SQTrue:SQFalse;\n    case 'A': return !isalpha(c)?SQTrue:SQFalse;\n    case 'w': return (isalnum(c) || c == '_')?SQTrue:SQFalse;\n    case 'W': return (!isalnum(c) && c != '_')?SQTrue:SQFalse;\n    case 's': return isspace(c)?SQTrue:SQFalse;\n    case 'S': return !isspace(c)?SQTrue:SQFalse;\n    case 'd': return isdigit(c)?SQTrue:SQFalse;\n    case 'D': return !isdigit(c)?SQTrue:SQFalse;\n    case 'x': return isxdigit(c)?SQTrue:SQFalse;\n    case 'X': return !isxdigit(c)?SQTrue:SQFalse;\n    case 'c': return iscntrl(c)?SQTrue:SQFalse;\n    case 'C': return !iscntrl(c)?SQTrue:SQFalse;\n    case 'p': return ispunct(c)?SQTrue:SQFalse;\n    case 'P': return !ispunct(c)?SQTrue:SQFalse;\n    case 'l': return islower(c)?SQTrue:SQFalse;\n    case 'u': return isupper(c)?SQTrue:SQFalse;\n    }\n    return SQFalse; /*cannot happen*/\n}\n\nstatic SQBool sqstd_rex_matchclass(SQRex* exp,SQRexNode *node,SQChar c)\n{\n    do {\n        switch(node->type) {\n            case OP_RANGE:\n                if(c >= node->left && c <= node->right) return SQTrue;\n                break;\n            case OP_CCLASS:\n                if(sqstd_rex_matchcclass(node->left,c)) return SQTrue;\n                break;\n            default:\n                if(c == node->type)return SQTrue;\n        }\n    } while((node->next != -1) && (node = &exp->_nodes[node->next]));\n    return SQFalse;\n}\n\nstatic const SQChar *sqstd_rex_matchnode(SQRex* exp,SQRexNode *node,const SQChar *str,SQRexNode *next)\n{\n\n    SQRexNodeType type = node->type;\n    switch(type) {\n    case OP_GREEDY: {\n        //SQRexNode *greedystop = (node->next != -1) ? &exp->_nodes[node->next] : NULL;\n        SQRexNode *greedystop = NULL;\n        SQInteger p0 = (node->right >> 16)&0x0000FFFF, p1 = node->right&0x0000FFFF, nmaches = 0;\n        const SQChar *s=str, *good = str;\n\n        if(node->next != -1) {\n            greedystop = &exp->_nodes[node->next];\n        }\n        else {\n            greedystop = next;\n        }\n\n        while((nmaches == 0xFFFF || nmaches < p1)) {\n\n            const SQChar *stop;\n            if(!(s = sqstd_rex_matchnode(exp,&exp->_nodes[node->left],s,greedystop)))\n                break;\n            nmaches++;\n            good=s;\n            if(greedystop) {\n                //checks that 0 matches satisfy the expression(if so skips)\n                //if not would always stop(for instance if is a '?')\n                if(greedystop->type != OP_GREEDY ||\n                (greedystop->type == OP_GREEDY && ((greedystop->right >> 16)&0x0000FFFF) != 0))\n                {\n                    SQRexNode *gnext = NULL;\n                    if(greedystop->next != -1) {\n                        gnext = &exp->_nodes[greedystop->next];\n                    }else if(next && next->next != -1){\n                        gnext = &exp->_nodes[next->next];\n                    }\n                    stop = sqstd_rex_matchnode(exp,greedystop,s,gnext);\n                    if(stop) {\n                        //if satisfied stop it\n                        if(p0 == p1 && p0 == nmaches) break;\n                        else if(nmaches >= p0 && p1 == 0xFFFF) break;\n                        else if(nmaches >= p0 && nmaches <= p1) break;\n                    }\n                }\n            }\n\n            if(s >= exp->_eol)\n                break;\n        }\n        if(p0 == p1 && p0 == nmaches) return good;\n        else if(nmaches >= p0 && p1 == 0xFFFF) return good;\n        else if(nmaches >= p0 && nmaches <= p1) return good;\n        return NULL;\n    }\n    case OP_OR: {\n            const SQChar *asd = str;\n            SQRexNode *temp=&exp->_nodes[node->left];\n            while( (asd = sqstd_rex_matchnode(exp,temp,asd,NULL)) ) {\n                if(temp->next != -1)\n                    temp = &exp->_nodes[temp->next];\n                else\n                    return asd;\n            }\n            asd = str;\n            temp = &exp->_nodes[node->right];\n            while( (asd = sqstd_rex_matchnode(exp,temp,asd,NULL)) ) {\n                if(temp->next != -1)\n                    temp = &exp->_nodes[temp->next];\n                else\n                    return asd;\n            }\n            return NULL;\n            break;\n    }\n    case OP_EXPR:\n    case OP_NOCAPEXPR:{\n            SQRexNode *n = &exp->_nodes[node->left];\n            const SQChar *cur = str;\n            SQInteger capture = -1;\n            if(node->type != OP_NOCAPEXPR && node->right == exp->_currsubexp) {\n                capture = exp->_currsubexp;\n                exp->_matches[capture].begin = cur;\n                exp->_currsubexp++;\n            }\n            SQInteger tempcap = exp->_currsubexp;\n            do {\n                SQRexNode *subnext = NULL;\n                if(n->next != -1) {\n                    subnext = &exp->_nodes[n->next];\n                }else {\n                    subnext = next;\n                }\n                if(!(cur = sqstd_rex_matchnode(exp,n,cur,subnext))) {\n                    if(capture != -1){\n                        exp->_matches[capture].begin = 0;\n                        exp->_matches[capture].len = 0;\n                    }\n                    return NULL;\n                }\n            } while((n->next != -1) && (n = &exp->_nodes[n->next]));\n\n            exp->_currsubexp = tempcap;\n            if(capture != -1)\n                exp->_matches[capture].len = cur - exp->_matches[capture].begin;\n            return cur;\n    }\n    case OP_WB:\n        if((str == exp->_bol && !isspace(*str))\n         || (str == exp->_eol && !isspace(*(str-1)))\n         || (!isspace(*str) && isspace(*(str+1)))\n         || (isspace(*str) && !isspace(*(str+1))) ) {\n            return (node->left == 'b')?str:NULL;\n        }\n        return (node->left == 'b')?NULL:str;\n    case OP_BOL:\n        if(str == exp->_bol) return str;\n        return NULL;\n    case OP_EOL:\n        if(str == exp->_eol) return str;\n        return NULL;\n    case OP_DOT:{\n        if (str == exp->_eol) return NULL;\n        str++;\n                }\n        return str;\n    case OP_NCLASS:\n    case OP_CLASS:\n        if (str == exp->_eol) return NULL;\n        if(sqstd_rex_matchclass(exp,&exp->_nodes[node->left],*str)?(type == OP_CLASS?SQTrue:SQFalse):(type == OP_NCLASS?SQTrue:SQFalse)) {\n            str++;\n            return str;\n        }\n        return NULL;\n    case OP_CCLASS:\n        if (str == exp->_eol) return NULL;\n        if(sqstd_rex_matchcclass(node->left,*str)) {\n            str++;\n            return str;\n        }\n        return NULL;\n    case OP_MB:\n        {\n            SQInteger cb = node->left; //char that opens a balanced expression\n            if(*str != cb) return NULL; // string doesnt start with open char\n            SQInteger ce = node->right; //char that closes a balanced expression\n            SQInteger cont = 1;\n            const SQChar *streol = exp->_eol;\n            while (++str < streol) {\n              if (*str == ce) {\n                if (--cont == 0) {\n                    return ++str;\n                }\n              }\n              else if (*str == cb) cont++;\n            }\n        }\n        return NULL; // string ends out of balance\n    default: /* char */\n        if (str == exp->_eol) return NULL;\n        if(*str != node->type) return NULL;\n        str++;\n        return str;\n    }\n    return NULL;\n}\n\n/* public api */\nSQRex *sqstd_rex_compile(const SQChar *pattern,const SQChar **error)\n{\n    SQRex * volatile exp = (SQRex *)sq_malloc(sizeof(SQRex)); // \"volatile\" is needed for setjmp()\n    exp->_eol = exp->_bol = NULL;\n    exp->_p = pattern;\n    exp->_nallocated = (SQInteger)scstrlen(pattern) * sizeof(SQChar);\n    exp->_nodes = (SQRexNode *)sq_malloc(exp->_nallocated * sizeof(SQRexNode));\n    exp->_nsize = 0;\n    exp->_matches = 0;\n    exp->_nsubexpr = 0;\n    exp->_first = sqstd_rex_newnode(exp,OP_EXPR);\n    exp->_error = error;\n    exp->_jmpbuf = sq_malloc(sizeof(jmp_buf));\n    if(setjmp(*((jmp_buf*)exp->_jmpbuf)) == 0) {\n        SQInteger res = sqstd_rex_list(exp);\n        exp->_nodes[exp->_first].left = res;\n        if(*exp->_p!='\\0')\n            sqstd_rex_error(exp,_SC(\"unexpected character\"));\n#ifdef _DEBUG\n        {\n            SQInteger nsize,i;\n            SQRexNode *t;\n            nsize = exp->_nsize;\n            t = &exp->_nodes[0];\n            scprintf(_SC(\"\\n\"));\n            for(i = 0;i < nsize; i++) {\n                if(exp->_nodes[i].type>MAX_CHAR)\n                    scprintf(_SC(\"[%02d] %10s \"), (SQInt32)i,g_nnames[exp->_nodes[i].type-MAX_CHAR]);\n                else\n                    scprintf(_SC(\"[%02d] %10c \"), (SQInt32)i,exp->_nodes[i].type);\n                scprintf(_SC(\"left %02d right %02d next %02d\\n\"), (SQInt32)exp->_nodes[i].left, (SQInt32)exp->_nodes[i].right, (SQInt32)exp->_nodes[i].next);\n            }\n            scprintf(_SC(\"\\n\"));\n        }\n#endif\n        exp->_matches = (SQRexMatch *) sq_malloc(exp->_nsubexpr * sizeof(SQRexMatch));\n        memset(exp->_matches,0,exp->_nsubexpr * sizeof(SQRexMatch));\n    }\n    else{\n        sqstd_rex_free(exp);\n        return NULL;\n    }\n    return exp;\n}\n\nvoid sqstd_rex_free(SQRex *exp)\n{\n    if(exp) {\n        if(exp->_nodes) sq_free(exp->_nodes,exp->_nallocated * sizeof(SQRexNode));\n        if(exp->_jmpbuf) sq_free(exp->_jmpbuf,sizeof(jmp_buf));\n        if(exp->_matches) sq_free(exp->_matches,exp->_nsubexpr * sizeof(SQRexMatch));\n        sq_free(exp,sizeof(SQRex));\n    }\n}\n\nSQBool sqstd_rex_match(SQRex* exp,const SQChar* text)\n{\n    const SQChar* res = NULL;\n    exp->_bol = text;\n    exp->_eol = text + scstrlen(text);\n    exp->_currsubexp = 0;\n    res = sqstd_rex_matchnode(exp,exp->_nodes,text,NULL);\n    if(res == NULL || res != exp->_eol)\n        return SQFalse;\n    return SQTrue;\n}\n\nSQBool sqstd_rex_searchrange(SQRex* exp,const SQChar* text_begin,const SQChar* text_end,const SQChar** out_begin, const SQChar** out_end)\n{\n    const SQChar *cur = NULL;\n    SQInteger node = exp->_first;\n    if(text_begin >= text_end) return SQFalse;\n    exp->_bol = text_begin;\n    exp->_eol = text_end;\n    do {\n        cur = text_begin;\n        while(node != -1) {\n            exp->_currsubexp = 0;\n            cur = sqstd_rex_matchnode(exp,&exp->_nodes[node],cur,NULL);\n            if(!cur)\n                break;\n            node = exp->_nodes[node].next;\n        }\n        text_begin++;\n    } while(cur == NULL && text_begin != text_end);\n\n    if(cur == NULL)\n        return SQFalse;\n\n    --text_begin;\n\n    if(out_begin) *out_begin = text_begin;\n    if(out_end) *out_end = cur;\n    return SQTrue;\n}\n\nSQBool sqstd_rex_search(SQRex* exp,const SQChar* text, const SQChar** out_begin, const SQChar** out_end)\n{\n    return sqstd_rex_searchrange(exp,text,text + scstrlen(text),out_begin,out_end);\n}\n\nSQInteger sqstd_rex_getsubexpcount(SQRex* exp)\n{\n    return exp->_nsubexpr;\n}\n\nSQBool sqstd_rex_getsubexp(SQRex* exp, SQInteger n, SQRexMatch *subexp)\n{\n    if( n<0 || n >= exp->_nsubexpr) return SQFalse;\n    *subexp = exp->_matches[n];\n    return SQTrue;\n}\n\n"
  },
  {
    "path": "extlibs/squirrel/sqstdlib/sqstdstream.cpp",
    "content": "/* see copyright notice in squirrel.h */\n#include <new>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <squirrel.h>\n#include <sqstdio.h>\n#include <sqstdblob.h>\n#include \"sqstdstream.h\"\n#include \"sqstdblobimpl.h\"\n\n#define SETUP_STREAM(v) \\\n    SQStream *self = NULL; \\\n    if(SQ_FAILED(sq_getinstanceup(v,1,(SQUserPointer*)&self,(SQUserPointer)((SQUnsignedInteger)SQSTD_STREAM_TYPE_TAG)))) \\\n        return sq_throwerror(v,_SC(\"invalid type tag\")); \\\n    if(!self || !self->IsValid())  \\\n        return sq_throwerror(v,_SC(\"the stream is invalid\"));\n\nSQInteger _stream_readblob(HSQUIRRELVM v)\n{\n    SETUP_STREAM(v);\n    SQUserPointer data,blobp;\n    SQInteger size,res;\n    sq_getinteger(v,2,&size);\n    if(size > self->Len()) {\n        size = self->Len();\n    }\n    data = sq_getscratchpad(v,size);\n    res = self->Read(data,size);\n    if(res <= 0)\n        return sq_throwerror(v,_SC(\"no data left to read\"));\n    blobp = sqstd_createblob(v,res);\n    memcpy(blobp,data,res);\n    return 1;\n}\n\n#define SAFE_READN(ptr,len) { \\\n    if(self->Read(ptr,len) != len) return sq_throwerror(v,_SC(\"io error\")); \\\n    }\nSQInteger _stream_readn(HSQUIRRELVM v)\n{\n    SETUP_STREAM(v);\n    SQInteger format;\n    sq_getinteger(v, 2, &format);\n    switch(format) {\n    case 'l': {\n        SQInteger i;\n        SAFE_READN(&i, sizeof(i));\n        sq_pushinteger(v, i);\n              }\n        break;\n    case 'i': {\n        SQInt32 i;\n        SAFE_READN(&i, sizeof(i));\n        sq_pushinteger(v, i);\n              }\n        break;\n    case 's': {\n        short s;\n        SAFE_READN(&s, sizeof(short));\n        sq_pushinteger(v, s);\n              }\n        break;\n    case 'w': {\n        unsigned short w;\n        SAFE_READN(&w, sizeof(unsigned short));\n        sq_pushinteger(v, w);\n              }\n        break;\n    case 'c': {\n        char c;\n        SAFE_READN(&c, sizeof(char));\n        sq_pushinteger(v, c);\n              }\n        break;\n    case 'b': {\n        unsigned char c;\n        SAFE_READN(&c, sizeof(unsigned char));\n        sq_pushinteger(v, c);\n              }\n        break;\n    case 'f': {\n        float f;\n        SAFE_READN(&f, sizeof(float));\n        sq_pushfloat(v, f);\n              }\n        break;\n    case 'd': {\n        double d;\n        SAFE_READN(&d, sizeof(double));\n        sq_pushfloat(v, (SQFloat)d);\n              }\n        break;\n    default:\n        return sq_throwerror(v, _SC(\"invalid format\"));\n    }\n    return 1;\n}\n\nSQInteger _stream_writeblob(HSQUIRRELVM v)\n{\n    SQUserPointer data;\n    SQInteger size;\n    SETUP_STREAM(v);\n    if(SQ_FAILED(sqstd_getblob(v,2,&data)))\n        return sq_throwerror(v,_SC(\"invalid parameter\"));\n    size = sqstd_getblobsize(v,2);\n    if(self->Write(data,size) != size)\n        return sq_throwerror(v,_SC(\"io error\"));\n    sq_pushinteger(v,size);\n    return 1;\n}\n\nSQInteger _stream_writen(HSQUIRRELVM v)\n{\n    SETUP_STREAM(v);\n    SQInteger format, ti;\n    SQFloat tf;\n    sq_getinteger(v, 3, &format);\n    switch(format) {\n    case 'l': {\n        SQInteger i;\n        sq_getinteger(v, 2, &ti);\n        i = ti;\n        self->Write(&i, sizeof(SQInteger));\n              }\n        break;\n    case 'i': {\n        SQInt32 i;\n        sq_getinteger(v, 2, &ti);\n        i = (SQInt32)ti;\n        self->Write(&i, sizeof(SQInt32));\n              }\n        break;\n    case 's': {\n        short s;\n        sq_getinteger(v, 2, &ti);\n        s = (short)ti;\n        self->Write(&s, sizeof(short));\n              }\n        break;\n    case 'w': {\n        unsigned short w;\n        sq_getinteger(v, 2, &ti);\n        w = (unsigned short)ti;\n        self->Write(&w, sizeof(unsigned short));\n              }\n        break;\n    case 'c': {\n        char c;\n        sq_getinteger(v, 2, &ti);\n        c = (char)ti;\n        self->Write(&c, sizeof(char));\n                  }\n        break;\n    case 'b': {\n        unsigned char b;\n        sq_getinteger(v, 2, &ti);\n        b = (unsigned char)ti;\n        self->Write(&b, sizeof(unsigned char));\n              }\n        break;\n    case 'f': {\n        float f;\n        sq_getfloat(v, 2, &tf);\n        f = (float)tf;\n        self->Write(&f, sizeof(float));\n              }\n        break;\n    case 'd': {\n        double d;\n        sq_getfloat(v, 2, &tf);\n        d = tf;\n        self->Write(&d, sizeof(double));\n              }\n        break;\n    default:\n        return sq_throwerror(v, _SC(\"invalid format\"));\n    }\n    return 0;\n}\n\nSQInteger _stream_seek(HSQUIRRELVM v)\n{\n    SETUP_STREAM(v);\n    SQInteger offset, origin = SQ_SEEK_SET;\n    sq_getinteger(v, 2, &offset);\n    if(sq_gettop(v) > 2) {\n        SQInteger t;\n        sq_getinteger(v, 3, &t);\n        switch(t) {\n            case 'b': origin = SQ_SEEK_SET; break;\n            case 'c': origin = SQ_SEEK_CUR; break;\n            case 'e': origin = SQ_SEEK_END; break;\n            default: return sq_throwerror(v,_SC(\"invalid origin\"));\n        }\n    }\n    sq_pushinteger(v, self->Seek(offset, origin));\n    return 1;\n}\n\nSQInteger _stream_tell(HSQUIRRELVM v)\n{\n    SETUP_STREAM(v);\n    sq_pushinteger(v, self->Tell());\n    return 1;\n}\n\nSQInteger _stream_len(HSQUIRRELVM v)\n{\n    SETUP_STREAM(v);\n    sq_pushinteger(v, self->Len());\n    return 1;\n}\n\nSQInteger _stream_flush(HSQUIRRELVM v)\n{\n    SETUP_STREAM(v);\n    if(!self->Flush())\n        sq_pushinteger(v, 1);\n    else\n        sq_pushnull(v);\n    return 1;\n}\n\nSQInteger _stream_eos(HSQUIRRELVM v)\n{\n    SETUP_STREAM(v);\n    if(self->EOS())\n        sq_pushinteger(v, 1);\n    else\n        sq_pushnull(v);\n    return 1;\n}\n\n SQInteger _stream__cloned(HSQUIRRELVM v)\n {\n     return sq_throwerror(v,_SC(\"this object cannot be cloned\"));\n }\n\nstatic const SQRegFunction _stream_methods[] = {\n    _DECL_STREAM_FUNC(readblob,2,_SC(\"xn\")),\n    _DECL_STREAM_FUNC(readn,2,_SC(\"xn\")),\n    _DECL_STREAM_FUNC(writeblob,-2,_SC(\"xx\")),\n    _DECL_STREAM_FUNC(writen,3,_SC(\"xnn\")),\n    _DECL_STREAM_FUNC(seek,-2,_SC(\"xnn\")),\n    _DECL_STREAM_FUNC(tell,1,_SC(\"x\")),\n    _DECL_STREAM_FUNC(len,1,_SC(\"x\")),\n    _DECL_STREAM_FUNC(eos,1,_SC(\"x\")),\n    _DECL_STREAM_FUNC(flush,1,_SC(\"x\")),\n    _DECL_STREAM_FUNC(_cloned,0,NULL),\n    {NULL,(SQFUNCTION)0,0,NULL}\n};\n\nvoid init_streamclass(HSQUIRRELVM v)\n{\n    sq_pushregistrytable(v);\n    sq_pushstring(v,_SC(\"std_stream\"),-1);\n    if(SQ_FAILED(sq_get(v,-2))) {\n        sq_pushstring(v,_SC(\"std_stream\"),-1);\n        sq_newclass(v,SQFalse);\n        sq_settypetag(v,-1,(SQUserPointer)((SQUnsignedInteger)SQSTD_STREAM_TYPE_TAG));\n        SQInteger i = 0;\n        while(_stream_methods[i].name != 0) {\n            const SQRegFunction &f = _stream_methods[i];\n            sq_pushstring(v,f.name,-1);\n            sq_newclosure(v,f.f,0);\n            sq_setparamscheck(v,f.nparamscheck,f.typemask);\n            sq_newslot(v,-3,SQFalse);\n            i++;\n        }\n        sq_newslot(v,-3,SQFalse);\n        sq_pushroottable(v);\n        sq_pushstring(v,_SC(\"stream\"),-1);\n        sq_pushstring(v,_SC(\"std_stream\"),-1);\n        sq_get(v,-4);\n        sq_newslot(v,-3,SQFalse);\n        sq_pop(v,1);\n    }\n    else {\n        sq_pop(v,1); //result\n    }\n    sq_pop(v,1);\n}\n\nSQRESULT declare_stream(HSQUIRRELVM v,const SQChar* name,SQUserPointer typetag,const SQChar* reg_name,const SQRegFunction *methods,const SQRegFunction *globals)\n{\n    if(sq_gettype(v,-1) != OT_TABLE)\n        return sq_throwerror(v,_SC(\"table expected\"));\n    SQInteger top = sq_gettop(v);\n    //create delegate\n    init_streamclass(v);\n    sq_pushregistrytable(v);\n    sq_pushstring(v,reg_name,-1);\n    sq_pushstring(v,_SC(\"std_stream\"),-1);\n    if(SQ_SUCCEEDED(sq_get(v,-3))) {\n        sq_newclass(v,SQTrue);\n        sq_settypetag(v,-1,typetag);\n        SQInteger i = 0;\n        while(methods[i].name != 0) {\n            const SQRegFunction &f = methods[i];\n            sq_pushstring(v,f.name,-1);\n            sq_newclosure(v,f.f,0);\n            sq_setparamscheck(v,f.nparamscheck,f.typemask);\n            sq_setnativeclosurename(v,-1,f.name);\n            sq_newslot(v,-3,SQFalse);\n            i++;\n        }\n        sq_newslot(v,-3,SQFalse);\n        sq_pop(v,1);\n\n        i = 0;\n        while(globals[i].name!=0)\n        {\n            const SQRegFunction &f = globals[i];\n            sq_pushstring(v,f.name,-1);\n            sq_newclosure(v,f.f,0);\n            sq_setparamscheck(v,f.nparamscheck,f.typemask);\n            sq_setnativeclosurename(v,-1,f.name);\n            sq_newslot(v,-3,SQFalse);\n            i++;\n        }\n        //register the class in the target table\n        sq_pushstring(v,name,-1);\n        sq_pushregistrytable(v);\n        sq_pushstring(v,reg_name,-1);\n        sq_get(v,-2);\n        sq_remove(v,-2);\n        sq_newslot(v,-3,SQFalse);\n\n        sq_settop(v,top);\n        return SQ_OK;\n    }\n    sq_settop(v,top);\n    return SQ_ERROR;\n}\n"
  },
  {
    "path": "extlibs/squirrel/sqstdlib/sqstdstream.h",
    "content": "/*  see copyright notice in squirrel.h */\n#ifndef _SQSTD_STREAM_H_\n#define _SQSTD_STREAM_H_\n\nSQInteger _stream_readblob(HSQUIRRELVM v);\nSQInteger _stream_readline(HSQUIRRELVM v);\nSQInteger _stream_readn(HSQUIRRELVM v);\nSQInteger _stream_writeblob(HSQUIRRELVM v);\nSQInteger _stream_writen(HSQUIRRELVM v);\nSQInteger _stream_seek(HSQUIRRELVM v);\nSQInteger _stream_tell(HSQUIRRELVM v);\nSQInteger _stream_len(HSQUIRRELVM v);\nSQInteger _stream_eos(HSQUIRRELVM v);\nSQInteger _stream_flush(HSQUIRRELVM v);\n\n#define _DECL_STREAM_FUNC(name,nparams,typecheck) {_SC(#name),_stream_##name,nparams,typecheck}\nSQRESULT declare_stream(HSQUIRRELVM v,const SQChar* name,SQUserPointer typetag,const SQChar* reg_name,const SQRegFunction *methods,const SQRegFunction *globals);\n#endif /*_SQSTD_STREAM_H_*/\n"
  },
  {
    "path": "extlibs/squirrel/sqstdlib/sqstdstring.cpp",
    "content": "/* see copyright notice in squirrel.h */\n#include <squirrel.h>\n#include <sqstdstring.h>\n#include <string.h>\n#include <stdlib.h>\n#include <stdio.h>\n#include <ctype.h>\n#include <assert.h>\n\n#define MAX_FORMAT_LEN  20\n#define MAX_WFORMAT_LEN 3\n#define ADDITIONAL_FORMAT_SPACE (100*sizeof(SQChar))\n\nstatic SQBool isfmtchr(SQChar ch)\n{\n    switch(ch) {\n    case '-': case '+': case ' ': case '#': case '0': return SQTrue;\n    }\n    return SQFalse;\n}\n\nstatic SQInteger validate_format(HSQUIRRELVM v, SQChar *fmt, const SQChar *src, SQInteger n,SQInteger &width)\n{\n    SQChar *dummy;\n    SQChar swidth[MAX_WFORMAT_LEN];\n    SQInteger wc = 0;\n    SQInteger start = n;\n    fmt[0] = '%';\n    while (isfmtchr(src[n])) n++;\n    while (scisdigit(src[n])) {\n        swidth[wc] = src[n];\n        n++;\n        wc++;\n        if(wc>=MAX_WFORMAT_LEN)\n            return sq_throwerror(v,_SC(\"width format too long\"));\n    }\n    swidth[wc] = '\\0';\n    if(wc > 0) {\n        width = scstrtol(swidth,&dummy,10);\n    }\n    else\n        width = 0;\n    if (src[n] == '.') {\n        n++;\n\n        wc = 0;\n        while (scisdigit(src[n])) {\n            swidth[wc] = src[n];\n            n++;\n            wc++;\n            if(wc>=MAX_WFORMAT_LEN)\n                return sq_throwerror(v,_SC(\"precision format too long\"));\n        }\n        swidth[wc] = '\\0';\n        if(wc > 0) {\n            width += scstrtol(swidth,&dummy,10);\n\n        }\n    }\n    if (n-start > MAX_FORMAT_LEN )\n        return sq_throwerror(v,_SC(\"format too long\"));\n    memcpy(&fmt[1],&src[start],((n-start)+1)*sizeof(SQChar));\n    fmt[(n-start)+2] = '\\0';\n    return n;\n}\n\nSQRESULT sqstd_format(HSQUIRRELVM v,SQInteger nformatstringidx,SQInteger *outlen,SQChar **output)\n{\n    const SQChar *format;\n    SQChar *dest;\n    SQChar fmt[MAX_FORMAT_LEN];\n    const SQRESULT res = sq_getstring(v,nformatstringidx,&format);\n    if (SQ_FAILED(res)) {\n        return res; // propagate the error\n    }\n    SQInteger format_size = sq_getsize(v,nformatstringidx);\n    SQInteger allocated = (format_size+2)*sizeof(SQChar);\n    dest = sq_getscratchpad(v,allocated);\n    SQInteger n = 0,i = 0, nparam = nformatstringidx+1, w = 0;\n    //while(format[n] != '\\0')\n    while(n < format_size)\n    {\n        if(format[n] != '%') {\n            assert(i < allocated);\n            dest[i++] = format[n];\n            n++;\n        }\n        else if(format[n+1] == '%') { //handles %%\n                dest[i++] = '%';\n                n += 2;\n        }\n        else {\n            n++;\n            if( nparam > sq_gettop(v) )\n                return sq_throwerror(v,_SC(\"not enough parameters for the given format string\"));\n            n = validate_format(v,fmt,format,n,w);\n            if(n < 0) return -1;\n            SQInteger addlen = 0;\n            SQInteger valtype = 0;\n            const SQChar *ts = NULL;\n            SQInteger ti = 0;\n            SQFloat tf = 0;\n            switch(format[n]) {\n            case 's':\n                if(SQ_FAILED(sq_getstring(v,nparam,&ts)))\n                    return sq_throwerror(v,_SC(\"string expected for the specified format\"));\n                addlen = (sq_getsize(v,nparam)*sizeof(SQChar))+((w+1)*sizeof(SQChar));\n                valtype = 's';\n                break;\n            case 'i': case 'd': case 'o': case 'u':  case 'x':  case 'X':\n#ifdef _SQ64\n                {\n                size_t flen = scstrlen(fmt);\n                SQInteger fpos = flen - 1;\n                SQChar f = fmt[fpos];\n                const SQChar *prec = (const SQChar *)_PRINT_INT_PREC;\n                while(*prec != _SC('\\0')) {\n                    fmt[fpos++] = *prec++;\n                }\n                fmt[fpos++] = f;\n                fmt[fpos++] = _SC('\\0');\n                }\n#endif\n            case 'c':\n                if(SQ_FAILED(sq_getinteger(v,nparam,&ti)))\n                    return sq_throwerror(v,_SC(\"integer expected for the specified format\"));\n                addlen = (ADDITIONAL_FORMAT_SPACE)+((w+1)*sizeof(SQChar));\n                valtype = 'i';\n                break;\n            case 'f': case 'g': case 'G': case 'e':  case 'E':\n                if(SQ_FAILED(sq_getfloat(v,nparam,&tf)))\n                    return sq_throwerror(v,_SC(\"float expected for the specified format\"));\n                addlen = (ADDITIONAL_FORMAT_SPACE)+((w+1)*sizeof(SQChar));\n                valtype = 'f';\n                break;\n            default:\n                return sq_throwerror(v,_SC(\"invalid format\"));\n            }\n            n++;\n            allocated += addlen + sizeof(SQChar);\n            dest = sq_getscratchpad(v,allocated);\n            switch(valtype) {\n            case 's': i += scsprintf(&dest[i],allocated,fmt,ts); break;\n            case 'i': i += scsprintf(&dest[i],allocated,fmt,ti); break;\n            case 'f': i += scsprintf(&dest[i],allocated,fmt,tf); break;\n            };\n            nparam ++;\n        }\n    }\n    *outlen = i;\n    dest[i] = '\\0';\n    *output = dest;\n    return SQ_OK;\n}\n\nstatic SQInteger _string_printf(HSQUIRRELVM v)\n{\n    SQChar *dest = NULL;\n    SQInteger length = 0;\n    if(SQ_FAILED(sqstd_format(v,2,&length,&dest)))\n        return -1;\n\n    SQPRINTFUNCTION printfunc = sq_getprintfunc(v);\n    if(printfunc) printfunc(v,dest);\n\n    return 0;\n}\n\nstatic SQInteger _string_format(HSQUIRRELVM v)\n{\n    SQChar *dest = NULL;\n    SQInteger length = 0;\n    if(SQ_FAILED(sqstd_format(v,2,&length,&dest)))\n        return -1;\n    sq_pushstring(v,dest,length);\n    return 1;\n}\n\nstatic void __strip_l(const SQChar *str,const SQChar **start)\n{\n    const SQChar *t = str;\n    while(((*t) != '\\0') && scisspace(*t)){ t++; }\n    *start = t;\n}\n\nstatic void __strip_r(const SQChar *str,SQInteger len,const SQChar **end)\n{\n    if(len == 0) {\n        *end = str;\n        return;\n    }\n    const SQChar *t = &str[len-1];\n    while(t >= str && scisspace(*t)) { t--; }\n    *end = t + 1;\n}\n\nstatic SQInteger _string_strip(HSQUIRRELVM v)\n{\n    const SQChar *str,*start,*end;\n    sq_getstring(v,2,&str);\n    SQInteger len = sq_getsize(v,2);\n    __strip_l(str,&start);\n    __strip_r(str,len,&end);\n    sq_pushstring(v,start,end - start);\n    return 1;\n}\n\nstatic SQInteger _string_lstrip(HSQUIRRELVM v)\n{\n    const SQChar *str,*start;\n    sq_getstring(v,2,&str);\n    __strip_l(str,&start);\n    sq_pushstring(v,start,-1);\n    return 1;\n}\n\nstatic SQInteger _string_rstrip(HSQUIRRELVM v)\n{\n    const SQChar *str,*end;\n    sq_getstring(v,2,&str);\n    SQInteger len = sq_getsize(v,2);\n    __strip_r(str,len,&end);\n    sq_pushstring(v,str,end - str);\n    return 1;\n}\n\nstatic SQInteger _string_split(HSQUIRRELVM v)\n{\n    const SQChar *str,*seps;\n    SQChar *stemp;\n    sq_getstring(v,2,&str);\n    sq_getstring(v,3,&seps);\n    SQInteger sepsize = sq_getsize(v,3);\n    if(sepsize == 0) return sq_throwerror(v,_SC(\"empty separators string\"));\n    SQInteger memsize = (sq_getsize(v,2)+1)*sizeof(SQChar);\n    stemp = sq_getscratchpad(v,memsize);\n    memcpy(stemp,str,memsize);\n    SQChar *start = stemp;\n    SQChar *end = stemp;\n    sq_newarray(v,0);\n    while(*end != '\\0')\n    {\n        SQChar cur = *end;\n        for(SQInteger i = 0; i < sepsize; i++)\n        {\n            if(cur == seps[i])\n            {\n                *end = 0;\n                sq_pushstring(v,start,-1);\n                sq_arrayappend(v,-2);\n                start = end + 1;\n                break;\n            }\n        }\n        end++;\n    }\n    if(end != start)\n    {\n        sq_pushstring(v,start,-1);\n        sq_arrayappend(v,-2);\n    }\n    return 1;\n}\n\nstatic SQInteger _string_escape(HSQUIRRELVM v)\n{\n    const SQChar *str;\n    SQChar *dest,*resstr;\n    SQInteger size;\n    sq_getstring(v,2,&str);\n    size = sq_getsize(v,2);\n    if(size == 0) {\n        sq_push(v,2);\n        return 1;\n    }\n#ifdef SQUNICODE\n#if WCHAR_SIZE == 2\n    const SQChar *escpat = _SC(\"\\\\x%04x\");\n    const SQInteger maxescsize = 6;\n#else //WCHAR_SIZE == 4\n    const SQChar *escpat = _SC(\"\\\\x%08x\");\n    const SQInteger maxescsize = 10;\n#endif\n#else\n    const SQChar *escpat = _SC(\"\\\\x%02x\");\n    const SQInteger maxescsize = 4;\n#endif\n    SQInteger destcharsize = (size * maxescsize); //assumes every char could be escaped\n    resstr = dest = (SQChar *)sq_getscratchpad(v,destcharsize * sizeof(SQChar));\n    SQChar c;\n    SQChar escch;\n    SQInteger escaped = 0;\n    for(int n = 0; n < size; n++){\n        c = *str++;\n        escch = 0;\n        if(scisprint(c) || c == 0) {\n            switch(c) {\n            case '\\a': escch = 'a'; break;\n            case '\\b': escch = 'b'; break;\n            case '\\t': escch = 't'; break;\n            case '\\n': escch = 'n'; break;\n            case '\\v': escch = 'v'; break;\n            case '\\f': escch = 'f'; break;\n            case '\\r': escch = 'r'; break;\n            case '\\\\': escch = '\\\\'; break;\n            case '\\\"': escch = '\\\"'; break;\n            case '\\'': escch = '\\''; break;\n            case 0: escch = '0'; break;\n            }\n            if(escch) {\n                *dest++ = '\\\\';\n                *dest++ = escch;\n                escaped++;\n            }\n            else {\n                *dest++ = c;\n            }\n        }\n        else {\n\n            dest += scsprintf(dest, destcharsize, escpat, c);\n            escaped++;\n        }\n    }\n\n    if(escaped) {\n        sq_pushstring(v,resstr,dest - resstr);\n    }\n    else {\n        sq_push(v,2); //nothing escaped\n    }\n    return 1;\n}\n\nstatic SQInteger _string_startswith(HSQUIRRELVM v)\n{\n    const SQChar *str,*cmp;\n    sq_getstring(v,2,&str);\n    sq_getstring(v,3,&cmp);\n    SQInteger len = sq_getsize(v,2);\n    SQInteger cmplen = sq_getsize(v,3);\n    SQBool ret = SQFalse;\n    if(cmplen <= len) {\n        ret = memcmp(str,cmp,sq_rsl(cmplen)) == 0 ? SQTrue : SQFalse;\n    }\n    sq_pushbool(v,ret);\n    return 1;\n}\n\nstatic SQInteger _string_endswith(HSQUIRRELVM v)\n{\n    const SQChar *str,*cmp;\n    sq_getstring(v,2,&str);\n    sq_getstring(v,3,&cmp);\n    SQInteger len = sq_getsize(v,2);\n    SQInteger cmplen = sq_getsize(v,3);\n    SQBool ret = SQFalse;\n    if(cmplen <= len) {\n        ret = memcmp(&str[len - cmplen],cmp,sq_rsl(cmplen)) == 0 ? SQTrue : SQFalse;\n    }\n    sq_pushbool(v,ret);\n    return 1;\n}\n\n#define SETUP_REX(v) \\\n    SQRex *self = NULL; \\\n    sq_getinstanceup(v,1,(SQUserPointer *)&self,0);\n\nstatic SQInteger _rexobj_releasehook(SQUserPointer p, SQInteger SQ_UNUSED_ARG(size))\n{\n    SQRex *self = ((SQRex *)p);\n    sqstd_rex_free(self);\n    return 1;\n}\n\nstatic SQInteger _regexp_match(HSQUIRRELVM v)\n{\n    SETUP_REX(v);\n    const SQChar *str;\n    sq_getstring(v,2,&str);\n    if(sqstd_rex_match(self,str) == SQTrue)\n    {\n        sq_pushbool(v,SQTrue);\n        return 1;\n    }\n    sq_pushbool(v,SQFalse);\n    return 1;\n}\n\nstatic void _addrexmatch(HSQUIRRELVM v,const SQChar *str,const SQChar *begin,const SQChar *end)\n{\n    sq_newtable(v);\n    sq_pushstring(v,_SC(\"begin\"),-1);\n    sq_pushinteger(v,begin - str);\n    sq_rawset(v,-3);\n    sq_pushstring(v,_SC(\"end\"),-1);\n    sq_pushinteger(v,end - str);\n    sq_rawset(v,-3);\n}\n\nstatic SQInteger _regexp_search(HSQUIRRELVM v)\n{\n    SETUP_REX(v);\n    const SQChar *str,*begin,*end;\n    SQInteger start = 0;\n    sq_getstring(v,2,&str);\n    if(sq_gettop(v) > 2) sq_getinteger(v,3,&start);\n    if(sqstd_rex_search(self,str+start,&begin,&end) == SQTrue) {\n        _addrexmatch(v,str,begin,end);\n        return 1;\n    }\n    return 0;\n}\n\nstatic SQInteger _regexp_capture(HSQUIRRELVM v)\n{\n    SETUP_REX(v);\n    const SQChar *str,*begin,*end;\n    SQInteger start = 0;\n    sq_getstring(v,2,&str);\n    if(sq_gettop(v) > 2) sq_getinteger(v,3,&start);\n    if(sqstd_rex_search(self,str+start,&begin,&end) == SQTrue) {\n        SQInteger n = sqstd_rex_getsubexpcount(self);\n        SQRexMatch match;\n        sq_newarray(v,0);\n        for(SQInteger i = 0;i < n; i++) {\n            sqstd_rex_getsubexp(self,i,&match);\n            if(match.len > 0)\n                _addrexmatch(v,str,match.begin,match.begin+match.len);\n            else\n                _addrexmatch(v,str,str,str); //empty match\n            sq_arrayappend(v,-2);\n        }\n        return 1;\n    }\n    return 0;\n}\n\nstatic SQInteger _regexp_subexpcount(HSQUIRRELVM v)\n{\n    SETUP_REX(v);\n    sq_pushinteger(v,sqstd_rex_getsubexpcount(self));\n    return 1;\n}\n\nstatic SQInteger _regexp_constructor(HSQUIRRELVM v)\n{\n    const SQChar *error,*pattern;\n    sq_getstring(v,2,&pattern);\n    SQRex *rex = sqstd_rex_compile(pattern,&error);\n    if(!rex) return sq_throwerror(v,error);\n    sq_setinstanceup(v,1,rex);\n    sq_setreleasehook(v,1,_rexobj_releasehook);\n    return 0;\n}\n\nstatic SQInteger _regexp__typeof(HSQUIRRELVM v)\n{\n    sq_pushstring(v,_SC(\"regexp\"),-1);\n    return 1;\n}\n\n#define _DECL_REX_FUNC(name,nparams,pmask) {_SC(#name),_regexp_##name,nparams,pmask}\nstatic const SQRegFunction rexobj_funcs[]={\n    _DECL_REX_FUNC(constructor,2,_SC(\".s\")),\n    _DECL_REX_FUNC(search,-2,_SC(\"xsn\")),\n    _DECL_REX_FUNC(match,2,_SC(\"xs\")),\n    _DECL_REX_FUNC(capture,-2,_SC(\"xsn\")),\n    _DECL_REX_FUNC(subexpcount,1,_SC(\"x\")),\n    _DECL_REX_FUNC(_typeof,1,_SC(\"x\")),\n    {NULL,(SQFUNCTION)0,0,NULL}\n};\n#undef _DECL_REX_FUNC\n\n#define _DECL_FUNC(name,nparams,pmask) {_SC(#name),_string_##name,nparams,pmask}\nstatic const SQRegFunction stringlib_funcs[]={\n    _DECL_FUNC(format,-2,_SC(\".s\")),\n    _DECL_FUNC(printf,-2,_SC(\".s\")),\n    _DECL_FUNC(strip,2,_SC(\".s\")),\n    _DECL_FUNC(lstrip,2,_SC(\".s\")),\n    _DECL_FUNC(rstrip,2,_SC(\".s\")),\n    _DECL_FUNC(split,3,_SC(\".ss\")),\n    _DECL_FUNC(escape,2,_SC(\".s\")),\n    _DECL_FUNC(startswith,3,_SC(\".ss\")),\n    _DECL_FUNC(endswith,3,_SC(\".ss\")),\n    {NULL,(SQFUNCTION)0,0,NULL}\n};\n#undef _DECL_FUNC\n\n\nSQInteger sqstd_register_stringlib(HSQUIRRELVM v)\n{\n    sq_pushstring(v,_SC(\"regexp\"),-1);\n    sq_newclass(v,SQFalse);\n    SQInteger i = 0;\n    while(rexobj_funcs[i].name != 0) {\n        const SQRegFunction &f = rexobj_funcs[i];\n        sq_pushstring(v,f.name,-1);\n        sq_newclosure(v,f.f,0);\n        sq_setparamscheck(v,f.nparamscheck,f.typemask);\n        sq_setnativeclosurename(v,-1,f.name);\n        sq_newslot(v,-3,SQFalse);\n        i++;\n    }\n    sq_newslot(v,-3,SQFalse);\n\n    i = 0;\n    while(stringlib_funcs[i].name!=0)\n    {\n        sq_pushstring(v,stringlib_funcs[i].name,-1);\n        sq_newclosure(v,stringlib_funcs[i].f,0);\n        sq_setparamscheck(v,stringlib_funcs[i].nparamscheck,stringlib_funcs[i].typemask);\n        sq_setnativeclosurename(v,-1,stringlib_funcs[i].name);\n        sq_newslot(v,-3,SQFalse);\n        i++;\n    }\n    return 1;\n}\n"
  },
  {
    "path": "extlibs/squirrel/sqstdlib/sqstdsystem.cpp",
    "content": "/* see copyright notice in squirrel.h */\n#include <squirrel.h>\n#include <time.h>\n#include <stdlib.h>\n#include <stdio.h>\n#include <sqstdsystem.h>\n\n#ifdef SQUNICODE\n#include <wchar.h>\n#define scgetenv _wgetenv\n#define scsystem _wsystem\n#define scasctime _wasctime\n#define scremove _wremove\n#define screname _wrename\n#else\n#define scgetenv getenv\n#define scsystem system\n#define scasctime asctime\n#define scremove remove\n#define screname rename\n#endif\n\nstatic SQInteger _system_getenv(HSQUIRRELVM v)\n{\n    const SQChar *s;\n    if(SQ_SUCCEEDED(sq_getstring(v,2,&s))){\n        sq_pushstring(v,scgetenv(s),-1);\n        return 1;\n    }\n    return 0;\n}\n\n\nstatic SQInteger _system_system(HSQUIRRELVM v)\n{\n    const SQChar *s;\n    if(SQ_SUCCEEDED(sq_getstring(v,2,&s))){\n        sq_pushinteger(v,scsystem(s));\n        return 1;\n    }\n    return sq_throwerror(v,_SC(\"wrong param\"));\n}\n\n\nstatic SQInteger _system_clock(HSQUIRRELVM v)\n{\n    sq_pushfloat(v,((SQFloat)clock())/(SQFloat)CLOCKS_PER_SEC);\n    return 1;\n}\n\nstatic SQInteger _system_time(HSQUIRRELVM v)\n{\n    SQInteger t = (SQInteger)time(NULL);\n    sq_pushinteger(v,t);\n    return 1;\n}\n\nstatic SQInteger _system_remove(HSQUIRRELVM v)\n{\n    const SQChar *s;\n    sq_getstring(v,2,&s);\n    if(scremove(s)==-1)\n        return sq_throwerror(v,_SC(\"remove() failed\"));\n    return 0;\n}\n\nstatic SQInteger _system_rename(HSQUIRRELVM v)\n{\n    const SQChar *oldn,*newn;\n    sq_getstring(v,2,&oldn);\n    sq_getstring(v,3,&newn);\n    if(screname(oldn,newn)==-1)\n        return sq_throwerror(v,_SC(\"rename() failed\"));\n    return 0;\n}\n\nstatic void _set_integer_slot(HSQUIRRELVM v,const SQChar *name,SQInteger val)\n{\n    sq_pushstring(v,name,-1);\n    sq_pushinteger(v,val);\n    sq_rawset(v,-3);\n}\n\nstatic SQInteger _system_date(HSQUIRRELVM v)\n{\n    time_t t;\n    SQInteger it;\n    SQInteger format = 'l';\n    if(sq_gettop(v) > 1) {\n        sq_getinteger(v,2,&it);\n        t = it;\n        if(sq_gettop(v) > 2) {\n            sq_getinteger(v,3,(SQInteger*)&format);\n        }\n    }\n    else {\n        time(&t);\n    }\n    tm *date;\n    if(format == 'u')\n        date = gmtime(&t);\n    else\n        date = localtime(&t);\n    if(!date)\n        return sq_throwerror(v,_SC(\"crt api failure\"));\n    sq_newtable(v);\n    _set_integer_slot(v, _SC(\"sec\"), date->tm_sec);\n    _set_integer_slot(v, _SC(\"min\"), date->tm_min);\n    _set_integer_slot(v, _SC(\"hour\"), date->tm_hour);\n    _set_integer_slot(v, _SC(\"day\"), date->tm_mday);\n    _set_integer_slot(v, _SC(\"month\"), date->tm_mon);\n    _set_integer_slot(v, _SC(\"year\"), date->tm_year+1900);\n    _set_integer_slot(v, _SC(\"wday\"), date->tm_wday);\n    _set_integer_slot(v, _SC(\"yday\"), date->tm_yday);\n    return 1;\n}\n\n\n\n#define _DECL_FUNC(name,nparams,pmask) {_SC(#name),_system_##name,nparams,pmask}\nstatic const SQRegFunction systemlib_funcs[]={\n    _DECL_FUNC(getenv,2,_SC(\".s\")),\n    _DECL_FUNC(system,2,_SC(\".s\")),\n    _DECL_FUNC(clock,0,NULL),\n    _DECL_FUNC(time,1,NULL),\n    _DECL_FUNC(date,-1,_SC(\".nn\")),\n    _DECL_FUNC(remove,2,_SC(\".s\")),\n    _DECL_FUNC(rename,3,_SC(\".ss\")),\n    {NULL,(SQFUNCTION)0,0,NULL}\n};\n#undef _DECL_FUNC\n\nSQInteger sqstd_register_systemlib(HSQUIRRELVM v)\n{\n    SQInteger i=0;\n    while(systemlib_funcs[i].name!=0)\n    {\n        sq_pushstring(v,systemlib_funcs[i].name,-1);\n        sq_newclosure(v,systemlib_funcs[i].f,0);\n        sq_setparamscheck(v,systemlib_funcs[i].nparamscheck,systemlib_funcs[i].typemask);\n        sq_setnativeclosurename(v,-1,systemlib_funcs[i].name);\n        sq_newslot(v,-3,SQFalse);\n        i++;\n    }\n    return 1;\n}\n"
  },
  {
    "path": "extlibs/squirrel/squirrel/CMakeLists.txt",
    "content": "set(SQUIRREL_SRC sqapi.cpp\n                 sqbaselib.cpp\n                 sqclass.cpp\n                 sqcompiler.cpp\n                 sqdebug.cpp\n                 sqfuncstate.cpp\n                 sqlexer.cpp\n                 sqmem.cpp\n                 sqobject.cpp\n                 sqstate.cpp\n                 sqtable.cpp\n                 sqvm.cpp)\n\nif(NOT DISABLE_DYNAMIC)\n  add_library(squirrel SHARED ${SQUIRREL_SRC})\n  if(NOT SQ_DISABLE_INSTALLER)\n    install(TARGETS squirrel RUNTIME DESTINATION ${INSTALL_BIN_DIR}\n                         LIBRARY DESTINATION ${INSTALL_LIB_DIR}\n                         ARCHIVE DESTINATION ${INSTALL_LIB_DIR})\n  endif()\nendif()\n\nif(NOT DISABLE_STATIC)\n  add_library(squirrel_static STATIC ${SQUIRREL_SRC})\n  if(NOT SQ_DISABLE_INSTALLER)\n    install(TARGETS squirrel_static ARCHIVE DESTINATION ${INSTALL_LIB_DIR})\n  endif()\nendif()\n\nif(LONG_OUTPUT_NAMES)\n  if(NOT DISABLE_DYNAMIC)\n    set_target_properties(squirrel PROPERTIES OUTPUT_NAME squirrel3)\n  endif()\n\n  if(NOT DISABLE_STATIC)\n    set_target_properties(squirrel_static PROPERTIES OUTPUT_NAME squirrel3_static)\n  endif()\nendif()\n"
  },
  {
    "path": "extlibs/squirrel/squirrel/Makefile",
    "content": "SQUIRREL= ..\n\n\nCC?= gcc\nOUT?= $(SQUIRREL)/lib/libsquirrel.a\nINCZ?= -I$(SQUIRREL)/include -I. -Iinclude\nDEFS= $(CC_EXTRA_FLAGS)\nLIB=\n\nOBJS= \\\n\tsqapi.o \\\n\tsqbaselib.o \\\n\tsqfuncstate.o \\\n\tsqdebug.o \\\n\tsqlexer.o \\\n\tsqobject.o \\\n\tsqcompiler.o \\\n\tsqstate.o \\\n\tsqtable.o \\\n\tsqmem.o \\\n\tsqvm.o \\\n\tsqclass.o\n\nSRCS= \\\n\tsqapi.cpp \\\n\tsqbaselib.cpp \\\n\tsqfuncstate.cpp \\\n\tsqdebug.cpp \\\n\tsqlexer.cpp \\\n\tsqobject.cpp \\\n\tsqcompiler.cpp \\\n\tsqstate.cpp \\\n\tsqtable.cpp \\\n\tsqmem.cpp \\\n\tsqvm.cpp \\\n\tsqclass.cpp\n\n\n\nsq32:\n\t$(CC) -O2 -fno-exceptions -fno-rtti -Wall -fno-strict-aliasing -c $(SRCS) $(INCZ) $(DEFS)\n\tar rc $(OUT) *.o\n\trm *.o\n\nsqprof:\n\t$(CC) -O2 -pg -fno-exceptions -fno-rtti -pie -gstabs -g3 -Wall -fno-strict-aliasing -c $(SRCS) $(INCZ) $(DEFS)\n\tar rc $(OUT) *.o\n\trm *.o\n\nsq64:\n\t$(CC) -O2 -m64 -D_SQ64 -fno-exceptions -fno-rtti -Wall -fno-strict-aliasing -c $(SRCS) $(INCZ) $(DEFS)\n\tar rc $(OUT) *.o\n\trm *.o\n"
  },
  {
    "path": "extlibs/squirrel/squirrel/sqapi.cpp",
    "content": "/*\n    see copyright notice in squirrel.h\n*/\n#include \"sqpcheader.h\"\n#include \"sqvm.h\"\n#include \"sqstring.h\"\n#include \"sqtable.h\"\n#include \"sqarray.h\"\n#include \"sqfuncproto.h\"\n#include \"sqclosure.h\"\n#include \"squserdata.h\"\n#include \"sqcompiler.h\"\n#include \"sqfuncstate.h\"\n#include \"sqclass.h\"\n\nstatic bool sq_aux_gettypedarg(HSQUIRRELVM v,SQInteger idx,SQObjectType type,SQObjectPtr **o)\n{\n    *o = &stack_get(v,idx);\n    if(sq_type(**o) != type){\n        SQObjectPtr oval = v->PrintObjVal(**o);\n        v->Raise_Error(_SC(\"wrong argument type, expected '%s' got '%.50s'\"),IdType2Name(type),_stringval(oval));\n        return false;\n    }\n    return true;\n}\n\n#define _GETSAFE_OBJ(v,idx,type,o) { if(!sq_aux_gettypedarg(v,idx,type,&o)) return SQ_ERROR; }\n\n#define sq_aux_paramscheck(v,count) \\\n{ \\\n    if(sq_gettop(v) < count){ v->Raise_Error(_SC(\"not enough params in the stack\")); return SQ_ERROR; }\\\n}\n\n\nSQInteger sq_aux_invalidtype(HSQUIRRELVM v,SQObjectType type)\n{\n    SQUnsignedInteger buf_size = 100 *sizeof(SQChar);\n    scsprintf(_ss(v)->GetScratchPad(buf_size), buf_size, _SC(\"unexpected type %s\"), IdType2Name(type));\n    return sq_throwerror(v, _ss(v)->GetScratchPad(-1));\n}\n\nHSQUIRRELVM sq_open(SQInteger initialstacksize)\n{\n    SQSharedState *ss;\n    SQVM *v;\n    sq_new(ss, SQSharedState);\n    ss->Init();\n    v = (SQVM *)SQ_MALLOC(sizeof(SQVM));\n    new (v) SQVM(ss);\n    ss->_root_vm = v;\n    if(v->Init(NULL, initialstacksize)) {\n        return v;\n    } else {\n        sq_delete(v, SQVM);\n        return NULL;\n    }\n    return v;\n}\n\nHSQUIRRELVM sq_newthread(HSQUIRRELVM friendvm, SQInteger initialstacksize)\n{\n    SQSharedState *ss;\n    SQVM *v;\n    ss=_ss(friendvm);\n\n    v= (SQVM *)SQ_MALLOC(sizeof(SQVM));\n    new (v) SQVM(ss);\n\n    if(v->Init(friendvm, initialstacksize)) {\n        friendvm->Push(v);\n        return v;\n    } else {\n        sq_delete(v, SQVM);\n        return NULL;\n    }\n}\n\nSQInteger sq_getvmstate(HSQUIRRELVM v)\n{\n    if(v->_suspended)\n        return SQ_VMSTATE_SUSPENDED;\n    else {\n        if(v->_callsstacksize != 0) return SQ_VMSTATE_RUNNING;\n        else return SQ_VMSTATE_IDLE;\n    }\n}\n\nvoid sq_seterrorhandler(HSQUIRRELVM v)\n{\n    SQObject o = stack_get(v, -1);\n    if(sq_isclosure(o) || sq_isnativeclosure(o) || sq_isnull(o)) {\n        v->_errorhandler = o;\n        v->Pop();\n    }\n}\n\nvoid sq_setnativedebughook(HSQUIRRELVM v,SQDEBUGHOOK hook)\n{\n    v->_debughook_native = hook;\n    v->_debughook_closure.Null();\n    v->_debughook = hook?true:false;\n}\n\nvoid sq_setdebughook(HSQUIRRELVM v)\n{\n    SQObject o = stack_get(v,-1);\n    if(sq_isclosure(o) || sq_isnativeclosure(o) || sq_isnull(o)) {\n        v->_debughook_closure = o;\n        v->_debughook_native = NULL;\n        v->_debughook = !sq_isnull(o);\n        v->Pop();\n    }\n}\n\nvoid sq_close(HSQUIRRELVM v)\n{\n    SQSharedState *ss = _ss(v);\n    _thread(ss->_root_vm)->Finalize();\n    sq_delete(ss, SQSharedState);\n}\n\nSQInteger sq_getversion()\n{\n    return SQUIRREL_VERSION_NUMBER;\n}\n\nSQRESULT sq_compile(HSQUIRRELVM v,SQLEXREADFUNC read,SQUserPointer p,const SQChar *sourcename,SQBool raiseerror)\n{\n    SQObjectPtr o;\n#ifndef NO_COMPILER\n    if(Compile(v, read, p, sourcename, o, raiseerror?true:false, _ss(v)->_debuginfo)) {\n        v->Push(SQClosure::Create(_ss(v), _funcproto(o), _table(v->_roottable)->GetWeakRef(OT_TABLE)));\n        return SQ_OK;\n    }\n    return SQ_ERROR;\n#else\n    return sq_throwerror(v,_SC(\"this is a no compiler build\"));\n#endif\n}\n\nvoid sq_enabledebuginfo(HSQUIRRELVM v, SQBool enable)\n{\n    _ss(v)->_debuginfo = enable?true:false;\n}\n\nvoid sq_notifyallexceptions(HSQUIRRELVM v, SQBool enable)\n{\n    _ss(v)->_notifyallexceptions = enable?true:false;\n}\n\nvoid sq_addref(HSQUIRRELVM v,HSQOBJECT *po)\n{\n    if(!ISREFCOUNTED(sq_type(*po))) return;\n#ifdef NO_GARBAGE_COLLECTOR\n    __AddRef(po->_type,po->_unVal);\n#else\n    _ss(v)->_refs_table.AddRef(*po);\n#endif\n}\n\nSQUnsignedInteger sq_getrefcount(HSQUIRRELVM v,HSQOBJECT *po)\n{\n    if(!ISREFCOUNTED(sq_type(*po))) return 0;\n#ifdef NO_GARBAGE_COLLECTOR\n   return po->_unVal.pRefCounted->_uiRef;\n#else\n   return _ss(v)->_refs_table.GetRefCount(*po);\n#endif\n}\n\nSQBool sq_release(HSQUIRRELVM v,HSQOBJECT *po)\n{\n    if(!ISREFCOUNTED(sq_type(*po))) return SQTrue;\n#ifdef NO_GARBAGE_COLLECTOR\n    bool ret = (po->_unVal.pRefCounted->_uiRef <= 1) ? SQTrue : SQFalse;\n    __Release(po->_type,po->_unVal);\n    return ret; //the ret val doesn't work(and cannot be fixed)\n#else\n    return _ss(v)->_refs_table.Release(*po);\n#endif\n}\n\nSQUnsignedInteger sq_getvmrefcount(HSQUIRRELVM SQ_UNUSED_ARG(v), const HSQOBJECT *po)\n{\n    if (!ISREFCOUNTED(sq_type(*po))) return 0;\n    return po->_unVal.pRefCounted->_uiRef;\n}\n\nconst SQChar *sq_objtostring(const HSQOBJECT *o)\n{\n    if(sq_type(*o) == OT_STRING) {\n        return _stringval(*o);\n    }\n    return NULL;\n}\n\nSQInteger sq_objtointeger(const HSQOBJECT *o)\n{\n    if(sq_isnumeric(*o)) {\n        return tointeger(*o);\n    }\n    return 0;\n}\n\nSQFloat sq_objtofloat(const HSQOBJECT *o)\n{\n    if(sq_isnumeric(*o)) {\n        return tofloat(*o);\n    }\n    return 0;\n}\n\nSQBool sq_objtobool(const HSQOBJECT *o)\n{\n    if(sq_isbool(*o)) {\n        return _integer(*o);\n    }\n    return SQFalse;\n}\n\nSQUserPointer sq_objtouserpointer(const HSQOBJECT *o)\n{\n    if(sq_isuserpointer(*o)) {\n        return _userpointer(*o);\n    }\n    return 0;\n}\n\nvoid sq_pushnull(HSQUIRRELVM v)\n{\n    v->PushNull();\n}\n\nvoid sq_pushstring(HSQUIRRELVM v,const SQChar *s,SQInteger len)\n{\n    if(s)\n        v->Push(SQObjectPtr(SQString::Create(_ss(v), s, len)));\n    else v->PushNull();\n}\n\nvoid sq_pushinteger(HSQUIRRELVM v,SQInteger n)\n{\n    v->Push(n);\n}\n\nvoid sq_pushbool(HSQUIRRELVM v,SQBool b)\n{\n    v->Push(b?true:false);\n}\n\nvoid sq_pushfloat(HSQUIRRELVM v,SQFloat n)\n{\n    v->Push(n);\n}\n\nvoid sq_pushuserpointer(HSQUIRRELVM v,SQUserPointer p)\n{\n    v->Push(p);\n}\n\nvoid sq_pushthread(HSQUIRRELVM v, HSQUIRRELVM thread)\n{\n    v->Push(thread);\n}\n\nSQUserPointer sq_newuserdata(HSQUIRRELVM v,SQUnsignedInteger size)\n{\n    SQUserData *ud = SQUserData::Create(_ss(v), size + SQ_ALIGNMENT);\n    v->Push(ud);\n    return (SQUserPointer)sq_aligning(ud + 1);\n}\n\nvoid sq_newtable(HSQUIRRELVM v)\n{\n    v->Push(SQTable::Create(_ss(v), 0));\n}\n\nvoid sq_newtableex(HSQUIRRELVM v,SQInteger initialcapacity)\n{\n    v->Push(SQTable::Create(_ss(v), initialcapacity));\n}\n\nvoid sq_newarray(HSQUIRRELVM v,SQInteger size)\n{\n    v->Push(SQArray::Create(_ss(v), size));\n}\n\nSQRESULT sq_newclass(HSQUIRRELVM v,SQBool hasbase)\n{\n    SQClass *baseclass = NULL;\n    if(hasbase) {\n        SQObjectPtr &base = stack_get(v,-1);\n        if(sq_type(base) != OT_CLASS)\n            return sq_throwerror(v,_SC(\"invalid base type\"));\n        baseclass = _class(base);\n    }\n    SQClass *newclass = SQClass::Create(_ss(v), baseclass);\n    if(baseclass) v->Pop();\n    v->Push(newclass);\n    return SQ_OK;\n}\n\nSQBool sq_instanceof(HSQUIRRELVM v)\n{\n    SQObjectPtr &inst = stack_get(v,-1);\n    SQObjectPtr &cl = stack_get(v,-2);\n    if(sq_type(inst) != OT_INSTANCE || sq_type(cl) != OT_CLASS)\n        return sq_throwerror(v,_SC(\"invalid param type\"));\n    return _instance(inst)->InstanceOf(_class(cl))?SQTrue:SQFalse;\n}\n\nSQRESULT sq_arrayappend(HSQUIRRELVM v,SQInteger idx)\n{\n    sq_aux_paramscheck(v,2);\n    SQObjectPtr *arr;\n    _GETSAFE_OBJ(v, idx, OT_ARRAY,arr);\n    _array(*arr)->Append(v->GetUp(-1));\n    v->Pop();\n    return SQ_OK;\n}\n\nSQRESULT sq_arraypop(HSQUIRRELVM v,SQInteger idx,SQBool pushval)\n{\n    sq_aux_paramscheck(v, 1);\n    SQObjectPtr *arr;\n    _GETSAFE_OBJ(v, idx, OT_ARRAY,arr);\n    if(_array(*arr)->Size() > 0) {\n        if(pushval != 0){ v->Push(_array(*arr)->Top()); }\n        _array(*arr)->Pop();\n        return SQ_OK;\n    }\n    return sq_throwerror(v, _SC(\"empty array\"));\n}\n\nSQRESULT sq_arrayresize(HSQUIRRELVM v,SQInteger idx,SQInteger newsize)\n{\n    sq_aux_paramscheck(v,1);\n    SQObjectPtr *arr;\n    _GETSAFE_OBJ(v, idx, OT_ARRAY,arr);\n    if(newsize >= 0) {\n        _array(*arr)->Resize(newsize);\n        return SQ_OK;\n    }\n    return sq_throwerror(v,_SC(\"negative size\"));\n}\n\n\nSQRESULT sq_arrayreverse(HSQUIRRELVM v,SQInteger idx)\n{\n    sq_aux_paramscheck(v, 1);\n    SQObjectPtr *o;\n    _GETSAFE_OBJ(v, idx, OT_ARRAY,o);\n    SQArray *arr = _array(*o);\n    if(arr->Size() > 0) {\n        SQObjectPtr t;\n        SQInteger size = arr->Size();\n        SQInteger n = size >> 1; size -= 1;\n        for(SQInteger i = 0; i < n; i++) {\n            t = arr->_values[i];\n            arr->_values[i] = arr->_values[size-i];\n            arr->_values[size-i] = t;\n        }\n        return SQ_OK;\n    }\n    return SQ_OK;\n}\n\nSQRESULT sq_arrayremove(HSQUIRRELVM v,SQInteger idx,SQInteger itemidx)\n{\n    sq_aux_paramscheck(v, 1);\n    SQObjectPtr *arr;\n    _GETSAFE_OBJ(v, idx, OT_ARRAY,arr);\n    return _array(*arr)->Remove(itemidx) ? SQ_OK : sq_throwerror(v,_SC(\"index out of range\"));\n}\n\nSQRESULT sq_arrayinsert(HSQUIRRELVM v,SQInteger idx,SQInteger destpos)\n{\n    sq_aux_paramscheck(v, 1);\n    SQObjectPtr *arr;\n    _GETSAFE_OBJ(v, idx, OT_ARRAY,arr);\n    SQRESULT ret = _array(*arr)->Insert(destpos, v->GetUp(-1)) ? SQ_OK : sq_throwerror(v,_SC(\"index out of range\"));\n    v->Pop();\n    return ret;\n}\n\nvoid sq_newclosure(HSQUIRRELVM v,SQFUNCTION func,SQUnsignedInteger nfreevars)\n{\n    SQNativeClosure *nc = SQNativeClosure::Create(_ss(v), func,nfreevars);\n    nc->_nparamscheck = 0;\n    for(SQUnsignedInteger i = 0; i < nfreevars; i++) {\n        nc->_outervalues[i] = v->Top();\n        v->Pop();\n    }\n    v->Push(SQObjectPtr(nc));\n}\n\nSQRESULT sq_getclosureinfo(HSQUIRRELVM v,SQInteger idx,SQInteger *nparams,SQInteger *nfreevars)\n{\n    SQObject o = stack_get(v, idx);\n    if(sq_type(o) == OT_CLOSURE) {\n        SQClosure *c = _closure(o);\n        SQFunctionProto *proto = c->_function;\n        *nparams = proto->_nparameters;\n        *nfreevars = proto->_noutervalues;\n        return SQ_OK;\n    }\n    else if(sq_type(o) == OT_NATIVECLOSURE)\n    {\n        SQNativeClosure *c = _nativeclosure(o);\n        *nparams = c->_nparamscheck;\n        *nfreevars = (SQInteger)c->_noutervalues;\n        return SQ_OK;\n    }\n    return sq_throwerror(v,_SC(\"the object is not a closure\"));\n}\n\nSQRESULT sq_setnativeclosurename(HSQUIRRELVM v,SQInteger idx,const SQChar *name)\n{\n    SQObject o = stack_get(v, idx);\n    if(sq_isnativeclosure(o)) {\n        SQNativeClosure *nc = _nativeclosure(o);\n        nc->_name = SQString::Create(_ss(v),name);\n        return SQ_OK;\n    }\n    return sq_throwerror(v,_SC(\"the object is not a nativeclosure\"));\n}\n\nSQRESULT sq_setparamscheck(HSQUIRRELVM v,SQInteger nparamscheck,const SQChar *typemask)\n{\n    SQObject o = stack_get(v, -1);\n    if(!sq_isnativeclosure(o))\n        return sq_throwerror(v, _SC(\"native closure expected\"));\n    SQNativeClosure *nc = _nativeclosure(o);\n    nc->_nparamscheck = nparamscheck;\n    if(typemask) {\n        SQIntVec res;\n        if(!CompileTypemask(res, typemask))\n            return sq_throwerror(v, _SC(\"invalid typemask\"));\n        nc->_typecheck.copy(res);\n    }\n    else {\n        nc->_typecheck.resize(0);\n    }\n    if(nparamscheck == SQ_MATCHTYPEMASKSTRING) {\n        nc->_nparamscheck = nc->_typecheck.size();\n    }\n    return SQ_OK;\n}\n\nSQRESULT sq_bindenv(HSQUIRRELVM v,SQInteger idx)\n{\n    SQObjectPtr &o = stack_get(v,idx);\n    if(!sq_isnativeclosure(o) &&\n        !sq_isclosure(o))\n        return sq_throwerror(v,_SC(\"the target is not a closure\"));\n    SQObjectPtr &env = stack_get(v,-1);\n    if(!sq_istable(env) &&\n        !sq_isarray(env) &&\n        !sq_isclass(env) &&\n        !sq_isinstance(env))\n        return sq_throwerror(v,_SC(\"invalid environment\"));\n    SQWeakRef *w = _refcounted(env)->GetWeakRef(sq_type(env));\n    SQObjectPtr ret;\n    if(sq_isclosure(o)) {\n        SQClosure *c = _closure(o)->Clone();\n        __ObjRelease(c->_env);\n        c->_env = w;\n        __ObjAddRef(c->_env);\n        if(_closure(o)->_base) {\n            c->_base = _closure(o)->_base;\n            __ObjAddRef(c->_base);\n        }\n        ret = c;\n    }\n    else { //then must be a native closure\n        SQNativeClosure *c = _nativeclosure(o)->Clone();\n        __ObjRelease(c->_env);\n        c->_env = w;\n        __ObjAddRef(c->_env);\n        ret = c;\n    }\n    v->Pop();\n    v->Push(ret);\n    return SQ_OK;\n}\n\nSQRESULT sq_getclosurename(HSQUIRRELVM v,SQInteger idx)\n{\n    SQObjectPtr &o = stack_get(v,idx);\n    if(!sq_isnativeclosure(o) &&\n        !sq_isclosure(o))\n        return sq_throwerror(v,_SC(\"the target is not a closure\"));\n    if(sq_isnativeclosure(o))\n    {\n        v->Push(_nativeclosure(o)->_name);\n    }\n    else { //closure\n        v->Push(_closure(o)->_function->_name);\n    }\n    return SQ_OK;\n}\n\nSQRESULT sq_setclosureroot(HSQUIRRELVM v,SQInteger idx)\n{\n    SQObjectPtr &c = stack_get(v,idx);\n    SQObject o = stack_get(v, -1);\n    if(!sq_isclosure(c)) return sq_throwerror(v, _SC(\"closure expected\"));\n    if(sq_istable(o)) {\n        _closure(c)->SetRoot(_table(o)->GetWeakRef(OT_TABLE));\n        v->Pop();\n        return SQ_OK;\n    }\n    return sq_throwerror(v, _SC(\"invalid type\"));\n}\n\nSQRESULT sq_getclosureroot(HSQUIRRELVM v,SQInteger idx)\n{\n    SQObjectPtr &c = stack_get(v,idx);\n    if(!sq_isclosure(c)) return sq_throwerror(v, _SC(\"closure expected\"));\n    v->Push(_closure(c)->_root->_obj);\n    return SQ_OK;\n}\n\nSQRESULT sq_clear(HSQUIRRELVM v,SQInteger idx)\n{\n    SQObject &o=stack_get(v,idx);\n    switch(sq_type(o)) {\n        case OT_TABLE: _table(o)->Clear();  break;\n        case OT_ARRAY: _array(o)->Resize(0); break;\n        default:\n            return sq_throwerror(v, _SC(\"clear only works on table and array\"));\n        break;\n\n    }\n    return SQ_OK;\n}\n\nvoid sq_pushroottable(HSQUIRRELVM v)\n{\n    v->Push(v->_roottable);\n}\n\nvoid sq_pushregistrytable(HSQUIRRELVM v)\n{\n    v->Push(_ss(v)->_registry);\n}\n\nvoid sq_pushconsttable(HSQUIRRELVM v)\n{\n    v->Push(_ss(v)->_consts);\n}\n\nSQRESULT sq_setroottable(HSQUIRRELVM v)\n{\n    SQObject o = stack_get(v, -1);\n    if(sq_istable(o) || sq_isnull(o)) {\n        v->_roottable = o;\n        v->Pop();\n        return SQ_OK;\n    }\n    return sq_throwerror(v, _SC(\"invalid type\"));\n}\n\nSQRESULT sq_setconsttable(HSQUIRRELVM v)\n{\n    SQObject o = stack_get(v, -1);\n    if(sq_istable(o)) {\n        _ss(v)->_consts = o;\n        v->Pop();\n        return SQ_OK;\n    }\n    return sq_throwerror(v, _SC(\"invalid type, expected table\"));\n}\n\nvoid sq_setforeignptr(HSQUIRRELVM v,SQUserPointer p)\n{\n    v->_foreignptr = p;\n}\n\nSQUserPointer sq_getforeignptr(HSQUIRRELVM v)\n{\n    return v->_foreignptr;\n}\n\nvoid sq_setsharedforeignptr(HSQUIRRELVM v,SQUserPointer p)\n{\n    _ss(v)->_foreignptr = p;\n}\n\nSQUserPointer sq_getsharedforeignptr(HSQUIRRELVM v)\n{\n    return _ss(v)->_foreignptr;\n}\n\nvoid sq_setvmreleasehook(HSQUIRRELVM v,SQRELEASEHOOK hook)\n{\n    v->_releasehook = hook;\n}\n\nSQRELEASEHOOK sq_getvmreleasehook(HSQUIRRELVM v)\n{\n    return v->_releasehook;\n}\n\nvoid sq_setsharedreleasehook(HSQUIRRELVM v,SQRELEASEHOOK hook)\n{\n    _ss(v)->_releasehook = hook;\n}\n\nSQRELEASEHOOK sq_getsharedreleasehook(HSQUIRRELVM v)\n{\n    return _ss(v)->_releasehook;\n}\n\nvoid sq_push(HSQUIRRELVM v,SQInteger idx)\n{\n    v->Push(stack_get(v, idx));\n}\n\nSQObjectType sq_gettype(HSQUIRRELVM v,SQInteger idx)\n{\n    return sq_type(stack_get(v, idx));\n}\n\nSQRESULT sq_typeof(HSQUIRRELVM v,SQInteger idx)\n{\n    SQObjectPtr &o = stack_get(v, idx);\n    SQObjectPtr res;\n    if(!v->TypeOf(o,res)) {\n        return SQ_ERROR;\n    }\n    v->Push(res);\n    return SQ_OK;\n}\n\nSQRESULT sq_tostring(HSQUIRRELVM v,SQInteger idx)\n{\n    SQObjectPtr &o = stack_get(v, idx);\n    SQObjectPtr res;\n    if(!v->ToString(o,res)) {\n        return SQ_ERROR;\n    }\n    v->Push(res);\n    return SQ_OK;\n}\n\nvoid sq_tobool(HSQUIRRELVM v, SQInteger idx, SQBool *b)\n{\n    SQObjectPtr &o = stack_get(v, idx);\n    *b = SQVM::IsFalse(o)?SQFalse:SQTrue;\n}\n\nSQRESULT sq_getinteger(HSQUIRRELVM v,SQInteger idx,SQInteger *i)\n{\n    SQObjectPtr &o = stack_get(v, idx);\n    if(sq_isnumeric(o)) {\n        *i = tointeger(o);\n        return SQ_OK;\n    }\n    if(sq_isbool(o)) {\n        *i = SQVM::IsFalse(o)?SQFalse:SQTrue;\n        return SQ_OK;\n    }\n  if(sq_isnull(o)) {\n    *i = SQFalse;\n    return SQ_OK;\n  }\n    return SQ_ERROR;\n}\n\nSQRESULT sq_getfloat(HSQUIRRELVM v,SQInteger idx,SQFloat *f)\n{\n    SQObjectPtr &o = stack_get(v, idx);\n    if(sq_isnumeric(o)) {\n        *f = tofloat(o);\n        return SQ_OK;\n    }\n    return SQ_ERROR;\n}\n\nSQRESULT sq_getbool(HSQUIRRELVM v,SQInteger idx,SQBool *b)\n{\n    SQObjectPtr &o = stack_get(v, idx);\n    if(sq_isbool(o)) {\n        *b = _integer(o);\n        return SQ_OK;\n    }\n    return SQ_ERROR;\n}\n\nSQRESULT sq_getstringandsize(HSQUIRRELVM v,SQInteger idx,const SQChar **c,SQInteger *size)\n{\n    SQObjectPtr *o = NULL;\n    _GETSAFE_OBJ(v, idx, OT_STRING,o);\n    *c = _stringval(*o);\n    *size = _string(*o)->_len;\n    return SQ_OK;\n}\n\nSQRESULT sq_getstring(HSQUIRRELVM v,SQInteger idx,const SQChar **c)\n{\n    SQObjectPtr *o = NULL;\n    _GETSAFE_OBJ(v, idx, OT_STRING,o);\n    *c = _stringval(*o);\n    return SQ_OK;\n}\n\nSQRESULT sq_getthread(HSQUIRRELVM v,SQInteger idx,HSQUIRRELVM *thread)\n{\n    SQObjectPtr *o = NULL;\n    _GETSAFE_OBJ(v, idx, OT_THREAD,o);\n    *thread = _thread(*o);\n    return SQ_OK;\n}\n\nSQRESULT sq_clone(HSQUIRRELVM v,SQInteger idx)\n{\n    SQObjectPtr &o = stack_get(v,idx);\n    v->PushNull();\n    if(!v->Clone(o, stack_get(v, -1))){\n        v->Pop();\n        return SQ_ERROR;\n    }\n    return SQ_OK;\n}\n\nSQInteger sq_getsize(HSQUIRRELVM v, SQInteger idx)\n{\n    SQObjectPtr &o = stack_get(v, idx);\n    SQObjectType type = sq_type(o);\n    switch(type) {\n    case OT_STRING:     return _string(o)->_len;\n    case OT_TABLE:      return _table(o)->CountUsed();\n    case OT_ARRAY:      return _array(o)->Size();\n    case OT_USERDATA:   return _userdata(o)->_size;\n    case OT_INSTANCE:   return _instance(o)->_class->_udsize;\n    case OT_CLASS:      return _class(o)->_udsize;\n    default:\n        return sq_aux_invalidtype(v, type);\n    }\n}\n\nSQHash sq_gethash(HSQUIRRELVM v, SQInteger idx)\n{\n    SQObjectPtr &o = stack_get(v, idx);\n    return HashObj(o);\n}\n\nSQRESULT sq_getuserdata(HSQUIRRELVM v,SQInteger idx,SQUserPointer *p,SQUserPointer *typetag)\n{\n    SQObjectPtr *o = NULL;\n    _GETSAFE_OBJ(v, idx, OT_USERDATA,o);\n    (*p) = _userdataval(*o);\n    if(typetag) *typetag = _userdata(*o)->_typetag;\n    return SQ_OK;\n}\n\nSQRESULT sq_settypetag(HSQUIRRELVM v,SQInteger idx,SQUserPointer typetag)\n{\n    SQObjectPtr &o = stack_get(v,idx);\n    switch(sq_type(o)) {\n        case OT_USERDATA:   _userdata(o)->_typetag = typetag;   break;\n        case OT_CLASS:      _class(o)->_typetag = typetag;      break;\n        default:            return sq_throwerror(v,_SC(\"invalid object type\"));\n    }\n    return SQ_OK;\n}\n\nSQRESULT sq_getobjtypetag(const HSQOBJECT *o,SQUserPointer * typetag)\n{\n  switch(sq_type(*o)) {\n    case OT_INSTANCE: *typetag = _instance(*o)->_class->_typetag; break;\n    case OT_USERDATA: *typetag = _userdata(*o)->_typetag; break;\n    case OT_CLASS:    *typetag = _class(*o)->_typetag; break;\n    default: return SQ_ERROR;\n  }\n  return SQ_OK;\n}\n\nSQRESULT sq_gettypetag(HSQUIRRELVM v,SQInteger idx,SQUserPointer *typetag)\n{\n    SQObjectPtr &o = stack_get(v,idx);\n    if (SQ_FAILED(sq_getobjtypetag(&o, typetag)))\n        return SQ_ERROR;// this is not an error it should be a bool but would break backward compatibility\n    return SQ_OK;\n}\n\nSQRESULT sq_getuserpointer(HSQUIRRELVM v, SQInteger idx, SQUserPointer *p)\n{\n    SQObjectPtr *o = NULL;\n    _GETSAFE_OBJ(v, idx, OT_USERPOINTER,o);\n    (*p) = _userpointer(*o);\n    return SQ_OK;\n}\n\nSQRESULT sq_setinstanceup(HSQUIRRELVM v, SQInteger idx, SQUserPointer p)\n{\n    SQObjectPtr &o = stack_get(v,idx);\n    if(sq_type(o) != OT_INSTANCE) return sq_throwerror(v,_SC(\"the object is not a class instance\"));\n    _instance(o)->_userpointer = p;\n    return SQ_OK;\n}\n\nSQRESULT sq_setclassudsize(HSQUIRRELVM v, SQInteger idx, SQInteger udsize)\n{\n    SQObjectPtr &o = stack_get(v,idx);\n    if(sq_type(o) != OT_CLASS) return sq_throwerror(v,_SC(\"the object is not a class\"));\n    if(_class(o)->_locked) return sq_throwerror(v,_SC(\"the class is locked\"));\n    _class(o)->_udsize = udsize;\n    return SQ_OK;\n}\n\n\nSQRESULT sq_getinstanceup(HSQUIRRELVM v, SQInteger idx, SQUserPointer *p,SQUserPointer typetag)\n{\n    SQObjectPtr &o = stack_get(v,idx);\n    if(sq_type(o) != OT_INSTANCE) return sq_throwerror(v,_SC(\"the object is not a class instance\"));\n    (*p) = _instance(o)->_userpointer;\n    if(typetag != 0) {\n        SQClass *cl = _instance(o)->_class;\n        do{\n            if(cl->_typetag == typetag)\n                return SQ_OK;\n            cl = cl->_base;\n        }while(cl != NULL);\n        return sq_throwerror(v,_SC(\"invalid type tag\"));\n    }\n    return SQ_OK;\n}\n\nSQInteger sq_gettop(HSQUIRRELVM v)\n{\n    return (v->_top) - v->_stackbase;\n}\n\nvoid sq_settop(HSQUIRRELVM v, SQInteger newtop)\n{\n    SQInteger top = sq_gettop(v);\n    if(top > newtop)\n        sq_pop(v, top - newtop);\n    else\n        while(top++ < newtop) sq_pushnull(v);\n}\n\nvoid sq_pop(HSQUIRRELVM v, SQInteger nelemstopop)\n{\n    assert(v->_top >= nelemstopop);\n    v->Pop(nelemstopop);\n}\n\nvoid sq_poptop(HSQUIRRELVM v)\n{\n    assert(v->_top >= 1);\n    v->Pop();\n}\n\n\nvoid sq_remove(HSQUIRRELVM v, SQInteger idx)\n{\n    v->Remove(idx);\n}\n\nSQInteger sq_cmp(HSQUIRRELVM v)\n{\n    SQInteger res;\n    v->ObjCmp(stack_get(v, -1), stack_get(v, -2),res);\n    return res;\n}\n\nSQRESULT sq_newslot(HSQUIRRELVM v, SQInteger idx, SQBool bstatic)\n{\n    sq_aux_paramscheck(v, 3);\n    SQObjectPtr &self = stack_get(v, idx);\n    if(sq_type(self) == OT_TABLE || sq_type(self) == OT_CLASS) {\n        SQObjectPtr &key = v->GetUp(-2);\n        if(sq_type(key) == OT_NULL) return sq_throwerror(v, _SC(\"null is not a valid key\"));\n        v->NewSlot(self, key, v->GetUp(-1),bstatic?true:false);\n        v->Pop(2);\n    }\n    return SQ_OK;\n}\n\nSQRESULT sq_deleteslot(HSQUIRRELVM v,SQInteger idx,SQBool pushval)\n{\n    sq_aux_paramscheck(v, 2);\n    SQObjectPtr *self;\n    _GETSAFE_OBJ(v, idx, OT_TABLE,self);\n    SQObjectPtr &key = v->GetUp(-1);\n    if(sq_type(key) == OT_NULL) return sq_throwerror(v, _SC(\"null is not a valid key\"));\n    SQObjectPtr res;\n    if(!v->DeleteSlot(*self, key, res)){\n        v->Pop();\n        return SQ_ERROR;\n    }\n    if(pushval) v->GetUp(-1) = res;\n    else v->Pop();\n    return SQ_OK;\n}\n\nSQRESULT sq_set(HSQUIRRELVM v,SQInteger idx)\n{\n    SQObjectPtr &self = stack_get(v, idx);\n    if(v->Set(self, v->GetUp(-2), v->GetUp(-1),DONT_FALL_BACK)) {\n        v->Pop(2);\n        return SQ_OK;\n    }\n    return SQ_ERROR;\n}\n\nSQRESULT sq_rawset(HSQUIRRELVM v,SQInteger idx)\n{\n    SQObjectPtr &self = stack_get(v, idx);\n    SQObjectPtr &key = v->GetUp(-2);\n    if(sq_type(key) == OT_NULL) {\n        v->Pop(2);\n        return sq_throwerror(v, _SC(\"null key\"));\n    }\n    switch(sq_type(self)) {\n    case OT_TABLE:\n        _table(self)->NewSlot(key, v->GetUp(-1));\n        v->Pop(2);\n        return SQ_OK;\n    break;\n    case OT_CLASS:\n        _class(self)->NewSlot(_ss(v), key, v->GetUp(-1),false);\n        v->Pop(2);\n        return SQ_OK;\n    break;\n    case OT_INSTANCE:\n        if(_instance(self)->Set(key, v->GetUp(-1))) {\n            v->Pop(2);\n            return SQ_OK;\n        }\n    break;\n    case OT_ARRAY:\n        if(v->Set(self, key, v->GetUp(-1),false)) {\n            v->Pop(2);\n            return SQ_OK;\n        }\n    break;\n    default:\n        v->Pop(2);\n        return sq_throwerror(v, _SC(\"rawset works only on array/table/class and instance\"));\n    }\n    v->Raise_IdxError(v->GetUp(-2));return SQ_ERROR;\n}\n\nSQRESULT sq_newmember(HSQUIRRELVM v,SQInteger idx,SQBool bstatic)\n{\n    SQObjectPtr &self = stack_get(v, idx);\n    if(sq_type(self) != OT_CLASS) return sq_throwerror(v, _SC(\"new member only works with classes\"));\n    SQObjectPtr &key = v->GetUp(-3);\n    if(sq_type(key) == OT_NULL) return sq_throwerror(v, _SC(\"null key\"));\n    if(!v->NewSlotA(self,key,v->GetUp(-2),v->GetUp(-1),bstatic?true:false,false)) {\n        v->Pop(3);\n        return SQ_ERROR;\n    }\n    v->Pop(3);\n    return SQ_OK;\n}\n\nSQRESULT sq_rawnewmember(HSQUIRRELVM v,SQInteger idx,SQBool bstatic)\n{\n    SQObjectPtr &self = stack_get(v, idx);\n    if(sq_type(self) != OT_CLASS) return sq_throwerror(v, _SC(\"new member only works with classes\"));\n    SQObjectPtr &key = v->GetUp(-3);\n    if(sq_type(key) == OT_NULL) return sq_throwerror(v, _SC(\"null key\"));\n    if(!v->NewSlotA(self,key,v->GetUp(-2),v->GetUp(-1),bstatic?true:false,true)) {\n        v->Pop(3);\n        return SQ_ERROR;\n    }\n    v->Pop(3);\n    return SQ_OK;\n}\n\nSQRESULT sq_setdelegate(HSQUIRRELVM v,SQInteger idx)\n{\n    SQObjectPtr &self = stack_get(v, idx);\n    SQObjectPtr &mt = v->GetUp(-1);\n    SQObjectType type = sq_type(self);\n    switch(type) {\n    case OT_TABLE:\n        if(sq_type(mt) == OT_TABLE) {\n            if(!_table(self)->SetDelegate(_table(mt))) {\n                return sq_throwerror(v, _SC(\"delagate cycle\"));\n            }\n            v->Pop();\n        }\n        else if(sq_type(mt)==OT_NULL) {\n            _table(self)->SetDelegate(NULL); v->Pop(); }\n        else return sq_aux_invalidtype(v,type);\n        break;\n    case OT_USERDATA:\n        if(sq_type(mt)==OT_TABLE) {\n            _userdata(self)->SetDelegate(_table(mt)); v->Pop(); }\n        else if(sq_type(mt)==OT_NULL) {\n            _userdata(self)->SetDelegate(NULL); v->Pop(); }\n        else return sq_aux_invalidtype(v, type);\n        break;\n    default:\n            return sq_aux_invalidtype(v, type);\n        break;\n    }\n    return SQ_OK;\n}\n\nSQRESULT sq_rawdeleteslot(HSQUIRRELVM v,SQInteger idx,SQBool pushval)\n{\n    sq_aux_paramscheck(v, 2);\n    SQObjectPtr *self;\n    _GETSAFE_OBJ(v, idx, OT_TABLE,self);\n    SQObjectPtr &key = v->GetUp(-1);\n    SQObjectPtr t;\n    if(_table(*self)->Get(key,t)) {\n        _table(*self)->Remove(key);\n    }\n    if(pushval != 0)\n        v->GetUp(-1) = t;\n    else\n        v->Pop();\n    return SQ_OK;\n}\n\nSQRESULT sq_getdelegate(HSQUIRRELVM v,SQInteger idx)\n{\n    SQObjectPtr &self=stack_get(v,idx);\n    switch(sq_type(self)){\n    case OT_TABLE:\n    case OT_USERDATA:\n        if(!_delegable(self)->_delegate){\n            v->PushNull();\n            break;\n        }\n        v->Push(SQObjectPtr(_delegable(self)->_delegate));\n        break;\n    default: return sq_throwerror(v,_SC(\"wrong type\")); break;\n    }\n    return SQ_OK;\n\n}\n\nSQRESULT sq_get(HSQUIRRELVM v,SQInteger idx)\n{\n    SQObjectPtr &self=stack_get(v,idx);\n    SQObjectPtr &obj = v->GetUp(-1);\n    if(v->Get(self,obj,obj,false,DONT_FALL_BACK))\n        return SQ_OK;\n    v->Pop();\n    return SQ_ERROR;\n}\n\nSQRESULT sq_rawget(HSQUIRRELVM v,SQInteger idx)\n{\n    SQObjectPtr &self=stack_get(v,idx);\n    SQObjectPtr &obj = v->GetUp(-1);\n    switch(sq_type(self)) {\n    case OT_TABLE:\n        if(_table(self)->Get(obj,obj))\n            return SQ_OK;\n        break;\n    case OT_CLASS:\n        if(_class(self)->Get(obj,obj))\n            return SQ_OK;\n        break;\n    case OT_INSTANCE:\n        if(_instance(self)->Get(obj,obj))\n            return SQ_OK;\n        break;\n    case OT_ARRAY:{\n        if(sq_isnumeric(obj)){\n            if(_array(self)->Get(tointeger(obj),obj)) {\n                return SQ_OK;\n            }\n        }\n        else {\n            v->Pop();\n            return sq_throwerror(v,_SC(\"invalid index type for an array\"));\n        }\n                  }\n        break;\n    default:\n        v->Pop();\n        return sq_throwerror(v,_SC(\"rawget works only on array/table/instance and class\"));\n    }\n    v->Pop();\n    return sq_throwerror(v,_SC(\"the index doesn't exist\"));\n}\n\nSQRESULT sq_getstackobj(HSQUIRRELVM v,SQInteger idx,HSQOBJECT *po)\n{\n    *po=stack_get(v,idx);\n    return SQ_OK;\n}\n\nconst SQChar *sq_getlocal(HSQUIRRELVM v,SQUnsignedInteger level,SQUnsignedInteger idx)\n{\n    SQUnsignedInteger cstksize=v->_callsstacksize;\n    SQUnsignedInteger lvl=(cstksize-level)-1;\n    SQInteger stackbase=v->_stackbase;\n    if(lvl<cstksize){\n        for(SQUnsignedInteger i=0;i<level;i++){\n            SQVM::CallInfo &ci=v->_callsstack[(cstksize-i)-1];\n            stackbase-=ci._prevstkbase;\n        }\n        SQVM::CallInfo &ci=v->_callsstack[lvl];\n        if(sq_type(ci._closure)!=OT_CLOSURE)\n            return NULL;\n        SQClosure *c=_closure(ci._closure);\n        SQFunctionProto *func=c->_function;\n        if(func->_noutervalues > (SQInteger)idx) {\n            v->Push(*_outer(c->_outervalues[idx])->_valptr);\n            return _stringval(func->_outervalues[idx]._name);\n        }\n        idx -= func->_noutervalues;\n        return func->GetLocal(v,stackbase,idx,(SQInteger)(ci._ip-func->_instructions)-1);\n    }\n    return NULL;\n}\n\nvoid sq_pushobject(HSQUIRRELVM v,HSQOBJECT obj)\n{\n    v->Push(SQObjectPtr(obj));\n}\n\nvoid sq_resetobject(HSQOBJECT *po)\n{\n    po->_unVal.pUserPointer=NULL;po->_type=OT_NULL;\n}\n\nSQRESULT sq_throwerror(HSQUIRRELVM v,const SQChar *err)\n{\n    v->_lasterror=SQString::Create(_ss(v),err);\n    return SQ_ERROR;\n}\n\nSQRESULT sq_throwobject(HSQUIRRELVM v)\n{\n    v->_lasterror = v->GetUp(-1);\n    v->Pop();\n    return SQ_ERROR;\n}\n\n\nvoid sq_reseterror(HSQUIRRELVM v)\n{\n    v->_lasterror.Null();\n}\n\nvoid sq_getlasterror(HSQUIRRELVM v)\n{\n    v->Push(v->_lasterror);\n}\n\nSQRESULT sq_reservestack(HSQUIRRELVM v,SQInteger nsize)\n{\n    if (((SQUnsignedInteger)v->_top + nsize) > v->_stack.size()) {\n        if(v->_nmetamethodscall) {\n            return sq_throwerror(v,_SC(\"cannot resize stack while in a metamethod\"));\n        }\n        v->_stack.resize(v->_stack.size() + ((v->_top + nsize) - v->_stack.size()));\n    }\n    return SQ_OK;\n}\n\nSQRESULT sq_resume(HSQUIRRELVM v,SQBool retval,SQBool raiseerror)\n{\n    if (sq_type(v->GetUp(-1)) == OT_GENERATOR)\n    {\n        v->PushNull(); //retval\n        if (!v->Execute(v->GetUp(-2), 0, v->_top, v->GetUp(-1), raiseerror, SQVM::ET_RESUME_GENERATOR))\n        {v->Raise_Error(v->_lasterror); return SQ_ERROR;}\n        if(!retval)\n            v->Pop();\n        return SQ_OK;\n    }\n    return sq_throwerror(v,_SC(\"only generators can be resumed\"));\n}\n\nSQRESULT sq_call(HSQUIRRELVM v,SQInteger params,SQBool retval,SQBool raiseerror)\n{\n    SQObjectPtr res;\n    if(!v->Call(v->GetUp(-(params+1)),params,v->_top-params,res,raiseerror?true:false)){\n        v->Pop(params); //pop args\n        return SQ_ERROR;\n    }\n    if(!v->_suspended)\n        v->Pop(params); //pop args\n    if(retval)\n        v->Push(res); // push result\n    return SQ_OK;\n}\n\nSQRESULT sq_tailcall(HSQUIRRELVM v, SQInteger nparams)\n{\n\tSQObjectPtr &res = v->GetUp(-(nparams + 1));\n\tif (sq_type(res) != OT_CLOSURE) {\n\t\treturn sq_throwerror(v, _SC(\"only closure can be tail called\"));\n\t}\n\tSQClosure *clo = _closure(res);\n\tif (clo->_function->_bgenerator)\n\t{\n\t\treturn sq_throwerror(v, _SC(\"generators cannot be tail called\"));\n\t}\n\t\n\tSQInteger stackbase = (v->_top - nparams) - v->_stackbase;\n\tif (!v->TailCall(clo, stackbase, nparams)) {\n\t\treturn SQ_ERROR;\n\t}\n\treturn SQ_TAILCALL_FLAG;\n}\n\nSQRESULT sq_suspendvm(HSQUIRRELVM v)\n{\n    return v->Suspend();\n}\n\nSQRESULT sq_wakeupvm(HSQUIRRELVM v,SQBool wakeupret,SQBool retval,SQBool raiseerror,SQBool throwerror)\n{\n    SQObjectPtr ret;\n    if(!v->_suspended)\n        return sq_throwerror(v,_SC(\"cannot resume a vm that is not running any code\"));\n    SQInteger target = v->_suspended_target;\n    if(wakeupret) {\n        if(target != -1) {\n            v->GetAt(v->_stackbase+v->_suspended_target)=v->GetUp(-1); //retval\n        }\n        v->Pop();\n    } else if(target != -1) { v->GetAt(v->_stackbase+v->_suspended_target).Null(); }\n    SQObjectPtr dummy;\n    if(!v->Execute(dummy,-1,-1,ret,raiseerror,throwerror?SQVM::ET_RESUME_THROW_VM : SQVM::ET_RESUME_VM)) {\n        return SQ_ERROR;\n    }\n    if(retval)\n        v->Push(ret);\n    return SQ_OK;\n}\n\nvoid sq_setreleasehook(HSQUIRRELVM v,SQInteger idx,SQRELEASEHOOK hook)\n{\n    SQObjectPtr &ud=stack_get(v,idx);\n    switch(sq_type(ud) ) {\n    case OT_USERDATA:   _userdata(ud)->_hook = hook;    break;\n    case OT_INSTANCE:   _instance(ud)->_hook = hook;    break;\n    case OT_CLASS:      _class(ud)->_hook = hook;       break;\n    default: return;\n    }\n}\n\nSQRELEASEHOOK sq_getreleasehook(HSQUIRRELVM v,SQInteger idx)\n{\n    SQObjectPtr &ud=stack_get(v,idx);\n    switch(sq_type(ud) ) {\n    case OT_USERDATA:   return _userdata(ud)->_hook;    break;\n    case OT_INSTANCE:   return _instance(ud)->_hook;    break;\n    case OT_CLASS:      return _class(ud)->_hook;       break;\n    default: return NULL;\n    }\n}\n\nvoid sq_setcompilererrorhandler(HSQUIRRELVM v,SQCOMPILERERROR f)\n{\n    _ss(v)->_compilererrorhandler = f;\n}\n\nSQRESULT sq_writeclosure(HSQUIRRELVM v,SQWRITEFUNC w,SQUserPointer up)\n{\n    SQObjectPtr *o = NULL;\n    _GETSAFE_OBJ(v, -1, OT_CLOSURE,o);\n    unsigned short tag = SQ_BYTECODE_STREAM_TAG;\n    if(_closure(*o)->_function->_noutervalues)\n        return sq_throwerror(v,_SC(\"a closure with free variables bound cannot be serialized\"));\n    if(w(up,&tag,2) != 2)\n        return sq_throwerror(v,_SC(\"io error\"));\n    if(!_closure(*o)->Save(v,up,w))\n        return SQ_ERROR;\n    return SQ_OK;\n}\n\nSQRESULT sq_readclosure(HSQUIRRELVM v,SQREADFUNC r,SQUserPointer up)\n{\n    SQObjectPtr closure;\n\n    unsigned short tag;\n    if(r(up,&tag,2) != 2)\n        return sq_throwerror(v,_SC(\"io error\"));\n    if(tag != SQ_BYTECODE_STREAM_TAG)\n        return sq_throwerror(v,_SC(\"invalid stream\"));\n    if(!SQClosure::Load(v,up,r,closure))\n        return SQ_ERROR;\n    v->Push(closure);\n    return SQ_OK;\n}\n\nSQChar *sq_getscratchpad(HSQUIRRELVM v,SQInteger minsize)\n{\n    return _ss(v)->GetScratchPad(minsize);\n}\n\nSQRESULT sq_resurrectunreachable(HSQUIRRELVM v)\n{\n#ifndef NO_GARBAGE_COLLECTOR\n    _ss(v)->ResurrectUnreachable(v);\n    return SQ_OK;\n#else\n    return sq_throwerror(v,_SC(\"sq_resurrectunreachable requires a garbage collector build\"));\n#endif\n}\n\nSQInteger sq_collectgarbage(HSQUIRRELVM v)\n{\n#ifndef NO_GARBAGE_COLLECTOR\n    return _ss(v)->CollectGarbage(v);\n#else\n    return -1;\n#endif\n}\n\nSQRESULT sq_getcallee(HSQUIRRELVM v)\n{\n    if(v->_callsstacksize > 1)\n    {\n        v->Push(v->_callsstack[v->_callsstacksize - 2]._closure);\n        return SQ_OK;\n    }\n    return sq_throwerror(v,_SC(\"no closure in the calls stack\"));\n}\n\nconst SQChar *sq_getfreevariable(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger nval)\n{\n    SQObjectPtr &self=stack_get(v,idx);\n    const SQChar *name = NULL;\n    switch(sq_type(self))\n    {\n    case OT_CLOSURE:{\n        SQClosure *clo = _closure(self);\n        SQFunctionProto *fp = clo->_function;\n        if(((SQUnsignedInteger)fp->_noutervalues) > nval) {\n            v->Push(*(_outer(clo->_outervalues[nval])->_valptr));\n            SQOuterVar &ov = fp->_outervalues[nval];\n            name = _stringval(ov._name);\n        }\n                    }\n        break;\n    case OT_NATIVECLOSURE:{\n        SQNativeClosure *clo = _nativeclosure(self);\n        if(clo->_noutervalues > nval) {\n            v->Push(clo->_outervalues[nval]);\n            name = _SC(\"@NATIVE\");\n        }\n                          }\n        break;\n    default: break; //shutup compiler\n    }\n    return name;\n}\n\nSQRESULT sq_setfreevariable(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger nval)\n{\n    SQObjectPtr &self=stack_get(v,idx);\n    switch(sq_type(self))\n    {\n    case OT_CLOSURE:{\n        SQFunctionProto *fp = _closure(self)->_function;\n        if(((SQUnsignedInteger)fp->_noutervalues) > nval){\n            *(_outer(_closure(self)->_outervalues[nval])->_valptr) = stack_get(v,-1);\n        }\n        else return sq_throwerror(v,_SC(\"invalid free var index\"));\n                    }\n        break;\n    case OT_NATIVECLOSURE:\n        if(_nativeclosure(self)->_noutervalues > nval){\n            _nativeclosure(self)->_outervalues[nval] = stack_get(v,-1);\n        }\n        else return sq_throwerror(v,_SC(\"invalid free var index\"));\n        break;\n    default:\n        return sq_aux_invalidtype(v, sq_type(self));\n    }\n    v->Pop();\n    return SQ_OK;\n}\n\nSQRESULT sq_setattributes(HSQUIRRELVM v,SQInteger idx)\n{\n    SQObjectPtr *o = NULL;\n    _GETSAFE_OBJ(v, idx, OT_CLASS,o);\n    SQObjectPtr &key = stack_get(v,-2);\n    SQObjectPtr &val = stack_get(v,-1);\n    SQObjectPtr attrs;\n    if(sq_type(key) == OT_NULL) {\n        attrs = _class(*o)->_attributes;\n        _class(*o)->_attributes = val;\n        v->Pop(2);\n        v->Push(attrs);\n        return SQ_OK;\n    }else if(_class(*o)->GetAttributes(key,attrs)) {\n        _class(*o)->SetAttributes(key,val);\n        v->Pop(2);\n        v->Push(attrs);\n        return SQ_OK;\n    }\n    return sq_throwerror(v,_SC(\"wrong index\"));\n}\n\nSQRESULT sq_getattributes(HSQUIRRELVM v,SQInteger idx)\n{\n    SQObjectPtr *o = NULL;\n    _GETSAFE_OBJ(v, idx, OT_CLASS,o);\n    SQObjectPtr &key = stack_get(v,-1);\n    SQObjectPtr attrs;\n    if(sq_type(key) == OT_NULL) {\n        attrs = _class(*o)->_attributes;\n        v->Pop();\n        v->Push(attrs);\n        return SQ_OK;\n    }\n    else if(_class(*o)->GetAttributes(key,attrs)) {\n        v->Pop();\n        v->Push(attrs);\n        return SQ_OK;\n    }\n    return sq_throwerror(v,_SC(\"wrong index\"));\n}\n\nSQRESULT sq_getmemberhandle(HSQUIRRELVM v,SQInteger idx,HSQMEMBERHANDLE *handle)\n{\n    SQObjectPtr *o = NULL;\n    _GETSAFE_OBJ(v, idx, OT_CLASS,o);\n    SQObjectPtr &key = stack_get(v,-1);\n    SQTable *m = _class(*o)->_members;\n    SQObjectPtr val;\n    if(m->Get(key,val)) {\n        handle->_static = _isfield(val) ? SQFalse : SQTrue;\n        handle->_index = _member_idx(val);\n        v->Pop();\n        return SQ_OK;\n    }\n    return sq_throwerror(v,_SC(\"wrong index\"));\n}\n\nSQRESULT _getmemberbyhandle(HSQUIRRELVM v,SQObjectPtr &self,const HSQMEMBERHANDLE *handle,SQObjectPtr *&val)\n{\n    switch(sq_type(self)) {\n        case OT_INSTANCE: {\n                SQInstance *i = _instance(self);\n                if(handle->_static) {\n                    SQClass *c = i->_class;\n                    val = &c->_methods[handle->_index].val;\n                }\n                else {\n                    val = &i->_values[handle->_index];\n\n                }\n            }\n            break;\n        case OT_CLASS: {\n                SQClass *c = _class(self);\n                if(handle->_static) {\n                    val = &c->_methods[handle->_index].val;\n                }\n                else {\n                    val = &c->_defaultvalues[handle->_index].val;\n                }\n            }\n            break;\n        default:\n            return sq_throwerror(v,_SC(\"wrong type(expected class or instance)\"));\n    }\n    return SQ_OK;\n}\n\nSQRESULT sq_getbyhandle(HSQUIRRELVM v,SQInteger idx,const HSQMEMBERHANDLE *handle)\n{\n    SQObjectPtr &self = stack_get(v,idx);\n    SQObjectPtr *val = NULL;\n    if(SQ_FAILED(_getmemberbyhandle(v,self,handle,val))) {\n        return SQ_ERROR;\n    }\n    v->Push(_realval(*val));\n    return SQ_OK;\n}\n\nSQRESULT sq_setbyhandle(HSQUIRRELVM v,SQInteger idx,const HSQMEMBERHANDLE *handle)\n{\n    SQObjectPtr &self = stack_get(v,idx);\n    SQObjectPtr &newval = stack_get(v,-1);\n    SQObjectPtr *val = NULL;\n    if(SQ_FAILED(_getmemberbyhandle(v,self,handle,val))) {\n        return SQ_ERROR;\n    }\n    *val = newval;\n    v->Pop();\n    return SQ_OK;\n}\n\nSQRESULT sq_getbase(HSQUIRRELVM v,SQInteger idx)\n{\n    SQObjectPtr *o = NULL;\n    _GETSAFE_OBJ(v, idx, OT_CLASS,o);\n    if(_class(*o)->_base)\n        v->Push(SQObjectPtr(_class(*o)->_base));\n    else\n        v->PushNull();\n    return SQ_OK;\n}\n\nSQRESULT sq_getclass(HSQUIRRELVM v,SQInteger idx)\n{\n    SQObjectPtr *o = NULL;\n    _GETSAFE_OBJ(v, idx, OT_INSTANCE,o);\n    v->Push(SQObjectPtr(_instance(*o)->_class));\n    return SQ_OK;\n}\n\nSQRESULT sq_createinstance(HSQUIRRELVM v,SQInteger idx)\n{\n    SQObjectPtr *o = NULL;\n    _GETSAFE_OBJ(v, idx, OT_CLASS,o);\n    v->Push(_class(*o)->CreateInstance());\n    return SQ_OK;\n}\n\nvoid sq_weakref(HSQUIRRELVM v,SQInteger idx)\n{\n    SQObject &o=stack_get(v,idx);\n    if(ISREFCOUNTED(sq_type(o))) {\n        v->Push(_refcounted(o)->GetWeakRef(sq_type(o)));\n        return;\n    }\n    v->Push(o);\n}\n\nSQRESULT sq_getweakrefval(HSQUIRRELVM v,SQInteger idx)\n{\n    SQObjectPtr &o = stack_get(v,idx);\n    if(sq_type(o) != OT_WEAKREF) {\n        return sq_throwerror(v,_SC(\"the object must be a weakref\"));\n    }\n    v->Push(_weakref(o)->_obj);\n    return SQ_OK;\n}\n\nSQRESULT sq_getdefaultdelegate(HSQUIRRELVM v,SQObjectType t)\n{\n    SQSharedState *ss = _ss(v);\n    switch(t) {\n    case OT_TABLE: v->Push(ss->_table_default_delegate); break;\n    case OT_ARRAY: v->Push(ss->_array_default_delegate); break;\n    case OT_STRING: v->Push(ss->_string_default_delegate); break;\n    case OT_INTEGER: case OT_FLOAT: v->Push(ss->_number_default_delegate); break;\n    case OT_GENERATOR: v->Push(ss->_generator_default_delegate); break;\n    case OT_CLOSURE: case OT_NATIVECLOSURE: v->Push(ss->_closure_default_delegate); break;\n    case OT_THREAD: v->Push(ss->_thread_default_delegate); break;\n    case OT_CLASS: v->Push(ss->_class_default_delegate); break;\n    case OT_INSTANCE: v->Push(ss->_instance_default_delegate); break;\n    case OT_WEAKREF: v->Push(ss->_weakref_default_delegate); break;\n    default: return sq_throwerror(v,_SC(\"the type doesn't have a default delegate\"));\n    }\n    return SQ_OK;\n}\n\nSQRESULT sq_next(HSQUIRRELVM v,SQInteger idx)\n{\n    SQObjectPtr o=stack_get(v,idx),&refpos = stack_get(v,-1),realkey,val;\n    if(sq_type(o) == OT_GENERATOR) {\n        return sq_throwerror(v,_SC(\"cannot iterate a generator\"));\n    }\n    int faketojump;\n    if(!v->FOREACH_OP(o,realkey,val,refpos,0,666,faketojump))\n        return SQ_ERROR;\n    if(faketojump != 666) {\n        v->Push(realkey);\n        v->Push(val);\n        return SQ_OK;\n    }\n    return SQ_ERROR;\n}\n\nstruct BufState{\n    const SQChar *buf;\n    SQInteger ptr;\n    SQInteger size;\n};\n\nSQInteger buf_lexfeed(SQUserPointer file)\n{\n    BufState *buf=(BufState*)file;\n    if(buf->size<(buf->ptr+1))\n        return 0;\n    return buf->buf[buf->ptr++];\n}\n\nSQRESULT sq_compilebuffer(HSQUIRRELVM v,const SQChar *s,SQInteger size,const SQChar *sourcename,SQBool raiseerror) {\n    BufState buf;\n    buf.buf = s;\n    buf.size = size;\n    buf.ptr = 0;\n    return sq_compile(v, buf_lexfeed, &buf, sourcename, raiseerror);\n}\n\nvoid sq_move(HSQUIRRELVM dest,HSQUIRRELVM src,SQInteger idx)\n{\n    dest->Push(stack_get(src,idx));\n}\n\nvoid sq_setprintfunc(HSQUIRRELVM v, SQPRINTFUNCTION printfunc,SQPRINTFUNCTION errfunc)\n{\n    _ss(v)->_printfunc = printfunc;\n    _ss(v)->_errorfunc = errfunc;\n}\n\nSQPRINTFUNCTION sq_getprintfunc(HSQUIRRELVM v)\n{\n    return _ss(v)->_printfunc;\n}\n\nSQPRINTFUNCTION sq_geterrorfunc(HSQUIRRELVM v)\n{\n    return _ss(v)->_errorfunc;\n}\n\nvoid *sq_malloc(SQUnsignedInteger size)\n{\n    return SQ_MALLOC(size);\n}\n\nvoid *sq_realloc(void* p,SQUnsignedInteger oldsize,SQUnsignedInteger newsize)\n{\n    return SQ_REALLOC(p,oldsize,newsize);\n}\n\nvoid sq_free(void *p,SQUnsignedInteger size)\n{\n    SQ_FREE(p,size);\n}\n"
  },
  {
    "path": "extlibs/squirrel/squirrel/sqarray.h",
    "content": "/*  see copyright notice in squirrel.h */\n#ifndef _SQARRAY_H_\n#define _SQARRAY_H_\n\nstruct SQArray : public CHAINABLE_OBJ\n{\nprivate:\n    SQArray(SQSharedState *ss,SQInteger nsize){_values.resize(nsize); INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this);}\n    ~SQArray()\n    {\n        REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this);\n    }\npublic:\n    static SQArray* Create(SQSharedState *ss,SQInteger nInitialSize){\n        SQArray *newarray=(SQArray*)SQ_MALLOC(sizeof(SQArray));\n        new (newarray) SQArray(ss,nInitialSize);\n        return newarray;\n    }\n#ifndef NO_GARBAGE_COLLECTOR\n    void Mark(SQCollectable **chain);\n    SQObjectType GetType() {return OT_ARRAY;}\n#endif\n    void Finalize(){\n        _values.resize(0);\n    }\n    bool Get(const SQInteger nidx,SQObjectPtr &val)\n    {\n        if(nidx>=0 && nidx<(SQInteger)_values.size()){\n            SQObjectPtr &o = _values[nidx];\n            val = _realval(o);\n            return true;\n        }\n        else return false;\n    }\n    bool Set(const SQInteger nidx,const SQObjectPtr &val)\n    {\n        if(nidx>=0 && nidx<(SQInteger)_values.size()){\n            _values[nidx]=val;\n            return true;\n        }\n        else return false;\n    }\n    SQInteger Next(const SQObjectPtr &refpos,SQObjectPtr &outkey,SQObjectPtr &outval)\n    {\n        SQUnsignedInteger idx=TranslateIndex(refpos);\n        while(idx<_values.size()){\n            //first found\n            outkey=(SQInteger)idx;\n            SQObjectPtr &o = _values[idx];\n            outval = _realval(o);\n            //return idx for the next iteration\n            return ++idx;\n        }\n        //nothing to iterate anymore\n        return -1;\n    }\n    SQArray *Clone(){SQArray *anew=Create(_opt_ss(this),0); anew->_values.copy(_values); return anew; }\n    SQInteger Size() const {return _values.size();}\n    void Resize(SQInteger size)\n    {\n        SQObjectPtr _null;\n        Resize(size,_null);\n    }\n    void Resize(SQInteger size,SQObjectPtr &fill) { _values.resize(size,fill); ShrinkIfNeeded(); }\n    void Reserve(SQInteger size) { _values.reserve(size); }\n    void Append(const SQObject &o){_values.push_back(o);}\n    void Extend(const SQArray *a);\n    SQObjectPtr &Top(){return _values.top();}\n    void Pop(){_values.pop_back(); ShrinkIfNeeded(); }\n    bool Insert(SQInteger idx,const SQObject &val){\n        if(idx < 0 || idx > (SQInteger)_values.size())\n            return false;\n        _values.insert(idx,val);\n        return true;\n    }\n    void ShrinkIfNeeded() {\n        if(_values.size() <= _values.capacity()>>2) //shrink the array\n            _values.shrinktofit();\n    }\n    bool Remove(SQInteger idx){\n        if(idx < 0 || idx >= (SQInteger)_values.size())\n            return false;\n        _values.remove(idx);\n        ShrinkIfNeeded();\n        return true;\n    }\n    void Release()\n    {\n        sq_delete(this,SQArray);\n    }\n\n    SQObjectPtrVec _values;\n};\n#endif //_SQARRAY_H_\n"
  },
  {
    "path": "extlibs/squirrel/squirrel/sqbaselib.cpp",
    "content": "/*\n    see copyright notice in squirrel.h\n*/\n#include \"sqpcheader.h\"\n#include \"sqvm.h\"\n#include \"sqstring.h\"\n#include \"sqtable.h\"\n#include \"sqarray.h\"\n#include \"sqfuncproto.h\"\n#include \"sqclosure.h\"\n#include \"sqclass.h\"\n#include <stdlib.h>\n#include <stdarg.h>\n#include <ctype.h>\n\nstatic bool str2num(const SQChar *s,SQObjectPtr &res,SQInteger base)\n{\n    SQChar *end;\n    const SQChar *e = s;\n    bool iseintbase = base > 13; //to fix error converting hexadecimals with e like 56f0791e\n    bool isfloat = false;\n    SQChar c;\n    while((c = *e) != _SC('\\0'))\n    {\n        if (c == _SC('.') || (!iseintbase && (c == _SC('E') || c == _SC('e')))) { //e and E is for scientific notation\n            isfloat = true;\n            break;\n        }\n        e++;\n    }\n    if(isfloat){\n        SQFloat r = SQFloat(scstrtod(s,&end));\n        if(s == end) return false;\n        res = r;\n    }\n    else{\n        SQInteger r = SQInteger(scstrtol(s,&end,(int)base));\n        if(s == end) return false;\n        res = r;\n    }\n    return true;\n}\n\nstatic SQInteger base_dummy(HSQUIRRELVM SQ_UNUSED_ARG(v))\n{\n    return 0;\n}\n\n#ifndef NO_GARBAGE_COLLECTOR\nstatic SQInteger base_collectgarbage(HSQUIRRELVM v)\n{\n    sq_pushinteger(v, sq_collectgarbage(v));\n    return 1;\n}\nstatic SQInteger base_resurectureachable(HSQUIRRELVM v)\n{\n    sq_resurrectunreachable(v);\n    return 1;\n}\n#endif\n\nstatic SQInteger base_getroottable(HSQUIRRELVM v)\n{\n    v->Push(v->_roottable);\n    return 1;\n}\n\nstatic SQInteger base_getconsttable(HSQUIRRELVM v)\n{\n    v->Push(_ss(v)->_consts);\n    return 1;\n}\n\n\nstatic SQInteger base_setroottable(HSQUIRRELVM v)\n{\n    SQObjectPtr o = v->_roottable;\n    if(SQ_FAILED(sq_setroottable(v))) return SQ_ERROR;\n    v->Push(o);\n    return 1;\n}\n\nstatic SQInteger base_setconsttable(HSQUIRRELVM v)\n{\n    SQObjectPtr o = _ss(v)->_consts;\n    if(SQ_FAILED(sq_setconsttable(v))) return SQ_ERROR;\n    v->Push(o);\n    return 1;\n}\n\nstatic SQInteger base_seterrorhandler(HSQUIRRELVM v)\n{\n    sq_seterrorhandler(v);\n    return 0;\n}\n\nstatic SQInteger base_setdebughook(HSQUIRRELVM v)\n{\n    sq_setdebughook(v);\n    return 0;\n}\n\nstatic SQInteger base_enabledebuginfo(HSQUIRRELVM v)\n{\n    SQObjectPtr &o=stack_get(v,2);\n\n    sq_enabledebuginfo(v,SQVM::IsFalse(o)?SQFalse:SQTrue);\n    return 0;\n}\n\nstatic SQInteger __getcallstackinfos(HSQUIRRELVM v,SQInteger level)\n{\n    SQStackInfos si;\n    SQInteger seq = 0;\n    const SQChar *name = NULL;\n\n    if (SQ_SUCCEEDED(sq_stackinfos(v, level, &si)))\n    {\n        const SQChar *fn = _SC(\"unknown\");\n        const SQChar *src = _SC(\"unknown\");\n        if(si.funcname)fn = si.funcname;\n        if(si.source)src = si.source;\n        sq_newtable(v);\n        sq_pushstring(v, _SC(\"func\"), -1);\n        sq_pushstring(v, fn, -1);\n        sq_newslot(v, -3, SQFalse);\n        sq_pushstring(v, _SC(\"src\"), -1);\n        sq_pushstring(v, src, -1);\n        sq_newslot(v, -3, SQFalse);\n        sq_pushstring(v, _SC(\"line\"), -1);\n        sq_pushinteger(v, si.line);\n        sq_newslot(v, -3, SQFalse);\n        sq_pushstring(v, _SC(\"locals\"), -1);\n        sq_newtable(v);\n        seq=0;\n        while ((name = sq_getlocal(v, level, seq))) {\n            sq_pushstring(v, name, -1);\n            sq_push(v, -2);\n            sq_newslot(v, -4, SQFalse);\n            sq_pop(v, 1);\n            seq++;\n        }\n        sq_newslot(v, -3, SQFalse);\n        return 1;\n    }\n\n    return 0;\n}\nstatic SQInteger base_getstackinfos(HSQUIRRELVM v)\n{\n    SQInteger level;\n    sq_getinteger(v, -1, &level);\n    return __getcallstackinfos(v,level);\n}\n\nstatic SQInteger base_assert(HSQUIRRELVM v)\n{\n    if(SQVM::IsFalse(stack_get(v,2))){\n        SQInteger top = sq_gettop(v);\n        if (top>2 && SQ_SUCCEEDED(sq_tostring(v,3))) {\n            const SQChar *str = 0;\n            if (SQ_SUCCEEDED(sq_getstring(v,-1,&str))) {\n                return sq_throwerror(v, str);\n            }\n        }\n        return sq_throwerror(v, _SC(\"assertion failed\"));\n    }\n    return 0;\n}\n\nstatic SQInteger get_slice_params(HSQUIRRELVM v,SQInteger &sidx,SQInteger &eidx,SQObjectPtr &o)\n{\n    SQInteger top = sq_gettop(v);\n    sidx=0;\n    eidx=0;\n    o=stack_get(v,1);\n    if(top>1){\n        SQObjectPtr &start=stack_get(v,2);\n        if(sq_type(start)!=OT_NULL && sq_isnumeric(start)){\n            sidx=tointeger(start);\n        }\n    }\n    if(top>2){\n        SQObjectPtr &end=stack_get(v,3);\n        if(sq_isnumeric(end)){\n            eidx=tointeger(end);\n        }\n    }\n    else {\n        eidx = sq_getsize(v,1);\n    }\n    return 1;\n}\n\nstatic SQInteger base_print(HSQUIRRELVM v)\n{\n    const SQChar *str;\n    if(SQ_SUCCEEDED(sq_tostring(v,2)))\n    {\n        if(SQ_SUCCEEDED(sq_getstring(v,-1,&str))) {\n            if(_ss(v)->_printfunc) _ss(v)->_printfunc(v,_SC(\"%s\"),str);\n            return 0;\n        }\n    }\n    return SQ_ERROR;\n}\n\nstatic SQInteger base_error(HSQUIRRELVM v)\n{\n    const SQChar *str;\n    if(SQ_SUCCEEDED(sq_tostring(v,2)))\n    {\n        if(SQ_SUCCEEDED(sq_getstring(v,-1,&str))) {\n            if(_ss(v)->_errorfunc) _ss(v)->_errorfunc(v,_SC(\"%s\"),str);\n            return 0;\n        }\n    }\n    return SQ_ERROR;\n}\n\nstatic SQInteger base_compilestring(HSQUIRRELVM v)\n{\n    SQInteger nargs=sq_gettop(v);\n    const SQChar *src=NULL,*name=_SC(\"unnamedbuffer\");\n    SQInteger size;\n    sq_getstring(v,2,&src);\n    size=sq_getsize(v,2);\n    if(nargs>2){\n        sq_getstring(v,3,&name);\n    }\n    if(SQ_SUCCEEDED(sq_compilebuffer(v,src,size,name,SQFalse)))\n        return 1;\n    else\n        return SQ_ERROR;\n}\n\nstatic SQInteger base_newthread(HSQUIRRELVM v)\n{\n    SQObjectPtr &func = stack_get(v,2);\n    SQInteger stksize = (_closure(func)->_function->_stacksize << 1) +2;\n    HSQUIRRELVM newv = sq_newthread(v, (stksize < MIN_STACK_OVERHEAD + 2)? MIN_STACK_OVERHEAD + 2 : stksize);\n    sq_move(newv,v,-2);\n    return 1;\n}\n\nstatic SQInteger base_suspend(HSQUIRRELVM v)\n{\n    return sq_suspendvm(v);\n}\n\nstatic SQInteger base_array(HSQUIRRELVM v)\n{\n    SQArray *a;\n    SQObject &size = stack_get(v,2);\n    if(sq_gettop(v) > 2) {\n        a = SQArray::Create(_ss(v),0);\n        a->Resize(tointeger(size),stack_get(v,3));\n    }\n    else {\n        a = SQArray::Create(_ss(v),tointeger(size));\n    }\n    v->Push(a);\n    return 1;\n}\n\nstatic SQInteger base_type(HSQUIRRELVM v)\n{\n    SQObjectPtr &o = stack_get(v,2);\n    v->Push(SQString::Create(_ss(v),GetTypeName(o),-1));\n    return 1;\n}\n\nstatic SQInteger base_callee(HSQUIRRELVM v)\n{\n    if(v->_callsstacksize > 1)\n    {\n        v->Push(v->_callsstack[v->_callsstacksize - 2]._closure);\n        return 1;\n    }\n    return sq_throwerror(v,_SC(\"no closure in the calls stack\"));\n}\n\nstatic const SQRegFunction base_funcs[]={\n    //generic\n    {_SC(\"seterrorhandler\"),base_seterrorhandler,2, NULL},\n    {_SC(\"setdebughook\"),base_setdebughook,2, NULL},\n    {_SC(\"enabledebuginfo\"),base_enabledebuginfo,2, NULL},\n    {_SC(\"getstackinfos\"),base_getstackinfos,2, _SC(\".n\")},\n    {_SC(\"getroottable\"),base_getroottable,1, NULL},\n    {_SC(\"setroottable\"),base_setroottable,2, NULL},\n    {_SC(\"getconsttable\"),base_getconsttable,1, NULL},\n    {_SC(\"setconsttable\"),base_setconsttable,2, NULL},\n    {_SC(\"assert\"),base_assert,-2, NULL},\n    {_SC(\"print\"),base_print,2, NULL},\n    {_SC(\"error\"),base_error,2, NULL},\n    {_SC(\"compilestring\"),base_compilestring,-2, _SC(\".ss\")},\n    {_SC(\"newthread\"),base_newthread,2, _SC(\".c\")},\n    {_SC(\"suspend\"),base_suspend,-1, NULL},\n    {_SC(\"array\"),base_array,-2, _SC(\".n\")},\n    {_SC(\"type\"),base_type,2, NULL},\n    {_SC(\"callee\"),base_callee,0,NULL},\n    {_SC(\"dummy\"),base_dummy,0,NULL},\n#ifndef NO_GARBAGE_COLLECTOR\n    {_SC(\"collectgarbage\"),base_collectgarbage,0, NULL},\n    {_SC(\"resurrectunreachable\"),base_resurectureachable,0, NULL},\n#endif\n    {NULL,(SQFUNCTION)0,0,NULL}\n};\n\nvoid sq_base_register(HSQUIRRELVM v)\n{\n    SQInteger i=0;\n    sq_pushroottable(v);\n    while(base_funcs[i].name!=0) {\n        sq_pushstring(v,base_funcs[i].name,-1);\n        sq_newclosure(v,base_funcs[i].f,0);\n        sq_setnativeclosurename(v,-1,base_funcs[i].name);\n        sq_setparamscheck(v,base_funcs[i].nparamscheck,base_funcs[i].typemask);\n        sq_newslot(v,-3, SQFalse);\n        i++;\n    }\n\n    sq_pushstring(v,_SC(\"_versionnumber_\"),-1);\n    sq_pushinteger(v,SQUIRREL_VERSION_NUMBER);\n    sq_newslot(v,-3, SQFalse);\n    sq_pushstring(v,_SC(\"_version_\"),-1);\n    sq_pushstring(v,SQUIRREL_VERSION,-1);\n    sq_newslot(v,-3, SQFalse);\n    sq_pushstring(v,_SC(\"_charsize_\"),-1);\n    sq_pushinteger(v,sizeof(SQChar));\n    sq_newslot(v,-3, SQFalse);\n    sq_pushstring(v,_SC(\"_intsize_\"),-1);\n    sq_pushinteger(v,sizeof(SQInteger));\n    sq_newslot(v,-3, SQFalse);\n    sq_pushstring(v,_SC(\"_floatsize_\"),-1);\n    sq_pushinteger(v,sizeof(SQFloat));\n    sq_newslot(v,-3, SQFalse);\n    sq_pop(v,1);\n}\n\nstatic SQInteger default_delegate_len(HSQUIRRELVM v)\n{\n    v->Push(SQInteger(sq_getsize(v,1)));\n    return 1;\n}\n\nstatic SQInteger default_delegate_tofloat(HSQUIRRELVM v)\n{\n    SQObjectPtr &o=stack_get(v,1);\n    switch(sq_type(o)){\n    case OT_STRING:{\n        SQObjectPtr res;\n        if(str2num(_stringval(o),res,10)){\n            v->Push(SQObjectPtr(tofloat(res)));\n            break;\n        }}\n        return sq_throwerror(v, _SC(\"cannot convert the string\"));\n        break;\n    case OT_INTEGER:case OT_FLOAT:\n        v->Push(SQObjectPtr(tofloat(o)));\n        break;\n    case OT_BOOL:\n        v->Push(SQObjectPtr((SQFloat)(_integer(o)?1:0)));\n        break;\n    default:\n        v->PushNull();\n        break;\n    }\n    return 1;\n}\n\nstatic SQInteger default_delegate_tointeger(HSQUIRRELVM v)\n{\n    SQObjectPtr &o=stack_get(v,1);\n    SQInteger base = 10;\n    if(sq_gettop(v) > 1) {\n        sq_getinteger(v,2,&base);\n    }\n    switch(sq_type(o)){\n    case OT_STRING:{\n        SQObjectPtr res;\n        if(str2num(_stringval(o),res,base)){\n            v->Push(SQObjectPtr(tointeger(res)));\n            break;\n        }}\n        return sq_throwerror(v, _SC(\"cannot convert the string\"));\n        break;\n    case OT_INTEGER:case OT_FLOAT:\n        v->Push(SQObjectPtr(tointeger(o)));\n        break;\n    case OT_BOOL:\n        v->Push(SQObjectPtr(_integer(o)?(SQInteger)1:(SQInteger)0));\n        break;\n    default:\n        v->PushNull();\n        break;\n    }\n    return 1;\n}\n\nstatic SQInteger default_delegate_tostring(HSQUIRRELVM v)\n{\n    if(SQ_FAILED(sq_tostring(v,1)))\n        return SQ_ERROR;\n    return 1;\n}\n\nstatic SQInteger obj_delegate_weakref(HSQUIRRELVM v)\n{\n    sq_weakref(v,1);\n    return 1;\n}\n\nstatic SQInteger obj_clear(HSQUIRRELVM v)\n{\n    return SQ_SUCCEEDED(sq_clear(v,-1)) ? 1 : SQ_ERROR;\n}\n\n\nstatic SQInteger number_delegate_tochar(HSQUIRRELVM v)\n{\n    SQObject &o=stack_get(v,1);\n    SQChar c = (SQChar)tointeger(o);\n    v->Push(SQString::Create(_ss(v),(const SQChar *)&c,1));\n    return 1;\n}\n\n\n\n/////////////////////////////////////////////////////////////////\n//TABLE DEFAULT DELEGATE\n\nstatic SQInteger table_rawdelete(HSQUIRRELVM v)\n{\n    if(SQ_FAILED(sq_rawdeleteslot(v,1,SQTrue)))\n        return SQ_ERROR;\n    return 1;\n}\n\n\nstatic SQInteger container_rawexists(HSQUIRRELVM v)\n{\n    if(SQ_SUCCEEDED(sq_rawget(v,-2))) {\n        sq_pushbool(v,SQTrue);\n        return 1;\n    }\n    sq_pushbool(v,SQFalse);\n    return 1;\n}\n\nstatic SQInteger container_rawset(HSQUIRRELVM v)\n{\n    return SQ_SUCCEEDED(sq_rawset(v,-3)) ? 1 : SQ_ERROR;\n}\n\nstatic SQInteger container_rawsafeget(HSQUIRRELVM v)\n{\n    if (SQ_SUCCEEDED(sq_rawget(v, -2)))\n    {\n        return 1;\n    }\n    sq_pushinteger(v, 0);\n    return 1;\n}\n\nstatic SQInteger container_rawget(HSQUIRRELVM v)\n{\n    return SQ_SUCCEEDED(sq_rawget(v,-2))?1:SQ_ERROR;\n}\n\nstatic SQInteger table_setdelegate(HSQUIRRELVM v)\n{\n    if(SQ_FAILED(sq_setdelegate(v,-2)))\n        return SQ_ERROR;\n    sq_push(v,-1); // -1 because sq_setdelegate pops 1\n    return 1;\n}\n\nstatic SQInteger table_getdelegate(HSQUIRRELVM v)\n{\n    return SQ_SUCCEEDED(sq_getdelegate(v,-1))?1:SQ_ERROR;\n}\n\nstatic SQInteger table_filter(HSQUIRRELVM v)\n{\n    SQObject &o = stack_get(v,1);\n    SQTable *tbl = _table(o);\n    SQObjectPtr ret = SQTable::Create(_ss(v),0);\n\n    SQObjectPtr itr, key, val;\n    SQInteger nitr;\n    while((nitr = tbl->Next(false, itr, key, val)) != -1) {\n        itr = (SQInteger)nitr;\n\n        v->Push(o);\n        v->Push(key);\n        v->Push(val);\n        if(SQ_FAILED(sq_call(v,3,SQTrue,SQFalse))) {\n            return SQ_ERROR;\n        }\n        if(!SQVM::IsFalse(v->GetUp(-1))) {\n            _table(ret)->NewSlot(key, val);\n        }\n        v->Pop();\n    }\n\n    v->Push(ret);\n    return 1;\n}\n\n\nconst SQRegFunction SQSharedState::_table_default_delegate_funcz[]={\n    {_SC(\"len\"),default_delegate_len,1, _SC(\"t\")},\n    {_SC(\"rawget\"),container_rawget,2, _SC(\"t\")},\n    {_SC(\"rawsafeget\"), container_rawsafeget, 2, _SC(\"t\")},\n    {_SC(\"rawset\"),container_rawset,3, _SC(\"t\")},\n    {_SC(\"rawdelete\"),table_rawdelete,2, _SC(\"t\")},\n    {_SC(\"rawin\"),container_rawexists,2, _SC(\"t\")},\n    {_SC(\"weakref\"),obj_delegate_weakref,1, NULL },\n    {_SC(\"tostring\"),default_delegate_tostring,1, _SC(\".\")},\n    {_SC(\"clear\"),obj_clear,1, _SC(\".\")},\n    {_SC(\"setdelegate\"),table_setdelegate,2, _SC(\".t|o\")},\n    {_SC(\"getdelegate\"),table_getdelegate,1, _SC(\".\")},\n    {_SC(\"filter\"),table_filter,2, _SC(\"tc\")},\n    {NULL,(SQFUNCTION)0,0,NULL}\n};\n\n//ARRAY DEFAULT DELEGATE///////////////////////////////////////\n\nstatic SQInteger array_append(HSQUIRRELVM v)\n{\n    return SQ_SUCCEEDED(sq_arrayappend(v,-2)) ? 1 : SQ_ERROR;\n}\n\nstatic SQInteger array_extend(HSQUIRRELVM v)\n{\n    _array(stack_get(v,1))->Extend(_array(stack_get(v,2)));\n    sq_pop(v,1);\n    return 1;\n}\n\nstatic SQInteger array_reverse(HSQUIRRELVM v)\n{\n    return SQ_SUCCEEDED(sq_arrayreverse(v,-1)) ? 1 : SQ_ERROR;\n}\n\nstatic SQInteger array_pop(HSQUIRRELVM v)\n{\n    return SQ_SUCCEEDED(sq_arraypop(v,1,SQTrue))?1:SQ_ERROR;\n}\n\nstatic SQInteger array_top(HSQUIRRELVM v)\n{\n    SQObject &o=stack_get(v,1);\n    if(_array(o)->Size()>0){\n        v->Push(_array(o)->Top());\n        return 1;\n    }\n    else return sq_throwerror(v,_SC(\"top() on a empty array\"));\n}\n\nstatic SQInteger array_insert(HSQUIRRELVM v)\n{\n    SQObject &o=stack_get(v,1);\n    SQObject &idx=stack_get(v,2);\n    SQObject &val=stack_get(v,3);\n    if(!_array(o)->Insert(tointeger(idx),val))\n        return sq_throwerror(v,_SC(\"index out of range\"));\n    sq_pop(v,2);\n    return 1;\n}\n\nstatic SQInteger array_remove(HSQUIRRELVM v)\n{\n    SQObject &o = stack_get(v, 1);\n    SQObject &idx = stack_get(v, 2);\n    if(!sq_isnumeric(idx)) return sq_throwerror(v, _SC(\"wrong type\"));\n    SQObjectPtr val;\n    if(_array(o)->Get(tointeger(idx), val)) {\n        _array(o)->Remove(tointeger(idx));\n        v->Push(val);\n        return 1;\n    }\n    return sq_throwerror(v, _SC(\"idx out of range\"));\n}\n\nstatic SQInteger array_resize(HSQUIRRELVM v)\n{\n    SQObject &o = stack_get(v, 1);\n    SQObject &nsize = stack_get(v, 2);\n    SQObjectPtr fill;\n    if(sq_isnumeric(nsize)) {\n        SQInteger sz = tointeger(nsize);\n        if (sz<0)\n          return sq_throwerror(v, _SC(\"resizing to negative length\"));\n\n        if(sq_gettop(v) > 2)\n            fill = stack_get(v, 3);\n        _array(o)->Resize(sz,fill);\n        sq_settop(v, 1);\n        return 1;\n    }\n    return sq_throwerror(v, _SC(\"size must be a number\"));\n}\n\nstatic SQInteger __map_array(SQArray *dest,SQArray *src,HSQUIRRELVM v) {\n    SQObjectPtr temp;\n    SQInteger size = src->Size();\n    SQObject &closure = stack_get(v, 2);\n    v->Push(closure);\n\n    SQInteger nArgs;\n    if(sq_type(closure) == OT_CLOSURE) {\n        nArgs = _closure(closure)->_function->_nparameters;\n    }\n    else if (sq_type(closure) == OT_NATIVECLOSURE) {\n        SQInteger nParamsCheck = _nativeclosure(closure)->_nparamscheck;\n        if (nParamsCheck > 0)\n            nArgs = nParamsCheck;\n        else // push all params when there is no check or only minimal count set\n            nArgs = 4;\n    }\n\n    for(SQInteger n = 0; n < size; n++) {\n        src->Get(n,temp);\n        v->Push(src);\n        v->Push(temp);\n        if (nArgs >= 3)\n            v->Push(SQObjectPtr(n));\n        if (nArgs >= 4)\n            v->Push(src);\n        if(SQ_FAILED(sq_call(v,nArgs,SQTrue,SQFalse))) {\n            return SQ_ERROR;\n        }\n        dest->Set(n,v->GetUp(-1));\n        v->Pop();\n    }\n    v->Pop();\n    return 0;\n}\n\nstatic SQInteger array_map(HSQUIRRELVM v)\n{\n    SQObject &o = stack_get(v,1);\n    SQInteger size = _array(o)->Size();\n    SQObjectPtr ret = SQArray::Create(_ss(v),size);\n    if(SQ_FAILED(__map_array(_array(ret),_array(o),v)))\n        return SQ_ERROR;\n    v->Push(ret);\n    return 1;\n}\n\nstatic SQInteger array_apply(HSQUIRRELVM v)\n{\n    SQObject &o = stack_get(v,1);\n    if(SQ_FAILED(__map_array(_array(o),_array(o),v)))\n        return SQ_ERROR;\n    sq_pop(v,1);\n    return 1;\n}\n\nstatic SQInteger array_reduce(HSQUIRRELVM v)\n{\n    SQObject &o = stack_get(v,1);\n    SQArray *a = _array(o);\n    SQInteger size = a->Size();\n    SQObjectPtr res;\n    SQInteger iterStart;\n    if (sq_gettop(v)>2) {\n        res = stack_get(v,3);\n        iterStart = 0;\n    } else if (size==0) {\n        return 0;\n    } else {\n        a->Get(0,res);\n        iterStart = 1;\n    }\n    if (size > iterStart) {\n        SQObjectPtr other;\n        v->Push(stack_get(v,2));\n        for (SQInteger n = iterStart; n < size; n++) {\n            a->Get(n,other);\n            v->Push(o);\n            v->Push(res);\n            v->Push(other);\n            if(SQ_FAILED(sq_call(v,3,SQTrue,SQFalse))) {\n                return SQ_ERROR;\n            }\n            res = v->GetUp(-1);\n            v->Pop();\n        }\n        v->Pop();\n    }\n    v->Push(res);\n    return 1;\n}\n\nstatic SQInteger array_filter(HSQUIRRELVM v)\n{\n    SQObject &o = stack_get(v,1);\n    SQArray *a = _array(o);\n    SQObjectPtr ret = SQArray::Create(_ss(v),0);\n    SQInteger size = a->Size();\n    SQObjectPtr val;\n    for(SQInteger n = 0; n < size; n++) {\n        a->Get(n,val);\n        v->Push(o);\n        v->Push(n);\n        v->Push(val);\n        if(SQ_FAILED(sq_call(v,3,SQTrue,SQFalse))) {\n            return SQ_ERROR;\n        }\n        if(!SQVM::IsFalse(v->GetUp(-1))) {\n            _array(ret)->Append(val);\n        }\n        v->Pop();\n    }\n    v->Push(ret);\n    return 1;\n}\n\nstatic SQInteger array_find(HSQUIRRELVM v)\n{\n    SQObject &o = stack_get(v,1);\n    SQObjectPtr &val = stack_get(v,2);\n    SQArray *a = _array(o);\n    SQInteger size = a->Size();\n    SQObjectPtr temp;\n    for(SQInteger n = 0; n < size; n++) {\n        bool res = false;\n        a->Get(n,temp);\n        if(SQVM::IsEqual(temp,val,res) && res) {\n            v->Push(n);\n            return 1;\n        }\n    }\n    return 0;\n}\n\n\nstatic bool _sort_compare(HSQUIRRELVM v,SQObjectPtr &a,SQObjectPtr &b,SQInteger func,SQInteger &ret)\n{\n    if(func < 0) {\n        if(!v->ObjCmp(a,b,ret)) return false;\n    }\n    else {\n        SQInteger top = sq_gettop(v);\n        sq_push(v, func);\n        sq_pushroottable(v);\n        v->Push(a);\n        v->Push(b);\n        if(SQ_FAILED(sq_call(v, 3, SQTrue, SQFalse))) {\n            if(!sq_isstring( v->_lasterror))\n                v->Raise_Error(_SC(\"compare func failed\"));\n            return false;\n        }\n        if(SQ_FAILED(sq_getinteger(v, -1, &ret))) {\n            v->Raise_Error(_SC(\"numeric value expected as return value of the compare function\"));\n            return false;\n        }\n        sq_settop(v, top);\n        return true;\n    }\n    return true;\n}\n\nstatic bool _hsort_sift_down(HSQUIRRELVM v,SQArray *arr, SQInteger root, SQInteger bottom, SQInteger func)\n{\n    SQInteger maxChild;\n    SQInteger done = 0;\n    SQInteger ret;\n    SQInteger root2;\n    while (((root2 = root * 2) <= bottom) && (!done))\n    {\n        if (root2 == bottom) {\n            maxChild = root2;\n        }\n        else {\n            if(!_sort_compare(v,arr->_values[root2],arr->_values[root2 + 1],func,ret))\n                return false;\n            if (ret > 0) {\n                maxChild = root2;\n            }\n            else {\n                maxChild = root2 + 1;\n            }\n        }\n\n        if(!_sort_compare(v,arr->_values[root],arr->_values[maxChild],func,ret))\n            return false;\n        if (ret < 0) {\n            if (root == maxChild) {\n                v->Raise_Error(_SC(\"inconsistent compare function\"));\n                return false; // We'd be swapping ourselve. The compare function is incorrect\n            }\n\n            _Swap(arr->_values[root],arr->_values[maxChild]);\n            root = maxChild;\n        }\n        else {\n            done = 1;\n        }\n    }\n    return true;\n}\n\nstatic bool _hsort(HSQUIRRELVM v,SQObjectPtr &arr, SQInteger SQ_UNUSED_ARG(l), SQInteger SQ_UNUSED_ARG(r),SQInteger func)\n{\n    SQArray *a = _array(arr);\n    SQInteger i;\n    SQInteger array_size = a->Size();\n    for (i = (array_size / 2); i >= 0; i--) {\n        if(!_hsort_sift_down(v,a, i, array_size - 1,func)) return false;\n    }\n\n    for (i = array_size-1; i >= 1; i--)\n    {\n        _Swap(a->_values[0],a->_values[i]);\n        if(!_hsort_sift_down(v,a, 0, i-1,func)) return false;\n    }\n    return true;\n}\n\nstatic SQInteger array_sort(HSQUIRRELVM v)\n{\n    SQInteger func = -1;\n    SQObjectPtr &o = stack_get(v,1);\n    if(_array(o)->Size() > 1) {\n        if(sq_gettop(v) == 2) func = 2;\n        if(!_hsort(v, o, 0, _array(o)->Size()-1, func))\n            return SQ_ERROR;\n\n    }\n    sq_settop(v,1);\n    return 1;\n}\n\nstatic SQInteger array_slice(HSQUIRRELVM v)\n{\n    SQInteger sidx,eidx;\n    SQObjectPtr o;\n    if(get_slice_params(v,sidx,eidx,o)==-1)return -1;\n    SQInteger alen = _array(o)->Size();\n    if(sidx < 0)sidx = alen + sidx;\n    if(eidx < 0)eidx = alen + eidx;\n    if(eidx < sidx)return sq_throwerror(v,_SC(\"wrong indexes\"));\n    if(eidx > alen || sidx < 0)return sq_throwerror(v, _SC(\"slice out of range\"));\n    SQArray *arr=SQArray::Create(_ss(v),eidx-sidx);\n    SQObjectPtr t;\n    SQInteger count=0;\n    for(SQInteger i=sidx;i<eidx;i++){\n        _array(o)->Get(i,t);\n        arr->Set(count++,t);\n    }\n    v->Push(arr);\n    return 1;\n\n}\n\nconst SQRegFunction SQSharedState::_array_default_delegate_funcz[]={\n    {_SC(\"len\"),default_delegate_len,1, _SC(\"a\")},\n    {_SC(\"append\"),array_append,2, _SC(\"a\")},\n    {_SC(\"extend\"),array_extend,2, _SC(\"aa\")},\n    {_SC(\"push\"),array_append,2, _SC(\"a\")},\n    {_SC(\"pop\"),array_pop,1, _SC(\"a\")},\n    {_SC(\"top\"),array_top,1, _SC(\"a\")},\n    {_SC(\"insert\"),array_insert,3, _SC(\"an\")},\n    {_SC(\"remove\"),array_remove,2, _SC(\"an\")},\n    {_SC(\"resize\"),array_resize,-2, _SC(\"an\")},\n    {_SC(\"reverse\"),array_reverse,1, _SC(\"a\")},\n    {_SC(\"sort\"),array_sort,-1, _SC(\"ac\")},\n    {_SC(\"slice\"),array_slice,-1, _SC(\"ann\")},\n    {_SC(\"weakref\"),obj_delegate_weakref,1, NULL },\n    {_SC(\"tostring\"),default_delegate_tostring,1, _SC(\".\")},\n    {_SC(\"clear\"),obj_clear,1, _SC(\".\")},\n    {_SC(\"map\"),array_map,2, _SC(\"ac\")},\n    {_SC(\"apply\"),array_apply,2, _SC(\"ac\")},\n    {_SC(\"reduce\"),array_reduce,-2, _SC(\"ac.\")},\n    {_SC(\"filter\"),array_filter,2, _SC(\"ac\")},\n    {_SC(\"find\"),array_find,2, _SC(\"a.\")},\n    {NULL,(SQFUNCTION)0,0,NULL}\n};\n\n//STRING DEFAULT DELEGATE//////////////////////////\nstatic SQInteger string_slice(HSQUIRRELVM v)\n{\n    SQInteger sidx,eidx;\n    SQObjectPtr o;\n    if(SQ_FAILED(get_slice_params(v,sidx,eidx,o)))return -1;\n    SQInteger slen = _string(o)->_len;\n    if(sidx < 0)sidx = slen + sidx;\n    if(eidx < 0)eidx = slen + eidx;\n    if(eidx < sidx) return sq_throwerror(v,_SC(\"wrong indexes\"));\n    if(eidx > slen || sidx < 0) return sq_throwerror(v, _SC(\"slice out of range\"));\n    v->Push(SQString::Create(_ss(v),&_stringval(o)[sidx],eidx-sidx));\n    return 1;\n}\n\nstatic SQInteger string_find(HSQUIRRELVM v)\n{\n    SQInteger top,start_idx=0;\n    const SQChar *str,*substr,*ret;\n    if(((top=sq_gettop(v))>1) && SQ_SUCCEEDED(sq_getstring(v,1,&str)) && SQ_SUCCEEDED(sq_getstring(v,2,&substr))){\n        if(top>2)sq_getinteger(v,3,&start_idx);\n        if((sq_getsize(v,1)>start_idx) && (start_idx>=0)){\n            ret=scstrstr(&str[start_idx],substr);\n            if(ret){\n                sq_pushinteger(v,(SQInteger)(ret-str));\n                return 1;\n            }\n        }\n        return 0;\n    }\n    return sq_throwerror(v,_SC(\"invalid param\"));\n}\n\n#define STRING_TOFUNCZ(func) static SQInteger string_##func(HSQUIRRELVM v) \\\n{\\\n    SQInteger sidx,eidx; \\\n    SQObjectPtr str; \\\n    if(SQ_FAILED(get_slice_params(v,sidx,eidx,str)))return -1; \\\n    SQInteger slen = _string(str)->_len; \\\n    if(sidx < 0)sidx = slen + sidx; \\\n    if(eidx < 0)eidx = slen + eidx; \\\n    if(eidx < sidx) return sq_throwerror(v,_SC(\"wrong indexes\")); \\\n    if(eidx > slen || sidx < 0) return sq_throwerror(v,_SC(\"slice out of range\")); \\\n    SQInteger len=_string(str)->_len; \\\n    const SQChar *sthis=_stringval(str); \\\n    SQChar *snew=(_ss(v)->GetScratchPad(sq_rsl(len))); \\\n    memcpy(snew,sthis,sq_rsl(len));\\\n    for(SQInteger i=sidx;i<eidx;i++) snew[i] = func(sthis[i]); \\\n    v->Push(SQString::Create(_ss(v),snew,len)); \\\n    return 1; \\\n}\n\n\nSTRING_TOFUNCZ(tolower)\nSTRING_TOFUNCZ(toupper)\n\nconst SQRegFunction SQSharedState::_string_default_delegate_funcz[]={\n    {_SC(\"len\"),default_delegate_len,1, _SC(\"s\")},\n    {_SC(\"tointeger\"),default_delegate_tointeger,-1, _SC(\"sn\")},\n    {_SC(\"tofloat\"),default_delegate_tofloat,1, _SC(\"s\")},\n    {_SC(\"tostring\"),default_delegate_tostring,1, _SC(\".\")},\n    {_SC(\"slice\"),string_slice,-1, _SC(\"s n  n\")},\n    {_SC(\"find\"),string_find,-2, _SC(\"s s n\")},\n    {_SC(\"tolower\"),string_tolower,-1, _SC(\"s n n\")},\n    {_SC(\"toupper\"),string_toupper,-1, _SC(\"s n n\")},\n    {_SC(\"weakref\"),obj_delegate_weakref,1, NULL },\n    {NULL,(SQFUNCTION)0,0,NULL}\n};\n\n//INTEGER DEFAULT DELEGATE//////////////////////////\nconst SQRegFunction SQSharedState::_number_default_delegate_funcz[]={\n    {_SC(\"tointeger\"),default_delegate_tointeger,1, _SC(\"n|b\")},\n    {_SC(\"tofloat\"),default_delegate_tofloat,1, _SC(\"n|b\")},\n    {_SC(\"tostring\"),default_delegate_tostring,1, _SC(\".\")},\n    {_SC(\"tochar\"),number_delegate_tochar,1, _SC(\"n|b\")},\n    {_SC(\"weakref\"),obj_delegate_weakref,1, NULL },\n    {NULL,(SQFUNCTION)0,0,NULL}\n};\n\n//CLOSURE DEFAULT DELEGATE//////////////////////////\nstatic SQInteger closure_pcall(HSQUIRRELVM v)\n{\n    return SQ_SUCCEEDED(sq_call(v,sq_gettop(v)-1,SQTrue,SQFalse))?1:SQ_ERROR;\n}\n\nstatic SQInteger closure_call(HSQUIRRELVM v)\n{\n\tSQObjectPtr &c = stack_get(v, -1);\n\tif (sq_type(c) == OT_CLOSURE && (_closure(c)->_function->_bgenerator == false))\n\t{\n\t\treturn sq_tailcall(v, sq_gettop(v) - 1);\n\t}\n\treturn SQ_SUCCEEDED(sq_call(v, sq_gettop(v) - 1, SQTrue, SQTrue)) ? 1 : SQ_ERROR;\n}\n\nstatic SQInteger _closure_acall(HSQUIRRELVM v,SQBool raiseerror)\n{\n    SQArray *aparams=_array(stack_get(v,2));\n    SQInteger nparams=aparams->Size();\n    v->Push(stack_get(v,1));\n    for(SQInteger i=0;i<nparams;i++)v->Push(aparams->_values[i]);\n    return SQ_SUCCEEDED(sq_call(v,nparams,SQTrue,raiseerror))?1:SQ_ERROR;\n}\n\nstatic SQInteger closure_acall(HSQUIRRELVM v)\n{\n    return _closure_acall(v,SQTrue);\n}\n\nstatic SQInteger closure_pacall(HSQUIRRELVM v)\n{\n    return _closure_acall(v,SQFalse);\n}\n\nstatic SQInteger closure_bindenv(HSQUIRRELVM v)\n{\n    if(SQ_FAILED(sq_bindenv(v,1)))\n        return SQ_ERROR;\n    return 1;\n}\n\nstatic SQInteger closure_getroot(HSQUIRRELVM v)\n{\n    if(SQ_FAILED(sq_getclosureroot(v,-1)))\n        return SQ_ERROR;\n    return 1;\n}\n\nstatic SQInteger closure_setroot(HSQUIRRELVM v)\n{\n    if(SQ_FAILED(sq_setclosureroot(v,-2)))\n        return SQ_ERROR;\n    return 1;\n}\n\nstatic SQInteger closure_getinfos(HSQUIRRELVM v) {\n    SQObject o = stack_get(v,1);\n    SQTable *res = SQTable::Create(_ss(v),4);\n    if(sq_type(o) == OT_CLOSURE) {\n        SQFunctionProto *f = _closure(o)->_function;\n        SQInteger nparams = f->_nparameters + (f->_varparams?1:0);\n        SQObjectPtr params = SQArray::Create(_ss(v),nparams);\n    SQObjectPtr defparams = SQArray::Create(_ss(v),f->_ndefaultparams);\n        for(SQInteger n = 0; n<f->_nparameters; n++) {\n            _array(params)->Set((SQInteger)n,f->_parameters[n]);\n        }\n    for(SQInteger j = 0; j<f->_ndefaultparams; j++) {\n            _array(defparams)->Set((SQInteger)j,_closure(o)->_defaultparams[j]);\n        }\n        if(f->_varparams) {\n            _array(params)->Set(nparams-1,SQString::Create(_ss(v),_SC(\"...\"),-1));\n        }\n        res->NewSlot(SQString::Create(_ss(v),_SC(\"native\"),-1),false);\n        res->NewSlot(SQString::Create(_ss(v),_SC(\"name\"),-1),f->_name);\n        res->NewSlot(SQString::Create(_ss(v),_SC(\"src\"),-1),f->_sourcename);\n        res->NewSlot(SQString::Create(_ss(v),_SC(\"parameters\"),-1),params);\n        res->NewSlot(SQString::Create(_ss(v),_SC(\"varargs\"),-1),f->_varparams);\n    res->NewSlot(SQString::Create(_ss(v),_SC(\"defparams\"),-1),defparams);\n    }\n    else { //OT_NATIVECLOSURE\n        SQNativeClosure *nc = _nativeclosure(o);\n        res->NewSlot(SQString::Create(_ss(v),_SC(\"native\"),-1),true);\n        res->NewSlot(SQString::Create(_ss(v),_SC(\"name\"),-1),nc->_name);\n        res->NewSlot(SQString::Create(_ss(v),_SC(\"paramscheck\"),-1),nc->_nparamscheck);\n        SQObjectPtr typecheck;\n        if(nc->_typecheck.size() > 0) {\n            typecheck =\n                SQArray::Create(_ss(v), nc->_typecheck.size());\n            for(SQUnsignedInteger n = 0; n<nc->_typecheck.size(); n++) {\n                    _array(typecheck)->Set((SQInteger)n,nc->_typecheck[n]);\n            }\n        }\n        res->NewSlot(SQString::Create(_ss(v),_SC(\"typecheck\"),-1),typecheck);\n    }\n    v->Push(res);\n    return 1;\n}\n\n\n\nconst SQRegFunction SQSharedState::_closure_default_delegate_funcz[]={\n    {_SC(\"call\"),closure_call,-1, _SC(\"c\")},\n    {_SC(\"pcall\"),closure_pcall,-1, _SC(\"c\")},\n    {_SC(\"acall\"),closure_acall,2, _SC(\"ca\")},\n    {_SC(\"pacall\"),closure_pacall,2, _SC(\"ca\")},\n    {_SC(\"weakref\"),obj_delegate_weakref,1, NULL },\n    {_SC(\"tostring\"),default_delegate_tostring,1, _SC(\".\")},\n    {_SC(\"bindenv\"),closure_bindenv,2, _SC(\"c x|y|t\")},\n    {_SC(\"getinfos\"),closure_getinfos,1, _SC(\"c\")},\n    {_SC(\"getroot\"),closure_getroot,1, _SC(\"c\")},\n    {_SC(\"setroot\"),closure_setroot,2, _SC(\"ct\")},\n    {NULL,(SQFUNCTION)0,0,NULL}\n};\n\n//GENERATOR DEFAULT DELEGATE\nstatic SQInteger generator_getstatus(HSQUIRRELVM v)\n{\n    SQObject &o=stack_get(v,1);\n    switch(_generator(o)->_state){\n        case SQGenerator::eSuspended:v->Push(SQString::Create(_ss(v),_SC(\"suspended\")));break;\n        case SQGenerator::eRunning:v->Push(SQString::Create(_ss(v),_SC(\"running\")));break;\n        case SQGenerator::eDead:v->Push(SQString::Create(_ss(v),_SC(\"dead\")));break;\n    }\n    return 1;\n}\n\nconst SQRegFunction SQSharedState::_generator_default_delegate_funcz[]={\n    {_SC(\"getstatus\"),generator_getstatus,1, _SC(\"g\")},\n    {_SC(\"weakref\"),obj_delegate_weakref,1, NULL },\n    {_SC(\"tostring\"),default_delegate_tostring,1, _SC(\".\")},\n    {NULL,(SQFUNCTION)0,0,NULL}\n};\n\n//THREAD DEFAULT DELEGATE\nstatic SQInteger thread_call(HSQUIRRELVM v)\n{\n    SQObjectPtr o = stack_get(v,1);\n    if(sq_type(o) == OT_THREAD) {\n        SQInteger nparams = sq_gettop(v);\n        _thread(o)->Push(_thread(o)->_roottable);\n        for(SQInteger i = 2; i<(nparams+1); i++)\n            sq_move(_thread(o),v,i);\n        if(SQ_SUCCEEDED(sq_call(_thread(o),nparams,SQTrue,SQTrue))) {\n            sq_move(v,_thread(o),-1);\n            sq_pop(_thread(o),1);\n            return 1;\n        }\n        v->_lasterror = _thread(o)->_lasterror;\n        return SQ_ERROR;\n    }\n    return sq_throwerror(v,_SC(\"wrong parameter\"));\n}\n\nstatic SQInteger thread_wakeup(HSQUIRRELVM v)\n{\n    SQObjectPtr o = stack_get(v,1);\n    if(sq_type(o) == OT_THREAD) {\n        SQVM *thread = _thread(o);\n        SQInteger state = sq_getvmstate(thread);\n        if(state != SQ_VMSTATE_SUSPENDED) {\n            switch(state) {\n                case SQ_VMSTATE_IDLE:\n                    return sq_throwerror(v,_SC(\"cannot wakeup a idle thread\"));\n                break;\n                case SQ_VMSTATE_RUNNING:\n                    return sq_throwerror(v,_SC(\"cannot wakeup a running thread\"));\n                break;\n            }\n        }\n\n        SQInteger wakeupret = sq_gettop(v)>1?SQTrue:SQFalse;\n        if(wakeupret) {\n            sq_move(thread,v,2);\n        }\n        if(SQ_SUCCEEDED(sq_wakeupvm(thread,wakeupret,SQTrue,SQTrue,SQFalse))) {\n            sq_move(v,thread,-1);\n            sq_pop(thread,1); //pop retval\n            if(sq_getvmstate(thread) == SQ_VMSTATE_IDLE) {\n                sq_settop(thread,1); //pop roottable\n            }\n            return 1;\n        }\n        sq_settop(thread,1);\n        v->_lasterror = thread->_lasterror;\n        return SQ_ERROR;\n    }\n    return sq_throwerror(v,_SC(\"wrong parameter\"));\n}\n\nstatic SQInteger thread_wakeupthrow(HSQUIRRELVM v)\n{\n    SQObjectPtr o = stack_get(v,1);\n    if(sq_type(o) == OT_THREAD) {\n        SQVM *thread = _thread(o);\n        SQInteger state = sq_getvmstate(thread);\n        if(state != SQ_VMSTATE_SUSPENDED) {\n            switch(state) {\n                case SQ_VMSTATE_IDLE:\n                    return sq_throwerror(v,_SC(\"cannot wakeup a idle thread\"));\n                break;\n                case SQ_VMSTATE_RUNNING:\n                    return sq_throwerror(v,_SC(\"cannot wakeup a running thread\"));\n                break;\n            }\n        }\n\n        sq_move(thread,v,2);\n        sq_throwobject(thread);\n        SQBool rethrow_error = SQTrue;\n        if(sq_gettop(v) > 2) {\n            sq_getbool(v,3,&rethrow_error);\n        }\n        if(SQ_SUCCEEDED(sq_wakeupvm(thread,SQFalse,SQTrue,SQTrue,SQTrue))) {\n            sq_move(v,thread,-1);\n            sq_pop(thread,1); //pop retval\n            if(sq_getvmstate(thread) == SQ_VMSTATE_IDLE) {\n                sq_settop(thread,1); //pop roottable\n            }\n            return 1;\n        }\n        sq_settop(thread,1);\n        if(rethrow_error) {\n            v->_lasterror = thread->_lasterror;\n            return SQ_ERROR;\n        }\n        return SQ_OK;\n    }\n    return sq_throwerror(v,_SC(\"wrong parameter\"));\n}\n\nstatic SQInteger thread_getstatus(HSQUIRRELVM v)\n{\n    SQObjectPtr &o = stack_get(v,1);\n    switch(sq_getvmstate(_thread(o))) {\n        case SQ_VMSTATE_IDLE:\n            sq_pushstring(v,_SC(\"idle\"),-1);\n        break;\n        case SQ_VMSTATE_RUNNING:\n            sq_pushstring(v,_SC(\"running\"),-1);\n        break;\n        case SQ_VMSTATE_SUSPENDED:\n            sq_pushstring(v,_SC(\"suspended\"),-1);\n        break;\n        default:\n            return sq_throwerror(v,_SC(\"internal VM error\"));\n    }\n    return 1;\n}\n\nstatic SQInteger thread_getstackinfos(HSQUIRRELVM v)\n{\n    SQObjectPtr o = stack_get(v,1);\n    if(sq_type(o) == OT_THREAD) {\n        SQVM *thread = _thread(o);\n        SQInteger threadtop = sq_gettop(thread);\n        SQInteger level;\n        sq_getinteger(v,-1,&level);\n        SQRESULT res = __getcallstackinfos(thread,level);\n        if(SQ_FAILED(res))\n        {\n            sq_settop(thread,threadtop);\n            if(sq_type(thread->_lasterror) == OT_STRING) {\n                sq_throwerror(v,_stringval(thread->_lasterror));\n            }\n            else {\n                sq_throwerror(v,_SC(\"unknown error\"));\n            }\n        }\n        if(res > 0) {\n            //some result\n            sq_move(v,thread,-1);\n            sq_settop(thread,threadtop);\n            return 1;\n        }\n        //no result\n        sq_settop(thread,threadtop);\n        return 0;\n\n    }\n    return sq_throwerror(v,_SC(\"wrong parameter\"));\n}\n\nconst SQRegFunction SQSharedState::_thread_default_delegate_funcz[] = {\n    {_SC(\"call\"), thread_call, -1, _SC(\"v\")},\n    {_SC(\"wakeup\"), thread_wakeup, -1, _SC(\"v\")},\n    {_SC(\"wakeupthrow\"), thread_wakeupthrow, -2, _SC(\"v.b\")},\n    {_SC(\"getstatus\"), thread_getstatus, 1, _SC(\"v\")},\n    {_SC(\"weakref\"),obj_delegate_weakref,1, NULL },\n    {_SC(\"getstackinfos\"),thread_getstackinfos,2, _SC(\"vn\")},\n    {_SC(\"tostring\"),default_delegate_tostring,1, _SC(\".\")},\n    {NULL,(SQFUNCTION)0,0,NULL}\n};\n\nstatic SQInteger class_getattributes(HSQUIRRELVM v)\n{\n    return SQ_SUCCEEDED(sq_getattributes(v,-2))?1:SQ_ERROR;\n}\n\nstatic SQInteger class_setattributes(HSQUIRRELVM v)\n{\n    return SQ_SUCCEEDED(sq_setattributes(v,-3))?1:SQ_ERROR;\n}\n\nstatic SQInteger class_instance(HSQUIRRELVM v)\n{\n    return SQ_SUCCEEDED(sq_createinstance(v,-1))?1:SQ_ERROR;\n}\n\nstatic SQInteger class_getbase(HSQUIRRELVM v)\n{\n    return SQ_SUCCEEDED(sq_getbase(v,-1))?1:SQ_ERROR;\n}\n\nstatic SQInteger class_newmember(HSQUIRRELVM v)\n{\n    SQInteger top = sq_gettop(v);\n    SQBool bstatic = SQFalse;\n    if(top == 5)\n    {\n        sq_tobool(v,-1,&bstatic);\n        sq_pop(v,1);\n    }\n\n    if(top < 4) {\n        sq_pushnull(v);\n    }\n    return SQ_SUCCEEDED(sq_newmember(v,-4,bstatic))?1:SQ_ERROR;\n}\n\nstatic SQInteger class_rawnewmember(HSQUIRRELVM v)\n{\n    SQInteger top = sq_gettop(v);\n    SQBool bstatic = SQFalse;\n    if(top == 5)\n    {\n        sq_tobool(v,-1,&bstatic);\n        sq_pop(v,1);\n    }\n\n    if(top < 4) {\n        sq_pushnull(v);\n    }\n    return SQ_SUCCEEDED(sq_rawnewmember(v,-4,bstatic))?1:SQ_ERROR;\n}\n\nconst SQRegFunction SQSharedState::_class_default_delegate_funcz[] = {\n    {_SC(\"getattributes\"), class_getattributes, 2, _SC(\"y.\")},\n    {_SC(\"setattributes\"), class_setattributes, 3, _SC(\"y..\")},\n    {_SC(\"rawget\"),container_rawget,2, _SC(\"y\")},\n    {_SC(\"rawset\"),container_rawset,3, _SC(\"y\")},\n    {_SC(\"rawin\"),container_rawexists,2, _SC(\"y\")},\n    {_SC(\"weakref\"),obj_delegate_weakref,1, NULL },\n    {_SC(\"tostring\"),default_delegate_tostring,1, _SC(\".\")},\n    {_SC(\"instance\"),class_instance,1, _SC(\"y\")},\n    {_SC(\"getbase\"),class_getbase,1, _SC(\"y\")},\n    {_SC(\"newmember\"),class_newmember,-3, _SC(\"y\")},\n    {_SC(\"rawnewmember\"),class_rawnewmember,-3, _SC(\"y\")},\n    {NULL,(SQFUNCTION)0,0,NULL}\n};\n\n\nstatic SQInteger instance_getclass(HSQUIRRELVM v)\n{\n    if(SQ_SUCCEEDED(sq_getclass(v,1)))\n        return 1;\n    return SQ_ERROR;\n}\n\nconst SQRegFunction SQSharedState::_instance_default_delegate_funcz[] = {\n    {_SC(\"getclass\"), instance_getclass, 1, _SC(\"x\")},\n    {_SC(\"rawget\"),container_rawget,2, _SC(\"x\")},\n    {_SC(\"rawset\"),container_rawset,3, _SC(\"x\")},\n    {_SC(\"rawin\"),container_rawexists,2, _SC(\"x\")},\n    {_SC(\"weakref\"),obj_delegate_weakref,1, NULL },\n    {_SC(\"tostring\"),default_delegate_tostring,1, _SC(\".\")},\n    {NULL,(SQFUNCTION)0,0,NULL}\n};\n\nstatic SQInteger weakref_ref(HSQUIRRELVM v)\n{\n    if(SQ_FAILED(sq_getweakrefval(v,1)))\n        return SQ_ERROR;\n    return 1;\n}\n\nconst SQRegFunction SQSharedState::_weakref_default_delegate_funcz[] = {\n    {_SC(\"ref\"),weakref_ref,1, _SC(\"r\")},\n    {_SC(\"weakref\"),obj_delegate_weakref,1, NULL },\n    {_SC(\"tostring\"),default_delegate_tostring,1, _SC(\".\")},\n    {NULL,(SQFUNCTION)0,0,NULL}\n};\n"
  },
  {
    "path": "extlibs/squirrel/squirrel/sqclass.cpp",
    "content": "/*\n    see copyright notice in squirrel.h\n*/\n#include \"sqpcheader.h\"\n#include \"sqvm.h\"\n#include \"sqtable.h\"\n#include \"sqclass.h\"\n#include \"sqfuncproto.h\"\n#include \"sqclosure.h\"\n\n\n\nSQClass::SQClass(SQSharedState *ss,SQClass *base)\n{\n    _base = base;\n    _typetag = 0;\n    _hook = NULL;\n    _udsize = 0;\n    _locked = false;\n    _constructoridx = -1;\n    if(_base) {\n        _constructoridx = _base->_constructoridx;\n        _udsize = _base->_udsize;\n        _defaultvalues.copy(base->_defaultvalues);\n        _methods.copy(base->_methods);\n        _COPY_VECTOR(_metamethods,base->_metamethods,MT_LAST);\n        __ObjAddRef(_base);\n    }\n    _members = base?base->_members->Clone() : SQTable::Create(ss,0);\n    __ObjAddRef(_members);\n\n    INIT_CHAIN();\n    ADD_TO_CHAIN(&_sharedstate->_gc_chain, this);\n}\n\nvoid SQClass::Finalize() {\n    _attributes.Null();\n    _NULL_SQOBJECT_VECTOR(_defaultvalues,_defaultvalues.size());\n    _methods.resize(0);\n    _NULL_SQOBJECT_VECTOR(_metamethods,MT_LAST);\n    __ObjRelease(_members);\n    if(_base) {\n        __ObjRelease(_base);\n    }\n}\n\nSQClass::~SQClass()\n{\n    REMOVE_FROM_CHAIN(&_sharedstate->_gc_chain, this);\n    Finalize();\n}\n\nbool SQClass::NewSlot(SQSharedState *ss,const SQObjectPtr &key,const SQObjectPtr &val,bool bstatic)\n{\n    SQObjectPtr temp;\n    bool belongs_to_static_table = sq_type(val) == OT_CLOSURE || sq_type(val) == OT_NATIVECLOSURE || bstatic;\n    if(_locked && !belongs_to_static_table)\n        return false; //the class already has an instance so cannot be modified\n    if(_members->Get(key,temp) && _isfield(temp)) //overrides the default value\n    {\n        _defaultvalues[_member_idx(temp)].val = val;\n        return true;\n    }\n    if(belongs_to_static_table) {\n        SQInteger mmidx;\n        if((sq_type(val) == OT_CLOSURE || sq_type(val) == OT_NATIVECLOSURE) &&\n            (mmidx = ss->GetMetaMethodIdxByName(key)) != -1) {\n            _metamethods[mmidx] = val;\n        }\n        else {\n            SQObjectPtr theval = val;\n            if(_base && sq_type(val) == OT_CLOSURE) {\n                theval = _closure(val)->Clone();\n                _closure(theval)->_base = _base;\n                __ObjAddRef(_base); //ref for the closure\n            }\n            if(sq_type(temp) == OT_NULL) {\n                bool isconstructor;\n                SQVM::IsEqual(ss->_constructoridx, key, isconstructor);\n                if(isconstructor) {\n                    _constructoridx = (SQInteger)_methods.size();\n                }\n                SQClassMember m;\n                m.val = theval;\n                _members->NewSlot(key,SQObjectPtr(_make_method_idx(_methods.size())));\n                _methods.push_back(m);\n            }\n            else {\n                _methods[_member_idx(temp)].val = theval;\n            }\n        }\n        return true;\n    }\n    SQClassMember m;\n    m.val = val;\n    _members->NewSlot(key,SQObjectPtr(_make_field_idx(_defaultvalues.size())));\n    _defaultvalues.push_back(m);\n    return true;\n}\n\nSQInstance *SQClass::CreateInstance()\n{\n    if(!_locked) Lock();\n    return SQInstance::Create(_opt_ss(this),this);\n}\n\nSQInteger SQClass::Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval)\n{\n    SQObjectPtr oval;\n    SQInteger idx = _members->Next(false,refpos,outkey,oval);\n    if(idx != -1) {\n        if(_ismethod(oval)) {\n            outval = _methods[_member_idx(oval)].val;\n        }\n        else {\n            SQObjectPtr &o = _defaultvalues[_member_idx(oval)].val;\n            outval = _realval(o);\n        }\n    }\n    return idx;\n}\n\nbool SQClass::SetAttributes(const SQObjectPtr &key,const SQObjectPtr &val)\n{\n    SQObjectPtr idx;\n    if(_members->Get(key,idx)) {\n        if(_isfield(idx))\n            _defaultvalues[_member_idx(idx)].attrs = val;\n        else\n            _methods[_member_idx(idx)].attrs = val;\n        return true;\n    }\n    return false;\n}\n\nbool SQClass::GetAttributes(const SQObjectPtr &key,SQObjectPtr &outval)\n{\n    SQObjectPtr idx;\n    if(_members->Get(key,idx)) {\n        outval = (_isfield(idx)?_defaultvalues[_member_idx(idx)].attrs:_methods[_member_idx(idx)].attrs);\n        return true;\n    }\n    return false;\n}\n\n///////////////////////////////////////////////////////////////////////\nvoid SQInstance::Init(SQSharedState *ss)\n{\n    _userpointer = NULL;\n    _hook = NULL;\n    __ObjAddRef(_class);\n    _delegate = _class->_members;\n    INIT_CHAIN();\n    ADD_TO_CHAIN(&_sharedstate->_gc_chain, this);\n}\n\nSQInstance::SQInstance(SQSharedState *ss, SQClass *c, SQInteger memsize)\n{\n    _memsize = memsize;\n    _class = c;\n    SQUnsignedInteger nvalues = _class->_defaultvalues.size();\n    for(SQUnsignedInteger n = 0; n < nvalues; n++) {\n        new (&_values[n]) SQObjectPtr(_class->_defaultvalues[n].val);\n    }\n    Init(ss);\n}\n\nSQInstance::SQInstance(SQSharedState *ss, SQInstance *i, SQInteger memsize)\n{\n    _memsize = memsize;\n    _class = i->_class;\n    SQUnsignedInteger nvalues = _class->_defaultvalues.size();\n    for(SQUnsignedInteger n = 0; n < nvalues; n++) {\n        new (&_values[n]) SQObjectPtr(i->_values[n]);\n    }\n    Init(ss);\n}\n\nvoid SQInstance::Finalize()\n{\n    SQUnsignedInteger nvalues = _class->_defaultvalues.size();\n    __ObjRelease(_class);\n    _NULL_SQOBJECT_VECTOR(_values,nvalues);\n}\n\nSQInstance::~SQInstance()\n{\n    REMOVE_FROM_CHAIN(&_sharedstate->_gc_chain, this);\n    if(_class){ Finalize(); } //if _class is null it was already finalized by the GC\n}\n\nbool SQInstance::GetMetaMethod(SQVM* SQ_UNUSED_ARG(v),SQMetaMethod mm,SQObjectPtr &res)\n{\n    if(sq_type(_class->_metamethods[mm]) != OT_NULL) {\n        res = _class->_metamethods[mm];\n        return true;\n    }\n    return false;\n}\n\nbool SQInstance::InstanceOf(SQClass *trg)\n{\n    SQClass *parent = _class;\n    while(parent != NULL) {\n        if(parent == trg)\n            return true;\n        parent = parent->_base;\n    }\n    return false;\n}\n"
  },
  {
    "path": "extlibs/squirrel/squirrel/sqclass.h",
    "content": "/*  see copyright notice in squirrel.h */\n#ifndef _SQCLASS_H_\n#define _SQCLASS_H_\n\nstruct SQInstance;\n\nstruct SQClassMember {\n    SQObjectPtr val;\n    SQObjectPtr attrs;\n    void Null() {\n        val.Null();\n        attrs.Null();\n    }\n};\n\ntypedef sqvector<SQClassMember> SQClassMemberVec;\n\n#define MEMBER_TYPE_METHOD 0x01000000\n#define MEMBER_TYPE_FIELD 0x02000000\n\n#define _ismethod(o) (_integer(o)&MEMBER_TYPE_METHOD)\n#define _isfield(o) (_integer(o)&MEMBER_TYPE_FIELD)\n#define _make_method_idx(i) ((SQInteger)(MEMBER_TYPE_METHOD|i))\n#define _make_field_idx(i) ((SQInteger)(MEMBER_TYPE_FIELD|i))\n#define _member_type(o) (_integer(o)&0xFF000000)\n#define _member_idx(o) (_integer(o)&0x00FFFFFF)\n\nstruct SQClass : public CHAINABLE_OBJ\n{\n    SQClass(SQSharedState *ss,SQClass *base);\npublic:\n    static SQClass* Create(SQSharedState *ss,SQClass *base) {\n        SQClass *newclass = (SQClass *)SQ_MALLOC(sizeof(SQClass));\n        new (newclass) SQClass(ss, base);\n        return newclass;\n    }\n    ~SQClass();\n    bool NewSlot(SQSharedState *ss, const SQObjectPtr &key,const SQObjectPtr &val,bool bstatic);\n    bool Get(const SQObjectPtr &key,SQObjectPtr &val) {\n        if(_members->Get(key,val)) {\n            if(_isfield(val)) {\n                SQObjectPtr &o = _defaultvalues[_member_idx(val)].val;\n                val = _realval(o);\n            }\n            else {\n                val = _methods[_member_idx(val)].val;\n            }\n            return true;\n        }\n        return false;\n    }\n    bool GetConstructor(SQObjectPtr &ctor)\n    {\n        if(_constructoridx != -1) {\n            ctor = _methods[_constructoridx].val;\n            return true;\n        }\n        return false;\n    }\n    bool SetAttributes(const SQObjectPtr &key,const SQObjectPtr &val);\n    bool GetAttributes(const SQObjectPtr &key,SQObjectPtr &outval);\n    void Lock() { _locked = true; if(_base) _base->Lock(); }\n    void Release() {\n        if (_hook) { _hook(_typetag,0);}\n        sq_delete(this, SQClass);\n    }\n    void Finalize();\n#ifndef NO_GARBAGE_COLLECTOR\n    void Mark(SQCollectable ** );\n    SQObjectType GetType() {return OT_CLASS;}\n#endif\n    SQInteger Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval);\n    SQInstance *CreateInstance();\n    SQTable *_members;\n    SQClass *_base;\n    SQClassMemberVec _defaultvalues;\n    SQClassMemberVec _methods;\n    SQObjectPtr _metamethods[MT_LAST];\n    SQObjectPtr _attributes;\n    SQUserPointer _typetag;\n    SQRELEASEHOOK _hook;\n    bool _locked;\n    SQInteger _constructoridx;\n    SQInteger _udsize;\n};\n\n#define calcinstancesize(_theclass_) \\\n    (_theclass_->_udsize + sq_aligning(sizeof(SQInstance) +  (sizeof(SQObjectPtr)*(_theclass_->_defaultvalues.size()>0?_theclass_->_defaultvalues.size()-1:0))))\n\nstruct SQInstance : public SQDelegable\n{\n    void Init(SQSharedState *ss);\n    SQInstance(SQSharedState *ss, SQClass *c, SQInteger memsize);\n    SQInstance(SQSharedState *ss, SQInstance *c, SQInteger memsize);\npublic:\n    static SQInstance* Create(SQSharedState *ss,SQClass *theclass) {\n\n        SQInteger size = calcinstancesize(theclass);\n        SQInstance *newinst = (SQInstance *)SQ_MALLOC(size);\n        new (newinst) SQInstance(ss, theclass,size);\n        if(theclass->_udsize) {\n            newinst->_userpointer = ((unsigned char *)newinst) + (size - theclass->_udsize);\n        }\n        return newinst;\n    }\n    SQInstance *Clone(SQSharedState *ss)\n    {\n        SQInteger size = calcinstancesize(_class);\n        SQInstance *newinst = (SQInstance *)SQ_MALLOC(size);\n        new (newinst) SQInstance(ss, this,size);\n        if(_class->_udsize) {\n            newinst->_userpointer = ((unsigned char *)newinst) + (size - _class->_udsize);\n        }\n        return newinst;\n    }\n    ~SQInstance();\n    bool Get(const SQObjectPtr &key,SQObjectPtr &val)  {\n        if(_class->_members->Get(key,val)) {\n            if(_isfield(val)) {\n                SQObjectPtr &o = _values[_member_idx(val)];\n                val = _realval(o);\n            }\n            else {\n                val = _class->_methods[_member_idx(val)].val;\n            }\n            return true;\n        }\n        return false;\n    }\n    bool Set(const SQObjectPtr &key,const SQObjectPtr &val) {\n        SQObjectPtr idx;\n        if(_class->_members->Get(key,idx) && _isfield(idx)) {\n            _values[_member_idx(idx)] = val;\n            return true;\n        }\n        return false;\n    }\n    void Release() {\n        _uiRef++;\n        if (_hook) { _hook(_userpointer,0);}\n        _uiRef--;\n        if(_uiRef > 0) return;\n        SQInteger size = _memsize;\n        this->~SQInstance();\n        SQ_FREE(this, size);\n    }\n    void Finalize();\n#ifndef NO_GARBAGE_COLLECTOR\n    void Mark(SQCollectable ** );\n    SQObjectType GetType() {return OT_INSTANCE;}\n#endif\n    bool InstanceOf(SQClass *trg);\n    bool GetMetaMethod(SQVM *v,SQMetaMethod mm,SQObjectPtr &res);\n\n    SQClass *_class;\n    SQUserPointer _userpointer;\n    SQRELEASEHOOK _hook;\n    SQInteger _memsize;\n    SQObjectPtr _values[1];\n};\n\n#endif //_SQCLASS_H_\n"
  },
  {
    "path": "extlibs/squirrel/squirrel/sqclosure.h",
    "content": "/*  see copyright notice in squirrel.h */\n#ifndef _SQCLOSURE_H_\n#define _SQCLOSURE_H_\n\n\n#define _CALC_CLOSURE_SIZE(func) (sizeof(SQClosure) + (func->_noutervalues*sizeof(SQObjectPtr)) + (func->_ndefaultparams*sizeof(SQObjectPtr)))\n\nstruct SQFunctionProto;\nstruct SQClass;\nstruct SQClosure : public CHAINABLE_OBJ\n{\nprivate:\n    SQClosure(SQSharedState *ss,SQFunctionProto *func){_function = func; __ObjAddRef(_function); _base = NULL; INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this); _env = NULL; _root=NULL;}\npublic:\n    static SQClosure *Create(SQSharedState *ss,SQFunctionProto *func,SQWeakRef *root){\n        SQInteger size = _CALC_CLOSURE_SIZE(func);\n        SQClosure *nc=(SQClosure*)SQ_MALLOC(size);\n        new (nc) SQClosure(ss,func);\n        nc->_outervalues = (SQObjectPtr *)(nc + 1);\n        nc->_defaultparams = &nc->_outervalues[func->_noutervalues];\n        nc->_root = root;\n         __ObjAddRef(nc->_root);\n        _CONSTRUCT_VECTOR(SQObjectPtr,func->_noutervalues,nc->_outervalues);\n        _CONSTRUCT_VECTOR(SQObjectPtr,func->_ndefaultparams,nc->_defaultparams);\n        return nc;\n    }\n    void Release(){\n        SQFunctionProto *f = _function;\n        SQInteger size = _CALC_CLOSURE_SIZE(f);\n        _DESTRUCT_VECTOR(SQObjectPtr,f->_noutervalues,_outervalues);\n        _DESTRUCT_VECTOR(SQObjectPtr,f->_ndefaultparams,_defaultparams);\n        __ObjRelease(_function);\n        this->~SQClosure();\n        sq_vm_free(this,size);\n    }\n    void SetRoot(SQWeakRef *r)\n    {\n        __ObjRelease(_root);\n        _root = r;\n        __ObjAddRef(_root);\n    }\n    SQClosure *Clone()\n    {\n        SQFunctionProto *f = _function;\n        SQClosure * ret = SQClosure::Create(_opt_ss(this),f,_root);\n        ret->_env = _env;\n        if(ret->_env) __ObjAddRef(ret->_env);\n        _COPY_VECTOR(ret->_outervalues,_outervalues,f->_noutervalues);\n        _COPY_VECTOR(ret->_defaultparams,_defaultparams,f->_ndefaultparams);\n        return ret;\n    }\n    ~SQClosure();\n\n    bool Save(SQVM *v,SQUserPointer up,SQWRITEFUNC write);\n    static bool Load(SQVM *v,SQUserPointer up,SQREADFUNC read,SQObjectPtr &ret);\n#ifndef NO_GARBAGE_COLLECTOR\n    void Mark(SQCollectable **chain);\n    void Finalize(){\n        SQFunctionProto *f = _function;\n        _NULL_SQOBJECT_VECTOR(_outervalues,f->_noutervalues);\n        _NULL_SQOBJECT_VECTOR(_defaultparams,f->_ndefaultparams);\n    }\n    SQObjectType GetType() {return OT_CLOSURE;}\n#endif\n    SQWeakRef *_env;\n    SQWeakRef *_root;\n    SQClass *_base;\n    SQFunctionProto *_function;\n    SQObjectPtr *_outervalues;\n    SQObjectPtr *_defaultparams;\n};\n\n//////////////////////////////////////////////\nstruct SQOuter : public CHAINABLE_OBJ\n{\n\nprivate:\n    SQOuter(SQSharedState *ss, SQObjectPtr *outer){_valptr = outer; _next = NULL; INIT_CHAIN(); ADD_TO_CHAIN(&_ss(this)->_gc_chain,this); }\n\npublic:\n    static SQOuter *Create(SQSharedState *ss, SQObjectPtr *outer)\n    {\n        SQOuter *nc  = (SQOuter*)SQ_MALLOC(sizeof(SQOuter));\n        new (nc) SQOuter(ss, outer);\n        return nc;\n    }\n    ~SQOuter() { REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this); }\n\n    void Release()\n    {\n        this->~SQOuter();\n        sq_vm_free(this,sizeof(SQOuter));\n    }\n\n#ifndef NO_GARBAGE_COLLECTOR\n    void Mark(SQCollectable **chain);\n    void Finalize() { _value.Null(); }\n    SQObjectType GetType() {return OT_OUTER;}\n#endif\n\n    SQObjectPtr *_valptr;  /* pointer to value on stack, or _value below */\n    SQInteger    _idx;     /* idx in stack array, for relocation */\n    SQObjectPtr  _value;   /* value of outer after stack frame is closed */\n    SQOuter     *_next;    /* pointer to next outer when frame is open   */\n};\n\n//////////////////////////////////////////////\nstruct SQGenerator : public CHAINABLE_OBJ\n{\n    enum SQGeneratorState{eRunning,eSuspended,eDead};\nprivate:\n    SQGenerator(SQSharedState *ss,SQClosure *closure){_closure=closure;_state=eRunning;_ci._generator=NULL;INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this);}\npublic:\n    static SQGenerator *Create(SQSharedState *ss,SQClosure *closure){\n        SQGenerator *nc=(SQGenerator*)SQ_MALLOC(sizeof(SQGenerator));\n        new (nc) SQGenerator(ss,closure);\n        return nc;\n    }\n    ~SQGenerator()\n    {\n        REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this);\n    }\n    void Kill(){\n        _state=eDead;\n        _stack.resize(0);\n        _closure.Null();}\n    void Release(){\n        sq_delete(this,SQGenerator);\n    }\n\n    bool Yield(SQVM *v,SQInteger target);\n    bool Resume(SQVM *v,SQObjectPtr &dest);\n#ifndef NO_GARBAGE_COLLECTOR\n    void Mark(SQCollectable **chain);\n    void Finalize(){_stack.resize(0);_closure.Null();}\n    SQObjectType GetType() {return OT_GENERATOR;}\n#endif\n    SQObjectPtr _closure;\n    SQObjectPtrVec _stack;\n    SQVM::CallInfo _ci;\n    ExceptionsTraps _etraps;\n    SQGeneratorState _state;\n};\n\n#define _CALC_NATVIVECLOSURE_SIZE(noutervalues) (sizeof(SQNativeClosure) + (noutervalues*sizeof(SQObjectPtr)))\n\nstruct SQNativeClosure : public CHAINABLE_OBJ\n{\nprivate:\n    SQNativeClosure(SQSharedState *ss,SQFUNCTION func){_function=func;INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this); _env = NULL;}\npublic:\n    static SQNativeClosure *Create(SQSharedState *ss,SQFUNCTION func,SQInteger nouters)\n    {\n        SQInteger size = _CALC_NATVIVECLOSURE_SIZE(nouters);\n        SQNativeClosure *nc=(SQNativeClosure*)SQ_MALLOC(size);\n        new (nc) SQNativeClosure(ss,func);\n        nc->_outervalues = (SQObjectPtr *)(nc + 1);\n        nc->_noutervalues = nouters;\n        _CONSTRUCT_VECTOR(SQObjectPtr,nc->_noutervalues,nc->_outervalues);\n        return nc;\n    }\n    SQNativeClosure *Clone()\n    {\n        SQNativeClosure * ret = SQNativeClosure::Create(_opt_ss(this),_function,_noutervalues);\n        ret->_env = _env;\n        if(ret->_env) __ObjAddRef(ret->_env);\n        ret->_name = _name;\n        _COPY_VECTOR(ret->_outervalues,_outervalues,_noutervalues);\n        ret->_typecheck.copy(_typecheck);\n        ret->_nparamscheck = _nparamscheck;\n        return ret;\n    }\n    ~SQNativeClosure()\n    {\n        __ObjRelease(_env);\n        REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this);\n    }\n    void Release(){\n        SQInteger size = _CALC_NATVIVECLOSURE_SIZE(_noutervalues);\n        _DESTRUCT_VECTOR(SQObjectPtr,_noutervalues,_outervalues);\n        this->~SQNativeClosure();\n        sq_free(this,size);\n    }\n\n#ifndef NO_GARBAGE_COLLECTOR\n    void Mark(SQCollectable **chain);\n    void Finalize() { _NULL_SQOBJECT_VECTOR(_outervalues,_noutervalues); }\n    SQObjectType GetType() {return OT_NATIVECLOSURE;}\n#endif\n    SQInteger _nparamscheck;\n    SQIntVec _typecheck;\n    SQObjectPtr *_outervalues;\n    SQUnsignedInteger _noutervalues;\n    SQWeakRef *_env;\n    SQFUNCTION _function;\n    SQObjectPtr _name;\n};\n\n\n\n#endif //_SQCLOSURE_H_\n"
  },
  {
    "path": "extlibs/squirrel/squirrel/sqcompiler.cpp",
    "content": "/*\n    see copyright notice in squirrel.h\n*/\n#include \"sqpcheader.h\"\n#ifndef NO_COMPILER\n#include <stdarg.h>\n#include <setjmp.h>\n#include \"sqopcodes.h\"\n#include \"sqstring.h\"\n#include \"sqfuncproto.h\"\n#include \"sqcompiler.h\"\n#include \"sqfuncstate.h\"\n#include \"sqlexer.h\"\n#include \"sqvm.h\"\n#include \"sqtable.h\"\n\n#define EXPR   1\n#define OBJECT 2\n#define BASE   3\n#define LOCAL  4\n#define OUTER  5\n\nstruct SQExpState {\n  SQInteger  etype;       /* expr. type; one of EXPR, OBJECT, BASE, OUTER or LOCAL */\n  SQInteger  epos;        /* expr. location on stack; -1 for OBJECT and BASE */\n  bool       donot_get;   /* signal not to deref the next value */\n};\n\n#define MAX_COMPILER_ERROR_LEN 256\n\nstruct SQScope {\n    SQInteger outers;\n    SQInteger stacksize;\n};\n\n#define BEGIN_SCOPE() SQScope __oldscope__ = _scope; \\\n                     _scope.outers = _fs->_outers; \\\n                     _scope.stacksize = _fs->GetStackSize();\n\n#define RESOLVE_OUTERS() if(_fs->GetStackSize() != _scope.stacksize) { \\\n                            if(_fs->CountOuters(_scope.stacksize)) { \\\n                                _fs->AddInstruction(_OP_CLOSE,0,_scope.stacksize); \\\n                            } \\\n                        }\n\n#define END_SCOPE_NO_CLOSE() {  if(_fs->GetStackSize() != _scope.stacksize) { \\\n                            _fs->SetStackSize(_scope.stacksize); \\\n                        } \\\n                        _scope = __oldscope__; \\\n                    }\n\n#define END_SCOPE() {   SQInteger oldouters = _fs->_outers;\\\n                        if(_fs->GetStackSize() != _scope.stacksize) { \\\n                            _fs->SetStackSize(_scope.stacksize); \\\n                            if(oldouters != _fs->_outers) { \\\n                                _fs->AddInstruction(_OP_CLOSE,0,_scope.stacksize); \\\n                            } \\\n                        } \\\n                        _scope = __oldscope__; \\\n                    }\n\n#define BEGIN_BREAKBLE_BLOCK()  SQInteger __nbreaks__=_fs->_unresolvedbreaks.size(); \\\n                            SQInteger __ncontinues__=_fs->_unresolvedcontinues.size(); \\\n                            _fs->_breaktargets.push_back(0);_fs->_continuetargets.push_back(0);\n\n#define END_BREAKBLE_BLOCK(continue_target) {__nbreaks__=_fs->_unresolvedbreaks.size()-__nbreaks__; \\\n                    __ncontinues__=_fs->_unresolvedcontinues.size()-__ncontinues__; \\\n                    if(__ncontinues__>0)ResolveContinues(_fs,__ncontinues__,continue_target); \\\n                    if(__nbreaks__>0)ResolveBreaks(_fs,__nbreaks__); \\\n                    _fs->_breaktargets.pop_back();_fs->_continuetargets.pop_back();}\n\nclass SQCompiler\n{\npublic:\n    SQCompiler(SQVM *v, SQLEXREADFUNC rg, SQUserPointer up, const SQChar* sourcename, bool raiseerror, bool lineinfo)\n    {\n        _vm=v;\n        _lex.Init(_ss(v), rg, up,ThrowError,this);\n        _sourcename = SQString::Create(_ss(v), sourcename);\n        _lineinfo = lineinfo;_raiseerror = raiseerror;\n        _scope.outers = 0;\n        _scope.stacksize = 0;\n        _compilererror[0] = _SC('\\0');\n    }\n    static void ThrowError(void *ud, const SQChar *s) {\n        SQCompiler *c = (SQCompiler *)ud;\n        c->Error(s);\n    }\n    void Error(const SQChar *s, ...)\n    {\n        va_list vl;\n        va_start(vl, s);\n        scvsprintf(_compilererror, MAX_COMPILER_ERROR_LEN, s, vl);\n        va_end(vl);\n        longjmp(_errorjmp,1);\n    }\n    void Lex(){ _token = _lex.Lex();}\n    SQObject Expect(SQInteger tok)\n    {\n\n        if(_token != tok) {\n            if(_token == TK_CONSTRUCTOR && tok == TK_IDENTIFIER) {\n                //do nothing\n            }\n            else {\n                const SQChar *etypename;\n                if(tok > 255) {\n                    switch(tok)\n                    {\n                    case TK_IDENTIFIER:\n                        etypename = _SC(\"IDENTIFIER\");\n                        break;\n                    case TK_STRING_LITERAL:\n                        etypename = _SC(\"STRING_LITERAL\");\n                        break;\n                    case TK_INTEGER:\n                        etypename = _SC(\"INTEGER\");\n                        break;\n                    case TK_FLOAT:\n                        etypename = _SC(\"FLOAT\");\n                        break;\n                    default:\n                        etypename = _lex.Tok2Str(tok);\n                    }\n                    Error(_SC(\"expected '%s'\"), etypename);\n                }\n                Error(_SC(\"expected '%c'\"), tok);\n            }\n        }\n        SQObjectPtr ret;\n        switch(tok)\n        {\n        case TK_IDENTIFIER:\n            ret = _fs->CreateString(_lex._svalue);\n            break;\n        case TK_STRING_LITERAL:\n            ret = _fs->CreateString(_lex._svalue,_lex._longstr.size()-1);\n            break;\n        case TK_INTEGER:\n            ret = SQObjectPtr(_lex._nvalue);\n            break;\n        case TK_FLOAT:\n            ret = SQObjectPtr(_lex._fvalue);\n            break;\n        }\n        Lex();\n        return ret;\n    }\n    bool IsEndOfStatement() { return ((_lex._prevtoken == _SC('\\n')) || (_token == SQUIRREL_EOB) || (_token == _SC('}')) || (_token == _SC(';'))); }\n    void OptionalSemicolon()\n    {\n        if(_token == _SC(';')) { Lex(); return; }        \n    }\n    void MoveIfCurrentTargetIsLocal() {\n        SQInteger trg = _fs->TopTarget();\n        if(_fs->IsLocal(trg)) {\n            trg = _fs->PopTarget(); //pops the target and moves it\n            _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), trg);\n        }\n    }\n    bool Compile(SQObjectPtr &o)\n    {\n        _debugline = 1;\n        _debugop = 0;\n\n        SQFuncState funcstate(_ss(_vm), NULL,ThrowError,this);\n        funcstate._name = SQString::Create(_ss(_vm), _SC(\"main\"));\n        _fs = &funcstate;\n        _fs->AddParameter(_fs->CreateString(_SC(\"this\")));\n        _fs->AddParameter(_fs->CreateString(_SC(\"vargv\")));\n        _fs->_varparams = true;\n        _fs->_sourcename = _sourcename;\n        SQInteger stacksize = _fs->GetStackSize();\n        if(setjmp(_errorjmp) == 0) {\n            Lex();\n            while(_token > 0){\n                Statement();\n                if(_lex._prevtoken != _SC('}') && _lex._prevtoken != _SC(';')) OptionalSemicolon();\n            }\n            _fs->SetStackSize(stacksize);\n            _fs->AddLineInfos(_lex._currentline, _lineinfo, true);\n            _fs->AddInstruction(_OP_RETURN, 0xFF);\n            _fs->SetStackSize(0);\n            o =_fs->BuildProto();\n#ifdef _DEBUG_DUMP\n            _fs->Dump(_funcproto(o));\n#endif\n        }\n        else {\n            if(_raiseerror && _ss(_vm)->_compilererrorhandler) {\n                _ss(_vm)->_compilererrorhandler(_vm, _compilererror, sq_type(_sourcename) == OT_STRING?_stringval(_sourcename):_SC(\"unknown\"),\n                    _lex._currentline, _lex._currentcolumn);\n            }\n            _vm->_lasterror = SQString::Create(_ss(_vm), _compilererror, -1);\n            return false;\n        }\n        return true;\n    }\n    void Statements()\n    {\n        while(_token != _SC('}') && _token != TK_DEFAULT && _token != TK_CASE) {\n            Statement();\n            if(_lex._prevtoken != _SC('}') && _lex._prevtoken != _SC(';')) OptionalSemicolon();\n        }\n    }\n    void Statement(bool closeframe = true)\n    {\n        _fs->AddLineInfos(_lex._currentline, _lineinfo);\n        switch(_token){\n        case _SC(';'):  Lex();                  break;\n        case TK_IF:     IfStatement();          break;\n        case TK_WHILE:      WhileStatement();       break;\n        case TK_DO:     DoWhileStatement();     break;\n        case TK_FOR:        ForStatement();         break;\n        case TK_FOREACH:    ForEachStatement();     break;\n        case TK_SWITCH: SwitchStatement();      break;\n        case TK_LOCAL:      LocalDeclStatement();   break;\n        case TK_RETURN:\n        case TK_YIELD: {\n            SQOpcode op;\n            if(_token == TK_RETURN) {\n                op = _OP_RETURN;\n            }\n            else {\n                op = _OP_YIELD;\n                _fs->_bgenerator = true;\n            }\n            Lex();\n            if(!IsEndOfStatement()) {\n                SQInteger retexp = _fs->GetCurrentPos()+1;\n                CommaExpr();\n                if(op == _OP_RETURN && _fs->_traps > 0)\n                    _fs->AddInstruction(_OP_POPTRAP, _fs->_traps, 0);\n                _fs->_returnexp = retexp;\n                _fs->AddInstruction(op, 1, _fs->PopTarget(),_fs->GetStackSize());\n            }\n            else{\n                if(op == _OP_RETURN && _fs->_traps > 0)\n                    _fs->AddInstruction(_OP_POPTRAP, _fs->_traps ,0);\n                _fs->_returnexp = -1;\n                _fs->AddInstruction(op, 0xFF,0,_fs->GetStackSize());\n            }\n            break;}\n        case TK_BREAK:\n            if(_fs->_breaktargets.size() <= 0)Error(_SC(\"'break' has to be in a loop block\"));\n            if(_fs->_breaktargets.top() > 0){\n                _fs->AddInstruction(_OP_POPTRAP, _fs->_breaktargets.top(), 0);\n            }\n            RESOLVE_OUTERS();\n            _fs->AddInstruction(_OP_JMP, 0, -1234);\n            _fs->_unresolvedbreaks.push_back(_fs->GetCurrentPos());\n            Lex();\n            break;\n        case TK_CONTINUE:\n            if(_fs->_continuetargets.size() <= 0)Error(_SC(\"'continue' has to be in a loop block\"));\n            if(_fs->_continuetargets.top() > 0) {\n                _fs->AddInstruction(_OP_POPTRAP, _fs->_continuetargets.top(), 0);\n            }\n            RESOLVE_OUTERS();\n            _fs->AddInstruction(_OP_JMP, 0, -1234);\n            _fs->_unresolvedcontinues.push_back(_fs->GetCurrentPos());\n            Lex();\n            break;\n        case TK_FUNCTION:\n            FunctionStatement();\n            break;\n        case TK_CLASS:\n            ClassStatement();\n            break;\n        case TK_ENUM:\n            EnumStatement();\n            break;\n        case _SC('{'):{\n                BEGIN_SCOPE();\n                Lex();\n                Statements();\n                Expect(_SC('}'));\n                if(closeframe) {\n                    END_SCOPE();\n                }\n                else {\n                    END_SCOPE_NO_CLOSE();\n                }\n            }\n            break;\n        case TK_TRY:\n            TryCatchStatement();\n            break;\n        case TK_THROW:\n            Lex();\n            CommaExpr();\n            _fs->AddInstruction(_OP_THROW, _fs->PopTarget());\n            break;\n        case TK_CONST:\n            {\n            Lex();\n            SQObject id = Expect(TK_IDENTIFIER);\n            Expect('=');\n            SQObject val = ExpectScalar();\n            OptionalSemicolon();\n            SQTable *enums = _table(_ss(_vm)->_consts);\n            SQObjectPtr strongid = id;\n            enums->NewSlot(strongid,SQObjectPtr(val));\n            strongid.Null();\n            }\n            break;\n        default:\n            CommaExpr();\n            _fs->DiscardTarget();\n            //_fs->PopTarget();\n            break;\n        }\n        _fs->SnoozeOpt();\n    }\n    void EmitDerefOp(SQOpcode op)\n    {\n        SQInteger val = _fs->PopTarget();\n        SQInteger key = _fs->PopTarget();\n        SQInteger src = _fs->PopTarget();\n        _fs->AddInstruction(op,_fs->PushTarget(),src,key,val);\n    }\n    void Emit2ArgsOP(SQOpcode op, SQInteger p3 = 0)\n    {\n        SQInteger p2 = _fs->PopTarget(); //src in OP_GET\n        SQInteger p1 = _fs->PopTarget(); //key in OP_GET\n        _fs->AddInstruction(op,_fs->PushTarget(), p1, p2, p3);\n    }\n    void EmitCompoundArith(SQInteger tok, SQInteger etype, SQInteger pos)\n    {\n        /* Generate code depending on the expression type */\n        switch(etype) {\n        case LOCAL:{\n            SQInteger p2 = _fs->PopTarget(); //src in OP_GET\n            SQInteger p1 = _fs->PopTarget(); //key in OP_GET\n            _fs->PushTarget(p1);\n            //EmitCompArithLocal(tok, p1, p1, p2);\n            _fs->AddInstruction(ChooseArithOpByToken(tok),p1, p2, p1, 0);\n            _fs->SnoozeOpt();\n                   }\n            break;\n        case OBJECT:\n        case BASE:\n            {\n                SQInteger val = _fs->PopTarget();\n                SQInteger key = _fs->PopTarget();\n                SQInteger src = _fs->PopTarget();\n                /* _OP_COMPARITH mixes dest obj and source val in the arg1 */\n                _fs->AddInstruction(_OP_COMPARITH, _fs->PushTarget(), (src<<16)|val, key, ChooseCompArithCharByToken(tok));\n            }\n            break;\n        case OUTER:\n            {\n                SQInteger val = _fs->TopTarget();\n                SQInteger tmp = _fs->PushTarget();\n                _fs->AddInstruction(_OP_GETOUTER,   tmp, pos);\n                _fs->AddInstruction(ChooseArithOpByToken(tok), tmp, val, tmp, 0);\n                _fs->PopTarget();\n                _fs->PopTarget();\n                _fs->AddInstruction(_OP_SETOUTER, _fs->PushTarget(), pos, tmp);\n            }\n            break;\n        }\n    }\n    void CommaExpr()\n    {\n        for(Expression();_token == ',';_fs->PopTarget(), Lex(), CommaExpr());\n    }\n    void Expression()\n    {\n         SQExpState es = _es;\n        _es.etype     = EXPR;\n        _es.epos      = -1;\n        _es.donot_get = false;\n        LogicalOrExp();\n        switch(_token)  {\n        case _SC('='):\n        case TK_NEWSLOT:\n        case TK_MINUSEQ:\n        case TK_PLUSEQ:\n        case TK_MULEQ:\n        case TK_DIVEQ:\n        case TK_MODEQ:{\n            SQInteger op = _token;\n            SQInteger ds = _es.etype;\n            SQInteger pos = _es.epos;\n            if(ds == EXPR) Error(_SC(\"can't assign expression\"));\n            else if(ds == BASE) Error(_SC(\"'base' cannot be modified\"));\n            Lex(); Expression();\n\n            switch(op){\n            case TK_NEWSLOT:\n                if(ds == OBJECT || ds == BASE)\n                    EmitDerefOp(_OP_NEWSLOT);\n                else //if _derefstate != DEREF_NO_DEREF && DEREF_FIELD so is the index of a local\n                    Error(_SC(\"can't 'create' a local slot\"));\n                break;\n            case _SC('='): //ASSIGN\n                switch(ds) {\n                case LOCAL:\n                    {\n                        SQInteger src = _fs->PopTarget();\n                        SQInteger dst = _fs->TopTarget();\n                        _fs->AddInstruction(_OP_MOVE, dst, src);\n                    }\n                    break;\n                case OBJECT:\n                case BASE:\n                    EmitDerefOp(_OP_SET);\n                    break;\n                case OUTER:\n                    {\n                        SQInteger src = _fs->PopTarget();\n                        SQInteger dst = _fs->PushTarget();\n                        _fs->AddInstruction(_OP_SETOUTER, dst, pos, src);\n                    }\n                }\n                break;\n            case TK_MINUSEQ:\n            case TK_PLUSEQ:\n            case TK_MULEQ:\n            case TK_DIVEQ:\n            case TK_MODEQ:\n                EmitCompoundArith(op, ds, pos);\n                break;\n            }\n            }\n            break;\n        case _SC('?'): {\n            Lex();\n            _fs->AddInstruction(_OP_JZ, _fs->PopTarget());\n            SQInteger jzpos = _fs->GetCurrentPos();\n            SQInteger trg = _fs->PushTarget();\n            Expression();\n            SQInteger first_exp = _fs->PopTarget();\n            if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp);\n            SQInteger endfirstexp = _fs->GetCurrentPos();\n            _fs->AddInstruction(_OP_JMP, 0, 0);\n            Expect(_SC(':'));\n            SQInteger jmppos = _fs->GetCurrentPos();\n            Expression();\n            SQInteger second_exp = _fs->PopTarget();\n            if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp);\n            _fs->SetInstructionParam(jmppos, 1, _fs->GetCurrentPos() - jmppos);\n            _fs->SetInstructionParam(jzpos, 1, endfirstexp - jzpos + 1);\n            _fs->SnoozeOpt();\n            }\n            break;\n        }\n        _es = es;\n    }\n    template<typename T> void INVOKE_EXP(T f)\n    {\n        SQExpState es = _es;\n        _es.etype     = EXPR;\n        _es.epos      = -1;\n        _es.donot_get = false;\n        (this->*f)();\n        _es = es;\n    }\n    template<typename T> void BIN_EXP(SQOpcode op, T f,SQInteger op3 = 0)\n    {\n        Lex();\n        INVOKE_EXP(f);\n        SQInteger op1 = _fs->PopTarget();SQInteger op2 = _fs->PopTarget();\n        _fs->AddInstruction(op, _fs->PushTarget(), op1, op2, op3);\n        _es.etype = EXPR;\n    }\n    void LogicalOrExp()\n    {\n        LogicalAndExp();\n        for(;;) if(_token == TK_OR) {\n            SQInteger first_exp = _fs->PopTarget();\n            SQInteger trg = _fs->PushTarget();\n            _fs->AddInstruction(_OP_OR, trg, 0, first_exp, 0);\n            SQInteger jpos = _fs->GetCurrentPos();\n            if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp);\n            Lex(); INVOKE_EXP(&SQCompiler::LogicalOrExp);\n            _fs->SnoozeOpt();\n            SQInteger second_exp = _fs->PopTarget();\n            if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp);\n            _fs->SnoozeOpt();\n            _fs->SetInstructionParam(jpos, 1, (_fs->GetCurrentPos() - jpos));\n            _es.etype = EXPR;\n            break;\n        }else return;\n    }\n    void LogicalAndExp()\n    {\n        BitwiseOrExp();\n        for(;;) switch(_token) {\n        case TK_AND: {\n            SQInteger first_exp = _fs->PopTarget();\n            SQInteger trg = _fs->PushTarget();\n            _fs->AddInstruction(_OP_AND, trg, 0, first_exp, 0);\n            SQInteger jpos = _fs->GetCurrentPos();\n            if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp);\n            Lex(); INVOKE_EXP(&SQCompiler::LogicalAndExp);\n            _fs->SnoozeOpt();\n            SQInteger second_exp = _fs->PopTarget();\n            if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp);\n            _fs->SnoozeOpt();\n            _fs->SetInstructionParam(jpos, 1, (_fs->GetCurrentPos() - jpos));\n            _es.etype = EXPR;\n            break;\n            }\n\n        default:\n            return;\n        }\n    }\n    void BitwiseOrExp()\n    {\n        BitwiseXorExp();\n        for(;;) if(_token == _SC('|'))\n        {BIN_EXP(_OP_BITW, &SQCompiler::BitwiseXorExp,BW_OR);\n        }else return;\n    }\n    void BitwiseXorExp()\n    {\n        BitwiseAndExp();\n        for(;;) if(_token == _SC('^'))\n        {BIN_EXP(_OP_BITW, &SQCompiler::BitwiseAndExp,BW_XOR);\n        }else return;\n    }\n    void BitwiseAndExp()\n    {\n        EqExp();\n        for(;;) if(_token == _SC('&'))\n        {BIN_EXP(_OP_BITW, &SQCompiler::EqExp,BW_AND);\n        }else return;\n    }\n    void EqExp()\n    {\n        CompExp();\n        for(;;) switch(_token) {\n        case TK_EQ: BIN_EXP(_OP_EQ, &SQCompiler::CompExp); break;\n        case TK_NE: BIN_EXP(_OP_NE, &SQCompiler::CompExp); break;\n        case TK_3WAYSCMP: BIN_EXP(_OP_CMP, &SQCompiler::CompExp,CMP_3W); break;\n        default: return;\n        }\n    }\n    void CompExp()\n    {\n        ShiftExp();\n        for(;;) switch(_token) {\n        case _SC('>'): BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_G); break;\n        case _SC('<'): BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_L); break;\n        case TK_GE: BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_GE); break;\n        case TK_LE: BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_LE); break;\n        case TK_IN: BIN_EXP(_OP_EXISTS, &SQCompiler::ShiftExp); break;\n        case TK_INSTANCEOF: BIN_EXP(_OP_INSTANCEOF, &SQCompiler::ShiftExp); break;\n        default: return;\n        }\n    }\n    void ShiftExp()\n    {\n        PlusExp();\n        for(;;) switch(_token) {\n        case TK_USHIFTR: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_USHIFTR); break;\n        case TK_SHIFTL: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_SHIFTL); break;\n        case TK_SHIFTR: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_SHIFTR); break;\n        default: return;\n        }\n    }\n    SQOpcode ChooseArithOpByToken(SQInteger tok)\n    {\n        switch(tok) {\n            case TK_PLUSEQ: case '+': return _OP_ADD;\n            case TK_MINUSEQ: case '-': return _OP_SUB;\n            case TK_MULEQ: case '*': return _OP_MUL;\n            case TK_DIVEQ: case '/': return _OP_DIV;\n            case TK_MODEQ: case '%': return _OP_MOD;\n            default: assert(0);\n        }\n        return _OP_ADD;\n    }\n    SQInteger ChooseCompArithCharByToken(SQInteger tok)\n    {\n        SQInteger oper;\n        switch(tok){\n        case TK_MINUSEQ: oper = '-'; break;\n        case TK_PLUSEQ: oper = '+'; break;\n        case TK_MULEQ: oper = '*'; break;\n        case TK_DIVEQ: oper = '/'; break;\n        case TK_MODEQ: oper = '%'; break;\n        default: oper = 0; //shut up compiler\n            assert(0); break;\n        };\n        return oper;\n    }\n    void PlusExp()\n    {\n        MultExp();\n        for(;;) switch(_token) {\n        case _SC('+'): case _SC('-'):\n            BIN_EXP(ChooseArithOpByToken(_token), &SQCompiler::MultExp); break;\n        default: return;\n        }\n    }\n\n    void MultExp()\n    {\n        PrefixedExpr();\n        for(;;) switch(_token) {\n        case _SC('*'): case _SC('/'): case _SC('%'):\n            BIN_EXP(ChooseArithOpByToken(_token), &SQCompiler::PrefixedExpr); break;\n        default: return;\n        }\n    }\n    //if 'pos' != -1 the previous variable is a local variable\n    void PrefixedExpr()\n    {\n        SQInteger pos = Factor();\n        for(;;) {\n            switch(_token) {\n            case _SC('.'):\n                pos = -1;\n                Lex();\n\n                _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_IDENTIFIER)));\n                if(_es.etype==BASE) {\n                    Emit2ArgsOP(_OP_GET);\n                    pos = _fs->TopTarget();\n                    _es.etype = EXPR;\n                    _es.epos   = pos;\n                }\n                else {\n                    if(NeedGet()) {\n                        Emit2ArgsOP(_OP_GET);\n                    }\n                    _es.etype = OBJECT;\n                }\n                break;\n            case _SC('['):\n                if(_lex._prevtoken == _SC('\\n')) Error(_SC(\"cannot brake deref/or comma needed after [exp]=exp slot declaration\"));\n                Lex(); Expression(); Expect(_SC(']'));\n                pos = -1;\n                if(_es.etype==BASE) {\n                    Emit2ArgsOP(_OP_GET);\n                    pos = _fs->TopTarget();\n                    _es.etype = EXPR;\n                    _es.epos   = pos;\n                }\n                else {\n                    if(NeedGet()) {\n                        Emit2ArgsOP(_OP_GET);\n                    }\n                    _es.etype = OBJECT;\n                }\n                break;\n            case TK_MINUSMINUS:\n            case TK_PLUSPLUS:\n                {\n                    if(IsEndOfStatement()) return;\n                    SQInteger diff = (_token==TK_MINUSMINUS) ? -1 : 1;\n                    Lex();\n                    switch(_es.etype)\n                    {\n                        case EXPR: Error(_SC(\"can't '++' or '--' an expression\")); break;\n                        case OBJECT:\n                        case BASE:\n                            if(_es.donot_get == true)  { Error(_SC(\"can't '++' or '--' an expression\")); break; } //mmh dor this make sense?\n                            Emit2ArgsOP(_OP_PINC, diff);\n                            break;\n                        case LOCAL: {\n                            SQInteger src = _fs->PopTarget();\n                            _fs->AddInstruction(_OP_PINCL, _fs->PushTarget(), src, 0, diff);\n                                    }\n                            break;\n                        case OUTER: {\n                            SQInteger tmp1 = _fs->PushTarget();\n                            SQInteger tmp2 = _fs->PushTarget();\n                            _fs->AddInstruction(_OP_GETOUTER, tmp2, _es.epos);\n                            _fs->AddInstruction(_OP_PINCL,    tmp1, tmp2, 0, diff);\n                            _fs->AddInstruction(_OP_SETOUTER, tmp2, _es.epos, tmp2);\n                            _fs->PopTarget();\n                        }\n                    }\n                }\n                return;\n                break;\n            case _SC('('):\n                switch(_es.etype) {\n                    case OBJECT: {\n                        SQInteger key     = _fs->PopTarget();  /* location of the key */\n                        SQInteger table   = _fs->PopTarget();  /* location of the object */\n                        SQInteger closure = _fs->PushTarget(); /* location for the closure */\n                        SQInteger ttarget = _fs->PushTarget(); /* location for 'this' pointer */\n                        _fs->AddInstruction(_OP_PREPCALL, closure, key, table, ttarget);\n                        }\n                        break;\n                    case BASE:\n                        //Emit2ArgsOP(_OP_GET);\n                        _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0);\n                        break;\n                    case OUTER:\n                        _fs->AddInstruction(_OP_GETOUTER, _fs->PushTarget(), _es.epos);\n                        _fs->AddInstruction(_OP_MOVE,     _fs->PushTarget(), 0);\n                        break;\n                    default:\n                        _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0);\n                }\n                _es.etype = EXPR;\n                Lex();\n                FunctionCallArgs();\n                break;\n            default: return;\n            }\n        }\n    }\n    SQInteger Factor()\n    {\n        //_es.etype = EXPR;\n        switch(_token)\n        {\n        case TK_STRING_LITERAL:\n            _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(_fs->CreateString(_lex._svalue,_lex._longstr.size()-1)));\n            Lex();\n            break;\n        case TK_BASE:\n            Lex();\n            _fs->AddInstruction(_OP_GETBASE, _fs->PushTarget());\n            _es.etype  = BASE;\n            _es.epos   = _fs->TopTarget();\n            return (_es.epos);\n            break;\n        case TK_IDENTIFIER:\n        case TK_CONSTRUCTOR:\n        case TK_THIS:{\n                SQObject id;\n                SQObject constant;\n\n                switch(_token) {\n                    case TK_IDENTIFIER:  id = _fs->CreateString(_lex._svalue);       break;\n                    case TK_THIS:        id = _fs->CreateString(_SC(\"this\"),4);        break;\n                    case TK_CONSTRUCTOR: id = _fs->CreateString(_SC(\"constructor\"),11); break;\n                }\n\n                SQInteger pos = -1;\n                Lex();\n                if((pos = _fs->GetLocalVariable(id)) != -1) {\n                    /* Handle a local variable (includes 'this') */\n                    _fs->PushTarget(pos);\n                    _es.etype  = LOCAL;\n                    _es.epos   = pos;\n                }\n\n                else if((pos = _fs->GetOuterVariable(id)) != -1) {\n                    /* Handle a free var */\n                    if(NeedGet()) {\n                        _es.epos  = _fs->PushTarget();\n                        _fs->AddInstruction(_OP_GETOUTER, _es.epos, pos);\n                        /* _es.etype = EXPR; already default value */\n                    }\n                    else {\n                        _es.etype = OUTER;\n                        _es.epos  = pos;\n                    }\n                }\n\n                else if(_fs->IsConstant(id, constant)) {\n                    /* Handle named constant */\n                    SQObjectPtr constval;\n                    SQObject    constid;\n                    if(sq_type(constant) == OT_TABLE) {\n                        Expect('.');\n                        constid = Expect(TK_IDENTIFIER);\n                        if(!_table(constant)->Get(constid, constval)) {\n                            constval.Null();\n                            Error(_SC(\"invalid constant [%s.%s]\"), _stringval(id), _stringval(constid));\n                        }\n                    }\n                    else {\n                        constval = constant;\n                    }\n                    _es.epos = _fs->PushTarget();\n\n                    /* generate direct or literal function depending on size */\n                    SQObjectType ctype = sq_type(constval);\n                    switch(ctype) {\n                        case OT_INTEGER: EmitLoadConstInt(_integer(constval),_es.epos); break;\n                        case OT_FLOAT: EmitLoadConstFloat(_float(constval),_es.epos); break;\n                        case OT_BOOL: _fs->AddInstruction(_OP_LOADBOOL, _es.epos, _integer(constval)); break;\n                        default: _fs->AddInstruction(_OP_LOAD,_es.epos,_fs->GetConstant(constval)); break;\n                    }\n                    _es.etype = EXPR;\n                }\n                else {\n                    /* Handle a non-local variable, aka a field. Push the 'this' pointer on\n                    * the virtual stack (always found in offset 0, so no instruction needs to\n                    * be generated), and push the key next. Generate an _OP_LOAD instruction\n                    * for the latter. If we are not using the variable as a dref expr, generate\n                    * the _OP_GET instruction.\n                    */\n                    _fs->PushTarget(0);\n                    _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));\n                    if(NeedGet()) {\n                        Emit2ArgsOP(_OP_GET);\n                    }\n                    _es.etype = OBJECT;\n                }\n                return _es.epos;\n            }\n            break;\n        case TK_DOUBLE_COLON:  // \"::\"\n            _fs->AddInstruction(_OP_LOADROOT, _fs->PushTarget());\n            _es.etype = OBJECT;\n            _token = _SC('.'); /* hack: drop into PrefixExpr, case '.'*/\n            _es.epos = -1;\n            return _es.epos;\n            break;\n        case TK_NULL:\n            _fs->AddInstruction(_OP_LOADNULLS, _fs->PushTarget(),1);\n            Lex();\n            break;\n        case TK_INTEGER: EmitLoadConstInt(_lex._nvalue,-1); Lex();  break;\n        case TK_FLOAT: EmitLoadConstFloat(_lex._fvalue,-1); Lex(); break;\n        case TK_TRUE: case TK_FALSE:\n            _fs->AddInstruction(_OP_LOADBOOL, _fs->PushTarget(),_token == TK_TRUE?1:0);\n            Lex();\n            break;\n        case _SC('['): {\n                _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(),0,0,NOT_ARRAY);\n                SQInteger apos = _fs->GetCurrentPos(),key = 0;\n                Lex();\n                while(_token != _SC(']')) {\n                    Expression();\n                    if(_token == _SC(',')) Lex();\n                    SQInteger val = _fs->PopTarget();\n                    SQInteger array = _fs->TopTarget();\n                    _fs->AddInstruction(_OP_APPENDARRAY, array, val, AAT_STACK);\n                    key++;\n                }\n                _fs->SetInstructionParam(apos, 1, key);\n                Lex();\n            }\n            break;\n        case _SC('{'):\n            _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(),0,NOT_TABLE);\n            Lex();ParseTableOrClass(_SC(','),_SC('}'));\n            break;\n        case TK_FUNCTION: FunctionExp(_token);break;\n        case _SC('@'): FunctionExp(_token);break;\n        case TK_CLASS: Lex(); ClassExp();break;\n        case _SC('-'):\n            Lex();\n            switch(_token) {\n            case TK_INTEGER: EmitLoadConstInt(-_lex._nvalue,-1); Lex(); break;\n            case TK_FLOAT: EmitLoadConstFloat(-_lex._fvalue,-1); Lex(); break;\n            default: UnaryOP(_OP_NEG);\n            }\n            break;\n        case _SC('!'): Lex(); UnaryOP(_OP_NOT); break;\n        case _SC('~'):\n            Lex();\n            if(_token == TK_INTEGER)  { EmitLoadConstInt(~_lex._nvalue,-1); Lex(); break; }\n            UnaryOP(_OP_BWNOT);\n            break;\n        case TK_TYPEOF : Lex() ;UnaryOP(_OP_TYPEOF); break;\n        case TK_RESUME : Lex(); UnaryOP(_OP_RESUME); break;\n        case TK_CLONE : Lex(); UnaryOP(_OP_CLONE); break;\n        case TK_RAWCALL: Lex(); Expect('('); FunctionCallArgs(true); break;\n        case TK_MINUSMINUS :\n        case TK_PLUSPLUS :PrefixIncDec(_token); break;\n        case TK_DELETE : DeleteExpr(); break;\n        case _SC('('): Lex(); CommaExpr(); Expect(_SC(')'));\n            break;\n        case TK___LINE__: EmitLoadConstInt(_lex._currentline,-1); Lex(); break;\n        case TK___FILE__: _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(_sourcename)); Lex(); break;\n        default: Error(_SC(\"expression expected\"));\n        }\n        _es.etype = EXPR;\n        return -1;\n    }\n    void EmitLoadConstInt(SQInteger value,SQInteger target)\n    {\n        if(target < 0) {\n            target = _fs->PushTarget();\n        }\n        if(value <= INT_MAX && value > INT_MIN) { //does it fit in 32 bits?\n            _fs->AddInstruction(_OP_LOADINT, target,value);\n        }\n        else {\n            _fs->AddInstruction(_OP_LOAD, target, _fs->GetNumericConstant(value));\n        }\n    }\n    void EmitLoadConstFloat(SQFloat value,SQInteger target)\n    {\n        if(target < 0) {\n            target = _fs->PushTarget();\n        }\n        if(sizeof(SQFloat) == sizeof(SQInt32)) {\n            _fs->AddInstruction(_OP_LOADFLOAT, target,*((SQInt32 *)&value));\n        }\n        else {\n            _fs->AddInstruction(_OP_LOAD, target, _fs->GetNumericConstant(value));\n        }\n    }\n    void UnaryOP(SQOpcode op)\n    {\n        PrefixedExpr();\n        SQInteger src = _fs->PopTarget();\n        _fs->AddInstruction(op, _fs->PushTarget(), src);\n    }\n    bool NeedGet()\n    {\n        switch(_token) {\n        case _SC('='): case _SC('('): case TK_NEWSLOT: case TK_MODEQ: case TK_MULEQ:\n        case TK_DIVEQ: case TK_MINUSEQ: case TK_PLUSEQ:\n            return false;\n        case TK_PLUSPLUS: case TK_MINUSMINUS:\n            if (!IsEndOfStatement()) {\n                return false;\n            }\n        break;\n        }\n        return (!_es.donot_get || ( _es.donot_get && (_token == _SC('.') || _token == _SC('['))));\n    }\n    void FunctionCallArgs(bool rawcall = false)\n    {\n        SQInteger nargs = 1;//this\n         while(_token != _SC(')')) {\n             Expression();\n             MoveIfCurrentTargetIsLocal();\n             nargs++;\n             if(_token == _SC(',')){\n                 Lex();\n                 if(_token == ')') Error(_SC(\"expression expected, found ')'\"));\n             }\n         }\n         Lex();\n         if (rawcall) {\n             if (nargs < 3) Error(_SC(\"rawcall requires at least 2 parameters (callee and this)\"));\n             nargs -= 2; //removes callee and this from count\n         }\n         for(SQInteger i = 0; i < (nargs - 1); i++) _fs->PopTarget();\n         SQInteger stackbase = _fs->PopTarget();\n         SQInteger closure = _fs->PopTarget();\n         _fs->AddInstruction(_OP_CALL, _fs->PushTarget(), closure, stackbase, nargs);\n    }\n    void ParseTableOrClass(SQInteger separator,SQInteger terminator)\n    {\n        SQInteger tpos = _fs->GetCurrentPos(),nkeys = 0;\n        while(_token != terminator) {\n            bool hasattrs = false;\n            bool isstatic = false;\n            //check if is an attribute\n            if(separator == ';') {\n                if(_token == TK_ATTR_OPEN) {\n                    _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(),0,NOT_TABLE); Lex();\n                    ParseTableOrClass(',',TK_ATTR_CLOSE);\n                    hasattrs = true;\n                }\n                if(_token == TK_STATIC) {\n                    isstatic = true;\n                    Lex();\n                }\n            }\n            switch(_token) {\n            case TK_FUNCTION:\n            case TK_CONSTRUCTOR:{\n                SQInteger tk = _token;\n                Lex();\n                SQObject id = tk == TK_FUNCTION ? Expect(TK_IDENTIFIER) : _fs->CreateString(_SC(\"constructor\"));\n                Expect(_SC('('));\n                _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));\n                CreateFunction(id);\n                _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0);\n                                }\n                                break;\n            case _SC('['):\n                Lex(); CommaExpr(); Expect(_SC(']'));\n                Expect(_SC('=')); Expression();\n                break;\n            case TK_STRING_LITERAL: //JSON\n                if(separator == ',') { //only works for tables\n                    _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_STRING_LITERAL)));\n                    Expect(_SC(':')); Expression();\n                    break;\n                }\n            default :\n                _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_IDENTIFIER)));\n                Expect(_SC('=')); Expression();\n            }\n            if(_token == separator) Lex();//optional comma/semicolon\n            nkeys++;\n            SQInteger val = _fs->PopTarget();\n            SQInteger key = _fs->PopTarget();\n            SQInteger attrs = hasattrs ? _fs->PopTarget():-1;\n            ((void)attrs);\n            assert((hasattrs && (attrs == key-1)) || !hasattrs);\n            unsigned char flags = (hasattrs?NEW_SLOT_ATTRIBUTES_FLAG:0)|(isstatic?NEW_SLOT_STATIC_FLAG:0);\n            SQInteger table = _fs->TopTarget(); //<<BECAUSE OF THIS NO COMMON EMIT FUNC IS POSSIBLE\n            if(separator == _SC(',')) { //hack recognizes a table from the separator\n                _fs->AddInstruction(_OP_NEWSLOT, 0xFF, table, key, val);\n            }\n            else {\n                _fs->AddInstruction(_OP_NEWSLOTA, flags, table, key, val); //this for classes only as it invokes _newmember\n            }\n        }\n        if(separator == _SC(',')) //hack recognizes a table from the separator\n            _fs->SetInstructionParam(tpos, 1, nkeys);\n        Lex();\n    }\n    void LocalDeclStatement()\n    {\n        SQObject varname;\n        Lex();\n        if( _token == TK_FUNCTION) {\n            Lex();\n            varname = Expect(TK_IDENTIFIER);\n            Expect(_SC('('));\n            CreateFunction(varname);\n            _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0);\n            _fs->PopTarget();\n            _fs->PushLocalVariable(varname);\n            return;\n        }\n\n        do {\n            varname = Expect(TK_IDENTIFIER);\n            if(_token == _SC('=')) {\n                Lex(); Expression();\n                SQInteger src = _fs->PopTarget();\n                SQInteger dest = _fs->PushTarget();\n                if(dest != src) _fs->AddInstruction(_OP_MOVE, dest, src);\n            }\n            else{\n                _fs->AddInstruction(_OP_LOADNULLS, _fs->PushTarget(),1);\n            }\n            _fs->PopTarget();\n            _fs->PushLocalVariable(varname);\n            if(_token == _SC(',')) Lex(); else break;\n        } while(1);\n    }\n    void IfBlock()\n    {\n        if (_token == _SC('{'))\n        {\n            BEGIN_SCOPE();\n            Lex();\n            Statements();\n            Expect(_SC('}'));\n            if (true) {\n                END_SCOPE();\n            }\n            else {\n                END_SCOPE_NO_CLOSE();\n            }\n        }\n        else {\n            //BEGIN_SCOPE();\n            Statement();\n            if (_lex._prevtoken != _SC('}') && _lex._prevtoken != _SC(';')) OptionalSemicolon();\n            //END_SCOPE();\n        }\n    }\n    void IfStatement()\n    {\n        SQInteger jmppos;\n        bool haselse = false;\n        Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));\n        _fs->AddInstruction(_OP_JZ, _fs->PopTarget());\n        SQInteger jnepos = _fs->GetCurrentPos();\n\n\n\n        IfBlock();\n        //\n        /*static int n = 0;\n        if (_token != _SC('}') && _token != TK_ELSE) {\n            printf(\"IF %d-----------------------!!!!!!!!!\\n\", n);\n            if (n == 5)\n            {\n                printf(\"asd\");\n            }\n            n++;\n            //OptionalSemicolon();\n        }*/\n\n\n        SQInteger endifblock = _fs->GetCurrentPos();\n        if(_token == TK_ELSE){\n            haselse = true;\n            //BEGIN_SCOPE();\n            _fs->AddInstruction(_OP_JMP);\n            jmppos = _fs->GetCurrentPos();\n            Lex();\n            //Statement(); if(_lex._prevtoken != _SC('}')) OptionalSemicolon();\n            IfBlock();\n            //END_SCOPE();\n            _fs->SetInstructionParam(jmppos, 1, _fs->GetCurrentPos() - jmppos);\n        }\n        _fs->SetInstructionParam(jnepos, 1, endifblock - jnepos + (haselse?1:0));\n    }\n    void WhileStatement()\n    {\n        SQInteger jzpos, jmppos;\n        jmppos = _fs->GetCurrentPos();\n        Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));\n\n        BEGIN_BREAKBLE_BLOCK();\n        _fs->AddInstruction(_OP_JZ, _fs->PopTarget());\n        jzpos = _fs->GetCurrentPos();\n        BEGIN_SCOPE();\n\n        Statement();\n\n        END_SCOPE();\n        _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1);\n        _fs->SetInstructionParam(jzpos, 1, _fs->GetCurrentPos() - jzpos);\n\n        END_BREAKBLE_BLOCK(jmppos);\n    }\n    void DoWhileStatement()\n    {\n        Lex();\n        SQInteger jmptrg = _fs->GetCurrentPos();\n        BEGIN_BREAKBLE_BLOCK()\n        BEGIN_SCOPE();\n        Statement();\n        END_SCOPE();\n        if(_token == TK_WHILE) {\n            Expect(TK_WHILE);\n            SQInteger continuetrg = _fs->GetCurrentPos();\n            Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));\n            _fs->AddInstruction(_OP_JZ, _fs->PopTarget(), 1);\n            _fs->AddInstruction(_OP_JMP, 0, jmptrg - _fs->GetCurrentPos() - 1);\n            END_BREAKBLE_BLOCK(continuetrg);\n        } else {\n            SQInteger continuetrg = _fs->GetCurrentPos();\n            _fs->AddInstruction(_OP_JZ, 1, 1);\n            _fs->AddInstruction(_OP_JMP, 0, jmptrg - _fs->GetCurrentPos() - 1);\n            END_BREAKBLE_BLOCK(continuetrg);\n        }\n    }\n    void ForStatement()\n    {\n        Lex();\n        BEGIN_SCOPE();\n        Expect(_SC('('));\n        if(_token == TK_LOCAL) LocalDeclStatement();\n        else if(_token != _SC(';')){\n            CommaExpr();\n            _fs->PopTarget();\n        }\n        Expect(_SC(';'));\n        _fs->SnoozeOpt();\n        SQInteger jmppos = _fs->GetCurrentPos();\n        SQInteger jzpos = -1;\n        if(_token != _SC(';')) { CommaExpr(); _fs->AddInstruction(_OP_JZ, _fs->PopTarget()); jzpos = _fs->GetCurrentPos(); }\n        Expect(_SC(';'));\n        _fs->SnoozeOpt();\n        SQInteger expstart = _fs->GetCurrentPos() + 1;\n        if(_token != _SC(')')) {\n            CommaExpr();\n            _fs->PopTarget();\n        }\n        Expect(_SC(')'));\n        _fs->SnoozeOpt();\n        SQInteger expend = _fs->GetCurrentPos();\n        SQInteger expsize = (expend - expstart) + 1;\n        SQInstructionVec exp;\n        if(expsize > 0) {\n            for(SQInteger i = 0; i < expsize; i++)\n                exp.push_back(_fs->GetInstruction(expstart + i));\n            _fs->PopInstructions(expsize);\n        }\n        BEGIN_BREAKBLE_BLOCK()\n        Statement();\n        SQInteger continuetrg = _fs->GetCurrentPos();\n        if(expsize > 0) {\n            for(SQInteger i = 0; i < expsize; i++)\n                _fs->AddInstruction(exp[i]);\n        }\n        _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1, 0);\n        if(jzpos>  0) _fs->SetInstructionParam(jzpos, 1, _fs->GetCurrentPos() - jzpos);\n        \n        END_BREAKBLE_BLOCK(continuetrg);\n\n\t\tEND_SCOPE();\n    }\n    void ForEachStatement()\n    {\n        SQObject idxname, valname;\n        Lex(); Expect(_SC('(')); valname = Expect(TK_IDENTIFIER);\n        if(_token == _SC(',')) {\n            idxname = valname;\n            Lex(); valname = Expect(TK_IDENTIFIER);\n        }\n        else{\n            idxname = _fs->CreateString(_SC(\"@INDEX@\"));\n        }\n        Expect(TK_IN);\n\n        //save the stack size\n        BEGIN_SCOPE();\n        //put the table in the stack(evaluate the table expression)\n        Expression(); Expect(_SC(')'));\n        SQInteger container = _fs->TopTarget();\n        //push the index local var\n        SQInteger indexpos = _fs->PushLocalVariable(idxname);\n        _fs->AddInstruction(_OP_LOADNULLS, indexpos,1);\n        //push the value local var\n        SQInteger valuepos = _fs->PushLocalVariable(valname);\n        _fs->AddInstruction(_OP_LOADNULLS, valuepos,1);\n        //push reference index\n        SQInteger itrpos = _fs->PushLocalVariable(_fs->CreateString(_SC(\"@ITERATOR@\"))); //use invalid id to make it inaccessible\n        _fs->AddInstruction(_OP_LOADNULLS, itrpos,1);\n        SQInteger jmppos = _fs->GetCurrentPos();\n        _fs->AddInstruction(_OP_FOREACH, container, 0, indexpos);\n        SQInteger foreachpos = _fs->GetCurrentPos();\n        _fs->AddInstruction(_OP_POSTFOREACH, container, 0, indexpos);\n        //generate the statement code\n        BEGIN_BREAKBLE_BLOCK()\n        Statement();\n        _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1);\n        _fs->SetInstructionParam(foreachpos, 1, _fs->GetCurrentPos() - foreachpos);\n        _fs->SetInstructionParam(foreachpos + 1, 1, _fs->GetCurrentPos() - foreachpos);\n        END_BREAKBLE_BLOCK(foreachpos - 1);\n        //restore the local variable stack(remove index,val and ref idx)\n        _fs->PopTarget();\n        END_SCOPE();\n    }\n    void SwitchStatement()\n    {\n        Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));\n        Expect(_SC('{'));\n        SQInteger expr = _fs->TopTarget();\n        bool bfirst = true;\n        SQInteger tonextcondjmp = -1;\n        SQInteger skipcondjmp = -1;\n        SQInteger __nbreaks__ = _fs->_unresolvedbreaks.size();\n        _fs->_breaktargets.push_back(0);\n        while(_token == TK_CASE) {\n            if(!bfirst) {\n                _fs->AddInstruction(_OP_JMP, 0, 0);\n                skipcondjmp = _fs->GetCurrentPos();\n                _fs->SetInstructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp);\n            }\n            //condition\n            Lex(); Expression(); Expect(_SC(':'));\n            SQInteger trg = _fs->PopTarget();\n            SQInteger eqtarget = trg;\n            bool local = _fs->IsLocal(trg);\n            if(local) {\n                eqtarget = _fs->PushTarget(); //we need to allocate a extra reg\n            }\n            _fs->AddInstruction(_OP_EQ, eqtarget, trg, expr);\n            _fs->AddInstruction(_OP_JZ, eqtarget, 0);\n            if(local) {\n                _fs->PopTarget();\n            }\n\n            //end condition\n            if(skipcondjmp != -1) {\n                _fs->SetInstructionParam(skipcondjmp, 1, (_fs->GetCurrentPos() - skipcondjmp));\n            }\n            tonextcondjmp = _fs->GetCurrentPos();\n            BEGIN_SCOPE();\n            Statements();\n            END_SCOPE();\n            bfirst = false;\n        }\n        if(tonextcondjmp != -1)\n            _fs->SetInstructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp);\n        if(_token == TK_DEFAULT) {\n            Lex(); Expect(_SC(':'));\n            BEGIN_SCOPE();\n            Statements();\n            END_SCOPE();\n        }\n        Expect(_SC('}'));\n        _fs->PopTarget();\n        __nbreaks__ = _fs->_unresolvedbreaks.size() - __nbreaks__;\n        if(__nbreaks__ > 0)ResolveBreaks(_fs, __nbreaks__);\n        _fs->_breaktargets.pop_back();\n    }\n    void FunctionStatement()\n    {\n        SQObject id;\n        Lex(); id = Expect(TK_IDENTIFIER);\n        _fs->PushTarget(0);\n        _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));\n        if(_token == TK_DOUBLE_COLON) Emit2ArgsOP(_OP_GET);\n\n        while(_token == TK_DOUBLE_COLON) {\n            Lex();\n            id = Expect(TK_IDENTIFIER);\n            _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));\n            if(_token == TK_DOUBLE_COLON) Emit2ArgsOP(_OP_GET);\n        }\n        Expect(_SC('('));\n        CreateFunction(id);\n        _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0);\n        EmitDerefOp(_OP_NEWSLOT);\n        _fs->PopTarget();\n    }\n    void ClassStatement()\n    {\n        SQExpState es;\n        Lex();\n        es = _es;\n        _es.donot_get = true;\n        PrefixedExpr();\n        if(_es.etype == EXPR) {\n            Error(_SC(\"invalid class name\"));\n        }\n        else if(_es.etype == OBJECT || _es.etype == BASE) {\n            ClassExp();\n            EmitDerefOp(_OP_NEWSLOT);\n            _fs->PopTarget();\n        }\n        else {\n            Error(_SC(\"cannot create a class in a local with the syntax(class <local>)\"));\n        }\n        _es = es;\n    }\n    SQObject ExpectScalar()\n    {\n        SQObject val;\n        val._type = OT_NULL; val._unVal.nInteger = 0; //shut up GCC 4.x\n        switch(_token) {\n            case TK_INTEGER:\n                val._type = OT_INTEGER;\n                val._unVal.nInteger = _lex._nvalue;\n                break;\n            case TK_FLOAT:\n                val._type = OT_FLOAT;\n                val._unVal.fFloat = _lex._fvalue;\n                break;\n            case TK_STRING_LITERAL:\n                val = _fs->CreateString(_lex._svalue,_lex._longstr.size()-1);\n                break;\n            case TK_TRUE:\n            case TK_FALSE:\n                val._type = OT_BOOL;\n                val._unVal.nInteger = _token == TK_TRUE ? 1 : 0;\n                break;\n            case '-':\n                Lex();\n                switch(_token)\n                {\n                case TK_INTEGER:\n                    val._type = OT_INTEGER;\n                    val._unVal.nInteger = -_lex._nvalue;\n                break;\n                case TK_FLOAT:\n                    val._type = OT_FLOAT;\n                    val._unVal.fFloat = -_lex._fvalue;\n                break;\n                default:\n                    Error(_SC(\"scalar expected : integer, float\"));\n                }\n                break;\n            default:\n                Error(_SC(\"scalar expected : integer, float, or string\"));\n        }\n        Lex();\n        return val;\n    }\n    void EnumStatement()\n    {\n        Lex();\n        SQObject id = Expect(TK_IDENTIFIER);\n        Expect(_SC('{'));\n\n        SQObject table = _fs->CreateTable();\n        SQInteger nval = 0;\n        while(_token != _SC('}')) {\n            SQObject key = Expect(TK_IDENTIFIER);\n            SQObject val;\n            if(_token == _SC('=')) {\n                Lex();\n                val = ExpectScalar();\n            }\n            else {\n                val._type = OT_INTEGER;\n                val._unVal.nInteger = nval++;\n            }\n            _table(table)->NewSlot(SQObjectPtr(key),SQObjectPtr(val));\n            if(_token == ',') Lex();\n        }\n        SQTable *enums = _table(_ss(_vm)->_consts);\n        SQObjectPtr strongid = id;\n        enums->NewSlot(SQObjectPtr(strongid),SQObjectPtr(table));\n        strongid.Null();\n        Lex();\n    }\n    void TryCatchStatement()\n    {\n        SQObject exid;\n        Lex();\n        _fs->AddInstruction(_OP_PUSHTRAP,0,0);\n        _fs->_traps++;\n        if(_fs->_breaktargets.size()) _fs->_breaktargets.top()++;\n        if(_fs->_continuetargets.size()) _fs->_continuetargets.top()++;\n        SQInteger trappos = _fs->GetCurrentPos();\n        {\n            BEGIN_SCOPE();\n            Statement();\n            END_SCOPE();\n        }\n        _fs->_traps--;\n        _fs->AddInstruction(_OP_POPTRAP, 1, 0);\n        if(_fs->_breaktargets.size()) _fs->_breaktargets.top()--;\n        if(_fs->_continuetargets.size()) _fs->_continuetargets.top()--;\n        _fs->AddInstruction(_OP_JMP, 0, 0);\n        SQInteger jmppos = _fs->GetCurrentPos();\n        _fs->SetInstructionParam(trappos, 1, (_fs->GetCurrentPos() - trappos));\n        Expect(TK_CATCH); Expect(_SC('(')); exid = Expect(TK_IDENTIFIER); Expect(_SC(')'));\n        {\n            BEGIN_SCOPE();\n            SQInteger ex_target = _fs->PushLocalVariable(exid);\n            _fs->SetInstructionParam(trappos, 0, ex_target);\n            Statement();\n            _fs->SetInstructionParams(jmppos, 0, (_fs->GetCurrentPos() - jmppos), 0);\n            END_SCOPE();\n        }\n    }\n    void FunctionExp(SQInteger ftype)\n    {\n        Lex(); Expect(_SC('('));\n        SQObjectPtr dummy;\n        CreateFunction(dummy);\n        _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, ftype == TK_FUNCTION?0:1);\n    }\n    void ClassExp()\n    {\n        SQInteger base = -1;\n        SQInteger attrs = -1;\n        if(_token == TK_EXTENDS) {\n            Lex(); Expression();\n            base = _fs->TopTarget();\n        }\n        if(_token == TK_ATTR_OPEN) {\n            Lex();\n            _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(),0,NOT_TABLE);\n            ParseTableOrClass(_SC(','),TK_ATTR_CLOSE);\n            attrs = _fs->TopTarget();\n        }\n        Expect(_SC('{'));\n        if(attrs != -1) _fs->PopTarget();\n        if(base != -1) _fs->PopTarget();\n        _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(), base, attrs,NOT_CLASS);\n        ParseTableOrClass(_SC(';'),_SC('}'));\n    }\n    void DeleteExpr()\n    {\n        SQExpState es;\n        Lex();\n        es = _es;\n        _es.donot_get = true;\n        PrefixedExpr();\n        if(_es.etype==EXPR) Error(_SC(\"can't delete an expression\"));\n        if(_es.etype==OBJECT || _es.etype==BASE) {\n            Emit2ArgsOP(_OP_DELETE);\n        }\n        else {\n            Error(_SC(\"cannot delete an (outer) local\"));\n        }\n        _es = es;\n    }\n    void PrefixIncDec(SQInteger token)\n    {\n        SQExpState  es;\n        SQInteger diff = (token==TK_MINUSMINUS) ? -1 : 1;\n        Lex();\n        es = _es;\n        _es.donot_get = true;\n        PrefixedExpr();\n        if(_es.etype==EXPR) {\n            Error(_SC(\"can't '++' or '--' an expression\"));\n        }\n        else if(_es.etype==OBJECT || _es.etype==BASE) {\n            Emit2ArgsOP(_OP_INC, diff);\n        }\n        else if(_es.etype==LOCAL) {\n            SQInteger src = _fs->TopTarget();\n            _fs->AddInstruction(_OP_INCL, src, src, 0, diff);\n\n        }\n        else if(_es.etype==OUTER) {\n            SQInteger tmp = _fs->PushTarget();\n            _fs->AddInstruction(_OP_GETOUTER, tmp, _es.epos);\n            _fs->AddInstruction(_OP_INCL,     tmp, tmp, 0, diff);\n            _fs->AddInstruction(_OP_SETOUTER, tmp, _es.epos, tmp);\n        }\n        _es = es;\n    }\n    void CreateFunction(SQObject &name)\n    {\n        SQFuncState *funcstate = _fs->PushChildState(_ss(_vm));\n        funcstate->_name = name;\n        SQObject paramname;\n        funcstate->AddParameter(_fs->CreateString(_SC(\"this\")));\n        funcstate->_sourcename = _sourcename;\n        SQInteger defparams = 0;\n        while(_token!=_SC(')')) {\n            if(_token == TK_VARPARAMS) {\n                if(defparams > 0) Error(_SC(\"function with default parameters cannot have variable number of parameters\"));\n                funcstate->AddParameter(_fs->CreateString(_SC(\"vargv\")));\n                funcstate->_varparams = true;\n                Lex();\n                if(_token != _SC(')')) Error(_SC(\"expected ')'\"));\n                break;\n            }\n            else {\n                paramname = Expect(TK_IDENTIFIER);\n                funcstate->AddParameter(paramname);\n                if(_token == _SC('=')) {\n                    Lex();\n                    Expression();\n                    funcstate->AddDefaultParam(_fs->TopTarget());\n                    defparams++;\n                }\n                else {\n                    if(defparams > 0) Error(_SC(\"expected '='\"));\n                }\n                if(_token == _SC(',')) Lex();\n                else if(_token != _SC(')')) Error(_SC(\"expected ')' or ','\"));\n            }\n        }\n        Expect(_SC(')'));\n        for(SQInteger n = 0; n < defparams; n++) {\n            _fs->PopTarget();\n        }\n\n        SQFuncState *currchunk = _fs;\n        _fs = funcstate;\n        Statement(false);\n        funcstate->AddLineInfos(_lex._prevtoken == _SC('\\n')?_lex._lasttokenline:_lex._currentline, _lineinfo, true);\n        funcstate->AddInstruction(_OP_RETURN, -1);\n        funcstate->SetStackSize(0);\n\n        SQFunctionProto *func = funcstate->BuildProto();\n#ifdef _DEBUG_DUMP\n        funcstate->Dump(func);\n#endif\n        _fs = currchunk;\n        _fs->_functions.push_back(func);\n        _fs->PopChildState();\n    }\n    void ResolveBreaks(SQFuncState *funcstate, SQInteger ntoresolve)\n    {\n        while(ntoresolve > 0) {\n            SQInteger pos = funcstate->_unresolvedbreaks.back();\n            funcstate->_unresolvedbreaks.pop_back();\n            //set the jmp instruction\n            funcstate->SetInstructionParams(pos, 0, funcstate->GetCurrentPos() - pos, 0);\n            ntoresolve--;\n        }\n    }\n    void ResolveContinues(SQFuncState *funcstate, SQInteger ntoresolve, SQInteger targetpos)\n    {\n        while(ntoresolve > 0) {\n            SQInteger pos = funcstate->_unresolvedcontinues.back();\n            funcstate->_unresolvedcontinues.pop_back();\n            //set the jmp instruction\n            funcstate->SetInstructionParams(pos, 0, targetpos - pos, 0);\n            ntoresolve--;\n        }\n    }\nprivate:\n    SQInteger _token;\n    SQFuncState *_fs;\n    SQObjectPtr _sourcename;\n    SQLexer _lex;\n    bool _lineinfo;\n    bool _raiseerror;\n    SQInteger _debugline;\n    SQInteger _debugop;\n    SQExpState   _es;\n    SQScope _scope;\n    SQChar _compilererror[MAX_COMPILER_ERROR_LEN];\n    jmp_buf _errorjmp;\n    SQVM *_vm;\n};\n\nbool Compile(SQVM *vm,SQLEXREADFUNC rg, SQUserPointer up, const SQChar *sourcename, SQObjectPtr &out, bool raiseerror, bool lineinfo)\n{\n    SQCompiler p(vm, rg, up, sourcename, raiseerror, lineinfo);\n    return p.Compile(out);\n}\n\n#endif\n"
  },
  {
    "path": "extlibs/squirrel/squirrel/sqcompiler.h",
    "content": "/*  see copyright notice in squirrel.h */\n#ifndef _SQCOMPILER_H_\n#define _SQCOMPILER_H_\n\nstruct SQVM;\n\n#define TK_IDENTIFIER   258\n#define TK_STRING_LITERAL   259\n#define TK_INTEGER  260\n#define TK_FLOAT    261\n#define TK_BASE 262\n#define TK_DELETE   263\n#define TK_EQ   264\n#define TK_NE   265\n#define TK_LE   266\n#define TK_GE   267\n#define TK_SWITCH   268\n#define TK_ARROW    269\n#define TK_AND  270\n#define TK_OR   271\n#define TK_IF   272\n#define TK_ELSE 273\n#define TK_WHILE    274\n#define TK_BREAK    275\n#define TK_FOR  276\n#define TK_DO   277\n#define TK_NULL 278\n#define TK_FOREACH  279\n#define TK_IN   280\n#define TK_NEWSLOT  281\n#define TK_MODULO   282\n#define TK_LOCAL    283\n#define TK_CLONE    284\n#define TK_FUNCTION 285\n#define TK_RETURN   286\n#define TK_TYPEOF   287\n#define TK_UMINUS   288\n#define TK_PLUSEQ   289\n#define TK_MINUSEQ  290\n#define TK_CONTINUE 291\n#define TK_YIELD 292\n#define TK_TRY 293\n#define TK_CATCH 294\n#define TK_THROW 295\n#define TK_SHIFTL 296\n#define TK_SHIFTR 297\n#define TK_RESUME 298\n#define TK_DOUBLE_COLON 299\n#define TK_CASE 300\n#define TK_DEFAULT 301\n#define TK_THIS 302\n#define TK_PLUSPLUS 303\n#define TK_MINUSMINUS 304\n#define TK_3WAYSCMP 305\n#define TK_USHIFTR 306\n#define TK_CLASS 307\n#define TK_EXTENDS 308\n#define TK_CONSTRUCTOR 310\n#define TK_INSTANCEOF 311\n#define TK_VARPARAMS 312\n#define TK___LINE__ 313\n#define TK___FILE__ 314\n#define TK_TRUE 315\n#define TK_FALSE 316\n#define TK_MULEQ 317\n#define TK_DIVEQ 318\n#define TK_MODEQ 319\n#define TK_ATTR_OPEN 320\n#define TK_ATTR_CLOSE 321\n#define TK_STATIC 322\n#define TK_ENUM 323\n#define TK_CONST 324\n#define TK_RAWCALL 325\n\n\n\ntypedef void(*CompilerErrorFunc)(void *ud, const SQChar *s);\nbool Compile(SQVM *vm, SQLEXREADFUNC rg, SQUserPointer up, const SQChar *sourcename, SQObjectPtr &out, bool raiseerror, bool lineinfo);\n#endif //_SQCOMPILER_H_\n"
  },
  {
    "path": "extlibs/squirrel/squirrel/sqdebug.cpp",
    "content": "/*\n    see copyright notice in squirrel.h\n*/\n#include \"sqpcheader.h\"\n#include <stdarg.h>\n#include \"sqvm.h\"\n#include \"sqfuncproto.h\"\n#include \"sqclosure.h\"\n#include \"sqstring.h\"\n\nSQRESULT sq_getfunctioninfo(HSQUIRRELVM v,SQInteger level,SQFunctionInfo *fi)\n{\n    SQInteger cssize = v->_callsstacksize;\n    if (cssize > level) {\n        SQVM::CallInfo &ci = v->_callsstack[cssize-level-1];\n        if(sq_isclosure(ci._closure)) {\n            SQClosure *c = _closure(ci._closure);\n            SQFunctionProto *proto = c->_function;\n            fi->funcid = proto;\n            fi->name = sq_type(proto->_name) == OT_STRING?_stringval(proto->_name):_SC(\"unknown\");\n            fi->source = sq_type(proto->_sourcename) == OT_STRING?_stringval(proto->_sourcename):_SC(\"unknown\");\n            fi->line = proto->_lineinfos[0]._line;\n            return SQ_OK;\n        }\n    }\n    return sq_throwerror(v,_SC(\"the object is not a closure\"));\n}\n\nSQRESULT sq_stackinfos(HSQUIRRELVM v, SQInteger level, SQStackInfos *si)\n{\n    SQInteger cssize = v->_callsstacksize;\n    if (cssize > level) {\n        memset(si, 0, sizeof(SQStackInfos));\n        SQVM::CallInfo &ci = v->_callsstack[cssize-level-1];\n        switch (sq_type(ci._closure)) {\n        case OT_CLOSURE:{\n            SQFunctionProto *func = _closure(ci._closure)->_function;\n            if (sq_type(func->_name) == OT_STRING)\n                si->funcname = _stringval(func->_name);\n            if (sq_type(func->_sourcename) == OT_STRING)\n                si->source = _stringval(func->_sourcename);\n            si->line = func->GetLine(ci._ip);\n                        }\n            break;\n        case OT_NATIVECLOSURE:\n            si->source = _SC(\"NATIVE\");\n            si->funcname = _SC(\"unknown\");\n            if(sq_type(_nativeclosure(ci._closure)->_name) == OT_STRING)\n                si->funcname = _stringval(_nativeclosure(ci._closure)->_name);\n            si->line = -1;\n            break;\n        default: break; //shutup compiler\n        }\n        return SQ_OK;\n    }\n    return SQ_ERROR;\n}\n\nvoid SQVM::Raise_Error(const SQChar *s, ...)\n{\n    va_list vl;\n    va_start(vl, s);\n    SQInteger buffersize = (SQInteger)scstrlen(s)+(NUMBER_MAX_CHAR*2);\n    scvsprintf(_sp(sq_rsl(buffersize)),buffersize, s, vl);\n    va_end(vl);\n    _lasterror = SQString::Create(_ss(this),_spval,-1);\n}\n\nvoid SQVM::Raise_Error(const SQObjectPtr &desc)\n{\n    _lasterror = desc;\n}\n\nSQString *SQVM::PrintObjVal(const SQObjectPtr &o)\n{\n    switch(sq_type(o)) {\n    case OT_STRING: return _string(o);\n    case OT_INTEGER:\n        scsprintf(_sp(sq_rsl(NUMBER_MAX_CHAR+1)),sq_rsl(NUMBER_MAX_CHAR), _PRINT_INT_FMT, _integer(o));\n        return SQString::Create(_ss(this), _spval);\n        break;\n    case OT_FLOAT:\n        scsprintf(_sp(sq_rsl(NUMBER_MAX_CHAR+1)), sq_rsl(NUMBER_MAX_CHAR), _SC(\"%.14g\"), _float(o));\n        return SQString::Create(_ss(this), _spval);\n        break;\n    default:\n        return SQString::Create(_ss(this), GetTypeName(o));\n    }\n}\n\nvoid SQVM::Raise_IdxError(const SQObjectPtr &o)\n{\n    SQObjectPtr oval = PrintObjVal(o);\n    Raise_Error(_SC(\"the index '%.50s' does not exist\"), _stringval(oval));\n}\n\nvoid SQVM::Raise_CompareError(const SQObject &o1, const SQObject &o2)\n{\n    SQObjectPtr oval1 = PrintObjVal(o1), oval2 = PrintObjVal(o2);\n    Raise_Error(_SC(\"comparison between '%.50s' and '%.50s'\"), _stringval(oval1), _stringval(oval2));\n}\n\n\nvoid SQVM::Raise_ParamTypeError(SQInteger nparam,SQInteger typemask,SQInteger type)\n{\n    SQObjectPtr exptypes = SQString::Create(_ss(this), _SC(\"\"), -1);\n    SQInteger found = 0;\n    for(SQInteger i=0; i<16; i++)\n    {\n        SQInteger mask = ((SQInteger)1) << i;\n        if(typemask & (mask)) {\n            if(found>0) StringCat(exptypes,SQString::Create(_ss(this), _SC(\"|\"), -1), exptypes);\n            found ++;\n            StringCat(exptypes,SQString::Create(_ss(this), IdType2Name((SQObjectType)mask), -1), exptypes);\n        }\n    }\n    Raise_Error(_SC(\"parameter %d has an invalid type '%s' ; expected: '%s'\"), nparam, IdType2Name((SQObjectType)type), _stringval(exptypes));\n}\n"
  },
  {
    "path": "extlibs/squirrel/squirrel/sqfuncproto.h",
    "content": "/*  see copyright notice in squirrel.h */\n#ifndef _SQFUNCTION_H_\n#define _SQFUNCTION_H_\n\n#include \"sqopcodes.h\"\n\nenum SQOuterType {\n    otLOCAL = 0,\n    otOUTER = 1\n};\n\nstruct SQOuterVar\n{\n\n    SQOuterVar(){}\n    SQOuterVar(const SQObjectPtr &name,const SQObjectPtr &src,SQOuterType t)\n    {\n        _name = name;\n        _src=src;\n        _type=t;\n    }\n    SQOuterVar(const SQOuterVar &ov)\n    {\n        _type=ov._type;\n        _src=ov._src;\n        _name=ov._name;\n    }\n    SQOuterType _type;\n    SQObjectPtr _name;\n    SQObjectPtr _src;\n};\n\nstruct SQLocalVarInfo\n{\n    SQLocalVarInfo():_start_op(0),_end_op(0),_pos(0){}\n    SQLocalVarInfo(const SQLocalVarInfo &lvi)\n    {\n        _name=lvi._name;\n        _start_op=lvi._start_op;\n        _end_op=lvi._end_op;\n        _pos=lvi._pos;\n    }\n    SQObjectPtr _name;\n    SQUnsignedInteger _start_op;\n    SQUnsignedInteger _end_op;\n    SQUnsignedInteger _pos;\n};\n\nstruct SQLineInfo { SQInteger _line;SQInteger _op; };\n\ntypedef sqvector<SQOuterVar> SQOuterVarVec;\ntypedef sqvector<SQLocalVarInfo> SQLocalVarInfoVec;\ntypedef sqvector<SQLineInfo> SQLineInfoVec;\n\n#define _FUNC_SIZE(ni,nl,nparams,nfuncs,nouters,nlineinf,localinf,defparams) (sizeof(SQFunctionProto) \\\n        +((ni-1)*sizeof(SQInstruction))+(nl*sizeof(SQObjectPtr)) \\\n        +(nparams*sizeof(SQObjectPtr))+(nfuncs*sizeof(SQObjectPtr)) \\\n        +(nouters*sizeof(SQOuterVar))+(nlineinf*sizeof(SQLineInfo)) \\\n        +(localinf*sizeof(SQLocalVarInfo))+(defparams*sizeof(SQInteger)))\n\n\nstruct SQFunctionProto : public CHAINABLE_OBJ\n{\nprivate:\n    SQFunctionProto(SQSharedState *ss);\n    ~SQFunctionProto();\n\npublic:\n    static SQFunctionProto *Create(SQSharedState *ss,SQInteger ninstructions,\n        SQInteger nliterals,SQInteger nparameters,\n        SQInteger nfunctions,SQInteger noutervalues,\n        SQInteger nlineinfos,SQInteger nlocalvarinfos,SQInteger ndefaultparams)\n    {\n        SQFunctionProto *f;\n        //I compact the whole class and members in a single memory allocation\n        f = (SQFunctionProto *)sq_vm_malloc(_FUNC_SIZE(ninstructions,nliterals,nparameters,nfunctions,noutervalues,nlineinfos,nlocalvarinfos,ndefaultparams));\n        new (f) SQFunctionProto(ss);\n        f->_ninstructions = ninstructions;\n        f->_literals = (SQObjectPtr*)&f->_instructions[ninstructions];\n        f->_nliterals = nliterals;\n        f->_parameters = (SQObjectPtr*)&f->_literals[nliterals];\n        f->_nparameters = nparameters;\n        f->_functions = (SQObjectPtr*)&f->_parameters[nparameters];\n        f->_nfunctions = nfunctions;\n        f->_outervalues = (SQOuterVar*)&f->_functions[nfunctions];\n        f->_noutervalues = noutervalues;\n        f->_lineinfos = (SQLineInfo *)&f->_outervalues[noutervalues];\n        f->_nlineinfos = nlineinfos;\n        f->_localvarinfos = (SQLocalVarInfo *)&f->_lineinfos[nlineinfos];\n        f->_nlocalvarinfos = nlocalvarinfos;\n        f->_defaultparams = (SQInteger *)&f->_localvarinfos[nlocalvarinfos];\n        f->_ndefaultparams = ndefaultparams;\n\n        _CONSTRUCT_VECTOR(SQObjectPtr,f->_nliterals,f->_literals);\n        _CONSTRUCT_VECTOR(SQObjectPtr,f->_nparameters,f->_parameters);\n        _CONSTRUCT_VECTOR(SQObjectPtr,f->_nfunctions,f->_functions);\n        _CONSTRUCT_VECTOR(SQOuterVar,f->_noutervalues,f->_outervalues);\n        //_CONSTRUCT_VECTOR(SQLineInfo,f->_nlineinfos,f->_lineinfos); //not required are 2 integers\n        _CONSTRUCT_VECTOR(SQLocalVarInfo,f->_nlocalvarinfos,f->_localvarinfos);\n        return f;\n    }\n    void Release(){\n        _DESTRUCT_VECTOR(SQObjectPtr,_nliterals,_literals);\n        _DESTRUCT_VECTOR(SQObjectPtr,_nparameters,_parameters);\n        _DESTRUCT_VECTOR(SQObjectPtr,_nfunctions,_functions);\n        _DESTRUCT_VECTOR(SQOuterVar,_noutervalues,_outervalues);\n        //_DESTRUCT_VECTOR(SQLineInfo,_nlineinfos,_lineinfos); //not required are 2 integers\n        _DESTRUCT_VECTOR(SQLocalVarInfo,_nlocalvarinfos,_localvarinfos);\n        SQInteger size = _FUNC_SIZE(_ninstructions,_nliterals,_nparameters,_nfunctions,_noutervalues,_nlineinfos,_nlocalvarinfos,_ndefaultparams);\n        this->~SQFunctionProto();\n        sq_vm_free(this,size);\n    }\n\n    const SQChar* GetLocal(SQVM *v,SQUnsignedInteger stackbase,SQUnsignedInteger nseq,SQUnsignedInteger nop);\n    SQInteger GetLine(SQInstruction *curr);\n    bool Save(SQVM *v,SQUserPointer up,SQWRITEFUNC write);\n    static bool Load(SQVM *v,SQUserPointer up,SQREADFUNC read,SQObjectPtr &ret);\n#ifndef NO_GARBAGE_COLLECTOR\n    void Mark(SQCollectable **chain);\n    void Finalize(){ _NULL_SQOBJECT_VECTOR(_literals,_nliterals); }\n    SQObjectType GetType() {return OT_FUNCPROTO;}\n#endif\n    SQObjectPtr _sourcename;\n    SQObjectPtr _name;\n    SQInteger _stacksize;\n    bool _bgenerator;\n    SQInteger _varparams;\n\n    SQInteger _nlocalvarinfos;\n    SQLocalVarInfo *_localvarinfos;\n\n    SQInteger _nlineinfos;\n    SQLineInfo *_lineinfos;\n\n    SQInteger _nliterals;\n    SQObjectPtr *_literals;\n\n    SQInteger _nparameters;\n    SQObjectPtr *_parameters;\n\n    SQInteger _nfunctions;\n    SQObjectPtr *_functions;\n\n    SQInteger _noutervalues;\n    SQOuterVar *_outervalues;\n\n    SQInteger _ndefaultparams;\n    SQInteger *_defaultparams;\n\n    SQInteger _ninstructions;\n    SQInstruction _instructions[1];\n};\n\n#endif //_SQFUNCTION_H_\n"
  },
  {
    "path": "extlibs/squirrel/squirrel/sqfuncstate.cpp",
    "content": "/*\n    see copyright notice in squirrel.h\n*/\n#include \"sqpcheader.h\"\n#ifndef NO_COMPILER\n#include \"sqcompiler.h\"\n#include \"sqstring.h\"\n#include \"sqfuncproto.h\"\n#include \"sqtable.h\"\n#include \"sqopcodes.h\"\n#include \"sqfuncstate.h\"\n\n#ifdef _DEBUG_DUMP\nSQInstructionDesc g_InstrDesc[]={\n    {_SC(\"_OP_LINE\")},\n    {_SC(\"_OP_LOAD\")},\n    {_SC(\"_OP_LOADINT\")},\n    {_SC(\"_OP_LOADFLOAT\")},\n    {_SC(\"_OP_DLOAD\")},\n    {_SC(\"_OP_TAILCALL\")},\n    {_SC(\"_OP_CALL\")},\n    {_SC(\"_OP_PREPCALL\")},\n    {_SC(\"_OP_PREPCALLK\")},\n    {_SC(\"_OP_GETK\")},\n    {_SC(\"_OP_MOVE\")},\n    {_SC(\"_OP_NEWSLOT\")},\n    {_SC(\"_OP_DELETE\")},\n    {_SC(\"_OP_SET\")},\n    {_SC(\"_OP_GET\")},\n    {_SC(\"_OP_EQ\")},\n    {_SC(\"_OP_NE\")},\n    {_SC(\"_OP_ADD\")},\n    {_SC(\"_OP_SUB\")},\n    {_SC(\"_OP_MUL\")},\n    {_SC(\"_OP_DIV\")},\n    {_SC(\"_OP_MOD\")},\n    {_SC(\"_OP_BITW\")},\n    {_SC(\"_OP_RETURN\")},\n    {_SC(\"_OP_LOADNULLS\")},\n    {_SC(\"_OP_LOADROOT\")},\n    {_SC(\"_OP_LOADBOOL\")},\n    {_SC(\"_OP_DMOVE\")},\n    {_SC(\"_OP_JMP\")},\n    {_SC(\"_OP_JCMP\")},\n    {_SC(\"_OP_JZ\")},\n    {_SC(\"_OP_SETOUTER\")},\n    {_SC(\"_OP_GETOUTER\")},\n    {_SC(\"_OP_NEWOBJ\")},\n    {_SC(\"_OP_APPENDARRAY\")},\n    {_SC(\"_OP_COMPARITH\")},\n    {_SC(\"_OP_INC\")},\n    {_SC(\"_OP_INCL\")},\n    {_SC(\"_OP_PINC\")},\n    {_SC(\"_OP_PINCL\")},\n    {_SC(\"_OP_CMP\")},\n    {_SC(\"_OP_EXISTS\")},\n    {_SC(\"_OP_INSTANCEOF\")},\n    {_SC(\"_OP_AND\")},\n    {_SC(\"_OP_OR\")},\n    {_SC(\"_OP_NEG\")},\n    {_SC(\"_OP_NOT\")},\n    {_SC(\"_OP_BWNOT\")},\n    {_SC(\"_OP_CLOSURE\")},\n    {_SC(\"_OP_YIELD\")},\n    {_SC(\"_OP_RESUME\")},\n    {_SC(\"_OP_FOREACH\")},\n    {_SC(\"_OP_POSTFOREACH\")},\n    {_SC(\"_OP_CLONE\")},\n    {_SC(\"_OP_TYPEOF\")},\n    {_SC(\"_OP_PUSHTRAP\")},\n    {_SC(\"_OP_POPTRAP\")},\n    {_SC(\"_OP_THROW\")},\n    {_SC(\"_OP_NEWSLOTA\")},\n    {_SC(\"_OP_GETBASE\")},\n    {_SC(\"_OP_CLOSE\")},\n};\n#endif\nvoid DumpLiteral(SQObjectPtr &o)\n{\n    switch(sq_type(o)){\n        case OT_STRING: scprintf(_SC(\"\\\"%s\\\"\"),_stringval(o));break;\n        case OT_FLOAT: scprintf(_SC(\"{%f}\"),_float(o));break;\n        case OT_INTEGER: scprintf(_SC(\"{\") _PRINT_INT_FMT _SC(\"}\"),_integer(o));break;\n        case OT_BOOL: scprintf(_SC(\"%s\"),_integer(o)?_SC(\"true\"):_SC(\"false\"));break;\n        default: scprintf(_SC(\"(%s %p)\"),GetTypeName(o),(void*)_rawval(o));break; break; //shut up compiler\n    }\n}\n\nSQFuncState::SQFuncState(SQSharedState *ss,SQFuncState *parent,CompilerErrorFunc efunc,void *ed)\n{\n        _nliterals = 0;\n        _literals = SQTable::Create(ss,0);\n        _strings =  SQTable::Create(ss,0);\n        _sharedstate = ss;\n        _lastline = 0;\n        _optimization = true;\n        _parent = parent;\n        _stacksize = 0;\n        _traps = 0;\n        _returnexp = 0;\n        _varparams = false;\n        _errfunc = efunc;\n        _errtarget = ed;\n        _bgenerator = false;\n        _outers = 0;\n        _ss = ss;\n\n}\n\nvoid SQFuncState::Error(const SQChar *err)\n{\n    _errfunc(_errtarget,err);\n}\n\n#ifdef _DEBUG_DUMP\nvoid SQFuncState::Dump(SQFunctionProto *func)\n{\n    SQUnsignedInteger n=0,i;\n    SQInteger si;\n    scprintf(_SC(\"SQInstruction sizeof %d\\n\"),(SQInt32)sizeof(SQInstruction));\n    scprintf(_SC(\"SQObject sizeof %d\\n\"), (SQInt32)sizeof(SQObject));\n    scprintf(_SC(\"--------------------------------------------------------------------\\n\"));\n    scprintf(_SC(\"*****FUNCTION [%s]\\n\"),sq_type(func->_name)==OT_STRING?_stringval(func->_name):_SC(\"unknown\"));\n    scprintf(_SC(\"-----LITERALS\\n\"));\n    SQObjectPtr refidx,key,val;\n    SQInteger idx;\n    SQObjectPtrVec templiterals;\n    templiterals.resize(_nliterals);\n    while((idx=_table(_literals)->Next(false,refidx,key,val))!=-1) {\n        refidx=idx;\n        templiterals[_integer(val)]=key;\n    }\n    for(i=0;i<templiterals.size();i++){\n        scprintf(_SC(\"[%d] \"), (SQInt32)n);\n        DumpLiteral(templiterals[i]);\n        scprintf(_SC(\"\\n\"));\n        n++;\n    }\n    scprintf(_SC(\"-----PARAMS\\n\"));\n    if(_varparams)\n        scprintf(_SC(\"<<VARPARAMS>>\\n\"));\n    n=0;\n    for(i=0;i<_parameters.size();i++){\n        scprintf(_SC(\"[%d] \"), (SQInt32)n);\n        DumpLiteral(_parameters[i]);\n        scprintf(_SC(\"\\n\"));\n        n++;\n    }\n    scprintf(_SC(\"-----LOCALS\\n\"));\n    for(si=0;si<func->_nlocalvarinfos;si++){\n        SQLocalVarInfo lvi=func->_localvarinfos[si];\n        scprintf(_SC(\"[%d] %s \\t%d %d\\n\"), (SQInt32)lvi._pos,_stringval(lvi._name), (SQInt32)lvi._start_op, (SQInt32)lvi._end_op);\n        n++;\n    }\n    scprintf(_SC(\"-----LINE INFO\\n\"));\n    for(i=0;i<_lineinfos.size();i++){\n        SQLineInfo li=_lineinfos[i];\n        scprintf(_SC(\"op [%d] line [%d] \\n\"), (SQInt32)li._op, (SQInt32)li._line);\n        n++;\n    }\n    scprintf(_SC(\"-----dump\\n\"));\n    n=0;\n    for(i=0;i<_instructions.size();i++){\n        SQInstruction &inst=_instructions[i];\n        if(inst.op==_OP_LOAD || inst.op==_OP_DLOAD || inst.op==_OP_PREPCALLK || inst.op==_OP_GETK ){\n\n            SQInteger lidx = inst._arg1;\n            scprintf(_SC(\"[%03d] %15s %d \"), (SQInt32)n,g_InstrDesc[inst.op].name,inst._arg0);\n            if(lidx >= 0xFFFFFFFF)\n                scprintf(_SC(\"null\"));\n            else {\n                SQInteger refidx;\n                SQObjectPtr val,key,refo;\n                while(((refidx=_table(_literals)->Next(false,refo,key,val))!= -1) && (_integer(val) != lidx)) {\n                    refo = refidx;\n                }\n                DumpLiteral(key);\n            }\n            if(inst.op != _OP_DLOAD) {\n                scprintf(_SC(\" %d %d \\n\"),inst._arg2,inst._arg3);\n            }\n            else {\n                scprintf(_SC(\" %d \"),inst._arg2);\n                lidx = inst._arg3;\n                if(lidx >= 0xFFFFFFFF)\n                    scprintf(_SC(\"null\"));\n                else {\n                    SQInteger refidx;\n                    SQObjectPtr val,key,refo;\n                    while(((refidx=_table(_literals)->Next(false,refo,key,val))!= -1) && (_integer(val) != lidx)) {\n                        refo = refidx;\n                }\n                DumpLiteral(key);\n                scprintf(_SC(\"\\n\"));\n            }\n            }\n        }\n        else if(inst.op==_OP_LOADFLOAT) {\n            scprintf(_SC(\"[%03d] %15s %d %f %d %d\\n\"), (SQInt32)n,g_InstrDesc[inst.op].name,inst._arg0,*((SQFloat*)&inst._arg1),inst._arg2,inst._arg3);\n        }\n    /*  else if(inst.op==_OP_ARITH){\n            scprintf(_SC(\"[%03d] %15s %d %d %d %c\\n\"),n,g_InstrDesc[inst.op].name,inst._arg0,inst._arg1,inst._arg2,inst._arg3);\n        }*/\n        else {\n            scprintf(_SC(\"[%03d] %15s %d %d %d %d\\n\"), (SQInt32)n,g_InstrDesc[inst.op].name,inst._arg0,inst._arg1,inst._arg2,inst._arg3);\n        }\n        n++;\n    }\n    scprintf(_SC(\"-----\\n\"));\n    scprintf(_SC(\"stack size[%d]\\n\"), (SQInt32)func->_stacksize);\n    scprintf(_SC(\"--------------------------------------------------------------------\\n\\n\"));\n}\n#endif\n\nSQInteger SQFuncState::GetNumericConstant(const SQInteger cons)\n{\n    return GetConstant(SQObjectPtr(cons));\n}\n\nSQInteger SQFuncState::GetNumericConstant(const SQFloat cons)\n{\n    return GetConstant(SQObjectPtr(cons));\n}\n\nSQInteger SQFuncState::GetConstant(const SQObject &cons)\n{\n    SQObjectPtr val;\n    if(!_table(_literals)->Get(cons,val))\n    {\n        val = _nliterals;\n        _table(_literals)->NewSlot(cons,val);\n        _nliterals++;\n        if(_nliterals > MAX_LITERALS) {\n            val.Null();\n            Error(_SC(\"internal compiler error: too many literals\"));\n        }\n    }\n    return _integer(val);\n}\n\nvoid SQFuncState::SetInstructionParams(SQInteger pos,SQInteger arg0,SQInteger arg1,SQInteger arg2,SQInteger arg3)\n{\n    _instructions[pos]._arg0=(unsigned char)*((SQUnsignedInteger *)&arg0);\n    _instructions[pos]._arg1=(SQInt32)*((SQUnsignedInteger *)&arg1);\n    _instructions[pos]._arg2=(unsigned char)*((SQUnsignedInteger *)&arg2);\n    _instructions[pos]._arg3=(unsigned char)*((SQUnsignedInteger *)&arg3);\n}\n\nvoid SQFuncState::SetInstructionParam(SQInteger pos,SQInteger arg,SQInteger val)\n{\n    switch(arg){\n        case 0:_instructions[pos]._arg0=(unsigned char)*((SQUnsignedInteger *)&val);break;\n        case 1:case 4:_instructions[pos]._arg1=(SQInt32)*((SQUnsignedInteger *)&val);break;\n        case 2:_instructions[pos]._arg2=(unsigned char)*((SQUnsignedInteger *)&val);break;\n        case 3:_instructions[pos]._arg3=(unsigned char)*((SQUnsignedInteger *)&val);break;\n    };\n}\n\nSQInteger SQFuncState::AllocStackPos()\n{\n    SQInteger npos=_vlocals.size();\n    _vlocals.push_back(SQLocalVarInfo());\n    if(_vlocals.size()>((SQUnsignedInteger)_stacksize)) {\n        if(_stacksize>MAX_FUNC_STACKSIZE) Error(_SC(\"internal compiler error: too many locals\"));\n        _stacksize=_vlocals.size();\n    }\n    return npos;\n}\n\nSQInteger SQFuncState::PushTarget(SQInteger n)\n{\n    if(n!=-1){\n        _targetstack.push_back(n);\n        return n;\n    }\n    n=AllocStackPos();\n    _targetstack.push_back(n);\n    return n;\n}\n\nSQInteger SQFuncState::GetUpTarget(SQInteger n){\n    return _targetstack[((_targetstack.size()-1)-n)];\n}\n\nSQInteger SQFuncState::TopTarget(){\n    return _targetstack.back();\n}\nSQInteger SQFuncState::PopTarget()\n{\n    SQUnsignedInteger npos=_targetstack.back();\n    assert(npos < _vlocals.size());\n    SQLocalVarInfo &t = _vlocals[npos];\n    if(sq_type(t._name)==OT_NULL){\n        _vlocals.pop_back();\n    }\n    _targetstack.pop_back();\n    return npos;\n}\n\nSQInteger SQFuncState::GetStackSize()\n{\n    return _vlocals.size();\n}\n\nSQInteger SQFuncState::CountOuters(SQInteger stacksize)\n{\n    SQInteger outers = 0;\n    SQInteger k = _vlocals.size() - 1;\n    while(k >= stacksize) {\n        SQLocalVarInfo &lvi = _vlocals[k];\n        k--;\n        if(lvi._end_op == UINT_MINUS_ONE) { //this means is an outer\n            outers++;\n        }\n    }\n    return outers;\n}\n\nvoid SQFuncState::SetStackSize(SQInteger n)\n{\n    SQInteger size=_vlocals.size();\n    while(size>n){\n        size--;\n        SQLocalVarInfo lvi = _vlocals.back();\n        if(sq_type(lvi._name)!=OT_NULL){\n            if(lvi._end_op == UINT_MINUS_ONE) { //this means is an outer\n                _outers--;\n            }\n            lvi._end_op = GetCurrentPos();\n            _localvarinfos.push_back(lvi);\n        }\n        _vlocals.pop_back();\n    }\n}\n\nbool SQFuncState::IsConstant(const SQObject &name,SQObject &e)\n{\n    SQObjectPtr val;\n    if(_table(_sharedstate->_consts)->Get(name,val)) {\n        e = val;\n        return true;\n    }\n    return false;\n}\n\nbool SQFuncState::IsLocal(SQUnsignedInteger stkpos)\n{\n    if(stkpos>=_vlocals.size())return false;\n    else if(sq_type(_vlocals[stkpos]._name)!=OT_NULL)return true;\n    return false;\n}\n\nSQInteger SQFuncState::PushLocalVariable(const SQObject &name)\n{\n    SQInteger pos=_vlocals.size();\n    SQLocalVarInfo lvi;\n    lvi._name=name;\n    lvi._start_op=GetCurrentPos()+1;\n    lvi._pos=_vlocals.size();\n    _vlocals.push_back(lvi);\n    if(_vlocals.size()>((SQUnsignedInteger)_stacksize))_stacksize=_vlocals.size();\n    return pos;\n}\n\n\n\nSQInteger SQFuncState::GetLocalVariable(const SQObject &name)\n{\n    SQInteger locals=_vlocals.size();\n    while(locals>=1){\n        SQLocalVarInfo &lvi = _vlocals[locals-1];\n        if(sq_type(lvi._name)==OT_STRING && _string(lvi._name)==_string(name)){\n            return locals-1;\n        }\n        locals--;\n    }\n    return -1;\n}\n\nvoid SQFuncState::MarkLocalAsOuter(SQInteger pos)\n{\n    SQLocalVarInfo &lvi = _vlocals[pos];\n    lvi._end_op = UINT_MINUS_ONE;\n    _outers++;\n}\n\nSQInteger SQFuncState::GetOuterVariable(const SQObject &name)\n{\n    SQInteger outers = _outervalues.size();\n    for(SQInteger i = 0; i<outers; i++) {\n        if(_string(_outervalues[i]._name) == _string(name))\n            return i;\n    }\n    SQInteger pos=-1;\n    if(_parent) {\n        pos = _parent->GetLocalVariable(name);\n        if(pos == -1) {\n            pos = _parent->GetOuterVariable(name);\n            if(pos != -1) {\n                _outervalues.push_back(SQOuterVar(name,SQObjectPtr(SQInteger(pos)),otOUTER)); //local\n                return _outervalues.size() - 1;\n            }\n        }\n        else {\n            _parent->MarkLocalAsOuter(pos);\n            _outervalues.push_back(SQOuterVar(name,SQObjectPtr(SQInteger(pos)),otLOCAL)); //local\n            return _outervalues.size() - 1;\n\n\n        }\n    }\n    return -1;\n}\n\nvoid SQFuncState::AddParameter(const SQObject &name)\n{\n    PushLocalVariable(name);\n    _parameters.push_back(name);\n}\n\nvoid SQFuncState::AddLineInfos(SQInteger line,bool lineop,bool force)\n{\n    if(_lastline!=line || force){\n        SQLineInfo li;\n        li._line=line;li._op=(GetCurrentPos()+1);\n        if(lineop)AddInstruction(_OP_LINE,0,line);\n        if(_lastline!=line) {\n            _lineinfos.push_back(li);\n        }\n        _lastline=line;\n    }\n}\n\nvoid SQFuncState::DiscardTarget()\n{\n    SQInteger discardedtarget = PopTarget();\n    SQInteger size = _instructions.size();\n    if(size > 0 && _optimization){\n        SQInstruction &pi = _instructions[size-1];//previous instruction\n        switch(pi.op) {\n        case _OP_SET:case _OP_NEWSLOT:case _OP_SETOUTER:case _OP_CALL:\n            if(pi._arg0 == discardedtarget) {\n                pi._arg0 = 0xFF;\n            }\n        }\n    }\n}\n\nvoid SQFuncState::AddInstruction(SQInstruction &i)\n{\n    SQInteger size = _instructions.size();\n    if(size > 0 && _optimization){ //simple optimizer\n        SQInstruction &pi = _instructions[size-1];//previous instruction\n        switch(i.op) {\n        case _OP_JZ:\n            if( pi.op == _OP_CMP && pi._arg1 < 0xFF) {\n                pi.op = _OP_JCMP;\n                pi._arg0 = (unsigned char)pi._arg1;\n                pi._arg1 = i._arg1;\n                return;\n            }\n            break;\n        case _OP_SET:\n        case _OP_NEWSLOT:\n            if(i._arg0 == i._arg3) {\n                i._arg0 = 0xFF;\n            }\n            break;\n        case _OP_SETOUTER:\n            if(i._arg0 == i._arg2) {\n                i._arg0 = 0xFF;\n            }\n            break;\n        case _OP_RETURN:\n            if( _parent && i._arg0 != MAX_FUNC_STACKSIZE && pi.op == _OP_CALL && _returnexp < size-1) {\n                pi.op = _OP_TAILCALL;\n            } else if(pi.op == _OP_CLOSE){\n                pi = i;\n                return;\n            }\n        break;\n        case _OP_GET:\n            if( pi.op == _OP_LOAD && pi._arg0 == i._arg2 && (!IsLocal(pi._arg0))){\n                pi._arg1 = pi._arg1;\n                pi._arg2 = (unsigned char)i._arg1;\n                pi.op = _OP_GETK;\n                pi._arg0 = i._arg0;\n\n                return;\n            }\n        break;\n        case _OP_PREPCALL:\n            if( pi.op == _OP_LOAD  && pi._arg0 == i._arg1 && (!IsLocal(pi._arg0))){\n                pi.op = _OP_PREPCALLK;\n                pi._arg0 = i._arg0;\n                pi._arg1 = pi._arg1;\n                pi._arg2 = i._arg2;\n                pi._arg3 = i._arg3;\n                return;\n            }\n            break;\n        case _OP_APPENDARRAY: {\n            SQInteger aat = -1;\n            switch(pi.op) {\n            case _OP_LOAD: aat = AAT_LITERAL; break;\n            case _OP_LOADINT: aat = AAT_INT; break;\n            case _OP_LOADBOOL: aat = AAT_BOOL; break;\n            case _OP_LOADFLOAT: aat = AAT_FLOAT; break;\n            default: break;\n            }\n            if(aat != -1 && pi._arg0 == i._arg1 && (!IsLocal(pi._arg0))){\n                pi.op = _OP_APPENDARRAY;\n                pi._arg0 = i._arg0;\n                pi._arg1 = pi._arg1;\n                pi._arg2 = (unsigned char)aat;\n                pi._arg3 = MAX_FUNC_STACKSIZE;\n                return;\n            }\n                              }\n            break;\n        case _OP_MOVE:\n            switch(pi.op) {\n            case _OP_GET: case _OP_ADD: case _OP_SUB: case _OP_MUL: case _OP_DIV: case _OP_MOD: case _OP_BITW:\n            case _OP_LOADINT: case _OP_LOADFLOAT: case _OP_LOADBOOL: case _OP_LOAD:\n\n                if(pi._arg0 == i._arg1)\n                {\n                    pi._arg0 = i._arg0;\n                    _optimization = false;\n                    //_result_elimination = false;\n                    return;\n                }\n            }\n\n            if(pi.op == _OP_MOVE)\n            {\n                pi.op = _OP_DMOVE;\n                pi._arg2 = i._arg0;\n                pi._arg3 = (unsigned char)i._arg1;\n                return;\n            }\n            break;\n        case _OP_LOAD:\n            if(pi.op == _OP_LOAD && i._arg1 < 256) {\n                pi.op = _OP_DLOAD;\n                pi._arg2 = i._arg0;\n                pi._arg3 = (unsigned char)i._arg1;\n                return;\n            }\n            break;\n        case _OP_EQ:case _OP_NE:\n            if(pi.op == _OP_LOAD && pi._arg0 == i._arg1 && (!IsLocal(pi._arg0) ))\n            {\n                pi.op = i.op;\n                pi._arg0 = i._arg0;\n                pi._arg1 = pi._arg1;\n                pi._arg2 = i._arg2;\n                pi._arg3 = MAX_FUNC_STACKSIZE;\n                return;\n            }\n            break;\n        case _OP_LOADNULLS:\n            if((pi.op == _OP_LOADNULLS && pi._arg0+pi._arg1 == i._arg0)) {\n\n                pi._arg1 = pi._arg1 + 1;\n                pi.op = _OP_LOADNULLS;\n                return;\n            }\n            break;\n        case _OP_LINE:\n            if(pi.op == _OP_LINE) {\n                _instructions.pop_back();\n                _lineinfos.pop_back();\n            }\n            break;\n        }\n    }\n    _optimization = true;\n    _instructions.push_back(i);\n}\n\nSQObject SQFuncState::CreateString(const SQChar *s,SQInteger len)\n{\n    SQObjectPtr ns(SQString::Create(_sharedstate,s,len));\n    _table(_strings)->NewSlot(ns,(SQInteger)1);\n    return ns;\n}\n\nSQObject SQFuncState::CreateTable()\n{\n    SQObjectPtr nt(SQTable::Create(_sharedstate,0));\n    _table(_strings)->NewSlot(nt,(SQInteger)1);\n    return nt;\n}\n\nSQFunctionProto *SQFuncState::BuildProto()\n{\n\n    SQFunctionProto *f=SQFunctionProto::Create(_ss,_instructions.size(),\n        _nliterals,_parameters.size(),_functions.size(),_outervalues.size(),\n        _lineinfos.size(),_localvarinfos.size(),_defaultparams.size());\n\n    SQObjectPtr refidx,key,val;\n    SQInteger idx;\n\n    f->_stacksize = _stacksize;\n    f->_sourcename = _sourcename;\n    f->_bgenerator = _bgenerator;\n    f->_name = _name;\n\n    while((idx=_table(_literals)->Next(false,refidx,key,val))!=-1) {\n        f->_literals[_integer(val)]=key;\n        refidx=idx;\n    }\n\n    for(SQUnsignedInteger nf = 0; nf < _functions.size(); nf++) f->_functions[nf] = _functions[nf];\n    for(SQUnsignedInteger np = 0; np < _parameters.size(); np++) f->_parameters[np] = _parameters[np];\n    for(SQUnsignedInteger no = 0; no < _outervalues.size(); no++) f->_outervalues[no] = _outervalues[no];\n    for(SQUnsignedInteger nl = 0; nl < _localvarinfos.size(); nl++) f->_localvarinfos[nl] = _localvarinfos[nl];\n    for(SQUnsignedInteger ni = 0; ni < _lineinfos.size(); ni++) f->_lineinfos[ni] = _lineinfos[ni];\n    for(SQUnsignedInteger nd = 0; nd < _defaultparams.size(); nd++) f->_defaultparams[nd] = _defaultparams[nd];\n\n    memcpy(f->_instructions,&_instructions[0],_instructions.size()*sizeof(SQInstruction));\n\n    f->_varparams = _varparams;\n\n    return f;\n}\n\nSQFuncState *SQFuncState::PushChildState(SQSharedState *ss)\n{\n    SQFuncState *child = (SQFuncState *)sq_malloc(sizeof(SQFuncState));\n    new (child) SQFuncState(ss,this,_errfunc,_errtarget);\n    _childstates.push_back(child);\n    return child;\n}\n\nvoid SQFuncState::PopChildState()\n{\n    SQFuncState *child = _childstates.back();\n    sq_delete(child,SQFuncState);\n    _childstates.pop_back();\n}\n\nSQFuncState::~SQFuncState()\n{\n    while(_childstates.size() > 0)\n    {\n        PopChildState();\n    }\n}\n\n#endif\n"
  },
  {
    "path": "extlibs/squirrel/squirrel/sqfuncstate.h",
    "content": "/*  see copyright notice in squirrel.h */\n#ifndef _SQFUNCSTATE_H_\n#define _SQFUNCSTATE_H_\n///////////////////////////////////\n#include \"squtils.h\"\n\nstruct SQFuncState\n{\n    SQFuncState(SQSharedState *ss,SQFuncState *parent,CompilerErrorFunc efunc,void *ed);\n    ~SQFuncState();\n#ifdef _DEBUG_DUMP\n    void Dump(SQFunctionProto *func);\n#endif\n    void Error(const SQChar *err);\n    SQFuncState *PushChildState(SQSharedState *ss);\n    void PopChildState();\n    void AddInstruction(SQOpcode _op,SQInteger arg0=0,SQInteger arg1=0,SQInteger arg2=0,SQInteger arg3=0){SQInstruction i(_op,arg0,arg1,arg2,arg3);AddInstruction(i);}\n    void AddInstruction(SQInstruction &i);\n    void SetInstructionParams(SQInteger pos,SQInteger arg0,SQInteger arg1,SQInteger arg2=0,SQInteger arg3=0);\n    void SetInstructionParam(SQInteger pos,SQInteger arg,SQInteger val);\n    SQInstruction &GetInstruction(SQInteger pos){return _instructions[pos];}\n    void PopInstructions(SQInteger size){for(SQInteger i=0;i<size;i++)_instructions.pop_back();}\n    void SetStackSize(SQInteger n);\n    SQInteger CountOuters(SQInteger stacksize);\n    void SnoozeOpt(){_optimization=false;}\n    void AddDefaultParam(SQInteger trg) { _defaultparams.push_back(trg); }\n    SQInteger GetDefaultParamCount() { return _defaultparams.size(); }\n    SQInteger GetCurrentPos(){return _instructions.size()-1;}\n    SQInteger GetNumericConstant(const SQInteger cons);\n    SQInteger GetNumericConstant(const SQFloat cons);\n    SQInteger PushLocalVariable(const SQObject &name);\n    void AddParameter(const SQObject &name);\n    //void AddOuterValue(const SQObject &name);\n    SQInteger GetLocalVariable(const SQObject &name);\n    void MarkLocalAsOuter(SQInteger pos);\n    SQInteger GetOuterVariable(const SQObject &name);\n    SQInteger GenerateCode();\n    SQInteger GetStackSize();\n    SQInteger CalcStackFrameSize();\n    void AddLineInfos(SQInteger line,bool lineop,bool force=false);\n    SQFunctionProto *BuildProto();\n    SQInteger AllocStackPos();\n    SQInteger PushTarget(SQInteger n=-1);\n    SQInteger PopTarget();\n    SQInteger TopTarget();\n    SQInteger GetUpTarget(SQInteger n);\n    void DiscardTarget();\n    bool IsLocal(SQUnsignedInteger stkpos);\n    SQObject CreateString(const SQChar *s,SQInteger len = -1);\n    SQObject CreateTable();\n    bool IsConstant(const SQObject &name,SQObject &e);\n    SQInteger _returnexp;\n    SQLocalVarInfoVec _vlocals;\n    SQIntVec _targetstack;\n    SQInteger _stacksize;\n    bool _varparams;\n    bool _bgenerator;\n    SQIntVec _unresolvedbreaks;\n    SQIntVec _unresolvedcontinues;\n    SQObjectPtrVec _functions;\n    SQObjectPtrVec _parameters;\n    SQOuterVarVec _outervalues;\n    SQInstructionVec _instructions;\n    SQLocalVarInfoVec _localvarinfos;\n    SQObjectPtr _literals;\n    SQObjectPtr _strings;\n    SQObjectPtr _name;\n    SQObjectPtr _sourcename;\n    SQInteger _nliterals;\n    SQLineInfoVec _lineinfos;\n    SQFuncState *_parent;\n    SQIntVec _scope_blocks;\n    SQIntVec _breaktargets;\n    SQIntVec _continuetargets;\n    SQIntVec _defaultparams;\n    SQInteger _lastline;\n    SQInteger _traps; //contains number of nested exception traps\n    SQInteger _outers;\n    bool _optimization;\n    SQSharedState *_sharedstate;\n    sqvector<SQFuncState*> _childstates;\n    SQInteger GetConstant(const SQObject &cons);\nprivate:\n    CompilerErrorFunc _errfunc;\n    void *_errtarget;\n    SQSharedState *_ss;\n};\n\n\n#endif //_SQFUNCSTATE_H_\n\n"
  },
  {
    "path": "extlibs/squirrel/squirrel/sqlexer.cpp",
    "content": "/*\n    see copyright notice in squirrel.h\n*/\n#include \"sqpcheader.h\"\n#include <ctype.h>\n#include <stdlib.h>\n#include \"sqtable.h\"\n#include \"sqstring.h\"\n#include \"sqcompiler.h\"\n#include \"sqlexer.h\"\n\n#define CUR_CHAR (_currdata)\n#define RETURN_TOKEN(t) { _prevtoken = _curtoken; _curtoken = t; return t;}\n#define IS_EOB() (CUR_CHAR <= SQUIRREL_EOB)\n#define NEXT() {Next();_currentcolumn++;}\n#define INIT_TEMP_STRING() { _longstr.resize(0);}\n#define APPEND_CHAR(c) { _longstr.push_back(c);}\n#define TERMINATE_BUFFER() {_longstr.push_back(_SC('\\0'));}\n#define ADD_KEYWORD(key,id) _keywords->NewSlot( SQString::Create(ss, _SC(#key)) ,SQInteger(id))\n\nSQLexer::SQLexer(){}\nSQLexer::~SQLexer()\n{\n    _keywords->Release();\n}\n\nvoid SQLexer::Init(SQSharedState *ss, SQLEXREADFUNC rg, SQUserPointer up,CompilerErrorFunc efunc,void *ed)\n{\n    _errfunc = efunc;\n    _errtarget = ed;\n    _sharedstate = ss;\n    _keywords = SQTable::Create(ss, 37);\n    ADD_KEYWORD(while, TK_WHILE);\n    ADD_KEYWORD(do, TK_DO);\n    ADD_KEYWORD(if, TK_IF);\n    ADD_KEYWORD(else, TK_ELSE);\n    ADD_KEYWORD(break, TK_BREAK);\n    ADD_KEYWORD(continue, TK_CONTINUE);\n    ADD_KEYWORD(return, TK_RETURN);\n    ADD_KEYWORD(null, TK_NULL);\n    ADD_KEYWORD(function, TK_FUNCTION);\n    ADD_KEYWORD(script, TK_FUNCTION);\n    ADD_KEYWORD(local, TK_LOCAL);\n    ADD_KEYWORD(for, TK_FOR);\n    ADD_KEYWORD(foreach, TK_FOREACH);\n    ADD_KEYWORD(in, TK_IN);\n    ADD_KEYWORD(typeof, TK_TYPEOF);\n    ADD_KEYWORD(base, TK_BASE);\n    ADD_KEYWORD(delete, TK_DELETE);\n    ADD_KEYWORD(try, TK_TRY);\n    ADD_KEYWORD(catch, TK_CATCH);\n    ADD_KEYWORD(throw, TK_THROW);\n    ADD_KEYWORD(clone, TK_CLONE);\n    ADD_KEYWORD(yield, TK_YIELD);\n    ADD_KEYWORD(resume, TK_RESUME);\n    ADD_KEYWORD(switch, TK_SWITCH);\n    ADD_KEYWORD(case, TK_CASE);\n    ADD_KEYWORD(default, TK_DEFAULT);\n    ADD_KEYWORD(this, TK_THIS);\n    ADD_KEYWORD(class,TK_CLASS);\n    ADD_KEYWORD(extends,TK_EXTENDS);\n    ADD_KEYWORD(constructor,TK_CONSTRUCTOR);\n    ADD_KEYWORD(instanceof,TK_INSTANCEOF);\n    ADD_KEYWORD(true,TK_TRUE);\n    ADD_KEYWORD(false,TK_FALSE);\n    ADD_KEYWORD(static,TK_STATIC);\n    ADD_KEYWORD(enum,TK_ENUM);\n    ADD_KEYWORD(const,TK_CONST);\n    ADD_KEYWORD(__LINE__,TK___LINE__);\n    ADD_KEYWORD(__FILE__,TK___FILE__);\n    ADD_KEYWORD(rawcall, TK_RAWCALL);\n\n\n    _readf = rg;\n    _up = up;\n    _lasttokenline = _currentline = 1;\n    _currentcolumn = 0;\n    _prevtoken = -1;\n    _reached_eof = SQFalse;\n    Next();\n}\n\nvoid SQLexer::Error(const SQChar *err)\n{\n    _errfunc(_errtarget,err);\n}\n\nvoid SQLexer::Next()\n{\n    SQInteger t = _readf(_up);\n    if(t > MAX_CHAR) Error(_SC(\"Invalid character\"));\n    if(t != 0) {\n        _currdata = (LexChar)t;\n        return;\n    }\n    _currdata = SQUIRREL_EOB;\n    _reached_eof = SQTrue;\n}\n\nconst SQChar *SQLexer::Tok2Str(SQInteger tok)\n{\n    SQObjectPtr itr, key, val;\n    SQInteger nitr;\n    while((nitr = _keywords->Next(false,itr, key, val)) != -1) {\n        itr = (SQInteger)nitr;\n        if(((SQInteger)_integer(val)) == tok)\n            return _stringval(key);\n    }\n    return NULL;\n}\n\nvoid SQLexer::LexBlockComment()\n{\n    bool done = false;\n    while(!done) {\n        switch(CUR_CHAR) {\n            case _SC('*'): { NEXT(); if(CUR_CHAR == _SC('/')) { done = true; NEXT(); }}; continue;\n            case _SC('\\n'): _currentline++; NEXT(); continue;\n            case SQUIRREL_EOB: Error(_SC(\"missing \\\"*/\\\" in comment\"));\n            default: NEXT();\n        }\n    }\n}\nvoid SQLexer::LexLineComment()\n{\n    do { NEXT(); } while (CUR_CHAR != _SC('\\n') && (!IS_EOB()));\n}\n\nSQInteger SQLexer::Lex()\n{\n    _lasttokenline = _currentline;\n    while(CUR_CHAR != SQUIRREL_EOB) {\n        switch(CUR_CHAR){\n        case _SC('\\t'): case _SC('\\r'): case _SC(' '): NEXT(); continue;\n        case _SC('\\n'):\n            _currentline++;\n            _prevtoken=_curtoken;\n            _curtoken=_SC('\\n');\n            NEXT();\n            _currentcolumn=1;\n            continue;\n        case _SC('#'): LexLineComment(); continue;\n        case _SC('/'):\n            NEXT();\n            switch(CUR_CHAR){\n            case _SC('*'):\n                NEXT();\n                LexBlockComment();\n                continue;\n            case _SC('/'):\n                LexLineComment();\n                continue;\n            case _SC('='):\n                NEXT();\n                RETURN_TOKEN(TK_DIVEQ);\n                continue;\n            case _SC('>'):\n                NEXT();\n                RETURN_TOKEN(TK_ATTR_CLOSE);\n                continue;\n            default:\n                RETURN_TOKEN('/');\n            }\n        case _SC('='):\n            NEXT();\n            if (CUR_CHAR != _SC('=')){ RETURN_TOKEN('=') }\n            else { NEXT(); RETURN_TOKEN(TK_EQ); }\n        case _SC('<'):\n            NEXT();\n            switch(CUR_CHAR) {\n            case _SC('='):\n                NEXT();\n                if(CUR_CHAR == _SC('>')) {\n                    NEXT();\n                    RETURN_TOKEN(TK_3WAYSCMP);\n                }\n                RETURN_TOKEN(TK_LE)\n                break;\n            case _SC('-'): NEXT(); RETURN_TOKEN(TK_NEWSLOT); break;\n            case _SC('<'): NEXT(); RETURN_TOKEN(TK_SHIFTL); break;\n            case _SC('/'): NEXT(); RETURN_TOKEN(TK_ATTR_OPEN); break;\n            }\n            RETURN_TOKEN('<');\n        case _SC('>'):\n            NEXT();\n            if (CUR_CHAR == _SC('=')){ NEXT(); RETURN_TOKEN(TK_GE);}\n            else if(CUR_CHAR == _SC('>')){\n                NEXT();\n                if(CUR_CHAR == _SC('>')){\n                    NEXT();\n                    RETURN_TOKEN(TK_USHIFTR);\n                }\n                RETURN_TOKEN(TK_SHIFTR);\n            }\n            else { RETURN_TOKEN('>') }\n        case _SC('!'):\n            NEXT();\n            if (CUR_CHAR != _SC('=')){ RETURN_TOKEN('!')}\n            else { NEXT(); RETURN_TOKEN(TK_NE); }\n        case _SC('@'): {\n            SQInteger stype;\n            NEXT();\n            if(CUR_CHAR != _SC('\"')) {\n                RETURN_TOKEN('@');\n            }\n            if((stype=ReadString('\"',true))!=-1) {\n                RETURN_TOKEN(stype);\n            }\n            Error(_SC(\"error parsing the string\"));\n                       }\n        case _SC('\"'):\n        case _SC('\\''): {\n            SQInteger stype;\n            if((stype=ReadString(CUR_CHAR,false))!=-1){\n                RETURN_TOKEN(stype);\n            }\n            Error(_SC(\"error parsing the string\"));\n            }\n        case _SC('{'): case _SC('}'): case _SC('('): case _SC(')'): case _SC('['): case _SC(']'):\n        case _SC(';'): case _SC(','): case _SC('?'): case _SC('^'): case _SC('~'):\n            {SQInteger ret = CUR_CHAR;\n            NEXT(); RETURN_TOKEN(ret); }\n        case _SC('.'):\n            NEXT();\n            if (CUR_CHAR != _SC('.')){ RETURN_TOKEN('.') }\n            NEXT();\n            if (CUR_CHAR != _SC('.')){ Error(_SC(\"invalid token '..'\")); }\n            NEXT();\n            RETURN_TOKEN(TK_VARPARAMS);\n        case _SC('&'):\n            NEXT();\n            if (CUR_CHAR != _SC('&')){ RETURN_TOKEN('&') }\n            else { NEXT(); RETURN_TOKEN(TK_AND); }\n        case _SC('|'):\n            NEXT();\n            if (CUR_CHAR != _SC('|')){ RETURN_TOKEN('|') }\n            else { NEXT(); RETURN_TOKEN(TK_OR); }\n        case _SC(':'):\n            NEXT();\n            if (CUR_CHAR != _SC(':')){ RETURN_TOKEN(':') }\n            else { NEXT(); RETURN_TOKEN(TK_DOUBLE_COLON); }\n        case _SC('*'):\n            NEXT();\n            if (CUR_CHAR == _SC('=')){ NEXT(); RETURN_TOKEN(TK_MULEQ);}\n            else RETURN_TOKEN('*');\n        case _SC('%'):\n            NEXT();\n            if (CUR_CHAR == _SC('=')){ NEXT(); RETURN_TOKEN(TK_MODEQ);}\n            else RETURN_TOKEN('%');\n        case _SC('-'):\n            NEXT();\n            if (CUR_CHAR == _SC('=')){ NEXT(); RETURN_TOKEN(TK_MINUSEQ);}\n            else if  (CUR_CHAR == _SC('-')){ NEXT(); RETURN_TOKEN(TK_MINUSMINUS);}\n            else RETURN_TOKEN('-');\n        case _SC('+'):\n            NEXT();\n            if (CUR_CHAR == _SC('=')){ NEXT(); RETURN_TOKEN(TK_PLUSEQ);}\n            else if (CUR_CHAR == _SC('+')){ NEXT(); RETURN_TOKEN(TK_PLUSPLUS);}\n            else RETURN_TOKEN('+');\n        case SQUIRREL_EOB:\n            return 0;\n        default:{\n                if (scisdigit(CUR_CHAR)) {\n                    SQInteger ret = ReadNumber();\n                    RETURN_TOKEN(ret);\n                }\n                else if (scisalpha(CUR_CHAR) || CUR_CHAR == _SC('_')) {\n                    SQInteger t = ReadID();\n                    RETURN_TOKEN(t);\n                }\n                else {\n                    SQInteger c = CUR_CHAR;\n                    if (sciscntrl((int)c)) Error(_SC(\"unexpected character(control)\"));\n                    NEXT();\n                    RETURN_TOKEN(c);\n                }\n                RETURN_TOKEN(0);\n            }\n        }\n    }\n    return 0;\n}\n\nSQInteger SQLexer::GetIDType(const SQChar *s,SQInteger len)\n{\n    SQObjectPtr t;\n    if(_keywords->GetStr(s,len, t)) {\n        return SQInteger(_integer(t));\n    }\n    return TK_IDENTIFIER;\n}\n\n#ifdef SQUNICODE\n#if WCHAR_SIZE == 2\nSQInteger SQLexer::AddUTF16(SQUnsignedInteger ch)\n{\n    if (ch >= 0x10000)\n    {\n        SQUnsignedInteger code = (ch - 0x10000);\n        APPEND_CHAR((SQChar)(0xD800 | (code >> 10)));\n        APPEND_CHAR((SQChar)(0xDC00 | (code & 0x3FF)));\n        return 2;\n    }\n    else {\n        APPEND_CHAR((SQChar)ch);\n        return 1;\n    }\n}\n#endif\n#else\nSQInteger SQLexer::AddUTF8(SQUnsignedInteger ch)\n{\n    if (ch < 0x80) {\n        APPEND_CHAR((char)ch);\n        return 1;\n    }\n    if (ch < 0x800) {\n        APPEND_CHAR((SQChar)((ch >> 6) | 0xC0));\n        APPEND_CHAR((SQChar)((ch & 0x3F) | 0x80));\n        return 2;\n    }\n    if (ch < 0x10000) {\n        APPEND_CHAR((SQChar)((ch >> 12) | 0xE0));\n        APPEND_CHAR((SQChar)(((ch >> 6) & 0x3F) | 0x80));\n        APPEND_CHAR((SQChar)((ch & 0x3F) | 0x80));\n        return 3;\n    }\n    if (ch < 0x110000) {\n        APPEND_CHAR((SQChar)((ch >> 18) | 0xF0));\n        APPEND_CHAR((SQChar)(((ch >> 12) & 0x3F) | 0x80));\n        APPEND_CHAR((SQChar)(((ch >> 6) & 0x3F) | 0x80));\n        APPEND_CHAR((SQChar)((ch & 0x3F) | 0x80));\n        return 4;\n    }\n    return 0;\n}\n#endif\n\nSQInteger SQLexer::ProcessStringHexEscape(SQChar *dest, SQInteger maxdigits)\n{\n    NEXT();\n    if (!isxdigit(CUR_CHAR)) Error(_SC(\"hexadecimal number expected\"));\n    SQInteger n = 0;\n    while (isxdigit(CUR_CHAR) && n < maxdigits) {\n        dest[n] = CUR_CHAR;\n        n++;\n        NEXT();\n    }\n    dest[n] = 0;\n    return n;\n}\n\nSQInteger SQLexer::ReadString(SQInteger ndelim,bool verbatim)\n{\n    INIT_TEMP_STRING();\n    NEXT();\n    if(IS_EOB()) return -1;\n    for(;;) {\n        while(CUR_CHAR != ndelim) {\n            SQInteger x = CUR_CHAR;\n            switch (x) {\n            case SQUIRREL_EOB:\n                Error(_SC(\"unfinished string\"));\n                return -1;\n            case _SC('\\n'):\n                if(!verbatim) Error(_SC(\"newline in a constant\"));\n                APPEND_CHAR(CUR_CHAR); NEXT();\n                _currentline++;\n                break;\n            case _SC('\\\\'):\n                if(verbatim) {\n                    APPEND_CHAR('\\\\'); NEXT();\n                }\n                else {\n                    NEXT();\n                    switch(CUR_CHAR) {\n                    case _SC('x'):  {\n                        const SQInteger maxdigits = sizeof(SQChar) * 2;\n                        SQChar temp[maxdigits + 1];\n                        ProcessStringHexEscape(temp, maxdigits);\n                        SQChar *stemp;\n                        APPEND_CHAR((SQChar)scstrtoul(temp, &stemp, 16));\n                    }\n                    break;\n                    case _SC('U'):\n                    case _SC('u'):  {\n                        const SQInteger maxdigits = CUR_CHAR == 'u' ? 4 : 8;\n                        SQChar temp[8 + 1];\n                        ProcessStringHexEscape(temp, maxdigits);\n                        SQChar *stemp;\n#ifdef SQUNICODE\n#if WCHAR_SIZE == 2\n                        AddUTF16(scstrtoul(temp, &stemp, 16));\n#else\n                        APPEND_CHAR((SQChar)scstrtoul(temp, &stemp, 16));\n#endif\n#else\n                        AddUTF8(scstrtoul(temp, &stemp, 16));\n#endif\n                    }\n                    break;\n                    case _SC('t'): APPEND_CHAR(_SC('\\t')); NEXT(); break;\n                    case _SC('a'): APPEND_CHAR(_SC('\\a')); NEXT(); break;\n                    case _SC('b'): APPEND_CHAR(_SC('\\b')); NEXT(); break;\n                    case _SC('n'): APPEND_CHAR(_SC('\\n')); NEXT(); break;\n                    case _SC('r'): APPEND_CHAR(_SC('\\r')); NEXT(); break;\n                    case _SC('v'): APPEND_CHAR(_SC('\\v')); NEXT(); break;\n                    case _SC('f'): APPEND_CHAR(_SC('\\f')); NEXT(); break;\n                    case _SC('0'): APPEND_CHAR(_SC('\\0')); NEXT(); break;\n                    case _SC('\\\\'): APPEND_CHAR(_SC('\\\\')); NEXT(); break;\n                    case _SC('\"'): APPEND_CHAR(_SC('\"')); NEXT(); break;\n                    case _SC('\\''): APPEND_CHAR(_SC('\\'')); NEXT(); break;\n                    default:\n                        Error(_SC(\"unrecognised escaper char\"));\n                    break;\n                    }\n                }\n                break;\n            default:\n                APPEND_CHAR(CUR_CHAR);\n                NEXT();\n            }\n        }\n        NEXT();\n        if(verbatim && CUR_CHAR == '\"') { //double quotation\n            APPEND_CHAR(CUR_CHAR);\n            NEXT();\n        }\n        else {\n            break;\n        }\n    }\n    TERMINATE_BUFFER();\n    SQInteger len = _longstr.size()-1;\n    if(ndelim == _SC('\\'')) {\n        if(len == 0) Error(_SC(\"empty constant\"));\n        if(len > 1) Error(_SC(\"constant too long\"));\n        _nvalue = _longstr[0];\n        return TK_INTEGER;\n    }\n    _svalue = &_longstr[0];\n    return TK_STRING_LITERAL;\n}\n\nvoid LexHexadecimal(const SQChar *s,SQUnsignedInteger *res)\n{\n    *res = 0;\n    while(*s != 0)\n    {\n        if(scisdigit(*s)) *res = (*res)*16+((*s++)-'0');\n        else if(scisxdigit(*s)) *res = (*res)*16+(toupper(*s++)-'A'+10);\n        else { assert(0); }\n    }\n}\n\nvoid LexInteger(const SQChar *s,SQUnsignedInteger *res)\n{\n    *res = 0;\n    while(*s != 0)\n    {\n        *res = (*res)*10+((*s++)-'0');\n    }\n}\n\nSQInteger scisodigit(SQInteger c) { return c >= _SC('0') && c <= _SC('7'); }\n\nvoid LexOctal(const SQChar *s,SQUnsignedInteger *res)\n{\n    *res = 0;\n    while(*s != 0)\n    {\n        if(scisodigit(*s)) *res = (*res)*8+((*s++)-'0');\n        else { assert(0); }\n    }\n}\n\nSQInteger isexponent(SQInteger c) { return c == 'e' || c=='E'; }\n\n\n#define MAX_HEX_DIGITS (sizeof(SQInteger)*2)\nSQInteger SQLexer::ReadNumber()\n{\n#define TINT 1\n#define TFLOAT 2\n#define THEX 3\n#define TSCIENTIFIC 4\n#define TOCTAL 5\n    SQInteger type = TINT, firstchar = CUR_CHAR;\n    SQChar *sTemp;\n    INIT_TEMP_STRING();\n    NEXT();\n    if(firstchar == _SC('0') && (toupper(CUR_CHAR) == _SC('X') || scisodigit(CUR_CHAR)) ) {\n        if(scisodigit(CUR_CHAR)) {\n            type = TOCTAL;\n            while(scisodigit(CUR_CHAR)) {\n                APPEND_CHAR(CUR_CHAR);\n                NEXT();\n            }\n            if(scisdigit(CUR_CHAR)) Error(_SC(\"invalid octal number\"));\n        }\n        else {\n            NEXT();\n            type = THEX;\n            while(isxdigit(CUR_CHAR)) {\n                APPEND_CHAR(CUR_CHAR);\n                NEXT();\n            }\n            if(_longstr.size() > MAX_HEX_DIGITS) Error(_SC(\"too many digits for an Hex number\"));\n        }\n    }\n    else {\n        APPEND_CHAR((int)firstchar);\n        while (CUR_CHAR == _SC('.') || scisdigit(CUR_CHAR) || isexponent(CUR_CHAR)) {\n            if(CUR_CHAR == _SC('.') || isexponent(CUR_CHAR)) type = TFLOAT;\n            if(isexponent(CUR_CHAR)) {\n                if(type != TFLOAT) Error(_SC(\"invalid numeric format\"));\n                type = TSCIENTIFIC;\n                APPEND_CHAR(CUR_CHAR);\n                NEXT();\n                if(CUR_CHAR == '+' || CUR_CHAR == '-'){\n                    APPEND_CHAR(CUR_CHAR);\n                    NEXT();\n                }\n                if(!scisdigit(CUR_CHAR)) Error(_SC(\"exponent expected\"));\n            }\n\n            APPEND_CHAR(CUR_CHAR);\n            NEXT();\n        }\n    }\n    TERMINATE_BUFFER();\n    switch(type) {\n    case TSCIENTIFIC:\n    case TFLOAT:\n        _fvalue = (SQFloat)scstrtod(&_longstr[0],&sTemp);\n        return TK_FLOAT;\n    case TINT:\n        LexInteger(&_longstr[0],(SQUnsignedInteger *)&_nvalue);\n        return TK_INTEGER;\n    case THEX:\n        LexHexadecimal(&_longstr[0],(SQUnsignedInteger *)&_nvalue);\n        return TK_INTEGER;\n    case TOCTAL:\n        LexOctal(&_longstr[0],(SQUnsignedInteger *)&_nvalue);\n        return TK_INTEGER;\n    }\n    return 0;\n}\n\nSQInteger SQLexer::ReadID()\n{\n    SQInteger res;\n    INIT_TEMP_STRING();\n    do {\n        APPEND_CHAR(CUR_CHAR);\n        NEXT();\n    } while(scisalnum(CUR_CHAR) || CUR_CHAR == _SC('_'));\n    TERMINATE_BUFFER();\n    res = GetIDType(&_longstr[0],_longstr.size() - 1);\n    if(res == TK_IDENTIFIER || res == TK_CONSTRUCTOR) {\n        _svalue = &_longstr[0];\n    }\n    return res;\n}\n"
  },
  {
    "path": "extlibs/squirrel/squirrel/sqlexer.h",
    "content": "/*  see copyright notice in squirrel.h */\n#ifndef _SQLEXER_H_\n#define _SQLEXER_H_\n\n#ifdef SQUNICODE\ntypedef SQChar LexChar;\n#else\ntypedef unsigned char LexChar;\n#endif\n\nstruct SQLexer\n{\n    SQLexer();\n    ~SQLexer();\n    void Init(SQSharedState *ss,SQLEXREADFUNC rg,SQUserPointer up,CompilerErrorFunc efunc,void *ed);\n    void Error(const SQChar *err);\n    SQInteger Lex();\n    const SQChar *Tok2Str(SQInteger tok);\nprivate:\n    SQInteger GetIDType(const SQChar *s,SQInteger len);\n    SQInteger ReadString(SQInteger ndelim,bool verbatim);\n    SQInteger ReadNumber();\n    void LexBlockComment();\n    void LexLineComment();\n    SQInteger ReadID();\n    void Next();\n#ifdef SQUNICODE\n#if WCHAR_SIZE == 2\n    SQInteger AddUTF16(SQUnsignedInteger ch);\n#endif\n#else\n    SQInteger AddUTF8(SQUnsignedInteger ch);\n#endif\n    SQInteger ProcessStringHexEscape(SQChar *dest, SQInteger maxdigits);\n    SQInteger _curtoken;\n    SQTable *_keywords;\n    SQBool _reached_eof;\npublic:\n    SQInteger _prevtoken;\n    SQInteger _currentline;\n    SQInteger _lasttokenline;\n    SQInteger _currentcolumn;\n    const SQChar *_svalue;\n    SQInteger _nvalue;\n    SQFloat _fvalue;\n    SQLEXREADFUNC _readf;\n    SQUserPointer _up;\n    LexChar _currdata;\n    SQSharedState *_sharedstate;\n    sqvector<SQChar> _longstr;\n    CompilerErrorFunc _errfunc;\n    void *_errtarget;\n};\n\n#endif\n"
  },
  {
    "path": "extlibs/squirrel/squirrel/sqmem.cpp",
    "content": "/*\n    see copyright notice in squirrel.h\n*/\n#include \"sqpcheader.h\"\n#ifndef SQ_EXCLUDE_DEFAULT_MEMFUNCTIONS\nvoid *sq_vm_malloc(SQUnsignedInteger size){ return malloc(size); }\n\nvoid *sq_vm_realloc(void *p, SQUnsignedInteger SQ_UNUSED_ARG(oldsize), SQUnsignedInteger size){ return realloc(p, size); }\n\nvoid sq_vm_free(void *p, SQUnsignedInteger SQ_UNUSED_ARG(size)){ free(p); }\n#endif\n"
  },
  {
    "path": "extlibs/squirrel/squirrel/sqobject.cpp",
    "content": "/*\n    see copyright notice in squirrel.h\n*/\n#include \"sqpcheader.h\"\n#include \"sqvm.h\"\n#include \"sqstring.h\"\n#include \"sqarray.h\"\n#include \"sqtable.h\"\n#include \"squserdata.h\"\n#include \"sqfuncproto.h\"\n#include \"sqclass.h\"\n#include \"sqclosure.h\"\n\n\nconst SQChar *IdType2Name(SQObjectType type)\n{\n    switch(_RAW_TYPE(type))\n    {\n    case _RT_NULL:return _SC(\"null\");\n    case _RT_INTEGER:return _SC(\"integer\");\n    case _RT_FLOAT:return _SC(\"float\");\n    case _RT_BOOL:return _SC(\"bool\");\n    case _RT_STRING:return _SC(\"string\");\n    case _RT_TABLE:return _SC(\"table\");\n    case _RT_ARRAY:return _SC(\"array\");\n    case _RT_GENERATOR:return _SC(\"generator\");\n    case _RT_CLOSURE:\n    case _RT_NATIVECLOSURE:\n        return _SC(\"function\");\n    case _RT_USERDATA:\n    case _RT_USERPOINTER:\n        return _SC(\"userdata\");\n    case _RT_THREAD: return _SC(\"thread\");\n    case _RT_FUNCPROTO: return _SC(\"function\");\n    case _RT_CLASS: return _SC(\"class\");\n    case _RT_INSTANCE: return _SC(\"instance\");\n    case _RT_WEAKREF: return _SC(\"weakref\");\n    case _RT_OUTER: return _SC(\"outer\");\n    default:\n        return NULL;\n    }\n}\n\nconst SQChar *GetTypeName(const SQObjectPtr &obj1)\n{\n    return IdType2Name(sq_type(obj1));\n}\n\nSQString *SQString::Create(SQSharedState *ss,const SQChar *s,SQInteger len)\n{\n    SQString *str=ADD_STRING(ss,s,len);\n    return str;\n}\n\nvoid SQString::Release()\n{\n    REMOVE_STRING(_sharedstate,this);\n}\n\nSQInteger SQString::Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval)\n{\n    SQInteger idx = (SQInteger)TranslateIndex(refpos);\n    while(idx < _len){\n        outkey = (SQInteger)idx;\n        outval = (SQInteger)((SQUnsignedInteger)_val[idx]);\n        //return idx for the next iteration\n        return ++idx;\n    }\n    //nothing to iterate anymore\n    return -1;\n}\n\nSQUnsignedInteger TranslateIndex(const SQObjectPtr &idx)\n{\n    switch(sq_type(idx)){\n        case OT_NULL:\n            return 0;\n        case OT_INTEGER:\n            return (SQUnsignedInteger)_integer(idx);\n        default: assert(0); break;\n    }\n    return 0;\n}\n\nSQWeakRef *SQRefCounted::GetWeakRef(SQObjectType type)\n{\n    if(!_weakref) {\n        sq_new(_weakref,SQWeakRef);\n#if defined(SQUSEDOUBLE) && !defined(_SQ64)\n        _weakref->_obj._unVal.raw = 0; //clean the whole union on 32 bits with double\n#endif\n        _weakref->_obj._type = type;\n        _weakref->_obj._unVal.pRefCounted = this;\n    }\n    return _weakref;\n}\n\nSQRefCounted::~SQRefCounted()\n{\n    if(_weakref) {\n        _weakref->_obj._type = OT_NULL;\n        _weakref->_obj._unVal.pRefCounted = NULL;\n    }\n}\n\nvoid SQWeakRef::Release() {\n    if(ISREFCOUNTED(_obj._type)) {\n        _obj._unVal.pRefCounted->_weakref = NULL;\n    }\n    sq_delete(this,SQWeakRef);\n}\n\nbool SQDelegable::GetMetaMethod(SQVM *v,SQMetaMethod mm,SQObjectPtr &res) {\n    if(_delegate) {\n        return _delegate->Get((*_ss(v)->_metamethods)[mm],res);\n    }\n    return false;\n}\n\nbool SQDelegable::SetDelegate(SQTable *mt)\n{\n    SQTable *temp = mt;\n    if(temp == this) return false;\n    while (temp) {\n        if (temp->_delegate == this) return false; //cycle detected\n        temp = temp->_delegate;\n    }\n    if (mt) __ObjAddRef(mt);\n    __ObjRelease(_delegate);\n    _delegate = mt;\n    return true;\n}\n\nbool SQGenerator::Yield(SQVM *v,SQInteger target)\n{\n    if(_state==eSuspended) { v->Raise_Error(_SC(\"internal vm error, yielding dead generator\"));  return false;}\n    if(_state==eDead) { v->Raise_Error(_SC(\"internal vm error, yielding a dead generator\")); return false; }\n    SQInteger size = v->_top-v->_stackbase;\n\n    _stack.resize(size);\n    SQObject _this = v->_stack[v->_stackbase];\n    _stack._vals[0] = ISREFCOUNTED(sq_type(_this)) ? SQObjectPtr(_refcounted(_this)->GetWeakRef(sq_type(_this))) : _this;\n    for(SQInteger n =1; n<target; n++) {\n        _stack._vals[n] = v->_stack[v->_stackbase+n];\n    }\n    for(SQInteger j =0; j < size; j++)\n    {\n        v->_stack[v->_stackbase+j].Null();\n    }\n\n    _ci = *v->ci;\n    _ci._generator=NULL;\n    for(SQInteger i=0;i<_ci._etraps;i++) {\n        _etraps.push_back(v->_etraps.top());\n        v->_etraps.pop_back();\n        // store relative stack base and size in case of resume to other _top\n        SQExceptionTrap &et = _etraps.back();\n        et._stackbase -= v->_stackbase;\n        et._stacksize -= v->_stackbase;\n    }\n    _state=eSuspended;\n    return true;\n}\n\nbool SQGenerator::Resume(SQVM *v,SQObjectPtr &dest)\n{\n    if(_state==eDead){ v->Raise_Error(_SC(\"resuming dead generator\")); return false; }\n    if(_state==eRunning){ v->Raise_Error(_SC(\"resuming active generator\")); return false; }\n    SQInteger size = _stack.size();\n    SQInteger target = &dest - &(v->_stack._vals[v->_stackbase]);\n    assert(target>=0 && target<=255);\n    SQInteger newbase = v->_top;\n    if(!v->EnterFrame(v->_top, v->_top + size, false))\n        return false;\n    v->ci->_generator   = this;\n    v->ci->_target      = (SQInt32)target;\n    v->ci->_closure     = _ci._closure;\n    v->ci->_ip          = _ci._ip;\n    v->ci->_literals    = _ci._literals;\n    v->ci->_ncalls      = _ci._ncalls;\n    v->ci->_etraps      = _ci._etraps;\n    v->ci->_root        = _ci._root;\n\n\n    for(SQInteger i=0;i<_ci._etraps;i++) {\n        v->_etraps.push_back(_etraps.top());\n        _etraps.pop_back();\n        SQExceptionTrap &et = v->_etraps.back();\n        // restore absolute stack base and size\n        et._stackbase += newbase;\n        et._stacksize += newbase;\n    }\n    SQObject _this = _stack._vals[0];\n    v->_stack[v->_stackbase] = sq_type(_this) == OT_WEAKREF ? _weakref(_this)->_obj : _this;\n\n    for(SQInteger n = 1; n<size; n++) {\n        v->_stack[v->_stackbase+n] = _stack._vals[n];\n        _stack._vals[n].Null();\n    }\n\n    _state=eRunning;\n    if (v->_debughook)\n        v->CallDebugHook(_SC('c'));\n\n    return true;\n}\n\nvoid SQArray::Extend(const SQArray *a){\n    SQInteger xlen;\n    if((xlen=a->Size()))\n        for(SQInteger i=0;i<xlen;i++)\n            Append(a->_values[i]);\n}\n\nconst SQChar* SQFunctionProto::GetLocal(SQVM *vm,SQUnsignedInteger stackbase,SQUnsignedInteger nseq,SQUnsignedInteger nop)\n{\n    SQUnsignedInteger nvars=_nlocalvarinfos;\n    const SQChar *res=NULL;\n    if(nvars>=nseq){\n        for(SQUnsignedInteger i=0;i<nvars;i++){\n            if(_localvarinfos[i]._start_op<=nop && _localvarinfos[i]._end_op>=nop)\n            {\n                if(nseq==0){\n                    vm->Push(vm->_stack[stackbase+_localvarinfos[i]._pos]);\n                    res=_stringval(_localvarinfos[i]._name);\n                    break;\n                }\n                nseq--;\n            }\n        }\n    }\n    return res;\n}\n\n\nSQInteger SQFunctionProto::GetLine(SQInstruction *curr)\n{\n    SQInteger op = (SQInteger)(curr-_instructions);\n    SQInteger line=_lineinfos[0]._line;\n    SQInteger low = 0;\n    SQInteger high = _nlineinfos - 1;\n    SQInteger mid = 0;\n    while(low <= high)\n    {\n        mid = low + ((high - low) >> 1);\n        SQInteger curop = _lineinfos[mid]._op;\n        if(curop > op)\n        {\n            high = mid - 1;\n        }\n        else if(curop < op) {\n            if(mid < (_nlineinfos - 1)\n                && _lineinfos[mid + 1]._op >= op) {\n                break;\n            }\n            low = mid + 1;\n        }\n        else { //equal\n            break;\n        }\n    }\n\n    while(mid > 0 && _lineinfos[mid]._op >= op) mid--;\n\n    line = _lineinfos[mid]._line;\n\n    return line;\n}\n\nSQClosure::~SQClosure()\n{\n    __ObjRelease(_root);\n    __ObjRelease(_env);\n    __ObjRelease(_base);\n    REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this);\n}\n\n#define _CHECK_IO(exp)  { if(!exp)return false; }\nbool SafeWrite(HSQUIRRELVM v,SQWRITEFUNC write,SQUserPointer up,SQUserPointer dest,SQInteger size)\n{\n    if(write(up,dest,size) != size) {\n        v->Raise_Error(_SC(\"io error (write function failure)\"));\n        return false;\n    }\n    return true;\n}\n\nbool SafeRead(HSQUIRRELVM v,SQREADFUNC read,SQUserPointer up,SQUserPointer dest,SQInteger size)\n{\n    if(size && read(up,dest,size) != size) {\n        v->Raise_Error(_SC(\"io error, read function failure, the origin stream could be corrupted/trucated\"));\n        return false;\n    }\n    return true;\n}\n\nbool WriteTag(HSQUIRRELVM v,SQWRITEFUNC write,SQUserPointer up,SQUnsignedInteger32 tag)\n{\n    return SafeWrite(v,write,up,&tag,sizeof(tag));\n}\n\nbool CheckTag(HSQUIRRELVM v,SQREADFUNC read,SQUserPointer up,SQUnsignedInteger32 tag)\n{\n    SQUnsignedInteger32 t;\n    _CHECK_IO(SafeRead(v,read,up,&t,sizeof(t)));\n    if(t != tag){\n        v->Raise_Error(_SC(\"invalid or corrupted closure stream\"));\n        return false;\n    }\n    return true;\n}\n\nbool WriteObject(HSQUIRRELVM v,SQUserPointer up,SQWRITEFUNC write,SQObjectPtr &o)\n{\n    SQUnsignedInteger32 _type = (SQUnsignedInteger32)sq_type(o);\n    _CHECK_IO(SafeWrite(v,write,up,&_type,sizeof(_type)));\n    switch(sq_type(o)){\n    case OT_STRING:\n        _CHECK_IO(SafeWrite(v,write,up,&_string(o)->_len,sizeof(SQInteger)));\n        _CHECK_IO(SafeWrite(v,write,up,_stringval(o),sq_rsl(_string(o)->_len)));\n        break;\n    case OT_BOOL:\n    case OT_INTEGER:\n        _CHECK_IO(SafeWrite(v,write,up,&_integer(o),sizeof(SQInteger)));break;\n    case OT_FLOAT:\n        _CHECK_IO(SafeWrite(v,write,up,&_float(o),sizeof(SQFloat)));break;\n    case OT_NULL:\n        break;\n    default:\n        v->Raise_Error(_SC(\"cannot serialize a %s\"),GetTypeName(o));\n        return false;\n    }\n    return true;\n}\n\nbool ReadObject(HSQUIRRELVM v,SQUserPointer up,SQREADFUNC read,SQObjectPtr &o)\n{\n    SQUnsignedInteger32 _type;\n    _CHECK_IO(SafeRead(v,read,up,&_type,sizeof(_type)));\n    SQObjectType t = (SQObjectType)_type;\n    switch(t){\n    case OT_STRING:{\n        SQInteger len;\n        _CHECK_IO(SafeRead(v,read,up,&len,sizeof(SQInteger)));\n        _CHECK_IO(SafeRead(v,read,up,_ss(v)->GetScratchPad(sq_rsl(len)),sq_rsl(len)));\n        o=SQString::Create(_ss(v),_ss(v)->GetScratchPad(-1),len);\n                   }\n        break;\n    case OT_INTEGER:{\n        SQInteger i;\n        _CHECK_IO(SafeRead(v,read,up,&i,sizeof(SQInteger))); o = i; break;\n                    }\n    case OT_BOOL:{\n        SQInteger i;\n        _CHECK_IO(SafeRead(v,read,up,&i,sizeof(SQInteger))); o._type = OT_BOOL; o._unVal.nInteger = i; break;\n                    }\n    case OT_FLOAT:{\n        SQFloat f;\n        _CHECK_IO(SafeRead(v,read,up,&f,sizeof(SQFloat))); o = f; break;\n                  }\n    case OT_NULL:\n        o.Null();\n        break;\n    default:\n        v->Raise_Error(_SC(\"cannot serialize a %s\"),IdType2Name(t));\n        return false;\n    }\n    return true;\n}\n\nbool SQClosure::Save(SQVM *v,SQUserPointer up,SQWRITEFUNC write)\n{\n    _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_HEAD));\n    _CHECK_IO(WriteTag(v,write,up,sizeof(SQChar)));\n    _CHECK_IO(WriteTag(v,write,up,sizeof(SQInteger)));\n    _CHECK_IO(WriteTag(v,write,up,sizeof(SQFloat)));\n    _CHECK_IO(_function->Save(v,up,write));\n    _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_TAIL));\n    return true;\n}\n\nbool SQClosure::Load(SQVM *v,SQUserPointer up,SQREADFUNC read,SQObjectPtr &ret)\n{\n    _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_HEAD));\n    _CHECK_IO(CheckTag(v,read,up,sizeof(SQChar)));\n    _CHECK_IO(CheckTag(v,read,up,sizeof(SQInteger)));\n    _CHECK_IO(CheckTag(v,read,up,sizeof(SQFloat)));\n    SQObjectPtr func;\n    _CHECK_IO(SQFunctionProto::Load(v,up,read,func));\n    _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_TAIL));\n    ret = SQClosure::Create(_ss(v),_funcproto(func),_table(v->_roottable)->GetWeakRef(OT_TABLE));\n    //FIXME: load an root for this closure\n    return true;\n}\n\nSQFunctionProto::SQFunctionProto(SQSharedState *ss)\n{\n    _stacksize=0;\n    _bgenerator=false;\n    INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this);\n}\n\nSQFunctionProto::~SQFunctionProto()\n{\n    REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this);\n}\n\nbool SQFunctionProto::Save(SQVM *v,SQUserPointer up,SQWRITEFUNC write)\n{\n    SQInteger i,nliterals = _nliterals,nparameters = _nparameters;\n    SQInteger noutervalues = _noutervalues,nlocalvarinfos = _nlocalvarinfos;\n    SQInteger nlineinfos=_nlineinfos,ninstructions = _ninstructions,nfunctions=_nfunctions;\n    SQInteger ndefaultparams = _ndefaultparams;\n    _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART));\n    _CHECK_IO(WriteObject(v,up,write,_sourcename));\n    _CHECK_IO(WriteObject(v,up,write,_name));\n    _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART));\n    _CHECK_IO(SafeWrite(v,write,up,&nliterals,sizeof(nliterals)));\n    _CHECK_IO(SafeWrite(v,write,up,&nparameters,sizeof(nparameters)));\n    _CHECK_IO(SafeWrite(v,write,up,&noutervalues,sizeof(noutervalues)));\n    _CHECK_IO(SafeWrite(v,write,up,&nlocalvarinfos,sizeof(nlocalvarinfos)));\n    _CHECK_IO(SafeWrite(v,write,up,&nlineinfos,sizeof(nlineinfos)));\n    _CHECK_IO(SafeWrite(v,write,up,&ndefaultparams,sizeof(ndefaultparams)));\n    _CHECK_IO(SafeWrite(v,write,up,&ninstructions,sizeof(ninstructions)));\n    _CHECK_IO(SafeWrite(v,write,up,&nfunctions,sizeof(nfunctions)));\n    _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART));\n    for(i=0;i<nliterals;i++){\n        _CHECK_IO(WriteObject(v,up,write,_literals[i]));\n    }\n\n    _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART));\n    for(i=0;i<nparameters;i++){\n        _CHECK_IO(WriteObject(v,up,write,_parameters[i]));\n    }\n\n    _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART));\n    for(i=0;i<noutervalues;i++){\n        _CHECK_IO(SafeWrite(v,write,up,&_outervalues[i]._type,sizeof(SQUnsignedInteger)));\n        _CHECK_IO(WriteObject(v,up,write,_outervalues[i]._src));\n        _CHECK_IO(WriteObject(v,up,write,_outervalues[i]._name));\n    }\n\n    _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART));\n    for(i=0;i<nlocalvarinfos;i++){\n        SQLocalVarInfo &lvi=_localvarinfos[i];\n        _CHECK_IO(WriteObject(v,up,write,lvi._name));\n        _CHECK_IO(SafeWrite(v,write,up,&lvi._pos,sizeof(SQUnsignedInteger)));\n        _CHECK_IO(SafeWrite(v,write,up,&lvi._start_op,sizeof(SQUnsignedInteger)));\n        _CHECK_IO(SafeWrite(v,write,up,&lvi._end_op,sizeof(SQUnsignedInteger)));\n    }\n\n    _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART));\n    _CHECK_IO(SafeWrite(v,write,up,_lineinfos,sizeof(SQLineInfo)*nlineinfos));\n\n    _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART));\n    _CHECK_IO(SafeWrite(v,write,up,_defaultparams,sizeof(SQInteger)*ndefaultparams));\n\n    _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART));\n    _CHECK_IO(SafeWrite(v,write,up,_instructions,sizeof(SQInstruction)*ninstructions));\n\n    _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART));\n    for(i=0;i<nfunctions;i++){\n        _CHECK_IO(_funcproto(_functions[i])->Save(v,up,write));\n    }\n    _CHECK_IO(SafeWrite(v,write,up,&_stacksize,sizeof(_stacksize)));\n    _CHECK_IO(SafeWrite(v,write,up,&_bgenerator,sizeof(_bgenerator)));\n    _CHECK_IO(SafeWrite(v,write,up,&_varparams,sizeof(_varparams)));\n    return true;\n}\n\nbool SQFunctionProto::Load(SQVM *v,SQUserPointer up,SQREADFUNC read,SQObjectPtr &ret)\n{\n    SQInteger i, nliterals,nparameters;\n    SQInteger noutervalues ,nlocalvarinfos ;\n    SQInteger nlineinfos,ninstructions ,nfunctions,ndefaultparams ;\n    SQObjectPtr sourcename, name;\n    SQObjectPtr o;\n    _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART));\n    _CHECK_IO(ReadObject(v, up, read, sourcename));\n    _CHECK_IO(ReadObject(v, up, read, name));\n\n    _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART));\n    _CHECK_IO(SafeRead(v,read,up, &nliterals, sizeof(nliterals)));\n    _CHECK_IO(SafeRead(v,read,up, &nparameters, sizeof(nparameters)));\n    _CHECK_IO(SafeRead(v,read,up, &noutervalues, sizeof(noutervalues)));\n    _CHECK_IO(SafeRead(v,read,up, &nlocalvarinfos, sizeof(nlocalvarinfos)));\n    _CHECK_IO(SafeRead(v,read,up, &nlineinfos, sizeof(nlineinfos)));\n    _CHECK_IO(SafeRead(v,read,up, &ndefaultparams, sizeof(ndefaultparams)));\n    _CHECK_IO(SafeRead(v,read,up, &ninstructions, sizeof(ninstructions)));\n    _CHECK_IO(SafeRead(v,read,up, &nfunctions, sizeof(nfunctions)));\n\n\n    SQFunctionProto *f = SQFunctionProto::Create(_opt_ss(v),ninstructions,nliterals,nparameters,\n            nfunctions,noutervalues,nlineinfos,nlocalvarinfos,ndefaultparams);\n    SQObjectPtr proto = f; //gets a ref in case of failure\n    f->_sourcename = sourcename;\n    f->_name = name;\n\n    _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART));\n\n    for(i = 0;i < nliterals; i++){\n        _CHECK_IO(ReadObject(v, up, read, o));\n        f->_literals[i] = o;\n    }\n    _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART));\n\n    for(i = 0; i < nparameters; i++){\n        _CHECK_IO(ReadObject(v, up, read, o));\n        f->_parameters[i] = o;\n    }\n    _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART));\n\n    for(i = 0; i < noutervalues; i++){\n        SQUnsignedInteger type;\n        SQObjectPtr name;\n        _CHECK_IO(SafeRead(v,read,up, &type, sizeof(SQUnsignedInteger)));\n        _CHECK_IO(ReadObject(v, up, read, o));\n        _CHECK_IO(ReadObject(v, up, read, name));\n        f->_outervalues[i] = SQOuterVar(name,o, (SQOuterType)type);\n    }\n    _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART));\n\n    for(i = 0; i < nlocalvarinfos; i++){\n        SQLocalVarInfo lvi;\n        _CHECK_IO(ReadObject(v, up, read, lvi._name));\n        _CHECK_IO(SafeRead(v,read,up, &lvi._pos, sizeof(SQUnsignedInteger)));\n        _CHECK_IO(SafeRead(v,read,up, &lvi._start_op, sizeof(SQUnsignedInteger)));\n        _CHECK_IO(SafeRead(v,read,up, &lvi._end_op, sizeof(SQUnsignedInteger)));\n        f->_localvarinfos[i] = lvi;\n    }\n    _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART));\n    _CHECK_IO(SafeRead(v,read,up, f->_lineinfos, sizeof(SQLineInfo)*nlineinfos));\n\n    _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART));\n    _CHECK_IO(SafeRead(v,read,up, f->_defaultparams, sizeof(SQInteger)*ndefaultparams));\n\n    _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART));\n    _CHECK_IO(SafeRead(v,read,up, f->_instructions, sizeof(SQInstruction)*ninstructions));\n\n    _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART));\n    for(i = 0; i < nfunctions; i++){\n        _CHECK_IO(_funcproto(o)->Load(v, up, read, o));\n        f->_functions[i] = o;\n    }\n    _CHECK_IO(SafeRead(v,read,up, &f->_stacksize, sizeof(f->_stacksize)));\n    _CHECK_IO(SafeRead(v,read,up, &f->_bgenerator, sizeof(f->_bgenerator)));\n    _CHECK_IO(SafeRead(v,read,up, &f->_varparams, sizeof(f->_varparams)));\n\n    ret = f;\n    return true;\n}\n\n#ifndef NO_GARBAGE_COLLECTOR\n\n#define START_MARK()    if(!(_uiRef&MARK_FLAG)){ \\\n        _uiRef|=MARK_FLAG;\n\n#define END_MARK() RemoveFromChain(&_sharedstate->_gc_chain, this); \\\n        AddToChain(chain, this); }\n\nvoid SQVM::Mark(SQCollectable **chain)\n{\n    START_MARK()\n        SQSharedState::MarkObject(_lasterror,chain);\n        SQSharedState::MarkObject(_errorhandler,chain);\n        SQSharedState::MarkObject(_debughook_closure,chain);\n        SQSharedState::MarkObject(_roottable, chain);\n        SQSharedState::MarkObject(temp_reg, chain);\n        for(SQUnsignedInteger i = 0; i < _stack.size(); i++) SQSharedState::MarkObject(_stack[i], chain);\n        for(SQInteger k = 0; k < _callsstacksize; k++) SQSharedState::MarkObject(_callsstack[k]._closure, chain);\n    END_MARK()\n}\n\nvoid SQArray::Mark(SQCollectable **chain)\n{\n    START_MARK()\n        SQInteger len = _values.size();\n        for(SQInteger i = 0;i < len; i++) SQSharedState::MarkObject(_values[i], chain);\n    END_MARK()\n}\nvoid SQTable::Mark(SQCollectable **chain)\n{\n    START_MARK()\n        if(_delegate) _delegate->Mark(chain);\n        SQInteger len = _numofnodes;\n        for(SQInteger i = 0; i < len; i++){\n            SQSharedState::MarkObject(_nodes[i].key, chain);\n            SQSharedState::MarkObject(_nodes[i].val, chain);\n        }\n    END_MARK()\n}\n\nvoid SQClass::Mark(SQCollectable **chain)\n{\n    START_MARK()\n        _members->Mark(chain);\n        if(_base) _base->Mark(chain);\n        SQSharedState::MarkObject(_attributes, chain);\n        for(SQUnsignedInteger i =0; i< _defaultvalues.size(); i++) {\n            SQSharedState::MarkObject(_defaultvalues[i].val, chain);\n            SQSharedState::MarkObject(_defaultvalues[i].attrs, chain);\n        }\n        for(SQUnsignedInteger j =0; j< _methods.size(); j++) {\n            SQSharedState::MarkObject(_methods[j].val, chain);\n            SQSharedState::MarkObject(_methods[j].attrs, chain);\n        }\n        for(SQUnsignedInteger k =0; k< MT_LAST; k++) {\n            SQSharedState::MarkObject(_metamethods[k], chain);\n        }\n    END_MARK()\n}\n\nvoid SQInstance::Mark(SQCollectable **chain)\n{\n    START_MARK()\n        _class->Mark(chain);\n        SQUnsignedInteger nvalues = _class->_defaultvalues.size();\n        for(SQUnsignedInteger i =0; i< nvalues; i++) {\n            SQSharedState::MarkObject(_values[i], chain);\n        }\n    END_MARK()\n}\n\nvoid SQGenerator::Mark(SQCollectable **chain)\n{\n    START_MARK()\n        for(SQUnsignedInteger i = 0; i < _stack.size(); i++) SQSharedState::MarkObject(_stack[i], chain);\n        SQSharedState::MarkObject(_closure, chain);\n    END_MARK()\n}\n\nvoid SQFunctionProto::Mark(SQCollectable **chain)\n{\n    START_MARK()\n        for(SQInteger i = 0; i < _nliterals; i++) SQSharedState::MarkObject(_literals[i], chain);\n        for(SQInteger k = 0; k < _nfunctions; k++) SQSharedState::MarkObject(_functions[k], chain);\n    END_MARK()\n}\n\nvoid SQClosure::Mark(SQCollectable **chain)\n{\n    START_MARK()\n        if(_base) _base->Mark(chain);\n        SQFunctionProto *fp = _function;\n        fp->Mark(chain);\n        for(SQInteger i = 0; i < fp->_noutervalues; i++) SQSharedState::MarkObject(_outervalues[i], chain);\n        for(SQInteger k = 0; k < fp->_ndefaultparams; k++) SQSharedState::MarkObject(_defaultparams[k], chain);\n    END_MARK()\n}\n\nvoid SQNativeClosure::Mark(SQCollectable **chain)\n{\n    START_MARK()\n        for(SQUnsignedInteger i = 0; i < _noutervalues; i++) SQSharedState::MarkObject(_outervalues[i], chain);\n    END_MARK()\n}\n\nvoid SQOuter::Mark(SQCollectable **chain)\n{\n    START_MARK()\n    /* If the valptr points to a closed value, that value is alive */\n    if(_valptr == &_value) {\n      SQSharedState::MarkObject(_value, chain);\n    }\n    END_MARK()\n}\n\nvoid SQUserData::Mark(SQCollectable **chain){\n    START_MARK()\n        if(_delegate) _delegate->Mark(chain);\n    END_MARK()\n}\n\nvoid SQCollectable::UnMark() { _uiRef&=~MARK_FLAG; }\n\n#endif\n\n"
  },
  {
    "path": "extlibs/squirrel/squirrel/sqobject.h",
    "content": "/*  see copyright notice in squirrel.h */\n#ifndef _SQOBJECT_H_\n#define _SQOBJECT_H_\n\n#include \"squtils.h\"\n\n#ifdef _SQ64\n#define UINT_MINUS_ONE (0xFFFFFFFFFFFFFFFF)\n#else\n#define UINT_MINUS_ONE (0xFFFFFFFF)\n#endif\n\n#define SQ_CLOSURESTREAM_HEAD (('S'<<24)|('Q'<<16)|('I'<<8)|('R'))\n#define SQ_CLOSURESTREAM_PART (('P'<<24)|('A'<<16)|('R'<<8)|('T'))\n#define SQ_CLOSURESTREAM_TAIL (('T'<<24)|('A'<<16)|('I'<<8)|('L'))\n\nstruct SQSharedState;\n\nenum SQMetaMethod{\n    MT_ADD=0,\n    MT_SUB=1,\n    MT_MUL=2,\n    MT_DIV=3,\n    MT_UNM=4,\n    MT_MODULO=5,\n    MT_SET=6,\n    MT_GET=7,\n    MT_TYPEOF=8,\n    MT_NEXTI=9,\n    MT_CMP=10,\n    MT_CALL=11,\n    MT_CLONED=12,\n    MT_NEWSLOT=13,\n    MT_DELSLOT=14,\n    MT_TOSTRING=15,\n    MT_NEWMEMBER=16,\n    MT_INHERITED=17,\n    MT_LAST = 18\n};\n\n#define MM_ADD      _SC(\"_add\")\n#define MM_SUB      _SC(\"_sub\")\n#define MM_MUL      _SC(\"_mul\")\n#define MM_DIV      _SC(\"_div\")\n#define MM_UNM      _SC(\"_unm\")\n#define MM_MODULO   _SC(\"_modulo\")\n#define MM_SET      _SC(\"_set\")\n#define MM_GET      _SC(\"_get\")\n#define MM_TYPEOF   _SC(\"_typeof\")\n#define MM_NEXTI    _SC(\"_nexti\")\n#define MM_CMP      _SC(\"_cmp\")\n#define MM_CALL     _SC(\"_call\")\n#define MM_CLONED   _SC(\"_cloned\")\n#define MM_NEWSLOT  _SC(\"_newslot\")\n#define MM_DELSLOT  _SC(\"_delslot\")\n#define MM_TOSTRING _SC(\"_tostring\")\n#define MM_NEWMEMBER _SC(\"_newmember\")\n#define MM_INHERITED _SC(\"_inherited\")\n\n\n#define _CONSTRUCT_VECTOR(type,size,ptr) { \\\n    for(SQInteger n = 0; n < ((SQInteger)size); n++) { \\\n            new (&ptr[n]) type(); \\\n        } \\\n}\n\n#define _DESTRUCT_VECTOR(type,size,ptr) { \\\n    for(SQInteger nl = 0; nl < ((SQInteger)size); nl++) { \\\n            ptr[nl].~type(); \\\n    } \\\n}\n\n#define _COPY_VECTOR(dest,src,size) { \\\n    for(SQInteger _n_ = 0; _n_ < ((SQInteger)size); _n_++) { \\\n        dest[_n_] = src[_n_]; \\\n    } \\\n}\n\n#define _NULL_SQOBJECT_VECTOR(vec,size) { \\\n    for(SQInteger _n_ = 0; _n_ < ((SQInteger)size); _n_++) { \\\n        vec[_n_].Null(); \\\n    } \\\n}\n\n#define MINPOWER2 4\n\nstruct SQRefCounted\n{\n    SQUnsignedInteger _uiRef;\n    struct SQWeakRef *_weakref;\n    SQRefCounted() { _uiRef = 0; _weakref = NULL; }\n    virtual ~SQRefCounted();\n    SQWeakRef *GetWeakRef(SQObjectType type);\n    virtual void Release()=0;\n\n};\n\nstruct SQWeakRef : SQRefCounted\n{\n    void Release();\n    SQObject _obj;\n};\n\n#define _realval(o) (sq_type((o)) != OT_WEAKREF?(SQObject)o:_weakref(o)->_obj)\n\nstruct SQObjectPtr;\n\n#define __AddRef(type,unval) if(ISREFCOUNTED(type)) \\\n        { \\\n            unval.pRefCounted->_uiRef++; \\\n        }\n\n#define __Release(type,unval) if(ISREFCOUNTED(type) && ((--unval.pRefCounted->_uiRef)==0))  \\\n        {   \\\n            unval.pRefCounted->Release();   \\\n        }\n\n#define __ObjRelease(obj) { \\\n    if((obj)) { \\\n        (obj)->_uiRef--; \\\n        if((obj)->_uiRef == 0) \\\n            (obj)->Release(); \\\n        (obj) = NULL;   \\\n    } \\\n}\n\n#define __ObjAddRef(obj) { \\\n    (obj)->_uiRef++; \\\n}\n\n#define is_delegable(t) (sq_type(t)&SQOBJECT_DELEGABLE)\n#define raw_type(obj) _RAW_TYPE((obj)._type)\n\n#define _integer(obj) ((obj)._unVal.nInteger)\n#define _float(obj) ((obj)._unVal.fFloat)\n#define _string(obj) ((obj)._unVal.pString)\n#define _table(obj) ((obj)._unVal.pTable)\n#define _array(obj) ((obj)._unVal.pArray)\n#define _closure(obj) ((obj)._unVal.pClosure)\n#define _generator(obj) ((obj)._unVal.pGenerator)\n#define _nativeclosure(obj) ((obj)._unVal.pNativeClosure)\n#define _userdata(obj) ((obj)._unVal.pUserData)\n#define _userpointer(obj) ((obj)._unVal.pUserPointer)\n#define _thread(obj) ((obj)._unVal.pThread)\n#define _funcproto(obj) ((obj)._unVal.pFunctionProto)\n#define _class(obj) ((obj)._unVal.pClass)\n#define _instance(obj) ((obj)._unVal.pInstance)\n#define _delegable(obj) ((SQDelegable *)(obj)._unVal.pDelegable)\n#define _weakref(obj) ((obj)._unVal.pWeakRef)\n#define _outer(obj) ((obj)._unVal.pOuter)\n#define _refcounted(obj) ((obj)._unVal.pRefCounted)\n#define _rawval(obj) ((obj)._unVal.raw)\n\n#define _stringval(obj) (obj)._unVal.pString->_val\n#define _userdataval(obj) ((SQUserPointer)sq_aligning((obj)._unVal.pUserData + 1))\n\n#define tofloat(num) ((sq_type(num)==OT_FLOAT)?_float(num):(SQFloat)_integer(num))\n#define tointeger(num) ((sq_type(num)==OT_FLOAT)?(SQInteger)_float(num):_integer(num))\n/////////////////////////////////////////////////////////////////////////////////////\n/////////////////////////////////////////////////////////////////////////////////////\n#if defined(SQUSEDOUBLE) && !defined(_SQ64) || !defined(SQUSEDOUBLE) && defined(_SQ64)\n#define SQ_REFOBJECT_INIT() SQ_OBJECT_RAWINIT()\n#else\n#define SQ_REFOBJECT_INIT()\n#endif\n\n#define _REF_TYPE_DECL(type,_class,sym) \\\n    SQObjectPtr(_class * x) \\\n    { \\\n        SQ_OBJECT_RAWINIT() \\\n        _type=type; \\\n        _unVal.sym = x; \\\n        assert(_unVal.pTable); \\\n        _unVal.pRefCounted->_uiRef++; \\\n    } \\\n    inline SQObjectPtr& operator=(_class *x) \\\n    {  \\\n        SQObjectType tOldType; \\\n        SQObjectValue unOldVal; \\\n        tOldType=_type; \\\n        unOldVal=_unVal; \\\n        _type = type; \\\n        SQ_REFOBJECT_INIT() \\\n        _unVal.sym = x; \\\n        _unVal.pRefCounted->_uiRef++; \\\n        __Release(tOldType,unOldVal); \\\n        return *this; \\\n    }\n\n#define _SCALAR_TYPE_DECL(type,_class,sym) \\\n    SQObjectPtr(_class x) \\\n    { \\\n        SQ_OBJECT_RAWINIT() \\\n        _type=type; \\\n        _unVal.sym = x; \\\n    } \\\n    inline SQObjectPtr& operator=(_class x) \\\n    {  \\\n        __Release(_type,_unVal); \\\n        _type = type; \\\n        SQ_OBJECT_RAWINIT() \\\n        _unVal.sym = x; \\\n        return *this; \\\n    }\nstruct SQObjectPtr : public SQObject\n{\n    SQObjectPtr()\n    {\n        SQ_OBJECT_RAWINIT()\n        _type=OT_NULL;\n        _unVal.pUserPointer=NULL;\n    }\n    SQObjectPtr(const SQObjectPtr &o)\n    {\n        _type = o._type;\n        _unVal = o._unVal;\n        __AddRef(_type,_unVal);\n    }\n    SQObjectPtr(const SQObject &o)\n    {\n        _type = o._type;\n        _unVal = o._unVal;\n        __AddRef(_type,_unVal);\n    }\n    _REF_TYPE_DECL(OT_TABLE,SQTable,pTable)\n    _REF_TYPE_DECL(OT_CLASS,SQClass,pClass)\n    _REF_TYPE_DECL(OT_INSTANCE,SQInstance,pInstance)\n    _REF_TYPE_DECL(OT_ARRAY,SQArray,pArray)\n    _REF_TYPE_DECL(OT_CLOSURE,SQClosure,pClosure)\n    _REF_TYPE_DECL(OT_NATIVECLOSURE,SQNativeClosure,pNativeClosure)\n    _REF_TYPE_DECL(OT_OUTER,SQOuter,pOuter)\n    _REF_TYPE_DECL(OT_GENERATOR,SQGenerator,pGenerator)\n    _REF_TYPE_DECL(OT_STRING,SQString,pString)\n    _REF_TYPE_DECL(OT_USERDATA,SQUserData,pUserData)\n    _REF_TYPE_DECL(OT_WEAKREF,SQWeakRef,pWeakRef)\n    _REF_TYPE_DECL(OT_THREAD,SQVM,pThread)\n    _REF_TYPE_DECL(OT_FUNCPROTO,SQFunctionProto,pFunctionProto)\n\n    _SCALAR_TYPE_DECL(OT_INTEGER,SQInteger,nInteger)\n    _SCALAR_TYPE_DECL(OT_FLOAT,SQFloat,fFloat)\n    _SCALAR_TYPE_DECL(OT_USERPOINTER,SQUserPointer,pUserPointer)\n\n    SQObjectPtr(bool bBool)\n    {\n        SQ_OBJECT_RAWINIT()\n        _type = OT_BOOL;\n        _unVal.nInteger = bBool?1:0;\n    }\n    inline SQObjectPtr& operator=(bool b)\n    {\n        __Release(_type,_unVal);\n        SQ_OBJECT_RAWINIT()\n        _type = OT_BOOL;\n        _unVal.nInteger = b?1:0;\n        return *this;\n    }\n\n    ~SQObjectPtr()\n    {\n        __Release(_type,_unVal);\n    }\n\n    inline SQObjectPtr& operator=(const SQObjectPtr& obj)\n    {\n        SQObjectType tOldType;\n        SQObjectValue unOldVal;\n        tOldType=_type;\n        unOldVal=_unVal;\n        _unVal = obj._unVal;\n        _type = obj._type;\n        __AddRef(_type,_unVal);\n        __Release(tOldType,unOldVal);\n        return *this;\n    }\n    inline SQObjectPtr& operator=(const SQObject& obj)\n    {\n        SQObjectType tOldType;\n        SQObjectValue unOldVal;\n        tOldType=_type;\n        unOldVal=_unVal;\n        _unVal = obj._unVal;\n        _type = obj._type;\n        __AddRef(_type,_unVal);\n        __Release(tOldType,unOldVal);\n        return *this;\n    }\n    inline void Null()\n    {\n        SQObjectType tOldType = _type;\n        SQObjectValue unOldVal = _unVal;\n        _type = OT_NULL;\n        _unVal.raw = (SQRawObjectVal)NULL;\n        __Release(tOldType ,unOldVal);\n    }\n    private:\n        SQObjectPtr(const SQChar *){} //safety\n};\n\n\ninline void _Swap(SQObject &a,SQObject &b)\n{\n    SQObjectType tOldType = a._type;\n    SQObjectValue unOldVal = a._unVal;\n    a._type = b._type;\n    a._unVal = b._unVal;\n    b._type = tOldType;\n    b._unVal = unOldVal;\n}\n\n/////////////////////////////////////////////////////////////////////////////////////\n#ifndef NO_GARBAGE_COLLECTOR\n#define MARK_FLAG 0x80000000\nstruct SQCollectable : public SQRefCounted {\n    SQCollectable *_next;\n    SQCollectable *_prev;\n    SQSharedState *_sharedstate;\n    virtual SQObjectType GetType()=0;\n    virtual void Release()=0;\n    virtual void Mark(SQCollectable **chain)=0;\n    void UnMark();\n    virtual void Finalize()=0;\n    static void AddToChain(SQCollectable **chain,SQCollectable *c);\n    static void RemoveFromChain(SQCollectable **chain,SQCollectable *c);\n};\n\n\n#define ADD_TO_CHAIN(chain,obj) AddToChain(chain,obj)\n#define REMOVE_FROM_CHAIN(chain,obj) {if(!(_uiRef&MARK_FLAG))RemoveFromChain(chain,obj);}\n#define CHAINABLE_OBJ SQCollectable\n#define INIT_CHAIN() {_next=NULL;_prev=NULL;_sharedstate=ss;}\n#else\n\n#define ADD_TO_CHAIN(chain,obj) ((void)0)\n#define REMOVE_FROM_CHAIN(chain,obj) ((void)0)\n#define CHAINABLE_OBJ SQRefCounted\n#define INIT_CHAIN() ((void)0)\n#endif\n\nstruct SQDelegable : public CHAINABLE_OBJ {\n    bool SetDelegate(SQTable *m);\n    virtual bool GetMetaMethod(SQVM *v,SQMetaMethod mm,SQObjectPtr &res);\n    SQTable *_delegate;\n};\n\nSQUnsignedInteger TranslateIndex(const SQObjectPtr &idx);\ntypedef sqvector<SQObjectPtr> SQObjectPtrVec;\ntypedef sqvector<SQInteger> SQIntVec;\nconst SQChar *GetTypeName(const SQObjectPtr &obj1);\nconst SQChar *IdType2Name(SQObjectType type);\n\n\n\n#endif //_SQOBJECT_H_\n"
  },
  {
    "path": "extlibs/squirrel/squirrel/sqopcodes.h",
    "content": "/*  see copyright notice in squirrel.h */\n#ifndef _SQOPCODES_H_\n#define _SQOPCODES_H_\n\n#define MAX_FUNC_STACKSIZE 0xFF\n#define MAX_LITERALS ((SQInteger)0x7FFFFFFF)\n\nenum BitWiseOP {\n    BW_AND = 0,\n    BW_OR = 2,\n    BW_XOR = 3,\n    BW_SHIFTL = 4,\n    BW_SHIFTR = 5,\n    BW_USHIFTR = 6\n};\n\nenum CmpOP {\n    CMP_G = 0,\n    CMP_GE = 2,\n    CMP_L = 3,\n    CMP_LE = 4,\n    CMP_3W = 5\n};\n\nenum NewObjectType {\n    NOT_TABLE = 0,\n    NOT_ARRAY = 1,\n    NOT_CLASS = 2\n};\n\nenum AppendArrayType {\n    AAT_STACK = 0,\n    AAT_LITERAL = 1,\n    AAT_INT = 2,\n    AAT_FLOAT = 3,\n    AAT_BOOL = 4\n};\n\nenum SQOpcode\n{\n    _OP_LINE=               0x00,\n    _OP_LOAD=               0x01,\n    _OP_LOADINT=            0x02,\n    _OP_LOADFLOAT=          0x03,\n    _OP_DLOAD=              0x04,\n    _OP_TAILCALL=           0x05,\n    _OP_CALL=               0x06,\n    _OP_PREPCALL=           0x07,\n    _OP_PREPCALLK=          0x08,\n    _OP_GETK=               0x09,\n    _OP_MOVE=               0x0A,\n    _OP_NEWSLOT=            0x0B,\n    _OP_DELETE=             0x0C,\n    _OP_SET=                0x0D,\n    _OP_GET=                0x0E,\n    _OP_EQ=                 0x0F,\n    _OP_NE=                 0x10,\n    _OP_ADD=                0x11,\n    _OP_SUB=                0x12,\n    _OP_MUL=                0x13,\n    _OP_DIV=                0x14,\n    _OP_MOD=                0x15,\n    _OP_BITW=               0x16,\n    _OP_RETURN=             0x17,\n    _OP_LOADNULLS=          0x18,\n    _OP_LOADROOT=           0x19,\n    _OP_LOADBOOL=           0x1A,\n    _OP_DMOVE=              0x1B,\n    _OP_JMP=                0x1C,\n    //_OP_JNZ=              0x1D,\n    _OP_JCMP=               0x1D,\n    _OP_JZ=                 0x1E,\n    _OP_SETOUTER=           0x1F,\n    _OP_GETOUTER=           0x20,\n    _OP_NEWOBJ=             0x21,\n    _OP_APPENDARRAY=        0x22,\n    _OP_COMPARITH=          0x23,\n    _OP_INC=                0x24,\n    _OP_INCL=               0x25,\n    _OP_PINC=               0x26,\n    _OP_PINCL=              0x27,\n    _OP_CMP=                0x28,\n    _OP_EXISTS=             0x29,\n    _OP_INSTANCEOF=         0x2A,\n    _OP_AND=                0x2B,\n    _OP_OR=                 0x2C,\n    _OP_NEG=                0x2D,\n    _OP_NOT=                0x2E,\n    _OP_BWNOT=              0x2F,\n    _OP_CLOSURE=            0x30,\n    _OP_YIELD=              0x31,\n    _OP_RESUME=             0x32,\n    _OP_FOREACH=            0x33,\n    _OP_POSTFOREACH=        0x34,\n    _OP_CLONE=              0x35,\n    _OP_TYPEOF=             0x36,\n    _OP_PUSHTRAP=           0x37,\n    _OP_POPTRAP=            0x38,\n    _OP_THROW=              0x39,\n    _OP_NEWSLOTA=           0x3A,\n    _OP_GETBASE=            0x3B,\n    _OP_CLOSE=              0x3C\n};\n\nstruct SQInstructionDesc {\n    const SQChar *name;\n};\n\nstruct SQInstruction\n{\n    SQInstruction(){};\n    SQInstruction(SQOpcode _op,SQInteger a0=0,SQInteger a1=0,SQInteger a2=0,SQInteger a3=0)\n    {   op = (unsigned char)_op;\n        _arg0 = (unsigned char)a0;_arg1 = (SQInt32)a1;\n        _arg2 = (unsigned char)a2;_arg3 = (unsigned char)a3;\n    }\n\n\n    SQInt32 _arg1;\n    unsigned char op;\n    unsigned char _arg0;\n    unsigned char _arg2;\n    unsigned char _arg3;\n};\n\n#include \"squtils.h\"\ntypedef sqvector<SQInstruction> SQInstructionVec;\n\n#define NEW_SLOT_ATTRIBUTES_FLAG    0x01\n#define NEW_SLOT_STATIC_FLAG        0x02\n\n#endif // _SQOPCODES_H_\n"
  },
  {
    "path": "extlibs/squirrel/squirrel/sqpcheader.h",
    "content": "/*  see copyright notice in squirrel.h */\n#ifndef _SQPCHEADER_H_\n#define _SQPCHEADER_H_\n\n#if defined(_MSC_VER) && defined(_DEBUG)\n#include <crtdbg.h>\n#endif\n\n#include <limits.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <assert.h>\n#include <new>\n//squirrel stuff\n#include <squirrel.h>\n#include \"sqobject.h\"\n#include \"sqstate.h\"\n\n#endif //_SQPCHEADER_H_\n"
  },
  {
    "path": "extlibs/squirrel/squirrel/sqstate.cpp",
    "content": "/*\n    see copyright notice in squirrel.h\n*/\n#include \"sqpcheader.h\"\n#include \"sqopcodes.h\"\n#include \"sqvm.h\"\n#include \"sqfuncproto.h\"\n#include \"sqclosure.h\"\n#include \"sqstring.h\"\n#include \"sqtable.h\"\n#include \"sqarray.h\"\n#include \"squserdata.h\"\n#include \"sqclass.h\"\n\nSQSharedState::SQSharedState()\n{\n    _compilererrorhandler = NULL;\n    _printfunc = NULL;\n    _errorfunc = NULL;\n    _debuginfo = false;\n    _notifyallexceptions = false;\n    _foreignptr = NULL;\n    _releasehook = NULL;\n}\n\n#define newsysstring(s) {   \\\n    _systemstrings->push_back(SQString::Create(this,s));    \\\n    }\n\n#define newmetamethod(s) {  \\\n    _metamethods->push_back(SQString::Create(this,s));  \\\n    _table(_metamethodsmap)->NewSlot(_metamethods->back(),(SQInteger)(_metamethods->size()-1)); \\\n    }\n\nbool CompileTypemask(SQIntVec &res,const SQChar *typemask)\n{\n    SQInteger i = 0;\n    SQInteger mask = 0;\n    while(typemask[i] != 0) {\n        switch(typemask[i]) {\n            case 'o': mask |= _RT_NULL; break;\n            case 'i': mask |= _RT_INTEGER; break;\n            case 'f': mask |= _RT_FLOAT; break;\n            case 'n': mask |= (_RT_FLOAT | _RT_INTEGER); break;\n            case 's': mask |= _RT_STRING; break;\n            case 't': mask |= _RT_TABLE; break;\n            case 'a': mask |= _RT_ARRAY; break;\n            case 'u': mask |= _RT_USERDATA; break;\n            case 'c': mask |= (_RT_CLOSURE | _RT_NATIVECLOSURE); break;\n            case 'b': mask |= _RT_BOOL; break;\n            case 'g': mask |= _RT_GENERATOR; break;\n            case 'p': mask |= _RT_USERPOINTER; break;\n            case 'v': mask |= _RT_THREAD; break;\n            case 'x': mask |= _RT_INSTANCE; break;\n            case 'y': mask |= _RT_CLASS; break;\n            case 'r': mask |= _RT_WEAKREF; break;\n            case '.': mask = -1; res.push_back(mask); i++; mask = 0; continue;\n            case ' ': i++; continue; //ignores spaces\n            default:\n                return false;\n        }\n        i++;\n        if(typemask[i] == '|') {\n            i++;\n            if(typemask[i] == 0)\n                return false;\n            continue;\n        }\n        res.push_back(mask);\n        mask = 0;\n\n    }\n    return true;\n}\n\nSQTable *CreateDefaultDelegate(SQSharedState *ss,const SQRegFunction *funcz)\n{\n    SQInteger i=0;\n    SQTable *t=SQTable::Create(ss,0);\n    while(funcz[i].name!=0){\n        SQNativeClosure *nc = SQNativeClosure::Create(ss,funcz[i].f,0);\n        nc->_nparamscheck = funcz[i].nparamscheck;\n        nc->_name = SQString::Create(ss,funcz[i].name);\n        if(funcz[i].typemask && !CompileTypemask(nc->_typecheck,funcz[i].typemask))\n            return NULL;\n        t->NewSlot(SQString::Create(ss,funcz[i].name),nc);\n        i++;\n    }\n    return t;\n}\n\nvoid SQSharedState::Init()\n{\n    _scratchpad=NULL;\n    _scratchpadsize=0;\n#ifndef NO_GARBAGE_COLLECTOR\n    _gc_chain=NULL;\n#endif\n    _stringtable = (SQStringTable*)SQ_MALLOC(sizeof(SQStringTable));\n    new (_stringtable) SQStringTable(this);\n    sq_new(_metamethods,SQObjectPtrVec);\n    sq_new(_systemstrings,SQObjectPtrVec);\n    sq_new(_types,SQObjectPtrVec);\n    _metamethodsmap = SQTable::Create(this,MT_LAST-1);\n    //adding type strings to avoid memory trashing\n    //types names\n    newsysstring(_SC(\"null\"));\n    newsysstring(_SC(\"table\"));\n    newsysstring(_SC(\"array\"));\n    newsysstring(_SC(\"closure\"));\n    newsysstring(_SC(\"string\"));\n    newsysstring(_SC(\"userdata\"));\n    newsysstring(_SC(\"integer\"));\n    newsysstring(_SC(\"float\"));\n    newsysstring(_SC(\"userpointer\"));\n    newsysstring(_SC(\"function\"));\n    newsysstring(_SC(\"generator\"));\n    newsysstring(_SC(\"thread\"));\n    newsysstring(_SC(\"class\"));\n    newsysstring(_SC(\"instance\"));\n    newsysstring(_SC(\"bool\"));\n    //meta methods\n    newmetamethod(MM_ADD);\n    newmetamethod(MM_SUB);\n    newmetamethod(MM_MUL);\n    newmetamethod(MM_DIV);\n    newmetamethod(MM_UNM);\n    newmetamethod(MM_MODULO);\n    newmetamethod(MM_SET);\n    newmetamethod(MM_GET);\n    newmetamethod(MM_TYPEOF);\n    newmetamethod(MM_NEXTI);\n    newmetamethod(MM_CMP);\n    newmetamethod(MM_CALL);\n    newmetamethod(MM_CLONED);\n    newmetamethod(MM_NEWSLOT);\n    newmetamethod(MM_DELSLOT);\n    newmetamethod(MM_TOSTRING);\n    newmetamethod(MM_NEWMEMBER);\n    newmetamethod(MM_INHERITED);\n\n    _constructoridx = SQString::Create(this,_SC(\"constructor\"));\n    _registry = SQTable::Create(this,0);\n    _consts = SQTable::Create(this,0);\n    _table_default_delegate = CreateDefaultDelegate(this,_table_default_delegate_funcz);\n    _array_default_delegate = CreateDefaultDelegate(this,_array_default_delegate_funcz);\n    _string_default_delegate = CreateDefaultDelegate(this,_string_default_delegate_funcz);\n    _number_default_delegate = CreateDefaultDelegate(this,_number_default_delegate_funcz);\n    _closure_default_delegate = CreateDefaultDelegate(this,_closure_default_delegate_funcz);\n    _generator_default_delegate = CreateDefaultDelegate(this,_generator_default_delegate_funcz);\n    _thread_default_delegate = CreateDefaultDelegate(this,_thread_default_delegate_funcz);\n    _class_default_delegate = CreateDefaultDelegate(this,_class_default_delegate_funcz);\n    _instance_default_delegate = CreateDefaultDelegate(this,_instance_default_delegate_funcz);\n    _weakref_default_delegate = CreateDefaultDelegate(this,_weakref_default_delegate_funcz);\n}\n\nSQSharedState::~SQSharedState()\n{\n    if(_releasehook) { _releasehook(_foreignptr,0); _releasehook = NULL; }\n    _constructoridx.Null();\n    _table(_registry)->Finalize();\n    _table(_consts)->Finalize();\n    _table(_metamethodsmap)->Finalize();\n    _registry.Null();\n    _consts.Null();\n    _metamethodsmap.Null();\n    while(!_systemstrings->empty()) {\n        _systemstrings->back().Null();\n        _systemstrings->pop_back();\n    }\n    _thread(_root_vm)->Finalize();\n    _root_vm.Null();\n    _table_default_delegate.Null();\n    _array_default_delegate.Null();\n    _string_default_delegate.Null();\n    _number_default_delegate.Null();\n    _closure_default_delegate.Null();\n    _generator_default_delegate.Null();\n    _thread_default_delegate.Null();\n    _class_default_delegate.Null();\n    _instance_default_delegate.Null();\n    _weakref_default_delegate.Null();\n    _refs_table.Finalize();\n#ifndef NO_GARBAGE_COLLECTOR\n    SQCollectable *t = _gc_chain;\n    SQCollectable *nx = NULL;\n    if(t) {\n        t->_uiRef++;\n        while(t) {\n            t->Finalize();\n            nx = t->_next;\n            if(nx) nx->_uiRef++;\n            if(--t->_uiRef == 0)\n                t->Release();\n            t = nx;\n        }\n    }\n    assert(_gc_chain==NULL); //just to proove a theory\n    while(_gc_chain){\n        _gc_chain->_uiRef++;\n        _gc_chain->Release();\n    }\n#endif\n\n    sq_delete(_types,SQObjectPtrVec);\n    sq_delete(_systemstrings,SQObjectPtrVec);\n    sq_delete(_metamethods,SQObjectPtrVec);\n    sq_delete(_stringtable,SQStringTable);\n    if(_scratchpad)SQ_FREE(_scratchpad,_scratchpadsize);\n}\n\n\nSQInteger SQSharedState::GetMetaMethodIdxByName(const SQObjectPtr &name)\n{\n    if(sq_type(name) != OT_STRING)\n        return -1;\n    SQObjectPtr ret;\n    if(_table(_metamethodsmap)->Get(name,ret)) {\n        return _integer(ret);\n    }\n    return -1;\n}\n\n#ifndef NO_GARBAGE_COLLECTOR\n\nvoid SQSharedState::MarkObject(SQObjectPtr &o,SQCollectable **chain)\n{\n    switch(sq_type(o)){\n    case OT_TABLE:_table(o)->Mark(chain);break;\n    case OT_ARRAY:_array(o)->Mark(chain);break;\n    case OT_USERDATA:_userdata(o)->Mark(chain);break;\n    case OT_CLOSURE:_closure(o)->Mark(chain);break;\n    case OT_NATIVECLOSURE:_nativeclosure(o)->Mark(chain);break;\n    case OT_GENERATOR:_generator(o)->Mark(chain);break;\n    case OT_THREAD:_thread(o)->Mark(chain);break;\n    case OT_CLASS:_class(o)->Mark(chain);break;\n    case OT_INSTANCE:_instance(o)->Mark(chain);break;\n    case OT_OUTER:_outer(o)->Mark(chain);break;\n    case OT_FUNCPROTO:_funcproto(o)->Mark(chain);break;\n    default: break; //shutup compiler\n    }\n}\n\nvoid SQSharedState::RunMark(SQVM* SQ_UNUSED_ARG(vm),SQCollectable **tchain)\n{\n    SQVM *vms = _thread(_root_vm);\n\n    vms->Mark(tchain);\n\n    _refs_table.Mark(tchain);\n    MarkObject(_registry,tchain);\n    MarkObject(_consts,tchain);\n    MarkObject(_metamethodsmap,tchain);\n    MarkObject(_table_default_delegate,tchain);\n    MarkObject(_array_default_delegate,tchain);\n    MarkObject(_string_default_delegate,tchain);\n    MarkObject(_number_default_delegate,tchain);\n    MarkObject(_generator_default_delegate,tchain);\n    MarkObject(_thread_default_delegate,tchain);\n    MarkObject(_closure_default_delegate,tchain);\n    MarkObject(_class_default_delegate,tchain);\n    MarkObject(_instance_default_delegate,tchain);\n    MarkObject(_weakref_default_delegate,tchain);\n\n}\n\nSQInteger SQSharedState::ResurrectUnreachable(SQVM *vm)\n{\n    SQInteger n=0;\n    SQCollectable *tchain=NULL;\n\n    RunMark(vm,&tchain);\n\n    SQCollectable *resurrected = _gc_chain;\n    SQCollectable *t = resurrected;\n\n    _gc_chain = tchain;\n\n    SQArray *ret = NULL;\n    if(resurrected) {\n        ret = SQArray::Create(this,0);\n        SQCollectable *rlast = NULL;\n        while(t) {\n            rlast = t;\n            SQObjectType type = t->GetType();\n            if(type != OT_FUNCPROTO && type != OT_OUTER) {\n                SQObject sqo;\n                sqo._type = type;\n                sqo._unVal.pRefCounted = t;\n                ret->Append(sqo);\n            }\n            t = t->_next;\n            n++;\n        }\n\n        assert(rlast->_next == NULL);\n        rlast->_next = _gc_chain;\n        if(_gc_chain)\n        {\n            _gc_chain->_prev = rlast;\n        }\n        _gc_chain = resurrected;\n    }\n\n    t = _gc_chain;\n    while(t) {\n        t->UnMark();\n        t = t->_next;\n    }\n\n    if(ret) {\n        SQObjectPtr temp = ret;\n        vm->Push(temp);\n    }\n    else {\n        vm->PushNull();\n    }\n    return n;\n}\n\nSQInteger SQSharedState::CollectGarbage(SQVM *vm)\n{\n    SQInteger n = 0;\n    SQCollectable *tchain = NULL;\n\n    RunMark(vm,&tchain);\n\n    SQCollectable *t = _gc_chain;\n    SQCollectable *nx = NULL;\n    if(t) {\n        t->_uiRef++;\n        while(t) {\n            t->Finalize();\n            nx = t->_next;\n            if(nx) nx->_uiRef++;\n            if(--t->_uiRef == 0)\n                t->Release();\n            t = nx;\n            n++;\n        }\n    }\n\n    t = tchain;\n    while(t) {\n        t->UnMark();\n        t = t->_next;\n    }\n    _gc_chain = tchain;\n\n    return n;\n}\n#endif\n\n#ifndef NO_GARBAGE_COLLECTOR\nvoid SQCollectable::AddToChain(SQCollectable **chain,SQCollectable *c)\n{\n    c->_prev = NULL;\n    c->_next = *chain;\n    if(*chain) (*chain)->_prev = c;\n    *chain = c;\n}\n\nvoid SQCollectable::RemoveFromChain(SQCollectable **chain,SQCollectable *c)\n{\n    if(c->_prev) c->_prev->_next = c->_next;\n    else *chain = c->_next;\n    if(c->_next)\n        c->_next->_prev = c->_prev;\n    c->_next = NULL;\n    c->_prev = NULL;\n}\n#endif\n\nSQChar* SQSharedState::GetScratchPad(SQInteger size)\n{\n    SQInteger newsize;\n    if(size>0) {\n        if(_scratchpadsize < size) {\n            newsize = size + (size>>1);\n            _scratchpad = (SQChar *)SQ_REALLOC(_scratchpad,_scratchpadsize,newsize);\n            _scratchpadsize = newsize;\n\n        }else if(_scratchpadsize >= (size<<5)) {\n            newsize = _scratchpadsize >> 1;\n            _scratchpad = (SQChar *)SQ_REALLOC(_scratchpad,_scratchpadsize,newsize);\n            _scratchpadsize = newsize;\n        }\n    }\n    return _scratchpad;\n}\n\nRefTable::RefTable()\n{\n    AllocNodes(4);\n}\n\nvoid RefTable::Finalize()\n{\n    RefNode *nodes = _nodes;\n    for(SQUnsignedInteger n = 0; n < _numofslots; n++) {\n        nodes->obj.Null();\n        nodes++;\n    }\n}\n\nRefTable::~RefTable()\n{\n    SQ_FREE(_buckets,(_numofslots * sizeof(RefNode *)) + (_numofslots * sizeof(RefNode)));\n}\n\n#ifndef NO_GARBAGE_COLLECTOR\nvoid RefTable::Mark(SQCollectable **chain)\n{\n    RefNode *nodes = (RefNode *)_nodes;\n    for(SQUnsignedInteger n = 0; n < _numofslots; n++) {\n        if(sq_type(nodes->obj) != OT_NULL) {\n            SQSharedState::MarkObject(nodes->obj,chain);\n        }\n        nodes++;\n    }\n}\n#endif\n\nvoid RefTable::AddRef(SQObject &obj)\n{\n    SQHash mainpos;\n    RefNode *prev;\n    RefNode *ref = Get(obj,mainpos,&prev,true);\n    ref->refs++;\n}\n\nSQUnsignedInteger RefTable::GetRefCount(SQObject &obj)\n{\n     SQHash mainpos;\n     RefNode *prev;\n     RefNode *ref = Get(obj,mainpos,&prev,true);\n     return ref->refs;\n}\n\n\nSQBool RefTable::Release(SQObject &obj)\n{\n    SQHash mainpos;\n    RefNode *prev;\n    RefNode *ref = Get(obj,mainpos,&prev,false);\n    if(ref) {\n        if(--ref->refs == 0) {\n            SQObjectPtr o = ref->obj;\n            if(prev) {\n                prev->next = ref->next;\n            }\n            else {\n                _buckets[mainpos] = ref->next;\n            }\n            ref->next = _freelist;\n            _freelist = ref;\n            _slotused--;\n            ref->obj.Null();\n            //<<FIXME>>test for shrink?\n            return SQTrue;\n        }\n    }\n    else {\n        assert(0);\n    }\n    return SQFalse;\n}\n\nvoid RefTable::Resize(SQUnsignedInteger size)\n{\n    RefNode **oldbucks = _buckets;\n    RefNode *t = _nodes;\n    SQUnsignedInteger oldnumofslots = _numofslots;\n    AllocNodes(size);\n    //rehash\n    SQUnsignedInteger nfound = 0;\n    for(SQUnsignedInteger n = 0; n < oldnumofslots; n++) {\n        if(sq_type(t->obj) != OT_NULL) {\n            //add back;\n            assert(t->refs != 0);\n            RefNode *nn = Add(::HashObj(t->obj)&(_numofslots-1),t->obj);\n            nn->refs = t->refs;\n            t->obj.Null();\n            nfound++;\n        }\n        t++;\n    }\n    assert(nfound == oldnumofslots);\n    SQ_FREE(oldbucks,(oldnumofslots * sizeof(RefNode *)) + (oldnumofslots * sizeof(RefNode)));\n}\n\nRefTable::RefNode *RefTable::Add(SQHash mainpos,SQObject &obj)\n{\n    RefNode *t = _buckets[mainpos];\n    RefNode *newnode = _freelist;\n    newnode->obj = obj;\n    _buckets[mainpos] = newnode;\n    _freelist = _freelist->next;\n    newnode->next = t;\n    assert(newnode->refs == 0);\n    _slotused++;\n    return newnode;\n}\n\nRefTable::RefNode *RefTable::Get(SQObject &obj,SQHash &mainpos,RefNode **prev,bool add)\n{\n    RefNode *ref;\n    mainpos = ::HashObj(obj)&(_numofslots-1);\n    *prev = NULL;\n    for (ref = _buckets[mainpos]; ref; ) {\n        if(_rawval(ref->obj) == _rawval(obj) && sq_type(ref->obj) == sq_type(obj))\n            break;\n        *prev = ref;\n        ref = ref->next;\n    }\n    if(ref == NULL && add) {\n        if(_numofslots == _slotused) {\n            assert(_freelist == 0);\n            Resize(_numofslots*2);\n            mainpos = ::HashObj(obj)&(_numofslots-1);\n        }\n        ref = Add(mainpos,obj);\n    }\n    return ref;\n}\n\nvoid RefTable::AllocNodes(SQUnsignedInteger size)\n{\n    RefNode **bucks;\n    RefNode *nodes;\n    bucks = (RefNode **)SQ_MALLOC((size * sizeof(RefNode *)) + (size * sizeof(RefNode)));\n    nodes = (RefNode *)&bucks[size];\n    RefNode *temp = nodes;\n    SQUnsignedInteger n;\n    for(n = 0; n < size - 1; n++) {\n        bucks[n] = NULL;\n        temp->refs = 0;\n        new (&temp->obj) SQObjectPtr;\n        temp->next = temp+1;\n        temp++;\n    }\n    bucks[n] = NULL;\n    temp->refs = 0;\n    new (&temp->obj) SQObjectPtr;\n    temp->next = NULL;\n    _freelist = nodes;\n    _nodes = nodes;\n    _buckets = bucks;\n    _slotused = 0;\n    _numofslots = size;\n}\n//////////////////////////////////////////////////////////////////////////\n//SQStringTable\n/*\n* The following code is based on Lua 4.0 (Copyright 1994-2002 Tecgraf, PUC-Rio.)\n* http://www.lua.org/copyright.html#4\n* http://www.lua.org/source/4.0.1/src_lstring.c.html\n*/\n\nSQStringTable::SQStringTable(SQSharedState *ss)\n{\n    _sharedstate = ss;\n    AllocNodes(4);\n    _slotused = 0;\n}\n\nSQStringTable::~SQStringTable()\n{\n    SQ_FREE(_strings,sizeof(SQString*)*_numofslots);\n    _strings = NULL;\n}\n\nvoid SQStringTable::AllocNodes(SQInteger size)\n{\n    _numofslots = size;\n    _strings = (SQString**)SQ_MALLOC(sizeof(SQString*)*_numofslots);\n    memset(_strings,0,sizeof(SQString*)*_numofslots);\n}\n\nSQString *SQStringTable::Add(const SQChar *news,SQInteger len)\n{\n    if(len<0)\n        len = (SQInteger)scstrlen(news);\n    SQHash newhash = ::_hashstr(news,len);\n    SQHash h = newhash&(_numofslots-1);\n    SQString *s;\n    for (s = _strings[h]; s; s = s->_next){\n        if(s->_len == len && (!memcmp(news,s->_val,sq_rsl(len))))\n            return s; //found\n    }\n\n    SQString *t = (SQString *)SQ_MALLOC(sq_rsl(len)+sizeof(SQString));\n    new (t) SQString;\n    t->_sharedstate = _sharedstate;\n    memcpy(t->_val,news,sq_rsl(len));\n    t->_val[len] = _SC('\\0');\n    t->_len = len;\n    t->_hash = newhash;\n    t->_next = _strings[h];\n    _strings[h] = t;\n    _slotused++;\n    if (_slotused > _numofslots)  /* too crowded? */\n        Resize(_numofslots*2);\n    return t;\n}\n\nvoid SQStringTable::Resize(SQInteger size)\n{\n    SQInteger oldsize=_numofslots;\n    SQString **oldtable=_strings;\n    AllocNodes(size);\n    for (SQInteger i=0; i<oldsize; i++){\n        SQString *p = oldtable[i];\n        while(p){\n            SQString *next = p->_next;\n            SQHash h = p->_hash&(_numofslots-1);\n            p->_next = _strings[h];\n            _strings[h] = p;\n            p = next;\n        }\n    }\n    SQ_FREE(oldtable,oldsize*sizeof(SQString*));\n}\n\nvoid SQStringTable::Remove(SQString *bs)\n{\n    SQString *s;\n    SQString *prev=NULL;\n    SQHash h = bs->_hash&(_numofslots - 1);\n\n    for (s = _strings[h]; s; ){\n        if(s == bs){\n            if(prev)\n                prev->_next = s->_next;\n            else\n                _strings[h] = s->_next;\n            _slotused--;\n            SQInteger slen = s->_len;\n            s->~SQString();\n            SQ_FREE(s,sizeof(SQString) + sq_rsl(slen));\n            return;\n        }\n        prev = s;\n        s = s->_next;\n    }\n    assert(0);//if this fail something is wrong\n}\n"
  },
  {
    "path": "extlibs/squirrel/squirrel/sqstate.h",
    "content": "/*  see copyright notice in squirrel.h */\n#ifndef _SQSTATE_H_\n#define _SQSTATE_H_\n\n#include \"squtils.h\"\n#include \"sqobject.h\"\nstruct SQString;\nstruct SQTable;\n//max number of character for a printed number\n#define NUMBER_MAX_CHAR 50\n\nstruct SQStringTable\n{\n    SQStringTable(SQSharedState*ss);\n    ~SQStringTable();\n    SQString *Add(const SQChar *,SQInteger len);\n    void Remove(SQString *);\nprivate:\n    void Resize(SQInteger size);\n    void AllocNodes(SQInteger size);\n    SQString **_strings;\n    SQUnsignedInteger _numofslots;\n    SQUnsignedInteger _slotused;\n    SQSharedState *_sharedstate;\n};\n\nstruct RefTable {\n    struct RefNode {\n        SQObjectPtr obj;\n        SQUnsignedInteger refs;\n        struct RefNode *next;\n    };\n    RefTable();\n    ~RefTable();\n    void AddRef(SQObject &obj);\n    SQBool Release(SQObject &obj);\n    SQUnsignedInteger GetRefCount(SQObject &obj);\n#ifndef NO_GARBAGE_COLLECTOR\n    void Mark(SQCollectable **chain);\n#endif\n    void Finalize();\nprivate:\n    RefNode *Get(SQObject &obj,SQHash &mainpos,RefNode **prev,bool add);\n    RefNode *Add(SQHash mainpos,SQObject &obj);\n    void Resize(SQUnsignedInteger size);\n    void AllocNodes(SQUnsignedInteger size);\n    SQUnsignedInteger _numofslots;\n    SQUnsignedInteger _slotused;\n    RefNode *_nodes;\n    RefNode *_freelist;\n    RefNode **_buckets;\n};\n\n#define ADD_STRING(ss,str,len) ss->_stringtable->Add(str,len)\n#define REMOVE_STRING(ss,bstr) ss->_stringtable->Remove(bstr)\n\nstruct SQObjectPtr;\n\nstruct SQSharedState\n{\n    SQSharedState();\n    ~SQSharedState();\n    void Init();\npublic:\n    SQChar* GetScratchPad(SQInteger size);\n    SQInteger GetMetaMethodIdxByName(const SQObjectPtr &name);\n#ifndef NO_GARBAGE_COLLECTOR\n    SQInteger CollectGarbage(SQVM *vm);\n    void RunMark(SQVM *vm,SQCollectable **tchain);\n    SQInteger ResurrectUnreachable(SQVM *vm);\n    static void MarkObject(SQObjectPtr &o,SQCollectable **chain);\n#endif\n    SQObjectPtrVec *_metamethods;\n    SQObjectPtr _metamethodsmap;\n    SQObjectPtrVec *_systemstrings;\n    SQObjectPtrVec *_types;\n    SQStringTable *_stringtable;\n    RefTable _refs_table;\n    SQObjectPtr _registry;\n    SQObjectPtr _consts;\n    SQObjectPtr _constructoridx;\n#ifndef NO_GARBAGE_COLLECTOR\n    SQCollectable *_gc_chain;\n#endif\n    SQObjectPtr _root_vm;\n    SQObjectPtr _table_default_delegate;\n    static const SQRegFunction _table_default_delegate_funcz[];\n    SQObjectPtr _array_default_delegate;\n    static const SQRegFunction _array_default_delegate_funcz[];\n    SQObjectPtr _string_default_delegate;\n    static const SQRegFunction _string_default_delegate_funcz[];\n    SQObjectPtr _number_default_delegate;\n    static const SQRegFunction _number_default_delegate_funcz[];\n    SQObjectPtr _generator_default_delegate;\n    static const SQRegFunction _generator_default_delegate_funcz[];\n    SQObjectPtr _closure_default_delegate;\n    static const SQRegFunction _closure_default_delegate_funcz[];\n    SQObjectPtr _thread_default_delegate;\n    static const SQRegFunction _thread_default_delegate_funcz[];\n    SQObjectPtr _class_default_delegate;\n    static const SQRegFunction _class_default_delegate_funcz[];\n    SQObjectPtr _instance_default_delegate;\n    static const SQRegFunction _instance_default_delegate_funcz[];\n    SQObjectPtr _weakref_default_delegate;\n    static const SQRegFunction _weakref_default_delegate_funcz[];\n\n    SQCOMPILERERROR _compilererrorhandler;\n    SQPRINTFUNCTION _printfunc;\n    SQPRINTFUNCTION _errorfunc;\n    bool _debuginfo;\n    bool _notifyallexceptions;\n    SQUserPointer _foreignptr;\n    SQRELEASEHOOK _releasehook;\nprivate:\n    SQChar *_scratchpad;\n    SQInteger _scratchpadsize;\n};\n\n#define _sp(s) (_sharedstate->GetScratchPad(s))\n#define _spval (_sharedstate->GetScratchPad(-1))\n\n#define _table_ddel     _table(_sharedstate->_table_default_delegate)\n#define _array_ddel     _table(_sharedstate->_array_default_delegate)\n#define _string_ddel    _table(_sharedstate->_string_default_delegate)\n#define _number_ddel    _table(_sharedstate->_number_default_delegate)\n#define _generator_ddel _table(_sharedstate->_generator_default_delegate)\n#define _closure_ddel   _table(_sharedstate->_closure_default_delegate)\n#define _thread_ddel    _table(_sharedstate->_thread_default_delegate)\n#define _class_ddel     _table(_sharedstate->_class_default_delegate)\n#define _instance_ddel  _table(_sharedstate->_instance_default_delegate)\n#define _weakref_ddel   _table(_sharedstate->_weakref_default_delegate)\n\nbool CompileTypemask(SQIntVec &res,const SQChar *typemask);\n\n\n#endif //_SQSTATE_H_\n"
  },
  {
    "path": "extlibs/squirrel/squirrel/sqstring.h",
    "content": "/*  see copyright notice in squirrel.h */\n#ifndef _SQSTRING_H_\n#define _SQSTRING_H_\n\ninline SQHash _hashstr (const SQChar *s, size_t l)\n{\n        SQHash h = (SQHash)l;  /* seed */\n        size_t step = (l>>5)|1;  /* if string is too long, don't hash all its chars */\n        for (; l>=step; l-=step)\n            h = h ^ ((h<<5)+(h>>2)+(unsigned short)*(s++));\n        return h;\n}\n\nstruct SQString : public SQRefCounted\n{\n    SQString(){}\n    ~SQString(){}\npublic:\n    static SQString *Create(SQSharedState *ss, const SQChar *, SQInteger len = -1 );\n    SQInteger Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval);\n    void Release();\n    SQSharedState *_sharedstate;\n    SQString *_next; //chain for the string table\n    SQInteger _len;\n    SQHash _hash;\n    SQChar _val[1];\n};\n\n\n\n#endif //_SQSTRING_H_\n"
  },
  {
    "path": "extlibs/squirrel/squirrel/sqtable.cpp",
    "content": "/*\nsee copyright notice in squirrel.h\n*/\n#include \"sqpcheader.h\"\n#include \"sqvm.h\"\n#include \"sqtable.h\"\n#include \"sqfuncproto.h\"\n#include \"sqclosure.h\"\n\nSQTable::SQTable(SQSharedState *ss,SQInteger nInitialSize)\n{\n    SQInteger pow2size=MINPOWER2;\n    while(nInitialSize>pow2size)pow2size=pow2size<<1;\n    AllocNodes(pow2size);\n    _usednodes = 0;\n    _delegate = NULL;\n    INIT_CHAIN();\n    ADD_TO_CHAIN(&_sharedstate->_gc_chain,this);\n}\n\nvoid SQTable::Remove(const SQObjectPtr &key)\n{\n\n    _HashNode *n = _Get(key, HashObj(key) & (_numofnodes - 1));\n    if (n) {\n        n->val.Null();\n        n->key.Null();\n        _usednodes--;\n        Rehash(false);\n    }\n}\n\nvoid SQTable::AllocNodes(SQInteger nSize)\n{\n    _HashNode *nodes=(_HashNode *)SQ_MALLOC(sizeof(_HashNode)*nSize);\n    for(SQInteger i=0;i<nSize;i++){\n        _HashNode &n = nodes[i];\n        new (&n) _HashNode;\n        n.next=NULL;\n    }\n    _numofnodes=nSize;\n    _nodes=nodes;\n    _firstfree=&_nodes[_numofnodes-1];\n}\n\nvoid SQTable::Rehash(bool force)\n{\n    SQInteger oldsize=_numofnodes;\n    //prevent problems with the integer division\n    if(oldsize<4)oldsize=4;\n    _HashNode *nold=_nodes;\n    SQInteger nelems=CountUsed();\n    if (nelems >= oldsize-oldsize/4)  /* using more than 3/4? */\n        AllocNodes(oldsize*2);\n    else if (nelems <= oldsize/4 &&  /* less than 1/4? */\n        oldsize > MINPOWER2)\n        AllocNodes(oldsize/2);\n    else if(force)\n        AllocNodes(oldsize);\n    else\n        return;\n    _usednodes = 0;\n    for (SQInteger i=0; i<oldsize; i++) {\n        _HashNode *old = nold+i;\n        if (sq_type(old->key) != OT_NULL)\n            NewSlot(old->key,old->val);\n    }\n    for(SQInteger k=0;k<oldsize;k++)\n        nold[k].~_HashNode();\n    SQ_FREE(nold,oldsize*sizeof(_HashNode));\n}\n\nSQTable *SQTable::Clone()\n{\n    SQTable *nt=Create(_opt_ss(this),_numofnodes);\n#ifdef _FAST_CLONE\n    _HashNode *basesrc = _nodes;\n    _HashNode *basedst = nt->_nodes;\n    _HashNode *src = _nodes;\n    _HashNode *dst = nt->_nodes;\n    SQInteger n = 0;\n    for(n = 0; n < _numofnodes; n++) {\n        dst->key = src->key;\n        dst->val = src->val;\n        if(src->next) {\n            assert(src->next > basesrc);\n            dst->next = basedst + (src->next - basesrc);\n            assert(dst != dst->next);\n        }\n        dst++;\n        src++;\n    }\n    assert(_firstfree > basesrc);\n    assert(_firstfree != NULL);\n    nt->_firstfree = basedst + (_firstfree - basesrc);\n    nt->_usednodes = _usednodes;\n#else\n    SQInteger ridx=0;\n    SQObjectPtr key,val;\n    while((ridx=Next(true,ridx,key,val))!=-1){\n        nt->NewSlot(key,val);\n    }\n#endif\n    nt->SetDelegate(_delegate);\n    return nt;\n}\n\nbool SQTable::Get(const SQObjectPtr &key,SQObjectPtr &val)\n{\n    if(sq_type(key) == OT_NULL)\n        return false;\n    _HashNode *n = _Get(key, HashObj(key) & (_numofnodes - 1));\n    if (n) {\n        val = _realval(n->val);\n        return true;\n    }\n    return false;\n}\nbool SQTable::NewSlot(const SQObjectPtr &key,const SQObjectPtr &val)\n{\n    assert(sq_type(key) != OT_NULL);\n    SQHash h = HashObj(key) & (_numofnodes - 1);\n    _HashNode *n = _Get(key, h);\n    if (n) {\n        n->val = val;\n        return false;\n    }\n    _HashNode *mp = &_nodes[h];\n    n = mp;\n\n\n    //key not found I'll insert it\n    //main pos is not free\n\n    if(sq_type(mp->key) != OT_NULL) {\n        n = _firstfree;  /* get a free place */\n        SQHash mph = HashObj(mp->key) & (_numofnodes - 1);\n        _HashNode *othern;  /* main position of colliding node */\n\n        if (mp > n && (othern = &_nodes[mph]) != mp){\n            /* yes; move colliding node into free position */\n            while (othern->next != mp){\n                assert(othern->next != NULL);\n                othern = othern->next;  /* find previous */\n            }\n            othern->next = n;  /* redo the chain with `n' in place of `mp' */\n            n->key = mp->key;\n            n->val = mp->val;/* copy colliding node into free pos. (mp->next also goes) */\n            n->next = mp->next;\n            mp->key.Null();\n            mp->val.Null();\n            mp->next = NULL;  /* now `mp' is free */\n        }\n        else{\n            /* new node will go into free position */\n            n->next = mp->next;  /* chain new position */\n            mp->next = n;\n            mp = n;\n        }\n    }\n    mp->key = key;\n\n    for (;;) {  /* correct `firstfree' */\n        if (sq_type(_firstfree->key) == OT_NULL && _firstfree->next == NULL) {\n            mp->val = val;\n            _usednodes++;\n            return true;  /* OK; table still has a free place */\n        }\n        else if (_firstfree == _nodes) break;  /* cannot decrement from here */\n        else (_firstfree)--;\n    }\n    Rehash(true);\n    return NewSlot(key, val);\n}\n\nSQInteger SQTable::Next(bool getweakrefs,const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval)\n{\n    SQInteger idx = (SQInteger)TranslateIndex(refpos);\n    while (idx < _numofnodes) {\n        if(sq_type(_nodes[idx].key) != OT_NULL) {\n            //first found\n            _HashNode &n = _nodes[idx];\n            outkey = n.key;\n            outval = getweakrefs?(SQObject)n.val:_realval(n.val);\n            //return idx for the next iteration\n            return ++idx;\n        }\n        ++idx;\n    }\n    //nothing to iterate anymore\n    return -1;\n}\n\n\nbool SQTable::Set(const SQObjectPtr &key, const SQObjectPtr &val)\n{\n    _HashNode *n = _Get(key, HashObj(key) & (_numofnodes - 1));\n    if (n) {\n        n->val = val;\n        return true;\n    }\n    return false;\n}\n\nvoid SQTable::_ClearNodes()\n{\n    for(SQInteger i = 0;i < _numofnodes; i++) { _HashNode &n = _nodes[i]; n.key.Null(); n.val.Null(); }\n}\n\nvoid SQTable::Finalize()\n{\n    _ClearNodes();\n    SetDelegate(NULL);\n}\n\nvoid SQTable::Clear()\n{\n    _ClearNodes();\n    _usednodes = 0;\n    Rehash(true);\n}\n"
  },
  {
    "path": "extlibs/squirrel/squirrel/sqtable.h",
    "content": "/*  see copyright notice in squirrel.h */\n#ifndef _SQTABLE_H_\n#define _SQTABLE_H_\n/*\n* The following code is based on Lua 4.0 (Copyright 1994-2002 Tecgraf, PUC-Rio.)\n* http://www.lua.org/copyright.html#4\n* http://www.lua.org/source/4.0.1/src_ltable.c.html\n*/\n\n#include \"sqstring.h\"\n\n\n#define hashptr(p)  ((SQHash)(((SQInteger)p) >> 3))\n\ninline SQHash HashObj(const SQObjectPtr &key)\n{\n    switch(sq_type(key)) {\n        case OT_STRING:     return _string(key)->_hash;\n        case OT_FLOAT:      return (SQHash)((SQInteger)_float(key));\n        case OT_BOOL: case OT_INTEGER:  return (SQHash)((SQInteger)_integer(key));\n        default:            return hashptr(key._unVal.pRefCounted);\n    }\n}\n\nstruct SQTable : public SQDelegable\n{\nprivate:\n    struct _HashNode\n    {\n        _HashNode() { next = NULL; }\n        SQObjectPtr val;\n        SQObjectPtr key;\n        _HashNode *next;\n    };\n    _HashNode *_firstfree;\n    _HashNode *_nodes;\n    SQInteger _numofnodes;\n    SQInteger _usednodes;\n\n///////////////////////////\n    void AllocNodes(SQInteger nSize);\n    void Rehash(bool force);\n    SQTable(SQSharedState *ss, SQInteger nInitialSize);\n    void _ClearNodes();\npublic:\n    static SQTable* Create(SQSharedState *ss,SQInteger nInitialSize)\n    {\n        SQTable *newtable = (SQTable*)SQ_MALLOC(sizeof(SQTable));\n        new (newtable) SQTable(ss, nInitialSize);\n        newtable->_delegate = NULL;\n        return newtable;\n    }\n    void Finalize();\n    SQTable *Clone();\n    ~SQTable()\n    {\n        SetDelegate(NULL);\n        REMOVE_FROM_CHAIN(&_sharedstate->_gc_chain, this);\n        for (SQInteger i = 0; i < _numofnodes; i++) _nodes[i].~_HashNode();\n        SQ_FREE(_nodes, _numofnodes * sizeof(_HashNode));\n    }\n#ifndef NO_GARBAGE_COLLECTOR\n    void Mark(SQCollectable **chain);\n    SQObjectType GetType() {return OT_TABLE;}\n#endif\n    inline _HashNode *_Get(const SQObjectPtr &key,SQHash hash)\n    {\n        _HashNode *n = &_nodes[hash];\n        do{\n            if(_rawval(n->key) == _rawval(key) && sq_type(n->key) == sq_type(key)){\n                return n;\n            }\n        }while((n = n->next));\n        return NULL;\n    }\n    //for compiler use\n    inline bool GetStr(const SQChar* key,SQInteger keylen,SQObjectPtr &val)\n    {\n        SQHash hash = _hashstr(key,keylen);\n        _HashNode *n = &_nodes[hash & (_numofnodes - 1)];\n        _HashNode *res = NULL;\n        do{\n            if(sq_type(n->key) == OT_STRING && (scstrcmp(_stringval(n->key),key) == 0)){\n                res = n;\n                break;\n            }\n        }while((n = n->next));\n        if (res) {\n            val = _realval(res->val);\n            return true;\n        }\n        return false;\n    }\n    bool Get(const SQObjectPtr &key,SQObjectPtr &val);\n    void Remove(const SQObjectPtr &key);\n    bool Set(const SQObjectPtr &key, const SQObjectPtr &val);\n    //returns true if a new slot has been created false if it was already present\n    bool NewSlot(const SQObjectPtr &key,const SQObjectPtr &val);\n    SQInteger Next(bool getweakrefs,const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval);\n\n    SQInteger CountUsed(){ return _usednodes;}\n    void Clear();\n    void Release()\n    {\n        sq_delete(this, SQTable);\n    }\n\n};\n\n#endif //_SQTABLE_H_\n"
  },
  {
    "path": "extlibs/squirrel/squirrel/squirrel.dsp",
    "content": "# Microsoft Developer Studio Project File - Name=\"squirrel\" - Package Owner=<4>\n# Microsoft Developer Studio Generated Build File, Format Version 6.00\n# ** DO NOT EDIT **\n\n# TARGTYPE \"Win32 (x86) Static Library\" 0x0104\n\nCFG=squirrel - Win32 Debug\n!MESSAGE This is not a valid makefile. To build this project using NMAKE,\n!MESSAGE use the Export Makefile command and run\n!MESSAGE \n!MESSAGE NMAKE /f \"squirrel.mak\".\n!MESSAGE \n!MESSAGE You can specify a configuration when running NMAKE\n!MESSAGE by defining the macro CFG on the command line. For example:\n!MESSAGE \n!MESSAGE NMAKE /f \"squirrel.mak\" CFG=\"squirrel - Win32 Debug\"\n!MESSAGE \n!MESSAGE Possible choices for configuration are:\n!MESSAGE \n!MESSAGE \"squirrel - Win32 Release\" (based on \"Win32 (x86) Static Library\")\n!MESSAGE \"squirrel - Win32 Debug\" (based on \"Win32 (x86) Static Library\")\n!MESSAGE \n\n# Begin Project\n# PROP AllowPerConfigDependencies 0\n# PROP Scc_LocalPath \"..\"\nCPP=cl.exe\nRSC=rc.exe\n\n!IF  \"$(CFG)\" == \"squirrel - Win32 Release\"\n\n# PROP BASE Use_MFC 0\n# PROP BASE Use_Debug_Libraries 0\n# PROP BASE Output_Dir \"Release\"\n# PROP BASE Intermediate_Dir \"Release\"\n# PROP BASE Target_Dir \"\"\n# PROP Use_MFC 0\n# PROP Use_Debug_Libraries 0\n# PROP Output_Dir \"Release\"\n# PROP Intermediate_Dir \"Release\"\n# PROP Target_Dir \"\"\n# ADD BASE CPP /nologo /W3 /GX /O2 /D \"WIN32\" /D \"NDEBUG\" /D \"_MBCS\" /D \"_LIB\" /YX /FD /c\n# ADD CPP /nologo /W3 /GX /O2 /I \"..\\include\" /D \"WIN32\" /D \"NDEBUG\" /D \"_MBCS\" /D \"_LIB\" /D \"GARBAGE_COLLECTOR\" /YX /FD /c\n# ADD BASE RSC /l 0x410 /d \"NDEBUG\"\n# ADD RSC /l 0x410 /d \"NDEBUG\"\nBSC32=bscmake.exe\n# ADD BASE BSC32 /nologo\n# ADD BSC32 /nologo\nLIB32=link.exe -lib\n# ADD BASE LIB32 /nologo\n# ADD LIB32 /nologo /out:\"..\\lib\\squirrel.lib\"\n\n!ELSEIF  \"$(CFG)\" == \"squirrel - Win32 Debug\"\n\n# PROP BASE Use_MFC 0\n# PROP BASE Use_Debug_Libraries 1\n# PROP BASE Output_Dir \"Debug\"\n# PROP BASE Intermediate_Dir \"Debug\"\n# PROP BASE Target_Dir \"\"\n# PROP Use_MFC 0\n# PROP Use_Debug_Libraries 1\n# PROP Output_Dir \"Debug\"\n# PROP Intermediate_Dir \"Debug\"\n# PROP Target_Dir \"\"\n# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D \"WIN32\" /D \"_DEBUG\" /D \"_MBCS\" /D \"_LIB\" /YX /FD /GZ /c\n# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I \"..\\include\" /D \"WIN32\" /D \"_DEBUG\" /D \"_MBCS\" /D \"_LIB\" /YX /FD /GZ /c\n# ADD BASE RSC /l 0x410 /d \"_DEBUG\"\n# ADD RSC /l 0x410 /d \"_DEBUG\"\nBSC32=bscmake.exe\n# ADD BASE BSC32 /nologo\n# ADD BSC32 /nologo\nLIB32=link.exe -lib\n# ADD BASE LIB32 /nologo\n# ADD LIB32 /nologo /out:\"..\\lib\\squirrel.lib\"\n\n!ENDIF \n\n# Begin Target\n\n# Name \"squirrel - Win32 Release\"\n# Name \"squirrel - Win32 Debug\"\n# Begin Group \"Source Files\"\n\n# PROP Default_Filter \"cpp;c;cxx;rc;def;r;odl;idl;hpj;bat\"\n# Begin Source File\n\nSOURCE=.\\sqapi.cpp\n\n!IF  \"$(CFG)\" == \"squirrel - Win32 Release\"\n\n!ELSEIF  \"$(CFG)\" == \"squirrel - Win32 Debug\"\n\n# ADD CPP /YX\"stdafx.h\"\n\n!ENDIF \n\n# End Source File\n# Begin Source File\n\nSOURCE=.\\sqbaselib.cpp\n\n!IF  \"$(CFG)\" == \"squirrel - Win32 Release\"\n\n!ELSEIF  \"$(CFG)\" == \"squirrel - Win32 Debug\"\n\n# ADD CPP /YX\"stdafx.h\"\n\n!ENDIF \n\n# End Source File\n# Begin Source File\n\nSOURCE=.\\sqcompiler.cpp\n\n!IF  \"$(CFG)\" == \"squirrel - Win32 Release\"\n\n!ELSEIF  \"$(CFG)\" == \"squirrel - Win32 Debug\"\n\n# ADD CPP /YX\"stdafx.h\"\n\n!ENDIF \n\n# End Source File\n# Begin Source File\n\nSOURCE=.\\sqdebug.cpp\n\n!IF  \"$(CFG)\" == \"squirrel - Win32 Release\"\n\n!ELSEIF  \"$(CFG)\" == \"squirrel - Win32 Debug\"\n\n# ADD CPP /YX\"stdafx.h\"\n\n!ENDIF \n\n# End Source File\n# Begin Source File\n\nSOURCE=.\\sqfuncstate.cpp\n\n!IF  \"$(CFG)\" == \"squirrel - Win32 Release\"\n\n!ELSEIF  \"$(CFG)\" == \"squirrel - Win32 Debug\"\n\n# ADD CPP /YX\"stdafx.h\"\n\n!ENDIF \n\n# End Source File\n# Begin Source File\n\nSOURCE=.\\sqlexer.cpp\n\n!IF  \"$(CFG)\" == \"squirrel - Win32 Release\"\n\n!ELSEIF  \"$(CFG)\" == \"squirrel - Win32 Debug\"\n\n# ADD CPP /YX\"stdafx.h\"\n\n!ENDIF \n\n# End Source File\n# Begin Source File\n\nSOURCE=.\\sqmem.cpp\n# End Source File\n# Begin Source File\n\nSOURCE=.\\sqobject.cpp\n\n!IF  \"$(CFG)\" == \"squirrel - Win32 Release\"\n\n!ELSEIF  \"$(CFG)\" == \"squirrel - Win32 Debug\"\n\n# ADD CPP /YX\"stdafx.h\"\n\n!ENDIF \n\n# End Source File\n# Begin Source File\n\nSOURCE=.\\sqstate.cpp\n\n!IF  \"$(CFG)\" == \"squirrel - Win32 Release\"\n\n!ELSEIF  \"$(CFG)\" == \"squirrel - Win32 Debug\"\n\n# ADD CPP /YX\"stdafx.h\"\n\n!ENDIF \n\n# End Source File\n# Begin Source File\n\nSOURCE=.\\sqtable.cpp\n\n!IF  \"$(CFG)\" == \"squirrel - Win32 Release\"\n\n!ELSEIF  \"$(CFG)\" == \"squirrel - Win32 Debug\"\n\n# ADD CPP /YX\"stdafx.h\"\n\n!ENDIF \n\n# End Source File\n# Begin Source File\n\nSOURCE=.\\sqclass.cpp\n\n!IF  \"$(CFG)\" == \"squirrel - Win32 Release\"\n\n!ELSEIF  \"$(CFG)\" == \"squirrel - Win32 Debug\"\n\n# ADD CPP /YX\"stdafx.h\"\n\n!ENDIF \n\n# End Source File\n# Begin Source File\n\nSOURCE=.\\sqvm.cpp\n\n!IF  \"$(CFG)\" == \"squirrel - Win32 Release\"\n\n!ELSEIF  \"$(CFG)\" == \"squirrel - Win32 Debug\"\n\n# ADD CPP /YX\"stdafx.h\"\n\n!ENDIF \n\n# End Source File\n# End Group\n# Begin Group \"Header Files\"\n\n# PROP Default_Filter \"h;hpp;hxx;hm;inl\"\n# Begin Source File\n\nSOURCE=.\\sqarray.h\n# End Source File\n# Begin Source File\n\nSOURCE=.\\sqclosure.h\n# End Source File\n# Begin Source File\n\nSOURCE=.\\sqcompiler.h\n# End Source File\n# Begin Source File\n\nSOURCE=.\\sqfuncproto.h\n# End Source File\n# Begin Source File\n\nSOURCE=.\\sqfuncstate.h\n# End Source File\n# Begin Source File\n\nSOURCE=.\\sqlexer.h\n# End Source File\n# Begin Source File\n\nSOURCE=.\\sqobject.h\n# End Source File\n# Begin Source File\n\nSOURCE=.\\sqopcodes.h\n# End Source File\n# Begin Source File\n\nSOURCE=.\\sqpcheader.h\n# End Source File\n# Begin Source File\n\nSOURCE=.\\sqstate.h\n# End Source File\n# Begin Source File\n\nSOURCE=.\\sqstring.h\n# End Source File\n# Begin Source File\n\nSOURCE=.\\sqtable.h\n# End Source File\n# Begin Source File\n\nSOURCE=.\\squserdata.h\n# End Source File\n# Begin Source File\n\nSOURCE=.\\squtils.h\n# End Source File\n# Begin Source File\n\nSOURCE=.\\sqclass.h\n# End Source File\n# Begin Source File\n\nSOURCE=.\\sqvm.h\n# End Source File\n# End Group\n# End Target\n# End Project\n"
  },
  {
    "path": "extlibs/squirrel/squirrel/squserdata.h",
    "content": "/*  see copyright notice in squirrel.h */\n#ifndef _SQUSERDATA_H_\n#define _SQUSERDATA_H_\n\nstruct SQUserData : SQDelegable\n{\n    SQUserData(SQSharedState *ss){ _delegate = 0; _hook = NULL; INIT_CHAIN(); ADD_TO_CHAIN(&_ss(this)->_gc_chain, this); }\n    ~SQUserData()\n    {\n        REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain, this);\n        SetDelegate(NULL);\n    }\n    static SQUserData* Create(SQSharedState *ss, SQInteger size)\n    {\n        SQUserData* ud = (SQUserData*)SQ_MALLOC(sq_aligning(sizeof(SQUserData))+size);\n        new (ud) SQUserData(ss);\n        ud->_size = size;\n        ud->_typetag = 0;\n        return ud;\n    }\n#ifndef NO_GARBAGE_COLLECTOR\n    void Mark(SQCollectable **chain);\n    void Finalize(){SetDelegate(NULL);}\n    SQObjectType GetType(){ return OT_USERDATA;}\n#endif\n    void Release() {\n        if (_hook) _hook((SQUserPointer)sq_aligning(this + 1),_size);\n        SQInteger tsize = _size;\n        this->~SQUserData();\n        SQ_FREE(this, sq_aligning(sizeof(SQUserData)) + tsize);\n    }\n\n\n    SQInteger _size;\n    SQRELEASEHOOK _hook;\n    SQUserPointer _typetag;\n    //SQChar _val[1];\n};\n\n#endif //_SQUSERDATA_H_\n"
  },
  {
    "path": "extlibs/squirrel/squirrel/squtils.h",
    "content": "/*  see copyright notice in squirrel.h */\n#ifndef _SQUTILS_H_\n#define _SQUTILS_H_\n\nvoid *sq_vm_malloc(SQUnsignedInteger size);\nvoid *sq_vm_realloc(void *p,SQUnsignedInteger oldsize,SQUnsignedInteger size);\nvoid sq_vm_free(void *p,SQUnsignedInteger size);\n\n#define sq_new(__ptr,__type) {__ptr=(__type *)sq_vm_malloc(sizeof(__type));new (__ptr) __type;}\n#define sq_delete(__ptr,__type) {__ptr->~__type();sq_vm_free(__ptr,sizeof(__type));}\n#define SQ_MALLOC(__size) sq_vm_malloc((__size));\n#define SQ_FREE(__ptr,__size) sq_vm_free((__ptr),(__size));\n#define SQ_REALLOC(__ptr,__oldsize,__size) sq_vm_realloc((__ptr),(__oldsize),(__size));\n\n#define sq_aligning(v) (((size_t)(v) + (SQ_ALIGNMENT-1)) & (~(SQ_ALIGNMENT-1)))\n\n//sqvector mini vector class, supports objects by value\ntemplate<typename T> class sqvector\n{\npublic:\n    sqvector()\n    {\n        _vals = NULL;\n        _size = 0;\n        _allocated = 0;\n    }\n    sqvector(const sqvector<T>& v)\n    {\n        copy(v);\n    }\n    void copy(const sqvector<T>& v)\n    {\n        if(_size) {\n            resize(0); //destroys all previous stuff\n        }\n        //resize(v._size);\n        if(v._size > _allocated) {\n            _realloc(v._size);\n        }\n        for(SQUnsignedInteger i = 0; i < v._size; i++) {\n            new ((void *)&_vals[i]) T(v._vals[i]);\n        }\n        _size = v._size;\n    }\n    ~sqvector()\n    {\n        if(_allocated) {\n            for(SQUnsignedInteger i = 0; i < _size; i++)\n                _vals[i].~T();\n            SQ_FREE(_vals, (_allocated * sizeof(T)));\n        }\n    }\n    void reserve(SQUnsignedInteger newsize) { _realloc(newsize); }\n    void resize(SQUnsignedInteger newsize, const T& fill = T())\n    {\n        if(newsize > _allocated)\n            _realloc(newsize);\n        if(newsize > _size) {\n            while(_size < newsize) {\n                new ((void *)&_vals[_size]) T(fill);\n                _size++;\n            }\n        }\n        else{\n            for(SQUnsignedInteger i = newsize; i < _size; i++) {\n                _vals[i].~T();\n            }\n            _size = newsize;\n        }\n    }\n    void shrinktofit() { if(_size > 4) { _realloc(_size); } }\n    T& top() const { return _vals[_size - 1]; }\n    inline SQUnsignedInteger size() const { return _size; }\n    bool empty() const { return (_size <= 0); }\n    inline T &push_back(const T& val = T())\n    {\n        if(_allocated <= _size)\n            _realloc(_size * 2);\n        return *(new ((void *)&_vals[_size++]) T(val));\n    }\n    inline void pop_back()\n    {\n        _size--; _vals[_size].~T();\n    }\n    void insert(SQUnsignedInteger idx, const T& val)\n    {\n        resize(_size + 1);\n        for(SQUnsignedInteger i = _size - 1; i > idx; i--) {\n            _vals[i] = _vals[i - 1];\n        }\n        _vals[idx] = val;\n    }\n    void remove(SQUnsignedInteger idx)\n    {\n        _vals[idx].~T();\n        if(idx < (_size - 1)) {\n            memmove(&_vals[idx], &_vals[idx+1], sizeof(T) * (_size - idx - 1));\n        }\n        _size--;\n    }\n    SQUnsignedInteger capacity() { return _allocated; }\n    inline T &back() const { return _vals[_size - 1]; }\n    inline T& operator[](SQUnsignedInteger pos) const{ return _vals[pos]; }\n    T* _vals;\nprivate:\n    void _realloc(SQUnsignedInteger newsize)\n    {\n        newsize = (newsize > 0)?newsize:4;\n        _vals = (T*)SQ_REALLOC(_vals, _allocated * sizeof(T), newsize * sizeof(T));\n        _allocated = newsize;\n    }\n    SQUnsignedInteger _size;\n    SQUnsignedInteger _allocated;\n};\n\n#endif //_SQUTILS_H_\n"
  },
  {
    "path": "extlibs/squirrel/squirrel/sqvm.cpp",
    "content": "/*\n    see copyright notice in squirrel.h\n*/\n#include \"sqpcheader.h\"\n#include <math.h>\n#include <sstream>\n#include <stdlib.h>\n#include <stdexcept>\n#include \"sqopcodes.h\"\n#include \"sqvm.h\"\n#include \"sqfuncproto.h\"\n#include \"sqclosure.h\"\n#include \"sqstring.h\"\n#include \"sqtable.h\"\n#include \"squserdata.h\"\n#include \"sqarray.h\"\n#include \"sqclass.h\"\n\n#define TOP() (_stack._vals[_top-1])\n#define TARGET _stack._vals[_stackbase+arg0]\n#define STK(a) _stack._vals[_stackbase+(a)]\n\nbool SQVM::BW_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2)\n{\n    SQInteger res;\n    if((sq_type(o1)| sq_type(o2)) == OT_INTEGER)\n    {\n        SQInteger i1 = _integer(o1), i2 = _integer(o2);\n        switch(op) {\n            case BW_AND:    res = i1 & i2; break;\n            case BW_OR:     res = i1 | i2; break;\n            case BW_XOR:    res = i1 ^ i2; break;\n            case BW_SHIFTL: res = i1 << i2; break;\n            case BW_SHIFTR: res = i1 >> i2; break;\n            case BW_USHIFTR:res = (SQInteger)(*((SQUnsignedInteger*)&i1) >> i2); break;\n            default: { Raise_Error(_SC(\"internal vm error bitwise op failed\")); return false; }\n        }\n    }\n    else { Raise_Error(_SC(\"bitwise op between '%s' and '%s'\"),GetTypeName(o1),GetTypeName(o2)); return false;}\n    trg = res;\n    return true;\n}\n\n#define _ARITH_(op,trg,o1,o2) \\\n{ \\\n    SQInteger tmask = sq_type(o1)|sq_type(o2); \\\n    switch(tmask) { \\\n        case OT_INTEGER: trg = _integer(o1) op _integer(o2);break; \\\n        case (OT_FLOAT|OT_INTEGER): \\\n        case (OT_FLOAT): trg = tofloat(o1) op tofloat(o2); break;\\\n        default: _GUARD(ARITH_OP((#op)[0],trg,o1,o2)); break;\\\n    } \\\n}\n\n#define _ARITH_NOZERO(op,trg,o1,o2,err) \\\n{ \\\n    SQInteger tmask = sq_type(o1)|sq_type(o2); \\\n    switch(tmask) { \\\n        case OT_INTEGER: { SQInteger i2 = _integer(o2); if(i2 == 0) { Raise_Error(err); SQ_THROW(); } trg = _integer(o1) op i2; } break;\\\n        case (OT_FLOAT|OT_INTEGER): \\\n        case (OT_FLOAT): trg = tofloat(o1) op tofloat(o2); break;\\\n        default: _GUARD(ARITH_OP((#op)[0],trg,o1,o2)); break;\\\n    } \\\n}\n\nbool SQVM::ARITH_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2)\n{\n    SQInteger tmask = sq_type(o1)| sq_type(o2);\n    switch(tmask) {\n        case OT_INTEGER:{\n            SQInteger res, i1 = _integer(o1), i2 = _integer(o2);\n            switch(op) {\n            case '+': res = i1 + i2; break;\n            case '-': res = i1 - i2; break;\n            case '/': if (i2 == 0) { Raise_Error(_SC(\"division by zero\")); return false; }\n                    else if (i2 == -1 && i1 == INT_MIN) { Raise_Error(_SC(\"integer overflow\")); return false; }\n                    res = i1 / i2;\n                    break;\n            case '*': res = i1 * i2; break;\n            case '%': if (i2 == 0) { Raise_Error(_SC(\"modulo by zero\")); return false; }\n                    else if (i2 == -1 && i1 == INT_MIN) { res = 0; break; }\n                    res = i1 % i2;\n                    break;\n            default: res = 0xDEADBEEF;\n            }\n            trg = res; }\n            break;\n        case (OT_FLOAT|OT_INTEGER):\n        case (OT_FLOAT):{\n            SQFloat res, f1 = tofloat(o1), f2 = tofloat(o2);\n            switch(op) {\n            case '+': res = f1 + f2; break;\n            case '-': res = f1 - f2; break;\n            case '/': res = f1 / f2; break;\n            case '*': res = f1 * f2; break;\n            case '%': res = SQFloat(fmod((double)f1,(double)f2)); break;\n            default: res = 0x0f;\n            }\n            trg = res; }\n            break;\n        default:\n            if(op == '+' && (tmask & _RT_STRING)){\n                if(!StringCat(o1, o2, trg)) return false;\n            }\n            else if(!ArithMetaMethod(op,o1,o2,trg)) {\n                return false;\n            }\n    }\n    return true;\n}\n\nSQVM::SQVM(SQSharedState *ss)\n{\n    _sharedstate=ss;\n    _suspended = SQFalse;\n    _suspended_target = -1;\n    _suspended_root = SQFalse;\n    _suspended_traps = -1;\n    _foreignptr = NULL;\n    _nnativecalls = 0;\n    _nmetamethodscall = 0;\n    _lasterror.Null();\n    _errorhandler.Null();\n    _debughook = false;\n    _debughook_native = NULL;\n    _debughook_closure.Null();\n    _openouters = NULL;\n    ci = NULL;\n    _releasehook = NULL;\n    INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this);\n}\n\nvoid SQVM::Finalize()\n{\n    if(_releasehook) { _releasehook(_foreignptr,0); _releasehook = NULL; }\n    if(_openouters) CloseOuters(&_stack._vals[0]);\n    _roottable.Null();\n    _lasterror.Null();\n    _errorhandler.Null();\n    _debughook = false;\n    _debughook_native = NULL;\n    _debughook_closure.Null();\n    temp_reg.Null();\n    _callstackdata.resize(0);\n    SQInteger size=_stack.size();\n    for(SQInteger i=0;i<size;i++)\n        _stack[i].Null();\n}\n\nSQVM::~SQVM()\n{\n    Finalize();\n    REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this);\n}\n\nbool SQVM::ArithMetaMethod(SQInteger op,const SQObjectPtr &o1,const SQObjectPtr &o2,SQObjectPtr &dest)\n{\n    SQMetaMethod mm;\n    switch(op){\n        case _SC('+'): mm=MT_ADD; break;\n        case _SC('-'): mm=MT_SUB; break;\n        case _SC('/'): mm=MT_DIV; break;\n        case _SC('*'): mm=MT_MUL; break;\n        case _SC('%'): mm=MT_MODULO; break;\n        default: mm = MT_ADD; assert(0); break; //shutup compiler\n    }\n    if(is_delegable(o1) && _delegable(o1)->_delegate) {\n\n        SQObjectPtr closure;\n        if(_delegable(o1)->GetMetaMethod(this, mm, closure)) {\n            Push(o1);Push(o2);\n            return CallMetaMethod(closure,mm,2,dest);\n        }\n    }\n    Raise_Error(_SC(\"arith op %c on between '%s' and '%s'\"),op,GetTypeName(o1),GetTypeName(o2));\n    return false;\n}\n\nbool SQVM::NEG_OP(SQObjectPtr &trg,const SQObjectPtr &o)\n{\n\n    switch(sq_type(o)) {\n    case OT_INTEGER:\n        trg = -_integer(o);\n        return true;\n    case OT_FLOAT:\n        trg = -_float(o);\n        return true;\n    case OT_TABLE:\n    case OT_USERDATA:\n    case OT_INSTANCE:\n        if(_delegable(o)->_delegate) {\n            SQObjectPtr closure;\n            if(_delegable(o)->GetMetaMethod(this, MT_UNM, closure)) {\n                Push(o);\n                if(!CallMetaMethod(closure, MT_UNM, 1, temp_reg)) return false;\n                _Swap(trg,temp_reg);\n                return true;\n\n            }\n        }\n    default:break; //shutup compiler\n    }\n    Raise_Error(_SC(\"attempt to negate a %s\"), GetTypeName(o));\n    return false;\n}\n\n#define _RET_SUCCEED(exp) { result = (exp); return true; }\nbool SQVM::ObjCmp(const SQObjectPtr &o1,const SQObjectPtr &o2,SQInteger &result)\n{\n    SQObjectType t1 = sq_type(o1), t2 = sq_type(o2);\n    if(t1 == t2) {\n        if(_rawval(o1) == _rawval(o2))_RET_SUCCEED(0);\n        SQObjectPtr res;\n        switch(t1){\n        case OT_STRING:\n            _RET_SUCCEED(scstrcmp(_stringval(o1),_stringval(o2)));\n        case OT_INTEGER:\n            _RET_SUCCEED((_integer(o1)<_integer(o2))?-1:1);\n        case OT_FLOAT:\n            _RET_SUCCEED((_float(o1)<_float(o2))?-1:1);\n        case OT_TABLE:\n        case OT_USERDATA:\n        case OT_INSTANCE:\n            if(_delegable(o1)->_delegate) {\n                SQObjectPtr closure;\n                if(_delegable(o1)->GetMetaMethod(this, MT_CMP, closure)) {\n                    Push(o1);Push(o2);\n                    if(CallMetaMethod(closure,MT_CMP,2,res)) {\n                        if(sq_type(res) != OT_INTEGER) {\n                            Raise_Error(_SC(\"_cmp must return an integer\"));\n                            return false;\n                        }\n                        _RET_SUCCEED(_integer(res))\n                    }\n                    return false;\n                }\n            }\n            //continues through (no break needed)\n        default:\n            _RET_SUCCEED( _userpointer(o1) < _userpointer(o2)?-1:1 );\n        }\n        assert(0);\n        //if(type(res)!=OT_INTEGER) { Raise_CompareError(o1,o2); return false; }\n        //  _RET_SUCCEED(_integer(res));\n\n    }\n    else{\n        if(sq_isnumeric(o1) && sq_isnumeric(o2)){\n            if((t1==OT_INTEGER) && (t2==OT_FLOAT)) {\n                if( _integer(o1)==_float(o2) ) { _RET_SUCCEED(0); }\n                else if( _integer(o1)<_float(o2) ) { _RET_SUCCEED(-1); }\n                _RET_SUCCEED(1);\n            }\n            else{\n                if( _float(o1)==_integer(o2) ) { _RET_SUCCEED(0); }\n                else if( _float(o1)<_integer(o2) ) { _RET_SUCCEED(-1); }\n                _RET_SUCCEED(1);\n            }\n        }\n        else if(t1==OT_NULL) {_RET_SUCCEED(-1);}\n        else if(t2==OT_NULL) {_RET_SUCCEED(1);}\n        else { Raise_CompareError(o1,o2); return false; }\n\n    }\n    assert(0);\n    _RET_SUCCEED(0); //cannot happen\n}\n\nbool SQVM::CMP_OP(CmpOP op, const SQObjectPtr &o1,const SQObjectPtr &o2,SQObjectPtr &res)\n{\n    SQInteger r;\n    if(ObjCmp(o1,o2,r)) {\n        switch(op) {\n            case CMP_G: res = (r > 0); return true;\n            case CMP_GE: res = (r >= 0); return true;\n            case CMP_L: res = (r < 0); return true;\n            case CMP_LE: res = (r <= 0); return true;\n            case CMP_3W: res = r; return true;\n        }\n        assert(0);\n    }\n    return false;\n}\n\nbool SQVM::ToString(const SQObjectPtr &o,SQObjectPtr &res)\n{\n    switch(sq_type(o)) {\n    case OT_STRING:\n        res = o;\n        return true;\n    case OT_FLOAT:\n        scsprintf(_sp(sq_rsl(NUMBER_MAX_CHAR+1)),sq_rsl(NUMBER_MAX_CHAR),_SC(\"%g\"),_float(o));\n        break;\n    case OT_INTEGER:\n        scsprintf(_sp(sq_rsl(NUMBER_MAX_CHAR+1)),sq_rsl(NUMBER_MAX_CHAR),_PRINT_INT_FMT,_integer(o));\n        break;\n    case OT_BOOL:\n        scsprintf(_sp(sq_rsl(6)),sq_rsl(6),_integer(o)?_SC(\"true\"):_SC(\"false\"));\n        break;\n    case OT_TABLE:\n    case OT_USERDATA:\n    case OT_INSTANCE:\n        if(_delegable(o)->_delegate) {\n            SQObjectPtr closure;\n            if(_delegable(o)->GetMetaMethod(this, MT_TOSTRING, closure)) {\n                Push(o);\n                if(CallMetaMethod(closure,MT_TOSTRING,1,res)) {\n                    if(sq_type(res) == OT_STRING)\n                        return true;\n                }\n                else {\n                    return false;\n                }\n            }\n        }\n    default:\n        scsprintf(_sp(sq_rsl((sizeof(void*)*2)+NUMBER_MAX_CHAR)),sq_rsl((sizeof(void*)*2)+NUMBER_MAX_CHAR),_SC(\"(%s : 0x%p)\"),GetTypeName(o),(void*)_rawval(o));\n    }\n    res = SQString::Create(_ss(this),_spval);\n    return true;\n}\n\n\nbool SQVM::StringCat(const SQObjectPtr &str,const SQObjectPtr &obj,SQObjectPtr &dest)\n{\n    SQObjectPtr a, b;\n    if(!ToString(str, a)) return false;\n    if(!ToString(obj, b)) return false;\n    SQInteger l = _string(a)->_len , ol = _string(b)->_len;\n    SQChar *s = _sp(sq_rsl(l + ol + 1));\n    memcpy(s, _stringval(a), sq_rsl(l));\n    memcpy(s + l, _stringval(b), sq_rsl(ol));\n    dest = SQString::Create(_ss(this), _spval, l + ol);\n    return true;\n}\n\nbool SQVM::TypeOf(const SQObjectPtr &obj1,SQObjectPtr &dest)\n{\n    if(is_delegable(obj1) && _delegable(obj1)->_delegate) {\n        SQObjectPtr closure;\n        if(_delegable(obj1)->GetMetaMethod(this, MT_TYPEOF, closure)) {\n            Push(obj1);\n            return CallMetaMethod(closure,MT_TYPEOF,1,dest);\n        }\n    }\n    dest = SQString::Create(_ss(this),GetTypeName(obj1));\n    return true;\n}\n\nbool SQVM::Init(SQVM *friendvm, SQInteger stacksize)\n{\n    _stack.resize(stacksize);\n    _alloccallsstacksize = 4;\n    _callstackdata.resize(_alloccallsstacksize);\n    _callsstacksize = 0;\n    _callsstack = &_callstackdata[0];\n    _stackbase = 0;\n    _top = 0;\n    if(!friendvm) {\n        _roottable = SQTable::Create(_ss(this), 0);\n        sq_base_register(this);\n    }\n    else {\n        _roottable = friendvm->_roottable;\n        _errorhandler = friendvm->_errorhandler;\n        _debughook = friendvm->_debughook;\n        _debughook_native = friendvm->_debughook_native;\n        _debughook_closure = friendvm->_debughook_closure;\n    }\n\n\n    return true;\n}\n\n\nbool SQVM::StartCall(SQClosure *closure,SQInteger target,SQInteger args,SQInteger stackbase,bool tailcall)\n{\n    SQFunctionProto *func = closure->_function;\n\n    SQInteger paramssize = func->_nparameters;\n    const SQInteger newtop = stackbase + func->_stacksize;\n    SQInteger nargs = args;\n    if(func->_varparams)\n    {\n        paramssize--;\n        if (nargs < paramssize) {\n            Raise_Error(_SC(\"wrong number of parameters (%d passed, at least %d required)\"),\n              (int)nargs, (int)paramssize);\n            return false;\n        }\n\n        //dumpstack(stackbase);\n        SQInteger nvargs = nargs - paramssize;\n        SQArray *arr = SQArray::Create(_ss(this),nvargs);\n        SQInteger pbase = stackbase+paramssize;\n        for(SQInteger n = 0; n < nvargs; n++) {\n            arr->_values[n] = _stack._vals[pbase];\n            _stack._vals[pbase].Null();\n            pbase++;\n\n        }\n        _stack._vals[stackbase+paramssize] = arr;\n        //dumpstack(stackbase);\n    }\n    else if (paramssize != nargs) {\n        SQInteger ndef = func->_ndefaultparams;\n        SQInteger diff;\n        if(ndef && nargs < paramssize && (diff = paramssize - nargs) <= ndef) {\n            for(SQInteger n = ndef - diff; n < ndef; n++) {\n                _stack._vals[stackbase + (nargs++)] = closure->_defaultparams[n];\n            }\n        }\n        else {\n            Raise_Error(_SC(\"wrong number of parameters (%d passed, %d required)\"),\n              (int)nargs, (int)paramssize);\n            return false;\n        }\n    }\n\n    if(closure->_env) {\n        _stack._vals[stackbase] = closure->_env->_obj;\n    }\n\n    if(!EnterFrame(stackbase, newtop, tailcall)) return false;\n\n    ci->_closure  = closure;\n    ci->_literals = func->_literals;\n    ci->_ip       = func->_instructions;\n    ci->_target   = (SQInt32)target;\n\n    if (_debughook) {\n        CallDebugHook(_SC('c'));\n    }\n\n    if (closure->_function->_bgenerator) {\n        SQFunctionProto *f = closure->_function;\n        SQGenerator *gen = SQGenerator::Create(_ss(this), closure);\n        if(!gen->Yield(this,f->_stacksize))\n            return false;\n        SQObjectPtr temp;\n        Return(1, target, temp);\n        STK(target) = gen;\n    }\n\n\n    return true;\n}\n\nbool SQVM::Return(SQInteger _arg0, SQInteger _arg1, SQObjectPtr &retval)\n{\n    SQBool    _isroot      = ci->_root;\n    SQInteger callerbase   = _stackbase - ci->_prevstkbase;\n\n    if (_debughook) {\n        for(SQInteger i=0; i<ci->_ncalls; i++) {\n            CallDebugHook(_SC('r'));\n        }\n    }\n\n    SQObjectPtr *dest;\n    if (_isroot) {\n        dest = &(retval);\n    } else if (ci->_target == -1) {\n        dest = NULL;\n    } else {\n        dest = &_stack._vals[callerbase + ci->_target];\n    }\n    if (dest) {\n        if(_arg0 != 0xFF) {\n            *dest = _stack._vals[_stackbase+_arg1];\n        }\n        else {\n            dest->Null();\n        }\n        //*dest = (_arg0 != 0xFF) ? _stack._vals[_stackbase+_arg1] : _null_;\n    }\n    LeaveFrame();\n    return _isroot ? true : false;\n}\n\n#define _RET_ON_FAIL(exp) { if(!exp) return false; }\n\nbool SQVM::PLOCAL_INC(SQInteger op,SQObjectPtr &target, SQObjectPtr &a, SQObjectPtr &incr)\n{\n    SQObjectPtr trg;\n    _RET_ON_FAIL(ARITH_OP( op , trg, a, incr));\n    target = a;\n    a = trg;\n    return true;\n}\n\nbool SQVM::DerefInc(SQInteger op,SQObjectPtr &target, SQObjectPtr &self, SQObjectPtr &key, SQObjectPtr &incr, bool postfix,SQInteger selfidx)\n{\n    SQObjectPtr tmp, tself = self, tkey = key;\n    if (!Get(tself, tkey, tmp, 0, selfidx)) { return false; }\n    _RET_ON_FAIL(ARITH_OP( op , target, tmp, incr))\n    if (!Set(tself, tkey, target,selfidx)) { return false; }\n    if (postfix) target = tmp;\n    return true;\n}\n\n#define arg0 (_i_._arg0)\n#define sarg0 ((SQInteger)*((const signed char *)&_i_._arg0))\n#define arg1 (_i_._arg1)\n#define sarg1 (*((const SQInt32 *)&_i_._arg1))\n#define arg2 (_i_._arg2)\n#define arg3 (_i_._arg3)\n#define sarg3 ((SQInteger)*((const signed char *)&_i_._arg3))\n\nSQRESULT SQVM::Suspend()\n{\n    if (_suspended)\n        return sq_throwerror(this, _SC(\"cannot suspend an already suspended vm\"));\n    if (_nnativecalls!=2)\n        return sq_throwerror(this, _SC(\"cannot suspend through native calls/metamethods\"));\n    return SQ_SUSPEND_FLAG;\n}\n\n\n#define _FINISH(howmuchtojump) {jump = howmuchtojump; return true; }\nbool SQVM::FOREACH_OP(SQObjectPtr &o1,SQObjectPtr &o2,SQObjectPtr\n&o3,SQObjectPtr &o4,SQInteger SQ_UNUSED_ARG(arg_2),int exitpos,int &jump)\n{\n    SQInteger nrefidx;\n    switch(sq_type(o1)) {\n    case OT_TABLE:\n        if((nrefidx = _table(o1)->Next(false,o4, o2, o3)) == -1) _FINISH(exitpos);\n        o4 = (SQInteger)nrefidx; _FINISH(1);\n    case OT_ARRAY:\n        if((nrefidx = _array(o1)->Next(o4, o2, o3)) == -1) _FINISH(exitpos);\n        o4 = (SQInteger) nrefidx; _FINISH(1);\n    case OT_STRING:\n        if((nrefidx = _string(o1)->Next(o4, o2, o3)) == -1)_FINISH(exitpos);\n        o4 = (SQInteger)nrefidx; _FINISH(1);\n    case OT_CLASS:\n        if((nrefidx = _class(o1)->Next(o4, o2, o3)) == -1)_FINISH(exitpos);\n        o4 = (SQInteger)nrefidx; _FINISH(1);\n    case OT_USERDATA:\n    case OT_INSTANCE:\n        if(_delegable(o1)->_delegate) {\n            SQObjectPtr itr;\n            SQObjectPtr closure;\n            if(_delegable(o1)->GetMetaMethod(this, MT_NEXTI, closure)) {\n                Push(o1);\n                Push(o4);\n                if(CallMetaMethod(closure, MT_NEXTI, 2, itr)) {\n                    o4 = o2 = itr;\n                    if(sq_type(itr) == OT_NULL) _FINISH(exitpos);\n                    if(!Get(o1, itr, o3, 0, DONT_FALL_BACK)) {\n                        Raise_Error(_SC(\"_nexti returned an invalid idx\")); // cloud be changed\n                        return false;\n                    }\n                    _FINISH(1);\n                }\n                else {\n                    return false;\n                }\n            }\n            Raise_Error(_SC(\"_nexti failed\"));\n            return false;\n        }\n        break;\n    case OT_GENERATOR:\n        if(_generator(o1)->_state == SQGenerator::eDead) _FINISH(exitpos);\n        if(_generator(o1)->_state == SQGenerator::eSuspended) {\n            SQInteger idx = 0;\n            if(sq_type(o4) == OT_INTEGER) {\n                idx = _integer(o4) + 1;\n            }\n            o2 = idx;\n            o4 = idx;\n            _generator(o1)->Resume(this, o3);\n            _FINISH(0);\n        }\n    default:\n        Raise_Error(_SC(\"cannot iterate %s\"), GetTypeName(o1));\n    }\n    return false; //cannot be hit(just to avoid warnings)\n}\n\n#define COND_LITERAL (arg3!=0?ci->_literals[arg1]:STK(arg1))\n\n#define SQ_THROW() { goto exception_trap; }\n\n#define _GUARD(exp) { if(!exp) { SQ_THROW();} }\n\nbool SQVM::CLOSURE_OP(SQObjectPtr &target, SQFunctionProto *func)\n{\n    SQInteger nouters;\n    SQClosure *closure = SQClosure::Create(_ss(this), func,_table(_roottable)->GetWeakRef(OT_TABLE));\n    if((nouters = func->_noutervalues)) {\n        for(SQInteger i = 0; i<nouters; i++) {\n            SQOuterVar &v = func->_outervalues[i];\n            switch(v._type){\n            case otLOCAL:\n                FindOuter(closure->_outervalues[i], &STK(_integer(v._src)));\n                break;\n            case otOUTER:\n                closure->_outervalues[i] = _closure(ci->_closure)->_outervalues[_integer(v._src)];\n                break;\n            }\n        }\n    }\n    SQInteger ndefparams;\n    if((ndefparams = func->_ndefaultparams)) {\n        for(SQInteger i = 0; i < ndefparams; i++) {\n            SQInteger spos = func->_defaultparams[i];\n            closure->_defaultparams[i] = _stack._vals[_stackbase + spos];\n        }\n    }\n    target = closure;\n    return true;\n\n}\n\n\nbool SQVM::CLASS_OP(SQObjectPtr &target,SQInteger baseclass,SQInteger attributes)\n{\n    SQClass *base = NULL;\n    SQObjectPtr attrs;\n    if(baseclass != -1) {\n        if(sq_type(_stack._vals[_stackbase+baseclass]) != OT_CLASS) { Raise_Error(_SC(\"trying to inherit from a %s\"),GetTypeName(_stack._vals[_stackbase+baseclass])); return false; }\n        base = _class(_stack._vals[_stackbase + baseclass]);\n    }\n    if(attributes != MAX_FUNC_STACKSIZE) {\n        attrs = _stack._vals[_stackbase+attributes];\n    }\n    target = SQClass::Create(_ss(this),base);\n    if(sq_type(_class(target)->_metamethods[MT_INHERITED]) != OT_NULL) {\n        int nparams = 2;\n        SQObjectPtr ret;\n        Push(target); Push(attrs);\n        if(!Call(_class(target)->_metamethods[MT_INHERITED],nparams,_top - nparams, ret, false)) {\n            Pop(nparams);\n            return false;\n        }\n        Pop(nparams);\n    }\n    _class(target)->_attributes = attrs;\n    return true;\n}\n\nbool SQVM::IsEqual(const SQObjectPtr &o1,const SQObjectPtr &o2,bool &res)\n{\n    if(sq_type(o1) == sq_type(o2)) {\n        res = (_rawval(o1) == _rawval(o2));\n    }\n    else {\n        if(sq_isnumeric(o1) && sq_isnumeric(o2)) {\n            res = (tofloat(o1) == tofloat(o2));\n        }\n        else {\n            res = false;\n        }\n    }\n    return true;\n}\n\nbool SQVM::IsFalse(SQObjectPtr &o)\n{\n    if(((sq_type(o) & SQOBJECT_CANBEFALSE)\n        && ( ((sq_type(o) == OT_FLOAT) && (_float(o) == SQFloat(0.0))) ))\n#if !defined(SQUSEDOUBLE) || (defined(SQUSEDOUBLE) && defined(_SQ64))\n        || (_integer(o) == 0) )  //OT_NULL|OT_INTEGER|OT_BOOL\n#else\n        || (((type(o) != OT_FLOAT) && (_integer(o) == 0))) )  //OT_NULL|OT_INTEGER|OT_BOOL\n#endif\n    {\n        return true;\n    }\n    return false;\n}\nextern SQInstructionDesc g_InstrDesc[];\nbool SQVM::Execute(SQObjectPtr &closure, SQInteger nargs, SQInteger stackbase,SQObjectPtr &outres, SQBool raiseerror,ExecutionType et)\n{\n    if ((_nnativecalls + 1) > MAX_NATIVE_CALLS) { Raise_Error(_SC(\"Native stack overflow\")); return false; }\n    _nnativecalls++;\n    AutoDec ad(&_nnativecalls);\n    SQInteger traps = 0;\n    CallInfo *prevci = ci;\n\n    switch(et) {\n        case ET_CALL: {\n            temp_reg = closure;\n            if(!StartCall(_closure(temp_reg), _top - nargs, nargs, stackbase, false)) {\n                //call the handler if there are no calls in the stack, if not relies on the previous node\n                if(ci == NULL) CallErrorHandler(_lasterror);\n                return false;\n            }\n            if(ci == prevci) {\n                outres = STK(_top-nargs);\n                return true;\n            }\n            ci->_root = SQTrue;\n                      }\n            break;\n        case ET_RESUME_GENERATOR: _generator(closure)->Resume(this, outres); ci->_root = SQTrue; traps += ci->_etraps; break;\n        case ET_RESUME_VM:\n        case ET_RESUME_THROW_VM:\n            traps = _suspended_traps;\n            ci->_root = _suspended_root;\n            _suspended = SQFalse;\n            if(et  == ET_RESUME_THROW_VM) { SQ_THROW(); }\n            break;\n    }\n\nexception_restore:\n    //\n    {\n        for(;;)\n        {\n            const SQInstruction &_i_ = *ci->_ip++;\n            //dumpstack(_stackbase);\n            //scprintf(\"\\n[%d] %s %d %d %d %d\\n\",ci->_ip-_closure(ci->_closure)->_function->_instructions,g_InstrDesc[_i_.op].name,arg0,arg1,arg2,arg3);\n            switch(_i_.op)\n            {\n            case _OP_LINE: if (_debughook) CallDebugHook(_SC('l'),arg1); continue;\n            case _OP_LOAD: TARGET = ci->_literals[arg1]; continue;\n            case _OP_LOADINT:\n#ifndef _SQ64\n                TARGET = (SQInteger)arg1; continue;\n#else\n                TARGET = (SQInteger)((SQInt32)arg1); continue;\n#endif\n            case _OP_LOADFLOAT: TARGET = *((const SQFloat *)&arg1); continue;\n            case _OP_DLOAD: TARGET = ci->_literals[arg1]; STK(arg2) = ci->_literals[arg3];continue;\n            case _OP_TAILCALL:{\n                SQObjectPtr &t = STK(arg1);\n                if (sq_type(t) == OT_CLOSURE\n                    && (!_closure(t)->_function->_bgenerator)){\n                    SQObjectPtr clo = t;\n                    SQInteger last_top = _top;\n                    if(_openouters) CloseOuters(&(_stack._vals[_stackbase]));\n                    for (SQInteger i = 0; i < arg3; i++) STK(i) = STK(arg2 + i);\n                    _GUARD(StartCall(_closure(clo), ci->_target, arg3, _stackbase, true));\n                    if (last_top >= _top) {\n                        _top = last_top;\n                    }\n                    continue;\n                }\n                              }\n            case _OP_CALL: {\n                    SQObjectPtr clo = STK(arg1);\n                    switch (sq_type(clo)) {\n                    case OT_CLOSURE:\n                        _GUARD(StartCall(_closure(clo), sarg0, arg3, _stackbase+arg2, false));\n                        continue;\n                    case OT_NATIVECLOSURE: {\n                        bool suspend;\n\t\t\t\t\t\tbool tailcall;\n                        _GUARD(CallNative(_nativeclosure(clo), arg3, _stackbase+arg2, clo, (SQInt32)sarg0, suspend, tailcall));\n                        if(suspend){\n                            _suspended = SQTrue;\n                            _suspended_target = sarg0;\n                            _suspended_root = ci->_root;\n                            _suspended_traps = traps;\n                            outres = clo;\n                            return true;\n                        }\n                        if(sarg0 != -1 && !tailcall) {\n                            STK(arg0) = clo;\n                        }\n                                           }\n                        continue;\n                    case OT_CLASS:{\n                        SQObjectPtr inst;\n                        _GUARD(CreateClassInstance(_class(clo),inst,clo));\n                        if(sarg0 != -1) {\n                            STK(arg0) = inst;\n                        }\n                        SQInteger stkbase;\n                        switch(sq_type(clo)) {\n                            case OT_CLOSURE:\n                                stkbase = _stackbase+arg2;\n                                _stack._vals[stkbase] = inst;\n                                _GUARD(StartCall(_closure(clo), -1, arg3, stkbase, false));\n                                break;\n                            case OT_NATIVECLOSURE:\n                                bool dummy;\n                                stkbase = _stackbase+arg2;\n                                _stack._vals[stkbase] = inst;\n                                _GUARD(CallNative(_nativeclosure(clo), arg3, stkbase, clo, -1, dummy, dummy));\n                                break;\n                            default: break; //shutup GCC 4.x\n                        }\n                        }\n                        break;\n                    case OT_TABLE:\n                    case OT_USERDATA:\n                    case OT_INSTANCE:{\n                        SQObjectPtr closure;\n                        if(_delegable(clo)->_delegate && _delegable(clo)->GetMetaMethod(this,MT_CALL,closure)) {\n                            Push(clo);\n                            for (SQInteger i = 0; i < arg3; i++) Push(STK(arg2 + i));\n                            if(!CallMetaMethod(closure, MT_CALL, arg3+1, clo)) SQ_THROW();\n                            if(sarg0 != -1) {\n                                STK(arg0) = clo;\n                            }\n                            break;\n                        }\n\n                        //Raise_Error(_SC(\"attempt to call '%s'\"), GetTypeName(clo));\n                        //SQ_THROW();\n                      }\n                    default:\n                        Raise_Error(_SC(\"attempt to call '%s'\"), GetTypeName(clo));\n                        SQ_THROW();\n                    }\n                }\n                  continue;\n            case _OP_PREPCALL:\n            case _OP_PREPCALLK: {\n                    SQObjectPtr &key = _i_.op == _OP_PREPCALLK?(ci->_literals)[arg1]:STK(arg1);\n                    SQObjectPtr &o = STK(arg2);\n                    if (!Get(o, key, temp_reg,0,arg2)) {\n                        SQ_THROW();\n                    }\n                    STK(arg3) = o;\n                    _Swap(TARGET,temp_reg);//TARGET = temp_reg;\n                }\n                continue;\n            case _OP_GETK:\n                if (!Get(STK(arg2), ci->_literals[arg1], temp_reg, 0,arg2)) { SQ_THROW();}\n                _Swap(TARGET,temp_reg);//TARGET = temp_reg;\n                continue;\n            case _OP_MOVE: TARGET = STK(arg1); continue;\n            case _OP_NEWSLOT:\n                _GUARD(NewSlot(STK(arg1), STK(arg2), STK(arg3),false));\n                if(arg0 != 0xFF) TARGET = STK(arg3);\n                continue;\n            case _OP_DELETE: _GUARD(DeleteSlot(STK(arg1), STK(arg2), TARGET)); continue;\n            case _OP_SET:\n                if (!Set(STK(arg1), STK(arg2), STK(arg3),arg1)) { SQ_THROW(); }\n                if (arg0 != 0xFF) TARGET = STK(arg3);\n                continue;\n            case _OP_GET:\n                if (!Get(STK(arg1), STK(arg2), temp_reg, 0,arg1)) { SQ_THROW(); }\n                _Swap(TARGET,temp_reg);//TARGET = temp_reg;\n                continue;\n            case _OP_EQ:{\n                bool res;\n                if(!IsEqual(STK(arg2),COND_LITERAL,res)) { SQ_THROW(); }\n                TARGET = res?true:false;\n                }continue;\n            case _OP_NE:{\n                bool res;\n                if(!IsEqual(STK(arg2),COND_LITERAL,res)) { SQ_THROW(); }\n                TARGET = (!res)?true:false;\n                } continue;\n            case _OP_ADD: _ARITH_(+,TARGET,STK(arg2),STK(arg1)); continue;\n            case _OP_SUB: _ARITH_(-,TARGET,STK(arg2),STK(arg1)); continue;\n            case _OP_MUL: _ARITH_(*,TARGET,STK(arg2),STK(arg1)); continue;\n            case _OP_DIV: _ARITH_NOZERO(/,TARGET,STK(arg2),STK(arg1),_SC(\"division by zero\")); continue;\n            case _OP_MOD: ARITH_OP('%',TARGET,STK(arg2),STK(arg1)); continue;\n            case _OP_BITW:  _GUARD(BW_OP( arg3,TARGET,STK(arg2),STK(arg1))); continue;\n            case _OP_RETURN:\n                if((ci)->_generator) {\n                    (ci)->_generator->Kill();\n                }\n                if(Return(arg0, arg1, temp_reg)){\n                    assert(traps==0);\n                    //outres = temp_reg;\n                    _Swap(outres,temp_reg);\n                    return true;\n                }\n                continue;\n            case _OP_LOADNULLS:{ for(SQInt32 n=0; n < arg1; n++) STK(arg0+n).Null(); }continue;\n            case _OP_LOADROOT:  {\n                SQWeakRef *w = _closure(ci->_closure)->_root;\n                if(sq_type(w->_obj) != OT_NULL) {\n                    TARGET = w->_obj;\n                } else {\n                    TARGET = _roottable; //shoud this be like this? or null\n                }\n                                }\n                continue;\n            case _OP_LOADBOOL: TARGET = arg1?true:false; continue;\n            case _OP_DMOVE: STK(arg0) = STK(arg1); STK(arg2) = STK(arg3); continue;\n            case _OP_JMP: ci->_ip += (sarg1); continue;\n            //case _OP_JNZ: if(!IsFalse(STK(arg0))) ci->_ip+=(sarg1); continue;\n            case _OP_JCMP:\n                _GUARD(CMP_OP((CmpOP)arg3,STK(arg2),STK(arg0),temp_reg));\n                if(IsFalse(temp_reg)) ci->_ip+=(sarg1);\n                continue;\n            case _OP_JZ: if(IsFalse(STK(arg0))) ci->_ip+=(sarg1); continue;\n            case _OP_GETOUTER: {\n                SQClosure *cur_cls = _closure(ci->_closure);\n                SQOuter *otr = _outer(cur_cls->_outervalues[arg1]);\n                TARGET = *(otr->_valptr);\n                }\n            continue;\n            case _OP_SETOUTER: {\n                SQClosure *cur_cls = _closure(ci->_closure);\n                SQOuter   *otr = _outer(cur_cls->_outervalues[arg1]);\n                *(otr->_valptr) = STK(arg2);\n                if(arg0 != 0xFF) {\n                    TARGET = STK(arg2);\n                }\n                }\n            continue;\n            case _OP_NEWOBJ:\n                switch(arg3) {\n                    case NOT_TABLE: TARGET = SQTable::Create(_ss(this), arg1); continue;\n                    case NOT_ARRAY: TARGET = SQArray::Create(_ss(this), 0); _array(TARGET)->Reserve(arg1); continue;\n                    case NOT_CLASS: _GUARD(CLASS_OP(TARGET,arg1,arg2)); continue;\n                    default: assert(0); continue;\n                }\n            case _OP_APPENDARRAY:\n                {\n                    SQObject val;\n                    val._unVal.raw = 0;\n                switch(arg2) {\n                case AAT_STACK:\n                    val = STK(arg1); break;\n                case AAT_LITERAL:\n                    val = ci->_literals[arg1]; break;\n                case AAT_INT:\n                    val._type = OT_INTEGER;\n#ifndef _SQ64\n                    val._unVal.nInteger = (SQInteger)arg1;\n#else\n                    val._unVal.nInteger = (SQInteger)((SQInt32)arg1);\n#endif\n                    break;\n                case AAT_FLOAT:\n                    val._type = OT_FLOAT;\n                    val._unVal.fFloat = *((const SQFloat *)&arg1);\n                    break;\n                case AAT_BOOL:\n                    val._type = OT_BOOL;\n                    val._unVal.nInteger = arg1;\n                    break;\n                default: val._type = OT_INTEGER; assert(0); break;\n\n                }\n                _array(STK(arg0))->Append(val); continue;\n                }\n            case _OP_COMPARITH: {\n                SQInteger selfidx = (((SQUnsignedInteger)arg1&0xFFFF0000)>>16);\n                _GUARD(DerefInc(arg3, TARGET, STK(selfidx), STK(arg2), STK(arg1&0x0000FFFF), false, selfidx));\n                                }\n                continue;\n            case _OP_INC: {SQObjectPtr o(sarg3); _GUARD(DerefInc('+',TARGET, STK(arg1), STK(arg2), o, false, arg1));} continue;\n            case _OP_INCL: {\n                SQObjectPtr &a = STK(arg1);\n                if(sq_type(a) == OT_INTEGER) {\n                    a._unVal.nInteger = _integer(a) + sarg3;\n                }\n                else {\n                    SQObjectPtr o(sarg3); //_GUARD(LOCAL_INC('+',TARGET, STK(arg1), o));\n                    _ARITH_(+,a,a,o);\n                }\n                           } continue;\n            case _OP_PINC: {SQObjectPtr o(sarg3); _GUARD(DerefInc('+',TARGET, STK(arg1), STK(arg2), o, true, arg1));} continue;\n            case _OP_PINCL: {\n                SQObjectPtr &a = STK(arg1);\n                if(sq_type(a) == OT_INTEGER) {\n                    TARGET = a;\n                    a._unVal.nInteger = _integer(a) + sarg3;\n                }\n                else {\n                    SQObjectPtr o(sarg3); _GUARD(PLOCAL_INC('+',TARGET, STK(arg1), o));\n                }\n\n                        } continue;\n            case _OP_CMP:   _GUARD(CMP_OP((CmpOP)arg3,STK(arg2),STK(arg1),TARGET))  continue;\n            case _OP_EXISTS: TARGET = Get(STK(arg1), STK(arg2), temp_reg, GET_FLAG_DO_NOT_RAISE_ERROR | GET_FLAG_RAW, DONT_FALL_BACK) ? true : false; continue;\n            case _OP_INSTANCEOF:\n                if(sq_type(STK(arg1)) != OT_CLASS)\n                {Raise_Error(_SC(\"cannot apply instanceof between a %s and a %s\"),GetTypeName(STK(arg1)),GetTypeName(STK(arg2))); SQ_THROW();}\n                TARGET = (sq_type(STK(arg2)) == OT_INSTANCE) ? (_instance(STK(arg2))->InstanceOf(_class(STK(arg1)))?true:false) : false;\n                continue;\n            case _OP_AND:\n                if(IsFalse(STK(arg2))) {\n                    TARGET = STK(arg2);\n                    ci->_ip += (sarg1);\n                }\n                continue;\n            case _OP_OR:\n                if(!IsFalse(STK(arg2))) {\n                    TARGET = STK(arg2);\n                    ci->_ip += (sarg1);\n                }\n                continue;\n            case _OP_NEG: _GUARD(NEG_OP(TARGET,STK(arg1))); continue;\n            case _OP_NOT: TARGET = IsFalse(STK(arg1)); continue;\n            case _OP_BWNOT:\n                if(sq_type(STK(arg1)) == OT_INTEGER) {\n                    SQInteger t = _integer(STK(arg1));\n                    TARGET = SQInteger(~t);\n                    continue;\n                }\n                Raise_Error(_SC(\"attempt to perform a bitwise op on a %s\"), GetTypeName(STK(arg1)));\n                SQ_THROW();\n            case _OP_CLOSURE: {\n                SQClosure *c = ci->_closure._unVal.pClosure;\n                SQFunctionProto *fp = c->_function;\n                if(!CLOSURE_OP(TARGET,fp->_functions[arg1]._unVal.pFunctionProto)) { SQ_THROW(); }\n                continue;\n            }\n            case _OP_YIELD:{\n                if(ci->_generator) {\n                    if(sarg1 != MAX_FUNC_STACKSIZE) temp_reg = STK(arg1);\n                    _GUARD(ci->_generator->Yield(this,arg2));\n                    traps -= ci->_etraps;\n                    if(sarg1 != MAX_FUNC_STACKSIZE) _Swap(STK(arg1),temp_reg);//STK(arg1) = temp_reg;\n                }\n                else { Raise_Error(_SC(\"trying to yield a '%s',only genenerator can be yielded\"), GetTypeName(ci->_generator)); SQ_THROW();}\n                if(Return(arg0, arg1, temp_reg)){\n                    assert(traps == 0);\n                    outres = temp_reg;\n                    return true;\n                }\n\n                }\n                continue;\n            case _OP_RESUME:\n                if(sq_type(STK(arg1)) != OT_GENERATOR){ Raise_Error(_SC(\"trying to resume a '%s',only genenerator can be resumed\"), GetTypeName(STK(arg1))); SQ_THROW();}\n                _GUARD(_generator(STK(arg1))->Resume(this, TARGET));\n                traps += ci->_etraps;\n                continue;\n            case _OP_FOREACH:{ int tojump;\n                _GUARD(FOREACH_OP(STK(arg0),STK(arg2),STK(arg2+1),STK(arg2+2),arg2,sarg1,tojump));\n                ci->_ip += tojump; }\n                continue;\n            case _OP_POSTFOREACH:\n                assert(sq_type(STK(arg0)) == OT_GENERATOR);\n                if(_generator(STK(arg0))->_state == SQGenerator::eDead)\n                    ci->_ip += (sarg1 - 1);\n                continue;\n            case _OP_CLONE: _GUARD(Clone(STK(arg1), TARGET)); continue;\n            case _OP_TYPEOF: _GUARD(TypeOf(STK(arg1), TARGET)) continue;\n            case _OP_PUSHTRAP:{\n                SQInstruction *_iv = _closure(ci->_closure)->_function->_instructions;\n                _etraps.push_back(SQExceptionTrap(_top,_stackbase, &_iv[(ci->_ip-_iv)+arg1], arg0)); traps++;\n                ci->_etraps++;\n                              }\n                continue;\n            case _OP_POPTRAP: {\n                for(SQInteger i = 0; i < arg0; i++) {\n                    _etraps.pop_back(); traps--;\n                    ci->_etraps--;\n                }\n                              }\n                continue;\n            case _OP_THROW: Raise_Error(TARGET); SQ_THROW(); continue;\n            case _OP_NEWSLOTA:\n                _GUARD(NewSlotA(STK(arg1),STK(arg2),STK(arg3),(arg0&NEW_SLOT_ATTRIBUTES_FLAG) ? STK(arg2-1) : SQObjectPtr(),(arg0&NEW_SLOT_STATIC_FLAG)?true:false,false));\n                continue;\n            case _OP_GETBASE:{\n                SQClosure *clo = _closure(ci->_closure);\n                if(clo->_base) {\n                    TARGET = clo->_base;\n                }\n                else {\n                    TARGET.Null();\n                }\n                continue;\n            }\n            case _OP_CLOSE:\n                if(_openouters) CloseOuters(&(STK(arg1)));\n                continue;\n            }\n\n        }\n    }\nexception_trap:\n    {\n        SQObjectPtr currerror = _lasterror;\n//      dumpstack(_stackbase);\n//      SQInteger n = 0;\n        SQInteger last_top = _top;\n\n        if(_ss(this)->_notifyallexceptions || (!traps && raiseerror)) CallErrorHandler(currerror);\n\n        while( ci ) {\n            if(ci->_etraps > 0) {\n                SQExceptionTrap &et = _etraps.top();\n                ci->_ip = et._ip;\n                _top = et._stacksize;\n                _stackbase = et._stackbase;\n                _stack._vals[_stackbase + et._extarget] = currerror;\n                _etraps.pop_back(); traps--; ci->_etraps--;\n                while(last_top >= _top) _stack._vals[last_top--].Null();\n                goto exception_restore;\n            }\n            else if (_debughook) {\n                    //notify debugger of a \"return\"\n                    //even if it really an exception unwinding the stack\n                    for(SQInteger i = 0; i < ci->_ncalls; i++) {\n                        CallDebugHook(_SC('r'));\n                    }\n            }\n            if(ci->_generator) ci->_generator->Kill();\n            bool mustbreak = ci && ci->_root;\n            LeaveFrame();\n            if(mustbreak) break;\n        }\n\n        _lasterror = currerror;\n        return false;\n    }\n    assert(0);\n}\n\nbool SQVM::CreateClassInstance(SQClass *theclass, SQObjectPtr &inst, SQObjectPtr &constructor)\n{\n    inst = theclass->CreateInstance();\n    if(!theclass->GetConstructor(constructor)) {\n        constructor.Null();\n    }\n    return true;\n}\n\nvoid SQVM::CallErrorHandler(SQObjectPtr &error)\n{\n    if(sq_type(_errorhandler) != OT_NULL) {\n        SQObjectPtr out;\n        Push(_roottable); Push(error);\n        Call(_errorhandler, 2, _top-2, out,SQFalse);\n        Pop(2);\n    }\n}\n\n\nvoid SQVM::CallDebugHook(SQInteger type,SQInteger forcedline)\n{\n    _debughook = false;\n    SQFunctionProto *func=_closure(ci->_closure)->_function;\n    if(_debughook_native) {\n        const SQChar *src = sq_type(func->_sourcename) == OT_STRING?_stringval(func->_sourcename):NULL;\n        const SQChar *fname = sq_type(func->_name) == OT_STRING?_stringval(func->_name):NULL;\n        SQInteger line = forcedline?forcedline:func->GetLine(ci->_ip);\n        _debughook_native(this,type,src,line,fname);\n    }\n    else {\n        SQObjectPtr temp_reg;\n        SQInteger nparams=5;\n        Push(_roottable); Push(type); Push(func->_sourcename); Push(forcedline?forcedline:func->GetLine(ci->_ip)); Push(func->_name);\n        Call(_debughook_closure,nparams,_top-nparams,temp_reg,SQFalse);\n        Pop(nparams);\n    }\n    _debughook = true;\n}\n\nbool SQVM::CallNative(SQNativeClosure *nclosure, SQInteger nargs, SQInteger newbase, SQObjectPtr &retval, SQInt32 target,bool &suspend, bool &tailcall)\n{\n    SQInteger nparamscheck = nclosure->_nparamscheck;\n    SQInteger newtop = newbase + nargs + nclosure->_noutervalues;\n\n    if (_nnativecalls + 1 > MAX_NATIVE_CALLS) {\n        Raise_Error(_SC(\"Native stack overflow\"));\n        return false;\n    }\n\n    if(nparamscheck && (((nparamscheck > 0) && (nparamscheck != nargs)) ||\n        ((nparamscheck < 0) && (nargs < (-nparamscheck)))))\n    {\n        Raise_Error(_SC(\"wrong number of parameters\"));\n        return false;\n    }\n\n    SQInteger tcs;\n    SQIntVec &tc = nclosure->_typecheck;\n    if((tcs = tc.size())) {\n        for(SQInteger i = 0; i < nargs && i < tcs; i++) {\n            if((tc._vals[i] != -1) && !(sq_type(_stack._vals[newbase+i]) & tc._vals[i])) {\n                Raise_ParamTypeError(i,tc._vals[i], sq_type(_stack._vals[newbase+i]));\n                return false;\n            }\n        }\n    }\n\n    if(!EnterFrame(newbase, newtop, false)) return false;\n    ci->_closure  = nclosure;\n\tci->_target = target;\n\n    SQInteger outers = nclosure->_noutervalues;\n    for (SQInteger i = 0; i < outers; i++) {\n        _stack._vals[newbase+nargs+i] = nclosure->_outervalues[i];\n    }\n    if(nclosure->_env) {\n        _stack._vals[newbase] = nclosure->_env->_obj;\n    }\n\n    _nnativecalls++;\n    SQInteger ret = (nclosure->_function)(this);\n    _nnativecalls--;\n\n    suspend = false;\n\ttailcall = false;\n\tif (ret == SQ_TAILCALL_FLAG) {\n\t\ttailcall = true;\n\t\treturn true;\n\t}\n    else if (ret == SQ_SUSPEND_FLAG) {\n        suspend = true;\n    }\n    else if (ret < 0) {\n        LeaveFrame();\n        Raise_Error(_lasterror);\n        return false;\n    }\n    if(ret) {\n        retval = _stack._vals[_top-1];\n    }\n    else {\n        retval.Null();\n    }\n    //retval = ret ? _stack._vals[_top-1] : _null_;\n    LeaveFrame();\n    return true;\n}\n\nbool SQVM::TailCall(SQClosure *closure, SQInteger parambase,SQInteger nparams)\n{\n\tSQInteger last_top = _top;\n\tSQObjectPtr clo = closure;\n\tif (ci->_root)\n\t{\n\t\tRaise_Error(\"root calls cannot invoke tailcalls\");\n\t\treturn false;\n\t}\n\tfor (SQInteger i = 0; i < nparams; i++) STK(i) = STK(parambase + i);\n\tbool ret = StartCall(closure, ci->_target, nparams, _stackbase, true);\n\tif (last_top >= _top) {\n\t\t_top = last_top;\n\t}\n\treturn ret;\n}\n\n#define FALLBACK_OK         0\n#define FALLBACK_NO_MATCH   1\n#define FALLBACK_ERROR      2\n\nbool SQVM::Get(const SQObjectPtr &self, const SQObjectPtr &key, SQObjectPtr &dest, SQUnsignedInteger getflags, SQInteger selfidx)\n{\n    switch(sq_type(self)){\n    case OT_TABLE:\n        if(_table(self)->Get(key,dest))return true;\n        break;\n    case OT_ARRAY:\n        if (sq_isnumeric(key)) { if (_array(self)->Get(tointeger(key), dest)) { return true; } if ((getflags & GET_FLAG_DO_NOT_RAISE_ERROR) == 0) Raise_IdxError(key); return false; }\n        break;\n    case OT_INSTANCE:\n        if(_instance(self)->Get(key,dest)) return true;\n        break;\n    case OT_CLASS:\n        if(_class(self)->Get(key,dest)) return true;\n        break;\n    case OT_STRING:\n        if(sq_isnumeric(key)){\n            SQInteger n = tointeger(key);\n            SQInteger len = _string(self)->_len;\n            if (n < 0) { n += len; }\n            if (n >= 0 && n < len) {\n                dest = SQInteger(_stringval(self)[n]);\n                return true;\n            }\n            if ((getflags & GET_FLAG_DO_NOT_RAISE_ERROR) == 0) Raise_IdxError(key);\n            return false;\n        }\n        break;\n    default:break; //shut up compiler\n    }\n    if ((getflags & GET_FLAG_RAW) == 0) {\n        switch(FallBackGet(self,key,dest)) {\n            case FALLBACK_OK: return true; //okie\n            case FALLBACK_NO_MATCH: break; //keep falling back\n            case FALLBACK_ERROR: return false; // the metamethod failed\n        }\n        if(InvokeDefaultDelegate(self,key,dest)) {\n            return true;\n        }\n    }\n//#ifdef ROOT_FALLBACK\n    if(selfidx == 0) {\n        SQWeakRef *w = _closure(ci->_closure)->_root;\n        if(sq_type(w->_obj) != OT_NULL)\n        {\n            if(Get(*((const SQObjectPtr *)&w->_obj),key,dest,0,DONT_FALL_BACK)) return true;\n        }\n\n    }\n//#endif\n    if ((getflags & GET_FLAG_DO_NOT_RAISE_ERROR) == 0) Raise_IdxError(key);\n    return false;\n}\n\nbool SQVM::InvokeDefaultDelegate(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest)\n{\n    SQTable *ddel = NULL;\n    switch(sq_type(self)) {\n        case OT_CLASS: ddel = _class_ddel; break;\n        case OT_TABLE: ddel = _table_ddel; break;\n        case OT_ARRAY: ddel = _array_ddel; break;\n        case OT_STRING: ddel = _string_ddel; break;\n        case OT_INSTANCE: ddel = _instance_ddel; break;\n        case OT_INTEGER:case OT_FLOAT:case OT_BOOL: ddel = _number_ddel; break;\n        case OT_GENERATOR: ddel = _generator_ddel; break;\n        case OT_CLOSURE: case OT_NATIVECLOSURE: ddel = _closure_ddel; break;\n        case OT_THREAD: ddel = _thread_ddel; break;\n        case OT_WEAKREF: ddel = _weakref_ddel; break;\n        default: return false;\n    }\n    return  ddel->Get(key,dest);\n}\n\n\nSQInteger SQVM::FallBackGet(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest)\n{\n    switch(sq_type(self)){\n    case OT_TABLE:\n    case OT_USERDATA:\n        //delegation\n        if(_delegable(self)->_delegate) {\n            if(Get(SQObjectPtr(_delegable(self)->_delegate),key,dest,0,DONT_FALL_BACK)) return FALLBACK_OK;\n        }\n        else {\n            return FALLBACK_NO_MATCH;\n        }\n        //go through\n    case OT_INSTANCE: {\n        SQObjectPtr closure;\n        if(_delegable(self)->GetMetaMethod(this, MT_GET, closure)) {\n            Push(self);Push(key);\n            _nmetamethodscall++;\n            AutoDec ad(&_nmetamethodscall);\n            if(Call(closure, 2, _top - 2, dest, SQFalse)) {\n                Pop(2);\n                return FALLBACK_OK;\n            }\n            else {\n                Pop(2);\n                if(sq_type(_lasterror) != OT_NULL) { //NULL means \"clean failure\" (not found)\n                    return FALLBACK_ERROR;\n                }\n            }\n        }\n                      }\n        break;\n    default: break;//shutup GCC 4.x\n    }\n    // no metamethod or no fallback type\n    return FALLBACK_NO_MATCH;\n}\n\nbool SQVM::Set(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val,SQInteger selfidx)\n{\n    switch(sq_type(self)){\n    case OT_TABLE:\n        if(_table(self)->Set(key,val)) return true;\n        break;\n    case OT_INSTANCE:\n        if(_instance(self)->Set(key,val)) return true;\n        break;\n    case OT_ARRAY:\n        if(!sq_isnumeric(key)) { Raise_Error(_SC(\"indexing %s with %s\"),GetTypeName(self),GetTypeName(key)); return false; }\n        if(!_array(self)->Set(tointeger(key),val)) {\n            Raise_IdxError(key);\n            return false;\n        }\n        return true;\n  \tcase OT_USERDATA: break; // must fall back\n    default:\n        Raise_Error(_SC(\"trying to set '%s'\"),GetTypeName(self));\n        return false;\n    }\n\n    switch(FallBackSet(self,key,val)) {\n        case FALLBACK_OK: return true; //okie\n        case FALLBACK_NO_MATCH: break; //keep falling back\n        case FALLBACK_ERROR: return false; // the metamethod failed\n    }\n    if(selfidx == 0) {\n        if(_table(_roottable)->Set(key,val))\n            return true;\n    }\n    Raise_IdxError(key);\n    return false;\n}\n\nSQInteger SQVM::FallBackSet(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val)\n{\n    switch(sq_type(self)) {\n    case OT_TABLE:\n        if(_table(self)->_delegate) {\n            if(Set(_table(self)->_delegate,key,val,DONT_FALL_BACK)) return FALLBACK_OK;\n        }\n        //keps on going\n    case OT_INSTANCE:\n    case OT_USERDATA:{\n        SQObjectPtr closure;\n        SQObjectPtr t;\n        if(_delegable(self)->GetMetaMethod(this, MT_SET, closure)) {\n            Push(self);Push(key);Push(val);\n            _nmetamethodscall++;\n            AutoDec ad(&_nmetamethodscall);\n            if(Call(closure, 3, _top - 3, t, SQFalse)) {\n                Pop(3);\n                return FALLBACK_OK;\n            }\n            else {\n                Pop(3);\n                if(sq_type(_lasterror) != OT_NULL) { //NULL means \"clean failure\" (not found)\n                    return FALLBACK_ERROR;\n                }\n            }\n        }\n                     }\n        break;\n        default: break;//shutup GCC 4.x\n    }\n    // no metamethod or no fallback type\n    return FALLBACK_NO_MATCH;\n}\n\nbool SQVM::Clone(const SQObjectPtr &self,SQObjectPtr &target)\n{\n    SQObjectPtr temp_reg;\n    SQObjectPtr newobj;\n    switch(sq_type(self)){\n    case OT_TABLE:\n        newobj = _table(self)->Clone();\n        goto cloned_mt;\n    case OT_INSTANCE: {\n        newobj = _instance(self)->Clone(_ss(this));\ncloned_mt:\n        SQObjectPtr closure;\n        if(_delegable(newobj)->_delegate && _delegable(newobj)->GetMetaMethod(this,MT_CLONED,closure)) {\n            Push(newobj);\n            Push(self);\n            if(!CallMetaMethod(closure,MT_CLONED,2,temp_reg))\n                return false;\n        }\n        }\n        target = newobj;\n        return true;\n    case OT_ARRAY:\n        target = _array(self)->Clone();\n        return true;\n    default:\n        Raise_Error(_SC(\"cloning a %s\"), GetTypeName(self));\n        return false;\n    }\n}\n\nbool SQVM::NewSlotA(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val,const SQObjectPtr &attrs,bool bstatic,bool raw)\n{\n    if(sq_type(self) != OT_CLASS) {\n        Raise_Error(_SC(\"object must be a class\"));\n        return false;\n    }\n    SQClass *c = _class(self);\n    if(!raw) {\n        SQObjectPtr &mm = c->_metamethods[MT_NEWMEMBER];\n        if(sq_type(mm) != OT_NULL ) {\n            Push(self); Push(key); Push(val);\n            Push(attrs);\n            Push(bstatic);\n            return CallMetaMethod(mm,MT_NEWMEMBER,5,temp_reg);\n        }\n    }\n    if(!NewSlot(self, key, val,bstatic))\n        return false;\n    if(sq_type(attrs) != OT_NULL) {\n        c->SetAttributes(key,attrs);\n    }\n    return true;\n}\n\nbool SQVM::NewSlot(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val,bool bstatic)\n{\n    if(sq_type(key) == OT_NULL) { Raise_Error(_SC(\"null cannot be used as index\")); return false; }\n    switch(sq_type(self)) {\n    case OT_TABLE: {\n        bool rawcall = true;\n        if(_table(self)->_delegate) {\n            SQObjectPtr res;\n            if(!_table(self)->Get(key,res)) {\n                SQObjectPtr closure;\n                if(_delegable(self)->_delegate && _delegable(self)->GetMetaMethod(this,MT_NEWSLOT,closure)) {\n                    Push(self);Push(key);Push(val);\n                    if(!CallMetaMethod(closure,MT_NEWSLOT,3,res)) {\n                        return false;\n                    }\n                    rawcall = false;\n                }\n                else {\n                    rawcall = true;\n                }\n            }\n        }\n        if(rawcall) _table(self)->NewSlot(key,val); //cannot fail\n\n        break;}\n    case OT_INSTANCE: {\n        SQObjectPtr res;\n        SQObjectPtr closure;\n        if(_delegable(self)->_delegate && _delegable(self)->GetMetaMethod(this,MT_NEWSLOT,closure)) {\n            Push(self);Push(key);Push(val);\n            if(!CallMetaMethod(closure,MT_NEWSLOT,3,res)) {\n                return false;\n            }\n            break;\n        }\n        Raise_Error(_SC(\"class instances do not support the new slot operator\"));\n        return false;\n        break;}\n    case OT_CLASS:\n        if(!_class(self)->NewSlot(_ss(this),key,val,bstatic)) {\n            if(_class(self)->_locked) {\n                Raise_Error(_SC(\"trying to modify a class that has already been instantiated\"));\n                return false;\n            }\n            else {\n                SQObjectPtr oval = PrintObjVal(key);\n                Raise_Error(_SC(\"the property '%s' already exists\"),_stringval(oval));\n                return false;\n            }\n        }\n        break;\n    default:\n        Raise_Error(_SC(\"indexing %s with %s\"),GetTypeName(self),GetTypeName(key));\n        return false;\n        break;\n    }\n    return true;\n}\n\n\n\nbool SQVM::DeleteSlot(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &res)\n{\n    switch(sq_type(self)) {\n    case OT_TABLE:\n    case OT_INSTANCE:\n    case OT_USERDATA: {\n        SQObjectPtr t;\n        //bool handled = false;\n        SQObjectPtr closure;\n        if(_delegable(self)->_delegate && _delegable(self)->GetMetaMethod(this,MT_DELSLOT,closure)) {\n            Push(self);Push(key);\n            return CallMetaMethod(closure,MT_DELSLOT,2,res);\n        }\n        else {\n            if(sq_type(self) == OT_TABLE) {\n                if(_table(self)->Get(key,t)) {\n                    _table(self)->Remove(key);\n                }\n                else {\n                    Raise_IdxError((const SQObject &)key);\n                    return false;\n                }\n            }\n            else {\n                Raise_Error(_SC(\"cannot delete a slot from %s\"),GetTypeName(self));\n                return false;\n            }\n        }\n        res = t;\n                }\n        break;\n    default:\n        Raise_Error(_SC(\"attempt to delete a slot from a %s\"),GetTypeName(self));\n        return false;\n    }\n    return true;\n}\n\nbool SQVM::Call(SQObjectPtr &closure,SQInteger nparams,SQInteger stackbase,SQObjectPtr &outres,SQBool raiseerror)\n{\n#ifdef _DEBUG\nSQInteger prevstackbase = _stackbase;\n#endif\n    switch(sq_type(closure)) {\n    case OT_CLOSURE:\n        return Execute(closure, nparams, stackbase, outres, raiseerror);\n        break;\n    case OT_NATIVECLOSURE:{\n        bool dummy;\n        return CallNative(_nativeclosure(closure), nparams, stackbase, outres, -1, dummy, dummy);\n\n                          }\n        break;\n    case OT_CLASS: {\n        SQObjectPtr constr;\n        SQObjectPtr temp;\n        CreateClassInstance(_class(closure),outres,constr);\n        SQObjectType ctype = sq_type(constr);\n        if (ctype == OT_NATIVECLOSURE || ctype == OT_CLOSURE) {\n            _stack[stackbase] = outres;\n            return Call(constr,nparams,stackbase,temp,raiseerror);\n        }\n        return true;\n                   }\n        break;\n    default:\n        return false;\n    }\n#ifdef _DEBUG\n    if(!_suspended) {\n        assert(_stackbase == prevstackbase);\n    }\n#endif\n    return true;\n}\n\nbool SQVM::CallMetaMethod(SQObjectPtr &closure,SQMetaMethod SQ_UNUSED_ARG(mm),SQInteger nparams,SQObjectPtr &outres)\n{\n    //SQObjectPtr closure;\n\n    _nmetamethodscall++;\n    if(Call(closure, nparams, _top - nparams, outres, SQFalse)) {\n        _nmetamethodscall--;\n        Pop(nparams);\n        return true;\n    }\n    _nmetamethodscall--;\n    //}\n    Pop(nparams);\n    return false;\n}\n\nvoid SQVM::FindOuter(SQObjectPtr &target, SQObjectPtr *stackindex)\n{\n    SQOuter **pp = &_openouters;\n    SQOuter *p;\n    SQOuter *otr;\n\n    while ((p = *pp) != NULL && p->_valptr >= stackindex) {\n        if (p->_valptr == stackindex) {\n            target = SQObjectPtr(p);\n            return;\n        }\n        pp = &p->_next;\n    }\n    otr = SQOuter::Create(_ss(this), stackindex);\n    otr->_next = *pp;\n    otr->_idx  = (stackindex - _stack._vals);\n    __ObjAddRef(otr);\n    *pp = otr;\n    target = SQObjectPtr(otr);\n}\n\nbool SQVM::EnterFrame(SQInteger newbase, SQInteger newtop, bool tailcall)\n{\n    if( !tailcall ) {\n        if( _callsstacksize == _alloccallsstacksize ) {\n            GrowCallStack();\n        }\n        ci = &_callsstack[_callsstacksize++];\n        ci->_prevstkbase = (SQInt32)(newbase - _stackbase);\n        ci->_prevtop = (SQInt32)(_top - _stackbase);\n        ci->_etraps = 0;\n        ci->_ncalls = 1;\n        ci->_generator = NULL;\n        ci->_root = SQFalse;\n    }\n    else {\n        ci->_ncalls++;\n    }\n\n    _stackbase = newbase;\n    _top = newtop;\n    if(newtop + MIN_STACK_OVERHEAD > (SQInteger)_stack.size()) {\n        if(_nmetamethodscall) {\n            Raise_Error(_SC(\"stack overflow, cannot resize stack while in a metamethod\"));\n            return false;\n        }\n        _stack.resize(newtop + (MIN_STACK_OVERHEAD << 2));\n        RelocateOuters();\n    }\n    return true;\n}\n\nvoid SQVM::LeaveFrame() {\n    SQInteger last_top = _top;\n    SQInteger last_stackbase = _stackbase;\n    SQInteger css = --_callsstacksize;\n\n    /* First clean out the call stack frame */\n    ci->_closure.Null();\n    _stackbase -= ci->_prevstkbase;\n    _top = _stackbase + ci->_prevtop;\n    ci = (css) ? &_callsstack[css-1] : NULL;\n\n    if(_openouters) CloseOuters(&(_stack._vals[last_stackbase]));\n    while (last_top >= _top) {\n        _stack._vals[last_top--].Null();\n    }\n}\n\nvoid SQVM::RelocateOuters()\n{\n    SQOuter *p = _openouters;\n    while (p) {\n        p->_valptr = _stack._vals + p->_idx;\n        p = p->_next;\n    }\n}\n\nvoid SQVM::CloseOuters(SQObjectPtr *stackindex) {\n  SQOuter *p;\n  while ((p = _openouters) != NULL && p->_valptr >= stackindex) {\n    p->_value = *(p->_valptr);\n    p->_valptr = &p->_value;\n    _openouters = p->_next;\n    __ObjRelease(p);\n  }\n}\n\nvoid SQVM::Remove(SQInteger n) {\n    n = (n >= 0)?n + _stackbase - 1:_top + n;\n    for(SQInteger i = n; i < _top; i++){\n        _stack[i] = _stack[i+1];\n    }\n    _stack[_top].Null();\n    _top--;\n}\n\nvoid SQVM::Pop() {\n    CheckStackAccess(_top-1);\n    _stack[--_top].Null();\n}\n\nvoid SQVM::Pop(SQInteger n) {\n    for(SQInteger i = 0; i < n; i++){\n        CheckStackAccess(_top-1);\n        _stack[--_top].Null();\n    }\n}\n\nvoid SQVM::PushNull() { CheckStackAccess(_top+1); _stack[_top++].Null(); }\nvoid SQVM::Push(const SQObjectPtr &o) { CheckStackAccess(_top+1); _stack[_top++] = o; }\nSQObjectPtr &SQVM::Top() { CheckStackAccess(_top-1); return _stack[_top-1]; }\nSQObjectPtr &SQVM::PopGet() { CheckStackAccess(_top-1); return _stack[--_top]; }\nSQObjectPtr &SQVM::GetUp(SQInteger n) { CheckStackAccess(_top+n); return _stack[_top+n]; }\nSQObjectPtr &SQVM::GetAt(SQInteger n) { CheckStackAccess(n); return _stack[n]; }\n\nvoid SQVM::CheckStackAccess(SQInteger n) {\n    if(n < 0 || n >= _stack.size()){\n        std::ostringstream s;\n        s << \"Stack of the VM accessed with n=\" << n << \" and stacksize=\" << _stack.size();\n        throw std::out_of_range(s.str());\n    }\n}\n\n#ifdef _DEBUG_DUMP\nvoid SQVM::dumpstack(SQInteger stackbase,bool dumpall)\n{\n    SQInteger size=dumpall?_stack.size():_top;\n    SQInteger n=0;\n    scprintf(_SC(\"\\n>>>>stack dump<<<<\\n\"));\n    CallInfo &ci=_callsstack[_callsstacksize-1];\n    scprintf(_SC(\"IP: %p\\n\"),ci._ip);\n    scprintf(_SC(\"prev stack base: %d\\n\"),ci._prevstkbase);\n    scprintf(_SC(\"prev top: %d\\n\"),ci._prevtop);\n    for(SQInteger i=0;i<size;i++){\n        SQObjectPtr &obj=_stack[i];\n        if(stackbase==i)scprintf(_SC(\">\"));else scprintf(_SC(\" \"));\n        scprintf(_SC(\"[\" _PRINT_INT_FMT \"]:\"),n);\n        switch(sq_type(obj)){\n        case OT_FLOAT:          scprintf(_SC(\"FLOAT %.3f\"),_float(obj));break;\n        case OT_INTEGER:        scprintf(_SC(\"INTEGER \" _PRINT_INT_FMT),_integer(obj));break;\n        case OT_BOOL:           scprintf(_SC(\"BOOL %s\"),_integer(obj)?\"true\":\"false\");break;\n        case OT_STRING:         scprintf(_SC(\"STRING %s\"),_stringval(obj));break;\n        case OT_NULL:           scprintf(_SC(\"NULL\"));  break;\n        case OT_TABLE:          scprintf(_SC(\"TABLE %p[%p]\"),_table(obj),_table(obj)->_delegate);break;\n        case OT_ARRAY:          scprintf(_SC(\"ARRAY %p\"),_array(obj));break;\n        case OT_CLOSURE:        scprintf(_SC(\"CLOSURE [%p]\"),_closure(obj));break;\n        case OT_NATIVECLOSURE:  scprintf(_SC(\"NATIVECLOSURE\"));break;\n        case OT_USERDATA:       scprintf(_SC(\"USERDATA %p[%p]\"),_userdataval(obj),_userdata(obj)->_delegate);break;\n        case OT_GENERATOR:      scprintf(_SC(\"GENERATOR %p\"),_generator(obj));break;\n        case OT_THREAD:         scprintf(_SC(\"THREAD [%p]\"),_thread(obj));break;\n        case OT_USERPOINTER:    scprintf(_SC(\"USERPOINTER %p\"),_userpointer(obj));break;\n        case OT_CLASS:          scprintf(_SC(\"CLASS %p\"),_class(obj));break;\n        case OT_INSTANCE:       scprintf(_SC(\"INSTANCE %p\"),_instance(obj));break;\n        case OT_WEAKREF:        scprintf(_SC(\"WEAKERF %p\"),_weakref(obj));break;\n        default:\n            assert(0);\n            break;\n        };\n        scprintf(_SC(\"\\n\"));\n        ++n;\n    }\n}\n\n\n\n#endif\n"
  },
  {
    "path": "extlibs/squirrel/squirrel/sqvm.h",
    "content": "/*  see copyright notice in squirrel.h */\n#ifndef _SQVM_H_\n#define _SQVM_H_\n\n#include \"sqopcodes.h\"\n#include \"sqobject.h\"\n#define MAX_NATIVE_CALLS 100\n#define MIN_STACK_OVERHEAD 15\n\n#define SQ_SUSPEND_FLAG -666\n#define SQ_TAILCALL_FLAG -777\n#define DONT_FALL_BACK 666\n//#define EXISTS_FALL_BACK -1\n\n#define GET_FLAG_RAW                0x00000001\n#define GET_FLAG_DO_NOT_RAISE_ERROR 0x00000002\n//base lib\nvoid sq_base_register(HSQUIRRELVM v);\n\nstruct SQExceptionTrap{\n    SQExceptionTrap() {}\n    SQExceptionTrap(SQInteger ss, SQInteger stackbase,SQInstruction *ip, SQInteger ex_target){ _stacksize = ss; _stackbase = stackbase; _ip = ip; _extarget = ex_target;}\n    SQExceptionTrap(const SQExceptionTrap &et) { (*this) = et;  }\n    SQInteger _stackbase;\n    SQInteger _stacksize;\n    SQInstruction *_ip;\n    SQInteger _extarget;\n};\n\n#define _INLINE\n\ntypedef sqvector<SQExceptionTrap> ExceptionsTraps;\n\nstruct SQVM : public CHAINABLE_OBJ\n{\n    struct CallInfo{\n        //CallInfo() { _generator = NULL;}\n        SQInstruction *_ip;\n        SQObjectPtr *_literals;\n        SQObjectPtr _closure;\n        SQGenerator *_generator;\n        SQInt32 _etraps;\n        SQInt32 _prevstkbase;\n        SQInt32 _prevtop;\n        SQInt32 _target;\n        SQInt32 _ncalls;\n        SQBool _root;\n    };\n\ntypedef sqvector<CallInfo> CallInfoVec;\npublic:\n    void DebugHookProxy(SQInteger type, const SQChar * sourcename, SQInteger line, const SQChar * funcname);\n    static void _DebugHookProxy(HSQUIRRELVM v, SQInteger type, const SQChar * sourcename, SQInteger line, const SQChar * funcname);\n    enum ExecutionType { ET_CALL, ET_RESUME_GENERATOR, ET_RESUME_VM,ET_RESUME_THROW_VM };\n    SQVM(SQSharedState *ss);\n    ~SQVM();\n    bool Init(SQVM *friendvm, SQInteger stacksize);\n    bool Execute(SQObjectPtr &func, SQInteger nargs, SQInteger stackbase, SQObjectPtr &outres, SQBool raiseerror, ExecutionType et = ET_CALL);\n    //starts a native call return when the NATIVE closure returns\n    bool CallNative(SQNativeClosure *nclosure, SQInteger nargs, SQInteger newbase, SQObjectPtr &retval, SQInt32 target, bool &suspend,bool &tailcall);\n\tbool TailCall(SQClosure *closure, SQInteger firstparam, SQInteger nparams);\n    //starts a SQUIRREL call in the same \"Execution loop\"\n    bool StartCall(SQClosure *closure, SQInteger target, SQInteger nargs, SQInteger stackbase, bool tailcall);\n    bool CreateClassInstance(SQClass *theclass, SQObjectPtr &inst, SQObjectPtr &constructor);\n    //call a generic closure pure SQUIRREL or NATIVE\n    bool Call(SQObjectPtr &closure, SQInteger nparams, SQInteger stackbase, SQObjectPtr &outres,SQBool raiseerror);\n    SQRESULT Suspend();\n\n    void CallDebugHook(SQInteger type,SQInteger forcedline=0);\n    void CallErrorHandler(SQObjectPtr &e);\n    bool Get(const SQObjectPtr &self, const SQObjectPtr &key, SQObjectPtr &dest, SQUnsignedInteger getflags, SQInteger selfidx);\n    SQInteger FallBackGet(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest);\n    bool InvokeDefaultDelegate(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest);\n    bool Set(const SQObjectPtr &self, const SQObjectPtr &key, const SQObjectPtr &val, SQInteger selfidx);\n    SQInteger FallBackSet(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val);\n    bool NewSlot(const SQObjectPtr &self, const SQObjectPtr &key, const SQObjectPtr &val,bool bstatic);\n    bool NewSlotA(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val,const SQObjectPtr &attrs,bool bstatic,bool raw);\n    bool DeleteSlot(const SQObjectPtr &self, const SQObjectPtr &key, SQObjectPtr &res);\n    bool Clone(const SQObjectPtr &self, SQObjectPtr &target);\n    bool ObjCmp(const SQObjectPtr &o1, const SQObjectPtr &o2,SQInteger &res);\n    bool StringCat(const SQObjectPtr &str, const SQObjectPtr &obj, SQObjectPtr &dest);\n    static bool IsEqual(const SQObjectPtr &o1,const SQObjectPtr &o2,bool &res);\n    bool ToString(const SQObjectPtr &o,SQObjectPtr &res);\n    SQString *PrintObjVal(const SQObjectPtr &o);\n\n\n    void Raise_Error(const SQChar *s, ...);\n    void Raise_Error(const SQObjectPtr &desc);\n    void Raise_IdxError(const SQObjectPtr &o);\n    void Raise_CompareError(const SQObject &o1, const SQObject &o2);\n    void Raise_ParamTypeError(SQInteger nparam,SQInteger typemask,SQInteger type);\n\n    void FindOuter(SQObjectPtr &target, SQObjectPtr *stackindex);\n    void RelocateOuters();\n    void CloseOuters(SQObjectPtr *stackindex);\n\n    bool TypeOf(const SQObjectPtr &obj1, SQObjectPtr &dest);\n    bool CallMetaMethod(SQObjectPtr &closure, SQMetaMethod mm, SQInteger nparams, SQObjectPtr &outres);\n    bool ArithMetaMethod(SQInteger op, const SQObjectPtr &o1, const SQObjectPtr &o2, SQObjectPtr &dest);\n    bool Return(SQInteger _arg0, SQInteger _arg1, SQObjectPtr &retval);\n    //new stuff\n    _INLINE bool ARITH_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2);\n    _INLINE bool BW_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2);\n    _INLINE bool NEG_OP(SQObjectPtr &trg,const SQObjectPtr &o1);\n    _INLINE bool CMP_OP(CmpOP op, const SQObjectPtr &o1,const SQObjectPtr &o2,SQObjectPtr &res);\n    bool CLOSURE_OP(SQObjectPtr &target, SQFunctionProto *func);\n    bool CLASS_OP(SQObjectPtr &target,SQInteger base,SQInteger attrs);\n    //return true if the loop is finished\n    bool FOREACH_OP(SQObjectPtr &o1,SQObjectPtr &o2,SQObjectPtr &o3,SQObjectPtr &o4,SQInteger arg_2,int exitpos,int &jump);\n    //_INLINE bool LOCAL_INC(SQInteger op,SQObjectPtr &target, SQObjectPtr &a, SQObjectPtr &incr);\n    _INLINE bool PLOCAL_INC(SQInteger op,SQObjectPtr &target, SQObjectPtr &a, SQObjectPtr &incr);\n    _INLINE bool DerefInc(SQInteger op,SQObjectPtr &target, SQObjectPtr &self, SQObjectPtr &key, SQObjectPtr &incr, bool postfix,SQInteger arg0);\n#ifdef _DEBUG_DUMP\n    void dumpstack(SQInteger stackbase=-1, bool dumpall = false);\n#endif\n\n#ifndef NO_GARBAGE_COLLECTOR\n    void Mark(SQCollectable **chain);\n    SQObjectType GetType() {return OT_THREAD;}\n#endif\n    void Finalize();\n    void GrowCallStack() {\n        SQInteger newsize = _alloccallsstacksize*2;\n        _callstackdata.resize(newsize);\n        _callsstack = &_callstackdata[0];\n        _alloccallsstacksize = newsize;\n    }\n    bool EnterFrame(SQInteger newbase, SQInteger newtop, bool tailcall);\n    void LeaveFrame();\n    void Release(){ sq_delete(this,SQVM); }\n    void CheckStackAccess(SQInteger n);\n////////////////////////////////////////////////////////////////////////////\n    //stack functions for the api\n    void Remove(SQInteger n);\n\n    static bool IsFalse(SQObjectPtr &o);\n\n    void Pop();\n    void Pop(SQInteger n);\n    void Push(const SQObjectPtr &o);\n    void PushNull();\n    SQObjectPtr &Top();\n    SQObjectPtr &PopGet();\n    SQObjectPtr &GetUp(SQInteger n);\n    SQObjectPtr &GetAt(SQInteger n);\n\n    SQObjectPtrVec _stack;\n\n    SQInteger _top;\n    SQInteger _stackbase;\n    SQOuter *_openouters;\n    SQObjectPtr _roottable;\n    SQObjectPtr _lasterror;\n    SQObjectPtr _errorhandler;\n\n    bool _debughook;\n    SQDEBUGHOOK _debughook_native;\n    SQObjectPtr _debughook_closure;\n\n    SQObjectPtr temp_reg;\n\n\n    CallInfo* _callsstack;\n    SQInteger _callsstacksize;\n    SQInteger _alloccallsstacksize;\n    sqvector<CallInfo>  _callstackdata;\n\n    ExceptionsTraps _etraps;\n    CallInfo *ci;\n    SQUserPointer _foreignptr;\n    //VMs sharing the same state\n    SQSharedState *_sharedstate;\n    SQInteger _nnativecalls;\n    SQInteger _nmetamethodscall;\n    SQRELEASEHOOK _releasehook;\n    //suspend infos\n    SQBool _suspended;\n    SQBool _suspended_root;\n    SQInteger _suspended_target;\n    SQInteger _suspended_traps;\n};\n\nstruct AutoDec{\n    AutoDec(SQInteger *n) { _n = n; }\n    ~AutoDec() { (*_n)--; }\n    SQInteger *_n;\n};\n\ninline SQObjectPtr &stack_get(HSQUIRRELVM v,SQInteger idx){return ((idx>=0)?(v->GetAt(idx+v->_stackbase-1)):(v->GetUp(idx)));}\n\n#define _ss(_vm_) (_vm_)->_sharedstate\n\n#ifndef NO_GARBAGE_COLLECTOR\n#define _opt_ss(_vm_) (_vm_)->_sharedstate\n#else\n#define _opt_ss(_vm_) NULL\n#endif\n\n#define PUSH_CALLINFO(v,nci){ \\\n    SQInteger css = v->_callsstacksize; \\\n    if(css == v->_alloccallsstacksize) { \\\n        v->GrowCallStack(); \\\n    } \\\n    v->ci = &v->_callsstack[css]; \\\n    *(v->ci) = nci; \\\n    v->_callsstacksize++; \\\n}\n\n#define POP_CALLINFO(v){ \\\n    SQInteger css = --v->_callsstacksize; \\\n    v->ci->_closure.Null(); \\\n    v->ci = css?&v->_callsstack[css-1]:NULL;    \\\n}\n#endif //_SQVM_H_\n"
  },
  {
    "path": "extlibs/squirrel/squirrel.dsw",
    "content": "Microsoft Developer Studio Workspace File, Format Version 6.00\n# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!\n\n###############################################################################\n\nProject: \"sq\"=.\\sq\\sq.dsp - Package Owner=<4>\n\nPackage=<5>\n{{{\n    begin source code control\n    .\n    end source code control\n}}}\n\nPackage=<4>\n{{{\n    Begin Project Dependency\n    Project_Dep_Name sqlibs\n    End Project Dependency\n    Begin Project Dependency\n    Project_Dep_Name squirrel\n    End Project Dependency\n    Begin Project Dependency\n    Project_Dep_Name sqstdlib\n    End Project Dependency\n}}}\n\n###############################################################################\n\nProject: \"sqstdlib\"=.\\sqstdlib\\sqstdlib.dsp - Package Owner=<4>\n\nPackage=<5>\n{{{\n    begin source code control\n    \"$/squirrel\", HAAAAAAA\n    .\n    end source code control\n}}}\n\nPackage=<4>\n{{{\n}}}\n\n###############################################################################\n\nProject: \"squirrel\"=.\\squirrel\\squirrel.dsp - Package Owner=<4>\n\nPackage=<5>\n{{{\n    begin source code control\n    \"$/squirrel\", HAAAAAAA\n    .\n    end source code control\n}}}\n\nPackage=<4>\n{{{\n}}}\n\n###############################################################################\n\nGlobal:\n\nPackage=<5>\n{{{\n    begin source code control\n    \"$/squirrel\", HAAAAAAA\n    .\n    end source code control\n}}}\n\nPackage=<3>\n{{{\n}}}\n\n###############################################################################\n\n"
  },
  {
    "path": "include/engge/Audio/SoundCategory.hpp",
    "content": "#pragma once\n\nnamespace ng {\nenum class SoundCategory {\n  Music,\n  Sound,\n  Talk\n};\n}\n"
  },
  {
    "path": "include/engge/Audio/SoundDefinition.hpp",
    "content": "#pragma once\n#include <iostream>\n#include <memory>\n#include <string>\n#include <ngf/Audio/SoundBuffer.h>\n#include \"engge/Engine/Function.hpp\"\n#include \"engge/Scripting/ScriptObject.hpp\"\n\nnamespace ng {\nclass SoundId;\n\nclass Sound : public ScriptObject {\npublic:\n  ~Sound() override;\n};\n\nclass SoundDefinition final : public Sound {\n  friend class SoundId;\n  friend class SoundManager;\n\npublic:\n  explicit SoundDefinition(std::string path);\n  ~SoundDefinition() final;\n\n  [[nodiscard]] std::string getPath() const { return m_path; };\n\n  void load();\n\nprivate:\n  std::string m_path;\n  bool m_isLoaded{false};\n  ngf::SoundBuffer m_buffer;\n};\n} // namespace ng"
  },
  {
    "path": "include/engge/Audio/SoundId.hpp",
    "content": "#pragma once\n#include <memory>\n#include <ngf/Audio/SoundHandle.h>\n#include <engge/Engine/ChangeProperty.hpp>\n#include \"SoundCategory.hpp\"\n#include \"SoundDefinition.hpp\"\n\nnamespace ng {\nclass Entity;\nclass SoundManager;\n\nclass SoundId final : public Sound {\npublic:\n  explicit SoundId(SoundManager &soundManager,\n                   std::shared_ptr<SoundDefinition> soundDefinition,\n                   std::shared_ptr<ngf::SoundHandle> sound,\n                   SoundCategory category,\n                   int entityId = 0);\n  ~SoundId() final;\n\n  std::shared_ptr<ng::SoundDefinition> getSoundDefinition() { return m_soundDefinition; }\n  std::shared_ptr<ngf::SoundHandle> getSoundHandle() { return m_sound; }\n  [[nodiscard]] SoundCategory getSoundCategory() const { return m_category; }\n\n  [[nodiscard]] bool isPlaying() const;\n  void stop(const ngf::TimeSpan &fadeOutTime = ngf::TimeSpan::Zero);\n\n  void update(const ngf::TimeSpan &elapsed);\n\nprivate:\n  void updateVolume();\n\nprivate:\n  SoundManager &m_soundManager;\n  std::shared_ptr<SoundDefinition> m_soundDefinition{};\n  std::shared_ptr<ngf::SoundHandle> m_sound{};\n  SoundCategory m_category;\n  const int m_entityId{0};\n};\n} // namespace ng\n"
  },
  {
    "path": "include/engge/Audio/SoundManager.hpp",
    "content": "#pragma once\n#include <array>\n#include <memory>\n#include <vector>\n#include \"SoundCategory.hpp\"\n#include \"SoundId.hpp\"\n#include \"SoundDefinition.hpp\"\n\nnamespace ng {\nclass Entity;\nclass Engine;\nclass SoundDefinition;\nclass SoundId;\n\nclass SoundManager {\npublic:\n  SoundManager();\n\n  void setEngine(Engine *pEngine) { m_pEngine = pEngine; }\n  [[nodiscard]] Engine *getEngine() const { return m_pEngine; }\n\n  std::shared_ptr<SoundDefinition> defineSound(const std::string &name);\n  std::shared_ptr<SoundId> playSound(std::shared_ptr<SoundDefinition> soundDefinition,\n                                     int loopTimes = 1,\n                                     const ngf::TimeSpan &fadeInTime = ngf::TimeSpan::Zero,\n                                     int id = 0);\n  std::shared_ptr<SoundId> playTalkSound(std::shared_ptr<SoundDefinition> soundDefinition,\n                                         int loopTimes = 1,\n                                         const ngf::TimeSpan &fadeInTime = ngf::TimeSpan::Zero,\n                                         int id = 0);\n  std::shared_ptr<SoundId> playMusic(std::shared_ptr<SoundDefinition> soundDefinition,\n                                     int loopTimes = 1,\n                                     const ngf::TimeSpan &fadeInTime = ngf::TimeSpan::Zero);\n\n  void pauseAllSounds();\n  void resumeAllSounds();\n\n  void stopAllSounds();\n  void stopSound(std::shared_ptr<SoundDefinition> soundDefinition);\n\n  void setMasterVolume(float volume) { m_masterVolume = std::clamp(volume, 0.f, 1.f); }\n  [[nodiscard]] float getMasterVolume() const { return m_masterVolume; }\n  void setSoundVolume(float volume) { m_soundVolume = std::clamp(volume, 0.f, 1.f); }\n  [[nodiscard]] float getSoundVolume() const { return m_soundVolume; }\n  void setMusicVolume(float volume) { m_musicVolume = std::clamp(volume, 0.f, 1.f); }\n  [[nodiscard]] float getMusicVolume() const { return m_musicVolume; }\n  void setTalkVolume(float volume) { m_talkVolume = std::clamp(volume, 0.f, 1.f); }\n  [[nodiscard]] float getTalkVolume() const { return m_talkVolume; }\n  void setVolume(const SoundDefinition *pSoundDefinition, float volume);\n\n  std::shared_ptr<SoundId> getSound(size_t index);\n  std::vector<std::shared_ptr<SoundDefinition>> &getSoundDefinitions() { return m_sounds; }\n  std::array<std::shared_ptr<SoundId>, 32> &getSounds() { return m_soundIds; }\n\n  void setSoundHover(std::shared_ptr<SoundDefinition> sound) { m_pSoundHover = sound; }\n  [[nodiscard]] std::shared_ptr<SoundDefinition> getSoundHover() const { return m_pSoundHover; }\n\n  [[nodiscard]] size_t getSize() const { return m_soundIds.size(); }\n\n  void update(const ngf::TimeSpan &elapsed);\n\nprivate:\n  std::shared_ptr<SoundId> play(std::shared_ptr<SoundDefinition> soundDefinition,\n                                SoundCategory category,\n                                int loopTimes = 1,\n                                const ngf::TimeSpan &fadeInTime = ngf::TimeSpan::Zero,\n                                int id = 0);\n\nprivate:\n  std::vector<std::shared_ptr<SoundDefinition>> m_sounds;\n  std::array<std::shared_ptr<SoundId>, 32> m_soundIds;\n  Engine *m_pEngine{nullptr};\n  float m_masterVolume{1};\n  float m_soundVolume{1};\n  float m_musicVolume{1};\n  float m_talkVolume{1};\n  std::shared_ptr<SoundDefinition> m_pSoundHover{nullptr};\n};\n} // namespace ng"
  },
  {
    "path": "include/engge/Audio/SoundTrigger.hpp",
    "content": "#pragma once\n#include <memory>\n#include <random>\n#include <vector>\n#include \"engge/Engine/Trigger.hpp\"\n\nnamespace ng {\nclass Entity;\nclass Engine;\nclass SoundDefinition;\nclass SoundId;\nclass SoundTrigger final : public Trigger {\npublic:\n  SoundTrigger(Engine &engine, const std::vector<std::shared_ptr<SoundDefinition>> &sounds, int id);\n  ~SoundTrigger() final;\n\n  std::string getName() final;\n\nprivate:\n  void trigCore() final;\n\nprivate:\n  Engine &m_engine;\n  int m_id{0};\n  std::vector<std::shared_ptr<SoundDefinition>> m_soundsDefinitions;\n  std::vector<int> m_sounds;\n  std::default_random_engine m_defaultRandomEngine;\n  std::uniform_int_distribution<int> m_distribution;\n  std::string m_name;\n};\n}\n"
  },
  {
    "path": "include/engge/Dialog/ConditionVisitor.hpp",
    "content": "#pragma once\n#include \"engge/Parsers/YackParser.hpp\"\n\nnamespace ng{\n\nclass DialogConditionAbstract;\n\nclass ConditionVisitor final : public Ast::AstVisitor {\npublic:\n  explicit ConditionVisitor(const DialogConditionAbstract &context);\n  [[nodiscard]] bool isAccepted() const { return m_isAccepted; }\n\nprivate:\n  void visit(const Ast::CodeCondition &node) override;\n  void visit(const Ast::OnceCondition &node) override;\n  void visit(const Ast::ShowOnceCondition &node) override;\n  void visit(const Ast::OnceEverCondition &node) override;\n  void visit(const Ast::TempOnceCondition &node) override;\n\nprivate:\n  const DialogConditionAbstract &m_context;\n  bool m_isAccepted{true};\n};\n}"
  },
  {
    "path": "include/engge/Dialog/DialogConditionAbstract.hpp",
    "content": "#pragma once\n#include <cstdint>\n#include <string>\n\nnamespace ng {\nclass DialogConditionAbstract {\npublic:\n  virtual ~DialogConditionAbstract() = default;\n  [[nodiscard]] virtual bool isOnce(int32_t line) const = 0;\n  [[nodiscard]] virtual bool isShowOnce(int32_t line) const = 0;\n  [[nodiscard]] virtual bool isOnceEver(int32_t line) const = 0;\n  [[nodiscard]] virtual bool isTempOnce(int32_t line) const = 0;\n  [[nodiscard]] virtual bool executeCondition(const std::string &condition) const = 0;\n};\n}"
  },
  {
    "path": "include/engge/Dialog/DialogContextAbstract.hpp",
    "content": "#pragma once\n#include <functional>\n#include <string>\n#include <ngf/System/TimeSpan.h>\n\nnamespace ng{\nclass DialogContextAbstract {\npublic:\n  virtual ~DialogContextAbstract()  = default;\n\n  virtual void allowObjects(bool allow) = 0;\n  virtual void dialog(const std::string &actor) = 0;\n  virtual void execute(const std::string &code) = 0;\n  virtual void gotoLabel(const std::string &label) = 0;\n  virtual void limit(int max) = 0;\n  virtual void override(const std::string &label) = 0;\n  virtual void parrot(bool enabled) = 0;\n  virtual std::function<bool()> pause(ngf::TimeSpan seconds) = 0;\n  virtual std::function<bool()> say(const std::string& actor, const std::string &text) = 0;\n  virtual void shutup() = 0;\n  virtual std::function<bool()> waitFor(const std::string &actor) = 0;\n  virtual std::function<bool()> waitWhile(const std::string &condition) = 0;\n};\n}"
  },
  {
    "path": "include/engge/Dialog/DialogManager.hpp",
    "content": "#pragma once\n#include <array>\n#include <optional>\n#include <ngf/Graphics/Drawable.h>\n#include \"engge/Parsers/YackParser.hpp\"\n#include \"engge/Engine/Function.hpp\"\n#include \"DialogPlayer.hpp\"\n#include \"engge/Graphics/GGFont.hpp\"\n#include \"EngineDialogScript.hpp\"\n\nnamespace ng {\nclass Actor;\nclass Engine;\n\nstruct DialogSlot {\n  std::wstring text;\n  const Ast::Statement *pChoice{nullptr};\n  mutable glm::vec2 pos;\n};\n\nclass DialogManager final : public ngf::Drawable {\npublic:\n  void setEngine(Engine *pEngine);\n  void start(const std::string &actor, const std::string &name, const std::string &node);\n  void update(const ngf::TimeSpan &elapsed);\n\n  void setMousePosition(glm::vec2 pos);\n\n  const std::vector<DialogConditionState> &getStates() const { return m_pPlayer->getStates(); }\n  std::vector<DialogConditionState> &getStates() { return m_pPlayer->getStates(); }\n  [[nodiscard]] DialogManagerState getState() const { return m_state; }\n  void choose(int choice);\n\n  void draw(ngf::RenderTarget &target, ngf::RenderStates states) const override;\n\nprivate:\n  void updateChoices(const ngf::TimeSpan &elapsed);\n  void updateDialogSlots();\n  static void onDialogEnded();\n\nprivate:\n  Engine *m_pEngine{nullptr};\n  DialogManagerState m_state{DialogManagerState::None};\n  glm::vec2 m_mousePos{0, 0};\n  std::unique_ptr<EngineDialogScript> m_pEngineDialogScript;\n  std::unique_ptr<DialogPlayer> m_pPlayer;\n  std::array<DialogSlot, 9> m_slots;\n};\n} // namespace ng\n"
  },
  {
    "path": "include/engge/Dialog/DialogPlayer.hpp",
    "content": "#pragma once\n#include <string>\n#include <ngf/System/TimeSpan.h>\n#include \"DialogContextAbstract.hpp\"\n#include \"DialogConditionAbstract.hpp\"\n\nnamespace ng {\n\nenum class DialogManagerState {\n  None,\n  Active,\n  WaitingForChoice\n};\n\nenum class DialogPlayerState {\n  None,\n  Start,\n  Running,\n  WaitingForChoice,\n  WaitingEndAnimation,\n  WaitingForSayingChoice\n};\n\nenum class DialogConditionMode {\n  Once,\n  ShowOnce,\n  OnceEver,\n  ShowOnceEver,\n  TempOnce\n};\n\nstruct DialogConditionState {\npublic:\n  DialogConditionMode mode;\n  std::string actorKey;\n  std::string dialog;\n  int32_t line;\n};\n\nclass DialogScriptAbstract;\nclass DialogPlayer final : public DialogContextAbstract, public DialogConditionAbstract {\nprivate:\n  DialogScriptAbstract &_script;\n\npublic:\n  explicit DialogPlayer(DialogScriptAbstract &script);\n  ~DialogPlayer() override;\n\n  void start(const std::string &actor, const std::string &name, const std::string &node);\n  void choose(int choiceId);\n  void update();\n\n  [[nodiscard]] DialogManagerState getState() const;\n  [[nodiscard]] std::string getActor() const { return m_actor; }\n  [[nodiscard]] std::string getDialogName() const { return m_dialogName; }\n\n  [[nodiscard]] const std::array<const Ast::Statement *, 9> &getChoices() const { return m_choices; }\n  [[nodiscard]] const std::vector<DialogConditionState>& getStates() const { return m_states; }\n  std::vector<DialogConditionState>& getStates() { return m_states; }\n\nprivate:\n  void resetState();\n\n  void selectLabel(const std::string &name);\n  void run(Ast::Statement *pStatement);\n\n  void addChoice(const Ast::Statement *pStatement, const Ast::Choice *pChoice);\n  void clearChoices();\n\n  [[nodiscard]] bool choicesReady() const;\n  bool acceptConditions(const Ast::Statement *pStatement);\n\n  void allowObjects(bool allow) override;\n  void dialog(const std::string &actor) override;\n  void execute(const std::string &code) override;\n  void gotoLabel(const std::string &label) override;\n  void limit(int max) override;\n  void override(const std::string &label) override;\n  void parrot(bool enabled) override;\n  std::function<bool()> pause(ngf::TimeSpan seconds) override;\n  std::function<bool()> say(const std::string &actor, const std::string &text) override;\n  void shutup() override;\n  std::function<bool()> waitFor(const std::string &actor) override;\n  std::function<bool()> waitWhile(const std::string &condition) override;\n\n  [[nodiscard]] bool isOnce(int32_t line) const override;\n  [[nodiscard]] bool isShowOnce(int32_t line) const override;\n  [[nodiscard]] bool isOnceEver(int32_t line) const override;\n  [[nodiscard]] bool isTempOnce(int32_t line) const override;\n  [[nodiscard]] bool executeCondition(const std::string &condition) const override;\n\n  void running();\n  bool gotoNextLabel();\n  void endDialog();\n\nprivate:\n  std::string m_dialogName;\n  std::unique_ptr<Ast::CompilationUnit> m_pCompilationUnit;\n  std::array<const Ast::Statement *, 9> m_choices{};\n  Ast::Label *m_pLabel{nullptr};\n  int m_currentStatement{0};\n  DialogPlayerState m_state{DialogPlayerState::None};\n  std::string m_actor;\n  bool m_parrot{true};\n  bool m_allowObjects{false};\n  int m_limit{6};\n  std::string m_overrideLabel;\n  std::function<bool()> m_pWaitAction{nullptr};\n  std::vector<DialogConditionState> m_states;\n  std::string m_nextLabel;\n};\n}"
  },
  {
    "path": "include/engge/Dialog/DialogScriptAbstract.hpp",
    "content": "#pragma once\n#include <functional>\n\nnamespace ng {\nclass DialogScriptAbstract {\npublic:\n  virtual ~DialogScriptAbstract() = default;\n  virtual std::function<bool()> pause(ngf::TimeSpan seconds) = 0;\n  virtual std::function<bool()> say(const std::string &actor, const std::string &text) = 0;\n  virtual void shutup() = 0;\n  virtual std::function<bool()> waitFor(const std::string &actor) = 0;\n  virtual std::function<bool()> waitWhile(const std::string &condition) = 0;\n  virtual void execute(const std::string &code) = 0;\n  [[nodiscard]] virtual bool executeCondition(const std::string &condition) const = 0;\n};\n}"
  },
  {
    "path": "include/engge/Dialog/EngineDialogScript.hpp",
    "content": "#pragma once\n#include <functional>\n#include <utility>\n#include \"DialogScriptAbstract.hpp\"\n\nnamespace ng {\nclass Engine;\n\nclass EngineDialogScript final : public DialogScriptAbstract {\npublic:\n  explicit EngineDialogScript(Engine &engine);\n  ~EngineDialogScript() final = default;\n\nprivate:\n  std::function<bool()> pause(ngf::TimeSpan time) final;\n  std::function<bool()> say(const std::string &actor, const std::string &text) final;\n  void shutup() final;\n  std::function<bool()> waitFor(const std::string &actor) final;\n  std::function<bool()> waitWhile(const std::string &condition) final;\n  void execute(const std::string &code) final;\n  [[nodiscard]] bool executeCondition(const std::string &condition) const final;\n\nprivate:\n  Engine &m_engine;\n};\n}"
  },
  {
    "path": "include/engge/Dialog/ExpressionVisitor.hpp",
    "content": "#pragma once\n#include <functional>\n#include \"engge/Parsers/YackParser.hpp\"\n\nnamespace ng {\nclass DialogContextAbstract;\nclass ExpressionVisitor final : public Ast::AstVisitor {\npublic:\n  explicit ExpressionVisitor(DialogContextAbstract &ctx);\n  ~ExpressionVisitor() final;\n\n  [[nodiscard]] const std::function<bool()>& getWaitAction() const { return m_pWaitAction; }\n\nprivate:\n  void visit(const Ast::Say &node) final;\n  void visit(const Ast::Code &node) final;\n  void visit(const Ast::Goto &node) final;\n  void visit(const Ast::Shutup &) final;\n  void visit(const Ast::Pause &node) final;\n  void visit(const Ast::WaitFor &node) final;\n  void visit(const Ast::Parrot &node) final;\n  void visit(const Ast::Dialog &node) final;\n  void visit(const Ast::Override &node) final;\n  void visit(const Ast::AllowObjects &node) final;\n  void visit(const Ast::WaitWhile &node) final;\n  void visit(const Ast::Limit &node) final;\n\nprivate:\n  DialogContextAbstract &m_context;\n  std::function<bool()> m_pWaitAction{nullptr};\n};\n}"
  },
  {
    "path": "include/engge/EnggeApplication.hpp",
    "content": "#pragma once\n#include <ngf/Application.h>\n#include <ngf/System/Event.h>\n#include <ngf/System/TimeSpan.h>\n#include <ngf/Graphics/RenderTarget.h>\n#include <ngf/Graphics/RenderStates.h>\n#include <engge/System/Services.hpp>\n#include <engge/Engine/Camera.hpp>\n#include <engge/Scripting/ScriptEngine.hpp>\n#include <glm/vec2.hpp>\n#include \"System/DebugTools/DebugTools.hpp\"\n\nnamespace ng {\n\nclass Engine;\n\nclass EnggeApplication final : public ngf::Application {\npublic:\n  ngf::AudioSystem &getAudioSystem() { return m_audioSystem; }\n\nprivate:\n  void onInit() final;\n  void onEvent(ngf::Event &event) final;\n  void onRender(ngf::RenderTarget &target) final;\n  void onImGuiRender() final;\n  void onUpdate(const ngf::TimeSpan &elapsed) final;\n  void onQuit() final;\n\nprivate:\n  ng::Engine *m_engine{nullptr};\n  bool m_init{false};\n  glm::ivec2 m_pos;\n  bool m_isMousePressed{false};\n  bool m_isKeyPressed{false};\n  std::unique_ptr<DebugTools> m_debugTools;\n};\n}\n"
  },
  {
    "path": "include/engge/Engine/ActorIconSlot.hpp",
    "content": "#pragma once\n\nnamespace ng {\nclass Actor;\nstruct ActorIconSlot {\n  bool selectable{false};\n  Actor *pActor{nullptr};\n};\n} // namespace ng\n"
  },
  {
    "path": "include/engge/Engine/ActorIcons.hpp",
    "content": "#pragma once\n#include <ngf/System/StopWatch.h>\n#include \"ActorIconSlot.hpp\"\n#include \"Verb.hpp\"\n#include \"Hud.hpp\"\n\nnamespace ng {\nenum class ActorSlotSelectableMode {\n  Off = 0,\n  On = 1,\n  TemporaryUnselectable = 2,\n};\n\nclass Engine;\nclass ActorIcons final : public ngf::Drawable {\npublic:\n  ActorIcons(std::array<ActorIconSlot, 6> &actorsIconSlots, Hud &hud,\n             Actor *&pCurrentActor);\n\n  void setEngine(Engine *pEngine);\n  void setMousePosition(const glm::vec2 &pos);\n  void update(const ngf::TimeSpan &elapsed);\n  [[nodiscard]] bool isMouseOver() const { return m_isInside; }\n  void flash(bool on);\n  void setMode(ActorSlotSelectableMode mode);\n  [[nodiscard]] inline ActorSlotSelectableMode getMode() const { return m_mode; }\n  void setVisible(bool visible) { m_visible = visible; }\n\n  void draw(ngf::RenderTarget &target, ngf::RenderStates states) const final;\n\nprivate:\n  void drawActorIcon(ngf::RenderTarget &target, const std::string &icon, int actorSlot, const glm::vec2 &offset,\n                     float alpha) const;\n  static void drawActorIcon(ngf::RenderTarget &target,\n                            const std::string &icon,\n                            ngf::Color backColor,\n                            ngf::Color frameColor,\n                            const glm::vec2 &offset,\n                            float alpha);\n  [[nodiscard]] int getCurrentActorIndex() const;\n  [[nodiscard]] int getIconsNum() const;\n  [[nodiscard]] float getOffsetY(int num) const;\n  static bool isSelectable(const ActorIconSlot &slot);\n\nprivate:\n  Engine *m_pEngine{nullptr};\n  std::array<ActorIconSlot, 6> &m_actorsIconSlots;\n  Hud &m_hud;\n  Actor *&m_pCurrentActor;\n  glm::vec2 m_mousePos{0, 0};\n  ngf::StopWatch m_clock;\n  bool m_isInside{false};\n  bool m_on{true};\n  float m_position{0};\n  bool m_isMouseButtonPressed{false};\n  ngf::TimeSpan m_time;\n  float m_alpha{0};\n  ActorSlotSelectableMode m_mode{ActorSlotSelectableMode::On};\n  bool m_visible{true};\n};\n} // namespace ng\n"
  },
  {
    "path": "include/engge/Engine/Callback.hpp",
    "content": "#pragma once\n#include <string>\n#include <vector>\n#include <squirrel.h>\n#include <ngf/System/TimeSpan.h>\n#include <engge/Engine/TimeFunction.hpp>\n\nnamespace ng {\nclass Callback final : public TimeFunction {\npublic:\n  Callback(int id, ngf::TimeSpan duration, std::string method, HSQOBJECT arg);\n  ~Callback() final;\n\n  [[nodiscard]] int getId() const { return m_id; }\n  [[nodiscard]] const std::string& getMethod() const { return m_method; }\n  [[nodiscard]] HSQOBJECT getArgument() const { return m_arg; }\n\nprivate:\n  void onElapsed() final;\n\nprivate:\n  bool m_callbackDone{false};\n  int m_id{0};\n  std::string m_method{};\n  HSQOBJECT m_arg;\n};\n}\n"
  },
  {
    "path": "include/engge/Engine/Camera.hpp",
    "content": "#pragma once\n#include <memory>\n#include <optional>\n#include \"Interpolations.hpp\"\n#include <glm/vec2.hpp>\n#include <ngf/System/TimeSpan.h>\n#include <ngf/Graphics/Rect.h>\n\nnamespace ng {\nclass Engine;\nclass Camera {\npublic:\n  Camera();\n  virtual ~Camera();\n\n  /// @brief Pans the camera to the target position in a specified time using a given interpolation.\n  /// \\param target Position where the camera needs to go.\n  /// \\param time Time needed for the camera to reach the target position.\n  /// \\param interpolation Interpolation method to use between the current position and the target position.\n  void panTo(glm::vec2 target, ngf::TimeSpan time, InterpolationMethod interpolation);\n\n  /// @brief Sets the position of the camera.\n  /// @details The position is the center of the camera.\n  /// \\param at Position of the camera to set.\n  void at(const glm::vec2 &at);\n\n  /// @brief Gets the position of the camera.\n  /// @details The position is the center of the camera.\n  /// \\return The current position of the camera.\n  [[nodiscard]] glm::vec2 getAt() const;\n\n  /// @brief Gets the rectangle of the camera.\n  [[nodiscard]] ngf::frect getRect() const;\n\n  void move(const glm::vec2 &offset);\n  [[nodiscard]] bool isMoving() const;\n\n  void setBounds(const ngf::irect &cameraBounds);\n  [[nodiscard]] std::optional<ngf::irect> getBounds() const;\n  void resetBounds();\n\n  void setEngine(Engine *pEngine);\n  void update(const ngf::TimeSpan &elapsed);\n\nprivate:\n  struct Impl;\n  std::unique_ptr<Impl> m_pImpl;\n};\n} // namespace ng"
  },
  {
    "path": "include/engge/Engine/ChangeProperty.hpp",
    "content": "#pragma once\n#include <functional>\n#include <ngf/System/TimeSpan.h>\n#include <engge/Engine/TimeFunction.hpp>\n#include <engge/Engine/Interpolations.hpp>\n\nnamespace ng {\ntemplate<typename Value>\nclass ChangeProperty : public TimeFunction {\npublic:\n  ChangeProperty(std::function<Value()> get,\n                 std::function<void(const Value &)> set,\n                 Value destination,\n                 const ngf::TimeSpan &time,\n                 InterpolationMethod method = InterpolationMethod::Linear)\n      : TimeFunction(time),\n        m_get(get),\n        m_set(set),\n        m_destination(destination),\n        m_init(get()),\n        m_delta(m_destination - m_init),\n        m_current(m_init) {\n    m_anim = InterpolationHelper::getInterpolationMethod(method);\n    m_isLooping =\n        ((method & InterpolationMethod::Looping) | (method & InterpolationMethod::Swing)) != InterpolationMethod::None;\n    m_isSwing = (method & InterpolationMethod::Swing) != InterpolationMethod::None;\n  }\n\n  void operator()(const ngf::TimeSpan &elapsed) override {\n    TimeFunction::operator()(elapsed);\n    m_set(m_current);\n    if (!isElapsed()) {\n      auto t = m_elapsed.getTotalSeconds() / m_time.getTotalSeconds();\n      auto f = m_dirForward ? m_anim(t) : 1.f - m_anim(t);\n      m_current = m_init + f * m_delta;\n      if (m_elapsed >= m_time && m_isLooping) {\n        m_elapsed = ngf::TimeSpan::seconds(m_elapsed.getTotalSeconds() - m_time.getTotalSeconds());\n        m_dirForward = !m_dirForward;\n      }\n    }\n  }\n\n  bool isElapsed() override {\n    if (!m_isLooping)\n      return TimeFunction::isElapsed();\n    return false;\n  }\n\n  void onElapsed() override {\n    m_set(m_destination);\n  }\n\nprivate:\n  std::function<Value()> m_get;\n  std::function<void(const Value &)> m_set;\n  Value m_destination;\n  Value m_init;\n  Value m_delta;\n  Value m_current;\n  std::function<float(float)> m_anim;\n  bool m_isLooping{false};\n  bool m_isSwing{false};\n  bool m_dirForward{true};\n};\n}"
  },
  {
    "path": "include/engge/Engine/Cutscene.hpp",
    "content": "#pragma once\n#include <squirrel.h>\n#include \"Function.hpp\"\n#include \"ThreadBase.hpp\"\n\nnamespace ng {\nclass Actor;\nclass Engine;\nclass Room;\nclass Cutscene final : public ThreadBase, public Function {\npublic:\n  Cutscene(Engine &engine,\n           HSQUIRRELVM v,\n           HSQOBJECT thread,\n           HSQOBJECT closureObj,\n           HSQOBJECT closureCutsceneOverrideObj,\n           HSQOBJECT envObj);\n  ~Cutscene() final;\n\n  [[nodiscard]] HSQUIRRELVM getThread() const final;\n  [[nodiscard]] std::string getName() const final;\n  [[nodiscard]] bool isGlobal() const final { return true; }\n  [[nodiscard]] bool isStopped() const final;\n\npublic:\n  bool isElapsed() final;\n  void operator()(const ngf::TimeSpan &elapsed) final;\n  void cutsceneOverride();\n  [[nodiscard]] bool hasCutsceneOverride() const { return m_hasCutsceneOverride; }\n\nprivate:\n  void startCutscene();\n  void checkEndCutscene();\n  void doCutsceneOverride();\n  void checkEndCutsceneOverride();\n  void endCutscene();\n\nprivate:\n  Engine &m_engine;\n  HSQUIRRELVM m_v{};\n  HSQOBJECT m_threadCutscene{};\n  int m_state{0};\n  HSQOBJECT m_closureObj{};\n  HSQOBJECT m_closureCutsceneOverrideObj{};\n  HSQOBJECT m_envObj{};\n  int m_inputState{0};\n  bool m_hasCutsceneOverride{false};\n};\n} // namespace ng"
  },
  {
    "path": "include/engge/Engine/Engine.hpp",
    "content": "#pragma once\n#include <memory>\n#include <squirrel.h>\n#include <ngf/Graphics/RenderWindow.h>\n#include <ngf/Application.h>\n#include <engge/Engine/ActorIcons.hpp>\n#include <engge/Engine/Callback.hpp>\n#include <engge/Engine/RoomEffect.hpp>\n#include <engge/Engine/SavegameSlot.hpp>\n#include <engge/System/NonCopyable.hpp>\n#include <engge/Input/InputConstants.hpp>\n\nnamespace ng {\nclass Actor;\nclass Camera;\nclass Cutscene;\nclass DialogManager;\nclass EnggeApplication;\nclass Entity;\nclass Function;\nclass Inventory;\nclass Object;\nclass Preferences;\nclass Room;\nclass ScriptExecute;\nclass Sentence;\nclass SoundDefinition;\nclass SoundManager;\nclass ResourceManager;\nclass ThreadBase;\nstruct Verb;\nclass VerbExecute;\n\nenum class UseFlag {\n  None = 0,\n  UseWith = 1,\n  UseOn = 2,\n  UseIn = 3,\n  GiveTo = 4\n};\n\nenum class FadeEffect {\n  None,\n  In,\n  Out,\n  Wobble\n};\n\nstruct FadeEffectParameters {\n  FadeEffect effect{FadeEffect::None};\n  Room *room{nullptr};\n  ngf::TimeSpan duration;\n  ngf::TimeSpan elapsed;\n  glm::vec2 cameraTopLeft{0, 0};\n  float movement{0.f};\n  bool fadeToSepia{false};\n};\n\nenum class WalkboxesFlags {\n  None = 0,\n  Merged = 1,\n  Graph = 2,\n  Walkboxes = 4,\n};\n\nclass Engine : public NonCopyable {\npublic:\n  Engine();\n  ~Engine();\n\n  void setApplication(ng::EnggeApplication *app);\n  [[nodiscard]] const ng::EnggeApplication *getApplication() const;\n  [[nodiscard]] ng::EnggeApplication *getApplication();\n\n  Room *getRoom();\n  SQInteger setRoom(Room *pRoom);\n  SQInteger enterRoomFromDoor(Object *pDoor);\n\n  [[nodiscard]] static std::wstring getText(int id);\n  [[nodiscard]] static std::wstring getText(const std::string &text);\n\n  void addRoom(std::unique_ptr<Room> room);\n  std::vector<std::unique_ptr<Room>> &getRooms();\n\n  void addActor(std::unique_ptr<Actor> actor);\n  std::vector<std::unique_ptr<Actor>> &getActors();\n  void setCurrentActor(Actor *pCurrentActor, bool userSelected);\n  Actor *getCurrentActor();\n  Entity *getEntity(const std::string &name);\n\n  void addCallback(std::unique_ptr<Callback> callback);\n  void removeCallback(int id);\n\n  void addFunction(std::unique_ptr<Function> function);\n  void cutscene(std::unique_ptr<Cutscene> function);\n  [[nodiscard]] bool inCutscene() const;\n  void cutsceneOverride();\n  [[nodiscard]] Cutscene *getCutscene() const;\n\n  void update(const ngf::TimeSpan &elapsed);\n  void draw(ngf::RenderTarget &target, bool screenshot = false) const;\n  [[nodiscard]] int getFrameCounter() const;\n\n  void setWalkboxesFlags(WalkboxesFlags flags);\n  [[nodiscard]] WalkboxesFlags getWalkboxesFlags() const;\n\n  [[nodiscard]] const VerbUiColors *getVerbUiColors(const std::string &name) const;\n  void setVerbExecute(std::unique_ptr<VerbExecute> verbExecute);\n  void setDefaultVerb();\n  [[nodiscard]] const Verb *getActiveVerb() const;\n  void pushSentence(int id, Entity *pObj1, Entity *pObj2);\n  void setSentence(std::unique_ptr<Sentence> sentence);\n  void stopSentence();\n\n  void setInputActive(bool active);\n  [[nodiscard]] bool getInputActive() const;\n  void inputSilentOff();\n  void setInputHUD(bool on);\n  void setInputVerbs(bool on);\n\n  void setInputState(int state);\n  [[nodiscard]] int getInputState() const;\n\n  void setScriptExecute(std::unique_ptr<ScriptExecute> scriptExecute);\n\n  void addThread(std::unique_ptr<ThreadBase> thread);\n  std::vector<std::unique_ptr<ThreadBase>> &getThreads();\n\n  void startDialog(const std::string &dialog, const std::string &node);\n  void execute(const std::string &code);\n  bool executeCondition(const std::string &code);\n  std::string executeDollar(const std::string &code);\n\n  SoundDefinition *getSoundDefinition(const std::string &name);\n\n  [[nodiscard]] glm::vec2 getMousePositionInRoom() const;\n\n  Preferences &getPreferences();\n  SoundManager &getSoundManager();\n  DialogManager &getDialogManager();\n  ResourceManager &getResourceManager();\n\n  Camera &getCamera();\n  void follow(Actor *pActor);\n  const Actor *getFollowActor() const;\n\n  void addSelectableActor(int index, Actor *pActor);\n  void actorSlotSelectable(Actor *pActor, bool selectable);\n  void actorSlotSelectable(int index, bool selectable);\n  void setActorSlotSelectable(ActorSlotSelectableMode mode);\n  [[nodiscard]] ActorSlotSelectableMode getActorSlotSelectable() const;\n  bool isActorSelectable(Actor *pActor) const;\n  void setUseFlag(UseFlag flag, Entity *object);\n  void flashSelectableActor(bool on);\n\n  [[nodiscard]] ngf::TimeSpan getTime() const;\n\n  HSQOBJECT &getDefaultObject();\n\n  /// Fades the screen with the specified effect and duration.\n  /// \\param effect: Effect to use to fade the screen.\n  /// \\param duration: Duration of the effect.\n  void fadeTo(FadeEffect effect, const ngf::TimeSpan &duration);\n  FadeEffectParameters &getFadeParameters();\n\n  void keyDown(const Input &key);\n  void keyUp(const Input &key);\n\n  void sayLineAt(glm::ivec2 pos, ngf::Color color, ngf::TimeSpan duration, const std::string &text);\n  void sayLineAt(glm::ivec2 pos, Entity &entity, const std::string &text);\n  void stopTalking() const;\n  void stopTalkingExcept(Entity *pEntity) const;\n\n  void showOptions(bool visible);\n  void quit();\n  void run();\n\n  Inventory &getInventory();\n  Hud &getHud();\n\n  void saveGame(int slot);\n  void loadGame(int slot);\n  static void getSlotSavegames(std::vector<SavegameSlot> &slots);\n  void setAutoSave(bool autosave);\n  [[nodiscard]] bool getAutoSave() const;\n  void allowSaveGames(bool allow);\n\npublic:\n  RoomEffect roomEffect;\n\nprivate:\n  struct Impl;\n  std::unique_ptr<Impl> m_pImpl;\n};\n} // namespace ng\n"
  },
  {
    "path": "include/engge/Engine/EngineCommands.hpp",
    "content": "#pragma once\n\nnamespace ng::EngineCommands {\nstatic const char *SkipText = \"SkipText\";\nstatic const char *SkipCutscene = \"SkipCutscene\";\nstatic const char *PauseGame = \"PauseGame\";\nstatic const char *SelectActor1 = \"SelectActor1\";\nstatic const char *SelectActor2 = \"SelectActor2\";\nstatic const char *SelectActor3 = \"SelectActor3\";\nstatic const char *SelectActor4 = \"SelectActor4\";\nstatic const char *SelectActor5 = \"SelectActor5\";\nstatic const char *SelectActor6 = \"SelectActor6\";\nstatic const char *SelectChoice1 = \"SelectChoice1\";\nstatic const char *SelectChoice2 = \"SelectChoice2\";\nstatic const char *SelectChoice3 = \"SelectChoice3\";\nstatic const char *SelectChoice4 = \"SelectChoice4\";\nstatic const char *SelectChoice5 = \"SelectChoice5\";\nstatic const char *SelectChoice6 = \"SelectChoice6\";\nstatic const char *SelectPreviousActor = \"SelectPreviousActor\";\nstatic const char *SelectNextActor = \"SelectNextActor\";\nstatic const char *ShowOptions = \"ShowOptions\";\nstatic const char *ToggleHud = \"ToggleHud\";\nstatic const char *ToggleDebug = \"ToggleDebug\";\nstatic const char *ShowHotspots = \"ShowHotspot\";\n}"
  },
  {
    "path": "include/engge/Engine/EngineSettings.hpp",
    "content": "#pragma once\n#include <string>\n#include <vector>\n#include <memory>\n#include <filesystem>\n#include <ngf/IO/GGPackValue.h>\n#include <ngf/IO/GGPack.h>\n\nnamespace ng {\nclass EngineSettings {\npublic:\n  using iterator = std::vector<std::unique_ptr<ngf::GGPack>>::iterator;\n  using const_iterator = std::vector<std::unique_ptr<ngf::GGPack>>::const_iterator;\n\npublic:\n  [[nodiscard]] std::filesystem::path getPath() const;\n  void loadPacks();\n\n  [[nodiscard]] int getPackCount() const { return static_cast<int>(m_packs.size()); }\n\n  bool hasEntry(const std::string &name);\n  [[nodiscard]] std::vector<char> readBuffer(const std::string &name) const;\n  [[nodiscard]] ngf::GGPackValue readEntry(const std::string &name) const;\n\n  iterator begin() { return m_packs.begin(); }\n  iterator end() { return m_packs.end(); }\n\n  [[nodiscard]] const_iterator cbegin() const { return m_packs.cbegin(); }\n  [[nodiscard]] const_iterator cend() const { return m_packs.cend(); }\n\nprivate:\n  std::vector<std::unique_ptr<ngf::GGPack>> m_packs;\n};\n} // namespace ng\n"
  },
  {
    "path": "include/engge/Engine/EntityManager.hpp",
    "content": "#pragma once\n#include <squirrel.h>\n#include <engge/Room/Room.hpp>\n#include <engge/Engine/Engine.hpp>\n#include <engge/Engine/Light.hpp>\n#include <engge/Entities/Object.hpp>\n#include <engge/System/Locator.hpp>\n\nnamespace ng {\nclass Actor;\nclass Entity;\nclass Sound;\nclass SoundDefinition;\nclass SoundId;\nclass ThreadBase;\n\nclass EntityManager {\nprivate:\n  static const int START_ACTORID = 1000;\n  static const int END_ACTORID = 2000;\n  static const int START_ROOMID = 2000;\n  static const int END_ROOMID = 3000;\n  static const int START_OBJECTID = 3000;\n  static const int END_OBJECTID = 100000;\n  static const int START_LIGHTID = 100000;\n  static const int END_LIGHTID = 200000;\n  static const int START_SOUNDID = 200000;\n  static const int END_SOUNDID = 300000;\n  static const int START_THREADID = 300000;\n  static const int END_THREADID = 8000000;\n  static const int START_CALLBACKID = 8000000;\n  static const int END_CALLBACKID = 10000000;\n\npublic:\n  inline int getActorId() { return START_ACTORID + m_actorId++; }\n  inline int getRoomId() { return START_ROOMID + m_roomId++; }\n  inline int getObjectId() { return START_OBJECTID + m_objectId++; }\n  inline int getLightId() { return START_LIGHTID + m_lightId++; }\n  inline int getSoundId() { return START_SOUNDID + m_soundId++; }\n  inline int getCallbackId() { return START_CALLBACKID + m_callbackId++; }\n  inline void setCallbackId(int id) { m_callbackId = id - START_CALLBACKID; }\n  inline int getThreadId() { return START_THREADID + m_threadId++; }\n\n  static Actor *getActorFromId(int id);\n  static Room *getRoomFromId(int id);\n  static Object *getObjectFromId(int id);\n  static Sound *getSoundFromId(int id);\n  static ThreadBase *getThreadFromId(int id);\n  static ThreadBase *getThreadFromVm(HSQUIRRELVM v);\n\n  template<typename TScriptObject>\n  static TScriptObject *getScriptObject(HSQUIRRELVM v, SQInteger index);\n  template<typename TScriptObject>\n  static TScriptObject *getScriptObject(HSQUIRRELVM v, HSQOBJECT obj);\n  template<typename TScriptObject>\n  static TScriptObject *getScriptObjectFromId(int id);\n\n  static Entity *getEntity(HSQUIRRELVM v, SQInteger index);\n  static Object *getObject(HSQUIRRELVM v, SQInteger index);\n  static Room *getRoom(HSQUIRRELVM v, SQInteger index);\n  static Actor *getActor(HSQUIRRELVM v, SQInteger index);\n  static SoundId *getSound(HSQUIRRELVM v, SQInteger index);\n  static std::shared_ptr<SoundDefinition> getSoundDefinition(HSQUIRRELVM v, SQInteger index);\n  static std::shared_ptr<SoundDefinition> getSoundDefinition(HSQUIRRELVM v, const std::string &name);\n\n  static bool tryGetLight(HSQUIRRELVM v, SQInteger index, Light *&light);\n\n  static bool isActor(int id) { return isBetween(id, START_ACTORID, END_ACTORID); }\n  static bool isRoom(int id) { return isBetween(id, START_ROOMID, END_ROOMID); }\n  static bool isObject(int id) { return isBetween(id, START_OBJECTID, END_OBJECTID); }\n  static bool isLight(int id) { return isBetween(id, START_LIGHTID, END_LIGHTID); }\n  static bool isSound(int id) { return isBetween(id, START_SOUNDID, END_SOUNDID); }\n  static bool isThread(int id) { return isBetween(id, START_THREADID, END_THREADID); }\n\nprivate:\n  static inline bool isBetween(int id, int min, int max) { return id >= min && id < max; }\n\nprivate:\n  int m_actorId{0};\n  int m_roomId{0};\n  int m_objectId{0};\n  int m_lightId{0};\n  int m_soundId{0};\n  int m_callbackId{0};\n  int m_threadId{0};\n};\n\ntemplate<typename TScriptObject>\nTScriptObject *EntityManager::getScriptObject(HSQUIRRELVM v, HSQOBJECT obj) {\n  sq_pushobject(v, obj);\n  sq_pushstring(v, _SC(\"_id\"), -1);\n  if (SQ_FAILED(sq_rawget(v, -2))) {\n    return nullptr;\n  }\n\n  SQInteger id = 0;\n  if (SQ_FAILED(sq_getinteger(v, -1, &id))) {\n    return nullptr;\n  }\n  sq_pop(v, 2);\n\n  return getScriptObjectFromId<TScriptObject>(id);\n}\n\ntemplate<typename TScriptObject>\nTScriptObject *EntityManager::getScriptObject(HSQUIRRELVM v, SQInteger index) {\n  auto type = sq_gettype(v, index);\n  // is it a table?\n  if (type != OT_TABLE) {\n    return nullptr;\n  }\n\n  HSQOBJECT object;\n  sq_resetobject(&object);\n  if (SQ_FAILED(sq_getstackobj(v, index, &object))) {\n    return nullptr;\n  }\n  return getScriptObject<TScriptObject>(v, object);\n}\n\ntemplate<typename TScriptObject>\nTScriptObject *EntityManager::getScriptObjectFromId(int id) {\n  if (EntityManager::isActor(id)) {\n    return dynamic_cast<TScriptObject *>(getActorFromId(id));\n  }\n\n  if (EntityManager::isRoom(id)) {\n    return dynamic_cast<TScriptObject *>(getRoomFromId(id));\n  }\n\n  if (EntityManager::isLight(id)) {\n    for (auto &&room : ng::Locator<ng::Engine>::get().getRooms()) {\n      for (auto &light : room->getLights()) {\n        if (light.getId() == id)\n          return dynamic_cast<TScriptObject *>(&light);\n      }\n    }\n    return nullptr;\n  }\n\n  if (EntityManager::isObject(id)) {\n    return dynamic_cast<TScriptObject *>(getObjectFromId(id));\n  }\n\n  if (EntityManager::isSound(id)) {\n    return dynamic_cast<TScriptObject *>(getSoundFromId(id));\n  }\n\n  return nullptr;\n}\n\n}\n"
  },
  {
    "path": "include/engge/Engine/ExCommandConstants.hpp",
    "content": "#pragma once\n\nnamespace ExCommandConstants {\nstatic const int EX_ALLOW_SAVEGAMES = 0x01;\nstatic const int EX_POP_CHARACTER_SELECTION = 0x02;\nstatic const int EX_CAMERA_TRACKING = 0x03;\nstatic const int EX_BUTTON_HOVER_SOUND = 0x04;\nstatic const int EX_RESTART = 0x06;\nstatic const int EX_IDLE_TIME = 0x07;\nstatic const int EX_AUTOSAVE = 0x08;\nstatic const int EX_AUTOSAVE_STATE = 0x09;\nstatic const int EX_DISABLE_SAVESYSTEM = 0x0A;\nstatic const int EX_SHOW_OPTIONS = 0x0B;\nstatic const int EX_OPTIONS_MUSIC = 0x0C;\nstatic const int EX_FORCE_TALKIE_TEXT = 0x0D;\n}"
  },
  {
    "path": "include/engge/Engine/Function.hpp",
    "content": "#pragma once\n#include <string>\n#include <functional>\n#include <engge/System/NonCopyable.hpp>\n#include <ngf/System/TimeSpan.h>\n\nnamespace ng {\nclass Function : public NonCopyable {\npublic:\n  virtual bool isElapsed() { return true; }\n  virtual void operator()(const ngf::TimeSpan &) {}\n  virtual ~Function() = default;\n};\n} // namespace ng\n"
  },
  {
    "path": "include/engge/Engine/Hud.hpp",
    "content": "#pragma once\n#include \"engge/Entities/Entity.hpp\"\n#include \"engge/Entities/Actor.hpp\"\n#include \"Verb.hpp\"\n#include \"Inventory.hpp\"\n\nnamespace ng {\nclass Hud final : public ngf::Drawable {\nprivate:\n  enum class State {\n    Off,\n    FadeIn,\n    On,\n    FadeOut\n  };\n\npublic:\n  Hud();\n  ~Hud() final;\n\n  void setTextureManager(ResourceManager *pTextureManager);\n\n  void setVerb(int characterSlot, int verbSlot, const Verb &verb);\n  [[nodiscard]] const VerbSlot &getVerbSlot(int characterSlot) const;\n  [[nodiscard]] const Verb *getVerb(int id) const;\n\n  void setVerbUiColors(int characterSlot, VerbUiColors colors);\n  [[nodiscard]] const VerbUiColors &getVerbUiColors(int characterSlot) const;\n\n  [[nodiscard]] glm::vec2 findScreenPosition(int verbId) const;\n\n  void setCurrentActor(ng::Actor *pActor);\n  void setCurrentActorIndex(int index);\n\n  void setCurrentVerb(const Verb *pVerb) { m_pVerb = pVerb; }\n  void setVerbOverride(const Verb *pVerb) { m_pVerbOverride = pVerb; }\n  [[nodiscard]] const Verb *getCurrentVerb() const { return m_pVerb; }\n  [[nodiscard]] const Verb *getVerbOverride() const { return m_pVerbOverride; }\n  void setHoveredEntity(Entity *pEntity) { m_pHoveredEntity = pEntity; };\n  [[nodiscard]] Entity *getHoveredEntity() const { return m_pHoveredEntity; }\n\n  void setMousePosition(glm::vec2 pos);\n  [[nodiscard]] const Verb *getHoveredVerb() const;\n  bool isMouseOver() const;\n\n  Inventory &getInventory() { return m_inventory; }\n\n  void update(const ngf::TimeSpan &elapsed);\n\n  void setVisible(bool visible) { m_isVisible = visible; }\n  void setActive(bool active);\n  [[nodiscard]] bool getActive() const { return m_active; }\n\n  void draw(ngf::RenderTarget &target, ngf::RenderStates states) const final;\n\nprivate:\n  static std::string getVerbName(const Verb &verb);\n\nprivate:\n  std::array<VerbSlot, 6> m_verbSlots;\n  std::array<VerbUiColors, 6> m_verbUiColors;\n  std::array<ngf::irect, 9> m_verbRects;\n  int m_currentActorIndex{-1};\n  const Verb *m_pVerb{nullptr};\n  const Verb *m_pVerbOverride{nullptr};\n  Entity *m_pHoveredEntity{nullptr};\n  mutable ngf::Shader m_verbShader{};\n  glm::vec2 m_mousePos{0, 0};\n  Inventory m_inventory;\n  bool m_active{false};\n  State m_state{State::Off};\n  float m_alpha{1.f};\n  bool m_isVisible{true};\n};\n}\n"
  },
  {
    "path": "include/engge/Engine/InputStateConstants.hpp",
    "content": "#pragma once\n\nnamespace ng::InputStateConstants {\nstatic const int UI_INPUT_ON = 1;\nstatic const int UI_INPUT_OFF = 2;\nstatic const int UI_VERBS_ON = 4;\nstatic const int UI_VERBS_OFF = 8;\nstatic const int UI_CURSOR_ON = 0x40;\nstatic const int UI_CURSOR_OFF = 0x80;\nstatic const int UI_HUDOBJECTS_ON = 0x10;\nstatic const int UI_HUDOBJECTS_OFF = 0x20;\n}"
  },
  {
    "path": "include/engge/Engine/Interpolations.hpp",
    "content": "#pragma once\n#include <cmath>\n#include <functional>\n\nnamespace ng {\nenum class InterpolationMethod {\n  None = 0,\n  Linear = 1,\n  EaseIn = 2,\n  EaseInOut = 3,\n  EaseOut = 4,\n  SlowEaseIn = 5,\n  SlowEaseOut = 6,\n  Looping = 0x10,\n  Swing = 0x20,\n};\n\ntemplate<class T> inline T operator~(T a) { return (T) ~(int) a; }\ntemplate<class T> inline T operator|(T a, T b) { return (T) ((int) a | (int) b); }\ntemplate<class T> inline T operator&(T a, T b) { return (T) ((int) a & (int) b); }\ntemplate<class T> inline T operator^(T a, T b) { return (T) ((int) a ^ (int) b); }\ntemplate<class T> inline T &operator|=(T &a, T b) { return (T &) ((int &) a |= (int) b); }\ntemplate<class T> inline T &operator&=(T &a, T b) { return (T &) ((int &) a &= (int) b); }\ntemplate<class T> inline T &operator^=(T &a, T b) { return (T &) ((int &) a ^= (int) b); }\n\nclass Interpolations {\npublic:\n  static float linear(float t) { return t; }\n\n  static float easeIn(float t) { return t * t * t * t; }\n\n  static float easeOut(float t) {\n    float f = (t - 1);\n    return f * f * f * (1 - t) + 1;\n  }\n\n  static float easeInOut(float t) {\n    if (t < 0.5) {\n      return 8 * t * t * t * t;\n    }\n\n    float f = (t - 1);\n    return -8 * f * f * f * f + 1;\n  }\n};\n\nclass InterpolationHelper {\npublic:\n  static std::function<float(float)> getInterpolationMethod(InterpolationMethod index) {\n    switch (index) {\n    case InterpolationMethod::SlowEaseIn:\n    case InterpolationMethod::EaseIn:return Interpolations::easeIn;\n    case InterpolationMethod::EaseInOut:return Interpolations::easeInOut;\n    case InterpolationMethod::SlowEaseOut:\n    case InterpolationMethod::EaseOut:return Interpolations::easeOut;\n    default:return Interpolations::linear;\n    }\n  }\n};\n} // namespace ng\n"
  },
  {
    "path": "include/engge/Engine/Inventory.hpp",
    "content": "#pragma once\n#include <array>\n#include \"engge/Graphics/Screen.hpp\"\n#include \"engge/Graphics/SpriteSheet.hpp\"\n\nnamespace ng {\nclass Object;\n\nclass Inventory final : public ngf::Drawable {\npublic:\n  void setTextureManager(ResourceManager *pTextureManager);\n  bool update(const ngf::TimeSpan &elapsed);\n\n  void setCurrentActorIndex(int index) { m_currentActorIndex = index; }\n  void setCurrentActor(Actor *pActor) { m_pCurrentActor = pActor; }\n  void setMousePosition(const glm::vec2 &pos) { m_mousePos = pos; }\n  Object *getCurrentInventoryObject() { return m_pCurrentInventoryObject; }\n  glm::vec2 getPosition(Object *pObject) const;\n\n  void setVerbUiColors(const VerbUiColors *pColors) { m_pColors = pColors; }\n  void setAlpha(float alpha) { m_alpha = alpha;}\n  [[nodiscard]] float getAlpha() const {return m_alpha;}\n\n  void draw(ngf::RenderTarget &target, ngf::RenderStates states) const final;\n\nprivate:\n  void drawUpArrow(ngf::RenderTarget &target) const;\n  void drawDownArrow(ngf::RenderTarget &target) const;\n  [[nodiscard]] bool hasUpArrow() const;\n  [[nodiscard]] bool hasDownArrow() const;\n\nprivate:\n  SpriteSheet m_gameSheet, m_inventoryItems;\n  std::array<ngf::frect, 8> m_inventoryRects;\n  ngf::frect m_scrollUpRect;\n  ngf::frect m_scrollDownRect;\n  Object *m_pCurrentInventoryObject{nullptr};\n  glm::vec2 m_mousePos{0, 0};\n  float m_jiggleTime{0};\n  Actor* m_pCurrentActor{nullptr};\n  int m_currentActorIndex{0};\n  const VerbUiColors *m_pColors{nullptr};\n  float m_alpha{1.f};\n  bool m_mouseWasDown{false};\n};\n} // namespace ng\n"
  },
  {
    "path": "include/engge/Engine/Light.hpp",
    "content": "#pragma once\n#include <squirrel.h>\n#include <ngf/Graphics/Color.h>\n#include <glm/vec2.hpp>\n#include <ngf/Graphics/Colors.h>\n#include \"engge/Scripting/ScriptObject.hpp\"\n\nnamespace ng {\nclass Light final : public ScriptObject {\npublic:\n  Light();\n  ~Light() final;\n\npublic:\n  HSQOBJECT table{};\n  ngf::Color color{ngf::Colors::White};\n  glm::ivec2 pos{0, 0};\n  float brightness{1.0f}; ///< light brightness 1.0f...100.f\n  float coneDirection{0}; ///< cone direction 0...360.f\n  float coneAngle;     ///< cone angle 0...360.f\n  float coneFalloff;   ///< cone falloff 0.f...1.0f\n  float cutOffRadius;  ///< cutoff raduis\n  float halfRadius;    ///< cone half radius 0.0f...1.0f\n  bool on{true};\n};\n} // namespace ng"
  },
  {
    "path": "include/engge/Engine/Preferences.hpp",
    "content": "#pragma once\n#include <functional>\n#include <map>\n#include <string>\n#include <ngf/IO/GGPackValue.h>\n\nnamespace ng {\nnamespace PreferenceNames {\nstatic const std::string HudSentence = \"hudSentence\";\nstatic const std::string UiBackingAlpha = \"uiBackingAlpha\";\nstatic const std::string InvertVerbHighlight = \"invertVerbHighlight\";\nstatic const std::string RetroVerbs = \"retroVerbs\";\nstatic const std::string RetroFonts = \"retroFonts\";\nstatic const std::string Language = \"language\";\nstatic const std::string ClassicSentence = \"hudSentence\";\nstatic const std::string Controller = \"controller\";\nstatic const std::string ScrollSyncCursor = \"controllerScollLockCursor\";\nstatic const std::string DisplayText = \"talkiesShowText\";\nstatic const std::string HearVoice = \"talkiesHearVoice\";\nstatic const std::string SayLineSpeed = \"sayLineSpeed\";\nstatic const std::string SayLineBaseTime = \"sayLineBaseTime\";\nstatic const std::string SayLineCharTime = \"sayLineCharTime\";\nstatic const std::string SayLineMinTime = \"sayLineMinTime\";\nstatic const std::string ToiletPaperOver = \"toiletPaperOver\";\nstatic const std::string AnnoyingInJokes = \"annoyingInJokes\";\nstatic const std::string SafeArea = \"safeScale\";\nstatic const std::string Fullscreen = \"windowFullscreen\";\nstatic const std::string RightClickSkipsDialog = \"rightClickSkipsDialog\";\nstatic const std::string KeySkipText = \"keySkipText\";\nstatic const std::string KeySelect1 = \"keySelect1\";\nstatic const std::string KeySelect2 = \"keySelect2\";\nstatic const std::string KeySelect3 = \"keySelect3\";\nstatic const std::string KeySelect4 = \"keySelect4\";\nstatic const std::string KeySelect5 = \"keySelect5\";\nstatic const std::string KeySelect6 = \"keySelect6\";\nstatic const std::string KeySelectPrev = \"keySelectPrev\";\nstatic const std::string KeySelectNext = \"keySelectNext\";\n// engge only\nstatic const std::string EnggeGameSpeedFactor = \"gameSpeedFactor\";\nstatic const std::string EnggeDevPath = \"devPath\";\nstatic const bool EnggeDebug = false;\n}\n\nnamespace PreferenceDefaultValues {\nstatic const bool HudSentence = false;\nstatic const float UiBackingAlpha = 0.33f;\nstatic const bool InvertVerbHighlight = true;\nstatic const bool RetroVerbs = false;\nstatic const bool RetroFonts = false;\nstatic const std::string Language = \"en\";\nstatic const bool ClassicSentence = false;\nstatic const bool Controller = false;\nstatic const bool ScrollSyncCursor = true;\nstatic const bool DisplayText = true;\nstatic const bool HearVoice = true;\nstatic const float SayLineSpeed = 0.5f;\nstatic const float SayLineBaseTime = 1.5f;\nstatic const float SayLineCharTime = 0.025f;\nstatic const float SayLineMinTime = 0.2f;\nstatic const bool ToiletPaperOver = true;\nstatic const float SafeArea = 1.f;\nstatic const bool Fullscreen = true;\nstatic const bool RightClickSkipsDialog = false;\nstatic const std::string KeySkipText = \".\";\nstatic const std::string KeySelect1 = \"1\";\nstatic const std::string KeySelect2 = \"2\";\nstatic const std::string KeySelect3 = \"3\";\nstatic const std::string KeySelect4 = \"4\";\nstatic const std::string KeySelect5 = \"5\";\nstatic const std::string KeySelect6 = \"6\";\nstatic const std::string KeySelectPrev = \"9\";\nstatic const std::string KeySelectNext = \"0\";\nstatic const bool AnnoyingInJokes = false;\nstatic const std::string EnggeDevPath = \"\";\nstatic const float EnggeGameSpeedFactor = 1.f;\nstatic const bool EnggeDebug = false;\n}\n\nnamespace TempPreferenceNames {\nstatic const std::string ForceTalkieText = \"forceTalkieText\";\nstatic const std::string ShowHotspot = \"showHotspot\";\n}\n\nnamespace TempPreferenceDefaultValues {\nstatic const int ForceTalkieText = 0;\nstatic const int ShowHotspot = 0;\n}\n\nclass Preferences {\npublic:\n  Preferences();\n\n  void save();\n\n  template<typename T>\n  void setTempPreference(const std::string &name, T value);\n  template<typename T>\n  T getTempPreference(const std::string &name, T value) const;\n\n  template<typename T>\n  void setUserPreference(const std::string &name, T value);\n  template<typename T>\n  T getUserPreference(const std::string &name, T value) const;\n\n  void removeUserPreference(const std::string &name);\n\n  void subscribe(const std::function<void(const std::string &)> &function);\n\n  template<typename T>\n  static ngf::GGPackValue toGGPackValue(T value);\n\n  template<typename T>\n  static T fromGGPackValue(const ngf::GGPackValue &value);\n\nprivate:\n  [[nodiscard]] ngf::GGPackValue getUserPreferenceCore(const std::string &name,\n                                                       const ngf::GGPackValue &defaultValue) const;\n  [[nodiscard]] ngf::GGPackValue getTempPreferenceCore(const std::string &name,\n                                                       const ngf::GGPackValue &defaultValue) const;\n\nprivate:\n  ngf::GGPackValue m_values;\n  ngf::GGPackValue m_tempValues;\n  std::vector<std::function<void(const std::string &)>> m_functions;\n};\n\ntemplate<typename T>\nvoid Preferences::setUserPreference(const std::string &name, T value) {\n  m_values[name] = value;\n  for (auto &&func : m_functions) {\n    func(name);\n  }\n}\n\ntemplate<>\nvoid Preferences::setUserPreference(const std::string &name, bool value);\n\ntemplate<typename T>\nT Preferences::getUserPreference(const std::string &name, T value) const {\n  return Preferences::fromGGPackValue<T>(getUserPreferenceCore(name, Preferences::toGGPackValue<T>(value)));\n}\n\ntemplate<typename T>\nvoid Preferences::setTempPreference(const std::string &name, T value) {\n  m_tempValues[name] = toGGPackValue(value);\n}\n\ntemplate<typename T>\nT Preferences::getTempPreference(const std::string &name, T value) const {\n  return Preferences::fromGGPackValue<T>(getTempPreferenceCore(name, Preferences::toGGPackValue<T>(value)));\n}\n\n} // namespace ng\n"
  },
  {
    "path": "include/engge/Engine/RoomEffect.hpp",
    "content": "#pragma once\n#include <glm/vec3.hpp>\n\nnamespace ng {\nstruct RoomEffect {\n  float iGlobalTime{0.f};\n  float iFade{1.f};\n  float wobbleIntensity{1.f};\n  glm::vec3 shadows{-0.3f, 0, 0};\n  glm::vec3 midtones{-0.2f, 0, 0.1f};\n  glm::vec3 highlights{0, 0, 0.2f};\n\n  float sepiaFlicker{1.f};\n  std::array<float,5> RandomValue;\n  float TimeLapse{0.f};\n\n  float iNoiseThreshold{1.f};\n\n  void reset() {\n    iFade = 1.f;\n    wobbleIntensity = 1.f;\n    shadows = {-0.3f, 0, 0};\n    midtones = {-0.2f, 0, 0.1f};\n    highlights = {0, 0, 0.2f};\n  }\n};\n}"
  },
  {
    "path": "include/engge/Engine/SavegameSlot.hpp",
    "content": "#pragma once\n#include <filesystem>\n#include <string>\n#include <ngf/System/TimeSpan.h>\n\nnamespace ng {\nclass SavegameSlot {\npublic:\n  int slot{0};\n  time_t savetime{};\n  ngf::TimeSpan gametime;\n  std::filesystem::path path;\n  bool easyMode{false};\n\n  [[nodiscard]] std::wstring getSaveTimeString() const;\n  [[nodiscard]] std::wstring getGameTimeString() const;\n};\n}\n"
  },
  {
    "path": "include/engge/Engine/Sentence.hpp",
    "content": "#pragma once\n#include <memory>\n#include <vector>\n#include <ngf/System/TimeSpan.h>\n#include <engge/Engine/Function.hpp>\n\nnamespace ng {\nclass Sentence : public Function {\npublic:\n  Sentence &push_back(std::unique_ptr<Function> func);\n  void stop();\n  bool isElapsed() override;\n  void operator()(const ngf::TimeSpan &elapsed) override;\n\nprivate:\n  std::vector<std::unique_ptr<Function>> m_functions;\n  bool m_stopped{false};\n};\n}"
  },
  {
    "path": "include/engge/Engine/TextDatabase.hpp",
    "content": "#pragma once\n#include <string>\n#include <map>\n\nnamespace ng {\nclass TextDatabase {\npublic:\n  TextDatabase();\n\n  void load(const std::string &path);\n  [[nodiscard]] std::wstring getText(int id) const;\n  [[nodiscard]] std::wstring getText(const std::string &text) const;\n\nprivate:\n  std::map<int, std::wstring> m_texts;\n};\n} // namespace ng\n"
  },
  {
    "path": "include/engge/Engine/Thread.hpp",
    "content": "#pragma once\n#include <string>\n#include <vector>\n#include \"squirrel.h\"\n#include \"ThreadBase.hpp\"\n\nnamespace ng {\nclass Thread final : public ThreadBase {\npublic:\n  Thread(std::string  name, bool isGlobal,\n         HSQUIRRELVM v,\n         HSQOBJECT thread_obj,\n         HSQOBJECT env_obj,\n         HSQOBJECT closureObj,\n         std::vector<HSQOBJECT> args);\n  ~Thread() final;\n\n  [[nodiscard]] std::string getName() const final;\n  [[nodiscard]] HSQUIRRELVM getThread() const final;\n  [[nodiscard]] bool isGlobal() const final { return m_isGlobal; }\n\n  bool call();\n\nprivate:\n  std::string m_name;\n  HSQUIRRELVM m_v;\n  HSQOBJECT m_threadObj;\n  HSQOBJECT m_envObj;\n  HSQOBJECT m_closureObj;\n  std::vector<HSQOBJECT> m_args;\n  bool m_isGlobal{false};\n};\n} // namespace ng\n"
  },
  {
    "path": "include/engge/Engine/ThreadBase.hpp",
    "content": "#pragma once\n#include <string>\n#include <squirrel.h>\n#include <engge/Scripting/ScriptObject.hpp>\n\nnamespace ng {\nclass ThreadBase : public ScriptObject {\nprotected:\n  ThreadBase();\n\npublic:\n  ~ThreadBase() override;\n\n  [[nodiscard]] virtual HSQUIRRELVM getThread() const = 0;\n  [[nodiscard]] virtual std::string getName() const = 0;\n\n  inline void setPauseable(bool value) { m_isPauseable = value; }\n  [[nodiscard]] inline bool isPauseable() const { return m_isPauseable; }\n  [[nodiscard]] virtual bool isGlobal() const { return false; }\n\n  void stop();\n  bool pause();\n  void suspend();\n  void resume();\n\n  [[nodiscard]] bool isSuspended() const;\n  [[nodiscard]] virtual bool isStopped() const;\n\nprivate:\n  bool m_isSuspended{false};\n  bool m_isPauseable{true};\n  bool m_isStopped{false};\n};\n}\n"
  },
  {
    "path": "include/engge/Engine/TimeFunction.hpp",
    "content": "#pragma once\n#include <ngf/System/TimeSpan.h>\n#include <engge/Engine/Function.hpp>\n\nnamespace ng {\nclass TimeFunction : public Function {\npublic:\n  explicit TimeFunction(const ngf::TimeSpan &time);\n  ~TimeFunction() override;\n\n  void operator()(const ngf::TimeSpan &elapsed) override;\n  [[nodiscard]] ngf::TimeSpan getElapsed() const;\n\n  bool isElapsed() override;\n\n  virtual void onElapsed();\n\nprotected:\n  ngf::TimeSpan m_elapsed;\n  ngf::TimeSpan m_time;\n  bool m_done{false};\n};\n}"
  },
  {
    "path": "include/engge/Engine/Trigger.hpp",
    "content": "#pragma once\n#include <string>\n\nnamespace ng {\nclass Trigger {\npublic:\n  Trigger();\n  virtual ~Trigger();\n\n  void trig();\n\n  [[nodiscard]] bool isEnabled() const;\n  void disable();\n\n  virtual std::string getName() = 0;\n\nprotected:\n  virtual void trigCore() = 0;\n\nprivate:\n  bool m_isEnabled{true};\n};\n} // namespace ng\n"
  },
  {
    "path": "include/engge/Engine/Verb.hpp",
    "content": "#pragma once\n#include <array>\n#include <string>\n#include <ngf/Graphics/Color.h>\n\nnamespace ng {\nnamespace VerbConstants {\nstatic const int VERB_WALKTO = 1;\nstatic const int VERB_LOOKAT = 2;\nstatic const int VERB_TALKTO = 3;\nstatic const int VERB_PICKUP = 4;\nstatic const int VERB_OPEN = 5;\nstatic const int VERB_CLOSE = 6;\nstatic const int VERB_PUSH = 7;\nstatic const int VERB_PULL = 8;\nstatic const int VERB_GIVE = 9;\nstatic const int VERB_USE = 10;\nstatic const int VERB_DIALOG = 13;\n} // namespace VerbConstants\n\nstruct Verb {\n  int id;\n  std::string image;\n  std::string func;\n  std::string text;\n  std::string key;\n\n  static std::string getName(int id) {\n    switch (id) {\n    case VerbConstants::VERB_CLOSE:return \"verbClose\";\n    case VerbConstants::VERB_GIVE:return \"verbGive\";\n    case VerbConstants::VERB_LOOKAT:return \"verbLookAt\";\n    case VerbConstants::VERB_OPEN:return \"verbOpen\";\n    case VerbConstants::VERB_PICKUP:return \"verbPickup\";\n    case VerbConstants::VERB_PULL:return \"verbPull\";\n    case VerbConstants::VERB_PUSH:return \"verbPush\";\n    case VerbConstants::VERB_TALKTO:return \"verbTalkTo\";\n    case VerbConstants::VERB_WALKTO:return \"verbWalkTo\";\n    case VerbConstants::VERB_USE:return \"verbUse\";\n    }\n    return \"\";\n  }\n};\n\nclass VerbSlot {\npublic:\n  void setVerb(int index, const Verb &verb) { m_verbs.at(index) = verb; }\n  [[nodiscard]] const Verb &getVerb(int index) const { return m_verbs.at(index); }\n\nprivate:\n  std::array<Verb, 10> m_verbs;\n};\n\nstruct VerbUiColors {\n  ngf::Color sentence;\n  ngf::Color verbNormal;\n  ngf::Color verbNormalTint;\n  ngf::Color verbHighlight;\n  ngf::Color verbHighlightTint;\n  ngf::Color dialogNormal;\n  ngf::Color dialogHighlight;\n  ngf::Color inventoryFrame;\n  ngf::Color inventoryBackground;\n  ngf::Color retroNormal;\n  ngf::Color retroHighlight;\n};\n} // namespace ng"
  },
  {
    "path": "include/engge/Entities/Actor.hpp",
    "content": "#pragma once\n#include <memory>\n#include <string>\n#include <optional>\n#include <squirrel.h>\n#include <engge/Entities/Entity.hpp>\n#include <engge/Entities/Facing.hpp>\n\nnamespace ng {\nclass Costume;\nclass Engine;\nclass Lip;\nclass Object;\nclass PathDrawable;\nclass Room;\n\nclass Actor final : public Entity {\npublic:\n  explicit Actor(Engine &engine);\n  ~Actor() final;\n\n  [[nodiscard]] std::wstring getTranslatedName() const;\n\n  [[nodiscard]] std::string getIcon() const;\n\n  void useWalkboxes(bool use);\n  [[nodiscard]] bool useWalkboxes() const;\n\n  [[nodiscard]] int getZOrder() const final;\n\n  void setCostume(const std::string &name, const std::string &sheet = \"\");\n  [[nodiscard]] Costume &getCostume() const;\n  Costume &getCostume();\n\n  Room *getRoom() final;\n  [[nodiscard]] const Room *getRoom() const final;\n  void setRoom(Room *pRoom);\n\n  void setFps(int fps) final;\n  [[nodiscard]] int getFps() const;\n\n  void setHotspot(const ngf::irect &hotspot);\n  [[nodiscard]] ngf::irect getHotspot() const;\n  void showHotspot(bool show);\n  [[nodiscard]] bool isHotspotVisible() const;\n  [[nodiscard]] bool contains(const glm::vec2 &pos) const;\n\n  void update(const ngf::TimeSpan &time) final;\n\n  void pickupObject(Object *pObject);\n  void pickupReplacementObject(Object *pObject1, Object *pObject2);\n  void giveTo(Object *pObject, Actor *pActor);\n  void removeInventory(Object *pObject);\n  void clearInventory();\n  [[nodiscard]] const std::vector<Object *> &getObjects() const;\n  void setInventoryOffset(int offset);\n  [[nodiscard]] int getInventoryOffset() const;\n\n  void setWalkSpeed(const glm::ivec2 &speed);\n  [[nodiscard]] const glm::ivec2 &getWalkSpeed() const;\n\n  std::vector<glm::vec2> walkTo(const glm::vec2 &destination, std::optional<Facing> facing = std::nullopt);\n  void stopWalking();\n  [[nodiscard]] bool isWalking() const;\n  std::unique_ptr<PathDrawable> getPath();\n\n  [[nodiscard]] bool isInventoryObject() const final;\n\n  HSQOBJECT &getTable() final;\n  [[nodiscard]] HSQOBJECT &getTable() const final;\n  [[nodiscard]] float getScale() const final;\n\nprivate:\n  void draw(ngf::RenderTarget &target, ngf::RenderStates states) const final;\n\nprivate:\n  struct Impl;\n  std::unique_ptr<Impl> m_pImpl;\n};\n} // namespace ng\n"
  },
  {
    "path": "include/engge/Entities/AnimationLoader.hpp",
    "content": "#pragma once\n#include <vector>\n#include <engge/Entities/Entity.hpp>\n#include <engge/Graphics/Animation.hpp>\n#include <engge/Graphics/SpriteSheet.hpp>\n#include <ngf/IO/GGPackValue.h>\n\nnamespace ng {\nclass AnimationLoader final {\npublic:\n  static std::vector<Animation> parseAnimations(\n      Entity &entity,\n      const ngf::GGPackValue &gAnimations,\n      const SpriteSheet &spriteSheet);\n};\n}"
  },
  {
    "path": "include/engge/Entities/BlinkState.hpp",
    "content": "#pragma once\n#include <cstdint>\n#include <ngf/System/TimeSpan.h>\n\nnamespace ng {\nclass Costume;\n\nclass BlinkState final {\npublic:\n  explicit BlinkState(Costume &costume);\n\n  void setRate(float min, float max);\n  void update(ngf::TimeSpan elapsed);\n\nprivate:\n  Costume &m_costume;\n  float m_min{0};\n  float m_max{0};\n  ngf::TimeSpan m_value;\n  int32_t m_state{-1};\n  ngf::TimeSpan m_elapsed;\n};\n}\n"
  },
  {
    "path": "include/engge/Entities/Costume.hpp",
    "content": "#pragma once\n#include <optional>\n#include <sstream>\n#include <set>\n#include <unordered_map>\n#include \"BlinkState.hpp\"\n#include \"DirectionConstants.hpp\"\n#include <ngf/Graphics/Drawable.h>\n#include <ngf/Graphics/RenderStates.h>\n#include <ngf/Graphics/RenderTarget.h>\n#include <engge/Graphics/SpriteSheet.hpp>\n#include <engge/Graphics/ResourceManager.hpp>\n#include <engge/Graphics/Animation.hpp>\n#include <engge/Graphics/AnimControl.hpp>\n#include <engge/Entities/Facing.hpp>\n\nnamespace ng {\n\nenum class Reaching {\n  High,\n  Medium,\n  Low\n};\n\nclass Actor;\n\nclass Costume final : public ngf::Drawable {\npublic:\n  explicit Costume(ResourceManager &textureManager);\n  ~Costume() final;\n\n  void loadCostume(const std::string &name, const std::string &sheet = \"\");\n  [[nodiscard]] std::string getPath() const { return m_path; }\n  [[nodiscard]] std::string getSheet() const { return m_sheet; }\n  void lockFacing(Facing left, Facing right, Facing front, Facing back);\n  void unlockFacing();\n  void resetLockFacing();\n  [[nodiscard]] std::optional<Facing> getLockFacing() const;\n\n  void setFacing(Facing facing);\n  [[nodiscard]] Facing getFacing() const;\n  void setState(const std::string &name, bool loop = false);\n  void setStandState() { setState(m_standAnimName); }\n  void setWalkState() { setState(m_walkAnimName, true); }\n  void setReachState(Reaching reaching);\n  bool setAnimation(const std::string &name);\n  Animation *getAnimation() { return m_pCurrentAnimation; }\n  AnimControl& getAnimControl() { return m_animControl; }\n  std::vector<Animation> &getAnimations() { return m_animations; }\n  void setLayerVisible(const std::string &name, bool isVisible);\n  void setHeadIndex(int index);\n  [[nodiscard]] int getHeadIndex() const;\n\n  void setAnimationNames(const std::string &headAnim,\n                         const std::string &standAnim,\n                         const std::string &walkAnim,\n                         const std::string &reachAnim);\n  void getAnimationNames(std::string &headAnim,\n                         std::string &standAnim,\n                         std::string &walkAnim,\n                         std::string &reachAnim) const;\n\n  void setActor(Actor *pActor) { m_pActor = pActor; }\n\n  void setBlinkRate(float min, float max);\n\n  void update(const ngf::TimeSpan &elapsed);\n\n  void draw(ngf::RenderTarget &target, ngf::RenderStates states) const final;\n\nprivate:\n  bool setMatchingAnimation(const std::string &animName);\n  void updateAnimation();\n\nprivate:\n  ResourceManager &m_textureManager;\n  std::string m_path;\n  std::string m_sheet;\n  std::vector<Animation> m_animations;\n  Animation *m_pCurrentAnimation{nullptr};\n  Facing m_facing{Facing::FACE_FRONT};\n  std::set<std::string> m_hiddenLayers;\n  std::string m_animation{\"stand\"};\n  std::string m_standAnimName{\"stand\"};\n  std::string m_headAnimName{\"head\"};\n  std::string m_walkAnimName{\"walk\"};\n  std::string m_reachAnimName{\"reach\"};\n  int m_headIndex{0};\n  Actor *m_pActor{nullptr};\n  BlinkState m_blinkState;\n  std::unordered_map<Facing, Facing> m_facings;\n  bool m_lockFacing{false};\n  SpriteSheet m_costumeSheet;\n  AnimControl m_animControl;\n};\n} // namespace ng"
  },
  {
    "path": "include/engge/Entities/DirectionConstants.hpp",
    "content": "#pragma once\n\nnamespace ng {\nnamespace DirectionConstants {\nstatic const int FACE_FRONT = 0x4;\nstatic const int FACE_BACK = 0x8;\nstatic const int FACE_LEFT = 0x2;\nstatic const int FACE_RIGHT = 0x1;\nstatic const int FACE_FLIP = 0x10;\n}\n}\n"
  },
  {
    "path": "include/engge/Entities/Entity.hpp",
    "content": "#pragma once\n#include <memory>\n#include <optional>\n#include <squirrel.h>\n#include <glm/vec2.hpp>\n#include <ngf/Graphics/Color.h>\n#include <ngf/Graphics/Drawable.h>\n#include <ngf/Graphics/RenderStates.h>\n#include <ngf/Graphics/RenderTarget.h>\n#include <ngf/Math/Transform.h>\n#include <engge/Engine/Interpolations.hpp>\n#include <engge/Scripting/ScriptObject.hpp>\n#include <engge/Entities/UseDirection.hpp>\n\nnamespace ng {\nclass Actor;\nclass Engine;\nclass Room;\nclass SoundDefinition;\nclass SoundTrigger;\nclass Trigger;\nstruct Motor;\n\nclass Entity : public ScriptObject, public ngf::Drawable {\npublic:\n  Entity();\n  ~Entity() override;\n\n  void setKey(const std::string &key);\n  [[nodiscard]] const std::string &getKey() const;\n\n  [[nodiscard]] uint32_t getFlags() const;\n\n  virtual void update(const ngf::TimeSpan &elapsed);\n  [[nodiscard]] virtual int getZOrder() const = 0;\n\n  void setName(const std::string &name);\n  [[nodiscard]] std::string getName() const;\n\n  void setVisible(bool isVisible);\n  [[nodiscard]] bool isVisible() const;\n\n  void setLit(bool isLit);\n  [[nodiscard]] bool isLit() const;\n\n  void setTouchable(bool isTouchable);\n  [[nodiscard]] virtual bool isTouchable() const;\n\n  void objectBumperCycle(bool enabled);\n  [[nodiscard]] bool objectBumperCycle() const;\n\n  [[nodiscard]] virtual bool isInventoryObject() const = 0;\n\n  void setRenderOffset(const glm::ivec2 &offset);\n  [[nodiscard]] glm::ivec2 getRenderOffset() const;\n\n  void setUseDirection(std::optional<UseDirection> direction);\n  [[nodiscard]] std::optional<UseDirection> getUseDirection() const;\n\n  void setUsePosition(std::optional<glm::vec2> pos);\n  [[nodiscard]] std::optional<glm::vec2> getUsePosition() const;\n\n  void setPosition(const glm::vec2 &pos);\n  [[nodiscard]] glm::vec2 getPosition() const;\n  [[nodiscard]] glm::vec2 getRealPosition() const;\n  [[nodiscard]] ngf::Transform getTransform() const;\n\n  void setOffset(const glm::vec2 &offset);\n  [[nodiscard]] glm::vec2 getOffset() const;\n\n  void setRotation(float angle);\n  [[nodiscard]] float getRotation() const;\n\n  void setScale(float s);\n  [[nodiscard]] virtual float getScale() const;\n\n  void setColor(const ngf::Color &color);\n  [[nodiscard]] ngf::Color getColor() const;\n\n  void setTalkColor(ngf::Color color);\n  [[nodiscard]] ngf::Color getTalkColor() const;\n\n  void setTalkOffset(const glm::ivec2 &offset);\n  [[nodiscard]] glm::ivec2 getTalkOffset() const;\n\n  void setTrigger(int triggerNumber, Trigger *pTrigger);\n  void removeTrigger(int triggerNumber);\n  void trig(const std::string &name);\n\n  void setVolume(float volume);\n  [[nodiscard]] float getVolume() const;\n\n  virtual void drawForeground(ngf::RenderTarget &target, ngf::RenderStates states) const;\n\n  virtual Room *getRoom() = 0;\n  [[nodiscard]] virtual const Room *getRoom() const = 0;\n  virtual void setFps(int fps) = 0;\n\n  virtual HSQOBJECT &getTable() = 0;\n  [[nodiscard]] virtual HSQOBJECT &getTable() const = 0;\n\n  [[nodiscard]] bool hasParent() const;\n  void setParent(Entity *pParent);\n  Entity *getParent();\n  [[nodiscard]] const Entity *getParent() const;\n\n  SoundTrigger *createSoundTrigger(Engine &engine, const std::vector<std::shared_ptr<SoundDefinition>> &sounds);\n\n  void alphaTo(float destination, ngf::TimeSpan time, InterpolationMethod method);\n  void offsetTo(glm::vec2 destination, ngf::TimeSpan time, InterpolationMethod method);\n  void moveTo(glm::vec2 destination, ngf::TimeSpan time, InterpolationMethod method);\n  void rotateTo(float destination, ngf::TimeSpan time, InterpolationMethod method);\n  void scaleTo(float destination, ngf::TimeSpan time, InterpolationMethod method);\n  void shake(float amount);\n  void jiggle(float amount);\n\n  void stopObjectMotors();\n\n  void say(const std::string &text, bool mumble = false);\n  void stopTalking();\n  [[nodiscard]] bool isTalking() const;\n\n  [[nodiscard]] int getDefaultVerb(int defaultVerbId) const;\n  static Actor *getActor(const Entity *pEntity);\n\nprivate:\n  static void update(Motor &motor, const ngf::TimeSpan &elapsed);\n\nprotected:\n  [[nodiscard]] std::vector<Entity *> getChildren() const;\n\nprivate:\n  struct Impl;\n  std::unique_ptr<Impl> m_pImpl;\n};\n} // namespace ng\n"
  },
  {
    "path": "include/engge/Entities/Facing.hpp",
    "content": "#pragma once\n#include <engge/Entities/DirectionConstants.hpp>\n\nnamespace ng {\nenum class Facing {\n  FACE_FRONT = DirectionConstants::FACE_FRONT,\n  FACE_BACK = DirectionConstants::FACE_BACK,\n  FACE_LEFT = DirectionConstants::FACE_LEFT,\n  FACE_RIGHT = DirectionConstants::FACE_RIGHT\n};\n}"
  },
  {
    "path": "include/engge/Entities/Object.hpp",
    "content": "#pragma once\n#include <optional>\n#include <squirrel.h>\n#include <engge/Entities/Entity.hpp>\n#include <engge/Graphics/Animation.hpp>\n#include <engge/Graphics/AnimControl.hpp>\n\nnamespace ng {\nenum class ScreenSpace {\n  Room,\n  Object\n};\n\nenum class ObjectType {\n  Object,\n  Spot,\n  Prop,\n  Trigger\n};\n\nclass Actor;\nclass Room;\n\nnamespace ObjectStateConstants {\nstatic const int ALL = 1;\nstatic const int HERE = 0;\nstatic const int GONE = 4;\nstatic const int OFF = 0;\nstatic const int ON = 1;\nstatic const int FULL = 0;\nstatic const int EMPTY = 1;\nstatic const int OPEN = 1;\nstatic const int CLOSED = 0;\n}\n\nnamespace ObjectFlagConstants {\nstatic const uint32_t USE_WITH = 2;\nstatic const uint32_t USE_ON = 4;\nstatic const uint32_t USE_IN = 32;\nstatic const int DOOR = 0x40;\nstatic const int DOOR_LEFT = 0x140;\nstatic const int DOOR_RIGHT = 0x240;\nstatic const int DOOR_BACK = 0x440;\nstatic const int DOOR_FRONT = 0x840;\nstatic const int GIVEABLE = 0x1000;\nstatic const int TALKABLE = 0x2000;\nstatic const int IMMEDIATE = 0x4000;\nstatic const int FEMALE = 0x80000;\nstatic const int MALE = 0x100000;\nstatic const int PERSON = 0x200000;\nstatic const int REACH_HIGH = 0x8000;\nstatic const int REACH_MED = 0x10000;\nstatic const int REACH_LOW = 0x20000;\nstatic const int REACH_NONE = 0x40000;\n}\n\nclass Object : public Entity {\npublic:\n  Object();\n  explicit Object(HSQOBJECT obj);\n  ~Object() override;\n\n  void setZOrder(int zorder);\n  [[nodiscard]] int getZOrder() const override;\n\n  void setType(ObjectType type);\n  [[nodiscard]] ObjectType getType() const;\n\n  [[nodiscard]] bool isTouchable() const override;\n  [[nodiscard]] bool isInventoryObject() const override;\n\n  void setHotspot(const ngf::irect &hotspot);\n  [[nodiscard]] ngf::irect getHotspot() const;\n\n  [[nodiscard]] ngf::irect getRealHotspot() const;\n  void showDebugHotspot(bool show);\n  [[nodiscard]] bool isHotspotVisible() const;\n\n  void setIcon(const std::string &icon);\n  void setIcon(int fps, const std::vector<std::string> &icons);\n  [[nodiscard]] std::string getIcon() const;\n\n  HSQOBJECT &getTable() override;\n  [[nodiscard]] HSQOBJECT &getTable() const override;\n\n  std::vector<Animation> &getAnims();\n\n  void setStateAnimIndex(int animIndex);\n  void playAnim(int animIndex, bool loop);\n  void playAnim(const std::string &anim, bool loop);\n  [[nodiscard]] int getState() const;\n  void setAnimation(const std::string &name);\n  Animation *getAnimation();\n  const Animation *getAnimation() const;\n  AnimControl &getAnimControl();\n\n  Room *getRoom() override;\n  [[nodiscard]] const Room *getRoom() const override;\n  void setRoom(Room *pRoom);\n\n  void update(const ngf::TimeSpan &elapsed) override;\n\n  friend std::wostream &operator<<(std::wostream &os, const Object &obj);\n\n  void addTrigger(const std::shared_ptr<Trigger> &trigger);\n  void removeTrigger();\n  Trigger *getTrigger();\n  void enableTrigger(bool enabled);\n\n  void dependentOn(Object *parentObject, int state);\n\n  void setFps(int fps) override;\n\n  [[nodiscard]] Actor *getOwner() const;\n  void setOwner(Actor *pActor);\n\n  void setScreenSpace(ScreenSpace screenSpace);\n  [[nodiscard]] ScreenSpace getScreenSpace() const;\n\n  void setTemporary(bool isTemporary);\n  [[nodiscard]] bool isTemporary() const;\n\n  void setJiggle(bool enabled);\n  [[nodiscard]] bool getJiggle() const;\n\n  void setPop(int count);\n  [[nodiscard]] int getPop() const;\n  [[nodiscard]] float getPopScale() const;\n\nprivate:\n  void draw(ngf::RenderTarget &target, ngf::RenderStates states) const override;\n\nprivate:\n  struct Impl;\n  std::unique_ptr<Impl> pImpl;\n};\n} // namespace ng\n"
  },
  {
    "path": "include/engge/Entities/TextObject.hpp",
    "content": "#pragma once\n#include \"Object.hpp\"\n\nnamespace ngf {\nclass Font;\n}\n\nnamespace ng {\nenum class TextAlignment : unsigned long {\n  None =   0x00000000,\n  Left =   0x00000001,\n  Center = 0x00000002,\n  Right =  0x00000004,\n  Horizontal = Left | Center | Right,\n  Top =    0x00000008,\n  Bottom = 0x00000010,\n  Vertical = Top | Bottom,\n};\n\nclass TextObject final : public Object {\npublic:\n  TextObject();\n  ~TextObject() final;\n\n  const ngf::Font *getFont() { return m_font; }\n  void setFont(const ngf::Font *font) { m_font = font; }\n\n  void setText(const std::string &text);\n  std::string getText() const;\n\n  void setAlignment(TextAlignment alignment) { m_alignment = alignment; }\n  TextAlignment getAlignment() const { return m_alignment; }\n\n  void setMaxWidth(int maxWidth) { m_maxWidth = maxWidth; }\n  int getMaxWidth() const { return m_maxWidth; }\n\nprivate:\n  void draw(ngf::RenderTarget &target, ngf::RenderStates states) const final;\n\nprivate:\n  mutable const ngf::Font *m_font{nullptr};\n  std::wstring m_text;\n  TextAlignment m_alignment{TextAlignment::Left};\n  int m_maxWidth{0};\n};\n} // namespace ng\n"
  },
  {
    "path": "include/engge/Entities/UseDirection.hpp",
    "content": "#pragma once\n#include <engge/Entities/DirectionConstants.hpp>\n\nnamespace ng {\nenum class UseDirection {\n  Front = DirectionConstants::FACE_FRONT,\n  Back = DirectionConstants::FACE_BACK,\n  Left = DirectionConstants::FACE_LEFT,\n  Right = DirectionConstants::FACE_RIGHT,\n};\n}\n"
  },
  {
    "path": "include/engge/Graphics/AnimControl.hpp",
    "content": "#pragma once\n#include <algorithm>\n#include <engge/Graphics/Animation.hpp>\n#include <engge/Graphics/AnimState.hpp>\n\nnamespace ng {\nclass AnimControl {\npublic:\n  void setAnimation(Animation *anim);\n  Animation *getAnimation();\n\n  void play(bool loop = false);\n  void resume(bool loop = false);\n  void stop();\n  void pause();\n\n  [[nodiscard]] AnimState getState() const;\n\n  void update(const ngf::TimeSpan &e);\n  [[nodiscard]] bool getLoop() const;\n\nprivate:\n  static void resetAnim(Animation &anim);\n  static void rewind(Animation &anim);\n  void update(const ngf::TimeSpan &e, Animation &animation) const;\n  [[nodiscard]] static int getFps(const Animation &animation);\n\nprivate:\n  static void trig(const Animation &animation);\n\nprivate:\n  Animation *m_anim{nullptr};\n  bool m_loop{false};\n};\n}"
  },
  {
    "path": "include/engge/Graphics/AnimDrawable.hpp",
    "content": "#pragma once\n#include <ngf/Graphics/Color.h>\n#include <ngf/Graphics/RenderTarget.h>\n#include <ngf/Graphics/RenderStates.h>\n\nnamespace ng {\nstruct Animation;\n\nclass AnimDrawable {\npublic:\n  void setAnim(const Animation *anim);\n  void setFlipX(bool flipX);\n  void setColor(const ngf::Color &color);\n\n  void draw(const glm::vec2 &pos, ngf::RenderTarget &target, ngf::RenderStates states) const;\n\nprivate:\n  void draw(const glm::vec2 &pos,\n            const Animation &anim,\n            ngf::RenderTarget &target,\n            ngf::RenderStates states) const;\n\nprivate:\n  const Animation *m_anim{nullptr};\n  bool m_flipX{false};\n  ngf::Color m_color{ngf::Colors::White};\n};\n}"
  },
  {
    "path": "include/engge/Graphics/AnimState.hpp",
    "content": "#pragma once\n\nnamespace ng {\nenum class AnimState {\n  Stopped,\n  Play,\n  Pause\n};\n}\n"
  },
  {
    "path": "include/engge/Graphics/Animation.hpp",
    "content": "#pragma once\n#include <string>\n#include <functional>\n#include <vector>\n#include <glm/vec2.hpp>\n#include <ngf/Graphics/Texture.h>\n#include <ngf/System/TimeSpan.h>\n#include <engge/Graphics/SpriteSheetItem.h>\n#include <engge/Graphics/AnimState.hpp>\n\nnamespace ng {\nstruct Animation {\n  std::string name;\n  std::string texture;\n  std::vector<SpriteSheetItem> frames;\n  std::vector<Animation> layers;\n  std::vector<glm::ivec2> offsets;\n  std::vector<std::string> triggers;\n  std::vector<std::function<void()>> callbacks;\n  bool loop{false};\n  int fps{0};\n  int flags{0};\n  int frameIndex{0};\n  ng::AnimState state{AnimState::Pause};\n  ngf::TimeSpan elapsed;\n  bool visible{true};\n};\n}\n"
  },
  {
    "path": "include/engge/Graphics/GGFont.hpp",
    "content": "#pragma once\n#include <ngf/IO/GGPackValue.h>\n#include <engge/Graphics/ResourceManager.hpp>\n#include <ngf/Graphics/Font.h>\n#include <memory>\n\nnamespace ng {\nclass GGFont : public ngf::Font {\npublic:\n  ~GGFont() override;\n  void setTextureManager(ResourceManager *textureManager);\n\n  void load(const std::string &path);\n\n  [[nodiscard]] const std::shared_ptr<ngf::Texture> &getTexture(unsigned int) const override;\n  [[nodiscard]] const ngf::Glyph &getGlyph(unsigned int codePoint) const override;\n  [[nodiscard]] float getKerning(unsigned int first, unsigned int second, unsigned int characterSize) const override;\n\nprivate:\n  std::map<unsigned int, ngf::Glyph> m_glyphs;\n  ResourceManager *m_resourceManager{nullptr};\n  std::string m_path;\n  std::string m_jsonFilename;\n  ngf::GGPackValue m_json;\n  std::shared_ptr<ngf::Texture> m_texture;\n};\n\n} // namespace ng"
  },
  {
    "path": "include/engge/Graphics/LightingShader.h",
    "content": "#pragma once\n#include <array>\n#include <ngf/Graphics/Color.h>\n#include <ngf/Graphics/Shader.h>\n#include <ngf/Graphics/Texture.h>\n#include <engge/Engine/Light.hpp>\n\nnamespace ng {\nclass LightingShader final : public ngf::Shader {\npublic:\n  static constexpr int MaxLights = 50;\n\npublic:\n  LightingShader();\n\n  void setContentSize(glm::vec2 size);\n  void setSpritePosInSheet(glm::vec2 spritePosInSheet);\n  void setSpriteSizeRelToSheet(glm::vec2 spriteSizeRelToSheet);\n  void setSpriteOffset(glm::vec2 spriteOffset);\n  void setAmbientColor(ngf::Color color);\n  [[nodiscard]] ngf::Color getAmbientColor() const;\n\n  void setTexture(const ngf::Texture &texture);\n\n  void setNumberLights(int numberLights);\n  [[nodiscard]] int getNumberLights() const;\n\n  void setLights(const std::array<Light, MaxLights> &lights);\n\nprivate:\n  int m_numberLights{0};\n  ngf::Color m_ambient{ngf::Colors::White};\n};\n}\n"
  },
  {
    "path": "include/engge/Graphics/ResourceManager.hpp",
    "content": "#pragma once\n#include <map>\n#include <memory>\n#include <engge/System/NonCopyable.hpp>\n#include <ngf/Graphics/Texture.h>\n\nnamespace ngf {\nclass FntFont;\n}\n\nnamespace ng {\nclass GGFont;\nclass SpriteSheet;\n\nstruct TextureResource {\n  std::shared_ptr<ngf::Texture> texture;\n  size_t size;\n};\n\nclass ResourceManager : public NonCopyable {\npublic:\n  ResourceManager();\n  ~ResourceManager();\n\n  std::shared_ptr<ngf::Texture> getTexture(const std::string &id);\n  GGFont &getFont(const std::string &id);\n  ngf::FntFont &getFntFont(const std::string &id);\n  const SpriteSheet &getSpriteSheet(const std::string &id);\n\n  [[nodiscard]] const std::map<std::string, TextureResource> &getTextureMap() const { return m_textureMap; }\n\nprivate:\n  void load(const std::string &id);\n  void loadFont(const std::string &id);\n  void loadFntFont(const std::string &id);\n  void loadSpriteSheet(const std::string &id);\n\nprivate:\n  std::map<std::string, TextureResource> m_textureMap;\n  std::map<std::string, std::shared_ptr<GGFont>> m_fontMap;\n  std::map<std::string, std::shared_ptr<ngf::FntFont>> m_fntFontMap;\n  std::map<std::string, std::shared_ptr<SpriteSheet>> m_spriteSheetMap;\n};\n} // namespace ng"
  },
  {
    "path": "include/engge/Graphics/Screen.hpp",
    "content": "#pragma once\n\nnamespace ng {\nclass Screen {\npublic:\n  static const int Width = 1280;\n  static const int Height = 720;\n  static constexpr int HalfWidth = Width / 2;\n  static constexpr int HalfHeight = Height / 2;\n};\n} // namespace ng\n"
  },
  {
    "path": "include/engge/Graphics/SpriteSheet.hpp",
    "content": "#pragma once\n#include <string>\n#include <map>\n#include <memory>\n#include \"ResourceManager.hpp\"\n#include \"SpriteSheetItem.h\"\n\nnamespace ng {\nclass SpriteSheet {\npublic:\n  void setTextureManager(ResourceManager *pTextureManager) { m_pResourceManager = pTextureManager; }\n  void load(const std::string &name);\n  [[nodiscard]] std::shared_ptr<ngf::Texture> getTexture() const { return m_pResourceManager->getTexture(m_textureName); }\n  [[nodiscard]] std::string getTextureName() const { return m_textureName; }\n  [[nodiscard]] bool hasRect(const std::string &name) const;\n  [[nodiscard]] ngf::irect getRect(const std::string &name) const;\n  [[nodiscard]] ngf::irect getSpriteSourceSize(const std::string &name) const;\n  [[nodiscard]] glm::ivec2 getSourceSize(const std::string &name) const;\n  [[nodiscard]] SpriteSheetItem getItem(const std::string &name) const;\n\nprivate:\n  ResourceManager *m_pResourceManager{nullptr};\n  std::map<std::string, ngf::irect> m_rects;\n  std::map<std::string, ngf::irect> m_spriteSourceSize;\n  std::map<std::string, glm::ivec2> m_sourceSize;\n  std::string m_textureName;\n};\n} // namespace ng\n"
  },
  {
    "path": "include/engge/Graphics/SpriteSheetItem.h",
    "content": "#pragma once\n#include <string>\n#include <ngf/Graphics/Rect.h>\n#include <glm/vec2.hpp>\n\nnamespace ng {\nstruct SpriteSheetItem {\n  std::string name;\n  ngf::irect frame{};\n  ngf::irect spriteSourceSize{};\n  glm::ivec2 sourceSize{};\n  bool isNull{true};\n};\n}\n"
  },
  {
    "path": "include/engge/Graphics/Text.hpp",
    "content": "#pragma once\n#include <ngf/Graphics/Text.h>\n\nnamespace ng {\nclass Text : public ngf::Text {\npublic:\n  /// @brief Creates an empty text.\n  Text();\n  /// @brief Creates a text from a string, font and size.\n  Text(std::wstring string, const ngf::Font &font, unsigned int characterSize);\n};\n}"
  },
  {
    "path": "include/engge/Input/CommandManager.hpp",
    "content": "#pragma once\n#include <functional>\n#include <string>\n#include <initializer_list>\n#include <unordered_map>\n#include \"InputConstants.hpp\"\n\nnamespace ng {\nclass CommandManager {\npublic:\n  using CommandHandler = std::function<void()>;\n  using PressedCommandHandler = std::function<void(bool)>;\n\n  void registerCommand(const std::string &command, CommandHandler handler);\n  void registerPressedCommand(const std::string &command, PressedCommandHandler handler);\n  void registerCommands(std::initializer_list<std::tuple<const char *, CommandHandler>> commands);\n  void registerInputBindings(std::initializer_list<std::tuple<Input, const char *>> bindings);\n  void registerInputBinding(const Input& input, const std::string& command);\n\n  void execute(const std::string &command) const;\n  void execute(const Input& input) const;\n  void execute(const Input& input, bool keyDown) const;\n\nprivate:\n  std::unordered_map<std::string, CommandHandler> m_commandHandlers;\n  std::unordered_map<std::string, PressedCommandHandler> m_pressedCommandHandlers;\n  std::unordered_map<Input, std::string, InputHash> m_inputBindings;\n};\n}\n"
  },
  {
    "path": "include/engge/Input/InputConstants.hpp",
    "content": "#pragma once\n#include <functional>\n\nnamespace ng {\n\nenum class InputConstants {\n  NONE = 0,\n  // these codes corresponds to SDL key codes used in TWP\n  KEY_UP = 0x40000052,\n  KEY_RIGHT = 0x4000004F,\n  KEY_DOWN = 0x40000051,\n  KEY_LEFT = 0x40000050,\n  KEY_PAD1 = 0x40000059,\n  KEY_PAD2 = 0x4000005A,\n  KEY_PAD3 = 0x4000005B,\n  KEY_PAD4 = 0x4000005C,\n  KEY_PAD5 = 0x4000005D,\n  KEY_PAD6 = 0x4000005E,\n  KEY_PAD7 = 0x4000005F,\n  KEY_PAD8 = 0x40000056,\n  KEY_PAD9 = 0x40000061,\n  KEY_ESCAPE = 0x08,\n  KEY_TAB = 0x09,\n  KEY_RETURN = 0x0D,\n  KEY_BACKSPACE = 0x1B,\n  KEY_SPACE = 0X20,\n  KEY_A = 0x61,\n  KEY_B = 0x62,\n  KEY_C = 0x63,\n  KEY_D = 0x64,\n  KEY_E = 0x65,\n  KEY_F = 0x66,\n  KEY_G = 0x67,\n  KEY_H = 0x68,\n  KEY_I = 0x69,\n  KEY_J = 0x6A,\n  KEY_K = 0x6B,\n  KEY_L = 0x6C,\n  KEY_M = 0x6D,\n  KEY_N = 0x6E,\n  KEY_O = 0x6F,\n  KEY_P = 0x70,\n  KEY_Q = 0x71,\n  KEY_R = 0x72,\n  KEY_S = 0x73,\n  KEY_T = 0x74,\n  KEY_U = 0x75,\n  KEY_V = 0x76,\n  KEY_W = 0x77,\n  KEY_X = 0x78,\n  KEY_Y = 0x79,\n  KEY_Z = 0x7A,\n  KEY_0 = 0x30,\n  KEY_1 = 0x31,\n  KEY_2 = 0x32,\n  KEY_3 = 0x33,\n  KEY_4 = 0x34,\n  KEY_5 = 0x35,\n  KEY_6 = 0x36,\n  KEY_7 = 0x37,\n  KEY_8 = 0x38,\n  KEY_9 = 0x39,\n  KEY_F1 = 0x4000003A,\n  KEY_F2 = 0x4000003B,\n  KEY_F3 = 0x4000003C,\n  KEY_F4 = 0x4000003D,\n  KEY_F5 = 0x4000003E,\n  KEY_F6 = 0x4000003F,\n  KEY_F7 = 0x40000040,\n  KEY_F8 = 0x40000041,\n  KEY_F9 = 0x40000042,\n  KEY_F10 = 0x40000043,\n  KEY_F11 = 0x40000044,\n  KEY_F12 = 0x40000045,\n\n  BUTTON_A = 0x3E8,\n  BUTTON_B = 0x3E9,\n  BUTTON_X = 0x3EA,\n  BUTTON_Y = 0x3EB,\n  BUTTON_START = 0x3EC,\n  BUTTON_BACK = 0x3EC,\n  BUTTON_MOUSE_LEFT = 0x3ED,\n  BUTTON_MOUSE_RIGHT = 0x3EE,\n};\n\nenum class MetaKeys {\n  None,\n  Alt,\n  Control,\n  Shift,\n  System\n};\n\nstruct Input {\npublic:\n  Input(MetaKeys metaKey, InputConstants input) {\n    this->metaKey = metaKey;\n    this->input = input;\n  }\n\n  Input(InputConstants input) {\n    this->input = input;\n  }\n\n  bool operator==(const Input &other) const {\n    return (metaKey == other.metaKey\n        && input == other.input);\n  }\n\n  MetaKeys metaKey{MetaKeys::None};\n  InputConstants input;\n};\n\nstruct InputHash {\n  std::size_t operator()(const ng::Input &k) const noexcept {\n    return std::hash<int>()(static_cast<int>(k.metaKey))\n        ^ std::hash<int>()(static_cast<int>(k.input));\n  }\n};\n\n}\n"
  },
  {
    "path": "include/engge/Input/InputMappings.hpp",
    "content": "#pragma once\n\nnamespace ng {\nclass InputMappings {\npublic:\n  static void registerMappings();\n};\n}"
  },
  {
    "path": "include/engge/Parsers/GGPackBufferStream.hpp",
    "content": "#pragma once\n#include <ios>\n#include <vector>\n#include \"GGPackStream.hpp\"\n\nclass GGPackBufferStream : public GGPackStream {\npublic:\n  GGPackBufferStream() = default;\n  explicit GGPackBufferStream(std::vector<char> input);\n\n  void setBuffer(const std::vector<char> &input);\n  void read(char *data, size_t size) override;\n  void seek(int pos) override;\n  [[nodiscard]] int getLength() const override;\n  int tell() override;\n  [[nodiscard]] bool eof() const override;\n  [[nodiscard]] char peek() const override;\n  GGPackBufferStream &ignore(std::streamsize n = 1, int delim = EOF);\n\nprivate:\n  std::vector<char> m_input;\n  int m_offset{0};\n};\n"
  },
  {
    "path": "include/engge/Parsers/GGPackStream.hpp",
    "content": "#pragma once\n#include <cstdio>\n\nclass GGPackStream {\npublic:\n  virtual void read(char *data, size_t size) = 0;\n  virtual void seek(int pos) = 0;\n  virtual int tell() = 0;\n  [[nodiscard]] virtual int getLength() const = 0;\n  [[nodiscard]] virtual bool eof() const = 0;\n  [[nodiscard]] virtual char peek() const = 0;\n};\n"
  },
  {
    "path": "include/engge/Parsers/Lip.hpp",
    "content": "#pragma once\n#include <string>\n#include <vector>\n#include <ngf/System/TimeSpan.h>\n\n// see https://github.com/DanielSWolf/rhubarb-lip-sync for more details\n\nnamespace ng {\nstruct NGLipData {\npublic:\n  ngf::TimeSpan time;\n  char letter;\n};\n\nclass Lip {\npublic:\n  Lip();\n\n  void clear();\n  void load(const std::string &path);\n  [[nodiscard]] std::vector<NGLipData> getData() const { return m_data; }\n  [[nodiscard]] std::string getPath() const { return m_path; }\n\nprivate:\n  std::string m_path;\n  std::vector<NGLipData> m_data;\n};\n} // namespace ng\n"
  },
  {
    "path": "include/engge/Parsers/SavegameManager.hpp",
    "content": "#pragma once\n#include <string>\n#include <filesystem>\n#include <vector>\n#include <ngf/IO/GGPackValue.h>\n\nnamespace ng {\nclass SavegameManager {\npublic:\n  static ngf::GGPackValue loadGame(const std::filesystem::path &path);\n  static void saveGame(const std::filesystem::path &path, const ngf::GGPackValue& hash);\n  static int32_t computeHash(const std::vector<char> &data, int32_t size);\n};\n}"
  },
  {
    "path": "include/engge/Parsers/YackParser.hpp",
    "content": "#pragma once\n#include <string>\n#include <fstream>\n#include <iostream>\n#include <memory>\n#include <vector>\n#include \"YackTokenReader.hpp\"\n\nnamespace ng {\nnamespace Ast {\nclass AstVisitor;\n\nclass Node {\nprotected:\n  Node() = default;\n\npublic:\n  virtual ~Node();\n  virtual void accept(AstVisitor &visitor) = 0;\n\n  std::streampos start;\n  std::streampos end;\n};\n\nclass Expression : public Node {\nprotected:\n  Expression() = default;\n\npublic:\n  ~Expression() override;\n};\n\nclass Condition : public Node {\nprotected:\n  explicit Condition(int32_t line);\npublic:\n  ~Condition() override;\n  int32_t getLine() const { return m_line; }\nprivate:\n  int32_t m_line;\n};\n\nclass CodeCondition : public Condition {\npublic:\n  explicit CodeCondition(int32_t line);\n  ~CodeCondition() override;\n\n  void accept(AstVisitor &visitor) override;\n\n  std::string code;\n};\n\nclass OnceCondition : public Condition {\npublic:\n  explicit OnceCondition(int32_t line);\n  ~OnceCondition() override;\n\n  void accept(AstVisitor &visitor) override;\n};\n\nclass ShowOnceCondition : public Condition {\npublic:\n  explicit ShowOnceCondition(int32_t line);\n  ~ShowOnceCondition() override;\n\n  void accept(AstVisitor &visitor) override;\n};\n\nclass OnceEverCondition : public Condition {\npublic:\n  explicit OnceEverCondition(int32_t line);\n  ~OnceEverCondition() override;\n\n  void accept(AstVisitor &visitor) override;\n};\n\nclass TempOnceCondition : public Condition {\npublic:\n  explicit TempOnceCondition(int32_t line);\n  ~TempOnceCondition() override;\n\n  void accept(AstVisitor &visitor) override;\n};\n\nclass Statement : public Node {\npublic:\n  Statement() = default;\n  ~Statement() override;\n\n  void accept(AstVisitor &visitor) override;\n\n  std::unique_ptr<Expression> expression;\n  std::vector<std::unique_ptr<Condition>> conditions;\n};\n\nclass Goto : public Expression {\npublic:\n  Goto() = default;\n  ~Goto() override;\n\n  void accept(AstVisitor &visitor) override;\n  std::string name;\n};\n\nclass Code : public Expression {\npublic:\n  Code() = default;\n  ~Code() override;\n\n  void accept(AstVisitor &visitor) override;\n  std::string code;\n};\n\nclass Choice : public Expression {\npublic:\n  Choice() = default;\n  ~Choice() override;\n\n  void accept(AstVisitor &visitor) override;\n  int number{0};\n  std::string text;\n  std::unique_ptr<Goto> gotoExp;\n};\n\nclass Say : public Expression {\npublic:\n  Say() = default;\n  ~Say() override;\n\n  void accept(AstVisitor &visitor) override;\n  std::string actor;\n  std::string text;\n};\n\nclass Pause : public Expression {\npublic:\n  Pause() = default;\n  ~Pause() override;\n\n  void accept(AstVisitor &visitor) override;\n  float time{0};\n};\n\nclass Parrot : public Expression {\npublic:\n  Parrot() = default;\n  ~Parrot() override;\n\n  void accept(AstVisitor &visitor) override;\n  bool active{true};\n};\n\nclass Dialog : public Expression {\npublic:\n  Dialog() = default;\n  ~Dialog() override;\n\n  void accept(AstVisitor &visitor) override;\n  std::string actor;\n};\n\nclass Override : public Expression {\npublic:\n  Override() = default;\n  ~Override() override;\n\n  void accept(AstVisitor &visitor) override;\n  std::string node;\n};\n\nclass Shutup : public Expression {\npublic:\n  Shutup() = default;\n  ~Shutup() override;\n\n  void accept(AstVisitor &visitor) override;\n};\n\nclass AllowObjects : public Expression {\npublic:\n  AllowObjects() = default;\n  ~AllowObjects() override;\n\n  void accept(AstVisitor &visitor) override;\n\n  bool allow{true};\n};\n\nclass Limit : public Expression {\npublic:\n  Limit() = default;\n  ~Limit() override;\n\n  void accept(AstVisitor &visitor) override;\n\n  int max{0};\n};\n\nclass WaitWhile : public Expression {\npublic:\n  WaitWhile() = default;\n  ~WaitWhile() override;\n\n  void accept(AstVisitor &visitor) override;\n\n  std::string condition;\n};\n\nclass WaitFor : public Expression {\npublic:\n  WaitFor() = default;\n  ~WaitFor() override;\n\n  void accept(AstVisitor &visitor) override;\n  std::string actor;\n};\n\nclass Label : public Node {\npublic:\n  Label() = default;\n  ~Label() override;\n\n  void accept(AstVisitor &visitor) override;\n  std::string name;\n  std::vector<std::unique_ptr<Statement>> statements;\n};\n\nclass CompilationUnit {\npublic:\n  CompilationUnit() = default;\n  virtual ~CompilationUnit();\n\n  std::vector<std::unique_ptr<Label>> labels;\n};\n\nclass AstVisitor {\npublic:\n  virtual ~AstVisitor();\n  virtual void visit(const Statement &node);\n  virtual void visit(const Label &node);\n  virtual void visit(const Say &node);\n  virtual void visit(const Choice &node);\n  virtual void visit(const Code &node);\n  virtual void visit(const Goto &node);\n  virtual void visit(const CodeCondition &node);\n  virtual void visit(const OnceCondition &node);\n  virtual void visit(const ShowOnceCondition &node);\n  virtual void visit(const OnceEverCondition &node);\n  virtual void visit(const TempOnceCondition &node);\n  virtual void visit(const Shutup &node);\n  virtual void visit(const Pause &node);\n  virtual void visit(const WaitFor &node);\n  virtual void visit(const Parrot &node);\n  virtual void visit(const Dialog &node);\n  virtual void visit(const Override &node);\n  virtual void visit(const AllowObjects &node);\n  virtual void visit(const WaitWhile &node);\n  virtual void visit(const Limit &node);\n  virtual void defaultVisit(const Node &node);\n};\n} // namespace Ast\n\nclass YackParser {\npublic:\n  explicit YackParser(YackTokenReader &reader);\n  std::unique_ptr<Ast::CompilationUnit> parse();\n\nprivate:\n  bool match(const std::initializer_list<TokenId> &ids);\n  std::unique_ptr<Ast::Label> parseLabel();\n  std::unique_ptr<Ast::Statement> parseStatement();\n  std::unique_ptr<Ast::Condition> parseCondition();\n  std::unique_ptr<Ast::Expression> parseExpression();\n  std::unique_ptr<Ast::Say> parseSayExpression();\n  std::unique_ptr<Ast::Expression> parseWaitWhileExpression();\n  std::unique_ptr<Ast::Expression> parseInstructionExpression();\n  std::unique_ptr<Ast::Goto> parseGotoExpression();\n  std::unique_ptr<Ast::Code> parseCodeExpression();\n  std::unique_ptr<Ast::Choice> parseChoiceExpression();\n\nprivate:\n  YackTokenReader &m_reader;\n  YackTokenReader::iterator m_it;\n};\n} // namespace ng\n"
  },
  {
    "path": "include/engge/Parsers/YackTokenReader.hpp",
    "content": "#pragma once\n#include <string>\n#include <iostream>\n#include <fstream>\n#include <map>\n#include <vector>\n#include \"GGPackBufferStream.hpp\"\n\nnamespace ng {\nenum class TokenId {\n  None,\n  NewLine,\n  Identifier,\n  WaitWhile,\n  Number,\n  Whitespace,\n  Colon,\n  Condition,\n  String,\n  Assign,\n  Comment,\n  Goto,\n  Code,\n  Dollar,\n  End\n};\n\nstruct Token {\n  TokenId id;\n  std::streampos start;\n  std::streampos end;\n\n  friend std::ostream &operator<<(std::ostream &os, const Token &obj);\n\nprivate:\n  [[nodiscard]] std::string readToken() const;\n};\n\nclass YackTokenReader {\npublic:\n  class Iterator {\n  public:\n    using value_type = Token;\n    using difference_type = ptrdiff_t;\n    using pointer = Token *;\n    using reference = Token &;\n    using iterator_category = std::forward_iterator_tag;\n\n  private:\n    YackTokenReader &m_reader;\n    std::streampos m_pos;\n    Token m_token;\n\n  public:\n    Iterator(YackTokenReader &reader, std::streampos pos);\n    Iterator(const Iterator &it);\n    Iterator &operator++();\n    Iterator operator++(int);\n\n    bool operator==(const Iterator &rhs) const { return m_pos == rhs.m_pos; }\n    bool operator!=(const Iterator &rhs) const { return m_pos != rhs.m_pos; }\n    Token &operator*();\n    const Token &operator*() const;\n    Token *operator->();\n  };\n\n  using iterator = Iterator;\n\npublic:\n  YackTokenReader();\n\n  void load(const std::string &path);\n  iterator begin();\n  iterator end();\n  bool readToken(Token &token);\n  std::string readText(std::streampos pos, std::streamsize size);\n  std::string readText(const Token &token);\n  int getLine(const Token &token) const;\n\nprivate:\n  TokenId readTokenId();\n  TokenId readCode();\n  TokenId readCondition();\n  TokenId readDollar();\n  TokenId readNumber();\n  TokenId readComment();\n  TokenId readString();\n  TokenId readIdentifier(char c);\n\nprivate:\n  GGPackBufferStream m_stream;\n  std::map<int, int> m_lines;\n  int m_offset;\n};\n} // namespace ng\n"
  },
  {
    "path": "include/engge/Room/Room.hpp",
    "content": "#pragma once\n#include <vector>\n#include <engge/Graphics/SpriteSheet.hpp>\n#include <squirrel.h>\n#include <ngf/System/TimeSpan.h>\n#include <ngf/Graphics/RenderTarget.h>\n#include <ngf/Graphics/Color.h>\n#include <engge/Scripting/ScriptObject.hpp>\n#include <engge/Graphics/LightingShader.h>\n\nnamespace ngf {\nclass Walkbox;\nclass Graph;\n}\n\nnamespace ng {\nclass Entity;\nclass Light;\nclass Object;\nclass RoomScaling;\nclass ResourceManager;\nclass TextObject;\nclass ThreadBase;\n\n/// @brief Room effect used by roomEffect method\n///\n/// Only None, Ghost and BlackAndWhite are explicitly used.\n/// The others can be used with flashbackEffect settings.\nnamespace RoomEffectConstants {\nstatic const int EFFECT_NONE = 0;\nstatic const int EFFECT_SEPIA = 1;\nstatic const int EFFECT_EGA = 2;\nstatic const int EFFECT_VHS = 3;\nstatic const int EFFECT_GHOST = 4;\nstatic const int EFFECT_BLACKANDWHITE = 5;\n}\n\nclass Room : public ScriptObject {\npublic:\n  static std::unique_ptr<Room> define(HSQOBJECT roomTable, const char *name = nullptr);\n\n  explicit Room(HSQOBJECT roomTable);\n  ~Room() override;\n\n  void setName(const std::string &name);\n  [[nodiscard]] std::string getName() const;\n\n  void load(const char *name);\n  std::vector<std::unique_ptr<Object>> &getObjects();\n  [[nodiscard]] const std::vector<std::unique_ptr<Object>> &getObjects() const;\n  [[nodiscard]] std::array<Light, LightingShader::MaxLights> &getLights();\n  [[nodiscard]] int getNumberLights() const;\n  LightingShader& getLightingShader();\n\n  void update(const ngf::TimeSpan &elapsed);\n  void draw(ngf::RenderTarget &target, const glm::vec2 &cameraPos) const;\n  void drawForeground(ngf::RenderTarget &target, const glm::vec2 &cameraPos) const;\n\n  void setWalkboxEnabled(const std::string &name, bool isEnabled);\n  [[nodiscard]] const ngf::Walkbox *getWalkbox(const std::string &name) const;\n  [[nodiscard]] std::vector<glm::vec2> calculatePath(glm::vec2 start, glm::vec2 end) const;\n  std::vector<ngf::Walkbox> &getWalkboxes();\n  std::vector<ngf::Walkbox> &getGraphWalkboxes();\n  [[nodiscard]] const ngf::Graph *getGraph() const;\n\n  Object &createObject(const std::string &sheet, const std::vector<std::string> &anims);\n  Object &createObject(const std::vector<std::string> &anims);\n  Object &createObject(const std::string &image);\n  Object &createObject();\n  TextObject &createTextObject(const std::string &fontName);\n  void deleteObject(Object &textObject);\n  [[nodiscard]] glm::ivec2 getRoomSize() const;\n  [[nodiscard]] glm::ivec2 getScreenSize() const;\n  [[nodiscard]] int32_t getFullscreen() const;\n  [[nodiscard]] int32_t getScreenHeight() const;\n  void setAsParallaxLayer(Entity *pEntity, int layer);\n  void roomLayer(int layer, bool enabled);\n  void setRoomScaling(const RoomScaling &scaling);\n  [[nodiscard]] const RoomScaling &getRoomScaling() const;\n  HSQOBJECT &getTable();\n\n  [[nodiscard]] const SpriteSheet &getSpriteSheet() const;\n\n  void setAmbientLight(ngf::Color color);\n  [[nodiscard]] ngf::Color getAmbientLight() const;\n\n  void removeEntity(Entity *pEntity);\n  std::vector<RoomScaling> &getScalings();\n\n  [[nodiscard]] float getRotation() const;\n  void setRotation(float angle);\n\n  Light *createLight(ngf::Color color, glm::ivec2 pos);\n  void exit();\n\n  void setEffect(int shader);\n  [[nodiscard]] int getEffect() const;\n\n  void setOverlayColor(ngf::Color color);\n  [[nodiscard]] ngf::Color getOverlayColor() const;\n\n  void setPseudoRoom(bool pseudoRoom);\n  [[nodiscard]] bool isPseudoRoom() const;\n\nprivate:\n  struct Impl;\n  std::unique_ptr<Impl> m_pImpl;\n};\n} // namespace ng\n"
  },
  {
    "path": "include/engge/Room/RoomLayer.hpp",
    "content": "#pragma once\n#include <vector>\n#include <ngf/Graphics/Texture.h>\n#include <engge/Entities/Entity.hpp>\n#include <engge/Graphics/SpriteSheetItem.h>\n\nnamespace ng {\n\nclass RoomLayer {\npublic:\n  RoomLayer();\n  ~RoomLayer() = default;\n\n  void setTexture(const std::string &texture);\n  void setRoomSizeY(int roomSizeY) { m_roomSizeY = roomSizeY; }\n  void setOffsetY(int offsetY) { m_offsetY = offsetY; }\n\n  std::vector<SpriteSheetItem> &getBackgrounds() { return m_backgrounds; }\n\n  void setParallax(const glm::vec2 &parallax) { m_parallax = parallax; }\n  [[nodiscard]] const glm::vec2 &getParallax() const { return m_parallax; }\n\n  void setZOrder(int zsort) { m_zsort = zsort; }\n  [[nodiscard]] int getZOrder() const { return m_zsort; }\n\n  void addEntity(Entity &entity);\n  void removeEntity(Entity &entity);\n\n  void setEnabled(bool enabled) { m_enabled = enabled; }\n  [[nodiscard]] bool isEnabled() const { return m_enabled; }\n\n  void draw(ngf::RenderTarget &target, ngf::RenderStates states) const;\n  void drawForeground(ngf::RenderTarget &target, ngf::RenderStates states) const;\n  void update(const ngf::TimeSpan &elapsed);\n\nprivate:\n  std::string m_textureName;\n  std::vector<SpriteSheetItem> m_backgrounds;\n  std::vector<std::reference_wrapper<Entity>> m_entities;\n  glm::vec2 m_parallax{1, 1};\n  int m_zsort{0};\n  bool m_enabled{true};\n  int m_offsetY{0};\n  int m_roomSizeY{0};\n};\n} // namespace ng\n"
  },
  {
    "path": "include/engge/Room/RoomScaling.hpp",
    "content": "#pragma once\n#include <vector>\n#include <string>\n\nnamespace ng {\nstruct Scaling {\n  float scale;\n  float yPos;\n};\n\nclass RoomScaling {\npublic:\n  RoomScaling() = default;\n  ~RoomScaling() = default;\n\n  void setTrigger(const std::string &trigger);\n  [[nodiscard]] const std::string &getName() const;\n  [[nodiscard]] float getScaling(float yPos) const;\n  std::vector<Scaling> &getScalings();\n\nprivate:\n  std::string m_trigger;\n  std::vector<Scaling> m_scalings;\n};\n} // namespace ng\n"
  },
  {
    "path": "include/engge/Scripting/ScriptEngine.hpp",
    "content": "#pragma once\n#include <cassert>\n#include <functional>\n#include <string>\n#include <squirrel.h>\n#include \"../../../extlibs/squirrel/squirrel/sqobject.h\"\n#include \"engge/Engine/Engine.hpp\"\n#include \"engge/Engine/Interpolations.hpp\"\n#include \"engge/System/Logger.hpp\"\n#include <sqstdaux.h>\n#include <sqstdio.h>\n\nnamespace ng {\nclass Pack {\npublic:\n  virtual void registerPack() const = 0;\n  virtual ~Pack() = default;\n};\nclass ScriptEngine {\npublic:\n  using ErrorCallback = std::function<void(\n      HSQUIRRELVM, const SQChar *, const SQChar *, SQInteger, SQInteger)>;\n  using PrintCallback = std::function<void(HSQUIRRELVM v, const SQChar *s)>;\n\npublic:\n  explicit ScriptEngine();\n  ~ScriptEngine();\n\n  void setEngine(Engine &engine);\n  static Engine &getEngine();\n\n  static HSQUIRRELVM getVm() { return m_vm; }\n\n  static SQObjectPtr toSquirrel(const std::string &value);\n\n  template <typename TConstant>\n  void registerConstants(\n      std::initializer_list<std::tuple<const SQChar *, TConstant>> list);\n  static void registerGlobalFunction(SQFUNCTION f, const SQChar *functionName,\n                                     SQInteger nparamscheck = 0,\n                                     const SQChar *typemask = nullptr);\n  static void executeScript(const std::string &name);\n  static void executeNutScript(const std::string &name);\n\n  template <class TPack> void registerPack();\n\n  template <class T> static void pushObject(HSQUIRRELVM v, T *pObject);\n\n  template <typename T> static void push(HSQUIRRELVM v, T value);\n  template <typename First, typename... Rest>\n  static void push(HSQUIRRELVM v, First firstValue, Rest... rest);\n\n  template <typename TThis> static bool exists(TThis pThis, const char *name);\n\n  template <typename T>\n  static bool get(SQInteger index, T &result);\n  template <typename T> static bool get(const char *name, T &result);\n  template <typename TThis, typename T>\n  static bool get(TThis pThis, const char *name, T &result);\n\n  template <typename T> static void set(const char *name, T value);\n\n  template <typename TThis, typename T>\n  static void set(TThis pThis, const char *name, T value);\n\n  template <typename... T> static bool call(const char *name, T... args);\n  static bool call(const char *name);\n\n  template <typename TThis, typename... T>\n  static bool objCall(TThis pThis, const char *name, T... args);\n  template <typename TThis> static bool objCall(TThis pThis, const char *name);\n  template <typename TThis>\n  static int getParameterCount(TThis pThis, const char *name);\n\n  template <typename TResult, typename TThis, typename... T>\n  static bool callFunc(TResult &result, TThis pThis, const char *name,\n                       T... args);\n\n  template <typename TResult, typename... T>\n  static bool callFunc(TResult &result, const char *name, T... args);\n\n  template <typename TThis>\n  static bool rawExists(TThis pThis, const char *name);\n\n  template <typename TThis, typename T>\n  static bool rawGet(TThis pThis, const char *name, T &result);\n\n  template <typename... T> static bool rawCall(const char *name, T... args);\n  static bool rawCall(const char *name);\n\n  template <typename TThis, typename... T>\n  static bool rawCall(TThis pThis, const char *name, T... args);\n  template <typename TThis> static bool rawCall(TThis pThis, const char *name);\n\n  template <typename TResult, typename TThis, typename... T>\n  static bool rawCallFunc(TResult &result, TThis pThis, const char *name,\n                          T... args);\n\n  static void registerErrorCallback(const PrintCallback &callback) {\n    m_errorCallbacks.push_back(callback);\n  }\n\n  static void registerPrintCallback(const PrintCallback &callback) {\n    m_printCallbacks.push_back(callback);\n  }\n\n  static void printfunc(HSQUIRRELVM v, const SQChar *s, ...);\n\nprivate:\n  static SQInteger aux_printerror(HSQUIRRELVM v);\n  static void errorHandler(HSQUIRRELVM v, const SQChar *desc,\n                           const SQChar *source, SQInteger line,\n                           SQInteger column);\n\n  static void errorfunc(HSQUIRRELVM v, const SQChar *s, ...);\n\nprivate:\n  inline static HSQUIRRELVM m_vm{};\n  std::vector<std::unique_ptr<Pack>> m_packs;\n  inline static std::vector<PrintCallback> m_errorCallbacks;\n  inline static std::vector<PrintCallback> m_printCallbacks;\n\nprivate:\n  static Engine *g_pEngine;\n};\n\ntemplate <typename First, typename... Rest>\nvoid ScriptEngine::push(HSQUIRRELVM v, First firstValue, Rest... rest) {\n  ScriptEngine::push(v, firstValue);\n  ScriptEngine::push(v, rest...);\n}\n\ntemplate <typename... T> bool ScriptEngine::call(const char *name, T... args) {\n  constexpr std::size_t n = sizeof...(T);\n  auto v = ScriptEngine::getVm();\n  auto top = sq_gettop(v);\n  sq_pushroottable(v);\n  sq_pushstring(v, _SC(name), -1);\n  if (SQ_FAILED(sq_get(v, -2))) {\n    sq_settop(v, top);\n    trace(\"can't find {} function\", name);\n    return false;\n  }\n  sq_remove(v, -2);\n\n  sq_pushroottable(v);\n  ScriptEngine::push(v, std::forward<T>(args)...);\n  if (SQ_FAILED(sq_call(v, n + 1, SQFalse, SQTrue))) {\n    sqstd_printcallstack(v);\n    sq_settop(v, top);\n    error(\"function {} call failed\", name);\n    return false;\n  }\n  sq_settop(v, top);\n  return true;\n}\n\ntemplate <typename TThis>\nint ScriptEngine::getParameterCount(TThis pThis, const char *name) {\n  auto v = ScriptEngine::getVm();\n  auto top = sq_gettop(v);\n  ScriptEngine::push(v, pThis);\n  sq_pushstring(v, name, -1);\n  if (SQ_FAILED(sq_get(v, -2))) {\n    sq_settop(v, top);\n    trace(\"can't find {} function\", name);\n    return 0;\n  }\n\n  SQInteger nparams, nfreevars;\n  sq_getclosureinfo(v, -1, &nparams, &nfreevars);\n  trace(\"{} function found with {} parameters\", name, nparams);\n  sq_settop(v, top);\n\n  return nparams;\n}\n\ntemplate <typename... T>\nbool ScriptEngine::rawCall(const char *name, T... args) {\n  constexpr std::size_t n = sizeof...(T);\n  auto v = ScriptEngine::getVm();\n  auto top = sq_gettop(v);\n  sq_pushroottable(v);\n  sq_pushstring(v, _SC(name), -1);\n  if (SQ_FAILED(sq_rawget(v, -2))) {\n    sq_settop(v, top);\n    trace(\"can't find {} function\", name);\n    return false;\n  }\n  sq_remove(v, -2);\n\n  sq_pushroottable(v);\n  ScriptEngine::push(v, std::forward<T>(args)...);\n  if (SQ_FAILED(sq_call(v, n + 1, SQFalse, SQTrue))) {\n    sqstd_printcallstack(v);\n    sq_settop(v, top);\n    error(\"function {} call failed\", name);\n    return false;\n  }\n  sq_settop(v, top);\n  return true;\n}\n\ntemplate <typename TThis, typename... T>\nbool ScriptEngine::objCall(TThis pThis, const char *name, T... args) {\n  constexpr std::size_t n = sizeof...(T);\n  auto v = ScriptEngine::getVm();\n  auto top = sq_gettop(v);\n  ScriptEngine::push(v, pThis);\n  sq_pushstring(v, _SC(name), -1);\n  if (SQ_FAILED(sq_get(v, -2))) {\n    sq_settop(v, top);\n    trace(\"can't find {} function\", name);\n    return false;\n  }\n  sq_remove(v, -2);\n\n  ScriptEngine::push(v, pThis);\n  ScriptEngine::push(v, std::forward<T>(args)...);\n  if (SQ_FAILED(sq_call(v, n + 1, SQFalse, SQTrue))) {\n    sqstd_printcallstack(v);\n    sq_settop(v, top);\n    error(\"function {} call failed\", name);\n    return false;\n  }\n  sq_settop(v, top);\n  return true;\n}\n\ntemplate <typename TThis, typename... T>\nbool ScriptEngine::rawCall(TThis pThis, const char *name, T... args) {\n  constexpr std::size_t n = sizeof...(T);\n  auto v = ScriptEngine::getVm();\n  auto top = sq_gettop(v);\n  ScriptEngine::push(v, pThis);\n  sq_pushstring(v, _SC(name), -1);\n  if (SQ_FAILED(sq_rawget(v, -2))) {\n    sq_settop(v, top);\n    trace(\"can't find {} function\", name);\n    return false;\n  }\n  sq_remove(v, -2);\n\n  ScriptEngine::push(v, pThis);\n  ScriptEngine::push(v, std::forward<T>(args)...);\n  if (SQ_FAILED(sq_call(v, n + 1, SQFalse, SQTrue))) {\n    sqstd_printcallstack(v);\n    sq_settop(v, top);\n    error(\"function {} call failed\", name);\n    return false;\n  }\n  sq_settop(v, top);\n  return true;\n}\n\ntemplate <typename TThis>\nbool ScriptEngine::objCall(TThis pThis, const char *name) {\n  auto v = ScriptEngine::getVm();\n  auto top = sq_gettop(v);\n  ScriptEngine::push(v, pThis);\n  sq_pushstring(v, _SC(name), -1);\n  if (SQ_FAILED(sq_get(v, -2))) {\n    sq_settop(v, top);\n    trace(\"can't find {} function\", name);\n    return false;\n  }\n  sq_remove(v, -2);\n\n  ScriptEngine::push(v, pThis);\n  if (SQ_FAILED(sq_call(v, 1, SQFalse, SQTrue))) {\n    sqstd_printcallstack(v);\n    sq_settop(v, top);\n    error(\"function {} call failed\", name);\n    return false;\n  }\n  sq_settop(v, top);\n  return true;\n}\n\ntemplate <typename TThis>\nbool ScriptEngine::rawCall(TThis pThis, const char *name) {\n  auto v = ScriptEngine::getVm();\n  auto top = sq_gettop(v);\n  ScriptEngine::push(v, pThis);\n  sq_pushstring(v, _SC(name), -1);\n  if (SQ_FAILED(sq_rawget(v, -2))) {\n    sq_settop(v, top);\n    trace(\"can't find {} function\", name);\n    return false;\n  }\n  sq_remove(v, -2);\n\n  ScriptEngine::push(v, pThis);\n  if (SQ_FAILED(sq_call(v, 1, SQFalse, SQTrue))) {\n    sqstd_printcallstack(v);\n    sq_settop(v, top);\n    error(\"function {} call failed\", name);\n    return false;\n  }\n  sq_settop(v, top);\n  return true;\n}\n\ntemplate <typename TResult, typename TThis, typename... T>\nbool ScriptEngine::callFunc(TResult &result, TThis pThis, const char *name,\n                            T... args) {\n  constexpr std::size_t n = sizeof...(T);\n  auto v = ScriptEngine::getVm();\n  auto top = sq_gettop(v);\n  ScriptEngine::push(v, pThis);\n  sq_pushstring(v, _SC(name), -1);\n  if (SQ_FAILED(sq_get(v, -2))) {\n    sq_settop(v, top);\n    trace(\"can't find {} function\", name);\n    return false;\n  }\n  sq_remove(v, -2);\n\n  ScriptEngine::push(v, pThis);\n  if constexpr(n > 0) {\n    ScriptEngine::push(v, std::forward<T>(args)...);\n  }\n  if (SQ_FAILED(sq_call(v, n + 1, SQTrue, SQTrue))) {\n    sqstd_printcallstack(v);\n    sq_settop(v, top);\n    error(\"function {} call failed\", name);\n    return false;\n  }\n  ScriptEngine::get(-1, result);\n  sq_settop(v, top);\n  return true;\n}\n\ntemplate <typename TResult, typename... T>\nbool ScriptEngine::callFunc(TResult &result, const char *name, T... args) {\n  constexpr std::size_t n = sizeof...(T);\n  auto v = ScriptEngine::getVm();\n  auto top = sq_gettop(v);\n  sq_pushroottable(v);\n  sq_pushstring(v, _SC(name), -1);\n  if (SQ_FAILED(sq_get(v, -2))) {\n    sq_settop(v, top);\n    trace(\"can't find {} function\", name);\n    return false;\n  }\n  sq_remove(v, -2);\n\n  sq_pushroottable(v);\n  ScriptEngine::push(v, std::forward<T>(args)...);\n  if (SQ_FAILED(sq_call(v, n + 1, SQTrue, SQTrue))) {\n    sqstd_printcallstack(v);\n    sq_settop(v, top);\n    error(\"function {} call failed\", name);\n    return false;\n  }\n  ScriptEngine::get(-1, result);\n  sq_settop(v, top);\n  return true;\n}\n\ntemplate <typename TResult, typename TThis, typename... T>\nbool ScriptEngine::rawCallFunc(TResult &result, TThis pThis, const char *name,\n                               T... args) {\n  constexpr std::size_t n = sizeof...(T);\n  auto v = ScriptEngine::getVm();\n  auto top = sq_gettop(v);\n  ScriptEngine::push(v, pThis);\n  sq_pushstring(v, _SC(name), -1);\n  if (SQ_FAILED(sq_rawget(v, -2))) {\n    sq_settop(v, top);\n    trace(\"can't find {} function\", name);\n    return false;\n  }\n\n  ScriptEngine::push(v, pThis);\n  if constexpr (n > 0) {\n    ScriptEngine::push(v, std::forward<T>(args)...);\n  }\n  if (SQ_FAILED(sq_call(v, n + 1, SQTrue, SQTrue))) {\n    sqstd_printcallstack(v);\n    sq_settop(v, top);\n    error(\"function {} call failed\", name);\n    return false;\n  }\n  ScriptEngine::get(-1, result);\n  sq_settop(v, top);\n  return true;\n}\n\ntemplate <typename T> bool ScriptEngine::get(const char *name, T &result) {\n  auto v = getVm();\n  sq_pushroottable(v);\n  HSQOBJECT rootTable;\n  sq_getstackobj(v, -1, &rootTable);\n  sq_pop(v, 1);\n  return ScriptEngine::get(rootTable, name, result);\n}\n\ntemplate <typename TThis, typename T>\nbool ScriptEngine::get(TThis pThis, const char *name, T &result) {\n  auto v = ScriptEngine::getVm();\n  auto top = sq_gettop(v);\n  push(v, pThis);\n  sq_pushstring(v, _SC(name), -1);\n  if (SQ_SUCCEEDED(sq_get(v, -2))) {\n    auto status = ScriptEngine::get(-1, result);\n    sq_settop(v, top);\n    return status;\n  }\n  sq_settop(v, top);\n  return false;\n}\n\ntemplate <typename TThis, typename T>\nbool ScriptEngine::rawGet(TThis pThis, const char *name,\n                          T &result) {\n  auto v = ScriptEngine::getVm();\n  auto top = sq_gettop(v);\n  push(v, pThis);\n  sq_pushstring(v, _SC(name), -1);\n  if (SQ_SUCCEEDED(sq_rawget(v, -2))) {\n    auto status = ScriptEngine::get(-1, result);\n    sq_settop(v, top);\n    return status;\n  }\n  sq_settop(v, top);\n  return false;\n}\n\ntemplate <typename TThis>\nbool ScriptEngine::exists(TThis pThis, const char *name) {\n  auto v = ScriptEngine::getVm();\n  auto top = sq_gettop(v);\n  push(v, pThis);\n  sq_pushstring(v, _SC(name), -1);\n  if (SQ_SUCCEEDED(sq_get(v, -2))) {\n    auto type = sq_gettype(v, -1);\n    sq_settop(v, top);\n    return type != OT_NULL;\n  }\n  sq_settop(v, top);\n  return false;\n}\n\ntemplate <typename TThis>\nbool ScriptEngine::rawExists(TThis pThis, const char *name) {\n  auto v = ScriptEngine::getVm();\n  auto top = sq_gettop(v);\n  push(v, pThis);\n  sq_pushstring(v, _SC(name), -1);\n  if (SQ_SUCCEEDED(sq_rawget(v, -2))) {\n    auto type = sq_gettype(v, -1);\n    sq_settop(v, top);\n    return type != OT_NULL;\n  }\n  sq_settop(v, top);\n  return false;\n}\n\ntemplate <typename T> void ScriptEngine::set(const char *name, T value) {\n  auto v = ScriptEngine::getVm();\n  sq_pushroottable(v);\n  sq_pushstring(v, _SC(name), -1);\n  ScriptEngine::push(v, value);\n  sq_newslot(v, -3, SQFalse);\n  sq_pop(v, 1);\n}\n\ntemplate <typename TThis, typename T>\nvoid ScriptEngine::set(TThis pThis, const char *name, T value) {\n  auto v = ScriptEngine::getVm();\n  push(v, pThis);\n  sq_pushstring(v, _SC(name), -1);\n  ScriptEngine::push(v, value);\n  sq_newslot(v, -3, SQFalse);\n  sq_pop(v, 1);\n}\n\n} // namespace ng"
  },
  {
    "path": "include/engge/Scripting/ScriptExecute.hpp",
    "content": "#pragma once\n#include <string>\n\nnamespace ng {\nclass SoundDefinition;\nclass ScriptExecute {\npublic:\n  virtual ~ScriptExecute() = default;\n  virtual void execute(const std::string &code) = 0;\n  virtual std::string executeDollar(const std::string &code) = 0;\n  virtual bool executeCondition(const std::string &code) = 0;\n  virtual SoundDefinition *getSoundDefinition(const std::string &name) = 0;\n};\n}"
  },
  {
    "path": "include/engge/Scripting/ScriptObject.hpp",
    "content": "#pragma once\n\nnamespace ng {\nclass ScriptObject {\npublic:\n  virtual ~ScriptObject() = default;\n\n  [[nodiscard]] int getId() const { return m_id; }\n\nprotected:\n  int m_id{0};\n};\n}"
  },
  {
    "path": "include/engge/Scripting/VerbExecute.hpp",
    "content": "#pragma once\n\nnamespace ng {\nclass Entity;\nstruct Verb;\n\nclass VerbExecute {\npublic:\n  virtual ~VerbExecute() = default;\n  virtual void execute(const Verb *pVerb, Entity *pObject1, Entity *pObject2) = 0;\n};\n}"
  },
  {
    "path": "include/engge/System/Locator.hpp",
    "content": "#pragma once\n#include <memory>\n\nnamespace ng {\nclass Logger;\nclass EntityManager;\n\ntemplate<typename TService>\nstruct Locator {\n  Locator() = delete;\n  ~Locator() = delete;\n\n  inline static void set(std::shared_ptr<TService> pService) {\n    m_pService = std::move(pService);\n  }\n\n  template<class ..._Args>\n  inline static TService &create(_Args &&...__args) {\n    m_pService = std::move(std::make_shared<TService>(std::forward<_Args>(__args)...));\n    return *m_pService;\n  }\n\n  inline static TService &get() {\n    return *m_pService;\n  }\n\n  static void reset() {\n    m_pService.reset();\n  }\n\nprivate:\n  static std::shared_ptr<TService> m_pService;\n};\n\ntemplate<typename TService>\nstd::shared_ptr<TService> Locator<TService>::m_pService{};\n}\n"
  },
  {
    "path": "include/engge/System/Logger.hpp",
    "content": "#pragma once\n#include <memory>\n#include <spdlog/spdlog.h>\n#include \"Locator.hpp\"\n#undef Yield\n\nnamespace ng {\ntemplate<typename T>\nusing basic_string_view_t = fmt::basic_string_view<T>;\n\nusing string_view_t = spdlog::string_view_t;\n\nclass Logger {\npublic:\n  Logger();\n  virtual ~Logger() = default;\n\n  template<typename... Args>\n  void trace(string_view_t message, const Args &... args);\n  template<typename... Args>\n  void info(string_view_t message, const Args &... args);\n  template<typename... Args>\n  void warn(string_view_t message, const Args &... args);\n  template<typename... Args>\n  void error(string_view_t message, const Args &... args);\n  template<typename... Args>\n  void critical(string_view_t message, const Args &... args);\n\nprivate:\n  std::shared_ptr<spdlog::logger> m_out;\n};\n\ntemplate<typename... Args>\nvoid Logger::trace(string_view_t message, const Args &... args) {\n  m_out->trace(message, args...);\n}\n\ntemplate<typename... Args>\nvoid Logger::info(string_view_t message, const Args &... args) {\n  m_out->info(message, args...);\n}\n\ntemplate<typename... Args>\nvoid Logger::warn(string_view_t message, const Args &... args) {\n  m_out->warn(message, args...);\n}\n\ntemplate<typename... Args>\nvoid Logger::error(string_view_t message, const Args &... args) {\n  m_out->error(message, args...);\n}\n\ntemplate<typename... Args>\nvoid Logger::critical(string_view_t message, const Args &... args) {\n  m_out->critical(message, args...);\n}\n\ntemplate<typename... Args>\nstatic void trace(string_view_t message, const Args &... args) {\n  Locator<Logger>::get().trace(message, args...);\n}\n\ntemplate<typename... Args>\nstatic void info(string_view_t message, const Args &... args) {\n  Locator<Logger>::get().info(message, args...);\n}\n\ntemplate<typename... Args>\nstatic void warn(string_view_t message, const Args &... args) {\n  Locator<Logger>::get().warn(message, args...);\n}\n\ntemplate<typename... Args>\nstatic void error(string_view_t message, const Args &... args) {\n  Locator<Logger>::get().error(message, args...);\n}\n\ntemplate<typename... Args>\nstatic void critical(string_view_t message, const Args &... args) {\n  Locator<Logger>::get().critical(message, args...);\n}\n} // namespace ng\n"
  },
  {
    "path": "include/engge/System/NonCopyable.hpp",
    "content": "#pragma once\n\nnamespace ng {\nclass NonCopyable {\nprotected:\n  NonCopyable() = default;\n\n  ~NonCopyable() = default;\n\nprivate:\n  NonCopyable(const NonCopyable &) = delete;\n  NonCopyable &operator=(const NonCopyable &) = delete;\n};\n} // namespace ng\n"
  },
  {
    "path": "include/engge/System/Services.hpp",
    "content": "#pragma once\n#include <Engine/AchievementManager.hpp>\n#include \"engge/Audio/SoundManager.hpp\"\n#include \"engge/Input/CommandManager.hpp\"\n#include \"engge/Engine/EngineSettings.hpp\"\n#include \"engge/Engine/EntityManager.hpp\"\n#include \"engge/Engine/Preferences.hpp\"\n#include \"engge/Engine/TextDatabase.hpp\"\n#include \"Locator.hpp\"\n#include \"Logger.hpp\"\n#include \"engge/Util/RandomNumberGenerator.hpp\"\n\nnamespace ng {\nclass Services final {\npublic:\n  static void init() {\n    ng::Locator<ng::Logger>::create();\n    ng::info(\"Init services\");\n    ng::Locator<ng::RandomNumberGenerator>::create();\n    ng::Locator<ng::CommandManager>::create();\n    ng::Locator<ng::AchievementManager>::create();\n    ng::Locator<ng::Preferences>::create();\n    ng::Locator<ng::EngineSettings>::create().loadPacks();\n    ng::Locator<ng::EntityManager>::create();\n    ng::Locator<ng::SoundManager>::create();\n    ng::Locator<ng::TextDatabase>::create();\n    ng::Locator<ng::ResourceManager>::create();\n  }\n};\n}"
  },
  {
    "path": "include/engge/UI/OptionsDialog.hpp",
    "content": "#pragma once\n#include <ngf/Graphics/Drawable.h>\n\nnamespace ng {\nclass OptionsDialog final : public ngf::Drawable {\npublic:\n  using Callback = std::function<void()>;\n\n  void draw(ngf::RenderTarget &target, ngf::RenderStates states) const final;\npublic:\n  OptionsDialog();\n  ~OptionsDialog() final;\n\n  void setCallback(Callback callback);\n  void setSaveEnabled(bool enabled);\n  void setEngine(Engine *pEngine);\n  void update(const ngf::TimeSpan &elapsed);\n\n  void showHelp();\n\nprivate:\n  struct Impl;\n  std::unique_ptr<Impl> m_pImpl;\n};\n}\n"
  },
  {
    "path": "include/engge/UI/QuitDialog.hpp",
    "content": "#pragma once\n\nnamespace ng {\nclass QuitDialog final : public ngf::Drawable {\npublic:\n  typedef std::function<void(bool)> Callback;\n\n  void draw(ngf::RenderTarget &target, ngf::RenderStates states) const final;\npublic:\n  QuitDialog();\n  ~QuitDialog() final;\n\n  void setCallback(Callback callback);\n  void setEngine(Engine *pEngine);\n  void update(const ngf::TimeSpan &elapsed);\n  void updateLanguage();\n\nprivate:\n  struct Impl;\n  std::unique_ptr<Impl> m_pImpl;\n};\n\n}\n"
  },
  {
    "path": "include/engge/UI/SaveLoadDialog.hpp",
    "content": "#pragma once\n#include <functional>\n#include <ngf/System/TimeSpan.h>\n#include <ngf/Graphics/Drawable.h>\n#include <ngf/Graphics/RenderStates.h>\n#include <ngf/Graphics/RenderTarget.h>\n\nnamespace ng {\n\nclass Engine;\n\nclass SaveLoadDialog final : public ngf::Drawable {\npublic:\n  using Callback =  std::function<void()>;\n  using SlotCallback = std::function<void(int slot)>;\n\n  void draw(ngf::RenderTarget &target, ngf::RenderStates states) const final;\npublic:\n  SaveLoadDialog();\n  ~SaveLoadDialog() final;\n\n  void setSaveMode(bool saveMode);\n  [[nodiscard]] bool getSaveMode() const;\n  void setCallback(Callback callback);\n  void setSlotCallback(SlotCallback callback);\n  void setEngine(Engine *pEngine);\n  void update(const ngf::TimeSpan &elapsed);\n  void updateLanguage();\n\nprivate:\n  struct Impl;\n  std::unique_ptr<Impl> m_pImpl;\n};\n}\n"
  },
  {
    "path": "include/engge/UI/StartScreenDialog.hpp",
    "content": "#pragma once\n#include \"SaveLoadDialog.hpp\"\n\nnamespace ng {\n\nclass StartScreenDialog final : public ngf::Drawable {\npublic:\n  using Callback = std::function<void()>;\n\n  void draw(ngf::RenderTarget &target, ngf::RenderStates states) const final;\npublic:\n  StartScreenDialog();\n  ~StartScreenDialog() final;\n\n  void setNewGameCallback(Callback callback);\n  void setSlotCallback(SaveLoadDialog::SlotCallback callback);\n  void setEngine(Engine *pEngine);\n  void update(const ngf::TimeSpan &elapsed);\n\nprivate:\n  struct Impl;\n  std::unique_ptr<Impl> m_pImpl;\n};\n}\n"
  },
  {
    "path": "include/engge/Util/BTEACrypto.hpp",
    "content": "#pragma once\n#include <cstdint>\n\nnamespace ng {\nclass BTEACrypto {\npublic:\n  static void encrypt(uint32_t *v, int n, const uint32_t *k);\n  static void decrypt(uint32_t *v, int n, const uint32_t *k);\n\nprivate:\n  static void btea(uint32_t *v, int n, const uint32_t *k);\n};\n}"
  },
  {
    "path": "include/engge/Util/RandomNumberGenerator.hpp",
    "content": "#pragma once\n\nnamespace ng {\nclass RandomNumberGenerator {\npublic:\n  RandomNumberGenerator();\n  void setSeed(long seed);\n  [[nodiscard]] long getSeed() const;\n\n  long generateLong(long min, long max);\n  float generateFloat(float min, float max);\n\nprivate:\n  long m_seed{0};\n};\n}"
  },
  {
    "path": "src/Audio/SoundDefinition.cpp",
    "content": "#include <utility>\n#include \"engge/Engine/EngineSettings.hpp\"\n#include \"engge/System/Locator.hpp\"\n#include \"engge/System/Logger.hpp\"\n#include \"engge/Engine/EntityManager.hpp\"\n#include \"engge/Audio/SoundDefinition.hpp\"\n\nnamespace ng {\nSound::~Sound() = default;\n\nSoundDefinition::SoundDefinition(std::string path)\n    : m_path(std::move(path)) {\n  m_id = Locator<EntityManager>::get().getSoundId();\n}\n\nSoundDefinition::~SoundDefinition() = default;\n\nvoid SoundDefinition::load() {\n  if (m_isLoaded)\n    return;\n  auto buffer = Locator<EngineSettings>::get().readBuffer(m_path);\n  m_buffer.loadFromMemory(buffer.data(), buffer.size());\n  m_isLoaded = true;\n}\n\n} // namespace ng\n"
  },
  {
    "path": "src/Audio/SoundId.cpp",
    "content": "#include \"engge/Engine/Camera.hpp\"\n#include \"engge/Entities/Entity.hpp\"\n#include \"engge/System/Locator.hpp\"\n#include \"engge/System/Logger.hpp\"\n#include \"engge/Engine/EntityManager.hpp\"\n#include \"engge/Audio/SoundId.hpp\"\n#include \"engge/Audio/SoundManager.hpp\"\n#include \"engge/Scripting/ScriptEngine.hpp\"\n\nnamespace ng {\nSoundId::SoundId(SoundManager &soundManager,\n                 std::shared_ptr<SoundDefinition> soundDefinition,\n                 std::shared_ptr<ngf::SoundHandle> sound,\n                 SoundCategory category,\n                 int entityId)\n    : m_soundManager(soundManager), m_soundDefinition(soundDefinition), m_sound(sound), m_category(category),\n      m_entityId(entityId) {\n  m_id = Locator<EntityManager>::get().getSoundId();\n}\n\nSoundId::~SoundId() {\n  //trace(\"delete SoundId ({}) {}\", (long)this, _pSoundDefinition->getPath());\n  m_sound.reset();\n}\n\nvoid SoundId::updateVolume() {\n  float entityVolume = 1.f;\n  Entity *pEntity = m_entityId ? EntityManager::getScriptObjectFromId<Entity>(m_entityId) : nullptr;\n\n  if (pEntity) {\n    auto pRoom = m_soundManager.getEngine()->getRoom();\n    auto at = m_soundManager.getEngine()->getCamera().getAt();\n    entityVolume = pRoom != pEntity->getRoom() ? 0 : pEntity->getVolume();\n\n    if (pRoom == pEntity->getRoom()) {\n      auto width = m_soundManager.getEngine()->getRoom()->getScreenSize().x;\n      auto diff = fabs(at.x - pEntity->getPosition().x);\n      entityVolume = (1.5f - (diff / width)) / 1.5f;\n      if (entityVolume < 0)\n        entityVolume = 0;\n      float pan = std::clamp((pEntity->getPosition().x - at.x) / (width / 2), -1.f, 1.f);\n      m_sound->get().setPanning(pan);\n    }\n  }\n  float categoryVolume = 0;\n  switch (m_category) {\n  case SoundCategory::Music:categoryVolume = m_soundManager.getMusicVolume();\n    break;\n  case SoundCategory::Sound:categoryVolume = m_soundManager.getSoundVolume();\n    break;\n  case SoundCategory::Talk:categoryVolume = m_soundManager.getTalkVolume();\n    break;\n  }\n  auto masterVolume = m_soundManager.getMasterVolume();\n  float volume = masterVolume * categoryVolume * entityVolume;\n  m_sound->get().setVolume(volume);\n}\n\nvoid SoundId::update(const ngf::TimeSpan &) {\n  updateVolume();\n}\n\nbool SoundId::isPlaying() const {\n  return m_sound->get().getStatus() == ngf::AudioChannel::Status::Playing;\n}\n\nvoid SoundId::stop(const ngf::TimeSpan &fadeOutTime) {\n  return m_sound->get().stop(fadeOutTime);\n}\n} // namespace ng\n"
  },
  {
    "path": "src/Audio/SoundManager.cpp",
    "content": "#include <memory>\n#include <ngf/Audio/AudioSystem.h>\n#include <engge/Engine/Engine.hpp>\n#include <engge/Engine/EngineSettings.hpp>\n#include <engge/Entities/Entity.hpp>\n#include <engge/EnggeApplication.hpp>\n#include <engge/System/Locator.hpp>\n#include <engge/System/Logger.hpp>\n#include <engge/Audio/SoundDefinition.hpp>\n#include <engge/Audio/SoundId.hpp>\n#include <engge/Audio/SoundManager.hpp>\n\nnamespace ng {\nSoundManager::SoundManager() = default;\n\nstd::shared_ptr<SoundId> SoundManager::getSound(size_t index) {\n  if (index < 1 || index > m_soundIds.size())\n    return nullptr;\n  return m_soundIds[index - 1];\n}\n\nstd::shared_ptr<SoundDefinition> SoundManager::defineSound(const std::string &name) {\n  if (!Locator<EngineSettings>::get().hasEntry(name))\n    return nullptr;\n\n  auto sound = std::make_shared<SoundDefinition>(name);\n  m_sounds.push_back(sound);\n  return sound;\n}\n\nstd::shared_ptr<SoundId> SoundManager::playSound(std::shared_ptr<SoundDefinition> soundDefinition,\n                                                 int loopTimes,\n                                                 const ngf::TimeSpan &fadeInTime,\n                                                 int id) {\n  return play(soundDefinition, SoundCategory::Sound, loopTimes, fadeInTime, id);\n}\n\nstd::shared_ptr<SoundId> SoundManager::playTalkSound(std::shared_ptr<SoundDefinition> soundDefinition,\n                                                     int loopTimes,\n                                                     const ngf::TimeSpan &fadeInTime,\n                                                     int id) {\n  return play(soundDefinition, SoundCategory::Talk, loopTimes, fadeInTime, id);\n}\n\nstd::shared_ptr<SoundId> SoundManager::playMusic(std::shared_ptr<SoundDefinition> soundDefinition,\n                                                 int loopTimes,\n                                                 const ngf::TimeSpan &fadeInTime) {\n  return play(soundDefinition, SoundCategory::Music, loopTimes, fadeInTime);\n}\n\nstd::shared_ptr<SoundId> SoundManager::play(std::shared_ptr<SoundDefinition> soundDefinition,\n                                            SoundCategory category,\n                                            int loopTimes,\n                                            const ngf::TimeSpan &fadeInTime,\n                                            int id) {\n  soundDefinition->load();\n  auto\n      sound = m_pEngine->getApplication()->getAudioSystem().playSound(soundDefinition->m_buffer, loopTimes, fadeInTime);\n  auto soundId = std::make_shared<SoundId>(*this, soundDefinition, sound, category, id);\n  auto index = sound->get().getChannel();\n  if (index == -1) {\n    error(\"cannot play sound no more channel available\");\n    return nullptr;\n  }\n  std::string sCategory;\n  switch (category) {\n  case SoundCategory::Music:sCategory = \"music\";\n    break;\n  case SoundCategory::Sound:sCategory = \"sound\";\n    break;\n  case SoundCategory::Talk:sCategory = \"talk\";\n    break;\n  }\n  trace(\"[{}] loop {} {} {}\", index, loopTimes, sCategory, soundDefinition->getPath());\n  m_soundIds[index] = soundId;\n  return soundId;\n}\n\nvoid SoundManager::stopAllSounds() {\n  trace(\"stopAllSounds\");\n  for (auto channel : m_pEngine->getApplication()->getAudioSystem()) {\n    channel.stop();\n  }\n  for (auto &soundId : m_soundIds) {\n    soundId.reset();\n  }\n}\n\nvoid SoundManager::stopSound(std::shared_ptr<SoundDefinition> soundDef) {\n  trace(\"stopSound (sound definition: {})\", soundDef->getPath());\n  for (size_t i = 0; i < getSize(); i++) {\n    auto sound = m_soundIds[i];\n    if (sound && soundDef.get()->getId() == sound->getId()) {\n      sound->getSoundHandle()->get().stop();\n      m_soundIds[i].reset();\n    }\n  }\n}\n\nvoid SoundManager::setVolume(const SoundDefinition *pSoundDef, float volume) {\n  volume = std::clamp(volume, 0.f, 1.f);\n  trace(\"setVolume (sound definition: {})\", pSoundDef->getPath());\n  for (size_t i = 1; i <= getSize(); i++) {\n    auto &&sound = getSound(i);\n    if (sound && pSoundDef->getId() == sound->getId()) {\n      sound->getSoundHandle()->get().setVolume(volume);\n    }\n  }\n}\n\nvoid SoundManager::update(const ngf::TimeSpan &elapsed) {\n  for (auto &&soundId : m_soundIds) {\n    if (soundId) {\n      soundId->update(elapsed);\n      if (soundId->getSoundHandle()->get().getStatus() == ngf::AudioChannel::Status::Stopped) {\n        soundId.reset();\n      }\n    }\n  }\n}\n\nvoid SoundManager::pauseAllSounds() {\n  for (auto soundId : m_soundIds) {\n    if (soundId) {\n      soundId->getSoundHandle()->get().pause();\n    }\n  }\n}\n\nvoid SoundManager::resumeAllSounds() {\n  for (auto &soundId : m_soundIds) {\n    if (soundId && soundId->getSoundHandle()->get().getStatus() == ngf::AudioChannel::Status::Paused) {\n      soundId->getSoundHandle()->get().play();\n    }\n  }\n}\n} // namespace ng\n"
  },
  {
    "path": "src/Audio/SoundTrigger.cpp",
    "content": "#include \"engge/Audio/SoundTrigger.hpp\"\n#include \"engge/Engine/Engine.hpp\"\n#include \"engge/Audio/SoundDefinition.hpp\"\n#include \"engge/Audio/SoundId.hpp\"\n#include \"engge/Audio/SoundManager.hpp\"\n\nnamespace ng {\nSoundTrigger::SoundTrigger(Engine &engine, const std::vector<std::shared_ptr<SoundDefinition>> &sounds, int id)\n    : m_engine(engine), m_id(id), m_distribution(0, sounds.size() - 1) {\n  m_name = \"SoundTrigger \";\n  m_soundsDefinitions.resize(sounds.size());\n  for (size_t i = 0; i < sounds.size(); i++) {\n    m_name.append(sounds[i]->getPath());\n    m_name.append(\",\");\n    m_soundsDefinitions[i] = sounds[i];\n  }\n  m_sounds.resize(sounds.size());\n  for (size_t i = 0; i < sounds.size(); i++) {\n    m_sounds[i] = 0;\n  }\n}\n\nSoundTrigger::~SoundTrigger() = default;\n\nvoid SoundTrigger::trigCore() {\n  int i = m_distribution(m_defaultRandomEngine);\n  auto pSound = m_engine.getSoundManager().playSound(m_soundsDefinitions[i], 1, ngf::TimeSpan::Zero, m_id);\n  if (!pSound)\n    return;\n  m_sounds[i] = pSound->getId();\n}\n\nstd::string SoundTrigger::getName() { return m_name; }\n} // namespace ng\n"
  },
  {
    "path": "src/CMakeLists.txt",
    "content": "include(\"../appInfo.cmake\")\n\ninclude_directories(../include/ ../extlibs/squirrel/include/ ../extlibs/spdlog/include/ ./)\nlink_directories(../extlibs/squirrel/squirrel/ ../extlibs/squirrel/sqstdlib/)\n\nset(SOURCES\n        Audio/SoundTrigger.cpp\n        Audio/SoundId.cpp\n        Audio/SoundDefinition.cpp\n        Audio/SoundManager.cpp\n        Dialog/Ast.cpp\n        Dialog/DialogManager.cpp\n        Dialog/ConditionVisitor.cpp\n        Dialog/ExpressionVisitor.cpp\n        Dialog/DialogPlayer.cpp\n        Dialog/EngineDialogScript.cpp\n        EnggeApplication.cpp\n        Engine/AchievementManager.cpp\n        Engine/ActorIcons.cpp\n        Engine/Callback.cpp\n        Engine/Camera.cpp\n        Engine/Cutscene.cpp\n        Engine/Engine.cpp\n        Engine/EngineImpl.cpp\n        Engine/EngineSettings.cpp\n        Engine/EntityManager.cpp\n        Engine/Hud.cpp\n        Engine/Inventory.cpp\n        Engine/Light.cpp\n        Engine/Preferences.cpp\n        Engine/Sentence.cpp\n        Engine/Shaders.cpp\n        Engine/TextDatabase.cpp\n        Engine/Thread.cpp\n        Engine/ThreadBase.cpp\n        Engine/TimeFunction.cpp\n        Engine/Trigger.cpp\n        Entities/Actor.cpp\n        Entities/AnimationLoader.cpp\n        Entities/BlinkState.cpp\n        Entities/Costume.cpp\n        Entities/LipAnimation.cpp\n        Entities/JiggleFunction.cpp\n        Entities/ShakeFunction.cpp\n        Entities/TalkingState.cpp\n        Entities/Entity.cpp\n        Entities/Object.cpp\n        Entities/TextObject.cpp\n        Entities/WalkingState.cpp\n        Graphics/AnimControl.cpp\n        Graphics/AnimDrawable.cpp\n        Graphics/GGFont.cpp\n        Graphics/ResourceManager.cpp\n        Graphics/SpriteSheet.cpp\n        Graphics/GraphDrawable.cpp\n        Graphics/LightingShader.cpp\n        Graphics/WalkboxDrawable.cpp\n        Graphics/PathDrawable.cpp\n        Graphics/Text.cpp\n        Input/CommandManager.cpp\n        Input/InputMappings.cpp\n        main.cpp\n        Parsers/Lip.cpp\n        Parsers/YackTokenReader.cpp\n        Parsers/YackParser.cpp\n        Parsers/GGPackBufferStream\n        Parsers/SavegameManager.cpp\n        Room/Room.cpp\n        Room/RoomLayer.cpp\n        Room/RoomScaling.cpp\n        Room/RoomTrigger.cpp\n        Room/RoomTriggerThread.cpp\n        Scripting/ActorWalk.cpp\n        Scripting/DefaultScriptExecute.cpp\n        Scripting/DefaultVerbExecute.cpp\n        Scripting/PostWalk.cpp\n        Scripting/ReachAnim.cpp\n        Scripting/SetDefaultVerb.cpp\n        Scripting/ScriptEngine.cpp\n        Scripting/VerbExecuteFunction.cpp\n        System/DebugTools/ActorTools.cpp\n        System/DebugTools/CameraTools.cpp\n        System/DebugTools/Console.cpp\n        System/DebugTools/ConsoleTools.cpp\n        System/DebugTools/DebugControls.cpp\n        System/DebugTools/DebugTools.cpp\n        System/DebugTools/GeneralTools.cpp\n        System/DebugTools/ObjectTools.cpp\n        System/DebugTools/PreferencesTools.cpp\n        System/DebugTools/RoomTools.cpp\n        System/DebugTools/SoundTools.cpp\n        System/DebugTools/TextureTools.cpp\n        System/DebugTools/ThreadTools.cpp\n        System/Logger.cpp\n        UI/Button.cpp\n        UI/Checkbox.cpp\n        UI/Control.cpp\n        UI/HelpDialog.cpp\n        UI/OptionsDialog.cpp\n        UI/QuitDialog.cpp\n        UI/SaveLoadDialog.cpp\n        UI/StartScreenDialog.cpp\n        UI/Slider.cpp\n        UI/SwitchButton.cpp\n        Util/BTEACrypto.cpp\n        Util/RandomNumberGenerator.cpp\n        Util/Util.cpp\n        )\n\nadd_executable(${PROJECT_NAME} ${SOURCES})\n\n# squirrel\ntarget_link_libraries(${PROJECT_NAME} squirrel_static sqstdlib_static)\n# clipper\ntarget_link_libraries(${PROJECT_NAME} clipper)\n# ngf\ntarget_link_libraries(${PROJECT_NAME} ngf)\n# std::filesystem\nif (CMAKE_CXX_COMPILER_ID STREQUAL GNU)\n    target_link_libraries(${PROJECT_NAME} stdc++fs)\nendif ()\n\n\n# Install exe\ninstall(TARGETS engge RUNTIME DESTINATION \"bin\")\n"
  },
  {
    "path": "src/Dialog/Ast.cpp",
    "content": "#include \"engge/Parsers/YackParser.hpp\"\n\nnamespace ng::Ast {\nvoid Statement::accept(AstVisitor &visitor) { visitor.visit(*this); }\nvoid Label::accept(AstVisitor &visitor) { visitor.visit(*this); }\nvoid Say::accept(AstVisitor &visitor) { visitor.visit(*this); }\nvoid Choice::accept(AstVisitor &visitor) { visitor.visit(*this); }\nvoid Code::accept(AstVisitor &visitor) { visitor.visit(*this); }\nvoid Goto::accept(AstVisitor &visitor) { visitor.visit(*this); }\nvoid CodeCondition::accept(AstVisitor &visitor) { visitor.visit(*this); }\nvoid OnceCondition::accept(AstVisitor &visitor) { visitor.visit(*this); }\nvoid ShowOnceCondition::accept(AstVisitor &visitor) { visitor.visit(*this); }\nvoid Shutup::accept(AstVisitor &visitor) { visitor.visit(*this); }\nvoid Override::accept(AstVisitor &visitor) { visitor.visit(*this); }\nvoid WaitFor::accept(AstVisitor &visitor) { visitor.visit(*this); }\nvoid Pause::accept(AstVisitor &visitor) { visitor.visit(*this); }\nvoid Parrot::accept(AstVisitor &visitor) { visitor.visit(*this); }\nvoid Dialog::accept(AstVisitor &visitor) { visitor.visit(*this); }\nvoid AllowObjects::accept(AstVisitor &visitor) { visitor.visit(*this); }\nvoid WaitWhile::accept(AstVisitor &visitor) { visitor.visit(*this); }\nvoid Limit::accept(AstVisitor &visitor) { visitor.visit(*this); }\nvoid OnceEverCondition::accept(AstVisitor &visitor) { visitor.visit(*this); }\nvoid TempOnceCondition::accept(AstVisitor &visitor) { visitor.visit(*this); }\n\nAstVisitor::~AstVisitor() = default;\nvoid AstVisitor::visit(const Statement &node) { defaultVisit(node); }\nvoid AstVisitor::visit(const Label &node) { defaultVisit(node); }\nvoid AstVisitor::visit(const Say &node) { defaultVisit(node); }\nvoid AstVisitor::visit(const Choice &node) { defaultVisit(node); }\nvoid AstVisitor::visit(const Code &node) { defaultVisit(node); }\nvoid AstVisitor::visit(const Goto &node) { defaultVisit(node); }\nvoid AstVisitor::visit(const CodeCondition &node) { defaultVisit(node); }\nvoid AstVisitor::visit(const OnceCondition &node) { defaultVisit(node); }\nvoid AstVisitor::visit(const ShowOnceCondition &node) { defaultVisit(node); }\nvoid AstVisitor::visit(const OnceEverCondition &node) { defaultVisit(node); }\nvoid AstVisitor::visit(const TempOnceCondition &node) { defaultVisit(node); }\nvoid AstVisitor::visit(const Shutup &node) { defaultVisit(node); }\nvoid AstVisitor::visit(const Pause &node) { defaultVisit(node); }\nvoid AstVisitor::visit(const WaitFor &node) { defaultVisit(node); }\nvoid AstVisitor::visit(const Parrot &node) { defaultVisit(node); }\nvoid AstVisitor::visit(const Dialog &node) { defaultVisit(node); }\nvoid AstVisitor::visit(const Override &node) { defaultVisit(node); }\nvoid AstVisitor::visit(const AllowObjects &node) { defaultVisit(node); }\nvoid AstVisitor::visit(const WaitWhile &node) { defaultVisit(node); }\nvoid AstVisitor::visit(const Limit &node) { defaultVisit(node); }\nvoid AstVisitor::defaultVisit(const Node &) {}\n\n} // namespace Ast\n\n"
  },
  {
    "path": "src/Dialog/AstDump.hpp",
    "content": "#pragma once\n#include \"engge/Parsers/YackParser.hpp\"\n\nnamespace ng {\nclass AstDump : public Ast::AstVisitor {\npublic:\n  static void dump(const std::string &filename) {\n    YackTokenReader reader;\n    reader.load(filename);\n    std::cout << \"# dump tokens: \" << std::endl;\n    for (auto it = reader.begin(); it != reader.end(); it++) {\n      auto token = *it;\n      auto text = reader.readText(token);\n      std::cout << token << \" \" << text << std::endl;\n    }\n    std::cout << \"# dump AST: \" << std::endl;\n    YackParser parser(reader);\n    auto pCu = parser.parse();\n    _AstDump dump;\n    for (const auto &label : pCu->labels) {\n      label->accept(dump);\n    }\n  }\n\nprivate:\n  void visit(const Ast::Statement &node) override {\n    node.expression->accept(*this);\n    for (const auto &cond : node.conditions) {\n      cond->accept(*this);\n    }\n  }\n  void visit(const Ast::Pause &node) override {\n    std::cout << \"pause: \" << node.time << std::endl;\n  }\n  void visit(const Ast::WaitFor &node) override {\n    std::cout << \"waitfor \" << node.actor << std::endl;\n  }\n  void visit(const Ast::Parrot &node) override {\n    std::cout << \"parrot \" << node.active << std::endl;\n  }\n  void visit(const Ast::Dialog &node) override {\n    std::cout << \"dialog \" << node.actor << std::endl;\n  }\n  void visit(const Ast::Shutup &) override {\n    std::cout << \"shutup \" << std::endl;\n  }\n  void visit(const Ast::Override &node) override {\n    std::cout << \"override \" << node.node << std::endl;\n  }\n  void visit(const Ast::Label &node) override {\n    std::cout << \"label \" << node.name << \":\" << std::endl;\n    for (const auto &statement : node.statements) {\n      statement->accept(*this);\n    }\n  }\n  void visit(const Ast::Say &node) override {\n    std::cout << \"say \" << node.actor << \": \" << node.text << std::endl;\n  }\n  void visit(const Ast::Choice &node) override {\n    std::cout << \"choice \" << node.number << \" \" << node.text << std::endl;\n  }\n  void visit(const Ast::Code &node) override {\n    std::cout << \"code \" << node.code << std::endl;\n  }\n  void visit(const Ast::Goto &node) override {\n    std::cout << \"goto \" << node.name << std::endl;\n  }\n  void visit(const Ast::OnceCondition & node) override {\n    std::cout << \"condition: once (\" << node.getLine() << \")\" << std::endl;\n  }\n  void visit(const Ast::ShowOnceCondition &node) override {\n    std::cout << \"condition: showonce (\" << node.getLine() << \")\" << std::endl;\n  }\n  void visit(const Ast::CodeCondition &node) override {\n    std::cout << \"condition: \" << node.code << \"(\" << node.getLine() << \")\" << std::endl;\n  }\n  void visit(const Ast::TempOnceCondition &node) override {\n    std::cout << \"condition: temponce (\" << node.getLine() << \")\" << std::endl;\n  }\n};\n} // namespace ng\n"
  },
  {
    "path": "src/Dialog/ConditionVisitor.cpp",
    "content": "#include \"engge/Parsers/YackParser.hpp\"\n#include \"engge/Dialog/ConditionVisitor.hpp\"\n#include \"engge/Dialog/DialogConditionAbstract.hpp\"\n\nnamespace ng {\nConditionVisitor::ConditionVisitor(const DialogConditionAbstract &context) : m_context(context) {\n}\n\nvoid ConditionVisitor::visit(const Ast::CodeCondition &node) {\n  m_isAccepted = m_context.executeCondition(node.code);\n}\n\nvoid ConditionVisitor::visit(const Ast::OnceCondition &node) {\n  m_isAccepted = m_context.isOnce(node.getLine());\n}\n\nvoid ConditionVisitor::visit(const Ast::ShowOnceCondition &node) {\n  m_isAccepted = m_context.isShowOnce(node.getLine());\n}\n\nvoid ConditionVisitor::visit(const Ast::OnceEverCondition &node) {\n  m_isAccepted = m_context.isOnceEver(node.getLine());\n}\n\nvoid ConditionVisitor::visit(const Ast::TempOnceCondition &node) {\n  m_isAccepted = m_context.isTempOnce(node.getLine());\n}\n}"
  },
  {
    "path": "src/Dialog/DialogManager.cpp",
    "content": "#include <regex>\n#include <ngf/System/Mouse.h>\n#include <ngf/Graphics/Text.h>\n#include <engge/Dialog/DialogManager.hpp>\n#include <engge/Engine/Engine.hpp>\n#include <engge/Engine/Preferences.hpp>\n#include <engge/Scripting/ScriptEngine.hpp>\n#include <engge/Graphics/Screen.hpp>\n#include <engge/Graphics/Text.hpp>\n\nnamespace ng {\nnamespace {\nconstexpr float DialogTop = 504.f;\nconst wchar_t *const Bullet = L\"\\u25CF \";\nconstexpr float SlidingSpeed = 25.f;\n\nngf::frect getGlobalBounds(const ngf::Text &text) {\n  return ngf::transform(text.getTransform().getTransform(), text.getLocalBounds());\n}\n}\n\nvoid DialogManager::setEngine(Engine *pEngine) {\n  m_pEngine = pEngine;\n  m_pEngineDialogScript = std::make_unique<EngineDialogScript>(*pEngine);\n  m_pPlayer = std::make_unique<DialogPlayer>(*m_pEngineDialogScript);\n}\n\nvoid DialogManager::start(const std::string &actor, const std::string &name, const std::string &node) {\n  m_pPlayer->start(actor, name, node);\n\n  auto oldState = m_state;\n  m_state = m_pPlayer->getState();\n\n  if (oldState != m_state) {\n    if (m_state == DialogManagerState::WaitingForChoice) {\n      updateDialogSlots();\n    } else if (m_state == DialogManagerState::None) {\n      onDialogEnded();\n    }\n  }\n}\n\nvoid DialogManager::draw(ngf::RenderTarget &target, ngf::RenderStates) const {\n  if (m_state != DialogManagerState::WaitingForChoice)\n    return;\n\n  const auto view = target.getView();\n  target.setView(ngf::View(ngf::frect::fromPositionSize({0, 0}, {Screen::Width, Screen::Height})));\n\n  auto retroFonts = m_pEngine->getPreferences().getUserPreference(PreferenceNames::RetroFonts,\n                                                                  PreferenceDefaultValues::RetroFonts);\n  const GGFont &font = m_pEngine->getResourceManager().getFont(retroFonts ? \"FontRetroSheet\" : \"FontModernSheet\");\n\n  auto y = DialogTop;\n\n  auto actorName = m_pPlayer->getActor();\n  auto dialogHighlight = m_pEngine->getVerbUiColors(actorName)->dialogHighlight;\n  auto dialogNormal = m_pEngine->getVerbUiColors(actorName)->dialogNormal;\n\n  ng::Text text;\n  text.setFont(font);\n  auto hoverDone = false;\n  for (const auto &slot : m_slots) {\n    if (!slot.pChoice)\n      continue;\n\n    std::wstring s;\n    s = Bullet;\n    s += slot.text;\n    text.setWideString(s);\n    text.getTransform().setPosition({slot.pos.x, y + slot.pos.y});\n    auto bounds = getGlobalBounds(text);\n    auto hover = bounds.contains(m_mousePos);\n    text.setColor(hover && !hoverDone ? dialogHighlight : dialogNormal);\n    hoverDone |= hover;\n    text.draw(target, {});\n\n    y += (2.f * getGlobalBounds(text).getHeight() / 3.f);\n  }\n\n  target.setView(view);\n}\n\nvoid DialogManager::update(const ngf::TimeSpan &elapsed) {\n  m_pPlayer->update();\n  auto oldState = m_state;\n  m_state = m_pPlayer->getState();\n\n  if (oldState != m_state && m_state == DialogManagerState::WaitingForChoice) {\n    updateDialogSlots();\n  }\n\n  updateChoices(elapsed);\n}\n\nvoid DialogManager::updateDialogSlots() {\n  int i = 0;\n  for (const auto &pStatement : m_pPlayer->getChoices()) {\n    if (pStatement) {\n      auto pChoice = dynamic_cast<Ast::Choice *>(pStatement->expression.get());\n      auto text = pChoice->text;\n      if (!text.empty() && text[0] == '$') {\n        text = m_pEngine->executeDollar(text.substr(1));\n      }\n      std::wstring dialogText = ng::Engine::getText(text);\n      std::wregex re(L\"(\\\\{([^\\\\}]*)\\\\})\");\n      std::wsmatch matches;\n      if (std::regex_search(dialogText, matches, re)) {\n        dialogText = matches.suffix();\n      }\n      m_slots[i].text = dialogText;\n      m_slots[i].pos = {0, 0};\n    }\n    m_slots[i].pChoice = pStatement;\n    i++;\n  }\n}\n\nvoid DialogManager::updateChoices(const ngf::TimeSpan &elapsed) {\n  if (m_state != DialogManagerState::WaitingForChoice)\n    return;\n\n  auto retroFonts = m_pEngine->getPreferences().getUserPreference(PreferenceNames::RetroFonts,\n                                                                  PreferenceDefaultValues::RetroFonts);\n  const GGFont &font = m_pEngine->getResourceManager().getFont(retroFonts ? \"FontRetroSheet\" : \"FontModernSheet\");\n\n  auto y = DialogTop;\n  int dialog = 0;\n  for (const auto &dlg : m_slots) {\n    if (dlg.pChoice == nullptr)\n      continue;\n\n    // HACK: bad, bad, this code is the same as in the draw function\n    std::wstring s;\n    s = Bullet;\n    s += dlg.text;\n    ng::Text text;\n    text.setFont(font);\n    text.getTransform().setPosition({dlg.pos.x, dlg.pos.y + y});\n    text.setWideString(s);\n    auto bounds = getGlobalBounds(text);\n    if (bounds.getWidth() > Screen::Width) {\n      if (bounds.contains(m_mousePos)) {\n        if ((bounds.getWidth() + dlg.pos.x) > Screen::Width) {\n          dlg.pos.x -= SlidingSpeed * elapsed.getTotalSeconds();\n          if ((bounds.getWidth() + dlg.pos.x) < Screen::Width) {\n            dlg.pos.x = Screen::Width - bounds.getWidth();\n          }\n        }\n      } else {\n        if (dlg.pos.x < 0) {\n          dlg.pos.x += SlidingSpeed * elapsed.getTotalSeconds();\n          if (dlg.pos.x > 0) {\n            dlg.pos.x = 0;\n          }\n        }\n      }\n    }\n    y += bounds.getHeight() / 2.f;\n    dialog++;\n  }\n\n  if (!ngf::Mouse::isButtonPressed(ngf::Mouse::Button::Left))\n    return;\n\n  y = DialogTop;\n  dialog = 0;\n\n  for (const auto &slot : m_slots) {\n    if (!slot.pChoice)\n      continue;\n\n    // HACK: bad, bad, this code is the same as in the draw function\n    std::wstring s;\n    s = Bullet;\n    s += slot.text;\n    ng::Text text;\n    text.setFont(font);\n    text.getTransform().setPosition({slot.pos.x, slot.pos.y + y});\n    text.setWideString(s);\n    if (getGlobalBounds(text).contains(m_mousePos)) {\n      choose(dialog + 1);\n      break;\n    }\n    y += getGlobalBounds(text).getHeight() / 2.f;\n    dialog++;\n  }\n}\n\nvoid DialogManager::choose(int choice) {\n  if ((choice < 1) || (choice > static_cast<int>(m_slots.size())))\n    return;\n\n  ScriptEngine::rawCall(\"onChoiceClick\");\n  m_pPlayer->choose(choice);\n}\n\nvoid DialogManager::setMousePosition(glm::vec2 pos) {\n  m_mousePos = pos;\n}\n\nvoid DialogManager::onDialogEnded() {\n  ScriptEngine::call(\"onDialogEnded\");\n}\n\n} // namespace ng\n"
  },
  {
    "path": "src/Dialog/DialogPlayer.cpp",
    "content": "#include <optional>\n#include \"engge/Dialog/ConditionVisitor.hpp\"\n#include \"engge/System/Logger.hpp\"\n#include \"engge/Dialog/ExpressionVisitor.hpp\"\n#include \"engge/Dialog/DialogPlayer.hpp\"\n#include \"engge/Dialog/DialogScriptAbstract.hpp\"\n\nnamespace ng {\n\nenum class DialogSelectMode {\n  Show,\n  Choose\n};\n\nclass ConditionStateVisitor : public Ast::AstVisitor {\npublic:\n  explicit ConditionStateVisitor(DialogPlayer& dialogPlayer, DialogSelectMode selectMode);\n  ~ConditionStateVisitor() override = default;\n  [[nodiscard]] std::optional<DialogConditionState> getState() const { return m_state; }\n\nprivate:\n  void visit(const Ast::OnceCondition &node) override;\n  void visit(const Ast::ShowOnceCondition &node) override;\n  void visit(const Ast::OnceEverCondition &node) override;\n  void visit(const Ast::TempOnceCondition &node) override;\n\n  void setState(int32_t line, DialogConditionMode mode);\n\nprivate:\n  DialogPlayer& m_dialogPlayer;\n  DialogSelectMode m_selectMode;\n  std::optional<DialogConditionState> m_state;\n};\n\nConditionStateVisitor::ConditionStateVisitor(DialogPlayer &dialogPlayer, DialogSelectMode selectMode)\n    : m_dialogPlayer(dialogPlayer), m_selectMode(selectMode) {\n}\n\nvoid ConditionStateVisitor::visit(const Ast::OnceCondition &condition) {\n  if (m_selectMode == DialogSelectMode::Choose) {\n    setState(condition.getLine(), DialogConditionMode::Once);\n  }\n}\n\nvoid ConditionStateVisitor::visit(const Ast::ShowOnceCondition &condition) {\n  if (m_selectMode == DialogSelectMode::Show) {\n    setState(condition.getLine(), DialogConditionMode::ShowOnce);\n  }\n}\n\nvoid ConditionStateVisitor::visit(const Ast::OnceEverCondition &condition) {\n  if (m_selectMode == DialogSelectMode::Choose) {\n    setState(condition.getLine(), DialogConditionMode::OnceEver);\n  }\n}\n\nvoid ConditionStateVisitor::visit(const Ast::TempOnceCondition &condition) {\n  if (m_selectMode == DialogSelectMode::Show) {\n    setState(condition.getLine(), DialogConditionMode::TempOnce);\n  }\n}\n\nvoid ConditionStateVisitor::setState(int32_t line, DialogConditionMode mode) {\n  DialogConditionState state;\n  state.mode = mode;\n  state.line = line;\n  state.dialog = m_dialogPlayer.getDialogName();\n  state.actorKey = m_dialogPlayer.getActor();\n  m_state = state;\n}\n\nDialogPlayer::DialogPlayer(DialogScriptAbstract &script) : _script(script) {}\nDialogPlayer::~DialogPlayer() = default;\n\nvoid DialogPlayer::start(const std::string &actor, const std::string &name, const std::string &node) {\n  resetState();\n  m_actor = actor;\n  m_dialogName = name;\n  std::string path;\n  path.append(name).append(\".byack\");\n\n  YackTokenReader reader;\n  reader.load(path);\n  YackParser parser(reader);\n  m_pCompilationUnit = parser.parse();\n  selectLabel(node);\n}\n\nvoid DialogPlayer::choose(int choiceId) {\n  if (m_state != DialogPlayerState::WaitingForChoice)\n    return;\n  int i = 1;\n  for (const auto &choice : m_choices) {\n    if (!choice)\n      continue;\n    if (i++ == choiceId) {\n      auto pChoice = dynamic_cast<ng::Ast::Choice *>(choice->expression.get());\n\n      for(const auto& cond : choice->conditions) {\n        ConditionStateVisitor visitor(*this, DialogSelectMode::Choose);\n        cond->accept(visitor);\n        auto state = visitor.getState();\n        if (state.has_value()) {\n          m_states.push_back(state.value());\n        }\n      }\n\n      if (m_parrot) {\n        m_state = DialogPlayerState::WaitingForSayingChoice;\n        m_pWaitAction = say(m_actor, pChoice->text);\n        m_nextLabel = pChoice->gotoExp->name;\n        return;\n      }\n      selectLabel(pChoice->gotoExp->name);\n      return;\n    }\n  }\n}\n\nvoid DialogPlayer::update() {\n  switch (m_state) {\n  case DialogPlayerState::None:break;\n  case DialogPlayerState::Start: running(); break;\n  case DialogPlayerState::Running: running(); break;\n  case DialogPlayerState::WaitingForChoice:break;\n  case DialogPlayerState::WaitingForSayingChoice: {\n    if (!m_pWaitAction || m_pWaitAction()) {\n      m_pWaitAction = nullptr;\n      selectLabel(m_nextLabel);\n    }\n    break;\n  }\n  case DialogPlayerState::WaitingEndAnimation:\n    if (!m_pWaitAction || m_pWaitAction()) {\n      m_pWaitAction = nullptr;\n      m_currentStatement++;\n      m_state = DialogPlayerState::Running;\n    }\n    break;\n  }\n}\n\nDialogManagerState DialogPlayer::getState() const {\n  switch (m_state) {\n  case DialogPlayerState::None:return DialogManagerState::None;\n  case DialogPlayerState::WaitingForChoice: return DialogManagerState::WaitingForChoice;\n  case DialogPlayerState::Running: return DialogManagerState::Active;\n  case DialogPlayerState::WaitingEndAnimation:return DialogManagerState::Active;\n  case DialogPlayerState::WaitingForSayingChoice:return DialogManagerState::Active;\n  case DialogPlayerState::Start:return DialogManagerState::Active;\n  }\n}\n\nvoid DialogPlayer::running() {\n  if (!m_pLabel) {\n    m_state = DialogPlayerState::None;\n    return;\n  }\n  auto count = static_cast<int>(m_pLabel->statements.size());\n  if (m_currentStatement == count) {\n    gotoNextLabel();\n    return;\n  }\n  m_state = DialogPlayerState::Running;\n  while (m_currentStatement < count && m_state == DialogPlayerState::Running) {\n    auto pCurrentStatement = m_pLabel->statements.at(m_currentStatement).get();\n    if (!acceptConditions(pCurrentStatement)) {\n      m_currentStatement++;\n      continue;\n    }\n    auto pChoice = dynamic_cast<Ast::Choice *>(pCurrentStatement->expression.get());\n    if (pChoice) {\n      addChoice(pCurrentStatement, pChoice);\n      m_currentStatement++;\n      continue;\n    }\n    if (choicesReady()) {\n      m_state = DialogPlayerState::WaitingForChoice;\n      return;\n    }\n    run(pCurrentStatement);\n    count = m_pLabel ? static_cast<int>(m_pLabel->statements.size()) : 0;\n    if(m_state != DialogPlayerState::WaitingEndAnimation) {\n      m_currentStatement++;\n    }\n  }\n  if (choicesReady()) {\n    m_state = DialogPlayerState::WaitingForChoice;\n    return;\n  }\n  if(m_state == DialogPlayerState::Running) {\n    gotoNextLabel();\n  }\n}\n\nvoid DialogPlayer::resetState() {\n  m_parrot = true;\n  m_limit = 6;\n  m_overrideLabel.clear();\n  m_states.erase(std::remove_if(m_states.begin(), m_states.end(), [](const auto &state) {\n    return state.mode == DialogConditionMode::TempOnce;\n  }), m_states.end());\n}\n\nvoid DialogPlayer::selectLabel(const std::string &name) {\n  trace(\"select label {}\", name);\n  auto it = std::find_if(m_pCompilationUnit->labels.rbegin(),\n                         m_pCompilationUnit->labels.rend(),\n                         [&name](const std::unique_ptr<Ast::Label> &label) {\n                           return label->name == name;\n                         });\n  m_pLabel = it != m_pCompilationUnit->labels.rend() ? it->get() : nullptr;\n  m_currentStatement = 0;\n  clearChoices();\n  if (m_pLabel) {\n    m_state = DialogPlayerState::Start;\n    update();\n    return;\n  }\n  m_state = DialogPlayerState::None;\n}\n\nvoid DialogPlayer::endDialog() {\n  m_state = DialogPlayerState::None;\n  m_pLabel = nullptr;\n}\n\nbool DialogPlayer::gotoNextLabel() {\n  if (!m_pCompilationUnit) {\n    endDialog();\n    return false;\n  }\n  if (!m_pLabel) {\n    endDialog();\n    return false;\n  }\n  auto it =\n      std::find_if(m_pCompilationUnit->labels.cbegin(), m_pCompilationUnit->labels.cend(), [this](const auto &pLabel) {\n        return pLabel.get() == m_pLabel;\n      });\n  if (it == m_pCompilationUnit->labels.cend()) {\n    endDialog();\n    return false;\n  }\n  it++;\n  if (it == m_pCompilationUnit->labels.cend()) {\n    endDialog();\n    return false;\n  }\n  selectLabel((*it)->name);\n  return true;\n}\n\nvoid DialogPlayer::run(Ast::Statement *pStatement) {\n  if (!acceptConditions(pStatement))\n    return;\n  ExpressionVisitor visitor(*this);\n  pStatement->expression->accept(visitor);\n  m_pWaitAction = visitor.getWaitAction();\n  if (m_pWaitAction) {\n    m_state = DialogPlayerState::WaitingEndAnimation;\n  }\n}\n\nvoid DialogPlayer::addChoice(const Ast::Statement *pStatement, const Ast::Choice *pChoice) {\n  if (m_choices[pChoice->number - 1])\n    return;\n  int count = 0;\n  for (auto &_choice : m_choices) {\n    if(_choice) count++;\n  }\n  if(count >= m_limit) return;\n  trace(\"Add choice {}\", pChoice->text);\n  m_choices[pChoice->number - 1] = pStatement;\n}\n\nvoid DialogPlayer::clearChoices() {\n  for (auto &choice : m_choices) {\n    choice = nullptr;\n  }\n}\n\nbool DialogPlayer::choicesReady() const {\n  return std::any_of(m_choices.cbegin(), m_choices.cend(), [](const auto &pStatement) {\n    return pStatement != nullptr;\n  });\n}\n\nbool DialogPlayer::acceptConditions(const Ast::Statement *pStatement) {\n  ConditionVisitor visitor(*this);\n  for (const auto &cond : pStatement->conditions) {\n    cond->accept(visitor);\n    if (!visitor.isAccepted())\n      return false;\n  }\n\n  for (const auto &cond : pStatement->conditions) {\n    ConditionStateVisitor stateVisitor(*this, DialogSelectMode::Show);\n    cond->accept(stateVisitor);\n    auto state = stateVisitor.getState();\n    if (state.has_value()) {\n      m_states.push_back(state.value());\n    }\n  }\n\n  return true;\n}\n\nvoid DialogPlayer::allowObjects(bool allow) { m_allowObjects = allow; }\nvoid DialogPlayer::dialog(const std::string &actor) { m_actor = actor; }\nvoid DialogPlayer::execute(const std::string &code) { _script.execute(code); }\nvoid DialogPlayer::gotoLabel(const std::string &label) { selectLabel(label); }\nvoid DialogPlayer::limit(int max) { m_limit = max; }\nvoid DialogPlayer::override(const std::string &label) { m_overrideLabel = label; }\nvoid DialogPlayer::parrot(bool enabled) { m_parrot = enabled; }\nstd::function<bool()> DialogPlayer::pause(ngf::TimeSpan seconds) { return _script.pause(seconds); }\nstd::function<bool()> DialogPlayer::say(const std::string &actor, const std::string &text) {\n  return _script.say(actor, text);\n}\nvoid DialogPlayer::shutup() { return _script.shutup(); }\nstd::function<bool()> DialogPlayer::waitFor(const std::string &actor) { return _script.waitFor(actor); }\nstd::function<bool()> DialogPlayer::waitWhile(const std::string &condition) { return _script.waitWhile(condition); }\n\nbool DialogPlayer::isOnce(int32_t line) const {\n  auto it =\n      std::find_if(m_states.cbegin(), m_states.cend(),\n                   [this, line](const auto &state) {\n                     return state.mode == DialogConditionMode::Once &&\n                         state.actorKey == m_actor &&\n                         state.dialog == m_dialogName &&\n                         state.line == line;\n                   });\n  return it == m_states.cend();\n}\n\nbool DialogPlayer::isShowOnce(int32_t line) const {\n  auto it =\n      std::find_if(m_states.cbegin(), m_states.cend(),\n                   [this, line](const auto &state) {\n                     return state.mode == DialogConditionMode::ShowOnce &&\n                         state.actorKey == m_actor &&\n                         state.dialog == m_dialogName &&\n                         state.line == line;\n                   });\n  return it == m_states.cend();\n}\n\nbool DialogPlayer::isOnceEver(int32_t line) const {\n  auto it =\n      std::find_if(m_states.cbegin(), m_states.cend(),\n                   [this, line](const auto &state) {\n                     return state.mode == DialogConditionMode::OnceEver &&\n                         state.dialog == m_dialogName &&\n                         state.line == line;\n                   });\n  return it == m_states.cend();\n}\n\nbool DialogPlayer::isTempOnce(int32_t line) const {\n  auto it =\n      std::find_if(m_states.cbegin(), m_states.cend(),\n                   [this, line](const auto &state) {\n                     return state.mode == DialogConditionMode::TempOnce &&\n                         state.actorKey == m_actor &&\n                         state.dialog == m_dialogName &&\n                         state.line == line;\n                   });\n  return it == m_states.cend();\n}\n\nbool DialogPlayer::executeCondition(const std::string &condition) const { return _script.executeCondition(condition); }\n}"
  },
  {
    "path": "src/Dialog/EngineDialogScript.cpp",
    "content": "#include <sstream>\n#include <engge/System/Logger.hpp>\n#include <engge/Entities/Actor.hpp>\n#include <engge/Dialog/EngineDialogScript.hpp>\n#include <engge/Engine/Engine.hpp>\n#include <engge/Scripting/ScriptEngine.hpp>\n\nnamespace ng {\n\nEngineDialogScript::EngineDialogScript(Engine &engine) : m_engine(engine) {}\n\nstd::function<bool()> EngineDialogScript::pause(ngf::TimeSpan time) {\n  //trace(\"pause {}\", time.asSeconds());\n  auto startTime = m_engine.getTime();\n  return [*this, startTime, time]() -> bool { return (m_engine.getTime() - startTime) >= time; };\n}\n\nstd::function<bool()> EngineDialogScript::say(const std::string &actor, const std::string &text) {\n  //trace(\"{}: {}\", actor, text);\n  auto* pEntity = m_engine.getEntity(actor);\n\n  // is it an animation to play ?\n  if (!text.empty() && text[0] == '^') {\n    auto pActor = dynamic_cast<Actor*>(pEntity);\n    if(pActor) {\n      auto anim = text.substr(2, text.length() - 3);\n      std::stringstream s;\n      s << \"actorPlayAnimation(\" << pActor->getKey() << \", \\\"\" << anim << \"\\\", NO)\";\n      m_engine.execute(s.str());\n      return []() { return true; };\n    }\n  }\n\n  // is it a script variable ?\n  if (!text.empty() && text[0] == '$') {\n    pEntity->say(m_engine.executeDollar(text.substr(1)));\n  } else {\n    pEntity->say(text);\n  }\n  return [pEntity]() -> bool { return !pEntity->isTalking(); };\n}\n\nvoid EngineDialogScript::shutup() {\n  //trace(\"shutup\");\n  m_engine.stopTalking();\n}\n\nstd::function<bool()> EngineDialogScript::waitFor(const std::string &actor) {\n  trace(\"TODO: waitFor {}\", actor);\n  return []() {\n    return true;\n  };\n}\nstd::function<bool()> EngineDialogScript::waitWhile(const std::string &condition) {\n  //trace(\"waitWhile {}\", condition);\n  return [*this, condition]() -> bool { return !m_engine.executeCondition(condition); };\n}\nvoid EngineDialogScript::execute(const std::string &code) {\n  //trace(\"execute {}\", code);\n  m_engine.execute(code);\n}\nbool EngineDialogScript::executeCondition(const std::string &condition) const {\n  std::string code = condition;\n  const auto &actors = m_engine.getActors();\n  // check if the code corresponds to an actor name\n  auto it = std::find_if(actors.cbegin(), actors.cend(), [&condition](const auto &pActor) {\n    return pActor->getKey() == condition;\n  });\n  if (it != actors.cend()) {\n    // yes, so we check if the current actor is the given actor name\n    auto pCurrentActor = m_engine.getCurrentActor();\n    return pCurrentActor && pCurrentActor->getKey() == (*it)->getKey();\n  }\n\n  auto result = m_engine.executeCondition(code);\n  //trace(\"executeCondition {} -> {}\", code, result ? \"yes\" : \"no\");\n  return result;\n}\n}"
  },
  {
    "path": "src/Dialog/ExpressionVisitor.cpp",
    "content": "#include \"engge/Dialog/DialogContextAbstract.hpp\"\n#include \"engge/Dialog/ExpressionVisitor.hpp\"\n\nnamespace ng {\nExpressionVisitor::ExpressionVisitor(DialogContextAbstract &ctx) : m_context(ctx) {\n}\nExpressionVisitor::~ExpressionVisitor() = default;\n\nvoid ExpressionVisitor::visit(const Ast::Say &node) {\n  auto func = m_context.say(node.actor, node.text);\n  m_pWaitAction = [func]() { return func(); };\n}\nvoid ExpressionVisitor::visit(const Ast::Code &node) {\n  m_context.execute(node.code);\n}\nvoid ExpressionVisitor::visit(const Ast::Goto &node) {\n  m_context.gotoLabel(node.name);\n}\nvoid ExpressionVisitor::visit(const Ast::Shutup &) {\n  m_context.shutup();\n}\nvoid ExpressionVisitor::visit(const Ast::Pause &node) {\n  m_pWaitAction = m_context.pause(ngf::TimeSpan::seconds(node.time));\n}\nvoid ExpressionVisitor::visit(const Ast::WaitFor &node) {\n  m_pWaitAction = m_context.waitFor(node.actor);\n}\nvoid ExpressionVisitor::visit(const Ast::Parrot &node) {\n  m_context.parrot(node.active);\n}\nvoid ExpressionVisitor::visit(const Ast::Dialog &node) {\n  m_context.dialog(node.actor);\n}\nvoid ExpressionVisitor::visit(const Ast::Override &node) {\n  m_context.override(node.node);\n}\nvoid ExpressionVisitor::visit(const Ast::AllowObjects &node) {\n  m_context.allowObjects(node.allow);\n}\nvoid ExpressionVisitor::visit(const Ast::WaitWhile &node) {\n  m_pWaitAction = m_context.waitWhile(node.condition);\n}\nvoid ExpressionVisitor::visit(const Ast::Limit &node) {\n  m_context.limit(node.max);\n}\n}"
  },
  {
    "path": "src/EnggeApplication.cpp",
    "content": "#include \"engge/EnggeApplication.hpp\"\n#include \"engge/Input/InputMappings.hpp\"\n#include \"Engine/DebugFeatures.hpp\"\n#include <ngf/Graphics/Colors.h>\n#include \"engge/Engine/EngineCommands.hpp\"\n\nnamespace {\nng::InputConstants toKey(ngf::Scancode key) {\n  if (key >= ngf::Scancode::A && key <= ngf::Scancode::Z) {\n    return static_cast<ng::InputConstants>(static_cast<int>(ng::InputConstants::KEY_A)\n        + (static_cast<int>(key) - static_cast<int>(ngf::Scancode::A)));\n  }\n  if (key >= ngf::Scancode::Keypad1 && key <= ngf::Scancode::Keypad9) {\n    return static_cast<ng::InputConstants>(static_cast<int>(ng::InputConstants::KEY_1)\n        + (static_cast<int>(key) - static_cast<int>(ngf::Scancode::Keypad1)));\n  }\n  if (key == ngf::Scancode::Keypad0) {\n    return ng::InputConstants::KEY_0;\n  }\n  if (key >= ngf::Scancode::D1 && key <= ngf::Scancode::D9) {\n    return static_cast<ng::InputConstants>(static_cast<int>(ng::InputConstants::KEY_PAD1)\n        + (static_cast<int>(key) - static_cast<int>(ngf::Scancode::D1)));\n  }\n  if (key >= ngf::Scancode::F1 && key <= ngf::Scancode::F12) {\n    return static_cast<ng::InputConstants>(static_cast<int>(ng::InputConstants::KEY_F1)\n        + (static_cast<int>(key) - static_cast<int>(ngf::Scancode::F1)));\n  }\n  switch (key) {\n  case ngf::Scancode::Space:return ng::InputConstants::KEY_SPACE;\n  case ngf::Scancode::Escape:return ng::InputConstants::KEY_ESCAPE;\n  case ngf::Scancode::Left:return ng::InputConstants::KEY_LEFT;\n  case ngf::Scancode::Right:return ng::InputConstants::KEY_RIGHT;\n  case ngf::Scancode::Up:return ng::InputConstants::KEY_UP;\n  case ngf::Scancode::Down:return ng::InputConstants::KEY_DOWN;\n  case ngf::Scancode::Tab:return ng::InputConstants::KEY_TAB;\n  case ngf::Scancode::Return:return ng::InputConstants::KEY_RETURN;\n  case ngf::Scancode::Backspace:return ng::InputConstants::KEY_BACKSPACE;\n  default:return ng::InputConstants::NONE;\n  }\n}\n\nng::MetaKeys toMetaKeys(const ngf::KeyModifiers &modifiers) {\n  auto metaKey = ((static_cast<int>(modifiers) & static_cast<int>(ngf::KeyModifiers::Alt)) ? ng::MetaKeys::Alt\n                                                                                           : ng::MetaKeys::None) |\n      ((static_cast<int>(modifiers) & static_cast<int>(ngf::KeyModifiers::Control)) ? ng::MetaKeys::Control\n                                                                                    : ng::MetaKeys::None) |\n      ((static_cast<int>(modifiers) & static_cast<int>(ngf::KeyModifiers::Shift)) ? ng::MetaKeys::Shift\n                                                                                  : ng::MetaKeys::None) |\n      ((static_cast<int>(modifiers) & static_cast<int>(ngf::KeyModifiers::Gui)) ? ng::MetaKeys::System\n                                                                                : ng::MetaKeys::None);\n  return metaKey;\n}\n}\n\nnamespace ng {\nvoid EnggeApplication::onInit() {\n  m_window.init({\"Engge\", {ng::Screen::Width, ng::Screen::Height}});\n  ng::Services::init();\n\n  // read achievements if any\n  auto achievementsPath = ng::Locator<ng::EngineSettings>::get().getPath();\n  achievementsPath.append(\"save.dat\");\n  if (std::filesystem::exists(achievementsPath)) {\n    ng::Locator<ng::AchievementManager>::get().load(achievementsPath);\n  }\n\n  // detect if we have any ggpack file\n  if (ng::Locator<ng::EngineSettings>::get().getPackCount() == 0) {\n    std::string s;\n    s = \"No ggpack files detected.\";\n    throw std::logic_error(s);\n  }\n\n  auto &scriptEngine = ng::Locator<ng::ScriptEngine>::create();\n  m_engine = &ng::Locator<ng::Engine>::create();\n  m_engine->setApplication(this);\n  scriptEngine.setEngine(*m_engine);\n  m_debugTools = std::make_unique<ng::DebugTools>(*m_engine);\n\n  Locator<CommandManager>::get().registerCommands({\n                                                      {EngineCommands::ToggleDebug,\n                                                       [this] { m_debugTools->visible = !m_debugTools->visible; }}\n                                                  });\n\n  ng::InputMappings::registerMappings();\n  ng::info(\"Start game\");\n}\n\nvoid EnggeApplication::onEvent(ngf::Event &event) {\n  switch (event.type) {\n  case ngf::EventType::Quit:\n    ng::Locator<Engine>::reset();\n    ng::Locator<SoundManager>::reset();\n    m_engine = nullptr;\n    break;\n  case ngf::EventType::WindowResized:\n    getRenderTarget()->setView(ngf::View{\n        ngf::frect::fromPositionSize({0, 0}, glm::vec2(event.resize.size) * ngf::Window::getDpiScale())});\n    break;\n  case ngf::EventType::MouseButtonPressed:\n    if (event.mouseButton.button == 0) {\n      m_isMousePressed = true;\n      m_pos = event.mouseButton.position;\n    }\n    break;\n  case ngf::EventType::MouseButtonReleased:\n    if (event.mouseButton.button == 0) {\n      m_isMousePressed = false;\n    }\n    break;\n  case ngf::EventType::MouseMoved: {\n    if (!m_isMousePressed || !m_isKeyPressed)\n      break;\n    auto pos2 = event.mouseMoved.position;\n    auto delta = pos2 - m_pos;\n    if (abs(delta.x) < 50) {\n      m_engine->getCamera().move(-(glm::vec2) delta);\n    }\n    m_pos = pos2;\n  }\n    break;\n  case ngf::EventType::KeyReleased: {\n    auto key = toKey(event.key.scancode);\n    auto metaKey = toMetaKeys(event.key.modifiers);\n    if (key != ng::InputConstants::NONE) {\n      m_engine->keyUp({metaKey, key});\n    }\n    if (event.key.scancode == ngf::Scancode::Space) {\n      m_isKeyPressed = false;\n    }\n  }\n    break;\n  case ngf::EventType::KeyPressed: {\n    auto key = toKey(event.key.scancode);\n    auto metaKey = toMetaKeys(event.key.modifiers);\n    if (key != ng::InputConstants::NONE) {\n      m_engine->keyDown({metaKey, key});\n    }\n    if (event.key.scancode == ngf::Scancode::Space) {\n      m_isKeyPressed = true;\n    }\n    break;\n  }\n  default:break;\n  }\n}\n\nvoid EnggeApplication::onRender(ngf::RenderTarget &target) {\n  ngf::StopWatch clock;\n  target.clear();\n  if (m_engine)\n    m_engine->draw(target);\n  Application::onRender(target);\n  ng::DebugFeatures::renderTime = clock.getElapsedTime();\n}\n\nvoid EnggeApplication::onImGuiRender() {\n  m_debugTools->render();\n}\n\nvoid EnggeApplication::onUpdate(const ngf::TimeSpan &elapsed) {\n  if (!m_init) {\n    m_engine->run();\n    m_init = true;\n  }\n  ngf::StopWatch clock;\n  m_engine->update(elapsed);\n  ng::DebugFeatures::updateTime = clock.getElapsedTime();\n}\n\nvoid EnggeApplication::onQuit() {\n  auto achievementsPath = ng::Locator<ng::EngineSettings>::get().getPath();\n  achievementsPath.append(\"save.dat\");\n  ng::Locator<ng::AchievementManager>::get().save(achievementsPath);\n  Application::onQuit();\n}\n}\n"
  },
  {
    "path": "src/Engine/AchievementManager.cpp",
    "content": "#include \"AchievementManager.hpp\"\n#include <engge/Util/BTEACrypto.hpp>\n#include <engge/Parsers/SavegameManager.hpp>\n#include <ngf/IO/Json/JsonParser.h>\n#include <fstream>\n#include <sstream>\n#include <string.h>\n#include <vector>\n\nnamespace {\nconst uint8_t\n    key[] = {0x93, 0x9D, 0xAB, 0x2A, 0x2A, 0x56, 0xF8, 0xAF, 0xB4, 0xDB, 0xA2, 0xB5, 0x22, 0xA3, 0x4B, 0x2B};\n\nstd::string toString(const ngf::GGPackValue &value) {\n  std::ostringstream os;\n  for (const auto &item : value.items()) {\n    os << item.key() << \": \";\n    if (item.value().isString()) {\n      os << \"\\\"\" << item.value().getString() << \"\\\"\";\n    } else if (item.value().isDouble()) {\n      os << item.value().getDouble();\n    } else if (item.value().isInteger()) {\n      os << item.value().getInt();\n    }\n    os << '\\n';\n  }\n  return os.str();\n}\n}\n\nnamespace ng {\nvoid AchievementManager::load(const std::filesystem::path &path) {\n  std::ifstream is(path, std::ifstream::binary);\n  is.seekg(0, std::ios::end);\n  auto size = static_cast<int>(is.tellg());\n  is.seekg(0, std::ios::beg);\n  std::vector<char> data(size, '\\0');\n  is.read(data.data(), size);\n  is.close();\n\n  const int32_t decSize = size / 4;\n  BTEACrypto::decrypt((uint32_t *) &data[0], decSize, (uint32_t *) key);\n\n  auto marker = data[size - 1];\n  data[size - (marker + 1 + 8)] = 0;\n\n  m_value = ngf::Json::parse(data.data());\n//  std::ofstream os(\"Save.dat.txt\", std::ifstream::binary);\n//  os.write(data.data(), size);\n//  os.close();\n}\n\nvoid AchievementManager::save(const std::filesystem::path &path) {\n  auto content = toString(m_value);\n  auto fullSize = content.size();\n  const int32_t marker = 8 - ((fullSize + 9) % 8);\n\n  std::vector<char> buffer(fullSize + 8 + marker + 1);\n  memcpy(buffer.data(), content.data(), fullSize);\n\n  time_t now;\n  time(&now);\n\n  // write at the end 16 bytes: hashdata (4 bytes) + savetime (4 bytes) + marker\n  *(int32_t *) &buffer[fullSize] = SavegameManager::computeHash(buffer, fullSize);\n  *(int32_t *) &buffer[fullSize + 4] = static_cast<int32_t>(now);\n  memset(&buffer[fullSize + 8], marker, marker + 1);\n\n  BTEACrypto::encrypt((uint32_t *) buffer.data(), buffer.size() / 4, (uint32_t *) key);\n\n  std::ofstream os(path, std::ifstream::binary);\n  os.write(buffer.data(), buffer.size());\n  os.close();\n}\n\nngf::GGPackValue AchievementManager::getPrivatePreference(const std::string &name) const {\n  return m_value[name];\n}\n}"
  },
  {
    "path": "src/Engine/AchievementManager.hpp",
    "content": "#pragma once\n#include <filesystem>\n#include <string>\n#include <ngf/IO/GGPackValue.h>\n#include <engge/System/Logger.hpp>\n\nnamespace ng {\nclass AchievementManager final {\npublic:\n  void load(const std::filesystem::path &path);\n  void save(const std::filesystem::path &path);\n\n  template<typename T>\n  void setPrivatePreference(const std::string &name, T value) {\n    trace(\"setPrivatePreference({},{})\", name, value);\n    m_value[name] = value;\n  }\n\n  [[nodiscard]] ngf::GGPackValue getPrivatePreference(const std::string &name) const;\n\nprivate:\n  ngf::GGPackValue m_value;\n};\n}\n"
  },
  {
    "path": "src/Engine/ActorIcons.cpp",
    "content": "#define _USE_MATH_DEFINES\n#include <cmath>\n#include <ngf/Graphics/Sprite.h>\n#include <ngf/System/Mouse.h>\n#include \"engge/System/Locator.hpp\"\n#include \"engge/Graphics/SpriteSheet.hpp\"\n#include \"engge/Engine/ActorIcons.hpp\"\n#include \"engge/Engine/Engine.hpp\"\n#include \"engge/Room/Room.hpp\"\n\nnamespace ng {\n\nstatic const float topMargin = 4.f;\nstatic const float rightMargin = 6.f;\nstatic const float iconsMargin = 6.f;\nstatic const glm::vec2 iconSize = {48.f, 54.f};\nstatic const float disableAlpha = 0.5f;\nstatic const float enableAlpha = 1.0f;\n\nActorIcons::ActorIcons(std::array<ActorIconSlot, 6> &actorsIconSlots, Hud &hud,\n                       Actor *&pCurrentActor)\n    : m_actorsIconSlots(actorsIconSlots), m_hud(hud), m_pCurrentActor(pCurrentActor) {\n}\n\nvoid ActorIcons::setEngine(Engine *pEngine) {\n  m_pEngine = pEngine;\n}\n\nvoid ActorIcons::setMousePosition(const glm::vec2 &pos) { m_mousePos = pos; }\n\nvoid ActorIcons::update(const ngf::TimeSpan &elapsed) {\n  if (m_on) {\n    m_time += elapsed;\n    m_alpha = (160.f + 96.f * sinf(M_PI * 4 * m_time.getTotalSeconds())) / 255.f;\n\n    if (m_time > ngf::TimeSpan::seconds(40)) {\n      flash(false);\n    }\n  }\n  ngf::frect iconRect = ngf::frect::fromPositionSize({Screen::Width - iconSize.x - rightMargin, topMargin},\n                                                     {iconSize.x, iconSize.y\n                                                         + (m_isInside ? getIconsNum() * (iconSize.y + iconsMargin)\n                                                                       : 0.f)});\n  bool wasInside = m_isInside;\n  m_isInside = iconRect.contains(m_mousePos);\n  if (wasInside != m_isInside) {\n    m_clock.restart();\n    if (m_isInside) {\n      flash(false);\n    }\n  }\n  m_position = m_clock.getElapsedTime().getTotalSeconds() / ngf::TimeSpan::milliseconds(250).getTotalSeconds();\n  if (m_position > 1) {\n    m_position = 1;\n  }\n\n  if (m_isInside && !m_isMouseButtonPressed && ngf::Mouse::isButtonPressed(ngf::Mouse::Button::Left)) {\n    m_isMouseButtonPressed = true;\n    return;\n  }\n\n  auto isEnabled = ((m_mode & ActorSlotSelectableMode::On) == ActorSlotSelectableMode::On)\n      && ((m_mode & ActorSlotSelectableMode::TemporaryUnselectable) != ActorSlotSelectableMode::TemporaryUnselectable);\n  if (m_isMouseButtonPressed && !ngf::Mouse::isButtonPressed(ngf::Mouse::Button::Left)) {\n    m_isMouseButtonPressed = false;\n    iconRect =\n        ngf::frect::fromPositionSize({Screen::Width - iconSize.x - rightMargin, topMargin + iconsMargin + iconSize.y},\n                                     {iconSize.x, iconSize.y});\n    for (auto selectableActor : m_actorsIconSlots) {\n      if (!isSelectable(selectableActor) || selectableActor.pActor == m_pCurrentActor)\n        continue;\n\n      if (isEnabled && iconRect.contains(m_mousePos)) {\n        m_pEngine->setCurrentActor(selectableActor.pActor, true);\n        return;\n      }\n      iconRect.min.y += iconsMargin + iconSize.y;\n      iconRect.max.y += iconsMargin + iconSize.y;\n    }\n    if (iconRect.contains(m_mousePos)) {\n      m_pEngine->showOptions(true);\n      return;\n    }\n  }\n}\n\nfloat ActorIcons::getOffsetY(int num) const {\n  if (m_isInside)\n    return (topMargin + (iconSize.y / 2.f) + (iconSize.y + iconsMargin) * num) * m_position;\n  return topMargin + (iconSize.y / 2.f) + (iconSize.y + iconsMargin) * num;\n}\n\nint ActorIcons::getIconsNum() const {\n  int numIcons = 1;\n  for (auto selectableActor : m_actorsIconSlots) {\n    if (!selectableActor.selectable || !selectableActor.pActor || selectableActor.pActor == m_pCurrentActor)\n      continue;\n\n    numIcons++;\n  }\n  return numIcons;\n}\n\nvoid ActorIcons::flash(bool on) {\n  m_time = ngf::TimeSpan::seconds(0);\n  m_alpha = disableAlpha;\n  m_on = on;\n}\n\nvoid ActorIcons::setMode(ActorSlotSelectableMode mode) { m_mode = mode; }\n\nbool ActorIcons::isSelectable(const ActorIconSlot &slot) {\n  if (!slot.selectable)\n    return false;\n\n  // the actor is not selectable if he is in room \"Void\"\n  const auto *pRoom = slot.pActor ? slot.pActor->getRoom() : nullptr;\n  if (pRoom && pRoom->getName() == \"Void\") {\n    pRoom = nullptr;\n  }\n  return pRoom;\n}\n\nvoid ActorIcons::draw(ngf::RenderTarget &target, ngf::RenderStates) const {\n  if ((m_mode & ActorSlotSelectableMode::TemporaryUnselectable) == ActorSlotSelectableMode::TemporaryUnselectable)\n    return;\n\n  auto currentActorIndex = getCurrentActorIndex();\n  if (currentActorIndex < 0)\n    return;\n\n  const auto view = target.getView();\n  target.setView(ngf::View(ngf::frect::fromPositionSize({0, 0}, {Screen::Width, Screen::Height})));\n\n  float alpha;\n  auto isEnabled = ((m_mode & ActorSlotSelectableMode::On) == ActorSlotSelectableMode::On)\n      && ((m_mode & ActorSlotSelectableMode::TemporaryUnselectable) != ActorSlotSelectableMode::TemporaryUnselectable);\n  if (isEnabled) {\n    alpha = m_isInside ? enableAlpha : m_alpha;\n  } else {\n    alpha = disableAlpha;\n  }\n\n  const auto &icon = m_actorsIconSlots.at(currentActorIndex).pActor->getIcon();\n\n  int numIcons = 0;\n  glm::vec2 offset(Screen::Width - (iconSize.x / 2.f) - rightMargin, getOffsetY(numIcons));\n  drawActorIcon(target, icon, currentActorIndex, offset, alpha);\n  numIcons++;\n\n  if (!m_isInside) {\n    target.setView(view);\n    return;\n  }\n\n  for (size_t i = 0; i < m_actorsIconSlots.size(); i++) {\n    const auto &selectableActor = m_actorsIconSlots.at(i);\n    if (!isSelectable(selectableActor) || selectableActor.pActor == m_pCurrentActor)\n      continue;\n\n    offset.y = getOffsetY(numIcons);\n    const auto &icon2 = selectableActor.pActor->getIcon();\n    drawActorIcon(target, icon2, i, offset, isEnabled ? enableAlpha : disableAlpha);\n    numIcons++;\n  }\n\n  offset.y = getOffsetY(numIcons);\n  drawActorIcon(target, \"icon_gear\", ngf::Colors::Black, ngf::Color(128, 128, 128), offset, enableAlpha);\n\n  target.setView(view);\n}\n\nvoid ActorIcons::drawActorIcon(ngf::RenderTarget &target, const std::string &icon, int actorSlot,\n                               const glm::vec2 &offset, float alpha) const {\n  const auto &colors = m_hud.getVerbUiColors(actorSlot);\n  drawActorIcon(target, icon, colors.inventoryBackground, colors.inventoryFrame, offset, alpha);\n}\n\nvoid ActorIcons::drawActorIcon(ngf::RenderTarget &target, const std::string &icon, ngf::Color backColor,\n                               ngf::Color frameColor, const glm::vec2 &offset, float alpha) {\n  ngf::RenderStates states;\n  auto &gameSheet = Locator<ResourceManager>::get().getSpriteSheet(\"GameSheet\");\n  const auto &texture = gameSheet.getTexture();\n  auto backRect = gameSheet.getRect(\"icon_background\");\n  auto backSpriteSourceSize = gameSheet.getSpriteSourceSize(\"icon_background\");\n  auto backSourceSize = gameSheet.getSourceSize(\"icon_background\");\n\n  auto rect = gameSheet.getRect(icon);\n  auto spriteSourceSize = gameSheet.getSpriteSourceSize(icon);\n  auto sourceSize = gameSheet.getSourceSize(icon);\n\n  auto frameRect = gameSheet.getRect(\"icon_frame\");\n  auto frameSpriteSourceSize = gameSheet.getSpriteSourceSize(\"icon_frame\");\n  auto frameSourceSize = gameSheet.getSourceSize(\"icon_frame\");\n\n  // draw icon background\n  ngf::Sprite s;\n  glm::vec2 pos(-backSourceSize.x / 2.f + backSpriteSourceSize.getTopLeft().x,\n                -backSourceSize.y / 2.f + backSpriteSourceSize.getTopLeft().y);\n  ngf::Color c(backColor);\n  c.a = alpha;\n  s.getTransform().setScale({2, 2});\n  s.setColor(c);\n  s.getTransform().setPosition(offset);\n  s.getTransform().setOrigin(-pos);\n  s.setTexture(*texture);\n  s.setTextureRect(backRect);\n  s.draw(target, states);\n\n  // draw actor's icon\n  pos = glm::vec2(-sourceSize.x / 2.f + spriteSourceSize.getTopLeft().x,\n                  -sourceSize.y / 2.f + spriteSourceSize.getTopLeft().y);\n  s.getTransform().setOrigin(-pos);\n  c = ngf::Colors::White;\n  c.a = alpha;\n  s.setColor(c);\n  s.setTextureRect(rect);\n  s.draw(target, states);\n\n  // draw frame\n  pos = glm::vec2(-frameSourceSize.x / 2.f + frameSpriteSourceSize.getTopLeft().x,\n                  -frameSourceSize.y / 2.f + frameSpriteSourceSize.getTopLeft().y);\n  s.getTransform().setOrigin(-pos);\n  c = frameColor;\n  c.a = alpha;\n  s.setColor(c);\n  s.setTextureRect(frameRect);\n  s.draw(target, states);\n}\n\nint ActorIcons::getCurrentActorIndex() const {\n  for (size_t i = 0; i < m_actorsIconSlots.size(); i++) {\n    const auto &selectableActor = m_actorsIconSlots.at(i);\n    if (selectableActor.pActor == m_pCurrentActor) {\n      return i;\n    }\n  }\n  return -1;\n}\n} // namespace ng\n"
  },
  {
    "path": "src/Engine/Callback.cpp",
    "content": "#include <squirrel.h>\n#include \"../../extlibs/squirrel/squirrel/sqpcheader.h\"\n#include \"../../extlibs/squirrel/squirrel/sqvm.h\"\n#include \"../../extlibs/squirrel/squirrel/sqstring.h\"\n#include \"../../extlibs/squirrel/squirrel/sqtable.h\"\n#include \"../../extlibs/squirrel/squirrel/sqarray.h\"\n#include \"../../extlibs/squirrel/squirrel/sqfuncproto.h\"\n#include \"../../extlibs/squirrel/squirrel/sqclosure.h\"\n#include \"../../extlibs/squirrel/squirrel/squserdata.h\"\n#include \"../../extlibs/squirrel/squirrel/sqclass.h\"\n#include \"engge/Engine/Callback.hpp\"\n#include \"engge/System/Locator.hpp\"\n#include \"engge/System/Logger.hpp\"\n#include \"engge/Scripting/ScriptEngine.hpp\"\n\nnamespace ng {\nCallback::Callback(int id, ngf::TimeSpan duration, std::string method, HSQOBJECT arg)\n    : TimeFunction(duration), m_id(id), m_method(std::move(method)), m_arg(arg) {\n  sq_addref(ScriptEngine::getVm(), &m_arg);\n}\n\nCallback::~Callback(){\n  sq_release(ScriptEngine::getVm(), &m_arg);\n}\n\nvoid Callback::onElapsed() {\n  if (m_callbackDone)\n    return;\n  m_callbackDone = true;\n\n  auto v = ScriptEngine::getVm();\n  SQObjectPtr method;\n  _table(v->_roottable)->Get(ScriptEngine::toSquirrel(m_method), method);\n\n  SQInteger numArgs = 1;\n  sq_pushobject(v, method);\n  sq_pushroottable(v);\n  if (m_arg._type != OT_NULL) {\n    numArgs++;\n    sq_pushobject(v, m_arg);\n  }\n  if (SQ_FAILED(sq_call(v, numArgs, SQFalse, SQTrue))) {\n    error(\"failed to call callback\");\n  }\n  sq_pop(v, 1);\n}\n} // namespace ng\n"
  },
  {
    "path": "src/Engine/Camera.cpp",
    "content": "#include <algorithm>\n#include \"engge/Engine/Camera.hpp\"\n#include \"engge/Engine/Engine.hpp\"\n#include \"engge/Room/Room.hpp\"\n\nnamespace ng {\nstruct Camera::Impl {\n  Engine *_pEngine{nullptr};\n  glm::vec2 _at{0, 0};\n  std::optional<ngf::irect> _bounds;\n  bool _isMoving{false};\n  glm::vec2 _init{0, 0}, _target{0, 0};;\n  ngf::TimeSpan _elapsed, _time;\n  std::function<float(float)> _function = InterpolationHelper::getInterpolationMethod(InterpolationMethod::Linear);\n  const Actor *pFollow{nullptr};\n\n  void clampCamera(glm::vec2 &at);\n};\n\nvoid Camera::Impl::clampCamera(glm::vec2 &at) {\n  if (at.x < 0)\n    at.x = 0;\n  if (at.y < 0)\n    at.y = 0;\n\n  auto pRoom = _pEngine->getRoom();\n  if (!pRoom)\n    return;\n\n  auto roomSize = pRoom->getRoomSize();\n  auto screenSize = pRoom->getScreenSize();\n\n  if (_bounds) {\n    at.x =\n        std::clamp<int>(at.x, screenSize.x / 2 + _bounds->getTopLeft().x, screenSize.x / 2 + _bounds->getTopRight().x);\n    at.y = std::clamp<int>(at.y,\n                           screenSize.y / 2 + _bounds->getTopLeft().y,\n                           screenSize.y / 2 + _bounds->getBottomLeft().y);\n  }\n  at.x = std::clamp<float>(at.x, screenSize.x / 2, std::max(roomSize.x - screenSize.x / 2, 0));\n  at.y = std::clamp<float>(at.y, screenSize.y / 2, std::max(roomSize.y - screenSize.y / 2, 0));\n}\n\nCamera::Camera() : m_pImpl(std::make_unique<Impl>()) {}\n\nCamera::~Camera() = default;\n\nvoid Camera::setEngine(Engine *pEngine) { m_pImpl->_pEngine = pEngine; }\n\nvoid Camera::at(const glm::vec2 &at) {\n  m_pImpl->_at = at;\n  m_pImpl->clampCamera(m_pImpl->_at);\n  m_pImpl->_target = m_pImpl->_at;\n  m_pImpl->_time = ngf::TimeSpan::seconds(0);\n  m_pImpl->_isMoving = false;\n}\n\nngf::frect Camera::getRect() const {\n  auto pRoom = m_pImpl->_pEngine->getRoom();\n  auto screenSize = pRoom->getScreenSize();\n  return ngf::frect::fromCenterSize(m_pImpl->_at, screenSize);\n}\n\nglm::vec2 Camera::getAt() const { return m_pImpl->_at; }\n\nvoid Camera::move(const glm::vec2 &offset) {\n  m_pImpl->_at += offset;\n  m_pImpl->clampCamera(m_pImpl->_at);\n  m_pImpl->_target = m_pImpl->_at;\n  m_pImpl->_isMoving = false;\n}\n\nvoid Camera::setBounds(const ngf::irect &cameraBounds) {\n  m_pImpl->_bounds = cameraBounds;\n  m_pImpl->clampCamera(m_pImpl->_at);\n}\n\nstd::optional<ngf::irect> Camera::getBounds() const { return m_pImpl->_bounds; }\n\nvoid Camera::resetBounds() { m_pImpl->_bounds = std::nullopt; }\n\nvoid Camera::panTo(glm::vec2 target, ngf::TimeSpan time, InterpolationMethod interpolation) {\n  if (!m_pImpl->_isMoving) {\n    m_pImpl->_isMoving = true;\n    m_pImpl->_init = m_pImpl->_at;\n    m_pImpl->_elapsed = ngf::TimeSpan::seconds(0);\n  }\n  m_pImpl->_function = InterpolationHelper::getInterpolationMethod(interpolation);\n  m_pImpl->_target = target;\n  m_pImpl->_time = time;\n}\n\nvoid Camera::update(const ngf::TimeSpan &elapsed) {\n  m_pImpl->_elapsed += elapsed;\n  auto isMoving = m_pImpl->_elapsed < m_pImpl->_time;\n\n  if (m_pImpl->_isMoving && !isMoving) {\n    m_pImpl->_isMoving = false;\n    m_pImpl->_time = ngf::TimeSpan::seconds(0);\n    at(m_pImpl->_target);\n  }\n\n  if (isMoving) {\n    auto t = m_pImpl->_elapsed.getTotalSeconds() / m_pImpl->_time.getTotalSeconds();\n    auto d = m_pImpl->_target - m_pImpl->_init;\n    auto pos = m_pImpl->_init + m_pImpl->_function(t) * d;\n\n    m_pImpl->clampCamera(pos);\n    m_pImpl->_at = pos;\n    return;\n  }\n\n  const auto *pFollowActor = m_pImpl->_pEngine->getFollowActor();\n  const auto *pRoom = m_pImpl->_pEngine->getRoom();\n  if (pFollowActor && pFollowActor->isVisible() && pFollowActor->getRoom() == pRoom) {\n    const auto screen = pRoom->getScreenSize();\n    const auto pos = pFollowActor->getPosition();\n    const auto margin = glm::vec2(screen.x / 4, screen.y / 4);\n    const auto cameraPos = getAt();\n\n    const auto d = pos - cameraPos;\n    const auto delta = d * elapsed.getTotalSeconds();\n    const auto sameActor = m_pImpl->pFollow == pFollowActor;\n\n    float x, y;\n    if (sameActor && (pos.x > (cameraPos.x + margin.x))) {\n      x = pos.x - margin.x;\n    } else if (sameActor && (pos.x < (cameraPos.x - margin.x))) {\n      x = pos.x + margin.x;\n    } else {\n      x = cameraPos.x + (d.x > 0 ? std::min(delta.x, d.x) : std::max(delta.x, d.x));\n    }\n    if (sameActor && (pos.y > (cameraPos.y + margin.y))) {\n      y = pos.y - margin.y;\n    } else if (sameActor && (pos.y < (cameraPos.y - margin.y))) {\n      y = pos.y + margin.y;\n    } else {\n      y = cameraPos.y + (d.y > 0 ? std::min(delta.y, d.y) : std::max(delta.y, d.y));\n    }\n    at({x, y});\n    if (!sameActor && std::abs(pos.x - x) < 1 && std::abs(pos.y - y) < 1) {\n      m_pImpl->pFollow = pFollowActor;\n    }\n  }\n}\n\nbool Camera::isMoving() const { return m_pImpl->_isMoving; }\n\n} // namespace ng\n"
  },
  {
    "path": "src/Engine/Cutscene.cpp",
    "content": "#include <engge/Engine/Camera.hpp>\n#include <engge/Engine/Cutscene.hpp>\n#include <engge/Engine/Engine.hpp>\n#include <engge/System/Logger.hpp>\n#include <engge/Scripting/ScriptEngine.hpp>\n#include <engge/Engine/EntityManager.hpp>\n\nnamespace ng {\nCutscene::Cutscene(Engine &engine,\n                   HSQUIRRELVM v,\n                   HSQOBJECT thread,\n                   HSQOBJECT closureObj,\n                   HSQOBJECT closureCutsceneOverrideObj,\n                   HSQOBJECT envObj)\n    : m_engine(engine), m_v(v), m_threadCutscene(thread), m_state(0), m_closureObj(closureObj),\n      m_closureCutsceneOverrideObj(closureCutsceneOverrideObj), m_envObj(envObj) {\n  auto engineVm = ScriptEngine::getVm();\n  m_hasCutsceneOverride = !sq_isnull(m_closureCutsceneOverrideObj);\n  m_inputState = m_engine.getInputState();\n  trace(\"Cutscene with inputState {}\", m_inputState);\n  m_engine.setInputActive(false);\n  m_engine.setInputVerbs(false);\n\n  sq_addref(engineVm, &m_threadCutscene);\n  sq_addref(engineVm, &m_closureObj);\n  sq_addref(engineVm, &m_closureCutsceneOverrideObj);\n  sq_addref(engineVm, &m_envObj);\n}\n\nCutscene::~Cutscene() {\n  auto engineVm = ScriptEngine::getVm();\n  sq_release(engineVm, &m_threadCutscene);\n  sq_release(engineVm, &m_closureObj);\n  sq_release(engineVm, &m_closureCutsceneOverrideObj);\n  sq_release(engineVm, &m_envObj);\n}\n\nHSQUIRRELVM Cutscene::getThread() const {\n  return m_threadCutscene._unVal.pThread;\n}\n\nstd::string Cutscene::getName() const {\n  return \"cutscene\";\n}\n\nbool Cutscene::isElapsed() { return m_state == 5; }\n\nvoid Cutscene::cutsceneOverride() {\n  if (m_hasCutsceneOverride && m_state == 1)\n    m_state = 2;\n}\n\nvoid Cutscene::operator()(const ngf::TimeSpan &) {\n  switch (m_state) {\n  case 0:trace(\"startCutscene\");\n    startCutscene();\n    break;\n  case 1:checkEndCutscene();\n    break;\n  case 2:trace(\"doCutsceneOverride\");\n    doCutsceneOverride();\n    break;\n  case 3:trace(\"checkEndCutsceneOverride\");\n    checkEndCutsceneOverride();\n    break;\n  case 4:trace(\"endCutscene\");\n    endCutscene();\n    break;\n  case 5:return;\n  }\n}\n\nvoid Cutscene::startCutscene() {\n  m_state = 1;\n  trace(\"start cutscene: {}\", m_id);\n  sq_pushobject(m_threadCutscene._unVal.pThread, m_closureObj);\n  sq_pushobject(m_threadCutscene._unVal.pThread, m_envObj);\n  if (SQ_FAILED(sq_call(m_threadCutscene._unVal.pThread, 1, SQFalse, SQTrue))) {\n    error(\"Couldn't call cutscene\");\n  }\n}\n\nvoid Cutscene::checkEndCutscene() {\n  if (ThreadBase::isStopped()) {\n    m_state = 4;\n    trace(\"end cutscene: {}\", m_id);\n  }\n}\n\nvoid Cutscene::doCutsceneOverride() {\n  if (m_hasCutsceneOverride) {\n    m_state = 3;\n    trace(\"start cutsceneOverride: {}\", m_id);\n    sq_pushobject(m_threadCutscene._unVal.pThread, m_closureCutsceneOverrideObj);\n    sq_pushobject(m_threadCutscene._unVal.pThread, m_envObj);\n    if (SQ_FAILED(sq_call(m_threadCutscene._unVal.pThread, 1, SQFalse, SQTrue))) {\n      error(\"Couldn't call cutsceneOverride\");\n    }\n    return;\n  }\n  m_state = 4;\n}\n\nvoid Cutscene::checkEndCutsceneOverride() {\n  if (ThreadBase::isStopped()) {\n    m_state = 4;\n    trace(\"end checkEndCutsceneOverride: {}\", m_id);\n  }\n}\n\nvoid Cutscene::endCutscene() {\n  m_state = 5;\n  trace(\"End cutscene {} with inputState {}\", m_id, m_inputState);\n  m_engine.setInputState(m_inputState);\n  m_engine.follow(m_engine.getCurrentActor());\n  ScriptEngine::call(\"onCutsceneEnded\");\n  auto pThread = EntityManager::getThreadFromVm(m_v);\n  if (pThread)\n    pThread->resume();\n  pThread = EntityManager::getThreadFromId(m_id);\n  if (pThread)\n    pThread->stop();\n}\n\nbool Cutscene::isStopped() const {\n  return m_state == 5;\n}\n\n} // namespace ng"
  },
  {
    "path": "src/Engine/DebugFeatures.hpp",
    "content": "#pragma once\n\nnamespace ng {\n\nstruct DebugFeatures {\n  inline static bool showHoveredObject{false};\n  inline static bool showCursorPosition{false};\n  inline static bool showTextBounds{false};\n  inline static ngf::TimeSpan renderTime;\n  inline static ngf::TimeSpan updateTime;\n};\n\n}"
  },
  {
    "path": "src/Engine/Engine.cpp",
    "content": "#ifdef _WIN32\n// for Windows you'll need this to have M_PI defined\n#define _USE_MATH_DEFINES\n#endif\n#include <cmath>\n#include <ctime>\n#include <cwchar>\n#include <filesystem>\n#include <iomanip>\n#include <memory>\n#include <set>\n#include <string>\n#include <unordered_set>\n#include <squirrel.h>\n#include <ngf/Application.h>\n#include <ngf/Graphics/Colors.h>\n#include <ngf/System/Mouse.h>\n#include <engge/Util/RandomNumberGenerator.hpp>\n#include <engge/EnggeApplication.hpp>\n#include <engge/Engine/Engine.hpp>\n#include <engge/Engine/ActorIcons.hpp>\n#include <engge/Engine/Camera.hpp>\n#include <engge/Engine/Cutscene.hpp>\n#include <engge/Engine/Hud.hpp>\n#include <engge/Input/InputConstants.hpp>\n#include <engge/Dialog/DialogManager.hpp>\n#include <engge/Engine/Inventory.hpp>\n#include <engge/Engine/Preferences.hpp>\n#include <engge/Room/Room.hpp>\n#include <engge/Room/RoomScaling.hpp>\n#include <engge/Scripting/ScriptEngine.hpp>\n#include <engge/Scripting/ScriptExecute.hpp>\n#include <engge/Engine/Sentence.hpp>\n#include <engge/Audio/SoundDefinition.hpp>\n#include <engge/Audio/SoundManager.hpp>\n#include <engge/Graphics/SpriteSheet.hpp>\n#include <engge/Engine/TextDatabase.hpp>\n#include <engge/Engine/Verb.hpp>\n#include <engge/Scripting/VerbExecute.hpp>\n#include <engge/System/Logger.hpp>\n#include <engge/Engine/InputStateConstants.hpp>\n#include \"EngineImpl.hpp\"\n\nnamespace fs = std::filesystem;\n\nnamespace ng {\n\nEngine::Engine() : m_pImpl(std::make_unique<Impl>()) {\n  m_pImpl->m_pEngine = this;\n  m_pImpl->m_soundManager.setEngine(this);\n  m_pImpl->m_dialogManager.setEngine(this);\n  m_pImpl->m_actorIcons.setEngine(this);\n  m_pImpl->m_camera.setEngine(this);\n  m_pImpl->m_talkingState.setEngine(this);\n\n  // load all messages\n  std::stringstream s;\n  auto lang =\n      m_pImpl->m_preferences.getUserPreference<std::string>(PreferenceNames::Language,\n                                                            PreferenceDefaultValues::Language);\n  s << \"ThimbleweedText_\" << lang << \".tsv\";\n  Locator<TextDatabase>::get().load(s.str());\n\n  m_pImpl->m_optionsDialog.setSaveEnabled(true);\n  m_pImpl->m_optionsDialog.setEngine(this);\n  m_pImpl->m_optionsDialog.setCallback([this]() {\n    showOptions(false);\n  });\n  m_pImpl->m_startScreenDialog.setEngine(this);\n  m_pImpl->m_startScreenDialog.setNewGameCallback([this]() {\n    m_pImpl->m_state = EngineState::Game;\n    m_pImpl->exitRoom(nullptr);\n    ScriptEngine::call(\"start\", true);\n  });\n  m_pImpl->m_startScreenDialog.setSlotCallback([this](int slot) {\n    m_pImpl->m_state = EngineState::Game;\n    loadGame(slot);\n  });\n\n  m_pImpl->m_preferences.subscribe([this](const std::string &name) {\n    if (name == PreferenceNames::Language) {\n      auto newLang = m_pImpl->m_preferences.getUserPreference<std::string>(PreferenceNames::Language,\n                                                                           PreferenceDefaultValues::Language);\n      m_pImpl->onLanguageChange(newLang);\n    } else if (name == PreferenceNames::Fullscreen) {\n      auto fullscreen = m_pImpl->m_preferences.getUserPreference(PreferenceNames::Fullscreen,\n                                                                 PreferenceDefaultValues::Fullscreen);\n      m_pImpl->m_pApp->getWindow().setFullscreen(fullscreen);\n    }\n  });\n}\n\nEngine::~Engine() = default;\n\nint Engine::getFrameCounter() const { return m_pImpl->m_frameCounter; }\n\nvoid Engine::setApplication(ng::EnggeApplication *app) { m_pImpl->m_pApp = app; }\n\nconst ng::EnggeApplication *Engine::getApplication() const { return m_pImpl->m_pApp; }\nng::EnggeApplication *Engine::getApplication() { return m_pImpl->m_pApp; }\n\nResourceManager &Engine::getResourceManager() { return m_pImpl->m_resourceManager; }\n\nRoom *Engine::getRoom() { return m_pImpl->m_pRoom; }\n\nstd::wstring Engine::getText(int id) {\n  auto text = Locator<TextDatabase>::get().getText(id);\n  removeFirstParenthesis(text);\n  return text;\n}\n\nstd::wstring Engine::getText(const std::string &text) {\n  auto text2 = Locator<TextDatabase>::get().getText(text);\n  removeFirstParenthesis(text2);\n  return text2;\n}\n\nvoid Engine::addActor(std::unique_ptr<Actor> actor) { m_pImpl->m_actors.push_back(std::move(actor)); }\n\nvoid Engine::addRoom(std::unique_ptr<Room> room) { m_pImpl->m_rooms.push_back(std::move(room)); }\n\nstd::vector<std::unique_ptr<Room>> &Engine::getRooms() { return m_pImpl->m_rooms; }\n\nvoid Engine::addFunction(std::unique_ptr<Function> function) { m_pImpl->m_newFunctions.push_back(std::move(function)); }\n\nvoid Engine::addCallback(std::unique_ptr<Callback> callback) { m_pImpl->m_callbacks.push_back(std::move(callback)); }\n\nvoid Engine::removeCallback(int id) {\n  auto it = std::find_if(m_pImpl->m_callbacks.begin(), m_pImpl->m_callbacks.end(),\n                         [id](auto &callback) -> bool { return callback->getId() == id; });\n  if (it != m_pImpl->m_callbacks.end()) {\n    m_pImpl->m_callbacks.erase(it);\n  }\n}\n\nstd::vector<std::unique_ptr<Actor>> &Engine::getActors() { return m_pImpl->m_actors; }\n\nActor *Engine::getCurrentActor() { return m_pImpl->m_pCurrentActor; }\n\nconst VerbUiColors *Engine::getVerbUiColors(const std::string &name) const {\n  if (name.empty()) {\n    auto index = m_pImpl->getCurrentActorIndex();\n    if (index == -1)\n      return nullptr;\n    return &m_pImpl->m_hud.getVerbUiColors(index);\n  }\n  for (int i = 0; i < static_cast<int>(m_pImpl->m_actorsIconSlots.size()); i++) {\n    const auto &selectableActor = m_pImpl->m_actorsIconSlots.at(i);\n    if (selectableActor.pActor && selectableActor.pActor->getKey() == name) {\n      return &m_pImpl->m_hud.getVerbUiColors(i);\n    }\n  }\n  return nullptr;\n}\n\nbool Engine::getInputActive() const { return m_pImpl->m_inputActive; }\n\nvoid Engine::setInputState(int state) {\n  if ((state & InputStateConstants::UI_INPUT_ON) == InputStateConstants::UI_INPUT_ON) {\n    m_pImpl->m_inputActive = true;\n  }\n  if ((state & InputStateConstants::UI_INPUT_OFF) == InputStateConstants::UI_INPUT_OFF) {\n    m_pImpl->m_inputActive = false;\n  }\n  if ((state & InputStateConstants::UI_VERBS_ON) == InputStateConstants::UI_VERBS_ON) {\n    m_pImpl->m_inputVerbsActive = true;\n  }\n  if ((state & InputStateConstants::UI_VERBS_OFF) == InputStateConstants::UI_VERBS_OFF) {\n    m_pImpl->m_inputVerbsActive = false;\n  }\n  if ((state & InputStateConstants::UI_CURSOR_ON) == InputStateConstants::UI_CURSOR_ON) {\n    m_pImpl->m_showCursor = true;\n  }\n  if ((state & InputStateConstants::UI_CURSOR_OFF) == InputStateConstants::UI_CURSOR_OFF) {\n    m_pImpl->m_showCursor = false;\n  }\n  if ((state & InputStateConstants::UI_HUDOBJECTS_ON) == InputStateConstants::UI_HUDOBJECTS_ON) {\n    m_pImpl->m_inputHUD = true;\n  }\n  if ((state & InputStateConstants::UI_HUDOBJECTS_OFF) == InputStateConstants::UI_HUDOBJECTS_OFF) {\n    m_pImpl->m_inputHUD = false;\n  }\n}\n\nint Engine::getInputState() const {\n  int inputState = 0;\n  inputState |= (m_pImpl->m_inputActive ? InputStateConstants::UI_INPUT_ON : InputStateConstants::UI_INPUT_OFF);\n  inputState |= (m_pImpl->m_inputVerbsActive ? InputStateConstants::UI_VERBS_ON : InputStateConstants::UI_VERBS_OFF);\n  inputState |= (m_pImpl->m_showCursor ? InputStateConstants::UI_CURSOR_ON : InputStateConstants::UI_CURSOR_OFF);\n  inputState |= (m_pImpl->m_inputHUD ? InputStateConstants::UI_HUDOBJECTS_ON : InputStateConstants::UI_HUDOBJECTS_OFF);\n  return inputState;\n}\n\nvoid Engine::follow(Actor *pActor) {\n  m_pImpl->m_pFollowActor = pActor;\n  if (!pActor)\n    return;\n\n  auto pos = pActor->getPosition();\n  auto pOldRoom = getRoom();\n  setRoom(pActor->getRoom());\n  if (pOldRoom != pActor->getRoom()) {\n    m_pImpl->m_camera.at(pos);\n  }\n}\n\nconst Actor *Engine::getFollowActor() const {\n  return m_pImpl->m_pFollowActor;\n}\n\nvoid Engine::setVerbExecute(std::unique_ptr<VerbExecute> verbExecute) {\n  m_pImpl->m_pVerbExecute = std::move(verbExecute);\n}\n\nvoid Engine::setDefaultVerb() {\n  m_pImpl->m_hud.setHoveredEntity(nullptr);\n  auto index = m_pImpl->getCurrentActorIndex();\n  if (index == -1)\n    return;\n\n  const auto &verbSlot = m_pImpl->m_hud.getVerbSlot(index);\n  m_pImpl->m_hud.setCurrentVerb(&verbSlot.getVerb(0));\n  m_pImpl->m_useFlag = UseFlag::None;\n  m_pImpl->m_pUseObject = nullptr;\n  m_pImpl->m_objId1 = 0;\n  m_pImpl->m_pObj2 = nullptr;\n}\n\nvoid Engine::setScriptExecute(std::unique_ptr<ScriptExecute> scriptExecute) {\n  m_pImpl->m_pScriptExecute = std::move(scriptExecute);\n}\n\nvoid Engine::addThread(std::unique_ptr<ThreadBase> thread) { m_pImpl->m_threads.push_back(std::move(thread)); }\n\nstd::vector<std::unique_ptr<ThreadBase>> &Engine::getThreads() { return m_pImpl->m_threads; }\n\nglm::vec2 Engine::getMousePositionInRoom() const { return m_pImpl->m_mousePosInRoom; }\n\nPreferences &Engine::getPreferences() { return m_pImpl->m_preferences; }\n\nSoundManager &Engine::getSoundManager() { return m_pImpl->m_soundManager; }\n\nDialogManager &Engine::getDialogManager() { return m_pImpl->m_dialogManager; }\n\nCamera &Engine::getCamera() { return m_pImpl->m_camera; }\n\nngf::TimeSpan Engine::getTime() const { return m_pImpl->m_time; }\n\nSQInteger Engine::setRoom(Room *pRoom) {\n  if (!pRoom)\n    return 0;\n\n  auto pOldRoom = m_pImpl->m_pRoom;\n  if (pRoom == pOldRoom)\n    return 0;\n\n  auto result = m_pImpl->exitRoom(nullptr);\n  if (SQ_FAILED(result))\n    return result;\n\n  m_pImpl->setCurrentRoom(pRoom);\n\n  result = m_pImpl->enterRoom(pRoom, nullptr);\n  if (SQ_FAILED(result))\n    return result;\n\n  return 0;\n}\n\nSQInteger Engine::enterRoomFromDoor(Object *pDoor) {\n  auto dir = pDoor->getUseDirection();\n  auto facing = toFacing(dir);\n  auto pRoom = pDoor->getRoom();\n\n  // exit current room\n  auto result = m_pImpl->exitRoom(nullptr);\n  if (SQ_FAILED(result))\n    return result;\n\n  // change current room\n  m_pImpl->setCurrentRoom(pRoom);\n\n  // move current actor to the new room\n  auto actor = getCurrentActor();\n  actor->getCostume().setFacing(facing);\n  actor->setRoom(pRoom);\n  auto pos = pDoor->getPosition();\n  auto usePos = pDoor->getUsePosition().value_or(glm::vec2());\n  pos += usePos;\n  actor->setPosition(pos);\n\n  // move camera to the actor if not closeup room\n  if (pRoom->getFullscreen() != 1) {\n    m_pImpl->m_camera.at(pos);\n  }\n\n  // enter current room\n  return m_pImpl->enterRoom(pRoom, pDoor);\n}\n\nvoid Engine::setInputHUD(bool on) { m_pImpl->m_inputHUD = on; }\n\nvoid Engine::setInputActive(bool active) {\n  if (inCutscene())\n    return;\n  m_pImpl->m_inputActive = active;\n  m_pImpl->m_showCursor = active;\n}\n\nvoid Engine::inputSilentOff() { m_pImpl->m_inputActive = false; }\n\nvoid Engine::setInputVerbs(bool on) { m_pImpl->m_inputVerbsActive = on; }\n\nvoid Engine::update(const ngf::TimeSpan &el) {\n  if (m_pImpl->m_state == EngineState::Quit)\n    return;\n\n  roomEffect.RandomValue[0] = Locator<RandomNumberGenerator>::get().generateFloat(0, 1.f);\n  roomEffect.iGlobalTime = fmod(m_pImpl->m_time.getTotalSeconds(), 1000.f);\n  roomEffect.TimeLapse = roomEffect.iGlobalTime;\n\n  auto gameSpeedFactor =\n      getPreferences().getUserPreference(PreferenceNames::EnggeGameSpeedFactor,\n                                         PreferenceDefaultValues::EnggeGameSpeedFactor);\n  const ngf::TimeSpan elapsed(ngf::TimeSpan::seconds(el.getTotalSeconds() * gameSpeedFactor));\n  m_pImpl->stopThreads();\n  auto screenSize = m_pImpl->m_pRoom->getScreenSize();\n  auto view = ngf::View{ngf::frect::fromPositionSize({0, 0}, screenSize)};\n  m_pImpl->m_mousePos = m_pImpl->m_pApp->getRenderTarget()->mapPixelToCoords(ngf::Mouse::getPosition(), view);\n  if (m_pImpl->m_pRoom && m_pImpl->m_pRoom->getName() != \"Void\") {\n    auto screenMouse = toDefaultView((glm::ivec2) m_pImpl->m_mousePos, screenSize);\n    m_pImpl->m_hud.setMousePosition(screenMouse);\n    m_pImpl->m_dialogManager.setMousePosition(screenMouse);\n  }\n  if (m_pImpl->m_state == EngineState::Options) {\n    m_pImpl->m_optionsDialog.update(elapsed);\n  } else if (m_pImpl->m_state == EngineState::StartScreen) {\n    m_pImpl->m_startScreenDialog.update(elapsed);\n    if (m_pImpl->m_state == EngineState::Quit)\n      return;\n  }\n\n  if (m_pImpl->m_state == EngineState::Paused) {\n    m_pImpl->updateKeys();\n    return;\n  }\n\n  // update fade effect\n  m_pImpl->m_fadeEffect.elapsed += elapsed;\n  m_pImpl->m_talkingState.update(elapsed);\n\n  m_pImpl->m_frameCounter++;\n  auto &io = ImGui::GetIO();\n  auto wasMouseDown = m_pImpl->m_isMouseDown && !io.WantCaptureMouse;\n  auto wasMouseRightDown = m_pImpl->m_isMouseRightDown;\n  m_pImpl->m_isMouseDown =\n      ngf::Mouse::isButtonPressed(ngf::Mouse::Button::Left) && !io.WantCaptureMouse;\n  if (!wasMouseDown || !m_pImpl->m_isMouseDown) {\n    m_pImpl->m_mouseDownTime = ngf::TimeSpan::seconds(0);\n    m_pImpl->run(false);\n  } else {\n    m_pImpl->m_mouseDownTime += elapsed;\n    if (m_pImpl->m_mouseDownTime > ngf::TimeSpan::seconds(0.5f)) {\n      m_pImpl->run(true);\n    }\n  }\n  m_pImpl->m_isMouseRightDown = ngf::Mouse::isButtonPressed(ngf::Mouse::Button::Right) && !io.WantCaptureMouse;\n  bool isRightClick = wasMouseRightDown != m_pImpl->m_isMouseRightDown && !m_pImpl->m_isMouseRightDown;\n  auto isMouseClick = wasMouseDown != m_pImpl->m_isMouseDown && !m_pImpl->m_isMouseDown;\n\n  m_pImpl->m_time += elapsed;\n  m_pImpl->m_noOverrideElapsed += elapsed;\n\n  m_pImpl->m_camera.update(elapsed);\n  m_pImpl->m_soundManager.update(elapsed);\n  m_pImpl->updateCutscene(elapsed);\n  m_pImpl->updateFunctions(elapsed);\n  m_pImpl->updateSentence(elapsed);\n  m_pImpl->updateKeys();\n\n  if (!m_pImpl->m_pRoom || m_pImpl->m_pRoom->getName() == \"Void\")\n    return;\n\n  m_pImpl->updateRoomScalings();\n\n  m_pImpl->m_pRoom->update(elapsed);\n  for (auto &pActor : m_pImpl->m_actors) {\n    if (!pActor || pActor->getRoom() == m_pImpl->m_pRoom)\n      continue;\n    pActor->update(elapsed);\n  }\n\n  m_pImpl->updateActorIcons(elapsed);\n\n  if (m_pImpl->m_state == EngineState::Options)\n    return;\n\n  m_pImpl->m_cursorDirection = CursorDirection::None;\n  m_pImpl->updateMouseCursor();\n\n  auto mousePos =\n      glm::vec2(m_pImpl->m_mousePos.x, m_pImpl->m_pRoom->getScreenSize().y - m_pImpl->m_mousePos.y);\n  m_pImpl->m_mousePosInRoom = mousePos + m_pImpl->m_camera.getRect().getTopLeft();\n\n  m_pImpl->m_dialogManager.update(elapsed);\n\n  m_pImpl->m_hud.setActive(\n      m_pImpl->m_inputVerbsActive && m_pImpl->m_dialogManager.getState() == DialogManagerState::None\n          && m_pImpl->m_pRoom->getFullscreen() != 1);\n  m_pImpl->m_hud.setHoveredEntity(m_pImpl->getHoveredEntity(m_pImpl->m_mousePosInRoom));\n  m_pImpl->updateHoveredEntity(isRightClick);\n\n  if (m_pImpl->m_pCurrentActor) {\n    auto &objects = m_pImpl->m_pCurrentActor->getObjects();\n    for (auto &object : objects) {\n      object->update(elapsed);\n    }\n  }\n\n  m_pImpl->m_hud.update(elapsed);\n\n  if (m_pImpl->m_actorIcons.isMouseOver())\n    return;\n\n  if (isMouseClick && m_pImpl->clickedAt(m_pImpl->m_mousePosInRoom))\n    return;\n\n  if (!m_pImpl->m_inputActive)\n    return;\n\n  m_pImpl->updateKeyboard();\n\n  if (m_pImpl->m_dialogManager.getState() != DialogManagerState::None) {\n    auto rightClickSkipsDialog = getPreferences().getUserPreference(PreferenceNames::RightClickSkipsDialog,\n                                                                    PreferenceDefaultValues::RightClickSkipsDialog);\n    if (rightClickSkipsDialog && isRightClick) {\n      m_pImpl->skipText();\n    }\n    return;\n  }\n\n  if (!m_pImpl->m_pCurrentActor)\n    return;\n\n  if (!isMouseClick && !isRightClick && !m_pImpl->m_isMouseDown)\n    return;\n\n  m_pImpl->m_hud.setVisible(true);\n  m_pImpl->m_actorIcons.setVisible(true);\n  m_pImpl->m_cursorVisible = true;\n  stopSentence();\n\n  const auto *pVerb = m_pImpl->getHoveredVerb();\n  // input click on a verb ?\n  if (m_pImpl->m_hud.getActive() && pVerb) {\n    m_pImpl->onVerbClick(pVerb);\n    return;\n  }\n\n  if (!isMouseClick && !isRightClick) {\n    if (!pVerb && !m_pImpl->m_hud.getHoveredEntity())\n      m_pImpl->m_pCurrentActor->walkTo(m_pImpl->m_mousePosInRoom);\n    return;\n  }\n\n  if (m_pImpl->m_hud.getHoveredEntity()) {\n    ScriptEngine::rawCall(\"onObjectClick\", m_pImpl->m_hud.getHoveredEntity());\n    auto pVerbOverride = m_pImpl->m_hud.getVerbOverride();\n    if (!pVerbOverride) {\n      pVerbOverride = m_pImpl->m_hud.getCurrentVerb();\n    }\n    pVerbOverride = m_pImpl->overrideVerb(pVerbOverride);\n    auto pObj1 = EntityManager::getScriptObjectFromId<Entity>(m_pImpl->m_objId1);\n    pObj1 = pVerbOverride->id == VerbConstants::VERB_TALKTO ? m_pImpl->getEntity(pObj1) : pObj1;\n    auto\n        pObj2 = pVerbOverride->id == VerbConstants::VERB_GIVE ? m_pImpl->getEntity(m_pImpl->m_pObj2) : m_pImpl->m_pObj2;\n    if (pObj1) {\n      m_pImpl->m_pVerbExecute->execute(pVerbOverride, pObj1, pObj2);\n    }\n    return;\n  }\n\n  if (m_pImpl->m_hud.isMouseOver())\n    return;\n\n  m_pImpl->m_pCurrentActor->walkTo(m_pImpl->m_mousePosInRoom);\n  setDefaultVerb();\n}\n\nvoid Engine::setCurrentActor(Actor *pCurrentActor, bool userSelected) {\n  m_pImpl->m_pCurrentActor = pCurrentActor;\n\n  int currentActorIndex = m_pImpl->getCurrentActorIndex();\n  m_pImpl->m_hud.setCurrentActorIndex(currentActorIndex);\n  m_pImpl->m_hud.setCurrentActor(m_pImpl->m_pCurrentActor);\n\n  ScriptEngine::rawCall(\"onActorSelected\", pCurrentActor, userSelected);\n  auto pRoom = pCurrentActor ? pCurrentActor->getRoom() : nullptr;\n  if (pRoom) {\n    if (ScriptEngine::rawExists(pRoom, \"onActorSelected\")) {\n      ScriptEngine::rawCall(pRoom, \"onActorSelected\", pCurrentActor, userSelected);\n    }\n  }\n\n  if (m_pImpl->m_pCurrentActor) {\n    follow(m_pImpl->m_pCurrentActor);\n  }\n}\n\nvoid Engine::draw(ngf::RenderTarget &target, bool screenshot) const {\n  if (!m_pImpl->m_pRoom)\n    return;\n\n  // update room shader if necessary\n  ngf::RenderStates states;\n  auto effect = m_pImpl->m_pRoom->getEffect();\n  if (m_pImpl->m_roomEffect != effect) {\n    if (effect == RoomEffectConstants::EFFECT_BLACKANDWHITE) {\n      m_pImpl->m_roomShader.load(Shaders::vertexShader, Shaders::bwFragmentShader);\n    } else if (effect == RoomEffectConstants::EFFECT_EGA) {\n      m_pImpl->m_roomShader.load(Shaders::vertexShader, Shaders::egaFragmenShader);\n    } else if (effect == RoomEffectConstants::EFFECT_GHOST) {\n      m_pImpl->m_roomShader.load(Shaders::vertexShader, Shaders::ghostFragmentShader);\n    } else if (effect == RoomEffectConstants::EFFECT_SEPIA) {\n      m_pImpl->m_roomShader.load(Shaders::vertexShader, Shaders::sepiaFragmentShader);\n    } else if (effect == RoomEffectConstants::EFFECT_VHS) {\n      m_pImpl->m_roomShader.load(Shaders::vertexShader, Shaders::vhsFragmentShader);\n    }\n    m_pImpl->m_roomEffect = effect;\n  }\n  states.shader = &m_pImpl->m_roomShader;\n  if (effect == RoomEffectConstants::EFFECT_GHOST) {\n    // don't remove the fmod function or you will have float overflow with the shader and the effect will look strange\n    m_pImpl->m_roomShader.setUniform(\"iGlobalTime\", roomEffect.iGlobalTime);\n    m_pImpl->m_roomShader.setUniform(\"iFade\", roomEffect.iFade);\n    m_pImpl->m_roomShader.setUniform(\"wobbleIntensity\", roomEffect.wobbleIntensity);\n    m_pImpl->m_roomShader.setUniform(\"shadows\", roomEffect.shadows);\n    m_pImpl->m_roomShader.setUniform(\"midtones\", roomEffect.midtones);\n    m_pImpl->m_roomShader.setUniform(\"highlights\", roomEffect.highlights);\n  } else if (effect == RoomEffectConstants::EFFECT_SEPIA) {\n    m_pImpl->m_roomShader.setUniform(\"sepiaFlicker\", roomEffect.sepiaFlicker);\n    m_pImpl->m_roomShader.setUniformArray(\"RandomValue\", roomEffect.RandomValue.data(), 5);\n    m_pImpl->m_roomShader.setUniform(\"TimeLapse\", roomEffect.TimeLapse);\n  } else if (effect == RoomEffectConstants::EFFECT_VHS) {\n    m_pImpl->m_roomShader.setUniform(\"iGlobalTime\", roomEffect.iGlobalTime);\n    m_pImpl->m_roomShader.setUniform(\"iNoiseThreshold\", roomEffect.iNoiseThreshold);\n  } else if (effect == RoomEffectConstants::EFFECT_NONE) {\n    states.shader = nullptr;\n  }\n\n  // render the room to a texture, this allows to create a post process effect: room effect\n  ngf::RenderTexture roomTexture(target.getSize());\n  auto screenSize = m_pImpl->m_pRoom->getScreenSize();\n  ngf::View view(ngf::frect::fromPositionSize({0, 0}, screenSize));\n  roomTexture.setView(view);\n  roomTexture.clear();\n  m_pImpl->m_pRoom->draw(roomTexture, m_pImpl->m_camera.getRect().getTopLeft());\n  roomTexture.display();\n\n  // then render a sprite with this texture and apply the room effect\n  ngf::RenderTexture roomWithEffectTexture(target.getSize());\n  roomWithEffectTexture.clear();\n  ngf::Sprite sprite(roomTexture.getTexture());\n  sprite.draw(roomWithEffectTexture, states);\n\n  // and render overlay\n  ngf::RectangleShape fadeShape;\n  fadeShape.setSize(roomWithEffectTexture.getSize());\n  fadeShape.setColor(m_pImpl->m_pRoom->getOverlayColor());\n  fadeShape.draw(roomWithEffectTexture, {});\n  roomWithEffectTexture.display();\n\n  // render fade\n  ngf::Sprite fadeSprite;\n  float fade = m_pImpl->m_fadeEffect.effect == FadeEffect::None ? 0.f :\n               std::clamp(\n                   m_pImpl->m_fadeEffect.elapsed.getTotalSeconds() / m_pImpl->m_fadeEffect.duration.getTotalSeconds(),\n                   0.f, 1.f);\n  ngf::RenderTexture roomTexture2(target.getSize());\n  roomTexture2.setView(view);\n  roomTexture2.clear();\n  if (m_pImpl->m_fadeEffect.effect == FadeEffect::Wobble) {\n    m_pImpl->m_fadeEffect.room->draw(roomTexture2, m_pImpl->m_fadeEffect.cameraTopLeft);\n  }\n  roomTexture2.display();\n\n  ngf::RenderTexture roomTexture3(target.getSize());\n  ngf::Sprite sprite2(roomTexture2.getTexture());\n  sprite2.draw(roomTexture3, {});\n  roomTexture3.display();\n\n  const ngf::Texture *texture1{nullptr};\n  const ngf::Texture *texture2{nullptr};\n  switch (m_pImpl->m_fadeEffect.effect) {\n  case FadeEffect::Wobble:\n  case FadeEffect::In:texture1 = &roomTexture3.getTexture();\n    texture2 = &roomWithEffectTexture.getTexture();\n    break;\n  case FadeEffect::Out:texture1 = &roomWithEffectTexture.getTexture();\n    texture2 = &roomTexture3.getTexture();\n    break;\n  default:texture1 = &roomWithEffectTexture.getTexture();\n    texture2 = &roomWithEffectTexture.getTexture();\n    break;\n  }\n  fadeSprite.setTexture(*texture1);\n  m_pImpl->m_fadeShader.setUniform(\"u_texture2\", *texture2);\n  m_pImpl->m_fadeShader.setUniform(\"u_fade\", fade); // fade value between [0.f,1.f]\n  m_pImpl->m_fadeShader.setUniform(\"u_fadeToSep\", m_pImpl->m_fadeEffect.fadeToSepia ? 1 : 0);  // 1 to fade to sepia\n  m_pImpl->m_fadeShader.setUniform(\"u_movement\",\n                                   sinf(M_PI * fade) * m_pImpl->m_fadeEffect.movement); // movement for wobble effect\n  m_pImpl->m_fadeShader.setUniform(\"u_timer\", m_pImpl->m_fadeEffect.elapsed.getTotalSeconds());\n  states.shader = &m_pImpl->m_fadeShader;\n\n  // apply the room rotation\n  auto pos = target.getView().getSize() / 2.f;\n  fadeSprite.getTransform().setOrigin(pos);\n  fadeSprite.getTransform().setPosition(pos);\n  fadeSprite.getTransform().setRotation(m_pImpl->m_pRoom->getRotation());\n  fadeSprite.draw(target, states);\n\n  // if we take a screenshot (for savegame) then stop drawing\n  if (screenshot)\n    return;\n\n  // draw dialogs, hud\n  m_pImpl->m_dialogManager.draw(target, {});\n  m_pImpl->drawHud(target);\n\n  // draw walkboxes, actor texts\n  auto orgView = target.getView();\n  target.setView(view);\n  m_pImpl->drawWalkboxes(target);\n  m_pImpl->drawActorHotspot(target);\n  const auto &objects = m_pImpl->m_pRoom->getObjects();\n  std::for_each(objects.begin(), objects.end(), [this, &target](const auto &pObj) {\n    m_pImpl->drawObjectHotspot(*pObj, target);\n    m_pImpl->drawDebugHotspot(*pObj, target);\n  });\n\n  ngf::RenderStates statesObjects;\n  auto &lightingShader = m_pImpl->m_pRoom->getLightingShader();\n  statesObjects.shader = &lightingShader;\n  lightingShader.setNumberLights(0);\n  lightingShader.setAmbientColor(ngf::Colors::White);\n  std::for_each(objects.begin(), objects.end(), [this, &target, statesObjects](const auto &pObj) {\n    m_pImpl->drawScreenSpace(*pObj, target, statesObjects);\n  });\n\n  m_pImpl->m_talkingState.draw(target, {});\n  m_pImpl->m_pRoom->drawForeground(target, m_pImpl->m_camera.getAt());\n  target.setView(orgView);\n\n  // draw actor icons\n  if ((m_pImpl->m_dialogManager.getState() == DialogManagerState::None)\n      && m_pImpl->m_inputActive) {\n    m_pImpl->m_actorIcons.draw(target, {});\n  }\n\n  // draw options or startscreen if necessary\n  if (m_pImpl->m_state == EngineState::Options) {\n    m_pImpl->m_optionsDialog.draw(target, {});\n  } else if (m_pImpl->m_state == EngineState::StartScreen) {\n    m_pImpl->m_startScreenDialog.draw(target, {});\n  }\n\n  // draw pause, cursor and no override icon\n  m_pImpl->drawPause(target);\n  m_pImpl->drawCursor(target);\n  m_pImpl->drawCursorText(target);\n  m_pImpl->drawNoOverride(target);\n}\n\nvoid Engine::setWalkboxesFlags(WalkboxesFlags show) { m_pImpl->m_showDrawWalkboxes = show; }\n\nWalkboxesFlags Engine::getWalkboxesFlags() const { return m_pImpl->m_showDrawWalkboxes; }\n\nvoid Engine::startDialog(const std::string &dialog, const std::string &node) {\n  std::string actor;\n  if (m_pImpl->m_pCurrentActor)\n    actor = m_pImpl->m_pCurrentActor->getKey();\n  m_pImpl->m_dialogManager.start(actor, dialog, node);\n}\n\nvoid Engine::execute(const std::string &code) { m_pImpl->m_pScriptExecute->execute(code); }\n\nSoundDefinition *Engine::getSoundDefinition(const std::string &name) {\n  return m_pImpl->m_pScriptExecute->getSoundDefinition(name);\n}\n\nbool Engine::executeCondition(const std::string &code) { return m_pImpl->m_pScriptExecute->executeCondition(code); }\n\nstd::string Engine::executeDollar(const std::string &code) { return m_pImpl->m_pScriptExecute->executeDollar(code); }\n\nvoid Engine::addSelectableActor(int index, Actor *pActor) {\n  m_pImpl->m_actorsIconSlots.at(index - 1).selectable = true;\n  m_pImpl->m_actorsIconSlots.at(index - 1).pActor = pActor;\n}\n\nvoid Engine::actorSlotSelectable(Actor *pActor, bool selectable) {\n  auto it = std::find_if(m_pImpl->m_actorsIconSlots.begin(), m_pImpl->m_actorsIconSlots.end(),\n                         [&pActor](auto &selectableActor) -> bool { return selectableActor.pActor == pActor; });\n  if (it != m_pImpl->m_actorsIconSlots.end()) {\n    it->selectable = selectable;\n  }\n}\n\nvoid Engine::actorSlotSelectable(int index, bool selectable) {\n  m_pImpl->m_actorsIconSlots.at(index - 1).selectable = selectable;\n}\n\nbool Engine::isActorSelectable(Actor *pActor) const {\n  for (auto &&slot : m_pImpl->m_actorsIconSlots) {\n    if (slot.pActor == pActor)\n      return slot.selectable;\n  }\n  return false;\n}\n\nActorSlotSelectableMode Engine::getActorSlotSelectable() const { return m_pImpl->m_actorIcons.getMode(); }\n\nvoid Engine::setActorSlotSelectable(ActorSlotSelectableMode mode) { m_pImpl->m_actorIcons.setMode(mode); }\n\nvoid Engine::setUseFlag(UseFlag flag, Entity *object) {\n  m_pImpl->m_useFlag = flag;\n  m_pImpl->m_pUseObject = object;\n}\n\nvoid Engine::cutsceneOverride() {\n  if (!m_pImpl->m_pCutscene)\n    return;\n  m_pImpl->m_pCutscene->cutsceneOverride();\n}\n\nvoid Engine::cutscene(std::unique_ptr<Cutscene> function) {\n  m_pImpl->m_pCutscene = function.get();\n  addThread(std::move(function));\n}\n\nCutscene *Engine::getCutscene() const { return m_pImpl->m_pCutscene; }\n\nbool Engine::inCutscene() const { return m_pImpl->m_pCutscene && !m_pImpl->m_pCutscene->isElapsed(); }\n\nHSQOBJECT &Engine::getDefaultObject() { return m_pImpl->m_pDefaultObject; }\n\nvoid Engine::flashSelectableActor(bool on) { m_pImpl->m_actorIcons.flash(on); }\n\nconst Verb *Engine::getActiveVerb() const { return m_pImpl->m_hud.getCurrentVerb(); }\n\nvoid Engine::fadeTo(FadeEffect effect, const ngf::TimeSpan &duration) {\n  m_pImpl->m_fadeEffect.effect = effect;\n  m_pImpl->m_fadeEffect.room = getRoom();\n  m_pImpl->m_fadeEffect.cameraTopLeft = m_pImpl->m_camera.getRect().getTopLeft();\n  m_pImpl->m_fadeEffect.duration = duration;\n  m_pImpl->m_fadeEffect.movement = effect == FadeEffect::Wobble ? 0.005f : 0.f;\n  m_pImpl->m_fadeEffect.elapsed = ngf::TimeSpan::seconds(0);\n}\n\nFadeEffectParameters &Engine::getFadeParameters() {\n  return m_pImpl->m_fadeEffect;\n}\n\nvoid Engine::pushSentence(int id, Entity *pObj1, Entity *pObj2) {\n  const Verb *pVerb = m_pImpl->m_hud.getVerb(id);\n  if (!pVerb)\n    return;\n  m_pImpl->m_pVerbExecute->execute(pVerb, pObj1, pObj2);\n}\n\nvoid Engine::setSentence(std::unique_ptr<Sentence> sentence) {\n  m_pImpl->m_pSentence = std::move(sentence);\n}\n\nvoid Engine::stopSentence() {\n  if (!m_pImpl->m_pSentence)\n    return;\n  m_pImpl->m_pSentence->stop();\n  m_pImpl->m_pSentence.reset();\n}\n\nvoid Engine::keyDown(const Input &key) {\n  m_pImpl->m_newKeyDowns.insert(key);\n}\n\nvoid Engine::keyUp(const Input &key) {\n  auto it = m_pImpl->m_newKeyDowns.find(key);\n  if (it == m_pImpl->m_newKeyDowns.end())\n    return;\n  m_pImpl->m_newKeyDowns.erase(it);\n}\n\nvoid Engine::sayLineAt(glm::ivec2 pos, ngf::Color color, ngf::TimeSpan duration, const std::string &text) {\n  m_pImpl->m_talkingState.setTalkColor(color);\n  auto size = getRoom()->getRoomSize();\n  m_pImpl->m_talkingState.setPosition(toDefaultView(pos, size));\n  m_pImpl->m_talkingState.setText(getText(text));\n  m_pImpl->m_talkingState.setDuration(duration);\n}\n\nvoid Engine::sayLineAt(glm::ivec2 pos, Entity &entity, const std::string &text) {\n  auto size = getRoom()->getRoomSize();\n  m_pImpl->m_talkingState.setPosition(toDefaultView(pos, size));\n  m_pImpl->m_talkingState.loadLip(text, &entity);\n}\n\nvoid Engine::showOptions(bool visible) {\n  m_pImpl->m_state = visible ? EngineState::Options : EngineState::Game;\n}\n\nvoid Engine::quit() {\n  m_pImpl->m_pApp->quit();\n  m_pImpl->m_state = EngineState::Quit;\n}\n\nvoid Engine::run() {\n  std::ifstream is(\"engge.nut\");\n  if (is.is_open()) {\n    info(\"execute engge.nut\");\n    m_pImpl->m_state = EngineState::Game;\n    ScriptEngine::executeScript(\"engge.nut\");\n    return;\n  }\n\n  ng::info(\"execute boot script\");\n  ScriptEngine::executeNutScript(\"Defines.nut\");\n  ScriptEngine::executeNutScript(\"Boot.nut\");\n  execute(\"cameraInRoom(StartScreen)\");\n}\n\nInventory &Engine::getInventory() { return m_pImpl->m_hud.getInventory(); }\nHud &Engine::getHud() { return m_pImpl->m_hud; }\n\nvoid Engine::saveGame(int slot) {\n  Impl::SaveGameSystem saveGameSystem(m_pImpl.get());\n  auto path = Impl::SaveGameSystem::getSlotPath(slot);\n  std::filesystem::path screenshotPath(path);\n  screenshotPath.replace_extension(\".png\");\n  m_pImpl->captureScreen(screenshotPath.string());\n  saveGameSystem.saveGame(path);\n}\n\nvoid Engine::loadGame(int slot) {\n  Impl::SaveGameSystem saveGameSystem(m_pImpl.get());\n  saveGameSystem.loadGame(Impl::SaveGameSystem::getSlotPath(slot).string());\n}\n\nvoid Engine::setAutoSave(bool autoSave) { m_pImpl->m_autoSave = autoSave; }\n\nbool Engine::getAutoSave() const { return m_pImpl->m_autoSave; }\n\nvoid Engine::allowSaveGames(bool allow) {\n  m_pImpl->m_optionsDialog.setSaveEnabled(allow);\n}\n\nEntity *Engine::getEntity(const std::string &name) {\n  if (name == \"agent\" || name == \"player\")\n    return m_pImpl->m_pCurrentActor;\n\n  Entity *pEntity = nullptr;\n  ScriptEngine::get(name.data(), pEntity);\n  return pEntity;\n}\n\nvoid Engine::getSlotSavegames(std::vector<SavegameSlot> &slots) {\n  for (int i = 1; i <= 9; ++i) {\n    auto path = Impl::SaveGameSystem::getSlotPath(i);\n\n    SavegameSlot slot;\n    slot.slot = i;\n    slot.path = path;\n\n    if (std::filesystem::exists(path)) {\n      Impl::SaveGameSystem::getSlot(slot);\n    }\n    slots.push_back(slot);\n  }\n}\n\nvoid Engine::stopTalking() const {\n  m_pImpl->stopTalking();\n}\n\nvoid Engine::stopTalkingExcept(Entity *pEntity) const {\n  m_pImpl->stopTalkingExcept(pEntity);\n}\n\nstd::wstring SavegameSlot::getSaveTimeString() const {\n  tm *ltm = localtime(&savetime);\n  wchar_t buffer[120];\n  // time format: \"%b %d at %H:%M\"\n  auto format = Locator<TextDatabase>::get().getText(99944);\n  wcsftime(buffer, 120, format.data(), ltm);\n  return buffer;\n}\n\nstd::wstring SavegameSlot::getGameTimeString() const {\n  wchar_t buffer[120];\n  auto min = static_cast<int>(gametime.getTotalSeconds() / 60.0);\n  if (min < 2) {\n    // \"%d minute\"\n    auto format = Locator<TextDatabase>::get().getText(99945);\n    swprintf(buffer, 120, format.data(), min);\n  } else if (min < 60) {\n    // \"%d minutes\"\n    auto format = Locator<TextDatabase>::get().getText(99946);\n    swprintf(buffer, 120, format.data(), min);\n  } else {\n    int format;\n    int hour = min / 60;\n    min = min % 60;\n    if (hour < 2 && min < 2) {\n      // \"%d hour %d minute\"\n      format = 99947;\n    } else if (hour < 2 && min >= 2) {\n      // \"%d hour %d minutes\";\n      format = 99948;\n    } else if (hour >= 2 && min < 2) {\n      // \"%d hours %d minute\";\n      format = 99949;\n    } else {\n      // \"%d hours %d minutes\";\n      format = 99950;\n    }\n    swprintf(buffer, 120, Locator<TextDatabase>::get().getText(format).data(), hour, min);\n  }\n\n  std::wstring s(buffer);\n  return s;\n}\n} // namespace ng\n"
  },
  {
    "path": "src/Engine/EngineImpl.cpp",
    "content": "#include \"EngineImpl.hpp\"\n#include <engge/EnggeApplication.hpp>\n#include <engge/Graphics/Text.hpp>\n#include <engge/Graphics/AnimDrawable.hpp>\n#include \"../Graphics/PathDrawable.hpp\"\n\nnamespace ng {\nngf::Color toColor(const ObjectType &type) {\n  ngf::Color color;\n  switch (type) {\n  case ObjectType::Object:color = ngf::Colors::Red;\n    break;\n  case ObjectType::Spot:color = ngf::Colors::Green;\n    break;\n  case ObjectType::Trigger:color = ngf::Colors::Magenta;\n    break;\n  case ObjectType::Prop:color = ngf::Colors::Blue;\n    break;\n  }\n  return color;\n}\n\nCursorDirection operator|=(CursorDirection &lhs, CursorDirection rhs) {\n  lhs = static_cast<CursorDirection>(static_cast<std::underlying_type<CursorDirection>::type>(lhs) |\n      static_cast<std::underlying_type<CursorDirection>::type>(rhs));\n  return lhs;\n}\n\nbool operator&(CursorDirection lhs, CursorDirection rhs) {\n  return static_cast<CursorDirection>(static_cast<std::underlying_type<CursorDirection>::type>(lhs) &\n      static_cast<std::underlying_type<CursorDirection>::type>(rhs)) >\n      CursorDirection::None;\n}\n\nEngine::Impl::Impl()\n    : m_resourceManager(Locator<ResourceManager>::get()),\n      m_preferences(Locator<Preferences>::get()),\n      m_soundManager(Locator<SoundManager>::get()),\n      m_actorIcons(m_actorsIconSlots, m_hud, m_pCurrentActor) {\n  m_hud.setTextureManager(&m_resourceManager);\n  sq_resetobject(&m_pDefaultObject);\n\n  Locator<CommandManager>::get().registerCommands(\n      {\n          {EngineCommands::SkipText, [this]() { skipText(); }},\n          {EngineCommands::SkipCutscene, [this] { skipCutscene(); }},\n          {EngineCommands::PauseGame, [this] { pauseGame(); }},\n          {EngineCommands::SelectActor1, [this] { selectActor(1); }},\n          {EngineCommands::SelectActor2, [this] { selectActor(2); }},\n          {EngineCommands::SelectActor3, [this] { selectActor(3); }},\n          {EngineCommands::SelectActor4, [this] { selectActor(4); }},\n          {EngineCommands::SelectActor5, [this] { selectActor(5); }},\n          {EngineCommands::SelectActor6, [this] { selectActor(6); }},\n          {EngineCommands::SelectPreviousActor, [this] { selectPreviousActor(); }},\n          {EngineCommands::SelectNextActor, [this] { selectNextActor(); }},\n          {EngineCommands::SelectChoice1, [this] { m_dialogManager.choose(1); }},\n          {EngineCommands::SelectChoice2, [this] { m_dialogManager.choose(2); }},\n          {EngineCommands::SelectChoice3, [this] { m_dialogManager.choose(3); }},\n          {EngineCommands::SelectChoice4, [this] { m_dialogManager.choose(4); }},\n          {EngineCommands::SelectChoice5, [this] { m_dialogManager.choose(5); }},\n          {EngineCommands::SelectChoice6, [this] { m_dialogManager.choose(6); }},\n          {EngineCommands::ShowOptions, [this] { m_pEngine->showOptions(true); }},\n          {EngineCommands::ToggleHud, [this] {\n            m_hud.setVisible(!m_cursorVisible);\n            m_actorIcons.setVisible(!m_cursorVisible);\n            m_cursorVisible = !m_cursorVisible;\n          }}\n      });\n  Locator<CommandManager>::get().registerPressedCommand(EngineCommands::ShowHotspots, [this](bool down) {\n    m_preferences.setTempPreference(TempPreferenceNames::ShowHotspot, down);\n  });\n\n  m_fadeShader.load(Shaders::vertexShader, Shaders::fadeFragmentShader);\n  uint32_t pixels[4]{0x000000FF, 0x000000FF, 0x000000FF, 0x000000FF};\n  m_blackTexture.loadFromMemory({2, 2}, pixels);\n}\n\nvoid Engine::Impl::pauseGame() {\n  m_state = m_state == EngineState::Game ? EngineState::Paused : EngineState::Game;\n  if (m_state == EngineState::Paused) {\n    // pause all pauseable threads\n    for (auto &thread : m_threads) {\n      if (thread->isPauseable() && !thread->isStopped()) {\n        thread->pause();\n      }\n    }\n    m_soundManager.pauseAllSounds();\n  } else {\n    // resume all pauseable threads\n    for (auto &thread : m_threads) {\n      if (thread->isPauseable() && !thread->isStopped()) {\n        thread->resume();\n      }\n    }\n    m_soundManager.resumeAllSounds();\n  }\n}\n\nvoid Engine::Impl::selectActor(int index) {\n  if (index <= 0 || index > static_cast<int>(m_actorsIconSlots.size()))\n    return;\n  const auto &slot = m_actorsIconSlots[index - 1];\n  if (!slot.selectable)\n    return;\n  m_pEngine->setCurrentActor(slot.pActor, true);\n}\n\nvoid Engine::Impl::selectPreviousActor() {\n  auto currentActorIndex = getCurrentActorIndex();\n  if (currentActorIndex == -1)\n    return;\n  auto size = static_cast<int>(m_actorsIconSlots.size());\n  for (auto i = 0; i < size; i++) {\n    auto index = currentActorIndex - i - 1;\n    if (index < 0)\n      index += size - 1;\n    if (index == currentActorIndex)\n      return;\n    const auto &slot = m_actorsIconSlots[index];\n    if (slot.selectable) {\n      m_pEngine->setCurrentActor(slot.pActor, true);\n      return;\n    }\n  }\n}\n\nvoid Engine::Impl::selectNextActor() {\n  auto currentActorIndex = getCurrentActorIndex();\n  if (currentActorIndex == -1)\n    return;\n  auto size = static_cast<int>(m_actorsIconSlots.size());\n  for (auto i = 0; i < size; i++) {\n    auto index = (currentActorIndex + i + 1) % size;\n    if (index == currentActorIndex)\n      return;\n    const auto &slot = m_actorsIconSlots[index];\n    if (slot.selectable) {\n      m_pEngine->setCurrentActor(slot.pActor, true);\n      return;\n    }\n  }\n}\n\nvoid Engine::Impl::skipCutscene() {\n  if (m_pEngine->inCutscene()) {\n    if (m_pCutscene && m_pCutscene->hasCutsceneOverride()) {\n      m_pEngine->cutsceneOverride();\n    } else {\n      m_noOverrideElapsed = ngf::TimeSpan::seconds(0);\n    }\n  }\n}\n\nvoid Engine::Impl::skipText() const {\n  if (m_dialogManager.getState() == DialogManagerState::Active) {\n    stopTalking();\n  }\n}\n\nvoid Engine::Impl::onLanguageChange(const std::string &lang) {\n  std::stringstream ss;\n  ss << \"ThimbleweedText_\" << lang << \".tsv\";\n  Locator<TextDatabase>::get().load(ss.str());\n\n  ScriptEngine::call(\"onLanguageChange\");\n}\n\nSQInteger Engine::Impl::exitRoom(Object *pObject) {\n  m_pEngine->setDefaultVerb();\n  m_talkingState.stop();\n\n  if (!m_pRoom)\n    return 0;\n\n  auto pOldRoom = m_pRoom;\n\n  actorExit();\n\n  // call exit room function\n  auto nparams = ScriptEngine::getParameterCount(pOldRoom, \"exit\");\n  trace(\"call exit room function of {} ({} params)\", pOldRoom->getName(), nparams);\n\n  if (nparams == 2) {\n    auto pRoom = pObject ? pObject->getRoom() : nullptr;\n    ScriptEngine::rawCall(pOldRoom, \"exit\", pRoom);\n  } else {\n    ScriptEngine::rawCall(pOldRoom, \"exit\");\n  }\n\n  pOldRoom->exit();\n\n  ScriptEngine::rawCall(\"exitedRoom\", pOldRoom);\n\n  // stop all local threads\n  std::for_each(m_threads.begin(), m_threads.end(), [](auto &pThread) {\n    if (!pThread->isGlobal())\n      pThread->stop();\n  });\n\n  return 0;\n}\n\nvoid Engine::Impl::actorEnter() const {\n  if (!m_pCurrentActor)\n    return;\n\n  m_pCurrentActor->stopWalking();\n  ScriptEngine::rawCall(\"actorEnter\", m_pCurrentActor);\n\n  if (!m_pRoom)\n    return;\n\n  if (ScriptEngine::rawExists(m_pRoom, \"actorEnter\")) {\n    ScriptEngine::rawCall(m_pRoom, \"actorEnter\", m_pCurrentActor);\n  }\n}\n\nvoid Engine::Impl::actorExit() const {\n  if (!m_pCurrentActor || !m_pRoom)\n    return;\n\n  if (ScriptEngine::rawExists(m_pRoom, \"actorExit\")) {\n    ScriptEngine::rawCall(m_pRoom, \"actorExit\", m_pCurrentActor);\n  }\n}\n\nSQInteger Engine::Impl::enterRoom(Room *pRoom, Object *pObject) const {\n  // call enter room function\n  trace(\"call enter room function of {}\", pRoom->getName());\n  auto nparams = ScriptEngine::getParameterCount(pRoom, \"enter\");\n  if (nparams == 2) {\n    ScriptEngine::rawCall(pRoom, \"enter\", pObject);\n  } else {\n    ScriptEngine::rawCall(pRoom, \"enter\");\n  }\n\n  actorEnter();\n\n  auto lang = Locator<Preferences>::get().getUserPreference<std::string>(PreferenceNames::Language,\n                                                                         PreferenceDefaultValues::Language);\n  const auto &spriteSheet = pRoom->getSpriteSheet();\n  auto &objects = pRoom->getObjects();\n  for (auto &obj : objects) {\n    for (auto &anim : obj->getAnims()) {\n      for (size_t i = 0; i < anim.frames.size(); ++i) {\n        auto &frame = anim.frames.at(i);\n        auto name = frame.name;\n        if (!endsWith(name, \"_en\"))\n          continue;\n\n        checkLanguage(name);\n        anim.frames[i] = spriteSheet.getItem(name);\n      }\n    }\n    if (obj->getId() == 0 || obj->isTemporary())\n      continue;\n\n    if (ScriptEngine::rawExists(obj.get(), \"enter\")) {\n      ScriptEngine::rawCall(obj.get(), \"enter\");\n    }\n  }\n\n  ScriptEngine::rawCall(\"enteredRoom\", pRoom);\n\n  return 0;\n}\n\nvoid Engine::Impl::run(bool state) {\n  if (m_run != state) {\n    m_run = state;\n    if (m_pCurrentActor) {\n      ScriptEngine::objCall(m_pCurrentActor, \"run\", state);\n    }\n  }\n}\n\nvoid Engine::Impl::setCurrentRoom(Room *pRoom) {\n  // reset fade effect if we change the room except for wobble effect\n  if (m_fadeEffect.effect != FadeEffect::Wobble) {\n    m_fadeEffect.effect = FadeEffect::None;\n  }\n\n  if (pRoom) {\n    ScriptEngine::set(\"currentRoom\", pRoom);\n  }\n  m_camera.resetBounds();\n  m_pRoom = pRoom;\n  m_camera.at(glm::vec2(0, 0));\n}\n\nvoid Engine::Impl::updateCutscene(const ngf::TimeSpan &elapsed) {\n  if (m_pCutscene) {\n    (*m_pCutscene)(elapsed);\n    if (m_pCutscene->isElapsed()) {\n      m_pCutscene = nullptr;\n    }\n  }\n}\n\nvoid Engine::Impl::updateSentence(const ngf::TimeSpan &elapsed) const {\n  if (!m_pSentence)\n    return;\n  (*m_pSentence)(elapsed);\n  if (!m_pSentence->isElapsed())\n    return;\n  m_pEngine->stopSentence();\n}\n\nvoid Engine::Impl::updateFunctions(const ngf::TimeSpan &elapsed) {\n  for (auto &function : m_newFunctions) {\n    m_functions.push_back(std::move(function));\n  }\n  m_newFunctions.clear();\n  for (auto &function : m_functions) {\n    (*function)(elapsed);\n  }\n  m_functions.erase(std::remove_if(m_functions.begin(), m_functions.end(),\n                                   [](std::unique_ptr<Function> &f) { return f->isElapsed(); }),\n                    m_functions.end());\n\n  std::vector<std::unique_ptr<Callback>> callbacks;\n  std::move(m_callbacks.begin(), m_callbacks.end(), std::back_inserter(callbacks));\n  m_callbacks.clear();\n  for (auto &callback : callbacks) {\n    (*callback)(elapsed);\n  }\n  callbacks.erase(std::remove_if(callbacks.begin(),\n                                 callbacks.end(),\n                                 [](auto &f) { return f->isElapsed(); }),\n                  callbacks.end());\n  std::move(callbacks.begin(), callbacks.end(), std::back_inserter(m_callbacks));\n}\n\nvoid Engine::Impl::updateActorIcons(const ngf::TimeSpan &elapsed) {\n  auto screenSize = m_pRoom->getScreenSize();\n  auto screenMouse = toDefaultView((glm::ivec2) m_mousePos, screenSize);\n  m_actorIcons.setMousePosition(screenMouse);\n  m_actorIcons.update(elapsed);\n}\n\nvoid Engine::Impl::updateMouseCursor() {\n  auto flags = getFlags(m_objId1);\n  auto screen = m_pApp->getRenderTarget()->getView().getSize();\n  m_cursorDirection = CursorDirection::None;\n  if ((m_mousePos.x < 20) || (flags & ObjectFlagConstants::DOOR_LEFT) == ObjectFlagConstants::DOOR_LEFT)\n    m_cursorDirection |= CursorDirection::Left;\n  else if ((m_mousePos.x > screen.x - 20) ||\n      (flags & ObjectFlagConstants::DOOR_RIGHT) == ObjectFlagConstants::DOOR_RIGHT)\n    m_cursorDirection |= CursorDirection::Right;\n  if ((flags & ObjectFlagConstants::DOOR_FRONT) == ObjectFlagConstants::DOOR_FRONT)\n    m_cursorDirection |= CursorDirection::Down;\n  else if ((flags & ObjectFlagConstants::DOOR_BACK) == ObjectFlagConstants::DOOR_BACK)\n    m_cursorDirection |= CursorDirection::Up;\n  if ((m_cursorDirection == CursorDirection::None) && m_objId1)\n    m_cursorDirection |= CursorDirection::Hotspot;\n}\n\nEntity *Engine::Impl::getHoveredEntity(const glm::vec2 &mousPos) {\n  Entity *pCurrentObject = nullptr;\n\n  // mouse on actor ?\n  for (auto &&actor : m_actors) {\n    if (actor.get() == m_pCurrentActor)\n      continue;\n    if (actor->getRoom() != m_pRoom)\n      continue;\n\n    if (actor->contains(mousPos)) {\n      if (!pCurrentObject || actor->getZOrder() < pCurrentObject->getZOrder()) {\n        pCurrentObject = actor.get();\n      }\n    }\n  }\n\n  // mouse on object ?\n  const auto &objects = m_pRoom->getObjects();\n  std::for_each(objects.cbegin(), objects.cend(), [mousPos, &pCurrentObject](const auto &pObj) {\n    if (!pObj->isTouchable())\n      return;\n    auto rect = pObj->getRealHotspot();\n    if (!rect.contains((glm::ivec2) mousPos))\n      return;\n    if (!pCurrentObject || pObj->getZOrder() <= pCurrentObject->getZOrder())\n      pCurrentObject = pObj.get();\n  });\n\n  if (!pCurrentObject && m_pRoom && m_pRoom->getFullscreen() != 1) {\n    // mouse on inventory object ?\n    pCurrentObject = m_hud.getInventory().getCurrentInventoryObject();\n  }\n\n  return pCurrentObject;\n}\n\nvoid Engine::Impl::updateHoveredEntity(bool isRightClick) {\n  m_hud.setVerbOverride(nullptr);\n  if (!m_hud.getCurrentVerb()) {\n    m_hud.setCurrentVerb(m_hud.getVerb(VerbConstants::VERB_WALKTO));\n  }\n\n  if (m_pUseObject) {\n    m_objId1 = m_pUseObject ? m_pUseObject->getId() : 0;\n    m_pObj2 = m_hud.getHoveredEntity();\n  } else {\n    m_objId1 = m_hud.getHoveredEntity() ? m_hud.getHoveredEntity()->getId() : 0;\n    m_pObj2 = nullptr;\n  }\n\n  // abort some invalid actions\n  if (!m_objId1 || !m_hud.getCurrentVerb()) {\n    return;\n  }\n\n  if (m_pObj2 && m_pObj2->getId() == m_objId1) {\n    m_pObj2 = nullptr;\n  }\n\n  if (m_objId1 && isRightClick) {\n    m_hud.setVerbOverride(m_hud.getVerb(EntityManager::getScriptObjectFromId<Entity>(m_objId1)->getDefaultVerb(\n        VerbConstants::VERB_LOOKAT)));\n  }\n\n  auto verbId = m_hud.getCurrentVerb()->id;\n  switch (verbId) {\n  case VerbConstants::VERB_WALKTO: {\n    auto pObj1 = EntityManager::getScriptObjectFromId<Entity>(m_objId1);\n    if (pObj1 && pObj1->isInventoryObject()) {\n      m_hud.setVerbOverride(m_hud.getVerb(EntityManager::getScriptObjectFromId<Entity>(m_objId1)->getDefaultVerb(\n          VerbConstants::VERB_LOOKAT)));\n    }\n    break;\n  }\n  case VerbConstants::VERB_TALKTO:\n    // select actor/object only if talkable flag is set\n    if (!hasFlag(m_objId1, ObjectFlagConstants::TALKABLE)) {\n      m_objId1 = 0;\n    }\n    break;\n  case VerbConstants::VERB_GIVE: {\n    auto pObj1 = EntityManager::getScriptObjectFromId<Entity>(m_objId1);\n    if (!pObj1->isInventoryObject())\n      m_objId1 = 0;\n\n    // select actor/object only if giveable flag is set\n    if (m_pObj2 && !hasFlag(m_pObj2->getId(), ObjectFlagConstants::GIVEABLE))\n      m_pObj2 = nullptr;\n    break;\n  }\n  default: {\n    auto pActor = EntityManager::getScriptObjectFromId<Actor>(m_objId1);\n    if (pActor) {\n      m_objId1 = 0;\n    }\n    break;\n  }\n  }\n}\n\nEntity *Engine::Impl::getEntity(Entity *pEntity) const {\n  if (!pEntity)\n    return nullptr;\n\n  // if an actor has the same name then get its flags\n  auto itActor = std::find_if(m_actors.begin(), m_actors.end(), [pEntity](const auto &pActor) -> bool {\n    return pActor->getName() == pEntity->getName();\n  });\n  if (itActor != m_actors.end()) {\n    return itActor->get();\n  }\n  return pEntity;\n}\n\nbool Engine::Impl::hasFlag(int id, uint32_t flagToTest) const {\n  auto pObj = EntityManager::getScriptObjectFromId<Entity>(id);\n  auto flags = getFlags(pObj);\n  if (flags & flagToTest)\n    return true;\n  auto pActor = getEntity(pObj);\n  flags = getFlags(pActor);\n  return flags & flagToTest;\n}\n\nuint32_t Engine::Impl::getFlags(int id) const {\n  auto pEntity = EntityManager::getScriptObjectFromId<Entity>(id);\n  return getFlags(pEntity);\n}\n\nuint32_t Engine::Impl::getFlags(Entity *pEntity) const {\n  if (pEntity)\n    return pEntity->getFlags();\n  return 0;\n}\n\nvoid Engine::Impl::updateRoomScalings() const {\n  auto actor = m_pCurrentActor;\n  if (!actor)\n    return;\n\n  auto &scalings = m_pRoom->getScalings();\n  auto &objects = m_pRoom->getObjects();\n  for (auto &&object : objects) {\n    if (object->getType() != ObjectType::Trigger)\n      continue;\n    if (object->getRealHotspot().contains((glm::ivec2) actor->getPosition())) {\n      auto it = std::find_if(scalings.begin(), scalings.end(), [&object](const auto &s) -> bool {\n        return s.getName() == object->getName();\n      });\n      if (it != scalings.end()) {\n        m_pRoom->setRoomScaling(*it);\n        return;\n      }\n    }\n  }\n  if (!scalings.empty()) {\n    m_pRoom->setRoomScaling(scalings[0]);\n  }\n}\n\nconst Verb *Engine::Impl::getHoveredVerb() const {\n  if (!m_hud.getActive())\n    return nullptr;\n  if (m_pRoom && m_pRoom->getFullscreen() == 1)\n    return nullptr;\n\n  return m_hud.getHoveredVerb();\n}\n\nvoid Engine::Impl::stopTalking() const {\n  for (auto &&a : m_pEngine->getActors()) {\n    a->stopTalking();\n  }\n  for (auto &&a : m_pEngine->getRoom()->getObjects()) {\n    a->stopTalking();\n  }\n}\n\nvoid Engine::Impl::stopTalkingExcept(Entity *pEntity) const {\n  for (auto &&a : m_pEngine->getActors()) {\n    if (a.get() == pEntity)\n      continue;\n    a->stopTalking();\n  }\n\n  for (auto &&a : m_pEngine->getRoom()->getObjects()) {\n    if (a.get() == pEntity)\n      continue;\n    a->stopTalking();\n  }\n}\n\nvoid Engine::Impl::updateKeys() {\n  ImGuiIO &io = ImGui::GetIO();\n  if (io.WantTextInput)\n    return;\n\n  const auto &cmdMgr = Locator<CommandManager>::get();\n  for (auto &key : m_oldKeyDowns) {\n    if (isKeyPressed(key)) {\n      cmdMgr.execute(key);\n      cmdMgr.execute(key, false);\n    }\n  }\n\n  for (auto &key : m_newKeyDowns) {\n    if (m_oldKeyDowns.find(key) != m_oldKeyDowns.end()) {\n      cmdMgr.execute(key, true);\n    }\n  }\n\n  m_oldKeyDowns.clear();\n  for (auto key : m_newKeyDowns) {\n    m_oldKeyDowns.insert(key);\n  }\n}\n\nbool Engine::Impl::isKeyPressed(const Input &key) {\n  auto wasDown = m_oldKeyDowns.find(key) != m_oldKeyDowns.end();\n  auto isDown = m_newKeyDowns.find(key) != m_newKeyDowns.end();\n  return wasDown && !isDown;\n}\n\nInputConstants Engine::Impl::toKey(const std::string &keyText) {\n  if (keyText.length() == 1) {\n    return static_cast<InputConstants>(keyText[0]);\n  }\n  return InputConstants::NONE;\n}\n\nvoid Engine::Impl::updateKeyboard() {\n  if (m_oldKeyDowns.empty())\n    return;\n\n  if (m_pRoom) {\n    for (auto key : m_oldKeyDowns) {\n      if (isKeyPressed(key) && ScriptEngine::rawExists(m_pRoom, \"pressedKey\")) {\n        ScriptEngine::rawCall(m_pRoom, \"pressedKey\", static_cast<int>(key.input));\n      }\n    }\n  }\n\n  int currentActorIndex = getCurrentActorIndex();\n  if (currentActorIndex == -1)\n    return;\n\n  const auto &verbSlot = m_hud.getVerbSlot(currentActorIndex);\n  for (auto i = 0; i < 10; i++) {\n    const auto &verb = verbSlot.getVerb(i);\n    if (verb.key.length() == 0)\n      continue;\n    auto id = std::strtol(verb.key.substr(1, verb.key.length() - 1).c_str(), nullptr, 10);\n    auto key = toKey(tostring(ng::Engine::getText(id)));\n    if (isKeyPressed(key)) {\n      onVerbClick(&verb);\n    }\n  }\n}\n\nvoid Engine::Impl::onVerbClick(const Verb *pVerb) {\n  m_hud.setCurrentVerb(pVerb);\n  m_useFlag = UseFlag::None;\n  m_pUseObject = nullptr;\n  m_objId1 = 0;\n  m_pObj2 = nullptr;\n\n  ScriptEngine::rawCall(\"onVerbClick\");\n}\n\nbool Engine::Impl::clickedAt(const glm::vec2 &pos) const {\n  if (!m_pRoom)\n    return false;\n\n  bool handled = false;\n  if (ScriptEngine::rawExists(m_pRoom, clickedAtCallback)) {\n    ScriptEngine::rawCallFunc(handled, m_pRoom, clickedAtCallback, pos.x, pos.y);\n    if (handled)\n      return true;\n  }\n\n  if (!m_pCurrentActor)\n    return false;\n\n  if (!ScriptEngine::rawExists(m_pCurrentActor, clickedAtCallback))\n    return false;\n\n  ScriptEngine::rawCallFunc(handled, m_pCurrentActor, clickedAtCallback, pos.x, pos.y);\n  return handled;\n}\n\nvoid Engine::Impl::drawActorHotspot(ngf::RenderTarget &target) const {\n  if (!m_pCurrentActor)\n    return;\n\n  if (!m_pCurrentActor->isHotspotVisible())\n    return;\n\n  auto at = m_camera.getRect().getTopLeft();\n  auto rect = m_pCurrentActor->getHotspot();\n  auto pos = m_pCurrentActor->getPosition();\n  pos = {pos.x - at.x, at.y + m_pRoom->getScreenSize().y - pos.y};\n\n  ngf::Transform t;\n  t.setPosition(pos);\n\n  ngf::RenderStates s;\n  s.transform = t.getTransform();\n\n  ngf::RectangleShape shape(rect.getSize());\n  shape.getTransform().setPosition(rect.getTopLeft());\n  shape.setOutlineThickness(1);\n  shape.setOutlineColor(ngf::Colors::Red);\n  shape.setColor(ngf::Colors::Transparent);\n  shape.draw(target, s);\n\n  // draw actor position\n  ngf::RectangleShape rectangle;\n  rectangle.setColor(ngf::Colors::Red);\n  rectangle.setSize(glm::vec2(2, 2));\n  rectangle.getTransform().setOrigin(glm::vec2(1, 1));\n  rectangle.draw(target, s);\n}\n\nglm::vec2 Engine::Impl::roomToScreen(const glm::vec2 &pos) const {\n  auto at = m_camera.getRect().getTopLeft();\n  return toDefaultView((glm::ivec2) (pos - at), m_pRoom->getScreenSize());\n}\n\nngf::irect Engine::Impl::roomToScreen(const ngf::irect &rect) const {\n  auto min = toDefaultView((glm::ivec2) rect.getSize(), m_pRoom->getScreenSize());\n  auto max = toDefaultView((glm::ivec2) rect.max, m_pRoom->getScreenSize());\n  return ngf::irect::fromMinMax(min, max);\n}\n\nvoid Engine::Impl::drawObjectHotspot(const Object &object, ngf::RenderTarget &target) const {\n  if (!object.isTouchable())\n    return;\n\n  const auto showHotspot =\n      Locator<Preferences>::get().getTempPreference(TempPreferenceNames::ShowHotspot,\n                                                    TempPreferenceDefaultValues::ShowHotspot);\n  if (!showHotspot)\n    return;\n\n  auto pos = object.getPosition();\n  pos = roomToScreen(pos);\n  pos = {pos.x, Screen::Height - pos.y};\n\n  ngf::Transform t;\n  t.setPosition(pos);\n\n  ngf::RenderStates s;\n  s.transform = t.getTransform();\n\n  const auto &view = target.getView();\n  target.setView(ngf::View{ngf::frect::fromPositionSize({0, 0}, {Screen::Width, Screen::Height})});\n\n  auto &gameSheet = Locator<ResourceManager>::get().getSpriteSheet(\"GameSheet\");\n  ngf::Sprite sprite(*gameSheet.getTexture(), gameSheet.getRect(\"hotspot_marker\"));\n  sprite.setColor(ngf::Color(255, 165, 0));\n  sprite.getTransform().setOrigin({15.f, 15.f});\n  sprite.draw(target, s);\n\n  target.setView(view);\n}\n\nclass ArrowShape final : public ngf::Drawable {\npublic:\n  ArrowShape(UseDirection dir, const ngf::Color &color) : m_dir(dir), m_color(color) {}\n\n  void draw(ngf::RenderTarget &target, ngf::RenderStates s) const final {\n    const auto headPos = size / 3.f;\n    switch (m_dir) {\n    case UseDirection::Front: {\n      ngf::RectangleShape dirShape({size, 1});\n      dirShape.getTransform().setPosition({-headPos, size - headPos});\n      dirShape.setColor(m_color);\n      dirShape.draw(target, s);\n    }\n      break;\n    case UseDirection::Back: {\n      ngf::RectangleShape dirShape(glm::vec2(size, 1));\n      dirShape.getTransform().setPosition({-headPos, headPos - size});\n      dirShape.setColor(m_color);\n      dirShape.draw(target, s);\n    }\n      break;\n    case UseDirection::Left: {\n      ngf::RectangleShape dirShape(glm::vec2(1, size));\n      dirShape.getTransform().setPosition({headPos - size, -headPos});\n      dirShape.setColor(m_color);\n      dirShape.draw(target, s);\n    }\n      break;\n    case UseDirection::Right: {\n      ngf::RectangleShape dirShape(glm::vec2(1, size));\n      dirShape.getTransform().setPosition({size - headPos, -headPos});\n      dirShape.setColor(m_color);\n      dirShape.draw(target, s);\n    }\n      break;\n    }\n  }\n\nprivate:\n  const float size = 3.f;\n  UseDirection m_dir;\n  ngf::Color m_color;\n};\n\nclass CrossShape final : public ngf::Drawable {\npublic:\n  explicit CrossShape(const ngf::Color &color) : m_color(color) {}\n\n  void draw(ngf::RenderTarget &target, ngf::RenderStates s) const final {\n    ngf::RectangleShape vl(glm::vec2(1, 7));\n    vl.getTransform().setPosition({0, -3});\n    vl.setColor(m_color);\n    vl.draw(target, s);\n\n    ngf::RectangleShape hl(glm::vec2(7, 1));\n    hl.getTransform().setPosition({-3, 0});\n    hl.setColor(m_color);\n    hl.draw(target, s);\n  }\n\nprivate:\n  ngf::Color m_color;\n};\n\nvoid Engine::Impl::drawDebugHotspot(const Object &object, ngf::RenderTarget &target) const {\n  if (!object.isHotspotVisible())\n    return;\n\n  auto pos = object.getPosition();\n  auto at = m_camera.getRect().getTopLeft();\n  pos = {pos.x - at.x, m_pRoom->getScreenSize().y - pos.y + at.y};\n\n  ngf::Transform t;\n  t.setPosition(pos);\n  ngf::RenderStates s;\n  s.transform = t.getTransform();\n\n  // fix hotspot\n  auto rect = object.getHotspot();\n  auto min = rect.min;\n  auto max = rect.max;\n  min.y = -min.y;\n  max.y = -max.y;\n  rect = ngf::irect::fromMinMax(min, max);\n\n  auto color = toColor(object.getType());\n  std::array<ngf::Vertex, 4> hotspotVertices = {\n      ngf::Vertex{rect.getTopLeft(), color},\n      ngf::Vertex{rect.getBottomLeft(), color},\n      ngf::Vertex{rect.getBottomRight(), color},\n      ngf::Vertex{rect.getTopRight(), color}};\n\n  // draw a rectangle\n  target.draw(ngf::PrimitiveType::LineLoop, hotspotVertices, s);\n\n  // draw a cross at the use position\n  auto usePos = object.getUsePosition().value_or(glm::vec2());\n  usePos.y = -usePos.y;\n  t.setPosition(usePos);\n  s.transform = t.getTransform() * s.transform;\n  CrossShape cross(color);\n  cross.draw(target, s);\n\n  // draw direction\n  const auto useDir = object.getUseDirection().value_or(UseDirection::Front);\n  ArrowShape arrow(useDir, color);\n  arrow.draw(target, s);\n}\n\nvoid Engine::Impl::drawScreenSpace(const Object &object, ngf::RenderTarget &target, ngf::RenderStates states) {\n  if (object.getScreenSpace() != ScreenSpace::Object)\n    return;\n\n  const auto *anim = object.getAnimation();\n  if (!anim)\n    return;\n\n  const auto view = target.getView();\n  target.setView(ngf::View(ngf::frect::fromPositionSize({0, 0}, {Screen::Width, Screen::Height})));\n\n  auto t = object.getTransform();\n  auto pos = t.getPosition();\n  ngf::RenderStates s;\n\n  t.setPosition({pos.x, Screen::Height - pos.y});\n  s.transform = t.getTransform();\n  s.shader = states.shader;\n\n  AnimDrawable animDrawable;\n  animDrawable.setAnim(anim);\n  animDrawable.setColor(object.getColor());\n  animDrawable.draw(pos, target, s);\n\n  target.setView(view);\n}\n\nvoid Engine::Impl::drawWalkboxes(ngf::RenderTarget &target) const {\n  if (!m_pRoom || m_showDrawWalkboxes == WalkboxesFlags::None)\n    return;\n\n  auto at = m_camera.getRect().getTopLeft();\n  ngf::Transform t;\n  t.setPosition({-at.x, at.y});\n  ngf::RenderStates states;\n  states.transform = t.getTransform();\n\n  if ((m_showDrawWalkboxes & WalkboxesFlags::Walkboxes) == WalkboxesFlags::Walkboxes) {\n    // draw walkboxes\n    for (const auto &walkbox : m_pRoom->getWalkboxes()) {\n      WalkboxDrawable wd(walkbox, m_pRoom->getScreenSize().y);\n      wd.draw(target, states);\n    }\n  }\n\n  if ((m_showDrawWalkboxes & WalkboxesFlags::Merged) == WalkboxesFlags::Merged) {\n    // draw merged walkboxes\n    for (const auto &walkbox : m_pRoom->getGraphWalkboxes()) {\n      WalkboxDrawable wd(walkbox, m_pRoom->getScreenSize().y);\n      wd.draw(target, states);\n    }\n  }\n\n  if ((m_showDrawWalkboxes & WalkboxesFlags::Graph) == WalkboxesFlags::Graph) {\n    // draw walkbox graph\n    const auto *pGraph = m_pRoom->getGraph();\n    if (pGraph) {\n      auto height = m_pRoom->getRoomSize().y;\n      ng::GraphDrawable d(*pGraph, height);\n      d.draw(target, states);\n    }\n  }\n\n  if (!m_pCurrentActor)\n    return;\n  auto path = m_pCurrentActor->getPath();\n  if (!path)\n    return;\n  path->draw(target, states);\n}\n\nvoid Engine::Impl::drawPause(ngf::RenderTarget &target) const {\n  if (m_state != EngineState::Paused)\n    return;\n\n  const auto view = target.getView();\n  auto viewRect = ngf::frect::fromPositionSize({0, 0}, {320, 176});\n  target.setView(ngf::View(viewRect));\n\n  auto &saveLoadSheet = Locator<ResourceManager>::get().getSpriteSheet(\"SaveLoadSheet\");\n  auto viewCenter = glm::vec2(viewRect.getWidth() / 2, viewRect.getHeight() / 2);\n  auto rect = saveLoadSheet.getRect(\"pause_dialog\");\n\n  ngf::Sprite sprite;\n  sprite.getTransform().setPosition(viewCenter);\n  sprite.setTexture(*saveLoadSheet.getTexture());\n  sprite.getTransform().setOrigin({rect.getWidth() / 2.f, rect.getHeight() / 2.f});\n  sprite.setTextureRect(rect);\n  sprite.draw(target, {});\n\n  viewRect = ngf::frect::fromPositionSize({0, 0}, {Screen::Width, Screen::Height});\n  viewCenter = glm::vec2(viewRect.getWidth() / 2, viewRect.getHeight() / 2);\n  target.setView(ngf::View(viewRect));\n\n  auto retroFonts =\n      m_pEngine->getPreferences().getUserPreference(PreferenceNames::RetroFonts, PreferenceDefaultValues::RetroFonts);\n  auto &font = m_pEngine->getResourceManager().getFont(retroFonts ? \"FontRetroSheet\" : \"FontModernSheet\");\n\n  ng::Text text;\n  auto screen = target.getView().getSize();\n  auto scale = screen.y / 512.f;\n  text.getTransform().setScale({scale, scale});\n  text.getTransform().setPosition(viewCenter);\n  text.setFont(font);\n  text.setColor(ngf::Colors::White);\n  text.setWideString(Engine::getText(99951));\n  auto bounds = getGlobalBounds(text);\n  text.getTransform().move({-bounds.getWidth() / 2.f, -scale * bounds.getHeight() / 2.f});\n  text.draw(target, {});\n\n  target.setView(view);\n}\n\nvoid Engine::Impl::stopThreads() {\n  m_threads.erase(std::remove_if(m_threads.begin(), m_threads.end(), [](const auto &t) -> bool {\n    return !t || t->isStopped();\n  }), m_threads.end());\n}\n\nvoid Engine::Impl::drawCursor(ngf::RenderTarget &target) const {\n  if (!m_cursorVisible)\n    return;\n  if (!m_showCursor && m_dialogManager.getState() != DialogManagerState::WaitingForChoice)\n    return;\n\n  auto cursorSize = glm::vec2(68.f, 68.f);\n  const auto &gameSheet = Locator<ResourceManager>::get().getSpriteSheet(\"GameSheet\");\n\n  const auto view = target.getView();\n  target.setView(ngf::View(ngf::frect::fromPositionSize({0, 0}, {Screen::Width, Screen::Height})));\n\n  auto screenSize = m_pRoom->getScreenSize();\n  auto pos = toDefaultView((glm::ivec2) m_mousePos, screenSize);\n\n  ngf::RectangleShape shape;\n  shape.getTransform().setPosition(pos);\n  shape.getTransform().setOrigin(cursorSize / 2.f);\n  shape.setSize(cursorSize);\n  shape.setTexture(*gameSheet.getTexture(), false);\n  shape.setTextureRect(getCursorRect());\n  shape.draw(target, {});\n\n  target.setView(view);\n}\n\nngf::irect Engine::Impl::getCursorRect() const {\n  auto &gameSheet = Locator<ResourceManager>::get().getSpriteSheet(\"GameSheet\");\n  if (m_state == EngineState::Paused)\n    return gameSheet.getRect(\"cursor_pause\");\n\n  if (m_state == EngineState::Options)\n    return gameSheet.getRect(\"cursor\");\n\n  if (m_dialogManager.getState() != DialogManagerState::None)\n    return gameSheet.getRect(\"cursor\");\n\n  if (m_pRoom->getFullscreen() == 1)\n    return gameSheet.getRect(\"cursor\");\n\n  if (m_cursorDirection & CursorDirection::Left) {\n    return m_cursorDirection & CursorDirection::Hotspot ? gameSheet.getRect(\"hotspot_cursor_left\")\n                                                        : gameSheet.getRect(\"cursor_left\");\n  }\n  if (m_cursorDirection & CursorDirection::Right) {\n    return m_cursorDirection & CursorDirection::Hotspot ? gameSheet.getRect(\"hotspot_cursor_right\")\n                                                        : gameSheet.getRect(\"cursor_right\");\n  }\n  if (m_cursorDirection & CursorDirection::Up) {\n    return m_cursorDirection & CursorDirection::Hotspot ? gameSheet.getRect(\"hotspot_cursor_back\")\n                                                        : gameSheet.getRect(\"cursor_back\");\n  }\n  if (m_cursorDirection & CursorDirection::Down) {\n    return (m_cursorDirection & CursorDirection::Hotspot) ? gameSheet.getRect(\"hotspot_cursor_front\")\n                                                          : gameSheet.getRect(\"cursor_front\");\n  }\n  return (m_cursorDirection & CursorDirection::Hotspot) ? gameSheet.getRect(\"hotspot_cursor\")\n                                                        : gameSheet.getRect(\"cursor\");\n}\n\nstd::wstring Engine::Impl::getDisplayName(const std::wstring &name) {\n  std::wstring displayName(name);\n  auto len = displayName.length();\n  if (len > 1 && displayName[0] == '^') {\n    displayName = name.substr(1, len - 1);\n  }\n  if (len > 2 && displayName[len - 2] == '#') {\n    displayName = name.substr(0, len - 2);\n  }\n  return displayName;\n}\n\nconst Verb *Engine::Impl::overrideVerb(const Verb *pVerb) const {\n  if (!pVerb || pVerb->id != VerbConstants::VERB_WALKTO)\n    return pVerb;\n\n  auto pObj1 = EntityManager::getScriptObjectFromId<Entity>(m_objId1);\n  if (!pObj1)\n    return pVerb;\n  return m_hud.getVerb(pObj1->getDefaultVerb(VerbConstants::VERB_WALKTO));\n}\n\nvoid Engine::Impl::drawCursorText(ngf::RenderTarget &target) const {\n  if (!m_cursorVisible)\n    return;\n\n  if (!m_showCursor || m_state != EngineState::Game)\n    return;\n\n  if (m_dialogManager.getState() != DialogManagerState::None)\n    return;\n\n  auto pVerb = m_hud.getVerbOverride();\n  if (!pVerb)\n    pVerb = m_hud.getCurrentVerb();\n  if (!pVerb)\n    return;\n\n  pVerb = overrideVerb(pVerb);\n\n  auto currentActorIndex = getCurrentActorIndex();\n  if (currentActorIndex == -1)\n    return;\n\n  auto textColor = m_hud.getVerbUiColors(currentActorIndex).sentence;\n  auto classicSentence = m_pEngine->getPreferences().getUserPreference(PreferenceNames::ClassicSentence,\n                                                                       PreferenceDefaultValues::ClassicSentence);\n\n  const auto view = target.getView();\n  target.setView(ngf::View(ngf::frect::fromPositionSize({0, 0}, {Screen::Width, Screen::Height})));\n\n  auto retroFonts =\n      m_pEngine->getPreferences().getUserPreference(PreferenceNames::RetroFonts, PreferenceDefaultValues::RetroFonts);\n  auto &font = m_pEngine->getResourceManager().getFont(retroFonts ? \"FontRetroSheet\" : \"FontModernSheet\");\n\n  std::wstring s;\n  // draw verb\n  if ((m_pRoom->getFullscreen() != 1) && (pVerb->id != VerbConstants::VERB_WALKTO || m_hud.getHoveredEntity())) {\n    auto id = std::strtol(pVerb->text.substr(1).data(), nullptr, 10);\n    s.append(ng::Engine::getText(id));\n  }\n  auto pObj1 = EntityManager::getScriptObjectFromId<Entity>(m_objId1);\n  // draw object 1 name\n  if (pObj1) {\n    if (!s.empty()) {\n      s.append(L\" \");\n    }\n    s.append(getDisplayName(ng::Engine::getText(pObj1->getName())));\n    if (DebugFeatures::showHoveredObject) {\n      if (pObj1) {\n        s.append(L\"(\").append(towstring(pObj1->getKey())).append(L\")\");\n      }\n    }\n  }\n  // draw use flags if any\n  appendUseFlag(s);\n  // draw object 2 name\n  if (m_pObj2) {\n    s.append(L\" \").append(getDisplayName(ng::Engine::getText(m_pObj2->getName())));\n  }\n\n  ng::Text text;\n  text.setFont(font);\n  text.setColor(textColor);\n  text.setWideString(s);\n\n  // do display cursor position:\n  if (DebugFeatures::showCursorPosition) {\n    std::wstringstream ss;\n    std::wstring txt = text.getWideString();\n    ss << txt << L\" (\" << std::fixed << std::setprecision(0) << m_mousePosInRoom.x << L\",\" << m_mousePosInRoom.y\n       << L\")\";\n    text.setWideString(ss.str());\n  }\n\n  // gets the position where to draw the cursor text\n  auto bounds = getGlobalBounds(text);\n  if (classicSentence) {\n    auto y = Screen::Height - 210.f;\n    auto x = Screen::HalfWidth - bounds.getWidth() / 2.f;\n    text.getTransform().setPosition({x, y});\n  } else {\n    auto screenSize = m_pRoom->getScreenSize();\n    auto pos = toDefaultView((glm::ivec2) m_mousePos, screenSize);\n    auto y = pos.y - 20 < 40 ? pos.y + 80 : pos.y - 40;\n    auto x = std::clamp<float>(pos.x - bounds.getWidth() / 2.f, 20.f, Screen::Width - 20.f - bounds.getWidth());\n    text.getTransform().setPosition({x, y - bounds.getHeight()});\n  }\n\n  text.draw(target, {});\n  target.setView(view);\n}\n\nvoid Engine::Impl::drawNoOverride(ngf::RenderTarget &target) const {\n  if (m_noOverrideElapsed > ngf::TimeSpan::seconds(2))\n    return;\n\n  auto &gameSheet = Locator<ResourceManager>::get().getSpriteSheet(\"GameSheet\");\n  const auto view = target.getView();\n  target.setView(ngf::View(ngf::frect::fromPositionSize({0, 0}, {Screen::Width, Screen::Height})));\n\n  ngf::Color c(ngf::Colors::White);\n  c.a = (2.f - m_noOverrideElapsed.getTotalSeconds() / 2.f);\n  ngf::Sprite spriteNo;\n  spriteNo.setColor(c);\n  spriteNo.getTransform().setPosition({8.f, 8.f});\n  spriteNo.getTransform().setScale({2.f, 2.f});\n  spriteNo.setTexture(*gameSheet.getTexture());\n  spriteNo.setTextureRect(gameSheet.getRect(\"icon_no\"));\n  spriteNo.draw(target, {});\n\n  target.setView(view);\n}\n\nvoid Engine::Impl::appendUseFlag(std::wstring &sentence) const {\n  switch (m_useFlag) {\n  case UseFlag::UseWith:sentence.append(L\" \").append(ng::Engine::getText(10000));\n    break;\n  case UseFlag::UseOn:sentence.append(L\" \").append(ng::Engine::getText(10001));\n    break;\n  case UseFlag::UseIn:sentence.append(L\" \").append(ng::Engine::getText(10002));\n    break;\n  case UseFlag::GiveTo:sentence.append(L\" \").append(ng::Engine::getText(10003));\n    break;\n  case UseFlag::None:break;\n  }\n}\n\nint Engine::Impl::getCurrentActorIndex() const {\n  for (int i = 0; i < static_cast<int>(m_actorsIconSlots.size()); i++) {\n    const auto &selectableActor = m_actorsIconSlots.at(i);\n    if (selectableActor.pActor == m_pCurrentActor) {\n      return i;\n    }\n  }\n  return -1;\n}\n\nvoid Engine::Impl::drawHud(ngf::RenderTarget &target) const {\n  if (m_state != EngineState::Game)\n    return;\n\n  m_hud.draw(target, {});\n}\n\nvoid Engine::Impl::captureScreen(const std::string &path) const {\n  ngf::RenderTexture target({320, 180});\n  m_pEngine->draw(target, true);\n  target.display();\n\n  auto screenshot = target.capture();\n  screenshot.saveToFile(path);\n}\n}\n"
  },
  {
    "path": "src/Engine/EngineImpl.hpp",
    "content": "#include <squirrel.h>\n#include <glm/gtc/epsilon.hpp>\n#include <engge/Engine/Engine.hpp>\n#include <engge/Engine/ActorIconSlot.hpp>\n#include <engge/Engine/ActorIcons.hpp>\n#include <engge/Engine/Camera.hpp>\n#include <engge/Engine/Cutscene.hpp>\n#include <engge/Engine/Hud.hpp>\n#include <engge/Input/InputConstants.hpp>\n#include <engge/Dialog/DialogManager.hpp>\n#include <engge/Graphics/GGFont.hpp>\n#include <engge/Engine/Inventory.hpp>\n#include <engge/UI/OptionsDialog.hpp>\n#include <engge/UI/StartScreenDialog.hpp>\n#include <engge/Engine/Preferences.hpp>\n#include <engge/Room/Room.hpp>\n#include <engge/Room/RoomScaling.hpp>\n#include <engge/Graphics/Screen.hpp>\n#include <engge/Scripting/ScriptEngine.hpp>\n#include <engge/Scripting/ScriptExecute.hpp>\n#include <engge/Engine/Sentence.hpp>\n#include <engge/Audio/SoundDefinition.hpp>\n#include <engge/Audio/SoundManager.hpp>\n#include <engge/Graphics/SpriteSheet.hpp>\n#include <engge/Engine/TextDatabase.hpp>\n#include <engge/Engine/Thread.hpp>\n#include <engge/Engine/Verb.hpp>\n#include <engge/Scripting/VerbExecute.hpp>\n#include <squirrel.h>\n#include \"../../extlibs/squirrel/squirrel/sqpcheader.h\"\n#include \"../../extlibs/squirrel/squirrel/sqvm.h\"\n#include \"../../extlibs/squirrel/squirrel/sqstring.h\"\n#include \"../../extlibs/squirrel/squirrel/sqtable.h\"\n#include \"../../extlibs/squirrel/squirrel/sqarray.h\"\n#include \"../../extlibs/squirrel/squirrel/sqfuncproto.h\"\n#include \"../../extlibs/squirrel/squirrel/sqclosure.h\"\n#include \"../../extlibs/squirrel/squirrel/squserdata.h\"\n#include \"../../extlibs/squirrel/squirrel/sqcompiler.h\"\n#include \"../../extlibs/squirrel/squirrel/sqfuncstate.h\"\n#include \"../../extlibs/squirrel/squirrel/sqclass.h\"\n#include <cmath>\n#include <ctime>\n#include <cctype>\n#include <cwchar>\n#include <filesystem>\n#include <iomanip>\n#include <memory>\n#include <set>\n#include <string>\n#include <unordered_set>\n#include <ngf/Graphics/Sprite.h>\n#include <ngf/Graphics/RenderTexture.h>\n#include <ngf/Graphics/RectangleShape.h>\n#include <ngf/Graphics/Text.h>\n#include <imgui.h>\n#include <engge/Engine/EngineSettings.hpp>\n#include <engge/Input/CommandManager.hpp>\n#include <engge/Engine/EngineCommands.hpp>\n#include <engge/System/Logger.hpp>\n#include <engge/Parsers/SavegameManager.hpp>\n#include \"DebugFeatures.hpp\"\n#include \"Entities/TalkingState.hpp\"\n#include \"Graphics/WalkboxDrawable.hpp\"\n#include \"Graphics/GraphDrawable.hpp\"\n#include \"Shaders.hpp\"\nnamespace fs = std::filesystem;\n\nnamespace ng {\nstatic const char *const objectKey = \"_objectKey\";\nstatic const char *const roomKey = \"_roomKey\";\nstatic const char *const actorKey = \"_actorKey\";\nstatic const char *const idKey = \"_id\";\nstatic const char *const pseudoObjectsKey = \"_pseudoObjects\";\nstatic const auto clickedAtCallback = \"clickedAt\";\n\nenum class CursorDirection : unsigned int {\n  None = 0,\n  Left = 1,\n  Right = 1u << 1u,\n  Up = 1u << 2u,\n  Down = 1u << 3u,\n  Hotspot = 1u << 4u\n};\n\nenum class EngineState {\n  Game, Paused, Options, StartScreen, Quit\n};\n\nstruct Engine::Impl {\n  class SaveGameSystem {\n  public:\n    explicit SaveGameSystem(Engine::Impl *pImpl) : m_pImpl(pImpl) {}\n\n    void saveGame(const std::filesystem::path &path) {\n      ScriptEngine::call(\"preSave\");\n\n      time_t now;\n      time(&now);\n\n      ngf::StopWatch watch;\n\n      SQObjectPtr g;\n      _table(ScriptEngine::getVm()->_roottable)->Get(ScriptEngine::toSquirrel(\"g\"), g);\n      SQObjectPtr easyMode;\n      _table(g)->Get(ScriptEngine::toSquirrel(\"easy_mode\"), easyMode);\n\n      ngf::GGPackValue saveGameHash = {\n          {\"actors\", saveActors()},\n          {\"callbacks\", saveCallbacks()},\n          {\"currentRoom\", m_pImpl->m_pRoom->getName()},\n          {\"dialog\", saveDialogs()},\n          {\"easy_mode\", static_cast<int>(_integer(easyMode))},\n          {\"gameGUID\", std::string()},\n          {\"gameScene\", saveGameScene()},\n          {\"gameTime\", m_pImpl->m_time.getTotalSeconds()},\n          {\"globals\", saveGlobals()},\n          {\"inputState\", m_pImpl->m_pEngine->getInputState()},\n          {\"inventory\", saveInventory()},\n          {\"objects\", saveObjects()},\n          {\"rooms\", saveRooms()},\n          {\"savebuild\", 958},\n          {\"savetime\", static_cast<int>(now)},\n          {\"selectedActor\", m_pImpl->m_pEngine->getCurrentActor()->getKey()},\n          {\"version\", 2},\n      };\n\n      SavegameManager::saveGame(path, saveGameHash);\n\n      info(\"Save game in {} s\", watch.getElapsedTime().getTotalSeconds());\n\n      ScriptEngine::call(\"postSave\");\n    }\n\n    void loadGame(const std::string &path) {\n      auto hash = SavegameManager::loadGame(path);\n\n      std::ofstream os(path + \".json\");\n      os << hash;\n      os.close();\n\n      loadGame(hash);\n    }\n\n    static std::filesystem::path getSlotPath(int slot) {\n      std::ostringstream filename;\n      filename << \"Savegame\" << slot << \".save\";\n      auto path = Locator<EngineSettings>::get().getPath();\n      path.append(filename.str());\n      return path;\n    }\n\n    static void getSlot(SavegameSlot &slot) {\n      auto hash = SavegameManager::loadGame(slot.path);\n      slot.easyMode = hash[\"easy_mode\"].getInt() != 0;\n      slot.savetime = (time_t) hash[\"savetime\"].getInt();\n      slot.gametime = ngf::TimeSpan::seconds(static_cast<float>(hash[\"gameTime\"].getDouble()));\n    }\n\n  private:\n    static std::string getValue(const ngf::GGPackValue &property) {\n      std::ostringstream s;\n      if (property.isInteger()) {\n        s << property.getInt();\n      } else if (property.isDouble()) {\n        s << property.getDouble();\n      } else if (property.isString()) {\n        s << property.getString();\n      }\n      return s.str();\n    }\n\n    SQObjectPtr toSquirrel(const ngf::GGPackValue &value) {\n      if (value.isString()) {\n        return ScriptEngine::toSquirrel(value.getString());\n      }\n      if (value.isInteger()) {\n        return static_cast<SQInteger>(value.getInt());\n      }\n      if (value.isDouble()) {\n        return static_cast<SQFloat>(value.getDouble());\n      }\n      if (value.isArray()) {\n        auto array = SQArray::Create(_ss(ScriptEngine::getVm()), value.size());\n        SQInteger i = 0;\n        for (auto &item : value) {\n          array->Set(i++, toSquirrel(item));\n        }\n        return array;\n      }\n      if (value.isHash()) {\n        auto actor = value[actorKey];\n        if (!actor.isNull()) {\n          auto pActor = getActor(actor.getString());\n          return pActor->getTable();\n        }\n        auto object = value[objectKey];\n        auto room = value[roomKey];\n        if (!object.isNull()) {\n          Object *pObject;\n          if (!room.isNull()) {\n            auto pRoom = getRoom(room.getString());\n            pObject = getObject(pRoom, object.getString());\n            if (!pObject) {\n              warn(\"load: object {} not found\", object.getString());\n              return SQObjectPtr();\n            }\n            return pObject->getTable();\n          }\n          pObject = getObject(object.getString());\n          if (!pObject) {\n            warn(\"load: object {} not found\", object.getString());\n            return SQObjectPtr();\n          }\n          return pObject->getTable();\n        }\n\n        if (!room.isNull()) {\n          auto pRoom = getRoom(room.getString());\n          return pRoom->getTable();\n        }\n\n        auto table = SQTable::Create(_ss(ScriptEngine::getVm()), 0);\n        for (const auto&[key, value] : value.items()) {\n          table->NewSlot(ScriptEngine::toSquirrel(key), toSquirrel(value));\n        }\n        return table;\n      }\n      if (!value.isNull()) {\n        warn(\"trying to convert an unknown value (type={}) to squirrel\", static_cast<int >(value.type()));\n      }\n      return SQObjectPtr();\n    }\n\n    void loadGameScene(const ngf::GGPackValue &hash) {\n      auto actorsSelectable = hash[\"actorsSelectable\"].getInt();\n      auto actorsTempUnselectable = hash[\"actorsTempUnselectable\"].getInt();\n      auto mode = actorsSelectable ? ActorSlotSelectableMode::On : ActorSlotSelectableMode::Off;\n      if (actorsTempUnselectable) {\n        mode |= ActorSlotSelectableMode::TemporaryUnselectable;\n      }\n      m_pImpl->m_pEngine->setActorSlotSelectable(mode);\n      auto forceTalkieText = hash[\"forceTalkieText\"].getInt() != 0;\n      m_pImpl->m_pEngine->getPreferences().setTempPreference(TempPreferenceNames::ForceTalkieText, forceTalkieText);\n      for (const auto &selectableActor : hash[\"selectableActors\"]) {\n        auto pActor = getActor(selectableActor[actorKey].getString());\n        auto selectable = selectableActor[\"selectable\"].getInt() != 0;\n        m_pImpl->m_pEngine->actorSlotSelectable(pActor, selectable);\n      }\n    }\n\n    void loadDialog(const ngf::GGPackValue &hash) {\n      auto &states = m_pImpl->m_dialogManager.getStates();\n      states.clear();\n      for (auto &property : hash.items()) {\n        const auto &dialog = property.key();\n        // dialog format: mode dialog number actor\n        // example: #ChetAgentStreetDialog14reyes\n        // mode:\n        // ?: once\n        // #: showonce\n        // &: onceever\n        // $: showonceever\n        // ^: temponce\n        auto state = parseState(dialog);\n        states.push_back(state);\n        // TODO: what to do with this dialog value ?\n        //auto value = property.second.getInt();\n      }\n    }\n\n    [[nodiscard]] static DialogConditionState parseState(const std::string &dialog) {\n      DialogConditionState state;\n      switch (dialog[0]) {\n      case '?':state.mode = DialogConditionMode::Once;\n        break;\n      case '#':state.mode = DialogConditionMode::ShowOnce;\n        break;\n      case '&':state.mode = DialogConditionMode::OnceEver;\n        break;\n      case '$':state.mode = DialogConditionMode::ShowOnceEver;\n        break;\n      case '^':state.mode = DialogConditionMode::TempOnce;\n        break;\n      }\n      std::string dialogName;\n      int i;\n      for (i = 1; i < static_cast<int>(dialog.length()) && !isdigit(dialog[i]); i++) {\n        dialogName.append(1, dialog[i]);\n      }\n      auto &settings = Locator<EngineSettings>::get();\n      while (!settings.hasEntry(dialogName + \".byack\")) {\n        dialogName.append(1, dialog.at(i++));\n      }\n      std::string num;\n      state.dialog = dialogName;\n      for (; i < static_cast<int>(dialog.length()) && isdigit(dialog[i]); i++) {\n        num.append(1, dialog[i]);\n      }\n      state.line = atol(num.data());\n      state.actorKey = dialog.substr(i);\n      return state;\n    }\n\n    void loadCallbacks(const ngf::GGPackValue &hash) {\n      m_pImpl->m_callbacks.clear();\n      for (auto &callBackHash : hash[\"callbacks\"]) {\n        auto name = callBackHash[\"function\"].getString();\n        auto id = callBackHash[\"guid\"].getInt();\n        auto time = ngf::TimeSpan::seconds(static_cast<float>(callBackHash[\"time\"].getInt()) / 1000.f);\n        auto arg = toSquirrel(callBackHash[\"param\"]);\n        auto callback = std::make_unique<Callback>(id, time, name, arg);\n        m_pImpl->m_callbacks.push_back(std::move(callback));\n      }\n      Locator<EntityManager>::get().setCallbackId(hash[\"nextGuid\"].getInt());\n    }\n\n    void loadActors(const ngf::GGPackValue &hash) {\n      for (auto &pActor : m_pImpl->m_actors) {\n        if (pActor->getKey().empty())\n          continue;\n\n        const auto &actorHash = hash[pActor->getKey()];\n        loadActor(pActor.get(), actorHash);\n      }\n    }\n\n    void loadActor(Actor *pActor, const ngf::GGPackValue &actorHash) {\n      glm::vec2 pos{0, 0};\n      getValue(actorHash, \"_pos\", pos);\n      pActor->setPosition(pos);\n\n      std::string costume;\n      getValue(actorHash, \"_costume\", costume);\n      std::string costumesheet;\n      getValue(actorHash, \"_costumeSheet\", costumesheet);\n      pActor->getCostume().loadCostume(costume, costumesheet);\n\n      std::string room;\n      getValue(actorHash, roomKey, room);\n      auto *pRoom = getRoom(room.empty() ? \"Void\" : room);\n      pActor->setRoom(pRoom);\n\n      int dir = static_cast<int>(Facing::FACE_FRONT);\n      getValue(actorHash, \"_dir\", dir);\n      pActor->getCostume().setFacing(static_cast<Facing>(dir));\n\n      int useDirValue = static_cast<int>(UseDirection::Front);\n      getValue(actorHash, \"_useDir\", useDirValue);\n      pActor->setUseDirection(static_cast<UseDirection>(dir));\n\n      int lockFacing = 0;\n      getValue(actorHash, \"_lockFacing\", lockFacing);\n      if (lockFacing == 0) {\n        pActor->getCostume().unlockFacing();\n      } else {\n        pActor->getCostume().lockFacing(static_cast<Facing>(lockFacing),\n                                        static_cast<Facing>(lockFacing),\n                                        static_cast<Facing>(lockFacing),\n                                        static_cast<Facing>(lockFacing));\n      }\n\n      glm::vec2 usePos{0, 0};\n      getValue(actorHash, \"_usePos\", usePos);\n      pActor->setUsePosition(usePos);\n\n      glm::vec2 renderOffset{0, 45};\n      getValue(actorHash, \"_renderOffset\", renderOffset);\n      pActor->setRenderOffset((glm::ivec2) renderOffset);\n\n      glm::vec2 offset{0, 0};\n      getValue(actorHash, \"_offset\", offset);\n      pActor->setOffset(offset);\n\n      for (auto &property : actorHash.items()) {\n        if (property.key().empty() || property.key()[0] == '_') {\n          if (property.key() == \"_animations\") {\n            std::vector<std::string> anims;\n            for (auto &value : property.value()) {\n              anims.push_back(value.getString());\n            }\n            // TODO: _animations\n            trace(\"load: actor {} property '{}' not loaded (type={}) size={}\",\n                  pActor->getKey(),\n                  property.key(),\n                  static_cast<int>(property.value().type()), anims.size());\n          } else if ((property.key() == \"_pos\")\n              || (property.key() == \"_costume\")\n              || (property.key() == \"_costumeSheet\")\n              || (property.key() == roomKey)\n              || (property.key() == \"_dir\")\n              || (property.key() == \"_useDir\")\n              || (property.key() == \"_lockFacing\")\n              || (property.key() == \"_usePos\")\n              || (property.key() == \"_renderOffset\")\n              || (property.key() == \"_offset\")) {\n          } else {\n            _table(pActor->getTable())->Set(ScriptEngine::toSquirrel(property.key()), toSquirrel(property.value()));\n          }\n          continue;\n        }\n\n        _table(pActor->getTable())->Set(ScriptEngine::toSquirrel(property.key()), toSquirrel(property.value()));\n      }\n      if (ScriptEngine::rawExists(pActor, \"postLoad\")) {\n        ScriptEngine::objCall(pActor, \"postLoad\");\n      }\n    }\n\n    void loadInventory(const ngf::GGPackValue &hash) {\n      for (auto i = 0; i < static_cast<int>(m_pImpl->m_actorsIconSlots.size()); ++i) {\n        auto *pActor = m_pImpl->m_actorsIconSlots[i].pActor;\n        if (!pActor)\n          continue;\n        auto &slot = hash[\"slots\"].at(i);\n        pActor->clearInventory();\n        int jiggleCount = 0;\n        for (const auto &obj : slot[\"objects\"]) {\n          auto pObj = getInventoryObject(obj.getString());\n          // TODO: why we don't find the inventory object here ?\n          if (!pObj)\n            continue;\n          const auto jiggle = slot[\"jiggle\"].isArray() && slot[\"jiggle\"][jiggleCount++].getInt() != 0;\n          pObj->setJiggle(jiggle);\n          pActor->pickupObject(pObj);\n        }\n        auto scroll = slot[\"scroll\"].getInt();\n        pActor->setInventoryOffset(scroll);\n      }\n    }\n\n    void loadObjects(const ngf::GGPackValue &hash) {\n      for (auto &obj :  hash.items()) {\n        const auto &objName = obj.key();\n        if (objName.empty())\n          continue;\n        auto pObj = getObject(objName);\n        // TODO: if the object does not exist creates it\n        if (!pObj) {\n          trace(\"load: object '{}' not loaded because it has not been found\", objName);\n          continue;\n        }\n        loadObject(pObj, obj.value());\n      }\n    }\n\n    static void getValue(const ngf::GGPackValue &hash, const std::string &key, int &value) {\n      if (!hash[key].isNull()) {\n        value = hash[key].getInt();\n      }\n    }\n\n    static void getValue(const ngf::GGPackValue &hash, const std::string &key, std::string &value) {\n      if (!hash[key].isNull()) {\n        value = hash[key].getString();\n      }\n    }\n\n    static void getValue(const ngf::GGPackValue &hash, const std::string &key, float &value) {\n      if (!hash[key].isNull()) {\n        value = static_cast<float>(hash[key].getDouble());\n      }\n    }\n\n    static void getValue(const ngf::GGPackValue &hash, const std::string &key, bool &value) {\n      if (!hash[key].isNull()) {\n        value = hash[key].getInt() != 0;\n      }\n    }\n\n    static void getValue(const ngf::GGPackValue &hash, const std::string &key, glm::vec2 &value) {\n      if (!hash[key].isNull()) {\n        value = parsePos(hash[key].getString());\n      }\n    }\n\n    static void getValue(const ngf::GGPackValue &hash, const std::string &key, ngf::Color &value) {\n      if (!hash[key].isNull()) {\n        value = fromRgba(hash[key].getInt());\n      }\n    }\n\n    void loadObject(Object *pObj, const ngf::GGPackValue &hash) {\n      auto state = 0;\n      getValue(hash, \"_state\", state);\n      pObj->setStateAnimIndex(state);\n      glm::vec2 offset{0, 0};\n      getValue(hash, \"_offset\", offset);\n      pObj->setOffset(offset);\n      float rotation = 0;\n      getValue(hash, \"_rotation\", rotation);\n      pObj->setRotation(rotation);\n\n      for (auto &property :  hash.items()) {\n        if (property.key().empty() || property.key()[0] == '_') {\n          if (property.key() == \"_state\" || property.key() == \"_offset\" || property.key() == \"_rotation\")\n            continue;\n\n          _table(pObj->getTable())->Set(ScriptEngine::toSquirrel(property.key()), toSquirrel(property.value()));\n          continue;\n        }\n\n        _table(pObj->getTable())->Set(ScriptEngine::toSquirrel(property.key()), toSquirrel(property.value()));\n      }\n    }\n\n    void loadPseudoObjects(Room *pRoom, const ngf::GGPackValue &hash) {\n      for (const auto &entry :  hash.items()) {\n        auto pObj = getObject(pRoom, entry.key());\n        if (!pObj) {\n          trace(\"load: room '{}' object '{}' not loaded because it has not been found\", pRoom->getName(), entry.key());\n          continue;\n        }\n        loadObject(pObj, entry.value());\n      }\n    }\n\n    void loadRooms(const ngf::GGPackValue &hash) {\n      for (auto &roomHash :  hash.items()) {\n        const auto &roomName = roomHash.key();\n        auto pRoom = getRoom(roomName);\n        if (!pRoom) {\n          trace(\"load: room '{}' not loaded because it has not been found\", roomName);\n          continue;\n        }\n\n        for (auto &property : roomHash.value().items()) {\n          if (property.key().empty() || property.key()[0] == '_') {\n            if (property.key() == pseudoObjectsKey) {\n              loadPseudoObjects(pRoom, property.value());\n            } else {\n              trace(\"load: room '{}' property '{}' (type={}) not loaded\",\n                    roomName,\n                    property.key(),\n                    static_cast<int>(property.value().type()));\n              continue;\n            }\n          }\n\n          _table(pRoom->getTable())->Set(ScriptEngine::toSquirrel(property.key()), toSquirrel(property.value()));\n          if (ScriptEngine::rawExists(pRoom, \"postLoad\")) {\n            ScriptEngine::objCall(pRoom, \"postLoad\");\n          }\n        }\n      }\n    }\n\n    void loadGame(const ngf::GGPackValue &hash) {\n      auto version = hash[\"version\"].getInt();\n      if (version != 2) {\n        warn(\"Cannot load savegame version {}\", version);\n        return;\n      }\n\n      ScriptEngine::call(\"preLoad\");\n\n      loadGameScene(hash[\"gameScene\"]);\n      loadDialog(hash[\"dialog\"]);\n      loadCallbacks(hash[\"callbacks\"]);\n      loadGlobals(hash[\"globals\"]);\n      loadActors(hash[\"actors\"]);\n      loadInventory(hash[\"inventory\"]);\n      loadRooms(hash[\"rooms\"]);\n\n      m_pImpl->m_time = ngf::TimeSpan::seconds(static_cast<float>(hash[\"gameTime\"].getDouble()));\n      m_pImpl->m_pEngine->setInputState(hash[\"inputState\"].getInt());\n\n      loadObjects(hash[\"objects\"]);\n      setActor(hash[\"selectedActor\"].getString());\n      setCurrentRoom(hash[\"currentRoom\"].getString());\n\n      ScriptEngine::set(\"SAVEBUILD\", hash[\"savebuild\"].getInt());\n\n      ScriptEngine::call(\"postLoad\");\n    }\n\n    void setActor(const std::string &name) {\n      auto *pActor = getActor(name);\n      m_pImpl->m_pEngine->setCurrentActor(pActor, false);\n    }\n\n    Actor *getActor(const std::string &name) {\n      return dynamic_cast<Actor *>(m_pImpl->m_pEngine->getEntity(name));\n    }\n\n    Room *getRoom(const std::string &name) {\n      auto &rooms = m_pImpl->m_pEngine->getRooms();\n      auto it = std::find_if(rooms.begin(), rooms.end(), [&name](auto &pRoom) { return pRoom->getName() == name; });\n      if (it != rooms.end())\n        return it->get();\n      return nullptr;\n    }\n\n    static Object *getInventoryObject(const std::string &name) {\n      auto v = ScriptEngine::getVm();\n      SQObjectPtr obj;\n      if (!_table(v->_roottable)->Get(ScriptEngine::toSquirrel(name), obj)) {\n        return nullptr;\n      }\n      SQObjectPtr id;\n      if (!_table(obj)->Get(ScriptEngine::toSquirrel(idKey), id)) {\n        return nullptr;\n      }\n      return EntityManager::getObjectFromId(static_cast<int>(_integer(id)));\n    }\n\n    Object *getObject(const std::string &name) {\n      for (auto &pRoom : m_pImpl->m_rooms) {\n        for (auto &pObj : pRoom->getObjects()) {\n          if (pObj->getKey() == name)\n            return pObj.get();\n        }\n      }\n      return nullptr;\n    }\n\n    static Object *getObject(Room *pRoom, const std::string &name) {\n      for (auto &pObj : pRoom->getObjects()) {\n        if (pObj->getKey() == name)\n          return pObj.get();\n      }\n      return nullptr;\n    }\n\n    void setCurrentRoom(const std::string &name) {\n      m_pImpl->m_pEngine->setRoom(getRoom(name));\n    }\n\n    [[nodiscard]] ngf::GGPackValue saveActors() const {\n      ngf::GGPackValue actorsHash;\n      for (auto &pActor : m_pImpl->m_actors) {\n        // TODO: find why this entry exists...\n        if (pActor->getKey().empty())\n          continue;\n\n        auto table = pActor->getTable();\n        auto actorHash = ng::toGGPackValue(table);\n        auto costume = fs::path(pActor->getCostume().getPath()).filename();\n        if (costume.has_extension())\n          costume.replace_extension();\n        actorHash[\"_costume\"] = costume.u8string();\n        actorHash[\"_dir\"] = static_cast<int>(pActor->getCostume().getFacing());\n        auto lockFacing = pActor->getCostume().getLockFacing();\n        actorHash[\"_lockFacing\"] = lockFacing.has_value() ? static_cast<int>(lockFacing.value()) : 0;\n        actorHash[\"_pos\"] = toString(pActor->getPosition());\n        auto useDir = pActor->getUseDirection();\n        if (useDir.has_value()) {\n          actorHash[\"_useDir\"] = static_cast<int>(useDir.value());\n        }\n        auto usePos = pActor->getUsePosition();\n        if (useDir.has_value()) {\n          actorHash[\"_usePos\"] = toString(usePos.value());\n        }\n        auto renderOffset = pActor->getRenderOffset();\n        if (renderOffset != glm::ivec2(0, 45)) {\n          actorHash[\"_renderOffset\"] = toString(renderOffset);\n        }\n        auto costumeSheet = pActor->getCostume().getSheet();\n        if (!costumeSheet.empty()) {\n          actorHash[\"_costumeSheet\"] = costumeSheet;\n        }\n        if (pActor->getRoom()) {\n          actorHash[roomKey] = pActor->getRoom()->getName();\n        } else {\n          actorHash[roomKey] = nullptr;\n        }\n\n        actorsHash[pActor->getKey()] = actorHash;\n      }\n      return actorsHash;\n    }\n\n    [[nodiscard]] static ngf::GGPackValue saveGlobals() {\n      auto v = ScriptEngine::getVm();\n      auto top = sq_gettop(v);\n      sq_pushroottable(v);\n      sq_pushstring(v, _SC(\"g\"), -1);\n      sq_get(v, -2);\n      HSQOBJECT g;\n      sq_getstackobj(v, -1, &g);\n\n      auto globalsHash = ng::toGGPackValue(g);\n      sq_settop(v, top);\n      return globalsHash;\n    }\n\n    [[nodiscard]] ngf::GGPackValue saveDialogs() const {\n      ngf::GGPackValue hash;\n      const auto &states = m_pImpl->m_dialogManager.getStates();\n      for (const auto &state : states) {\n        std::ostringstream s;\n        switch (state.mode) {\n        case DialogConditionMode::TempOnce:continue;\n        case DialogConditionMode::OnceEver:s << \"&\";\n          break;\n        case DialogConditionMode::ShowOnce:s << \"#\";\n          break;\n        case DialogConditionMode::Once:s << \"?\";\n          break;\n        case DialogConditionMode::ShowOnceEver:s << \"$\";\n          break;\n        }\n        s << state.dialog << state.line << state.actorKey;\n        // TODO: value should be 1 or another value ?\n        hash[s.str()] = state.mode == DialogConditionMode::ShowOnce ? 2 : 1;\n      }\n      return hash;\n    }\n\n    [[nodiscard]] ngf::GGPackValue saveGameScene() const {\n      auto actorsSelectable =\n          ((m_pImpl->m_actorIcons.getMode() & ActorSlotSelectableMode::On) == ActorSlotSelectableMode::On);\n      auto actorsTempUnselectable = ((m_pImpl->m_actorIcons.getMode() & ActorSlotSelectableMode::TemporaryUnselectable)\n          == ActorSlotSelectableMode::TemporaryUnselectable);\n\n      ngf::GGPackValue selectableActors;\n      for (auto &slot : m_pImpl->m_actorsIconSlots) {\n        ngf::GGPackValue selectableActor;\n        if (slot.pActor) {\n          selectableActor = {\n              {actorKey, slot.pActor->getKey()},\n              {\"selectable\", slot.selectable ? 1 : 0},\n          };\n        } else {\n          selectableActor = {{\"selectable\", 0}};\n        }\n        selectableActors.push_back(selectableActor);\n      }\n\n      auto forceTalkieText = m_pImpl->m_pEngine->getPreferences()\n          .getTempPreference(TempPreferenceNames::ForceTalkieText,\n                             TempPreferenceDefaultValues::ForceTalkieText);\n      return {\n          {\"actorsSelectable\", actorsSelectable ? 1 : 0},\n          {\"actorsTempUnselectable\", actorsTempUnselectable ? 1 : 0},\n          {\"forceTalkieText\", forceTalkieText ? 1 : 0},\n          {\"selectableActors\", selectableActors}\n      };\n    }\n\n    [[nodiscard]] ngf::GGPackValue saveInventory() const {\n      ngf::GGPackValue slots;\n      for (auto &slot : m_pImpl->m_actorsIconSlots) {\n        ngf::GGPackValue actorSlot;\n        if (slot.pActor) {\n          std::vector<int> jiggleArray(slot.pActor->getObjects().size());\n          ngf::GGPackValue objects;\n          int jiggleCount = 0;\n          for (auto &obj : slot.pActor->getObjects()) {\n            jiggleArray[jiggleCount++] = obj->getJiggle() ? 1 : 0;\n            objects.push_back(obj->getKey());\n          }\n          actorSlot = {\n              {\"objects\", objects},\n              {\"scroll\", slot.pActor->getInventoryOffset()},\n          };\n          const auto saveJiggle = std::any_of(jiggleArray.cbegin(),\n                                              jiggleArray.cend(), [](int value) { return value == 1; });\n          if (saveJiggle) {\n            ngf::GGPackValue jiggle;\n            std::copy(jiggleArray.cbegin(),\n                      jiggleArray.cend(),\n                      std::back_inserter(jiggle));\n            actorSlot[\"jiggle\"] = jiggle;\n          }\n        } else {\n          actorSlot = {{\"scroll\", 0}};\n        }\n        slots.push_back(actorSlot);\n      }\n\n      return {\n          {\"slots\", slots},\n      };\n    }\n\n    [[nodiscard]] ngf::GGPackValue saveObjects() const {\n      ngf::GGPackValue hash;\n      for (auto &room : m_pImpl->m_rooms) {\n        for (auto &object : room->getObjects()) {\n          if (object->getType() != ObjectType::Object)\n            continue;\n          auto pRoom = object->getRoom();\n          if (pRoom && pRoom->isPseudoRoom())\n            continue;\n          hash[object->getKey()] = saveObject(object.get());\n        }\n      }\n      return hash;\n    }\n\n    static ngf::GGPackValue savePseudoObjects(const Room *pRoom) {\n      ngf::GGPackValue hashObjects;\n      for (const auto &pObj : pRoom->getObjects()) {\n        hashObjects[pObj->getKey()] = saveObject(pObj.get());\n      }\n      return hashObjects;\n    }\n\n    static ngf::GGPackValue saveObject(const Object *pObject) {\n      auto hashObject = ng::toGGPackValue(pObject->getTable());\n      if (pObject->getState() != 0) {\n        hashObject[\"_state\"] = pObject->getState();\n      }\n      if (!pObject->isTouchable()) {\n        hashObject[\"_touchable\"] = 0;\n      }\n      // this is the way to compare 2 vectors... not so simple\n      if (glm::any(glm::epsilonNotEqual(pObject->getOffset(), glm::vec2(0, 0), 1e-6f))) {\n        hashObject[\"_offset\"] = toString(pObject->getOffset());\n      }\n      return hashObject;\n    }\n\n    [[nodiscard]] ngf::GGPackValue saveRooms() const {\n      ngf::GGPackValue hash;\n      for (auto &room : m_pImpl->m_rooms) {\n        auto hashRoom = ng::toGGPackValue(room->getTable());\n        if (room->isPseudoRoom()) {\n          hashRoom[pseudoObjectsKey] = savePseudoObjects(room.get());\n        }\n        hash[room->getName()] = hashRoom;\n      }\n      return hash;\n    }\n\n    [[nodiscard]] ngf::GGPackValue saveCallbacks() const {\n      ngf::GGPackValue callbacksArray;\n      for (auto &callback : m_pImpl->m_callbacks) {\n        ngf::GGPackValue callbackHash{\n            {\"function\", callback->getMethod()},\n            {\"guid\", callback->getId()},\n            {\"time\", callback->getElapsed().getTotalMilliseconds()}\n        };\n        auto arg = callback->getArgument();\n        if (arg._type != OT_NULL) {\n          callbackHash[\"param\"] = ng::toGGPackValue(arg);\n        }\n        callbacksArray.push_back(callbackHash);\n      }\n\n      auto &resourceManager = Locator<EntityManager>::get();\n      auto id = resourceManager.getCallbackId();\n      resourceManager.setCallbackId(id);\n\n      return {\n          {\"callbacks\", callbacksArray},\n          {\"nextGuid\", id},\n      };\n    }\n\n    void loadGlobals(const ngf::GGPackValue &hash) {\n      SQTable *pRootTable = _table(ScriptEngine::getVm()->_roottable);\n      SQObjectPtr gObject;\n      pRootTable->Get(ScriptEngine::toSquirrel(\"g\"), gObject);\n      SQTable *gTable = _table(gObject);\n      for (const auto &variable : hash.items()) {\n        gTable->Set(ScriptEngine::toSquirrel(variable.key()), toSquirrel(variable.value()));\n      }\n    }\n\n    static std::string toString(const glm::vec2 &pos) {\n      std::ostringstream os;\n      os << \"{\" << static_cast<int>(pos.x) << \",\" << static_cast<int>(pos.y) << \"}\";\n      return os.str();\n    }\n\n    static std::string toString(const glm::ivec2 &pos) {\n      std::ostringstream os;\n      os << \"{\" << pos.x << \",\" << pos.y << \"}\";\n      return os.str();\n    }\n\n  private:\n    Impl *m_pImpl{nullptr};\n  };\n\n  Engine *m_pEngine{nullptr};\n  ResourceManager &m_resourceManager;\n  Room *m_pRoom{nullptr};\n  int m_roomEffect{0};\n  ngf::Shader m_roomShader;\n  ngf::Shader m_fadeShader;\n  ngf::Texture m_blackTexture;\n  std::vector<std::unique_ptr<Actor>> m_actors;\n  std::vector<std::unique_ptr<Room>> m_rooms;\n  std::vector<std::unique_ptr<Function>> m_newFunctions;\n  std::vector<std::unique_ptr<Function>> m_functions;\n  std::vector<std::unique_ptr<Callback>> m_callbacks;\n  Cutscene *m_pCutscene{nullptr};\n  ng::EnggeApplication *m_pApp{nullptr};\n  Actor *m_pCurrentActor{nullptr};\n  bool m_inputHUD{false};\n  bool m_inputActive{false};\n  bool m_showCursor{true};\n  bool m_inputVerbsActive{false};\n  Actor *m_pFollowActor{nullptr};\n  Entity *m_pUseObject{nullptr};\n  int m_objId1{0};\n  Entity *m_pObj2{nullptr};\n  glm::vec2 m_mousePos{0, 0};\n  glm::vec2 m_mousePosInRoom{0, 0};\n  std::unique_ptr<VerbExecute> m_pVerbExecute;\n  std::unique_ptr<ScriptExecute> m_pScriptExecute;\n  std::vector<std::unique_ptr<ThreadBase>> m_threads;\n  DialogManager m_dialogManager;\n  Preferences &m_preferences;\n  SoundManager &m_soundManager;\n  CursorDirection m_cursorDirection{CursorDirection::None};\n  std::array<ActorIconSlot, 6> m_actorsIconSlots;\n  UseFlag m_useFlag{UseFlag::None};\n  ActorIcons m_actorIcons;\n  ngf::TimeSpan m_time;\n  bool m_isMouseDown{false};\n  ngf::TimeSpan m_mouseDownTime;\n  bool m_isMouseRightDown{false};\n  int m_frameCounter{0};\n  HSQOBJECT m_pDefaultObject{};\n  Camera m_camera;\n  std::unique_ptr<Sentence> m_pSentence{};\n  std::unordered_set<Input, InputHash> m_oldKeyDowns;\n  std::unordered_set<Input, InputHash> m_newKeyDowns;\n  EngineState m_state{EngineState::StartScreen};\n  TalkingState m_talkingState;\n  WalkboxesFlags m_showDrawWalkboxes{WalkboxesFlags::None};\n  OptionsDialog m_optionsDialog;\n  StartScreenDialog m_startScreenDialog;\n  bool m_run{false};\n  ngf::TimeSpan m_noOverrideElapsed{ngf::TimeSpan::seconds(2)};\n  Hud m_hud;\n  bool m_autoSave{true};\n  bool m_cursorVisible{true};\n  FadeEffectParameters m_fadeEffect;\n\n  Impl();\n\n  void drawHud(ngf::RenderTarget &target) const;\n  void drawCursor(ngf::RenderTarget &target) const;\n  void drawCursorText(ngf::RenderTarget &target) const;\n  void drawNoOverride(ngf::RenderTarget &target) const;\n  void drawActorHotspot(ngf::RenderTarget &target) const;\n  void drawObjectHotspot(const Object &obj, ngf::RenderTarget &target) const;\n  void drawDebugHotspot(const Object &object, ngf::RenderTarget &target) const;\n  static void drawScreenSpace(const Object &object, ngf::RenderTarget &target, ngf::RenderStates states);\n  glm::vec2 roomToScreen(const glm::vec2 &pos) const;\n  ngf::irect roomToScreen(const ngf::irect &rect) const;\n  int getCurrentActorIndex() const;\n  ngf::irect getCursorRect() const;\n  void appendUseFlag(std::wstring &sentence) const;\n  bool clickedAt(const glm::vec2 &pos) const;\n  void updateCutscene(const ngf::TimeSpan &elapsed);\n  void updateFunctions(const ngf::TimeSpan &elapsed);\n  void updateActorIcons(const ngf::TimeSpan &elapsed);\n  void updateSentence(const ngf::TimeSpan &elapsed) const;\n  void updateMouseCursor();\n  void updateHoveredEntity(bool isRightClick);\n  SQInteger enterRoom(Room *pRoom, Object *pObject) const;\n  SQInteger exitRoom(Object *pObject);\n  void updateRoomScalings() const;\n  void setCurrentRoom(Room *pRoom);\n  uint32_t getFlags(int id) const;\n  uint32_t getFlags(Entity *pEntity) const;\n  Entity *getHoveredEntity(const glm::vec2 &mousPos);\n  void actorEnter() const;\n  void actorExit() const;\n  static void onLanguageChange(const std::string &lang);\n  void onVerbClick(const Verb *pVerb);\n  void updateKeyboard();\n  bool isKeyPressed(const Input &key);\n  void updateKeys();\n  static InputConstants toKey(const std::string &keyText);\n  void drawPause(ngf::RenderTarget &target) const;\n  void stopThreads();\n  void drawWalkboxes(ngf::RenderTarget &target) const;\n  const Verb *getHoveredVerb() const;\n  static std::wstring getDisplayName(const std::wstring &name);\n  void run(bool state);\n  void stopTalking() const;\n  void stopTalkingExcept(Entity *pEntity) const;\n  Entity *getEntity(Entity *pEntity) const;\n  const Verb *overrideVerb(const Verb *pVerb) const;\n  void captureScreen(const std::string &path) const;\n  void skipText() const;\n  void skipCutscene();\n  void pauseGame();\n  void selectActor(int index);\n  void selectPreviousActor();\n  void selectNextActor();\n  bool hasFlag(int id, uint32_t flagToTest) const;\n};\n}"
  },
  {
    "path": "src/Engine/EngineSettings.cpp",
    "content": "#include <sstream>\n#include <filesystem>\n#include \"engge/System/Locator.hpp\"\n#include \"engge/System/Logger.hpp\"\n#include \"engge/Engine/Preferences.hpp\"\n#include \"engge/Engine/EngineSettings.hpp\"\n#include \"../Util/Util.hpp\"\nnamespace fs = std::filesystem;\n\nnamespace {\nvoid throwEntryNotFound(const std::string &name) {\n  std::string s;\n  s = \"File '\" + name + \"' not found in ggpack files.\";\n  throw std::logic_error(s);\n}\n}\n\nnamespace ng {\nstd::filesystem::path EngineSettings::getPath() const {\n  auto devPath = ng::Locator<ng::Preferences>::get().getUserPreference(PreferenceNames::EnggeDevPath,\n                                                                       PreferenceDefaultValues::EnggeDevPath);\n  return devPath.empty() ? fs::current_path() : fs::path(devPath);\n}\n\nvoid EngineSettings::loadPacks() {\n  auto path = getPath();\n  for (const auto &entry : fs::directory_iterator(path)) {\n    if (ng::startsWith(entry.path().extension().string(), \".ggpack\")) {\n      auto pack = std::make_unique<ngf::GGPack>();\n      info(\"Opening pack '{}'...\", entry.path().string());\n      pack->open(entry.path().string());\n      m_packs.push_back(std::move(pack));\n    }\n  }\n}\n\nbool EngineSettings::hasEntry(const std::string &name) {\n  std::ifstream is;\n  is.open(name);\n  if (is.is_open()) {\n    is.close();\n    return true;\n  }\n  auto it = std::find_if(m_packs.cbegin(), m_packs.cend(), [&name](const auto &pack) {\n    return pack->contains(name);\n  });\n  return it != m_packs.end();\n}\n\nstd::vector<char> EngineSettings::readBuffer(const std::string &name) const {\n  // first try to find the resource in the filesystem\n  std::ifstream is;\n  is.open(name);\n  if (is.is_open()) {\n    is.seekg(0, std::ios::end);\n    auto size = is.tellg();\n    std::vector<char> data;\n    data.resize(size);\n    is.seekg(0, std::ios::beg);\n    is.read(data.data(), size);\n    is.close();\n    return data;\n  }\n\n  // not found in filesystem, check in the pack files\n  auto it = std::find_if(m_packs.cbegin(), m_packs.cend(), [&name](const auto &pack) {\n    return pack->contains(name);\n  });\n  if (it != m_packs.end()) {\n    return it->get()->readEntry(name);\n  }\n  throwEntryNotFound(name);\n  assert(false);\n}\n\nngf::GGPackValue EngineSettings::readEntry(const std::string &name) const {\n  auto it = std::find_if(m_packs.cbegin(), m_packs.cend(), [&name](const auto &pack) {\n    return pack->contains(name);\n  });\n  if (it != m_packs.end()) {\n    return it->get()->readHashEntry(name);\n  }\n  throwEntryNotFound(name);\n  assert(false);\n}\n\n} // namespace ng\n"
  },
  {
    "path": "src/Engine/EntityManager.cpp",
    "content": "#include <algorithm>\n#include <engge/Audio/SoundId.hpp>\n#include <engge/Audio/SoundManager.hpp>\n#include <engge/Engine/Cutscene.hpp>\n#include <engge/Engine/Engine.hpp>\n#include <engge/Engine/EntityManager.hpp>\n#include <engge/Engine/Light.hpp>\n#include <engge/Engine/ThreadBase.hpp>\n#include <engge/Entities/Object.hpp>\n#include <engge/Entities/Actor.hpp>\n#include <engge/Room/Room.hpp>\n#include <engge/System/Locator.hpp>\n\nnamespace ng {\nActor *EntityManager::getActorFromId(int id) {\n  if (!EntityManager::isActor(id))\n    return nullptr;\n\n  for (auto &&actor : ng::Locator<ng::Engine>::get().getActors()) {\n    if (actor->getId() == id)\n      return actor.get();\n  }\n  return nullptr;\n}\n\nObject *EntityManager::getObjectFromId(int id) {\n  if (!EntityManager::isObject(id))\n    return nullptr;\n  auto currentRoom = ng::Locator<ng::Engine>::get().getRoom();\n  if (currentRoom) {\n    for (auto &&obj : currentRoom->getObjects()) {\n      if (obj->getId() == id)\n        return obj.get();\n    }\n  }\n  for (auto &&room : ng::Locator<ng::Engine>::get().getRooms()) {\n    for (auto &&obj : room->getObjects()) {\n      if (obj->getId() == id)\n        return obj.get();\n    }\n  }\n  return nullptr;\n}\n\nRoom *EntityManager::getRoomFromId(int id) {\n  if (!EntityManager::isRoom(id))\n    return nullptr;\n  for (auto &&room : ng::Locator<ng::Engine>::get().getRooms()) {\n    if (room->getId() == id)\n      return room.get();\n  }\n  return nullptr;\n}\n\nSound *EntityManager::getSoundFromId(int id) {\n  if (!EntityManager::isSound(id))\n    return nullptr;\n\n  for (auto sound : ng::Locator<ng::Engine>::get().getSoundManager().getSoundDefinitions()) {\n    if (sound->getId() == id)\n      return sound.get();\n  }\n\n  for (auto sound : ng::Locator<ng::Engine>::get().getSoundManager().getSounds()) {\n    if (sound && sound->getId() == id)\n      return sound.get();\n  }\n  return nullptr;\n}\n\nThreadBase *EntityManager::getThreadFromId(int id) {\n  if (!EntityManager::isThread(id))\n    return nullptr;\n\n  auto &threads = ng::Locator<ng::Engine>::get().getThreads();\n  auto it = std::find_if(threads.begin(), threads.end(), [id](auto &t) -> bool {\n    return t->getId() == id;\n  });\n  if (it != threads.end())\n    return (*it).get();\n\n  return nullptr;\n}\n\nThreadBase *EntityManager::getThreadFromVm(HSQUIRRELVM v) {\n  auto pCutscene = ng::Locator<ng::Engine>::get().getCutscene();\n  if (pCutscene && pCutscene->getThread() == v) {\n    return pCutscene;\n  }\n\n  auto &threads = ng::Locator<ng::Engine>::get().getThreads();\n  auto it = std::find_if(threads.begin(), threads.end(), [v](auto &t) -> bool {\n    return t->getThread() == v;\n  });\n  if (it != threads.end())\n    return (*it).get();\n\n  return nullptr;\n}\n\nEntity *EntityManager::getEntity(HSQUIRRELVM v, SQInteger index) {\n  return EntityManager::getScriptObject<Entity>(v, index);\n}\n\nObject *EntityManager::getObject(HSQUIRRELVM v, SQInteger index) {\n  return EntityManager::getScriptObject<Object>(v, index);\n}\n\nRoom *EntityManager::getRoom(HSQUIRRELVM v, SQInteger index) { return EntityManager::getScriptObject<Room>(v, index); }\n\nActor *EntityManager::getActor(HSQUIRRELVM v, SQInteger index) {\n  return EntityManager::getScriptObject<Actor>(v,\n                                               index);\n}\n\nSoundId *EntityManager::getSound(HSQUIRRELVM v, SQInteger index) {\n  return EntityManager::getScriptObject<SoundId>(v,\n                                                 index);\n}\n\nstd::shared_ptr<SoundDefinition> EntityManager::getSoundDefinition(HSQUIRRELVM v,\n                                                                   SQInteger index) {\n  auto type = sq_gettype(v, index);\n  // is it a table?\n  if (type != OT_TABLE) {\n    return nullptr;\n  }\n\n  HSQOBJECT object;\n  sq_resetobject(&object);\n  if (SQ_FAILED(sq_getstackobj(v, index, &object))) {\n    return nullptr;\n  }\n\n  sq_pushobject(v, object);\n  sq_pushstring(v, _SC(\"_id\"), -1);\n  if (SQ_FAILED(sq_rawget(v, -2))) {\n    return nullptr;\n  }\n\n  SQInteger id = 0;\n  if (SQ_FAILED(sq_getinteger(v, -1, &id))) {\n    return nullptr;\n  }\n  sq_pop(v, 2);\n\n  if (EntityManager::isSound(id)) {\n    for (auto sound : ng::Locator<ng::Engine>::get().getSoundManager().getSoundDefinitions()) {\n      if (sound->getId() == id) {\n        return sound;\n      }\n    }\n  }\n\n  return nullptr;\n}\n\nstd::shared_ptr<SoundDefinition> EntityManager::getSoundDefinition(HSQUIRRELVM v, const std::string &name) {\n  auto top = sq_gettop(v);\n  sq_pushroottable(v);\n  sq_pushstring(v, name.data(), -1);\n  sq_get(v, -2);\n\n  auto sound = getSoundDefinition(v, -1);\n  sq_settop(v, top);\n  return sound;\n}\n\nbool EntityManager::tryGetLight(HSQUIRRELVM v, SQInteger index, Light *&light) {\n  HSQOBJECT obj;\n  light = nullptr;\n  if (SQ_SUCCEEDED(sq_getstackobj(v, index, &obj)) && sq_isinteger(obj) && sq_objtointeger(&obj) == 0) {\n    return false;\n  }\n  light = EntityManager::getScriptObject<Light>(v, index);\n  return true;\n}\n}"
  },
  {
    "path": "src/Engine/Hud.cpp",
    "content": "#include <ngf/Graphics/Sprite.h>\n#include \"engge/Engine/Hud.hpp\"\n#include \"engge/Engine/Preferences.hpp\"\n#include \"engge/Graphics/Screen.hpp\"\n#include \"engge/Graphics/SpriteSheet.hpp\"\n#include \"engge/Scripting/ScriptEngine.hpp\"\n#include \"engge/System/Locator.hpp\"\n#include \"Shaders.hpp\"\n\nnamespace ng {\nHud::Hud() {\n  glm::vec2 size(Screen::Width / 6.f, Screen::Height / 14.f);\n  for (int i = 0; i < 9; i++) {\n    auto left = static_cast<float>(i / 3) * size.x;\n    auto top = Screen::Height - size.y * 3 + static_cast<float>(i % 3) * size.y;\n    m_verbRects.at(i) = ngf::irect::fromPositionSize({left, top}, {size.x, size.y});\n  }\n\n  m_verbShader.load(Shaders::verbVertexShaderCode, Shaders::verbFragmentShaderCode);\n}\n\nHud::~Hud() = default;\n\nbool Hud::isMouseOver() const {\n  if (!m_active)\n    return false;\n  return m_mousePos.y >= m_verbRects.at(0).getTopLeft().y;\n}\n\nvoid Hud::setTextureManager(ResourceManager *pTextureManager) {\n  m_inventory.setTextureManager(pTextureManager);\n}\n\nvoid Hud::setVerb(int characterSlot, int verbSlot, const Verb &verb) {\n  m_verbSlots.at(characterSlot).setVerb(verbSlot, verb);\n}\n\n[[nodiscard]] const VerbSlot &Hud::getVerbSlot(int characterSlot) const {\n  return m_verbSlots.at(characterSlot);\n}\n\nvoid Hud::setVerbUiColors(int characterSlot, VerbUiColors colors) {\n  m_verbUiColors.at(characterSlot) = colors;\n}\n\n[[nodiscard]] const VerbUiColors &Hud::getVerbUiColors(int characterSlot) const {\n  return m_verbUiColors.at(characterSlot);\n}\n\nvoid Hud::draw(ngf::RenderTarget &target, ngf::RenderStates) const {\n  if (!m_isVisible)\n    return;\n  if (m_currentActorIndex == -1 || getVerbSlot(m_currentActorIndex).getVerb(0).id == 0)\n    return;\n\n  auto pVerb = m_pVerbOverride;\n  if (!pVerb) {\n    pVerb = m_pVerb;\n  }\n  auto verbId = pVerb->id;\n  if (m_pHoveredEntity && verbId == VerbConstants::VERB_WALKTO) {\n    verbId = m_pHoveredEntity->getDefaultVerb(VerbConstants::VERB_LOOKAT);\n  } else {\n    for (int i = 0; i < static_cast<int>(m_verbRects.size()); i++) {\n      if (m_verbRects.at(i).contains((glm::ivec2) m_mousePos)) {\n        verbId = m_verbSlots.at(m_currentActorIndex).getVerb(1 + i).id;\n        break;\n      }\n    }\n  }\n\n  const auto view = target.getView();\n  target.setView(ngf::View(ngf::frect::fromPositionSize({0, 0}, {Screen::Width, Screen::Height})));\n\n  // draw UI background\n  const auto &preferences = Locator<Preferences>::get();\n  auto hudSentence = preferences.getUserPreference(PreferenceNames::HudSentence, PreferenceDefaultValues::HudSentence);\n  auto uiBackingAlpha =\n      preferences.getUserPreference(PreferenceNames::UiBackingAlpha, PreferenceDefaultValues::UiBackingAlpha);\n  auto invertVerbHighlight = preferences.getUserPreference(PreferenceNames::InvertVerbHighlight,\n                                                           PreferenceDefaultValues::InvertVerbHighlight);\n  const auto &verbUiColors = getVerbUiColors(m_currentActorIndex);\n  auto verbHighlight = invertVerbHighlight ? ngf::Colors::White : verbUiColors.verbHighlight;\n  auto verbColor = invertVerbHighlight ? verbUiColors.verbHighlight : ngf::Colors::White;\n  auto &gameSheet = Locator<ResourceManager>::get().getSpriteSheet(\"GameSheet\");\n  auto uiBackingRect = hudSentence ? gameSheet.getRect(\"ui_backing_tall\") : gameSheet.getRect(\"ui_backing\");\n\n  ngf::Sprite uiBacking(*gameSheet.getTexture(), uiBackingRect);\n  uiBacking.setColor(ngf::Color(0.f, 0.f, 0.f, uiBackingAlpha * m_alpha));\n  uiBacking.getTransform().setPosition({0, 720.f - uiBackingRect.getHeight()});\n  uiBacking.draw(target, {});\n\n  m_verbShader.setUniform(\"u_ranges\", glm::vec2(0.8f, 0.8f));\n  m_verbShader.setUniform4(\"u_shadowColor\", verbUiColors.verbNormalTint);\n  m_verbShader.setUniform4(\"u_normalColor\", verbUiColors.verbHighlight);\n  m_verbShader.setUniform4(\"u_highlightColor\", verbUiColors.verbHighlightTint);\n\n  ngf::RenderStates verbStates;\n  verbStates.shader = &m_verbShader;\n  auto &verbSheet = Locator<ResourceManager>::get().getSpriteSheet(\"VerbSheet\");\n  for (int i = 1; i <= 9; i++) {\n    auto verb = getVerbSlot(m_currentActorIndex).getVerb(i);\n    auto color = verb.id == verbId ? verbHighlight : verbColor;\n    color.a = m_alpha;\n\n    auto verbName = getVerbName(verb);\n    auto rect = verbSheet.getRect(verbName);\n    auto s = verbSheet.getSpriteSourceSize(verbName);\n    ngf::Sprite verbSprite(*verbSheet.getTexture(), rect);\n    verbSprite.setColor(color);\n    verbSprite.getTransform().setPosition(s.getTopLeft());\n    verbSprite.draw(target, verbStates);\n  }\n\n  target.setView(view);\n\n  m_inventory.draw(target, {});\n}\n\nvoid Hud::setCurrentActorIndex(int index) {\n  m_currentActorIndex = index;\n  m_inventory.setCurrentActorIndex(index);\n  m_inventory.setVerbUiColors(&getVerbUiColors(m_currentActorIndex));\n}\n\nvoid Hud::setCurrentActor(Actor *pActor) {\n  m_inventory.setCurrentActor(pActor);\n}\n\nglm::vec2 Hud::findScreenPosition(int verbId) const {\n  auto pVerb = getVerb(verbId);\n  auto s = getVerbName(*pVerb);\n  auto &verbSheet = Locator<ResourceManager>::get().getSpriteSheet(\"VerbSheet\");\n  auto r = verbSheet.getSpriteSourceSize(s);\n  return glm::vec2(r.getTopLeft().x + r.getWidth() / 2.f, Screen::Height - (r.getTopLeft().y + r.getHeight() / 2.f));\n}\n\nconst Verb *Hud::getVerb(int id) const {\n  auto index = m_currentActorIndex;\n  if (index < 0)\n    return nullptr;\n  const auto &verbSlot = getVerbSlot(index);\n  for (auto i = 0; i < 10; i++) {\n    const auto &verb = verbSlot.getVerb(i);\n    if (verb.id == id) {\n      return &verb;\n    }\n  }\n  return nullptr;\n}\n\nstd::string Hud::getVerbName(const Verb &verb) {\n  const auto &preferences = Locator<Preferences>::get();\n  auto lang = preferences.getUserPreference(PreferenceNames::Language, PreferenceDefaultValues::Language);\n  auto isRetro = preferences.getUserPreference(PreferenceNames::RetroVerbs, PreferenceDefaultValues::RetroVerbs);\n  std::string s;\n  s.append(verb.image).append(isRetro ? \"_retro\" : \"\").append(\"_\").append(lang);\n  return s;\n}\n\nvoid Hud::setMousePosition(glm::vec2 pos) {\n  m_mousePos = pos;\n  m_inventory.setMousePosition(pos);\n}\n\nconst Verb *Hud::getHoveredVerb() const {\n  if (m_currentActorIndex == -1)\n    return nullptr;\n\n  for (int i = 0; i < static_cast<int>(m_verbRects.size()); i++) {\n    if (m_verbRects.at(i).contains((glm::ivec2) m_mousePos)) {\n      auto verbId = getVerbSlot(m_currentActorIndex).getVerb(1 + i).id;\n      return getVerb(verbId);\n    }\n  }\n  return nullptr;\n}\n\nvoid Hud::update(const ngf::TimeSpan &elapsed) {\n  if (m_state == State::FadeIn) {\n    m_alpha += elapsed.getTotalSeconds();\n    if (m_alpha >= 1.f) {\n      m_state = State::On;\n      m_alpha = 1.f;\n    }\n  } else if (m_state == State::FadeOut) {\n    m_alpha -= elapsed.getTotalSeconds();\n    if (m_alpha <= 0.f) {\n      m_state = State::Off;\n      m_alpha = 0.f;\n    }\n  }\n  m_inventory.setAlpha(m_alpha);\n  m_inventory.update(elapsed);\n}\n\nvoid Hud::setActive(bool active) {\n  if (!m_active && active) {\n    m_state = State::FadeIn;\n  } else if (m_active && !active) {\n    m_state = State::FadeOut;\n  }\n  m_active = active;\n}\n}"
  },
  {
    "path": "src/Engine/Inventory.cpp",
    "content": "#include <algorithm>\n#include <ngf/Graphics/RectangleShape.h>\n#include <ngf/Graphics/Sprite.h>\n#include <ngf/System/Mouse.h>\n#include <engge/Engine/Engine.hpp>\n#include <engge/Engine/Inventory.hpp>\n#include <engge/Entities/Object.hpp>\n#include <engge/Engine/Preferences.hpp>\n#include <engge/Room/Room.hpp>\n#include <engge/Graphics/Screen.hpp>\n#include <engge/System/Locator.hpp>\n\nnamespace ng {\n\nvoid Inventory::setTextureManager(ResourceManager *pTextureManager) {\n  m_gameSheet.setTextureManager(pTextureManager);\n  m_gameSheet.load(\"GameSheet\");\n\n  m_inventoryItems.setTextureManager(pTextureManager);\n  m_inventoryItems.load(\"InventoryItems\");\n\n  // compute all inventory rects\n  auto scrollUpFrameRect = m_gameSheet.getRect(\"scroll_up\");\n  auto inventoryRect = m_gameSheet.getRect(\"inventory_background\");\n\n  m_scrollUpRect = ngf::frect::fromPositionSize({Screen::Width - 627.f, Screen::Height - 167.f},\n                                                {static_cast<float>(scrollUpFrameRect.getWidth()),\n                                                static_cast<float>(scrollUpFrameRect.getHeight())});\n  m_scrollDownRect = ngf::frect::fromPositionSize({Screen::Width - 627.f, Screen::Height - 73.f},\n                                                  {static_cast<float>(scrollUpFrameRect.getWidth()),\n                                                  static_cast<float>(scrollUpFrameRect.getHeight())});\n\n  glm::vec2 sizeBack = {static_cast<float>(inventoryRect.getWidth()), static_cast<float>(inventoryRect.getHeight())};\n  glm::vec2 scrollUpSize(scrollUpFrameRect.getWidth(), scrollUpFrameRect.getHeight());\n  glm::vec2 scrollUpMargin(4, 7);\n\n  auto startX = sizeBack.x / 2.f + m_scrollUpRect.getTopLeft().x + scrollUpSize.x + scrollUpMargin.x;\n  auto startY = sizeBack.y / 2.f + m_scrollUpRect.getTopLeft().y;\n\n  auto x = 0, y = 0;\n  glm::vec2 gap = {7.f, 7.f};\n\n  for (size_t i = 0; i < 8; i++) {\n    m_inventoryRects[i] = ngf::frect::fromPositionSize({x + startX, y + startY}, {sizeBack.x, sizeBack.y});\n    if ((i % 4) == 3) {\n      x = 0;\n      y += sizeBack.y + gap.y;\n    } else {\n      x += sizeBack.x + gap.x;\n    }\n  }\n}\n\nbool Inventory::update(const ngf::TimeSpan &elapsed) {\n  m_jiggleTime += 20.f * elapsed.getTotalSeconds();\n  m_pCurrentInventoryObject = nullptr;\n\n  if (m_pCurrentActor == nullptr)\n    return false;\n\n  auto inventoryOffset = m_pCurrentActor->getInventoryOffset();\n  for (size_t i = 0; i < m_inventoryRects.size(); i++) {\n    auto r = m_inventoryRects.at(i);\n    r.min.x -= r.getWidth() / 2.f;\n    r.min.y -= r.getHeight() / 2.f;\n    r.max.x -= r.getWidth() / 2.f;\n    r.max.y -= r.getHeight() / 2.f;\n    if (r.contains(m_mousePos)) {\n      auto &objects = m_pCurrentActor->getObjects();\n      if ((inventoryOffset * 4 + i) < objects.size()) {\n        m_pCurrentInventoryObject = objects[inventoryOffset * 4 + i];\n        return false;\n      }\n    }\n  }\n\n  auto mouseDown = ngf::Mouse::isButtonPressed(ngf::Mouse::Button::Left);\n  if (!m_mouseWasDown || mouseDown) {\n    m_mouseWasDown = mouseDown;\n    return false;\n  }\n\n  m_mouseWasDown = mouseDown;\n\n  if (hasUpArrow()) {\n    if (m_scrollUpRect.contains(m_mousePos)) {\n      m_pCurrentActor->setInventoryOffset(inventoryOffset - 1);\n      return true;\n    }\n  }\n\n  if (hasDownArrow()) {\n    if (m_scrollDownRect.contains(m_mousePos)) {\n      m_pCurrentActor->setInventoryOffset(inventoryOffset + 1);\n      return true;\n    }\n  }\n  return false;\n}\n\nvoid Inventory::drawUpArrow(ngf::RenderTarget &target) const {\n  if (!hasUpArrow())\n    return;\n\n  const auto &preferences = Locator<Preferences>::get();\n  auto isRetro =\n      preferences.getUserPreference(PreferenceNames::RetroVerbs, PreferenceDefaultValues::RetroVerbs);\n  auto rect = m_gameSheet.getRect(isRetro ? \"scroll_up_retro\" : \"scroll_up\");\n\n  auto color = m_pColors->verbNormal;\n  color.a = m_alpha;\n\n  glm::vec2 scrollUpSize(rect.getWidth(), rect.getHeight());\n  ngf::RectangleShape scrollUpShape;\n  scrollUpShape.setColor(color);\n  scrollUpShape.getTransform().setPosition(m_scrollUpRect.getTopLeft());\n  scrollUpShape.setSize(scrollUpSize);\n  scrollUpShape.setTexture(*m_gameSheet.getTexture(), false);\n  scrollUpShape.setTextureRect(m_gameSheet.getTexture()->computeTextureCoords(rect));\n  scrollUpShape.draw(target, {});\n}\n\nvoid Inventory::drawDownArrow(ngf::RenderTarget &target) const {\n  if (!hasDownArrow())\n    return;\n\n  const auto &preferences = Locator<Preferences>::get();\n  auto isRetro =\n      preferences.getUserPreference(PreferenceNames::RetroVerbs, PreferenceDefaultValues::RetroVerbs);\n\n  auto scrollDownFrameRect = m_gameSheet.getRect(isRetro ? \"scroll_down_retro\" : \"scroll_down\");\n  glm::vec2 scrollDownSize(scrollDownFrameRect.getWidth(), scrollDownFrameRect.getHeight());\n\n  auto color = m_pColors->verbNormal;\n  color.a = m_alpha;\n\n  ngf::RectangleShape scrollDownShape;\n  scrollDownShape.setColor(color);\n  scrollDownShape.getTransform().setPosition(m_scrollDownRect.getTopLeft());\n  scrollDownShape.setSize(scrollDownSize);\n  scrollDownShape.setTexture(*m_gameSheet.getTexture(), false);\n  scrollDownShape.setTextureRect(m_gameSheet.getTexture()->computeTextureCoords(scrollDownFrameRect));\n  scrollDownShape.draw(target, {});\n}\n\nbool Inventory::hasUpArrow() const {\n  auto inventoryOffset = m_pCurrentActor->getInventoryOffset();\n  return inventoryOffset != 0;\n}\n\nbool Inventory::hasDownArrow() const {\n  const auto &objects = m_pCurrentActor->getObjects();\n  auto inventoryOffset = m_pCurrentActor->getInventoryOffset();\n  return static_cast<int>(objects.size()) > (inventoryOffset * 4 + 8);\n}\n\nvoid Inventory::draw(ngf::RenderTarget &target, ngf::RenderStates) const {\n  if (m_currentActorIndex == -1)\n    return;\n\n  const auto view = target.getView();\n  target.setView(ngf::View(ngf::frect::fromPositionSize({0, 0}, {Screen::Width, Screen::Height})));\n\n  auto color = ngf::Colors::White;\n  color.a = m_alpha;\n\n  // draw inventory items\n  ngf::Color c(m_pColors->inventoryBackground);\n  c.a = m_alpha * 0.5f;\n\n  auto inventoryRect = m_gameSheet.getRect(\"inventory_background\");\n  ngf::Sprite inventoryShape;\n  inventoryShape.setColor(c);\n  inventoryShape.setTexture(*m_gameSheet.getTexture());\n  inventoryShape.setTextureRect(inventoryRect);\n  for (auto i = 0; i < 8; i++) {\n    inventoryShape.getTransform().setPosition(m_inventoryRects[i].getTopLeft());\n    inventoryShape.getTransform().setOrigin({m_inventoryRects[i].getWidth() / 2.f,\n                                             m_inventoryRects[i].getHeight() / 2.f});\n    inventoryShape.draw(target);\n  }\n\n  // draw inventory objects\n  if (!m_pCurrentActor) {\n    target.setView(view);\n    return;\n  }\n\n  auto &objects = m_pCurrentActor->getObjects();\n  drawUpArrow(target);\n  drawDownArrow(target);\n\n  auto inventoryOffset = m_pCurrentActor->getInventoryOffset();\n  auto count = std::min((size_t) 8, objects.size() - inventoryOffset * 4);\n  for (size_t i = 0; i < count; i++) {\n    auto &object = objects.at(inventoryOffset * 4 + i);\n    auto icon = object->getIcon();\n    auto rect = m_inventoryItems.getRect(icon);\n    auto spriteSourceSize = m_inventoryItems.getSpriteSourceSize(icon);\n    auto sourceSize = m_inventoryItems.getSourceSize(icon);\n    glm::vec2 origin\n        (sourceSize.x / 2.f - spriteSourceSize.getTopLeft().x, sourceSize.y / 2.f - spriteSourceSize.getTopLeft().y);\n\n    ngf::Sprite sprite;\n    sprite.getTransform().setOrigin(origin);\n    if (object->getJiggle()) {\n      sprite.getTransform().setRotation(3.f * sinf(m_jiggleTime));\n    }\n    sprite.getTransform().setPosition(m_inventoryRects[i].getTopLeft());\n    sprite.setTexture(*m_inventoryItems.getTexture());\n    sprite.setTextureRect(rect);\n    if (object->getPop() > 0) {\n      const auto pop = 4.25f + object->getPopScale() * 0.25f;\n      sprite.getTransform().setScale({pop, pop});\n    } else {\n      sprite.getTransform().setScale({4, 4});\n    }\n    sprite.setColor(color);\n    sprite.draw(target, {});\n  }\n  target.setView(view);\n}\n\nglm::vec2 Inventory::getPosition(Object *pObject) const {\n  if (!m_pCurrentActor)\n    return glm::vec2();\n  auto inventoryOffset = m_pCurrentActor->getInventoryOffset() * 4;\n  const auto &objects = m_pCurrentActor->getObjects();\n  auto it = std::find(objects.cbegin(), objects.cend(), pObject);\n  auto index = std::distance(objects.cbegin(), it);\n  if (index >= inventoryOffset && index < (inventoryOffset + 8)) {\n    const auto &rect = m_inventoryRects.at(index - inventoryOffset);\n    return rect.getTopLeft();\n  }\n  return glm::vec2();\n}\n\n} // namespace ng\n"
  },
  {
    "path": "src/Engine/Light.cpp",
    "content": "#include \"engge/Engine/Light.hpp\"\n#include \"engge/System/Locator.hpp\"\n#include \"engge/Engine/EntityManager.hpp\"\n\nnamespace ng {\nLight::Light() {\n  sq_resetobject(&table);\n  m_id = Locator<EntityManager>::get().getLightId();\n}\n\nLight::~Light() = default;\n\n} // namespace ng\n"
  },
  {
    "path": "src/Engine/Preferences.cpp",
    "content": "#include <ngf/IO/Json/JsonParser.h>\n#include \"engge/Engine/Preferences.hpp\"\n\nnamespace ng {\nPreferences::Preferences() {\n  m_values = ngf::Json::load(\"Prefs.json\");\n}\n\nvoid Preferences::save() {\n  std::ofstream os;\n  os.open(\"Prefs.json\");\n  for (auto &&pref : m_values.items()) {\n    os << pref.key() << \": \";\n    if (pref.value().isString()) {\n      os << \"\\\"\" << pref.value().getString() << \"\\\"\";\n    } else if (pref.value().isDouble()) {\n      os << pref.value().getDouble();\n    } else if (pref.value().isInteger()) {\n      os << pref.value().getInt();\n    }\n    os << std::endl;\n  }\n}\n\nvoid Preferences::removeUserPreference(const std::string &name) {\n  auto value = m_values[name];\n  if (!value.isNull()) {\n    // TODO: removeUserPreference\n    //_values.erase(it);\n  }\n}\n\nvoid Preferences::subscribe(const std::function<void(const std::string &)> &function) {\n  m_functions.emplace_back(function);\n}\n\nngf::GGPackValue Preferences::getUserPreferenceCore(const std::string &name,\n                                                    const ngf::GGPackValue &defaultValue) const {\n  auto value = m_values[name];\n  if (!value.isNull()) {\n    return value;\n  }\n  return defaultValue;\n}\n\nngf::GGPackValue Preferences::getTempPreferenceCore(const std::string &name,\n                                                    const ngf::GGPackValue &defaultValue) const {\n  auto value = m_tempValues[name];\n  if (!value.isNull()) {\n    return value;\n  }\n  return defaultValue;\n}\n\ntemplate<>\nint Preferences::fromGGPackValue<int>(const ngf::GGPackValue &value) {\n  return value.getInt();\n}\n\ntemplate<>\nbool Preferences::fromGGPackValue<bool>(const ngf::GGPackValue &value) {\n  return value.getInt() != 0;\n}\n\ntemplate<>\nstd::string Preferences::fromGGPackValue<std::string>(const ngf::GGPackValue &value) {\n  return value.getString();\n}\n\ntemplate<>\nfloat Preferences::fromGGPackValue<float>(const ngf::GGPackValue &value) {\n  return static_cast<float>(value.getDouble());\n}\n\ntemplate<>\nngf::GGPackValue Preferences::fromGGPackValue<ngf::GGPackValue>(const ngf::GGPackValue &value) {\n  return value;\n}\n\ntemplate<>\nngf::GGPackValue Preferences::toGGPackValue<ngf::GGPackValue>(ngf::GGPackValue value) {\n  return value;\n}\n\ntemplate<>\nngf::GGPackValue Preferences::toGGPackValue<int>(int value) {\n  return value;\n}\n\ntemplate<>\nngf::GGPackValue Preferences::toGGPackValue<bool>(bool value) {\n  return value ? 1 : 0;\n}\n\ntemplate<>\nngf::GGPackValue Preferences::toGGPackValue<float>(float value) {\n  return value;\n}\n\ntemplate<>\nngf::GGPackValue Preferences::toGGPackValue<std::string>(std::string value) {\n  return value;\n}\n\ntemplate<>\nvoid Preferences::setUserPreference(const std::string &name, bool value) {\n  setUserPreference(name, value ? 1 : 0);\n}\n\n} // namespace ng\n"
  },
  {
    "path": "src/Engine/Sentence.cpp",
    "content": "#include \"engge/Engine/Sentence.hpp\"\n\nnamespace ng {\nSentence &Sentence::push_back(std::unique_ptr<Function> func) {\n  m_functions.push_back(std::move(func));\n  return *this;\n}\n\nvoid Sentence::stop() { m_stopped = true; }\n\nbool Sentence::isElapsed() { return m_functions.empty(); }\n\nvoid Sentence::operator()(const ngf::TimeSpan &elapsed) {\n  if (m_functions.empty())\n    return;\n  if (m_stopped) {\n    m_functions.clear();\n    return;\n  }\n  if (m_functions[0]->isElapsed()) {\n    m_functions.erase(m_functions.begin());\n  } else {\n    (*m_functions[0])(elapsed);\n  }\n}\n} // namespace ng\n"
  },
  {
    "path": "src/Engine/Shaders.cpp",
    "content": "#include \"Shaders.hpp\"\n\nnamespace ng {\nconst char *Shaders::vertexShader =\n    R\"(#version 100\nprecision mediump float;\nattribute vec2 a_position;\nattribute vec4 a_color;\nattribute vec2 a_texCoords;\n\nuniform mat3 u_transform;\nvarying vec2 v_texCoords;\nvarying vec4 v_color;\n\nvoid main(void) {\n  v_color = a_color;\n  v_texCoords = a_texCoords;\n\n  vec3 worldPosition = vec3(a_position, 1);\n  vec3 normalizedPosition = worldPosition * u_transform;\n  gl_Position = vec4(normalizedPosition.xy, 0, 1);\n})\";\n\nconst char *Shaders::bwFragmentShader =\n    R\"(#version 100\nprecision mediump float;\nvarying vec2 v_texCoords;\nvarying vec4 v_color;\nuniform sampler2D u_texture;\nvoid main()\n{\n  vec4 texColor = texture2D(u_texture, v_texCoords);\n  vec4 col = v_color * texColor;\n  float gray = dot(col.xyz, vec3(0.299, 0.587, 0.114));\n  gl_FragColor = vec4(gray, gray, gray, col.a);\n})\";\n\nconst char *Shaders::egaFragmenShader =\n    R\"(#version 100\n#ifdef GL_ES\nprecision highp float;\n#endif\n\nvarying vec2 v_texCoords;\nvarying vec4 v_color;\nuniform sampler2D u_texture;\n\nvec3 rgb2hsv(vec3 c)\n{\n    vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\n    vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));\n    vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));\n\n    float d = q.x - min(q.w, q.y);\n    float e = 1.0e-10;\n    return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\n}\n\nfloat dist_sq(vec3 a, vec3 b)\n{\n    vec3 delta = a - b;\n    return dot(delta, delta);\n}\n\nvec3 nearest_rgbi (vec3 orig)\n{\n    vec3 original = rgb2hsv(orig);\n    float min_dst = 4.0;\n    vec3 ret = vec3(1,1,1);\n\n    vec3 pal = vec3(0, 0, 0);\n    float dst = dist_sq(original, pal);\n    if(dst < min_dst) { min_dst = dst; ret = vec3(0.0,     0.0,     0.0); }\n\n    pal = vec3(0.66667, 1, 0.66667);\n    dst = dist_sq(original, pal);\n    if(dst < min_dst) { min_dst = dst; ret = vec3(0.0,     0.0,     0.66667); }\n\n    pal = vec3(0.33333, 1, 0.66667);\n    dst = dist_sq(original, pal);\n    if(dst < min_dst) { min_dst = dst; ret = vec3(0.0,     0.66667, 0.0); }\n\n    pal = vec3(0.5, 1, 0.66667);\n    dst = dist_sq(original, pal);\n    if(dst < min_dst) { min_dst = dst; ret = vec3(0.0,     0.66667, 0.66667); }\n\n    pal = vec3(0, 1, 0.66667);\n    dst = dist_sq(original, pal);\n    if(dst < min_dst) { min_dst = dst; ret = vec3(0.66667, 0.0,     0.0); }\n\n    pal = vec3(0.83333, 1, 0.66667);\n    dst = dist_sq(original, pal);\n    if(dst < min_dst) { min_dst = dst; ret = vec3(0.66667, 0.0,     0.66667); }\n\n    pal = vec3(0.083333, 1, 0.66667);\n    dst = dist_sq(original, pal);\n    if(dst < min_dst) { min_dst = dst; ret = vec3(0.66667, 0.33333, 0.0); }\n\n    pal = vec3(0, 0, 0.666667);\n    dst = dist_sq(original, pal);\n    if(dst < min_dst) { min_dst = dst; ret = vec3(0.66667, 0.66667, 0.66667); }\n\n    pal = vec3(0, 0, 0.333333);\n    dst = dist_sq(original, pal);\n    if(dst < min_dst) { min_dst = dst; ret = vec3(0.33333, 0.33333, 0.33333); }\n\n    pal = vec3(0.66667, 0.66667, 1);\n    dst = dist_sq(original, pal);\n    if(dst < min_dst) { min_dst = dst; ret = vec3(0.33333, 0.33333, 1.0); }\n\n    pal = vec3(0.33333, 0.66667, 1);\n    dst = dist_sq(original, pal);\n    if(dst < min_dst) { min_dst = dst; ret = vec3(0.33333, 1.0,     0.33333); }\n\n    pal = vec3(0.5, 0.66667, 1);\n    dst = dist_sq(original, pal);\n    if(dst < min_dst) { min_dst = dst; ret = vec3(0.33333, 1.0,     1.0); }\n\n    pal = vec3(0, 0.66667, 1);\n    dst = dist_sq(original, pal);\n    if(dst < min_dst) { min_dst = dst; ret = vec3(1.0,     0.33333, 0.33333); }\n\n    pal = vec3(0.83333, 0.66667, 1);\n    dst = dist_sq(original, pal);\n    if(dst < min_dst) { min_dst = dst; ret = vec3(1.0,     0.33333, 1.0); }\n\n    pal = vec3(0.16666, 0.66667, 1);\n    dst = dist_sq(original, pal);\n    if(dst < min_dst) { min_dst = dst; ret = vec3(1.0,     1.0,     0.33333); }\n\n    return ret;\n}\n\nvoid main()\n{\n   vec4 texColor = texture2D( u_texture, v_texCoords );\n   vec4 srcCol = v_color * texColor;\n   vec3 newCol = nearest_rgbi(srcCol.rgb);\n   gl_FragColor = vec4(newCol, srcCol.a);\n})\";\n\nconst char *Shaders::fadeFragmentShader =\n    R\"(#version 100\n#ifdef GL_ES\nprecision highp float;\n#endif\n\nvarying vec2 v_texCoords;\nvarying vec4 v_color;\nuniform sampler2D u_texture;\nuniform sampler2D u_texture2;\n\nuniform float u_timer;\nuniform float u_fade;\nuniform int u_fadeToSep;\nuniform float u_movement;\n\nvoid main()\n{\n   const float RADIUS = 0.75;\n   const float SOFTNESS = 0.45;\n   const float ScratchValue = 0.3;\n   vec2 uv = v_texCoords;\n   float pi2 = (3.142*2.0);\n   float intervals = 4.0;\n   uv.x += sin((u_timer+uv.y)*(pi2*intervals))*u_movement;\n   vec4 texColor1 = v_color * texture2D( u_texture, uv);\n   vec4 texColor2 = v_color * texture2D( u_texture2, uv);\n   if (u_fadeToSep!=0) {\n       float gray = dot(texColor2.rgb, vec3(0.299, 0.587, 0.114));\n       vec2 dist = vec2(uv.x - 0.5, uv.y - 0.5);\n       vec3 sepiaColor = vec3(gray,gray,gray) * vec3(0.9, 0.8, 0.6);\n       float len = dot(dist,dist);\n       float vignette = smoothstep(RADIUS, RADIUS-SOFTNESS, len);\n       vec3 sep = mix(texColor2.rgb, sepiaColor, 0.80) * vignette;\n       gl_FragColor.rgb = (texColor1.rgb*(1.0-u_fade)) + (sep*u_fade);\n   }\n   else {\n       gl_FragColor.rgb = (texColor1.rgb*(1.0-u_fade)) + (texColor2.rgb*u_fade);\n   }\n   gl_FragColor.a = 1.0;\n})\";\n\nconst char *Shaders::ghostFragmentShader =\n    R\"(#version 100\n// Work in progress ghost shader.. Too over the top at the moment, it'll make you sick.\n\n#ifdef GL_ES\nprecision highp float;\n#endif\n\nuniform float iGlobalTime;\nuniform float iFade;\nuniform float wobbleIntensity;\nuniform vec3 shadows;\nuniform vec3 midtones;\nuniform vec3 highlights;\nuniform sampler2D u_texture;\n\nvarying vec2 v_texCoords;\n\nconst float speed = 0.1;\nconst float emboss = 0.70;\nconst float intensity = 0.6;\nconst int steps = 4;\nconst float frequency = 9.0;\n\n\nfloat colour(vec2 coord) {\n    float col = 0.0;\n\n    float timeSpeed = iGlobalTime*speed;\n    vec2 adjc = coord;\n    adjc.x += timeSpeed;   //adjc0.x += fcos*timeSpeed;\n    float sum0 = cos( adjc.x*frequency)*intensity;\n    col += sum0;\n\n    adjc = coord;\n    float fcos = 0.623489797;\n    float fsin = 0.781831503;\n    adjc.x += fcos*timeSpeed;\n    adjc.y -= fsin*timeSpeed;\n    float sum1 = cos( (adjc.x*fcos - adjc.y*fsin)*frequency)*intensity;\n    col += sum1;\n\n    adjc = coord;\n    fcos = -0.900968909;\n    fsin = 0.433883607;\n    adjc.x += fcos*timeSpeed;\n    adjc.y -= fsin*timeSpeed;\n    col += cos( (adjc.x*fcos - adjc.y*fsin)*frequency)*intensity;\n\n    // do same in reverse.\n    col += sum1;\n    col += sum0;\n\n    return cos(col);\n}\n\nvec3 rgb2hsv(vec3 c)\n{\n    vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\n    vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));\n    vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));\n\n    float d = q.x - min(q.w, q.y);\n    float e = 1.0e-10;\n    return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\n}\n\nvec3 hsv2rgb(vec3 c)\n{\n    vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n    vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\n    return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);\n}\n\nfloat rand(vec2 Input)\n{\n    float dt= dot(Input, vec2(12.9898,78.233));\n    float sn= mod(dt,3.14);\n    return fract(sin(sn)*43758.5453123);\n}\n\nfloat color_balance( float col, float l, vec3 change )\n{\n    // NOTE: change = (shadow, midtones, highlights)\n\n    float sup = 83.0;    // shadow upper bounds\n    float mup = 166.0;    // midtones upper bounds\n\n    float value = col*255.0;\n    l = l * 100.0;\n\n    if (l < sup)\n    {\n        // shadow\n        float f = (sup - l + 1.0)/(sup + 1.0);\n        value += change.x * f;\n    }\n    else if (l < mup)\n    {\n        // midtone\n        float mrange = (mup - sup)/2.0;\n        float mid = mrange + sup;\n        float diff = mid - l;\n        diff = -diff;\n        if (diff < 0.0)\n        {\n            float f = 1.0 - (diff + 1.0) / (mrange + 1.0);\n            value += change.y * f;\n        }\n    }\n    else\n    {\n        // highlight\n        float f = (l - mup + 1.0)/(255.0 - mup + 1.0);\n        value += change.z * f;\n    }\n    value = min(255.0,max(0.0,value));\n    return value/255.0;\n}\n\nvec2 rgb2cv(vec3 RGB)\n{\n    vec4 P = (RGB.g < RGB.b) ? vec4(RGB.bg, -1.0, 2.0/3.0) : vec4(RGB.gb, 0.0, -1.0/3.0);\n    vec4 Q = (RGB.r < P.x) ? vec4(P.xyw, RGB.r) : vec4(RGB.r, P.yzx);\n    float C = Q.x - min(Q.w, Q.y);\n    return vec2(C, Q.x);\n}\n\nfloat rgbToLuminance(vec3 RGB)\n{\n    float cMax = max( max(RGB.x, RGB.y), RGB.z);\n    float cMin = min( min(RGB.x, RGB.y), RGB.z);\n\n    return (cMax+cMin) * 0.5;\n}\n\n\nvoid main(void)\n{\n    vec2 c1 = v_texCoords;\n   float cc1 = colour(c1);\n    vec2 offset;\n\n    c1.x += (0.001 *wobbleIntensity);      // appx 12 pixels horizontal\n    offset.x = emboss*(cc1-colour(c1));\n\n    c1.x = v_texCoords.x;\n    c1.y += (0.002*wobbleIntensity);      // appx 12 pixels verticle\n    offset.y = emboss*(cc1-colour(c1));\n\n    // TODO: The effect should be centered around Franklyns position in the room, not the center\n    //if ( emitFromCenter == 1)\n    {\n        vec2 center = vec2(0.5, 0.5);\n        float distToCenter = distance(center, v_texCoords);\n        offset *= distToCenter * 2.0;\n    }\n\n    c1 = v_texCoords;\n    c1 += ( offset * iFade );\n\n    vec3 col = vec3(0,0,0);\n    if ( c1.x >= 0.0 && c1.x < (1.0-0.003125) )\n    {\n        col = texture2D(u_texture,c1).rgb;\n        float intensity = rgbToLuminance(col);  //(col.r + col.g + col.b) * 0.333333333;\n\n        // Exponential Shadows\n        float shadowsBleed = 1.0 - intensity;\n        shadowsBleed *= shadowsBleed;\n        shadowsBleed *= shadowsBleed;\n\n        // Exponential midtones\n        float midtonesBleed = 1.0 - abs(-1.0 + intensity * 2.0);\n        midtonesBleed *= midtonesBleed;\n        midtonesBleed *= midtonesBleed;\n\n        // Exponential Hilights\n        float hilightsBleed = intensity;\n        hilightsBleed *= hilightsBleed;\n        hilightsBleed *= hilightsBleed;\n\n        vec3 colorization = col.rgb + shadows * shadowsBleed +\n        midtones * midtonesBleed +\n        highlights * hilightsBleed;\n\n        colorization = mix(col, colorization,iFade);\n\n        //col = lerp(col, colorization, _Amount);\n        col =  min(vec3(1.0),max(vec3(0.0),colorization));\n    }\n    gl_FragColor = vec4(col,1);\n})\";\n\nconst char *Shaders::sepiaFragmentShader =\n    R\"(#version 100\n#ifdef GL_ES\nprecision highp float;\n#endif\n\nvarying vec4 v_color;\nuniform sampler2D u_texture;\nuniform float sepiaFlicker;\nuniform float RandomValue[5];\nuniform float TimeLapse;\nvarying vec2 v_texCoords;\n\nvec3 mod289(vec3 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }\nvec2 mod289(vec2 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }\nvec3 permute(vec3 x) { return mod289(((x*34.0)+1.0)*x); }\nfloat snoise (vec2 v)\n{\n    const vec4 C = vec4(0.211324865405187,   // (3.0-sqrt(3.0))/6.0\n                        0.366025403784439,   // 0.5*(sqrt(3.0)-1.0)\n                        -0.577350269189626,   // -1.0 + 2.0 * C.x\n                        0.024390243902439);   // 1.0 / 41.0\n\n    // First corner\n    vec2 i  = floor(v + dot(v, C.yy) );\n    vec2 x0 = v -   i + dot(i, C.xx);\n\n    // Other corners\n    vec2 i1;\n    i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);\n    vec4 x12 = x0.xyxy + C.xxzz;\n    x12.xy -= i1;\n\n    // Permutations\n    i = mod289(i); // Avoid truncation effects in permutation\n    vec3 p = permute( permute( i.y + vec3(0.0, i1.y, 1.0 ))\n                     + i.x + vec3(0.0, i1.x, 1.0 ));\n\n    vec3 m = max(0.5 - vec3(dot(x0,x0), dot(x12.xy,x12.xy), dot(x12.zw,x12.zw)), 0.0);\n    m = m*m ;\n    m = m*m ;\n\n    // Gradients: 41 points uniformly over a line, mapped onto a diamond.\n    // The ring size 17*17 = 289 is close to a multiple of 41 (41*7 = 287)\n\n    vec3 x = 2.0 * fract(p * C.www) - 1.0;\n    vec3 h = abs(x) - 0.5;\n    vec3 ox = floor(x + 0.5);\n    vec3 a0 = x - ox;\n\n    // Normalise gradients implicitly by scaling m\n    // Approximation of: m *= inversesqrt( a0*a0 + h*h );\n    m *= 1.79284291400159 - 0.85373472095314 * ( a0*a0 + h*h );\n\n    // Compute final noise value at P\n    vec3 g;\n    g.x  = a0.x  * x0.x  + h.x  * x0.y;\n    g.yz = a0.yz * x12.xz + h.yz * x12.yw;\n    return 130.0 * dot(m, g);\n}\n\n\nvoid main(void)\n{\n    const float RADIUS = 0.75;\n    const float SOFTNESS = 0.45;\n    const float ScratchValue = 0.3;\n\n    vec4 texColor = texture2D( u_texture, v_texCoords);\n    vec4 col = v_color * texColor;\n    float gray = dot(col.rgb, vec3(0.299, 0.587, 0.114));\n    vec2 dist = vec2(v_texCoords.x - 0.5, v_texCoords.y - 0.5);\n    vec3 sepiaColor = vec3(gray) * vec3(0.9, 0.8, 0.6);   //vec3(1.2, 1.0, 0.8);\n    float len = dot(dist,dist);\n    float vignette = smoothstep(RADIUS, RADIUS-SOFTNESS, len);\n    //   float vignette = (1.0 - len);\n    col.rgb = mix(col.rgb, sepiaColor, 0.80) * vignette * sepiaFlicker;  // Want to keep SOME of the original color, so only use 80% sepia\n    //   col.rgb = vec3( vignette ) * sepiaFlicker;\n\n    for ( int i = 0; i < 1; i ++)\n    {\n        if ( RandomValue[i] < ScratchValue )\n        {\n            // Pick a random spot to show scratches\n            float dist = 1.0 / ScratchValue;\n            float d = distance(v_texCoords, vec2(RandomValue[i] * dist, RandomValue[i] * dist));\n            if ( d < 0.4 )\n            {\n                // Generate the scratch\n                float xPeriod = 8.0;\n                float yPeriod = 1.0;\n                float pi = 3.141592;\n                float phase = TimeLapse;\n                float turbulence = snoise(v_texCoords * 2.5);\n                float vScratch = 0.5 + (sin(((v_texCoords.x * xPeriod + v_texCoords.y * yPeriod + turbulence)) * pi + phase) * 0.5);\n                vScratch = clamp((vScratch * 10000.0) + 0.35, 0.0, 1.0);\n\n                col.rgb *= vScratch;\n            }\n        }\n    }\n    gl_FragColor = col;\n}\n)\";\n\nconst char *Shaders::vhsFragmentShader =\n    R\"(#version 100\n#ifdef GL_ES\nprecision highp float;\n#endif\n\nuniform float iGlobalTime;\nuniform float iNoiseThreshold;\nuniform sampler2D u_texture;\n\nvarying vec2 v_texCoords;\n\nfloat hash( float Input )\n{\n    return fract(sin(Input)*43758.5453123);\n}\n\nfloat rand(vec2 Input)\n{\n    float dt= dot(Input, vec2(12.9898,78.233));\n    float sn= mod(dt,3.14);\n    return hash(sn);\n}\n\n// 1d noise function\nfloat noise1d( float x )\n{\n    float p = floor(x);\n    float f = fract(x);\n    f = f*f*(3.0-2.0*f);\n    float n = p + 57.0 + 113.0;\n\n    return mix( hash(n), hash(n+1.0),f);\n}\n\n// 2d noise function\nfloat noise2d( vec2 x )\n{\n    vec2 p = floor(x);\n    vec2 f = fract(x);\n    f = f*f*(3.0-2.0*f);\n    float n = p.x + p.y*57.0 + 113.0;\n\n    float a = mix( hash(n),      hash(n+ 1.0),f.x);\n    float b = mix( hash(n+57.0), hash(n+58.0),f.x);\n\n    return mix(a,b,f.y);\n}\n\n//tape noise\nfloat tapenoise()\n{\n    vec2 iResolution = vec2(1280,720);\n    float linesN = 250.0; //fields per seconds\n    float one_y = iResolution.y / linesN; //field line\n    vec2 p = floor(v_texCoords*iResolution.xy/one_y)*one_y;\n\n    float s = iGlobalTime;\n    vec2 fP = vec2(p.x+s, p.y);\n\n    float v = 0.3 + ( noise1d( p.y*.01 +s ) * noise1d( p.y*.011+1000.0+s ) * noise1d( p.y*.51+421.0+s ) * noise2d( fP * 100.0 ) );\n\n    // if ( v < iNoiseThreshold ) v = 0.0;\n\n    // Same as above, without if\n    v *= step(iNoiseThreshold, v);\n\n    return v;\n}\n\n\nvoid main(void)\n{\n    // Apply a vhs-style distortion.\n    const float magnitude = 0.000003;\n    vec2 colRuv = vec2(v_texCoords.x + (rand(vec2(iGlobalTime*0.03,v_texCoords.y*0.42)) * 0.001 + sin(rand(vec2(iGlobalTime*0.2, v_texCoords.y)))*magnitude), v_texCoords.y);\n    vec2 colGuv = vec2(v_texCoords.x + (rand(vec2(iGlobalTime*0.004,v_texCoords.y*0.002)) * 0.004 + sin(iGlobalTime*9.0)*magnitude), v_texCoords.y);\n    vec2 colBuv = v_texCoords;\n\n    // Now make colours distort around edge\n    const float RADIUS = 0.85;\n    const float SOFTNESS = 0.65;\n\n    vec2 position = v_texCoords / vec2(0.6,1.0) - vec2(0.8,0.5) ;\n    float len = length(position);\n    float vignette = 1.0-smoothstep(RADIUS, RADIUS-SOFTNESS, len);\n\n    float angle = dot(position, v_texCoords) / (length(position)*length(v_texCoords));\n    vec2 screenPos = vec2(1.0)-( v_texCoords );\n    vec3 video;\n\n    video.r = texture2D(u_texture, colRuv-(vignette*(position*(len*0.015)))).r;\n    video.g = texture2D(u_texture, colGuv).g;\n    video.b = texture2D(u_texture, colBuv+(vignette*(position*(len*0.015)))).b;\n\n    // Now add the tape noise\n    video += vec3( tapenoise() );\n\n    gl_FragColor = vec4(video,1.0);\n}\n)\";\n\nconst char *Shaders::verbVertexShaderCode =\n    R\"(#version 100\nprecision mediump float;\nattribute vec2 a_position;\nattribute vec4 a_color;\nattribute vec2 a_texCoords;\n\nuniform vec4 u_shadowColor;\nuniform vec4 u_normalColor;\nuniform vec4 u_highlightColor;\nuniform vec2 u_ranges;\nuniform mat3 u_transform;\n\nvarying vec4 v_color;\nvarying vec2 v_texCoords;\nvarying vec4 v_shadowColor;\nvarying vec4 v_normalColor;\nvarying vec4 v_highlightColor;\nvarying vec2 v_ranges;\n\nvoid main(void) {\n  v_color = a_color;\n  v_texCoords = a_texCoords;\n  v_shadowColor = u_shadowColor;\n  v_normalColor = u_normalColor;\n  v_highlightColor = u_highlightColor;\n  v_ranges = u_ranges;\n\n  vec3 worldPosition = vec3(a_position, 1);\n  vec3 normalizedPosition = worldPosition * u_transform;\n  gl_Position = vec4(normalizedPosition.xy, 0, 1);\n})\";\n\nconst char *Shaders::verbFragmentShaderCode =\n    R\"(#version 100\n#ifdef GL_ES\nprecision highp float;\n#endif\n\nvarying vec4 v_color;\nvarying vec2 v_texCoords;\nvarying vec4 v_shadowColor;\nvarying vec4 v_normalColor;\nvarying vec4 v_highlightColor;\nvarying vec2 v_ranges;\nuniform sampler2D u_texture;\n\nvoid main(void)\n{\n    float shadows = v_ranges.x;\n    float highlights = v_ranges.y;\n\n    vec4 texColor = texture2D(u_texture, v_texCoords);\n\n    if ( texColor.g <= shadows)\n    {\n        texColor*=v_shadowColor;\n    }\n    else if (texColor.g >= highlights)\n    {\n        texColor*=v_highlightColor;\n    }\n    else\n    {\n        texColor*=v_normalColor;\n    }\n    texColor *= v_color;\n    gl_FragColor = texColor;\n}\n)\";\n\n}"
  },
  {
    "path": "src/Engine/Shaders.hpp",
    "content": "#pragma once\n\nnamespace ng {\nstruct Shaders {\n  static const char *vertexShader;\n  static const char *bwFragmentShader;\n  static const char *egaFragmenShader;\n  static const char *fadeFragmentShader;\n  static const char *ghostFragmentShader;\n  static const char *sepiaFragmentShader;\n  static const char *vhsFragmentShader;\n  static const char *verbVertexShaderCode;\n  static const char *verbFragmentShaderCode;\n};\n}"
  },
  {
    "path": "src/Engine/TextDatabase.cpp",
    "content": "#include <regex>\n#include \"engge/System/Logger.hpp\"\n#include \"engge/Engine/EngineSettings.hpp\"\n#include \"engge/Engine/TextDatabase.hpp\"\n#include \"../Util/Util.hpp\"\n\nnamespace ng {\nTextDatabase::TextDatabase() = default;\n\nvoid TextDatabase::load(const std::string &path) {\n  m_texts.clear();\n  std::wregex re(L\"^(\\\\d+)\\\\s+(.*)$\");\n  auto buffer = Locator<EngineSettings>::get().readBuffer(path);\n  GGPackBufferStream input(buffer);\n  std::wstring line;\n  while (getLine(input, line)) {\n    std::wsmatch matches;\n    if (!std::regex_search(line, matches, re))\n      continue;\n\n    wchar_t *end;\n    auto num = std::wcstoul(matches[1].str().c_str(), &end, 10);\n    auto text = matches[2].str();\n    m_texts.insert(std::make_pair(num, text));\n  }\n}\n\nstd::wstring TextDatabase::getText(int id) const {\n  const auto it = m_texts.find(id);\n  if (it == m_texts.end()) {\n    error(\"Text ID {} doest not exist\", id);\n    return L\"\";\n  }\n  auto text = it->second;\n  replaceAll(text, L\"\\\\\\\"\", L\"\\\"\");\n  return text;\n}\n\nstd::wstring TextDatabase::getText(const std::string &text) const {\n  if (!text.empty() && text[0] == '@') {\n    auto id = std::strtol(text.c_str() + 1, nullptr, 10);\n    return getText(id);\n  }\n  return towstring(text);\n}\n\n} // namespace ng\n"
  },
  {
    "path": "src/Engine/Thread.cpp",
    "content": "#include <squirrel.h>\n#include \"engge/System/Locator.hpp\"\n#include \"engge/Engine/EntityManager.hpp\"\n#include \"engge/Engine/Thread.hpp\"\n#include <utility>\n\nnamespace ng {\nThread::Thread(std::string name, bool isGlobal,\n               HSQUIRRELVM v,\n               HSQOBJECT thread_obj,\n               HSQOBJECT env_obj,\n               HSQOBJECT closureObj,\n               std::vector<HSQOBJECT> args)\n    : m_name(std::move(name)), m_v(v), m_threadObj(thread_obj), m_envObj(env_obj), m_closureObj(closureObj), m_args(std::move(args)),\n      m_isGlobal(isGlobal) {\n  sq_addref(m_v, &m_threadObj);\n  sq_addref(m_v, &m_envObj);\n  sq_addref(m_v, &m_closureObj);\n  m_id = Locator<EntityManager>::get().getThreadId();\n}\n\nThread::~Thread() {\n  sq_release(m_v, &m_threadObj);\n  sq_release(m_v, &m_envObj);\n  sq_release(m_v, &m_closureObj);\n}\n\nstd::string Thread::getName() const {\n  return m_name;\n}\n\nHSQUIRRELVM Thread::getThread() const { return m_threadObj._unVal.pThread; }\n\nbool Thread::call() {\n  auto thread = getThread();\n  // call the closure in the thread\n  SQInteger top = sq_gettop(thread);\n  sq_pushobject(thread, m_closureObj);\n  sq_pushobject(thread, m_envObj);\n  for (auto arg : m_args) {\n    sq_pushobject(thread, arg);\n  }\n  if (SQ_FAILED(sq_call(thread, 1 + m_args.size(), SQFalse, SQTrue))) {\n    sq_settop(thread, top);\n    return false;\n  }\n  return true;\n}\n\n} // namespace ng\n\n"
  },
  {
    "path": "src/Engine/ThreadBase.cpp",
    "content": "#include <engge/Engine/ThreadBase.hpp>\n#include \"engge/System/Locator.hpp\"\n#include \"engge/System/Logger.hpp\"\n#include <engge/Engine/EntityManager.hpp>\n\nnamespace ng {\nThreadBase::ThreadBase() {\n  m_id = Locator<EntityManager>::get().getThreadId();\n}\n\nThreadBase::~ThreadBase() {\n  trace(\"stop thread {}\", m_id);\n}\n\nvoid ThreadBase::stop() {\n  m_isStopped = true;\n}\n\nbool ThreadBase::pause() {\n  if (!m_isPauseable)\n    return false;\n  suspend();\n  return true;\n}\n\nvoid ThreadBase::suspend() {\n  if (isSuspended())\n    return;\n  sq_suspendvm(getThread());\n  m_isSuspended = true;\n}\n\nvoid ThreadBase::resume() {\n  if (!isSuspended())\n    return;\n  sq_wakeupvm(getThread(), SQFalse, SQFalse, SQTrue, SQFalse);\n  m_isSuspended = false;\n}\n\nbool ThreadBase::isSuspended() const {\n  if (m_isSuspended)\n    return true;\n  auto state = sq_getvmstate(getThread());\n  return state != SQ_VMSTATE_RUNNING;\n}\n\nbool ThreadBase::isStopped() const {\n  if (m_isStopped)\n    return true;\n  auto state = sq_getvmstate(getThread());\n  return state == SQ_VMSTATE_IDLE;\n}\n}"
  },
  {
    "path": "src/Engine/TimeFunction.cpp",
    "content": "#include <engge/Engine/TimeFunction.hpp>\n\nnamespace ng {\nTimeFunction::TimeFunction(const ngf::TimeSpan &time)\n    : m_time(time) {\n}\n\nTimeFunction::~TimeFunction() = default;\n\nvoid TimeFunction::operator()(const ngf::TimeSpan &elapsed) {\n  m_elapsed += elapsed;\n}\n\nngf::TimeSpan TimeFunction::getElapsed() const { return m_elapsed; }\n\nbool TimeFunction::isElapsed() {\n  auto isElapsed = m_elapsed > m_time;\n  if (isElapsed && !m_done) {\n    m_done = true;\n    onElapsed();\n  }\n  return isElapsed;\n}\n\nvoid TimeFunction::onElapsed() {}\n}"
  },
  {
    "path": "src/Engine/Trigger.cpp",
    "content": "#include <engge/Engine/Trigger.hpp>\n\nnamespace ng {\nTrigger::Trigger() = default;\n\nTrigger::~Trigger() = default;\nvoid Trigger::trig() {\n  if (!isEnabled())\n    return;\n  trigCore();\n}\n\nbool Trigger::isEnabled() const { return m_isEnabled; }\n\nvoid Trigger::disable() { m_isEnabled = false; }\n\n} // namespace ng\n"
  },
  {
    "path": "src/Entities/Actor.cpp",
    "content": "#include <engge/Entities/Actor.hpp>\n#include <engge/Engine/Engine.hpp>\n#include <engge/System/Locator.hpp>\n#include <engge/Engine/EntityManager.hpp>\n#include <engge/Entities/Costume.hpp>\n#include <engge/Entities/Object.hpp>\n#include <engge/Room/Room.hpp>\n#include <engge/Room/RoomScaling.hpp>\n#include <engge/Scripting/ScriptEngine.hpp>\n#include <glm/vec2.hpp>\n#include <ngf/Graphics/RectangleShape.h>\n#include \"Graphics/PathDrawable.hpp\"\n#include \"WalkingState.hpp\"\n\nnamespace ng {\n\nnamespace {\nbool frameContains(const SpriteSheetItem &frame, const glm::vec2 &pos) {\n  ngf::Transform t;\n  t.setOrigin(frame.sourceSize / 2);\n  t.setPosition(frame.spriteSourceSize.getTopLeft());\n\n  auto rect = ngf::frect::fromPositionSize({0, 0}, frame.frame.getSize());\n  auto r = ngf::transform(t.getTransform(), rect);\n  return r.contains(pos);\n}\n\nbool animContains(const Animation &anim, const glm::vec2 &pos) {\n  if (!anim.frames.empty() && frameContains(anim.frames.at(anim.frameIndex), pos))\n    return true;\n\n  return std::any_of(anim.layers.cbegin(), anim.layers.cend(), [pos](const auto &layer) {\n    if (!layer.visible)\n      return false;\n    return animContains(layer, pos);\n  });\n}\n}\n\nstruct Actor::Impl {\n  explicit Impl(Engine &engine)\n      : _engine(engine), _costume(engine.getResourceManager()) {\n  }\n\n  void setActor(Actor *pActor) {\n    _pActor = pActor;\n    _walkingState.setActor(pActor);\n    _costume.setActor(pActor);\n  }\n\n  Engine &_engine;\n  Actor *_pActor{nullptr};\n  Costume _costume;\n  bool _useWalkboxes{true};\n  Room *_pRoom{nullptr};\n  ngf::irect _hotspot{};\n  std::vector<Object *> _objects;\n  WalkingState _walkingState;\n  glm::ivec2 _speed{30, 15};\n  std::unique_ptr<PathDrawable> _path;\n  HSQOBJECT _table{};\n  bool _hotspotVisible{false};\n  int _inventoryOffset{0};\n  int _fps{10};\n};\n\nstd::wstring Actor::getTranslatedName() const {\n  return Engine::getText(getName());\n}\n\nstd::string Actor::getIcon() const {\n  const char *icon = nullptr;\n  ScriptEngine::rawGet(m_pImpl->_table, \"icon\", icon);\n  if (!icon)\n    return \"\";\n  return icon;\n}\n\nvoid Actor::useWalkboxes(bool useWalkboxes) { m_pImpl->_useWalkboxes = useWalkboxes; }\n\nbool Actor::useWalkboxes() const { return m_pImpl->_useWalkboxes; }\n\nstd::unique_ptr<PathDrawable> Actor::getPath() { return std::move(m_pImpl->_path); }\n\nCostume &Actor::getCostume() { return m_pImpl->_costume; }\n\nCostume &Actor::getCostume() const { return m_pImpl->_costume; }\n\nRoom *Actor::getRoom() { return m_pImpl->_pRoom; }\n\nvoid Actor::setHotspot(const ngf::irect &hotspot) { m_pImpl->_hotspot = hotspot; }\n\nngf::irect Actor::getHotspot() const { return m_pImpl->_hotspot; }\n\nvoid Actor::showHotspot(bool show) { m_pImpl->_hotspotVisible = show; }\n\nbool Actor::isHotspotVisible() const { return m_pImpl->_hotspotVisible; }\n\nbool Actor::contains(const glm::vec2 &pos) const {\n  auto pAnim = m_pImpl->_costume.getAnimation();\n  if (!pAnim)\n    return false;\n\n  auto scale = getScale();\n  auto transformable = getTransform();\n  transformable.setScale({scale, scale});\n  transformable.move({getRenderOffset().x * scale, getRenderOffset().y * scale});\n  auto t = glm::inverse(transformable.getTransform());\n  auto pos2 = ngf::transform(t, pos);\n  return animContains(*pAnim, pos2);\n}\n\nvoid Actor::pickupObject(Object *pObject) {\n  pObject->setOwner(this);\n  m_pImpl->_objects.push_back(pObject);\n\n  ScriptEngine::call(\"onPickup\", pObject, this);\n\n  if (ScriptEngine::rawExists(pObject, \"onPickUp\")) {\n    ScriptEngine::rawCall(pObject, \"onPickUp\", this);\n  }\n}\n\nvoid Actor::pickupReplacementObject(Object *pObject1, Object *pObject2) {\n  pObject2->setOwner(this);\n  std::replace(m_pImpl->_objects.begin(), m_pImpl->_objects.end(), pObject1, pObject2);\n  pObject1->setOwner(nullptr);\n}\n\nvoid Actor::giveTo(Object *pObject, Actor *pActor) {\n  if (!pObject || !pActor)\n    return;\n  pObject->setOwner(pActor);\n  auto srcIt = std::find(m_pImpl->_objects.begin(), m_pImpl->_objects.end(), pObject);\n  std::move(srcIt, srcIt + 1, std::inserter(pActor->m_pImpl->_objects, pActor->m_pImpl->_objects.end()));\n  m_pImpl->_objects.erase(srcIt);\n}\n\nvoid Actor::removeInventory(Object *pObject) {\n  if (!pObject)\n    return;\n  pObject->setOwner(nullptr);\n  m_pImpl->_objects.erase(std::remove(m_pImpl->_objects.begin(),\n                                      m_pImpl->_objects.end(),\n                                      pObject), m_pImpl->_objects.end());\n}\n\nvoid Actor::clearInventory() {\n  for (auto &&obj : m_pImpl->_objects) {\n    obj->setOwner(nullptr);\n  }\n  m_pImpl->_objects.clear();\n}\n\nconst std::vector<Object *> &Actor::getObjects() const { return m_pImpl->_objects; }\n\nvoid Actor::setWalkSpeed(const glm::ivec2 &speed) { m_pImpl->_speed = speed; }\n\nconst glm::ivec2 &Actor::getWalkSpeed() const { return m_pImpl->_speed; }\n\nvoid Actor::stopWalking() { m_pImpl->_walkingState.stop(); }\n\nbool Actor::isWalking() const { return m_pImpl->_walkingState.isWalking(); }\n\nHSQOBJECT &Actor::getTable() { return m_pImpl->_table; }\nHSQOBJECT &Actor::getTable() const { return m_pImpl->_table; }\n\nbool Actor::isInventoryObject() const { return false; }\n\nActor::Actor(Engine &engine) : m_pImpl(std::make_unique<Impl>(engine)) {\n  m_pImpl->setActor(this);\n  m_id = Locator<EntityManager>::get().getActorId();\n}\n\nActor::~Actor() = default;\n\nconst Room *Actor::getRoom() const { return m_pImpl->_pRoom; }\n\nint Actor::getZOrder() const { return static_cast<int>(getPosition().y); }\n\nvoid Actor::setRoom(Room *pRoom) {\n  if (m_pImpl->_pRoom) {\n    m_pImpl->_pRoom->removeEntity(this);\n  }\n  m_pImpl->_pRoom = pRoom;\n  m_pImpl->_pRoom->setAsParallaxLayer(this, 0);\n}\n\nvoid Actor::setCostume(const std::string &name, const std::string &sheet) {\n  std::string path;\n  path.append(name).append(\".json\");\n  m_pImpl->_costume.loadCostume(path, sheet);\n}\n\nfloat Actor::getScale() const {\n  auto pRoom = m_pImpl->_pRoom;\n  if (!pRoom)\n    return 1.f;\n  return pRoom->getRoomScaling().getScaling(getPosition().y);\n}\n\nvoid Actor::draw(ngf::RenderTarget &target, ngf::RenderStates states) const {\n  if (!isVisible())\n    return;\n\n  auto scale = getScale();\n  auto transformable = getTransform();\n  transformable.setScale({scale, scale});\n  transformable.setPosition({transformable.getPosition().x + scale * getRenderOffset().x,\n                             m_pImpl->_pRoom->getScreenSize().y - transformable.getPosition().y\n                                 - scale * getRenderOffset().y});\n  states.transform = transformable.getTransform() * states.transform;\n  m_pImpl->_costume.draw(target, states);\n}\n\nvoid Actor::update(const ngf::TimeSpan &elapsed) {\n  Entity::update(elapsed);\n\n  m_pImpl->_costume.update(elapsed);\n  m_pImpl->_walkingState.update(elapsed);\n}\n\nstd::vector<glm::vec2> Actor::walkTo(const glm::vec2 &destination, std::optional<Facing> facing) {\n  if (m_pImpl->_pRoom == nullptr)\n    return {getPosition()};\n\n  std::vector<glm::vec2> path;\n  if (m_pImpl->_useWalkboxes) {\n    path = m_pImpl->_pRoom->calculatePath(getPosition(), destination);\n    if (path.size() < 2) {\n      m_pImpl->_path = nullptr;\n      return path;\n    }\n  } else {\n    path.push_back(getPosition());\n    path.push_back(destination);\n  }\n\n  m_pImpl->_path = std::make_unique<PathDrawable>(path);\n  if (ScriptEngine::rawExists(this, \"preWalking\")) {\n    ScriptEngine::rawCall(this, \"preWalking\");\n  }\n  m_pImpl->_walkingState.setDestination(path, facing);\n  return path;\n}\n\nvoid Actor::setFps(int fps) {\n  m_pImpl->_fps = fps;\n}\n\nint Actor::getFps() const {\n  return m_pImpl->_fps;\n}\n\nvoid Actor::setInventoryOffset(int offset) { m_pImpl->_inventoryOffset = offset; }\n\nint Actor::getInventoryOffset() const {\n  if ((m_pImpl->_inventoryOffset * 4) > static_cast<int>(getObjects().size())) {\n    m_pImpl->_inventoryOffset = 0;\n  }\n  return m_pImpl->_inventoryOffset;\n}\n\n} // namespace ng\n"
  },
  {
    "path": "src/Entities/AnimationLoader.cpp",
    "content": "#include <glm/vec2.hpp>\n#include <engge/Entities/AnimationLoader.hpp>\n#include <engge/Entities/Entity.hpp>\n#include <engge/Graphics/Animation.hpp>\n#include <engge/Graphics/SpriteSheet.hpp>\n#include <engge/System/Locator.hpp>\n#include <ngf/IO/GGPackValue.h>\n\nnamespace ng {\nnamespace {\n\nbool toBool(const ngf::GGPackValue &gValue) {\n  return !gValue.isNull() && gValue.getInt() == 1;\n}\n\nglm::ivec2 parseIVec2(std::string_view value) {\n  char *ptr;\n  auto x = std::strtol(value.data() + 1, &ptr, 10);\n  auto y = std::strtol(ptr + 1, &ptr, 10);\n  return glm::ivec2{x, y};\n}\n\nAnimation parseAnimation(Entity &entity,\n                         const ngf::GGPackValue &gAnimation,\n                         const SpriteSheet &defaultSpriteSheet) {\n  const SpriteSheet *spriteSheet = &defaultSpriteSheet;\n  Animation anim;\n  if (gAnimation[\"sheet\"].isString()) {\n    spriteSheet = &Locator<ResourceManager>::get().getSpriteSheet(gAnimation[\"sheet\"].getString());\n  }\n  anim.texture = spriteSheet->getTextureName();\n  anim.name = gAnimation[\"name\"].getString();\n  anim.loop = toBool(gAnimation[\"loop\"]);\n  anim.fps = gAnimation[\"fps\"].isNull() ? 0 : gAnimation[\"fps\"].getInt();\n  anim.flags = gAnimation[\"flags\"].isNull() ? 0 : gAnimation[\"flags\"].getInt();\n  if (!gAnimation[\"frames\"].isNull()) {\n    for (const auto &gFrame : gAnimation[\"frames\"]) {\n      auto name = gFrame.getString();\n      if (name == \"null\") {\n        SpriteSheetItem item;\n        item.isNull = true;\n        anim.frames.push_back(item);\n      } else {\n        anim.frames.push_back(spriteSheet->getItem(name));\n      }\n    }\n  }\n\n  if (!gAnimation[\"layers\"].isNull()) {\n    for (const auto &gLayer : gAnimation[\"layers\"]) {\n      auto layer = parseAnimation(entity, gLayer, *spriteSheet);\n      anim.layers.push_back(layer);\n    }\n  }\n  if (!gAnimation[\"offsets\"].isNull()) {\n    for (const auto &gOffset : gAnimation[\"offsets\"]) {\n      auto offset = parseIVec2(gOffset.getString());\n      anim.offsets.push_back(offset);\n    }\n  }\n  if (!gAnimation[\"triggers\"].isNull()) {\n    auto numTriggers = gAnimation[\"triggers\"].size();\n    anim.callbacks.resize(numTriggers);\n    anim.triggers.resize(numTriggers);\n    for (auto i = 0; i < static_cast<int>(gAnimation[\"triggers\"].size()); i++) {\n      const auto &gTrigger = gAnimation[\"triggers\"][i];\n      if (gTrigger.isNull())\n        continue;\n      auto trigName = gTrigger.getString();\n      anim.triggers[i] = trigName;\n      anim.callbacks[i] = [&entity, trigName]() { entity.trig(trigName); };\n    }\n  }\n  return anim;\n}\n}\n\nstd::vector<Animation> AnimationLoader::parseAnimations(Entity &entity,\n                                                        const ngf::GGPackValue &gAnimations,\n                                                        const SpriteSheet &spriteSheet) {\n  std::vector<Animation> anims;\n  if (gAnimations.isNull())\n    return anims;\n  for (const auto &gAnimation : gAnimations) {\n    if (gAnimation.isNull())\n      continue;\n    anims.push_back(parseAnimation(entity, gAnimation, spriteSheet));\n  }\n  return anims;\n}\n}"
  },
  {
    "path": "src/Entities/BlinkState.cpp",
    "content": "#include <engge/Entities/BlinkState.hpp>\n#include <engge/System/Locator.hpp>\n#include <engge/Util/RandomNumberGenerator.hpp>\n#include \"Util/Util.hpp\"\n\nnamespace ng {\nBlinkState::BlinkState(Costume &costume) : m_costume(costume) {\n}\n\nvoid BlinkState::setRate(float min, float max) {\n  m_min = min;\n  m_max = max;\n  if (min == 0 && max == 0) {\n    // blinking is disabled\n    m_state = -1;\n  } else {\n    m_state = ObjectStateConstants::CLOSED;\n    m_value = ngf::TimeSpan::seconds(Locator<RandomNumberGenerator>::get().generateFloat(m_min, m_max));\n  }\n  m_elapsed = ngf::TimeSpan::seconds(0);\n  m_costume.setLayerVisible(\"blink\", false);\n}\n\nvoid BlinkState::update(ngf::TimeSpan elapsed) {\n  if (m_state == ObjectStateConstants::CLOSED) {\n    // wait to blink\n    m_elapsed += elapsed;\n    if (m_elapsed > m_value) {\n      m_state = ObjectStateConstants::OPEN;\n      m_costume.setLayerVisible(\"blink\", true);\n      m_elapsed = ngf::TimeSpan::seconds(0);\n    }\n  } else if (m_state == ObjectStateConstants::OPEN) {\n    // wait time the eyes are closed\n    m_elapsed += elapsed;\n    if (m_elapsed > ngf::TimeSpan::seconds(0.2)) {\n      m_costume.setLayerVisible(\"blink\", false);\n      m_value = ngf::TimeSpan::seconds(Locator<RandomNumberGenerator>::get().generateFloat(m_min, m_max));\n      m_elapsed = ngf::TimeSpan::seconds(0);\n      m_state = ObjectStateConstants::CLOSED;\n    }\n  }\n}\n}\n"
  },
  {
    "path": "src/Entities/Costume.cpp",
    "content": "#include <filesystem>\n#include <iostream>\n#include <engge/Graphics/AnimDrawable.hpp>\n#include <engge/Entities/Actor.hpp>\n#include <engge/Entities/BlinkState.hpp>\n#include <engge/Entities/Costume.hpp>\n#include <engge/Engine/EngineSettings.hpp>\n#include <engge/System/Locator.hpp>\n#include <engge/Entities/AnimationLoader.hpp>\n#include <engge/Room/Room.hpp>\n#include \"Util/Util.hpp\"\n\nnamespace fs = std::filesystem;\n\nnamespace ng {\nCostume::Costume(ResourceManager &textureManager)\n    : m_textureManager(textureManager),\n      m_blinkState(*this) {\n  resetLockFacing();\n  setLayerVisible(\"eyes_left\", false);\n  setLayerVisible(\"eyes_right\", false);\n}\n\nCostume::~Costume() = default;\n\nvoid Costume::setLayerVisible(const std::string &name, bool isVisible) {\n  if (!isVisible) {\n    m_hiddenLayers.emplace(name);\n  } else {\n    m_hiddenLayers.erase(name);\n  }\n  if (m_pCurrentAnimation == nullptr)\n    return;\n  if (m_pCurrentAnimation->layers.empty())\n    return;\n  auto it =\n      std::find_if(m_pCurrentAnimation->layers.begin(), m_pCurrentAnimation->layers.end(), [name](auto &layer) {\n        return layer.name == name;\n      });\n  if (it != m_pCurrentAnimation->layers.end()) {\n    it->visible = isVisible;\n  }\n}\n\nFacing Costume::getFacing() const {\n  if (m_lockFacing) {\n    return m_facings.at(m_facing);\n  }\n  return m_facing;\n}\n\nvoid Costume::setFacing(Facing facing) {\n  if (m_facing == facing)\n    return;\n  m_facing = facing;\n  updateAnimation();\n}\n\nvoid Costume::lockFacing(Facing left, Facing right, Facing front, Facing back) {\n  m_facings[Facing::FACE_LEFT] = left;\n  m_facings[Facing::FACE_RIGHT] = right;\n  m_facings[Facing::FACE_FRONT] = front;\n  m_facings[Facing::FACE_BACK] = back;\n  m_lockFacing = true;\n}\n\nvoid Costume::resetLockFacing() {\n  m_facings[Facing::FACE_LEFT] = Facing::FACE_LEFT;\n  m_facings[Facing::FACE_RIGHT] = Facing::FACE_RIGHT;\n  m_facings[Facing::FACE_FRONT] = Facing::FACE_FRONT;\n  m_facings[Facing::FACE_BACK] = Facing::FACE_BACK;\n}\n\nvoid Costume::unlockFacing() {\n  m_lockFacing = false;\n}\n\nstd::optional<Facing> Costume::getLockFacing() const {\n  if (!m_lockFacing)\n    return std::nullopt;\n  auto frontFacing = m_facings.find(Facing::FACE_FRONT)->second;\n  auto backFacing = m_facings.find(Facing::FACE_BACK)->second;\n  if (frontFacing != backFacing)\n    return std::nullopt;\n  return frontFacing;\n}\n\nvoid Costume::setState(const std::string &name, bool loop) {\n  m_animation = name;\n  auto pOldAnim = m_pCurrentAnimation;\n  updateAnimation();\n  if (pOldAnim != m_pCurrentAnimation) {\n    m_animControl.play(loop);\n  } else {\n    m_animControl.resume(loop);\n  }\n}\n\nvoid Costume::setReachState(Reaching reaching) {\n  std::string animName;\n  switch (reaching) {\n  case Reaching::High:animName = m_reachAnimName + \"_high\";\n    break;\n  case Reaching::Medium:animName = m_reachAnimName + \"_med\";\n    break;\n  case Reaching::Low:animName = m_reachAnimName + \"_low\";\n    break;\n  }\n  setState(animName);\n  if (!m_pCurrentAnimation) {\n    setState(m_reachAnimName);\n  }\n}\n\nvoid Costume::loadCostume(const std::string &path, const std::string &sheet) {\n  m_path = path;\n  auto costumeSheet = m_sheet = sheet;\n\n  auto costumePath = fs::path(path);\n  if (!costumePath.has_extension()) {\n    costumePath.replace_extension(\".json\");\n  }\n  auto hash = Locator<EngineSettings>::get().readEntry(costumePath.string());\n  if (costumeSheet.empty()) {\n    costumeSheet = hash[\"sheet\"].getString();\n  }\n\n  m_costumeSheet.setTextureManager(&m_textureManager);\n\n  if (!costumeSheet.empty()) {\n    m_costumeSheet.load(costumeSheet);\n  }\n\n  // load animations\n  m_animations.clear();\n  m_pCurrentAnimation = nullptr;\n  m_animControl.setAnimation(nullptr);\n  setHeadIndex(m_headIndex);\n\n  m_animations = AnimationLoader::parseAnimations(*m_pActor, hash[\"animations\"], m_costumeSheet);\n\n  // don't know if it's necessary, reyes has no costume in the intro\n  setStandState();\n}\n\nbool Costume::setAnimation(const std::string &animName) {\n  if (m_pCurrentAnimation && m_pCurrentAnimation->name == animName)\n    return true;\n\n  for (auto &anim : m_animations) {\n    if (anim.name == animName) {\n      m_pCurrentAnimation = &anim;\n      m_animControl.setAnimation(m_pCurrentAnimation);\n      for (auto &layer : m_pCurrentAnimation->layers) {\n        auto layerName = layer.name;\n        layer.visible = m_hiddenLayers.find(layerName) == m_hiddenLayers.end();\n      }\n\n      m_animControl.play();\n      return true;\n    }\n  }\n\n  return false;\n}\n\nbool Costume::setMatchingAnimation(const std::string &animName) {\n  if (m_pCurrentAnimation && startsWith(m_pCurrentAnimation->name, animName))\n    return true;\n\n  for (auto &anim : m_animations) {\n    if (startsWith(anim.name, animName)) {\n      m_pCurrentAnimation = &anim;\n      m_animControl.setAnimation(m_pCurrentAnimation);\n      for (auto &layer : m_pCurrentAnimation->layers) {\n        auto layerName = layer.name;\n        layer.visible = m_hiddenLayers.find(layerName) == m_hiddenLayers.end();\n      }\n\n      m_animControl.play();\n      return true;\n    }\n  }\n\n  return false;\n}\n\nvoid Costume::updateAnimation() {\n  std::string animName = m_animation;\n  if (animName == \"stand\") {\n    animName = m_standAnimName;\n  } else if (animName == \"head\") {\n    animName = m_headAnimName;\n  } else if (animName == \"walk\") {\n    animName = m_walkAnimName;\n  } else if (animName == \"reach\") {\n    animName = m_reachAnimName;\n  }\n\n  // special case for eyes... bof\n  if (m_pCurrentAnimation && startsWith(animName, \"eyes_\")) {\n    auto &layers = m_pCurrentAnimation->layers;\n    for (auto &&layer : layers) {\n      if (!startsWith(layer.name, \"eyes_\"))\n        continue;\n      setLayerVisible(layer.name, false);\n    }\n    setLayerVisible(animName, true);\n    return;\n  }\n\n  if (!setAnimation(animName)) {\n    std::string name(animName);\n    name.append(\"_\");\n    switch (getFacing()) {\n    case Facing::FACE_BACK:name.append(\"back\");\n      break;\n    case Facing::FACE_FRONT:name.append(\"front\");\n      break;\n    case Facing::FACE_LEFT:\n    case Facing::FACE_RIGHT:name.append(\"right\");\n      break;\n    }\n    if (!setAnimation(name)) {\n      setMatchingAnimation(name);\n    }\n  }\n\n  setHeadIndex(m_headIndex);\n}\n\nvoid Costume::update(const ngf::TimeSpan &elapsed) {\n  if (!m_pCurrentAnimation)\n    return;\n  m_animControl.update(elapsed);\n  m_blinkState.update(elapsed);\n}\n\nvoid Costume::draw(ngf::RenderTarget &target, ngf::RenderStates states) const {\n  if (!m_pCurrentAnimation)\n    return;\n  AnimDrawable animDrawable;\n  animDrawable.setAnim(m_pCurrentAnimation);\n  animDrawable.setColor(m_pActor->getColor());\n  if (getFacing() == Facing::FACE_LEFT)\n    animDrawable.setFlipX(true);\n  animDrawable.draw(m_pActor->getPosition(), target, states);\n}\n\nvoid Costume::setHeadIndex(int index) {\n  m_headIndex = index;\n\n  setLayerVisible(m_headAnimName, m_headIndex == 0);\n  for (int i = 0; i < 6; i++) {\n    auto name = m_headAnimName;\n    name.append(std::to_string(i + 1));\n    setLayerVisible(name, i == m_headIndex);\n  }\n}\n\nint Costume::getHeadIndex() const { return m_headIndex; }\n\nvoid Costume::setAnimationNames(const std::string &headAnim,\n                                const std::string &standAnim,\n                                const std::string &walkAnim,\n                                const std::string &reachAnim) {\n  if (!headAnim.empty()) {\n    setLayerVisible(m_headAnimName, false);\n    for (int i = 0; i < 6; ++i) {\n      auto name = m_headAnimName;\n      name.append(std::to_string(i + 1));\n      setLayerVisible(name, false);\n    }\n    m_headAnimName = headAnim;\n    setLayerVisible(m_headAnimName, m_headIndex == 0);\n    for (int i = 0; i < 6; ++i) {\n      auto name = m_headAnimName;\n      name.append(std::to_string(i + 1));\n      setLayerVisible(name, m_headIndex == i);\n    }\n  }\n  if (!standAnim.empty()) {\n    m_standAnimName = standAnim;\n  }\n  if (!walkAnim.empty()) {\n    m_walkAnimName = walkAnim;\n  }\n  if (!reachAnim.empty()) {\n    m_reachAnimName = reachAnim;\n  }\n  // update animation if necessary\n  if (m_pCurrentAnimation) {\n    m_pCurrentAnimation = nullptr;\n    setState(m_animation, m_animControl.getLoop());\n  }\n}\n\nvoid Costume::getAnimationNames(std::string &headAnim,\n                                std::string &standAnim,\n                                std::string &walkAnim,\n                                std::string &reachAnim) const {\n  headAnim = m_headAnimName;\n  standAnim = m_standAnimName;\n  walkAnim = m_walkAnimName;\n  reachAnim = m_reachAnimName;\n}\n\nvoid Costume::setBlinkRate(float min, float max) {\n  m_blinkState.setRate(min, max);\n}\n} // namespace ng\n"
  },
  {
    "path": "src/Entities/Entity.cpp",
    "content": "#include <memory>\n#include <optional>\n#include <utility>\n#include <glm/vec2.hpp>\n#include <engge/Entities/Entity.hpp>\n#include <engge/Scripting/ScriptEngine.hpp>\n#include <engge/Audio/SoundTrigger.hpp>\n#include <engge/Engine/Camera.hpp>\n#include <engge/Engine/Trigger.hpp>\n#include \"JiggleFunction.hpp\"\n#include \"ShakeFunction.hpp\"\n#include \"TalkingState.hpp\"\n\nnamespace ng {\nstruct Motor {\n  bool isEnabled{false};\n  std::unique_ptr<Function> function;\n};\n\nstruct Entity::Impl {\n  std::string m_key;\n  Engine &m_engine;\n  std::map<int, Trigger *> m_triggers;\n  std::vector<std::unique_ptr<SoundTrigger>> m_soundTriggers;\n  std::optional<glm::vec2> m_usePos;\n  std::optional<UseDirection> m_useDir;\n  glm::vec2 m_offset{0, 0};\n  glm::vec2 m_shakeOffset{0, 0};\n  float m_jiggleOffset{0.f};\n  bool m_isLit{false};\n  glm::ivec2 m_renderOffset{0, 0};\n  Motor m_offsetTo, m_scaleTo, m_rotateTo, m_moveTo, m_alphaTo, m_shake, m_jiggle;\n  bool m_objectBumperCycle{true};\n  ngf::Color m_talkColor;\n  glm::ivec2 m_talkOffset{0, 90};\n  TalkingState m_talkingState;\n  ngf::Transform m_transform;\n  Entity *m_pParent{nullptr};\n  std::vector<Entity *> m_children;\n\n  Impl() : m_engine(ng::Locator<ng::Engine>::get()) {\n    m_talkingState.setEngine(&m_engine);\n  }\n\n  static std::optional<int> getDefaultVerb(const Entity *pEntity) {\n    if (!pEntity)\n      return std::nullopt;\n\n    const char *dialog = nullptr;\n    if (ScriptEngine::rawGet(pEntity, \"dialog\", dialog))\n      return std::make_optional(VerbConstants::VERB_TALKTO);\n\n    int value = 0;\n    if (ScriptEngine::rawGet(pEntity, \"defaultVerb\", value))\n      return std::make_optional(value);\n    return std::nullopt;\n  }\n};\n\nEntity::Entity() : m_pImpl(std::make_unique<Entity::Impl>()) {\n}\n\nEntity::~Entity() = default;\n\nvoid Entity::objectBumperCycle(bool enabled) { m_pImpl->m_objectBumperCycle = enabled; }\n\nbool Entity::objectBumperCycle() const { return m_pImpl->m_objectBumperCycle; }\n\nvoid Entity::update(const ngf::TimeSpan &elapsed) {\n  m_pImpl->m_talkingState.update(elapsed);\n  update(m_pImpl->m_offsetTo, elapsed);\n  update(m_pImpl->m_scaleTo, elapsed);\n  update(m_pImpl->m_rotateTo, elapsed);\n  update(m_pImpl->m_moveTo, elapsed);\n  update(m_pImpl->m_alphaTo, elapsed);\n  update(m_pImpl->m_shake, elapsed);\n  update(m_pImpl->m_jiggle, elapsed);\n}\n\nvoid Entity::update(Motor &motor, const ngf::TimeSpan &elapsed) {\n  if (motor.isEnabled) {\n    (*motor.function)(elapsed);\n    if (motor.isEnabled && motor.function->isElapsed()) {\n      motor.isEnabled = false;\n    }\n  }\n}\n\nvoid Entity::setLit(bool isLit) {\n  m_pImpl->m_isLit = isLit;\n}\n\nbool Entity::isLit() const {\n  return m_pImpl->m_isLit;\n}\n\nvoid Entity::setVisible(bool isVisible) {\n  ScriptEngine::set(getTable(), \"_hidden\", !isVisible);\n}\n\nbool Entity::isVisible() const {\n  auto hidden = false;\n  ScriptEngine::rawGet(getTable(), \"_hidden\", hidden);\n  return !hidden;\n}\n\nvoid Entity::setUsePosition(std::optional<glm::vec2> pos) {\n  m_pImpl->m_usePos = std::move(pos);\n}\n\nvoid Entity::setUseDirection(std::optional<UseDirection> direction) {\n  m_pImpl->m_useDir = direction;\n}\n\nstd::optional<UseDirection> Entity::getUseDirection() const {\n  return m_pImpl->m_useDir;\n}\n\nvoid Entity::setPosition(const glm::vec2 &pos) {\n  m_pImpl->m_transform.setPosition(pos);\n  m_pImpl->m_moveTo.isEnabled = false;\n}\n\nglm::vec2 Entity::getPosition() const {\n  return m_pImpl->m_transform.getPosition();\n}\n\nglm::vec2 Entity::getRealPosition() const {\n  return m_pImpl->m_transform.getPosition() + m_pImpl->m_offset;\n}\n\nvoid Entity::setOffset(const glm::vec2 &offset) {\n  m_pImpl->m_offset = offset;\n  m_pImpl->m_offsetTo.isEnabled = false;\n}\n\nglm::vec2 Entity::getOffset() const {\n  return m_pImpl->m_offset + m_pImpl->m_shakeOffset;\n}\n\nvoid Entity::setRotation(float angle) {\n  m_pImpl->m_transform.setRotation(angle);\n  m_pImpl->m_rotateTo.isEnabled = false;\n}\n\nfloat Entity::getRotation() const {\n  // rotation is in degree between [0, 360]\n  float angle = m_pImpl->m_transform.getRotation();\n  // convert it to [-180, 180]\n  if (angle > 180)\n    angle -= 360;\n  return angle;\n}\n\nvoid Entity::setColor(const ngf::Color &color) {\n  ScriptEngine::set(getTable(), \"_color\", toInteger(color));\n  m_pImpl->m_alphaTo.isEnabled = false;\n}\n\nngf::Color Entity::getColor() const {\n  auto color = toInteger(ngf::Colors::White);\n  ScriptEngine::rawGet(getTable(), \"_color\", color);\n  return fromRgba(color);\n}\n\nvoid Entity::setScale(float s) {\n  m_pImpl->m_transform.setScale({s, s});\n  m_pImpl->m_scaleTo.isEnabled = false;\n}\n\nfloat Entity::getScale() const {\n  return m_pImpl->m_transform.getScale().x;\n}\n\nngf::Transform Entity::getTransform() const {\n  auto transform = m_pImpl->m_transform;\n  transform.move(getOffset());\n  transform.rotate(m_pImpl->m_jiggleOffset);\n  return transform;\n}\n\nstd::optional<glm::vec2> Entity::getUsePosition() const {\n  return m_pImpl->m_usePos;\n}\n\nvoid Entity::setTrigger(int triggerNumber, Trigger *pTrigger) {\n  m_pImpl->m_triggers[triggerNumber] = pTrigger;\n}\n\nvoid Entity::removeTrigger(int triggerNumber) {\n  m_pImpl->m_triggers.erase(triggerNumber);\n}\n\nvoid Entity::trig(const std::string &name) {\n  char *end;\n  auto id = std::strtol(name.data() + 1, &end, 10);\n  if (end == name.data() + 1) {\n    // trig sound\n    auto soundId = EntityManager::getSoundDefinition(ScriptEngine::getVm(), name.data() + 1);\n    if (!soundId)\n      return;\n    m_pImpl->m_engine.getSoundManager().playSound(soundId);\n  } else {\n    // find a corresponding trigger\n    auto it = m_pImpl->m_triggers.find(id);\n    if (it != m_pImpl->m_triggers.end()) {\n      it->second->trig();\n    }\n  }\n}\n\nvoid Entity::drawForeground(ngf::RenderTarget &target, ngf::RenderStates s) const {\n  if (!m_pImpl->m_talkingState.isTalking())\n    return;\n\n  m_pImpl->m_talkingState.draw(target, s);\n}\n\nSoundTrigger *Entity::createSoundTrigger(Engine &engine, const std::vector<std::shared_ptr<SoundDefinition>> &sounds) {\n  auto trigger = std::make_unique<SoundTrigger>(engine, sounds, this->getId());\n  SoundTrigger *pTrigger = trigger.get();\n  m_pImpl->m_soundTriggers.push_back(std::move(trigger));\n  return pTrigger;\n}\n\nvoid Entity::setKey(const std::string &key) { m_pImpl->m_key = key; }\n\nconst std::string &Entity::getKey() const { return m_pImpl->m_key; }\n\nuint32_t Entity::getFlags() const {\n  int flags = 0;\n  ScriptEngine::rawGet(this, \"flags\", flags);\n  return (uint32_t) flags;\n}\n\nvoid Entity::setTouchable(bool isTouchable) {\n  ScriptEngine::set(getTable(), \"_touchable\", isTouchable);\n}\n\nbool Entity::isTouchable() const {\n  if (!isVisible())\n    return false;\n  int touchable = 1;\n  if (!ScriptEngine::rawGet(getTable(), \"_touchable\", touchable)) {\n    ScriptEngine::rawGet(getTable(), \"initTouchable\", touchable);\n  }\n  return touchable != 0;\n}\n\nvoid Entity::setRenderOffset(const glm::ivec2 &offset) {\n  m_pImpl->m_renderOffset = offset;\n}\n\nglm::ivec2 Entity::getRenderOffset() const {\n  return m_pImpl->m_renderOffset;\n}\n\nvoid Entity::shake(float amount) {\n  auto setShake = [this](const auto &offset) { m_pImpl->m_shakeOffset = offset; };\n  auto shake = std::make_unique<ShakeFunction>(setShake, amount);\n  m_pImpl->m_shake.function = std::move(shake);\n  m_pImpl->m_shake.isEnabled = true;\n}\n\nvoid Entity::jiggle(float amount) {\n  auto setJiggle = [this](const auto &offset) { m_pImpl->m_jiggleOffset = offset; };\n  auto jiggle = std::make_unique<JiggleFunction>(setJiggle, amount);\n  m_pImpl->m_jiggle.function = std::move(jiggle);\n  m_pImpl->m_jiggle.isEnabled = true;\n}\n\nvoid Entity::alphaTo(float destination, ngf::TimeSpan time, InterpolationMethod method) {\n  auto getAlpha = [this] { return getColor().a; };\n  auto setAlpha = [this](const float &a) {\n    auto color = getColor();\n    color.a = a;\n    ScriptEngine::set(getTable(), \"_color\", toInteger(color));\n  };\n  auto alphaTo = std::make_unique<ChangeProperty<float>>(getAlpha, setAlpha, destination, time, method);\n  m_pImpl->m_alphaTo.function = std::move(alphaTo);\n  m_pImpl->m_alphaTo.isEnabled = true;\n}\n\nvoid Entity::offsetTo(glm::vec2 destination, ngf::TimeSpan time, InterpolationMethod method) {\n  auto get = [this] { return m_pImpl->m_offset; };\n  auto set = [this](const glm::vec2 &value) { m_pImpl->m_offset = value; };\n  auto offsetTo = std::make_unique<ChangeProperty<glm::vec2>>(get, set, destination, time, method);\n  m_pImpl->m_offsetTo.function = std::move(offsetTo);\n  m_pImpl->m_offsetTo.isEnabled = true;\n}\n\nvoid Entity::moveTo(glm::vec2 destination, ngf::TimeSpan time, InterpolationMethod method) {\n  auto get = [this] { return m_pImpl->m_transform.getPosition(); };\n  auto set = [this](const glm::vec2 &value) { m_pImpl->m_transform.setPosition(value); };\n  auto moveTo = std::make_unique<ChangeProperty<glm::vec2>>(get, set, destination, time, method);\n  m_pImpl->m_moveTo.function = std::move(moveTo);\n  m_pImpl->m_moveTo.isEnabled = true;\n}\n\nvoid Entity::rotateTo(float destination, ngf::TimeSpan time, InterpolationMethod method) {\n  auto get = [this] { return m_pImpl->m_transform.getRotation(); };\n  auto set = [this](const float &value) { m_pImpl->m_transform.setRotation(value); };\n  auto rotateTo =\n      std::make_unique<ChangeProperty<float>>(get, set, destination, time, method);\n  m_pImpl->m_rotateTo.function = std::move(rotateTo);\n  m_pImpl->m_rotateTo.isEnabled = true;\n}\n\nvoid Entity::scaleTo(float destination, ngf::TimeSpan time, InterpolationMethod method) {\n  auto get = [this] { return m_pImpl->m_transform.getScale().x; };\n  auto set = [this](const float &s) { m_pImpl->m_transform.setScale({s, s}); };\n  auto scalteTo = std::make_unique<ChangeProperty<float>>(get, set, destination, time, method);\n  m_pImpl->m_scaleTo.function = std::move(scalteTo);\n  m_pImpl->m_scaleTo.isEnabled = true;\n}\n\nvoid Entity::setName(const std::string &name) {\n  ScriptEngine::set(getTable(), \"name\", name.c_str());\n}\nstd::string Entity::getName() const {\n  const char *name = nullptr;\n  ScriptEngine::get(getTable(), \"name\", name);\n  if (!name)\n    return std::string();\n  return name;\n}\n\nvoid Entity::stopObjectMotors() {\n  m_pImpl->m_offsetTo.isEnabled = false;\n  m_pImpl->m_scaleTo.isEnabled = false;\n  m_pImpl->m_rotateTo.isEnabled = false;\n  m_pImpl->m_moveTo.isEnabled = false;\n  m_pImpl->m_alphaTo.isEnabled = false;\n  m_pImpl->m_shake.isEnabled = false;\n  m_pImpl->m_jiggle.isEnabled = false;\n  for (auto &&child : m_pImpl->m_children) {\n    child->stopObjectMotors();\n  }\n}\n\nvoid Entity::setTalkColor(ngf::Color color) { m_pImpl->m_talkColor = color; }\n\nngf::Color Entity::getTalkColor() const { return m_pImpl->m_talkColor; }\n\nvoid Entity::setTalkOffset(const glm::ivec2 &offset) { m_pImpl->m_talkOffset = offset; }\n\nglm::ivec2 Entity::getTalkOffset() const { return m_pImpl->m_talkOffset; }\n\nvoid Entity::say(const std::string &text, bool mumble) {\n  m_pImpl->m_talkingState.loadLip(text, this, mumble);\n  glm::vec2 pos;\n  auto screenSize = m_pImpl->m_engine.getRoom()->getScreenSize();\n  if (getRoom() == m_pImpl->m_engine.getRoom()) {\n    auto at = m_pImpl->m_engine.getCamera().getRect().getTopLeft();\n    pos = getPosition();\n    pos = {pos.x - at.x + m_pImpl->m_talkOffset.x + m_pImpl->m_renderOffset.x,\n           screenSize.y - pos.y - at.y - m_pImpl->m_talkOffset.y - m_pImpl->m_renderOffset.y};\n  } else {\n    // TODO: the position in this case is wrong, don't know what to do yet\n    pos = (glm::vec2) m_pImpl->m_talkOffset;\n  }\n  pos = toDefaultView((glm::ivec2) pos, m_pImpl->m_engine.getRoom()->getScreenSize());\n  m_pImpl->m_talkingState.setPosition(pos);\n}\n\nvoid Entity::stopTalking() { m_pImpl->m_talkingState.stop(); }\n\nbool Entity::isTalking() const { return m_pImpl->m_talkingState.isTalking(); }\n\nint Entity::getDefaultVerb(int defaultVerbId) const {\n  auto result = m_pImpl->getDefaultVerb(this);\n  if (result.has_value())\n    return result.value();\n\n  result = m_pImpl->getDefaultVerb(getActor(this));\n  return result.value_or(defaultVerbId);\n}\n\nActor *Entity::getActor(const Entity *pEntity) {\n  // if an actor has the same name then get its flags\n  auto &actors = Locator<Engine>::get().getActors();\n  auto itActor = std::find_if(actors.begin(), actors.end(), [pEntity](auto &pActor) -> bool {\n    return pActor->getName() == pEntity->getName();\n  });\n  if (itActor != actors.end()) {\n    return itActor->get();\n  }\n  return nullptr;\n}\n\nEntity *Entity::getParent() {\n  return m_pImpl->m_pParent;\n}\n\nconst Entity *Entity::getParent() const {\n  return m_pImpl->m_pParent;\n}\n\nbool Entity::hasParent() const { return m_pImpl->m_pParent != nullptr; }\n\nvoid Entity::setParent(Entity *pParent) {\n  auto pOldParent = m_pImpl->m_pParent;\n  if (pOldParent) {\n    pOldParent->m_pImpl->m_children.erase(std::remove_if(pOldParent->m_pImpl->m_children.begin(),\n                                                         pOldParent->m_pImpl->m_children.end(),\n                                                         [this](const auto *pChild) {\n                                                           return pChild == this;\n                                                         }), pOldParent->m_pImpl->m_children.end());\n  }\n  m_pImpl->m_pParent = pParent;\n  if (pParent) {\n    pParent->m_pImpl->m_children.push_back(this);\n  }\n}\n\nstd::vector<Entity *> Entity::getChildren() const {\n  return m_pImpl->m_children;\n}\n\nvoid Entity::setVolume(float volume) {\n  ScriptEngine::set(getTable(), \"_volume\", std::clamp(volume, 0.f, 1.f));\n}\n\nfloat Entity::getVolume() const {\n  float volume = 1.f;\n  ScriptEngine::rawGet(getTable(), \"_volume\", volume);\n  return volume;\n}\n\n} // namespace ng"
  },
  {
    "path": "src/Entities/JiggleFunction.cpp",
    "content": "#include \"JiggleFunction.hpp\"\n\nnamespace ng {\nJiggleFunction::JiggleFunction(std::function<void(float)> jiggle, float amount)\n    : m_jiggle(std::move(jiggle)), m_amount(amount) {}\n\nJiggleFunction::~JiggleFunction() = default;\n\nbool JiggleFunction::isElapsed() { return false; }\n\nvoid JiggleFunction::operator()(const ngf::TimeSpan &elapsed) {\n  m_jiggleTime += 20.f * elapsed.getTotalSeconds();\n  m_jiggle(m_amount * sinf(m_jiggleTime));\n}\n}"
  },
  {
    "path": "src/Entities/JiggleFunction.hpp",
    "content": "#pragma once\n#include <functional>\n#include <glm/vec2.hpp>\n#include <ngf/System/TimeSpan.h>\n#include <engge/Engine/Function.hpp>\n\nnamespace ng {\nclass JiggleFunction final : public Function {\npublic:\n  JiggleFunction(std::function<void(float)> jiggle, float amount);\n  ~JiggleFunction() final;\n\n  bool isElapsed() final;\n  void operator()(const ngf::TimeSpan &elapsed) final;\n\nprivate:\n  std::function<void(float)> m_jiggle;\n  float m_amount{0.f};\n  float m_jiggleTime{0.f};\n};\n}"
  },
  {
    "path": "src/Entities/LipAnimation.cpp",
    "content": "#include \"LipAnimation.hpp\"\n#include <engge/Entities/Actor.hpp>\n#include <engge/Entities/Costume.hpp>\n\nnamespace ng {\nvoid LipAnimation::load(const std::string &path) {\n  m_lip.load(path);\n  m_index = 0;\n  m_elapsed = ngf::TimeSpan::seconds(0);\n  updateHead();\n}\n\nvoid LipAnimation::clear() {\n  m_lip.clear();\n  m_index = 0;\n}\n\nvoid LipAnimation::setActor(Actor *pActor) {\n  m_pActor = pActor;\n}\n\nvoid LipAnimation::update(const ngf::TimeSpan &elapsed) {\n  if (m_lip.getData().empty() || m_index == static_cast<int>(m_lip.getData().size()))\n    return;\n\n  auto time = m_lip.getData().at(m_index).time;\n  m_elapsed += elapsed;\n  const auto lipSize = static_cast<int>(m_lip.getData().size());\n  if ((m_elapsed > time) && (m_index < lipSize)) {\n    m_index++;\n  }\n  if (m_index == static_cast<int>(m_lip.getData().size())) {\n    end();\n    return;\n  }\n  updateHead();\n}\n\nvoid LipAnimation::end() {\n  if (!m_pActor)\n    return;\n  m_pActor->getCostume().setHeadIndex(0);\n}\n\nvoid LipAnimation::updateHead() {\n  if (m_lip.getData().empty() && m_index >= static_cast<int>(m_lip.getData().size()))\n    return;\n  auto letter = m_lip.getData().at(m_index).letter;\n  if (letter == 'X' || letter == 'G')\n    letter = 'A';\n  if (letter == 'H')\n    letter = 'D';\n  auto index = letter - 'A';\n//    trace(\"lip: {} {}\", _lip.getData().at(_index).time.asSeconds(), _lip.getData().at(_index).letter);\n  // TODO: what is the correspondence between letter and head index ?\n  m_pActor->getCostume().setHeadIndex(index);\n}\n\nngf::TimeSpan LipAnimation::getDuration() const {\n  if (m_lip.getData().empty())\n    return ngf::TimeSpan(0);\n  return m_lip.getData().back().time;\n}\n}\n"
  },
  {
    "path": "src/Entities/LipAnimation.hpp",
    "content": "#pragma once\n#include <ngf/System/TimeSpan.h>\n#include <engge/Parsers/Lip.hpp>\n\nnamespace ng {\nclass Actor;\n\nclass LipAnimation final {\npublic:\n  void load(const std::string &path);\n\n  void clear();\n  void setActor(Actor *pActor);\n  void update(const ngf::TimeSpan &elapsed);\n  void end();\n  [[nodiscard]] ngf::TimeSpan getDuration() const;\n\nprivate:\n  void updateHead();\n\nprivate:\n  Lip m_lip;\n  Actor *m_pActor{nullptr};\n  int m_index{0};\n  ngf::TimeSpan m_elapsed;\n};\n}\n"
  },
  {
    "path": "src/Entities/Object.cpp",
    "content": "#ifdef _WIN32\n// for Windows you'll need this to have M_PI_2 defined\n#define _USE_MATH_DEFINES\n#include <cmath>\n#endif\n#include <engge/Entities/Object.hpp>\n#include <engge/Engine/Function.hpp>\n#include <engge/System/Locator.hpp>\n#include <engge/Engine/EntityManager.hpp>\n#include <engge/Room/Room.hpp>\n#include <engge/Graphics/Screen.hpp>\n#include <engge/Scripting/ScriptEngine.hpp>\n#include <engge/Audio/SoundTrigger.hpp>\n#include <engge/Engine/Trigger.hpp>\n#include <engge/Engine/Preferences.hpp>\n#include \"Util/Util.hpp\"\n#include <sstream>\n#include <ngf/Graphics/Sprite.h>\n#include <engge/Graphics/AnimDrawable.hpp>\n\nnamespace ng {\nstruct Object::Impl {\n  std::vector<Animation> anims;\n  Animation *pAnim{nullptr};\n  std::wstring name;\n  int zorder{0};\n  ObjectType type{ObjectType::Object};\n  ngf::irect hotspot;\n  Room *pRoom{nullptr};\n  int state{0};\n  std::optional<std::shared_ptr<Trigger>> trigger;\n  HSQOBJECT table{};\n  bool hotspotVisible{false};\n  bool triggerEnabled{true};\n  Object *pParentObject{nullptr};\n  int dependentState{0};\n  Actor *owner{nullptr};\n  int fps{0};\n  std::vector<std::string> icons;\n  ngf::TimeSpan elapsed;\n  ngf::TimeSpan popElapsed;\n  int iconIndex{0};\n  ScreenSpace screenSpace{ScreenSpace::Room};\n  bool temporary{false};\n  bool jiggle{false};\n  int pop{0};\n  AnimControl animControl;\n\n  Impl() {\n    auto v = ScriptEngine::getVm();\n    sq_resetobject(&table);\n    sq_newtable(v);\n    sq_getstackobj(v, -1, &table);\n    sq_addref(v, &table);\n    sq_pop(v, 1);\n  }\n\n  explicit Impl(HSQOBJECT obj) {\n    auto v = ScriptEngine::getVm();\n    sq_pushobject(v, obj);\n    sq_getstackobj(v, -1, &table);\n    sq_addref(v, &table);\n    sq_pop(v, 1);\n  }\n\n  ~Impl() {\n    auto v = ScriptEngine::getVm();\n    sq_release(v, &table);\n  }\n};\n\nObject::Object() : pImpl(std::make_unique<Impl>()) {\n  m_id = Locator<EntityManager>::get().getObjectId();\n  ScriptEngine::set(this, \"_id\", m_id);\n}\n\nObject::Object(HSQOBJECT obj) : pImpl(std::make_unique<Impl>(obj)) {\n  m_id = Locator<EntityManager>::get().getObjectId();\n  ScriptEngine::set(this, \"_id\", m_id);\n}\n\nObject::~Object() = default;\n\nvoid Object::setZOrder(int zorder) { pImpl->zorder = zorder; }\n\nint Object::getZOrder() const { return pImpl->zorder; }\n\nvoid Object::setType(ObjectType type) { pImpl->type = type; }\nObjectType Object::getType() const { return pImpl->type; }\n\nvoid Object::setHotspot(const ngf::irect &hotspot) { pImpl->hotspot = hotspot; }\nngf::irect Object::getHotspot() const { return pImpl->hotspot; }\n\nvoid Object::setIcon(const std::string &icon) {\n  pImpl->icons.clear();\n  pImpl->fps = 0;\n  pImpl->iconIndex = 0;\n  pImpl->elapsed = ngf::TimeSpan::seconds(0);\n  pImpl->icons.push_back(icon);\n}\n\nstd::string Object::getIcon() const {\n  if (!pImpl->icons.empty())\n    return pImpl->icons.at(pImpl->iconIndex);\n\n  auto v = ScriptEngine::getVm();\n  auto top = sq_gettop(v);\n  sq_pushobject(v, getTable());\n  sq_pushstring(v, _SC(\"icon\"), -1);\n  if (SQ_SUCCEEDED(sq_rawget(v, -2))) {\n    if (sq_gettype(v, -1) == OT_STRING) {\n      const SQChar *icon = nullptr;\n      sq_getstring(v, -1, &icon);\n      pImpl->icons.emplace_back(icon);\n    } else if (sq_gettype(v, -1) == OT_ARRAY) {\n      SQInteger fps = 0;\n      pImpl->iconIndex = 0;\n      const SQChar *icon = nullptr;\n      sq_pushnull(v); // null iterator\n      if (SQ_SUCCEEDED(sq_next(v, -2))) {\n        sq_getinteger(v, -1, &fps);\n        sq_pop(v, 2);\n        pImpl->fps = static_cast<int>(fps);\n      }\n      while (SQ_SUCCEEDED(sq_next(v, -2))) {\n        sq_getstring(v, -1, &icon);\n        pImpl->icons.emplace_back(icon);\n        sq_pop(v, 2);\n      }\n      sq_pop(v, 1); // pops the null iterator\n    }\n  }\n  sq_settop(v, top);\n  return pImpl->icons.at(pImpl->iconIndex);\n}\n\nvoid Object::setIcon(int fps, const std::vector<std::string> &icons) {\n  pImpl->icons.clear();\n  pImpl->fps = fps;\n  pImpl->iconIndex = 0;\n  pImpl->elapsed = ngf::TimeSpan::seconds(0);\n  std::copy(icons.begin(), icons.end(), std::back_inserter(pImpl->icons));\n}\n\nvoid Object::setOwner(Actor *pActor) { pImpl->owner = pActor; }\nActor *Object::getOwner() const { return pImpl->owner; }\n\nHSQOBJECT &Object::getTable() { return pImpl->table; }\nHSQOBJECT &Object::getTable() const { return pImpl->table; }\nbool Object::isInventoryObject() const { return getOwner() != nullptr; }\n\nstd::vector<Animation> &Object::getAnims() { return pImpl->anims; }\n\nRoom *Object::getRoom() { return pImpl->pRoom; }\nconst Room *Object::getRoom() const { return pImpl->pRoom; }\nvoid Object::setRoom(Room *pRoom) { pImpl->pRoom = pRoom; }\n\nvoid Object::addTrigger(const std::shared_ptr<Trigger> &trigger) { pImpl->trigger = trigger; }\n\nvoid Object::removeTrigger() {\n  if (pImpl->trigger.has_value()) {\n    (*pImpl->trigger)->disable();\n  }\n}\n\nTrigger *Object::getTrigger() { return pImpl->trigger.has_value() ? (*pImpl->trigger).get() : nullptr; }\nvoid Object::enableTrigger(bool enabled) { pImpl->triggerEnabled = enabled; }\n\nbool Object::isTouchable() const {\n  if (getType() != ObjectType::Object)\n    return false;\n  if (pImpl->state == ObjectStateConstants::GONE)\n    return false;\n  return Entity::isTouchable();\n}\n\nngf::irect Object::getRealHotspot() const {\n  auto rect = getHotspot();\n  auto rectf = ngf::frect::fromPositionSize(rect.getPosition(), rect.getSize());\n  auto transform = getTransform().getTransform();\n  auto result = ngf::transform(transform, rectf);\n  return ngf::irect::fromPositionSize(result.getPosition(), result.getSize());\n}\n\nvoid Object::setStateAnimIndex(int animIndex) {\n  pImpl->state = animIndex;\n  std::string name = \"state\" + std::to_string(animIndex);\n  auto it = std::find_if(pImpl->anims.rbegin(), pImpl->anims.rend(), [&name](const auto &anim) {\n    return anim.name == name;\n  });\n  if (it == pImpl->anims.rend()) {\n    pImpl->pAnim = nullptr;\n    pImpl->animControl.setAnimation(nullptr);\n    return;\n  }\n\n  pImpl->pAnim = it.operator->();\n  pImpl->animControl.setAnimation(pImpl->pAnim);\n}\n\nvoid Object::playAnim(const std::string &anim, bool loop) {\n  setAnimation(anim);\n  pImpl->animControl.play(loop);\n}\n\nvoid Object::playAnim(int animIndex, bool loop) {\n  setStateAnimIndex(animIndex);\n  pImpl->animControl.play(loop);\n}\n\nint Object::getState() const { return pImpl->state; }\n\nvoid Object::setAnimation(const std::string &name) {\n  auto it = std::find_if(pImpl->anims.begin(), pImpl->anims.end(),\n                         [name](auto &animation) { return animation.name == name; });\n  if (it == pImpl->anims.end()) {\n    pImpl->pAnim = nullptr;\n    pImpl->animControl.setAnimation(nullptr);\n    return;\n  }\n\n  auto &anim = *it;\n  pImpl->pAnim = &anim;\n  pImpl->animControl.setAnimation(&anim);\n}\n\nAnimation *Object::getAnimation() { return pImpl->pAnim; }\nconst Animation *Object::getAnimation() const { return pImpl->pAnim; }\n\nAnimControl &Object::getAnimControl() { return pImpl->animControl; }\n\nvoid Object::update(const ngf::TimeSpan &elapsed) {\n  if (isInventoryObject()) {\n    if (pImpl->pop > 0) {\n      pImpl->popElapsed += elapsed;\n      if (pImpl->popElapsed.getTotalSeconds() > 0.5f) {\n        pImpl->pop--;\n        pImpl->popElapsed -= ngf::TimeSpan::seconds(0.5);\n      }\n    }\n    if (pImpl->fps == 0)\n      return;\n    pImpl->elapsed += elapsed;\n    if (pImpl->elapsed.getTotalSeconds() > (1.f / static_cast<float>(pImpl->fps))) {\n      pImpl->elapsed = ngf::TimeSpan::seconds(0);\n      pImpl->iconIndex = static_cast<int>((pImpl->iconIndex + 1) % pImpl->icons.size());\n    }\n    return;\n  }\n\n  Entity::update(elapsed);\n  if (pImpl->pParentObject) {\n    setVisible(pImpl->pParentObject->getState() == pImpl->dependentState);\n  }\n  pImpl->animControl.update(elapsed);\n  if (pImpl->triggerEnabled && pImpl->trigger.has_value()) {\n    (*pImpl->trigger)->trig();\n  }\n}\n\nvoid Object::showDebugHotspot(bool show) { pImpl->hotspotVisible = show; }\n\nbool Object::isHotspotVisible() const { return pImpl->hotspotVisible; }\n\nvoid Object::setScreenSpace(ScreenSpace screenSpace) { pImpl->screenSpace = screenSpace; }\n\nScreenSpace Object::getScreenSpace() const { return pImpl->screenSpace; }\n\nvoid Object::draw(ngf::RenderTarget &target, ngf::RenderStates states) const {\n  if (!isVisible())\n    return;\n\n  if (pImpl->screenSpace == ScreenSpace::Object)\n    return;\n\n  ngf::RenderStates initialStates = states;\n  ngf::Transform t = getTransform();\n\n  if (pImpl->pAnim) {\n    auto pos = t.getPosition();\n    auto scale = getScale();\n    t.setPosition({pos.x, pImpl->pRoom->getScreenSize().y - pos.y - scale * getRenderOffset().y});\n    states.transform = t.getTransform() * states.transform;\n\n    AnimDrawable animDrawable;\n    animDrawable.setAnim(pImpl->pAnim);\n    animDrawable.setColor(getColor());\n    animDrawable.draw(pos, target, states);\n  }\n\n  initialStates.transform = t.getTransform() * initialStates.transform;\n\n  for (const auto *pChild : getChildren()) {\n    pChild->draw(target, initialStates);\n  }\n}\n\nvoid Object::dependentOn(Object *parentObject, int state) {\n  pImpl->dependentState = state;\n  pImpl->pParentObject = parentObject;\n}\n\nvoid Object::setFps(int fps) {\n  if (pImpl->pAnim) {\n    pImpl->pAnim->fps = fps;\n  }\n}\n\nvoid Object::setTemporary(bool isTemporary) { pImpl->temporary = isTemporary; }\n\nbool Object::isTemporary() const { return pImpl->temporary; }\n\nvoid Object::setJiggle(bool enabled) { pImpl->jiggle = enabled; }\n\nbool Object::getJiggle() const { return pImpl->jiggle; }\n\nvoid Object::setPop(int count) {\n  pImpl->popElapsed = ngf::TimeSpan::seconds(0);\n  pImpl->pop = count;\n}\n\nint Object::getPop() const { return pImpl->pop; }\n\nfloat Object::getPopScale() const {\n  return 0.5f + 0.5f * sinf(static_cast<float>(-M_PI_2 + pImpl->popElapsed.getTotalSeconds() * 4 * M_PI));\n}\n\nstd::wostream &operator<<(std::wostream &os, const Object &obj) {\n  return os << towstring(obj.getName()) << L\" (\" << obj.getPosition().x << L\",\" << obj.getPosition().y << L\":\"\n            << obj.getZOrder() << L\")\";\n}\n\n} // namespace ng\n"
  },
  {
    "path": "src/Entities/ShakeFunction.cpp",
    "content": "#include \"ShakeFunction.hpp\"\n\nnamespace ng {\nShakeFunction::ShakeFunction(std::function<void(const glm::vec2 &)> shake, float amount)\n    : m_shake(std::move(shake)), m_amount(amount) {}\n\nShakeFunction::~ShakeFunction() = default;\n\nbool ShakeFunction::isElapsed() { return false; }\n\nvoid ShakeFunction::operator()(const ngf::TimeSpan &elapsed) {\n  m_shakeTime += 20.f * elapsed.getTotalSeconds();\n  m_shake({m_amount * cosf(m_shakeTime + 0.3f), m_amount * sinf(m_shakeTime)});\n}\n}"
  },
  {
    "path": "src/Entities/ShakeFunction.hpp",
    "content": "#pragma once\n#include <functional>\n#include <glm/vec2.hpp>\n#include <ngf/System/TimeSpan.h>\n#include <engge/Engine/Function.hpp>\n\nnamespace ng {\nclass ShakeFunction final : public Function {\npublic:\n  ShakeFunction(std::function<void(const glm::vec2 &)> shake, float amount);\n  ~ShakeFunction() final;\n\n  bool isElapsed() final;\n  void operator()(const ngf::TimeSpan &elapsed) final;\n\nprivate:\n  std::function<void(const glm::vec2 &)> m_shake;\n  float m_amount{0.f};\n  float m_shakeTime{0.f};\n};\n}"
  },
  {
    "path": "src/Entities/TalkingState.cpp",
    "content": "#include <engge/Engine/EngineSettings.hpp>\n#include <engge/Graphics/Text.hpp>\n#include \"TalkingState.hpp\"\n\nnamespace ng {\nvoid TalkingState::setPosition(glm::vec2 pos) {\n  m_transform.setPosition(pos);\n}\n\nvoid TalkingState::setEngine(Engine *pEngine) {\n  m_pEngine = pEngine;\n}\n\nvoid TalkingState::update(const ngf::TimeSpan &elapsed) {\n  if (!m_isTalking)\n    return;\n\n  bool end;\n  m_elapsed += elapsed;\n  auto pSound = dynamic_cast<SoundId *>(EntityManager::getSoundFromId(m_soundId));\n  if (pSound) {\n    end = !pSound->isPlaying();\n  } else {\n    end = m_elapsed > m_duration;\n  }\n\n  if (end) {\n    if (m_ids.empty()) {\n      m_isTalking = false;\n      m_lipAnim.end();\n      return;\n    }\n    auto[id, text, mumble] = m_ids.front();\n    loadId(id, text, mumble);\n    m_ids.erase(m_ids.begin());\n  }\n  m_lipAnim.update(elapsed);\n}\n\nvoid TalkingState::stop() {\n  m_ids.clear();\n  m_isTalking = false;\n  if (m_soundId) {\n    auto pSound = dynamic_cast<SoundId *>(EntityManager::getSoundFromId(m_soundId));\n    if (pSound) {\n      pSound->stop();\n    }\n    m_soundId = 0;\n  }\n}\n\nbool TalkingState::isTalking() const { return m_isTalking; }\n\nvoid TalkingState::setTalkColor(ngf::Color color) { m_talkColor = color; }\n\nvoid TalkingState::setDuration(ngf::TimeSpan duration) {\n  m_isTalking = true;\n  m_duration = duration;\n  trace(\"Talk duration: {}\", m_duration.getTotalSeconds());\n  m_elapsed = ngf::TimeSpan::seconds(0);\n}\n\nvoid TalkingState::setText(const std::wstring &text) { m_sayText = text; }\n\nvoid TalkingState::loadLip(const std::string &text, Entity *pEntity, bool mumble) {\n  m_pEntity = pEntity;\n  setTalkColor(pEntity->getTalkColor());\n\n  // load lip data\n  auto id = std::strtol(text.c_str() + 1, nullptr, 10);\n\n  if (m_isTalking) {\n    m_ids.emplace_back(id, text, mumble);\n    return;\n  }\n\n  loadId(id, text, mumble);\n}\n\nvoid TalkingState::draw(ngf::RenderTarget &target, ngf::RenderStates) const {\n  if (!m_isTalking)\n    return;\n\n  if (!m_pEngine->getPreferences().getUserPreference(PreferenceNames::DisplayText, PreferenceDefaultValues::DisplayText))\n    return;\n\n  auto view = target.getView();\n  target.setView(ngf::View(ngf::frect::fromPositionSize({0, 0}, {Screen::Width, Screen::Height})));\n\n  auto retroFonts = m_pEngine->getPreferences().getUserPreference(PreferenceNames::RetroFonts,\n                                                                  PreferenceDefaultValues::RetroFonts);\n  auto &font = m_pEngine->getResourceManager().getFont(retroFonts ? \"FontRetroSheet\" : \"FontModernSheet\");\n\n  ng::Text text;\n  text.setMaxWidth(static_cast<int>((Screen::Width * 3) / 4));\n  text.setFont(font);\n  text.setColor(m_talkColor);\n  text.setWideString(m_sayText);\n\n  auto bounds = text.getLocalBounds();\n  auto pos = m_transform.getPosition();\n\n  if ((pos.x + bounds.getWidth() / 2) > (Screen::Width - 20)) {\n    pos.x = Screen::Width - bounds.getWidth() - 20;\n  } else if ((pos.x - bounds.getWidth() / 2) < 20) {\n    pos.x = 20;\n  } else {\n    pos.x = pos.x - bounds.getWidth() / 2;\n  }\n  if ((pos.y + bounds.getHeight()) > (Screen::Height - 20)) {\n    pos.y = Screen::Height - 20 - bounds.getHeight();\n  } else if ((pos.y - bounds.getHeight()) < 20) {\n    pos.y = 20 + bounds.getHeight();\n  } else {\n    pos.y = pos.y - bounds.getHeight();\n  }\n  text.getTransform().setPosition(pos);\n  text.draw(target, {});\n\n// sf::RectangleShape shape;\n// shape.setFillColor(sf::Color::Transparent);\n// shape.setOutlineColor(sf::Color::White);\n// shape.setOutlineThickness(1.f);\n// shape.setSize(sf::Vector2f(bounds.width, bounds.height));\n// shape.setPosition(pos);\n// target.draw(shape);\n\n  target.setView(view);\n}\n\nvoid TalkingState::loadActorSpeech(const std::string &name, bool hearVoice) {\n  if (!hearVoice)\n    return;\n\n  auto soundDefinition = m_pEngine->getSoundManager().defineSound(name + \".ogg\");\n  if (!soundDefinition) {\n    error(\"File {}.ogg not found\", name);\n    return;\n  }\n\n  auto pSound = m_pEngine->getSoundManager().playTalkSound(soundDefinition, 1, ngf::TimeSpan::Zero, m_pEntity->getId());\n  if (pSound) {\n    m_soundId = pSound->getId();\n  }\n}\n\nvoid TalkingState::loadId(int id, const std::string &text, bool mumble) {\n  ScriptEngine::callFunc(id, \"onTalkieID\", m_pEntity, id);\n  auto sayText = id != 0 ? Engine::getText(id) : towstring(text);\n  setText(sayText);\n\n  const char *key = nullptr;\n  if (!ScriptEngine::rawGet(m_pEntity, \"_talkieKey\", key)) {\n    ScriptEngine::rawGet(m_pEntity, \"_key\", key);\n  }\n  auto name = str_toupper(key).append(\"_\").append(std::to_string(id));\n  std::string path;\n  path.append(name).append(\".lip\");\n\n  auto pActor = dynamic_cast<Actor *>(m_pEntity);\n  if (pActor) {\n    m_lipAnim.setActor(pActor);\n  }\n\n  // actor animation\n  std::wregex re(LR\"(\\{([^\\}]*)\\})\");\n  std::wsmatch matches;\n  std::string anim;\n\n  if (std::regex_search(m_sayText, matches, re)) {\n    anim = tostring(matches[1].str());\n    m_sayText = matches.suffix();\n    if (!pActor || anim == \"notalk\") {\n      mumble = true;\n    } else {\n      pActor->getCostume().setState(anim);\n    }\n  }\n\n  // force mumble if there is no lip file see issue #234\n  if (!mumble) {\n    mumble = !Locator<EngineSettings>::get().hasEntry(path);\n  }\n\n  if (pActor && !mumble) {\n    m_lipAnim.load(path);\n  } else {\n    m_lipAnim.clear();\n  }\n\n  auto hearVoice = (id != 0) && (m_pEngine->getPreferences().getTempPreference(TempPreferenceNames::ForceTalkieText,\n                                                                               TempPreferenceDefaultValues::ForceTalkieText)\n      || m_pEngine->getPreferences().getUserPreference(PreferenceNames::HearVoice,\n                                                       PreferenceDefaultValues::HearVoice));\n  if (hearVoice) {\n    setDuration(m_lipAnim.getDuration());\n  } else {\n    auto sayLineBaseTime = m_pEngine->getPreferences().getUserPreference(PreferenceNames::SayLineBaseTime,\n                                                                         PreferenceDefaultValues::SayLineBaseTime);\n    auto sayLineCharTime = m_pEngine->getPreferences().getUserPreference(PreferenceNames::SayLineCharTime,\n                                                                         PreferenceDefaultValues::SayLineCharTime);\n    auto sayLineMinTime = m_pEngine->getPreferences().getUserPreference(PreferenceNames::SayLineMinTime,\n                                                                        PreferenceDefaultValues::SayLineMinTime);\n    auto sayLineSpeed = m_pEngine->getPreferences().getUserPreference(PreferenceNames::SayLineSpeed,\n                                                                      PreferenceDefaultValues::SayLineSpeed);\n    auto speed = (sayLineBaseTime + sayLineCharTime * m_sayText.length()) / (0.2f + sayLineSpeed);\n    if (speed < sayLineMinTime)\n      speed = sayLineMinTime;\n    setDuration(ngf::TimeSpan::seconds(speed));\n  }\n\n  auto sayLine = tostring(m_sayText);\n  const char *pAnim = anim.empty() ? nullptr : anim.data();\n  ScriptEngine::rawCall(m_pEntity, \"sayingLine\", pAnim, sayLine);\n\n  loadActorSpeech(name, hearVoice);\n}\n}\n"
  },
  {
    "path": "src/Entities/TalkingState.hpp",
    "content": "#pragma once\n#include <ngf/Graphics/Text.h>\n#include <engge/Engine/Engine.hpp>\n#include <engge/Engine/EntityManager.hpp>\n#include <engge/Graphics/GGFont.hpp>\n#include <engge/Graphics/Screen.hpp>\n#include <engge/Scripting/ScriptEngine.hpp>\n#include <engge/Audio/SoundId.hpp>\n#include <engge/Engine/Preferences.hpp>\n#include <engge/Audio/SoundManager.hpp>\n#include \"LipAnimation.hpp\"\n#include \"Util/Util.hpp\"\n\nnamespace ng {\nclass TalkingState final : public ngf::Drawable {\npublic:\n  TalkingState() = default;\n  ~TalkingState() override = default;\n\n  void setPosition(glm::vec2 pos);\n\n  void setEngine(Engine *pEngine);\n\n  void update(const ngf::TimeSpan &elapsed);\n\n  void stop();\n\n  bool isTalking() const;\n\n  void setTalkColor(ngf::Color color);\n\n  void setDuration(ngf::TimeSpan duration);\n\n  void setText(const std::wstring &text);\n\n  void loadLip(const std::string &text, Entity *pEntity, bool mumble = false);\n\n  void draw(ngf::RenderTarget &target, ngf::RenderStates) const override;\n\nprivate:\n  void loadActorSpeech(const std::string &name, bool hearVoice);\n  void loadId(int id, const std::string &text, bool mumble);\n\nprivate:\n  Engine *m_pEngine{nullptr};\n  Entity *m_pEntity{nullptr};\n  bool m_isTalking{false};\n  std::wstring m_sayText;\n  ngf::Color m_talkColor{ngf::Colors::White};\n  ngf::TimeSpan m_elapsed;\n  ngf::TimeSpan m_duration;\n  LipAnimation m_lipAnim;\n  int m_soundId{0};\n  std::vector<std::tuple<int, std::string, bool>> m_ids;\n  ngf::Transform m_transform;\n};\n}"
  },
  {
    "path": "src/Entities/TextObject.cpp",
    "content": "#include <engge/Entities/TextObject.hpp>\n#include <ngf/Graphics/Text.h>\n#include <engge/Room/Room.hpp>\n#include <engge/Graphics/Text.hpp>\n#include \"Util/Util.hpp\"\n\nnamespace ng {\nnamespace {\nbool operator&(TextAlignment lhs, TextAlignment rhs) {\n  return static_cast<TextAlignment>(\n      static_cast<std::underlying_type<TextAlignment>::type>(lhs) &\n          static_cast<std::underlying_type<TextAlignment>::type>(rhs)) > TextAlignment::None;\n}\n\nngf::Anchor toAnchor(TextAlignment alignment) {\n  auto anchor = static_cast<int>(ngf::Anchor::CenterLeft);\n  if (alignment & TextAlignment::Center) {\n    anchor = static_cast<int>(ngf::Anchor::Center);\n  } else if (alignment & TextAlignment::Right) {\n    anchor = static_cast<int>(ngf::Anchor::CenterRight);\n  }\n  if (alignment & TextAlignment::Top) {\n    anchor -= 3;\n  } else if (alignment & TextAlignment::Bottom) {\n    anchor += 3;\n  }\n  return static_cast<ngf::Anchor>(anchor);\n}\n}\n\nTextObject::TextObject() {\n  setTemporary(true);\n}\n\nTextObject::~TextObject() = default;\n\nvoid TextObject::setText(const std::string &text) {\n  m_text = towstring(text);\n}\n\nstd::string TextObject::getText() const {\n  return tostring(m_text);\n}\n\nvoid TextObject::draw(ngf::RenderTarget &target, ngf::RenderStates states) const {\n  if (!isVisible())\n    return;\n\n  const auto view = target.getView();\n  if (getScreenSpace() == ScreenSpace::Object) {\n    target.setView(ngf::View(ngf::frect::fromPositionSize({0, 0}, {Screen::Width, Screen::Height})));\n  }\n\n  ng::Text txt;\n  txt.setFont(*m_font);\n  txt.setColor(getColor());\n  txt.setMaxWidth(static_cast<float>(m_maxWidth));\n  txt.setWideString(m_text);\n  txt.setAnchor(toAnchor(m_alignment));\n\n  auto height = target.getView().getSize().y;\n  auto transformable = getTransform();\n  transformable.setPosition({transformable.getPosition().x, height - transformable.getPosition().y});\n\n  if (getScreenSpace() == ScreenSpace::Object) {\n    ngf::RenderStates s;\n    s.transform = transformable.getTransform();\n    txt.draw(target, s);\n    target.setView(view);\n  } else {\n    states.transform = transformable.getTransform() * states.transform;\n    txt.draw(target, states);\n  }\n}\n\n} // namespace ng\n"
  },
  {
    "path": "src/Entities/WalkingState.cpp",
    "content": "#include \"WalkingState.hpp\"\n#include <engge/Entities/Actor.hpp>\n#include <engge/Entities/Costume.hpp>\n#include <engge/Scripting/ScriptEngine.hpp>\n#include <engge/System/Logger.hpp>\n\nnamespace ng {\nvoid WalkingState::setActor(Actor *pActor) { m_pActor = pActor; }\n\nvoid WalkingState::setDestination(const std::vector <glm::vec2> &path, std::optional <Facing> facing) {\n  m_path = path;\n  m_facing = facing;\n  m_path.erase(m_path.begin());\n  m_pActor->getCostume().setFacing(getFacing());\n  m_pActor->getCostume().setWalkState();\n  m_isWalking = true;\n  m_init = m_pActor->getPosition();\n  m_elapsed = ngf::TimeSpan::seconds(0);\n  trace(\"{} go to : {},{}\", m_pActor->getName(), m_path[0].x, m_path[0].y);\n}\n\nvoid WalkingState::stop() {\n  m_isWalking = false;\n  m_pActor->getCostume().setStandState();\n  if (ScriptEngine::rawExists(m_pActor, \"postWalking\")) {\n    ScriptEngine::objCall(m_pActor, \"postWalking\");\n  }\n}\n\nFacing WalkingState::getFacing() {\n  auto pos = m_pActor->getPosition();\n  auto dx = m_path[0].x - pos.x;\n  auto dy = m_path[0].y - pos.y;\n  if (fabs(dx) > fabs(dy))\n    return (dx > 0) ? Facing::FACE_RIGHT : Facing::FACE_LEFT;\n  return (dy < 0) ? Facing::FACE_FRONT : Facing::FACE_BACK;\n}\n\nvoid WalkingState::update(const ngf::TimeSpan &elapsed) {\n  if (!m_isWalking)\n    return;\n\n  // update actor position\n  m_elapsed += elapsed;\n  auto delta = (m_path[0] - m_init);\n  auto vSpeed = m_pActor->getWalkSpeed();\n  glm::vec2 vDuration;\n  vDuration.x = std::abs(delta.x) / vSpeed.x;\n  vDuration.y = std::abs(delta.y) / vSpeed.y;\n  auto maxDuration = std::max(vDuration.x, vDuration.y);\n  auto factor = (2.f * m_elapsed.getTotalSeconds()) / maxDuration;\n  auto end = factor >= 1.f;\n  auto newPos = end ? m_path[0] : (m_init + factor * delta);\n  m_pActor->setPosition(newPos);\n  if (!end)\n    return;\n\n  // if the actor is arrived to destination\n  m_path.erase(m_path.begin());\n  // check if we have an other destination\n  if (!m_path.empty()) {\n    m_pActor->getCostume().setFacing(getFacing());\n    m_pActor->getCostume().setWalkState();\n    m_init = newPos;\n    m_elapsed = ngf::TimeSpan::seconds(0);\n    trace(\"{} go to : {},{}\", m_pActor->getName(), m_path[0].x, m_path[0].y);\n    return;\n  }\n\n  // the actor is arrived to the final destination\n  stop();\n  trace(\"Play anim stand\");\n  if (m_facing.has_value()) {\n    m_pActor->getCostume().setFacing(m_facing.value());\n  }\n  if (ScriptEngine::rawExists(m_pActor, \"actorArrived\")) {\n    ScriptEngine::rawCall(m_pActor, \"actorArrived\");\n  }\n}\n}"
  },
  {
    "path": "src/Entities/WalkingState.hpp",
    "content": "#pragma once\n#include <optional>\n#include <vector>\n#include <glm/vec2.hpp>\n#include <ngf/System/TimeSpan.h>\n#include <engge/Entities/Facing.hpp>\n\nnamespace ng {\nclass Actor;\n\nclass WalkingState final {\npublic:\n  void setActor(Actor *pActor);\n  void setDestination(const std::vector<glm::vec2> &path, std::optional<Facing> facing);\n  void update(const ngf::TimeSpan &elapsed);\n  void stop();\n\n  [[nodiscard]] inline bool isWalking() const { return m_isWalking; }\n\nprivate:\n  Facing getFacing();\n\nprivate:\n  Actor *m_pActor{nullptr};\n  std::vector<glm::vec2> m_path;\n  std::optional<Facing> m_facing{Facing::FACE_FRONT};\n  bool m_isWalking{false};\n  glm::vec2 m_init{0, 0};\n  ngf::TimeSpan m_elapsed;\n};\n}"
  },
  {
    "path": "src/Graphics/AnimControl.cpp",
    "content": "#include <engge/Graphics/AnimControl.hpp>\n\nnamespace ng {\nvoid AnimControl::setAnimation(Animation *anim) {\n  m_anim = anim;\n  stop();\n}\n\nAnimation *AnimControl::getAnimation() { return m_anim; }\n\nvoid AnimControl::play(bool loop) {\n  m_loop = loop;\n  if (!m_anim)\n    return;\n  m_anim->state = AnimState::Play;\n  rewind(*m_anim);\n}\n\nvoid AnimControl::resume(bool loop) {\n  m_loop = loop;\n  if (!m_anim)\n    return;\n  m_anim->state = AnimState::Play;\n}\n\nvoid AnimControl::stop() {\n  if (!m_anim)\n    return;\n  m_anim->state = AnimState::Stopped;\n  resetAnim(*m_anim);\n}\n\nvoid AnimControl::pause() { m_anim->state = AnimState::Pause; }\n\nAnimState AnimControl::getState() const {\n  if (!m_anim)\n    return AnimState::Stopped;\n  return m_anim->state;\n}\n\nvoid AnimControl::update(const ngf::TimeSpan &e) {\n  if (!m_anim)\n    return;\n\n  if (m_anim->state != AnimState::Play)\n    return;\n\n  if (m_anim->frames.empty() && m_anim->layers.empty())\n    return;\n\n  if (!m_anim->frames.empty()) {\n    update(e, *m_anim);\n    return;\n  }\n\n  bool isOver = true;\n  for (auto &layer : m_anim->layers) {\n    update(e, layer);\n    isOver &= layer.state == ng::AnimState::Stopped;\n  }\n  if (isOver)\n    m_anim->state = ng::AnimState::Stopped;\n}\n\nbool AnimControl::getLoop() const { return m_loop; }\n\nvoid AnimControl::resetAnim(Animation &anim) {\n  if (!anim.frames.empty()) {\n    anim.state = ng::AnimState::Stopped;\n    anim.frameIndex = static_cast<int>(anim.frames.size()) - 1;\n  }\n  if (!anim.layers.empty()) {\n    std::for_each(anim.layers.begin(), anim.layers.end(), resetAnim);\n  }\n}\n\nvoid AnimControl::rewind(Animation &anim) {\n  if (!anim.frames.empty()) {\n    anim.frameIndex = 0;\n    anim.state = ng::AnimState::Play;\n  }\n  if (!anim.layers.empty()) {\n    std::for_each(anim.layers.begin(), anim.layers.end(), rewind);\n  }\n}\n\nvoid AnimControl::update(const ngf::TimeSpan &e, Animation &animation) const {\n  animation.elapsed += e;\n  auto fps = getFps(animation);\n  assert(fps > 0);\n\n  // frame time elapsed?\n  const auto frameTime = 1.f / static_cast<float>(fps);\n  if (animation.elapsed.getTotalSeconds() <= frameTime)\n    return;\n\n  animation.elapsed = ngf::TimeSpan::seconds(animation.elapsed.getTotalSeconds() - frameTime);\n  animation.frameIndex++;\n\n  // quit if animation length not reached\n  if (animation.frameIndex != static_cast<int>(animation.frames.size())) {\n    trig(animation);\n    return;\n  }\n\n  // loop if requested\n  if (m_loop || animation.loop) {\n    animation.frameIndex = 0;\n    return;\n  }\n\n  // or stay at the last frame\n  animation.frameIndex = animation.frameIndex - 1;\n  trig(animation);\n  animation.state = AnimState::Stopped;\n}\n\nint AnimControl::getFps(const Animation &animation) {\n  if (animation.fps <= 0)\n    return 10;\n  return animation.fps;\n}\n\nvoid AnimControl::trig(const Animation &animation) {\n  if (animation.callbacks.empty() || animation.frameIndex < 0\n      || animation.frameIndex >= static_cast<int>(animation.callbacks.size()))\n    return;\n\n  auto callback = animation.callbacks.at(animation.frameIndex);\n  if (callback) {\n    callback();\n  }\n}\n}"
  },
  {
    "path": "src/Graphics/AnimDrawable.cpp",
    "content": "#include <engge/Graphics/AnimDrawable.hpp>\n#include <engge/Graphics/Animation.hpp>\n#include <engge/Graphics/LightingShader.h>\n#include <ngf/Math/Transform.h>\n#include <ngf/Graphics/Sprite.h>\n#include <engge/Graphics/ResourceManager.hpp>\n#include <engge/System/Locator.hpp>\n\nnamespace ng {\nvoid AnimDrawable::setAnim(const Animation *anim) { m_anim = anim; }\n\nvoid AnimDrawable::setFlipX(bool flipX) { m_flipX = flipX; }\n\nvoid AnimDrawable::setColor(const ngf::Color &color) { m_color = color; }\n\nvoid AnimDrawable::draw(const glm::vec2 &pos, ngf::RenderTarget &target, ngf::RenderStates states) const {\n  if (!m_anim)\n    return;\n\n  if (m_anim->frames.empty() && m_anim->layers.empty())\n    return;\n\n  draw(pos, *m_anim, target, states);\n\n  for (const auto &layer : m_anim->layers) {\n    draw(pos, layer, target, states);\n  }\n}\n\nvoid AnimDrawable::draw(const glm::vec2 &pos,\n                        const Animation &anim,\n                        ngf::RenderTarget &target,\n                        ngf::RenderStates states) const {\n  if (!anim.visible)\n    return;\n  if (anim.frames.empty())\n    return;\n\n  glm::ivec2 offset{0, 0};\n  if (!anim.offsets.empty() && anim.frameIndex < static_cast<int>(anim.offsets.size())) {\n    offset = anim.offsets.at(anim.frameIndex);\n  }\n  const auto frame = anim.frames.at(anim.frameIndex);\n  if (frame.isNull)\n    return;\n\n  glm::vec2 origin = {static_cast<int>(frame.sourceSize.x / 2.f), static_cast<int>((frame.sourceSize.y + 1) / 2.f)};\n\n  glm::vec2 off = {m_flipX ? frame.sourceSize.x - frame.spriteSourceSize.min.x - offset.x :\n                   frame.spriteSourceSize.min.x + offset.x,\n                   frame.spriteSourceSize.min.y - offset.y};\n  ngf::Transform t;\n  t.setPosition(off);\n  t.setOrigin(origin);\n\n  // flip X if actor goes left\n  ngf::Transform tFlipX;\n  tFlipX.setScale({m_flipX ? -1 : 1, 1});\n  states.transform = tFlipX.getTransform() * t.getTransform() * states.transform;\n\n  auto pShader = (LightingShader *) states.shader;\n  auto texture = Locator<ResourceManager>::get().getTexture(anim.texture);\n  if (!texture)\n    return;\n\n  auto texSize = texture->getSize();\n  pShader->setTexture(*texture);\n  pShader->setContentSize(frame.sourceSize);\n  pShader->setSpriteOffset({-frame.frame.getWidth() / 2.f + pos.x, -frame.frame.getHeight() / 2.f - pos.y});\n  pShader->setSpritePosInSheet({static_cast<float>(frame.frame.min.x) / texSize.x,\n                                static_cast<float>(frame.frame.min.y) / texSize.y});\n  pShader->setSpriteSizeRelToSheet({static_cast<float>(frame.sourceSize.x) / texSize.x,\n                                    static_cast<float>(frame.sourceSize.y) / texSize.y});\n\n  ngf::Sprite sprite(*texture, frame.frame);\n  sprite.setColor(m_color);\n  sprite.draw(target, states);\n}\n}"
  },
  {
    "path": "src/Graphics/GGFont.cpp",
    "content": "#include <fstream>\n#include <ngf/IO/Json/JsonParser.h>\n#include \"engge/Engine/EngineSettings.hpp\"\n#include \"engge/Graphics/GGFont.hpp\"\n#include \"engge/System/Locator.hpp\"\n#include \"../Util/Util.hpp\"\n\nnamespace ng {\nGGFont::~GGFont() = default;\n\nconst std::shared_ptr<ngf::Texture> &GGFont::getTexture(unsigned int) const { return m_texture; }\n\nfloat GGFont::getKerning(unsigned int, unsigned int, unsigned int) const { return 0; }\n\nconst ngf::Glyph &GGFont::getGlyph(unsigned int codePoint) const {\n  if (m_glyphs.find(codePoint) == m_glyphs.end())\n    return m_glyphs.at(0x20);\n  return m_glyphs.at(codePoint);\n}\n\nvoid GGFont::setTextureManager(ResourceManager *textureManager) {\n  m_resourceManager = textureManager;\n}\n\nvoid GGFont::load(const std::string &path) {\n  m_path = path + \".png\";\n  m_jsonFilename = path + \".json\";\n\n  auto buffer = Locator<EngineSettings>::get().readBuffer(m_jsonFilename);\n  m_json = ngf::Json::parse(buffer.data());\n\n#if 0\n  std::ofstream o;\n  o.open(_jsonFilename);\n  o.write(buffer.data(), buffer.size());\n  o.close();\n#endif\n\n  m_texture = m_resourceManager->getTexture(m_path);\n\n  for (const auto &jFrame : m_json[\"frames\"].items()) {\n    auto sValue = jFrame.key();\n    auto key = std::stoi(sValue);\n    auto frame = toRect(m_json[\"frames\"][sValue][\"frame\"]);\n    auto spriteSourceSize = toRect(m_json[\"frames\"][sValue][\"spriteSourceSize\"]);\n    auto sourceSize = toSize(m_json[\"frames\"][sValue][\"sourceSize\"]);\n    ngf::Glyph glyph;\n    glyph.advance = std::max(sourceSize.x - spriteSourceSize.getTopLeft().x - 4, 0);\n    glyph.bounds = spriteSourceSize;\n    glyph.textureRect = frame;\n    m_glyphs[key] = glyph;\n  }\n}\n} // namespace ng\n"
  },
  {
    "path": "src/Graphics/GraphDrawable.cpp",
    "content": "#include \"GraphDrawable.hpp\"\n#include <ngf/Math/PathFinding/Graph.h>\n#include <ngf/Graphics/CircleShape.h>\n\nnamespace ng {\nGraphDrawable::GraphDrawable(const ngf::Graph &graph, int height)\n    : m_graph(graph), m_height(height) {\n}\n\nvoid GraphDrawable::draw(ngf::RenderTarget &target, ngf::RenderStates states) const {\n  ngf::Color color(180, 180, 250);\n  std::vector<ngf::Vertex> vertices;\n  for (const auto &edge : m_graph.edges) {\n    for (const auto &e : edge) {\n      auto nodeFrom = (glm::vec2)m_graph.nodes[e->from];\n      nodeFrom.y = m_height - nodeFrom.y;\n      auto nodeTo = (glm::vec2)m_graph.nodes[e->to];\n      nodeTo.y = m_height - nodeTo.y;\n      vertices.push_back({nodeFrom, color});\n      vertices.push_back({nodeTo, color});\n    }\n  }\n  target.draw(ngf::PrimitiveType::Lines, vertices, states);\n\n  for (auto node : m_graph.nodes) {\n    ngf::CircleShape shape(2);\n    auto pos = (glm::vec2)node;\n    pos.y = m_height - pos.y;\n    shape.getTransform().setOrigin({1, 1});\n    shape.getTransform().setPosition(pos);\n    shape.setColor(color);\n    shape.draw(target, states);\n  }\n}\n} // namespace ng\n"
  },
  {
    "path": "src/Graphics/GraphDrawable.hpp",
    "content": "#pragma once\n#include <vector>\n#include <memory>\n#include <ngf/Graphics/Drawable.h>\n#include <ngf/Graphics/RenderStates.h>\n#include <ngf/Graphics/RenderTarget.h>\n\nnamespace ngf {\n  class Graph;\n}\n\nnamespace ng {\n\nclass GraphDrawable : public ngf::Drawable {\npublic:\n  explicit GraphDrawable(const ngf::Graph &graph, int height);\n\n  void draw(ngf::RenderTarget &target, ngf::RenderStates states) const override;\n\nprivate:\n  const ngf::Graph &m_graph;\n  const int m_height;\n};\n\n} // namespace ng\n"
  },
  {
    "path": "src/Graphics/LightingShader.cpp",
    "content": "#include <engge/Graphics/LightingShader.h>\n\nnamespace ng {\nnamespace {\nconstexpr const char *vertexShaderCode =\n    R\"(#version 100\nprecision mediump float;\nattribute vec2 a_position;\nattribute vec4 a_color;\nattribute vec2 a_texCoords;\n\nuniform mat3 u_transform;\n\nvarying vec4 v_color;\nvarying vec2 v_texCoords;\n\nvoid main(void) {\n  v_color = a_color;\n  v_texCoords = a_texCoords;\n  vec3 worldPosition = vec3(a_position, 1);\n  vec3 normalizedPosition = worldPosition * u_transform;\n  gl_Position = vec4(normalizedPosition.xy, 0, 1);\n})\";\n\nconstexpr const char *fragmentShaderCode = R\"(#version 100\n#ifdef GL_ES\nprecision highp float;\n#endif\n\nvarying vec2 v_texCoords;\nvarying vec4 v_color;\n\nuniform sampler2D u_texture;\n\nuniform vec2  u_contentSize;\nuniform vec3  u_ambientColor;\nuniform vec2 u_spritePosInSheet;\nuniform vec2 u_spriteSizeRelToSheet;\nuniform vec2 u_spriteOffset;\n\nuniform int  u_numberLights;\nuniform vec3  u_lightPos[50];\nuniform vec3  u_lightColor[50];\nuniform float u_brightness[50];\nuniform float u_cutoffRadius[50];\nuniform float u_halfRadius[50];\nuniform float u_coneCosineHalfConeAngle[50];\nuniform float u_coneFalloff[50];\nuniform vec2  u_coneDirection[50];\n\nvoid main(void)\n{\n    vec4 texColor = texture2D(u_texture, v_texCoords);\n\n    vec2 spriteTexCoord = (v_texCoords - u_spritePosInSheet) / u_spriteSizeRelToSheet; // [0..1]\n    vec2 pixelPos = spriteTexCoord * u_contentSize + u_spriteOffset; // [0..origSize]\n    vec2 curPixelPosInLocalSpace = vec2(pixelPos.x, -pixelPos.y);\n\n    vec3 diffuse = vec3(0,0,0);\n    for ( int i = 0; i < u_numberLights; i ++)\n    {\n        vec2 lightVec = curPixelPosInLocalSpace.xy - u_lightPos[i].xy;\n        float coneValue = dot( normalize(-lightVec), u_coneDirection[i] );\n        if ( coneValue >= u_coneCosineHalfConeAngle[i] )\n        {\n            float intercept = u_cutoffRadius[i] * u_halfRadius[i];\n            float dx_1 = 0.5 / intercept;\n            float dx_2 = 0.5 / (u_cutoffRadius[i] - intercept);\n            float offset = 0.5 + intercept * dx_2;\n\n            float lightDist = length(lightVec);\n            float falloffTermNear = clamp((1.0 - lightDist * dx_1), 0.0, 1.0);\n            float falloffTermFar  = clamp((offset - lightDist * dx_2), 0.0, 1.0);\n            float falloffSelect = step(intercept, lightDist);\n            float falloffTerm = (1.0 - falloffSelect) * falloffTermNear + falloffSelect * falloffTermFar;\n            float spotLight = u_brightness[i] * falloffTerm;\n\n            vec3 ltdiffuse = vec3(u_brightness[i] * falloffTerm) * u_lightColor[i];\n\n            float coneRange = 1.0-u_coneCosineHalfConeAngle[i];\n            float halfConeRange = coneRange * u_coneFalloff[i];\n            float conePos   = 1.0-coneValue;\n            float coneFalloff = 1.0;\n            if ( conePos > halfConeRange )\n            {\n                coneFalloff = 1.0-((conePos-halfConeRange)/(coneRange-halfConeRange));\n            }\n\n            diffuse += ltdiffuse*coneFalloff;;\n        }\n    }\n    vec4 finalCol = texColor * v_color;\n    vec3 finalLight = (diffuse+u_ambientColor);\n    finalLight = min( finalLight, vec3(1,1,1) );\n    gl_FragColor = vec4(finalCol.rgb*finalLight, finalCol.a);\n})\";\n}\n\nLightingShader::LightingShader() {\n  load(vertexShaderCode, fragmentShaderCode);\n}\n\nvoid LightingShader::setContentSize(glm::vec2 size) {\n  setUniform(\"u_contentSize\", size);\n}\n\nvoid LightingShader::setSpritePosInSheet(glm::vec2 spritePosInSheet) {\n  setUniform(\"u_spritePosInSheet\", spritePosInSheet);\n}\n\nvoid LightingShader::setSpriteSizeRelToSheet(glm::vec2 spriteSizeRelToSheet) {\n  setUniform(\"u_spriteSizeRelToSheet\", spriteSizeRelToSheet);\n}\n\nvoid LightingShader::setSpriteOffset(glm::vec2 spriteOffset) {\n  setUniform(\"u_spriteOffset\", spriteOffset);\n}\n\nvoid LightingShader::setAmbientColor(ngf::Color color) {\n  setUniform3(\"u_ambientColor\", color);\n  m_ambient = color;\n}\n\nngf::Color LightingShader::getAmbientColor() const { return m_ambient; }\n\nvoid LightingShader::setTexture(const ngf::Texture &texture) {\n  setUniform(\"u_texture\", texture);\n}\n\nvoid LightingShader::setNumberLights(int numberLights) {\n  setUniform(\"u_numberLights\", numberLights);\n  m_numberLights = std::min(numberLights, LightingShader::MaxLights);\n}\n\nint LightingShader::getNumberLights() const { return m_numberLights; }\n\nvoid LightingShader::setLights(const std::array<Light, MaxLights> &lights) {\n  std::array<glm::vec3, MaxLights> u_lightPos{};\n  std::array<glm::vec2, MaxLights> u_coneDirection{};\n  std::array<float, MaxLights> u_coneCosineHalfConeAngle{};\n  std::array<float, MaxLights> u_coneFalloff{};\n  std::array<ngf::Color, MaxLights> u_lightColor;\n  std::array<float, MaxLights> u_brightness{};\n  std::array<float, MaxLights> u_cutoffRadius{};\n  std::array<float, MaxLights> u_halfRadius{};\n\n  int numLights = 0;\n  for (int i = 0; i < m_numberLights; ++i) {\n    auto &light = lights[i];\n    if (!light.on)\n      continue;\n    auto direction = light.coneDirection - 90.f;\n    u_coneDirection[numLights] = glm::vec2(std::cos(glm::radians(direction)), std::sin(glm::radians(direction)));\n    u_coneCosineHalfConeAngle[numLights] = cos(glm::radians(light.coneAngle / 2.f));\n    u_coneFalloff[numLights] = light.coneFalloff;\n    u_lightColor[numLights] = light.color;\n    u_lightPos[numLights] = glm::vec3(light.pos, 1.f);\n    u_brightness[numLights] = light.brightness;\n    u_cutoffRadius[numLights] = std::max(1.0f, light.cutOffRadius);\n    u_halfRadius[numLights] = std::max(0.01f, std::min(0.99f, light.halfRadius));\n    numLights++;\n  }\n  m_numberLights = numLights;\n  setUniformArray(\"u_lightPos\", u_lightPos.data(), MaxLights);\n  setUniformArray(\"u_coneDirection\", u_coneDirection.data(), MaxLights);\n  setUniformArray(\"u_coneCosineHalfConeAngle\", u_coneCosineHalfConeAngle.data(), MaxLights);\n  setUniformArray(\"u_coneFalloff\", u_coneFalloff.data(), MaxLights);\n  setUniformArray3(\"u_lightColor\", u_lightColor.data(), MaxLights);\n  setUniformArray(\"u_brightness\", u_brightness.data(), MaxLights);\n  setUniformArray(\"u_cutoffRadius\", u_cutoffRadius.data(), MaxLights);\n  setUniformArray(\"u_halfRadius\", u_halfRadius.data(), MaxLights);\n}\n}\n"
  },
  {
    "path": "src/Graphics/PathDrawable.cpp",
    "content": "#include <ngf/Graphics/CircleShape.h>\n#include \"PathDrawable.hpp\"\n\nnamespace ng {\nPathDrawable::PathDrawable(std::vector<glm::vec2> path)\n    : m_path(std::move(path)) {\n}\n\nvoid PathDrawable::draw(ngf::RenderTarget &target, ngf::RenderStates states) const {\n  auto height = target.getView().getSize().y;\n  auto color = ngf::Colors::Yellow;\n  std::vector<ngf::Vertex> lines(m_path.size());\n  for (size_t i = 0; i < m_path.size(); ++i) {\n    auto &node = m_path[i];\n    auto pos = glm::vec2(node.x, height - node.y);\n    lines[i].pos = pos;\n    lines[i].color = color;\n    ngf::CircleShape shape(1);\n    shape.getTransform().setPosition(pos - glm::vec2(0.5f, 0.5f));\n    shape.setColor(color);\n    shape.draw(target, states);\n  }\n  target.draw(ngf::PrimitiveType::LineStrip, lines, states);\n}\n}\n"
  },
  {
    "path": "src/Graphics/PathDrawable.hpp",
    "content": "#pragma once\n#include <vector>\n#include <memory>\n#include <glm/vec2.hpp>\n#include <ngf/Graphics/Drawable.h>\n#include <ngf/Graphics/RenderTarget.h>\n#include <ngf/Graphics/RenderStates.h>\n\nnamespace ng {\nclass PathDrawable final : public ngf::Drawable {\npublic:\n  explicit PathDrawable(std::vector<glm::vec2> path);\n\n  [[nodiscard]] const std::vector<glm::vec2> &getPath() const { return m_path; }\n  void draw(ngf::RenderTarget &target, ngf::RenderStates states) const override;\n\nprivate:\n  std::vector<glm::vec2> m_path;\n};\n}\n"
  },
  {
    "path": "src/Graphics/ResourceManager.cpp",
    "content": "#include \"engge/Engine/EngineSettings.hpp\"\n#include \"engge/Graphics/GGFont.hpp\"\n#include \"engge/System/Locator.hpp\"\n#include \"engge/System/Logger.hpp\"\n#include \"engge/Graphics/ResourceManager.hpp\"\n#include \"engge/Graphics/SpriteSheet.hpp\"\n#include <ngf/Graphics/FntFont.h>\n#include <ngf/IO/MemoryStream.h>\n\nnamespace ng {\nResourceManager::ResourceManager() = default;\nResourceManager::~ResourceManager() = default;\n\nvoid ResourceManager::load(const std::string &id) {\n  info(\"Load texture {}\", id);\n  auto data = Locator<EngineSettings>::get().readBuffer(id);\n\n#if 0\n  std::ofstream os(path, std::ios::out|std::ios::binary);\n  os.write(data.data(), data.size());\n  os.close();\n#endif\n\n  ngf::Image img;\n  if (!img.loadFromMemory(data.data(), data.size())) {\n    error(\"Fail to load texture {}\", id);\n  }\n\n  auto texture = std::make_shared<ngf::Texture>(img);\n  m_textureMap.insert(std::make_pair(id, TextureResource{texture, data.size()}));\n}\n\nvoid ResourceManager::loadFont(const std::string &id) {\n  info(\"Load font {}\", id);\n  auto font = std::make_shared<GGFont>();\n  font->setTextureManager(this);\n  font->load(id);\n  m_fontMap.insert(std::make_pair(id, font));\n}\n\nvoid ResourceManager::loadFntFont(const std::string &id) {\n  info(\"Load Fnt font {}\", id);\n  auto font = std::make_shared<ngf::FntFont>();\n\n  auto data = Locator<EngineSettings>::get().readBuffer(id);\n  ngf::MemoryStream ms(data.data(), data.data() + data.size());\n  font->load(id, ms, [](auto name) {\n    return Locator<ResourceManager>::get().getTexture(name.string());\n  });\n\n  m_fntFontMap.insert(std::make_pair(id, font));\n}\n\nvoid ResourceManager::loadSpriteSheet(const std::string &id) {\n  info(\"Load SpriteSheet {}\", id);\n  auto spriteSheet = std::make_shared<SpriteSheet>();\n  spriteSheet->setTextureManager(this);\n  spriteSheet->load(id);\n  m_spriteSheetMap.insert(std::make_pair(id, spriteSheet));\n}\n\nstd::shared_ptr<ngf::Texture> ResourceManager::getTexture(const std::string &id) {\n  auto found = m_textureMap.find(id);\n  if (found == m_textureMap.end()) {\n    load(id);\n    found = m_textureMap.find(id);\n  }\n  return found->second.texture;\n}\n\nGGFont &ResourceManager::getFont(const std::string &id) {\n  auto found = m_fontMap.find(id);\n  if (found == m_fontMap.end()) {\n    loadFont(id);\n    found = m_fontMap.find(id);\n  }\n  return *found->second;\n}\n\nngf::FntFont &ResourceManager::getFntFont(const std::string &id) {\n  auto found = m_fntFontMap.find(id);\n  if (found == m_fntFontMap.end()) {\n    loadFntFont(id);\n    found = m_fntFontMap.find(id);\n  }\n  return *found->second;\n}\n\nconst SpriteSheet &ResourceManager::getSpriteSheet(const std::string &id) {\n  auto found = m_spriteSheetMap.find(id);\n  if (found == m_spriteSheetMap.end()) {\n    loadSpriteSheet(id);\n    found = m_spriteSheetMap.find(id);\n  }\n  return *found->second;\n}\n\n} // namespace ng\n"
  },
  {
    "path": "src/Graphics/SpriteSheet.cpp",
    "content": "#include <ngf/IO/Json/JsonParser.h>\n#include \"engge/Engine/EngineSettings.hpp\"\n#include \"engge/System/Locator.hpp\"\n#include \"../Util/Util.hpp\"\n#include \"engge/Graphics/SpriteSheet.hpp\"\n\nnamespace ng {\nvoid SpriteSheet::load(const std::string &name) {\n  if (m_textureName == name)\n    return;\n\n  m_textureName = name + \".png\";\n\n  m_rects.clear();\n  m_spriteSourceSize.clear();\n  m_sourceSize.clear();\n\n  ngf::GGPackValue json;\n\n  {\n    auto jsonFilename = name + \".json\";\n    auto buffer = Locator<EngineSettings>::get().readBuffer(jsonFilename);\n\n#if 0\n    std::ofstream out;\n    out.open(jsonFilename, std::ios::out);\n    out.write(buffer.data(), buffer.size());\n    out.close();\n#endif\n    json = ngf::Json::parse(buffer.data());\n  }\n\n  auto jFrames = json[\"frames\"];\n  for (auto &it : jFrames.items()) {\n    auto rect = toRect(it.value()[\"frame\"]);\n    m_rects.insert(std::make_pair(it.key(), rect));\n    rect = toRect(it.value()[\"spriteSourceSize\"]);\n    m_spriteSourceSize.insert(std::make_pair(it.key(), rect));\n    auto size = toSize(it.value()[\"sourceSize\"]);\n    m_sourceSize.insert(std::make_pair(it.key(), size));\n  }\n}\n\nbool SpriteSheet::hasRect(const std::string &name) const {\n  const auto it = m_rects.find(name);\n  return it != m_rects.end();\n}\n\nngf::irect SpriteSheet::getRect(const std::string &name) const {\n  const auto it = m_rects.find(name);\n  return it->second;\n}\n\nngf::irect SpriteSheet::getSpriteSourceSize(const std::string &name) const {\n  const auto it = m_spriteSourceSize.find(name);\n  return it->second;\n}\n\nglm::ivec2 SpriteSheet::getSourceSize(const std::string &name) const {\n  const auto it = m_sourceSize.find(name);\n  return it->second;\n}\n\n[[nodiscard]] SpriteSheetItem SpriteSheet::getItem(const std::string &name) const {\n  return SpriteSheetItem{name, getRect(name), getSpriteSourceSize(name), getSourceSize(name), false};\n}\n\n} // namespace ng\n"
  },
  {
    "path": "src/Graphics/Text.cpp",
    "content": "#include <engge/Graphics/Text.hpp>\n#include <Engine/DebugFeatures.hpp>\n\nnamespace ng {\nText::Text() {\n  showTextBounds(DebugFeatures::showTextBounds);\n}\n\nText::Text(std::wstring string, const ngf::Font &font, unsigned int characterSize)\n    : ngf::Text(string, font, characterSize) {\n  showTextBounds(DebugFeatures::showTextBounds);\n}\n}"
  },
  {
    "path": "src/Graphics/WalkboxDrawable.cpp",
    "content": "#include \"WalkboxDrawable.hpp\"\n\nnamespace ng {\nWalkboxDrawable::WalkboxDrawable(const ngf::Walkbox &walkbox, float roomHeight)\n    : m_walkbox(walkbox), m_roomHeight(roomHeight) {\n}\n\nvoid WalkboxDrawable::draw(ngf::RenderTarget &target, ngf::RenderStates states) const {\n  auto color = m_walkbox.isEnabled() ? ngf::Colors::Green : ngf::Colors::Red;\n  std::vector<ngf::Vertex> vertices(m_walkbox.getVertices().size());\n  for (size_t i = 0; i < m_walkbox.getVertices().size(); ++i) {\n    auto &vertex = m_walkbox.at(i);\n    vertices[i].pos = {vertex.x, m_roomHeight - vertex.y};\n    vertices[i].color = color;\n  }\n  target.draw(ngf::PrimitiveType::LineLoop, vertices, states);\n}\n\n}\n"
  },
  {
    "path": "src/Graphics/WalkboxDrawable.hpp",
    "content": "#pragma once\n#include <ngf/Graphics/Drawable.h>\n#include <ngf/Graphics/RenderStates.h>\n#include <ngf/Graphics/RenderTarget.h>\n#include <ngf/Math/PathFinding/Walkbox.h>\n\nnamespace ng {\n\nclass WalkboxDrawable final : public ngf::Drawable {\npublic:\n  WalkboxDrawable(const ngf::Walkbox &walkbox, float roomHeight);\n\n  void draw(ngf::RenderTarget &target, ngf::RenderStates states) const override;\n\nprivate:\n  const ngf::Walkbox &m_walkbox;\n  const float m_roomHeight{0.f};\n};\n}\n"
  },
  {
    "path": "src/Input/CommandManager.cpp",
    "content": "#include \"engge/System/Logger.hpp\"\n#include \"engge/Input/CommandManager.hpp\"\n\nnamespace ng {\nvoid CommandManager::registerCommand(const std::string &command, CommandHandler handler) {\n  m_commandHandlers[command] = std::move(handler);\n}\n\nvoid CommandManager::registerPressedCommand(const std::string &command, PressedCommandHandler handler) {\n  m_pressedCommandHandlers[command] = std::move(handler);\n}\n\nvoid CommandManager::registerCommands(std::initializer_list<std::tuple<const char *, CommandHandler>> commands) {\n  for (auto&[cmd, handler] : commands) {\n    registerCommand(cmd, handler);\n  }\n}\n\nvoid CommandManager::registerInputBinding(const Input& input, const std::string &command) {\n  m_inputBindings[input] = command;\n}\n\nvoid CommandManager::registerInputBindings(std::initializer_list<std::tuple<Input, const char *>> bindings){\n  for (auto&[input, cmd] : bindings) {\n    registerInputBinding(input, cmd);\n  }\n}\n\nvoid CommandManager::execute(const std::string &command) const {\n  trace(\"Execute command {}\", command);\n  auto it = m_commandHandlers.find(command);\n  if (it != m_commandHandlers.end()) {\n    it->second();\n  }\n}\n\nvoid CommandManager::execute(const Input& input) const {\n  auto it = m_inputBindings.find(input);\n  if (it != m_inputBindings.end()) {\n    execute(it->second);\n  }\n}\n\nvoid CommandManager::execute(const Input& input, bool keyDown) const {\n  auto it = m_inputBindings.find(input);\n  if (it != m_inputBindings.end()) {\n    auto it2 = m_pressedCommandHandlers.find(it->second);\n    if (it2 != m_pressedCommandHandlers.end()) {\n      it2->second(keyDown);\n    }\n  }\n}\n}"
  },
  {
    "path": "src/Input/InputMappings.cpp",
    "content": "#include <string>\n#include \"engge/Input/InputConstants.hpp\"\n#include \"engge/System/Locator.hpp\"\n#include \"engge/Engine/Preferences.hpp\"\n#include \"engge/Input/CommandManager.hpp\"\n#include \"engge/Engine/EngineCommands.hpp\"\n#include \"engge/Input/InputMappings.hpp\"\n\nnamespace ng {\n\nstatic InputConstants toKey(const std::string &keyText) {\n  if (keyText.length() == 1) {\n    return static_cast<ng::InputConstants>(keyText[0]);\n  }\n  return ng::InputConstants::NONE;\n}\n\ntemplate<typename T>\nstatic InputConstants toKey(const std::string &name, T value) {\n  const auto &preferences = ng::Locator<ng::Preferences>::get();\n  return toKey(preferences.getUserPreference(name, value));\n}\n\nvoid InputMappings::registerMappings() {\n  auto keySkip = toKey(ng::PreferenceNames::KeySkipText, ng::PreferenceDefaultValues::KeySkipText);\n  auto keySelect1 = toKey(ng::PreferenceNames::KeySelect1, ng::PreferenceDefaultValues::KeySelect1);\n  auto keySelect2 = toKey(ng::PreferenceNames::KeySelect2, ng::PreferenceDefaultValues::KeySelect2);\n  auto keySelect3 = toKey(ng::PreferenceNames::KeySelect3, ng::PreferenceDefaultValues::KeySelect3);\n  auto keySelect4 = toKey(ng::PreferenceNames::KeySelect4, ng::PreferenceDefaultValues::KeySelect4);\n  auto keySelect5 = toKey(ng::PreferenceNames::KeySelect5, ng::PreferenceDefaultValues::KeySelect5);\n  auto keySelect6 = toKey(ng::PreferenceNames::KeySelect6, ng::PreferenceDefaultValues::KeySelect6);\n  auto keySelectPrev = toKey(ng::PreferenceNames::KeySelectPrev, ng::PreferenceDefaultValues::KeySelectPrev);\n  auto keySelectNext = toKey(ng::PreferenceNames::KeySelectNext, ng::PreferenceDefaultValues::KeySelectNext);\n\n  ng::Locator<ng::CommandManager>::get().registerInputBindings(\n      {\n          {{ng::InputConstants::KEY_SPACE}, ng::EngineCommands::PauseGame},\n          {{ng::InputConstants::KEY_ESCAPE}, ng::EngineCommands::SkipCutscene},\n          {{keySelect1}, ng::EngineCommands::SelectActor1},\n          {{keySelect2}, ng::EngineCommands::SelectActor2},\n          {{keySelect3}, ng::EngineCommands::SelectActor3},\n          {{keySelect4}, ng::EngineCommands::SelectActor4},\n          {{keySelect5}, ng::EngineCommands::SelectActor5},\n          {{keySelect6}, ng::EngineCommands::SelectActor6},\n          {{keySelectPrev}, ng::EngineCommands::SelectPreviousActor},\n          {{keySelectNext}, ng::EngineCommands::SelectNextActor},\n          {{keySkip}, ng::EngineCommands::SkipText},\n          {{MetaKeys::Control, ng::InputConstants::KEY_O}, ng::EngineCommands::ShowOptions},\n          {{MetaKeys::Control, ng::InputConstants::KEY_U}, ng::EngineCommands::ToggleHud},\n          {{MetaKeys::Control, ng::InputConstants::KEY_D}, ng::EngineCommands::ToggleDebug},\n          {{ng::InputConstants::KEY_TAB}, ng::EngineCommands::ShowHotspots},\n      });\n}\n}"
  },
  {
    "path": "src/Parsers/GGPackBufferStream.cpp",
    "content": "#include <cstring>\n#include \"engge/Parsers/GGPackBufferStream.hpp\"\n\nGGPackBufferStream::GGPackBufferStream(std::vector<char> input) : m_input(std::move(input)) {}\n\nvoid GGPackBufferStream::setBuffer(const std::vector<char> &input) {\n  m_input = input;\n  m_offset = 0;\n}\n\nvoid GGPackBufferStream::read(char *data, size_t size) {\n  if ((static_cast<int>(m_offset + size)) > getLength())\n    return;\n  memcpy(data, m_input.data() + m_offset, size);\n  m_offset += size;\n}\n\nvoid GGPackBufferStream::seek(int pos) {\n  m_offset = pos;\n}\n\nint GGPackBufferStream::getLength() const {\n  return m_input.size();\n}\n\nint GGPackBufferStream::tell() {\n  return m_offset;\n}\n\nbool GGPackBufferStream::eof() const {\n  return m_offset == static_cast<int>(m_input.size());\n}\n\nchar GGPackBufferStream::peek() const {\n  return m_offset >= m_input.size() ? EOF : m_input.at(m_offset);\n}\n\nGGPackBufferStream &GGPackBufferStream::ignore(std::streamsize n, int delim) {\n  for (int i = 0; i < n && m_offset < static_cast<int>(m_input.size()); i++) {\n    if (m_input[m_offset++] == delim)\n      return *this;\n  }\n  return *this;\n}"
  },
  {
    "path": "src/Parsers/Lip.cpp",
    "content": "#include <regex>\n#include \"engge/Engine/EngineSettings.hpp\"\n#include \"engge/Parsers/Lip.hpp\"\n#include \"engge/System/Locator.hpp\"\n#include \"../Util/Util.hpp\"\n\nnamespace ng {\nLip::Lip() = default;\n\nvoid Lip::clear() {\n  m_data.clear();\n}\n\nvoid Lip::load(const std::string &path) {\n  auto buffer = Locator<EngineSettings>::get().readBuffer(path);\n  GGPackBufferStream input(buffer);\n  m_data.clear();\n  m_path = path;\n  std::regex re(R\"(^(\\d*\\.?\\d*)\\s+(\\w)$)\");\n\n  std::string line;\n  while (getLine(input, line) || !line.empty()) {\n    std::smatch matches;\n    if (!std::regex_search(line, matches, re))\n      continue;\n\n    auto t = std::strtof(matches[1].str().c_str(), nullptr);\n    auto text = matches[2].str();\n    NGLipData data{ngf::TimeSpan::seconds(t), text[0]};\n    m_data.emplace_back(data);\n  }\n}\n} // namespace ng\n"
  },
  {
    "path": "src/Parsers/SavegameManager.cpp",
    "content": "#include <sstream>\n#include <ngf/IO/GGPackHashReader.h>\n#include <ngf/IO/MemoryStream.h>\n#include <ngf/IO/GGPackHashWriter.h>\n#include \"engge/Util/BTEACrypto.hpp\"\n#include \"engge/System/Logger.hpp\"\n#include \"engge/Parsers/SavegameManager.hpp\"\n\nnamespace ng {\nstatic const uint8_t\n    _savegameKey[] = {0xF3, 0xED, 0xA4, 0xAE, 0x2A, 0x33, 0xF8, 0xAF, 0xB4, 0xDB, 0xA2, 0xB5, 0x22, 0xA0, 0x4B, 0x9B};\n\nngf::GGPackValue SavegameManager::loadGame(const std::filesystem::path &path) {\n  std::ifstream is(path, std::ifstream::binary);\n  is.seekg(0, std::ios::end);\n  auto size = static_cast<int>(is.tellg());\n  is.seekg(0, std::ios::beg);\n  std::vector<char> data(size, '\\0');\n  is.read(data.data(), size);\n  is.close();\n\n  const int decSize = size / 4;\n  BTEACrypto::decrypt((uint32_t *) &data[0], decSize, (uint32_t *) _savegameKey);\n\n  const int32_t hashData = *(int32_t *) &data[size - 16];\n  const int32_t hashCheck = computeHash(data, size - 16);\n\n  if (hashData != hashCheck) {\n    warn(\"Invalid savegame: {}\", path.string().c_str());\n    return nullptr;\n  }\n\n  ngf::MemoryStream ms(data.data(), data.data() + data.size());\n  return ngf::GGPackHashReader::read(ms);\n}\n\nvoid SavegameManager::saveGame(const std::filesystem::path &path, const ngf::GGPackValue &saveGameHash) {\n  // save hash\n  std::stringstream o;\n  ngf::GGPackHashWriter::write(saveGameHash, o);\n\n  // encode data\n  const int fullSize = 500000;\n  const int fullSizeAndFooter = fullSize + 16;\n  const int32_t marker = 8 - ((fullSize + 9) % 8);\n\n  std::vector<char> buf(fullSizeAndFooter);\n  o.read(buf.data(), fullSize);\n\n  // write at the end 16 bytes: hashdata (4 bytes) + savetime (4 bytes) + marker (8 bytes)\n  const int32_t hashData = computeHash(buf, fullSize);\n  *(int32_t *) &buf[fullSize] = hashData;\n  *(int32_t *) &buf[fullSize + 4] = saveGameHash[\"savetime\"].getInt();\n  memset(&buf[fullSize + 8], marker, 8);\n\n  // then encode data\n  const int decSize = fullSizeAndFooter / 4;\n  BTEACrypto::encrypt((uint32_t *) buf.data(), decSize, (uint32_t *) _savegameKey);\n\n  // write data\n  std::ofstream os(path, std::ofstream::binary);\n  os.write((char *) buf.data(), fullSizeAndFooter);\n  os.close();\n}\n\nint32_t SavegameManager::computeHash(const std::vector<char> &data, int32_t size) {\n  int32_t v10 = 0;\n  int32_t v11 = 0x6583463;\n  int32_t v12;\n\n  do {\n    v12 = *(uint8_t *) &data[v10++];\n    v11 += v12;\n  } while (v10 < size);\n  return v11;\n}\n}\n"
  },
  {
    "path": "src/Parsers/YackParser.cpp",
    "content": "#include <cassert>\n#include \"engge/Parsers/YackParser.hpp\"\n\nnamespace ng {\nAst::Node::~Node() = default;\nAst::Expression::~Expression() = default;\nAst::Condition::Condition(int32_t line) : m_line(line) {}\nAst::Condition::~Condition() = default;\nAst::CodeCondition::CodeCondition(int32_t line) : Condition(line) {}\nAst::CodeCondition::~CodeCondition() = default;\nAst::OnceCondition::OnceCondition(int32_t line) : Condition(line) {}\nAst::OnceCondition::~OnceCondition() = default;\nAst::ShowOnceCondition::ShowOnceCondition(int32_t line) : Condition(line) {}\nAst::ShowOnceCondition::~ShowOnceCondition() = default;\nAst::OnceEverCondition::OnceEverCondition(int32_t line) : Condition(line) {}\nAst::OnceEverCondition::~OnceEverCondition() = default;\nAst::TempOnceCondition::TempOnceCondition(int32_t line) : Condition(line) {}\nAst::TempOnceCondition::~TempOnceCondition() = default;\nAst::Statement::~Statement() = default;\nAst::Goto::~Goto() = default;\nAst::Code::~Code() = default;\nAst::Choice::~Choice() = default;\nAst::Say::~Say() = default;\nAst::Pause::~Pause() = default;\nAst::Parrot::~Parrot() = default;\nAst::Dialog::~Dialog() = default;\nAst::Override::~Override() = default;\nAst::Shutup::~Shutup() = default;\nAst::AllowObjects::~AllowObjects() = default;\nAst::Limit::~Limit() = default;\nAst::WaitWhile::~WaitWhile() = default;\nAst::WaitFor::~WaitFor() = default;\nAst::Label::~Label() = default;\nAst::CompilationUnit::~CompilationUnit() = default;\n\nstd::ostream &operator<<(std::ostream &os, const Token &token) {\n  return os << \"[\" << token.start << \",\" << token.end << \"] \" << token.readToken();\n}\n\nYackParser::YackParser(YackTokenReader &reader)\n    : m_reader(reader), m_it(m_reader.begin()) {\n}\n\nstd::unique_ptr<Ast::CompilationUnit> YackParser::parse() {\n  auto pCu = std::make_unique<Ast::CompilationUnit>();\n  while (!match({TokenId::End})) {\n    pCu->labels.push_back(parseLabel());\n  }\n  return pCu;\n}\n\nstd::unique_ptr<Ast::Label> YackParser::parseLabel() {\n  auto pLabel = std::make_unique<Ast::Label>();\n\n  // :\n  m_it++;\n  // label\n  pLabel->name = m_reader.readText(*m_it++);\n  do {\n    if (match({TokenId::Colon}) || match({TokenId::End}))\n      break;\n    auto pStatement = parseStatement();\n    pLabel->statements.push_back(std::move(pStatement));\n  } while (true);\n\n  return pLabel;\n}\n\nstd::unique_ptr<Ast::Statement> YackParser::parseStatement() {\n  auto pStatement = std::make_unique<Ast::Statement>();\n  // expression\n  auto pExp = parseExpression();\n  pStatement->expression = std::move(pExp);\n  // conditions\n  while (match({TokenId::Condition})) {\n    pStatement->conditions.push_back(parseCondition());\n  }\n  return pStatement;\n}\n\nstd::unique_ptr<Ast::Condition> YackParser::parseCondition() {\n  auto text = m_reader.readText(*m_it);\n  auto conditionText = text.substr(1, text.length() - 2);\n  auto line = m_reader.getLine(*m_it++);\n  assert(line > 0);\n  if (conditionText == \"once\") {\n    return std::make_unique<Ast::OnceCondition>(line);\n  } else if (conditionText == \"showonce\") {\n    return std::make_unique<Ast::ShowOnceCondition>(line);\n  } else if (conditionText == \"onceever\") {\n    return std::make_unique<Ast::OnceEverCondition>(line);\n  } else if (conditionText == \"temponce\") {\n    return std::make_unique<Ast::TempOnceCondition>(line);\n  }\n  auto pCondition = std::make_unique<Ast::CodeCondition>(line);\n  pCondition->code = conditionText;\n  return pCondition;\n}\n\nstd::unique_ptr<Ast::Expression> YackParser::parseExpression() {\n  if (match({TokenId::Identifier, TokenId::Colon, TokenId::String}))\n    return parseSayExpression();\n  if (match({TokenId::WaitWhile}))\n    return parseWaitWhileExpression();\n  if (match({TokenId::Identifier}))\n    return parseInstructionExpression();\n  if (match({TokenId::Goto}))\n    return parseGotoExpression();\n  if (match({TokenId::Number}))\n    return parseChoiceExpression();\n  if (match({TokenId::Code}))\n    return parseCodeExpression();\n  return nullptr;\n}\n\nbool YackParser::match(const std::initializer_list<TokenId> &ids) {\n  auto it = m_it;\n  for (auto id : ids) {\n    if (it->id != id)\n      return false;\n    it++;\n  }\n  return true;\n}\n\nstd::unique_ptr<Ast::Say> YackParser::parseSayExpression() {\n  auto actor = m_reader.readText(*m_it++);\n  m_it++;\n  auto text = m_reader.readText(*m_it);\n  m_it++;\n  auto pExp = std::make_unique<Ast::Say>();\n  pExp->actor = actor;\n  pExp->text = text.substr(1, text.length() - 2);\n  return pExp;\n}\n\nstd::unique_ptr<Ast::Expression> YackParser::parseWaitWhileExpression() {\n  auto waitwhile = m_reader.readText(*m_it++);\n  auto code = waitwhile.substr(10);\n  auto pExp = std::make_unique<Ast::WaitWhile>();\n  pExp->condition = code;\n  return pExp;\n}\n\nstd::unique_ptr<Ast::Expression> YackParser::parseInstructionExpression() {\n  auto identifier = m_reader.readText(*m_it++);\n  if (identifier == \"shutup\") {\n    return std::make_unique<Ast::Shutup>();\n  } else if (identifier == \"pause\") {\n    // pause number\n    auto time = std::strtod(m_reader.readText(*m_it++).data(), nullptr);\n    auto pExp = std::make_unique<Ast::Pause>();\n    pExp->time = time;\n    return pExp;\n  } else if (identifier == \"waitfor\") {\n    // waitfor [actor]\n    auto pExp = std::make_unique<Ast::WaitFor>();\n    if (m_it->id == TokenId::Identifier) {\n      auto actor = m_reader.readText(*m_it++);\n      pExp->actor = actor;\n    }\n    return pExp;\n  } else if (identifier == \"parrot\") {\n    // parrot [active]\n    auto pExp = std::make_unique<Ast::Parrot>();\n    if (m_it->id == TokenId::Identifier) {\n      auto active = m_reader.readText(*m_it++);\n      pExp->active = active == \"yes\";\n    }\n    return pExp;\n  } else if (identifier == \"dialog\") {\n    // dialog [actor]\n    auto pExp = std::make_unique<Ast::Dialog>();\n    if (m_it->id == TokenId::Identifier) {\n      auto actor = m_reader.readText(*m_it++);\n      pExp->actor = actor;\n    }\n    return pExp;\n  } else if (identifier == \"override\") {\n    // override [node]\n    auto pExp = std::make_unique<Ast::Override>();\n    if (m_it->id == TokenId::Identifier) {\n      auto node = m_reader.readText(*m_it++);\n      pExp->node = node;\n    }\n    return pExp;\n  } else if (identifier == \"allowobjects\") {\n    // allowobjects [allow]\n    auto pExp = std::make_unique<Ast::AllowObjects>();\n    if (m_it->id == TokenId::Identifier) {\n      auto node = m_reader.readText(*m_it++);\n      pExp->allow = node == \"YES\";\n    }\n    return pExp;\n  } else if (identifier == \"limit\") {\n    // limit [number]\n    auto pExp = std::make_unique<Ast::Limit>();\n    if (m_it->id == TokenId::Number) {\n      auto node = m_reader.readText(*m_it++);\n      pExp->max = std::strtol(node.c_str(), nullptr, 10);\n    }\n    return pExp;\n  }\n  throw std::domain_error(\"Unknown instruction: \" + identifier);\n}\n\nstd::unique_ptr<Ast::Goto> YackParser::parseGotoExpression() {\n  m_it++;\n  auto name = m_reader.readText(*m_it++);\n  auto pExp = std::make_unique<Ast::Goto>();\n  pExp->name = name;\n  return pExp;\n}\n\nstd::unique_ptr<Ast::Code> YackParser::parseCodeExpression() {\n  auto code = m_reader.readText(*m_it++);\n  auto pExp = std::make_unique<Ast::Code>();\n  pExp->code = code.substr(1);\n  return pExp;\n}\n\nstd::unique_ptr<Ast::Choice> YackParser::parseChoiceExpression() {\n  auto number = std::strtol(m_reader.readText(*m_it).data(), nullptr, 10);\n  m_it++;\n  std::string text;\n  if (m_it->id == TokenId::Dollar) {\n    text = m_reader.readText(*m_it);\n  } else {\n    text = m_reader.readText(*m_it);\n    text = text.substr(1, text.length() - 2);\n  }\n\n  m_it++;\n  auto pExp = std::make_unique<Ast::Choice>();\n  pExp->number = number;\n  pExp->text = text;\n  auto pGoto = parseGotoExpression();\n  pExp->gotoExp = std::move(pGoto);\n  return pExp;\n}\n} // namespace ng\n"
  },
  {
    "path": "src/Parsers/YackTokenReader.cpp",
    "content": "#include <algorithm>\n#include \"engge/Engine/EngineSettings.hpp\"\n#include \"engge/Parsers/YackTokenReader.hpp\"\n#include \"engge/System/Logger.hpp\"\n\nnamespace ng {\nstd::string Token::readToken() const {\n  switch (id) {\n  case TokenId::Assign:return \"Assign\";\n  case TokenId::NewLine:return \"NewLine\";\n  case TokenId::Colon:return \"Colon\";\n  case TokenId::Code:return \"Code\";\n  case TokenId::Comment:return \"Comment\";\n  case TokenId::End:return \"End\";\n  case TokenId::Goto:return \"Goto\";\n  case TokenId::Identifier:return \"Identifier\";\n  case TokenId::None:return \"None\";\n  case TokenId::Number:return \"Number\";\n  case TokenId::Condition:return \"Condition\";\n  case TokenId::String:return \"String\";\n  case TokenId::Whitespace:return \"Whitespace\";\n  default:return \"?\";\n  }\n}\n\nYackTokenReader::Iterator::Iterator(YackTokenReader &reader, std::streampos pos)\n    : m_reader(reader),\n      m_pos(pos) {\n  operator++();\n}\n\nYackTokenReader::Iterator::Iterator(const Iterator &it)\n    : m_reader(it.m_reader), m_pos(it.m_pos), m_token(it.m_token) {\n}\n\nYackTokenReader::Iterator &YackTokenReader::Iterator::operator++() {\n  m_reader.m_stream.seek(m_pos);\n  m_reader.readToken(m_token);\n  m_pos = m_reader.m_stream.tell();\n  return *this;\n}\n\nYackTokenReader::Iterator YackTokenReader::Iterator::operator++(int) {\n  Iterator tmp(*this);\n  operator++();\n  return tmp;\n}\n\nToken &YackTokenReader::Iterator::operator*() {\n  return m_token;\n}\n\nconst Token &YackTokenReader::Iterator::operator*() const {\n  return m_token;\n}\n\nToken *YackTokenReader::Iterator::operator->() {\n  return &m_token;\n}\n\nvoid YackTokenReader::load(const std::string &path) {\n  auto buffer = Locator<EngineSettings>::get().readBuffer(path);\n\n#if 0\n  std::ofstream o;\n  o.open(path);\n  o.write(buffer.data(), buffer.size());\n  o.close();\n#endif\n\n  m_stream.setBuffer(buffer);\n}\n\nYackTokenReader::iterator YackTokenReader::begin() {\n  return Iterator(*this, 0);\n}\nYackTokenReader::iterator YackTokenReader::end() {\n  auto start = m_stream.tell();\n  m_stream.seek(m_stream.getLength());\n  auto pos = m_stream.tell();\n  m_stream.seek(start);\n  return Iterator(*this, pos);\n}\n\nYackTokenReader::YackTokenReader()\n    : m_offset(-1) {\n}\n\nint YackTokenReader::getLine(const Token &token) const {\n  auto previous = -1;\n  auto previousVal = -1;\n  for (auto &[key, val] : m_lines) {\n    if ((previous < token.start) && (token.start < key)) {\n      return val;\n    }\n    previousVal = val;\n    previous = key;\n  }\n  return previousVal + 1;\n}\n\nbool YackTokenReader::readToken(Token &token) {\n  std::streampos start = m_stream.tell();\n  auto id = readTokenId();\n  while (id == TokenId::Whitespace || id == TokenId::Comment || id == TokenId::NewLine || id == TokenId::None) {\n    start = m_stream.tell();\n    id = readTokenId();\n  }\n  std::streampos end = m_stream.tell();\n  token.id = id;\n  token.start = start;\n  token.end = end;\n  return true;\n}\n\nstd::string YackTokenReader::readText(std::streampos pos, std::streamsize size) {\n  std::string out;\n  out.reserve(size);\n  m_stream.seek(pos);\n  char c;\n  for (int i = 0; i < size; i++) {\n    m_stream.read(&c, 1);\n    out.append(&c, 1);\n  }\n  return out;\n}\n\nstd::string YackTokenReader::readText(const Token &token) {\n  return readText(token.start, token.end - token.start);\n}\n\nTokenId YackTokenReader::readTokenId() {\n  char c;\n  m_stream.read(&c, 1);\n  if (m_stream.eof()) {\n    return TokenId::End;\n  }\n\n  switch (c) {\n  case '\\0':return TokenId::End;\n  case '\\n':\n    if (m_lines.find(m_stream.tell() - 1) == m_lines.end()) {\n      m_lines[m_stream.tell() - 1] = m_offset == -1 ? 1 : m_lines[m_offset] + 1;\n      m_offset = m_stream.tell() - 1;\n    }\n    return TokenId::NewLine;\n  case '\\t':\n  case ' ':\n    while (isspace(m_stream.peek()) && m_stream.peek() != '\\n')\n      m_stream.ignore();\n    return TokenId::Whitespace;\n  case '!':return readCode();\n  case ':':return TokenId::Colon;\n  case '$':return readDollar();\n  case '[':return readCondition();\n  case '=':return TokenId::Assign;\n  case '\\\"':return readString();\n  case '#':\n  case ';':return readComment();\n  default:\n    if (c == '-' && m_stream.peek() == '>') {\n      m_stream.ignore();\n      return TokenId::Goto;\n    }\n    if (c == '-' || isdigit(c)) {\n      return readNumber();\n    } else if (isalpha(c)) {\n      return readIdentifier(c);\n    }\n    error(\"unknown character: {}\", c);\n    return TokenId::None;\n  }\n}\n\nTokenId YackTokenReader::readCode() {\n  char c;\n  char previousChar = '\\0';\n  while ((c = m_stream.peek()) != '\\n' && c != '\\0') {\n    m_stream.ignore();\n    if (previousChar == ' ' && c == '[' && m_stream.peek() != ' ') {\n      m_stream.seek(m_stream.tell() - 1);\n      return TokenId::Code;\n    }\n    previousChar = c;\n  }\n  return TokenId::Code;\n}\n\nTokenId YackTokenReader::readDollar() {\n  char c;\n  while ((c = m_stream.peek()) != '[' && c != ' ' && c != '\\n' && c != '\\0') {\n    m_stream.ignore();\n  }\n  return TokenId::Dollar;\n}\n\nTokenId YackTokenReader::readCondition() {\n  while (m_stream.peek() != ']') {\n    m_stream.ignore();\n  }\n  m_stream.ignore();\n  return TokenId::Condition;\n}\n\nTokenId YackTokenReader::readNumber() {\n  while (isdigit(m_stream.peek())) {\n    m_stream.ignore();\n  }\n  if (m_stream.peek() == '.') {\n    m_stream.ignore();\n  }\n  while (isdigit(m_stream.peek())) {\n    m_stream.ignore();\n  }\n  return TokenId::Number;\n}\n\nTokenId YackTokenReader::readComment() {\n  m_stream.ignore(std::numeric_limits<std::streamsize>::max(), '\\n');\n  m_stream.seek(m_stream.tell() - 1);\n  return TokenId::Comment;\n}\n\nTokenId YackTokenReader::readString() {\n  m_stream.ignore(std::numeric_limits<std::streamsize>::max(), '\\\"');\n  return TokenId::String;\n}\n\nTokenId YackTokenReader::readIdentifier(char c) {\n  std::string id;\n  id.push_back(c);\n  while (isalnum(m_stream.peek()) || m_stream.peek() == '_') {\n    m_stream.read(&c, 1);\n    id.push_back(c);\n  }\n  if (id == \"waitwhile\") {\n    readCode();\n    return TokenId::WaitWhile;\n  }\n  return TokenId::Identifier;\n}\n} // namespace ng\n"
  },
  {
    "path": "src/Room/Room.cpp",
    "content": "#include <engge/Room/Room.hpp>\n#include <engge/Engine/EngineSettings.hpp>\n#include <engge/Engine/Light.hpp>\n#include <engge/System/Locator.hpp>\n#include <engge/System/Logger.hpp>\n#include <engge/Engine/EntityManager.hpp>\n#include <engge/Room/RoomLayer.hpp>\n#include <engge/Room/RoomScaling.hpp>\n#include <engge/Graphics/SpriteSheet.hpp>\n#include <engge/Entities/TextObject.hpp>\n#include <engge/Scripting/ScriptEngine.hpp>\n#include <engge/Entities/AnimationLoader.hpp>\n#include \"Util/Util.hpp\"\n#include <squirrel.h>\n#include <algorithm>\n#include <iostream>\n#include <cmath>\n#include <memory>\n#include <ngf/Math/PathFinding/PathFinder.h>\n#include <ngf/Math/PathFinding/Walkbox.h>\n#include <ngf/Graphics/RectangleShape.h>\n#include <ngf/Graphics/FntFont.h>\n\nnamespace ng {\n\nstruct CmpLayer {\n  bool operator()(int a, int b) const { return a > b; }\n};\n\nstruct Room::Impl {\n  ResourceManager &_textureManager;\n  std::vector<std::unique_ptr<Object>> _objects;\n  std::vector<Object *> _objectsToDelete;\n  std::vector<ngf::Walkbox> _walkboxes;\n  std::vector<ngf::Walkbox> _graphWalkboxes;\n  std::map<int, std::unique_ptr<RoomLayer>, CmpLayer> _layers;\n  std::vector<RoomScaling> _scalings;\n  RoomScaling _scaling;\n  glm::ivec2 _roomSize{0, 0};\n  int32_t _screenHeight{0};\n  std::string _sheet;\n  std::string _name;\n  int _fullscreen{0};\n  HSQOBJECT _roomTable{};\n  std::shared_ptr<ngf::PathFinder> _pf;\n  ngf::Color _ambientColor{255, 255, 255, 255};\n  SpriteSheet _spriteSheet;\n  Room *_pRoom{nullptr};\n  std::array<Light, LightingShader::MaxLights> _lights;\n  int _numLights{0};\n  float _rotation{0};\n  LightingShader _lightingShader;\n  int _selectedEffect{RoomEffectConstants::EFFECT_NONE};\n  ngf::Color _overlayColor{ngf::Colors::Transparent};\n  bool _pseudoRoom{false};\n\n  explicit Impl(HSQOBJECT roomTable)\n      : _textureManager(Locator<ResourceManager>::get()),\n        _roomTable(roomTable) {\n    _spriteSheet.setTextureManager(&_textureManager);\n    for (int i = -3; i < 6; ++i) {\n      _layers[i] = std::make_unique<RoomLayer>();\n    }\n  }\n\n  void setEffect(int effect) {\n    _selectedEffect = effect;\n  }\n\n  void setRoom(Room *pRoom) { _pRoom = pRoom; }\n\n  void loadBackgrounds(ngf::GGPackValue &jWimpy) {\n    int width = 0;\n    if (!jWimpy[\"fullscreen\"].isNull()) {\n      _fullscreen = jWimpy[\"fullscreen\"].getInt();\n    }\n    _layers[0]->setTexture(_spriteSheet.getTextureName());\n    auto screenHeight = _pRoom->getScreenSize().y;\n    auto offsetY = screenHeight - _pRoom->getRoomSize().y;\n    if (jWimpy[\"background\"].isArray()) {\n      for (auto &bg : jWimpy[\"background\"]) {\n        auto frame = _spriteSheet.getRect(bg.getString());\n        auto sourceSize = _spriteSheet.getSourceSize(bg.getString());\n        auto spriteSourceSize = _spriteSheet.getSpriteSourceSize(bg.getString());\n        _layers[0]->setRoomSizeY(_pRoom->getRoomSize().y);\n        _layers[0]->setOffsetY(offsetY);\n        _layers[0]->getBackgrounds().emplace_back(SpriteSheetItem{\"background\", frame, spriteSourceSize, sourceSize,\n                                                                  false});\n        width += frame.getWidth();\n      }\n    } else if (jWimpy[\"background\"].isString()) {\n      auto frame = _spriteSheet.getRect(jWimpy[\"background\"].getString());\n      auto sourceSize = _spriteSheet.getSourceSize(jWimpy[\"background\"].getString());\n      auto spriteSourceSize = _spriteSheet.getSpriteSourceSize(jWimpy[\"background\"].getString());\n      _layers[0]->setRoomSizeY(_pRoom->getRoomSize().y);\n      _layers[0]->setOffsetY(offsetY);\n      _layers[0]->getBackgrounds().emplace_back(SpriteSheetItem{\"background\", frame, spriteSourceSize, sourceSize,\n                                                                false});\n    }\n    // room width seems to be not enough :S\n    if (width > _roomSize.x) {\n      _roomSize.x = width;\n    }\n  }\n\n  void loadLayers(const ngf::GGPackValue &jWimpy) {\n    if (jWimpy[\"layers\"].isNull())\n      return;\n\n    auto offsetY = _pRoom->getScreenSize().y - _pRoom->getRoomSize().y;\n\n    for (auto jLayer : jWimpy[\"layers\"]) {\n      auto zsort = jLayer[\"zsort\"].getInt();\n      auto &layer = _layers[zsort];\n      layer->setRoomSizeY(_pRoom->getRoomSize().y);\n      layer->setOffsetY(offsetY);\n      layer->setTexture(_spriteSheet.getTextureName());\n      layer->setZOrder(zsort);\n      if (jLayer[\"name\"].isArray()) {\n        for (const auto &jName : jLayer[\"name\"]) {\n          layer->getBackgrounds().push_back(_spriteSheet.getItem(jName.getString()));\n        }\n      } else {\n        layer->getBackgrounds().push_back(_spriteSheet.getItem(jLayer[\"name\"].getString()));\n      }\n      if (jLayer[\"parallax\"].isString()) {\n        layer->setParallax(parsePos(jLayer[\"parallax\"].getString()));\n      } else {\n        layer->setParallax({jLayer[\"parallax\"].getDouble(), 1});\n      }\n    }\n  }\n\n  void loadObjects(const ngf::GGPackValue &jWimpy) {\n    for (auto jObject : jWimpy[\"objects\"]) {\n      std::unique_ptr<Object> object;\n\n      auto objectName = jObject[\"name\"].getString();\n      auto v = ScriptEngine::getVm();\n      sq_pushobject(v, _pRoom->getTable());\n      sq_pushstring(v, objectName.c_str(), -1);\n      if (SQ_FAILED(sq_rawget(v, -2))) {\n        object = std::make_unique<Object>();\n        object->setTouchable(false);\n        object->setName(objectName);\n      } else {\n        HSQOBJECT objTable;\n        sq_resetobject(&objTable);\n        if (_pRoom->isPseudoRoom()) {\n          sq_clone(v, -1);\n          sq_getstackobj(v, -1, &objTable);\n          sq_remove(v, -2);\n        } else {\n          sq_getstackobj(v, -1, &objTable);\n        }\n        object = std::make_unique<Object>(objTable);\n\n        bool initTouchable;\n        if (ScriptEngine::get(object.get(), \"initTouchable\", initTouchable)) {\n          object->setTouchable(initTouchable);\n        }\n      }\n      if (!_pRoom->isPseudoRoom()) {\n        ScriptEngine::set(objectName.data(), object->getTable());\n      }\n      ScriptEngine::set(_pRoom, objectName.data(), object->getTable());\n\n      if (!ScriptEngine::rawExists(object.get(), \"flags\")) {\n        ScriptEngine::set(object.get(), \"flags\", 0);\n      }\n\n      sq_pushobject(v, object->getTable());\n      sq_pushobject(v, _pRoom->getTable());\n      sq_setdelegate(v, -2);\n      sq_pop(v, 1);\n\n      // name\n      object->setKey(objectName);\n      // parent\n      if (jObject[\"parent\"].isString()) {\n        auto parent = jObject[\"parent\"].getString();\n        auto it = std::find_if(_objects.begin(), _objects.end(), [&parent](const std::unique_ptr<Object> &o) {\n          return o->getName() == parent;\n        });\n        if (it != _objects.end()) {\n          object->setParent((*it).get());\n        }\n      }\n      // zsort\n      object->setZOrder(jObject[\"zsort\"].getInt());\n      // position\n      auto pos = parsePos(jObject[\"pos\"].getString());\n      auto usePos = parsePos(jObject[\"usepos\"].getString());\n      auto useDir = toDirection(jObject[\"usedir\"].getString());\n      object->setUseDirection(useDir);\n      // hotspot\n      auto hotspot = parseRect(jObject[\"hotspot\"].getString());\n      object->setHotspot(ngf::irect::fromPositionSize(hotspot.getTopLeft(), hotspot.getSize()));\n      // prop\n      bool isProp = jObject[\"prop\"].isInteger() && jObject[\"prop\"].getInt() == 1;\n      if (isProp)\n        object->setType(ObjectType::Prop);\n      // spot\n      bool isSpot = jObject[\"spot\"].isInteger() && jObject[\"spot\"].getInt() == 1;\n      if (isSpot)\n        object->setType(ObjectType::Spot);\n      // trigger\n      bool isTrigger = jObject[\"trigger\"].isInteger() && jObject[\"trigger\"].getInt() == 1;\n      if (isTrigger)\n        object->setType(ObjectType::Trigger);\n\n      object->setPosition(pos);\n      object->setUsePosition(usePos);\n\n      // animations\n      if (jObject[\"animations\"].isArray()) {\n        auto anims = AnimationLoader::parseAnimations(*object, jObject[\"animations\"], _spriteSheet);\n        auto &objAnims = object->getAnims();\n        std::copy(anims.begin(), anims.end(), std::back_inserter(objAnims));\n\n        int initState = 0;\n        ScriptEngine::get(object.get(), \"initState\", initState);\n        object->setStateAnimIndex(initState);\n      }\n      object->setRoom(_pRoom);\n      _layers[0]->addEntity(*object);\n      _objects.push_back(std::move(object));\n    }\n\n    // update parent, it has to been done after objects initialization\n    const auto &jObjects = jWimpy[\"objects\"];\n    for (auto &object : _objects) {\n      auto name = object->getName();\n      auto it = std::find_if(jObjects.cbegin(), jObjects.cend(), [&name](const auto &jObject) {\n        return jObject[\"name\"].getString() == name;\n      });\n      if (it == jObjects.cend())\n        continue;\n      auto jParent = (*it)[\"parent\"];\n      if (jParent.isNull())\n        continue;\n      auto parent = jParent.getString();\n      auto itParent = std::find_if(_objects.cbegin(), _objects.cend(), [&parent](const auto &o) {\n        return o->getName() == parent;\n      });\n      if (itParent == _objects.cend())\n        continue;\n      object->setParent(itParent->get());\n    }\n\n    // sort objects\n    auto cmpObjects = [](std::unique_ptr<Object> &a, std::unique_ptr<Object> &b) {\n      return a->getZOrder() > b->getZOrder();\n    };\n    std::sort(_objects.begin(), _objects.end(), cmpObjects);\n  }\n\n  static SQInteger createObjectsFromTable(Room *pRoom, std::unordered_map<std::string, HSQOBJECT> &roomObjects) {\n    auto v = ScriptEngine::getVm();\n    auto isPseudoRoom = pRoom->isPseudoRoom();\n    auto &roomTable = pRoom->getTable();\n\n    // iterate each table from roomTable\n    sq_pushobject(v, roomTable);\n    sq_pushnull(v);\n    while (SQ_SUCCEEDED(sq_next(v, -2))) {\n//here -1 is the value and -2 is the key\n      auto type = sq_gettype(v, -1);\n      if (type == OT_TABLE) {\n        const SQChar *key = nullptr;\n        sq_getstring(v, -2, &key);\n        HSQOBJECT object;\n        sq_resetobject(&object);\n        sq_getstackobj(v, -1, &object);\n        if (roomObjects.find(key) == roomObjects.end()) {\n          std::unique_ptr<Object> obj;\n          if (isPseudoRoom) {\n            obj = std::make_unique<Object>();\n            sq_pushobject(v, object);\n            sq_clone(v, -1);\n            sq_getstackobj(v, -1, &obj->getTable());\n            sq_addref(v, &obj->getTable());\n            sq_pop(v, 2);\n          } else {\n            sq_addref(v, &object);\n            obj = std::make_unique<Object>(object);\n            ScriptEngine::set(key, obj->getTable());\n          }\n\n          auto initState = 0;\n          ScriptEngine::get(obj.get(), \"initState\", initState);\n          obj->setStateAnimIndex(initState);\n\n          bool initTouchable;\n          if (ScriptEngine::get(obj.get(), \"initTouchable\", initTouchable)) {\n            obj->setTouchable(initTouchable);\n          }\n\n          if (!ScriptEngine::rawExists(obj.get(), \"flags\")) {\n            ScriptEngine::set(obj.get(), \"flags\", 0);\n          }\n\n          sq_pushobject(v, obj->getTable());\n          sq_pushobject(v, roomTable);\n          sq_setdelegate(v, -2);\n          sq_pop(v, 1);\n\n          obj->setRoom(pRoom);\n          obj->setKey(key);\n          ScriptEngine::set(pRoom, key, obj->getTable());\n          pRoom->getObjects().push_back(std::move(obj));\n          roomObjects[key] = object;\n        }\n      }\n      sq_pop(v, 2); //pops key and val before the nex iteration\n    }\n    sq_pop(v, 2); //pops the null iterator & roomTable\n    return 0;\n  }\n\n  static Scaling parseScaling(std::string_view value) {\n    auto index = value.find('@');\n    auto scale = std::strtof(value.substr(0, index).data(), nullptr);\n    auto yPos = std::strtof(value.substr(index + 1).data(), nullptr);\n    return {scale, yPos};\n  }\n\n  void loadScalings(const ngf::GGPackValue &jWimpy) {\n    if (jWimpy[\"scaling\"].isArray()) {\n      if (jWimpy[\"scaling\"][0].isString()) {\n        RoomScaling scaling;\n        for (const auto &jScaling : jWimpy[\"scaling\"]) {\n          scaling.getScalings().push_back(parseScaling(jScaling.getString()));\n        }\n        _scalings.push_back(scaling);\n      } else if (jWimpy[\"scaling\"][0].isHash()) {\n        for (auto jScaling : jWimpy[\"scaling\"]) {\n          RoomScaling scaling;\n          if (jScaling[\"trigger\"].isString()) {\n            scaling.setTrigger(jScaling[\"trigger\"].getString());\n          }\n          for (const auto &jSubScaling : jScaling[\"scaling\"]) {\n            if (jSubScaling.isString()) {\n              scaling.getScalings().push_back(parseScaling(jSubScaling.getString()));\n            } else if (jSubScaling.isArray()) {\n              for (const auto &jSubScalingScaling : jSubScaling) {\n                scaling.getScalings().push_back(parseScaling(jSubScalingScaling.getString()));\n              }\n            }\n          }\n          _scalings.push_back(scaling);\n        }\n      }\n    }\n\n    if (_scalings.empty()) {\n      RoomScaling scaling;\n      _scalings.push_back(scaling);\n    }\n  }\n\n  void loadWalkboxes(const ngf::GGPackValue &jWimpy) {\n    for (auto jWalkbox : jWimpy[\"walkboxes\"]) {\n      std::vector<glm::ivec2> vertices;\n      auto polygon = jWalkbox[\"polygon\"].getString();\n      parsePolygon(polygon, vertices);\n      ngf::Walkbox walkbox(vertices);\n      walkbox.setYAxisDirection(ngf::YAxisDirection::Up);\n      if (jWalkbox[\"name\"].isString()) {\n        auto walkboxName = jWalkbox[\"name\"].getString();\n        walkbox.setName(walkboxName);\n      }\n      _walkboxes.push_back(walkbox);\n    }\n    _pf.reset();\n  }\n\n  bool updateGraph(const glm::vec2 &start) {\n    _graphWalkboxes.clear();\n    if (!_walkboxes.empty()) {\n      _graphWalkboxes = ngf::Walkbox::merge(_walkboxes);\n      return sortWalkboxes(start);\n    }\n    return false;\n  }\n\n  bool sortWalkboxes(const glm::vec2 &start) {\n    auto it = std::find_if(_graphWalkboxes.begin(), _graphWalkboxes.end(), [start](auto &w) {\n      return w.inside(start);\n    });\n    if (it != _graphWalkboxes.end()) {\n      std::iter_swap(_graphWalkboxes.begin(), it);\n    }\n    _pf = std::make_shared<ngf::PathFinder>(_graphWalkboxes);\n    return true;\n  }\n};\n\nstd::unique_ptr<Room> Room::define(HSQOBJECT roomTable, const char *name) {\n  auto isPseudoRoom = name != nullptr;\n  auto pRoom = std::make_unique<Room>(roomTable);\n\n  // loadRoom\n  const char *background = nullptr;\n  if (!ScriptEngine::get(pRoom.get(), \"background\", background)) {\n    error(\"Can't find background entry\");\n    return nullptr;\n  }\n\n  pRoom->setName(isPseudoRoom ? name : background);\n  ScriptEngine::set(pRoom.get(), \"_key\", pRoom->getName());\n  pRoom->setPseudoRoom(isPseudoRoom);\n  pRoom->load(background);\n\n  std::unordered_map<std::string, HSQOBJECT> roomObjects;\n  for (auto &obj: pRoom->getObjects()) {\n    roomObjects[obj->getKey()] = obj->getTable();\n  }\n  auto result = Impl::createObjectsFromTable(pRoom.get(), roomObjects);\n  if (SQ_FAILED(result)) {\n    error(\"Error when reading room objects\");\n    return nullptr;\n  }\n\n  // declare room in root table\n  ScriptEngine::set(pRoom->getName().data(), pRoom.get());\n  return pRoom;\n}\n\nRoom::Room(HSQOBJECT roomTable)\n    : m_pImpl(std::make_unique<Impl>(roomTable)) {\n  m_id = Locator<EntityManager>::get().getRoomId();\n  m_pImpl->setRoom(this);\n  ScriptEngine::set(this, \"_id\", getId());\n}\n\nRoom::~Room() = default;\n\nvoid Room::setName(const std::string &name) { m_pImpl->_name = name; }\nstd::string Room::getName() const { return m_pImpl->_name; }\n\nstd::vector<std::unique_ptr<Object>> &Room::getObjects() { return m_pImpl->_objects; }\nconst std::vector<std::unique_ptr<Object>> &Room::getObjects() const { return m_pImpl->_objects; }\n\nstd::array<Light, LightingShader::MaxLights> &Room::getLights() { return m_pImpl->_lights; }\n\nstd::vector<ngf::Walkbox> &Room::getWalkboxes() { return m_pImpl->_walkboxes; }\n\nconst ngf::Walkbox *Room::getWalkbox(const std::string &name) const {\n  auto it = std::find_if(m_pImpl->_walkboxes.begin(), m_pImpl->_walkboxes.end(), [&name](const auto &w) {\n    return w.getName() == name;\n  });\n  if (it != m_pImpl->_walkboxes.end()) {\n    return &(*it);\n  }\n  return nullptr;\n}\n\nstd::vector<ngf::Walkbox> &Room::getGraphWalkboxes() { return m_pImpl->_graphWalkboxes; }\n\nglm::ivec2 Room::getRoomSize() const { return m_pImpl->_roomSize; }\n\nint32_t Room::getScreenHeight() const { return m_pImpl->_screenHeight; }\n\nint32_t Room::getFullscreen() const { return m_pImpl->_fullscreen; }\n\nHSQOBJECT &Room::getTable() { return m_pImpl->_roomTable; }\n\nvoid Room::setAmbientLight(ngf::Color color) { m_pImpl->_ambientColor = color; }\n\nngf::Color Room::getAmbientLight() const { return m_pImpl->_ambientColor; }\n\nvoid Room::setAsParallaxLayer(Entity *pEntity, int layerNum) {\n  for (auto &layer : m_pImpl->_layers) {\n    layer.second->removeEntity(*pEntity);\n  }\n  m_pImpl->_layers[layerNum]->addEntity(*pEntity);\n}\n\nvoid Room::roomLayer(int layerNum, bool enabled) { m_pImpl->_layers[layerNum]->setEnabled(enabled); }\n\nvoid Room::removeEntity(Entity *pEntity) {\n  for (auto &layer : m_pImpl->_layers) {\n    layer.second->removeEntity(*pEntity);\n  }\n  m_pImpl->_objects.erase(std::remove_if(m_pImpl->_objects.begin(), m_pImpl->_objects.end(),\n                                         [pEntity](auto &pObj) { return pObj.get() == pEntity; }),\n                          m_pImpl->_objects.end());\n}\n\nvoid Room::load(const char *name) {\n  // load wimpy file\n  std::string wimpyFilename;\n  wimpyFilename.append(name).append(\".wimpy\");\n  trace(\"Load room {}\", wimpyFilename);\n\n  if (!Locator<EngineSettings>::get().hasEntry(wimpyFilename))\n    return;\n\n  auto hash = Locator<EngineSettings>::get().readEntry(wimpyFilename);\n\n#if 0\n  std::ofstream out;\n  out.open(wimpyFilename, std::ios::out);\n  out << hash;\n  out.close();\n#endif\n\n  m_pImpl->_sheet = hash[\"sheet\"].getString();\n  m_pImpl->_screenHeight = hash[\"height\"].getInt();\n  m_pImpl->_roomSize = (glm::ivec2) parsePos(hash[\"roomsize\"].getString());\n\n  // load json file\n  m_pImpl->_spriteSheet.load(m_pImpl->_sheet);\n\n  m_pImpl->loadBackgrounds(hash);\n  m_pImpl->loadLayers(hash);\n  m_pImpl->loadObjects(hash);\n  m_pImpl->loadScalings(hash);\n  m_pImpl->loadWalkboxes(hash);\n}\n\nTextObject &Room::createTextObject(const std::string &fontName) {\n  auto object = std::make_unique<TextObject>();\n  std::string path;\n  path.append(fontName).append(\".fnt\");\n  if (!Locator<EngineSettings>::get().hasEntry(path)) {\n    path.clear();\n    path.append(fontName).append(\"Font.fnt\");\n  }\n\n  const auto &font = m_pImpl->_textureManager.getFntFont(path);\n  object->setFont(&font);\n  auto &obj = *object;\n  obj.setRoom(this);\n  std::ostringstream s;\n  s << \"TextObject #\" << m_pImpl->_objects.size();\n  m_pImpl->_objects.push_back(std::move(object));\n  m_pImpl->_layers[0]->addEntity(obj);\n  return obj;\n}\n\nvoid Room::deleteObject(Object &object) {\n  m_pImpl->_objectsToDelete.push_back(&object);\n}\n\nObject &Room::createObject(const std::vector<std::string> &anims) { return createObject(m_pImpl->_sheet, anims); }\n\nObject &Room::createObject(const std::string &sheet, const std::vector<std::string> &frames) {\n  auto object = std::make_unique<Object>();\n  auto spriteSheet = m_pImpl->_textureManager.getSpriteSheet(sheet);\n\n  Animation anim;\n  anim.name = \"state0\";\n  anim.texture = spriteSheet.getTextureName();\n\n  for (auto frame :frames) {\n    checkLanguage(frame);\n    anim.frames.push_back(spriteSheet.getItem(frame));\n  }\n  object->getAnims().push_back(anim);\n  object->setStateAnimIndex(0);\n  object->setTemporary(true);\n  object->setRoom(this);\n  object->setZOrder(1);\n  auto &obj = *object;\n  m_pImpl->_layers[0]->addEntity(obj);\n  m_pImpl->_objects.push_back(std::move(object));\n  return obj;\n}\n\nObject &Room::createObject(const std::string &image) {\n  auto name = image;\n  checkLanguage(name);\n\n  const std::vector<std::string> anims{name};\n  auto object = std::make_unique<Object>();\n  auto texture = Locator<ResourceManager>::get().getTexture(name + \".png\");\n\n  Animation anim;\n  auto size = texture->getSize();\n  ngf::irect rect = ngf::irect::fromPositionSize({0, 0}, size);\n  anim.name = \"state0\";\n  anim.texture = name + \".png\";\n  anim.frames.push_back(SpriteSheetItem{\"state0\", rect, rect, size, false});\n  object->getAnims().push_back(anim);\n\n  object->setAnimation(\"state0\");\n  auto &obj = *object;\n  obj.setTemporary(true);\n  obj.setZOrder(1);\n  obj.setRoom(this);\n  m_pImpl->_layers[0]->addEntity(obj);\n  m_pImpl->_objects.push_back(std::move(object));\n  return obj;\n}\n\nObject &Room::createObject() {\n  auto object = std::make_unique<Object>();\n\n  auto &obj = *object;\n  obj.setTemporary(true);\n  obj.setZOrder(1);\n  obj.setRoom(this);\n  m_pImpl->_layers[0]->addEntity(obj);\n  m_pImpl->_objects.push_back(std::move(object));\n  return obj;\n}\n\nconst ngf::Graph *Room::getGraph() const {\n  if (m_pImpl->_pf) {\n    return m_pImpl->_pf->getGraph().get();\n  }\n  return nullptr;\n}\n\nvoid Room::update(const ngf::TimeSpan &elapsed) {\n  if (!m_pImpl->_objectsToDelete.empty()) {\n    for (auto &obj : m_pImpl->_objectsToDelete) {\n      for (auto &&layer : m_pImpl->_layers) {\n        layer.second->removeEntity(*obj);\n      }\n      m_pImpl->_objects.erase(std::remove_if(\n          m_pImpl->_objects.begin(), m_pImpl->_objects.end(),\n          [&obj](auto &pObj) { return pObj.get() == obj; }), m_pImpl->_objects.end());\n    }\n    m_pImpl->_objectsToDelete.clear();\n  }\n\n  for (auto &&layer : m_pImpl->_layers) {\n    layer.second->update(elapsed);\n  }\n}\n\nvoid Room::draw(ngf::RenderTarget &target, const glm::vec2 &cameraPos) const {\n  // update lighting\n  auto nLights = m_pImpl->_numLights;\n  m_pImpl->_lightingShader.setAmbientColor(m_pImpl->_ambientColor);\n  m_pImpl->_lightingShader.setNumberLights(nLights);\n  m_pImpl->_lightingShader.setLights(m_pImpl->_lights);\n\n  for (const auto &layer : m_pImpl->_layers) {\n    auto parallax = layer.second->getParallax();\n    ngf::Transform t;\n    t.move({-cameraPos.x * parallax.x, cameraPos.y * parallax.y});\n\n    ngf::RenderStates states;\n    states.shader = &m_pImpl->_lightingShader;\n    states.transform = t.getTransform();\n    layer.second->draw(target, states);\n  }\n}\n\nvoid Room::drawForeground(ngf::RenderTarget &target, const glm::vec2 &cameraPos) const {\n  ngf::RenderStates states;\n  states.shader = &m_pImpl->_lightingShader;\n  m_pImpl->_lightingShader.setNumberLights(0);\n  m_pImpl->_lightingShader.setAmbientColor(ngf::Colors::White);\n\n  for (const auto &layer : m_pImpl->_layers) {\n    auto parallax = layer.second->getParallax();\n    ngf::Transform t;\n    t.setPosition({-cameraPos.x * parallax.x, cameraPos.y * parallax.y});\n\n    states.transform = t.getTransform();\n    layer.second->drawForeground(target, states);\n  }\n}\n\nconst RoomScaling &Room::getRoomScaling() const { return m_pImpl->_scaling; }\n\nvoid Room::setRoomScaling(const RoomScaling &scaling) { m_pImpl->_scaling = scaling; }\n\nvoid Room::setWalkboxEnabled(const std::string &name, bool isEnabled) {\n  auto it = std::find_if(m_pImpl->_walkboxes.begin(), m_pImpl->_walkboxes.end(),\n                         [&name](const auto &walkbox) { return walkbox.getName() == name; });\n  if (it == m_pImpl->_walkboxes.end()) {\n    error(\"walkbox {} has not been found\", name);\n    return;\n  }\n  it->setEnabled(isEnabled);\n  m_pImpl->_pf.reset();\n}\n\nstd::vector<RoomScaling> &Room::getScalings() { return m_pImpl->_scalings; }\n\nstd::vector<glm::vec2> Room::calculatePath(glm::vec2 start, glm::vec2 end) const {\n  if (!m_pImpl->_pf) {\n    if (!m_pImpl->updateGraph(start)) {\n      return std::vector<glm::vec2>();\n    }\n  } else if (!m_pImpl->_graphWalkboxes.empty() && !m_pImpl->_graphWalkboxes[0].inside(start)) {\n    if (!m_pImpl->sortWalkboxes(start)) {\n      return std::vector<glm::vec2>();\n    }\n  }\n  return m_pImpl->_pf->calculatePath(start, end);\n}\n\nfloat Room::getRotation() const { return m_pImpl->_rotation; }\n\nvoid Room::setRotation(float angle) { m_pImpl->_rotation = angle; }\n\nLight *Room::createLight(ngf::Color color, glm::ivec2 pos) {\n  auto &light = m_pImpl->_lights[m_pImpl->_numLights++];\n  light.color = color;\n  light.pos = pos;\n  return &light;\n}\n\nint Room::getNumberLights() const { return m_pImpl->_numLights; }\n\nLightingShader& Room::getLightingShader() { return m_pImpl->_lightingShader; }\n\nvoid Room::exit() {\n  m_pImpl->_numLights = 0;\n  for (auto &obj : m_pImpl->_objects) {\n    if (!obj->isTemporary())\n      continue;\n    for (auto &layer : m_pImpl->_layers) {\n      layer.second->removeEntity(*obj);\n    }\n  }\n  m_pImpl->_objects.erase(std::remove_if(m_pImpl->_objects.begin(), m_pImpl->_objects.end(),\n                                         [](auto &pObj) { return pObj->isTemporary(); }), m_pImpl->_objects.end());\n}\n\nvoid Room::setEffect(int effect) { m_pImpl->setEffect(effect); }\n\nint Room::getEffect() const { return m_pImpl->_selectedEffect; }\n\nvoid Room::setOverlayColor(ngf::Color color) { m_pImpl->_overlayColor = color; }\n\nngf::Color Room::getOverlayColor() const { return m_pImpl->_overlayColor; }\n\nconst SpriteSheet &Room::getSpriteSheet() const { return m_pImpl->_spriteSheet; }\n\nglm::ivec2 Room::getScreenSize() const {\n  glm::ivec2 screen;\n  if (getFullscreen() == 1) {\n    screen = getRoomSize();\n    if (getScreenHeight() != 0) {\n      screen.y = getScreenHeight();\n    }\n  } else {\n    auto height = getScreenHeight();\n    switch (height) {\n    case 0:return getRoomSize();\n    case 128:return glm::ivec2(320, 180);\n    case 172:return glm::ivec2(428, 240);\n    case 256:return glm::ivec2(640, 360);\n    default: {\n      height = 180.f * height / 128.f;\n      auto ratio = 320.f / 180.f;\n      return glm::ivec2(ratio * height, height);\n    }\n    }\n  }\n  return screen;\n}\n\nvoid Room::setPseudoRoom(bool pseudoRoom) {\n  m_pImpl->_pseudoRoom = pseudoRoom;\n}\n\nbool Room::isPseudoRoom() const {\n  return m_pImpl->_pseudoRoom;\n}\n\n} // namespace ng\n"
  },
  {
    "path": "src/Room/RoomLayer.cpp",
    "content": "#include <ngf/Graphics/Sprite.h>\n#include <engge/Graphics/LightingShader.h>\n#include \"engge/Room/RoomLayer.hpp\"\n#include \"engge/Graphics/ResourceManager.hpp\"\n#include \"engge/System/Locator.hpp\"\n\nnamespace ng {\nRoomLayer::RoomLayer() = default;\n\nvoid RoomLayer::setTexture(const std::string &textureName) {\n  m_textureName = textureName;\n}\n\nvoid RoomLayer::addEntity(Entity &entity) { m_entities.emplace_back(entity); }\n\nvoid RoomLayer::removeEntity(Entity &entity) {\n  m_entities.erase(std::remove_if(m_entities.begin(), m_entities.end(),\n                                  [&entity](auto &pEntity) -> bool { return &pEntity.get() == &entity; }),\n                   m_entities.end());\n}\n\nvoid RoomLayer::draw(ngf::RenderTarget &target, ngf::RenderStates states) const {\n  if (!m_enabled)\n    return;\n\n  // disable lighting for layer rendering\n  auto pShader = (LightingShader *) states.shader;\n  auto count = pShader->getNumberLights();\n  auto ambient = pShader->getAmbientColor();\n  pShader->setAmbientColor(ngf::Colors::White);\n  pShader->setNumberLights(0);\n\n  // sort entities by z-order\n  std::vector<std::reference_wrapper<Entity>> entities;\n  std::copy(m_entities.begin(), m_entities.end(), std::back_inserter(entities));\n  std::sort(entities.begin(), entities.end(),\n            [](const Entity &a, const Entity &b) {\n              if (a.getZOrder() == b.getZOrder())\n                return a.getId() < b.getId();\n              return a.getZOrder() > b.getZOrder();\n            });\n\n  float offsetX = 0.f;\n  // draw layer sprites\n  for (const auto &item : m_backgrounds) {\n    auto texture = Locator<ResourceManager>::get().getTexture(m_textureName);\n    auto texSize = texture->getSize();\n    pShader->setTexture(*texture);\n    pShader->setContentSize(item.sourceSize);\n    pShader->setSpriteOffset({0, -item.frame.getHeight()});\n    pShader->setSpritePosInSheet({static_cast<float>(item.frame.min.x) / texSize.x,\n                                  static_cast<float>(item.frame.min.y) / texSize.y});\n    pShader->setSpriteSizeRelToSheet({static_cast<float>(item.sourceSize.x) / texSize.x,\n                                      static_cast<float>(item.sourceSize.y) / texSize.y});\n\n    ngf::Sprite s(*texture, item.frame);\n    glm::vec2 off{item.spriteSourceSize.min.x, item.spriteSourceSize.min.y + m_roomSizeY - item.sourceSize.y};\n    s.getTransform().setPosition(off + glm::vec2{offsetX, m_offsetY});\n    offsetX += item.frame.getWidth();\n    s.draw(target, states);\n  }\n\n  // draw layer entities: actors and objects\n  for (const Entity &entity : entities) {\n    if (entity.hasParent())\n      continue;\n\n    // indicates whether or not the entity needs lighting\n    pShader->setAmbientColor(entity.isLit() ? ambient : ngf::Colors::White);\n    pShader->setNumberLights(entity.isLit() ? count : 0);\n    entity.draw(target, states);\n  }\n\n  pShader->setAmbientColor(ambient);\n  pShader->setNumberLights(count);\n}\n\nvoid RoomLayer::drawForeground(ngf::RenderTarget &target, ngf::RenderStates states) const {\n  std::for_each(m_entities.begin(), m_entities.end(),\n                [&target, &states](const Entity &entity) { entity.drawForeground(target, states); });\n}\n\nvoid RoomLayer::update(const ngf::TimeSpan &elapsed) {\n  std::for_each(m_entities.begin(), m_entities.end(), [elapsed](Entity &obj) { obj.update(elapsed); });\n}\n\n} // namespace ng\n"
  },
  {
    "path": "src/Room/RoomScaling.cpp",
    "content": "#include \"engge/Room/RoomScaling.hpp\"\n\nnamespace ng {\n\nvoid RoomScaling::setTrigger(const std::string &trigger) {\n  m_trigger = trigger;\n}\n\nfloat RoomScaling::getScaling(float yPos) const {\n  if (m_scalings.empty())\n    return 1.0f;\n  for (size_t i = 0; i < m_scalings.size(); i++) {\n    const auto &scaling = m_scalings[i];\n    if (yPos < scaling.yPos) {\n      if (i == 0)\n        return m_scalings[i].scale;\n      auto prevScaling = m_scalings[i - 1];\n      auto dY = scaling.yPos - prevScaling.yPos;\n      auto dScale = scaling.scale - prevScaling.scale;\n      auto p = (yPos - prevScaling.yPos) / dY;\n      auto scale = prevScaling.scale + (p * dScale);\n      return scale;\n    }\n  }\n  return m_scalings[m_scalings.size() - 1].scale;\n}\n\nstd::vector<Scaling> &RoomScaling::getScalings() {\n  return m_scalings;\n}\n\nconst std::string &RoomScaling::getName() const {\n  return m_trigger;\n}\n\n} // namespace ng"
  },
  {
    "path": "src/Room/RoomTrigger.cpp",
    "content": "#include \"RoomTrigger.hpp\"\n#include \"RoomTriggerThread.hpp\"\n#include <engge/System/Locator.hpp>\n#include <engge/System/Logger.hpp>\n#include <engge/Entities/Object.hpp>\n#include <engge/Scripting/ScriptEngine.hpp>\n#include <squirrel.h>\n\nnamespace ng {\nRoomTrigger::RoomTrigger(Engine &engine, Object &object, HSQOBJECT inside, HSQOBJECT outside)\n    : m_engine(engine), m_object(object), m_inside(inside), m_outside(outside) {\n  m_vm = ScriptEngine::getVm();\n  sq_addref(m_vm, &inside);\n  sq_addref(m_vm, &outside);\n\n  SQInteger top = sq_gettop(m_vm);\n\n  const SQChar *insideName{nullptr};\n  SQInteger nfreevars;\n  sq_pushobject(m_vm, m_inside);\n  sq_getclosureinfo(m_vm, -1, &m_insideParamsCount, &nfreevars);\n  if (SQ_SUCCEEDED(sq_getclosurename(m_vm, -1))) {\n    sq_getstring(m_vm, -1, &insideName);\n    if (insideName)\n      m_insideName = insideName;\n  }\n\n  const SQChar *outsideName{nullptr};\n  sq_pushobject(m_vm, m_outside);\n  sq_getclosureinfo(m_vm, -1, &m_outsideParamsCount, &nfreevars);\n  if (SQ_SUCCEEDED(sq_getclosurename(m_vm, -1))) {\n    sq_getstring(m_vm, -1, &outsideName);\n    if (outsideName)\n      m_outsideName = outsideName;\n  }\n  sq_settop(m_vm, top);\n  m_name.append(m_object.getName())\n      .append(\" [\")\n      .append(m_insideName)\n      .append(\",\")\n      .append(m_outsideName)\n      .append(\"]\");\n\n  trace(\"add trigger: {}\", m_name);\n}\n\nRoomTrigger::~RoomTrigger() {\n  trace(\"end room trigger thread: {}\", m_id);\n  sq_release(m_vm, &m_inside);\n  sq_release(m_vm, &m_outside);\n}\n\nHSQUIRRELVM RoomTrigger::createThread() {\n  HSQOBJECT thread_obj{};\n  sq_resetobject(&thread_obj);\n\n  HSQUIRRELVM thread = sq_newthread(m_vm, 1024);\n  if (SQ_FAILED(sq_getstackobj(m_vm, -1, &thread_obj))) {\n    error(\"Couldn't get coroutine thread from stack\");\n    return {};\n  }\n\n  auto pUniquethread = std::make_unique<RoomTriggerThread>(m_vm, m_name, thread_obj);\n  sq_pop(m_vm , 1); // pop thread\n  m_id = pUniquethread->getId();\n  trace(\"start room trigger thread: {}\", m_id);\n  m_engine.addThread(std::move(pUniquethread));\n  return thread;\n}\n\nvoid RoomTrigger::trigCore() {\n  auto actor = m_engine.getCurrentActor();\n  if (!actor)\n    return;\n\n  auto inObjectHotspot = m_object.getRealHotspot().contains(actor->getPosition());\n  if (!m_isInside && inObjectHotspot) {\n    m_isInside = true;\n\n    std::vector<HSQOBJECT> params;\n    if (m_insideParamsCount == 2) {\n      params.push_back(m_inside);\n      params.push_back(m_object.getTable());\n      params.push_back(actor->getTable());\n    } else {\n      params.push_back(m_inside);\n      params.push_back(m_object.getTable());\n    }\n\n    std::string name;\n    name.append(\"inside\");\n    if (!m_insideName.empty()) {\n      name.append(\" \").append(m_insideName);\n    }\n    callTrigger(params, name);\n  } else if (m_isInside && !inObjectHotspot) {\n    m_isInside = false;\n    if (m_outside._type != SQObjectType::OT_NULL) {\n      std::vector<HSQOBJECT> params;\n      if (m_outsideParamsCount == 2) {\n        params.push_back(m_outside);\n        params.push_back(m_object.getTable());\n        params.push_back(actor->getTable());\n      } else {\n        params.push_back(m_outside);\n        params.push_back(m_object.getTable());\n      }\n\n      std::string name;\n      name.append(\"outside\");\n      if (!m_outsideName.empty()) {\n        name.append(\" \").append(m_outsideName);\n      }\n      callTrigger(params, \"outside\");\n    }\n  }\n}\n\nvoid RoomTrigger::callTrigger(std::vector<HSQOBJECT> &params, const std::string &name) {\n  auto thread = createThread();\n  for (auto param : params) {\n    sq_pushobject(thread, param);\n  }\n\n  trace(\"call room {} trigger ({})\", name, m_id);\n  if (SQ_FAILED(sq_call(thread, params.size() - 1, SQFalse, SQTrue))) {\n    error(\"failed to call room {} trigger\", name);\n    return;\n  }\n}\n\nstd::string RoomTrigger::getName() { return m_name; }\n} // namespace ng\n"
  },
  {
    "path": "src/Room/RoomTrigger.hpp",
    "content": "#pragma once\n#include <engge/Engine/Trigger.hpp>\n#include <squirrel.h>\n#include <string>\n#include <vector>\n\nnamespace ng {\nclass Engine;\nclass Object;\n\nclass RoomTrigger : public Trigger {\npublic:\n  RoomTrigger(Engine &engine, Object &object, HSQOBJECT inside, HSQOBJECT outside);\n  ~RoomTrigger() override;\n\n  HSQOBJECT &getInside() { return m_inside; }\n  HSQOBJECT &getOutside() { return m_outside; }\n\n  std::string getName() override;\n\nprivate:\n  HSQUIRRELVM createThread();\n  void trigCore() override;\n  void callTrigger(std::vector<HSQOBJECT> &params, const std::string &name);\n\nprivate:\n  Engine &m_engine;\n  HSQUIRRELVM m_vm{};\n  Object &m_object;\n  HSQOBJECT m_inside{};\n  HSQOBJECT m_outside{};\n  bool m_isInside{false};\n  SQInteger m_insideParamsCount{0};\n  SQInteger m_outsideParamsCount{0};\n  std::string m_insideName;\n  std::string m_outsideName;\n  std::string m_name;\n  int m_id{0};\n};\n} // namespace ng\n"
  },
  {
    "path": "src/Room/RoomTriggerThread.cpp",
    "content": "#include \"RoomTriggerThread.hpp\"\n#include <utility>\n\nnamespace ng {\nRoomTriggerThread::RoomTriggerThread(HSQUIRRELVM vm, std::string name, HSQOBJECT thread_obj)\n    : m_vm(vm), m_name(std::move(name)), m_thread_obj(thread_obj) {\n  sq_addref(m_vm, &m_thread_obj);\n}\n\nRoomTriggerThread::~RoomTriggerThread() {\n  sq_release(m_vm, &m_thread_obj);\n}\n\nHSQUIRRELVM RoomTriggerThread::getThread() const {\n  return m_thread_obj._unVal.pThread;\n}\n\nstd::string RoomTriggerThread::getName() const {\n  return m_name;\n}\n}\n"
  },
  {
    "path": "src/Room/RoomTriggerThread.hpp",
    "content": "#pragma once\n#include \"engge/Engine/ThreadBase.hpp\"\n#include <squirrel.h>\n#include <string>\n\nnamespace ng {\nclass RoomTriggerThread final : public ThreadBase {\npublic:\n  RoomTriggerThread(HSQUIRRELVM vm, std::string name, HSQOBJECT thread_obj);\n  ~RoomTriggerThread() override;\n\n  [[nodiscard]] std::string getName() const override;\n  [[nodiscard]] HSQUIRRELVM getThread() const override;\n\nprivate:\n  HSQUIRRELVM m_vm;\n  std::string m_name;\n  HSQOBJECT m_thread_obj;\n};\n}"
  },
  {
    "path": "src/Scripting/ActorPack.hpp",
    "content": "#pragma once\n#include \"../Util/Util.hpp\"\n#include \"engge/Engine/Engine.hpp\"\n#include \"engge/Parsers/Lip.hpp\"\n#include <squirrel.h>\n#include <ngf/Math/PathFinding/Walkbox.h>\n\nnamespace ng {\nclass ActorPack final : public Pack {\nprivate:\n  static Engine *g_pEngine;\n\nprivate:\n  void registerPack() const override {\n    g_pEngine = &ScriptEngine::getEngine();\n    ScriptEngine::registerGlobalFunction(actorAlpha, \"actorAlpha\");\n    ScriptEngine::registerGlobalFunction(actorAnimationNames, \"actorAnimationNames\");\n    ScriptEngine::registerGlobalFunction(actorAnimationFlags, \"actorAnimationFlags\");\n    ScriptEngine::registerGlobalFunction(actorAt, \"actorAt\");\n    ScriptEngine::registerGlobalFunction(actorBlinkRate, \"actorBlinkRate\");\n    ScriptEngine::registerGlobalFunction(actorColor, \"actorColor\");\n    ScriptEngine::registerGlobalFunction(actorCostume, \"actorCostume\");\n    ScriptEngine::registerGlobalFunction(actorDistanceTo, \"actorDistanceTo\");\n    ScriptEngine::registerGlobalFunction(actorDistanceWithin, \"actorDistanceWithin\");\n    ScriptEngine::registerGlobalFunction(actorFace, \"actorFace\");\n    ScriptEngine::registerGlobalFunction(actorHidden, \"actorHidden\");\n    ScriptEngine::registerGlobalFunction(actorHideLayer, \"actorHideLayer\");\n    ScriptEngine::registerGlobalFunction(actorInTrigger, \"actorInTrigger\");\n    ScriptEngine::registerGlobalFunction(actorInWalkbox, \"actorInWalkbox\");\n    ScriptEngine::registerGlobalFunction(actorLockFacing, \"actorLockFacing\");\n    ScriptEngine::registerGlobalFunction(actorPlayAnimation, \"actorPlayAnimation\");\n    ScriptEngine::registerGlobalFunction(actorPosX, \"actorPosX\");\n    ScriptEngine::registerGlobalFunction(actorPosY, \"actorPosY\");\n    ScriptEngine::registerGlobalFunction(actorRenderOffset, \"actorRenderOffset\");\n    ScriptEngine::registerGlobalFunction(actorRoom, \"actorRoom\");\n    ScriptEngine::registerGlobalFunction(actorShowLayer, \"actorShowLayer\");\n    ScriptEngine::registerGlobalFunction(actorSlotSelectable, \"actorSlotSelectable\");\n    ScriptEngine::registerGlobalFunction(actorStand, \"actorStand\");\n    ScriptEngine::registerGlobalFunction(actorStopWalking, \"actorStopWalking\");\n    ScriptEngine::registerGlobalFunction(actorTalkColors, \"actorTalkColors\");\n    ScriptEngine::registerGlobalFunction(actorTalkOffset, \"actorTalkOffset\");\n    ScriptEngine::registerGlobalFunction(actorTalking, \"actorTalking\");\n    ScriptEngine::registerGlobalFunction(actorTurnTo, \"actorTurnTo\");\n    ScriptEngine::registerGlobalFunction(actorUsePos, \"actorUsePos\");\n    ScriptEngine::registerGlobalFunction(actorUseWalkboxes, \"actorUseWalkboxes\");\n    ScriptEngine::registerGlobalFunction(actorVolume, \"actorVolume\");\n    ScriptEngine::registerGlobalFunction(actorWalkForward, \"actorWalkForward\");\n    ScriptEngine::registerGlobalFunction(actorWalkSpeed, \"actorWalkSpeed\");\n    ScriptEngine::registerGlobalFunction(actorWalkTo, \"actorWalkTo\");\n    ScriptEngine::registerGlobalFunction(actorWalking, \"actorWalking\");\n    ScriptEngine::registerGlobalFunction(addSelectableActor, \"addSelectableActor\");\n    ScriptEngine::registerGlobalFunction(createActor, \"createActor\");\n    ScriptEngine::registerGlobalFunction(flashSelectableActor, \"flashSelectableActor\");\n    ScriptEngine::registerGlobalFunction(isActor, \"isActor\");\n    ScriptEngine::registerGlobalFunction(isActorOnScreen, \"isActorOnScreen\");\n    ScriptEngine::registerGlobalFunction(isActor, \"is_actor\");\n    ScriptEngine::registerGlobalFunction(isActorSelectable, \"isActorSelectable\");\n    ScriptEngine::registerGlobalFunction(masterActorArray, \"masterActorArray\");\n    ScriptEngine::registerGlobalFunction(mumbleLine, \"mumbleLine\");\n    ScriptEngine::registerGlobalFunction(sayLine, \"sayLine\");\n    ScriptEngine::registerGlobalFunction(sayLineAt, \"sayLineAt\");\n    ScriptEngine::registerGlobalFunction(selectActor, \"selectActor\");\n    ScriptEngine::registerGlobalFunction(stopTalking, \"stopTalking\");\n    ScriptEngine::registerGlobalFunction(triggerActors, \"triggerActors\");\n    ScriptEngine::registerGlobalFunction(verbUIColors, \"verbUIColors\");\n  }\n\n  static SQInteger actorAlpha(HSQUIRRELVM v) {\n    auto actor = EntityManager::getActor(v, 2);\n    if (!actor) {\n      return sq_throwerror(v, _SC(\"failed to get actor\"));\n    }\n    SQFloat alpha;\n    if (SQ_FAILED(sq_getfloat(v, 3, &alpha))) {\n      return sq_throwerror(v, _SC(\"failed to get alpha\"));\n    }\n    auto color = actor->getColor();\n    color.a = alpha;\n    actor->setColor(color);\n    return 0;\n  }\n\n  static SQInteger actorAnimationNames(HSQUIRRELVM v) {\n    const SQChar *head = nullptr;\n    const SQChar *stand = nullptr;\n    const SQChar *walk = nullptr;\n    const SQChar *reach = nullptr;\n    auto *pActor = EntityManager::getActor(v, 2);\n    if (!pActor) {\n      return sq_throwerror(v, _SC(\"failed to get actor\"));\n    }\n    HSQOBJECT obj;\n    sq_resetobject(&obj);\n    sq_getstackobj(v, 3, &obj);\n\n    sq_pushobject(v, obj);\n    sq_pushstring(v, _SC(\"head\"), -1);\n    if (SQ_SUCCEEDED(sq_get(v, -2))) {\n      sq_getstring(v, -1, &head);\n    }\n    sq_pop(v, 1);\n\n    sq_pushstring(v, _SC(\"stand\"), -1);\n    if (SQ_SUCCEEDED(sq_get(v, -2))) {\n      sq_getstring(v, -1, &stand);\n    }\n    sq_pop(v, 1);\n\n    sq_pushstring(v, _SC(\"walk\"), -1);\n    if (SQ_SUCCEEDED(sq_get(v, -2))) {\n      sq_getstring(v, -1, &walk);\n    }\n    sq_pop(v, 1);\n\n    sq_pushstring(v, _SC(\"reach\"), -1);\n    if (SQ_SUCCEEDED(sq_get(v, -2))) {\n      sq_getstring(v, -1, &reach);\n    }\n    sq_pop(v, 1);\n\n    pActor->getCostume().setAnimationNames(head ? head : \"\", stand ? stand : \"\", walk ? walk : \"\",\n                                           reach ? reach : \"\");\n    return 0;\n  }\n\n  static SQInteger actorAnimationFlags(HSQUIRRELVM v) {\n    auto *pActor = EntityManager::getActor(v, 2);\n    if (!pActor) {\n      return sq_throwerror(v, _SC(\"failed to get actor\"));\n    }\n    auto pAnim = pActor->getCostume().getAnimation();\n    if (!pAnim) {\n      sq_pushinteger(v, 0);\n      return 1;\n    }\n    sq_pushinteger(v, pAnim->flags);\n    return 1;\n  }\n\n  static Facing _getFacing(SQInteger dir, Facing currentFacing) {\n    if (dir == 0x10) {\n      switch (currentFacing) {\n      case Facing::FACE_BACK:return Facing::FACE_FRONT;\n      case Facing::FACE_FRONT:return Facing::FACE_BACK;\n      case Facing::FACE_LEFT:return Facing::FACE_RIGHT;\n      case Facing::FACE_RIGHT:return Facing::FACE_LEFT;\n      default:throw std::invalid_argument(\"currentFacing is invalid\");\n      }\n    } else {\n      switch (currentFacing) {\n      case Facing::FACE_BACK:return Facing::FACE_BACK;\n      case Facing::FACE_FRONT:return Facing::FACE_FRONT;\n      case Facing::FACE_LEFT:return Facing::FACE_LEFT;\n      case Facing::FACE_RIGHT:return Facing::FACE_RIGHT;\n      default:throw std::invalid_argument(\"currentFacing is invalid\");\n      }\n    }\n  }\n\n  static SQInteger actorAt(HSQUIRRELVM v) {\n    auto numArgs = sq_gettop(v);\n    switch (numArgs) {\n    case 3: {\n      auto *pActor = EntityManager::getActor(v, 2);\n      if (!pActor) {\n        return sq_throwerror(v, _SC(\"failed to get actor\"));\n      }\n\n      auto *pRoom = EntityManager::getRoom(v, 3);\n      if (pRoom) {\n        pActor->setRoom(pRoom);\n        return 0;\n      }\n\n      auto *pObj = EntityManager::getObject(v, 3);\n      if (!pObj) {\n        return sq_throwerror(v, _SC(\"failed to get object or room\"));\n      }\n      auto pos = pObj->getPosition() + pObj->getUsePosition().value_or(glm::vec2());\n      pRoom = pObj->getRoom();\n      pActor->setRoom(pRoom);\n      pActor->setPosition(pos);\n      pActor->getCostume().setFacing(toFacing(pObj->getUseDirection()));\n      return 0;\n    }\n\n    case 4: {\n      auto *pActor = EntityManager::getActor(v, 2);\n      if (!pActor) {\n        return sq_throwerror(v, _SC(\"failed to get actor\"));\n      }\n      SQInteger x, y;\n      if (SQ_FAILED(sq_getinteger(v, 3, &x))) {\n        return sq_throwerror(v, _SC(\"failed to get x\"));\n      }\n      if (SQ_FAILED(sq_getinteger(v, 4, &y))) {\n        return sq_throwerror(v, _SC(\"failed to get y\"));\n      }\n      pActor->setPosition(glm::vec2(x, y));\n      return 0;\n    }\n    case 5: [[fallthrough]];\n    case 6: {\n      auto *pActor = EntityManager::getActor(v, 2);\n      if (!pActor) {\n        return sq_throwerror(v, _SC(\"failed to get actor\"));\n      }\n      auto *pRoom = EntityManager::getRoom(v, 3);\n      if (!pRoom) {\n        return sq_throwerror(v, _SC(\"failed to get room\"));\n      }\n      SQInteger x, y, dir = 0;\n      if (SQ_FAILED(sq_getinteger(v, 4, &x))) {\n        return sq_throwerror(v, _SC(\"failed to get x\"));\n      }\n      if (SQ_FAILED(sq_getinteger(v, 5, &y))) {\n        return sq_throwerror(v, _SC(\"failed to get y\"));\n      }\n      if (numArgs == 6 && SQ_FAILED(sq_getinteger(v, 6, &dir))) {\n        return sq_throwerror(v, _SC(\"failed to get direction\"));\n      }\n      auto facing = _getFacing(dir, pActor->getCostume().getFacing());\n      pActor->setPosition(glm::vec2(x, y));\n      pActor->getCostume().setFacing(facing);\n      pActor->setRoom(pRoom);\n      return 0;\n    }\n    }\n\n    return sq_throwerror(v, _SC(\"invalid number of arguments\"));\n  }\n\n  static SQInteger flashSelectableActor(HSQUIRRELVM v) {\n    SQInteger on;\n    if (SQ_FAILED(sq_getinteger(v, 2, &on))) {\n      return sq_throwerror(v, _SC(\"failed to get on\"));\n    }\n    g_pEngine->flashSelectableActor(on != 0);\n    return 0;\n  }\n\n  static SQInteger actorColor(HSQUIRRELVM v) {\n    auto actor = EntityManager::getActor(v, 2);\n    if (!actor) {\n      return sq_throwerror(v, _SC(\"failed to get actor\"));\n    }\n    SQInteger c;\n    if (SQ_FAILED(sq_getinteger(v, 3, &c))) {\n      return sq_throwerror(v, _SC(\"failed to get color\"));\n    }\n    auto alpha = actor->getColor().a;\n    auto color = fromRgb(c);\n    color.a = alpha;\n    actor->setColor(color);\n    return 0;\n  }\n\n  static SQInteger actorCostume(HSQUIRRELVM v) {\n    const SQChar *name;\n    auto actor = EntityManager::getActor(v, 2);\n    if (!actor) {\n      return sq_throwerror(v, _SC(\"failed to get actor\"));\n    }\n    if (SQ_FAILED(sq_getstring(v, 3, &name))) {\n      return sq_throwerror(v, _SC(\"failed to get name\"));\n    }\n    const SQChar *pSheet = nullptr;\n    sq_getstring(v, 4, &pSheet);\n    actor->setCostume(name, pSheet ? pSheet : \"\");\n    return 0;\n  }\n\n  static SQInteger actorDistanceTo(HSQUIRRELVM v) {\n    auto pActor = EntityManager::getActor(v, 2);\n    if (!pActor) {\n      return sq_throwerror(v, _SC(\"failed to get actor\"));\n    }\n    auto pActor2 = EntityManager::getActor(v, 3);\n    if (pActor2) {\n      auto dist = _distance(pActor->getPosition(), pActor2->getPosition());\n      sq_pushinteger(v, dist);\n      return 1;\n    }\n    auto pObject = EntityManager::getObject(v, 3);\n    if (!pObject) {\n      return sq_throwerror(v, _SC(\"failed to get object\"));\n    }\n    auto posObj = pObject->getRealPosition() + pObject->getUsePosition().value_or(glm::vec2());\n    auto dist = _distance(pActor->getPosition(), posObj);\n    sq_pushinteger(v, dist);\n    return 1;\n  }\n\n  static SQInteger actorDistanceWithin(HSQUIRRELVM v) {\n    auto actor = EntityManager::getActor(v, 2);\n    if (!actor) {\n      return sq_throwerror(v, _SC(\"failed to get actor\"));\n    }\n    SQInteger d;\n    if (SQ_FAILED(sq_getinteger(v, 4, &d))) {\n      return sq_throwerror(v, _SC(\"failed to get distance\"));\n    }\n    auto pActor2 = EntityManager::getActor(v, 3);\n    if (pActor2) {\n      auto dist = _distance(actor->getPosition(), pActor2->getPosition());\n//      trace(\"actorDistanceWithin({},{},{})=>{} ({})\",\n//            actor->getKey(),\n//            pActor2->getKey(),\n//            d,\n//            (dist < d) ? \"YES\" : \"NO\",\n//            dist);\n      sq_pushbool(v, dist < d);\n      return 1;\n    }\n\n    auto pObject = EntityManager::getObject(v, 3);\n    if (!pObject) {\n      return sq_throwerror(v, _SC(\"failed to get object or actor\"));\n    }\n\n    auto posObj = pObject->getPosition() + pObject->getUsePosition().value_or(glm::vec2());\n    auto dist = _distance(actor->getPosition(), posObj);\n//    trace(\"actorDistanceWithin({},{},{})=>{} ({})\",\n//          actor->getKey(),\n//          pObject->getName(),\n//          d,\n//          (dist < d) ? \"YES\" : \"NO\",\n//          dist);\n    sq_pushbool(v, dist < d);\n    return 1;\n  }\n\n  static float _distance(glm::vec2 p1, glm::vec2 p2) {\n    auto pos = p1 - p2;\n    return sqrt(pos.x * pos.x + pos.y * pos.y);\n  }\n\n  static SQInteger actorFace(HSQUIRRELVM v) {\n    auto actor = EntityManager::getActor(v, 2);\n    if (!actor) {\n      return sq_throwerror(v, _SC(\"failed to get actor\"));\n    }\n    auto count = sq_gettop(v);\n    SQInteger dir;\n    if (count == 2) {\n      dir = (SQInteger) actor->getCostume().getFacing();\n      sq_pushinteger(v, dir);\n      return 1;\n    }\n\n    if (sq_gettype(v, 3) == OT_INTEGER) {\n      if (SQ_FAILED(sq_getinteger(v, 3, &dir))) {\n        return sq_throwerror(v, _SC(\"failed to get direction\"));\n      }\n      // FACE_FLIP ?\n      if (dir == 0x10) {\n        auto facing = _flip(actor->getCostume().getFacing());\n        actor->getCostume().setFacing(facing);\n        return 0;\n      }\n      actor->getCostume().setFacing((Facing) dir);\n      return 0;\n    }\n\n    auto actor2 = EntityManager::getActor(v, 3);\n    if (!actor2) {\n      return sq_throwerror(v, _SC(\"failed to get actor to face to\"));\n    }\n    auto facing = _getFacingToFaceTo(actor, actor2);\n    actor->getCostume().setFacing(facing);\n    return 0;\n  }\n\n  static SQInteger actorHidden(HSQUIRRELVM v) {\n    auto *pActor = EntityManager::getActor(v, 2);\n    if (!pActor) {\n      return sq_throwerror(v, _SC(\"failed to get actor\"));\n    }\n    SQInteger hidden = 0;\n    if (SQ_FAILED(sq_getinteger(v, 3, &hidden))) {\n      return sq_throwerror(v, _SC(\"failed to get hidden\"));\n    }\n    pActor->setVisible(hidden == 0);\n    return 0;\n  }\n\n  static SQInteger actorShowHideLayer(HSQUIRRELVM v, bool isVisible) {\n    auto *pActor = EntityManager::getActor(v, 2);\n    if (!pActor) {\n      return sq_throwerror(v, _SC(\"failed to get actor\"));\n    }\n    const SQChar *layerName;\n    if (SQ_FAILED(sq_getstring(v, 3, &layerName))) {\n      return sq_throwerror(v, _SC(\"failed to get layerName\"));\n    }\n    pActor->getCostume().setLayerVisible(layerName, isVisible);\n    return 0;\n  }\n\n  static SQInteger actorHideLayer(HSQUIRRELVM v) { return actorShowHideLayer(v, false); }\n\n  static SQInteger actorInTrigger(HSQUIRRELVM v) {\n    auto *actor = EntityManager::getActor(v, 2);\n    if (!actor) {\n      return sq_throwerror(v, _SC(\"failed to get actor\"));\n    }\n    auto *object = EntityManager::getObject(v, 3);\n    if (!object) {\n      return sq_throwerror(v, _SC(\"failed to get object\"));\n    }\n    bool isInside = object->getRealHotspot().contains(actor->getPosition());\n    sq_pushbool(v, isInside);\n    return 1;\n  }\n\n  static SQInteger actorInWalkbox(HSQUIRRELVM v) {\n    auto *actor = EntityManager::getActor(v, 2);\n    if (!actor) {\n      return sq_throwerror(v, _SC(\"failed to get actor\"));\n    }\n\n    const SQChar *walkboxName;\n    if (SQ_FAILED(sq_getstring(v, 3, &walkboxName))) {\n      return sq_throwerror(v, _SC(\"failed to get walkbox\"));\n    }\n    auto pWalkbox = g_pEngine->getRoom()->getWalkbox(walkboxName);\n    auto inWalkbox = pWalkbox && pWalkbox->inside(actor->getPosition());\n    sq_pushbool(v, inWalkbox ? SQTrue : SQFalse);\n    return 1;\n  }\n\n  static SQInteger actorLockFacing(HSQUIRRELVM v) {\n    SQInteger facing;\n    Actor *actor = EntityManager::getActor(v, 2);\n    if (!actor) {\n      return sq_throwerror(v, _SC(\"failed to get actor\"));\n    }\n    HSQOBJECT obj;\n    sq_getstackobj(v, 3, &obj);\n    if (sq_istable(obj)) {\n      auto back = static_cast<SQInteger>(Facing::FACE_BACK);\n      auto front = static_cast<SQInteger>(Facing::FACE_FRONT);\n      auto left = static_cast<SQInteger>(Facing::FACE_LEFT);\n      auto right = static_cast<SQInteger>(Facing::FACE_RIGHT);\n      SQInteger reset = 0;\n      readFieldInt(v, _SC(\"back\"), back);\n      readFieldInt(v, _SC(\"front\"), front);\n      readFieldInt(v, _SC(\"left\"), left);\n      readFieldInt(v, _SC(\"right\"), right);\n      readFieldInt(v, _SC(\"reset\"), reset);\n      if (reset) {\n        actor->getCostume().resetLockFacing();\n        return 0;\n      }\n      actor->getCostume().lockFacing(static_cast<Facing>(left), static_cast<Facing>(right),\n                                     static_cast<Facing>(front), static_cast<Facing>(back));\n      return 0;\n    }\n    if (SQ_FAILED(sq_getinteger(v, 3, &facing))) {\n      return sq_throwerror(v, _SC(\"failed to get facing\"));\n    }\n    if (facing == 0) {\n      actor->getCostume().unlockFacing();\n      return 0;\n    }\n    auto allFacing = static_cast<Facing>(facing);\n    actor->getCostume().lockFacing(allFacing, allFacing, allFacing, allFacing);\n    return 0;\n  }\n\n  static SQInteger actorBlinkRate(HSQUIRRELVM v) {\n    Actor *pActor = EntityManager::getActor(v, 2);\n    if (!pActor) {\n      return sq_throwerror(v, _SC(\"failed to get actor\"));\n    }\n    SQFloat min = 0;\n    if (SQ_FAILED(sq_getfloat(v, 3, &min))) {\n      return sq_throwerror(v, _SC(\"failed to get min\"));\n    }\n    SQFloat max = 0;\n    if (SQ_FAILED(sq_getfloat(v, 4, &max))) {\n      return sq_throwerror(v, _SC(\"failed to get max\"));\n    }\n    pActor->getCostume().setBlinkRate(min, max);\n    return 0;\n  }\n\n  static SQInteger actorPlayAnimation(HSQUIRRELVM v) {\n    Actor *pActor = EntityManager::getActor(v, 2);\n    if (!pActor) {\n      return sq_throwerror(v, _SC(\"failed to get actor\"));\n    }\n    const SQChar *animation = nullptr;\n    if (SQ_FAILED(sq_getstring(v, 3, &animation))) {\n      return sq_throwerror(v, _SC(\"failed to get animation\"));\n    }\n    SQInteger loop = 0;\n    sq_getinteger(v, 4, &loop);\n    trace(\"Play anim {} {}{}\", pActor->getName(), animation, (loop != 0 ? \" (loop)\" : \"\"));\n    pActor->stopWalking();\n    pActor->getCostume().setState(animation, loop != 0);\n    return 0;\n  }\n\n  static SQInteger actorPosX(HSQUIRRELVM v) {\n    auto *pActor = EntityManager::getActor(v, 2);\n    if (!pActor) {\n      return sq_throwerror(v, _SC(\"failed to get actor\"));\n    }\n    sq_pushinteger(v, pActor->getPosition().x);\n    return 1;\n  }\n\n  static SQInteger actorPosY(HSQUIRRELVM v) {\n    auto *pActor = EntityManager::getActor(v, 2);\n    if (!pActor) {\n      return sq_throwerror(v, _SC(\"failed to get actor\"));\n    }\n    sq_pushinteger(v, pActor->getPosition().y);\n    return 1;\n  }\n\n  static SQInteger actorRenderOffset(HSQUIRRELVM v) {\n    auto *pActor = EntityManager::getActor(v, 2);\n    if (!pActor) {\n      return sq_throwerror(v, _SC(\"failed to get actor\"));\n    }\n    SQInteger x, y;\n    if (SQ_FAILED(sq_getinteger(v, 3, &x))) {\n      return sq_throwerror(v, _SC(\"failed to get x\"));\n    }\n    if (SQ_FAILED(sq_getinteger(v, 4, &y))) {\n      return sq_throwerror(v, _SC(\"failed to get y\"));\n    }\n    pActor->setRenderOffset(glm::ivec2(x, y));\n    return 0;\n  }\n\n  static SQInteger actorRoom(HSQUIRRELVM v) {\n    auto *pActor = EntityManager::getActor(v, 2);\n    if (!pActor) {\n      return sq_throwerror(v, _SC(\"failed to get actor\"));\n    }\n    auto pRoom = pActor->getRoom();\n    if (pRoom) {\n      sq_pushobject(v, pRoom->getTable());\n      return 1;\n    }\n    sq_pushnull(v);\n    return 1;\n  }\n\n  static SQInteger actorStand(HSQUIRRELVM v) {\n    auto *pActor = EntityManager::getActor(v, 2);\n    if (!pActor) {\n      return sq_throwerror(v, _SC(\"failed to get actor\"));\n    }\n    pActor->getCostume().setStandState();\n    return 0;\n  }\n\n  static SQInteger actorShowLayer(HSQUIRRELVM v) { return actorShowHideLayer(v, true); }\n\n  static SQInteger actorSlotSelectable(HSQUIRRELVM v) {\n    auto numArgs = sq_gettop(v);\n    if (numArgs == 2) {\n      SQInteger selectable;\n      if (SQ_FAILED(sq_getinteger(v, 2, &selectable))) {\n        return sq_throwerror(v, _SC(\"failed to get selectable\"));\n      }\n      auto mode = g_pEngine->getActorSlotSelectable();\n      switch (selectable) {\n      case 0:g_pEngine->setActorSlotSelectable(mode & ~ActorSlotSelectableMode::On);\n        return 0;\n      case 1:g_pEngine->setActorSlotSelectable(mode | ActorSlotSelectableMode::On);\n        return 0;\n      case 2:g_pEngine->setActorSlotSelectable(mode | ActorSlotSelectableMode::TemporaryUnselectable);\n        return 0;\n      case 3:g_pEngine->setActorSlotSelectable(mode & ~ActorSlotSelectableMode::TemporaryUnselectable);\n        return 0;\n      default:return sq_throwerror(v, _SC(\"invalid selectable value\"));\n      }\n    }\n\n    if (numArgs == 3) {\n      SQInteger selectable;\n      if (SQ_FAILED(sq_getinteger(v, 3, &selectable))) {\n        return sq_throwerror(v, _SC(\"failed to get selectable\"));\n      }\n      if (sq_gettype(v, 2) == OT_INTEGER) {\n        SQInteger actorIndex = 0;\n        if (SQ_FAILED(sq_getinteger(v, 2, &actorIndex))) {\n          return sq_throwerror(v, _SC(\"failed to get actor index\"));\n        }\n        g_pEngine->actorSlotSelectable(actorIndex, selectable == SQTrue);\n        return 0;\n      }\n      auto actor = EntityManager::getActor(v, 2);\n      if (!actor) {\n        return sq_throwerror(v, _SC(\"failed to get actor\"));\n      }\n      g_pEngine->actorSlotSelectable(actor, selectable != 0);\n      return 0;\n    }\n    return sq_throwerror(v, _SC(\"invalid number of arguments\"));\n  }\n\n  static SQInteger actorTalking(HSQUIRRELVM v) {\n    Actor *pActor;\n    if (sq_gettop(v) == 2) {\n      pActor = EntityManager::getActor(v, 2);\n      if (!pActor) {\n        return sq_throwerror(v, _SC(\"failed to get actor\"));\n      }\n    } else {\n      pActor = g_pEngine->getCurrentActor();\n    }\n    sq_pushbool(v, pActor && pActor->isTalking());\n    return 1;\n  }\n\n  static SQInteger actorStopWalking(HSQUIRRELVM v) {\n    auto actor = EntityManager::getActor(v, 2);\n    if (!actor) {\n      return sq_throwerror(v, _SC(\"failed to get actor\"));\n    }\n    actor->stopWalking();\n    return 0;\n  }\n\n  static SQInteger actorTalkColors(HSQUIRRELVM v) {\n    auto pEntity = EntityManager::getEntity(v, 2);\n    if (!pEntity) {\n      return sq_throwerror(v, _SC(\"failed to get actor/object\"));\n    }\n    SQInteger color;\n    if (SQ_FAILED(sq_getinteger(v, 3, &color))) {\n      return sq_throwerror(v, _SC(\"failed to get fps\"));\n    }\n    pEntity->setTalkColor(fromRgb(color));\n    return 0;\n  }\n\n  static SQInteger actorTalkOffset(HSQUIRRELVM v) {\n    auto pEntity = EntityManager::getEntity(v, 2);\n    if (!pEntity) {\n      return sq_throwerror(v, _SC(\"failed to get actor/object\"));\n    }\n    SQInteger x;\n    if (SQ_FAILED(sq_getinteger(v, 3, &x))) {\n      return sq_throwerror(v, _SC(\"failed to get x\"));\n    }\n    SQInteger y;\n    if (SQ_FAILED(sq_getinteger(v, 4, &y))) {\n      return sq_throwerror(v, _SC(\"failed to get y\"));\n    }\n    pEntity->setTalkOffset(glm::ivec2(x, y));\n    return 0;\n  }\n\n  static SQInteger actorTurnTo(HSQUIRRELVM v) {\n    Actor *actor = EntityManager::getActor(v, 2);\n    if (!actor) {\n      return sq_throwerror(v, _SC(\"failed to get actor\"));\n    }\n\n    if (sq_gettype(v, 3) == OT_INTEGER) {\n      SQInteger facing = 0;\n      if (SQ_FAILED(sq_getinteger(v, 3, &facing))) {\n        return sq_throwerror(v, _SC(\"failed to get facing\"));\n      }\n      actor->getCostume().setFacing((Facing) facing);\n      return 0;\n    }\n\n    Entity *entity = EntityManager::getEntity(v, 3);\n    if (!entity) {\n      return sq_throwerror(v, _SC(\"failed to get entity to face to\"));\n    }\n\n    auto facing = _getFacingToFaceTo(actor, entity);\n    actor->getCostume().setFacing(facing);\n    return 0;\n  }\n\n  static Facing _getFacingToFaceTo(Actor *pActor, Entity *pEntity) {\n    Facing facing;\n    auto d = pEntity->getPosition() - pActor->getPosition();\n    if (d.x == 0) {\n      facing = d.y > 0 ? Facing::FACE_FRONT : Facing::FACE_BACK;\n    } else {\n      facing = d.x > 0 ? Facing::FACE_RIGHT : Facing::FACE_LEFT;\n    }\n    return facing;\n  }\n\n  static Facing _flip(Facing facing) {\n    switch (facing) {\n    case Facing::FACE_BACK:return Facing::FACE_FRONT;\n    case Facing::FACE_FRONT:return Facing::FACE_BACK;\n    case Facing::FACE_LEFT:return Facing::FACE_RIGHT;\n    case Facing::FACE_RIGHT:return Facing::FACE_LEFT;\n    }\n    throw std::out_of_range(\"Invalid facing\");\n  }\n\n  static SQInteger actorUsePos(HSQUIRRELVM v) {\n    auto numArgs = sq_gettop(v);\n    auto *actor = EntityManager::getActor(v, 2);\n    if (!actor) {\n      return sq_throwerror(v, _SC(\"failed to get actor\"));\n    }\n    auto *obj = EntityManager::getObject(v, 3);\n    if (!obj) {\n      actor->setUsePosition(glm::vec2());\n      return 0;\n    }\n    auto usePos = obj->getUsePosition();\n    actor->setUsePosition(usePos);\n    if (numArgs == 4) {\n      SQInteger dir;\n      if (SQ_FAILED(sq_getinteger(v, 5, &dir))) {\n        return sq_throwerror(v, _SC(\"failed to get direction\"));\n      }\n      actor->setUseDirection(static_cast<UseDirection>(dir));\n    }\n    return 0;\n  }\n\n  static SQInteger actorUseWalkboxes(HSQUIRRELVM v) {\n    Actor *actor = EntityManager::getActor(v, 2);\n    if (!actor) {\n      return sq_throwerror(v, _SC(\"failed to get actor\"));\n    }\n    SQBool use;\n    sq_tobool(v, 3, &use);\n\n    actor->useWalkboxes(use);\n    return 0;\n  }\n\n  static SQInteger actorVolume(HSQUIRRELVM v) {\n    Actor *actor = EntityManager::getActor(v, 2);\n    if (!actor) {\n      return sq_throwerror(v, _SC(\"failed to get actor\"));\n    }\n    SQFloat volume;\n    if (SQ_FAILED(sq_getfloat(v, 3, &volume))) {\n      return sq_throwerror(v, _SC(\"failed to get volume\"));\n    }\n    actor->setVolume(volume);\n    return 0;\n  }\n\n  static SQInteger actorWalkForward(HSQUIRRELVM v) {\n    Actor *actor = EntityManager::getActor(v, 2);\n    if (!actor) {\n      return sq_throwerror(v, _SC(\"failed to get actor\"));\n    }\n    SQInteger dist;\n    if (SQ_FAILED(sq_getinteger(v, 3, &dist))) {\n      return sq_throwerror(v, _SC(\"failed to get distance\"));\n    }\n    glm::vec2 direction;\n    switch (actor->getCostume().getFacing()) {\n    case Facing::FACE_FRONT:direction = glm::vec2(0, -dist);\n      break;\n    case Facing::FACE_BACK:direction = glm::vec2(0, dist);\n      break;\n    case Facing::FACE_LEFT:direction = glm::vec2(-dist, 0);\n      break;\n    case Facing::FACE_RIGHT:direction = glm::vec2(dist, 0);\n      break;\n    }\n    actor->walkTo(actor->getPosition() + direction);\n    return 0;\n  }\n\n  static SQInteger actorWalking(HSQUIRRELVM v) {\n    auto numArgs = sq_gettop(v) - 1;\n    Actor *pActor = nullptr;\n    if (numArgs == 0) {\n      pActor = g_pEngine->getCurrentActor();\n    } else if (numArgs == 1) {\n      pActor = EntityManager::getActor(v, 2);\n    }\n    if (!pActor) {\n      return sq_throwerror(v, _SC(\"failed to get actor\"));\n    }\n    sq_pushbool(v, pActor->isWalking() ? SQTrue : SQFalse);\n    return 1;\n  }\n\n  static SQInteger actorWalkSpeed(HSQUIRRELVM v) {\n    auto pActor = EntityManager::getActor(v, 2);\n    if (!pActor) {\n      return sq_throwerror(v, _SC(\"failed to get actor\"));\n    }\n    SQInteger x, y;\n    if (SQ_FAILED(sq_getinteger(v, 3, &x))) {\n      return sq_throwerror(v, _SC(\"failed to get x\"));\n    }\n    if (SQ_FAILED(sq_getinteger(v, 4, &y))) {\n      return sq_throwerror(v, _SC(\"failed to get y\"));\n    }\n    pActor->setWalkSpeed(glm::ivec2(x, y));\n    return 0;\n  }\n\n  static SQInteger actorWalkTo(HSQUIRRELVM v) {\n    auto numArgs = sq_gettop(v);\n    auto *pActor = EntityManager::getActor(v, 2);\n    if (!pActor) {\n      return sq_throwerror(v, _SC(\"failed to get actor\"));\n    }\n    if (numArgs == 3) {\n      auto *pObject = EntityManager::getObject(v, 3);\n      if (pObject) {\n        auto pos = pObject->getPosition();\n        auto usePos = pObject->getUsePosition().value_or(glm::vec2());\n        pos.x += usePos.x;\n        pos.y += usePos.y;\n        pActor->walkTo(pos, toFacing(pObject->getUseDirection()));\n        return 0;\n      }\n\n      pActor = EntityManager::getActor(v, 3);\n      if (!pActor) {\n        return sq_throwerror(v, _SC(\"failed to get object or actor\"));\n      }\n\n      auto pos = pActor->getPosition();\n      pActor->walkTo(glm::vec2(pos), getOppositeFacing(pActor->getCostume().getFacing()));\n      return 0;\n    }\n\n    SQInteger x, y;\n    if (SQ_FAILED(sq_getinteger(v, 3, &x))) {\n      return sq_throwerror(v, _SC(\"failed to get x\"));\n    }\n    if (SQ_FAILED(sq_getinteger(v, 4, &y))) {\n      return sq_throwerror(v, _SC(\"failed to get y\"));\n    }\n    pActor->walkTo(glm::vec2(x, y));\n    return 0;\n  }\n\n  static SQInteger addSelectableActor(HSQUIRRELVM v) {\n    SQInteger slot;\n    if (SQ_FAILED(sq_getinteger(v, 2, &slot))) {\n      return sq_throwerror(v, _SC(\"failed to get slot\"));\n    }\n    auto *pActor = EntityManager::getActor(v, 3);\n    g_pEngine->addSelectableActor(slot, pActor);\n    return 0;\n  }\n\n  static SQInteger createActor(HSQUIRRELVM v) {\n    auto pActor = std::make_unique<Actor>(*g_pEngine);\n    auto &table = pActor->getTable();\n    sq_resetobject(&table);\n    sq_getstackobj(v, 2, &table);\n    sq_addref(v, &table);\n\n    const char *key = nullptr;\n    if (ScriptEngine::rawGet(pActor.get(), \"_key\", key)) {\n      pActor->setKey(key);\n    }\n\n    // define instance\n    ScriptEngine::set(pActor.get(), \"_id\", pActor->getId());\n\n    trace(\"Create actor {}\", pActor->getName());\n    g_pEngine->addActor(std::move(pActor));\n\n    sq_pushobject(v, table);\n    return 1;\n  }\n\n  static SQInteger isActor(HSQUIRRELVM v) {\n    auto actor = EntityManager::getActor(v, 2);\n    sq_pushbool(v, actor ? SQTrue : SQFalse);\n    return 1;\n  }\n\n  static SQInteger isActorSelectable(HSQUIRRELVM v) {\n    auto actor = EntityManager::getActor(v, 2);\n    bool isSelectable = g_pEngine->isActorSelectable(actor);\n    sq_pushbool(v, isSelectable ? SQTrue : SQFalse);\n    return 1;\n  }\n\n  static SQInteger isActorOnScreen(HSQUIRRELVM v) {\n    auto entity = EntityManager::getEntity(v, 2);\n    if (!entity) {\n      return sq_throwerror(v, _SC(\"failed to get entity\"));\n    }\n\n    const Room *pEntityRoom = entity->getRoom();\n    const Room *pRoom = g_pEngine->getRoom();\n    if (pEntityRoom != pRoom) {\n      sq_pushbool(v, SQFalse);\n      return 1;\n    }\n\n    auto pos = entity->getPosition();\n    auto isOnScreen = g_pEngine->getCamera().getRect().contains(pos);\n    sq_pushbool(v, isOnScreen ? SQTrue : SQFalse);\n    return 1;\n  }\n\n  static SQInteger masterActorArray(HSQUIRRELVM v) {\n    auto &actors = g_pEngine->getActors();\n    sq_newarray(v, 0);\n    for (auto &actor : actors) {\n      sq_pushobject(v, actor->getTable());\n      sq_arrayappend(v, -2);\n    }\n    return 1;\n  }\n\n  static SQInteger _sayLine(HSQUIRRELVM v, bool mumble = false) {\n    Entity *pEntity;\n    SQInteger index;\n    if (sq_gettype(v, 2) == OT_TABLE) {\n      pEntity = EntityManager::getEntity(v, 2);\n      index = 3;\n    } else {\n      pEntity = g_pEngine->getCurrentActor();\n      index = 2;\n    }\n\n    if (!pEntity) {\n      return sq_throwerror(v, _SC(\"failed to get actor/object\"));\n    }\n\n    if (sq_gettype(v, index) == OT_ARRAY) {\n      sq_push(v, index);\n      sq_pushnull(v);  //null iterator\n      while (SQ_SUCCEEDED(sq_next(v, -2))) {\n        //here -1 is the value and -2 is the key\n        const SQChar *idText = nullptr;\n        sq_getstring(v, -1, &idText);\n        pEntity->say(idText, mumble);\n        sq_pop(v, 2); //pops key and val before the nex iteration\n      }\n      sq_pop(v, 2); //pops the null iterator + array\n    } else {\n      auto numIds = sq_gettop(v) - index + 1;\n      for (int i = 0; i < numIds; i++) {\n        const SQChar *idText = nullptr;\n        if (SQ_FAILED(sq_getstring(v, index + i, &idText))) {\n          return sq_throwerror(v, _SC(\"failed to get text\"));\n        }\n        pEntity->say(idText, mumble);\n      }\n    }\n    return 0;\n  }\n\n  static SQInteger mumbleLine(HSQUIRRELVM v) { return _sayLine(v, true); }\n\n  static SQInteger sayLine(HSQUIRRELVM v) {\n    auto pEntity = EntityManager::getActor(v, 2);\n    if (!pEntity) {\n      pEntity = g_pEngine->getCurrentActor();\n    }\n\n    // actors should stop talking except current actor\n    g_pEngine->stopTalkingExcept(pEntity);\n    return _sayLine(v);\n  }\n\n  static SQInteger sayLineAt(HSQUIRRELVM v) {\n    SQInteger x;\n    if (SQ_FAILED(sq_getinteger(v, 2, &x))) {\n      return sq_throwerror(v, _SC(\"failed to get x\"));\n    }\n    SQInteger y;\n    if (SQ_FAILED(sq_getinteger(v, 3, &y))) {\n      return sq_throwerror(v, _SC(\"failed to get y\"));\n    }\n    if (sq_gettype(v, 4) == OT_INTEGER) {\n      SQInteger c;\n      if (SQ_FAILED(sq_getinteger(v, 4, &c))) {\n        return sq_throwerror(v, _SC(\"failed to get color\"));\n      }\n      auto color = fromRgb(c);\n      SQFloat t;\n      if (SQ_FAILED(sq_getfloat(v, 5, &t))) {\n        return sq_throwerror(v, _SC(\"failed to get time\"));\n      }\n      const SQChar *text;\n      if (SQ_FAILED(sq_getstring(v, 6, &text))) {\n        return sq_throwerror(v, _SC(\"failed to get text\"));\n      }\n      g_pEngine->sayLineAt({x, y}, color, ngf::TimeSpan::seconds(t), text);\n      return 0;\n    }\n    auto *actor = EntityManager::getActor(v, 4);\n    if (!actor) {\n      return sq_throwerror(v, _SC(\"failed to get actor\"));\n    }\n    const SQChar *text;\n    if (SQ_FAILED(sq_getstring(v, 6, &text))) {\n      return sq_throwerror(v, _SC(\"failed to get text\"));\n    }\n    g_pEngine->sayLineAt({x, y}, *actor, text);\n    return 0;\n  }\n\n  static SQInteger selectActor(HSQUIRRELVM v) {\n    auto *actor = EntityManager::getActor(v, 2);\n    if (!actor) {\n      return sq_throwerror(v, _SC(\"failed to get actor\"));\n    }\n    g_pEngine->setCurrentActor(actor, false);\n    return 0;\n  }\n\n  static SQInteger stopTalking(HSQUIRRELVM v) {\n    auto numArgs = sq_gettop(v) - 1;\n    if (numArgs == 1) {\n      if (sq_gettype(v, 2) == OT_INTEGER) {\n        g_pEngine->stopTalking();\n        return 0;\n      }\n      auto pEntity = EntityManager::getEntity(v, 2);\n      if (!pEntity) {\n        return sq_throwerror(v, _SC(\"failed to get actor/object\"));\n      }\n      pEntity->stopTalking();\n      return 0;\n    }\n\n    g_pEngine->getCurrentActor()->stopTalking();\n    return 0;\n  }\n\n  static SQInteger triggerActors(HSQUIRRELVM v) {\n    auto *object = EntityManager::getObject(v, 2);\n    if (!object) {\n      return sq_throwerror(v, _SC(\"failed to get object\"));\n    }\n    sq_newarray(v, 0);\n    for (const auto &actor : g_pEngine->getActors()) {\n      if (object->getRealHotspot().contains((glm::ivec2) actor->getPosition())) {\n        sq_pushobject(v, actor->getTable());\n        sq_arrayappend(v, -2);\n      }\n    }\n    return 1;\n  }\n\n  static SQInteger readFieldInt(HSQUIRRELVM v, const SQChar *name, SQInteger &field) {\n    sq_pushstring(v, name, -1);\n    if (SQ_FAILED(sq_get(v, -2))) {\n      return SQ_ERROR;\n    }\n\n    field = 0;\n    if (SQ_FAILED(sq_getinteger(v, -1, &field))) {\n      return SQ_ERROR;\n    }\n    sq_pop(v, 1);\n    return SQ_OK;\n  }\n\n  static SQInteger verbUIColors(HSQUIRRELVM v) {\n    SQInteger actorSlot;\n    if (SQ_FAILED(sq_getinteger(v, 2, &actorSlot))) {\n      return sq_throwerror(v, _SC(\"failed to get actor slot\"));\n    }\n\n    HSQOBJECT table;\n    if (SQ_FAILED(sq_getstackobj(v, 3, &table))) {\n      return sq_throwerror(v, _SC(\"failed to get verb definitionTable\"));\n    }\n    if (!sq_istable(table)) {\n      const SQChar *tmp;\n      sq_getstring(v, 3, &tmp);\n      return sq_throwerror(v, _SC(\"failed to get verb definitionTable\"));\n    }\n\n    sq_pushobject(v, table);\n\n    // sentence\n    SQInteger sentence = 0;\n    if (SQ_FAILED(readFieldInt(v, _SC(\"sentence\"), sentence))) {\n      return sq_throwerror(v, _SC(\"failed to get sentence\"));\n    }\n\n    SQInteger verbNormal = 0;\n    if (SQ_FAILED(readFieldInt(v, _SC(\"verbNormal\"), verbNormal))) {\n      return sq_throwerror(v, _SC(\"failed to get verbNormal\"));\n    }\n\n    SQInteger verbNormalTint = 0;\n    if (SQ_FAILED(readFieldInt(v, _SC(\"verbNormalTint\"), verbNormalTint))) {\n      return sq_throwerror(v, _SC(\"failed to get verbNormal\"));\n    }\n\n    SQInteger verbHighlight = 0;\n    if (SQ_FAILED(readFieldInt(v, _SC(\"verbHighlight\"), verbHighlight))) {\n      return sq_throwerror(v, _SC(\"failed to get verbHighlight\"));\n    }\n\n    SQInteger verbHighlightTint = 0;\n    if (SQ_FAILED(readFieldInt(v, _SC(\"verbHighlightTint\"), verbHighlightTint))) {\n      return sq_throwerror(v, _SC(\"failed to get verbHighlightTint\"));\n    }\n\n    SQInteger inventoryFrame = 0;\n    if (SQ_FAILED(readFieldInt(v, _SC(\"inventoryFrame\"), inventoryFrame))) {\n      return sq_throwerror(v, _SC(\"failed to get inventoryFrame\"));\n    }\n\n    SQInteger inventoryBackground = 0;\n    if (SQ_FAILED(readFieldInt(v, _SC(\"inventoryBackground\"), inventoryBackground))) {\n      return sq_throwerror(v, _SC(\"failed to get inventoryBackground\"));\n    }\n\n    SQInteger retroNormal = verbNormal;\n    readFieldInt(v, _SC(\"retroNormal\"), retroNormal);\n\n    SQInteger retroHighlight = verbNormalTint;\n    readFieldInt(v, _SC(\"retroHighlight\"), retroHighlight);\n\n    SQInteger dialogNormal = verbNormal;\n    readFieldInt(v, _SC(\"dialogNormal\"), dialogNormal);\n\n    SQInteger dialogHighlight = verbHighlight;\n    readFieldInt(v, _SC(\"dialogHighlight\"), dialogHighlight);\n\n    VerbUiColors colors;\n    colors.sentence = fromRgb(sentence);\n    colors.verbNormal = fromRgb(verbNormal);\n    colors.verbNormalTint = fromRgb(verbNormalTint);\n    colors.verbHighlight = fromRgb(verbHighlight);\n    colors.verbHighlightTint = fromRgb(verbHighlightTint);\n    colors.dialogNormal = fromRgb(dialogNormal);\n    colors.dialogHighlight = fromRgb(dialogHighlight);\n    colors.inventoryFrame = fromRgb(inventoryFrame);\n    colors.inventoryBackground = fromRgb(inventoryBackground);\n    colors.retroNormal = fromRgb(retroNormal);\n    colors.retroHighlight = fromRgb(retroHighlight);\n    g_pEngine->getHud().setVerbUiColors(static_cast<int>(actorSlot) - 1, colors);\n    return 0;\n  }\n};\n\nEngine *ActorPack::g_pEngine = nullptr;\n\n} // namespace ng\n"
  },
  {
    "path": "src/Scripting/ActorWalk.cpp",
    "content": "#include \"ActorWalk.hpp\"\n#include <engge/Engine/Engine.hpp>\n#include <engge/Entities/Actor.hpp>\n#include <engge/Entities/Costume.hpp>\n#include <engge/Entities/Entity.hpp>\n#include <engge/Engine/Sentence.hpp>\n#include <engge/Engine/Verb.hpp>\n#include <engge/Scripting/ScriptEngine.hpp>\n#include \"Util/Util.hpp\"\n\nnamespace ng {\nActorWalk::ActorWalk(Engine &engine, Actor &actor, Entity *pEntity, Sentence *pSentence, const Verb *pVerb)\n    : m_engine(engine), m_actor(actor), m_pEntity(pEntity), m_pSentence(pSentence), m_pVerb(pVerb) {\n  auto pActor = dynamic_cast<Actor *>(pEntity);\n  auto pos = pEntity->getPosition();\n  auto usePos = pEntity->getUsePosition().value_or(glm::vec2());\n  auto facing = getFacing(pEntity);\n  auto destination = pActor ? pos : pos + usePos;\n  m_path = m_actor.walkTo(destination, facing);\n  int useDist = 0;\n  ScriptEngine::rawGet(pEntity, \"useDist\", useDist);\n  useDist = std::max(useDist, 4);\n  m_isDestination = distance(m_path.back(), destination) <= static_cast<float>(useDist);\n}\n\nFacing ActorWalk::getFacing(const Entity *pEntity) {\n  const auto pActor = dynamic_cast<const Actor *>(pEntity);\n  if (pActor) {\n    return getOppositeFacing(pActor->getCostume().getFacing());\n  }\n  const auto pObj = dynamic_cast<const Object *>(pEntity);\n  return toFacing(pObj->getUseDirection());\n}\n\nbool ActorWalk::isElapsed() {\n  if (m_done)\n    return true;\n  auto isWalking = m_actor.isWalking();\n  if (isWalking)\n    return false;\n\n  m_done = true;\n  auto pos = m_actor.getPosition();\n  if (m_isDestination)\n    return true;\n\n  // to talk to someone, there's no need to reach him\n  if (m_pVerb->id == VerbConstants::VERB_TALKTO)\n    return true;\n\n  m_pSentence->stop();\n  if (m_path.back() != pos)\n    return true;\n\n  if (ScriptEngine::rawExists(m_pEntity, \"verbCantReach\")) {\n    ScriptEngine::objCall(m_pEntity, \"verbCantReach\");\n    return true;\n  }\n  callDefaultObjectVerb();\n  return true;\n}\n\nvoid ActorWalk::callDefaultObjectVerb() {\n  auto &obj = m_engine.getDefaultObject();\n  ScriptEngine::objCall(obj, \"verbCantReach\", m_pEntity, nullptr);\n}\n}"
  },
  {
    "path": "src/Scripting/ActorWalk.hpp",
    "content": "#pragma once\n#include <vector>\n#include <glm/vec2.hpp>\n#include <engge/Engine/Function.hpp>\n#include <engge/Entities/Facing.hpp>\n\nnamespace ng {\nclass Actor;\nclass Engine;\nclass Entity;\nclass Sentence;\nstruct Verb;\n\nclass ActorWalk final : public Function {\npublic:\n  ActorWalk(Engine &engine, Actor &actor, Entity *pEntity, Sentence *pSentence, const Verb *pVerb);\n\nprivate:\n  static Facing getFacing(const Entity *pEntity);\n\nprivate:\n  bool isElapsed() final;\n  void callDefaultObjectVerb();\n\nprivate:\n  Engine &m_engine;\n  Actor &m_actor;\n  Entity *m_pEntity{nullptr};\n  Sentence *m_pSentence{nullptr};\n  const Verb *m_pVerb{nullptr};\n  std::vector<glm::vec2> m_path;\n  bool m_isDestination{false};\n  bool m_done{false};\n};\n}"
  },
  {
    "path": "src/Scripting/BnutPass.hpp",
    "content": "namespace ng {\nstatic unsigned char _bnutPass[] =\n    {\n        0x04, 0x1f, 0x5a, 0xac, 0x5f, 0x79, 0x10, 0xaf, 0x04, 0x1d,\n        0x46, 0x3a, 0x5f, 0x08, 0xee, 0xcb, 0xb5, 0x29, 0x06, 0x2e,\n        0xf9, 0x4b, 0xca, 0x44, 0x5e, 0xb3, 0xac, 0x81, 0xaf, 0x87,\n        0x04, 0x36, 0x60, 0xf4, 0x86, 0x93, 0x62, 0x0d, 0x77, 0x6a,\n        0xba, 0x74, 0x9e, 0xb3, 0xd0, 0xbb, 0xfa, 0xd2, 0x87, 0x87,\n        0x38, 0x9b, 0x10, 0x78, 0xe2, 0x11, 0x7e, 0xcb, 0x57, 0xf1,\n        0x18, 0xbc, 0x7e, 0xf1, 0x71, 0xac, 0x38, 0xc7, 0x38, 0x05,\n        0x99, 0xeb, 0xcf, 0xe0, 0xd6, 0x1b, 0x9d, 0x63, 0xfc, 0xa2,\n        0x23, 0xeb, 0x65, 0x58, 0xcf, 0xee, 0xe9, 0x68, 0x93, 0x9c,\n        0xd7, 0xd4, 0x33, 0x4a, 0xa1, 0xb8, 0x61, 0x8e, 0x59, 0x50,\n        0x8a, 0x29, 0xdf, 0xba, 0x6d, 0xa9, 0xd6, 0x7b, 0x70, 0xc9,\n        0x5b, 0xc2, 0xb1, 0x9e, 0x74, 0x6f, 0xdd, 0x72, 0x48, 0xd1,\n        0xc3, 0x6e, 0x12, 0x32, 0xa7, 0xfa, 0xd6, 0x13, 0x57, 0xe4,\n        0xd1, 0x36, 0xfe, 0x41, 0xb1, 0x5f, 0xba, 0x16, 0x88, 0xd9,\n        0xef, 0xb5, 0x7f, 0xba, 0x58, 0xe8, 0x4d, 0xe6, 0xe2, 0xcf,\n        0x66, 0xd5, 0x37, 0x89, 0xf3, 0x13, 0x1c, 0x94, 0x84, 0x8a,\n        0x7a, 0xf3, 0x86, 0x81, 0x3d, 0x14, 0x75, 0x63, 0xe0, 0x70,\n        0xd1, 0x3f, 0xc3, 0xef, 0xd1, 0x13, 0x42, 0x10, 0xd9, 0xc7,\n        0x85, 0xcb, 0xac, 0xfa, 0x18, 0x34, 0x60, 0x80, 0x39, 0xdf,\n        0x14, 0xa6, 0xf4, 0x06, 0x62, 0x3a, 0xef, 0x6b, 0x96, 0x4d,\n        0x05, 0xfe, 0x9b, 0xb4, 0x94, 0x3e, 0xb9, 0x53, 0x95, 0x5f,\n        0xff, 0x1a, 0x70, 0x2f, 0x80, 0xca, 0x8c, 0xb8, 0x41, 0x7f,\n        0xa8, 0xa4, 0xed, 0xed, 0xeb, 0x63, 0x4d, 0x68, 0xbc, 0x0e,\n        0x79, 0xa5, 0x52, 0x09, 0xce, 0x41, 0x0a, 0x6b, 0x9d, 0x04,\n        0x7b, 0x1d, 0xa8, 0xe5, 0x49, 0xc2, 0x4d, 0xcc, 0xbc, 0x5c,\n        0x7e, 0x1a, 0x0f, 0xab, 0x77, 0xe9, 0x89, 0x53, 0x2e, 0x13,\n        0x4c, 0xc5, 0x88, 0xf3, 0xef, 0xd9, 0x50, 0xec, 0xcd, 0x3d,\n        0xe8, 0xad, 0x1a, 0x91, 0xbb, 0x31, 0xba, 0x4e, 0x79, 0x89,\n        0xd0, 0x6a, 0x00, 0x58, 0x18, 0xbb, 0x1b, 0x21, 0xf4, 0x1e,\n        0xed, 0x43, 0x47, 0x57, 0x2b, 0xbf, 0x04, 0xb6, 0x0c, 0xbf,\n        0x85, 0x7d, 0xff, 0xd6, 0x9c, 0x04, 0x21, 0x07, 0x69, 0x99,\n        0x6c, 0x87, 0xf0, 0x27, 0xaf, 0x41, 0x69, 0x9d, 0x41, 0x1d,\n        0x56, 0x0c, 0x73, 0x00, 0x55, 0x8c, 0xc9, 0x92, 0xb9, 0xe7,\n        0xe7, 0xc1, 0xda, 0xf3, 0x4c, 0x08, 0x27, 0xbe, 0xc1, 0x6e,\n        0x00, 0x6b, 0x8f, 0x50, 0x44, 0xde, 0x72, 0xde, 0xab, 0x19,\n        0x4f, 0x66, 0xd5, 0x64, 0xa8, 0x53, 0x1e, 0x2e, 0xca, 0xf2,\n        0x36, 0xb5, 0xcc, 0xfa, 0x73, 0x67, 0x37, 0xc9, 0xe4, 0x06,\n        0x84, 0x6e, 0x25, 0x8e, 0x49, 0x6a, 0xf4, 0xd5, 0x31, 0x36,\n        0x87, 0xf7, 0xb0, 0x82, 0x9a, 0x6e, 0x72, 0x42, 0x4a, 0x03,\n        0x97, 0x69, 0xa3, 0x68, 0xa0, 0x72, 0xfa, 0xa0, 0x27, 0xa3,\n        0xfb, 0x25, 0x51, 0x0f, 0x81, 0xc8, 0x02, 0x5f, 0x28, 0x55,\n        0xd5, 0x50, 0xa3, 0xfe, 0xc9, 0xfb, 0xcd, 0x74, 0xbc, 0xd7,\n        0x80, 0xd4, 0x98, 0x7e, 0x28, 0x47, 0x4d, 0x32, 0x16, 0x67,\n        0x84, 0x1d, 0x94, 0x63, 0x10, 0x5a, 0xbc, 0xe1, 0x23, 0xb7,\n        0x08, 0xa6, 0x45, 0x36, 0xa8, 0xf7, 0x05, 0x58, 0x96, 0xbc,\n        0x6b, 0x19, 0x6a, 0x68, 0x33, 0xba, 0xed, 0x9b, 0xbb, 0x40,\n        0x6e, 0x84, 0xb7, 0xbf, 0xd7, 0x07, 0xaa, 0x56, 0x7e, 0xa3,\n        0x14, 0xf8, 0xbc, 0x10, 0x6a, 0xf0, 0x3e, 0xa9, 0xc9, 0x21,\n        0x1d, 0x8f, 0x69, 0x10, 0xae, 0x89, 0xd2, 0xa3, 0x1a, 0xac,\n        0xd1, 0xa6, 0xac, 0xbf, 0x27, 0x11, 0xec, 0x5b, 0x06, 0x0a,\n        0x6f, 0xd4, 0x3c, 0xac, 0x6c, 0xda, 0x2b, 0x84, 0x0d, 0xdd,\n        0x7f, 0xdf, 0x8a, 0x34, 0x9e, 0xc5, 0xf6, 0xfd, 0xdd, 0xc3,\n        0xd6, 0xc1, 0x77, 0x6b, 0x76, 0xdf, 0x3d, 0x9b, 0xfb, 0xa5,\n        0x0d, 0x81, 0x37, 0x3c, 0x03, 0x59, 0x3f, 0x4c, 0x71, 0xfc,\n        0xbd, 0x5b, 0x8f, 0x18, 0x05, 0xf4, 0xf1, 0x3e, 0xe8, 0x8c,\n        0xbb, 0xa0, 0x4b, 0x24, 0x96, 0x97, 0x76, 0xac, 0x60, 0xe6,\n        0x2c, 0x2d, 0xa6, 0xc0, 0x7e, 0xa5, 0xd2, 0x89, 0x5f, 0xb0,\n        0x23, 0x5e, 0xf6, 0xeb, 0x5f, 0x56, 0xb6, 0x17, 0x4a, 0x85,\n        0x2e, 0xff, 0xd5, 0xc4, 0x9f, 0x1a, 0x15, 0x32, 0x52, 0xf0,\n        0xf9, 0x79, 0xa7, 0x3c, 0xba, 0xd0, 0xec, 0xd5, 0x10, 0xc3,\n        0xf2, 0x4c, 0x29, 0xb4, 0x60, 0x54, 0x5a, 0x20, 0xc4, 0xe5,\n        0x92, 0xa1, 0x6e, 0x1e, 0x92, 0xb7, 0xfc, 0xee, 0xdd, 0x45,\n        0xb3, 0x71, 0x6f, 0xdc, 0x94, 0x1a, 0x30, 0xba, 0x29, 0x95,\n        0x26, 0x90, 0x22, 0x69, 0x6c, 0x06, 0xa2, 0x5f, 0xe6, 0xfe,\n        0x59, 0xa5, 0xb0, 0x9a, 0x51, 0xb1, 0x5a, 0xff, 0x88, 0xe6,\n        0xd5, 0xd7, 0x42, 0xf8, 0x2a, 0x97, 0x1a, 0x0f, 0xf0, 0x85,\n        0xdc, 0xac, 0x7b, 0x76, 0x15, 0x4e, 0xd4, 0x5a, 0x66, 0xd4,\n        0x6b, 0x78, 0x9c, 0xa0, 0x8d, 0x79, 0x7f, 0x7f, 0x96, 0x26,\n        0x6d, 0x4b, 0xe5, 0xf0, 0xa5, 0x4c, 0x93, 0x33, 0x63, 0x62,\n        0xe3, 0x38, 0xaf, 0xe4, 0x77, 0xff, 0xf4, 0x45, 0x47, 0xb9,\n        0x53, 0x7a, 0x51, 0x17, 0xb4, 0x1e, 0x10, 0x44, 0xa1, 0x51,\n        0xad, 0xb2, 0xd1, 0x64, 0xf6, 0x98, 0x85, 0x37, 0x12, 0x36,\n        0x95, 0x5c, 0xf0, 0xde, 0x49, 0x02, 0x83, 0xb2, 0xe8, 0x94,\n        0xb0, 0x2c, 0x10, 0x1a, 0x01, 0x61, 0xcb, 0x66, 0x21, 0x05,\n        0x5d, 0xef, 0x08, 0x2d, 0xdd, 0x7b, 0xf0, 0xd7, 0x8a, 0x7e,\n        0x0e, 0x2a, 0xda, 0x45, 0x00, 0x7c, 0x51, 0xd1, 0x07, 0x17,\n        0x17, 0x83, 0xf4, 0xba, 0x47, 0x7c, 0xe3, 0xe0, 0x07, 0xc1,\n        0xa9, 0xc3, 0x5c, 0x21, 0x0e, 0x1f, 0xb9, 0xd6, 0xba, 0xb6,\n        0x5c, 0xec, 0xef, 0x96, 0x58, 0x64, 0xfa, 0x1c, 0x71, 0x17,\n        0x6a, 0xb6, 0xaa, 0x5b, 0xfd, 0x6b, 0x9e, 0x67, 0x5e, 0x1b,\n        0x92, 0x77, 0x90, 0x86, 0x45, 0xae, 0x27, 0x0e, 0x8e, 0xbd,\n        0x3c, 0x3b, 0xa3, 0x47, 0x1d, 0x02, 0x38, 0x02, 0xc7, 0xc4,\n        0x4f, 0x9d, 0x14, 0x17, 0xc9, 0x64, 0xb3, 0x47, 0xbf, 0xa5,\n        0xda, 0x9b, 0x92, 0xcf, 0xbd, 0x57, 0xc2, 0x5e, 0xbc, 0x83,\n        0x82, 0x7a, 0x5f, 0x70, 0x07, 0x58, 0x02, 0xf6, 0xa3, 0x67,\n        0x4e, 0x7e, 0x94, 0x2b, 0x6e, 0xc3, 0x9c, 0xe6, 0xfd, 0x57,\n        0x50, 0xfb, 0xc0, 0xe6, 0x30, 0x12, 0x18, 0x3c, 0x7a, 0xfb,\n        0x35, 0x07, 0xbe, 0x53, 0x0a, 0x5c, 0x2f, 0xe7, 0x03, 0xfb,\n        0xbf, 0xda, 0x78, 0x51, 0xe9, 0x88, 0xdf, 0x41, 0x4b, 0x28,\n        0xc3, 0xa1, 0xfa, 0x34, 0x77, 0x86, 0x94, 0x88, 0x8a, 0x3f,\n        0x15, 0x4b, 0xf9, 0x21, 0x69, 0x90, 0x26, 0x07, 0xc5, 0xbb,\n        0x8a, 0x97, 0xb5, 0xa4, 0x2c, 0x46, 0xf4, 0x7d, 0xcf, 0x19,\n        0xfe, 0x73, 0xee, 0x2f, 0x65, 0x16, 0x68, 0x01, 0xe6, 0x78,\n        0xfa, 0x67, 0x3b, 0x17, 0x70, 0x59, 0xad, 0x7b, 0x9a, 0x7a,\n        0x70, 0x9d, 0xfe, 0x54, 0xad, 0x0d, 0x52, 0x63, 0x5e, 0xd2,\n        0xa7, 0xd3, 0xdd, 0x0f, 0x65, 0x08, 0x3a, 0x6a, 0xfa, 0xe1,\n        0x4e, 0x2c, 0x51, 0xbc, 0x93, 0x26, 0x03, 0x37, 0xb1, 0x5a,\n        0x4e, 0xbb, 0xd7, 0x55, 0xc8, 0xb9, 0xcf, 0x5d, 0xd3, 0xb2,\n        0xcf, 0x4e, 0xcf, 0xf7, 0x0f, 0x43, 0x11, 0x34, 0x1f, 0xf7,\n        0x96, 0xae, 0xf4, 0xe9, 0x76, 0x46, 0xc7, 0x42, 0x19, 0x44,\n        0x9d, 0x75, 0x2b, 0xd4, 0xa4, 0xaa, 0x50, 0x4f, 0x43, 0xdb,\n        0x96, 0x3a, 0xef, 0xba, 0xae, 0x0e, 0xbe, 0x59, 0xd9, 0xbc,\n        0xbd, 0x87, 0xa3, 0xee, 0x00, 0xfa, 0x51, 0x0d, 0x7d, 0x31,\n        0x1a, 0x07, 0x98, 0x16, 0x18, 0xcc, 0x7d, 0x65, 0xfc, 0x9c,\n        0x31, 0xd0, 0x84, 0x03, 0x66, 0xde, 0xac, 0x9f, 0x11, 0x96,\n        0xa6, 0xa6, 0xbc, 0xe0, 0x89, 0x2a, 0x9a, 0xa5, 0xcb, 0x1a,\n        0x5f, 0xbb, 0x70, 0x07, 0xcc, 0x83, 0xfe, 0xab, 0x0c, 0x4e,\n        0x37, 0x2a, 0xc1, 0x83, 0x84, 0x15, 0xdc, 0x81, 0x32, 0x32,\n        0x2f, 0x45, 0x5f, 0xfc, 0xc3, 0xca, 0xb1, 0xeb, 0xea, 0x33,\n        0xcc, 0x74, 0x13, 0xa9, 0x80, 0xce, 0x60, 0x05, 0xc4, 0x7a,\n        0xf7, 0x2d, 0x66, 0x80, 0x1b, 0x3d, 0x7f, 0x78, 0xf9, 0x6d,\n        0xa7, 0x4f, 0x42, 0xac, 0xec, 0xc5, 0x7c, 0x0e, 0x82, 0xb8,\n        0x18, 0xec, 0x3a, 0x23, 0x42, 0xc3, 0xb4, 0xe4, 0x7b, 0xe3,\n        0x53, 0x3f, 0xe7, 0xc9, 0xf3, 0x26, 0x66, 0x46, 0x5c, 0x35,\n        0x64, 0x67, 0x74, 0x7e, 0x70, 0x14, 0x36, 0x09, 0x8e, 0x74,\n        0x65, 0x19, 0x4b, 0x17, 0x00, 0x2f, 0x94, 0xd1, 0x73, 0xcf,\n        0x46, 0x66, 0x92, 0x04, 0x85, 0xeb, 0x46, 0xa4, 0xcc, 0xe6,\n        0x03, 0x53, 0xc7, 0x3a, 0x00, 0x48, 0xe3, 0xc4, 0x24, 0xd1,\n        0xa1, 0xc4, 0xc1, 0x96, 0xad, 0xfd, 0x03, 0xa0, 0xb2, 0x9a,\n        0x26, 0x19, 0xea, 0xd6, 0x6a, 0xd0, 0x77, 0x5a, 0xc6, 0x82,\n        0x74, 0x64, 0x5d, 0xda, 0xc9, 0xac, 0xb3, 0x33, 0xc1, 0x06,\n        0x9f, 0x23, 0x5c, 0xc5, 0xff, 0xb8, 0x65, 0xe5, 0x2d, 0x7f,\n        0x42, 0xe7, 0x34, 0x48, 0x8d, 0x7b, 0xc2, 0xab, 0x66, 0xdf,\n        0xdb, 0x49, 0x85, 0x09, 0x51, 0xd2, 0x11, 0x86, 0xf6, 0xc9,\n        0x33, 0x1f, 0x8e, 0x09, 0x69, 0x41, 0x86, 0x06, 0x9a, 0x19,\n        0x66, 0xd3, 0xed, 0x80, 0x06, 0xe6, 0x58, 0x9c, 0x82, 0x9d,\n        0xfa, 0x42, 0xee, 0x80, 0x29, 0x1d, 0xc8, 0x43, 0x49, 0x8f,\n        0x31, 0x91, 0x61, 0x5a, 0xda, 0x8a, 0x6e, 0xfd, 0xbf, 0x07,\n        0x76, 0xdf, 0x95, 0xa4, 0x5b, 0x2d, 0x03, 0x7b, 0x74, 0x82,\n        0x93, 0xaf, 0xdb, 0x4b, 0x66, 0xae, 0x86, 0xe7, 0xa9, 0x36,\n        0x17, 0x91, 0xcb, 0x13, 0x74, 0xfd, 0x6a, 0xae, 0x15, 0xc4,\n        0x11, 0x46, 0x1f, 0x7f, 0xa2, 0xfa, 0x34, 0xb5, 0x94, 0x8d,\n        0x07, 0x75, 0xdc, 0xe8, 0xb1, 0xc1, 0xac, 0x5e, 0xc5, 0xb0,\n        0xdd, 0xb1, 0x25, 0x52, 0x2c, 0xd8, 0x92, 0x51, 0x27, 0x7d,\n        0x04, 0x5c, 0xe4, 0x48, 0xbe, 0x43, 0x76, 0xdd, 0x20, 0xe1,\n        0x20, 0xa5, 0x3a, 0xbc, 0x46, 0x4f, 0x24, 0x6d, 0x27, 0x15,\n        0x0f, 0xc0, 0x4b, 0xbe, 0x19, 0x9a, 0xbd, 0x66, 0xe4, 0x9e,\n        0xf8, 0x00, 0xe4, 0x8e, 0xa1, 0x96, 0x7b, 0x71, 0xf9, 0x56,\n        0xc6, 0x78, 0x0f, 0x4c, 0x35, 0xa0, 0xb8, 0xef, 0xdb, 0x17,\n        0x3f, 0x5c, 0x8a, 0x5e, 0xdc, 0x64, 0x9c, 0x33, 0xe5, 0x47,\n        0x92, 0x2b, 0xc5, 0x3d, 0x5e, 0x21, 0xaf, 0xb9, 0x7f, 0x52,\n        0x11, 0x6b, 0xd0, 0x43, 0xca, 0x09, 0x20, 0x69, 0x1b, 0xcd,\n        0x80, 0x86, 0x5d, 0xbc, 0x5f, 0xd3, 0x77, 0xac, 0x57, 0xe3,\n        0x0c, 0x02, 0xc3, 0x41, 0x77, 0x3e, 0x18, 0xde, 0x77, 0x38,\n        0xf0, 0x2d, 0xa9, 0x26, 0xe5, 0x0a, 0xb8, 0x64, 0x22, 0x5e,\n        0x56, 0xf2, 0xba, 0x83, 0xe9, 0xbc, 0xb6, 0x67, 0x04, 0x9c,\n        0xf0, 0x72, 0x9b, 0x1f, 0xa1, 0x28, 0xf5, 0x0a, 0xbb, 0x8d,\n        0x60, 0x9b, 0xf7, 0x4b, 0xa6, 0x8e, 0xac, 0x95, 0x42, 0xe5,\n        0x65, 0xc8, 0x51, 0x67, 0x30, 0xd6, 0x4a, 0xe4, 0xb7, 0x62,\n        0x6c, 0x3e, 0x10, 0xaa, 0xfa, 0x27, 0x53, 0x27, 0x28, 0xa9,\n        0xef, 0xf6, 0xd2, 0x6a, 0xbc, 0xf4, 0xf2, 0xac, 0xcf, 0xab,\n        0xcf, 0x15, 0x10, 0xef, 0xf5, 0x33, 0x8c, 0x46, 0xe8, 0xbc,\n        0x8a, 0x0b, 0x96, 0x99, 0x5f, 0x51, 0x90, 0xa0, 0x01, 0x87,\n        0xf7, 0x24, 0x5c, 0xe0, 0x36, 0x2d, 0x67, 0x70, 0x75, 0x86,\n        0xf4, 0x15, 0xc8, 0x7b, 0x4b, 0x1a, 0x2a, 0x5e, 0x74, 0x9c,\n        0x2c, 0xcd, 0x57, 0xab, 0x6b, 0xb5, 0x85, 0x2f, 0xc5, 0x14,\n        0xd2, 0x90, 0x4a, 0x81, 0xaa, 0x14, 0xf4, 0x6d, 0x20, 0x06,\n        0x16, 0x26, 0xc5, 0x9a, 0x94, 0x9e, 0x3d, 0x92, 0xd6, 0xf0,\n        0x92, 0xa0, 0x7d, 0x9d, 0x46, 0x89, 0xd2, 0x9a, 0x2a, 0x0e,\n        0x02, 0x0a, 0xf0, 0x8a, 0x0a, 0xca, 0x81, 0x59, 0x73, 0xb0,\n        0x0e, 0xff, 0xbd, 0x92, 0xe8, 0x04, 0x9b, 0x08, 0x10, 0x9f,\n        0xe4, 0xf1, 0x8c, 0x19, 0x43, 0xb6, 0x7f, 0xef, 0xb4, 0x50,\n        0xf5, 0xb4, 0xae, 0x0a, 0x81, 0xbc, 0x1f, 0x06, 0x89, 0x79,\n        0x1b, 0x80, 0x5b, 0xa2, 0x53, 0xd4, 0x06, 0x18, 0x46, 0x41,\n        0xea, 0x89, 0x39, 0x6a, 0x0b, 0xd0, 0xe7, 0x9f, 0x29, 0x22,\n        0xf8, 0xe0, 0x90, 0xea, 0x32, 0x9d, 0xaf, 0x6f, 0x70, 0x3d,\n        0x69, 0x3a, 0x55, 0x64, 0x2e, 0x38, 0xbf, 0xf4, 0xc8, 0xa1,\n        0xfd, 0xcf, 0xf5, 0x97, 0xbf, 0x61, 0xb8, 0x8d, 0xd1, 0xe1,\n        0x6e, 0x6d, 0x86, 0x51, 0xa2, 0x77, 0xf5, 0x49, 0xa0, 0xea,\n        0xe5, 0x77, 0xcb, 0x64, 0x88, 0xe5, 0xae, 0x09, 0xea, 0xf8,\n        0xd4, 0x65, 0x27, 0x3c, 0x57, 0x12, 0x5e, 0xe0, 0x39, 0x18,\n        0x68, 0x02, 0x74, 0x16, 0x47, 0xab, 0xd3, 0x25, 0x5f, 0x98,\n        0x7e, 0x76, 0x67, 0xbd, 0x56, 0xc1, 0x1d, 0x89, 0x05, 0x5d,\n        0xbb, 0xea, 0xd3, 0x2e, 0x2c, 0x0e, 0x39, 0x41, 0xfd, 0xee,\n        0x37, 0x38, 0x14, 0x8b, 0x65, 0x66, 0x22, 0xf6, 0xca, 0xb9,\n        0xd9, 0x11, 0x6f, 0x5b, 0xdd, 0x16, 0xb1, 0x17, 0x7b, 0xda,\n        0x59, 0x7b, 0x1b, 0xd0, 0x6d, 0xc1, 0x74, 0xcf, 0xc3, 0x6e,\n        0x84, 0x94, 0x5a, 0xb6, 0x3e, 0x05, 0x67, 0xa5, 0x00, 0x3a,\n        0x31, 0xfe, 0xcb, 0x3c, 0x9c, 0xe1, 0x30, 0x8a, 0x86, 0x2e,\n        0x0a, 0x5f, 0xd4, 0xac, 0xf1, 0xb4, 0x4a, 0xe9, 0x69, 0x06,\n        0x1e, 0xde, 0xdc, 0xd8, 0x4a, 0x59, 0x4d, 0xf7, 0xa4, 0x1a,\n        0xc8, 0x80, 0xae, 0xba, 0x9b, 0xa1, 0x2d, 0x4f, 0x47, 0x21,\n        0x7b, 0xd0, 0x33, 0xa0, 0x9c, 0x38, 0x25, 0x9d, 0x12, 0x6c,\n        0x70, 0x3c, 0x70, 0xdc, 0xed, 0xc4, 0xaf, 0xeb, 0xaa, 0xe9,\n        0x42, 0x0e, 0x63, 0xce, 0xea, 0xb6, 0xb4, 0xc8, 0x4a, 0xee,\n        0x0a, 0xe3, 0x3a, 0xc3, 0x5e, 0x25, 0xdb, 0x66, 0xa0, 0x94,\n        0x6d, 0x13, 0xf3, 0xf7, 0xe2, 0xae, 0x9d, 0x5f, 0x31, 0x32,\n        0xbc, 0x64, 0x6a, 0xc9, 0xb8, 0x2e, 0x8e, 0xba, 0x7b, 0x3a,\n        0x1b, 0x06, 0x62, 0xd8, 0x69, 0xd0, 0xf1, 0x76, 0xb7, 0x7f,\n        0x49, 0x9f, 0x03, 0xa5, 0x5a, 0xc1, 0x9c, 0x9d, 0xd6, 0xb1,\n        0x77, 0xf6, 0xeb, 0xee, 0x45, 0x93, 0xb0, 0xa7, 0x40, 0x8d,\n        0x5b, 0x7e, 0xc8, 0xde, 0x37, 0x09, 0xb1, 0xbe, 0x57, 0x1c,\n        0x59, 0xcb, 0x09, 0xc8, 0x7b, 0xeb, 0x0b, 0x21, 0xc6, 0xf1,\n        0x80, 0xc2, 0x2b, 0x01, 0xa0, 0x11, 0xf9, 0xb3, 0x32, 0x42,\n        0xa9, 0xf8, 0xb9, 0x1c, 0x79, 0xbf, 0x70, 0x7d, 0xba, 0x56,\n        0xf5, 0x9e, 0xe9, 0x92, 0xc7, 0x16, 0x7f, 0xad, 0x71, 0x9f,\n        0x87, 0xf1, 0x82, 0x9b, 0xf4, 0x19, 0x43, 0x54, 0xaf, 0x71,\n        0x26, 0x05, 0x71, 0xc3, 0xff, 0x9c, 0x56, 0xf1, 0xf5, 0x3c,\n        0x2c, 0x60, 0x36, 0x84, 0x8f, 0x1b, 0x6c, 0x91, 0xb6, 0xb3,\n        0xf2, 0xc3, 0x09, 0xe6, 0xc5, 0x42, 0x79, 0x06, 0x3b, 0x3f,\n        0x8f, 0x17, 0x75, 0xfa, 0x40, 0xb5, 0x95, 0x86, 0x87, 0xbb,\n        0xaf, 0x4e, 0xb0, 0xa4, 0x7f, 0x56, 0x73, 0xaf, 0xdf, 0x41,\n        0xc7, 0xc4, 0xf6, 0x16, 0x73, 0x18, 0x30, 0xc1, 0x64, 0x92,\n        0xf0, 0x5a, 0xc1, 0xeb, 0x06, 0x28, 0xbf, 0x97, 0xe2, 0x63,\n        0x33, 0x66, 0x85, 0xbc, 0xec, 0xe9, 0x3a, 0x9c, 0xbd, 0x95,\n        0x08, 0x2f, 0x5c, 0xa9, 0xe5, 0x1e, 0xed, 0xcf, 0xab, 0x1f,\n        0x5b, 0x83, 0xcb, 0x2e, 0x6d, 0x36, 0xc2, 0x97, 0x93, 0x31,\n        0x4e, 0xba, 0x84, 0x3a, 0x5f, 0x8c, 0x88, 0xf8, 0xcf, 0xdf,\n        0x95, 0x16, 0xd0, 0x61, 0x1b, 0x29, 0x28, 0x65, 0x9e, 0x52,\n        0x1f, 0x64, 0x08, 0xa2, 0x33, 0x41, 0xbb, 0x3f, 0x90, 0x4f,\n        0x67, 0x4a, 0x42, 0x13, 0xa1, 0x7f, 0x26, 0xc8, 0x2e, 0x99,\n        0xa4, 0xa6, 0x23, 0x7a, 0x1f, 0xe1, 0xad, 0x0e, 0x27, 0x72,\n        0xb0, 0xea, 0x73, 0x98, 0x11, 0xb6, 0x90, 0x1d, 0xd2, 0x50,\n        0x59, 0x58, 0xe2, 0xac, 0x25, 0xf6, 0xb1, 0x7c, 0xc2, 0x77,\n        0x85, 0x93, 0x24, 0x78, 0x8e, 0x09, 0xdb, 0xb6, 0xbb, 0x1d,\n        0x49, 0xce, 0x49, 0xde, 0x90, 0xc4, 0x1f, 0x88, 0x4c, 0x49,\n        0xdc, 0xaf, 0x04, 0xbb, 0xac, 0x1c, 0x60, 0xeb, 0xdd, 0x7a,\n        0x1a, 0xa1, 0x35, 0xaf, 0xb5, 0xe0, 0x00, 0x0a, 0xef, 0xe8,\n        0xeb, 0x21, 0xf6, 0xff, 0x93, 0x77, 0x5d, 0xef, 0xdb, 0xe0,\n        0xcc, 0x4d, 0x00, 0xa4, 0x79, 0x7f, 0x6d, 0x65, 0x5a, 0x7a,\n        0x4e, 0xc0, 0x16, 0x4e, 0xe6, 0xb5, 0xbf, 0x63, 0xa0, 0xc6,\n        0x40, 0x80, 0xe6, 0xe0, 0x97, 0x8f, 0xb4, 0xfd, 0xc2, 0x21,\n        0xeb, 0x86, 0x7a, 0xb2, 0x65, 0x78, 0xa1, 0xac, 0xcc, 0x4d,\n        0x7b, 0x2c, 0x2a, 0x97, 0x9f, 0x87, 0x3f, 0x6c, 0xaa, 0x8a,\n        0x95, 0x85, 0xb9, 0x84, 0x54, 0x24, 0x93, 0x04, 0xd5, 0xb8,\n        0xa8, 0x62, 0xf8, 0x41, 0xbd, 0xfe, 0x35, 0x73, 0x64, 0x4a,\n        0x73, 0x9d, 0x2c, 0x88, 0x9a, 0x47, 0x9c, 0x53, 0xea, 0x9d,\n        0xdf, 0xde, 0x09, 0x8e, 0x3f, 0xfe, 0xdd, 0xb2, 0x53, 0xe8,\n        0x1f, 0xef, 0xf7, 0xba, 0xaa, 0xda, 0xfe, 0xbb, 0x96, 0xdd,\n        0xa8, 0x61, 0x08, 0x1c, 0xd5, 0x16, 0xc7, 0x18, 0xf6, 0xb9,\n        0x8d, 0x10, 0xc6, 0xe6, 0x22, 0x2a, 0xbc, 0xf5, 0x29, 0x55,\n        0x3e, 0xc2, 0xb8, 0xeb, 0x96, 0x32, 0xa9, 0x18, 0xa4, 0x70,\n        0xb2, 0xfd, 0x58, 0xfa, 0x35, 0x94, 0xdc, 0x5e, 0xd7, 0x51,\n        0x94, 0xc4, 0xd2, 0x8c, 0xc6, 0x2a, 0x0a, 0xa1, 0x18, 0x71,\n        0xe0, 0xd3, 0xbd, 0x1b, 0xc9, 0xf3, 0x6d, 0xd0, 0x9d, 0xc5,\n        0x18, 0xa5, 0xaf, 0x1d, 0x59, 0x1b, 0xa0, 0xcb, 0xac, 0xe9,\n        0xf3, 0x3b, 0x5e, 0x79, 0x5f, 0xda, 0x47, 0x32, 0xe7, 0x3a,\n        0x39, 0x7a, 0xaa, 0xf5, 0x37, 0x79, 0x7a, 0x51, 0x65, 0x9e,\n        0x2e, 0xa6, 0xc1, 0xe2, 0xb6, 0x82, 0x95, 0xce, 0xf3, 0x89,\n        0xaa, 0x3d, 0x43, 0x1e, 0x3d, 0xe1, 0xdd, 0xc2, 0xb2, 0x87,\n        0xe2, 0x3e, 0x0a, 0x19, 0x2f, 0x82, 0x14, 0x66, 0xf3, 0x4b,\n        0x65, 0xa3, 0x03, 0x86, 0x08, 0xb0, 0xef, 0x77, 0xf4, 0x1a,\n        0xd4, 0x98, 0x41, 0xe4, 0xef, 0x41, 0x19, 0x05, 0xf5, 0x0c,\n        0x6e, 0xaf, 0x23, 0xf5, 0x70, 0x54, 0x17, 0x43, 0xbd, 0x69,\n        0x5c, 0x29, 0x55, 0xe7, 0xc6, 0x2b, 0x54, 0x96, 0x83, 0x42,\n        0x5d, 0x08, 0xec, 0xbe, 0xd6, 0x65, 0x1f, 0xed, 0xd8, 0xec,\n        0x4d, 0x7f, 0xe4, 0x34, 0xd2, 0xa6, 0x56, 0x35, 0x09, 0x00,\n        0x99, 0x0a, 0xdd, 0x35, 0x1e, 0x73, 0x1e, 0x5e, 0x0d, 0x1b,\n        0x98, 0x2c, 0xb8, 0x9e, 0xe3, 0xc3, 0xd3, 0x48, 0xfa, 0x6a,\n        0x65, 0x9e, 0x8e, 0xe4, 0x7b, 0x9d, 0x17, 0x9a, 0xa1, 0xc3,\n        0xaf, 0x81, 0x11, 0xd1, 0x9d, 0xb5, 0xa8, 0x4d, 0xb2, 0xe7,\n        0x9c, 0xca, 0x57, 0x7c, 0xee, 0xe6, 0x61, 0x71, 0xa0, 0x16,\n        0xaa, 0xff, 0xa5, 0x23, 0x60, 0x02, 0x9c, 0x72, 0x1a, 0x19,\n        0x3b, 0x07, 0xaf, 0x8d, 0x8c, 0x47, 0xc6, 0xf2, 0xda, 0x7f,\n        0x2c, 0x8e, 0x68, 0x28, 0xe8, 0x7b, 0xe6, 0xe7, 0x0e, 0x8e,\n        0xa3, 0x55, 0x56, 0xf5, 0x82, 0x83, 0x6b, 0xa2, 0xae, 0x3b,\n        0x03, 0x6b, 0x0c, 0x07, 0xb3, 0xed, 0x73, 0xf2, 0x7f, 0x33,\n        0x9c, 0x10, 0x32, 0x1a, 0xda, 0xbe, 0x73, 0x71, 0x89, 0xa9,\n        0x92, 0xe2, 0x47, 0x8f, 0x26, 0x94, 0xe4, 0xc7, 0x57, 0x8c,\n        0x19, 0x81, 0xfa, 0xd7, 0xfb, 0xcd, 0x61, 0x68, 0x2d, 0x5c,\n        0xef, 0xc1, 0xd7, 0x08, 0x6e, 0x53, 0x59, 0x15, 0x1f, 0xa6,\n        0xbe, 0x34, 0x95, 0x37, 0xf2, 0x4b, 0x41, 0x23, 0xb2, 0xf6,\n        0xcc, 0x88, 0x46, 0xcb, 0x27, 0xa6, 0xf0, 0x60, 0x63, 0xc8,\n        0x22, 0x0c, 0x40, 0xe4, 0x72, 0x70, 0x86, 0x03, 0x4e, 0xb4,\n        0x16, 0x61, 0x6e, 0x90, 0xbf, 0x53, 0x0c, 0x11, 0xd1, 0xec,\n        0xd5, 0x18, 0x72, 0x5d, 0x9c, 0xa1, 0xb2, 0x1f, 0xd4, 0xc8,\n        0x5f, 0xd2, 0xbb, 0x8a, 0x98, 0xe3, 0x56, 0x4e, 0x23, 0xf0,\n        0x20, 0x23, 0x7f, 0xeb, 0x80, 0xc6, 0xb8, 0xff, 0xfd, 0x69,\n        0xfc, 0x34, 0x33, 0x35, 0xf0, 0xd4, 0x84, 0x8b, 0xc3, 0x8c,\n        0x8e, 0x0d, 0xfe, 0x51, 0x60, 0x5f, 0x21, 0x08, 0x6a, 0xac,\n        0xee, 0xe3, 0x37, 0xea, 0x82, 0x8b, 0xdc, 0xdd, 0x27, 0x02,\n        0x2f, 0xdc, 0xeb, 0x46, 0xb7, 0x55, 0xf0, 0xb5, 0x65, 0x11,\n        0x81, 0x33, 0x07, 0x37, 0xe8, 0x0b, 0x77, 0x11, 0x01, 0x98,\n        0x97, 0x91, 0x8d, 0xa3, 0xfc, 0x91, 0x46, 0x8b, 0x6b, 0xdd,\n        0xb6, 0x26, 0x07, 0xf1, 0xc7, 0x68, 0x47, 0x81, 0x19, 0xc7,\n        0xa8, 0xbc, 0x16, 0x5c, 0x26, 0x4f, 0xc5, 0xca, 0x6b, 0x2a,\n        0x61, 0xde, 0xc4, 0x05, 0xa9, 0xfa, 0xd6, 0xa1, 0xf5, 0x31,\n        0x15, 0xce, 0x0c, 0x30, 0xef, 0x2f, 0xb6, 0xe3, 0xcb, 0xbf,\n        0x12, 0xd3, 0xb4, 0x12, 0xa8, 0x51, 0xd4, 0x5b, 0x3d, 0x53,\n        0xa1, 0x31, 0x6a, 0x20, 0xd9, 0x10, 0xea, 0xad, 0x2e, 0xa1,\n        0xb5, 0xc5, 0xc0, 0xb8, 0xd0, 0xeb, 0x4e, 0x21, 0xe1, 0xff,\n        0x2b, 0x19, 0x85, 0xa1, 0xf2, 0x9d, 0x61, 0x58, 0xf8, 0x65,\n        0xf8, 0x71, 0x83, 0xae, 0x42, 0xa7, 0xbf, 0xbb, 0xf8, 0x87,\n        0x6b, 0x19, 0xb0, 0x91, 0x57, 0xa4, 0xac, 0x1d, 0x8d, 0x4c,\n        0x70, 0x03, 0x50, 0x96, 0x18, 0xf8, 0xc9, 0xe4, 0x67, 0xb9,\n        0x7a, 0x75, 0x9e, 0xea, 0x79, 0x2a, 0x12, 0xbb, 0x5d, 0x0d,\n        0x7b, 0x4e, 0xf6, 0x91, 0x0c, 0xdb, 0xbf, 0x99, 0x46, 0x8f,\n        0x14, 0x39, 0x8b, 0x38, 0x22, 0x3f, 0x75, 0xa2, 0xa1, 0x6f,\n        0xe3, 0xbe, 0x43, 0x91, 0xd7, 0x87, 0xea, 0x2b, 0x02, 0xa3,\n        0x9c, 0x0d, 0x1b, 0xcb, 0x36, 0x91, 0xf2, 0xeb, 0xe2, 0x9e,\n        0x47, 0x09, 0x49, 0x71, 0x5a, 0xe6, 0x88, 0x1a, 0x42, 0x64,\n        0xe3, 0xc7, 0xfd, 0xad, 0x3a, 0xc2, 0x4b, 0x0f, 0x3e, 0x3b,\n        0x3a, 0xa8, 0x63, 0xc5, 0x7f, 0xc6, 0x94, 0xa2, 0x8a, 0x0b,\n        0xa8, 0xbe, 0x58, 0x52, 0x96, 0x7b, 0x05, 0x54, 0x6a, 0x31,\n        0x28, 0x09, 0xf6, 0x72, 0xde, 0xcf, 0x48, 0x11, 0xa2, 0x4b,\n        0xde, 0xe1, 0xe2, 0x12, 0x9b, 0x3d, 0x51, 0x06, 0x77, 0x4a,\n        0xfc, 0x81, 0xf8, 0xfe, 0x1f, 0x33, 0x63, 0xdf, 0xb4, 0xcb,\n        0xb1, 0x8b, 0xcf, 0x57, 0x43, 0xfa, 0xac, 0x6b, 0x54, 0x85,\n        0x83, 0x03, 0x32, 0xa5, 0x22, 0x28, 0x2b, 0x7b, 0x38, 0x54,\n        0x47, 0x13, 0x71, 0x96, 0xba, 0x67, 0x45, 0x74, 0x17, 0x25,\n        0x8f, 0x93, 0x44, 0x30, 0xdf, 0x17, 0x31, 0xe6, 0x90, 0xca,\n        0x47, 0x26, 0x98, 0xff, 0xa0, 0x0f, 0x21, 0x33, 0xfb, 0x89,\n        0xdb, 0x78, 0x6d, 0x84, 0x0f, 0x91, 0xd7, 0x02, 0x72, 0xdc,\n        0x1a, 0xd5, 0xbe, 0xf3, 0x0c, 0x28, 0x00, 0x10, 0x28, 0xbe,\n        0xb2, 0x34, 0x08, 0xfc, 0x88, 0x06, 0x93, 0xa8, 0x09, 0x7b,\n        0xf4, 0x6e, 0xe4, 0x39, 0x50, 0x25, 0xff, 0xbb, 0x36, 0xd6,\n        0x4e, 0x34, 0xd5, 0x78, 0x69, 0x34, 0xf0, 0x7b, 0xda, 0x0c,\n        0x91, 0x0b, 0x3a, 0xf0, 0x7f, 0x10, 0xfa, 0xe1, 0x70, 0xf6,\n        0x01, 0x47, 0xfd, 0x32, 0xf9, 0x60, 0x59, 0x7f, 0x68, 0x5c,\n        0xc0, 0xeb, 0x81, 0x44, 0xb0, 0x94, 0xb7, 0x9e, 0xd9, 0x32,\n        0x15, 0xd1, 0xd4, 0x53, 0x50, 0x48, 0x95, 0x68, 0x97, 0x57,\n        0xa1, 0x83, 0x30, 0xe1, 0xff, 0xdd, 0xc4, 0xb5, 0xef, 0x19,\n        0x74, 0xbc, 0x5c, 0x49, 0xb3, 0xd3, 0x12, 0xb3, 0xd2, 0x78,\n        0xae, 0x54, 0x59, 0x27, 0x58, 0x20, 0x1b, 0x81, 0x32, 0x0e,\n        0x08, 0x32, 0x8e, 0xd6, 0xc0, 0x8e, 0xe2, 0x77, 0xeb, 0x00,\n        0x7b, 0x7a, 0x4a, 0x22, 0xf3, 0xf8, 0x8c, 0xab, 0x63, 0x5d,\n        0xe0, 0x0b, 0x57, 0xe8, 0x4e, 0xd7, 0x85, 0xf9, 0xc5, 0xe6,\n        0x3d, 0x09, 0xf3, 0x37, 0x9e, 0x77, 0xd7, 0x99, 0x8c, 0x09,\n        0x17, 0x08, 0x64, 0x2c, 0x12, 0xd7, 0x6c, 0x01, 0xb3, 0x91,\n        0x0b, 0x18, 0x0b, 0x9f, 0xbd, 0xf9, 0x9c, 0xa9, 0xc4, 0x66,\n        0x75, 0xbd, 0x9e, 0x61, 0x01, 0x31, 0x39, 0xef, 0x9f, 0x48,\n        0xe7, 0x99, 0xf1, 0x96, 0x12, 0xb7, 0xf3, 0x22, 0xaf, 0x6b,\n        0xd2, 0x50, 0x73, 0x6d, 0x79, 0x7c, 0xc8, 0x8c, 0xeb, 0x65,\n        0x7c, 0xef, 0x52, 0x4f, 0x3d, 0x1f, 0xdb, 0xe6, 0xc8, 0xc4,\n        0x3e, 0xe4, 0xdb, 0x31, 0x1f, 0x71, 0xee, 0xa1, 0x17, 0x4d,\n        0xa5, 0x3e, 0x90, 0xae, 0x03, 0xe5, 0x53, 0xe9, 0x5e, 0xaa,\n        0xe2, 0xd2, 0x16, 0x1d, 0x86, 0xe4, 0x04, 0x49, 0x27, 0x20,\n        0xb2, 0x80, 0xde, 0xb4, 0x4f, 0xd8, 0x4a, 0x62, 0x60, 0x74,\n        0xa5, 0x9e, 0x36, 0x82, 0x94, 0x74, 0x22, 0x07, 0xc2, 0x2f,\n        0x69, 0x5c, 0x2b, 0xba, 0xf9, 0x76, 0x38, 0xc3, 0xd8, 0xe9,\n        0x8e, 0xa4, 0x60, 0xaa, 0xa5, 0x02, 0x2b, 0x97, 0x1a, 0x31,\n        0xce, 0xb6, 0xc4, 0x5d, 0x48, 0x3f, 0x88, 0x69, 0x38, 0x5b,\n        0xec, 0x96, 0xd1, 0xa9, 0x6c, 0xe2, 0x8d, 0x84, 0x8f, 0x35,\n        0xa3, 0x06, 0xb8, 0x3d, 0x39, 0xca, 0xbc, 0x14, 0x58, 0x74,\n        0x37, 0xa6, 0xa3, 0xf1, 0x9d, 0xd4, 0xc6, 0x7e, 0x12, 0x57,\n        0xae, 0x69, 0xfa, 0x65, 0x7d, 0x99, 0x4f, 0x15, 0x3b, 0xce,\n        0xb4, 0x82, 0x4d, 0xa8, 0x4d, 0xb1, 0xa5, 0x69, 0x4b, 0x32,\n        0xbd, 0x79, 0x49, 0x88, 0x44, 0xac, 0x59, 0x49, 0x95, 0x46,\n        0xdc, 0x04, 0xeb, 0xba, 0x14, 0xe5, 0x56, 0x34, 0x7a, 0x19,\n        0x6b, 0xdd, 0xd0, 0xf1, 0xbc, 0xd7, 0xf4, 0xc9, 0x0d, 0x0d,\n        0x7a, 0xa6, 0x43, 0xad, 0xf8, 0xa0, 0x1b, 0x70, 0x1e, 0x05,\n        0x9f, 0x9f, 0x8c, 0x38, 0x58, 0xd4, 0x62, 0x5d, 0x43, 0x83,\n        0x96, 0xb7, 0x83, 0x37, 0x09, 0xcb, 0xdb, 0x9c, 0x57, 0x4c,\n        0xd9, 0x40, 0x71, 0xb5, 0xd1, 0x18, 0xeb, 0xb6, 0x90, 0xc3,\n        0x15, 0x4f, 0xcc, 0x91, 0xcb, 0xbd, 0x5c, 0x41, 0x0c, 0x17,\n        0x2c, 0x8d, 0x4c, 0xb6, 0xee, 0x66, 0x88, 0x58, 0x90, 0xfe,\n        0x1d, 0x03, 0x70, 0x89, 0x58, 0xaa, 0x50, 0xc2, 0xcc, 0x91,\n        0x0a, 0x2f, 0x66, 0x70, 0x03, 0x24, 0x41, 0x59, 0x60, 0x88,\n        0x3a, 0x59, 0xfa, 0x59, 0x42, 0xdf, 0x11, 0xf0, 0x75, 0xe0,\n        0xc3, 0x04, 0xee, 0xb6, 0x3a, 0x70, 0x57, 0xcc, 0xa7, 0xb3,\n        0x42, 0xfa, 0xf1, 0x3b, 0x39, 0xb0, 0x2c, 0x60, 0x97, 0xd4,\n        0xcb, 0x31, 0x14, 0x6b, 0x94, 0xf1, 0x21, 0xfa, 0x57, 0x5f,\n        0xf8, 0xaa, 0x5c, 0xb9, 0x71, 0x2d, 0xa0, 0x7d, 0x96, 0x62,\n        0xbe, 0xf4, 0xf4, 0xb9, 0xae, 0x6f, 0xb6, 0x56, 0x30, 0x4e,\n        0x73, 0xf8, 0x05, 0xc5, 0xc1, 0x97, 0xe3, 0x5d, 0x91, 0xcf,\n        0x25, 0x3b, 0x39, 0xff, 0x44, 0x22, 0x50, 0x2f, 0x09, 0x39,\n        0x3c, 0xb4, 0x7e, 0x8c, 0x8c, 0x95, 0xa8, 0x53, 0x05, 0xab,\n        0xf6, 0xf5, 0x7e, 0x8b, 0x77, 0xca, 0x6b, 0x23, 0xce, 0xa3,\n        0x3a, 0x25, 0xe5, 0x0a, 0x60, 0x26, 0x63, 0x48, 0x31, 0x85,\n        0xde, 0x2a, 0x73, 0x0c, 0xcf, 0x83, 0xb0, 0x57, 0x48, 0x70,\n        0x4e, 0xf7, 0x67, 0x5d, 0x60, 0x55, 0x89, 0xca, 0x39, 0x58,\n        0x3e, 0xcd, 0xc4, 0xc5, 0xff, 0x55, 0x95, 0x68, 0xa0, 0x34,\n        0xbe, 0xf6, 0x86, 0xda, 0x62, 0xb0, 0x98, 0xe1, 0x0a, 0xc7,\n        0xf5, 0x4c, 0xb9, 0x82, 0x6a, 0x8e, 0xc1, 0x20, 0xa1, 0x4c,\n        0x52, 0x7d, 0x1a, 0xe1, 0xd7, 0x76, 0xd9, 0xa5, 0x00, 0x0d,\n        0xe3, 0xed, 0x9d, 0x4c, 0x69, 0xd0, 0x30, 0xe9, 0xc1, 0xae,\n        0x40, 0xac, 0x18, 0x71, 0x6e, 0x93, 0xe8, 0x91, 0x48, 0xb2,\n        0x2a, 0xd8, 0xe0, 0xdb, 0x4a, 0xe9, 0x1b, 0x02, 0xde, 0x81,\n        0xc9, 0x5d, 0x15, 0x7b, 0x77, 0x4d, 0xf0, 0x94, 0x07, 0xfe,\n        0x32, 0xf3, 0xfb, 0xd0, 0x18, 0x66, 0x95, 0x73, 0xc8, 0x6c,\n        0x9f, 0xd4, 0x89, 0xf6, 0x09, 0xba, 0xb7, 0xec, 0x37, 0x2f,\n        0x74, 0x71, 0x17, 0x9f, 0x1d, 0xe6, 0xf5, 0xc1, 0x82, 0xaf,\n        0x0d, 0x38, 0xd5, 0xb7, 0xe4, 0xf8, 0x5d, 0xb3, 0x55, 0x6a,\n        0xf2, 0x29, 0x6d, 0x4d, 0x28, 0x2f, 0xf7, 0x62, 0x48, 0xf3,\n        0xd5, 0xc5, 0x03, 0xfd, 0x14, 0x1c, 0xe4, 0x36, 0xbd, 0x72,\n        0x88, 0xa7, 0x6b, 0xdf, 0x8f, 0x02, 0xa1, 0xef, 0x50, 0xe1,\n        0xd8, 0xbf, 0x4f, 0xcf, 0x59, 0xe7, 0x6f, 0x09, 0xd0, 0x1a,\n        0xe6, 0x04, 0x9c, 0x8e, 0xf3, 0xae, 0xe6, 0x1c, 0x51, 0x74,\n        0x78, 0x26, 0x69, 0x06, 0x4a, 0x3b, 0x4a, 0xdc, 0xdb, 0x7b,\n        0x59, 0x76, 0x44, 0xbb, 0xc7, 0x66, 0x0d, 0x67, 0xc5, 0x0e,\n        0xbd, 0x2b, 0x78, 0x29, 0x33, 0x50, 0xad, 0x0b, 0xb7, 0xe6,\n        0x4d, 0xa7, 0xce, 0xa5, 0x8e, 0x53, 0xd0, 0x93, 0xee, 0x4d,\n        0x3a, 0x65, 0xdf, 0xfc, 0xc3, 0xa6, 0x40, 0xf6, 0x30, 0x98,\n        0x92, 0xc5, 0xe6, 0xdc, 0xe7, 0x69, 0x44, 0xd4, 0x99, 0x9b,\n        0xad, 0xc3, 0xbf, 0xd7, 0x67, 0xb9, 0x5e, 0x16, 0x26, 0x30,\n        0x61, 0x5e, 0x66, 0x75, 0x4a, 0xfa, 0x7b, 0xc7, 0xa5, 0x88,\n        0x69, 0x40, 0x3f, 0xb7, 0x74, 0x77, 0x1a, 0xcc, 0x75, 0xe1,\n        0x1e, 0xe9, 0xf2, 0xfb, 0x8f, 0x0c, 0xeb, 0x28, 0x42, 0xd8,\n        0x74, 0x5a, 0x8e, 0x15, 0x07, 0x72, 0x02, 0xf8, 0x96, 0x67,\n        0xdb, 0x23, 0x61, 0x28, 0x33, 0x6a, 0x8d, 0x42, 0xfa, 0x5a,\n        0x70, 0x40, 0xa4, 0x7a, 0xac, 0xd5, 0xa6, 0x4e, 0x02, 0xbb,\n        0xa1, 0x1f, 0xe2, 0x58, 0x5a, 0x7c, 0xc5, 0x25, 0x71, 0x7e,\n        0x3a, 0xce, 0xcc, 0xcf, 0xc1, 0x18, 0xd7, 0x68, 0x5a, 0x85,\n        0x6d, 0x1c, 0xdb, 0xb9, 0x94, 0xd7, 0x04, 0x9a, 0xeb, 0xa5,\n        0x53, 0x39, 0xe3, 0x75, 0x98, 0x73, 0xb0, 0x9a, 0x47, 0x55,\n        0xfc, 0x15, 0x90, 0x43, 0x60, 0x94, 0x2f, 0xd7, 0x92, 0x38,\n        0x03, 0x8a, 0x5e, 0x18, 0x5f, 0x13, 0x55, 0x89, 0x22, 0x92,\n        0x47, 0x1a, 0x88, 0x6b, 0x71, 0x61, 0xbe, 0xf3, 0x75, 0x77,\n        0x37, 0xcc, 0x0d, 0x44, 0xc0, 0x0f, 0x7e, 0x7a, 0x54, 0x2e,\n        0xcd, 0x62, 0xaf, 0x97, 0xb3, 0x58, 0xa4, 0x18, 0x50, 0x17,\n        0x2e, 0x04, 0xa1, 0xb4, 0x48, 0x19, 0xb2, 0x6b, 0x7c, 0x1f,\n        0x93, 0x1c, 0x3c, 0x50, 0x0b, 0x93, 0xf2, 0x7a, 0x0e, 0x89,\n        0xd8, 0xe5, 0xef, 0x6e, 0x88, 0xf4, 0x54, 0xe3, 0x52, 0x8d,\n        0xec, 0x09, 0x51, 0x39, 0xe2, 0x7b, 0x3a, 0x0b, 0x0f, 0x1b,\n        0xfa, 0x40, 0xf2, 0x8f, 0xfd, 0xa9, 0x5f, 0x8a, 0x4e, 0xcb,\n        0xf9, 0xca, 0x63, 0xc3, 0x60, 0xe4, 0xb5, 0xeb, 0x2a, 0xc1,\n        0x11, 0x3d, 0x92, 0xe7, 0xb1, 0x79, 0xf1, 0x77, 0x08, 0x08,\n        0xef, 0xfa, 0x5f, 0x9e, 0x79, 0xda, 0x24, 0xa1, 0x71, 0xb1,\n        0xfc, 0x4c, 0x26, 0x44, 0x9d, 0x91, 0x89, 0x4d, 0x5e, 0xc2,\n        0x1c, 0xfb, 0x89, 0xee, 0xa9, 0x39};\n}\n"
  },
  {
    "path": "src/Scripting/DefaultScriptExecute.cpp",
    "content": "#include <engge/System/Logger.hpp>\n#include <engge/Engine/EntityManager.hpp>\n#include \"DefaultScriptExecute.hpp\"\n\nnamespace ng {\nvoid DefaultScriptExecute::execute(const std::string &code) {\n  sq_resetobject(&m_result);\n  auto top = sq_gettop(m_vm);\n// compile\n  sq_pushroottable(m_vm);\n  if (SQ_FAILED(sq_compilebuffer(m_vm, code.data(), code.size(), _SC(\"_DefaultScriptExecute\"), SQTrue))) {\n    error(\"Error executing code {}\", code);\n    return;\n  }\n  sq_push(m_vm, -2);\n// call\n  if (SQ_FAILED(sq_call(m_vm, 1, SQTrue, SQTrue))) {\n    error(\"Error calling code {}\", code);\n    return;\n  }\n  sq_getstackobj(m_vm, -1, &m_result);\n  sq_settop(m_vm, top);\n}\n\nbool DefaultScriptExecute::executeCondition(const std::string &code) {\n  std::string c;\n  c.append(\"return \");\n  c.append(code);\n\n  execute(c);\n  if (m_result._type == OT_BOOL) {\n    trace(\"{} returns {}\", code, sq_objtobool(&m_result));\n    return sq_objtobool(&m_result);\n  }\n\n  if (m_result._type == OT_INTEGER) {\n    trace(\"{} return {}\", code, sq_objtointeger(&m_result));\n    return sq_objtointeger(&m_result) != 0;\n  }\n\n  error(\"Error getting result {}\", code);\n  return false;\n}\n\nstd::string DefaultScriptExecute::executeDollar(const std::string &code) {\n  std::string c;\n  c.append(\"return \");\n  c.append(code);\n\n  execute(c);\n// get the result\n  if (m_result._type != OT_STRING) {\n    error(\"Error getting result {}\", code);\n    return \"\";\n  }\n  trace(\"{} returns {}\", code, sq_objtostring(&m_result));\n  return sq_objtostring(&m_result);\n}\n\nSoundDefinition *DefaultScriptExecute::getSoundDefinition(const std::string &name) {\n  auto top = sq_gettop(m_vm);\n  sq_pushroottable(m_vm);\n  sq_pushstring(m_vm, name.data(), -1);\n  sq_get(m_vm, -2);\n\n  auto sound = EntityManager::getSoundDefinition(m_vm, -1);\n  sq_settop(m_vm, top);\n  return sound.get();\n}\n}\n"
  },
  {
    "path": "src/Scripting/DefaultScriptExecute.hpp",
    "content": "#pragma once\n#include <squirrel.h>\n#include \"engge/Scripting/ScriptExecute.hpp\"\n\nnamespace ng {\nclass DefaultScriptExecute final : public ScriptExecute {\npublic:\n  explicit DefaultScriptExecute(HSQUIRRELVM vm) : m_vm(vm) {}\n\npublic:\n  void execute(const std::string &code) override;\n  bool executeCondition(const std::string &code) override;\n  std::string executeDollar(const std::string &code) override;\n  SoundDefinition *getSoundDefinition(const std::string &name) override;\n\nprivate:\n  HSQUIRRELVM m_vm{};\n  HSQOBJECT m_result{};\n};\n}\n"
  },
  {
    "path": "src/Scripting/DefaultVerbExecute.cpp",
    "content": "#include \"DefaultVerbExecute.hpp\"\n#include <engge/Engine/Engine.hpp>\n#include <engge/Engine/Sentence.hpp>\n#include <engge/Scripting/ScriptEngine.hpp>\n#include \"Scripting/ActorWalk.hpp\"\n#include \"Scripting/PostWalk.hpp\"\n#include \"Scripting/ReachAnim.hpp\"\n#include \"Scripting/SetDefaultVerb.hpp\"\n#include \"Scripting/VerbExecuteFunction.hpp\"\n#include \"../Util/Util.hpp\"\n\nnamespace ng {\nDefaultVerbExecute::DefaultVerbExecute(Engine &engine) : m_engine(engine) {}\n\nvoid DefaultVerbExecute::execute(const Verb *pVerb, Entity *pObject1, Entity *pObject2) {\n  getVerb(pObject1, pVerb);\n  if (!pVerb)\n    return;\n\n  // TODO: do it earlier\n  if (pVerb->id == VerbConstants::VERB_TALKTO) {\n    pObject2 = m_engine.getCurrentActor();\n  }\n\n  if (pVerb->id == VerbConstants::VERB_USE && !pObject2 && useFlags(pObject1))\n    return;\n\n  if (pVerb->id == VerbConstants::VERB_GIVE && !pObject2) {\n    m_engine.setUseFlag(UseFlag::GiveTo, pObject1);\n    return;\n  }\n\n  if (callObjectOrActorPreWalk(pVerb->id, pObject1, pObject2))\n    return;\n\n  auto pActor = m_engine.getCurrentActor();\n  if (!pActor)\n    return;\n\n  auto sentence = std::make_unique<Sentence>();\n  auto pObjToWalkTo =\n      (pVerb->id == VerbConstants::VERB_USE || pVerb->id == VerbConstants::VERB_GIVE) ? pObject2 : pObject1;\n  if (needsToWalkTo(pVerb->id, pObjToWalkTo)) {\n    auto walk = std::make_unique<ActorWalk>(m_engine, *pActor, pObjToWalkTo, sentence.get(), pVerb);\n    sentence->push_back(std::move(walk));\n    auto postWalk = std::make_unique<PostWalk>(*sentence, pObject1, pObject2, pVerb->id);\n    sentence->push_back(std::move(postWalk));\n  }\n\n  if (needsReachAnim(pVerb->id)) {\n    if (ScriptEngine::exists(pObject1, pVerb->func.data())) {\n      auto reach = std::make_unique<ReachAnim>(*pActor, pObject1);\n      sentence->push_back(std::move(reach));\n    }\n  }\n\n  auto verb = std::make_unique<VerbExecuteFunction>(m_engine, *pActor, pObject1, pObject2, pVerb);\n  sentence->push_back(std::move(verb));\n  auto setDefaultVerb = std::make_unique<SetDefaultVerb>(m_engine);\n  sentence->push_back(std::move(setDefaultVerb));\n  m_engine.setSentence(std::move(sentence));\n}\n\nbool DefaultVerbExecute::needsToWalkTo(int verbId, Entity *pObj) {\n  if (verbId == VerbConstants::VERB_LOOKAT && isFarLook(pObj))\n    return false;\n  return pObj && !pObj->isInventoryObject();\n}\n\nbool DefaultVerbExecute::needsReachAnim(int verbId) {\n  return verbId == VerbConstants::VERB_PICKUP || verbId == VerbConstants::VERB_OPEN\n      || verbId == VerbConstants::VERB_CLOSE || verbId == VerbConstants::VERB_PUSH\n      || verbId == VerbConstants::VERB_PULL\n      || verbId == VerbConstants::VERB_USE;\n}\n\nbool DefaultVerbExecute::isFarLook(const Entity *pEntity) {\n  auto flags = pEntity->getFlags();\n  return flags & 8u;\n}\n\nbool DefaultVerbExecute::useFlags(Entity *pObject) {\n  auto flags = pObject->getFlags();\n  UseFlag useFlag;\n  if (flags & ObjectFlagConstants::USE_WITH) {\n    useFlag = UseFlag::UseWith;\n  } else if (flags & ObjectFlagConstants::USE_ON) {\n    useFlag = UseFlag::UseOn;\n  } else if (flags & ObjectFlagConstants::USE_IN) {\n    useFlag = UseFlag::UseIn;\n  } else {\n    return false;\n  }\n  m_engine.setUseFlag(useFlag, pObject);\n  return true;\n}\n\nbool DefaultVerbExecute::callObjectOrActorPreWalk(int verb, Entity *pObj1, Entity *pObj2) {\n  auto handled = false;\n  auto pActor = m_engine.getCurrentActor();\n  if (ScriptEngine::rawExists(pActor, \"actorPreWalk\")) {\n    ScriptEngine::callFunc(handled, pActor, \"actorPreWalk\", verb, pObj1, pObj2);\n    if (handled)\n      return true;\n  }\n\n  auto *pObj = dynamic_cast<Object *>(pObj1);\n  auto functionName = pObj ? \"objectPreWalk\" : \"actorPreWalk\";\n  if (ScriptEngine::rawExists(pObj1, functionName)) {\n    ScriptEngine::callFunc(handled, pObj1, functionName, verb, pObj1, pObj2);\n  }\n  return handled;\n}\n\nvoid DefaultVerbExecute::getVerb(Entity *pObj, const Verb *&pVerb) {\n  int verb;\n  if (pVerb) {\n    verb = pVerb->id;\n    pVerb = m_engine.getHud().getVerb(verb);\n    return;\n  }\n  auto defaultVerb = pObj->getDefaultVerb(VerbConstants::VERB_LOOKAT);\n  if (!defaultVerb)\n    return;\n  verb = defaultVerb;\n  pVerb = m_engine.getHud().getVerb(verb);\n}\n}"
  },
  {
    "path": "src/Scripting/DefaultVerbExecute.hpp",
    "content": "#pragma once\n#include <engge/Scripting/VerbExecute.hpp>\n\nnamespace ng {\nclass Engine;\nclass Entity;\n\nclass DefaultVerbExecute final : public VerbExecute {\npublic:\n  explicit DefaultVerbExecute(Engine &engine);\n\nprivate:\n  void execute(const Verb *pVerb, Entity *pObject1, Entity *pObject2) final;\n  static bool needsToWalkTo(int verbId, Entity *pObj);\n  static bool needsReachAnim(int verbId);\n  static bool isFarLook(const Entity *pEntity);\n  bool useFlags(Entity *pObject);\n  bool callObjectOrActorPreWalk(int verb, Entity *pObj1, Entity *pObj2);\n  void getVerb(Entity *pObj, const Verb *&pVerb);\n\nprivate:\n  Engine &m_engine;\n};\n} // namespace ng\n"
  },
  {
    "path": "src/Scripting/GeneralPack.hpp",
    "content": "#pragma once\n#include <string>\n#include <squirrel.h>\n#include \"engge/Dialog/DialogManager.hpp\"\n#include \"engge/Engine/Camera.hpp\"\n#include \"engge/Engine/Cutscene.hpp\"\n#include \"engge/Engine/EngineSettings.hpp\"\n#include \"engge/Engine/Inventory.hpp\"\n#include \"engge/System/Locator.hpp\"\n#include \"engge/Util/RandomNumberGenerator.hpp\"\n\nnamespace ng {\nclass GeneralPack final : public Pack {\nprivate:\n  static Engine *g_pEngine;\n  static unsigned int g_CRCTab[256];\n\nprivate:\n  void registerPack() const override {\n    g_pEngine = &ScriptEngine::getEngine();\n    init_crc32();\n    ScriptEngine::registerGlobalFunction(activeVerb, \"activeVerb\");\n    ScriptEngine::registerGlobalFunction(arrayShuffle, \"arrayShuffle\");\n    ScriptEngine::registerGlobalFunction(assetExists, \"assetExists\");\n    ScriptEngine::registerGlobalFunction(cameraAt, \"cameraAt\");\n    ScriptEngine::registerGlobalFunction(cameraPos, \"cameraPos\");\n    ScriptEngine::registerGlobalFunction(cameraBounds, \"cameraBounds\");\n    ScriptEngine::registerGlobalFunction(cameraFollow, \"cameraFollow\");\n    ScriptEngine::registerGlobalFunction(cameraInRoom, \"cameraInRoom\");\n    ScriptEngine::registerGlobalFunction(cameraPanTo, \"cameraPanTo\");\n    ScriptEngine::registerGlobalFunction(cutscene, \"cutscene\");\n    ScriptEngine::registerGlobalFunction(cutsceneOverride, \"cutsceneOverride\");\n    ScriptEngine::registerGlobalFunction(distance, \"distance\");\n    ScriptEngine::registerGlobalFunction(findScreenPosition, \"findScreenPosition\");\n    ScriptEngine::registerGlobalFunction(frameCounter, \"frameCounter\");\n    ScriptEngine::registerGlobalFunction(in_array, \"in_array\");\n    ScriptEngine::registerGlobalFunction(incutscene, \"incutscene\");\n    ScriptEngine::registerGlobalFunction(indialog, \"indialog\");\n    ScriptEngine::registerGlobalFunction(integer, \"int\");\n    ScriptEngine::registerGlobalFunction(is_array, \"is_array\");\n    ScriptEngine::registerGlobalFunction(is_function, \"is_function\");\n    ScriptEngine::registerGlobalFunction(loadArray, \"loadArray\");\n    ScriptEngine::registerGlobalFunction(markAchievement, \"markAchievement\");\n    ScriptEngine::registerGlobalFunction(markProgress, \"markProgress\");\n    ScriptEngine::registerGlobalFunction(markStat, \"markStat\");\n    ScriptEngine::registerGlobalFunction(random, \"random\");\n    ScriptEngine::registerGlobalFunction(randomFrom, \"randomfrom\");\n    ScriptEngine::registerGlobalFunction(randomOdds, \"randomOdds\");\n    ScriptEngine::registerGlobalFunction(randomOdds, \"randomodds\");\n    ScriptEngine::registerGlobalFunction(randomseed, \"randomseed\");\n    ScriptEngine::registerGlobalFunction(refreshUI, \"refreshUI\");\n    ScriptEngine::registerGlobalFunction(screenSize, \"screenSize\");\n    ScriptEngine::registerGlobalFunction(setVerb, \"setVerb\");\n    ScriptEngine::registerGlobalFunction(startDialog, \"startDialog\");\n    ScriptEngine::registerGlobalFunction(stopSentence, \"stopSentence\");\n    ScriptEngine::registerGlobalFunction(strcount, \"strcount\");\n    ScriptEngine::registerGlobalFunction(strcrc, \"strcrc\");\n    ScriptEngine::registerGlobalFunction(strfind, \"strfind\");\n    ScriptEngine::registerGlobalFunction(strfirst, \"strfirst\");\n    ScriptEngine::registerGlobalFunction(strlast, \"strlast\");\n    ScriptEngine::registerGlobalFunction(strlines, \"strlines\");\n    ScriptEngine::registerGlobalFunction(strreplace, \"strreplace\");\n    ScriptEngine::registerGlobalFunction(strsplit, \"strsplit\");\n    ScriptEngine::registerGlobalFunction(translate, \"translate\");\n  }\n\n  static SQInteger activeVerb(HSQUIRRELVM v) {\n    const auto &pVerb = g_pEngine->getActiveVerb();\n    if (!pVerb) {\n      sq_pushinteger(v, 0);\n      return 1;\n    }\n\n    sq_pushinteger(v, pVerb->id);\n    return 1;\n  }\n\n  static void _shuffle(SQArray &array) {\n    auto &rng = Locator<RandomNumberGenerator>::get();\n    for (long i = array.Size() - 1; i > 0; i--) {\n      auto j = rng.generateLong(0, i);\n      auto x = array._values[i];\n      array._values[i] = array._values[j];\n      array._values[j] = x;\n    }\n  }\n\n  static SQInteger arrayShuffle(HSQUIRRELVM v) {\n    if (sq_gettype(v, 2) != OT_ARRAY) {\n      return sq_throwerror(v, \"An array is expected\");\n    }\n\n    HSQOBJECT array;\n    sq_resetobject(&array);\n    if (SQ_FAILED(sq_getstackobj(v, 2, &array))) {\n      return sq_throwerror(v, \"Failed to get array\");\n    }\n    _shuffle(*array._unVal.pArray);\n\n    sq_pushobject(v, array);\n    return 1;\n  }\n\n  static SQInteger assetExists(HSQUIRRELVM v) {\n    const SQChar *filename = nullptr;\n    if (SQ_FAILED(sq_getstring(v, 2, &filename))) {\n      return sq_throwerror(v, \"failed to get filename\");\n    }\n    sq_pushbool(v, Locator<EngineSettings>::get().hasEntry(filename) ? SQTrue : SQFalse);\n    return 1;\n  }\n\n  static SQInteger distance(HSQUIRRELVM v) {\n    if (sq_gettype(v, 2) == OT_INTEGER) {\n      SQInteger num1;\n      if (SQ_FAILED(sq_getinteger(v, 2, &num1))) {\n        return sq_throwerror(v, \"failed to get num1\");\n      }\n      SQInteger num2;\n      if (SQ_FAILED(sq_getinteger(v, 3, &num2))) {\n        return sq_throwerror(v, \"failed to get num2\");\n      }\n      auto d = std::abs(num1 - num2);\n      sq_pushinteger(v, d);\n      return 1;\n    }\n    auto obj1 = EntityManager::getEntity(v, 2);\n    if (!obj1) {\n      return sq_throwerror(v, \"failed to get object1 or actor1\");\n    }\n    auto obj2 = EntityManager::getEntity(v, 3);\n    if (!obj2) {\n      return sq_throwerror(v, \"failed to get object2 or actor2\");\n    }\n    auto pos1 = obj1->getPosition();\n    auto pos2 = obj1->getPosition();\n    auto dx = pos1.x - pos2.x;\n    auto dy = pos1.y - pos2.y;\n    auto d = std::sqrt(dx * dx + dy * dy);\n    sq_pushfloat(v, d);\n    return 1;\n  }\n\n  static SQInteger findScreenPosition(HSQUIRRELVM v) {\n    SQInteger verb;\n    glm::vec2 pos;\n    if (sq_gettype(v, 2) == OT_INTEGER) {\n      if (SQ_FAILED(sq_getinteger(v, 2, &verb))) {\n        return sq_throwerror(v, _SC(\"failed to get verb\"));\n      }\n      pos = g_pEngine->getHud().findScreenPosition(static_cast<int>(verb));\n    } else {\n      auto entity = EntityManager::getEntity(v, 2);\n      if (!entity) {\n        return sq_throwerror(v, _SC(\"failed to get object or actor\"));\n      }\n      if (entity->isInventoryObject()) {\n        const auto pObject = dynamic_cast<Object *>(entity);\n        pos = g_pEngine->getInventory().getPosition(pObject);\n        pos.y = Screen::Height - pos.y;\n      } else {\n        auto screenSize = g_pEngine->getRoom()->getScreenSize();\n        pos = entity->getPosition() - g_pEngine->getCamera().getRect().getTopLeft();\n        const auto pObject = dynamic_cast<Object *>(entity);\n        if (pObject) {\n          auto rect = pObject->getHotspot();\n          auto center = rect.getCenter();\n          pos += center;\n        }\n        pos = glm::vec2(Screen::Width * pos.x / screenSize.x, Screen::Height * pos.y / screenSize.y);\n      }\n    }\n    ScriptEngine::push(v, pos);\n    return 1;\n  }\n\n  static SQInteger frameCounter(HSQUIRRELVM v) {\n    sq_pushinteger(v, g_pEngine->getFrameCounter());\n    return 1;\n  }\n\n  static SQInteger in_array(HSQUIRRELVM v) {\n    HSQOBJECT obj;\n    sq_resetobject(&obj);\n    if (SQ_FAILED(sq_getstackobj(v, 2, &obj))) {\n      return sq_throwerror(v, \"Failed to get object\");\n    }\n    HSQOBJECT array;\n    sq_resetobject(&array);\n    if (SQ_FAILED(sq_getstackobj(v, 3, &array))) {\n      return sq_throwerror(v, \"Failed to get array\");\n    }\n\n    std::vector<HSQOBJECT> objs;\n\n    sq_pushobject(v, array);\n    sq_pushnull(v); //null iterator\n    while (SQ_SUCCEEDED(sq_next(v, -2))) {\n      HSQOBJECT tmp;\n      sq_getstackobj(v, -1, &tmp);\n      objs.push_back(tmp);\n      sq_pop(v, 2); //pops key and val before the nex iteration\n    }\n    sq_pop(v, 1); //pops the null iterator\n\n    for (auto &&o : objs) {\n      sq_pushobject(v, obj);\n      sq_pushobject(v, o);\n      if (sq_cmp(v) == 0) {\n        sq_pop(v, 2);\n        sq_pushinteger(v, 1);\n        return 1;\n      }\n      sq_pop(v, 2);\n    }\n\n    sq_pushinteger(v, 0);\n    return 1;\n  }\n\n  static SQInteger incutscene(HSQUIRRELVM v) {\n    sq_pushinteger(v, g_pEngine->inCutscene() ? 1 : 0);\n    return 1;\n  }\n\n  static SQInteger indialog(HSQUIRRELVM v) {\n    sq_pushinteger(v, static_cast<SQInteger>(g_pEngine->getDialogManager().getState()));\n    return 1;\n  }\n\n  static SQInteger integer(HSQUIRRELVM v) {\n    SQFloat f = 0;\n    if (SQ_FAILED(sq_getfloat(v, 2, &f))) {\n      return sq_throwerror(v, \"Failed to get float value\");\n    }\n    sq_pushinteger(v, (SQInteger) f);\n    return 1;\n  }\n\n  static SQInteger is_array(HSQUIRRELVM v) {\n    sq_pushbool(v, sq_gettype(v, 2) == OT_ARRAY ? SQTrue : SQFalse);\n    return 1;\n  }\n\n  static SQInteger is_function(HSQUIRRELVM v) {\n    auto type = sq_gettype(v, 2);\n    sq_pushbool(v, type == OT_CLOSURE || type == OT_NATIVECLOSURE ? SQTrue : SQFalse);\n    return 1;\n  }\n\n  static SQInteger loadArray(HSQUIRRELVM v) {\n    std::string filename;\n    const SQChar *name;\n    if (SQ_FAILED(sq_getstring(v, 2, &name))) {\n      return sq_throwerror(v, \"Failed to get filename\");\n    }\n    filename = name;\n    checkLanguage(filename);\n    auto &settings = Locator<EngineSettings>::get();\n    std::vector<char> buffer;\n    if (settings.hasEntry(filename)) {\n      buffer = settings.readBuffer(filename);\n    } else {\n      buffer = settings.readBuffer(name);\n    }\n    GGPackBufferStream input(buffer);\n    std::string line;\n\n    sq_newarray(v, 0);\n    while (getLine(input, line)) {\n      sq_pushstring(v, line.data(), -1);\n      sq_arrayappend(v, -2);\n    }\n    return 1;\n  }\n\n  static SQInteger strsplit(HSQUIRRELVM v) {\n    const SQChar *text;\n    if (SQ_FAILED(sq_getstring(v, 2, &text))) {\n      return sq_throwerror(v, \"Failed to get text\");\n    }\n\n    const SQChar *delimiter;\n    if (SQ_FAILED(sq_getstring(v, 3, &delimiter))) {\n      return sq_throwerror(v, \"Failed to get delimiter\");\n    }\n\n    sq_newarray(v, 0);\n    std::string token;\n    std::istringstream tokenStream(text);\n    while (std::getline(tokenStream, token, delimiter[0])) {\n      sq_pushstring(v, token.data(), -1);\n      sq_arrayappend(v, -2);\n    }\n    return 1;\n  }\n\n  static SQInteger cameraAt(HSQUIRRELVM v) {\n    glm::vec2 pos;\n    auto numArgs = sq_gettop(v) - 1;\n    if (numArgs == 2) {\n      SQInteger x, y;\n      if (SQ_FAILED(sq_getinteger(v, 2, &x))) {\n        return sq_throwerror(v, _SC(\"failed to get x\"));\n      }\n      if (SQ_FAILED(sq_getinteger(v, 3, &y))) {\n        return sq_throwerror(v, _SC(\"failed to get y\"));\n      }\n      pos = glm::vec2(x, y);\n    } else {\n      auto entity = EntityManager::getEntity(v, 2);\n      if (!entity) {\n        return sq_throwerror(v, _SC(\"failed to get spot or actor\"));\n      }\n      auto result = g_pEngine->setRoom(entity->getRoom());\n      if (SQ_FAILED(result)) {\n        return result;\n      }\n      pos = entity->getPosition();\n    }\n\n    g_pEngine->getCamera().at(pos);\n    return 0;\n  }\n\n  static SQInteger cameraBounds(HSQUIRRELVM v) {\n    SQInteger xMin, xMax, yMin, yMax;\n    if (SQ_FAILED(sq_getinteger(v, 2, &xMin))) {\n      return sq_throwerror(v, _SC(\"failed to get xMin\"));\n    }\n    if (SQ_FAILED(sq_getinteger(v, 3, &xMax))) {\n      return sq_throwerror(v, _SC(\"failed to get xMax\"));\n    }\n    if (SQ_FAILED(sq_getinteger(v, 4, &yMin))) {\n      return sq_throwerror(v, _SC(\"failed to get yMin\"));\n    }\n    if (SQ_FAILED(sq_getinteger(v, 5, &yMax))) {\n      return sq_throwerror(v, _SC(\"failed to get yMax\"));\n    }\n    g_pEngine->getCamera().setBounds(ngf::irect::fromMinMax({xMin, yMin}, {xMax, yMax}));\n    return 0;\n  }\n\n  static SQInteger cameraFollow(HSQUIRRELVM v) {\n    auto *pActor = EntityManager::getActor(v, 2);\n    g_pEngine->follow(pActor);\n    return 0;\n  }\n\n  static void _cameraPanTo(glm::ivec2 pos, float timeInSeconds, int interpolation) {\n    g_pEngine->follow(nullptr);\n    g_pEngine->getCamera().panTo(pos, ngf::TimeSpan::seconds(timeInSeconds), toInterpolationMethod(interpolation));\n  }\n\n  static SQInteger cameraPanTo(HSQUIRRELVM v) {\n    auto numArgs = sq_gettop(v);\n    SQInteger x, y, interpolation{0};\n    SQFloat t;\n    if (sq_gettype(v, 2) == OT_TABLE) {\n      auto *pEntity = EntityManager::getEntity(v, 2);\n      if (!pEntity) {\n        return sq_throwerror(v, _SC(\"failed to get actor/object\"));\n      }\n      x = static_cast<int>(pEntity->getPosition().x);\n      y = static_cast<int>(pEntity->getPosition().y);\n      if (SQ_FAILED(sq_getfloat(v, 3, &t))) {\n        return sq_throwerror(v, _SC(\"failed to get time\"));\n      }\n      _cameraPanTo(glm::ivec2(x, y), t, interpolation);\n      return 0;\n    }\n\n    if (numArgs == 4) {\n      if (SQ_FAILED(sq_getinteger(v, 2, &x))) {\n        return sq_throwerror(v, _SC(\"failed to get x\"));\n      }\n      y = g_pEngine->getCamera().getAt().y;\n      if (SQ_FAILED(sq_getfloat(v, 3, &t))) {\n        return sq_throwerror(v, _SC(\"failed to get time\"));\n      }\n      if (SQ_FAILED(sq_getinteger(v, 4, &interpolation))) {\n        interpolation = 0;\n      }\n      _cameraPanTo(glm::ivec2(x, y), t, interpolation);\n      return 0;\n    }\n\n    if (SQ_FAILED(sq_getinteger(v, 2, &x))) {\n      return sq_throwerror(v, _SC(\"failed to get x\"));\n    }\n    if (SQ_FAILED(sq_getinteger(v, 3, &y))) {\n      return sq_throwerror(v, _SC(\"failed to get y\"));\n    }\n    if (SQ_FAILED(sq_getfloat(v, 4, &t))) {\n      return sq_throwerror(v, _SC(\"failed to get time\"));\n    }\n    if (SQ_FAILED(sq_getinteger(v, 5, &interpolation))) {\n      interpolation = 0;\n    }\n    _cameraPanTo(glm::ivec2(x, y), t, interpolation);\n    return 0;\n  }\n\n  static SQInteger cameraPos(HSQUIRRELVM v) {\n    auto pos = g_pEngine->getCamera().getAt();\n    ScriptEngine::push(v, pos);\n    return 1;\n  }\n\n  static SQInteger cutscene(HSQUIRRELVM v) {\n    auto numArgs = sq_gettop(v);\n    HSQOBJECT env_obj;\n    sq_resetobject(&env_obj);\n    if (SQ_FAILED(sq_getstackobj(v, 1, &env_obj))) {\n      return sq_throwerror(v, _SC(\"Couldn't get environment from stack\"));\n    }\n\n    // create thread and store it on the stack\n    sq_newthread(v, 1024);\n    HSQOBJECT threadObj;\n    sq_resetobject(&threadObj);\n    if (SQ_FAILED(sq_getstackobj(v, -1, &threadObj))) {\n      return sq_throwerror(v, _SC(\"Couldn't get coroutine thread from stack\"));\n    }\n\n    // get the cutscene  closure\n    HSQOBJECT closureObj;\n    sq_resetobject(&closureObj);\n    if (SQ_FAILED(sq_getstackobj(v, 2, &closureObj))) {\n      return sq_throwerror(v, _SC(\"failed to get cutscene closure\"));\n    }\n\n    // get the cutscene override closure\n    HSQOBJECT closureCutsceneOverrideObj;\n    sq_resetobject(&closureCutsceneOverrideObj);\n    if (numArgs == 3) {\n      if (SQ_FAILED(sq_getstackobj(v, 3, &closureCutsceneOverrideObj))) {\n        return sq_throwerror(v, _SC(\"failed to get cutscene override closure\"));\n      }\n    }\n\n    auto scene = std::make_unique<Cutscene>(*g_pEngine, v, threadObj, closureObj, closureCutsceneOverrideObj, env_obj);\n    g_pEngine->cutscene(std::move(scene));\n\n    auto pThread = EntityManager::getThreadFromVm(v);\n    pThread->suspend();\n    return SQ_SUSPEND_FLAG;\n  }\n\n  static SQInteger cutsceneOverride(HSQUIRRELVM) {\n    g_pEngine->cutsceneOverride();\n    return 0;\n  }\n\n  static SQInteger random(HSQUIRRELVM v) {\n    if (sq_gettype(v, 2) == OT_INTEGER) {\n      SQInteger min = 0;\n      SQInteger max = 0;\n      sq_getinteger(v, 2, &min);\n      sq_getinteger(v, 3, &max);\n      auto value = Locator<RandomNumberGenerator>::get().generateLong(min, max);\n      sq_pushinteger(v, value);\n      return 1;\n    }\n    {\n      SQFloat min = 0;\n      SQFloat max = 0;\n      sq_getfloat(v, 2, &min);\n      sq_getfloat(v, 3, &max);\n      auto value = Locator<RandomNumberGenerator>::get().generateFloat(min, max);\n      sq_pushfloat(v, value);\n      return 1;\n    }\n  }\n\n  static SQInteger randomOdds(HSQUIRRELVM v) {\n    SQFloat value = 0;\n    if (SQ_FAILED(sq_getfloat(v, 2, &value))) {\n      return sq_throwerror(v, _SC(\"failed to get value\"));\n    }\n    auto rnd = Locator<RandomNumberGenerator>::get().generateFloat(0.f, 1.f);\n    auto result = static_cast<SQBool>(rnd <= value);\n    sq_pushbool(v, result);\n    return 1;\n  }\n\n  static SQInteger randomseed(HSQUIRRELVM v) {\n    auto nArgs = sq_gettop(v);\n    if (nArgs == 1) {\n      // get seed\n      auto seed = Locator<RandomNumberGenerator>::get().getSeed();\n      sq_pushinteger(v, seed);\n      return 1;\n    }\n    if (sq_gettype(v, 2) == OT_NULL) {\n      // set seed with time\n      time_t t;\n      auto seed = static_cast<long>(time(&t));\n      Locator<RandomNumberGenerator>::get().setSeed(seed);\n      return 0;\n    }\n    SQInteger seed;\n    if (SQ_FAILED(sq_getinteger(v, 2, &seed))) {\n      return sq_throwerror(v, _SC(\"failed to get seed\"));\n    }\n    // set seed with parameter\n    Locator<RandomNumberGenerator>::get().setSeed(static_cast<long>(seed));\n    return 0;\n  }\n\n  static SQInteger randomFrom(HSQUIRRELVM v) {\n    if (sq_gettype(v, 2) == OT_ARRAY) {\n      HSQOBJECT obj;\n      sq_resetobject(&obj);\n\n      auto size = sq_getsize(v, 2);\n      auto index = Locator<RandomNumberGenerator>::get().generateLong(0, size - 1);\n\n      int i = 0;\n      sq_push(v, 2);  // array\n      sq_pushnull(v); //null iterator\n      while (SQ_SUCCEEDED(sq_next(v, -2))) {\n        sq_getstackobj(v, -1, &obj);\n        sq_pop(v, 2); //pops key and val before the nex iteration\n        if (index == i++)\n          break;\n      }\n      sq_pop(v, 2); //pops the null iterator and array\n\n      sq_pushobject(v, obj);\n      return 1;\n    }\n    auto size = sq_gettop(v);\n    auto index = Locator<RandomNumberGenerator>::get().generateLong(0, size - 2);\n    sq_push(v, 2 + index);\n    return 1;\n  }\n\n  static SQInteger refreshUI(HSQUIRRELVM) {\n    error(\"TODO: refreshUI: not implemented\");\n    return 0;\n  }\n\n  static SQInteger cameraInRoom(HSQUIRRELVM v) {\n    auto *pRoom = EntityManager::getRoom(v, 2);\n    if (!pRoom) {\n      auto pEntity = EntityManager::getEntity(v, 2);\n      pRoom = pEntity ? pEntity->getRoom() : nullptr;\n      if (!pRoom) {\n        return sq_throwerror(v, _SC(\"failed to get room\"));\n      }\n    }\n    return g_pEngine->setRoom(pRoom);\n  }\n\n  static SQInteger markAchievement(HSQUIRRELVM v) {\n    const SQChar *id = nullptr;\n    sq_getstring(v, 2, &id);\n    auto numArgs = sq_gettop(v);\n    auto &achievements = ng::Locator<ng::AchievementManager>::get();\n    auto earnedValue = achievements.getPrivatePreference(\"earnedAchievements\");\n    std::string earned = earnedValue.isNull() ? \"\" : earnedValue.getString();\n    switch (numArgs) {\n    case 2:achievements.setPrivatePreference(\"earnedAchievements\", earned + \"|\" + id);\n      break;\n    case 4: {\n      SQInteger count;\n      SQInteger total;\n      sq_getinteger(v, 3, &count);\n      sq_getinteger(v, 4, &total);\n      if (count == total) {\n        achievements.setPrivatePreference(\"earnedAchievements\", earned + \"|\" + id);\n      }\n    }\n      break;\n    default:error(\"TODO: markAchievement not implemented\");\n      break;\n    }\n    return 0;\n  }\n\n  static SQInteger markProgress(HSQUIRRELVM) {\n    error(\"TODO: markProgress: not implemented\");\n    return 0;\n  }\n\n  static SQInteger markStat(HSQUIRRELVM) {\n    error(\"TODO: markStat: not implemented\");\n    return 0;\n  }\n\n  static SQInteger screenSize(HSQUIRRELVM v) {\n    auto screen = g_pEngine->getRoom()->getScreenSize();\n    ScriptEngine::push(v, screen);\n    return 1;\n  }\n\n  static SQInteger setVerb(HSQUIRRELVM v) {\n    SQInteger actorSlot;\n    if (SQ_FAILED(sq_getinteger(v, 2, &actorSlot))) {\n      return sq_throwerror(v, _SC(\"failed to get actor slot\"));\n    }\n    SQInteger verbSlot;\n    if (SQ_FAILED(sq_getinteger(v, 3, &verbSlot))) {\n      return sq_throwerror(v, _SC(\"failed to get verb slot\"));\n    }\n    HSQOBJECT table;\n    if (SQ_FAILED(sq_getstackobj(v, 4, &table))) {\n      return sq_throwerror(v, _SC(\"failed to get verb definitionTable\"));\n    }\n    if (!sq_istable(table)) {\n      return sq_throwerror(v, _SC(\"failed to get verb definitionTable\"));\n    }\n\n    sq_pushobject(v, table);\n    // id\n    sq_pushstring(v, _SC(\"verb\"), -1);\n    if (SQ_FAILED(sq_get(v, -2))) {\n      sq_pop(v, 2);\n      return sq_throwerror(v, _SC(\"failed to get verb\"));\n    }\n\n    SQInteger id = 0;\n    if (SQ_FAILED(sq_getinteger(v, -1, &id))) {\n      sq_pop(v, 2);\n      return sq_throwerror(v, _SC(\"failed to get verb\"));\n    }\n    sq_pop(v, 1);\n\n    // image\n    sq_pushstring(v, _SC(\"image\"), -1);\n    if (SQ_FAILED(sq_get(v, -2))) {\n      sq_pop(v, 2);\n      return sq_throwerror(v, _SC(\"failed to get image\"));\n    }\n\n    const SQChar *image = nullptr;\n    if (SQ_FAILED(sq_getstring(v, -1, &image))) {\n      sq_pop(v, 2);\n      return sq_throwerror(v, _SC(\"failed to get image\"));\n    }\n    sq_pop(v, 1);\n\n    // text\n    sq_pushstring(v, _SC(\"text\"), -1);\n    if (SQ_FAILED(sq_get(v, -2))) {\n      sq_pop(v, 2);\n      return sq_throwerror(v, _SC(\"failed to get text\"));\n    }\n\n    const SQChar *text = nullptr;\n    if (SQ_FAILED(sq_getstring(v, -1, &text))) {\n      sq_pop(v, 2);\n      return sq_throwerror(v, _SC(\"failed to get text\"));\n    }\n    sq_pop(v, 1);\n\n    // func\n    sq_pushstring(v, _SC(\"func\"), -1);\n    if (SQ_FAILED(sq_get(v, -2))) {\n      sq_pop(v, 2);\n      return sq_throwerror(v, _SC(\"failed to get func\"));\n    }\n\n    const SQChar *func = nullptr;\n    if (SQ_FAILED(sq_getstring(v, -1, &func))) {\n      sq_pop(v, 2);\n      return sq_throwerror(v, _SC(\"failed to get func\"));\n    }\n    sq_pop(v, 1);\n\n    // key\n    sq_pushstring(v, _SC(\"key\"), -1);\n    if (SQ_FAILED(sq_get(v, -2))) {\n      sq_pop(v, 2);\n      return sq_throwerror(v, _SC(\"failed to get key\"));\n    }\n\n    const SQChar *key = nullptr;\n    if (SQ_FAILED(sq_getstring(v, -1, &key))) {\n      sq_pop(v, 2);\n      return sq_throwerror(v, _SC(\"failed to get key\"));\n    }\n    sq_pop(v, 2);\n\n    VerbSlot slot;\n    Verb verb;\n    verb.id = id;\n    verb.func = func;\n    verb.image = image;\n    verb.text = text;\n    verb.key = key;\n    g_pEngine->getHud().setVerb(static_cast<int>(actorSlot - 1), verbSlot, verb);\n    return 0;\n  }\n\n  static SQInteger startDialog(HSQUIRRELVM v) {\n    auto count = sq_gettop(v);\n    const SQChar *dialog;\n    if (SQ_FAILED(sq_getstring(v, 2, &dialog))) {\n      return sq_throwerror(v, _SC(\"failed to get dialog\"));\n    }\n    const SQChar *node = \"start\";\n    if (count == 3) {\n      sq_getstring(v, 3, &node);\n    }\n    g_pEngine->startDialog(dialog, node);\n    return 0;\n  }\n\n  static SQInteger stopSentence(HSQUIRRELVM) {\n    g_pEngine->stopSentence();\n    return 0;\n  }\n\n  static SQInteger strcount(HSQUIRRELVM v) {\n    const SQChar *str1;\n    if (SQ_FAILED(sq_getstring(v, 2, &str1))) {\n      return sq_throwerror(v, _SC(\"failed to get string1\"));\n    }\n    const SQChar *str2;\n    if (SQ_FAILED(sq_getstring(v, 3, &str2))) {\n      return sq_throwerror(v, _SC(\"failed to get string1\"));\n    }\n    int count = 0;\n    while ((str1 = strstr(str1, str2))) {\n      str1 += strlen(str2);\n      ++count;\n    }\n    sq_pushinteger(v, static_cast<SQInteger>(count));\n    return 1;\n  }\n\n  static void init_crc32() {\n    unsigned int i, j, c;\n    for (i = 0; i < 256; i++) {\n      for (c = i, j = 0; j < 8; j++)\n        c = (c & 1) ? (c >> 1) ^ 0xEDB88320L : (c >> 1);\n      g_CRCTab[i ^ 0xFF] = c ^ 0xFF000000;\n    }\n  }\n\n  static unsigned int crc32_update(unsigned int x, char c) {\n    return g_CRCTab[(x ^ c) & 0xFF] ^ (x >> 8);\n  }\n\n  static SQInteger strcrc(HSQUIRRELVM v) {\n    const SQChar *str;\n    if (SQ_FAILED(sq_getstring(v, 2, &str))) {\n      return sq_throwerror(v, _SC(\"failed to get string\"));\n    }\n    unsigned int x;\n    for (x = 0; *str++; x = crc32_update(x, str[-1]));\n    sq_pushinteger(v, x);\n    return 1;\n  }\n\n  static SQInteger strfind(HSQUIRRELVM v) {\n    const SQChar *str1;\n    if (SQ_FAILED(sq_getstring(v, 2, &str1))) {\n      return sq_throwerror(v, _SC(\"failed to get string1\"));\n    }\n    const SQChar *str2;\n    if (SQ_FAILED(sq_getstring(v, 3, &str2))) {\n      return sq_throwerror(v, _SC(\"failed to get string1\"));\n    }\n    auto p = std::strstr(str1, str2);\n    if (p == nullptr) {\n      sq_pushinteger(v, -1);\n    } else {\n      sq_pushinteger(v, p - str1);\n    }\n    return 1;\n  }\n\n  static SQInteger strfirst(HSQUIRRELVM v) {\n    const SQChar *str;\n    if (SQ_FAILED(sq_getstring(v, 2, &str))) {\n      return sq_throwerror(v, _SC(\"failed to get string\"));\n    }\n    if (strlen(str) > 0) {\n      const SQChar s[2]{str[0], '\\0'};\n      sq_pushstring(v, s, 1);\n      return 1;\n    }\n    sq_pushnull(v);\n    return 1;\n  }\n\n  static SQInteger strlast(HSQUIRRELVM v) {\n    const SQChar *str;\n    if (SQ_FAILED(sq_getstring(v, 2, &str))) {\n      return sq_throwerror(v, _SC(\"failed to get string\"));\n    }\n    auto len = strlen(str);\n    if (len > 0) {\n      const SQChar s[2]{str[len - 1], '\\0'};\n      sq_pushstring(v, s, 1);\n      return 1;\n    }\n    sq_pushnull(v);\n    return 1;\n  }\n\n  static SQInteger strlines(HSQUIRRELVM v) {\n    const SQChar *text;\n    if (SQ_FAILED(sq_getstring(v, 2, &text))) {\n      return sq_throwerror(v, _SC(\"failed to get text\"));\n    }\n    std::istringstream is(text);\n    sq_newarray(v, 0);\n    std::string line;\n    while (std::getline(is, line)) {\n      sq_pushstring(v, line.data(), -1);\n      sq_arrayappend(v, -2);\n    }\n    return 1;\n  }\n\n  static SQInteger strreplace(HSQUIRRELVM v) {\n    const SQChar *input;\n    const SQChar *search;\n    const SQChar *replace;\n    if (SQ_FAILED(sq_getstring(v, 2, &input))) {\n      return sq_throwerror(v, _SC(\"failed to get input\"));\n    }\n    if (SQ_FAILED(sq_getstring(v, 3, &search))) {\n      return sq_throwerror(v, _SC(\"failed to get search\"));\n    }\n    if (SQ_FAILED(sq_getstring(v, 4, &replace))) {\n      return sq_throwerror(v, _SC(\"failed to get replace\"));\n    }\n    std::string strInput(input);\n    std::string strSearch(search);\n    std::string strReplace(replace);\n    replaceAll(strInput, strSearch, strReplace);\n    sq_pushstring(v, strInput.data(), -1);\n    return 1;\n  }\n\n  static SQInteger translate(HSQUIRRELVM v) {\n    const SQChar *idText;\n    if (SQ_FAILED(sq_getstring(v, 2, &idText))) {\n      return sq_throwerror(v, _SC(\"failed to get idText\"));\n    }\n    std::string s(idText);\n    s = s.substr(1);\n    auto id = std::strtol(s.c_str(), nullptr, 10);\n    auto text = Engine::getText(id);\n    sq_pushstring(v, tostring(text).c_str(), -1);\n    return 1;\n  }\n};\n\nEngine *GeneralPack::g_pEngine = nullptr;\nunsigned int GeneralPack::g_CRCTab[256] = {};\n\n} // namespace ng\n"
  },
  {
    "path": "src/Scripting/ObjectPack.hpp",
    "content": "#pragma once\n#include <utility>\n#include <engge/Entities/TextObject.hpp>\n#include <squirrel.h>\n\nnamespace ng {\nclass ObjectPack final : public Pack {\nprivate:\n  static Engine *g_pEngine;\n\nprivate:\n  void registerPack() const override {\n    g_pEngine = &ScriptEngine::getEngine();\n    ScriptEngine::registerGlobalFunction(createObject, \"createObject\");\n    ScriptEngine::registerGlobalFunction(createTextObject, \"createTextObject\");\n    ScriptEngine::registerGlobalFunction(deleteObject, \"deleteObject\");\n    ScriptEngine::registerGlobalFunction(findObjectAt, \"findObjectAt\");\n    ScriptEngine::registerGlobalFunction(isObject, \"is_object\");\n    ScriptEngine::registerGlobalFunction(isInventoryOnScreen, \"isInventoryOnScreen\");\n    ScriptEngine::registerGlobalFunction(isObject, \"isObject\");\n    ScriptEngine::registerGlobalFunction(jiggleInventory, \"jiggleInventory\");\n    ScriptEngine::registerGlobalFunction(jiggleObject, \"jiggleObject\");\n    ScriptEngine::registerGlobalFunction(loopObjectState, \"loopObjectState\");\n    ScriptEngine::registerGlobalFunction(objectAlpha, \"objectAlpha\");\n    ScriptEngine::registerGlobalFunction(objectAlphaTo, \"objectAlphaTo\");\n    ScriptEngine::registerGlobalFunction(objectAt, \"objectAt\");\n    ScriptEngine::registerGlobalFunction(objectBumperCycle, \"objectBumperCycle\");\n    ScriptEngine::registerGlobalFunction(objectCenter, \"objectCenter\");\n    ScriptEngine::registerGlobalFunction(objectColor, \"objectColor\");\n    ScriptEngine::registerGlobalFunction(objectDependentOn, \"objectDependentOn\");\n    ScriptEngine::registerGlobalFunction(objectFPS, \"objectFPS\");\n    ScriptEngine::registerGlobalFunction(objectHidden, \"objectHidden\");\n    ScriptEngine::registerGlobalFunction(objectHotspot, \"objectHotspot\");\n    ScriptEngine::registerGlobalFunction(objectIcon, \"objectIcon\");\n    ScriptEngine::registerGlobalFunction(objectLit, \"objectLit\");\n    ScriptEngine::registerGlobalFunction(objectMoveTo, \"objectMoveTo\");\n    ScriptEngine::registerGlobalFunction(objectOffset, \"objectOffset\");\n    ScriptEngine::registerGlobalFunction(objectOffsetTo, \"objectOffsetTo\");\n    ScriptEngine::registerGlobalFunction(objectOwner, \"objectOwner\");\n    ScriptEngine::registerGlobalFunction(objectParallaxLayer, \"objectParallaxLayer\");\n    ScriptEngine::registerGlobalFunction(objectParent, \"objectParent\");\n    ScriptEngine::registerGlobalFunction(objectPosX, \"objectPosX\");\n    ScriptEngine::registerGlobalFunction(objectPosY, \"objectPosY\");\n    ScriptEngine::registerGlobalFunction(objectRenderOffset, \"objectRenderOffset\");\n    ScriptEngine::registerGlobalFunction(objectRoom, \"objectRoom\");\n    ScriptEngine::registerGlobalFunction(objectRotate, \"objectRotate\");\n    ScriptEngine::registerGlobalFunction(objectRotateTo, \"objectRotateTo\");\n    ScriptEngine::registerGlobalFunction(objectScale, \"objectScale\");\n    ScriptEngine::registerGlobalFunction(objectScaleTo, \"objectScaleTo\");\n    ScriptEngine::registerGlobalFunction(objectScreenSpace, \"objectScreenSpace\");\n    ScriptEngine::registerGlobalFunction(objectShader, \"objectShader\");\n    ScriptEngine::registerGlobalFunction(objectSort, \"objectSort\");\n    ScriptEngine::registerGlobalFunction(objectState, \"objectState\");\n    ScriptEngine::registerGlobalFunction(objectTouchable, \"objectTouchable\");\n    ScriptEngine::registerGlobalFunction(objectUsePos, \"objectUsePos\");\n    ScriptEngine::registerGlobalFunction(objectUsePosX, \"objectUsePosX\");\n    ScriptEngine::registerGlobalFunction(objectUsePosY, \"objectUsePosY\");\n    ScriptEngine::registerGlobalFunction(objectValidUsePos, \"objectValidUsePos\");\n    ScriptEngine::registerGlobalFunction(objectValidVerb, \"objectValidVerb\");\n    ScriptEngine::registerGlobalFunction(pickupObject, \"pickupObject\");\n    ScriptEngine::registerGlobalFunction(pickupReplacementObject, \"pickupReplacementObject\");\n    ScriptEngine::registerGlobalFunction(playObjectState, \"playObjectState\");\n    ScriptEngine::registerGlobalFunction(popInventory, \"popInventory\");\n    ScriptEngine::registerGlobalFunction(removeInventory, \"removeInventory\");\n    ScriptEngine::registerGlobalFunction(setDefaultObject, \"setDefaultObject\");\n    ScriptEngine::registerGlobalFunction(scale, \"scale\");\n    ScriptEngine::registerGlobalFunction(shakeObject, \"shakeObject\");\n    ScriptEngine::registerGlobalFunction(stopObjectMotors, \"stopObjectMotors\");\n  }\n\n  static SQInteger findObjectAt(HSQUIRRELVM v) {\n    SQInteger x = 0;\n    if (SQ_FAILED(sq_getinteger(v, 2, &x))) {\n      return sq_throwerror(v, _SC(\"failed to get x\"));\n    }\n    SQInteger y = 0;\n    if (SQ_FAILED(sq_getinteger(v, 3, &y))) {\n      return sq_throwerror(v, _SC(\"failed to get y\"));\n    }\n    auto *room = g_pEngine->getRoom();\n    auto &objects = room->getObjects();\n\n    std::sort(objects.begin(), objects.end(),\n              [](const std::unique_ptr<Object> &obj1, const std::unique_ptr<Object> &obj2) {\n                return obj1->getZOrder() < obj2->getZOrder();\n              });\n\n    for (auto &obj : objects) {\n      if (!obj->isVisible())\n        continue;\n      if (obj->getRealHotspot().contains({x, y})) {\n        sq_pushobject(v, obj->getTable());\n        return 1;\n      }\n    }\n\n    sq_pushnull(v);\n    return 1;\n  }\n\n  static SQInteger isInventoryOnScreen(HSQUIRRELVM v) {\n    auto object = EntityManager::getObject(v, 2);\n    auto owner = object->getOwner();\n    if (!owner) {\n      sq_pushbool(v, SQFalse);\n      return 1;\n    }\n    if (g_pEngine->getCurrentActor() != owner) {\n      sq_pushbool(v, SQFalse);\n      return 1;\n    }\n    auto offset = owner->getInventoryOffset();\n    auto &objects = owner->getObjects();\n    auto it = std::find(objects.begin(), objects.end(), object);\n    auto index = std::distance(objects.begin(), it);\n    if (index >= offset * 4 && index < (offset * 4 + 8)) {\n      sq_pushbool(v, SQTrue);\n      return 1;\n    }\n    sq_pushbool(v, SQFalse);\n    return 1;\n  }\n\n  static SQInteger isObject(HSQUIRRELVM v) {\n    auto object = EntityManager::getObject(v, 2);\n    sq_pushbool(v, object ? SQTrue : SQFalse);\n    return 1;\n  }\n\n  static SQInteger jiggleInventory(HSQUIRRELVM v) {\n    Object *obj = EntityManager::getObject(v, 2);\n    if (!obj) {\n      return sq_throwerror(v, _SC(\"failed to get object\"));\n    }\n    SQInteger enabled = 0;\n    if (SQ_FAILED(sq_getinteger(v, 3, &enabled))) {\n      return sq_throwerror(v, _SC(\"failed to get enabled\"));\n    }\n    obj->setJiggle(enabled != 0);\n    return 0;\n  }\n\n  static SQInteger jiggleObject(HSQUIRRELVM v) {\n    if (sq_gettype(v, 2) == OT_NULL)\n      return 0;\n\n    auto *obj = EntityManager::getEntity(v, 2);\n    if (!obj) {\n      return sq_throwerror(v, _SC(\"failed to get object/actor\"));\n    }\n    SQFloat amount = 0;\n    if (SQ_FAILED(sq_getfloat(v, 3, &amount))) {\n      return sq_throwerror(v, _SC(\"failed to get amount\"));\n    }\n    obj->jiggle(amount);\n    return 0;\n  }\n\n  static SQInteger scale(HSQUIRRELVM v) {\n    SQFloat s = 0;\n    if (SQ_FAILED(sq_getfloat(v, 3, &s))) {\n      return sq_throwerror(v, _SC(\"failed to get scale\"));\n    }\n    Object *self = EntityManager::getObject(v, 2);\n    if (!self) {\n      return sq_throwerror(v, _SC(\"failed to get object\"));\n    }\n    self->setScale(s);\n    return 0;\n  }\n\n  static SQInteger objectAlpha(HSQUIRRELVM v) {\n    if (sq_gettype(v, 2) == OT_NULL)\n      return 0;\n\n    Object *obj = EntityManager::getObject(v, 2);\n    if (!obj) {\n      return sq_throwerror(v, _SC(\"failed to get object\"));\n    }\n    SQFloat alpha = 0;\n    if (SQ_FAILED(sq_getfloat(v, 3, &alpha))) {\n      return sq_throwerror(v, _SC(\"failed to get alpha\"));\n    }\n    alpha = std::clamp(alpha, 0.f, 1.f);\n    auto color = obj->getColor();\n    obj->setColor(ngf::Color(color.r, color.g, color.b, alpha));\n    return 0;\n  }\n\n  static SQInteger objectAlphaTo(HSQUIRRELVM v) {\n    if (sq_gettype(v, 2) == OT_NULL)\n      return 0;\n\n    auto *obj = EntityManager::getEntity(v, 2);\n    if (!obj) {\n      return sq_throwerror(v, _SC(\"failed to get object/actor\"));\n    }\n    SQFloat alpha = 0;\n    if (SQ_FAILED(sq_getfloat(v, 3, &alpha))) {\n      return sq_throwerror(v, _SC(\"failed to get alpha\"));\n    }\n    alpha = alpha > 1.f ? 1.f : alpha;\n    alpha = alpha < 0.f ? 0.f : alpha;\n    SQFloat time = 0;\n    if (SQ_FAILED(sq_getfloat(v, 4, &time))) {\n      return sq_throwerror(v, _SC(\"failed to get time\"));\n    }\n    SQInteger interpolation;\n    if (SQ_FAILED(sq_getinteger(v, 5, &interpolation))) {\n      interpolation = 0;\n    }\n    obj->alphaTo(alpha, ngf::TimeSpan::seconds(time), toInterpolationMethod(interpolation));\n    return 0;\n  }\n\n  static SQInteger objectBumperCycle(HSQUIRRELVM v) {\n    auto pObj = EntityManager::getEntity(v, 2);\n    if (!pObj) {\n      return sq_throwerror(v, _SC(\"failed to get object\"));\n    }\n    SQInteger enabled = 0;\n    if (SQ_FAILED(sq_getinteger(v, 3, &enabled))) {\n      return sq_throwerror(v, _SC(\"failed to get enabled\"));\n    }\n    pObj->objectBumperCycle(enabled != 0);\n    return 0;\n  }\n\n  static SQInteger objectHotspot(HSQUIRRELVM v) {\n    SQInteger left = 0;\n    SQInteger top = 0;\n    SQInteger right = 0;\n    SQInteger bottom = 0;\n\n    auto numArgs = sq_gettop(v);\n\n    Object *obj = EntityManager::getObject(v, 2);\n    Actor *actor = nullptr;\n    if (!obj) {\n      actor = EntityManager::getActor(v, 2);\n      if (!actor) {\n        return sq_throwerror(v, _SC(\"failed to get object or actor\"));\n      }\n    }\n    if (numArgs == 2) {\n      // this really fucked up, when seeting hotspot it's a relative rect,\n      // when getting hotspot the position is absolute\n      const auto pos = obj->getPosition();\n      const auto hotspot = obj->getHotspot();\n      auto r = ngf::irect::fromPositionSize({hotspot.getTopLeft().x + static_cast<int>(pos.x),\n                                             hotspot.getTopLeft().y + static_cast<int>(pos.y)}, hotspot.getSize());\n      ScriptEngine::push(v, r);\n      return 1;\n    }\n    if (SQ_FAILED(sq_getinteger(v, 3, &left))) {\n      return sq_throwerror(v, _SC(\"failed to get left\"));\n    }\n    if (SQ_FAILED(sq_getinteger(v, 4, &top))) {\n      return sq_throwerror(v, _SC(\"failed to get top\"));\n    }\n    if (SQ_FAILED(sq_getinteger(v, 5, &right))) {\n      return sq_throwerror(v, _SC(\"failed to get right\"));\n    }\n    if (SQ_FAILED(sq_getinteger(v, 6, &bottom))) {\n      return sq_throwerror(v, _SC(\"failed to get bottom\"));\n    }\n\n    if (obj) {\n      obj->setHotspot(ngf::irect::fromMinMax({static_cast<int>(left), static_cast<int>(top)}, {static_cast<int>(right),\n                                                                                               static_cast<int>(bottom)}));\n    } else {\n      actor->setHotspot(ngf::irect::fromMinMax({static_cast<int>(left), static_cast<int>(top)},\n                                               {static_cast<int>(right),\n                                                static_cast<int>(bottom)}));\n    }\n    return 0;\n  }\n\n  static SQInteger objectOffset(HSQUIRRELVM v) {\n    SQInteger x = 0;\n    SQInteger y = 0;\n    auto *obj = EntityManager::getEntity(v, 2);\n    if (!obj) {\n      return sq_throwerror(v, _SC(\"failed to get object or actor\"));\n    }\n    if (SQ_FAILED(sq_getinteger(v, 3, &x))) {\n      return sq_throwerror(v, _SC(\"failed to get x\"));\n    }\n    if (SQ_FAILED(sq_getinteger(v, 4, &y))) {\n      return sq_throwerror(v, _SC(\"failed to get y\"));\n    }\n    obj->setOffset(glm::vec2(x, y));\n    return 0;\n  }\n\n  static SQInteger objectScreenSpace(HSQUIRRELVM v) {\n    auto obj = EntityManager::getObject(v, 2);\n    if (!obj) {\n      return sq_throwerror(v, _SC(\"failed to get object\"));\n    }\n    SQInteger enable = 1;\n    if (sq_gettop(v) == 3) {\n      sq_getinteger(v, 3, &enable);\n    }\n    obj->setScreenSpace(enable ? ScreenSpace::Object : ScreenSpace::Room);\n    return 0;\n  }\n\n  static SQInteger objectState(HSQUIRRELVM v) {\n    auto obj = EntityManager::getObject(v, 2);\n    if (!obj) {\n      return sq_throwerror(v, _SC(\"failed to get object\"));\n    }\n    auto numArgs = sq_gettop(v) - 2;\n    if (numArgs == 0) {\n      sq_pushinteger(v, obj->getState());\n      return 1;\n    }\n\n    SQInteger state;\n    if (SQ_FAILED(sq_getinteger(v, 3, &state))) {\n      return sq_throwerror(v, _SC(\"failed to get state\"));\n    }\n    obj->playAnim(state, false);\n\n    return 0;\n  }\n\n  static SQInteger objectOffsetTo(HSQUIRRELVM v) {\n    SQInteger x = 0;\n    SQInteger y = 0;\n    SQFloat t = 0;\n    auto *obj = EntityManager::getEntity(v, 2);\n    if (!obj) {\n      return sq_throwerror(v, _SC(\"failed to get entity\"));\n    }\n    if (SQ_FAILED(sq_getinteger(v, 3, &x))) {\n      return sq_throwerror(v, _SC(\"failed to get x\"));\n    }\n    if (SQ_FAILED(sq_getinteger(v, 4, &y))) {\n      return sq_throwerror(v, _SC(\"failed to get y\"));\n    }\n    if (SQ_FAILED(sq_getfloat(v, 5, &t))) {\n      return sq_throwerror(v, _SC(\"failed to get t\"));\n    }\n    SQInteger interpolation;\n    if (SQ_FAILED(sq_getinteger(v, 6, &interpolation))) {\n      interpolation = 0;\n    }\n    obj->offsetTo({x, y}, ngf::TimeSpan::seconds(t), toInterpolationMethod(interpolation));\n    return 0;\n  }\n\n  static SQInteger objectMoveTo(HSQUIRRELVM v) {\n    SQInteger x = 0;\n    SQInteger y = 0;\n    SQFloat t = 0;\n    Entity *obj = EntityManager::getEntity(v, 2);\n    if (!obj) {\n      return sq_throwerror(v, _SC(\"failed to get object\"));\n    }\n    if (SQ_FAILED(sq_getinteger(v, 3, &x))) {\n      return sq_throwerror(v, _SC(\"failed to get x\"));\n    }\n    if (SQ_FAILED(sq_getinteger(v, 4, &y))) {\n      return sq_throwerror(v, _SC(\"failed to get y\"));\n    }\n    if (SQ_FAILED(sq_getfloat(v, 5, &t))) {\n      return sq_throwerror(v, _SC(\"failed to get t\"));\n    }\n    SQInteger interpolation;\n    if (SQ_FAILED(sq_getinteger(v, 6, &interpolation))) {\n      interpolation = 0;\n    }\n    obj->moveTo({x, y}, ngf::TimeSpan::seconds(t), toInterpolationMethod(interpolation));\n    return 0;\n  }\n\n  static SQInteger loopObjectState(HSQUIRRELVM v) {\n    SQInteger index;\n    Object *obj = EntityManager::getObject(v, 2);\n    if (!obj) {\n      return sq_throwerror(v, _SC(\"failed to get object\"));\n    }\n    if (SQ_FAILED(sq_getinteger(v, 3, &index))) {\n      return sq_throwerror(v, _SC(\"failed to get state\"));\n    }\n    obj->playAnim(static_cast<int>(index), true);\n    return 0;\n  }\n\n  static SQInteger playObjectState(HSQUIRRELVM v) {\n    if (sq_gettype(v, 2) == OT_NULL)\n      return 0;\n\n    Object *obj = EntityManager::getObject(v, 2);\n    if (!obj) {\n      return sq_throwerror(v, _SC(\"failed to get object\"));\n    }\n    if (sq_gettype(v, 3) == OT_INTEGER) {\n      SQInteger index;\n      if (SQ_FAILED(sq_getinteger(v, 3, &index))) {\n        return sq_throwerror(v, _SC(\"failed to get state\"));\n      }\n      obj->playAnim(static_cast<int>(index), false);\n      return 0;\n    }\n    if (sq_gettype(v, 3) == OT_STRING) {\n      const SQChar *state;\n      if (SQ_FAILED(sq_getstring(v, 3, &state))) {\n        return sq_throwerror(v, _SC(\"failed to get state\"));\n      }\n      obj->playAnim(state, false);\n      return 0;\n    }\n    return sq_throwerror(v, _SC(\"failed to get state\"));\n  }\n\n  static SQInteger popInventory(HSQUIRRELVM v) {\n    auto *obj = EntityManager::getObject(v, 2);\n    if (!obj) {\n      return sq_throwerror(v, _SC(\"failed to get object\"));\n    }\n    SQInteger count = 1;\n    if (sq_gettop(v) == 3) {\n      if (SQ_FAILED(sq_getinteger(v, 3, &count))) {\n        return sq_throwerror(v, _SC(\"failed to get count\"));\n      }\n    }\n    obj->setPop(static_cast<int>(count));\n    return 0;\n  }\n\n  static SQInteger removeInventory(HSQUIRRELVM v) {\n    Object *obj = EntityManager::getObject(v, 2);\n    if (obj) {\n      auto owner = obj->getOwner();\n      if (owner) {\n        owner->removeInventory(obj);\n      }\n      return 0;\n    }\n\n    Actor *actor = EntityManager::getActor(v, 2);\n    if (!actor) {\n      return sq_throwerror(v, _SC(\"failed to get object or actor\"));\n    }\n    actor->clearInventory();\n    return 0;\n  }\n\n  static SQInteger objectAt(HSQUIRRELVM v) {\n    SQInteger x, y;\n    auto numArgs = sq_gettop(v);\n    Object *obj = EntityManager::getObject(v, 2);\n    if (!obj) {\n      return sq_throwerror(v, _SC(\"failed to get object\"));\n    }\n    if (numArgs == 3) {\n      Object *spot = EntityManager::getObject(v, 3);\n      if (!spot) {\n        return sq_throwerror(v, _SC(\"failed to get spot\"));\n      }\n      auto pos = spot->getPosition();\n      auto usePos = spot->getUsePosition().value_or(glm::vec2());\n      x = pos.x + usePos.x;\n      y = pos.y + usePos.y;\n    } else {\n      if (SQ_FAILED(sq_getinteger(v, 3, &x))) {\n        return sq_throwerror(v, _SC(\"failed to get x\"));\n      }\n      if (SQ_FAILED(sq_getinteger(v, 4, &y))) {\n        return sq_throwerror(v, _SC(\"failed to get y\"));\n      }\n    }\n    obj->setPosition(glm::vec2(x, y));\n    return 0;\n  }\n\n  static SQInteger objectScale(HSQUIRRELVM v) {\n    SQFloat value;\n    Object *obj = EntityManager::getObject(v, 2);\n    if (!obj) {\n      return sq_throwerror(v, _SC(\"failed to get object\"));\n    }\n    if (SQ_FAILED(sq_getfloat(v, 3, &value))) {\n      return sq_throwerror(v, _SC(\"failed to get scale\"));\n    }\n    obj->setScale(value);\n    return 0;\n  }\n\n  static SQInteger objectScaleTo(HSQUIRRELVM v) {\n    Object *obj = EntityManager::getObject(v, 2);\n    if (!obj) {\n      return sq_throwerror(v, _SC(\"failed to get object\"));\n    }\n    SQFloat value;\n    if (SQ_FAILED(sq_getfloat(v, 3, &value))) {\n      return sq_throwerror(v, _SC(\"failed to get scale\"));\n    }\n    SQFloat t;\n    if (SQ_FAILED(sq_getfloat(v, 4, &t))) {\n      return sq_throwerror(v, _SC(\"failed to get time\"));\n    }\n    SQInteger interpolation;\n    if (SQ_FAILED(sq_getinteger(v, 5, &interpolation))) {\n      interpolation = 0;\n    }\n    obj->scaleTo(value, ngf::TimeSpan::seconds(t), toInterpolationMethod(interpolation));\n    return 0;\n  }\n\n  static SQInteger objectPosX(HSQUIRRELVM v) {\n    Object *obj = EntityManager::getObject(v, 2);\n    if (!obj) {\n      return sq_throwerror(v, _SC(\"failed to get object\"));\n    }\n    auto pos = obj->getPosition();\n    auto hotspot = obj->getHotspot();\n    auto usePos = obj->getUsePosition().value_or(glm::vec2());\n    sq_pushinteger(v, static_cast<SQInteger>(pos.x + usePos.x + hotspot.getTopLeft().x + hotspot.getWidth() / 2));\n    return 1;\n  }\n\n  static SQInteger objectPosY(HSQUIRRELVM v) {\n    Object *obj = EntityManager::getObject(v, 2);\n    if (!obj) {\n      return sq_throwerror(v, _SC(\"failed to get object\"));\n    }\n    auto pos = obj->getPosition();\n    auto hotspot = obj->getHotspot();\n    auto usePos = obj->getUsePosition().value_or(glm::vec2());\n    pos.y += usePos.y + hotspot.getTopLeft().y + hotspot.getHeight() / 2;\n    sq_pushinteger(v, static_cast<SQInteger>(pos.y));\n    return 1;\n  }\n\n  static SQInteger objectRenderOffset(HSQUIRRELVM v) {\n    Object *obj = EntityManager::getObject(v, 2);\n    if (!obj) {\n      return sq_throwerror(v, _SC(\"failed to get object\"));\n    }\n    SQInteger x;\n    if (SQ_FAILED(sq_getinteger(v, 3, &x))) {\n      return sq_throwerror(v, _SC(\"failed to get x\"));\n    }\n    SQInteger y;\n    if (SQ_FAILED(sq_getinteger(v, 4, &y))) {\n      return sq_throwerror(v, _SC(\"failed to get y\"));\n    }\n    obj->setRenderOffset({static_cast<int>(x), static_cast<int>(y)});\n    return 0;\n  }\n\n  static SQInteger objectRoom(HSQUIRRELVM v) {\n    Object *obj = EntityManager::getObject(v, 2);\n    if (!obj) {\n      return sq_throwerror(v, _SC(\"failed to get object\"));\n    }\n    auto pRoom = obj->getRoom();\n    if (!pRoom) {\n      sq_pushnull(v);\n      return 1;\n    }\n    sq_pushobject(v, pRoom->getTable());\n    return 1;\n  }\n\n  static SQInteger objectSort(HSQUIRRELVM v) {\n    SQInteger zOrder;\n    Object *obj = EntityManager::getObject(v, 2);\n    if (!obj) {\n      return sq_throwerror(v, _SC(\"failed to get object\"));\n    }\n    if (SQ_FAILED(sq_getinteger(v, 3, &zOrder))) {\n      return sq_throwerror(v, _SC(\"failed to get zOrder\"));\n    }\n    obj->setZOrder(static_cast<int>(zOrder));\n    return 0;\n  }\n\n  static SQInteger objectRotate(HSQUIRRELVM v) {\n    SQInteger angle;\n    Object *obj = EntityManager::getObject(v, 2);\n    if (!obj) {\n      return sq_throwerror(v, _SC(\"failed to get object\"));\n    }\n    if (SQ_FAILED(sq_getinteger(v, 3, &angle))) {\n      return sq_throwerror(v, _SC(\"failed to get angle\"));\n    }\n    obj->setRotation(static_cast<float>(angle));\n    return 0;\n  }\n\n  static SQInteger objectRotateTo(HSQUIRRELVM v) {\n    SQFloat value;\n    SQFloat t;\n    Object *obj = EntityManager::getObject(v, 2);\n    if (!obj) {\n      return sq_throwerror(v, _SC(\"failed to get object\"));\n    }\n    if (SQ_FAILED(sq_getfloat(v, 3, &value))) {\n      return sq_throwerror(v, _SC(\"failed to get value\"));\n    }\n    if (SQ_FAILED(sq_getfloat(v, 4, &t))) {\n      return sq_throwerror(v, _SC(\"failed to get time\"));\n    }\n    SQInteger interpolation;\n    if (SQ_FAILED(sq_getinteger(v, 5, &interpolation))) {\n      interpolation = 0;\n    }\n    obj->rotateTo(value, ngf::TimeSpan::seconds(t), toInterpolationMethod(interpolation));\n    return 0;\n  }\n\n  static SQInteger objectParallaxLayer(HSQUIRRELVM v) {\n    SQInteger layer;\n    Object *obj = EntityManager::getObject(v, 2);\n    if (!obj) {\n      return sq_throwerror(v, _SC(\"failed to get object\"));\n    }\n    if (SQ_FAILED(sq_getinteger(v, 3, &layer))) {\n      return sq_throwerror(v, _SC(\"failed to get layer number\"));\n    }\n    g_pEngine->getRoom()->setAsParallaxLayer(obj, static_cast<int>(layer));\n    return 0;\n  }\n\n  static SQInteger objectParent(HSQUIRRELVM v) {\n    auto pChild = EntityManager::getObject(v, 2);\n    if (!pChild) {\n      return sq_throwerror(v, _SC(\"failed to get child object\"));\n    }\n    auto pParent = EntityManager::getObject(v, 3);\n    if (!pParent) {\n      return sq_throwerror(v, _SC(\"failed to get parent object\"));\n    }\n    pChild->setParent(pParent);\n    return 0;\n  }\n\n  static SQInteger objectTouchable(HSQUIRRELVM v) {\n    SQInteger isTouchable;\n    auto *obj = EntityManager::getEntity(v, 2);\n    if (!obj) {\n      return sq_throwerror(v, _SC(\"failed to get object or actor\"));\n    }\n    auto numArgs = sq_gettop(v);\n    if (numArgs == 2) {\n      isTouchable = obj->isTouchable() ? 1 : 0;\n      sq_pushinteger(v, isTouchable);\n      return 1;\n    }\n    if (SQ_FAILED(sq_getinteger(v, 3, &isTouchable))) {\n      return sq_throwerror(v, _SC(\"failed to get isTouchable\"));\n    }\n    obj->setTouchable(isTouchable != 0);\n    return 0;\n  }\n\n  static SQInteger objectLit(HSQUIRRELVM v) {\n    SQInteger isLit;\n    auto *obj = EntityManager::getEntity(v, 2);\n    if (!obj) {\n      return sq_throwerror(v, _SC(\"failed to get actor or object\"));\n    }\n    if (SQ_FAILED(sq_getinteger(v, 3, &isLit))) {\n      return sq_throwerror(v, _SC(\"failed to get isLit parameter\"));\n    }\n    obj->setLit(isLit != 0);\n    return 0;\n  }\n\n  static SQInteger objectOwner(HSQUIRRELVM v) {\n    auto *obj = EntityManager::getObject(v, 2);\n    if (!obj) {\n      return sq_throwerror(v, _SC(\"failed to get object\"));\n    }\n\n    Actor *pActor = obj->getOwner();\n    if (!pActor) {\n      sq_pushnull(v);\n      return 1;\n    }\n\n    sq_pushobject(v, pActor->getTable());\n    return 1;\n  }\n\n  static SQInteger objectUsePos(HSQUIRRELVM v) {\n    auto *obj = EntityManager::getObject(v, 2);\n    if (!obj) {\n      return sq_throwerror(v, _SC(\"failed to get object\"));\n    }\n    SQInteger x, y, dir;\n    if (SQ_FAILED(sq_getinteger(v, 3, &x))) {\n      return sq_throwerror(v, _SC(\"failed to get x\"));\n    }\n    if (SQ_FAILED(sq_getinteger(v, 4, &y))) {\n      return sq_throwerror(v, _SC(\"failed to get y\"));\n    }\n    if (SQ_FAILED(sq_getinteger(v, 5, &dir))) {\n      return sq_throwerror(v, _SC(\"failed to get direction\"));\n    }\n    obj->setUsePosition(glm::vec2(x, y));\n    obj->setUseDirection(static_cast<UseDirection>(dir));\n    return 0;\n  }\n\n  static SQInteger objectUsePosX(HSQUIRRELVM v) {\n    auto *obj = EntityManager::getObject(v, 2);\n    if (!obj) {\n      return sq_throwerror(v, _SC(\"failed to get object\"));\n    }\n    auto usePos = obj->getUsePosition().value_or(glm::vec2());\n    sq_pushinteger(v, (SQInteger) usePos.x);\n    return 1;\n  }\n\n  static SQInteger objectUsePosY(HSQUIRRELVM v) {\n    auto *obj = EntityManager::getObject(v, 2);\n    if (!obj) {\n      return sq_throwerror(v, _SC(\"failed to get object\"));\n    }\n    auto height = obj->getRoom()->getRoomSize().y;\n    sq_pushinteger(v, (SQInteger) height - obj->getUsePosition().value_or(glm::vec2()).y);\n    return 1;\n  }\n\n  static SQInteger objectCenter(HSQUIRRELVM v) {\n    glm::vec2 pos;\n    Object *obj = EntityManager::getObject(v, 2);\n    if (obj) {\n      pos = obj->getPosition();\n      auto usePos = obj->getUsePosition().value_or(glm::vec2());\n      pos += usePos;\n    } else {\n      auto *actor = EntityManager::getActor(v, 2);\n      if (!actor) {\n        return sq_throwerror(v, _SC(\"failed to get object or actor\"));\n      }\n      pos = actor->getPosition();\n    }\n\n    ScriptEngine::push(v, pos);\n    return 1;\n  }\n\n  static SQInteger objectColor(HSQUIRRELVM v) {\n    Object *obj = EntityManager::getObject(v, 2);\n    if (!obj) {\n      return sq_throwerror(v, _SC(\"failed to get object\"));\n    }\n    SQInteger color;\n    if (SQ_FAILED(sq_getinteger(v, 3, &color))) {\n      return sq_throwerror(v, _SC(\"failed to get color\"));\n    }\n    obj->setColor(fromRgb(color));\n    return 0;\n  }\n\n  static SQInteger objectDependentOn(HSQUIRRELVM v) {\n    Object *childObject = EntityManager::getObject(v, 2);\n    if (!childObject) {\n      return sq_throwerror(v, _SC(\"failed to get childObject\"));\n    }\n    Object *parentObject = EntityManager::getObject(v, 3);\n    if (!parentObject) {\n      return sq_throwerror(v, _SC(\"failed to get parentObject\"));\n    }\n    SQInteger state;\n    if (SQ_FAILED(sq_getinteger(v, 4, &state))) {\n      return sq_throwerror(v, _SC(\"failed to get state\"));\n    }\n    childObject->dependentOn(parentObject, state);\n    return 0;\n  }\n\n  static SQInteger objectIcon(HSQUIRRELVM v) {\n    Object *obj = EntityManager::getObject(v, 2);\n    if (!obj) {\n      return sq_throwerror(v, _SC(\"failed to get object\"));\n    }\n    if (sq_gettype(v, 3) == OT_STRING) {\n      const SQChar *icon;\n      if (SQ_FAILED(sq_getstring(v, 3, &icon))) {\n        return sq_throwerror(v, _SC(\"failed to get icon\"));\n      }\n      obj->setIcon(icon);\n      return 0;\n    }\n    if (sq_gettype(v, 3) == OT_ARRAY) {\n      SQInteger fps = 0;\n      const SQChar *icon = nullptr;\n      std::vector<std::string> icons;\n      sq_push(v, 3);\n      sq_pushnull(v); // null iterator\n      if (SQ_SUCCEEDED(sq_next(v, -2))) {\n        sq_getinteger(v, -1, &fps);\n        sq_pop(v, 2);\n      }\n      while (SQ_SUCCEEDED(sq_next(v, -2))) {\n        sq_getstring(v, -1, &icon);\n        icons.emplace_back(icon);\n        sq_pop(v, 2);\n      }\n      sq_pop(v, 2); // pops the null iterator and object\n      obj->setIcon(fps, icons);\n      return 0;\n    }\n    error(\"TODO: objectIcon with type {} not implemented\", sq_gettype(v, 3));\n    return 0;\n  }\n\n  static SQInteger objectFPS(HSQUIRRELVM v) {\n    auto obj = EntityManager::getEntity(v, 2);\n    if (!obj) {\n      return sq_throwerror(v, _SC(\"failed to get object or actor\"));\n    }\n    SQInteger fps;\n    if (SQ_FAILED(sq_getinteger(v, 3, &fps))) {\n      return sq_throwerror(v, _SC(\"failed to get fps\"));\n    }\n    obj->setFps(fps);\n    return 0;\n  }\n\n  static SQInteger objectValidUsePos(HSQUIRRELVM v) {\n    Object *obj = EntityManager::getObject(v, 2);\n    if (!obj) {\n      return sq_throwerror(v, _SC(\"failed to get object\"));\n    }\n    sq_pushbool(v, obj->getUsePosition() != glm::vec2() ? SQTrue : SQFalse);\n    return 1;\n  }\n\n  static SQInteger objectValidVerb(HSQUIRRELVM v) {\n    auto *obj = EntityManager::getEntity(v, 2);\n    if (!obj) {\n      return sq_throwerror(v, _SC(\"failed to get object or actor\"));\n    }\n    SQInteger verb;\n    if (SQ_FAILED(sq_getinteger(v, 3, &verb))) {\n      return sq_throwerror(v, _SC(\"failed to get verb\"));\n    }\n    std::string name = Verb::getName(verb);\n    sq_pushobject(v, obj->getTable());\n    sq_pushstring(v, name.data(), -1);\n    SQInteger isValid = 0;\n    if (SQ_SUCCEEDED(sq_get(v, -2))) {\n      isValid = 1;\n    }\n    sq_pop(v, 2);\n    sq_pushinteger(v, isValid);\n    return 1;\n  }\n\n  static SQInteger objectShader(HSQUIRRELVM) {\n    error(\"TODO: objectShader: not implemented\");\n    return 0;\n  }\n\n  static SQInteger objectHidden(HSQUIRRELVM v) {\n    SQInteger hidden;\n    Object *obj = EntityManager::getObject(v, 2);\n    if (!obj) {\n      return 0;\n    }\n    if (SQ_FAILED(sq_getinteger(v, 3, &hidden))) {\n      return sq_throwerror(v, _SC(\"failed to get hidden\"));\n    }\n    obj->setVisible(hidden == 0);\n    return 0;\n  }\n\n  static SQInteger pickupObject(HSQUIRRELVM v) {\n    auto object = EntityManager::getObject(v, 2);\n    if (!object) {\n      return sq_throwerror(v, _SC(\"failed to get object to pickup\"));\n    }\n\n    auto actor = EntityManager::getActor(v, 3);\n    if (!actor) {\n      actor = g_pEngine->getCurrentActor();\n    }\n\n    if (!actor) {\n      error(\"There is no actor to pickup object\");\n      return 0;\n    }\n\n    if (!object->getRoom()) {\n      // if the object is not in a room, than no need to animate the actor\n      actor->pickupObject(object);\n      return 0;\n    }\n\n    sq_pushobject(v, object->getTable());\n    sq_pushstring(v, _SC(\"flags\"), -1);\n    if (SQ_FAILED(sq_rawget(v, -2))) {\n      sq_pushstring(v, _SC(\"flags\"), -1);\n      sq_pushinteger(v, 0);\n      sq_newslot(v, -3, SQFalse);\n    }\n\n    actor->pickupObject(object);\n\n    return 0;\n  }\n\n  static SQInteger pickupReplacementObject(HSQUIRRELVM v) {\n    auto *obj1 = EntityManager::getObject(v, 2);\n    if (!obj1) {\n      return sq_throwerror(v, _SC(\"failed to get object 1\"));\n    }\n    auto *obj2 = EntityManager::getObject(v, 3);\n    if (!obj2) {\n      return sq_throwerror(v, _SC(\"failed to get object 2\"));\n    }\n    auto actor = obj2->getOwner();\n    assert(actor);\n    actor->pickupReplacementObject(obj2, obj1);\n    return 0;\n  }\n\n  static SQInteger createTextObject(HSQUIRRELVM v) {\n    auto numArgs = sq_gettop(v);\n\n    const SQChar *fontName;\n    if (SQ_FAILED(sq_getstring(v, 2, &fontName))) {\n      return sq_throwerror(v, _SC(\"failed to get fontName\"));\n    }\n    auto &obj = g_pEngine->getRoom()->createTextObject(fontName);\n\n    const SQChar *text;\n    if (SQ_FAILED(sq_getstring(v, 3, &text))) {\n      return sq_throwerror(v, _SC(\"failed to get text\"));\n    }\n    std::string s(text);\n    obj.setText(s);\n    if (numArgs == 4) {\n      SQInteger alignment;\n      if (SQ_FAILED(sq_getinteger(v, 4, &alignment))) {\n        return sq_throwerror(v, _SC(\"failed to get alignment\"));\n      }\n      auto hAlign   = (uint64_t) (alignment & (uint64_t) 0x0000000070000000);\n      auto vAlign   = (uint64_t) (alignment & (uint64_t) 0xFFFFFFFFA1000000);\n      auto maxWidth = (uint64_t) (alignment & (uint64_t) 0x00000000000FFFFF);\n      TextAlignment align;\n      switch (hAlign) {\n      case 0x0000000010000000:\n        align = TextAlignment::Left;\n        break;\n      case 0x0000000020000000:\n        align = TextAlignment::Center;\n        break;\n      case 0x0000000040000000:\n        align = TextAlignment::Right;\n        break;\n      }\n      switch (vAlign) {\n      case 0x0000000001000000:\n        align |= TextAlignment::Bottom;\n        break;\n      case 0x0000000020000000:\n        align |= TextAlignment::Center;\n        break;\n      default:\n        align |= TextAlignment::Top;\n        break;\n      }\n      obj.setAlignment(align);\n      obj.setMaxWidth(static_cast<int>(maxWidth));\n    }\n    ScriptEngine::push<Object *>(v, &obj);\n    return 1;\n  }\n\n  static SQInteger setDefaultObject(HSQUIRRELVM v) {\n    auto &defaultObj = g_pEngine->getDefaultObject();\n    sq_getstackobj(v, 2, &defaultObj);\n    sq_addref(v, &defaultObj);\n    return 0;\n  }\n\n  static SQInteger shakeObject(HSQUIRRELVM v) {\n    if (sq_gettype(v, 2) == OT_NULL)\n      return 0;\n\n    auto *obj = EntityManager::getEntity(v, 2);\n    if (!obj) {\n      return sq_throwerror(v, _SC(\"failed to get object/actor\"));\n    }\n    SQFloat amount = 0;\n    if (SQ_FAILED(sq_getfloat(v, 3, &amount))) {\n      return sq_throwerror(v, _SC(\"failed to get amount\"));\n    }\n    obj->shake(amount);\n    return 0;\n  }\n\n  static SQInteger stopObjectMotors(HSQUIRRELVM v) {\n    auto *obj = EntityManager::getEntity(v, 2);\n    if (!obj) {\n      return sq_throwerror(v, _SC(\"failed to get object or actor\"));\n    }\n    obj->stopObjectMotors();\n    return 0;\n  }\n\n  static SQInteger deleteObject(HSQUIRRELVM v) {\n    auto *obj = EntityManager::getObject(v, 2);\n    if (!obj) {\n      // this function can be called with null\n      return 0;\n    }\n    g_pEngine->getRoom()->deleteObject(*obj);\n    return 0;\n  }\n\n  static void _getArray(HSQUIRRELVM v, SQInteger index, std::vector<std::string> &array) {\n    sq_push(v, index);\n    sq_pushnull(v); //null iterator\n    while (SQ_SUCCEEDED(sq_next(v, -2))) {\n      const SQChar *name;\n      sq_getstring(v, -1, &name);\n      array.emplace_back(name);\n      sq_pop(v, 2);\n    }\n    sq_pop(v, 1); //pops the null iterator\n  }\n\n  static SQInteger createObject(HSQUIRRELVM v) {\n    auto numArgs = sq_gettop(v);\n    if (numArgs == 1) {\n      auto &obj = g_pEngine->getRoom()->createObject();\n      ScriptEngine::push(v, &obj);\n      return 1;\n    }\n\n    if (numArgs == 2) {\n      std::vector<std::string> anims;\n      if (sq_gettype(v, 2) == OT_ARRAY) {\n        _getArray(v, 2, anims);\n      } else if (sq_gettype(v, 2) == OT_STRING) {\n        for (int i = 0; i < numArgs - 1; i++) {\n          const SQChar *animName;\n          sq_getstring(v, 2 + i, &animName);\n          anims.emplace_back(animName);\n        }\n      } else {\n        return sq_throwerror(v, _SC(\"createObject called with invalid type\"));\n      }\n      auto &obj = g_pEngine->getRoom()->createObject(anims);\n      ScriptEngine::push(v, &obj);\n      return 1;\n    }\n\n    HSQOBJECT obj;\n    const SQChar *sheet;\n    sq_getstring(v, 2, &sheet);\n    sq_getstackobj(v, 3, &obj);\n    if (sq_isarray(obj)) {\n      std::vector<std::string> anims;\n      _getArray(v, 3, anims);\n      auto &object = g_pEngine->getRoom()->createObject(sheet, anims);\n      ScriptEngine::push(v, &object);\n      return 1;\n    }\n\n    if (sq_isstring(obj)) {\n      const SQChar *image;\n      sq_getstring(v, 3, &image);\n      std::string s;\n      s.append(image);\n      std::size_t pos = s.find('.');\n      if (pos == std::string::npos) {\n        std::vector<std::string> anims{s};\n        auto &object = g_pEngine->getRoom()->createObject(sheet, anims);\n        ScriptEngine::push(v, &object);\n        return 1;\n      }\n\n      s = s.substr(0, pos);\n      auto &object = g_pEngine->getRoom()->createObject(s);\n      ScriptEngine::push(v, &object);\n      return 1;\n    }\n\n    return sq_throwerror(v, _SC(\"createObject called with invalid number of arguments\"));\n  }\n};\n\nEngine *ObjectPack::g_pEngine = nullptr;\n\n} // namespace ng\n"
  },
  {
    "path": "src/Scripting/PostWalk.cpp",
    "content": "#include \"PostWalk.hpp\"\n#include <engge/Entities/Object.hpp>\n#include <engge/Engine/Sentence.hpp>\n#include <engge/Scripting/ScriptEngine.hpp>\n\nnamespace ng {\nPostWalk::PostWalk(Sentence &sentence, Entity *pObject1, Entity *pObject2, int verb)\n    : m_sentence(sentence), m_pObject1(pObject1), m_pObject2(pObject2), m_verb(verb) {\n}\n\nbool PostWalk::isElapsed() { return m_done; }\n\nvoid PostWalk::operator()(const ngf::TimeSpan &) {\n  auto *pObj = dynamic_cast<Object *>(m_pObject1);\n  auto functionName = pObj ? \"objectPostWalk\" : \"actorPostWalk\";\n  bool handled = false;\n  if (ScriptEngine::rawExists(m_pObject1, functionName)) {\n    ScriptEngine::callFunc(handled, m_pObject1, functionName, m_verb, m_pObject1, m_pObject2);\n  }\n  if (handled) {\n    m_sentence.stop();\n  }\n  m_done = true;\n}\n}"
  },
  {
    "path": "src/Scripting/PostWalk.hpp",
    "content": "#pragma once\n#include <engge/Engine/Function.hpp>\n\nnamespace ng {\nclass Entity;\nclass Sentence;\n\nclass PostWalk final : public Function {\npublic:\n  PostWalk(Sentence &sentence, Entity *pObject1, Entity *pObject2, int verb);\n\n  bool isElapsed() final;\n  void operator()(const ngf::TimeSpan &) final;\n\nprivate:\n  Sentence &m_sentence;\n  Entity *m_pObject1{nullptr};\n  Entity *m_pObject2{nullptr};\n  int m_verb{0};\n  bool m_done{false};\n};\n}"
  },
  {
    "path": "src/Scripting/ReachAnim.cpp",
    "content": "#include \"ReachAnim.hpp\"\n#include <engge/Entities/Actor.hpp>\n#include <engge/Entities/Entity.hpp>\n#include <engge/Entities/Object.hpp>\n\nnamespace ng {\nReachAnim::ReachAnim(Actor &actor, Entity *obj)\n    : m_actor(actor) {\n  auto flags = obj->getFlags();\n  if (flags & ObjectFlagConstants::REACH_HIGH) {\n    m_reaching = Reaching::High;\n  } else if (flags & ObjectFlagConstants::REACH_MED) {\n    m_reaching = Reaching::Medium;\n  } else if (flags & ObjectFlagConstants::REACH_LOW) {\n    m_reaching = Reaching::Low;\n  } else {\n    m_state = 2;\n  }\n}\n\nbool ReachAnim::isElapsed() { return m_state == 3; }\n\nvoid ReachAnim::playReachAnim() {\n  m_actor.getCostume().setReachState(m_reaching);\n  m_actor.getCostume().getAnimControl().play(false);\n}\n\nvoid ReachAnim::operator()(const ngf::TimeSpan &elapsed) {\n  switch (m_state) {\n  case 0:playReachAnim();\n    m_state = 1;\n    break;\n  case 1:m_elapsed += elapsed;\n    if (m_elapsed.getTotalSeconds() > 0.330)\n      m_state = 2;\n    break;\n  case 2:m_actor.getCostume().setStandState();\n    m_state = 3;\n    break;\n  }\n}\n}"
  },
  {
    "path": "src/Scripting/ReachAnim.hpp",
    "content": "#pragma once\n#include <engge/Engine/Function.hpp>\n#include <engge/Entities/Costume.hpp>\n#include <ngf/System/TimeSpan.h>\n\nnamespace ng {\nclass Actor;\nclass Entity;\n\nclass ReachAnim final : public Function {\npublic:\n  ReachAnim(Actor &actor, Entity *obj);\n\nprivate:\n  bool isElapsed() final;\n  void playReachAnim();\n  void operator()(const ngf::TimeSpan &elapsed) final;\n\nprivate:\n  int32_t m_state{0};\n  Actor &m_actor;\n  Reaching m_reaching{Reaching::Medium};\n  ngf::TimeSpan m_elapsed;\n};\n}"
  },
  {
    "path": "src/Scripting/RoomPack.hpp",
    "content": "#pragma once\n#include <optional>\n#include <squirrel.h>\n#include \"engge/Engine/Engine.hpp\"\n#include \"engge/Engine/EngineSettings.hpp\"\n#include \"engge/Engine/Function.hpp\"\n#include \"engge/Engine/Light.hpp\"\n#include \"engge/System/Locator.hpp\"\n#include \"../Room/RoomTrigger.hpp\"\n\nnamespace ng {\nclass ChangeColor final : public TimeFunction {\npublic:\n  ChangeColor(Room *pRoom,\n              ngf::Color startColor,\n              ngf::Color endColor,\n              const ngf::TimeSpan &time,\n              std::function<float(float)> anim = Interpolations::linear,\n              bool isLooping = false)\n      : TimeFunction(time),\n        m_pRoom(pRoom),\n        m_isLooping(isLooping),\n        m_anim(std::move(anim)),\n        m_a(endColor.a - startColor.a),\n        m_r(endColor.r - startColor.r),\n        m_g(endColor.g - startColor.g),\n        m_b(endColor.b - startColor.b),\n        m_startColor(startColor),\n        m_endColor(endColor),\n        m_current(startColor) {\n  }\n\n  void operator()(const ngf::TimeSpan &elapsed) override {\n    TimeFunction::operator()(elapsed);\n    m_pRoom->setOverlayColor(m_current);\n    if (!isElapsed()) {\n      auto t = m_elapsed.getTotalSeconds() / m_time.getTotalSeconds();\n      auto f = m_anim(t);\n      m_current = plusColor(m_startColor, f);\n    }\n  }\n\n  bool isElapsed() override {\n    if (!m_isLooping)\n      return TimeFunction::isElapsed();\n    return false;\n  }\n\n  void onElapsed() override {\n    m_pRoom->setOverlayColor(m_endColor);\n  }\n\nprivate:\n  [[nodiscard]] ngf::Color plusColor(const ngf::Color &color1, float f) const {\n    auto a = color1.a + f * m_a;\n    auto r = color1.r + f * m_r;\n    auto g = color1.g + f * m_g;\n    auto b = color1.b + f * m_b;\n    return ngf::Color(r, g, b, a);\n  }\n\nprivate:\n  Room *m_pRoom{nullptr};\n  bool m_isLooping;\n  std::function<float(float)> m_anim;\n  float m_a, m_r, m_g, m_b;\n  ngf::Color m_startColor;\n  ngf::Color m_endColor;\n  ngf::Color m_current;\n};\n\nclass RoomPack final : public Pack {\nprivate:\n  static Engine *g_pEngine;\n\nprivate:\n  void registerPack() const override {\n    g_pEngine = &ScriptEngine::getEngine();\n    ScriptEngine::registerGlobalFunction(addTrigger, \"addTrigger\");\n    ScriptEngine::registerGlobalFunction(clampInWalkbox, \"clampInWalkbox\");\n    ScriptEngine::registerGlobalFunction(createLight, \"createLight\");\n    ScriptEngine::registerGlobalFunction(defineRoom, \"defineRoom\");\n    ScriptEngine::registerGlobalFunction(definePseudoRoom, \"definePseudoRoom\");\n    ScriptEngine::registerGlobalFunction(enableTrigger, \"enableTrigger\");\n    ScriptEngine::registerGlobalFunction(enterRoomFromDoor, \"enterRoomFromDoor\");\n    ScriptEngine::registerGlobalFunction(findRoom, \"findRoom\");\n    ScriptEngine::registerGlobalFunction(lightBrightness, \"lightBrightness\");\n    ScriptEngine::registerGlobalFunction(lightConeAngle, \"lightConeAngle\");\n    ScriptEngine::registerGlobalFunction(lightConeDirection, \"lightConeDirection\");\n    ScriptEngine::registerGlobalFunction(lightConeFalloff, \"lightConeFalloff\");\n    ScriptEngine::registerGlobalFunction(lightCutOffRadius, \"lightCutOffRadius\");\n    ScriptEngine::registerGlobalFunction(lightHalfRadius, \"lightHalfRadius\");\n    ScriptEngine::registerGlobalFunction(lightTurnOn, \"lightTurnOn\");\n    ScriptEngine::registerGlobalFunction(lightZRange, \"lightZRange\");\n    ScriptEngine::registerGlobalFunction(masterRoomArray, \"masterRoomArray\");\n    ScriptEngine::registerGlobalFunction(removeTrigger, \"removeTrigger\");\n    ScriptEngine::registerGlobalFunction(roomActors, \"roomActors\");\n    ScriptEngine::registerGlobalFunction(roomEffect, \"roomEffect\");\n    ScriptEngine::registerGlobalFunction(roomFade, \"roomFade\");\n    ScriptEngine::registerGlobalFunction(roomLayer, \"roomLayer\");\n    ScriptEngine::registerGlobalFunction(roomOverlayColor, \"roomOverlayColor\");\n    ScriptEngine::registerGlobalFunction(roomRotateTo, \"roomRotateTo\");\n    ScriptEngine::registerGlobalFunction(roomSize, \"roomSize\");\n    ScriptEngine::registerGlobalFunction(walkboxHidden, \"walkboxHidden\");\n  }\n\n  static SQInteger createLight(HSQUIRRELVM v) {\n    SQInteger color;\n    if (SQ_FAILED(sq_getinteger(v, 2, &color))) {\n      return sq_throwerror(v, _SC(\"failed to get color\"));\n    }\n    SQInteger x;\n    if (SQ_FAILED(sq_getinteger(v, 3, &x))) {\n      return sq_throwerror(v, _SC(\"failed to get x\"));\n    }\n    SQInteger y;\n    if (SQ_FAILED(sq_getinteger(v, 4, &y))) {\n      return sq_throwerror(v, _SC(\"failed to get y\"));\n    }\n    auto pRoom = g_pEngine->getRoom();\n    auto pLight = pRoom->createLight(fromRgba(color), {x, y});\n\n    ScriptEngine::pushObject(v, pLight);\n    sq_getstackobj(v, -1, &pLight->table);\n    sq_addref(v, &pLight->table);\n    return 1;\n  }\n\n  static SQInteger lightBrightness(HSQUIRRELVM v) {\n    Light *pLight;\n    if (!EntityManager::tryGetLight(v, 2, pLight))\n      return 0;\n\n    if (!pLight)\n      return sq_throwerror(v, _SC(\"failed to get light\"));\n\n    SQFloat brightness;\n    if (SQ_FAILED(sq_getfloat(v, 3, &brightness)))\n      return sq_throwerror(v, _SC(\"failed to get brightness\"));\n\n    pLight->brightness = brightness;\n    return 0;\n  }\n\n  static SQInteger lightConeDirection(HSQUIRRELVM v) {\n    Light *pLight;\n    if (!EntityManager::tryGetLight(v, 2, pLight))\n      return 0;\n\n    if (!pLight)\n      return sq_throwerror(v, _SC(\"failed to get light\"));\n\n    SQFloat direction;\n    if (SQ_FAILED(sq_getfloat(v, 3, &direction))) {\n      return sq_throwerror(v, _SC(\"failed to get direction\"));\n    }\n    pLight->coneDirection = direction;\n    return 0;\n  }\n\n  static SQInteger lightConeAngle(HSQUIRRELVM v) {\n    Light *pLight;\n    if (!EntityManager::tryGetLight(v, 2, pLight))\n      return 0;\n\n    if (!pLight)\n      return sq_throwerror(v, _SC(\"failed to get light\"));\n\n    SQFloat angle;\n    if (SQ_FAILED(sq_getfloat(v, 3, &angle))) {\n      return sq_throwerror(v, _SC(\"failed to get angle\"));\n    }\n    pLight->coneAngle = angle;\n    return 0;\n  }\n\n  static SQInteger lightConeFalloff(HSQUIRRELVM v) {\n    Light *pLight;\n    if (!EntityManager::tryGetLight(v, 2, pLight))\n      return 0;\n\n    if (!pLight)\n      return sq_throwerror(v, _SC(\"failed to get light\"));\n\n    SQFloat falloff;\n    if (SQ_FAILED(sq_getfloat(v, 3, &falloff))) {\n      return sq_throwerror(v, _SC(\"failed to get falloff\"));\n    }\n    pLight->coneFalloff = falloff;\n    return 0;\n  }\n\n  static SQInteger lightCutOffRadius(HSQUIRRELVM v) {\n    Light *pLight;\n    if (!EntityManager::tryGetLight(v, 2, pLight))\n      return 0;\n\n    if (!pLight)\n      return sq_throwerror(v, _SC(\"failed to get light\"));\n\n    SQFloat cutOffRadius;\n    if (SQ_FAILED(sq_getfloat(v, 3, &cutOffRadius))) {\n      return sq_throwerror(v, _SC(\"failed to get cutOffRadius\"));\n    }\n    pLight->cutOffRadius = cutOffRadius;\n    return 0;\n  }\n\n  static SQInteger lightHalfRadius(HSQUIRRELVM v) {\n    Light *pLight;\n    if (!EntityManager::tryGetLight(v, 2, pLight))\n      return 0;\n\n    if (!pLight)\n      return sq_throwerror(v, _SC(\"failed to get light\"));\n\n    SQFloat halfRadius;\n    if (SQ_FAILED(sq_getfloat(v, 3, &halfRadius))) {\n      return sq_throwerror(v, _SC(\"failed to get halfRadius\"));\n    }\n    pLight->halfRadius = halfRadius;\n    return 0;\n  }\n\n  static SQInteger lightTurnOn(HSQUIRRELVM v) {\n    Light *pLight;\n    if (!EntityManager::tryGetLight(v, 2, pLight))\n      return 0;\n\n    if (!pLight)\n      return sq_throwerror(v, _SC(\"failed to get light\"));\n\n    SQInteger on;\n    if (SQ_FAILED(sq_getinteger(v, 3, &on))) {\n      return sq_throwerror(v, _SC(\"failed to get on\"));\n    }\n    pLight->on = (on != 0);\n    return 0;\n  }\n\n  static SQInteger lightZRange(HSQUIRRELVM v) {\n    Light *pLight;\n    if (!EntityManager::tryGetLight(v, 2, pLight))\n      return 0;\n\n    if (!pLight)\n      return sq_throwerror(v, _SC(\"failed to get light\"));\n\n    SQInteger nearY, farY;\n    if (SQ_FAILED(sq_getinteger(v, 3, &nearY))) {\n      return sq_throwerror(v, _SC(\"failed to get nearY\"));\n    }\n    if (SQ_FAILED(sq_getinteger(v, 4, &farY))) {\n      return sq_throwerror(v, _SC(\"failed to get farY\"));\n    }\n    // TODO: ZRange ??\n    return 0;\n  }\n\n  static SQInteger masterRoomArray(HSQUIRRELVM v) {\n    sq_newarray(v, 0);\n    for (auto &&pRoom : g_pEngine->getRooms()) {\n      sq_pushobject(v, pRoom->getTable());\n      sq_arrayappend(v, -2);\n    }\n    return 1;\n  }\n\n  static SQInteger roomRotateTo(HSQUIRRELVM v) {\n    auto pRoom = g_pEngine->getRoom();\n    SQFloat rotation = 0;\n    if (SQ_FAILED(sq_getfloat(v, 2, &rotation))) {\n      return sq_throwerror(v, _SC(\"failed to get rotation\"));\n    }\n    auto get = [pRoom] { return pRoom->getRotation(); };\n    auto set = [pRoom](float value) { pRoom->setRotation(value); };\n    auto t = ngf::TimeSpan::seconds(0.200);\n    auto rotateTo = std::make_unique<ChangeProperty<float>>(get, set, rotation, t);\n    g_pEngine->addFunction(std::move(rotateTo));\n    return 0;\n  }\n\n  static SQInteger roomSize(HSQUIRRELVM v) {\n    auto pRoom = EntityManager::getRoom(v, 2);\n    if (!pRoom) {\n      return sq_throwerror(v, _SC(\"failed to get room\"));\n    }\n    auto size = pRoom->getRoomSize();\n    ScriptEngine::push(v, size);\n    return 1;\n  }\n\n  static SQInteger addTrigger(HSQUIRRELVM v) {\n    auto numArgs = sq_gettop(v);\n    auto object = EntityManager::getObject(v, 2);\n    if (!object) {\n      return sq_throwerror(v, _SC(\"failed to get object\"));\n    }\n    HSQOBJECT inside;\n    sq_resetobject(&inside);\n    if (SQ_FAILED(sq_getstackobj(v, 3, &inside))) {\n      return sq_throwerror(v, _SC(\"failed to get insideTriggerFunction\"));\n    }\n\n    HSQOBJECT outside;\n    sq_resetobject(&outside);\n    if (numArgs == 4) {\n      if (SQ_FAILED(sq_getstackobj(v, 4, &outside))) {\n        return sq_throwerror(v, _SC(\"failed to get outsideTriggerFunction\"));\n      }\n    }\n    auto trigger = std::make_shared<RoomTrigger>(*g_pEngine, *object, inside, outside);\n    object->addTrigger(trigger);\n\n    return 0;\n  }\n\n  static SQInteger clampInWalkbox(HSQUIRRELVM v) {\n    auto numArgs = sq_gettop(v);\n    glm::vec2 pos1, pos2;\n    if (numArgs == 3) {\n      SQInteger x = 0;\n      if (SQ_FAILED(sq_getinteger(v, 2, &x))) {\n        return sq_throwerror(v, _SC(\"failed to get x\"));\n      }\n      SQInteger y = 0;\n      if (SQ_FAILED(sq_getinteger(v, 3, &y))) {\n        return sq_throwerror(v, _SC(\"failed to get y\"));\n      }\n      pos1 = {x, y};\n      auto pActor = g_pEngine->getCurrentActor();\n      pos2 = pActor->getPosition();\n    } else if (numArgs == 5) {\n      SQInteger x1 = 0;\n      if (SQ_FAILED(sq_getinteger(v, 2, &x1))) {\n        return sq_throwerror(v, _SC(\"failed to get x1\"));\n      }\n      SQInteger y1 = 0;\n      if (SQ_FAILED(sq_getinteger(v, 3, &y1))) {\n        return sq_throwerror(v, _SC(\"failed to get y1\"));\n      }\n      pos1 = {x1, y1};\n      SQInteger x2 = 0;\n      if (SQ_FAILED(sq_getinteger(v, 2, &x2))) {\n        return sq_throwerror(v, _SC(\"failed to get x2\"));\n      }\n      SQInteger y2 = 0;\n      if (SQ_FAILED(sq_getinteger(v, 3, &y1))) {\n        return sq_throwerror(v, _SC(\"failed to get y2\"));\n      }\n      pos2 = {x2, y2};\n    } else {\n      return sq_throwerror(v, _SC(\"Invalid argument number in clampInWalkbox\"));\n    }\n    auto walkboxes = g_pEngine->getRoom()->getWalkboxes();\n    auto it = std::find_if(walkboxes.cbegin(), walkboxes.cend(), [pos2](const auto &walkbox) {\n      return walkbox.inside(pos2);\n    });\n    if (it == walkboxes.cend()) {\n      error(\"Actor's walkbox has not been found.\");\n      ScriptEngine::push(v, glm::ivec2(pos1));\n    } else {\n      auto pos = it->getClosestPointOnEdge(pos1);\n      ScriptEngine::push(v, pos);\n    }\n    return 1;\n  }\n\n  static SQInteger enableTrigger(HSQUIRRELVM v) {\n    auto object = EntityManager::getObject(v, 2);\n    if (!object) {\n      return sq_throwerror(v, _SC(\"failed to get object\"));\n    }\n    SQInteger enabled = 0;\n    if (SQ_FAILED(sq_getinteger(v, 3, &enabled))) {\n      return sq_throwerror(v, _SC(\"failed to get enabled\"));\n    }\n    object->enableTrigger(enabled != 0);\n    return 0;\n  }\n\n  static SQInteger enterRoomFromDoor(HSQUIRRELVM v) {\n    auto obj = EntityManager::getObject(v, 2);\n    return g_pEngine->enterRoomFromDoor(obj);\n  }\n\n  static SQInteger roomEffect(HSQUIRRELVM v) {\n    SQInteger effect = 0;\n    auto count = sq_gettop(v);\n    if (SQ_FAILED(sq_getinteger(v, 2, &effect))) {\n      return sq_throwerror(v, _SC(\"failed to get effect\"));\n    }\n    auto pRoom = g_pEngine->getRoom();\n    if (!pRoom)\n      return 0;\n    if (count == 14) {\n      SQInteger unused;\n      sq_getfloat(v, 3, &g_pEngine->roomEffect.iFade);\n      sq_getfloat(v, 4, &g_pEngine->roomEffect.wobbleIntensity);\n      sq_getinteger(v, 5, &unused);\n      sq_getfloat(v, 6, &g_pEngine->roomEffect.shadows.r);\n      sq_getfloat(v, 7, &g_pEngine->roomEffect.shadows.g);\n      sq_getfloat(v, 8, &g_pEngine->roomEffect.shadows.b);\n      sq_getfloat(v, 9, &g_pEngine->roomEffect.midtones.r);\n      sq_getfloat(v, 10, &g_pEngine->roomEffect.midtones.g);\n      sq_getfloat(v, 11, &g_pEngine->roomEffect.midtones.b);\n      sq_getfloat(v, 12, &g_pEngine->roomEffect.highlights.r);\n      sq_getfloat(v, 13, &g_pEngine->roomEffect.highlights.g);\n      sq_getfloat(v, 14, &g_pEngine->roomEffect.highlights.b);\n    } else {\n      g_pEngine->roomEffect.reset();\n    }\n    pRoom->setEffect(static_cast<int>(effect));\n    return 0;\n  }\n\n  static SQInteger findRoom(HSQUIRRELVM v) {\n    const SQChar *name = nullptr;\n    if (SQ_FAILED(sq_getstring(v, 2, &name))) {\n      return sq_throwerror(v, _SC(\"failed to get room name\"));\n    }\n    for (auto &&pRoom : g_pEngine->getRooms()) {\n      if (pRoom->getName() == name) {\n        sq_pushobject(v, pRoom->getTable());\n        return 1;\n      }\n    }\n    info(\"findRoom({}) -> null\", name);\n    sq_pushnull(v);\n    return 1;\n  }\n\n  static SQInteger walkboxHidden(HSQUIRRELVM v) {\n    const SQChar *name = nullptr;\n    if (SQ_FAILED(sq_getstring(v, 2, &name))) {\n      return sq_throwerror(v, _SC(\"failed to get walkbox name\"));\n    }\n    SQBool hidden;\n    sq_tobool(v, 3, &hidden);\n    g_pEngine->getRoom()->setWalkboxEnabled(name, hidden == SQFalse);\n    return 0;\n  }\n\n  static SQInteger removeTrigger(HSQUIRRELVM v) {\n    trace(\"removeTrigger\");\n    if (sq_gettype(v, 2) == OT_CLOSURE) {\n      HSQOBJECT closure;\n      sq_getstackobj(v, 2, &closure);\n      for (auto &obj : g_pEngine->getRoom()->getObjects()) {\n        auto pTrigger = obj->getTrigger();\n        if (!pTrigger)\n          continue;\n        auto pRoomTrigger = dynamic_cast<RoomTrigger *>(pTrigger);\n        if (!pRoomTrigger)\n          continue;\n        if (&pRoomTrigger->getInside() == &closure) {\n          obj->removeTrigger();\n          return 0;\n        }\n        if (&pRoomTrigger->getOutside() == &closure) {\n          obj->removeTrigger();\n          return 0;\n        }\n      }\n      return 0;\n    }\n    auto object = EntityManager::getObject(v, 2);\n    if (!object) {\n      return sq_throwerror(v, _SC(\"failed to get object\"));\n    }\n    object->removeTrigger();\n    return 0;\n  }\n\n  static SQInteger roomActors(HSQUIRRELVM v) {\n    auto pRoom = EntityManager::getRoom(v, 2);\n    if (!pRoom) {\n      return sq_throwerror(v, _SC(\"failed to get room\"));\n    }\n    sq_newarray(v, 0);\n    for (auto &&pActor : g_pEngine->getActors()) {\n      if (pActor->getRoom() != pRoom)\n        continue;\n      sq_pushobject(v, pActor->getTable());\n      sq_arrayappend(v, -2);\n    }\n    return 1;\n  }\n\n  static SQInteger roomFade(HSQUIRRELVM v) {\n    SQInteger type;\n    SQFloat t;\n    if (SQ_FAILED(sq_getinteger(v, 2, &type))) {\n      return sq_throwerror(v, _SC(\"failed to get type\"));\n    }\n    if (SQ_FAILED(sq_getfloat(v, 3, &t))) {\n      return sq_throwerror(v, _SC(\"failed to get time\"));\n    }\n    FadeEffect effect;\n    switch (type) {\n    case 0:\n      effect = FadeEffect::In;\n      break;\n    case 1:\n      effect = FadeEffect::Out;\n      break;\n    case 2:\n      effect = FadeEffect::Wobble;\n      break;\n    default: {\n      error(\"roomFade not implemented\");\n      return 0;\n    }\n    }\n    g_pEngine->fadeTo(effect, ngf::TimeSpan::seconds(t));\n    return 0;\n  }\n\n  static SQInteger roomOverlayColor(HSQUIRRELVM v) {\n    SQInteger startColor;\n    auto numArgs = sq_gettop(v);\n    if (SQ_FAILED(sq_getinteger(v, 2, &startColor))) {\n      return sq_throwerror(v, _SC(\"failed to get startColor\"));\n    }\n    auto pRoom = g_pEngine->getRoom();\n    pRoom->setOverlayColor(fromRgba(startColor));\n    if (numArgs == 4) {\n      SQInteger endColor;\n      if (SQ_FAILED(sq_getinteger(v, 3, &endColor))) {\n        return sq_throwerror(v, _SC(\"failed to get endColor\"));\n      }\n      SQFloat duration;\n      if (SQ_FAILED(sq_getfloat(v, 4, &duration))) {\n        return sq_throwerror(v, _SC(\"failed to get duration\"));\n      }\n      auto fadeTo = std::make_unique<ChangeColor>(pRoom,\n                                                  fromRgba(startColor),\n                                                  fromRgba(endColor),\n                                                  ngf::TimeSpan::seconds(duration),\n                                                  Interpolations::linear,\n                                                  false);\n      g_pEngine->addFunction(std::move(fadeTo));\n    }\n    return 0;\n  }\n\n  static SQInteger _defineRoom(HSQUIRRELVM v, HSQOBJECT roomTable, const char *name = nullptr) {\n    auto pRoom = Room::define(roomTable, name);\n    sq_pushobject(v, pRoom->getTable());\n    trace(\"Define room {}\", pRoom->getName());\n    g_pEngine->addRoom(std::move(pRoom));\n    return 1;\n  }\n\n  static SQInteger defineRoom(HSQUIRRELVM v) {\n    HSQOBJECT roomTable;\n    sq_resetobject(&roomTable);\n    sq_getstackobj(v, 2, &roomTable);\n\n    return _defineRoom(v, roomTable);\n  }\n\n  static SQInteger definePseudoRoom(HSQUIRRELVM v) {\n    const SQChar *name = nullptr;\n    if (SQ_FAILED(sq_getstring(v, 2, &name))) {\n      return sq_throwerror(v, _SC(\"failed to get name\"));\n    }\n\n    // if this is a pseudo room, we have to clone the table\n    // to have a different instance by room\n    HSQOBJECT roomTable;\n    sq_resetobject(&roomTable);\n    sq_clone(v, 3);\n    sq_getstackobj(v, -1, &roomTable);\n\n    return _defineRoom(v, roomTable, name);\n  }\n\n  static SQInteger roomLayer(HSQUIRRELVM v) {\n    auto pRoom = EntityManager::getRoom(v, 2);\n    SQInteger layer;\n    if (SQ_FAILED(sq_getinteger(v, 3, &layer))) {\n      return sq_throwerror(v, _SC(\"failed to get layer\"));\n    }\n    SQInteger enabled;\n    if (SQ_FAILED(sq_getinteger(v, 4, &enabled))) {\n      return sq_throwerror(v, _SC(\"failed to get enabled\"));\n    }\n    pRoom->roomLayer(static_cast<int>(layer), enabled != 0);\n    return 0;\n  }\n};\n\nEngine *RoomPack::g_pEngine = nullptr;\n\n} // namespace ng"
  },
  {
    "path": "src/Scripting/ScriptEngine.cpp",
    "content": "#include <cstdarg>\n#include <squirrel.h>\n#include \"../../extlibs/squirrel/squirrel/sqpcheader.h\"\n#include \"../../extlibs/squirrel/squirrel/sqvm.h\"\n#include \"../../extlibs/squirrel/squirrel/sqstring.h\"\n#include <sqstdio.h>\n#include <sqstdaux.h>\n#include <sqstdstring.h>\n#include <sqstdmath.h>\n#include \"engge/Entities/Entity.hpp\"\n#include \"engge/System/Locator.hpp\"\n#include \"engge/System/Logger.hpp\"\n#include \"engge/Engine/ExCommandConstants.hpp\"\n#include \"engge/Room/Room.hpp\"\n#include \"engge/Scripting/ScriptEngine.hpp\"\n#include \"engge/Audio/SoundDefinition.hpp\"\n#include \"engge/Scripting/VerbExecute.hpp\"\n#include \"ScriptEngine.inl\"\n#include \"SystemPack.hpp\"\n#include \"GeneralPack.hpp\"\n#include \"ObjectPack.hpp\"\n#include \"ActorPack.hpp\"\n#include \"RoomPack.hpp\"\n#include \"SoundPack.hpp\"\n#include \"DefaultScriptExecute.hpp\"\n#include \"DefaultVerbExecute.hpp\"\n#include \"BnutPass.hpp\"\n#include \"engge/Input/InputConstants.hpp\"\n#include \"engge/Engine/InputStateConstants.hpp\"\n\n#ifdef SQUNICODE\n#define scvprintf vfwprintf\n#else\n#define scvprintf vfprintf\n#endif\n\nnamespace ng {\ntemplate<typename TConstant>\nvoid ScriptEngine::registerConstants(std::initializer_list<std::tuple<const SQChar *, TConstant>> list) {\n  for (auto t : list) {\n    sq_pushconsttable(m_vm);\n    sq_pushstring(m_vm, std::get<0>(t), -1);\n    push(m_vm, std::get<1>(t));\n    sq_newslot(m_vm, -3, SQTrue);\n    sq_pop(m_vm, 1);\n  }\n}\n\ntemplate<class T>\nvoid ScriptEngine::pushObject(HSQUIRRELVM v, T *pObject) {\n  sq_newtable(v);\n  sq_pushstring(v, _SC(\"_id\"), -1);\n  sq_pushinteger(v, pObject ? pObject->getId() : 0);\n  sq_newslot(v, -3, SQFalse);\n}\n\ntemplate<typename TPack>\nvoid ScriptEngine::registerPack() {\n  auto pack = std::make_unique<TPack>();\n  auto pPack = (Pack *) pack.get();\n  pPack->registerPack();\n  m_packs.push_back(std::move(pack));\n}\n\nenum class Platform : int {\n  Mac = 1,\n  Win = 2,\n  Linux = 3,\n  Xbox = 4,\n  IOS = 5,\n  Android = 6,\n  Switch = 7,\n  PS4 = 8,\n};\n\nstatic Platform _getPlatform() {\n#ifdef __APPLE__\n#ifdef TARGET_OS_MAC\n  return Platform::Mac;\n#elif TARGET_OS_IPHONE\n  return Platform::IOS;\n#endif\n#elif _WIN32\n  return Platform::Win;\n#elif defined __linux__ && !defined __ANDROID__\n  return Platform::Linux;\n// TODO: XBOX\n//     return Platform::Xbox;\n#elif __ANDROID__\n  return Platform::Android;\n// TODO: SWITCH\n//    return Platform::Switch;\n// TODO: PS4__\n// TODO: return Platform::PS4;\n#endif\n}\n\nScriptEngine::ScriptEngine() {\n  m_vm = sq_open(1024 * 2);\n  sq_setcompilererrorhandler(m_vm, errorHandler);\n  sq_newclosure(m_vm, aux_printerror, 0);\n  sq_seterrorhandler(m_vm);\n  sq_setprintfunc(m_vm, printfunc, errorfunc); // sets the print function\n\n  sq_pushroottable(m_vm);\n  sqstd_register_mathlib(m_vm);\n  sqstd_register_stringlib(m_vm);\n  sq_pushstring(m_vm, _SC(\"PLATFORM\"), -1);\n  sq_pushinteger(m_vm, (SQInteger) _getPlatform());\n  sq_newslot(m_vm, -3, SQFalse);\n  registerConstants<int>({\n                             {\"ALL\", ObjectStateConstants::ALL},\n                             {\"HERE\", ObjectStateConstants::HERE},\n                             {\"GONE\", ObjectStateConstants::GONE},\n                             {\"OFF\", ObjectStateConstants::OFF},\n                             {\"ON\", ObjectStateConstants::ON},\n                             {\"FULL\", ObjectStateConstants::FULL},\n                             {\"EMPTY\", ObjectStateConstants::EMPTY},\n                             {\"OPEN\", ObjectStateConstants::OPEN},\n                             {\"CLOSED\", ObjectStateConstants::CLOSED},\n                             {\"FALSE\", 0},\n                             {\"TRUE\", 1},\n                             {\"MOUSE\", 1},\n                             {\"CONTROLLER\", 2},\n                             {\"DIRECTDRIVE\", 3},\n                             {\"TOUCH\", 4},\n                             {\"REMOTE\", 5},\n                             {\"FADE_IN\", 0},\n                             {\"FADE_OUT\", 1},\n                             {\"FADE_WOBBLE\", 2},\n                             {\"FADE_WOBBLE_TO_SEPIA\", 3},\n                             {\"FACE_FRONT\", DirectionConstants::FACE_FRONT},\n                             {\"FACE_BACK\", DirectionConstants::FACE_BACK},\n                             {\"FACE_LEFT\", DirectionConstants::FACE_LEFT},\n                             {\"FACE_RIGHT\", DirectionConstants::FACE_RIGHT},\n                             {\"FACE_FLIP\", DirectionConstants::FACE_FLIP},\n                             {\"DIR_FRONT\", DirectionConstants::FACE_FRONT},\n                             {\"DIR_BACK\", DirectionConstants::FACE_BACK},\n                             {\"DIR_LEFT\", DirectionConstants::FACE_LEFT},\n                             {\"DIR_RIGHT\", DirectionConstants::FACE_RIGHT},\n                             {\"LINEAR\", 0},\n                             {\"EASE_IN\", 1},\n                             {\"EASE_INOUT\", 2},\n                             {\"EASE_OUT\", 3},\n                             {\"SLOW_EASE_IN\", 4},\n                             {\"SLOW_EASE_OUT\", 5},\n                             {\"LOOPING\", 0x100},\n                             {\"SWING\", 0X200},\n                             {\"ALIGN_LEFT\",   0x0000000010000000},\n                             {\"ALIGN_CENTER\", 0x0000000020000000},\n                             {\"ALIGN_RIGHT\",  0x0000000040000000},\n                             {\"ALIGN_TOP\",    0xFFFFFFFF80000000},\n                             {\"ALIGN_BOTTOM\", 0x0000000001000000},\n                             {\"LESS_SPACING\", 0x0000000000200000},\n                             {\"EX_ALLOW_SAVEGAMES\", ExCommandConstants::EX_ALLOW_SAVEGAMES},\n                             {\"EX_POP_CHARACTER_SELECTION\", ExCommandConstants::EX_POP_CHARACTER_SELECTION},\n                             {\"EX_CAMERA_TRACKING\", ExCommandConstants::EX_CAMERA_TRACKING},\n                             {\"EX_BUTTON_HOVER_SOUND\", ExCommandConstants::EX_BUTTON_HOVER_SOUND},\n                             {\"EX_RESTART\", ExCommandConstants::EX_RESTART},\n                             {\"EX_IDLE_TIME\", ExCommandConstants::EX_IDLE_TIME},\n                             {\"EX_AUTOSAVE\", ExCommandConstants::EX_AUTOSAVE},\n                             {\"EX_AUTOSAVE_STATE\", ExCommandConstants::EX_AUTOSAVE_STATE},\n                             {\"EX_DISABLE_SAVESYSTEM\", ExCommandConstants::EX_DISABLE_SAVESYSTEM},\n                             {\"EX_SHOW_OPTIONS\", ExCommandConstants::EX_SHOW_OPTIONS},\n                             {\"EX_OPTIONS_MUSIC\", ExCommandConstants::EX_OPTIONS_MUSIC},\n                             {\"EX_FORCE_TALKIE_TEXT\", ExCommandConstants::EX_FORCE_TALKIE_TEXT},\n                             {\"GRASS_BACKANDFORTH\", 0x00},\n                             {\"EFFECT_NONE\", 0x00},\n                             {\"DOOR\", 0x40},\n                             {\"DOOR_LEFT\", 0x140},\n                             {\"DOOR_RIGHT\", 0x240},\n                             {\"DOOR_BACK\", 0x440},\n                             {\"DOOR_FRONT\", 0x840},\n                             {\"FAR_LOOK\", 0x8},\n                             {\"USE_WITH\", ObjectFlagConstants::USE_WITH},\n                             {\"USE_ON\", ObjectFlagConstants::USE_ON},\n                             {\"USE_IN\", ObjectFlagConstants::USE_IN},\n                             {\"GIVEABLE\", ObjectFlagConstants::GIVEABLE},\n                             {\"TALKABLE\", ObjectFlagConstants::TALKABLE},\n                             {\"IMMEDIATE\", ObjectFlagConstants::IMMEDIATE},\n                             {\"FEMALE\", ObjectFlagConstants::FEMALE},\n                             {\"MALE\", ObjectFlagConstants::MALE},\n                             {\"PERSON\", ObjectFlagConstants::PERSON},\n                             {\"REACH_HIGH\", ObjectFlagConstants::REACH_HIGH},\n                             {\"REACH_MED\", ObjectFlagConstants::REACH_MED},\n                             {\"REACH_LOW\", ObjectFlagConstants::REACH_LOW},\n                             {\"REACH_NONE\", ObjectFlagConstants::REACH_NONE},\n                             {\"VERB_CLOSE\", VerbConstants::VERB_CLOSE},\n                             {\"VERB_GIVE\", VerbConstants::VERB_GIVE},\n                             {\"VERB_LOOKAT\", VerbConstants::VERB_LOOKAT},\n                             {\"VERB_OPEN\", VerbConstants::VERB_OPEN},\n                             {\"VERB_PICKUP\", VerbConstants::VERB_PICKUP},\n                             {\"VERB_PULL\", VerbConstants::VERB_PULL},\n                             {\"VERB_PUSH\", VerbConstants::VERB_PUSH},\n                             {\"VERB_TALKTO\", VerbConstants::VERB_TALKTO},\n                             {\"VERB_USE\", VerbConstants::VERB_USE},\n                             {\"VERB_WALKTO\", VerbConstants::VERB_WALKTO},\n                             {\"VERB_DIALOG\", VerbConstants::VERB_DIALOG},\n                             {\"VERBFLAG_INSTANT\", 1},\n                             {\"NO\", 0},\n                             {\"YES\", 1},\n                             {\"UNSELECTABLE\", 0},\n                             {\"SELECTABLE\", 1},\n                             {\"TEMP_UNSELECTABLE\", 2},\n                             {\"TEMP_SELECTABLE\", 3},\n                             {\"MAC\", 1},\n                             {\"WIN\", 2},\n                             {\"LINUX\", 3},\n                             {\"XBOX\", 4},\n                             {\"IOS\", 5},\n                             {\"ANDROID\", 6},\n                             {\"SWITCH\", 7},\n                             {\"PS4\", 8},\n                             {\"EFFECT_NONE\", RoomEffectConstants::EFFECT_NONE},\n                             {\"EFFECT_SEPIA\", RoomEffectConstants::EFFECT_SEPIA},\n                             {\"EFFECT_EGA\", RoomEffectConstants::EFFECT_EGA},\n                             {\"EFFECT_VHS\", RoomEffectConstants::EFFECT_VHS},\n                             {\"EFFECT_GHOST\", RoomEffectConstants::EFFECT_GHOST},\n                             {\"EFFECT_BLACKANDWHITE\", RoomEffectConstants::EFFECT_BLACKANDWHITE},\n                             {\"KEY_UP\", static_cast<int>(InputConstants::KEY_UP)},\n                             {\"KEY_RIGHT\", static_cast<int>(InputConstants::KEY_RIGHT)},\n                             {\"KEY_DOWN\", static_cast<int>(InputConstants::KEY_DOWN)},\n                             {\"KEY_LEFT\", static_cast<int>(InputConstants::KEY_LEFT)},\n                             {\"KEY_PAD1\", static_cast<int>(InputConstants::KEY_PAD1)},\n                             {\"KEY_PAD2\", static_cast<int>(InputConstants::KEY_PAD2)},\n                             {\"KEY_PAD3\", static_cast<int>(InputConstants::KEY_PAD3)},\n                             {\"KEY_PAD4\", static_cast<int>(InputConstants::KEY_PAD4)},\n                             {\"KEY_PAD5\", static_cast<int>(InputConstants::KEY_PAD5)},\n                             {\"KEY_PAD6\", static_cast<int>(InputConstants::KEY_PAD6)},\n                             {\"KEY_PAD7\", static_cast<int>(InputConstants::KEY_PAD7)},\n                             {\"KEY_PAD8\", static_cast<int>(InputConstants::KEY_PAD8)},\n                             {\"KEY_PAD9\", static_cast<int>(InputConstants::KEY_PAD9)},\n                             {\"BUTTON_A\", static_cast<int>(InputConstants::BUTTON_A)},\n                             {\"BUTTON_B\", static_cast<int>(InputConstants::BUTTON_B)},\n                             {\"BUTTON_X\", static_cast<int>(InputConstants::BUTTON_X)},\n                             {\"BUTTON_Y\", static_cast<int>(InputConstants::BUTTON_Y)},\n                             {\"BUTTON_START\", static_cast<int>(InputConstants::BUTTON_START)},\n                             {\"BUTTON_BACK\", static_cast<int>(InputConstants::BUTTON_BACK)},\n                             {\"UI_INPUT_ON\", InputStateConstants::UI_INPUT_ON},\n                             {\"UI_INPUT_OFF\", InputStateConstants::UI_INPUT_OFF},\n                             {\"UI_VERBS_ON\", InputStateConstants::UI_VERBS_ON},\n                             {\"UI_VERBS_OFF\", InputStateConstants::UI_VERBS_OFF},\n                             {\"UI_CURSOR_ON\", InputStateConstants::UI_CURSOR_ON},\n                             {\"UI_CURSOR_OFF\", InputStateConstants::UI_CURSOR_OFF},\n                             {\"UI_HUDOBJECTS_ON\", InputStateConstants::UI_HUDOBJECTS_ON},\n                             {\"UI_HUDOBJECTS_OFF\", InputStateConstants::UI_HUDOBJECTS_OFF},\n                             {\"WAITING_FOR_CHOICE\", 2},\n                         });\n}\n\nScriptEngine::~ScriptEngine() {\n  sq_close(m_vm);\n}\n\nvoid ScriptEngine::setEngine(Engine &engine) {\n  g_pEngine = &engine;\n  auto pVerbExecute = std::make_unique<DefaultVerbExecute>(engine);\n  engine.setVerbExecute(std::move(pVerbExecute));\n  auto pScriptExecute = std::make_unique<DefaultScriptExecute>(m_vm);\n  engine.setScriptExecute(std::move(pScriptExecute));\n\n  registerPack<ActorPack>();\n  registerPack<GeneralPack>();\n  registerPack<ObjectPack>();\n  registerPack<RoomPack>();\n  registerPack<SoundPack>();\n  registerPack<SystemPack>();\n}\n\nEngine &ScriptEngine::getEngine() { return *g_pEngine; }\n\nSQInteger ScriptEngine::aux_printerror(HSQUIRRELVM v) {\n  auto pf = sq_geterrorfunc(v);\n  if (!pf)\n    return 0;\n\n  if (sq_gettop(v) < 1)\n    return 0;\n\n  const SQChar *error = nullptr;\n  if (SQ_FAILED(sq_getstring(v, 2, &error))) {\n    error = \"unknown\";\n  }\n  pf(v, _SC(\"\\nAn error occured in the script: %s\\n\"), error);\n  sqstd_printcallstack(v);\n\n  return 0;\n}\n\nvoid ScriptEngine::errorHandler(HSQUIRRELVM v, const SQChar *desc, const SQChar *source, SQInteger line,\n                                SQInteger column) {\n  std::ostringstream os;\n  os << desc << ' ' << source << '(' << line << ',' << column << ')';\n  for (auto &callback : m_errorCallbacks) {\n    callback(v, os.str().data());\n  }\n  error(os.str());\n}\n\nvoid ScriptEngine::errorfunc(HSQUIRRELVM v, const SQChar *s, ...) {\n  SQChar buf[1024];\n  va_list vl;\n  va_start(vl, s);\n  vsprintf(buf, s, vl);\n  va_end(vl);\n\n  for (auto &callback : m_errorCallbacks) {\n    callback(v, buf);\n  }\n  error(buf);\n}\n\nvoid ScriptEngine::printfunc(HSQUIRRELVM v, const SQChar *s, ...) {\n  std::vector<SQChar> buf(1024 * 1024);\n  va_list vl;\n  va_start(vl, s);\n  vsnprintf(buf.data(), buf.size(), s, vl);\n  va_end(vl);\n\n  for (auto &callback : m_printCallbacks) {\n    callback(v, buf.data());\n  }\n  trace(buf.data());\n}\n\nvoid ScriptEngine::registerGlobalFunction(SQFUNCTION f, const SQChar *functionName, SQInteger nparamscheck,\n                                          const SQChar *typemask) {\n  sq_pushroottable(m_vm);\n  sq_pushstring(m_vm, functionName, -1);\n  sq_newclosure(m_vm, f, 0); // create a new function\n  sq_setparamscheck(m_vm, nparamscheck, typemask);\n  sq_setnativeclosurename(m_vm, -1, functionName);\n  sq_newslot(m_vm, -3, SQFalse);\n  sq_pop(m_vm, 1); // pops the root table\n}\n\nvoid ScriptEngine::executeScript(const std::string &name) {\n  if (SQ_FAILED(sqstd_dofile(m_vm, name.c_str(), SQFalse, SQTrue))) {\n    error(\"failed to execute {}\", name);\n    sq_getlasterror(m_vm);\n    aux_printerror(m_vm);\n    return;\n  }\n}\n\nvoid ScriptEngine::executeNutScript(const std::string &name) {\n  std::vector<char> code;\n\n  std::ifstream is(name);\n  if (is.is_open()) {\n    trace(\"Load local file file {}\", name);\n    is.seekg(-1, std::ios::end);\n    auto len = (size_t) is.tellg();\n    is.seekg(0, std::ios::beg);\n    code.resize(len + 1);\n    is.read(code.data(), len);\n  } else {\n    auto entryName = std::regex_replace(name, std::regex(\"\\\\.nut\"), \".bnut\");\n    code = Locator<EngineSettings>::get().readBuffer(entryName);\n\n    // decode bnut\n    int cursor = static_cast<int>(code.size() - 1) & 0xff;\n    for (char &i : code) {\n      i ^= _bnutPass[cursor];\n      cursor = (cursor + 1) % 4096;\n    }\n  }\n\n#if 0\n  std::ofstream o;\n  o.open(name);\n  o.write(code.data(), code.size());\n  o.close();\n#endif\n  auto top = sq_gettop(m_vm);\n  sq_pushroottable(m_vm);\n  if (SQ_FAILED(sq_compilebuffer(m_vm, code.data(), code.size() - 1, _SC(name.data()), SQTrue))) {\n    error(\"Error compiling {}\", name);\n    return;\n  }\n  sq_push(m_vm, -2);\n  // call\n  if (SQ_FAILED(sq_call(m_vm, 1, SQFalse, SQTrue))) {\n    error(\"Error calling {}\", name);\n    sqstd_printcallstack(m_vm);\n    return;\n  }\n  sq_settop(m_vm, top);\n}\n\nbool ScriptEngine::rawCall(const char *name) {\n  sq_pushroottable(m_vm);\n  sq_pushstring(m_vm, _SC(name), -1);\n  if (SQ_FAILED(sq_rawget(m_vm, -2))) {\n    sq_pop(m_vm, 1);\n    trace(\"can't find {} function\", name);\n    return false;\n  }\n  sq_remove(m_vm, -2);\n\n  sq_pushroottable(m_vm);\n  if (SQ_FAILED(sq_call(m_vm, 1, SQFalse, SQTrue))) {\n    sqstd_printcallstack(m_vm);\n    sq_pop(m_vm, 1);\n    error(\"function {} call failed\", name);\n    return false;\n  }\n  sq_pop(m_vm, 1);\n  return true;\n}\n\nbool ScriptEngine::call(const char *name) {\n  sq_pushroottable(m_vm);\n  sq_pushstring(m_vm, _SC(name), -1);\n  if (SQ_FAILED(sq_get(m_vm, -2))) {\n    sq_pop(m_vm, 1);\n    trace(\"can't find {} function\", name);\n    return false;\n  }\n  sq_remove(m_vm, -2);\n\n  sq_pushroottable(m_vm);\n  if (SQ_FAILED(sq_call(m_vm, 1, SQFalse, SQTrue))) {\n    sqstd_printcallstack(m_vm);\n    sq_pop(m_vm, 1);\n    error(\"function {} call failed\", name);\n    return false;\n  }\n  sq_pop(m_vm, 1);\n  return true;\n}\n\nSQObjectPtr ScriptEngine::toSquirrel(const std::string &value) {\n  SQObjectPtr string = SQString::Create(_ss(getVm()), value.c_str());\n  return string;\n}\n\nEngine *ScriptEngine::g_pEngine = nullptr;\n\n} // namespace ng\n"
  },
  {
    "path": "src/Scripting/ScriptEngine.inl",
    "content": "#include <engge/Engine/EntityManager.hpp>\n#include <engge/Entities/Object.hpp>\n#include <engge/Entities/Entity.hpp>\n#include \"../../extlibs/squirrel/squirrel/sqobject.h\"\n#include \"../../extlibs/squirrel/squirrel/sqtable.h\"\n\nnamespace ng {\ntemplate<>\nbool ScriptEngine::get(SQInteger index, bool &result) {\n  SQInteger integer = 0;\n  auto status = SQ_SUCCEEDED(sq_getinteger(getVm(), index, &integer));\n  result = integer != 0;\n  return status;\n}\n\ntemplate<>\nbool ScriptEngine::get(SQInteger index, int &result) {\n  SQInteger integer = 0;\n  auto status = SQ_SUCCEEDED(sq_getinteger(getVm(), index, &integer));\n  result = integer;\n  return status;\n}\n\ntemplate<>\nbool ScriptEngine::get(SQInteger index, const char *&result) {\n  const SQChar *text = nullptr;\n  auto v = getVm();\n  if(sq_gettype(v, index) == OT_NULL) return true;\n  auto status = SQ_SUCCEEDED(sq_getstring(v, index, &text));\n  result = text;\n  return status;\n}\n\ntemplate<>\nbool ScriptEngine::get(SQInteger index, float &result) {\n  SQFloat value = 0;\n  auto v = getVm();\n  auto status = SQ_SUCCEEDED(sq_getfloat(v, index, &value));\n  result = value;\n  return status;\n}\n\ntemplate<>\nbool ScriptEngine::get(SQInteger index, Entity *&result) {\n  auto v = getVm();\n  result = EntityManager::getScriptObject<Entity>(v, index);\n  return result != nullptr;\n}\n\ntemplate<>\nvoid ScriptEngine::push<bool>(HSQUIRRELVM v, bool value) {\n  sq_pushbool(v, value ? SQTrue : SQFalse);\n}\n\ntemplate<>\nvoid ScriptEngine::push<int>(HSQUIRRELVM v, int value) {\n  sq_pushinteger(v, value);\n}\n\ntemplate<>\nvoid ScriptEngine::push<const char *>(HSQUIRRELVM v, const char *value) {\n  sq_pushstring(v, value, -1);\n}\n\ntemplate<>\nvoid ScriptEngine::push<char *>(HSQUIRRELVM v, char *value) {\n  sq_pushstring(v, value, -1);\n}\n\ntemplate<>\nvoid ScriptEngine::push<std::string>(HSQUIRRELVM v, std::string value) {\n  if (!value.empty()) {\n    sq_pushstring(v, value.data(), -1);\n  } else {\n    sq_pushnull(v);\n  }\n}\n\ntemplate<>\nvoid ScriptEngine::push<SQFloat>(HSQUIRRELVM v, SQFloat value) {\n  sq_pushfloat(v, value);\n}\n\ntemplate<>\nvoid ScriptEngine::push<glm::ivec2>(HSQUIRRELVM v, glm::ivec2 pos) {\n  sq_newtable(v);\n  sq_pushstring(v, _SC(\"x\"), -1);\n  sq_pushinteger(v, static_cast<int>(pos.x));\n  sq_newslot(v, -3, SQFalse);\n  sq_pushstring(v, _SC(\"y\"), -1);\n  sq_pushinteger(v, static_cast<int>(pos.y));\n  sq_newslot(v, -3, SQFalse);\n}\n\ntemplate<>\nvoid ScriptEngine::push<ngf::irect>(HSQUIRRELVM v, ngf::irect rect) {\n  sq_newtable(v);\n  sq_pushstring(v, _SC(\"x1\"), -1);\n  sq_pushinteger(v, rect.getTopLeft().x);\n  sq_newslot(v, -3, SQFalse);\n  sq_pushstring(v, _SC(\"y1\"), -1);\n  sq_pushinteger(v, rect.getTopLeft().y);\n  sq_newslot(v, -3, SQFalse);\n  sq_pushstring(v, _SC(\"x2\"), -1);\n  sq_pushinteger(v, rect.getBottomRight().x);\n  sq_newslot(v, -3, SQFalse);\n  sq_pushstring(v, _SC(\"y2\"), -1);\n  sq_pushinteger(v, rect.getBottomRight().y);\n  sq_newslot(v, -3, SQFalse);\n}\n\ntemplate<>\nvoid ScriptEngine::push<glm::vec2>(HSQUIRRELVM v, glm::vec2 pos) {\n  return ScriptEngine::push(v, (glm::ivec2) pos);\n}\n\ntemplate<>\nvoid ScriptEngine::push<Entity *>(HSQUIRRELVM v, Entity *pEntity) {\n  if (!pEntity) {\n    sq_pushnull(v);\n    return;\n  }\n  sq_pushobject(v, pEntity->getTable());\n}\n\ntemplate<>\nvoid ScriptEngine::push<const Entity *>(HSQUIRRELVM v, const Entity *pEntity) {\n  if (!pEntity) {\n    sq_pushnull(v);\n    return;\n  }\n  sq_pushobject(v, pEntity->getTable());\n}\n\ntemplate<>\nvoid ScriptEngine::push<Actor *>(HSQUIRRELVM v, Actor *pActor) {\n  if (!pActor) {\n    sq_pushnull(v);\n    return;\n  }\n  sq_pushobject(v, pActor->getTable());\n}\n\ntemplate<>\nvoid ScriptEngine::push<Room *>(HSQUIRRELVM v, Room *pRoom) {\n  if (!pRoom) {\n    sq_pushnull(v);\n    return;\n  }\n  sq_pushobject(v, pRoom->getTable());\n}\n\ntemplate<>\nvoid ScriptEngine::push<Object *>(HSQUIRRELVM v, Object *pObject) {\n  if (!pObject) {\n    sq_pushnull(v);\n    return;\n  }\n  sq_pushobject(v, pObject->getTable());\n}\n\ntemplate<>\nvoid ScriptEngine::push<ScriptObject *>(HSQUIRRELVM v, ScriptObject *pObject) {\n  if (!pObject) {\n    sq_pushnull(v);\n    return;\n  }\n  auto pEntity = dynamic_cast<Entity *>(pObject);\n  if (pEntity) {\n    sq_pushobject(v, pEntity->getTable());\n    return;\n  }\n  auto pRoom = dynamic_cast<Room *>(pObject);\n  if (pRoom) {\n    sq_pushobject(v, pRoom->getTable());\n    return;\n  }\n  throw std::logic_error(\"Unable to push an unknown ScriptObject type\");\n}\n\ntemplate<>\nvoid ScriptEngine::push<std::nullptr_t>(HSQUIRRELVM v, std::nullptr_t) {\n  sq_pushnull(v);\n}\n\ntemplate<>\nvoid ScriptEngine::push<HSQOBJECT>(HSQUIRRELVM v, HSQOBJECT obj) {\n  sq_pushobject(v, obj);\n}\n\ntemplate<>\nvoid ScriptEngine::push<SQObjectPtr>(HSQUIRRELVM v, SQObjectPtr obj) {\n  sq_pushobject(v, obj);\n}\n\n}\n"
  },
  {
    "path": "src/Scripting/SetDefaultVerb.cpp",
    "content": "#include \"SetDefaultVerb.hpp\"\n#include <engge/Engine/Engine.hpp>\n\nnamespace ng {\nSetDefaultVerb::SetDefaultVerb(Engine &engine) : m_engine(engine) {}\n\nbool SetDefaultVerb::isElapsed() { return m_done; }\n\nvoid SetDefaultVerb::operator()(const ngf::TimeSpan &) {\n  if (m_done)\n    return;\n\n  m_done = true;\n  m_engine.setDefaultVerb();\n}\n}"
  },
  {
    "path": "src/Scripting/SetDefaultVerb.hpp",
    "content": "#pragma once\n#include <engge/Engine/Function.hpp>\n\nnamespace ng {\nclass Engine;\n\nclass SetDefaultVerb final : public Function {\npublic:\n  explicit SetDefaultVerb(Engine &engine);\n\n  bool isElapsed() final;\n  void operator()(const ngf::TimeSpan &) final;\n\nprivate:\n  Engine &m_engine;\n  bool m_done{false};\n};\n}"
  },
  {
    "path": "src/Scripting/SoundPack.hpp",
    "content": "#pragma once\n#include <random>\n#include <squirrel.h>\n#include \"engge/Engine/Engine.hpp\"\n#include \"engge/Audio/SoundTrigger.hpp\"\n\nnamespace ng {\nclass SoundPack final : public Pack {\nprivate:\n  static Engine *g_pEngine;\n\nprivate:\n  void registerPack() const override {\n    g_pEngine = &ScriptEngine::getEngine();\n    ScriptEngine::registerGlobalFunction(actorSound, \"actorSound\");\n    ScriptEngine::registerGlobalFunction(defineSound, \"defineSound\");\n    ScriptEngine::registerGlobalFunction(fadeOutSound, \"fadeOutSound\");\n    ScriptEngine::registerGlobalFunction(isSoundPlaying, \"isSoundPlaying\");\n    ScriptEngine::registerGlobalFunction(loadSound, \"loadSound\");\n    ScriptEngine::registerGlobalFunction(loopSound, \"loopSound\");\n    ScriptEngine::registerGlobalFunction(loopObjectSound, \"loopObjectSound\");\n    ScriptEngine::registerGlobalFunction(loopMusic, \"loopMusic\");\n    ScriptEngine::registerGlobalFunction(masterSoundVolume, \"masterSoundVolume\");\n    ScriptEngine::registerGlobalFunction(playMusic, \"playMusic\");\n    ScriptEngine::registerGlobalFunction(playSound, \"playSound\");\n    ScriptEngine::registerGlobalFunction(playSoundVolume, \"playSoundVolume\");\n    ScriptEngine::registerGlobalFunction(playObjectSound, \"playObjectSound\");\n    ScriptEngine::registerGlobalFunction(soundVolume, \"soundVolume\");\n    ScriptEngine::registerGlobalFunction(soundMixVolume, \"soundMixVolume\");\n    ScriptEngine::registerGlobalFunction(musicMixVolume, \"musicMixVolume\");\n    ScriptEngine::registerGlobalFunction(talkieMixVolume, \"talkieMixVolume\");\n    ScriptEngine::registerGlobalFunction(stopAllSounds, \"stopAllSounds\");\n    ScriptEngine::registerGlobalFunction(stopSound, \"stopSound\");\n  }\n\n  static bool _getArray(HSQUIRRELVM v,\n                        SQInteger index,\n                        SQInteger size,\n                        std::vector<std::shared_ptr<SoundDefinition>> &array) {\n    for (auto i = 0; i < static_cast<int>(size); i++) {\n      auto pSound = EntityManager::getSoundDefinition(v, index + i);\n      if (!pSound)\n        return false;\n      array.push_back(pSound);\n    }\n    return true;\n  }\n\n  static bool _getArray(HSQUIRRELVM v, SQInteger index, std::vector<std::shared_ptr<SoundDefinition>> &array) {\n    HSQOBJECT paramObj;\n    sq_resetobject(&paramObj);\n    sq_getstackobj(v, index, &paramObj);\n    if (!sq_isarray(paramObj))\n      return false;\n\n    sq_push(v, 3);\n    sq_pushnull(v); //null iterator\n    while (SQ_SUCCEEDED(sq_next(v, -2))) {\n      auto pSound = EntityManager::getSoundDefinition(v, -1);\n      if (!pSound)\n        return false;\n      array.emplace_back(pSound);\n      sq_pop(v, 2);\n    }\n    sq_pop(v, 1); //pops the null iterator\n    return true;\n  }\n\n  static SQInteger actorSound(HSQUIRRELVM v) {\n    auto pEntity = EntityManager::getEntity(v, 2);\n    if (!pEntity) {\n      return sq_throwerror(v, _SC(\"failed to get actor or object\"));\n    }\n    SQInteger triggerNumber;\n    if (SQ_FAILED(sq_getinteger(v, 3, &triggerNumber))) {\n      return sq_throwerror(v, _SC(\"failed to get triggerNumber\"));\n    }\n\n    auto numSounds = sq_gettop(v) - 3;\n    if (numSounds == 0) {\n      return 0;\n    }\n\n    SQInteger tmp;\n    if (numSounds == 1 && SQ_SUCCEEDED(sq_getinteger(v, 4, &tmp)) && !tmp) {\n      pEntity->removeTrigger(triggerNumber);\n      return 0;\n    }\n\n    std::vector<std::shared_ptr<SoundDefinition>> sounds;\n    if (numSounds >= 1 || !_getArray(v, 4, sounds)) {\n      if (!_getArray(v, 4, numSounds, sounds)) {\n        return sq_throwerror(v, _SC(\"failed to get sounds\"));\n      }\n    }\n\n    auto *pSound = pEntity->createSoundTrigger(*g_pEngine, sounds);\n    pEntity->setTrigger(triggerNumber, pSound);\n    return 0;\n  }\n\n  static SQInteger loopMusic(HSQUIRRELVM v) {\n    auto pSound = EntityManager::getSoundDefinition(v, 2);\n    if (!pSound) {\n      return sq_throwerror(v, _SC(\"failed to get music\"));\n    }\n    auto music = g_pEngine->getSoundManager().playMusic(pSound, -1);\n    ScriptEngine::pushObject(v, music.get());\n    return 1;\n  }\n\n  static SQInteger masterSoundVolume(HSQUIRRELVM v) {\n    SQFloat volume = 0;\n    if (SQ_FAILED(sq_getfloat(v, 2, &volume))) {\n      return sq_throwerror(v, _SC(\"failed to get volume\"));\n    }\n    g_pEngine->getSoundManager().setMasterVolume(volume);\n    return 0;\n  }\n\n  static SQInteger defineSound(HSQUIRRELVM v) {\n    const SQChar *filename;\n    if (SQ_FAILED(sq_getstring(v, 2, &filename))) {\n      return sq_throwerror(v, _SC(\"failed to get filename\"));\n    }\n    auto sound = g_pEngine->getSoundManager().defineSound(filename);\n    ScriptEngine::pushObject(v, sound.get());\n    return 1;\n  }\n\n  static SQInteger loopObjectSound(HSQUIRRELVM v) {\n    auto pSound = EntityManager::getSoundDefinition(v, 2);\n    if (!pSound) {\n      return sq_throwerror(v, _SC(\"failed to get sound\"));\n    }\n    auto pEntity = EntityManager::getEntity(v, 3);\n    if (!pEntity) {\n      return sq_throwerror(v, _SC(\"failed to get actor or object\"));\n    }\n    SQInteger loopTimes = -1;\n    sq_getinteger(v, 4, &loopTimes);\n    SQFloat fadeInTime = 0;\n    sq_getfloat(v, 5, &fadeInTime);\n    auto pSoundId =\n        g_pEngine->getSoundManager().playSound(pSound, loopTimes, ngf::TimeSpan::seconds(fadeInTime), pEntity->getId());\n    if (!pSoundId) {\n      sq_pushnull(v);\n      return 1;\n    }\n    ScriptEngine::pushObject(v, pSoundId.get());\n    return 1;\n  }\n\n  static SQInteger loadSound(HSQUIRRELVM v) {\n    auto pSound = EntityManager::getSoundDefinition(v, 2);\n    if (!pSound) {\n      return sq_throwerror(v, _SC(\"failed to get sound\"));\n    }\n    pSound->load();\n    return 0;\n  }\n\n  static SQInteger loopSound(HSQUIRRELVM v) {\n    auto pSound = EntityManager::getSoundDefinition(v, 2);\n    if (!pSound) {\n      return sq_throwerror(v, _SC(\"failed to get sound\"));\n    }\n    SQInteger loopTimes = -1;\n    sq_getinteger(v, 3, &loopTimes);\n    SQFloat fadeInTime = 0;\n    sq_getfloat(v, 4, &fadeInTime);\n    auto pSoundId = g_pEngine->getSoundManager().playSound(pSound, loopTimes, ngf::TimeSpan::seconds(fadeInTime));\n    ScriptEngine::pushObject(v, pSoundId.get());\n    return 1;\n  }\n\n  static SQInteger fadeOutSound(HSQUIRRELVM v) {\n    auto pSound = EntityManager::getSound(v, 2);\n    float t;\n    if (SQ_FAILED(sq_getfloat(v, 3, &t))) {\n      return sq_throwerror(v, _SC(\"failed to get fadeOut time\"));\n    }\n    auto time = ngf::TimeSpan::seconds(t);\n    if (pSound) {\n      pSound->stop(time);\n      return 0;\n    }\n\n    auto pSoundDefinition = EntityManager::getSoundDefinition(v, 2);\n    if (pSoundDefinition == nullptr) {\n      error(\"no sound to fadeOutSound\");\n      return 0;\n    }\n    auto size = g_pEngine->getSoundManager().getSize();\n    for (size_t i = 1; i <= size; i++) {\n      auto pSound2 = g_pEngine->getSoundManager().getSound(i);\n      if (pSound2 && pSound2->getSoundDefinition() == pSoundDefinition) {\n        pSound2->stop(time);\n      }\n    }\n    return 0;\n  }\n\n  static SQInteger isSoundPlaying(HSQUIRRELVM v) {\n    auto pSound = EntityManager::getSound(v, 2);\n    if (pSound) {\n      sq_pushinteger(v, pSound->isPlaying() ? 1 : 0);\n      return 1;\n    }\n    auto pSoundDef = EntityManager::getSoundDefinition(v, 2);\n    if (!pSoundDef) {\n      sq_pushinteger(v, 0);\n      return 1;\n    }\n\n    for (size_t i = 1; i <= g_pEngine->getSoundManager().getSize(); i++) {\n      auto sound = g_pEngine->getSoundManager().getSound(i);\n      if (sound && pSoundDef == sound->getSoundDefinition() && sound->isPlaying()) {\n        sq_pushinteger(v, 1);\n        return 1;\n      }\n    }\n    sq_pushinteger(v, 0);\n    return 1;\n  }\n\n  static SQInteger playObjectSound(HSQUIRRELVM v) {\n    auto pSound = EntityManager::getSoundDefinition(v, 2);\n    if (!pSound) {\n      return sq_throwerror(v, _SC(\"failed to get sound\"));\n    }\n    auto pEntity = EntityManager::getEntity(v, 3);\n    if (!pEntity) {\n      return sq_throwerror(v, _SC(\"failed to get actor or object\"));\n    }\n    SQInteger loopTimes = 1;\n    sq_getinteger(v, 4, &loopTimes);\n    SQFloat fadeInTime = 0;\n    sq_getfloat(v, 5, &fadeInTime);\n    auto soundId =\n        g_pEngine->getSoundManager().playSound(pSound, loopTimes, ngf::TimeSpan::seconds(fadeInTime), pEntity->getId());\n    ScriptEngine::pushObject(v, soundId.get());\n    return 1;\n  }\n\n  static SQInteger playMusic(HSQUIRRELVM v) {\n    auto pSound = EntityManager::getSoundDefinition(v, 2);\n    if (!pSound) {\n      return sq_throwerror(v, _SC(\"failed to get music\"));\n    }\n    auto soundId = g_pEngine->getSoundManager().playMusic(pSound);\n    ScriptEngine::pushObject(v, soundId.get());\n\n    return 1;\n  }\n\n  static SQInteger playSound(HSQUIRRELVM v) {\n    auto pSound = EntityManager::getSoundDefinition(v, 2);\n    if (!pSound) {\n      return sq_throwerror(v, _SC(\"failed to get sound\"));\n    }\n    auto soundId = g_pEngine->getSoundManager().playSound(pSound);\n    ScriptEngine::pushObject(v, soundId.get());\n\n    return 1;\n  }\n\n  static SQInteger playSoundVolume(HSQUIRRELVM v) {\n    auto pSound = EntityManager::getSoundDefinition(v, 2);\n    if (!pSound) {\n      return sq_throwerror(v, _SC(\"failed to get sound\"));\n    }\n    SQFloat volume = 0;\n    if (SQ_FAILED(sq_getfloat(v, 3, &volume))) {\n      return sq_throwerror(v, _SC(\"failed to get volume\"));\n    }\n    auto soundId = g_pEngine->getSoundManager().playSound(pSound);\n    if (soundId) {\n      soundId->getSoundHandle()->get().setVolume(volume);\n    }\n    ScriptEngine::pushObject(v, soundId.get());\n    return 1;\n  }\n\n  static SQInteger soundMixVolume(HSQUIRRELVM v) {\n    SQFloat volume = 0;\n    if (SQ_FAILED(sq_getfloat(v, 2, &volume))) {\n      return sq_throwerror(v, _SC(\"failed to get volume\"));\n    }\n    g_pEngine->getSoundManager().setSoundVolume(volume);\n    return 0;\n  }\n\n  static SQInteger musicMixVolume(HSQUIRRELVM v) {\n    SQFloat volume = 0;\n    if (SQ_FAILED(sq_getfloat(v, 2, &volume))) {\n      return sq_throwerror(v, _SC(\"failed to get volume\"));\n    }\n    g_pEngine->getSoundManager().setMusicVolume(volume);\n    return 0;\n  }\n\n  static SQInteger talkieMixVolume(HSQUIRRELVM v) {\n    SQFloat volume = 0;\n    if (SQ_FAILED(sq_getfloat(v, 2, &volume))) {\n      return sq_throwerror(v, _SC(\"failed to get volume\"));\n    }\n    g_pEngine->getSoundManager().setTalkVolume(volume);\n    return 0;\n  }\n\n  static SQInteger soundVolume(HSQUIRRELVM v) {\n    SQFloat volume = 0;\n    if (SQ_FAILED(sq_getfloat(v, 3, &volume))) {\n      return sq_throwerror(v, _SC(\"failed to get volume\"));\n    }\n    auto pSound = EntityManager::getSound(v, 2);\n    if (pSound) {\n      pSound->getSoundHandle()->get().setVolume(volume);\n      return 0;\n    }\n    auto pSoundDef = EntityManager::getSoundDefinition(v, 2);\n    if (pSoundDef) {\n      g_pEngine->getSoundManager().setVolume(pSoundDef.get(), volume);\n    }\n    return 0;\n  }\n\n  static SQInteger stopAllSounds(HSQUIRRELVM) {\n    g_pEngine->getSoundManager().stopAllSounds();\n    return 0;\n  }\n\n  static SQInteger stopSound(HSQUIRRELVM v) {\n    auto pSound = EntityManager::getSound(v, 2);\n    if (pSound) {\n      pSound->stop();\n      return 0;\n    }\n    auto pSoundDef = EntityManager::getSoundDefinition(v, 2);\n    if (pSoundDef) {\n      g_pEngine->getSoundManager().stopSound(pSoundDef);\n    }\n    return 0;\n  }\n};\n\nEngine *SoundPack::g_pEngine = nullptr;\n\n} // namespace ng\n"
  },
  {
    "path": "src/Scripting/SystemPack.hpp",
    "content": "#pragma once\n#include <squirrel.h>\n#include \"../../extlibs/squirrel/squirrel/sqpcheader.h\"\n#include \"../../extlibs/squirrel/squirrel/sqvm.h\"\n#include \"../../extlibs/squirrel/squirrel/sqstring.h\"\n#include \"../../extlibs/squirrel/squirrel/sqtable.h\"\n#include \"../../extlibs/squirrel/squirrel/sqarray.h\"\n#include \"../../extlibs/squirrel/squirrel/sqfuncproto.h\"\n#include \"../../extlibs/squirrel/squirrel/sqclosure.h\"\n#include <engge/Entities/Actor.hpp>\n#include <engge/Engine/Camera.hpp>\n#include <engge/Dialog/DialogManager.hpp>\n#include <engge/Engine/Engine.hpp>\n#include <engge/Engine/Function.hpp>\n#include <engge/System/Logger.hpp>\n#include <engge/Engine/Preferences.hpp>\n#include <engge/Room/Room.hpp>\n#include <engge/Audio/SoundId.hpp>\n#include <engge/Audio/SoundManager.hpp>\n#include <engge/Engine/Thread.hpp>\n#include <Engine/AchievementManager.hpp>\n#include \"Util/Util.hpp\"\n\n#define SQ_SUSPEND_FLAG -666\n\nnamespace ng {\nclass BreakFunction : public Function {\nprotected:\n  Engine &m_engine;\n  int m_threadId;\n  bool m_done{false};\n\npublic:\n  explicit BreakFunction(Engine &engine, int id)\n      : m_engine(engine), m_threadId(id) {\n  }\n\n  [[nodiscard]] virtual std::string getName() const {\n    return \"_BreakFunction \";\n  }\n\n  void operator()(const ngf::TimeSpan &) override {\n    if (m_done)\n      return;\n\n    if (!isElapsed())\n      return;\n\n    m_done = true;\n    auto pThread = EntityManager::getThreadFromId(m_threadId);\n    if (!pThread)\n      return;\n    pThread->resume();\n  }\n};\n\nclass BreakHereFunction final : public BreakFunction {\npublic:\n  explicit BreakHereFunction(Engine &engine, int id, int numFrames)\n      : BreakFunction(engine, id), m_fc(engine.getFrameCounter()), m_numFrames(numFrames) {\n  }\n\n  bool isElapsed() override {\n    return m_engine.getFrameCounter() >= (m_fc + m_numFrames);\n  }\n\n  [[nodiscard]] std::string getName() const override {\n    return \"_BreakHereFunction\";\n  }\n\nprivate:\n  int m_fc;\n  int m_numFrames;\n};\n\nclass BreakWhileAnimatingFunction final : public BreakFunction {\nprivate:\n  std::string m_name;\n  Actor &m_actor;\n  Animation *m_pAnimation;\n\npublic:\n  BreakWhileAnimatingFunction(Engine &engine, int id, Actor &actor)\n      : BreakFunction(engine, id), m_actor(actor), m_pAnimation(actor.getCostume().getAnimation()) {\n    m_name = m_pAnimation->name;\n  }\n\n  [[nodiscard]] std::string getName() const override {\n    return \"_BreakWhileAnimatingFunction \" + m_name;\n  }\n\n  bool isElapsed() override {\n    auto animControl = m_actor.getCostume().getAnimControl();\n    return animControl.getAnimation() != m_pAnimation || animControl.getState() != AnimState::Play;\n  }\n};\n\nclass BreakWhileAnimatingObjectFunction final : public BreakFunction {\nprivate:\n  Object &m_object;\n  std::optional<Animation *> m_animation;\n\npublic:\n  BreakWhileAnimatingObjectFunction(Engine &engine, int id, Object &object)\n      : BreakFunction(engine, id), m_object(object), m_animation(object.getAnimation()) {\n  }\n\n  [[nodiscard]] std::string getName() const override {\n    return \"_BreakWhileAnimatingObjectFunction\";\n  }\n\n  bool isElapsed() override {\n    return !m_animation.has_value() || m_object.getAnimControl().getState() != AnimState::Play;\n  }\n};\n\nclass BreakWhileWalkingFunction final : public BreakFunction {\nprivate:\n  Actor &m_actor;\n\npublic:\n  explicit BreakWhileWalkingFunction(Engine &engine, int id, Actor &actor)\n      : BreakFunction(engine, id), m_actor(actor) {\n  }\n\n  [[nodiscard]] std::string getName() const override {\n    return \"_BreakWhileWalkingFunction\";\n  }\n\n  bool isElapsed() override {\n    return !m_actor.isWalking();\n  }\n};\n\nclass BreakWhileTalkingFunction final : public BreakFunction {\nprivate:\n  Entity &m_entity;\n\npublic:\n  explicit BreakWhileTalkingFunction(Engine &engine, int id, Entity &entity)\n      : BreakFunction(engine, id), m_entity(entity) {\n  }\n\n  [[nodiscard]] std::string getName() const override {\n    return \"_BreakWhileTalkingFunction\";\n  }\n\n  bool isElapsed() override {\n    return !m_entity.isTalking();\n  }\n};\n\nclass BreakWhileAnyActorTalkingFunction final : public BreakFunction {\npublic:\n  explicit BreakWhileAnyActorTalkingFunction(Engine &engine, int id)\n      : BreakFunction(engine, id) {\n  }\n\n  [[nodiscard]] std::string getName() const override {\n    return \"_BreakWhileAnyActorTalkingFunction\";\n  }\n\n  bool isElapsed() override {\n    for (auto &&actor : m_engine.getActors()) {\n      if (actor->isTalking())\n        return false;\n    }\n    return true;\n  }\n};\n\nclass BreakWhileSoundFunction final : public BreakFunction {\nprivate:\n  int m_soundId;\n\npublic:\n  BreakWhileSoundFunction(Engine &engine, int id, int soundId)\n      : BreakFunction(engine, id), m_soundId(soundId) {\n  }\n\n  [[nodiscard]] std::string getName() const override {\n    return \"_BreakWhileSoundFunction\";\n  }\n\n  bool isElapsed() override {\n    auto pSoundId = dynamic_cast<SoundId *>(EntityManager::getSoundFromId(m_soundId));\n    return !pSoundId || !pSoundId->isPlaying();\n  }\n};\n\nclass BreakWhileRunningFunction final : public Function {\nprivate:\n  int m_currentThreadId, m_threadId;\n  bool m_done;\n\npublic:\n  BreakWhileRunningFunction(int currentThreadId, int threadId)\n      : m_currentThreadId(currentThreadId), m_threadId(threadId), m_done(false) {\n  }\n\n  void operator()(const ngf::TimeSpan &) override {\n    if (m_done)\n      return;\n\n    auto pThread = EntityManager::getThreadFromId(m_threadId);\n    if (!pThread || pThread->isStopped()) {\n      auto pCurrentThread = EntityManager::getThreadFromId(m_currentThreadId);\n      if (pCurrentThread) {\n        pCurrentThread->resume();\n      }\n      m_done = true;\n    }\n  }\n\n  bool isElapsed() override {\n    return m_done;\n  }\n};\n\nclass BreakWhileDialogFunction final : public BreakFunction {\npublic:\n  BreakWhileDialogFunction(Engine &engine, int id)\n      : BreakFunction(engine, id) {\n  }\n\n  [[nodiscard]] std::string getName() const override {\n    return \"_BreakWhileDialogFunction\";\n  }\n\n  bool isElapsed() override {\n    return m_engine.getDialogManager().getState() == DialogManagerState::None;\n  }\n};\n\nclass BreakWhileCutsceneFunction final : public BreakFunction {\npublic:\n  BreakWhileCutsceneFunction(Engine &engine, int id)\n      : BreakFunction(engine, id) {\n  }\n\n  [[nodiscard]] std::string getName() const override {\n    return \"_BreakWhileCutsceneFunction\";\n  }\n\n  bool isElapsed() override {\n    return !m_engine.inCutscene();\n  }\n};\n\nclass BreakWhileCameraFunction final : public BreakFunction {\npublic:\n  BreakWhileCameraFunction(Engine &engine, int id)\n      : BreakFunction(engine, id) {\n  }\n\n  [[nodiscard]] std::string getName() const override {\n    return \"_BreakWhileCameraFunction\";\n  }\n\n  bool isElapsed() override {\n    return !m_engine.getCamera().isMoving();\n  }\n};\n\nclass BreakWhileInputOffFunction final : public BreakFunction {\npublic:\n  BreakWhileInputOffFunction(Engine &engine, int id)\n      : BreakFunction(engine, id) {\n  }\n\n  [[nodiscard]] std::string getName() const override {\n    return \"_BreakWhileInputOffFunction\";\n  }\n\n  bool isElapsed() override {\n    return m_engine.getInputActive();\n  }\n};\n\nclass BreakTimeFunction final : public TimeFunction {\nprivate:\n  int m_threadId;\n\npublic:\n  BreakTimeFunction(int id, const ngf::TimeSpan &time)\n      : TimeFunction(time), m_threadId(id) {\n  }\n\n  void operator()(const ngf::TimeSpan &elapsed) override {\n    if (m_done)\n      return;\n    TimeFunction::operator()(elapsed);\n    if (isElapsed()) {\n      m_done = true;\n      auto pThread = EntityManager::getThreadFromId(m_threadId);\n      if (!pThread)\n        return;\n      pThread->resume();\n    }\n  }\n};\n\nclass SystemPack final : public Pack {\nprivate:\n  static Engine *g_pEngine;\n\nprivate:\n  void registerPack() const override {\n    g_pEngine = &ScriptEngine::getEngine();\n    ScriptEngine::registerGlobalFunction(activeController, \"activeController\");\n    ScriptEngine::registerGlobalFunction(addCallback, \"addCallback\");\n    ScriptEngine::registerGlobalFunction(addFolder, \"addFolder\");\n    ScriptEngine::registerGlobalFunction(breakhere, \"breakhere\");\n    ScriptEngine::registerGlobalFunction(breaktime, \"breaktime\");\n    ScriptEngine::registerGlobalFunction(breakwhileanimating, \"breakwhileanimating\");\n    ScriptEngine::registerGlobalFunction(breakwhilecamera, \"breakwhilecamera\");\n    ScriptEngine::registerGlobalFunction(breakwhilecutscene, \"breakwhilecutscene\");\n    ScriptEngine::registerGlobalFunction(breakwhiledialog, \"breakwhiledialog\");\n    ScriptEngine::registerGlobalFunction(breakwhileinputoff, \"breakwhileinputoff\");\n    ScriptEngine::registerGlobalFunction(breakwhilesound, \"breakwhilesound\");\n    ScriptEngine::registerGlobalFunction(breakwhilerunning, \"breakwhilerunning\");\n    ScriptEngine::registerGlobalFunction(breakwhiletalking, \"breakwhiletalking\");\n    ScriptEngine::registerGlobalFunction(breakwhilewalking, \"breakwhilewalking\");\n    ScriptEngine::registerGlobalFunction(chr, \"chr\");\n    ScriptEngine::registerGlobalFunction(cursorPosX, \"cursorPosX\");\n    ScriptEngine::registerGlobalFunction(cursorPosY, \"cursorPosY\");\n    ScriptEngine::registerGlobalFunction(dumpvar, \"dumpvar\");\n    ScriptEngine::registerGlobalFunction(dumprt, \"dumprt\");\n    ScriptEngine::registerGlobalFunction(exCommand, \"exCommand\");\n    ScriptEngine::registerGlobalFunction(gameTime, \"gameTime\");\n    ScriptEngine::registerGlobalFunction(getPrivatePref, \"getPrivatePref\");\n    ScriptEngine::registerGlobalFunction(getUserPref, \"getUserPref\");\n    ScriptEngine::registerGlobalFunction(include, \"include\");\n    ScriptEngine::registerGlobalFunction(inputHUD, \"inputHUD\");\n    ScriptEngine::registerGlobalFunction(inputOff, \"inputOff\");\n    ScriptEngine::registerGlobalFunction(inputOn, \"inputOn\");\n    ScriptEngine::registerGlobalFunction(inputSilentOff, \"inputSilentOff\");\n    ScriptEngine::registerGlobalFunction(inputState, \"inputState\");\n    ScriptEngine::registerGlobalFunction(isInputOn, \"isInputOn\");\n    ScriptEngine::registerGlobalFunction(is_string, \"is_string\");\n    ScriptEngine::registerGlobalFunction(is_table, \"is_table\");\n    ScriptEngine::registerGlobalFunction(ord, \"ord\");\n    ScriptEngine::registerGlobalFunction(inputController, \"inputController\");\n    ScriptEngine::registerGlobalFunction(inputVerbs, \"inputVerbs\");\n    ScriptEngine::registerGlobalFunction(logEvent, \"logEvent\");\n    ScriptEngine::registerGlobalFunction(logInfo, \"logInfo\");\n    ScriptEngine::registerGlobalFunction(logWarning, \"logWarning\");\n    ScriptEngine::registerGlobalFunction(microTime, \"microTime\");\n    ScriptEngine::registerGlobalFunction(moveCursorTo, \"moveCursorTo\");\n    ScriptEngine::registerGlobalFunction(pushSentence, \"pushSentence\");\n    ScriptEngine::registerGlobalFunction(removeCallback, \"removeCallback\");\n    ScriptEngine::registerGlobalFunction(setAmbientLight, \"setAmbientLight\");\n    ScriptEngine::registerGlobalFunction(setPrivatePref, \"setPrivatePref\");\n    ScriptEngine::registerGlobalFunction(setUserPref, \"setUserPref\");\n    ScriptEngine::registerGlobalFunction(startglobalthread, \"startglobalthread\");\n    ScriptEngine::registerGlobalFunction(startthread, \"startthread\");\n    ScriptEngine::registerGlobalFunction(stopthread, \"stopthread\");\n    ScriptEngine::registerGlobalFunction(threadid, \"threadid\");\n    ScriptEngine::registerGlobalFunction(threadpauseable, \"threadpauseable\");\n  }\n\n  static SQInteger activeController(HSQUIRRELVM v) {\n    error(\"TODO: activeController: not implemented\");\n    // harcode mouse\n    sq_pushinteger(v, 1);\n    return 1;\n  }\n\n  static SQInteger addCallback(HSQUIRRELVM v) {\n    auto count = sq_gettop(v);\n    SQFloat duration;\n    if (SQ_FAILED(sq_getfloat(v, 2, &duration))) {\n      return sq_throwerror(v, _SC(\"failed to get duration\"));\n    }\n    HSQOBJECT method;\n    sq_resetobject(&method);\n    if (SQ_FAILED(sq_getstackobj(v, 3, &method)) || !sq_isclosure(method)) {\n      return sq_throwerror(v, _SC(\"failed to get method\"));\n    }\n\n    std::string methodName;\n    if (SQ_SUCCEEDED(sq_getclosurename(v, 3))) {\n      const SQChar *tmpMethodName = nullptr;\n      sq_getstring(v, -1, &tmpMethodName);\n      methodName = tmpMethodName;\n    }\n\n    HSQOBJECT arg;\n    sq_resetobject(&arg);\n    if (count == 4 && SQ_FAILED(sq_getstackobj(v, 4, &arg))) {\n      return sq_throwerror(v, _SC(\"failed to get argument\"));\n    }\n\n    auto id = Locator<EntityManager>::get().getCallbackId();\n    auto callback = std::make_unique<Callback>(id, ngf::TimeSpan::seconds(duration), methodName, arg);\n    g_pEngine->addCallback(std::move(callback));\n\n    sq_pushinteger(v, static_cast<SQInteger>(id));\n    return 1;\n  }\n\n  static SQInteger addFolder(HSQUIRRELVM) {\n    // do nothing\n    return 0;\n  }\n\n  static SQInteger breakhere(HSQUIRRELVM v) {\n    SQFloat numFrames;\n    if (SQ_FAILED(sq_getfloat(v, 2, &numFrames))) {\n      return sq_throwerror(v, _SC(\"failed to get numFrames\"));\n    }\n    auto pThread = EntityManager::getThreadFromVm(v);\n    pThread->suspend();\n\n    g_pEngine->addFunction(std::make_unique<BreakHereFunction>(*g_pEngine, pThread->getId(), numFrames));\n    return SQ_SUSPEND_FLAG;\n  }\n\n  static SQInteger breakwhileanimating(HSQUIRRELVM v) {\n    auto *pActor = EntityManager::getActor(v, 2);\n    if (pActor) {\n      auto pAnim = pActor->getCostume().getAnimation();\n      if (!pAnim)\n        return 0;\n\n      auto pThread = EntityManager::getThreadFromVm(v);\n      pThread->suspend();\n\n      g_pEngine->addFunction(std::make_unique<BreakWhileAnimatingFunction>(*g_pEngine, pThread->getId(), *pActor));\n      return SQ_SUSPEND_FLAG;\n    }\n\n    auto *pObj = EntityManager::getObject(v, 2);\n    if (pObj) {\n      auto pThread = EntityManager::getThreadFromVm(v);\n      pThread->suspend();\n\n      g_pEngine->addFunction(std::make_unique<BreakWhileAnimatingObjectFunction>(*g_pEngine, pThread->getId(), *pObj));\n      return SQ_SUSPEND_FLAG;\n    }\n    return sq_throwerror(v, _SC(\"failed to get actor or object\"));\n  }\n\n  static SQInteger breakwhilecamera(HSQUIRRELVM v) {\n    auto pThread = EntityManager::getThreadFromVm(v);\n    pThread->suspend();\n\n    g_pEngine->addFunction(std::make_unique<BreakWhileCameraFunction>(*g_pEngine, pThread->getId()));\n    return SQ_SUSPEND_FLAG;\n  }\n\n  static SQInteger breakwhilecutscene(HSQUIRRELVM v) {\n    auto pThread = EntityManager::getThreadFromVm(v);\n    pThread->suspend();\n\n    g_pEngine->addFunction(std::make_unique<BreakWhileCutsceneFunction>(*g_pEngine, pThread->getId()));\n    return SQ_SUSPEND_FLAG;\n  }\n\n  static SQInteger breakwhileinputoff(HSQUIRRELVM v) {\n    auto pThread = EntityManager::getThreadFromVm(v);\n    pThread->suspend();\n\n    g_pEngine->addFunction(std::make_unique<BreakWhileInputOffFunction>(*g_pEngine, pThread->getId()));\n    return SQ_SUSPEND_FLAG;\n  }\n\n  static SQInteger breakwhilesound(HSQUIRRELVM v) {\n    SoundId *pSound = EntityManager::getSound(v, 2);\n    auto pThread = EntityManager::getThreadFromVm(v);\n    pThread->suspend();\n\n    g_pEngine->addFunction(std::make_unique<BreakWhileSoundFunction>(*g_pEngine,\n                                                                     pThread->getId(),\n                                                                      pSound ? pSound->getId() : 0));\n    return SQ_SUSPEND_FLAG;\n  }\n\n  static SQInteger breakwhiledialog(HSQUIRRELVM v) {\n    auto pThread = EntityManager::getThreadFromVm(v);\n    pThread->suspend();\n\n    g_pEngine->addFunction(std::make_unique<BreakWhileDialogFunction>(*g_pEngine, pThread->getId()));\n    return SQ_SUSPEND_FLAG;\n  }\n\n  static SQInteger breakwhilewalking(HSQUIRRELVM v) {\n    auto *pActor = EntityManager::getActor(v, 2);\n    if (!pActor) {\n      return sq_throwerror(v, _SC(\"failed to get actor\"));\n    }\n\n    auto pThread = EntityManager::getThreadFromVm(v);\n    pThread->suspend();\n\n    g_pEngine->addFunction(std::make_unique<BreakWhileWalkingFunction>(*g_pEngine, pThread->getId(), *pActor));\n    return SQ_SUSPEND_FLAG;\n  }\n\n  static SQInteger breakwhiletalking(HSQUIRRELVM v) {\n    if (sq_gettop(v) == 2) {\n      auto *pEntity = EntityManager::getEntity(v, 2);\n      if (!pEntity) {\n        return sq_throwerror(v, _SC(\"failed to get actor/object\"));\n      }\n      auto pThread = EntityManager::getThreadFromVm(v);\n      pThread->suspend();\n\n      g_pEngine->addFunction(std::make_unique<BreakWhileTalkingFunction>(*g_pEngine, pThread->getId(), *pEntity));\n      return SQ_SUSPEND_FLAG;\n    }\n\n    auto pThread = EntityManager::getThreadFromVm(v);\n    pThread->suspend();\n\n    g_pEngine->addFunction(std::make_unique<BreakWhileAnyActorTalkingFunction>(*g_pEngine, pThread->getId()));\n    return SQ_SUSPEND_FLAG;\n  }\n\n  static SQInteger breakwhilerunning(HSQUIRRELVM v) {\n    SQInteger id = 0;\n    if (sq_gettype(v, 2) == OT_INTEGER) {\n      sq_getinteger(v, 2, &id);\n    }\n\n    if (EntityManager::isThread(id)) {\n      auto pCurrentThread = EntityManager::getThreadFromVm(v);\n      if (!pCurrentThread) {\n        return sq_throwerror(v, \"Current thread should be created with startthread\");\n      }\n\n      auto pThread = EntityManager::getThreadFromId(id);\n      if (!pThread)\n        return 0;\n\n      pCurrentThread->suspend();\n      g_pEngine->addFunction(std::make_unique<BreakWhileRunningFunction>(pCurrentThread->getId(), id));\n      return SQ_SUSPEND_FLAG;\n    }\n    return breakwhilesound(v);\n  }\n\n  static SQInteger chr(HSQUIRRELVM v) {\n    SQInteger number;\n    if (SQ_FAILED(sq_getinteger(v, 2, &number))) {\n      return sq_throwerror(v, \"Failed to get number\");\n    }\n    auto character = (char) number;\n    char s[]{character, '\\0'};\n    sq_pushstring(v, s, -1);\n    return 1;\n  }\n\n  static SQInteger cursorPosX(HSQUIRRELVM v) {\n    auto roomSize = g_pEngine->getRoom()->getRoomSize();\n    auto pos = g_pEngine->getMousePositionInRoom();\n    auto x = Screen::Width * pos.x / roomSize.x;\n    sq_pushinteger(v, static_cast<SQInteger>(x));\n    return 1;\n  }\n\n  static SQInteger cursorPosY(HSQUIRRELVM v) {\n    auto roomSize = g_pEngine->getRoom()->getRoomSize();\n\n    auto pos = g_pEngine->getMousePositionInRoom();\n    auto y = Screen::Height * pos.y / roomSize.y;\n    sq_pushinteger(v, static_cast<SQInteger>(y));\n    return 1;\n  }\n\n  static SQInteger dumpvar(HSQUIRRELVM v) {\n    HSQOBJECT obj;\n    if (sq_gettype(v, 2) == OT_BOOL) {\n      SQBool value;\n      sq_getbool(v, 2, &value);\n      ScriptEngine::printfunc(v, \"%s\", value ? \"true\" : \"false\");\n      return 0;\n    }\n    if (sq_gettype(v, 2) == OT_INTEGER) {\n      SQInteger value;\n      sq_getinteger(v, 2, &value);\n      ScriptEngine::printfunc(v, \"%ld\", value);\n      return 0;\n    }\n    if (sq_gettype(v, 2) == OT_FLOAT) {\n      SQFloat value;\n      sq_getfloat(v, 2, &value);\n      ScriptEngine::printfunc(v, \"%lf\", value);\n      return 0;\n    }\n    if (sq_gettype(v, 2) == OT_STRING) {\n      const SQChar *value;\n      sq_getstring(v, 2, &value);\n      ScriptEngine::printfunc(v, \"%s\", value);\n      return 0;\n    }\n    if (sq_gettype(v, 2) != OT_TABLE) {\n      return sq_throwerror(v, _SC(\"A bool, int, float or table was expected\"));\n    }\n    if (SQ_FAILED(sq_getstackobj(v, 2, &obj))) {\n      return sq_throwerror(v, _SC(\"Failed to get object\"));\n    }\n    auto value = ng::toGGPackValue(obj);\n    std::ostringstream os;\n    os << value;\n    ScriptEngine::printfunc(v, \"%s\", os.str().data());\n    return 0;\n  }\n\n  static SQInteger dumprt(HSQUIRRELVM v) {\n    HSQOBJECT rt;\n    sq_resetobject(&rt);\n    sq_pushroottable(v);\n    if (SQ_FAILED(sq_getstackobj(v, -1, &rt))) {\n      return sq_throwerror(v, _SC(\"Failed to get root table from stack\"));\n    }\n    auto value = ng::toGGPackValue(rt);\n    std::ostringstream os;\n    os << value;\n    ScriptEngine::printfunc(v, \"%s\", os.str().data());\n    return 0;\n  }\n\n  static SQInteger exCommand(HSQUIRRELVM v) {\n    SQInteger command;\n    if (SQ_FAILED(sq_getinteger(v, 2, &command))) {\n      return sq_throwerror(v, _SC(\"Failed to get command\"));\n    }\n    switch (command) {\n    case ExCommandConstants::EX_ALLOW_SAVEGAMES: {\n      SQInteger enabled;\n      if (SQ_FAILED(sq_getinteger(v, 3, &enabled))) {\n        return sq_throwerror(v, _SC(\"Failed to get enabled\"));\n      }\n      g_pEngine->allowSaveGames(enabled != 0);\n      return 0;\n    }\n    case ExCommandConstants::EX_POP_CHARACTER_SELECTION: {\n      error(\"TODO: exCommand EX_POP_CHARACTER_SELECTION: not implemented\");\n      return 0;\n    }\n    case ExCommandConstants::EX_CAMERA_TRACKING: {\n      error(\"TODO: exCommand EX_CAMERA_TRACKING: not implemented\");\n      return 0;\n    }\n    case ExCommandConstants::EX_BUTTON_HOVER_SOUND: {\n      auto pSound = EntityManager::getSoundDefinition(v, 3);\n      if (!pSound) {\n        return sq_throwerror(v, _SC(\"failed to get sound for EX_BUTTON_HOVER_SOUND\"));\n      }\n      g_pEngine->getSoundManager().setSoundHover(pSound);\n      return 0;\n    }\n    case ExCommandConstants::EX_RESTART: {\n      error(\"TODO: exCommand EX_RESTART: not implemented\");\n      return 0;\n    }\n    case ExCommandConstants::EX_IDLE_TIME: {\n      error(\"TODO: exCommand EX_IDLE_TIME: not implemented\");\n      return 0;\n    }\n    case ExCommandConstants::EX_AUTOSAVE: {\n      if (g_pEngine->getAutoSave()) {\n        g_pEngine->saveGame(1);\n      }\n      return 0;\n    }\n    case ExCommandConstants::EX_AUTOSAVE_STATE: {\n      SQInteger enabled;\n      if (SQ_FAILED(sq_getinteger(v, 3, &enabled))) {\n        return sq_throwerror(v, _SC(\"Failed to get enabled\"));\n      }\n      g_pEngine->setAutoSave(enabled != 0);\n      return 0;\n    }\n    case ExCommandConstants::EX_DISABLE_SAVESYSTEM: {\n      error(\"TODO: exCommand EX_DISABLE_SAVESYSTEM: not implemented\");\n      return 0;\n    }\n    case ExCommandConstants::EX_SHOW_OPTIONS: {\n      g_pEngine->showOptions(true);\n      return 0;\n    }\n    case ExCommandConstants::EX_OPTIONS_MUSIC: {\n      error(\"TODO: exCommand EX_OPTIONS_MUSIC: not implemented\");\n      return 0;\n    }\n    case ExCommandConstants::EX_FORCE_TALKIE_TEXT: {\n      SQInteger enabled;\n      if (SQ_FAILED(sq_getinteger(v, 3, &enabled))) {\n        return sq_throwerror(v, _SC(\"Failed to get enabled\"));\n      }\n      g_pEngine->getPreferences().setTempPreference(TempPreferenceNames::ForceTalkieText, enabled != 0);\n      return 0;\n    }\n    default:error(\"TODO: exCommand {}: not implemented\", command);\n      break;\n    }\n    return 0;\n  }\n\n  static SQInteger gameTime(HSQUIRRELVM v) {\n    sq_pushfloat(v, g_pEngine->getTime().getTotalSeconds());\n    return 1;\n  }\n\n  static SQInteger logEvent(HSQUIRRELVM v) {\n    auto numArgs = sq_gettop(v);\n    const SQChar *event = nullptr;\n    if (SQ_SUCCEEDED(sq_getstring(v, 2, &event))) {\n      info(event);\n    }\n    if (numArgs == 3) {\n      if (SQ_SUCCEEDED(sq_getstring(v, 3, &event))) {\n        info(event);\n      }\n    }\n    return 0;\n  }\n\n  static SQInteger logInfo(HSQUIRRELVM v) {\n    const SQChar *msg = nullptr;\n    if (SQ_SUCCEEDED(sq_getstring(v, 2, &msg))) {\n      info(msg);\n    }\n    return 0;\n  }\n\n  static SQInteger logWarning(HSQUIRRELVM v) {\n    const SQChar *msg = nullptr;\n    if (SQ_SUCCEEDED(sq_getstring(v, 2, &msg))) {\n      warn(msg);\n    }\n    return 0;\n  }\n\n  static SQInteger microTime(HSQUIRRELVM v) {\n    sq_pushfloat(v, g_pEngine->getTime().getTotalSeconds());\n    return 1;\n  }\n\n  static SQInteger moveCursorTo(HSQUIRRELVM v) {\n    SQInteger x;\n    if (SQ_FAILED(sq_getinteger(v, 2, &x))) {\n      return sq_throwerror(v, _SC(\"Failed to get x\"));\n    }\n    SQInteger y;\n    if (SQ_FAILED(sq_getinteger(v, 3, &y))) {\n      return sq_throwerror(v, _SC(\"Failed to get y\"));\n    }\n    SQFloat t;\n    if (SQ_FAILED(sq_getfloat(v, 4, &t))) {\n      return sq_throwerror(v, _SC(\"Failed to get time\"));\n    }\n\n    // WIP need to be check\n    // auto pos = g_pEngine->getApplication()->getRenderTarget()->mapCoordsToPixel(glm::vec2(x, y) - g_pEngine->getCamera().getAt());\n    // TODO: ngf::Mouse::setPosition(pos, g_pEngine->getApplication()->get);\n    error(\"moveCursorTo not implemented\");\n    return 0;\n  }\n\n  static SQInteger pushSentence(HSQUIRRELVM v) {\n    auto numArgs = sq_gettop(v);\n    SQInteger id;\n    if (SQ_FAILED(sq_getinteger(v, 2, &id))) {\n      return sq_throwerror(v, _SC(\"Failed to get verb id\"));\n    }\n\n    if (id == VerbConstants::VERB_DIALOG) {\n      SQInteger choice;\n      if (SQ_FAILED(sq_getinteger(v, 3, &choice))) {\n        return sq_throwerror(v, _SC(\"Failed to get choice\"));\n      }\n      g_pEngine->getDialogManager().choose(choice);\n      return 0;\n    }\n\n    Entity *pObj1{nullptr};\n    Entity *pObj2{nullptr};\n    if (numArgs > 2) {\n      pObj1 = EntityManager::getEntity(v, 3);\n      if (!pObj1) {\n        return sq_throwerror(v, _SC(\"Failed to get obj1\"));\n      }\n    }\n    if (numArgs > 3) {\n      pObj2 = EntityManager::getEntity(v, 4);\n      if (!pObj2) {\n        return sq_throwerror(v, _SC(\"Failed to get obj2\"));\n      }\n    }\n    g_pEngine->pushSentence(static_cast<int>(id), pObj1, pObj2);\n    return 0;\n  }\n\n  static SQInteger stopthread(HSQUIRRELVM v) {\n    auto type = sq_gettype(v, 2);\n    if (type == OT_NULL) {\n      sq_pushinteger(v, 0);\n      return 1;\n    }\n\n    SQInteger id;\n    if (SQ_FAILED(sq_getinteger(v, 2, &id))) {\n      trace(\"Failed to stopthread: got {} instead\", type);\n      sq_pushinteger(v, 0);\n      return 1;\n    }\n\n    auto pThread = EntityManager::getThreadFromId(id);\n    if (!pThread) {\n      sq_pushinteger(v, 0);\n      return 1;\n    }\n\n    trace(\"stopthread {}\", id);\n    pThread->stop();\n\n    sq_pushinteger(v, 0);\n    return 1;\n  }\n\n  static SQInteger startglobalthread(HSQUIRRELVM v) {\n    return startthread(v, true);\n  }\n\n  static SQInteger startthread(HSQUIRRELVM v) {\n    return startthread(v, false);\n  }\n\n  static SQInteger startthread(HSQUIRRELVM v, bool global) {\n    SQInteger size = sq_gettop(v);\n\n    HSQOBJECT env_obj;\n    sq_resetobject(&env_obj);\n    if (SQ_FAILED(sq_getstackobj(v, 1, &env_obj))) {\n      return sq_throwerror(v, _SC(\"Couldn't get environment from stack\"));\n    }\n\n    auto vm = ScriptEngine::getVm();\n    // create thread and store it on the stack\n    sq_newthread(vm, 1024);\n    HSQOBJECT thread_obj;\n    sq_resetobject(&thread_obj);\n    if (SQ_FAILED(sq_getstackobj(vm, -1, &thread_obj))) {\n      return sq_throwerror(v, _SC(\"Couldn't get coroutine thread from stack\"));\n    }\n\n    std::vector<HSQOBJECT> args;\n    for (auto i = 0; i < size - 2; i++) {\n      HSQOBJECT arg;\n      sq_resetobject(&arg);\n      if (SQ_FAILED(sq_getstackobj(v, 3 + i, &arg))) {\n        return sq_throwerror(v, _SC(\"Couldn't get coroutine args from stack\"));\n      }\n      args.push_back(arg);\n    }\n\n    // get the closure\n    HSQOBJECT closureObj;\n    sq_resetobject(&closureObj);\n    if (SQ_FAILED(sq_getstackobj(v, 2, &closureObj))) {\n      return sq_throwerror(v, _SC(\"Couldn't get coroutine thread from stack\"));\n    }\n\n    const SQChar *name = nullptr;\n    if (SQ_SUCCEEDED(sq_getclosurename(v, 2))) {\n      sq_getstring(v, -1, &name);\n    }\n\n    std::string threadName = name ? name : \"anonymous\";\n    std::string pSource = _stringval(_closure(closureObj)->_function->_sourcename);\n    auto line = _closure(closureObj)->_function->_lineinfos->_line;\n    threadName += ' ' + pSource + '(' + std::to_string(line) + ')';\n    auto pUniquethread = std::make_unique<Thread>(threadName, global, vm, thread_obj, env_obj, closureObj, args);\n    sq_pop(vm, 1);\n    auto pThread = pUniquethread.get();\n    trace(\"start thread ({}): {}\", threadName, pThread->getId());\n    if (name) {\n      sq_pop(v, 1); // pop name\n    }\n    sq_pop(v, 1); // pop closure\n    g_pEngine->addThread(std::move(pUniquethread));\n\n    // call the closure in the thread\n    if (!pThread->call()) {\n      return sq_throwerror(v, _SC(\"call failed\"));\n    }\n\n    sq_pushinteger(v, pThread->getId());\n    return 1;\n  }\n\n  static SQInteger breaktime(HSQUIRRELVM v) {\n    SQFloat time = 0;\n    if (SQ_FAILED(sq_getfloat(v, 2, &time))) {\n      return sq_throwerror(v, _SC(\"failed to get time\"));\n    }\n\n    auto pThread = EntityManager::getThreadFromVm(v);\n    if (!pThread) {\n      return sq_throwerror(v, _SC(\"failed to get thread\"));\n    }\n\n    pThread->suspend();\n\n    g_pEngine->addFunction(std::make_unique<BreakTimeFunction>(pThread->getId(), ngf::TimeSpan::seconds(time)));\n    return SQ_SUSPEND_FLAG;\n  }\n\n  static SQInteger setPrivatePref(HSQUIRRELVM v) {\n    const SQChar *key;\n    if (SQ_FAILED(sq_getstring(v, 2, &key))) {\n      return sq_throwerror(v, _SC(\"failed to get key\"));\n    }\n    auto &achievements = ng::Locator<ng::AchievementManager>::get();\n    auto type = sq_gettype(v, 3);\n    if (type == SQObjectType::OT_STRING) {\n      const SQChar *str = nullptr;\n      sq_getstring(v, 3, &str);\n      std::string strValue = str;\n      achievements.setPrivatePreference(key, strValue);\n      return 0;\n    }\n    if (type == SQObjectType::OT_INTEGER) {\n      SQInteger integer;\n      sq_getinteger(v, 3, &integer);\n      achievements.setPrivatePreference(key, integer);\n      return 0;\n    }\n    if (type == SQObjectType::OT_BOOL) {\n      SQBool b;\n      sq_getbool(v, 3, &b);\n      achievements.setPrivatePreference(key, static_cast<int>(b));\n      return 0;\n    }\n    if (type == SQObjectType::OT_FLOAT) {\n      SQFloat fl;\n      sq_getfloat(v, 3, &fl);\n      achievements.setPrivatePreference(key, fl);\n      return 0;\n    }\n    return 0;\n  }\n\n  static HSQOBJECT toSquirrel(HSQUIRRELVM v, const ngf::GGPackValue &value) {\n    HSQOBJECT obj;\n    switch (value.type()) {\n    case ngf::detail::GGPackValueType::String:obj._type = OT_STRING;\n      obj._unVal.pString = SQString::Create(v->_sharedstate, value.getString().c_str(), -1);\n      return obj;\n    case ngf::detail::GGPackValueType::Integer:obj._type = OT_INTEGER;\n      obj._unVal.nInteger = value.getInt();\n      return obj;\n    case ngf::detail::GGPackValueType::Double:obj._type = OT_FLOAT;\n      obj._unVal.fFloat = value.getDouble();\n      return obj;\n    case ngf::detail::GGPackValueType::Null:obj._type = OT_NULL;\n      return obj;\n    default:throw std::runtime_error(\"Cannot convert this type to squirrel\");\n    }\n  }\n\n  static SQInteger getPrivatePref(HSQUIRRELVM v) {\n    const SQChar *key;\n    if (SQ_FAILED(sq_getstring(v, 2, &key))) {\n      return sq_throwerror(v, _SC(\"failed to get key\"));\n    }\n\n    auto &achievements = ng::Locator<ng::AchievementManager>::get();\n    auto value = achievements.getPrivatePreference(key);\n    // key found in preferences ?\n    if (!value.isNull()) {\n      sq_pushobject(v, toSquirrel(v, value));\n      return 1;\n    }\n    // we have a default value ?\n    if (sq_gettop(v) == 3) {\n      sq_push(v, 3);\n      return 1;\n    }\n\n    // return null\n    sq_pushnull(v);\n    return 1;\n  }\n\n  static SQInteger getUserPref(HSQUIRRELVM v) {\n    return _getPref(v,\n                    [](auto name, auto value) { return g_pEngine->getPreferences().getUserPreference(name, value); });\n  }\n\n  static SQInteger _getPref(HSQUIRRELVM v,\n                            const std::function<ngf::GGPackValue(const std::string &name,\n                                                                 ngf::GGPackValue value)> &func) {\n    const SQChar *key;\n    if (SQ_FAILED(sq_getstring(v, 2, &key))) {\n      return sq_throwerror(v, _SC(\"failed to get key\"));\n    }\n    auto numArgs = sq_gettop(v) - 1;\n    ngf::GGPackValue defaultValue;\n    if (numArgs > 1) {\n      auto type = sq_gettype(v, 3);\n      if (type == SQObjectType::OT_STRING) {\n        const SQChar *str = nullptr;\n        sq_getstring(v, 3, &str);\n        defaultValue = str;\n      } else if (type == SQObjectType::OT_INTEGER) {\n        SQInteger integer;\n        sq_getinteger(v, 3, &integer);\n        defaultValue = integer;\n      } else if (type == SQObjectType::OT_BOOL) {\n        SQBool b;\n        sq_getbool(v, 3, &b);\n        defaultValue = b ? 1 : 0;\n      } else if (type == SQObjectType::OT_FLOAT) {\n        SQFloat fl;\n        sq_getfloat(v, 3, &fl);\n        defaultValue = fl;\n      }\n    }\n\n    auto value = func(key, defaultValue);\n    if (value.isString()) {\n      sq_pushstring(v, value.getString().data(), -1);\n    } else if (value.isInteger()) {\n      sq_pushinteger(v, value.getInt());\n    } else if (value.isDouble()) {\n      sq_pushfloat(v, value.getDouble());\n    } else {\n      sq_pushnull(v);\n    }\n\n    return 1;\n  }\n\n  static SQInteger removeCallback(HSQUIRRELVM v) {\n    SQInteger id = 0;\n    if (SQ_FAILED(sq_getinteger(v, 2, &id))) {\n      return sq_throwerror(v, _SC(\"failed to get callback\"));\n    }\n    g_pEngine->removeCallback(id);\n    return 0;\n  }\n\n  static SQInteger setAmbientLight(HSQUIRRELVM v) {\n    SQInteger c = 0;\n    if (SQ_FAILED(sq_getinteger(v, 2, &c))) {\n      return sq_throwerror(v, _SC(\"failed to get color\"));\n    }\n    auto color = fromRgb(c);\n    g_pEngine->getRoom()->setAmbientLight(color);\n    return 0;\n  }\n\n  static SQInteger setUserPref(HSQUIRRELVM v) {\n    _setPref(v,\n             [](auto key, auto value) { return g_pEngine->getPreferences().setUserPreference(key, value); },\n             [](auto key) { return g_pEngine->getPreferences().removeUserPreference(key); });\n    return 0;\n  }\n\n  static SQInteger _setPref(HSQUIRRELVM v,\n                            const std::function<void(const std::string &, ngf::GGPackValue)> &setPref,\n                            const std::function<void(const std::string &)> &removePref) {\n    const SQChar *key;\n    if (SQ_FAILED(sq_getstring(v, 2, &key))) {\n      return sq_throwerror(v, _SC(\"failed to get key\"));\n    }\n    auto type = sq_gettype(v, 3);\n    if (type == SQObjectType::OT_STRING) {\n      const SQChar *str = nullptr;\n      sq_getstring(v, 3, &str);\n      std::string strValue = str;\n      setPref(key, Preferences::toGGPackValue(strValue));\n      return 0;\n    }\n    if (type == SQObjectType::OT_INTEGER) {\n      SQInteger integer;\n      sq_getinteger(v, 3, &integer);\n      setPref(key, Preferences::toGGPackValue(static_cast<int>(integer)));\n      return 0;\n    }\n    if (type == SQObjectType::OT_BOOL) {\n      SQBool b;\n      sq_getbool(v, 3, &b);\n      setPref(key, Preferences::toGGPackValue(b != 0));\n      return 0;\n    }\n    if (type == SQObjectType::OT_FLOAT) {\n      SQFloat fl;\n      sq_getfloat(v, 3, &fl);\n      setPref(key, Preferences::toGGPackValue(fl));\n      return 0;\n    }\n\n    removePref(key);\n\n    return 0;\n  }\n\n  static SQInteger include(HSQUIRRELVM v) {\n    const SQChar *filename = nullptr;\n    if (SQ_FAILED(sq_getstring(v, 2, &filename))) {\n      return sq_throwerror(v, \"failed to get filename\");\n    }\n    trace(\"include {}\", filename);\n    ng::ScriptEngine::executeNutScript(filename);\n    return 0;\n  }\n\n  static SQInteger inputHUD(HSQUIRRELVM v) {\n    SQInteger on;\n    if (SQ_FAILED(sq_getinteger(v, 2, &on))) {\n      return sq_throwerror(v, _SC(\"failed to get on\"));\n    }\n    g_pEngine->setInputHUD(on);\n    return 0;\n  }\n\n  static SQInteger inputOff(HSQUIRRELVM) {\n    g_pEngine->setInputActive(false);\n    return 0;\n  }\n\n  static SQInteger inputOn(HSQUIRRELVM) {\n    g_pEngine->setInputActive(true);\n    return 0;\n  }\n\n  static SQInteger inputSilentOff(HSQUIRRELVM) {\n    g_pEngine->inputSilentOff();\n    return 0;\n  }\n\n  static SQInteger isInputOn(HSQUIRRELVM v) {\n    bool isActive = g_pEngine->getInputActive();\n    sq_pushinteger(v, isActive ? 1 : 0);\n    return 1;\n  }\n\n  static SQInteger inputState(HSQUIRRELVM v) {\n    auto numArgs = sq_gettop(v);\n    if (numArgs == 1) {\n      auto state = g_pEngine->getInputState();\n      sq_pushinteger(v, state);\n      return 1;\n    } else if (numArgs == 2) {\n      SQInteger state;\n      if (SQ_FAILED(sq_getinteger(v, 2, &state))) {\n        return sq_throwerror(v, _SC(\"failed to get state\"));\n      }\n      g_pEngine->setInputState(state);\n      return 0;\n    }\n    error(\"TODO: inputState: not implemented\");\n    return 0;\n  }\n\n  static SQInteger inputController(HSQUIRRELVM) {\n    error(\"TODO: inputController: not implemented\");\n    return 0;\n  }\n\n  static SQInteger inputVerbs(HSQUIRRELVM v) {\n    SQInteger on;\n    if (SQ_FAILED(sq_getinteger(v, 2, &on))) {\n      return sq_throwerror(v, _SC(\"failed to get isActive\"));\n    }\n    g_pEngine->setInputVerbs(on);\n    return 1;\n  }\n\n  static SQInteger is_table(HSQUIRRELVM v) {\n    sq_pushbool(v, sq_gettype(v, 2) == OT_TABLE ? SQTrue : SQFalse);\n    return 1;\n  }\n\n  static SQInteger ord(HSQUIRRELVM v) {\n    const SQChar *letter;\n    if (SQ_FAILED(sq_getstring(v, 2, &letter))) {\n      return sq_throwerror(v, \"Failed to get letter\");\n    }\n    sq_pushinteger(v, (SQInteger) letter[0]);\n    return 1;\n  }\n\n  static SQInteger is_string(HSQUIRRELVM v) {\n    sq_pushbool(v, sq_gettype(v, 2) == OT_STRING ? SQTrue : SQFalse);\n    return 1;\n  }\n\n  static SQInteger threadid(HSQUIRRELVM v) {\n    auto pThread = EntityManager::getThreadFromVm(v);\n    sq_pushinteger(v, pThread ? pThread->getId() : 0);\n    return 1;\n  }\n\n  static SQInteger threadpauseable(HSQUIRRELVM v) {\n    SQInteger threadId = 0;\n    if (SQ_FAILED(sq_getinteger(v, 2, &threadId))) {\n      return sq_throwerror(v, _SC(\"failed to get threadId\"));\n    }\n    auto pThread = EntityManager::getThreadFromId(threadId);\n    if (!pThread) {\n      return 0;\n    }\n    SQInteger pauseable = 0;\n    if (SQ_FAILED(sq_getinteger(v, 3, &pauseable))) {\n      return sq_throwerror(v, _SC(\"failed to get pauseable\"));\n    }\n    pThread->setPauseable(pauseable != 0);\n    return 0;\n  }\n};\n\nEngine *SystemPack::g_pEngine = nullptr;\n\n} // namespace ng\n"
  },
  {
    "path": "src/Scripting/VerbExecuteFunction.cpp",
    "content": "#include \"VerbExecuteFunction.hpp\"\n#include <engge/Engine/Verb.hpp>\n#include <engge/Entities/Actor.hpp>\n#include <engge/Entities/Object.hpp>\n#include <engge/Scripting/ScriptEngine.hpp>\n\nnamespace ng {\nVerbExecuteFunction::VerbExecuteFunction(Engine &engine,\n                                         Actor &actor,\n                                         Entity *pObject1,\n                                         Entity *pObject2,\n                                         const Verb *pVerb)\n    : m_engine(engine), m_pVerb(pVerb), m_pObject1(pObject1), m_pObject2(pObject2), m_actor(actor) {\n}\n\nbool VerbExecuteFunction::isElapsed() { return m_done; }\n\nbool VerbExecuteFunction::needToExecuteVerb() {\n  auto executeVerb = true;\n  if (m_pVerb->id == VerbConstants::VERB_GIVE && m_pObject2) {\n    auto *pActor2 = dynamic_cast<Actor *>(m_pObject2);\n    if (!pActor2)\n      pActor2 = Entity::getActor(m_pObject2);\n    bool selectable = true;\n    ScriptEngine::rawGet(pActor2, \"selectable\", selectable);\n    executeVerb = !selectable;\n  }\n  return executeVerb;\n}\n\nbool VerbExecuteFunction::callVerb() {\n  if (m_pVerb->id == VerbConstants::VERB_GIVE && ScriptEngine::rawExists(&m_actor, m_pVerb->func.data())) {\n    auto handled = false;\n    if (ScriptEngine::rawCallFunc(handled, &m_actor, m_pVerb->func.data(), m_pObject1) && handled)\n      return true;\n  }\n\n  if (!ScriptEngine::rawExists(m_pObject1, m_pVerb->func.data()))\n    return false;\n\n  auto count = ScriptEngine::getParameterCount(m_pObject1, m_pVerb->func.data());\n  if (count == 2) {\n    return ScriptEngine::objCall(m_pObject1, m_pVerb->func.data(), m_pObject2);\n  }\n  return ScriptEngine::objCall(m_pObject1, m_pVerb->func.data());\n}\n\nvoid VerbExecuteFunction::operator()(const ngf::TimeSpan &) {\n  m_done = true;\n\n  if (needToExecuteVerb()) {\n    if (callVerb()) {\n      onPickup();\n      return;\n    }\n  }\n\n  if (callVerbGive())\n    return;\n\n  if (callVerbDefault(m_pObject1))\n    return;\n\n  callDefaultObjectVerb();\n}\n\nbool VerbExecuteFunction::callVerbGive() {\n  if (m_pVerb->id != VerbConstants::VERB_GIVE)\n    return false;\n\n  auto *pActor2 = dynamic_cast<Actor *>(m_pObject2);\n  if (!pActor2)\n    pActor2 = Entity::getActor(m_pObject2);\n  ScriptEngine::call(\"objectGive\", m_pObject1, &m_actor, pActor2);\n\n  auto *pObject = dynamic_cast<Object *>(m_pObject1);\n  m_actor.giveTo(pObject, pActor2);\n  return true;\n}\n\nvoid VerbExecuteFunction::onPickup() {\n  if (m_pVerb->id != VerbConstants::VERB_PICKUP)\n    return;\n\n  ScriptEngine::call(\"onPickup\", m_pObject1, &m_actor);\n}\n\nvoid VerbExecuteFunction::callDefaultObjectVerb() {\n  auto &obj = m_engine.getDefaultObject();\n  ScriptEngine::objCall(obj, m_pVerb->func.data(), m_pObject1, m_pObject2);\n}\n\nbool VerbExecuteFunction::callVerbDefault(Entity *pEntity) {\n  return ScriptEngine::objCall(pEntity, \"verbDefault\");\n}\n}"
  },
  {
    "path": "src/Scripting/VerbExecuteFunction.hpp",
    "content": "#pragma once\n#include <ngf/System/TimeSpan.h>\n#include <engge/Engine/Function.hpp>\n\nnamespace ng {\nclass Actor;\nclass Engine;\nclass Entity;\nstruct Verb;\n\nclass VerbExecuteFunction : public Function {\npublic:\n  VerbExecuteFunction(Engine &engine, Actor &actor, Entity *pObject1, Entity *pObject2, const Verb *pVerb);\n\nprivate:\n  bool isElapsed() final;\n  void operator()(const ngf::TimeSpan &) final;\n  void onPickup();\n  bool callVerb();\n  bool callVerbGive();\n  void callDefaultObjectVerb();\n  bool needToExecuteVerb();\n  static bool callVerbDefault(Entity *pEntity);\n\nprivate:\n  Engine &m_engine;\n  const Verb *m_pVerb{nullptr};\n  Entity *m_pObject1{nullptr};\n  Entity *m_pObject2{nullptr};\n  Actor &m_actor;\n  bool m_done{false};\n};\n}"
  },
  {
    "path": "src/System/DebugTools/ActorTools.cpp",
    "content": "#include \"ActorTools.hpp\"\n#include <ngf/Graphics/ImGuiExtensions.h>\n#include <engge/Engine/Engine.hpp>\n#include <engge/Engine/EngineSettings.hpp>\n#include <engge/Room/Room.hpp>\n#include <engge/Scripting/ScriptEngine.hpp>\n#include \"Util/Util.hpp\"\n#include \"DebugControls.hpp\"\n\nnamespace ng {\nActorTools::ActorTools(Engine &engine) : m_engine(engine) {}\n\nvoid ActorTools::render() {\n  if (!actorsVisible)\n    return;\n\n  ImGui::Begin(\"Actors\", &actorsVisible);\n  if (ImGui::SmallButton(\"Table...\")) {\n    m_showActorTable = true;\n  }\n  ImGui::Checkbox(\"General\", &m_showProperties);\n  ImGui::Checkbox(\"Inventory\", &m_showInventory);\n  ImGui::Checkbox(\"Costume\", &m_showCostume);\n  ImGui::Separator();\n\n  // show actor list\n  auto &actors = m_engine.getActors();\n  for (auto &&actor : actors) {\n    ImGui::PushID(actor.get());\n    bool isSelected = actor.get() == m_selectedActor;\n    auto visible = actor->isVisible();\n    if (ImGui::Checkbox(\"\", &visible)) {\n      actor->setVisible(visible);\n    }\n    ImGui::SameLine();\n    if (ImGui::Selectable(toUtf8(actor->getTranslatedName()).c_str(), isSelected)) {\n      m_selectedActor = actor.get();\n    }\n    ImGui::PopID();\n  }\n\n  ImGui::End();\n\n  if (m_selectedActor) {\n    showActorTable(m_selectedActor);\n    showProperties(m_selectedActor);\n    showInventory(m_selectedActor);\n    showCostume(m_selectedActor);\n  }\n}\n\nvoid ActorTools::showInventory(Actor *actor) {\n  if (!m_showInventory)\n    return;\n\n  ImGui::Begin(\"Inventory\", &m_showInventory);\n  for (const auto &obj : actor->getObjects()) {\n    if (ImGui::TreeNode(&obj, \"%s\", obj->getKey().c_str())) {\n      auto jiggle = obj->getJiggle();\n      if (ImGui::Checkbox(\"Jiggle\", &jiggle)) {\n        obj->setJiggle(jiggle);\n      }\n      auto pop = obj->getPop();\n      if (ImGui::DragInt(\"Pop\", &pop, 1, 0, 10)) {\n        obj->setPop(pop);\n      }\n      ImGui::TreePop();\n    }\n  }\n  ImGui::End();\n}\n\nvoid ActorTools::showProperties(Actor *actor) {\n  if (!m_showProperties)\n    return;\n\n  ImGui::Begin(\"Actor properties\", &m_showProperties);\n\n  auto isTouchable = actor->isTouchable();\n  if (ImGui::Checkbox(\"Touchable\", &isTouchable)) {\n    actor->setTouchable(isTouchable);\n  }\n  auto isLit = actor->isLit();\n  if (ImGui::Checkbox(\"Lit\", &isLit)) {\n    actor->setLit(isLit);\n  }\n  auto useWalkboxes = actor->useWalkboxes();\n  if (ImGui::Checkbox(\"Use Walkboxes\", &useWalkboxes)) {\n    actor->useWalkboxes(useWalkboxes);\n  }\n  auto pRoom = actor->getRoom();\n  auto flags = getFlags(*actor);\n  ImGui::Text(\"Key: %s\", actor->getKey().c_str());\n  ImGui::Text(\"Flags: %s\", flags.c_str());\n  ImGui::Text(\"Icon: %s\", actor->getIcon().c_str());\n  ImGui::Text(\"Room: %s\", pRoom ? pRoom->getName().c_str() : \"(none)\");\n  ImGui::Text(\"Talking: %s\", actor->isTalking() ? \"yes\" : \"no\");\n  ImGui::Text(\"Walking: %s\", actor->isWalking() ? \"yes\" : \"no\");\n  ImGui::Text(\"Z-Order: %d\", actor->getZOrder());\n  if (pRoom) {\n    auto scale = actor->getScale();\n    ImGui::Text(\"Scale: %.3f\", scale);\n  }\n  auto facing = facingToInt(actor->getCostume().getFacing());\n  auto facings = \"Front\\0Back\\0Left\\0Right\\0\";\n  if (ImGui::Combo(\"Facing\", &facing, facings)) {\n    actor->getCostume().setFacing(intToFacing(facing));\n  }\n  auto color = actor->getColor();\n  if (ngf::ImGui::ColorEdit4(\"Color\", &color)) {\n    actor->setColor(color);\n  }\n  auto talkColor = actor->getTalkColor();\n  if (ngf::ImGui::ColorEdit4(\"Talk color\", &talkColor)) {\n    actor->setTalkColor(talkColor);\n  }\n  auto talkOffset = actor->getTalkOffset();\n  if (ImGui::DragInt2(\"Talk offset\", &talkOffset.x)) {\n    actor->setTalkOffset(talkOffset);\n  }\n  auto pos = actor->getPosition();\n  if (ImGui::DragFloat2(\"Position\", &pos.x)) {\n    actor->setPosition(pos);\n  }\n  auto usePos = actor->getUsePosition().value_or(glm::vec2());\n  if (ImGui::DragFloat2(\"Use Position\", &usePos.x)) {\n    actor->setUsePosition(usePos);\n  }\n  auto offset = actor->getOffset();\n  if (ImGui::DragFloat2(\"Offset\", &offset.x)) {\n    actor->setOffset(offset);\n  }\n  auto renderOffset = actor->getRenderOffset();\n  if (ImGui::DragInt2(\"Render Offset\", &renderOffset.x)) {\n    actor->setRenderOffset(renderOffset);\n  }\n  auto walkSpeed = actor->getWalkSpeed();\n  if (ImGui::DragInt2(\"Walk speed\", &walkSpeed.x)) {\n    actor->setWalkSpeed(walkSpeed);\n  }\n  auto hotspotVisible = actor->isHotspotVisible();\n  if (ImGui::Checkbox(\"Show hotspot\", &hotspotVisible)) {\n    actor->showHotspot(hotspotVisible);\n  }\n  auto hotspot = actor->getHotspot();\n  if (ImGui::DragInt4(\"Hotspot\", &hotspot.min.x)) {\n    actor->setHotspot(hotspot);\n  }\n  auto useDirection = directionToInt(actor->getUseDirection().value_or(UseDirection::Front));\n  auto directions = \"Front\\0Back\\0Left\\0Right\\0\";\n  if (ImGui::Combo(\"Use direction\", &useDirection, directions)) {\n    actor->setUseDirection(intToDirection(useDirection));\n  }\n  auto fps = actor->getFps();\n  if (ImGui::InputInt(\"FPS\", &fps)) {\n    actor->setFps(fps);\n  }\n  auto inventoryOffset = actor->getInventoryOffset();\n  if (ImGui::InputInt(\"Inventory Offset\", &inventoryOffset)) {\n    actor->setInventoryOffset(inventoryOffset);\n  }\n  auto volume = actor->getVolume();\n  if (ImGui::SliderFloat(\"Volume\", &volume, 0.f, 1.0f)) {\n    actor->setVolume(volume);\n  }\n  auto rotation = actor->getRotation();\n  if (ImGui::DragFloat(\"Rotation\", &rotation, 0.f, 360.0f)) {\n    actor->setRotation(rotation);\n  }\n  auto scale = actor->getScale();\n  if (ImGui::DragFloat(\"scale\", &scale, 0.f, 100.f)) {\n    actor->setScale(scale);\n  }\n\n  // head index\n  ImGui::Separator();\n  auto head = actor->getCostume().getHeadIndex();\n  for (int i = 0; i < 6; ++i) {\n    std::string s;\n    s.append(\"Head #\").append(std::to_string(i + 1));\n    if (ImGui::RadioButton(s.c_str(), head == i)) {\n      actor->getCostume().setHeadIndex(head);\n    }\n    ImGui::SameLine();\n  }\n  ImGui::NewLine();\n\n  // animation names\n  ImGui::Separator();\n  std::string headAnim;\n  std::string standAnim;\n  std::string walkAnim;\n  std::string reachAnim;\n  actor->getCostume().getAnimationNames(headAnim, standAnim, walkAnim, reachAnim);\n  ImGui::Text(\"Head: %s\", headAnim.c_str());\n  ImGui::Text(\"Stand: %s\", standAnim.c_str());\n  ImGui::Text(\"Walk: %s\", walkAnim.c_str());\n  ImGui::Text(\"Reach: %s\", reachAnim.c_str());\n\n  ImGui::End();\n}\n\nvoid ActorTools::showCostume(Actor *actor) {\n  if (!m_showCostume)\n    return;\n\n  ImGui::Begin(\"General\", &m_showCostume);\n\n  auto state = actor->getCostume().getAnimControl().getState();\n  auto loop = actor->getCostume().getAnimControl().getLoop();\n  auto pAnim = actor->getCostume().getAnimControl().getAnimation();\n  std::string stateText;\n  switch (state) {\n  case AnimState::Stopped:stateText = \"Stopped\";\n    break;\n  case AnimState::Play:stateText = \"Play\";\n    break;\n  case AnimState::Pause:stateText = \"Pause\";\n    break;\n  default:stateText = \"?\";\n    break;\n  }\n  ImGui::Text(\"Anim: %s\", pAnim ? pAnim->name.c_str() : \"(none)\");\n  ImGui::Text(\"State: %s\", stateText.c_str());\n  ImGui::Text(\"Loop: %s\", loop ? \"yes\" : \"no\");\n  ImGui::Separator();\n\n  m_filterCostume.Draw(\"Filter\");\n  if (ImGui::ListBoxHeader(\"Costume\")) {\n    auto actorKey = actor->getKey();\n    std::vector<std::string> entries;\n    for (const auto &pack : Locator<EngineSettings>::get()) {\n      for (const auto &itEntry : *pack) {\n        const auto &entry = itEntry.first;\n        if (entry.length() < 15)\n          continue;\n        auto extension = entry.substr(entry.length() - 14, 14);\n        CaseInsensitiveCompare cmp;\n        if (!cmp(extension, \"Animation.json\"))\n          continue;\n        auto prefix = entry.substr(0, actorKey.length());\n        if (!cmp(prefix, actorKey))\n          continue;\n        if (m_filterCostume.PassFilter(entry.c_str())) {\n          if (ImGui::Selectable(entry.c_str(), actor->getCostume().getPath() == entry)) {\n            actor->getCostume().loadCostume(entry);\n          }\n        }\n      }\n    }\n    ImGui::ListBoxFooter();\n  }\n  ImGui::End();\n}\n\nstd::string ActorTools::getFlags(Actor &actor) {\n  auto flags = actor.getFlags();\n  std::ostringstream os;\n  if (flags & ObjectFlagConstants::GIVEABLE) {\n    os << \"GIVEABLE \";\n  }\n  if (flags & ObjectFlagConstants::TALKABLE) {\n    os << \"TALKABLE \";\n  }\n  if (flags & ObjectFlagConstants::FEMALE) {\n    os << \"FEMALE \";\n  }\n  if (flags & ObjectFlagConstants::MALE) {\n    os << \"MALE \";\n  }\n  if (flags & ObjectFlagConstants::MALE) {\n    os << \"PERSON \";\n  }\n  os << std::hex << flags;\n  return os.str();\n}\n\nvoid ActorTools::showActorTable(Actor *actor) {\n  if (!m_showActorTable)\n    return;\n\n  ImGui::Begin(\"Actor table\", &m_showActorTable);\n  if (actor) {\n    auto table = actor->getTable();\n    DebugControls::createTree(actor->getName().c_str(), table);\n  }\n  ImGui::End();\n}\n\nint ActorTools::facingToInt(Facing facing) {\n  switch (facing) {\n  case Facing::FACE_FRONT:return 0;\n  case Facing::FACE_BACK:return 1;\n  case Facing::FACE_LEFT:return 2;\n  case Facing::FACE_RIGHT:return 3;\n  }\n  return 0;\n}\n\nFacing ActorTools::intToFacing(int facing) {\n  switch (facing) {\n  case 0:return Facing::FACE_FRONT;\n  case 1:return Facing::FACE_BACK;\n  case 2:return Facing::FACE_LEFT;\n  case 3:return Facing::FACE_RIGHT;\n  }\n  return Facing::FACE_FRONT;\n}\n\nint ActorTools::directionToInt(UseDirection dir) {\n  switch (dir) {\n  case UseDirection::Front:return 0;\n  case UseDirection::Back:return 1;\n  case UseDirection::Left:return 2;\n  case UseDirection::Right:return 3;\n  }\n  return 0;\n}\n\nUseDirection ActorTools::intToDirection(int dir) {\n  switch (dir) {\n  case 0:return UseDirection::Front;\n  case 1:return UseDirection::Back;\n  case 2:return UseDirection::Left;\n  case 3:return UseDirection::Right;\n  }\n  return UseDirection::Front;\n}\n}"
  },
  {
    "path": "src/System/DebugTools/ActorTools.hpp",
    "content": "#pragma once\n#include <imgui.h>\n#include <utility>\n#include <vector>\n#include <engge/Entities/Entity.hpp>\n#include <engge/Entities/Costume.hpp>\n\nnamespace ng {\nclass Actor;\nclass Engine;\n\nclass ActorTools final {\npublic:\n  explicit ActorTools(Engine &engine);\n  void render();\n\nprivate:\n  void showInventory(Actor *actor);\n  void showProperties(Actor *actor);\n  void showCostume(Actor *actor);\n  void showActorTable(Actor *actor);\n\nprivate:\n  static std::string getFlags(Actor &actor);\n  static int facingToInt(Facing facing);\n  static Facing intToFacing(int facing);\n  static int directionToInt(UseDirection dir);\n  static UseDirection intToDirection(int dir);\n\npublic:\n  bool actorsVisible{false};\n\nprivate:\n  Engine &m_engine;\n  Actor* m_selectedActor{nullptr};\n  ImGuiTextFilter m_filterCostume;\n  bool m_showActorTable{false};\n  bool m_showInventory{false};\n  bool m_showProperties{false};\n  bool m_showCostume{false};\n};\n}"
  },
  {
    "path": "src/System/DebugTools/CameraTools.cpp",
    "content": "#include \"CameraTools.hpp\"\n#include <ngf/Graphics/ImGuiExtensions.h>\n#include <engge/Engine/Engine.hpp>\n#include <engge/Engine/Camera.hpp>\n\nnamespace ng {\nCameraTools::CameraTools(Engine &engine) : m_engine(engine) {}\n\nvoid CameraTools::render() {\n  if (!ImGui::CollapsingHeader(\"Camera\"))\n    return;\n\n  ImGui::Text(\"Is moving: %s\", m_engine.getCamera().isMoving() ? \"yes\" : \"no\");\n  auto pos = m_engine.getCamera().getAt();\n  if (ngf::ImGui::InputFloat2(\"Position\", &pos)) {\n    m_engine.getCamera().at(pos);\n  }\n  auto optBounds = m_engine.getCamera().getBounds();\n  ngf::irect bounds;\n  if (optBounds.has_value()) {\n    bounds = optBounds.value();\n  }\n  if (ngf::ImGui::InputInt4(\"Bounds\", &bounds)) {\n    m_engine.getCamera().setBounds(bounds);\n  }\n  ImGui::SameLine();\n  if (ImGui::Button(\"Reset##Bounds\")) {\n    m_engine.getCamera().resetBounds();\n  }\n}\n}"
  },
  {
    "path": "src/System/DebugTools/CameraTools.hpp",
    "content": "#pragma once\n#include <imgui.h>\n\nnamespace ng {\nclass Engine;\n\nclass CameraTools final {\npublic:\n  explicit CameraTools(Engine &engine);\n  void render();\n\nprivate:\n  Engine &m_engine;\n};\n}"
  },
  {
    "path": "src/System/DebugTools/Console.cpp",
    "content": "#include \"Console.hpp\"\n#include <ctype.h>                        // toupper\n#include <string>\n#include <engge/Engine/Engine.hpp>\n#include <engge/Room/Room.hpp>\n#include \"Util/Util.hpp\"\n\nnamespace ng {\nConsole::Console(Engine &engine) : _engine(engine) {\n  ClearLog();\n  memset(InputBuf, 0, sizeof(InputBuf));\n  HistoryPos = -1;\n  Commands.push_back(\"HELP\");\n  Commands.push_back(\"HISTORY\");\n  Commands.push_back(\"CLEAR\");\n  Commands.push_back(\"actors\");\n  Commands.push_back(\"print\");\n  AutoScroll = true;\n  ScrollToBottom = false;\n  AddLog(\"Welcome to the Console!\");\n}\n\nConsole::~Console() {\n  ClearLog();\n  for (int i = 0; i < History.Size; i++)\n    free(History[i]);\n}\n\n// Portable helpers\nint Console::Stricmp(const char *str1, const char *str2) {\n  int d;\n  while ((d = toupper(*str2) - toupper(*str1)) == 0 && *str1) {\n    str1++;\n    str2++;\n  }\n  return d;\n}\n\nint Console::Strnicmp(const char *str1, const char *str2, int n) {\n  int d = 0;\n  while (n > 0 && (d = toupper(*str2) - toupper(*str1)) == 0 && *str1) {\n    str1++;\n    str2++;\n    n--;\n  }\n  return d;\n}\n\nchar *Console::Strdup(const char *str) {\n  size_t len = strlen(str) + 1;\n  void *buf = malloc(len);\n  IM_ASSERT(buf);\n  return (char *) memcpy(buf, (const void *) str, len);\n}\n\nvoid Console::Strtrim(char *str) {\n  char *str_end = str + strlen(str);\n  while (str_end > str && str_end[-1] == ' ')\n    str_end--;\n  *str_end = 0;\n}\n\nvoid Console::ClearLog() {\n  for (int i = 0; i < Items.Size; i++)\n    free(Items[i]);\n  Items.clear();\n}\n\nvoid Console::PrintVar(const char *var) {\n  std::string s(\"dumpvar(\");\n  s.append(var).append(\")\");\n  _engine.execute(s);\n}\n\nvoid Console::DumpActors() {\n  std::ostringstream os;\n  AddLog(\"[%-4s] %-20s %-22s (%-4s,%-3s) %4s\", \"id\", \"name\", \"room\", \"x\", \"y\", \"scale\");\n  for (const auto &actor : _engine.getActors()) {\n    std::string roomName(\"Void\");\n    if (actor->getRoom()) {\n      roomName = actor->getRoom()->getName();\n      roomName.append(\"(\").append(std::to_string(actor->getRoom()->getId())).append(\")\");\n    }\n    auto name = toUtf8(_engine.getText(actor->getName()));\n    AddLog(\"[%-4d] %-20s %-22s (%-4.0f,%-3.0f) %3.1f\",\n           actor->getId(),\n           name.data(),\n           roomName.data(),\n           actor->getPosition().x,\n           actor->getPosition().y, actor->getScale());\n  }\n}\n\nvoid Console::AddLog(const char *fmt, ...) {\n// FIXME-OPT\n  char buf[1024];\n  va_list args;\n  va_start(args, fmt\n  );\n  vsnprintf(buf, IM_ARRAYSIZE(buf), fmt, args\n  );\n  buf[\n      IM_ARRAYSIZE(buf)\n          - 1] = 0;\n  va_end(args);\n  Items.\n      push_back(Strdup(buf)\n  );\n}\n\nvoid Console::Draw(const char *title, bool *p_open) {\n  ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver);\n  if (!ImGui::Begin(title, p_open)) {\n    ImGui::End();\n    return;\n  }\n\n  // As a specific feature guaranteed by the library, after calling Begin() the last Item represent the title bar. So e.g. IsItemHovered() will return true when hovering the title bar.\n  // Here we create a context menu only available from the title bar.\n  if (ImGui::BeginPopupContextItem()) {\n    if (ImGui::MenuItem(\"Close Console\"))\n      *p_open = false;\n    ImGui::EndPopup();\n  }\n\n  ImGui::TextWrapped(\"Enter 'HELP' for help, press TAB to use text completion.\");\n\n  if (ImGui::SmallButton(\"Clear\")) {\n    ClearLog();\n  }\n  ImGui::SameLine();\n  bool copy_to_clipboard = ImGui::SmallButton(\"Copy\");\n  ImGui::Separator();\n\n  // Options menu\n  if (ImGui::BeginPopup(\"Options\")) {\n    ImGui::Checkbox(\"Auto-scroll\", &AutoScroll);\n    ImGui::EndPopup();\n  }\n\n  // Options, Filter\n  if (ImGui::Button(\"Options\"))\n    ImGui::OpenPopup(\"Options\");\n  ImGui::SameLine();\n  Filter.Draw(\"Filter (\\\"incl,-excl\\\") (\\\"error\\\")\", 180);\n  ImGui::Separator();\n\n  const float footer_height_to_reserve =\n      ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing(); // 1 separator, 1 input text\n  ImGui::BeginChild(\"ScrollingRegion\",\n                    ImVec2(0, -footer_height_to_reserve),\n                    false,\n                    ImGuiWindowFlags_HorizontalScrollbar); // Leave room for 1 separator + 1 InputText\n  if (ImGui::BeginPopupContextWindow()) {\n    if (ImGui::Selectable(\"Clear\"))\n      ClearLog();\n    ImGui::EndPopup();\n  }\n\n  // Display every line as a separate entry so we can change their color or add custom widgets. If you only want raw text you can use ImGui::TextUnformatted(log.begin(), log.end());\n  // NB- if you have thousands of entries this approach may be too inefficient and may require user-side clipping to only process visible items.\n  // You can seek and display only the lines that are visible using the ImGuiListClipper helper, if your elements are evenly spaced and you have cheap random access to the elements.\n  // To use the clipper we could replace the 'for (int i = 0; i < Items.Size; i++)' loop with:\n  //     ImGuiListClipper clipper(Items.Size);\n  //     while (clipper.Step())\n  //         for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)\n  // However, note that you can not use this code as is if a filter is active because it breaks the 'cheap random-access' property. We would need random-access on the post-filtered list.\n  // A typical application wanting coarse clipping and filtering may want to pre-compute an array of indices that passed the filtering test, recomputing this array when user changes the filter,\n  // and appending newly elements as they are inserted. This is left as a task to the user until we can manage to improve this example code!\n  // If your items are of variable size you may want to implement code similar to what ImGuiListClipper does. Or split your data into fixed height items to allow random-seeking into your list.\n  ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4, 1)); // Tighten spacing\n  if (copy_to_clipboard)\n    ImGui::LogToClipboard();\n  for (int i = 0; i < Items.Size; i++) {\n    const char *item = Items[i];\n    if (!Filter.PassFilter(item))\n      continue;\n\n    // Normally you would store more information in your item (e.g. make Items[] an array of structure, store color/type etc.)\n    bool pop_color = false;\n    if (strstr(item, \"[error]\")) {\n      item += 7;\n      ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.4f, 0.4f, 1.0f));\n      pop_color = true;\n    } else if (strncmp(item, \"> \", 2) == 0) {\n      ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.8f, 0.6f, 1.0f));\n      pop_color = true;\n    }\n    ImGui::TextUnformatted(item);\n    if (pop_color)\n      ImGui::PopStyleColor();\n  }\n  if (copy_to_clipboard)\n    ImGui::LogFinish();\n\n  if (ScrollToBottom || (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY()))\n    ImGui::SetScrollHereY(1.0f);\n  ScrollToBottom = false;\n\n  ImGui::PopStyleVar();\n  ImGui::EndChild();\n  ImGui::Separator();\n\n  // Command-line\n  bool reclaim_focus = false;\n  if (ImGui::InputText(\"Input\",\n                       InputBuf,\n                       IM_ARRAYSIZE(InputBuf),\n                       ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_CallbackCompletion\n                           | ImGuiInputTextFlags_CallbackHistory,\n                       &TextEditCallbackStub,\n                       (void *) this)) {\n    char *s = InputBuf;\n    Strtrim(s);\n    if (s[0])\n      ExecCommand(s);\n    strcpy(s, \"\");\n    reclaim_focus = true;\n  }\n\n  // Auto-focus on window apparition\n  ImGui::SetItemDefaultFocus();\n  if (reclaim_focus)\n    ImGui::SetKeyboardFocusHere(-1); // Auto focus previous widget\n\n  ImGui::End();\n}\n\nvoid Console::ExecCommand(const char *command_line) {\n  AddLog(\"> %s\\n\", command_line);\n\n  // Insert into history. First find match and delete it so it can be pushed to the back. This isn't trying to be smart or optimal.\n  HistoryPos = -1;\n  for (int i = History.Size - 1; i >= 0; i--)\n    if (Stricmp(History[i], command_line) == 0) {\n      free(History[i]);\n      History.erase(History.begin() + i);\n      break;\n    }\n  History.push_back(Strdup(command_line));\n\n  // Process command\n  if (Stricmp(command_line, \"actors\") == 0) {\n    DumpActors();\n  } else if (Strnicmp(command_line, \"print\", 5) == 0) {\n    PrintVar(command_line + 5);\n  } else if (Stricmp(command_line, \"CLEAR\") == 0) {\n    ClearLog();\n  } else if (Stricmp(command_line, \"HELP\") == 0) {\n    AddLog(\"Commands:\");\n    for (int i = 0; i < Commands.Size; i++)\n      AddLog(\"- %s\", Commands[i]);\n  } else if (Stricmp(command_line, \"HISTORY\") == 0) {\n    int first = History.Size - 10;\n    for (int i = first > 0 ? first : 0; i < History.Size; i++)\n      AddLog(\"%3d: %s\\n\", i, History[i]);\n  } else {\n    AddLog(\"%s\", command_line);\n    _engine.execute(command_line);\n  }\n\n  // On commad input, we scroll to bottom even if AutoScroll==false\n  ScrollToBottom = true;\n}\n\nint Console::TextEditCallbackStub(ImGuiInputTextCallbackData *data) // In C++11 you are better off using lambdas for this sort of forwarding callbacks\n{\n  Console *console = (Console *) data->UserData;\n  return console->TextEditCallback(data);\n}\n\nint Console::TextEditCallback(ImGuiInputTextCallbackData *data) {\n  switch (data->EventFlag) {\n  case ImGuiInputTextFlags_CallbackCompletion: {\n    // Example of TEXT COMPLETION\n\n    // Locate beginning of current word\n    const char *word_end = data->Buf + data->CursorPos;\n    const char *word_start = word_end;\n    while (word_start > data->Buf) {\n      const char c = word_start[-1];\n      if (c == ' ' || c == '\\t' || c == ',' || c == ';')\n        break;\n      word_start--;\n    }\n\n    // Build a list of candidates\n    ImVector<const char *> candidates;\n    for (int i = 0; i < Commands.Size; i++)\n      if (Strnicmp(Commands[i], word_start, (int) (word_end - word_start)) == 0)\n        candidates.push_back(Commands[i]);\n\n    if (candidates.Size == 0) {\n      // No match\n      AddLog(\"No match for \\\"%.*s\\\"!\\n\", (int) (word_end - word_start), word_start);\n    } else if (candidates.Size == 1) {\n      // Single match. Delete the beginning of the word and replace it entirely so we've got nice casing\n      data->DeleteChars((int) (word_start - data->Buf), (int) (word_end - word_start));\n      data->InsertChars(data->CursorPos, candidates[0]);\n      data->InsertChars(data->CursorPos, \" \");\n    } else {\n      // Multiple matches. Complete as much as we can, so inputing \"C\" will complete to \"CL\" and display \"CLEAR\" and \"CLASSIFY\"\n      int match_len = (int) (word_end - word_start);\n      for (;;) {\n        int c = 0;\n        bool all_candidates_matches = true;\n        for (int i = 0; i < candidates.Size && all_candidates_matches; i++)\n          if (i == 0)\n            c = toupper(candidates[i][match_len]);\n          else if (c == 0 || c != toupper(candidates[i][match_len]))\n            all_candidates_matches = false;\n        if (!all_candidates_matches)\n          break;\n        match_len++;\n      }\n\n      if (match_len > 0) {\n        data->DeleteChars((int) (word_start - data->Buf), (int) (word_end - word_start));\n        data->InsertChars(data->CursorPos, candidates[0], candidates[0] + match_len);\n      }\n\n      // List matches\n      AddLog(\"Possible matches:\\n\");\n      for (int i = 0; i < candidates.Size; i++)\n        AddLog(\"- %s\\n\", candidates[i]);\n    }\n\n    break;\n  }\n  case ImGuiInputTextFlags_CallbackHistory: {\n    // Example of HISTORY\n    const int prev_history_pos = HistoryPos;\n    if (data->EventKey == ImGuiKey_UpArrow) {\n      if (HistoryPos == -1)\n        HistoryPos = History.Size - 1;\n      else if (HistoryPos > 0)\n        HistoryPos--;\n    } else if (data->EventKey == ImGuiKey_DownArrow) {\n      if (HistoryPos != -1)\n        if (++HistoryPos >= History.Size)\n          HistoryPos = -1;\n    }\n\n    // A better implementation would preserve the data on the current input line along with cursor position.\n    if (prev_history_pos != HistoryPos) {\n      const char *history_str = (HistoryPos >= 0) ? History[HistoryPos] : \"\";\n      data->DeleteChars(0, data->BufTextLen);\n      data->InsertChars(0, history_str);\n    }\n  }\n  }\n  return 0;\n}\n}"
  },
  {
    "path": "src/System/DebugTools/Console.hpp",
    "content": "#pragma once\n#include <imgui.h>\n\nnamespace ng {\nclass Engine;\n\nstruct Console {\n  char InputBuf[256];\n  ImVector<char *> Items;\n  ImVector<const char *> Commands;\n  ImVector<char *> History;\n  int HistoryPos;    // -1: new line, 0..History.Size-1 browsing history.\n  ImGuiTextFilter Filter;\n  bool AutoScroll;\n  bool ScrollToBottom;\n  Engine &_engine;\n\n  Console(Engine &engine);\n  ~Console();\n\n  // Portable helpers\n  static int Stricmp(const char *str1, const char *str2);\n  static int Strnicmp(const char *str1, const char *str2, int n);\n  static char *Strdup(const char *str);\n  static void Strtrim(char *str);\n\n  void ClearLog();\n  void PrintVar(const char *var);\n  void DumpActors();\n  void AddLog(const char *fmt, ...) IM_FMTARGS(2);\n  void Draw(const char *title, bool *p_open);\n  void ExecCommand(const char *command_line);\n  static int TextEditCallbackStub(ImGuiInputTextCallbackData *data); // In C++11 you are better off using lambdas for this sort of forwarding callbacks\n  int TextEditCallback(ImGuiInputTextCallbackData *data);\n};\n}"
  },
  {
    "path": "src/System/DebugTools/ConsoleTools.cpp",
    "content": "#include \"ConsoleTools.hpp\"\n#include <engge/Scripting/ScriptEngine.hpp>\n\nnamespace ng {\nConsoleTools::ConsoleTools(Engine &engine) : m_console(engine) {\n  ScriptEngine::registerErrorCallback([this](HSQUIRRELVM, const SQChar *s) {\n    m_console.AddLog(\"[error] %s\", s);\n  });\n  ScriptEngine::registerPrintCallback([this](HSQUIRRELVM, const SQChar *s) {\n    m_console.AddLog(\"%s\", s);\n  });\n}\n\nvoid ConsoleTools::render() {\n  if (!consoleVisible)\n    return;\n  m_console.Draw(\"Console\", &consoleVisible);\n}\n}"
  },
  {
    "path": "src/System/DebugTools/ConsoleTools.hpp",
    "content": "#pragma once\n#include \"Console.hpp\"\n\nnamespace ng {\nclass Engine;\n\nclass ConsoleTools final {\npublic:\n  explicit ConsoleTools(Engine &engine);\n  void render();\n\npublic:\n  bool consoleVisible{false};\n\nprivate:\n  Console m_console;\n};\n}"
  },
  {
    "path": "src/System/DebugTools/DebugControls.cpp",
    "content": "#include <imgui.h>\n#include <vector>\n#include \"DebugControls.hpp\"\n#include <engge/Scripting/ScriptEngine.hpp>\n#include \"../../extlibs/squirrel/squirrel/sqstring.h\"\n#include \"../../extlibs/squirrel/squirrel/sqstate.h\"\n#include \"../../extlibs/squirrel/squirrel/sqtable.h\"\n\nnamespace ng {\nbool DebugControls::stringGetter(void *vec, int idx, const char **out_text) {\n  auto &vector = *static_cast<std::vector<std::string> *>(vec);\n  if (idx < 0 || idx >= static_cast<int>(vector.size())) {\n    return false;\n  }\n  *out_text = vector.at(idx).data();\n  return true;\n}\n\nvoid DebugControls::createTree(const char *tableKey, HSQOBJECT obj) {\n  if (ImGui::TreeNode(tableKey, \"%s = {}\", tableKey)) {\n    ImGui::PushID(tableKey);\n    SQObjectPtr refpos;\n    SQObjectPtr outkey, outvar;\n    SQInteger res;\n    while ((res = _table(obj)->Next(false, refpos, outkey, outvar)) != -1) {\n      auto key = _stringval(outkey);\n      ImGui::PushID(key);\n      if (outvar._type == OT_STRING) {\n        char value[32];\n        strcpy(value, _stringval(outvar));\n        ImGui::Text(\"%s = \", key);\n        ImGui::SameLine(300);\n        if (ImGui::InputText(\"\", value, IM_ARRAYSIZE(value))) {\n          ScriptEngine::set(obj, key, value);\n        }\n      } else if (outvar._type == OT_INTEGER) {\n        auto value = static_cast<int>(_integer(outvar));\n        ImGui::Text(\"%s = \", key);\n        ImGui::SameLine(300);\n        if (ImGui::InputInt(\"\", &value)) {\n          ScriptEngine::set(obj, key, value);\n        }\n      } else if (outvar._type == OT_BOOL) {\n        auto value = _integer(outvar) != 0;\n        ImGui::Text(\"%s = \", key);\n        ImGui::SameLine(300);\n        if (ImGui::Checkbox(\"\", &value)) {\n          ScriptEngine::set(obj, key, value);\n        }\n      } else if (outvar._type == OT_FLOAT) {\n        auto value = _float(outvar);\n        ImGui::Text(\"%s = \", key);\n        ImGui::SameLine(300);\n        if (ImGui::InputFloat(\"\", &value)) {\n          ScriptEngine::set(obj, key, value);\n        }\n      } else if (outvar._type == OT_CLOSURE || outvar._type == OT_NATIVECLOSURE) {\n        ImGui::Text(\"%s = code()\", key);\n      } else if (outvar._type == OT_NULL) {\n        ImGui::Text(\"%s = (null)\", key);\n      } else if (outvar._type == OT_TABLE) {\n        createTree(key, outvar);\n      } else {\n        ImGui::Text(\"%s = (not managed, type = %d)\", key, outvar._type);\n      }\n      refpos._type = OT_INTEGER;\n      refpos._unVal.nInteger = res;\n      ImGui::PopID();\n    }\n    ImGui::PopID();\n    ImGui::TreePop();\n  }\n}\n}"
  },
  {
    "path": "src/System/DebugTools/DebugControls.hpp",
    "content": "#pragma once\n#include <squirrel.h>\n\nnamespace ng {\nclass DebugControls final {\npublic:\n  static bool stringGetter(void *vec, int idx, const char **out_text);\n  static void createTree(const char *tableKey, HSQOBJECT obj);\n};\n}\n"
  },
  {
    "path": "src/System/DebugTools/DebugTools.cpp",
    "content": "#include \"DebugTools.hpp\"\n#include <engge/Scripting/ScriptEngine.hpp>\n#include <engge/Room/Room.hpp>\n#include <engge/Engine/InputStateConstants.hpp>\n#include \"Engine/DebugFeatures.hpp\"\n#include \"../../extlibs/squirrel/squirrel/sqpcheader.h\"\n#include \"../../extlibs/squirrel/squirrel/sqvm.h\"\n#include \"../../extlibs/squirrel/squirrel/sqstring.h\"\n#include \"../../extlibs/squirrel/squirrel/sqtable.h\"\n#include \"../../extlibs/squirrel/squirrel/sqarray.h\"\n#include \"../../extlibs/squirrel/squirrel/sqfuncproto.h\"\n#include \"../../extlibs/squirrel/squirrel/sqclosure.h\"\n#include \"../../extlibs/squirrel/squirrel/squserdata.h\"\n#include \"../../extlibs/squirrel/squirrel/sqclass.h\"\n\nnamespace ng {\nDebugTools::DebugTools(Engine &engine)\n    : m_engine(engine),\n      m_consoleTools(engine),\n      m_actorTools(engine),\n      m_objectTools(engine),\n      m_roomTools(engine),\n      m_soundTools(engine),\n      m_threadTools(engine),\n      m_generalTools(engine,\n                     m_texturesTools.texturesVisible,\n                     m_consoleTools.consoleVisible,\n                     m_showGlobalsTable,\n                     m_soundTools.soundsVisible,\n                     m_threadTools.threadsVisible,\n                     m_actorTools.actorsVisible,\n                     m_objectTools.objectsVisible),\n      m_cameraTools(engine),\n      m_preferencesTools(engine) {\n  memset(m_renderTimes.values, 0, IM_ARRAYSIZE(m_renderTimes.values));\n  memset(m_updateTimes.values, 0, IM_ARRAYSIZE(m_updateTimes.values));\n}\n\nvoid DebugTools::render() {\n  if (!visible)\n    return;\n\n  ImGui::Begin(\"Debug\");\n\n  m_generalTools.render();\n  m_texturesTools.render();\n  showGlobalsTable();\n  m_consoleTools.render();\n  m_cameraTools.render();\n  showInputState();\n  m_preferencesTools.render();\n\n  m_actorTools.render();\n  m_objectTools.render();\n  m_roomTools.render();\n  m_soundTools.render();\n  m_threadTools.render();\n  showRoomTable();\n  showPerformance();\n\n  ImGui::End();\n}\n\nvoid DebugTools::showPerformance() {\n  if (!ImGui::CollapsingHeader(\"Performance\"))\n    return;\n\n  renderTimes(\"Rendering (ms)\", m_renderTimes, []() { return DebugFeatures::renderTime; });\n  renderTimes(\"Update (ms)\", m_updateTimes, []() { return DebugFeatures::updateTime; });\n}\n\nvoid DebugTools::renderTimes(const char *label, Plot &plot, const std::function<ngf::TimeSpan()> &func) {\n  float average = 0.0f;\n  for (int n = 0; n < IM_ARRAYSIZE(plot.values); n++)\n    average += plot.values[n];\n  average /= (float) IM_ARRAYSIZE(plot.values);\n  char overlay[48];\n  sprintf(overlay, \"avg %f ms\", average);\n\n  plot.values[plot.offset] = func().getTotalSeconds() * 1000.f;\n  ImGui::PlotLines(label, plot.values, IM_ARRAYSIZE(plot.values), plot.offset, overlay);\n  plot.offset = (plot.offset + 1) % IM_ARRAYSIZE(plot.values);\n}\n\nvoid DebugTools::showRoomTable() {\n  if (!m_showRoomTable)\n    return;\n\n  ImGui::Begin(\"Room table\", &m_showRoomTable);\n  auto pRoom = m_engine.getRoom();\n  if (pRoom) {\n    auto table = pRoom->getTable();\n    DebugControls::createTree(pRoom->getName().c_str(), table);\n  }\n  ImGui::End();\n}\n\nvoid DebugTools::showGlobalsTable() {\n  if (!m_showGlobalsTable)\n    return;\n\n  ImGui::Begin(\"Globals table\", &m_showGlobalsTable);\n  SQObjectPtr g;\n  _table(ScriptEngine::getVm()->_roottable)->Get(ScriptEngine::toSquirrel(\"g\"), g);\n  DebugControls::createTree(\"Globals\", g);\n  ImGui::End();\n}\n\nvoid DebugTools::showInputState() {\n  if (!ImGui::CollapsingHeader(\"Input\"))\n    return;\n\n  auto inputState = m_engine.getInputState();\n  auto inputActive = (inputState & InputStateConstants::UI_INPUT_ON) == InputStateConstants::UI_INPUT_ON;\n  if (ImGui::Checkbox(\"Input active\", &inputActive)) {\n    m_engine.setInputState(inputActive ? InputStateConstants::UI_INPUT_ON : InputStateConstants::UI_INPUT_OFF);\n  }\n  auto cursorVisible = (inputState & InputStateConstants::UI_CURSOR_ON) == InputStateConstants::UI_CURSOR_ON;\n  if (ImGui::Checkbox(\"Cusrsor visible\", &cursorVisible)) {\n    m_engine.setInputState(cursorVisible ? InputStateConstants::UI_CURSOR_ON\n                                         : InputStateConstants::UI_CURSOR_OFF);\n  }\n\n  auto inputVerbs = (inputState & InputStateConstants::UI_VERBS_ON) == InputStateConstants::UI_VERBS_ON;\n  if (ImGui::Checkbox(\"Input verbs\", &inputVerbs)) {\n    m_engine.setInputState(inputVerbs ? InputStateConstants::UI_VERBS_ON : InputStateConstants::UI_VERBS_OFF);\n  }\n  auto inputHUD = (inputState & InputStateConstants::UI_HUDOBJECTS_ON) == InputStateConstants::UI_HUDOBJECTS_ON;\n  if (ImGui::Checkbox(\"Input HUD\", &inputHUD)) {\n    m_engine.setInputState(inputHUD ? InputStateConstants::UI_HUDOBJECTS_ON\n                                    : InputStateConstants::UI_HUDOBJECTS_OFF);\n  }\n}\n}"
  },
  {
    "path": "src/System/DebugTools/DebugTools.hpp",
    "content": "#pragma once\n#include <optional>\n#include <functional>\n#include \"ConsoleTools.hpp\"\n#include \"TextureTools.hpp\"\n#include \"DebugControls.hpp\"\n#include \"ActorTools.hpp\"\n#include \"ObjectTools.hpp\"\n#include \"RoomTools.hpp\"\n#include \"SoundTools.hpp\"\n#include \"ThreadTools.hpp\"\n#include \"GeneralTools.hpp\"\n#include \"CameraTools.hpp\"\n#include \"PreferencesTools.hpp\"\n\nnamespace ng {\nclass Engine;\n\nclass DebugTools final {\npublic:\n  explicit DebugTools(Engine &engine);\n\n  void render();\n\nprivate:\n  struct Plot {\n    float values[16];\n    int offset{0};\n  } m_renderTimes, m_updateTimes;\n\n  void showPerformance();\n  static void renderTimes(const char *label, Plot &plot, const std::function<ngf::TimeSpan()> &func);\n  void showRoomTable();\n  void showGlobalsTable();\n  void showInputState();\n\npublic:\n  bool visible{false};\n\nprivate:\n  Engine &m_engine;\n  bool m_showRoomTable{false};\n  bool m_showGlobalsTable{false};\n  TextureTools m_texturesTools;\n  ConsoleTools m_consoleTools;\n  ActorTools m_actorTools;\n  ObjectTools m_objectTools;\n  RoomTools m_roomTools;\n  SoundTools m_soundTools;\n  ThreadTools m_threadTools;\n  GeneralTools m_generalTools;\n  CameraTools m_cameraTools;\n  PreferencesTools m_preferencesTools;\n};\n} // namespace ng\n"
  },
  {
    "path": "src/System/DebugTools/GeneralTools.cpp",
    "content": "#include \"GeneralTools.hpp\"\n#include <imgui.h>\n#include <engge/Dialog/DialogManager.hpp>\n#include <engge/Scripting/ScriptEngine.hpp>\n#include <engge/Engine/Preferences.hpp>\n#include <engge/Engine/EntityManager.hpp>\n#include <engge/Engine/ThreadBase.hpp>\n#include \"Engine/DebugFeatures.hpp\"\n#include \"DebugControls.hpp\"\n#include <squirrel.h>\n#include <Util/Util.hpp>\n#include \"../../extlibs/squirrel/squirrel/sqvm.h\"\n#include \"../../extlibs/squirrel/squirrel/sqstate.h\"\n#include \"../../extlibs/squirrel/squirrel/sqstring.h\"\n#include \"../../extlibs/squirrel/squirrel/sqfuncproto.h\"\n#include \"../../extlibs/squirrel/squirrel/sqclosure.h\"\n\nnamespace ng {\nGeneralTools::GeneralTools(Engine &engine,\n                           bool &textureVisible,\n                           bool &consoleVisible,\n                           bool &showGlobalsTable,\n                           bool &soundsVisible,\n                           bool &threadsVisible,\n                           bool &actorsVisible,\n                           bool &objectsVisible)\n    : m_engine(engine), m_textureVisible(textureVisible), m_consoleVisible(consoleVisible),\n      m_showGlobalsTable(showGlobalsTable), m_soundsVisible(soundsVisible), m_threadsVisible(threadsVisible),\n      m_actorsVisible(actorsVisible), m_objectsVisible(objectsVisible) {}\n\nvoid GeneralTools::render() {\n  std::stringstream s;\n  s << \"Stack: \" << sq_gettop(ScriptEngine::getVm());\n  std::vector<std::string> stack;\n  getStack(stack);\n  ImGui::Combo(s.str().c_str(),\n               &m_selectedStack,\n               DebugControls::stringGetter,\n               static_cast<void *>(&stack),\n               stack.size());\n  ImGui::Text(\"In cutscene: %s\", m_engine.inCutscene() ? \"yes\" : \"no\");\n  auto dialogState = m_engine.getDialogManager().getState();\n  ImGui::Text(\"In dialog: %s\",\n              ((dialogState == DialogManagerState::Active)\n               ? \"yes\"\n               : (dialogState == DialogManagerState::WaitingForChoice ? \"waiting for choice\" : \"no\")));\n  ImGui::Separator();\n\n  auto mousePos = m_engine.getMousePositionInRoom();\n  ImGui::Text(\"Pos (room): (%.0f, %0.f)\", mousePos.x, mousePos.y);\n  auto pRoom = m_engine.getRoom();\n  if (pRoom) {\n    auto pos = toDefaultView((glm::ivec2) mousePos, pRoom->getScreenSize());\n    ImGui::Text(\"Pos (screen): (%.0f, %0.f)\", pos.x, pos.y);\n  }\n  ImGui::Separator();\n\n  auto gameSpeedFactor = m_engine.getPreferences().getUserPreference(PreferenceNames::EnggeGameSpeedFactor,\n                                                                     PreferenceDefaultValues::EnggeGameSpeedFactor);\n  if (ImGui::SliderFloat(\"Game speed factor\", &gameSpeedFactor, 0.f, 5.f)) {\n    m_engine.getPreferences().setUserPreference(PreferenceNames::EnggeGameSpeedFactor, gameSpeedFactor);\n  }\n  ImGui::Checkbox(\"Show cursor position\", &DebugFeatures::showCursorPosition);\n  ImGui::Checkbox(\"Show hovered object\", &DebugFeatures::showHoveredObject);\n  ImGui::Checkbox(\"Show text bounds\", &DebugFeatures::showTextBounds);\n  ImGui::Checkbox(\"Actors\", &m_actorsVisible);\n  ImGui::Checkbox(\"Objects\", &m_objectsVisible);\n  ImGui::Checkbox(\"Sounds\", &m_soundsVisible);\n  ImGui::Checkbox(\"Textures\", &m_textureVisible);\n  ImGui::Checkbox(\"Threads\", &m_threadsVisible);\n  ImGui::Checkbox(\"Console\", &m_consoleVisible);\n  ImGui::SameLine();\n  if (ImGui::SmallButton(\"Globals...\")) {\n    m_showGlobalsTable = true;\n  }\n}\n\nvoid GeneralTools::getStack(std::vector<std::string> &stack) {\n  HSQOBJECT obj;\n  auto size = static_cast<int>(sq_gettop(ScriptEngine::getVm()));\n  for (int i = 1; i <= size; ++i) {\n    auto type = sq_gettype(ScriptEngine::getVm(), -i);\n    sq_getstackobj(ScriptEngine::getVm(), -i, &obj);\n    std::ostringstream s;\n    s << \"#\" << i << \": \";\n    switch (type) {\n    case OT_NULL:s << \"null\";\n      break;\n    case OT_INTEGER:s << sq_objtointeger(&obj);\n      break;\n    case OT_FLOAT:s << sq_objtofloat(&obj);\n      break;\n    case OT_BOOL:s << (sq_objtobool(&obj) == SQTrue ? \"true\" : \"false\");\n      break;\n    case OT_USERPOINTER: {\n      s << \"userpointer\";\n      break;\n    }\n    case OT_STRING:s << sq_objtostring(&obj);\n      break;\n    case OT_TABLE: {\n      int id;\n      if (ScriptEngine::rawGet(obj, \"_id\", id)) {\n        if (EntityManager::isActor(id)) {\n          s << \"actor\";\n        } else if (EntityManager::isRoom(id)) {\n          s << \"room\";\n        } else if (EntityManager::isObject(id)) {\n          s << \"object\";\n        } else if (EntityManager::isLight(id)) {\n          s << \"light\";\n        } else if (EntityManager::isSound(id)) {\n          s << \"sound\";\n        } else if (EntityManager::isThread(id)) {\n          s << \"thread table\";\n        } else {\n          s << \"table\";\n        }\n      } else {\n        s << \"table\";\n      }\n    }\n      break;\n    case OT_ARRAY:s << \"array\";\n      break;\n    case OT_CLOSURE: {\n      s << \"closure: \";\n      auto pName = _closure(obj)->_function->_name;\n      auto pSourcename = _closure(obj)->_function->_sourcename;\n      auto line = _closure(obj)->_function->_lineinfos->_line;\n      s << (pName._type != OT_NULL ? _stringval(pName) : \"null\");\n      s << ' ' << (pSourcename._type != OT_NULL ? _stringval(pSourcename) : \"-null\");\n      s << \" [\" << line << ']';\n      break;\n    }\n    case OT_NATIVECLOSURE:s << \"native closure\";\n      break;\n    case OT_GENERATOR:s << \"generator\";\n      break;\n    case OT_USERDATA:s << \"user data\";\n      break;\n    case OT_THREAD: {\n      s << \"thread\";\n      auto pThread = EntityManager::getThreadFromVm(_thread(obj));\n      if (pThread) {\n        s << \" \" << pThread->getName();\n      }\n      break;\n    }\n    case OT_INSTANCE:s << \"instance\";\n      break;\n    case OT_WEAKREF:s << \"weak ref\";\n      break;\n    default:s << \"?\";\n      break;\n    }\n    stack.push_back(s.str());\n  }\n}\n}"
  },
  {
    "path": "src/System/DebugTools/GeneralTools.hpp",
    "content": "#pragma once\n#include <string>\n#include <vector>\n\nnamespace ng {\nclass Engine;\n\nclass GeneralTools final {\npublic:\n  explicit GeneralTools(Engine &engine, bool &textureVisible, bool &consoleVisible, bool &showGlobalsTable,\n                        bool &soundsVisible, bool & threadsVisible, bool & actorsVisible, bool &objectsVisible);\n\n  void render();\n\nprivate:\n  static void getStack(std::vector<std::string> &stack);\n\nprivate:\n  Engine &m_engine;\n  int m_selectedStack{0};\n  bool &m_textureVisible;\n  bool &m_consoleVisible;\n  bool &m_showGlobalsTable;\n  bool& m_soundsVisible;\n  bool& m_threadsVisible;\n  bool& m_actorsVisible;\n  bool& m_objectsVisible;\n};\n}"
  },
  {
    "path": "src/System/DebugTools/ObjectTools.cpp",
    "content": "#include \"ObjectTools.hpp\"\n#include <engge/Engine/Engine.hpp>\n#include <engge/Room/Room.hpp>\n#include <engge/Entities/Object.hpp>\n#include <engge/Entities/TextObject.hpp>\n#include <engge/Engine/Trigger.hpp>\n#include <ngf/Graphics/ImGuiExtensions.h>\n#include <imgui.h>\n#include <imgui_stdlib.h>\n#include <engge/Engine/EntityManager.hpp>\n#include \"Util/Util.hpp\"\n\nnamespace ng {\nnamespace {\nstd::string getName(Object *object) {\n  auto name = toUtf8(ng::Engine::getText(object->getKey()));\n  if (!name.empty())\n    return name;\n\n  auto textObj = dynamic_cast<TextObject *>(object);\n  if (textObj) {\n    name = textObj->getText();\n    if (name.size() > 10) {\n      name.erase(name.begin() + 10, name.end());\n      return name + \"...\";\n    }\n  }\n  name = \"#\" + std::to_string(object->getId());\n  return name;\n}\n\nstd::string getType(Object *object) {\n  switch (object->getType()) {\n  case ObjectType::Object:return \"object\";\n  case ObjectType::Spot:return \"spot\";\n  case ObjectType::Trigger:return \"trigger\";\n  case ObjectType::Prop:return \"prop\";\n  }\n  return \"?\";\n}\n\nbool showHorizontalTextAlignment(TextAlignment *alignment) {\n  auto hAlign = *alignment & TextAlignment::Horizontal;\n  if (ImGui::RadioButton(\"Left\", hAlign == TextAlignment::Left)) {\n    *alignment &= ~TextAlignment::Horizontal;\n    *alignment |= TextAlignment::Left;\n    return true;\n  }\n  ImGui::SameLine();\n  if (ImGui::RadioButton(\"Center\", hAlign == TextAlignment::Center)) {\n    *alignment &= ~TextAlignment::Horizontal;\n    *alignment |= TextAlignment::Center;\n    return true;\n  }\n  ImGui::SameLine();\n  if (ImGui::RadioButton(\"Right\", hAlign == TextAlignment::Right)) {\n    *alignment &= ~TextAlignment::Horizontal;\n    *alignment |= TextAlignment::Right;\n    return true;\n  }\n  return false;\n}\n\nbool showVerticalTextAlignment(TextAlignment *alignment) {\n  auto vTop = *alignment & TextAlignment::Top;\n  auto vBottom = *alignment & TextAlignment::Bottom;\n  if (ImGui::RadioButton(\"Top\", vTop == ng::TextAlignment::Top)) {\n    *alignment &= ~TextAlignment::Vertical;\n    *alignment |= TextAlignment::Top;\n    return true;\n  }\n  ImGui::SameLine();\n  if (ImGui::RadioButton(\"Center##Vertical\", vTop == ng::TextAlignment::None && vBottom == ng::TextAlignment::None)) {\n    *alignment &= ~TextAlignment::Vertical;\n    return true;\n  }\n  ImGui::SameLine();\n  if (ImGui::RadioButton(\"Bottom\", vBottom == ng::TextAlignment::Bottom)) {\n    *alignment &= ~TextAlignment::Vertical;\n    *alignment |= TextAlignment::Bottom;\n    return true;\n  }\n  return false;\n}\n}\n\nObjectTools::ObjectTools(Engine &engine) : m_engine(engine) {}\n\nvoid ObjectTools::render() {\n  if (!objectsVisible)\n    return;\n\n  ImGui::Begin(\"Objects\", &objectsVisible);\n  ImGui::Checkbox(\"Properties\", &m_showProperties);\n  ImGui::Checkbox(\"Animations\", &m_showAnimations);\n  ImGui::Separator();\n\n  // show object list\n  auto &objects = m_engine.getRoom()->getObjects();\n  ImGui::Text(\"Count: %ld\", objects.size());\n  m_textFilter.Draw();\n\n  for (auto &&object : objects) {\n    auto name = getName(object.get());\n    if (!m_textFilter.PassFilter(name.c_str()))\n      continue;\n    ImGui::PushID(object.get());\n    bool isSelected = object->getId() == m_objectId;\n    auto visible = object->isVisible();\n    if (ImGui::Checkbox(\"\", &visible)) {\n      object->setVisible(visible);\n    }\n    ImGui::SameLine();\n    if (ImGui::Selectable(name.c_str(), isSelected)) {\n      m_objectId = object->getId();\n    }\n    ImGui::PopID();\n  }\n\n  ImGui::Separator();\n\n  auto pObj = EntityManager::getObjectFromId(m_objectId);\n  if (pObj) {\n    showProperties(pObj);\n    showAnimations(pObj);\n  }\n\n  ImGui::End();\n}\n\nvoid ObjectTools::showAnimations(Object *object) {\n  if (!m_showAnimations)\n    return;\n\n  ImGui::Begin(\"Object Animations\", &m_showAnimations);\n  for (auto &anim : object->getAnims()) {\n    showAnimationNode(&anim);\n  }\n  ImGui::End();\n}\n\nvoid ObjectTools::showAnimationNode(Animation *anim) {\n  if (ImGui::TreeNode(anim, \"%s\", anim->name.c_str())) {\n    for (auto &frame : anim->frames) {\n      ImGui::Text(\"%s\", frame.name.c_str());\n    }\n    for (auto &layer : anim->layers) {\n      showAnimationNode(&layer);\n    }\n    ImGui::TreePop();\n  }\n}\n\nvoid ObjectTools::showProperties(Object *object) {\n  if (!m_showProperties)\n    return;\n\n  auto textObject = dynamic_cast<TextObject *>(object);\n\n  ImGui::Begin(\"Object Properties\", &m_showProperties);\n  auto name = object->getName();\n  ImGui::LabelText(\"Name\", \"%s\", name.c_str());\n  ImGui::Separator();\n\n  if (textObject) {\n    auto text = textObject->getText();\n    if (ImGui::InputText(\"Text\", &text)) {\n      textObject->setText(text);\n    }\n    auto alignment = textObject->getAlignment();\n    if (showHorizontalTextAlignment(&alignment)) {\n      textObject->setAlignment(alignment);\n    }\n    if (showVerticalTextAlignment(&alignment)) {\n      textObject->setAlignment(alignment);\n    }\n    auto maxWidth = textObject->getMaxWidth();\n    if (ImGui::InputInt(\"Max width\", &maxWidth)) {\n      textObject->setMaxWidth(maxWidth);\n    }\n    ImGui::Separator();\n  }\n\n  auto type = getType(object);\n  ImGui::LabelText(\"Type\", \"%s\", type.c_str());\n  auto pOwner = object->getOwner();\n  ImGui::LabelText(\"Owner\", \"%s\", pOwner ? pOwner->getName().c_str() : \"(none)\");\n  auto pParent = object->getParent();\n  ImGui::LabelText(\"Parent\", \"%s\", pParent ? pParent->getName().c_str() : \"(none)\");\n  auto isVisible = object->isVisible();\n  if (ImGui::Checkbox(\"Visible\", &isVisible)) {\n    object->setVisible(isVisible);\n  }\n  auto isLit = object->isLit();\n  if (ImGui::Checkbox(\"Is lit\", &isLit)) {\n    object->setLit(isLit);\n  }\n  auto isTouchable = object->isTouchable();\n  if (ImGui::Checkbox(\"Touchable\", &isTouchable)) {\n    object->setTouchable(isTouchable);\n  }\n  auto state = object->getState();\n  if (ImGui::DragInt(\"State\", &state, 1.0f, 0)) {\n    object->playAnim(state, false);\n  }\n  auto zorder = object->getZOrder();\n  if (ImGui::DragInt(\"Z-Order\", &zorder)) {\n    object->setZOrder(zorder);\n  }\n  auto pos = object->getPosition();\n  if (ImGui::DragFloat2(\"Position\", &pos.x)) {\n    object->setPosition(pos);\n  }\n  auto usePos = object->getUsePosition().value_or(glm::vec2());\n  if (ImGui::DragFloat2(\"Use Position\", &usePos.x)) {\n    object->setUsePosition(usePos);\n  }\n  auto offset = object->getOffset();\n  if (ImGui::DragFloat2(\"Offset\", &offset.x)) {\n    object->setOffset(offset);\n  }\n  auto renderOffset = object->getRenderOffset();\n  if (ImGui::DragInt2(\"Render Offset\", &renderOffset.x)) {\n    object->setRenderOffset(renderOffset);\n  }\n  auto hotspotVisible = object->isHotspotVisible();\n  if (ImGui::Checkbox(\"Show hotspot\", &hotspotVisible)) {\n    object->showDebugHotspot(hotspotVisible);\n  }\n  auto hotspot = object->getHotspot();\n  if (ImGui::DragInt4(\"Hotspot\", &hotspot.min.x)) {\n    object->setHotspot(hotspot);\n  }\n  auto color = object->getColor();\n  if (ngf::ImGui::ColorEdit4(\"Color\", &color)) {\n    object->setColor(color);\n  }\n  auto trigger = object->getTrigger();\n  if (trigger) {\n    ImGui::LabelText(\"Trigger\", \"%s\", trigger->getName().c_str());\n  }\n  ImGui::End();\n}\n}"
  },
  {
    "path": "src/System/DebugTools/ObjectTools.hpp",
    "content": "#pragma once\n#include <imgui.h>\n\nnamespace ng {\nstruct Animation;\nclass Engine;\nclass Object;\n\nclass ObjectTools final {\npublic:\n  explicit ObjectTools(Engine &engine);\n\n  void render();\n\nprivate:\n  void showProperties(Object *object);\n  void showAnimations(Object *object);\n  static void showAnimationNode(Animation *anim);\n\npublic:\n  bool objectsVisible{false};\n\nprivate:\n  Engine &m_engine;\n  int m_objectId{0};\n  ImGuiTextFilter m_textFilter;\n  bool m_showProperties{false};\n  bool m_showAnimations{false};\n};\n}"
  },
  {
    "path": "src/System/DebugTools/PreferencesTools.cpp",
    "content": "#include \"PreferencesTools.hpp\"\n#include <engge/Engine/Engine.hpp>\n#include <engge/Engine/Preferences.hpp>\n#include <string>\n#include <imgui.h>\n\nnamespace ng {\nPreferencesTools::PreferencesTools(Engine &engine) : m_engine(engine) {}\n\nvoid PreferencesTools::render() {\n  if (!ImGui::CollapsingHeader(\"Preferences\"))\n    return;\n\n  auto selectedLang = getSelectedLang();\n  if (ImGui::Combo(\"Language\", &selectedLang, langs, 5)) {\n    setSelectedLang(selectedLang);\n  }\n  auto retroVerbs = m_engine.getPreferences().getUserPreference(PreferenceNames::RetroVerbs,\n                                                               PreferenceDefaultValues::RetroVerbs) != 0;\n  if (ImGui::Checkbox(\"Retro Verbs\", &retroVerbs)) {\n    m_engine.getPreferences().setUserPreference(PreferenceNames::RetroVerbs, retroVerbs ? 1 : 0);\n  }\n  auto retroFonts = m_engine.getPreferences().getUserPreference(PreferenceNames::RetroFonts,\n                                                               PreferenceDefaultValues::RetroFonts);\n  if (ImGui::Checkbox(\"Retro Fonts\", &retroFonts)) {\n    m_engine.getPreferences().setUserPreference(PreferenceNames::RetroFonts, retroFonts ? 1 : 0);\n  }\n  auto invertVerbHighlight =\n      m_engine.getPreferences().getUserPreference(PreferenceNames::InvertVerbHighlight,\n                                                 PreferenceDefaultValues::InvertVerbHighlight);\n  if (ImGui::Checkbox(\"Invert Verb Highlight\", &invertVerbHighlight)) {\n    m_engine.getPreferences().setUserPreference(PreferenceNames::InvertVerbHighlight, invertVerbHighlight ? 1 : 0);\n  }\n  auto hudSentence = m_engine.getPreferences().getUserPreference(PreferenceNames::HudSentence,\n                                                                PreferenceDefaultValues::HudSentence);\n  if (ImGui::Checkbox(\"HUD Sentence\", &hudSentence)) {\n    m_engine.getPreferences().setUserPreference(PreferenceNames::HudSentence, hudSentence ? 1 : 0);\n  }\n  auto uiBackingAlpha = m_engine.getPreferences().getUserPreference(PreferenceNames::UiBackingAlpha,\n                                                                   PreferenceDefaultValues::UiBackingAlpha) * 100.f;\n  if (ImGui::SliderFloat(\"UI Backing Alpha\", &uiBackingAlpha, 0.f, 100.f)) {\n    m_engine.getPreferences().setUserPreference(PreferenceNames::UiBackingAlpha, uiBackingAlpha * 0.01f);\n  }\n}\n\nint PreferencesTools::getSelectedLang() {\n  auto lang =\n      m_engine.getPreferences().getUserPreference(PreferenceNames::Language, PreferenceDefaultValues::Language);\n  for (size_t i = 0; i < 5; ++i) {\n    if (!strcmp(lang.c_str(), langs[i]))\n      return i;\n  }\n  return 0;\n}\n\nvoid PreferencesTools::setSelectedLang(int lang) {\n  m_engine.getPreferences().setUserPreference(PreferenceNames::Language, std::string(langs[lang]));\n}\n}"
  },
  {
    "path": "src/System/DebugTools/PreferencesTools.hpp",
    "content": "#pragma once\n\nnamespace ng {\nclass Engine;\n\nclass PreferencesTools final {\npublic:\n  explicit PreferencesTools(Engine &engine);\n\n  void render();\n\nprivate:\n  int getSelectedLang();\n  void setSelectedLang(int lang);\n\nprivate:\n  Engine &m_engine;\n  inline static const char *langs[] = {\"en\", \"fr\", \"de\", \"es\", \"it\"};\n};\n}"
  },
  {
    "path": "src/System/DebugTools/RoomTools.cpp",
    "content": "#include \"RoomTools.hpp\"\n#include <imgui.h>\n#include <sstream>\n#include <engge/Room/Room.hpp>\n#include <engge/Engine/Engine.hpp>\n#include <ngf/Math/PathFinding/Walkbox.h>\n#include <ngf/Graphics/ImGuiExtensions.h>\n#include \"DebugControls.hpp\"\n\nnamespace ng {\nnamespace {\nconst char *RoomEffects = \"None\\0Sepia\\0EGA\\0VHS\\0Ghost\\0Black & White\\0\";\nconst char *FadeEffects = \"None\\0In\\0Out\\0Wobble\\0\";\n}\n\nRoomTools::RoomTools(Engine &engine) : m_engine(engine) {}\n\nvoid RoomTools::render() {\n  if (!ImGui::CollapsingHeader(\"Room\"))\n    return;\n\n  auto &rooms = m_engine.getRooms();\n  m_roomInfos.clear();\n  int i = 0;\n  int currentRoom = 0;\n  for (auto &&room : rooms) {\n    if (room.get() == m_engine.getRoom()) {\n      currentRoom = i;\n    }\n    m_roomInfos.push_back(room->getName());\n    i++;\n  }\n\n  if (ImGui::Combo(\"Room\",\n                   &currentRoom,\n                   DebugControls::stringGetter,\n                   static_cast<void *>(&m_roomInfos),\n                   rooms.size())) {\n    m_engine.setRoom(rooms[currentRoom].get());\n  }\n\n  ImGui::SameLine();\n  if (ImGui::SmallButton(\"Table...\")) {\n    m_showRoomTable = true;\n  }\n\n  auto &room = rooms[currentRoom];\n\n  auto options = m_engine.getWalkboxesFlags();\n  auto showWalkboxes = (options & WalkboxesFlags::Walkboxes) == WalkboxesFlags::Walkboxes;\n  if (ImGui::Checkbox(\"Walkboxes\", &showWalkboxes)) {\n    m_engine.setWalkboxesFlags(showWalkboxes ? (WalkboxesFlags::Walkboxes | options) : (options\n        & ~WalkboxesFlags::Walkboxes));\n  }\n  auto showMergedWalkboxes = (options & WalkboxesFlags::Merged) == WalkboxesFlags::Merged;\n  if (ImGui::Checkbox(\"Merged Walkboxes\", &showMergedWalkboxes)) {\n    m_engine.setWalkboxesFlags(showMergedWalkboxes ? (WalkboxesFlags::Merged | options) : (options\n        & ~WalkboxesFlags::Merged));\n  }\n  auto showGraph = (options & WalkboxesFlags::Graph) == WalkboxesFlags::Graph;\n  if (ImGui::Checkbox(\"Graph\", &showGraph)) {\n    m_engine.setWalkboxesFlags(showGraph ? (WalkboxesFlags::Graph | options) : (options & ~WalkboxesFlags::Graph));\n  }\n  updateWalkboxInfos(room.get());\n  ImGui::Combo(\"##walkboxes\", &m_selectedWalkbox, DebugControls::stringGetter, static_cast<void *>(&m_walkboxInfos),\n               m_walkboxInfos.size());\n  auto rotation = room->getRotation();\n  if (ImGui::SliderFloat(\"rotation\", &rotation, -180.f, 180.f, \"%.0f deg\")) {\n    room->setRotation(rotation);\n  }\n  auto overlay = room->getOverlayColor();\n  if (ngf::ImGui::ColorEdit4(\"Overlay\", &overlay)) {\n    room->setOverlayColor(overlay);\n  }\n  auto ambient = room->getAmbientLight();\n  if (ngf::ImGui::ColorEdit4(\"ambient\", &ambient)) {\n    room->setAmbientLight(ambient);\n  }\n  for (i = 0; i < static_cast<int>(room->getLights().size()); ++i) {\n    if (i >= room->getNumberLights())\n      break;\n\n    std::ostringstream ss;\n    ss << \"Light \" << (i + 1);\n\n    if (ImGui::TreeNode(ss.str().c_str())) {\n      auto &light = room->getLights()[i];\n      ImGui::DragInt2(\"Position\", &light.pos.x);\n      ngf::ImGui::ColorEdit4(\"Color\", &light.color);\n      ImGui::DragFloat(\"Direction angle\", &light.coneDirection,\n                       1.0f, 0.0f, 360.f);\n      ImGui::DragFloat(\"Angle\", &light.coneAngle, 1.0f, 0.0f, 360.f);\n      ImGui::DragFloat(\"Cutoff\", &light.cutOffRadius, 1.0f);\n      ImGui::DragFloat(\"Falloff\", &light.coneFalloff, 0.1f, 0.f, 1.0f);\n      ImGui::DragFloat(\n          \"Brightness\", &light.brightness, 1.0f, 1.0f, 100.f);\n      ImGui::DragFloat(\n          \"Half Radius\", &light.halfRadius, 1.0f, 0.01f, 0.99f);\n      ImGui::TreePop();\n    }\n  }\n  auto effect = room->getEffect();\n  if (ImGui::Combo(\"Shader\", &effect, RoomEffects)) {\n    room->setEffect(effect);\n  }\n  ImGui::DragFloat(\"iGlobalTime\", &m_engine.roomEffect.iGlobalTime);\n  if (effect == 1) {\n    ImGui::DragFloat(\"sepiaFlicker\", &m_engine.roomEffect.sepiaFlicker, 0.01f, 0.f, 1.f);\n    ImGui::DragFloat(\"RandomValue\", &m_engine.roomEffect.RandomValue[0], 0.01f, 0.f, 1.f);\n    ImGui::DragFloat(\"TimeLapse\", &m_engine.roomEffect.TimeLapse);\n  } else if (effect == 3) {\n    ImGui::DragFloat(\"iNoiseThreshold\", &m_engine.roomEffect.iNoiseThreshold, 0.01f, 0.f, 1.f);\n  } else if (effect == 4) {\n    ImGui::DragFloat(\"iFade\", &m_engine.roomEffect.iFade, 0.01f, 0.f, 1.f);\n    ImGui::DragFloat(\"wobbleIntensity\", &m_engine.roomEffect.wobbleIntensity, 0.01f, 0.f, 1.f);\n    ImGui::DragFloat3(\"shadows\", glm::value_ptr(m_engine.roomEffect.shadows), 0.1f, -1.f, 1.f);\n    ImGui::DragFloat3(\"midtones\", glm::value_ptr(m_engine.roomEffect.midtones), 0.1f, -1.f, 1.f);\n    ImGui::DragFloat3(\"highlights\", glm::value_ptr(m_engine.roomEffect.highlights), 0.1f, -1.f, 1.f);\n  }\n  ImGui::Separator();\n\n  ImGui::Combo(\"Effect\", (int *) &m_fadeEffect, FadeEffects);\n  ImGui::DragFloat(\"Duration\", &m_fadeDuration, 0.1f, 0.f, 10.f);\n  if (ImGui::Button(\"Fade\")) {\n    m_engine.fadeTo((FadeEffect) m_fadeEffect, ngf::TimeSpan::seconds(m_fadeDuration));\n  }\n}\n\nvoid RoomTools::updateWalkboxInfos(Room *pRoom) {\n  m_walkboxInfos.clear();\n  if (!pRoom)\n    return;\n  auto &walkboxes = pRoom->getWalkboxes();\n  for (size_t i = 0; i < walkboxes.size(); ++i) {\n    auto walkbox = walkboxes.at(i);\n    const auto &name = walkbox.getName();\n    std::ostringstream s;\n    if (!name.empty()) {\n      s << name;\n    } else {\n      s << \"Walkbox #\" << i;\n    }\n    s << \" \" << (walkbox.isEnabled() ? \"[enabled]\" : \"[disabled]\");\n    m_walkboxInfos.push_back(s.str());\n  }\n}\n}"
  },
  {
    "path": "src/System/DebugTools/RoomTools.hpp",
    "content": "#pragma once\n#include <string>\n#include <vector>\n\nnamespace ng {\nclass Engine;\nclass Room;\n\nclass RoomTools final {\npublic:\n  explicit RoomTools(Engine &engine);\n\n  void render();\n  void updateWalkboxInfos(Room *pRoom);\n\npublic:\n  bool m_showRoomTable{false};\n\nprivate:\n  Engine &m_engine;\n  int m_selectedWalkbox{0};\n  int m_fadeEffect{0};\n  float m_fadeDuration{3.f};\n  std::vector<std::string> m_walkboxInfos;\n  std::vector<std::string> m_roomInfos;\n};\n}"
  },
  {
    "path": "src/System/DebugTools/SoundTools.cpp",
    "content": "#include \"SoundTools.hpp\"\n#include <imgui.h>\n#include <engge/Audio/SoundManager.hpp>\n#include <engge/Engine/Engine.hpp>\n#include <ngf/Graphics/ImGuiExtensions.h>\n\nnamespace ng {\nnamespace {\nstd::string getName(SoundId *soundId) {\n  auto sd = soundId ? soundId->getSoundDefinition() : nullptr;\n  if (!sd)\n    return {};\n  return sd->getPath();\n}\n\nstd::string getLoopTimes(SoundId *soundId) {\n  if (!soundId)\n    return {};\n  auto loopTimes = soundId->getSoundHandle()->get().getNumLoops();\n  if (loopTimes == -1)\n    return \"Inf.\";\n  return std::to_string(loopTimes);\n}\n\nstd::string getCategory(SoundId *soundId) {\n  if (!soundId)\n    return {};\n\n  switch (soundId->getSoundCategory()) {\n  case SoundCategory::Music:return \"music\";\n  case SoundCategory::Sound:return \"sound\";\n  case SoundCategory::Talk:return \"talk\";\n  default: return \"?\";\n  }\n}\n\nngf::Color getCategoryColor(SoundId *soundId) {\n  if (!soundId)\n    return ngf::Colors::White;\n  switch (soundId->getSoundCategory()) {\n  case SoundCategory::Music:return ngf::Colors::Green;\n  case SoundCategory::Sound:return ngf::Colors::Red;\n  case SoundCategory::Talk:return ngf::Colors::Yellow;\n  default: return ngf::Colors::White;\n  }\n}\n\nstd::string getStatus(SoundId *soundId) {\n  if (!soundId)\n    return \"Stopped\";\n  switch (soundId->getSoundHandle().get()->get().getStatus()) {\n  case ngf::AudioChannel::Status::Playing:return \"Playing\";\n  case ngf::AudioChannel::Status::Stopped:return \"Stopped\";\n  case ngf::AudioChannel::Status::Paused:return \"Paused\";\n  default: return \"?\";\n  }\n}\n\n}\n\nSoundTools::SoundTools(Engine &engine) : m_engine(engine) {}\n\nvoid SoundTools::render() {\n  if (!soundsVisible)\n    return;\n\n  auto &sounds = m_engine.getSoundManager().getSounds();\n  auto numSounds = 0;\n  for (auto &sound : sounds) {\n    if (sound)\n      numSounds++;\n  }\n\n  ImGui::Begin(\"Sounds\", &soundsVisible);\n  ImGui::Text(\"# sounds: %d/%lu\", numSounds, sounds.size());\n  ImGui::Separator();\n\n  if (ImGui::BeginTable(\"Sounds\",\n                        7,\n                        ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Resizable\n                            | ImGuiTableFlags_RowBg)) {\n    ImGui::TableSetupColumn(\"\");\n    ImGui::TableSetupColumn(\"Id\");\n    ImGui::TableSetupColumn(\"Name\");\n    ImGui::TableSetupColumn(\"Loops\");\n    ImGui::TableSetupColumn(\"Category\");\n    ImGui::TableSetupColumn(\"Volume\");\n    ImGui::TableSetupColumn(\"Status\");\n    ImGui::TableHeadersRow();\n\n    for (auto i = 0; i < static_cast<int>(sounds.size()); i++) {\n      const auto &sound = sounds[i];\n      const auto name = getName(sound.get());\n      const auto loopTimes = getLoopTimes(sound.get());\n      const auto volume = sound ? sound->getSoundHandle()->get().getVolume() : 0.f;\n      const auto category = getCategory(sound.get());\n      const auto catColor = getCategoryColor(sound.get());\n      const auto status = getStatus(sound.get());\n\n      ImGui::TableNextRow();\n      if (name.empty()) {\n        ImGui::TableNextColumn();\n        ImGui::TableNextColumn();\n        ImGui::Text(\"%2d\", i);\n        ImGui::TableNextColumn();\n        ImGui::TableNextColumn();\n        ImGui::TableNextColumn();\n        ImGui::TableNextColumn();\n        ImGui::TableNextColumn();\n        continue;\n      }\n\n      ImGui::TableNextColumn();\n      if (ImGui::SmallButton(\"stop\")) {\n        sound->stop();\n      }\n      ImGui::TableNextColumn();\n      ImGui::Text(\"%2d\", i);\n      ImGui::TableNextColumn();\n      ImGui::Text(\"%-48s\", name.c_str());\n\n      ImGui::TableNextColumn();\n      ImGui::Text(\"%s\", loopTimes.c_str());\n      ImGui::TableNextColumn();\n      ImGui::TextColored(ngf::ImGui::ImVec4(catColor), \" %7s\", category.data());\n      ImGui::TableNextColumn();\n      ImGui::Text(\"%.1f\", volume);\n      ImGui::TableNextColumn();\n      ImGui::Text(\"%s\", status.c_str());\n    }\n    ImGui::EndTable();\n  }\n  ImGui::End();\n}\n}"
  },
  {
    "path": "src/System/DebugTools/SoundTools.hpp",
    "content": "#pragma once\n\nnamespace ng {\nclass Engine;\n\nclass SoundTools final {\npublic:\n  explicit SoundTools(Engine &engine);\n  void render();\n\npublic:\n  bool soundsVisible{false};\n\nprivate:\n  Engine &m_engine;\n};\n}"
  },
  {
    "path": "src/System/DebugTools/TextureTools.cpp",
    "content": "#include \"TextureTools.hpp\"\n#include <imgui.h>\n#include <engge/Graphics/ResourceManager.hpp>\n#include <engge/System/Locator.hpp>\n\nnamespace ng {\nvoid TextureTools::render() {\n  if (!texturesVisible)\n    return;\n\n  ImGui::Begin(\"Textures\", &texturesVisible);\n  const auto &map = Locator<ResourceManager>::get().getTextureMap();\n  size_t totalSize = 0;\n  for (const auto&[key, value] :map) {\n    totalSize += value.size;\n  }\n  auto totalSizeText = convertSize(totalSize);\n  ImGui::Text(\"Total memory: %s\", totalSizeText.data());\n  ImGui::Separator();\n\n  if (ImGui::BeginTable(\"Textures\",\n                        3,\n                        ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Resizable\n                            | ImGuiTableFlags_RowBg)) {\n    ImGui::TableSetupColumn(\"Name\");\n    ImGui::TableSetupColumn(\"Size\");\n    ImGui::TableSetupColumn(\"Refs\");\n    ImGui::TableHeadersRow();\n\n    for (const auto&[key, value] :map) {\n      auto fileSize = convertSize(value.size);\n      ImGui::TableNextRow();\n      ImGui::TableNextColumn();\n      ImGui::Text(\"%s\", key.data());\n      ImGui::TableNextColumn();\n      ImGui::Text(\"%s\", fileSize.data());\n      ImGui::TableNextColumn();\n      ImGui::Text(\"%ld\", value.texture.use_count());\n    }\n    ImGui::EndTable();\n  }\n  ImGui::End();\n}\n\nstd::string TextureTools::convertSize(size_t size) {\n  const char *suffix[] = {\"B\", \"KB\", \"MB\", \"GB\", \"TB\"};\n  char length = sizeof(suffix) / sizeof(suffix[0]);\n  auto dblBytes = static_cast<double>(size);\n  auto i = 0;\n  if (size > 1024) {\n    for (i = 0; (size / 1024) > 0 && i < length - 1; i++, size /= 1024)\n      dblBytes = size / 1024.0;\n  }\n\n  char output[200];\n  sprintf(output, \"%.02lf %s\", dblBytes, suffix[i]);\n  return output;\n}\n}"
  },
  {
    "path": "src/System/DebugTools/TextureTools.hpp",
    "content": "#pragma once\n#include <string>\n\nnamespace ng {\nclass TextureTools final {\npublic:\n  void render();\n\npublic:\n  bool texturesVisible{false};\n\nprivate:\n  static std::string convertSize(size_t size);\n};\n}"
  },
  {
    "path": "src/System/DebugTools/ThreadTools.cpp",
    "content": "#include \"ThreadTools.hpp\"\n#include <engge/Engine/Engine.hpp>\n#include <engge/Engine/ThreadBase.hpp>\n#include <imgui.h>\n#include <string>\n\nnamespace ng {\nnamespace {\nstd::string getType(ThreadBase *thread) {\n  return thread->isGlobal() ? \"global\" : \"local\";\n}\n\nstd::string getState(ThreadBase *thread) {\n  if (thread->isSuspended())\n    return \"suspended\";\n  if (thread->isStopped())\n    return \"stopped\";\n  return \"playing\";\n}\n\nvoid showControls(ThreadBase *thread) {\n  if (thread->isSuspended()) {\n    if (ImGui::SmallButton(\"resume\")) {\n      thread->resume();\n    }\n    ImGui::SameLine();\n  } else {\n    if (ImGui::SmallButton(\"pause\") && thread->isPauseable()) {\n      thread->pause();\n    }\n    ImGui::SameLine();\n  }\n  if (ImGui::SmallButton(\"stop\")) {\n    thread->stop();\n  }\n}\n}\n\nThreadTools::ThreadTools(Engine &engine) : m_engine(engine) {}\n\nvoid ThreadTools::render() {\n  if (!threadsVisible)\n    return;\n\n  const auto &threads = m_engine.getThreads();\n  ImGui::Begin(\"Threads\", &threadsVisible);\n  ImGui::Text(\"# threads: %lu\", threads.size());\n  ImGui::Separator();\n\n  if (ImGui::BeginTable(\"Threads\",\n                        5,\n                        ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Resizable\n                            | ImGuiTableFlags_RowBg)) {\n    ImGui::TableSetupColumn(\"\");\n    ImGui::TableSetupColumn(\"Id\");\n    ImGui::TableSetupColumn(\"Name\");\n    ImGui::TableSetupColumn(\"Type\");\n    ImGui::TableSetupColumn(\"State\");\n    ImGui::TableHeadersRow();\n\n    for (const auto &thread : threads) {\n      const auto name = thread->getName();\n      const auto id = thread->getId();\n      const auto type = getType(thread.get());\n      const auto state = getState(thread.get());\n\n      ImGui::TableNextRow();\n      ImGui::TableNextColumn();\n      showControls(thread.get());\n      ImGui::TableNextColumn();\n      ImGui::Text(\"%5d\", id);\n      ImGui::TableNextColumn();\n      ImGui::Text(\"%-56s\", name.c_str());\n      ImGui::TableNextColumn();\n      ImGui::Text(\"%-6s\", type.c_str());\n      ImGui::TableNextColumn();\n      ImGui::Text(\"%-9s\", state.c_str());\n    }\n    ImGui::EndTable();\n  }\n  ImGui::End();\n}\n}"
  },
  {
    "path": "src/System/DebugTools/ThreadTools.hpp",
    "content": "#pragma once\n\nnamespace ng {\nclass Engine;\n\nclass ThreadTools final {\npublic:\n  explicit ThreadTools(Engine &engine);\n\n  void render();\n\npublic:\n  bool threadsVisible{false};\n\nprivate:\n  Engine &m_engine;\n};\n}"
  },
  {
    "path": "src/System/Logger.cpp",
    "content": "#include <memory>\n#include <spdlog/sinks/stdout_color_sinks.h>\n#include <spdlog/sinks/basic_file_sink.h>\n#include <spdlog/sinks/dist_sink.h>\n#include \"engge/System/Logger.hpp\"\n\nnamespace ng {\nLogger::Logger() {\n  auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();\n  console_sink->set_level(spdlog::level::trace);\n  auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>(\"log.txt\", true);\n  file_sink->set_level(spdlog::level::trace);\n  auto dist_sink = std::make_shared<spdlog::sinks::dist_sink_st>();\n  dist_sink->add_sink(console_sink);\n  dist_sink->add_sink(file_sink);\n  m_out = std::make_shared<spdlog::logger>(\"log\", dist_sink);\n  m_out->set_level(spdlog::level::trace);\n}\n} // namespace ng\n"
  },
  {
    "path": "src/UI/Button.cpp",
    "content": "#include \"Button.hpp\"\n#include <engge/Engine/Engine.hpp>\n#include <engge/Audio/SoundManager.hpp>\n#include <utility>\n#include <ngf/System/Mouse.h>\n#include <ngf/Graphics/RectangleShape.h>\n#include <ngf/Graphics/FntFont.h>\n#include \"ControlConstants.hpp\"\n#include \"Util/Util.hpp\"\n\nnamespace ng {\nButton::Button(int id, float y, Callback callback, bool enabled, Size size)\n    : Control(enabled), m_callback(std::move(callback)), m_id(id), m_y(y), m_size(size) {\n  m_text.setColor(enabled ? ControlConstants::NormalColor : ControlConstants::DisabledColor);\n}\n\nButton::~Button() = default;\n\nvoid Button::onClick() {\n  if (m_callback) {\n    m_callback();\n  }\n}\n\nvoid Button::draw(ngf::RenderTarget &target, ngf::RenderStates states) const {\n  m_text.draw(target, states);\n}\n\nvoid Button::onEngineSet() {\n  const auto &uiFontLargeOrMedium =\n      m_pEngine->getResourceManager().getFntFont(m_size == Size::Large ? \"UIFontLarge.fnt\" : \"UIFontMedium.fnt\");\n  m_text.setFont(uiFontLargeOrMedium);\n  m_text.setWideString(ng::Engine::getText(m_id));\n  auto textRect = m_text.getLocalBounds();\n  m_text.getTransform().setOrigin({textRect.getWidth() / 2.f, 0});\n  m_text.getTransform().setPosition({Screen::Width / 2.f, m_y});\n}\n\nvoid Button::onStateChanged() {\n  ngf::Color color;\n  switch (m_state) {\n  case ControlState::Disabled:color = ControlConstants::DisabledColor;\n    break;\n  case ControlState::None:color = ControlConstants::NormalColor;\n    break;\n  case ControlState::Hover:color = ControlConstants::HoverColor;\n    break;\n  }\n  m_text.setColor(color);\n}\n\nbool Button::contains(glm::vec2 pos) const {\n  auto p = ngf::transform(glm::inverse(m_text.getTransform().getTransform()), pos);\n  return m_text.getLocalBounds().contains(p);\n}\n\nvoid Button::update(const ngf::TimeSpan &elapsed, glm::vec2 pos) {\n  Control::update(elapsed, pos);\n  m_text.getTransform().setPosition(m_shakeOffset + glm::vec2{Screen::Width / 2.f, m_y});\n}\n}"
  },
  {
    "path": "src/UI/Button.hpp",
    "content": "#pragma once\n#include <imgui.h>\n#include <functional>\n#include <ngf/Graphics/RenderTarget.h>\n#include <ngf/Graphics/RenderStates.h>\n#include <engge/Graphics/Text.hpp>\n#include \"UI/Control.hpp\"\n\nnamespace ng {\nclass Engine;\n\nclass Button final : public Control {\npublic:\n  using Callback = std::function<void()>;\n  enum class Size { Large, Medium };\n\n  Button(int id, float y, Callback callback, bool enabled = true, Size size = Size::Large);\n  ~Button() final;\n\n  void draw(ngf::RenderTarget &target, ngf::RenderStates states) const override;\n  void update(const ngf::TimeSpan &elapsed, glm::vec2 pos) final;\n\nprivate:\n  bool contains(glm::vec2 pos) const final;\n  void onStateChanged() final;\n  void onEngineSet() final;\n  void onClick() final;\n\nprivate:\n  Callback m_callback{nullptr};\n  int m_id{0};\n  float m_y{0};\n  ng::Text m_text;\n  Size m_size{Size::Large};\n};\n}\n"
  },
  {
    "path": "src/UI/Checkbox.cpp",
    "content": "#include \"Checkbox.hpp\"\n#include <engge/Engine/Engine.hpp>\n#include \"Util/Util.hpp\"\n#include \"ControlConstants.hpp\"\n#include <ngf/Graphics/FntFont.h>\n#include <ngf/System/Mouse.h>\n\nnamespace ng {\nCheckbox::Checkbox(int id, float y, bool enabled, bool checked, Callback callback)\n    : Control(enabled), m_callback(callback), m_id(id), m_y(y), m_isChecked(checked) {\n}\n\nvoid Checkbox::draw(ngf::RenderTarget &target, ngf::RenderStates states) const {\n  m_text.draw(target, states);\n  m_sprite.draw(target, states);\n}\n\nvoid Checkbox::onEngineSet() {\n  const auto &uiFontMedium = m_pEngine->getResourceManager().getFntFont(\"UIFontMedium.fnt\");\n  m_text.setFont(uiFontMedium);\n  m_text.setWideString(ng::Engine::getText(m_id));\n  auto textRect = m_text.getLocalBounds();\n  m_text.getTransform().setOrigin(glm::vec2(0, textRect.getHeight() / 2.f));\n  m_text.getTransform().setPosition({420.f, m_y});\n}\n\nvoid Checkbox::setSpriteSheet(SpriteSheet *pSpriteSheet) {\n  m_pSpriteSheet = pSpriteSheet;\n  auto checkedRect = pSpriteSheet->getRect(\"option_unchecked\");\n  m_sprite.getTransform().setPosition({820.f, m_y});\n  glm::vec2 scale(Screen::Width / 320.f, Screen::Height / 180.f);\n  m_sprite.getTransform().setScale(scale);\n  m_sprite.getTransform().setOrigin({checkedRect.getWidth() / 2.f, checkedRect.getHeight() / 2.f});\n  m_sprite.setTexture(*pSpriteSheet->getTexture());\n  m_sprite.setTextureRect(checkedRect);\n\n  updateCheckState();\n}\n\nvoid Checkbox::setChecked(bool checked) {\n  if (m_isChecked != checked) {\n    m_isChecked = checked;\n    if (m_callback) {\n      m_callback(checked);\n    }\n    updateCheckState();\n  }\n}\n\nbool Checkbox::contains(glm::vec2 pos) const {\n  auto textRect = ng::getGlobalBounds(m_sprite);\n  return textRect.contains(pos);\n}\n\nvoid Checkbox::updateCheckState() {\n  ngf::Color color;\n  switch (m_state) {\n  case ControlState::Disabled:color = ControlConstants::DisabledColor;\n    break;\n  case ControlState::None:color = ControlConstants::NormalColor;\n    break;\n  case ControlState::Hover:color = ControlConstants::HoverColor;\n    break;\n  }\n\n  m_sprite.setColor(color);\n  m_text.setColor(color);\n\n  auto checkedRect =\n      m_isChecked ? m_pSpriteSheet->getRect(\"option_checked\") : m_pSpriteSheet->getRect(\"option_unchecked\");\n  m_sprite.setTextureRect(checkedRect);\n}\n\nvoid Checkbox::onStateChanged() {\n  updateCheckState();\n}\n\nvoid Checkbox::onClick() {\n  setChecked(!m_isChecked);\n}\n\nvoid Checkbox::update(const ngf::TimeSpan &elapsed, glm::vec2 pos) {\n  Control::update(elapsed, pos);\n  m_sprite.getTransform().setPosition(m_shakeOffset + glm::vec2{820.f, m_y});\n  m_text.getTransform().setPosition(m_shakeOffset + glm::vec2{420.f, m_y});\n}\n}"
  },
  {
    "path": "src/UI/Checkbox.hpp",
    "content": "#pragma once\n#include <utility>\n#include <ngf/Graphics/Drawable.h>\n#include <ngf/Graphics/Sprite.h>\n#include <engge/Graphics/Text.hpp>\n#include \"UI/Control.hpp\"\n\nnamespace ng {\nclass Engine;\nclass SpriteSheet;\n\nclass Checkbox final : public Control {\npublic:\n  using Callback = std::function<void(bool)>;\n  Checkbox(int id, float y, bool enabled = true, bool checked = false, Callback callback = nullptr);\n\n  void setSpriteSheet(SpriteSheet *pSpriteSheet);\n  void setChecked(bool checked);\n  void draw(ngf::RenderTarget &target, ngf::RenderStates states) const override;\n  void update(const ngf::TimeSpan &elapsed, glm::vec2 pos) final;\n\nprivate:\n  bool contains(glm::vec2 pos) const final;\n  void onStateChanged() final;\n  void onEngineSet() final;\n  void onClick() final;\n  void updateCheckState();\n\nprivate:\n  Callback m_callback{nullptr};\n  int m_id{0};\n  float m_y{0};\n  bool m_isChecked{false};\n  ng::Text m_text;\n  ngf::Sprite m_sprite;\n  SpriteSheet *m_pSpriteSheet{nullptr};\n};\n}\n"
  },
  {
    "path": "src/UI/Control.cpp",
    "content": "#include \"Control.hpp\"\n#include <ngf/System/Mouse.h>\n#include <imgui.h>\n#include <engge/Audio/SoundManager.hpp>\n#include <engge/Engine/Engine.hpp>\n\nnamespace ng {\nControl::Control(bool enabled) :\n    m_state(enabled ? ControlState::None : ControlState::Disabled) {\n}\n\nControl::~Control() = default;\n\nvoid Control::update(const ngf::TimeSpan &elapsed, glm::vec2 pos) {\n  if (m_state == ControlState::Disabled)\n    return;\n\n  // update state\n  auto oldState = m_state;\n  m_state = ControlState::None;\n  if (contains((glm::vec2) pos)) {\n    m_state = ControlState::Hover;\n    auto isDown = ngf::Mouse::isButtonPressed(ngf::Mouse::Button::Left);\n    auto &io = ImGui::GetIO();\n    if (!io.WantCaptureMouse && m_wasMouseDown && !isDown) {\n      onClick();\n    }\n    m_wasMouseDown = isDown;\n  }\n\n  // play sound cursor is over it\n  if (m_state != oldState) {\n    if (m_state == ControlState::Hover) {\n      m_shake = true;\n      m_shakeTime = 0;\n      auto pSound = m_pEngine->getSoundManager().getSoundHover();\n      if (pSound) {\n        m_pEngine->getSoundManager().playSound(pSound);\n      }\n    } else {\n      m_shake = false;\n    }\n    onStateChanged();\n  }\n\n  // update shake offset\n  if (m_shake && m_state == ControlState::Hover) {\n    m_shakeTime += 20.f * elapsed.getTotalSeconds();\n    m_shakeOffset = {0.6f * cosf(m_shakeTime + 0.3f), 0.6f * sinf(m_shakeTime)};\n    m_shake = m_shakeTime < 10.f;\n  }\n}\n\nvoid Control::setEngine(Engine *pEngine) {\n  m_pEngine = pEngine;\n  onEngineSet();\n}\n}"
  },
  {
    "path": "src/UI/Control.hpp",
    "content": "#pragma once\n#include <functional>\n#include <glm/vec2.hpp>\n#include <ngf/Graphics/Drawable.h>\n#include <ngf/Graphics/RenderTarget.h>\n#include <ngf/Graphics/RenderStates.h>\n\nnamespace ng {\n\nenum class ControlState {\n  None,\n  Hover,\n  Disabled\n};\n\nclass Engine;\n\nclass Control : public ngf::Drawable {\npublic:\n  void setEngine(Engine *pEngine);\n  virtual void update(const ngf::TimeSpan &elapsed, glm::vec2 pos);\n\nprotected:\n  explicit Control(bool enabled = true);\n  ~Control() override;\n\n  [[nodiscard]] virtual bool contains(glm::vec2 pos) const = 0;\n\n  virtual void onClick() {}\n  virtual void onStateChanged() {}\n  virtual void onEngineSet() {}\n\nprotected:\n  Engine *m_pEngine{nullptr};\n  ControlState m_state{ControlState::None};\n  glm::vec2 m_shakeOffset{0, 0};\n\nprivate:\n  bool m_wasMouseDown{false};\n  float m_shakeTime{0};\n  bool m_shake{false};\n};\n}"
  },
  {
    "path": "src/UI/ControlConstants.hpp",
    "content": "#pragma once\n#include <ngf/Graphics/Color.h>\n#include <ngf/Graphics/Colors.h>\n\nnamespace ng {\nstruct ControlConstants {\n  inline static const ngf::Color NormalColor{ngf::Colors::White};\n  inline static const ngf::Color DisabledColor{255, 255, 255, 128};\n  inline static const ngf::Color HoverColor{ngf::Colors::Yellow};\n};\n}\n"
  },
  {
    "path": "src/UI/HelpDialog.cpp",
    "content": "#include \"HelpDialog.hpp\"\n#include \"Button.hpp\"\n#include \"Control.hpp\"\n#include \"ControlConstants.hpp\"\n#include <engge/EnggeApplication.hpp>\n#include <engge/Engine/Engine.hpp>\n#include <engge/Graphics/Screen.hpp>\n#include <ngf/Graphics/FntFont.h>\n#include <ngf/System/Mouse.h>\n#include <utility>\n#include \"Util/Util.hpp\"\n\nnamespace ng {\n\nclass HelpButton final : public Control {\npublic:\n  using Callback = std::function<void()>;\n  enum class Size { Large, Medium };\n\n  HelpButton(int id, glm::vec2 pos = {0, 0}, Callback callback = nullptr, bool enabled = true, Size size = Size::Large)\n      : Control(enabled), m_id(id), m_pos(pos), m_callback(callback), m_size(size) {\n    m_text.setColor(enabled ? ControlConstants::NormalColor : ControlConstants::DisabledColor);\n  }\n\n  ~HelpButton() final = default;\n\n  void draw(ngf::RenderTarget &target, ngf::RenderStates states) const override {\n    if (!m_isVisible)\n      return;\n    m_text.draw(target, states);\n  }\n\n  void update(const ngf::TimeSpan &elapsed, glm::vec2 pos) final {\n    Control::update(elapsed, pos);\n    m_text.getTransform().setPosition(m_shakeOffset + m_pos);\n  }\n\n  void setCallback(Callback callback) { m_callback = callback; }\n\n  void setVisible(bool visible) { m_isVisible = visible; }\n  bool isVisible() const { return m_isVisible; }\n\n  void setPosition(const glm::vec2 &pos) { m_pos = pos; }\n  glm::vec2 getPosition() const { return m_pos; }\n\n  void setAnchor(ngf::Anchor anchor) {\n    m_text.setAnchor(anchor);\n  }\n\nprivate:\n  bool contains(glm::vec2 pos) const final {\n    if (!m_isVisible)\n      return false;\n    auto p = ngf::transform(glm::inverse(m_text.getTransform().getTransform()), pos);\n    return m_text.getLocalBounds().contains(p);\n  }\n\n  void onStateChanged() final {\n    ngf::Color color;\n    switch (m_state) {\n    case ControlState::Disabled:color = ControlConstants::DisabledColor;\n      break;\n    case ControlState::None:color = ControlConstants::NormalColor;\n      break;\n    case ControlState::Hover:color = ControlConstants::HoverColor;\n      break;\n    }\n    m_text.setColor(color);\n  }\n\n  void onEngineSet() final {\n    const auto &uiFontLargeOrMedium =\n        m_pEngine->getResourceManager().getFntFont(m_size == Size::Large ? \"UIFontLarge.fnt\" : \"UIFontMedium.fnt\");\n    m_text.setFont(uiFontLargeOrMedium);\n    m_text.setWideString(ng::Engine::getText(m_id));\n    m_text.getTransform().setPosition(m_pos);\n  }\n\n  void onClick() final {\n    if (m_callback) {\n      m_callback();\n    }\n  }\n\nprivate:\n  int m_id{0};\n  glm::vec2 m_pos{0, 0};\n  Callback m_callback{nullptr};\n  ng::Text m_text;\n  Size m_size{Size::Large};\n  bool m_isVisible{true};\n};\n\nstruct HelpDialog::Impl {\n  struct Ids {\n    static constexpr int Back = 99904;\n    static constexpr int Next = 99962;\n    static constexpr int Prev = 99963;\n  };\n\n  Engine *m_pEngine{nullptr};\n  HelpButton m_back;\n  HelpButton m_prev;\n  HelpButton m_next;\n  std::vector<int> m_pages;\n  ngf::Sprite m_backgroundSprite;\n  ngf::Sprite m_helpPageSprite;\n  int m_pageIndex{0};\n\n  Impl()\n      : m_back{Ids::Back, {0, 0}, nullptr, true, HelpButton::Size::Medium},\n        m_prev{Ids::Prev, {0, 0}, nullptr, true, HelpButton::Size::Medium},\n        m_next{Ids::Next, {300, 0}, nullptr, true, HelpButton::Size::Medium} {\n    m_prev.setCallback([this]() { prevPage(); });\n    m_next.setCallback([this]() { nextPage(); });\n  }\n\n  void nextPage() {\n    displayPage(++m_pageIndex);\n  }\n\n  void prevPage() {\n    displayPage(--m_pageIndex);\n  }\n\n  void init(Engine *pEngine, Callback exitCallback, std::initializer_list<int> pages) {\n    m_pEngine = pEngine;\n    if (!pEngine)\n      return;\n\n    m_pages = pages;\n    m_back.setEngine(pEngine);\n    m_back.setCallback(exitCallback);\n    m_back.setPosition({50.f, 16.f});\n    m_prev.setEngine(pEngine);\n    m_next.setEngine(pEngine);\n\n    m_backgroundSprite.setTexture(*m_pEngine->getResourceManager().getTexture(\"HelpScreen_bg\"));\n    m_backgroundSprite.getTransform().setPosition({Screen::HalfWidth, Screen::HalfHeight});\n    m_backgroundSprite.setAnchor(ngf::Anchor::Center);\n\n    m_helpPageSprite.getTransform().setPosition({Screen::HalfWidth, Screen::HalfHeight});\n\n    displayPage(0);\n  }\n\n  void displayPage(int index) {\n    m_pageIndex = index;\n    m_prev.setVisible(m_pageIndex > 0);\n    m_prev.setAnchor(ngf::Anchor::BottomLeft);\n    m_prev.setPosition({30.f, Screen::Height - 30.f});\n\n    m_next.setVisible(m_pageIndex < static_cast<int>(m_pages.size() - 1));\n    m_next.setAnchor(ngf::Anchor::BottomRight);\n    m_next.setPosition({Screen::Width - 32.f, Screen::Height - 32.f});\n\n    char background[17];\n    sprintf(background, \"HelpScreen_%02d_en\", m_pages[index]);\n    std::string backgroundWithLang = background;\n    checkLanguage(backgroundWithLang);\n    m_helpPageSprite.setTexture(*m_pEngine->getResourceManager().getTexture(backgroundWithLang));\n    m_helpPageSprite.setAnchor(ngf::Anchor::Center);\n  }\n\n  void draw(ngf::RenderTarget &target, ngf::RenderStates states) {\n    const auto view = target.getView();\n    auto viewRect = ngf::frect::fromPositionSize({0, 0}, {Screen::Width, Screen::Height});\n    target.setView(ngf::View(viewRect));\n\n    m_backgroundSprite.draw(target, states);\n    m_helpPageSprite.draw(target, states);\n    m_back.draw(target, states);\n    m_prev.draw(target, states);\n    m_next.draw(target, states);\n\n    target.setView(view);\n  }\n\n  void update(const ngf::TimeSpan &elapsed) {\n    auto pos = m_pEngine->getApplication()->getRenderTarget()->mapPixelToCoords(\n        ngf::Mouse::getPosition(),\n        ngf::View(ngf::frect::fromPositionSize(\n            {0, 0}, {Screen::Width, Screen::Height})));\n    m_back.update(elapsed, pos);\n    m_prev.update(elapsed, pos);\n    m_next.update(elapsed, pos);\n  }\n};\n\nHelpDialog::HelpDialog()\n    : m_pImpl(std::make_unique<Impl>()) {\n}\n\nHelpDialog::~HelpDialog() = default;\n\nvoid HelpDialog::init(Engine *pEngine, Callback exitCallback, std::initializer_list<int> pages) {\n  m_pImpl->init(pEngine, exitCallback, pages);\n}\n\nvoid HelpDialog::draw(ngf::RenderTarget &target, ngf::RenderStates states) const {\n  m_pImpl->draw(target, states);\n}\n\nvoid HelpDialog::update(const ngf::TimeSpan &elapsed) {\n  m_pImpl->update(elapsed);\n}\n}\n"
  },
  {
    "path": "src/UI/HelpDialog.hpp",
    "content": "#pragma once\n#include <functional>\n#include <ngf/Graphics/Drawable.h>\n#include <ngf/Graphics/RenderTarget.h>\n#include <ngf/Graphics/RenderStates.h>\n#include <ngf/System/TimeSpan.h>\n\nnamespace ng {\nclass Engine;\n\nclass HelpDialog final : public ngf::Drawable {\npublic:\n  using Callback = std::function<void()>;\n\npublic:\n  HelpDialog();\n  ~HelpDialog() final;\n\n  void init(Engine *pEngine, Callback exitCallback, std::initializer_list<int> pages);\n\n  void draw(ngf::RenderTarget &target, ngf::RenderStates states) const final;\n  void update(const ngf::TimeSpan &elapsed);\n\nprivate:\n  struct Impl;\n  std::unique_ptr<Impl> m_pImpl;\n};\n\n}\n"
  },
  {
    "path": "src/UI/OptionsDialog.cpp",
    "content": "#include \"Button.hpp\"\n#include \"Checkbox.hpp\"\n#include \"Slider.hpp\"\n#include \"SwitchButton.hpp\"\n#include <engge/EnggeApplication.hpp>\n#include <engge/Audio/SoundManager.hpp>\n#include <engge/Engine/Engine.hpp>\n#include <engge/Engine/Preferences.hpp>\n#include <engge/Graphics/Screen.hpp>\n#include <engge/Graphics/SpriteSheet.hpp>\n#include <engge/Scripting/ScriptEngine.hpp>\n#include <engge/System/Logger.hpp>\n#include <engge/UI/OptionsDialog.hpp>\n#include <engge/UI/SaveLoadDialog.hpp>\n#include <engge/UI/QuitDialog.hpp>\n#include \"HelpDialog.hpp\"\n#include <utility>\n#include <ngf/Graphics/FntFont.h>\n#include <ngf/Graphics/RectangleShape.h>\n#include <ngf/System/Mouse.h>\n\nnamespace ng {\nstruct OptionsDialog::Impl {\n  enum class State { None, Main, Sound, Video, Controls, TextAndSpeech, Help };\n\n  struct Ids {\n    inline static const int EnglishText = 98001;\n    inline static const int FrenchText = 98003;\n    inline static const int ItalianText = 98005;\n    inline static const int GermanText = 98007;\n    inline static const int SpanishText = 98009;\n    inline static const int Back = 99904;\n    inline static const int LoadGame = 99910;\n    inline static const int SaveGame = 99911;\n    inline static const int Options = 99913;\n    inline static const int Credits = 99914;\n    inline static const int Quit = 99915;\n    inline static const int Sound = 99916;\n    inline static const int Video = 99917;\n    inline static const int Controls = 99918;\n    inline static const int TextAndSpeech = 99919;\n    inline static const int Fullscreen = 99927;\n    inline static const int SafeArea = 99929;\n    inline static const int RetroFonts = 99933;\n    inline static const int RetroVerbs = 99934;\n    inline static const int ClassicSentence = 99935;\n    inline static const int SoundVolume = 99937;\n    inline static const int MusicVolume = 99938;\n    inline static const int VoiceVolume = 99939;\n    inline static const int Controller = 99940;\n    inline static const int TextSpeed = 99941;\n    inline static const int DisplayText = 99942;\n    inline static const int HearVoice = 99943;\n    inline static const int ScrollSyncCursor = 99960;\n    inline static const int Help = 99961;\n    inline static const int InvertVerbColors = 99964;\n    inline static const int ToiletPaperOver = 99965;\n    inline static const int Introduction = 99966;\n    inline static const int MouseTips = 99967;\n    inline static const int ControllerTips = 99968;\n    inline static const int ControllerMap = 99969;\n    inline static const int KeyboardMap = 99970;\n    inline static const int AnnoyingInJokes = 99971;\n  };\n\n  inline static const std::array<std::string, 5> LanguageValues = {\"en\", \"fr\", \"it\", \"de\", \"es\"};\n  static constexpr float yPosStart = 84.f;\n  static constexpr float yPosLarge = 58.f;\n  static constexpr float yPosSmall = 54.f;\n\n  Engine *m_pEngine{nullptr};\n  SpriteSheet m_saveLoadSheet;\n\n  ng::Text m_headingText;\n  std::vector<Button> m_buttons;\n  std::vector<SwitchButton> m_switchButtons;\n  std::vector<Checkbox> m_checkboxes;\n  std::vector<Slider> m_sliders;\n  bool m_showQuit{false};\n  bool m_showSaveLoad{false};\n  bool m_showHelp{false};\n  QuitDialog m_quitDialog;\n  SaveLoadDialog m_saveLoadDialog;\n  HelpDialog m_help;\n  Callback m_callback{nullptr};\n  bool m_isDirty{false};\n  State m_state{State::None};\n  State m_nextState{State::None};\n  bool m_saveEnabled{false};\n\n  inline static float getSlotPos(int slot) {\n    return yPosStart + yPosLarge + yPosSmall * static_cast<float>(slot);\n  }\n\n  void setHeading(int id) {\n    m_headingText.setWideString(Engine::getText(id));\n    auto textRect = m_headingText.getLocalBounds();\n    m_headingText.getTransform().setPosition({(Screen::Width - textRect.getWidth()) / 2.f,\n                                              yPosStart - textRect.getHeight() / 2});\n  }\n\n  template<typename T>\n  void setUserPreference(const std::string &name, T value) {\n    Locator<Preferences>::get().setUserPreference(name, value);\n  }\n\n  template<typename T>\n  T getUserPreference(const std::string &name, T value) const {\n    return Locator<Preferences>::get().getUserPreference(name, value);\n  }\n\n  static int getLanguageUserPreference() {\n    auto lang =\n        Locator<Preferences>::get().getUserPreference(PreferenceNames::Language, PreferenceDefaultValues::Language);\n    auto it = std::find(LanguageValues.begin(), LanguageValues.end(), lang);\n    return static_cast<int>(std::distance(LanguageValues.begin(), it));\n  }\n\n  void setState(State state) {\n    m_nextState = state;\n  }\n\n  void onStateChanged() {\n    if (m_isDirty) {\n      Locator<Preferences>::get().save();\n      m_quitDialog.updateLanguage();\n      m_isDirty = false;\n    }\n    m_sliders.clear();\n    m_buttons.clear();\n    m_switchButtons.clear();\n    m_checkboxes.clear();\n    switch (m_state) {\n    case State::Main:setHeading(Ids::Options);\n      m_buttons.emplace_back(Ids::SaveGame, getSlotPos(0), [this]() {\n        m_saveLoadDialog.updateLanguage();\n        m_saveLoadDialog.setSaveMode(true);\n        m_showSaveLoad = true;\n      }, m_saveEnabled);\n      m_buttons.emplace_back(Ids::LoadGame, getSlotPos(1), [this]() {\n        m_saveLoadDialog.updateLanguage();\n        m_saveLoadDialog.setSaveMode(false);\n        m_showSaveLoad = true;\n      });\n      m_buttons.emplace_back(Ids::Sound, getSlotPos(2), [this]() { setState(State::Sound); });\n      m_buttons.emplace_back(Ids::Video, getSlotPos(3), [this]() { setState(State::Video); });\n      m_buttons.emplace_back(Ids::Controls, getSlotPos(4), [this]() { setState(State::Controls); });\n      m_buttons.emplace_back(Ids::TextAndSpeech, getSlotPos(5), [this]() { setState(State::TextAndSpeech); });\n      m_buttons.emplace_back(Ids::Help, getSlotPos(6), [this]() { setState(State::Help); });\n      m_buttons.emplace_back(Ids::Quit, getSlotPos(7), [this]() { m_showQuit = true; }, true);\n      m_buttons.emplace_back(Ids::Back, getSlotPos(9), [this]() {\n        if (m_callback)\n          m_callback();\n      }, true, Button::Size::Medium);\n      break;\n    case State::Sound:setHeading(Ids::Sound);\n      m_sliders.emplace_back(Ids::SoundVolume,\n                             getSlotPos(2),\n                             true,\n                             Locator<SoundManager>::get().getSoundVolume(),\n                             [this](auto value) {\n                               m_isDirty = true;\n                              Locator<SoundManager>::get().setSoundVolume(value);\n                            });\n      m_sliders.emplace_back(Ids::MusicVolume,\n                             getSlotPos(3),\n                             true,\n                             Locator<SoundManager>::get().getMusicVolume(),\n                             [this](auto value) {\n                               m_isDirty = true;\n                              Locator<SoundManager>::get().setMusicVolume(value);\n                            });\n      m_sliders.emplace_back(Ids::VoiceVolume,\n                             getSlotPos(4),\n                             true,\n                             Locator<SoundManager>::get().getTalkVolume(),\n                             [this](auto value) {\n                               m_isDirty = true;\n                              Locator<SoundManager>::get().setTalkVolume(value);\n                            });\n      m_buttons.emplace_back(Ids::Back,\n                             getSlotPos(9),\n                             [this]() { setState(State::Main); },\n                             true,\n                             Button::Size::Medium);\n      break;\n    case State::Video:setHeading(Ids::Video);\n      m_checkboxes.emplace_back(Ids::Fullscreen, getSlotPos(1), true,\n                                getUserPreference(PreferenceNames::Fullscreen, PreferenceDefaultValues::Fullscreen),\n                                [this](auto value) {\n                                  m_isDirty = true;\n                                 setUserPreference(PreferenceNames::Fullscreen, value);\n                               });\n      m_sliders.emplace_back(Ids::SafeArea, getSlotPos(2), false,\n                             getUserPreference(PreferenceNames::SafeArea, PreferenceDefaultValues::SafeArea),\n                             [this](auto value) {\n                               m_isDirty = true;\n                              setUserPreference(PreferenceNames::SafeArea, value);\n                            });\n      m_checkboxes.emplace_back(Ids::ToiletPaperOver, getSlotPos(4), true,\n                                getUserPreference(PreferenceNames::ToiletPaperOver,\n                                                 PreferenceDefaultValues::ToiletPaperOver),\n                                [this](auto value) {\n                                  m_isDirty = true;\n                                 setUserPreference(PreferenceNames::ToiletPaperOver, value);\n                                 ScriptEngine::call(\"setSettingVar\", \"toilet_paper_over\", value ? 1 : 0);\n                               });\n      m_checkboxes.emplace_back(Ids::AnnoyingInJokes, getSlotPos(5), true,\n                                getUserPreference(PreferenceNames::AnnoyingInJokes,\n                                                 PreferenceDefaultValues::AnnoyingInJokes),\n                                [this](auto value) {\n                                  m_isDirty = true;\n                                 setUserPreference(PreferenceNames::AnnoyingInJokes, value);\n                                 ScriptEngine::call(\"setSettingVar\", \"annoying_injokes\", value ? 1 : 0);\n                               });\n      m_buttons.emplace_back(Ids::Back,\n                             getSlotPos(9),\n                             [this]() { setState(State::Main); },\n                             true,\n                             Button::Size::Medium);\n      break;\n    case State::Controls:setHeading(Ids::Controls);\n      m_checkboxes.emplace_back(Ids::Controller, getSlotPos(1), false,\n                                getUserPreference(PreferenceNames::Controller, PreferenceDefaultValues::Controller),\n                                [this](auto value) {\n                                  m_isDirty = true;\n                                 setUserPreference(PreferenceNames::Controller, value);\n                               });\n      m_checkboxes.emplace_back(Ids::ScrollSyncCursor, getSlotPos(2), false,\n                                getUserPreference(PreferenceNames::ScrollSyncCursor,\n                                                 PreferenceDefaultValues::ScrollSyncCursor),\n                                [this](auto value) {\n                                  m_isDirty = true;\n                                 setUserPreference(PreferenceNames::ScrollSyncCursor, value);\n                               });\n      m_checkboxes.emplace_back(Ids::InvertVerbColors, getSlotPos(4), true,\n                                getUserPreference(PreferenceNames::InvertVerbHighlight,\n                                                 PreferenceDefaultValues::InvertVerbHighlight),\n                                [this](auto value) {\n                                  m_isDirty = true;\n                                 setUserPreference(PreferenceNames::InvertVerbHighlight, value);\n                               });\n      m_checkboxes.emplace_back(Ids::RetroFonts, getSlotPos(5), true,\n                                getUserPreference(PreferenceNames::RetroFonts, PreferenceDefaultValues::RetroFonts),\n                                [this](auto value) {\n                                  m_isDirty = true;\n                                 setUserPreference(PreferenceNames::RetroFonts, value);\n                               });\n      m_checkboxes.emplace_back(Ids::RetroVerbs, getSlotPos(6), true,\n                                getUserPreference(PreferenceNames::RetroVerbs, PreferenceDefaultValues::RetroVerbs),\n                                [this](auto value) {\n                                  m_isDirty = true;\n                                 setUserPreference(PreferenceNames::RetroVerbs, value);\n                                 if (value) {\n                                   m_checkboxes[3].setChecked(true);\n                                   m_checkboxes[5].setChecked(true);\n                                 }\n                               });\n      m_checkboxes.emplace_back(Ids::ClassicSentence, getSlotPos(7), true,\n                                getUserPreference(PreferenceNames::ClassicSentence,\n                                                 PreferenceDefaultValues::ClassicSentence),\n                                [this](auto value) {\n                                  m_isDirty = true;\n                                 setUserPreference(PreferenceNames::ClassicSentence, value);\n                               });\n      m_buttons.emplace_back(Ids::Back,\n                             getSlotPos(9),\n                             [this]() { setState(State::Main); },\n                             true,\n                             Button::Size::Medium);\n      break;\n    case State::TextAndSpeech:setHeading(Ids::TextAndSpeech);\n      m_sliders.emplace_back(Ids::TextSpeed, getSlotPos(1), true,\n                             getUserPreference(PreferenceNames::SayLineSpeed, PreferenceDefaultValues::SayLineSpeed),\n                             [this](auto value) {\n                               m_isDirty = true;\n                              setUserPreference(PreferenceNames::SayLineSpeed, value);\n                            });\n      m_checkboxes.emplace_back(Ids::DisplayText, getSlotPos(3), true,\n                                getUserPreference(PreferenceNames::DisplayText, PreferenceDefaultValues::DisplayText),\n                                [this](auto value) {\n                                  m_isDirty = true;\n                                 if (!value && !getUserPreference(PreferenceNames::HearVoice,\n                                                                  PreferenceDefaultValues::HearVoice)) {\n                                   m_checkboxes[1].setChecked(true);\n                                   setUserPreference(PreferenceNames::HearVoice, true);\n                                 }\n                                 setUserPreference(PreferenceNames::DisplayText, value);\n                               });\n      m_checkboxes.emplace_back(Ids::HearVoice, getSlotPos(4), true,\n                                getUserPreference(PreferenceNames::HearVoice, PreferenceDefaultValues::HearVoice),\n                                [this](auto value) {\n                                  m_isDirty = true;\n                                 if (!value && !getUserPreference(PreferenceNames::DisplayText,\n                                                                  PreferenceDefaultValues::DisplayText)) {\n                                   m_checkboxes[0].setChecked(true);\n                                   setUserPreference(PreferenceNames::DisplayText, true);\n                                 }\n                                 setUserPreference(PreferenceNames::HearVoice, value);\n                               });\n      m_switchButtons.push_back(SwitchButton({Ids::EnglishText, Ids::FrenchText, Ids::ItalianText, Ids::GermanText,\n                                              Ids::SpanishText}, getSlotPos(5), true,\n                                             getLanguageUserPreference(), [this](auto index) {\n            m_isDirty = true;\n            setUserPreference(PreferenceNames::Language, LanguageValues[index]);\n          }));\n      m_buttons.emplace_back(Ids::Back,\n                             getSlotPos(9),\n                             [this]() { setState(State::Main); },\n                             true,\n                             Button::Size::Medium);\n      break;\n    case State::Help:setHeading(Ids::Help);\n      m_buttons.emplace_back(Ids::Introduction, getSlotPos(1), [this]() {\n        m_help.init(m_pEngine, [this]() { m_showHelp = false; }, {1, 2, 3, 4, 5, 6});\n        m_showHelp = true;\n      }, true);\n      m_buttons.emplace_back(Ids::MouseTips, getSlotPos(2), [this]() {\n        m_help.init(m_pEngine, [this]() { m_showHelp = false; }, {7, 8, 9});\n        m_showHelp = true;\n      }, true);\n      m_buttons.emplace_back(Ids::ControllerTips, getSlotPos(3), [this]() {\n        m_help.init(m_pEngine, [this]() { m_showHelp = false; }, {10, 11, 12, 13, 14});\n        m_showHelp = true;\n      }, true);\n      m_buttons.emplace_back(Ids::ControllerMap, getSlotPos(4), [this]() {\n        m_help.init(m_pEngine, [this]() { m_showHelp = false; }, {15});\n        m_showHelp = true;\n      }, true);\n      m_buttons.emplace_back(Ids::KeyboardMap, getSlotPos(5), [this]() {\n        m_help.init(m_pEngine, [this]() { m_showHelp = false; }, {16});\n        m_showHelp = true;\n      }, true);\n      m_buttons.emplace_back(Ids::Back,\n                             getSlotPos(9),\n                             [this]() { setState(State::Main); },\n                             true,\n                             Button::Size::Medium);\n      break;\n    default:setState(State::Main);\n      break;\n    }\n\n    for (auto &button : m_buttons) {\n      button.setEngine(m_pEngine);\n    }\n    for (auto &switchButton : m_switchButtons) {\n      switchButton.setEngine(m_pEngine);\n    }\n    for (auto &checkbox : m_checkboxes) {\n      checkbox.setEngine(m_pEngine);\n      checkbox.setSpriteSheet(&m_saveLoadSheet);\n    }\n    for (auto &slider : m_sliders) {\n      slider.setEngine(m_pEngine);\n      slider.setSpriteSheet(&m_saveLoadSheet);\n    }\n  }\n\n  void setEngine(Engine *pEngine) {\n    m_pEngine = pEngine;\n    if (!pEngine)\n      return;\n\n    auto &tm = pEngine->getResourceManager();\n    m_saveLoadSheet.setTextureManager(&tm);\n    m_saveLoadSheet.load(\"SaveLoadSheet\");\n\n    const auto &headingFont = m_pEngine->getResourceManager().getFntFont(\"HeadingFont.fnt\");\n    m_headingText.setFont(headingFont);\n    m_headingText.setColor(ngf::Colors::White);\n\n    m_quitDialog.setEngine(pEngine);\n    m_quitDialog.setCallback([this](bool result) {\n      if (result)\n        m_pEngine->quit();\n      m_showQuit = result;\n    });\n\n    m_saveLoadDialog.setEngine(pEngine);\n    m_saveLoadDialog.setCallback([this]() {\n      m_showSaveLoad = false;\n    });\n    m_saveLoadDialog.setSlotCallback([this](int slot) {\n      if (m_saveLoadDialog.getSaveMode()) {\n        m_pEngine->saveGame(slot);\n        m_showSaveLoad = false;\n        if (m_callback)\n          m_callback();\n      } else {\n        m_pEngine->loadGame(slot);\n        m_showSaveLoad = false;\n        if (m_callback)\n          m_callback();\n      }\n    });\n\n    setState(State::Main);\n  }\n\n  void draw(ngf::RenderTarget &target, ngf::RenderStates states) {\n    if (m_showHelp) {\n      m_help.draw(target, states);\n      return;\n    }\n\n    const auto view = target.getView();\n    auto viewRect = ngf::frect::fromPositionSize({0, 0}, {320, 180});\n    target.setView(ngf::View(viewRect));\n\n    ngf::Color backColor{0, 0, 0, 128};\n    ngf::RectangleShape fadeShape;\n    fadeShape.setSize(viewRect.getSize());\n    fadeShape.setColor(backColor);\n    fadeShape.draw(target, {});\n\n    // draw background\n    auto viewCenter = glm::vec2(viewRect.getWidth() / 2, viewRect.getHeight() / 2);\n    auto rect = m_saveLoadSheet.getRect(\"options_background\");\n    ngf::Sprite sprite;\n    sprite.getTransform().setPosition(viewCenter);\n    sprite.setTexture(*m_saveLoadSheet.getTexture());\n    sprite.getTransform().setOrigin({static_cast<float>(rect.getWidth() / 2.f),\n                                     static_cast<float>(rect.getHeight() / 2.f)});\n    sprite.setTextureRect(rect);\n    sprite.draw(target, {});\n\n    viewRect = ngf::frect::fromPositionSize({0, 0}, {Screen::Width, Screen::Height});\n    target.setView(ngf::View(viewRect));\n\n    // heading\n    m_headingText.draw(target, {});\n\n    // controls\n    for (auto &button : m_buttons) {\n      button.draw(target, {});\n    }\n    for (auto &switchButton : m_switchButtons) {\n      switchButton.draw(target, {});\n    }\n    for (auto &checkbox : m_checkboxes) {\n      checkbox.draw(target, {});\n    }\n    for (auto &slider : m_sliders) {\n      slider.draw(target, {});\n    }\n\n    target.setView(view);\n\n    if (m_showSaveLoad) {\n      m_saveLoadDialog.draw(target, states);\n    }\n\n    if (m_showQuit) {\n      m_quitDialog.draw(target, states);\n    }\n  }\n\n  void update(const ngf::TimeSpan &elapsed) {\n    if (m_state != m_nextState) {\n      m_state = m_nextState;\n      onStateChanged();\n    }\n\n    if (m_showHelp) {\n      m_help.update(elapsed);\n      return;\n    }\n\n    if (m_showSaveLoad) {\n      m_saveLoadDialog.update(elapsed);\n      return;\n    }\n\n    if (m_showQuit) {\n      m_quitDialog.update(elapsed);\n      return;\n    }\n\n    auto pos = m_pEngine->getApplication()->getRenderTarget()->mapPixelToCoords(ngf::Mouse::getPosition(),\n                                                                                ngf::View(ngf::frect::fromPositionSize({0,\n                                                                                                                       0},\n                                                                                                                      {Screen::Width,\n                                                                                                                       Screen::Height})));\n    for (auto &button : m_buttons) {\n      button.update(elapsed, pos);\n    }\n    for (auto &switchButton : m_switchButtons) {\n      switchButton.update(elapsed, pos);\n    }\n    for (auto &checkbox : m_checkboxes) {\n      checkbox.update(elapsed, pos);\n    }\n    for (auto &slider : m_sliders) {\n      slider.update(elapsed, pos);\n    }\n  }\n};\n\nOptionsDialog::OptionsDialog()\n    : m_pImpl(std::make_unique<Impl>()) {\n}\n\nOptionsDialog::~OptionsDialog() = default;\n\nvoid OptionsDialog::setSaveEnabled(bool enabled) { m_pImpl->m_saveEnabled = enabled; }\n\nvoid OptionsDialog::setEngine(Engine *pEngine) { m_pImpl->setEngine(pEngine); }\n\nvoid OptionsDialog::draw(ngf::RenderTarget &target, ngf::RenderStates states) const {\n  m_pImpl->draw(target, states);\n}\n\nvoid OptionsDialog::update(const ngf::TimeSpan &elapsed) {\n  m_pImpl->update(elapsed);\n}\n\nvoid OptionsDialog::showHelp() {\n  m_pImpl->setState(Impl::State::Help);\n}\n\nvoid OptionsDialog::setCallback(Callback callback) {\n  m_pImpl->m_callback = std::move(callback);\n}\n}\n"
  },
  {
    "path": "src/UI/QuitDialog.cpp",
    "content": "#include \"ControlConstants.hpp\"\n#include \"Button.hpp\"\n#include <engge/EnggeApplication.hpp>\n#include <engge/Engine/Engine.hpp>\n#include <engge/Graphics/Screen.hpp>\n#include <engge/Graphics/SpriteSheet.hpp>\n#include <engge/UI/QuitDialog.hpp>\n#include <utility>\n#include <ngf/Graphics/FntFont.h>\n#include <ngf/Graphics/RectangleShape.h>\n#include <ngf/Graphics/Sprite.h>\n#include <ngf/System/Mouse.h>\n#include \"Util/Util.hpp\"\n\nnamespace ng {\nclass BackButton final : public Control {\npublic:\n  using Callback = std::function<void()>;\n\npublic:\n  BackButton(int id, bool value, Callback callback, bool enabled = true)\n      : Control(enabled), m_id(id), m_value(value), m_callback(std::move(callback)) {\n  }\n\n  void draw(ngf::RenderTarget &target, ngf::RenderStates states) const final {\n    m_text.draw(target, states);\n  }\n\n  bool contains(glm::vec2 pos) const final {\n    auto textRect = ng::getGlobalBounds(m_text);\n    return textRect.contains((glm::vec2) pos);\n  }\n\n  void onEngineSet() final {\n    m_text.setFont(m_pEngine->getResourceManager().getFntFont(\"UIFontLarge.fnt\"));\n    m_text.setWideString(Engine::getText(m_id));\n    auto textRect = m_text.getLocalBounds();\n    auto originX = m_value ? textRect.getWidth() : 0;\n    auto x = m_value ? -60.f : 60.f;\n    m_text.getTransform().setOrigin({originX, textRect.getHeight() / 2.f});\n    m_text.getTransform().setPosition({Screen::Width / 2.0f + x, 400.f});\n  }\n\n  void onStateChanged() final {\n    ngf::Color color;\n    switch (m_state) {\n    case ControlState::Disabled:color = ControlConstants::DisabledColor;\n      break;\n    case ControlState::None:color = ControlConstants::NormalColor;\n      break;\n    case ControlState::Hover:color = ControlConstants::HoverColor;\n      break;\n    }\n    m_text.setColor(color);\n  }\n\n  void onClick() final {\n    if (m_callback) {\n      m_callback();\n    }\n  }\n\n  void update(const ngf::TimeSpan &elapsed, glm::vec2 pos) final {\n    Control::update(elapsed, pos);\n    auto x = m_value ? -60.f : 60.f;\n    m_text.getTransform().setPosition(m_shakeOffset + glm::vec2{Screen::Width / 2.0f + x, 400.f});\n  }\n\nprivate:\n  int m_id{0};\n  bool m_value{false};\n  Callback m_callback;\n  ng::Text m_text;\n};\n\nstruct QuitDialog::Impl {\n  struct Ids {\n    static constexpr int Yes = 99907;\n    static constexpr int No = 99908;\n    static constexpr int QuitText = 99909;\n  };\n\n  Engine *m_pEngine{nullptr};\n  SpriteSheet m_saveLoadSheet;\n  ng::Text m_headingText;\n  std::vector<BackButton> m_buttons;\n  Callback m_callback{nullptr};\n\n  void setHeading(int id) {\n    m_headingText.setWideString(Engine::getText(id));\n    auto textRect = m_headingText.getLocalBounds();\n    m_headingText.getTransform().setPosition({(Screen::Width - textRect.getWidth()) / 2.f, 260.f});\n  }\n\n  void updateState() {\n    m_buttons.clear();\n\n    setHeading(Ids::QuitText);\n\n    m_buttons.emplace_back(Ids::Yes, true, [this]() {\n      if (m_callback)\n        m_callback(true);\n    });\n    m_buttons.emplace_back(Ids::No, false, [this]() {\n      if (m_callback)\n        m_callback(false);\n    });\n\n    for (auto &button : m_buttons) {\n      button.setEngine(m_pEngine);\n    }\n  }\n\n  void setEngine(Engine *pEngine) {\n    m_pEngine = pEngine;\n    if (!pEngine)\n      return;\n\n    m_saveLoadSheet.setTextureManager(&pEngine->getResourceManager());\n    m_saveLoadSheet.load(\"SaveLoadSheet\");\n\n    auto &headingFont = m_pEngine->getResourceManager().getFntFont(\"UIFontMedium.fnt\");\n    m_headingText.setFont(headingFont);\n    m_headingText.setColor(ngf::Colors::White);\n\n    updateState();\n  }\n\n  void draw(ngf::RenderTarget &target, ngf::RenderStates) {\n    const auto view = target.getView();\n    auto viewRect = ngf::frect::fromPositionSize({0, 0}, {320, 180});\n    target.setView(ngf::View(viewRect));\n\n    ngf::Color backColor{0, 0, 0, 128};\n    ngf::RectangleShape fadeShape;\n    fadeShape.setSize(viewRect.getSize());\n    fadeShape.setColor(backColor);\n    fadeShape.draw(target, {});\n\n    // draw background\n    auto viewCenter = glm::vec2(viewRect.getWidth() / 2, viewRect.getHeight() / 2);\n    auto rect = m_saveLoadSheet.getRect(\"error_dialog_small\");\n    ngf::Sprite sprite;\n    sprite.getTransform().setPosition(viewCenter);\n    sprite.setTexture(*m_saveLoadSheet.getTexture());\n    sprite.getTransform().setOrigin({static_cast<float>(rect.getWidth() / 2),\n                                     static_cast<float>(rect.getHeight() / 2)});\n    sprite.setTextureRect(rect);\n    sprite.draw(target, {});\n\n    viewRect = ngf::frect::fromPositionSize({0, 0}, {Screen::Width, Screen::Height});\n    target.setView(ngf::View(viewRect));\n\n    // heading\n    m_headingText.draw(target, {});\n\n    // controls\n    for (auto &button : m_buttons) {\n      button.draw(target, {});\n    }\n    target.setView(view);\n  }\n\n  void update(const ngf::TimeSpan &elapsed) {\n    auto pos = m_pEngine->getApplication()->getRenderTarget()->mapPixelToCoords(\n        ngf::Mouse::getPosition(),\n        ngf::View(ngf::frect::fromPositionSize(\n            {0, 0}, {Screen::Width, Screen::Height})));\n    for (auto &button : m_buttons) {\n      button.update(elapsed, pos);\n    }\n  }\n};\n\nQuitDialog::QuitDialog()\n  : m_pImpl(std::make_unique<Impl>()) {\n}\n\nQuitDialog::~QuitDialog() = default;\n\nvoid QuitDialog::setEngine(Engine *pEngine) { m_pImpl->setEngine(pEngine); }\n\nvoid QuitDialog::draw(ngf::RenderTarget &target, ngf::RenderStates states) const {\n  m_pImpl->draw(target, states);\n}\n\nvoid QuitDialog::update(const ngf::TimeSpan &elapsed) {\n  m_pImpl->update(elapsed);\n}\n\nvoid QuitDialog::setCallback(Callback callback) {\n  m_pImpl->m_callback = std::move(callback);\n}\n\nvoid QuitDialog::updateLanguage() {\n  m_pImpl->updateState();\n}\n}\n"
  },
  {
    "path": "src/UI/SaveLoadDialog.cpp",
    "content": "#include <filesystem>\n#include <string>\n#include <engge/EnggeApplication.hpp>\n#include <engge/UI/SaveLoadDialog.hpp>\n#include <engge/Engine/Engine.hpp>\n#include <engge/Graphics/Screen.hpp>\n#include <engge/Graphics/SpriteSheet.hpp>\n#include <ngf/Graphics/Sprite.h>\n#include <ngf/Graphics/RectangleShape.h>\n#include <ngf/Graphics/Text.h>\n#include <ngf/Graphics/FntFont.h>\n#include <engge/Engine/EngineSettings.hpp>\n#include <engge/System/Locator.hpp>\n#include <engge/Engine/TextDatabase.hpp>\n#include <ngf/System/Mouse.h>\n#include \"Button.hpp\"\n#include \"ControlConstants.hpp\"\n#include \"Util/Util.hpp\"\n\nnamespace ng {\nstruct SaveLoadDialog::Impl {\n  class BackButton final : public Control {\n  private:\n    inline static const int BackId = 99904;\n\n  public:\n    typedef std::function<void()> Callback;\n\n    void draw(ngf::RenderTarget &target, ngf::RenderStates states) const override {\n      m_text.draw(target, states);\n    }\n\n  public:\n    void setCallback(Callback callback) {\n      m_callback = std::move(callback);\n    }\n\n    void onEngineSet() final {\n      m_text.setFont(m_pEngine->getResourceManager().getFntFont(\"UIFontLarge.fnt\"));\n      m_text.setWideString(Engine::getText(BackId));\n      auto textRect = ng::getGlobalBounds(m_text);\n      m_text.getTransform().setOrigin({textRect.getWidth() / 2.f, textRect.getHeight() / 2.f});\n      m_text.getTransform().setPosition({Screen::Width / 2.0f, 660.f});\n    }\n\n    bool contains(glm::vec2 pos) const final {\n      auto textRect = ng::getGlobalBounds(m_text);\n      return textRect.contains((glm::vec2) pos);\n    }\n\n    void onClick() final {\n      if (m_callback) {\n        m_callback();\n      }\n    }\n\n    void onStateChanged() final {\n      ngf::Color color;\n      switch (m_state) {\n      case ControlState::Disabled:color = ControlConstants::DisabledColor;\n        break;\n      case ControlState::None:color = ControlConstants::NormalColor;\n        break;\n      case ControlState::Hover:color = ControlConstants::HoverColor;\n        break;\n      }\n      m_text.setColor(color);\n    }\n\n    void update(const ngf::TimeSpan &elapsed, glm::vec2 pos) final {\n      Control::update(elapsed, pos);\n      m_text.getTransform().setPosition(m_shakeOffset + glm::vec2{Screen::Width / 2.0f, 660.f});\n    }\n\n  private:\n    Callback m_callback{nullptr};\n    ng::Text m_text;\n  };\n\n  class Slot final : public Control {\n  private:\n    inline static const int AutosaveId = 99901;\n\n  public:\n    void init(const SavegameSlot &slot, const SpriteSheet &spriteSheet, Engine &engine) {\n      setEngine(&engine);\n      m_index = slot.slot - 1;\n      auto x = m_index % 3;\n      auto y = m_index / 3;\n      glm::vec2 pos = {168.f + 39.f * 4.f + 78.f * 4.f * x + 4.f * x,\n                       92.f + 22.f * 4.f + 44.f * 4.f * y + 4.f * y};\n\n      m_transform.setPosition(pos);\n\n      const auto &uiFontSmallBold = engine.getResourceManager().getFntFont(\"UIFontSmallBold.fnt\");\n\n      // prepare the text for the game time\n      m_gameTimeText.setWideString(slot.getGameTimeString());\n      m_gameTimeText.setFont(uiFontSmallBold);\n      m_gameTimeText.setColor(ngf::Colors::White);\n      auto gameTimeSize = m_gameTimeText.getLocalBounds();\n      m_gameTimeText.getTransform().setOrigin({static_cast<float>(gameTimeSize.getWidth() / 2), 0});\n      m_gameTimeText.getTransform().setPosition({pos.x, pos.y - 88.f});\n\n      // prepare the text for the time when the game has been saved\n      std::wstring saveTimeText;\n      if (slot.slot == 1) {\n        saveTimeText = ng::Engine::getText(AutosaveId);\n      } else {\n        saveTimeText = slot.getSaveTimeString();\n      }\n      if (slot.easyMode) {\n        saveTimeText.append(1, L' ');\n        saveTimeText.append(Locator<TextDatabase>::get().getText(99955));\n      }\n      m_saveTimeText.setWideString(saveTimeText);\n      m_saveTimeText.setFont(uiFontSmallBold);\n      m_saveTimeText.setColor(ngf::Colors::White);\n      auto saveTimeSize = m_saveTimeText.getLocalBounds();\n      m_saveTimeText.getTransform().setOrigin({static_cast<float>(saveTimeSize.getWidth() / 2), 0});\n      m_saveTimeText.getTransform().setPosition({pos.x, pos.y + 48.f});\n\n      // prepare the sprite for the frame\n      auto rect = spriteSheet.getRect(\"saveload_slot_frame\");\n      m_sprite.setTexture(*spriteSheet.getTexture());\n      m_sprite.getTransform().setOrigin({static_cast<float>(rect.getWidth() / 2.f),\n                                         static_cast<float>(rect.getHeight() / 2.f)});\n      m_sprite.getTransform().setScale({4, 4});\n      m_sprite.setTextureRect(rect);\n      m_sprite.getTransform().setPosition(pos);\n\n      // try to find the savegame thumbnail\n      std::ostringstream s;\n      s << \"Savegame\" << (m_index + 1) << \".png\";\n      auto path = Locator<EngineSettings>::get().getPath();\n      path.append(s.str());\n\n      m_isEmpty = !std::filesystem::exists(path);\n      if (!m_isEmpty) {\n        // prepare a sprite for the savegame thumbnail\n        m_texture.load(path);\n        m_spriteImg.setTexture(m_texture, true);\n        m_spriteImg.getTransform().setOrigin({160.f, 90.f});\n        auto size = m_texture.getSize();\n        m_spriteImg.getTransform().setScale({(rect.getWidth() * 4.f) / size.x, (rect.getHeight() * 4.f) / size.y});\n        m_spriteImg.getTransform().setPosition(pos);\n        return;\n      }\n\n      // or prepare a sprite for the savegame empty slot\n      auto saveslotRect = spriteSheet.getRect(\"saveload_slot\");\n      m_spriteImg.setTexture(*spriteSheet.getTexture());\n      m_spriteImg.setTextureRect(saveslotRect);\n      m_spriteImg.getTransform().setOrigin({static_cast<float>(saveslotRect.getWidth() / 2.f),\n                                            static_cast<float>(saveslotRect.getHeight() / 2.f)});\n      m_spriteImg.getTransform().setScale({4.f, 4.f});\n      m_spriteImg.getTransform().setPosition(pos);\n    }\n\n    bool contains(glm::vec2 pos) const final {\n      auto trsf = m_transform;\n      trsf.move({-156.f, -88.f});\n      return ngf::transform(trsf.getTransform(), m_rect).contains(pos);\n    }\n\n    inline bool isEmpty() const {\n      return m_isEmpty;\n    }\n\n    void draw(ngf::RenderTarget &target, ngf::RenderStates states) const final {\n      m_spriteImg.draw(target, states);\n      m_sprite.draw(target, states);\n      if (!m_isEmpty) {\n        m_gameTimeText.draw(target, states);\n        m_saveTimeText.draw(target, states);\n      }\n    }\n\n  private:\n    int m_index{0};\n    bool m_isEmpty{true};\n    ngf::Texture m_texture;\n    ngf::Sprite m_sprite, m_spriteImg;\n    ng::Text m_gameTimeText;\n    ng::Text m_saveTimeText;\n    ngf::Transform m_transform;\n    ngf::frect m_rect = ngf::frect::fromPositionSize({0, 0}, {78 * 4, 44 * 4});\n  };\n\n  inline static const int LoadGameId = 99910;\n  inline static const int SaveGameId = 99911;\n\n  Engine *m_pEngine{nullptr};\n  SpriteSheet m_saveLoadSheet;\n  ng::Text m_headingText;\n  SaveLoadDialog::Impl::BackButton m_backButton;\n  Callback m_callback{nullptr};\n  SlotCallback m_slotCallback{nullptr};\n  std::array<Slot, 9> m_slots;\n  bool m_wasMouseDown{false};\n  bool m_saveMode{false};\n\n  void setHeading(bool saveMode) {\n    m_headingText.setWideString(Engine::getText(saveMode ? SaveGameId : LoadGameId));\n    auto textRect = m_headingText.getLocalBounds();\n    m_headingText.getTransform().setOrigin({textRect.getWidth() / 2.f, 0});\n    m_headingText.getTransform().setPosition({Screen::Width / 2.f, 32.f});\n  }\n\n  void updateState() {\n    std::vector<SavegameSlot> slots;\n    ng::Engine::getSlotSavegames(slots);\n\n    for (int i = 0; i < static_cast<int>(m_slots.size()); ++i) {\n      m_slots[i].init(slots[i], m_saveLoadSheet, *m_pEngine);\n    }\n\n    m_wasMouseDown = false;\n    setHeading(m_saveMode);\n\n    m_backButton.setCallback([this]() {\n      if (m_callback)\n        m_callback();\n    });\n\n    m_backButton.setEngine(m_pEngine);\n  }\n\n  void setEngine(Engine *pEngine) {\n    m_pEngine = pEngine;\n    if (!pEngine)\n      return;\n\n    ResourceManager &tm = pEngine->getResourceManager();\n    m_saveLoadSheet.setTextureManager(&tm);\n    m_saveLoadSheet.load(\"SaveLoadSheet\");\n\n    auto &headingFont = m_pEngine->getResourceManager().getFntFont(\"HeadingFont.fnt\");\n    m_headingText.setFont(headingFont);\n    m_headingText.setColor(ngf::Colors::White);\n  }\n\n  void draw(ngf::RenderTarget &target, ngf::RenderStates) {\n    const auto view = target.getView();\n    auto viewRect = ngf::frect::fromPositionSize({0, 0}, {320, 180});\n    target.setView(ngf::View(viewRect));\n\n    ngf::Color backColor{0, 0, 0, 128};\n    ngf::RectangleShape fadeShape;\n    fadeShape.setSize(viewRect.getSize());\n    fadeShape.setColor(backColor);\n    fadeShape.draw(target, {});\n\n    // draw background\n    auto viewCenter = glm::vec2(viewRect.getWidth() / 2, viewRect.getHeight() / 2);\n    auto rect = m_saveLoadSheet.getRect(\"saveload\");\n    ngf::Sprite sprite;\n    sprite.getTransform().setPosition(viewCenter);\n    sprite.setTexture(*m_saveLoadSheet.getTexture());\n    sprite.getTransform().setOrigin({static_cast<float>(rect.getWidth() / 2.f),\n                                     static_cast<float>(rect.getHeight() / 2.f)});\n    sprite.setTextureRect(rect);\n    sprite.draw(target, {});\n\n    viewRect = ngf::frect::fromPositionSize({0, 0}, {Screen::Width, Screen::Height});\n    target.setView(ngf::View(viewRect));\n\n    // heading\n    m_headingText.draw(target, {});\n\n    // slots\n    for (auto &slot : m_slots) {\n      slot.draw(target, {});\n    }\n\n    // back button\n    m_backButton.draw(target, {});\n\n    target.setView(view);\n  }\n\n  void update(const ngf::TimeSpan &elapsed) {\n    auto pos = m_pEngine->getApplication()->getRenderTarget()->mapPixelToCoords(\n        ngf::Mouse::getPosition(),\n        ngf::View(ngf::frect::fromPositionSize(\n            {0, 0}, {Screen::Width, Screen::Height})));\n    m_backButton.update(elapsed, pos);\n    for (auto &slot : m_slots) {\n      slot.update(elapsed, pos);\n    }\n\n    bool isDown = ngf::Mouse::isButtonPressed(ngf::Mouse::Button::Left);\n    const ImGuiIO &io = ImGui::GetIO();\n    if (!io.WantCaptureMouse && m_wasMouseDown && !isDown) {\n      int i = 0;\n      for (const auto &slot : m_slots) {\n        if (slot.contains(pos) && m_slotCallback) {\n          if (m_saveMode) {\n            if (i != 0) {\n              m_slotCallback(i + 1);\n            }\n          } else if (!slot.isEmpty()) {\n            m_slotCallback(i + 1);\n          }\n          return;\n        }\n        i++;\n      }\n    }\n    m_wasMouseDown = isDown;\n  }\n};\n\nSaveLoadDialog::SaveLoadDialog()\n    : m_pImpl(std::make_unique<Impl>()) {\n}\n\nSaveLoadDialog::~SaveLoadDialog() = default;\n\nvoid SaveLoadDialog::setEngine(Engine *pEngine) { m_pImpl->setEngine(pEngine); }\n\nvoid SaveLoadDialog::draw(ngf::RenderTarget &target, ngf::RenderStates states) const {\n  m_pImpl->draw(target, states);\n}\n\nvoid SaveLoadDialog::update(const ngf::TimeSpan &elapsed) {\n  m_pImpl->update(elapsed);\n}\n\nvoid SaveLoadDialog::setCallback(Callback callback) {\n  m_pImpl->m_callback = std::move(callback);\n}\n\nvoid SaveLoadDialog::setSlotCallback(SlotCallback callback) {\n  m_pImpl->m_slotCallback = std::move(callback);\n}\n\nvoid SaveLoadDialog::updateLanguage() {\n  m_pImpl->updateState();\n}\n\nvoid SaveLoadDialog::setSaveMode(bool saveMode) {\n  m_pImpl->m_saveMode = saveMode;\n  m_pImpl->setHeading(saveMode);\n}\n\nbool SaveLoadDialog::getSaveMode() const { return m_pImpl->m_saveMode; }\n}"
  },
  {
    "path": "src/UI/Slider.cpp",
    "content": "#include \"Slider.hpp\"\n#include <engge/Engine/Engine.hpp>\n#include <ngf/Graphics/FntFont.h>\n#include \"ControlConstants.hpp\"\n#include <ngf/System/Mouse.h>\n#include \"Util/Util.hpp\"\n#include <imgui.h>\n\nnamespace ng {\nSlider::Slider(int id, float y, bool enabled, float value, Callback callback)\n    : Control(enabled), m_id(id), m_y(y), m_value(value), m_onValueChanged(callback) {\n}\n\nvoid Slider::setSpriteSheet(SpriteSheet *pSpriteSheet) {\n  const auto &uiFontMedium = m_pEngine->getResourceManager().getFntFont(\"UIFontMedium.fnt\");\n  m_text.setFont(uiFontMedium);\n  m_text.setWideString(Engine::getText(m_id));\n  auto textRect = m_text.getLocalBounds();\n  m_text.getTransform().setOrigin({textRect.getWidth() / 2.f, textRect.getHeight()});\n  m_text.getTransform().setPosition({Screen::Width / 2.f, m_y});\n\n  auto sliderRect = pSpriteSheet->getRect(\"slider\");\n  auto handleRect = pSpriteSheet->getRect(\"slider_handle\");\n  glm::vec2 scale(Screen::Width / 320.f, Screen::Height / 180.f);\n  m_sprite.getTransform().setPosition({Screen::Width / 2.f, m_y});\n  m_sprite.getTransform().setScale(scale);\n  m_sprite.getTransform().setOrigin({sliderRect.getWidth() / 2.f, 0});\n  m_sprite.setTexture(*pSpriteSheet->getTexture());\n  m_sprite.setTextureRect(sliderRect);\n\n  m_min = Screen::Width / 2.f - (sliderRect.getWidth() * scale.x / 2.f);\n  m_max = Screen::Width / 2.f + (sliderRect.getWidth() * scale.x / 2.f);\n  auto x = m_min + m_value * (m_max - m_min);\n  m_spriteHandle.getTransform().setPosition({x, m_y});\n  m_spriteHandle.getTransform().setScale(scale);\n  m_spriteHandle.getTransform().setOrigin({handleRect.getWidth() / 2.f, 0});\n  m_spriteHandle.setTexture(*pSpriteSheet->getTexture());\n  m_spriteHandle.setTextureRect(handleRect);\n}\n\nbool Slider::contains(glm::vec2 pos) const {\n  auto textRect = ng::getGlobalBounds(m_sprite);\n  return textRect.contains(pos);\n}\n\nvoid Slider::update(const ngf::TimeSpan &elapsed, glm::vec2 pos) {\n  Control::update(elapsed, pos);\n\n  auto textRect = ng::getGlobalBounds(m_sprite);\n  bool isDown = ngf::Mouse::isButtonPressed(ngf::Mouse::Button::Left);\n  if (!isDown) {\n    m_isDragging = false;\n  }\n  ngf::Color color;\n  if (m_state == ControlState::Disabled) {\n    color = ControlConstants::DisabledColor;\n  } else if (textRect.contains(pos)) {\n    color = ControlConstants::HoverColor;\n    ImGuiIO &io = ImGui::GetIO();\n    if (!io.WantCaptureMouse && isDown) {\n      m_isDragging = true;\n    }\n  } else {\n    m_isDragging = false;\n    color = ControlConstants::NormalColor;\n  }\n  m_sprite.setColor(color);\n  m_text.setColor(color);\n\n  if (m_isDragging) {\n    auto x = std::clamp(pos.x, m_min, m_max);\n    auto value = (x - m_min) / (m_max - m_min);\n    if (m_value != value) {\n      m_value = value;\n      if (m_onValueChanged) {\n        m_onValueChanged.value()(value);\n      }\n    }\n    m_spriteHandle.getTransform().setPosition({x, m_y});\n  } else if (m_state == ControlState::Hover) {\n    m_text.getTransform().setPosition(m_shakeOffset + glm::vec2{Screen::Width / 2.f, m_y});\n    m_sprite.getTransform().setPosition(m_shakeOffset + glm::vec2{Screen::Width / 2.f, m_y});\n    m_spriteHandle.getTransform().setPosition(m_shakeOffset + glm::vec2{m_min + m_value * (m_max - m_min), m_y});\n  }\n}\n\nvoid Slider::draw(ngf::RenderTarget &target, ngf::RenderStates states) const {\n  m_text.draw(target, states);\n  m_sprite.draw(target, states);\n  m_spriteHandle.draw(target, states);\n}\n}"
  },
  {
    "path": "src/UI/Slider.hpp",
    "content": "#pragma once\n#include <ngf/Graphics/Drawable.h>\n#include <ngf/Graphics/Sprite.h>\n#include <engge/Graphics/Text.hpp>\n#include <engge/Graphics/SpriteSheet.hpp>\n#include <ngf/Graphics/RenderStates.h>\n#include <ngf/Graphics/RenderTarget.h>\n#include <functional>\n#include <optional>\n#include <glm/vec2.hpp>\n#include \"UI/Control.hpp\"\n\nnamespace ng {\nclass Engine;\n\nclass Slider final : public Control {\npublic:\n  using Callback = std::function<void(float)>;\n  Slider(int id, float y, bool enabled, float value, Callback callback);\n\n  void setSpriteSheet(SpriteSheet *pSpriteSheet);\n  void draw(ngf::RenderTarget &target, ngf::RenderStates states) const override;\n  void update(const ngf::TimeSpan &elapsed, glm::vec2 pos) final;\n\nprivate:\n  bool contains(glm::vec2 pos) const final;\n\nprivate:\n  int m_id{0};\n  float m_y{0};\n  float m_min{0}, m_max{0}, m_value{0};\n  bool m_isDragging{false};\n  ngf::Sprite m_sprite;\n  ngf::Sprite m_spriteHandle;\n  ng::Text m_text;\n  std::optional<Callback> m_onValueChanged;\n};\n}\n"
  },
  {
    "path": "src/UI/StartScreenDialog.cpp",
    "content": "#include \"Button.hpp\"\n#include <engge/EnggeApplication.hpp>\n#include <engge/Engine/Engine.hpp>\n#include <engge/Engine/Preferences.hpp>\n#include <engge/Graphics/Screen.hpp>\n#include <engge/UI/OptionsDialog.hpp>\n#include <engge/UI/SaveLoadDialog.hpp>\n#include <engge/UI/StartScreenDialog.hpp>\n#include <utility>\n#include <ngf/System/Mouse.h>\n#include <engge/UI/QuitDialog.hpp>\n\nnamespace ng {\nstruct StartScreenDialog::Impl {\n  enum class State { None, Main, Options, Help, Quit };\n\n  struct Ids {\n    inline static const int LoadGame = 99910;\n    inline static const int NewGame = 99912;\n    inline static const int Options = 99913;\n    inline static const int Quit = 99915;\n    inline static const int Help = 99961;\n  };\n\n  static constexpr float yPosStart = 155.f;\n  static constexpr float yStep = 80.f;\n\n  Engine *m_pEngine{nullptr};\n\n  std::vector<Button> m_buttons;\n  QuitDialog m_quit;\n  OptionsDialog m_options;\n  SaveLoadDialog m_saveload;\n  State m_state{State::None};\n  State m_nextState{State::None};\n  Callback m_newGameCallback;\n\n  inline static constexpr float getSlotPos(int slot) {\n    return yPosStart + yStep * static_cast<float>(slot - 1);\n  }\n\n  void setState(State state) {\n    m_nextState = state;\n  }\n\n  void setEngine(Engine *pEngine) {\n    m_pEngine = pEngine;\n    if (!pEngine)\n      return;\n\n    m_saveload.setEngine(pEngine);\n    m_saveload.setCallback([this]() {\n      _showSaveLoad = false;\n    });\n\n    m_options.setEngine(pEngine);\n    m_options.setCallback([this]() {\n      setState(State::Main);\n    });\n\n    m_quit.setEngine(pEngine);\n    m_quit.setCallback([this](bool result) {\n      if (result)\n        m_pEngine->quit();\n      setState(State::Main);\n    });\n\n    setState(State::Main);\n  }\n\n  void draw(ngf::RenderTarget &target, ngf::RenderStates states) {\n    switch (m_state) {\n    case State::Main: {\n      const auto view = target.getView();\n      auto viewRect = ngf::frect::fromPositionSize({0, 0}, {Screen::Width, Screen::Height});\n      target.setView(ngf::View(viewRect));\n\n      // controls\n      for (auto &button : m_buttons) {\n        button.draw(target, {});\n      }\n\n      target.setView(view);\n\n      if (_showSaveLoad) {\n        m_saveload.draw(target, states);\n      }\n      break;\n    }\n\n    case State::Options:\n    case State::Help:m_options.draw(target, states);\n      break;\n\n    case State::Quit:m_quit.draw(target, states);\n      break;\n    case State::None:break;\n    }\n  }\n\n  void onStateChanged() {\n    m_buttons.clear();\n    switch (m_state) {\n    case State::Main:m_buttons.emplace_back(Ids::LoadGame, getSlotPos(1), [this]() { _showSaveLoad = true; });\n      m_buttons.emplace_back(Ids::LoadGame, getSlotPos(1), [this]() {\n        m_saveload.updateLanguage();\n        m_saveload.setSaveMode(false);\n        _showSaveLoad = true;\n      });\n      m_buttons.emplace_back(Ids::NewGame, getSlotPos(2), [this]() {\n        if (m_newGameCallback)\n          m_newGameCallback();\n      });\n      m_buttons.emplace_back(Ids::Options, getSlotPos(3), [this]() { setState(State::Options); });\n      m_buttons.emplace_back(Ids::Help, getSlotPos(4), [this]() { setState(State::Help); });\n      m_buttons.emplace_back(Ids::Quit, getSlotPos(5), [this]() { setState(State::Quit); });\n      break;\n    case State::Help:m_options.showHelp();\n      break;\n    case State::Options:break;\n    case State::Quit:break;\n    default:setState(State::Main);\n      break;\n    }\n\n    for (auto &button : m_buttons) {\n      button.setEngine(m_pEngine);\n    }\n  }\n\n  void update(const ngf::TimeSpan &elapsed) {\n    if (m_nextState != m_state) {\n      m_state = m_nextState;\n      onStateChanged();\n    }\n\n    switch (m_state) {\n    case State::Quit:m_quit.update(elapsed);\n      break;\n\n    case State::Options:\n    case State::Help:m_options.update(elapsed);\n      break;\n\n    default:\n      if (_showSaveLoad) {\n        m_saveload.update(elapsed);\n        return;\n      }\n\n      auto pos = m_pEngine->getApplication()->getRenderTarget()->mapPixelToCoords(ngf::Mouse::getPosition(),\n                                                                                  ngf::View(ngf::frect::fromPositionSize(\n                                                                                      {0,\n                                                                                       0},\n                                                                                      {Screen::Width,\n                                                                                       Screen::Height})));\n      for (auto &button : m_buttons) {\n        button.update(elapsed, pos);\n      }\n      break;\n    }\n  }\n  bool _showSaveLoad{false};\n};\n\nStartScreenDialog::StartScreenDialog()\n    : m_pImpl(std::make_unique<Impl>()) {\n}\n\nStartScreenDialog::~StartScreenDialog() = default;\n\nvoid StartScreenDialog::setEngine(Engine *pEngine) { m_pImpl->setEngine(pEngine); }\n\nvoid StartScreenDialog::draw(ngf::RenderTarget &target, ngf::RenderStates states) const {\n  m_pImpl->draw(target, states);\n}\n\nvoid StartScreenDialog::update(const ngf::TimeSpan &elapsed) {\n  m_pImpl->update(elapsed);\n}\n\nvoid StartScreenDialog::setNewGameCallback(Callback callback) {\n  m_pImpl->m_newGameCallback = std::move(callback);\n}\n\nvoid StartScreenDialog::setSlotCallback(SaveLoadDialog::SlotCallback callback) {\n  m_pImpl->m_saveload.setSlotCallback(std::move(callback));\n}\n}\n"
  },
  {
    "path": "src/UI/SwitchButton.cpp",
    "content": "#include \"SwitchButton.hpp\"\n#include <engge/Engine/Engine.hpp>\n#include <ngf/Graphics/FntFont.h>\n#include \"Util/Util.hpp\"\n#include \"ControlConstants.hpp\"\n#include <ngf/System/Mouse.h>\n#include <imgui.h>\n\nnamespace ng {\nSwitchButton::SwitchButton(std::initializer_list<int> ids,\n                           float y, bool enabled, int index, Callback callback)\n    : Control(enabled), m_ids(ids), m_index(index), m_y(y), m_callback(std::move(callback)) {\n}\n\nvoid SwitchButton::draw(ngf::RenderTarget &target, ngf::RenderStates states) const {\n  m_text.draw(target, states);\n}\n\nvoid SwitchButton::onEngineSet() {\n  auto &uiFontMedium = m_pEngine->getResourceManager().getFntFont(\"UIFontMedium.fnt\");\n  m_text.setFont(uiFontMedium);\n  m_text.setWideString(Engine::getText(m_ids[m_index]));\n  auto textRect = m_text.getLocalBounds();\n  m_text.getTransform().setOrigin({textRect.getWidth() / 2.f, 0});\n  m_text.getTransform().setPosition({Screen::Width / 2.f, m_y});\n}\n\nbool SwitchButton::contains(glm::vec2 pos) const {\n  auto textRect = ng::getGlobalBounds(m_text);\n  return textRect.contains(pos);\n}\n\nvoid SwitchButton::onClick() {\n  m_index = (m_index + 1) % static_cast<int>(m_ids.size());\n  m_text.setWideString(Engine::getText(m_ids[m_index]));\n  if (m_callback) {\n    m_callback(m_index);\n  }\n  auto textRect = m_text.getLocalBounds();\n  m_text.getTransform().setOrigin({textRect.getWidth() / 2.f, 0});\n}\n\nvoid SwitchButton::onStateChanged() {\n  ngf::Color color;\n  switch (m_state) {\n  case ControlState::Disabled:color = ControlConstants::DisabledColor;\n    break;\n  case ControlState::None:color = ControlConstants::NormalColor;\n    break;\n  case ControlState::Hover:color = ControlConstants::HoverColor;\n    break;\n  }\n  m_text.setColor(color);\n}\n\nvoid SwitchButton::update(const ngf::TimeSpan &elapsed, glm::vec2 pos) {\n  Control::update(elapsed, pos);\n  m_text.getTransform().setPosition(m_shakeOffset + glm::vec2{Screen::Width / 2.f, m_y});\n}\n}"
  },
  {
    "path": "src/UI/SwitchButton.hpp",
    "content": "#pragma once\n#include <glm/vec2.hpp>\n#include <functional>\n#include <initializer_list>\n#include <vector>\n#include <ngf/Graphics/RenderTarget.h>\n#include <ngf/Graphics/RenderStates.h>\n#include <ngf/Graphics/Drawable.h>\n#include <engge/Graphics/Text.hpp>\n#include \"UI/Control.hpp\"\n\nnamespace ng {\nclass Engine;\n\nclass SwitchButton final : public Control {\npublic:\n  using Callback = std::function<void(int)>;\n\n  SwitchButton(std::initializer_list<int> ids,\n               float y,\n               bool enabled = true,\n               int index = 0,\n               Callback callback = nullptr);\n  void draw(ngf::RenderTarget &target, ngf::RenderStates states) const final;\n  void update(const ngf::TimeSpan &elapsed, glm::vec2 pos) final;\n\nprivate:\n  bool contains(glm::vec2 pos) const final;\n  void onEngineSet() final;\n  void onClick() final;\n  void onStateChanged() final;\n\nprivate:\n  std::vector<int> m_ids;\n  int m_index{0};\n  float m_y{0};\n  Callback m_callback{nullptr};\n  ng::Text m_text;\n};\n}\n"
  },
  {
    "path": "src/Util/BTEACrypto.cpp",
    "content": "#include \"engge/Util/BTEACrypto.hpp\"\n\nnamespace ng {\n#define DELTA 0x9e3779b9\n#define MX (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z)))\n\nvoid BTEACrypto::encrypt(uint32_t *v, int n, const uint32_t *key) {\n  btea(v, n, key);\n}\n\nvoid BTEACrypto::decrypt(uint32_t *v, int n, const uint32_t *key) {\n  btea(v, -n, key);\n}\n\n// This method comes from https://en.wikipedia.org/wiki/XXTEA\nvoid BTEACrypto::btea(uint32_t *v, int n, const uint32_t *key) {\n  uint32_t y, z, sum;\n  unsigned p, rounds, e;\n  if (n > 1) {          /* Coding Part */\n    rounds = 6 + 52 / n;\n    sum = 0;\n    z = v[n - 1];\n    do {\n      sum += DELTA;\n      e = (sum >> 2) & 3;\n      for (p = 0; p < static_cast<uint32_t>(n - 1); p++) {\n        y = v[p + 1];\n        z = v[p] += MX;\n      }\n      y = v[0];\n      z = v[n - 1] += MX;\n    } while (--rounds);\n  } else if (n < -1) {  /* Decoding Part */\n    n = -n;\n    rounds = 6 + 52 / n;\n    sum = rounds * DELTA;\n    y = v[0];\n    do {\n      e = (sum >> 2) & 3;\n      for (p = n - 1; p > 0; p--) {\n        z = v[p - 1];\n        y = v[p] -= MX;\n      }\n      z = v[n - 1];\n      y = v[0] -= MX;\n      sum -= DELTA;\n    } while (--rounds);\n  }\n}\n}\n"
  },
  {
    "path": "src/Util/Dumper.hpp",
    "content": "#pragma once\n#include \"../Dialog/AstDump.hpp\"\n#include \"engge/Parsers/SavegameManager.hpp\"\n#include <filesystem>\n#include <iostream>\nnamespace fs = std::filesystem;\n\nclass Dumper {\npublic:\n  static void dump(const std::string& filename){\n    auto filepath = fs::path(filename);\n    auto ext = filepath.extension();\n    if (ext == \".byack\") {\n      ng::_AstDump::dump(filename);\n    } else if (ext == \".save\") {\n      ng::GGPackValue hash;\n      ng::SavegameManager::loadGame(filename, hash);\n      std::cout << hash;\n    }\n  }\n};\n"
  },
  {
    "path": "src/Util/RandomNumberGenerator.cpp",
    "content": "#include <ctime>\n#include <random>\n#include \"engge/Util/RandomNumberGenerator.hpp\"\n\nnamespace ng {\nRandomNumberGenerator::RandomNumberGenerator() {\n  time_t t;\n  setSeed(static_cast<long>(time(&t)));\n}\n\nvoid RandomNumberGenerator::setSeed(long seed) {\n  m_seed = seed;\n  srand(m_seed);\n}\n\nlong RandomNumberGenerator::getSeed() const { return m_seed; }\n\nlong RandomNumberGenerator::generateLong(long min, long max) {\n  max++;\n  auto value = rand() % (max - min) + min;\n  return value;\n}\n\nfloat RandomNumberGenerator::generateFloat(float min, float max) {\n  float scale = rand() / (float) RAND_MAX; /* [0, 1.0] */\n  return min + scale * (max - min);       /* [min, max] */\n}\n\n}\n"
  },
  {
    "path": "src/Util/Util.cpp",
    "content": "#include \"../../extlibs/squirrel/squirrel/sqpcheader.h\"\n#include \"../../extlibs/squirrel/squirrel/sqvm.h\"\n#include \"../../extlibs/squirrel/squirrel/sqstring.h\"\n#include \"../../extlibs/squirrel/squirrel/sqtable.h\"\n#include \"../../extlibs/squirrel/squirrel/sqarray.h\"\n#include \"../../extlibs/squirrel/squirrel/sqfuncproto.h\"\n#include \"../../extlibs/squirrel/squirrel/sqclosure.h\"\n#include \"engge/Engine/EntityManager.hpp\"\n#include \"engge/Scripting/ScriptEngine.hpp\"\n#include <codecvt>\n#include <ngf/IO/GGPackValue.h>\n#include \"Util.hpp\"\n#include \"engge/System/Locator.hpp\"\n#include \"engge/Engine/Preferences.hpp\"\n\nnamespace ng {\n\nnamespace {\nconstexpr const char *objectKey = \"_objectKey\";\nconstexpr const char *roomKey = \"_roomKey\";\nconstexpr const char *actorKey = \"_actorKey\";\nconstexpr const char *idKey = \"_id\";\n\nngf::GGPackValue toGGPackValue(SQObject obj, bool checkId, const std::string &tableKey = \"\");\n\nbool canSave(HSQOBJECT obj) {\n  switch (sq_type(obj)) {\n  case OT_STRING: return true;\n  case OT_INTEGER: return true;\n  case OT_BOOL:return true;\n  case OT_FLOAT:return true;\n  case OT_NULL:return true;\n  case OT_TABLE:return true;\n  case OT_ARRAY:return true;\n  default:return false;\n  }\n}\n\nngf::GGPackValue toArray(HSQOBJECT obj) {\n  ngf::GGPackValue array;\n  SQObjectPtr refpos;\n  SQObjectPtr outkey, outvar;\n  SQInteger res;\n  while ((res = obj._unVal.pArray->Next(refpos, outkey, outvar)) != -1) {\n    if (canSave(outvar)) {\n      array.push_back(toGGPackValue(outvar, true));\n    }\n    refpos._type = OT_INTEGER;\n    refpos._unVal.nInteger = res;\n  }\n  return array;\n}\n\nngf::GGPackValue toTable(HSQOBJECT table, bool checkId, const std::string &tableKey = \"\") {\n  ngf::GGPackValue hash;\n  int id;\n  if (checkId && ng::ScriptEngine::get(table, idKey, id)) {\n    if (ng::EntityManager::isActor(id)) {\n      auto pActor = ng::EntityManager::getActorFromId(id);\n      if (pActor && pActor->getKey() != tableKey) {\n        hash[actorKey] = pActor->getKey();\n        return hash;\n      }\n      return nullptr;\n    }\n    if (ng::EntityManager::isObject(id)) {\n      auto pObj = ng::EntityManager::getObjectFromId(id);\n      if (pObj && pObj->getKey() != tableKey) {\n        auto pRoom = pObj->getRoom();\n        if (pRoom && pRoom->isPseudoRoom()) {\n          hash[roomKey] = pRoom->getName();\n        }\n        hash[objectKey] = pObj->getKey();\n        return hash;\n      }\n      return nullptr;\n    }\n    if (ng::EntityManager::isRoom(id)) {\n      auto pRoom = ng::EntityManager::getRoomFromId(id);\n      if (pRoom && pRoom->getName() != tableKey) {\n        hash[roomKey] = pRoom->getName();\n        return hash;\n      }\n      return nullptr;\n    }\n    return nullptr;\n  }\n\n  SQObjectPtr refpos;\n  SQObjectPtr outkey, outvar;\n  SQInteger res;\n  while ((res = table._unVal.pTable->Next(false, refpos, outkey, outvar)) != -1) {\n    std::string key = _stringval(outkey);\n    if (!key.empty() && key[0] != '_' && canSave(outvar)) {\n      auto value = toGGPackValue(outvar, true, key);\n      if (!value.isNull()) {\n        hash[key] = value;\n      }\n    }\n    refpos._type = OT_INTEGER;\n    refpos._unVal.nInteger = res;\n  }\n  return hash;\n}\n\nngf::GGPackValue toGGPackValue(SQObject obj, bool checkId, const std::string &tableKey) {\n  switch (sq_type(obj)) {\n  case OT_STRING:return _stringval(obj);\n  case OT_INTEGER:\n  case OT_BOOL:return static_cast<int>(_integer(obj));\n  case OT_FLOAT:return static_cast<float >(_float(obj));\n  case OT_NULL:return nullptr;\n  case OT_TABLE: return toTable(obj, checkId, tableKey);\n  case OT_ARRAY: {\n    return toArray(obj);\n  }\n  default:assert(false);\n  }\n}\n}\n\nstd::string str_toupper(std::string s) {\n  std::transform(s.begin(), s.end(), s.begin(),\n                 [](unsigned char c) { return ::toupper(c); } // correct\n  );\n  return s;\n}\n\nvoid replaceAll(std::string &text, const std::string &search, const std::string &replace) {\n  auto pos = text.find(search);\n  while (pos != std::string::npos) {\n    text.replace(pos, search.size(), replace);\n    pos = text.find(search, pos + replace.size());\n  }\n}\n\nvoid replaceAll(std::wstring &text, const std::wstring &search, const std::wstring &replace) {\n  auto pos = text.find(search);\n  while (pos != std::wstring::npos) {\n    text.replace(pos, search.size(), replace);\n    pos = text.find(search, pos + replace.size());\n  }\n}\n\nvoid removeFirstParenthesis(std::wstring &text) {\n  if (text.size() < 2)\n    return;\n  if (text.find(L'(') != 0)\n    return;\n  auto pos = text.find(L')');\n  if (pos == std::wstring::npos)\n    return;\n  text = text.substr(pos + 1);\n}\n\nbool startsWith(const std::string &str, const std::string &prefix) {\n  return str.length() >= prefix.length() && 0 == str.compare(0, prefix.length(), prefix);\n}\n\nbool endsWith(const std::string &str, const std::string &suffix) {\n  return str.length() >= suffix.length() && 0 == str.compare(str.length() - suffix.length(), suffix.length(), suffix);\n}\n\nvoid checkLanguage(std::string &str) {\n  if (endsWith(str, \"_en\")) {\n    const auto &lang = Locator<Preferences>::get().getUserPreference<std::string>(PreferenceNames::Language,\n                                                                                  PreferenceDefaultValues::Language);\n    str = str.substr(0, str.length() - 3).append(\"_\").append(lang);\n    return;\n  }\n\n  if (str.length() > 7 && str[str.length() - 4] == '.' && str.substr(str.length() - 7, 3) == \"_en\") {\n    const auto &lang = Locator<Preferences>::get().getUserPreference<std::string>(PreferenceNames::Language,\n                                                                                  PreferenceDefaultValues::Language);\n    str = str.substr(0, str.length() - 7).append(\"_\").append(lang).append(str.substr(str.length() - 4, 4));\n  }\n}\n\nbool getLine(GGPackBufferStream &input, std::string &line) {\n  char c;\n  line.clear();\n  do {\n    input.read(&c, 1);\n    if (c == 0 || c == '\\n') {\n      return input.tell() < input.getLength();\n    }\n    line.append(&c, 1);\n  } while (true);\n}\n\nstd::wstring towstring(const std::string &text) {\n  std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> converter;\n  return converter.from_bytes(text.data(), text.data() + text.size());\n}\n\nstd::string tostring(const std::wstring &text) {\n  std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> converter;\n  return converter.to_bytes(text);\n}\n\nstd::string toUtf8(const std::wstring &text) {\n  std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;\n  return converter.to_bytes(text);\n}\n\nbool getLine(GGPackBufferStream &input, std::wstring &wline) {\n  std::string line;\n  char c;\n  do {\n    input.read(&c, 1);\n    if (c == 0 || c == '\\n') {\n      std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> converter;\n      wline = converter.from_bytes(line.data(), line.data() + line.size());\n\n      return input.tell() < input.getLength();\n    }\n    line.append(&c, 1);\n  } while (true);\n}\n\nfloat distanceSquared(const glm::vec2 &vector1, const glm::vec2 &vector2) {\n  float dx = vector1.x - vector2.x;\n  float dy = vector1.y - vector2.y;\n\n  return dx * dx + dy * dy;\n}\n\nfloat distance(const glm::vec2 &v1, const glm::vec2 &v2) {\n  return std::sqrt(distanceSquared(v1, v2));\n}\n\nfloat length(const glm::vec2 &v) {\n  return sqrtf(v.x * v.x + v.y * v.y);\n}\n\nconst double EPS = 1E-9;\n\ndouble det(float a, float b, float c, float d) {\n  return a * d - b * c;\n}\n\ninline bool betw(float l, float r, float x) {\n  return fmin(l, r) <= x + EPS && x <= fmax(l, r) + EPS;\n}\n\ntemplate<typename T>\nvoid swap(T &a, T &b) {\n  T c = a;\n  a = b;\n  b = c;\n}\n\ninline bool intersect_1d(float a, float b, float c, float d) {\n  if (a > b)\n    swap(a, b);\n  if (c > d)\n    swap(c, d);\n  return fmax(a, c) <= fmin(b, d) + EPS;\n}\n\nbool less(const glm::vec2 &p1, const glm::vec2 &p2) {\n  return p1.x < p2.x - EPS || (fabs(p1.x - p2.x) < EPS && p1.y < p2.y - EPS);\n}\n\nFacing toFacing(std::optional<UseDirection> direction) {\n  auto dir = direction.value_or(UseDirection::Front);\n  switch (dir) {\n  case UseDirection::Front:return Facing::FACE_FRONT;\n  case UseDirection::Back:return Facing::FACE_BACK;\n  case UseDirection::Left:return Facing::FACE_LEFT;\n  case UseDirection::Right:return Facing::FACE_RIGHT;\n  }\n}\n\nFacing getOppositeFacing(Facing facing) {\n  switch (facing) {\n  case Facing::FACE_FRONT:return Facing::FACE_BACK;\n  case Facing::FACE_BACK:return Facing::FACE_FRONT;\n  case Facing::FACE_LEFT:return Facing::FACE_RIGHT;\n  case Facing::FACE_RIGHT:return Facing::FACE_LEFT;\n  }\n}\n\nngf::irect toRect(const ngf::GGPackValue &json) {\n  auto x = json[\"x\"].getInt();\n  auto y = json[\"y\"].getInt();\n  auto w = json[\"w\"].getInt();\n  auto h = json[\"h\"].getInt();\n  return ngf::irect::fromPositionSize({x, y}, {w, h});\n}\n\nglm::ivec2 toSize(const ngf::GGPackValue &json) {\n  glm::ivec2 v;\n  v.x = json[\"w\"].getInt();\n  v.y = json[\"h\"].getInt();\n  return v;\n}\n\nUseDirection toDirection(const std::string &text) {\n  if (strcmp(text.c_str(), \"DIR_FRONT\") == 0) {\n    return UseDirection::Front;\n  }\n  if (strcmp(text.c_str(), \"DIR_LEFT\") == 0) {\n    return UseDirection::Left;\n  }\n  if (strcmp(text.c_str(), \"DIR_BACK\") == 0) {\n    return UseDirection::Back;\n  }\n  if (strcmp(text.c_str(), \"DIR_RIGHT\") == 0) {\n    return UseDirection::Right;\n  }\n  return UseDirection::Front;\n}\n\nglm::vec2 parsePos(const std::string &text) {\n  auto commaPos = text.find_first_of(',');\n  auto x = std::strtof(text.substr(1, commaPos - 1).c_str(), nullptr);\n  auto y = std::strtof(text.substr(commaPos + 1, text.length() - 1).c_str(), nullptr);\n  return glm::vec2(x, y);\n}\n\nngf::irect parseRect(const std::string &text) {\n  auto re = std::regex(R\"(\\{\\{(\\-?\\d+),(\\-?\\d+)\\},\\{(\\-?\\d+),(\\-?\\d+)\\}\\})\");\n  std::smatch matches;\n  std::regex_search(text, matches, re);\n  auto left = std::strtol(matches[1].str().c_str(), nullptr, 10);\n  auto top = std::strtol(matches[2].str().c_str(), nullptr, 10);\n  auto right = std::strtol(matches[3].str().c_str(), nullptr, 10);\n  auto bottom = std::strtol(matches[4].str().c_str(), nullptr, 10);\n  return ngf::irect::fromPositionSize({left, top}, {right - left, bottom - top});\n}\n\nvoid parsePolygon(const std::string &text, std::vector<glm::ivec2> &vertices) {\n  int i = 1;\n  int endPos;\n  do {\n    auto commaPos = text.find_first_of(',', i);\n    auto x = std::strtol(text.substr(i, commaPos - i).c_str(), nullptr, 10);\n    endPos = text.find_first_of('}', commaPos + 1);\n    auto y = std::strtol(text.substr(commaPos + 1, endPos - commaPos - 1).c_str(), nullptr, 10);\n    i = endPos + 3;\n    vertices.emplace_back(x, y);\n  } while (static_cast<int>(text.length() - 1) != endPos);\n}\n\nngf::Color parseColor(const std::string &color) {\n  auto c = std::strtol(color.c_str(), nullptr, 16);\n  return fromRgb(c);\n}\n\nngf::Color fromRgba(SQInteger color) {\n  auto col = static_cast<uint32_t>(color);\n  ngf::Color c(\n      static_cast<int>((col >> 16) & 255),\n      static_cast<int>((col >> 8) & 255),\n      static_cast<int>(col & 255),\n      static_cast<int>((col >> 24) & 255));\n  return c;\n}\n\nint toInteger(const ngf::Color &c) {\n  auto r = static_cast<uint32_t>(c.r * 255u);\n  auto g = static_cast<uint32_t>(c.g * 255u);\n  auto b = static_cast<uint32_t>(c.b * 255u);\n  auto a = static_cast<uint32_t>(c.a * 255u);\n  return static_cast<int>((r << 16) | (g << 8) | b | (a << 24));\n}\n\nngf::Color fromRgb(SQInteger color) {\n  auto col = static_cast<int>(color);\n  ngf::Color c((col >> 16) & 255, (col >> 8) & 255, col & 255);\n  return c;\n}\n\nglm::vec2 toDefaultView(glm::ivec2 pos, glm::ivec2 fromSize) {\n  return glm::vec2((Screen::Width * pos.x) / fromSize.x, (Screen::Height * pos.y) / fromSize.y);\n}\n\nInterpolationMethod toInterpolationMethod(SQInteger interpolation) {\n  auto method = static_cast<InterpolationMethod>((interpolation & 7) + 1);\n  if (interpolation & 0x100) {\n    method |= InterpolationMethod::Looping;\n  }\n  if (interpolation & 0x200) {\n    method |= InterpolationMethod::Swing;\n  }\n  return method;\n}\n\nngf::frect getGlobalBounds(const ngf::Text &text) {\n  return ngf::transform(text.getTransform().getTransform(), text.getLocalBounds());\n}\n\nngf::frect getGlobalBounds(const ngf::Sprite &sprite) {\n  return ngf::transform(sprite.getTransform().getTransform(), sprite.getLocalBounds());\n}\n\nngf::GGPackValue toGGPackValue(HSQOBJECT obj) {\n  return toGGPackValue((SQObject) obj, false);\n}\n\n} // namespace ng\n"
  },
  {
    "path": "src/Util/Util.hpp",
    "content": "#pragma once\n#include <optional>\n#include <regex>\n#include <ngf/IO/GGPackValue.h>\n#include <ngf/Graphics/Sprite.h>\n#include <ngf/Graphics/Text.h>\n#include <engge/Parsers/GGPackBufferStream.hpp>\n#include <engge/Entities/Costume.hpp>\n#include <engge/Entities/Object.hpp>\n#include <engge/Graphics/Screen.hpp>\n\nnamespace ng {\n\nstruct CaseInsensitiveCompare {\n  bool operator()(const std::string &a, const std::string &b) const noexcept {\n#ifdef WIN32\n    return _stricmp(a.c_str(), b.c_str()) == 0;\n#else\n    return ::strcasecmp(a.c_str(), b.c_str()) == 0;\n#endif\n  }\n};\n\nvoid replaceAll(std::string &text, const std::string &search, const std::string &replace);\nvoid replaceAll(std::wstring &text, const std::wstring &search, const std::wstring &replace);\n\nvoid removeFirstParenthesis(std::wstring &text);\nbool startsWith(const std::string &str, const std::string &prefix);\nbool endsWith(const std::string &str, const std::string &suffix);\nvoid checkLanguage(std::string &str);\n\nbool getLine(GGPackBufferStream &input, std::string &line);\n\nstd::wstring towstring(const std::string &text);\nstd::string tostring(const std::wstring &text);\nstd::string toUtf8(const std::wstring &text);\nstd::string str_toupper(std::string s);\n\nbool getLine(GGPackBufferStream &input, std::wstring &wline);\n\nfloat distanceSquared(const glm::vec2 &vector1, const glm::vec2 &vector2);\nfloat distance(const glm::vec2 &v1, const glm::vec2 &v2);\n\nfloat length(const glm::vec2 &v);\n\nFacing toFacing(std::optional<UseDirection> direction);\nUseDirection toDirection(const std::string &text);\nFacing getOppositeFacing(Facing facing);\n\nngf::irect toRect(const ngf::GGPackValue &json);\nglm::ivec2 toSize(const ngf::GGPackValue &json);\n\nglm::vec2 parsePos(const std::string &text);\nngf::irect parseRect(const std::string &text);\nvoid parsePolygon(const std::string &text, std::vector<glm::ivec2> &vertices);\n\nngf::Color parseColor(const std::string &color);\nngf::Color fromRgba(SQInteger color);\nngf::Color fromRgb(SQInteger color);\nint toInteger(const ngf::Color& color);\n\nglm::vec2 toDefaultView(glm::ivec2 pos, glm::ivec2 fromSize);\n\nInterpolationMethod toInterpolationMethod(SQInteger interpolation);\n\nngf::frect getGlobalBounds(const ngf::Text &text);\nngf::frect getGlobalBounds(const ngf::Sprite &sprite);\n\nngf::GGPackValue toGGPackValue(HSQOBJECT obj);\n\n} // namespace ng\n"
  },
  {
    "path": "src/main.cpp",
    "content": "#include \"Engine/AchievementManager.hpp\"\n#include \"engge/EnggeApplication.hpp\"\n\nint main(int, char *[]) {\n  ng::EnggeApplication app;\n  try {\n    app.run();\n    ng::Locator<ng::Engine>::reset();\n  }\n  catch (std::exception &e) {\n    app.showMessageBox(\"Critical Error!\", e.what(), ngf::MessageBoxType::Warning);\n    return 1;\n  }\n  catch (...) {\n    ng::error(\"Sorry, an error occurred\");\n    return 2;\n  }\n  return EXIT_SUCCESS;\n}\n"
  }
]