diff --git a/programs/games/codemaster/ReadMe.txt b/programs/games/codemaster/ReadMe.txt new file mode 100644 index 0000000000..a82e78f290 --- /dev/null +++ b/programs/games/codemaster/ReadMe.txt @@ -0,0 +1,39 @@ +3 GAMES FOR KOLIBRI (AND WINDOWS) + +Binary Master: Fun game for programmers. +Practice binary arithmetic. + +Hang Programmer: Teaches English words/phrases +related to programming + +Puzzle Challenge: Custom game for Kolibri. +Tests your visual attention to fine details. +If you solve the puzzle, lines will disappear +and there will be a message. Look close into +the clouds and direction of lights. + +Written in FASM(1) macros, Abakis advanced language ++ library, 7,000+ lines, custom graphics and fonts. +Spent the most time on this library. + +* Created by codemaster (codemazt3r@gmail.com) +* Educational games made specifically for programmers. +* Very clear professional style, good examples +for the community. +* First portable games written in FASM. Assembles +on/for both Kolibri and Windows with the same +source just by changing the first 1-2 lines +in A.INC. Allows programmers to create games +_for_Kolibri_ on Windows +* 24-27 years of programming experience, +recreationally in my freetime. Made 1,000s of +programs, given 100s of examples away for free +while poor. Never been paid. + +Thanks. Happy new years! +=========================================================== + +(1) FASM is the abbreviation for Flat ASseMbler, open-source +assembly language being developed by Tomasz Grysztar. +FASM is available for Windows, DOS, Linux and KolibriOS. +You can download FASM from: http://www.flatassembler.net/ \ No newline at end of file diff --git a/programs/games/codemaster/a.inc b/programs/games/codemaster/a.inc new file mode 100644 index 0000000000..333a76b2db --- /dev/null +++ b/programs/games/codemaster/a.inc @@ -0,0 +1,47 @@ +; $$$$$$$$$$$$$$$$$$$ ABAKIS $$$$$$$$$$$$$$$$$$$$$ +; ************** STAR^2 SOFTWARE ***************** +; ???????????????????????????????????????????????? + +; true portability: windows + kolibri + +; define cpu intel windows + define cpu intel kolibri +; define cpu arm mobile + +; current directory. optional '/usbhd0/1' +; prefix to assemble+run from SD in kolibri + + CD fix '' +; CD fix '/usbhd0/1' + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +MAIN.ICON fix '' + +SCREEN.W = WINDOW.W ; 1024 +SCREEN.H = WINDOW.H ; 768-32 +SCREEN.BPP = 32 +SCREEN.PI = SCREEN.W*(SCREEN.BPP/8) + +match x =windows, cpu { + format PE GUI 4.0 + entry !main + stack 8*KB + heap 16*KB + include CD#'/include/a.inc' + WINDOW.X=0 + WINDOW.Y=0 +} + +match x =kolibri, cpu { + format binary as "" + use32 + org 0 + db 'MENUET01' + dd 1, !main, end.code,\ + 4*MB, 32*KB, 0, 0 + postpone \{ end.code: \} + include CD#'/include/a.inc' + WINDOW.X=(1024/2)-(WINDOW.W/2) + WINDOW.Y=(768/2)-(WINDOW.H/2) +} \ No newline at end of file diff --git a/programs/games/codemaster/binary_master.asm b/programs/games/codemaster/binary_master.asm new file mode 100644 index 0000000000..3b506043f9 --- /dev/null +++ b/programs/games/codemaster/binary_master.asm @@ -0,0 +1,299 @@ +; BINARY MASTER + +WINDOW.W=360 +WINDOW.H=492 + +include 'a.inc' + +text t(256), title.t='Binary Master: %hh' + +text help.t=+\ + 'Fun Game for Programmers.' RET\ + 'Click BITs. Count in binary.' RET\ + 'Match the decimal number' RET\ + 'in the red box to make rows' RET\ + 'disappear. Press any key.' RET\ + 'r=Reset. p=Pause. Esc=exit' + +text pause.t=+\ + 'Paused. Press p to continue' RET\ + 'or r=Reset. Esc=exit' + +text game.over.t=+\ + 'Game over. Score: %hh.' RET\ + 'Press any key' + +align + +integer scene, score +numeric SCENE.*, TITLE, PLAY,\ + PAUSE, GAME.OVER +numeric EASY=5000, NORMAL=4000, HARD=2000 + +BOX board, my.box +integer my.n, red.n, magic.n=10101101b +integer cbit.x, cbit.y, bits.h +numeric BIT.*, W=32, H=48 + +text my.numbers(8+4), red.numbers(8+4) + +FONT main.font='font' + +IMAGE bits.i='bits', bit1.i='1',\ + bit0.i='0', close.i='x' + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +function random.byte + locals n + .r: + random 3 + if r0<2 + random 16 + else.if r0=2 + random 128 + else.if r0=3 + random 255 + end + . n=r0 + text.find red.numbers, n + if true, go .r, end + . r0=n + if false, r0++, end +endf + +function reset.game + locals n, p + . score=0, bits.h=1 + memory.zero my.numbers, 12 + memory.zero red.numbers, 12 + . n=8, p=red.numbers + loop n + random.byte + . r1=p, *r1++=r0, p=r1 + endl + set.box board, 4, 70, BIT.W*8, BIT.H*8 + . scene=SCENE.TITLE +endf + +function on.create + set.font main.font + set.timer NORMAL + reset.game +endf + +function remove.byte, t, i + locals n + alias p=r0, q=r1, x=r2 + if i=7, go .new, end + . p=t, p+i, q=p, q++, x=7, x-i, n=x + loop n, *p++=*q++, endl + .new: + . p=my.numbers, *(p+7)=0 + random.byte + . q=red.numbers, *(q+7)=r0 +endf + +function remove.row, i + remove.byte my.numbers, i + remove.byte red.numbers, i + . bits.h-- + if bits.h<1, bits.h=1, end +endf + +function check.numbers + locals i + . i=0 + while i<8, r0=my.numbers, r0+i + . r1=*r0, r0=red.numbers + . r0+i, r2=*r0 + if r1=r2, score+r1 + remove.row i + return 1 + end + . i++ + endw +endf 0 + +function draw.board + locals i, n, x, y, w, h + draw.image bits.i, 4, 35 + draw.image bits.i, 4, 457 + . x=0, y=0, w=32, h=48 + while y<8, x=0 + while x<8 + . r0=x, r0*w, r0+board.x + . r1=y, r1*h, r1+board.y + set.box my.box, r0, r1, w, h + draw.box my.box, BLACK, GRAY + . x++ + endw + . r0=x, r0*w, r0+board.x + . r1=y, r1*h, r1+board.y + set.box my.box, r0, r1, 48, h + draw.box.o my.box, WHITE + . my.box.x+48 + draw.box.o my.box, RED + . r0=y, r1=8, r1-bits.h + if r0>=r1 + . r0=my.numbers, r1=y, r2=8 + . r2-bits.h, r1-r2, r0+r1 + . r1=*r0, my.n=r1 + . r0=red.numbers, r1=y, r2=8 + . r2-bits.h, r1-r2, r0+r1 + . r1=*r0, red.n=r1 + u2t my.n, t + . my.box.x-40, my.box.y+11 + draw.text t, my.box.x, my.box.y + . my.box.x+44 + u2t red.n, t + draw.text t, my.box.x, my.box.y + end + . y++ + endw +endf + +function draw.bit, n, x, y + if n + draw.image bit1.i, x, y + else + draw.image bit0.i, x, y + end +endf + +function draw.byte, n, x, y + locals i + . i=8 + loop i, r0=n, r1=i, r1--, r0>>cl, r0&1 + draw.bit r0, x, y + . x+BIT.W + endl +endf + +function draw.my.numbers + locals i, n, y + . i=bits.h, y=404 + loop i, r0=my.numbers, r0+i, r0-- + . r0=*r0, n=r0 + draw.byte n, 4, y + . y-BIT.H + endl +endf + +function draw.title.scene + draw.text help.t, 16, 130 + draw.byte magic.n, 50, 300 +endf + +function draw.play.scene + draw.board + draw.my.numbers +endf + +function draw.pause.scene + draw.text pause.t, 16, 130 + draw.byte magic.n, 50, 300 +endf + +function draw.game.over + print t, game.over.t, score + draw.text t, 44, 170 + draw.byte magic.n, 50, 300 +endf + +function on.draw + locals x, y, w, h + clear.screen BLACK + print t, title.t, score + draw.text t, 4, 4 + draw.image close.i, 324, 4 + . r0=screen.w, r0-- + . r1=screen.h, r1-- + draw.outline 0, 0, r0, r1, GRAY + if scene=SCENE.TITLE + draw.title.scene + else.if scene=SCENE.PLAY + draw.play.scene + else.if scene=SCENE.PAUSE + draw.pause.scene + else.if scene=SCENE.GAME.OVER + draw.game.over + end +endf + +function on.key + if key.event='c' + if scene=SCENE.TITLE + . scene=SCENE.PLAY + go .draw + end + if scene=SCENE.GAME.OVER + go .reset + end + if key='r' + .reset: + reset.game + go .draw + end + if key='p' + .pause: + if scene=SCENE.PLAY + . scene=SCENE.PAUSE + else.if scene=SCENE.PAUSE + . scene=SCENE.PLAY + end + go .draw + end + .draw: + render + end +endf + +function on.mouse + if.select board + . r0=mouse.x, r0-WINDOW.X, r0-board.x + . r1=BIT.W, r0/r1, cbit.x=r0 + . r0=mouse.y, r0-WINDOW.Y, r0-board.y + . r1=BIT.H, r0/r1, cbit.y=r0 + if mouse.event='c' + . r0=cbit.y, r1=8, r1-bits.h + if r0>=r1, r0=my.numbers, r1=cbit.y + . r2=8, r2-bits.h, r1-r2, r0+r1 + . r3=*r0, r2=1, r1=7, r1-cbit.x + . r2<SCENE.PLAY + reset.game + . scene=SCENE.PLAY + end + .draw: + render + end +endf + +function on.timer + if scene<>SCENE.PLAY + return + end + if mouse.1, return, end + if bits.h<8, bits.h++ + else + . scene=SCENE.GAME.OVER + end + render +endf + +function on.exit + ; ... +endf \ No newline at end of file diff --git a/programs/games/codemaster/hang_programmer.asm b/programs/games/codemaster/hang_programmer.asm new file mode 100644 index 0000000000..9603e77b9a --- /dev/null +++ b/programs/games/codemaster/hang_programmer.asm @@ -0,0 +1,392 @@ +; HANG PROGRAMMER + +WINDOW.W=720 +WINDOW.H=512 + +include 'a.inc' +include 'include/words.txt' + +text title.t(32)='Hang Programmer' +text t(256), t2(256) + +integer scene +numeric SCENE.*, TITLE, PLAY, GAME.OVER + +integer guesses, word.index +BOX my.box + +text word.t(64), used.letters(16) + +align + +IMAGE8 \ + board.i='board', logo.i='logo',\ + stand1.i='stand1', stand2.i='stand2',\ + head.i='head', body.i='body',\ + arm1.i='arm1', arm2.i='arm2',\ + leg1.i='leg1', leg2.i='leg2',\ + smile.i='smile', money.i='money',\ + prize.i='1000' + +IMAGE close.i='x' + +text abc='ABCDEFGHIJKLM', xyz='NOPQRSTUVWXYZ' + +text help.t='CLICK TO START',\ + winner.t='WINNER', looser.t='LOOSER' + +text example.t='DYNAMIC BINARY TRANSLATION' + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +function reset.game + . guesses=0 + text.zero used.letters + text.zero word.t + . r0=word.index, r0*4, r0+words.pa + . (u32) r0=*r0 + text.copy word.t, r0 + . word.index++ + if word.index>=(N.WORDS-1) + . word.index=0 + end +endf + +; exchange pointer array elements. +; words.pa[a] and [b] + +function exchange.words, a, b + alias pa=r0, i=r0, p=r1, q=r2, x=r3 + . pa=words.pa + . p=a, p*4, p+pa, q=b, q*4, q+pa + . (u32) i=*p, (u32) x=*q + . (u32) *p=x, (u32) *q=i +endf + +; do this once when game begins. +; initialize pointer array to words[0-n] +; then randomize indices + +function initialize + locals i, n, j + alias p=r0, x=r1 + . p=words.pa, i=0, n=N.WORDS + loop n, x=i, (u32) x=*(words.ta+r1*4) + . (u32) *p++=x, i++ + endl + . i=N.WORDS + loop i + get j=random (N.WORDS-1) + exchange.words i, j + endl + . word.index=0 ; random (N.WORDS-1) +endf + +; is winner? if all characters in +; word.t have been used. return +; winner.t/looser.t + +function is.winner + locals i, q, n, win + alias p=r0, c=r1 + . q=word.t + get n=text.n q + . win=1 + loop n, p=q, c=*p++ + if c<>' ' + text.find used.letters, c + if false + . win=0, break + end + end + . q++ + endl + if win, r0=winner.t + else, r0=looser.t, end +endf + +function on.create + initialize + reset.game +endf + +function insert.c, c + if c>='a', c-32, end + if c<'A', return, end + if c>'Z', return, end + text.find used.letters, c + if true, return, end + text.attach.c used.letters, c + is.winner + if r0=winner.t + go .reset + end + text.find word.t, c + if true, return, end + . guesses++ + if guesses=6 + .reset: . scene=SCENE.GAME.OVER + end +endf + +; special "my" font + +align +alphabet.p: dd \ + a.i, b.i, c.i, d.i, e.i, f.i, g.i, h.i, i.i,\ + j.i, k.i, l.i, m.i, n.i, o.i, p.i, q.i, r.i,\ + s.i, t.i, u.i, v.i, w.i, x.i, y.i, z.i + +irps _,\ + a b c d e f g h i j k l m \ + n o p q r s t u v w x y z { + IMAGE8 _#.i='a/'#`_ +} + +function index.my.c, c + . r0=c, r0-'A', r0*4, r0+alphabet.p + . (u32) r0=*r0 +endf + +function get.my.cw, c + if c=' ', return 0, end + index.my.c c + . (u32) r0=*(r0+?image.w) +endf + +function get.my.tw, t + locals n, w + alias p=r0, c=r1 + get n=text.n t + . w=0 + loop n, p=t, c=*p + get.my.cw c + . w+r0, t++ + endl +endf w + +function draw.my.c, c, x, y, co + locals im, w + if c=' ', return, end + get im=index.my.c c + . (u32) r1=*(r0+?image.w), w=r1 + draw.image.v8 im, x, y, co +endf w + +function draw.my.text, t, x, y + locals p, n + get n=text.n t + . p=t + loop n, r0=p, r0=*r0 + draw.my.c r0, x, y, WHITE + . x+r0, x+4, p++ + endl +endf + +function draw.my.word, t, x, y + locals p, n, w, c, co + get n=text.n t + . p=t + loop n, r0=p, r0=*r0, c=r0 + get w=get.my.cw c + text.find used.letters, c + if true + . r0=x, r0+18, r1=w, r1/2, r0-r1 + draw.my.c c, r0, y, WHITE + end + . r0=x, r0+2, r1=y, r1+48 + draw.box r0, r1, 32, 3, WHITE + . r0=36, x+r0, p++ + endl +endf + +function draw.message + locals n, x, y, w + get n=text.count.w word.t + if n=0, n=1, end + set.source word.t + set.token t + . x=250, y=80 + loop n + skip.space + copy.until C.SPACE + set.box my.box, 250, 65, 390, 220 + text.n t + . r0*36, w=r0, r0=my.box.x, r0+195 + . r1=w, r1/2, r0-r1 + draw.my.word t, r0, y + . y+70 + endl +endf + +function draw.letters, t, x, y + locals n, p, c, co + get n=text.n t + . p=t + loop n, r0=p, r0=*r0, c=r0 + index.my.c c + . r0+?image.box + memory.copy my.box, r0, 16 + . my.box.x=x, my.box.y=y + if.select my.box + if mouse.1 + insert.c c + end + end + . co=WHITE + text.find used.letters, c + if true, co=409040h, end + draw.my.c c, x, y, co + . r0+4, x+r0, p++ + endl +endf + +function draw.alphabet + draw.letters abc, 255, 308 + draw.letters xyz, 248, 370 +endf + +function draw.man + locals x, y + . x=40, y=62 + . alpha.bias=A.DARK + draw.image.v.8 stand1.i, x, y, WHITE + . r0=x, r0+27 + draw.image.v.8 stand2.i, r0, y, WHITE + . alpha.bias=A.DARKER + if guesses>0 + . r0=x, r0+80, r1=y, r1+40 + draw.image.v.8 head.i, r0, r1, WHITE + end + if guesses>1 + . r0=x, r0+95, r1=y, r1+150 + draw.image.v.8 body.i, r0, r1, WHITE + end + if guesses>2 + . r0=x, r0+70, r1=y, r1+150 + draw.image.v.8 arm1.i, r0, r1, WHITE + end + if guesses>3 + . r0=x, r0+143, r1=y, r1+150 + draw.image.v.8 arm2.i, r0, r1, WHITE + end + if guesses>4 + . r0=x, r0+87, r1=y, r1+228 + draw.image.v.8 leg1.i, r0, r1, WHITE + end + if guesses>5 + . r0=x, r0+118, r1=y, r1+228 + draw.image.v.8 leg2.i, r0, r1, WHITE + end + . alpha.bias=0 +endf + +function draw.hang.man + . guesses=6 + draw.man + . guesses=0 +endf + +function draw.winner + locals x, y + . alpha.bias=A.DARKER + . x=40, y=62 + . r0=x, r0+80, r1=y, r1+40 + draw.image.v.8 head.i, r0, r1, WHITE + . r0=x, r0+95, r1=y, r1+150 + draw.image.v.8 body.i, r0, r1, WHITE + . r0=x, r0+67, r1=y, r1+87 + draw.image.viy.8 arm1.i, r0, r1, WHITE + . r0=x, r0+147, r1=y, r1+87 + draw.image.viy.8 arm2.i, r0, r1, WHITE + . r0=x, r0+87, r1=y, r1+228 + draw.image.v.8 leg1.i, r0, r1, WHITE + . r0=x, r0+118, r1=y, r1+228 + draw.image.v.8 leg2.i, r0, r1, WHITE + . alpha.bias=A.LIGHT + draw.image.v.8 smile.i, 547, 307, WHITE + draw.image.v.8 smile.i, 310, 307, WHITE + . alpha.bias=A.DARK + draw.image.v.8 money.i, 547, 342, 0DDFFDDh + draw.image.v.8 prize.i, 367, 377, WHITE + . alpha.bias=0 +endf + +function draw.title.scene + draw.my.text help.t, 237, 100 + draw.hang.man +endf + +function draw.play.scene + draw.message + draw.alphabet + draw.man +endf + +function draw.game.over + locals p + get p=is.winner + draw.my.text p, 362, 308 + draw.message + if p=winner.t + draw.winner + else + draw.hang.man + end +endf + +function on.draw + clear.screen 283D25h + draw.image.8 board.i, 0, 0 + . alpha.bias=A.DARKER + draw.image.v.8 logo.i, 240, 32, WHITE + . alpha.bias=0 + if scene=SCENE.TITLE + draw.title.scene + else.if scene=SCENE.PLAY + draw.play.scene + else.if scene=SCENE.GAME.OVER + draw.game.over + end + draw.image close.i, 663, 28 +endf + +function on.key + if key.event='k' + if scene=SCENE.PLAY + insert.c key + else.if scene=SCENE.TITLE + reset.game + . scene=SCENE.PLAY + else.if scene=SCENE.GAME.OVER + reset.game + . scene=SCENE.TITLE + end + render + end +endf + +function on.mouse + if mouse.event='c' + . r0=&close.i.x + if.select r0 + exit + end + if scene=SCENE.TITLE + reset.game + . scene=SCENE.PLAY + else.if scene=SCENE.GAME.OVER + reset.game + . scene=SCENE.TITLE + end + render + end +endf + +function on.timer + ; ... +endf + +function on.exit + ; ... +endf \ No newline at end of file diff --git a/programs/games/codemaster/include/a.inc b/programs/games/codemaster/include/a.inc new file mode 100644 index 0000000000..c604b71a2d --- /dev/null +++ b/programs/games/codemaster/include/a.inc @@ -0,0 +1,26 @@ +match =intel x, cpu { + include 'language.inc' +} + +include 'memory.inc' +include 'text.inc' + +match x =windows, cpu + { include 'draw.inc' } + +match x =kolibri, cpu + { include 'drawk.inc' } + +match x =windows, cpu + { include 'image.inc' } + +match x =kolibri, cpu + { include 'imagek.inc' } + +include 'font.inc' + +match x =windows, cpu + { include 'system.inc' } + +match x =kolibri, cpu + { include 'systemk.inc' } \ No newline at end of file diff --git a/programs/games/codemaster/include/box.inc b/programs/games/codemaster/include/box.inc new file mode 100644 index 0000000000..4f0c915982 --- /dev/null +++ b/programs/games/codemaster/include/box.inc @@ -0,0 +1,218 @@ +; $$$$$$$$$$$$$$$$$$$ ABAKIS $$$$$$$$$$$$$$$$$$$$$ +; *************** STAR^2 SOFTWARE **************** +; ??????????????????? BOX.INC ???????????????????? + +screen.w equ [!screen.w] ; forward reference +screen.h equ [!screen.h] ; restore at end + +macro BOX [p] { + forward p: integer p#.x, p#.y, p#.w, p#.h +} + +;;;;;;;;;;;;;;;;;; VISIBILITY ;;;;;;;;;;;;;;;;;;;; + +; is visible or partially? return 0 if +; completely invisible + +function visible, x, y, w, h + if w<=0, go .0, end + if h<=0, go .0, end + . r0=x, r1=y + if r0>=screen.w, go .0, end + if r1>=screen.h, go .0, end + . r0+w, r1+h + if r0<0, go .0, end + if r1<0, go .0, end + return 1 + .0: +endf 0 + +;;;;;;;;;;;;;;; POINT INSIDE BOX? ;;;;;;;;;;;;;;;; + +; x>=bx and x=by and y=screen.w, go .0, end + if r1<0, go .0, end + if r1>=screen.h, go .0, end + return 1 + .0: +endf 0 + +; 2-DO: convert to ABAKIS... + +; clip.line o, &x, &y, &n. return 0 if +; completely invisible or adjust x/y/n +; if partially in/visible. o/rientation= +; 'h'/'v'. n=w/h. parameters sent by +; reference + +function clip.line, o, x, y, n + push r6 r7 r3 + . r6=x, r7=y, r3=n,\ + r0=[r6], r2=[r7], r1=[r3] + + ; if invisible, return 0 + + cmp r0, screen.w ; x>=screen.w? + jge .0 + cmp r2, screen.h ; y>=screen.h? + jge .0 + cmp r1, 0 ; w/h<=0? + jle .0 + cmp o, 0 ; orientation? + jne .vertical + .horizontal: + cmp r2, 0 ; y<0? + jl .0 + cmp r2, screen.h ; y>=screen.h? + jge .0 + . r2=r0, r2+r1 ; x+w<0? + cmp r2, 0 + jl .0 + if r0<0 ; if x<0 + . r0+r1,\ ; { w=x+w, x=0 } + [r3]=r0,\ + dword [r6]=0 + end + cmp r2, screen.w ; if x+w>=screen.w + jl @f ; { w=screen.w-x } + . r0=screen.w,\ + r0-[r6], [r3]=r0 + @@: + jmp .yes + .vertical: + cmp r0, 0 ; x<0? + jl .0 + cmp r0, screen.w ; x>=screen.w? + jge .0 + . r1=r2,\ + r1+[r3] ; y+h<0? + cmp r1, 0 + jl .0 + if r2<0 ; if y<0 + . [r3]=r1,\ ; { h=y+h, y=0 } + dword [r7]=0 + end + cmp r1, screen.h ; if y+h>=screen.h + jl .yes ; { h=screen.h-y } + . r0=screen.h,\ + r0-[r7], [r3]=r0 + .yes: . r0=YES + jmp .e + .0: . r0=NO + .e: + pop r3 r7 r6 +endf + +; clip.scanline &s, &x, &y, &w does the same +; as clip.line but sets the s/tart offset of +; pixels and adjusts w correctly. this only +; applies to scanlines, not one-color lines + +function clip.scanline, s, x, y, w + push r3 + . r3=s,\ + dword [r3]=0,\ ; offset=0 initially + r0=x, r0=[r0] + cmp r0, screen.w ; x>=screen.w? + jge .0 + . r2=y, r2=[r2] + cmp r2, screen.h ; y>=screen.h? + jge .0 + cmp r2, 0 ; y<0? + jl .0 + cmp r2, screen.h ; y>=screen.h? + jge .0 + . r1=w, r1=[r1],\ + r3=r0, r3+r1 ; x+w<0? + cmp r3, 0 + jl .0 + cmp r3, screen.w ; if x+w>=screen.w + jl @f ; w=screen.w-x + . r1=screen.w,\ + r1-r0, r3=w,\ + [r3]=r1 + @@: + cmp r0, 0 ; if x<0, clip + jg .e + . r2=r0, -r2, r2*4 ; index=-x * scale + . r3=s, [r3]=r2,\ + r1=w, [r1]+r0,\ ; w+=x + r3=x, dword [r3]=0 ; x=0 + . r0=YES + jmp .e + .0: . r0=NO + .e: + pop r3 +endf + +;;;;;;;;;;;;;;;;;;;;;;; BOX ;;;;;;;;;;;;;;;;;;;;;; + +; BOX structure... + +virtual at 0 + ?box: + .x dd 0 + .y dd 0 + .w dd 0 + .h dd 0 +END virtual + +align + +box: + integer .x, .y, .w, .h + +macro set.box box, x, y, w, h { + . box#.x=x, box#.y=y,\ + box#.w=w, box#.h=h +} + +function move.box.right, b, n + . r0=b, r1=n, r0+?box.x, [r0]+r1 +endf + +function move.box.down, b, n + . r0=b, r1=n, r0+?box.y, [r0]+r1 +endf + +function move.box.r, b + . r0=b, r1=[?box.w+r0], r0+?box.x, [r0]+r1 +endf + +function move.box.d, b + . r0=b, r1=[?box.h+r0], r0+?box.y, [r0]+r1 +endf + +restore screen.w, screen.h \ No newline at end of file diff --git a/programs/games/codemaster/include/color.inc b/programs/games/codemaster/include/color.inc new file mode 100644 index 0000000000..5828561209 --- /dev/null +++ b/programs/games/codemaster/include/color.inc @@ -0,0 +1,227 @@ +; $$$$$$$$$$$$$$$$$$$ ABAKIS $$$$$$$$$$$$$$$$$$$$$ +; *************** STAR^2 SOFTWARE **************** +; ?????????????????? COLOR.INC ??????????????????? + +COLOR fix integer +PIXEL fix integer + +; rgb r, g, b +; get.rgb c, &r, &g, &b +; set.rgb &c, r, g, b + +; mix a, b, n ; alpha combination +; lightness c, n ; adjust light/darkness. n=+/- +; colorize a, b, n ; in/decrease r/g/b +; grayscale c ; convert to grayscale +; inversion c ; invert +; channelize a, b ; split r/g/b channel + +; PAL1 = I (2) +; PAL2 = II (4) +; PAL4 = IIII (16) +; PAL8 = IIIIIIII (256) +; PAL10 = IIIIIIIIII (1K, 1024) +; PAL12 = IIIIIIIIIIII (4K, 4096) +; RGB15 = X.RRRRR.GGGGG.BBBBB (32768, 32K) +; RGB16 = RRRRR.GGGGGG.BBBBB (65535, 64K) +; RGB24 = R8.G8.B8 (16777216, 16M) +; RGB32 = A8.R8.G8.B8 (same with alpha) + +; "standard" colors + +numeric BLACK=0, WHITE=0FFFFFFh,\ + RED=0FF0000h, GREEN=0FF00h, BLUE=0FFh,\ + CYAN=BLUE+GREEN, MAGENTA=RED+BLUE,\ + YELLOW=RED+GREEN, GRAY32=202020h,\ + GRAY64=404040h, GRAY128=808080h,\ + GRAY192=0C0C0C0h, GRAY224=0E0E0E0h,\ + GRAY=808080h, GRAY25=404040h,\ + GRAY50=GRAY, GRAY75=0C0C0C0h + +; personally selected "cool colors". includes +; nature colors for custom brushes/textures - +; grass, dirt, etc + +numeric \ + RED.CHERRY=720E21h, FIRE.RED=821100h,\ + RED.ROSE=7B0024h, DARK.RED=470707h,\ + POWER.BLUE=0B008Ah, ROYAL.BLUE=140357h,\ + BEACH.BLUE=0362C1h, DARK.BLUE=070720h,\ + ICE.BLUE=8ACAE2h, SKY.BLUE=0A3A3F9h,\ + CLOUD.BLUE=11A3F5h, BABY.BLUE=4F77FFh,\ + LILAC=0DA4FE7h, PURPLE=700E7Fh,\ + VIOLET=08C047Ah, DARK.VIOLET=2D0327h,\ + LIME.GREEN=8CE007h, SEA.GREEN=72CC90h,\ + LEAF.GREEN=7EBB1Dh, GRASS.GREEN=507B11h,\ + DARK.GREEN=0B1F0Fh, EMERALD.GREEN=1C3E14h,\ + PINK=0FF67A0h, PASTEL.PINK=0F7A7CFh,\ + ROSE.PINK=0FB57A0h, PINK.FLESH=0FBD7BDh,\ + FLESH=0FCEEDEh, MEDIUM.FLESH=0EF9F5Dh,\ + DARK.FLESH=0E87D2Eh, LIGHT.BROWN=0C77237h,\ + DARK.BROWN=4D2207h, ORANGE.BROWN=0B04700h,\ + RED.BROWN=782712h, SAND=0D1A877h,\ + COOL.GRAY=837B9Bh, LILAC.GRAY=0E1ABFFh,\ + METAL.GRAY=0AEBEBEh, LIGHT.GRAY=0E7E7E7h + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +; construct RGB 24/32BPP. assumes 0-255 + +function rgb, r, g, b + . r0=r, r0<<16, r1=g, r1<<8,\ + r0|r1, r2=b, r0|r2 +endf + +macro rgbm r, g, b { + . r0=r, r0<<16, r1=g, r1<<8,\ + r0|r1, r0|b +} + +; with truncation. ensure 0-255 + +function rgbc, r, g, b + . r0=r, r0&0FFh, r0<<16,\ + r1=g, r1&0FFh, r1<<8, r0|r1,\ + r2=b, r2&0FFh, r0|r2 +endf + +; extract rgb components from color +; parameters: c, &r, &g, &b. addresses + +function get.rgb, c, r, g, b + . r0=c,\ + r1=r0, r1>>16, r1&0FFh, r2=r, [r2]=r1,\ + r1=r0, r1>>8, r1&0FFh, r2=g, [r2]=r1,\ + r1=r0, r1&0FFh, r2=b, [r2]=r1 +endf + +; set rgb of color. parameters: &c, r, g, b. +; c is address + +function set.rgb, c, r, g, b + rgbm r, g, b + . r1=c, [r1]=r0 +endf + +;;;;;;;;;;;;;;;;;;; CLIP RGB ;;;;;;;;;;;;;;;;;;;;; + +; clip RGB components, 0-255. if cmax, c=max. all parameters are address + +function clip.c, c + . r0=c, r0=[r0] + if r0<0, r0=0 + else.if r0>255 + r0=255 + end + . r2=c, [r2]=r0 +endf + +function clip.rgb, r, g, b + clip.c r + clip.c g + clip.c b +endf + +;;;;;;;;;;;;;;;;;;;;; ALPHA ;;;;;;;;;;;;;;;;;;;;;; + +; mix a, b, n - alpha blend/combination. +; n=0-255. (((s-d)*n)/256)+d + +function mix, a, b, n + locals sr, sg, sb, dr, dg, db + . r0=a, r2=b,\ + r1=r0, r1>>16, r1&0FFh, sr=r1,\ + r1=r0, r1>>8, r1&0FFh, sg=r1,\ + r1=r0, r1&0FFh, sb=r1,\ + r1=r2, r1>>16, r1&0FFh, dr=r1,\ + r1=r2, r1>>8, r1&0FFh, dg=r1,\ + r1=r2, r1&0FFh, db=r1,\ + r0=sr, r0-dr, r0*n, r0>>8, r0+dr,\ + r1=sg, r1-dg, r1*n, r1>>8, r1+dg,\ + r2=sb, r2-db, r2*n, r2>>8, r2+db,\ + r0<<16, r1<<8, r0|r1, r0|r2 +endf + +; mix25/50/75 a, b, n - much faster +; if alpha is constant 25%/50%/75% +; ((a&0FEFEFEh)>>1)|((b&0FEFEFEh)>>1) + +macro mix50 a, b { + . r0=a, r2=b, r1=0FEFEFEh,\ + r0&r1, r0>>1, r2&r1, r2>>1, r0|r2 +} + +function mix25, a, b + mix50 a, b + mix50 r0, b +endf + +function mix75, a, b + mix50 a, b + mix50 a, r0 +endf + +;;;;;;;;;;;;;;;; COLOR OPERATIONS ;;;;;;;;;;;;;;;; + +macro operation name, [ps] { + common + function name, ps + locals r, g, b + . r0=&r, r1=&g, r2=&b + get.rgb c, r0, r1, r2 + ; ... +} + +macro endo { + ; ... + . r0=&r, r1=&g, r2=&b + clip.rgb r0, r1, r2 + rgb r, g, b + endf +} + +; adjust light/darkness. n=+/- + +operation lightness, c, n + . r1=n, r+r1, g+r1, b+r1 +endo + +; in/decrease r/g/b + +operation colorize, c, x, n + . r1=n + if x=RED, r+r1, g-r1, b-r1 + else.if x=GREEN, r-r1, g+r1, b-r1 + else.if x=BLUE, r-r1, g-r1, b+r1 + end +endo + +; convert to grayscale. algorithm: +; g=(r+g+b)/3, rgb(g,g,g). no "endo" +; after. r0=return. note: n/3 = +; (n*155h)>>10 + +operation grayscale, c + . r0=r, r0+g, r0+b, r0*155h,\ + r0>>>10, r1=r0, r1<<8, r0|r1,\ + r1<<8, r0|r1 +endf + +; invert color: c=255-c + +operation inversion, c + . \ + r1=255, r1-r, r0=&r, [r0]=r1,\ + r1=255, r1-g, r0=&g, [r0]=r1,\ + r1=255, r1-b, r0=&b, [r0]=r1 +endo + +; split rgb channel: a=&~b. for 3D +; anaglyph images with R/B glasses + +function channelize, a, b + . r0=a, r1=b, not r1, r0&r1 +endf + +purge operation, endo \ No newline at end of file diff --git a/programs/games/codemaster/include/draw.inc b/programs/games/codemaster/include/draw.inc new file mode 100644 index 0000000000..73c85763bc --- /dev/null +++ b/programs/games/codemaster/include/draw.inc @@ -0,0 +1,385 @@ +; $$$$$$$$$$$$$$$$$$$ ABAKIS $$$$$$$$$$$$$$$$$$$$$ +; *************** STAR^2 SOFTWARE **************** +; ?????????????????? DRAW.INC ???????????????????? + +; fast portable graphics + +include 'color.inc' +include 'box.inc' + +;;;;;;;;;;;;;;;;;;;;; SCREEN ;;;;;;;;;;;;;;;;;;;;; + +align + +void vga.p + +integer screen.x, screen.y,\ + screen.w, screen.h, screen.n,\ + screen.bpp, screen.size,\ + screen.pw, screen.pitch +void palette.p +BOX g.box + +function set.screen, w, h, bpp + alias n=r0, pw=r1 + . screen.w=w, screen.h=h ; size + . n=w, n*h, screen.n=n ; # pixels + . pw=bpp, pw/8 ; pixel width + . screen.pw=pw, n*pw ; screen size + . screen.size=n ; in bytes + . n=w, n*pw ; screen pitch + . screen.pitch=n ; w in bytes + . screen.bpp=bpp ; bits per pixel +endf + +;;;;;;;;;;;;;;;;;;;; DRAWING ;;;;;;;;;;;;;;;;;;;;; + +; erase screen with color + +function clear.screen, c + alias p=r0, n=r1, z=r2 + . p=vga.p, n=screen.n, z=c + loop n, (u32) *p++=z, endl +endf + +; calculate x/y offset: (y*screen.w+x)*4 + +macro get.xy x, y + { . r0=y, r0*screen.w, r0+x, r0*4 } + +; address &vga[(y*screen.w+x)*4] + +function vga.xy, x, y + get.xy x, y + . r0+vga.p +endf + +; draw pixel + +function draw.pixel, x, y, c + alias p=r0, z=r1 + try clip.pixel x, y + vga.xy x, y + . z=c, (u32) *p=z +endf 1 + +; draw horizontal line + +function draw.line.h, x, y, n, c + alias p=r0, z=r1, w=r2 + . p=&x, z=&y, w=&n + try clip.line 0, p, z, w + vga.xy x, y + . z=c + loop n, (u32) *p++=z, endl +endf 1 + +; draw vertical line + +function draw.line.v, x, y, n, c + locals swb + alias p=r0, z=r1, h=r2 + . p=&x, z=&y, h=&n + try clip.line 1, p, z, h + vga.xy x, y + . z=c, swb=screen.pitch + loop n, (u32) *p=z, p+swb, endl +endf 1 + +; draw solid rectangle + +function draw.box, x, y, w, h, c + locals i + try visible x, y, w, h + . i=y, i-- + loop h, i++ + draw.line.h x, i, w, c + endl +endf 1 + +; draw rectangle outline + +function draw.outline, x, y, w, h, c + try visible x, y, w, h + draw.line.h x, y, w, c ; top + . r0=y, r0+h, r0-- ; bottom + draw.line.h x, r0, w, c + . r0=y, r0++, r1=h, r1-2 ; left + draw.line.v x, r0, r1, c + . r0=x, r0+w, r0-- + . r2=y, r2++, r1=h, r1-2 ; right + draw.line.v r0, r2, r1, c +endf 1 + +macro draw.box.s b, c + { draw.box b#.x, b#.y, b#.w, b#.h, c } +macro draw.box.o b, c + { draw.outline b#.x, b#.y, b#.w, b#.h, c } + +macro draw.box a, b, c, d, e { + IF ~e eq + draw.box a, b, c, d, e + ELSE IF ~d eq + 'Unsupported' + ELSE IF ~c eq + draw.box.s a, b + draw.box.o a, c + ELSE IF ~b eq + draw.box.s a, b + END IF +} + +; draw scanline + +function draw.scanline, pixels, x, y, w + locals i + alias p=r0, s=r1 + . r0=&i, r1=&x, r2=&y, r3=&w + try clip.scanline r0, r1, r2, r3 + vga.xy x, y + . s=pixels, s+i + loop w, (u32) *p++=*s++, endl +endf 1 + +; draw scanline with transparent key + +function draw.scanline.t, pixels, x, y, w, key + locals i + alias p=r0, s=r1, c=r2 + . r0=&i, r1=&x, r2=&y, r3=&w + try clip.scanline r0, r1, r2, r3 + vga.xy x, y + . s=pixels, s+i + loop w, (u32) c=*s++ + if c<>key, (u32) *p=c, end, p+4 + endl +endf 1 + +; draw scanline with inverted x + +function draw.scanline.ix, pixels, x, y, w + locals i + alias p=r0, s=r1 + . r0=x, r0+w + vga.xy r0, y + . p-4, s=pixels + loop w, (u32) *p--=*s++, endl +endf 1 + +; draw variant scanline. pixels are +; grayscale, alpha intensity of co=color. +; for brushes and special effects + +function draw.scanline.v, pixels, x, y, w, co + locals a, i + alias p=r0, s=r1, c=r2, c2=r3 + . r0=&i, r1=&x, r2=&y, r3=&w + try clip.scanline r0, r1, r2, r3 + vga.xy x, y + . s=pixels, s+i + loop w, (u32) c=*s++ + . a=c, a&0FFh + if a=0, go .next, end + if a=0FFh, c=co, go .draw, end + . (u32) c2=*p + push p s + get c=mix co, c2, a + pop s p + .draw: . (u32) *p=c + .next: . p+4 + endl +endf 1 + +; draw bitmap + +function draw.bitmap, pixels, x, y, w, h + locals i, p + try visible x, y, w, h + . i=y, p=pixels + loop h + draw.scanline p, x, i, w + . r0=w, r0*4, p+r0, i++ + endl +endf 1 + +; draw bitmap with transparency by +; upper left pixel color (X=0, Y=0) + +function draw.bitmap.t, pixels, x, y, w, h + locals i, p, key + try visible x, y, w, h + . i=y, r0=pixels, p=r0 + . (u32) r0=*r0, key=r0 + loop h + draw.scanline.t p, x, i, w, key + . r0=w, r0*4, p+r0, i++ + endl +endf 1 + +; draw bitmap with inverted x + +function draw.bitmap.ix, pixels, x, y, w, h + locals i, p + try visible x, y, w, h + . p=pixels + loop h + draw.scanline.ix p, x, y, w + . r0=w, r0*4, p+r0, y++ + endl +endf 1 + +; draw bitmap with inverted y + +function draw.bitmap.iy, pixels, x, y, w, h + locals i, p + try visible x, y, w, h + . r0=h, r0--, y+r0, p=pixels + loop h + draw.scanline p, x, y, w + . r0=w, r0*4, p+r0, y-- + endl +endf 1 + +; draw bitmap with both inverted + +function draw.bitmap.ixy, pixels, x, y, w, h + locals i, p, n + try visible x, y, w, h + . p=pixels + loop h + draw.scanline.ix p, x, y, w + . r0=w, r0*4, p+r0, y-- + endl +endf 1 + +; draw variant bitmap + +function draw.bitmap.v, pixels, x, y, w, h, c + locals i, p + try visible x, y, w, h + . i=y, r0=pixels, p=r0 + loop h + draw.scanline.v p, x, i, w, c + . r0=w, r0*4, p+r0, i++ + endl +endf 1 + +; draw gradual vertical fade from +; color a to b. o/rient: +; 'h'=horizontal, 'v'=vertical + +function draw.fade, bo, c1, c2 + locals x, y, w, h, i, n, c,\ + r, g, b, red, green, blue,\ + nr, ng, nb, first, last + . r0=bo,\ + x=[?box.x+r0], y=[?box.y+r0],\ + w=[?box.w+r0], h=[?box.h+r0] + + . r0=y, first=r0, r1=h + . n=r1, r0+r1, last=r0 + + . r0=&r, r1=&g, r2=&b + get.rgb c1, r0, r1, r2 + . r0=&red, r1=&green, r2=&blue + get.rgb c2, r0, r1, r2 + + . r<<8, g<<8, b<<8, r1=n + if r1=0, r1++, end + . r0=red, r0<<8, r0-r, r0/r1, nr=r0 + . r0=green, r0<<8, r0-g, r0/r1, ng=r0 + . r0=blue, r0<<8, r0-b, r0/r1, nb=r0 + + . i=first + forever + . r0=r, r0>>8, r1=g, r1>>8, r2=b, r2>>8 + get c=rgb r0, r1, r2 + draw.line.h x, i, w, c + . r0=nr, r+r0, r1=ng, g+r1, r2=nb, b+r2 + . i++, r0=last + if i>r0, go .out, end + endfv + .out: +endf + +; draw with vertical center fade: +; a to b then b to a + +function draw.shade, bo, a, b + memory.copy g.box, bo, 16 + . g.box.h>>>1 + draw.fade g.box, a, b + . r0=g.box.h, g.box.y+r0 + draw.fade g.box, b, a +endf + +;;;;;;;;;;;;;;;;; PALETTE PIXELS ;;;;;;;;;;;;;;;;; + +; 8BPP versions with pa/lette. no clipping + +function draw.scanline.8, pixels, x, y, w + alias p=r0, s=r1, c=r2, q=r3 + vga.xy x, y + . s=pixels + loop w, q=*s++, q*4, q+palette.p + . (u32) c=*q, (u32) *p++=c + endl +endf 1 + +function draw.bitmap.8, pixels, x, y, w, h + locals i, p + try visible x, y, w, h + . i=y, i--, p=pixels + loop h, i++ + draw.scanline.8 p, x, i, w + . r0=w, p+r0 + endl +endf 1 + +;;;;;;;;;;;;;;;;;;;;; SPECIAL ;;;;;;;;;;;;;;;;;;;; + +; special variant 8BPP with alpha bias for +; fonts and sketching effects (example: +; chalkboard) + +A.LIGHTEST=128 +A.LIGHTER=96 +A.LIGHT=64 +A.DARK=-32 +A.DARKER=-64 +A.DARKEST=-96 + +align +integer alpha.bias=0 ; A.DARKEST + +function draw.scanline.v.8, pixels, x, y, w, co + locals a, i + alias p=r0, s=r1, c=r2, c2=r3, q=r3 + vga.xy x, y + . s=pixels + loop w, q=*s++, q*4, q+palette.p + . (u32) c=*q, a=c, a&0FFh + if a=0, go .next, end + . (u32) c2=*p + push p s + . r0=a + if alpha.bias, r0+alpha.bias + if r0<0, r0=0 + else.if r0>255, r0=255, end + end + get c=mix co, c2, r0 + pop s p + .draw: . (u32) *p=c + .next: . p+4 + endl +endf 1 + +function draw.bitmap.v.8, pixels, x, y, w, h, c + locals i, p + try visible x, y, w, h + . i=y, i--, p=pixels + loop h, i++ + draw.scanline.v.8 p, x, i, w, c + . r0=w, p+r0 + endl +endf 1 \ No newline at end of file diff --git a/programs/games/codemaster/include/drawk.inc b/programs/games/codemaster/include/drawk.inc new file mode 100644 index 0000000000..5a75c6e3fe --- /dev/null +++ b/programs/games/codemaster/include/drawk.inc @@ -0,0 +1,344 @@ +; $$$$$$$$$$$$$$$$$$$ ABAKIS $$$$$$$$$$$$$$$$$$$$$ +; *************** STAR^2 SOFTWARE **************** +; ?????????????????? DRAW.INC ???????????????????? + +; fast portable graphics + +include 'color.inc' +include 'box.inc' + +;;;;;;;;;;;;;;;;;;;;; SCREEN ;;;;;;;;;;;;;;;;;;;;; + +align + +vga equ (gs:r0) + +; void vga.p + +integer \ + screen.w, screen.h, screen.n,\ + screen.size, screen.pitch,\ + screen.bpp, screen.pw + +void palette.p + +function set.screen, w, h, bpp + alias n=r0, pw=r1 + . screen.w=w, screen.h=h ; size + . n=w, n*h, screen.n=n ; # pixels + . n=bpp, n>>>3, pw=n ; pixel width + . screen.pw=pw, n*pw ; size + . screen.size=n ; in bytes + . n=w, n*4 ; width + . screen.pitch=n ; in bytes + . screen.bpp=bpp ; bits per pixel +endf + +; calculate x/y offset: (y*screen.w+x)*4 + +macro xy x, y { + . r0=y, r0*1024, r0+x, r0*4 + . r1=WINDOW.Y, r1*4096, r0+r1 + . r1=WINDOW.X, r1*4, r0+r1 +} + +; erase screen with color + +function clear.screen, c + callf draw.box, 0, 0, WINDOW.W-1, WINDOW.H-1, c +endf + +; draw straight line: loop n, *p++=c + +function draw.line.h, x, y, w, c + xy x, y + . r1=c + loop w, (u32) *vga=r1, r0+4, endl +endf + +; draw vertical line + +function draw.line.v, x, y, n, c + locals swb + alias p=r0, z=r1, h=r2 + xy x, y + . z=c, swb=4096 + loop n, (u32) *vga=z, p+swb, endl +endf 1 + +; draw solid rectangle + +function draw.box, x, y, w, h, c + try visible x, y, w, h + loop h + draw.line.h x, y, w, c + . y++ + endl +endf + +; draw rectangle outline + +function draw.outline, x, y, w, h, c + try visible x, y, w, h + draw.line.h x, y, w, c + . r0=y, r0+h, r0-- + draw.line.h x, r0, w, c + . r0=y, r0++, r1=h, r1-2 + draw.line.v x, r0, r1, c + . r0=x, r0+w, r0-- + . r1=y, r1++, r2=h, r2-2 + draw.line.v r0, r1, r2, c +endf + +macro draw.box.s b, c + { draw.box b#.x, b#.y, b#.w, b#.h, c } +macro draw.box.o b, c + { draw.outline b#.x, b#.y, b#.w, b#.h, c } + +macro draw.box a, b, c, d, e { + IF ~e eq + draw.box a, b, c, d, e + ELSE IF ~d eq + 'Unsupported' + ELSE IF ~c eq + draw.box.s a, b + draw.box.o a, c + ELSE IF ~b eq + draw.box.s a, b + END IF +} + +; draw scanline: multi-color line, +; array of pixels: + +; loop w, *p++=*s++, endl + +function draw.scanline, s, x, y, w + alias p=r0, q=r1, c=r2 + xy x, y + . q=s + loop w, (u32) c=*q, (u32) *vga=c + . p+4, q+4 + endl +endf + +; draw transparent scanline with color +; "key" to exclude + +function draw.scanline.t, s, x, y, w, k + alias p=r0, q=r1, c=r2 + xy x, y + . q=s + loop w, (u32) c=*q + if c<>k, (u32) *vga=c, end + . p+4, q+4 + endl +endf + +; draw scanline with inverted x + +function draw.scanline.ix, pixels, x, y, w + alias p=r0, s=r1, c=r2 + . r0=x, r0+w + xy r0, y + . p-4, s=pixels + loop w, (u32) c=*s++, (u32) *vga=c, p-4, endl +endf 1 + +; draw variant scanline. pixels are +; grayscale, alpha intensity of co=color. +; for brushes and special effects + +function draw.scanline.v, pixels, x, y, w, co + locals a + alias p=r0, s=r1, c=r2, c2=r3 + xy x, y + . s=pixels + loop w, (u32) c=*s++ + . a=c, a&0FFh + if a=0, go .next, end + if a=0FFh, c=co, go .draw, end + . (u32) c2=*p + push p s + get c=mix co, c2, a + pop s p + .draw: . (u32) *vga=c + .next: . p+4 + endl +endf 1 + +; draw transparent scanline with key and +; alpha (0-255) applied to entire line + +function draw.scanline.a, s, x, y, w, k, a + alias p=r0, q=r1, c=r2, c2=r3 + xy x, y + . q=s + loop w, (u32) c=*q + if c<>k, (u32) c2=*vga + push p q + get c=mix c, c2, a + pop q p + end, (u32) *vga=c + .next: + . p+4, q+4 + endl +endf + +; draw bitmap; 2D array of pixels + +function draw.bitmap, p, x, y, w, h + locals i + try visible x, y, w, h + . i=y + loop h, i++ + draw.scanline p, x, i, w + . r0=w, r0*4, p+r0 + endl +endf + +; draw transparent bitmap with color +; "key" by upper left pixel (X0,Y0) + +function draw.bitmap.t, p, x, y, w, h + locals i, k + try visible x, y, w, h + . r0=p, (u32) r0=*r0, k=r0 + . i=y + loop h, i++ + draw.scanline.t p, x, i, w, k + . r0=w, r0*4, p+r0 + endl +endf + +; draw transparent bitmap with key and +; alpha (0-255) applied to entire image + +function draw.bitmap.a, p, x, y, w, h, a + locals i, k + try visible x, y, w, h + . i=y, r0=p, (u32) r0=*r0, k=r0 + loop h, i++ + draw.scanline.a p, x, i, w, k, a + . r0=w, r0*4, p+r0 + endl +endf + +; draw bitmap with inverted x + +function draw.bitmap.ix, pixels, x, y, w, h + locals p + try visible x, y, w, h + . p=pixels + loop h + draw.scanline.ix p, x, y, w + . r0=w, r0*4, p+r0, y++ + endl +endf 1 + +; draw bitmap with inverted y + +function draw.bitmap.iy, pixels, x, y, w, h + locals p + try visible x, y, w, h + . r0=h, r0--, y+r0, p=pixels + loop h + draw.scanline p, x, y, w + . r0=w, r0*4, p+r0, y-- + endl +endf 1 + +; draw bitmap with both inverted + +function draw.bitmap.ixy, pixels, x, y, w, h + locals p, n + try visible x, y, w, h + . p=pixels + loop h + draw.scanline.ix p, x, y, w + . r0=w, r0*4, p+r0, y-- + endl +endf 1 + +; draw variant bitmap + +function draw.bitmap.v, pixels, x, y, w, h, c + locals i, p + try visible x, y, w, h + . i=y, r0=pixels, p=r0 + loop h + draw.scanline.v p, x, i, w, c + . r0=w, r0*4, p+r0, i++ + endl +endf 1 + +;;;;;;;;;;;;;;;;; PALETTE PIXELS ;;;;;;;;;;;;;;;;; + +; 8BPP versions with pa/lette. no clipping + +function draw.scanline.8, pixels, x, y, w + alias p=r0, s=r1, c=r2, q=r3 + xy x, y + . s=pixels + loop w, q=*s++, q*4, q+palette.p + . (u32) c=*q, (u32) *vga=c, r0+4 + endl +endf 1 + +function draw.bitmap.8, pixels, x, y, w, h + locals i, p + try visible x, y, w, h + . i=y, p=pixels + loop h + draw.scanline.8 p, x, i, w + . i++, r0=w, p+r0 + endl +endf 1 + +;;;;;;;;;;;;;;;;;;;;; SPECIAL ;;;;;;;;;;;;;;;;;;;; + +; special variant 8BPP with alpha bias for +; fonts and sketching effects (example: +; chalkboard) + +A.LIGHTEST=128 +A.LIGHTER=96 +A.LIGHT=64 +A.DARK=-32 +A.DARKER=-64 +A.DARKEST=-96 + +align +integer alpha.bias=0 ; A.DARKEST + +function draw.scanline.v.8, pixels, x, y, w, co + locals a + alias p=r0, s=r1, c=r2, c2=r3, q=r3 + xy x, y + . s=pixels + loop w, q=*s++, q*4, q+palette.p + . (u32) c=*q, a=c, a&0FFh + if a=0, go .next, end + . (u32) c2=*vga + push p s + . r0=a + if alpha.bias, r0+alpha.bias + if r0<0, r0=0 + else.if r0>255, r0=255, end + end + get c=mix co, c2, r0 + pop s p + .draw: . (u32) *vga=c + .next: . p+4 + endl +endf 1 + +function draw.bitmap.v.8, pixels, x, y, w, h, c + locals i, p + try visible x, y, w, h + . i=y, p=pixels + loop h + draw.scanline.v.8 p, x, i, w, c + . i++, r0=w, p+r0 + endl +endf 1 \ No newline at end of file diff --git a/programs/games/codemaster/include/font.inc b/programs/games/codemaster/include/font.inc new file mode 100644 index 0000000000..85dac71e5e --- /dev/null +++ b/programs/games/codemaster/include/font.inc @@ -0,0 +1,104 @@ +; $$$$$$$$$$$$$$$$$$$ ABAKIS $$$$$$$$$$$$$$$$$$$$$ +; *************** STAR^2 SOFTWARE **************** +; ?????????????????? FONT.INC ???????????????????? + +; 100% portable font + +;;;;;;;;;;;;;;;;;;;; SYMBOLS ;;;;;;;;;;;;;;;;;;;;; + +; my default character arrangement: 95 symbols. +; includes all standard visible characters + +; 0 1 2 3 4 5 6 7 8 9 A B C D E F G H I +; J K L M N O P Q R S T U V W X Y Z a b +; c d e f g h i j k l m n o p q r s t u +; v w x y z _ . ? ; : ' " , ~ ! @ # $ +; % ^ & * ( ) [ ] { } = + - < > / \ | ` + +; symbol lookup table to convert 7BIT ASCII +; character to index. 63=ignore (spaces, etc) + +align 4 + +FONT.SYMBOLS: db \ +63,63,63,63,63,63,63,63, 63,63,63,63,63,63,63,63,\ +63,63,63,63,63,63,63,63, 63,63,63,63,63,63,63,63,\ +63,72,69,74,75,76,78,68, 80,81,79,87,70,88,64,91,\ +00,01,02,03,04,05,06,07, 08,09,67,66,89,86,90,65,\ +73,10,11,12,13,14,15,16, 17,18,19,20,21,22,23,24,\ +25,26,27,28,29,30,31,32, 33,34,35,82,92,83,77,62,\ +94,36,37,38,39,40,41,42, 43,44,45,46,47,48,49,50,\ +51,52,53,54,55,56,57,58, 59,60,61,84,93,85,71,63 +NO.C=63 + +macro FONT [p] { common IMAGE p } + +align + +void font.image.p +integer font.image.w, font.w, font.h +integer font.color=WHITE + +macro set.font i { + . font.image.p=i#.p, r0=i#.w + . font.image.w=r0, r1=95, r0/r1 + . font.w=r0, font.h=i#.h +} + +;;;;;;;;;;;;;;;;; DRAW CHARACTER ;;;;;;;;;;;;;;;;; + +function draw.c, c, x, y + locals i, p, iw + try visible x, y, font.w, font.h + . r0=FONT.SYMBOLS, r0+c, r0=*r0 + if r0=NO.C, return, end + . r0*font.w, r0*4, r0+font.image.p + . p=r0, iw=font.image.w, iw*4, i=font.h + loop i, r0=i + if r0>=font.h, break, end + draw.scanline p, x, y, font.w + . r1=iw, p+r1, y++ + endl +endf + +;;;;;;;;;;;;;;;;;;; DRAW TEXT ;;;;;;;;;;;;;;;;;;;; + +align +integer clip.tx=-1, clip.ty=-1 + +function draw.text, t, x, y + locals i, n, p + . r0=t, p=r0, i=0 + while true ; draw all characters + . r1=i, r1*font.w ; x=i*font.w+x + . r1+x, r0=p, r0=*r0 ; get c + if r0=0Dh ; return? + . i=0, r1=font.h ; reset x + . y+r1, p++ ; y+font.h + go .next + end + . r2=y, r2-font.h ; clipping + if r2>screen.h + return + end + . r2=clip.tx + if r2<>-1, r2-font.w + if r1>=r2, return, end + end + . r2=clip.ty + if r2<>-1, r2-font.h + if r1>=r2, return, end + end + draw.c r0, r1, y ; draw + . i++ + .next: + . p++, r0=p, r0=*r0 + endw +endf + +; get width of text=a1 with insets + +function get.text.w, t + text.n t + . r1=r0, r1+2, r0=font.w, r0*r1 +endf \ No newline at end of file diff --git a/programs/games/codemaster/include/image.inc b/programs/games/codemaster/include/image.inc new file mode 100644 index 0000000000..4feda4cdf3 --- /dev/null +++ b/programs/games/codemaster/include/image.inc @@ -0,0 +1,397 @@ +; $$$$$$$$$$$$$$$$$$$ ABAKIS $$$$$$$$$$$$$$$$$$$$$ +; *************** STAR^2 SOFTWARE **************** +; ;;;;;;;;;;;;;;;;;;; IMAGE ;;;;;;;;;;;;;;;;;;;;;; + +; image class/object/structure + +macro IMAGE a { + a: + void a#.p + integer a#.x, a#.y, a#.w, a#.h + integer a#.bpp=32, a#.key, a#.alpha +} + +virtual at 0 + ?image.p dd 0 + ?image.x dd 0 + ?image.y dd 0 + ?image.w dd 0 + ?image.h dd 0 + ?image.bpp dd 32 + ?image.key dd 0 + ?image.alpha dd 0 +END virtual + +?image.box fix ?image.x + +; create image file/s with header: +; 8 bytes: + +; byte s='I' ; signature +; byte v=0 ; version: AABBCC.VV +; int16 w, h ; size: w:h +; byte bpp ; bpp: 32/24/16/15/8 +; byte n ; # colors or 0=256+ + +; byte pixels[w*h*(bpp/8)] ; or *2 if 15 + +macro IMAGE [p] { + forward + local w, h + w=0 + h=0 + define ?s 0 + match a==b, p \{ + \local ..q + ..q: inject.image b, 32 + load w word from ..q+2 + load h word from ..q+4 + a: + void a\#.p=..q+8 + integer a\#.x, a\#.y, a\#.w=w, a\#.h=h + integer a\#.bpp, a\#.key, a\#.alpha + define ?s 1 + \} + IF ?s eq 0 + IMAGE p + END IF +} + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +; load 24PP .BMP, store as .IMAGE 15/16/24/32. +; for OSs, ROMs. warning: causes slow compile +; with 1+ MB worth of images. to compile fast +; without images, comment "; IMAGE name='abc'" + +macro inject.image name, bpp { + local i, p, a, r, g, b,\ + x, y, w, h, wb + virtual at 0 + p:: file CD#'/media/'#name#'.BMP' + END virtual + IF ~bpp in <15,16,24,32> + 'Invalid BPP' name + END IF + load a word from p:0 + IF a<>'BM' + 'Invalid signature' name + END IF + load a byte from p:1Ch + IF a<>24 + 'Must be 24BPP' name + END IF + load w dword from p:12h + load h dword from p:16h + db 'I', 0 + dw w, h + db bpp, 0 + a=((3-((w*3)+3)) and 3) + wb=(w*3)+a + y=h + WHILE y>0 + o=36h+((y-1)*wb) + x=0 + WHILE x'BM' + 'Invalid signature' name + END IF + load a byte from p:1Ch + IF a<>8 + 'Must be 8BPP' name + END IF + load w dword from p:12h + load h dword from p:16h + db 'I', 0 + dw w, h + db 8, 0 + i=0 + WHILE i<256 + o=36h+(i*4) + load b byte from p:o + load g byte from p:o+1 + load r byte from p:o+2 + db b, g, r, 0 + i=i+1 + END WHILE + a=((3-(w+3)) and 3) + wb=w+a + y=h + WHILE y>0 + o=436h+((y-1)*wb) + x=0 + WHILE x + 'Invalid BPP' name + END IF + load a word from p:0 + IF a<>'BM' + 'Invalid signature' name + END IF + load a byte from p:1Ch + IF a<>24 + 'Must be 24BPP' name + END IF + load w dword from p:12h + load h dword from p:16h + db 'I', 0 + dw w, h + db bpp, 0 + a=((3-((w*3)+3)) and 3) + wb=(w*3)+a + y=h + WHILE y>0 + o=36h+((y-1)*wb) + x=0 + WHILE x'BM' + 'Invalid signature' name + END IF + load a byte from p:1Ch + IF a<>8 + 'Must be 8BPP' name + END IF + load w dword from p:12h + load h dword from p:16h + db 'I', 0 + dw w, h + db 8, 0 + i=0 + WHILE i<256 + o=36h+(i*4) + load b byte from p:o + load g byte from p:o+1 + load r byte from p:o+2 + db b, g, r, 0 + i=i+1 + END WHILE + a=((3-(w+3)) and 3) + wb=w+a + y=h + WHILE y>0 + o=436h+((y-1)*wb) + x=0 + WHILE x + +is.r32? fix in \ + + +is.r16? fix in +is.r16x? fix in + +is.r8l? fix in +is.r8h? fix in +is.r8? fix in + +;;;;;;;;;;;;;;;;; SYNTAX, VERIFY ;;;;;;;;;;;;;;;;; + +?not fix ~ +?empty fix eq + +macro syntax v { + IF v eq + define ?s 1 + ELSE + define ?s v + END IF +} + +macro verify e { + IF ?s eq 0 + display `e + 'Error: ' e + END IF +} + +if.syntax fix IF ?s eq +if.not.syntax fix IF ?s eq 0 + +macro verify.r [r] { + IF ~r is.r? + 'Register expected:' r + END IF +} + +macro verify.r32 [r] { + IF ~r is.r32? + 'Register expected:' r + END IF +} + +macro verify.i i { + IF ~i is.i? + 'Number expected:' i + END IF +} + +macro verify.n n, min, max { + IF nmax + 'Number exceeds range:' min-max + END IF +} + +macro verify.u3 n { verify.n n, 0, 7 } +macro verify.u4 n { verify.n n, 0, 15 } +macro verify.u5 n { verify.n n, 0, 31 } +macro verify.u6 n { verify.n n, 0, 63 } +macro verify.u7 n { verify.n n, 0, 127 } +macro verify.8 n { verify.n n, -255, 255 } +macro verify.u8 n { verify.n n, 0, 255 } +macro verify.i8 n { verify.n n, -128, 127 } +macro verify.12 n { verify.n n, -4095, 4095 } +macro verify.u12 n { verify.n n, 0, 4095 } +macro verify.i12 n { verify.n n, -2048, 2047 } +macro verify.16 n { verify.n n, -65535, 65535 } +macro verify.u16 n { verify.n n, 0, 65535 } +macro verify.i16 n { verify.n n, -32768, 32767 } + +; verify size of block/text/array + +macro verify.size n { + IF n eq + 'Size must be specified' + ELSE IF ~ n eqtype 0 + 'Size must be numeric' + ELSE IF n eq 0 + 'Size cannot be zero' + END IF +} + +;;;;;;;;;;;;;;;;;;; ALIGNMENT ;;;;;;;;;;;;;;;;;;;; + +macro align n { + IF n eq ; by address size + align 4 + ELSE + IF n is.i? ; align n (standard) + align n + ELSE ; align integer i=123 + align 4 + n ; line after + END IF + END IF +} + +macro IF.align n, by { IF n mod by=0 } + +macro IF.not.align n, by { IF n mod by<>0 } + +macro verify.a n, by { + display.h n + IF.not.align n, by + 'Number' n 'must be aligned by:' by + END IF +} + +;;;;;;;;;;;;;;;;;;;; DISPLAY ;;;;;;;;;;;;;;;;;;;;; + +; display numbers at assembly time + +macro display.b n { + REPEAT 32 + display '0'+((n shr (32-%)) and 1) + END REPEAT +} + +macro display.h n { + local c + REPEAT 8 + c=(n and (0Fh shl ((8-%) shl 2))) \ + shr ((8-%) shl 2) + '0' + IF c>'9' + c=c+7 + END IF + display c + IF %=8 + display 'h' + END IF + IF (((%*4) and 31)=0) + display ' ' + END IF + END REPEAT +} + +;;;;;;;;;;;;;;;;;; EQUATE LIST ;;;;;;;;;;;;;;;;;;; + +macro ?list.attach list, item { + match any, list \{ list equ list, item \} + match , list \{ list equ item \} +} + +macro ?display.list [p] { + common + match q, p \{ + ?p equ q + irps s, q \\{ + display \\`s, ' ' + match a b, ?p \\\{ + restore ?p + ?p equ b + \\\} + \\} + restore ?p + \} +} + +;;;;;;;;;;;;;;;;;;;; SETTINGS ;;;;;;;;;;;;;;;;;;;; + +; example: ?enable align + +?setting.align equ +?setting.debug equ + +IF.align fix match =1, ?setting.align +IF.debug fix match =1, ?setting.debug + +macro ?enable s, v { + restore ?setting.#s + match , v + \{ ?setting.#s equ 1 \} + match any, v + \{ ?setting.#s equ v \} +} + +macro ?disable s { + restore ?setting.#s + ?setting.#s equ 0 +} + +;;;;;;;;;;;;;;;;;;;; VARIABLE ;;;;;;;;;;;;;;;;;;;; + +_strict_ equ 0 ; strict type safety? +_scope_ equ 0 ; 0=global, 1=local + +_object_ equ 0 + +; create variable: name (a), type, value, +; size (n), sign (s) + +macro ?V a, t, v, n, s { + + IF.align \{ align \} + + IF n=8 + !#a dq v + ELSE IF n=4 + !#a dd v + ELSE IF n=2 + !#a dw v + ELSE IF n=1 + !#a db v + ELSE + 'Invalid size' + END IF + + name$#a equ a + type$#a=t + size$#a=n + sign$#a=s + scope$#a=_scope_ + strict$#a=_strict_ + + a equ [!#a] +} + +; define X. syntax: type then any a/a=b +; sequence/s separated with ,s. +; variables=0 if there is no initial value + +macro ?D type, [p] { + forward + define ?s 0 + match =0 \ + a==b, ?s p \{ ; a=b + type a, b + define ?s 1 + \} + match =0 \ + a=,, ?s p \{ ; a, (next) + type a, 0 + define ?s 1 + \} + match =0 \ + a, ?s p \{ ; a (end) + type a, 0 + define ?s 1 + \} + verify variable +} + +; real variable names... + +macro i8 a, v { ?V a, 'i', v, 1, 1 } +macro u8 a, v { ?V a, 'i', v, 1, 0 } +macro i16 a, v { ?V a, 'i', v, 2, 1 } +macro u16 a, v { ?V a, 'i', v, 2, 0 } +macro i32 a, v { ?V a, 'i', v, 4, 1 } +macro u32 a, v { ?V a, 'i', v, 4, 0 } +macro i64 a, v { ?V a, 'i', v, 8, 1 } +macro u64 a, v { ?V a, 'i', v, 8, 0 } + +; aliases... + +macro void [a] { ?D u32, a } + +macro char [a] { ?D i8, a } +macro uchar [a] { ?D u8, a } +macro wchar [a] { ?D u16, a } +macro short [a] { ?D i16, a } +macro ushort [a] { ?D u16, a } +macro int [a] { ?D i32, a } +macro uint [a] { ?D u32, a } +macro long [a] { ?D i64, a } +macro ulong [a] { ?D u64, a } +macro float [a] { ?D u32, a } +macro double [a] { ?D u64, a } + +macro byte [a] { ?D i8, a } +macro ubyte [a] { ?D u8, a } +macro integer [a] { ?D i32, a } +macro uinteger [a] { ?D u32, a } +macro boolean [a] { ?D i32, a } + +;;;;;;;;;;;;;;;;; LITERAL TABLE ;;;;;;;;;;;;;;;; + +?literals.i=0 ; offset + +?literals equ align 4,\ + ?LITERALS:, ?literals.i=0 + +; store literal 'text'. attach line + +macro ?literal t { + local n + virtual at 0 + db t, 0 + n=$ + END virtual + ?literals equ ?literals,\ + db t, db 0 + ?literals.i=?literals.i+n +} + +; store table. expand line/s + +macro @literals { + IF ?literals.i + match j, ?literals \{ + irp i, j \\{ i \\} + \} + END IF +} + +;;;;;;;;;;;;;;;;; TEXT VARIABLES ;;;;;;;;;;;;;;;;; + +; create HL 'text' variable/s. text t='X'. +; note: (n) is the size + +macro text [p] { + forward + local l + define ?s 0 + match =0 \ ; text t(n)='abc' + name(n)==t, ?s p \{ + l=$ + verify.size n + name: db t, 0 + times \ + (n-($-l)) db 0 + name\#.$=n + define ?s 1 + \} + match =0 name(n),\ ; text t(n) + ?s p \{ + verify.size n + name: db n dup(0) + name\#.$=n + define ?s 1 + \} + match =0 name==t,\ ; text t='abc' + ?s p \{ + l=$ + name: db t, 0 + name\#.$=($-l) + define ?s 1 + \} + match =0 name, ?s p \{ + 'Size not specified:' name + define ?s 1 + \} + verify name +} + +; helper macros: text/x/a/i/p + +; text extended to 2+ lines: + +; text name=+'Hi, how ',\ +; 'are ', 'you?' + +macro textx name, [p] { + common + name: db p, 0 +} + +; create array of pointers and literal +; 'text'. optional a/lign each to size +; or 0=none: + +; text names[]='ann', 'kim', 'sue' + +macro texta a, name, [t] { + common + local n + n=0 + label name dword + forward + local l + dd l + n=n+1 + forward + l db t, 0 + IF a + times (a-($-l)) db 0 + END IF + common + name#.$=n +} + +; like texta with ids (0-n): + +; textai 0, names.ta, 'ann', 'kim', 'sue' + +macro textai a, name, [p] { + common + local n + n=0 + label name dword + forward + local l + dd l + forward + define ?s 0 + match id==t, p \{ + l db t, 0 + id=n + n=n+1 + define ?s 1 + \} + verify textai + IF a + times (a-($-l)) db 0 + END IF + common + name#.$=n +} + +; same with prefix + +macro textaip a, name, x, [p] { + common + local n + n=0 + label name dword + forward + local l + dd l + forward + define ?s 0 + match id==t, p \{ + l db t, 0 + x\#id=n + n=n+1 + define ?s 1 + \} + verify textaip + IF a + times (a-($-l)) db 0 + END IF + common + name#.$=n +} + +; upgrade text to support ()/textx/a/i/p + +macro text [p] { + common + define ?s 0 + match =0 (n), ?s p \{ + db n dup(0) + define ?s 1 + \} + match =0 a==+b, ?s p \{ + textx a, b + define ?s 1 + \} + match =0 \ + a[]==name* t, ?s p \{ + match x==y, t \\{ + textaip 0, a, name, t + define ?s 1 + \\} + IF ?s eq 0 + texta 0, a, t + END IF + define ?s 1 + \} + match =0 \ + a[]==t, ?s p \{ + match x==y, t \\{ + textai 0, a, t + define ?s 1 + \\} + IF ?s eq 0 + texta 0, a, t + END IF + define ?s 1 + \} + match =0 \ + a[](n)==t, ?s p \{ + texta n, a, t + define ?s 1 + \} + IF ?s eq 0 + text p + END IF +} + +; create 'text' in code. r/egister='t/ext' +; WARNING: all commands that accept a literal +; 'text' parameter (.t suffix) will alter eax. +; only intended for testing and utilities + +macro make.txt r, t { + IF t eqtype "" + local ..t, ..e + jmp ..e + ..t db t, 0 + ..e: + mov r, ..t + ELSE + mov r, t + END IF +} + +;;;;;;;;;;;;;;; VARIABLE EXAMPLES ;;;;;;;;;;;;;; + +; variables: void, int, float, x + +; int i, n=123 + +; void p + +; float f=1.0, g=0.5 +; double d, e=7.25 + +; text t='ABC', name(64) ; byte[] + +; extended 2+ lines: + +; text name=+'Hi, how ',\ +; 'are ', 'you?' + +; void[]+'text'... + +; text ta[]='A', '123' + +; with alignment: + +; text names[](8)='ann', 'kim', 'sue' + +; with numeric ID #s (0-n): + +; text xyz[]= \ +; ID.A='A', ID.B='B', ID.C='C' + +; with prefix + ID #s (ERROR.NAME): + +; text errors[]= ERROR.* \ +; NONE = 'No error',\ +; SYNTAX = 'Syntax',\ +; ADDRESS = 'Invalid address',\ +; MEMORY = 'Memory allocation',\ +; SETUP = 'Initiation' + +; access text from pointer array: + +; mov eax, [ta+3*4] +; say [errors+ERROR.MEMORY*4] + +;;;;;;;;;;;;;; NUMERIC CONSTANTS ;;;;;;;;;;;;;;;;; + +; create incremental (0-n) list of numeric +; constants with optional prefix. each token +; can be assigned or it equals previous+1. +; if first token ends with *, it becomes the +; prefix for subsequent tokens. example: + +; numeric COLOR.*,\ +; BLACK, WHITE, RED, GREEN, BLUE + +; COLOR.BLACK=0 ; output... +; COLOR.WHITE=1 +; COLOR.RED=2 +; COLOR.GREEN=3 +; COLOR.BLUE=4 + +macro numeric ?p, [p] { + common + local n + n=0 ; n=0 + syntax 0 + match z$*, ?p \{ ; extract prefix + syntax 1 + \} + match a==b, ?p \{ ; first item + a=b + n=b+1 + syntax 1 + \} + match =0, ?s \{ ; else, first=0 + ?p=0 + n=1 + \} + forward + syntax 0 + match a==b, p \{ ; assigment? + n=b ; set n + match z$*, ?p \\{ ; extract prefix + z$\\#a=b + syntax 1 + \\} + if.syntax 0 ; no prefix + a=b + END IF + syntax 1 ; yes, specified + \} + match =0, ?s \{ ; else=n (previous+1) + match z$*, ?p \\{ ; extract prefix + z$\\#p=n + syntax 1 + \\} + if.syntax 0 ; no prefix + p=n + END IF + \} + n=n+1 ; n++ +} + +KB=1024 ; 1<<10 +MB=1048576 ; 1<<20 +GB=1073741824 ; 1<<30 + +numeric YES=1, NO=0, TRUE=1, FALSE=0,\ + NULL=0, DEFAULT=0, NONE=-1, INVALID=-1,\ + DETECT=-1, INFINITE=-1, NOTHING=-1 + +; note: -1 means "not zero and not maximum" +; (FFFF/FF/FFh) for indices, sizes, handles +; (index or pointer), etc, where >=0 is +; valid/finite/something... + +; if n=INFINITE ; if -1 +; if handle=INVALID ; if -1 +; if n not INVALID ; if <>-1 +; if win>NOTHING ; if >=0 + +;;;;;;;;;;;;;;;;;;;;; POWERS ;;;;;;;;;;;;;;;;;;;;; + +; create successive powers of 2 starting +; at BIT0, from right to left. example: + +; powers IS.*, ACTIVE, VISIBLE,\ +; DRAWABLE, MOVEABLE, SIZABLE + +macro _powers [id] { + common local n + n=0 + forward id=1 shl n + n=n+1 +} + +macro powers ?p, [p] { + common + local n + n=0 ; n=1 + syntax 0 + match z$*, ?p \{ ; extract prefix + syntax 1 + \} + match =0, ?s \{ ; else, first item + ?p=0 + n=1 + \} + forward + syntax 0 + match a==b, p \{ ; assigment? + n=b ; set n + match z$*, ?p \\{ ; extract prefix + z$\\#a=1 shl n + syntax 1 + \\} + if.syntax 0 ; no prefix + a=1 shl n + END IF + syntax 1 ; yes, specified + \} + match =0, ?s \{ ; else=n (previous+1) + match z$*, ?p \\{ ; extract prefix + z$\\#p=1 shl n + syntax 1 + \\} + if.syntax 0 ; no prefix + p=1 shl n + END IF + \} + n=n+1 ; next bit +} + +; create readable bit structure from +; left to right. example: 0000ABCDb. +; powerz A, B, C, D ; A=8, B=4, C=2, D=1 + +macro powerz [id] { + common local n + n=1 + forward n=n+1 + common n=n-2 + forward id=1 shl n + n=n-1 +} + +; get power of 2. n-1 then search from left +; to right for 1st 0 BIT. rv=return value + +; n=0 +; ?power.2 256, n +; say.n n + +macro ?power.2 n, rv { + local i, x + i=0 + IF (n and (n-1))=0 + i=1 + x=n-1 + WHILE 1 + IF x and (1 shl i)=0 + ?break + END IF + i=i+1 + END WHILE + END IF + rv=i +} + +;;;;;;;;;;;;;;;;;;;; IF BIT/S ;;;;;;;;;;;;;;;;;;;; + +; compare BITs in r or eax. alters edx + +; if.bit 20 +; if.bits 4-7=1001b +; if.bit 20, eax +; if.bits 31-24=11110011b, eax + +macro if.bit n, r { + IF ~r eq + mov edx, r + ELSE + mov edx, eax + END IF + local ..start, ..else, ..end + ?IF equ + ?START equ ..start + ?ELSE equ ..else + ?END equ ..end + ?START: + test edx, (1 shl n) + jz ?ELSE +} + +macro if.not.bit n, r { + IF ~r eq + mov edx, r + ELSE + mov edx, eax + END IF + local ..start, ..else, ..end + ?IF equ + ?START equ ..start + ?ELSE equ ..else + ?END equ ..end + ?START: + test edx, (1 shl n) + jnz ?ELSE +} + +; alters edx + +macro if.bits n, r { + local i, b,\ + lo, hi, mask + syntax 0 + match l-h==v, n \{ ; BITs = value + IF l0 + ?break + END IF + i=i+1 + END REPEAT + b=0 ; # BITs required + REPEAT 32-i ; for v/alue + b=b+1 + END REPEAT + IF b>(hi-lo+1) ; example: 4-5=111b + 'Value exceeds size' ; 4-5 is only 2BITs, + END IF ; not enough for 111b. + i=0 + mask=0 ; create mask: 111xb + REPEAT (hi-lo+1) ; # 1 BITs + mask=\ + (mask or (1 shl i)) + i=i+1 + END REPEAT + local ..start, ..else, ..end + ?IF equ + ?START equ ..start + ?ELSE equ ..else + ?END equ ..end + IF ~r eq + mov edx, r + ELSE + mov edx, eax + END IF + shr edx, lo ; extract BITs + and edx, mask + ?START: + cmp edx, v + jne ?ELSE + syntax 1 + \} + verify +} + +;;;;;;;;;;;;;;;;;;;;; CLASS ;;;;;;;;;;;;;;;;;;;;;; + +; unfinished + +; macro class name { +; name: +; macro u8 a, v \{ u8 name\#.\#a, v \} +; macro i8 a, v \{ i8 name\#.\#a, v \} +; macro u16 a, v \{ u16 name\#.\#a, v \} +; macro i16 a, v \{ i16 name\#.\#a, v \} +; macro u32 a, v \{ u32 name\#.\#a, v \} +; macro i32 a, v \{ i32 name\#.\#a, v \} +; macro u64 a, v \{ u64 name\#.\#a, v \} +; macro i64 a, v \{ i64 name\#.\#a, v \} +; ... +; } +; +; macro endc [p] { +; common +; restore u8, i8, u16, i16,\ +; u32, i32, u64, i64 +; } + +; 2-DO: single-line classes: + +; class RGB = byte a, r, g, b +; class POINT = integer x, y +; class LINE = POINT a, b +; class BOX = integer x, y, w, h +; class POINT3D = integer x, y, z +; class POLYGON = ARRAY POINT3D points[] + +macro assume [p] { + common + match name==type, p \{ + virtual at 0 + type name + END virtual + \} +} + +;;;;;;;;;;;;;;;;; LET ARITHMETIC ;;;;;;;;;;;;;;;;; + +; perform assignment/s, operation/s and +; low-level "expressions". + +; signed is the default for numbers that can +; be negative (ex, coordinates). some symbols +; are for unsigned operations (>>> is shr) + +; = is a standard copy, move, assignment + +; =& gets the address of integers/void/x + +; WARNING: both ++/--/+-/-+ cannot used. +; replace let eax+[?image.x+edx] (has 2 ++) +; with: let ecx=[?image.x+edx], eax+ecx + +macro let [p] { +forward + define ?s 0 + + ; a=&b, lea r, [b] + + match =0 a==&(b), ?s p \{ + lea a, [b] + define ?s 1 + \} + + match =0 a==&b, ?s p \{ + lea a, b + define ?s 1 + \} + + match =0 a> + xor a, a + ELSE + mov a, b + END IF + END IF + define ?s 1 + \} + + ; binary and/or + + match =0 a&b, ?s p \{ and a, b + define ?s 1 \} + match =0 a|b, ?s p \{ or a, b + define ?s 1 \} + + ; shifts. note: >>> must be matched + ; before >> or there will be a partial match + + match =0 a>>>b, ?s p \{ shr a, b + define ?s 1 \} + match =0 a<>b, ?s p \{ sar a, b + define ?s 1 \} + match =0 a<>>b, ?s p \{ ror a, b + define ?s 1 \} + + ; increment/decrement. must be matched + ; before a-b, a+b + + match =0 a--, ?s p \{ + dec a + define ?s 1 + \} + + match =0 a++, ?s p \{ + inc a + define ?s 1 + \} + + ; add/subtract + + match =0 a-b, ?s p \{ + IF b eq 1 + dec a + ELSE + sub a, b + END IF + define ?s 1 + \} + + match =0 a+b, ?s p \{ + IF b eq 1 + inc a + ELSE + add a, b + END IF + define ?s 1 + \} + + ; multiply. 2/4/8/16 will be optimized + ; and replaced with shift left 1/2/3/4 + + match =0 a*b, ?s p \{ + IF b eq 2 + sal a, 1 + ELSE IF b eq 4 + sal a, 2 + ELSE IF b eq 8 + sal a, 3 + ELSE IF b eq 16 + sal a, 4 + ELSE + imul a, b + END IF + define ?s 1 + \} + + ; divide. a: must be eax or m/2/4/8/16. + ; b: must be m, ecx or 2/4/8/16. + ; example: eax=n/123 may be written as: + + ; let eax=n, ecx=123, eax/ecx + + ; ... instead of 4 separate lines + + match =0 a/b, ?s p \{ + IF b eq 2 + sar a, 1 + ELSE IF b eq 4 + sar a, 2 + ELSE IF b eq 8 + sar a, 3 + ELSE IF b eq 16 + sar a, 4 + ELSE + IF a eq eax + cdq + idiv b + ELSE + 'Unsupported' + END IF + END IF + define ?s 1 + \} + + ; jmp/jz/jnz. only support the most + ; common ones for fast assembly speed... + + match =0 =jmp l, ?s p \{ + jmp l + define ?s 1 + \} + + match =0 =jz l, ?s p \{ + jz l + define ?s 1 + \} + + match =0 =jnz l, ?s p \{ + jnz l + define ?s 1 + \} + + ; unary prefixes + + match =0 -a, ?s p \{ + neg a + define ?s 1 + \} + + match =0 =neg a, ?s p \{ + neg a + define ?s 1 + \} + + match =0 =not a, ?s p \{ + not a + define ?s 1 + \} + + match =0 =bswap a, ?s p \{ + bswap a + define ?s 1 + \} + + match =0 xchg(a=,b), ?s p \{ + xchg a, b + define ?s 1 + \} + + match =0 =mul a, ?s p \{ + mul a + define ?s 1 + \} + + match =0 =div a, ?s p \{ + div a + define ?s 1 + \} + + verify let +} + +;;;;;;;;;;;;;;;;; GET SIZE/SIGN ;;;;;;;;;;;;;;;;;; + +; from t=type name, return s=size and +; i=sign in numeric constants. example: + +; size=0 +; sign=0 +; @gets i32, size, sign ; s=32, i=1 + +macro @gets t, s, i { + s=0 + i=0 + IF t eq u32 | t eq i32 | t eq dword + s=32 + ELSE IF t eq u16 | t eq i16 | t eq word + s=16 + ELSE IF t eq u8 | t eq i8 | t eq byte + s=8 + ELSE + 'Unknown type' + END IF + IF t eq i32 | t eq i16 | t eq i8 + i=1 + END IF +} + +;;;;;;;;;;;;;;; POINTER ARITHMETIC ;;;;;;;;;;;;;;; + +;;;;;;;;;;;;;;;;;; GET/SET VALUE ;;;;;;;;;;;;;;;;; + +; helper load/store... + +; t=type, r=register, v=value, +; s=size, i=sign + +macro @gv t, r, v, s, i { + IF s=32 + mov r, v + ELSE IF s=8 + IF i=1 + movsx r, byte v + ELSE + movzx r, byte v + END IF + ELSE IF s=16 + IF i=1 + movsx r, word v + ELSE + movzx r, word v + END IF + END IF +} + +macro @get t, r, [v] { + common + local s, i ; get size + @gets t, s, i ; and sign + define ?s 0 + match *a, v \{ ; *p + match x++, a \\{ ; *p++ + ?a equ x + ?o equ add + define ?s 1 + \\} + match =0 \ + x--, ?s a \\{ ; *p-- + ?a equ x + ?o equ sub + define ?s 1 + \\} + match =0 x, ?s a \\{ ; else, *p + ?a equ x + ?o equ ; no advance + define ?s 1 + \\} + IF ~ ?a is.r? + 'Error' + END IF + @gv t, r, [?a], s, i ; get value + IF ~ ?o eq ; advance? + ?o ?a, s/8 ; add/sub n + END IF + verify + \} + match =0 a, ?s v \{ ; r + @gv t, r, a, s, i + define ?s 1 + \} + verify + restore ?a, ?o +} + +; t=type, r=register, v=value + +macro @sv t, r, v { + IF t eq u32 | t eq i32 | t eq dword + mov dword v, r + ELSE IF t eq u16 \ + | t eq i16 | t eq word + IF r eq eax + mov v, ax + ELSE IF r eq ecx + mov v, cx + ELSE IF r eq edx + mov v, dx + ELSE IF r eq ebx + mov v, bx + ELSE ; assume i + mov dword v, r + END IF + ELSE IF t eq u8 \ + | t eq i8 | t eq byte + IF r eq eax + mov v, al + ELSE IF r eq ecx + mov v, cl + ELSE IF r eq edx + mov v, dl + ELSE IF r eq ebx + mov v, bl + ELSE ; assume i + mov dword v, r + END IF + ELSE + 'Unknown type/size' + END IF +} + +macro @set t, r, [v] { + common + local s, i ; get size + @gets t, s, i ; and sign + define ?s 0 + match *a, v \{ ; *p + match x++, a \\{ ; *p++ + ?a equ x + ?o equ add + define ?s 1 + \\} + match =0 \ + x--, ?s a \\{ ; *p-- + ?a equ x + ?o equ sub + define ?s 1 + \\} + match =0 x, ?s a \\{ ; else, *p + ?a equ x + ?o equ ; no advance + define ?s 1 + \\} + IF ~ ?a is.r? + 'Error' + END IF + @sv t, r, [?a] ; set value + IF ~ ?o eq ; advance + ?o ?a, s/8 ; add/sub n + END IF + verify + \} + match =0 a, ?s v \{ ; r + @sv t, r, a ; set value + define ?s 1 + \} + verify + restore ?a, ?o +} + +;;;;;;;;;;;;;;;; POINTER OPERATION ;;;;;;;;;;;;;;; + +macro let [p] { + forward + define ?s 0 + match =0 (t) \ ; (t) a=*(b) + a==*(b), ?s p \{ + @get t, a, [b] + define ?s 1 + \} + match =0 \ ; a=*(b) + a==*(b), ?s p \{ ; (u8) default + @get u8, a, [b] + define ?s 1 + \} + match =0 (t) \ ; (t) *(a)=b + *(a)==b, ?s p \{ + @set t, b, [a] + define ?s 1 + \} + match =0 \ ; *(a)=b + *(a)==b, ?s p \{ ; (u8) default + @set u8, b, [a] + define ?s 1 + \} + match \ + (t) a==b, p \{ ; (t) a=b + match *x, a \\{ ; m,m + match *y, b \\\{ + @get t, ebx, b ; use ebx + @set t, ebx, a + define ?s 1 + \\\} + \\} + IF ?s eq 0 + match *y, b \\{ ; source=*p + @get t, a, b + define ?s 1 + \\} + IF ?s eq 0 + match *x, a \\{ ; destiny=*p + @set t, b, a + define ?s 1 + \\} + END IF + END IF + \} + match =0 \ + a==b, ?s p \{ ; a=b + match *x, a \\{ ; m,m + match *y, b \\\{ + @get u8, ebx, b ; use ebx + @set u8, ebx, a + define ?s 1 + \\\} + \\} + IF ?s eq 0 + match *y, b \\{ ; source=* + @get u8, a, b + define ?s 1 + \\} + IF ?s eq 0 + match *x, a \\{ ; destiny=*p + @set u8, b, a + define ?s 1 + \\} + END IF + END IF + \} + + ; 2-DO: insert improved let + + IF ?s eq 0 ; default + let p + END IF +} + +;;;;;;;;;;;;;;;;;;; FUNCTION ;;;;;;;;;;;;;;;;;;;;; + +macro pushr [p] { ; push parameters backwards + common ; to access forwards + IF ~p eq + reverse + pushd p + common + END IF +} + +; call a/ddress direct or p/ointer indirect + +macro call a, [p] { + common pushr p + call a +} + +macro callp f, [p] { common call [f], p } + +; call "function" forward reference that +; has not been defined yet + +macro callf f, [p] { common call !#f, p } + +; call "variadic" procedure with "variable +; arguments" (...). push invisible # arguments +; last, call, then adjust esp after + +macro callv f, [p] { + common ?n=0 + reverse pushd p + ?n=?n+1 + common push ?n + call f + add esp, (?n+1)*4 +} + +; call "interface" + +macro callx c, x, [p] { + common + pushr p ; push parameters + mov eax, c + push eax ; push class address + mov eax, [eax] + call dword [eax+x] ; call method offset +} + +; call function pointer IF non-zero + +macro callfp f { + cmp dword [f], 0 + jz @f + call dword [f] + @@: +} + +; call function IF defined + +macro ?call name, [p] { + common + IF defined name + call name, p + END IF +} + +; call function then get return. example: + +; get n=text.n t +; get c=rgb 128, 0, 64 + +macro get [p] { + common + define ?s 0 + match v==f ps, p \{ + f ps + mov v, eax + define ?s 1 + \} + match =0 v==f, ?s p \{ + f + mov v, eax + define ?s 1 + \} + verify get +} + +; set label for try/fail + +define ?ef .! ; end function + +macro fault l { define ?ef l } +macro catch l { define ?ef l } + +; call function then jmp to return +; if it returns 0. example: + +; try open filename +; try p=allocate 4*KB + +macro try [p] { + common + define ?s 0 + match a==b, p \{ + b + mov a, eax + define ?s 1 + \} + IF ?s eq 0 + common p + END IF + fail ?ef ; endf +} + +;;;;;;;;;;;;;; FUNCTION/PROCEDURE ;;;;;;;;;;;;;;; + +; create "function/proc/edure"... + +macro function name, [p] { + common + local i, n + n=0 + forward + n=n+1 + common + !#name#$type='f' + + ; only insert this inside of the executable + ; if it was accessed somewhere + + IF used !#name ; real function !name + !#name: + + ; macro to call with no prefix. + ; example: f a, b, c + + macro name p \{ + pushr p + call !\#name + \} + + ?begin equ !#name + ?parameters equ p + ?alias equ + + ..n.parameters=0 + ..n.locals=0 + ..locals.size=0 + + ; create parameter names and offsets + + IF ~ p eq ; if parameters + virtual at ebp+8 + forward + local ..p + ..p dd ? ; (ebp+8)+i*4 + p equ [..p] + ..n.parameters=\ ; i++ + ..n.parameters+1 + common + END virtual + push ebp ; create stack frame + mov ebp, esp + END IF + ; ... +} + +; HL return statement. use this instead of +; ret/n in functions. no ret/urn before endf. +; it inserts one automatically + +macro return v { + IF ~v eq ; value? + mov eax, v + END IF + IF ..n.parameters<>0 ; if parameters + mov esp, ebp + pop ebp + ret ..n.parameters*4 ; ret n + ELSE IF ..n.locals<>0 ; if locals + mov esp, ebp + pop ebp + ret + ELSE + ret + END IF +} + +; end function + +macro endf v { + IF ~v eq + mov eax, v + END IF + .!: + return + .$=$-?begin ; total size + IF ..n.parameters<>0 ; if parameters + match p, ?parameters + \{ restore p, ?begin \} + END IF + IF ..n.locals<>0 ; if locals + match l, local.names + \{ restore l \} + match a, ?alias \ + \{ restore a \} + fault .! ; reset try label + END IF + + ; end "if used name" at very beginning + ; of function + + END IF +} + +; aliases for register names inside functions. +; endf will restore names. example: + +; alias x=r0, y=r1, w=r2, h=r3, c=v1 + +macro alias [x] { + forward + syntax 0 + match name==r, x \{ + ?list.attach ?alias, name + name equ r + syntax 1 + \} + verify +} + +; end alias outside function + +macro endal + { match a, ?alias \{ restore a \} } + +;;;;;;;;;;;;;;;;;;;;; LOCALS ;;;;;;;;;;;;;;;;;;;;; + +; locals ... - create local 32BIT variables. +; example: locals x, y, n, c + +macro locals [p] { + common local.names equ p + forward ..n.locals=..n.locals+1 + common ..locals.size=..n.locals*4 + virtual at ebp-..locals.size + forward + local ..l + ..l dd ? + p equ [..l] + common + END virtual + IF ..n.parameters=0 ; create stack frame? + push ebp + mov ebp, esp + END IF + sub esp, ..locals.size ; allocate locals +} + +; create locals of specified sizes or 32BIT. +; example: + +; locale x, y, username(32), filename(256),\ +; image(IMAGE.$), my.font(FONT.$), etc + +macro locale [p] { + common + ..locals.size=0 + forward ; get names and sizes + define ?s 0 + match name(size), p \{ ; size specified + ?list.attach \ + local.names, name + verify.size size + ..locals.size=..locals.size+size + define ?s 1 + \} + match =0 name, ?s p \{ ; default 32BIT + ?list.attach \ + local.names, name + ..locals.size=..locals.size+4 + define ?s 1 + \} + ..n.locals=..n.locals+1 + common + virtual at ebp-..locals.size ; get offsets + forward + local ..l + define ?s 0 + match name(size), p \{ + ..l dd (size/4) dup(?) + name equ [..l] + define ?s 1 + \} + match =0 name, ?s p \{ ; default 32BIT + ..l dd ? + name equ [..l] + define ?s 1 + \} + common + END virtual + IF ..n.parameters=0 ; create stack frame? + push ebp + mov ebp, esp + END IF + sub esp, ..locals.size ; allocate locals +} + +;;;;;;;;;;;;;;;;;; IF EXPRESSION ;;;;;;;;;;;;;;;;; + +?NOT equ 0 +?use.r equ 0 + +; jump if condition to l (or ?NOT IF 1) + +macro jif l, [c] { +common + local f + define ?s 0 + + match =0 =true, ?s c \{ + test eax, eax + jz l + define ?s 1 + \} + match =0 =false, ?s c \{ + test eax, eax + jnz l + define ?s 1 + \} + match =0 =valid, ?s c \{ + cmp eax, -1 + je l + define ?s 1 + \} + match =0 =invalid, ?s c \{ + cmp eax, -1 + jne l + define ?s 1 + \} + + macro ?J O,A,C,B, [X] \{ + match =0 X, ?s c \\{ + IF ?use.r eq 0 + O A, B ; opcode o1, o2 + ELSE + mov ?use.r, A + O ?use.r, B + END IF + IF ?NOT eq 0 + j\#C l + ELSE + jN\#C l + END IF + define ?s 1 + \\} + \} + + ; standard expressions... + + ?J cmp,a,NE,b, a<>b ; a not b (a<>b) + + ?J cmp,a,BE,b, a<<==b ; a<<=b + ?J cmp,a,AE,b, a>>==b ; a>>=b + ?J cmp,a,B,b, a<>b ; a>>b + + ?J cmp,a,LE,b, a<==b ; a<=b + ?J cmp,a,GE,b, a>==b ; a>=b + ?J cmp,a,L,b, ab ; a>b + ?J cmp,a,E,b, a==b ; a=b + ?J cmp,a,NE,b, a =not b ; a not b (a<>b) + ?J test,a,NE,b, a&b ; a&b + ?J or,a,NE,b, a|b ; a|b + ?J cmp,a,E,0, =not a ; not a (=0) + + ; 2-DO: support pointer arithmetic + ; and functions: if p=allocate 4*KB + + ; else, default: a (not 0, by itself) + + ?J cmp,a,NE,0,a + + verify 'Invalid expression' c + ?use.r equ 0 +} + +; jump to l IF NOT condition + +macro jifn l, [c] { + common + ?NOT equ 1 + jif l, c + ?NOT equ 0 ; restore default +} + +; HL IF/ELSE + +macro if.begin { + local ..start, ..else, ..end + ?IF equ + ?START equ ..start + ?ELSE equ ..else + ?END equ ..end + ?START: +} + +macro if.n [c] { + common + if.begin + jif ?ELSE, c +} + +macro if [p] { + common + if.begin + define ?s 0 + match a=,b, p \{ + jifn ?ELSE, a + let b + define ?s 1 + \} + match =0, ?s \{ + jifn ?ELSE, p + \} + verify if +} + +macro else [p] { + common + jmp ?END + ?ELSE: + restore ?IF + ?IF equ , + match =,x, p \{ let x \} +} + +macro else.if [p] { + common + local ..else + jmp ?END + ?ELSE: + restore ?ELSE + ?ELSE equ ..else + define ?s 0 + match a=,b, p \{ + jifn ?ELSE, a + . b + define ?s 1 + \} + match =0 a, ?s p \{ + jifn ?ELSE, a + \} + verify else.if +} + +macro end [p] { + common + IF ?IF eq + ?ELSE: + END IF + ?END: + restore ?IF, ?START, ?ELSE, ?END + match =,x, p \{ let x \} +} + +; call function with parameters then +; if non/zero + +macro !if f, [p] { + common f p + if eax +} + +macro !if.n f, [p] { + common f p + if eax=0 +} + +jNE equ jne +jNNE equ je +jNA equ jna +jNB equ jnb +jNG equ jng +jNL equ jnl + +macro jifc r, c, l { + test r, r + j#c l +} + +macro fail l { + IF l eq + jifc eax, z, ?ef + ELSE + jifc eax, z, l + END IF +} + +macro failn l { + IF l eq + cmp eax, -1 + je ?ef + ELSE + cmp eax, -1 + je l + END IF +} + +macro success l { jifc eax, nz, l } + +failnz fix success + +; fail? or escape? on condition +; example: escape? eax=-1 + +macro fail? [c] { + common + IF c eq + test eax, eax + jz ?ef + ELSE + if c + jmp ?ef + end + END IF +} + +;;;;;;;;;;;;;;;;;;;;;; LOOP ;;;;;;;;;;;;;;;;;;;;;; + +; loop variations. unfinished... + +macro forever [p] { + common + local ..start, ..next, ..end + ?STARTFV equ ..start + ?NEXTFV equ ..next + ?ENDFV equ ..end + ?STARTFV: + ?HL.BLOCK='fv' + match =,x, p \{ let x \} +} + +macro endfv [p] { + common + ?NEXTFV: + jmp ?STARTFV + ?ENDFV: + restore ?STARTFV, ?NEXTFV, ?ENDFV + match a=,b, p \{ let b \} +} + +macro repeat n { + local ..start, ..end + ?STARTR equ ..start + ?ENDR equ ..end + ?NR equ n + ?HL.BLOCK='r' + ?STARTR: + cmp ?NR, 0 + jle ?ENDR +} + +macro endr { + dec ?NR + jmp ?STARTR + ?ENDR: + restore ?STARTR, ?ENDR, ?NR +} + +macro while [c] { + common + local ..a, ..b, ..c + ?STARTW equ ..a + ?NEXTW equ ..b + ?ENDW equ ..c + ?HL.BLOCK='w' + ?STARTW: + define ?s 0 + match a=,b, c \{ + jifn ?ENDW, a + let b + define ?s 1 + \} + match =0 a, ?s c \{ + jifn ?ENDW, a + \} +} + +macro endw [p] { + common + ?NEXTW: + jmp ?STARTW + ?ENDW: + restore ?STARTW, ?NEXTW, ?ENDW + match =,x, p \{ let x \} +} + +; unfinished, exhausted, can't keep +; eyes open... 2-DO: improve all +; blocks/if/loops + +; loop ; infinite +; loop n ; # times +; loop i=0 to n ; iterate (2-DO) +; loop X, ... ; optional arithmetic + +?LOOP.N fix 1 ; repeat # times +?LOOP.I fix 2 ; index, i=0 to n +?LOOP.F fix 3 ; forever, infinite + +macro loop [c] { + common + local ..a, ..b, ..c + ?STARTL equ ..a + ?NEXTL equ ..b + ?ENDL equ ..c + ?STARTL: + define ?s 0 + match =0 n=,x, ?s c \{ ; loop n, ... + ?HL.BLOCK=?LOOP.N + ?N equ n + cmp n, 0 + jle ?ENDL + let x + define ?s 1 + \} + match =0 =,x, ?s c \{ ; loop, ... + ?HL.BLOCK=?LOOP.F + let x + define ?s 1 + \} + match =0 n, ?s c \{ ; loop n + ?HL.BLOCK=?LOOP.N + ?N equ n + cmp n, 0 + jle ?ENDL + define ?s 1 + \} + verify loop +} + +macro endl [p] { + common + IF ?HL.BLOCK=?LOOP.N + dec ?N + restore ?N + END IF + ?NEXTL: + jmp ?STARTL + ?ENDL: + restore ?STARTL, ?NEXTL, ?ENDL + match =,x, p \{ let x \} +} + +macro break [p] { + common + IF ?HL.BLOCK='fv' + jmp ?ENDFV + ELSE IF ?HL.BLOCK='r' + jmp ?ENDR + ELSE IF ?HL.BLOCK='w' + jmp ?ENDW + ELSE IF ?HL.BLOCK='l' + jmp ?ENDL + END IF + match =,x, p \{ let x \} +} + +macro next [p] { + common + IF ?HL.BLOCK='fv' + jmp ?STARTFV + ELSE IF ?HL.BLOCK='r' + jmp ?STARTR + ELSE IF ?HL.BLOCK='w' + jmp ?STARTW + ELSE IF ?HL.BLOCK='l' + jmp ?STARTL + END IF + match =,x, p \{ let x \} +} + +macro continue [p] { common next p } + +; 2-DO: create one "end" for all HL blocks + +;;;;;;;;;;;;;;;;;; NEW LANGUAGE ;;;;;;;;;;;;;;;;;; + +; upgrade let with multi-statements. +; unfinished. 2-DO: create one good "let" +; with helper macros + +macro let [p] { + forward + define ?s 0 + match =0 \ + l:, ?s p \{ + l: + define ?s 1 + \} + match =0 \ + =go x, ?s p \{ + jmp x + define ?s 1 + \} + match =0 \ + =if x, ?s p \{ + if x + define ?s 1 + \} + match =0 \ + =return x, ?s p \{ + return x + define ?s 1 + \} + match =0 \ + =return, ?s p \{ + return + define ?s 1 + \} + match =0 \ + =while x, ?s p \{ + while x + define ?s 1 + \} + match =0 \ + =forever x, ?s p \{ + forever x + define ?s 1 + \} + match =0 \ + =loop x, ?s p \{ + loop x + define ?s 1 + \} + match =0 \ + =end, ?s p \{ + end + define ?s 1 + \} + match =0 \ + =endw, ?s p \{ + endw + define ?s 1 + \} + match =0 \ + =endl, ?s p \{ + endl + define ?s 1 + \} + match =0 \ + =endfv x, ?s p \{ + endfv + define ?s 1 + \} + match =0 \ + =break, ?s p \{ + break + define ?s 1 + \} + match =0 \ + =next, ?s p \{ + next + define ?s 1 + \} + IF ?s eq 0 + let p + END IF +} + +macro . [p] { common let p } + +macro go [p] { + common + define ?s 0 + match a=,b, p \{ + jmp a + let b + define ?s 1 + \} + match =0, ?s \{ jmp p \} +} \ No newline at end of file diff --git a/programs/games/codemaster/include/memory.inc b/programs/games/codemaster/include/memory.inc new file mode 100644 index 0000000000..7c5bb2db49 --- /dev/null +++ b/programs/games/codemaster/include/memory.inc @@ -0,0 +1,274 @@ +; $$$$$$$$$$$$$$$$$$$ ABAKIS $$$$$$$$$$$$$$$$$$$$$ +; *************** STAR^2 SOFTWARE **************** +; ????????????????? MEMORY.INC ??????????????????? + +; allocate n ; see SYSTEM.INC +; allocate.p p, n +; destroy p + +; memory.set p, v, n ; 32BIT set/copy/zero +; memory.copy a, b, n +; memory.zero p, n + +; get.bit v, n ; get/set/zero bit +; set.bit v, n +; zero.bit v, n +; enable.f v, n ; enable/disable flag +; disable.f v, n + +; power.2 n ; is power of 2? which one? +; align.n n, p ; versatile align n to p + +;;;;;;;;;;;;; MEMORY COPY, SET, ZERO ;;;;;;;;;;;;; + +; portable. 32BIT + +function memory.copy, a, b, n + alias p=r0, q=r1 + . p=a, q=b, n>>>2 + loop n, (u32) *p++=*q++, endl +endf + +function memory.set, a, b, n + alias p=r0, v=r1, x=r2 + . p=a, v=b, n>>>2 + loop n, (u32) *p++=v, endl +endf + +macro memory.zero p, n { memory.set p, 0, n } + +; x86 specific. aligned + +function memory.copy.x, a, b, n + push r6 r7 + . r7=a,\ + r6=b, r1=n + test r7, r6 ; address=0? + jz .e + cmp r1, 4 ; if n<4 + jb @f + push r1 + shr r1, 2 ; n/4 + rep movsd ; copy dwords + pop r1 + and r1, 3 ; modulo 4 + jz .e ; remainder? + @@: + rep movsb ; copy bytes + .e: + pop r7 r6 +endf + +function memory.set.x, p, v, n + push r7 + . r7=p, r0=v,\ + r0*01010101h,\ + r1=n + test r7, r7 ; address=0? + jz .e + cmp r1, 4 ; n<4? + jb @f + push r1 + shr r1, 2 + rep stosd ; copy dwords + pop r1 + and r1, 3 ; modulo 4 + jz .e ; remainder? + @@: + rep stosb ; copy bytes + .e: + pop r7 +endf + +;;;;;;;;;;;;;;;; GET/SET/ZERO BIT ;;;;;;;;;;;;;;;; + +; 76543210. warning: r0/r1/r2 cannot be used +; as parameters. 'v' should be m, 'i' can be m/i + +macro get.bit v, i { ; (v>>i)&1 + . r0=v, r1=i, r0>>cl, r0&1 +} + +macro set.bit v, i { ; v|=(1<>(i*4))&1111b + . r0=v, r1=i, r1<<2, r0>>cl, r0&1111b +} + +macro set.nibble v, i, n { ; v|=(n<<(i*4)) + . r0=v, r1=i, r2=n, r1<<2, r2<>(i*2))&11b + . r0=v, r1=i, r1<<1, r0>>cl, r0&11b +} + +macro set.couple v, i, n { ; v|=(n<<(i*2)) + . r0=v, r1=i, r2=n, r1<<1, r2<>>8 } + +macro reverse.16 n + { . r0=n, cl=al, al=ah, ah=cl } + +;;;;;;;;;;;;;;;;;; POWERS OF 2 ;;;;;;;;;;;;;;;;;;; + +; an unsigned number is a power of 2 if only +; 1 BIT is set: if !(n&n-1). subtracting 1 +; inverts all BITs. if n=10000000b (80h/128), +; n&01111111b=0 + +; to find out which power of 2, search n +; for 1st 0 BIT from right to left + +; is n power of 2? example: power.2 128 +; returns 7 + +function power.2, n + locals i + . r0=n + if r0<2, go .r0, end + . r1=r0, r1-1, r0&r1 + test r0, r0 + jnz .r0 + . n--, i=1 + @@: + . r0=1, r1=i, r0<>16)&7FFFh)/(n+1) + +function random, n + . r0=@seed + if false ; initialize seed + rdtsc ; read date/time stamp counter + . @seed=r0 + end + . r0*343FDh, r0+269EC3h,\ + @seed=r0, r0>>16, r0&7FFFh,\ + r1=n, r1+1, r0/r1, r0=r2 +endf + +; random(from-to-2)+from + +function random.x, from, to + . r0=from, r0-to, r0-2 + random r0 + . r0+from +endf + +;;;;;;;;;;;;;;;;;;; FILE I/O ;;;;;;;;;;;;;;;;;;;;; + +numeric EOF=-1,\ + CREATE_NEW=1, CREATE_ALWAYS, OPEN_EXISTING,\ + OPEN_ALWAYS, TRUNCATE_EXISTING,\ + GENERIC_READ=80000000h, GENERIC_WRITE=40000000h,\ + FILE_SHARE_READ=1, FILE_SHARE_WRITE,\ + FILE_ATTRIBUTE_NORMAL=80h,\ + SEEK.BEGIN=0, SEEK.SET, SEEK.END + +;;;;;;;;;;;;;;;;; CURRENT FILE ;;;;;;;;;;;;;;;;;;; + +align + +void file.p ; pointer for load/save +integer file.h,\ ; handle + file.n64, file.n ; size 64:32 +integer tmp.rw + +macro flush { destroy file.p } + +; return handle or -1 if error + +function os.create.file, file, access, share,\ + security, action, attributes, template + call !text.copy, file.name, file + CreateFileA file.name, access, share,\ + security, action, attributes, template + . file.h=r0 +endf + +macro os.open file { + os.create.file file, GENERIC_READ \ + or GENERIC_WRITE, FILE_SHARE_READ,\ + 0, OPEN_EXISTING, 0, 0 +} + +macro os.create file { + os.create.file file, GENERIC_WRITE,\ + 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0 +} + +macro os.seek n, r + { SetFilePointer file.h, n, 0, r } + +macro os.read p, n { + . r0=&tmp.rw + ReadFile file.h, p, n, r0, 0 +} + +macro os.write p, n { + . r0=&tmp.rw + WriteFile file.h, p, n, r0, 0 +} + +macro os.get.file.size { GetFileSize file.h, 0 } + +macro os.close { CloseHandle file.h } + +;;;;;;;;;;;;;;; COPY, MOVE, DELETE ;;;;;;;;;;;;;;; + +macro copy.file a, b, r { CopyFileA a, b, r } +macro move.file a, b { MoveFileA a, b } +macro delete.file f { DeleteFileA f } +macro rename.file a, b { os.move.file a, b } + +;;;;;;;;;;;;;;;;;; DIRECTORIES ;;;;;;;;;;;;;;;;;;; + +macro os.get.directory + { GetCurrentDirectoryA 256, directory } + +macro os.set.directory f + { SetCurrentDirectoryA f } + +macro os.create.directory f + { CreateDirectoryA f, 0 } + +macro os.get.file.name + { GetModuleFileNameA 0, directory, 1*KB } + +macro os.get.command.line { GetCommandLineA } + +;;;;;;;;;;;;;;;;;;;; EXECUTE ;;;;;;;;;;;;;;;;;;;;; + +macro execute file + { ShellExecuteA 0, 0, file, 0, 0, 3 } + +;;;;;;;;;;;;;;;;;; FIND FILES ;;;;;;;;;;;;;;;;;;;; + +macro os.find.data { + BLOCK find.data(338) ; WIN32_FIND_DATA + os.found.file equ find.data+44 +} + +macro os.find.first file + { FindFirstFileA file, find.data } + +macro os.find.next + { FindNextFileA find.data.h, find.data } + +macro os.find.end { FindClose find.data.h } + +;;;;;;;;;;;;;;;;;;;;; REDRAW ;;;;;;;;;;;;;;;;;;;;; + +macro create.blank.screen w, h { + create.vga os.w, os.h, WHITE ; 0 + create.blank.window w, h +} + +macro redraw { + calle draw +} + +macro render b { + ; call !clear.screen + IF b eq + redraw + END IF + IF used cursor + call !draw.cursor, cursor + END IF + IF b eq + call !show.vga + ELSE + copy.box box, b + call !show.vga.box + END IF +} + +;;;;;;;;;;;;;;;;;;;; WINDOZE ;;;;;;;;;;;;;;;;;;;;; + +macro POINT [a] { a: integer a#.x, a#.y } + +macro RECT [a] { a: integer a#.left,\ + a#.top, a#.right, a#.bottom } + +macro MSG [a] { + a: integer a#.hwnd, a#.message,\ + a#.wParam, a#.lParam, a#.time + POINT a#.pt +} + +macro WNDCLASSEX [a] { + a: integer a#.cbSize=48,\ + a#.style, a#.lpfnWndProc, a#.cbClsExtra,\ + a#.cbWndExtra, a#.hInstance, a#.hIcon,\ + a#.hCursor, a#.hbrBackground,\ + a#.lpszMenuName, a#.lpszClassName, a#.hIconSm + WNDCLASSEX.$=$-a +} + +macro PAINTSTRUCT [a] { + a: integer a#.hdc, a#.fErase + RECT a#.rcPaint + integer a#.fRestore, a#.fIncUpdate + text a#.rgbReserved(32) +} + +macro BITMAP [a] { + a: integer a#.bmType,\ + a#.bmWidth, a#.bmHeight, a#.bmWidthBytes + short a#.bmPlanes, a#.bmBitsPixel + void a#.bmBits + BITMAP.$=$-a +} + +macro BITMAPINFOHEADER [a] { + a: integer a#.biSize, a#.biWidth, a#.biHeight + short a#.biPlanes, a#.biBitCount + integer a#.biCompression, a#.biSizeImage,\ + a#.biXPelsPerMeter, a#.biYPelsPerMeter,\ + a#.biClrUsed, a#.biClrImportant + BITMAPINFOHEADER.$=$-a +} + +macro BITMAPINFO [a] { + BITMAPINFOHEADER a + integer bmiColors + BITMAPINFO.$=BITMAPINFOHEADER.$+4 +} + +; window messages + +numeric WM_*, \ + CREATE=1, DESTROY=2, MOVE=3, SIZE=5,\ + SETFOCUS=7, KILLFOCUS=8, GETTEXT=0Dh,\ + SETTEXT=0Ch, GETTEXTLENGTH=0Eh,\ + PAINT=0Fh, CLOSE=10h, QUIT=12h, CUT=300h,\ + COPY=301h, PASTE=302h, CLEAR=303h,\ + SETFONT=30h, COMMAND=111h, TIMER=0113h + +; window styles + +numeric WS_*, \ + POPUP=80000000h, MINIMIZE=20000000h,\ + VISIBLE=10000000h, MAXIMIZE=1000000h,\ + CAPTION=0C00000h, BORDER=800000h,\ + DLGFRAME=400000h, VSCROLL=200000h,\ + HSCROLL=100000h, SYSMENU=80000h,\ + THICKFRAME=40000h, MINIMIZEBOX=20000h,\ + MAXIMIZEBOX=10000h + +WS_BLANK = WS_VISIBLE+WS_POPUP +WS_DEFAULT = WS_VISIBLE+WS_CAPTION+\ + WS_MINIMIZEBOX+WS_SYSMENU + +CS_DBLCLKS=8 + +; keyboard+mouse messages + +numeric WM_*,\ + KEYDOWN=100h, KEYUP, CHAR, DEADCHAR,\ + SYSKEYDOWN, SYSKEYUP, SYSCHAR + +numeric WM_*,\ + MOUSEMOVE=200h, LBUTTONDOWN, LBUTTONUP,\ + LBUTTONDBLCLK, RBUTTONDOWN, RBUTTONUP,\ + RBUTTONDBLCLK, MBUTTONDOWN, MBUTTONUP,\ + MBUTTONDBLCLK, MOUSEWHEEL + +; virtual key codes. function keys=(6Fh+N). +; example: F1=70h (6Fh+1) + +numeric K.*,\ + FUNCTION=6Fh, LEFT=25h, UP=26h, RIGHT=27h,\ + DOWN=28h, ESCAPE=1Bh, SPACE=20h, DELETE=2Eh,\ + CONTROL=11h, LCONTROL=0A2h, RCONTROL=0A3h,\ + LALT=0A4h, RALT=0A5h, BACK=8, TAB=9,\ + RETURN=0Dh, END=23h, HOME=24h,\ + A='A', S='S', D='D', W='W' + +SRCCOPY=00CC0020h + +macro os.show.cursor { ShowCursor 1 } + +;;;;;;;;;;;;;;;;;;;;; SYSTEM ;;;;;;;;;;;;;;;;;;;;; + +align + +integer os.w, os.h, os.bpp + +void _hwnd ; handle +void _dc ; device context +void _mdc ; memory dc + +WNDCLASSEX _wc ; window +MSG _wm ; message +PAINTSTRUCT _ps ; for PAINT +BITMAP _bm ; for draw.bitmap.w + +void vga.hbm +BITMAPINFO vga.bmi +RECT vga.rect + +text _cn='WC', _wt='' ; classname, title + +;;;;;;;;;;;;;;;;; CREATE WINDOW ;;;;;;;;;;;;;;;;;; + +function create.window.x, style, procedure,\ + w, h, title, class.name + locals x, y + + . _wc.cbSize=WNDCLASSEX.$ + . _wc.hInstance=@module + . _wc.lpfnWndProc=procedure + . _wc.lpszClassName=class.name + . _wc.style=CS_DBLCLKS, _wc.hbrBackground=8 + get _wc.hIcon=LoadIconA 0, 7F00h + get _wc.hCursor=LoadCursorA 0, 7F00h + + try RegisterClassExA _wc + + . r0=os.w, r0>>1, r2=w, r2>>1, r0-r2, x=r0 + . r0=os.h, r0>>1, r2=h, r2>>1, r0-r2, y=r0 + + try _hwnd=CreateWindowExA 0, class.name,\ + title, style, x, y, w, h, 0, 0, @module, 0 +endf 1 + +macro create.blank.window w, h { + create.window.x WS_BLANK, !_window.procedure,\ + w, h, _wt, _wc +} + +macro create.default.window title { + create.window.x WS_DEFAULT, !_window.procedure,\ + os.w, os.h, title, _wc +} + +;;;;;;;;;;;;;;;;;; MESSAGE LOOP ;;;;;;;;;;;;;;;;;; + +macro begin.message.loop { + .begin.ml: + GetMessageA _wm, 0, 0, 0 + fail .end.ml + TranslateMessage _wm + DispatchMessageA _wm +} + +macro end.message.loop { + go .begin.ml + .end.ml: + . r0=_wm.wParam +} + +macro message.loop { + begin.message.loop + end.message.loop +} + +macro process.messages { + .begin.ml: + PeekMessageA _wm, 0, 0, 0, 0 + fail .no.message + GetMessageA _wm, 0, 0, 0 + fail .end.ml + TranslateMessage _wm + DispatchMessageA _wm + go .begin.ml + .no.message: +} + +macro end.messages { + go .begin.ml + .end.ml: + ExitProcess _wm.wParam +} + +macro minimize.window { ShowWindow _hwnd, 6 } + +;;;;;;;;;;;;;;;;;;;;;; INPUT ;;;;;;;;;;;;;;;;;;;;; + +align 4 + +integer event.id, key.event, mouse.event,\ + key, any.key, key.c, exit.if.esc=YES,\ + mouse.1, mouse.2, mouse.x, mouse.y,\ + mouse.px, mouse.py, mouse.double, mouse.wheel,\ + mouse.drag, mouse.drag.x, mouse.drag.y,\ + mouse.drop, mouse.drop.x, mouse.drop.y + +macro os.key.state k { GetAsyncKeyState k } + +macro os.set.cursor.xy x, y + { SetCursorPos x, y } + +function key.state, k + os.key.state k +endf + +; if key state + +macro if.key k { !if key.state K.#k } +macro if.not.keys k { !if.n key.state K.#k } + +function select.box, box + . r0=mouse.x, r1=mouse.y + IF defined cursor + . r0+cursor.spot.x, r1+cursor.spot.y + END IF + call !point.inside, box, r0, r1 +endf + +macro if.select box { !if select.box, box } +macro else.if.select box + { !else.if select.box, box } + +macro if.not.select box + { !if.n select.box, box } + +macro if.click box { + select.box box + and r0, mouse.1 + if true +} + +;;;;;;;;;;;;;;;;;;;;; EVENTS ;;;;;;;;;;;;;;;;;;;;; + +align +void !_on.event, !on.main,\ + !_on.create, !_on.destroy, !_on.close,\ + !_on.draw, !_on.game, !_on.command,\ + !_on.key, !_on.mouse, !_on.timer, !_on.exit + +macro define.events [e] + { mov [!!_on.#e], !on.#e } + +macro calle e { + if dword [!!_on.#e] + call dword [!!_on.#e] + end +} + +!call fix calle + +macro !on name { function on.#name } +macro !end { endf 1 } + +;;;;;;;;;;;;;;;;;;;;; TIMER ;;;;;;;;;;;;;;;;;;;;;; + +macro os.set.timer f, ms + { SetTimer _hwnd, 1, ms, f } + +macro set.timer a, b { + IF b eq + os.set.timer !on.timer, a + ELSE + os.set.timer a, b + END IF +} + +;;;;;;;;;;;;;;;; WINDOW PROCEDURE ;;;;;;;;;;;;;;;; + +function _window.procedure, window, message, wp, lp + alias m=r0 + . m=message, event.id=0, mouse.double=0 + + if m=WM_PAINT + get _dc=BeginPaint _hwnd, _ps + render + EndPaint _hwnd, _ps + go .default + + else.if m=WM_COMMAND + calle command + + else.if m=WM_KEYDOWN + . key=wp, event.id='k', key.event='k' + if exit.if.esc + if wp=K.ESCAPE + SendMessageA window, WM_DESTROY, 0, 0 + end + end + .key: + calle key + return 0 + + else.if m=WM_KEYUP + . key=NO, event.id='k', key.event='r' + go .key + + else.if m=WM_CHAR + . key=wp, event.id='k', key.event='c' + go .key + + else.if m=WM_MOUSEMOVE + . mouse.event='m' + if mouse.1 + if not mouse.drag + . mouse.drag=YES,\ + mouse.drag.x=mouse.x,\ + mouse.drag.y=mouse.y + end + end + .mouse: + . event.id='m', r0=lp, r1=r0,\ + r0&0FFFFh, mouse.x=r0,\ + r1>>16, r1&0FFFFh, mouse.y=r1 + calle mouse + if mouse.event='m' + . mouse.px=mouse.x,\ + mouse.py=mouse.y + end + return 0 + + else.if m=WM_LBUTTONDOWN + . mouse.event='c', mouse.1=YES,\ + mouse.drop=NO + go .mouse + + else.if m=WM_LBUTTONUP + . mouse.event='r', mouse.1=NO + if mouse.drag + . mouse.drop=YES,\ + mouse.drop.x=mouse.x,\ + mouse.drop.y=mouse.y,\ + mouse.drag=NO + end + go .mouse + + else.if m=WM_LBUTTONDBLCLK + . mouse.double=YES + go .mouse + + else.if m=WM_RBUTTONDOWN + . mouse.event='rc', mouse.2=YES + go .mouse + + else.if m=WM_RBUTTONUP + . mouse.event='rr', mouse.2=NO + go .mouse + + else.if m=WM_MOUSEWHEEL + . mouse.event='w', r1=wp,\ + r1>>16, mouse.wheel=r1 + go .mouse + + else.if m=WM_CREATE + calle create + go .default + + else.if m=WM_DESTROY + .destroy: + calle destroy + PostQuitMessage 0 + end + + .default: DefWindowProcA \ + window, message, wp, lp +endf + +;;;;;;;;;;;;;;; LOAD/DRAW H/BITMAP ;;;;;;;;;;;;;;; + +function load.bitmap.w, file + locals p + try p=LoadImageA @module, file, 0, 0, 0, 10h + GetObjectA p, BITMAP.$, _bm +endf p + +function draw.bitmap.w, hbmp, x, y, w, h + locals bmw, bmh + GetObjectA hbmp, BITMAP.$, _bm + . bmw=_bm.bmWidth, bmh=_bm.bmHeight + get _mdc=CreateCompatibleDC _dc + SelectObject _mdc, hbmp + StretchBlt _dc, x, y, w, h,\ + _mdc, 0, 0, bmw, bmh, SRCCOPY + DeleteDC _mdc +endf + +;;;;;;;;;;;;;;;;;;;;;; VGA ;;;;;;;;;;;;;;;;;;;;;;; + +macro os.get.screen.w + { get os.w=GetSystemMetrics 0 } + +macro os.get.screen.h + { get os.h=GetSystemMetrics 1 } + +function os.create.vga, w, h + alias p=r0, x=r1 + ; set.screen screen.w, screen.h, screen.bpp + try vga.hbm=CreateBitmap \ + screen.w, screen.h, 32, 1, vga.p + memory.zero vga.bmi, BITMAPINFOHEADER.$ + . vga.bmi.biSize=BITMAPINFOHEADER.$ + . vga.bmi.biWidth=screen.w + . x=screen.h, neg x, vga.bmi.biHeight=x + . vga.bmi.biPlanes=1, vga.bmi.biBitCount=32 +endf + +function os.show.vga + SetDIBits _dc, vga.hbm, 0, screen.h,\ + vga.p, vga.bmi, 0 + draw.bitmap.w vga.hbm, 0, 0, screen.w, screen.h + . vga.rect.left=0, vga.rect.top=0,\ + vga.rect.right=screen.w,\ + vga.rect.bottom=screen.h + InvalidateRect _hwnd, vga.rect, 0 +endf + +function show.vga.box + SetDIBits _dc, vga.hbm, 0, screen.h,\ + vga.p, vga.bmi, 0 + draw.bitmap.w vga.hbm,\ + box.x, box.y, box.w, box.y + . r0=box.x, r1=box.y,\ + vga.rect.left=r0, vga.rect.top=r1,\ + r0+box.w, vga.rect.right=r0,\ + r1+box.h, vga.rect.bottom=r1 + InvalidateRect _hwnd, vga.rect, 0 +endf + +macro show.vga.box b { + IF ~b eq + copy.box box, b + END IF + show.vga.box +} + +macro define.vga { os.define.vga } + +; create vga/buffer for drawing + +function create.vga, w, h, c + if vga.p=0, r0=w, r0*h, r0<<2 + try vga.p=allocate r0 + end + call !clear.screen, c + os.create.vga w, h +endf 1 + +function show.vga + os.show.vga +endf + +function set.vga, w, h + os.set.vga +endf + +function end.vga + destroy vga + os.end.vga +endf + +;;;;;;;;;;;;;;;;;; ENTER+EXIT ;;;;;;;;;;;;;;;;;;;; + +; user-defined enter/exit routines will be called +; if defined/nonzero + +function os.enter + try @module=GetModuleHandleA 0 + try @heap=HeapCreate 0, 0, 0 + try directory=allocate 1*KB + . r0=directory, *r0=0 + try file.name=allocate 1*KB + . r0=file.name, *r0=0 + os.get.directory + os.get.command.line + . command.line=r0 +endf 1 + +function exit + ExitProcess 0 +endf + +;;;;;;;;;;;;; EXECUTABLE STRUCTURE ;;;;;;;;;;;;;;; + +align + +section '.one' \ + code readable writable executable + !main: + os.enter + if false + say 'System error' + exit + end + call !main! + exit + ret + +function main! + os.get.screen.w + os.get.screen.h + set.screen WINDOW.W, WINDOW.H, 32 + try create.vga screen.w, screen.h, BLACK + define.events create, draw, key, mouse + create.blank.window screen.w, screen.h + os.show.cursor + message.loop +endf + +align \ No newline at end of file diff --git a/programs/games/codemaster/include/systemk.inc b/programs/games/codemaster/include/systemk.inc new file mode 100644 index 0000000000..e11650b74f --- /dev/null +++ b/programs/games/codemaster/include/systemk.inc @@ -0,0 +1,231 @@ +;;;;;;;;;;;;;;;;;;;;; SYSTEM ;;;;;;;;;;;;;;;;;;;;; + +; menuet interrupt: eax, ebx, ecx, edx + +macro mint a, b, c, d { + IF ~a eq + . r0=a + END IF + IF ~b eq + . r3=b + END IF + IF ~c eq + . r1=c + END IF + IF ~d eq + . r2=d + END IF + db 0CDh, 40h +} + +; events + +EVENT.REDRAW=1 +EVENT.KEY=2 +EVENT.BUTTON=3 + +align +integer timer.speed=-1,\ + timer.counter, event.delay=1 + +macro set.timer n { + . r0=n, r1=10, r0/r1 + . timer.speed=r0, timer.counter=r0 +} + +macro get.timer { mint 26, 9 } + +macro delay x { + . r0=x, r0/100, r3=r0 + mint 5 +} + +macro wait.event { mint 23, event.delay } + +;;;;;;;;;;;;;;;;;;;;; WINDOW ;;;;;;;;;;;;;;;;;;;;; + +function draw.window + . r2=0, r6=0, r7=0FFFFFFh + . r3=WINDOW.X, r3<<16, r3|screen.w + . r1=WINDOW.Y, r1<<16, r1|screen.h + mint 0 +endf + +macro draw.begin { mint 12, 1 } +macro draw.end { mint 12, 2 } +macro render { call !on.draw } ; mint 15, 3 +macro retrace { mint 18, 14 } + +;;;;;;;;;;;;;;;;;;;;; INPUT ;;;;;;;;;;;;;;;;;;;;;; + +align 4 + +align +integer event.type + +integer key, old.key, key.event +text keys.t(128) + +numeric KEY.ESCAPE=27, KEY.SPACE=' ',\ + KEY.UP=0B2h, KEY.RIGHT=0B3h, KEY.DOWN=0B1h,\ + KEY.LEFT=0B0h, KEY.A='a', KEY.S='s',\ + KEY.D='d', KEY.W='w' + +macro get.key.buffer { mint 26, 2, 1, keys.t } + +integer mouse.event,\ + mouse.1, mouse.2, mouse.x, mouse.y,\ + mouse.drag, mouse.drag.x, mouse.drag.y,\ + mouse.drop, mouse.drop.x, mouse.drop.y,\ + old.mouse.1, old.mouse.2,\ + old.mouse.x, old.mouse.y + +macro get.mouse.xy { mint 37, 0 } +macro get.mouse.buttons { mint 37, 2 } +macro get.mouse.wheel { mint 37, 3 } + +function update.mouse + . mouse.event=0 + . old.mouse.1=mouse.1, old.mouse.2=mouse.2 + . old.mouse.x=mouse.x, old.mouse.y=mouse.y + + get.mouse.xy + . r1=r0, r1&0FFFFh, r0>>>16, r0&0FFFFh + . mouse.x=r0, mouse.y=r1 + get.mouse.buttons + . r1=r0, r1&1, mouse.1=r1 + . r1=r0, r1&2, mouse.2=r1 + + if mouse.1 + if not old.mouse.1, mouse.event='c' + . mouse.drop=NO + callf on.mouse + return 1 + end + else.if old.mouse.1, mouse.event='r' + callf on.mouse + if mouse.drag + . mouse.drop=YES,\ + mouse.drop.x=mouse.x,\ + mouse.drop.y=mouse.y,\ + mouse.drag=NO + . mouse.event='d' + callf on.mouse + end + return 1 + end + . r0=mouse.x, r1=old.mouse.x + if r0<>r1 + .mouse.move: + . mouse.event='m' + callf on.mouse + if mouse.1 + if not mouse.drag + . mouse.drag=YES,\ + mouse.drag.x=mouse.x,\ + mouse.drag.y=mouse.y + end + else + . mouse.drop=NO + end + return 1 + else + . r0=mouse.y, r1=old.mouse.y + if r0<>r1 + go .mouse.move + end + end +endf 0 + + function select.box, box + . r0=mouse.x, r1=mouse.y + . r0-WINDOW.X, r1-WINDOW.Y + callf point.inside, box, r0, r1 +endf + +macro if.select box { !if select.box, box } +macro else.if.select box + { !else.if select.box, box } + +;;;;;;;;;;;;;;;;;;;;; RANDOM ;;;;;;;;;;;;;;;;;;;;; + +align integer @seed + +; generate unique random number: 0-n + +function random, n + . r0=@seed + if false + rdtsc + . @seed=r0 + end + . r0*343FDh, r0+269EC3h,\ + @seed=r0, r0>>16, r0&7FFFh,\ + r1=n, r1+1, r0/r1, r0=r2 +endf + +; random(from-to-2)+from + +function random.x, from, to + . r0=from, r0-to, r0-2 + random r0 + . r0+from +endf + +;;;;;;;;;;;;;;;;;;;;;; MAIN ;;;;;;;;;;;;;;;;;;;;;; + +; main entry. detect current input states, +; translate and redirect to on.event handlers. + +; drawing has slight flicker. no double +; buffer yet. kolibri only supports misaligned +; 24BPP images :( images should be stored in +; memory as 1-8BPP or 16/32BPP for fast access + +!main: + callf set.screen,\ + SCREEN.W, SCREEN.H, SCREEN.BPP + callf on.create + + get.event: + wait.event + . event.type=r0 + + update.mouse + + if timer.speed<>-1 + . timer.counter-- + if timer.counter<=0 + . timer.counter=timer.speed + callf on.timer + end + end + + if event.type=EVENT.REDRAW +; draw.begin + callf draw.window + callf on.draw +; draw.end +; retrace ; ? + + else.if event.type=EVENT.KEY + mint 2 + if r0<>1, r0>>8, r0&0FFh, key=r0 + . key.event='k' + callf on.key + . key.event='c' + callf on.key + if key=KEY.ESCAPE + callf exit + end + end + + else.if event.type=EVENT.BUTTON + callf exit + end +go get.event + +function exit + callf on.exit + mint -1 +endf \ No newline at end of file diff --git a/programs/games/codemaster/include/text.inc b/programs/games/codemaster/include/text.inc new file mode 100644 index 0000000000..dab4a2fd8e --- /dev/null +++ b/programs/games/codemaster/include/text.inc @@ -0,0 +1,1006 @@ +; $$$$$$$$$$$$$$$$$$$ ABAKIS $$$$$$$$$$$$$$$$$$$$$ +; *************** STAR^2 SOFTWARE **************** +; ???????????????????? TEXT ?????????????????????? + +; fast portable text operations + +; text.zero t ; initialize, *t=0 +; text.end t ; return end address (*t=0) +; text.n t ; get # characters +; text.copy a, b ; standard copy with 0 +; text.copy.n... ; copy with maximum size +; text.attach a, b ; attach b to a +; text.attach.c... ; attach c/haracter +; text.compare a, b ; compare lexical. <0> +; text.equal a, b ; equal? return 1/0 +; text.search a, b ; search for text. &/0 +; text.find a, c ; search for c. &/0 +; text.find.r a, c ; search for c in reverse +; text.count.c t, c ; count # of 'c's +; text.count.w t ; count # of words: 'a b c' +; text.count.n t ; count # of lines +; text.go t, n ; advance to line # +; text.upper t ; uppercase +; text.lower t ; lowercase +; text.reverse t ; reverse +; text.begins a, b ; begins with b? +; text.ends a, b ; ends with b? +; text.skip.0 t ; skip '0's. return & +; text.shift.l t, n ; shift characters left +; text.shift.la... ; shift left and assign +; text.expand t, n ; expand; shift right at 0 +; text.align t, n ; align; prefix with '0's + +; x2t n, t ; convert number to text +; u2t n, t ; unsigned decimal +; h2t n, t ; hexadecimal +; b2t n, t ; binary + +; t2x t ; convert text to number +; t2u t ; unsigned decimal +; t2h t ; hexadecimal +; t2b t ; binary + +; print t, f, ... - a fast print formatted +; text to buffer + +macro debug { callf _say, bug.t, bug.t } + +RET equ ,0Dh,0Ah, + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +; text.zero t - initialize + +macro text.zero t { . r0=t, *r0=0 } + +; text.end t - return end address: *p=0 + +function text.end, t + alias p=r0, c=r1 + . p=t, c=1 + while c, c=*p++, endw, p-- +endf + +; text.n t - get length, # characters + +function text.n, t + alias p=r0, s=r1, c=r2 + . p=t, s=p, c=1 + while c, c=*p++, endw, p-s, p-- +endf + +; text.copy a, b - standard copy with +; 0 after. return advanced address + +function text.copy, a, b + alias p=r0, s=r1, c=r2 + . p=a, s=b, c=1 + while c, c=*s++, *p++=c, endw, p-- +endf + +; text.copy.n a, b, n - copy with maximum +; size specified. return & + +function text.copy.n, a, b, n + alias p=r0, s=r1, c=r2 + . p=a, s=b + loop n, c=*s++, *p++=c + if c=0, break, end + endl, p-- +endf + +; text.attach a, b - attach b to a. return & + +function text.attach, a, b + text.end a + text.copy r0, b +endf + +; text.attach.c t, c - attach c/haracter. +; return & + +function text.attach.c, t, c + alias p=r0, x=r1 + text.end t + . x=c, *p++=x, *p=0 +endf + +; text.compare a, b - lexical comparison. +; return <0> + +function text.compare, a, b + alias p=r0, s=r1, c=r2, d=r3 + . p=a, s=b, c=d + while c=d, c=*p++, d=*s++ + if c=0, break, end + if d=0, break, end + endw, p=c, p-d +endf + +; text.equal a, b - equal? return 1/0 + +function text.equal, a, b + text.compare a, b + if false, return 1, end +endf 0 + +; text.find t, c - search for character: +; if t contains c. return &/0 + +function text.find, t, x + alias p=r0, c=r1, k=r2 + . p=t, k=x + loop, c=*p + if c=0, return 0, end + if c=k, return p, end, p++ + endl +endf + +; text.count.c t, c - count # of c/haracters + +function text.count.c, t, x + locals n + alias p=r0, c=r1, k=r2 + . p=t, k=x, n=0, c=1 + while c, c=*p++ + if c=k, n++, end + endw +endf n + +; text.count.w t - count # words 'a b c' + +function text.count.w, t + try text.count.c t, ' ' + . r0++ +endf + +; text.count.n t - count # lines + +function text.count.n, t + try text.count.c t, 0Dh + . r0++ +endf + +; text.go t, n - advance to line # + +function text.go, t, n + loop n + try t=text.find t, 0Dh + . t+2 + endl +endf t + +; text.upper t - convert to uppercase + +function text.upper, t + alias p=r0, c=r1 + . p=t + loop, c=*p + if c=0, return, end + if c>=97 + if c<=122, c-32, *p=c, end + end, p++ + endl +endf + +; text.lower t - convert to lowercase + +function text.lower, t + alias p=r0, c=r1 + . p=t + loop, c=*p + if c=0, return, end + if c>=65 + if c<=90, c+32, *p=c, end + end, p++ + endl +endf + +; text.reverse t - reverse text + +function text.reverse, t + locals p + alias s=r0, e=r1, c=r2 + get p=text.end t + . e=&(s-1), s=t + while s0, return 0, end +endf + +; text.ends a, b - a ends with b? + +function text.ends, a, b + locals p + get p=text.end a + text.n b + . p-r0 + text.equal p, b +endf + +; text.search t, c - search for text: +; if a contains b. return &/0 + +function text.search, a, b + locals n, p + get n=text.n a + . p=a + loop n + text.begins p, b + if true, return p, end + . p++ + endl +endf 0 + +; text.skip.0 a - skip 0s, return address or 0 + +function text.skip.0, a + alias p=r0, c=r1 + . p=a, c='0' + while c='0', c=*p++, endw, p-- + if c=0, return 0, end +endf + +; shift all characters left + +; before: 'abc123' +; after <<3: '123' + +function text.shift.l, t, n + alias p=r0, q=r1 + . p=t, q=p, q+n + text.copy p, q +endf + +; shift left and assign s to BITs +; copied out ('abc' in example above) + +function text.shift.la, t, s, n + alias p=r0, q=r1 + . p=t, q=p, q+n + text.copy.n s, t, n + text.shift.l t, n +endf + +; expand; shift all characters right. +; example: 'abc123' becomes 'XXXabc123' +; after expand 3 where X is unknown + +function text.expand, t, n + locals x + alias p=r0, q=r1, c=r2 + get x=text.n t + . p+t, p--, q=p, p+n, *p=0 + loop x, *p--=*q--, endl +endf + +; prefix text with '0's or ensure maximum n. +; example: before: t='7FAB' +; text.align t, 8 ; after: t='00007FAB' + +function text.align, t, n + locals tn + alias n1=r0, n2=r1,\ + c=r1, p=r2 + get tn=text.n t + . n2=n + if n1=n2, return, end ; same size + if n1>n2, p=t, *(p+n1)=0 ; exceeds maximum + return ; end at t+n + end, n-n1 ; else, n2>n1 + text.expand t, n ; expand t + . p=t, c='0' ; write '0's + loop n, *p++=c, endl +endf + +; search text array ta for t using text.equal. +; return index or -1 (<0) if not found. ta is +; an array of text addresses (text[]) + +function text.array.equal, ta, t, n + locals i + alias p=r0, q=r1, x=r2 + . i=0 + loop n, x=i, q=ta, (u32) p=*(q+x*4) + text.equal p, t + if true, return i, end + . i++ + endl +endf -1 + +;;;;;;;;;;;;;;;;;; CONVERSIONS ;;;;;;;;;;;;;;;;;;; + +; u2t n, t ; unsigned decimal +; h2t n, t ; hexadecimal +; b2t n, t ; binary + +; convert unsigned 32BIT integer to text + +function u2t, n, t + alias i=r0, x=r1, y=r2, c=r3, p=r7 + push c p + . i=n, p=t + if i=0, *p++='0', *p=0 + . r0=p + go .r + end + . x=1999999Ah + while i, c=i, mul x, i=y, y=&(y+y*4) + . y+y, c-y, c+'0', *p++=c + endw, *p=0 + text.reverse t + .r: + pop p c +endf + +; convert 32BIT hexadecimal number to text + +function h2t, n, t + alias p=r0, x=r1 + . p=t + if n=0, *p++='0', *p=0 + return + end + while n, x=n, x&15 + . x=*(@HEX+x), *p++=x, n>>>4 + endw, *p=0 + text.reverse t +endf + +align @HEX: db '0123456789ABCDEF' + +; convert 32BIT binary number to text + +function b2t, n, t + alias p=r0, x=r1 + . p=t + if n=0, *p++='0', *p=0 + return + end + while n, x=n, x&1, x+'0' + . *p++=x, n>>>1 + endw, *p=0 + text.reverse t +endf + +; t2u t ; unsigned decimal +; t2h t ; hexadecimal +; t2b t ; binary + +; convert text to unsigned 32BIT integer + +function t2u, t + alias p=r0, c=r1, n=r2, x=r3 + try text.skip.0 t + . n=0 + loop, c=*p++ + if c=0, return n, end + . x=n, x<<2, n+x, n+n, n-'0', n+c + endl +endf + +; convert text to 32BIT hexadecimal + +function t2h, t + alias p=r0, c=r1, n=r2 + try text.skip.0 t + . n=0 + loop, c=*p++ + if c=0, return n, end + if c<=39h, c-30h + else.if c>=61h, c-57h + else, c-37h, end, n<<4, n+c + endl +endf + +; convert text to 32BIT binary + +function t2b, t + alias p=r0, c=r1, n=r2 + try text.skip.0 t + . n=0 + loop, c=*p++ + if c=0, return n, end + . n<<1, n-'0', n+c + endl +endf + +; convert number to text with alignment. +; example: n2t.a 1234h, t, 8, h +; after: t='00001234' + +macro n2t.a n, t, a, b { + b#2t n, t + text.align t, a +} + +macro u2t.a n, t, a { n2t.a n, t, a, u } +macro h2t.a n, t, a { n2t.a n, t, a, h } +macro b2t.a n, t, a { n2t.a n, t, a, b } + +;;;;;;;;;;;;;;;;;;;;; PRINT ;;;;;;;;;;;;;;;;;;;;;; + +; print t, f, ... - a fast print formatted +; text to buffer + +; %t %s - 'text'; "string" +; %c - character +; %n %u - 32BIT decimal unsigned +; %b - 32BIT binary +; %h - 32BIT hexadecimal +; %r - return. insert 0Dh, 0Ah +; %0 - 0/NULL +; %% - % + +macro print t, f, [p] { + common callv !print, t, f, p +} + +; note: text.copy/reverse/etc and x2t +; must return end (*p=0) address for this + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +align integer BASE='n' + +; !print(n, $t, $f, ...) + +!print: + alias \ ; aliases... + s=r6, p=r7,\ ; source, destiny + c=r0, i=r1,\ + va.s=r2,\ ; &va[...] start + va.n=[esp+4],\ ; # va + va=[r2+r1*4],\ ; current va[i] + n=[.a], z=[.z] ; temporary + + . (u32) c=*(esp+8) ; text buffer + . (u32) i=*(esp+12) ; format + . va.s=&(esp+16) ; &va[...] start + + push s p + . p=c, s=i, i=0 ; index=0 + + .get: . c=*s++ ; get c/haracter + if c=0, go .e, end ; end? *s=0 + if c<>'%' ; not % + .1: . *p++=c ; copy c + go .get ; next + end + . c=*s++ ; %x + if c='%', go .1 ; 2 %% = % + end + + if c='0', *p++=0 ; '0' = 0/NULL + go .get + end + + if c='r' ; 'r' = return + . *p++=\ + 0A0Dh, go .get + end + + if c='c' ; %c + . c=va, i++ ; get va[i++] + . *p++=c + go .get + end + + if c='t' + .t: ; %t %s - text + . z=va, i++ ; get va[i++] + pusha + get z=\ + text.copy p, z ; copy, save & + popa + . p=z ; advance text buffer + go .get + end + if c='s', go .t + end + + if c='n', go .n, end + if c='u', go .n, end + if c='h', go .n, end + if c='b', go .n, end + + go .x ; unrecognized + + .n: + . n=va, i++ ; get va[i] + pusha ; copy/convert + if c='n' ; number to text + u2t n, p ; in selected base + else.if c='u' + u2t n, p + else.if c='h' + h2t n, p + else.if c='b' + b2t n, p + end + . z=r0 ; save end address + popa + . p=z ; advance text buffer + go .get + + .x: . *p++='?' ; else, unrecognized, + go .get ; replace with '?' + + .0: . r0=0, go .q ; error + .e: . r0=p, *r0=0 ; success. terminate + .q: ; return end + pop p s + ret ; callv adjusts esp after + +endal ; end alias + +.a dd 0 +.z dd 0 + +;;;;;;;;;;;;;;; CHARACTER TABLES ;;;;;;;;;;;;;;;;; + +; ILT - insensitive lookup table. A-Z/a-z are +; the same. this increases processing speed by +; many times. example: if (tt[a]=tt[b]) instead +; of: if ((a>='a'&a<='z')&(b>='a'&b<='z')) | +; ((a>='A'&a<='Z')&(b>='Z'&b<='Z')) + +; TLT - type lookup table. each byte contains +; C.X BITs to determine its type fast in one +; comparison. example: if tt[c]&SYMBOL + +align 8 + +; byte XLT[128]= + +ILT db \ + 00h,01h,02h,03h,04h,05h,06h,07h,08h,09h,0Ah,0Bh,0Ch,0Dh,0Eh,0Fh,\ + 10h,11h,12h,13h,14h,15h,16h,17h,18h,19h,1Ah,1Bh,1Ch,1Dh,1Eh,1Fh,\ + 20h,21h,22h,23h,24h,25h,26h,27h,28h,29h,2Ah,2Bh,2Ch,2Dh,2Eh,2Fh,\ + 30h,31h,32h,33h,34h,35h,36h,37h,38h,39h,3Ah,3Bh,3Ch,3Dh,3Eh,3Fh,\ + 40h,41h,42h,43h,44h,45h,46h,47h,48h,49h,4Ah,4Bh,4Ch,4Dh,4Eh,4Fh,\ + 50h,51h,52h,53h,54h,55h,56h,57h,58h,59h,5Ah,5Bh,5Ch,5Dh,5Eh,5Fh,\ + 60h,41h,42h,43h,44h,45h,46h,47h,48h,49h,4Ah,4Bh,4Ch,4Dh,4Eh,4Fh,\ + 50h,51h,52h,53h,54h,55h,56h,57h,58h,59h,5Ah,7Bh,7Ch,7Dh,7Eh,7Fh + +TLT db \ + 00h,80h,80h,80h,80h,80h,80h,80h,80h,80h,40h,80h,80h,40h,80h,80h,\ + 80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,\ + 20h,10h,04h,04h,10h,04h,04h,04h,04h,04h,04h,04h,04h,04h,10h,04h,\ + 01h,01h,01h,01h,01h,01h,01h,01h,01h,01h,04h,04h,04h,04h,04h,10h,\ + 10h,0Ah,0Ah,0Ah,0Ah,0Ah,0Ah,02h,0Ah,02h,02h,0Ah,02h,0Ah,02h,02h,\ + 02h,02h,02h,02h,02h,02h,02h,02h,02h,02h,02h,04h,04h,04h,04h,10h,\ + 04h,0Ah,0Ah,0Ah,0Ah,0Ah,0Ah,02h,0Ah,02h,02h,0Ah,02h,0Ah,02h,02h,\ + 02h,02h,02h,02h,02h,02h,02h,02h,02h,02h,02h,04h,04h,04h,04h,80h + +; 76543210b +C.NULL = 00000000b ; 0 +C.NUMBER = 00000001b ; 0-9 +C.ALPHA = 00000010b ; A-Z, a-z +C.SYMBOL = 00000100b ; all symbols except _.?!@$ +C.NUMERIC = 00001000b ; A-F/a-f, h,b,k,m/H,B,K,M +C.SYMBOLIC = 00010000b ; _.?!@$ +C.SPACE = 00100000b ; ' ', '/t' +C.RETURN = 01000000b ; 0Dh, 0Ah +C.IGNORE = 10000000b ; extended: 1.XXXXXXXb +C.KEYWORD = 11111111b + +C.DIGIT = C.NUMBER or C.NUMERIC +C.NAME = C.ALPHA or C.NUMBER or C.SYMBOLIC +C.SYMBOLS = C.SYMBOL or C.SYMBOLIC +C.ALPHAN = C.ALPHA or C.NUMBER +C.VISIBLE = C.ALPHAN or C.SYMBOLS +C.WHITE = C.SPACE or C.RETURN +C.BLANK = C.WHITE or C.IGNORE +C.END = C.SYMBOL or C.WHITE +C.0 = 0 + +function is.c, c, type + . r0=c, r0=*(TLT+r0), r0&type +endf + +macro if.is c, t { + is.c c, t + if true +} + +;;;;;;;;;;;;;;;;;;; PARSE TEXT ;;;;;;;;;;;;;;;;;;; + +; skip while type and not 0 + +; get p=text.skip.while p, C.WHITE + +function text.skip.while, t, type + alias p=r0, q=r1, c=r2 + . p=t, c=1 + while c, c=*p++ + . c=*(TLT+c), c&type + endw, p-- +endf + +; skip until type and while not 0. +; kind of tricky + +; get p=text.skip.until p, C.RETURN + +function text.skip.until, t, type + alias p=r0, q=r1, c=r2 + . p=t, c=0 + while c=0, c=*p++ + if c=0, return 0, end + . c=*(TLT+c), c&type + endw, p-- +endf + +; copy while type and not 0 + +; get s=text.copy.while t, s, C.NAME + +function text.copy.while, t, s, type + alias a=r7, b=r6, c=r1, x=r2 + . a=t, b=s, c=*b + if c=0, return 0, end + while c, c=*b++, *a++=c + . x=*(TLT+c), x&type + if x=0, break, end + endw, a--, *a=0, b-- +endf b + +; copy until type and while not 0 + +; get s=text.copy.until t, s, C.END + +function text.copy.until, t, s, type + alias a=r7, b=r6, c=r1, x=r2 + . a=t, b=s, c=*b + if c=0, return 0, end + while c, c=*b++, *a++=c + . x=*(TLT+c), x&type + if x, break, end + endw, a--, *a=0, b-- +endf b + +; copy until 'c'/x. if 0 or return is +; encountered before, return 0 + +function text.copy.until.c, t, s, x + alias a=r7, b=r6, c=r1 + . a=t, b=s, c=*b + if c=0, return 0, end + while c, c=*b++, *a++=c + if c=x, break, end + if c=0, return 0, end + if c=0Dh, return 0, end + endw, a--, *a=0, b-- +endf b + +; skip whitespace and returns +; (if parse.skip.r?) or only spaces +; and tabs. return advanced & + +align boolean parse.skip.r?=YES + +function text.skip.ws, t + if parse.skip.r? + text.skip.while t, C.WHITE + else + text.skip.while t, C.SPACE + end +endf + +; skip all whitespace, returns +; (if parse.skip.r?) and comments. +; return advanced & + +function text.skip.x, t + locals q + alias p=r0, c=r1 + . p=t, q=p + .get: + . p=q, c=*p + if c=0 + return 0 + end + if.is c, C.WHITE + try q=text.skip.ws q + end + . p=q, c=*p + if c=';' + try q=text.skip.until \ + q, C.RETURN + . p+2 + go .get + end +endf q + +function text.get, a, b + locals q + alias p=r0, c=r1 + . q=b + try q=text.skip.x q + . c=*p + if c=0, return 0, end + if.is c, C.SYMBOL + . p=a, *p++=c, *p=0, q++ + return q + end + text.copy.until a, q, C.END +endf + +;;;;;;;;;;;;;;;; SOURCE, DESTINY ;;;;;;;;;;;;;;;;; + +align + +void source.p, destiny.p, token.p +integer source.n, destiny.n, token.n + +macro set.source p { . source.p=p } +macro set.destiny p { . destiny.p=p } +macro set.token p { . token.p=p } + +function skip.while, type + get source.p=text.skip.while \ + source.p, type +endf + +function skip.until, type + get source.p=text.skip.until \ + source.p, type +endf + +function copy.while, type + get source.p=text.copy.while \ + token.p, source.p, type +endf + +function copy.until, type + get source.p=text.copy.until \ + token.p, source.p, type +endf + +function copy.until.c, c + get source.p=text.copy.until.c \ + token.p, source.p, c +endf + +macro skip.space { skip.while C.SPACE } +macro skip.white { skip.while C.WHITE } +macro skip.line { skip.until C.RETURN } + +; skip all whitespace, returns +; (if parse.skip.r?) and comments. +; return advanced & + +function skip.x + alias p=r0, c=r1 + .get: + . p=source.p, c=*p + if c=0, return 0, end + if.is c, C.WHITE + try skip.while C.WHITE + end + . p=source.p, c=*p + if c=';' + try skip.until C.RETURN + . source.p+2 + go .get + end + . p=source.p +endf p + +; get token + +function get.token + alias p=r0, c=r1 + try skip.x + . c=*p + if c=0, return 0, end + if.is c, C.SYMBOL + . p=token.p, *p++=c, *p++=0 + . source.p++, p=source.p + if c='''', c=*p + if c='''', source.p++ + return source.p + end + try copy.until.c '''' + . source.p++ + end + . p=source.p + return + end + copy.until C.END +endf + +; MOVE TO PARSE.INC... + +;;;;;;;;;;;;;;;;;;; NAME TABLE ;;;;;;;;;;;;;;;;;;; + +; name table: + +; 'ann',0, 'kim',0, 'sue',0 + +align 4 + +void name.table, name.table.p,\ + name.table.n, name.table.size, name.table.end + +; allocate name.table + +function create.name.table, size + try name.table=call !allocate, size + . name.table.p=r0, r0+size + . name.table.end=r0, name.table.n=0 + . name.table.size=0 +endf 1 + +; get name address by index + +function get.name, i + locals p + . p=name.table + loop i + get p=text.end p + . p++ + endl +endf p + +; search for name. return index or -1 + +function search.name, t + locals i, p + . p=name.table, i=name.table.n + loop i + get.name i + text.equal p, r0 + if true, return i, end + endl +endf -1 + +; attach 'text'. return address + +function create.name, t + locals p, n + . p=name.table.p + text.n t + . r0++, n=r0, r0+p + if r0>=name.table.end + return 0 + end + text.copy name.table.p, t + . r0=p, r0+n, name.table.p=r0 + . name.table.n++, r0=n + . name.table.size+r0 +endf p + +; remove name at index + +function remove.name, i + locals p, q, n, size + get p=get.name i + get n=text.n p + . i++ + get q=get.name i + . r0=name.table.p, r0+name.table.size + . r0-p, size=r0, r0=n + . name.table.size-r0, name.table.p-r0 + memory.copy p, q, size + . name.table.n-- +endf + +; get name at index + +function copy.name, i, t + get.name i + text.copy t, r0 +endf + +; name structure: 16 bytes + +virtual at 0 + ?define: + .type dd 0 ; type: TTTT... + .value dd 0 ; name index + .name dd 0 ; value or index + .i dd 0 ; anything, align 16 + .$=$ +END virtual + +powers DEFINE.*, ALIVE, USED,\ + D, ABLE, NUMERIC + +; .type = + +; TTTT.SSSS XXXXXXXX XXXXXXXX XXX.NR.DUA +; 23-16 15-8 7-0 + +; T: type: number, define, constant, label, +; macro, register, instruction, variable +; S: data size +; P: parameter 1 +; Q: parameter 2 +; X: anything +; N: 1=numeric, 0=symbolic +; R: 1=redefinable, 0=not +; D: 1=defined, 0=not +; U: 1=used, 0=not +; A: 1=alive, 0=dead + +; name structures. last structure is +; defines.p+((defines.n-1)*48) + +align 4 + +void defines.p ; name structures +void defines.end.p ; end allocation +integer defines.n + +;;;;;;;;;;;;;;;;;;;;; ERRORS ;;;;;;;;;;;;;;;;;;;;; + +; MOVE TO ASSEMBLER.INC + +text errors.ta[]=\ + E.NONE ='None',\ + E.SYNTAX ='Syntax',\ + E.LOAD ='Error loading',\ + E.FILE ='File I/O error',\ + E.UNEXPECT ='Unexpected',\ + E.CPU ='Unsupported by CPU',\ + E.ADDRESS ='Address not aligned',\ + E.OPERANDS ='Invalid operand/s',\ + E.AMODE ='Invalid addressing mode',\ + E.SHIFT ='Invalid shift #',\ + E.NUMBER ='Invalid number',\ + E.NUMBER2 ='Number can''t be encoded',\ + E.VALUE ='Value exceeds size',\ + E.ALIGN ='Number must be aligned',\ + E.POWER ='# must be power of 2',\ + E.REGISTER ='Register expected',\ + E.EXPECTN ='Number expected',\ + E.EXPECTA ='Name expected',\ + E.INAME ='Invalid name',\ + E.NAME ='Name too long',\ + E.RESERVE ='Reserved name',\ + E.UNDEFINE ='Undefined',\ + E.REDEFINE ='Redefinition',\ + E.EXPECTT ='Text expected',\ + E.ENDT ='Text has no end ''',\ + E.COMMA =', expected',\ + E.END ='end expected',\ + E.MISMATCH ='Mismatched parenthesis' + +;;;;;;;;;;;;;;;;;;; KEYWORDS ;;;;;;;;;;;;;;;;;;;;; + +; MOVE TO ASSEMBLER.INC + +text keywords.ta[]=\ + K.ALIGN='align', K.BYTE='byte',\ + K.D1='d1', K.D2='d2', K.D4='d4', K.D8='d8',\ + K.DEFINE='define', K.DOUBLE='double',\ + K.EQUATE='equate', K.FLOAT='float',\ + K.FORMAT='format', K.INCLUDE='include',\ + K.INJECT='inject', K.INTEGER='integer',\ + K.MAIN='main', K.ORG='org',\ + K.RESTORE='restore', K.TEXT='text',\ + K.USE='use', K.VOID='void' + +align 4 + +void keywords.ta.p=keywords.ta +integer keywords.n=keywords.ta.$ + +function is.keyword, t + if keywords.n=0, return -1, end + text.array.equal \ + keywords.ta.p, t, keywords.n +endf \ No newline at end of file diff --git a/programs/games/codemaster/include/words.txt b/programs/games/codemaster/include/words.txt new file mode 100644 index 0000000000..8b201b0b27 --- /dev/null +++ b/programs/games/codemaster/include/words.txt @@ -0,0 +1,79 @@ +; 100+ words/phrases. maximum 3 words, +; 1-12 letters each. example: +; 'PREPROCESSOR' = 12 + +text words.ta[]=\ + 'ABSTRACT SYNTAX TREE',\ + 'ACCUMULATOR',\ + 'ADDRESS SIZE OVERRIDE',\ + 'ADDRESSING MODE',\ + 'ARRAY BOUNDS EXCEPTION',\ + 'ARITHMETIC LOGICAL UNIT',\ + 'ARTIFICIAL INTELLIGENCE', 'ASSEMBLER',\ + 'BARREL SHIFTER', 'BINARY TREE',\ + 'BINARY ARITHMETIC', 'BITS AND BYTES',\ + 'BITWISE OPERATION', 'BREAKPOINT',\ + 'CALLING CONVENTION',\ + 'CENTRAL PROCESSING UNIT', 'CPU CLOCK CYCLE',\ + 'COMPRESSION SCHEME', 'COMPUTER',\ + 'CONDITIONAL ASSEMBLY',\ + 'COSINE OF ANGLE', 'DATA ALIGNMENT',\ + 'DIRECT MEMORY ACCESS', 'DISASSEMBLER',\ + 'DIVIDE BY ZERO', 'DRAW TRANSPARENT BITMAP',\ + 'DYNAMIC ARRAY', 'DYNAMIC BINARY TRANSLATION',\ + 'EFFECIENT ALGORITHM', 'ENCRYPTION',\ + 'EXPRESSION PARSER', 'FILE INPUT OUTPUT',\ + 'FIXED POINT DIVISION',\ + 'FLAT ASSEMBLER', 'FLOATING POINT UNIT',\ + 'FLOPPY DISK', 'FOUR BIT MULTIPLIER',\ + 'FUNCTION PROTOTYPE',\ + 'FUNCTION EPILOGUE SEQUENCE',\ + 'GIGABYTE', 'GLOBAL VARIABLE',\ + 'EXTERNAL HARD DRIVE', 'HARDWARE INTERRUPT',\ + 'HELLO WORLD', 'HEXADECIMAL EDITOR',\ + 'HIGH LEVEL ASSEMBLER', 'HYPOTENUSE',\ + 'IF EXPRESSION', 'INFINITE LOOP',\ + 'INSTRUCTION POINTER',\ + 'INTEGRATED CIRCUIT',\ + 'KEYBOARD AND MOUSE', 'KOLIBRI OS',\ + 'LINKED LIST', 'LOCAL VARIABLES',\ + 'LOCAL DESCRIPTOR TABLE', 'LOGARITHM',\ + 'LOGIC GATE', 'LOOKUP TABLE',\ + 'MACHINE LANGUAGE', 'MACRO INSTRUCTION',\ + 'MEMORY COPY', 'MOTHERBOARD', 'MENUET OS',\ + 'MULTIPLE INHERITANCE',\ + 'NATURAL LOGARITHM', 'NO OPERATION',\ + 'NULL POINTER', 'NUMERIC CONSTANT',\ + 'OBJECT ORIENTED PROGRAMMING',\ + 'OPCODE', 'OPERATING SYSTEM',\ + 'OPTIMIZATION', 'STACK OVERFLOW',\ + 'PARAMETERS AND LOCALS', 'PIPELINE',\ + 'POINTER OPERATION', 'PORTABLE EXECUTABLE',\ + 'POSITION INDEPENDANT CODE',\ + 'POWERS OF TWO', 'PRECEDENCE',\ + 'PREPROCESSOR DIRECTIVE',\ + 'PRINT FORMATTED TEXT', 'PROCEDURE',\ + 'PROTECTED MODE', 'RANDOM ACCESS MEMORY',\ + 'READ ONLY MEMORY', 'RECURSIVE FUNCTION',\ + 'REGISTER', 'RELATIONAL OPERATOR',\ + 'RELATIVE OFFSET', 'RETURN VALUE',\ + 'REVERSE ENGINEERING',\ + 'REVERSE POLISH NOTATION',\ + 'SCALED INDEX BYTE', 'SEGMENT PREFIX',\ + 'SIGNED INTEGER OVERFLOW', 'SILICON CHIP',\ + 'SOFTWARE INTERRUPT', 'SOURCE AND DESTINY',\ + 'SPRITE ANIMATION', 'STRING LENGTH',\ + 'STRUCTURE', 'SYMBOLIC CONSTANT',\ + 'TOMASZ GRYSZTAR',\ ; :) + 'TRANSISTOR', 'TRUTH TABLE', 'TWO BIT ADDER',\ + 'UNSIGNED INTEGER', 'VARIABLE DECLARATION',\ + 'VIDEO CARD', 'VIDEO GRAPHICS ARRAY',\ + 'VIRTUAL MACHINE', 'VIRTUAL MEMORY' + +N.WORDS=words.ta.$-1 + +; pointer array + +align + +words.pa dd N.WORDS dup(0) \ No newline at end of file diff --git a/programs/games/codemaster/kolibri_puzzle.asm b/programs/games/codemaster/kolibri_puzzle.asm new file mode 100644 index 0000000000..26679845c0 --- /dev/null +++ b/programs/games/codemaster/kolibri_puzzle.asm @@ -0,0 +1,231 @@ +; KOLIBRI PUZZLE CHALLENGE + +TILE.W=64 +TILE.H=64 +MAP.X=TILE.W +MAP.Y=TILE.H +MAP.W=8 +MAP.H=8 +PUZZLE.W=MAP.W*TILE.W +PUZZLE.H=MAP.H*TILE.H + +WINDOW.W=PUZZLE.W+(TILE.W*2) +WINDOW.H=PUZZLE.H+(TILE.H*2) + +include 'a.inc' + +text title(64)='Kolibri Puzzle Challenge' + +align + +integer scene +numeric SCENE.*, TITLE, PLAY, SOLVED + +integer solved, select.x, select.y + +puzzle: db (MAP.W*MAP.H*4) dup(0) +numeric NORMAL, ROTATE.R, INVERT.XY, ROTATE.L + +IMAGE piece.i +piece.pixels: db (TILE.W*TILE.H*4) dup(0) + +BOX my.box, puzzle.box +integer grid.color=WHITE + +IMAGE kolibri.i='kolibri', logo.i='logo2',\ + wood1.i='wood1', wood2.i='wood2',\ + close.i='x', solved.i='solved' + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +get.random equ random.x ROTATE.R, ROTATE.L + +function erase.puzzle + memory.zero piece.pixels, (TILE.W*TILE.H*4) +endf + +function randomize.puzzle + locals q, n + alias p=r0, x=r1 + . q=puzzle, n=(MAP.W*MAP.H) + loop n + . x=ROTATE.L, p=q, (u32) *p=x, q+4 + endl +endf + +function reset.game + randomize.puzzle +endf + +function on.create + erase.puzzle + . scene=SCENE.TITLE + set.box puzzle.box,\ + MAP.X, MAP.Y, PUZZLE.W, PUZZLE.H +endf + +function is.solved + locals n + alias p=r0, x=r1 + . p=puzzle, n=(MAP.W*MAP.H) + loop n, (u32) x=*p++ + if x<>NORMAL, return 0, end + endl +endf 1 + +function get.piece, x, y + . r0=y, r0*MAP.W, r0+x, r0*4, r0+puzzle +endf + +function get.piece.rotate, x, y + get.piece x, y + . (u32) r0=*r0 +endf + +function set.piece.rotate, x, y, r + if r>ROTATE.L, r=0, end + get.piece x, y + . r1=r, (u32) *r0=r1 + is.solved + if true + . scene=SCENE.SOLVED + end +endf + +function copy.piece, x, y + locals w, h, pw + alias p=r0, s=r1, n=r2 + . p=piece.pixels, piece.i.p=p + . piece.i.w=TILE.W, piece.i.h=TILE.H + . n=PUZZLE.W, n*4, pw=n + . n=y, n*pw, n*TILE.W + . s=x, s*TILE.W, s*4, n+s + . s=kolibri.i.p, s+n + . h=TILE.H + loop h, w=TILE.W + loop w, (u32) *p++=*s++ + endl + . n=TILE.W, n*4, s-n, s+pw + endl +endf + +function draw.piece, px, py, x, y + locals z + get z=get.piece.rotate px, py + copy.piece px, py + if z=NORMAL + draw.image piece.i, x, y + else.if z=ROTATE.R + draw.image.rr piece.i, x, y + else.if z=INVERT.XY + . r0=y, r0+TILE.H + draw.image.ixy piece.i, x, r0 + else.if z=ROTATE.L + draw.image.rl piece.i, x, y + end +endf + +function draw.puzzle + locals x, y + . y=0 + while y<8, x=0 + while x<8 + . r0=x, r0*TILE.W, r0+MAP.X + . r1=y, r1*TILE.H, r1+MAP.Y + draw.piece x, y, r0, r1 + . x++ + endw + . y++ + endw +endf + +function draw.grid + locals x, y + . y=0 + while y<8, x=0 + while x<8 + . r0=x, r0*TILE.W, r0+MAP.X + . r1=y, r1*TILE.H, r1+MAP.Y + draw.outline r0, r1,\ + TILE.W, TILE.H, grid.color + . x++ + endw + . y++ + endw +endf + +function draw.wood.frame + draw.image wood1.i, 0, 0 + draw.image wood1.i, 0, WINDOW.H-TILE.H + draw.image wood2.i, 0, TILE.H + draw.image wood2.i, WINDOW.W-TILE.W, TILE.H + draw.image close.i, WINDOW.W-40, 8 +endf + +function on.draw + draw.wood.frame + draw.puzzle + if scene=SCENE.TITLE + draw.box.o puzzle.box, grid.color + end + if scene=SCENE.PLAY + draw.grid + end + if scene=SCENE.SOLVED + draw.image.v solved.i, 132, 13, WHITE + else + draw.image.v logo.i, 180, 13, WHITE + end +endf + +function on.key + ; ... +endf + +function get.select.xy + . r0=mouse.x, r0-MAP.X, r0-WINDOW.X + . r1=TILE.W, r0/r1, select.x=r0 + . r0=mouse.y, r0-MAP.Y, r0-WINDOW.Y + . r1=TILE.H, r0/r1, select.y=r0 +endf + +function on.mouse + locals r + if mouse.event='c' + . r0=&close.i.x + if.select r0 + exit + end + if scene=SCENE.TITLE + reset.game + . scene=SCENE.PLAY + go .draw + end + if scene=SCENE.PLAY + if.select puzzle.box + get.select.xy + get r=get.piece.rotate \ + select.x, select.y + . r++ + set.piece.rotate \ + select.x, select.y, r + go .draw + end + end + if scene=SCENE.SOLVED + reset.game + . scene=SCENE.TITLE + go .draw + end + .draw: + render + end +endf + +function on.timer + ; ... +endf + +function on.exit + ; ... +endf \ No newline at end of file diff --git a/programs/games/codemaster/media/0.bmp b/programs/games/codemaster/media/0.bmp new file mode 100644 index 0000000000..1c37681752 Binary files /dev/null and b/programs/games/codemaster/media/0.bmp differ diff --git a/programs/games/codemaster/media/1.bmp b/programs/games/codemaster/media/1.bmp new file mode 100644 index 0000000000..58b42be9dd Binary files /dev/null and b/programs/games/codemaster/media/1.bmp differ diff --git a/programs/games/codemaster/media/1000.bmp b/programs/games/codemaster/media/1000.bmp new file mode 100644 index 0000000000..b89773725e Binary files /dev/null and b/programs/games/codemaster/media/1000.bmp differ diff --git a/programs/games/codemaster/media/a/a.bmp b/programs/games/codemaster/media/a/a.bmp new file mode 100644 index 0000000000..fd4f58fe79 Binary files /dev/null and b/programs/games/codemaster/media/a/a.bmp differ diff --git a/programs/games/codemaster/media/a/b.bmp b/programs/games/codemaster/media/a/b.bmp new file mode 100644 index 0000000000..9db12bd880 Binary files /dev/null and b/programs/games/codemaster/media/a/b.bmp differ diff --git a/programs/games/codemaster/media/a/c.bmp b/programs/games/codemaster/media/a/c.bmp new file mode 100644 index 0000000000..4703508262 Binary files /dev/null and b/programs/games/codemaster/media/a/c.bmp differ diff --git a/programs/games/codemaster/media/a/d.bmp b/programs/games/codemaster/media/a/d.bmp new file mode 100644 index 0000000000..73e2cb0fa4 Binary files /dev/null and b/programs/games/codemaster/media/a/d.bmp differ diff --git a/programs/games/codemaster/media/a/e.bmp b/programs/games/codemaster/media/a/e.bmp new file mode 100644 index 0000000000..c7b5f91aa2 Binary files /dev/null and b/programs/games/codemaster/media/a/e.bmp differ diff --git a/programs/games/codemaster/media/a/f.bmp b/programs/games/codemaster/media/a/f.bmp new file mode 100644 index 0000000000..a96db4e6f4 Binary files /dev/null and b/programs/games/codemaster/media/a/f.bmp differ diff --git a/programs/games/codemaster/media/a/g.bmp b/programs/games/codemaster/media/a/g.bmp new file mode 100644 index 0000000000..5b3b4dfd41 Binary files /dev/null and b/programs/games/codemaster/media/a/g.bmp differ diff --git a/programs/games/codemaster/media/a/h.bmp b/programs/games/codemaster/media/a/h.bmp new file mode 100644 index 0000000000..d1497f545d Binary files /dev/null and b/programs/games/codemaster/media/a/h.bmp differ diff --git a/programs/games/codemaster/media/a/i.bmp b/programs/games/codemaster/media/a/i.bmp new file mode 100644 index 0000000000..c85d349e68 Binary files /dev/null and b/programs/games/codemaster/media/a/i.bmp differ diff --git a/programs/games/codemaster/media/a/j.bmp b/programs/games/codemaster/media/a/j.bmp new file mode 100644 index 0000000000..781acfbd68 Binary files /dev/null and b/programs/games/codemaster/media/a/j.bmp differ diff --git a/programs/games/codemaster/media/a/k.bmp b/programs/games/codemaster/media/a/k.bmp new file mode 100644 index 0000000000..142a6a63c1 Binary files /dev/null and b/programs/games/codemaster/media/a/k.bmp differ diff --git a/programs/games/codemaster/media/a/l.bmp b/programs/games/codemaster/media/a/l.bmp new file mode 100644 index 0000000000..d838654c4f Binary files /dev/null and b/programs/games/codemaster/media/a/l.bmp differ diff --git a/programs/games/codemaster/media/a/m.bmp b/programs/games/codemaster/media/a/m.bmp new file mode 100644 index 0000000000..58d105ab05 Binary files /dev/null and b/programs/games/codemaster/media/a/m.bmp differ diff --git a/programs/games/codemaster/media/a/n.bmp b/programs/games/codemaster/media/a/n.bmp new file mode 100644 index 0000000000..e6c1ce5d39 Binary files /dev/null and b/programs/games/codemaster/media/a/n.bmp differ diff --git a/programs/games/codemaster/media/a/o.bmp b/programs/games/codemaster/media/a/o.bmp new file mode 100644 index 0000000000..7591dc6785 Binary files /dev/null and b/programs/games/codemaster/media/a/o.bmp differ diff --git a/programs/games/codemaster/media/a/p.bmp b/programs/games/codemaster/media/a/p.bmp new file mode 100644 index 0000000000..9f0c40bfb5 Binary files /dev/null and b/programs/games/codemaster/media/a/p.bmp differ diff --git a/programs/games/codemaster/media/a/q.bmp b/programs/games/codemaster/media/a/q.bmp new file mode 100644 index 0000000000..ccbe11a85b Binary files /dev/null and b/programs/games/codemaster/media/a/q.bmp differ diff --git a/programs/games/codemaster/media/a/r.bmp b/programs/games/codemaster/media/a/r.bmp new file mode 100644 index 0000000000..410248af3c Binary files /dev/null and b/programs/games/codemaster/media/a/r.bmp differ diff --git a/programs/games/codemaster/media/a/s.bmp b/programs/games/codemaster/media/a/s.bmp new file mode 100644 index 0000000000..a49817cb65 Binary files /dev/null and b/programs/games/codemaster/media/a/s.bmp differ diff --git a/programs/games/codemaster/media/a/t.bmp b/programs/games/codemaster/media/a/t.bmp new file mode 100644 index 0000000000..de566cd624 Binary files /dev/null and b/programs/games/codemaster/media/a/t.bmp differ diff --git a/programs/games/codemaster/media/a/u.bmp b/programs/games/codemaster/media/a/u.bmp new file mode 100644 index 0000000000..2223aa1cc1 Binary files /dev/null and b/programs/games/codemaster/media/a/u.bmp differ diff --git a/programs/games/codemaster/media/a/v.bmp b/programs/games/codemaster/media/a/v.bmp new file mode 100644 index 0000000000..ae10ac1e8a Binary files /dev/null and b/programs/games/codemaster/media/a/v.bmp differ diff --git a/programs/games/codemaster/media/a/w.bmp b/programs/games/codemaster/media/a/w.bmp new file mode 100644 index 0000000000..32993b7c28 Binary files /dev/null and b/programs/games/codemaster/media/a/w.bmp differ diff --git a/programs/games/codemaster/media/a/x.bmp b/programs/games/codemaster/media/a/x.bmp new file mode 100644 index 0000000000..3345c97da6 Binary files /dev/null and b/programs/games/codemaster/media/a/x.bmp differ diff --git a/programs/games/codemaster/media/a/y.bmp b/programs/games/codemaster/media/a/y.bmp new file mode 100644 index 0000000000..1cfd86b3ed Binary files /dev/null and b/programs/games/codemaster/media/a/y.bmp differ diff --git a/programs/games/codemaster/media/a/z.bmp b/programs/games/codemaster/media/a/z.bmp new file mode 100644 index 0000000000..f65e561533 Binary files /dev/null and b/programs/games/codemaster/media/a/z.bmp differ diff --git a/programs/games/codemaster/media/arm1.bmp b/programs/games/codemaster/media/arm1.bmp new file mode 100644 index 0000000000..9a1005e403 Binary files /dev/null and b/programs/games/codemaster/media/arm1.bmp differ diff --git a/programs/games/codemaster/media/arm2.bmp b/programs/games/codemaster/media/arm2.bmp new file mode 100644 index 0000000000..78ee815960 Binary files /dev/null and b/programs/games/codemaster/media/arm2.bmp differ diff --git a/programs/games/codemaster/media/bits.bmp b/programs/games/codemaster/media/bits.bmp new file mode 100644 index 0000000000..dc2c2e124f Binary files /dev/null and b/programs/games/codemaster/media/bits.bmp differ diff --git a/programs/games/codemaster/media/board.bmp b/programs/games/codemaster/media/board.bmp new file mode 100644 index 0000000000..5ef5c79932 Binary files /dev/null and b/programs/games/codemaster/media/board.bmp differ diff --git a/programs/games/codemaster/media/body.bmp b/programs/games/codemaster/media/body.bmp new file mode 100644 index 0000000000..c02e803bb7 Binary files /dev/null and b/programs/games/codemaster/media/body.bmp differ diff --git a/programs/games/codemaster/media/font.bmp b/programs/games/codemaster/media/font.bmp new file mode 100644 index 0000000000..4a3247a90f Binary files /dev/null and b/programs/games/codemaster/media/font.bmp differ diff --git a/programs/games/codemaster/media/head.bmp b/programs/games/codemaster/media/head.bmp new file mode 100644 index 0000000000..4b3b34e0f2 Binary files /dev/null and b/programs/games/codemaster/media/head.bmp differ diff --git a/programs/games/codemaster/media/kolibri.bmp b/programs/games/codemaster/media/kolibri.bmp new file mode 100644 index 0000000000..3a40341cfe Binary files /dev/null and b/programs/games/codemaster/media/kolibri.bmp differ diff --git a/programs/games/codemaster/media/leg1.bmp b/programs/games/codemaster/media/leg1.bmp new file mode 100644 index 0000000000..ffa68dfdc3 Binary files /dev/null and b/programs/games/codemaster/media/leg1.bmp differ diff --git a/programs/games/codemaster/media/leg2.bmp b/programs/games/codemaster/media/leg2.bmp new file mode 100644 index 0000000000..b83c2d3807 Binary files /dev/null and b/programs/games/codemaster/media/leg2.bmp differ diff --git a/programs/games/codemaster/media/logo.bmp b/programs/games/codemaster/media/logo.bmp new file mode 100644 index 0000000000..66a2b534f9 Binary files /dev/null and b/programs/games/codemaster/media/logo.bmp differ diff --git a/programs/games/codemaster/media/logo2.bmp b/programs/games/codemaster/media/logo2.bmp new file mode 100644 index 0000000000..0e4b66d907 Binary files /dev/null and b/programs/games/codemaster/media/logo2.bmp differ diff --git a/programs/games/codemaster/media/money.bmp b/programs/games/codemaster/media/money.bmp new file mode 100644 index 0000000000..b341bd52c8 Binary files /dev/null and b/programs/games/codemaster/media/money.bmp differ diff --git a/programs/games/codemaster/media/smile.bmp b/programs/games/codemaster/media/smile.bmp new file mode 100644 index 0000000000..5f6773bc13 Binary files /dev/null and b/programs/games/codemaster/media/smile.bmp differ diff --git a/programs/games/codemaster/media/solved.bmp b/programs/games/codemaster/media/solved.bmp new file mode 100644 index 0000000000..f132d11fa9 Binary files /dev/null and b/programs/games/codemaster/media/solved.bmp differ diff --git a/programs/games/codemaster/media/stand1.bmp b/programs/games/codemaster/media/stand1.bmp new file mode 100644 index 0000000000..94716a999b Binary files /dev/null and b/programs/games/codemaster/media/stand1.bmp differ diff --git a/programs/games/codemaster/media/stand2.bmp b/programs/games/codemaster/media/stand2.bmp new file mode 100644 index 0000000000..2c71bd0f83 Binary files /dev/null and b/programs/games/codemaster/media/stand2.bmp differ diff --git a/programs/games/codemaster/media/wood1.bmp b/programs/games/codemaster/media/wood1.bmp new file mode 100644 index 0000000000..31e2686f38 Binary files /dev/null and b/programs/games/codemaster/media/wood1.bmp differ diff --git a/programs/games/codemaster/media/wood2.bmp b/programs/games/codemaster/media/wood2.bmp new file mode 100644 index 0000000000..b419ba9be1 Binary files /dev/null and b/programs/games/codemaster/media/wood2.bmp differ diff --git a/programs/games/codemaster/media/x.bmp b/programs/games/codemaster/media/x.bmp new file mode 100644 index 0000000000..e54f2f25bf Binary files /dev/null and b/programs/games/codemaster/media/x.bmp differ