diff --git a/.tarpit.json b/.tarpit.json new file mode 100644 index 0000000..952f4a2 --- /dev/null +++ b/.tarpit.json @@ -0,0 +1,17 @@ +{ + "audio": { + "you_died": "./assets/you_died.mp3", + "build_success": "", + "build_failed": "./assets/build_failed.mp3", + "building": "./mysounds/building.mp3" + }, + "images": { + "build_success": "./assets/build_success.png", + "you_died": "./assets/you_died.png", + "build_failed": "./assets/build_failed.png", + "building": "./assets/building.png" + }, + "git_path": ".\\", + "build_cmd": "meson compile -C builddir", + "test_cmd": "./builddir/runtests.exe" +} diff --git a/.vimrc_proj b/.vimrc_proj new file mode 100644 index 0000000..d58d328 --- /dev/null +++ b/.vimrc_proj @@ -0,0 +1 @@ +set makeprg=meson\ compile\ -j\ 4\ -C\ . diff --git a/assets/hit.wav b/assets/hit.wav new file mode 100644 index 0000000..e64c544 Binary files /dev/null and b/assets/hit.wav differ diff --git a/assets/text.ttf b/assets/text.ttf new file mode 100644 index 0000000..3094772 Binary files /dev/null and b/assets/text.ttf differ diff --git a/fsm.hpp b/fsm.hpp index 5898ea4..d42dfbe 100644 --- a/fsm.hpp +++ b/fsm.hpp @@ -12,7 +12,7 @@ template class DeadSimpleFSM { protected: // BUG: don't put this in your class because state() won't work - S _state = S::START; + S _state = S::START; public: template diff --git a/main.cpp b/main.cpp index 83a80dd..0862174 100644 --- a/main.cpp +++ b/main.cpp @@ -3,6 +3,9 @@ // the LICENSE file. #include // for operator""s, chrono_literals #include // for cout, ostream +#include +#include +#include #include // for allocator, shared_ptr #include // for string, operator<< #include // for sleep_for @@ -14,8 +17,15 @@ #include #include #include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive +#include +#include +#include +#include +#include +#include #include +#include "fsm.hpp" #include "map.hpp" #include "dbc.hpp" @@ -23,42 +33,128 @@ using std::string; using namespace fmt; using namespace std::chrono_literals; +enum class Value { + BLACK=0, DARK_DARK, DARK_MID, + DARK_LIGHT, MID, LIGHT_DARK, LIGHT_MID, + LIGHT_LIGHT, WHITE, TRANSPARENT +}; + +std::array VALUES{ + sf::Color{1, 4, 2}, // black + sf::Color{9, 29, 16}, // dark dark + sf::Color{14, 50, 26}, // dark mid + sf::Color{0, 109, 44}, // dark light + sf::Color{63, 171, 92}, // mid + sf::Color{161, 217, 155}, // light dark + sf::Color{199, 233, 192}, // light mid + sf::Color{229, 245, 224}, // light light + sf::Color{255, 255, 255}, // white + sf::Color::Transparent, // white +}; + +enum class EntityState { + START, HUNTING, DEAD +}; + +enum class EntityEvent { + GO, HIT +}; + + +class Entity : public DeadSimpleFSM { +public: + Point location; + int hp = 20; + int damage = 10; + + Entity(Point loc) : location(loc) { + }; + + // disable copy + Entity(Entity &e) = delete; + + void move(Point loc) { + location = loc; + } + + void event(EntityEvent ev) { + switch(_state) { + FSM_STATE(EntityState, START, ev); + FSM_STATE(EntityState, HUNTING, ev); + FSM_STATE(EntityState, DEAD, ev); + } + } + + void START(EntityEvent ev) { + state(EntityState::HUNTING); + } + + void HUNTING(EntityEvent ev) { + switch(ev) { + case EntityEvent::HIT: + hp -= damage; + break; + default: + state(EntityState::HUNTING); + } + + if(hp <= 0) { + state(EntityState::DEAD); + } else { + state(EntityState::HUNTING); + } +} + + void DEAD(EntityEvent ev) { + state(EntityState::DEAD); + } +}; + +sf::SoundBuffer g_hit_buf; +sf::Sound g_hit_sound; + int main() { using namespace ftxui; - std::string reset_position; + auto c = Canvas(60 * 2, 20 * 4); - auto c = Canvas(60 * 2, 27 * 4); + int res = g_hit_buf.loadFromFile("./hit.wav"); + dbc::check(res, "faile to load hit.wav"); + g_hit_sound.setBuffer(g_hit_buf); - Map game_map(50, 27); + Map game_map(50, 20); game_map.generate(); Matrix &walls = game_map.walls(); Room &start = game_map.room(0); Room &bad_room = game_map.room(1); Room &gold_room = game_map.room(game_map.room_count() - 1); - Point me = {.x=start.x+1, .y=start.y+1}; - Point enemy = {.x=bad_room.x+1, .y=bad_room.y+1}; - Point goal = {.x=gold_room.x+1, .y=gold_room.y+1}; - string dead_yet = "NOT DEAD"; + Entity me({.x=start.x+1, .y=start.y+1}); + Entity enemy({.x=bad_room.x+1, .y=bad_room.y+1}); + Point goal{.x=gold_room.x+1, .y=gold_room.y+1}; + string status_text = "NOT DEAD"; bool show_paths = false; bool bomb = false; auto map = Renderer([&] { - game_map.set_target(me); + game_map.set_target(me.location); game_map.make_paths(); Matrix &paths = game_map.paths(); + if(me.in_state(EntityState::DEAD)) { + status_text = "DEAD!"; + } + for(size_t x = 0; x < walls[0].size(); ++x) { for(size_t y = 0; y < walls.size(); ++y) { string tile = walls[y][x] == 1 ? "#" : format("{}", paths[y][x]); if(tile == "#") { - c.DrawText(x*2, y*4, tile, Color::GrayDark); + c.DrawText(x*2, y*4, tile); } else if(show_paths) { - int pnum = paths[y][x]; - c.DrawText(x*2, y*4, tile, Color::Palette16(pnum % 7 + 1)); + //int pnum = paths[y][x]; + c.DrawText(x*2, y*4, tile); } else { - c.DrawText(x*2, y*4, ".", Color::GrayDark); + c.DrawText(x*2, y*4, "."); } } } @@ -66,12 +162,12 @@ int main() { if(bomb) { /// draw bomb = false; - c.DrawPointCircle(me.x*2, me.y*4, 4, Color::Red); + c.DrawPointCircle(me.location.x*2, me.location.y*4, 4); } - c.DrawText(enemy.x*2, enemy.y*4, "!", Color::Red); - c.DrawText(me.x*2, me.y*4, "@", Color::Blue); - c.DrawText(goal.x*2, goal.y*4, "$", Color::Yellow); + c.DrawText(enemy.location.x*2, enemy.location.y*4, "!"); + c.DrawText(me.location.x*2, me.location.y*4, "@"); + c.DrawText(goal.x*2, goal.y*4, "$"); return canvas(c); }); @@ -80,56 +176,76 @@ int main() { return hbox({ hflow( vbox( - gauge(0.5) | border, - text(dead_yet) | border + text(format("HP: {}", me.hp)) | border, + text(status_text) | border ) | xflex_grow ), separator(), hbox(map->Render()), - }) | border; + }); }); - document |= CatchEvent([&](Event e) -> bool { - size_t x = me.x; - size_t y = me.y; - - if(e == Event::ArrowLeft) { - x -= 1; - } else if(e == Event::ArrowRight) { - x += 1; - } else if(e == Event::ArrowDown) { - y += 1; - } else if(e == Event::ArrowUp) { - y -= 1; - } else if(e == Event::Backspace) { - bomb = true; - } else { - return false; - } + auto screen = Screen::Create(Dimension::Full()); + + sf::RenderWindow window(sf::VideoMode(1600,900), "Roguish"); + + sf::Font font; + font.loadFromFile("./unifont-16.0.01.otf"); + sf::Text text; + text.setFont(font); + text.setCharacterSize(30); + text.setFillColor(VALUES[size_t(Value::LIGHT_LIGHT)]); + + while(window.isOpen()) { + Render(screen, document->Render()); + std::string screen_out = screen.ToString(); + std::wstring_convert> converter; + std::wstring utf8 = converter.from_bytes(screen_out); + + text.setString(utf8); + text.setPosition({0,0}); + window.clear(); + window.draw(text); + window.display(); + + sf::Event event; + while(window.pollEvent(event)) { + if(event.type == sf::Event::Closed) { + window.close(); + } else if(event.type == sf::Event::KeyPressed) { + size_t x = me.location.x; + size_t y = me.location.y; + + if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left)) { + x -= 1; + } else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right)) { + x += 1; + } else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up)) { + y -= 1; + } else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Down)) { + y += 1; + } - if(game_map.inmap(x,y) && !game_map.iswall(x,y)) { - game_map.clear_target(me); - me.x = x; - me.y = y; - } + if(game_map.inmap(x,y) && !game_map.iswall(x,y)) { + game_map.clear_target(me.location); + me.move({x, y}); + } else { + g_hit_sound.play(); + } - // move enemy here - bool found = game_map.neighbors(enemy, true); + // move enemy here + bool found = game_map.neighbors(enemy.location, true); + if(!found) { + status_text = "ENEMY STUCK!"; + } - if(enemy.x == me.x && enemy.y == me.y) { - dead_yet = "YOU DIED!"; - } else if(goal.x == me.x && goal.y == me.y) { - dead_yet = "YOU WIN!"; + if(enemy.location.x == me.location.x && enemy.location.y == me.location.y) { + me.event(EntityEvent::HIT); + } else if(goal.x == me.location.x && goal.y == me.location.y) { + status_text = "YOU WIN!"; + } } - - return true; - }); - - auto screen = ScreenInteractive::Fullscreen(); - Loop loop(&screen, document); - - while(!loop.HasQuitted()) { - loop.RunOnceBlocking(); + } } return 0; diff --git a/meson.build b/meson.build index 89deb62..b3f1723 100644 --- a/meson.build +++ b/meson.build @@ -7,10 +7,11 @@ json = dependency('nlohmann_json') ftxui_screen = dependency('ftxui-screen') ftxui_dom = dependency('ftxui-dom') ftxui_component = dependency('ftxui-component') +sfml = dependency('sfml') dependencies = [catch2, fmt, ftxui_screen, ftxui_dom, ftxui_component, - json] + json, sfml] runtests = executable('runtests', [ 'dbc.cpp', diff --git a/scripts/reset_build.ps1 b/scripts/reset_build.ps1 index 8e5818b..9b8c152 100644 --- a/scripts/reset_build.ps1 +++ b/scripts/reset_build.ps1 @@ -8,6 +8,13 @@ meson wrap install fmt meson wrap install catch2 meson wrap install ftxui meson wrap install nlohmann_json +meson wrap install libpng +meson wrap install vorbis +meson wrap install ogg +meson wrap install flac +meson wrap install freetype2 +meson wrap install openal-soft +meson wrap install sfml # $env:CC="clang" # $env:CXX="clang++" meson setup --default-library=static --prefer-static builddir diff --git a/scripts/reset_build.sh b/scripts/reset_build.sh index abaf744..e8c0b32 100644 --- a/scripts/reset_build.sh +++ b/scripts/reset_build.sh @@ -11,4 +11,12 @@ meson wrap install fmt meson wrap install catch2 meson wrap install ftxui meson wrap install nlohmann_json +meson wrap install sfml +meson wrap install libpng +meson wrap install vorbis +meson wrap install ogg +meson wrap install flac +meson wrap install freetype2 +meson wrap install openal-soft +meson wrap install sfml meson setup builddir diff --git a/status.txt b/status.txt index bd5a0a4..f145d8e 100644 --- a/status.txt +++ b/status.txt @@ -1,8 +1,5 @@ - - TODO: -* Create a map gen of some kind. -* Research how hard to create a non-terminal/graphic backend to FTXUI. -* Look into font rendering libraries. -* Lua integration +* Clean up the code to not be such a horrible hack mess. +* Figure out how to render color fonts from FTUI. +* Lua integration? diff --git a/tests/map.cpp b/tests/map.cpp index 41969a7..4f2674b 100644 --- a/tests/map.cpp +++ b/tests/map.cpp @@ -37,7 +37,5 @@ TEST_CASE("dijkstra algo test", "[map]") { TEST_CASE("bsp algo test", "[map]") { Map map(50, 20); - map.generate(); - map.dump(); }