summaryrefslogtreecommitdiff
path: root/Userland/Games/Solitaire
diff options
context:
space:
mode:
authorMatthew B. Jones <matthewbjones85@gmail.com>2021-06-03 01:43:28 -0600
committerGitHub <noreply@github.com>2021-06-03 08:43:28 +0100
commitecaae2d10f9a589977c84710f681247c6f4cb19a (patch)
tree0b7e84944d4a26522ab1a1519dec7c86edaeaa53 /Userland/Games/Solitaire
parente7cfa9bf8e115baeacf82aed93405c790073fd97 (diff)
downloadserenity-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.cpp207
-rw-r--r--Userland/Games/Solitaire/Game.h4
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();