DECLARE SUB setField (member AS STRING, fldString AS STRING) DECLARE SUB getField (member AS STRING, fldString AS STRING, fldHandle AS INTEGER) DECLARE SUB fieldSelect (member AS STRING, fldOffset AS INTEGER, fldLength AS INTEGER, fldHandle AS INTEGER) TYPE config ' configuration stuff continues AS INTEGER ' offset: 0, length: 2 login AS STRING * 8 ' offset: 2, length: 8 sndfx AS INTEGER ' offset: 10, length: 2 music AS INTEGER ' offset: 12, length: 2 END TYPE CONST handleSTRING = 1 ' this is a string CONST handleINTEGER = 2 ' this is an integer CONST handleTOGGLE = 3 ' this is a toggle DIM SHARED cfg AS config ' settings for the whole program cfg.continues = 3 ' number of continues cfg.login = "me" ' player name cfg.sndfx = 1 ' allow sound effects cfg.music = 9 ' sound card index to use DIM numItems AS INTEGER, itemSkip AS STRING, itemPrefix AS STRING, itemSuffix AS STRING DIM menuSeek AS STRING, menuName AS STRING DIM cursorPos AS INTEGER, cursorNew AS INTEGER, r AS STRING DIM fieldHandle AS INTEGER, fieldCopy AS STRING ' default menu menuSeek = "main" DO ' seek menu IF (LEN(menuSeek)) THEN RESTORE dataMenu DO READ menuName, numItems SELECT CASE menuName ' menu doesn't exist CASE "" END ' menu found CASE menuSeek REDIM itemName(1 TO numItems) AS STRING REDIM itemFunc(1 TO numItems) AS STRING FOR i% = 1 TO numItems READ itemName(i%), itemFunc(i%) NEXT i% EXIT DO ' menu doesn't match, skip CASE ELSE FOR i% = 1 TO numItems READ itemSkip, itemSkip NEXT i% END SELECT LOOP cursorNew = 1 menuSeek = "" END IF ' display CLS : cursorPos = cursorNew + 1 FOR i% = 1 TO numItems LOCATE , 3 IF (LEFT$(itemFunc(i%), 1) = "&") THEN getField RIGHT$(itemFunc(i%), LEN(itemFunc(i%)) - 1), fieldCopy, fieldHandle PRINT itemName(i%) + ": " + fieldCopy ELSE PRINT itemName(i%) END IF NEXT i% ' move cursor DO IF (cursorPos <> cursorNew) THEN LOCATE cursorPos, 1: PRINT " " LOCATE cursorNew, 1: PRINT CHR$(16) cursorPos = cursorNew END IF itemPrefix = LEFT$(itemFunc(cursorPos), 1) itemSuffix = RIGHT$(itemFunc(cursorPos), LEN(itemFunc(cursorPos)) - 1) DO: r = INKEY$: LOOP UNTIL LEN(r): r = RIGHT$(r, 1) SELECT CASE r CASE "H", "P" ' move up and down IF (r = "H") THEN ofs = -1 ELSE ofs = 1 cursorNew = cursorPos + ofs IF (cursorNew < 1) THEN cursorNew = 1 IF (cursorNew > numItems) THEN cursorNew = numItems CASE "K", "M" ' move left and right IF (itemPrefix = "&") THEN IF (r = "K") THEN ofs = -1 ELSE ofs = 1 getField itemSuffix, fieldCopy, fieldHandle IF (fieldHandle = handleINTEGER) THEN fieldCopy = LTRIM$(STR$(VAL(fieldCopy) + ofs)) setField itemSuffix, fieldCopy END IF EXIT DO END IF CASE " " ' activate IF (itemPrefix = "&") THEN getField itemSuffix, fieldCopy, fieldHandle IF (fieldHandle = handleTOGGLE) THEN IF (fieldCopy = "On") THEN fieldCopy = "Off" ELSE fieldCopy = "On" setField itemSuffix, fieldCopy EXIT DO END IF ELSEIF (itemPrefix = ">") THEN menuSeek = itemSuffix EXIT DO ELSEIF (itemPrefix = "_") THEN IF (itemFunc(cursorPos) = "_QUIT") THEN END ELSEIF (LEFT$(itemFunc(cursorPos), 5) = "_PLAY") THEN ' skill = val(right$(itemFunc(cursorPos), 1)) ' level = 0 ' CALL playLevel(level, skill) EXIT DO ELSEIF (LEFT$(itemFunc(cursorPos), 5) = "_SAVE") THEN ' slot = val(right$(itemFunc(cursorPos), 1)) ' CALL saveGame(slot) ELSEIF (LEFT$(itemFunc(cursorPos), 5) = "_LOAD") THEN ' slot = val(right$(itemFunc(cursorPos), 1)) ' CALL loadGame(slot, level, skill) ' CALL playLevel(level, skill) EXIT DO END IF END IF CASE ELSE IF (itemPrefix = "&") THEN getField itemSuffix, fieldCopy, fieldHandle IF (fieldHandle = handleSTRING) THEN IF (r = CHR$(8)) THEN IF (LEN(fieldCopy) > 0) THEN fieldCopy = LEFT$(fieldCopy, LEN(fieldCopy) - 1) ELSEIF ((asc(r) >= 65) AND (asc(r) <= 122)) then fieldCopy = fieldCopy + r END IF setField itemSuffix, fieldCopy EXIT DO END IF END IF END SELECT LOOP LOOP END dataMenu: DATA "main", 5 DATA "new game", ">new" DATA "save game", ">save" DATA "load game", ">load" DATA "settings", ">config" DATA "exit", "_QUIT" DATA "new", 4 DATA "easy", "_PLAY0" DATA "normal", "_PLAY1" DATA "hard", "_PLAY2" DATA "go back", ">main" DATA "save", 3 DATA "slot 1", "_SAVE0" DATA "slot 2", "_SAVE1" DATA "go back", ">main" DATA "load", 3 DATA "slot 1", "_LOAD0" DATA "slot 2", "_LOAD1" DATA "go back", ">main" DATA "config", 5 DATA "continues", "&continues" DATA "sound", "&sound" DATA "music", "&music" DATA "player", "&login" DATA "go back", ">main" ' get member offset, length and handle type SUB fieldSelect (member AS STRING, fldOffset AS INTEGER, fldLength AS INTEGER, fldHandle AS INTEGER) SELECT CASE LTRIM$(LCASE$(member)) CASE "continues" fldOffset = 0: fldLength = LEN(cfg.continues): fldHandle = handleINTEGER CASE "login" fldOffset = 2: fldLength = LEN(cfg.login): fldHandle = handleSTRING CASE "sound" fldOffset = 10: fldLength = LEN(cfg.sndfx): fldHandle = handleTOGGLE CASE "music" fldOffset = 12: fldLength = LEN(cfg.music): fldHandle = handleINTEGER END SELECT END SUB ' return readable field and handle type SUB getField (member AS STRING, fldString AS STRING, fldHandle AS INTEGER) DIM fldOffset AS INTEGER, fldLength AS INTEGER ' get member fieldSelect member, fldOffset, fldLength, fldHandle ' copy fldString = SPACE$(fldLength) DEF SEG = VARSEG(cfg) FOR i% = 0 TO fldLength - 1 MID$(fldString, i% + 1, 1) = CHR$(PEEK(VARPTR(cfg) + i% + fldOffset)) NEXT i% DEF SEG ' make it readable SELECT CASE fldHandle CASE handleINTEGER fldString = LTRIM$(STR$(CVI(fldString))) CASE handleSTRING fldString = RTRIM$(fldString) CASE handleTOGGLE if (CVI(fldString) = 0) then fldString = "Off" else fldString = "On" END SELECT END SUB ' store value back where it belongs SUB setField (member AS STRING, fldString AS STRING) DIM fldOffset AS INTEGER, fldLength AS INTEGER, fldHandle AS INTEGER, fldStuff AS STRING ' get member fieldSelect member, fldOffset, fldLength, fldHandle ' convert to byte SELECT CASE fldHandle CASE handleINTEGER fldStuff = MKI$(VAL(fldString)) CASE handleSTRING fldStuff = LEFT$(fldString, fldLength) IF (LEN(fldStuff) < fldLength) THEN fldStuff = fldStuff + SPACE$(fldLength - LEN(fldStuff)) CASE handleTOGGLE if fldString = "On" then fldStuff = mki$(1) else fldStuff = mki$(0) END SELECT ' stuff everything back where it belongs DEF SEG = VARSEG(cfg) FOR i% = 0 TO fldLength - 1 POKE VARPTR(cfg) + i% + fldOffset, ASC(MID$(fldStuff, i% + 1, 1)) NEXT i% DEF SEG END SUB