|
Subject: [stella] Euchre: light on the horizon From: Erik Eid <eeid@xxxxxxxxx> Date: Mon, 15 Jul 2002 20:08:40 -0400 |
Greetings! It's been just over three months since my last update, which wasn't so much an update as an overhaul to drop fancy features in favor of much-needed space. These last three months have been rather productive! To save on some space, I cut out the copyright and byline messages, which allowed me to eliminate a lot of image data and reduce the six-digit message display to a four-digit display. I also revamped the bidding routines so that they are based on a point system rather than trying to determine how many tricks a hand is likely to take. (I found that, due to a small bug critical bug, the computer was often thinking it could take well over five tricks!) This routine is a little cleaner and shorter, plus it seems to be more effective. The biggest and most important change is the addition of the computer's playing intelligence. Rather than just playing the first available card it can find, it now follows suit properly, and calculates the best follow-up or lead card. While it doesn't play exactly as I or another human might, it does keep track of important factors such as which suits are broken and which trump cards have yet to be played. In short, this means Euchre is now a fully playable game! I still have a bit more work to do. First, there is no sound yet. While I don't need much sound, I do want some noises for when the human player plays a card or selects an action, when the hand is over, and when an illegal choice is made. Second, now that I've taken away the copyright and byline messages, I need some sort of indicator that the game is over. If I have space, I may investigate a color-cycling attract mode; otherwise I might just use a single-letter message. Third, again if there is room, I would like to implement a "stick the dealer" variant, accessible through a difficulty switch. This is the lowest priority, though. Can I do all this with 130 bytes left? We'll see. I also need to write a manual and set up a web page, but these activities are good for when I need a mental break from the coding. :) Anyhow, please enjoy the game now that it is playable, and let me know if you see it violate any rules or make really strange decisions. I have attached the source, binary, and Stella profile entry as usual. The version of vcs.h that I am using until the list decides on a standard is athttp://www.io.com/~nickb/atari/doc/vcs.h.
"Cartridge.MD5" "15bf2ef7583bfcbbba630847a1dc5539" "Cartridge.Name" "Euchre (July 15, 2002 pre-release)" "Cartridge.Manufacturer" "Erik Eid" "Cartridge.Rarity" "New Release" "Cartridge.Type" "4K" "Controller.Left" "Joystick" "Display.Format" "NTSC" ""
Attachment:
Euchre.bin
Description: Euchre ROM
;
; Euchre game program for the Atari 2600 video computer system
;
; Copyright 2001 by Erik Eid (eeid@xxxxxxxxx)
;
; Last update: July 15, 2002
;
; Compiled with the dasm assembler (version 2.12.04) using the -f3 option
;
processor 6502
include vcs.h
; Constants
seg.u defines
CardsInDeck = $18 ; 24 cards in a Euchre deck
CardsInHand = $05
TricksInRound = $05
SuitsInDeck = $04
Team1Color = $88
Team2Color = $38
TableRegionColor = $d4
CardTableColor = $0f
RedSuitColor = $36
BlackSuitColor = $00
MessageRegionDisplayColor = $22
MessageRegionChoiceColor = $84
MessageTextColor = $1c
CursorColor = $82
TrumpDisplayColor = %00101000
RankMask = %00011100 ; Bit mask for rank of a card
DispSuitMask = %01100000 ; Bit mask for suit displayed on a card
RealSuitMask = %00000011 ; Bit mask for suit used when following (the left
; bower becomes the suit of the right bower)
FullSuitMask = %01100011 ; Bit mask for both display and real suit
CardHiddenMask = %10000000 ; Bit mask for determining if a card is hidden
ShowCardMask = %01111111 ; Bit mask to force a card to be shown
HideCardValue = %10000000 ; Bit mask to force a card to be hidden
CardPlayedMask = %10000000
CardPlayedValue = %10000000
; This mask is used only when calculating the strength of a hand
; because they rely on the original rank and suit of a card
RankSuitMask = %01111100 ; Bit mask for rank and suit combined
RightRankValue = %00011100
LeftRankValue = %00011000
AceRankValue = %00010100
KingRankValue = %00010000
QueenRankValue = %00001100
JackRankValue = %00001000
TenRankValue = %00000100
NineRankValue = %00000000
HeartSuitValue = %00000000
DiamondSuitValue = %00100001
ClubSuitValue = %01000010
SpadeSuitValue = %01100011
BlackSuitMask = %00000010
FlipColorSuitMask = %00000001 ; EOR with this to change suit to other suit
; of the same color
PlayersMask = %00000011
NoPlayer = %11111111 ; Since players are numbered 0-3, a 255 indicates
; that no player meets the condition
NoSuit = %11111111
NoCard = %11111111
NoChoice = %11111111
SWACNT = $281 ; Strangely not part of the original vcs.h
VS_Disable = 0 ; Ditto
CenterRankPos = $75 ; Player positions
CenterSuitPos = $66
LeftRankPos = $a2
RightRankPos = $57
LeftScorePos = $31
RightScorePos = $97
LeftTrickPos = $f1
RightTrickPos = $97
BidArrowPos = $35
BidDecisionPos = $b5
InstructionPos = $f5
MessageP0Pos = $c4
MessageP1Pos = $35
NoCursorPos = $FF
MsgNumBlank = $00
MsgNumSelectAction = $01
MsgNumSelectTrump = $02
MsgNumDeal = $03
StageHold = $00
StageNewGame = $01
StageNewHand = $02
StageGameOver = $03
StageShuffle = $04
StageDeal = $05
StageBidding1 = $06
StageDiscarding = $07
StageBidding2 = $08
StagePlaying = $09
StageAddToTricks = $0a
StageAddToScore = $0b
StageBetweenHands = $0c
FramesWait = 90 ; Number of frames to wait for 1 1/2 seconds
FramesShortWait = 45 ; Number of frames to wait for 3/4 second
FramesLongWait = 180 ; Number of frames to wait for 3 seconds
FramesJoyWait = 15
ChoicePass = $00
ChoiceCall = $01
ChoiceAlone = $02
TriggerOff = $00
TriggerOn = $01
TriggerHeld = $02
CursorModeNone = $00
CursorModeCard = $01
CursorModeAction = $02
CursorModeTrump = $03
CursorModeSelectMask = %00000010
TrumpScoreValue = %01000000 ; Value to add to rank for trump cards when
; considering the card to play
LeadSuitScoreValue = %00100000 ; Value to add to rank for cards of the
; led suit when considering the card to play
UnbrokenModifier = %00100010 ; Value to add to rank for cards of an unbroken
; suit when considering the card to lead
BrokenModifier = %00100000 ; Value to add to rank for cards of a broken
; suit when considering the card to lead
; Variables
seg.u vars
org $80
Team1Score ds 1
Team2Score ds 1
Team1Tricks ds 1
Team2Tricks ds 1
SouthHand ds 5 ; Cards in a player's hand
WestHand ds 5
NorthHand ds 5
EastHand ds 5
SouthCard ds 1 ; Cards down on the table
WestCard ds 1
NorthCard ds 1
EastCard ds 1
ImgPtr1 ds 2 ; Pointers to playfield and player images
ImgPtr2 ds 2
ImgPtr3 ds 2
ImgPtr4 ds 2
HandCard ds 1 ; Pointer to a card in a hand
T1 ds 1 ; Temporary variables used in subroutines
T2 ds 1
T3 ds 1
T4 ds 1
rand1 ds 1 ; Locations to hold bits of random number
rand2 ds 1
rand3 ds 1
rand4 ds 1
NeedShuffle ds 1 ; Flag indicating if a shuffle is needed
MessageNum ds 1 ; Number of message to display
MessagePtr ds 2
CursorPos ds 1 ; Card selection cursor position
Stage ds 1
Turn ds 1
BiddingTeam ds 1
Dealer ds 1
FrameCounter ds 1
RightBowerMask ds 1 ; Calculated masks for bower when figuring hand strength
LeftBowerMask ds 1
TriggerTrack ds 1 ; Low four bits are number of frames held, high bit
; indicates release after a full hold
MessageRegionColor ds 1 ; Color to use as background of message area
JoyDir ds 1
HighCardScore ds 1
HighCardNum ds 1
TrumpSuitMask ds 1
HandStartOffset ds 1
HandEndOffset ds 1
Choice ds 1
JoyPause ds 1
CursorMode ds 1
NumTrumps ds 1
HighestRemainingTrump ds 1
NumTrumpsLeft ds 1 ; Amount of trumps left in the round
TrumpsLeft ds 1 ; Array of bits representing which trumps are left
SuitBroken ds 4
DeclinedSuit ds 1
DeclinedBower ds 1
Overlay ds 31
DeckStart = SouthHand
Upcards = SouthCard
seg.u vars
org Overlay
PotentialTrump ds 1
Upcard ds 1
HighStrength ds 1
BestSuit ds 1
HandStrength ds 1
CardScore ds 1
NumInSuit ds 1
NumOffLoneAces ds 1
NumVoids ds 1
HasRight ds 1
HasLeft ds 1
HasTrumpAce ds 1
HasAce ds 1
LowTrumpFactor ds 1
UpcardFactor ds 1
OtherFactor ds 1
Bidder ds 1
seg.u vars
org Overlay
TrickNum ds 1
Leader ds 1
LeadSuitMask ds 1
HasLeadSuit ds 1
PlayerToSkip ds 1
TrickWinner ds 1
CardInTrickNum ds 1
CardsInFullTrick ds 1
CardToPlay ds 1
CardToPlayOffset ds 1
LeadSuitCount ds 1
HighCard ds 1
LegalPlays ds 5
GatheredInfo ds 1
TrickWinningScore ds 1
CurrentCardScore ds 1
OpponentsWinning ds 1
TrueIdealScore ds 1
HighWinnerNum ds 1
HighWinnerScore ds 1
LowWinnerNum ds 1
LowWinnerScore ds 1
LowCardNum ds 1
LowCardScore ds 1
IdealTrumpNum ds 1
IdealTrumpScore ds 1
BestLeadNum = HighWinnerNum
BestLeadScore = HighWinnerScore
BestTrumpNum = LowWinnerNum
BestTrumpScore = LowWinnerScore
ProcessedCounters = GatheredInfo
; Program
seg code
org $f000 ; 4K cartridge
;
; Initialization
;
CartStart
sei ; Disable all interrupts
cld ; Clear decimal mode (so carry is at 256, not 100)
ldx #$ff
txs ; Reset the stack pointer to the highest point possible
; Clear out registers and variables
lda #$00
ClearRAM
sta $00,x
dex
bne ClearRAM ; Loop does not zero WSYNC, but it's not needed
sta SWACNT ; Tell port A to accept input
lda #$6d ; seed random number generator
sta rand1
sta rand2
sta rand3
sta rand4
lda #NoCursorPos
sta CursorPos
lda #$80
ldx #CardsInDeck
HideLoop
dex
sta DeckStart,x
bne HideLoop
jsr StartGameOver
jmp Main
ProgStart ; These initializations are done when Reset is pressed
lda #NoCursorPos
sta CursorPos
lda #TriggerOff
sta TriggerTrack
;
; Main loop
;
Main
; Start of display kernel
; Provide three lines of vertical sync
lda #VB_DumpPots + #VB_Enable
sta VBLANK
lda #VS_Enable
sta WSYNC
sta WSYNC
sta WSYNC
sta VSYNC
sta WSYNC
sta WSYNC
; sta WSYNC
lda #VS_Disable
sta VSYNC
lda #VB_Enable
sta VBLANK ; Start recharge of paddle
; Provide 37 scanlines of vertical blank
lda #43 ; 37 lines * 76 cycles/line = 2812 cycles / 64 cycles/interval = 43.96 intervals
sta TIM64T
jsr RandomBit ; keep the randomness flowing
lda INPT4
bpl TriggerPressed
; lda TriggerTrack
; cmp #TriggerOff
; beq TriggerEnd
lda #TriggerOff
beq TriggerEnd ; We know TriggerOff = 0 so we can beq instead of jmp
TriggerPressed
lda TriggerTrack
cmp #TriggerOff
bne TriggerWasHeld
lda #TriggerOn
bne TriggerEnd ; We know TriggerOn <> 0 so we can bne instead of jmp
TriggerWasHeld
lda #TriggerHeld
TriggerEnd
sta TriggerTrack
lda JoyPause
beq JoyRead
dec JoyPause
lda #$00
beq JoySetDir
JoyRead
lda SWCHA
sta T1
and #J0_Up
beq JoyMinus
lda T1
and #J0_Left
beq JoyMinus
lda T1
and #J0_Down
beq JoyPlus
lda T1
and #J0_Right
beq JoyPlus
lda #$00
sta JoyPause
beq JoySetDir
JoyPlus
lda #FramesJoyWait
sta JoyPause
lda #$01
bne JoySetDir
JoyMinus
lda #FramesJoyWait
sta JoyPause
lda #$FF
JoySetDir
sta JoyDir
JoyEnd
lda #CursorModeNone
ldx Turn
bne DCM4
DetermineCursorMode
ldx CursorPos
bmi DCM4
ldx Stage
cpx #StageDiscarding
beq DCM0
cpx #StagePlaying
bne DCM1
DCM0
lda #CursorModeCard
bne DCM4
DCM1
cpx #StageBidding1
bne DCM2
lda #CursorModeAction
bne DCM4
DCM2
cpx #StageBidding2
bne DCM4
ldx Choice
bmi DCM3
lda #CursorModeTrump
bne DCM4
DCM3
lda #CursorModeAction
DCM4
sta CursorMode
WaitVBlank
lda INTIM
bne WaitVBlank
sta WSYNC ; Finish up last line
sta VBLANK ; Stop vertical blank (accumulator holds zero)
; Now we start on the visible portion of the screen
lda Stage
cmp #StageShuffle
bne NormalKernel
ShuffleKernel
lda #228 ; 192 lines * 76 cycles/line = 14592 cycles / 64 cycles/interval = 228 intervals
sta TIM64T
; Shuffling takes an awfully long time. It costs about 5.6 lines to get one random byte and
; we need 24 random numbers for one shuffle, or 134.4 lines. Since there's not enough time
; to do this during overscan (30 lines), we'll just draw a blank screen whenever we're
; shuffling. This will last for only eight frames, or 0.133 seconds (0.16 seconds in PAL),
; which should not be terribly disruptive.
ShuffleDeck
ldx #CardsInDeck
OneShuffle
dex
stx T1
SD1
jsr RandomByte ; Assume this is a number R between 0 and 1
lsr
lsr
lsr
lsr ; Four high bits are now four low, let this be R * 16
sta T2
lsr ; Now the three high bits are low, let this be R * 8
clc
adc T2 ; A = R * 8 + R * 16 = R * 24, a number between 0 and 23
; (The shift rights are more efficient than rotating
; left into a separate variable.)
SD3
ldx T1
tay
lda DeckStart,x
sta T2
lda DeckStart,y
sta DeckStart,x
lda T2
sta DeckStart,y
ldx T1
bne OneShuffle
sta WSYNC
jmp WaitForEnd
NormalKernel
; First eight lines are blank...
lda #9 ; 8 lines * 76 cycles/line = 608 cycles / 64 cycles/interval = 9.5 intervals
sta TIM64T
; Since we have some time, prepare the playfield for displaying the scores
; and get pointers to playfield images for them.
lda #Team1Color
sta COLUP0
lda #Team2Color
sta COLUP1
lda #LeftScorePos
ldx #0
jsr PositionPlayer
lda #RightScorePos
inx
jsr PositionPlayer
sta WSYNC
sta HMOVE
lda #P_Quad
sta NUSIZ0
sta NUSIZ1
lda Team1Score
ldx #ImgPtr1
jsr GetScoreImage
lda Team2Score
ldx #ImgPtr2
jsr GetScoreImage
WaitEndScore
lda INTIM
bne WaitEndScore
; Now we spend ten lines drawing the scores on the playfield
ldx #$01
jsr DrawBookkeeping
; Pause for four lines and prepare to show tricks
sta WSYNC
lda #$00
sta GRP0
sta GRP1
lda #P_Reflect
sta REFP0
lda #LeftTrickPos
ldx #0
jsr PositionPlayer
lda #RightTrickPos ; Despite the fact that the position for the second
ldx #1 ; score and tricks are identical, the HMOVE will
jsr PositionPlayer ; cause another move, so we need to reset the
; position.
sta WSYNC
sta HMOVE
lda Team1Tricks
ldx #ImgPtr1
jsr GetTrickImage
lda Team2Tricks
ldx #ImgPtr2
jsr GetTrickImage
ldx #$00
jsr DrawBookkeeping
sta WSYNC
lda #$00
sta GRP0
sta GRP1
sta NUSIZ0
sta NUSIZ1
sta REFP0
; Draw an informational region. Depending on the stage, it can be the current
; trump suit, an arrow indicating the current bidder and bid, or an instruction
; to the human player (D = deal, S = swap).
lda Stage
cmp #StageBidding1
beq PrepareShowBid
cmp #StageBidding2
beq PrepareShowBid
cmp #StageBetweenHands
beq PrepareShowD
cmp #StageDiscarding
beq PrepareShowS
cmp #StagePlaying
bcc PrepareShowNothing
PrepareShowTrump
sta WSYNC
lda TrumpSuitMask
ldx #ImgPtr1
jsr GetSuitImage
lda #<LetterImageSpace
ldx #ImgPtr2
jsr GetLetterImage
ldx BiddingTeam
lda BidTeamToTrumpPos,x
ldx #0
jsr PositionPlayer
jmp ShowInformation
PrepareShowNothing
sta WSYNC ; Compensate for this being a short routine
sta WSYNC
sta WSYNC
lda #<LetterImageSpace
ldx #ImgPtr1
jsr GetLetterImage
lda #<LetterImageSpace
ldx #ImgPtr2
jsr GetLetterImage
jmp ShowInformation
PrepareShowD
lda #<LetterImageD
PSD2
ldx #ImgPtr1
jsr GetLetterImage
lda #<LetterImageSpace
ldx #ImgPtr2
jsr GetLetterImage
sta WSYNC ; Compensate for this being a short routine
lda #InstructionPos
ldx #0
jsr PositionPlayer
jmp ShowInformation
PrepareShowS
lda Turn
bne PrepareShowNothing
lda #<LetterImageS
bne PSD2
PrepareShowBid
lda Turn
ldx #ImgPtr1
jsr GetArrowImage
lda Choice
and #$03 ; Change NoChoice ($FF) to $03
tax
lda ChoiceToLetterTable,x
ldx #ImgPtr2
jsr GetLetterImage
lda #BidArrowPos
ldx #0
jsr PositionPlayer
lda #BidDecisionPos
ldx #1
jsr PositionPlayer
ShowInformation
sta WSYNC
sta HMOVE
lda #TrumpDisplayColor
sta COLUP0
sta COLUP1
jsr DrawSingleCard
lda #$00
sta GRP0
sta GRP1
sta WSYNC
lda #7
sta TIM64T
; Position the players for display of a card. This is well in advance but
; we have time now.
lda #CenterRankPos
ldx #0
jsr PositionPlayer
lda #CenterSuitPos
ldx #1
jsr PositionPlayer
sta WSYNC
sta HMOVE
WaitBeginTable
lda INTIM
bne WaitBeginTable
; Now switch to the "card table" display
sta WSYNC
lda #TableRegionColor
sta COLUBK
lda #CardTableColor
sta COLUPF
lda #PF_Reflect
sta CTRLPF
lda #$0f
sta PF1
lda #$ff
sta PF2
lda NorthCard
ldx #ImgPtr1
ldy #ImgPtr2
jsr GetCardGraphics
sta COLUP0
sta COLUP1
jsr DrawSingleCard
lda #$00
sta GRP0
sta GRP1
; Now we come to the hard one... both West and East
lda #P_TwoClose ; Two copies close
sta NUSIZ0
sta NUSIZ1
lda WestCard
ldx #ImgPtr1
ldy #ImgPtr3
jsr GetCardGraphics
sta COLUP0
lda EastCard
ldx #ImgPtr2
ldy #ImgPtr4
jsr GetCardGraphics
sta COLUP1
lda #LeftRankPos
ldx #0
jsr PositionPlayer
lda #RightRankPos
ldx #1
jsr PositionPlayer
; sta WSYNC
; sta HMOVE
jsr DrawTwoCards
lda #$00
sta GRP0
sta GRP1
sta NUSIZ0
sta NUSIZ1
lda #CenterRankPos
ldx #0
jsr PositionPlayer
lda #CenterSuitPos
ldx #1
jsr PositionPlayer
sta WSYNC
sta HMOVE
lda SouthCard
ldx #ImgPtr1
ldy #ImgPtr2
jsr GetCardGraphics
sta COLUP0
sta COLUP1
jsr DrawSingleCard
lda #4
sta TIM64T
lda #$00
sta GRP0
sta GRP1
WaitEndSouth
lda INTIM
bne WaitEndSouth
sta WSYNC ; Stabilizer
lda #9 ; burn 8 lines
sta TIM64T
lda #$00
sta COLUBK
sta PF1
sta PF2
WaitBeforeHand
lda INTIM
bne WaitBeforeHand
; Draw the five cards in the player's hand. For each of the cards, draw four
; black lines then twelve card lines. The middle eight lines of the card have
; the images. During the four black lines, get the image pointers and player
; colors.
lda #$00
sta HandCard
ShowHandLoop
lda #4
sta TIM64T
lda #$00
sta COLUBK
sta PF2
ldx HandCard
lda SouthHand,x
ldx #ImgPtr1
ldy #ImgPtr2
jsr GetCardGraphics
sta COLUP0
sta COLUP1
WaitToDrawHandCard
lda INTIM
bne WaitToDrawHandCard
lda #$f0
sta PF2
sta WSYNC
sta WSYNC
lda #$00
ldx CursorMode
cpx #CursorModeCard
bne SC
ldx HandCard
cpx CursorPos
bne SC
ShowCursor
lda #CursorColor
SC
sta COLUBK
jsr DrawSingleCard
lda #$00
sta GRP0
sta GRP1
sta WSYNC
sta COLUBK
sta WSYNC
sta WSYNC
inc HandCard
lda HandCard
cmp #CardsInHand
bne ShowHandLoop
; Now the gap between the last card and the message region
lda #13
sta TIM64T
lda #$00
sta COLUBK
sta PF2
sta COLUP0
sta COLUP1
; Prepare for the message section
lda #MessageP0Pos
ldx #0
jsr PositionPlayer
lda #MessageP1Pos
ldx #1
jsr PositionPlayer
sta WSYNC
sta HMOVE
ldx #MessagePtr
lda CursorMode
cmp #CursorModeAction
beq DetermineMessageAction
cmp #CursorModeTrump
beq DetermineMessageTrump
ldy MessageNum
jmp DM0
DetermineMessageAction
ldy #MsgNumSelectAction
bne DM0
DetermineMessageTrump
ldy #MsgNumSelectTrump
DM0
jsr GetMessagePointer
jsr GetMessageImages
WaitForGap
lda INTIM
bne WaitForGap
sta WSYNC
lda MessageRegionColor
sta COLUBK
lda #19 ; 16 lines of message
sta TIM64T
lda #P_TwoClose
sta NUSIZ0
sta NUSIZ1
lda #MessageTextColor
sta COLUP0
sta COLUP1
sta WSYNC
sta WSYNC
sta WSYNC
jsr DrawMessageText
lda #$00
sta GRP0
sta GRP1
sta VDELP0
sta VDELP1
sta NUSIZ0
sta NUSIZ1
lda CursorMode
and #CursorModeSelectMask
bne DrawSelector
lda #$00
beq DS2
DrawSelector
lda #%11000000
DS2
pha
lda #MessageTextColor
sta COLUP0
ldx CursorPos
lda CursorPosToSelectorPos,x
ldx #$00
jsr PositionPlayer
sta WSYNC
sta HMOVE
pla
sta GRP0
sta WSYNC
sta WSYNC
lda #$00
sta GRP0
WaitForMessage
lda INTIM
bne WaitForMessage
; lda #1 ; 8 lines
; sta INTIM
lda #$00
sta WSYNC
sta COLUP0
sta COLUP1
sta GRP0
sta GRP1
sta NUSIZ0
sta NUSIZ1
WaitForEnd
; lda INTIM
; bne WaitForEnd
sta WSYNC
sta WSYNC
lda #35 ; 30 lines of overscan
sta TIM64T
lda #$02
sta VBLANK
CheckReset
lda SWCHB
and #$01
bne CheckStages
jsr StartNewGame
jmp ProgStart
CheckStages
lda Stage
asl
asl
sta T1
lda Stage
asl
clc
adc T1
clc
adc #<StageJumpTable
sta T2
lda #>StageJumpTable
adc #$00
sta T3
jmp (T2)
StageJumpTable
jsr PerformHold
jmp EndCase
jsr PerformNewGame
jmp EndCase
jsr PerformNewHand
jmp EndCase
jsr PerformGameOver
jmp EndCase
jsr PerformShuffle
jmp EndCase
jsr PerformDeal
jmp EndCase
jsr PerformBidding1
jmp EndCase
jsr PerformDiscarding
jmp EndCase
jsr PerformBidding2
jmp EndCase
jsr PerformPlaying
jmp EndCase
jsr PerformAddToTricks
jmp EndCase
jsr PerformAddToScore
jmp EndCase
jsr PerformBetweenHands
EndCase
WaitOverscan
lda INTIM
bne WaitOverscan
sta WSYNC
jmp Main
StartHolding ; Stop the action - only used during development
lda #StageHold
sta Stage
PerformHold
rts
StartBidding1
lda #StageBidding1
sta Stage
lda #NoSuit
sta DeclinedSuit
sta DeclinedBower
jsr StartBidding
rts
StartBidding
lda Dealer
clc
adc #$01
and #PlayersMask
sta Turn
lda #NoChoice
sta Choice
lda #$00
sta CursorPos
rts
PerformBidding1
ldx Turn
; bne PB1NotSouth ; Handle case of human player separately
; jmp PB1South ; Can't beq PB1South - too far away
beq PB1South
PB1NotSouth
lda Choice ; Has the computer player made a decision?
bmi PB1TimeToAct ; No - get the player's bid.
dec FrameCounter ; Yes - pause for a bit, then go to next player
beq PB1Advance
rts
PB1TimeToAct
jsr GetHandOffsets ; x still has the turn number, so this is fine
lda Upcard
and #RealSuitMask
sta PotentialTrump
jsr AnalyzeHand
jsr DecideBid
PB1SetDelay
lda #FramesWait
sta FrameCounter
rts
PB1Advance
lda Choice
cmp #ChoicePass
beq PB1Pass
lda Turn
sta Bidder
and #$01
sta BiddingTeam
lda Upcard
and #RealSuitMask
sta TrumpSuitMask
jsr CreateBowers
jsr StartDiscarding ; StartDiscarding also starts play
rts
PB1Pass
lda Turn
cmp Dealer ; Did the dealer just pass?
beq PB1DealerPass ; Yes!
clc ; No, advance to the next player
adc #$01
and #PlayersMask
sta Turn
lda #NoChoice
sta Choice
rts
PB1DealerPass
jsr StartBidding2
rts
PB1South
lda TriggerTrack
cmp #TriggerOn
bne PB1SouthMove
lda CursorPos
sta Choice
jmp PB1Advance
PB1SouthMove
ldx #$03
jsr MoveCursor
rts
; x = highest possible choice number plus one (lowest is zero)
MoveCursor
stx T1
lda JoyDir
clc
adc CursorPos
bmi MCUnder
cmp T1
beq MCOver
MCSave
sta CursorPos
rts
MCUnder
dex
txa ; "Wrap" from lowest to highest by loading highest
bne MCSave
MCOver
lda #$00 ; "Wrap" from highest to lowest by loading lowest
beq MCSave
StartBidding2
lda #StageBidding2
sta Stage
ldx Dealer
lda Upcards,x
ora #HideCardValue
sta Upcards,x
and #RealSuitMask
sta DeclinedSuit
lda Upcards,x
and #RankMask
cmp #JackRankValue
bne SB2A
lda DeclinedSuit
sta DeclinedBower
SB2A
jsr StartBidding
rts
PerformBidding2
ldx Turn
; bne PB2NotSouth ; Handle case of human player separately
; jmp PB2South ; Can't beq PB2South - too far away
beq PB2South
PB2NotSouth
lda Choice ; Has the computer player made a decision?
bmi PB2TimeToAct ; No - get the player's bid.
dec FrameCounter ; Yes - pause for a bit, then go to next player
beq PB2Advance
rts
PB2TimeToAct
jsr GetHandOffsets ; x still has the turn number, so this is fine
lda #$00
sta HighStrength
lda #$03
sta T4
PB2FindBestSuit
lda T4 ; Real suits are 0-3; usable as loop control
cmp DeclinedSuit
beq PB2Declined
sta PotentialTrump
jsr AnalyzeHand
lda HandStrength
jmp PB2CheckIfHigh
PB2Declined
lda #$00
PB2CheckIfHigh
cmp HighStrength ; Is the strength of this hand with the suit
; being checked as trump better than the best
; suit so far?
bcc PB2NextSuit ; No, carry on to the next suit
sta HighStrength ; Yes, store this number and set the best suit
lda T4
sta BestSuit
PB2NextSuit
dec T4
bpl PB2FindBestSuit
lda HighStrength
sta HandStrength
jsr DecideBid ; Submit the highest possible tricks to be taken
; with this hand to get a choice
PB2SetDelay
lda #FramesWait
sta FrameCounter
rts
PB2Advance
lda Choice
cmp #ChoicePass
beq PB2Pass
lda Turn
sta Bidder
and #$01
sta BiddingTeam
lda BestSuit
and #RealSuitMask
sta TrumpSuitMask
jsr CreateBowers
jsr StartPlaying
rts
PB2Pass
lda Turn
cmp Dealer ; Did the dealer just pass?
beq PB2DealerPass ; Yes!
clc ; No, advance to the next player
adc #$01
and #PlayersMask
sta Turn
lda #NoChoice
sta Choice
rts
PB2DealerPass
jsr StartBetweenHands ; Everybody passed! Throw in the hand.
rts
PB2South
lda Choice ; Has south made a bid yet?
bpl PB2SouthSuit ; Yes, so go set a trump suit
lda TriggerTrack ; No, so see if south is setting the bid now
cmp #TriggerOn
bne PB2SouthMoveAction ; South is still in the process of selecting
lda CursorPos
sta Choice
cmp #ChoicePass ; Did the human player pass?
beq PB2Advance ; Yes, go to the next player
lda #$00 ; No, in next frame start suit selection
sta CursorPos
rts
PB2SouthMoveAction
ldx #$03
jsr MoveCursor
rts
PB2SouthSuit
lda TriggerTrack ; Did south pick a suit yet?
cmp #TriggerOn
bne PB2SouthMoveSuit ; No, south is still selecting a trump suit
lda CursorPos
cmp DeclinedSuit ; Did south set trump to the turned-down suit?
beq PB2ChoseDeclined
sta BestSuit
jmp PB2Advance
PB2ChoseDeclined
; buzz?
rts
PB2SouthMoveSuit
ldx #$04
jsr MoveCursor
rts
StartDiscarding
lda #StageDiscarding
sta Stage
ldx Dealer
stx Turn ; Need to show cursor position if south dealt
jsr GetHandOffsets
lda Upcards,x
and #RealSuitMask
sta PotentialTrump
lda #$00
sta CursorPos
rts
PerformDiscarding
lda Dealer
bne PDNotSouth ; Handle case of human player separately
jmp PDSouth ; Can't beq PDSouth - too far away
PDNotSouth
lda #$00
sta HighCardScore ; Assume highest rating of a card is zero
ldx HandEndOffset
stx HighCardNum ; Assume the best card is the last one
PDCardLoop1
lda DeckStart,x ; Get a card from the hand
and #RankMask ; Extract its rank
lsr ; Move rank to lowest three bits, making a number
lsr ; between zero and seven
eor #RankMask ; Effectively inverts rank, turning high to low
sta CardScore ; Starts the card's score as seven minus its rank
lda DeckStart,x
and #RealSuitMask
cmp PotentialTrump ; Is this card a trump?
beq PDCardTrump ; Yes, do not add to the score
lda CardScore
clc
adc #$08 ; Card is not trump; add 8 to its score
sta CardScore
lda DeckStart,x
and #RankMask
cmp #AceRankValue ; Is this card an off-suit ace?
beq PDCardAce ; Yes, do not check if it's alone
lda DeckStart,x
and #RealSuitMask
sta T1 ; T1 will hold the suit of this card so we can use
; it to count how many of the same suit we have
stx T2 ; Stow the current loop index for recovery later
lda #$00
sta NumInSuit
ldx HandEndOffset
PDCardLoop2
lda DeckStart,x
and #RealSuitMask
cmp T1 ; Is this card of the same suit?
bne PDC1 ; No, move on
inc NumInSuit ; Yes, increment count of the suit
PDC1
dex
cpx HandStartOffset
bpl PDCardLoop2
ldx T2 ; Restore the original loop index
lda NumInSuit
cmp #$01 ; Is this card the only one of its suit?
bne PDC2 ; No, there are others
lda CardScore ; Yes, it's the only one of the suit
clc
adc #$08 ; Add 8 to its card score to encourage voiding
sta CardScore
PDCardAce
PDC2
PDCardTrump
lda CardScore
cmp HighCardScore ; Is the score of the current card the highest?
bcc PDC3 ; No, go on to the next card
lda CardScore ; Yes, save the score and the index of the card
sta HighCardScore
stx HighCardNum
PDC3
dex
cpx HandStartOffset
bpl PDCardLoop1
lda HighCardNum
jmp PDSwap
PDSouth
lda TriggerTrack
cmp #TriggerOn
bne PDSouthSelecting
lda CursorPos
clc
adc HandStartOffset
jmp PDSwap ; a could be 0; must jump instead of branch
PDSouthSelecting
jsr GetSelection
rts
PDSwap ; Assumes index of card to swap is in accumulator
tax
lda DeckStart,x
sta T1
txa
tay ; Save its index in the y register
ldx Dealer
lda Upcards,x ; Get the upcard (need original because dealer might
; not be the bidder)
sta T2 ; Save the upcard
tya ; Retrieve index of card to swap
tax
lda T2 ; Retrieve upcard
sta DeckStart,x ; Place upcard in hand
ldx Dealer
lda T1 ; Retrieve card to be swapped
ora #HideCardValue
sta Upcards,x ; Discard it!
jsr StartPlaying
rts
StartShuffle
lda #StageShuffle
sta Stage
lda #$08
sta Turn
RefreshDeck
ldx #CardsInDeck-1
RD1
lda NewDeck,x
sta DeckStart,x
dex
bpl RD1
rts
PerformShuffle
; Note that the shuffling is done from within the specialized
; shuffle kernel, since one shuffle takes too long to do in overscan.
; However, the counter of shuffles (Turn) is still decremented here.
dec Turn
bpl PSOut
jsr StartDeal
PSOut
rts
StartDeal
lda #StageDeal
sta Stage
; lda #MsgNumDeal
; sta MessageNum
rts
PerformDeal
; Flag all the cards in all the hands as available.
ldx #CardsInHand*4-1
DealLoop
lda DeckStart,x
and #ShowCardMask
sta DeckStart,x
dex
bpl DealLoop
; Reveal the turned-up card.
ldx Dealer
lda Upcards,x
and #ShowCardMask
sta Upcards,x
sta Upcard ; Save upcard for use in AnalyzeHand
jsr StartBidding1
rts
StartNewGame
lda #StageNewGame
sta Stage
lda #MsgNumBlank
sta MessageNum
rts
PerformNewGame
lda #$00
sta Team1Score
sta Team2Score
lda rand1
and #PlayersMask
sta Dealer
jsr StartNewHand
rts
StartNewHand
lda #StageNewHand
sta Stage
rts
PerformNewHand
lda #$00
sta Team1Tricks
sta Team2Tricks
lda Dealer
clc
adc #$01
and #PlayersMask
sta Dealer
jsr StartShuffle
rts
StartGameOver
lda #StageGameOver
sta Stage
lda #MsgNumBlank
sta MessageNum
lda #FramesLongWait
sta FrameCounter
rts
PerformGameOver
lda TriggerTrack
cmp #TriggerOn
bne PGOHold
jsr StartNewGame
jmp ProgStart
PGOHold
rts
StartPlaying
lda TrumpSuitMask ; Has both display and "real" suit during bidding
and #RealSuitMask
sta TrumpSuitMask ; Now has only "real" suit
lda #$00
sta TrickNum
lda Choice
cmp #ChoiceAlone
beq SPCalcSkip
lda #$04
sta CardsInFullTrick
lda #NoPlayer
jmp SPDoSkip
SPCalcSkip
lda #$03
sta CardsInFullTrick
lda Bidder
clc
adc #$02
and #PlayersMask
SPDoSkip
sta PlayerToSkip
lda Dealer
SPAdvanceLeader
clc
adc #$01
and #PlayersMask
cmp PlayerToSkip
beq SPAdvanceLeader
sta Leader
sta Turn
lda #$00
ldx #SuitsInDeck-1
SPClearBroken
sta SuitBroken,x
dex
bpl SPClearBroken
lda DeclinedSuit
bmi SPSetTrumpsLeft
tax
lda #$01 ; Mark the turned-down suit as broken since one
sta SuitBroken,x ; less card is available.
SPSetTrumpsLeft
lda DeclinedBower
eor #FlipColorSuitMask
cmp TrumpSuitMask
bne SPSetTrumpsLeft20
lda #%10111011 ; Left bower was turned down, so there are only
ldx #$06 ; six trump available.
bne SPSetTrumpsLeft30
SPSetTrumpsLeft20
lda #%11111011 ; Left bower was not turned down, so there are
ldx #$07 ; seven trump available.
SPSetTrumpsLeft30
sta TrumpsLeft
stx NumTrumpsLeft
lda #RightRankValue
sta HighestRemainingTrump
ContinuePlaying
lda #StagePlaying
sta Stage
lda Turn
beq CP1
sta CursorPos ; Value for south and cursor are both $00
CP1
lda #$00
sta CardInTrickNum
sta GatheredInfo
lda #FramesWait
sta FrameCounter
rts
PerformPlaying
ldx Turn
bne PPNotSouth
jmp PPSouth
PPNotSouth
lda Upcards,x ; Has a card been laid down by the computer player?
bmi PPTimeToAct ; No, go pick a card
dec FrameCounter
beq PPAdvance
rts
PPAdvance
inc CardInTrickNum
lda CardInTrickNum
cmp CardsInFullTrick
beq PPTrickComplete
lda #$00
sta GatheredInfo
sta CursorPos
lda Turn
PPAdvanceTurn
clc
adc #$01
and #PlayersMask
cmp PlayerToSkip
beq PPAdvanceTurn
sta Turn
PPSetDelay
lda #FramesWait
sta FrameCounter
rts
PPTrickComplete
jsr StartAddToTricks
rts
PPTimeToAct
ldx Turn
jsr GetHandOffsets
lda GatheredInfo
beq PPComputerGatherInfo
ldx CardInTrickNum
beq PPComputerLead
jsr PickCardToPlay
jmp PPPlayCard
PPComputerLead
jsr PickCardToLead
jmp PPPlayCard
PPComputerGatherInfo
jsr FindLegalPlays
ldx CardInTrickNum
beq PPComputerGatherInfo2
jsr GatherInfoNonLeader
jmp PPComputerGatherInfoDone
PPComputerGatherInfo2
jsr GatherInfoLeader
PPComputerGatherInfoDone
lda #$01
sta GatheredInfo
rts
PPSouth
lda TriggerTrack
cmp #TriggerOn
bne PPSouthSelecting
ldx Turn
jsr GetHandOffsets
lda CursorPos
clc
adc HandStartOffset
sta CardToPlayOffset
jsr IsCardValidPlay
beq PPInvalidSelection
lda #NoCursorPos
sta CursorPos
jmp PPPlayCard
PPInvalidSelection
; buzz?
rts
PPSouthSelecting
jsr GetSelection
rts
PPPlayCard
ldx CardToPlayOffset
lda DeckStart,x
; and #ShowCardMask
sta CardToPlay ; Tuck away the card to be played for safe keeping
lda CardInTrickNum ; Check if this is the first play of the trick
bne PPNotFirst ; It's not the first play of the trick
lda CardToPlay
sta HighCard ; It is the first card of the trick, so it's the
and #RealSuitMask ; winner and its suit is recorded as the led suit
sta LeadSuitMask
lda Turn
sta TrickWinner
jmp PPShowPlay
PPNotFirst
lda CardToPlay
and #RealSuitMask
cmp TrumpSuitMask ; Is the card that was played a trump?
beq PPTrumped ; Yes, go handle it
cmp LeadSuitMask ; The card wasn't trump - is it in the led suit?
beq PPFollowedSuit ; Yes, go handle it
jmp PPShowPlay ; If card isn't trump or in led suit, it can't win,
; so just go show the card
PPFollowedSuit
lda HighCard
and #RealSuitMask
cmp TrumpSuitMask ; Is the current high card a trump?
beq PPShowPlay ; Yes, and the card just played wasn't, so it can't win
lda HighCard ; No, so see if this card beat the high card
and #RankMask
sta T1
lda CardToPlay
and #RankMask
cmp T1 ; Is the card that was played higher than the current
; winning card in the trick?
bmi PPShowPlay ; No, so just show the card
lda CardToPlay ; Yes, save its information
sta HighCard
lda Turn
sta TrickWinner
jmp PPShowPlay
PPTrumped
lda HighCard
and #RealSuitMask
cmp TrumpSuitMask ; Is the current high card a trump?
bne PPTrumpSucceeds ; No, so this card will become high
lda HighCard ; Yes, so we have to see if this card is a higher trump
and #RankMask
sta T1
lda CardToPlay
and #RankMask
cmp T1 ; Is the card that was played higher than the current
; winning card in the trick?
bmi PPShowPlay ; No, so just show the card
PPTrumpSucceeds
lda CardToPlay
sta HighCard
lda Turn
sta TrickWinner
PPShowPlay
ldx Turn
lda CardToPlay
sta Upcards,x ; Put the card on the "table"
ldx CardToPlayOffset
ora #CardPlayedValue
sta DeckStart,x ; Mark the card played as "used"
lda Turn
bne PPOut
jmp PPAdvance ; Force an advance if it's south's turn (jmp needed)
PPOut
rts
StartAddToTricks
lda #StageAddToTricks
sta Stage
lda TrickWinner
and #$01
tax
inc Team1Tricks,x
; sound?
lda #$00
sta ProcessedCounters
lda #FramesShortWait
sta FrameCounter
rts
PerformAddToTricks
dec FrameCounter
beq PAT010
rts
PAT010
lda ProcessedCounters
bne PAT200
inc ProcessedCounters
inc FrameCounter ; Force one more process frame
ldx #$03
PAT025
lda Upcards,x
bmi PAT050 ; The card wasn't played since the partner went alone.
and #RealSuitMask
tay
lda #$01
sta SuitBroken,y ; Register that the suit of this card is now broken.
cpy TrumpSuitMask ; Is this card trump?
bne PAT050 ; No, so perform no more checks on it.
dec NumTrumpsLeft
lda Upcards,x
and #RankMask
lsr
lsr ; Convert rank to an index
tay
lda TrumpsLeft
and RankToTrumpsLeftTable,y
sta TrumpsLeft ; Clear the bit corresponding to this trump in the
; array of remaining trumps.
PAT050
dex
bpl PAT025
ldx #$07 ; Scan for highest remaining trump, starting with
; the right bower.
PAT100
lda TrumpsLeft
and TrumpsLeftIndexTable,x
beq PAT180 ; This rank is not among those remaining.
txa
asl
asl ; Convert index into the proper bits for a card rank.
sta HighestRemainingTrump
rts
PAT180
dex
bpl PAT100
; If there are no trumps left in the game, the
; HighestRemainingTrump variable will still hold the
; last trump that was high. However, since the
; leader will be out of trump, the variable will not
; be examined.
rts
PAT200
ldx #$03
PATClear
lda Upcards,x
ora #NoCard
sta Upcards,x
dex
bpl PATClear
lda #$00
sta CardInTrickNum
inc TrickNum
lda TrickNum
cmp #TricksInRound
beq PATHandComplete
lda TrickWinner
sta Leader
sta Turn
jsr ContinuePlaying
rts
PATHandComplete
jsr StartAddToScore
rts
StartAddToScore
lda #StageAddToScore
sta Stage
ldx BiddingTeam
lda Team1Tricks,x
cmp #$03
bmi SASEuchre
cmp #$05
beq SASMarch
inc Team1Score,x
jmp SAS1
SASEuchre
txa
eor #$01
tax
lda Team1Score,x
clc
adc #$02
sta Team1Score,x
jmp SAS1
SASMarch
lda PlayerToSkip
cmp #NoPlayer
beq SASMarch2
lda #$04
sta T1
jmp SASFive
SASMarch2
lda #$02
sta T1
SASFive
lda Team1Score,x
clc
adc T1
sta Team1Score,x
SAS1
lda #FramesWait*2
sta FrameCounter
rts
PerformAddToScore
dec FrameCounter
beq PAS1
rts
PAS1
lda Team1Score
cmp #$0a
bpl PASOver
lda Team2Score
cmp #$0a
bpl PASOver
jsr StartBetweenHands
rts
PASOver
; sound?
jsr StartGameOver
rts
StartBetweenHands
lda #StageBetweenHands
sta Stage
rts
PerformBetweenHands
lda TriggerTrack
cmp #TriggerOn
bne PBH1
jsr StartNewHand
PBH1
rts
; determine if a card can be played on a trick
;
; Requires values in CardToPlayOffset, HandStartOffset, HandEndOffset,
; Turn, Leader
;
; returns: a = 00 if card cannot be played, 01 if it can
IsCardValidPlay
ldx CardToPlayOffset
lda DeckStart,x
bpl VPAvailable ; No, continue checking
lda #$00 ; Yes, so it cannot be played again
rts
VPAvailable
lda Turn
cmp Leader ; Is this card leading the trick?
beq VPIsLeader ; Yes, so any card can be played
lda DeckStart,x ; Card is not leading the trick
and #RealSuitMask
cmp LeadSuitMask ; Does this card follow the led suit?
beq VPFollowingSuit ; Yes, so it can be played
lda #$00 ; No, check if hand has the led suit
sta LeadSuitCount
ldx HandEndOffset
VPCountLeadSuit
lda DeckStart,x
and #CardPlayedMask ; Was this card already played?
cmp #CardPlayedValue
beq VPAlreadyPlayed ; Yes, so don't bother checking its suit
lda DeckStart,x
and #RealSuitMask
cmp LeadSuitMask ; Is this card in the lead suit?
bne VPNotLeadSuit ; No, carry on
inc LeadSuitCount ; Yes!
VPNotLeadSuit
VPAlreadyPlayed
dex
cpx HandStartOffset
bpl VPCountLeadSuit
lda LeadSuitCount ; Does this hand have a card in the lead suit?
beq VPVoidInLeadSuit ; No, so an off-suit or trump can be played
lda #$00 ; Yes, so this card cannot be played
rts
VPVoidInLeadSuit
VPFollowingSuit
VPIsLeader
lda #$01
rts
; analyze a hand for its ability to take tricks
;
; Requires values in HandStartOffset, HandEndOffset, and PotentialTrump
AnalyzeHand
lda #$00
sta NumTrumps
sta NumOffLoneAces
sta HandStrength
sta UpcardFactor
lda PotentialTrump
ora #JackRankValue
and #RankMask+#RealSuitMask
sta RightBowerMask
eor #FlipColorSuitMask
sta LeftBowerMask
; Check on the trumps in the hand
ldx HandEndOffset
AHCountLoop1
lda DeckStart,x
and #RealSuitMask
cmp PotentialTrump ; Is this card a trump?
bne AHNotTrump ; No, so do nothing more with it, unless the left bower
AHIsTrump
inc NumTrumps ; Yes! Add one more to the count
lda DeckStart,x
jsr GetTrumpCardStrength
AHIT2
clc
adc HandStrength
sta HandStrength
bne AHCL1
AHNotTrump
lda DeckStart,x
and #RankMask+#RealSuitMask
cmp LeftBowerMask ; It's not of the trump suit, but is it the left bower?
bne AHCL1 ; No, go on to next card
lda #$06 ; Strength of the left bower
bne AHIT2 ; Add left bower to the hand strength
AHCL1
dex
cpx HandStartOffset
bpl AHCountLoop1
; Check on voids and off-suit lone aces, looping once through
; the hand for each non-trump suit
ldy #SuitsInDeck-1
AHCountLoop2
lda #$00
sta NumInSuit
ldx HandEndOffset
AHCountLoop3
cpy PotentialTrump ; Is this loop for trump?
beq AHCL2 ; Yes, advance out of the inner loop
sty T1 ; Loop control variable equivalent to suit
lda DeckStart,x
and #RealSuitMask
cmp T1 ; Is this card in the suit we're examining?
bne AHCL3 ; no, so ignore it
inc NumInSuit ; Yes, increase our count of the suit
lda DeckStart,x
and #RankMask
cmp #AceRankValue ; Is this card an ace?
bne AHCL3 ; No, carry on
inc HasAce ; Yes, indicate we have the ace of this suit
AHCL3
dex
cpx HandStartOffset
bpl AHCountLoop3
lda NumInSuit
cmp #$01 ; Do we have only one card in this suit?
bne AHCL2
lda HasAce ; Yes - is it the ace?
beq AHCL2
inc NumOffLoneAces ; It's a lone off-suit ace.
AHCL2
dey
bpl AHCountLoop2
ldx NumTrumps
lda NumTrumpsToStrength,x
clc
adc HandStrength
sta HandStrength
ldx NumOffLoneAces
lda NumOffLoneAcesToStrength,x
clc
adc HandStrength
sta HandStrength
lda Stage
cmp #StageBidding1 ; Is this the first bidding stage?
bne AHOut ; No, so the upcard isn't relevant
lda Dealer
eor Turn ; But 0 will be 1 if the upcard goes to an opponent
and #$01
bne AHUpOpp ; Upcard goes to opponent
lda Dealer ; Upcard goes to my team
cmp Turn ; Is it to me?
bne AHOut ; No, it's to my partner, and it's unclear what
; effect it will have
lda #$01
sta UpcardFactor
bne AHUpCalc
AHUpOpp
lda #$02
sta UpcardFactor
AHUpCalc
lda Upcard
jsr GetTrumpCardStrength
sta T1
lda UpcardFactor
cmp #$01 ; Does the upcard go to me?
beq AHUpMe
lda HandStrength ; No, subtract the strength of the upcard plus 3
; from the strength of my hand
sec
sbc T1
sec
sbc #$03
bmi AHBelowZero ; If strength is negative, set it to zero
AHUCSet
sta HandStrength
AHOut
rts
AHBelowZero
lda #$00
beq AHUCSet
AHUpMe
lda HandStrength ; Upcard goes to me; add its strength to my hand
clc
adc T1
sta HandStrength
lda NumTrumps
cmp #$03
bmi AHOut ; If I have less than three trumps, the upcard
; won't add the many-trump advantage
beq AHUpMe3 ; Do I have three trump exactly?
cmp #$05 ; No... how about five?
beq AHUpMeX ; If I have five trump, the upcard won't help in
; terms of number of trump
lda #$03
AHUpMeW
clc ; I have four trump and will go to five
adc HandStrength
sta HandStrength
bne AHUpMeX
AHUpMe3
lda #$04 ; I have three trump and will go to four
bne AHUpMeW
AHUpMeX
lda NumTrumps
clc
adc NumOffLoneAces
cmp #$05 ; If I currently have only trump and off-trump
; lone aces, the upcard will eliminate an advantage.
; Subtract a fudge factor of 2.
bne AHOut
lda HandStrength
sec
sbc #$02
jmp AHUCSet
; Assumptions: card is in accumulator, is trump, and the LeftBowerMask is set
GetTrumpCardStrength
and #RankMask+#RealSuitMask
cmp LeftBowerMask
beq GTCSLeft
and #RankMask
lsr
lsr
tay
lda PotentialTrumpRankToStrength,y ; Must be y since calling routines
; normally use x for loop control
rts
GTCSLeft
lda #$06
rts
DecideBid
lda HandStrength
cmp #24
bpl DBAlone
cmp #23
beq DBUorA
cmp #14
bpl DBUp
cmp #13
beq DBPorU
lda #ChoicePass
beq DBEnd
DBAlone
lda #ChoiceAlone
beq DBEnd
DBUorA
lda Dealer
clc
adc #$01
and #$03
cmp Turn ; Will I lead first?
beq DBAlone ; If so, go alone, otherwise just call.
DBUp
lda #ChoiceCall
bne DBEnd
DBPorU
lda Turn ; Borderline hand... depending on the score, choose
; to pass or call.
and #$01 ; If last bit is set, bidder is west or east
beq DBNS ; Bidder is north or south
ldx Team2Score
ldy Team1Score
jmp DB3a
DBNS
ldx Team1Score
ldy Team2Score
; The end result is that x has "our" score
; and y has "their" score
DB3a
cpx #$09 ; Do we have nine points?
bne DB3b ; No, move on...
cpy #$08 ; Does the other team have eight or more points?
bpl DB3c ; Yes, go to next check
cpy #$06 ; Does the other team have six or seven points?
bmi DB3c ; No, go to next check
lda #ChoiceCall ; With score 9-6 or 9-7, it's better to risk a euchre
; than a march
bne DBEnd
DB3b
cpx #$06 ; Do we have six points?
bne DB3c ; No, move on...
cpy #$04 ; Does the other team have four or more points?
bpl DB3c ; Yes, go to next check
cpy #$02 ; Does the other team have two or three points?
bmi DB3c ; No, go to next check
lda #ChoiceCall ; Call to protect the lead (a march would let the
; other team catch up and another would win the
; game for them)
bne DBEnd
DB3c
lda #ChoicePass
beq DBEnd
DBEnd
sta Choice
rts ; Whew!
; determine which cards in a hand are legal to play in a trick
;
; Requires values in CardToPlayOffset, HandStartOffset, HandEndOffset,
; Turn, Leader (all due to use of IsCardValidPlay)
;
; returns: five-byte array in LegalPlays; each byte = 00 if card cannot be
; played, 01 if it can
FindLegalPlays
ldx #CardsInHand-1
FLP2
stx T3
txa
clc
adc HandStartOffset
sta CardToPlayOffset
jsr IsCardValidPlay
ldx T3
sta LegalPlays,x
dex
bpl FLP2
rts
GatherInfoLeader
lda #$00
sta NumTrumps
lda #NoCard
sta BestLeadNum
sta BestTrumpNum
lda HandEndOffset
sta T1
ldx #CardsInHand-1
GILLoop
lda LegalPlays,x
beq GILOut ; This card was already played, so don't examine it.
stx T2 ; Save x, the offset into the hand, for later use.
ldx T1 ; Load the offset into the whole deck into x.
lda DeckStart,x
and #RankMask
sta CurrentCardScore
lda DeckStart,x
ldx T2 ; Restore original value of x.
and #RealSuitMask
cmp TrumpSuitMask ; Is the card being examined trump?
bne GIL100 ; No.
inc NumTrumps ; Yes, so increase the count of trumps in this hand.
lda CurrentCardScore ; Reload since it is expected for the upcoming
; comparison and the store in GIL010.
ldy BestTrumpNum ; Have we designated a best trump?
bmi GIL010 ; No, so do so!
cmp BestTrumpScore ; Is this card the best trump so far?
bmi GILOut ; No, so skip the other checks.
GIL010
sta BestTrumpScore
stx BestTrumpNum
jmp GILOut
GIL100
tay ; Copy suit (from prior to cmp TrumpSuitMask) to y
lda SuitBroken,y ; 0 if not broken, 1 if broken
bne GIL150
lda #BrokenModifier
bne GIL180
GIL150
lda #UnbrokenModifier
GIL180
clc
adc CurrentCardScore
sta CurrentCardScore
ldy BestLeadNum
bmi GIL190
cmp BestLeadScore
bmi GILOut
GIL190
sta BestLeadScore
stx BestLeadNum
GILOut
dec T1
dex
bpl GILLoop
rts
PickCardToLead
lda BestTrumpNum ; Was any trump found in the hand?
bmi PCTL250 ; No!
lda BestTrumpScore
cmp HighestRemainingTrump ; Yes - were any of them the highest still out?
bne PCTL250 ; No!
lda NumTrumpsLeft ; We have the highest trump still in the game.
lsr
sta T4 ; Number of remaining trump, divided by 2, rounded down.
lda NumTrumps
cmp T4 ; Do we have half of the trump left?
bmi PCTL250 ; No.
PCTL200
lda BestTrumpNum ; Yes, so play our highest trump.
bpl PCTLCardSelected
PCTL250
lda BestLeadNum ; Play the card designated as "best" lead.
bmi PCTL200 ; If no best non-trump lead exists, play the best trump.
PCTLCardSelected
clc
adc HandStartOffset
sta CardToPlayOffset
rts
GatherInfoNonLeader
lda #NoCard
sta HighWinnerNum
sta LowWinnerNum
sta LowCardNum
sta IdealTrumpNum
lda HighCard
and #RankMask
sta TrickWinningScore
lda HighCard
and #RealSuitMask
cmp TrumpSuitMask ; Is the winning card trump?
beq GINL10 ; Yes!
lda #LeadSuitScoreValue ; No, so it must be of the led suit
bne GINL15
GINL10
lda #TrumpScoreValue
GINL15
clc
adc TrickWinningScore
sta TrickWinningScore
ldy Turn
lda PlayerToPartnerTable,y
cmp TrickWinner ; Is my partner winning the trick?
bne GINLOpponentsWinning
lda #$00
beq GINL20
GINLOpponentsWinning
lda #$01
GINL20
sta OpponentsWinning ; 1 if the opponents are winning
; the trick or 0 if my partner is winning
ldy TrickNum
lda TrickToIdealTrump,y
sta TrueIdealScore
lda HandEndOffset
sta T1
ldx #CardsInHand-1
GINLLoop
lda LegalPlays,x
beq GINLOut ; This card is not a valid play or was already played,
; so don't examine it
stx T2
ldx T1
lda DeckStart,x
and #RankMask
sta CurrentCardScore
lda DeckStart,x
ldx T2
and #RealSuitMask
cmp TrumpSuitMask ; Is the current card trump?
beq GINL40 ; Yes!
cmp LeadSuitMask ; No. Is it of the led suit?
bne GINL70 ; No, so there's nothing to add.
lda #LeadSuitScoreValue ; Yes, this suit was led, so it is of more worth.
bne GINL60
GINL40
lda #TrumpScoreValue
GINL60
clc
adc CurrentCardScore
sta CurrentCardScore
bne GINL80
GINL70
lda CurrentCardScore ; There was nothing to add to the current card's
; relative strength, but it needs to be in the
; accumulator. The last data loaded there was
; the card's suit!
GINL80
ldy LowCardNum ; Has a card been designated as lowest in the hand?
bmi GINL90 ; No, so designate this one. This is particularly
; important as it is the default card to play.
cmp LowCardScore ; Is it the lowest so far?
bpl GINLHigher ; No, but continue comparing it...
GINL90
sta LowCardScore
stx LowCardNum
GINLHigher
cmp TrickWinningScore ; Can the current card beat the trick winner?
bmi GINLOut ; No, so stop processing it
ldy HighWinnerNum ; Has a card been designated as the highest winner?
bmi GINLHigherSet ; No, so designate this one.
cmp HighWinnerScore ; Does this card beat the current highest winner?
bmi GINLLowWinner ; No, but check if it is the lowest winning card.
GINLHigherSet
sta HighWinnerScore ; Yes, it's the highest winner encountered so far.
stx HighWinnerNum
GINLLowWinner
ldy LowWinnerNum ; Has a card been designated as the lowest winner?
bmi GINLLowWinSet ; No, so designate this one.
cmp LowWinnerScore ; Is this card lower than the current lowest winner?
bpl GINLIdeal ; No, but check if it's an ideal trump.
GINLLowWinSet
sta LowWinnerScore ; Yes, it's the lowest winner encountered so far.
stx LowWinnerNum
GINLIdeal
cmp #NineRankValue+#TrumpScoreValue ; Is the current card a trump?
bmi GINLOut ; No, so there's nothing else to consider.
ldy LeadSuitMask
cpy TrumpSuitMask ; Was trump led?
beq GINLOut ; Yes; treat it as a normal suit, ignoring
; considerations of "ideal".
ldy IdealTrumpNum ; Has any trump been encountered yet?
bmi GINLSetNewIdeal ; No, so this one is our "ideal" so far.
cmp TrueIdealScore ; How does this trump compare to the true ideal?
bmi GINLLessThanTrueIdeal ; It's lower...
cmp IdealTrumpScore ; It's >= true ideal, but is it less than closest?
bpl GINLOut ; No, so we've got the closest so far
GINLSetNewIdeal
sta IdealTrumpScore
stx IdealTrumpNum
jmp GINLOut
GINLLessThanTrueIdeal
cmp IdealTrumpScore ; This trump is less than true ideal; can we get closer?
bpl GINLSetNewIdeal ; Yes!
GINLOut
dec T1
dex
bpl GINLLoop
rts
PickCardToPlay
; Now we've collected all the information about the hand we need to make
; a decision. "Player" refers to the player in the trick; i.e. player #2
; is the second person to play in the trick, the one immediately after
; the leader.
lda CardInTrickNum
cmp #$01 ; Is this for player #2?
PCTPPlayer2
bne PCTPPlayer3 ; No, keep checking
; Player 2: If it's possible to win the trick, do so with the highest
; possible non-trump or the trump closest to ideal, otherwise play the
; lowest valid card
PCTPP2a
lda HighWinnerNum
bmi PCTPPlayLow
lda IdealTrumpNum
bpl PCTPCardSelected
lda HighWinnerNum
bpl PCTPCardSelected
PCTPPlayLow
lda LowCardNum
bpl PCTPCardSelected
PCTPPlayer3
cmp #$02 ; Is this for player #3?
bne PCTPPlayer4 ; No, so it must be for player #4
; Player 3: If partner is winning with a queen or lower, or if an
; opponent is winning the trick, beat the trick just as player 2
; does, otherwise play the lowest valid card
lda OpponentsWinning ; Is opponent winning?
bne PCTPP2a ; Yes, try to beat it
lda TrickWinningScore ; Partner is winning, but high enough?
cmp #KingRankValue ; Is the winning card a king or better?
bmi PCTPP2a ; No, try to beat it
bpl PCTPPlayLow ; Yes, go under if possible
PCTPPlayer4
; Player 4: If partner is winning, play low, otherwise win with the lowest
; available winning card
lda OpponentsWinning ; Is opponent winning?
beq PCTPPlayLow ; No, so play low
lda LowWinnerNum ; Yes - can this hand win?
bmi PCTPPlayLow ; No, so play low
;bpl PCTPCardSelected ; Yes, play this card
PCTPCardSelected
clc
adc HandStartOffset
sta CardToPlayOffset
rts
; find the zero page address of the first and last cards of a player's hand
; x = hand (0=south, 1=west, 2=north, 3=east)
;
; returns: HandStartOffset = zero page address of first card of desired hand
; HandEndOffset = zero page address of last card of desired hand
GetHandOffsets
lda HandToStartOffset,x
sta HandStartOffset
clc
adc #CardsInHand-1
sta HandEndOffset
rts
; translate a paddle position into a selection of one of five cards
;
; returns: CursorPos = which card is selected (0-4)
GetSelection
ldx #$05
jsr MoveCursor
rts
; Change jack of trumps and jack of suit of same color as trumps to the right
; bower and left bower
;
; Requires that TrumpSuitMask be set prior to call
CreateBowers
lda TrumpSuitMask
ora #JackRankValue
sta RightBowerMask
eor #FlipColorSuitMask
sta LeftBowerMask
ldx #CardsInDeck-1
CBLoop
lda DeckStart,x
and #RankMask+#RealSuitMask ; compare against card information only
cmp RightBowerMask ; Is this card the jack of trump?
bne CBLB ; No, check if it is the other jack of the same color
lda TrumpSuitMask
ora #RightRankValue ; Grant the card the right bower rank
bne CBSet ; Will always be > 0, bne instead of jmp
CBLB
cmp LeftBowerMask ; Is this card the jack of the same color as trump?
bne CBLoopEnd ; No, it is not either bower
lda TrumpSuitMask ; By doing this we make the "real" suit trump while the
; displayed suit remains the original.
ora #LeftRankValue ; Grant the card the left bower rank
CBSet
sta T4
lda DeckStart,x
and #HideCardValue+#DispSuitMask
ora T4 ; Do not change whether card is hidden or shown
sta DeckStart,x
CBLoopEnd
dex
bpl CBLoop
rts
; Routines that get an image from a table
;
; a = image number out of the set
; x = offset to the addresses to receive the pointer
GetTrickImage
ldy #$04
bne GRI2
GetScoreImage
ldy #$03
bne GRI2
GetArrowImage
ldy #$02
bne GRI2
GetSuitImage
ldy #$01
bne GRI2
GetRankImage
ldy #$00
GRI2
clc
adc ImageBankOffsets,y
asl
sta T4
asl
clc
adc T4
adc #<RankImageStart
sta $00,x
lda #>RankImageStart
adc #$00
sta $01,x
rts
GetLetterImage
clc
adc #<LetterImageStart
sta $00,x
lda #>LetterImageStart
adc #$00
sta $01,x
rts
GetMessagePointer
tya
asl
asl
clc
adc #<MessageTableStart
sta $00,x
lda #>MessageTableStart
adc #$00
sta $01,x
rts
GetMessageImages
ldy #$04
MessageImageLoop
dey
sty T4
lda (MessagePtr),y
sta T3
tya
asl
clc
adc #ImgPtr1
tax
lda T3
jsr GetLetterImage
ldy T4
bne MessageImageLoop
rts
; All images are reversed since they are read by decrementing loops.
; routine for getting images and colors of a card
; a = card
; x = image pointer for rank
; y = image pointer for suit
; returns: a = color of card
GetCardGraphics
sta T1
stx T2
sty T3
and #RankMask
lsr
lsr
tay
ldx T2
jsr GetRankImage
lda T1
and #DispSuitMask
lsr
lsr
lsr
lsr
lsr
tay
ldx T3
jsr GetSuitImage
lda T1
bmi HideCard
and #RealSuitMask
tax
lda SuitToColorTable,x
rts
HideCard
lda #CardTableColor
rts
; routine to position a player
; original version by Erik Mooney in the Stella mailing list message
; "Re: [stella] sexp8.bin Multi-Japanese Sprites" from April 18, 1998
; (http://www.biglist.com/lists/stella/archives/199804/msg00170.html)
; modified to work on both player 0 and 1 and to take a hard-coded
; position value rather than look at a table (there is no motion in
; this game, so the table is not necessary)
; This must not cross a page boundary!
;
; a = position value - high nybble = fine position, low nybble =
; course position
; x = player number
; routine to draw a single card
; assumes ImgPtr1 and ImgPtr2 point to proper images, sprites are
; positioned, and so on
DrawSingleCard
ldy #$05
DrawCardLoop
sta WSYNC
lda (ImgPtr1),y
sta GRP0
lda (ImgPtr2),y
sta GRP1
dey
bpl DrawCardLoop
sta WSYNC
rts
; routine to draw two cards
; assumes ImgPtr1-4 point to proper images, sprites are positioned,
; and so on
DrawTwoCards
sta WSYNC
sta HMOVE
ldy #$05
DrawCardLoop2
nop
nop
ror T1
ror T1
lda (ImgPtr3),y
tax
lda (ImgPtr1),y
sta GRP0
stx GRP0
pha
lda (ImgPtr4),y
tax
lda (ImgPtr2),y
sta GRP1
nop
stx GRP1
pla
sta WSYNC
dey
bpl DrawCardLoop2
rts
; input: x = $00 for single-line, $01 for double
DrawBookkeeping
ldy #$05
stx T4
DrB1
ldx T4
DrB2
sta WSYNC
lda (ImgPtr1),y
sta GRP0
lda (ImgPtr2),y
sta GRP1
dex
bpl DrB2
dey
bpl DrB1
rts
; Six-digit score display
; original version by Robert Colbert in the Stella mailing list message
; "Re: [stella] Displaying scores - how?" from March 11, 1997
; (http://www.biglist.com/lists/stella/archives/199703/msg00219.html)
; Adapted to four-digit display
DrawMessageText
ldy #$05
loop2
sta WSYNC
sty T2
lda (ImgPtr1),y
sta GRP0
lda (ImgPtr2),y
sta GRP1
lda (ImgPtr3),y
tax
lda (ImgPtr4),y
tay
ror T1
lda $00
lda $00
stx GRP0
sty GRP1
ldy T2
dey
bpl loop2
rts
END_UTIL = *
org $fe00
echo *-END_UTIL, "bytes available in utility area 1: ", END_UTIL, "-", *-1
ImageBanks
; All images are reversed since they are read by decrementing loops.
LetterImageStart
LetterImageSpace
.byte %00000000
.byte %00000000
.byte %00000000
.byte %00000000
.byte %00000000
.byte %00000000
LetterImageD
.byte %01111100
.byte %01100110
.byte %01100110
.byte %01100110
.byte %01100110
.byte %01111100
LetterImageP
.byte %01100000
.byte %01100000
.byte %01111100
.byte %01100110
.byte %01100110
.byte %01111100
LetterImageS
.byte %00111100
.byte %00000110
.byte %00000110
.byte %00111100
.byte %01100000
.byte %00111100
LetterImageU
.byte %00111100
.byte %01100110
.byte %01100110
.byte %01100110
.byte %01100110
.byte %01100110
RankImageStart
RankImage9
.byte %00111100
.byte %01000110
.byte %00000110
.byte %00111110
.byte %01100110
.byte %00111100
RankImage10
.byte %11101110
.byte %01011011
.byte %01011011
.byte %01011011
.byte %11011011
.byte %01001110
RankImageJ
LetterImageJ
.byte %00111100
.byte %01100110
.byte %00000110
.byte %00000110
.byte %00000110
.byte %00001110
RankImageQ
LetterImageQ
.byte %00111010
.byte %01100100
.byte %01101010
.byte %01100110
.byte %01100110
.byte %00111100
RankImageK
LetterImageK
.byte %01100110
.byte %01100110
.byte %01101100
.byte %01111000
.byte %01101100
.byte %01100110
RankImageA
LetterImageA
.byte %01100110
.byte %01100110
.byte %01111110
.byte %01100110
.byte %00111100
.byte %00011000
RankImageLeft
.byte %11101100
.byte %10001010
.byte %10001010
.byte %10001100
.byte %10001010
.byte %10001100 ; "LB" used for debugging
RankImageRight
.byte %10101100
.byte %10101010
.byte %10101010
.byte %11001100
.byte %10101010
.byte %11001100 ; "RB" used for debugging
SuitImageStart
SuitImageHeart
.byte %00010000
.byte %00111000
.byte %01111100
.byte %11111110
.byte %11101110
.byte %01000100
SuitImageDiamond
.byte %00011000
.byte %00111100
.byte %01111110
.byte %01111110
.byte %00111100
.byte %00011000
SuitImageClub
.byte %00011000
.byte %01111110
.byte %11111111
.byte %00011000
.byte %00111100
.byte %00011000
SuitImageSpade
.byte %00111000
.byte %10111010
.byte %11111110
.byte %01111100
.byte %00111000
.byte %00010000
ArrowImageStart
ArrowImageSouth
.byte %00011000
.byte %00111100
.byte %01111110
.byte %11011011
.byte %00011000
.byte %00011000
ArrowImageWest
.byte %00110000
.byte %01100000
.byte %11111111
.byte %11111111
.byte %01100000
.byte %00110000
ArrowImageNorth
.byte %00011000
.byte %00011000
.byte %11011011
.byte %01111110
.byte %00111100
.byte %00011000
ArrowImageEast
.byte %00001100
.byte %00000110
.byte %11111111
.byte %11111111
.byte %00000110
.byte %00001100
ScoreImageStart
.byte %00000000
.byte %01110111
.byte %01010101
.byte %01010101
.byte %01010101
.byte %01110111
.byte %00000000
.byte %01110111
.byte %01010010
.byte %01010010
.byte %01010110
.byte %01110010
.byte %00000000
.byte %01110111
.byte %01010100
.byte %01010111
.byte %01010001
.byte %01110111
.byte %00000000
.byte %01110111
.byte %01010001
.byte %01010011
.byte %01010001
.byte %01110111
.byte %00000000
.byte %01110001
.byte %01010001
.byte %01010111
.byte %01010101
.byte %01110001
.byte %00000000
.byte %01110111
.byte %01010001
.byte %01010111
.byte %01010100
.byte %01110111
.byte %00000000
.byte %01110111
.byte %01010101
.byte %01010111
.byte %01010100
.byte %01110111
.byte %00000000
.byte %01110100
.byte %01010100
.byte %01010010
.byte %01010001
.byte %01110111
.byte %00000000
.byte %01110111
.byte %01010101
.byte %01010010
.byte %01010101
.byte %01110111
.byte %00000000
.byte %01110111
.byte %01010001
.byte %01010111
.byte %01010101
.byte %01110111
.byte %00000000
.byte %01110111
.byte %00100101
.byte %00100101
.byte %01100101
.byte %00100111
.byte %00000000
.byte %01110111
.byte %00100010
.byte %00100010
.byte %01100110
.byte %00100010
.byte %00000000
.byte %01110111
.byte %00100100
.byte %00100111
.byte %01100001
.byte %00100111
.byte %00000000
.byte %01110111
.byte %00100001
.byte %00100011
.byte %01100001
.byte %00100111
TrickImageStart
.byte %00000000
.byte %00000000
.byte %00000000
.byte %00000000
.byte %00000000
.byte %00000000
.byte %00000000
.byte %00000000
.byte %00000000
.byte %00000000
.byte %00000001
.byte %00000001
.byte %00000000
.byte %00000000
.byte %00000000
.byte %00000000
.byte %00000101
.byte %00000101
.byte %00000001
.byte %00000001
.byte %00000000
.byte %00000000
.byte %00000101
.byte %00000101
.byte %00000101
.byte %00000101
.byte %00000000
.byte %00000000
.byte %00000101
.byte %00000101
.byte %00000101
.byte %00000101
.byte %00000010
.byte %00000010
.byte %00000101
.byte %00000101
NewDeck
.byte #HideCardValue + #NineRankValue + #HeartSuitValue
.byte #HideCardValue + #TenRankValue + #HeartSuitValue
.byte #HideCardValue + #JackRankValue + #HeartSuitValue
.byte #HideCardValue + #QueenRankValue + #HeartSuitValue
.byte #HideCardValue + #KingRankValue + #HeartSuitValue
.byte #HideCardValue + #AceRankValue + #HeartSuitValue
.byte #HideCardValue + #NineRankValue + #DiamondSuitValue
.byte #HideCardValue + #TenRankValue + #DiamondSuitValue
.byte #HideCardValue + #JackRankValue + #DiamondSuitValue
.byte #HideCardValue + #QueenRankValue + #DiamondSuitValue
.byte #HideCardValue + #KingRankValue + #DiamondSuitValue
.byte #HideCardValue + #AceRankValue + #DiamondSuitValue
.byte #HideCardValue + #NineRankValue + #ClubSuitValue
.byte #HideCardValue + #TenRankValue + #ClubSuitValue
.byte #HideCardValue + #JackRankValue + #ClubSuitValue
.byte #HideCardValue + #QueenRankValue + #ClubSuitValue
.byte #HideCardValue + #KingRankValue + #ClubSuitValue
.byte #HideCardValue + #AceRankValue + #ClubSuitValue
.byte #HideCardValue + #NineRankValue + #SpadeSuitValue
.byte #HideCardValue + #TenRankValue + #SpadeSuitValue
.byte #HideCardValue + #JackRankValue + #SpadeSuitValue
.byte #HideCardValue + #QueenRankValue + #SpadeSuitValue
.byte #HideCardValue + #KingRankValue + #SpadeSuitValue
.byte #HideCardValue + #AceRankValue + #SpadeSuitValue
MessageTableStart
MessageBlank
.byte #<LetterImageSpace, #<LetterImageSpace
.byte #<LetterImageSpace, #<LetterImageSpace
MessageSelectAction
ChoiceToLetterTable
.byte #<LetterImageP, #<LetterImageU
.byte #<LetterImageA, #<LetterImageSpace
MessageSelectTrump
.byte #<SuitImageHeart, #<SuitImageDiamond
.byte #<SuitImageClub, #<SuitImageSpade
CursorPosToSelectorPos
.byte $94, $05, $76, $f6
BidTeamToTrumpPos
.byte $a2,$48
TrickToIdealTrump
.byte #TenRankValue + #TrumpScoreValue
.byte #QueenRankValue + #TrumpScoreValue
.byte #AceRankValue + #TrumpScoreValue
.byte #RightRankValue + #TrumpScoreValue
.byte #RightRankValue + #TrumpScoreValue
PlayerToPartnerTable
.byte $02, $03, $00, $01
HandToStartOffset
.byte $00, $05, $0a, $0f
ImageBankOffsets
.byte $00
.byte (#SuitImageStart-#RankImageStart)/6
.byte (#ArrowImageStart-#RankImageStart)/6
.byte (#ScoreImageStart-#RankImageStart)/6
.byte (#TrickImageStart-#RankImageStart)/6
SuitToColorTable
.byte #RedSuitColor, #RedSuitColor, #BlackSuitColor, #BlackSuitColor
NumTrumpsToStrength
.byte $00, $00, $00, $00, $04, $07
NumOffLoneAcesToStrength
.byte $00, $03, $05, $06
PotentialTrumpRankToStrength
; Since the bower masks haven't been set yet, the rank of the jack is
; still third-lowest. The GetTrumpCardStrength routine adjusts for the
; left bower, and since the input card is definitely trump, its jack
; rank gets the highest strength value.
.byte $01, $01, $08, $02, $02, $04
RankToTrumpsLeftTable
; These are masks used to remove a particular trump from the list of
; trumps left in a round. Notice that the third-from-last bit is always
; zero since the jack is promoted to a bower.
.byte %11111010, %11111001, %11111011, %11110011
.byte %11101011, %11011011, %10111011, %01111011
TrumpsLeftIndexTable
; These are used to translate a loop index into a bit of a byte. In
; this game, they are only for examining the TrumpsLeft bit array.
; The third value is intentionally zero since there is no jack rank
; in the trump suit.
.byte %00000001, %00000010, %00000000, %00001000
.byte %00010000, %00100000, %01000000, %10000000
; routine to generate a random number
; original version by Erik Mooney in the Stella mailing list message
; "Re: [stella] demo update: PCMSD20.BIN" from April 14, 1997
; (http://www.biglist.com/lists/stella/archives/199704/msg00136.html)
; requires four memory locations to be reserved for generation
;
; returns: a = random number
RandomBit
lda rand4 ; +3 = 3
asl ; +2 = 5
asl ; +2 = 7
asl ; +2 = 9
eor rand4 ; +3 = 12 ;new bit is now in bit 6 of A
asl ; +2 = 14
asl ; +2 = 16 ;new bit is now in carry
rol rand1 ; +5 = 21 ;shift new bit into bit 0 of register
;bit 7 goes into carry
rol rand2 ; +5 = 26 ;shift old bit 7 into bit 8, etc.
rol rand3 ; +5 = 31
rol rand4 ; +5 = 36
rts ; +5 = 41
RandomByte
ldx #8 ; +2
RandomByte1
jsr RandomBit ; +6+41 = +47
dex ; +2
bne RandomByte1 ; +3 when taken (7 times), +2 when not (1 time)
; Total after all loops is 2+(47+2+3)*7+(47+2+2)=417
lda rand1 ; +3 = 420
rts ; +5 = 425, or roughly 5.6 scan lines
PositionPlayer
sta WSYNC
ror T1 ; waste 5 cycles
sta HMP0,x
and #$0f
tay
P0
dey
bpl P0
sta RESP0,x
; Rather than WSYNC and HMOVE now, let the calling routine do it. If both
; players are positioned in succession, this saves a scanline.
rts
; This and other free space calculations were taken from Brian Watson's
; Poker Squares. See "[stella] Poker solitaire source, versions 012 & 014"
; from November 26, 2001.
; (http://www.biglist.com/lists/stella/archives/200111/msg00421.html)
END_DATA = *
org $fffc
echo *-END_DATA, "bytes available in image and table area: ", END_DATA, "-", *-1
.word CartStart
.word CartStart
| Current Thread |
|---|
|
| <- Previous | Index | Next -> |
|---|---|---|
| Re: [stella] Marble Craze almost co, Paul Slocum | Thread | Re: [stella] Euchre: light on the h, zu03776 |
| [stella] dasm.doc, Ruffin Bailey | Date | Re: [stella] Kirk tutorial question, Gary Szwiec |
| Month |