;   ->  GPWS Custom Module V1.4      by Wilco van Deijl (puk_muk@knoware.nl)
;   ->  YOU CAN ADD THIS FILE AS CUSTOM MODULE TO A FLIGHTSHOP ATC ADVENTURE

gpws:
DECLARE init
IF init=0 THEN
init=1
DECLARE aa,alt0,ap,crs,dh,dist,dist0,dist1,gear,gpws,gs,ias,ias0,lastcall,loc
DECLARE ra,ra0,ra1,time,time0,trim,vs,warning,x0
gpws=2                       ;GPWS on (0=off,1=alt,2=on,3=g/s,4=flap,5=gear)
gear=10                      ;default RA correction for gear height (ft)
ADV_KEYS ADD,287,288
ONKEY 288 GOSUB dh           ;Shift-d
ONKEY 287 GOSUB setup        ;Shift-s
ONSTALL GOSUB stickshaker
trim=ELEVATOR_TRIM_POSITION

DECLARE xVOR_1_GLIDE_SLOPE   ; -> DELETE THESE LINES IF YOU'VE GOT AN UPDATED
xVOR_1_GLIDE_SLOPE=3         ; -> VERSION OF FLIGHTSHOP AND DELETE THE 'x' OF
                             ; -> ALL THE xVOR_1_GLIDE_SLOPE VARIABLES IN THE
                             ; -> REST OF THIS PROGRAM
ENDIF

