4IBM p@ >> FastCopy PRO << by Martin Backschat, Bergstr.16, D-8071 Hepberg // (c) 1991 ICP Verlag/TOS Magazin, Wendelsteinstr. 3, D-8011 Vaterstetten, Tel. 0810633954ߘ` /@`! #@%`')+-/1 3@5`79;=?A CoGIKMOQ SU`WY[]_a c@e`gikmoq s@u`y{ @` ` O o @ ` ǀ @ ` ׀ ٠  @`/o!Oa  Aa!!#A%a')+/13A5a7;=A!OoGIMOQ!SUaWY]_a!cAeagikmo/sAuawy{}!A!Aa!Aa!Aa!Aaǁɡ!Aaׁ!Aa!Aa " B b  !"!B!b!!!!!"!""#B"%b"'")"+"-"/#1"#3B#5b#7#9#;#=#?$A"$CB$Eb$G$I$K$M$O%Q"%SB%Ub%W%Y%[%]%_&a"&cB&eb&g&im&o'q"'sB'ub'y'{'}'("(B(b((((()")B)b))))*"*B*b*****+O+b+++++,",B,b,,-"-B--٢---.".B.b....` /@`! #@%`')+-/1 3@5`79;=?A CoGIKMOQ SU`WY[]_a c@e`gikmoq s@u`y{ @` ` O o @ ` ǀ @ ` ׀ ٠  @`/o!Oa  Aa!!#A%a')+/13A5a7;=A!OoGIMOQ!SUaWY]_a!cAeagikmo/sAuawy{}!A!Aa!Aa!Aa!Aaǁɡ!Aaׁ!Aa!Aa " B b  !"!B!b!!!!!"!""#B"%b"'")"+"-"/#1"#3B#5b#7#9#;#=#?$A"$CB$Eb$G$I$K$M$O%Q"%SB%Ub%W%Y%[%]%_&a"&cB&eb&g&im&o'q"'sB'ub'y'{'}'("(B(b((((()")B)b))))*"*B*b*****+O+b+++++,",B,b,,-"-B--٢---.".B.b....ICTARI 014q(ASSEMBLY d0AUTO d0C d0GFA e0MISC !e0jSTOS 1e0DESKTOP INF ICTARI TXT [0QREAD_ME TXT qnV . d0.. OVERSCAN d0SPRITE TUTd0BOUNCE d0SIF_MATH d0. d0.. d0GALLERY MUS OX3DIAMOND DSO /ZOVERSCANTXT ؘD.ICTARI1 S WE9DIAMOND2S TXODIAMOND1S h:BORDERS PC1 w,ICTARI PC1 %}HS`J``/A _NuHA a`"z@@M:tNqMp,"hMh,"hM`,"h M0,"hM ,"hM*,"h,M$PM<NuAJgCGG|?```G]LH@NuS(&jh'&"h" fn&h4$Pf!E$Prj,j*B Bf B(` f B;BA&zR6sf!K" ` f Q'Y&`z fQ'Y&!I"Nu@A AgY!I"!E8Jkp( A($zA4r!ERZrZ|@.BBZ!J @g($zA4r!J!E0EENu~G J(gS(`"h0 g f)?!@0"h fB|R0` f.    T0` f")@@"z2q!I!G0`n fiT0`D fG*i T0`< f|*R0` f |*R0` fV0ii"h0Q+R0J(gS(`NS(fHh"h  f Ti` g f)?[!@`Q-R(+k((,@C@20(!(*fVC`. f"VCh (+j D ` ( `VCJ( g(  C(.J(gS(`V((Jjf&f(dr`(eA dAeAdA G.( g~2(H$(8v ԁ!B8HBB(-((jrNuAB. ,R pACtEx!I BB(-B(B( !IB0||B(BBhB( CCZ! t!zp4ݨ4ר4ߐא!| &PA(zN8tb!L"B&|*k,B(+kB((+A Af +A(B(-B8, ~wpjd^YTOKGC?;852/,*'%#!COSO@))^TFMX/-@  ,0:DNW[iow-BR`kq(", 2 梠 攌桞䔜        效斟䓞       揝僄       哌        刍       $,8@Me{  4CKSh~%0F]n+=Sjw                                     ! " #    $ % & ' (  ) *  + ,  0  0P  . /  %Sz   ? `  # 8 A J   ) @ S f } 1 T w 5 p s z Aj K~ BSb>bEry3v0w :Ux+Pu@'tAl .Y|X]binsz 00000+@0.@0:@)@+@7@.@'@3@00<00+@7@.@.@:@)@+@7@.@'@3@000000+@.@00000+@.@0   42454+-54200/               0000000 00@ 0A 0B 0@ 0A 0@ 0A 0B 2@ 2A 2B 2@ 2A 2@ 2A 2B 0@ 0A 0B 0@ 0A /@/A /B-@-A-B-@-A-@-A -B 42454+-54200/    42454+-54200 / 0/-4240247><72<720720+20+&/+&#+&#&## 0/-97 52 020240+440+457205<505<54774477405:505:5-494-49405500550-292-292/38;/38;+/22+/22,/33,/33/27;/27;     !     ! @/+2/72;2/+2/72;2/,3/83;3/,3/83;3 +- /23/2/2383//    $ 3//                 44244774440       444 422447400++         ..00++.00344$$$@$A$$$@$$$$@$A$$$@$999 9<995500255..0 00++.++*))7777276555503 40...000+..0030077:77:<<?@@ 00++..00"3 "0077:;; <<<<<<<<77665533..CCC C>>AACC>>CCBBCCC C>>AACC>>AABB<<<<<<<<<<77665533..<<<<                           $$$"$&')+,)+000++2++0++2++3+2+0++2++0++2++3+2+             0 0 0 0 0 0 0 0 0Y0Y0Y0Y         @@@0 0 0 .Y.Y.Y    @@@@@@"@$0000++.0066553005330..0000++..00*))''$$**))''$$ @ @@ @ @ @ @@ @ @@ @ @ @ @@ @@  @ @ @@@@$$0202357858 53.00+'2+'3+'0+'2+.+0+'2+'3+'0+'2+.00+(0+(0+(0+(0+(0/+(/+(/+(/+(/+(/-)$-)$-)$-)$-)$-/+&/+&/+&/+&/+&/     P           ( (&((&++(++(++-----++)-+ +( (+0//-//-//-----++)-+ +& &&& 0 &## !$#$&$&( ++0/+(&()-059<;7272/2/+/+&+&#&+@+@+@+@+@((@((@(@)@)@)@)@)@+@+@+@+@+@' (+---++((($$ $$$""$$" $$$""$$&((+))$)))''$$""$$$$$"" (0(0(0$0(00035785753023557875770357857530235320.3.00                                  302352320+.022353233+02352320+.000.++0+++$$$$$$$$$@$@$@$@$@$@$@$@       0000+..00+.+55335330000.....),.....0200000+.00<<7:653        $@$@$@$@$@$@$@$@&&&&&&&&         $$$$$$$$$$$$$$$$0$2&3'2&3'57+5)3'2&3'2$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@0$2&4(2&4(57+5)4(2&4(200+.,)+',+'$&             0.+),+'+)'$ &                                                  *(')*(+')+*(+')+*(,'),*(-')-*(.').*(.'):*(0')/13023/19 029 /14025/16028/14025/16027/13023/19 029 /14 025 /16 02; /14 025 /16 027 /ACABECDEAFECGEABECJEABECDEAHECIEABECJEALECMEAKECNECOEAPECQEAECEAECEAECEAERRRSRSRSTRSURSURSURSVRSWRSXRSYR[ZR[ZR[ZR[ZR\ZR\Z]\Z]\Z]\Z]\Z]\Z]\Z]\Z ]\Z ]\Z ]\Z ]\Z ]\Z ]\Z ^`_a^`bc^`d_ae^`f_ag^`d _ae ^`f _ag ^hd_ie^hf_ig^`d_ag^`j_a^`k^`l^`m^`l^`n^`o^`o^`p^`p^`p^`p^hp^hp^`p^`p^`p^`p^`o^`^`o^`^ho^h^`o^`^`o^`^`o^`^ho^hq^`o^`trustvruwszxr}ys|xr{ysz xr} ys| xr{ ys~xrysxrysxr ysxr ysxr ysxr ys<<==<<<<<<<><>=>=><><><>=><><>            CD_`~  ,#* % 4! ",#$@x<(d@z= p@ x8@ @@|# ? `?|@@>00 p@@? @@}|C<<y@@ VQa>?2! x8:x>00x' 0 x>}||>x||s0=  `8x&( 8z`ςs|C<@8p@@<~ 0|3p>0  ^ a G8 0l~qtxs~{ , cC<`! #*1|0~a;8'|G8p0p~>?`=1X GpB/0# |@T4= ? } W 0^0) `G80p~?P Pcx@?70/  x >#80:9 ㄃l: $$E8> 0n~<<0  p0#|><s@?lr $.$ GAx60~~8p ` 8 8"7c1_@?`I7>'N'@ ?0~~ xB q9(' 8# <#c9l7<8??80l||px@Ap8 `? @:A|> 00l ??80?ppppg@@g$00b>`M@? @(H0axxd'$8|&?8ppxB|CX,?.x8HAd D788;<p00Nx  y8x?0q07p8 #<?>~x6& `ǐx8P$8pc?!0@>p88>~6~G? 8 x >pXG;@Cp>88>~\ #@?`"!::9><?|@~xhpxp3 !898>pp8 7H?gǀ38<`xxx~8D8p`r0 8> 0x< xC@880<>8<~>?0Gx80x|9F8p(p8p H7 ?:<0>~s O>w@G8~ p9|ʏ5pp?DG8lc8FfG8@;2  a@>pp;C<~@> ? @# <; %xxA>!@p###? >0<>8p>pys  #>!:@ $8 x pp!!x|c|<&>0xN>h`@ !0 880Äpp8p? s|>.0p? 8 #c<80 pp <`?|1>?>60qO@pxG8<w@``X0x/  _?p<# `p~#@.  dx?}>080@@x>0|0 >X@@8x&(7 yǸ0?# ^ aG80}= BA|pG80ppr' `G80px^X 6ppE8 >0`8 ? 0 @@1 ;<p9p ?#<>? @G8~>6~~@?08>N>x>yCy<@@x@p>pt< AA\=  >0p 98 &`#2 >8s` #%>8<8avd 0@:<00πv J2p>1t@H0p @>`p>8px p` &>0p??:x>.0 x@ yF8>60?<`|#?    x@@8 2 xx?qa@>@?`7/'    _? @@ ^>d>00> a߁@s|s0=8' ?p< +(p |x>00s x8sbo |3p>08AK0<s~>ǀ8|x&( ? %@ 8 !1 aO@<߄x(^B<|C?q?2P.`@|pGx8p0` 08!A~?< l0 |߄x0/>$?``hGp80>@ x |D?? 0?c@8 r>9> J9@ ?p@ GA`x60l8rp ?܀|8>``xn"bX0M>.1/@ ?` ?0`8@8x< @|00q>Xvr D4z `<1 ?pp??8p0xx>8paxx?0 d|dzy y= >| p@@??8`0?88~?8x.8xvpId@!(&{?C@ $>`&?8`p(<`8x #<?0d0`8c&$1AA0`;<`p 80dL?00AB~<!@! >#<`?><@8A8@@< !X<|! pp@ {$؇@H< |x8>`~6ps#?@8$>#`1000`  `?dAO? x88>`y? 8o0c#@@?@# @?b@C@_>0@@> z5p88Ώ0c\qC<`'&&` >   rr # ?xx8``>ppR"gx`8@߼ |`a.`.9>? ' Dx|8`> 0@0@@C<@?x̀2~qp0 y@@><@@~ 88/ 8 8`&dD@@<00ᄟx('pG? \" `@<|?8@8 >`8`^ !8><(p8p qp`  x` "?? 8 <8>p8<0(  88s|?DpG8<p !f%`d O7 ??00>8:`<0 6@8p;xC<a` 0C? @@! 8t>P 8|  ###?   0!΀HIp8<>0pp8!!x`y<@ Ax@@3A 8 p>8p @188?px @x~x8 &>00??D 88 |G@7x88 <>.0???p?p/@0@ |X`0x |' v888>  60pp>(' 800 p<p? p ?<x`9?>pp(d8_!00@@ @  @ @@@ P(@z= }8:G8@8À|0X@@`E{# o<@?g<|= BA?' xM@@P``6ppx$$$r<O@Pp~xy$ $p>88}>xBA<8`|8<~ 808#X,>>x@>?``39660 <?1   8\ qp @Fx~`@G`?#80?0y@C?9x| F8Ё(x@a80 AA\= x!!: #2   @/` #%8QN?vd 1@x>Q8pv J2p~px t@H0p @>8wx=  `p"<GGG8>!~@ x p` 0>CC<:x8>##p yF88> x?r >p $@ A> @0@H0 8 @ ?`@@p D`8~|`a @wP`z<@@@|?8 ' <<~|aa?@ay_C<qtp$$op`/p_@GG?AqMPA ?@@ËB0 <q=` 80d\?F @8p@`@p9??H0z  }<}p`   p` gcF@y?x0@p 0NA |  !p<`! 0?P0xÞ#8z <1 < xt( l0@~@@ p|`!`x`( 0@@pt0NA  x^?x>xx<#?;@l <`@@`\l02HHHx~9 |p4 &   ??1x@@ ~` |< x8H@Hf`98@6p<Cp !tpx``rA8# <|pp|8xxpC<x@GcX |L@CpA!|s <@cA,@x#AA>wx|?|p<q2|>r gs<ll` x~A<08@@?@@0Gx|~|xcw82r cAp@>q04{y@@@pp| lx/@G2Ox0h?#  |@``s p /0q|| A@@ `@N&2?} qG ?p`x 89@0| H pA4|||| $8G<\~`@>?8a8`r`x<BD8 pa?||/`?0 89pP ={@ !xq? |A?`  ap<p`@ )rp@3 |#>"@88<0L? 0@@p Ð0p` ={@x0@qx@@F J2"#  p<?cxd h` `@p@8x| 8`{0F@@0/cc3#|?!p8? ` p0&`@ x?x? ? p| p9PF30d!8>?t3 (|2x>p` | p| 0000` p |p8{ @x%& @|@0 p`8@L |` ?t(D4 x 0 Џp|C@8@t|d| \ `1|0<n @`|x1<p"~`| l`8p`@pxN<tp|pGG88<$$yp>"p88 ?/@=0 and n<=127 then no rept for n+1 ; -127 <= n <= -1 ; n>=-127 and n<=-1 then rept for -n+1 ; n = -128 ; no operation. move.w #199,d7 ; scan lines .UNCOMP0: moveq.w #3,d6 .UNCOMP1: move.l #_DEGASBUFF,a3 .UNCOMP2: move.b (a0)+,d0 ext.w d0 cmp.b #-128,d0 ; ignore. beq.s .UNCOMP2 cmp.b #-1,d0 ble.s .REPT .LOOP1: move.b (a0)+,(a3)+ ; no repeat. dbra d0,.LOOP1 cmp.l #_DEGASBUFF+40,a3 blt.s .UNCOMP2 bra.s .DUMP_SCANLINE .REPT: neg.w d0 move.b (a0)+,d1 .LOOP2: move.b d1,(a3)+ ; repeat. dbra d0,.LOOP2 cmp.l #_DEGASBUFF+40,a3 blt.s .UNCOMP2 .DUMP_SCANLINE: move.l #_DEGASBUFF,a3 ; dump completed move.l a2,a6 ; uncompressed scan line REPT 20 ; plane too screen. move.w (a3)+,(a2)+ addq.l #6,a2 ENDR lea.l 2(a6),a2 dbra d6,.UNCOMP1 lea.l 152(a2),a2 dbra d7,.UNCOMP0 rts *************************************************************************** * DRAW THE BACKGROUND * * Don't use this drawing routine because it's too slow in main loops!!!!! * *************************************************************************** draw_back1 dl1 i set 0 set to 0 rept 3 repeat chunks (1 chunk=16 pixels) move.l i(a2),i(a0) copy 1st half of a chunk (logical) move.l i+4(a2),i+4(a0) copy 2nd half a chunk (logical) i set i+8 next chunk endr end of copying chunks add.l #scan2,a0 next scanline line for logical add.l #scan1,a2 next scanline line for piccy dbf d1,dl1 end of copying lines rts draw_back2 move #199-1,d1 ;lines dl2 i set 0 set to 0 rept 20 repeat chunks (1 chunk=16 pixels) move.l i(a2),i(a0) copy 1st half of a chunk (logical) move.l i+4(a2),i+4(a0) copy 2nd half a chunk (logical) i set i+8 next chunk endr end of copying chunks add.l #scan2,a0 next scanline line for logical add.l #scan1,a2 next scanline line for piccy dbf d1,dl2 end of copying lines rts *************************************************************************** * DRAW THE ICTARI PICTURE * * A Crap way of drawing it but who cares? * *************************************************************************** draw_ictari move.l #pc1_bord,a0 move.l #palette,a1 move.l #bord,a2 bsr unpack_pc1 move.l #pc1_ictari,a0 move.l #palette,a1 move.l #ictari,a2 bsr unpack_pc1 move.l #bord,a2 move.l screen,a0 copy to the left add.l #160*1,a0 hand side of the screen add.l #230*28,a0 add.l #8,a0 move #198-1,d1 lines jsr draw_back1 move.l #bord,a2 move.l screen,a0 copy to the right add.l #160*1,a0 hand side of the screen add.l #230*28,a0 add.l #8*23,a0 move #199-1,d1 lines jsr draw_back1 move.l #ictari,a2 move.l screen,a0 copy to the right add.l #160*1,a0 hand side of the screen add.l #230*28,a0 add.l #8*4,a0 jsr draw_back2 i set 0 draw the top of the sky rept 10 move.l #bord,a2 add.l #8*7,a2 move.l screen,a0 add.l #160*1,a0 add.l #i,a0 move #29-1,d1 lines jsr draw_back1 move.l #bord,a2 draw the water in the bottom add.l #75*160,a2 add.l #8*7,a2 move.l screen,a0 add.l #160*1,a0 add.l #230*(199+29),a0 sub.l #8*5,a0 sub.l #2,a0 add.l #i,a0 move #50-1,d1 lines jsr draw_back1 i set i+8*3 endr rts *************************************************************************** pc1_bord incbin "a:\assembly\overscan\borders.pc1" pc1_ictari incbin "a:\assembly\overscan\ictari.pc1" high_mess dc.b 27,"E",27,"p" cls, inverse on dc.b "Sorry but this program needs more than two colours..." dc.b 27,"q",0 inverse off, null even mon dc.b 8 code for mouse on moff dc.b 18 code for mouse off old4 dc.l 0 old interupts oldtb dc.l 0 old07 dc.b 0 old09 dc.b 0 old0f dc.b 0 old11 dc.b 0 old1b dc.b 0 oldtimera dc.l 0 timera1 dc.l 0 timera2 dc.l 0 timera3 dc.l 0 timera4 dc.l 0 section bss oldres ds.b 2 old resolution oldscr ds.l 4 old screen address oldpal ds.b 32 old palette screen ds.l 1 drawing scr ds.l 1 scr_xor ds.l 1 oldsp ds.l 1 old stack pointer ds.l 100 blank ds.b 32 palette ds.b 32 bord ds.b 32000 ictari ds.b 32000 screens ds.b 64000 space for physical screen ds.b 64000 space for logical screen ; not the actuall size!!! _DEGASBUFF: ds.b 40 *************************************************************************** * * * STFM Overscan - Source code (c) Diamond Software 1994 * * Source Code - Steven J * * Graphics - ????? (From Punish Your Machine) * * * * - Set your tabs to 10 * * - Assemble with GENST V2+ * * - Does not work on STEs (Thanks Nik B!) * * * * The left & right border removing routines are controled by Timer B. * * This means that you don't have to clock cycle you routine in the vbl, * * but it does means that graphics will be distorted! * * * * This version draws and pic, plays music, draw loads of raster that move * * with the music and also does a palette raster fading thing!!! * * * *************************************************************************** scan1 equ 160 left & right borders on scan2 equ 230 left & right borders off scan3 equ 180 left or right border off bsr setup setup picture, screen etc mainloop cmp.b #57,$fffffc02 is space pressed?... bne mainloop no. keep looping bra exit yes, quit *************************************************************************** * EXIT * * Restore all that was changed * *************************************************************************** exit bsr mfp_off restore old interupts bsr stop_music stop the music playing move.b #2,$fff820a move.w oldres,-(sp) set old resolution move.l oldscr,-(sp) set old physical screen address move.l oldscr,-(sp) set old logical screen address move.w #5,-(sp) set screen trap #14 call xbios add.l 12,sp adjust stack bsr resetoldpal reset the old palette move.l #mon,-(sp) mouse on clr.w -(sp) keep old move.w #25,-(sp) trap #14 call xbios addq.l #8,sp adjust the stack move.l oldsp,-(sp) reset old stack address move.w #32,-(sp) set in supervisor mode trap #1 call gemdos addq.l #6,sp adjust the stack clr.l -(sp) quit trap #1 *************************************************************************** * SETUP * * Setup the screens, resolution, picture etc... * *************************************************************************** setup clr.l -(sp) keep old stack move.w #32,-(sp) call supervisor trap #1 call gemdos addq.l #6,sp adjust the stack move.l d0,oldsp save old supervisor bsr setscreen setup the screens and res bsr mouse_off turn the mouse off bsr start_music setup the music bsr savepal save and set the palette bsr draw_backgrnd draw the full screen ictari picture bsr mfp_on save and install interupts rts *************************************************************************** * SETUP THE SCREENS AND RESOLUTION IF WE CAN * *************************************************************************** setscreen move.w #4,-(sp) get screen res trap #14 call xbios addq.l #2,sp adjust stack cmp.b #2,d0 are we in high res? beq high yes, quit move.w d0,oldres save old res move.w #3,-(sp) get screen address trap #14 call xbios add.l #2,sp adjust stack move.l d0,oldscr save old screen move.l #screens,d0 clr.b d0 move.l d0,screen move.l d0,d1 add.l #64000,d1 eor.l d0,d1 move.l d1,scr_xor move.w #0,-(sp) low resolution move.l screen,-(sp) physical screen address move.l screen,-(sp) logical screen address move.w #5,-(sp) set screen trap #14 call xbios add.l #12,sp adjust stack move.l #screen,a6 move.l (a6),d6 move.l d6,4(a6) move.l scr_xor,d0 eor.l d0,d6 move.l d6,screen lsr.l #8,d6 move.l #$ffff8201,a5 movep.w d6,(a5) rts *************************************************************************** * WE'RE IN HIGH REZ * *************************************************************************** high move.l #high_mess,-(sp) get the high res message move.w #9,-(sp) print it to the screen trap #1 gemdos add.l #6,sp restore stack move.w #8,-(sp) wait for a key trap #1 gemdos add.l #2,sp restore stack clr.l -(sp) quit trap #1 gemdos *************************************************************************** * SETUP THE MUS TO PLAY * *************************************************************************** start_music move #1,d3 min music number move #9,d4 max music number bsr random random music number! jsr music setup the music rts *************************************************************************** * STOP THE MUSIC * *************************************************************************** stop_music moveq #0,d0 music no. 0 jsr music set music move.b #8,$ffff8800 chanel A clr.b $ffff8802 no volume move.b #9,$ffff8800 chanel B clr.b $ffff8802 no volume move.b #10,$ffff8800 chanel C clr.b $ffff8802 no volume rts *************************************************************************** * TURN THE MOUSE OFF * *************************************************************************** mouse_off move.l #moff,-(sp) mouse off clr.w -(sp) keep old move.w #25,-(sp) trap #14 call xbios addq.l #8,sp adjust the stack rts *************************************************************************** * RESET OLD PALETTE * *************************************************************************** resetoldpal movem.l oldpal,d0-d7 get our old palette movem.l d0-d7,$ffff8240 set it rts *************************************************************************** * SAVE THE PALETTE * * *************************************************************************** savepal movem.l $ffff8240,d0-d7 get entire palette movem.l d0-d7,oldpal save palette movem.l pal1,d0-d7 get new palette movem.l d0-d7,$fff8240 set palette rts *************************************************************************** * RANDOM NUMBER * * * d3=min / d4=max / d0=result * *************************************************************************** random addq.l #1,d4 move.w #17,-(a7) trap #14 addq.w #2,a7 and.l #$ffff,d0 sub.l d3,d4 divu d4,d0 swap d0 and.l #$ffff,d0 add.l d3,d0 rts *************************************************************************** * SAVE AND INSTALL INTERUPTS * *************************************************************************** mfp_on: move.l $120,oldtb save old timer B vector move.l $70,old4 save old vb vector move.l $134,oldtimera old timer A move.b $fffffa07,old07 timer B enable move.b $fffffa09,old09 timer C enable move.b $fffffa0f,old0f timer B in-service move.b $fffffa11,old11 timer C in-service move.b $fffffa1b,old1b timer B control and.b #$df,$fffa09 disable timer C and.b #$fe,$fffa07 disable timer B move.b $fffffa07,timera1 interupt enable a move.b $fffffa13,timera2 interupt mask a move.b $fffffa19,timera3 timer a control move.b $fffffa1f,timera4 timer a data clr.b $fffffa19 empty timer a data move.b #$21,$fffffa07 disable interupt a move.b #$21,$fffffa13 set mask a bclr #3,$fffffa17 reset vector base move.l #topbord,$134 put top border rout in timer a move.l #new_vbl,$70 new vb vector move.l #left_n_right,$120 new timer B or.b #1,$fffffa07 enable timer B or.b #1,$fffffa13 set timer B mask rts *************************************************************************** * RESET INTERUPTS * *************************************************************************** mfp_off: move.w sr,-(sp) save move.w #$2700,sr cut out all interrupts move.b old07,$fffffa07 restore all old vectors move.b old09,$fffffa09 timer c enable move.b old0f,$fffffa0f timer b in-service move.b old11,$fffffa11 timer c in-service move.b old1b,$fffffa1b timer b control move.b timera1,$fffffa07 interupt enable a move.b timera2,$fffffa13 interupt mask a move.b timera3,$fffffa19 timer a control move.b timera4,$fffffa1f timer a data move.l oldtimera,$134 timer a interupt move.l oldtb,$120 old timer b move.l old4,$70 old vbl move.w (sp)+,sr retore rts return *************************************************************************** * VBLANK ROUTINE * * BSR / BSR.S and JSR takes a massive 36 cycles!! - don't use them! * * The vu routines were coded by UNT - everything else by me! * *************************************************************************** new_vbl clr.b $fffffa19 stop timer A... move.b #100,$fffffa1f set data move.l #topbord,$134 top border rout. move.b #4,$fffffa19 start timer A again clr.b $fffffa1b stop timer b move.b #7,$fffffa21 scan line move.l #left_n_right,$120 timer B rout move.b #8,$fffffa1b start timer B agian ;>> Strange colour routine not.b slower execute only every other VBL tst.b slower ...to slow it down a bit! beq exit_col exit my colour routine addq #2,offset2 increment pointer in palette cmp #560,offset2 time to wrap? bne.s carryon no. not yet clr offset2 yes, clear counter 'coz we have ; reached the end of the palettes! carryon move.l #buffer2,a1 get the buffer move.l #cols,a0 and the colours move.w offset2,d0 get the pos through the cols add d0,a0 and add them to the colour ; to get the correct colours copy move.l (a0),(a1)+ draw the colours move.l 2(a0),(a1)+ move.l 4(a0),(a1)+ move.l 6(a0),(a1)+ move.l 8(a0),(a1)+ move.l 10(a0),(a1)+ move.l 12(a0),(a1)+ move.l 14(a0),(a1)+ move.l 14(a0),(a1)+ move.l 12(a0),(a1)+ move.l 10(a0),(a1)+ move.l 8(a0),(a1)+ move.l 6(a0),(a1)+ move.l 4(a0),(a1)+ move.l 2(a0),(a1)+ move.l (a0),(a1)+ exit_col ;>> VU colour bar routine jsr music+8 play music move.l #buffer,a0 get the bars rept 25 clear 'em clr.l (a0)+ er, clear and increment clr.l (a0)+ clr.l (a0)+ clr.l (a0)+ endr lea $ffff8800.w,a1 get soundchip... move.b #8,(A1) on chanel A move.b (a1),d0 get amplitude and #7,d0 mask off lower 8 bits move d0,d1 save volume coz we're using to count move.l #bar_1,a0 copy the volume to bar 1 copy1 move d0,-(a0) do the top part move d0,-(a0) and again because I want it bigger dbf d0,copy1 repeat for the volume move.l #bar_1,a0 copy to the bar again .copy move d1,(a0)+ but this time draw a bottom bar move d1,(a0)+ and again because I want it bigger dbf d1,.copy repeat for the volume move.b #9,(A1) chanel B move.b (a1),d0 the rest of this routine and #7,d0 is basicly the same as above move d0,d1 expect for chanel number move.l #bar_2,a0 copy2 move d0,-(a0) move d0,-(a0) dbf d0,copy2 move.l #bar_2,a0 .copy move d1,(a0)+ move d1,(a0)+ dbf d1,.copy move.b #10,(A1) chanel C move.b (a1),d0 and #7,d0 move d0,d1 move.l #bar_3,a0 copy3 move d0,-(a0) move d0,-(a0) dbf d0,copy3 move.l #bar_3,a0 .copy move d1,(a0)+ move d1,(a0)+ dbf d1,.copy rte *************************************************************************** * REMOVE THE LEFT AND RIGHT BORDER AND RASTER ROUTINES - Steven J * * Routine adapted from Powerman. Now uses less registers and time. * * Err, it does'nt use less registers now because of the top vu bars!!! * * * * If you want to put anything in here then you have to change the number * * of 'nops'. I'll show you how in the documentation i'm currently doing.. * *************************************************************************** left_n_right clr.b $fffffa1b stop timer B move.w #$2700,sr cut out all interupts move.l #$ffff8209,a0 lowbyte of video address counter move.l #$fffffa21,a1 timer b data (i.e. scanline) moveq.w #0,d0 clear register moveq.w #0,d1 clear register moveq.w #16,d2 delay move.b #10,(a1) scanline move.b #8,$fffffa1b.w start timer b move.b (a1),d3 get scanline .l1 cmp.b (a1),d3 are we at the start of it? beq .l1 no, keep on trying .l2 move.b (a0),d0 make sure we start on right line beq.s .l2 if not, keep trying sub.w d0,d2 sub start from delay lsl.w d2,d0 get correct amount of cycles clr.b $fffffa1b.w stop time b dcb.w 62,$4e71 wait until we're in the border lea $ffff820a.w,a0 synchronisation mode (Hz) lea $ffff8260.w,a1 picture resolution lea bar_1,a2 vu palette 1 lea bar_2,a3 vu palette 2 lea bar_3,a4 vu palette 3 lea pal1,a5 blank space moveq.w #2,d1 high res/50Hz moveq.w #0,d2 low res/60Hz ;>> Overscan 25 lines and draw the top 3 vu bars on the same line move.w #25-1,d0 set number lines to overscan .no_lines0 dcb.w 10,$4e71 move into the left border move.b d1,(a1) set high res move.b d2,(a1) set low res (left border) move.w (a5),$fff8240 draw a blank space move.w (a2)+,$fff8240 draw the vu bar 1 colours dcb.w 25,$4e71 delay (space for next bar) move.w (a5),$fff8240 draw a blank space move.w (a3)+,$fff8240 draw the vu bar 2 colours dcb.w 20,$4e71 delay (space for next bar) move.w (a5),$fff8240 draw a blank space move.w (a4)+,$fff8240 draw the vu bar 3 colours dcb.w 14,$4e71 move into the right border move.b d2,(a0) set 60Hz move.b d1,(a0) set 50Hz dcb.w 13,$4e71 move into far right/left border move.b d1,(a1) set high res nop pause for 4 cycles move.b d2,(a1) set low res dbf d0,.no_lines0 end of repeat ;>> These vu bars are different so we're do a new overscan part! lea buffer,a2 all vu paletted (bars 1,2,3) dcb.w 4,$4e71 move into the left border move.w #224-30-1,d0 set number lines to overscan .no_lines1 move.b d1,(a1) set high res move.b d2,(a1) set low res move.w (a2)+,$fff8240 draw the vu bar cols (20 cycles) dcb.w 89-5,$4e71 move into the right border move.b d2,(a0) set 60Hz move.b d1,(a0) set 50Hz dcb.w 13,$4e71 move into far right/left border move.b d1,(a1) set high res nop pause for 4 cycles move.b d2,(a1) set low res dcb.w 10,$4e71 move into the left border dbf d0,.no_lines1 end of repeat ;>> Bottom border removing routine - took ages to time this! move.b d1,(a1) set high res move.b d2,(a1) set low res dcb.w 85,$4e71 move into the border lea buffer2,a2 get the colours move.b d2,(a0) set 60Hz move.b d1,(a0) set 50Hz dcb.w 12,$4e71 small delay move.b d2,(a0) set 60Hz move.b d1,(a1) set high res nop pause for 4 cycles move.b d2,(a1) set low res moveq.w #45-1,d0 no. lines in the bottom border dcb.w 9,$4e71 pause move.b d1,(a0) set 50hz .no_lines2 move.b d1,(a1) set high res move.b d2,(a1) set low res move.w (a2)+,$fff8240 draw the fading(?) colours (5 nops) dcb.w 89-5,$4e71 move into the border move.b d2,(a0) set 60Hz move.b d1,(a0) set 50Hz dcb.w 13,$4e71 small delay move.b d1,(a1) set high res nop wait for 4 cycles move.b d2,(a1) set low res dcb.w 10,$4e71 move into the border dbf d0,.no_lines2 keep overscaning the scanline bclr #0,$ffffa0f rte *************************************************************************** * TOP BORDER REMOVING ROUTINE - REMOVES 28 SCANLINES * *************************************************************************** topbord move.w #$2100,sr set status register stop #$2100 wait for interupt clr.b $fffffa19 disable timer a dcb.w 78,$4e71 wait until we're in the border clr.b $ffff820a change to 60HZ dcb.w 2,$4e71 pause for hertz delay move.b #2,$ffff820a set it back to 50hz. NO TOP BORDER rte return from interupt *************************************************************************** * DRAW THE BACKGROUND * * Don't use this drawing routine because it's too slow in main loops!!!!! * *************************************************************************** draw_back1 move #210-1,d1 lines dl1 i set 0 set to 0 rept 25 repeat chunks (1 chunk=16 pixels) move.l i(a2),i(a0) copy 1st half of a chunk (logical) move.l i+4(a2),i+4(a0) copy 2nd half a chunk (logical) i set i+8 next chunk endr end of copying chunks add.l #scan2,a0 next scanline line for logical add.l #scan2,a2 next scanline line for piccy dbf d1,dl1 end of copying lines rts *************************************************************************** * DRAW THE PICTURE * *************************************************************************** draw_backgrnd move.l #name1,a2 copy our names add.l #160*9,a2 add 9 scanline move.l screen,a0 add.l #160*9,a0 miss 9 scanlines add.l #230*9,a0 add another 9 scanlines jsr draw_back1 draw rts *************************************************************************** name1 incbin "d:\assembly\overscan\diamond.dso" music incbin "d:\assembly\overscan\gallery.mus" even offset dc.l 0 buffer ds.w 48 start pos. dcb.w 0,0 bar_1 dc.w 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 dcb.w 26,0 space out each bar bar_2 dc.w 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 dcb.w 26,0 bar_3 dc.w 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 dcb.w 28,0 buff_end ds.w 72+60 pal1 dc.w $0000,$0211,$0211,$0321,$0332,$0433,$0443,$05C4 dc.w $0555,$0665,$0666,$0777,$0210,$0200,$0100,$0777 high_mess dc.b 27,"E",27,"p" cls, inverse on dc.b "Sorry but this program needs more than two colours..." dc.b 27,"q",0 inverse off, null even mon dc.b 8 code for mouse on moff dc.b 18 code for mouse off old4 dc.l 0 old interupts oldtb dc.l 0 old07 dc.b 0 old09 dc.b 0 old0f dc.b 0 old11 dc.b 0 old1b dc.b 0 oldtimera dc.l 0 timera1 dc.l 0 timera2 dc.l 0 timera3 dc.l 0 timera4 dc.l 0 section bss oldres ds.b 2 old resolution oldscr ds.l 4 old screen address oldpal ds.b 32 old palette screen ds.l 1 drawing scr ds.l 1 scr_xor ds.l 1 oldsp ds.l 1 old stack pointer ds.l 100 screens ds.b 64000 space for physical screen ds.b 64000 space for logical section data offset2 dc.w 0 counter slower dc.b 0 will either be 0 or 1 pointer dc.l 0 pointer to next color cols dc.l 0,0,0,0,0,0,0,0,0,0,0,0 dc.w $111,$222,$333,$444,$555,$666,$777,$777 dc.w $666,$555,$444,$333,$222,$111,$000,$000 dc.l 0,0,0,0,0,0,0,0,0,0,0,0 dc.w $011,$022,$033,$044,$055,$066,$077,$077 dc.w $066,$055,$044,$033,$022,$011,$000,$000 dc.l 0,0,0,0,0,0,0,0,0,0,0,0 dc.w $101,$202,$303,$404,$505,$606,$707,$707 dc.w $606,$505,$404,$303,$202,$101,$000,$000 dc.l 0,0,0,0,0,0,0,0,0,0,0,0 dc.w $110,$220,$330,$440,$550,$660,$770,$770 dc.w $660,$550,$440,$330,$220,$110,$000,$000 dc.l 0,0,0,0,0,0,0,0,0,0,0,0 dc.w $010,$020,$030,$040,$050,$060,$070,$070 dc.w $060,$050,$040,$030,$020,$010,$000,$000 dc.l 0,0,0,0,0,0,0,0,0,0,0,0 dc.w $100,$200,$300,$400,$500,$600,$700,$700 dc.w $600,$500,$400,$300,$200,$100,$000,$000 dc.l 0,0,0,0,0,0,0,0,0,0,0,0 dc.w $001,$002,$003,$004,$005,$006,$007,$007 dc.w $006,$005,$004,$003,$002,$001,$000,$000 dc.l 0,0,0,0,0,0,0,0,0,0,0,0 ;extras dc.l 0,0,0,0,0,0,0,0,0,0,0,0 dc.w $101,$202,$303,$404,$505,$606,$707,$707 dc.w $606,$505,$404,$303,$202,$101,$000,$000 dc.l 0,0,0,0,0,0,0,0,0,0,0,0 dc.w $110,$220,$330,$440,$550,$660,$770,$770 dc.w $660,$550,$440,$330,$220,$110,$000,$000 buffer2 ds.w buffer2-cols store for shifted colors *************************************************************************** * * * STFM Overscan - Source code (c) Diamond Software 1994 * * Original Overscan - Neil (Powerman of TWB - The Wild Boys) * * New Source Code - Steven J * * Font Graphics - ???? * * * * - Set your tabs to 10 * * - Assemble with GENST V2+ * * - Does not work on STEs (Thanks Nik B!) * * * * The left & right border removing routines are controled by Timer B. * * This means that you don't have to clock cycle you routine in the vbl, * * but it does means that graphics will be distorted! (put you routine in * * the vbl) * * * * This version only draw a picture and plays some music. The upper and * * lower border and switched off but I did'nt put anything in them! * *************************************************************************** scan1 equ 160 left & right borders on scan2 equ 230 left & right borders off scan3 equ 180 left or right border off bsr setup setup picture, screen etc mainloop cmp.b #57,$fffffc02 is space pressed?... bne mainloop no. keep looping bra exit yes, quit *************************************************************************** * EXIT * * Restore all that was changed * *************************************************************************** exit bsr mfp_off restore old interupts bsr stop_music stop the music playing move.b #2,$fff820a move.w oldres,-(sp) set old resolution move.l oldscr,-(sp) set old physical screen address move.l oldscr,-(sp) set old logical screen address move.w #5,-(sp) set screen trap #14 call xbios add.l 12,sp adjust stack bsr resetoldpal reset the old palette move.l #mon,-(sp) mouse on clr.w -(sp) keep old move.w #25,-(sp) trap #14 call xbios addq.l #8,sp adjust the stack move.l oldsp,-(sp) reset old stack address move.w #32,-(sp) set in supervisor mode trap #1 call gemdos addq.l #6,sp adjust the stack clr.l -(sp) quit trap #1 *************************************************************************** * SETUP * * Setup the screens, resolution, picture etc... * *************************************************************************** setup clr.l -(sp) keep old stack move.w #32,-(sp) call supervisor trap #1 call gemdos addq.l #6,sp adjust the stack move.l d0,oldsp save old supervisor bsr setscreen setup the screens and res bsr mouse_off turn the mouse off bsr start_music setup the music bsr savepal save and set the palette bsr draw_backgrnd draw the full screen ictari picture bsr mfp_on save and install interupts rts *************************************************************************** * SETUP THE SCREENS AND RESOLUTION IF WE CAN * *************************************************************************** setscreen move.w #4,-(sp) get screen res trap #14 call xbios addq.l #2,sp adjust stack cmp.b #2,d0 are we in high res? beq high yes, quit move.w d0,oldres save old res move.w #3,-(sp) get screen address trap #14 call xbios add.l #2,sp adjust stack move.l d0,oldscr save old screen move.l #screens,d0 clr.b d0 move.l d0,screen move.l d0,d1 add.l #64000,d1 eor.l d0,d1 move.l d1,scr_xor move.w #0,-(sp) low resolution move.l screen,-(sp) physical screen address move.l screen,-(sp) logical screen address move.w #5,-(sp) set screen trap #14 call xbios add.l #12,sp adjust stack move.l #screen,a6 move.l (a6),d6 move.l d6,4(a6) move.l scr_xor,d0 eor.l d0,d6 move.l d6,screen lsr.l #8,d6 move.l #$ffff8201,a5 movep.w d6,(a5) rts *************************************************************************** * WE'RE IN HIGH REZ * *************************************************************************** high move.l #high_mess,-(sp) get the high res message move.w #9,-(sp) print it to the screen trap #1 gemdos add.l #6,sp restore stack move.w #8,-(sp) wait for a key trap #1 gemdos add.l #2,sp restore stack clr.l -(sp) quit trap #1 gemdos *************************************************************************** * SETUP THE MUS TO PLAY * *************************************************************************** start_music move #1,d3 min music number move #9,d4 max music number bsr random random music number! jsr music setup the music rts *************************************************************************** * STOP THE MUSIC * *************************************************************************** stop_music moveq #0,d0 music no. 0 jsr music set music move.b #8,$ffff8800 chanel A clr.b $ffff8802 no volume move.b #9,$ffff8800 chanel B clr.b $ffff8802 no volume move.b #10,$ffff8800 chanel C clr.b $ffff8802 no volume rts *************************************************************************** * TURN THE MOUSE OFF * *************************************************************************** mouse_off move.l #moff,-(sp) mouse off clr.w -(sp) keep old move.w #25,-(sp) trap #14 call xbios addq.l #8,sp adjust the stack rts *************************************************************************** * RESET OLD PALETTE * *************************************************************************** resetoldpal movem.l oldpal,d0-d7 get our old palette movem.l d0-d7,$ffff8240 set it rts *************************************************************************** * SAVE THE PALETTE * * *************************************************************************** savepal movem.l $ffff8240,d0-d7 get entire palette movem.l d0-d7,oldpal save palette movem.l pal1,d0-d7 get new palette movem.l d0-d7,$fff8240 set palette rts *************************************************************************** * RANDOM NUMBER * * * d3=min / d4=max / d0=result * *************************************************************************** random addq.l #1,d4 move.w #17,-(a7) trap #14 addq.w #2,a7 and.l #$ffff,d0 sub.l d3,d4 divu d4,d0 swap d0 and.l #$ffff,d0 add.l d3,d0 rts *************************************************************************** * SAVE AND INSTALL INTERUPTS * *************************************************************************** mfp_on: move.l $120,oldtb save old timer B vector move.l $70,old4 save old vb vector move.l $134,oldtimera old timer A move.b $fffffa07,old07 timer B enable move.b $fffffa09,old09 timer C enable move.b $fffffa0f,old0f timer B in-service move.b $fffffa11,old11 timer C in-service move.b $fffffa1b,old1b timer B control and.b #$df,$fffa09 disable timer C and.b #$fe,$fffa07 disable timer B move.b $fffffa07,timera1 interupt enable a move.b $fffffa13,timera2 interupt mask a move.b $fffffa19,timera3 timer a control move.b $fffffa1f,timera4 timer a data clr.b $fffffa19 empty timer a data move.b #$21,$fffffa07 disable interupt a move.b #$21,$fffffa13 set mask a bclr #3,$fffffa17 reset vector base move.l #topbord,$134 put top border rout in timer a move.l #new_vbl,$70 new vb vector move.l #left_n_right,$120 new timer B or.b #1,$fffffa07 enable timer B or.b #1,$fffffa13 set timer B mask rts *************************************************************************** * RESET INTERUPTS * *************************************************************************** mfp_off: move.w sr,-(sp) save move.w #$2700,sr cut out all interrupts move.b old07,$fffffa07 restore all old vectors move.b old09,$fffffa09 timer c enable move.b old0f,$fffffa0f timer b in-service move.b old11,$fffffa11 timer c in-service move.b old1b,$fffffa1b timer b control move.b timera1,$fffffa07 interupt enable a move.b timera2,$fffffa13 interupt mask a move.b timera3,$fffffa19 timer a control move.b timera4,$fffffa1f timer a data move.l oldtimera,$134 timer a interupt move.l oldtb,$120 old timer b move.l old4,$70 old vbl move.w (sp)+,sr retore rts return *************************************************************************** * VBLANK ROUTINE * * BSR / BSR.S and JSR takes a massive 36 cycles!! - don't use them! * *************************************************************************** new_vbl clr.b $fffffa19 stop timer A... move.b #100,$fffffa1f set data move.l #topbord,$134 top border rout. move.b #4,$fffffa19 start timer A again clr.b $fffffa1b stop timer b move.b #7,$fffffa21 scan line move.l #left_n_right,$120 timer B rout move.b #8,$fffffa1b start timer B agian jsr music+8 play music rte *************************************************************************** * REMOVE THE LEFT AND RIGHT BORDER * * Routine adapted from Powerman. Now uses less registers and time. * *************************************************************************** left_n_right clr.b $fffffa1b stop timer B move.w #$2700,sr cut out all interupts move.l #$ffff8209,a0 lowbyte of video address counter move.l #$fffffa21,a1 timer b data (i.e. scanline) moveq.w #0,d0 clear register moveq.w #0,d1 clear register moveq.w #16,d2 delay move.b #10,(a1) scanline move.b #8,$fffffa1b.w start timer b move.b (a1),d3 get scanline .l1 cmp.b (a1),d3 are we at the start of it? beq .l1 no, keep on trying .l2 move.b (a0),d0 make sure we start on right line beq.s .l2 if not, keep trying sub.w d0,d2 sub start from delay lsl.w d2,d0 get correct amount of cycles clr.b $fffffa1b.w stop time b dcb.w 84,$4e71 wait until we're in the border lea $ffff820a.w,a0 synchronisation mode (Hz) lea $ffff8260.w,a1 picture resolution moveq.w #2,d1 high res/50Hz moveq.w #0,d2 low res/60Hz move.w #219-1,d0 set number lines to overscan .lines1 move.b d1,(a1) set high res move.b d2,(a1) set low res dcb.w 89,$4e71 move into the right border move.b d2,(a0) set 60Hz move.b d1,(a0) set 50Hz dcb.w 13,$4e71 move into far right/left border move.b d1,(a1) set high res nop pause for 4 cycles move.b d2,(a1) set low res dcb.w 10,$4e71 move into the left border dbf d0,.lines1 end of repeat ;>> Bottom border removing routine - took ages to time this! move.b d1,(a1) set high res move.b d2,(a1) set low res dcb.w 88,$4e71 move into the border move.b d2,(a0) set 60Hz move.b d1,(a0) set 50Hz dcb.w 12,$4e71 small delay move.b d2,(a0) set 60Hz move.b d1,(a1) set high res nop pause for 4 cycles move.b d2,(a1) set low res moveq.w #45-1,d0 no. lines in the bottom border dcb.w 9,$4e71 pause move.b d1,(a0) set 50hz .no_lines2 move.b d1,(a1) set high res move.b d2,(a1) set low res dcb.w 89,$4e71 move into the border move.b d2,(a0) set 60Hz move.b d1,(a0) set 50Hz dcb.w 13,$4e71 small delay move.b d1,(a1) set high res nop wait for 4 cycles move.b d2,(a1) set low res dcb.w 10,$4e71 move into the border dbf d0,.no_lines2 keep overscaning the scanline bclr #0,$ffffa0f rte *************************************************************************** * TOP BORDER REMOVING ROUTINE - REMOVES 28 SCANLINES * *************************************************************************** topbord move.w #$2100,sr set status register stop #$2100 wait for interupt clr.b $fffffa19 disable timer a dcb.w 78,$4e71 wait until we're in the border clr.b $ffff820a change to 60HZ dcb.w 2,$4e71 pause for hertz delay move.b #2,$ffff820a set it back to 50hz. NO TOP BORDER rte return from interupt *************************************************************************** * DRAW THE BACKGROUND * * Don't use this drawing routine because it's too slow in main loops!!!!! * *************************************************************************** draw_back1 move #210-1,d1 lines dl1 i set 0 set to 0 rept 25 repeat chunks (1 chunk=16 pixels) move.l i(a2),i(a0) copy 1st half of a chunk (logical) move.l i+4(a2),i+4(a0) copy 2nd half a chunk (logical) i set i+8 next chunk endr end of copying chunks add.l #scan2,a0 next scanline line for logical add.l #scan2,a2 next scanline line for piccy dbf d1,dl1 end of copying lines rts *************************************************************************** * DRAW THE PICTURE * *************************************************************************** draw_backgrnd move.l #name1,a2 copy our names add.l #160*9,a2 move.l screen,a0 add.l #160*9,a0 add.l #230*9,a0 jsr draw_back1 rts *************************************************************************** name1 incbin "a:\assembly\overscan\diamond.dso" music incbin "a:\assembly\overscan\gallery.mus" pal1 dc.w $0000,$0211,$0211,$0321,$0332,$0433,$0443,$05C4 dc.w $0555,$0665,$0666,$0777,$0210,$0200,$0100,$0777 high_mess dc.b 27,"E",27,"p" cls, inverse on dc.b "Sorry but this program needs more than two colours..." dc.b 27,"q",0 inverse off, null even mon dc.b 8 code for mouse on moff dc.b 18 code for mouse off old4 dc.l 0 old interupts oldtb dc.l 0 old07 dc.b 0 old09 dc.b 0 old0f dc.b 0 old11 dc.b 0 old1b dc.b 0 oldtimera dc.l 0 timera1 dc.l 0 timera2 dc.l 0 timera3 dc.l 0 timera4 dc.l 0 section bss oldres ds.b 2 old resolution oldscr ds.l 4 old screen address oldpal ds.b 32 old palette screen ds.l 1 drawing scr ds.l 1 scr_xor ds.l 1 oldsp ds.l 1 old stack pointer ds.l 100 screens ds.b 64000 space for physical screen ds.b 64000 space for logical `$@@PQt0 p25c  @@   $ $1@ "1@ "D D   BD"  BD" $@  D $@  D JQV JQV ZUr] ZUr] }v_ }v_ o o~~ o o}}߿߿~~oo ޿{ ޿{{~{~ }ۿvw }ۿvw *m{*EQ *m{*EQ DUT( DUT(*UDEU*UDEU T$* T$* %[@TD %[@TD$q q $!$!tK B B@@ ! !  T  $$B!pB!p@!(  %D  %D A, $ E A, $ E@G[] @*R@*R B QDT(P B QDT(PHU*UU*UM}ڪWVM}ڪWV ۿT= ۿT= wv{n wv{noo~o~o P~~PbB# aB1$A*uH%UU  B $ .$P ߯ߕ dpo2.] 0[ xZ! }c {_=. kM\5*B   ` ߟ ߟ*!uH$@ J%4mkZ[YmkZ[YMf&,;;IQ)*m[]vm[]vqwB\]::򼾙ys/. CAf CAfww"$D"$D ~_/   tt_ @E- @E- q/ (J%H (J%H  CP CP@@8@@8 ۸xW %$G#^| %$G#^|s3J3J~B@!0B@!0w =KsӞw ´,av, ´,av,$$ wW_ *B *B Ͷm{ ]zr w7qw O v,`bر ߀ ~ `f06` 8Vs, R%1)S4!`X  @ @!.K8@ X[إaj!B X$BAXP`$@@PQt0 p25c0$H$H$HBKZBBz22f$I@0$I@B@< x@Z_ K@  @~ /z_ B  !~/h-H$O `H$ 0`H$ 0`H$ 0`H$ 0`H$ 0`H$ 0`H$ 0`H$ 0`H$ 0`H$ 0`H$ 0`H$ 0`H$ 0`H$ 0`L?? $ ? 0`H@ A@$ A 0? ?`@ H @$@ @ @@ / 0/~?@` "H'A? 9O@$"@ "@  "@_? 9_ 0X 60`$ RHH@ IHA"H$$ A@? 0>HK Y]/ 0 A m0`" HL $$H $"L D" L!?p "L D| $. 0h F0h`L I H I$@@H 0@@H/ IyK 0- @0h`(HdRH"@% H H%$Ȁ耡" (HdA$?aâȀ耡"_ K 0Z /m0Z`D"0HJ'$ H $"Da"DD"0@"Da"DK % 0 @ X0Z-`V"T2IEIV"HH R ,dHTEQRV"T!EPV"aCHTEQR~ KK 0h Z0-`']UURL%]UHT H \ꪹ']UUA]U UV \ꪹ/ Kt 0- hh0@`+K_$O) T]dWW_+_C/X|=CWW__//_ 0Zh0 E`'~rNH V@ A/m['~a}6?> m[K/__]/ 0 @0`'ݷO _@Ԁ H ۻo?v'ݷߺ?m ۻo?v_. 0h @ @0h`'L  v K}' }/O 0- @0h`Oz@% H|?_J 0Z--0h` rOK$ / a K/ 0 @-ZZ0j`MKH "W07~KK*_ 0hZ0ՠ`O/HI D08/KyT 0-hh0@`O$_/ I C?0pϥ_//y 0Zh0 V`OH _@I aw??0sK/__yR 0 @ 0`N @I %?x0߿Η?_tyҥ߿ 1h @ @0-Z`O  I Kx0Æ/tyJ 0- @-0`N@%&I %;?0w;_yҥw 1--Y0-Z`O %JI 0/JyR 0--ZZ0`N KHI  0p "ΗKKy{ 1hZi0 V`OHH.I D'av08v_'sKK*yTv_ 0 @hhц0@`O_/ ^I "_'~C?<0>w'~%_֗//^y*^w 0Zh0ՠ`O/ _@I /'~o~;?|0'~oϒ+}/[_y/ 0- A0j`O@ ~I H'w;?wx0w ݻo'w~;_t6yOwJݻo 0h @ @0h`OK I KEQ"oeAH0*ÇʢEQ"oeSID]y*Kʢ 0 @ @-0Z`O@%'I %'(]ʁ|?*00TaC޻E]|}w'(]ʓz_*)yTRg޻E]|}w 0Z--X0-Z`O %@I $EUQ*aUC0 Q"$EUQ*̩/RU%@yORQ" 0--ZZ0`O KHI dEQAUC0 pAUE'EQAT%JKyO'AUE 0hZ0 V` OHXI DD h*AA 08cU PHD h*SˠKK@yTU PH 0 @hh0x`O^< I "D "A C%?0B3 "A%D /yOA*G 0Zx0ո`O(|@I $#"@!?HD0  DB@#"@ _FyO' DB@ 0- @0j`O L I H D@ A! 0_@"!D@ S! ~yOJ@"! 0o @0l`OII H  0C!BI"yO%I!B 0 @ -0Z` O@$ %I R$ ?0!  _yO@ 0[Z0[`@O  KI 0/?HyO)R 0/0֭`O ǀID0p@yO? 0h h0V`OH /I D  @08 K @yOT 00`O _y>@ @0?? @ 'PyO>O @ 0X 0?`O K  @`B  A @P"@' A 0/@?`O  ? ?I $ @@I  0??`O @ 8p@ 8 @ 7p@? 8 0`O; AD%B % @  AD%B % @  0`O E$ / H " E$ H " 0`O REU`AU* V)U REU`ST** V)U 0`O PA*(+TQQD  ( * PA*(Ȩ(TQQD@  ( * 0?`Oo EQUGʎ*_ UQ UG EQUD( *@ UQ UG 0~?`O~_O# WVUA_U} vT WVUSP_m} vT 00`O~ =w~_ ݻ =w~zP ݻ 08`O n.}_{{ _ n.}_ ~{{ _ 0p|?`O m=   mϷoc  00|`O? a o{ sox 0`O?.m  m 0`Ov o~=OoϿ~?p 0`O  { < 0x?`O}/t= x  0 `O}S8K   A `-/w~ p/h }/__ Q_~??/_ Pz_ B ~B__ ~?z{|K?KQ???1?H_P~= ~`?> Wd c?x 8e_ O!<8U` _<U8f?X<_?g6?_`ƟO~?@ܿݿ"ݿ^;"?|>c<c<?@?~?>3~Cx~>~ coc? ؾz?/ ?ؾ8'Az?<CCoпSoп@꾦%5 e >&% @/ ` b~6 +\p b~6?  _@pI Uߧ?(/_Y) @ Ѐ?Uߧ ^/_ X +aT/oC #  (@\% H`R%ԅ '߿_}+ aT/ @ 'Β_'5he\IR^;='a@wJ 5@?T6b[B]sfԲ~?@??>?瞿Hz]3 s@?T=b[BB잻rmufHjT)`??#BlSo}'t@K1h6+rаt>#8pD@f r/@ @K1h6 rаt0O @]'D@Ηh ހ/OW @]@@UBѾ T-( @l .> _@UBѾ T!?|.!9!Z_C"% B `@AG" !?4Z_Bw"$y?7 nOB_y%ʿ_@\@Sz c6\ Q%ʿ_\@Sza@5OgKBa@/HW.0_/vOܱ@ 0@A@0܎_;@/HW.0_/vOܱзQ @MW CB^'ޠz vь`; !\! @H"CB^'ޠz vь]߀!Hzbr#Wj١U^ݭ)~RMT*!&"@(!rbr#Wj١U^ݭ)~RMT*!?&^+ց(!_EX> UJ Pm[@  B>!P0Z@T > J Pm[_ZTRU ? WJs"wAG6><݀)! { AWJs"wAG޴ z?jy@߈)KA"_tx>*W}v+֭^3 >T_tx*W=v+֭^ը‰R )Rw UYe*Wn߶vR5>P AZIA+?"*WN߶vR5>PWZBT Iz.+!/ W7k[ߺ z3}P|( 6/ Wk[ߺ z}P) @? ExJD~ LB vmK/+o(`R[@>zWן~ LB vmK/+o( R[AD%#" Ԑ@W(JY@/Bo7stwYL & 8Wp(JY@/BotwYO ߵR@"&W8H I[WI " Bc?^ [G/k\ ?Zh  Ϡ Bc?^[G/k ]@ Zh A " _ ',|W'm~_o ??_|W'm~_o  $HOW ? ^ ;;w CY}I]E8 ~ QW}@ ;;w C}I]EM ~ QĈ WKu@ AV "Wb. @  @Ku@ AV "Wb.Z H. (_+ ) oj.K?~_?_+ )oj.@w^*W >s*~7Uz>w^*PsP>HJ%PRB[[y~LU*ЍyB}  @[[y~LU*/r @b"% }:k/rFP@"пk{ZhT*sMPtF"пk{ZhT(YtF MPT /蔄@_Y95XZPBۿt/>o]USw_S/?,`z5XZPBۿt/>o]U@,`z W$$@(()'[4 U]swr( @'DPU[4 U]swr'DPU( @@QR B G _Έ $ [}w w@xRLx A1p $ [}w w@x A1pR_d@ St: v}} jN@ 7 v}}@ 7? ~$N _} pJ+_ Ӂ'p@J@ @Q@@?J@H pJ+_  J@H Ԡ@J@ @Q@@0yX@~U}u}Q@H/%%Q0@~U}u0H/%%Q/gzB:Wܶr/#Ie p/gzBWܶpИ/#Ie ۸C; p^B 6}E( 邺O$GDTp^@}E"$GDT 邺O" RwZ }[oꘓ%&o gHZ gHjI o% )>欽Bf"2)>@Bf"@Jmu?wz  6 o Q @?wzHZ Q~@@HZs H. ?-\H-\oB 2Z#Cl?%i?Z "7=% "DyO WKY @KY Ww[_-1̴?6 8-?b@ ?b@>5_v{   ? ͷ^n]ݿ"~݀   no/"݀G_cg c ]|>Tuwl]q<ϻc&ot "w 7pXp?g v_^V.A> @\zFt@t@,"߭// S[Ј w4/w??/w??fn,@֗W5A3p[ekӀ|Ӏ|';Ű?S{h^- J9ݍ,l ) X?ss'%3H%T[FM/Z~fR"  >'bO>J peg$>^# m{XQ ^+ ?B@[-8%@ii,m# JSuqE`  , ",T$*% je" ?+"4(D /a@?9N792@PC-ABNX0 R}} Y)%&@T ,tR>@?>?[ %8F` 4mp@zD@: ?'?' CtK DC b 4F   kX@X@DL9 F @@1h (t&Rb@TH H||  n$n$((@@. d0.. d0SOURCE d0MAIN PRG `tSPRITE TXT O". d0.. d0SPRITE LIB C`MAIN S O` GRAPHICSLIB 4`qPAC_HD OBJ *PAC OBJ JOYSTICKLIB -`MOUSE LIB %`***************************************************** * SPRITE SUBROUTINES * * * * (c) Nick Bates 1994 * * Last modified: 10/07/94 * ***************************************************** ***************************************************** * DRAW_SPRITE_16 * * * * Draws a 16x16 sprite to logical screen * * WITH CLIPPING: X AND Y * * * * Parameters: D0 - x cordinates * * D1 - y co-ordinates * * D2 - spite number * * sprite - pointer to sprites file * * log - logical screen * * NOTE: * * PHRASES WITHIN ****/ /***** SHOW WHERE TO * * MODIFY FOR DIFFERENT SPRITE SIZES * ***************************************************** draw_sprite_16 movem.l a0-a1/d0-d7,-(sp) STORE REGISTERS lea sprites,a1 POINTER TO SPRITE FILE move.l log,a0 POINTER TO LOGICAL SCREEN * NEED TO MOVE TO THE REQUIRED SPRITE IN THE SPRITE FILE mulu #128,d2 ****/ SPRITE SIZE : x * y / 2 : 16 * 16 / 2 = 128 /**** add.l d2,a1 ADJUST INTO SPRITE FILE TO REQUIRED SPRITE NUMBER * NEED TO CONVERT X and Y CORDINATES TO VALUES TO ADD INTO SCREEN ADDRES moveq #16,d2 ******/ SPRITE HEIGHT******/ tst.w d1 IS Y NEGATIVE ?? bge.s .ypos NO neg.w d1 sub.w d1,d2 SUBTRACT FROM HEIGHT TO WORK OUT HOW MUCH TO DISPLAY ble .no_draw NOTHING TO DRAW ******/ A SIXTEEN BIT SPRITE HAS EIGHT BYTES PER LINE *********/ * NEED TO MULTIPLY BY EIGHT move.w d1,d7 STORE add.w d1,d1 *2 add.w d1,d1 *2 add.w d1,d1 *2 - ABOVE IN EFFECT MULTIPLIES BY 8 add.w d1,a1 ADJUST INTO SPRITE FILE bra .do_x .ypos *Y IS POSITIVE cmp.w #200,d1 IS IT OFF THE SCREEN ? bge .no_draw YES move.w d1,d7 STORE Y CO-ORDINATE add.w d7,d7 add.w d7,d7 add.w d1,d7 lsl.w #5,d7 ABOVE IN EFFECT MULTIPLIES : * 5 * 32 adda.w d7,a0 GOTO Y CO-ORDINATE IN LOGICAL SCREEN add.w d2,d1 subi.w #200,d1 DO WE NEED T ADJUST SPRITE HEIGHT ? blt.s .do_x NO sub.w d1,d2 NEW SPRITE HEIGHT .do_x tst d0 bge.s .xpos X = POSITIVE NUMBER cmp.w #-16,d0 OFF THE SCREEN ? ble.s .no_draw YES bra .do_left CLIP ON THE LEFT .xpos move.w d0,d7 STORE X CO-ORDINATE andi.w #$f,d0 andi.w #$fff0,d7 ADJUST TO 16 BOUNDARY lsr.w #1,d7 DIVIDE BY 2 moveq #96,d6 256-160 neg.b d6 cmp.w d6,d7 bge.s .no_draw NOTHING TO DRAW adda.w d7,a0 ADJUST INTO SCREEN subq.w #8,d6 cmp.w d6,d7 TEST FOR CLIPPING ON THE RIGHT bne .do_all NO CLIPPING moveq #0,d1 *** CLIP SPRITE TO THE RIGHT *** .do_right subq #1,d2 FOR DBRA ROUTINE .loop_rt bsr right add.w #152,a0 ADJUST FOR NEXT LINE - 160 - 8 dbra d2,.loop_rt bra .no_draw EXIT *** CLIP SPRITE ON THE LEFT **** .do_left moveq #0,d1 subq #1,d2 FOR DBRA ROUTINE neg.w d0 andi.w #$f,d0 .loop_lt adda.w d1,a1 bsr left2 add.w #152,a0 ADJUST FOR NEXT LINE - 160-8 dbra d2,.loop_lt bra .no_draw *** NO CLIPPING *** .do_all subq #1,d2 FOR DBRA .loop_all bsr right bsr left add.w #144,a0 160 - 16 dbra d2,.loop_all .no_draw movem.l (sp)+,a0-a1/d0-d7 RESTORE REGISTERS rts ************************************************************* * RIGHT * * * * LOAD IN THE FOUR PLANES, AND ROTATE THEM TO ALLOW FOR * * THE 16 PIXEL BOUNDARY * ************************************************************* right moveq #0,d4 ZERO DATA REGISTER move.w (a1)+,d4 PLANE 0 ror.l d0,d4 ROTATE BY REQUIRED VALUE moveq #0,d5 move.w (a1)+,d5 PLANE 1 ror.l d0,d5 moveq #0,d6 move.w (a1)+,d6 PLANE 2 ror.l d0,d6 moveq #0,d7 move.w (a1)+,d7 PLANE 3 ror.l d0,d7 * CREATE A MASK FROM THE FOUR PLANES INTO D3 move.w d4,d3 or.w d5,d3 or.w d6,d3 or.w d7,d3 OR ALL THE VALUES TOGETHER not.w d3 NEGATE THE RESULT * PUT INTO LOGICAL SCREEN - AND THE MASK WITH THE * CURRENT SCREEN DATA, AND OR THE NEW DATA IN and.w d3,(a0) AND MASK or.w d4,(a0)+ OR PLANE 0 - INCREMENT SCREEN and.w d3,(a0) or.w d5,(a0)+ PLANE 1 and.w d3,(a0) or.w d6,(a0)+ PLANE 2 and.w d3,(a0) or.w d7,(a0)+ PLANE 3 rts ************************************************************* * LEFT * * * * NOW DO THE PART THAT WAS ROTATED TO THE OTHER HIGH WORD * ************************************************************* left swap d4 SWAP HI-LOW VALUES OF REGISTER swap d5 swap d6 swap d7 * CREATE MASK move.w d4,d3 or.w d5,d3 or.w d6,d3 or.w d7,d3 not.w d3 * AND MASK WITH CURRENT SCREEN DATA, OR WITH NEW DATA and.w d3,(a0) or.w d4,(a0)+ and.w d3,(a0) or.w d5,(a0)+ and.w d3,(a0) or.w d6,(a0)+ and.w d3,(a0) or.w d7,(a0)+ rts ***************************************************** * LEFT2 * * * * FOR LEFT BORDER CLIP - NO NEED TO ROTATE AND SWAP * * MAY AS WEEL JUST USE LOGICAL SHIFT * ***************************************************** left2 move.w (a1)+,d4 PLANE 0 lsl.w d0,d4 SHIFT BY REQUIRED VALUE move.w (a1)+,d5 PLANE 1 lsl.w d0,d5 move.w (a1)+,d6 PLANE 2 lsl.w d0,d6 move.w (a1)+,d7 PLANE 3 lsl.w d0,d7 * CREATE A MASK FROM THE FOUR PLANES INTO D3 move.w d4,d3 or.w d5,d3 or.w d6,d3 or.w d7,d3 OR ALL THE VALUES TOGETHER not.w d3 NEGATE THE RESULT * PUT INTO LOGICAL SCREEN - AND THE MASK WITH THE * CURRENT SCREEN DATA, AND OR THE NEW DATA IN and.w d3,(a0) AND MASK or.w d4,(a0)+ OR PLANE 0 - INCREMENT SCREEN and.w d3,(a0) or.w d5,(a0)+ PLANE 1 and.w d3,(a0) or.w d6,(a0)+ PLANE 2 and.w d3,(a0) or.w d7,(a0)+ PLANE 3 rts ********************************************************* * MAIN PROGRAM * * * * NOW WITH CLIPPING AND JOYSTICK MOVEMENT !!!!!! * * * * (c) Nick Bates 1994 * * Version: 1.1 * * Last modified: 10/07/94 * * * * SET TAB TO 4 * ********************************************************* bra main include graphics.lib include sprite.lib include mouse.lib include joystick.lib main bsr setup bsr main_loop bsr restore clr.l -(sp) QUIT trap #1 ********* * SETUP * ********* setup bsr go_super SUPERVISOR MODE bsr kill_mouse bsr init_joystick JOYSTICK ROUTINE bsr save_palette STORE PALETTE bsr get_screen_addr GET PHYSICAL AND LOGICAL SCREEN ADDRESS bsr save_vbi SAVE VBI bsr go_low GO TO LOW RESOLUTION rts *********** * RESTORE * *********** restore bsr restore_screen RESTORE OLD SCREEN bsr restore_palette RESTORE OLD PALETTE bsr show_mouse bsr go_user USER MODE rts ********************* * MAIN PROGRAM LOOP * ********************* main_loop movem.l palette,d0-d7 movem.l d0-d7,$ffff8240.w CHANGE PALETTE .loop bsr wait_vbi WAIT FOR VBI bsr clear_screen CLEAR SCREEN ***************************************************************** * PLAYER CO-ORDINATES move.w player_x,d0 X CO-ORDINATES move.w player_y,d1 Y CO-ORDINATES move.w #0,d2 SPRITE NUMBER ****************************************************************** bsr draw_sprite_16 bsr flip_screen FLIP SCREENS bsr move_player JOYSTICK MOVEMENT cmp.b #$39,$fffffc02 TEST FOR beq .exit YES .jloop btst.b #1,$fffffc00 IS KEYBOARD READY ??? beq.s .jloop NO - LOOP move.b #$16,$fffffc02 YES - REQAUEST JOY PACKET bra .loop .exit rts *************** * MOVE_PLAYER * *************** move_player movem.w joy_xy,d6/d7 * TEST FOR JOYSTICK MOVEMENT * * * D7 = VERTICAL MOVEMENT -1 = UP, -1 = DOWN, 0 = NO MOVEMENT * D6 = HORIZONTAL MOVEMENT -1 = LEFT, -1 = RIGHT, 0 = NO MOVEMENT cmp.w #0,d7 ANY VERTICAL MOVEMENT beq .horiz NO !!!! blt .up * JOYSTICK DOWN add.w #1,player_y ADD 1 TO PLAYER POSITION cmp.w #201,player_y IS IT OFF LIMIT ???? blt .horiz NO move.w #200,player_y YES - SO FIX TO LIMIT bra.s .horiz * JOYSTICK UP .up sub.w #1,player_y cmp.w #-16,player_y bgt .horiz move.w #-15,player_y .horiz cmp.w #0,d6 ANY HORIZONTAL MOVEMENT beq .exit NO!!! bgt .right * JOTSTICK LEFT sub.w #1,player_x cmp.w #-16,player_x bgt .exit move.w #-15,player_x bra.s .exit * JOYSTICK RIGHT .right add.w #1,player_x cmp.w #321,player_x blt .exit move.w #320,player_x .exit rts sprites incbin "b:\assembly\sprite\source\pac.obj" pic dc.l 1 palette dc.w $000,$007,$005,$003,$770,$700,$060,$707 dc.w $000,$440,$500,$744,$373,$047,$505,$777 set_relative dc.b $08 bss even old_res ds.b 1 old_pal ds.w 16 vbi_done ds.b 1 old_vbi ds.l 1 old_stk ds.l 1 old_scrn ds.l 1 old_mvec ds.l 1 playerxy player_x ds.w 1 player_y ds.w 1 joy_xy joy_x ds.w 1 joy_y ds.w 1 fire ds.b 1 jpack_addr ds.l 1 mpacket ds.l 1 kvtable ds.l 1 log ds.l 1 phys ds.l 1 screen ds.b 32000+256 ********************************************************* * GRAPHICS SUBROUTINES * * * * Author: Nick Bates (c) 1994 * * Last Modified: 10/07/94 * ******************************************************** ***************************************************** * GO_SUPER * * * * Goto supervisor mode, * * - Saves old stack to old_stk * ***************************************************** go_super pea 0 move.w #$20,-(sp) trap #1 addq.l #6,sp move.l d0,old_stk save stack rts ***************************************************** * SAVE_PALETTE * * * * Saves pallete to: old_pal * ***************************************************** save_palette movem.l $fff8240,d0-d7 movem.l d0-d7,old_pal rts ***************************************************** * GET_SCREEN_ADDR * * * * Get logical screen and generates physical * * - Saves to log, phys * ***************************************************** get_screen_addr move.w #2,-(sp) trap #14 addq.l #2,sp move.l d0,phys move.l d0,old_scrn move.l #screen,d0 PHYSICAL SCREEN addi.l #256,d0 256 BYTE BOUNDARY andi.l #$ffffff00,d0 move.l d0,log rts ***************************************************** * SAVE_VBI * * * * Saves vbi to: old_vbi * ***************************************************** save_vbi move.l $70,old_vbi STORE OLD VBI move.l #vbi,$70 NEW VBI rts ***************************************************** * GO_LOW * * * * Saves current resolution to: old_res * * and change to low resolution. * ***************************************************** go_low move.b $ff8260,old_res store resolution move.b #0,$ff8260 low resolution rts ***************************************************** * GO_USER * * * * Restore stack from: old_stk * * Goes to User Mode * ***************************************************** go_user move.l old_stk,-(sp) restore stack move.w #$20,-(sp) GEMDOS - USER MODE trap #1 addq.l #6,sp user mode rts ********************************************************* * CLEAR_SCREEN * * * * Clear the logical screen * ********************************************************* clear_screen move.l log,a0 lea 32000(a0),a0 movem.l a0-a6/d0-d7,-(sp) clr.l d1 clr.l d2 clr.l d3 clr.l d4 clr.l d5 clr.l d6 clr.l d7 move.l d1,a1 move.l d1,a2 move.l d1,a3 move.l d1,a4 move.l d1,a5 move.l d1,a6 move.w #614,d0 .loop movem.l d1-d7/a1-a6,-(a0) dbra d0,.loop movem.l d1-d5,-(a0) movem.l (sp)+,a0-a6/d0-d7 rts ********************************************************* * WAIT_VBI * * * * Wait for vbi interupt * ********************************************************* wait_vbi tst.b vbi_done beq.s wait_vbi rts vbi st vbi_done rte ********************************************************* * FLIP_SCREEN * * * * Flips the logical to Physical screens * * Requires: log, phys * ********************************************************* flip_screen movem.l d0-d1,-(sp) move.l log,d0 move.l phys,d1 move.l d1,log move.l d0,phys lsr.w #8,d0 move.l d0,$ffff8200.w sf vbi_done movem.l (sp)+,d0-d1 rts ***************************************************** * RESTORE_SCREEN * * * * Restores vbi, resolution, logical and physical * * screens. * * Parameters: old_vbi, old_res, old_scrn * ***************************************************** restore_screen move.l old_vbi,$70 move.w old_res,-(sp) restore resolution move.l old_scrn,-(sp) restore physical move.l old_scrn,-(sp) restore logical move #5,-(sp) XBIOS - SET SCREEN trap #14 lea 12(sp),sp rts ***************************************************** * RESTORE_PALETTE * * * * Restore old palette from: old_pal * ***************************************************** restore_palette movem.l old_pal,d0-d7 movem.l d0-d7,$fff8240 restore pallette rts NEOOBJPACMAN.PI1  1R p   @?@~|~@?@ @ @  @?@|@?@    @?@@?@  ""@@?    @?@@?@""  X?}(g0g0Bg0ppppXX @@ }?}ss豈ssZнpppp  }?}hNpNphNpNpZнppppj@@j@@@@  @?@~|~@?@ @ @  @?@|@?@    @?@@?@  ""@@?    @?@@?@""  X?}(g0g0Bg0ppppXX @@ }?}ss豈ssZнpppp  }?}hNpNphNpNpZнppppj@@j@@@@***************************************************** * JOYSTICK ROUTINES * * * * (c) Nick Bates 1994 * * Last modified: 10/07/94 * ***************************************************** ***************************************************** * INIT_JOYSTICK * * * * Iniialise joystick routines * * Requires: kvtable, oldmvec, * * and arguments * ***************************************************** init_joystick move.w #34,-(sp) trap #14 addq.l #2,sp move.l d0,kvtable move.l d0,a0 lea 24(a0),a0 move.l a0,jpack_addr move.l #jhandler,(a0) rts ***************************************************** * JHANDLER * * * * Joystick handler routine - called from init_joy * ***************************************************** jhandler move.w d0,-(sp) SAVE REGISTER clr.w d0 move.b 1(a0),d0 add.b d0,d0 scs fire add.b d0,d0 move.l jlt(pc,d0.w),joy_xy MOVE VALUES INTO JOY_X AND JOY_Y move.w (sp)+,d0 RESTORE REGISTER rts ** JOYSTICK LOOKUP TABLE - INCLUDES IMPOSSIBLE MOVEMENTS !!!! jlt dc.w 0,0 NOTHING dc.w 0,-1 UP dc.w 0,1 DOWN dc.w 0,0 **** UP AND DOWN dc.w -1,0 LEFT dc.w -1,-1 LEFT AND UP dc.w -1,1 LEFT AND DOWN dc.w -1,0 **** LEFT, DOWN AND UP dc.w 1,0 RIGHT dc.w 1,-1 RIGHT AND UP dc.w 1,1 RIGHT AND DOWN dc.w 1,0 **** RIGHT, DOWN AND UP dc.w 0,0 **** RIGHT AND LEFT dc.w 0,-1 **** RIGHT, LEFT AND UP dc.w 0,1 **** RIGHT, LEFT AND DOWN dc.w 0,0 **** RIGHT, LEFT, DOWN AND UP ***************************************************** * MOUSE SUBROUTINES * * * * (c) Nick Bates 1994 * * Last modified: 10/07/94 * ***************************************************** ***************************************************** * KILL_MOUSE * * * * Disables mouse * ***************************************************** kill_mouse dc.w $a00a hide mouse move.b #$12,$fffc02 disable mouse rts ***************************************************** * RESTORE_MOUSE * * * * restore old mouse vector, set relative * * requires: kvtable, old_mvec, and set_relative * * arguments. * ***************************************************** restore_mouse move.l kvtable,a0 move.l old_mvec,a1 move.l a1,16(a0) move.l set_relative,-(sp) move.w #0,-(sp) move.w #25,-(sp) trap #14 addq.l #8,sp rts ***************************************************** * SHOW_MOUSE * * * * Restores mouse * ***************************************************** show_mouse move.b #$8,$fffc02 enable mouse dc.w $a009 show mouse rts `"~R`NHy?< NA\#JNuL@H$Nu?<NNT#p#N <t#lNu#pF#pNu`"`Nu/9J?< NA\Nu ylA}HBBBBBBB"A$A&A(A*A,A0<fH~QH|LNuJ9DgNuPDNsH 9l"9p#l#pH!QDLNu#Fp?9"/9N/9N?<NNO NuL$H@NuHC| yltJAlDAAo>AAA` |l>GGAOBAmAJ@l |od`4>@GO|`DFlLQFFf2rSBaBQ`0rSBD@@a~Q`SBaaDQLNux8z:|<~>6EFGFCPXPXPXPXNuHDHEHFHG6EFGFCPXPXPXPXNu8l:m<n>o6EFGFCPXPXPXPXNu Nu yh"yR!I/9 ?<?<NNPNu Nu?<"NNT#h @A#` Nu?B@(U^# Z0Nuaa:a$BNAaa.afaaaaNuaaa  L (  <    ASSEMBLY SPRITE TUTORIAL PART 3 CLIPPING THAT SPRITE + JOYSTICK MOVEMENT PRODUCED FOR: ICTARI USER GROUP (C) Nick Bates 1994 ---------------------------------------------------------------------- Last month I left you with a lot of things to experiment with and this month I have produced my solution to two of the problems. The first being a routine to clip the sprite around the borders and the second a routine to allow control via the joystick. First the clipping routine ..... This is quite straightforward, and as the source is documented, you should have no problems following it. The code itself performs an extension of the actual sprite routine. The idea behind this routine, is that a sprite should be able to be displayed partly on the screen, and not either all on or all off. Therefore for a 16 pixel sprite, you should be able to pass a sprite co-ordinate of say -10, and still see part of the sprite on screen. The problem is separated into two clear tasks. First clipping for vertical borders (y) and second the horizontal borders (x). First the vertical borders. The first thing to do is test whether the y co-ordinate is negative. If it is negative then clearly we have to display either part of the sprite or nothing. Clearly by subtracting the (negated) y co-ordinate from the sprite height, we can see whether any of the sprite will be visible, i.e if the co-ordinate is less than -16 then draw nothing. All we have to do now is to move down the sprite file the number of lines that are to be skipped because these are not visible and to adjust the sprite height accordingly. A 16 pixel sprite has 8 bytes per line, so we need to multiply be eight. That's it, we have done the top vertical border. The bottom border is even easier, because all we need to do is adjust the height of the sprite so that only what we need is displayed. A test to ensure that nothing is attempted to be shown for a co-ordinate over the value of 200, would of course be carried out first. The horizontal borders are a lot trickier. If you look at this months source and in particular the sprite routine, you will notice that I have separated the rotating part and the swapping part into two different subroutines. This is because for a clip on the right border only the first part is needed. The left border requires its own subroutine, because there is no point in rotating the sprite and swapping to the second word when you can just use the logical shift command. The only required thing to do therefore is to detect whether there is to be a left clip, right clip or no clip. For the left border, just test for a negative number. A number less than -16 means there is nothing to draw, any other negative number indicates a left clip. The right border is much the same except that 320 is the magic number. Lets look at an example, if you want to display a sprite at say co-ordinates 315, then clearly we need to only display part of the sprite. The part we don't want has to be rotated into the higher word which is not used. Now onto the joystick subroutine... This subroutine is straightforward and is very similar to the mouse routine in previous issues of the Ictari Disks. Armed with your trusty copy of ST Internals you can soon find the required keyboard vector number to patch the new joystick handler into. The magic number is, of course, 24. Hence the command: LEA 24(A0),A0 MOVE.L JHANDLER,(A0) The joystick handler is a routine that converts the joystick movements into values to indicate a movement. i.e 0,0 NOTHING 0,-1 UP 0,1 DOWN -1,0 LEFT -1,-1 LEFT AND UP -1,1 LEFT AND DOWN 1,0 RIGHT 1,-1 RIGHT AND UP 1,1 RIGHT AND DOWN I have done this by having a look-up table with all the possible outcomes, remember to include the impossible outcomes as well. These values can therefore be saved to a variable, and used by the program. In the main program, you have a call to the "DO MOVEMENT" subroutine, which will check the variables to see if any movement has been made. You must remember to ask for a joystick packet, and of course first of all you must ensure that the keyboard is ready to receive. Hence : .jloop btst.b #1,$fffffc00 IS KEYBOARD READY ??? beq.s .jloop NO - LOOP move.b #$16,$fffffc02 YES - REQUEST JOY PACKET bra .loop This loops until the keyboard is ready, requests a joystick packet, and then branches to the main loop. My MOVE PLAYER routine is so straightforward it's not worth explaining. You may be wondering why I have use subtract and add commands, when surely if you add a negative number it would be the same as a subtract. The reason I have done this is because you may wish to alter the rate of speed, or allow acceleration, deceleration times. Next month I hope to show you better sprites in action with acceleration and deceleration added into the movement. I might also add a background, to give a better feeling. In the meantime fiddle around with this code, or even have a go yourself at doing acceleration, and deceleration. All you have to do is to alter the speed of the movement so that the sprite moves faster the more it moves and when the player stops moving, it takes a small response time to stop. You should of course have a maximum acceleration time. If you haven't already, then have a go at writing a 32x32 sprite routine based on this 16x16 routine. If you have done so then incorporate the new clipping routines into it. Until next month ..... Nick Bates. . d0.. d0BOUNCE DOC p8 BOUNCE S K! SUB-ROUTINE NAME Bounce BRIEF DESCRIPTION Calculate pixel position of bouncing sprite FILENAME BOUNCE.S OTHER RESOURCES None LANGUAGE Assembler (Devpac) AUTHOR Carl Pattinson ENTRY PARAMETERS d0.w holds original X position of sprite d1.w holds original Y position of sprite d2.w holds original DX value d3.w holds original DY value EXIT PARAMETERS d0.w = new X position of sprite d1.w = new Y position of sprite d2.w = new DX value d3.w = new DY value DETAILS. The routine takes the DX value in d2.w and adds it to the X value in d0.w. It then checks to see whether X is greater than the max value and if it is it makes DX negative. After the X values are sorted out it alters the Y values. If DY is less than the max DY value then it will increment the DY value. It will then add the DY value in d3.w to the Y value in d1.w. After this is done it makes a check on the Y value to see if it has become to large to actually be on the screen. If it is larger than the max Y value then DY is made negative. On exit the new values are placed in the data registers 0-3. * NOTE * This routine only calculates the pixel coordinates for the sprite but does not actually draw the sprite on the screen. That has to be done with another routine. A typical example code is shown below :- movem.w sprite_xydxdy,d0-3 ;load values in to d0-3 bsr bounce ;calculate position movem.w d0-3,sprite_xydxdy ;save new values bsr drawsprite ;draw sprite .. DATA sprite_xydxdy ;label for values sprite_x dc.w 20 ;X value sprite_y dc.w 20 ;Y value sprite_dx dc.w 4 ;DX value sprite_dy dc.w 1 ;DY value Note that when loading the values into the data registers, sprite_xydxdy is used instead of sprite_x. They both point to the same value but movem.w sprite_xydxdy,d0-3 makes more sense than movem.w sprite_x,d0-3 The routine was converted from a STOS basic listing by Billy Allen in ST FORMAT #55 Febuary 1994. For those who would like the STOS basic listing but dont have that issue, the routine is included below. 10 key off : hide : curs off : mode 0 20 X=20 : Y=20 : SX=4 : SY=0 30 sprite 1,X,Y,1 40 X=X+SX : if X>300 or X<4 then SX=-SX 50 if SY<19 then inc SY 60 Y=Y+SY 70 if Y>184 then Y=184 : SY=-SY 80 wait vbl 90 if inkey$<>" " then goto 30 ;Routine to calculate the position of a sprite under the effects of ;gravity whilst moving it left and right about the screen. ;ENTRY: D0.w = Current X value of sprite X ; D1.w = Current Y value of sprite Y ; D2.w = Increment of X value ( +ve or -ve ) DX ; D3.w = Increment of Y value ( +ve or -ve ) DY ;EXIT: D0.w = New X value for sprite X ; D1.w = New Y value for sprite Y ; D2.w = New Increment of X value ( +ve or -ve ) DX ; D3.w = New Increment of Y value ( +ve or -ve ) DY ;USES: D0-D3 maxX equ 300 Maximum X value ( Based on a 16x16 minX equ 4 Minimum X value sprite block ). maxY equ 184 Maximum Y value maxDY equ 19 Maximum DY value TEXT bounce ; First we sort out the X value because it is easy with not being ; affected by gravity. ( Condition of parabolic motion !!! for all ; you physicists out there. ! ) add.w d2,d0 ;Add DX to X cmp.w #maxX,d0 ;Is X = Max X value ? bgt.s negx ;Greater than cmp.w #minX,d0 ;Is X = Min X value ? blt.s negx ;Less than bra yvar ;Do y variable negx neg d2 ;Negate DX (subtract it from 0 ) ; If X is greater than maxX then we just make the DX value negative ; coz when you add the negative DX value it will decrease the ; X value. ; Now here comes the vertical (Y) value. This is affected by a ; psuedo-gravity thingy. Every time the routine is called 1 is ; added to DY if it is less than the max DY value. If it is ; equal to maxDY value then the DY value is then added to the ; Y value. yvar cmp.w #maxDY,d3 ;Is DY = Max DY value ? blt.s less_than ;Less than bra.s not_less ;Greater or equal less_than add.w #1,d3 ;Add 1 to DY not_less add.w d3,d1 ;Add DY to Y cmp.w #maxY,d1 ;Is Y = Max Y value ? bgt.s greathan ;Greater than bra.s endrout ;Less or equal greathan move.w #maxY,d1 ;Make Y = Max Y value neg d3 ;Negate DY ( subtract it from 0 ) ; If Y is greater than the maxY value then Y=maxY endrout rts ;Return !! . d0.. d0MATH_TST d0SIF_MATHS G{L. d0.. d0MATH_TSTDOC 5DIMATH_TSTPRG *MATH_TSTRSC  MATH_TSTS D=MATH_TST.PRG demonstrates the limitations in range and accuracy of the SIF_MATH.S module. Numbers can be entered as decimal or hex numbers in the appropriate box. Move from entry box to entry box by pressing the cursor keys or clicking on the box. If entering hex numbers then all 8 digits must be entered. Number entry is terminated by pressing return. * clears the entire entry. / backspaces. shift_0 to shift_5 gives A to F for hex entry. ( quits the programme Help gives the above information. JI Logan, Belfast City Hospital, Lisburn Road, Belfast BT9 7AB, UK.`l`xggކh.<Nuggh.<NuHBCJj DkR CJj DkB C*(BGHGHEޅHF*ޅHDHDJDfބkJCgD`.<L8NuHBCJngDk CJngrDkv C8<RDjSDj⎸| nRJDkBHD8<eQ` ކQF.HDdRkJCgD`.<`.<L8Nu,aNuH<Jj .<`(@m`쾼m`ܾm`̾m`@m`m`m`m`~@m`nm`^m`Nm`>@m`.m`m`m,*.a6ޅ⏺fL+s&H<Jo\tSBjBGHG,a*,a^(A.,aP&.,aF*,a>ևJf.HBނ`.<L z0<a<3333pa 33333333 3"p3a z^0<a`J9 9ny:g Am Fo am fo`p f\:< 5_PgZRE E oB:<5P Am_0,<aބRE EfRE E oPJ` /f EoSE EfSE_P`P *f:< _PSE El|.:<`& E o :< ` EfREPRE z0:2ax`Nu#@333 3p+a :0:36 @fz3:Q<` @fz3:P<`h @ fz3:Q<`L @ fz3 :P<`0?<?<NAX333pa` z20:NA z0:8az z0:.A z0:aX3834333pa X` yLg`* o ( ШШOR//?<?<JNAO p a30pMa3PA`p 0Q0a#@pnaJy2f3#+@p4a~`^33#p#3"<v0<NB0:#33#p#3"<v0<NB0:#$(<a|z3438 zv0:A 3pNa#R@p6aL^HU@UAXBXCH33 R3333plaXLH3 3333pda$32#N3 3pia3 3 3 3 z3 tpea3ja >3ja ZL N@SBASC3 j3 l3 n3 pa333333 3 3  3 "p3a@ z 0<a>3pNa&3pNaQBB y4g* y4gr y 4g y 4g`(<a\aap#>(<aDa z L0<a(<a*a: z 20<aa`z(<a:< _PSE El| |. z 0<aR(<aa<#>(<aa z 0<a$aJ`(< aaa#B(< aa2 z 0< a(< ajaz z r0< aa`(< aH:< _PSE El| |. z 40< a(< aa|#B(< aa z 0< ada`N:<B5P _g .g0 DE`ܰlZB*< B5P<_g<.g0HDބ,< a.E`H@ހg- -fD`.<Nu:<g>8  l 0`7PE EfE E o`_PRE E o|.Nu,k | `DkV|-.:<BFHF HF0PBFHFSE ElB<:< HF0PBFHFRE E o`":<_PRE E o| |.Nu.: ,: aR(<aLa\ z T0<a.: n,: naN(<a&a6 z .0<a.: H,: HaJ(<aa z 0<af.: ",: "a(<aa z0<a@.:a"(<aa z0<a.:aP(<aa z0<a.:a0(<ata z|0<a.:a(<aRab zZ0<a.:t,:ta(<a,a< z40<aNuL(33333333 3"p3a:3pfa,3pgapoaapa?<?<LNAXC v2@ A p222BQ"<v0<NB0: NupByT3 XaN3 PNuByTByXp`*pd3 r^`ByTByXpe` pByTByX`p`pwByT3XByja0: @Nupx`3T3X0<`pByX`p`p `prC g2Rj3X3Tp`3T3Xpg`j3TByXpr`Vp`p3T3XB nB rBy x`|3TByXp`h3TByXpB nBy t`J3T3Xp`63T3Xp`"3TByXp`p3TByX3\p `p `prC g2Rj3X3Tp `ByT3Xp `hByT3Xp`TByT3Xp`@ByT3Xpq`,3TByXBy lp`ByT3Xp`ByT3Xpl`ByT3Xp`3TByXBy jp`ByT3Xp`3TByXBy jp `ByT3Xpk`zByT3Xp `fByT3Xp`RByT3Xp`>ByT3Xpj`*ByT3Xp'`ByT3Xp`ByT3Xp`ByT3Xp`ByT3Xph`ByTpp`3T3Xpm`3T3Xpy`ByTByXpn`|3TByXpi`hByTByXpv`VByT3Xpz`BByTByXp{`0ByTByXp|`ByTByXp}` ByTByXp~`ByTByXp`ByTByX0<`ByT3Xpf`ByT3Xp`ByTByXp#`ByTByXp$`ByTByXp%`vByTByXp&`dprCg2Rj3XByTpt`@ByT3Xpu`,ByT3X0<`ByTByX0<`3L^3R"<0<sNBNuMATH_TST.RSC[3][Resource file missing][Quit] Sign_Integer_Fraction 32-bit Maths 2@L Rj jj!jintJaddrFexitintinjptsin jstackstart lv_arcv_barcontrlRform_h"form_w form_xform_yglobalhelp_h.help_w,help_x(help_y*hex_invint_inintoutjnoobjc ptsout!jv_pallLv_rboxDwind_hwind_w wind_xwind_y work_hwork_wwork_xwork_yLOW_VDI abort_1Xaddr_in@appl_id0contrl1Tcontrl2Vcontrl3Xcontrl4Zcontrl5\contrl6^contrl7`contrl8bcontrl9dcontroldcml_inNdcmlhexCALL_AEStCALL_VDIaddr_outLalog2.srJascii.srcontrl10fcontrl11hcur_head8cur_objc4decimoutdo_keybddo_mesag \do_xdcmlddo_ydcmllog10.srnxt_head:nxt_objcppower.srroot2.srhrtn_objc6setxdcml setydcml Nstacklowlstacktoptryxdcml ~v_circlev_clsvwkv_ellarc v_ellpiev_hide_cv_opnvwkv_show_cvex_butvvex_curv vex_motvvex_timvvq_colorDvq_extnd0vq_key_svq_mousevqt_namevr_recflvr_trnfmvvs_colorvsl_endsvsl_typevsm_typevst_fontalog10.sHrdcmltoheH$xdo_buttoH nform_addHrhelp_addH$rhex_inpuHtlog2fctrHsmaths_ouHtobjcfounH dpower2.sH`rrsrc_filHestackhigHhtst_keybHdtst_mesaHgv_ellipsH2ev_pmarkeHVrvfont_alHlvqt_widtHhvro_cpyfHJmvrt_cpyfH`mvsf_coloHrvsf_stylHevsf_updaH>tvsl_coloHrvsl_udstHyvsl_widtHhvsm_coloHHrvst_coloHrvst_poinHvtvswr_modHewind_bitHLsaes_paraHvmsalog2fctH*rsdcml_inpHutgdp_arcpHiehextodcmHlomesag_buHLffrsrc_aleH+rttst_buttHonv_fillarHZeav_piesliHcevdi_paraHmsvqt_exteHntvsm_heigH.htvst_heigH\htwind_titHNlev_get_piHxelv_justifHdiedvst_effeHctstxt_gaddHr.srvqt_fontHinfovsf_inteHriorvst_rotaHtiongem_ctrlH_listv_contouHrfillvsf_periH*metervst_aligHnmentcurrent_HPhandlevqf_attrH|ibutesvql_attrHXibutesvqm_attrHjibutesvqt_attrHibutesvst_loadH_fontsvst_unloH.ad_fonts d| .V@         :L $     "                                   db66$6 * _____.______$ ____.____Y decimal inputY hexadecimal input _____.______Y decimal translationX decimal input _____.______X hexadecimal input$ ____.____X decimal translation _____.______ Y + X Y - X Y * X Y / X Log10 Y Square root Y _____.______ _____.______ _____.______ _____.______ _____.______ _____.______ Log2 Y _____.______ _____.______ _____.______ Antilog2 Y Y power X Fixed Point Math Demonstration Help > Hex entry needs all 8 digits > Use arrows/mouse to change input box > Shift_0 to shift_5 gives A to F (hex) > '*' clears entry, '/' backspaces, '(' quits JI Logan, Belfast City Hospital, Lisburn Road, Belfast BT9 7AB. OK > '-' and '+' change number sign$234@A BRSThijxyz   &'(23 4DEFTUVdeftuv     A =<6 R n( (     2  N(j(  ((  . J f  (   (       *(  F  b( 4'  3 $3 E3 n 3 3 ~ 2    3  * June 1994 * * sif maths test programme. Written in Devpac 3. * * Used to demonstrate the capabilities of the SIF_MATH.S module. * * JI Logan, Belfast City Hospital, Lisburn Road, Belfast BT9 7AB, UK. opt x+ dump long labels for debugging opt a+ automatic PC mode to save bytes include gemmacro.i HiSoft file include math_tst.i rsc constants include sif_math.s math routines SECTION TEXT bra start * macro area push macro move.\0 \1,-(sp) endm pop macro move.\0 (sp)+,\1 endm gemdos macro function,tidystack push.w #\1 trap #1 IFGE 8-\2 addq.l #\2,a7 ELSEIF lea \2(a7),a7 ENDC endm bell macro push.w #$ff07 gemdos $2,4 endm select macro tree,object move.l \1,a0 tree address move.w \2,d0 object index mulu #objc_size,d0 displacement in tree lea 0(a0,d0.l),a0 a0 points to object bset #0,objc_state+1(a0) set 'select' bit endm deselect macro tree,object move.l \1,a0 tree address move.w \2,d0 object index mulu #objc_size,d0 displacement in tree lea 0(a0,d0.l),a0 a0 points to object bclr #0,objc_state+1(a0) clear 'select' bit endm draw macro tree,object move.l \1,a0 tree address move.w \2,d0 object index bsr draw.sr endm txt_gaddr macro item move.l \1,d4 bsr txt_gaddr.sr endm * subroutine area draw.sr move.l a0,addr move.w d0,int objc_offset a0,d0 move.l addr,a0 move.w int,d0 mulu #objc_size,d0 displacement in tree lea 0(a0,d0.l),a0 a0 points to object graf_mouse #256 objc_draw addr,int,#8,int_out+2,int_out+4,objc_w(a0),objc_h(a0) graf_mouse #257 rts txt_gaddr.sr rsrc_gaddr #1,d4 movea.l addr_out,a5 point to object movea.l objc_spec(a5),a5 point to ted_info movea.l (a5),a5 point to string rts SECTION BSS decimout ds.w 5 word boundry SECTION TEXT dcml_in move.w #fracend,d5 .escloop move.b #'_',0(a5,d5.w) subq.w #1,d5 cmpi.w #intstart,d5 bge .escloop move.b #' ',sign(a5) move.b #'.',dcmlpoint(a5) move.w #intstart,d5 bra nxtevnt hex_in move.w #hexend,d5 .escloop move.b #'_',0(a5,d5.w) subq.w #1,d5 cmpi.w #hexstart,d5 bge .escloop move.b #'.',hexpoint(a5) move.w #hexstart,d5 * wait for key board, left click down or close message nxtevnt evnt_multi #$13,#1,#1,#1,,,,,,,,,,,#mesag_buff,, * test which event tst_keybd btst.b #0,int_out+1 keyboard event? bne do_keybd tst_button btst.b #1,int_out+1 button event? bne do_button tst_mesag btst.b #4,int_out+1 bne do_mesag bra nxtevnt do_keybd move.w int_out+10,d0 cmpi.b #'(',d0 beq exit cmpi.w #$4800,d0 beq .up cmpi.w #$5000,d0 beq .down cmpi.w #$4B00,d0 beq .left cmpi.w #$4D00,d0 beq .right cmpi.w #$6200,d0 beq .help bra .tstdcmlhex .up move.w cur_objc,d0 cmpi.w #xdcml,d0 beq .xdcml cmpi.w #xhex,d0 bne nxtevnt move.w #yhex,rtn_objc bra setyhex .xdcml move.w #ydcml,rtn_objc bra setydcml .down move.w cur_objc,d0 cmpi.w #yhex,d0 beq .yhex cmpi.w #ydcml,d0 bne nxtevnt move.w #xdcml,rtn_objc bra setxdcml .yhex move.w #xhex,rtn_objc bra setxhex .left move.w cur_objc,d0 cmpi.w #xhex,d0 beq .xhex cmpi.w #yhex,d0 bne nxtevnt move.w #ydcml,rtn_objc bra setydcml .xhex move.w #xdcml,rtn_objc bra setxdcml .right move.w cur_objc,d0 cmpi.w #ydcml,d0 beq .ydcml cmpi.w #xdcml,d0 bne nxtevnt move.w #xhex,rtn_objc bra setxhex .ydcml move.w #yhex,rtn_objc bra setyhex .help form_center help_addr movem.w int_out+2,d0-3 movem.w d0-3,help_x form_dial #0,#0,#0,#0,#0,help_x,help_y,help_w,help_h draw help_addr,#0 evnt_multi #$03,#1,#1,#1,,,,,,,,,,,,, form_dial #3,#0,#0,#0,#0,help_x,help_y,help_w,help_h draw form_addr,#0 bra nxtevnt .tstdcmlhex tst.b dcmlhex bne hex_input dcml_input cmpi.b #'0',d0 blt .tryminus cmpi.b #'9',d0 ble .charout bra nxtevnt .tryminus cmpi.b #'-',d0 bne .tryplus move.b d0,sign(a5) bra .drawit .tryplus cmpi.b #'+',d0 bne .trypoint move.b #' ',sign(a5) bra .drawit .trypoint cmpi.b #'.',d0 bne .trycr .notstart move.b #'.',dcmlpoint(a5) move.w #dcmlpoint+1,d5 bra .drawit .trycr cmpi.b #13,d0 bne .trybs move.w #intstart,d4 .crloop cmpi.b #'0',(a5,d4.w) blt .probpoint cmpi.b #'9',(a5,d4.w) ble .notempty .probpoint addq.w #1,d4 cmpi.w #fracend,d4 bgt nxtevnt bra .crloop .notempty bra .exit .trybs cmpi.b #'/',d0 bne .tryesc cmpi.w #intstart,d5 bgt .decindex move.b #' ',sign(a5) bra .bsout .decindex subq.w #1,d5 cmpi.w #dcmlpoint,d5 bne .bsout subq.w #1,d5 .bsout move.b #'_',0(a5,d5.w) bra .drawit .tryesc cmpi.b #'*',d0 bne nxtevnt move.w #fracend,d5 .escloop move.b #'_',0(a5,d5.w) subq.w #1,d5 cmpi.w #intstart,d5 bge .escloop move.b #' ',sign(a5) move.b #'.',dcmlpoint(a5) move.w #intstart,d5 bra .drawit .charout cmpi.w #dcmlpoint,d5 bne .notpoint addq.w #1,d5 .notpoint cmpi.w #fracend,d5 ble .notend move.w #fracend+1,d5 bra nxtevnt .notend move.b d0,0(a5,d5.w) addq.w #1,d5 .drawit draw form_addr,cur_objc bra nxtevnt .exit rts hex_input cmpi.b #'0',d0 blt .trycr cmpi.b #'9',d0 bgt .tstalpha andi.w #$03,int_out+8 beq .charout add.b #17,d0 .tstalpha cmpi.b #'A',d0 blt .exit cmpi.b #'F',d0 ble .charout cmpi.b #'a',d0 blt .exit cmpi.b #'f',d0 ble .tocaps bra nxtevnt .trycr cmpi.b #13,d0 bne .trybs move.w #hexstart,d5 .crloop cmpi.b #'_',(a5,d5.w) beq nxtevnt addq.w #1,d5 cmpi.w #hexend,d5 ble .crloop clr.l d7 move.w #hexstart,d5 .hexloop move.b (a5,d5.w),d4 cmpi.b #'A',d4 blt .digit subq.b #7,d4 .digit sub.b #48,d4 move.l #$00100000,d6 bsr lmul.sr add.l d4,d7 addq.w #1,d5 cmpi.w #hexpoint,d5 bne .notpoint addq.w #1,d5 .notpoint cmpi.w #hexend,d5 ble .hexloop st int bra .exit .trybs cmpi.b #'/',d0 bne .tryesc cmpi.w #hexstart,d5 ble .bsout subq.w #1,d5 cmpi.w #hexpoint,d5 bne .bsout subq.w #1,d5 .bsout move.b #'_',0(a5,d5.w) bra .drawit .tryesc cmpi.b #'*',d0 bne nxtevnt move.w #hexend,d5 .escloop move.b #'_',0(a5,d5.w) subq.w #1,d5 cmpi.w #hexstart,d5 bge .escloop move.b #'.',hexpoint(a5) move.w #hexstart,d5 bra .drawit .tocaps subi.b #32,d0 .charout cmpi.w #hexend,d5 ble .notend move.w #hexend+1,d5 bra nxtevnt .notend cmpi.w #hexpoint,d5 bne .dochar addq.w #1,d5 .dochar move.b d0,0(a5,d5.w) addq.w #1,d5 .drawit draw form_addr,cur_objc bra nxtevnt .exit rts do_button objc_find form_addr,#0,#8,int_out+2,int_out+4 move.w int_out,d0 move.w d0,rtn_objc cmpi.w #ydcml,d0 bne tryyhex setydcml moveq.w #intstart,d5 move.w #ydcmlhead,nxt_head sf dcmlhex bra objcfound tryyhex cmpi.w #yhex,d0 bne tryxdcml setyhex moveq.w #hexstart,d5 move.w #yhexhead,nxt_head st dcmlhex bra objcfound tryxdcml cmpi.w #xdcml,d0 bne tryxhex setxdcml moveq.w #intstart,d5 move.w #xdcmlhead,nxt_head sf dcmlhex bra objcfound tryxhex cmpi.w #xhex,d0 bne noobjc setxhex moveq.w #hexstart,d5 move.w #xhexhead,nxt_head st dcmlhex bra objcfound noobjc bell evnt_button #1,#1,#0 bra nxtevnt objcfound deselect form_addr,cur_head draw form_addr,cur_head select form_addr,nxt_head draw form_addr,nxt_head move.w nxt_head,cur_head move.w rtn_objc,cur_objc evnt_button #1,#1,#0 addq.l #4,a7 bra nxt_objc do_mesag cmp.w #22,mesag_buff beq exit close window bra nxtevnt * programme starts here start move.l 4(a7),a0 base page move.l $C(a0),d0 text len add.l $14(a0),d0 data len add.l $1C(a0),d0 BSS len add.l #$100,d0 basepage lea stacktop,a7 set stackpointer push.l d0 push parameters push.l a0 push.w #0 gemdos $4A,12 shrink memory * Initialise application and store handle appl_init move.w d0,appl_id * Get VDI handle and store it in gemmac location graf_handle move.w d0,current_handle * Prepare int_in and open virtual workstation lea int_in,a0 moveq.w #10-1,d0 .fill move.w #1,(a0)+ dbra d0,.fill move.w #2,(a0) v_opnvwk * load resource file rsrc_load #rsrc_file tst.w int_out bne rsrc_ok form_alert #1,#rsrc_alert bra abort_1 * get resource form address rsrc_ok rsrc_gaddr #0,#form move.l addr_out,form_addr * get resource help address rsrc_gaddr #0,#help move.l addr_out,help_addr * initialise a5, d5 etc txt_gaddr #ydcml moveq.w #intstart,d5 move.w #ydcml,cur_objc move.w #ydcmlhead,cur_head select form_addr,cur_head * mouse off graf_mouse #256 * get form's centred coordinates form_center form_addr movem.w int_out+2,d0-3 movem.w d0-3,form_x * calc outer window size given inner size = form + border subq.w #2,d0 subq.w #2,d1 addq.w #4,d2 addq.w #4,d3 movem.w d0-3,work_x wind_calc #0,wind_bits,d0,d1,d2,d3 movem.w int_out+2,d0-3 movem.w d0-3,wind_x * create window and save handle wind_create wind_bits,d0,d1,d2,d3 move.w d0,wind_id * set title in move bar move.l #wind_title,int_in+4 wind_set wind_id,#2 * open window wind_open wind_id,wind_x,wind_y,wind_w,wind_h * set style solid and colour white vsf_interior #1 vsf_color #0 * get window work and convert to vdi movem.w work_x,d0-3 add.w d0,d2 subq.w #1,d2 add.w d1,d3 subq.w #1,d3 vr_recfl d0,d1,d2,d3 * draw form using centred coordinates form_dial #0,#0,#0,#0,#0,form_x,form_y,form_w,form_h draw form_addr,#0 * mouse arrow (#0) and on (#257) graf_mouse #0 graf_mouse #257 sf dcmlhex clr.l yhexnum clr.l xhexnum nxt_objc cmpi.w #ydcml,cur_objc beq do_ydcml cmpi.w #yhex,cur_objc beq do_yhex cmpi.w #xdcml,cur_objc beq do_xdcml cmpi.w #xhex,cur_objc beq do_xhex bra nxt_objc do_ydcml txt_gaddr #ydcml bsr dcml_in bsr dcmltohex move.l d7,yhexnum txt_gaddr #yhex bsr hex_out draw form_addr,#yhex txt_gaddr #ydcmlo bsr hextodcmlo draw form_addr,#ydcmlo bsr maths_out bra nxt_objc do_yhex txt_gaddr #ydcml move.w #fracend,d5 .escloop move.b #'_',0(a5,d5.w) subq.w #1,d5 cmpi.w #intstart,d5 bge .escloop move.b #' ',sign(a5) move.b #'.',dcmlpoint(a5) draw form_addr,#ydcml txt_gaddr #yhex bsr hex_in move.l d7,yhexnum txt_gaddr #ydcmlo bsr hextodcmlo draw form_addr,#ydcmlo bsr maths_out bra nxt_objc do_xdcml txt_gaddr #xdcml bsr dcml_in bsr dcmltohex move.l d7,xhexnum txt_gaddr #xhex bsr hex_out draw form_addr,#xhex txt_gaddr #xdcmlo bsr hextodcmlo draw form_addr,#xdcmlo bsr maths_out bra nxt_objc do_xhex txt_gaddr #xdcml move.w #fracend,d5 .escloop move.b #'_',0(a5,d5.w) subq.w #1,d5 cmpi.w #intstart,d5 bge .escloop move.b #' ',sign(a5) move.b #'.',dcmlpoint(a5) draw form_addr,#xdcml txt_gaddr #xhex bsr hex_in move.l d7,xhexnum txt_gaddr #xdcmlo bsr hextodcmlo draw form_addr,#xdcmlo bsr maths_out bra nxt_objc dcmltohex move.w #intstart,d5 clr.l d0 .intloop move.b (a5,d5.w),d4 cmpi.b #'_',d4 beq .notint cmpi.b #'.',d4 beq .endint sub.b #'0',d4 mulu #10,d0 add.w d4,d0 .notint add.w #1,d5 bra .intloop .endint cmp.l #$00008000,d0 bge .overflow clr.l d7 move.l #fracend,d5 .fracloop clr.l d4 move.b (a5,d5.w),d4 cmp.b #'_',d4 beq .notfrac cmp.b #'.',d4 beq .endfrac sub.b #'0',d4 swap d4 add.l d4,d7 move.l #$000A0000,d6 bsr ldiv.sr .notfrac sub.w #1,d5 bra .fracloop .endfrac swap d0 add.l d0,d7 cmp.l #$80000000,d7 beq .exit .dosign move.b sign(a5),d4 cmpi.b #'-',d4 bne .exit neg.l d7 bra .exit .overflow move.l #$80000000,d7 .exit rts hex_out move.w #hexstart,d5 cmp.l #$80000000,d7 beq .overflow .nexthex rol.l #4,d7 move.w d7,d4 andi.b #$000F,d4 cmpi.b #$A,d4 bge .notdcml add.b #'0',d4 bra .hexout .notdcml add.b #55,d4 .hexout move.b d4,(a5,d5.w) add.w #1,d5 cmpi.w #hexpoint,d5 bne .notpoint add.w #1,d5 .notpoint cmpi.w #hexend,d5 ble .nexthex bra .exit .overflow move.b #'_',(a5,d5.w) addq.w #1,d5 cmpi.w #hexend,d5 ble .overflow move.b #'.',hexpoint(a5) .exit rts hextodcmlo move.l d7,d6 get value bmi .neg move.b #' ',sign(a5) number is positive bra .cont .neg neg.l d6 negate value bmi .overflow branch infinity move.b #'-',sign(a5) number is negative move.l d6,d7 store positive value .cont move.w #intend,d5 clr.w d6 swap d6 get int part .intloop divu #10,d6 remainder in hi d5 swap d6 add.b #$30,d6 make ascii move.b d6,(a5,d5.w) store ascii clr.w d6 swap d6 subq.w #1,d5 cmpi.w #intstart,d5 bge .intloop next integer digit .endint clr.l d6 move.w d7,d6 get frac move.w #fracstart,d5 point to lsf .fracloop mulu #10,d6 swap d6 get fraction add.b #$30,d6 make ascii move.b d6,(a5,d5.w) save fraction clr.w d6 swap d6 addq.w #1,d5 cmpi.w #fracend,d5 ble .fracloop bra .exit .overflow move.w #intstart,d5 .overfloop move.b #'_',(a5,d5.w) addq.w #1,d5 cmpi.w #fracend,d5 ble .overfloop move.b #' ',sign(a5) move.b #'.',dcmlpoint(a5) .exit rts maths_out load yhexnum ladd xhexnum txt_gaddr #yaddx bsr hextodcmlo draw form_addr,#yaddx load yhexnum lsub xhexnum txt_gaddr #ysubx bsr hextodcmlo draw form_addr,#ysubx load yhexnum lmul xhexnum txt_gaddr #ymulx bsr hextodcmlo draw form_addr,#ymulx load yhexnum ldiv xhexnum txt_gaddr #ydivx bsr hextodcmlo draw form_addr,#ydivx load yhexnum root2 txt_gaddr #rooty bsr hextodcmlo draw form_addr,#rooty load yhexnum log10 txt_gaddr #log10y bsr hextodcmlo draw form_addr,#log10y load yhexnum log2 txt_gaddr #log2y bsr hextodcmlo draw form_addr,#log2y load yhexnum alog2 txt_gaddr #alog2y bsr hextodcmlo draw form_addr,#alog2y load yhexnum power xhexnum txt_gaddr #ypowerx bsr hextodcmlo draw form_addr,#ypowerx rts * delete form exit movem.w form_x,d4-d7 form_dial #3,#0,#0,#0,#0,d4,d5,d6,d7 * close window and delete it wind_close wind_id wind_delete wind_id * free up resources abort_1 rsrc_free * close virtual workstation v_clsvwk * exit application appl_exit * terminate GEM push.w #0 gemdos $4c,4 SECTION DATA rsrc_file dc.b 'MATH_TST.RSC',0 rsrc_alert dc.b '[3][Resource file missing][Quit]',0 wind_bits dc.w %0000000000000011 close,title wind_title dc.b ' Sign_Integer_Fraction 32-bit Maths ',0 sign equ 0 intstart equ 1 intend equ 5 dcmlpoint equ 6 fracstart equ 7 fracend equ 12 hexstart equ 2 hexpoint equ 6 hexend equ 10 SECTION BSS * these have to remain together to be referenced by movem.w or move.l wind_x ds.w 1 * window frame wind_y ds.w 1 * wind_w ds.w 1 * wind_h ds.w 1 * work_x ds.w 1 * workow work work_y ds.w 1 * work_w ds.w 1 * work_h ds.w 1 * form_addr ds.l 1 resource form address form_x ds.w 1 * form coordinates form_y ds.w 1 * form_w ds.w 1 * form_h ds.w 1 * help_addr ds.l 1 resource help address help_x ds.w 1 * help coordinates help_y ds.w 1 * help_w ds.w 1 * help_h ds.w 1 * appl_id ds.w 1 application number wind_id ds.w 1 aes window number cur_objc ds.w 1 rtn_objc ds.w 1 cur_head ds.w 1 nxt_head ds.w 1 dcmlhex ds.b 1 yhexnum ds.l 1 xhexnum ds.l 1 addr ds.l 1 int ds.w 1 mesag_buff ds.w 16 area for messages stacklow ds.w 10 lower overrun stack ds.w 299 stack area stacktop ds.w 1 stack start stackhigh ds.w 10 upper overrun rsreset objc_next rs.w 1 objc_head rs.w 1 objc_tail rs.w 1 objc_type rs.w 1 objc_flags rs.w 1 objc_state rs.w 1 objc_spec rs.l 1 objc_x rs.w 1 objc_y rs.w 1 objc_w rs.w 1 objc_h rs.w 1 objc_size rs.w 0 * if not linking then include the run-times IFEQ __LK include aeslib.s include vdilib.s ENDC * 21 June 1994 * * sif (sign-integer-fraction) math routines * * Written in 68000 assembler using Devpac-3 * * Each sif number is 32 bits long and has an imaginary binary point between * bits 15 and 16 giving the format %siiiiiiiiiiiiiii.ffffffffffffffff. The * integer range is from $FFFF0000 to $EFFF0000 (-32767 to +32767). The * fraction range is from $00000001 (0.000015 to six decimal places) to * $0000FFFF (0.999984 to six decimal places). The 2's complement system is * used but for multiplication and division the number is converted to an * unsigned format before the operation and converted back after. * * The number $80000000 ("-32767.999984") is reserved as an indicator of * overflow. This number is assumed to behave like infinity. Any number * added to, subtracted from, multiplied by or divided into infinity equals * infinity. Infinity subtracted from a number should be minus infinity * presumably but this cannot be indicated here and is simply called * infinity. Any number divided by infinity equals zero. * * Routines available are load, store, dup (duplicate d7 to d6) ladd, lsub, * lcmp, lmul, ldiv, power2, root2, log2, alog2, log10, and power. * * The routines were written for use in a physiological simulator (a model * of the blood circulation) where the restricted range was not of import- * ance but speed was. * * The module can be included in your own programme: * * include SIF_MATH.S * * and can be used by calling the appropriate routine. To make the listing * look neater, I have used macros which load d6 and then jump to the * appropriate subroutine. * * Example 1 * calculate the circumference of a circle * pi dc.l $0003243F * * load #pi load pi (= 355/113) * lmul #$00020000 load '2', d6*d7->d7 * lmul radius(a5) load radius, d6*d7->d7 * store circumference(a5) store result * * * Example 2 * test for overflow * load result * lcmp #infinity * beq overflow * * * Example 3 * taken from a physiological simulator * IF PRA >= 8.028 THEN FA:= ((PRA * (-4.256E-2)) + 13.806) * HS * SYMHSM; * load pra(a5) * lcmp #$0008072B 8.028 * blt .pra1 * lmul #$FFFFF51B -0.04256 * ladd #$000DCE56 13.806 * lmul hs(a5) * lmul symhsm(a5) * store fa(a6) * bra .continue * .pra1 (further code) * .continue * * * Example 4 * taken from MATH_TST.S * load yhexnum * root2 * txt_gaddr #rooty * bsr hextodcmlo * draw form_addr,#rooty * * * Data register d7 is used as an accumulator and all operations act on it. * Second operators (if given) are loaded into d6 by the calling macro. * * NB If you wish to perform an operation using the value already in d6 * then you should specify d6 as the second operator. * * Example 5 * lmul d6 uses values in d6 and d7 * * * Most routines are based on those given by Eric Huggins in his most * invaluable book "Microprocessors and Microcomputers - Their Use and * Programming" published by The Macmillan Press Ltd in 1979. Other sources * were "Programming the 68000" by Tim King and Brian Knight published by * Addison-Wesley Publishing Company in 1983, and "Computer Arithmetic - * Logic and Design" by Otto Spaniol published by John Wiley & Sons in 1981. * The latter contains routines for speeding up multiplication and division * but I have not been able to implement them. Any advice or coding leading * to faster routines would be welcome. * * * MATH_TST.PRG shows the limitations of the number format and allows you * to check the accuracy of the routines. * * Please contact me if you have any comments or queries. SIF_MATH.S and * MATH_TST.PRG are in the Public Domain and may be freely copied and used. * Please distribute all files together. * * JI Logan, Belfast City Hospital, Lisburn Road, Belfast BT9 7AB, UK. SECTION TEXT bra sif_end infinity equ $80000000 load macro d7 = memory move.l \1,d7 endm store macro memory = d7 move.l d7,\1 endm dup macro d6 = d7 move.l d7,d6 endm * Compare * * Compare d7 with second operator if given or with d6. This simply * uses the standard cmp.l and is only given for uniformity with the * other operators. lcmp macro compare by (d7 - d6) cmp.l \1,d7 endm * Addition * * Check for infinity (answer is infinity if d7 or d6 infinity) * and deal with overflow. ladd macro d7 = d7 + d6 IFNC '\1','d6' move.l \1,d6 load x if given ENDC bsr ladd.sr do it endm ladd.sr lcmp #infinity,d7 beq .exit lcmp #infinity,d6 beq .overflow add.l d6,d7 bvc .exit .overflow move.l #infinity,d7 .exit rts * Subtraction * * Check for infinity (answer is infinity if d6 or d7 infinity) * and deal with overflow. lsub macro d7 = d7 - d6 IFNC '\1','d6' move.l \1,d6 load x if given ENDC bsr lsub.sr do it endm lsub.sr lcmp #infinity,d7 beq .exit lcmp #infinity,d6 beq .overflow sub.l d6,d7 bvc .exit .overflow move.l #infinity,d7 .exit rts * Multiplication * * Check both y and x for infinity and sign. If negative make positive. * d7 * d6 -> d7. The 68000 does not have a 32 bit multiply instruction * but does have a 16 * 16 bit instruction. This is used to form the * partial products (fraction2 * fraction1, integer2 * fraction1, * fraction2 * integer1 and integer2 * integer1) which are then added. * Of the 64 bit answer, only the middle 32 bits are preserved. The upper * 16 and lower 16 bits are discarded after using them to test for over- * flow and rounding respectively. lmul macro d7 = d7 * d6 IFNC '\1','d6' move.l \1,d6 load x if given ENDC bsr lmul.sr basic routine endm lmul.sr movem.l d3-5,-(a7) save registers clr.w d3 clear sign tst.l d7 bpl .yplus neg.l d7 bmi .overflow d7 = infinity eori.w #1,d3 d7 negative .yplus tst.l d6 bpl .xplus neg.l d6 bmi .overflow d6 = infinity eori.w #1,d3 d6 negative .xplus move.l d7,d5 copy num_2 move.l d7,d4 and again mulu d6,d7 frac_2 * frac_1 addi.l #$00008000,d7 roundoff result clr.w d7 forget least signif word swap d7 shift right 16 times swap d5 access int_2 mulu d6,d5 int_2 * frac_1 add.l d5,d7 add to result swap d6 access int_1 move.l d4,d5 copy num_2 mulu d6,d5 frac_2 * int_1 add.l d5,d7 add to result swap d4 access int_2 mulu d6,d4 int_2 * int_1 swap d4 shift left 16 times tst.w d4 word <> 0 means overflow bne .overflow add.l d4,d7 result bmi .overflow overflow if bit #31 set tst.w d3 sign beq .exit = 0 positive result neg.l d7 <> 0 negative bra .exit .overflow move.l #infinity,d7 .exit movem.l (a7)+,d3-5 restore registers rts and return * Division * * Check both y and x for infinity and sign. If negative make positive. * d7 / d6 -> d7. The 68000 does not have a 32 bit divide instruction and * unlike the multiply routine, use cannot be made of the 32 / 16 bit * instruction. This routine therefore does the division completely in * software using a restoring algorithm. * * >>>> If anyone knows how to code a quicker algorithm (eg non-restoring * with shift over zeros and ones) then please let me know <<<<. ldiv macro d7 = d7 / d6 IFNC '\1','d6' move.l \1,d6 load x if given ENDC bsr ldiv.sr endm * clear low d3 to be exor'd with signs of d6 and d7. Check d6 and d7 * for zero and infinity (of all the negative numbers, only $80000000 * remains negative after negation). ldiv.sr movem.l d3-5,-(a7) save registers clr.w d3 tst.l d7 bgt .ygtzero gt correct here beq .underflow as test eq here neg.l d7 bmi .overflow eori.w #1,d3 .ygtzero tst.l d6 bgt .xgtzero gt ditto beq .overflow eq ditto neg.l d6 bmi .underflow eori.w #1,d3 * If d7 and d6 are equal, then at the end the quotient = $80000000. The * answer should be $00010000 so the quotient has to be shifted right 15 * times. This figure of 15 is modified according to the number of shifts * required to normalise d7 and d6. The figure is increased by one for * each d7 shift to the left (because more d7 shifts mean a smaller d7 * therefore a smaller answer) and decreased for every d6 shift (because * more d6 shifts means a smaller d6 and therefore a larger answer). If * the final shift figure is greater than 32, then d7 is excessively small * compared with d6 and underflow will result. Similarly, if the final * figure is less than 0, then d6 is excessively small compared with d7 and * overflow will result. After normalisation, d6 and d7 are shifted right * to leave a leading zero. .xgtzero move.w #15,d4 base count is 15 .normaly addq.w #1,d4 asl.l #1,d7 normalise d7 bpl .normaly lsr.l #1,d7 leave a leading 0 .normalx subq.w #1,d4 asl.l #1,d6 normalise d6 bpl .normalx lsr.l #1,d6 leave a leading 0 cmp.w #32,d4 bgt .underflow d7 <<< d6 tst.w d4 bmi .overflow d7 >>> d6 swap d4 save shift figure * Here is the main loop. The divisor is subtracted from the dividend and * a branch taken if the carry is set (NB not if the result is negative). * The carry is rotated into the quotient, the dividend restored (if * necessary) and shifted. Because the answer is built from the carry, it * is in fact the 1's complement of what is required and must be reversed. move.w #31,d4 going to do 32 loops .divloop sub.l d6,d7 dividend - divisor bcs .restore NB use CARRY not NEGATIVE roxl.l #1,d5 insert carry into quotient asl.l #1,d7 dividend left dbra d4,.divloop again till done bra .donediv .restore roxl.l #1,d5 insert carry into quotient add.l d6,d7 divisor > dividend, add back asl.l #1,d7 and shift dividend dbra d4,.divloop again till done .donediv not.l d5 1's complement quotient * The main loop is finished. The quotient is moved to d7 and the shift * figure retrieved and used to shift the answer. The answer is rounded if * the last bit to be shifted out was set. The sign is checked and d7 is * negated if required. move.l d5,d7 swap d4 lsr.l d4,d7 shift right 0 < n < 32 bcc .tstover check for rounding addq.l #1,d7 round .tstover bmi .overflow overflow if msb set tst.w d3 check sign beq .exit OK if positive neg.l d7 negate if not bra .exit .overflow move.l #infinity,d7 set d7 = infinity bra .exit .underflow move.l #0,d7 set d7 = 0 .exit movem.l (a7)+,d3-5 restore register rts * Square * power2 macro d7 = d7 * d7 bsr power2.sr endm power2.sr dup lmul d6 rts * Square root d7 * * This routine uses Newton's method of successive approximation to * determine the square root of the number in d7. To speed things up a * first "guess" is made as to the answer. This guess is arrived at by * dividing the original number by a power of 2 (by shifting right) if there * is an integer component or multiplying by a power of 2 (by shifting left) * if there is only a fraction. The number of shifts right or left depends on * the size of the original number. A good guess will reduce the number of * times round the loop. Since each loop contains a long division (slow), * greatest speed is obtained by reducing the number of loops. * Once the first guess has been made there is then an iterative process to * determine the next approximation. The process is stopped when there is no * difference between the current approximation and the new approximation. * The maximum number of loops seems to be 5 but can be as few as 1 (for * perfect squares which are also a power of 2 eg 4, 16, 64 etc). root2 macro d7 = square root d7 bsr root2.sr endm root2.sr movem.l d2-5,-(a7) save registers tst.l d7 bpl .yplus move.l #infinity,d7 error if negative bra .exit .yplus move.l d7,d4 save original number (a) lcmp #$40000000,d7 >= 16384 ? blt .try28 then / by 128 lsr.l #7,d7 bra .nextry .try28 lcmp #$10000000,d7 >= 4096 ? blt .try26 then / by 64 lsr.l #6,d7 bra .nextry .try26 lcmp #$04000000,d7 >= 1024 ? blt .try24 lsr.l #5,d7 then / by 32 bra .nextry .try24 lcmp #$01000000,d7 >= 256 ? blt .try22 lsr.l #4,d7 then / by 16 bra .nextry .try22 lcmp #$00400000,d7 >= 64 ? blt .try20 lsr.l #3,d7 then / by 8 bra .nextry .try20 lcmp #$00100000,d7 >= 16 ? blt .try18 lsr.l #2,d7 then / by 4 bra .nextry .try18 lcmp #$00040000,d7 >= 4 ? blt .try16 lsr.l #1,d7 then / by 2 bra .nextry .try16 lcmp #$00010000,d7 >= 1 ? blt .tryfrac bra .nextry .tryfrac lcmp #$00004000,d7 >= 0.25 ? blt .try12 lsl.l #1,d7 then * by 2 bra .nextry .try12 lcmp #$00001000,d7 >= 0.0625 ? blt .try10 lsl.l #2,d7 then * by 4 bra .nextry .try10 lcmp #$00000400,d7 >= 0.015625 ? blt .try8 lsl.l #3,d7 then * by 8 bra .nextry .try8 lcmp #$00000100,d7 >= 0.00390625 ? blt .try6 lsl.l #4,d7 then * by 16 bra .nextry .try6 lcmp #$00000040,d7 >= 0.000976563 ? blt .try4 lsl.l #5,d7 then * by 32 bra .nextry .try4 lcmp #$00000010,d7 >= 0.000244141 ? blt .try2 lsl.l #6,d7 then * by 64 bra .nextry .try2 lcmp #$00000004,d7 >= 0.000061035 ? blt .try1 lsl.l #7,d7 then * by 128 bra .nextry .try1 lcmp #$00000001,d7 >= 0.000015259 ? blt .nextry lsl.l #8,d7 then * by 256 .nextry move.l d7,d6 save xn move.l d7,d5 save xn move.l d4,d7 load a (original number) ldiv d6 a / xn add.l d5,d7 xn + (a / xn) lsr.l d7 xn+1 = 1/2(xn + (a / xn)) lcmp d7,d5 bne .nextry .exit movem.l (a7)+,d2-5 restore registers rts * Logarithm (base2) * * Logs of a number 'a' to any base can be found by computing the series: * 2rx + 2r(xpower3)/3 + 2r(xpower5)/5 + etc etc where x = (a-1)/(a+1) * and r = the conversion factor from log e to the required base. Base 2 is * convenient for dealing with binary numbers. The precomputed factors below * are 2*1.4426952, 2*1.4426952/3, 2*1.4426952/5 etc until the resultant * factor is too small to be represented by the sif method. The number has * to be normalised first. log2 macro d7 = log d7 base 2 bsr log2.sr endm log2fctrs dc.l $0002E2A9,$0000F638,$000093BB,$00006986,$00005213 dc.l $00004327,$000038D2,$0000313E,$00002B73,$000026E0 log2.sr movem.l d2-5/a0,-(a7) tst.l d7 ble .error moveq.l #16,d2 set characteristic count .normalx subq.w #1,d2 subtract 1 lsl.l #1,d7 & shift up bpl .normalx till normalised clr.w d7 swap d7 shift right 16 times move.l d7,d6 a sub.l #$00010000,d7 a - 1 add.l #$00010000,d6 a + 1 ldiv d6 x = a - 1 / a + 1 move.l d7,d5 save copy move.l d7,d6 prepare to square lmul d6 x power 2 move.l d7,d4 saved lea log2fctrs,a0 precomputed factors move.l d5,d7 x into d4 for 1st factor move.l (a0)+,d6 lmul d6 move.l d7,d3 .nxtfactor move.l d5,d7 x power i move.l d4,d6 x power 2 lmul d6 x power i * x power 2 move.l d7,d5 x power (i + 2) move.l (a0)+,d6 get factor lmul d6 add.l d7,d3 2r(x power i)/i tst.l d7 stop when next factor bne .nxtfactor is zero move.l d3,d7 swap d2 move characteristic up add.l d2,d7 add characteristic bra .exit & finish .error move.l #infinity,d7 error .exit movem.l (a7)+,d2-5/a0 rts * Antilogarithm (base 2) * * The antilog base e of a number can be found by computing the series: * e(powerx) = 1 + x + x(power2)/2! + x(power3)/3! etc etc. This can be * converted to another base by multiplying by a conversion factor. alog2 macro d7 = antilog d7 base 2 bsr alog2.sr endm alog2fctrs dc.l $00008000,$00002AAB,$00000AAB,$00000222,$0000005B dc.l $0000000D,$00000002,$00000000 alog2.sr movem.l d2-5/a0,-(a7) lcmp #$000F0000,d7 bgt .overflow won't fit into sif move.l d7,d2 save characteristic move.l #$00010000,d3 x power 0 andi.l #$0000FFFF,d7 clear characteristic move.l #$0000B172,d6 log of 2 (base e) lmul d6 x * factor add.l d7,d3 x power 1 move.l d7,d5 save x move.l d7,d4 " lea alog2fctrs,a0 .nxtfactor move.l d5,d7 get x power i move.l d4,d6 get x power 1 lmul d6 x power i * x power 1 move.l d7,d5 save x power (i + 1) move.l (a0)+,d6 get factor lmul d6 multiply add.l d7,d3 add to answer tst.l d7 stop when next factor bne .nxtfactor is zero swap d2 tst.w d2 bpl .shiftleft neg.w d2 lsr.l d2,d3 move.l d3,d7 bra .exit .shiftleft lsl.l d2,d3 move.l d3,d7 bra .exit .overflow move.l #infinity,d7 .exit movem.l (a7)+,d2-5/a0 rts * Logarithm (base 10) * * log 10 is obtained by determining log 2 and applying a conversion factor log10 macro d7 = log d7 base 10 bsr log10.sr endm log10.sr log2 ldiv #$0003526A rts * can't get this going yet alog10 macro bsr alog10.sr endm alog10.sr rts * Power * * simply uses logs in the usual way power macro d7 = d7 raised to power d6 IFNC '\1','d6' move.l \1,d6 load x if given ENDC bsr power.sr endm power.sr move.l d6,-(a7) save exponent log2 log y move.l (a7)+,d6 restore exponent lmul d6 log y * exponent alog2 alog rts * Make ASCII. Other input/output routines can be found in MATH_TST.S * * This routine converts the value in d7 to ascii and outputs it to memory * pointed to by a0. The ascii format is determined by a word passed in * d1 of the form 'if' where 'i' represents number of decimal integer digits * required and 'f' represents the number of decimal fraction digits * required (eg '41' will give 4 integer digits and 1 fraction digit). * NOTE - the space required for output is the number of integer digits plus * the number of fraction digits plus 1 for a leading space plus 1 for the * sign plus 1 for the decimal point. * The integer routine finds the decimal digits starting with 'units' and * progressing to 'tens' etc. These have to be written in reverse and this * is why the addressing mode is (a0,d1.w) as d1 contains the count which * decreases by 1 each time. ascii macro address,format lea \1,a0 move.w \2,d6 bsr ascii.sr endm ascii.sr move.l d3,-(a7) save register move.l d7,d5 get value bmi .neg move.b #' ',(a0)+ leading space bra .cont .neg neg.l d5 negate value bmi .overflow branch infinity move.b #'-',(a0)+ leading minus sign move.l d5,d7 store pos value .cont move.l a0,-(a7) address of 1st digit andi.l #$0000FFFF,d6 clear high d6 divu #10,d6 'i' d6.lo,'f' d6.hi move.w d6,-(a7) save for later clr.w d5 swap d5 get int part bra .enterint 'while...end' .intloop divu #10,d5 remainder in hi d5 swap d5 add.b #$30,d5 make ascii move.b d5,(a0,d6.w) store ascii clr.w d5 swap d5 .enterint dbra d6,.intloop next integer adda.w (a7)+,a0 point past int move.b #'.',(a0)+ decimal point clr.l d5 move.w d7,d5 get frac swap d6 get frac count bra .enterfrac 'while...end' .fracloop mulu #10,d5 swap d5 get fraction add.b #$30,d5 make ascii move.b d5,(a0)+ save fraction clr.w d5 swap d5 .enterfrac dbra d6,.fracloop another frac? move.l (a7)+,a0 address 1st digit cmpi.b #'0',(a0) ascii zero bne .exit .space move.b #' ',(a0)+ blank leading zeros cmpi.b #'0',(a0) beq .space not anything else bra .exit .overflow divu #10,d6 split format move.w d6,-(a7) store one swap d6 add.w (a7)+,d6 add together .overfloop move.b #' ',(a0)+ all spaces - no dbra d6,.overfloop decimal point clr.b (a0) terminal null .exit move.l (a7)+,d3 restore register rts end sif_end. d0.. STE_FIX PRG 3``:` f`dJxfA`A P=f" hmBCzp f8QP`, P?f J9g##/|vByN"m y #f EgQ`R( yNJDESKTOP.INF&o k  Ј<.@// ?<?<JNAO aBg/<?<1NAJ/ / B@rC02 x$f*`0 _INFf2` _MCHf fpRPH$fJ@f2`p$x )g2`\o _INF!|PHBpЁ!@`: xC!` $HPH&IPI&& f"_INF#|PIB#|(&_$_NuA8NA NZ090g A#NH090D@HA pN0A+N&090gNAp!N#rNu?<NA/?< NA\ONu/ /??<NMPO @$_Nu/ /?<&NN\O$_NuDESKTOP.INF patch installedalready installedthis machine is not an STEthis STE ROM version does not need the patch ERROR: . mytrap1main_StkSizeerrno0Pterm0dmsgCconwsjstartt1savercookie_jvalidate:SetexcvSupexecMADMAClongframjmp_abs_NFopen=opcodeFO_filenFO_modeFread?FR_handlFR_countFR_bufstartupsuptrp gheadplstkchkfnckreadDdeskinftstb4gotopennoreadjreadbufsaveretmungeitvxmunggetbytnxbytgoteresendTpaStartTpaEndTextSegSTextSegS DataSegSDataSegSBssSegStBssSegSiDtaPtr PntPrcPt$Reserved(EnvStrPt,Reserved0CurDrv7Reserved8CmdLineBasePage> h""   <. d0.. LEAGUE d0OTHELO C d0GEM_TUT 004e0p. d0.. d0LEAGUE TOS 5LEAGUE C cLEAGUE TXT `( `4P"o#1j*i,EB&J(JSB  g  g  f RSBj` gn =fa6 n <#00` %fa n <#-`Rpr A9nA0m/ПЁRSBkB`Jg:NuA16`A1rRSBk$  gJ  gB  g:Qp`JBkQB$)ԩ 00&9-f &`nր n&< Ѓй00// Bg?<JNAJfV.B#1V00#1Z#1^#1b#1fNN/ / K,MNBpJ1zg / y1zNXO??<LNA` /`a6aajNuNVaBn09C 2.@dBn09C 2.@d0.@gt @4P"A4P0(2)Af=|p0.r2.t4.///aO R@f n4dRn` n4fpN^Nup0./@rN.| @4P0(h @9`0.H0 /r0N.| @40.H0Rn`Rn`pN^NuNVBn ndnBn0. @4d.2. A4P2(h A9`HBPRn`Bn0. @d2.0 A4HBPRn`Rn`N^NuNV0.0 @40. H0=@Jg6r2. bp0.Dr2."p09C SdpN^Nup0. cr2. S//avPS@f&p0. 2.UA//aVPS@fpN^Nup0.2.SA//a0PU@f&p0.2.UA//aPU@fpN^Nu0.  @4P0(h @9`0.H0S@fpN^Nup0. r2.t4.///aO N^NuNVBn09C 2.@d0. t0 @4Hp0t4.gZ0.0 @4p0g@0.0 @40. H0Bg 0.0 @40.H0BfpN^NuRn`fpN^NuNVBn09C 2.@d|Bn09C 2.@db0.4. @f 0 @4H0nfpN^Nu0.2. @f$2.0 A4H0nfpN^NuRn`Rn`xpN^NuNVp /N-rXHy1~NPXHy1NPXByC HnHnHnHy1N O09C  @4P".0 @4P".1A @4P .1@p/N-rXpA/N-rXp/N-rXpo/N-rX09C  @4Pr2 @4Pt4( @4Pp0(///Hy1NPO09C R@3C p09C dSrN.| @4P0J@fN^NuNVp /N-rXHy2NPXHy24NPXBn09C 2.@dBn09C 2.@dp0./@r0N.| @/H4r2./A 4/AJBgz$/ rN.| @/H4Pr2$/ /ArN.| @4Pp0 o4Pr2( o4$/t4/////$Hy2WNPORn`:Rn`N^NuNV# p# lp nR"@2gR` nJgX 9 R @ p nJgR"@2fR` nrR@JftNqJ2gp` <r#-@#p# .## .#p# .#p# .#91JgR/Hy1p=/N0O -@Jj HyHy N vPp/N~X/.BpF/N0O p916Jg >fBHy17p=/N0O -@`BHy16pfp//.BpB/N0O/.p/pF/N0O /. NX/91nHy /9 NO BN~XN^NuCPROGCan't open stdin file Can't open stdout file dNVp nR-@Jg/. /N PRfpN^NupN^NuNV n (g f//.NPN^Nu n (S!@Jk"PR .r` ./. /NP" N^NuNVA B-H nJgrR A-H2f %f n %f\ 9rS#rJkp ynRn`HynN6X-@ n2f %gp .N^Nu n *g -nX`BRB/.HnHz/.N O-@Jg-@ fJgRJo .N^NupN^NuJgHyn/.N.PJfd .N^Nu 9rS#rJkp ynRn`HynN6X-@ n2f .g| .N^NuR`l .N^Nu 9rS#rJkp ynRn`HynN6XNuNVRC$ 9S#Jk yR .r` .Hy/NP"N^NuNVBC$Hn /.HzN*O 9C$N^Nu/NVB . lTrN.| @n-H(f2 n(g& n  -@Jg//( /(NO R`B ./l( @/Jg @//(NXR`/.NXN^NudNV n (VDHH (0AJg BpN^Nu n(g(g/p/NP nJf$B/NzXJg npN^NuJ.gr n (T!@nb P"nRp-@ g2 f: n (S!@Jk "PRp` /.a"XN^Nu npN^Nu .N^Nu n(fr (//( /(-@NNO -@Jj nJf nJo(J.g .D n!@` n!n n n (2JgJ.gp!@` nBpN^Nu n (S!@Jk "PRp` /.a4XN^NuNV-n n (0JgpN^Nu n (VDHHAJf(fp!@ fN^Nu/. NzXJg n pN^Nu n J.g (D!@` n !h n (S!@Jk"PR .r` ./. /a$P" N^Nu n (gx fpN^Nu .@J.g. f&p/Hyn n /(-@NO -@`"p/Hn n /(-@NO -@p-@`2 n (gpN^Nu n J.g^ gT (T!@ f""PR Jk /p/a>P n R"n QR .JjN^Nup-@ n  -@Jg(gpp/B/(N :O -@J.gR .S-@JkDB/ n /(N :O p/Hn n /(NO J1rf . gNq/. n /( /(NO -@`B f n ` .g n J.g n (D!@` n !h"n i " . g2")S#AJk QRr` ./. /aP" n (0JgpN^Nu fpN^Nu .N^Nu dNV nJg(fpN^Nu/92NX n !@ Jfp #4LpN^Nu n!y2p!@!@N^NuNV-np-@ nJg/N/hXRѮR` opN^Nu ./-@NX-@JfpN^Nu n#1nB-H nJg "n"/N/hXRѮRX` nBJC/N0P#1rJjp #4LpN^NupN^Nud?NVx . gJfp /N0X g . ~nS`p}@|Hn|p /N0Pp /p/N0Pp.}Bx-@ .xl n C~Rx` . }lF n R `6/. /./.p?/N0O-@Jj#1rp#4LpN^NuB1r .N^NudNV/. /./.p@/N0O-@Jj#1rp#4LpN^NuB1r .N^NudNV/././. pB/N0O-@Jj#1rp#4LpN^NuB1r .N^NudNVpr nR A2-@-@g> .r N.|r nRЁ-@p nR @2f n lf Rp-@ n N n-@ cg n2g n N-@` . f n pN^Nup nr0kfNs`Dc`h`Hx`o`d`p-@Jg o6 . -g +f" -fp`p-@ n NS-@ n2f n pN^NuB .r N.|".Ё-@ n N-@ .S-@Jg n2fJgJjDJf"n Q `"n Q ` . 0m 7o n pN^NuB .".Ё-@ n N-@ .S-@Jg 0m 7oJgJf"n Q `"n Q ` n2f n pN^Nu-n n N-@Jg oN 0fD . xg Xf0 n N @-H2f n pN^NuBS`` n2g .0-@ n2g .7-@ n2g .W-@ .S-@Jg n2gx . n2-@g".0 n2g .7 n2g .W n N-@`hJgbJf"n Q `N"n Q `@ n2f n pN^NuB .r N.|".Ё-@ n N-@ .S-@Jg n2fJg"n Q .0`Jg"n QR . .S-@Jo$ n N-@RgJg"n QR .` . f n pN^Nu nR N^NuJg"n QR . n N-@Rg .S-@Jg n2g"n QB`pN^Nu n nR N^NuSNVH p| r-Ar-ArA@@@@@-A-A-H nJg^rp kPfN#`2 `"+`-`|`|`|`|NqR` n 0f |0R n *f$n "RX-QR`Hn/.N,PѮ n .f4R-H *f$n "RX-QR`Hn/.N,PѮ n lf |R nR@r8kvfNc`Js`X`x`o`*u`d`J.g "n QX ` "n QX -@Jj r-ADJgp-` J.gp+`p @p.".肀p.JgRR/./.N,BP-@Jjp-@ .".-AJo8 n//./N0:$ VD  2   $: d$. $:0  P4Xf,"20&"NR  B4 :0` 0 . **>&2f( 0$ X&2@8X" X~2`**fT0@/* PROGRAM */ /* ------- */ #define NONE 0 #define HOME 1 #define AWAY 2 #define TEAM_MIN 2 /* Fixed by algorithm */ #define TEAM_MAX 24 /* Variable */ #define DIV_MIN 1 /* Fixed by algorithm */ /* DIV_MAX determined at input time as TOP_DIV */ #define WEEK_MAX 52 /* Variable */ #define NOT_BOOKED 0 #define BOOKED 1 /* for Pitch */ #define Week_Of(a,b) League[a][b] /* used instead of a function */ #define abs(a) ((a>0) ? (a):(-a)) typedef struct team { unsigned short Team_Num; unsigned short Pitch_Num; unsigned short Div_Num; } TEAM; typedef unsigned short LEAGUE; /* League table arranged as a matrix of the form [home][away] containing the week number of each match (or zero for no match) Note that all tables actually go from 0 to TEAM_MAX-1 */ typedef unsigned short PITCH; TEAM Team[TEAM_MAX]; LEAGUE League[TEAM_MAX][TEAM_MAX]; PITCH Pitch[TEAM_MAX][WEEK_MAX]; unsigned short Top_Team; /* filled in by input */ unsigned short Top_Div; /* filled in by input */ /* SUBROUTINES */ void Input_Teams(); short Make_League(); void Empty_League(); short Week_Test(unsigned short,unsigned short,unsigned short); short Playing(unsigned short,unsigned short,unsigned short); unsigned short Play_Status(unsigned short,unsigned short); void Print_League(); void main() { Input_Teams(); /* Implementation Specific */ Make_League(); /* Generic Routine */ Print_League(); /* Implementation Specific */ } /*===================================================================*/ short Make_League() { unsigned short Home_Team,Away_Team; unsigned short Home_Week; /* Current Week */ Empty_League(); /* Initialise League Table and Pitches */ for(Home_Team=0;Home_Team2) /* else last two matches don't exist! */ { if((Play_Status(Home_Team,(unsigned short) (Home_Week-1))==HOME) &&(Play_Status(Home_Team,(unsigned short) (Home_Week-2))==HOME)) return -1; if((Play_Status(Away_Team,(unsigned short) (Home_Week-1))==AWAY) &&(Play_Status(Away_Team,(unsigned short) (Home_Week-2))==AWAY)) return -1; } if(Pitch[Team[Home_Team].Pitch_Num][Home_Week]==BOOKED) return -1; return (Playing(Home_Team,Away_Team,Home_Week)); } short Playing(Home,Away,Week) unsigned short Home,Away,Week; { /* find out if either team already playing */ unsigned short x; for(x=0;x AWAY_TEAM THEN ..... NEXT AWAY_TEAM NEXT HOME_TEAM A good start I think! 5] There should be the maximum amount of time between reverse fixtures (A vs B and B vs A); the second half of the season can be a complete reverse of the first half ( 1st game of 1st half = 1st game of 2nd half etc). Be wary of the word CAN, as in MAY: it is suggesting a potential solution to part of the problem, which is not the job of the spec. This line is a hard one to code because we want the maximum difference between two week numbers with (as we shall see later) no limit on what the top limit on week numbers is. Since we know that each home_team plays one less game than there are teams, then the away match must be at least TOP_TEAM-1 weeks away from the home match. This means we need a function that returns the week the match between home_team and away_team was played. i.e. WEEK=WEEK_OF(home_team,away_team) or zero if not allocated IF ABS(WEEK_OF(HOME_TEAM,AWAY_TEAM)-WEEK_OF(AWAY_TEAM,HOME_TEAM)) < (TOP_TEAM-1) THEN reallocate match to later week number 6] No team plays more than two consecutive games at home or away. This requires a function that is given a team and a week number and returns the status of the match HOME or AWAY. We will now define home as 1, away as 2 and none as 0. i.e. DEFINE NONE=0 DEFINE HOME=1 DEFINE AWAY=2 STATUS=PLAY_STATUS(TEAM,WEEK) where status is HOME,AWAY or NONE IF (PLAY_STATUS(HOME_TEAM,current_week-1)=HOME) AND (PLAY_STATUS(HOME_TEAM,current_week-2)=HOME) THEN reallocate match to later week number IF (PLAY_STATUS(AWAY_TEAM,current_week-1)=AWAY) AND (PLAY_STATUS(AWAY_TEAM,current_week-2)=AWAY) THEN reallocate match to later week number 7] Consideration needs to be given to teams that share the same pitch (they both can't play at home at the same time). This means that we need to book each pitch for the week a match is being played on it. This gives us an object called PITCH which has a property called BOOKED for each week in which we might play. There is at most one pitch per team, but may be less if teams share one pitch. This means that each team must have the property of which pitch it plays on. It does not state how many teams may share one pitch, but this question is avoided by booking the pitch out. PITCH[1-TOP_TEAM]: BOOKED[1-MAX_WEEKS] TEAM[1-TOP_TEAM]: TEAM_NUM PITCH_NUM 8] The number of divisions is variable between 1 and 4. This is a bit nasty to drop in at the end; each team has a property of a division number in which it plays. We ASSUME that this means that each team only plays teams in the same division. TEAM[1-TOP_TEAM]: TEAM_NUM PITCH_NUM DIV_NUM [1-TOP_TEAM] [1-TOP_DIV] FOR HOME_TEAM = 1 TO TOP_TEAM FOR AWAY_TEAM = 1 TO TOP_TEAM IF (HOME_TEAM <> AWAY_TEAM) AND HOME_TEAM.DIVISION == AWAY_TEAM.DIVISION THEN ..... NEXT AWAY_TEAM NEXT HOME_TEAM 9] The teams are to be referenced by number rather than name in order to comply with the League Update program that I have written. Note that there is no mention of whether team numbers are sequential or not. We will have to have the team number as a property of the team and search for the team number as a result of this. *] We have now gleaned all the information we can out of the specification and should now collate it into something like a program. I will choose to go into something like C, due to its ease of use with structures. SEE LEAGUE.C . d0.. d0COMPUTERC `7DO_MOVE C ` &FOOBAR C `*GRAPH C `-HUMAN C `23INIT C `9mMAIN C `? MAKEFILE `COTHELLO H `EkOTHELLO HS `K!TOOLKIT C `TOTHELLO PRG `[j3README 1ST ]0h/******************************************************************************* Program: Program: Othello Desc: A program to play Othello on the AtarI ST Author: Roy Stead Created: 19/2/93 File: computer.c Desc: Functions to handle the Computer-controlled Othello player. Notes: This code is written to accompany the _C'ing Straight_ C Tutorial series, which started in the April 1993 issue of _Atari ST User_ magazine. Updates: Date By Comments 19/2/93 RS Moved stalemate check from game_over() to do_computer() *******************************************************************************/ #include "othello.h" /* OTHELLO program definitions. */ extern void kill_list(), pause(), bsshowtext(); extern int make_move(); extern BOARD *brddup(); /******************************************************************************* do_computer() - Handle a single turn by a computer-controlled Player. *******************************************************************************/ extern int do_computer ( brd ) register BOARD *brd; /* Pointer to Board Descriptor structure*/ { register BOARD *legal; /* Linked list of legal moves. */ register int flipped; /* Number of pieces flipped by move. */ int len; /* Length of string in (char)outstr[] */ char outstr[80]; /* Used to store output text. */ BOARD *get_legal(); /* Returns linked list of legal moves. */ void get_best(); /* Obtains the best possible move. */ void lookahead(); /* Weight minimax by looking ahead. */ /* The first thing we do is obtain a list of all legal moves from this * position. If none are available, NULL is returnd. */ if ( (legal = get_legal (brd)) != NULL ) { /* Weight the minimax value. * The sophistication of the weighting depends on the level of this * computer Player. */ lookahead ( legal, brd->player->level ); get_best ( brd, legal ); /* Put best move in (BOARD *)brd */ kill_list ( legal ); /* Erase legal moves found linked list. */ /* At this point, we have our best legal move stored in the Board * Descriptor pointed to by (BOARD *)brd, and we have deleted the two * scratchpad linked lists used to obtain that best legal move. * * We now execute this move, if it really is a legal one (if it is not * a legal move, then there are no legal moves available to the * computer. We need do nothing, as Game Over will be checked for us * on exit from this function). */ flipped = make_move ( brd ); /* Update the scores. */ if ( flipped > 0 ) { brd->player->score += flipped + 1; brd->player->opponent->score -= flipped; }; brd->player = brd->player->opponent; /* Switch to next Player.*/ return ( FALSE ); /* Signal not a stalemate */ } else { /* Provide "No legal moves found" message. * * sprintf() behaves exactly like printf(), but takes an extra * argument before the formatting string, which is a pointer to a * string to which all output will be sent _instead of_ being sent to * the screen. Like printf(), sprintf() returns the number of * characters output. */ len = sprintf ( &outstr[0], "%s (%c) can\'t make a move", brd->player->name, brd->player->piece ); brd->player = brd->player->opponent; /* Switch to next player */ if ( ( legal = get_legal (brd) ) == NULL ) { /* If the opponent could make no legal moves either, then * provide a message to that effect also. */ len += sprintf ( &outstr[len], "| %s (%c) can\'t make a move", brd->player->name, brd->player->piece ); kill_list ( legal ); }; pause ( &outstr[0] ); /* Show text and wait for key */ if ( legal == NULL ) return ( TRUE ); /* Signal stalemate */ else return ( FALSE ); /* Signal not a stalemate */ }; }; /******************************************************************************* get_legal() - Given a Board descriptor, this function will return a pointer to the first element of a linked list of all legal moves which are available to the Player specified in the Board Descriptor, given the state of the Board specified, or NULL if no legal moves are available or an error occurs. *******************************************************************************/ static BOARD *get_legal ( brd ) register BOARD *brd; /* Pointer to Board Descriptor. */ { register BOARD *first; /* First possible move. */ register BOARD *currbrd; /* General Board Descriptor pointer */ /* Duplicate current Board and point to the duplicate with (BOARD *)first . */ if ( (first = currbrd = brddup (brd)) == NULL ) return ( NULL ); /* Loop through all possible moves on the Board, building up a linked list * of all legal moves and their effects. * * Study this loop carefully. Don't move on to look at the get_best() function * until you are sure you can see what this function is doing. */ for ( currbrd->offset = 0; currbrd->offset < BRD_SIZ; (currbrd->offset)++ ) { /* Check whether this move is legal... */ if ( make_move ( currbrd ) > 0 ) { /* It is legal, and its consequences are in the * Board Descriptor pointed to by (BOARD *)currbrd, * so create a new duplicate of the _original_ Board, * pointing to it from the (BOARD *)nxtbrd field of * the 'current' Board Descriptor. * * Note: We duplicate the original as the "current" * Board has been modified by make_move(). * This implies that we must physically copy * the current square coords across afterwards. */ if ( (currbrd->nxtbrd = brddup (brd)) == NULL ) return ( NULL ); /* Make the new Board into the new * "current" Board before we carry on. */ currbrd->nxtbrd->offset = currbrd->offset; currbrd = currbrd->nxtbrd; }; }; /* The final entry in the 'legal moves' linked list is a dummy Board * Descriptor, which was never filled in, so delete and unlink it. */ if ( first->nxtbrd == NULL ) { /* The entire list consists only of this dummy entry, so delete it, */ free ( first->board ); free ( first ); return ( NULL ); /* Signal no legal moves */ } else { /* Find penultimate Board Descriptor in this linked list. */ currbrd = first; while ( currbrd->nxtbrd->nxtbrd != NULL ) currbrd = currbrd->nxtbrd; free ( currbrd->nxtbrd->board ); /* Delete final Board */ free ( currbrd->nxtbrd ); currbrd->nxtbrd = NULL; /* Unlink it. */ return ( first ); /* Return linked list. */ }; }; /******************************************************************************* lookahead() - Given a list of legal responses, looks ahead (int)level moves and weights the minimax field of each element of the list passed in according to the likely outcome of that move in (int)level moves time. *******************************************************************************/ static void lookahead ( legal, level ) register BOARD *legal; /* Linked list of legal moves. */ int level; /* Number of moves to look ahead. */ { register BOARD *next; /* Pointer to next item in legal list. */ register BOARD *brd; /* Pointer to current item in legal. */ register BOARD *response; /* Linked list of legal responses. */ register BOARD *scratch; /* Pointer to scratchpad Board Desc. */ int flipped, lastflip; /* Pieces flipped this/last turn. */ int x, y; /* General looping variables. */ char outstr[80]; /* Used to store output text. */ BOARD *get_legal(); /* Returns linked list of legal moves. */ void get_best(); /* Obtains the best possible move. */ if ( level < 1 ) /* No lookahead, so return immediately */ return; next = legal; /* Start at head of list (BOARD *)legal */ do { brd = next; /* Pointer to 1st item in list. */ next = brd->nxtbrd; /* This will be 1st next time. */ flipped = lastflip = 1; /* Set up scratchpad variables. */ if ( (scratch = brddup (brd) ) == NULL ) return; /* Note: Never, Never, Never, Never, Never use nested ternary * operators (as I've done in this sprintf() statement) - it makes * your code very awkward to read and understand. Not to mention debug. */ sprintf ( &outstr[0], "Contemplating %c%c...", (scratch->offset / BRD_W) + 'A', (scratch->offset % BRD_W) + (( (scratch->offset % BRD_W) < 10) ? '1' : ( ((scratch->offset % BRD_W) == 10) ? ('0' - 10) : ('A' - 11) )) ); bsshowtext ( &outstr[0] ); /* Look (int)level moves ahead in the game for each legal move in * the (BOARD *)legal linked list. As we look ahead, we adjust the * minimax field for the linked list entry to reflect the board * in moves to come, assuming that the opponent will always use the * best move available to her. If a stalemate is the consequence then * we halt the lookahead at that point. */ for ( x = 0; x < level && (flipped != 0 || lastflip != 0); x++ ) { /* Must do this twice for each move - once for the opponent's * response to the original move, and once for our reply. */ for ( y = 0; y < 2; y++ ) { lastflip = flipped; scratch->player = scratch->player->opponent; /* Get list of legal responses to the move in the * (BOARD *)scratch scratchpad Board Descriptor. */ if ( (response = get_legal (scratch)) != NULL ) { /* Get the best possible response and store it * in the (BOARD *)scratch temporary Board * Descriptor. */ get_best ( scratch, response ); kill_list ( response ); /* Kill list */ /* Adjust the board field of (BOARD *)scratch to * look like it would after the opponent's best * response was played. */ if ( (flipped = make_move (scratch)) > 0 ) { /* Update the minimax field of the * original move in the passed-in list. */ if ( scratch->player == brd->player ) { brd->minimax += flipped + flipped + 1; } else { brd->minimax -= flipped + flipped + 1; }; }; } else flipped = 0; /* No legal response */ }; }; free ( scratch->board ); /* Reclaim scratch */ free ( scratch ); } while ( next != NULL ); /* Carry on to end */ }; /******************************************************************************* get_best() - Given a Board descriptor and a list of all legal moves, this function chooses the best possible move from the list and returns that move in the current square fields of the passed-in Board Descriptor. The method used is to select the move which results in the maximum number of pieces belonging to the Player, _and_ the minimum number of pieces belonging to the opponent: the minimax method. The actual minimax value is calculated in make_move() for every move as it is made. If there are several equal-best moves then one will be chosen at random _unless_ one of those moves is in a corner square of the Board, in which case that move will be performed in preference to other apparently equally-good moves. This latter, by the way, is a small example of a heuristic. It doesn't take much Othello playing to learn that the corner squares are valuable. *******************************************************************************/ static void get_best ( brd, legal ) register BOARD *brd; /* Board Descriptor to return move in. */ register BOARD *legal; /* Linked list of legal moves. */ { register BOARD *currbrd; /* Pointer into legal moves list. */ register BOARD *best; /* Linked list of best possible moves. */ register BOARD *currbest; /* Best possible move, general pointer. */ int n; /* General purpose int variable. */ int mfound = 0; /* Moves found. */ /* First legal move is initially the best move. */ if ( ( best = currbest = brddup (legal) ) == NULL ) return; mfound = 1; currbrd = legal; while ( currbrd != NULL ) { if ( currbrd->minimax == best->minimax ) { /* Equivalent moves, in terms of value, so add this move to * our list of best moves found. */ if ( ( currbest->nxtbrd = brddup (currbrd) ) == NULL ) return; /* String the current move onto the end of the best * moves found so far linked list. */ currbest = currbest->nxtbrd; mfound++; } else { if ( currbrd->minimax > best->minimax ) { /* We've found a better move than the current best move, * so erase the current best moves list and replace it * with a copy of this Board Descriptor. */ kill_list ( best ); /* Erase current list */ /* Make the current Board Descriptor the entirety of * the best-move-found-so-far linked list. */ if ( (best = currbest = brddup (currbrd)) == NULL ) return; mfound = 1; }; }; currbrd = currbrd->nxtbrd; }; currbest = best; if ( mfound > 1 ) { /* If We have a choice of best moves then quickly skim through the * list to see if any of them are in a corner square. */ currbrd = best; do { currbest = currbrd; /* Ptr to 1st item in list. */ currbrd = currbest->nxtbrd; /* Will be 1st next time. */ /* Check whether this move is a corner square. * If it is, then use it in preference to all others. */ if ( At_top(currbest) || At_bottom(currbest) ) if ( At_left(currbest) || At_right(currbest) ) mfound = 0; /* Signal found corner */ } while ( (currbrd != NULL) && mfound ); /* Carry on to end */ if ( mfound != 0 ) { /* Select a random move from the best-moves-found linked list. */ currbest = best; if ( best->nxtbrd != NULL ) { /* Get random number from zero to (int)mfound */ n = (int)rand() % mfound; while ( n ) /* Choose n'th move from list */ { currbest = currbest->nxtbrd; n--; }; }; }; }; /* Put the offset of the move chosen into the passed-in Board Desc. */ brd->offset = currbest->offset; kill_list ( best ); /* Erase best-move-found linked list. */ }; /* End of File COMPUTER.C */ /******************************************************************************* Program: Program: Othello Desc: A program to play Othello on the AtarI ST Author: Roy Stead Created: 19/2/93 File: do_move.c Desc: Functions to perform an Othello move. Notes: This code is written to accompany the _C'ing Straight_ C Tutorial series, which started in the April 1993 issue of _Atari ST User_ magazine. Updates: Date By Comments 19/2/93 RS Adjusted make_move() and subsidiary functions to make use of new offset field instead of x and y. *******************************************************************************/ #include "othello.h" /* OTHELLO program definitions. */ /* Directional offsets used to move in a straight line through the Othello * Board. These constants are pre-calculated in an array to take advantage * of compile-time calculation, and thus speed up the make_move() function, * where they are made use of. * * The order in which these constants appear in the array is important, and * is used in is_trail() to speed up and simplify edge detection. */ static int drn_ary[8] = { -1 - BRD_W, /* Left and up */ -1, /* Left */ BRD_W - 1, /* Left and down */ -(BRD_W), /* Up */ BRD_W, /* Down */ 1 - BRD_W, /* Right and up */ 1, /* Right */ BRD_W + 1 /* Right and down */ }; /******************************************************************************* make_move() - Check the legality of placing a piece belonging to the specified Player at the specified square of the specified Othello Board. All of the above information is given in the Board descriptor pointed to by the passed-in (BOARD *)brd . If the move is legal, then it will be executed on the board provided. The number of pieces flipped by this move is returned (zero indicates an illegal move). *******************************************************************************/ extern int make_move ( brd ) register BOARD *brd; /* Pointer to Othello Board descriptor */ { register int d_off; /* Index to obtain Directional offsets. */ register int cur_off; /* Offset to the current square. */ register int flipped = 0; /* Holds number of pieces flipped. */ int is_trail(); /* Check if trail exists in some dirn. */ int flip_trail(); /* Flip all opponent's pieces in trail. */ /* If the proposed move is to a non-empty square then it is automatically * illegal. */ if ( *(brd->board + brd->offset) != EMPTY ) return ( 0 ); /* Since the is_trail() and flip_trail() functions will corrupt the * coordinates of the current square, make a note of them to restore them * after every call to either of those functions. */ cur_off = brd->offset; /* We loop around all eight neighbours of the current piece. */ for ( d_off = 0; d_off < 8; d_off++ ) { /* If we find a valid trail of pieces in this direction then the move * is valid. Otherwise, continue checking other directions. */ if ( is_trail ( brd, d_off ) ) { /* Having found a valid trail of pieces, we execute the move * by flipping all opponent's pieces in the trail. * * (int)flipped is simultaneously increased by the number of * pieces flipped on this trail. */ brd->offset = cur_off; /* Restore current square. */ flipped += flip_trail ( brd, drn_ary[d_off] ); }; brd->offset = cur_off; /* Restore current square. */ }; /* Set Minimax value of this move. * * This value is used by the get_best() function to decide which move is * the best for a computer-controlled Player to make. */ if ( flipped > 0 ) { brd->minimax = brd->player->score + flipped + flipped + 1 - brd->player->opponent->score; }; /* Return the number of pieces which were flipped in the course of making this * move. If zero is returned, the move was an illegal one. */ return ( flipped ); }; /******************************************************************************* is_trail() - This function attempts to follow a trail of pieces in the direction specified, starting from the current square on the specified Board. If the trail consists of an unbroken line of pieces belonging to the opponent of the current Player followed by a piece belonging to the current Player then TRUE is returned, otherwise FALSE. The direction is specified as an index into the (static int)drn_ary[] array, which is used to look up a value which is to be successively added to the pointer offset to the current square. It's done in this roundabout manner to simplify and speed up edge detection. As usual, the Othello Board, current Player and current square are given in the structure pointed to by (BOARD *)brd . *******************************************************************************/ static int is_trail ( brd, index ) register BOARD *brd; /* Board and position to start from */ register int index; /* Direction of trail */ { int start; /* Offset of starting square. */ start = brd->offset; /* Continue moving in the direction given by offset (int)drn_ary[index] until * we reach a piece which does not belong to the opponent of the current * Player or we threaten to fall off the edge of the board. */ do { /* We return FALSE in the cases when we are about to wander off the * left- or right-hand side of the board. We don't need to check for * wandering off the top or bottom, as that is covered by the * check for a valid offset below. * * Note that using the index into the offsets array, combined with the * ordering of the array itself, allows us to check this case quickly. */ if ( (At_left(brd) && index <= 2) || (At_right(brd) && index >= 5) ) return ( FALSE ); brd->offset += drn_ary[index]; /* Take one step in direction */ if ( brd->offset < 0 || brd->offset >= BRD_SIZ ) return ( FALSE ); /* Ensure new offset is valid */ } while ( *(brd->board + brd->offset) == brd->player->opponent->piece ); #ifdef DEBUG /* Debugging code used to let me know which trails the program is accepting as * valid, and which it is dismissing, and gives me a little information about * each valid trail located. This code is not compiled for the final program. * * Note that those of you using the Hisoft C Interpreter should delete the * "#ifdef DEBUG" line above and the #endif which follows if you wish to make * use of this debugging code. For some reason, Hisoft C ignores this code * even if DEBUG has been defined in this file. * * Because of Hisoft C's problem with automatics, you will also need to move * the automatic variable declarations (of (int)x and (char)outstr[]) to the * head of this function. */ if ( *(brd->board + brd->offset) == brd->player->piece && brd->offset != (start + drn_ary[index]) ) { int x; char outstr[90]; x = sprintf ( &outstr[0], "Valid %c%c %c trail found ", ((index == 0 || index == 3 || index == 5) ? '^' : ((index == 1) ? '<': ((index == 6) ? '>' : 'v') )), ((index <= 2) ? '<' : ((index >= 5) ? '>' : ((index == 3) ? '^' : 'v' ))), brd->player->piece ); x += sprintf ( &outstr[x], "from %c%c (%d = \'%c\') to %c%c (%d = \'%c\')", (start / BRD_W) + 'A', (start % BRD_W) + (( (start % BRD_W) < 10) ? '1' : ( ((start % BRD_W) == 10) ? ('0' - 10) : ('A' - 11) )), start, *(brd->board + start), (brd->offset / BRD_W) + 'A', (brd->offset % BRD_W) + (( (brd->offset % BRD_W) < 10) ? '1' : ( ((brd->offset % BRD_W) == 10) ? ('0' - 10) : ('A' - 11) )), brd->offset, *(brd->board + brd->offset) ); bsshowtext ( &outstr[0] ); }; #endif /* DEBUG */ /* Check that the piece at the end of the trail belongs to the current Player * and that at least one intermediate piece was detected (i.e. that the end * of the trail is not in a square adjacent to the start of the trail). * If so return TRUE (valid trail), else, return FALSE (trail invalid). */ if ( *(brd->board + brd->offset) == brd->player->piece && brd->offset != (start + drn_ary[index]) ) { return ( TRUE ); } else return ( FALSE ); }; /******************************************************************************* flip_trail() - This function attempts to invert a trail of pieces belonging to the opponent of the specified Player on the specified Board, starting at the specified square, in the direction specified. The trail is assumed to be a valid one, and the number of pieces actually flipped is returned. The direction is specified as an offset (int dirn) to be successively added to the pointer offset to the current square. As usual, the Othello Board, current Player and current square are given in the Board descriptor pointed to by (BOARD *)brd . *******************************************************************************/ static int flip_trail ( brd, dirn ) register BOARD *brd; /* Board and poisiotn to start from. */ register int dirn; /* Direction of trail. */ { register int flipped = 0; /* Number of pieces actually flipped. */ /* Continue moving in the direction given by offset (int)dirn until we reach * a piece which does not belong to the opponent of the current Player. */ do { /* Flip the piece. */ *(brd->board + brd->offset) = brd->player->piece; flipped++; brd->offset += dirn; /* Move in specified direction */ } while ( *(brd->board + brd->offset) == brd->player->opponent->piece ); /* Return number of pieces flipped, compensating for the newly-placed piece. */ return ( flipped - 1 ); }; /* End of File DO_MOVE.C */ PMF$#"othello.h"G* strdup( str)G* str;;{G* newstr;;x;;$(( newstr(G*)(H( str)+W)) NULL) { (x_;;xH( str);;x)*( newstr+x)*( str+x);; };;o( newstr);;};;E The At_???? macros each take a Board Descriptor as their argument. E Their value is TRUE or FALSE, depending on whether the square E described by the (BOARD *)brd descriptor is in the topmost row, E bottommost row, leftmost column or rightmost column of the Board E respectively. E E.IMPORTANT...IMPORTANT...IMPORTANT...IMPORTANT...IMPORTANT...IMPORTAE E These macros will not work with Hisoft C. From experience, it E appears that - among the many, many things which the Hisoft C E Interpreter cannot handle - it cannot handle macros which involve E struct's. You may remember the problems with the macros used in E game_over() last month - which have now been abandoned. E E As a consequence, the macros have been replaced by the 4 (slower) E functions given below. Sorry, but these macros are just too damn E useful for me to deprive non-Hisoft C users of them.  At_top( brd) BOARD* brd;;{o( brd offset BRD_W);;};;At_bottom( brd) BOARD* brd;;{o(( brd offset+ BRD_W) BRD_SIZ);;};; At_left( brd) BOARD* brd;;{o(( brd offset% BRD_W)_);;};;At_right( brd) BOARD* brd;;{o(( brd offset% BRD_W)( BRD_W-W));;};;/******************************************************************************* Program: Othello Desc: A program to play Othello on the AtarI ST Author: Roy Stead Created: 19/2/93 File: graph.c Desc: Graphics routines. Notes: This code is written to accompany the _C'ing Straight_ C Tutorial series, which started in the April 1993 issue of _Atari ST User_ magazine. Updates: Date By Comments *******************************************************************************/ #include "othello.h" /* OTHELLO program definitions. */ extern char get_key(); extern int end_othello; /******************************************************************************* show_board() - Displays the entire Othello Board, a pointer to which is passed in (BOARD *)brd . This function also detects a Game Over. *******************************************************************************/ extern void show_board ( brd ) register BOARD *brd; /* The Othello Board to display.*/ { register int x; /* General looping variable. */ register PLAYER *player0, *player1; /* Ptrs to the two players. */ printf ( "%cE", ESC ); /* VT52 control code - clears the screen*/ /* Display the header line above the Board. */ printf ( " " /* two spaces*/ ); for ( x = 0; x < BRD_W; x++ ) { if ( x < 9 ) /* Only needed for wider Board */ putchar ( '1' + x ); else { if ( x == 9 ) putchar ( '0' ); else putchar ( 'A' + x - 10 ); }; }; printf ("\n " /* two spaces */ ); for ( x = 0; x < BRD_W; x++ ) putchar ( '_' ); printf (" \n" ); for ( brd->offset = 0; brd->offset < BRD_SIZ; (brd->offset)++ ) { if ( At_left(brd) ) { putchar ( 'A' + (brd->offset / 8) ); /* Show line */ putchar ( '|' ); }; if ( (putchar ( *(brd->board + brd->offset) )) == - 1 ) { end_othello = 2; /* Putchar() error */ return; /* Exit function, but no return value */ }; if ( At_right(brd) ) { putchar ( '|' ); putchar ( '\n' ); /* Output '\n' at end of line */ }; }; printf (" " /* two spaces */ ); for ( x = 0; x < BRD_W; x++ ) /* Underline Board. */ putchar ( '' ); printf (" \n\n" ); /* Set (PLAYER *)player0 to point to Player Zero, and (PLAYER *)player1 to * point to Player One, to fascilitate the display of names with the score. */ if ( brd->player->piece == PLAY0_PIECE ) { player0 = brd->player; player1 = brd->player->opponent; } else { player0 = brd->player->opponent; player1 = brd->player; }; /* Show the current score. */ printf ( "Score:\t%s (%c): %d\t\t%s (%c): %d\n", player0->name, player0->piece, player0->score, player1->name, player1->piece, player1->score ); /* Prompt user to enter a move if the user is human. */ if ( brd->player->level < 0 ) { printf ( "\n\nCommands available: " ); printf ( "Q (Quit), R (Restart), ESC (skip a go)\n\n" ); printf ( "Type your move, player %s (%c) (e.g. A7): ", brd->player->name, brd->player->piece ); }; }; /******************************************************************************* The functions which follow are not commented for two reasons. Firstly, they should be self-explanatory, and secondly they are merely stop-gap functions, provided to perform simple output-to-screen operations. They are here to provide a screen interface which is under our control and through which all screen output from this program is to pass. As we move into the world of GEM, in coming months, these functions will gradually be extended and/or replaced until we end up with a full GEM screen interface without having the problems of having to rewrite large chunks of the rest of our program every time we make a change to the way text is shown on-screen. *******************************************************************************/ extern void showtext ( str ) char *str; { printf ( str ); }; extern void bsshowtext ( str ) char *str; { int x; x = printf ( str ); for ( ; x ; x-- ) putchar ( '\b' ); }; extern void pause ( str ) char *str; { int len; char outstr[90]; void bsshowtext(); len = sprintf ( &outstr[0], "%s: Press A Key", str ); bsshowtext ( &outstr[0] ); get_key(); /* Wait for a key press */ do { /* Erase text */ len--; outstr[len] = SPC; } while ( len != 0 ); bsshowtext ( &outstr[0] ); }; extern void showchar ( c ) char c; { putchar ( c ); }; extern void moveleft ( x ) int x; { while ( x-- ) putchar ( '\b' ); }; /* End file GRAPH.C */ /******************************************************************************* Program: Othello Desc: A program to play Othello on the AtarI ST Author: Roy Stead Created: 19/2/93 File: human.c Desc: Human player handling routines. Notes: This code is written to accompany the _C'ing Straight_ C Tutorial series, which started in the April 1993 issue of _Atari ST User_ magazine. Updates: Date By Comments *******************************************************************************/ #include "othello.h" /* OTHELLO program definitions. */ extern void setup_board(), bsshowtext(), pause(); extern void showchar(), moveleft(); extern int make_move(); extern char get_key(); extern int end_othello; /******************************************************************************* do_human() - Handle a single turn by a human Player. Given the state of the Board in the structure pointed to by (BOARD *)brd, this function gets commands from the user until a valid move or command key is entered. Commands are executed, and moves are checked for legality, and executed if legal. Illegal moves generate a message and a prompt for another move. *******************************************************************************/ extern void do_human ( brd ) register BOARD *brd; /* Pointer to Board Descriptor structure*/ { register int flipped; /* Number of pieces flipped by move. */ int move_made; /* "User made their move?" flag. */ int len; /* Length of string in (char)outstr[] */ char outstr[80]; /* Used to store output text. */ int get_move(); /* Gets a move from the Player. */ do { /* Read in a move from the (human)Player. * The move entered is placed in the 'x' and 'y' fields of the * (BOARD *)brd structure passed to the function. * * Note: If a command key was pressed, get_move() now returns TRUE. */ move_made = get_move ( brd ); if ( !move_made ) { flipped = make_move ( brd ); if ( flipped > 0 ) /* Do move if legal */ { /* Update score. */ brd->player->score += flipped + 1; brd->player->opponent->score -= flipped; /* Switch to next Player if the move given was legal. */ brd->player = brd->player->opponent; move_made = TRUE; /* Signal command done */ } else { /* Move was illegal, so try again. */ len = sprintf ( &outstr[0], "| Illegal Move" ); pause ( &outstr[0] ); /* Show text and pause */ moveleft ( 2 ); bsshowtext ( " " ); /* Erase move */ }; }; /* End if (!move_made) */ } while ( !move_made ); }; /******************************************************************************* get_move() - Get a move from the Player. Reads in two characters from the Player, and translates them into coordinates in the Othello Board. Those coordinates are then placed into the 'x' and 'y' fields of the Board descriptor pointed to by the passed-in (BOARD *)brd structure. Returns TRUE if a command was typed, FALSE if a move was entered. Exercise: Above certain values of BRD_W or BRD_H this function will have some problems. Can you work out what those values are, and why they cause problems? How could you cure this? (hint: the values are different for BRD_W and BRD_H) *******************************************************************************/ static int get_move ( brd ) register BOARD *brd; /* Pointer to Othello Board descriptor */ { register char c; /* The character typed by the Player. */ /* We first of all obtain a single character from the Player, * repeating this as many times as is necessary before we get a * valid one. */ do { c = get_key(); /* Note that valid characters are a command key or a row indicator. */ } while ( !((c >= 'A' && c <= ('A' + BRD_H)) || c == QUIT_KEY || c == RESTART_KEY || c == SKIPGO_KEY) ); brd->offset = (c - 'A') * BRD_W; if ( c >= 'A' && c <= 'Z' ) /* Echo character to the screen */ showchar ( c ); /* We only bother to obtain the second character from the user if the first * was a coordinate, rather than a command. */ if ( c >= 'A' && c <= ('A' + BRD_H) ) { /* Next we repeat the operation but we're looking for a character to * give us the column of the square this time. */ do { c = get_key(); /* Valid characters are a command key or a column-indicator. * * Note that enabling the code to be more general causes us * to put in some code which is to be conditionally compiled * depending on the value of BRD_W. Try to work out exactly * which pieces of code will be compiled with different values * of BRD_W before you experiment with the BRD_W value. If you * are using Hisoft C then this is more than an academic * exercise: you will have to re-write this while() conditional * slightly, using the #if/#endif statements as a guide, * whenever the BRD_W value is altered before your code will * work with that interpreter. */ } while ( !( /* Start of while() conditional */ #if ( BRD_W > 9 ) ( c >= '0' && c <= '9') || #if ( BRD_W > 10 ) ( c >= 'A' && c <= ('A' + BRD_W - 10) ) || #endif /* ( BRD_W > 10 ) */ #else ( c >= '1' && c <= ('0' + BRD_W) ) || #endif /* ( BRD_W > 9 ) */ c == QUIT_KEY || c == QUIT_KEY || c == SKIPGO_KEY ) ); /* End of while() conditional */ if ( c != QUIT_KEY && c != RESTART_KEY && c != SKIPGO_KEY ) { showchar ( c ); /* Echo character to the screen */ /* Translate character pressed into an x-coordinate. */ if ( c >= '1' && c <= '9' ) brd->offset += c - '1'; else { if ( c == '0' ) brd->offset += 9; else brd->offset += c - 'A' + 10; }; }; }; /* Handle commands given by the user. */ if ( c == QUIT_KEY ) /* Quit program */ end_othello = 3; if ( c == SKIPGO_KEY ) /* Skip a turn: switch... */ brd->player = brd->player->opponent; /* ...to next Player. */ if ( c == RESTART_KEY ) /* Restart (new game) */ setup_board ( brd ); /* Return TRUE if a move has been entered by the Player, FALSE if a command. */ if ( c == SKIPGO_KEY || c == RESTART_KEY || c == QUIT_KEY ) return ( TRUE ); else return ( FALSE ); }; /* End of File HUMAN.C */ /******************************************************************************* Program: Othello Desc: A program to play Othello on the AtarI ST Author: Roy Stead Created: 19/2/93 File: init.c Desc: Initialisation routines. Notes: This code is written to accompany the _C'ing Straight_ C Tutorial series, which started in the April 1993 issue of _Atari ST User_ magazine. Updates: Date By Comments *******************************************************************************/ /* If using the Hisoft C Interpreter, delete the #include lines between the * #ifndef IC/#endif lines or that package will produce a weird error message * about finding an error in the header file. Don't ask me why, but it does... */ #ifndef IC #include /* STRING definitions. */ #include /* Memory ALLOCation Header file */ #endif /* IC */ #include "othello.h" /* OTHELLO program definitions. */ extern int end_othello; /******************************************************************************* setup_board() - Setups a blank Board ready for a new game. The Board to set up is given in the Board descriptor pointed to by (BOARD *)brd . *******************************************************************************/ extern void setup_board ( brd ) register BOARD *brd; /* Pointer to Board to initialise. */ { register int x; /* Looping variable. */ for ( x = 0; x < BRD_SIZ; x++ ) *(brd->board + x) = EMPTY; /* Set Board to empty squares */ /* Player zero goes first. */ if ( brd->player->piece != PLAY0_PIECE ) brd->player = brd->player->opponent; /* Othello starts off with the central four pieces already on the Board. */ brd->offset = (BRD_W >> 1) + ((BRD_H * BRD_W) >> 1); /* <4,4> in 8x8 */ *(brd->board + brd->offset) = brd->player->piece; /* 44 */ *(brd->board + brd->offset - 1) = brd->player->opponent->piece; /* 34 */ *(brd->board + brd->offset - BRD_W - 1) = brd->player->piece; /* 33 */ *(brd->board + brd->offset - BRD_W) = brd->player->opponent->piece; /* 34 */ /* Reset scores for the two Players. */ brd->player->score = brd->player->opponent->score = 2; brd->minimax = 0; }; /******************************************************************************* brdcreat() - Creates an Othello Board descriptor. Returns a pointer to the new Othello Board, or NULL. *******************************************************************************/ extern BOARD *brdcreat() { register BOARD *brd; /* Pointer to Othello Board. */ /* Obtain a memory block for our Othello Board Descriptor. * Note the use of sizeof(), which calculates - at compile time - the correct * number of bytes required to store a BOARD structure. sizeof() can, of * course, be used with any C variable type and "returns" an int . * * Exercise: Try combining these two malloc() calls into a single call to * allocate sufficent memory for both required memory blocks. * Hint: You'll need to use cast-to-type statements, and * to think about the way pointer addition is handled in C. */ if ( (brd = (BOARD *)malloc ( (long)sizeof(BOARD) )) == NULL ) end_othello = 1; else { brd->nxtbrd = NULL; /* Reset Next Board pointer */ /* Now obtain a memory block for the 'board' field of the descriptor. */ if ( (brd->board = (char *)malloc ( (long)BRD_SIZ )) == NULL ) end_othello = 1; }; return ( brd ); /* Return pointer to new Board descriptor */ }; /******************************************************************************* get_players() - Takes as its argument a pointer to a (previously initialised) Board descriptor structure (BOARD *)brd . Initialises the 'player' field of that structure, by allocating memory for the PLAYER blocks and initialising those blocks. Returns TRUE on success, FALSE on failure. *******************************************************************************/ extern int get_players ( brd ) register BOARD *brd; /* Board descriptor to place Players */ { register PLAYER *newplayer; /* Pointer to blocks containing Players */ /* Allocate space for two players. */ if ( (newplayer = (PLAYER *)malloc ( 2L * (long)sizeof(PLAYER) )) == NULL ) { end_othello = 1; return ( FALSE ); } else { /* Two players, pointing to each other so that each is defined * as the opponent of the other. * * Remember that (newplayer + 1) points to the second PLAYER * struct in the block, _not_ the second byte or field. */ newplayer->opponent = newplayer + 1; brd->player = newplayer->opponent->opponent = newplayer; /* Initialise the actual player data fields. Note the use of strdup(), * which allocates memory for a string and then copies the given * string into the newly-allocated position, and returns a pointer * to it. */ brd->player->piece = PLAY0_PIECE; /* Piece used by Player */ brd->player->name = strdup ( PLAY0_NAME ); /* Player's name*/ brd->player->score = 0; /* Player's score */ brd->player->level = PLAY0_LEVEL; /* Player's skill level */ brd->player->opponent->piece = PLAY1_PIECE; /* Piece*/ brd->player->opponent->name = strdup ( PLAY1_NAME ); /* Name */ brd->player->opponent->score = 0; /* Score*/ brd->player->opponent->level = PLAY1_LEVEL; /* Skill*/ return ( TRUE ); }; }; /* End file INIT.C */ /******************************************************************************* Program: Othello Desc: A program to play Othello on the AtarI ST Author: Roy Stead Created: 19/2/93 File: main.c Desc: Entry point and main controlling loop. Notes: This code is written to accompany the _C'ing Straight_ C Tutorial series, which started in the April 1993 issue of _Atari ST User_ magazine. Updates: Date By Comments *******************************************************************************/ #include "othello.h" /* OTHELLO program definitions. */ extern void setup_board(), show_board(), do_human(), pause(); extern int do_computer(), get_players(), game_over(); extern BOARD *brdcreat(); /******************************************************************************* Set up extern variables: These variables are visible to all files. *******************************************************************************/ int end_othello = 0; /* Set non-zero to exit Othello */ /******************************************************************************* Set up static variables: These variables are visible to this file only. *******************************************************************************/ /* Error messages for Othello. */ static char *errors[3] = { /* end_othello */ "Not enough memory", /* 1 */ "Error displaying Board", /* 2 */ "Quit pressed" /* 3 */ }; /******************************************************************************* main() - Entry point of program. *******************************************************************************/ main() { register BOARD *brd; /* The main Othello Board descriptor. */ register int stalemate; /* TRUE if no legal moves for anyone. */ /* Create the main Othello Board. */ if ( (brd = brdcreat()) != NULL ) { if ( get_players ( brd ) ) /* Initialise Players */ { setup_board ( brd ); /* Set up Othello Board. */ show_board ( brd ); /* Display Othello Board. */ }; }; /* Main loop - repeats until end_othello takes a non-zero value */ while ( !end_othello ) { /* Handle a single turn for a computer or human Player. */ if ( brd->player->level >= 0 ) { /* Handle the computer-controlled Player's turn - note that * do_computer() now returns TRUE if the computer could * find no legal moves for itself _or_ for the human player. * * This facility used to be in the function game_over(), but * has been shifted into do_computer() to speed up execution. */ stalemate = do_computer ( brd ); } else { do_human ( brd ); /* Handle a human Player's turn */ stalemate = FALSE; }; show_board ( brd ); /* Redisplay Othello Board. */ if ( game_over ( brd, stalemate ) ) /* If Game Over found...*/ { setup_board ( brd ); /* ...Set up Board for new game */ show_board ( brd ); /* Redisplay Othello Board. */ }; }; /* Display the error code, waiting for a key press after it is displayed. */ pause ( errors[end_othello - 1] ); while ( brd != NULL ) /* Free Othello Board descriptor memory block. */ { if ( brd->board != NULL ) free ( brd->board ); if ( brd->player != NULL ) { if ( brd->player < brd->player->opponent ) free ( brd->player ); else free ( brd->player->opponent ); }; free ( brd ); brd = brd->nxtbrd; }; }; /* End of File MAIN.C */ # makefile for Othello program # # Created: 18/2/93 by RS # # If you own a MAKE program then this file can be used to assist you in # compiling and linking your code. See the documentation for your MAKE # program for details. Note that hash (#) marks the start of a comment. # # Pre-processor symbols: # # DEBUG used to compile debugging code in do_move.c # # Compiler flags to use when compiling this program CFLAGS = -O #CFLAGS = -DDEBUG # C libraries to link with this code # dlibs.a is the Sozobon standard ANSI & Unix C libraries. # These libraries are built in to Hisoft C, and may have a different name # for your compiler. Lattice C's, for example, is called clib.bin # LIBS = dlibs.a # The object code files which are to be linked together to form our Othello # program. Each .o file is derived from a .c file. A common mistake when # constructing makefiles is to list the source code files (*.c) here instead # of the object code files (*.o) # OBJ = computer.o do_move.o graph.o human.o init.o main.o toolkit.o # Creation of othello.prg program depends on all object files. # othello.prg: $(OBJ) $(CC) -o $@ $(OBJ) $(LIBS) # If othello.h is altered, recompile everything # $(OBJ): othello.h /******************************************************************************* Program: Othello Desc: A program to play Othello on the AtarI ST Author: Roy Stead Created: 19/2/93 File: othello.h Desc: Header file for the Othello package Notes: This code is written to accompany the _C'ing Straight_ C Tutorial series, which started in the April 1993 issue of _Atari ST User_ magazine. Notes2: A separate version of this header file, OTHELLO.HS, is provided for use with the Hisoft C Interpreter. That file should be renamed to OTHELLO.H and placed in the same folder as your Hisoft C program. Updates: Date By Comments 19/2/93 RS Changed BOARD struct definition to use a single offset into block pointed to by (char *)board field instead of separate x and y fields *******************************************************************************/ #ifndef OTHELLO_H #define OTHELLO_H #include /* STandarD Input and Output Header */ /******************************************************************************* Portability Macros - this code fascilitates the transfer of code between different compilers, possibly even on different machines. *******************************************************************************/ #ifdef SOZOBON /* Sozobon C compiler-specific redefinitions. */ #define const /* Sozobon doesn't understand const */ #define malloc lalloc /* Sozobon's malloc uses int as arg... */ /* ...Substitute lalloc (uses a long) */ #endif /* SOZOBON */ /******************************************************************************* Constant Definitions *******************************************************************************/ #define ESC 0x1B /* ESCape code */ #define SPC 0x20 /* ASCII code for a space character */ /******************************************************************************* The Defaults: Default values of major parameters of this program *******************************************************************************/ /* The default names used for the two Players. */ #define PLAY0_NAME "Human" #define PLAY1_NAME "Mini Max" /* The default skill levels for the Players. * A value of (-1) indicates a human Player; * zero, or positive values, indicate computer Players of increasing skill. * * Notice, by the way, the brackets around the (-1). Always used brackets in * these circumstances, to avoid ambiguity when the macro is expanded. */ #define PLAY0_LEVEL (-1) #define PLAY1_LEVEL 3 /* The characters used for the individual pieces and blanks squares. */ #define PLAY0_PIECE 'O' /* Player zero's piece */ #define PLAY1_PIECE 'X' /* Player one's piece */ #define EMPTY '.' /* Empty square */ /* The command keys used in this program. */ #define QUIT_KEY 'Q' /* 'q' or 'Q' key Quits the program */ #define RESTART_KEY 'R' /* 'r' or 'R' key Restarts program */ #define SKIPGO_KEY ESC /* ESC key is used to skip a turn */ #define BRD_W 8 /* Width of Othello Board (1 <= BRD_W <= 36 */ #define BRD_H 8 /* Height of Othello Board (1 <= BRD_H <= 15)*/ /* BRD_SIZ holds the number of squares in our Othello Board. * Since we define this in terms of BRD_W and BRD_H, we could modify either * or both of those values and not have to change the definition of BRD_SIZ */ #define BRD_SIZ (BRD_W * BRD_H) /******************************************************************************* typedef'initions of struct'ures *******************************************************************************/ /* Define a structure to hold information about the Players, PLAYER. */ typedef struct plyr { char piece; /* Player's piece. */ char *name; /* Player's name. */ int score; /* Player's score. */ int level; /* Skill level (-1 is human)*/ struct plyr *opponent; /* Pointer to opponent. */ } PLAYER; /* Define the Othello Board descriptor structure, BOARD. * * A move is specified by loading field (int)offset of a structure of * this type with an offset into the (char *)board field which specifies the * square to move to, with the (struct plyr *)player field holding the * description of the Player who is making the move (held in a PLAYER block, * as defined above) and the (char *)board field pointing to a 64-byte memory * block in which is stored a description of the Othello Board on which the * move is to be made. * * The (BOARD *)nxtbrd field is provided for linked list construction. */ typedef struct oth_brd { char *board; /* The Othello Board. */ struct plyr *player; /* The current Player. */ int offset; /* Offset to current square.*/ int minimax; /* Minimax value of Board. */ struct oth_brd *nxtbrd; /* Pointer to next Board. */ } BOARD; /******************************************************************************* Macros: Macros used by the Othello program *******************************************************************************/ /* The At_???? macros each take a Board Descriptor as their argument. * Their value is TRUE or FALSE, depending on whether the square described by * the (BOARD *)brd descriptor is in the topmost row, bottommost row, * leftmost column or rightmost column of the Board respectively. */ #define At_top( brd ) ( (brd)->offset < BRD_W ) #define At_bottom( brd ) ( ((brd)->offset + BRD_W) >= BRD_SIZ ) #define At_left( brd ) ( ((brd)->offset % BRD_W) == 0 ) #define At_right( brd ) ( ((brd)->offset % BRD_W) == (BRD_W - 1) ) #endif /* OTHELLO_H */ /* End file OTHELLO.H */ PMF$E********************************************************************E E Program: Othello E Desc: A program to play Othello on the AtarI ST E Author: Roy Stead E Created: 19/2/93 E E File: othello.hs E Desc: Hisoft C-specific Header file for the Othello package E E Notes: This code is written to accompany the _C'ing Straight_ C E Tutorial series, which started in the April 1993 issue of E _Atari ST User_ magazine. E E Notes2: A separate version of this header file, OTHELLO.H, is E provided for use with every C compiler except the Hisoft E C Interpreter. This file should be renamed to OTHELLO.H E and placed in the same folder as your Hisoft C program. E********************************************************************#OTHELLO_H#nOTHELLO_H(){W}E********************************************************************E Hisoft C-specifics: Little bits missed out of the Hisoft C E Interpreter which are too important to E work-around. E E The bulk of these definitions/declarations E are a straight replacement for Hisoft C's E embarrassingly bad stdio.h file, which E should - of course - be taken out and shot - E and to provide definitions which would be in E a stddef.h file, if Hisoft C bothered to E provide one. We can't #include stdio.h and E then #undef and then re-#define the incorrectE definitions, because Hisoft C doesn't E understand #undef. And we cant conditionally-E compile this code because Hisoft C won't E allow code to be loaded in unless it conformsE to that package's ludicrous restrictions - E which means that the compiler-portability E stuff in the plain ASCII OTHELLO.H file E cannot even be loaded into Hisoft C, let E alone interpretted by it. You may have E gathered that I am less than impressed by E the Hisoft C Interpreter. E********************************************************************#n TRUE(){(WW)+ TRUE and FALSE are oddly...}#n FALSE(){(W_)+ ...defined in Hisoft C's...})) ...portab.h header file,...)) ...and nowhere else. #n NULL(){(*)_+ Incorrectly defined in... })) ...Hisoft C's stdio.h #n EOS(){+ For some bizarre reason,...})) ...omitted from Hisoft... )) C's stdio.h file. E This chunk below is lifted from Hisoft C's stdio.h header file. E We're not actually using many of these yet, but we will be as we E go on, so I might as well put them here now...  _iobuf{G* _ptr;; _rcnt;; _wcnt;;G* _base;; _size;; _flag;; _file;;G _cbuff;;} FILE;;#n EOF(){-W}#n BUFSIZ(){[}#n _BUFSIZ(){[}#n _NFILES(){W}#n stdin(){()}#n stdout(){()}#n stderr(){()}#n stdaux(){()}#n stdprn(){()}#n errno(){()}E********************************************************************E Constant Definitions E********************************************************************#n ESC(){!' ESCape code }#n SPC(){ !' ASCII code for a space character }E********************************************************************E The Defaults: Default values of major parameters of this program E********************************************************************E The default names used for the two Players. #nPLAY0_NAME(){Human}#nPLAY1_NAME(){ Mini Max}E The default skill levels for the Players. E * A value of (-1) indicates a human Player; E * zero, or positive values, indicate computer Players of E increasing skill. #nPLAY0_LEVEL(){(-W)}#nPLAY1_LEVEL(){W!' Larger values are very, very slow }E The characters used for the individual pieces and blanks squares. #nPLAY0_PIECE(){O0 Player zero's piece }#nPLAY1_PIECE(){X0 Player one's piece }#n EMPTY(){.0 Empty square }E The command keys used in this program. #nQUIT_KEY(){Q!' 'q' or 'Q' key Quits the program }#nRESTART_KEY(){R!' 'r' or 'R' key Restarts program }#nSKIPGO_KEY(){ ESC!' ESC key is used to skip a turn }#n BRD_W(){W1 Width of Othello Board (1 <= BRD_W <= 36) }#n BRD_H(){W1 Height of Othello Board (1 <= BRD_H <= 15) }E BRD_SIZ holds the number of squares in our Othello Board. #n BRD_SIZ(){( BRD_W* BRD_H)}E********************************************************************E typedef'initions of struct'ures E********************************************************************E Define a structure to hold information about the Players, PLAYER.  plyr{G piece;;) Player's piece. G* name;;) Player's name.  score;;) Player's score.  level;;) Skill level (-1 is human)  plyr*opponent;;) Pointer to opponent. } PLAYER;;E Define the Othello Board descriptor structure, BOARD. E A move is specified by loading field (int)offset of a structure of E this type with an offset into the (char *)board field which E specifies the square to move to, with the (struct plyr *)player E field holding the description of the Player who is making the move E (held in a PLAYER block, as defined above) and the (char *)board E field pointing to a 64-byte memory block in which is stored a E description of the Othello Board on which the move is to be made. E E The (BOARD *)nxtbrd field is provided for linked list construction. oth_brd{G* board;;) The Othello Board.  plyr* player;;) The current Player.  offset;;) Offset to current square.  minimax;;) Minimax value of Board.  oth_brd* nxtbrd;;) Pointer to next Board. } BOARD;;E********************************************************************E Macros: Macros used by the Othello program E********************************************************************E The At_???? macros do not work with Hisoft C. I have no idea why. E They are replaced by (slower) function calls, to be found in E FOOBAR.C # OTHELLO_H  End file OTHELLO.H /******************************************************************************* Program: Othello Desc: A program to play Othello on the AtarI ST Author: Roy Stead Created: 19/2/93 File: toolkit.c Desc: General purpose bread-and-butter functions Notes: This code is written to accompany the _C'ing Straight_ C Tutorial series, which started in the April 1993 issue of _Atari ST User_ magazine. Updates: Date By Comments *******************************************************************************/ #include /* Operating System BINDings */ #include "othello.h" /* OTHELLO program definitions. */ extern void pause(); extern BOARD *brdcreat(); extern int end_othello; /******************************************************************************* get_key() - Waits for a key press from the user, and returns the ASCII code of the key pressed. If the key was an alphabetic character, then the _upper case_ character is returned. *******************************************************************************/ extern char get_key() { register char c; /* Character pressed by the user. */ /* Bconin() waits for a keypress and returns a long integer containing * the keyboard scan code for that key. Bconin() is a gemdos function, * and is declared in the header file . * * The ampersand (&) performs a bitwise AND operation. * We use it here because we are only interested in the lower word of * the value returned from Bconin(), as that word contains the ASCII * code of the character typed. Explanations in future articles, okay? */ c = (char)(Bconin ( 2 ) & 0x00FF); if ( c >= 'a' && c <= 'z' ) /* Convert upper to lower case */ c -= 'a' - 'A'; return ( c ); }; /******************************************************************************* game_over() - Checks for a Game Over situation. If Game Over is detected, produces an appropriate Win/Lose/Draw message and returns TRUE, otherwise just returns FALSE. *******************************************************************************/ extern int game_over ( brd, stalemate ) register BOARD *brd; /* Pointer to current Board Descriptor */ register int stalemate; /* TRUE if no legal moves for anyone. */ { int len; /* Length of string in (char)outstr[] */ char outstr[80]; /* Used to store output text. */ /* Check to see if the game is over. * * This happens if all of the squares are filled or if either Player has no * pieces remaining on the Board. A Game Over is also forced when neither * Player has any legal moves available (a stalemate). */ if ( (brd->player->score + brd->player->opponent->score) == BRD_SIZ || brd->player->score == 0 || brd->player->opponent->score == 0 || stalemate ) { /* sprintf() behaves exactly like printf(), but takes an extra * argument before the formatting string, which is a pointer to a * string to which all output will be sent _instead of_ being sent * to the screen. Like printf(), sprintf() returns the number of * characters output. */ len = sprintf ( &outstr[0], "Game Over: " ); /* Signal to the user that a stalemate has been found. * Only signal if the stalemate is the _sole_ reason for Game Over. */ if (((brd->player->score + brd->player->opponent->score) != BRD_SIZ) && stalemate && brd->player->score != 0 && brd->player->opponent->score != 0 ) { len += sprintf ( &outstr[len], "Stalemate: " ); }; /* Handle outright win or draw messages. */ if ( brd->player->score == brd->player->opponent->score ) len += sprintf ( &outstr[len], "It was a draw." ); else { /* Show message indicating which Player has won. * * Note the use of the ternary conditional operator within * this sprintf() statement. */ len += sprintf ( &outstr[len], "Player %s (%c) has won.", ((brd->player->score > brd->player->opponent->score) ? brd->player->name : brd->player->opponent->name ), ((brd->player->score > brd->player->opponent->score) ? brd->player->piece : brd->player->opponent->piece ) ); }; pause ( &outstr[0] ); /* Show text and wait for key */ return ( TRUE ); /* Signal Game Over */ } else return ( FALSE ); /* Signal Game not over */ }; /******************************************************************************* kill_list() - Given a pointer to the first element in a linked list, this function will delete the entire list. *******************************************************************************/ extern void kill_list ( first ) register BOARD *first; /* Pointer to 1st item in list to kill. */ { register BOARD *currbrd; /* Pointer to items in list. */ /* Note that first always points to the first item in the linked list on * every iteration of the loop (the previous first item having been erased). */ do { currbrd = first; /* Pointer to 1st item in list. */ first = currbrd->nxtbrd; /* This will be 1st next time. */ free ( currbrd->board ); /* Kill block used by 1st item. */ free ( currbrd ); /* Kill the first item in list. */ /* NB/ We don't delete player fields as these are... */ /* shared globally by all Board Descriptors. */ } while ( first != NULL ); /* Carry on until end detected. */ }; /******************************************************************************* brddup() - Given a pointer to an Othello Board descriptor structures (BOARD *srcbrd), this function creates a duplicate of (BOARD *)srcbrd and returns a pointer to the new structure. Note that the new structure's (char *)board field points to a different memory block from that pointed to by the (char *)board field of the passed-in descriptor, though the contents of the latter are copied across to the new structure. The (PLAYER *)player field of the new both structures do, however, point at the same memory block. Since this function is used mainly in the creation of linked lists, the (BOARD *)nxtbrd field of the new structure is not duplicated, but is set to NULL. *******************************************************************************/ extern BOARD *brddup ( srcbrd ) register BOARD *srcbrd; /* Board descriptor to duplicate. */ { register BOARD *newbrd; /* Pointer to duplicate Board. */ register int x; /* Looping variable. */ /* Create a new Othello Board descriptor. */ if ( (newbrd = brdcreat()) != NULL ) { /* Copy contents of srcbrd to newbrd */ for ( x = 0; x < BRD_SIZ; x++ ) /* Copy Board info */ *(newbrd->board + x) = *(srcbrd->board + x); newbrd->offset = srcbrd->offset; /* Copy square info */ newbrd->player = srcbrd->player; /* Copy Player info */ newbrd->minimax = srcbrd->minimax; /* Copy minimax value */ /* (BOARD *)nxtbrd field was set to NULL by brdcreat() */ }; return ( newbrd ); /* Return a pointer to newbrd, or NULL */ }; /* End of File TOOLKIT.C */ `,\n*O(o#1&,֬ #1&,֬#1&,֬#1#1#,1N|&91&CD֬$|0$ g$jԃl$<m/<,j?< NA\?X6/ N$X?/ N\J@g/ N .N$X`/ N TXv`09-S@H |-/0N X" gPJg /N&XJg k + d/+N&X/ N&X&k ` k/( N&X`LN^NuNV/?<?<NX<am <zn< H0&N^NuNVH&n6. k"k"i 0(i|@g kJhg k h JhgJCg/<.7HnNP8 k"k"i 0(i|@g4JCg0 kJhg& k h Jhg/<.+0A/NP@ k"k"i 0(if./<.0A/NP@HnN XpLN^Nu k"k"i 0(ioT kH? k"k"i 0(io& k (//<.0A/NO@` k h (` k h `p`~NVH&n(K&l /N&.N&X fLN^NuNVH&nN J(@ g0v|@lH Ѓ @H "CRC`9k)k9k LN^NuNVN+NN,N^NuNVH6.0|@?N)T&@ f/<.\?< N\?XR`R`NVaRaJ@f aDJ@faR y,dJf y,d 1@N^NuNV/ 1.fBg?<B/<.N.O v|l0pм. @0( |gpм. @/NXRC`&N^NuNVHv&|.|l?+ N^TJ@gk RCG`9.g?<?</<1/<.N.O /<N,*XLN^NuNVH,. *.&y,` f pLxN^Nu(EvJg =gRRC`xH Jg@H (sH 4=8f(?// N%O J@fJg H ЃR F 0`RD`p`NV/ &n gJfp&_N^NuHn/ aTP|fp` .`NVH6.?<?/<?<BN (Jo$?<?/NN^NuNVH6. ?</NT&@/<2f?<N\gDpH6?/.?<NNP31/ ?<N\Jy1g pHLN^Nup`p`NVH&n(n Bg/ ap\J@f\AC2fp0Q,g>p@, +:f H| |a@,|-pLN^Nu?<NTp`0<`p`NVBg/.aJ@f 92N^Nup`NVBgBg/.?<CNO =@m0.|W|N^Nup`NVHn/. /<r/.NN^NuNV/./. /<r/.NN^NuNVHn /./<r/<.NN^NuNV/. /./<r/<.NN^NuNV n R @ HN^NuNVH&nHn/. /<HnN6HA8B0LN^NuNVH&n/./. /<HnN6HA8B0LN^NuNVH. &n BFk 8+ 0|g0|Pg 0Eg k@ 0<`JFg < f< `B@`vNV/ &nk 0.k BS ngJ fBBk'k&_N^Nu'n 7n`NVH&90#/0?.N)FTO&@#/#/0 LN^NuNV/ &n0+ |f7|?<aTO'@f(k k A'H7|'kBS&_N^Nuk `NVH&ng/ aLXOLN^NuBD|l60<Hм. @6( 0|g0<Hм. @HPa XORD`B@`NVH&nBDf B@LxN^Nu6+ 0|f0|fB@`JSg(0|g,?/+?+ N$LPOSg k@ 8<'kBS0`0D@H,?</?+ N$POJ@l8<`NVH&n(nBDJg %fBEB.| =|Bn=|| KBFBCRpм0 @B@|g8B@|02< @6Jng=C`JCf . f|0`=C`B@|=C`6S`|Xm|xn|XH {N4x`$0L8xN^Nu<<`~?< / JFgP /N JFg8I?.?..H?.H??/ /. /.N@`I`0H`|.H?/ JFg* /N z JFgI xf/ / N%PO`p0`|`<<|0=|=||`` LTABB.| `:*TI`` NVH&n(n *n.8.BE/ N%pXO< -fz ng no<.Fl8:FJDfJFgJJnf0JDg,JFg Jg .0fBSF/ H?N\O`.SD`JFgJf`.SD`0L8N^NuJgRF`NVH&.&n 8.(KH//N*POм/ @H//N*PO&JbB/ N%XOLN^NuNVH&.&n (KJl - D&?./ /a LN^NuNV?./. 0.H/aN^NuNVH&nvx0.H*/<0HnN+POHHм0 @B@|gR` -f*xRJf 0f0RHHм0 @B@|gH @ |XfRzA0.HBHHм0 @B@|g\H @ ?HnN+f\O(@gR//N*RPOA" Ё&`J g n Jg DL8N^Nu `H`z`tH``fb 0fZAHHм0 @B@|gAH @ |Xf*T`$AH` +fR`NVH&nv0.H(/<0HnN+POHHм0 @B@|gR`Jf 0f0RHHм0 @B@|gH @ |XfRxA0.HBHHм0 @B@|gRH @ ?HnN+f\O(@g//N*RPOA" Ё&R`J g n LN^NuH`x`~H`jfl 0fdAHHм0 @B@|gAH @ |Xf4T`.AH`NV/?.?./. ?<BN &Jl31 &N^NuNV?<B?.aN^NuNV//. p0./?.?<@N &Jl310&N^NuNV//. /.?.?<@N &Jl31 &N^NuNVH&n(n f&y04JgH?/ N+f\OJgR`Jf pL8N^Nu*KJgH?/ N+f\OJfR`JgB#04 `NVH&n/ N%pXOR@?N)FTO(@g / / N+PO LN^Nu opRJgRJg RJgRJfNu o"HrAtZgmn( ` Nu o"H JfUo S`Nu4/ o"opQNug gkpNuJgpNuNVH0.@Hм08 @&P&SfLN^NuA(Pg& ЃfAC" ѓ`&L` Г(@0.@Hм08 @ Y"f f0.@Hм08 @/?<IN\O0.@Hм08 @B0.@Hм0x @B``NVH&nf 0<L8N^NuYBC|lf0@Hм08 @(PfRC`޷e0@Hм0x @ Аb*Tg XdcBA (?aTO0<`(M`B@`NVH&.P м,0d.90x|lH  |08JgRD`/J 4 &(.$ b 06 (  | There are few changes in this month's source code. The (int)x and (int)y fields of the BOARD struct have been replaced by a single (int)offset field, all text output has been redirected - using sprint() - through a small suite of functions in the file GRAPH.C and the source code has been split into separate files. If you are not using Hisoft C then you can ignore the remainder of this file, and ignore the files OTHELLO.HS and FOOBAR.C as well. Convertion Notes for Users of the Hisoft C Interpreter ------------------------------------------------------ I have gone out of my way in writing this source code to make it as compatible with the Hisoft C Interpreter as is possible, without compromising the code. Whole functions have been re-written, variables renamed, macro definitions endlessly modified and algorithms re- thought toward this end. Since this source code is to accompany a tutorial series on the C language, however, I have occassionally had to present source code which is not permitted within the extremely narrow limitations imposed by Hisoft C. So far in this tutorial series, I have provided two copies of the source code, one for Hisoft C users and one for everybody else. I will no longer be doing this, because - so long as I was supplying Hisoft C users with separate source code - you have been deprived of the opportunity to learn and get used to some of the most useful and important C commands, the compiler directives. From now on, then, you will instead be provided with a file along the lines of this one which will provide you with a guide to converting the code yourself, thus allowing you to become familiar with those commands which are incorrectly handled - or not handled at all - by the Hisoft C Interpreter. When the program works from within Hisoft C, you will know that you have succeeded. Initially, I will guide you step-by-step through the modifications which are required. As time goes by, however, you should not need to have your hand held quite so tightly, and this file will start to shrink. Before this source code will operate with Hisoft C, then, you will have to make the following changes. Not making the changes will cause Hisoft C to produce spurious, and often entirely irrelevant, error messages. -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- The OTHELLO.HS file must be moved to the same folder as your Hisoft C Interpreter program and renamed to OTHELLO.H - this replaces the OTHELLO.H file already on this disk. I would recommend, however, that you read through the OTHELLO.H file at least once, if only to get some idea of the changes made to that file in order to produce OTHELLO.HS . The Hisoft C standard library does not contain the strdup() function, a standard function which takes a pointer to a string, allocates a block of memory the same size as that string, copies the original string into the new memory block and then returns a pointer to the new memory block - or NULL if an error occurred. As a consequence, a Hisoft C file, FOOBAR.C, is supplied which defines this function for you. In the file DO_MOVE.C there is a segment of code which is to be conditionally compiled only if the symbol DEBUG is pre-defined. Hisoft C has serious difficulties, unfortunately, with all compiler commands, and so the lines "#ifdef DEBUG" and "#endif /* DEBUG */" in that file must be deleted if you wish to make use of this debugging code. In any event, the automatic variables declared within that block will need to be relocated to the head of the function, or the DEBUGging block of code deleted altogether. At the top of the file INIT.C are two lines: #include #include These two lines must be deleted or, alternatively, dummy files (containing only a comment) with these names placed in the HEADER directory. Throughout the code, function definitions are preceded with 'extern' or 'static' to indicate the scope of the function. Delete these words from in front of the function declarations, as it appears that the Hisoft C Interpreter treats functions in an odd manner and cannot handle scoped functions. On a related note: at the head of most files is a block of 'extern' statements, declaring functions and/or variables outside that file for use within it. While these declarations are _essential_ for use with a C compiler, Hisoft C, again, throws up spurious error messages when it encounters them. Therefore, delete all 'extern' lines which declare functions. e.g. delete a line "extern int foo();", but not a line "extern int foo;". In the get_best() function in the file COMPUTER.C there is a do...while() loop which has its final condition "while ((currbrd != NULL) && mfound);". While (no pun intended) this is perfectly correct C code, Hisoft C can't handle it - for no reason that I can see. You are going to have to rewrite this condition to take the "(currbrd != NULL)" out of the while() statement and replace it with a flag instead. If you've got the source code from last month's CoverDisk, you can patch in the replacement used in get_best() in that code. If not, just rewrite by introducing a new (int)flag variable whose value depends on whether or not currbrd has the value NULL. All conditional compilation has to be re-written to remove it. In particular, the conditional of the do...while() loop in get_move() should be simplified, to remove conditional compilation, to a simple condition. The precise value of the condition depends, of course, on the value which you have given to BRD_W in OTHELLO.H . -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- In the OTHELLO.H file, four macros which take arguments are defined: At_left(), At_right(), At_top() and At_bottom(). I'm very, very sorry about this, but these macros are damn-near essential for the code to be readable. Since Hisoft C cannot handle these macros, however, four functions with the same names are provided in the Hisoft C-specific file FOOBAR.C It would appear that, amongst many other things, the Hisoft C Interpreter cannot handle macros in relation to struct's. You may remember the problems caused by the PLAYR and OPPONENT macros used in game_over() last month to help clarify the code in that function. A similar problem appears to be operating here. Finally, for now, there also appear to be some problems with the pointer test function in the Hisoft C Interpreter - it claims that there are pointer errors in the strdup() function in FOOBAR.C and in setup_board() in INIT.C . No doubt it would also have difficulty with brddup() in TOOLKIT.C as well. It is best simply to switch off this feature of Hisoft C as there is nothing wrong with these routines. I say again: There is nothing wrong with these routines - Hisoft C's pointer test apparently cannot cope with looping through a memory block. /* End file README.1ST */ T */ . e0p.. d0FIG1 IMG gq$LESSON4 TXT )c0x7tt P8  x0`0`??,D@@  @0`0`!-@@  @8`8` -" %.@(( !,`,pp*"8F!D&1~((!!00*"D!!D$ ! @-- ?X ! !*"D! D$? !?@% %#! !!*!D!!D$  ! @% %" ! !+"DD#Dd!@' '!0 Б#  *"8d c!z" "   ` xx*#P ~<8% C Ad% A @BD% Ap!A#% C ! !% ~ !A!% C !@#% A @BB% A A"% A0 =~2%$%$% P#+#+#*"*")"(!(!?' ' & &%?$$#? # " " ! ?!  ????P ! ` ` AB@3"Hd@1@@B H A($  A@04x !x":8@`0$b0@G9q`,pqp 0#b$34FD@ g" @CD$hH0A!40"0QD$@ !@C( @ x `Px@A0(d @G(!@@`H"QD @AH$` Qh(СA @#2bb4FF@"$1@DP4(HI ~`@1xD:<@'`8 y xy B  !  P"""""#>#>|#|#"~"??"?"#>#>?|#|#""?"" # >#>?|#|#~"~"??"?"#>#>?|#|"""?""Pp 0x` A@1A`!1 !  @B@!  60ƀ0@G!A#C@G0qs\Վ.BY"" D @C! !B@CH!b#61ff"&$$" l!@C!A!B@C BA D$$&0!( @G!@#B@G BA D'$"AA(` !@B@A  !BA D$$ A81D!A A1@H #B#41D"4$dd!~0@z`0q B.D!#  ::P,>0, !c, !A ,B\pq`Aː,Bb"DLH@,BBA<H(H@ ,BBOH@,AB@ A HH@AB#cDhH@B>0sCG@ɐ  &?&?&%$$$$|$|>>$>>|$|# " " " " |"| >>">> |"| !         | | >> >> | |        P`?A? `@@ x@`B @B @`H! "@pB @ B @ p!A@QDāB @0 B @0$QA \8G !`Dž\QGDB ~B ~$QB&$ HDHHСD! (F b"[D$B @xB @$[D$ HLLDx! D AAJD4B @ B @ $JG$ HGGl! A  AJDB @ B @ $JD$ H@@С(!qA D A@ND BB @8B @$NB4$`HFHAQ(8!1"2( b#DG <B?B?$DA#L' item, followed by a separator (a line of minus signs with the disabled flag set) followed by 6 empty strings to use to fill in accessory names. The second title should be 'File' and should contain the following list (although you might drop out items which are irrelevant). New, Open..., Save, Save as...,Save all (optional), Recall (optional), Separator, Import, Export, Any other file commands (see below), Separator, Page Setup..., Print, Any other output relevant commands, Separator, Quit NOTE: 'Save all' saves all the files your application has open. Recall restores the current document / image / whatever to the state it was when last saved 'Any other file commands' SHOULD NOT include such as 'format disk' or delete file. File management tasks should be left to the desktop or other multitasking interface, NOT done by applications. The third title should be 'Edit', containing items as follows.. Undo, Redo (if multiple undos are allowed), Separator Cut, Copy, Paste, Delete, Separator (we'll be going into the clipboard at a later date) Select All (optional), Separator Find, Replace, Find Next (all optional), Separator Any other editing commands Other pointers are that 'save preferences' and / or 'set preferences' should be in an 'Options' menu, not the file menu. Menu items for Bold, Underline etc should actually BE bold, underlined etc (you can use settings for these). 'Help' should be at the far right. So, after you have built your menu you can save it in the resource file. It's a good idea to name menu Titles the same as their text, for reasons we shall see later. The resource editor will usually save a file too, a .H file for C, which contains defined variables so you can work by the menu titles names rather than their object numbers, which will be easier to understand and read. USING MENUS Once you have your .RSC file loaded (that's in article two, in case you were wondering) the first thing you have to do is get the address of the menu tree out of this structure. You do this with the call :- int status OBJECT *menutree (don't worry what an OBJECT is just yet. It's a resource file structure) status=rsrc_gaddr(R_TREE,MAINMENU,&menutree) Here, MAINMENU is the name I gave to the menu in the resource editor. R_TREE tells the routine to search for a particular tree of objects (it can search for other things too. See this months reference file) and menutree is the pointer to the object structure, which will now point to where our menu is. Note it is perfectly allowed to have more than one menu tree in your resource file, and shift between them as you wish. Each will have to have a separate pointer though, to keep things neat. If status=0 afterwards, you have found your tree. If it's not, you have a problem, and should really quit the program. Once you have your menu, you can display it with the following commands.. graf_mouse(256,&dummy); (stop the mouse interfering with the menu draw) status=menu_bar(menutree,1); (draw the menu) graf_mouse(257,&dummy); (turn the mouse back on) I have includes set up so I can use the two graf_mouse calls with MOUSE_OFF and MOUSE_ON, respectively. If status is >0, an error has occurred and if it is 0 you are OK. Should you want to remove the menu bar, you can do it like this.. graf_mouse(256,&dummy); (stop the mouse interfering with the menu draw) status=menu_bar(menutree,0); (erase the menu) graf_mouse(257,&dummy); (turn the mouse back on) Note forgetting to turn the mouse back on afterwards is very embarrassing.. Once you have your menu drawn, the system deals with dropping the menus down, making the selected item invert, all that. What it expects you to deal with is the effects of a click. Actually, it will probably also send you a message telling you to redraw the window underneath the menu, but that's for another time. How does it tell you about a click? It sends you a message! We have gone over how to receive messages before, so I won't repeat that. The message you get has the following form.. Menu Word Contents 0 10 (will be defined somewhere as MN_SELECTED, so you can use that) 3 Object number of menu title 4 Object number of menu item The last two should be defined in the include file the RSC editor produced, so instead of :- if ((message[3]=5) AND (message[4]=8)) THEN Do_Quit() You can do :- if ((message[3]=FILE) AND (message[4]=QUIT) THEN Do_Quit() (I know, it's not C, but AND is clearer than && or whatever. If you care, SUE ME). Actually, you are better off using nested CASE statements rather than lots of IF's as well, if you are programming in C. When you have dealt with the click, the last thing you have to do is reset the inverted menu title back to normal. You do this with :- status=menu_tnormal(menutree,message[3],1); If status is <0, you were OK, if it equals 0, you have an error. (status=menu_tnormal(menutree,message[3],0) will make it inverted) Now, some menus have to be disabled, some of the time, and sometimes you want little checkmarks next to menus, yes? That's the next thing.,. CHANGING MENUS You could, of course have different menu trees and swap between them, but that's somewhat wasteful. Luckily, the AES provides several routines to deal with changes to menu items. a) Disabling /enabling menu items. You want to disable a menu item either if it isn't relevant right now (i.e. save... if no document is open, or if it might be dangerous - I have seen menus where 'quit' was disabled if you had an unsaved document, but that's a little bit strong). You could do this by directly altering the objects structure, but that's the long way. The easy way is to use.. status=menu_ienable(menutree,ITEMNO (or name, if you have a .H),flag) flag=0 to disable, 1 to enable status=0 for an error. Note you TECHNICALLY cannot enable / disable menu titles. However, there is an undocumented feature such that if you call this with the top bit of the object no set to 1 (requires bit-twiddling), the AES will disable the title. I haven't been able to verify which versions of the AES this works in, so really you ought to do this by directly altering the object structure, which we'll know how to do soon enough. b) Checking /Unchecking items If you want to put a checkmark next to an item, you have to have remembered to make the box big enough in the menu, and the text far enough over to the right to do it. If you don't, It'll force the text out of the box and your program will crash. So remember that when you are in the editor. To set / remove checkmarks, you use a call much like the one above :- status=menu_icheck(menutree,ITEMNO,flag) flag=0 to uncheck, 1 to check status=0 if you have an error. C) Changing the text of menus You can actually change the text of menu items if you wish. Again, you can do it by hacking the menu structure (indeed, that's the only way to change menu TITLE strings) but if you want to change the menu item string, you can use the following call :- char *text status=menu_text(menutree,itemno,text) *text is a pointer to a standard C string WHICH MUST FIT INSIDE THE DROP DOWN BOX or your program will crash. Remember, ANYTHING in the menu structure can be changed if you know enough about resource structures. However, things can also go horribly wrong this way. You are better off using these routines, believe me... Well, that about covers it for menus and along the way we've had a little about resources (although not very much). Next time, we'll look at our first VDI section and go through how to display standard text on the screen in a window (I'm leaving GDOS text for now. Partly because I can't decide whether to include Speedo GDOS or not. Could those of you reading this pass a message to Peter Hibbs yes or no? Please bear in mind whether you want to write speedo compatible programs is the issue, rather than whether you use speedo programs yourself.) So, it's goodbye from me. I'm off to enjoy the sunshine while it lasts. See you next time. . e0.. DIOX95 e0GFA_MAN PT2e0. e0.. e0DIOX95 TOS O_8READ_ME 1ST 3N^`T*|N Z@ZIP!NV/HxHyN YN |" ae zb_ YfHxHyN |``BHyN B."N^NuNVH xGItCzJ1 f |``Cz 1\ ftCzE$$$$$$$$$$$$$$$$$$$$4B3 C/ N UHxPHS?<N J_f,fUHxPHSN J_lB.`RBCzJ1 ft|LN^NuE*Gzz EfaHx;HyN "m0")"m0ҩ+A "m0+i" x"c+|x"Y(m0","ҭ //-"/ Encrypted file not supported Error writing Error while extracting (disk full ?) CRC error Unsupported compression method Press Return. _/HO>N _///O.NHT _" "_x$HBJgSf)f&)f)f f( SSf.LTN _0g HT$_"_S@QLTNPNN NA=@ LN^ _TNNVH``/./. ?.?<@NA-@LN^ _O NNVH``/.?<ANA=@LN^ _PNNVH``/.?<HNA-@ LN^ _XNNVH``?./. ?<NNA=@LN^ _O NNVH``?.?. /. ?<WNALN^ _PNNUNV2J@gA??<LNA o"h ($I!Sf+H0 ( ШШ"h$) Ђ"҈.A//??<JNAO +@,#aBNAN vH~E#*yBG<9F(yQJ9f.raraJ@g. @gh @gp`a B@FL~ _>NJGgRBGt-JTv-KTFCCgp`SBNqSFfaQ`tAp2<Qp 2<oQp2<Qp2<QAp2<Q3 H aL0EG,y"y`Hra@<raR@:ra8VDpABQAClra2QHIG,KBGBCBD|BE4Pf"<2tQPQ<<żGg pFvk>CRE EfRF FfEIt042v@xlSDzm((EQfL MIEA0<BQApBQA43Ea*HaL L@E`G,y"y`C Nq-0@64 GcGR beNu fraT@(Q`" f ra|T@` rap@ BQeNuIG@,KBGBCBD|BE4Pf"<2tQPQ<<żGg pFvk>CREyeRF Ff$y(yg.t2&4&0&v@xlSDzm(>G5xEQfIG@,KBCBD|BE4Pf"<2tQPQ<<żGg pFvk>CRE E eRF Ff$y(yfNut2&4&0&v@xlSDzm((EQfNuNq-H@-06Ѐ01 Gb GcGR`GT @l SFfa` @g @b4B`4@4-0BC3 Cr0 GcGRB43 <@-HA-2 y0 y0A Gb GcGR`GT-H@-0BC3Cr0 Gc GT` GcGRA23v@Fea< LBSBQ`-H@-0AAr GcGRNuH&y, gZ K0S@*9MrAA"6Q#/ /?9?<@NAg LO?pX` 0< L(yQ<9FLO?Nu  #+3;CScs !1Aa  0@`?     NLApBr4Bf `f J Bf R@ @fNPK4Fv0 DIOX95/BOXTEST.BASXMl_+R\ja[cgJ$p/3$SpW)re1 IŖ#DP9AQE AZ ii*9vCAC/NF=-(MHC,y{o޼fHHEn#:>}WIR݊$"I,IO} CkY0- }n4^}1aKfJsi6)c#7-Xƾmtm޿_Ce$pO$3a9işāXL8XN;|+O.ᔅ&!; ;q4fn'em3M`&p3iffssAN59 g\<Ɏ':SbX۱br̴Ӌ 8ճ 4aI9ٛҍ-7/s/ᴹ`ͤm3-J-J= >!u/:lg×L #ti r2 =Q3 rA22V^X,)C*flw H 何D%YjxtvA\84ZgmX(nhXېY1}[UGOqJ򰐇 9r>w`.ii)+{ yg ^q#|\q29䮡ws# ]£C{Ga9DF>~)nQ n C;As*/mЈ]wj&{qUYET* I~'%Oƍ %(ڴyb/sF\OQHX6_gvʜʵǼnAghyJ-&Q)7+ j~>c*O1̲b 5i )`.C{1jJ:ꅂ{*.4s6!'&`M5b2J%/Yur%H/yr [-:pwŏ}W4ګѠF4 ~htctH5z@5z\'4:QC^q:0|U7IPv+sd8A 9Kzw \ItNtr$8OQڋH 5^{ Jophu, LZ 5 ~' $8)D8qC5G$}̇CnH~.ևVv_;]a~=">n[NjCU|є1EW"DeZyST]wb :i?~xt ӓCOU?%Ї<+?mXl Q֮=Kn.!oЁBz6$8j^1~vXĚ|ԳdϮݳ GfPvi84 d`:[D=s?Q ށvǨ QEš*4~ĻQ:(8W!ѳѺRЃX_#CkOw $Jx C^]'6#τX <۝9]OסygtɈS}!aJ!e;*d,ep "NVx(Yd೎(}O}$l>?zCzAU~c {Uy Cʿx0v CUSw>@2UWS[kʿ~#ۧۀooV!>ʿ} Uy'6gTݳXln4$P,^|^o|1ބ<*T_W ΟO?PK:F1tY;DIOX95/CHANGES.NEWuUNHG?\)=%$;v9nU.@]UzUvx~(6]bYvz$g:NM:9-1G&%Wd3'[q4;wp䨹.$3UUzhϙ(xAk@^'qi4h1"KCq|uPpe &%U,9eM$z|j{NJۙ?pup./ xXwǟdmDPE1-.xvdzƋ0Id $T:#M{}/F>%_^6E֯r 6\XXL'hXASUvd %KYσbb,p00i"5ZCxS/0~u@ ]&v\f`K9~Q%fx{LyX,==@>Hk|R6w ZlᇍˋU%~H/Ge :IE}"JF͌B$gi2q7[c܅im9}651X"qπ g }I5N2Le5RyR1U GPzΣ+k\ثf >dgul|v#U]l) .ʕ:[F4Wrh|"&ev|efD2tRAɝ _:8J__#? J_e\C@;eO_=ӛ\6ojFTLC'QҠ~Ipf 1j0شD=ˀBGfp|çl4V&0:?[6K$Ǣ ,ݞH̶WްumΩkewaփi 'fbh9 Kٳ"|M-z RH({܇?y? Gogߧ ;N؀ryN!U] 0(fi: ҋ-`jPK5FA`> DIOX95/DIOX.DOC}{sIrqߡ3H^3݉!Fh -Fб򗏪yYaHdwuUVV>~?G?eߊMSU|:;v_Գ*߭j[V7ۺzr}XzUl plwEv+m-ժe^os{?P?߲) 7.+MZ>M]x~[ff@ӓǿ;M绻O_N/{oզ݆hRg"+67boɴ?ElVm "1r^vMWYK&ǫA?};|´ V59}}t]xb\[eWD9GgCϝ?~qͺn^ <]?o$ܕڌEVMIU:O֭hzpkoߗ}I'7s|+![ya/o+v[t5Hsf[MGA즨 f!5nC fn}ĮCvS{BbUޕ I3ل7%UkhfeE,6Mz<:24ٜ^ߜ՜>3%Qx&e1&_x]0:K1U9'|sͧ>*w[L:E,OV>]Em,VXhYo2ΛlXewY.+z)zlCtв$?r0Ɇc(_~ޏFٻctm4نz}¾yfwyElAzM8Zb;~féAe&}gu1tnxd|8liK >NLko]༭`lebAvqh9+9N6VM͚5q9[Ql#ՖE"fݰh*2klRaeN5B[D|3"=CsyH(ؽM1olbajrՑ4E"Ddҧxܿ~iN.Ïq]BfL;n=&%Q5kI^ztLoH: ;rS]O-]ãf$2Ŝj1wgё}$o-'BdK"ϩcfM~_ʊ߶e ,D~crǒF;~>_'6:ÏgٿC2Pg}o gʹn2fχ tlh]:2z23&cx鰉j#cf_ _aǺbAӸsO,(0¬rO?VMz⟗'ztϫrvx(E"8$G]OHJ>Ϊ?kR]?ZšagCS^v"g20 5 ,\(rGڔJnH2c#%[`A;u=` f$BD6Qd:FVk c{}Sb i3f )erHMYt_Wx7s%x-J^.iO*lam4Nd1x AW9$BͺׯG7Qoֺ溲Sm 64T6:j<:_eS{ٛiZ %?X7Kzc U Q?,Ds6Ii#y`fhz$@ ~%-a}-ؑ/hJبY>^/rfQ5ծC®: @:k#4c5D^VA4Gȩ}?AХ":kؐ37+6{hݦӧie:E krJ]]s(EP@RXH^1tH__eB>X}7W]ާ(RuF@Ɋu @|ߟ_xrbS.ww n d+ NJC6kοl /mJN $ J dyWI2t =Uc(3_"̀+Em#ސ-Py >>Y3 !%djz:5ξ,mm,珣Q*L"ڑE8fӉaa]EHaEepө6}mZ:CH IvH#t5a]MN8'}bnuz$ Ng֨l|WyFI3Q[0=j2@Pr_0w\[UKd0E-ԉ*"ʚMR:ÿɏ_KO~9P#.L-J'KtBxeI0jBeݔ4h,wPuMXEYoOԫfG;ܗEt{+w%Ky9 !<ָ  8VVTtS Jm%cn;x:XQF>` rEzEz;ſ Pu6ɼ-2 g9kv4>} Elt1E \ca1(?$CS`dʠm:]($T!OBs!q0 f*>N2fnjzBV*3Cb 6؞ QE)X&t ."1XY0uyJv:D-B{'A8}8/. JR@ dG> l2O(Ü'DB)ɋTD+g<__ſ(d g~4'kR+yݦxUc^&F7aaɩndTRqP!曚3"H72ѡ2X]_s6!Ā3%19T ",D]4$+Dp,sxd]V' >M[Jc,o %)71F갳 –h3ᯞG" ޖsJWi;F.[> pRZB ̒h5("ϑSجTb2?|@UoU(SQhmM-g?@`͇CH_q; ε4IIUP  \_rXS=>D[mߩr UrD1zp. .:U!KYHI?0Ҽ|$7 wA4]>q|rZkXE'gF`[mZބg,4Z/ɂ6Z{b4Ŵbh$1-ÃC@[pG;4LǗ&64J`G`0a/ y@q3I=[?ޢO6F mQ.XtNPd ,z*?g<8JkQ_/@B [HɎrgПx=i)c$+*&f{ ἓQF^{B^oVHqSY b)Pb!fa/;mZ-E (Jh2U$g%#wW˲(Hp^$;-I0 u@-i'H!}p(>#F»RJa.Mx(nXpwueQjMt̛EJKJbr.d=%.-HaFo=GW+'\`~sMrhf"Ѻ< h#̲q=a_v.&ߜ ṛծ?]tO`8+dPWJ3pLqA :ĩ3'4lȺ^$lCm,&q U7A2k\ [EAm-ޖU34Ʀ^ " N uڴR2' 5PTc.?wDp)ZIY.y"7h#!ZvTVdhݙ2z_ȏh;:!)0$V H!/-K;}5;30 ^_f`qm$\9 U"S+NӠ<6Kr';+ I YeXd5 0"@ɃiT s j;Vs~[c\)P$>!]a 䨸QR٢$xu7Lbm$ Huj!G v$B̙o׆?Tj5 8]`IМ C$m<[)/^g!uPEoeVZE/~m%|GM&rZ :4 $RpLfX8k s'cB128ޥNNa !C_ 7Evo5 Xnb+$dkvA A mA15o lP;2k U5~O44ybC Mȍ19+ǨF^%U>à 42Hư`MD#8輌cg@r>E}R3xX!FX5A WS¨TW܅sХB*5S0pQiPdi@^`G0;LKRB a`ra-`#|$ж3 Rd; 4z( #$2|].Vl`4A—W\ħ|RD4Eic`peVLl9OG .kR.]pF34CϋYGӜ`I4;p1WP\sS'C̚M%Pf ְV_o[ʈ2"<)3ϩ 8MAWV)3PW8ǦLU$BJ޺yWTՈ@fEŚ˵!ȅ(IunhBrȬ[xcp|.@@@k6) ba\׻HsN:(cBNtS@AVZl r(ȕp9~'oKy͐phZoQUIxqY, .Db1o@HH!Dv`,>9l~CO 9?쑋39zJy*تϒKq/vCbҤ,jx!wTQX }<<dTQseŸ4U"-,NlU,8;f(;71!sdLTV ,DX'9GU>#);zgCG4 #VsqhQHLhĵ>I\ g2^)-РP XR O Ǒ)Y*UD H1Pԋ}8OW=wS{zdP{4O,{]!ZD·+MW!d\jX }?*ar,ҐZRvG<ToZSٲv]E7 ou [\-jVP*%~]$5Ґ$=;x >2C/wjĸglS4%͠M נh4 d=#*AɤlaNhU 3 W{j*@<0Nq.EDݳqr@; 9k xyŚF>`I6V2s;^⊹zm\(}_Flt>x%LhS5)Nkw,MN$H@T@qaAתpthaI=G4#bȤI(T<iU 755b-bx&qFB3.N7)PUہ>rO:SbStL_E69U~v[h C!wUIkك iI|C!yԺܟ"{lbe[BZ9ftfmI+|i&f6A0}-dyza3ot-mP +wc@ <P4ƃ9U|15zHI.Ifb -pUB 5"ደf6- +elYlċb6o-70\dg+3K(t]dAj45W"[_9l)]{ۀUηDOCy0܆L ]/{4|H_נJV&æz/4⋖,rm g=O,i&e~KaMPhWI+P,/6#&5c@ a0K[ ( 򜑋Ɓ9 +R^b.Odҝ gĐ d•Ay4ZZ+ѢĮFO$SzkvSmB,w?U$5y<#l!8#}?$#Y!}B:nGe=fHrmm)CAv @:6tNHim,Q,!iqH`3R J$q@ ր=Û7ov^1՜Z,FZ# Zic(4f ]سgF@[Ґ/hd4G㑌ꄈk#JRRC?i?ŋQ@ُxtd%au$Ij(#b`}@IEHm9*lfD t LSHg!l& sc V$K:~ ”a[Ӥ!;h,B,`.o'S%($|s~<EKaxek,OMȄz "&jlK7'In6:Ŭv.J$`̹:-Jz6KW]W5jK+”AJٴDbJ/{W_9٤}c~NUrL#\c1شb'}ћҢČ㺕^E L$])x ߘ\sꞈGs baA+R@]އ=[ 0Db9ʻ];7^l&ְ5WKuRCAhRWZ]+[ځBf)rm[IunbiT$aok׵ڼO?t"6Sj|Ќr}FlkZmli:BoQC*S. T?nvoe3iS7i6+e&`9S%$c+{>\"2̊ }&ʙA.&m7W Μ,ڡxW.ϛ-ў6Nz?"ex{uF熯Q\HrgzRDWIyc77H/D/{rE;+n\D>vOﱩQ/5NaW[oZi 78"eT,Ba0Y4~ v%Ƀ5ro:de# ٨ѲL:GkV,ְ5P3qQ%߼󛘅h6JbE(@v(o 8P^WI͊=3RR1׎;5umqQGDL^I 5 vpgAd k. M#Uk)h fېBA.cpʴx5q?ɇiz3+]n6Ѹbsg^ x źFv|R - `$&ϡzZI*wٱD=O~7!NrVS2o ^ڄWt+ 6 .9V) *r ]pC#(:׻"ٻؤ !ALҦrkH!GGp _d EFK'iIH4.iTy1A+ axVv\]OghxEbgAuV.qp(&EdyE)^6no)?!HP,oZipؿ_MXٳ{'#*7څkhl#eNڢQXꭕ_9stdn V??*tc=c=f tڍb\$<&-HjڟuipBunHTcYzG]'!ސo10>uH[ +UHCei}CXQO=\qfF:C 2^Ҕttd8hй'3h1Ĺ]ڸ˂c[& Qbt(bpYB|dz*G+*D 7 "ILɼpO|oe.cpۓ'tOɭأVwCp l4d!cxnq6t!.ĨuO 11Fd\NIڞ-ιyDKOG}y4jp\Cgl6DKG`G13,QIÈ%lDz*Ӈѝ4^0~fD s hvb^fcWb7RIBBn6?D4U{KʐypsxIݟ_5xj]MTSB9-3(`rcZ?<7A!9n_Z})^J39p&\LF] a`ѡ.)"?]\Opſϧ]+ w1jm=в@XH VTYXg-  qeBUY(ptK8 v3>\_"|FZqx.CǤ1b4&U: eqCYNV_yWI_av/zN=u~]`V,K/_xw/er`~_;}W/?'B<4KsLF7ZDHE|v |Y W$??=U[ |:һ-GGFch+jmጼ,3en~˲w|C?4$6Q u˭]~Uޝ3瞔ئ'}ٯ }r %Ncˏ3@һ\5#ßU:A32*#c,Srɤ7ȫcQ[z{U='_u&0`lc?~vy0kV ,|՟5.ݚW͓ϕdrW/9SYbݧ֋)xOFr_Kwc1- @ O{1ь ԵJR>h eIn> _RAH-O594FrX%|=O}mwjv^E>1ە4_ku i!ݽ6T\_{O&[8w@yyZ.rXYR,˵].˅b @aw#l]Y*iYl)p,OipXu"r?t%+?;5g0gh89=M+#-$oF" qѴtpK4 )^LhHC.QnsC!Tkc"}w)Ħıp7/cQoɕ_bc4RX"ŢjQՖ{Lw!.x ЮD/¡vy5ʭp?Їp?7 Y]!,Bl 'X0#{j=r嶔4!~]s$u^H|MXo )|e2'K$Y':4H8b[`pR宭\aR*7Vir4PkI&+pn=X?*IGNQ W4pFv9*."~t%L5IeL#qžy{8'39;Zfc<iw[D'_֘Zs")%ve1uqgҶԙ{ӏS:4T6A؎R.W-&0{ O[ǭ=B^ۅq|HZ&5!w@媤.t:V+ƿˆr_8ij-EPf,]=tDhqSr#[|?mH%i4sĩ"__^i!eԒj[Jp'V'O{OEv'[E\^~~v?9,cu#ZF0:U3Sݑ~G{2B@nNHiF*P5"9f+ԞBK" 6)KiIh6ovKT)Kb6VIgP +tzZ=`JczT>*wǺI)Ѽ#IbZ:P+X1c)zפ]=,w8c| KUTvq?̳i|mqUĮ2Q6Q/mbq{'xM)@'Dh /N.k/Ri:w MkVJxZbO5FpBGNJݩt _u#],Zw2@#:#n^s-rdpCtS3(7'KV F(d@;9] m27ujB"T *ZP/ ylzyNN:;_N(j^BwVm1έd MFZYV~lhN_"C"eCrAF7lm2hAnt+n0EN? w2Άо3&2KI*3'^&HAG2ԏjF-Z4H[a_">vO(ia-6Os*Oab F`k:*MNnE[FAԾ-)oeqOiӸP$yƭzu3'׫RB ^la[ —[ H,IF@R؜CB~Ȥ& lTI5{ F|+<__=g a|)^NMf@2ke;< =#k* +w¸!6NBmII_x7V<} ljwEDk.xf)VV0hR%\;+<ɠ7&_hoxwDHJ{/!$\bl_׭ܣy7,,(1KCqͬ3cclclV32Xλ:adl[g9nCa5PZmٳ[?+e(\`*ɫ -TɏW gY*!ss !H`o-7nkE/)b>>uF6-]M2aIg C&OA4V y_<#c,59;!Cr Ot3w`R eU'<`7nv85 r-&.+8zN w#%>F H9`C(|c2vh3g`}#[#//;vޗF̷ {gIJ6{[|-?}LB`֤Wqn?-cJksԝ%w Ⱬ(W.џNFk(J}aA c$3? QMn&-I1]Q7(=Tb]FPM{yb n0uo_'P@eWGr@|r{H#'xaF7( ("LjǗXC%t)57lduc#7Lg爩a<$EG"ȼ&yV0#*W|]-nXsiFF5Ւ_ _~H ZkP0!U'n8{U͒*?ivDӋ˥t q\bGe HAǽOn 6߬&a5{ }F|J$qqGv~^~^Z ȱQjҌcTso9-=D B{ᎅK, | ¾C'(4|vFnJC$Q4!J#C: 47܎-DvCw|;zp_ t"zE /!:S$#WO@STcjpѱ/CFlDX +83 U]~哯~ӟ 1??7w?ow䓳{9M{^~m/'_߹ &_ ST[ޫC{[;I*@d5&,d%71B8 F&$4HF DBݔMܔ# ./KfYB(:.Bu)u;s}wo$w>933gY$iYB4?&6Wy.h!G?BnIsu Zgי(r8mm%$8p7YṰ{ ?q>d2*'2MGM;U>&qv}6ñ*jIcE/^[ae(j>cޱɏE.M/%%h~[.DWho0ɡɇ'ti4em_o 7In yN碗]{K~IܚQGi09n&WN Viĝk -m%?UԞ7Jwڢ^%KJH;S%"cCl0cN09l ?d+;mw\pkC6mO]B=ȩOsZǿ P u.["VbMw3!pPDl#h"`ZA/l-I>_QhmNq>y%I3tʤJ;$zBs\%3kvC6-]aby.{*ghmdzm&\|Vmo7:۸gѨy wE;f$nN˴Օ-CT[YQZEL|xr4mw%IrG{#4Q^t$z8*~|SZOŇωm/W9өYMiۇ᧎Goٛ̀2Zmos5a pKH5>-P+GоAnEoUgL|4-#$)-gz(YR)BU}7 9>Yk3Gya=A_;h}Ϻ֗%9g5r{ݐi~|k:w>'"n۵byZ] ;Ĭ |p1lHmg`PP7.]4"jgBjml.au;=,-LZzWrT+JpwazOY 27y- jFv(9ef ϯ|Я7&BxQ3r5]'}YZoJ y^t_vU/"*Cu2ϿPS2e}_bsC0bs[E2uc?itejEҕnGFmEي2g׹UMuUMyrļ0̝TUAZs8^tN h[ዛB۴`o"\qYs>j9Q~6k+4Nx2X$Lgֳqڽ70YzL,y,uUHϤۦ% W85ȕ@*|6#IlzG+J ?}4@*W|ݬjUT!* K@}^U #meZfh&9Hߤ%2wie^ %ZF\9$tZNO*7r@89.N*EvRR3aj `Tm q|mvZQmmD+*&M}~0cu&#ƹo>rRcXL94Ҥ~֤O? ́ӦTBmz}cdRoO9g<0)U9"9gTgoz.7]>5 e|[$S°ʸ.wFF1I~cɮ:v5vUww//j*:aM0{f$zq>2} <1o  Ӷo,|ɏpI˿:2=-h*2ƯL_9KNT+ $FAi sVb8]*ۯyi $un[IM֪rA%7wA)^v'Oyj־sAY\hb^ 7m~֫4wq{'Eœyi'FlP -yZ[ҜceL<wao~e.r<@fT?t Z mo 2B}FUS`Jz,M{ :q"5nSuPdL @) ZI[M[gbzmɽ)p^5V> AOK@Pc\NO3z)\jMJ)4psV[Zx/!\Vo !wM|!}xGn~t?fZlu9g͟a{lΩ1.4T[^g cn @,0g<ec,վ1\Y:5A~ToKB,XIpbw8>7dSpR&pnw$u {SCKVh2 hǼV1) 0 5jJw!K KXWyMv=?ӱ)}ҙẼ GUaζ}lեn*L0[@C6.Cw!ľ+k`TxEWP=Ͼ d|ͳh>w&RK/m'4h)kBV-tV:XH_8Wo྾ݿ.w{WV㾴"}A3}<n![w0L)4,Хa^t铃tC4"4Rzuiww{G1ekO)PFL b[O g_ojuBsV.ɞ]}^~z/gnHXڼGnZiyj, {|YYɳzh8-Gى5n"+bys;r cKmն^q#y3$b} 2ͧ~فeUHZ5]~o<ȁ7M_U`]X5i/'0> koڕ2N c!V=/F!Cj/,+\Uig:3 JY[.DZ# r]gz Jz/Obr^~=}Nh뽷ESk 3a `Ͱ} K?7:;J,{tn4s(R`#k2 k+}Z A;i*Vsعíĭ˸|"3JPFokMSMY.Sl`9s8g;!b!-xgM7:2&!n^ht>%!$o0=PRMuXs`p?$\qX`5+ 6۝#3bn<@h\4K&{??濄8jt(dVD%)lp۝PO=6,g1g﹠;~Kr0j.:,ghYhTCh9j*>f8〵i pM P YB!/Uܓ0UtybIƞ%ZKGo=oho[_{]OjJ\u7 ŧWkqnPBHHw93Lgw#o"(bERݨ]hǩ>|Cv 8{zoe\ivS.!27&u) t̜yoT~ZR!jho$\ " +Ur0ך\nus2?^(7>Lst7u\+x }7wB>^"75絺c. s'*ȥz!;TtbS n[soZ+MA0bߵQQ,$6@; ފ"|SwW-0; !v%LY \NX{SBƯ䭘AuwPE,ћk%O{?5OӋ/~ t0R[ `U1qD&,^)7qE73t]ݛ`L]kp!D:_> {|3ItnQ%~,ri|Zg>u9mݲ0@:( aEuf9ُF(s(y0+q%` x\54 Anu)+5Y`>KuMn:UIenص0 ϝ%4`3BhKgK!}Ӗ1WZbFXcy9|X\q Ab $9 õasm3Ρ|e`Yw5w"yy?s?;;2BA~T]`q1k9j`n']eⱖj~06,W]返ZroJ'9Ѩg#e.DYX=S5?`1pDC.י2/d vBo)4\V K%ė !ܷ..L?ɏհ Ma |&5 +q> t>* |f؜NJ ^G!(4_jr V(Gh ?Tٍ3]V-)wc)B]B il`nHց!~ok vQ)to&( 5ѤFxaE]3~+D7V"ճ$ꪛ]W@A 9I5r_ cc2`ۯ[㟸xtkvu V,jk_DEo 7P{OC,W~ÒK@ed2z]+4^'oB ɍs9Ƌ{v/{><F}]Ƌua9r?No^[_2*2(._>`JY,@b6wq ył&龾*?TO?G2WWv&7xLM7<΃6v:"Z8:nVo%"^THP p*y^A+aaV%eٰXY9 -=V1֗0ςe,i> :j*Qb0bpE/q-\۫Zu6o] ی5a7aJ.:_{=hV Á"[oqC>6럔@&=lk= ؑ؆ :,,\{T vih;NGG\۵3"[oJ5?"Nɚ01ii¹I a%j2GCpm"p R1F[ e`M)0h:Y2uƓ43$&Bh:+1͎'Oщy79}@5@RsMcBOr2GuNd9Jy SkAǟr_{GzOm'\ν>@z95@:k5͇xh{1449Byus,=j'1Lۢ$+$C(%IΙ^gM5 gS>f,ՙm^[*w^l$/Is<'G݀5vؗg—몦V.M H dN$Hz UU{Y[~E2ƋWHWj Öm,?F lL ^g~N}o`7*&a0v &`Y2RK üIsx?qJQ`R^a x:3rs'݅)ŏzl.pt~ˆ16[`+GhvM6VO)B=oEfSVZSVAMѡd\r+a\Jꋏt{qG$ÔZKj ~iRt[3lmzes#N "w!!]ܝIB&0y )JR7|ԑS{gq6ƼRCvxfOpmx Xpu)}{)Wh>]cvAY;r+BкHd X)av˭-ӎ+཈rON|rKӹ\S:kqAV xۀfЖ":IJ`LqOZO8ajܔF]NyW[!II֓;v`/F3mPӱ 0X FJk%Z/*0$F "$]S%'XHL\ؑD4p; zS@rOiP909}Far`L-UǑ#{K #uV\q@HȻ{mKk߅5?%x0as5 G@.!>>` w@Oi!Ń2@tzZy}h\%)39 򍸶݋p E#;R:+ {܇=Iެ)^$a1'z [SKBȓ mNI)BW辔㓻L붥rK%hKQ 3 G DZ /LJH Q# mEv> %. {(|9qN4OND\X:qKkXipĈ'Au:s,Fwz:S.@;G.ώ'9jъ.XWsbو|ǽޜ܅y&{B4Y$`;k;?;pwp/~L2*@g;?be)kAgk_kf\ȷ[ -_*]xD;&g1z"ϟf!0CNqAxkvSNOvLdI; w#;m1᝺~Rxgn?-~Vx߷ ׭/WW.߿&B5{p\:*oAx?#Ux0 o =u^=eG.q@xO۱eV>_spZ=H>X†K_oY:Gypi\d]H(+?u8܋dzAn3d,f*y/edL;W.2tLj̽Je 29~YE~Y$soߔKd2A;$sWddN{, -{}@&gP[ຄVba7.p Ag۴U\`PLέߔBW}BcOԹCo_k`,"<Ж?3QTF-K)c#.h"M/paeN`}I){XpIr\,.z+ϟDs稆F|csN8/lAukg6JSEh[5Thӳ-m(]8m0,,Wp߁Cմx0e_7upP&U,c΁eClGW4u>gkm4M#Zۋ'+C=m-0|cq}[kkKs Y5BVbWL[QCsB_QXi^ N^~:`,=H x0Ar`/P{¼e4Jq_em{"S $$2Q,r9 :*ɢrELS ߧ+1IZU5|P x-jټ+4޲6WK[KfwL"j^}"އUx.&'-Qu Dj/cwwԕl}cc;n87B9_Xq1Op G#o3Lk{Y*LrE ^Nurw\g FWAWe0nr`e·.UyGYm;pqdViΟύxW rDjX4hm ܚeLWK[קXA|mLJgq}!$[je79],6KLCcTgH)s\ڸb9NL8WZӶW~wyFĉiHbLSZP\%صȳx8{KPG`S^eAIJo?jsA5(_XLU (5ܪuq5K ,>8y8*Cyj4yUOFE~4ˏPܜVOpy~*ӥOWtSG"Qb@cB>EU^E^E))6O|FwAw1O%<% ;Oc9nn[+h@*#pWhjt93~EU9ҍ-4u,?cs'2h+1/m`vHRW裛攖h7B>dj*O(B^~$% b] 8r56F1!Coq|%CJrs d(khݵYfQp&io2ň<ˬ3Z[89ǻEYdŗs`&Ds[8ʱlk'NEhD ԷoP ~R@yBD1a X?g0^1F? IFsKH/$W$^?I)Ʒ %a(rxZm~K )URDD<{l%{\;J/X`'[pw#Nq%`TGLleܱH\̴W6Bi+; qBLvV?XZ4wq9mRr,X:o.'Ò)k ֖z:h3rk%,i."u_nvNqӕkZ /ZVMx#{mhNd*W4aߢ[/o#ғ 1ftӷTiyN!Mra},o4t;9](bT> Y/g!,NL BAoZorceaW4SOޤoLǃ~ӿ v6a:캒~-$ivzbi '>QZc2XWe~x}JxvO.*1OCڮk~rud>_EdnbjAkz B:m_cm6 1 (%cٖ f'녳 oCE nĤĔsC0W3w/b5ϧmeMAV.*^:k/`/3^zޣH/\ưmkC:j~1IoVzzgعluήB Q+C@6ߦuHh^Le[t)/!5NJSc MZ -jxiR,Z,/fAzdIjMm2wXz$7Aw&$sen햹[:ښh ޝ_c'~w_/bA:ڢt4=b>iPnӢl:Ym1 jߋ}|rHl!V_"s45?)B3֡~ƚhdA'8Ib$J\SHLYYhb%F'J<&].1*QVTdEIԨ^OXeu.俶N6[d/Ҩ}Ϳz0\ jܬmcLBIKa)m#։iTSE{7>`>4oS)mbڴb*-xUj k71DoRKEPG54x*O&p^"=&xQͮRsfCW]^YfG %ZjGKT_l5+(QZ&/eȵL,eҭM*+OZi'FK7Y n;MlW}5XmOEap _'DYk7H!c0 Ґn)$i ˇ{D{N#ti é}9Bt1w"*hUӧ%|RkidǶ?6\g8>Բm 8< ;xP,|Z_ qή۽BͲ/v̩~Qy-x|Ozx}@ƦhykۊgV~{yeZC.)]\ g䋅/O/bx+*q3H^EJxRF*e{s7״[RTru^_:kh=YyVr梢BMv1NbOok8UO",:/Z}s#*C+h#lPHC~eZ7`>nnu`pf?}i/!HϾCUƇ߳nP %kNZcȧw+Iy1M'_f}rX @˚9ZwI%% ݃eG֙5xN+떮RE3>1yC#ԤGrxgzՃi3Cajrǔ|X.ov7%ǔ0JRA1~nCLۛ<\m|$U/Hz>W3 ڐ6O\Pzbcs61a[ڸ\8)n{yM͙?q^o!S^g mݳ2)ExdZf] R=p~]F,d$eExTi"Q<"8)U$ ↴B(jegJhZpFqc7cw w|ߟn)Gcp}pteõ@i-Fl;NXj |c7tF[̿{_g6}>lza%>RVEm.v&r@yVDA^<L1n0IL[H=IgeӜo?KoU40,I'L~y+6mDV7/['&3ƞWfQ;gXJaw DnU'6oF//U1_@OiW-riszZ&[֋y yZA hFQY/ Z YIPj|zxy4۔8y\+Ul]&2u21HmmeZ5X厩0ZE5z*Ls*LKR|T-KX5mߊ6k rZMV:7& cc8lUeqrMJ0 ]%b e;ƮcXYåRpٿ4Tk5x ZQ^i$YxϊKMVKkm 5+1Ja,T)TX8Z\8u\k`zy9eeW BLvGD(Fyt=#E#㬨iKCSMoM u#5&bCEVLhP54J-CByU '4jYepV_BF&[LOylyͭmYjC0@hI:o Eq-; g<Ȣ6S?f g9'5 >˄bR@$oyF6)e-v:$3 p   `o;%[ZBu֛aIgY,ZAF?㾓wwI5?X^3?M$&s6hc"Qތ:+WٮllOGד_+Zt T7E+--_W m7fMLYVY-VY-_VҚ@lJJ_i0-Z$:WVw _6s8511-DmtTOƦ:4uq]=1Q"hO` 9Kiÿc%_l3" )B+?qw_lP[9z&hC||hb4ΏI>gdhR}EEșԝ1!!!Ԧ1!CRo A}OCh}KQꊫ'\u;X;j-CW;kGޕp+W7T"&7f}ܘ ziޱvv3ĦCo^Ԭ:;ws׋x%캵,r$q;_XQLgg+|YT2oZ=)ijm3$7=/XmmB.Q kz2xS3m3E);Bå4뵡7r[!G3!쯀CCB"!tO:1$ltވVHX#WO׳ 'h8}v|7X5ǮJ9E5]䡷63>$4^5E;+Vŗu5gvw+{{%}n/1Z hYˑ{P)8xJ9mM ܭY2vL4 @flam*d?~$]ӾgvW/?r^+]a"$̚YੈHyE$`(P5b{`~^l *l|? j tGfe_/~uZߏ|Գ_Td aZUw8ddXzN]pӂ 3@ W$H;k%-Yj~X?ӰTD [9ȑN9ZCp_㓷xRLyx"8fem1 +-Owʖ[ْv4([Ҏy;BnVZmrumu^}&nj[d콟#}}{4{MeT6+o^U40] g{-+Eog̿73oc̿w1fۘ2.?{8cn?e b>?י"b+a>3uOe[̟N?"̟z̟_ofI?]C;su"w=-P ?Ko*i Kh/Yp]n8Ɖ3-fZ[/ y1T,Jv/fҵ mV},Gh5{⡝^,Ja%^bV`h)\(7ڇEYЖ(F6u6R-Mgh3?lVGKPn<%ŢDhKh9PvLC{%G{ȡrxhKEY Zc١t*=c ݣ@{C-BqZlp*Dzo| mr5C{'G{Mu C+eV9} ;Z =}ǥrxhp*Dz#Z#dhwKhǮgh/0Ghu C+eGV9颶 푧%7 q.u C+em)m.v F kaac}w:VʅrU[A0*lG$CWBz!Ɛ#=UGJPnQR []%!=*n37ҳ ԑR.4QRjgȐfH/ʑ@)Bq U j/!#!5͠H_1WH A()R[Ԓ)!=HB:~!CjdHHRGJPnEI *lϧ6V z i Đ^#}:Rʅr }XVmj!72[ ՑR.i()RNjRB!H%[Bz|:Rʅr -%qk+j3RV_fXsV/~ʅrUǩiV@e%B_Q LOchT9:u C+*+Z =Q/Leht=h)ʍWTV6k3h妻!_bw?m1C)G+:ZʅrcZ (+ZSVYtFH `0Oc K3B1 %*zč$ 8AC '8A|IRx z" ), )%(NHPB )NHQ4%aZ%aZELI[OK_ ? $A{ǴcZ1-^PP"~&nSN>%|.zb#1Nj#8b#6bc׈9c߈9Ȉ9{FqvGqe}#>b[#1~#H1G9&݉dw~cˤ1g·Vp"T+ ;v`ME 'yWgqw9rx:gX%ЃIsJ*<(pJ:ߛǐ|c8H_hH_ oМ&iTh> !htA M4cFQ9?~ThGF;}9"oxE"[ wO/d).i|64*84Oq O)B OB?4*yCE/ߟҾ,_ ?FF?FfxOGQڟG4hTASSƗE2?Ql4hTӄѠ^~gTh^)sThGFџ~ UրOa?% 'oМ&iTh> EJ)h:3*4 !hB?4*iXWɗO ?,hBhШ'h ?E3? ͫB3? MhV/H, ,@c$($&$ PKȄ Lfƙ cD5F!(eReY>,)'ҔO"!Eysd^0w޹{}߼?,U;féą%%E) :KDV79؇uB9dKIzxˑ神b?vt𑇅:ǥ&-x\d/x09DgmG' kG':;n(tN*G':YO*|6\=:=i셎Ye/t:l/;=i*YG6^蘵YBǬͲ:Yg,ۣUe/t,{cf NOڬgAY6GIe/t,{a{I=l{e{tj셎Ye/t,{a{ىBksGKrMJP3+U9L>o¨(Q\Y(#P\"Mb( >?NVXjL+u%_ ,fA=g@gN0bA}_2 R$>%]Hɑ8[{ H#2r$oE$F2@"CD9nIP $G/q"enuˑٶ Ly!$N 5:$!1Zc;C[Y$ϥ}a 2bb5:,4" Ro 4bjEz56:,ƧanoO6bR5v:,Rr";baEv:,R5bEvsXWaŃ반2"mEv:,&hMFXYdG"tuXd4aa s2u,~lLIދtVCCHXb6@¢되bE!!HXbSN ajH]gy,x VCCbjXĴHXb 2ӭ[ waajuXd&aa4+4mѝ>œSܯ;X,]ן w1%ݷjL7.IiDiF)/ޅmer輙, U5sqwkye녶6ؼ^㲥sg !r}o\#z1*39UY 0@j¥d-aWB>oPuBJg+4ҏu1k=o6-9S(ڑ`#Ž.kIU6ڤA5:pL80ܩ3z. VJRd`:o=C'NxV6W&W岚a,gdIsmeF(×h>=C\F4A-hnJлYsKuzW[.en3䂞-S8gtE t!mT!s26@le3pԦԜoT1=CVzSPbǽd,8M+] L6JIRbR,R,(==HXO$ yCҟ{a,R&=LIOi?SYQl'T=6*+\i\,Ulj~yОճ ؁|i~R KQ/Q=yK*SFZ'}'_0G=^x4L^(A/髒Iore*N"B桨Ϗfv;Gb|fьR0xʳ0Z?Ԏψ~z(uBoTtg0.OZ,#-qؼFI@T~IdP7ɼ$h ٛI֊#N}ĨD~DǞ=崊9H 9&1i`!U% 1Cd5Eηƽ8/6 55Hc^}D< !2ˤk{*}޿x[ `Q{7fC'ȼ)!A8Ч8t;L{&>-Ğ}CUՇUzJX<^ HM>you!Wu*d5?Uh{_UW|UwGzh<G}oz7{,MmTV@,a'<`q\VSa9\[jh;Dw̋Oɾ:Lߤ &8-_t'@ސ+<0cy5E7.7PfLg;8 dG/X\\SK+˖{*>`jUL1&?Xd_ ޒ*g@χ^BqZmȫB.˄$K#za¼UJ;EEE±Ejc STgjuBj)*5WFSY.qyQݟ5AmK,♏mpxC`g3(F[{{пޏAÜq?h]~BDڑzxҹ9u[8;?;$R2>2 kCh·#U-0r! ZTaSĒQ8e8ŻM{3\3Ҧ^Sy"x]MCcw`P}q{cOڝ$»u)rd OlKk^ue8c<||<wR?&܊3Ic(/1`! HjΓ5S]'9"eL0r&^xe?Zj-ߍ>QH~߅4?Cp3|DwGAO'< kPBPzF{zeM(<n;p@gh\P /VkHk~t=lE0b-7B8C)&Q YΆUG䮟OA*>yCd,ՔcRe)[ڦԟZLz&j(i#GlZsǏgI?=w6"z>Qrj` T8mƣվAtSXGtjL17І}6fwɾYy="WёSZQ֬=^rFjx:mHmjڣv ПgQvILJXCM߷; #3u+.{"nY/vsR؃FRõԤQx%3TwB[#0^>V^z\wAu[0[CÈP6|8(B)D<{7]ͬ `9|6ǧU24xN Pw''%Zu- `#6/V:V?w,}*T)>4 5pAnZGyKx$گIY?=&.kǣܧ\uʼzߎ$(6zhݐ^GC*jYFZқi_i66Pӳy^ :1zB5U X_3^!2>3#Zr3-9$!&N4[GY[E k¦fBZT^k  %ŶdmÏҸjBBItY[gm=7Hh+krH()!i)d b[dmz G k4,ӽY5-L֤Z8M7|'k+Yx=iEM4O 1<IV5Qi- ;Wt_@"L#K k¤c]׹[({>C yֿ\1y''Mj+_x_s_{_[_{7#_*_7 5Eмr,zu7xuNS{ԓͮ[;,ڈ+۞OVtP=P RW%]湙5:__(s"X_ >MFWrI-DWQ1pl,\blOz&)Qˣ], \ZefDc|6T= l|_;B,k!('9N9%]Q>#+OߖpiE{H&!yc:olE6݋5Me5qtæk4qtkq:V v' 6爝7PI|{~1ULI_~KI?Epg>2 O;љb$篴}.%2a WSd'"N:_x}=lnaq;ZAbn¯pE/w5bFopMWT٥S V-^Sp>#CPzs|AMSɠvBƤtoY<Ċqb/tE ]0hbnς |U g j͖>C"MIKzNܻ[OKP51B½k>2D?IuDŹ"1Rb4U[M.!R HZ)eBUb8RI_FR,s&@#u ‘d}]AYe߷2ILlh7i~Y#q`6{ ހo4o/ye֪o\q*A{u#"LM!h\p2?މV ]@s@9Bz.)O$_qy4ί;=TDOr"xFw%=fKPTDD_!>ګKXZ>A/|\ +$/?J> ?S3vo%i,o˧ފF.(q@oNq%c>-rQ؆iփ}ljd&pRq"_7XKF0@52x!> {]dk۰8,m0Zǵr{W\[)u_jO3\R6R~iclܵz̴ʝUд%6ktBQގ뢞2M5' * XD(ȟ"iH6CehؤZqIvfwRT9YEڈR,G=q<áT73}37o7!ɆGf~3h-(oYK2_g*tO"*Vb 5M`:o>XNa$FF@yi,5EdHU[ևI{Zߟa!L^eԼgKɞ-RoKlgˀlo-l8eUk8BHW{2.#?v ȶֲ>i&kei޳Ng"$d;[ d[~k>@LJzZ6ߺwvyϖ=[."DߖΖַZ_&e$c0Ȇ÷ _G~-PQa[j7._ٟl<8#;'hqp韆R|Tp_`ЪYKsPh X=Kԫӏ|l;E6ʩV1cѷ|O[>:Jx7vYU;(ldp1ha%dV2]|`:3 γ)/gH-\"??ĵ0;yROA(@}Z۽L?V}~ÅwǶh={.h&voI!MOlJPW8F|vP, C͕,sq ߥ)dJygƼ>"v22?bLrjQ]è'(,K7{5ЧjIZd>ؿ.o7ûtmLt|&!9)i&FJ /1r$|EAdj-aޏ}.?C,za%j&^,P%/3{{ެϦfh~2vS h2;r^֧ 5fW<#oY_c~!sT7CVt0ՓuĪzs$|S&qt$=vhNϏ,f\gwnq} ҥJ f4?K1і>vHMݪgx}ǘ>vcL_X4+oFsڰP!"$?C^scެ"/"lR۲([My²5_R}k'Ϭi'+_ͷIJmSeNR81')-')-CM4-58g~xH*DbЩ#@d!$$V<pz~i`?xJ qB)%StEΠ3::s[k# opZ حpvJ܃uCk8J34G1-&uVXr[c2k+}Z/˳Ly|ms%@?_7u+vUv* }4KƎ eV}\\2fQ4>u)N3nI<}#W9c iQ^EC:ƾb}ʺQukc im|}!=6hg7jgwjw | x>j7$3a>0lk}HZǤNSލڧ;w$x,]ILl'mڧi>5kmxd N0:pEpC?Q!9N!"W*?(?_V~v)?P~Gǔ''(*JXd,^ӓSF3v:}"&.C6雧3?ioL}5LJs3:fg|/aOalH$'DT\ i>|GӷgFPf>ڃhQO=f#^vXx &Cj/qiNF*& SS xa;>_ע|SS$.~?SCp}8Cx~_ՠb\iHKt<AZ6"LX<1N/R%a #gĎխ)WFqw[?ʡcHx` xIs;t64:1Dx_*?Κ[13Cqc8.h'0XsyJx%h '~xnCi: myi dtehe5 d*؜,>˸!2 !~ XM I ɕ+}Q2֒hὩy$c: e[X2h/r+`Ox3E[˪}3BA N[Ixk tM5%Acpm0u(^jt$0A B AיX]HI)ik`]b֡[_,]25^gSQRVPCivBi0lzm} *5"vYIYsNw{-VUN/*ϧ3ZEtr)& ]qnf;V@3$EMPP>J@c,@%^405,[FFAjAwAQ ;As$шY%;;9Z<86\rY7Yg2: %ov@潷a1J;D|%ț CD J^+PPD\5F\.Y .Ix];آNI:΅r3vz"gh2G,aUq$fYeoX>F>D+":0}:IBO#7ma,,=׶4;_Vw3f-5NO>^m%z mgVV,ƶi3xۧfX/(,0w/mbmg}]'+/X0e涳ivi]:ߢ{s;k{4m)%olW=w%v5izZTZh ^; eJTIkk4^Mvi33xd^=oSWt/7lo)ȞVU'c\?^6g.DHv>~k.lwD f6?S/-Yu4!Qۡl'C="?䧙 J&Iw|_f/컵o¾_ @̱8Mʓ{oo1ful!,oo"o*o2c;e;CɝJJIw(iޫ W^gOU8$W5R64$GgU"kVWQԍ}naW)h BЭrqggp\ǭ,HbY\bJXZW* # ȳ'}Un, SG)ǒ>5(%q,Ybʙ(hj3QF8bʙprpT-6$qTեr8y8qsG9D)gc6GuǽM⨾;Ŕ31G)93)9 [7QA5bʙq#6\ SG mq>cH J7q Y)Unά4b|Y f%X_y=OqyI}[YZ1l@ٺN-&?F6 [c1.[JY˖QeOsl#eoc0.[Nc0.;*8n`\vUmZ߸lYvhܸ\l gMm\*g쉌F5Kivr(R7R2f6B7 ;̬ot /w2 \('ow5 q}3+H遻68W벙%N%Nkvތ}!(&Kת4;.aA_A!$ZuH -iP}vh.'fA/eٜ6Lvh~OIp' NF>w-:?@'56E9F^Miڳ=h.+/YI+l>+/r_Xg+<4L >+`~Xg|T)J uP.s4\ר֬lcXgyY9p36٪U<`CV$>Co hOs`hDqe s'oKNH ۘKǻi,}h{,moʊlcY1N%^ c]_Y]|nO2xI׵3bH%Dn Խge~? ylMFhǛNS-(7 MK<g_CƠcXUpE VG|5O :jEĴ8+],E$IH0puo4ClާM0V/ H;P.SlOSWM ;IC@m0 (cӴE-O"xp"ژ/ A{b8&j|%>ЎO FY=m[hE6{K.4'h B06cT^;cAs9w%?uєh,%"hyq-Ѝ ϳPSFD)q/'_)'-fK Rp [[Nfp돺gl9l_J,{Oi׌}_\'O2J՛te:Z+ss~WWhRh%q,K.>.R?K'ss ߟK!\?GvP듶tBħȡoh~L_pnI?ַWʷ+c9/6cnrޟv 7$d~MzP({yo &ZSf\"AcCS,aNK"cȣ  ޗT FԐ fWg=X4ДA))gan#hȆ#D76Im_ߜ.!]N2`}sh3sWgcי@ĜA:#&0ezNHN{Nm:}xz5׸_^/6sO/y=/bTp{z<:%VP3i$>{ҷ{,: ÑYEJOfc@Z+=,#?)JPʙZU2_}Ď{/M!{SX<& ʞ= _Z/UwاZ8 Vé46iU5J-XK**B1 ɍhPцD%hˆ'G`0]&^Ӕ*>T{zO=U]5@d<̆T̵=qƐ^)*` !SY$0RY#O;d /SPTGb t+c #mxV`%#oH87\3<8 =OWbvI-H5'JP9EAO2 u:nӐaY`9M,kr1Ԡс^6hB7SpRr0ݚ>Re%. U zCPH ppWOw(jkѮ ^; r{;)H H<2i*{F`QtyP5F|QO+kc8Cj<nD¡=,4: D]$:pED C@Ltdg9S /jSK]: X=^ag6 1tL.tG NNG "%X'#<,$ϕ13y$JtT͌$ 74Ans/q:M>Mz~o|䓟Ct;`mj43Qs7xT;CnKΨr3Ҟu +y$Ft(#x|M m+ҤUta)!Vm(- zP=T4Vt"=Mw0w;͔B/6vh/,c)/{ftu^"b[Q̎*2+ןaj'+ 볮?V}8 3{D4CD2ߥ3qtIfMX*7Sji;L )fgtU^d)0$[D!yC;Թ9R>9IvHtiT^> *7.R͌+ͼq3Y(ԯѹ:f-wy'~I}Hs/}lBeg &6g؜wZ+ee MlesڷuQV)h+otlYO|aYkEQ@i1(=1JFڎ/+|&s -Y'%?J؄O)G>Qy@{Mr(=V{D,tt+lKqcTttL2& 4mvޑdܩyGWv*g)-3 `nO ys(y}v A G]cυfC`TsTsc[u[` p4|Kՠrueu|0"PÜg0C*Tޫl]TKz8l5v aN%5h܃J^y=3s[(x'Q6vU}+/X;њ70  !1i*ٵ: BJf~=uDz\W6_w2"-vZHb 45[e#%(.s|gW5Yt`X;Mv5 >+hMTˇdvJq eiro9/y' Oď3GHaC5ˆRqP,S6ku'v yo=Eѹ'SL؉8u$M%aPnδ T*9 RFX`!ٍIaZ*tDs=C!pt<a@rmqA jŹ AH4Ġg)^(:2j{T8`gѰ'醞#%J5.A:}1e*2 3UfgĊ2GfT&)IYywXw;+LjAV,VT*Z+.$8ʃU;o1&15DXo:VO,~.-%*)gEX4U/dV%:u-9&֒i> L1i7!3"N*U#/'އ#ʱ*8hriDcDE1QIo-|]L` OĿ)cFfy1D~PJހ'ވgY^(g)n:a{VR|B O`(2潦\spT= dOP# R\+(c4ǃY<_xO;W9 gH|&ft|/ . 8 #0`ΌB>um ~J1FZ`ȸLx1+y=`JyX ^{d"gG;:)zAySVi"-=Ð+BHHDH.5ו3=NqvqG+(R.m.%~ T~12 V2TDXEܠ%Z]9-TKL"RU{h~t~0R-JH]9n2n$-FT' k/kϪׯK9$鸉̺$#n.2{؝GŊ }:2aݎyJ!:1SYsPo$T<{t~($?+ TLsމ|_PzZ j f>FP:MƝpx"Wu^(}z#e*v?@×ӭ~56ǙdD˕^a/Ѡ~^fG&TҸ) +Pb158=Ap.5x6u8^ \!/V"}8¥fВ.N..w,*)e7 .N`\(t ο[XA{MPrBVdfDvp1vpgO$W}l(7_;Tn683Hrf޷w^yx]%rZTKz:,vwy;%HUyab- )1܂&i.ay E"̷8=R۵K$u 075,(hdRô ΑL$Sm|k2 )RJ& >w gȚ$OW'b)-1(\^=q$B#8zodcI+i(2^ãq1WŠD4f/P4`L5&Tlp59MM Ij{i6tw&[dŸ[;lzSl-ߺ超n~kͯ18 NSsK3>gcHsĚ*c[Hm5n6.s:mxq#5x-9f- Z &Kx0Vkz7myx\rկj4_~|Yuo9eZ>=dX6}a!26ݑ[7,- dqX{n`hѳr~gxûڅZkmwԤܮ]^[Z[q9x[¿ =yAG+eQuӼ7hΘ1USm5/-+ےRQH?bc_zs밉}JS3¥SsNh|zX |y} v#11U}Xy+QrskݚFzE7CFl76``V @FgY2'-j[~1/-#8[n9v&gl\vMQ-ߢEel[cV lV+na\=Z<\} k\v3{^lסDNvuxh { 7i:_]n<<m.q%u_Uh W\߆Oe۪L2+ŋWqy= {}|+kf d6K|qO &10dUn69P~Ps\m^y[xuS'D4nҦ֘;.W @; D@P: P@*@@2Q b/i]BW\O7?ݏ)۠>Da?_g?vg}LrE8DȪe%x':ßS\4ȞEvٮ ,=7̂~VNn WdzrWzUU9JY0u*lY0S3噩rT˜B瞥yT%4E$u&+]WUH{R|I@^ hZQ F tHia,-s @- v e,#(4TϮ>Z 1A#&Ą&1TbVLh1x1bY=贗sj=k~7|`|"iZ<jr*-'4` .xF0Qn|8yurfBSd'-~bdW"PKiQK/a|m_bTڗ |nsF>7@nv܎صr;ayHn/._nr .\ L.)Rox  -U-UezQ~%XT|%11?V뵃m#}x}*z Ex8a]G 睃{$P%B#,>rYd f! 9sF"&4bR"&4bR"\ӈՍs|~(!-='%*opa40Fd؂@2'/E0?]tiP0 ";P61dQQe ȏiM A8ഛ8Og$0&rw[p6̾^ Ó/1MepWF[2 weYQ^x2훑q)#ctP~S6Cc#1LH ӣ= 7q; =iG i882' `•NZZ7`=+`\а;aCsR;Z׭X1&FX[‘Q O2 Ak9Ų(T:P+C1 a뎜̇_U?PK4Fv0  DIOX95/BOXTEST.BASPK:F1tY; DIOX95/CHANGES.NEWPK5FA`>  WDIOX95/DIOX.DOCPK;FPZN MDIOX95/DIOXMH95.PRGPK8F}  oDIOX95/DRAW_BTN.LSTPK5F5K* DIOX95/EXAMPLE.DATPK8F~[s DIOX95/EXAMPLE.DSHPK9F߄ EX) DIOX95/EXAMPLE.LSTPK>(~DT     ( & 4 $" .    :  "F ~  .R60 N2 $@8L  4 B SELF-EXTRACTING FILES ===================== The TOS file/s in this folder are self-extracting files. First copy the file/s to a blank disk (or spare partition) and then run the program. If all files extract OK, delete the .TOS file.. e0.. e0READ ME 7^0n LIBRARY1APP t WA READ.ME READ.ME READ.ME (Thank you) Please take your time to read this text carefully. It's not a bad idea to print this 3-page text (double-click on READ.ME and choose 'Print' in the Alert-box). Before you do that you are advised to write-protect this disk so you can't damage any file. I'll refer to this disk as the GFA-disk from now on. On the GFA-disk you can find the following: READ.ME - this text-file (ASCII-text) LIBRARY1.APP - first part of the Library (packed) LIBRARY2.APP - second part of the Library (packed) MANUAL.APP - the Manual (packed) EXTRA-folder - some sound-related Extra's (all packed) In the following instructions I'll assume you use a double-sided disk in drive A (or B). You'll need at least three blank formatted disks to unpack the files on the GFA-disk. It will take some time to unpack all files, but you will finish with a Library-disk, a Manual-disk and an Extra-disk that are certainly worth the effort. Do not use a standard TOS-formatted disk (80 tracks, 9 sectors/track, 726016 bytes), but a disk with 10 sectors/track. Use a program like TWISTER or DCOPY to format such a disk. If you trust the source where you obtained the GFA-disk, you can use a harddisk instead of the three floppy disks. However, if a virus destroys your harddisk or burns your house down, you're completely on your own. You can also use a (large) RAM-disk for unpacking. ---------------------------------------------------------------------- Create the Library-disk by following these instructions: 1. Put a blank formatted double-sided disk in drive A (or B). 2. Create the folder LIBRARY on the blank disk. 3. Copy LIBRARY1.APP from the GFA-disk to the LIBRARY-folder. 4. Double-click on LIBRARY1.APP in the LIBRARY-folder. Choose 'Extract' in the Alert-box and press in the Fileselector. The Library-folders CHAPTER.01 - CHAPTER.15 are now unpacked automatically. Be patient, it will take some time to unpack the 202 LST-files. 5. Kill LIBRARY1.APP in the LIBRARY-folder. 6. Copy LIBRARY2.APP from the GFA-disk to the LIBRARY-folder. 7. Repeat step 4 and 5 for LIBRARY2.APP. The Library-folders CHAPTER.16 - CHAPTER.24 (167 LST-files), the folder GFABUGS (11 GFA-programs), the folder INLINE (15 files) and the folder STANDARD (5 files) are unpacked now. ---------------------------------------------------------------------- Create the Manual-disk by following these instructions: 1. Take a blank formatted double-sided disk. 2. Copy MANUAL.APP from the GFA-disk to the blank disk. 3. Double-click on MANUAL.APP and extract the packed files as described before. The 1st Word Plus files MANUAL00.DOC - MANUAL25.DOC (26 files) and ABBREVNS.DOC will appear in the folder MANUAL. 4. Kill MANUAL.APP in the MANUAL-folder. Now you should start 1st Word Plus and print the file MANUAL00.DOC (24 pages). I suggest a left margin of 10 and NLQ print-quality. Of course you can use any wordprocessor that recognizes the 1st Word Plus format. Please read the INTRODUCTION (starting on page 9) thoroughly before you do anything else with the Manual or the Library. ---------------------------------------------------------------------- The EXTRA-folder contains some packed sound-files: GIST.APP - demo of GIST sound-effects SAMPLE.APP - sample-player SND_MACH.APP - player of (Mini) Soundmachine songs XBIOS_32.APP - XBIOS 32 songs and sound-effects Copy the files from the GFA-disk to the Extra-disk and unpack these as described before. As far as I know everything in the EXTRA-folder is Public Domain. Here is some information about the folders you will find after unpacking: GIST-folder: Contains 52 GIST sound-effects as INLINE-files (*.INL). Run GIST.PRG for a demonstration of the sound-effects. Read the paragraph 'GIST' in chapter 16 of the Manual and try the GIST-Procedures (described on page 16-12) yourself. I apologize for not including the original GFA-program. Unfortunately I seem to have deleted it... SAMPLE-folder: This folder contains two samples (PERFECT and WELCOME) and the program SAMPLES.GFA to play these (or other) samples. Read the paragraph 'Samples' in chapter 16 of the Manual and use Procedure Sample (page 16-12) yourself. SND_MACH-folder: This folder contains one Soundmachine song (HARMONY) and three Mini Soundmachine songs (ACIDLINE, BANANA and MIAMI2). These songs (and other songs) can be played with the program SND_MACH.GFA. Read the paragraph 'Soundmachine' in chapter 16 of the Manual. The program uses Procedures that you can find in the folders SND_MACH and MINI_SM (page 16-12). SONGS-folder (in XBIOS_32-folder): A collection of 24 XBIOS 32 songs as INLINE-files (*.INL). Run X32_SONG.GFA to play these (or other) songs. Some songs are pretty good, e.g. ALTURE, BADIN, KINGOTR, MICHELLE, MUSIC2, POPCORN, RUMORES. You can find more information in the paragraph 'Dosound (XBIOS 32)' in chapter 16 of the Manual. The Cont_song- and Song-Procedures (page 16-11 and 16-13) can be used with the songs. SOUND_FX-folder (in XBIOS_32-folder): There are 32 XBIOS 32 sound-effects in this folder (*.INL). Test the sound-effects with the program SOUND_FX.GFA. It's not HiFi Stereo, but our humble sound-chip is not bad either. Try e.g. BOING3, DINGDONG, EXPLOSN2, GONG2, SIREN2. And of course you need ridiculously few RAM-bytes compared with sampled sound-effects. Read more about it in chapter 16 of the Manual. The sound-effects are stored in INLINE-lines in SOUND_FX.GFA, so only the Procedure Dosound (page 16-11) is necessary in the program. You can also create sound- effects with Procedure Dosound_init (page 16-11). There are some other sound-effects available as Procedures in the SOUND-folder in CHAPTER.16 (page 16-13). ---------------------------------------------------------------------- If you already have printed MANUAL00.DOC you can read page 14 of the Manual and skip the following. You are free to use and change all files, but only for personal use. If you plan to spread my Works (Manual and Library) among your GFA- friends you are doing me a big favour. If you spread the Works you are not allowed to change anything in the original files. Furthermore, you should assume that files in the Works are not 'Public Domain' but 'Freeware', unless specifically stated otherwise. Freeware software can be given away only if you don't change anything (not even bugs and mistakes!) in the original files. Public Domain Clubs may distribute the Works on disk and BBS's are free to make the Works available for downloading. It is not necessary to ask my permission to do so, although I would appreciate a short description of the way the Works are distributed. Please note that I retain the full copyright to the complete Works, but the distributor assumes legal responsibility for distributing the Works. It is possible that parts of the Works fall under the copyright of a third party, but it is the responsibility of the distributor to check for copyright infringements before distributing the Works. I can not be held responsible for any damage that may result from using the Works. (c) Han Kempen, December 1993.BX r`""АBQBBBBXN"JI`8$L"JIpf S@k"Q`rdAAS@kQdm`NuTC $I&IJh k" @"grѐg<fA`BeNu`0:`bC2| f A!,(4,(Z>0 222BQ"<0<NB09"XNu*O.Bg?<NMPr0P,  h#Z\Q.|(L*m - Э // ?JNA/p$rJd B0RJfp a#L"f jpxa NATA"r sBg/mtGNAP |2 a\B 0TԠ 38 Cp4 (g31($ r†"jpZ nJy"Zg y @ PK,"h0LTx\P >L=J JjAa. `D3Bg?9/<R?<BNA y faa` a\BgNA LB,h0h4Byj* NMXJ@g<g TJ@kJR{ <ъiLLpCl84bLD@^pH"pڈ"F0$@P ` (N,o/."WC/ $I$ A r?"QNu _"n &J$Sj$nE/ a( Wap _C$BX r`""АBQBBBBXN"JI`8$L"JIpf S@k"Q`rdAAS@kQdm`NuTC $I&IJh k" @"grѐg<fA`BeNu`0:`bC2| f A!,(4,(Z>0 222BQ"<0<NB09"XNu*O.Bg?<NMPr0P,  h#Z\Q.|(L*m - Э // ?JNA/p$rJd B0RJfp a#L"f jpxa NATA"r sBg/mtGNAP |2 a\B 0TԠ 38 Cp4 (g31($ r†"jpZ nJy"Zg y @ PK,"h0LTx\P >L=J JjAa. `D3Bg?9/<R?<BNA y faa` a\BgNA LB,h0h4Byj* NMXJ@g<g TJ@kJR{ <ъiLLpCl84bLD@^pH"pڈ"F0$@P 2H@P 2LX2M 2HB<BeB | o)@ LXꊋ? A|a4*چ p Q?<?9/38. BNA `42. >NAXJyf a`p+&>l 9, lƆlC l~B09xlZܖVl2l(l Nu..NMZ@g&Nu/. NA\NupJgRR`NuJgىRHJb &0plrvzm(R'($<'JCfJ@gv@0H@ |lSEXG H@H `BL?Nuሉ:<L/<?9?<?NA Jg ܧLfP44*ZJ&RF9&QR A&Za|3in\tlxn^t\xn`t@#y ݆H>솚4֊ֆ -ֆRyNNRYNFRqgHRQ8@ca?-/-8 BNA `SJ<Jj J`3XWl c,m bD/?92?<?NA JjAa `^ yD,H#Ȇ(H #D((,9(8zC <gr/C@8 @& <?nn 3(ap0Cѹ( @JfJV&0@l4`#߈p*'@NuaJ'V~ /m†ANA\38#  fp4a"|V|BCˆr†jpZa?MZB  a`,>NAXqEVvLP,ZLL Nu (3  3 B'a~f°|aN y fJ3 3 3 an3$%0 |gp9a`0E$y eL3B2ER] ] $A1 ybAg ap*]@Nu ycXrxI B0xA`3k`gFB`HJg SP@ 00a`؆ fh `DHpPH@:Hx8Ј]$|b0 EH(Đ"]DJ\S`HHa#D (x&ypvK@ӆ JEg0hrEt9* jB6p0?@A p0L8Nu/ y? e BLR{  @&Nu J H 1 L  r y l  NuJ0NH瀀 Lm //?? ?<?NAsJ0j1 Ta3Nu/J"&SA" |@$H0MEQ /?@/ @f  .`1j21 1L1Nއҍҍ Store5dCrunchedEPress [ESC] to abort. Actual Stored,Type,,Dat;Tim; Name ====Z Zb=astZ#<</ /<:<EY 5Select EXTRACT path : " any key bytes skipped!File has bad ZOO header! Unknown compion!  ExtractingS3x OK CRC failsInvaliH9 Cannot openI.creC - d ERRORstack overflow!feWARQNING : exist! rewrite(Y/N/Q)? E[3][ Error during WRITE.| Extract file again?& No | Yes ][1& DC SEA 2.10 - ZOO=or| W!ten by Paul W. Lee| 1989-91 DoubHClick Software|V Please seleC unction :][>#|Verbose|Exit]0123456789ABCDEF8Xfn)  .(? P 6ZZc         c   { 4 &  > $  & 7     H?        #  & $  "",,ZOO 2.00 Archive.ܧ*ܧx}t y7tos_vers.lstaP /chapter.01@)#(OPA'SX)"e &S ,ŋ3j( Gi$:aذ'̙2 b@*NPI :o|SFΜ4oܐYS ! :r1QH݀u9iܜ3.@O*ɐ L@YW0H`!"EB �)XMoa)ET3VY &EPa9AVY4ܧt xauto_prg.lstsK /chapter.01@)#(OPAD*T|" &S ,ŋ3j( Gi$:aذ'̙2 b@@*@H)C7s@PR4f@ 4lʐIRΛ3r´q'L9tȡ#[&la 2e$RĈ' ԡ 9gzR&F0RԼIpr̀ܧ{t wBXNres_cold.lst /chapter.01@)#(OPA"S y„ &S ,ŋ3j( Gi$:aذ'̙2 b@P<RH 䔙SΗ1oؐYS QO1uTiСEE@0r> %J'ӨU:g݀s' 1hҸ9"ϛ:v#xc EuAyc0b*h:q9oڀdJL49s҈a/^4Kwށ'y6FW{sħ}Ɂ~_]x bԠ{vE( OI 8Q(АB 5jY VFMQ5%ՖYܧ t wo reset_b.lst /chapter.01@)#(OPA"SP")TAŋ3^ #FhM0lXL1Zh(R )BAr)CO ! B :te4nR0#*2xq9iTIB" "PYAl`Cgje-\{q̘d~,8 'K0L  eX;w4?X$y2 ,0-03BFC,-H^tB* ܧ0 + t wres_warm.lst# /chapter.01@)#(OPA"S\ " &S ,ŋ3b #FhM0lXL1ZaČ8('Cr2sr'6:+ B A )3">5T(z I餠j 0b ƍ M@)H@ӗn޼1j 3< y9'Le̘6̜G{&hJ[J_ #DDWA *Ot1%ەodN x M9<*MVZriN;QZQh/QFb-PkE@x@XDt(  LpDM" 2 50 +b3ҐA8A6̠c ) BkaK]qoё_#x(̀:0EE,NjA9JlFG y Tb^( miAۀ/iyڈ?& 3"D$a98W 5XZFrQA:uլܧ t v &A60_hertz.lst2N /chapter.01@)#(OPA _BE &S ,ŋ3j( Gi$:aذ'̙2 b@P<RH)E "DSF=5+H B A ICg cްySGN6oP}#7BA A@DS)S 3lҌYSt6ea n1gjիgӮ <\Aԙ3 LZPbgzK0g t 'K@b02PYbwS&P*?,ܧ t v50_hertz.lst /chapter.01@)#(OPAD _BE &S ,ŋ3j( Gi$:aذ'̙2 b@P<RH)E "DSF=5+H B A ICg cްySGN6oP}#7BA 4i怈k(2ēÆ0f BN9e`TA)P, j#8dBȔ"TP@)Rd ʗ3oN"b@tR*j ܧMt z?Rllistset.lst /chapter.02@)#(OPA&IPR & Aŋ3V #FhM0lXL2ZĀ@P<RH)E@af/sС͙95) B A (et3o$ja>lGΛ3r´7'謔T/7}[yӦMI2sXPZ2-LSS4V 3Lbe5,LS3@acwҐ Ơ w PHmm5aɼDC9eʸis7 ʐIC'lqZM (Qm]90oY7 -F p4<Ȇ3Xm5EONU$XS@ܧQt zJ8llistibm.lst ) /chapter.02@)#(OPA&IPI" & Aŋ3V #FhM0lXL2ZĀ@P<RH)E@af/iĴQ≦ Tbʝ4tƠY)':e䀠& f Xs1Bfވ#AFI.м@'5R餦ԩUXܧt zP?Oed_debug.lst\ /chapter.02@)#(OPAD"_R &S ,ŋ3j( Gi$:aذ'̙2 d Hy2`)E@!2e9c≦ T":i섡NQ4:@PD(QH2Ut"U(r̙G6\Z'!oБ_)iΠb 4f4FK[)sԂpߌZ'.:s䂰B1oڴ1IfJ:hĥl:0< )F >bΘ=q2w䄁+1?1cĝYI#d[a/׳#LXh1aVBElxPx[b9 }Qp1%0X`!Tbe cRK@&L JA ,QGpВL&Y sѤm0TII,B 10S =0OHBND$ c3GB PUO,TDd ,Đ 6L CE1q QFbuJ[E0S ŊiQY p1GQi*NqD%⒲faXOZQh<ĠE}!W4[D9Ař,Ȑ"LHB1ECCG+T"+ B8h@*C ƕ4 L@0!Ƚ B@A2]d 2PŽЃ=KGC&[D CJ00 =T0)Xţ,{fΠ}2A _RZH}v6dn * ~u|f* ܧt vp)$day_pass.lst /chapter.03@)#(OPA Y@ 2e &S ,ŋ3j( Gi$:aذ'̙2 f!#U d9eȠ  22HYU 1$:lЁy2r@1TtЈ!LH?sL7pi;vլfZe޶3 D!MyBq*'C0a",n[l=-qH&!"TNFLI\Uμsґ0D 4=`DH$bIB /)ÊjLaQ7 E)D_IQ`|&8EC `Y$L-!}ע|هCD8D) 6@~%Vd[MCM] {T` 0@ 20C7MX1!Dt ("(vq,f 6lc L '0LXzIRRA[iW9QqUR0TDp UHSBL–n*0'8dbZ-kS@ܧht 8day_week.lst /chapter.03@)#(OPA Y\)Rd &S ,ŋ3j( Gi$:aذ'̙2 f!#U d̗;eʬ!"hA!fVA$2tq3PEA U E9ej)ÆM9'y挜:e܌)SUՉ]& fJc10ɐqѦZ=4B ,Ȑ "T ( Yoݵ_O]57mDhzEPqPB5(fAjEP*@Vdܧ)$t e time_inp.lst7 /chapter.03@)#(OPA$M|I &S ,ŋ3j( Gi$:aذ'̙2 f Hy2*RM/iC R-"))lV<@*@qCFAbL9rʐmv9-༙7 P)3/9 ܼap9sɓU։aSdҘ1cV.[3w۬D .hpF:f!FEi`3eώACxM3 P5+tq\:o X4:ڴYq9s&fHUz۵=Bae}DuĽV|oW_k!Gm|Y $1RJ1!\w5hL B,F,eTU!A h lţrFRLQeSF"Yru+pIe8XaiIa8.# []RL1Ltǚm2PWO8!~ODuST!v 9burXJ樃Q1Kѕ!@Uѕ}6aCUHT[S$a!A]=<(0U *n F& Bլ  ] ,CIk( "Ѓ Z$,=tbEE@:j. ^. [i"!lXNkED<KlDDEA 6*kڊX 0 7<żZŅՄIYDW&R$q#|4 ;t)2ĮC +L4ڊkORݕdSuʶIkU{mr) i?ݯg䵕`EޜpNpEMp‰Q+*p#sWLЄcY L96:+r1אC;Ƭ0ŗz"څ 63[f=p{ndCK7 P7?>U;?Zs-=dr?-ڂ2p06:GRF9`*]:aD)) (pev-dQZR/K`A("Npe@0P؊!=Bf<$Z JMDt OήHWEK) Dwkl '=? XR aPrEŃB &y ̐@F2y&iP(N NtE(*6! *ЁƐ D\?jP u*! pB@J 6XLܧ,)t hstopwtch.lst /chapter.03@)#(OPA*O\2 &Aŋ3V #FhM0lXL3ZĈ@P<RH)E@̡Ν0tƠIS a$ ƠdC(0rx-z4RM%NRf̛YvZtQJF-XeK(rތ)CS54n]82:h^a_tҴ)WڏlވAI]e8,x!*n1Ftqú.j8Dž_猨X .|j} *ݸ2h>e3%&1;o7!CkmSP{#vv/#. 0C,jg٧*&.+5E*T5ܧ/,t :.millitim.lsttR /chapter.03@)#(OPAD$L$ &S ,ŋ3j( Gi$:aذ'̙2 f Hy2*Rh 4tҴ)#K7HmV=!k'4aİ)3ĝT5 tJA7XA)cF &ƅq y 6 6 Ǒ'dcs/n433nŴ|I1tҼ-wf9(gvUgvSlP %[Blp aFљT:X.T%`EBMEXQY` =1EB|wt ђLBfd`?5bUH1[yh]zl@ъŹXgVR%xQR<1DDTAHWELRnY(= !CFSqeYn9Bj$S96*|*@#zjSMܧa42t }Z@Gdate_prt.lst /chapter.03@)#(OPA T|" &S ,ŋ3j( Gi$:aذ'̙2 f >RH)E@ C8rҸR:.%fVA$"gҥB 3GC8FL9 ڼYD2a3.IJL6F8DTUpubW*h`Jf˯E?A'31u)9o䴀fN:ifZH6ߘ4Xq̡­Yd\i"<"v[a1 /wʔY3e>yŒR 'm:qŝwYwkHLa]y\tiFVi`ń(0QThMł )LVrЃID+4P=T\s6GVF^1@  M$AN-b&DDR,d+bYUTD aVND>Ȑyf\c ;%i5zFxUFYYDE)F!YXcBNTJxW GDg(G SGQm,8e4K-e6EONWkS@ܧ64t |Qwdate_new.lst /chapter.03@)#(OPA T|qR &S ,ŋ3j( Gi$:aذ'̙2 f Hy2*R N/nܱYS QčQ9 1'mZ5 E7pQĘ:r䔱7rZy3' 4oܤxmھ13h_=M A6m\#ĩOMs/3xaE6f[6l)E 8\2a>.8+hz:7cÅyo+Tjh1 hb :oܲU7L6gB` P!\!hSLnFmIpVZtU Owa= !CctK 205ڻ%c ־BN 6` ^/X0FJs^_ftdW1*J5 [.w=~B?0H@Iv߫];ޡ`+Qf%!w=Ah 8l0NI^Hz怆]m ShiUkX@]+[$Ӝ5ajUs lF8Par6بm3Îv=t {harrshufl.lsty /chapter.03@)#(OPAD)R b &S ,ŋ3j( Gi$:aذ'̙2 f Hy2*R#GN<_栩c 2(Z()lV<@*@LY)mĔ3D7 CQy~-Xi2nMC[euvΝ0pxaߴQ/`0@p+AVP)n{H&?Pܵ5"O8DM\ *^R8!bJ!CPbwY;)EbAubs/mܧF?t {date_inp.lstk /chapter.03@)#(OPA T|I &S ,ŋ3j( Gi$:aذ'̙2 f Hy2*R N/iC R-"))lV<@*@qcTT SG2d׶FN 8o椡捛_ BfL2mac9 섑ӷd3uD6Z" 3?8Å O dbu2@(fAH[  :w Msf/0-,40󔙼|SFяt8^Mek$\y GsY0mQ@.ц ya!AV;EE0eq_n5`) augF_8XWEDLRLUYHOA0,QFU%$!Fqf~Rp'Yh՘C Fzrĩd]RL1LtǦ2PWO8!ODuST![aV&UV1Ca%&oXkWsRTQDWFu U!Q 8fpkН]p?LaUFHǸpnBRkqSe .ERNn" B =EF1\,Dp -o=1wһ"[T/[l"\sEE8A=]M4zEA '󚲝jW  @-5M" B '} QeYs=HHL0,@XʹuEWIū3Bq;Ư5DE,0B Pa X BXP( c_pdsP`AX* ,p`EhvM vo hj"PPD%"JE+*b$(A P FbS4z EDR+.c bs052j#ė39JYrV!dΔQ*1r Tߌ8)GFr~ DRuL+* 4]$u jW9yedN1'i|WR\.*Ӝ^iK$@[XExP=3 N.cp6OAM8G't<2s6rg z܀hAiH c2;E]%JR[= 8W.U\ɘLbiD"l6g iFZSPYJ˴Rr)lʂusjdƒyfD<%)1^*kK_:d\"1ϋl:qD*"b)>O~<R*5Uq:[ҶmoS7uCuj$NhL.O\3P0+ pH* C>^8xۄ'0$*+{jjf$ag‹v#8WZAB  #d j W>e"Vpm3E,TaBF ,޳D)bܧKHt kmemblock.lst" /chapter.04@)#(OPAD"M0y2d &S ,ŋ3j( Gi$:aذ'̙2 h@P0,B" ڔiFN/bؼroAsv¤a&)̻r apd (O&96@,!7A"<_6zÀA%gvgpebeg^z_ elF}85k[F!%_cbdX^{u!`d(CEG9eDByE kT%De~9 2PC ,t9` TlБ!ئ b%a(41^y(C r8U > 1  i'tQǠQiǝwbUYǐSv%V魸gs5ju v%*`O(P +d% ުaQqg(耯ylEB[ע!ua-ǹYmꢯ)ۻ 8el\ǫlNQAB"`_UMHFx\1iUo qq\,Ňa BDR,)\ d8lxI4  "DQǔ| ~t3&VAB)%RLq]OTDMPM9O?HW m` ʡѕrZ]6Gf"JZQ}TK%ʎ3EX0GQή7x[oE]DR @eExMܧMKt Yquik_srt.lstj /chapter.05@)#(OPAD*I|" &S ,ŋ3j( Gi$:aذ'̙2 j@P<RH)E@ĩf̚/sȡJ),"EO`! SqG)a l:h@)39i<Qb*:k9ehf2崅k2k۷K 6c)(} ju6ʔ' dg& ؄C:m*x=QI 8RZ:Q`ќwT~:y3Ξ?7B{ܾi j0FllVrlu\ryT%a AAD},ǂ VmEAV]DL5!UlÃʡhQN WNgVU8AdEUÞ}هqVUl hEߡΩzԕWiMܧONt Kkbin_word.lstn /chapter.05@)#(OPA$N\y" &S ,ŋ3j( Gi$:aذ'̙2 j@P<RH)E@I˜2aA9dPaSM7tXX "7cP`AL<,ެ fnA$ VJQs))IN:huѤK*x;n3Sf3uTxf񘗪U~瀐SN9n0QmTT)WsE&;0a&9Yل΢M2dƭ~Nqc' "I@k^AIPqUxT(A(vt%C[Y텕ᕁaF0EC 1w%hQ1E@x7PߏDe\uإЃ^U׆Ujfуq8uy]aM@Q5Eכ*YS@ܧRPt zstr_indx.lst /chapter.05@)#(OPA*R$qB &Aŋ3Z #FhM0lXL5Zh(R )B" Б͙/Eɔ%Μ7r0æeVHAg)(RHD4)H B A aY<-ȑ&;i ǻ-LSFoZL޽}zVZpP6z߮x: Ơ)Ln &LjU ~40sƤIguuBK(rތ^G ɗ7}ZܠofN{ 41͖ LPPc5 = D$(Z jdQvudBlFnVMh`0RaW+B_VF :]fQ>xK=Gc#ޅAF?_(!E ZVbJeQeRTALa ™xYEE0#[6h[FPV s~6b1XxCJ+kUg'E@E}IYfS(J+pET q\x̅U 1Ěy iJqE E*Yp۫޵/:j>9ASno|2MܧTSt ~ Oshel_srt.lst /chapter.05@)#(OPA$E|" &S ,ŋ3j( Gi$:aذ'̙2 j@P<RH)E@AS /sȡJ),"EO`! J逸L0r36 4\5 vVY'~ ̔gED9 )Q )S4z"AHf 6Pb ΋21uҖq#2vҼQ:=rDA$I(lOju+"9+H[EvE8=xhzS ;k׳WLbn5)xܖnqn(sC2iEh6"I,[}N{K߼vp DONVX Mܧ`YVt "iter_srt.lst /chapter.05@)#(OPAD*E|" &S ,ŋ3j( Gi$:aذ'̙2 j@P<RH)E@SFΗ8uҌYe9tPX "7cPHQ≮ TbS: <%"9aF(Qt؁y"Jҥe~U,AC'RdҴa& ctaQ# 1eΤq" 5,ڤ!CMԫ]IY ؄AexV$M~s5V7~M*ANQȀ^xQ. QĚjf:nPIDM@Q5ݔN=t@لhed Aw01o)%#f,Bfb@RSHU1_T9 džwÅQue7hwۀG҂6JFٟ`1SL ߑQF о! `BM[F`fs^@FdqtD* 5ԐERIDFXlZ0 Vdijaҁ-hĊ@ PDL7XipFg9DXH(у 5r0d5p3g h3B=9ܠ41ȀU³I߹1SBaU]hsTD+ dpE@QD^PA᝵V{ӪF;-}QNPa PJ7NG:JK݂%DȜ@lZFk!_]6,p e5`? k " w? {OCwo66|d@} oأX@{ O}4wUzTX P|5Wj05@_٨C{aw=RJ "nhb`>)bTnx,b;XDŠ7Ňс"pE@2aG{r_Ц7Pc!kܧgft 2Zfdenomntr.lstd /chapter.06@)#(OPA"N4qBE &S ,ŋ3j( Gi$:aذ'̙2 l@*NPI 2eܼiM:oSE)jVUDHfΚܧahkgt zAarr_frq.lst /chapter.06@)#(OPAD)R)TAŋ3^ #FhM0lXL6ZhH'C$yD9rbFN8(ʰ)ӆ+"E O`! RЩ# Gq3&7f@(ejDw!g<[*ɐ L"V#O' H)B$M~#ի+&1u*4)zmbQg#[qTH6Dlի 4ܧjht ?P1arr_comp.lst /chapter.06@)#(OPAD)R y &S ,ŋ3j( Gi$:aذ'̙2 l@P<RH)E@#'L/c޴#̜9(d))RԬxb+UR;0ԁ&͘0t`aS:s@Ĝ7r~LEx[p/I4o܀xc40 +A`fiXu=QI VfG W$aUDPÇs) :!" tVLdHwE{MbjpST>]<xMۈW5]} TrAy}WEWUfl^t)@V{nMFwavXc`C!QFy%DOX:\C , bJ2+Đ 2`cRpHe &yFK()WXbe8qGpIAy{6 e5LqFnBٵYPTDMe*5ܧAljt nXEfaculty.lst /chapter.06@)#(OPA C0)TAŋ3^ #[4 N6,@ s -r4P`!TE9WtY`EIDpFw}WDx=y!5xSN5GP5ܧoPnt fswapword.lstz /chapter.06@)#(OPAĔ+A\y" &S ,ŋ3j( Gi$:aذ'̙2 l@*NPI 9wr2(HQ≦ Ta0(hҜAG6o7f@= Ř7n씑CGяt޼0#MIܘeŒ6a0U"TH9$HCRHZ8!r3gMSUܧ=pfot $multiple.lstKD /chapter.06@)#(OPAD*L$¤ &S ,ŋ3j( Gi$:aذ'̙2 l@*N(|D:l褁æ 7%X 3&E͊'HP#i<&e9t|J3 1B éR<Omz4yBDRv+&1⓮ԊRP"*BP!R,$Qb "O"N, ͜5VUf@ܧqpt ݪmasktest.lst /chapter.06@)#(OPAD SP)2 & Aŋ3Z #FhM0lXL6ZhH'C$yD0s|Sf(ل`Ϡ)hR1 ۰o܀FvIF xLTZ0Iڤ!z- "iܠ- ۦQ/p=7bYWfGHfq/ffl1G)XԪIVZ"TH Mߦj͵BN:vrQzrI14ܧtqt >bin_chnc.lst /chapter.06@)#(OPA$N Ad &S ,ŋ3j( Gi$:aذ'̙2 l@* $y4n޴I4&ǔAq2rXMZf 7)jV<@*@PDJ:P݄N9ffΜ4bؔJ 3.@) \IfNV['-4mʸ" \2o S9&@1mh'hit)1 A,!H(_cԑ4ҫ"3o(f옹WϣO.vZlod\%ugr5_cuUAF![p!mnkP`eaahyL<1DL|'VC29]%aDk<]Ud=aFuܘSu8}V&6-y&^)-`UNaԑ/d }.yEPQ= (R#VC V%ՙ}E@TĠ ]N֤*75TӅ`ZS@ܧIuVtt {-0arr_sum.lst /chapter.06@)#(OPAD)RL)TAŋ3^ #FhM0lXL6ZhH'C$yD9r2NVf )hR/chapter.06/gonio@)#(OPAD)CLA* Hŋ/pC#AZ4 N6,@ s -p4P@#N@34(Hуɓ#AGEJRB[Hb@* ܧ1t 1gharsinh.lstI./chapter.06/gonio@)#(OPAD)S8A* Hŋ/pC#AZ4 N6,@ s -p4P@#N@3'4(Hуɓ#AGEJRBWHb@* ܧNt iy\coth.lsth/chapter.06/gonio@)#(OPAĐ'T`2 "JHŋ2ܐqHM¸ pœ)F  )bĈcAψ=b H>SHPҘܧt ktanh.lstX/chapter.06/gonio@)#(OPA N`2 "JHŋ2ܐqHM¸ pœ)F  )bĈtDAgD(`g D[LEСES@B1T5f@ܧ͉kt ܝbcosh.lstM/chapter.06/gonio@)#(OPAĐ'S`2 "JHŋ2ܐqHM¸ pœ)F  )bĈcAψ=PC" 1T5f@ܧ&t ;bsinh.lst/chapter.06/gonio@)#(OPAĔ$N`2 "JHŋ2ܐqHM¸ pœ)F  )bĈsҸAψ=PC" 1T5f@ܧDt {carccot.lst/chapter.06/gonio@)#(OPAD)C<* Hŋ/pC#AZ4 N6,@ s -p4P@#N@3f:(H#'(ZMJ2f $B̀ܧt Rf trim_r.lstY /chapter.07@)#(OPA)I|* Hŋ/pC#AZ4 N6,@ s -f4P`!ThL9dL~}Lܧkt <lowrcase.lst /chapter.07@)#(OPA'W 2 &S ,ŋ3j( Gi$:aذ'̙2 n@*NPI 6o3&̜2$PCDO@! RЩ# 9tqsĝ4tЀHDQ8hSqƍt|gСnZ`ֻrxcD(PH!AxL@a1|!#D+:6j=`)E`RĉRN*عG"GfFE=dRdO>S+&1▏6jHw=rnQ:u%DoHh5[MdT'E`!QSFERe wSN5fU5ܧmt  sleft.lst /chapter.07@)#(OPA"F`2 "JHŋ2ܐqHM¸ pœ)F d$O`S (ؼSFΘ0sʄ`AOIEC"Ë'HP)eԑT: ޘ'4eyZQʵ Xd tXΡ#NI]w Unޠ5ƷeU$k5Ti*Ra:i f:є,&,2eSȍMW+'C0A5N8:iH⤡U@)",ϯ2VB J AUTUUN]wߩÁRAER$ڄr!:}EDVx1SM1U1ܧ.t nchrcount.lstT /chapter.07@)#(OPA$R<ℊ &S ,ŋ3j( Gi$:aذ'̙2 n@C$y4a|:(ؼSFΘ0sʄ`A,~%f^A$2tqRmLA'M2s|f zx3fڼiΡ#'VI[0J:*)U0bo7lɤYj4xAA˴ :p613Q'edH& P}C'e$F@8y"!VzG(PH!;W^"\*`FS!%gAZ* ,-|pPEl;#huJD{ >8rʤmN㌂ef?[C)[QDhyfK$~HBMPavnВ3oy֖KYui$ = jFSoe5Day 4$X|fs:=G9c.WɥTDi gT*hڠqxPRDWuQ;T<Syu9~ (E IA p&ɰ2ScS!0s$>=Ozhw@L7N8H^rwDX@Cp#g}YDi S>!s& /9c9, $-0b j0bkA9J[];6sLhP0\,vs$?;-MK"7܌a h!fێo\(i1=s ƂhXd+Gmp{ݚ&LqC*ґ" U܌*9HQ`DŽL `ߢtnhl3 Z'\ h B@%m\B1ZAR8J9ዄ!Ab)l -BBg?nM>5)=5~EAFJu%u4A=fЈNt;XzP"i|p2SBc,!%i_*R hHGZҌ*mj/Ux)aU^iTņB!J Nws74-. jSMKrd( ʻsulC&),/%>8-ނS<+2+E;6ݴ[⼕NqrUr]~q#"f8 xAyg|tPB W|MS@ܧۭt t popchoic.lst /chapter.08@)#(OPA'P yd &S ,ŋ3j( Gi$:aذ'̙2 p!<RH)EXe 7iƔAEVH DžQJIHPG 5͊'΂HP#i̡bLJ6QJP K7iyL6xȑ&UXh5DᴨD2'A9z87 pj N:0QHˤKhL3L1lQ˶`3 )Wu6oګ7 " ̳dhaL0zLDgy1l< Qp_]፱rqtǝwbAbfju@lKtYa ڃ qcrXaxv"B+5bjׄ Et@4DuI_eFoQ#}QfWU]%YHD zh[nGt,':Ty!FݕP.&TGJd.%udgyE_ej`vXb labaF|0qdzhzl]dL Bxstz,!Sh i  ,C18l,,, 1ZiMTkc|shZn@DMY 3UAL͎Z37qYdQhZ&aD>طX_ `Pg%zbKb2Z+a13DE= 0@vNlZ]DNUZBF<1Ux@yA`]VilnoQE`!QӮ^(t )ZxD7ŪxL6̣M5<7eʧ= {/FAASn=txC7CG(D7ZA YF6%r3 j (ԇ;^ZA0ڔ xZ\R)x@ _bp  ǂ :! w @"2* a㊾X\q"TBb˃X}.tAn cE)"#ȰÝ w5t2IԦ8mcHM^$T%G`:1iܣ;\ TYiRe-чK n on_V|#-6JÙsZI<`(C Xg@ۜ hܠ];5gͨFj$HU.qMԜ)D2_MP. !,`2Ɏx\٦~Q v u_(yHH\b@-{p('L1-YP>X1Wx\# yHۧZ"3=0PPT"RS縈 yߚ*cx@y0o E &5I=P2V+9<.^YE;Z[D98j lD zH5%(=Qq=20/@ FpJ̊F5(WyLa CB%&2ICM!\)Ko*pLr#^4]xLb^nu]z\@D\i6ObvπxWffoU* h.X|׼"xSЖ)@ EۺlܱA Bݬe1YvBhZ۸)ڠF)(X >0Co+W3X Etf\Xƞ0E o;VwWa9'Ӄ_Ze wsvxȻܙX὞z/\yB:Q\6\c?sn"EwWߏzʐEJIomۚ"9_Xc-ZNw2oalZяx3 +X+PC]Gh8yx[Cpxٷ%da=O h4h1tspt`85pDa|v7zgw|||ENd&L|-@LDGtX(X`e!Rx!E'|,(G?'wwh{}9x׃-X|dt|18ʇOOdΧKn*r0WрeSvamrGfx*W#YswtۧGIIbX5Eatxe:gyBiM4!XR0_0,A**eP䄡WO4p0;`ӃGR**v(Gr*HoG g(G5jxmą 5LNOQdOԍ߈}U8({IdLA5F8Ȁ8}ٴx}%1|<8xA8x(+XǧG(:(HoJhJ3 FSdJٸN,Z1pKDOJ َG8(Kٔ8B;S(G9BHa̓#Wl eR69xheK7cVfXX=rT rYp3~6~WeZ~g$VjrD@E40 O2҉>4B%]εBM1+ҥ@A?6e=C,aA(S u3YUn1w-R,r--n$1A,T5ympb&tWB!-'U10W9Ydpa36J~C艉Ny.z)r"IvS46{@Vz4BI#VZ4Y P:H: jiY0QjR0"# .B$s[4vєJ-0Q4H6D{Ȥ1E>cS3d4iUZ^ZDy.D7@bhj,mZ MqT!t7}ڥQvfʤmay6mq 5ܧݰ.t iAmacro.lst9 /chapter.08@)#(OPAD CRH ֔GN9sP) Fԑ&D O`! SҴ&9 ҸS1y@ԙSF4f@)30ræg@RF*U(̔MLEJ"Wduɷ0(7FA$q F0aXd ̖[jd[!B!ILA)XHѧC \pСb&BL3fn5DJ1@PyBL9E%PCM1 M$A 6T) E`!Q[%aQMUVCS`1 ËD'xEcShQllڴ?9aSW^5’6ܧ޴ t !cursor.lst /chapter.08@)#(OPAĐ*R<* Hŋ-pC#AZ4 N6,@ s -bh(R )BacșFC`!M7k6}FN:eRМxb+Ur' 1h@Py2Rr@q3 HvSlکPK׮` m(6u!%_ht4 P P0IH T8X!NZ ):nΑ7Ƌ0RCn\7bSf܎(zSF4cN0#L:e܌ɣUW 02&zĬ7ϛ:瞘|d:oI-Fb^%aPBWI 1iuxQ &\ `QNqa2p衇 Y {TV3xZ! 40՞2b"Z*PD(XbQ%- M$1a[be\Nᥐ id0i晍xWWfiMRABNДXX*JS@ܧl1t  4;key_wait.lst> /chapter.08@)#(OPAĒ"Y\ &S ,ŋ3j( Gi$:aذ'̙2 p Hy2*RXS&ϗ;a" 2a@EӧQYX "6d\PkثP餰Y[ 1ɗC GyZ N60Qh!F Nk'e2/jĜ2cx3.@ cGcMi{5A&6n*Aw7u@}nyb]7x頁9ATfsdTSFKu>˹N:4D1g]s <wwFQau]6{r@wMͱ]Sgz1bx(x!oa_!`x\rP8FdE1eayvRjQ[LN`%I<1 3LgYEfZBdAE{X+F!xIao9ri'2Q#WRW[Iq=VEJFeSP&nTwxI %cid ǩbiXV F}Q$Z:*ʗ_fSPTM-6ܧt _Flinput.lst\ /chapter.08@)#(OPA$NT* Hŋ-pC#AZ4 N6,@ s -bh(R )B" ؤqSP8u0L cXdS :rX!+2[J) ru 9e褠9] A:liˣI[ythy BWH:sҺ)q "o1YoF0@,'b)GH0 2%b!Đ0p0y3f fyկ1IT#͛ P1r0txbg9т{_ͥ@]Csqr^shj7_}t~kGnaхig -lsmHG sWU<6pQ!rr6FjWlWhuz F-wXI]RE ԍhfiwQ 74W!&\o&g誛FuV$C+U³rkf¾K$7nsqqK^P2oQ[dsF\hT%j&kC8`C 4 L; T7tS6 3M-LTBf1&`! "`vˤLx4| ‹RU&TgiXlfoPDF-cfE{^t!p}~8VɂRΖ^{;(g$(θqdjmR.~" BJ"|" wf[H7g,W[M8aaײc)m |*k|RY Ny@ fQ]0$$!]qMb Bi3bpIS0uD B`$HWJ 'i| X3NI `x}Hj2TE~9Xwr@a&.V""C\8Ьg4DɌnC!R[T#f^"5)9T:ԦFK_(!d‹('N" W,|4YYi:u04>I:2/fc%7UظeBk]iK7A6%!~g0mNXa˥Y(|is9Dq t RD $C8/ s&$LHDߕ:\ T<@ 1x ^:ҀpGC:/Fg <3Lŕ!,X#AurNR2i=PEʂpIVP G|TVwVQT.T6 kezP,(K44@G$op4JC`ZrH%TT+3 0cN >S!R,P.-]t-t'TÄA B  xpmlѠ!&).m1iKRbL7T]EHƻSE~jz@)T(FBQ/EǞ…@,)O& $ޚ;Q{S?23R{@T# &Q>cP?r#"DeQԥƳ`#$ !Ӿ*X,YA*G-Kq9JdnY<Am# ~).BQe g>`-˝e!V SSdЩzCQXg}nF9\,/pq$q%9Z/KUSbM9IEʩJz9=ڟtˊw1q׀ױrP78Zɫ*bz)Jyܚ_ 5!ZʟȖn ߦފé9i`hAhe.x/0d$Ud15feiaŗhGǸ;hSזRti)Dmfg1)n)zJ VT{G=zG7*E%6M,㈖4'?7Iyו~t [c0u^JLNs;SM# 3U(EymK(\Rg@HG{׬RЩ +ZJ0 ;8iAQb+{d[f[b!j Զ4i#Xs4!+:jkuBD{Usv#}w!Y[zwAYY( YYn`BPEV XY(Y0$dB(T &))LȲ$Y\;b{+hD]S3hu6rrJd@v&k7*|&[V(V;GIIhtqaGAǻ㊷ds˷K 0;drEGh| <@a lh̼,  6aiPa.qgz̅[`ȒŗL({bH$l/,68"=RXÚŔ,!]]ڼa7 ʪȍL't I̠#B\=kjqב%q?וkRgXDvaX\l,1/ll'L*Lj¦f'1\ACY}җ dDЕ<0M&mY< 57A#TB'DZiӮq% p!tf@!>Dt{Aڌk&40A[MX,7228=#$6LHP>}N'F쨘7SEWM%$ E%ֵ~<`Ai-&2;5 } K|*x{pUX)ՂXX0G$DBlm q| sb BV5miMجښgs }o][? v g3'[f` ~\(M<Ǿ'Z ,FI'cm8Kg yAf}ߣS!2":b3~ц2<Ohf^CRoz*[F}}r~  mo&¤,i.}{봮R :[@$hK3Z;y_N]ag:u좎4L]۝GXf s^םە+TAaD#&c@7ސ+|G Qt&l&. y]~3ZTb<`1`1JS>% eiw½eOP%-(o>0+ﺍ~.c3_gϣ}6P`=G ^;Y]#7F#EN~NOQoyH`kY<WPpD,J ;1Ԇ\**fޕ5KsĭZ_<Ъ1qDԧ,D2l H32+uϫKY-j].՝v}E\[VLsBPE\GE*K˶RSikWȋlx_;ݎsşsi1'AD:P^k?o9[ 2~Nȸ@aNV\RԘTHåXTI +ROݼEbTD$"8b=~d͠s )POԦ){.Є#b,(tqL&b[lG2F@M#EKZc"A@\"kN]zw6 [F0 DQ| J,yIK"4"2{{:2N2bE8y-3KpV . Ex0w?f2#." )j 0@Ddl~[IHd;Ƥ R\sC{"bF1`\F92!QCgG27X=TRZ0bw5ː0E :PId0"` C"<_BH*I'} !<Œ\=- 5:!J,!ӔЌfLH L%(JIdO HI|%uJh"E$!NW5V,T ^x0D,A C##$D6CsAQ1\RM L0']p4GZJ@0vyAm 104+ 4 )+4resY.a gDx{\k`F7nO\4K sRls.2}̬2_x"aέV3NkDXќSNޠpSd2_e C! 7Lę7ex33=f0k̴3GϤ@3Ԙ94cMJ{Qa H((b9TT!OQlRį>*"7TS]RM\S@ܧIt 41asc_caps.lst8J /chapter.08@)#(OPAD)C e &S ,ŋ3j( Gi$:aذ'̙2 p1URN9n "LŘ7d`1bM< Ĝ1&"y4S g7cրx&"F8j4_,eRJ=AAx,B<" LtĬ9)6BIp̀ܧ"bt iasc_shft.lst' /chapter.08@)#(OPAD)CLAb &S ,ŋ3j( Gi$:aذ'̙2 p1URN9n "LŘ7d`14ibM< Ĝ1&"y4 D1Di|jr.T(ʖICH*E!B{Id 6X01S2gBo 1dl'6ܧut  asc_scan.lst /chapter.08@)#(OPAD)C )TAŋ3V #FhM0lXL8ZĘ@@*@H)C7&Ib2/ߘLwAbΘE4DM"Eq"4iX-k=dRdO"DP"$ɓ)(b`DL†c  k$(f@ܧrt 0#any_key.lst}c /chapter.08@)#(OPAD'Y,))TAŋ3V #FhM0lXL8ZĘ@*NPI y)&FA$ĕ0i0FO7y@ GN9s@TM9eZaf̚K A:nIƍ~Jn=AAE)(b`# )1eX*h2-1cW$aRD'UY7tɚE:}ze-8!TJ(EPIs'Hda)@hHt)S*9ZNZN-3u攑4l`r'PP37m`)N^h)͘2d 6h)/cЄfl9ӘxsYA$_y0~+#o8#IsX OS sްo_7lXyaˑCEhA *i Bag_F01SLF $ 91 ZVFMTe Vh#=ptDaZNͱ UClXFt0 -!x  ?X :0䚋DTC $/g1s!#2̰6s+s\5'ʮjUDBi ߆{Q3ʮkF!q|dg~F T" u38n3*rq 4,B|uYKyD ʹq+HV}ϩg,m:hDh .kN>M,@Aa̓L2lе[05VC~-Ԭč# 81+ylY4Y~ 4Ἑ3'l߀3[uEG s!QgwSQitYfuVg4LcyVFxL<ՅnU-QYo(WZ]!fGi}f~eЗ$<>,`ASaCEixdT%.ha32SL y]r`{!1Q ] saҢ"9X_!t!E4A= !C<]y:*ѕUu]I =D$AGd "VQA++k KWN*]m}\yE²zZ(4Q($eaO(B ,`EyĠ.+h½DǾ[=AD`q ˯h+/fyP0d"TDzɂ 貜aDLĹgM3VO`!gf:$QTKg ;0QT- ++4y%@I<1 1B ڐB=F!\&f QFOeقuaƅlVD.QDG|Y%,(=B^sz(Lguh P:f0W8RXnQ Hdd䱬C_1GKc҅a'Y%ʙgV$Npv >@Fl ̤fJV,*HO7 eemjP'|+BɯCiR P":4 vn@]w-IPB$%B$2LjC愭umOہ<:7һߡ x w䥡UWg%&QѣE$HD;)T+J< "V0""x&AP`'>PȆdq)[dR:|,|`<Ś(I-(RDG,ӂuQGd)jPy̡Ґ(4,/0 _9,WC`p"Hdu ,! v rA AGS5ie-߭=xp%_zMl{yx7'AڠF=E nM؂i?vnNJ F564 Ze ^' 3hH1 (b`X>-%[۸oIFL#,aVֲapXB0Q,Zz㡍c0(7b̰!O] J;;#/Njĝ0 ?,ηccC)oi3y4tP2mT.AWJԳ+Oqܱ=AwaՖ?*gֵ.e ]leܚ2T^X4G,kQEU$tsuT/Go!1* 8b bAbcn,RdouVC>&/Tsok;'WCHBn.z@$l}{ "&|G2IX~䞼O.89x_:}ף;#6].[(r)#o$L<",aPt}芼HFw6,a{ܧt jz choictbl.lst8 /chapter.08@)#(OPA$O " &S ,ŋ3j( Gi$:aذ'̙2 p Hy2*RM1e #MlҸ)J) ȑbi2$P`+QHŦY[ 0XfiB7r@Zh9 d1e1" 2m漍[H9s M&^dȁ90RL~j7CWl LNn:f ;рpjFt7uSm75YAtƋ/d"2aVW+t6GR gkepypw`k V i!bMAFuo]oW"yrr0RiE U&ԈƍБA= m ,iVWQcdBvR[=jRŊ 2SLL'aH*xH! g3exС[rA'k.e`JG2: n!drX* DY',䑫y:skh o11 z2({  oDo},W x`Z F5yуN>`m?P֟ (=̐[o5@0l o])= CĝvF5eXQ1T3JGR$q~s#],0h}dB`9Lާ4 <*Ɂ =סG8$  Pjg;0|A@뗢NmI\ÂP]5/".ri=rC)j,6J?mlI_>͐ [(ER|VD}Ġ̇*~ň4HA}э(ELhcjG%z" iFD氈:Iy]D:,1#8Y2>-Eq, W׫\N1"I1W f2mW%1KUDny>f5ӸLQ5f20 F0qB?@"YEZv2P@]򲙌f3M}"i424ַX SI7dȃC+R RBfSlufyuEJ f}kP~@MDBZ[^b i|UZ )ȫEv <@\e*|-Z':JȀ^k%pYo\/R ".A?c6E"@D(eo㥮2+Q| M{h#Aeu pÝφ˿sgAOgu{r&Hf=ϝ]Omt{]iwe#;7)3i5 ͡MWBQԷܙ2.6 X>kfbý?C m\ x;-jnZzß5j3Uۼ2VD9GҲU-OՏ=px6.7 o; 7 Y ܈ 5J~^GW.-=`n> oɹȁ-C /)rvx!'zsLvS7!u8!*Xŝo|ԓ9Qh?rWuuFV^8î|\ {l[?Gq<׋ТwۢEqhnw/|kd3Wl}t~*yڣ~} /L `sh+ϞS~83W!52Ϸ9P'! a* G'oQR@Q4̈́.AA@6:>Bq(W"A(`X_fca$Am$%C&&Q"&`0A&n`&j&be')*ipBx@,-#$E` 2Bailp{Wc) !5/b (fj)% xURpxqs'@'ࢂA1(21@2&#J3i'uD.S_ٵ]4"ympHG]N03rPX^(RPH+9A=pSRX?TA "NhAQ"D B#b.FI"e('s4zp@dB6[0,1H* 2 $r,&l 1p`s_51L@!gP28$0Ae`aPl 0P%bѨ&H-rP&y%015@ZQ"gY8Ht0;X'⌂1T lZIbQxs ҌWqPA$*Xxr1xAX?Vst@Ē*ayMX61r!iܧ t ŝ <choice_3.lstz /chapter.08@)#(OPA$O )e &S ,ŋ3j( Gi$:aذ'̙2 p HyH)E@A&͘2 QI :e!bhѣ1Z5ZFV\gPDPGSجxb-U\:f 6eM9eZC7 Z&닭G>F[F,˘ㅌ3*`;Qn3 J.409fo߿V `\vf1WaȔM:.xҴn7g^'F U* i怘Ql9a@3gehm1l bp 7r!S 1[|>WiPealtDydPPہtf.ܑ8Ƅ.&p8L5*e&ÑVECHC x`2`94`Y6[ߏSV. o@Ǖonfo~)xdŸxx5(bY L 9(JْHP 2=p[uٚy5T=0QTª$0A,$k@uv)WYjQ&hp0g1@DV0EB(,De28( *뭹u1¹⪫U 1Ў+r;) .W2Rov[ķJoFF.;p{pƕmlpfbg^7C^ sz{Qb],.#} sG|?ꔄA z2XF"I)pUKqu[+M]1M7ڛTn?I CU0NE6H"2҈.8 A!wC.k9)f73hS:[x㡏>i@>q{yo{ ?^9ၚ@iQ2%*B"PBEL1^~ni|G)DJX@% 7]ʑeI(C 1&4Jn!4iiDjĚP6MDQ24&yM''Y+J&,'3;"Ƭ 8 UkI Rf@4tM@O`%I@ܧ>s t choice_2.lstd /chapter.08@)#(OPA$O )E &S ,ŋ3j( Gi$:aذ'̙2 p HyH)E@A&͘2 QI :e!bhѣ1Z5ZFU+A%5͊'΂HPcրlʘ͛:sʴS7n@ {LVrs ֣&@2f6y +.L9iΠ`†_.y3nH>7 2GQO6u-]ŧJ%"3n #'r,csYZ$f9e]ށ FcFI0^y畑}tPH:T4y.QFlev ta BaaOA01c.XYG9dd^n0,0kDI] Va_?$xx bBkbUƘTY& jMQE !Q7樖zVD Fc8`e"D؃ [^0CId8X:]TCQ( ʨE6QiD,F* t膪Pd4؀,у 1j*`-uS! jzZMFPA 钰PлRRB&7dVRuLIXUOaU VpNF )P$.C a21$nƍyS' ?NBy1ϓ1 iL. 8UĬ6SNH(`TS)j6k3ղ*mh|GS ^ј=4Q(Tzg:'c2oOBD`lcts15 SzN;趫 :庸;t矇o KJ-*HC[}SGؽl߫%X|xP ꘗi?( p X< ay^"}@ÂKw<I@Fj9B$1kwԓ_dV&MSVRœ`O/^ +8C φ2! A1A,B EX**LlZ`xZ=Qm\T2cz#ă2#P 2: M)L SxG ꑏÃdE9qAɂEQ#$0#dcS^DAYH&+{T%AHIJK ?qMӖjN&ܧt ,q.wwrapword.lst /chapter.09@)#(OPA)A\y" &S ,ŋ3j( Gi$:aذ'̙2 r Hy2*R#' /w!b6uڸa&2,!C :e!ffA$"t@KDMFuc2&R3NJ⍙[@&L1`I`sa捛rVv+ 䔙ױܰyG Q*9eM˄g& M8hLf6$XI{I&B;AVz)IDwx Udh `B Ldo~THтu!a}],ЂuB bKaXaFD7]>VS~AE^MU\)쀞TpX,GLe^M$AUYba #dNydb{uUOF9ex>jWE[v,sUk9'x=[ !JMPpJ]TQI-I'eUda%L**¤$ Z脕hZW&~RF RfY}qr=W]x1ST8KŚN#yEwsޟe鄝H$E@ ,Л\PTM06ܧB[t +rCtextfont.lstn; /chapter.09@)#(OPA"Xyℊ &S ,ŋ3j( Gi$:aذ'̙2 r Hy2*RS3oM:6+ B A C'%IaXHl90qdjg C6HW9i'16$S^լnIJ1e1=ٔ+!McLC& tм˦kRfk)Ղku,'Yy$LaAJ_E\SfI8QD QsaavA|'W~:@DF,Im wB%24`UJgMypuŁ.e3Q9ţ1"VG)wh}re{Qd '* )LA_9 p\rUvYS5%X`% 1SL邆s -( ~jT%aI4 |˨)CMOVƮ FbRH)E@yS8rҸN:հEIHl PILf#Ŏ " bQC;\8D[?y 3&?\ YԸ]sW ӉͬZ6ܧt *ݔscrl_txt.lst /chapter.09@)#(OPAĔ!R| &S ,ŋ3j( Gi$:aذ'̙2 r Hy2*R3F6l)MI";)lV<@* =T:$@qB< ޘq' :h蚠/*E@1͛7x1ƤXHNV['XN1K@S&4tZ&uԉA)c&L6QFŻqH#vZ1eԑΜ2I3'60yqh2eؚya&Ӵy 1I&2:Tih@!T4Fg.u&VNE7]>2|V_Mq^zqGp8"_H{e܇Lm%M`x iTkLCUK!CU2teF$0CWI€]]U4erB1P=PӌH=-U晁& 6F1lIY=-9cNeW@.O1V *,_vEHDUxpGU{imF 0QIgוO`«SJ+] DP,’z1ӳ3uuV ULQbJĮƫkYlq?tGDB$(@) B= / bk[тuab]Au$zF_( sP2pYE0EC 7G :sA;كN>Tat2,O`)EAśF̙j`b'Ѳ/<5}SdC19ՓTDjuUV>䕟 HKmT|cWPTjU8%=uMAQ61ܧt *Mscreen2.lstx% /chapter.09@)#(OPAĔ!Rq")TAŋ3^ #FhM0lXL9Zh(R )BJBs)Sƍ/iܤ;eBD PDݸQEСE](&fA$D7sd̘7u"IF lޜI3ެ Pӗ s~*lڵjTT)p!ܘ梀ޅG:oZxqE?Kl+D7u@ԙg'Tti&7\n6%=yS/i;&r =A9.Qf rppRh$cVS`UQWg4\!7~Q PĄNA0-Bae>RwW^uL\WD l$Ui!, 5Ԑ}Da5 H0E!Vta 16liV\ۉ)Ѣy| XSP LXB ,:')$^w5FPEiiOEEB4qɕWvV q€*Eu"BD$aM Q4لN<GqGp4TTY%lWzV#Z8\ ty{'^}`*֋oapeY81Dn aW{seRmMqFA`dLd.A7pI㕧I/-}w̹0aY76WZTZ)|Eُ^U'Ƴ?~kD lRg }\*UqH_UvnE#A W7\Ɯɍ Prɱy_af;Yi+. Bolo BWEX]7G+n؂ʲʔE *,\PTDM45ܧ##X"t )hcharprnt.lst /chapter.09@)#(OPA$A@ℊ &S ,ŋ3j( Gi$:aذ'̙2 r@ )B" Ơ # 9i 6IYyr*2)jV<@*p"U dCC(RyN:h@2$IVah1#F o܀ s9eʸUAE&:P ՍT]TX՚?tR+*Z ܧ%v#t )h^lin_max.lstn /chapter.09@)#(OPA$N4 )TAŋ3^ #FhM0lXL9Zh(R )B" ؤqM<(ܤIS 1MI LSF7fnJAHP7e|uʓ)-挑S ۤoe&5*h*q*iApe:h^ 3NP Ѕ G:eƀ&sBeg\dٌУiԂEm k,E<|Z/+3he<3:l@ r:[, )IF3Ϻ0DŽnz4AXQ KW %kp1ii.Y{0H4G8@uAaK\u!vfZqEG0  OG_l( cXVGM?Q4&՗]ܧ&e%t %flush_ri.lst /chapter.09@)#(OPA&U "% &S ,ŋ3j( Gi$:aذ'̙2 rURN9n@)3lAS棜4gб:&ɄCFG1oظh D1hҥ_FCТ$R%Ȑ"u)U+,L8Kn)VܥKu 6ܧ'o&t %$center.lst /chapter.09@)#(OPAĐ"N* Hŋ-pC#AZ4 N6,@ s -bh@ A SGcʸSFNDСi:$ɄCF1oظh D1PrHHJDS9H+()U+L-m,d<^ӈ* ܧ)r't $=dwrap.lsts /chapter.09@)#(OPA)A`2 "JHE2ܐqHM¸ pœ)"G0('C";rAq'D O ! S3Ϡp@qhTT)Bft-#CKU aR €CGN7g ̛2s@yԓi"LJ[%2q>+i6Doހ`ɪaSFNoЙLs)Skp (L19)F0ANm8od|>7lq)$n_ &U{ETka(FlaWWuz‘$gՆQq-?TDuHHA 2ܐ"!܅pUk[-U[/$gh#:xǏAi+<9!\N9LܧP*i)t $.vert_prt.lst /chapter.09@)#(OPA"R|)TAŋ3V #FhM0lXL9ZĀ@ )B" 씑C 9iA1 :mܰ` :e!&^A$'R j%t(4cP" LBucbjU]| Dg& ҄5DJ1@PyI'(n la'P4_7eVbG$DHdκE18pRKD ~RXUܧx-*t #-font_new.lstQ /chapter.09@)#(OPA'N|qR &S ,ŋ3j( Gi$:aذ'̙2 r Hy2*Rg2m̼qC狛2wP(e"͊'HP!hLZhҥt@(SJiܜ40 3KSZ^̡FNfJ>Ǯ&u);6oSw7B$dPgpGd0 hrFi&@EL1US1Gx`KMY$`*1Y'eȠJHG } ` Xb$8 1(C'`#Lұ dQD$yYgAaLޑflAO`!e' dP (0 _[R "uI0TOT1EKZD)wppd@AA XS ,Đ 6G0*+cZzy(|uamdEAPAVEFoDhB IA .d 1 yy5G 2d9Ñ!RG`1X 2LD 2DQ*Snt魦rQTK~QO %矃q cRۅt'0\kh27SOTL5ݔN= QVGn AB I'QUYmՕd%Raj.gD+9C AH!THBpjΤT;S@ܧ:8t "Nqprntclrs.lst%f /chapter.09@)#(OPA)N a"e &S ,ŋ3j( Gi$:aذ'̙2 r@R )B",qC˘7lșb,Z)# R@ %)ԭ.R%ffA$4&_LѤu02tPG1aƬ9#M{!FL*O3k VS!us0_9 蠁yױ^e\qBč""þ& Nl+p^7LDjeka`V z9)t CFGEtj1ٴ`*$DXId ,' 1B J8}q% _ N`=`!VLQBO0DV1p(0Q6S.M$AD^  #镋i85 Rc# I.†NBi(PaLU DON[YS@ܧ&<;t (/#prtcolrs.lst&/chapter.09/vt52@)#(OPA)Tә Y r4očc?;Y1gͻrN6ܧ=~<t (Mrev.lst/chapter.09/vt52@)#(OPA"V\0Be`A#JHEnȀ8b$H&a Æ8aΔE  $`:u!2r8M9a:'&"F8xHc)VeHB+j], dEs&1ܧ >`=t (printpap.lst/chapter.09/vt52@)#(OPA)IP &S ,ŋ3j( Gi$:aذ'̙2 r!UKab6oa҃ qs&΂S$F甡c(R$RĈ',LP9$Pu$Rʸb1"V B,٣NBBMܧ?e>t 'Cprintink.lstu/chapter.09/vt52@)#(OPA)IPI)TAŋ3V #FhM0lXL9ZĐ@@*@ AS%4nִ͛:r@y`B*@ԼYp d!2tcED1dt]CX)z A")V#b޾(-.c9)ڔbj̀ܧ?h?t '9cl_rscrn.lst/chapter.09/vt52@)#(OPA&_L"ʼn &S ,ŋ3j( Gi$:aذ'̙2 rUdS&s)S 3r޴1n0u:獜pIC'761b S6r CKСEID 2nX!B8 ܧ@V@t 'V*cl_rline.lst/chapter.09/vt52@)#(OPA&_0I⤈ &S ,ŋ3j( Gi$:aذ'̙2 rUdS&cȑS lҸiFΛ6@y#7sIƍM"Eq/Dt)CH!Bƍ+D,a'6ܧBAAt &K clr_lito.lstּ/chapter.09/vt52@)#(OPA&R0IB &S ,ŋ3j( Gi$:aذ'̙2 rUdS&s)S 3r޴9F: ؤq(L~:M2SϤ: 8 N'ǼaMclr_line.lstl/chapter.09/vt52@)#(OPA&R0I⤈ &S ,ŋ3j( Gi$:aذ'̙2 rUdS&lҸ)c&"F81/A@LCH*F"Xu+ DE_N!#V^a'6ܧLQDt 0>star24.lst /chapter.10@)#(OPA*AȠAHHŋe!∑ -qS'  9SD -f4P)O!REJiܤe0rΔxb)UH"Ni 7bLN9- *V#9f7ny#ѾL,l)ԂCΩÆS.oyMD)z/&qjM P! C`2EoA $ 6%2!Vp5 4x4jICam0!S𤑤  N 0`rarBnQkpAȦXE H0dat(_І?ZAlP8PUH4 :0[\`PЄ',A l@@)JRK"4 9HNĘ49 *cP2H$ sa<&p;> `yAޜAXZ}/#CY)6?O{aCĉ 2 šP64 h(:e (VfկMf/0T=x>:ъ|Ҁ,l4H;Cdw|cPWƥ6Ph.D׬+3žخP>g"j hS},p؊ X Vse Q7UfEf:/ګ\\fײ{=L2.iZ&_qP=AԔ =Sw7,k(ϭnm=hRԎYlw(ߔIf2V&%'h*9z{fYTtԌ0cLHFꮴZf ? n̐HR"CP7ZeD`*H!HIP@\6k -5c+,"( J`j8HK2:֢žR4VQQp9 e'U?$$;QkEv BO0F%*UI@ܧ5RLt /@ Sstr24dmp.lst /chapter.10@)#(OPA*Rd  &Aŋ3V #FhM0lXL1`@P<RH)E@#Lu2N9 kR'Lk oO(T$`7xM#C`$D! ECC@AH؃2 B02S~3!7Tx!:wC aʁ ANII(t\M"Jd"C {Z#ijE>Qoq;z /KE)ڹ"L@Rc\a%a1FjrQ$#yJ bRhBc.u( bK(Bf9 ;A@-SRx}a,"1_bg3%ױOd$V '/rȃJR4+|0MV9A0 ip: MFs~K3U3* ~ℚ +XiMܧVRt /g3fx80_dmp.lst /chapter.10@)#(OPA,8`|! &S ,ŋ3j( Gi$:aذ'̙2 bh1 Hy2*R3FN2봁 9oܘfVA$ĔG.aFΛ6 ؼ9fLʡ`DQ biQUՉ]yS;odxݴs%4bQ2YIN9YxA Is PԹ7*1px怙Ć͕r4DeEDDE#ZHW@N`P(Nȸ)$ ܧ3[Vt .?laserdmp.lst> /chapter.10@)#(OPA SH! &S ,ŋ3j( Gi$:aذ'̙2 bh1 Hy2*R3FN2봁% 0r|afN96+ B A =t)3r޴͙4cR7 e ɓ!AX`I"1Ex1R1IN"1Y- 2jRXv6|~1t୼Ρ>D"A`! c|@wqڥ B<'K }ݙY2VBTT!OtMQlEՃ@AQDThdRcYyEE`DIQM(D 1L ES\teN>K- OC$T4/] jg LbXUzstd)De>!Y $LJ;vkg=X;5&)y΃^d NvpOr,͙?=H>*ap~#CB34вX@ N2BX!IYBPp@L !S.:Agɋ7- c٬ /cëռ,aHbCVBUOdDl ncP>gA haythБ72"tQtFLiuK ҆ I`H@-tAU>)ϚPlڦxYY`F)0<_MehJR83-WI_L`1ŐT ,%GWaddyϼ oN0,a %=MtK#jt!2Vl. ?qBM*㕢&ܧksft -jhp_dmp.lst /chapter.10@)#(OPA(_4* Hŋ-pC#AZ4 N6,@ s 0Zh(R )B" 挑S :m|ATM:4' B A -z4)3r޴͙4cNj7`fN9Nx#2s /3'U]3D7ӜA7y4<#b2nNx64SL Lʺ CZ64a츤K8r.Ӗ3qY$Foov9D<.ڄcbb5+n)0:Dp% ,% ޑB AUF<Ua؃Zeo^IdեvI'Zm\VmsGbp !u PP>@"!D1\`" ER!kÓEA@ќtVvYalRTI@tE4AS`1XMDN 0q* 4 C Nd)V٩ J*馝iեV QN ,d[rxoETyBbb%^NVczf2:`ͱm=P!EEZD)Ih.#*Ug:DDD$+8%DC ! (pC ;`2;鱴PJpup O\00y|!iAFOaR(̰KL13tmp坅YRp)OC{m![puf= Gt*adwlE rpTr9a=(LQC|x) rvbTBMT n}wER7V'`q}ıW ߎ{ba&'*#*~+O{斧7qQP%nR CYggW PDOt=r) . P–P,^& a`Ĥ OPڐ +`A,P6=2iGuzw 1V [P-Gga`J  F 1{B( C0-ytu)S4{1d<Ȼ74X1^e*C+/rCJ09A a=}&4q`, C*ֵ@ &2M} |@*%MܧUoikt ,_qdeskjdmp.lst /chapter.10@)#(OPA"S(! &S ,ŋ3j( Gi$:aذ'̙2 bh1 Hy2*R3FN2봁L9kԔc≪ TbJѣI0#MlޜI3&ЯHAy ONŪ7rM4gЀ0: :tҼ1P#!D1p# eKGW †_=eEAAQDm$)Qb?iQX$!GOL HC V4U8ADLh€ , 5* 6:kftjk Zjb4le2Qc0 jo(!0gko8ډ VDyn=P!EEZ-J*I`/^lEv:DEH$qPXG8 bjJ&}[`2b`o\NĜ*DT萲)șGrRl&aNI8!iL 5H1A9 $c(6d;G $1Xo8eOHq^%O0 0dq$E_鱉;.U*Qj)vvDY8R 76I)Gma(ZriJqia j/tgafaN!TђLDڏEE@p7#<( P< sC`¸ 0jTcxYԒȵ΄.6ɉNҟl* 6VfCܧrqot H"writprot.lstJ /chapter.11@)#(OPA)I@ &S ,ŋ3j( Gi$:aذ'̙2 bh!FF8B%' IC8rS 2C!fVA$2tq3)UHc4s֬u6T(DB`ǸHPeZ UZi2Y fr%kZ )07Ɲzt4R#Oz卜5emDĕb9n&}SQGUWgHRV4ia@[TN0Q(::sҸ9'"RJ!#rV&Oa:6e0EBCPPGSvQ 6@E!D0$D1 Y%aD4X(0"& A2B1C jm!jrrYU$ETT!P/cBȰTqcM6WD=neDgdQ^!$E$9Ôv]YC&ޤ'9td\ zS@ܧ-tqt GU)htrckchck.lst /chapter.11@)#(OPA)C A)TAŋ3R #FhM0lXL1bQ#U t4e #'2,!55)lR<@*@ AJв(HR@E nAI3g 4o:}IG1zQYYlS`k8O=t͜f&F0r^y#tqs`"'a1tŭ7 6e̱խLWR<]<:fQ%@ itL,(X` 0@Fu}F hQ k%F?tE=1 4 L`# =ŖYyFG}ᢆ1ROHa WdI;J}C C@"|ktUD$aDWFd=B 1)hF$l%JqZNGYPQAa%BvDXD`z~X 1䀣X`7 pF5UUgdj@ZYpbBU~8$Z!l=)ETT!O!gtϖ+"]ݢ$Zm>tiӜDओM_6ܧwtt G7file_mal.lst /chapter.11@)#(OPA$L|i &S ,ŋ3j( Gi$:aذ'̙2 bh!FF8B%' ̤aS 7aȠJDO@! R)#6eڼɏG :&7nؔ;L NN9n%CFVòHKGnaH:6&WUDlfKtހ0<'a`Œ5{&L7:,ibDJ"()љލȓ+{J)VLg(r%Lnߜ͗2xЙ>ɓ! Aƅ,䡣eRB$Tw_FQDP %aE`DDKT%GV 2rQ-t"*C,X $=A H'Ò)XcuAGpBb LiÐ qr:aml!RĐ` >D9dE=-D&F:W RM6\ 1P_kW^}XeYvYo%'Q ^DXFjefjAVoTT!PQb9fE@$]u1؃}VɱN\Bq*|i۫0-cZ "@+HHPABMߚB ; 7("PE =' 6 " ז'G!F1T C:g3@x2N!I/]]VKµm߲kD[̵b=DA ۸sA{\_  t_!%$THQĊR[ ,؀Vu,8K7WE8q\1DERM7U7ܧ{yt Ew;(textsave.lstF /chapter.11@)#(OPA"XL b &S ,ŋ3j( Gi$:aذ'̙2 bh!cF>@@dH"UA :_愱S4lʐ`4naa%a )nV<@*@LY լsLxcD)C$iQ(Xdͦ;Ө$ھ-HMPSL90 b Yـ7r@(Lza5,Ą&I@$SR&L=@RDY)I bTL8y9E N"Ja^h_CDe ]G "ha|useDUcSA,mU[wo,DdXFQ|"F $=@dEK$owQ$K=$Ey ]i$>peEGBA}S?8ݔU B%'hgF1$QO9\qWz DM _SH&Vm=>$k6FVDOZk,5VYgQeVZ5DnS MBQ7M׳ܧ`~2|t E27.textload.lst /chapter.11@)#(OPA"X0y &S ,ŋ3j( Gi$:aذ'̙2 bh!cF>@@dH"UA :_ؼ C4lʐ`&2sXX "D9r!" 7.^S"͊'ނHP&K?=iT~@dʐ$IB-U`ŒuD%iS mĔj:*V+Ì΢Ia65[t RA[7cʐ#f9Ǡ1y0!3_6\92:*B9~&l/F _n L@Fn# DDN-FeI4 _5VY)\!EaCE(YYF`IHN?[ ZE8Iu0 ! 5~ȂB goU4BS ţ\E@TD Euv^y5gQHuctY0Ƈ\~+HHPA֏,0QcQ؂ND$R ""~J4 CVQQ!E k C{|Hb=YB'7 EEPN\]J{S@ܧ~t Dtext_arr.lsta /chapter.11@)#(OPA"X| "E &S ,ŋ3j( Gi$:aذ'̙2 bh!cF>@@dH"UA :_ȑ&ϗ4nAa!L@"͊'HP#iذ HEC(fiH*#@-3G,قU4JÌ)*g n`B$&?6)C&MraSN7n@h 9 ޘQë&IȓT<f&oH=guױQynk88)tB+%".0,I L׆ʂM9tY,!VF6oy^mtQ lw=tlbQbU$!T=` a]Mwn0GKcVD (P=!T]G@FYDD(_`MVnq0BR1P`jՐE!leN?֕XF(=PDyegPTfVV0A)p) BaXP^Y&r*- ffQ]~`s4$ ""$[oWl|$0e]rGy0ɫι!U>!TgЦK-ڎGu(F0AWdԑAv%ՖSPIÄ+% _[q]沏cV. Jy2*R C͗9e4lʐ`AFN;RYX "Ө.Z%ffA$4ƌWRA&^2iC獜< L~L6dșC W][PJ:u両 Jy2*R #gN/fҰ)&L2(Z-S, AFN;ekҥXC"͊'ނHP)pؤ,LF: "^bJv_ F^KB.݂"r$H"S AzADSf̛s*3h. FDubj֮ao1{)E cд^cL7rӚ@@dH"Ua& 2sCK0rΤq3Ŝ0vʄ`A :$X&,2faQ3m9 R-C"͊'HP*I M9 ! b̛6mʸӂT()3&MJ6y>Aɔ.`Ux$f@\)U>;51rhl 10q`3(|KɏrdaA9 M북pck'eMcQgG%Z^`a LAyPCEh̅ ҅Pel&T.HFY-V.'"&XHL%YXy%anXi%XESQD N 6DM>"]$"” $d1t Ql=`!EAEXH 2 00 ZhL:Z /9fn֟J* `P ^钜b) Np% h1 'C–Z,,˂ ]~揭6Q(i ST! (,$ ]}W ;ƍ11#;¼07?!EP OT%^YCkXXT 6J&Ar7r&:sPĜl60s2ps.L:)mC88}2Pmq1 $ ; PWdq %4DcYiVQGZQIPT%}G}PTMf97ܧ~7t BGfile_sel.lstgc /chapter.11@)#(OPA$L|R &S ,ŋ3j( Gi$:aذ'̙2 bh!CF>@@dH"Ua& 2sC2x`ђdʘ STVH!j 7+H B A Ic9) M9  b̛6mʸӂM70>_)ـdJwӼq3ۂIln9x0!ÄC$AΜ‡/np\.Fc=~=U3v DË:g)C Bߌ|r5BuAnq T 0Fua0iϽtV:TFg}s0 }'""ŵ"rlFx au.FU:1.G"ta~ 0SL xVF4YNEuUUH$ 7lk(Rl鞗=$d$th1%X^%PQ(A(0Q( FȐ C mUmșv&goEVDp TaVZqTEe!' X!YEY,0 1,: -NkNjG!Ѵa#,Р<Y",LY% W]RVRMR}BҥpA/.P%ֱ!a k2W2V VU |Wf9jPl +T. AqMN:&ܧяt Afileread.lst# /chapter.11@)#(OPA$LH) &S ,ŋ3j( Gi$:aذ'̙2 bh!CF>@@dH"U0M/rʄ!Q,̰q R@Y"͊'HPk`:ti7nt=HR$V9 ڄI " mɼ#0̺T{W,ق[[ 9uƌ)3L62 0t@m tc 5biĊ!H@ëKC8 u8R 'SP@Bc &a Es%RDl# Ko1c؊ DfQT-!oV ! R$qT,WyE8ԁ$BND$ŇO "E|afQG"Bk Ido,Ġ"O,,EP}ё~3cz . JHj"'"&XT+E1G8ȣ@J!$ D9`K6)VDg~3U^))Z>YQ| AED(_j)E[q͵>VDOH$U*fXK-ej~=1'ި]w߅7^yW[YJ,%}k/&cC+e\tlblE Aޝi˝wGyEG~f.{ikĢ+BTM37ܧҒt @R/fileload.lst׿ /chapter.11@)#(OPA$L0y &S ,ŋ3j( Gi$:aذ'̙2 bh!CF>@@dH"Ua& 2_ؼ CEѣ$XX "D9r" rJYY dǧeHHb)j@@dH"Ua& 2_Ф!SEѣ$Xa2 +Ax&DO! H| )3!zPRHr@ fQvI#(U{hwlق\έ "sSf:le3a蠉Ru yukƶ^݃-CH!WwaEnccqH"O0 LF c#+6=$F@H_bƌo1񬑿-!oe ! R$qTxE8_$BND$ŅP "pEݶ|DQG"iEH!w <"r Gl@gN8`! B(!Z蛆zbQX.h4ڈ Տ IcUH|7>7ÍN$7%7{2TD|>޵ѩRd0Q`cEM:DSUꮧW_`1E L|Hj pfTuawށ'k>lj*oTFDZ"ک :,a%kƗ+\kuԱ%+D{Tk,r]v}rnF㖛ƹ&kD#PTM%37ܧKt =ռsfilecop2.lst /chapter.11@)#(OPA$L yE &S ,ŋ3j( Gi$:aذ'̙2 bh!#F>@@dH"Ua& 2_Ƽ m)Ŝ7u)C0r^!ffA$Đyy5V V,^n´)3ĝ4tЀPQ:0[&QVىmoI3N7%+&. AtP)+%*MurAD2dʐIfQAEJ6+gYgd¬3b4&ݔ>" AԷiYmy$ipq1cƁb^nawy@Xrsi1SL@,6XWpW,Uab% atXZ-ex%a% =|gEYQ,t^rdƎrUQL`[ !Go]ŇsSƉ}wc%*Zvćf+`GNe܍%iUDbRH4 h j>"FZE@TDG EG A (TY=`QZ\g~5Zc5װ+(dcBNt])I!n]{[eGdX$Q׎/F2YP KmW$Y&nuŪm)d,"P\BҍUyӋ '7j\a* DKjF ©*1CG?/묡Z=ƵNqkуV<,.ܶqE o[" ,BQQcKyG3Ђg$/Fԝ+Rn5\xd[$A41 1$=/y k֧^>{~]g؃F{XBMHUBn3 >n=MRi( z ;t9%dudШ!M :X%I~ރގF/+|hfzMx.XeGl d Txp  EX`@ɆPC2ɇE%449ԏ}xDAzh$^d"V50>AiT72}rlkL(GP)<2թ*ț AqMÖJN&ܧt <Ifilecopy.lstl /chapter.11@)#(OPA$L y% &S ,ŋ3j( Gi$:aذ'̙2 bh!#F>@@dH"Ua& 2_ƼE7vʄ`1M9cʐ`A'tHYY 1diFaV:ozk0mq' 4 s̖CUPv$f~-67s̡3MfȈ?yBDTD""ʢGy\ZA 2dΦ-Ө!zPReﺄ!ȕ[ֹ;+0I7eGmRF;I3G 7Xc(Ƙhh([lQ\n 1$Ɔzq ݕF`ʝDOA0VkW`[nZ FcQYIUCWuёnzeȡo !ZEyVEm)EjPIFՂRL'r8ݍ Ȟi?"lb] I qrqnБl_E)!D3% 1K  kUDE#R$qTՃ!ypnhƗ֐{B֊u5&Ĵ@֕B :MvQNѣ>ElXbU@BKneEmNG0_Җ* •+k()5Z[e!i:Tg0pШ Bfz qc|\zEу~-G.}= ¹BmW*>PE4 )zt]5m3[4یwFkگ /(]oS[څEB9DC BSHNZ~n/&q|@S;:ajKF%p(8W P7@C;!,Q~, EB/= U:K_Q;q;ͧC5~v9*RԘ" PwP&> Sspʥ"P'd9jI oܧBt <&dsk_name.lstH /chapter.11@)#(OPA)K8 Ҥ &S ,ŋ3j( Gi$:aذ'̙2 bh!#F>@@dH"UA&͜5_ܔ&L2(Ic MHq≮ Tb/Ad Qk@qCtjU P"9 D7jZ+ 4lk!ZM:e>1n&6 4[Cg: #,A# TmL9لә"גQ "RH^xy!@ԁ91aKz#GW!WU =LQ(1(t]xQeU )` 块^==H!EV %rbzӊ#qї<oAG EQɑXI8DC1t,@X~1~ s%dأAXjič饂 *bks}Tek%ullGbRf +C~jޠk`5AS` ,0BA(Z]0uGt1moGj ꪭNdEEx 5$jV ¥}jk,~xm'ZeZhf[ƻ,V.Zr_}aczFΑddiV~#yPTM27ܧ4t <_xdiskinfo.lstGk /chapter.11@)#(OPA$S$qb &S ,ŋ3j( Gi$:aذ'̙2 bh!#F>@@dH"UA&͜5_Ҹ19$XX "9iȔÂ0cp d1s,܄iS&j  E0*+oEhI)J>ҟ)K5 OԪvmk_\0(Ji[ * 7bT՛ܧt ;| disk_ibm.lst /chapter.11@)#(OPA$S|I" &S ,ŋ3j( Gi$:aذ'̙2 bh!#F>@@dH"UA&͜5_҈i4vʐ`a%oքHq≮ Tb7Q!jt i}Dr@I 0FN0t-EΛ1eԑ2n`ڃ*CӘ1s昩FDM d 2xCGsһʙ󂎜0c֬7 8F < ܼYę7o>!S_c78lZlMLy&n[54Xa%W1dQAm%eDOA0uaF%Teb sapBSVN0P H" 5 X'FCS BP@Q$4ET)Ђ 5B \(ڵR $LBU}VXe D@ 2A(G1WlGb[pQEu7&Ձq[0UQtؙE(+@C^f槻5w\rJZ /~C'. 83.*zcׄk`F bAL(dmoJh.pĉDEuޙy9 yS(Xۥ+\B4> [_YB@.qUicC4 z.2\C@¸ִ.ee͘$'5PS(pUdf5;ZҘf,3UWܧɶlt ;!^A ]disknumb.lstN /chapter.11@)#(OPA$S8D &S ,ŋ3j( Gi$:aذ'̙2 bh!#F>@@dH"UA&͜5_NSF 2r)C R@Y"͊'HP!hL1i-2 Qk@qC4T P"B+]BDxUvY(rވ #Mnę7o>!Sst,zTI4i1MtT"1Ǭ)Cfq߸9N[aƗGmlF߃)@c4$hp̱yLަώ81~=yo)0t؋Op *UEc{M`I ,OsL'8b+8AhSQ{v<@@dH*R0FΘ2_ڔ!&4(Ic 7+ B A `:gM9wf9oImsd&DLYy' 4CI b7y)^ V p[r%SGLrNDQBؚaf:b`: ܔ<'a): XRI"0dVe|A8oY1\x;1 re3T˔$ND$ "!,TEHABTYVY$U~%0EBC@U,PC U0 V =UE~L' 4 L谣 :paU%PxDT"i$E87EPNܔW\jyS@ܧ t 9Zsteprate.lst\ /chapter.11@)#(OPA*EH  Hŋ'pC#AZ4 N6,@ s 1ZȨ@@*@H)C7 )GN ޘAFN;.$RĈ'Abth"PY4`y ۚܧ]t 9pfilepath.lstC /chapter.11@)#(OPA$L@ B &S ,ŋ3j( Gi$:aذ'̙2 bh!F ! :rܰ C w}S3iؔqM+˸8 : Ҥ."n)bĈQ|iY RIxː`!%R,m7s|3 ܧ Yt 8Bfilename.lst[ /chapter.11@)#(OPA$L8 Ҥ &S ,ŋ3j( Gi$:aذ'̙2 bh!F ! :r܀0M7aDq' 4oaie\qB$ELq2D1dh2_*%Q)zHIr vː`Iݷx[uQ,Dp"͜/ ܧ\t 8|"file_len.lst /chapter.11@)#(OPA$L|I)TAŋ3R #FhM0lXL1bA#U fҰ)e3tР:D O@! RЩ#F PeH@DnNǧ NZ7cʐZFEo Kˆ%f6]\$N " HbaA-"q\=AED(g#:`' Q}o0@ ]0YReSQE1餆QRɧ(LbL0g^X bT}g\؂.Ȓ :!WI1t\U$ETT!PjUQnX He7eN;W*|S@ܧt 7sectload.lstQ /chapter.11@)#(OPAĔ"C0y &S ,ŋ3j( Gi$:aذ'̙2 bh!FF8IdY3:o|a& d䤱SEѣISܬxb+U`cB״T4n@$qdnl 2tq3Өe~c:f̔ql7t@0uZV\N EΛ1Q3r´RO:|.cȒ`aKmHXun]'EGF ^!4X`DYİj-S˜g ^U]"`E[a1E}BDRBfrB%U X8B5b+P~݇|phUcy@0aDnqK%B Wt0tUG|"Le C PV$ETT!OfQ&@n6&E8AD^yo9vɕ*P(9tS_amzS@ܧ.t 7Kdiskname.lst /chapter.11@)#(OPA$S8 Ҥ &S ,ŋ3j( Gi$:aذ'̙2 bh!FF8B%' Ȥ招0mʐ@AFN;JSܬxb*URN9n@AhRò@1P ҸI)TV*:Q+9oƔ!󵌎ߜKM ,:v,# F!(](A]7UF+Ah^x cN9AA-Ӣ4p C'7W|Y2.hp ac -iaTm:ڷs_edH&,i!eW͏ﱚĊRH=POj# AED(QDDL H0 L'^ ,Pa ,PERAEREYWQWU! ҉%:A7!cN;ݤV:ܧW^t 5kwverify.lsti /chapter.11@)#(OPA)VHIb$ &S ,ŋ3j( Gi$:aذ'̙2 bh!cF>@@dH"UqGN:e)cLsBYU A7"ai ހ}#'3W"f٦y@Ab`y6e/2jOAGN9<64UzC\8ʓ%CM E !kګE  ԫ[À-{ݳyUP" o MZ_ܧt 52Z textshow.lstm /chapter.11@)#(OPA"XLA &S ,ŋ3j( Gi$:aذ'̙2 bh!cF>@@dH"UA :_ys4tؔ!J) ȑ& )Rܬxb,UQt@qukׯ)@;g2e袐e NTKԬY,d1eԅ)0q頁I h a&0i؄syM tt+p{dIYw w_ߋgTHQErߜPD wX_uZhL-YE@[tn Fr\DFm=C)G\!i7?Y=[,Whq]o!pPb24 a@\2+Grí\ "f!B`$0Nc 2A&$q `MޔId*蠂:P`(X KxhY '1`}&!i''H$o U D& NT )S2 U``dp)Xˤ#:@9D!,9"4 Qx!=d"&Q@l<`ˈDVAC+""٥0y=4/,#L{E0@G:n8CE7tR`>Q QD(  5u&~5x&OMq(5l 짜% h ̲4,{J!$ S@A hpF3 }^ 6h%eɑ`3jMVEiL o+=T 4AR_"TY=Ѹ*LGߠ#+ 8!zȹ`jVѰ«Qa\ "5.9`_Cb#X"h!Mx@XQn|p3BpH;͋`Wx6KHdA*|EuV!,<DZdpE \6hvo[|z}oL˸$πy,mYhNtdŀ R ܌uU_ e3Bl_ (8`,H f;A>l b!0|guȹW0 ,0P.j\Ax(p0Yг%܉9a&0W]q9^llU@S4#'eCLi?A痶^D~ 0hpM bH s$,]N\9Rf*'wZ]1rO}Iv{ұһE;b_5^ټ`JP: +5ɇd֛ ]^;i6+bl t˞m٭hCv_yρk_Ct mjR>0\ hit׿5zVµ '[|8kdpcpUo1orhsgPD{3·)iv:zIz"sQ`>KLJa}fe*]5r&.%BGtcu@h)x_J?DWhH6MȂyUR*B“aRd"<?&A8oinhXIXZX\SH_va5Zo^Hqȏu8Z ZuUd5ZST1FObcTH1$t(UAգEE`DD[v\9QhD~ŨA\FZ.1)EC0QeLZ41W1=`թniSPTM٥+6ܧB@t 4T4 format.lst_ /chapter.11@)#(OPA'R* Hŋ+pC#AZ4 N6,@ s 1ZȀ@P<RH)E@I3g3o C9i!͜4daAGN1k΁CP9bᘩTVHaFN2%RԜxb/ULPk@q#TA@$!SSA!"r8 W߈,>æL BӺլlV_–Qt`NS&3 ~ kY:9&R3$6y@RL8b!9oTsv N)3N9*5W`Y6BAaAv@ir9]ntV1b_RQh%(  s8Q~+`h AZ2PL FVCX\m[$w1RJ1%tfژeT gA4QM&IL 0 >oQuVn`hXЅ!4`.thAF:i.EGVeKb*o0[b(uW^;@c*'anTd7kj:B( RxBQDFBiHDl,v'Fj!;VGVOEUbZRiQ vx ґaFs[ U+/̲rsZA_I8DA|[%,UAL1 U@ERp$B 6\IQKAfcSƳZ ݵW@R (1@OSxUع]V*rqN,DTƸfvaK + \45f*u0V>\ԩTܦNCSXЊV1CHGZࠥXJgn y= |$3QⱘrpMЀ2njldsEӆ!"Mm*@A G3R *˂V , N b|>$emv8%7j|3CK f@ oV@cGT*^rZSӝ?Ot`E j=pƶU\gԦV¤jլ"IiuEhۗ*w)k8+R$n-C C %OF \M*؁%0 `1%( /= `ϼNɐe&Yd%I{ue)q3( lv7_qc*(Tjb5 ܧ;t 3filearch.lstĬ /chapter.11@)#(OPA$L2 &S ,ŋ3j( Gi$:aذ'̙2 bh!#F>@@dH"Ua& 2_Eѣ$Xa2 + AY"͊'HP)eP42-ĤQ Q0R=)U*ĘJ.E\z QXDsSf:l.e3a蠉Rv ȹvk֞i+J!WaEpbsqH"O0 LFs b5Ov=$F=ŌbU["LdxPrQXY|+HHPqQ%SxB : Bł\s "jF !DB + BpЁPDe =GÏXN)ȠF8afa!#xbǭ\Ì5ޘ= .bI~] < @:AĕUqf_Y)0) 5 ѫX[o5sÏMUľ*ae$6MڃC0⪭2[Qoyx䙇z~d: )RRYc>ʬEɚZ{BGVNwWyI'f g?ܨ EEPN܄YY4|S@ܧt 3drvspeed.lst| /chapter.11@)#(OPA)V@)R &S ,ŋ3j( Gi$:aذ'̙2 bh!#F>@@dH*R #'2_)S FːHq≪ TJ9t=B)ӏ(x#:@Ab`΀8mj-(ݰiȥ{ 4)#N 1oʤg& ڐ`ԣ%Xc t~یج2%zL"$!(@Y(ӱRS`aF-G_!=lΊ5QK yZQtLʄ B 9T+ lUQrox4 " =V tQcpb&ex}Vh,hKGI8DBk, DI<1 1Аt6{مvcLF[,ٙd\ƚkrhǔU^ L`$ iХfp lgbUeA[ƖlUZ[T$Č^cVqUNږIvALa@ңK5aP A9,sRi% w'~^,tƩZQn#$(;G *,׺/{[ t& 1aNt E8BKTjh|]-7ho!W pD͡Q%UĀ) {c-%kE2Ӎ>QxE@TxV !mmŇPP@@dH"U FN1tɃ%4$XX "4lʐ@WIq≲ T)XZf\V߰!SF;i #)Ti܀CGN3-ȑ&ZjE zp LnưC͙OA[Լs Т~zy"[ڜY=i2dZi"<3<84A@Frs^ "")o,ѡE&] ⍙SdzqADM<{B.c1G|Lfŗ1DuE`h@S F^텱LcX0C !l`e-$cAFFP!T_X*P=ba}aB#}OFx@a b h-G9dE![m(S&és}ٕEFpćFv+ZC0QẂVFD?\ )`!ESfdA[AMgKE[d tmnu:DNX[y@ h!O0Q( AA )2ؐmEl0p'Cl߆֣NڃGATZ~Q1mitJIA1q_hAԸ&M \DLX˪_>|VEr eFfk~gV_3Z;7y=VX|32,^%sFŘ9vFb)!=i+A9qSN;SP}qMgA[C%GCe_G&gioZr%eiK}1FJcCymTSB~WUABpyFbQ& huF " D@,hɠEU T6`H0iڈ=@.`OU j#[@I~2r;a - MvPO!.R!!! m1k)ŋ .j 5n&VdsـEaP#X<3:%2q{DKYpDD [Q"'NI=U٫ď|4 OOCVD|= "lE P%:#pj.t|FͲ% v_̃¡A1,_X6Eozl f*lEc1e>ebt;'P@K[Q͎_|:)$ yO2t`` D=E" `N ((3HcN ğF1"JRTbJ g4K^ؔAubu3a3\RuVfG/ L!)N> zhZ:wN4*_F}OIod( j1)ЇFTLGE:=,JSR ec߈z뎮UlFיA NOMFW'>Pt QJU0شdi[9/cNJw[ ;6-^gȰ'1=N5'sPXЄ*}̮ L,1hanDp*% V<"߸Zh{#K-Jt Zrܧt 2.dir_fold.lst /chapter.11@)#(OPA$Ry„ &S ,ŋ3j( Gi$:aذ'̙2 bh!F>@@dH"UA&/fް!SF-! :TBԨK!" 6a7+ B A: n瀸F*0NU:eIƍ$@V3-ȑ&])ò ڿmj, :rܔ8MI L4SF, " 9%oC7I@QT۰NɦHÇMH 2ehGWNd]5ѕ{ŇB9Q ^mlh 0``"_d^R!0wId)FB =tUDuS "+@@dH"UA&/fҰ)3EK:hH(T+A5"9$P`&:]Iq≶ T)ـĝ4PY 4*^ )fN7nW%"Mr,iF0y-H LdxcTeU[y9eԑG bkB4\&=0bNc C'0dh^$F &iEQ9iM .d陮[A#pV 9F!wnaRL00W!^d]Pa(~IaFB =pUtQ "+(F#; >\I\Yv=qDTAEbu`aN,Fxb`RrƗLv|5$~egC ]^] +CYPPKIGNbj VՆe, ^lQN QْJ`~AcF%bEilNPtgpMBQ76׸ܧt 1~3Vatr_writ.lsti /chapter.11@)#(OPAD*R\ &S ,ŋ3j( Gi$:aذ'̙2 bh!F>@@dH"U9_IC 3iؔ!BN0d\q&OhҐ!S9y4m51aj%oքHq≾ TҦ JmQh1u"IΛQG桖A̩3fL9fWAE&=0aY ՖtД`Xm7i)CCH!_ۼaEt >VjpEB8 aUVe=_w HZe ~ a\i x=aB )!xawDM( 3y qx`=0 &׃fDh-!o& ! YG> )ITT)Xɭ nAGbo V5, r4H` \94tI—a[gfo9g{:}Szh裑NjFf' xJՔj*58 BQ7 6ؼ*{S@ܧ5Et 1 !atr_read.lst /chapter.11@)#(OPAD*RH) &S ,ŋ3j( Gi$:aذ'̙2 bh!F>@@dH"UC/rʄ!L6eHD 7kBHT+4d3G+0by&,0rƠ fvA$2tq340ײaN7g@8ڂ4b)S8Y{ RDG޽/r%6yV~%Ccln2lP f7aڔIRqm9C=x4vʜˤg&,pEo#uM{Lb)$P"=X|$ez=QDD<1 & A ,01x~yaB"ATD^I1Tz0 yU^"LԗOBrA|+HHP|R1QMHB -DDR4 T"p!B ]"{+o!ux$B))DB , {P xQ)@/ȗNݘ|cCy.ieTPJIXj%$dVdgE&qJExgEKQb^C0aj^%Yf[nY7&X>8AN1zԪx諠}8ڈ * ]bDhRF!ZkfkC&nEK/ƾ{R.,@E,՛nj W Q r{ l4|f[0|QX<45lJWT(Ff? Q7mܧt 0 accesory.lst/ /chapter.11@)#(OPAD!CLy"% &S ,ŋ3j( Gi$:aذ'̙2 bh!F>@@$!*R3fL9sɃ !Rܬxb*UC'0t`5Ti >=)Ub /A͜4o܀pq 4n|pU!kءE&svNZP{(]01ÉDU攑S͛7=l-4r94lU YG74x-#87p(SM:y@(\e9yrHGcV1SL  ,!f@WR ` aUF[QyeU`"`!C=3*PQ 1W*E$ܘE&  ZE4 X ,  FGE`D ("R$qTԝ)Ux[pq=piDNEBND$E)JA4!T4fce`O<Ň!*ZF4r#RXmQGXa||FvGfA\J! ,p ifqN,:ZT=@cE~`!DOL 8L@QDK@CxGrpNYeRRiMAQ7A!ܧlt PHxmidircrd.lst3 /chapter.12@)#(OPAD$DH" &S ,ŋ3j( Gi$:aذ'̙2 bh! Hy2*RhL/rʌy# +A`fb)SQX"עi\Iӆk6+ B A (e mI3F7o [[#'Lk2vxK9)[kh@Lgq` ЄSL26=2S& C&O  BF  a14g'%.$Ԫt |}qR:uհ[Kt/jI-pC FXtiБr1pQ_it1SLGGWbaeA it! q{|XuFWm colAdaDLtUZ0 BJAH*Zle TDU%(,Xo]9$) cb-6[Ӆ!cS N=`pWS!L!D3xub ,0! kеGDB$(@ 1eC }Fjc:koLFF !X"]͒hbI8AD붽lb"JKW=%@EMXJWPPtUYK p{ZZ/[ s4$|QaNQ(,Ff6b =(EfR=P|N ~[T 9Uv%T.QD$pyf)IG#@1ZmrhF䍘U`ʂ H =$2dEpMxo]J6Ew>v܎ύD DXH$9Xc)gYB)s!^KFzYߘ`B u7|t^:7ٴ|›ql'e(A]ʝcw>@PTM?6 ܧ bt Jmidiplay.lstW /chapter.12@)#(OPAD$D@a$ &S ,ŋ3j( Gi$:aذ'̙2 bh! Hy2*RhL/p؄ɃB:.S +A -&2|P`AԨ :iTfnA$"eDWylD OT^hN_g kjjBx坷 1€n ĸnJK- 6(ig/;4|Qn +/ ,8 E`!@9a\t6ܧ{ O t J,midi_all.lst6 /chapter.12@)#(OPAD$D| „ &S ,ŋ3j( Gi$:aذ'̙2 bh! Hy2*RhL/o̘͊'HP)wD;e䡃&3 IDS\M)fԨ *2.ty"/`6=`$f T8 $B`fJc n)3'R $SY3g,l`!z49u cֵزATytYདt7d C'͛jOVNaPHV Ĕh\"X$ (NDUU Mܧ  t Js"midi_off.lst /chapter.12@)#(OPAD$D|ybĈ &S ,ŋ3j( Gi$:aذ'̙2 bh! Hy2*RhL/o̘A1I7eؤYU 1N:MASFN:hҸ9"n@M3DӧQA" ^}RE &BON@BaCH7tu;0É7J2^6hĜ:sQViiÈ3v)*ި2u؄M\ҁAp֮S\f8_Ê)㱷Aub3* ܧ= t Imidi_mon.lst i /chapter.12@)#(OPAD$D|iĉ &S ,ŋ3j( Gi$:aذ'̙2 bh! Hy2*RhL/m޸ICO@! SҴfiZ$]S d( kXC t˼ES[1icL9oהv nʰ:.SIŌSŬ3 ς,"q沈 l؀< Q7g mQ|PS2jHNܫa#'pݏJA b9eʸ#bjW@qSZ2ٴ|S8)[EH!Q ,"LAGr!\]AXyQSheQn `ESo1K0SDI<1 1а` ,ؐB=ѓbydGafU$Ɨ]PD P TIxYaS T:)AA$ ) e! *hA*k+EATm駪]N,QD$jQFp&?x6Fìz>DGKEM%  fԧC9x&T^J}$Fwt\qsTkQN$dAòJS!QqE$Eg޺K$eH*e@:Aq]|Xl~@i hAʂΐk/6j&֩=`R\eC q0 ,I/CӥZ|jKDd9AYI.6OYYn)GcfN$c;4 P7q&A|S+j6EPNTU MܧEt I~[1midi_buf.lstD /chapter.12@)#(OPAD$D|Rň &S ,ŋ3j( Gi$:aذ'̙2 bh! Hy2*RhL/b1SF7eN9%XX "6d\!#D O! CИ| bN=0ߘ1X4MK@A0uЉ)VUv[)eԑXWxFN3iܤ|Kڶ1ϡS:iԪٰN:hry3 0Eں9Wyc}2H6oĤQQ]A19Z&<0aIZ8K"$ɓ)(@ 2'[XcPQ(WV UBo^Sk%P}WAvU -@ùO,!Ym%THyiHz00cE~U$R5ui(ldrm [ڲMqUALalKg4d A.r0yE* [ܧ:t Oämodulatn.lst/chapter.12/midi_com@)#(OPAD'D0 Bʼn &S ,ŋ3j( Gi$:aذ'̙2 bh! Hy2HB)E@IC&͗6oaN7nPAcMH2u 5͊OH!0V)lR"ҦOJ'6L8̀ܧt OAvolume.lst!w/chapter.12/midi_com@)#(OPA'L4)* Hŋ-pC#AZ4 N6,@ s 2Zh(R )B" ڤ!拝7l)b nʠRH ڤ!˚2ySfΜ:LQAcMn)biӧLSج,L cžR&[2u MT~:)Ämܧt LPhold.lstp/chapter.12/midi_com@)#(OPA'L`2 "JHE2ܐqHM¸ pœ)"2('C"6iȤ 2(Ơ馌9wQ"̈LpaQ>WA$1Ta#z%ça0,Q=`uBdl'U`a+lLMS6)Xؠb-X=t"S Ϡ; ܧt Ldata.lst/chapter.12/midi_com@)#(OPA T`2 "JHE2ܐqHM¸ pœ)"2('C"6iȤB& 0(Ơ馌ɢGSȌ,L cMIi& ,ٓ O'2K7̀ܧ t KFcontrol.lst,/chapter.12/midi_com@)#(OPAĐ'NHy)TAŋ3Z #FhM0lXL1d@P)B" ڤ!˘7ny4%ݔIi2rXAYLT8 $B`)T7R٤`Q V\Iŧ  f@ܧp! t K)ch_press.lst/chapter.12/midi_com@)#(OPA$_H)2e &S ,ŋ3j( Gi$:aذ'̙2 bh! >RH ڤ!4&ݔa2syhҥ,B4͊OH"0V(YlRd}uj tbS ܧ7#!t Q3tbaud.lst[n /chapter.13@)#(OPA U`2 "JHE2ܐqHM¸ pœ)"ƌ2('C"1aA!' 2%RȌxb)UFʟA=괩LpaL S0)2VNI2 0FcGޯSa޲%zĈ+ \3 7 teЈ̹/ >عG -!of[8`X=9qع%#V<5fWrc};.axo Cxf#'S@SL ?ˌyӦ̜wa%ToAz^|w_~dA`NiՖS~`!D B .b1*@OTLPE <ܧr$#t Ramouse.lst /chapter.14@)#(OPAD'Uqd AHHŋe!∑ -qS'  9SD -l4P)O!REJmԙSŜ;iA"L'HP"iæQJذH o3N;ax"Ytд :Ԩ $&1hҥ!JD #S ۸{]{&L7RU 11 KLL֭]jn) aa'"gLU8>3 ܧ($t Rmousinit.lstX /chapter.14@)#(OPAD'U$q &S ,ŋ3j( Gi$:aذ'̙2 bha Hy2*RhΜ2_ҸICK VHZh )lV<@*@ S& a@)s2-ԑ3a怘CG3n`1t1 ۸s޽D9P㣃lќrތ)Cf.&U*eE3vc2+0aҨUv}`/cȚM۸hA#> Y9n\|.+Х'bլ׹^oI{x:EDQ 0]mC =`] F\oQFsIri6|A 3By!g1KiQ J0IHa,bb0d C \vɥ0t"2f1h)efkoƉ%u^7xzlv4(d*eg::rZ it(fe樣7^ >NQIUY*g K})zJ[ fjfF[m^;Ӧ KvYЦ+-)> j*k-nkSPTM`N:P=]YTCae] _rԁo-mfԲ-Ts <e( <0]tL$4 ZWmCDR,t (@)ld 7p]d|]PAAFKc8UIv7 C =4D`Q6ڔWr|t)ᆷW 38(1yh_wL~x5ㇿ!gz z G3: 9 O{{nW򩻽: ]Z=I1ِk{ -piEt۽7]U9 2HOzTL@L`~X{sC@0|] Z0\~EoBsy4?P4xؕ6P- +Bä0D ,`Mܧ%+)t Qmous_act.lsty~ /chapter.14@)#(OPAD'U| 2 &S ,ŋ3j( Gi$:aذ'̙2 bha Hy2*RhΜ2_Œs輁 R@aŚ6+ B A ICD7Lٸ=*g;e5 M]8F{:t!k2tqM;˴fۦM~N_3 'vx"$N у*B)͘2d$LM3m /S(D:&^po}6-[4  Q ̰I3f sqsƮt7+UW~4ƅGGi!GtwVms !l$VchEo7^)FVm\ E<V1pYS MuPBBdMAVPPdUtYrYU8AEKjɃxDV\ΙYyY$I Uedy=QhE\@dFPeLZEmg Dw)EMAQ65v֮ܧY-x+t S騝joystck1.lsto /chapter.15@)#(OPA'YP$ & Aŋ3V #FhM0lXL1j@*NPI 5o̡f̚/1jR<@*@H)C7s@ S53?-D7 Cfӧ3%i׶ĘZaBKeȼu lebF3_qD mLG9czM<I<.S)PCDB4 3А 6ЗFZlsyd_M%aBP BdAE{LQ(~%}E^Qtr0BIQFgb\S MQ$ETT!O3P%b\ bA5UD)`ѕYnI,` }|icf1ZeAN!bME4zSN5U5ܧ.-t S%Kjoystick.lsti /chapter.15@)#(OPA'YPI2d & Aŋ3V #FhM0lXL1j@*N,|7yI3f 8oIQ≦ TBJ:u丙Bh\ߘ T(5 P@IJ Ia2UT"'nQgN1l^1C .͛/p%S& u"o;i: FN1C߸If2zL1/ik6dѣǀ!ԧtA$1$GMQcMSP)J)B3 0), this register should contain the additional width of a display line minus one data fetch (in low resolution one data fetch would be four words, one word for monochrome, etc). 3) VBASELO - This register contains the low-order byte of the video display base address. It can be altered at any time and will not affect the display until the next vertical blank interrupt. The following registers have been changed on the STE to allow greater control over the display: 1) VIDEO ADDRESS COUNTER - Now read/write. Allows update of the video refresh address during the frame. The effect is immediate, therefore it should be reloaded carefully (or during blanking) to provide reliable results. 2) COLOUR PALETTE - A fourth bit of resolution is added to each colour. Note that the least significant bit is added above the old most significant bit to retain compatible with the ST. These registers, when used in combination, can provide several video effects. In this document we will discuss only fine-scrolling and split-scrolling displays. FINE SCROLLING: Many games use horizontal and vertical scrolling techniques to provide virtual playfields which are larger than a single screen. We will first discuss vertical scrolling (line-wise), then horizontal scrolling (pixel-wise) and finally the example program "neowall.s" which combines both. VERTICAL SCROLLING: To scroll line-wise, we simply alter the video display address by one line each time we wish to scroll one line. This is done at vertical blank interrupt time by writing to the three eight-bit video display address registers to define a twenty-four bit pointer to memory. Naturally, additional data must be available to be displayed. We might imagine this as a tall, skinny screen which we are opening onto for the user. The video display address registers define where this window will start. HORIZONTAL SCROLLING: To scroll horizontally we might also adjust the video display address. If that was all we did, we would find that the screen would jump sideways in sixteen pixel increments. To achieve smooth pixel-wise scrolling we must use the HSCROLL register to select where within each sixteen pixel block we wish to start displaying data to the screen. Finally, we must adjust the LINEWID register to reflect both the fact that each line of video data is wider than a single display line and any display processor fetch incurred by a non-zero value of HSCROLL. All this is done at vertical blank interrupt time. Naturally, additional data must be available to be displayed. We might imagine this is an extremely wide screen which we are opening a window onto for the user. These registers define where this window will start. FOR EXAMPLE: The program "neowall.s" reads in nine NEOchrome picture files, organizes them into a three by three grid and allows the user to scroll both horizontally and vertically over the images. The heart of this program (the only interesting thing about it actually) is the vertical blank interrupt server. This routine first determines the pixel offset and loads it into HSCROLL. The LINEWID register is now set to indicate that each virtual line is three times longer than the actual display width. If we are now actively scrolling, this amount is reduced to reflect the additional four-plane data fetch which will be caused by the scrolling. Finally the video display address is computed to designate a window onto the grid of pictures. This twenty-four-bit address determines where the upper left corner of the displayed region begins in memory. Thus, every frame an arbitrary portion of the total image is selected for display. The speed and resolution of this scrolling technique is limited only by the dexterity of the user. SPLIT SCREEN: In many applications it is desirable to subdivide the screen into several independent regions. On the STE you may reload some video registers on a line-by-line basis (using horizontal blanking interrupts) to split the screen vertically into multiple independent regions. A single screen no longer need be a contiguous block of storage, but could be composed of dozens of strips which might reside in memory in any other. The same data could be repeated on one or more display lines. Individual regions might each have their own individual data and scrolling directions. FOR EXAMPLE: The program "hscroll.s" reads in a NEOchrome picture file and duplicates each line of the image. This, combined with the proper use of LINWID, effectively places two copies of the same picture side-by- side. Next, both vertical and horizontal blanking interrupt vectors are captured and the horizontal blanking interrupt is enabled in counter mode. To prevent flicker caused by keyboard input, the IKBD/MIDI interrupt priority is lowered below that of the HBL interrupt. Note that the program 'main loop' doesn't even call the BIOS to check the keyboard, since the BIOS sets the IPL up causes flicker by locking out horizontal interrupts - this may cause trouble for programs in the real world. The screen is effectively divided into ten regions which scroll independently of one another. There are two ten-element arrays which contain the base address of each region and its current scroll offset. At vertical blank interrupt time we compute the final display values for each region in advance and store them into a third array. We then initialize the display processor for the first region and request an interrupt every twenty lines (actually every twenty horizontal blankings). During each horizontal interrupt service, we quickly reload the video display address registers and the HSCROLL register. This must be done immediately - before the display processor has time to start the current line or garbage may result. Note that horizontal blank interrupts are triggered by the display processor having finished reading the previous data line. You have approximately 144 machine cycles to reload the HSCROLL and video display registers before they will be used again by the display processor finishes reading the data for the current display line. We then pre-compute the data we will need for the next horizontal interrupt to shave few more cycles off the critical path and exit. ---------------------------------------------------------------------- STE DIGITIZED SOUND OVERVIEW Sound is stored in memory as digitized samples. Each sample is a number, from -128 to +127, which represents displacement of the speaker from the "neutral" or middle position. During horizontal blanking (transparent to the processor) the DMA sound chip fetches samples from memory and provides them to a digital-to-analog converter (DCA) at one of several constant rates, programmable as (approximately) 50KHz (kilohertz), 25 Khz, 12.5KHz, and 6.25KHz. This rate is called the sample frequency. The output of the DAC is then filtered to a frequency equal to 40% of the sample frequency by a four-pole switched low-pass filter. This program "anti-aliasing" of the sound data in a sample- frequency- sensitive way. The signal is further filtered by a two-pole fixed frequency (16KHz) low-pass filter and provided to a National LMC1992 Volume/Tone Controller. Finally, the output is available at an RCA- style output jack on the back of the computer. This can be fed into an amplifier, and then to speakers, headphones, or tape recorders. There are two channels which behave as described above; they are intended to be used as the left and right channels of a stereo system when using the audio outputs of the machine. A monophonic mode is provided which will send the same sample data to each channel. The stereo sound output is also mixed onto the standard ST audio output sent to the monitor's speaker. The ST's GI sound chip output can be mixed to the monitor and to both stereo output jacks as well. DATA FORMAT Each sample is stored as a signed eight-bit quantity, where - 128 (80 hex) means full negative displacement of the speaker, and 127 (7F hex) means full positive displacement. In some stereo modes, each word represents two samples: the upper byte is the sample for the left channel, and the lower byte is the sample for the right channel. In mono mode each byte is one sample. However, the samples are always fetched a word at a time, so only an even number of mono samples can be played. A group of samples is called a "frame". A frame may be played once or can automatically be repeated forever (until stopped). A frame is described by its start and end addresses. The end address of a frame is actually the address of the first byte in memory beyond the frame; a frame starting at address 21100 which is 10 bytes long has an end address of 21110. Note: a zero can be written to the DMA sound control register at any time to stop playback immediately. PROGRAMMING CONSIDERATIONS The simplest way to produce a sound is to assemble a frame in memory, write the start address of the frame into the Frame Start Address register, and the end address of the frame into the Frame End address register, set the Mode register appropriately (set stereo to mono, and the sample frequency), and write a one into the Sound DMA Control register. The frame will play once, then stop. To produce continuous sound, and link frames together, more elaborate techniques are required. The DMA sound chip produces a signal called "DMA sound active" which is one when the chip is playing sounds, and a zero when it's not. When a frame ends in the repeat mode (mode 3), there is a transition from "active" to "idle" and back again on this signal. The signal is presented as the external input to MFP Timer A. You can put Timer A into Event Count mode and use it to generate an interrupt, for example when a frame has played a given number of times. Because of the design of the MFP, the active edge for this signal must be the same as the input on GPIP 14, which is the interrupt line from the keyboard and MIDI interfaces. It is, and the Active Edge Register is already programmed for that, so you need not worry about that if you use Timer A to count frames. The DMA Sound Chip's mode 3 (repeat mode) ensures seamless linkage of frames, because the start and end registers are actually double- buffered. When you write to these resisters, what you write really goes into a "holding area". The contents of the holding area go into the true registers at the end of the current frame. (Actually, they go in when the chip is idle, which means right away if the chip was idle to begin with.) If you have two frames which you want played in succession, you can write the start and end address of the first frame into the chip, then set its control register to 3. The first frame will begin playing. You can then immediately write the start and end addresses of the second frame into the chip: they will be held in the holding area until the first frame finishes, then they'll be copied into the true registers and the second frame will play. The interrupt between frames will still happen, so you can tell when the first frame has finished. Then, for instance, you can write the start and end registers for the start of the third frame, knowing that it will begin as soon as the second frame has finished. You could even write new data into the first frame and write its start and end address into the chip; this kind of ping-pong effect is rather like double-buffering of a graphics display. Here is an example of using Timer A in Event Count mode to play a controlled series of frames. Suppose you have three frames, A, B and C, and you want to play frame A three times, then frame B five times, and finally frame C twice. The sequence of steps below will accomplish this. Numbered steps are carried out by your program; the bracketed descriptions are of things which are happening as a result. 1. Set Timer A to event count mode, and its counter to 2 (not 3) 2. Write Frame A's start and end addresses into the registers. 3. Write a 3 to the sound DMA control register. [Play begins.] Go do something else until interrupted. [At the end of the sound repetition of Frame A, the timer's interrupt fires. At the same time, frame A begins its third repetition.] 4. Write Frame B's start and end addresses into the DMA sound chip. These values will be held until the third repetition of Frame A finishes. 5. Set Timer A's count register to 5, then go away until interrupted. [When the current repetition finishes, the start and end registers are loaded from the holding area, and Frame B will begin playing. The end of play signal will cause Timer A to count from 5 to 4. At the end of Frame B's fourth repetition, its fifth will start, the timer will count down from 1 to 0, and the interrupt will occur.] 6. Write frame C's start and end addresses into the registers, and program Timer A to count to 2. Go away until interrupted. [When the current repetition (B's fifth) finishes, the start and end registers are loaded from the holding area, and Frame C will begin playing. The end-of-frame signal causes Timer A to count down from 2 to 1. When Frame C finishes its first repetition, Timer A counts down from 1 to 0 and interrupts.] 7. Write a 1 to the DMA Sound Control Register to play the current frame, then stop. Disable TimerA and mask its interrupt. You're done. As you can see you program the timer to interrupt after one repetition less than the number of times you want a frame to play. That is so you can set up the next frame while the DMA sound chip is playing the last repetition of the current frame. This ensures seamless linkage of frames. INTERRUPTS WITHOUT TIMER A Besides going to the external input signal of Timer A, the DMA-sound- active signal, true high, is exclusive-ORed with the monochrome-detect signal, and together they form the GPIP 17 input to the M68901 MFP. The intent of this is to provide for interrupt-driven sound drivers without using up the last general-purpose timer in the MFP. It is a little trickier to use, however. For one thing, it causes the interrupt at the end of every frame, not after a specified number of frames. For another, the "interesting" edge on this signal depends on what kind of monitor you have. On an ST, monochrome monitors ground the mono-detect signal, so when you read the bit in the MFP you get a zero. Colour monitors do not ground it, so it reads as a one. When the DMA sound is idle (0), this is still the case. However, when the sound is active (1), the mono- detect signal is inverted by the XOR, so the bit in the MFP reads the opposite way. (The one place where the OS reads this bit as at VBLANK time, to see if you've changed monitors. The ROMs on any machine with DMA sound are appropriately modified, so you need not worry about this.) If you want to use the mono-detect / DMA interrupt signal, you have to set up the active-edge register in the MFP to cause the interrupt at the right time. The interesting edge on the DMA signal is the falling edge, that is, from active to idle; this happens when a frame finishes. If you have a monochrome monitor, this edge is seen as a transition from 1 to 0 on MFP bit 17. However, with a colour monitor, the edge will be seen as a transition from 0 to 1. Therefore, you have to program the MFP's active-edge register differently depending on which monitor you have. Make sure the DMA sound is idle (write a zero to the control register), then check MFP 17: if it's one, you have a colour monitor, and you need to see the rising edge. If it's zero, you have a monochrome monitor, and you need to see the falling edge. The DMA sound active signal goes from "active" to "idle" when a frame finishes. If it was playing in mode one, it stays "idle" and the control register reverts to zero. If it was playing in mode 3 the signal goes back to "active" as the next frame begins. In this case, the signal is actually in the "idle" state for a very short time, but the MFP catches it and causes the interrupt, so don't worry. ADDITIONAL CONSIDERATIONS Regardless of how you manage your interrupts, there is more you should know: the signal goes from "active" to "idle" when the DMA sound chip has fetched the last sample in the frame. There is a four-word FIFO in the chip, however, so it will be eight sample-times (four in stereo mode) before the sound actually finishes. If you are using mode 1, you can use this time to set up the chip with the start and end addresses of the next frame, so it will start as soon as the current one ends. However, if the interrupt should be postponed for four or eight sample-times, you could miss your chance to start the sound seamlessly. Therefore, for seamless linkage, use the pre-loading technique described above. MICROWIRE INTERFACE The MICROWIRE interface provided to talk to the national LMC1992 Computer Controlled Volume / Tone Control is a general purpose MICROWIRE interface to allow the future addition of other MICROWIRE devices. For this reason, the following description of its use will make no assumptions about the device being addressed. The MICROWIRE bus is a three wire serial connection and protocol designed to allow multiple devices to be individually addressed by the controller. The length of the serial data stream depends on the destination device. In general, the stream consists of N bits of address, followed by zero or more don't care bits, followed by M bits of data. The hardware interface provided consists of two 16 bit read/write registers: one data register which contains the actual bit stream to be shifted out, and one mask register which indicates which bits are valid. Let's consider a mythical device which requires two address bits and one data bit. For this device the total bit stream is three bits (minimum). Any three bits of the register pair may be used. However, since the most significant bit is shifted first, the command will be received by the device soonest if the three most significant bits are used. Let's assume: 01 is the device's address, D is the data to be written, and X's are don't cares. Then all of the following register combinations will provide the same information to the device. 1110 0000 0000 0000 Mask 01DX XXXX XXXX XXXX Data 0000 0000 0000 0111 Mask XXXX XXXX XXXX X01D Data 0000 0001 1100 0000 Mask XXXX XXX0 1DXX XXXX Data 0000 1100 0001 0000 Mask XXXX 01XX XXXD XXXX Data 1100 0000 0000 0001 Mask 01XX XXXX XXXX XXXD Data As you can see, the address bits must be contiguous, and so must the data bits, but they don't have to be contiguous with each other. The mask register must be written before the data register. Sending commences when the data register is written and takes approximately 16usec. Subsequent writes to the data and mask registers are blocked until sending is complete. Reading the registers while sending is in progress will return a snapshot of the shift register shifting the data and mask out. This means that you know it is safe to send the next command when these registers (or either one) return to their original state. Note that the mask register does not need to be rewritten if it is already correct. That is, when sending a series of commands the mask register only needs to be written once. VOLUME AND TONE CONTROL The LMC1992 is used to provide volume and tone control. Before you go and find a data sheet for this part, be warned that we do not use all of its features. Commands for the features we do use are listed below. Communication with this device is achieved using the MICROWIRE interface. See MICROWIRE INTERFACE the section for details. The device has a two bit address field, address = 10, and a nine bit data field. There is no way to reading the current setting. VOLUME / TONE CONTROLLER COMMANDS Device address = 10 (Address precedes command) Data field 001 DDD DDD Set Master Volume 000 000 -80 dB 010 100 -40 dB 101 XXX 0 dB 101 XDD DDD Set Left Channel Volume 00 000 -40 dB 01 010 -20 dB 10 1XX 0 dB 100 XDD DDD Set Right Channel Volume 00 000 -40 dB 01 010 -20 dB 10 1XX 0 dB 010 XXD DDD Set Treble 0 000 -12 dB 0 100 0 dB (Flat) 1 100 =12 dB 001 XXD DDD Set Base 0 000 -12 dB 0 110 0 dB (Flat) 1 100 +12 dB 000 XXX XDD Set Mix 00 -12 dB 01 Mix GI sound chip output 10 Do not mix GI sound chip output 11 reserved Note: The volume controls attenuate in 2 dB steps. The tone controls attenuate in 2 dB steps at 50 kHz (Note that these frequencies may change). USING THE MICROWIRE INTERFACE AND THE VOLUME/TONE CONTROL CHIP The MICROWIRE interface is not hard to use: once you get it right, you'll never have to figure it out again. The easiest way to use it is to ignore the flexibility, and just use one form for all commands. Since the Volume/Tone chip is the only device, and it has a total of 11 bits of address and data, your mask should be $07ff. If you're picky, you can use $ffe0, because the high-order bits are shifted out first, but it adds conceptual complexity. With a mask of $07ff, the lower 9 bits of the data register are used for the data, and the next higher two bits are for the address: Mask: %0000 0111 1111 1111 Data: %xxxx x10d dddd dddd Replace the d's with the command code and its data. For example, this combination sets the master volume to $14: Mask: %0000 0111 1111 1111 Data: %xxxx x100 1101 0100 The other important concept you must understand is that the bits shift out of these registers as soon as you write the data, and it takes an appreciable time (16 usec) to finish. You can't attempt another write until the first one is finished. If you read either register while it's being shifted out, you will see a "snapshot" of the data being shifted. You know the shifting is complete when the mask returns to its original value. (This theory is wrong if you use a mask which equals its original value sometime during the shifting, but $07ff never does.) Assuming you write $07ff into the mask register ahead of time, the following routine can be used to write new data from the D0 register to the volume/tone control chip. MWMASK equ $ffff8924 MWDATA equ $ffff8922 mwwrite: cmp.w #$07ff,MWMASK ; wait for prev to finish bne.s mwwrite ; loop until equal move.w d0,MWDATA ; write the data rts ; and return The purpose of the loop at the beginning is to wait until previous write completes. This loop is at the beginning of the routine, not at the end because waiting at the end would always force a 16 usec delay. Even if it has been longer than that since the last write. ---------------------------------------------------------------------- NEW CONTROLLER PINOUT Arrangement (Looking towards STE): 5 4 3 2 1 10 9 8 7 6 15 14 13 12 11 Connections (PORT A): 1: UP 0 5: PAD 0Y 9: GND 13: LT 2 2: DN 0 6: FIRE 0 10: FIRE 2 14: RT 2 3: LT 0 7: +5v 11: UP 2 15: PAD 0X 4: RT 0 8: n/c 12: DN 2 Connections (PORT B): 1: UP 1 5: PAD 1Y 9: GND 13: LT 3 2: DN 1 6: FIRE 1 10: FIRE 3 14: RT 3 3: LT 1 7: +5v 11: UP 3 15: PAD 1X 4: RT 1 8: n/c 12: DN 3 CONTROLLER MEMORY LOCATIONS FF9201 ---- 3120 RO Fire Buttons FF9202 UDLR UDLR UDLR UDLR RW Joystick 3/2/1/0 Directions FF9211 xxxx xxxx RO X-Paddle 0 FF9213 xxxx xxxx RO Y-Paddle 0 FF9215 xxxx xxxx RO X-Paddle 1 FF9217 xxxx xxxx RO Y-Paddle 1 FF9220 ---- --xx xxxx xxxx RO Light Gun X-Pos FF9222 ---- --xx xxxx xxxx RO Light Gun Y-Pos VIDEO REGISTER MODIFICATIONS FF8205 --xx xxxx RW Video Address High FF8207 xxxx xxxx RW Video Address Mid FF8209 xxxx xxx- RW Video Address Low FF820D xxxx xxx- RW Video Base Address Low FF820F xxxx xxxx RW Over-Length Line Width FF8264 ---- xxxx RW Undocumented HSCROLL register: no extra fetch FF8265 ---- xxxx RW Documented HSCROLL register FF8240+ ---- 0321 0321 0321 RW Red/Green/Blue Colour settings DMA SOUND REGISTERS FF8901 ---- --cc RW Sound DMA Control cc: 00 Sound DMA disabled (reset state). 01 Sound DMA enabled, disable at end of frame. 11 Sound DMA enabled, repeat frame forever. FF8903 --xx xxxx RW Frame Base Address (high) FF8905 xxxx xxxx RW Frame Base Address (middle) FF8907 xxxx xxx- RW Frame Base Address (low) FF8909 --xx xxxx RO Frame Address Counter (high) FF890B xxxx xxxx RO Frame Address Counter (middle) FF890D xxxx xxx- RO Frame Address Counter (low) FF890F --xx xxxx RW Frame End Address (high) FF8911 xxxx xxxx RW Frame End Address (middle) FF8913 xxxx xxx- RW Frame End Address (low) FF8921 m--- --rr RW Sound Mode Control rr: 00 6258 Hz sample rate (reset state) 01 12517 Hz sample rate 10 25033 Hz sample rate 11 50066 Hz sample rate m: 0 Stereo Mode (reset state) 1 Mono Mode FF8922 xxxx xxxx xxxx xxxx RW MICROWIRE Data register FF8924 xxxx xxxx xxxx xxxx RW MICROWIRE Mask register ICTARI PROGRAMMERS USER GROUP ============================= INDEX FOR MAGAZINE ISSUES 1-12 ============================== Symbol keys used (S)=Source code (Assembler, C, Basic, etc) (P)=Program file only. (D)=Document text files. ------------------------- ICTARI ISSUE 1 --------------------------- ASSEMBLY Executable file cruncher/decruncher code (S) Mandelbrot & Julia set picture generator, low rez (S) Caps lock disable routine (S) Virus killer program and info on 19 viruses (S)(D) Bootsector Companion program and bootsector code (S) Code to erase boot sector programs (S) C Routine to set time on boot up (S) Code to fast erase floppy disk data (S) istBinary file to assembler source code converter (S) Program to show ST type (P)(S) Code to get/set system clock (S) STOS Games cheat program code (S) MISC Falcon review (D) Falcon specifications (D) Program to force memory size to 0.5Mb (P) Personal accounts program (P) ------------------------- ICTARI ISSUE 2 --------------------------- ASSEMBLY Document displayer code, medium rez (S) ICTARI display text code (S) Menu display program (S) Code to remove lower screen border (S) Code to play digitized sampled sound on STE only (S)(P) C ICTARI Database program (S)(P) Graphics information, VDI calls demo (S) Code to read and display keyboard data (S) GFA Font designer program (S)(P) STOS Ball-in-ball model demo code (S) Cyberworm game (S) Filter scroller (S) Pontoon game (S)(P) Raster routine code (S) Unlimited sprites demo code (S) MISC File move program (P) ST Zip program (P) Bug reports (D) Midi information and sample (D) ------------------------- ICTARI ISSUE 3 --------------------------- ASSEMBLY Code to display disk information (S) Tips for speeding up machine code programs (D) Code to remove top and bottom screen borders (S) Loading and saving files using GEMDOS (S) Code to load and display SPECTRUM pictures (S) Accessing disk sectors including boot sectors (S) Code to display TOS, sysbase, STE, memsize, etc (S) C Disk back up utility (S) Tim Oren GEM Tutorial Parts 1 & 2 Windows (D)(S) Screen re-draw code (S) GFA Multi-tasking clock accessory (S) Routines to load and display DEGAS pictures (S) Beginners GFA Tutorial (D)(S) Make menu utility program for GFA programmers (P) BASIC Mandelbrot & Julia display program (S) STOS Circle drawing demo (S) Code for calendar to name any day (S) Code to display droid sprite in dungeon (S) Program to rescue data from corrupted disk (S) MISC Chameleon program (P) Demos information (D) GEMBENCH program (P) GEMDOS manual for assembler and C (D) File unpacker program (P) Program to trace TOS system calls (P) Virus protection program (P) Guide to Railroad Tycoon game (D) ------------------------- ICTARI ISSUE 4 --------------------------- ASSEMBLY Mega funky screen flipper (S) Document display program (S) HBL colour change code (S) Assembler Tutorial Part 1 Scope and concepts (D)(S) Assembler Tutorial Part 2 Editors, Assembler, Debugger C A simple form handler routine (S)(P) Tim Oren GEM Tutorial Part 3 Dialog handler (S)(D) Tim Oren GEM Tutorial Part 4 GEM Resource structures (D) Sound samples replay code for STE (S) STOS 29 new STOS Basic extensions (S)(D) MISC Sampled sounds formats V2.10 by Guido van Rossum (D) VT52 Control codes list (D) Program to convert DEGAS pictures to DEGAS ELITE (P) Stereo hardware modifications for STFMs (D) Picture formats information by David Baggett (D) Sound sample play program before a warm reset (P) Program to change mouse cursor to hourglass shape (P) Program to play MOD files on machines with PCM chip (P) ------------------------- ICTARI ISSUE 5 --------------------------- ASSEMBLY Code to remove upper and lower screen borders (S) Document display program (S) Reset picture demo, displays picture after reset (S) Starburst routine (S) TOS version detection code (S) Assembler Tutorial Part 3 Addressing modes (D)(S) Assembler Tutorial Part 4 Initialization Algorithms (D) Simple raster routine (S) Executable file structure & relocation table (S) C Tim Oren GEM Tutorial Part 5 Resource Trees (D)(S) Tim Oren GEM Tutorial Part 6 Raster operations (D)(S) Linking machine code into C programs and vice versa (S) GFA Image display routines (S) Scroller routine (S) Screen meltdown routine (S) Sprite routines (S) STOS Screen border removal code (S) Sine wave programs (S) Code to use more than 15 sprites (S) MISC MIDI data file Disk formats information (D) Pexec TOS call information (D) Disk/memory display/edit program (P) Icon editor program (P) ------------------------- ICTARI ISSUE 6 --------------------------- ASSEMBLY Assembler Tutorial Part 5 Program timings (D)(S) Assembler Tutorial Part 6 Instruction timings (D)(S) Routine to locate box image on screen (S) GEM shell code (S) Code to use interrupt routines (S) Random number generator and scaling routines (S) Hi-resolution scroll routine (S) Square root calculation routine (S) Notes on sub-routine library files (D) C Tim Oren GEM Tutorial Part 7 Menu structures (D)(S) Tim Oren GEM Tutorial Part 8 User interfaces (D)(S) GFA 19 miscellaneous procedures (S) 22 misc files including sprites, rasters, starfields (S) STOS Screen demos (S) PASCAL Disk address book program (S) MISC Handwriting recognition program (P) Stereo sampled sound sequencer system STE (P) Playing sampled sounds in Basic using DMA, STE only (S) ------------------------- ICTARI ISSUE 7 --------------------------- ASSEMBLY Assembler Tutorial Part 7 Adaptive algorithms (D)(S) Assembler Tutorial Part 8 Seizing system control (D)(S) Routine to position cursor at set co-ordinates (S) Sprite routines using Neochrome Master (S)(P)(D) Tracker module player code (S) C Tim Oren GEM Tutorial Part 9 Lines & Solids (D)(S) Tim Oren GEM Tutorial Part 10 Text output (D)(S) GFA Overscan utility (S) Pixels program (P) STOS ICTARI accounts program (S)(P) MISC Text printing program for GDOS fonts (P) Astra DTMT program (Update from issue 4) (P) Handwriting recognition program (P) Bitplane information (D) ------------------------- ICTARI ISSUE 8 --------------------------- ASSEMBLY Programming techniques. Passing in-line data to S/R (D) Notes on program layout (D) 68K instruction set display accessory (S) Mouse problem request (S) C GEM tutorial Chapters 0-7 (D) 82 source code routines for use with GEM tutorial (S) GFA Graphics mapping bitmaps (D)(S) PASCAL Directory lister (S)(P) MISC Images (4D cube and DSP56001 circuit) 18 Atari books briefly reviewed (D) ------------------------- ICTARI ISSUE 9 --------------------------- ASSEMBLY Cookie Jar find program and documentation (D) Cookie Jar find source code (S) Assembler MACRO tutorial (D) Two MACRO files for system TOS calls (S) Twist scroll demo program and source (needs fixing) (S) Mouse problem answered (D) C C Tutorial Chapters 8-14, (see last month also) (D) Program to delete .BAK files and source code (S)(P) GFA Handy tips for GFA programmers (D) Horizontal scroll routine (S) PASCAL Address book program and source code (S)(P) MISC Atari Explorer Online Programmers Journal Issue 1 (D) 'The Atari Compendium' book review (D) Pexec TOS call information (D) Executable file structure information (D) Index for ICTARI disk magazines issues 1-8 (D) List of current members (D) ------------------------- ICTARI ISSUE 10 --------------------------- ASSEMBLY Complete set of floating point arithmetic routines (S) Routine to read command line text string (S) Event_multi 'right button' problem solved at last (D) Twist scroll program, updated version (S) C Boink, a Break-out type game with source code (S) Event_multi 'right button' problem solved at last (D) GFA Code to read command line on TTP programs (S) GEM Window handling routines (S) Colour scroller routines (S) Corrections to bit maps article (see issue 8) (D) PASCAL Pipe monitor. Displays AES messages (S) STOS Moving block puzzle game (S) MISC Atari Explorer Online Programmers Journal Issue 2 (D) Various GEM bugs discussed (D) Program to show active GEM/TOS/BIOS/AES/VDI calls (P) The LZW and GIF compression algorithms explained (D) List of current members (D) Index for issues 1-9 (D) ------------------------- ICTARI ISSUE 11 --------------------------- ASSEMBLY Binary to decimal conversion routine (S) Decimal to binary conversion routine (S) Code to play chip music in interrupts (S) Code to set up time and date when booting up (S) Routine to convert number to a binary string (S) Routine to convert number to hex string (S) Routine to enter hex number from keyboard (S) C GEM Tutorial by J White. Part 1 Introduction (D) Using floating dialogue boxes in Lattice C (S) Porting IBM PC RSC/Doodle to Atari GEM (D) GFA Code to generate circles, spheres, etc (S)(D) Picture image cutter and saver program for GFA (P) PASCAL Code to show boolean expressions as a Karnaugh map (S) STOS Code for number guessing game that talks to you (S) MISC Blitter chip manual (D) Click anywhere title box using Resource File editor (D) List of current members (D) Index for issues 1-10 (D) ------------------------- ICTARI ISSUE 12 --------------------------- ASSEMBLY Load file routines (S) Colour palette fading routines for STFM & STE (S) User defined mouse shapes for GEM programs (S) Sprite drawing routines (S) Sprite tutorial Part 1. Beating the 16 pixel boundary (D) Updates for Cookie find & Mouse routines (S) C Fractal drawing code (S) GEM Tutorial by J White. Part 2. Initialising GEM (D) GFA GFA Manual Part 1 of 3 (D) GFA Alert box designer program (P) STOS Bootview program code (S) Pipe perfect game (S) MISC Analyzer program to display info on system crashes (P) Atari Questions and Answers file No 1 (D) Warning for DevPac 3 and Lattice C users (D) Current membership list (D) Index for issues 1-11 (D) ------------------------- ICTARI ISSUE 13 --------------------------- ASSEMBLY Setting up system timers (S) Vertical Blanking List (VBL) notes (D) Colour cycling on raster lines (S) Nick Bates. Sprite tutorial Part 2. (S)(D) Keyboard equates file (S) Compare routine (S) Disk formatting code (S)(P) C C Graphics extensions (S) Various C functions for use with GEM dialogs (S) GEM Tutorial by J White. Part 3. (D) GFA Anagram generating code and recursion techniques (D)(S) Sound sample play routines (S) STOS STOS extra extensions (S) MISC Atari Questions and Answers file No 2 (D) Discussion on drawing tangents on curves (D) Current membership list (D) Copies of any of the above issues are available for 1 each from :- ICTARI User Group, 63 Woolsbridge Road, Ringwood, Hampshire, BH24 2LX. -------------- END ------------- ,4(),()()()",,*6(),()()@JDone.-lmMEdE].LH K8*odl.vADaaW#`J E ]M999w#9 1pfف$ {pֱňl 2X8@BA{a K{F6ub- (u2( \B6fE !FT*@1lM R6#e !Yr"^0,7X(ikConlTM* x.<@ f< ş8R,mQ(a`r`yK "xs8odrY O,0 \;sYȞӁH`f ݩ`D ˾3u\ P1NrJ@26m M\vA[=t2! @‚4cm!KTi1AЌ 2 A@ֈUФ%1H,liB ICTARI PROGRAMMERS GROUP ======================== CURRENT LIST OF MEMBERS September 1994 Martyn Armitage 101 South Terrace, Wales Bar, Sheffield S31 8QL Tel. 0909 773564 Keith Baines 8 Lumley Court, Denmark Avenue, London SW19 4HQ Ian & Mark Baker 256 Lower Road, Great Bookham, Surrey KT23 4DL Tel. 0372 454875 Lee Ball 117 Millfield Avenue, Bloxwich, Walsall West Midlands, WS3 3QU Tel. 0922 402815 Nick Bates 17 Elliott Close, Forches estate, Barnstaple N Devon, EX32 8EW Tel. 0271 24633 Mark Blackwood 64 Chantry Road, Moseley, Birmingham, B73 8DJ Te. 027 4490936 Paul Brookes 32 Dudsbury Road, West Parley, Ferndown Dorset, BH22 8RE Jamie-Lee Burrows 220 Broadlands Drive, Lawrence Weston Bristol, Avon, BS11 0PN Tel. 0272 384771 John Charles 'Ash Tree', Priory Lane, Grimoldby, Louth Lincs, LN11 8SP James Collett Park View Farm, Carlton, Nr Nuneaton, Warks CV13 0DA Internet E-Mail- S6005/46@brookes.ac.uk Martin Cubitt 14 Deepdene Ave, Rayleigh, Essex SS6 9LG Robert Darling 11b Turketel Rd, Folkstone, Kent CT20 2PA Tel. 0303 245203, BBS No 0303 249306 Richard Davey 10 Oak Drive, Portishead, Bristol, Avon BS20 8QS Tel. 0275 843241 Leslie Dewhurst 8 Stirling Avenue, Leamington Spa Warwickshire, CV32 7HN Paul Ditchfield 499 Owen, Ashworth North, Maghull, Liverpool L31 1HW Tel. 051 4730303 Extn 4364 Richard Evans 3 Gervis Crescent, Parkstone, Poole, Dorset BH14 0LR Tel. 0202 744151 Marten Dryden 21 Rowlands Hill, Wimborne, Dorset BH21 2QQ James Ford 4 Berceau Walk, Watford, Herts, WD1 3BL Tel. 0923 248762 Vimal Goricha 29 Abbey Way, Bradville, Milton Keynes MK13 7AQ David Gunby 12 Windrush Drive, Oadby, Leicester LE2 4GH Tel. 0833 720246 Ian Hancock 74 Frank Cowin Court, Sussex St, Salford M7 1QX Michael Herman 3 Sheridan Gdns, Kenton, Harrow, Middx HA3 0JT George Hodgson 4a Millicent Close, Hednesford, Staffs WS12 4BJ Tel. 0543 423804 Robert Holbrook 3 Windmill Close, Haylands, Ryde, IoW PO33 3JB David Holmes 22 South Road, Great Abington, Cambridge CB1 6AU Kenneth Hughes 220 Broadlands Drive, Lawrence Weston Bristol, Avon, BS11 0PN Tel. 0272 384771 Jefferson Humber 16 Kingfisher Close, Carisbrooke Park Newport, Isle of Wight, PO30 5XS Tel. 0983 526046 Steven Jordan 38 Wylam, Mill Park, Bracknell, Berks RG12 8XS Tel. 0344 427581 Peter King 5 Marlborough Rd, Dover, Kent CT17 9ND Paul Laddie 29 Elliott Street, Sacriston, Durham DH7 6JH Tel. 0913 710554 John Levon 12 St Johns Ave, Wakefield, W Yorks WF1 2RE Ralph Lovesy 25 Town End Road, Faringdon, Oxon SN7 7UW Tel. 0367 241940 Marten Lindstrom Savenasvagen 24, S-932 31 Skelleftehamn Sweden John Logan 9 Myrtlefield Park, Belfast, BT9 6NE Tel. 0232 660302 Ralph Lovesy 12 Bell Lane, Syresham, Northants, NN13 5HP Tel. 0280 850450 Andrew Martin 23 Earlswood, Hanworth, Bracknell, Berks RG12 7LB Tel. 0344 57308 John McGarrity 1 Hillwood Gdns, Ratho Station, Newbridge Midlothian, EH28 8PX Tel. 031 333 3982 Iain McLeod 15 Regis Court, Barnton, Edinburgh, EH4 6RG Andrew Miller 19 Dundas Street, Edinburgh, EH3 6QG Jason Murdoch 13 Woodmoor, Finchampstead, Wokingham Berks, RG11 3TT Simon Oke 10 Symn Lane, Wotton-under-edge, Gloucs GL12 7BG Carl Pattinson 40 Silverdale Place, Newton Ayecliffe County Durham, DL5 7DZ Mark Pearce 5 Marlborough Rd, Dover, Kent CT17 9ND John Phillips 20 Hawkesworth House, Cavendish Road, London SW4 8NA Kevin Preece 17 Chislet way, Grange Park, Tuffley Gloucester, GL4 0QQ Gary Priest 167 Ludlow Rd, Itchen, Southampton SO19 2EL Christopher Reeder 101 Icknield Walk, Royston, Herts SG8 7LJ Tel. 0763 247913 Raymond Reid 10 Daviot Drive, Hilton, Inverness, IV2 4UL Alan Richardson 55 Alderbrook Road, Clapham South, London SW12 8AD Tel. 081 675 1866 Simon Rigby 116 Rosmead St, Newbridge Rd, Hull HU9 2TE Gair Shields 73 Old Castle Road, Cathcart, Glasgow G44 5TG Tel. 041 633 3358 William Shields 19 Tennyson Rd, Chelmsford, Essex, CM1 4HZ Geoff Smith 6 Humber Road, Beeston, Nottingham, NG9 2EF John Stevenson 28 Gun Bank, Masham, Ripon, N Yorkshire HG4 4EW Peter Strath 75 Cavendish Road, Highams Park, London E4 9NQ James Taylor 12 West Drive, Cleadon, Sunderland, T & W SR6 7SJ Tel. 091 5362165 Christopher Teague 7 Union Street, Nantyffylon, Maesteg Mid Glamorgan, S Wales, CF34 0BG George Voulgaris Larisis 88, TK60100, Katerini, GREECE Justin Ward 51 Vicarage Road, Sutton, Surrey SM1 1QN Martyn Wells 86 Cornwall Road, Kettering, Northants NN16 8PE Tel. 0536 520240 Jonathan White 20 Fryent Close, Black Rod, Bolton BL6 5BU (This is not a complete list as some members do not want to be listed) . 1e0.. ACCESSORIES3e0PLAZMA :e0REBOUND =e0. 3e0.. 1e0DISPLAY ACB NDISPLAY DOC 셳DELETE ACB H|LionpoulosNz5zH  DISPLAY ACCESSORY V2.1 - M.Cubitt 14/10/1990,1/4/91,7/4/91 H Allow ASCII document file to be viewed easilyL S T O S Use mouse keys, cursor keys (with/without shift)0( T - Top, B - Bottom.,2 L - Load anotherD< F - Find string (from line & wrap around)*F A - Find again&P Esc - ends.Z:d ASCII <32/>127 replaced with _Ln ------------------------------------------------*x FIND text entryB F1 - field exit (clear from cursor), UNDO - exit FINDȊҊ܊: MXFS now stored in MBK 6 bytes 2028,2029,2030,2031F Temp NUMBER_READ now stored in MBK 6 bytes 2024,2025,2026,2027B NUMBER_READ now stored in MBK 6 bytes 2004,2005,2006,2007: LOW now stored in MBK 6 bytes 2008,2009,2010,2011: LOW1 now stored in MBK 6 bytes 2012,2013,2014,2015: HIGH now stored in MBK 6 bytes 2016,2017,2018,2019<" HIGH1 now stored in MBK 6 bytes 2020,2021,2022,20234, SCAN$ now stored in MBK 6 bytes 1924 - 2001<6 FOUND now stored in MBK 6 bytes 2032,2033,2034,2035D@ MXFS-MaXimum File Size, you may use what ever value you likeBJ Memory banks 5 & 6 must be set up as DATA banks so the info>T is not lost when returning back to STOS command screenL^ They should be filled with zeros before saving OR load a file you use6h often and save it with this in memory. Do this:&r ** reserve as data 5,MXFS*80+4$| ** reserve as data 6,80*24+10 ** fill start(5) to start(5)+length(5),00 ** fill start(6) to start(6)+length(6),0" ** loke start(6)+2028,MXFS( ** loke start(6)+2032,(MXFS+2)*80 ** GOTO 40008 Remove REMarks to free more space & rid of 4000-ŠN̊ -----------------------------------------------------------------------֊v"(),*(),()(),2(),()()&0,().:(),()()()D*N,(())P.X(),()()() b,(())lqv0%Insufficient memory to run accessory.OkFIRST ƠͦРڠ 䠰:,(())*8, :(L)oad new or (V)iew current:4:X(LV,()):X : ,,, XHF*,:: D I S P L A Y : by M. Cubitt :24,:: Bytes Free:::D>, :: DISPLAY using:::()()HP$R,:(N);R\:FILE$(*.*, Select an ASCII file to view. P$):$fFILE$z(pFIRST$zA$(FILE$,) A$0P$** File not found. Reselect.R#,FILE$h,: Reading ';FILE$;';();Size:;((A$, ,)); A,:Line #;P$OK(),8(())(())OK#,LINE$0(),(())$G,.(()); 8(LINE$)P8B(())(())j&LLINE$(LINE$,P)VOK`"jA$(LINE$,P)4tLINE$(LINE$,(LINE$)P)~LINE$,A$ (LINE$A$0(),(()) (LINE$)P4LINE$LINE$(P(LINE$))ăΙ (ؘ⏘ #, (())(0P$** No ASCII found. Reselect.R(((),(())2OKZ<, <F0WARNING ! Maximum size reached - load terminatedPZdn(),x(),0(),(())8(())(())((),(())(),((),(())FIRSTș:ҩ,:(N);P$A()S.AFAf" n."AAAa@,6.@A2SP^JT.^A8SH|hr(|SP(SH `.ATAt™\̘.֢ALAlR.ABAb A  End Program &$0  Display Text on Screen :, D,,(N()(), X()((()))P,()(())P():()((())(()))P,b lv  Page Down 8(())(()) 0(),(())0(),(())8(())(())((),(())(ƈ(),(())Й:ڋ  Page Up ,(())  H0 (),(())0(),(()), (())>*(),(4(),(())>:HR  Top ,\(())zf pz(),((),(()):  Bottom 8(())(()) (ʈ(),(())(Ԉ(),(())ޙ:  Line down 8(())(())     V0 (),(())0 $(),(()). .,,,,,, 8,x B()((()))P,()(())P():()P, L  V, `(()) ~ j  t 0 ~(),(())0 (),(()). ,,,,,, ,x ()((()))P,()(())P():()P,  $ Ċ  Show text m/c interface  λ() ؼ()() ⠟   Error    "   Store LINE$ in memory ( (Q(LINE$), 2X((LINE$)Q)6 <X XX_F F()((()))PQ,X PQ Z d  Find string  nN x P$ XM( A(()X)( AA P$P$(A) X X ȩ,:P$; Ҡ6 ܩX,:(P$,X,);  A():S. AS   print A,S : goto 2080> ASa ,: Not  UNDO   ".L ,ASKX T: Not  LEFT 6 6X,:(P$,X,); @X J N TASMXN |: Not  RIGHT 6 ^X,:(P$,X,); hX r R |ASX : Not  BACKSPACE  XN Z (P$,OX)(OX) 6: Nothing after cursor anywayF P$(P$,X)(P$,OX) X @ ASS : Not  DELETE  ¢XN Z ̢(P$,OX)(OX) : Nothing after cursor anywayF P$(P$,X)(P$,NX)  @ ASR : Not  INSERT , NN񸣛N   F A4SK D: Not  LEFT & shift 6 X,:(P$,X,); &XX( 0XX : H DA6SM v: Not  RIGHT & shift 6 NX,:(P$,X,); XXX( bXNXN l J vAS; : Not  F1  (field exit)\ XP$(N)(P$,OX)(OX) . A :  RETURN . A A SSHSKSMSP(SRS^)(S:SE)SaSb ( NXN * (P$,X,)(A)& ƩX,:(A); ТXNX ژ < (P$,) : R P$(P$,X)(A)(P$,X,NX)   XM@ ()X,((P$,X,)) X8 *(P$,) (P$)* 4P$(P$,(P$)) >2 HST((()))P. REN(())P \j< fX(()ST()EN,P$) p~ zX ST  ST ENX f 8 . XX() ʈ(),X" LXP. ީ,: Found @ line;L;  ,:();, (())L.@L(())L(())(),L$(),L$:.$8,: Not Found;:B(),((()))PLV,:( );`&j,: Scanning...;t~,:( );  Again (find) H(())((()))P nP$ XM2P$P$((()X)) ĂX8ʞ(P$,) (P$)*P$(P$,(P$))̃H΢(())((()))P *(ST(())JST((()))P H R,:(N);8 *************** End of Program *****************: Packing...(L(())P4()L()(),"L(,())Ƞ,L,Ҡ(),()L()ܠ栩,L.(),()()()(),L,4(),()()()",,*6(),()()@JDone.-lmMEdE].LH K8*odl.vADaaW#`J E ]M999w#9 1pfف$ {pֱňl 2X8@BA{a K{F6ub- (u2( \B6fE !FT*@1lM R6#e !Yr"^0,7X(ikConlTM* x.<@ f< ş8R,mQ(a`r`yK "xs8odrY O,0 \;sYȞӁH`f ݩ`D ˾3u\ P1NrJ@26m M\vA[=t2! @‚4cm!KTi1AЌ 2 A@ֈUФ%1H,liBr5"mi-cbM]YQf>AZNz:!U0f)T4Ɩ&B5--#@ @ "fIg6a@󓁂GzBSFفL ".v(>e z !08F0;h,g5BA4*P - A(vD s(? y0#@Z{ZB62..(h p @Àх>eV!*LT&> UD ںp5/ Cf4 !a2W9a(`i@с%h`lS7:a(YSl\S8̸A`h쇇8%\ QQfIzj}`II/ށ8+B:@RJ*dLMPhn>M,` w?@ Ϝŧe hHv.\ldۚ ?qDcV}}uː~^`jjU$ ~@0ၵy6) 'h}S{'a糳~ -9chؘ.K J] J ih)oh8C k?`oghcn Y( *3L :B Kv0p<4{BUK'W#8 ;pF.a`LG!q{142S aӬ6aȀCR`hq9!@ȽGbh ,ٕWogblUMNMg.MR`!jh Þ(C;SpIs^'b2: xυ˄ +P;:H#)D#2@D>d;0 1:C4 Πl'd  ~ghRP:@ptQE2VаP4m` ;W[#S22d 2P8 %Ps`", uï!'"1oXgዡh06>|mps""Jʠ̰( vƔ`hPM,]MLCa38NrNDTCD &UP1y#;p W}IEpon=Ω;.0 &n8lbccivEh L}(L r#jlnAAHLFA".E- ܉ X;&ܣ,]HrE$U%OB=3Rp(3qXB$ 婡Cn ,3(bbdL] eB 5Ήә Ja<d$, bO\@@3L 07a$s 3Lo5Р`b ' @@lXUX P`4FFcV t t@;@mM K^cz?g`KobFi&C*"(2"(4E k" `e@7S$^L-S'{Kg1zX(D囡1/ !@ꐋ eTd],lP`fH7AbIX IDH9gh|4$ r(TEEMmL`h<ҷP``P_V48p GؚP2S؃gP`yXՉJ [0@i@ yH4$30&qt$~Ƅ{xĠ|Nq x 볡VodlQΦm ga$CAr(P@f1N(8:ؙWBYXRR@VT-m (9 ]lL ϩ@0 ʛȀCV66N.@q@эD8!, xFT؅-a xb^VT#2((3*fdB `PҥX, @ꂠ.p\*b^ m MN|H'$"KASc6&% m0i DIrt2+5 X@꜠^ Bw0X5 Tcf$u%<`e!,Ԁ B++RRAJ(($4 (P bԮL\fUBS#vfGl \]Ù+{5 |2 * KK{;COu<`&T9RP~0|ЀT <4F̖ C2@DT- 퉐AuFPx(tQP (D;*Dj |hMH50< H%33561p~DDB6Dx1zyzU9yzWحg()*Nvf7 4`pȸkj9RFFRDP`0@NFMiVxS^榀E * q%31 s,{ C7Bpt668/`\̅&E l,m#il@0$0! ofhBjgD?3N.v®F.. pPMb ƕ FDeleting contents of ;(B$,(B$))PxZB$\*.*dDone.nx Not Done.  B$8Deleting folder ;(B$,(B$))B$Done.ȡҠtܠ Not Done. the VBL will execute the "subroutine" pointed to by SWV_VEC (Long at $46E) which will actually be initialised simply to a computer reset (pointer to OS-start). 8. BOTH physical AND logical screen are set according to the one pointer in SCREENPT. In addition SCREENPT is not, unlike COLORPTR, automatically zeroed after being used. So I . :e0.. 1e0PLAZMA_1BAS  Lionpoulos $ >> Fake Plazma Looking Think2 >> Coded By The Eskimo & Nig-Nog Of Ignite> >> Needs The Missing Link and Misty Extension Installed*( >> Contributed By Diamond SoftwareF2 >> Thanks to our German contacs and the German STOS User Group< >> Enjoy...F$Pͦ::ަ:::: Z#SHT(h)Fd: gosub 250 : rem << Remove The 'rem' to what's going onlnAh:B((A))d:#SHT(A)B:A:AxJ -------------------------------------------------------------------J | Main Loop |J ------------------------------------------------------------------- >A:A:G:GȚ&X#SHT(A)}.Ȩ,(),,X,,0Ҩ,,,@,,,,ܨ,,,,2,:AhA( 9:q::::h,q,r,s,t,u,v,w,w,w,g,W,G,G,',8H p`P@0 7w.@< ????????xxxxxxx<<<<<<<????????xxxxxxx<<<<<<<@< xxxxxxxxx<<<<<<<<<??x???????<xxxxxxxxx<<<<<<<<??<x??????!Y():!Y():!Y():!Y() : Set up screenGT:GB:!X():!X():X():Y ():|OXX:tOYY:lXI:dYI:()lXI,()dYIL:v,:,:::Rebounder National League::: Use joystick!:Home team 0 v 0 Away team::((),();:\I:V();(&);();::((),()f[,:GOAL:,:GOAL:' M.Cubitt D E M O 19898^:, : DEMO VERSION! :`X,Y:O:,!Y():P$():,!Y():P$():,!Y():P$():,!Y():P$(): Move ballX|OX,tOY: :X,Y:O:|OXX:tOYY: Check moveX|OXlXI:YtOYdYI:VCH(X,Y):lXI dYIL VCH HP2((X,Y) < 2lXI:*<(X,Y)  FdYI: PXx ZY2.dlXI:dYI: xY:zXX #((F<(X,Y) d(F VCH 2(X,Y) 2*(X,Y) "dYI: XZ@ "Y20,XI:YI: @YT:BXX #<T(X,Y) , dYIv VCH 2(X,Y) "lXI:6̢(X,Y) F X'* Yb0lXI:dYI: Y: XX #((F<(X,Y) (F vVCH H2(X,Y) b6(X,Y)  X' Y2XI:YI: ТY:ҢXX #<䢺(X,Y)  Move player 1=you!< !X()&@ ¢(!X(),!Y()) @ ̢(!X(),!Y()) ֩!X(),!Y(): :!X(),!Y(): :!X()!X():!X(),!Y():PB$():!X(),!Y():PB$():  @ (!X(),!Y()) N@ 0(!X(),!Y()) D :!X(),!Y(): :!X(),!Y(): :!X()!X():!X(),!Y():PB$():!X(),!Y():PB$(): D N W basic comp move=p2(X!Y() bY vY  Y(X!X().X!X() JNQ!X():XNQNQn!X(),!Y(): :!X(),!Y(): :!X()NQf!X(),!Y():P$():!X(),!Y():P$():\NQ!X():XNQNQ&(X!X()(ƢX!X().Т()  ڢY YB Y B#(GT:#GB:c2,wpp 0PU33ss77w̏3?3630>03<6;73;73?c<30>03<633kc?007?06kc73 73k663>07?06kc ȋ ں@@@@@@@@@@@@@@@@@º(FvÎô:FT|ĎĜľ2222222222222222222Z"NYA$X AFFFLAGSC1wC0DOS (S) Code to load and display SPECTRUM pictures (S) Accessing disk sectors including boot sectors (S) Code to display TOS, sysbase, STE, memsize, etc (S) C Disk back up utility (S) Tim Oren GEM Tutorial Parts 1 & 2 Windows (D)(S) Screen re-draw code (S) GFA Multi-tasking clock ac#a000000 #b000000 #c7770007000600070055200505552220770557075055507703111103 #d #E 18 12 #W 00 00 02 07 4B 10 08 A:\*.*@ #W 00 00 02 0B 4C 09 00 @ #W 00 00 0A 0F 34 09 00 @ #W 00 00 0E 01 34 09 00 @ #M 03 00 00 FF A ICTARI_MAG@ @ #M 00 01 00 FF B FLOPPY DISK@ @ #T 00 03 02 FF TRASH@ @ #F FF 04 @ *.*@ #D FF 01 @ *.*@ #G 03 FF *.APP@ @ #G 03 FF *.PRG@ @ #P 03 FF *.TTP@ @ #F 03 04 *.TOS@ @ SC Chameleon program (P) Demos information (D) GEMBENCH program (P) GEMDOS manual for assembler and C (D) File unpacker program (P) Program to trace TOS system calls (P) Virus protection program (P) Guide to Railroad Tycoon game (D) ------------------------- ICTARI ISSUE 4 --------------------------- ASSEMBLY Mega funky screen flipper (S) Document display program (S) ICTARI USER GROUP ISSUE 14 September 1994 ___ ______ ___ _________ _________ ___ \__\ \ __\ \ \__ \______ \ \ _____\ \__\ ___ \ \ \ __\ _____\ \ \ \ ___ \ \ \ \ \ \ \ ____ \ \ \ \ \ \ \ \ \_____ \ \____ \ \__\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \__\ \_______\ \______\ \________\ \__\ \__\ * m a g a z i n e * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= I C T A R I U S E R G R O U P 63 Woolsbridge Road, Ringwood, Hants, BH24 2LX Tel. 0425-474415 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= INDEX FOR ISSUE 14 ================== ASSEMBLY STFM Overscan techniques. Nick Bates, Sprite tutorial Part 3. Code to calculate position of bouncing sprite. Sign Integer Fraction maths routines. C GEM Tutorial by J White. Part 3. Othello game source code. League table solution. GFA GFA Manual Part 2. Dialog box designer program. STOS STOS accessory to display text files. Rebound football game. Plazma screen display code. MISC Atari Questions and Answers file No 3. STE hardware information. Current membership list. Index to issues 1-13. In next months issue of ICTARI (this may change) :- ASSEMBLY Sampled sound play routines. Sampled sound play routine and editor. Sound sample conversion routines. C Music score writing program code. GFA GFA Manual Part 3. STOS Disco display and sound program. Timing routine MISC Date to day conversion algorithm. Atari Questions and Answers file No 3. Information on sampled sounds and PSG chip. PSG Musical note/register code listing. For future issues :- Polyline drawing routines in machine code. Bezier curve drawing routines. Picture decompression routines for IMG, Degas, Tiny, PCX, PAC, etc. Picture compression routine for IMG pictures. HP DeskJet/LaserJet compression routines (Mode 2 TIFF). Picture switching techniques. Printer driver code for printing mono/colour images. ---------------------------------------------------------------------- EDITORIAL ========= MEMBERSHIP ---------- As a result of a mention in ST Format magazine we have had a total of 27 enquiries about ICTARI since the middle of July and so far 11 have joined the group (including two from Sweden). Hopefully some more will join later, anyway welcome to all the new members. SURVEY ------ We have done a small survey on languages used and hardware owned. The percentages refer to the numbers used compared with the total number of members (60) although a lot of members do program in more than one language. Languages. C 34 83% (Mainly Lattice C) Assembler 31 51% (Mainly DevPac 2 or 3) GFA BASIC 18 30% STOS BASIC 13 21% HISOFT BASIC 11 18% PASCAL 10 16% COBOL 2 3% FORTH 1 1% LISP 1 1% PROLOG 1 1% FORTRAN 1 1% APL 1 1% LOGO 1 1% SMALLTALK 1 1% MODULA2 1 1% CORAL66 1 1% Hardware. STF/STE 50 83 Falcon 11 18% TT 0 0% Mega 1 1% Hard Drives 38 63% Scanners 13 21% Printers 24 40% Modems 10 16% Sound samplers 11 11% MIDI keyboards 1 1% Tabby pens 3 5% These figures are very rough, however, because the questionnaire did not ask for the type of computer used (STF/STFM/STE) and also most Falcons have already got hard drives built in. We also suspect that more members have printers but didn't bother to mention it. Although we cover C, Assembler and the various Basics fairly well we haven't published any Pascal code recently. If any of the Pascal users would like to send something in we would be happy to use it in a later issue. Also, the figures mentioned above refer to the information provided in the questionnaires. If you have upgraded your hardware please let us know so that we can keep our records updated. SAMPLED SOUND ------------- Next month we are publishing a number of articles on sound sampling on the STFM and STE. If anyone has something available on this subject, please send them in straight away so that we can start putting together the disk mag. PICTURE IMAGES -------------- In the November issue we will be publishing some articles on encoding and decoding various picture file formats. If you have written any code in any language on this subject, please send it in as soon as possible. DISK FORMAT ----------- Due to the large amount of data on this disk we had to format it with 10 sectors per track (80 tracks). Please bear this in mind if making copies of the disk. LETTERS ------- We would like to publish more letters in the correspondence section so when you return a disk please include some comments if you can. A programming query, what you would like to see on future disks or whatever. We also still need articles for future issues so if you have not sent anything in yet and there is something you think you can contribute, please send it in when you can. The ICTARI group relies almost entirely on its members for its material so if nobody sends anything in we will not have anything to publish. ---------------------------------------------------------------------- CORRESPONDENCE ============== To: GNU C and C++ GURUS. From: Jim Ford I am using GNU C and C++ (versions 2.1) and have run into some problems that you gurus out there might have some answers to. 1: Using the 'curses' library, I can't get the 'scanw' function or its relatives 'wscanw' and 'mvscanw' to work. The following code demonstrates the problem:- int main(void) { char ch = 'A'; initscr(); erase(); mvprintw(LINES - 1, 0, "Enter a char: "); refresh(); scanw("%c", &ch); mvprintw(10, 10, "The char was:%c", ch); refresh(); endwin(); return 0; } Whatever the input, 'A' is always printed. If 'char' is not initialised then garbage is printed. The same problem occurs with other data types. A 'workaround' for this problem is to get the data using 'wgetstr' and convert the string to a double using 'atof()', but I'd rather have a proper fix for the problem so I don't have to remember not to use 'scanw'. 2: I'd like to use the 'curses' library with C++ using the C++ idiom, but when I include the 'xcurses.h' header the preprocessor doesn't like what it finds and typically reports:- 'xcurses.h:88 macro 'getyx' used with only 2 args' The problem appears to be that when macro substitution, invoked by the 'curses.h' header (included by 'xcurses.h') takes place, the preprocessor doesn't recognise that the functions are missing an argument because they are overloaded. This 'do nothing' code doesn't get past the preprocessor because of this:- #include int main (void) { return 0; } 3: The last problem relates to the C++ 'cin' function. I want to input a sequence of floating point numbers using a while loop. The code:- float number; while (cin >> number) { . . . } ought to work - 'cin >> number' should return an ostream object that is true as long as 'number' is of the expected type - in this case a float. If data of another type e.g. the char 'a' is input then the returned value is 0 and the loop terminates. What happens is that the floats are input OK, but when attempting to exit with a 'q' or other alpha, garbage is printed and the program crashes (2 bombs). I would be grateful for any advice or info where I can get copies of libraries with these problems fixed. ---------------------------------------------------------------------- To ICTARI From Mrten Lindstrm ICTARI seems to be exactly what I have been looking for. A forum for exchange of ideas, techniques and not least information. Finding information is, in my experience, the hardest part of programming. One needs information on the system (TOS and Atari computer) but as much, and harder to find, on the file formats and programming standards etc. that could make programs live and work in harmony with each other, and with each others data. So I am very much looking forward to the announced ICTARI effort to clarify sound on the Atari. Text formats: For anyone interested I could describe the Protext file format. I could also say something about the First Word and ST Writer formats, although someone else is bound to know more about these (but could perhaps fill me in). */ Would anyone be interested in these Word Processor formats, please let us know. We think the Rich Text Format (RTF) would be useful to publish so that anyone writing text editing programs could include this format. If anyone has a detailed description of RTF please send it in. ICTARI /* To Mike Barnard, ICTARI and all others ______________________________ Comments on the VBL interrupt. Mike Barnard explained most about the VBL interrupt in ICTARI 13, but made a request for some "gap-filling", and this is an attempt at that. Firstly, there should be no problems with using the stack in your VBL routines. Any VBL routine will always run in SUPERVISOR mode (even if your main program runs in user mode), and the ban in the books, against touching the USER stack pointer, must be just an advice that you don't, for any strange reason, use a command like "move A0,USP", since that may obviously create problems when execution is returned to the main program (in user mode) after the VBL. To the description of the VBL-interrupt I'd like to make the following additions (using the same numbering as Mike): 2 and 13. VBLSEM (Word at $452) is initialised at bootup to 1 (one). It is decreased (-1) at start and increased (+1) at end of each VBL. If the decrease makes VBLSEM negative (i.e. if it is 0 before VBL) the VBL will be skipped completely except for updating FRCLOCK (and restoring VBLSEM to what it was before the decrease). Thus, by subtracting one from VBLSEM, the VBL can be turned off, and by adding one it can be turned on again. And these "commands" can be nested - i.e. the actual turn-on will happen only when all routines (possibly including a VBL) that issued "turn-offs" are ready and have issued "turn-ons" again. 5. Screen mode and monitor type are checked as follows (on an ST/E): The hardware Video Shifter mode register (Byte at $FF8260) is read, and from this it is determined what resolution (high/medium/low) the screen is currently in. (The register - or its two lowest bits - will be 2 for high, 1 for medium and 0 for low.) A corresponding check is made of bit 7 in byte $FFFA01, which is hardware connected to a pin in the monitor port and will be zero if a mono-monitor is connected. In case of a mismatch between screen mode and monitor type, the screen mode is changed, i.e. written to byte $FF8260. (If the change is from high to a colour rez, the actual rez - low or medium - will be that of defshiftmod: Word at $44A. This change will be done immediately while a change from colour to high will be preceded by a pause of about 3 milliseconds.) After a change, the VBL will execute the "subroutine" pointed to by SWV_VEC (Long at $46E) which will actually be initialised simply to a computer reset (pointer to OS-start). 8. BOTH physical AND logical screen are set according to the one pointer in SCREENPT. In addition SCREENPT is not, unlike COLORPTR, automatically zeroed after being used. So I personally do not see why anyone would like to use it. (And I haven't seen that the system does either.) Use XBIOS call SETSCREEN instead. 9. The floppy VBL routines. Before these are run, the variable FLOCK (Word at $43E) is checked; if FLOCK is non-zero the floppy routines are skipped. (FLOCK signals that someone is accessing disks at the moment. It is set automatically by all system calls for reading/- writing disks, and should be checked and set - and cleared when ready - by any disk routine not using system calls.) The floppy routines do exactly the two things stated by Mike Barnard: a) Check for possible floppy disk change b) Deselect floppies when controller signals it has turned motor off. The first of these - a) - is actually a check of the write-protect flag for drive A and B (every 8th VBL, or every 16th VBL for each drive; this unremitting activity can be detected by anyone as a faint flicker in the drive lamp). If the write-protect flag is set, a note is made that the disk may have been taken out of the drive (thus leaving a "hole" where the write-protect tab is supposed to be), and that - when a disk-access is to be made after a certain time delay - a further check may have to be undertaken by TOS (a comparison of the disk serial number with the one read earlier). b) will only be done if the drives were used with a system disk call. (The VBL routine checks an internal flag before bothering to check the motor-on bit.) A routine that doesn't use system calls for disk access has to wait for the floppy controller to zero the motor-on bit (about a second after last access) and then deselect floppies itself. ---------------------------------------------------------------------- To *.* From Kevin Preece A request, I have written routines to perform 4-way hardware tile based scrolling on my STE, but now I would like to extend it to do 8- way scrolling. Does anyone have any routines to do this on an STE, or can anyone explain it in English? Book or Internet references would be fine. Thanks in advance. ---------------------------------------------------------------------- To Nick Bates and anyone else interested in C From Dick Teuber Last month I mentioned HiSofts C Interpreter program as a possible alternative to Lattice C. In case you haven't seen any magazine adverts lately, HiSoft are now selling the C Interpreter program for a mere 9.95 and since the manual alone is worth more than this I would suggest that now is the time to purchase it. Also the Lattice C 5.52 program and manuals are available for only 39.95 and Power BASIC for 19.95 which are also good bargains. */ Perhaps HiSoft should be paying us a commission for this hard selling. ICTARI */ ---------------------------------------------------------------------- To: Everyone From: Richard Evans When running Gulam under the VT52 emulator included with MagiC, the text cursor often vanishes when GEM programs return back to the CLI after execution. I thought that a simple program sending the VT52 enable cursor code (ESC e) would be enough to redisplay it. However, although this works sometimes, it appears that these text cursor codes are nested much in the way that the graf_mouse M_OFF and M_ON routines are, since I sometimes have to run my program 6 or more times in a row before the text cursor re-appears. Obviously this isn't much good. I know that the mouse cursor can be displayed from any depth by calling linea9 with INTIN[0]=0. Does anyone know if there is a similar call that will display the text cursor from any depth, or am I wrong in my assumptions altogether? P.S. I need the Kawai K4 driver for Lizard V1.0, If anyone has one, or knows how I can get one, please get in contact with me. Thanks. ---------------------------------------------------------------------- To ICTARI From Richard Davey (fog@walusoft.centron.com) Some problems with HiSoft Basic 2.10 = Why can I not use the HGT.T token file and use the GEMVDI library in the same program? I keep getting errors reporting I have redefined some functions, although I know it was nothing my code has done. Once I remove one or the other the code compiles fine but obviously does not run. = Does anyone know how to load and display a NEO picture on the screen with the correct palette installed on a Falcon? The picture appears but all hell breaks loose in the colour department. I tried using the PALETTE x,&hxxx command to set the palette to that of the picture but for some reason it still didn't work. Help anyone??? = Is there any way to include required files WITHIN the actual compiled PRG file. So for example if I had 5 text files, how could I have them already in memory instead of having to have them on disk and then load them up into the array? This would certainly tidy up my programs and also means a little more protection would be given over my data files which anyone can 'rip' at present. = My final problem is with DMA sound. I cannot seem to get the STESOUND library commands to work, this can't be due to my Falcon can it? After all they do share the same DMA chips. If someone has some example source code (and indeed a sample) to show me how to play a sampled sound via the DMA it would be very much appreciated. ---------------------------------------------------------------------- To ICTARI Fron Iain McLeod It would be nice to know what percentage of users own TTs, Falcons, STEs, etc.. What's the best way to map a bitmap on to a polygon ? Using C or Assembly - or even DSP. */ See above for membership survey. We presume you want to display a bitmap image within an irregular polygon in the same way that the GEM fill function does. Does anyone have a suitable algorithm or source code for this operation ? ICTARI. /* ---------------------------- End of file ----------------------------- ICTARI PROGRAMMERS USER GROUP ============================= METHODS OF PAYMENT We will be using two basic systems for exchanging disks. You can either send a disk to us each month together with the return postage or you can send money and we will provide a disk from that. If you send a disk please erase any old data on it so that we don't have to check through it again to see if there is anything new being returned. If possible some new material for the magazine would be very useful, even if it is just a letter about some aspect of programming, requests for help or comments about the group. With the disk please enclose two second class stamps (or the money equivalent) to pay for the return postage and packing. Don't forget to write your name and address on the disk or we may not know where to send it. Alternatively you can send 75p for each month that you wish to pay for in advance. Any cheques or postal orders should be made payable to :- Mr P D Hibbs. Of the two methods, we would prefer the first one because this means we don't have to keep buying dozens of disks each month and also it is more likely that members will put something on the disk for the magazine. The only slight drawback is that members have to remember to return the disk each month. We would suggest that you buy a book of stamps and a packet of envelopes in readiness and also return the disk as soon as you can after you receive it to avoid any problems. If you do send money and then send a disk with a contribution for the magazine, your credit will be adjusted accordingly. The credit system means that a disk+stamps or 75p is worth one credit. When your credit rating is zero you will be informed so that you can send more disks/money as you wish. Back issues of the magazine are available from us for 1 per disk. The address for ICTARI is :- 63 Woolsbridge Road, Ashley Heath, Ringwood, Hants, BH24 2LX. (Please note that this document will not change each month unless mentioned in the ICTARI.TXT document file) ----------------