--- title: "Ymir Dungeon Designer" id: 51377 type: "computer_media" slug: "ymir-dungeon-designer" url: "http://localhost/computer_media/ymir-dungeon-designer/" markdown_url: "http://localhost/computer_media/ymir-dungeon-designer.md" published_at: "2023-07-29T15:42:50+00:00" modified_at: "2026-04-04T20:18:09+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2019/02/20230809-041332.jpg" excerpt: "Design and install custom nine-level dungeons into an existing game using this maze editor that patches mazes directly via machine code and SRAM." category: - name: "Archived Media" slug: "archived-media" taxonomy: "category" url: "http://localhost/category/archived-media/" post_tag: - name: "Downloadable" slug: "downloadable" taxonomy: "post_tag" url: "http://localhost/tag/downloadable/" - name: "SyncWare Co." slug: "syncware-co" taxonomy: "post_tag" url: "http://localhost/tag/syncware-co/" - name: "TS 1000" slug: "ts1000" taxonomy: "post_tag" url: "http://localhost/tag/ts1000/" model: - name: "Timex/Sinclair 1000" slug: "ts-1000" taxonomy: "model" url: "http://localhost/model/ts-1000/" indiv: - name: "Fred Nachbaur" slug: "fred-nachbaur" taxonomy: "indiv" url: "http://localhost/indiv/fred-nachbaur/" genre: - name: "Game" slug: "game" taxonomy: "genre" url: "http://localhost/type/game/" media_type: "Cassette" programmers: - name: "Fred Nachbaur" slug: "fred-nachbaur" taxonomy: "indiv" url: "http://localhost/indiv/fred-nachbaur/" download_url: "https://archive.org/download/timex-sinclair-software-archive/Ymir%20Dungeon%20Designer%20%28198x%29%28Nachbaur%2C%20Fred%29%28US%29%28TS1000%29%28Program%29.zip" mediadate: "198x" producer_company: - id: 20332 title: "Silicon Mountain Computers" type: "company" url: "http://localhost/company/silicon-mountain-computers/" related_products: - id: 27803 title: "Dungeon of Ymir" type: "product" url: "http://localhost/product/dungeon-of-ymir/" media_type_tags: "Game" --- # Ymir Dungeon Designer Ymir Dungeon Designer is a level editor for [Dungeon of Ymir](http://localhost/computer_media/dungeon-of-ymir/), allowing users to design, review, save, and export custom maze sets. The program stores up to nine dungeon levels in a three-dimensional string array `M$(9,20,30)`, with each cell holding either a space or CHR$(128) (the inverse space block graphic used as a wall tile). Cursor movement in the editor follows an 8-direction numpad-style scheme, with row and column wrapping handled explicitly. The export process is notably complex: it uses `RAND USR` calls at addresses 8200 and 837 to invoke machine code routines that transfer the designed mazes into the original game’s data via SRAM, requiring the user to load Part 2 of the Dungeon of Ymir tape in a specific sequence. Variables such as `WL`, `FRAME`, `PRINT`, `CLEAR2`, `CLEAR1`, and `KEY` store line numbers used as `GOSUB` targets, a common technique to make subroutine dispatch more readable. *** ## Program Analysis ### Program Structure The program is organized into clearly separated functional sections, with a main menu dispatching to numbered modules via `GOTO 1000*VAL Z$`. An introductory splash screen runs first at line 9000, then falls through to initialization at line 100. | Line Range | Function | | --- | --- | | 100–230 | Initialization: array, subroutine address variables, mode flags | | 500–550 | Main menu display and dispatch | | 1000–1090 | Option 1: View a maze level | | 2000–2320 | Option 2: Edit a maze level | | 3000–3080 | Option 3: Save dungeon to tape | | 4000–4190 | Option 4: Export/install dungeon into game | | 8000–8030 | Subroutine: level selector | | 8100–8170 | Subroutine: draw border frame | | 8200–8240 | Subroutine: print maze contents to screen | | 8300–8340 | Subroutine: clear status lines 22–23 | | 8400–8450 | Subroutine: “press any key” wait | | 9000–9090 | Introduction/splash screen | ### Data Storage All nine dungeon levels are held in a single three-dimensional string array declared at line 100: `DIM M$(9,20,30)`. Each element is a one-character string; walls are stored as `CHR$(128)` (the inverse-space block graphic) and empty cells as the default space. This maps neatly to a 20-row by 30-column playfield bordered by the frame subroutine. ### Subroutine Address Variables Lines 110–160 assign BASIC line numbers to named variables (`WL`, `FRAME`, `PRINT`, `CLEAR2`, `CLEAR1`, `KEY`), which are then used as `GOSUB` targets throughout the program. This is a deliberate idiom that improves readability and makes renumbering easier, at the cost of shadowing the BASIC keyword `PRINT` with a numeric variable of the same name — a legal but unusual choice that could surprise a reader. ### Menu Dispatch The menu at line 500 accepts a single keypress and dispatches with `GOTO 1000*VAL Z$`, routing to lines 1000, 2000, 3000, or 4000 for options 1–4, and to line 0 (non-existent) for option 0 — which causes a BASIC error and effectively performs a `NEW`-like reset since option 0 is described as “START ANEW (CLEARS DUNGEON).” This is a well-known technique for clearing program state without a dedicated handler. ### Editor Mechanics The maze editor at line 2000 uses an 8-direction movement scheme mapped to the keys 1–8. Row and column deltas are computed simultaneously using Boolean arithmetic in lines 2250–2260: - Keys `6`, `1`, `3` move south (row+1); keys `7`, `2`, `4` move north (row−1) - Keys `8`, `3`, `4` move east (col+1); keys `5`, `1`, `2` move west (col−1) Wrapping is handled explicitly at lines 2270–2300, with the boundary check `IF NOT R` serving as a test for zero (since `NOT 0` is true in BASIC). The cursor is shown by printing an inverse asterisk `[*]` then immediately reprinting the cell’s actual content at the same position, exploiting the print position to restore the display. The fill/erase toggle uses `M` as a Boolean (0 or 1). Pressing `CHR$(118)` (the `ENTER`/newline character as detected via `INKEY$`) toggles the mode. Wall data is written as `CHR$(128*M)` — either `CHR$(128)` for fill or `CHR$(0)` (space) for erase. ### Machine Code Integration and Export Process Option 4 provides a multi-step export procedure to patch the maze data into the original “Dungeon of Ymir” game. Two `RAND USR` calls are central to this process: - `RAND USR 837`: loads Part 2 of the game tape into memory (the maze data segment) - `RAND USR 8200`: installs the new maze data from the designer into the game’s memory area Line 4180 calls `RAND USR 16514` to trigger a system-level routine, followed by `NEW` at line 4190 to reset BASIC. The SRAM (8K static RAM expansion) is required as temporary storage during the transfer. The process also involves re-saving the patched Part 2 back to tape, as described in the step-by-step on-screen instructions. ### System Variable Manipulation `POKE 16418` appears repeatedly throughout the program. Address 16418 is the system variable `FLAGS`; poking it to 0 clears the print-suppression flag, ensuring output goes to the screen rather than the printer, while poking it to 2 at line 3010 redirects output. This is used carefully around `SAVE` to control what the system variable state is during tape operations. ### Level Display The print subroutine at line 8200 uses `PRINT AT N,1;M$(L,N)` to output each row of the current level’s maze slice as a string, exploiting the fact that slicing a 2D sub-array of a 3D string array returns a string of the full row width. Line 8230 displays the level number using `CHR$(L+156)`, which maps levels 1–9 to characters 157–165 — the UDG character range, though here it relies on the game’s own character definitions being present. ### Notable Anomalies - Line 2030 lists “4: NORTH-WEST” twice (for both keys 2 and 4), though the movement code at line 2260 makes key 4 move northeast (east + north). This is a display bug in the help text. - The introductory sequence calls `CLEAR` at line 9080 before jumping to line 100 where `DIM M$(9,20,30)` is declared — this intentionally wipes any previous array contents, fulfilling the “CLEAR” semantics without losing the program itself. - The “press any key” subroutine at lines 8420–8430 first waits for all keys to be released, then waits for a keypress — a standard debounce pattern to avoid immediately consuming a prior keypress. ## Source Code ``` 1 REM E(RND)~~ ;)=4▘/+#[B]C▝Y▛>7<"#[L]4 PAUSE 5[F]RND)▒4▘£ GOSUB [K]TAN ▘/+5=4) # GOSUB [K]TAN 10 GOTO 9000 100 DIM M$(9,20,30) 110 LET WL=8000 120 LET FRAME=8100 130 LET PRINT=8200 140 LET CLEAR2=8300 150 LET CLEAR1=8320 160 LET KEY=8400 200 LET MENU=500 210 LET M=0 220 LET R=NOT M 230 LET C=NOT M 500 CLS 510 PRINT "[M][E][N][U][:]",,"0: START ANEW (CLEARS DUNGEON)","1: VIEW A MAZE",,"2: EDIT A MAZE",,"3: SAVE DUNGEON TO TAPE","4: INSTALL DUNGEON" 520 LET Z$=INKEY$ 530 IF Z$="" THEN GOTO 520 540 IF Z$<"0" OR Z$>"4" THEN GOTO MENU 550 GOTO 1000*VAL Z$ 1000 CLS 1010 GOSUB WL 1020 GOSUB FRAME 1030 GOSUB CLEAR2 1035 GOSUB PRINT 1040 PRINT AT 23,5;"PRINT NEXT LEVEL? Y/N" 1050 IF INKEY$ ="N" THEN GOTO MENU 1060 IF INKEY$ <>"Y" THEN GOTO 1050 1070 LET L=L+1 1080 IF L=10 THEN LET L=1 1090 GOTO 1030 2000 CLS 2010 GOSUB FRAME 2020 PRINT AT 3,8;"[C][U][R][S][O][R]█[C][O][N][T][R][O][L][S][:]" 2030 PRINT AT 5,3;"1: SOUTH-WEST 5: WEST";AT 6,3;"2: NORTH-WEST 6: SOUTH";AT 7,3;"3: SOUTH-EAST 7: NORTH";AT 8,3;"4: NORTH-WEST 8: EAST" 2040 PRINT AT 10,2;"ENTER: CHANGE FILL/ERASE MODE";AT 12,3;"Q: RETURN TO MENU";AT 16,3; 2050 GOSUB WL 2060 GOSUB PRINT 2100 LET M=NOT M 2105 GOSUB CLEAR1 2110 PRINT AT 23,0;"MODE: ";("FILL" AND M);("ERASE" AND NOT M) 2200 PRINT AT R,C;"[*]";AT R,C;M$(L,R,C) 2210 LET Z$=INKEY$ 2220 IF Z$="Q" THEN GOTO MENU 2230 IF Z$=CHR$ 118 THEN GOTO 2100 2250 LET R=R+(Z$="6" OR Z$="1" OR Z$="3")-(Z$="7" OR Z$="2" OR Z$="4") 2260 LET C=C+(Z$="8" OR Z$="3" OR Z$="4")-(Z$="5" OR Z$="1" OR Z$="2") 2270 IF R>20 THEN LET R=1 2280 IF NOT R THEN LET R=20 2290 IF C>30 THEN LET C=1 2300 IF NOT C THEN LET C=30 2310 LET M$(L,R,C)=CHR$ (128*M) 2320 GOTO 2200 3000 CLS 3010 POKE 16418,2 3020 PRINT "SAVE TO TAPE: INPUT SAVE NAME.",,,,,"START TAPE BEFORE PRESSING ENTER" 3030 INPUT S$ 3040 CLS 3050 PRINT "DUNGEON OF YMIR ALTERNATE MAZE: ",,"NAME: ";S$ 3060 SAVE S$ 3070 GOSUB KEY 3080 GOTO MENU 4000 CLS 4010 PRINT "ARE YOU SURE THAT THE DUNGEON ISAS YOU WANT IT?" 4020 PAUSE 4E4 4030 IF INKEY$ <>"Y" THEN GOTO MENU 4040 CLS 4050 PRINT "TO EXPORT YOUR NEW MAZE SET TO DUNGEON OF YMIR, PROCEED THUSLY:" 4060 PRINT ,,"1: BE SURE THAT YOUR 8K SRAM IS [E][N][A][B][L][E][D]. MAZES WILL BE TEMPO- RARILY STORED THERE." 4070 PRINT ,,"2: THIS PROGRAM WILL NEW ITSELF. WHEN THE CURSOR RE-APPEARS, ENTER [F][A][S][T] MODE." 4080 PRINT ,,"3: POSITION YOUR ORIGINAL D OF Y TAPE TO THE START OF PART 2." 4090 PRINT ,,"4: ENTER [R][A][N][D]█[U][S][R]█[8][3][7] AND START THE TAPE IN PLAY MODE." 4100 PRINT ,,"5: WHEN LOADED WITH ERROR C/0, ENTER [R][A][N][D]█[U][S][R]█[8][2][0][0]. THIS IN- STALLS THE NEW MAZE." 4110 GOSUB KEY 4120 PRINT "6: PUT YOUR NEW TAPE INTO YOUR RECORDER, AND POSITION TO JUST AFTER THEN END OF PART 1." 4130 PRINT ,,"7: SAVE THE MODIFIED PART TO YOUR TAPE BY ENTERING [G][O][T][O]█[2]." 4140 PRINT ,,"8: AFTER SAVING, THE PROGRAM WILL RUN, BUT THE COVER SCREEN WILL BE MESSED UP. THE PROPER SCREEN WILL BE DISPLAYED ON RE-LOADING LATER." 4150 PRINT ,,,,"[R][E][A][D]█[I][N][S][T][R][U][C][T][I][O][N][S]█[A][G][A][I][N][?]█[Y][/][N]" 4160 IF INKEY$ ="Y" THEN GOTO 4000 4170 IF INKEY$ <>"N" THEN GOTO 4160 4180 RAND USR 16514 4190 NEW 8000 PRINT "WHICH LEVEL? 1-9" 8010 LET L=CODE INKEY$ -28 8020 IF L<1 OR L>9 THEN GOTO 8010 8030 RETURN 8100 CLS 8110 POKE 16418,0 8120 PRINT "[▒][▒][▒][▒][▒][▒][▒][▒][▒][▒][▒][▒][▒][▒][▒][▒][▒][▒][▒][▒][▒][▒][▒][▒][▒][▒][▒][▒][▒][▒][▒][▒]"; 8130 FOR N=0 TO 19 8140 PRINT "[▒]";TAB 31;"[▒]"; 8150 NEXT N 8160 PRINT "[▒][▒][▒][▒][▒][▒][▒][▒][▒][▒][▒][▒][▒][▒][▒][▒][▒][▒][▒][▒][▒][▒][▒][▒][▒][▒][▒][▒][▒][▒][▒][▒]"; 8170 RETURN 8200 FOR N=1 TO 20 8210 PRINT AT N,1;M$(L,N) 8220 NEXT N 8230 PRINT AT 22,4;"[T][H][I][S]█[I][S]█[D][U][N][G][E][O][N]█[L][E][V][E][L]█";CHR$ (L+156) 8240 RETURN 8300 POKE 16418,0 8310 PRINT AT 22,0;" " 8320 POKE 16418,0 8330 PRINT AT 23,0;" " 8340 RETURN 8400 POKE 16418,0 8410 PRINT AT 23,0;"[P][R][E][S][S]█[A][N][Y]█[K][E][Y]█[T][O]█[C][O][N][T][I][N][U][E][.][.][.][.][.][.][.]" 8420 IF INKEY$ <>"" THEN GOTO 8420 8430 IF INKEY$ ="" THEN GOTO 8430 8440 CLS 8450 RETURN 9000 CLS 9010 PRINT "[C][U][S][T][O][M]█[M][A][Z][E][S]█[F][O][R]█[D][U][N][G][E][O][N]█[O][F]█[Y][M][I][R]",,"THIS PROGRAM LETS YOU DESIGN ANDINSTALL YOUR OWN MAZES FOR VERSN3 OF ""DUNGEON OF YMIR""" 9020 PRINT ,,"START BY LOADING ""YMIR"" (PART","1), AND BREAK WHEN LOADED. SAVE TO A NEW BLANK TAPE WITH GOTO 2." 9030 PRINT ,,"THEN LOAD THIS PROGRAM TO DESIGNYOUR NEW MAZES. FROM THE MENU, YOU MAY EDIT, SAVE, REVIEW, OR ""EXPORT"" (INSTALL) NEW ""DUNGEON""" 9040 PRINT ,,"[R][U][N] OR [C][L][E][A][R] ZAPS YOUR WORK. TO RE-START AFTER BREAK, ENTER [G][O][T][O]█[M][E][N][U]." 9050 PRINT ,,"YOU MAY MAKE YOUR MAZE LEVELS ASSIMPLE OR AS COMPLEX AS YOU LIKE" 9060 SLOW 9070 GOSUB 8400 9080 CLEAR 9090 GOTO 100 ```