!*************************** AMUS Program Label ******************************
! Filename: SHIP.BAS                                        Date: 10/??/90
! Category: GAMES        Hash Code:                      Version: 1.0(100)
! Initials: WENG/AM      Name: Michael Mc Murdie
! Company: Morton & Pitalo, Inc.                   Telephone #: 9169272400
! Related Files: SHIP.CMD, AMIGOS STUFF, INKEY.SBR, SLEEP.SBR, ...
! Min. Op. Sys.: AMOSL 1.3B/AMOS32 1.0         Expertise Level: BEG
! Special: not really...
! Description: Just a silly graphical lunar lander game
!*****************************************************************************
!This is my variation of the lunar lander program. It works as follows:
!The Left/Right arrow keys rotate the ship CCW/CW and each rotation
!consumes 10 units of fuel. In order to slow the ship press the numbers
! 1 - 9 for variable burn rate of fuel, 1 being the lowest, 9 being the
!highest. The point is to land on the landing pad at a slow speed. The ship
!will continue to move in the direction it is currently going taking into
!account gravity. If you hit the land first you die or if you hit the landing
!pad too fast you also die. Right now this is a REAL simple implementation
!but in the future I would like to see more variation. Such things as a
!variable landscape and location of the landing pad. In addition maybe you
!could offer variable gravity, fuel amount and height of mountains based on
!level of difficulty. In other words run amuk...
!
       PROGRAM SHIP,1.0(100)           !el numero de version...

++INCLUDE AMGSYM.BSI                    !grab the AMIGOS defs

       MAP1 GCB,X,50000                !graphics control block

       MAP1 PT'ARY                     !point array data structure
       MAP2    PT'CT,B,2               !number of points
       MAP2    PTS(50)                 !actual point array
       MAP3            PT'X,B,2        !x values
       MAP3            PT'Y,B,2        !y values

       MAP1 OLD'POS
       MAP2    OLD'CT,B,2
       MAP2    OLD'PTS(50)
       MAP3            OLD'X,B,2
       MAP3            OLD'Y,B,2

!surface is the actual surface of the planet we're landing on
       MAP1 SURFACE                    !surface to check
       MAP2    SRF'CT,B,2              !number of points
       MAP2    SRF'PTS(50)             !position of each point
       MAP3            SRF'X,B,2
       MAP3            SRF'Y,B,2

       MAP1 SHIP(20,2),F,6             !array to hold the SHIP shape
       MAP1 FLAME(10,2),F,6            !flame shape
       MAP1 SHIP'X,F,6                 !current SHIP position x
       MAP1 SHIP'Y,F,6                 !current SHIP position y
       MAP1 SHIP'ANG,F,6,0             !current SHIP angle index
       MAP1 NO'SHIP'PTS,F,6            !number of points making up the SHIP
       MAP1 CHAR,S,1                   !input character

!sine & cosine values are stored in an array to increase speed
       MAP1 SIN'ARY(72),F,6            !sine values
       MAP1 COS'ARY(72),F,6            !cosine values

       MAP1 STAT'STR,S,80

       XCALL AMGSBR,G'OPWK,GCB,"",STATUS       !open the workstation
       XCALL AMGSBR,G'SWM,GCB,1,STATUS         !set XOR mode
       XCALL AMGSBR,G'SPLC,GCB,1,STATUS        !white lines
       XCALL AMGSBR,G'SPLT,GCB,1,STATUS        !solid lines

       CALL BUILD'SHIP
       XCALL NOECHO : ? TAB(-1,29);TAB(-1,0);
       CALL SHOW'BASE
       PT'CT = NO'SHIP'PTS
       OLD'CT = PT'CT
!the following segment sets the initial values change them as desired
       SHIP'X = 2000 : SHIP'Y = 22000 : SHIP'ANG = 17
       VEL'X = 400 : VEL'Y = 75 : FUEL = 2000 : BURN = 0
       GRAVITY = 10

       ? tab(-1,11);
       ? tab(34,1);
       ? "Velocity  X:       Y:";tab(34,31);"Height:";tab(34,46);"Fuel:";
       ? TAB(-1,12);

       INIT'FLAG = 0 : CLK = 0
