*** asteroids game
** 1 1 10601 ship
* ov00: control method. 0 = mouse, 1 = keyboard (only fully-featured for 1)
* ov01 controller
* ov02 asteroids controller
* ov03 hull damage (0-2)
* ov04 text display
* ov05 is speed (+ forward, - backward)
* ov06 score
* ov50 & ov51 left & top of metaroom
* 0 (deact) p1 text to relay
* 1000 fire
* 1001 orient or move (p1 direction)
* 1002 hit (by p1 size)
* 1003 relay text (p1)

** 1 1 10602 bullet

** 1 1 10603 ship control
* ov00 ship

** 1 1 10604 asteroids control
* ov00 ship
* 9 timer, (p1 -1) => (p2 no. of asteroids to make)

** 1 1 10605 asteroid
* ov00 controller
* ov01 ship
* ov02 size (0 big - 2 small)
* 9 timer checks collisions

** 1 1 10606 display; pt 1 fixd
* ov00 ship
* 1000 append p1, or -1 clean, -2 welcome

** 1 3 10607 favourite place signpost
* thereto: 1 4 10607, icon

* TODO.
* * Levels, possibly. No way to win, but increasing pace could be good.

* DONETO.
* * Asteroids colliding with each other? How would this work? -- DONE with
*   them glancing off one another. realistic?
* * Is it unrealistic to make ship slow but not asteroids? If change, need to
*   sort out braking/reversing (down arrow). -- DONE
* * Need more UI. Buttons should take user back to ship/etc. Ought to make
*   text display AFTER activation. Maybe best to get to ship with button too?
*   -- DONE with fav place. display remains always, but only contains stuff
*   when ship's visible.
* * Do spaces tend to go to the speech bubble? -- DONE
* * Test on quick box. What intervals are suitable for asteroid appearance?
*   (poss. use RACE to detect speed/adjust?) -- DONE using PACE
* * Points counter.

inst

* asteroid speed components
setv game "ast_max" 10
setv game "ast_min" 5

new: simp 1 1 10601 "asteroids" 16 0 5000
attr 39
clac 0
bhvr 0
pose 0

* define location of tip - not perfect
puhl 0 22 8
puhl 1 15 8
puhl 2 10 9
puhl 3 7 14
puhl 4 9 23
puhl 5 8 30
puhl 6 9 35
puhl 7 14 38
puhl 8 23 36
puhl 9 30 37
puhl 10 35 36
puhl 11 38 31
puhl 12 36 21
puhl 13 37 15
puhl 14 36 10
puhl 15 31 7

* used in timer script
fric 3

tran 0 0

seta va00 targ

