#pragma once #include #include #include "app.h" #include "key_mapper.h" #include "key_value_store.h" #include "mines.h" #include "pong.h" #include "settings.h" #include "snake.h" #include "tetris.h" #include "tune.h" #include "twenty48.h" namespace roro { // The Games App (issue #101): three Games as a row of icons, and the one being played. The rules are in // lib/games; this draws them, gives them the keys and the time, beeps, and keeps the best of each. // A Game left in the middle, for the list or for another App, is found again paused. class GamesApp : public App { public: GamesApp(const KeyMapper& keys, const Settings& settings, KeyValueStore& store) : keys_(keys), settings_(settings), store_(store) {} void onEnter() override; void onExit() override; bool onKey(const KeyEvent& e) override; void update(uint32_t nowMs) override; void draw(Canvas& c) override; void help(std::vector& out) const override; const char* helpTitle() const override; // A Game being played is the device in use, key or no key: the screen stays lit. // Not for the two that wait for a move: there a key is pressed, or nobody is playing. bool keepsScreenOn() const override { return which_ <= Tetris && state_[which_] == State::Playing; } private: enum Which { Pong, Snake, Tetris, Mines, Twenty48, Menu }; // all but the last index the arrays static constexpr int kGames = 5; enum class State : uint8_t { Ready, Playing, Paused, Over }; void begin(); // a new game of the one chosen void pause(); void ended(int score); void beep(int hz, int ms); bool musicOn(); int volume(); // of the tune, 1 to kLoudest void setVolume(int level); void quiet(); // the tune stops where it is void loud(bool on); // the speaker turned up for the tune, or back as it was int best(Which w); bool pongKey(const KeyEvent& e); bool snakeKey(const KeyEvent& e); bool tetrisKey(const KeyEvent& e); bool minesKey(const KeyEvent& e); bool twenty48Key(const KeyEvent& e); void moveCursor(int dc, int dr); void drawMines(Canvas& c); void drawTwenty48(Canvas& c); void drawMenu(Canvas& c); void drawPong(Canvas& c); void drawSnake(Canvas& c); void drawTetris(Canvas& c); void drawBanner(Canvas& c, const std::string& title, const std::string& detail); const KeyMapper& keys_; const Settings& settings_; KeyValueStore& store_; int chosen_ = 0; // in the row of games Which which_ = Menu; State state_[kGames] = {State::Ready, State::Ready, State::Ready, State::Ready, State::Ready}; int best_[kGames] = {-1, -1, -1, -1, -1}; // -1: not read from the store yet bool newBest_ = false; std::unique_ptr pong_; std::unique_ptr snake_; std::unique_ptr tetris_; std::unique_ptr mines_; std::unique_ptr twenty48_; // Minesweeper's cursor, and the arrow held to run it along. int cursorCol_ = 0, cursorRow_ = 0, runDir_ = -1; uint32_t runMs_ = 0, shownSeconds_ = 0; bool running_ = false; uint32_t lastMs_ = 0, lastDrawMs_ = 0; // Keys that came as presses since the last step: a tap moves too, held or not. int tapMove_ = 0; uint32_t tapUntilMs_ = 0; games::TetrisInput tapped_; // Tetris's tune (Korobeiniki), switched with 0 and remembered. games::TunePlayer tune_{games::korobeiniki::at, games::korobeiniki::kCount, games::korobeiniki::kEighthMs}; int music_ = -1, volume_ = -1; // -1: not read from the store yet int masterWas_ = -1; // the speaker's own volume, while the tune has it turned up }; } // namespace roro