|
Subject: [stella] Euchre: long winding road From: "Erik J. Eid" <eeid@xxxxxxxxx> Date: Sun, 14 Apr 2002 17:23:45 -0400 |
;
; Euchre game program for the Atari 2600 video computer system
;
; Copyright 2001 by Erik Eid (eeid@xxxxxxxxx)
;
; Last update: April 14, 2002
;
; Compiled with the dasm assembler 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
Team1Color = $88
Team2Color = $38
TableRegionColor = $d4
CardTableColor = $0f
RedSuitColor = $36
BlackSuitColor = $00
MessageRegionDisplayColor = $22
MessageRegionChoiceColor = $84
MessageTextColor = $1c
CursorColor = $82
TrumpDisplayColor = %00101000
RankMask = %01110000 ; Bit mask for rank of a card
DispSuitMask = %00001100 ; 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 = %00001111 ; 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 = %01110000
LeftRankValue = %01100000
AceRankValue = %01010000
KingRankValue = %01000000
QueenRankValue = %00110000
JackRankValue = %00100000
TenRankValue = %00010000
NineRankValue = %00000000
HeartSuitValue = %00000000
DiamondSuitValue = %00000101
ClubSuitValue = %00001010
SpadeSuitValue = %00001111
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
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 = $44
MessageP1Pos = $c4
NoCursorPos = $FF
MsgNumBlank = $00
MsgNumDeal = $01
MsgNumGameOver = $02
MsgNumEuchre = $03
MsgNumCopyright = $04
MsgNumByline = $05
MsgNumSelectAction = $06
MsgNumSelectTrump = $07
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
; 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
ImgPtr5 ds 2
ImgPtr6 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
Overlay ds 19
DeckStart = SouthHand
Upcards = SouthCard
seg.u vars
org Overlay
PotentialTrump ds 1
Upcard ds 1
DeclinedSuit ds 1
HighPsblTrks ds 1
BestSuit ds 1
PossibleTricks ds 1
CardScore ds 1
NumInSuit ds 1
NumTrumps 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
; 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.
jsr ShuffleDeck
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
ldx Choice
inx ; Change NoChoice (255) to 0
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_ThreeClose
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
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
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 HighPsblTrks
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 PossibleTricks
jmp PB2CheckIfHigh
PB2Declined
lda #$00
PB2CheckIfHigh
cmp HighPsblTrks ; Is the number of possible tricks with the suit
; being checked as trump better than the best
; suit so far?
bcc PB2NextSuit ; No, carry on to the next suit
sta HighPsblTrks ; Yes, store this number and set the best suit
lda T4
sta BestSuit
PB2NextSuit
dec T4
bpl PB2FindBestSuit
lda HighPsblTrks
sta PossibleTricks
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
jsr RefreshDeck
rts
PerformShuffle
; Note that the call to ShuffleDeck 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
ldx #$04
DealLoop
lda SouthHand,x
and #ShowCardMask
sta SouthHand,x
dex
bpl DealLoop
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 #MsgNumGameOver
sta MessageNum
lda #FramesLongWait
sta FrameCounter
rts
PerformGameOver
lda TriggerTrack
cmp #TriggerOn
bne PGOAttract
jsr StartNewGame
jmp ProgStart
PGOAttract
lda FrameCounter
beq PGOChange
dec FrameCounter
rts
PGOChange
lda #FramesLongWait
sta FrameCounter
inc MessageNum
lda MessageNum
cmp #MsgNumByline+1
bcc PGOEnd
lda #MsgNumEuchre
sta MessageNum
PGOEnd
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
ContinuePlaying
lda #StagePlaying
sta Stage
lda Turn
beq CP1
sta CursorPos ; Value for south and cursor are both $00
CP1
lda #$00
sta CardInTrickNum
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 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 ; This is a stub that simply picks the nth card from
; a computer player's hand, where n is the number of
; the current trick (0-4)
jsr GetHandOffsets
lda TrickNum
clc
adc HandStartOffset
sta CardToPlayOffset
jmp PPPlayCard
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 #FramesShortWait
sta FrameCounter
rts
PerformAddToTricks
dec FrameCounter
beq PAT1
rts
PAT1
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
and #CardPlayedMask ; Has the card already been played?
cmp #CardPlayedValue
bne 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 NumVoids
sta LowTrumpFactor
sta OtherFactor
sta HasRight
sta HasLeft
sta HasTrumpAce
lda PotentialTrump
ora #JackRankValue
; and #RankSuitMask
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
and #RankMask+#RealSuitMask
cmp RightBowerMask
beq AHIsRight
and #RankMask
cmp #AceRankValue
beq AHIsAce
cmp #QueenRankValue
bmi AHLowTrump
inc LowTrumpFactor ; The omission of a branch is intentional. If the
; trump is a king or queen, LowTrumpFactor will be
; incremented twice.
AHLowTrump
inc LowTrumpFactor
bne AHCL1
AHIsRight
inc HasRight
bne AHCL1
AHIsAce
inc HasTrumpAce
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
inc NumTrumps
inc HasLeft
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 #$03
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
bne AHNotVoid ; If a <> 0, we had a card in the suit
inc NumVoids ; If a = 0, we were void in the suit
bne AHCL2
AHNotVoid
lda HasAce
beq AHCL2 ; If a = 0, we do not have any aces in the suit
lda NumInSuit
cmp #$02 ; Do we have the ace plus just one other card?
beq AHAcePlus ; Yes, so the ace might still take one.
cmp #$01 ; Did we have just one card in the suit?
bne AHCL2 ; No, so we didn't get an off-suit lone ace
lda PotentialTrump ; We have an off-suit lone ace...
eor #FlipColorSuitMask
cmp T1 ; ...but is it the same color as trump?
bne AHOffColorAce ; No, so there's a good chance it will take a trick.
AHAcePlus
inc OtherFactor ; Yes, but it may be possible given how the hand plays out.
bne AHCL2
AHOffColorAce
inc NumOffLoneAces
AHCL2
dey
bpl AHCountLoop2
; Now calculate the number of tricks this hand will probably take.
GetPossibleTricks
lda #$00
sta PossibleTricks
lda Stage
cmp #StageBidding1
beq PTExamineUpcard
lda #$00 ; If this is the second round of bidding, there is no
sta UpcardFactor ; upcard to consider.
beq PTRight
PTExamineUpcard
lda Dealer
eor Turn ; Bit 0 will be 1 if the upcard goes to an opponent
and #$01 ; Does upcard belong to opponent?
bne PTEUOpp
lda Dealer ; No, the upcard goes to my team...
cmp Turn ; ... but does it go to my partner?
bne PTRight ; Yes, so the upcard's effect is uncertain.
lda NumTrumps ; The upcard goes to the bidder. Unless the hand is
; full of trumps, or there are four and an off-trump-
; color lone ace, the upcard potentially adds a
; likely trick.
cmp #$05
bpl PTRight
cmp #$04
bmi PTEU1
lda NumOffLoneAces
bne PTRight
PTEU1
lda #$01
sta UpcardFactor
bne PTRight
PTEUOpp
lda NumTrumps ; The upcard going to the opponent will be a likely
; trick for their team unless the bidder already has
; four or five trumps and the upcard isn't rather low.
cmp #$04
bpl PTRight
lda Upcard
cmp #JackRankValue
bmi PTRight
PTEUOpp2
lda #$ff ; Save a -1 to "add" to the count of likely tricks.
sta UpcardFactor
PTRight
lda HasRight ; Do we have the right bower?
beq PTLeft ; No, move on to next check
inc PossibleTricks ; Yes, this is a guaranteed trick
PTLeft
lda HasLeft ; Do we have the left bower?
beq PTAce ; No, move on to next check
lda NumTrumps
clc
adc UpcardFactor
cmp #$02 ; Is left bower the only trump? (If the upcard goes to
; the opponent, it may cancel one of ours.)
bmi PTAce ; Yes, so we can't count it.
inc PossibleTricks ; No, so the left bower should take a trick.
PTAce
lda HasTrumpAce ; Do we have the ace of trump?
beq PTLowTrumps ; No, move on to next check
lda NumTrumps
clc
adc UpcardFactor
cmp #$03 ; Is the ace one of only two trumps? (If the upcard
; goes to the opponent, it may cancel one of ours.)
bmi PTLowTrumps
inc PossibleTricks ; No, so the ace should take a trick.
PTLowTrumps
lda LowTrumpFactor ; We counted king and queen of trump as "two" and 10
lsr ; and 9 of trump as "one". Cut the total in half and
clc ; add this to our likely tricks.
adc PossibleTricks
sta PossibleTricks
PTOther
lda OtherFactor ; Much like with low trumps, count half of our "other"
lsr ; good cards as potential tricks.
clc
adc PossibleTricks
sta PossibleTricks
PTUpcard
lda PossibleTricks
clc
adc UpcardFactor ; Finally count the upcard as one of ours... or theirs
sta PossibleTricks
PTOffColorAces
lda PossibleTricks ; Each ace that is alone in a suit that is not trump or
; the same color as trump will probably take a trick.
clc
adc NumOffLoneAces
sta PossibleTricks
;PTTwoSuited
; lda NumVoids ; Do we have only two suits in this hand? (Since there
; cmp #$02 ; are four suits, two voids implies two remaining suits.)
; bne PTEnd ; No, so move on...
; lda NumTrumps ; Yes!
; cmp #$02 ; Do we have two or more trump?
; bmi PTEnd ; No, so there'll be no help.
; lda NumOffLoneAces ; Do we only have an ace in the non-trump suit?
; bne PTEnd ; Yes, so the ace will likely take one anyway.
; inc PossibleTricks ; Being void in two suits, with two or three trumps,
; ; gives us a good opportunity to use a trump that might
; ; otherwise be taken.
PTEnd
rts
DecideBid
lda PossibleTricks
bmi DB2a ; If we got a negative count (zero with upcard going
; to opponent), make sure to pass! Don't allow a low
; negative number to be treated as greather than five!
cmp #$05 ; Will this hand take five tricks?
bmi DB1 ; No, so keep considering.
lda #ChoiceAlone ; Yes! Go alone!
bne DBEnd ; Knowing a <> 0, a bne is a savings over a jmp
DB1
cmp #$03 ; Will this hand take exactly three tricks?
bne DB2 ; No, keep checking.
lda #ChoiceCall ; With three tricks, call, but don't go alone.
bne DBEnd
DB2
cmp #$02 ; Will this hand take zero or one tricks?
bpl DB3 ; No, keep checking.
DB2a
lda #ChoicePass ; This is a weak hand, so pass.
beq DBEnd
DB3
bne DB4 ; It's not two tricks, so it's four...
lda Turn ; This hand will take two tricks.
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
DB4
lda Dealer ; If we got here, then our hand is likely to take four
clc ; tricks. Go alone if we lead (because then we can
adc #$01 ; pull out trump easily), otherwise leave our partner
and #PlayersMask ; in so they can provide the fifth tricks for a two-
cmp Turn ; point march.
beq DB4a
lda #ChoiceCall
bne DBEnd
DB4a
lda #ChoiceAlone
DBEnd
sta Choice
rts ; Whew!
; 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 ; No need to clear carry; previous addition cannot
; be > 255
sta HandEndOffset
rts
HandToStartOffset
.byte #$00, #$05, #$0a, #$0f
; 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
ImageBankOffsets
.byte $00
.byte (#SuitImageStart-#RankImageStart)/6
.byte (#ArrowImageStart-#RankImageStart)/6
.byte (#ScoreImageStart-#RankImageStart)/6
.byte (#TrickImageStart-#RankImageStart)/6
GetLetterImage
clc
adc #<LetterImageStart
sta $00,x
lda #>LetterImageStart
adc #$00
sta $01,x
rts
GetMessagePointer
tya
asl
sta T1
asl
clc
adc T1
clc
adc #<MessageTableStart
sta $00,x
lda #>MessageTableStart
adc #$00
sta $01,x
rts
GetMessageImages
ldy #$06
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 to shuffle the deck
RefreshDeck
ldx #CardsInDeck-1
RD1
lda NewDeck,x
sta DeckStart,x
dex
bpl RD1
rts
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
rts
; org $fc00
; 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
; 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
lsr
lsr
tay
ldx T2
jsr GetRankImage
lda T1
and #DispSuitMask
lsr
lsr
tay
ldx T3
jsr GetSuitImage
lda T1
bmi HideCard
and #RealSuitMask
tax
lda SuitToColorTable,x
rts
HideCard
lda #CardTableColor
rts
SuitToColorTable
.byte #RedSuitColor, #RedSuitColor, #BlackSuitColor, #BlackSuitColor
END_UTIL1 = *
org $fd00
echo *-END_UTIL1, "bytes available in utility area 1: ", END_UTIL1, "-", *-1
; 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)
;
; a = position value - high nybble = fine position, low nybble =
; course position
; x = player number
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
; 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)
DrawMessageText
lda #$01
sta VDELP0
sta VDELP1
ldy #$05
sty T2
loop2
ldy T2
lda (ImgPtr1),y
sta GRP0
sta WSYNC
lda (ImgPtr2),y
sta GRP1
lda (ImgPtr3),y
sta GRP0
lda (ImgPtr4),y
sta T1
lda (ImgPtr5),y
tax
lda (ImgPtr6),y
tay
lda T1
sta GRP1
stx GRP0
sty GRP1
sta GRP0
dec T2
bpl loop2
rts
END_UTIL2 = *
org $fe00
echo *-END_UTIL2, "bytes available in utility area 2: ", END_UTIL2, "-", *-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
LetterImageC
.byte %00111100
.byte %01100110
.byte %01100000
.byte %01100000
.byte %01100110
.byte %00111100
LetterImageD
.byte %01111100
.byte %01100110
.byte %01100110
.byte %01100110
.byte %01100110
.byte %01111100
LetterImageE
.byte %01111110
.byte %01100000
.byte %01100000
.byte %01111000
.byte %01100000
.byte %01111110
LetterImageH
.byte %01100110
.byte %01100110
.byte %01100110
.byte %01111110
.byte %01100110
.byte %01100110
LetterImageL
.byte %01111110
.byte %01100000
.byte %01100000
.byte %01100000
.byte %01100000
.byte %01100000
LetterImageO
.byte %00111100
.byte %01100110
.byte %01100110
.byte %01100110
.byte %01100110
.byte %00111100
LetterImageP
.byte %01100000
.byte %01100000
.byte %01111100
.byte %01100110
.byte %01100110
.byte %01111100
LetterImageR
.byte %01100110
.byte %01100110
.byte %01100110
.byte %01111100
.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
LetterImageV
.byte %00010000
.byte %00111000
.byte %01101100
.byte %11000110
.byte %11000110
.byte %11000110
CopyImage01
.byte %00000000
.byte %11101110
.byte %10001010
.byte %10001110
.byte %10000000
.byte %11100000
CopyImage02
.byte %10001110
.byte %10000010
.byte %11101110
.byte %10101010
.byte %11101010
.byte %00000000
CopyImage03
.byte %00000111
.byte %10010001
.byte %10010111
.byte %11010101
.byte %00000111
.byte %00010000
CopyImage04
.byte %00000000
.byte %01010011
.byte %01010010
.byte %01110010
.byte %01000111
.byte %01000010
CopyImage05
.byte %00000000
.byte %01110111
.byte %01000101
.byte %01110101
.byte %00010101
.byte %01110111
CopyImage06
.byte %00000000
.byte %01110111
.byte %01010010
.byte %01010010
.byte %01010110
.byte %01110010
BylineImage01
.byte %00001110
.byte %11100010
.byte %10101110
.byte %11101010
.byte %10001010
.byte %10000000
BylineImage02
.byte %00000000
.byte %01110100
.byte %01000100
.byte %01100110
.byte %01000000
.byte %01110000
BylineImage03
.byte %00000000
.byte %10101001
.byte %10101001
.byte %10110001
.byte %00101001
.byte %10100001
BylineImage04
.byte %00000000
.byte %11010111
.byte %00010101
.byte %10010111
.byte %00000001
.byte %11010001
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, #<LetterImageSpace
.byte #<LetterImageSpace, #<LetterImageSpace, #<LetterImageSpace
MessageDeal
.byte #<LetterImageSpace, #<LetterImageD, #<LetterImageE
.byte #<LetterImageA, #<LetterImageL, #<LetterImageSpace
MessageGameOver
.byte #<LetterImageSpace, #<LetterImageO, #<LetterImageV
.byte #<LetterImageE, #<LetterImageR, #<LetterImageSpace
MessageEuchre
.byte #<LetterImageE, #<LetterImageU, #<LetterImageC
.byte #<LetterImageH, #<LetterImageR, #<LetterImageE
MessageCopyright
.byte #<CopyImage01, #<CopyImage02, #<CopyImage03
.byte #<CopyImage04, #<CopyImage05, #<CopyImage06
MessageByline
.byte #<LetterImageSpace, #<BylineImage01, #<BylineImage02
.byte #<BylineImage03, #<BylineImage04, #<LetterImageSpace
MessageSelectAction
ChoiceToLetterTable
.byte #<LetterImageSpace, #<LetterImageP, #<LetterImageU
.byte #<LetterImageA, #<LetterImageSpace, #<LetterImageSpace
MessageSelectTrump
.byte #<LetterImageSpace, #<SuitImageHeart, #<SuitImageDiamond
.byte #<SuitImageClub, #<SuitImageSpade, #<LetterImageSpace
CursorPosToSelectorPos
.byte $94, $05, $76, $f6
BidTeamToTrumpPos
.byte $a2,$48
; 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
Attachment:
Euchre.bin
Description: Binary data
"Cartridge.MD5" "01264c091efc27ce23e43a6aa5cfd89a" "Cartridge.Name" "Euchre (April 14, 2002 pre-release)" "Cartridge.Manufacturer" "Erik Eid" "Cartridge.Rarity" "New Release" "Cartridge.Type" "4K" "Controller.Left" "Joystick" "Display.Format" "NTSC" ""
| Current Thread |
|---|
|
| <- Previous | Index | Next -> |
|---|---|---|
| Re: [stella] ideas.., Thomas Jentzsch | Thread | [stella] RAM carts?, Ruffin Bailey |
| Re: [stella] ideas.., Ben Larson | Date | [stella] RAM carts?, Ruffin Bailey |
| Month |