Cards
The cards use a simple system of splitting the value into two halves, the first four bits signify the card value - which, for the ease of evaluating the hands, starts from 00 representing "Two".
Then, in order (as you'd expect), the cards are:
Diamonds Hearts Spades Clubs
Byte Card Byte Card Byte Card Byte Card
00 Two 10 Two 20 Two 30 Two
01 Three 11 Three 21 Three 31 Three
02 Four 12 Four 22 Four 32 Four
03 Five 13 Five 23 Five 33 Five
04 Six 14 Six 24 Six 34 Six
05 Seven 15 Seven 25 Seven 35 Seven
06 Eight 16 Eight 26 Eight 36 Eight
07 Nine 17 Nine 27 Nine 37 Nine
08 Ten 18 Ten 28 Ten 38 Ten
09 Jack 19 Jack 29 Jack 39 Jack
0A Queen 1A Queen 2A Queen 3A Queen
0B King 1B King 2B King 3B King
0C Ace 1C Ace 2C Ace 3C Ace
The upper four bits, when shifted four positions to the right, represent the suits. Obviously, they don't have to be shifted, just this is how the game evaluates them, so that's what we'll do here.
The suits are: 00: Diamonds, 01: Hearts, 02: Spades and 03: Clubs.
Card Graphics
Here are some examples of cards and their values:
Byte Bits Breakdown Result
Lower Upper Card Suit
Byte Bits Byte Bits
06 00000110 06 0110 00 0000 Eight Diamonds
0C 00001100 0C 1100 00 0000 Ace Diamonds
19 00011001 09 1001 01 0001 Jack Hearts
1A 00011010 0A 1010 01 0001 Queen Hearts
27 00100111 07 0111 02 0010 Nine Spades
2B 00101011 0B 1011 02 0010 King Spades
34 00110100 04 0100 03 0011 Six Clubs
To follow the mechanism in the game, start from PrintHand which cycles through all five cards in a hand and prints them to the screen via CheckCardType.
CheckCardType E33A LD B,A Store the card value in B to process the suit later.
E33B AND %00001111 Keep only bits 0-3.
E33D CP 09 Jump to PrintNumberCard if A is 09 or lower.
E33F JR C,PrintNumberCard
E341 CP 0C Jump to PrintAceCard if A is equal to 0C.
E343 JR Z,PrintAceCard
Anything else is a picture card, so work out what we're printing.
* The picture card routine is not shown here as it complicates things, check the disassembly for further details.
Let's take an example and follow it all the way through: 25 The AND turns it into 05, so this card is a "Seven".
Moving onto PrintNumberCard:
PrintNumberCard E3BD LD C,B Copy the original card value into C as we need B for the loop below.
E3BE LD B,A Set a counter in B of the card number (this is the lower four bits).
E3BF INC B Increment B by one, due to the way the loop below works.
E3C0 LD DE,$001E The card UDG data blocks are 001E in length, so store this in DE for the calculation.
E3C3 LD HL,E436 The card data begins from E436 so store this in HL.
E3C6 XOR A Reset the flags.
E3C7 SBC HL,DE Subtract DE from HL as the loop will add it back and then it will be pointing to the beginning again.
FindCardUDGData_Loop E3C9 ADD HL,DE Add 001E to HL to move to the next block of card UDG data.
E3CA DJNZ FindCardUDGData_Loop Decrease the card value counter by one and loop back to FindCardUDGData_Loop until the appropriate card UDG data block is found.
E3CC LD (E563),HL Write the card UDG data block pointer to *PointerCardUDGData.
So, our card 25 will end up writing Graphics_CardSeven to *PointerCardUDGData (which will be used later). This references the number part of the card (without any suit applied yet).
Work out the suit.
E3CF LD B,04 Using the original card value, shift the upper four bits to be the lower four bits.
SuitShift_Loop E3D1 SRL C
E3D3 DJNZ SuitShift_Loop
E3D5 LD A,C Write the calculated suit to *CurrentCardSuit.
E3D6 LD (E562),A
Now calculate the suit UDG data address.
E3D9 LD B,C Set a counter in B of the calculated suit (this is the upper four bits).
E3DA INC B Increment B by one, due to the way the loop below works.
E3DB LD DE,0058 The suit UDG data blocks are 0058 in length, so store this in DE for the calculation.
E3DE LD HL,E6BF The suit UDG data begins from E6BF so store this in HL.
E3E1 XOR A Reset the flags.
E3E2 SBC HL,DE Subtract DE from HL as the loop will add it back and then it will be pointing to the beginning again.
FindSuitUDGData_Loop E3E4 ADD HL,DE Add 0058 to HL to move to the next block of suit UDG data.
E3E5 DJNZ FindSuitUDGData_Loop Decrease the suit counter by one and loop back to FindSuitUDGData_Loop until the appropriate suit UDG data block is found.
E3E7 PUSH DE Set a counter in BC to the length of the suit UDG data block: 0058.
E3E8 POP BC
E3E9 LD DE,E667 Set the target in DE to Buffer_CardData.
E3EC LDIR Copy the suit UDG data block to the card data buffer.
With 25 after shifting the bits, we end up with 02 - so the suit is Spades. And after the "Find" loop, HL will point to Graphics_SpadesSuitData which is then copied into Buffer_CardData so it becomes the "upper part" of the font data and can be referenced by the UDG data.
Next, we set the UDG font pointer and discover the colour of the card to be printed.
Set the card character-set to be the in-use font.
         E3EE LD HL,E35F Write E35F to *CHARS.
E3F1 LD (5C36),HL
Handle setting the colour of the card.
E3F4 LD A,13 BRIGHT: ON.
E3F6 RST 10
E3F7 LD A,01
E3F9 RST 10
E3FA LD A,10 Set INK: BLACK.
E3FC RST 10
E3FD LD A,00
E3FF RST 10
E400 LD A,(E562) Jump to PrintCard if *CurrentCardSuit is 02 or higher (so Spades or Clubs).
E403 CP 02
E405 JR NC,PrintCard
Else this card is a Diamonds or Hearts so set the INK appropriately.
E407 LD A,10 Set INK: RED.
E409 RST 10
E40A LD A,02
E40C RST 10
Our suit is 02 so the colour will be BLACK.
Now we have all the components, we know the card UDG data and the suit UDG data has been copied into the upper range of it. We also know the colour too, so all that's left to do is to print it on the screen using PrintCard.
The cards are printed using the standard Spectrum printing routine, and so the data is stored as a series of references:
42 43 43 43 43 44
50 6B 5F 5F 6B 51
69 5F 61 62 5F 6A
41 5F 63 64 5F 45
41 65 5F 5F 65 45
For ease of explaining this, if the data just referenced ASCII - then the print would output the following letter graphics:
B C C C C D
P k _ _ k Q
i _ a b _ j
A _ c d _ E
A e _ _ e E
How the code works, is that we write E35F to CHARS and this is where the "magic" happens! Rather than reference the graphics for each letter in ROM - the print routine references the game UDGs instead.
So the data we have links through to these address (click to see):
E56F E577 E577 E577 E577 E57F
E5DF E6B7 E657 E657 E6B7 E5E7
E6A7 E657 E667 E66F E657 E6AF
E567 E657 E677 E67F E657 E587
E567 E687 E657 E657 E687 E587
And produces the following output:
udg58735_120x4 udg58743_120x4 udg58743_120x4 udg58743_120x4 udg58743_120x4 udg58751_120x4
udg58847_120x4 udg59063_120x4 udg58967_120x4 udg58967_120x4 udg59063_120x4 udg58855_120x4
udg59047_120x4 udg58967_120x4 udg58983_120x4 udg58991_120x4 udg58967_120x4 udg59055_120x4
udg58727_120x4 udg58967_120x4 udg58999_120x4 udg59007_120x4 udg58967_120x4 udg58759_120x4
udg58727_120x4 udg59015_120x4 udg58967_120x4 udg58967_120x4 udg59015_120x4 udg58759_120x4
The blank spaces are due to the cards being stored "suit-less" (at least on game load anyway). The print routine copies in the suit UDGs when printing every card (regardless of the previous card suit). So the final result looks like this:
demo-card-0-0 demo-card-1-0 demo-card-2-0 demo-card-3-0 demo-card-4-0 demo-card-5-0
demo-card-0-1 demo-card-1-1 demo-card-2-1 demo-card-3-1 demo-card-4-1 demo-card-5-1
demo-card-0-2 demo-card-1-2 demo-card-2-2 demo-card-3-2 demo-card-4-2 demo-card-5-2
demo-card-0-3 demo-card-1-3 demo-card-2-3 demo-card-3-3 demo-card-4-3 demo-card-5-3
demo-card-0-4 demo-card-1-4 demo-card-2-4 demo-card-3-4 demo-card-4-4 demo-card-5-4
Girls
To save on space, the girls are created with one initial image, and then the other "frames" are single sections which are overlaid on top of them.
This means that often, an image is an amalgamation of several images all printed on top of each other.
Girl 1: Shelia
girl-1-frame-1
girl-1-frame-2
girl-1-frame-3
girl-1-frame-4
girl-1-frame-5
girl-1-frame-6
girl-1-frame-7
Girl 2: Ireen
girl-2-frame-1
girl-2-frame-2
girl-2-frame-3
girl-2-frame-4
girl-2-frame-5
Girl 3: Diane
girl-3-frame-1
girl-3-frame-2
girl-3-frame-3
girl-3-frame-4
girl-3-frame-5
Two Pairs
Of interest, the game will (intentionally) randomly gamble redrawing when the girl has two pairs. It's not a particularly strong hand, only higher than a single pair but obviously it's still a pretty good hand!
The girls hand has no cards which form one of the "special" outcomes (special, as in, which aren't able to be found by counting duplicate card face values).
         96DE CALL GetRandomNumber Call GetRandomNumber.
96E1 CP 0A Jump to FindCardsToMark if the random number is lower than 0A.
96E3 JR C,FindCardsToMark
Two pairs is also somewhat of a "special" outcome, so handle it separately.
96E5 LD A,(949B) Jump to FindLowestSingleCard if *TableHandEvaluation_Type is equal to "Two Pairs".
96E8 CP 03
96EA JR Z,FindLowestSingleCard