'*********WRITTEN FOR XC=BASIC 3.1.2 - NO GUARANTEES FOR FUTURE VERSIONS! OPTION INLINEDATA goto data_mem_end text_data_mem: include "data_strings.bas" verbs_struct: include "data_verbs.bas" objects_struct: include "data_objects.bas" rooms_struct: include "data_rooms.bas" commands_struct: include "data_commands.bas" general_help_struct: include "data_general_help.bas" '******OTHER FIXED STRINGS******** ' "ADVENT 101" fixed_str_gamename: DATA AS BYTE $21, $24, $36, $25, $2E, $74, $11, $10, $D1 ' "- >ORIGINAL DEVELOPMENT BY #>WILL #>CROWTHER, 1976|- >GREATLY EXPANDED BY #>DON #>WOODS, 1977|- >STREAMLINED WITH RANDOM MAPS AND NEW PUZZLES BY #>JEFFREY #>HENNING, 2017|::TROYPRESS.COM|- >PORTED TO >C64 >X>C=>B>A>S>I>C 3, BUG-FIXED AND FURTHER TOUCHES BY #>J>J>FLASH, 2023|::JJFLASH.ITCH.IO|- >X>C=>B>A>S>I>C 3 BY #>CSABA #>FEKETE, 2022-2023|::XC-BASIC.NET|- >THANKS TO #>DIDUZ : DIDUZ.ITCH.IO" fixed_str_credits: DATA AS BYTE $4D, $1E, $2F, $32, $29, $27, $29, $2E, $21, $6C, $24, $25, $36, $25, $2C, $2F, $30, $2D, $25, $2E, $74, $22, $79, $03, $1E, $37, $29, $2C, $6C, $03, $1E, $23, $32, $2F, $37, $34, $28, $25, $32, $0C, $11, $19, $17, $96, $4D, $1E, $27, $32, $25, $21, $34, $2C, $79, $25, $38, $30, $21, $2E, $24, $25, $64, $22, $79, $03, $1E, $24, $2F, $6E, $03, $1E, $37, $2F, $2F, $24, $33, $4C, $11, $19, $17, $97, $4D, $1E, $33, $34, $32, $25, $21, $2D, $2C, $29, $2E, $25, $64, $37, $29, $34, $68, $32, $21, $2E, $24, $2F, $6D, $2D, $21, $30, $73, $21, $2E, $64, $2E, $25, $B7, $30, $35, $3A, $3A, $2C, $25, $73, $22, $79, $03, $1E, $2A, $25, $26, $26, $32, $25, $79, $03, $1E, $28, $25, $2E, $2E, $29, $2E, $27, $4C, $12, $10, $11, $97, $1A, $1A, $34, $32, $2F, $39, $30, $32, $25, $33, $33, $0E, $23, $2F, $AD, $4D, $1E, $30, $2F, $32, $34, $25, $64, $34, $6F, $1E, $23, $16, $54, $1E, $38, $1E, $23, $1D, $1E, $22, $1E, $21, $1E, $33, $1E, $29, $1E, $63, $13, $4C, $22, $35, $27, $0D, $26, $29, $38, $25, $A4, $21, $2E, $64, $26, $35, $32, $34, $28, $25, $72, $34, $2F, $35, $23, $28, $25, $73, $22, $79, $03, $1E, $2A, $1E, $2A, $1E, $26, $2C, $21, $33, $28, $4C, $12, $10, $12, $93, $1A, $1A, $2A, $2A, $26, $2C, $21, $33, $28, $0E, $29, $34, $23, $28, $0E, $29, $AF, $4D, $1E, $38, $1E, $23, $1D, $1E, $22, $1E, $21, $1E, $33, $1E, $29, $1E, $63, $53, $22, $79, $03, $1E, $23, $33, $21, $22, $61, $03, $1E, $26, $25, $2B, $25, $34, $25, $4C, $12, $10, $12, $12, $0D, $12, $10, $12, $93, $1A, $1A, $38, $23, $0D, $22, $21, $33, $29, $23, $0E, $2E, $25, $B4, $4D, $1E, $34, $28, $21, $2E, $2B, $73, $34, $6F, $03, $1E, $24, $29, $24, $35, $7A, $5A, $24, $29, $24, $35, $3A, $0E, $29, $34, $23, $28, $0E, $29, $EF ' "SAY `HELP` FOR GENERAL & SPECIFIC HINTS. PRESS A KEY TO START YOUR CAVING ADVENTURE!" fixed_str_start_game: DATA AS BYTE $33, $21, $79, $02, $28, $25, $2C, $30, $42, $26, $2F, $72, $27, $25, $2E, $25, $32, $21, $6C, $46, $33, $30, $25, $23, $29, $26, $29, $63, $28, $29, $2E, $34, $33, $0E, $30, $32, $25, $33, $73, $61, $2B, $25, $79, $34, $6F, $33, $34, $21, $32, $74, $39, $2F, $35, $72, $23, $21, $36, $29, $2E, $A7, $21, $24, $36, $25, $2E, $34, $35, $32, $25, $C1 ' "I SEE NO " fixed_str_i_see_no: DATA AS BYTE $69, $33, $25, $65, $2E, $2F, $C0 ' " HERE." fixed_str_here: DATA AS BYTE $00, $28, $25, $32, $E5 ' "IT IS NOW CLOSED." fixed_str_it_is_now_closed: DATA AS BYTE $29, $74, $29, $73, $2E, $2F, $77, $23, $2C, $2F, $33, $25, $E4 ' "IT WAS ALREADY CLOSED." fixed_str_it_was_already_closed: DATA AS BYTE $29, $74, $37, $21, $73, $21, $2C, $32, $25, $21, $24, $79, $23, $2C, $2F, $33, $25, $E4 ' "DROPPED." fixed_str_dropped: DATA AS BYTE $24, $32, $2F, $30, $30, $25, $E4 ' "YOU GIVE THE " fixed_str_you_give_the: DATA AS BYTE $39, $2F, $75, $27, $29, $36, $65, $34, $28, $25, $C0 ' " TO THE " fixed_str_to_the: DATA AS BYTE $00, $34, $6F, $34, $28, $25, $C0 ' "LAMP" fixed_str_headlamp: DATA AS BYTE $2C, $21, $2D, $F0 ' "AS YOU JUMPED, UNFORTUNATELY YOU DROPPED THE " fixed_str_as_you_jumped_you_dropped_the: DATA AS BYTE $21, $73, $39, $2F, $75, $2A, $35, $2D, $30, $25, $24, $4C, $35, $2E, $26, $2F, $32, $34, $35, $2E, $21, $34, $25, $2C, $79, $39, $2F, $75, $24, $32, $2F, $30, $30, $25, $24, $34, $28, $25, $C0 ' "IT IS NOW OPENED." fixed_str_it_is_now_opened: DATA AS BYTE $29, $74, $29, $73, $2E, $2F, $77, $2F, $30, $25, $2E, $25, $E4 ' "IT WAS ALREADY OPENED." fixed_str_it_was_already_opened: DATA AS BYTE $29, $74, $37, $21, $73, $21, $2C, $32, $25, $21, $24, $79, $2F, $30, $25, $2E, $25, $E4 ' "YOU'RE ALREADY CARRYING IT." fixed_str_youre_already_carrying_it: DATA AS BYTE $39, $2F, $35, $07, $32, $65, $21, $2C, $32, $25, $21, $24, $79, $23, $21, $32, $32, $39, $29, $2E, $67, $29, $F4 ' "TAKEN." fixed_str_taken: DATA AS BYTE $34, $21, $2B, $25, $EE ' "$TAKEN!" fixed_str_treasure_taken: DATA AS BYTE $04, $34, $21, $2B, $25, $2E, $C1 ' "ALWAYS FULL DESCRIPTIONS FROM NOW ON." fixed_str_always_full_descriptions_on: DATA AS BYTE $21, $2C, $37, $21, $39, $73, $26, $35, $2C, $6C, $24, $25, $33, $23, $32, $29, $30, $34, $29, $2F, $2E, $73, $26, $32, $2F, $6D, $2E, $2F, $77, $2F, $EE ' "THAT WAS A RHETORICAL QUESTION." fixed_str_that_was_a_rhetorical_question: DATA AS BYTE $34, $28, $21, $74, $37, $21, $73, $61, $32, $28, $25, $34, $2F, $32, $29, $23, $21, $6C, $31, $35, $25, $33, $34, $29, $2F, $EE ' "YOU SCORED A TOTAL OF " fixed_str_your_score: DATA AS BYTE $39, $2F, $75, $33, $23, $2F, $32, $25, $64, $61, $34, $2F, $34, $21, $6C, $2F, $26, $C0 ' " POINTS, OUT|OF A POSSIBLE MAXIMUM OF 125 POINTS." fixed_str_maximum_score: DATA AS BYTE $00, $30, $2F, $29, $2E, $34, $33, $4C, $2F, $35, $B4, $2F, $66, $61, $30, $2F, $33, $33, $29, $22, $2C, $65, $2D, $21, $38, $29, $2D, $35, $6D, $2F, $66, $11, $12, $55, $30, $2F, $29, $2E, $34, $F3 ' "YOU WIN!!" fixed_str_you_win: DATA AS BYTE $39, $2F, $75, $37, $29, $2E, $01, $C1 ' "YOU'VE SOLVED IT ALL!|HAIL THE CONQUERING ADVENTURER!" fixed_str_conquered: DATA AS BYTE $39, $2F, $35, $07, $36, $65, $33, $2F, $2C, $36, $25, $64, $29, $74, $21, $2C, $2C, $81, $28, $21, $29, $6C, $34, $28, $65, $23, $2F, $2E, $31, $35, $25, $32, $29, $2E, $67, $21, $24, $36, $25, $2E, $34, $35, $32, $25, $32, $C1 ' "PRESS ANY KEY TO TRY AGAIN." fixed_str_try_again: DATA AS BYTE $30, $32, $25, $33, $73, $21, $2E, $79, $2B, $25, $79, $34, $6F, $34, $32, $79, $21, $27, $21, $29, $EE data_mem_end: declare sub strngPrnt(bLngStrng as BYTE, wMemLoc as WORD, bFirstCharOffset as BYTE, bCharOffset as BYTE, bExitFlag as BYTE) STATIC declare sub describeRoom() STATIC declare sub loadAndUpdateCurrentRoom() STATIC declare function checkDirections as BYTE (bMovingDirection as BYTE) STATIC declare sub processCommand() STATIC declare sub prntSingleChar(bChar as BYTE) STATIC declare sub shuffleRandomList() STATIC declare sub eraseCharacters() STATIC declare sub drawMap() STATIC declare sub drawMap_drawRoom() STATIC declare sub drawMap_clear() STATIC declare sub moveObject(bObjectNumRequested as BYTE, bMoveTo_Col as BYTE, bMoveTo_Row as BYTE) STATIC declare sub waitForKey() STATIC declare sub updateScore() STATIC declare sub makeApause(bJiffiesToWait as BYTE) STATIC declare sub synchromyEnding() STATIC declare function myRandom as BYTE (bMax as BYTE, bMask as BYTE) STATIC Const TRUE = 255 Const FALSE = 0 type tVerbs wpName as WORD wpDefaultMessage as WORD bCommandStartIndex as BYTE end type Dim aVerbs(26) as tVerbs @verbs_struct type tObjects wpName as WORD bObjectKind as BYTE wpDescription as WORD end type Dim aObjects(26) as tObjects @objects_struct Const OBJECT_LIVE_MAP = 11 Const OBJECTKIND_TREASURE = 36 type tRooms bRoomLetter as BYTE bDirections as BYTE wpBlockingReason as WORD wpDescription as WORD end type Const ROOMS_MAXINDEX = 82 Dim aRooms(83) as tRooms @rooms_struct Const ROOM_REPOSITORY = 62 Const ROOM_ENTRANCE = 1 Const ROOM_GAMEWON = 254 Const ROOM_GAMEQUIT = 253 type tCommands bActionNumber as BYTE bObjectNumber as BYTE bLocationNumber as BYTE bNewObjectLocationNumber as BYTE wpNewObjectDescription as WORD bNewLocationNumber as BYTE wpNewLocationDescription as WORD wpMessage as WORD bNewDirections as BYTE end type Const COMMANDS_MAXINDEX = 109 Dim aCommands(110) as tCommands @commands_struct type tMap bRoomNumber as BYTE wpRoomDescription as WORD bRoomDirections as BYTE bCharToDraw as BYTE bCharColor as BYTE end type Const MAP_XMAX = 8 Const MAP_YMAX = 9 Dim aMap(9, 10) as tMap Const DIR_NORTH = %00001000 Const DIR_EAST = %00000100 Const DIR_SOUTH = %00000010 Const DIR_WEST = %00000001 type tObjectsMap bCol as BYTE bRow as BYTE wpCurrentDescription as WORD bCurrentKind as BYTE end type Dim aObjectsMap(26) as tObjectsMap Const OBJ_CARRIED = 255 '-1 Const OBJ_REMOVED = 254 '-2 Const OBJ_IN_ROOM = 253 '-3 Const OBJ_NOT_FOUND = 252 '-4 CONST GENHELP_MAXINDEX = 3 Dim aHelpLines(4) as WORD @general_help_struct Dim bBorder as BYTE @$D020 Dim bBackground as BYTE @$D021 Dim bInkColor as BYTE @646 'text colour Dim bCursorFlash as BYTE @$CC 'this controls the flashing of the cursor Dim bCursorColumn as BYTE @211 'cursor LOGICAL column position... Dim bCursorRow as BYTE @214 'cursor row position bBorder = 0 : bBackground = 0 'black sys $E544 FAST 'clear screen poke 657, 128 'disable C= & Shift to change case poke $D018, %00010111 'screen $0400, char location: $1800 (lowercase) poke 808, 234 'THE OLD BASIC WAY OF DISABLING RUNSTOP+RESTORE! :'-) Dim bLinesScrolled as BYTE : bLinesScrolled = 128 'the intro screen doesn't need counting the printed lines Dim bBitFlags as BYTE FAST Dim bLngStrng_LastChar as BYTE Const LNG_STRNG = 255 Const SHRT_STRNG = 0 '***************************************PRINT INTRO SCREEN bCursorRow = 23 : call prntSingleChar(13) 'so that it actually starts printing from line 24 bInkColor = 1 'white call strngPrnt(LNG_STRNG, @fixed_str_gamename, 32, 0, %11000000) : call prntSingleChar(13) bInkColor = 5 'green call strngPrnt(SHRT_STRNG, @fixed_str_credits, 0, 0, %11000000) call prntSingleChar(13) : call prntSingleChar(13) bInkColor = 3 'cyan call strngPrnt(LNG_STRNG, @fixed_str_start_game, 32, 0, %11000000) '********************************************************* '********************PATCH KERNAL********************************** 'Copy KERNAL to RAM, patch in the number of *unscrollable* lines (thanks Diduz! - https://diduz.itch.io ) memcpy $E000, $E000, 8192 POKE $01, 53 'for some MYSTERIOUS reason, $01 has to be %00110101 and NOT %00110100 POKE 59639, 9 'number of unscrollable lines (range 0 - 9) '****************************************************************** restart_adv: call waitForKey() VOLUME 15 call prntSingleChar(13) '******************DRAW UPPER PART************************************** 'clear upper part memset $0400, 360, 32 'spaces on the first 9 lines of the screen 'brown colour for the Map space memset $D800, 360, 9 'brown colour set on the first 9 lines of the screen 'N S E W charat 26, 1, $4E, 11 '"N" - dark grey charat 25, 2, $57, 11 '"W" - dark grey charat 27, 2, $45, 11 '"E" - dark grey charat 26, 3, $53, 11 '"S" - dark grey 'horizontal line on the 10th line of the screen memset $D968, 40, 1 'set the 10th line of the screen to white memset $0568, 40, $40 Dim bColIndex as BYTE FAST Dim bRowIndex as BYTE FAST For bRowIndex = 0 to 8 charat 23, bRowIndex, $5D, 1 'vertical line 1, white charat 30, bRowIndex, $5D, 1 'vertical line 2, white next bRowIndex charat 23, 9, $71, 1 'junction with the horizontal line 1, in white charat 30, 9, $71, 1 'junction with the horizontal line 1, in white textat 24, 6, "Score:", 8 'orange textat 26, 8, 0, 7 'yellow textat 31, 3, "Inventory", 8 'orange textat 33, 4, "count:", 8 'orange textat 35, 6, 0, 7 'yellow '*********************************************************************** bBorder = 11 'dark grey VOICE 1 ADSR 8, 0, 8, 12 WAVE PULSE PULSE 1024 TONE 8192 ON Dim bScanIndex as BYTE FAST 'multi-purpose variable for For-next cycles and whatnot Dim bAccumulator as BYTE FAST 'multi-purpose variable Randomize TI() 'discarding the first 10 random numbers as they are not that random, alas For bScanIndex = 1 to 10 bAccumulator = RNDB() '"recycled" as dummy variable next bScanIndex Dim bPlayer_Row as BYTE Dim bPlayer_Col as BYTE Dim bPlayer_LastOppositeDirection as BYTE : bPlayer_LastOppositeDirection = 0 Dim bPlayer_InventoryCount as BYTE : bPlayer_InventoryCount = 0 Dim bPlayer_Score as BYTE : bPlayer_Score = 0 Dim bPlayer_Map_PreviousRow as BYTE FAST Dim bPlayer_Map_PreviousCol as BYTE FAST Dim bPlayer_PreviousRow as BYTE FAST Dim bPlayer_PreviousCol as BYTE FAST '-------------------------MAP-BUILDING---------------------------------------------- Dim aRandomList(90) as BYTE 'a deck of "cards" to store room numbers to shuffle Dim aRandomObjectList(90) as BYTE 'a deck of "cards" to store object numbers to shuffle 'Shuffle the object numbers first memset @aRandomList, 90, 255 'initialize the array with all 255s for bScanIndex = 0 to 25 aObjectsMap(bScanIndex).bCol = OBJ_NOT_FOUND if aObjects(bScanIndex).wpName > $0000 then aRandomList(bScanIndex) = bScanIndex next bScanIndex swap aRandomList(OBJECT_LIVE_MAP), aRandomList(0) 'swap the "L"ive map with the start of the deck call shuffleRandomList() bAccumulator = myRandom(3, 3) + 4 swap aRandomList(0), aRandomList(bAccumulator) 'move the "L"ive map to a position between 4 and 7 (swapping the cards) memcpy @aRandomList, @aRandomObjectList, 90 'now re-use aRandomList for the rooms memset @aRandomList, 90, 0 'initialize the array with all zeros For bScanIndex = 1 to ROOMS_MAXINDEX aRandomList(bScanIndex) = bScanIndex next bScanIndex swap aRandomList(ROOM_ENTRANCE), aRandomList(0) 'swap the Entrance room with the start of the deck swap aRandomList(ROOM_REPOSITORY), aRandomList(85) 'swap the Repository room with the 86th position of the deck call shuffleRandomList() bAccumulator = myRandom(7, 7) + 47 swap aRandomList(85), aRandomList(bAccumulator) For bColIndex = 0 to MAP_XMAX For bRowIndex = 0 to MAP_YMAX aMap(bColIndex, bRowIndex).bRoomNumber = 255 'mark the room as "new" aMap(bColIndex, bRowIndex).bRoomDirections = 0 'every new room starts with no directions available Next bRowIndex Next bColIndex bPlayer_Col = myRandom(MAP_XMAX, 15) bPlayer_Row = myRandom(MAP_YMAX, 15) '-------------------------END-MAP-BUILDING------------------------------------------ VOICE 1 TONE 16384 OFF Dim bRoom_CurrNumber as BYTE Dim bRoom_CurrDirections as BYTE Dim bRoom_New as BYTE Dim wpRoom_Creature as WORD Dim bGenericCounter as BYTE FAST Dim bNewRoomSequenceIndex as BYTE : bNewRoomSequenceIndex = 0 Dim bAction_Petscii as BYTE Dim bObject_Petscii as BYTE Dim bAction_Petscii_Previous as BYTE Dim bAction_Index as BYTE Dim bObject_Index as BYTE Dim bObject_KindCached as BYTE Dim bCommand_OK as BYTE Dim wpPostPromptMessage as WORD Dim bCommand_CurrStartIndex as BYTE FAST Dim bVerboseDescripts as BYTE : bVerboseDescripts = FALSE Dim bGenHelpIndex as BYTE : bGenHelpIndex = 0 Dim bInputPhase as BYTE Dim aCursorPreviousColumnPos(3) as BYTE 'one for each phase of the Input Dim bDrawMap_ForceRedraw as BYTE FAST : bDrawMap_ForceRedraw = TRUE Dim wSoundTone as WORD FAST Const SCORE_MAX = 125 Dim bScoreDelta as BYTE FAST : bScoreDelta = 0 bBorder = 6 'blue '************************MAIN LOOP************************************** bAction_Petscii = 0 bLinesScrolled = 0 call describeRoom() do 'this is done up here because, in the event a Treasure is first "dealt" in the Repository, the score MUST be updated! if bScoreDelta then call updateScore() bLinesScrolled = 254 : call prntSingleChar(13) 'separate input prompt from any text printed before call prntSingleChar(62) '">" a.k.a. the PROMPT bAction_Petscii_Previous = bAction_Petscii bInputPhase = 0 do bCursorFlash = 0 call waitForKey() bCursorFlash = 255 on bInputPhase goto INPT_VERB, INPT_SPACE, INPT_OBJECT, INPT_ENTER INPT_VERB: get bAction_Petscii if (bAction_Petscii < 65) OR (bAction_Petscii > 90) then continue do bAction_Index = bAction_Petscii - 65 if (aVerbs(bAction_Index).wpName = $0000) then continue do 'alas, a few verbs are empty... bObject_Petscii = 0 aCursorPreviousColumnPos(0) = bCursorColumn call strngPrnt(SHRT_STRNG, aVerbs(bAction_Index).wpName AND %0111111111111111, 32, 32, %11000000) if (aVerbs(bAction_Index).wpName AND %1000000000000000) > 0 then bInputPhase = bInputPhase + 1 'wait for SPACE else bInputPhase = 3 'wait directly for the RETURN key end if continue do INPT_SPACE: get bScanIndex 'recycled as temporary place to read the key pressed if bScanIndex = 20 then 'Del (backspace) bInputPhase = bInputPhase - 1 'go back to accept a Verb call eraseCharacters() continue do end if if bScanIndex = 32 then 'SPACE aCursorPreviousColumnPos(1) = bCursorColumn call prntSingleChar(32) 'print a SPACE bInputPhase = bInputPhase + 1 'now wait for the Object to be inputted end if continue do INPT_OBJECT: get bObject_Petscii if bObject_Petscii = 20 then 'Del (backspace) bInputPhase = bInputPhase - 1 'go back waiting for a SPACE call eraseCharacters() continue do end if if (bObject_Petscii < 65) OR (bObject_Petscii > 90) then continue do bObject_Index = bObject_Petscii - 65 if (aObjectsMap(bObject_Index).bCol = OBJ_NOT_FOUND) then continue do 'refuse Object if it hasn't been found yet bObject_KindCached = aObjectsMap(bObject_Index).bCurrentKind aCursorPreviousColumnPos(2) = bCursorColumn call strngPrnt(SHRT_STRNG, aObjects(bObject_Index).wpName, 32, 32, %11000000) bInputPhase = bInputPhase + 1 'now wait for the Return key continue do INPT_ENTER: get bScanIndex 'recycled as temporary place to read the key pressed if bScanIndex = 20 then 'Del (backspace) if bObject_Petscii then bInputPhase = bInputPhase - 1 'go back to accept another Object else bInputPhase = 0 'go straight back to accept another Verb end if call eraseCharacters() continue do end if if bScanIndex = 13 then 'Return key call prntSingleChar(32) 'prints a space to erase the cursor, in case it's visible call prntSingleChar(13) 'print a CR call prntSingleChar(13) 'print another CR to separate the input line from the text that will follow exit do 'Everything needed has been inputted! end if loop if bObject_Petscii then if (bPlayer_Col <> aObjectsMap(bObject_Index).bCol OR bPlayer_Row <> aObjectsMap(bObject_Index).bRow) and aObjectsMap(bObject_Index).bCol <> OBJ_CARRIED then bInkColor = 15 'light grey call strngPrnt(SHRT_STRNG, @fixed_str_i_see_no, 32, 0, %11000000) '"I see no" call strngPrnt(SHRT_STRNG, aObjects(bObject_Index).wpName, 0, 0, %11000000) '"" call strngPrnt(LNG_STRNG, @fixed_str_here, 0, 0, %11000000) '"here." - The is automatic continue do 'restart Main Loop end if end if bCommand_OK = TRUE bInkColor = 3 'cyan wpPostPromptMessage = aVerbs(bAction_Index).wpDefaultMessage '~ on bAction_Index goto VERB_ACTIONS, VERB_BACK, VERB_CLOSE, VERB_DROP, VERB_EAST, VERB_FIGHT, VERB_GIVE, VERB_HELP, VERB_INVENTORY, VERB_JUMP, _ '~ VERB_KICK, VERB_LOOK, VERB_MAP, VERB_NORTH, VERB_OPEN, VERB_POINTS, VERB_QUIT, VERB_READ, VERB_SOUTH, VERB_TAKE, _ '~ VERB_USE, VERB_VERBOSE, VERB_WEST, VERB_XPLORE, VERB_YES, VERB_ZZZ on bAction_Index goto VERB_ACTIONS, VERB_BACK, VERB_CLOSE, VERB_DROP, VERB_EAST, VERB_FIGHT, VERB_GIVE, VERB_HELP, VERB_INVENTORY, VERB_JUMP, _ VERB_FIGHT, VERB_LOOK, VERB_end, VERB_NORTH, VERB_OPEN, VERB_end, VERB_end, VERB_end, VERB_SOUTH, VERB_TAKE, _ VERB_end, VERB_VERBOSE, VERB_WEST, VERB_XPLORE, VERB_YES, VERB_end VERB_ACTIONS: call strngPrnt(LNG_STRNG, wpPostPromptMessage, 32, 0, %11000000) bGenericCounter = 0 'recycled to simulate TAB() for bScanIndex = 0 to 25 if aVerbs(bScanIndex).wpName > 0 then bCursorColumn = bGenericCounter call strngPrnt(SHRT_STRNG, aVerbs(bScanIndex).wpName AND %0111111111111111, 32, 0, %11000000) bGenericCounter = bGenericCounter + 10 : if bGenericCounter > 30 then call prntSingleChar(13) : bGenericCounter = 0 end if next bScanIndex goto VERB_end VERB_BACK: select case bPlayer_LastOppositeDirection case DIR_NORTH goto VERB_NORTH case DIR_EAST goto VERB_EAST case DIR_SOUTH goto VERB_SOUTH case DIR_WEST goto VERB_WEST end select goto VERB_end VERB_CLOSE: bCommand_OK = FALSE if bObject_KindCached = $2B then '"+" aObjectsMap(bObject_Index).bCurrentKind = $2D '"-" wpPostPromptMessage = @fixed_str_it_is_now_closed bCommand_OK = TRUE else if bObject_KindCached = $2D then '"-" wpPostPromptMessage = @fixed_str_it_was_already_closed end if end if goto VERB_end VERB_DROP: if aObjectsMap(bObject_Index).bCol <> OBJ_CARRIED then bCommand_OK = FALSE else call moveObject(bObject_Index, bPlayer_Col, bPlayer_Row) wpPostPromptMessage = @fixed_str_dropped if bObject_Index = OBJECT_LIVE_MAP then call drawMap_clear() 'so that the Map is erased right away... >-( end if goto VERB_end VERB_EAST: if checkDirections(DIR_EAST) then bPlayer_Col = bPlayer_Col + 1 if bPlayer_Col > MAP_XMAX then bPlayer_Col = 0 bPlayer_LastOppositeDirection = DIR_WEST goto VERB_LOOK 'calls describeRoom() and loops end if goto VERB_end VERB_FIGHT: 'these two are for handling an alias (KICK) which GOTOs here bAction_Petscii = 70 '"F"ight bAction_Index = 5 goto VERB_end VERB_GIVE: wpRoom_Creature = aMap(bPlayer_Col, bPlayer_Row).wpRoomDescription do bAccumulator = peek(wpRoom_Creature) if (bAccumulator AND %11000000) = %11000000 then bCommand_OK = FALSE : exit do 'loop until the end of the string wpRoom_Creature = wpRoom_Creature + 1 if (bAccumulator AND %00111111) = 32 then exit do 'that's "@" but "encoded" - the Creature name starts right after the @ loop goto VERB_end VERB_HELP: wpPostPromptMessage = aHelpLines(bGenHelpIndex) bGenHelpIndex = (bGenHelpIndex + 1) AND 3 goto VERB_end VERB_INVENTORY: call strngPrnt(LNG_STRNG, wpPostPromptMessage, 32, 0, %11000000) for bScanIndex = 0 to 25 if aObjectsMap(bScanIndex).bCol = OBJ_CARRIED then bInkColor = 1 'white if aObjectsMap(bScanIndex).bCurrentKind = OBJECTKIND_TREASURE then bInkColor = 7 'yellow call strngPrnt(SHRT_STRNG, aObjects(bScanIndex).wpName, 32, 0, %11000000) call prntSingleChar(13) end if next bScanIndex '"Lamp" is a fake object always carried bInkColor = 15 'light grey call strngPrnt(SHRT_STRNG, @fixed_str_headlamp, 32, 0, %11000000) : call prntSingleChar(13) bInkColor = 1 'white goto VERB_end VERB_JUMP: call strngPrnt(LNG_STRNG, wpPostPromptMessage, 32, 0, %11000000) if (myRandom(255, 255) > 99) then ' ~60% probability of dropping an object bGenericCounter = 255 for bScanIndex = 0 to 25 if (bScanIndex <> OBJECT_LIVE_MAP) AND (aObjectsMap(bScanIndex).bCol = OBJ_CARRIED) then bGenericCounter = bScanIndex next bScanIndex if bGenericCounter < 255 then call strngPrnt(SHRT_STRNG, @fixed_str_as_you_jumped_you_dropped_the, 32, 0, %11000000) call strngPrnt(SHRT_STRNG, aObjects(bGenericCounter).wpName, 0, 0, %11000000) : call prntSingleChar(33) '"!" call prntSingleChar(13) 'CR call moveObject(bGenericCounter, bPlayer_Col, bPlayer_Row) end if end if goto VERB_XPLORE '*not* VERB_end ! VERB_LOOK: call describeRoom() continue do VERB_NORTH: if checkDirections(DIR_NORTH) then bPlayer_Row = bPlayer_Row - 1 if bPlayer_Row = 255 then bPlayer_Row = MAP_YMAX bPlayer_LastOppositeDirection = DIR_SOUTH goto VERB_LOOK 'calls describeRoom() and loops end if goto VERB_end VERB_OPEN: bCommand_OK = FALSE if bObject_KindCached = $2D then '"-" aObjectsMap(bObject_Index).bCurrentKind = $2B '"+" wpPostPromptMessage = @fixed_str_it_is_now_opened bCommand_OK = TRUE else if bObject_KindCached = $2B then '"+" wpPostPromptMessage = @fixed_str_it_was_already_opened end if end if goto VERB_end VERB_SOUTH: if checkDirections(DIR_SOUTH) then bPlayer_Row = bPlayer_Row + 1 if bPlayer_Row > MAP_YMAX then bPlayer_Row = 0 bPlayer_LastOppositeDirection = DIR_NORTH goto VERB_LOOK 'calls describeRoom() and loops end if goto VERB_end VERB_TAKE: bCommand_OK = FALSE if aObjectsMap(bObject_Index).bCol = OBJ_CARRIED then wpPostPromptMessage = @fixed_str_youre_already_carrying_it else if bPlayer_InventoryCount < 8 then bCommand_OK = TRUE bPlayer_InventoryCount = bPlayer_InventoryCount + 1 call moveObject(bObject_Index, OBJ_CARRIED, OBJ_CARRIED) wpPostPromptMessage = @fixed_str_taken if bObject_KindCached = OBJECTKIND_TREASURE then wpPostPromptMessage = @fixed_str_treasure_taken if bObject_Index = OBJECT_LIVE_MAP then call drawMap() 'so that the Map appears right away :-) if (bRoom_CurrNumber = ROOM_REPOSITORY) AND (bObject_KindCached = OBJECTKIND_TREASURE) then bScoreDelta = %11111011 '"$", -5 end if end if goto VERB_end VERB_VERBOSE: bVerboseDescripts = NOT bVerboseDescripts if bVerboseDescripts then wpPostPromptMessage = @fixed_str_always_full_descriptions_on goto VERB_end VERB_WEST: if checkDirections(DIR_WEST) then bPlayer_Col = bPlayer_Col - 1 if bPlayer_Col = 255 then bPlayer_Col = MAP_XMAX bPlayer_LastOppositeDirection = DIR_EAST goto VERB_LOOK 'calls describeRoom() and loops end if goto VERB_end VERB_XPLORE: bGenericCounter = 4 'recycled as the number of required open directions... if bAction_Petscii = 88 then '"X"plore - JUMP also GOTOs here ... call strngPrnt(LNG_STRNG, wpPostPromptMessage, 32, 0, %11000000) bGenericCounter = 2 'recycled as the number of required open directions... end if call prntSingleChar(13) 'CR Dim bNewRoomRandomIndex as BYTE FAST : bNewRoomRandomIndex = bNewRoomSequenceIndex - 1 Dim bFoundNewRandomRoom as BYTE FAST VOICE 1 WAVE NOISE TONE 13169 ADSR 11, 0, 15, 10 ON call makeApause(5) for bScanIndex = 1 to 8 'eight tries to find a "new" room with the right number of open directions do do bColIndex = myRandom(MAP_XMAX, 15) 'range 0-8 loop while bColIndex = bPlayer_Col do bRowIndex = myRandom(MAP_YMAX, 15) 'range 0-9 loop while bRowIndex = bPlayer_Row bFoundNewRandomRoom = FALSE bRoom_New = aMap(bColIndex, bRowIndex).bRoomDirections 'recycled to copy the possible new room directions if aMap(bColIndex, bRowIndex).bRoomNumber = 255 then 'if the room is "new" bFoundNewRandomRoom = TRUE if bNewRoomRandomIndex < 89 then bNewRoomRandomIndex = bNewRoomRandomIndex + 1 bRoom_New = aRooms(aRandomList(bNewRoomRandomIndex)).bDirections end if bBitFlags = 0 'recycled to count the open directions if (bRoom_New AND %10000000) then 'if this room is blocked, it's not a valid destination else if (bRoom_New AND DIR_NORTH) then bBitFlags = bBitFlags + 1 if (bRoom_New AND DIR_EAST) then bBitFlags = bBitFlags + 1 if (bRoom_New AND DIR_SOUTH) then bBitFlags = bBitFlags + 1 if (bRoom_New AND DIR_WEST) then bBitFlags = bBitFlags + 1 end if loop while (bBitFlags > bGenericCounter) OR (bBitFlags = 0) 'the new room MUST have the number (or less, but not zero) of open directions required by JUMP or XPLORE if (bFoundNewRandomRoom) then swap aRandomList(bNewRoomSequenceIndex), aRandomList(bNewRoomRandomIndex) exit for end if next bScanIndex 'after eight tries, even a room which is not "new" will be fine... bPlayer_Col = bColIndex bPlayer_Row = bRowIndex bPlayer_LastOppositeDirection = 0 'forget where the Player came from VOICE 1 OFF goto VERB_LOOK 'calls describeRoom() and loops VERB_YES: if bAction_Petscii_Previous = 81 then '"Q"uit bRoom_CurrNumber = ROOM_GAMEQUIT '~ wpPostPromptMessage = 0 'skip default message exit do 'nothing to process, nothing to print, it's simpler to directly exit the main loop end if if bLngStrng_LastChar = 63 then '"?" wpPostPromptMessage = @fixed_str_that_was_a_rhetorical_question end if VERB_end: if bCommand_OK then bCommand_CurrStartIndex = aVerbs(bAction_Index).bCommandStartIndex if bCommand_CurrStartIndex < 255 then call processCommand() else bInkColor = 15 'light grey end if if wpPostPromptMessage > 0 then call strngPrnt(LNG_STRNG, wpPostPromptMessage, 32, 0, %11000000) 'this also zeroes wpPostPromptMessage end if loop while bRoom_CurrNumber < ROOM_GAMEQUIT 'end of MAIN LOOP ********************************************************************* 'give 1 point for each Treasure carried for bScanIndex = 0 to 25 if aObjectsMap(bScanIndex).bCurrentKind = OBJECTKIND_TREASURE then if aObjectsMap(bScanIndex).bCol = OBJ_CARRIED then bScoreDelta = bScoreDelta + 1 end if next bScanIndex if bScoreDelta then call updateScore() if bRoom_CurrNumber = ROOM_GAMEWON then bInkColor = 7 'yellow call strngPrnt(LNG_STRNG, @fixed_str_you_win, 32, 0, %11000000) bInkColor = 3 'cyan call prntSingleChar(13) end if call strngPrnt(SHRT_STRNG, @fixed_str_your_score, 32, 0, %11000000) print bPlayer_Score ; call strngPrnt(LNG_STRNG, @fixed_str_maximum_score, 0, 0, %11000000) if bPlayer_Score = SCORE_MAX then bLinesScrolled = 254 call strngPrnt(LNG_STRNG, @fixed_str_conquered, 32, 0, %11000000) call synchromyEnding() end if call prntSingleChar(13) call strngPrnt(LNG_STRNG, @fixed_str_try_again, 32, 0, %11000000) goto restart_adv sub strngPrnt(bLngStrng as BYTE, wMemLoc as WORD, bFirstCharOffset as BYTE, bCharOffset as BYTE, bExitFlag as BYTE) STATIC dim bUpperCaseNumber as BYTE FAST : bUpperCaseNumber = bFirstCharOffset dim bQuoteToggle as BYTE FAST : bQuoteToggle = 32 Dim bMainTextColor as BYTE FAST bMainTextColor = bInkColor do bCommand_CurrStartIndex = peek(wMemLoc) 'recycled to cache the wMemLoc content bAccumulator = (bCommand_CurrStartIndex AND %00111111) + 32 'adding 32 "decodes" the character 'Characters to intercept select case bAccumulator case $2A' "*" - marker for short descriptions if NOT bVerboseDescripts then if (bRoom_New = FALSE) AND (bAction_Petscii <> 76) then '"L"ook bAccumulator = 65 '"A" - so that a full stop *will* be printed at the end exit do end if end if bAccumulator = 0 case $3E ' ">" bUpperCaseNumber = 32 'always bring the next character to Upper case bAccumulator = 0 case $23 ' "#" bInkColor = 13 'light green bAccumulator = 0 case $24 ' "$" bInkColor = 7 'yellow bAccumulator = 0 case $40 ' "@" bInkColor = 10 'light red bAccumulator = 0 end select 'Character printing if bAccumulator then if (bAccumulator AND %01000000) then 'if it contains a letter... bAccumulator = bAccumulator + bUpperCaseNumber bUpperCaseNumber = bCharOffset else select case bAccumulator case $2E, $21, $3F '".", "!", "?" bUpperCaseNumber = bFirstCharOffset case $22 ' quotes bUpperCaseNumber = bUpperCaseNumber OR bQuoteToggle bQuoteToggle = bQuoteToggle XOR 32 case $2C ' "," bInkColor = bMainTextColor end select end if call prntSingleChar(bAccumulator) end if bBitFlags = (bCommand_CurrStartIndex AND %11000000) if bBitFlags = bExitFlag then exit do '%11000000 = string END - %01000000 = SPACE select case bBitFlags case %01000000 'print SPACE bInkColor = bMainTextColor call prntSingleChar(32) 'SPACE case %10000000 'print CR bInkColor = bMainTextColor call prntSingleChar(13) 'Carriage Return end select wMemLoc = wMemLoc + 1 loop if bLngStrng then bLngStrng_LastChar = bAccumulator if (bAccumulator AND %01000000) then 'if the last char printed is a letter... call prntSingleChar( $2E) 'full stop end if bInkColor = 1 'white - doing this to mitigate (but not completely solve) a problem with the flashing cursor not always showing in white if bCursorColumn <> 40 then call prntSingleChar(13) wpPostPromptMessage = 0 'the string has been printed, so this gets zeroed (and doesn't risk getting printed again) end if end sub sub describeRoom() STATIC if bAction_Petscii <> 76 then call loadAndUpdateCurrentRoom() 'if the player said "L"ook there's nothing to load & update & draw... bInkColor = 5 'green call strngPrnt(LNG_STRNG, aMap(bPlayer_Col, bPlayer_Row).wpRoomDescription, 32, 0, %11000000) 'Manage Objects in the Room! bGenericCounter = 0 for bScanIndex = 0 to 25 if aObjectsMap(bScanIndex).bCol = OBJ_IN_ROOM then if aObjectsMap(bScanIndex).bRow <> bRoom_CurrNumber then continue for call moveObject(bScanIndex, bPlayer_Col, bPlayer_Row) end if if aObjectsMap(bScanIndex).bCol = bPlayer_Col AND aObjectsMap(bScanIndex).bRow = bPlayer_Row then if bGenericCounter = 0 then call prntSingleChar(13) 'first object found separates its description from the room description bInkColor = 5 'green call strngPrnt(LNG_STRNG, aObjectsMap(bScanIndex).wpCurrentDescription, 32, 0, %11000000) bGenericCounter = bGenericCounter + 1 end if next bScanIndex end sub sub loadAndUpdateCurrentRoom() STATIC bRoom_New = FALSE bRoom_CurrNumber = aMap(bPlayer_Col, bPlayer_Row).bRoomNumber bRoom_CurrDirections = aMap(bPlayer_Col, bPlayer_Row).bRoomDirections if bRoom_CurrNumber = 255 then 'if the room is "new"... bRoom_New = TRUE bRoom_CurrNumber = aRandomList(bNewRoomSequenceIndex) aMap(bPlayer_Col, bPlayer_Row).bRoomNumber = bRoom_CurrNumber aMap(bPlayer_Col, bPlayer_Row).wpRoomDescription = aRooms(bRoom_CurrNumber).wpDescription aMap(bPlayer_Col, bPlayer_Row).bCharToDraw = 32 if bRoom_CurrNumber = ROOM_REPOSITORY then aMap(bPlayer_Col, bPlayer_Row).bCharToDraw = $D2 'reversed "R" aMap(bPlayer_Col, bPlayer_Row).bCharColor = 7 'yellow end if bRoom_CurrDirections = aRooms(bRoom_CurrNumber).bDirections OR aMap(bPlayer_Col, bPlayer_Row).bRoomDirections aMap(bPlayer_Col, bPlayer_Row).bRoomDirections = bRoom_CurrDirections bScanIndex = aRandomObjectList(bNewRoomSequenceIndex) 'recycled to read the next newfound object to place here if bScanIndex < 255 then aObjectsMap(bScanIndex).wpCurrentDescription = aObjects(bScanIndex).wpDescription aObjectsMap(bScanIndex).bCurrentKind = aObjects(bScanIndex).bObjectKind call moveObject(bScanIndex, bPlayer_Col, bPlayer_Row) end if bNewRoomSequenceIndex = bNewRoomSequenceIndex + 1 end if 'if bRoom_CurrNumber = 255 then 'update adjacent rooms. Unfortunately I have to do this *ALWAYS* (too many exceptions to handle otherwise) Dim bAdjacentRoomIndex as BYTE FAST if (bRoom_CurrDirections AND DIR_NORTH) then bAdjacentRoomIndex = bPlayer_Row - 1 if bAdjacentRoomIndex = 255 then bAdjacentRoomIndex = MAP_YMAX aMap(bPlayer_Col, bAdjacentRoomIndex).bRoomDirections = aMap(bPlayer_Col, bAdjacentRoomIndex).bRoomDirections OR DIR_SOUTH end if if bRoom_CurrDirections AND DIR_SOUTH then bAdjacentRoomIndex = bPlayer_Row + 1 if bAdjacentRoomIndex > MAP_YMAX then bAdjacentRoomIndex = 0 aMap(bPlayer_Col, bAdjacentRoomIndex).bRoomDirections = aMap(bPlayer_Col, bAdjacentRoomIndex).bRoomDirections OR DIR_NORTH end if if bRoom_CurrDirections AND DIR_WEST then bAdjacentRoomIndex = bPlayer_Col - 1 if bAdjacentRoomIndex = 255 then bAdjacentRoomIndex = MAP_XMAX aMap(bAdjacentRoomIndex, bPlayer_Row).bRoomDirections = aMap(bAdjacentRoomIndex, bPlayer_Row).bRoomDirections OR DIR_EAST end if if bRoom_CurrDirections AND DIR_EAST then bAdjacentRoomIndex = bPlayer_Col + 1 if bAdjacentRoomIndex > MAP_XMAX then bAdjacentRoomIndex = 0 aMap(bAdjacentRoomIndex, bPlayer_Row).bRoomDirections = aMap(bAdjacentRoomIndex, bPlayer_Row).bRoomDirections OR DIR_WEST end if call drawMap() end sub function checkDirections as BYTE (bMovingDirection as BYTE) STATIC if (bRoom_CurrDirections AND %10000000) then 'if it's a BLOCKED room... if (bPlayer_LastOppositeDirection AND bMovingDirection) then return TRUE wpPostPromptMessage = aRooms(bRoom_CurrNumber).wpBlockingReason VOICE 1 WAVE SAW TONE 390 ADSR 0, 0, 15, 9 ON OFF return FALSE end if if (bRoom_CurrDirections AND bMovingDirection) then return TRUE return FALSE end function sub processCommand() STATIC Dim bExaminedValue as BYTE FAST Dim bAlreadyChanged as BYTE FAST for bScanIndex = bCommand_CurrStartIndex to COMMANDS_MAXINDEX if aCommands(bScanIndex).bActionNumber <> bAction_Petscii then exit for 'not the examined Verb anymore... 'Check the inputted object bExaminedValue = aCommands(bScanIndex).bObjectNumber if bExaminedValue >= 65 then 'if this line has a *specific* object in the Object field... if bExaminedValue <> bObject_Petscii then continue for else if bExaminedValue >= 33 then 'if this line has a Object Kind in the Object field... if bExaminedValue <> bObject_KindCached then continue for end if end if 'Or... the Object field can be blank, which is just fine 'Check the current location bExaminedValue = aCommands(bScanIndex).bLocationNumber if bExaminedValue then if bExaminedValue <> bRoom_CurrNumber then continue for end if 'Or... the Location field can be blank, and that's fine too wSoundTone = 4096 'default sound 'Update the object location and description, and the location number, description & directions (where needed) bAlreadyChanged = FALSE bExaminedValue = aCommands(bScanIndex).bNewObjectLocationNumber select case bExaminedValue case 0 'empty - do nothing case 252 '"DRO" call moveObject(bObject_Index, bPlayer_Col, bPlayer_Row) case 254 '"RMV" call moveObject(bObject_Index, OBJ_REMOVED, OBJ_REMOVED) wSoundTone = 1024 ' "negative" sound case 255 '"RND" do bColIndex = myRandom(MAP_XMAX, 15) loop while bColIndex = bPlayer_Col call moveObject(bObject_Index, bColIndex, myRandom(MAP_YMAX, 15)) case else call moveObject(bObject_Index, OBJ_IN_ROOM, bExaminedValue) end select if aCommands(bScanIndex).wpNewObjectDescription > $0000 then if aObjectsMap(bObject_Index).wpCurrentDescription = aCommands(bScanIndex).wpNewObjectDescription then bAlreadyChanged = TRUE else aObjectsMap(bObject_Index).wpCurrentDescription = aCommands(bScanIndex).wpNewObjectDescription end if end if bExaminedValue = aCommands(bScanIndex).bNewLocationNumber if bExaminedValue then if aMap(bPlayer_Col, bPlayer_Row).wpRoomDescription = aCommands(bScanIndex).wpNewLocationDescription then bAlreadyChanged = TRUE else aMap(bPlayer_Col, bPlayer_Row).bRoomNumber = bExaminedValue aMap(bPlayer_Col, bPlayer_Row).wpRoomDescription = aCommands(bScanIndex).wpNewLocationDescription aMap(bPlayer_Col, bPlayer_Row).bRoomDirections = aCommands(bScanIndex).bNewDirections OR (aMap(bPlayer_Col, bPlayer_Row).bRoomDirections AND %01111111) bScoreDelta = 5 bDrawMap_ForceRedraw = FALSE call loadAndUpdateCurrentRoom() end if end if if NOT bAlreadyChanged then wpPostPromptMessage = aCommands(bScanIndex).wpMessage if bScoreDelta = 0 then VOICE 1 OFF ADSR 0, 0, 9, 9 WAVE TRI TONE wSoundTone ON OFF end if end if exit sub next bScanIndex if bAction_Petscii = 71 then '"G"ive call moveObject(bObject_Index, OBJ_REMOVED, OBJ_REMOVED) call strngPrnt(SHRT_STRNG, @fixed_str_you_give_the, 32, 0, %11000000) call strngPrnt(SHRT_STRNG, aObjects(bObject_Index).wpName, 0, 0, %11000000) call strngPrnt(SHRT_STRNG, @fixed_str_to_the, 0, 0, %11000000) call strngPrnt(LNG_STRNG, wpRoom_Creature, 0, 0, %01000000) 'strngPrnt will end at the first SPACE, not the end of the string! VOICE 1 WAVE TRI TONE 680 ADSR 0, 8, 1, 12 ON OFF end if end sub sub prntSingleChar(bChar as BYTE) STATIC asm LDA {bChar} JSR $FFD2 end asm if (bCursorColumn = 0) OR (bCursorColumn = 40) then bLinesScrolled = bLinesScrolled + 1 if bLinesScrolled = 14 then 'number of lines: 15. 13 scrolled lines + the first one + the one for "(press a key)" textat 0, 24, "(press a key)" 'can't use strngPrnt recursively! :-( call waitForKey() memset $07C0, 13, 32 'clear the "(press a key)" line (13 = length of the textat string) bLinesScrolled = 0 end if end sub sub shuffleRandomList() STATIC For bScanIndex = 1 to 84 'the first and last few cards are left alone do bAccumulator = myRandom(83, 127) + 1 '"recycled" as random selector loop while bAccumulator = bScanIndex swap aRandomList(bScanIndex), aRandomList(bAccumulator) next bScanIndex end sub sub eraseCharacters() STATIC call prntSingleChar(32) 'prints a space to erase the cursor, in case it's visible do call prntSingleChar(20) 'erase a character loop until bCursorColumn = aCursorPreviousColumnPos(bInputPhase) end sub Dim bDrawMap_Col as BYTE FAST Dim bDrawMap_Row as BYTE FAST Dim bDrawMap_Row_Minus_One as BYTE FAST Dim bDrawMap_Row_Plus_One as BYTE FAST Dim bDrawMap_Col_Minus_One as BYTE FAST Dim bDrawMap_Col_Plus_One as BYTE FAST Dim bDrawMap_PreviousRowIndex as BYTE FAST sub drawMap() STATIC Dim bDrawMap_Row_Player as BYTE FAST Dim bDrawMap_Col_Player as BYTE FAST Dim bDrawMap_PlayerRowOffset as BYTE FAST Dim bDrawMap_CurrDirections as BYTE FAST 'handle N W E S bDrawMap_CurrDirections = bRoom_CurrDirections if (bDrawMap_CurrDirections AND %10000000) then bDrawMap_CurrDirections = bPlayer_LastOppositeDirection poke $D842, 11 'dark grey in the "N" position if (bDrawMap_CurrDirections AND DIR_NORTH) then poke $D842, 1 'change it to white poke $D869, 11 'dark grey in the "W" position if (bDrawMap_CurrDirections AND DIR_WEST) then poke $D869, 1 'change it to white poke $D86B, 11 'dark grey in the "E" position if (bDrawMap_CurrDirections AND DIR_EAST) then poke $D86B, 1 'change it to white poke $D892, 11 'dark grey in the "S" position if (bDrawMap_CurrDirections AND DIR_SOUTH) then poke $D892, 1 'change it to white 'no Live Map if the Player is not carrying it! if aObjectsMap(OBJECT_LIVE_MAP).bCol <> OBJ_CARRIED then exit sub 'set the Map "camera" bRowIndex = bPlayer_Row if bRowIndex then bRowIndex = bRowIndex - 1 if bRowIndex > 6 then bRowIndex = 6 bDrawMap_Row_Player = shl(bPlayer_Row, 1) + 1 if bPlayer_Row then bDrawMap_PlayerRowOffset = shl(bPlayer_Row - 1, 1) 'the distance between bPlayerRow and Row 1, times 2) if bDrawMap_PlayerRowOffset > 12 then bDrawMap_PlayerRowOffset = 12 bDrawMap_Row_Player = bDrawMap_Row_Player - bDrawMap_PlayerRowOffset end if bDrawMap_Col_Player = shl(bPlayer_Col, 1) + 3 '+ 1 + 2 ? if (bRowIndex <> bDrawMap_PreviousRowIndex) OR (bDrawMap_ForceRedraw) then '**************DRAW WHOLE MAP************************************************** call drawMap_clear() bDrawMap_PreviousRowIndex = bRowIndex for bDrawMap_Row = 1 to 7 step 2 bDrawMap_Row_Minus_One = bDrawMap_Row - 1 bDrawMap_Row_Plus_One = bDrawMap_Row + 1 bColIndex = 0 for bDrawMap_Col = 3 to 19 step 2 bDrawMap_Col_Minus_One = bDrawMap_Col - 1 bDrawMap_Col_Plus_One = bDrawMap_Col + 1 call drawMap_drawRoom() bColIndex = bColIndex + 1 next bDrawMap_Col bRowIndex = bRowIndex + 1 next bDrawMap_Row bDrawMap_ForceRedraw = FALSE else '**************DRAW ONLY THE PLAYER ROOM*************************************** charat bPlayer_Map_PreviousCol, bPlayer_Map_PreviousRow, _ aMap(bPlayer_PreviousCol, bPlayer_PreviousRow).bCharToDraw, _ aMap(bPlayer_PreviousCol, bPlayer_PreviousRow).bCharColor bDrawMap_Row_Minus_One = bDrawMap_Row_Player - 1 bDrawMap_Row_Plus_One = bDrawMap_Row_Player + 1 bDrawMap_Col_Minus_One = bDrawMap_Col_Player - 1 bDrawMap_Col_Plus_One = bDrawMap_Col_Player + 1 bRowIndex = bPlayer_Row bColIndex = bPlayer_Col bDrawMap_Col = bDrawMap_Col_Player bDrawMap_Row = bDrawMap_Row_Player charat bDrawMap_Col_Player, bDrawMap_Row_Minus_One, $20 'space charat bDrawMap_Col_Minus_One, bDrawMap_Row_Player, $20 'space charat bDrawMap_Col_Plus_One, bDrawMap_Row_Player, $20 'space charat bDrawMap_Col_Player, bDrawMap_Row_Plus_One, $20 'space call drawMap_drawRoom() end if '**************PLOT PLAYER ASTERISK (AND CACHE THE PLAYER INFO)************ charat bDrawMap_Col_Player, bDrawMap_Row_Player, $AA, 1 'reversed asterisk, white bPlayer_Map_PreviousCol = bDrawMap_Col_Player bPlayer_Map_PreviousRow = bDrawMap_Row_Player bPlayer_PreviousCol = bPlayer_Col bPlayer_PreviousRow = bPlayer_Row '***********************DRAW BLOCKED FRAME********************************** if (bRoom_CurrDirections AND %10000000) then bDrawMap_Row_Minus_One = bDrawMap_Row_Player - 1 bDrawMap_Row_Plus_One = bDrawMap_Row_Player + 1 bDrawMap_Col_Minus_One = bDrawMap_Col_Player - 1 bDrawMap_Col_Plus_One = bDrawMap_Col_Player + 1 charat bDrawMap_Col_Minus_One, bDrawMap_Row_Minus_One, $A3 if (bPlayer_LastOppositeDirection AND DIR_NORTH) then else charat bDrawMap_Col_Player, bDrawMap_Row_Minus_One, $A3 end if charat bDrawMap_Col_Plus_One, bDrawMap_Row_Minus_One, $A3 if (bPlayer_LastOppositeDirection AND DIR_WEST) then else charat bDrawMap_Col_Minus_One, bDrawMap_Row_Player, $A3 end if if (bPlayer_LastOppositeDirection AND DIR_EAST) then else charat bDrawMap_Col_Plus_One, bDrawMap_Row_Player, $A3 end if charat bDrawMap_Col_Minus_One, bDrawMap_Row_Plus_One, $A3 if (bPlayer_LastOppositeDirection AND DIR_SOUTH) then else charat bDrawMap_Col_Player, bDrawMap_Row_Plus_One, $A3 end if charat bDrawMap_Col_Plus_One, bDrawMap_Row_Plus_One, $A3 bDrawMap_ForceRedraw = TRUE 'so that the Map gets redrawn when the Player moves away from the blocked room end if end sub sub drawMap_drawRoom() STATIC if aMap(bColIndex, bRowIndex).bRoomNumber = 255 then 'if this room is "new"... charat bDrawMap_Col, bDrawMap_Row, $3F, 11 '"?", dark grey else bGenericCounter = aMap(bColIndex, bRowIndex).bRoomDirections 'recycled if (bGenericCounter AND %10000000) then charat bDrawMap_Col, bDrawMap_Row, aRooms(aMap(bColIndex, bRowIndex).bRoomNumber).bRoomLetter, 2 ' red else charat (bDrawMap_Col_Minus_One), (bDrawMap_Row_Minus_One), $69 if (bGenericCounter AND DIR_NORTH) then else charat (bDrawMap_Col), (bDrawMap_Row_Minus_One), $5F end if charat (bDrawMap_Col_Plus_One), (bDrawMap_Row_Minus_One), $69 if (bGenericCounter AND DIR_WEST) then else charat (bDrawMap_Col_Minus_One), (bDrawMap_Row), $5F end if charat bDrawMap_Col, bDrawMap_Row, aMap(bColIndex, bRowIndex).bCharToDraw, aMap(bColIndex, bRowIndex).bCharColor if (bGenericCounter AND DIR_EAST ) then else charat (bDrawMap_Col_Plus_One), (bDrawMap_Row), $5F end if charat (bDrawMap_Col_Minus_One), (bDrawMap_Row_Plus_One), $69 if (bGenericCounter AND DIR_SOUTH) then else charat (bDrawMap_Col), (bDrawMap_Row_Plus_One), $5F end if charat (bDrawMap_Col_Plus_One), (bDrawMap_Row_Plus_One), $69 end if end if end sub sub drawMap_clear() STATIC memset $0402, 19, 32 memset $042A, 19, 32 memset $0452, 19, 32 memset $047A, 19, 32 memset $04A2, 19, 32 memset $04CA, 19, 32 memset $04F2, 19, 32 memset $051A, 19, 32 memset $0542, 19, 32 bDrawMap_ForceRedraw = TRUE 'always force a Map redraw end sub sub moveObject(bObjectNumRequested as BYTE, bMoveTo_Col as BYTE, bMoveTo_Row as BYTE) STATIC Dim bObjectReplacementIndex as BYTE FAST 'if the player is about to LOSE an object... if aObjectsMap(bObjectNumRequested).bCol = OBJ_CARRIED then bPlayer_InventoryCount = bPlayer_InventoryCount - 1 end if charat 35, 6, ( $30 + bPlayer_InventoryCount), 7 'yellow aObjectsMap(bObjectNumRequested).bCol = bMoveTo_Col aObjectsMap(bObjectNumRequested).bRow = bMoveTo_Row 'if the requested Object is not to be placed where the Player is, it's not a Drop action, so a replacement for the player Map cell must be found if (bMoveTo_Col <> bPlayer_Col) OR (bMoveTo_Row <> bPlayer_Row) then if bRoom_CurrNumber <> ROOM_REPOSITORY then 'don't touch the Repository map position! aMap(bPlayer_Col, bPlayer_Row).bCharToDraw = 32 for bObjectReplacementIndex = 0 to 25 'find a possible replacement for the Map if aObjectsMap(bObjectReplacementIndex).bCol = bPlayer_Col and aObjectsMap(bObjectReplacementIndex).bRow = bPlayer_Row then exit for end if next bObjectReplacementIndex if (bObjectReplacementIndex < 26) then aMap(bPlayer_Col, bPlayer_Row).bCharToDraw = 65 + bObjectReplacementIndex aMap(bPlayer_Col, bPlayer_Row).bCharColor = 13 'light green if aObjectsMap(bObjectReplacementIndex).bCurrentKind = OBJECTKIND_TREASURE then '"$" aMap(bPlayer_Col, bPlayer_Row).bCharColor = 7 'yellow end if end if end if end if 'if the requested Object is to be placed here on the Map, then do it if bMoveTo_Col <= MAP_XMAX then 'don't touch the Map if the Object requested moves in the Repository! But do give the treasure points... if aMap(bMoveTo_Col, bMoveTo_Row).bRoomNumber = ROOM_REPOSITORY then if aObjectsMap(bObjectNumRequested).bCurrentKind = OBJECTKIND_TREASURE then bScoreDelta = 5 exit sub end if aMap(bMoveTo_Col, bMoveTo_Row).bCharToDraw = 65 + bObjectNumRequested aMap(bMoveTo_Col, bMoveTo_Row).bCharColor = 13 'light green if aObjectsMap(bObjectNumRequested).bCurrentKind = OBJECTKIND_TREASURE then '"$" aMap(bMoveTo_Col, bMoveTo_Row).bCharColor = 7 'yellow end if end if end sub sub waitForKey() STATIC poke 198, 0 : wait 198, 1 end sub sub updateScore() STATIC dim bScoreColour as BYTE FAST bPlayer_Score = bPlayer_Score + bScoreDelta bGenericCounter = 26 'recycled if bPlayer_Score > 99 then bGenericCounter = bGenericCounter - 1 memset $0559, 3, 32 'erase (32=SPACE) previous score, in case it goes down from 100 to 95 or from 10 to 5 textat bGenericCounter, 8, bPlayer_Score bScoreColour = 0 'Black wSoundTone = 12288 if bScoreDelta > 127 then wSoundTone = 768 'if the Delta is negative, play a "negative" sound VOICE 1 OFF WAVE PULSE TONE wSoundTone PULSE 2047 ADSR 0, 0, 15, 9 ON OFF for bScanIndex = 1 to 12 memset $D959, 3, bScoreColour 'change the score colour call makeApause(2) bScoreColour = bScoreColour XOR 7 'change to yellow or back to black next bScanIndex bScoreDelta = 0 end sub sub makeApause(bJiffiesToWait as BYTE) STATIC Dim bJiffyTimer as BYTE @ $A2 asm sei lda #$00 sta $A2 cli end asm do : loop while bJiffyTimer <= bJiffiesToWait end sub sub synchromyEnding() STATIC Dim bDescendingVolume as BYTE FAST : bDescendingVolume = 15 Dim bVolumeDescendToggle as BYTE FAST: bVolumeDescendToggle = 0 VOICE 1 ADSR 0, 0, 15, 0 WAVE PULSE PULSE 2048 VOICE 2 ADSR 0, 0, 15, 0 WAVE PULSE PULSE 2048 do VOICE 1 TONE 1277 ON VOICE 2 TONE 10220 ON call makeApause(1) VOICE 2 TONE 20440 ON call makeApause(1) VOICE 1 TONE 5110 ON VOICE 2 TONE 10220 ON call makeApause(1) VOICE 2 TONE 20440 ON call makeApause(1) bVolumeDescendToggle = bVolumeDescendToggle XOR 255 if bVolumeDescendToggle then bDescendingVolume = bDescendingVolume - 1 VOLUME bDescendingVolume asm inc $d020 end asm loop while bDescendingVolume < 128 sound clear bBorder = 6 'blue end sub function myRandom as BYTE (bMax as BYTE, bMask as BYTE) STATIC do myRandom = RNDB() AND bMask loop while myRandom > bMax end function