diff options
author | Matthew B. Jones <matthewbjones85@gmail.com> | 2021-06-03 01:43:28 -0600 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-06-03 08:43:28 +0100 |
commit | ecaae2d10f9a589977c84710f681247c6f4cb19a (patch) | |
tree | 0b7e84944d4a26522ab1a1519dec7c86edaeaa53 /Userland/Games/Solitaire | |
parent | e7cfa9bf8e115baeacf82aed93405c790073fd97 (diff) | |
download | serenity-ecaae2d10f9a589977c84710f681247c6f4cb19a.zip |
Solitaire: Add keys for drawing and moving cards to foundation stacks
Also shifts logic of starting game length timer into function
`start_timer_if_necessary`, so it can be called from original
mouse event handler and new `auto_move_eligible_cards_to_stacks`
Diffstat (limited to 'Userland/Games/Solitaire')
-rw-r--r-- | Userland/Games/Solitaire/Game.cpp | 207 | ||||
-rw-r--r-- | Userland/Games/Solitaire/Game.h | 4 |
2 files changed, 139 insertions, 72 deletions
diff --git a/Userland/Games/Solitaire/Game.cpp b/Userland/Games/Solitaire/Game.cpp index bf1b0c51f4..e17a3b25ce 100644 --- a/Userland/Games/Solitaire/Game.cpp +++ b/Userland/Games/Solitaire/Game.cpp @@ -131,6 +131,14 @@ void Game::setup(Mode mode) update(); } +void Game::start_timer_if_necessary() +{ + if (on_game_start && m_waiting_for_new_game) { + on_game_start(); + m_waiting_for_new_game = false; + } +} + void Game::score_move(CardStack& from, CardStack& to, bool inverse = false) { if (from.type() == CardStack::Type::Play && to.type() == CardStack::Type::Normal) { @@ -157,10 +165,16 @@ void Game::keydown_event(GUI::KeyEvent& event) if (m_new_game_animation || m_game_over_animation) return; - if (event.shift() && (event.key() == KeyCode::Key_F12)) + if (event.shift() && event.key() == KeyCode::Key_F12) { start_game_over_animation(); - else if (event.shift() && (event.key() == KeyCode::Key_F11)) + } else if (event.key() == KeyCode::Key_Tab) { + auto_move_eligible_cards_to_stacks(); + } else if (event.key() == KeyCode::Key_Space) { + draw_cards(); + invalidate_layout(); // FIXME: Stock stack won't render properly after draw_cards() without this + } else if (event.shift() && event.key() == KeyCode::Key_F11) { dump_layout(); + } } void Game::mousedown_event(GUI::MouseEvent& event) @@ -170,10 +184,7 @@ void Game::mousedown_event(GUI::MouseEvent& event) if (m_new_game_animation || m_game_over_animation) return; - if (on_game_start && m_waiting_for_new_game) { - on_game_start(); - m_waiting_for_new_game = false; - } + start_timer_if_necessary(); auto click_location = event.position(); for (auto& to_check : m_stacks) { @@ -182,66 +193,7 @@ void Game::mousedown_event(GUI::MouseEvent& event) if (to_check.bounding_box().contains(click_location)) { if (to_check.type() == CardStack::Type::Stock) { - auto& waste = stack(Waste); - auto& stock = stack(Stock); - auto& play = stack(Play); - - if (stock.is_empty()) { - if (waste.is_empty() && play.is_empty()) - return; - - update(waste.bounding_box()); - update(play.bounding_box()); - - while (!play.is_empty()) { - auto card = play.pop(); - stock.push(card); - } - - while (!waste.is_empty()) { - auto card = waste.pop(); - stock.push(card); - } - - if (m_passes_left_before_punishment == 0) - update_score(recycle_rules().punishment); - else - --m_passes_left_before_punishment; - - update(stock.bounding_box()); - } else { - auto play_bounding_box = play.bounding_box(); - play.move_to_stack(waste); - - size_t cards_to_draw = 0; - switch (m_mode) { - case Mode::SingleCardDraw: - cards_to_draw = 1; - break; - case Mode::ThreeCardDraw: - cards_to_draw = 3; - break; - default: - VERIFY_NOT_REACHED(); - break; - } - - update(stock.bounding_box()); - - NonnullRefPtrVector<Card> cards_drawn; - for (size_t i = 0; (i < cards_to_draw) && !stock.is_empty(); ++i) { - auto card = stock.pop(); - cards_drawn.prepend(card); - play.push(move(card)); - } - - remember_move_for_undo(stock, play, cards_drawn); - - if (play.bounding_box().size().width() > play_bounding_box.size().width()) - update(play.bounding_box()); - else - update(play_bounding_box); - } + draw_cards(); } else if (!to_check.is_empty()) { auto& top_card = to_check.peek(); @@ -289,12 +241,7 @@ void Game::mouseup_event(GUI::MouseEvent& event) remember_move_for_undo(*m_focused_stack, stack, m_focused_cards); if (m_focused_stack->type() == CardStack::Type::Play) { - auto& waste = this->stack(Waste); - if (m_focused_stack->is_empty() && !waste.is_empty()) { - auto card = waste.pop(); - m_focused_cards.prepend(card); - m_focused_stack->push(move(card)); - } + pop_waste_to_play_stack(); } update(m_focused_stack->bounding_box()); @@ -416,6 +363,122 @@ void Game::move_card(CardStack& from, CardStack& to) update(to.bounding_box()); } +void Game::draw_cards() +{ + auto& waste = stack(Waste); + auto& stock = stack(Stock); + auto& play = stack(Play); + + if (stock.is_empty()) { + if (waste.is_empty() && play.is_empty()) + return; + + update(waste.bounding_box()); + update(play.bounding_box()); + + while (!play.is_empty()) { + auto card = play.pop(); + stock.push(card); + } + + while (!waste.is_empty()) { + auto card = waste.pop(); + stock.push(card); + } + + if (m_passes_left_before_punishment == 0) + update_score(recycle_rules().punishment); + else + --m_passes_left_before_punishment; + + update(stock.bounding_box()); + } else { + auto play_bounding_box = play.bounding_box(); + play.move_to_stack(waste); + + size_t cards_to_draw = 0; + switch (m_mode) { + case Mode::SingleCardDraw: + cards_to_draw = 1; + break; + case Mode::ThreeCardDraw: + cards_to_draw = 3; + break; + default: + VERIFY_NOT_REACHED(); + break; + } + + update(stock.bounding_box()); + + for (size_t i = 0; (i < cards_to_draw) && !stock.is_empty(); ++i) { + auto card = stock.pop(); + play.push(move(card)); + } + + if (play.bounding_box().size().width() > play_bounding_box.size().width()) + update(play.bounding_box()); + else + update(play_bounding_box); + } +} + +void Game::pop_waste_to_play_stack() +{ + auto& waste = this->stack(Waste); + auto& play = this->stack(Play); + if (play.is_empty() && !waste.is_empty()) { + auto card = waste.pop(); + m_focused_cards.append(card); + play.push(move(card)); + } +} + +void Game::auto_move_eligible_cards_to_stacks() +{ + bool card_was_moved = false; + + for (auto& to_check : m_stacks) { + if (to_check.type() != CardStack::Type::Normal && to_check.type() != CardStack::Type::Play) + continue; + + if (to_check.is_empty()) + continue; + + auto& top_card = to_check.peek(); + if (top_card.is_upside_down()) + continue; + + if (stack(Foundation1).is_allowed_to_push(top_card)) { + move_card(to_check, stack(Foundation1)); + card_was_moved = true; + if (to_check.type() == CardStack::Type::Play) + pop_waste_to_play_stack(); + } else if (stack(Foundation2).is_allowed_to_push(top_card)) { + move_card(to_check, stack(Foundation2)); + card_was_moved = true; + if (to_check.type() == CardStack::Type::Play) + pop_waste_to_play_stack(); + } else if (stack(Foundation3).is_allowed_to_push(top_card)) { + move_card(to_check, stack(Foundation3)); + card_was_moved = true; + if (to_check.type() == CardStack::Type::Play) + pop_waste_to_play_stack(); + } else if (stack(Foundation4).is_allowed_to_push(top_card)) { + move_card(to_check, stack(Foundation4)); + card_was_moved = true; + if (to_check.type() == CardStack::Type::Play) + pop_waste_to_play_stack(); + } + } + + // If at least one card was moved, check again to see if now any additional cards can now be moved + if (card_was_moved) { + start_timer_if_necessary(); + auto_move_eligible_cards_to_stacks(); + } +} + void Game::mark_intersecting_stacks_dirty(Card& intersecting_card) { for (auto& stack : m_stacks) { diff --git a/Userland/Games/Solitaire/Game.h b/Userland/Games/Solitaire/Game.h index 1e59919691..c782a73778 100644 --- a/Userland/Games/Solitaire/Game.h +++ b/Userland/Games/Solitaire/Game.h @@ -160,6 +160,10 @@ private: void remember_flip_for_undo(Card& card); void update_score(int to_add); void move_card(CardStack& from, CardStack& to); + void draw_cards(); + void pop_waste_to_play_stack(); + void auto_move_eligible_cards_to_stacks(); + void start_timer_if_necessary(); void start_game_over_animation(); void stop_game_over_animation(); void create_new_animation_card(); |