gpws_1:
    GOSUB apdisc_trim
    ra=MTOF(PLANE_ALT-GROUND_ALTITUDE)-gear           ;Radio Altitude
    vs=VELOCITY_Y*196.8                               ;Vertical Speed
    ias=VELOCITY_INDICATED                            ;Indicated Airspeed 
    IF ON_GROUND THEN
        GOSUB on_gnd
        IF ias>ias0 AND ias0>30 THEN
            IF NOT INRANGE(ELEVATOR_TRIM_POSITION,-8000,8000) OR FLAPS_LEFT_POSITION>25000 OR PARKING_BRAKES THEN
                PLAY "-towarn.wav"                        ;take-off config
                WAIT 1
                warning=1
                GOTO gpws_1
            ENDIF
        ENDIF
        ias0=ias
    ELSEIF INRANGE(ra,-30,2450) THEN
        IF ias0-ias>9 AND INRANGE(ias,1,170) AND PLANE_PITCH<25 AND ra<1500 AND (WIND_SURF_VEL>10 OR WIND_LOW_VEL>10) THEN 
            IF (INRANGE((WIND_SURF_DEPTH-PLANE_ALT),-50,50) OR INRANGE((WIND_LOW_BASE-PLANE_ALT),50,50)) AND gpws>1 THEN
                PLAY "-windshr.wav"                   ;mode7
                WAIT 1
                warning=1
                ias0=ias
                GOTO gpws_1
            ENDIF
        ENDIF
        ias0=ias
        IF vs<100 THEN
            IF ra<65 AND gpws>0 THEN                             
                GOTO flare                            ;mode6
            ELSEIF ra<1000 THEN
                IF vs<-1.8*ra-1400 AND gpws>1 THEN                  
                    IF vs<-1.2*ra-2000 THEN           
                        PLAY "-terrnpu.wav"           ;mode2
                    ELSE
                        PLAY "-snkrtpu.wav"           ;mode1
                    ENDIF                      
                    WAIT 2              
                    warning=1
                    GOTO gpws_1
                ELSEIF GEAR_3_POSITION=0 AND ra1=0 AND INRANGE(gpws,2,4) THEN
                    IF ra<500 AND VELOCITY_INDICATED<190 THEN
                        PLAY "-gear.wav"              ;mode4a
                        WAIT 2
                        warning=1
                        GOTO gpws_1
                    ELSEIF VELOCITY_INDICATED>0.12*ra+130 THEN
                        PLAY "-toolowt.wav"
                        WAIT 2
                        warning=1
                        GOTO gpws_1
                    ENDIF
                ELSEIF FLAPS_LEFT_POSITION<20000 AND ra1=0 AND INRANGE(gpws,2,3) THEN
                    IF ra<245 AND VELOCITY_INDICATED<160 THEN
                        PLAY "-flaps.wav"             ;mode4b (flaps<20)
                        WAIT 2
                        warning=1
                        GOTO gpws_1
                    ELSEIF VELOCITY_INDICATED>0.12*ra+130 THEN
                        PLAY "-toolowt.wav"
                        WAIT 2
                        warning=1
                        GOTO gpws_1
                    ENDIF
                ENDIF
                IF ra<110 THEN                        
                    IF lastcall!=100 THEN
                        IF dh!=100 AND gpws>0 THEN
                            PLAY "-100.wav"           ;mode6
                        ELSEIF gpws>0 THEN
                            PLAY "-min.wav"
                        ENDIF 
                        lastcall=100    
                    ENDIF 
                    IF vs<-1.6*ra-1000 AND gpws>1 THEN                     
                        PLAY "-snkrate.wav"           ;mode1
                        WAIT 1     
                    ELSEIF ra1>1 AND ra1-ra>ra/10 AND gpws>1 THEN
                        PLAY "-dontsnk.wav"           ;mode3
                        WAIT 1
                    ENDIF
                    GOTO gpws_1
                ELSEIF NOT INRANGE(ra,lastcall-90,lastcall+10) THEN
                    IF INRANGE(ra,160,210) THEN
                        IF dh!=200 AND gpws>0 THEN
                            PLAY "-200.wav"           ;mode6
                        ELSEIF gpws>0 THEN
                            PLAY "-min.wav"
                        ENDIF
                    ELSEIF INRANGE(ra,450,510) AND gpws>0 THEN
                        PLAY "-500.wav"               ;mode6
                    ENDIF                             
                    lastcall=((ra+90) IDIV 100)*100   
                ELSEIF ra<610 THEN
                    GOSUB gpws_2
                    GOSUB ap_trim
                    GOTO gpws_1
                ENDIF                                 
            ELSEIF vs<-2.5*ra-1000 AND gpws>1 THEN    ;ra>1000ft
                IF vs<-5.2*ra+2800 THEN               
                    PLAY "-terrnpu.wav"               ;mode2
                ELSE
                    PLAY "-snkrtpu.wav"               ;mode1
                ENDIF                      
                WAIT 2              
                warning=1
                GOTO gpws_1
            ENDIF
            GOSUB gpws_2
        ELSEIF ra<245 AND (GEAR_3_POSITION=0 OR FLAPS_LEFT_POSITION<20000) THEN  
            ra1=1  ;mode3 arm (take-off / go-around<245ft & gear/flaps raised)
        ENDIF
    ENDIF
    GOSUB alt_alert
    IF warning=1 THEN
        warning=0
        GOTO gpws_1
    ELSEIF OVERSPEED_WARNING THEN
        PLAY "-clacker.wav"
        WAIT 1
        GOTO gpws_1
    ELSEIF AUTOPILOT_ALTITUDE_HOLD THEN
        GOSUB alt_alert
    ENDIF
    GOSUB ap_trim
RETURN

