This fixes#7792.
The visual glitches with card corners, and the screen-clear when
opening a menu, were both caused by the widgets having
`fill_with_background_color` set. We need that set most of the time,
so we just disable it for the duration of the game-over animation.
Also resove a FIXME that no longer applies. :^)
Previously, the timer started if you clicked within the game area,
whether that was on a card or not. Now, we only start when you click
on a card or otherwise attempt a move.
As a bonus, we now immediately update the status bar time indicator
on game start, instead of having to wait until 1 second has elapsed.
Previously, if a tab-move moved all the remaining cards to the
foundations, the game would not notice until you moved a card
away and then back again.
I had to add a 1-frame delay to starting the animation, so that it
would have time to re-paint the foundation in that case.
Whether or not tiles moved used to be determined by comparing new_tiles
with m_tiles. This is no longer possible since the slide is done
in-place.
This fix makes the game look through the m_sliding_tiles, which contains
previous and current position for each tile on the board, to determine
whether any tile moved at all. If not, the move is deemed unsuccessful.
Fixes#8008.
Keeping this as a separate commit as I'm not certain whether this
is a good change or not. The repeated if-else for each Foundation
stack bothered me a bit, though more so before I reduced the code
in the {}. But maybe the ifs are clearer than the loop?
Doing that also meant I could inline the move_card() code instead
of needing to make it a lambda. Again, maybe it would be better as
a lambda? I'm still figuring out the style Serenity uses, and I
know Andreas is big on expressiveness, and move_card() is more
expressive than just having the code in the loop.
The two paths did the same thing, in two different ways. Now they
are the same. :^)
Can't quite put all of the logic into
attempt_to_move_card_to_foundations() because the double-click has
to check that you clicked on the top card.
Previously, AK::Function would accept _any_ callable type, and try to
call it when called, first with the given set of arguments, then with
zero arguments, and if all of those failed, it would simply not call the
function and **return a value-constructed Out type**.
This lead to many, many, many hard to debug situations when someone
forgot a `const` in their lambda argument types, and many cases of
people taking zero arguments in their lambdas to ignore them.
This commit reworks the Function interface to not include any such
surprising behaviour, if your function instance is not callable with
the declared argument set of the Function, it can simply not be
assigned to that Function instance, end of story.
Now that the cards have rounded corners, draw the stack box behind the
cards with rounded corners as well. This way, the corner of the stack
box doesn't peek out from behind the cards.
The caveat here is that the "play" card stack now needs to hold a
reference to the "waste" stack beneath it so it knows when not to draw
its background on top of the waste stack. To faciliate that, the array
of card stacks is now a NonnullRefPtrVector so the play stack can store
a smart pointer to the waste stack (instead of a raw pointer or
reference).
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`
When we don't have a matching card for the lead card rather than
always preferring to play hearts we should try to get rid of our
high value cards first if no other player has hearts cards higher
than what we have.
When we're the third player in a trick and we don't have a lower value
card we would previously pick a slightly higher value card. Instead
we should pick the highest value card unless there are points in the
current trick or the lead card is spades and the higher value card
we would've picked is higher than the queen and another player still
has the queen.
The rationale is that we have to take the trick anyway so we might as
well get rid of our highest value card. If the trailing player has a
lower value card of the same type we take the trick but don't gain
any points. If they don't have a card of the same type it doesn't
matter whether we play a high value or low value card.
Previously the AI would prefer playing a lead card for which no other
player had a card with a higher value even though it also had a card
for which a higher value card was still in play.
Currently, the player loses 100 points each time the waste stack is
recycled. In three-card draw mode, it's standard to only lose 20 points
after the third recycle event.
This invocation will exit immediately. There's also no reason to invoke
stop_game_over_animation here because that's the first thing that will
happen in the call to setup.
When an animation is stopped the cards should be moved to their final
position anyway. Otherwise they might end up getting stuck in the
middle of the animation.
This changes the game so that more than one hand can be played. Once
one player has 100 or more points the game ends. A score card is shown
between each hand.
Fixes#7374.