require assets.fs require user.fs require screens.fs require list.fs require random.fs variable lives variable points variable player-pos variable update-counter variable tickcounter variable level variable levelspeed : create-ufo-type ( type health ) >r >r :noname r> r> POSTPONE literal POSTPONE literal POSTPONE ; ; : player-move-left 3 player-pos @ < if -1 player-pos +! then ; : player-move-right form swap drop ( width ) 4 - player-pos @ > if 1 player-pos +! then ; : between? ( min max x -- flag ) tuck >= ( min x flag ) -rot <= and ; : draw ( ufo -- ) dup ufo-x swap dup ufo-y swap ( x y ufo ) head execute swap drop ( x y type ) case 1 of draw-ufo endof 2 of draw-ufo2 endof endcase ; : draw-ufos ( -- ) ['] draw iterate-ufo ; : draw-shot ( shot-pos -- ) dup shot-x swap shot-y at-xy ." |" ; : draw-shots ( -- ) ['] draw-shot iterate-shot ; : update-s ( shot-addr -- ) dup shot-y ( addr y ) 1 - swap set-shot-y ; : update-shot ( shot-pos -- ) drop shot_list begin dup while dup update-s @ repeat drop ; : draw-block ( block -- ) dup block-x swap block-y ( x y ) draw-block2 ; : draw-blocks ( -- ) ['] draw-block iterate-blocks ; : ufo-intersect? ( ufo x y -- flag ) 2>r ufo-position ( bx by ) dup 2 + r> between? ( bx flag ) swap 3 - dup 7 + r> between? ( flag flag ) and ; : check-ufos-collision { x y -- flag } 0 >r ufo_list begin dup while dup ( entry ufo-pos ) x y ufo-intersect? if \ return true ( entry ) dup ufo-damage 1 + 2dup ( entry dmg entry dmg ) swap set-ufo-damage 5 >= if \ Abschuss bonus 50 points +! r@ remove-ufo then 10 points +! rdrop drop -1 EXIT then r> 1 + >r @ repeat drop rdrop \ return false 0 ; : block-intersect? ( block x y -- flag ) 2>r block-position ( bx by ) 2 - dup 4 + r> between? ( bx flag ) swap 2 - dup 6 + r> between? ( flag flag ) and ; : check-blocks-collision ( x y -- flag ) 2>r 0 >r block_list begin dup while dup ( block ) dup r> swap ( block counter block ) 2r@ block-intersect? ( block counter flag ) swap >r if dup block-health 1 - 2dup swap set-block-health ( block health ) 0 <= if 20 points +! r@ remove-block then 2drop rdrop 2rdrop -1 EXIT then drop r> 1 + >r @ repeat drop rdrop 2rdrop 0 ; variable tmpcounter : update-shots ( -- ) 0 tmpcounter ! shot_list begin dup while ( entry ) dup update-shot dup shot-x over shot-y ( entry x y ) swap over ( entry y x y ) 2dup check-blocks-collision -rot check-ufos-collision or ( entry y flag ) swap 0 < or if @ tmpcounter @ remove-shot -1 tmpcounter +! else @ then 1 tmpcounter +! repeat drop ; : update ( ufo-addr -- ) dup ufo-y over ufo-x ( addr y x ) dup form nip 5 - > if drop ( addr y ) 4 + over set-ufo-y 0 swap set-ufo-x else ( addr y x ) nip 1 + swap set-ufo-x then ; : update-ufos ( -- ) ufo_list begin dup while dup update ( entry ) @ repeat drop ; : clear-map ( -- ) clear-ufos clear-blocks clear-shots ; : start-new-wave ( -- ) \ spawn new 100 5 +DO 5 i 2 10 create-ufo-type add-ufo level @ 2 > if 10 i 1 5 create-ufo-type add-ufo then level @ 3 > if 17 i level @ 7 > if 10 else 5 then add-block then 20 +LOOP level @ 5 > if \ random blocks level @ 0 ?do form 5 - random swap mod 2 + swap 5 - random swap mod 2 + ( x y ) swap level @ 7 > if 10 else 5 then add-block loop then ; : init-stats ( -- ) 3 lives ! 0 points ! form 2 / player-pos ! drop 0 update-counter ! 1 tickcounter ! 1 level ! 20 levelspeed ! ; : init-map ( -- ) 1 5 create-ufo-type 100 5 +DO 5 i 2 pick add-ufo 20 +LOOP drop 2 10 create-ufo-type 100 5 +DO 10 i 2 pick add-ufo 20 +LOOP drop 100 5 +DO 15 i 10 add-block 20 +LOOP ; : game-run ( -- level points ) \ initialize memory init-stats start-new-wave \ gameloop 1 0 do lives @ 0 <= if leave then \ start time tracker utime drop >r ufo_list empty? if 1 level +! level @ 0 > if -2 levelspeed +! levelspeed @ 1 < if 1 levelspeed ! then then start-new-wave then clear-screen ." Level: " level @ . ." " ." Points: " points @ . ." Lives: " lives @ 0 ?do ." /\" loop tickcounter @ levelspeed @ mod 0= if update-ufos update-shots 0 tickcounter ! \ reset the counter then 1 tickcounter +! \ draw stuff draw-ufos draw-shots draw-blocks \ draw player player-pos @ draw-player \ check if player is dead player-pos @ form drop 2 - check-ufos-collision if -1 lives +! then \ keyboard input handler ekey? if ekey case k-left of player-move-left endof k-right of player-move-right endof k-insert of form drop player-pos @ add-shot endof k-end of clear-screen bye endof 27 of pause-screen 0= if rdrop \ clean time tracking leave then endof 9 of clear-map endof \ tab key endcase then \ user-wait utime drop ( newtime ) r> ( newtime oldtime ) - ( elapsed_time ) 10000 swap - ( time_to_wait ) dup 0 > if 10 emit 1000 / ms else drop then \ wait if needed 0 +loop \ fancy clear animation clear-screen-funny \ clean up memory clear-map \ return stats level @ points @ ;