LOOP:   NEW'VEL'Y = VEL'Y - BURN + GRAVITY      !get new velocity
       SHIP'Y = SHIP'Y - 0.5*(NEW'VEL'Y + VEL'Y)       !new y position
       SHIP'X = SHIP'X + VEL'X                 !new x position
       VEL'Y = NEW'VEL'Y
       ? TAB(34,13);VEL'X USING "####";        !show current x velocity
       ? TAB(34,22);VEL'Y USING "####";        !show current y velocity
       ? TAB(34,38);SHIP'Y USING "#####";      !show height
       ? TAB(34,51);FUEL USING "####";         !show fuel left
!       ? TAB(34,61);CLK USING "#######";       !show elapsed time

       BURN = 0
       CALL CHECK'COLLISION                    !how's my driving?
       CALL SHOW'SHIP                          !update ship position
       XCALL INKEY,CHAR                        !key press waiting?
       CHAR = UCS(CHAR)
       IF CHAR=CHR(12) CALL ROTATE'RIGHT
       IF CHAR=CHR( 8) CALL ROTATE'LEFT
       IF CHAR >= "0" AND CHAR <= "9" CALL BURN'FUEL
       IF CHAR="Q" GOTO QUIT'SHIP              !quiters never win ... wimp!
       IF CHAR="" XCALL SLEEP,0.1              !nothing, just snooze...
       CLK = CLK + 1
       GOTO LOOP

QUIT'SHIP:
       CALL ERASE'SHIP
       XCALL AMGSBR,G'CLWK,GCB,STATUS          !close the workstation
       ? TAB(-1,0);TAB(-1,28);
       CHAIN "DSK0:COGO[15,1]"                 !this is only for our system
       END

SHOW'SHIP:
       !draw the ship at the current x & y position
       FOR I=1 TO NO'SHIP'PTS
         ARY'INDEX = SHIP'ANG + SHIP(I,2)
         IF ARY'INDEX > 72 ARY'INDEX = ARY'INDEX - 72
         PT'X(I) = SHIP'X + COS'ARY(ARY'INDEX)*SHIP(I,1)
         PT'Y(I) = SHIP'Y + SIN'ARY(ARY'INDEX)*SHIP(I,1)
       NEXT I
       IF INIT'FLAG XCALL AMGSBR,G'PL,GCB,OLD'POS,STATUS
       XCALL AMGSBR,G'PL,GCB,PT'ARY,STATUS
       OLD'POS = PT'ARY
       INIT'FLAG = 1
       RETURN

!since were using XOR writing mode, just redraw the ship and it disappears...
ERASE'SHIP:
       XCALL AMGSBR,G'PL,GCB,PT'ARY,STATUS
       RETURN

ROTATE'LEFT:                            !rotate ship CCW
       IF FUEL < 10 RETURN             !check GAS
       FUEL = FUEL - 10                !burn some fuel
       SHIP'ANG = SHIP'ANG - 2         !change angle by 10 degrees
       IF SHIP'ANG < 1 SHIP'ANG = SHIP'ANG + 72        !adjust array index
       RETURN

ROTATE'RIGHT:                           !rotate ship CW
       IF FUEL < 10 RETURN             !any gas left?
       FUEL = FUEL - 10                !burn some fuel
       SHIP'ANG = SHIP'ANG + 2         !change angle by 10 degrees
       IF SHIP'ANG > 72 SHIP'ANG = SHIP'ANG - 72       !adjust index
       RETURN

BUILD'SHIP:
!this SHIP array holds the dimensions of the ship. Each measurement is
!taken as a distance and an angle from this center point. Each angle
!is actually a reference into the sine & cosine arrays.
! SHIP( 1,1) = 500 ... 500 units from center to 1st point
! SHIP( 1,2) = 18  ...  18*5 or 90 degrees from horizontal, references
!                       18th position in sine & cosine arrays...