setv va01 meta
* set up metaroom (don't change the size! please.)
setv ov50 5830
setv ov51 4550
setv game "ship_meta" addm ov50 ov51 800 600 "black"
setv va02 ov50
addv va02 400
setv va03 ov51
addv va03 300
mvto va02 va03 
cmrt 0
*doif meta ne va01
*  enum 0 0 0
*    mesg writ targ 900
*  next
*endi
targ va00

* operation: 0 mouse, 1 keyboard
setv ov00 1

* create main controller (timer)
new: simp 1 1 10603 "blnk" 1 0 0
seta ov00 va00
seta va01 targ
targ va00
seta ov01 va01

* create asteroid controller
new: simp 1 1 10604 "blnk" 1 0 0
seta ov00 va00
seta va01 targ
targ va00
seta ov02 va01

* create text-display
new: comp 1 1 10606 "caos" 1 1 9000
attr 32
flto 0 100
seta ov00 va00

pat: fixd 1 "caos" 1 0 0 0 "whiteontransparentchars"
part 1
tran 1 1
setv va02 2000
subv va02 wndw
frmt 0 0 va02 1800 0 0 0

mesg wrt+ targ 1000 -2 0 0

seta va01 targ
targ va00
seta ov04 va01

* make favourite places signpost. DS will do its magic with it.
setv va03 ov50
addv va03 200
setv va04 ov51
addv va04 200
new: simp 1 3 10607 "fav_place_asteroids" 1 0 1
plne 0
attr 272
mvto va03 va04
tick 10

slow


*scrp 1 1 10601 5
*  dbg: outs "drop called"
*endm


*** activate - turn timer on
scrp 1 1 10601 1 
  inst
  clac 2
  targ ov01
  tick 1
  targ ownr

  targ ov02
  * level 1
  setv va00 buzz
  doif pace gt 1
    mulv va00 pace
  endi
  * va01 is asteroid addition interval in milliseconds
  setv va01 10000
  divv va01 va00
  tick va01
  mesg wrt+ targ 9 -1 3 0
  targ ownr

  setv ov06 0
  mesg wrt+ ov04 1000 -1 "Score: 0000" 0

  doif ov00 eq 0
    pure 1
    imsk 28
  elif ov00 eq 1
    imsk 3
  endi

  targ null
  fcus

  slow
endm

*** deactivate
scrp 1 1 10601 0
  inst
  clac 0

  * timers off
  targ ov01
  tick 0
  targ ownr
  targ ov02
  tick 0
  targ ownr

  * tidy
  enum 1 1 10602
    kill targ
  next
  enum 1 1 10605
    kill targ
  next
  
  * only effective for ov00 eq 0
  pure 0
  imsk 0

  * reset the ship
  setv ov03 0
  pose 0
  setv va00 ov50
  addv va00 400
  setv va01 ov51
  addv va01 300
  mvto va00 va01
  velo 0 0
  setv ov05 0

  targ game "c3_default_focus"
  part game "c3_default_focus_part"
  fcus
  targ ownr

*  * how can we tell if no p1 is passed??
*  doif type _p1_ ne 2
*    sets _p1_ "Game ended."
*  endi

  * relay text
  mesg wrt+ ownr 1003 _p1_ 0 0

  slow
endm

** pickup - deactivate
scrp 1 1 10601 4
  mesg wrt+ ownr 2 0 0 0
endm

** meta changed
scrp 1 1 10601 900
  doif meta eq game "ship_meta"
    mesg wrt+ ownr 2 -2 0 0
  else
    mesg wrt+ ownr 2 -1 0 0
  endi
endm

*** timer IN CONTROL AGENT - follow hand around
scrp 1 1 10603 9

  inst

  targ ov00
  
  * just in case
  doif meta ne game "ship_meta"
    mesg wrt+ targ 2 -1 0 0
    stop
  endi
  
  doif ov00 eq 0
    * mouse control only 

    setv va00 mopy negv va00
    setv va01 mopx negv va01
    * va00 = mop x
    * va01 = mop y
  
    setv va02 posy negv va02
    setv va03 posx negv va03
    * va02 = agent x
    * va03 = agent y
  
    subv va01 va03
    subv va00 va02
    * va01 = (y2 - y1)
    * va00 = (x2 - x1)
  
    setv va04 va01
    setv va04 itof va04
    doif va00 eq 0
      setv va04 0
    else
      divv va04 va00
    endi
    * va04 = Dy/Dx
  
    setv va05 atan va04
    doif va05 lt 0
      addv va05 180
    endi
    doif va01 lt 0
      addv va05 180
    endi
    * va05 = angle of hand from agent
  
    divv va05 22.5
    setv va05 ftoi va05
    doif va05 eq 16
      setv va05 0
    endi
    * va05 = pose for ship
  
    pose va05
 
  endi
  * any control method
  
  setv va01 velx
  setv va02 vely

  ** wrap edges for both ship & asteroids

  gsub wrap
  enum 1 1 10605
    gsub wrap
  next

  *adjust velocity dir
  mesg wrt+ mv00 1001 0 0 0

  slow stop

  subr wrap
    doif posb lt wndt
      mvto posl wndb
    elif post gt wndb
      mvto posl wndt
    endi
    doif posr lt wndl
      mvto wndr post
    elif posl gt wndr
      mvto wndl post
    endi
  retn

endm


*** raw key down
* caught when activated while ov00 eq 1
** left:37, right:39, up:38, down:40
** space:32, return:13

scrp 1 1 10601 73
  inst

  doif _p1_ eq 37
    * rotate ccw
    setv va00 pose addv va00 1
    doif va00 eq 16
      setv va00 0
    endi
    pose va00
  elif _p1_ eq 39
    * rotate cw
    setv va00 pose subv va00 1
    doif va00 eq -1
      setv va00 15
    endi
    pose va00
  elif _p1_ eq 38
    * move forward
    mesg wrt+ ownr 1001 1 0 0
  elif _p1_ eq 40
    * move backward
    mesg wrt+ ownr 1001 2 0 0
  elif _p1_ eq 32
    * fire
    mesg wrt+ ownr 1000 0 0 0
  elif _p1_ eq 13
    * deact
    mesg wrt+ ownr 2 0 0 0
  endi
  
endm

*** raw mouse down - fire
* left-click within agent does pure 0
* right-click deactivates
* (NB, only caught when active and ov00 eq 0)
scrp 1 1 10601 76
  inst

  doif _P1_ ne 1 and _P1_ ne 2 and _P1_ ne 4
    stop
  endi
  
  doif _P1_ eq 2
    * deact
    mesg wrt+ ownr 2 0 0 0
    stop
  endi
  
  doif _P1_ eq 1
    
    doif mopx gt posl and mopx lt posr and mopy gt post and mopy lt posb
      pure 0
      * engine will now handle click to agent (deact)
      stop
    else
      * fire
      mesg wrt+ ownr 1000 0 0 0
    endi

  endi
  * any _P1_:
  
  slow

endm

*** fire
scrp 1 1 10601 1000

  inst

  * value for resultant velocity (ne 0 please)
  setv va10 game "ast_max"
  mulv va10 1.4142
  * momentum
  addv va10 ov05

  doif ov00 eq 0
    * mouse control only

    setv va00 mopx subv va00 posx
    setv va01 mopy subv va01 posy
    * va00 = (x2 - x1); va01 = (y2 - y1)
    
    setv va02 va00 mulv va02 va02
    setv va03 va01 mulv va03 va03
    addv va03 va02
    * va03 = (x2-x1)^2 + (y2-y1)^2
  
    setv va03 sqrt itof va03
    divv va03 va10
    * now may divide directional components by va03 so resultant = va10
    
    divv va00 va03 divv va01 va03
    * these now hold velocities
  
  elif ov00 eq 1
    * keyboard control only
    setv va00 360
    setv va00 itof va00
    divv va00 16
    mulv va00 pose
    * va00 = bearing to fire at
    setv va01 tan_ va00
    setv va02 1
    * discontinuity at 90 (pose 4) and 270 (pose 12) not a problem :)
    * va01 = opposite (y', actually -x); va02 = adjacent (x', = -y)
    setv va03 va01 mulv va03 va03
    addv va03 1
    *setv va03 itof va03
    setv va03 sqrt va03
    * va03 = (opp^2 + adj^2)^(1/2)
    divv va03 va10
    * va03 = val to divide components so total=va10
    divv va01 va03
    divv va02 va03
    * va01 and va02 now y' and x' components of velocity
    doif va00 le 90 or va00 gt 270
      negv va01 negv va02
    endi
    setv va00 va01 setv va01 va02
    * va00 and va01 now moved/-ved, so hold x and y (respectively)
  endi
  * any control method
    
  setv va04 puhl pose 1 addv va04 posl
  setv va05 puhl pose 2 addv va05 post

  * va00 & va01 are x & y velocities
  * va04 & va05 are x and y starting positions for bullet
  new: simp 1 1 10602 "asteroids" 1 16 4999
  attr 32
  bhvr 0
  pose 0
  tick 40
  mvto va04 va05
  velo va00 va01

  slow

