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" ""
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