;---------------------------------------- ; TriMounts 86 v 0.1 ; TI-86 port by Andreas Finne with permission ; a_finne@hotmail.com ; Date: 08/22/1998 ;---------------------------------------- ; All code and comments are Josh Pieper's ; All I did was to translate it to the 86. ; To the next version, I will try to optimize ; the code a little. ; Now the word over to Josh. ;---------------------------------------- ; ;; v 0.2 TriMounts, (c) 1996 Josh Pieper ;; josh@nemonet.com ;; Feel free to distribute this file, just don't change it ;; in any way. ;; This code is horribly unoptimized and in future versions ;; I will condense it a bit. ;; Some of the comments are outdated, I will fix them ;; when I have some time. ;; Variables, SEED is for the Random Number Engine ;; CARDS is the deck of cards ;; CINDEX is the index to the top card of the deck ;; PEAK is the matrix holding the cards in trimounts positions ;; MONEY is a count of your current money ;; PILE has the current card on top of the pile ;; STREAK has the number of hits in a row w/o pressing enter ;; PKS has the number of peaks hit, used to determine final amount ;; TEMPSTR is used to display the amount of money #include "asm86.h" #include "ti86asm.inc" randvar = $C0F9 TEMP = $C0FB CARDS = $C0FD CINDEX = $C131 MINDEX = $C133 ;; 4x23 matrix for storing cards PEAK = $C135 PILE = $C193 STREAK = $C195 PKS = $C196 CL = $C197 TEMP2 = $C198 TEMP3 = $C19A TEMPSTR = $C19D .org _asm_exec_ram nop jp Start .dw $0000 .dw Description Description: .db "TriMounts 86 v0.1",0 ;; Clear screen and display title Start: call _flushallmenus call _runindicoff call _clrLCD ;; Clear the screen res 1,(iy+$0D) ld a,0 ;TriMounts 86 ld (_curRow),a ld a,2 ld (_curCol),a ld hl,Title1 call _puts ;; Rom call to display zero terminated string ld bc,12*256+27 ld (_penCol),bc call _vputs ;; Last call automaticly increased hl to next str ld bc,18*256+31 ld (_penCol),bc call _vputs ld bc,28*256+20 ld (_penCol),bc call _vputs ld bc,34*256+28 ld (_penCol),bc call _vputs ld a,6 ;2nd reset ld (_curRow),a ld a,1 ld (_curCol),a call _puts ld a,3 ;Enter start ld (_curCol),a ld a,7 ld (_curRow),a call _puts ;; Wait for enter to be pressed ;; This is where we will get our seed for the random number engine. ld bc,$0 KeyWait1: call GET_KEY ; Wait for key inc bc cp 54 jr z,ClrStats ; Counter is incremented for each pass of the cp $9 ; loop and is used as the seed for the random jr z, EnterPressed ; number generator jr KeyWait1 ClrStats: ld hl,HIGHSTRK ld a,0 ld (hl),0 ld hl,0 call PutMoney jr KeyWait1 EnterPressed: ld a,c ld (randvar),a ;; Fill the deck with four of each card ;; This is done with a nested loop call _clrLCD ; Display status messaqe ld a,7 ld (_curRow),a ld a,2 ld (_curCol),a ld hl,Msg1 call _puts ld hl,CARDS ld a,13 ODealLp: dec a ld b,4 IDealLp: ld (hl),a inc hl djnz IDealLp cp $0 jr nz, ODealLp ;; This code was a last minute addition to allow the player ;; to see their money without actually having to start a ;; game ld a,51 ld (CINDEX),a ld a,0 ld (CL),a call _clrLCD jp DisplayStats NewGame: ld a,30 ld (CINDEX),a ;Set the Deck counter ;This is where we go to start new game. ld (CL),a ld b,92 ;Fill the PEAK matrix with 13's ld hl,PEAK FlLoop: ld (hl),13 inc hl djnz FlLoop ;; Now that the deck is filled we must shuffle it. ld b,255 ; Shuffling is done by the following TI-BASIC ShufLp: ; code: rand->a push bc ; rand->b call Random ; CARDS(A)->temp ld b,h ; CARDS(B)->CARDS(A) ld c,l ; temp->CARDS(B) call Random ; This is repeated 255 times to get a good ld d,h ; shuffle. ld e,l ld hl,CARDS add hl,bc ld a,(hl) ld hl,CARDS add hl,de ld d,(hl) ld (hl),a ld hl,CARDS add hl,bc ld (hl),d pop bc djnz ShufLp ;; Deal the deck into the PEAK matrix. ;; bc will be the index for the Tpos array and for the CARDS list ;; when it == 30 time to quit ld a,14 ; This uses a list to determine which indices ld (TEMP),a ; of the PEAKS matrix get cards. It just ld bc,0 ; runs through the list and puts the next DealLoop: ; card in the appropriate cell. ld hl,CARDS ; 14 is added to the first 18 cards so that they add hl,bc ; appear as #'s on the screen. The 13's we ld a,(hl) ; filled in earlier appear as spaces. ld hl,TEMP add a,(hl) ld hl,TPos add hl,bc ld e,(hl) ld d,0 ld hl,PEAK add hl,de ld (hl),a inc bc ld a,18 cp c jr nz, SkipChng ld a,0 ld (TEMP),a SkipChng: ld a,30 cp c jr nz,DealLoop ;; Display the deck in TriMounts format ;; the X and Y pos are in the temp variable ;; de is the index to PEAK ;; b is a counter of the number of pos's to be read ;; should be displayed call _clrLCD ;Clear the screen ld b,5 ld c,6 ld (TEMP),bc ld b,92 ; cycle through the matrix indicing its contents ld de,0 ; with the Nums string so that the cards appear AnDispLoop: ; as A-K push bc ld hl,PEAK add hl,de ld a,(hl) ld hl,Nums ld c,a ld b,0 add hl,bc ld bc,(TEMP) ld a,b ld (_penCol),a ld a,c ld (_penRow),a ld b,1 call _vputsn SkipDisp: inc de ld bc,(TEMP) ld a,b add a,5 ld b,a cp $78 jr nz, BefKeyWait4 ld b,5 ld a,c add a,6 ld c,a BefKeyWait4: ld (TEMP),bc pop bc djnz AnDispLoop ld a,0 ld (STREAK),a ld (PKS),a ld c,4 ; c hold the current x pos of pointer ld hl,CARDS ld a,(CINDEX) ld e,a ld d,0 add hl,de ld a,(hl) ld (PILE),a DisplayStats: push bc ; save current x pos ;; Now we'll show the rest of the Screen ld a,44 ; Display the stats at the bottom ld (_penRow),a ; As well as the reminder on keys. ld a,10 ld (_penCol),a ld hl,Scrn1 ; Display "Money:" call _vputs ;Display zero-string, menu ld a,44 ld (_penRow),a ; Display "Pile:" ld a,67 ld (_penCol),a call _vputs ld a,58 ld (_penRow),a ld a,10 ; Display help at bottom ld (_penCol),a call _vputs ld a,51 ld (_penRow),a ; Display "Cur. Streak:" ld a,10 ld (_penCol),a call _vputs ld a,51 ld (_penRow),a ld a,67 ; Display "Longest Streak:" ld (_penCol),a call _vputs ld de,TEMPSTR ld a,(STREAK) ld l,a ld h,0 call CONV_HL_STR ld a,51 ld (_penRow),a ld a,40 ld (_penCol),a ld b,6 ld hl,TEMPSTR call _vputsn ld de,TEMPSTR ld hl,HIGHSTRK ld a,(hl) ld l,a ld h,0 call CONV_HL_STR ld a,51 ld (_penRow),a ld a,100 ld (_penCol),a ld b,6 ld hl,TEMPSTR call _vputsn call GetMoney ld de,TEMPSTR ; Use my CONV_HL_STR proc to convert hl to a call CONV_HL_STR ; outputted in menu text. (Otherwise I would ld a,40 ; have used D_HL_DECI) ld (_penCol),a ld a,44 ld (_penRow),a ld b,6 ld hl,TEMPSTR call _vputsn ;Display length-string, menu ld a,(PILE) ld e,a ld d,0 ld hl,Nums add hl,de ld a,87 ld (_penCol),a ld a,44 ld (_penRow),a ld b,1 call _vputsn ;; Here is where we get the card that the user want to remove. ;; c holds the x pos of the pointer. pop bc ;retrieve current xpos GetInput: ld a,32 ld (_penRow),a ld a,c ld (_penCol),a ld a,6 ld (TEMP),a ld b,1 ld hl,TEMP call _vputsn WaitForKey: call GET_KEY cp $0 jr z, WaitForKey cp K_EXIT jp z,TentEGme cp 2 jr z,Move cp 3 jr z,Move cp K_SECOND jp z,TryClrCard cp K_MORE jp z,PutCardOnPile cp K_ENTER jp z,TentNGme jr WaitForKey ;; Right here is where we erase the old pointer. ;; I was going to use direct memory access, but it kept ;; locking up the calculator!! Move: push af ld a,32 ld (_penRow),a ld a,c ld (_penCol),a ld b,5 RemOld: ld a,32 call _vputmap djnz RemOld pop af cp 2 jr z,Left cp 3 jr z,Right ;; Now we change c to point to the new cursor. Left: ld a,c sub 5 ld c,a cp 255 jr nz, GetInput ld c,114 jr GetInput Right: ld a,c add a,5 ld c,a cp 119 jr nz, GetInput ld c,4 jr GetInput TentNGme: call CancelGame cp 0 jp z,DisplayStats call _clrLCD jp NewGame TentEGme: call CancelGame cp 0 jp z,DisplayStats call Save set 1,(iy+$0D) ; Restoring the 'update textshadow' flag call _homeup call _clrScrn ret ;Thanks to Jimmy Mardell Save: ld hl,ProgName ; All this stuff is to make sure the highstreak rst 20h ; and cash are stored in the variable rst 10h ex de,hl ; HL -> start of variable ld a,b ld de,HIGHSTRK-$D748+4 ; DE = relative offset to stuff to store (-4) add hl,de adc a,0 ; Next block if necessary ld de,HIGHSTRK ; DE = start of bytes to copy ld b,3 ; 3 bytes to copy RepCopy: push af push hl call $46C3 ld a,(de) ; Read ld (hl),a ; And save it in the real variable pop hl pop af call $4637 inc de djnz RepCopy ret ; PutCardOnPile: push bc ld bc,5 ld a,(CINDEX) inc a cp 52 jr nz, SkipChng2 ld a,51 ld bc,0 SkipChng2: ld (CINDEX),a ld e,a ld d,0 ld hl,CARDS add hl,de ld a,(hl) ld (PILE),a call GetMoney sbc hl,bc call PutMoney ld a,0 ld (STREAK),a pop bc jp DisplayStats TryClrCard: ld a,(CL) cp $0 jp z,GetInput push bc ld b,c inc b ld d,0 DivLoop: ld a,b ld b,4 sbc a,b ld b,a inc d djnz DivLoop ld a,68 add a,d ld e,a ld d,0 ld hl,PEAK add hl,de ld de,23 ld bc,$0500 ld (TEMP),bc ld b,4 ld a,5 ScanLoop: ld a,(hl) add a,243 jr c,SkipSet ld (TEMP),bc ld (MINDEX),hl SkipSet: scf ccf sbc hl,de djnz ScanLoop ld bc,(TEMP) ld a,b cp 5 jr nz, PosGood pop bc jp GetInput PosGood: ld hl,(MINDEX) ld a,(hl) ld b,a ld a,(PILE) add a,0 sub b cp 255 jr z,Good cp 1 jr z,Good cp 12 jr z,Good cp 244 jr z,Good pop bc jp GetInput Good: ; Check for the top of each peak ld a,(hl) ld (PILE),a ld bc,(TEMP) ld a,1 cp b ld a,0 ld (TEMP3),a jr nz, NotAPeak ld a,1 ld (TEMP3),a ld a,(PKS) inc a ld (PKS),a cp 3 jr nz, NotLastPeak ld de,30 call GetMoney add hl,de call PutMoney jr NotAPeak NotLastPeak: ld de,15 call GetMoney add hl,de call PutMoney NotAPeak: ld a,(CL) ;Update Streaks,money, and cards left dec a ld (CL),a ld a,(STREAK) inc a ld (STREAK),a ld hl,HIGHSTRK ld d,a ld a,(hl) ld e,a ld a,255 add a,0 sub e add a,d jr nc,NotHighStreak ld a,(STREAK) ld (hl),a NotHighStreak: ld a,(STREAK) ld e,a ld d,0 call GetMoney add hl,de call PutMoney ld hl,(MINDEX) ;Set PEAKS as visited this card ld (hl),13 ld bc,(TEMP) ;Blank out card on screen ld e,6 ld d,0 call Mult ld a,l ld (_penRow),a pop bc ld a,c push bc ld (_penCol),a ld b,5 ClearChar: ld a,32 call _vputmap djnz ClearChar ld a,(TEMP3) ; If card was at top cp 1 ; there won't be any cards above jp z,DoneChecking ; to check ;Now we have to check if card above can be cleared ld hl,(MINDEX) dec hl dec hl ld a,(hl) cp 13 jr nz,CheckOnlyRight ld de,22 add a,0 sbc hl,de ld a,(hl) cp 13 jr z,CheckOnlyRight sub 14 ld (hl),a ld (TEMP2),hl ld bc,(TEMP) ;Show new card out card on screen dec b ld e,6 ld d,0 call Mult ld a,l ld (_penRow),a pop bc ld a,c sub 4 ld (_penCol),a push bc ld hl,(TEMP2) ld a,(hl) ld hl,Nums ld e,a ld d,0 add hl,de ld a,(hl) call _vputmap CheckOnlyRight: ld hl,(MINDEX) inc hl inc hl ld a,(hl) cp 13 jr nz,DoneChecking ld de,24 add a,0 sbc hl,de ld a,(hl) cp 13 jr z,DoneChecking sub 14 ld (hl),a ld (TEMP2),hl ld bc,(TEMP) ;Show new card out card on screen dec b ld e,6 ld d,0 call Mult ld a,l ld (_penRow),a pop bc ld a,c add a,5 ld (_penCol),a push bc ld hl,(TEMP2) ld a,(hl) ld hl,Nums ld e,a ld d,0 add hl,de ld a,(hl) call _vputmap DoneChecking: pop bc jp DisplayStats ; Ask user if they want to cancel this game ; Will lose $5 for every card left on the board ; returns a=1 if cancel game is requested ; returns a=0 if cancel game is not requested CancelGame: push bc push de push hl ld a,(CL) cp $0 jr nz, NotZero ld a,1 call ClearStatus pop hl pop de pop bc ret NotZero: call ClearStatus ld hl,AreSure ld a,51 ld (_penRow),a ld a,10 ld (_penCol),a call _vputs ld a,58 ld (_penRow),a ld a,10 ld (_penCol),a call _vputs ld a,(CL) ld b,a ld e,5 ld d,0 call Mult ld (TEMP),hl ld de,TEMPSTR call CONV_HL_STR ld hl,TEMPSTR ld b,6 call _vputsn KeyLoop6: call GET_KEY cp 52 jr nz, KeyLoop61 ld a,0 call ClearStatus pop hl pop de pop bc ret KeyLoop61: cp 53 jr z, Sure_Yes jr KeyLoop6 Sure_Yes: ex de,hl call GetMoney ld de,(TEMP) add a,0 sbc hl,de call PutMoney ld a,1 call ClearStatus pop hl pop de pop bc ret ;; This function clears the status area ClearStatus: push bc push af push hl ld a,7 ld (_curRow),a ld a,0 ld (_curCol),a ld b,3 ld c,7 ClrLoop: ld hl,Blank call _puts dec c ld a,c ld (_curRow),a ld a,0 ld (_curCol),a djnz ClrLoop pop hl pop af pop bc ret ;; This Generates a random number 0-51 in hl ;; It works by the following pseudocode ;; (SEED*57) % 9303 -> SEED ;; It then does SEED % 52 -> hl ;; This is built only for the shuffling routine, you ;; could change the last modulus routine for any number you ;; like, but I'm not sure that it would be very random ;; for large numbers. ;; (I took the C library's rand() routine and greatly simplified the ;; the numbers involved, all of them had a lot of prime number factors ;; and I just reduced them according to a simple pattern until I found ;; one that was semi-random) Random: ;; Save all registers push af push bc push de ;; I'm going to try and use someone else's random number generator for this ;; part, We'll see if it works. #ifndef OLDRAND call rand srl a ld l,a ld h,0 jr Mod #endif #ifdef OLDRAND ld de,(SEED) ld b,57 call Mult ld bc,$dba8 ld de,$2457 RandModLoop: add hl,bc scf ccf add hl,de jr c, RandDone sbc hl,de jr RandModLoop RandDone: ld (SEED),hl #endif Mod: ld bc,$ffcc ld de,$34 RandModLoop2: add hl,bc scf ccf add hl,de jr c, RandDone2 sbc hl,de jr RandModLoop2 RandDone2: ;; Restore all registers pop de pop bc pop af ret ;;This routine makes hl point to the correct value for (CINDEX) ;; It indexs through Nums to allow easier acces to the printable ;; value for each card. GetCard: push bc push de ld a,(CINDEX) ld c,a ld b,0 ld hl,CARDS add hl,bc ld a,(hl) ld hl,Nums ld c,a ld b,0 add hl,bc pop de pop bc ret ;; This Routine Converts HL to a string at the location de CONV_HL_STR: push af push bc push hl ex de,hl ld a,'+' rl d jr nc,BefConvLoop ld a,'-' BefConvLoop: ld (hl),a scf ccf rr d ex de,hl cp '-' jr nz, SkipAdjust push hl pop bc ld hl,32768 sbc hl,bc SkipAdjust: inc de inc de inc de inc de inc de ld b,5 ConvLoop: call UNPACK_HL add a,'0' ld (de),a dec de djnz ConvLoop pop hl pop bc pop af ret ;; This puts hl in the Money Variable PutMoney push bc push de push hl pop bc ld hl,MONEY ld (hl),b inc hl ld (hl),c pop de pop bc ret ;; This gets the amount of money and puts it in hl GetMoney: push bc push de ld hl,MONEY ld b,(hl) inc hl ld c,(hl) push bc pop hl pop de pop bc ret ;; this multiplies b * de -> hl ;; just make sure it won't overflow hl ;; It works just by 0->hl ;; then hl+de->hl, for b number oftimes Mult: push af ld a,0 cp b jr z,EqualsZero push bc ld hl,0 MultLoop: add hl,de djnz MultLoop pop bc pop af ret EqualsZero: pop af ld hl,0 ret rand: ld a,(randvar) ;;must be defined in text area ld b,a ld a,0 add a,b sla b sla b add a,b sla b sla b add a,b inc a ld (randvar),a srl a ret ;;end rand TPos: .db 3,11,19,25,27,33,35,41,43,47,49,51,55,57,59,63,65,67 .db 69,71,73,75,77,79,81,83,85,87,89,91 Title1: .db "TriMounts 86 v0.1 ",0 Title2: .db "Original by Josh Pieper",0 Title3: .db "josh@nemonet.com",0 Title4: .db "TI-86 port by Andreas Finne",0 Title5: .db "a_finne@hotmail.com",0 Title6: .db "2nd to reset stats",0 Title7: .db "Enter to Start!",0 Msg1: .db "Shuffling deck!",0 Nums: .db "A23456789TJQK +++++++++++++" Nums2: .db "#" Scrn1: .db "Money:$",0 Scrn2: .db "Pile:",0 Scrn3: .db "More ",45," new card " .db "Ent ",45," new game",0 Scrn4: .db "Streak:",0 Scrn5: .db "High Strk:",0 AreSure: .db "Are you sure? (Y-F1/N-F2)",0 .db "You will lose:$",0 Blank: .db " ",0 ProgName: .db $12,3,"tri" HIGHSTRK: .db 0 MONEY: .db 0,0 .end END