endm

*** move
* _p1_ = 1 for forward, _p1_ = 2 for backward
* _p1_ = 0 just adjusts current angle
scrp 1 1 10601 1001
  inst
  * check/adjust current velo angle
  doif ov00 eq 0
    * grab intended angle

    setv va00 mopy negv va00
    setv va01 mopx negv va01
    * va00 = mop x; va01 = mop y
  
    setv va02 posy negv va02
    setv va03 posx negv va03
    * va02 = agent x; va03 = agent y
  
    subv va01 va03
    subv va00 va02
    * va01 = (y2 - y1)
    * va00 = (x2 - x1)
  
    setv va04 va01
    setv va04 itof va04
    doif va00 eq 0
      setv va04 0
    else
      divv va04 va00
    endi
    * va04 = Dy/Dx
  
    setv va05 atan va04
    doif va05 lt 0
      addv va05 180
    endi
    doif va01 lt 0
      addv va05 180
    endi
    * va05 = angle of hand from agent

    setv va00 va05
    
  elif ov00 eq 1
    * grab intended angle
    setv va00 360
    setv va00 itof va00
    divv va00 16
    mulv va00 pose
  endi
  * va00 = angle of ship (ccw from N)

  setv va01 0 setv va02 0 setv va03 0 setv va04 0 setv va05 0

  setv va01 cos_ va00
  setv va02 sin_ va00

  * va03 = current speed
  setv va03 ov05

  doif _p1_ ne 0
    doif _p1_ eq 1
      addv ov05 10
    elif _p1_ eq 2
      subv ov05 10
    endi
    doif ov05 gt 70
      setv ov05 70
    elif ov05 lt -70
      setv ov05 -70
    endi
  endi

  mulv va01 va03
  mulv va02 va03

  negv va01 negv va02
  velo va02 va01

