Script:Files:script/misc/parachute.script

From Mod Wiki
object parachute : parachute_base {
    void            preinit();
    void            init();
    void            destroy();
    void            syncFields();

    void            Idle();
    void            FindWeapon();
    void            RestoreWeapon();

    void            SetDeployStart( float t );

    void            OnOwnerChanged();
    void            OnDeployStartChanged();

    entity            owner;
    void            vSetOwner( entity o ) { owner = o; OnOwnerChanged(); }
    entity            vGetOwner() { return owner; }

    void            vCancel();
    void            Cancel();

    float            openDelay;
    void            vSetDelay( float time ) { openDelay = time; }

    boolean            forceStayOpen;
    void            vForceStayOpen( boolean force ) { forceStayOpen = force; }

    float            deployStart;
    boolean            collapsing;
    string            previousWeapon;

    boolean            weaponRestored;
}

void parachute::preinit() {
    deployStart = -1;
    hide();
}

void parachute::syncFields() {
    syncBroadcast( "owner" );
    syncBroadcast( "collapsing" );
    syncBroadcast( "deployStart" );

    syncCallback( "owner", "OnOwnerChanged" );
    syncCallback( "deployStart", "OnDeployStartChanged" );
}

void parachute::OnOwnerChanged() {
    setOwner( owner );
    player playerOwner = owner;
    if ( playerOwner != $null_entity ) {
        playerOwner.binAdd( self );
    }
}

void parachute::OnDeployStartChanged() {
    setDeployStart( deployStart );
}

void parachute::init() {
    setContents( 0 );
    setClipmask( 0 );

    while( owner == $null_entity ) {
        sys.waitFrame();
    }

    setState( "Idle" );
}

void parachute::destroy() {
    player playerOwner = owner;
    if ( playerOwner != $null_entity ) {
        playerOwner.binRemove( self );
    }

    RestoreWeapon();
}

void parachute::SetDeployStart( float t ) {
    deployStart = t;
    setDeployStart( t );
}

void parachute::FindWeapon() {
    if ( !sys.isClient() ) {
        previousWeapon = owner.getCurrentWeapon();
    }
}

void parachute::RestoreWeapon() {
    if ( weaponRestored ) {
        return;
    }
    weaponRestored = true;

    if ( !sys.isClient() ) {
        player playerOwner = owner;
        if ( playerOwner != $null_entity ) {
            if ( previousWeapon != "" && previousWeapon != "inventory/tools/gdf_parachute" ) {
                playerOwner.setWeapon( previousWeapon, 0 );
            } else {
                playerOwner.selectBestWeapon( false );
            }
        }
    }
}


void parachute::Idle() {
    player playerOwner = owner;
    if ( playerOwner != $null_entity ) {        
        // change the owner's weapon
        if ( openDelay > 0.0f ) {
            playerOwner.setWeapon( "inventory/tools/gdf_parachute", 1 );
        } else {
            // find out what weapon the player has
            FindWeapon();

            playerOwner.setWeapon( "inventory/tools/gdf_parachute", 0 );
        }
    }


    sys.wait( openDelay );

    playAnim( ANIMCHANNEL_ALL, "deploy" );

    startSound( "snd_start", SND_VEHICLE_IDLE );

    entity p = owner;
    vector origin;
    vector angles = g_vectorZero;
    if ( playerOwner != $null_entity ) {
        origin = playerOwner.getWorldOrigin() + '0 0 80';
        angles = owner.getViewAngles();
        angles_x = 0;
        angles_z = 0;
    } else {
        origin =  sys.toWorldSpace( p.getCenterOfMass(), p );
        angles = owner.getAngles();
    }
    setAngles( angles );

    vector offset = owner.getVectorKey( "parachute_offset" );
    offset = sys.rotateVecByAngles( offset, angles );
    origin += offset;

    setOrigin( origin );
    bind( p );
    show();

    if ( !sys.isClient() ) {
        SetDeployStart( sys.getTime() );
    }

    while ( 1 ) {
        // HACK - force change to parachute
        if ( playerOwner != $null_entity ) {
            string weapon = playerOwner.getCurrentWeapon();
            if ( weapon != "inventory/tools/gdf_parachute" ) {
                // change the owner's weapon
                if ( openDelay > 0.0f ) {
                    playerOwner.setWeapon( "inventory/tools/gdf_parachute", 1 );
                } else {
                    playerOwner.setWeapon( "inventory/tools/gdf_parachute", 0 );
                }
            }
        }

        if ( !isAnimating() ) {
            playCycle( ANIMCHANNEL_ALL, "idle_open" );
        }

        if ( !sys.isClient() ) {
            if ( owner == $null_entity ) {
                break;
            }

            if ( playerOwner != $null_entity ) {
                if ( playerOwner.getProxyEntity() != $null_entity ) {
                    break;
                }
            }

            if ( owner.getHealth() <= 0 ) {
                break;
            }

            if ( !forceStayOpen ) {
                if ( playerOwner == $null_entity ) {
                    if ( isMovingTooSlow() ) {
                        break;
                    }
                } else {
                    if ( playerOwner.AI_ONLADDER || playerOwner.AI_INWATER || playerOwner.AI_ONGROUND ) {
                        break;
                    }
                }
            }
        }

        if ( collapsing ) {
            break;
        }

        if ( playerOwner == sys.getLocalViewPlayer() && !pm_thirdperson.getBoolValue() ) {
            hide();
        } else {
            show();
        }

        sys.waitFrame();
    }

    vCancel();
}

