### Caverns of Freitag for the Apple II ### Copyright 1982 by David Shapiro ### Published by Muse Software ### ### Disassembly of "CF" ### SETUP ### 1 ONERR GOTO 400 # disconnect DOS; call $6D1E and $6D1B (CF.OBJ) 2 PR# 0: IN# 0: CALL 27934: CALL 27931 # set HIMEM to $6D00 4 HIMEM: 27904 # Set WNDBTM to 23 (guards bottom line). C2/C9 never used again 6 C2 = 256: POKE 35,23:C0 = 36:C9 = 9 8 BX = 0:ZA = 0 9 & CLR,0: & WINDOFF # query game parameters (skill in SL%, speed-1 in 793 ($319)) 10 GOSUB 50000 # generate a random number between 1 and N 15 DEF FN R(X) = INT ( RND (1) * X + 1) 20 ML = 40960:MX = 79:MY = 79:CX = 0:CY = 35:AX = 1:AY = 4 # set player start position (44081=$AC31 -> X=1 Y=39), set under-tile to Inn 21 K9 = MY + 1: POKE 44081,2:T0 = C0 + 2 # poke in the dragon parts (30-35) # adress 40960 + 80*71 + 75 = 46715 ($B67B) 25 POKE ML + K9 * 71 + 75,30: POKE ML + K9 * 71 + 76,31: POKE ML + K9 * 71 + 77,34 26 POKE ML + K9 * 72 + 75,32: POKE ML + K9 * 72 + 76,33: POKE ML + K9 * 72 + 77,35 # TB is 32704 ($7FC0); 34048 is $8500 30 TB = 34048 - 84 * 16:EP = 0:EL = 1:HP = 125:BH = 125:AR = 12:EN = 25 * SL% 40 DP = 1:XL = 1:YL = 1:XR = 8:YR = 7:HW = 1:SM = 0:RR = 0 50 DIM HH(35): DIM AA%(35): DIM M$(35) # set BX/BY to pointers to monster data # initially 110 monsters created on map 53 NM = 110:BX = 16384:BY = BX + 170:BT = BY + 170: DIM MH%(175) # set $31A = skill level + 4 (5-13) 54 POKE 794,SL% + 4 # $300=$03, $301=110 call $6D12 (create serpents?); set $4E to random 55 POKE 768,3: POKE 769,NM: CALL 27922: POKE 78, RND (1) * 256 # call $6D12 (create 62 chests?) 56 POKE 768,C0 + 1: POKE 769,62: CALL 27922 59 GOTO 63 ### find random empty map location, return in ZX/ZY/ZL ### # ZX,ZY = random number between 0 and 79. # ZL = $A000 + 80 * ZY + ZX 60 ZX = FN R(80) - 1:ZY = FN R(80) - 1:ZL = ML + K9 * ZY + ZX: IF PEEK (ZL) THEN 60 61 RETURN ### Initialization, continued ### # generate 110 monsters; this is repeated below (line 63 can be replaced with a REM) 63 FOR ZA = 1 TO NM:ZB = PEEK (ML + (MY + 1) * PEEK (BY + ZA) + PEEK (BX + ZA)): POKE BT + ZA,ZB:MH%(ZA) = HH(ZB): NEXT # 775=$307 66 POKE 775,0 # init rank names 67 FOR A = 1 TO 9: READ RN$(A): NEXT : DATA CANNON FODDER,STABLE BOY,NOVICE,ADVENTURER,SWORDSMAN,VETERAN,MIGHTY WARRIOR,LORD ,DRAGON SLAYER # read monster names and attributes 80 FOR A = 3 TO 35: READ M$(A),HH(A),AA%(A): NEXT # repeat the thing we did on line 63, this time with values in HH # (the "POKE BT+ZA,ZB" appears to be redundant) 83 FOR ZA = 1 TO NM:ZB = PEEK (ML + (MY + 1) * PEEK (BY + ZA) + PEEK (BX + ZA)): POKE BT + ZA,ZB:MH%(ZA) = HH(ZB): NEXT # update display, enable hi=res; 800=$320 90 GOSUB 10000: GOSUB 10100: & HIRES: POKE 800,0 # monster slot 0 doesn't get populated; used for dragon (which is on # the map but not included in BX/BY/BT). 95 MH%(0) = 350 ### MAIN LOOP ### 100 GOSUB 20000 110 GOSUB 30000 120 GOTO 100 ## onerr goto ## 400 RESUME ### monsters: name, hit points, attack damage # the "dwagon" doesn't actually have 10K hits; see line 95 1000 DATA SERPENT,30,20 1001 DATA ELECTRIC MOTH,15,15 1002 DATA MAD ROBOT,50,30 1003 DATA BURBLEBLORT,75,45 1004 DATA GRIFFIN,150,100 1005 DATA FLAMEBAT,100, 70 1006 DATA INVISOID,20,20 1007 DATA THUNDERBUG,5,150 1008 DATA COLDCRYSTAL,300,8 1009 DATA PHOENIX,200,150 1010 DATA MIMIC,88,200 1011 DATA HEALER,1,1 1012 DATA WIZARD,65,20 1013 DATA ,, 1014 DATA ,, 1015 DATA ,, 1016 DATA ,, 1017 DATA ,, 1018 DATA ,, 1019 DATA ,, 1020 DATA ,, 1021 DATA ,, 1022 DATA ,, 1023 DATA ,, 1024 DATA ,, 1025 DATA ,, 1026 DATA ,, 1027 DATA DWAGON,, 1028 DATA DWAGON,, 1029 DATA DWAGON,, 1030 DATA DWAGON,, 1031 DATA DWAGON,, 1032 DATA DWAGON,10000,120 ### redraw hi-res screen ### # Set $300/301 to the map center. If in hi-res mode, call 27904=$6D00 10000 POKE 768,CX: POKE 769,CY: IF DP > 1 THEN RETURN 10010 CALL 27904: RETURN ### draw character sheet ### 10100 REM 10105 POKE 34,0: POKE 35,24: HOME : POKE 35,23: PRINT NN$ TAB( 29)"+----------+"; 10110 FOR A = 1 TO 9: PRINT TAB( 29)"! !";: NEXT : PRINT TAB( 29)"+----------+" 10120 VTAB 3: PRINT "RANK: "RN$(EL): PRINT "HITS: "HP"/"BH 10130 PRINT "ARROWS: "AR: PRINT "GOLD: "GP 10135 PRINT "EXP: "EP # set WNDTOP 10140 POKE 34,12 10143 VTAB 10: IF MS THEN PRINT "MAGIC SWORD +"MS 10146 VTAB 11: IF SH THEN PRINT "MAGIC SHIELD +"SH 10150 GOSUB 10200: REM REPLOT WINDMAP 10160 GOSUB 10300 10190 RETURN ## draw the text mini-map (unless showing map) ## 10200 IF DP = 3 THEN RETURN 10210 POKE 768,CX: POKE 769,CY: CALL 27907: RETURN ## update wield (unless showing map) ## 10300 IF DP = 3 THEN RETURN 10310 VTAB 8: HTAB 1: PRINT "HOLDING: ";: IF HW = 1 THEN PRINT "SWORD": RETURN 10320 PRINT "BOW ": RETURN ## update gold (unless showing map) ## 10400 IF DP = 3 THEN RETURN 10410 VTAB 6: HTAB 9: PRINT " ": VTAB 6: HTAB 9: PRINT GP: RETURN ## update arrows (unless showing map) ## 10500 IF DP = 3 THEN RETURN 10510 VTAB 5: HTAB 9: PRINT AR" ": RETURN ## update HP (unless showing map) ## 10600 IF DP = 3 THEN RETURN 10610 VTAB 4: HTAB 9: PRINT HP"/"BH" ": RETURN ## update experience rank (unless showing map) ## 10700 IF DP = 3 THEN RETURN 10710 VTAB 3: HTAB 9: PRINT RN$(EL)" ": RETURN ### draw map ### 11000 POKE 770,AX: POKE 771,AY: CALL 27910: RETURN ### redraw a single tile ### # $305=X, $306=Y, $304=DP, call $6D09 ### 12000 POKE 773,X: POKE 774,Y: POKE 772,DP: CALL 27913: RETURN ### print message ### # no messages in map mode, ever; clear urgent flag and return 13000 IF DP = 3 THEN O9 = 0: RETURN # double-space it 13020 IF H9 = 0 THEN VTAB 23: PRINT : PRINT : VTAB 22:H9 = 1 # if the message ends in '!' or '.' we flash it when messages are on 13030 PRINT M$;: IF RIGHT$ (M$,1) = "!" OR RIGHT$ (M$,1) = "." THEN 13040 13035 RETURN # if hi-res, and messages are enabled or this is urgent, show it briefly 13040 H9 = 0: IF DP = 1 AND (SM = 1 OR O9 = 1) THEN & WINDOW: FOR A = 1 TO 888: NEXT : & WINDOFF 13050 O9 = 0: RETURN ### arrow animation ### # pass in ZX/ZY to indicate direction and SX/SY to indicate position 14000 REM 14010 IF ZX = 1 THEN 14100 14020 IF ZX = - 1 THEN 14200 14030 IF ZY = 1 THEN 14300 14040 A1 = SX * 28 + 12:A2 = SY * 21 + 12:A3 = 3:A4 = 7935:A5 = 2: FOR Z6 = 0 TO 20 * ( ABS (Y1 - SY)) STEP 6: FOR B = 1 TO 2: & CHARSET,A1,A2 - Z6,A3,A4,A5: NEXT B,Z6: RETURN 14100 A1 = SX * 28:A2 = SY * 21 + 9:A3 = 0:A4 = 7935:A5 = 2: FOR Z6 = 0 TO 27 * ABS (X1 - SX) STEP 9: FOR B = 1 TO 2: & CHARSET,A1 + Z6,A2,A3,A4,A5: NEXT B,Z6: RETURN 14200 A1 = SX * 28 + 18:A2 = SY * 21 + 9:A3 = 1:A4 = 7935:A5 = 2: FOR Z6 = 0 TO 27 * ABS (X1 - SX) STEP 9: FOR B = 1 TO 2: & CHARSET,A1 - Z6,A2,A3,A4,A5: NEXT B,Z6: RETURN 14300 A1 = SX * 28 + 12:A2 = SY * 21:A3 = 4:A4 = 7935:A5 = 2: FOR Z6 = 0 TO 20 * ( ABS (Y1 - SY)) STEP 6: FOR B = 1 TO 2: & CHARSET,A1,A2 + Z6,A3,A4,A5: NEXT B,Z6: RETURN # draw "hit" graphic; data set is at 7935 ($1EFF, CF.MISC) 15000 & CHARSET,(X - CX) * 28 + 9,(Y - CY) * 21 + 6,2,7935,2: RETURN ### update player bitmap when RR <> 0 ### 15500 ZW = 25: IF RR = - 4 THEN ZW = 17 + HW ### update player bitmap (val in ZW) ### # TB is $7FC0 (SKETCHZ); 168 is 84*2 == item #2 (the player) 16000 Z1 = TB + ZA + 168 # ZW is icon source (18=sword, 16/17/19/20=bow, 25=bird, 36=blank) :Z2 = TB + ZA + 84 * ZW # set destination and source : POKE 7,Z1 / 256: POKE 6,Z1 - 256 * PEEK (7) : POKE 9,Z2 / 256: POKE 8,Z2 - 256 * PEEK (9) # call 27925=$6D15 to copy 84 bytes from $08/09 to $06/07 : CALL 27925 # update X/Y to current position :X = CX + AX:Y = CY + AY # redraw tile : GOTO 12000 ### update display and wait for input or timeout ### # set $304 to display mode and call $6D0C. If $308 is nonzero # (input pending), head to 20050 to handle it. 20000 POKE 772,DP: CALL 27916: IF PEEK (776) THEN 20050 # If we're in the post-run cooldown, update RR. 20025 IF RR < 0 THEN RR = RR + 1 20030 RETURN 20040 TM = PEEK (775): & CBOX,1,TM,189,TM + 1,191,1,0 20045 POKE 775,0: RETURN ### handle user input ### # if we're in run cooldown, player doesn't get to move 20050 IF RR < 0 THEN 20025 # get the input, see if it's a display mode (1-3) 20051 GET A$:ZA = VAL (A$): IF ZA = 0 THEN 20085 # always in mode 1 (hi-res) while running 20052 IF RR THEN 20090 # handle mode switch 20055 IF ZA = 1 THEN DP = 1: GOSUB 10000: & HIRES: GOSUB 10100: GOTO 20000 20060 IF ZA > 2 THEN 20080 20065 IF DP = 3 THEN DP = 2: GOSUB 10100 20070 DP = 2: & HROFF: GOTO 20000 20080 IF ZA = 3 THEN & HROFF: GOSUB 11000:DP = ZA: GOTO 20000 # check movement, unless we're stick to a mimic (S2) 20085 IF S2 = 1 THEN 20200 20090 ZQ = 1:ZF = 0: FOR DY = - 1 TO 1: FOR DX = - 1 TO 1: IF A$ = MID$ ("TYUGHJBNM",ZQ,1) THEN ZX = DX:ZY = DY:ZF = ZQ:DX = 1:DY = 1 20100 ZQ = ZQ + 1: NEXT DX,DY: IF ZF = 0 THEN 20200 20110 X = CX + AX:Y = CY + AY:ZZ = PEEK (ML + K9 * (Y + ZY) + X + ZX): IF ZZ = 0 OR ZZ = 14 OR ZZ > C0 THEN 20140 # run into a wall? 1-3 HP dam 20120 IF ZZ = 1 THEN POKE 6,2: CALL 27946:M$ = "OOF! HIT A WALL, ": GOSUB 13000:ZD = FN R(3): GOSUB 51000: GOTO 20040 20122 IF A$ = "H" THEN 20040 # 27946=$6D2A 20130 POKE 6,2: CALL 27946 20135 M$ = "BLOCKED BY " + M$(ZZ) + "!": GOSUB 13000: GOTO 20040 # set Z9 to the thing we moved onto (empty, healer, chest, Inn) 20140 Z9 = ZZ: POKE ML + K9 * Y + X,T0: GOSUB 12000:X = X + ZX:Y = Y + ZY:AX = AX + ZX:AY = AY + ZY: POKE ML + (MY + 1) * Y + X,2:T0 = 0 20145 IF DP = 3 THEN GOSUB 11000 # something special about column 74? 20147 IF AX + CX = 74 AND ZX < > 0 THEN 20152 # have we reached the edge of the display? 20150 IF AX > = XL AND AX < = XR AND AY > = YL AND AY < = YR THEN 20160 # yes, recenter map on our current position # don't push past edges of map 20152 CX = X - 4:CY = Y - 4: IF CX < 0 THEN CX = 0 20153 IF CY < 0 THEN CY = 0 20154 IF CX > MX - 9 THEN CX = MX - 9 20155 IF CY > MY - 8 THEN CY = MY - 8 # update AX/AY 20156 AX = X - CX:AY = Y - CY: GOSUB 10200: GOSUB 10000 20160 GOSUB 12000: POKE 6,0: IF RR THEN POKE 6,1 # call $6D2A; if we moved onto something other than empty space, branch 20161 CALL 27946: IF Z9 THEN 20170 # if run mode is active, decrement it 20163 IF RR = 0 THEN 20040 20165 RR = RR - 1: IF RR = 0 THEN RR = - 4: GOSUB 15500: GOTO 20040 20167 IF RR = 4 THEN O9 = 1:M$ = "THE SPELL IS WEARING OFF.": GOSUB 13000 # on even counts, player moves twice 20168 IF RR / 2 = INT (RR / 2) THEN 20000 20169 GOTO 20040 ## handle movement onto something (chest, healer, Inn) 20170 IF Z9 < > C0 + 1 THEN 20185 # open chest; U2 is set to 1 if it's a teleport trap 20175 GOSUB 52000: IF U2 THEN 20152 20180 GOTO 20040 # if it's the Inn then handle that 20185 IF Z9 = C0 + 2 THEN GOSUB 53000: GOTO 20040 # if it's a healer then do that 20190 IF Z9 = 14 THEN GOSUB 54000: GOTO 20040 ## shouldn't fall through here ## # can't attack, change modes, or various other things or while running 20200 IF RR THEN IF A$ < > CHR$ (27) THEN 20000 # check for attack key # sets XZ/ZY to {-1,0,1} based on direction; sets ZF>0 on match 20205 ZQ = 1:ZX = 0:ZY = 0:ZF = 0: FOR DY = - 1 TO 1: FOR DX = - 1 TO 1: IF ASC (A$) = ASC ( MID$ ("TYUG*JBNM",ZQ,1)) - 64 THEN ZX = DX:ZY = DY:ZF = ZQ 20210 ZQ = ZQ + 1: NEXT DX,DY: IF ZF = 0 THEN 20500 # compute X/Y of attacked square; set ZZ to tile contents 20215 X = CX + AX + ZX:Y = CY + AY + ZY:ZZ = PEEK (ML + K9 * Y + X) # ZZ is type of object at target location 20220 ON HW GOTO 20240,20350 # swing sword; if attacked a monster, branch 20240 IF ZZ > 1 AND ZZ < C0 + 1 THEN 20250 20243 M$ = "SWISH...": IF ZZ = 1 THEN M$ = "CLUNK!" 20244 POKE 6,0: CALL 27943 20246 GOSUB 13000: RETURN # damage is 1-10 * level, plus bonus for a magic sword 20250 ZD = FN R(10) * (EL + MS) # figure out which monster we hit (781=$30d, 27949=$6D2D) # (returns 0 if nothing found, which indicates it's part of the dragon) 20255 POKE 781,NM: POKE 6,X: POKE 7,Y: CALL 27949:ZF = PEEK (781) # play a sound (27943=$6D27) 20262 GOSUB 15000: POKE 6,1: CALL 27943: GOSUB 15000 20265 Z5 = ZF 20270 MH%(ZF) = MH%(ZF) - ZD:M$ = "YOU HIT THE " + M$(ZZ) + " FOR " + STR$ (ZD) + " POINTS.": GOSUB 13000 # if monster is still alive, branch 20271 IF MH%(ZF) > 0 THEN 20040 # monster is dead; if Z5 is zero (meaning we didn't find it in the # table) then we must've killed the dragon 20272 IF Z5 = 0 THEN 40000 20273 KL% = KL% + 1 # set Z8 to type of monster we just killed; if it was a Mimic, clear "stuck" flag 20275 Z8 = ZZ: IF ZZ = 13 THEN S2 = 0 # draw "poof" death (27943=$6D27) 20283 POKE ML + K9 * Y + X,C0 + 3: GOSUB 12000: POKE 6,4: CALL 27943 20285 POKE ML + K9 * Y + X,0: GOSUB 12000 # pick a new monster type at random (3-15) :ZT = 2 + FN R(13) # update experience points 20290 EP = EP + HH(Z8) # find an empty map square, spawn a replacement, and put it in monster table : GOSUB 60: POKE BX + Z5,ZX: POKE BY + Z5,ZY: POKE BT + Z5,ZT: POKE ZL,ZT # if it's on-screen, draw it :X = ZX:Y = ZY: GOSUB 12000 # set the monster's health according to type, then pick a new type in case we want to expand the set 20292 MH%(ZF) = HH(ZT):ZT = 2 + FN R(13) # if there's fewer than 170 monsters, spawn another one 20293 IF NM < 169 THEN NM = NM + 1: GOSUB 60: POKE BX + NM,ZX: POKE BY + NM,ZY: POKE BT + NM,ZT: POKE ZL,ZT:X = ZX:Y = ZY: GOSUB 12000:MH%(NM) = HH(ZT) 20295 IF DP < > 3 THEN VTAB 7: HTAB 1: PRINT "EXP: "EP 20300 RETURN ### shoot arrow ### # ZX/ZY are {-1,0,1} indicating direction of shot; player cannot shoot # diagonally, so one should be zero 20350 IF ZX AND ZY THEN 20000 # update player tile with direction-specific bow image 20351 ZW = 18 + ZX + 2 * ZY: GOSUB 16000:X = CX + AX + ZX:Y = CY + AY + ZY 20353 IF AR = 0 THEN M$ = "OUT OF ARROWS!": GOSUB 13000: GOTO 20040 # reduce arrow count 20355 AR = AR - 1: IF DP < 3 THEN VTAB 5: HTAB 9: PRINT " ": VTAB 5: HTAB 9: PRINT AR # check to see if the adjacent tile in the firing direction is occupied 20360 IF ZZ > 0 THEN M$ = "TOO CLOSE!": GOSUB 13000: GOTO 20040 20365 SX = X - CX:SY = Y - CY # loop to figure out what we hit: 20370 X1 = X - CX:Y1 = Y - CY 20380 IF X1 < 0 OR X1 > 9 OR Y1 < 0 OR Y1 > 9 THEN 20410 20390 ZZ = PEEK (ML + K9 * Y + X): IF ZZ < > 1 AND ZZ < > C0 + 1 AND ZZ < > C0 + 2 THEN 20420 20410 GOSUB 14000:M$ = "MISSED...": GOSUB 13000: GOTO 20040 20420 IF ZZ = 0 THEN X = X + ZX:Y = Y + ZY: GOTO 20370 20425 GOSUB 14000 # hit something that isn't a wall, chest, or Inn; compute arrow damage 20430 ZD = FN R(6) * (EL + 2): GOTO 20255 # not reachable? 20435 GOSUB 14000 ### continue checking keys ### 20500 IF A$ < > "O" THEN 20550 # toggle messages on/off 20510 ZJ = 1 - SM: INVERSE :SM = 1:M$ = "MESSAGES O": IF ZJ = 0 THEN M$ = M$ + "FF." 20520 IF ZJ = 1 THEN M$ = M$ + "N." 20530 GOSUB 13000: NORMAL :SM = ZJ: GOTO 20000 20550 IF A$ < > ":" THEN 20610 # recenter map 20560 X = CX + AX:Y = CY + AY:CX = X - 4:CY = Y - 4: IF CX < 0 THEN CX = 0 20570 IF CY < 0 THEN CY = 0 20580 IF CX > MX - 9 THEN CX = MX - 9 20590 IF CY > MY - 8 THEN CY = MY - 8 20600 AX = X - CX:AY = Y - CY: GOSUB 10000: GOSUB 10200: GOTO 20000 20610 IF A$ < > " " THEN 20700 # toggle weapon 1/2 20620 HW = 3 - HW: GOSUB 10300 20630 ZW = 17 + HW: GOSUB 16000: GOTO 20040 20700 IF (A$ = "A" OR A$ = "P") AND (DP = 3 OR T0 = 0) THEN 20000 20710 IF A$ < > "A" THEN 20800 # 10 gold for 5 arrows 20730 ZA = 5: IF AR > 94 THEN M$ = "CAN'T CARRY ANY MORE!": GOSUB 13000: GOTO 20040 20740 IF GP < ZA * 2 THEN M$ = "YOU NEED MORE GOLD FIRST.": GOSUB 13000: GOTO 20040 20750 GP = GP - ZA * 2:AR = AR + ZA: GOSUB 10400: GOSUB 10500 20760 GOTO 20040 20800 IF A$ < > "P" THEN 20900 # 25 gold for 5 HP 20830 ZA = 5 20840 IF GP < ZA * 5 THEN M$ = "YOU NEED MORE GOLD FIRST.": GOSUB 13000: GOTO 20040 20850 GP = GP - ZA * 5:BH = BH + ZA:HP = BH: GOSUB 10400: GOSUB 10600: GOTO 20040 20900 IF A$ < > CHR$ (27) THEN 20000 # if currently running, cancel run mode 20905 IF RR > 0 THEN RR = - 4: GOSUB 15500: GOTO 20040 20910 IF RR THEN 20000 # enable run mode 20920 RR = 24 - SL%:M$ = "RUN AWAY!": GOSUB 15500: GOSUB 13000:ZA = 1: GOTO 20055 ### move monsters ### 30000 TN% = TN% + 1 30005 POKE 777,CX + AX: POKE 778,CY + AY: POKE 772,DP: POKE 770,AX: POKE 771,AY # 27919=$6D0F 30010 POKE 781,NM: CALL 27919: IF PEEK (782) THEN GOSUB 31000 30012 Z7 = 795 # check for zap by wizards -- window X/Y will be other than $ff/$ff # first wizard's coords in 795/796; second coords in 797/798 30014 IF PEEK (Z7) < 30 THEN GOSUB 33000:Z7 = Z7 + 2: IF Z7 < 799 THEN 30014 # check for hit by dragon flame 30020 IF PEEK (799) THEN GOSUB 42000 # if we're next to the dragon, it will attack us 30030 IF CX + AX > 73 THEN IF CY + AY > 70 AND CY + AY < 74 AND EL < 9 THEN MT = 35: GOSUB 32010 30050 RETURN ### handle all monster attacks ### # 782($30e): number of attacks (0-3) # 783-786($30f-312): attacking monster ID (0-169) 31000 FOR Z7 = 1 TO PEEK (782):ZC = PEEK (782 + Z7): GOSUB 32000: NEXT Z7: RETURN ### handle single monster attack (ident 0-169 in ZC) ### # get monster type 32000 MT = PEEK (BT + ZC) # check for block (can't block with bow, when running, or when # attacked by Invisoid) 32010 IF HW = 1 AND RR = 0 THEN IF RND (1) < (SH + EL) / 20 AND MT < > 9 THEN M$ = M$(MT) + " BLOCKED WITH SHIELD.": GOSUB 13000: RETURN 32011 X = CX + AX:Y = CY + AY 32012 GOSUB 15000: POKE 6,2: CALL 27943: GOSUB 15000 32015 M$ = M$(MT) + " ATTACKS, ": GOSUB 13000 # damage is limited to 70% of value in table 32020 ZD = FN R(AA%(MT) * .7): GOSUB 51000 # successful attack by mimic makes you immobile : IF MT = 13 AND S2 = 0 THEN M$ = "YOU'RE STUCK TO THE MIMIC!":S2 = 1:O9 = 1: GOSUB 13000 32030 RETURN ### wizard ranged attack ### 33000 ZX = PEEK (Z7):ZY = PEEK (Z7 + 1):ZB = ZX * 28 + 17:ZC = ZY * 21 + 13:ZD = 816:ZG = 0:ZH = 2 # if vertical attack, branch 33010 IF ZX = AX THEN 33040 # horizontal attack 33020 ZF = ABS (ZX - AX) * 16:ZE = 2: IF AX < ZX THEN ZE = 0 33030 GOTO 33050 33040 ZF = ABS (ZY - AY) * 16:ZE = 3: IF AY < ZY THEN ZE = 1 33050 IF ZF = 16 OR ZF > 100 THEN RETURN # draw twice in "invert" mode (ZH=2); first draws, second erases # ZA = colorIndex = 5 (white) # ZB = screen X coord of wizard # ZC = screen Y coord of wizard # ZD = data ptr (816/$330) # ZE = direction (0=left, 1=up, 2=right, 3=down) # ZF = distance in squares, * 16 # ZG = angle = 0 # ZH = drawMode = 2 (invert) 33051 POKE 6,0: FOR ZZ = 1 TO 2: FOR ZA = 5 TO 5: & LINESET,ZA,ZB,ZC,ZD,ZE,ZF,ZG,ZH: NEXT : IF ZZ = 1 THEN POKE 6,5: CALL 27943 33052 NEXT # damage is (1-50)+25 rather than melee monster damage 33060 M$ = "ZAPPO! ": GOSUB 13000:ZD = FN R(50) + 25: GOSUB 51000: RETURN ### dragon is dead ### # remove all dragon tiles 40000 ZX = 75 - CX:ZY = 71 - CY: FOR ZA = 71 TO 72: FOR ZB = 75 TO 77: POKE ML + K9 * ZA + ZB,0: NEXT : NEXT # draw a solid box in "invert" mode on the dragon, and play sound 40010 ZX = ZX * 28:ZY = ZY * 21: & BOX,ZX,ZY,ZX + 83,ZY + 41,2,2: POKE 6,3: CALL 27943 40020 GOSUB 10000: GOSUB 10200 # disable dragon breath : POKE 800,9 # give up to 800 HP 40030 ZA = 100 * (9 - EL):BH = BH + ZA:HP = HP + ZA:EL = 9: GOSUB 10600: GOSUB 10700: RETURN ### hit by dragon flame attack ### 42000 M$ = "SIZZLE! ":ZD = 250: GOSUB 13000: GOSUB 51000: RETURN ### initial setup -- ask player for game parameters ### 50000 TEXT 50010 HOME : INPUT "YOUR NAME, WARRIOR? ";NN$: IF LEN (NN$) > 16 THEN NN$ = LEFT$ (NN$,16) 50020 PRINT : PRINT "SKILL LEVEL (1-9)? "; 50030 GET A$:SL% = VAL (A$): IF SL% = 0 THEN 50030 50040 PRINT A$: PRINT : INPUT "GAME SPEED (1-50)? ";A$:ZA = VAL (A$): IF ZA = 0 THEN ZA = 1 50045 IF ZA > 50 THEN ZA = 50 # store speed-1 in $319 50050 POKE 793,ZA - 1:ZD = 0: IF SL% > 7 THEN ZD = 1 # for skill levels 8/9 add a couple of walls to make the maze harder to traverse # (7,39) and (6,42) are visible from starting point 50051 POKE 44087,ZD: POKE 44326,ZD 50100 PRINT : PRINT : PRINT : PRINT : INVERSE : PRINT "ONE MOMENT WHILE I AWAKEN THE MONSTERS.": NORMAL : RETURN ### handle player being hit ### # damage taken is in ZD 51000 M$ = STR$ (ZD) + " HITS.": GOSUB 13000 51020 HP = HP - ZD: GOSUB 10600: IF HP > 0 THEN 51060 # play funeral song ($6D24) 51025 CALL 27940: IF DP = 3 THEN DP = 2: GOSUB 10100 51027 INVERSE 51030 M$ = "YOU'RE DEAD!": GOSUB 13000: NORMAL : POKE - 16368,0: TEXT : VTAB 24: HTAB 1: PRINT "PRESS ANY KEY TO PLAY AGAIN....";: GET A$ 51040 GOSUB 57000: RUN 51060 IF H4 = 0 AND (HP / BH) < .33 THEN H4 = 1:O9 = 1:M$ = "YOU'RE FEELING WEAK.": GOSUB 13000 51070 IF H4 = 1 THEN IF (HP / BH) < .1 THEN H4 = 2:O9 = 1:M$ = "YOU'VE LOST A LOT OF BLOOD...": GOSUB 13000 51080 RETURN ### open chest ### # clear teleport flag, set urgent message flag 52000 U2 = 0:O9 = 1 # every other time we open a chest, create a new one at a random location 52005 N4 = 1 - N4: IF N4 THEN GOSUB 60: POKE ZL,C0 + 1 # 83% chance of 1-50 gold coins, 17% chance of other 52010 IF RND (1) > .83 THEN 52030 52020 ZG = FN R(50):M$ = "YOU FOUND " + STR$ (ZG) + " GOLD COINS.":GP = GP + ZG: GOSUB 13000: GOSUB 10400: RETURN ## other: 20% chance each of arrows, +N magic sword, magic shield, empty, trap 52030 ON FN R(5) GOTO 52040,52100,52200,52300,52400 52040 ZA = FN R(30) + 2:M$ = "YOU FOUND " + STR$ (ZA) + " ARROWS.": GOSUB 13000:AR = AR + ZA: IF AR > 99 THEN AR = 99 52045 GOSUB 10500: RETURN 52050 ZP = FN R(3):M$ = "YOU FOUND A +" + STR$ (ZP) + " MAGIC S": RETURN 52100 GOSUB 52050:M$ = M$ + "WORD!": GOSUB 13000 52110 IF ZP > MS THEN MS = ZP: IF DP < > 3 THEN VTAB 10: HTAB 1: PRINT "MAGIC SWORD +"MS 52120 RETURN 52200 GOSUB 52050:M$ = M$ + "HIELD!": GOSUB 13000 52210 IF ZP > SH THEN SH = ZP: IF DP < > 3 THEN VTAB 11: HTAB 1: PRINT "MAGIC SHIELD +"SH 52220 RETURN 52300 M$ = "THE CHEST IS EMPTY!": GOSUB 13000: RETURN # clear the square we were on, then find a random empty square # play teleportation sound (27943=$6D27) 52400 POKE ML + K9 * (CY + AY) + CX + AX,0:M$ = "IT'S A TELEPORT TRAP!": GOSUB 13000: GOSUB 60:X = ZX:Y = ZY:U2 = 1: POKE ZL,2: POKE 6,3: CALL 27943: RETURN ### moved onto Inn ### 53000 REM INN # if we're a Dragon Slayer, game won 53001 IF EL = 9 THEN 60000 # set prev tile = Inn 53005 T0 = C0 + 2 # handle level-up 53010 IF EP > = EN THEN O9 = 1:BH = BH + 100:EL = EL + 1: GOSUB 10700:M$ = "YOU WENT UP A LEVEL!": GOSUB 13000:EN = EN * 2: IF EL > 7 THEN EN = 1E10 # restore hit points to max, reset health warning 53020 HP = BH: GOSUB 10600:H4 = 0 53025 M$ = "HIT A TO BUY ARROWS, P FOR HIT POINTS.": GOSUB 13000 53030 RETURN ### touched a healer ### 54000 ZD = FN R(150) + 25: IF ZD > BH - HP THEN ZD = BH - HP 54010 M$ = "YOU REGAIN " + STR$ (ZD) + " HIT POINTS.":O9 = 1: POKE 6,4: CALL 27943: GOSUB 13000:HP = HP + ZD: GOSUB 10600 # remove the healer, and replace it with a randomly-placed wizard 54020 POKE 781,NM: POKE 6,CX + AX: POKE 7,CY + AY: CALL 27949:Z9 = PEEK (781): POKE BT + Z9,15:XX = T0: GOSUB 60: POKE BX + Z9,ZX: POKE BY + Z9,ZY: POKE ZL,15:MH%(15) = HH(15) 54030 RETURN ### post-death cleanup ### # update player bitmap # BUG: should set RR to 0 to reset player bitmap 57000 TEXT : IF RR > 0 THEN GOSUB 15500 # BUG: C0 is a blank image, so you're invisible if you were holding the bow 57010 IF HW = 2 THEN ZW = C0: GOSUB 16000 57020 RETURN ### victory ### # 31232=$7A00, fireworks display 60000 HOME : TEXT : VTAB 21: PRINT "THOU HAST SLAIN THE DRAGON AND ESCAPED! ": PRINT "PRESS ANY KEY TO PLAY AGAIN...": CALL 31232: RUN