endm

* ship got hit - p1 is size of asteroid
scrp 1 1 10601 1002
  inst
  addv ov03 1
  doif ov03 gt 2
    mesg wrt+ ownr 2 "GAME OVER" 0 0
  else
    sets va00 "Hull damage sustained! Strength: "
    doif ov03 eq 1
      adds va00 "50"
    else
      adds va00 "25"
    endi
    adds va00 "%"
    mesg wrt+ ownr 1003 va00 0 0
  endi
endm

* relay text
scrp 1 1 10601 1003
  inst
  mesg wrt+ ov04 1000 _p1_ 0 0
endm

* kill bullet after some time
scrp 1 1 10602 9
  kill ownr
endm

* asteroid scheduler - timer
scrp 1 1 10604 9
  inst

  doif _p1_ eq -1
    setv va10 _p2_
  else
    setv va10 1
  endi

  reps va10

    targ mv00
    setv va00 ov50
    setv va01 ov51
    targ ownr
  
    new: simp 1 1 10605 "asteroids" 3 17 4998 
    attr 32
  
    * related agents
    seta ov00 ownr
    seta ov01 mv00
  
    * size
    setv va04 rand 0 2
    setv ov02 va04
    pose ov02
  
    * position on edge of screen
    doif rand 0 1 eq 0
      setv va02 rand 0 800
      addv va02 va00
      doif rand 0 1 eq 0
        addv va01 600
      endi
      mvto va02 va01
    else
      setv va03 rand 0 600
      addv va03 va01
      doif rand 0 1 eq 0
        addv va00 800
      endi
      mvto va00 va03
    endi
  
    * give some velocity
    setv va00 rand game "ast_min" game "ast_max"
    doif rand 0 1 eq 0
      negv va00
    endi
    setv va01 rand game "ast_min" game "ast_max"
    doif rand 0 1 eq 0
      negv va01
    endi
  
    velo va00 va01
  
    * timer watches collisions:
    tick 1

  repe

  slow
endm