!define the SHIP shape
       SHIP( 1,1) = 500
       SHIP( 1,2) = 18
       SHIP( 2,1) = 640
       SHIP( 2,2) = 42
       SHIP( 3,1) = 700
       SHIP( 3,2) = 48
       SHIP( 4,1) = 480
       SHIP( 4,2) = 54
       SHIP( 5,1) = 700
       SHIP( 5,2) = 60
       SHIP( 6,1) = 640
       SHIP( 6,2) = 66
       SHIP( 7,1) = 500
       SHIP( 7,2) = 18
       NO'SHIP'PTS = 7
!define the flame shape
       FLAME(1,1) = 600
       FLAME(1,2) = 52
       FLAME(2,1) = 1500
       FLAME(2,2) = 54
       FLAME(3,1) = 600
       FLAME(3,2) = 56
!load the sines & cosines into arrays for speed
!loaded at 5 degree increments.
       ? "ANGS INIT"
       FOR I=1 TO 72
         SIN'ARY(I) = SIN((I-1)*0.087266463)
         COS'ARY(I) = COS((I-1)*0.087266463)
         ? ".";
       NEXT I
       ?
       RETURN

!BURN'FUEL at the rate determined by user input. Each burn contributes to
!the x velocity & the y velocity depending on the ship angle.
BURN'FUEL:
       BURN'RATE = VAL(CHAR)*10
       IF FUEL < BURN'RATE CALL NO'GAS : RETURN
       FUEL = FUEL - BURN'RATE
       BURN = BURN'RATE*COS'ARY(SHIP'ANG)
       VEL'X = VEL'X - BURN'RATE*SIN'ARY(SHIP'ANG)
       FOR I=1 TO 3
         ARY'INDEX = SHIP'ANG + FLAME(I,2)
         IF ARY'INDEX > 72 ARY'INDEX = ARY'INDEX - 72
         PT'X(I) = SHIP'X + COS'ARY(ARY'INDEX)*FLAME(I,1)
         PT'Y(I) = SHIP'Y + SIN'ARY(ARY'INDEX)*FLAME(I,1)
       NEXT I
       PT'CT = 3
       XCALL AMGSBR,G'SPLC,GCB,4,STATUS
       XCALL AMGSBR,G'PL,GCB,PT'ARY,STATUS
       XCALL SLEEP,0.1
       XCALL AMGSBR,G'PL,GCB,PT'ARY,STATUS
       XCALL AMGSBR,G'SPLC,GCB,1,STATUS
       PT'CT = NO'SHIP'PTS
       RETURN

!check to see if the midpoint of the ship has found terra firma anywhere,
!is so we blow up.
CHECK'COLLISION:
       IF SHIP'X < 13500 AND SHIP'X > 9500 GOTO CHECK'LANDING
       I = 2
CC'1:   IF I > SRF'CT GOTO CC'3
       IF SHIP'X <= SRF'X(I) AND SHIP'X >= SRF'X(I-1) GOTO CC'2
       I = I+1
       GOTO CC'1
CC'2:   Y'POS = SRF'Y(I-1) + &
         (((SHIP'X-SRF'X(I-1))*(SRF'Y(I)-SRF'Y(I-1)))/(SRF'X(I)-SRF'X(I-1)))
       IF Y'POS < SHIP'Y RETURN
CC'3:   GOTO BOOM

!we are over the landing pad...have we landed yet??
CHECK'LANDING:
       LAND'FLAG = 0
       FOR I=1 TO NO'SHIP'PTS          !check all corners of the ship
         ARY'INDEX = SHIP'ANG + SHIP(I,2)
         IF ARY'INDEX > 72 ARY'INDEX = ARY'INDEX - 72
         Y'POS = SHIP'Y + SIN'ARY(ARY'INDEX)*SHIP(I,1)
         IF Y'POS < 4000 LAND'FLAG = 1
       NEXT I
       IF LAND'FLAG = 0 RETURN
!at this point we know we are on the ground
       ? TAB(33,1);
