From cd0d0bff8b6e1b0934e8a4a928b0a896e87594bb Mon Sep 17 00:00:00 2001 From: Jeremy Penner Date: Sun, 2 Feb 2020 18:33:07 -0500 Subject: [PATCH] Initial commit (forked from pete286) --- .gitignore | 7 + adlib.c | 26 ++ adlib.h | 6 + boot.jor | 101 ++++ defs.jor | 167 +++++++ egamap.h | 15 + egavga.bgi | Bin 0 -> 5554 bytes entity.jor | 114 +++++ footer.jor | 116 +++++ footer.tif | Bin 0 -> 8076 bytes footer2.tif | Bin 0 -> 8076 bytes game.exe | Bin 0 -> 115800 bytes game.jor | 170 +++++++ game.prj | Bin 0 -> 5721 bytes gameboot.jor | 35 ++ input.jor | 33 ++ jazzbass.sbi | Bin 0 -> 52 bytes jeanne.jor | 59 +++ jeanne.map | Bin 0 -> 904 bytes jiles.jor | 114 +++++ job.jor | 86 ++++ jopl.c | 158 +++++++ jopl.exe | Bin 0 -> 68278 bytes jopl.jor | 371 +++++++++++++++ jopl.prj | Bin 0 -> 4609 bytes jorth.c | 1247 ++++++++++++++++++++++++++++++++++++++++++++++++++ jorth.h | 75 +++ kbd.c | 78 ++++ kbd.h | 108 +++++ lev00001.jor | 7 + lev00001.map | Bin 0 -> 264 bytes map.jor | 87 ++++ mouse.c | 55 +++ mouse.h | 13 + ntiles.gfx | Bin 0 -> 8192 bytes ntiles.tif | Bin 0 -> 4078 bytes pete.jor | 63 +++ pete.map | Bin 0 -> 524 bytes petehous.jor | 95 ++++ petehous.map | Bin 0 -> 368 bytes portrait.gfx | Bin 0 -> 8192 bytes portrait.tif | Bin 0 -> 7955 bytes repl.jor | 6 + road.jor | 32 ++ road.map | Bin 0 -> 2504 bytes serial.c | 109 +++++ serial.h | 29 ++ space | Bin 0 -> 2504 bytes space.jor | 26 ++ space.map | Bin 0 -> 2504 bytes sprite.gfx | Bin 0 -> 10240 bytes sprite.tif | Bin 0 -> 7918 bytes state.jor | 23 + template.map | Bin 0 -> 264 bytes testbed.c | 759 ++++++++++++++++++++++++++++++ tiff.c | 187 ++++++++ tiff.h | 17 + tiles.c | 329 +++++++++++++ tiles.gfx | Bin 0 -> 8192 bytes tiles.h | 48 ++ tiles.tif | Bin 0 -> 4078 bytes timer.c | 44 ++ timer.h | 12 + timer.jor | 37 ++ trail1.jor | 54 +++ trail1.map | Bin 0 -> 5629 bytes video.c | 39 ++ video.h | 39 ++ 68 files changed, 5196 insertions(+) create mode 100644 .gitignore create mode 100755 adlib.c create mode 100755 adlib.h create mode 100755 boot.jor create mode 100755 defs.jor create mode 100755 egamap.h create mode 100755 egavga.bgi create mode 100755 entity.jor create mode 100755 footer.jor create mode 100755 footer.tif create mode 100755 footer2.tif create mode 100755 game.exe create mode 100755 game.jor create mode 100755 game.prj create mode 100755 gameboot.jor create mode 100755 input.jor create mode 100755 jazzbass.sbi create mode 100755 jeanne.jor create mode 100755 jeanne.map create mode 100755 jiles.jor create mode 100755 job.jor create mode 100755 jopl.c create mode 100755 jopl.exe create mode 100755 jopl.jor create mode 100755 jopl.prj create mode 100755 jorth.c create mode 100755 jorth.h create mode 100755 kbd.c create mode 100755 kbd.h create mode 100755 lev00001.jor create mode 100755 lev00001.map create mode 100755 map.jor create mode 100755 mouse.c create mode 100755 mouse.h create mode 100755 ntiles.gfx create mode 100755 ntiles.tif create mode 100755 pete.jor create mode 100755 pete.map create mode 100755 petehous.jor create mode 100755 petehous.map create mode 100755 portrait.gfx create mode 100755 portrait.tif create mode 100755 repl.jor create mode 100755 road.jor create mode 100755 road.map create mode 100755 serial.c create mode 100755 serial.h create mode 100755 space create mode 100755 space.jor create mode 100755 space.map create mode 100755 sprite.gfx create mode 100755 sprite.tif create mode 100755 state.jor create mode 100755 template.map create mode 100755 testbed.c create mode 100755 tiff.c create mode 100755 tiff.h create mode 100755 tiles.c create mode 100755 tiles.gfx create mode 100755 tiles.h create mode 100755 tiles.tif create mode 100755 timer.c create mode 100755 timer.h create mode 100755 timer.jor create mode 100755 trail1.jor create mode 100755 trail1.map create mode 100755 video.c create mode 100755 video.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..978054b --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +*.obj +*.bak +*.dsk +*.swp +*.log +*.jim +game.map diff --git a/adlib.c b/adlib.c new file mode 100755 index 0000000..0c4fff7 --- /dev/null +++ b/adlib.c @@ -0,0 +1,26 @@ +#include "adlib.h" + +static void adlib_wait(int delay) { + int i; + for (i = 0; i < delay; i ++) adlib_read(); +} + +void adlib_write(int reg, int val) { + int i; + outp(0x388, reg); + adlib_wait(6); + outp(0x389, val); + adlib_wait(35); +} + +void adlib_reset() { + int i; + for (i = 0; i < 0xff; i ++) { + adlib_write(i, 0); + } +} + +void adlib_init() { + adlib_reset(); + atexit(adlib_reset); +} diff --git a/adlib.h b/adlib.h new file mode 100755 index 0000000..009857f --- /dev/null +++ b/adlib.h @@ -0,0 +1,6 @@ +#include + +void adlib_init(); +#define adlib_read() inp(0x388) +void adlib_write(int reg, int val); +void adlib_reset(); \ No newline at end of file diff --git a/boot.jor b/boot.jor new file mode 100755 index 0000000..003c392 --- /dev/null +++ b/boot.jor @@ -0,0 +1,101 @@ +2 const cell +: cells cell * ; + +key ) const ')' + +10 const '\n' +13 const '\r' +key const sp + +128 const F_IMMEDIATE +0x100 const F_USERWORD + +: cr '\n' emit ; +: bl sp emit ; + +: if ' BZ_ , here 0 , ; immediate +: else ' GOTO_ , 0 , here swap ! here cell - ; immediate +: then here swap ! ; immediate + +: begin here ; immediate +: while ' BZ_ , here 0 , ; immediate +: repeat ' GOTO_ , swap , here swap ! ; immediate +: again ' GOTO_ , , ; immediate +: until ' BZ_ , , ; immediate + +: ( begin key ')' = until ; immediate +: lit ' LIT_ , , ; + +: inline| ' INLINEDATA_ , here 0 , ; +: |inline [ ' then , ] ; + +' cells @ const $DOCOLON ( get the colon execution token ) +: :| inline| $DOCOLON , ; immediate +: |; ' ret , |inline ; immediate + +key " const '"' + +: s" state if inline| else here then + begin key dup '"' != over 0 != and while b, repeat drop 0 b, + state if |inline else dup here! then ; immediate + +: interpretword F_IMMEDIATE & state not or if execute else , then ; +: interpretnumber state if lit then ; +: interpretunknown type s" ?" type cr ; +: compileword lookup dup + if interpretword + else drop number + if interpretnumber + else interpretunknown + then + then ; +: interpreter + begin word dup b@ while compileword repeat drop ; +: load-input swap-input >r >r interpreter r execute r >r interpretjor + rot r 2dup r@ >rot r >r 2dup r@ >rot rswap r@ >rot r r >rot rot ; + +: negate 0 swap - ; +: abs dup 0 < if negate then ; + +: ~ -1 ^ ; +: f! ( b v flag -- ) + >rot >r r@ @ >rot ( val flag b r: v ) + if | else ~ & then rot ! ; + +: userword 1 latest wordflags F_USERWORD f! ; + +: expile state if , else execute then ; + +: :noname here $DOCOLON , ] ; + +: withfp ( xt fp -- ) :| factivate execute fdeactivate drop |; preservefp ; + +: array word new-word $DOVAR , ; +: create word new-word $DOCREATE , 0 , ; + +: finishcreate ( ipfirst -- ) + ( set cell after codepointer to first instruction of does> ) + latest codepointer cell + ! ; + +: does> here 4 cells + lit ' finishcreate , ' ret , ] ; immediate + +: +towards ( from to -- from+-1 ) + over > if 1 + else 1 - then ; + +: for ( from to -- ) + ' >r , [ ' begin , ] ( from r: to ) + ' dup , ' r@ , ' != , [ ' while , ] + ' >r , ; immediate ( r: to from ) +: i ' r@ , ; immediate +: next + ' r , 1 lit ' >r , ; immediate + +: yield rswap ; +: done rdrop 0 >r rswap ; +: ;done ' done , ] ; immediate +: each [ ' begin , ] ' r@ , [ ' while , ] ; immediate +: more ' yield , [ ' repeat , ] ' rdrop , ; immediate +: break rswap rdrop :| yield done |; execute rswap ; + +: links begin yield @ dup not until drop ;done + +: files findfile begin dup while yield nextfile repeat drop ;done +: .files files each type s" " type more ; + +: min ( x y -- x|y ) 2dup > if swap then drop ; +: max ( x y -- x|y ) 2dup < if swap then drop ; + +: +!pos ( n var -- ) dup @ r dup r@ @ <= if + drop 0 r@ ! + else r@ @ 0 < if + r@ ! + else drop then then rdrop ; + +: +!cycle ( n var lim -- ) + >r >r r@ +! if drop 0 else dup 0 < +: checkpoint ( cp -- ) + create here 4 cells + , latest , tasks , , + does> dup @ here! + dup cell + @ latest! + dup 2 cells + @ tasks! + 3 cells + @ execute ; + +: intern create latest wordname , does> @ ; + +: preserving ( cp 0 vars... -- ) + 0 >r begin dup while dup @ >r >r repeat drop + execute + begin r@ while if wordname type drop 0 break then + more dup if . else drop then ; userword + +: tasks.s + tasks links each + dup .wordin s" : " type + dup task-sp @ over task-stack ( task stackLim stack ) + begin 2dup > while dup @ . cell + repeat + cr drop drop more ; userword + +: doactivate ( task ip -- ) + over task-ip ! + dup task-stack over task-sp ! + dup task-rstack over task-rsp ! + drop +; + +: activate + here 4 cells + lit + ' doactivate , + ' ret , +; immediate + +: >task ( val task -- ) + task-sp >r r@ @ ! r@ @ cell + r> ! ; + +: try-send ( val task -- b ) + mailbox dup @ if drop drop 0 else ! 1 then ; + +: wait-send ( val task -- ) + mailbox + begin dup @ while suspend repeat ( wait for empty mailbox ) + ! ; + +: send ( val task -- ) try-send drop ; + +: receive ( -- val ) + running mailbox + begin dup @ not while suspend repeat ( wait for mail ) + dup @ 0 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 kPT-l++>43}H-W+FDTLtile 4 >> swap 4 >> swap ; userword +: tile>world 4 << swap 4 << swap ; userword + +: +pos ( x1 y1 x2 y2 -- x y ) + rot + swap ; userword + +: -pos ( x1 y1 x2 y2 -- x y ) + negate swap negate swap +pos ; userword + +: defentity ( x y dir anim -- ) array ' drop , , , tile>world , , ; +: entity.x 4 cells + ; +: entity.y 3 cells + ; +: entity.dir 2 cells + ; +: entity>sprite cell + @ execute ; +: entity>do ( entity event ) swap @ execute ; +: entity>pos dup entity.x @ swap entity.y @ ; userword +: entity.pos! ( x y entity ) pos ( dir -- dx dy ) + dup W = if drop -1 0 ret then + dup E = if drop 1 0 ret then + dup N = if drop 0 -1 ret then + S = if 0 1 else 0 0 then ; + +: pos>dir ( dx dy -- dir ) + dup 0 < if drop drop N else + 0 > if drop S else + dup 0 < if drop W else + 0 > if E else NODIR then then then then ; + +: facing ( x1 y1 x2 y2 -- dir ) -pos pos>dir ; + +: entity-dst ( e -- x y ) + >r r@ entity.dir @ dir>pos + r@ entity.x @ tile +pos ; + +: move-entity ( e -- ) + dup entity.dir @ dir>pos ( e dx dy ) + dup if swap drop swap entity.y + else drop swap entity.x then + swap 16 * over @ + 4 b@ sprindex ; +: defsingle ( sprindex -- ) create b, does> swap drop b@ ; +: lookup-frame ( anim -- val ) + dup dup 1 + b@ swap b@ ( a count tpf ) + ticks swap / swap % ( a index ) + 2 + + b@ ; + +: defanim ( frame... framecount ticks-per-frame -- ) + create b, dup b, 0 for b, next + does> ( dir a -- ) lookup-frame sprindex ; +: defmulti ( sprindex... framecount ticks-per-frame -- ) + create b, dup b, 0 for b, next + does> ( dir a -- ) swap drop lookup-frame ; + +0 defstatic {car} +5 defstatic {car-lit} +1 defstatic {pete-stand} +1 2 2 5 defanim {pete-walk} +13 defsingle {pete-table} +14 defsingle {chair} +15 defsingle {pete-bed} +16 defsingle {horse} +3 defstatic {mary} +3 4 2 5 defanim {mary-walk} +6 defstatic {jeanne} +6 7 2 5 defanim {jeanne-walk} +18 defsingle {phone} +38 defsingle {fridge} +43 defsingle {boat} +8 defstatic {boat-pete} +9 defstatic {duck} +46 defsingle {aliem} +13 14 2 5 defmulti {neut} + +: sprite-bob ( x y sprindex -- x y sprindex ) + dup 13 >= over 14 <= and if + >rot 2dup + ticks + 40 % 20 < if 1 + then rot drop drop else drop break then more ; + +: canchooseleft ichoose @ 0 > ; +: canchooseright ichoose @ cchoose @ 1 - < ; + +: displaychoice + clear + canchooseleft if s" <" 6 20 textxy then + canchooseright if s" >" 38 20 textxy then + getchoice drop slowtext ; + +: navchoice ( -- done ) + 0 begin suspend + ^LEFT key-pressed canchooseleft and if drop 1 -1 ichoose +! then + ^RIGHT key-pressed canchooseright and if drop 1 1 ichoose +! then + ^ENTER key-pressed if drop 2 then + dup until 1 - ; + +: choose ( gen -- ) + ' choosegen redefine countchoosegen 0 ichoose ! + textleftchoice clear show-footer + begin displaychoice navchoice until + getchoice swap drop execute ; + +: character ( iportrait color ) create , , + does> dup @ text-color ! cell + @ draw-portrait ; + +0 GREEN character pete userword +1 MAGENTA character mary userword +2 BROWN character chuck userword +3 YELLOW character jeanne userword +4 LGRAY character phone userword + +: noone WHITE text-color ! s" " dup dup dup + 8 portraity 16 portraity 24 portraity 32 portraity ; userword diff --git a/footer.tif b/footer.tif new file mode 100755 index 0000000000000000000000000000000000000000..c4d3ba64cad50582a496eda9abd4bc5be24a7112 GIT binary patch literal 8076 zcmeI0F$%&!5Je|OL_rW6Z9IXMM@V54u*?}ef=QV|NRHw$EG(@(LQY}f47*Cgf`uQ6 z;Gbo)e|Kg!o5zr1({wFk5t)cYu|%p8eMDYwbUyHUs5r>UM zR(zt`_B&{Q*-2c>#I?J)W&!3g%XBoad7h(r+ugja-l%i0pViECT#D2*h(Jywfqn@T zK>=5JxE2I`f1z?*3j0-cOwZSu_cY=8F!1C@ei#8PoApP27y&Gs^+$df0W6#KM}8Oq zESvR5ei#8PoApP27y&Gs^+$df0W6#K_aFR%o7&&H-|hGIn{Oup68MppSvG33u7bN&x}zi{K9LjEdQe+HTF`vKojepdG9QrVxsmHpuY z&ahmf%h~kH+2s2kli%aldOt<`rBcfmUi5#qwDT8^-n?|a7jD4j`3%_o3s<$} znx=U+1NNovv3^0*HqT%{3)Z38Z^FWzzFO3DaBe51!WnjJ&*F2^)dF-EV=PHMB$=o(f#3`!SscqK>g7R=d?n_A7z ztGcVT#z(I>$VdU{fR@ZfX`8EMVK;;^!bD-zt_1~^Y>k;f60}4D*VJq^Sp~CrKc2H6 zKh9l8HwqgDB~m!%!Tmzp0*}QbO8f@CxvZgPDltYuvS?8PGx#RL2h6mrcf{UeT2|O8 z;i@6mHf+0LxY&SC3wV!-tTfBF=-Y%92cSJ)oPXUhBYe={_yjGhBHtu?_gc(a@QGt( zSub_RNU1l@ptX!8RYN=}?+EG6KROs?E)xgv(X1t3aBR;Dt{cv)s;g(vRExH}YOk`s z_}Li|e0FZVRnzT>L8Xks2Ypw?E*CLP3$LAgiZ+C8O|F*d+>B&JC~ko-ig&{ z#{h?EXjUrcQx@_L-xM*ugS{ol5jhX=N!V^cY0sM!Dv_Ouv~2}X9Ns2t)-cO!@S!yd z_F&(3d>1W#i^+OB-J(Sd8SaUlu1tP7xE2HIc32PXpvybOo?`LKS9 zFKz7j%E*D5aKY68K}%-#BcBGJcojCLvAtrp4vc4V&;CdW@d*wT ze{am=QW=+O@n_@sPK~mBvbPdGVKCmm7Djrq|4P1Iv`9W`#i-Rw;=bs>2ottpgkE4T z@scv;1d?p6BuT(d!yIg6S79j^Nl)U4b8--R)w%-|FE%97Othr*t__WBw*)JSc1hdt z8WFoLps(aB^MjI)@e5G7e@i}IY=icRw5Yqg75C-M?bQ-bO3v_8;LE6DIur93hh@(f z@FC6(b}NNY!o_wwt7Z-i#Kl%@qrsw-Gr;root$pS>YuSo3Xsk=E^K=02^LcYR{0wpp9kLZ4)&;zW7d+K$*osf3 r;L!KhhrZy$^B*kmf3v_ZN?l){F4gt&Z29B22bJ%Bd#L<+$h-dmBT@7X literal 0 HcmV?d00001 diff --git a/game.exe b/game.exe new file mode 100755 index 0000000000000000000000000000000000000000..6c96d80a45a582767a1c5eec9af91f93f5b0ab78 GIT binary patch literal 115800 zcmeFaeOy#k9zTBPfthhY#3y{H5HnqqG?SzUd?3?{meHu&;P`;lvbNi{X*dIDI1Ejj z&Rli3EYscE#puDzEo`Z-_=KQfrY2fGwJD<6880FN0m3l%`#$I18Nk}zet&#lukRnf zZH0T^=X0Ju=W{;ib3W&DE|1Mi*KFX7Tr9_Nvb?U33%}|ACgGokYajbeCVTx4KQzG4 z;a?OU9@cVP%m|LVe zV_3&|V!WJZ%zGS}sM$YhH78UGr+3JC{)Ue(KKby7`@>cfs4N?=9$)=-otTw`*7q6H)dVTc;?wqXL@<3%K6S?7Q4y`*|vOsfW=#X+0G5kPuCWq%3QIE$g zA(m%6~FeB7bor1qO9^AFItD%;Pr(caSO}w zSn@DeG@;JR>+g_DlDImgY&V@C$_pddyp;<#Y~$=Bjf)f?&{`N)zL@5IU27r#oMU6Ppx&zL zI}N+iH;d_E(Oe>)vid2{g}c&4l5QchIUAW1u29G9N=FWl(G5E7{{?7Iu=qV{@p3{@ zI@v9&jiuEm2MUYQMX;YtR$)2elXSA_CYnzanp;9NCF#U*6HSRi(-H_4FQ&`cTGBt1 zM@%OVsV_5U3QFxBKEP_<7qF>_jt|f$PjW!`p7G=-w6BL~|P=taD<`Dk`|NxzxVT>T{GE#VWym}nR0(&riZ&` za{j_hkzF&b{Dqm$_`5J7?-yozr)#FnUzll0*GyTzFw=uwGcEgtnZmke%Kn9!jJ>2cY&tI7Fjn0e?!~d6zX-Y;+`C(y9B4UxOKFl)XP^^b6cCJEK`VU`vK4(-btA|K zkDfKN^oA|1YhJH$W7o_q@1lU$SPYYjX-7uft<055ncn2UYNgC)gJm+Zb z(XaMSV-&Smi9S^m8DF+^p_H=&q@vrqpM0jiyKD8Vl;i-G6y?e9;gynkKV3~|-}!(C zwJGb0yVmd@b0oKU_%66lWx`ZpOr%zp4Z>461nG@>W6F7UUd@s4&Vk3JyXmglO zF$(%5k6zMO>N!p_#+O>iKU&nGv8D#|#>+JKAml!^z$Uc1W!VvdmltN*XtsDcl|0j8 zTcpUPlFP&itu%K8t$89;mpq<4i<+O(E0sLh0=X8^1Ow;jO$(184+T)F)tP>S&C zH(JO?O*V2%fDdoBhq)$j4v7ud+@>xH3TzNt(kCoY>M5M#c})2ssC$!~2u16-s?HxOUK_g7v^UydL?fc14t0~89S z3F^tspQS^?Z!X49eG8PH%;bY&#?6I4S=;i0+tMurXSW(;`$x-Gmpl%3L{#4e^nav)6K%_d;=CI^zb zStQETfJu@KmNNzmC-ZCaI9*v-STMIzD4pa2_JE8mFOW*oGHk(J+AY^@QmU1_aNR~; zmr4H?wW#5F9NpH$rxN>ho0Tj;a=J`@#WXZqjCxT*4|I-QCbL_mJJ{4dS|6Oh`|EAO zz3Ak-sU-fojjmOO>z%5?N?Ri(Scx9x#s}3tEip0K@94*v^dd@7tGFDH1~BY7wbTll zf=SJBL9U5-)oPSYK2`sCQ@8w9h(8!tpC92;sYTRQOV`Kqw5hiUT_5NB?9h*BIgW()i<+*;dkH1~k1#T?)z0x}e7RP!@0L%yy2q z*$S2AlDtu;C_h%!^}4QAL7TEBLwl&i(xk)}{hN%a-hw!cgdF15T$Lxoal79&_f z30U9QYuR+0g)C7?-L)~+wR}xz+V@MR-TIkn8l2v!SUi~%qR&=T2r@7cfN(bDNIhr^ zyU3}P<{){qm6FY36W;pOsk-C)tKF9|@|s1lGIFk}3udjpyTwLrMInqD$NHdM3~Mt? zVVK{eSkFvdF^F27{?KwwMLrU1Q@&cdVk%k4^XfZOrEvC)RNu+KX0q*u*wo)bQm$gw z-XLRdFkUiMY#|Q>>FR$ZFWnGti?)yvpbNhNMv>-P8_|Twq1`N`$5k6s=D)hiRs*WP zL+V`JpMjHXVJS|R!k7|gV*2}9g&nj{Ocnh+*_05OT87ftVkiR(SyPKjyW+Gk$dU3( z)!A*N-xJXNBK2rCNx@3hY1@-c+f?-HNxu|H+MCGh$}BphQZn^S?TpVb$X}${Y%q<@ zu3ewyjB#kCo;-t3rr8oJ@~((OFfS^?C}9BzX(J#spXDgZ&0Rae8sAKgG>|RwT7G{> z;xZT7Y~iJjyE~=UPtp|Z7J>h_U_G12x8+9Ug(X^BJDnxU3N%~_D%aq01^K51Q3vTD zr4WO_w-(j}7hZQQGa%^*&{?&XZ?=$Ur(!+{d~>3qCf#nP;~Xj3d_{1^s&+6V3|Pp+ zl(0MMw~*04Mcc5J{uFJ6TUV(nkO+&(ej9BCo%mUbmHGxvq}BiVicK0v>p=>oVP;Il z!$_rO47yXqtO=}yd|RRF+?;>KrcPa&vO(8Db;88)Q%1K#-}%Xv z8(9DG_)>uU<%S~aG!>9I2?hC)dx}y}HXgtJk#$X3+YQ}TdP8toqMgczfJAG=Xblw* zD>;H4kzsR5x<~IxC`q@H^+Z*&%)XC;0;OiB9wX_Qs@=Q?KlRG`uQVt`CFrRQI#mmw zzc5u_xF=mr7ZTtC|5!#1g<`tY{{g((4P?JezHg#Uh3No&F-e3ee91#ex5`RJF$rVZ z_=BQU*vsYMiwP-b)ECN-C;c|@qdpdL`Ujgh1B|)&gN@`ikzp-j0njp_j{-dcba9h- zD%?Uo2J{%95I6wq`)7aGMKy)0xDpd3Ks0Ud1=|E9yt z29yuzc0fBD#VvsJfL;dF3(%HEaWA0jmu=!2K>o|HNE^k&fX)G056B1T#YXWWpf3Ua z4bVwIOB%&`Kq8>cfXV?aXcUcl3wamN7C=RSW;BZC0T%KqppO8(1t_7BeD|YhL7#Gg z76DxaG`3NErniOs9?&O%?0|YUiY`D_Ksy0F38<|>d>zokfDQmk0rW$IxEIh^KvjSe z0e#&dn)+JEZGcV#8VP7$gLo7*ngN{!)F04C4djU*MLkx`rtfXyzk$l%+sMWS@h(6Y z0M!7h1@xx|@fq;;D4@%L&H&165br=wcLEv&r~=TU2GIg&3!qv+{{l3#LCgj8I-oj0 z1%MuC5Vrt&5l}s#wSY!6h~EHO0;mDd3P63)T9bt=0MrENX+T_qC;^%Qs0Glk0bRW= z>cT7}0Z==jhX9?uF5VAl7@!V7V*piN7yk$-3J~{{h1>$D_`3KuppHv6Q3uEbXtPq* z6+pDCA1~R+y6fU8P@Mu42C5oBFI*QR3>LBB?fGN|$aO$4+C(C~Wk2|&*QN&>VTP@j77 zSwQmvO$D?VkbF&C4`@1|WI%HO)m{@z0F4JU6HpSMGuOoPfNlpg3(#ml71u-q8qo_- zDxkrD{&h{X0`k|`#D##2fC{dOivjrnJqf6(2CLRJaR#81fEEL~0BFTEF$+*Rpg#aQ z3h3!;;ub(ffR+N<3Fz0?#5zE40dfG^0_Y($0_x8TC7@%EsqOPZfgaP^hP!ymK>cm(;4HuxF0CilzzN}7s4A6N%#el8=a@UCmp>Pia z+5zYkprv(UF`ylQ=uUD!poMkfE~t+80F{DjJD^AE#ODC52UG#*?||;B6JH190(1zF z0O*c7@erUt0{RM24xrw3;sxldd4TA?`L}=qSH<@uEhHJxx1gF0NV+N>0dy~*?*L5( zbo#2e0?<%E)qw5-bl|Gk2q+TJ_kacg`sAuO04lA$+9nb}20;I~Dn1H`0ICJlSZyO~ zu8JE0eFLZtP&J_CSH)iau>JwM4(JG=#aG3tfIbG)45$RqoU7uGP{3~j;(miE0VwIJ zco9?{Kn6gs0UC{_0?Go^6Hq>&!B@qn0sRKh06@@}pJp(8kP*knB5|9m04xkJ`9g?UUXdyhH zRe)vzx*~~}0mTD)1<)iwrzEik!W0YWZ-C+e?UzLFU<>I9s1VRVK-(p8BcQf(m^v90gwyOAc^gDp8`}5=#PL5k~k9` zdK{1UUSX+Ik=lk-3Xv;p(|Zpdqm|SVNY!Lm2!#$^5&wZ%+82+lK9<*n)SgJC(6%db zLQOjP>N_l)K5-yWTa!&3ir+m|NBGQ{n=er>DYXbMfb3Vbod!95Vy8<1W@bT=9`>5&eV} z>wfr2(wl7VNtba%AkkuP4(*X{5uy_^(4+@5R zQpV;98DZ2!9*Aw7q0)eC!H(keuafs8-iHq)aV&0Uf0|!+8i$^R2^n}txDr|<>bbbG z!U<}tbVV+N78!7?(Mp>+1p!BfJ7oG;r!-sVh~z&nnw^dQ#G;Y&)1I*r`t? z3sT^NB7c&>Uug=C)J%4Iq?YH96gfL@WQzY3{Z~^wi~^7=HP}FA>)zMsOt@x2|jl z#~q1}FFg{^T8yzp@J&)*5JYPn5kc^Zhp*)mvznLbd>OKwWq`h5%%FVO47TZ| z*h;>RPLg_r^L9_qXX%|om|t7QSySPk=cB_o4z*SC&0Img(=c6=ZEWEUMnt&8m-@zO z#V~O5s19bu!!{c`PW0&z3}wM6RaIA2ZxYh_2`PPa2m79#Gm9#)%j3X3Jg`xKGmwo! z3LLR`d0%`Rl9shShu{ z#wA(feQ}b!n!oDhuNHH|qqwS8`k&W&^)oKNM#Iq)%qvQo7HKLT%OUEtjcOgDr0H2c zH8qLb9;T#TR#HvfOLcME4NCeYp<<_=DH|P>O;xprukrF%yeT!utG(7n^Rd;|MlY&R z-W%w9gO|UozF(*B*S-8D^}U|H*F#V^J4C8(dSZp+_o7x~5%+`Pqo>$x`_r1dd?O9l z(CQU*KoGsoPy{zpT1^mbV5mt!rH9lK>Ve99Q+HNEl19Og>;p%(~z-B zz7=X5dRTvgv^;k!+}iv=!5Zzc)_eE{p`r@H-yo#b>rQ*pYB32Eq)teyr3k@LD##Tf zjZoy0$9h>oE(>XwC{pdQ)+mD87lPZ1b0Cf&MxTrM7Zc{BLY$&il$e)Io?uXE|!fl<%4|as%x3nBT5czp)_;JU50v|KIrLL-4 zLp5md5p4-Rq9wt{OP!C^-Q@e8kbM8DyL^8Ul5Yg;pyEyer-r!rHKyN-lWdB+4=Yrb zUPv*-%Tk=k6|5^A;nfRgO7K*MDaii>O4ji1eWQ}ya#ZfIP~?u_)WcLM=4e1hi5B{7 zHk;$Op%NT43{VQG2$R)^X&TvGIf{1&qH-^FmVstC4e{Sfj|S^h8xa<2gbGa4`~=bd z1kv%R;$e4tY;KWS1y*%*77^4?+Ed#tqWV-=1y{}+yRHX8EH8vG>$EGhSGm0_4n z%j6KBDigc#3FB3G7+oR5^)J zatD%fFDgc z2%rjI^UGYE$BH0340$96Bkn8C?KE>Me}|!LIql)i)O_KjS!mWIrCG}Ez?)(|fhD?4 zfD{QD!P-VGcG^}dbZ18h11LewFe?lLO5)K##9DKAyLm&byE0bho88W4eeMTR+J7k@ zWBT9Azw$rJ_vPwncXD;U-B?tV9>LOiR})_fGt zZb&VVvE2};LNja@-zE<070eLIo@$t&f8v`$G0hhCUXOPzi+rC46~v%gK>F?w0b~k7 z9_u9`EmD_u2?3-Y{!$BnNyFK3*ocLt0WS!mP+scrq7S}Y!HX&Qa#`kUU=Kw>NYmv1 zJ(4i4ZW=)0oVz@#>tI{!x{|O&kA_mkcB6s`*C`1sQK1^!jS7ZbS1KebB7^463HUzK zV9-AJzcFZ)d=2b}|A)tn%~x|GU*m+O_>+PA=@d~0uItSB4+9q@`R@bQNrh4Uj|109 z)pg(=4|LJz2*W67UJ5_O2u;fs9k0h!FqHJ?TCU8~9m_9Uks&mA^>B8$IET(xz-`XV zfTo7Q64-2KPeQ9uspAbTW1v5+0i9J3T^4hAvF2~9Z>ae4WE#&1ks9)AP5SHxg(jnxgF2_SKf-}$d%Dh(NQb0b&aTZn%#1} zGmIJ~T4|)5WtOu{q&i@;sVx!e<*cYwIV(chV_HdnG%O-y7tlzS%#7jnG8V76W8hC4 zB1*v@hM0p0b{3}Ly%3)aeMEnw%m^zA^|PHh-P@9xvU`6dg@wwndKp`G0<80zCq79VPfjprJv~M=)l(GUrEv= zmM!bmEm1OWW~tSqlQgh`!euAjMNu0zda0W0ActHLohit|lB!1^q_Np5pY-`P^>SjF zqp!-QQ|i0Ux0S2l+d1D~gQ8|p1&vA=L=r{;8cJo*0^0$~+b)TNL2iUCwqbHh&A@OVAf)W_TvqGeSI_IWuGmrNyhJkTm*d48kO&(g2B(TyT7o zo9Tv3wegOGoIw4UbkVMM&N><)1>239bkUg^ao`FpNx$-LXYZ|@(`GNG4d15haha{b zx9%Lp&2EtxJDWRaKiCGpNXSt7`#3~~hhc9{oguH_B_8~MMN%)#MdetXspY{7X-&G* zuF3h1y9B;oQ3DNKb->kB_!l<9*?^{2V4BY+2ODj+A9?9cNnv$QhZ z%lHw;mB`m;zZGKR0MyL9JW?uSV_i49`o=vrTR|)I7lNDPs4ry{0#0Dq$e$lwiU{wZ zCXt%JTcLs~A>4;+6dItJiaB^64$FL<+gYd2EDZJgJrpTtHIs+5HY%=0_-7YuZD7;A znzx&mBIDbwOPMtYR|Ti2MtxDfq%CrR7pplwKQKa*Srd|o&23A=4gRI}7&*beR8DAH zD)vB$BStfiZ`)FOrPGg}KlMY;oY_{A&eeJkmORPTM!dM1m+|1`Ww>?aJM!>c*SybV zAL8AIEp;9zoc68?EWIPoTSfQOct5)u?@}~PR?;F|G)=+1``&gwuQ;#UA!%K&tyUPE z&qIe6IG^7bUTSZ}Z%K)iR6F9hPjs<}B{8rRk#b|u57wh;ci9TtmU^Q7OC!ZMCs-Jk zbQeusIsr#WgVgBGj5>qy*d8Glbp~q%S$Et1T(j6~))#XUGYT3pj=+ zihCE0{akk>N;t4^4V{2~BW4i%#-3=`^Mx-yuQm=UJw@40Q+Fj6M!JiN-XG(7euP)k zxiwG5HXIulQ||Y{Ewqqjkow?$fY*rSRWHL7KroQaMm_GnE}I){+r}ZfwAvC4OF>r& z?PVg5Vw|yPG9M^QBgM1Ve4zU$){#y> zgS+;2_-dP_2brUZMUk!L&sj+2t#lfo6~@%Gc+A&S^_lR~6l{?!u!k)or$?Bg!avZjIZhq*1EyF>%@z0lTdkxl8ey_Z zvY0*#_tLMSoM6yqsJ_1pqVA}#^r5zii#bQnU>xEQ*(R~LW(2h2)JQpwsV)r;pwe-1BzS6IE$Q0xr!RNy`E3u0 z7OanBnK}%0c*H|ivKAZ~XeCwsLsuvme-J1qCnz!_rsE*;{i_%>)_f}|?I2~}i#?&p z#IGk}{QKI7r%hb2!9x0!(nx#atRd-NhPEFRO+^pzba(+^vBgWS$q^!xd9xUV+iTLN0uWlr4Bu1M@<%T{6|}taBf`E zLA=Bz#%2UjnjOX>9O5S+{)bB68+%nn&kl041609df$GIg#ChpWcZj>C>5H_Io+4De zEBb~Nfm@|m$WVkUcoBp#jGoA_ArA&PGveexNdXn?=(Ga5qew59P3B|iH?z2B{~lE( zE25%iCrwSz+c*m&|5nrGgv<;QwHLB#&mbnXKXSqrjzp?2YF$;;C4bh$!KC@q4W;vc zRZ9pNFZ1ri5TQEU7^0rGF3!y)q%ejp-oq#;R~1Ts$tc<;=hWq-EClk)$)~}Jg09PZX=8(y=CA0>ERD*H05jp}Tp4&p z?a}ydtq9#onihq0I*k28bxlVD&Iji;c4_KJU@>5&m6^Qanx6I0nGHRkzO>NPUW>4v_jQ_ZqS8VEkZKe;( zV-u`AU|rUG7*y6&cmsOjBM&l+67dOY7UtvVpK2+F;Cm``n`I~&Nv9)tV(R6*)jjFu z=Q(@dN&|jThoZ7OS~lEflj3MvFD0!P(qIYFol`2(u=S_YUjcXkkh{@1S7kvQ5T`Jh zof51)KV6wwb?0^P(w`RTiOO7hkU}lBqahJttq(R0P8+oDXWRAd9ls^{j9Sn;4 z19xGqkeCkK)`NdUxo7{(4g}&r?(E5--PcH^n!91M3}?=fHft)GLYIH|#&MQTg@XQP zK_~;f83uNgbP_Fy$~`PCLIYx7&`Or}RJ8n1QC*;+0o5oJjBN0! zZ$D*Ia`<)|`2BMN{0UM*i`KjJC8(P>;sqLv#5b~E3)IWF?%L>^hxXxib!e3l$0rI} zl_&TNnxSFX5|;D1vL5CsD){$!g*&3FGHPNH;lSBQGYvMtfkbOBrw%6*OdAcSGrmEn z98M34Y5Yj#aOGGS2L^Z!9s(n91aDC^1fq33&2ohmhs_c@jP|6dBIr$NI#JznY=2rC zQ)>bb_d1YphIpW2sd}S#p?*SG|4RwsjsImO*8Uu!A}zQ7Tnpg9?^1A=Nk`8qyG^uCSfCdDd3ssL92^il@Q zL@iu$=2KPhl_un|TWEq>*9)K8Iv1^{n1z;6Fgq17?U*;gZRpQsobo9ZKIQ+=KNcut zy1<2uyi^3bcY0*m;b({ej1_szOc1i$m=HD=+pKC~l|L zf|+!GM+>G~h({^V3KyI*R$-!rQ+PseRVUH4h0_SFjM*!SsR|uL#VQ!ir<~2T;%tr{ z_qJqS>|}gxsMY}ee1=l%f2jnD6>@@Gn6wrj&R@G$b1YtFfhp20OqNfc-Db8p$YNZww3OCv4P#e^dp~H3H`kFR~o~Z0VNgpc`@Yft zdM>dt`<*VsLyaj#%tBV05CfT1TSU{`d43Mxo|18K84VO#!{wEV;nEBJYQtOSQcTlS zd3hX(@WWy#XM6(v*c4>G8#kTt?Le4@@N>*iPG~0xS#8+eSH!_k>n>AD_u^V`!0R}V z!3m~U8u5h;^iDbK4a?mV>eBz5I3?S0Vy_q|2qmEI2V(Z!v@BwH3SWAj?a}bH!RJZk zc10ruH}h=g|F83y@d^z*3>Ut@wT*`n|GwQO&c$Bz$aciP?-8E{^f91xK&Y9_*&}`k z=uJS+0(u`%(jM^vY?eKM9DrT}GwoWKuxSpSyMU?z6#<&DTYMPMtAGfgw*V#V7JmmQ572c$UO>Zkiz@*=3#biHHlV28 z;;Dxa*$K$F4Ds)PI(CW8pyC1b1~d!Mm0jY5yRqa08VG0-pi{fVm??;V2Q&mw9H9NX z#D+%@)D37bpn-t4?-B{1wvTOM9H1~jf8QmZ1M~x+@qijWM*RCO@eeZ){|;y}p!0xo zc8SwKwGYr^fDQxt?Jkjj6!GtX<^tLQX!b6#dM4uE0X+%mJwTIpiDMr_us5J*0Idgf z*DmpoD9ZsT3y=%Ypk3l(P(2063Fwc247#^;sQWAK-&RD0(yU^m;l>wT+Q_OoDk-dQG0DTN-`c84W z1*bBAZUA}{(DDk6?J@=?RMY2XGCj zqQbEHd5+=Rj?)|1|7Mf2(qPIA#nrnITB|1$D{xEq2@8oq_5sL#C#ozf5x+nM;ec)h z6b|lO_oI$azrvCj5GUesD}D4!gK;;M^pnXw z2dHNH>MPtVz>}XG_{vrw!-a%XZ2P~v1$N^yx)fHjT1Uf-^|{T8+X?T~@lI*9LY&eXNx!igsH#skh)2tS9KNln|Wp31+y_ofn*mA8j z7;&34HlzhX=?=Oe^r$qv%7t-QC{$1Tq$&1T#a-4{h?!zXOa>y$RxK`&4O8s#rEHL> zpCG(BH_RRAm)nCiwnty77d`x{T(vGsmaXJBz38rhet=XmE2YS9EH2nQ#V$uqv170$ zITzxQjN4=xp3(`J|?qoXQ7CG^OFfniOc&_eH^0pZ=pas*u{1+~sN`G@ zpeC(^4-nvhwYBqvB}>0omLIT3VjWI*=NdSB3_iZKGTcf&;4q7TKGHH(i+~@aY&Ve^ zaW+@3p34pQPNm;{dKjPPY^|J%Z@N@Y#dUA`DYJ^HdfA;D0mlMlO2$XY3e31s7Hg}V z8i7#a%8*lD&knWOk+u;19=93HiA1Yo3OMq6wZn)ITl4Q+&j?&6X!5P7Q(m(rkWkmw56dplQ7lf znQEr~C}FBWr%ys)gFdd(qfb>5EJ|l{&6v4~mG(%K#%UeK{F&M)PWmewc`BIHc2tVLhr@Nt&Wuhi6zMB*O1v|C!9-ENqFzwaQ zuQN-ruC{DP*j_C@gXU^`($RCTwg+fk+zteI(FvF7)q9WeuC_RPFV}=P$8cAh9iQQ9 zd&+SOFo&L|Vgu=yd+K4e(VUtcIu1k*L;hD>k`zNp>7z^PwfVEG;aq7r0%1PjTy}l_ z7fCqMo$jc~Kp-Q`<1{^5?lB7cSnJCSRNATkM#!SK2IvYM#{Lf57D`mipt7i zY)?jGJILRAgM+K5>dmDqdr~=Jl7k*Rq%e4PFDh_h;47yUIjx298N;Z2!d3Zjz=sCx z>p*3+lF1!5sZ0^83VQN__E^DpCZ8B;uzTXVtjv1$PWhx2D$?jUS;;9GpO7hK+RAK2 z%W2!L#2o2=w&5m{k9-Q?;r(@BgySSUg<0)3Q89JqB}8K)(`4eqnHuuH2Eqy z8A=D-OEx6(hAhOV7$o%_A@yncmSk-bXNQH2**8xiS~iP@E8a7`cZ6$^;Y8F(NoV8_lhjt?Np7TMg7Yh$HZ@X4(XOGaU+8O$4-VjoSL zW1Q|WhL`5{nIkMR3+40WWHSz$@ZC$vNVVzU2)Zau#Fq+7**zky^s(EC7V3Os5iWvF zuEO(>3>Yx`v{Hg_4noYE;*XQ{cdGlmHcj@BOnrFivO$d5*rJ=sd7Kfz%^6pQAckfd zcN021OQp@8%&jz`zdB!m2+d~!F03hu%(Efrh3;#f&VJCiu7Gatb*F1_b7fpbFlWyzbs>Oodheuj2Y zfN2Y+Bb0zDjIkoI+an;2?l#$BrfdqTadq8e6GN{My2I$Ij=de#tv#(ITHd7L{k^RL z36=GrmH7ujn=yqJWP~!aC|4mcCh49|#y&W*ld%ICWBYV6_H)h6996_nFSJMoDhPUh zbBbenVTuDoA1TDlb;yRf4mRv2F~xy>fLR@PcK6Ke_>zsjDY1o3nBEn7uEk(+MB!`U zY*Im`t14KmT7=784r(H-<#BU=*5KgcZV>d-J$fr<38XcQ3m(B?5YQt1+wT>)C&(-B zW8cvf7MSI!=7RSMRvVetw%_KO^j?A4Zlu3@Ixr=Bx6whP9~1W#bG~gH$o_)OBz|e} zOVP?TREcQVayAt#w}Z=PZz#)IC3HN(j`csOXi&F`kYkIQ<8^5|OL7cB9Z8&HAT{K~ zU0Le7a1Y`G4Ai-x;O`Zv_#hRxn~@C*hR*ktjD8iXCm2)$DYvYo3E_E)%qSyeK#Ip1 zKrV#Vj*tdhg){_HnGlz2AqPRrWDR#?TCkqd_2j(o3S|OXrt`Tu*6H6qkZV{rQtf$l ztJ3qsINvcT^0@Lgww5i^N}v1w$q9O0W$s{5JIvr}+*AWTXG;68=6j9i!`JA^QMv+B zVvk;vYnB|H<&9R$)A<(5(n8jRhoB1Rhf%{zS4Jzmo)hfH{MA&+^a}M07v?*ZZs~j@ zWTjK(QgmnW8lBQyozDo>qb#1v@&gO2a8DLKf|f<&j)ch4EPM$zt7M)=9G^n^3=h+A z?&BONJkh0Dn@h7c4VUxE3uZgO$x9}11qY0Ci8k?c*yF8DRK#CBAGK@S>cMMG^+RgG9uVTUox z#={gAtpC8gp zifOC%1qW_fdL|C{l2Q`}MKeLTwZfdpKo`Nxe7>X=JSK!ka)1sL!fWq#c zNJDP!RMH?0df`6VNDUUVY830eWx@FZ6GZOC3ZVtEa&fKh>Qgw0!sY$K@L>1>l~r14 zm&BJtiJdH@D_jFLCPF$2idMI0YXS6|crXjoa%vy!&hVK~a1$FiwzTWX8Y8lZhiUp9 zNQX(GTK#N6aZlP(K-U3C19g&V3|k5|Zz;g07N!CUu#z1OikyE#Gg6*nD?--~wsZ`p zofS?uubO7p+k4QLFa#Mf7BJfUS}*S8VJ%3SsO6T?+i@p3@T}@$3pPox*RTlCuG5~q zH3(zl`&>!Re;<1&Tz`UzK(AzA?T}LC6dWH=KPe4vZl7Rw=qvO+dBmM!d06{$mMol% zJC@&uxU_isB($YctxkAaEQ|tJ!TqUqj_kAoy!cGQA^F7&BSKxF-KrJHt`xzD-1)9l_``DR@FZQadr zuJ$;)!PP$6p`QlS)&4;C7?(6Q^UjtFy7E3J?Gl2>+K{c~!W*lqT54W>Ls#CnN+k>f z;j#;l8Jif_JKF7A56;_-GX*x1Aldj8pd~-;* zu)KKCk)azY8;T>nG;O0&Yl^A(VK@R5a@{MGdLyVQ-6Tj9%7_SVy_K?7D5=WDu@u^7 z;kwYavsyFkEaG7$cg>I;TwvH&Rlb*xH1E?nz*B9OW(v0Y|JatTJNqd7+OB4q?KHVFwCB+py8m}X(o*vRJ!3iSdLTsKz_H%Dohp$22AhgzJp1dEJIv05UmBnAEu z_#7@vyMs;cFEevX44PF}^k^_v;aJ6z856L<_Cl7AyS4aTsn9h^guzJdLTs+K)6Nx$ ziuJ{o^~Yr!6?oM+jxmPI_Q6G*clZuj#@|V5shWY0#!gz36E4FPbA*F0quhKzE8x$S zU^%s4^M;vA?Y;-A9X{cV>w$@m8g#w!y;Wa2&LmSWhbjWa<6++(8M=N=nKHYE<2B|0 z6^9`TFqKY2ta~YD+_<3gjxEr7p-eK+S*e9lLzNf`hkvZUJ22O&+mp(95{_qiU-~)= zU!stD3l%M==|_@><$YgiI1X=_C*f7a{ibYnf|C6z!p>M}O!$>Wp?HcHA*{51dIJ*m zYo##kC*@6ykj1VV1gAL$cMMGK_B*oYVq#~`!CgNgB{KYrmAzebLl|BWHafZG4AkHm zZf(}Ni@jcnLty$VEsd-D@fUkY*XbJ`F=jumO*z+cMt9Vo;?>_}UZ&SSDCxAkerwIO zB5o@}fX&J*jbM%ir^)P~9<)soz0eVVd^TP5vBVW=EcBajX^I9_7Cg4{nTt4K9TXz{7R8WSV7&S%(GN$LbiO)}S_l z*TXlk%+Ns_sq^C=3cCf2Hqp(F?s|&u#^Y+$z2BJ;S0C5PiV4%z>ssHz=VMuAN&~9uLh%O)C&P~k4L~&Z z6`RGZq38&2`oM*$OlKxZ>ric@cW&5%9)mkucoRI-RJkdUO@Wq*dd_|)*aKqnjEwWc z(v^LE+c^}gw-3WXGosx(e1%*p$+=;Z27r({z8_KupYg4xpO4`<>Wd*SVFO9?=gvV{ zspNA%t=3OH;xYM0xmc9wvd0XUIVdmYb5A9&Axy>~nUSKk<0~uhP{Qi4_hW5}q@7@9 z$)#4RS>)W?K&QhB!bPza1Yhr#TfqU`DE7RuF00Gzo;kBf11D|EK5RVAMcS5qdd{IO zf|pmnz5ezTgLz-^L`y4;1{yY+n{6@P8e=qu<;FiP=NN;s>c>AcX+s*GtRYpOt!`mx8D41 z&Op~*`rNxKQQl?WV>)D+BU=r)29wezZHL|ZPau{c;!D!`ChBndEX&mD*tXG=Wqtz^ zFv$DXnCx+~yS;yw&S%n9T^u97KX}<2z8u*XsdJ^s8tH5IwXv(5&7eJmJwnS58opU7 zMT$u(!B4$ZjGtQRBiCa2ytD<+vC`X!?Tb5(zH01`ORw+2z1xUAX1LlAP6RP)ZmEpr z946d{iO}PE4E^%TTD}b~vS#d9EfD+QDCb}+jC+8soO2*8%h3zhxyX*dhj_skYhL}( zcQAmf$iLJ2W@!nooi5gP?Qj0#W;u_-4(;p-58C@<)yGA^PJYZ=^R09XO@Bf=A8Apu z=X6b-KabTIMIOON7W}W$Dr4>1^&k442>32)f=w3XykYnXac7GU_D4JmYw`W)-o_8G z_}@v4vFi@J&FQh8iN< zhmh4A-n>$`2WozB_X2aH)p}C$E-U0{fiJbg_dOR^>W?GCa(DCn0e>k}f`}q+Q7TSkT811<5V886|TzEOXZB&{4d+o7f z2i&JP5Csl8nxt=hZ*q`I)=#udZRJ6KO0MOm#y!44IEPy5Xf0nJ|NfZH4&#tJZT76r9JYBFtMP#^a_{jH*VVC^ zqg);4%mJ>ey)$E79fnM^>uPLfG@h3Ab{#M)k+4-Y+Ha)K;!0gN^mc<%fz7u_4b54V zN&m}SvV2M263g@DOUjoVS@M^q>zDjv$)+WHmNYG0_x$!H2bbKw^xY*NE}293d$+sV zdt~)-wU5fiuFfdwT+**768_+sWyYyfTR+DHoqvPcVQl|HHAPT^;ZIRAwy0|9cN^C? zm%DIsGtEx7m>1W}DG|BzCdAo|80Y8!FVpu&x@8$3*9?W6V!rs8`^FvEe%{b#-Z^2c z;}5PIQH~5sKCY8|LXLgbgt_*|q-9W^*m#FA9U78o?CG)1^}UZd!c7=k$(zlbV;C*s zT4xbJO&rS6Pnhc%jTb1N0jPaF`7y9QvuJ~4-q5nxtgG+a=D3UIoY|R^QGFFyzwA3{ z)CRgEKGag9Yw5f1jXozGI9iCvjlGGs5VR+|HcmLT!R3^3lBjN(aiJL>3DMjpV84JU z#@nQ5NLPuRr{!h*bxv%E(LH!lPIoRVkH87EjvCbX({$*+VGh1I*)*4}neN)Vtf_0Q zUl$KX>OELNcSLi=DR>_4wff?ko6C|M_rN;P1X8|kE{k&X$8&yj89e^^M_rtRGs-ub zq{s4)CMC&PwQ|-K5_SC*sb?kswJd{RXdL!}IMt7#OXAlXKU^PI`r(ETv0~!qhwDGY z=b!Me{=-*3d^PkRJr-0q0aloRPCXXhQ{zgpyJ+}mE&h6f)4(2Es^V^}YN3bccI`XV zqNLX6tKBR^Y73sGq3$he_LeG04Bc&br^?=ia$I?L@|#GV`o^CzXX8u#to~P8j!jn# zSj7xQOIby*_k}MTK8ibomaqB}C4AYqRW*vOsp9c$gmd7}#lQ%&XQsl~v`y4=nZNUf zZKU@zr`b1tfCFHgcbcZ_`wZ_iZP)h)Tq|{>?S1hx&fe2IO@}n<`qJ8Cl^3NTm{ya$ z)AXT?c)z>Sa4cJclgY!`7QWJOG#laT-(({M`CvA|-^4@!3Vk`0O|Ia@w-bN1RdL@@ z=+_7~W^v7_jNHJ?WDV01Nz7m3pv5hoTU3}p4kFv8G zq@l>6%M1?@+I2Flu{6V@utHaTl#P21Akb&NV5h&$*~=WyvfMb?jB?_hyg~2iA^dq; zwtJsZ(hGn7C>w@ee)%WH=5n1~GXpOVSG8BQ>&{Rw&SJf;9Dg|?{`gKK*U}hw2zvuo zKxE>+>}bazm(#4x>?=hi?#nbe!tsW`Xp4!%PW%>@ndnZh_#sSJ%v9BH6?uJOxwisa zUvJshQ7>2H;pJ-mUw+ju=~r7RGxBRUurHIbkLA@`pd_w<0emXNd0Z*mxGySCz-eb7 zrPgsb{ZqGVUw%f8Yo$Nw1s50xX6!_vIK!0MDA5tb_BARp$Wq}ev^l5k8o z?ZWwed-}4z-hX_b?QS0cdvdd4Pp(<%dqd~y;IdoYDFKaij6Pn)qgFaVA8TCBALH!0 z)z%-SPjSWfyrf53?5APU`!w~j7Wg7yM*%Z^s*%?FX6i6e6NE4~uh+Udw9ER0moCRK z7cCE7-%oYEC9L1J)W888MB!!Gp-*u&w%PZD{OVm}HzHH^pii}{c)GEwLP+W{ zdNn~;rr}$C@htD(R`Jc4@1J%}YxWJ0QAd>Tw{m_;04Hv^jErxHd~TA=pPTV7>R&$X z*$VzgZnd>N{`hKyp0HL*QJ&3zD8?wDW_B4o*x9dL{D``K8^_Gzyftnk>838m$KiiV(t=wqw!h)Vd z#$Ssz;tEap@jQI*j`R6xTTt0rX9)y3LB8+dhdnq_=J8kZ>`@8A0QMSfBrkLnJ-9X6 zIFDp@BvgdqQx0t$de^=-r34!LD-@Vmm8TV|eE2KZS%y$YDF3M;xO3d41Wy>kH+(xf z(^(~so(TfBI(jX2IZ5FObl;=buPF_$bcDqi_nylp@g0dN%~?7jrCC}TDjRQbxaf8m zxYSu|({|38jY)*RE{YvO-~(*Td%$!?Ic5o)C%uVCYjx*Ox<$LH5*x8oh0*8Jt#;I0>Np_M!txS6 zN79u%nzJK}Q~&Dsj$d&lmK^HO@de!6fBfH=#OSe3`+e)qu8Yy)3=;8McH@{eG2@)l z{cBE-Ni-m_|7H_6rf{5--uWY&>E97ga7x3*2*^055(FHFU*nWt_tIaKU^XRgKRtJD z`MR?)>kt=MiGLio#(=U|m19P*+8iS`bKHEx2o2V*HT!hO@P$1EH;(W`Vh?D>FM5VX zW^u+fr6Y78TX$M%r=}cPm5ilpzSYGbrF=x8mRs{}VhntdgVq@g+`1S&>NId8*5CpC zy4Shx+j2CQwzGW9=6jt`W3g*aw5>aqK*C^M)H9ZwWq#c8vbXd(hy1 z{2<_SE%D!a|BX96(urz@!<5wkpO3?R`@k_C%4QF0Sa;TgE_$N1)QTyOFWprBGZ_z_ z3S|@`$92mHHU={aXYT|bb0F27VhXpUNeRTC}QtJs5t-o)*@Z8snJ{ zwUpJ%jzs#Ei4!&E8YT+hL@XY_(c|_$!r66aA3zn$ZWW>pT;d5wJ((p-Lx>bWIIByR z`lI<$RCW`YjSD9x)&R6E#JM?RgoOK@R{VU>X(h|#`SYRqwe!n|tSd9b%n{IT|06i> z6I!4H8{b8R_pK>ST35Q}bke%h_!w@Ba47!<7nP;k!9`VFp#L?#i?g?=tf)1mVO$g? zq`yu}Cs>W-uE4x`^C)k|Btr1*4-4(O)^(M_^|<;Go&<;(<&VKag$oDjCv;Uo8MQ-3 zF=M1K{4#MuBe~cyZ=P_HmNZA9)}5w~Nz(X@S^?v#8FmqDES0es+xwkk3LkWae`_Cy zbH79Oc!kSB?xG|ilH(E&W=3Wkg%c6%;PkjwxIw>KVMRvI7{)NK?R{kFC_$_rWJMc}; z4@a4H**J1bSkt4>y(O6a`vgX3gJ|h)KX646V%c$I}Vv(BDPe5K=W$+ap~&($T`^OE{hUQpQt`j(|pFY zFY1I8e&S1)FY49!(i1gb8Y2x@^&(nMv{bpvHSQ`-x?5MiOrKxIMR|SO^~b;0{^%tq zi0+v80A||HkXOY~a)^QV2FQOH_ifyXn=+&dH@tOVd(H8yx?`?yunRcx!|__(d2B)B zP7JQ~9@zNmB3dv;(V7}_Aj`1dY4+2NTHh}k-=RKybZUOwg-9uEzA^5CVNPm{;CEM= z)|^-eCAc9(xnannFT3euj75{Mz~GkjnURSxE3kr+DOBa@a8z0TKuk`KeHi|PWV2pl zH+T|OwCL(R3$(&{Apc!VqCmOFY|Pqx0?6O)_cS)}(YGT=NC-I+=wN@gR-HZx&( zK%Qvgmg%TnGASpAvkwtK3^D5|oOr;vY_PD%ka*VdBU#KzLy4D@ZY8(E6@l}DzBtRO zFg8_Sq+tny>btF97J~GjVe;igHP~CRcAkZJPrN#fT44f z@MYU_y-;30KfaWzO^^vHS+sC^^NJi#vbH$=;x7hLGY6%1~;fFab-d+)sydWR4?2`z+#03jg>9YTOmLra1CjO3Qh@Asbf z-gD3Yo_o#?to(Vt8clgL8m*+!tn>Tsc)uU7>P}8MG3JC(*u}x^r(9&axK2LF@Pi?D z5({$kM)&TIY+0W(sVDXN#=`>l!;4A7Xv`$_lrN{;z!!q2{D6f=w+i1C@QDjvwbTZo z|9r5;Opzx|`3C3iA9MTtm_LkaxPwLzcCOlFa4X#8kr9qR!2O)@VamxzGW=zb_jsS= z!A$HYy5ksylX>%JkHaUdZ|>Y_HS5iN?)dyScew9*oy?m2fOS3WK$?8#(xa~2my>_O zBWlbYdDz7|8g}yJ2iNKKA6#eRXEuK3Vyl>8@NxYNgR%G-Uyoe+Im{>n4Vsiao z({b?pkx>wM*L6$O)GsD{H)l$RiI9+hJ<_O%nZQ+>O*fbfQ{L|!$u8LLRE&B)GIPpt z?qn3UnJIsHy{+ysO%e8^WHckI|!ixz%OgTB_o7e|dFxap<>VY{7euv)= zjqm{mA8uUtAn@3uyXYRnm`(U?jl_<>8F=j79rczZZ^v3W?-<^r&Tv$?V;$X+Bz=AI z*Ly>|a_6wa!~)xnsE_4-#D@FW>rwUnDfcG%j;g<7I%yD$`GR)9Z+-V9Ij5Up1nB&Bw56RQ;N<@WJ)tdOQS7CqmYPmw$VBVO*t^%N zsr75d!^wYi7&J5=ZN=#EY&mD>dL;=`Q`Q)y}Yy{zqYipLMHj2O7L&(#L5#Z|E=m3y$AFj(0f4d0lf$G z9?*M0?*Y9B^d8WAK<@#)2lO7$dqD32y$AFj(0f4d0lf$G9?*M0?*Y9B^d8WAK<@#) z2lO7$dqD32y$AFj(0f4d0lf$G9?*M0?*Y9B^d8WAK<@#)2lO7$dqD32y$AFj(0f4d z0lf$G9?*M0?*Y9B^d8WAK<@#)2lO7$dqD32y$AFj(0f4d0lf$G9?*M0?*Y9B^d8WA zK<@#)2lO7$dqD32y$AFj(0f4d0lf$G9?*M0?*Y9B^d8WAK<@#)2lO8Jf5QX#lb1r+ z0XyInBs5t6Ddi6z*xI^^qT=e3vdX~@5^yO5mm+&`sj~CeL!<;M z2S^~lzzYWB$G3lJIh0lA7nPKj6${Y6vKj^y5AkUdYHF)XEBZor=*e_pU4v9yURn!- zE31p3w7k5ys5HN}7>etQ3+wQ2Me$%CVO784>SACE2Pne`HMI?Y9H2J8Wed@B}|_ z0j)n&ps581Ekxjd2#0Vj)FIYIKwUWg*8=|N1GvI4=mp{75D@`>5!LMX8^AMM{2K*c z4p0yUb@(Z80EZIHC5kNy1S}A^2n$j~?bA(RNqzQwgQP*GQ2fGKy($jRspG2QT!j*F!9)TH$I zxaged-rx&$zEC@)su+B0z_+>vyrIAwDyxbsghCCjE=7+PmQ~iUy;53(X_n*{)|L)p zjxH%GZsMBa;sL-G#psjT;<7TK7*K-6z!KpSO2o8Es*CfBpro`yY%LYV^|eAPDePBN zT8(WWzi%Kl|?K+*2Dw}YVrpai&S1*UXI>_fpw*rM_FYZ=8issnz|aS zgJ|I1u7c{iiVD^Qv5gcCs3{#<4AspjIJ2&%xY|cp;~bX}+bKReCmxXUqC2raaq$W9 zojS$GiABU>mKH)mWo4}|YwJbDB{c$IF={c3qDtHuEkjx*rfy$UU5Y!}9@~|DDYiOn zaK%Oc`%it`G+gQ3G7UZJJ)rl1-UE6M=slqKfZhXo59mFh_ki95dJp`c^MFfPoqfR& zyaQp6*RjR;Q;-$K#YOh0N}##`5;8J!;yd}~Bqcyi6}xiw?ORe0Rh8AX)%m5hf>Ddt zwlx9`F2L*MYT;U*-72Z7F0QF5E)s5y6jctcXt+m`UtKE@yOu4g&L8X}CMG53XZIZ7E*;;sttrt*|JBa=hPwAK|*U;jaUfv&&VM zjsOL9wY7McM7aJI$`5@p#ln7gzo?|HaDbrul;E{6-f9pwsOeWZSfqaVi9zoKworT4KOH-z*$010irMcE5&ta;;V zyoCi2OSvX{1llo_Z?dPO4ItdU6tv|!_BI{+h>m?h$G)y(Khd$@>)57){+Yk6j_s>s zN9fq;I(9D|yF$kvF^Jex{Kv1PD?j|l08#9&t_+%dtH?>q1Yc)oXTecQO8Hg>*jiNT zR>}{WR%Y}cskLhL4-*af2PcXP49X85C~YNY8z73oiT!axTiAU<+a)YCwc;iaB#xQ9 zptWiWO;MxGp7c6eX68`Q%B z*bA58C72O^l1|FW!Iei=W+ni7B&Qq1XXikCTn>PH1^!~M2Y^aNRBCpNQBZNb%DAam z;(;eDf%0Oi_z=T?*Y9B^d8WAK<@#) z2lO7$dqD32y$AFj(0f4d0lf$G9?*M0?*Y9B^d8WAK<@#)2lO7$dqD32y$AFj(0f4d z0lf$G9?*M0?*Y9B^d8WAK<@#)2lO8JKjMKuI~mi#Z2$_nWLg1X{4XRQ^9`h58A^ct z>*FPkS#2D-%KpmPf(;AyWx&P*Z)Cs*0^2jW6@JxUsg|EN^6SFjd^AOHJ246x315=zjp@4xL&Osdm1sITt49wsuEMZ^{M_?lZ zC7ghx3{ezk&%l0@bH<-arzA2zUp13?i|ulrV^bau~!Q8Vt!s z1~G6Go-l}oM_?dDh=bQ)%^)6r0#61BKuJ3W9bqPvFi3=5u!=zvjw!y%AQ_&4qX|L^ z@MJ54RCoZK3?U6i9NRNUhhHF#K?dA_o(wYK7))l61()C;gHB*dt})04LR?G{a^Mx@ zGRTErVJL$Ybq6@xCY9$qr&3JbwPj?fK0hA;-*;Vz^w=m9@Me+E6_8(7Go z7aWIA8T1BoVy-~w1IwTdgM8Qtkqio8E%abe2%o}a21T$ERxl`r`>=;W30#LW4En-b zXlI7d54J;p2BokCMlt9Qvtb^C0dN?OGAM&NkZF!k4ohJrg9=y<+Za^Bd^p6Q3YNeH z1_PlMZZW8aYha{AsDVk~z@Qe!LNm#V zeAo@stPmE!0ocx9A&h~G3>Lu(=x2?v82*OI43@w>Sjb>0JcRWOmcc=|#9%oNrhms^ z1$+WlHV7+WI&@;N3Z_7B2CHErlrdNXt;i4tYvCk}aY0xIzrkS!>+xlc^9(k?3%JT) zBRG=vt_Yui11WGr*aS{wHiOMzPj)ca0(RsqgRS6A+PNca122-wU_1Db0tP!Ej(oyk zC(e2E#sgs&#FOqgiH7BF=tIK&5cWV3NoTMZ^2sa)`(OaM!eBoXkYIm=15iTlG58ev z5p4j%K`0}#K!nd=5b40+5EPSM3=TtIA`3z|0)^x;gQHMNGJ_G0L4P6%K{yV*Nv}|Z z6EK);V{j5ik*aWn&tW*R*CKoYBS;8?Q!tv0U~n47k;@Fuz+`fr0d~qHHUi-sOeB>I zzJy6+1%vbOHQCGHD>z7QGPnRg5bO)V@@sIQVGO>3Q)DfJi}*&3CJNzOxK4U9xCFnD zM+`2*N#YWXa0R|43mJR|QhJraRd_>eV-UWFb7U}sAK)UH&)^zps5TbiN4QP;GWZFe zlg$i%h9~4SgX?&nrf~>2;7{Vn;3jy{AO^SKHHl+z8|-KigFE0vPcpa*$B9Ec!aaN| z$d|!=ctv6v`~p1f$KV0nAj28_3irum1`olHo@MX|-!1x;!DH~GuNnLXm&mFFgeP#8 z{K?=c_)~*KglF)Ae9quGd`AW(A-sTRBt9A8C0NpO2ET)hUT5$M{vZz+yoL|t1%o%B zq6sMoZ$U|KrXsw9Ux|Mj!XNOSlrZ=c-+fxa;4ipBZZr5B2yL5=@E%O)Ck#H|_neU# z2te+V#7qQ2{w6kA2$b9+Js5E0CKW29^ke7+8@X$;2KA)+CCA^+d2C#juP) zYvM+)GiXB|6SrOnw&Zg%gMl4xzMg?S!Z8L82#0$kI3iqR;Do^CBRG?%M8&`bl~4w* z2x}O)ks_E^fZ&eGE(RWC0K8$~iHf=qfqfATWZ;dE%)kd>Dg$2K}EC#Wt2oQ%5R*FhILL7qxGK8#V z(2>-WoeUCj)d>bk2){B&MsV$qkb)4zAQhnxgEWMn8Kfid0}wJ0Y#C&dJ`l?w3zZ@U zoyagUl|eS)=voFjxat&xT#Rg1hLDF!HiOOxqskGwknhQP23=A4o802GKHyIQl$Oj=5VtLv!D8e{t42ltkFepKI zFc_gP!s&X1eh9A^lp-7&j?f>$e+0q+gg^#m2<;e@lRKnhBtixGisXz!sKiy9Mk7>_ zzM%OSVIV4245}NU2B8g8Y7y)i)HT8&1Q(_ZMsR0P-v~nxe3&v6!JolLjW7)J`kX1l zQ8~?EL?etuxW|-H2oD&HZiJ5!RAW#XgJ8j6Y$J?Ah-b=pghU1t8et+ar{zqUgh~~I z$&D}tS50NgR8(d&nAQl>5soos2EvT72s07xk3*P+g%28!FdLP026GT98O%kfVK5J2 zFoXFBA2C>ffORo~g$UIQ79k8`uoz(|gCz(f7%WBjn87lHu?&_YjAyU{VIqT-2$LDC zLYT^6HNtcTYY=8KSlbBe5N0uDJ;H1T8xZC)U>C9r8GM4Un87B5r3^MBtYokSVJ(BL zL;@QbY$Mz7$`WBaIRiWTAnYI;VHbm)#2xl9*oCl93m7(3`96g4v|p|j*y3BEQ6!C z)p!QS5R9r3j$`3tY7tH##4$LDkWh#4IYJ_XFA$O$oI*%va2jFyAcQjr`xu->IKbc> z!a)XKBAjAy9^qRCUm;v(Z~ql9(X~Kao8ok-^VIPLmm2Cx*1!N`xDv z745~~CV5E;7~H~iN*LTm*vQ}x9v7^&wz`Xo0QVZ-uhadRb26!T*3Stv#zO@e)_f^8d>c9`<#Eamo% zS#+SuVtWqymlBLyy=IX^(1&jsgwhmocZbnbu_c7lG|>qxj^GU~O&1ev0U3=-6J&}? zIL#7^s-+DIM>~nDnjnH^i*X`pP9x-s5JB@q2%??Et(w4&b`cd#qobOXC{%<4zX_r# zUIMTRvfk#71@<;67)Jos?Ff)ceMK;6SY?<<#|es|H%$;BnQ91&Y?*|vyUp5a27=(0 zOavor36d-Xws$0*5QJi|IKn}cO)ZFUeEo;WO)Vh@XP*!@Z-QKEiQOKi%z$NKl1HsX zr88zB6r-tauvM&Ony@N|;z?8JUGNne;)h?1`HPvlDAC1QrLnBZM>P zLET6MgRaztP<94kN1RZdd<3C71&wW^gnHuHfPeu{eTm?WI$R~RG3->tT{(ybl51>V z45n>~(CX@GJ93{XY%8J6LohPl;{nM~EQTe6k5JJtV37s)^0d8J_hA@EIGTnd+-2#E zKoAlfiSU3aqYxf47)_1fHwGW0@`M5Q;_!@t5yEo@V-Q|2FhO|9U@YxGerGU_29XE` zw$P{5ZLJu$jffbCOh#H3Q}Z!5dR)2+?&yaI+K6 zvw|@vTwuVQ@C^gzgl`!zCtPO0oN$!^bHeuwrlEU`F^)zOceaXoOz~;rMFWr)(8Q0u#21ZD+C^ zUB^JeRy9QylKjUip&9?rDRV4;wn~W8l=2Gn2Kz!KVXk9^m8_&4#il;KF|Sn!g2z@P z2yJW)ZY8v_wFqL(5QJU%-z3O37xG$%ARMslKocscqKRVDVwnnA6g8~kS?)p>|IOy> zX_8or4Y-xyF%?ZFLZ8r7oqweK&w8;AO~~ut>1@OVg)+0_ODOXvG({})e^|ANritZI z(Nr-q%R+G7zgKOhnZ%Usi!B&O*gLGZ5j?h)W;CXgE~c{$R|yA56KqFC=$dw5357#u zCxXy5vHnmvc6K2MU6T=la1iZA5W1!@2*S~{2ce-yl86Tp^St20jR?Zg#2T$oi@g|G zXe9e+mUz1PZ)+hm$o&oJNDd$f`|DF|^TJNqgzz^zmJebU!cO@NL1-I?XeYrN{J%Hf zOmhfcABa8_oXLDBIFm&doXPSMcI8%@Ejm+0bHxPzvAIyf|7P>ev@;R1U~UnzC~VFm zPt4*lDuTz3APCiAMi$|Kb4ze(q4LpqXU2!h8B(Jo@)kE0^&rV|LlZaRrR{FC|c zb5w-9zCaN2V(ADKY)Yra!Pr$SGu!V%g&dbq^(6m2g3t{%9eOOCKk$lPNJoGl=*MI!KATv0jgBEq0agpaz3loz za6*&P)I+v_hJ7&}BMV#IXspFe1YvVSEC%zB@a;l~(^Q^Y7)NLl|A-@;3phGOJn-2r z5VmSmOq!J2xJqbsDmqh)+=@;W_uw5|CG3>Djal5Iv&0kYf7q(UsyU4b&K48A-Y!d__uO|pXF<9RseSh z=&b&o>C;A!J!?$)d1Hbv5QHrL!{#qBj?ip=NBCc|c!jHkGB@S51{I;qO9Ar5 z-e8dh|FBF2rLkT-tFq7lexu8X;IY@J2zj-l%f&s||D=r5nVp-eMf# z_+tHYLzNp2G?tf8_jh!onAcPKiMZ7txT@)Ev(SFn?iM2d+32Xh5QMz`Mi5edN;ip{ zGiM50G1oQJbhB8~_jIe^1W6FxA|AQ_R`TdJGLhXx4Wiq{I4Zh>jAC6%lk$P?6w?8& z;m~_ecZ=>N+#azQ6hUw=i_D5)(iC|Cb}7QCSIntpctnWt6RbOF`1cC!GHQ&Cgb1H>N{lC<&7sXcebAmm3HDgxryttar~$M> zn|+p`U5f=`DYDOHw1=Z@h|E4eq0RDVCs_8mj;SfBjJc~7>|D$!u}vF&wi2OZl{ z$9B@Oopo#%9otpMcGI!lb!;{$ux0SnvAuL`Zyno5$M)5+{d8=99XmkB4%D&R>e%gc z?Djf#2OT>|#}3x9Lv-v=9Xm|NW@9H?2Ca@Ap<_qt*ikxmw2mF4W5?>)aXNOqj-8-m zchs>Hb?hV^J6Xq0(Xmr?>@*!aUB_laOk0Lb9Xm_M?xbU9>)1IucCL<{r(<{4vAgKl zU3KhkI(By*yN8b5Q^)S5WB1mv`{>yDIyM`L+cFgD*bhl&{q*$T$%J9y8EKSXGB>?9 z^;;X9-j~iQo0qBaO2wHP~`SF z3b_LgKn}vO$H6%4I0PngVK~@09F}uhSkFb`c;hJ8%tgaqE(Q*Bu{i8F4o-0KaE|MU zBaai|Yc2_X;F94Mmx=?B)8Iar4o|pD9D|$%FS$N^)S{wd0dBPieo>e z?_q}Y1I&^VGEYj$0x3_HOAW{>sUcY}H6q)j#$<<7LiS3f@?2^~-bk&CjO+4NdW0*5=aJ^v?X;Weq^{wd$Po&16gSj zL^hg);IQjZvdbil95M+fpPOjOd6Nio(Ik>wHi;tFOk&8-Cb8tUNgR1#5>FnPB#_@s z63Hu*B=W{2g?uncBb+Rq7|1e+MwUrzWu1t3tbk0E6_LrZVlquuLgvc)ksY#9azHkK9F&!jBeHUGTvkEO z$g0S1# z=9tbSOHJpKwWbSk%=lum$#e-hYPyu1FV%7c2k(r9tt@vP$+0W zg&D0-nA2K?k`7j==um~4j#6moc!edMtgxcf6xMW}!iFwWw4o~$wsf_^j&4!d(_IQj zx<}ze_bZ&~afJ&#rEsHX6z=qb!h>E?c+!UoFZxvBLk-M)snpDms?GeVt62bbH)~7% z%-Yj-W*um-SrAP#3#PedA+)bq80~KsPRq@-bc9(19c30t$CyRYIc70*o>?qiWEMx) zn8njWW*zBKvqXBzEQy{oOQsjiQs@t6>GY0S27O?bNuQWy(Z9_);hgB%)X+SKO3ZVq z%sh`;n0KbO=3S_Rc~|Oe-krLd_n^M!J*mHWZyIc#Mnlc>X@q$JjWsW%$>zm0)4YV{ znD?XI%u8u+^ZvBJd;qOBFQY@v%jszI3Od%jijFrQNT-|kr8CWI=v?z!y3BkKU1>g; zt}(BtTg->hZRSJiPVVagK7$%4XHg^NY${dGp{B~Y)J!>#S}Et#*2)FcPPvFW zC>K*_HabGNosL%Sq+^u3=y>IBI!U>Q&Qb2AOO*TQa^-%yQF(ywP<~2xD-Y7W z%FpOwij(#Og#=@aEw^riA^ z`bzl?eXG1kKPbPYhN{a{ruvS`Ro_#k>Idqgx<=cpexxC)pJ=q|I*n7^pdD2=X|n1T z?Wwv=i&b}NU)4R@Uv-~WtA3&Ns$c0))k8X5^@xsAJ*JaYztP#Mr*y9B8C{@yPPeIE z(0!`k=>gR%`kCrA{aW>wUR1rKmsNkzTdKe49o2jKQ1yZSr2@`W&2dUK&snHjaXxAT zE1GPP;J2tQ(JOl z)z;j2wGB62-I|-PZo@5C+j48vcHBm_J-1Wsz#UXOa-XZ6xC?3*?y}mIyQ+5MZmT`G zyJ}DF7qu7nLhZx-uJ+~LsQoyq3E+55AZMs)%SkltIGLtBr`B}fEHy!#jV6R^qY35g zHDR2mM$36?A~-)yBp0ZO;@WGXIjts!i_*k$9W`-WvL=B`)pX=CG>Kd{O%hk2N#@El zsa%C7jT@**=RVS8aAP%@+;~kVZi*(Go1@9)=4tY{g__RXYE2hzv!*MzRnwi@rRl*P z)b!#GX?k-6mvH#ETMXpfEUGzAi&`$wqK<24F@y`Y7|JDDe8i<%4Ce|gMsNcyMshT(;GI zuGH!PH`?k`Zj#k!+%&60+)S&(+ybj3+zP9s+-j?1+$O8z+*YfT+;*$axm{LYaGzS8 z;*MLL=03MN!=1M}%YAKip1WxE6?etz0{4T}*W693Z@4>F7rFaZ-*V5aE^%+IE^~ic zUE$taea8{&s~m6rJ!feB17~J^jkB`;nX|FJ&N*4%;9RY5avs*VxB%&i?@EjrCI;V-NwdRza-6<9yvimjh<{j8sJ1FTwO&8EwuidTVnm5TWd}D^>{mVlQqY0v*!6d z)~)yx)&~4(YeW7^Ya{*}YYBhJTFPIwHsNnr%lNz2ru;)|IseRB!N0aP=igZ?`M<4I zd@CC@FR{_^3L6VvV`I%*+1T)HY+CaUHf?xk8#~_H#-0zfap2qAIPt+YwtTdW3!iA? z%BR}6@fkKAd?y=EKG(*J?`h-B_qOrj3v7J({x*JmnTHlh5tHevidn{fWEjh2_Tj^J%uNAdx!qxiVi(R}CDF?|2lvHbAX zas15I@%)tI&mXoe;J>jg``HcP zKe8+1r`whDtL!THJ$9A+X}c=^n%zMDH@j*c>}z-lQ? zA^bS|q5MMokNC~@!}ufi!}*K$Blx@aBl$P>qj-tKXugfZ$GpG87(UivET88vjxTi> z&ku8$z|U})$gg&o#P4;O%%5?X!vE+nm4D(ejVF%Nd6nY~-pz3)AL=-ZPjj5j_i>!V z*Er7Q$2-pB7dg)7w>U1~k2)^ozja*1-*a5dzja)~OP!YTwoc3V0H@`AoYM-vv(rkx zztbvyxYKHWrqddJjni6wpVK=2tkZh_C#MbkQ>TqQb^e4`J8$CMoj3Dg&Rh6&=dFCc z^ESTLc{@MBc?ZAPc_+Wsc^7}oc{hK_c@KZzc`yIYc^_}#vY&77a)8fvIl>QgIm!=l zImVB6Il+%{`JA8b@&!N7gvFi<9;c5peR|jx)b%eIA_7Lsr z44JMjkmrg&xb5l=#jYMu=IRNfT)kj|t2Zol^@Y{0{;=LP0JgZcg?+B=;FN0zxat}N zw_JnaiE9YFbqxj1EgWQSTCj7AfB?5h=;#&&>25KQ=N1dS+~T3YEdfg0Izp*iB2>F2 z!Em<}nBtZSGu+Z)wp#`)aLa`CZdtI+EgN>Y<-(_KIdIIaGn{hk3TNHA!6mmIaLuhJ z+{U*^p1Adfr*3`Vxm!NGbt{B-Zbk6ktpp6*`+|vkKQMPM1uOS5@N_Q+Uw1=j=WYx^ z?l_FgT?*muCJ^B+gBW*HNN~q{1@7jM>aKM|jpoe>F=;dw; zecbJ#z}*4*xjVuDcNeH~cZF(qH>h>@fWhvbFx=e>#<}~zG(-;=(rh~s{1_XO%LKn|0DEG{Uk)Am)!7~?Tc;>-c&(5&R zvkUC^>1Cf?Pc@UDX_??I63T@T&8he46|NGSCl1$Ew|VYK(h zFvoigtn(fV`@JW?S?`H($9oDq@SY0Kyr+S}XF9m}%!DAHSrF+n8#?;TfgV0{q10y{ z4D^`~BYhUY5}$>z-)9kA@mUP7e3pWd?=n#OE(crR72x5!3flUvh8W*9kl~B(#QLs- zQs4DZ1W_}%v) z1o(Xh9sD#9?q>m!ewL8xXAS9ot)Z)58|dk03sru0FxJljrujL+EI$`mOhJofJnFa3MK z8~>hQ8qfX@S#VM&NW<95@r!1kQrpfwSRI;2by+I2X z5x!Ht7+SYo3hr%}foI$05YTo7v~Rl-lG?6@`nGFeSljh5vF#@?rR^q|+x8SJZF?Hh z+n<4~_7}h~=o^p)T?BQ|C1@9P8KQ!&KyuJ`kR5atDucd@gt5V| zU~2GdSQGpPjt9Sm8^P~@5BU=$A%B57g3=VBg zria>+O`-PquBijr7wSlkg*uUQq0Z!5s0(=*>Pp^(x)EiVCvgh%BK~1ML>uNyBE$Sh z$1s1A5f(stgawkCuy$l(SO>B&ESPKx3nBZ%LdlV^Fmfd0#QV0yR-EDkq=rQvGW7H$FC!!2QNxD^}; zw}vmmTf>F$HgGB27M_LM!HaMQFw#1LOzQ+ntuv^!u3)cq11GIJcxpW$Q0oanT5kx^ z`arnW7vi;kkf+6d4&T(R)wYFU+V(I)+W|h-2E$lw2#nK)!X#}N%+hLMkv0NWX(M61 zHVQUsqhXsi7ItXkV3#%?_GuH~fVLwX)uzC4Z5n)|O^1tG9Jr}%1y{8O@RJtb;n3nJ zW~~(7X-(jRRt829reG2w2iph*xI~zNSA;pVi%>#vgbE@fG!PqM0SOV7kR4$KeIl%( zJfaO$M%Y4igdI$Xu!m(4j<6!a306lq!}gB{9FDMoqYNPZ4f#Gr}DnM0moh2rqaS;SJJAPcV)21y!U! z&WjKT4v_)SHnJTAM+QMyWC+AYYN2Cf1oViEgzCs>sErJVL6NbrI5G~FM<&49$VAu@ znF>21)8JHOI{X-!0Y67(!tKZuxEq-bCQ&({h$;k4R1sK36@ydMJ7SnOOh7!Z3Ks$=iK^w_(wG4?)ej{OC;#Xf*9Vjsfk*hg?K z_A$JT{S6@QDbToQ&?@dZPGRu^?Bjk1$GBJE689Q>;@&{}xOWf~_XmW={RuH~e?wf{ zd*~SV0lLKjDTt$_D2^k2<9JdV*NRM!Ga&Qh49TZ)M&x*$gq)0%l2dUeH z;vL9Mk~vLW7^9F6xOr{n#|*?50) zK0bilhz}&c#J4BE#&;l(l60g0nYSmMVdI&lo?o;a5DOdLlBCr%&}6DN|X`1e5KWO5{ND!yGl zot#gcNq$J2OA%7&!C1y$UiF?ul5}CA+#Nyw)q}ilL(h^dfvOI ztI6b~HDq?uTCyl<9a*2Wo@`3mK(-}qBuA0IMeX~f&E$I07IHIbE4iDrjXX%&PTnQ$ zAhP7G#3gwP@lM`N0+aWW$mIR_PWu6pnEWXzOg=~kBp)K>$%o0nU;XCl6Bbz5G<5A5sZ5NTXDi##41# zE9#kMNd41{XxlVn8k#1dF=b@0Sn`TWnr`gb5X|3tOv^Mm5njO8JW>0@jbD%HN9O)lvPL!lOQ{!}3>XYt{ zFZX-UuyjwFn(jq=ru)*N>3;O%bbmS?|1M7tq-)aK;d}q>>CW^H^hA0ny_p_HAEbxV z-_o`8&-4iTcX}k{Goq*>BZ9Whh@~zWakN85JWa?*pxGH6X+cIJEy@U^RT(LC2tNB9 znUO&!WMtB{898)cMlL;;kw>p(bf&j6y3qR>UFpM&ZuD(NcdE?9w@@;BQqRoJ)Hky? zjmgZXiJ1j7GqaGEWfsv$*Q61tU79wHHbQ94W`~%^|Wo)5E_~_l*VLzMDwzS(;itPXz#3%v@~lp z9gy`gt;iZf2W5?;^;zTTM_Ci-w5-W=M%ENMJ8LRklr@cR$(l}&X3e1AX3eDcvS!h@ zS$L1Q(;RBsX)X=uG>^u0nom1-T0r}ET1ba?T101dT1?k;T0-}AT1wA$T1J2Bw46Te zw1U#?l~kR*in?d7reWD@XnOWKnxDO%)@E;@6S6nb#o3?Gt=XICvFy$CQuY>lKYJ^E zm%WXe%7{d9lM0eUXyApJS#5WSmo zm_E%pO5fxh$2l0jpzm`|QG?vm)HL@DHOu{+YI4s}$K0=QOw zIl^)G~NKfZJqTl8|p*M1$(%ZSu=)K(M^g-?m`ZV_?eUbYceV6;1a(Qp4 zAr1wQ<+TE{JOi-HGXh7PG|44T3f_4p&@N8~VR@zyo2P*IJab6OQ$kvv8hYkgK%YEI zD9p2hl00juz#&*-2%-K0u;Exq_%!?h5eH_KQYlV;!NywQyYD#K_hExxi%-jOtQL;3 z!q>C$33_9ghp$4iz=o(T#CJmGk!Lzku$V8n(-3!g!7Wy#MdDMMSAKgOV$ooJm)N!I6*vh+$ ziQw`I?+XT~2OwYLSuSGWTD1p5)Z3zI)Jkk)Y)vrgMyR((*0#{gQ8z|C2=(d~`fAkK z&r64(zM+MF6?J^jjXx9&@KX!j#GpOS!$Lrdx|u<9zR{@5P>)1Cp@lvObyL)%QU9og zz8Q5n>Uci|cC^rMqOL$a9`$=IbhTj!n4#Vgb!$WMSU|+l6d_=adJ=MW3w?s2H_kFc zAO-cQhRyqBH|i?X(@;OqLcf8!8g-mk2JW`drAEH^ULgUTIR+F)&HfKT-2(M&)FWEx zeT_t)utA;ujo4lm!vZ7bd7PvJKZ}i;%YVU$wPc*C13wpy*voWccx1%hF2o5t@bkoo z9Zh23j79E=rh&0}ql_az+}QLt&>NN3#;jF~A<|eQKt3*GjM>pDhFoLu_$oxRi*fVu zRfg$UVLHXASG7oI4(crQ#m|Bk`axrMq~O#Z_&IFsC@@>xXo%0ID!J1lzJbJ5h*OSB zV@Y#4y(OX_DpB{7H2Wb*A`{{d#AT|a`MArIh{tIS>RlV+u!toMdL43U3w@9z5Z|_@ zFc|e=5^ok&2pc5{(3)~M9U#tzAc+!1Tt1PA{{IO1xun_u22#;i!%;VuvR+XP)>5%N zBhhRl70b-lcuK`Gk4E;98Zt=;?WBP?mlK6CXoX6f%Tpo^!|A99j6=P@RBSVBgH_TF z;E3@jAg`CQ-argjr77Ty`Xn@ek|s3DIQ!ldaK(B}LB-vKr6z{0CgQ1S8k)OIvcLnk zosN9Sg!KSo;AG;yn2Dx=ta)G9%Y1|gvvKJp^AscFGEFAdeJ*mQthw$z8{*GLy-$ny zlV$$GwhM7NtsxE*4$ACt#w&tTd;lDgu{TV`a7~s1zNjxn^Oh_Qys^y7kbjf0-c<}P zrec~a&~!Hy%gNT{nu_gn6>=BT=Jq)haOA=5k)A~60%v~tW-8&tq48rchjfD={XY+2@_Z<)QVLBE2$vxR=h+#Dh?ovWxH zYly?*UoaQT`~&huHtS?VxMl7p(2uyhYwp}A<7|&s0{@IlsZy*v6C9MHPi`PPEB%-x zglwg_A8(K&ZWh1$shi86sCEUsL4@-`;`vD3+@Dma#q-4n)Ca1?wugvwU#3GmzQMu1 z9#2;{_s^HrVjVfuud18-fx8WQE7X5!q5s~X8>0TEh0bfl`WmBdsA;Zm8;w{;DeCqb z6IK);j`p%L4m8R`Qy&FyergRVqONW$wViqqa< zKVT8hBq0p9D1j6_e(g{nYtb7=DI;LGV_}a|VNhWTyk9Mv+dpS{2eN1@VIn+ZOLjDg z;XY2gnTOlD;O38TzRu1K=}fb7gf7T#sL!;r!x7M8`rA?OhU|gnF4Vg>=ohUP;0zU1 zm>}lPG&bRGLs;0L2cW*Bg}&a}hrOc% zY&wBW*3IqqlC>-3quw6%tC&|~cxR1IT2T)|{cr2$^NW>D2o$0of_fX9_KneT-cqqm zhM}HoBYuZrD|5I#9?45|18odq^$UxvHbPcpl}9j9Q%blA*&{oJErZbSN?xTlkO_^wtT z)c3f@k|kId7T$Oi(G56?zW{ac>`vEX{6gdjo(suJj9-Mj-!p;iM`oeB_bq%GTqDfr zSLFRYJ&E!AVw^~yW8^T#>4!Yf#}}7k2=^2F*#0bzpB!%D{$(NEFBV7mbHW^dUHyXL zUV}c%FAjb|y#nJe@(YKD4f++oLU@dN73w$ry1-NHKUoO&-wLm&p)l)Tl>a(-iScVN zP9JADAvq);c?wH2B#HFG^rs@P z4cP?Uk=eV6n?n}h6!W5gdWB}1hOt3ICMM#@1wuPP`rJNL}6vR2^LJyLDSpM0_ zJ;J=3;#7r;JQwwv@aDc~Y4}*Y2SkM#2DgP*H^sNtisvjg&!Cf5Y};&Q2tH+Gfz37; zu8k3xEkN2r%sHs-1Vb^+Wf*6YHmWJkWqk6;!V1){Y7JpD#%JNWwirIf_^Z&o zqwOPTY!Qo3|5#XqdP0N;jBSWt8Q~A(kk_GJ9pMAx8}t?Uv~mLS2Gm#M6U@f27oQ|f z#PmNw{WE;ZI2oCRn-Re<75C9*)E{7)GaGcvNGF($ycKo3$ks3yea=EyWGO7beZ3v^ z*vNcX)}XJAtcF#n??in|WPezRW!Qzh1D{eh22E5)0okjlR#9<{GCpCP4jVB3KGX}N zCN}AhqC)X484l+$#2G)M+T;B-1Pm_GHLwNsgJ^n3m%;W1ePMJY?7%V~LVam;SW`Mz zqs4rWpnfg7IbYkDuCNQ^A4AO`?cLY+4f%oeS2T~pRoMD0{Y%Q{y*ovQ~Lf3=#P7g zv+|SPaiQ~zil6Zo`uVEm^EBvR+sEe{-tU-?!{+%T>2G_#X8zdP&#zYAW&Q;C*FgX6 zO2<5DZTs2EjVqskpZrhIkDf9spS1L&>wkt{Y8}J3rSX;J^^cp+Szq^8>%V32H?a5$ zHRM_Ui1`Qb{BPjjT<_&`->!badCy88CKy?0vU z&u2hiKdt&?<>d4Q+!rJM2mQk7N#6d8r*&Qa7xXWmK9m*S_}8ltGEk>oV9gFHYe&D+Z+S^q54BPeOUi7 z^FLtn641Bn3!m_jddWNk`i-Ffdi@=F`>)i`nrETsn?V0+{d7)$sIg{8ZlN{moCBm#iMay((gf=AWDES8@Lj{NI{y z$=j^AK4*Sl^%(9-FwX~kn?uXztvS6 zVEa2ZG|s#e^t(5%H?Kw;{=0u;U|s`0cZ2?>jUPA1E&mT~;IFqZ_t$~`D;u$S$hN-; zZ-pL4n|ncj#pWx_n{4~rHg7j?2L49S@7z2ty!r4pZ#Hj1-}^zY;%$=q_bA>p@!tcW z_wn`#0QVq&Vf0t?`u^zI!mDn-5nr?BZ}}M&yz;K&_}tXX@NP-pBRzc295Lll`7J-A zi6`#)(9uWnSsVV2pBDVK`yamPv6a`$@A$7rdG@x!$}g?lh&p|*^!c}c8RsfLX~j_u z{`%(J4?eN-lkz)$YU`%WKIVD7{ElD0FK{#DEZ`e)zY9yd&U_lb&g2Iej;-E?F`=u~ z3mEID`S9wK7~`1PJc9oZ3jX`qBlw@W;J@EE@mQq zDJ(<`0X+cq{0AHAPX>V=1m0`=!DB-OuQIojDY_hlxA2pJ81L0eKj!LJm)beHg=nXI z@5tLJpSza$teDpxWiWk%w#WM<=?A;h{%^?pEB!ux*bh^-{8#a*Q_7#irT)wO^0I5U zfXKLyla=yY(6wCP=L0eB0$#1%bJHC^$o~euEPeT*aSo1uH8~s~SHBFG>s|S3aM2&* zL#qX=Z@0ehv2xz0^gTzv8oa^w@7sQsU*7NNLHeYu@0(@r0K(dg|SYwylqEy`{_FLeH{ z-!lAO@mc2kVlAsatlxSO`HAn9zOQ8udLFOlep=fv`=eXbN+7_&_w6$=<Xp7+E?9j!e)z_;teY#lbN+C@<#Alu>D$SBu)J80{~z7yXXun0h<`)}wz8^bSU-(12FWve4cwTnvsd75M_{+Bb z6PC~6_S$dBuJ@M8hwSjBxnFSOItaUmKYX{Xf6ChDVS91y55mve_SdretMOa(dtQ70 zj?dR+J-Bff^xL?&{I_@I{qM!sZ*@NZk+0jq`7Qb#q`UKFA^&pybC<8q@44GM`L6~S z{G7c*kLFQK(UreDzOvt6emDHy!Txr<{M=cV>tl!P`(Xd&_J_;5zplpTh3fl-wqNM; zx#hlA{o(oOxe_d$D{sX&!k+J3c_-`lzVmZsdE9Hui9deEImiEB3jW*~JK~%CO7F9z zeQV`@yrNqzOh+dwf(_d#dmOT=KEV4;}A?#GXgo6Zk8X z75rVmLfnWw9^+#h-%j4cZw_#g&Egb~y_m%rix>DvSWMY2BgRkF8-AVMe2Rj9nvc&E z@M`wSLX6j5toY5s1^l5~Az6X0@ZR-r3-cB86z=`Z-{G@%%U>+w6OY`vk@M4tp$6+uviUTBJn#Dfa6%-CWss4o!fK>vi*twcY{f807MN`W+P-Sn11hmC2T45RNQ1e6cqdfxb^|FV zDnK%uiy%oBY|DI;OuHqnf0EiB+u2!Maa4bO6%N!C@9dZtZ}fw{^vmaA#3~#4~6+#?Bu4t}qmdqsb&3M0Of! zIEixM61A?pEQ8EIbt{z<76Rv_`E+|4@9rP(P%o9ZKaNwGRy+%(IZZ8J*+CfevuMYP zw;xZ#P!^3a)LoW^W7$0LW2rTjXgU~1SW?b=h{80yD0qKs5ak9PO|3=IWk3VcLh$~U zY(cKrRGH++Al?atg9T`lTSM=%tYdGga1>{;5TfZgnuh)$$O0)(!pQ{FrEnMKv06$r z2}U8ehFfkS`16?$Cg>@x$8j(aI=iO9PM8;1<2DxY$JDzxvfqcH=nkG^Ms7P^m`B#D z#&a=6&R%%WQ!I;+>`_1}Yn_qHc1felBA0F+S7Nhy8YZr+{vWPejI=Lea9=0}8AS0( zIKwKUo3HJO&0?-BF|iE4cZqt)%Zg&}Q@zHY#2D3I97eXxlZ|^ri^@EUhBauZ9%k6% zw&0yA<~WgYXeH@kgLcJf5$nX`Xs|Yp={s0{=)sE*J*a3soOI*O2x^-J*b!^60Osp%A}Mtt$!R`>cAIqir8+mAPJR&@drt;t5w|?wEYC=pr44E_Kj&9 zz%seFwtE9#&Ub2oh24NEC#KpUHVAw1eA>s@JJG)8I2JlH&f4;V^(;|PE=TDM!Z(LQ zIYsbTkCW(fJk5e}i(y5E?Ptdll=JcXTii%_83rc$zzGGEj$AN!0yyA4Hh@1GUPLf* zpahd2iz?Z^8x5_7wIs@>*#(14HLnGK7-Q4PCQd@u&Jf=u&tdDFSyC7g7*en*8oke|(P@pV~Wfh8D1?9*oMuhz*de#EC z9b{1mqz!23maABGZ=PlFRP0Pq+jsIOop_|PWENcv zvEj(05@c&J^i8}R&wJz0QFM%9zz+5xW+M=K?4XWG)(TUhq+8JdW@QWMR=mpsG#O?v zwNN}Q9I+i6(uE6Lhv>sHW#U}M2YcKA7-g0?6sr`>_7i47nuTo4hQo0*bNJ5w!gM|u zg^NkZ{&CF145wq3S?!2W2MKC9)~>{AhPmCS+Zx1}Bz@Wh&H#qXh0rbU3Zes7(5)Es z`!F%kU<}-(_L$Uy-%H?h{8YfuouEO|N2opyhg8vUJWsK*0Bd z_OUuth#*ni&mgj2ZF=o?vu*q+4YCa3@K~3_uQeN|x=ox%NEmQJA-N#XC!&Y`3~j*; zD9kII0Ok3%6EegQ%++X|p-b*7h_Tn0(D@dDcc8z7I2Leerqnt7S1=XjVt}3=dCaIV zc9y^;E1cj|VOeC#5=1ako(dtmEVB94PPx;?L>LLthBsU7YNP96>iNndP?LzwM~=s! z3-a((gb4=;&I9h{Aeo5&7ZlR+EHDkfR<3TIH2SRA5~v$O20;-EP=WmQqyb%^KG|H0 z3fN1^s5n>atb@G*R4CH$Tg9^QQK(N)I~!}{u27$(t|52UC+k>h_?=R-b^fHWpyJA? zUKiq3Y?bPgqqn_ct+WY^+co6!ay65bd8(i@WGm%jx7hJc zF{`gmvlE-JP6m!FJiNc~Bl`<)$_u3vaF8^9L15}YVDeGIjKc?3W6Dh=4K31ltLgsn!=0t9e82HUrd60TnPlTUck&jcKUdS+h`vV8-78P zq*QMyl<}dGGacHn}P0z1X zYv@|8;=zPUHj+Eb5fg~NV?2czdo)7)0L2dx2w^%nPuyuMj^CRGI8_IwpudIbl$#B( zw0^(O4v5(=%}^uvGs0Ie>(B+a`x?713?}f{vcrd5>mghk`%dF*V^GZN|%Asv_wf=lCQv_%o!mbE+9Zdl)11psVf zVGwQX*wRjxn@>35Kan0@$8tx zG15a)1RqJ4-`~lGft;S=m1jaMu6Nd}6_|iuT(34tZPPz-U$Ij+r4t>)BcOd>NulZY zj9h7{HAQJ+@;oCRBl5&eShdqO*4S*y!SKz`%n+d(!0BeYyAFl|&D4y;9RypN(PPcF zz{m6?;=^JiaWMTkQZ}TtAv|mrBiqF<&*x@lQZock(?{A1hss^kH;G9zeDe%jIxsym zpAOK!+Q9K_c7m}9kAZOKUgQ1473C>&t9LINpI2+hdL?H{$hXVkA+9TQHIt z!vyBgFVbk21i)Vms8P~r%u#ZII_;sY{BUVN+EqvbQP~1Djyj(xtN_Qj%z&m`x~g5fLGabVo!q9N3E8Xpn80 ztx%j%67Qz1FzH|&utoS(MuKXG6ze@wDiCxGxJ@R!1lWaDTs&`(kXYX7R)l~$LQ;^J zM4lsg_T(waieOQWQa>Yupvpj$G6S(#6XHb^=n~rsrbHQ$GEZ?GaH$>6aGj{dHLMA4 zqLUp1&)M5C*!gG)H!zx+p6$XJ!nY&at@6%@cNp+4D6Y$V6z>KjA~>u%qGv!WPB*ql z1sBYQw|ww4qH-RMJ&ed~&T2tqG>?fsF(z7cC6gAnYun&6ph#FrF_MUxOKLYZv+AiP zarJF_qa-rO4DeE66q{a*j_Ef2lbld9Oy<1d^PHi7q6?JGcwWIdgS$Hf$!wuRYiq^N znQ6Fto{w{sM~U3ed7%ma%D$wW=YtH5rs#Gmu`JkmtDtkX(!u@1(Q!gR+Yg>Pfh%m0 zJFgnCjFetZM~hQ$gN`KqSeRXA2!LnS%2*ye4HE+BU0j;Hv`C}T6snP18thPdyxxFk z%x1OhHPK6;VFo&&p5t%>lY)IHzAFeFsg+Gk8f$(2&G?bQ%eR4O&T$D$wa=<`7%q++dRDo8Fo zQ)#xmhN&P}FPloo^T6a0nZzlt+cE22u~kF8q)HWo!@OkL#YP#2L3g87Z4z#-ZBz_r z-sl2$O2r01_YAvrJ&e<>w~$bqZnM^W1lg8yKW9ZfXGJWc+HeY`^>Ve1Cxk2NEQ?07 z;SJ+8E0{&2T&cD@2J)5o@EV&0n_j7Fs?AcjhNq^q)lRY7J#T6ql?&J#dx zoFJPXvkxL58PNnEMbq5qa^;Mug^waKq++81`3Wg3IIPv0r8Agov5QB$WI??pC5!_i zwE)oIu-$iY)Qv{1+BjqK>{IlCscv>FMJT`6rq0c}rot + entities each >r 2dup ( 0 x y x y r:e ) + r@ entity.x @ r@ entity.y @ world>tile 2= ( 0 x y eq r:e ) + if rot break ( e x y ) + else rdrop then ( 0 x y ) + more drop drop ; + +( P L A Y E R ) +var player.state userword +var player.prevdir + +1 const MOVING userword +2 const NOCLIP userword +4 const ISNEUT userword + +: noclip player.state NOCLIP fnot! ; userword + +: isneut? player.state ISNEUT f@ ; userword + +: {jaye} + isneut? not player.state MOVING f@ and + if {jeanne-walk} else {jeanne} then ; + +: player.canmove? ( x y -- ) + player.state NOCLIP f@ not if + isneut? if NEUTABLE else WALKABLE then mapflag? + else drop drop 1 then ; + +12 9 N ' {jaye} defentity pjaye +17 5 N ' {neut} defentity pneut + +: player isneut? if pneut else pjaye then ; + +: sched-move-entity ( entity -- ) :| jobdata move-entity |; sched-with ; +: move-player + :| 1 player.state MOVING f! + player move-entity + 0 player.state MOVING f! + |; sched + isneut? not if ( only jaye can have a party ) + player.prevdir @ party each + dup player != if + dup entity.dir @ >r + dup >rot entity.dir ! + sched-move-entity rot mapsize ( b x y w h ) + rot ( b b x w ) + >= or or ; + +: leaving? ( x y dir -- b ) + dup N = if drop swap drop 0 < else + dup W = if drop drop 0 < else + S = if swap drop mapsize swap drop >= else + drop mapsize drop >= then then then ; + +defer jaye-touch ( x y -- b ) +defer neut-touch ( x y -- b ) + +: player-touch isneut? if neut-touch else jaye-touch then ; + +: touch-begin each 2dup more >rot drop drop ; +: touch-next dup if rdrop done then drop rswap ; +: touch-last ' done , ; immediate +: ;touch [ ' touch-last , ' [ , ] ; immediate + +: check-player-touch ( x y -- b ) + touch-begin entity-at dup if EVTOUCH entity>do 1 then + touch-next player-touch + touch-next out-of-bounds + touch-next player.canmove? not ;touch + +: try-move-player + player entity-dst check-player-touch not if move-player then ; + +: follow ( e -- ) + player entity>pos do more + party each EVTICK entity>do more + pneut EVTICK entity>do + + tick-mapedit jiles + tick-debounce + q-level @ dup if + 0 q-level ! + reset-level + loadlevel + q-player.x @ q-player.y @ tile>world player entity.pos! + party each follow more + else drop then ; + +' mode-move MODE-MOVE ! +' tick-debounce MODE-WAIT ! + +: draw-entity + >r r@ entity.x @ r@ entity.y @ + r@ entity.dir @ sprite + sprite-bob draw-sprite ; + +var showmouse +1 showmouse ! +var glitchlevel + +: full-draw + player entity.x @ 152 - + player entity.y @ 92 - + scroll + + entities each draw-entity more + party each draw-entity more + pneut draw-entity + + showmouse @ if + mouseworldpos 4 draw-sprite + then + glitchlevel @ glitch + draw-screen + draw-footer ; + +:noname + reset-level + MODE-MOVE @ ' tick redefine + ' full-draw ' draw redefine + :| pjaye yield done |; ' party redefine + :| MODE-WAIT @ ' tick redefine |; ' any-job-started redefine + :| MODE-MOVE @ ' tick redefine hide-footer |; ' all-jobs-complete redefine +; ' onload redefine diff --git a/game.prj b/game.prj new file mode 100755 index 0000000000000000000000000000000000000000..b5590aa15c4022b4ecb2e7c0eed6c65837f82936 GIT binary patch literal 5721 zcmeI0NpKWp6vzKP-B}2PkcB|P)<8rEVFF<_MrATHNruekOrrrt1(E?-10f&?ghdvS zO(0yxIRw6x;Xjo`HbD2}~*n%dgVEyx0A{_rC9a zTlX02+ZMO#Zav)Ax;)<8uGcMF8P`jph|{vu2QirkX| zMHN6JGKfsx%Mz4i3tIXK^c(^D69b4`VxU0Dqcn)fCklu{qDY_&CW?t6yf>66Axep1 z#BhN!g3?HVI*O`Jb)v!?&2xypLV)>{77#JwDdK738Db%^h*(TC6D>rXSVAl%o)usj zrIo}gs;h}ss%wa~RNE-6qts5UCpPfjbCfnx+C)50Y$mn{aERDSwS(A3Y$tXQJBb$r z*hOhKv4`qj;zg?ah?j`{!~x56a;LYe5Ok9fm9XvosG_?jM=_1I+6>WO+;z#AApW7-70EEtMD=?d#*;YcVDHuN&L zD1m7Gcs8y|gb5p3m$m5S&St&G0s6@BGgIj>tTWfOZe4uU;+65cjYc*9XnLwKBE! zxtl4J_r4{v-Q0B&qJ526r1scji~mXr&zsyG|1W7}U^-4{zyoO7^mgzQ@sussB)JS< zz#EYxNLE@bDW?;t2!m0K{^G)k(vF%?$yne@Gw_2%pA(804T)GuIh|OAC_p}P#6>xp zrC+*y68J@1C0EoN@wxmGO!{?GP9xYrp^4b>&hNovneq`O4nLI3@YU5xsCs+6EIFM}5~ZJHFiU()!ajNRn3fCd9{@DU zCx_wld!vbdCFOL2^~V6@O5cF-SRpxVkr=y03(D14>ybz?t6#R9P9#`g!J1^!fifJB z9CjVACwv}nNTT&_(InOwd92 zsc|gC0%f6i&qg73$!yo4XUB@OEM{BGz&M#LdANGAB0LzKE04>}i4{AY@{6S89z!PUM^ zA~onbS}~%Jv`=>6yKjh|9Ho5C0%*GJx z-BJ^>yV2ijwB3yXmTWi6G(R5kR>HHn^Nm@-TWdzcSn!Tr$*liRTT zR3*QE1tfKLPHhX*lx0!PSOsX@cqrlDerAuA#G2#cpykWvRLu5KX{=?PfzV#&{Kw3wkGR4OK6jK=S)zU!9Z5j1lFBTC!B>c5y`wYcKtm z$G#Bz!p*{78h11Ggg6c}VaWC&uO*1!afA_)LoXmND~*@~9~w}PI(ShFH#~4*HXg&H Rcmy?xZMQ~hc3=2r{5J)9gk=B# literal 0 HcmV?d00001 diff --git a/gameboot.jor b/gameboot.jor new file mode 100755 index 0000000..c89bde0 --- /dev/null +++ b/gameboot.jor @@ -0,0 +1,35 @@ +: blah ' seremit task-emit ! ; +blah + +s" game.log" open seekend fdeactivate const LOGFILE +: emit-log ' fputc LOGFILE withfp ; +: atexit LOGFILE factivate close ; + +: start-repl activate blah ' emit-log task-echo ! + s" .:: J O R T H ( jean forth) ::." type cr + begin receive loadstring s" ok" type cr again ; +task const REPL +REPL start-repl + +defer tick +defer draw +defer loadlevel + +:noname +s" input.jor" loadfile +s" timer.jor" loadfile +s" entity.jor" loadfile +s" footer.jor" loadfile +s" map.jor" loadfile +s" state.jor" loadfile +s" jiles.jor" loadfile +s" job.jor" loadfile +s" game.jor" loadfile +; execute + +intern lev00001.jor + +:noname loadfile ; checkpoint _loadlevel +' _loadlevel ' loadlevel redefine + +lev00001.jor loadlevel diff --git a/input.jor b/input.jor new file mode 100755 index 0000000..95d7763 --- /dev/null +++ b/input.jor @@ -0,0 +1,33 @@ +( K E Y B O A R D ) +1 const ^ESC +15 const ^TAB +28 const ^ENTER +29 const ^CTRL +51 const ^< +52 const ^> +56 const ^ALT +57 const ^SPACE +72 const ^UP +75 const ^LEFT +77 const ^RIGHT +80 const ^DOWN + +: wait-key ( k -- ) begin dup key-pressed not while suspend repeat drop ; +: udelta ( u u -- u ) + 2dup u> if + swap -1 swap - + 1 + + else + swap - + then ; + +( M O U S E ) +var prevbutton +: tick-debounce + mousebuttons prevbutton ! ; + +1 const MOUSEL +2 const MOUSER +: mousedown ( button -- bool ) mousebuttons & ; +: clicked ( button -- bool ) + dup mousedown not swap + prevbutton @ & and ; diff --git a/jazzbass.sbi b/jazzbass.sbi new file mode 100755 index 0000000000000000000000000000000000000000..eefdfdf439ae32e6c351890c95b1eacad02fcf65 GIT binary patch literal 52 jcmWG`@|4O-tg1>%EG}li0TdJ+7^=TAl`t}JfmHwi_5MF>0R;)sd2tYMiMn(n(+$Ix}MK}n|0=kL~0)Q+uIgn9MNj5f+ zEQY=8Fo0c_gB=2~%i`Ayl;r`bz^a!S0kF6VA<2wI7AYPEjVwyCVq`?&3JC!K7Fr8v literal 0 HcmV?d00001 diff --git a/jiles.jor b/jiles.jor new file mode 100755 index 0000000..aaf5e39 --- /dev/null +++ b/jiles.jor @@ -0,0 +1,114 @@ +var lcolor 0x0f lcolor ! +var rcolor 0x10 rcolor ! +var spriteindex + +var refresh-needed +: refresh 1 refresh-needed ! ; + +array preview 128 allot + +: color! >r dup r@ @ = if drop else r@ ! refresh then rdrop ; + +: +sprite! spriteindex spritecount +!cycle spriteindex @ . refresh ; + +: draw-palette 0 0x11 for i 79 i 3 << drawfatbox next ; + +: draw-preview + 0 18 for + 0 edittarget = if + i preview tile>buf + spriteindex @ preview spr>buf + else + spriteindex @ preview tile>buf + then + i 3 % 2 * 65 + i 3 / 16 * preview paintbuf + next ; + +: mousecoord>sprcoord 2 edittarget = if 2 else 3 then >> ; +: mousepos>sprpos mousecoord>sprcoord swap mousecoord>sprcoord swap ; +: mousexys mousepos mousepos>sprpos spriteindex @ ; + +: mousepixel! ( color -- ) + >r mousexys getpixel r@ != if + r@ mousexys putpixel refresh + then rdrop ; + +: gfxfilename + 0 edittarget = if + s" sprite.gfx" + else 1 edittarget = if + NIGHT flag@ if + s" ntiles.gfx" + else + s" tiles.gfx" + then + else s" portrait.gfx" then then ; + +var jiles-old-tick +var jiles-old-draw + +44 const ^Z +45 const ^X +31 const ^S +20 const ^T +33 const ^F +19 const ^R +46 const ^C +47 const ^V +73 const ^PgUp +81 const ^PgDn + +var copysrc + +: jiles-tick + mousepos 128 < swap 128 < and if + MOUSEL mousedown if lcolor @ mousepixel! then + MOUSER mousedown if rcolor @ mousepixel! then + then + mousepos 136 < swap 312 >= and if + mousepos swap drop 3 >> dup + MOUSEL mousedown if lcolor color! else drop then + MOUSER mousedown if rcolor color! else drop then + then + ^LEFT key-pressed if -1 +sprite! then + ^RIGHT key-pressed if 1 +sprite! then + ^Z key-pressed if mousexys getpixel lcolor color! then + ^X key-pressed if mousexys getpixel rcolor color! then + ^S key-pressed if s" SAVING " type gfxfilename dup type cr savegfx then + ^T key-pressed if edittarget 1 + 3 % edittarget! 0 +sprite! then + ^C key-pressed if spriteindex @ copysrc ! then + ^V key-pressed if copysrc @ spriteindex @ paste-tile refresh then + ^F key-pressed if spriteindex @ flip-tile refresh then + ^R key-pressed if spriteindex @ vflip-tile refresh then + ^PgDn key-pressed if 5 +sprite! then + ^PgUp key-pressed if -5 +sprite! then + ^UP key-pressed if -1 spriteindex @ nudge-sprite refresh then + ^DOWN key-pressed if 1 spriteindex @ nudge-sprite refresh then + ^TAB key-pressed if + jiles-old-draw @ ' draw redefine + jiles-old-tick @ ' tick redefine + mousehide unfuck invalidate-map reloadtiles reloadportraits load-footer + then + tick-debounce +; + +: jiles-draw + refresh-needed @ if + mousehide + draw-preview + spriteindex @ drawfatsprite + lcolor @ 77 0 drawfatbox + rcolor @ 78 0 drawfatbox + draw-palette + mouseshow + 0 refresh-needed ! + then ; + +: jiles + ^TAB key-pressed if + ' draw definition jiles-old-draw ! + ' tick definition jiles-old-tick ! + ' jiles-draw ' draw redefine + ' jiles-tick ' tick redefine + fuck mouseshow refresh + then ; diff --git a/job.jor b/job.jor new file mode 100755 index 0000000..20c7457 --- /dev/null +++ b/job.jor @@ -0,0 +1,86 @@ +defer any-job-started +defer all-jobs-complete + +var JOBSTATE +array JOBTASKS 4 cells allot +array JOBS 8 cells allot +array JOBDATA 8 cells allot + +: by-jobid ( jobid p -- p ) swap 1 - cells + ; + +: jobdata ( jobid -- jobid data ) dup JOBDATA by-jobid @ ; +: jobdata! ( data jobid -- ) JOBDATA by-jobid ! ; + +: ijobtask-running ( -- i ) + 0 0 4 for JOBTASKS i cells + @ running = if drop i then next ; + +: jobtask-busy-flag ( ijobtask -- v f ) + 1 swap << JOBSTATE swap ; + +: job-scheduled-flag ( jobid -- v f ) + 0x08 swap << JOBSTATE swap ; + +: next-matching-jobid ( matcher -- jobid ) + 0 1 9 for dup not if + over i swap execute if drop i then + then next swap drop ; + +: job-unscheduled+xp ( jobid -- b xp ) + dup job-scheduled-flag f@ not + swap JOBS by-jobid @ ; + +: next-unused-jobid ( -- jobid ) + :| job-unscheduled+xp not and |; next-matching-jobid ; + +: next-waiting-jobid ( -- jobid ) + :| job-unscheduled+xp and |; next-matching-jobid ; + +: on-job-complete ( jobid -- ) + 0 swap job-scheduled-flag f! + next-waiting-jobid dup if + dup running send + 1 swap job-scheduled-flag f! + else + ( 0 ) ijobtask-running jobtask-busy-flag f! + JOBSTATE @ not if all-jobs-complete then + then ; + +: listen-for-jobs activate blah + begin receive ( jobid ) + any-job-started + dup JOBS by-jobid 0 swap @! + execute + on-job-complete + again ; + +: start-jobtask ( i -- ) + task dup listen-for-jobs swap cells JOBTASKS + ! ; + +: next-free-job-task ( -- task ) + 0 0 4 for dup not if + JOBSTATE 1 i << f@ not if + drop JOBTASKS i cells + @ + then + then next ; + +: enqueue-job ( xp -- jobid ) + next-unused-jobid dup if + dup >rot 1 - cells JOBS + ! + else swap drop then ; + +: try-run-job ( jobid -- ) + 0 4 for i jobtask-busy-flag f@ not if + 1 i jobtask-busy-flag f! + 1 over job-scheduled-flag f! + JOBTASKS i cells + @ send breakfor + then next ; + +: sched ( xp -- ) enqueue-job try-run-job ; +: sched-with ( data xp -- ) enqueue-job dup >rot jobdata! try-run-job ; + +:noname +0 start-jobtask +1 start-jobtask +2 start-jobtask +3 start-jobtask +; ' onload redefine diff --git a/jopl.c b/jopl.c new file mode 100755 index 0000000..585363e --- /dev/null +++ b/jopl.c @@ -0,0 +1,158 @@ +#include +#include +#include +#include "jorth.h" +#include "adlib.h" +#include "kbd.h" +#include "timer.h" +#include "serial.h" + +cell ontick = 0; +void f_adlib_read() { + PUSHU(adlib_read()); +} + +void f_adlib_write() { + adlib_write(TOP().u & 0xff, ST1().u & 0xff); + DROP(2); +} + +volatile int WAKE = 0; +static void timer_callback() { + if (adlib_read() & 0x20) { + WAKE = 1; + } +} + +int DONE = 0; +static void f_quit() { + DONE = 1; +} + +void f_keyWasPressed() { + int k = TOP().i; + TOP().i = keyWasPressed(k); + consumeKey(k); +} + +void f_keydown() { + TOP().i = keyIsDown(TOP().i); +} + +char *gather_input() { + static char buf[128]; + static int ibuf = 0; + + if (bioskey(1)) { + int key = bioskey(0); + char ch = key & 0xff; + if (ch == 0x08) { + if (ibuf > 0) { + printf("%c %c", ch, ch); + ibuf --; + } + } else { + buf[ibuf] = ch; + ibuf ++; + if (ch == 0x0d) { + printf("\n"); + buf[ibuf] = 0; + ibuf = 0; + return buf; + } else { + printf("%c", ch); + } + } + } + return NULL; +} + +void f_seremit() { + ser_write_byte(TOP().i); + if (TOP().i == '\n') { + ser_write_byte('\r'); + } + DROP(1); +} + +void f_random() { + TOP().i = random(TOP().i); +} + +void do_repl(char *exe) { + adlib_init(); + + timer_init(TIMER_18HZ); + f_init(exe); + + ser_init(SER_COM2, BAUD_19200, SER_8N1); + CDEF("seremit", f_seremit); + CDEF("_quit", f_quit); + CDEF("adlib!", f_adlib_write); + CDEF("adlib@", f_adlib_read); + CDEF("key-start", kbd_init); + CDEF("key-end", kbd_cleanup); + CDEF("key-debounce", kbd_debounce); + CDEF("key-pressed", f_keyWasPressed); + CDEF("key-down", f_keydown); + CDEF("rnd", f_random); + f_loadfile("jopl.jor"); + ontick = f_lookupcp("ontick"); + timer_setcallback(timer_callback); + + f_taskloop(); + + while (!DONE) { + char *buf = gather_input(); + if (buf) { + PUSHS(buf); + f_runstring("REPL send"); + } + if (WAKE) { + WAKE = 0; + if (ontick.p != NULL) { + f_execcp(ontick); + } + } + f_taskloop(); + } +} + +#define RIGHT 0x01 +#define LEFT 0x02 +#define CTRL 0x04 +#define ALT 0x08 + +void keything() { + int key, modifiers, done; + done = 0; + while (!done) { + /* function 1 returns 0 until a key is pressed */ + while (bioskey(1) == 0); + + /* function 0 returns the key that is waiting */ + key = bioskey(0); + + /* use function 2 to determine if shift keys were used */ + modifiers = bioskey(2); + if (modifiers) + { + printf("[%#02x", modifiers); + if (modifiers & RIGHT) printf(" RIGHT"); + if (modifiers & LEFT) printf(" LEFT"); + if (modifiers & CTRL) printf(" CTRL"); + if (modifiers & ALT) printf(" ALT"); + printf("]"); + } + /* print out the character read */ + printf("'%c' %#02x\n", key & 0xff, key); + if ((key & 0xff) == 'q') done = 1; + + } +} +int main(int argc, char *argv[]) { +// keything(); + randomize(); + do_repl(argv[0]); + return 0; +} \ No newline at end of file diff --git a/jopl.exe b/jopl.exe new file mode 100755 index 0000000000000000000000000000000000000000..97c6696feee73fcd7b0b0564ff2d8de73ae57d94 GIT binary patch literal 68278 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⪻Alat(kzVwwBP<3nI_=Ro z-oVhLoKIzlyXk;RGQme<#}OyC?CBsUQpr;|6+*E~^fzeSkn`?H7M8*tIe3)YR|OF^6U+!w~*aP0w__XmQOz_o;XHAB;!SLj zZkA#cf%;QjODqqNvTJCSu8s%K!_3sojJx^jt-(v#cE2?;pg`H`x0zhk{pl;F%9%Tk zyQI#1erTOpjn1V##>U5x3Fw)5=cHFA2A8DOB)#)%{uonJQcLHXBxO(nl~*{{hD0W2%z1RU@_K z<~ms>+hNBhcdqGG)O6>yJo`&RbPAZv{jF2svgjYI8I!sX<6P?3+v!K&3rEQJD$?+#bDj#_6YN$yy>JD{H}^42UQu(Rll*glBOuby8IJ+ zBG}arcA(lXC(UsLq2eQU6fvA-HNZr@yvM-xJb3Ik<6|dwVAHEl(rkNd(m=;A_eQSx z*$KzV9sT#)f72X2`jzWP1|iSaj%(5nRj)I&N~N60nKzeTH>KxU0x~!G75)rTxkRZP zI`-S@M^C)6(T-(>9AP&~SZ&}lSP6b$yR`3iJ>UnE>Yh?P^(Yc4WL1+wQs?9xdNAOj zJD72*`mmV8in@tm?ro~V)vy-5GrxTcz1x4Yx%O%0U+fJw>C3oddvpx-kT-711Ghrh zW}vQydcMiKyHIpq9Gu88s2 zT{n7Toq0o(-7jgd<1y!r2*&~vA971PX{G&vqzCQyOF1};$C{CjKn!Do{iZ%Uy)3&)Gst?YuYzD z22jXJw?ZmX-+4CX{4Di(6WJ+wXg|-3bRy=|b~j0%W&B_C(9f@jt%e%$IS5 z?p+)6`QiMWChiU%R{xwv_Z?CcT34}LpfSt%9WyLzQ9Nveob*pC)}lDFenR4S}N zB_F)<0p?D;f3Wcb-h2s9%?B@ju)+V2HkrNaI%`G~3`R`BKMpCuYN7VSb@)nazFvX# z6>&G#)YGj9yXGCT5XqX{;5Fb>Tac{3lVtqWdxO_kpzYA=p)f@*oGr(d-Yy;>nye|Z6kFo`;o#RWh3p0ahu-99SB?DIIg8Tt#F*CrF(?)DeXXed%VZl!wSdICS2W` zC&p>)F{+~wj!o~wn7XfUoX#H*?z_tM;b|O>`%P&UbGbe=4L70Mr{Sx9`ZN(gQ)Ux7 zlEauLUVx+OGyK$@x(i3t>T9rZ=(Vr5;8{_L4bq7G zHss|9=AXYX-nGvl>Gg3KxLI*idx~~t7V5O6_&RU=vCj;w z{%YJoSglF~;fecJL^(P;^G%xU_EKo#zHFl-1TOpvAUY0B_}CdR(#ox9w7Rk6-G>@= zWp-&{8J4nz`@fHP_8h>o=X5XhjZE&lokrtT)vsXVv)p`%E^t;`@OA+TFlV4S4=GU= z;&V$AaD~8=UhTMxE*`IY_E9;mf!I0ZoV^;PNl6+xw_Y*Mwny5_IRI z!@>~NlOfs;hG<)Fgawzx9kNtabxG^at=R#OKOh?ajXS;8o$gtie!bk>Amern3`>dI zG2~bND1Xw4OEEVe%4uKtX0J5Y&5p1vx2Tq7iM8rgt+Sb}XmF)_IO!{FoS!1T9 zR7J%({wN(1X!mpGhN^fa>|fWI>(JjnY3Wy2)lo(o5mlM;s&o$ys26%JSJ~uGjgsk8 z6P}2Vt2C#}%-7jk>&^IMYpsoHE~SW1O=Y-P2393Dr>45G%rtv&3LlifcYrfrw=VxP z)YM(r6FSAUnD#mW;x3 zx?tI8nJQ*pjxylvD&$y!w(1J2YNEU#v32>yXvhiju(4y^xTj&p4;R@Z68MgaGs+=M-FswX>k?#TDP^f(0rX5Ig$2I*RooizSOeGebxqvJDT`<()gSPA&8P1 z8N?jz3m4vWHf1@&T=})E0G+57UAe2XX(g_4H9d%*hD!G&Pn?KoG*6KyW7_muWB^Sy zRMPK^5i^@6CY~y&1BE@dke!3YX_!!Nia39;)*^d-;||81?o+5s8fZ5r#lT#Na~S&U z5btVAo4Dp+r2+E2o6g?=Y!`Q`&kkRw)QTOO&ew$elpo9=LK+-Iszx_Kb7)(t%0v7r zmkeHoV~?S~xms(!)W;nJA+$R~YHFYIAgnbs==wD%`OaAJlbaX<91YI=YRgkvapz5g zEB^voC@dB_nz*D)@fgI~OuaEBWvXs!_SAx@UraqP^_!^!r`AqAI`#XhC#No()@AzM zX=kQQv%aAG>pnGhDuyw%J?~kK(cYdeHhX`i0*h=|oCl0W$&gTXfN7hp4V_I^RIZ{$ zcf^CVRnVz=c4_hIG)Y_RPTLd2yuXyXr!OmBpGG@4RR_1*!XJqLMvB4*-OUT9PZ(Bu z`qZ-N*k7pTZ(t9Nx8l-PIG-L7@{Pk7a?HLs2*&!=*iC43O;;wdWPCoy~%=%Kg^U0U-KUPTf zrF69KjSUvdK_jM%`f>o8-1^K;i1o-LjVwn?eR|Yx zoKbh@A&hDXJv{pu8Rwq)I%&}Qa7<140>!ix5vJ2nQ_FhoGS4#SvK%A zF+(GC28m0=zs;N(3p+EIwnoK|;Cj#!|I<{9_%0x>;MgPilWvsX4TV0Kj31^d)$ygJ zGviATp2P~gVp06bEkc?*Rdc)GgAnXz;IC?j@g8jh?#Vzi(3`7F$Cs7z)l)4G;EPW3 zO#UQ_*&T*7Zm#0yaVY$)uBsrie6foq_V&!g?iehhQhvW{zcI05#ZbP2s@T!SZIBJx zQe@=&UuVvgqWPQJ2KQ`D+|hm=Q4h85Jk1z)2mTO$RvhNxPa*SAtJ2S~KZzONJ`DOB zh!(@QN#l>=YbLJqxb0`m(H0w7;=%0D6+s9h8F5^PdY&xvr4p|0W_l$3RPhCDY0kuv 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 literal 0 HcmV?d00001 diff --git a/jopl.jor b/jopl.jor new file mode 100755 index 0000000..9b8ff8f --- /dev/null +++ b/jopl.jor @@ -0,0 +1,371 @@ +' putc task-emit ! +s" jopl.log" open seekend fdeactivate const LOGFILE +: emit-log fdeactivate LOGFILE factivate fputc fdeactivate drop factivate ; +: quit LOGFILE factivate close _quit ; + +: DBG :| ' seremit task-emit ! execute cr |; 0 task-emit preserving ; +: DTYPE ' type DBG ; + +: start-repl activate + ' putc task-emit ! ' emit-log task-echo ! + s" .:: J O P L ( jean OPL2 print loop) ::." type cr + begin receive loadstring s" ok" type cr again ; +task const REPL +REPL start-repl + +var voice +var op + +: +voice! voice @ + 10 % voice ! ; + +: op-with-voice voice @ + dup 5 > if 5 + then + dup 2 > if 5 + then + + op @ + ; +: opreg create b, does> ub@ op-with-voice ; +: voicereg create b, does> ub@ voice @ + ; + +0x20 opreg ar-flags +0x40 opreg ar-level +0x60 opreg ar-ad +0x80 opreg ar-sr +0xe0 opreg ar-wave +0xc0 voicereg ar-alg + +0xa0 voicereg ar-freq +0xb0 voicereg ar-note + +: op2 3 op ! ; +: op1 0 op ! ; +: loadop ( flags level ad sr wave -- ) + ar-wave adlib! + ar-sr adlib! + ar-ad adlib! + ar-level adlib! + ar-flags adlib! ; + +: readop ( v -- ) + >r r@ 4 + b@ r@ 3 + b@ r@ 2 + b@ r@ 1 + b@ + dup dup 5 + op1 readop op2 readop + 10 + b@ ar-alg adlib! ; + +0 0x01 0x10 0xf0 0x77 0 0x01 0x00 0xf0 0x77 0 instrument default + +: freqon ( oct freq -- ) + dup 0xff & ar-freq adlib! + 8 >> 0x03 & swap 2 << | 0x20 | ar-note adlib! ; +: noteoff ( -- ) 0 ar-note adlib! ; userword + +array semitones +3520 3520 />ratio , +3729 3520 />ratio , +3951 3520 />ratio , +4186 3520 />ratio , +4435 3520 />ratio , +4699 3520 />ratio , +4978 3520 />ratio , +5274 3520 />ratio , +5588 3520 />ratio , +5920 3520 />ratio , +6272 3520 />ratio , +6645 3520 />ratio , + +: note dup 12 / 8 % swap 12 % cells semitones + @ 440 swap * ub@ oct+ notestate @ if b, else noteon rest then ; +: %loop 0xfe b, , ; userword +: mod % ; +: % notestate @ if 0xf0 b, else rest then ; userword +: %% 0 for % next ; userword +: %- notestate @ if 0xfd b, else noteoff then ; userword +: %do 0xff b, , ; userword + +11 mknote G# userword +10 mknote G userword +9 mknote F# userword +8 mknote F userword +7 mknote E userword +6 mknote D# userword +5 mknote D userword +4 mknote C# userword +3 mknote C userword +2 mknote B userword +1 mknote A# userword +0 mknote A userword + +array tracks 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , + +: track ( i -- p ) cells tracks + ; +: dotrack ( ip -- ip ) + dup if dup 1 + swap ub@ >r + r@ 0xff = if dup @ swap cell + swap execute then + r@ 0xfe = if @ dotrack then + r@ 0xfd = if noteoff then + r@ 0xf0 < if r@ noteon then + rdrop then ; + +: track-tick ( i -- ) + track dup @ dotrack swap ! ; + +: :track create here 1 notestate ! does> voice @ track ! ; userword +: ;track %loop 0 notestate ! ; userword +: shush 0 voice @ track ! %- ; userword + +: prev-name ( wordname -- wordname ) + 2 cells - @ 2 cells + ; +: 'name [ ' [ , ' ' , ' ] , ] ` lit ; immediate + +: emit-octave ( note -- ) + 12 / dup octave @ != if dup octave ! . s" %O " type else drop then ; + +: emit-note ( note -- ) + 'name A swap 12 mod 0 for prev-name next type bl ; + +: emit-cmd ( cmd -- more ) + dup 0xf0 = if s" % " type then + dup 0xfd = if s" %- " type then + dup 0xf0 < if dup emit-octave emit-note 1 then + dup 0xfe = if 'name ;track type cr drop 0 then ; + +: emit-track ( 'track -- ) + -1 octave ! dup ` swap 2 cells + + 'name :track type bl swap type bl + begin dup ub@ emit-cmd while 1 + repeat drop ; userword + +( T E X T ) + +var textx +var texty +var textattr +var textleft +0x1f textattr ! + +: out-direct ( c -- ) + textattr @ 8 << | + texty @ 160 * textx @ 1 << + + 0xb800 !far ; + +: setattr-to ( w -- ) + texty @ 80 * textx @ + + dup rot + for dup i 1 << 1 + 0xb800 b!far next drop ; + +: clearline + textattr @ 8 << + texty @ 80 * textx @ + + texty @ 1 + 80 * + for dup i 1 << 0xb800 !far next drop ; + +: +textx! ( n -- ) + textx @ + dup 80 >= if drop cr else textx ! then ; +: emit-direct ( c -- ) + dup '\n' = if textleft @ textx ! 1 texty +! drop else + dup '\r' = if drop else + out-direct 1 +textx! then then ; + +: rpad ( n -- ) + textleft @ + textx @ for bl next ; + +: read-direct ( x y -- s ) + 80 * + here swap + begin dup 1 << 0xb800 b@far dup sp != while b, 1 + repeat + 0 b, drop drop dup here! ; + +: status + 0 textx ! 0 texty ! 0 textleft ! + s" V: " type voice @ . + s" O: " type octave @ . + s" T: " type songticks @ . + clearline ; + +: emit-status-cmd ( ip -- ip ) + dup ub@ swap 1 + swap + dup 0xf0 = if s" % " type then + dup 0xfd = if s" - " type then + dup 0xf0 < if dup emit-note then + dup 0xfe = if + 16 textattr +! + swap @ emit-status-cmd swap + -16 textattr +! + then drop ; + +: showtrack ( n -- ) + dup . s" : " type + track @ dup if 20 0 for emit-status-cmd next then drop + clearline ; + +: trackstatus cr voice @ showtrack ; + +var tempo userword 1 tempo ! +: player + 1 songticks +! + songticks @ tempo @ mod 0 = if + voice @ + 0 10 for i voice ! i track-tick next + voice ! + then ; + +var t2 +: startt2 + 0x60 0x04 adlib! + 0x80 0x04 adlib! + t2 @ 0x03 adlib! + 0x42 0x04 adlib! ; + +: ontick startt2 player ' status 0 textleft textx texty preserving ( trackstatus ) ; + +: keynote [ inline| +44 b, 31 b, 45 b, 32 b, 46 b, 47 b, 34 b, 48 b, 35 b, 49 b, 36 b, 50 b, +16 b, 3 b, 17 b, 4 b, 18 b, 19 b, 6 b, 20 b, 7 b, 21 b, 8 b, 22 b, +23 b, 10 b, 24 b, 11 b, 25 b, +|inline ] 0 29 for dup i + ub@ key-pressed if drop i 3 + rdrop rdrop ret then next + drop 51 key-pressed if 15 else 0 then ; userword + +: onkeynote ( cp -- ) keynote dup if oct+ swap execute else drop drop then ; + +var stopkeys +: stoponesc 1 key-pressed if 1 stopkeys ! then ; +: voicekeys + 78 key-pressed if 1 octave +! then + 74 key-pressed if -1 octave +! then + 75 key-pressed if -1 +voice! then + 77 key-pressed if 1 +voice! then ; + +: dokeys ( cp -- ) + >r 0 stopkeys ! key-start begin + key-debounce r@ execute suspend + stopkeys @ until key-end rdrop ; + +: nextnote ( ip -- ip ) + dup if + dup ub@ >r + r@ 0xff = if drop 0 else + r@ 0xfe = if 1 + @ nextnote then then + rdrop + then ; + +: setnote ( note -- ) + voice @ track @ nextnote + dup if b! else drop drop then ; + +: record + 0x4f textattr ! + :| stoponesc voicekeys + ' setnote onkeynote + 41 key-pressed if 0xfd setnote then + 52 key-down if 0xf0 setnote then + |; dokeys + 0x1f textattr ! ; userword + +: jamkeys + stoponesc voicekeys + ' noteon onkeynote + 41 key-pressed if noteoff then + 88 key-pressed if rndinst then ; + +: jam ' jamkeys dokeys ; userword + +var menuscroll +var menuy +var menuw + +defer onselect + +: menu-at ( cp x y w -- ) + :| menuw ! texty ! dup textx ! textleft ! ' emit-direct task-emit ! + 0 menuscroll ! 0 menuy ! + execute ' noop ' onselect redefine |; + 0 textleft task-emit preserving ; + +: menu-lines ( -- count ) 24 texty @ - ; +: menu-skip menuscroll @ 0 max ; +: menu-selectedy menuy @ menu-skip - texty @ + ; + +: menuitem-bg ( attr -- ) + :| menu-selectedy texty ! + textleft @ textx ! + textattr ! menuw @ setattr-to |; + 0 texty textx textattr preserving ; + +: deselect-menu ( -- ) 0x1f menuitem-bg ; +: select-menu ( -- ) 0x30 menuitem-bg ; + +: selected-text textx @ menu-selectedy read-direct ; + +: draw-menu ( cp -- ) 0 texty textattr preserving select-menu ; + +: change-selection ( dy -- ) + deselect-menu menuy +!pos select-menu onselect ; + +: page-selection ( redraw dy -- 1 ) + dup menuscroll +!pos menuy +!pos drop 1 ; + +: key-menu ( -- redraw ) + :| + 0 ( redraw ) + 72 key-pressed if -1 change-selection then + 80 key-pressed if 1 change-selection then + 73 key-pressed if -10 page-selection then + 81 key-pressed if 10 page-selection then + |; draw-menu ; + +: draw-filemenu ( glob -- ) + :| findfile + menu-skip 0 for drop nextfile next + menu-lines 0 for dup if type else drop then 13 rpad cr nextfile next + drop |; draw-menu ; + +: inst ( -- ) + :| selected-text loadsbi |; ' onselect redefine + :| s" *.sbi" draw-filemenu + :| jamkeys + key-menu if s" *.sbi" draw-filemenu then + 28 key-pressed if 1 stopkeys ! then + |; dokeys + |; 66 1 13 menu-at ; userword + +: dune ( -- ) s" dune" chdir inst s" .." chdir ; userword + +:noname + 9 -1 for i voice ! default next + startt2 + ' emit-direct task-emit ! +; ' onload redefine diff --git a/jopl.prj b/jopl.prj new file mode 100755 index 0000000000000000000000000000000000000000..d34877d3ed1d7bf33d22e6feb70fd0c0e342c78a GIT binary patch literal 4609 zcmeH~+f!Rr6vo#M2?PjGkV1>Ko`+1QEfOw;(9$~7kVHr!mr3GCG2VcbVrijVYEcV_ zt=6h&wNKWW&h)VkFP-}8gHQJ2rPc9C`v>@DtJWE<$L~8QpwwWP;NXnoo}AyTwX@b) zYp=b}IeW*)M|y@duND~@dN$cRradw+nAEC76_r)0Dv`Vfxof*D7Ey8q6uD~1*9?AY z^n7N>pM$#og~96vZy5bw8vF{(k*~qs@;&Y)w}{)s4}kiS(oe)4;uqpqK;5PE8=(`T z(1#`}2M{Y^BXZf72duXPeffY^07xO>Ac}}$K$TEhLzEI_#C=3Lpw?2VAS#J<#CoEN zxS!Yns0S!*1acmvs!^?0tkGTz^aFr&Q+k|85KjF9N6VDJmL@&`tB#C`QKd~Q> z0ZN0!L8^y{A*#c~VX7mPMk$REH+8bs=qO&XdIzX3vhU7g4_HMRQbERNWyHp!6FZrq|dL*dwCo`~j*M8m;ITyuJ%1Y>QRnOp;eEk}k1 z`n0XCUTxU{R>|-aT}{S~Z?0!_GWnIh)PWqBP1tP z9^5M>I(aG7C9fL@gC`L>*NBq9ycJmP{(uV*%OX1l2OByyn;wL5=x1z!O2vn z-7;svnO9C*j$8IyK2$exbbHvc!BS$Gky-V=vRcl`9rc~Mpf;)N>Xv*Y-O7zkk{dn_ z%(xAi+C;M_DoP9%8Z3~Xk6jAc4Y^!ASm{>AS;yBAN4ou)lEK!|G44*PP#veI4 zyU54POV{DU1WU2N3?C}-0Da1&;~pP#M1~KCR*We$e5iD^(kD+gjbBW~$v3KCW@uK; ztQ4w%+{_}RQZyD92G4;lEH9nm&4(y`ReXUcE5?eO?+_?#sYRokL*YY$KREvRr$jds z_OYLHXTBAnq@9`A-dG|Q_r(8hb^>Ak%dyYDVbb5r7mm>|xR5e;;Z{5d19KCpWuxog yC^`SFF`{PKCFQW#DJ`-?wo9|PrAZpGXK#>tsgqi~2x{aZsm38J-7$<`u-^geah +#include +#include +#include +#include "jorth.h" + +#define TASK_REGISTER_SIZE 3 +#define TASK_USER_SIZE 8 +#define TASK_HEADER_SIZE (TASK_USER_SIZE + TASK_REGISTER_SIZE) +#define TASK_SIZE (TASK_HEADER_SIZE + STACK_SIZE + RSTACK_SIZE) +#define STACK_OFFSET (TASK_HEADER_SIZE) +#define RSTACK_OFFSET (TASK_HEADER_SIZE + STACK_SIZE) + +#define TASK_USER_NEXT 0 +#define TASK_USER_STATE 1 +#define TASK_USER_MAILBOX 2 +#define TASK_USER_QUIET 3 +#define TASK_USER_KEY 4 +#define TASK_USER_KEYSRC 5 +#define TASK_USER_ECHO 6 +#define TASK_USER_EMIT 7 + +char mem[MEM_SIZE] = { 0 }; +cell *HERE = ((cell*)mem) + TASK_SIZE; +cell *LATEST = NULL; +cell IP = NULL; +cell W = NULL; +#define STATE (*(RUNNING + TASK_USER_STATE)) +cell *RUNNING = (cell*)mem; +cell *TASKS = (cell*)mem; +cell *stack = ((cell*)mem) + STACK_OFFSET; +cell *rstack = ((cell*)mem) + RSTACK_OFFSET; +#ifdef TRACE +int TRACING = 0; +#endif + +#define QUIET (*(RUNNING + TASK_USER_QUIET)) + +FILE *ACTIVE_FILE = NULL; + +void DROP(n) { + stack -= n; + if (stack < RUNNING + STACK_OFFSET) { + stack = RUNNING + STACK_OFFSET; + PUSHS("underflow!\n"); + f_puts(); + } +} + +void PUSHC(cell c) { *stack = c; stack++; } +void PUSHI(int i) { stack->i = i; stack++; } +void PUSHU(unsigned int u) { stack->u = u; stack++; } +void PUSHCP(cell *c) { stack->p = c; stack++; } +void PUSHS(char *s) { stack->s = s; stack++; } +void RPUSH(cell c) { *rstack = c; rstack++; } + +void f_here() { + PUSHCP(HERE); +} + +void f_here_set() { + HERE = TOP().p; + DROP(1); +} +void f_latest() { + PUSHCP(LATEST); +} + +void f_latest_set() { + LATEST = TOP().p; + DROP(1); +} + +void f_tasks() { + PUSHCP(TASKS); +} + +void f_tasks_set() { + TASKS = TOP().p; + DROP(1); +} + +void f_state() { + PUSHC(STATE); +} + +void f_running() { + PUSHCP(RUNNING); +} + +#define BINOP(name, type, op) \ + void name() { \ + cell r = TOP(); \ + DROP(1); \ + TOP().type = TOP().type op r.type; \ + } + +BINOP(f_add, i, +) +BINOP(f_sub, i, -) +BINOP(f_mul, i, *) +BINOP(f_div, i, /) +BINOP(f_mod, u, %) +BINOP(f_eq, i, ==) +BINOP(f_neq, i, !=) +BINOP(f_ge, i, >=) +BINOP(f_gt, i, >) +BINOP(f_lt, i, <) +BINOP(f_le, i, <=) +BINOP(f_uge, u, >=) +BINOP(f_ugt, u, >) +BINOP(f_ult, u, <) +BINOP(f_ule, u, <=) +BINOP(f_and, u, &&) +BINOP(f_or, u, ||) +BINOP(f_bitand, u, &) +BINOP(f_bitor, u, |) +BINOP(f_bitxor, u, ^) +BINOP(f_shr, u, >>) +BINOP(f_shl, u, <<) + +#define RATIO_FRACTIONAL_BITS 14 + +void f_toratio() { // a/b ( a b -- r ) + ST1().i = ((long)ST1().i * (1 << RATIO_FRACTIONAL_BITS)) / TOP().i; + DROP(1); +} + +void f_fromratio() { // a*r ( a r -- b ) + ST1().i = ((long)ST1().i * (long)TOP().i) / (1 << RATIO_FRACTIONAL_BITS); + DROP(1); +} + +void f_eq0() { + TOP().i = (TOP().i == 0); +} +void f_not() { + TOP().i = !TOP().i; +} + +void f_get() { + TOP() = (*(TOP().p)); +} + +void f_set() { + cell *p = TOP().p; + DROP(1); + (*p) = TOP(); + DROP(1); +} + +void f_bget() { + TOP().i = *((char*)TOP().p); +} + +void f_ubget() { + TOP().u = *((unsigned char*)TOP().p); +} + +void f_bset() { + char *p = (char*)TOP().p; + DROP(1); + (*p) = TOP().i; + DROP(1); +} + +void f_farset() { + *((cell far *)MK_FP(TOP().u, ST1().u)) = ST2(); + DROP(3); +} + +void f_farget() { + ST1() = *((cell far *)MK_FP(TOP().u, ST1().u)); + DROP(1); +} + +void f_farbset() { + *((char far *)MK_FP(TOP().u, ST1().u)) = ST2().i; + DROP(3); +} + +void f_farbget() { + ST1().i = *((char far *)MK_FP(TOP().u, ST1().u)); + DROP(1); +} + +void f_addset() { + TOP().p->i += ST1().i; + DROP(2); +} + +void f_drop() { + DROP(1); +} + +void f_dup() { + PUSHC(TOP()); +} + +void f_over() { + PUSHC(ST1()); +} + +void f_swap() { + cell top = TOP(); + cell st1 = ST1(); + TOP() = st1; + ST1() = top; +} + +void f_rot() { // a b c -- b c a + cell c = TOP(); + cell b = ST1(); + cell a = ST2(); + TOP() = a; + ST1() = c; + ST2() = b; +} + +void f_rput() { + RPUSH(TOP()); + DROP(1); +} + +void f_rtake() { + PUSHC(*RPOP()); +} + +void f_rtop() { + PUSHC(*(rstack - 1)); +} + +void f_rdrop() { + RPOP(); +} + +void f_rswap() { + cell top = *(rstack - 1); + cell under = *(rstack - 2); + *(rstack - 1) = under; + *(rstack - 2) = top; +} + +void f_cexecute(); + +void f_key_string() { + cell *INPUT = RUNNING + TASK_USER_KEYSRC; + if (INPUT->p) { + PUSHCP(INPUT->p); + f_bget(); + if (TOP().i != 0) { + INPUT->p = CELL_OFFSET(INPUT->p, 1); + } else { + INPUT->p = NULL; + } + } else { + PUSHI(0); + } +} + +void f_key_file() { + cell *INPUT = RUNNING + TASK_USER_KEYSRC; + int val = 0; + if (INPUT->fp) { + val = fgetc(INPUT->fp); + if (val == EOF) { + fclose(INPUT->fp); + INPUT->fp = NULL; + val = 0; + } + } + PUSHI(val); +} + +void f_key() { + cell *keyword = RUNNING + TASK_USER_KEY; + cell *echoword = RUNNING + TASK_USER_ECHO; + if (keyword->p) { + PUSHCP(keyword->p); + f_cexecute(); + } else { + PUSHI(0); + } + if (!QUIET.i && echoword->p) { + f_dup(); + PUSHCP(echoword->p); + f_cexecute(); + } +} + +void f_word() { + static char buf[32] = {0}; + int key = ' '; + int ibuf = 0; + + while (key == ' ' || key == '\t' || key == '\n' || key == '\r') { + f_key(); + key = TOP().i; + DROP(1); + } + + while (key != ' ' && key != '\t' && key != '\n' && key != '\r' && key != 0) { + buf[ibuf++] = key; + f_key(); + key = TOP().i; + DROP(1); + } + buf[ibuf] = 0; + PUSHS(buf); +} + +void f_emit() { + if (!QUIET.i) { + cell *echoword = RUNNING + TASK_USER_ECHO; + cell *emitword = RUNNING + TASK_USER_EMIT; + if (echoword->p) { + f_dup(); + PUSHCP(echoword->p); + f_cexecute(); + } + if (emitword->p) { + PUSHCP(emitword->p); + f_cexecute(); + } else { + DROP(1); + } + } else { + DROP(1); + } +} + +void f_putc() { + printf("%c", TOP().i); + DROP(1); +} + +void f_fputc() { + if (ACTIVE_FILE) { + fwrite(&TOP().i, 1, 1, ACTIVE_FILE); + } + DROP(1); +} + +void f_gets() { + gets(TOP().s); +} + +void f_fput() { + if (ACTIVE_FILE) { + fwrite(&TOP().u, 2, 1, ACTIVE_FILE); + } + DROP(1); +} + +void f_fwrite() { // ( length p ) + if (ACTIVE_FILE) { + fwrite(TOP().p, ST1().u, 1, ACTIVE_FILE); + } + DROP(2); +} + +void f_fgetc() { + int result = EOF; + if (ACTIVE_FILE) { + result = fgetc(ACTIVE_FILE); + } + PUSHI(result); +} + +void f_fget() { + unsigned int result = 0; + if (ACTIVE_FILE) { + int low = fgetc(ACTIVE_FILE); + int high = fgetc(ACTIVE_FILE); + if (low != EOF && high != EOF) { + result = low | (high << 8); + } + } + PUSHU(result); +} + +void f_fread() { // ( length p ) + if (ACTIVE_FILE) { + fread(TOP().p, ST1().u, 1, ACTIVE_FILE); + } + DROP(2); +} + +void f_feof() { + if (ACTIVE_FILE) { + PUSHI(feof(ACTIVE_FILE)); + } else { + PUSHI(1); + } +} + +void f_puts() { + char *s = TOP().s; + while (s && *s) { + PUSHI(*s); + f_emit(); + s++; + } + DROP(1); +} + +void f_dot() { + static char num[16]; + sprintf(num, "%d ", TOP().i); + TOP().s = num; + f_puts(); +} + +void f_udot() { + static char num[16]; + sprintf(num, "%u ", TOP().i); + TOP().s = num; + f_puts(); +} + +void f_printstack() { + cell *v = RUNNING + STACK_OFFSET; + while (v != stack) { + PUSHC(*v++); + f_dot(); + } +} + +void f_printrstack() { + cell *v = RUNNING + RSTACK_OFFSET; + while (v != rstack) { + PUSHC(*v++); + f_dot(); + } +} + +void f_cr() { + PUSHI('\n'); + f_emit(); +} + +void f_comma() { + *HERE++ = TOP(); + DROP(1); +} + +void f_allot() { + memset(HERE, 0, TOP().u); + HERE = CELL_OFFSET(HERE, TOP().u); + DROP(1); +} + +void f_bcomma() { + *((char*)HERE) = TOP().i; + HERE = CELL_OFFSET(HERE, 1); + DROP(1); +} + +void f_create() { // name -- + int namelen; + HERE->p = LATEST; + LATEST = HERE; + HERE++; + namelen = strlen(TOP().s); + HERE->u = namelen; HERE ++; + memcpy(HERE, TOP().s, namelen + 1); + HERE = CELL_OFFSET(HERE, namelen + 1); + DROP(1); +} + +void f_cdef() { // func name -- + f_create(); + f_comma(); +} + +void f_revlookup(); + +#ifdef TRACE +void f_traceon() { + TRACING = 1; +} +void f_traceoff() { + TRACING = 0; +} + +void f_colondispatch() { + static int printing = 0; + + if (TRACING && !printing) { + printing = 1; + PUSHCP(W.p); + f_revlookup(); + if (TOP().s) { + f_puts(); + PUSHU(' '); + f_emit(); + } else { + TOP().p = W.p; + f_dot(); + } + printing = 0; + } + W.p->f(); +} +#else +#define f_colondispatch() W.p->f() +#endif + +void f_colonloop() { + while (IP.p) { + W = *IP.p; + IP.p++; + f_colondispatch(); + } +} + +// this version of f_execute can be run from a colon word +void f_execute() { + W = TOP(); + DROP(1); + f_colondispatch(); +} + +// C code must always call a colon word through f_cexecute() +void f_cexecute() { + cell oldW = W; + cell oldIP = IP; + IP.p = NULL; + f_execute(); + f_colonloop(); + W = oldW; + IP = oldIP; +} + +void f_docolon() { + RPUSH(IP); + IP.p = W.p + 1; +} + +void f_dodeferred() { + W = *(W.p + 1); + f_colondispatch(); +} + +void f_lit_() { + PUSHC(*IP.p); + IP.p++; +} + +void f_number() { // str -- (num 1 | str 0) + int num = 0, result; + result = sscanf(TOP().s, "0x%x", &num); + if (result != 1) { + result = sscanf(TOP().s, "%d", &num); + } + if (result == 1) { + TOP().i = num; + PUSHI(result == 1); + } else { + PUSHI(0); + } +} + +void f_streq() { + int result = strcmp(TOP().s, ST1().s); + DROP(1); + TOP().i = result == 0; +} + +void f_wordname() { + TOP().p = TOP().p + 2; +} +void f_wordflags() { + TOP().p = TOP().p + 1; +} + +void f_codepointer() { + unsigned int flags = TOP().p[1].u; + TOP().p = CELL_OFFSET(TOP().p + 2, (flags & F_NAMELEN_MASK) + 1); +} + +void f_lookup() { // name -- (codepointer flags) | (name 0) + cell *entry = LATEST; + char *name = TOP().s; + int len = strlen(name); + DROP(1); + + while (entry) { + PUSHP(entry); + f_wordflags(); f_get(); + if (len == (TOP().u & F_NAMELEN_MASK)) { + PUSHS(name); + PUSHP(entry); + f_wordname(); + f_streq(); + if (TOP().i) { + TOP().p = entry; + f_codepointer(); + f_swap(); + return; + } + DROP(2); + } else { + DROP(1); + } + entry = entry->p; + } + PUSHS(name); + PUSHU(0); +} + +void f_revlookup() { // codepointer -- name + cell *entry = LATEST; + while (entry) { + PUSHCP(entry); + f_codepointer(); + if (TOP().p == ST1().p) { + DROP(1); + TOP().p = entry; + f_wordname(); + return; + } + DROP(1); + entry = entry->p; + } + TOP().p = NULL; +} + +void f_compileon() { + STATE.i = 1; +} +void f_compileoff() { + STATE.i = 0; +} + +void f_immediate() { + cell *flags = LATEST + 1; + flags->u |= F_IMMEDIATE; +} +void f_compileword(); + +void f_semicolon() { + PUSHS("ret"); + f_compileword(); + f_compileoff(); +} + +void f_ret() { + if (rstack == RUNNING + RSTACK_OFFSET) { + IP.p = NULL; + } else { + IP = *RPOP(); + } +} + +void f_colon() { + f_word(); + f_create(); + PUSHP(f_docolon); + f_comma(); + f_compileon(); +} + +void f_interpretword() { // codefield flags -- + if (!STATE.i || (TOP().u & F_IMMEDIATE)) { + DROP(1); + f_cexecute(); + } else { + DROP(1); + f_comma(); + } +} + +void f_interpretnumber() { // number -- + if (STATE.i) { + PUSHS("LIT_"); + f_compileword(); + f_comma(); + } +} + +void f_interpretunknown() { // name -- + f_puts(); + PUSHS("?\n"); + f_puts(); +} + +void f_compileword() { // name -- + f_lookup(); + if (!TOP().u) { // name 0 + DROP(1); // name + f_number(); // n isnum + if (TOP().i) { + DROP(1); + f_interpretnumber(); + } else { + DROP(1); + f_interpretunknown(); + } + } else { // codepointer flags + f_interpretword(); + } +} + +void f_interpreter() { + while(1) { + f_word(); // w + if (TOP().s[0] == '\0') { + PUSHS("ok\n"); + f_puts(); + DROP(1); + return; + } + f_compileword(); + } +} + +void f_close() { + if (ACTIVE_FILE) { + fclose(ACTIVE_FILE); + ACTIVE_FILE = NULL; + } +} + +void f_open() { + FILE *fp; + fp = fopen(TOP().s, "ab+"); + fseek(fp, 0, SEEK_SET); + ACTIVE_FILE = fp; + DROP(1); +} + +void f_overwrite() { + f_close(); + ACTIVE_FILE = fopen(TOP().s, "wb+"); + DROP(1); +} + +void f_deactivate() { + PUSHP(ACTIVE_FILE); + ACTIVE_FILE = NULL; +} + +void f_activate() { + f_close(); + ACTIVE_FILE = TOP().fp; + DROP(1); +} + +void f_seek() { + fseek(ACTIVE_FILE, TOP().u, SEEK_SET); + DROP(1); +} + +void f_seekend() { + fseek(ACTIVE_FILE, 0, SEEK_END); +} + +void f_tell() { + PUSHU(ftell(ACTIVE_FILE)); +} + +void f_exists() { + struct stat statbuf; + int rc = stat(TOP().s, &statbuf); + TOP().i = rc == 0; +} + +struct ffblk findfile; +void f_findfirst() { + int result = findfirst(TOP().s, &findfile, 0); + if (result == 0) { + TOP().s = findfile.ff_name; + } else { + TOP().u = 0; + } +} + +void f_findnext() { + int result = findnext(&findfile); + if (result == 0) { + PUSHS(findfile.ff_name); + } else { + PUSHU(0); + } +} + +void f_chdir() { + chdir(TOP().s); + DROP(1); +} + +void f_swapinput() { + cell *key = RUNNING + TASK_USER_KEY; + cell *keysrc = RUNNING + TASK_USER_KEYSRC; + cell oldKey = *key; + cell oldKeysrc = *keysrc; + *key = TOP(); + *keysrc = ST1(); + TOP() = oldKey; + ST1() = oldKeysrc; +} + +void f_taskemit() { + PUSHCP(RUNNING + TASK_USER_EMIT); +} + +void f_taskecho() { + PUSHCP(RUNNING + TASK_USER_ECHO); +} + +void f_doconst() { + PUSHC(*(W.p + 1)); +} + +void f_const() { + f_word(); + f_create(); + PUSHP(f_doconst); + f_comma(); + f_comma(); +} + +void f_dovar() { + PUSHCP(W.p + 1); +} + +void f_var() { + f_word(); + f_create(); + PUSHP(f_dovar); + f_comma(); + PUSHI(0); + f_comma(); +} + +void f_docreate() { + PUSHCP(W.p + 2); + RPUSH(IP); + IP = *(W.p + 1); +} + +void f_bz_() { + if (!TOP().u) { + IP.p = IP.p->p; // branch + } else { + IP.p ++; // skip branch destination cell + } + DROP(1); +} + +void f_bnz_() { + if (TOP().u) { + IP.p = IP.p->p; // branch + } else { + IP.p ++; // skip branch destination cell + } + DROP(1); +} + +void f_goto_() { + IP.p = IP.p->p; +} + +void f_inline_data_() { + PUSHCP(IP.p + 1); + IP = *IP.p; +} + +void f_memmove() { // ( dst src size -- ) + memmove(ST2().p, ST1().p, TOP().u); + DROP(3); +} +void f_quote() { + if (STATE.i) { + PUSHS("LIT_"); + f_compileword(); + } else { + f_word(); + f_lookup(); + DROP(1); + } +} +void f_imagefilename() { + static char imagefilename[32]; + int i; + + strcpy(imagefilename, TOP().s); + for (i = 0; i < strlen(imagefilename); i ++) { + if (imagefilename[i] == '.') break; + } + strcpy(&imagefilename[i], ".jim"); + TOP().s = imagefilename; +} + +void f_image_up_to_date() { + struct stat src, img; + int uptodate = 0; + f_dup(); + f_imagefilename(); + if (stat(TOP().s, &img) == 0 && stat(ST1().s, &src) == 0) { + uptodate = img.st_mtime > src.st_mtime; + } + DROP(1); + TOP().i = uptodate; +} + +static int imagemagic = -1; +static void f_calc_imagemagic(char *exefilename) { + struct stat exe; + if (stat(exefilename, &exe) == 0) { + imagemagic = exe.st_mtime; + } +} + + +void f_loadimage() { + cell *start, *latestNew, *tasksNew; + size_t size; + int magic; + + fread(&magic, sizeof(int), 1, ACTIVE_FILE); + if (magic != imagemagic) { + PUSHI(0); + return; + } + fread(&start, sizeof(cell *), 1, ACTIVE_FILE); + fread(&latestNew, sizeof(cell *), 1, ACTIVE_FILE); + fread(&tasksNew, sizeof(cell *), 1, ACTIVE_FILE); + fread(&size, sizeof(size_t), 1, ACTIVE_FILE); + if (start != HERE) { + fseek(ACTIVE_FILE, size, SEEK_CUR); + PUSHI(0); + } else { + fread(HERE, 1, size, ACTIVE_FILE); + HERE = CELL_OFFSET(HERE, size); + LATEST = latestNew; + TASKS = tasksNew; + PUSHI(1); + } +} + +void f_saveimage() { + size_t size = (size_t)(((char*)HERE) - TOP().s); + fwrite(&imagemagic, sizeof(int), 1, ACTIVE_FILE); + fwrite(&TOP().p, sizeof(cell *), 1, ACTIVE_FILE); + fwrite(&LATEST, sizeof(cell *), 1, ACTIVE_FILE); + fwrite(&TASKS, sizeof(cell *), 1, ACTIVE_FILE); + fwrite(&size, sizeof(size_t), 1, ACTIVE_FILE); + fwrite(TOP().p, 1, size, ACTIVE_FILE); + DROP(1); +} + +void f_loadfile(char *filename) { + PUSHS(filename); + PUSHS("loadfile"); + f_lookup(); + DROP(1); + f_cexecute(); +} + +void f_loadjor(char *filename) { + PUSHS(filename); + PUSHS("loadjor"); + f_lookup(); + DROP(1); + f_cexecute(); +} + +// does not use the jorth interpreter defined in boot.jor +void f_loadfile_cterp(char *filename) { + cell *start = HERE; + PUSHS(filename); + f_dup(); + f_image_up_to_date(); + if (TOP().i) { + DROP(1); + f_dup(); + f_imagefilename(); + f_open(); + f_loadimage(); + f_close(); + if (TOP().i) { + DROP(2); + return; + } + } + DROP(1); + f_open(); + f_deactivate(); + PUSHS("key-file"); + f_lookup(); + DROP(1); + f_swapinput(); + f_interpreter(); + f_swapinput(); + DROP(2); + + PUSHS(filename); + f_imagefilename(); + f_overwrite(); + PUSHCP(start); + f_saveimage(); + f_close(); +} + +void f_runstring(char *s) { + PUSHS(s); + PUSHS("loadstring"); + f_lookup(); + DROP(1); + f_cexecute(); +} + +void f_quiet() { + QUIET.i = 1; +} + +void f_loud() { + QUIET.i = 0; +} + +// task switching +void f_task() { + cell *task = HERE; + HERE += TASK_SIZE; + memset(task, 0, TASK_SIZE * 2); + task->p = TASKS; + TASKS = task; + PUSHP(task); +} + +void f_suspend() { + cell *registers = RUNNING + TASK_USER_SIZE; + registers[0] = IP; + registers[1].p = stack; + registers[2].p = rstack; + IP.p = 0; +} + +void f_restore() { + cell *registers = RUNNING + TASK_USER_SIZE; + IP = registers[0]; + stack = registers[1].p; + rstack = registers[2].p; +} + +// run all tasks once, except the task that triggered the loop +void f_taskloop() { + cell *task = RUNNING; + f_suspend(); + RUNNING = TASKS; + while (RUNNING) { + if (RUNNING != task) { + f_restore(); + f_colonloop(); + } + RUNNING = RUNNING->p; + } + RUNNING = task; + f_restore(); +} + +void f_stacksize() { + PUSHU(STACK_SIZE); +} +void f_rstacksize() { + PUSHU(RSTACK_SIZE); +} +void f_taskusersize() { + PUSHU(TASK_USER_SIZE); +} + +void f_init(char *exe) { + f_calc_imagemagic(exe); + + CDEF("[", f_compileoff); f_immediate(); + CDEF("]", f_compileon); + CDEF("key", f_key); + CDEF("key-string", f_key_string); + CDEF("key-file", f_key_file); + CDEF("emit", f_emit); + CDEF("word", f_word); + CDEF("immediate", f_immediate); + CDEF("execute", f_execute); + CDEF("new-word", f_create); + CDEF("here", f_here); + CDEF("here!", f_here_set); + CDEF("latest", f_latest); + CDEF("latest!", f_latest_set); + CDEF("tasks", f_tasks); + CDEF("tasks!", f_tasks_set); + CDEF("state", f_state); + CDEF("'", f_quote); f_immediate(); + CDEF("`", f_revlookup); + CDEF("wordname", f_wordname); + CDEF("wordflags", f_wordflags); + CDEF("codepointer", f_codepointer); + CDEF("lookup", f_lookup); + CDEF(":", f_colon); + CDEF(";", f_semicolon); f_immediate(); + CDEF("const", f_const); + CDEF("var", f_var); + CDEF("allot", f_allot); + CDEF("+", f_add); + CDEF("-", f_sub); + CDEF("*", f_mul); + CDEF("/", f_div); + CDEF("%", f_mod); + CDEF("=0", f_eq0); + CDEF("not", f_not); + CDEF("=", f_eq); + CDEF("!=", f_neq); + CDEF(">=", f_ge); + CDEF(">", f_gt); + CDEF("=", f_eq); + CDEF("<", f_lt); + CDEF("<=", f_le); + CDEF("u>=", f_uge); + CDEF("u>", f_ugt); + CDEF("u<", f_ult); + CDEF("u<=", f_ule); + CDEF("and", f_and); + CDEF("or", f_or); + CDEF("&", f_bitand); + CDEF("|", f_bitor); + CDEF("^", f_bitxor); + CDEF("<<", f_shl); + CDEF(">>", f_shr); + CDEF("/>ratio", f_toratio); + CDEF("*r", f_rput); + CDEF(" + +#define MEM_SIZE 24576 +#define STACK_SIZE 64 +#define RSTACK_SIZE 64 + +void f_init(char *exe); + +void f_cdef(); +void f_immediate(); + +void f_loadfile(char *filename); +void f_runstring(char *s); + +void f_quiet(); +void f_loud(); +void f_interpreter(); + +union cell_union; +typedef union cell_union cell; + +union cell_union { + int i; + unsigned int u; + cell *p; + char *s; + void (*f)(); + FILE *fp; +}; + +extern char mem[MEM_SIZE]; +extern cell *HERE; +extern cell *LATEST; +extern cell IP; +extern cell W; +extern cell *rstack; +extern cell *stack; + +#define F_NAMELEN_MASK 0x7f +#define F_IMMEDIATE 0x80 + +#define CELL_OFFSET(cp, b) ((cell*)(((char *)(cp)) + b)) +#define TOP() (*(stack - 1)) +#define ST1() (*(stack - 2)) +#define ST2() (*(stack - 3)) +void DROP(int n); +void PUSHC(cell c); +void PUSHI(int i); +void PUSHU(unsigned int u); +void PUSHCP(cell *c); +#define PUSHP(p) PUSHCP((cell*)p) +void PUSHS(char *s); +void RPUSH(cell c); +#define RPOP() (--rstack) +#define RTOP() (*(rstack - 1)) + +void f_key(); +void f_word(); +void f_emit(); +void f_puts(); +void f_dot(); +void f_cr(); +void f_comma(); +void f_bcomma(); +void f_create(); // name -- +void f_cdef(); // func name -- +void f_doconst(); +void f_compileword(); + +cell f_lookupcp(char *name); +void f_execcp(cell cp); + +#define CDEF(name, def) PUSHP(def); PUSHS(name); f_cdef() +#define ICONST(name, v) CDEF(name, f_doconst); PUSHI(v); f_comma() +#define PCONST(name, p) CDEF(name, f_doconst); PUSHP(p); f_comma() diff --git a/kbd.c b/kbd.c new file mode 100755 index 0000000..2ac4678 --- /dev/null +++ b/kbd.c @@ -0,0 +1,78 @@ +#include +#include +#include "kbd.h" + +static void interrupt (*oldKbdISR)() = NULL; + +void kbd_cleanup() { + if (oldKbdISR != NULL) { + setvect(KBD_INT, oldKbdISR); + oldKbdISR = NULL; + } +} + +volatile unsigned char keybuf[128] = { 0 }; +volatile char kbd_triggered = 0; + +static void interrupt kbd_isr() { + unsigned char raw; + char ctl; + + disable(); + + raw = inp(0x60); + ctl = inp(0x61) | 0x82; + outp(0x61, ctl); + outp(0x61, ctl & 0x7f); + + if (raw & 0x80) { + keybuf[raw & 0x7f] &= ~KEY_SIGNAL; + } else { + keybuf[raw] |= KEY_SIGNAL; + } + kbd_triggered = raw; + outp(0x20, 0x20); + enable(); +} + +unsigned char kbd_wait() { + kbd_triggered = 0; + while (!kbd_triggered) {} + return kbd_triggered; +} + +void kbd_init() { + if (oldKbdISR == NULL) { + memset(keybuf, 0, 128); + oldKbdISR = getvect(KBD_INT); + setvect(KBD_INT, kbd_isr); + atexit(kbd_cleanup); + } +} + +void kbd_debounce() { + int i = 0; + + disable(); + for (i = 0; i < 128; i ++) { + unsigned char signal = keybuf[i] & KEY_SIGNAL; + unsigned char keystate = keybuf[i] & 0x0f; + + if (!signal) { + if (keystate == KEY_RELEASED) { + keystate = KEY_OFF; + } else if (keystate != KEY_OFF) { + keystate = KEY_RELEASED; + } + } else { + if (keystate == KEY_OFF) { + keystate = KEY_PRESSED; + } else if (keystate == KEY_PRESSED) { + keystate = KEY_DOWN; + } + } + + keybuf[i] = signal | keystate; + } + enable(); +} \ No newline at end of file diff --git a/kbd.h b/kbd.h new file mode 100755 index 0000000..6061ef5 --- /dev/null +++ b/kbd.h @@ -0,0 +1,108 @@ +/*** K E Y B O A R D ***/ +#define KBD_INT 0x09 + +extern volatile unsigned char keybuf[128]; +extern volatile char kbd_triggered; + +void kbd_init(); +void kbd_debounce(); // call once per frame +void kbd_cleanup(); +unsigned char kbd_wait(); + +#define KEY_OFF 0 +#define KEY_PRESSED 1 +#define KEY_DOWN 2 +#define KEY_RELEASED 3 +#define KEY_SIGNAL 0x80 + +#define keyIsDown(k) (keybuf[k] & KEY_SIGNAL) +#define keyWasPressed(k) ((keybuf[k] & 0x0f) == KEY_PRESSED) +#define consumeKey(k) (keybuf[k] = keyWasPressed(k) ? KEY_DOWN : keybuf[k]) +#define keyWasReleased(k) ((keybuf[k] & 0x0f) == KEY_RELEASED) + +#define K_ESC 1 +#define K_1 2 +#define K_2 3 +#define K_3 4 +#define K_4 5 +#define K_5 6 +#define K_6 7 +#define K_7 8 +#define K_8 9 +#define K_9 10 +#define K_0 11 +#define K_MINUS 12 +#define K_EQUAL 13 +#define K_BKSP 14 +#define K_TAB 15 +#define K_Q 16 +#define K_W 17 +#define K_E 18 +#define K_R 19 +#define K_T 20 +#define K_Y 21 +#define K_U 22 +#define K_I 23 +#define K_O 24 +#define K_P 25 +#define K_LBRK 26 +#define K_RBRK 27 +#define K_ENTER 28 +#define K_CTRL 29 +#define K_A 30 +#define K_S 31 +#define K_D 32 +#define K_F 33 +#define K_G 34 +#define K_H 35 +#define K_J 36 +#define K_K 37 +#define K_L 38 +#define K_SEMI 39 +#define K_APOS 40 +#define K_TILDE 41 +#define K_LSHFT 42 +#define K_BSLSH 43 +#define K_Z 44 +#define K_X 45 +#define K_C 46 +#define K_V 47 +#define K_B 48 +#define K_N 49 +#define K_M 50 +#define K_COMMA 51 +#define K_DOT 52 +#define K_SLASH 53 +#define K_RSHFT 54 +#define K_PSCRN 55 +#define K_ALT 56 +#define K_SPACE 57 +#define K_CAPS 58 +#define K_F1 59 +#define K_F2 60 +#define K_F3 61 +#define K_F4 62 +#define K_F5 63 +#define K_F6 64 +#define K_F7 65 +#define K_F8 66 +#define K_F9 67 +#define K_F10 68 +#define K_NUMLK 69 +#define K_SCRL 70 +#define K_HOME 71 +#define K_UP 72 +#define K_PGUP 73 +#define K_NDASH 74 +#define K_LEFT 75 +#define K_CENT 76 +#define K_RIGHT 77 +#define K_NPLUS 78 +#define K_END 79 +#define K_DOWN 80 +#define K_PGDN 81 +#define K_INS 82 +#define K_DEL 83 +#define K_F11 87 +#define K_F12 88 + diff --git a/lev00001.jor b/lev00001.jor new file mode 100755 index 0000000..ef0ae2d --- /dev/null +++ b/lev00001.jor @@ -0,0 +1,7 @@ +( L E V E L 0 0 0 0 1 ) + +:noname + :| done |; ' entities redefine + + s" lev00001.map" load-map +; ' onload redefine diff --git a/lev00001.map b/lev00001.map new file mode 100755 index 0000000000000000000000000000000000000000..4df9252a49a6d7c150dcb34f0780f42245bf4b8e GIT binary patch literal 264 ycmWe(;ALP&2TTmaiZP;VWhP!Pk#;bmsbgbf!D0tH7BP@pm@ohXBM`y>oCN@diUOSg literal 0 HcmV?d00001 diff --git a/map.jor b/map.jor new file mode 100755 index 0000000..efdae3f --- /dev/null +++ b/map.jor @@ -0,0 +1,87 @@ +( M A P ) +var tileselect +: invalidate-map mapsize mapsize! ; +: mouseworldpos mousepos scrollpos +pos ; +: mousetile mouseworldpos world>tile ; +: tile ( x y -- ptr ) mapsize drop * + map + ; + +1 const WALKABLE +2 const NEUTABLE + +array tileflags +( sky ) 0 b, +( cloud ) 0 b, +( wall ) NEUTABLE b, +( carpet ) WALKABLE b, +( comp-off ) 0 b, +( comp-on ) NEUTABLE b, +( table ) 0 b, +( chair ) 0 b, +( table-brok ) 0 b, + +here tileflags - 1 - const MAXTILE + +: mapflag? ( x y flag -- b ) >rot tile b@ tileflags + b@ & ; + +: tick-mapedit + tileselect @ + ^< key-pressed if 1 - then + ^> key-pressed if 1 + then + 0 max MAXTILE min +( dup 0 < if drop MAXTILE then + dup MAXTILE > if drop 0 then ) + tileselect ! + + MOUSEL mousedown if tileselect @ mousetile tile b! invalidate-map then + MOUSER clicked if + mouseworldpos world>tile + 2dup tile b@ tileselect ! + swap . . cr then ; + +: copy-mapseg ( neww oldw y -- ) + >r ( oldw neww r: y ) + 2dup min >rot ( copyw neww oldw ) + r@ * map + ( copyw neww src ) + swap r ( newh neww oldw r: oldh ) + 2dup < if 1 r ( dx dy r: h ) + swap mapw over abs - >rot ( w dy dx r: h ) + 2dup map swap offset-map + swap mapw * offset-map >rot ( w end dy dx r: h ) + map swap negate offset-map + swap mapw * negate offset-map ( w end start r: h ) + 2dup > if r@ mapw * + swap r@ mapw * + swap then + +#include "mouse.h"; + +/*** M O U S E ***/ +Mouse_t MOUSE; + +void far mouse_callback() { + asm { + mov ax, DGROUP + mov ds, ax + shr cx, 1 + mov MOUSE.x, cx + mov MOUSE.y, dx + mov MOUSE.buttons, bx + } +} + +void mouse_cleanup() { + //uninstall handler + asm { + mov ax, 0ch + mov dx, 0 + mov es, dx + mov cx, 0 + int 33h + + xor ax, ax + int 33h + } +} + +void mouse_init() { + unsigned seg_mouse_callback = FP_SEG(mouse_callback); + unsigned off_mouse_callback = FP_OFF(mouse_callback); + unsigned int result; + asm { + xor ax, ax + int 33h + mov result, ax + } + if (result == 0) { + printf("Mouse driver not installed\n"); + exit(1); + } + atexit(mouse_cleanup); + + asm { + mov ax, seg_mouse_callback + mov es, ax + mov dx, off_mouse_callback + mov ax, 0ch + mov cx, 1fh + int 33h + } +} diff --git a/mouse.h b/mouse.h new file mode 100755 index 0000000..6dc02d1 --- /dev/null +++ b/mouse.h @@ -0,0 +1,13 @@ +/*** M O U S E ***/ +typedef struct { + unsigned int x; + unsigned int y; + unsigned int buttons; +} Mouse_t; + +extern Mouse_t MOUSE; + +void mouse_init(); + +#define mouse_hide() asm { mov ax, 02h; int 33h } +#define mouse_show() asm { mov ax, 01h; int 33h } diff --git a/ntiles.gfx b/ntiles.gfx new file mode 100755 index 0000000000000000000000000000000000000000..9cce95a6718cef8309fe234ab58934a3ba606f29 GIT binary patch literal 8192 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 R546czI>%a};V^k){V!F7{$>CG literal 0 HcmV?d00001 diff --git a/ntiles.tif b/ntiles.tif new file mode 100755 index 0000000000000000000000000000000000000000..e81a7a292268109e99cb00284a1f96ec5c9a03f3 GIT binary patch literal 4078 zcmeHJKX2MV96g%Kp;Ct)LMVSgyWGK(Pd%wSDbH;}c4?n27QtFjbwH;N1^#-gt`x=24 z&VGsbj@&E)4<*NulH<3Mg9XeGM^I*&@ycwK z%vLx<@;fdl!B>0t8rKIjIB4AkX^L_rtlA0;UTKNzRf;Qf*aV`sg;^S199|_7i~@_3 zIF1!aM}aVblh``qvxNB(7+41#v{}O(Vf_(&1qVfvwRuKj=^h2l5gmtIpy84xHw+ll z!H2MEo#(WT_=Y9)i9AOVP2w4wLx3|_*d%J;*bs9BZ{u^K-|rt(nK>*+?<*GhMc-Z| zSRQ_Jc^Y9Yy>lJc6c+hdpaForYm}@1q8OPlvrGG{ivd;X@6P z?CHeTgiwaq+zi8GJBMz06<2Fqs&cGD!4yKmth%l$MU0e@b({6yudJ*%CnVNi|K&>Q zUcZ0fa9$L*mql^2t`6lyW3Nkn*KQuAZqBdO?WIz?XG+!6iu&^wGdY|Trw%?|tl+V_ z$KosPi)sCN%K6*~&7_>037*`!<$N+X`qtNryjouVGxpN1j1 zX@Bx06w-BC%*1g1ljd4!in$vGNrF$3#MIN7sQ5n5bQL}xFt~mneuu-c{1~4_`TY22 z2(T3Xyapp21O zCTe}y#Nvd09~Ny;{2rZPBgZR4D@l&|UcvjyEET)>aU8@!3jrz%U4B)&NgUXTs0~cy zefBKBo!E#BU7h399j!YC0h4QEzF=GU28#N)(+0H5y7zyn?;`K&@qPXQzHF+R)+x1a y|EREN^zn}aKUHb{A;q6p9d(NZb_Qp82y#2N<8}qME3jRG|8E6;DwSfxRDS?ccIPSp literal 0 HcmV?d00001 diff --git a/pete.jor b/pete.jor new file mode 100755 index 0000000..44c9226 --- /dev/null +++ b/pete.jor @@ -0,0 +1,63 @@ +( P E T E ) + +13 8 N ' {car} defentity car +32 5 W ' {horse} defentity e_chuck +17 10 W ' {boat} defentity boat +26 10 W ' {duck} defentity duck1 +32 7 E ' {duck} defentity duck2 + +car :touch + move-player + 1 player.state DRIVING f! +;entity + +boat :touch + move-player + 1 player.state BOATING f! +;entity + +e_chuck :touch + pete say" It's good to have you\back, Chuck." + chuck say" * w h i n n y *\(I remember this place...)" +;entity + +:noname +:| player.driving? not CHUCK-FOLLOW flag@ not and if car yield then + CHUCK-STOLEN flag@ if e_chuck yield then + player.boating? not if boat yield then + duck1 yield duck2 yield + done |; ' entities redefine + + :| +touch-begin S leaving? dup + if player.driving? not CHUCK-FOLLOW flag@ not and + if pete say" It's too far to walk to town." + else move-player 5 10 road.jor queue-level + then + then +touch-next N leaving? dup + if move-player 24 49 space.jor queue-level then +touch-next 13 8 2= player.driving? and dup + if move-player + 0 player.state DRIVING f! + W player entity.dir ! + move-player + then +touch-next 19 9 2= CHUCK-FOLLOW flag@ and player entity.dir @ E = and dup + if pete say" Hmm, yeah, lots of good\grazing over here..." + say" Let's get you comfy, Chuck." move-player then +touch-next 22 9 2= CHUCK-FOLLOW flag@ and dup + if pete say" Welcome home, old buddy." + chuck say" * n e i g h *\(OK, Pete.)" + CHUCK-FOLLOW clearflag CHUCK-STOLEN setflag + 13 7 petehous.jor queue-level then +touch-next 12 7 2= player.driving? not and dup + if move-player 16 9 petehous.jor queue-level then +touch-next 30 7 2= dup + if pete say" It's... kinda swampy.\I don't wanna get wet if I\don't have to." then +touch-next 30 9 2= dup + if pete say" Feels spooky over here,\somehow." then +touch-last |; ' player-touch redefine + +s" pete.map" load-map +; ' onload redefine diff --git a/pete.map b/pete.map new file mode 100755 index 0000000000000000000000000000000000000000..cb3160be8d979b9ad1ad45e37f09f2becfa281a8 GIT binary patch literal 524 zcmajbYZ8MX5Ch0B;v3_A&h{fh@9eG3^*LoeOi}O}5wh0G3 literal 0 HcmV?d00001 diff --git a/petehous.jor b/petehous.jor new file mode 100755 index 0000000..20358ad --- /dev/null +++ b/petehous.jor @@ -0,0 +1,95 @@ +( P E T E ' S H O U S E ) + +16 5 N ' {pete-table} defentity table +15 5 N ' {chair} defentity chair +7 6 N ' {pete-bed} defentity bed +10 9 N ' {phone} defentity e_phone +18 3 N ' {fridge} defentity fridge + +table :touch pete say" Yesterday's breakfast is still\on the table." + say" Maybe the day before's too." ;entity +chair :touch pete say" I've had my morning coffee\already." ;entity +bed :touch pete say" I'm not tired yet." ;entity +fridge :touch pete say" Should get some more beer soon." ;entity + +e_phone :touch phone :| + +s" [don't pick up]" +:| pete say" Hmm... no answer." |; yield + +s" Hey Pete, what's up?" +:| pete say" Not much, old friend!" + 0 begin phone :| + JEANNE-ANGRY flag@ CHUCK-GONE flag@ not and if + s" I hear Jeanne's awful mad\at you!" + :| pete say" Ohh, she'll come round." + phone say" What'd you do, anyway?" + pete say" Me?! What makes you think I\did anything?" + phone say" Come on, Pete, how long\have we known each other?" + pete say" Haw haw haw! Well, it's a\pretty good story..." + say" I was taking Chuck out for a\midnight ride, see..." + phone say" *sigh* You didn't even think\of asking, did you." + pete say" Hell no! He's my horse!" + phone say" Chuck hasn't been your horse\for years, Pete. That's what\happens when you sell them." + pete say" Quit moralizing and let me tell\my story. So there I was,\riding on the trail..." + say" We get to the clearing, and\I look up at the stars." + say" It's the clearest night\you've ever seen in your life." + say" Just as I'm looking up,\I see something." + phone say" 'Something'?" + pete say" I have seen my share of\airplanes and shooting stars.\This was not that." + say" I'm not saying it was aliens..." + phone say" ... but it was aliens." + pete say" I'm not saying it!\You said it." + say" Anyway, I get off Chuck and\lie down on the grass, to\get a better look, see?" + say" Maybe have a pull or two of\whiskey, while I'm watching\the sky." + say" I guess I must've dozed off,\because next thing I know\it's morning and Chuck's gone." + phone say" You LOST him??" + pete say" I figured he just went home!\But when I went to Jeanne's,\he wasn't there." + phone say" You lost him." + pete say" He's a smart old goat,\just like me. He'll\turn up soon." + CHUCK-GONE setflag + |; yield + then + CHUCK-GONE flag@ if + s" You found Chuck yet?" + :| pete say" I'm sure he'll turn up soon!\Sheesh, get off my back." |; yield + then + CHUCK-FOLLOW flag@ if + s" You found Chuck yet?" + :| pete say" He's right here." + chuck say" * s n o r t *" + phone say" You brought him in your house??" + phone say" Of course you did.\Never mind.\Don't even bother explaining." + |; yield + then + CHUCK-STOLEN flag@ CHUCK-HOME flag@ or CHUCK-EXPLAINED flag@ not and if + s" You found Chuck yet?" + :| pete say" He found his way home." + phone say" Well, thank goodness\for that." + CHUCK-EXPLAINED setflag + |; yield + then + s" Goodbye, Pete." :| pete say" Goodbye!" drop 1 |; yield + done |; choose + dup until drop +|; yield + +done |; choose ;entity + +:noname + reset-level + :| table yield chair yield bed yield e_phone yield fridge yield done |; ' entities redefine + :| +touch-begin 16 10 2= dup if + move-player 12 8 pete.jor queue-level +then touch-next 9 4 2= dup if + pete say" The closet is a disaster.\I don't want to deal with that\right now." +then touch-next 11 4 2= dup if + pete say" I'm already dressed." +then touch-next 16 3 2= dup if + pete say" The sink's full of nasty dishes.\I'm not touching them." +then touch-last |; ' player-touch redefine + + s" petehous.map" load-map +; ' onload redefine + diff --git a/petehous.map b/petehous.map new file mode 100755 index 0000000000000000000000000000000000000000..36e00accb4e41c4f4ab13dcd3606a8787831184c GIT binary patch literal 368 zcmZ{f0SfBIgRGs&TM^O9Cw7h(N;%5J zCCaobeQr})XAeT0xgcd=bn>-Ybae1I9CEWuHg~YOx zwvh^+!UYaU;n)kxf&YLDr)K#Bs#Y8j2P7}#kV~bw0x7N%d-#smw$doA6F@{lJITj0 z-gz_c&G)@sTQab_762CC1?&TW#g!eT69)Ea_5lYp8DJp_$OaZ|+BH!GDx{_~25KB{ zzyl}~N=3>FxrzbwVXyqFT%}q>Uu6~efiadNq!;*|2RqX4{M1C&3{;dK8$>D7YVkB- zBu}fgXwEASbs?)B+-;7Pm-~6~Sao2Xwv}}Q57&W*cYvuS;1*-dk?_m(?`>}MFZ7+< zvzhDNZs&7i+9>jP3R3NMy|(`+{@eMhd2ma4qe^+DQvN24Rp;$(n|Uh}TUAZFRP`^E zS~ezan|bwHw0BtR{!tUSfV#c5z;?k z$dzw9aOZAUba-iW{Als#h3|{MTI#HVTCQoNQZ;HwippBoEICw5N)pZ~Tiqv~nypY1 z3YEoG*o!Na_=qTgthF4{E>S}Vl~l$F(~=0s2cti z{VVz>EkD(*{%>%u;LNxD_rbopoqyi*HD^yr-M7`>`5XtHXM6`qn2eJxO@9VIwKa6N zX`q)g>pO3*|N6(;_WJ9(xXJHTU!wBWH^8|U4Sd&QAlB&5`3(3v4ZLI+^0yAdMu!n5 zKEf|(};A#63LS^nX8+`MrnUadlO>jdOANfF`ua01-N}k9B~#E#+s{- ziNwh0P%@rMBu9s0@yj8>DEWWk;_$Gu%b8ewFmRab2DroFkjSJsKE<(~b|&-bPbPB5 zH=ES2Y&P6~MF%=E{QiY_z=D!aWM5^BO=Ej|D-{n zWs#nk6mRs4*_k{?!JiK5A4~YVIq+sSGnvka`2y?smTUXJ*%vJ4J${qnDHu(E-ukKJCGKfosqC zR|q_Eeh=||=W|}>{C)UO;IsY%*HafC!G9j*7w}&p_7+#LPo$q?($AXo!wIag9b;vc z6~D3?U#v#gHN+vl*7X4EGj4K=)m=OrvULIFE+BH3;N+m^r<&j!4vktP0iTT=Va;`S z%yLM^s-3zm%m?9FLt0|&YKEXwKMZZ)4^=BG5=cF#u^wK zMSASmA?3y(CCEg(JRXflqe$n5BjekVG#qs({4Qe3`{u&$M${|IYF3toi{O%)(Hymb2 z1lL32Brx*8V#wz;a}n+b#9ocaO<+lr^NKDiZeHJJY{6E0{RTtX(v|sSdLCCG^ODp| z?xCL}Y~k|tc%Bh;0o9o$K*E9;2GW@oc{sx44AYZ-p0z=s_}8aFIen!6lY7{9p)GCYor6`SGO{8^_+qZE~^V_{rRa6ojD8uOmyhKKOx~FXzZZiPCm1CGWi%% zCKKimIG9Y%zC;XH%@ug`1v`v#XWb5AtH@bJKHR|$ZyqFX7w;1O#5P?lXUIElNIrwj zMvv6wl;?;!15wi;7%}uM{)^sp`O+)qyg|AD!rX|DIQ3($7b{udW=ad7fNJ@t@v97R6)!5N?Mg#2xbpMsHz;O8WS5>?t} z10nzda9$MvY6$f}pcfK^AQ2oyhLn=VC@vyrlSgQ&98}@55^X2~7f`v?iim|Tn=yfK zZ(AT|iDA5qKx6GgIr2WoK_}#h>>7^WLm1-bOVde+i(e2~1G z2!W+? +#include +#include "serial.h" + +int comport = 0; + +#define SER_LATCH_LO 0 +#define SER_LATCH_HI 1 +#define SER_TX 0 +#define SER_RX 0 +#define SER_IER 1 +#define SER_LCR 3 +#define SER_MCR 4 +#define SER_LSR 5 + +#define PIC1 0x20 +#define OCW1 0x21 +#define PIC_EOI 0x20 + +// COM1 - IRQ4, COM2 - IRQ3, COM3 - IRQ4, COM4 - IRQ3 +#define SER_IRQ(port) (4 - (port % 2)) +#define SER_VECTOR(irq) (0x08 + (irq)) + +static char readbuf[SER_READ_BUFFER_SIZE]; +static int ireadbufStart = 0; +static volatile int ireadbufLim = 0; +static int irq = 0; + +static void interrupt (*oldSerISR)() = NULL; + +static void interrupt ser_isr() { + while (inp(comport + SER_LSR) & 0x01) { + readbuf[ireadbufLim] = inp(comport + SER_RX); + ireadbufLim = (ireadbufLim + 1) % SER_READ_BUFFER_SIZE; + } + outp(PIC1, PIC_EOI); +} + +static void ser_cleanup() { + if (irq) { + int ocw = inp(OCW1) | (1 << irq); + outp(OCW1, ocw); + setvect(SER_VECTOR(irq), oldSerISR); + irq = 0; + } +} + +void ser_init(int port, int baudrate, int protocol) { + int far *comport_addr = MK_FP(0x0040, 0x0000); + int lcr, ocw; + comport = comport_addr[port]; + irq = SER_IRQ(port); + + outp(comport + SER_LCR, 0x80); + outp(comport + SER_LATCH_HI, baudrate >> 8); + outp(comport + SER_LATCH_LO, baudrate & 0xff); + outp(comport + SER_LCR, protocol); + outp(comport + SER_MCR, 0x0b); + + oldSerISR = getvect(SER_VECTOR(irq)); + setvect(SER_VECTOR(irq), ser_isr); + ocw = inp(OCW1) & ~(1 << irq); + outp(OCW1, ocw); + outp(comport + SER_IER, 0x01); + + atexit(ser_cleanup); +} + +int ser_poll() { + int result = SER_NODATA; + if (ireadbufStart != ireadbufLim) { + result = readbuf[ireadbufStart]; + ireadbufStart = (ireadbufStart + 1) % SER_READ_BUFFER_SIZE; + } + return result; +} + +void ser_write_byte(char byte) { + while (!(inp(comport + SER_LSR) & 0x20)) {} + outp(comport + SER_TX, byte); +} + +void ser_write(char *str) { + for (; *str; str ++) { + ser_write_byte(*str); + } +} + +int ser_getline(char *line) { + int i = strlen(line); + int value; + for (value = ser_poll(); value != SER_NODATA; value = ser_poll()) { + if (value == '\b' || value == 127) { + i --; + } else { + line[i] = value; + i ++; + } + line[i] = '\0'; + ser_write_byte(value); // echo + + if (value == '\r') { + line[i - 1] = '\n'; + ser_write_byte('\n'); + return 1; + } + } + return 0; +} \ No newline at end of file diff --git a/serial.h b/serial.h new file mode 100755 index 0000000..c293072 --- /dev/null +++ b/serial.h @@ -0,0 +1,29 @@ +#define SER_COM1 0 +#define SER_COM2 1 +#define SER_COM3 2 +#define SER_COM4 3 + +#define SER_8N1 0x03 + +#define BAUD_50 0x0900 +#define BAUD_110 0x0417 +#define BAUD_220 0x020c +#define BAUD_300 0x0180 +#define BAUD_600 0x00c0 +#define BAUD_1200 0x0060 +#define BAUD_2400 0x0030 +#define BAUD_4800 0x0018 +#define BAUD_9600 0x000c +#define BAUD_19200 0x0006 +#define BAUD_38400 0x0003 +#define BAUD_57600 0x0002 +#define BAUD_115200 0x0001 + +#define SER_READ_BUFFER_SIZE 64 +#define SER_NODATA -1 + +void ser_init(int port, int baudrate, int protocol); +int ser_poll(); +void ser_write_byte(char byte); +void ser_write(char *str); +int ser_getline(char *line); diff --git a/space b/space new file mode 100755 index 0000000000000000000000000000000000000000..dc1ec09152c7a92d0b297810c43249955e9b409a GIT binary patch literal 2504 qcmXqFFk%oH1*0J_8UmvsFd71*Aut*OqaiRF0!&OyBnH9&>i_`Er^4L; literal 0 HcmV?d00001 diff --git a/space.jor b/space.jor new file mode 100755 index 0000000..063aa8f --- /dev/null +++ b/space.jor @@ -0,0 +1,26 @@ +( S P A C E ) + +24 10 N ' {aliem} defentity aliem +28 28 N ' {pete-bed} defentity bed +19 21 N ' {phone} defentity e_phone + +aliem :touch + pete say" hey mr aliem" +;entity + +:noname +:| aliem yield bed yield e_phone yield done |; ' entities redefine + +:| touch-begin S leaving? dup + if move-player 0 glitchlevel ! 19 0 pete.jor queue-level then +touch-next 5 11 2= dup + if move-player 41 37 tile>world player entity.pos! then +touch-next 41 37 2= dup + if move-player 5 11 tile>world player entity.pos! then +touch-next 44 23 2= dup + if pete say" It's...." say" home?" then +touch-last |; ' player-touch redefine + +s" space.map" load-map +4 glitchlevel ! +; ' onload redefine diff --git a/space.map b/space.map new file mode 100755 index 0000000000000000000000000000000000000000..bede0abdfe088ec67a5ebbb40f247a47f16e72af GIT binary patch literal 2504 zcmb`I3vPoj5JXW_3N4M2R^}qP|KYm7S=+G2AO*Gc+MYMFhJ?O`*N}p1U4z9pEv=#X z`9M-ajIrGrhlxsxmfjR(Y-%-Z$vut*{%gkyPv-;*ShE^6_H2}8YP;CZWv(_9rZ-&H zU;|)(-GZJ*^(ceQ^@m1Q3$)fm9FYAPstGfVhkaKX5XZoScRhqAeYKL@nX3<=!cqwS z!1OQEDAAXzVy58=@g)6&i8CEp6VtVfIZdBany++~(npbTrnLv@pYh3mt?k{=yjS*7 z-T>b^56=-3W^jQhp80*bR}HM)j3q4(Mbff lzi_R`VIV*Ws??%Z)H7Bq!WHzIQ!723kIv$o0$i%nsedSNvPS>_ literal 0 HcmV?d00001 diff --git a/sprite.gfx b/sprite.gfx new file mode 100755 index 0000000000000000000000000000000000000000..65c7b468b9ed125fa0318e11b611b178f514305c GIT binary patch literal 10240 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 DO$s9N literal 0 HcmV?d00001 diff --git a/sprite.tif b/sprite.tif new file mode 100755 index 0000000000000000000000000000000000000000..3eac9014bd03dc1660554b27b30a18584baf7bf0 GIT binary patch literal 7918 zcmeHLziV4p6uz#5Q4v%Xgmy7#@6>BwDjC^PS^^olXsh4^@Qt$Xhy<^uqbcT@iE(iS9828DRSj%(v?fpYE?pLc- zYdeU-PK!s3)^+PSz8o=JfrTk1ZeS=<00dP+@a`kP#6afFIaen`cNhF{M@Um{#x#!) z)*fO(%leC=-!?@4*6r)xIkh{d5NvIoH|Uc3sYGOci?SNXK9zX(SOVE&31p8Y0OWwl zK9#9{LRTj^r8 zr=b$kAhN6RpJ2y{FR>ePKD&B8&Xmt%9)@u#vdC9}P&t_ZMaZ-O=}#^3&ppzyhFQT` z-NK*T5gh5yKQGWUdcWO=9HTgkL<#6{@|8rl5f}Fp!B6-YY zu!#5ZOVR!Kr6l^f^xqKwmGw_;!^r(`$jxfM$r$bZO7#e%Ff?n1o|ba_SI#{;AfKKq z7@e=wxyn4GMJBc$1KFg?sXhi+hofmI{b@x}pHGbA5zL2?gft>`6{4Pl2ytAH+GLyx zZj?6V9pd}s0Qd-41x6kt82mlJlY(IWp`!ZH6U_U?Vt`^q>slM`0e{4Y)>o_~E}5(Y zW#e2KW6097U>N4u^;p3oA@y;>=u_l6VC)D{pfrUK)$=Z1ohu?d|J~)+7k#mF%(hO7 z)bN;WYdqNHcrOTeTo42$YP?WH{5AO+hsy(jmM0`dS%=2VGx`Gy@op~Hr9ULfYnfVk z4f4vh%vx9hW@&Zp>@3% z^XnhLXyE1Re>r|ETcUMoeL4U=%}3*KgA#-!KzeWz7DW@LEz#$~?{`Zc#6;0;>p9pA zWT5hbxWr5K6oVhwCt`{NxWl8f3sSfue-8_TW-03dbXY?8T%2wRbd_n>bvMSjywOJ(rAe9v8{f)EpdOpCVyXf z2b$kP{)X~S^V1oF{i9_WPUArO-RIJOP5ztG|6X->{(jAZJ1s#srQg?K2LEhIp+@_E zE`CGs+{yl5wBJhH-&Ox*`TM#L&8W!<`g1tS$G;ymlu-CD>aIdGH)-aeAN6^KXml{y#eaYp x&)sDGp}gLv9^4qIy|iTomK9i5U|E4>1(p?9R$y6yWd;6M6?kS$t(K{qe*y1Au^<2d literal 0 HcmV?d00001 diff --git a/state.jor b/state.jor new file mode 100755 index 0000000..8097366 --- /dev/null +++ b/state.jor @@ -0,0 +1,23 @@ +0 const JEANNE-ANGRY userword +1 const CHUCK-GONE userword +2 const CHUCK-FOLLOW userword +3 const CHUCK-HOME userword +4 const CHUCK-STOLEN userword +5 const CHUCK-EXPLAINED userword +6 const NIGHT userword + +7 const FLAG-COUNT + +array flags FLAG-COUNT 8 / 1 + allot + +: flagstof ( f -- v f ) dup 8 / flags + swap 8 % 1 swap << ; +: flagsf! ( b f -- ) flagstof f! ; +: flag@ ( f -- b ) flagstof f@ ; userword +: setflag 1 swap flagsf! ; userword +: clearflag 0 swap flagsf! ; userword + +: day s" tiles.gfx" loadtiles invalidate-map NIGHT clearflag ; userword +: night s" ntiles.gfx" loadtiles invalidate-map NIGHT setflag ; userword + +: {car-drive} NIGHT flag@ if {car-lit} else {car} then ; + diff --git a/template.map b/template.map new file mode 100755 index 0000000000000000000000000000000000000000..ec016a84b8f1f5baff51b132fa46f7090d3f6aa8 GIT binary patch literal 264 XcmWe(;ALP&2TTmZMvMsqFkl4$fYkzx literal 0 HcmV?d00001 diff --git a/testbed.c b/testbed.c new file mode 100755 index 0000000..ae4e3f7 --- /dev/null +++ b/testbed.c @@ -0,0 +1,759 @@ +#include +#include +#include +#include +#include + +#include "video.h" +#include "kbd.h" +#include "mouse.h" +#include "tiff.h" +#include "tiles.h" +#include "serial.h" +#include "timer.h" +#include "jorth.h" +#include "egamap.h" +#include "adlib.h" + +/*** T E X T ***/ +char far *font = NULL; + +void text_init() { + unsigned int fontSeg, fontOff; + asm { + push es + push bp + mov ah, 11h + mov al, 30h + mov bh, 3 + int 10h + mov ax, bp + pop bp + mov fontSeg, es + mov fontOff, ax + pop es + } + font = MK_FP(fontSeg, fontOff); +} + +void text_draw_char(unsigned int vidOffset, unsigned char c) { + unsigned int fontOffset = c << 3; + int i; + for (i = 0; i < 8; i ++) { + VID[vidOffset] = font[fontOffset++]; + vidOffset += PAGE_STRIDE; + } +} + +void text_draw(unsigned int vidOffset, unsigned char *s) { + while (*s) { + text_draw_char(vidOffset++, *s++); + } +} + +/*** I / O ***/ +size_t fwritefar(FILE *fp, void far *buf, size_t length) { + char nearbuf[32]; + size_t written = 0; + size_t towrite; + + for (; towrite = min(32, length), length > 0; length -= towrite) { + movedata(FP_SEG(buf), FP_OFF(buf) + written, _SS, nearbuf, towrite); + if (!fwrite(nearbuf, towrite, 1, fp)) { + break; + } + written += towrite; + } + return written; +} + +size_t freadfar(FILE *fp, void far *buf, size_t length) { + char nearbuf[32]; + size_t totalread = 0; + size_t toread; + + for (; toread = min(32, length), length > 0; length -= toread) { + size_t bytesread = fread(nearbuf, 1, toread, fp); + movedata(_SS, nearbuf, FP_SEG(buf), FP_OFF(buf) + totalread, bytesread); + totalread += bytesread; + if (bytesread != toread) { + break; + } + } + return totalread; +} + +/*** S C R A T C H ***/ +#define PORTRAIT_GFX + +#define NUM_SPRITES 64 +#define TILE_STRIDE 64 +#define SPRITE_STRIDE 80 +#define PORTRAIT_STRIDE 256 +unsigned int far *tiles; +unsigned int far *sprites; +unsigned int far *portraits; +unsigned char map[10000]; + + +void deallocate_gfx() { + if (tiles) farfree(tiles); + if (sprites) farfree(sprites); + if (portraits) farfree(portraits); +} + +void allocate_gfx() { + unsigned long memleft = farcoreleft(); + tiles = farmalloc(NUM_TILES * TILE_STRIDE * 2); + sprites = farmalloc(NUM_SPRITES * SPRITE_STRIDE * 2); + portraits = farmalloc(NUM_PORTRAITS * PORTRAIT_STRIDE * 2); + atexit(deallocate_gfx); + + if (!tiles || !sprites || !portraits) { + printf("%lu bytes free - need %lu\n", memleft, + (unsigned long) + ((NUM_TILES * TILE_STRIDE * 2) + + (NUM_SPRITES * SPRITE_STRIDE * 2) + + (NUM_PORTRAITS * PORTRAIT_STRIDE * 2))); + exit(1); + } +} + +void fillMap() { + unsigned int x, y, z; + z = 0; + + for (y = 0; y < 100; y ++) { + for (x = 0; x < 100; x ++) { + map[x + (y * 100)] = ((x + y + z) >> 2) % 4; + } + } +} + +void readTifTiles(char *filename) { + FILE *f; + TifImageMeta_t meta; + + f = fopen(filename, "rb"); + meta = tifLoadMeta(f); + tifLoad(f, meta, tiles, NUM_TILES * 16, 16, 4); + fclose(f); + + loadTiles(OFF_TILES, tiles); +} + +void readTiles(char *filename) { + FILE *f = fopen(filename, "rb"); + freadfar(f, tiles, NUM_TILES * TILE_STRIDE * 2); + fclose(f); + + loadTiles(OFF_TILES, tiles); +} + +void f_loadtiles() { + if (tolower(TOP().s[strlen(TOP().s) - 1]) == 'f') { + readTifTiles(TOP().s); + } else { + readTiles(TOP().s); + } + DROP(1); +} + +void f_load_footer() { + FILE *f = fopen("FOOTER.TIF", "rb"); + TifImageMeta_t meta = tifLoadMeta(f); + tifLoadEGA(f, meta, 0, 48, 336); + fclose(f); +} + +void f_reloadportraits() { + blitMemToVid(OFF_PORTRAITS, portraits, PORTRAIT_STRIDE >> 2, NUM_PORTRAITS); +} + +void game_init() { + FILE *f; + TifImageMeta_t meta; + + allocate_gfx(); + + mouse_init(); + + setEGAMode(); + atexit(vid_cleanup); + + kbd_init(); + timer_init(TIMER_30HZ); + text_init(); + + tile_init(); + fillMap(); + + f_load_footer(); + + f = fopen("sprite.gfx", "rb"); + freadfar(f, sprites, NUM_SPRITES * SPRITE_STRIDE * 2); + fclose(f); + +#ifdef PORTRAIT_GFX + f = fopen("portrait.gfx", "rb"); + freadfar(f, portraits, NUM_PORTRAITS * PORTRAIT_STRIDE * 2); + fclose(f); + f_reloadportraits(); +#else + f = fopen("PORTRAIT.TIF", "rb"); + meta = tifLoadMeta(f); + tifLoad(f, meta, portraits, NUM_PORTRAITS * 32, 32, 4); + tifLoadEGA(f, meta, OFF_PORTRAITS, NUM_PORTRAITS * 32, 32); + fclose(f); +#endif + + readTiles("tiles.gfx"); + + loadMap(map, 100, 100); + scroll(0, 0); +} + +void f_seremit() { + ser_write_byte(TOP().i); + if (TOP().i == '\n') { + ser_write_byte('\r'); + } + DROP(1); +} + +void f_keyWasPressed() { + int k = TOP().i; + TOP().i = keyWasPressed(k); + consumeKey(k); +} + +void f_keyIsDown() { + TOP().i = keyIsDown(TOP().i); +} + +void f_drawSprite() { // ( x y sprite -- ) + drawSprite(&sprites[TOP().i * SPRITE_STRIDE], ST2().i, ST1().i, NULL); + DROP(3); +} + +void f_scroll() { // ( x y -- ) + scroll(ST1().i, TOP().i); + DROP(2); +} + +void f_scrollpos() { // ( -- x y ) + PUSHI(screen.scrollX); + PUSHI(screen.scrollY); +} + +void f_ticks() { + PUSHU(timer_counter); +} + +void f_splitscreen() { + setSplitScreen(399 - (TOP().i << 1)); + DROP(1); +} + +void f_textc() { // ( col line c color -- ) + setWriteMode(0); + setPlaneColor(TOP().u); + DROP(1); + text_draw_char(ST2().u + (ST1().u * PAGE_STRIDE), TOP().i); + DROP(3); +} + +void f_text() { // ( col line s color -- ) + setWriteMode(0); + setPlaneColor(TOP().u); + DROP(1); + text_draw(ST2().u + (ST1().u * PAGE_STRIDE), TOP().s); + DROP(3); +} + +void f_map() { + PUSHP(map); +} + +void f_mapsize() { // ( -- w h ) + PUSHI(screen.w); + PUSHI(screen.h); +} + +void f_mapsize_set() { // ( w h -- ) + loadMap(map, ST1().i, TOP().i); + DROP(2); +} + +void f_mousepos() { // ( -- x y ) + PUSHI(MOUSE.x); + PUSHI(MOUSE.y); +} +void f_mousebuttons() { + PUSHI(MOUSE.buttons); +} + +void f_drawportrait() { + setAllPlanes(); + setWriteMode(1); + blit32x32(OFF_PORTRAITS + (TOP().u << 7), (PAGE_STRIDE << 3) + 1); + DROP(1); +} + +void f_adlib() { + adlib_write(TOP().u, ST1().u); + DROP(2); +} + +cell f_atexit; +void f_cleanup() { + f_execcp(f_atexit); +} + +void f_glitch() { + int count = TOP().u; + int i, x, y; + DROP(1); + for (i = 0; i < count; i ++) { + x = screen.scrollX + (rand() % 352) - 16; + y = screen.scrollY + (rand() % 232) - 16; + switch(rand()%2) { + case 0: + drawSprite(sprites + (rand() % (NUM_SPRITES * SPRITE_STRIDE)), x, y, NULL); + break; + case 1: + drawSprite(mem + (rand() % MEM_SIZE), x, y, NULL); + break; + } + } +} + +/* JILES */ +#define SCREEN_STRIDE 40 + +typedef enum { + ET_SPRITE = 0, + ET_TILE = 1, + ET_PORTRAIT = 2 +} EditTarget_t; +EditTarget_t editTarget = ET_SPRITE; + +unsigned int far *getTarget(int index) { + if (editTarget == ET_SPRITE) { + return &sprites[index * SPRITE_STRIDE]; + } else if (editTarget == ET_TILE) { + return &tiles[index * TILE_STRIDE]; + } else { + return &portraits[index * PORTRAIT_STRIDE]; + } +} + +#define ET_STRIDE (editTarget == ET_SPRITE ? SPRITE_STRIDE : \ + (editTarget == ET_TILE ? TILE_STRIDE : PORTRAIT_STRIDE)) + +int getsprpixel(int x, int y, unsigned int far *spr) { + int shift = (15 - (x % 16)); + int plane_stride = 16; + int b, g, r, i, v; + if (editTarget == ET_PORTRAIT) { + y = y << 1; + if (x > 15) y ++; + plane_stride = 64; + } + spr += y; + b = (*spr & (1 << shift)) >> shift; spr += plane_stride; + g = (*spr & (1 << shift)) >> shift; spr += plane_stride; + r = (*spr & (1 << shift)) >> shift; spr += plane_stride; + i = (*spr & (1 << shift)) >> shift; spr += plane_stride; + v = editTarget != ET_SPRITE || (*spr & (1 << shift)) ? 0 : 1; + return b | (g << 1) | (r << 2) | (i << 3) | (v << 4); +} +int resetEnabledCache = 0; + +#define setResetEnabledCached(m) \ + if (resetEnabledCache != m) { \ + resetEnabledCache = m; \ + setResetEnabled(m); \ + } + +void drawFatBox(int x, int y, int color) { + int faty; + int fill1 = color <= 0x0f ? 0xff : 0x55; + int fill2 = fill1 == 0xff ? 0xff : 0xaa; + unsigned int dst = SCREEN_STRIDE * y; + + if (color > 0x0f) { + setResetEnabledCached(0); + } else { + setResetEnabledCached(0x0f); + setResetMask(color); + } + for ( faty = 0; faty < 8; faty ++) { + VID[dst + x + (SCREEN_STRIDE * faty)] = (faty % 2) ? fill1 : fill2; + } +} + +void drawDoubleFatBox(int x, int y, int colorl, int colorr) { + int faty, plane; + unsigned int dst = (SCREEN_STRIDE * y) + x; + + setResetEnabledCached(0); + + for ( plane = 0; plane < 4; plane ++ ) { + int fill = colorr & ( 1 << plane ) ? 0x0f : 0x00; + fill |= colorl & ( 1 << plane ) ? 0xf0 : 0x00; + + setPlane( plane ); + for ( faty = 0; faty < 4; faty ++ ) { + VID[dst + (SCREEN_STRIDE * faty)] = fill; + } + } +} + +void f_drawfatsprite() { + int isprite = TOP().i; + unsigned int far *spr = getTarget(isprite); + int x, y; + + DROP(1); + if (editTarget != ET_PORTRAIT) { + setAllPlanes(); + for ( y = 0; y < 16; y ++ ) { + for ( x = 0; x < 16; x ++ ) { + int color = getsprpixel(x, y, spr); + drawFatBox(x, y << 3, color); + } + } + } else { + for ( y = 0; y < 32; y ++ ) { + for ( x = 0; x < 32; x += 2 ) { + int colorl = getsprpixel( x, y, spr); + int colorr = getsprpixel(x + 1, y, spr); + drawDoubleFatBox(x >> 1, y << 2, colorl, colorr); + } + } + setAllPlanes(); + } +} + +void f_drawfatbox() { + drawFatBox(ST1().i, TOP().i, ST2().i); + DROP(3); +} + +void f_savegfx() { + FILE *fp = fopen(TOP().s, "wb"); + if (editTarget == ET_SPRITE) { + fwritefar(fp, sprites, NUM_SPRITES * SPRITE_STRIDE * 2); + } else if (editTarget == ET_TILE) { + fwritefar(fp, tiles, NUM_TILES * TILE_STRIDE * 2); + } else { + fwritefar(fp, portraits, NUM_PORTRAITS * PORTRAIT_STRIDE * 2); + } + fclose(fp); + DROP(1); +} + +void f_mousehide() { + mouse_hide(); +} + +void f_mouseshow() { + mouse_show(); +} + +void f_resetvideo() { + setLogicalWidth(SCREEN_STRIDE >> 1); + setResetEnabledCached(0); + setWriteMode(0); + setAllPlanes(); + setDisplayOffset(0); + setHorizontalPan(0); +} + +void f_putpixel() { + int isprite = TOP().i; + unsigned int far *spr = getTarget(isprite); + int x = ST2().i; + int y = ST1().i; + int color, shift, b, g, r, i, v; + int plane_stride = 16; + + DROP(3); + color = TOP().i; + DROP(1); + + shift = (15 - (x % 16)); + if (editTarget == ET_PORTRAIT) { + y = y << 1; + if (x > 15) y ++; + plane_stride = 64; + } + + b = (color & 0x01); + g = (color & 0x02) >> 1; + r = (color & 0x04) >> 2; + i = (color & 0x08) >> 3; + v = ((color & 0x10) >> 4) ^ 1; + spr = &spr[y]; + + *spr = (*spr & ~(1 << shift)) | (b << shift); spr += plane_stride; + *spr = (*spr & ~(1 << shift)) | (g << shift); spr += plane_stride; + *spr = (*spr & ~(1 << shift)) | (r << shift); spr += plane_stride; + *spr = (*spr & ~(1 << shift)) | (i << shift); spr += plane_stride; + if (editTarget == ET_SPRITE) { + *spr = (*spr & ~(1 << shift)) | (v << shift); + } +} + +void f_getpixel() { + int isprite = TOP().i; + unsigned int far *spr = getTarget(isprite); + int x = ST2().i; + int y = ST1().i; + DROP(2); + + TOP().i = getsprpixel(x, y, spr); +} + +void f_spritecount() { + if (editTarget == ET_SPRITE) { + PUSHI(NUM_SPRITES); + } else if (editTarget == ET_TILE) { + PUSHI(NUM_TILES); + } else if (editTarget == ET_PORTRAIT) { + PUSHI(NUM_PORTRAITS); + } +} + +void f_tile2buf() { + unsigned int *buf = (unsigned int *)TOP().p; + unsigned int itile = ST1().u; + DROP(2); + writeTile(buf, &tiles[itile * TILE_STRIDE]); +} + +void f_spr2buf() { + unsigned int *buf = (unsigned int *)TOP().p; + unsigned int isprite = ST1().u; + DROP(2); + overlaySprite(buf, &sprites[isprite * SPRITE_STRIDE], 0, 0, NULL); +} + +void f_remap_spr2buf() { + unsigned int *buf = (unsigned int *)TOP().p; + unsigned int isprite = ST1().u; + char *remap = (char*)ST2().p; + DROP(3); + overlaySprite(buf, &sprites[isprite * SPRITE_STRIDE], 0, 0, remap); + +} + +void f_pastetile() { + unsigned int far *src = getTarget(ST1().i); + unsigned int far *dst = getTarget(TOP().i); + unsigned int stride = ET_STRIDE; + unsigned int i; + + DROP(2); + for (i = 0; i < stride; i ++) { + dst[i] = src[i]; + } +} + +void f_fliptile() { + unsigned int far *dst = getTarget(TOP().i); + unsigned int stride = ET_STRIDE; + unsigned int i; + unsigned int bit; + + DROP(1); + for (i = 0; i < stride; i ++) { + unsigned int src = dst[i]; + unsigned int result = 0; + for (bit = 0; bit < 16; bit ++) { + if (src & (1 << bit)) { + result |= (1 << (15 - bit)); + } + } + if (editTarget == ET_PORTRAIT && ((i % 2) == 1)) { + bit = dst[i - 1]; + dst[i - 1] = result; + dst[i] = bit; + } else { + dst[i] = result; + } + } +} + +void f_vfliptile() { + unsigned int far *dst; + unsigned int far *gfx = editTarget == ET_SPRITE ? sprites : tiles; + unsigned int stride = editTarget == ET_SPRITE ? SPRITE_STRIDE : TILE_STRIDE; + unsigned int y; + unsigned int plane; + + if (editTarget == ET_PORTRAIT) return; // TODO + dst = &gfx[TOP().i * stride]; + DROP(1); + for (plane = 0; plane < (editTarget == ET_SPRITE ? 5 : 4); plane ++) { + for (y = 0; y < 8; y ++) { + unsigned int tmp = dst[y]; + dst[y] = dst[15 - y]; + dst[15 - y] = tmp; + } + dst += 16; + } +} + +void f_nudgesprite() { + unsigned int far *dst = &sprites[TOP().i * SPRITE_STRIDE]; + int direction = ST1().i < 0 ? -1 : 1; + int ystart = direction < 0 ? 0 : 15; + int ylim = direction < 0 ? 15 : 0; + int plane, y; + unsigned int itransparent = direction < 0 ? 64 : 79; + DROP(2); + if (dst[itransparent] != 0 || editTarget != ET_SPRITE) { + return; + } + for (plane = 0; plane < 5; plane ++) { + for (y = ystart; y != ylim; y -= direction) { + dst[y] = dst[y - direction]; + } + dst[ylim] = 0; + dst += 16; + } +} + +void f_paintbuf() { + unsigned int *buf = (unsigned int *)TOP().p; + int y = ST1().i; + int x = ST2().i; + DROP(3); + paintBuffer(buf, x + (y * SCREEN_STRIDE)); +} + +void f_setedittarget() { + editTarget = TOP().i; +} + +void f_getedittarget() { + PUSHI(editTarget); +} + +void f_reloadtiles() { + loadTiles(OFF_TILES, tiles); +} + +/* INIT */ +void game_f_init(char *exe, char *bootjor) { + f_init(exe); + CDEF("seremit", f_seremit); + CDEF("key-pressed", f_keyWasPressed); + CDEF("key-down", f_keyIsDown); + CDEF("key-start", kbd_init); + CDEF("key-end", kbd_cleanup); + CDEF("draw-sprite", f_drawSprite); + CDEF("draw-portrait", f_drawportrait); + CDEF("scroll", f_scroll); + CDEF("scrollpos", f_scrollpos); + CDEF("draw-screen", drawScreen); + CDEF("split-screen", f_splitscreen); + CDEF("ticks", f_ticks); + CDEF("text", f_text); + CDEF("textc", f_textc); + CDEF("map", f_map); + CDEF("mapsize", f_mapsize); + CDEF("mapsize!", f_mapsize_set); + CDEF("mousepos", f_mousepos); + CDEF("mousebuttons", f_mousebuttons); + CDEF("loadtiles", f_loadtiles); + CDEF("glitch", f_glitch); + CDEF("unfuck", tile_init); + CDEF("load-footer", f_load_footer); + CDEF("fuck", f_resetvideo); + + CDEF("mouseshow", f_mouseshow); + CDEF("mousehide", f_mousehide); + CDEF("drawfatsprite", f_drawfatsprite); + CDEF("drawfatbox", f_drawfatbox); + CDEF("putpixel", f_putpixel); + CDEF("getpixel", f_getpixel); + CDEF("spritecount", f_spritecount); + CDEF("savegfx", f_savegfx); + CDEF("tile>buf", f_tile2buf); + CDEF("spr>buf", f_spr2buf); + CDEF("remap-spr>buf", f_remap_spr2buf); + CDEF("paintbuf", f_paintbuf); + CDEF("edittarget", f_getedittarget); + CDEF("edittarget!", f_setedittarget); + CDEF("reloadtiles", f_reloadtiles); + CDEF("reloadportraits", f_reloadportraits); + CDEF("paste-tile", f_pastetile); + CDEF("flip-tile", f_fliptile); + CDEF("vflip-tile", f_vfliptile); + CDEF("nudge-sprite", f_nudgesprite); + + f_loadjor(bootjor); + + f_atexit = f_lookupcp("atexit"); + atexit(f_cleanup); + +} + +void f_poll() { + static char line[128] = { 0 }; + + while (ser_getline(line)) { + PUSHS(line); + f_runstring("REPL send"); + f_taskloop(); + line[0] = '\0'; + } +} + +int DONE = 0; +static void f_quit() { + DONE = 1; +} +void do_repl(char *exe) { + char buf[128]; + + f_init(exe); + CDEF("quit", f_quit); + CDEF("adlib", f_adlib); + + f_loadfile("repl.jor"); + f_taskloop(); + + while (!DONE) { + PUSHS(gets(buf)); + f_runstring("REPL send"); + f_taskloop(); + } +} + +int main(int argc, char *argv[]) { + cell tick, draw; + char *bootjor = "gameboot.jor"; + if (argc > 1) { + bootjor = argv[1]; + } + ser_init(SER_COM2, BAUD_19200, SER_8N1); + game_init(); + game_f_init(argv[0], bootjor); + tick = f_lookupcp("tick"); + draw = f_lookupcp("draw"); + + while (!keyIsDown(K_ESC)) { + kbd_debounce(); + f_poll(); + f_taskloop(); + f_execcp(tick); + f_taskloop(); + f_execcp(draw); + } + + return 0; +} diff --git a/tiff.c b/tiff.c new file mode 100755 index 0000000..f0d088e --- /dev/null +++ b/tiff.c @@ -0,0 +1,187 @@ +#include +#include "tiff.h" +#include "video.h" + +/*** T I F F ***/ +typedef struct { + unsigned int endian; + unsigned int version; + unsigned long ifdOffset; +} TifHeader_t; + +#define TIF_WIDTH 256 +#define TIF_HEIGHT 257 +#define TIF_BITSPERSAMPLE 258 +#define TIF_COMPRESSION 259 +#define TIF_STRIPOFFSETS 273 +#define TIF_ROWSPERSTRIP 278 + +typedef struct { + unsigned int id; + unsigned int dataType; + unsigned long dataCount; + unsigned long dataOffset; +} TifTag_t; + +TifImageMeta_t tifLoadMeta(FILE *f) { + TifImageMeta_t meta = {0, 0, 0, 0, 0}; + TifHeader_t header; + TifTag_t tag; + unsigned int i, tagCount; + + fseek(f, 0, SEEK_SET); + fread(&header, 8, 1, f); + + if (header.endian != 0x4949 || header.version != 0x2a) { + goto fail; + } + fseek(f, header.ifdOffset, SEEK_SET); + fread(&tagCount, 2, 1, f); + for (i = 0; i < tagCount; i ++) { + fread(&tag, 12, 1, f); + if (tag.id == TIF_WIDTH) { + meta.width = tag.dataOffset; + } else if (tag.id == TIF_HEIGHT) { + meta.height = tag.dataOffset; + } else if (tag.id == TIF_BITSPERSAMPLE) { + if (tag.dataOffset != 4) goto fail; + } else if (tag.id == TIF_COMPRESSION) { + if (tag.dataOffset != 1) goto fail; + } else if (tag.id == TIF_STRIPOFFSETS) { + meta.stripCount = tag.dataCount; + meta.stripOffsets = tag.dataOffset; + } else if (tag.id == TIF_ROWSPERSTRIP) { + meta.rowsPerStrip = tag.dataOffset; + } + } + return meta; +fail: + meta.stripCount = 0; + return meta; +} + +int tifLoadEGA(FILE *f, TifImageMeta_t meta, unsigned int vidOffset, int maxY, unsigned int w) { + int istrip; + int irow; + int ipixelpair; + int y = 0; + unsigned long offset; + unsigned char rowData[MAX_WIDTH >> 1]; + volatile unsigned char far *out = &VID[vidOffset]; + unsigned char b, g, r, i; + + if (meta.width > MAX_WIDTH || (meta.width % 8) != 0) { + return 0; + } + setWriteMode(0); + + for (istrip = 0; istrip < meta.stripCount; istrip ++) { + fseek(f, meta.stripOffsets + (istrip << 2), SEEK_SET); + fread(&offset, 4, 1, f); + fseek(f, offset, SEEK_SET); + + for (irow = 0; irow < meta.rowsPerStrip; irow ++) { + int ipixelpairLim = meta.width >> 1; + fread(rowData, 1, ipixelpairLim, f); + b = g = r = i = 0; + for (ipixelpair = 0; ipixelpair < ipixelpairLim; ipixelpair ++) { + unsigned char pixelpair = rowData[ipixelpair]; + int bpair = (pixelpair & 0x01) | (pixelpair & 0x10) >> 3; + int gpair = (pixelpair & 0x02) >> 1 | (pixelpair & 0x20) >> 4; + int rpair = (pixelpair & 0x04) >> 2 | (pixelpair & 0x40) >> 5; + int ipair = (pixelpair & 0x08) >> 3 | (pixelpair & 0x80) >> 6; + int shift = (3 - (ipixelpair % 4)) << 1; + + b |= bpair << shift; + g |= gpair << shift; + r |= rpair << shift; + i |= ipair << shift; + + if (shift == 0 || ipixelpair == ipixelpairLim - 1) { + // todo: use write mode 2, this is slooww + setPlane(PLANE_B); *out = b; + setPlane(PLANE_R); *out = r; + setPlane(PLANE_G); *out = g; + setPlane(PLANE_I); *out = i; + out ++; + b = g = r = i = 0; + } + } + y++; + if (y == maxY) { + return y; + } + out += (w - meta.width) >> 3; + } + } + return y; +} + +int tifLoad(FILE *f, TifImageMeta_t meta, unsigned int far *planeBuf, int maxY, int yRepeat, int planes) { + int istrip; + int irow; + int ipixelpair; + int y = 0; + unsigned long offset; + unsigned char rowData[MAX_WIDTH >> 1]; + unsigned int planeStride = (meta.width >> 4) * yRepeat; + unsigned int far *bp = planeBuf; + unsigned int far *gp = bp + planeStride; + unsigned int far *rp = gp + planeStride; + unsigned int far *ip = rp + planeStride; + unsigned int far *mp = ip + planeStride; + unsigned int bv, gv, rv, iv; + + if (meta.width > MAX_WIDTH || (meta.width % 16) != 0 || planes < 4 || planes > 5) { + return 0; + } + + for (istrip = 0; istrip < meta.stripCount; istrip ++) { + fseek(f, meta.stripOffsets + (istrip << 2), SEEK_SET); + fread(&offset, 4, 1, f); + fseek(f, offset, SEEK_SET); + + for (irow = 0; irow < meta.rowsPerStrip; irow ++) { + int ipixelpairLim = meta.width >> 1; + fread(rowData, 1, ipixelpairLim, f); + bv = gv = rv = iv = 0; + for (ipixelpair = 0; ipixelpair < ipixelpairLim; ipixelpair ++) { + unsigned char pixelpair = rowData[ipixelpair]; + int bpair = (pixelpair & 0x01) | (pixelpair & 0x10) >> 3; + int gpair = (pixelpair & 0x02) >> 1 | (pixelpair & 0x20) >> 4; + int rpair = (pixelpair & 0x04) >> 2 | (pixelpair & 0x40) >> 5; + int ipair = (pixelpair & 0x08) >> 3 | (pixelpair & 0x80) >> 6; + int shift = (7 - (ipixelpair % 8)) << 1; + + bv |= bpair << shift; + gv |= gpair << shift; + rv |= rpair << shift; + iv |= ipair << shift; + + if (shift == 0 || ipixelpair == ipixelpairLim - 1) { + *bp++ = bv; + *gp++ = gv; + *rp++ = rv; + *ip++ = iv; + if (planes == 5) { + iv = ~(bv & gv & rv & iv); + *mp++ = iv; + } + bv = gv = rv = iv = 0; + } + } + y++; + if (y == maxY) { + return y; + } + if (y % yRepeat == 0) { + bp += planeStride * (planes - 1); + gp += planeStride * (planes - 1); + rp += planeStride * (planes - 1); + ip += planeStride * (planes - 1); + mp += planeStride * (planes - 1); + } + } + } + return y; +} diff --git a/tiff.h b/tiff.h new file mode 100755 index 0000000..2ee2fcd --- /dev/null +++ b/tiff.h @@ -0,0 +1,17 @@ +#include + +/*** T I F F ***/ + +typedef struct { + unsigned int width; + unsigned int height; + unsigned long rowsPerStrip; + unsigned long stripCount; + unsigned long stripOffsets; +} TifImageMeta_t; + +#define MAX_WIDTH 328 + +TifImageMeta_t tifLoadMeta(FILE *f); +int tifLoadEGA(FILE *f, TifImageMeta_t meta, unsigned int vidOffset, int maxY, unsigned int w); +int tifLoad(FILE *f, TifImageMeta_t meta, unsigned int far *planeBuf, int maxY, int yRepeat, int planes); diff --git a/tiles.c b/tiles.c new file mode 100755 index 0000000..fd5160c --- /dev/null +++ b/tiles.c @@ -0,0 +1,329 @@ +#include +#include +#include +#include "video.h" +#include "tiles.h" +#include "egamap.h" + +/*** T I L E S ***/ + +// Tiles are 16x16 bitmaps, stored as arrays of words. +// Each tile has 4 or 5 planes (depending on whether it is a tile or sprite) +// which are stored adjacant to each other; ie. a 16-word array of blue, +// followed by a 16-word array of green, etc. +// Tiles in RAM are stored byte-swapped to aid in fast bit-shifting, and must +// be byte-swapped before being written to video memory. + +// Because bit-shifting operations happen on little-endian words: +// 01234567 89ABCDEF << 3 => 34567XXX BCDEF012 +// which is wrong. So instead we do: +// 89ABCDEF 01234567 << 3 => BCDEFXXX 3456789A byteswap => 3456789A BCDEFXXX + +void tile_init() { + setLogicalWidth(PAGE_STRIDE >> 1); +} + +void blitTile(unsigned int offsetFrom, unsigned int offsetTo) { + int y; + for (y = 0; y < 16; y ++) { + VID[offsetTo] = VID[offsetFrom ++]; + VID[offsetTo + 1] = VID[offsetFrom ++]; + offsetTo += PAGE_STRIDE; + } +} + +void blitSolidBlock(unsigned int offsetTo, unsigned char color) { + int y; + setPlaneColor(color); + for (y = 0; y < 16; y ++) { + VID[offsetTo] = 0xff; + VID[offsetTo + 1] = 0xff; + offsetTo += PAGE_STRIDE; + } +} + +void blit32x32(unsigned int offsetFrom, unsigned int offsetTo) { + int y; + for (y = 0; y < 32; y ++) { + VID[offsetTo] = VID[offsetFrom ++]; + VID[offsetTo + 1] = VID[offsetFrom ++]; + VID[offsetTo + 2] = VID[offsetFrom ++]; + VID[offsetTo + 3] = VID[offsetFrom ++]; + offsetTo += PAGE_STRIDE; + } +} + +void blitMemToVid(unsigned int offset, unsigned int far *mem, unsigned int planeStride, int count) { + int i, j, plane; + + offset = offset >> 1; // word aligned + setWriteMode(0); + for (i = 0; i < count; i ++) { + for (plane = 0; plane < 4; plane ++) { + unsigned int drawOffset = offset; + unsigned int bmp; + + setPlane(plane); + for (j = 0; j < planeStride; j ++) { + bmp = mem[j]; + WVID[drawOffset + j] = (bmp << 8) | (bmp >> 8); + } + mem += planeStride; + } + offset += planeStride; + } + setAllPlanes(); +} + +#define D_NOTHING 0x80 +#define D_BGTILE 0x81 +#define isBufIndex(d) (!((d) & 0x80)) + +#define nextBufferIndex(i) ((i + 1) % NUM_BUFFERS) + +TiledScreen_t screen = { 0, 0, 0, 0, { OFF_PAGE1, OFF_PAGE2 }, 0, 0, NULL, NULL, + 0, 0, 0, 0, 0 }; + + +void paintBufferPlane(unsigned int *buf, unsigned int vidOffset, int stride, int plane) { + unsigned int drawOffset = vidOffset >> 1; + unsigned int y, bmp; + for (y = 0; y < 16; y ++) { + bmp = buf[y + (BUF_WSTRIDE * plane)]; + WVID[drawOffset] = (bmp << 8) | (bmp >> 8); + drawOffset += stride >> 1; + } +} + +void loadTiles(unsigned int tilesOffset, unsigned int far *memTiles) { + int i, plane; + screen.tilesOffset = tilesOffset; + screen.memTiles = memTiles; + setWriteMode(0); + for (plane = 0; plane < 4; plane ++) { + unsigned int drawOffset = tilesOffset >> 1; + setPlane(plane); + for (i = 0; i < NUM_TILES; i ++) { + unsigned int y, bmp; + unsigned int far *buf = &memTiles[(i * BUF_WSIZE) + (BUF_WSTRIDE * plane)]; + for (y = 0; y < 16; y ++) { + bmp = buf[y]; + WVID[drawOffset ++] = (bmp << 8) | (bmp >> 8); + } + } + } + setAllPlanes(); +} + +void loadMap(unsigned char *map, unsigned int w, unsigned int h) { + screen.map = map; + screen.w = w; + screen.h = h; + memset(screen.dirty, D_BGTILE, PAGE_TILES_COUNT * 2); +} + +void writeTile(unsigned int *buf, unsigned int far *tile) { + int i; + for (i = 0; i < BUF_WSIZE; i ++) { + buf[i] = tile[i]; + } +} + +void overlaySprite(unsigned int *buf, unsigned int far *sprite, int shift, int yStart, char *remap) { + unsigned int far *mask; + unsigned int maskval; + int y, h, plane; + + if (yStart < 0) { + sprite = &sprite[-yStart]; + h = yStart + 16; + } else { + buf = &buf[yStart]; + h = 16 - yStart; + } + mask = &sprite[BUF_WSTRIDE * 4]; + if (!remap) { + if (shift < 0) { + shift = -shift; + for (plane = 0; plane < 4; plane ++) { + for (y = 0; y < h; y ++) { + maskval = mask[y] << shift; + buf[y] = (buf[y] & ~maskval) | ((sprite[y] << shift) & maskval); + } + sprite += BUF_WSTRIDE; + buf += BUF_WSTRIDE; + } + } else { + for (plane = 0; plane < 4; plane ++) { + for (y = 0; y < h; y ++) { + maskval = mask[y] >> shift; + buf[y] = (buf[y] & ~maskval) | ((sprite[y] >> shift) & maskval); + } + sprite += BUF_WSTRIDE; + buf += BUF_WSTRIDE; + } + } + } else { + unsigned int b, bo, g, go, r, ro, i, io, bgri; + int bit; + if (shift < 0) { + shift = -shift; +#define SPLANE(b, y, p) b[y + (BUF_WSTRIDE * (p))] +#define DO_REMAP(ss, bitstart, bitlim) \ + for (y = 0; y < h; y ++) { \ + bo = go = ro = io = 0; \ + b = SPLANE(sprite, y, 0); \ + g = SPLANE(sprite, y, 1); \ + r = SPLANE(sprite, y, 2); \ + i = SPLANE(sprite, y, 3); \ + for (bit = (bitstart); bit < (bitlim); bit ++) { \ + int bshift = 1 << bit; \ + bgri = ((b & bshift) ? 0x01 : 0x00) | \ + ((g & bshift) ? 0x02 : 0x00) | \ + ((r & bshift) ? 0x04 : 0x00) | \ + ((i & bshift) ? 0x08 : 0x00); \ + bgri = remap[bgri]; \ + if (bgri & 0x01) bo |= bshift; \ + if (bgri & 0x02) go |= bshift; \ + if (bgri & 0x04) ro |= bshift; \ + if (bgri & 0x08) io |= bshift; \ + } \ + maskval = mask[y] ss shift; \ + SPLANE(buf, y, 0) = (SPLANE(buf, y, 0) & ~maskval) | ((bo ss shift) & maskval); \ + SPLANE(buf, y, 1) = (SPLANE(buf, y, 1) & ~maskval) | ((go ss shift) & maskval); \ + SPLANE(buf, y, 2) = (SPLANE(buf, y, 2) & ~maskval) | ((ro ss shift) & maskval); \ + SPLANE(buf, y, 3) = (SPLANE(buf, y, 3) & ~maskval) | ((io ss shift) & maskval); \ + } + + DO_REMAP(<<, shift, 16) + } else { + DO_REMAP(>>, 0, 16 - shift) + +#undef DO_REMAP +#undef SPLANE + } + } +} + +int prepareBuffer(int pageX, int pageY) { + unsigned char *dirty = &screen.dirty[screen.currentPage][pageX + (pageY * PAGE_TILES_W)]; + int i; + if (!isBufIndex(*dirty)) { + unsigned int startX = screen.scrollX >> 4; + unsigned int startY = screen.scrollY >> 4; + unsigned char tile = screen.map[startX + pageX + ((startY + pageY) * screen.w)]; + unsigned char ibuffer = screen.nextBuffer; + screen.nextBuffer = nextBufferIndex(ibuffer); + *dirty = ibuffer; + writeTile(screen.buffer[ibuffer], &screen.memTiles[tile * BUF_WSIZE]); + screen.bufferOffset[ibuffer] = screen.pageOffset[screen.currentPage] + + (pageX << 1) + (pageY * PAGE_STRIDE * 16); + } + return *dirty; +} + +void drawSpriteToBuf(unsigned int far *sprite, int pageX, int pageY, int shift, int yStart, char *remap) { + unsigned int *buf; + + if (pageX < 0 || pageY < 0 || + pageX >= PAGE_TILES_W || pageY >= PAGE_TILES_H || + shift >= 16 || shift <= -16 || + yStart <= -16 || yStart >= 16) { + return; + } + + buf = screen.buffer[prepareBuffer(pageX, pageY)]; + overlaySprite(buf, sprite, shift, yStart, remap); +} + +void drawSprite(unsigned int far *sprite, int x, int y, char *remap) { + int pageX = (int)(x - (screen.scrollX & 0xfff0)) >> 4; + int pageY = (int)(y - (screen.scrollY & 0xfff0)) >> 4; + int pageOffsetX = x & 0x0f; + int pageOffsetY = y & 0x0f; + + drawSpriteToBuf(sprite, pageX, pageY, pageOffsetX, pageOffsetY, remap); + drawSpriteToBuf(sprite, pageX + 1, pageY, pageOffsetX - 16, pageOffsetY, remap); + drawSpriteToBuf(sprite, pageX, pageY + 1, pageOffsetX, pageOffsetY - 16, remap); + drawSpriteToBuf(sprite, pageX + 1, pageY + 1, pageOffsetX - 16, pageOffsetY - 16, remap); +} + +void scroll(int newX, int newY) { + newX = min(max(newX, 0), (screen.w << 4) - 320); + newY = min(max(newY, 0), (screen.h << 4) - 200); + if ((screen.scrollX & 0xfff0) != (newX & 0xfff0) || + (screen.scrollY & 0xfff0) != (newY & 0xfff0)) { + int mapX, mapY; + unsigned char page; + for (page = 0; page < 2; page ++) { + int mapOffsetOld = (screen.scrollX >> 4) + ((screen.scrollY >> 4) * screen.w); + int mapOffsetNew = (newX >> 4) + ((newY >> 4) * screen.w); + unsigned char *dirty = screen.dirty[page]; + for (mapY = 0; mapY < PAGE_TILES_H; mapY ++) { + for (mapX = 0; mapX < PAGE_TILES_W; mapX ++) { + if (*dirty != D_NOTHING || + screen.map[mapOffsetOld + mapX] != screen.map[mapOffsetNew + mapX]) { + *dirty = D_BGTILE; + } + dirty ++; + } + mapOffsetNew += screen.w; + mapOffsetOld += screen.w; + } + } + } + screen.scrollX = newX; + screen.scrollY = newY; +} + +void paintBuffer(unsigned int *buf, unsigned int vidOffset) { + int plane; + setWriteMode(0); + for (plane = 0; plane < 4; plane ++) { + setPlane(plane); + paintBufferPlane(buf, vidOffset, 40, plane); + } +} + +void drawScreen() { + unsigned int startX = screen.scrollX >> 4; + unsigned int startY = screen.scrollY >> 4; + unsigned int offsetX = screen.scrollX - (startX << 4); + unsigned int offsetY = screen.scrollY - (startY << 4); + unsigned int drawOffset = screen.pageOffset[screen.currentPage]; + unsigned int scrollOffset = drawOffset + (offsetX >> 3) + (offsetY * PAGE_STRIDE); + unsigned char *dirty = screen.dirty[screen.currentPage]; + unsigned int x, y, di, plane, bmp; + + setAllPlanes(); + setWriteMode(1); + + di = 0; + for (y = startY; y < startY + PAGE_TILES_H; y ++) { + for (x = startX; x < startX + PAGE_TILES_W; x ++) { + if (dirty[di++] == D_BGTILE) { + char tile = screen.map[x + (y * screen.w)]; + blitTile(screen.tilesOffset + (tile << 5), drawOffset); + } + drawOffset += 2; + } + drawOffset += PAGE_STRIDE * 15; + } + setWriteMode(0); + for(plane = 0; plane < 4; plane ++) { + setPlane(plane); + for (di = screen.firstBuffer; di != screen.nextBuffer; di = nextBufferIndex(di)) { + paintBufferPlane(screen.buffer[di], screen.bufferOffset[di], PAGE_STRIDE, plane); + } + } + setAllPlanes(); + + setDisplayOffset(scrollOffset); + setHorizontalPan(screen.scrollX & 0x07); + + screen.currentPage ^= 1; + screen.firstBuffer = screen.nextBuffer; + for (di = 0; di < PAGE_TILES_COUNT; di ++) { + dirty[di] = isBufIndex(dirty[di]) ? D_BGTILE : D_NOTHING; + } +} diff --git a/tiles.gfx b/tiles.gfx new file mode 100755 index 0000000000000000000000000000000000000000..eaaa7776233c7af4524c5d3822e9f2d7d09e2dd8 GIT binary patch literal 8192 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 F{{UU*tSSHi literal 0 HcmV?d00001 diff --git a/timer.c b/timer.c new file mode 100755 index 0000000..031aa95 --- /dev/null +++ b/timer.c @@ -0,0 +1,44 @@ +#include +#include +#include "timer.h" + +#define TIMER_INTERRUPT 0x1c +#define REG_8253_CTL 0x43 +#define REG_COUNTER0 0x40 + +volatile unsigned int timer_counter = 0; + +static void interrupt (*oldTimerISR)() = NULL; +static void (*callback)() = NULL; + +static void interrupt timer_isr() { + disable(); + timer_counter ++; + if (callback) callback(); + enable(); + oldTimerISR(); +} + +void timer_setcallback(void (*cb)()) { + callback = cb; +} + +void timer_setrate(unsigned int rate) { + outp(REG_8253_CTL, 0x3c); + outp(REG_COUNTER0, rate & 0xff); + outp(REG_COUNTER0, (rate >> 8) & 0xff); +} + +static void timer_cleanup() { + if (oldTimerISR != NULL) { + setvect(TIMER_INTERRUPT, oldTimerISR); + timer_setrate(TIMER_18HZ); + oldTimerISR = NULL; + } +} +void timer_init(unsigned int rate) { + timer_setrate(rate); + oldTimerISR = getvect(TIMER_INTERRUPT); + setvect(TIMER_INTERRUPT, timer_isr); + atexit(timer_cleanup); +} diff --git a/timer.h b/timer.h new file mode 100755 index 0000000..9d804be --- /dev/null +++ b/timer.h @@ -0,0 +1,12 @@ +#define TIMER_60HZ 0x4dae +#define TIMER_50HZ 0x5d37 +#define TIMER_40HZ 0x7486 +#define TIMER_30HZ 0x965c +#define TIMER_20HZ 0xe90b +#define TIMER_18HZ 0xffff + +extern volatile unsigned int timer_counter; + +void timer_init(unsigned int rate); +void timer_setrate(unsigned int rate); +void timer_setcallback(void (*cb)()); diff --git a/timer.jor b/timer.jor new file mode 100755 index 0000000..31fa9f0 --- /dev/null +++ b/timer.jor @@ -0,0 +1,37 @@ +( timer + lerping ) +: clamp0 ( range val -- i ) + 2dup <= if drop else + dup 0 <= if drop drop 0 else + swap drop then then ; +: >ratio ( range value -- f ) + over swap clamp0 swap />ratio ; +: range ( start end -- start range ) over - ; +: r >range r >range ratio lerpr ; +: lerp ( start end duration start -- i ) + ticks udelta ( start end duration delta ) + >ratio lerpr ; + +: triggered ( duration timer -- b ) + dup >r @ ticks udelta ( duration delta ) + 2dup <= if drop r @ >rot ticks ( from to duration start ) + begin + 4dup lerp r@ ! + rot suspend + repeat rdrop drop drop drop drop ; + +: sleep ( count -- ) + ticks swap begin over ticks udelta over u< while suspend repeat drop drop ; diff --git a/trail1.jor b/trail1.jor new file mode 100755 index 0000000..a62dc9c --- /dev/null +++ b/trail1.jor @@ -0,0 +1,54 @@ +( T R A I L 1 ) + +50 17 E ' {horse} defentity e_chuck +39 71 N ' {car} defentity car + +car :touch + CHUCK-FOLLOW flag@ if + pete say" I can't leave Chuck here!" + else + move-player 1 player.state DRIVING f! + then +;entity + +e_chuck :touch + pete say" Woah, boy. Calm down." move-player + chuck say" * w h i n n y *\(You came back!)" + pete say" Of course I did, boy.\Of course I did." + p_chuck follow CHUCK-GONE clearflag CHUCK-FOLLOW setflag +;entity + +:noname +0 player.state DRIVING f! + +:| CHUCK-GONE flag@ if e_chuck yield then + player.driving? not if car yield then + done |; ' entities redefine + +:| +touch-begin S leaving? dup + if player.driving? not CHUCK-FOLLOW flag@ not and + if pete say" I'm not walking." + else move-player 13 7 road.jor queue-level + then + then +CHUCK-GONE flag@ if + touch-next 49 17 2= dup + if + pete say" Oh for the love of..." + say" Chuck! How on Earth did you\end up over there!?" + W e_chuck entity.dir ! + chuck say" * n e i g h *\(Help me Pete, I'm lost!)" + then +then +touch-next 3 56 2= dup + if + 1 glitchlevel ! + pete say" This is where I buried it." + say" All those years ago." + 0 glitchlevel ! + then +touch-last |; ' player-touch redefine + +s" trail1.map" load-map +; ' onload redefine diff --git a/trail1.map b/trail1.map new file mode 100755 index 0000000000000000000000000000000000000000..429d959c7de647b4ac3011ea3f8dd0e0a6dee7af GIT binary patch literal 5629 zcmeH}S(4i@3`AwSe7d>+eS$^%LldNzpY3OR{~!OZ1CO&qB#zK3 zd$>OuCh74gthUtJC4dVSs1C6eLtBb(T95!%Nt}^~0iHhtd(jy&ElS%lH&a_q*;CcV zFvakU(usMq47jabWThDsFAiDe{i% zX*+#9Uig-`>Lj6Spp&^+axt!M+w2Ndvss%cTm0GfXld!B1nW0u%1^@)+sir z;%=b~vDuZNFgfd`P-bhnW*$HbWT~_?@f+ij3WAXae=j#Iw!dZ6*uN-IiDx+%q> zXUvG$0F*D(aC?0Hs9BpTYE=y;CV}!@WK-y=r~+7vj*^PYwD6jc9Pig_Xj^W(M~32l zYdB-EX9PW$9?lZVyCo)X(H@F<%B!%23cHy=rULg^4O@Ou^c_M5!E$-?2}_(EgGzP6Z(fA0kQ4(a8{fWjGb@m;RiNj^&VO$xaQ6 zQzfRVq_%|=TcV3k&mk-)RDDK~f=*#bt16rB{5(QgEKU#CA*ZG}s-%%Td1|7*tJ-k9 zF+Oz6sICg(xsba9gUMHvTy)WoL*CycHz#gRda>0U_`%SM>6WgH0~C+UlssR50IVxm AcK`qY literal 0 HcmV?d00001 diff --git a/video.c b/video.c new file mode 100755 index 0000000..39710c4 --- /dev/null +++ b/video.c @@ -0,0 +1,39 @@ +#include +#include "video.h" + +void vid_cleanup() { + setTextMode(); +} + +void setSplitScreen(unsigned int y) { + int val; + outport(REG_CRTC, 0x18 | (y << 8)); + outp(REG_CRTC, 7); + val = inp(REG_CRTC + 1); + val &= ~0x10; + val |= (y & 0x100) >> 4; + outp(REG_CRTC + 1, val); + outp(REG_CRTC, 9); + val = inp(REG_CRTC + 1); + val &= ~0x40; + outp(REG_CRTC + 1, val); +} + +void unsetSplitScreen() { + outport(REG_CRTC, 0xff18); + outport(REG_CRTC, 0x1107); + outport(REG_CRTC, 0x0f09); +} + + +void setDisplayOffset(unsigned int offset) { + outport(REG_CRTC, 0x0c | (offset & 0xff00)); + outport(REG_CRTC, 0x0d | (offset << 8)); +} + +void setHorizontalPan(int offset) { + inp(0x3da); // INPUT_STATUS_1? + outp(REG_AC, 0x13 | 0x20); + outp(REG_AC, offset); +} + diff --git a/video.h b/video.h new file mode 100755 index 0000000..c468472 --- /dev/null +++ b/video.h @@ -0,0 +1,39 @@ +/*** V I D E O ***/ +#define setMode(hexval) asm { mov ax, hexval; int 10h } + +#define setVGAMode() setMode(0013h) +#define setEGAMode() setMode(000Dh) +#define setTextMode() setMode(0003h) + +#define REG_AC 0x03c0 +#define REG_TS 0x03c4 +#define REG_GDC 0x03ce +#define REG_CRTC 0x03d4 + +#define PLANE_B 0x00 +#define PLANE_G 0x01 +#define PLANE_R 0x02 +#define PLANE_I 0x03 +#define setPlane(p) outport(REG_TS, 2 | (0x100 << p)) +#define setPlaneColor(c) outport(REG_TS, 2 | (c << 8)) +#define setAllPlanes() setPlaneColor(0x0f) + +#define setWriteMode(m) outport(REG_GDC, 0x05 | (m << 8)) +#define setBitMask(m) outport(REG_GDC, 0x08 | (m << 8)) + +#define setResetEnabled(m) outport(REG_GDC, 0x01 | (m << 8)) +#define setResetMask(m) outport(REG_GDC, m << 8) + +#define VID ((volatile char far *)MK_FP(0xa000, 0)) +#define WVID ((volatile int far *)MK_FP(0xa000, 0)) + +#define flipPage(p) outport(REG_CRTC, 0x0c | (p << 8)) + +#define setLogicalWidth(w) outport(REG_CRTC, 0x13 | (w << 8)) + +void vid_cleanup(); +void setSplitScreen(unsigned int y); +void unsetSplitScreen(); +void setDisplayOffset(unsigned int offset); +void setHorizontalPan(int offset); +