gpws_2:
    IF vs<-1.6*ra-1000 AND gpws>1 THEN                ;ra<2450ft
        PLAY "-snkrate.wav"                           ;mode1
        warning=1
        WAIT 2
    ELSEIF ra1>0 THEN                                 ;mode3
        IF ra>1333 OR (ra>700 AND VELOCITY_INDICATED<190) OR (GEAR_3_POSITION=32767 AND FLAPS_LEFT_POSITION>20000) THEN
            ra1=0                                     ;mode3 disarm
        ELSEIF ra>ra1 THEN
            ra1=ra
        ELSEIF ra1-ra>ra/10 AND gpws>1 THEN
            PLAY "-dontsnk.wav"
            warning=1
            WAIT 2
        ENDIF 
    ELSEIF VOR_1_GS_AVAIL AND ra<1500 THEN            ;mode5
        dist=GROUND_DISTANCE(VOR_1_LAT,VOR_1_LON)     ;distance to loc antenna
        ra=PLANE_ALT-VOR_1_ALT                        ;alt above loc antenna
        IF gs<5 THEN                                  ;if not 5x on g/p: reset
            IF NOT INRANGE((ra0-ra)/(dist0-dist),29.1*xVOR_1_GLIDE_SLOPE,35.6*xVOR_1_GLIDE_SLOPE) THEN
                gs=0                                  ;glide path 2.7-3.3
                dist0=dist
                ra0=ra
                RETURN
            ELSEIF gs=4 THEN
                GOSUB gs_crs
                IF INRANGE(crs,-1,1) AND GLIDE_SLOPE(VOR_1_LAT,VOR_1_LON)<xVOR_1_GLIDE_SLOPE AND gpws=2 THEN
                    PLAY "-ss2.WAV"
                    PLAY "-ss2.WAV"                   ;mode5 armed
                    loc=VOR_1_LOCALIZER
                ELSE
                    ra0=0                             ;g/p not valid
                ENDIF
            ENDIF
            gs=gs+1
        ELSEIF ra>ra0 OR loc!=VOR_1_LOCALIZER THEN
            gs=0
            ra0=0
        ELSEIF ra<(ra0*.278-(dist0-dist)*27)*xVOR_1_GLIDE_SLOPE AND ra<305 THEN
            GOSUB gs_crs
            IF INRANGE(crs,-30,30) AND dist<10 AND gpws=2 THEN
                PLAY "-gs.wav"                        ;0.5degree below g/p
                warning=1
                WAIT 1
            ENDIF
        ENDIF
    ELSE                                              
        ra0=0                                         ;mode5 reset
    ENDIF
RETURN
gs_crs:
    crs=VOR_1_LOCALIZER-VOR_1_RADIAL+180
    IF crs>180 THEN                                
        crs=crs-360                               
    ENDIF
RETURN

alt_alert:
    x0=AUTOPILOT_ALTITUDE-PLANE_ALT
    IF alt0=AUTOPILOT_ALTITUDE THEN      
        IF INRANGE(x0,-230,230) THEN                  ;within 750ft
            IF INRANGE(x0,-75,75) THEN                ;within 250ft
                aa=0
            ELSEIF aa=0 THEN
                GOSUB alt_arm
                GOSUB alt_alert2
            ENDIF
        ELSEIF aa>0 THEN
            IF aa>1 THEN                              ;exit alert
                GOSUB alt_alert2
            ENDIF
            aa=0
        ENDIF
    ELSEIF alt0=-AUTOPILOT_ALTITUDE THEN
        alt0=-alt0
        IF INRANGE(x0,-230,230) THEN                  ;within 750ft
            GOSUB alt_arm                             ;no alert
        ELSE
            aa=0
        ENDIF
    ELSE
        alt0=-AUTOPILOT_ALTITUDE                      ;delay
    ENDIF
RETURN

alt_alert2:
    IF GEAR_3_POSITION=0 AND FLAPS_LEFT_POSITION<20000 THEN
        PLAY "-altalrt.wav"
    ENDIF
RETURN

alt_arm:
    IF x0/vs<0 THEN                                   ;exit from 250ft
        aa=1                                           
    ELSE                                              ;entry within 750ft:
        aa=2                                          ;      arm exit warn
    ENDIF
RETURN

ap_trim:
    IF ap=1 AND NOT INRANGE(trim-ELEVATOR_TRIM_POSITION,-1248,1248) THEN
        PLAY "-trim2.wav"
        trim=ELEVATOR_TRIM_POSITION
    ENDIF
RETURN

apdisc_trim:                                          ;ap disconnect / trim
    IF AUTOPILOT_MASTER=0 THEN
        IF ap=1 THEN
            PLAY "-apdisco.wav"
            trim=ELEVATOR_TRIM_POSITION
            ap=0
        ELSEIF trim!=ELEVATOR_TRIM_POSITION THEN
            IF INRANGE(trim-ELEVATOR_TRIM_POSITION,-32,32) THEN
                PLAY "-trim1.wav"
            ELSE
                PLAY "-trim2.wav"
            ENDIF
            trim=ELEVATOR_TRIM_POSITION
        ENDIF
    ELSE
        ap=1
    ENDIF
RETURN

flare:                                                ;mode6 ra<60ft
    ON (45-ra) IDIV 10 GOTO forty,thirty,twenty,ten,zero
    WHILE ra>54
        IF ra>75 OR ON_GROUND THEN
            GOTO flare_end
        ENDIF
        GOSUB apdisc_trim
        ra=MTOF(PLANE_ALT-GROUND_ALTITUDE)-gear
    ENDWHILE
    IF dh!=50 THEN
        PLAY "-50.wav"
    ELSE
        PLAY "-min.wav"
    ENDIF
    forty:
    WHILE ra>44
        IF ra>70 OR ON_GROUND THEN
            GOTO flare_end
        ENDIF
        GOSUB apdisc_trim
        ra=MTOF(PLANE_ALT-GROUND_ALTITUDE)-gear
    ENDWHILE
    PLAY "-40.wav"
    thirty:
    WHILE ra>34
        IF ra>60 OR ON_GROUND THEN
            GOTO flare_end
        ENDIF
        GOSUB apdisc_trim
        ra=MTOF(PLANE_ALT-GROUND_ALTITUDE)-gear
    ENDWHILE
    PLAY "-30.wav"
    twenty:
    WHILE ra>23
        IF ra>50 OR ON_GROUND THEN
            GOTO flare_end
        ENDIF
        GOSUB apdisc_trim
        ra=MTOF(PLANE_ALT-GROUND_ALTITUDE)-gear
    ENDWHILE
    IF dh!=20 THEN
        PLAY "-20.wav"
    ELSE
        PLAY "-min.wav"
    ENDIF
    ten:
    WHILE ra>13
        IF ra>40 OR ON_GROUND THEN
            GOTO flare_end
        ENDIF
        GOSUB apdisc_trim
        ra=MTOF(PLANE_ALT-GROUND_ALTITUDE)-gear
    ENDWHILE
    PLAY "-10.wav"
    zero:
    WHILE NOT ON_GROUND
        IF NOT INRANGE(ra,-30,30) THEN
            GOTO flare_end
        ENDIF
        GOSUB apdisc_trim
        ra=MTOF(PLANE_ALT-GROUND_ALTITUDE)-gear
    ENDWHILE
    time=0
    time0=SECOND
    WHILE time<6 AND ra<30
        GOSUB apdisc_trim
        GOSUB on_gnd
        GOSUB time
        ra=MTOF(PLANE_ALT-GROUND_ALTITUDE)-gear
    ENDWHILE
flare_end:
    ias0=0
    lastcall=0
    trim=ELEVATOR_TRIM_POSITION
GOTO gpws_1

on_gnd:                                ;RA correction on gnd of gear height
    IF INRANGE(PLANE_ALT-GROUND_ALTITUDE,0,9) AND ON_GROUND THEN    
         gear=MTOF(PLANE_ALT-GROUND_ALTITUDE)          
    ENDIF
RETURN

stickshaker:
    PLAY "-stkshkr.wav"
    WAIT .7
    warning=1
RETURN

time:
    time=SECOND-time0
    IF time<0 THEN                                  
        time=time+60
    ENDIF
RETURN

dh:
    PLAY "-ss1.wav"
    PRINT
    IF dh=0 THEN
        PRINT "DH 200"
        dh=200
    ELSEIF dh=200 THEN
        PRINT "DH 100"
        dh=100
    ELSEIF dh=100 THEN
        PRINT "DH 50"
        dh=50
    ELSEIF dh=50 THEN
        PRINT "DH 20"
        dh=20
    ELSE
        PRINT "DH OFF"
        dh=0
    ENDIF
    WAIT 0,KEYPRESS
RETURN

setup:
    gpws=gpws+1
    IF gpws>5 THEN
        gpws=0
        ra0=0
        ra1=0
    ENDIF
    PLAY "-ss1.wav"
    PRINT
    ON gpws GOSUB gpws0,gpws1,gpws2,gpws3,gpws4,gpws5
RETURN

gpws0:
    PRINT "GPWS OFF"
RETURN
gpws1:
    PRINT "GPWS ALT"
RETURN
gpws2:
    PRINT "GPWS ON"
RETURN
gpws3:
    PRINT "GPWS g/s-inhibit"
RETURN
gpws4:
    PRINT "GPWS flap-inhibit"
RETURN
gpws5:
    PRINT "GPWS gear-inhibit"
RETURN