!could definitely stand a little better messages...
       IF VEL'Y < 50 ? "Good Landing"
       IF VEL'Y > 50 AND VEL'Y < 75 ? "Landed with structural damage"
       IF VEL'Y > 75 AND VEL'Y < 125 ? "Landed, severe damage, few survivors"
       IF VEL'Y > 125 ? "Landed, Ship completely destroyed, all lives lost" : GOTO BOOM
       ? TAB(34,13);VEL'X USING "####";
       ? TAB(34,22);VEL'Y USING "####";
       ? TAB(34,38);SHIP'Y USING "#####";
       ? TAB(34,51);FUEL USING "####";
       ? TAB(1,1);
       ? TAB(-1,28);
       XCALL AMGSBR,G'CLWK,GCB,STATUS          !close the workstation
       END

!we crashed so let's blow up...
BOOM:   XCALL AMGSBR,G'SPLT,GCB,2,STATUS
       XCALL AMGSBR,G'PL,GCB,PT'ARY,STATUS
       XCALL SLEEP,0.1
       XCALL AMGSBR,G'SPLT,GCB,3,STATUS
       XCALL AMGSBR,G'PL,GCB,PT'ARY,STATUS
       XCALL SLEEP,0.1
       CALL ERASE'SHIP
       FOR I=1 TO 10
         ? TAB(-1,36);
         XCALL SLEEP,0.1
         ? TAB(-1,37);
         XCALL SLEEP,0.1
       NEXT I
       ? TAB(1,1);
       ? "YOU DIED..."
       ? TAB(-1,28);
       XCALL AMGSBR,G'CLWK,GCB,STATUS          !close the workstation
       END

SHOW'BASE:
!in the future, we should alter the landscape for variety,
!possibly using random number generation for the surface.
       SRF'X( 1) = 00000 : SRF'Y( 1) = 2662
       SRF'X( 2) = 00000 : SRF'Y( 2) = 6600
       SRF'X( 3) = 02600 : SRF'Y( 3) = 12500
       SRF'X( 4) = 03600 : SRF'Y( 4) = 5300
       SRF'X( 5) = 06000 : SRF'Y( 5) = 8400
       SRF'X( 6) = 07500 : SRF'Y( 6) = 6000
       SRF'X( 7) = 08200 : SRF'Y( 7) = 9000
       SRF'X( 8) = 09500 : SRF'Y( 8) = 4000
       SRF'X( 9) = 13500 : SRF'Y( 9) = 4000
       SRF'X(10) = 15200 : SRF'Y(10) = 13000
       SRF'X(11) = 16500 : SRF'Y(11) = 7100
       SRF'X(12) = 19400 : SRF'Y(12) = 10000
       SRF'X(13) = 21000 : SRF'Y(13) = 8000
       SRF'X(14) = 24100 : SRF'Y(14) = 13500
       SRF'X(15) = 26200 : SRF'Y(15) = 8700
       SRF'X(16) = 28000 : SRF'Y(16) = 13000
       SRF'X(17) = 29900 : SRF'Y(17) = 8100
       SRF'X(18) = 32000 : SRF'Y(18) = 12000
       SRF'X(19) = 32000 : SRF'Y(19) = 2662
       SRF'X(20) = 00000 : SRF'Y(20) = 2662
       SRF'CT = 20
       XCALL AMGSBR,G'SFAS,GCB,3,STATUS
       XCALL AMGSBR,G'SFAI,GCB,22,STATUS
       XCALL AMGSBR,G'SFAC,GCB,9,STATUS
       XCALL AMGSBR,G'FA,GCB,SURFACE,STATUS
       PT'X(1) = 9500  : PT'Y(1) = 4000
       PT'X(2) = 13500 : PT'Y(2) = 4000
       PT'X(3) = 13500 : PT'Y(3) = 3000
       PT'X(4) = 9500  : PT'Y(4) = 3000
       PT'X(5) = 9500  : PT'Y(5) = 4000
       PT'CT = 5
       XCALL AMGSBR,G'SFAS,GCB,2,STATUS
       XCALL AMGSBR,G'SFAC,GCB,5,STATUS
       XCALL AMGSBR,G'FA,GCB,PT'ARY,STATUS
       RETURN

!no gas left in the tanks...bummer...
NO'GAS: ? TAB(32,1);
       ? TAB(-2,1);TAB(-3,4);CHR(7);" INSUFFICIENT FUEL ";
       ? TAB(-2,1);TAB(-3,0);
       RETURN