This class had slightly confusing semantics and the added weirdness
doesn't seem worth it just so we can say "." instead of "->" when
iterating over a vector of NNRPs.
This patch replaces NonnullRefPtrVector<T> with Vector<NNRP<T>>.
Instead of indicating which individual cards should be highlighted, card
games now indicate which stack is highlighted. This lets the stack draw
empty stacks with a highlight (e.g. the Foundation stack in Solitaire).
If the stack is non-empty, the stack can delegate highlighting to the
top-most card.
For example, in Solitaire, when dragging a card around, it's common for
other implementations to highlight the card underneath the dragged card
if that other card is a valid drop target. This implementation will draw
a rounded rectangle within the edges of the highlighted card, using a
rudimentary complementary color of the board background color.
Gfx::Color is always 4 bytes (it's just a wrapper over u32) it's less
work just to pass the color directly.
This also updates IPCCompiler to prevent from generating
Gfx::Color const &, which makes replacement easier.
`create_standard_deck()` is the usual 52-card deck, but more custom
setups (such as Spider's multiples-of-one-suit) can be created by
passing suit counts to `create_deck()`.
Instead of each card being responsible for painting its own bitmaps, we
now have a CardPainter which is responsible for this. It paints a given
card the first time it is requested, and then re-uses that bitmap when
requested in the future. This saves memory for duplicate cards (such as
in Spider where several sets of the same suit are used) or unused ones
(for example, the inverted cards which are only used by Hearts). It
also means we don't throw away bitmaps and then re-create identical
ones when starting a new game.
We get some nice memory savings from this:
| | Before | After | Before (Virtual) | After (Virtual) |
|:----------|---------:|---------:|-----------------:|----------------:|
| Hearts | 12.2 MiB | 9.3 MiB | 25.1 MiB | 22.2 MiB |
| Spider | 12.1 MiB | 10.1 MiB | 29.2 MiB | 22.9 MiB |
| Solitaire | 16.4 MiB | 9.0 MiB | 25.0 MiB | 21.9 MiB |
All these measurements taken from x86_64 build, from a fresh launch of
each game after the animation has finished, but without making any
moves. The Hearts value will go up once inverted cards start being
requested.
Because `card->value() == 11` is a lot less clear than `card->rank() ==
Cards::Rank::Queen`, and also safer.
Put this, along with the `Suit` enum, in the `Cards` namespace directly
instead of inside `Cards::Card`. Slightly less typing that way.
Each of these strings would previously rely on StringView's char const*
constructor overload, which would call __builtin_strlen on the string.
Since we now have operator ""sv, we can replace these with much simpler
versions. This opens the door to being able to remove
StringView(char const*).
No functional changes.
Playing cards have a `suit` such as `hearts`/`diamonds`, not a
`type`. Make the internal naming consistent with the way playing cards
are typically named.
`CharacterBitmap` instances are generated at run-time and put on the
heap, but they can be created in a `constexpr` context and stored in
static memory.
Also, remove additional `width` and `height` `static` values in favor
of using the `constexpr` member functions of `CharacterBitmap`.
These changes also include the removal of some initialization code
which tests if the `CharacterBitmap` is created since it is always
created and removes function-local `static` values which cause
run-time branches to ensure it is initialized each time the function
is called.
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).