diff --git a/mines.com b/mines.com deleted file mode 100755 index 4f94445..0000000 Binary files a/mines.com and /dev/null differ diff --git a/readme.txt b/readme.txt new file mode 100755 index 0000000..0d9ffa8 --- /dev/null +++ b/readme.txt @@ -0,0 +1,73 @@ + S W I N E M E E P E R + ======================= +Created for the DOS COM Game Jam 2023 +https://itch.io/jam/dos-com-game-jam + +Technical Details +----------------- +This source repository contains a full development toolchain for creating +DOS COM programs in Forth and assembly. This toolchain was written in a +custom Forth dialect originally built for Neut Tower[1]; through a fairly +involved bootstrapping process it is now completely capable of rebuilding +itself. Every byte of every .COM file in this repository has been generated +from the included 8086 assembler, including the .COM file of the assembler. + +We start with MINIJORT.EXE, compiled with Borland Turbo C++ from MINIJORT.C +and MAIN.C. This is a stripped-down version of the Jorth engine that Neut +Tower[1] was built with, and the only part of this project that existed in +any form before August 14, 2023. (I started early on the jam because I +basically knew what I wanted to implement, and I knew that getting _anything_ +playable by the end of September with the absurd plan I had in mind was +going to be a long shot.) MINIJORT.EXE is a simple Forth interpreter that +loads BOOT.JOR and then reads the rest of its input from stdin. + +We then use MiniJort to generate TINYJORT.COM. This is done by piping the +contents of TINYBOOT.JRT to MiniJort. TINYBOOT loads some common definitions +from DEFS.JRT and the assembler from TARGET.JRT and ASM.JRT, then executes +TINYJORT.JRT, which assembles a second Forth interpreter that understands +a substantially similar vocabulary as MiniJort, with some improvements. +TinyJort internally embeds the definitions from BOOT.JOR and is entirely +self-contained. + +We could load TINYBOOT into TINYJORT.COM to rebuild itself, but one of the +big advantages of TinyJort over MiniJort is that TinyJort is trivially +capable of adding more definitions to itself and then writing out a new +.COM file with those definitions already loaded. So the next step is to use +TinyJort to build ASSEMBLE.COM, which is just TinyJort with the basic defs +and assembler pre-loaded, ready to get to work as soon as you launch it, +saving precious seconds of build time. TINYJORT.JRT can be loaded directly +into ASSEMBLE.COM in order to produce a byte-exact copy of TINYJORT.COM. + +REBUILD.BAT automates the process of bootstrapping TinyJort, and includes +a check to ensure that both Jorts produce the same .COM file. REASM.BAT +regenerates TINYJORT.COM and ASSEMBLE.COM using TINYJORT.COM and +ASSEMBLE.COM and is much faster. + +But that's not enough Forth interpreters yet! This tooling would allow us +to write assembly code _using_ Forth, and it would allow us to _extend_ +TinyForth to produce another Forth interpreter, but it does not yet allow +us to generate .COM files, written in Forth, that do not include extraneous +data like the Forth dictionary and the assembler. Since the .COM format is +limited to 64kb, space is at a premium. The final custom Forth interpreter +is ZIPOFF.COM and ZIPSTUB.SEG. + +Why ZipOff? Imagine a pair of Jorts - these are the Forth interpreter, +assembler, and extended runtime. Now imagine extending these Jorts into +full-on Jeans, by bringing in the definitions of the code that needs to +actually be included in the final product. When the two pieces are together, +the host Jorts can take advantage of the immediate interactive development +workflow of Forth, calling out to words defined in the final .COM, and +providing useful debugging tools not needed for the final product. But once +the development cycle is complete, the legs of the Jeans can be jettisoned - +zipped off, if you will - and... worn on their own, I guess? The metaphor +breaks down a little bit here. The point is that the target .COM file is +minimal and completely self-sufficient. + +Yo dawg, I heard you liked Forth, so I wrote a Forth interpreter in Forth +that I used to implement another Forth. + +THIS, finally, is the tool we use to build games and demos with. Importing +SWINE.JRT into ZipOff produces SWINE.COM; importing DIRTRECT.JRT produces +DIRTRECT.COM, and so forth. + +[1] https://spindleyq.itch.io/neut-tower/ diff --git a/swine.com b/swine.com new file mode 100755 index 0000000..ca90f54 Binary files /dev/null and b/swine.com differ diff --git a/mines.jrt b/swine.jrt similarity index 74% rename from mines.jrt rename to swine.jrt index 757253e..a526537 100755 --- a/mines.jrt +++ b/swine.jrt @@ -87,9 +87,9 @@ var theme countcolors + b@ dup 0 colvar = if drop col-grid else fg! then ; { :timm deftheme CREATE >t >t >t >t >t >t DOES} theme ! ; -( cursor grid block mine flag bg ) - blue white black black red lgray deftheme win31 - white yellow black black yellow red deftheme hotdog +( cursor grid block mine flag bg ) + blue white black magenta red lgray deftheme win31 + white yellow black lmagenta yellow red deftheme hotdog win31 @@ -97,7 +97,7 @@ win31 NEIGHBOUR-MASK & dup col-count dup if [ key 0 lit ] + else drop [ key lit ] then draw-char ; : draw-flag ( -- ) col-flag 0x0d draw-char ; -: draw-mine ( -- ) col-mine 0x0f draw-char ; +: draw-mine ( -- ) col-mine 0xec draw-char ; : draw-block ( -- ) col-block 0xb1 draw-char ; : draw-revealed ( b -- ) dup FMINE & if draw-mine drop else draw-neighbour-count then ; @@ -207,4 +207,60 @@ IN-PROGRESS bvar, game-state ' start ' main redefine -{ s" mines.com" writecom } +( title menu ) +array title-text t", SWINE MEEPER" + +: emptych? ( ch -- f ) dup 32 = swap 0 = or ; +: drawdot? ( st -- f ) dup b@ emptych? swap 1+ b@ emptych? or not ; + +: dot 7 draw-char ; +: sp 32 draw-char ; +: spacer ( st -- ) sp drawdot? if dot else sp then sp ; + +: draw-spaced-text ( st -- ) + begin dup b@ dup while draw-char dup spacer 1+ repeat drop drop ; + +2 cells const menu-optsize +2 const menu-size +array menu-options menu-optsize menu-size * allot + +: menu-option ( iopt -- p ) menu-optsize * menu-options + ; +: defmenu ( cp name iopt -- ) menu-option dup >rot ! cell + ! ; + +' start s" Start Game" 0 defmenu +' terminate s" Quit" 1 defmenu + +0 var, menu-selected + +: menu-activate menu-selected @ menu-option cell + @ execute ; + +: draw-selection ( iopt -- ) + menu-selected @ = if draw-mine else sp then sp ; +: draw-option ( iopt -- ) white fg! menu-option @ draw-text ; +: draw-menu + 33 10 textxy! + textx 0 begin dup menu-size < while + dup draw-selection dup draw-option 1+ nextline over textx! repeat + drop drop ; + +: draw-title + blue bg! yellow fg! 32 fill-page + 17 3 textxy! title-text draw-spaced-text + draw-menu ; + +: menu-selected! ( i -- ) + dup 0 >= over menu-size < and if menu-selected ! else drop then ; +: menu-selected+! ( di -- ) menu-selected @ + menu-selected! ; + +: await-menu + wait-key key>scan + dup %esc = if terminate then + dup %up = if -1 menu-selected+! then + dup %down = if 1 menu-selected+! then + %enter = if menu-activate then ; + +: title draw-title begin await-menu draw-menu again ; + +' title ' main redefine + +{ s" swine.com" writecom }