diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..d4251ed --- /dev/null +++ b/.editorconfig @@ -0,0 +1,9 @@ +root = true + +[*] +insert_final_newline = true +indent_style = space +indent_size = 4 +charset = utf-8-bom +trim_trailing_whitespace = true +tab_width = 4 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b236644 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +build +release diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..7236cb1 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required(VERSION 3.8) + +project(a-maze-batz) + +add_subdirectory(source) +add_subdirectory(assets) diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..ac2d8cf --- /dev/null +++ b/LICENSE @@ -0,0 +1,7 @@ +Copyright 2018 Mario Liebisch + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/assets/CMakeLists.txt b/assets/CMakeLists.txt new file mode 100644 index 0000000..c44f60f --- /dev/null +++ b/assets/CMakeLists.txt @@ -0,0 +1,4 @@ +install(DIRECTORY fonts DESTINATION assets) +install(DIRECTORY sounds DESTINATION assets) +install(DIRECTORY textures DESTINATION assets) +install(DIRECTORY levels DESTINATION assets) diff --git a/assets/fonts/CompassPro.md b/assets/fonts/CompassPro.md new file mode 100644 index 0000000..9a3029a --- /dev/null +++ b/assets/fonts/CompassPro.md @@ -0,0 +1 @@ +Compass Pro is a free font by [Eeve Somepx](https://somepx.itch.io/humble-fonts-free). diff --git a/assets/fonts/CompassPro.ttf b/assets/fonts/CompassPro.ttf new file mode 100644 index 0000000..5432d65 Binary files /dev/null and b/assets/fonts/CompassPro.ttf differ diff --git a/assets/sounds/drop.wav b/assets/sounds/drop.wav new file mode 100644 index 0000000..dd69f20 Binary files /dev/null and b/assets/sounds/drop.wav differ diff --git a/assets/sounds/ping0.wav b/assets/sounds/ping0.wav new file mode 100644 index 0000000..b2eb2f9 Binary files /dev/null and b/assets/sounds/ping0.wav differ diff --git a/assets/sounds/ping1.wav b/assets/sounds/ping1.wav new file mode 100644 index 0000000..5263648 Binary files /dev/null and b/assets/sounds/ping1.wav differ diff --git a/assets/textures/bat0.png b/assets/textures/bat0.png new file mode 100644 index 0000000..736aabe Binary files /dev/null and b/assets/textures/bat0.png differ diff --git a/assets/textures/bat1.png b/assets/textures/bat1.png new file mode 100644 index 0000000..421c934 Binary files /dev/null and b/assets/textures/bat1.png differ diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..d933fe2 --- /dev/null +++ b/readme.md @@ -0,0 +1,47 @@ +# A-Maze Batz +*A small casual game entry for the [Game Maker's Toolkit Game Jam 2018](https://itch.io/jam/gmtk-2018).* + +© 2018 Mario Liebisch + +## About the Game + +You're helping **Batz** on his way through dark and deep caverns on the look for the one thing that really matters: **Batsie**. This must be true bat love in some way, although Batsie seems to leave our hero from time to time and he'll have to find her once again. + + There's no real end: Once the last level has been beaten, the game will simply restart from the first one. You can even create your own levels and challenge your friends to find Batsie as fast as possible. + +You can't really lose the game. There are no lives, there's no timer. Some kind of time attack mode was planned, but I was lacking time so far. In its current form, consider this a prototype and proof of concept. + +**This project originalted in a game jam weekend in a total of less than 24 hours.** This code isn't clean and it's clearly not built around best practices and optimization only. If you're curious, have a look, but always keep this in mind. + +## Controls + +The game controls are pretty straight forward: + +* **Cursor Keys** and **W/A/S/D**: Steer Batz through the dark saves. +* **Space**: Use Batz's sonar to identify caverns, tunnels and openings. Batsie will also answer your call, if she can hear you. + +## Building the Game + +To build the game, you'll need a recent version of [CMake](https://cmake.org/) as well as [SFML](https://sfml-dev.org/) and an up-to-date C/C++ toolchain (like GCC, MinGW, Visual Studio, etc.). + +To configure and build the project, just run CMake in the usual way: `cmake path/to/source`. + +You might have to specify to your SFML installation: `cmake -DSFML_DIR=C:/Code/SFML/lib/cmake/SFML path/to/source` (note the sub path pointing inside the installation directory). + +## License + +This game is released under the [MIT License](LICENSE). Feel free to use all or portions of it in your own projects. If you finish some cool project, I'd love to hear about it! + +## Modding and Level Editing + +The game's levels are stored in a very simple and easy to edit way. Open the sub directory `assets/levels`, where you'll find one PNG image per level. + +You can edit existing levels or create new ones, simply creating a new file following the existing numbering pattern. If the last level is `level5.png`, save your own level as `level6.png` to extend the game. There's no need to recompile or rebuild the game in order to test new levels. + +There are a few tiny things to keep in mind here: + +* Your PNG file has to be saved as an 24-bit or 32-bit color PNG image. 8-bit PNGs are not supported. +* Fully black parts (RGB: 0/0/0) are considered solid. You don't have to fill shapes. Even 1 pixel thin lines should count, although sonar pings might pass through thin diagonal lines. +* Make sure that tunnels and choke points are at least 10-12 pixels wide. +* Green pixels (RGB: 0/255/0) are potential starting positions. If there's more than one position available, the actual starting position will be picked at random. +* Red pixels (RGB: 255/0/0) are potential goal positions, i.e. where Batsie may be found. \ No newline at end of file diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt new file mode 100644 index 0000000..9974020 --- /dev/null +++ b/source/CMakeLists.txt @@ -0,0 +1,17 @@ +find_package(SFML 2.5 COMPONENTS audio graphics main) + +set(SOURCES main.cpp game.hpp game.cpp icon.cpp) +if (WIN32) +list(APPEND SOURCES resources.rc) +endif() + +add_executable(a-maze-batz ${SOURCES}) + +set_target_properties(a-maze-batz PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}") +target_link_libraries(a-maze-batz sfml-graphics sfml-audio sfml-main) + +if(MSVC) +set_target_properties(a-maze-batz PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:WINDOWS") +endif() + +install(TARGETS a-maze-batz DESTINATION .) diff --git a/source/game.cpp b/source/game.cpp new file mode 100644 index 0000000..8e91e12 --- /dev/null +++ b/source/game.cpp @@ -0,0 +1,424 @@ +#include "game.hpp" +#include +#include +#include +#include +#include +#include +#include +#include + +extern const char *iconData; + +Game::Game() { + mWindow.create({ 512, 288 }, L"A-Maze Batz – a GMTK Game Jam 2018 entry", sf::Style::Close | sf::Style::Titlebar); + mWindow.setVerticalSyncEnabled(true); + mWindow.setIcon(32, 32, reinterpret_cast(iconData)); + + mPlayer.setTexture(get("assets/textures/bat0.png")); + mPlayer.setTextureRect({ 0, 0, 32, 16 }); + mPlayer.setOrigin(16, 8); + + mGoal.setTexture(get("assets/textures/bat1.png")); + mGoal.setTextureRect({ 0, 0, 32, 16 }); + mGoal.setOrigin(16, 8); + + mSonar.reserve(5000); +} + +Game::~Game() { +} + +int Game::run() { + sf::RenderTexture mScreen; + mScreen.create(256, 144); + sf::Sprite mShow(mScreen.getTexture()); + + sf::View view({ 128, 72 }, { 256, 144 }); + sf::View sview({ 128, 72 }, { 256, 144 }); + mWindow.setView(sview); + + sf::Clock timer; + sf::Time elapsed; + const sf::Time frameTime(sf::seconds(1) / 60.f); + long tick = 0; + + unsigned char movement = None; + Direction dir = Right; + bool lastLeft = false; + + if (!resetLevel()) + throw Exception("Couldn't load the first level!"); + + sf::Sound ping0(get("assets/sounds/ping0.wav")); + sf::Sound ping0e(get("assets/sounds/ping0.wav")); + ping0e.setVolume(25); + sf::Sound ping1(get("assets/sounds/ping1.wav")); + sf::Sound ping1e(get("assets/sounds/ping1.wav")); + ping1e.setVolume(25); + sf::Sound drop(get("assets/sounds/drop.wav")); + sf::Sound drope(get("assets/sounds/drop.wav")); + drope.setVolume(25); + + sf::RectangleShape white({ 256,144 }); + white.setFillColor(sf::Color::White); + + sf::Font &font = get("assets/fonts/CompassPro.ttf"); + const_cast(font.getTexture(16)).setSmooth(false); + + sf::Text intro("Can you help Batz to find love?\n\nUse the cursor keys or [WASD],\n and [Space] to find your way!\n\n [Space] Start game\n [Alt] + [Return] Fullscreen", font, 16); + intro.setPosition(32, 8); + intro.setOutlineThickness(1); + intro.setOutlineColor(sf::Color::Black); + intro.setFillColor(sf::Color::White); + + sf::Text outro("Unfortunately, this was the last level.\n\n Hit [Space] to restart the game\n or use [Esc] to quit the game.", font, 16); + outro.setPosition(8, 8); + outro.setOutlineThickness(1); + outro.setOutlineColor(sf::Color::Black); + outro.setFillColor(sf::Color::White); + + sf::Text caption("Level 1", font, 16); + caption.setPosition(8, 8); + caption.setOutlineThickness(1); + caption.setOutlineColor(sf::Color::Black); + caption.setFillColor(sf::Color::White); + + float fading = 0; + + while (mWindow.isOpen()) { + sf::Event event; + while (mWindow.pollEvent(event)) { + switch (event.type) { + case sf::Event::Closed: + mWindow.close(); + break; + case sf::Event::KeyPressed: + switch (event.key.code) { + case sf::Keyboard::Return: + if (event.key.alt) { + mFullscreen = !mFullscreen; + if (mFullscreen) { + sf::VideoMode vm(sf::VideoMode::getDesktopMode()); + mWindow.create(vm, "A-Maze Batz – a GMTK Game Jam 2018 entry", sf::Style::Close | sf::Style::Fullscreen); + mWindow.setMouseCursorVisible(false); + + const float ar = static_cast(vm.width) / static_cast(vm.height); + const float tar = 16.f / 9.f; + + if (ar < tar) + sview.setViewport({ 0, .5f - ar / tar / 2.f, 1, ar / tar }); + else + sview.setViewport({ .5f - tar / ar / 2.f, 0, tar / ar, 1 }); + } + else { + mWindow.create({ 512, 288 }, "A-Maze Batz – a GMTK Game Jam 2018 entry", sf::Style::Close | sf::Style::Titlebar); + mWindow.setMouseCursorVisible(true); + sview.setViewport({ 0, 0, 1, 1 }); + } + } + break; + case sf::Keyboard::Space: + if (fading < 1) { + + } + if (mIntro) { + mIntro = false; + mLevelTimer.restart(); + break; + } + else if (mEnd) { + mIntro = true; + resetLevel(); + caption.setString("Level " + std::to_string(mLevelNumber)); + break; + } + if (mSonarTimer.getElapsedTime() < sf::seconds(.5f)) + break; + mSonarTimer.restart(); + ping(mPlayer.getPosition(), 0, 2 * PI, 32, sf::Color::White); + ping0.play(); + break; + case sf::Keyboard::A: + case sf::Keyboard::Left: + movement |= Left; + dir = Left; + lastLeft = true; + break; + case sf::Keyboard::D: + case sf::Keyboard::Right: + movement |= Right; + dir = Right; + lastLeft = false; + break; + case sf::Keyboard::W: + case sf::Keyboard::Up: + movement |= Up; + dir = Up; + break; + case sf::Keyboard::S: + case sf::Keyboard::Down: + movement |= Down; + dir = Down; + break; + case sf::Keyboard::Escape: + mWindow.close(); + break; + } + break; + case sf::Event::KeyReleased: + switch (event.key.code) { + case sf::Keyboard::A: + case sf::Keyboard::Left: + movement &= ~Left; + break; + case sf::Keyboard::D: + case sf::Keyboard::Right: + movement &= ~Right; + break; + case sf::Keyboard::W: + case sf::Keyboard::Up: + movement &= ~Up; + break; + case sf::Keyboard::S: + case sf::Keyboard::Down: + movement &= ~Down; + break; + } + break; + } + } + + if (mIntro || mEnd) + fading = 0; + else if (mWon) + fading = std::max(0.f, 1.f - mLevelTimer.getElapsedTime() / sf::seconds(1)); + else + fading = mLevelTimer.getElapsedTime() / sf::seconds(1); + + if (mWon && !mEnd && mLevelTimer.getElapsedTime() > sf::seconds(1)) { + mEnd = !resetLevel(mLevelNumber + 1); + caption.setString("Level " + std::to_string(mLevelNumber)); + if (!mEnd) { + mLevelTimer.restart(); + } + } + + + elapsed += timer.restart(); + + long ticks = 0; + while (elapsed > frameTime) { + elapsed -= frameTime; + ++tick; + + if (++ticks == 10 || mIntro || mEnd || mWon) { // max 10 updates between draws + elapsed = sf::Time::Zero; + break; + } + const sf::Vector2f pos(mPlayer.getPosition()); + + if (!mWon && !mIntro) { + if (movement & Left && !solid(pos - sf::Vector2f(5, 0))) { + mPlayer.move(-1, 0); + } + if (movement & Right && !solid(pos + sf::Vector2f(5, 0))) { + mPlayer.move(1, 0); + } + if (movement & Up && !solid(pos - sf::Vector2f(0, 5))) { + mPlayer.move(0, -1); + } + if (movement & Down && !solid(pos + sf::Vector2f(0, 5))) { + mPlayer.move(0, 1); + } + } + + if (tick % 50 == 0) { + ping(*(mDroppers.begin() + (rand() % mDroppers.size())), .5f * PI, .5f * PI, 1, sf::Color::Cyan, .5f); + } + + unsigned char ga = mGoal.getColor().a; + const sf::FloatRect gr = mGoal.getGlobalBounds(); + for (int i = 0; i < 2; ++i) { + for (auto &ping : mSonar) { + if (ping.texCoords.x != 0 || ping.texCoords.y != 0) { + if (solid(ping.position + ping.texCoords)) { + if (ping.color.a > 64) { + if (ping.color.r == 0 && ping.color.g == 255 && ping.color.b == 255) // Water drops + drop.play(); + } + + ping.color.a /= 2; + if (ping.color.a > 64) { + this->ping(ping.position, 0, 2 * PI, 32, ping.color); + if (ping.color.r == 255 && ping.color.g == 255 && ping.color.b == 255) + ping0e.play(); + else if (ping.color.r == 0 && ping.color.g == 255 && ping.color.b == 255) + drope.play(); + else + ping1e.play(); + } + ping.position += ping.texCoords; + ping.texCoords = { 0, 0 }; + } + else + ping.position += ping.texCoords; + } + ping.color.a -= 1; + if (gr.contains(ping.position) && ping.color.r == 255 && ping.color.g == 255 && ping.color.b == 255) { + ga = static_cast(std::min(255, ga + ping.color.a / 64)); + if (mGoalSonarTimer.getElapsedTime() > sf::seconds(.5f) && ping.color.a > 128) { + mGoalSonarTimer.restart(); + this->ping(mGoal.getPosition(), 0, 2 * PI, 32, { 255, 192, 192, 127 }, .5f); + ping1.play(); + } + } + } + mSonar.erase(std::remove_if(mSonar.begin(), mSonar.end(), [](const sf::Vertex &ping) { return ping.color.a == 0; }), mSonar.end()); + } + + if (mWon) { + + } + else { + + if (ga > 4) + ga -= 4; + else + ga = 0; + + if (ga > 192 && gr.intersects(mPlayer.getGlobalBounds())) { + // Win! + mWon = true; + mGoal.setColor(sf::Color::White); + mLevelTimer.restart(); + } + + mGoal.setColor({ 255, 255, 255, ga }); + } + } + + mPlayer.setTextureRect({ movement & Up ? 64 : (lastLeft ? 0 : 32), 16 * std::abs(-2 + ((tick >> 3) % 6)), 32, 16 }); + mGoal.setTextureRect({ 0, 16 * std::abs(-2 + (((tick >> 3) + 4) % 6)), 32, 16 }); + view.setCenter(mPlayer.getPosition()); + + mScreen.setView(view); + mScreen.clear(); + + mScreen.draw(mGoal); + mScreen.draw(mSonar.data(), mSonar.size(), sf::Points); + mScreen.draw(mPlayer); + + view.setCenter(view.getSize() / 2.f); + mScreen.setView(view); + + if (!mWon) { + if (fading < 2) { + const sf::Uint8 a = static_cast(255 * std::max(0.f, 2.f - fading) / 2.f); + caption.setFillColor({ 255, 255, 255, a }); + caption.setOutlineColor({ 0, 0, 0, a }); + mScreen.draw(caption); + } + } + + if (fading < 1) { + white.setFillColor({ 255, 255, 255, static_cast(255 * (1.f - fading)) }); + mScreen.draw(white); + } + + if (mIntro) + mScreen.draw(intro); + else if (mEnd) + mScreen.draw(outro); + + mScreen.display(); + + mWindow.setView(view); + mWindow.clear(); + mWindow.setView(sview); + mWindow.draw(mShow); + mWindow.display(); + } + return 0; +} + +void Game::ping(const sf::Vector2f &pos, const float from, const float to, const unsigned char count, const sf::Color &color, const float speed) { + /*switch (dir) { + case None: + from = 0; + to = 2 * PI; + break; + case Up: + from = PI; + to = 2 * PI; + break; + case Down: + from = 0; + to = PI; + break; + case Left: + from = .5f * PI; + to = 1.5f * PI; + break; + case Right: + from = -.5f * PI; + to = .5f * PI; + break; + }*/ + + //for (float a = from; a <= to; a += 2.f * PI / count) { + for (unsigned int i = 0; i < count; ++i) { + const float a = from + i * (to - from) / count; + mSonar.push_back({ pos, color, {speed * cos(a), speed * sin(a)} }); + } +} + +bool Game::solid(const sf::Vector2f &pos) const { + if (pos.x < 0 || pos.x >= mWidth || pos.y < 0 || pos.y >= mHeight) + return true; + return mLevel.getPixel(static_cast(pos.x), static_cast(pos.y)) == sf::Color::Black; +} + +bool Game::resetLevel(unsigned int newLevel) { + const std::string file(std::string("assets/levels/level") + std::to_string(newLevel) + ".png"); + if (!mLevel.loadFromFile(file)) { + mEnd = true; + return false; + } + + mLevelNumber = newLevel; + mWon = false; + mEnd = false; + const sf::Vector2i size(mLevel.getSize()); + mWidth = size.x; + mHeight = size.y; + + std::vector starts; + std::vector goals; + for (std::size_t y = 0; y < mHeight; ++y) + for (std::size_t x = 0; x < mWidth; ++x) { + sf::Color pixel = mLevel.getPixel(x, y); + if (pixel == sf::Color(255, 0, 0, 255)) { // goal + goals.push_back({ static_cast(x), static_cast(y) }); + } + else if (pixel == sf::Color(0, 255, 0, 255)) { // start + starts.push_back({ static_cast(x), static_cast(y) }); + } + else if (pixel == sf::Color(0, 0, 255, 255)) { // water dripping + mDroppers.push_back({ static_cast(x), static_cast(y) }); + } + } + + if (starts.empty()) + throw Exception("The level doesn't contain valid start pixels"); + if (goals.empty()) + throw Exception("The level doesn't contain valid goal pixels"); + + mGoal.setPosition(*(goals.begin() + (rand() % goals.size()))); + mPlayer.setPosition(*(starts.begin() + (rand() % starts.size()))); + + mLevelTimer.restart(); + mSonarTimer.restart(); + mSonar.clear(); + return true; +} diff --git a/source/game.hpp b/source/game.hpp new file mode 100644 index 0000000..7505b6b --- /dev/null +++ b/source/game.hpp @@ -0,0 +1,70 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +constexpr float PI = 3.1415f; + +enum Direction { + None = 0, + Left = 1, + Right = 2, + Up = 4, + Down = 8 +}; + +class Exception : public std::exception { +public: + Exception(const std::string &what) : mWhat(what) { } + const char *what() const noexcept { return mWhat.c_str(); } +private: + std::string mWhat; +}; + +class Game { +public: + Game(); + ~Game(); + int run(); +private: + sf::RenderWindow mWindow; + std::vector mSonar; + std::vector mDroppers; + sf::Sprite mPlayer; + sf::Sprite mGoal; + sf::Clock mSonarTimer; + sf::Clock mGoalSonarTimer; + sf::Image mLevel; + std::size_t mLevelNumber = 0; + std::size_t mWidth; + std::size_t mHeight; + bool mWon = false; + bool mIntro = true; + bool mEnd = false; + bool mFullscreen = false; + sf::Clock mLevelTimer; + + template T& get(const std::string &file) const { + static std::map> mCache; + auto &entry = mCache[file]; + if (!entry) { + entry.reset(new T()); + if (!entry->loadFromFile(file)) + throw Exception("Failed to load file '" + file + "'!"); + } + return *entry; + } + + void ping(const sf::Vector2f &pos, const float from, const float to, const unsigned char count, const sf::Color &color, const float speed = 1.f); + bool solid(const sf::Vector2f &pos) const; + bool resetLevel(unsigned int newLevel = 1); +}; diff --git a/source/icon.cpp b/source/icon.cpp new file mode 100644 index 0000000..dab5004 --- /dev/null +++ b/source/icon.cpp @@ -0,0 +1,192 @@ +const char *iconData = "\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377" + "\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377" + "\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377" + "\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000" + "\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377" + "\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377" + "\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377" + "\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000" + "\377\377\377\000\377\377\377\000\377\377\377\000\000\000\000\377\000\000\000\377\377\377\377" + "\000\377\377\377\000\000\000\000\377\000\000\000\377\377\377\377\000\377\377\377\000\377\377" + "\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377" + "\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000" + "\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377" + "\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377" + "\377\000\377\377\377\000\000\000\000\377\377\377\377\377\377\377\377\377\000\000\000\377" + "\000\000\000\377\377\377\377\377\377\000\000\377\000\000\000\377\377\377\377\000\377\377\377" + "\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000" + "\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377" + "\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377" + "\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377" + "\000\377\377\377\000\000\000\000\377\377\377\377\377\377\000\000\377\377\000\000\377\377\377" + "\377\377\377\000\000\377\177\000\000\377\000\000\000\377\377\377\377\000\377\377\377\000\377" + "\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377" + "\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377" + "\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000" + "\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377" + "\377\377\000\000\000\000\377\377\377\377\377\377\000\000\377\377\000\000\377\377\000\000\377" + "\377\000\000\377\177\000\000\377\000\000\000\377\377\377\377\000\377\377\377\000\377\377\377" + "\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000" + "\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377" + "\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377" + "\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377" + "\000\377\377\377\000\000\000\000\377\377\000\000\377\377\000\000\377\377\000\000\377\177\000\000\377" + "\000\000\000\377\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377" + "\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377" + "\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000" + "\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377" + "\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377" + "\377\000\377\377\377\000\000\000\000\377\377\000\000\377\177\000\000\377\000\000\000\377\377\377" + "\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377" + "\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000" + "\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377" + "\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377" + "\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377" + "\000\377\377\377\000\377\377\377\000\000\000\000\377\000\000\000\377\377\377\377\000\377\377" + "\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377" + "\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000" + "\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377" + "\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377" + "\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377" + "\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000" + "\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377" + "\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377" + "\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377" + "\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000" + "\377\377\377\000\377\377\377\000\377\377\377\000\000\000\000\377\000\000\000\377\000\000\000\377" + "\000\000\000\377\000\000\000\377\377\377\377\000\377\377\377\000\000\000\000\377\000\000\000\377\000\000" + "\000\377\000\000\000\377\000\000\000\377\377\377\377\000\377\377\377\000\377\377\377\000\377" + "\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377" + "\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377" + "\000\377\377\377\000\377\377\377\000\377\377\377\000\000\000\000\377\000\000\000\377\000\000\000\377" + "\240\240\240\377\000\000\000\377\377\377\377\000\377\377\377\000\377\377\377\000\377" + "\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\000\000\000" + "\377\240\240\240\377\000\000\000\377\000\000\000\377\000\000\000\377\377\377\377\000\377\377" + "\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377" + "\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000" + "\000\000\000\377\000\000\000\377\240\240\240\377\240\240\240\377\240\240\240\377\300" + "\300\300\377\240\240\240\377\000\000\000\377\377\377\377\000\377\377\377\000\377\377" + "\377\000\377\377\377\000\377\377\377\000\377\377\377\000\000\000\000\377\240\240\240\377" + "\300\300\300\377\240\240\240\377\240\240\240\377\240\240\240\377\000\000\000\377" + "\000\000\000\377\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377" + "\377\000\377\377\377\000\377\377\377\000\377\377\377\000\000\000\000\377\000\000\000\377\240" + "\240\240\377\240\240\240\377\300\300\300\377\300\300\300\377\240\240\240" + "\377\377\377\377\377\300\300\300\377\240\240\240\377\000\000\000\377\377\377\377" + "\000\377\377\377\000\377\377\377\000\377\377\377\000\000\000\000\377\240\240\240\377\300" + "\300\300\377\377\377\377\377\240\240\240\377\300\300\300\377\300\300\300" + "\377\240\240\240\377\240\240\240\377\000\000\000\377\000\000\000\377\377\377\377\000\377" + "\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\000\000\000\377\240\240\240" + "\377\240\240\240\377\300\300\300\377\300\300\300\377\377\377\377\377\240" + "\240\240\377\377\377\377\377\377\377\377\377\240\240\240\377\300\300\300" + "\377\240\240\240\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\240\240\240" + "\377\300\300\300\377\240\240\240\377\377\377\377\377\377\377\377\377\240" + "\240\240\377\377\377\377\377\300\300\300\377\300\300\300\377\240\240\240" + "\377\240\240\240\377\000\000\000\377\377\377\377\000\377\377\377\000\377\377\377\000" + "\000\000\000\377\240\240\240\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\240\240" + "\240\377\377\377\377\377\377\377\377\377\377\377\377\377\240\240\240\377" + "\377\377\377\377\000\000\000\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\000\000\000\377\377\377\377\377\240\240\240\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\240\240\240\377\000\000\000\377\000\000\000\377\000\000" + "\000\377\000\000\000\377\240\240\240\377\000\000\000\377\377\377\377\000\377\377\377\000\000" + "\000\000\377\000\000\000\377\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377" + "\000\000\000\000\377\000\000\000\377\377\377\377\377\240\240\240\377\377\377\377\377\000" + "\000\000\377\377\377\377\377\000\000\000\377\240\240\240\377\000\000\000\377\377\377\377" + "\377\240\240\240\377\000\000\000\377\377\377\377\377\240\240\240\377\377\377\377" + "\377\000\000\000\377\000\000\000\377\377\377\377\000\377\377\377\000\377\377\377\000\377\377" + "\377\000\000\000\000\377\000\000\000\377\377\377\377\000\377\377\377\000\000\000\000\377\377\377" + "\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377" + "\000\377\377\377\000\000\000\000\377\377\377\377\377\377\377\377\377\000\000\000\377\377" + "\377\377\377\000\000\000\377\300\300\300\377\000\000\000\377\300\300\300\377\240\240" + "\240\377\000\000\000\377\377\377\377\377\377\377\377\377\000\000\000\377\377\377\377" + "\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000" + "\377\377\377\000\000\000\000\377\377\377\377\000\377\377\377\000\377\377\377\000\377\377" + "\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377" + "\000\377\377\377\000\377\377\377\000\000\000\000\377\000\000\000\377\000\000\000\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\300\300\300\377\240" + "\240\240\377\000\000\000\377\000\000\000\377\000\000\000\377\377\377\377\000\377\377\377\000\377" + "\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377" + "\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377" + "\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000" + "\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\000\000\000\377\377\377" + "\377\377\300\300\300\377\300\300\300\377\300\300\300\377\240\240\240\377" + "\240\240\240\377\000\000\000\377\377\377\377\000\377\377\377\000\377\377\377\000\377" + "\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377" + "\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377" + "\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000" + "\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377" + "\377\377\000\000\000\000\377\240\240\240\377\240\240\240\377\240\240\240\377\240" + "\240\240\377\000\000\000\377\377\377\377\000\377\377\377\000\377\377\377\000\377\377" + "\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377" + "\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000" + "\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377" + "\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377" + "\377\000\377\377\377\000\377\377\377\000\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377" + "\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377" + "\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377" + "\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377" + "\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000" + "\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377" + "\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377" + "\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377" + "\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000" + "\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377" + "\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377" + "\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377" + "\000\377\377\377\000\377\377\377\000\377\377\377\000\000\000\000\377\000\000\000\377\377\377" + "\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377" + "\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000" + "\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377" + "\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377" + "\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\000\000\000\377" + "\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377" + "\377\377\000\377\377\377\000\377\377\377\000\000\000\000\377\377\377\377\000\377\377\377" + "\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000" + "\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377" + "\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377" + "\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377" + "\000\000\000\000\377\000\000\000\377\377\377\377\000\377\377\377\000\377\377\377\000\377\377" + "\377\000\000\000\000\377\000\000\000\377\377\377\377\000\377\377\377\000\377\377\377\000\377" + "\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377" + "\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377" + "\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000" + "\377\377\377\000\000\000\000\377\377\377\377\000\377\377\377\000\377\377\377\000\377\377" + "\377\000\377\377\377\000\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\377\377\377" + "\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\000\000\000\377\377" + "\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377" + "\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377" + "\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000" + "\377\377\377\000\000\000\000\377\000\000\000\377\377\377\377\000\377\377\377\000\377\377\377" + "\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000" + "\377\377\377\000\377\377\377\000\000\000\000\377\000\000\000\377\377\377\377\000\377\377\377" + "\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000" + "\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377" + "\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377" + "\377\000\377\377\377\000\377\377\377\000\000\000\000\377\000\000\000\377\000\000\000\377\377\377" + "\377\000\377\377\377\000\377\377\377\000\377\377\377\000\000\000\000\377\000\000\000\377\000\000" + "\000\377\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377" + "\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000" + "\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377" + "\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377" + "\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\000\000\000\377" + "\000\000\000\377\000\000\000\377\000\000\000\377\377\377\377\000\377\377\377\000\377\377\377\000" + "\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377" + "\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377" + "\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377" + "\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000" + "\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377" + "\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377" + "\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377" + "\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000" + "\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377" + "\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377" + "\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377" + "\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000" + "\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377" + "\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377" + "\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377" + "\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000" + "\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377" + "\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377" + "\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377" + "\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000\377\377\377\000" + "\377\377\377\000\377\377\377\000"; diff --git a/source/icon.ico b/source/icon.ico new file mode 100644 index 0000000..6cc70ee Binary files /dev/null and b/source/icon.ico differ diff --git a/source/main.cpp b/source/main.cpp new file mode 100644 index 0000000..99a6aa0 --- /dev/null +++ b/source/main.cpp @@ -0,0 +1,27 @@ +#include "game.hpp" +#include +#ifdef WIN32 +#define WIN32_EXTRA_LEAN +#include +#else +#include +#endif + +int main(int argc, char **argv) { +#ifdef NDEBUG + try { +#endif + Game game; + return game.run(); +#ifdef NDEBUG + } + catch (const Exception &exception) { +#ifdef WIN32 + MessageBoxA(0, exception.what(), "An unhandled exception appeared in A-Maze Batz!", MB_ICONSTOP | MB_OK); +#else + std::cerr << "An unhandled exception appeared in A-Maze Batz!\n\nException: " << exception.what() << std::endl; +#endif + return 1; + } +#endif +} diff --git a/source/resources.rc b/source/resources.rc new file mode 100644 index 0000000..1c302d4 --- /dev/null +++ b/source/resources.rc @@ -0,0 +1 @@ +100 ICON "icon.ico" \ No newline at end of file