* asteroid timer checks collisions.
scrp 1 1 10605 9
  inst

  * are we scheduled to self-destruct?
  ** this will occur if we've split, so if we're hit by a bullet or ship
  doif ov99 ne 0
    doif ov99 eq 2
      targ mv01
      addv ov06 1
      setv va00 ftoi ov06
      modv va00 10000
      targ ov04
      part 1
      sets va01 ptxt
      doif va01 ne ""
        doif strl va01 gt 11
          sets va02 subs va01 12 -1
        else
          sets va02 ""
        endi
        sets va03 "Score: "
        sets va04 vtos va00
        doif strl va04 lt 4
          loop
            sets va05 "0"
            adds va05 va04
            sets va04 va05
          untl strl va04 ge 4
        endi
        adds va03 va04
        adds va03 va02
        ptxt va03
      endi
    endi
    kill ownr
  endi

  * in case we just split (hack):
  tick 1

  * are we being struck by a bullet?
  enum 1 1 10602
    doif touc targ ownr eq 1
      setv va11 2
      gsub split
      kill targ
   endi
  next

  * have we hit another asteroid?
  enum 1 1 10605
    doif touc targ ownr eq 1
      seta va00 targ
      gsub makevel
      targ ownr
      velo va01 va02
    endi
  next

  * have we hit the ship?
  doif touc mv01 ownr eq 1
    targ mv01
    gsub split
    * warn ship of collision (p1 size)
    mesg wrt+ mv01 1002 mv02 0 0
  endi

  stop

  * make 2 smaller asteroids and throw them off
  subr split
    * NB targ is collided agent
    * we may only do this once
    doif va10 eq 0
      setv va10 1
      seta va00 targ
      doif mv02 ne 2
        addv mv02 1
        * generate rebound...
        gsub makevel
        gsub newast
        * swap x and y velo (crude angular momentum)
        setv va03 va01
        setv va01 va02
        setv va02 va03
        gsub newast
      endi
      * schedule death
      doif va11 eq 0
        setv va11 1
      endi
      setv mv99 va11
      setv va11 0
      targ va00
    endi
  retn

  subr makevel
    * va00/targ is colliding with ownr. make a velocity for ownr in va01 va02
    setv va01 posx  setv va02 posy
    targ ownr
    subv va01 posx  subv va02 posy
    negv va01  negv va02
    setv va03 disq va00
    setv va03 sqrt va03
    divv va01 va03  divv va02 va03
    mulv va01 rand game "ast_min" game "ast_max"
    mulv va02 rand game "ast_min" game "ast_max"
  retn

  * make an asteroid    
  subr newast
    * va01 and va02 are x and y velo.
    new: simp 1 1 10605 "asteroids" 3 17 4998
    attr 32
    seta ov00 mv00
    seta ov01 mv01
    setv ov02 mv02
    pose ov02
    
    * find position of original
    seta va03 targ
    targ ownr
    setv va04 posl setv va05 post
    targ va03
    
    mvto va04 va05
    velo va01 va02
    
    * temporary invincibility & harmlessness (hack)
    tick 3
  retn

endm

* add p1 to output text, or -1 to wipe/say p2, -2 for welcome
scrp 1 1 10606 1000
  inst

  part 1
  
  doif type _p1_ ne 2
    doif _p1_ eq -1
      doif type _p2_ eq 2
        ptxt _p2_
      else
       ptxt ""
      endi
    elif _p1_ eq -2
      ptxt "Hello! Click the ship to start.\n\nArrow keys move and turn, SPACE\nfires, and RETURN ends the game."
    endi
  else
    sets va00 ptxt
    doif va00 ne ""
      adds va00 "\n"
    endi
    adds va00 _p1_
    ptxt va00
  endi

endm


rscr
inst

* where are we? (we may be being injected)
doif meta ne game "ship_meta"
  setv va10 meta
else
  setv va10 11
endi

targ game "c3_default_focus"
part game "c3_default_focus_part"
fcus

targ null

setv va00 10600
reps 6
  addv va00 1
  enum 1 1 va00
    kill targ
  next
repe
scrx 1 1 10601 1
scrx 1 1 10601 0
scrx 1 1 10601 9
scrx 1 1 10601 4
scrx 1 1 10601 76
setv va00 1000
reps 4
  scrx 1 1 10601 va00
  addv va00 1
repe
scrx 1 1 10602 9
scrx 1 1 10603 9
scrx 1 1 10604 9
scrx 1 1 10605 9
scrx 1 1 10606 1000
delm game "ship_meta"
delg "ship_meta"
delg "ast_min" delg "ast_max"

* shuffle fav places along and kill ourselves
rtar 1 4 10607
doif targ ne null
  setv va00 ov50
  enum 1 4 0
    doif ov50 gt va00
      subv ov50 1
    endi
  next
  subv game "ds_favourites" 1
endi
enum 1 0 10607
  kill targ
next
*enum 1 4 0
*  mesg wrt+ targ 9 0 0 0
*next

*** REMOVED for .agents injection compatibility (!)
* finally, move back to the wherever we started (or the Norn Meso)
*setv va11 -1
*enum 1 4 0
*  doif ov01 eq va10
*    setv va11 spcs
*  endi
*next
*doif va11 eq -1
*  setv va11 10
*endi
*rtar 1 3 va11
*doif targ ne null
*  cmrt 0
*  enum 0 0 0
*    mesg writ targ 900
*  next
*else
*  meta 11 0 0 0
*endi
