REM GALAGA enemy behavior. The C engine loads this file, runs it once so the
REM definitions exist, and then calls one UPDATE function per enemy per frame.
REM There is no top-level code: definitions, then END.
REM
REM Names the engine binds before every call:
REM   SELF@  - this enemy's record (ENEMY): the state machine's memory
REM   ACTOR@ - the engine's live actor (ACTOR): position is the real thing
REM   GAME@  - shared frame state (GAME): player position, wave, randomness
REM
REM SELF@.STATE# bits: 1 = entering  2 = in formation  4 = diving
REM
REM Two rules of this dialect that bite here, both from docs/03:
REM   - the LEFT operand decides integer or float arithmetic, so a float
REM     always goes first: SELF@.T% * 150 + 260, never 260 + 150 * SELF@.T%
REM   - RETURN at the start of a line ends the DEF body, so every early
REM     return rides an IF ... THEN, and only the last RETURN starts a line

REM Ease toward the formation slot, with a little entry swirl.
REM Answers 1 once the slot is reached, else 0.
DEF GLIDEHOME(DT%)
  DX% = SELF@.HOMEX% - ACTOR@.X%
  DY% = SELF@.HOMEY% - ACTOR@.Y%
  K% = DT% * 4.5
  IF K% > 1 THEN K% = 1
  ACTOR@.X% = ACTOR@.X% + DX% * K% + SIN(SELF@.T% * 6) * 90 * DT%
  ACTOR@.Y% = ACTOR@.Y% + DY% * K%
  IF ABS(DX%) < 3 AND ABS(DY%) < 3 THEN RETURN 1
  RETURN 0

REM One frame of a dive: accelerate downward, weave, lean toward the
REM player's column, and glide back in from the top after falling out.
DEF DIVESTEP(DT%, WEAVE%, LEAD%)
  SPD% = SELF@.T% * 150 + 260
  ACTOR@.Y% = ACTOR@.Y% + SPD% * DT%
  ACTOR@.X% = ACTOR@.X% + SIN(SELF@.T% * 4) * WEAVE% * DT%
  DX% = GAME@.PLAYERX% - ACTOR@.X%
  IF DX% > 220 THEN DX% = 220
  IF DX% < -220 THEN DX% = -220
  ACTOR@.X% = ACTOR@.X% + DX% * LEAD% * DT%
  IF ACTOR@.Y% > 1040 THEN BEGIN
    ACTOR@.Y% = 0.0 - 90
    SELF@.STATE# = 1
    SELF@.T% = 0
  BEND
  RETURN 0

REM Raise the fire flag when diving roughly above the player. The engine
REM consumes FIRE# and does the spawning; the script only wishes.
DEF DECIDEFIRE(DT%)
  DX% = GAME@.PLAYERX% - ACTOR@.X%
  IF ABS(DX%) > 140 THEN RETURN 0
  IF ACTOR@.Y% > GAME@.PLAYERY% THEN RETURN 0
  IF SELF@.ROLL% < DT% * 1.5 THEN SELF@.FIRE# = 1
  RETURN 0

REM Bee: enter, breathe in formation, occasionally dive nearly straight.
DEF UPDATEBEE(DT%)
  SELF@.T% = SELF@.T% + DT%
  IF SELF@.T% < 0 THEN RETURN 0
  S# = SELF@.STATE#
  IF (S# AND 1) > 0 THEN BEGIN
    R# = GLIDEHOME(DT%)
    IF R# = 1 THEN SELF@.STATE# = 2 : SELF@.T% = 0
  BEND
  IF (S# AND 2) > 0 THEN BEGIN
    ACTOR@.X% = SELF@.HOMEX% + SIN(SELF@.T% * 1.7) * 16
    ACTOR@.Y% = SELF@.HOMEY%
    IF SELF@.ROLL% < DT% * 0.04 THEN SELF@.STATE# = 4 : SELF@.T% = 0
  BEND
  IF (S# AND 4) > 0 THEN BEGIN
    R# = DIVESTEP(DT%, 130, 0.2)
    R# = DECIDEFIRE(DT%)
  BEND
  RETURN 0

REM Butterfly: the same machine with a wide lateral weave on the dive.
DEF UPDATEBFLY(DT%)
  SELF@.T% = SELF@.T% + DT%
  IF SELF@.T% < 0 THEN RETURN 0
  S# = SELF@.STATE#
  IF (S# AND 1) > 0 THEN BEGIN
    R# = GLIDEHOME(DT%)
    IF R# = 1 THEN SELF@.STATE# = 2 : SELF@.T% = 0
  BEND
  IF (S# AND 2) > 0 THEN BEGIN
    ACTOR@.X% = SELF@.HOMEX% + SIN(SELF@.T% * 2.1) * 24
    ACTOR@.Y% = SELF@.HOMEY%
    IF SELF@.ROLL% < DT% * 0.05 THEN SELF@.STATE# = 4 : SELF@.T% = 0
  BEND
  IF (S# AND 4) > 0 THEN BEGIN
    R# = DIVESTEP(DT%, 260, 0.1)
    R# = DECIDEFIRE(DT%)
  BEND
  RETURN 0

REM Boss: two hit points, a slow sway, and a dive that leads the player.
REM At one hit point it raises actor state bit 13 (8192), and the engine's
REM character mapping swaps the sprite - the boundary crossed the other way.
DEF UPDATEBOSS(DT%)
  SELF@.T% = SELF@.T% + DT%
  IF SELF@.T% < 0 THEN RETURN 0
  IF SELF@.HP# = 1 THEN ACTOR@.STATE# = ACTOR@.STATE# OR 8192
  S# = SELF@.STATE#
  IF (S# AND 1) > 0 THEN BEGIN
    R# = GLIDEHOME(DT%)
    IF R# = 1 THEN SELF@.STATE# = 2 : SELF@.T% = 0
  BEND
  IF (S# AND 2) > 0 THEN BEGIN
    ACTOR@.X% = SELF@.HOMEX% + SIN(SELF@.T% * 1.1) * 10
    ACTOR@.Y% = SELF@.HOMEY%
    IF SELF@.ROLL% < DT% * 0.03 THEN SELF@.STATE# = 4 : SELF@.T% = 0
  BEND
  IF (S# AND 4) > 0 THEN BEGIN
    R# = DIVESTEP(DT%, 60, 0.9)
    R# = DECIDEFIRE(DT%)
  BEND
  RETURN 0

END