void parachute::vCancel() {

    player playerOwner = owner;
    if ( playerOwner != $null_entity ) {
        playerOwner.binRemove( self );
    }

    if ( !sys.isClient() ) {
        SetDeployStart( -1 );
    }

    // collapse into a crumpled heap
    collapsing = true;

    startSound( "snd_stop", SND_VEHICLE_IDLE );

    playAnim( ANIMCHANNEL_ALL, "compact" );
    RestoreWeapon();

    setState( "Cancel" );
}

void parachute::Cancel() {
    waitUntil( !isAnimating() );

    if ( !sys.isClient() ) {
        remove();
    }
}


/*
===============================================================================

Parachute cockpit

===============================================================================
*/

object tool_parachute : weapon_base {
    void        init();
    void        Idle();
};

void tool_parachute::init() {
    weaponState( "Raise", 0 );
}

void tool_parachute::Idle() {
    weaponReady();
    enableClamp( '0 0 0' );

    playCycle( ANIMCHANNEL_ALL, "idle" );

    sys.wait( 0.2f );
    while ( true ) {
        if ( WEAPON_LOWERWEAPON ) {
            weaponState( "Lower", 4 );
        }

        sys.waitFrame();
    }
}


/*
===============================================================================

Strogg "Parachute"

===============================================================================
*/
object strogg_parachute : parachute_base {
    void            preinit();
    void            init();
    void            destroy();
    void            syncFields();

    void            Idle();

    void            CleanUp();
    void            OnOwnerChanged();

    entity            owner;
    void            vSetOwner( entity o ) { owner = o; OnOwnerChanged(); }

    void            vCancel();
    void            Cancel();

    float            openDelay;
    void            vSetDelay( float time ) { openDelay = time; }

    boolean            collapsing;
    boolean            cleanupApplied;
}

void strogg_parachute::preinit() {
    collapsing = false;
    openDelay = 0;
}

void strogg_parachute::syncFields() {
    syncBroadcast( "owner" );
    syncCallback( "owner", "OnOwnerChanged" );

    syncBroadcast( "collapsing" );
}

void strogg_parachute::init() {
    while( owner == $null_entity ) {
        sys.waitFrame();
    }

    setState( "Idle" );
}

void strogg_parachute::destroy() {
    CleanUp();
}

void strogg_parachute::CleanUp() {
    if ( cleanupApplied ) {
        return;
    }

    player playerOwner = owner;
    if ( playerOwner != $null_entity ) {
        playerOwner.binRemove( self );
        playerOwner.disableFallingDamage( false );
    }

    cleanupApplied = true;
}

void strogg_parachute::OnOwnerChanged() {
    player playerOwner = owner;
    if ( playerOwner != $null_entity ) {
        playerOwner.binAdd( self );
        playerOwner.disableFallingDamage( true );
    }
}

void strogg_parachute::Idle() {
    player playerOwner = owner;

    if ( openDelay > 0.f ) {
        if ( playerOwner != $null_entity ) {
            playerOwner.selectBestWeapon( true );
        }
        sys.wait( openDelay );
    }

    setContents( 0 );

    if ( owner != sys.getLocalViewPlayer() || pm_thirdperson.getBoolValue() ) {
        playEffect( "fx_fly", "", 1 );
    }

    startSound( "snd_start", SND_VEHICLE_IDLE );

    float deployTime = 1.0f;

    // Doesn't really need to do this I guess, but if they use a model it will work
    entity p = owner;
    vector origin;
    vector angles = g_vectorZero;
    if ( owner != $null_entity ) {
        origin = playerOwner.getWorldOrigin() + '0 0 80';
        angles = owner.getViewAngles();
        angles_x = 0;
        angles_z = 0;
    } else {
        origin =  sys.toWorldSpace( p.getCenterOfMass(), p );
        angles = owner.getAngles();
    }
    setAngles( angles );

    vector offset = owner.getVectorKey( "parachute_offset" );
    offset = sys.rotateVecByAngles( offset, angles );
    origin += offset;

    setOrigin( origin );
    bind( p );

    float maxSpeed = getFloatKey( "min_speed" );

    float tooSlowTime = 0;

    float deployStart = sys.getTime();
    while ( 1 ) {
        if ( !sys.isClient() ) {
            if ( owner == $null_entity ) {
                break;
            }
            if ( playerOwner != $null_entity ) {
                if ( playerOwner.getProxyEntity() != $null_entity ) {
                    break;
                }
            }
            if ( owner.getHealth() <= 0 ) {
                break;
            }
        }

        if ( collapsing ) {
            break;
        }

        if ( owner == sys.getLocalViewPlayer() && !pm_thirdperson.getBoolValue() ) {
            hide();
        } else {
            show();
        }

        // convert velocity to metric
        vector velocity = InchesToMetres( p.getLinearVelocity() );
        float speedSquared = sys.vecLengthSquared( velocity );

        if ( velocity_z > -maxSpeed ) {
            if ( !sys.isClient() ) {
                if ( !tooSlowTime ) {
                    tooSlowTime = sys.getTime();
                } else {
                    if ( sys.getTime() - tooSlowTime > 0.1f ) {
                        break;
                    }
                }
            }
        }

        sys.waitFrame();
    }

    vCancel();
}

void strogg_parachute::vCancel() {
    CleanUp();

    // collapse into a crumpled heap
    collapsing = true;

    startSound( "snd_stop", SND_VEHICLE_IDLE );

    stopEffect( "fx_fly" );

    setState( "Cancel" );
}

void strogg_parachute::Cancel() {
    sys.wait( 1.0f );

    if ( !sys.isClient() ) {
        remove();
    }
}