mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 06:57:44 +00:00
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`
This commit is contained in:
parent
e7cfa9bf8e
commit
ecaae2d10f
2 changed files with 139 additions and 72 deletions
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue