var reset_all_damage = func
{
    setprop("/engines/active-engine/crash-engine", 0);
    setprop("/engines/active-engine/kill-engine", 0);

    # Landing gear
    setprop("/fdm/jsbsim/gear/unit[0]/broken", 0);
    setprop("/fdm/jsbsim/gear/unit[1]/broken", 0);
    setprop("/fdm/jsbsim/gear/unit[2]/broken", 0);

    setprop("/fdm/jsbsim/gear/unit[19]/broken", 0);
    setprop("/fdm/jsbsim/gear/unit[20]/broken", 0);
    setprop("/fdm/jsbsim/gear/unit[21]/broken", 0);
    setprop("/fdm/jsbsim/gear/unit[22]/broken", 0);

    if (getprop("/fdm/jsbsim/bushkit")==3) {
        if (getprop("/fdm/jsbsim/hydro/active-norm")) {
            setprop("controls/gear/gear-down-command", 0);
            setprop("/fdm/jsbsim/gear/gear-pos-norm", 0);
        } else {
            setprop("controls/gear/gear-down-command", 1);
            setprop("/fdm/jsbsim/gear/gear-pos-norm", 1);
        }
    }

    # Wings
    setprop("/fdm/jsbsim/wing-damage/left-wing", 0);
    setprop("/fdm/jsbsim/wing-damage/right-wing", 0);

    # Collapsed wings
    setprop("/fdm/jsbsim/crash", 0);

    # Pontoons
    setprop("/fdm/jsbsim/pontoon-damage/left-pontoon", 0);
    setprop("/fdm/jsbsim/pontoon-damage/right-pontoon", 0);
    
    if (getprop("fdm/jsbsim/orientation/upside-down")) {
        setprop("/orientation/pitch-deg", 0);
        setprop("/orientation/roll-deg", 0);
    }
    
     # Repair engine damage
    setprop("/fdm/jsbsim/engine/damage-level", 0);
}

var repair_damage = func {
    set_bushkit(getprop("/fdm/jsbsim/bushkit"));
};

var killengine = func
{
    if (getprop("/fdm/jsbsim/settings/damage"))
        setprop("/engines/active-engine/crash-engine", 1);
}

# Hydro system loop

var anchor_pos = geo.Coord.new();
var aircraft_pos = geo.Coord.new();
var anchor_dist = 0.0;

var heading_diff = 0.0;
var wind_from_heading  = 0.0;
var aircraft_heading  = 0.0;
var wind_speed = 0.0;
var forward_speed = 0.0;

var poll_hydro = func
{
    var engine_rpm = getprop("fdm/jsbsim/propulsion/engine/engine-rpm");
    var hydro_active_norm = getprop("/fdm/jsbsim/hydro/active-norm");
    var ground_splash_norm = getprop("/environment/aircraft-effects/ground-splash-norm");

    # Use engine RPM and speed to control ground splash if on the water
    # and below 2 meter AGL
    if (getprop("position/altitude-agl-m") < 2 and hydro_active_norm > 0) {
        var groundspeed_half_pc = 0.005 * getprop("/velocities/groundspeed-kt");
        var engine_rpm_almost_nothing = 0.005 * 0.065 * engine_rpm;

        var splash_norm = std.max(engine_rpm_almost_nothing, groundspeed_half_pc);
        setprop("/environment/aircraft-effects/ground-splash-norm", splash_norm);
    }
    elsif (ground_splash_norm > 0)
        setprop("/environment/aircraft-effects/ground-splash-norm", ground_splash_norm - 0.005);

    if (getprop("/controls/mooring/anchor") and !getprop("fdm/jsbsim/mooring/mooring-connected")) {
        if (getprop("/fdm/jsbsim/mooring/anchor-length") == 0) {
            wind_from_heading = getprop("/environment/wind-from-heading-deg");
            aircraft_heading = getprop("/orientation/heading-deg");
            heading_diff = math.min(math.abs(aircraft_heading-wind_from_heading),math.abs(360-aircraft_heading+wind_from_heading),math.abs(360-wind_from_heading+aircraft_heading));
            wind_speed = getprop("/environment/windsock/wind-speed-kt");
            forward_speed = getprop("/fdm/jsbsim/hydro/vbx-fps");
            if (heading_diff > 85) {
                gui.popupTip("Face into the wind to set anchor", 5);
                setprop("/controls/mooring/anchor", 0);
                return;
            } elsif (wind_speed > 40) {
                gui.popupTip("Wind too high to anchor", 5);
                setprop("/controls/mooring/anchor", 0);
                return;
            } elsif (forward_speed > 7) {
                gui.popupTip("Can't anchor while moving forward", 5);
                setprop("/controls/mooring/anchor", 0);
                return;
            } elsif (getprop("/engines/active-engine/running")) {
                gui.popupTip("Can't anchor with engine running", 5);
                setprop("/controls/mooring/anchor", 0);
                return;
            } else {
                anchor_pos.set_latlon(getprop("/fdm/jsbsim/mooring/anchor-lat"), getprop("/fdm/jsbsim/mooring/anchor-lon"));
                setprop("fdm/jsbsim/mooring/latitude-deg", anchor_pos.lat());
                setprop("fdm/jsbsim/mooring/longitude-deg", anchor_pos.lon());
                setprop("fdm/jsbsim/mooring/altitude-ft", getprop("/position/ground-elev-ft"));
                anchor_dist = 0.0;
                setprop("/fdm/jsbsim/mooring/anchor-length", 1);
                setprop("/sim/anchorbuoy/enable", 1);
                setprop("fdm/jsbsim/mooring/mooring-connected", 1);
            }
        }
    }

    if (getprop("fdm/jsbsim/mooring/mooring-connected")) {
        aircraft_pos = geo.aircraft_position();
        anchor_dist = aircraft_pos.distance_to(anchor_pos);
        aircraft_heading = getprop("/orientation/heading-deg");
        var bearing = aircraft_pos.course_to(anchor_pos);
        var rel_bearing = (aircraft_heading - 180.0) - bearing;
        setprop("fdm/jsbsim/mooring/rope-yaw", rel_bearing);

        if (anchor_dist < (getprop("/fdm/jsbsim/mooring/rope-length-ft")*0.3048)-1) {
            setprop("fdm/jsbsim/mooring/rope-visible", 0);
        } else {
            setprop("fdm/jsbsim/mooring/rope-visible", 1);
        }
    }
}

# Duration in which no damage will occur. Assumes the aircraft has
# stabilized within this duration.
var bushkit_change_timeout = 8.0;

var physics_loop = func
{
    if (getprop("/sim/freeze/replay-state")) {
        return;
    }
    c172p.particle_effects_loop();
    if (getprop("/fdm/jsbsim/bushkit") == 3 or getprop("/fdm/jsbsim/bushkit") == 4)
        poll_hydro();
    if (getprop("/fdm/jsbsim/contact/unit[9]/WOW") or getprop("/fdm/jsbsim/contact/unit[10]/WOW"))
        killengine();
}

var set_bushkit = func (bushkit) {
    setprop("/fdm/jsbsim/damage/repairing", 1);
    reset_all_damage();
    bushkit_changed_timer.restart(bushkit_change_timeout);
};

# This timer object is used to enable damage again a short time after
# changing to the last bush kit option.
var bushkit_changed_timer = maketimer(bushkit_change_timeout, func {
    setprop("/fdm/jsbsim/damage/repairing", 0);
    setprop("/fdm/jsbsim/damage/traversing", 0);
});
bushkit_changed_timer.singleShot = 1;

# Update the 3D model when changing bush kit
setlistener("/fdm/jsbsim/bushkit", func (n) {
    set_bushkit(n.getValue());
}, 1, 0);

setlistener("/fdm/jsbsim/crash", func (n) {
    if (n.getBoolValue() and getprop("position/altitude-agl-m") < 10) {
        killengine();
    }
}, 0, 0);

setlistener("/fdm/jsbsim/wing-damage/left-wing", func (n) {
    var damage = n.getValue();
    var altitude = getprop("position/altitude-agl-m");

    if (damage < 1.0 and damage > 0.0 and altitude < 10.0)
        killengine();
}, 0, 0);

setlistener("/fdm/jsbsim/wing-damage/right-wing", func (n) {
    var damage = n.getValue();
    var altitude = getprop("position/altitude-agl-m");

    if (damage < 1.0 and damage > 0.0 and altitude < 10.0)
        killengine();
}, 0, 0);

setlistener("controls/gear/gear-down-command", func (n) {
    if (getprop("/fdm/jsbsim/pontoon-damage/left-pontoon")==0 and getprop("/fdm/jsbsim/pontoon-damage/right-pontoon")==0) {
        setprop("/fdm/jsbsim/damage/traversing", 1);
        bushkit_changed_timer.restart(bushkit_change_timeout);
    }
}, 0, 0);