#define _USE_MATH_DEFINES #include #include #include #include #include #include #include #include #include #include #include #include "sfmlbackend.hpp" #include #include using namespace fmt; using namespace nlohmann; using std::string; 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 }; void SoundQuip::load(json &data, const char *file_key, bool loop) { auto audio = data["audio"]; json::string_t file_name = audio[file_key].template get(); if(!buffer.loadFromFile(file_name)) { println("Failed to load sound: {} with file {}", file_key, file_name); } sound.setBuffer(buffer); sound.setLoop(loop); } void SoundQuip::play() { sound.play(); } void SoundQuip::stop() { sound.stop(); } void SFMLBackend::Window_update() { window.display(); } sf::Color SFMLBackend::value(Value level) { return VALUES.at(int(level)); } void SFMLBackend::handle_events() { sf::Event event; // is this a main event loop while (window.pollEvent(event)) { switch(event.type) { case sf::Event::Closed: fmt::print("Exiting...\n"); window.close(); break; case sf::Event::KeyPressed: if(sf::Keyboard::isKeyPressed(sf::Keyboard::Escape)) { window.close(); } else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Space)) { fmt::println("STOP THE CLOCK"); } break; case sf::Event::MouseButtonPressed: { // rect::contains(x,y) for if mouse is in the button rect sf::Event::MouseButtonEvent btn = event.mouseButton; fmt::println("BUTTON: X={}, Y={}", btn.x, btn.y); break; } default: // do nothing break; } } } sf::Vector2f translate(int x, int y) { float step_x = X_DIM / TEXT_SIZE; float step_y = (Y_DIM - 12) / TEXT_SIZE; sf::Vector2f position{step_x * x, step_y * y * 2}; return position; } void SFMLBackend::write_text(int x, int y, string content, float size_mult, Value color) { sf::Vector2f position = translate(x,y); sf::Text text; text.setFont(font); text.setString(content); text.setCharacterSize(TEXT_SIZE * size_mult); text.setFillColor(value(color)); text.setPosition(position); window.draw(text); } sf::RectangleShape SFMLBackend::box(int x, int y, int width, int height, Value fill, Value outline, int thickness) { sf::RectangleShape box(translate(width, height)); box.setPosition(translate(x,y)); box.setOutlineColor(value(outline)); box.setOutlineThickness(thickness); box.setFillColor(value(fill)); window.draw(box); return box; } void SFMLBackend::update_entities() { window.clear(); sf::RectangleShape face_box = box(2, 2, X_ROWS/4, Y_LINES/2, Value::DARK_DARK); face_sprite.setPosition(translate(2,2)); window.draw(face_sprite); sf::RectangleShape stats_box = box(X_ROWS/4 + 4, 2, X_ROWS - X_ROWS/4 - 5, Y_LINES/2, Value::DARK_DARK); constexpr int hp_box_len = 45; int current_hp = (float(game.hit_points) / float(game.starting_hp)) * float(hp_box_len); sf::RectangleShape hp_bar = box(2, 21, current_hp, 2, Value::LIGHT_MID, Value::LIGHT_MID, 0); sf::RectangleShape hp_box = box(2, 21, hp_box_len, 2, Value::TRANSPARENT); string status = fmt::format("HP {}\nRounds {}\nStreaks {}\nDeaths {}", game.hit_points, game.rounds, game.streak, game.deaths); write_text(X_ROWS/4 + 5, 2, status); std::chrono::time_point now = std::chrono::system_clock::now(); string time = fmt::format("{:%r}", now); write_text(2, 14, time, 2.0f); sf::RectangleShape start_btn = box(27, 16, 8, 3, Value::DARK_MID); write_text(29, 16, "START", 1.0f); sf::RectangleShape done_btn = box(37, 16, 8, 3, Value::DARK_MID); write_text(39, 16, "DONE", 1.0f); Window_update(); } void SFMLBackend::change_face(const string name) { std::ifstream infile(".tarpit.json"); json data = json::parse(infile); auto images = data["images"]; json::string_t file_name = images[name].template get(); face_texture.loadFromFile(file_name); face_sprite.setTexture(face_texture); } SFMLBackend::SFMLBackend(GameEngine &g) : window(sf::VideoMode(X_DIM, Y_DIM), "Turing's Tarpit", sf::Style::None, settings), game(g) { change_face("building"); } /* * This makes my soul hurt. Make it stop. * * TODO: Make this more efficient, and don't display * more than 10 or so errors since more than that is * not very useful. */ void SFMLBackend::update_log(std::vector &lines) { log.clear(); for(string &line : lines) { log.push_back(line); } } void SFMLBackend::startup() { fmt::print("Setting up a window for you...\n"); settings.antialiasingLevel = 8; if(!font.loadFromFile("./assets/text.ttf")) { fmt::println("Cannot load font."); } window.setPosition({.x=0,.y=0}); window.setFramerateLimit(FPS); window.setVerticalSyncEnabled(true); } bool SFMLBackend::is_open() { return window.isOpen(); } void SFMLBackend::shutdown() { }