Script:Files:script/deployables/turret.script

From Mod Wiki
object deployable_turret : deployable_base {
    void    preinit();
    void    init();
    void    destroy();

    // states
    float    OnUsed( entity p, float distance );

    void    OnDisabled();
    void    OnReEnabled();

    void    OnBeginAttack();
    void    OnEndAttack();

    boolean    InRange( vector targetPos );
    boolean    InFiringRange( vector targetPos );

    void    KillAttackThread();
    void    AttackThread();

    void    vCheckProficiency();

    boolean    TargetIsValid( entity targetEnt ) { return false; }

    void    FireMissile();

    void    FreeArcIcon();
    void    SetupFiringArc();

    void    vOnDeploy();

    float GetTurretMaxRange();
    float GetTurretMinRange();

    boolean    TraceCheck( entity other );

    void    OnEnter( entity user );
    void    OnExit( entity user );

    void    OnKilled( entity inflictor, entity attacker, float damage, vector dir, float location );

    float    OnValidateTarget();

    float    OnUpdateCrosshairInfo( entity p );

    void    CreateDestroyThread();

    void    UpdateCharge() { }

    float    vGetFiringStatus( object traceObject );

    float    numTracerJoints;

    float    minRange;
    float    maxRange;
    float    firingRange;

    float    angleRange;

    float    jointBarrel;

    float    projectileIndex;

    float    projectileSpeed;
    float    spread;
    float    fireRate;
    float    reFire;

    float    commandmapVisibleArcHandle;

    float    checkMask;

    vector    traceCheckOffset;

    boolean    playingBrassSound;

    entity    myUser;

    // overheating/power bar stuff
    boolean    CanFire() { return true; }
    void    Fired() { }

    boolean attacking;
};

void deployable_turret::preinit() {
    projectileIndex        = GetEntityDef( getKey( "def_projectile" ) );

    projectileSpeed        = getFloatKey( "missile_velocity" );

    minRange            = MetresToInches( getFloatKey( "range_min" ) );
    maxRange            = MetresToInches( getFloatKey( "range_max" ) );
    firingRange            = MetresToInches( getFloatKeyWithDefault( "range_firing", InchesToMetres( maxRange ) ) );

    fireRate            = getFloatKey( "fireRate" );
    spread                = getFloatKey( "spread" );
    reFire                = 0;

    jointBarrel            = getJointHandle( getKey( "joint_barrel" ) );


    numTracerJoints        = getFloatKey( "num_tracerjoints" );

    checkMask            = MASK_SHOT_RENDERMODEL | MASK_SHOT_BOUNDINGBOX;

    vector mins            = getMins();
    vector maxs            = getMaxs();

    traceCheckOffset_z = mins_z + ( ( maxs_z - mins_z ) * ( getFloatKeyWithDefault( "trace_offset_pct", 75.f ) * 0.01f ) );

    commandmapVisibleArcHandle    = -1;
}

void deployable_turret::FreeArcIcon() {
    if ( commandmapVisibleArcHandle != -1 ) {
        sys.freeCMIcon( self, commandmapVisibleArcHandle );
        commandmapVisibleArcHandle = -1;
    }
}

void deployable_turret::SetupFiringArc() {
    FreeArcIcon();

    angleRange            = getFloatKey( "angle_range" );
    if ( angleRange <= 0 ) {
        angleRange = 135;
    }

    vector ang = getAngles();

    commandmapVisibleArcHandle = sys.allocCMIcon( self, 100 );
    sys.setCMIconAngle( commandmapVisibleArcHandle, -ang_y );
    sys.setCMIconSizeMode( commandmapVisibleArcHandle, SM_WORLD );
    sys.setCMIconColor( commandmapVisibleArcHandle, g_colorRed, 0.25f );
    sys.setCMIconSides( commandmapVisibleArcHandle, 24 );
    sys.setCMIconDrawMode( commandmapVisibleArcHandle, DM_ARC );
    sys.setCMIconMaterial( commandmapVisibleArcHandle, GetMaterial( "_white_depth" ) );
    sys.setCMIconUnknownMaterial( commandmapVisibleArcHandle, GetMaterial( "_white_depth" ) );
    sys.setCMIconSize( commandmapVisibleArcHandle, maxRange );
    sys.setCMIconUnknownSize( commandmapVisibleArcHandle, maxRange );
    sys.setCMIconFlag( commandmapVisibleArcHandle, CMF_ENEMYONLY | CMF_ONLYSHOWKNOWN );
    sys.setCMIconArcAngle( commandmapVisibleArcHandle, angleRange );
    sys.setCMIconFlag( commandmapVisibleArcHandle, CMF_FOLLOWROTATION );

    angleRange            = sys.cos( angleRange * 0.5f );
}

void deployable_turret::vOnDeploy() {
    SetupFiringArc();

    thread DoDeploy();
}

void deployable_turret::init() {
    startSound( "snd_turret_yaw", SND_DEPLOYABLE_YAW );
    startSound( "snd_turret_pitch", SND_DEPLOYABLE_PITCH );
    fadeSound( SND_DEPLOYABLE_YAW, -60.f, 0.f );
    fadeSound( SND_DEPLOYABLE_PITCH, -60.f, 0.f );
}

void deployable_turret::destroy() {
    FreeArcIcon();
    KillAttackThread();
}

boolean deployable_turret::TraceCheck( entity other ) {
    vector targetPos = getTargetPosition( other );

    sys.tracePoint( getWorldOrigin() + traceCheckOffset, targetPos, checkMask, self );
    if ( sys.getTraceFraction() == 1.f ) {
        return true;
    }
    if ( sys.getTraceEntity() != other ) {
        return false;
    }
    return true;
}

void deployable_turret::KillAttackThread() {
    sys.killThread( "AttackThread_" + getName() );
}

void deployable_turret::AttackThread() {
    float delay = reFire - sys.getTime();
    if ( delay > 0 ) {
        sys.wait( delay );
    }

    while ( true ) {
        if ( CanFire() ) {
            FireMissile();
        }

        delay = fireRate;
        reFire = sys.getTime() + delay;
        sys.wait( delay );
    }
}

// ==========================================
// Utility Funcs
// ==========================================

void deployable_turret::FireMissile() {
    entity target;
    entity controller = getBoundPlayer( 0 );
    if ( controller != $null_entity ) {
        target = controller.getEnemy();
    } else {
        if ( owner != $null_entity ) {
            controller = owner;
        } else {
            controller = self;
        }
        target = getEnemy();
    }

    launchMissileSimple( controller, self, target, projectileIndex, -1, spread, getJointPos( jointBarrel ), getJointAxis( jointBarrel, 0 ) * projectileSpeed );
    playJointEffect( "fx_fire", jointBarrel, 0 );

    float muzzleJoint;
    if ( playTracerFX ) {
        if( numTracerJoints > 1 ) {
            muzzleJoint = int( sys.random( numTracerJoints ) ) + 1;
        } else {
            muzzleJoint = numTracerJoints;
        }
        playEffect( "fx_tracer", getKey( "joint_tracer" + muzzleJoint ), 0 );
    }
    playEffect( "fx_muzzle", getKey( "joint_tracer" + muzzleJoint ), 0 );

    Fired();
}

float deployable_turret::OnValidateTarget() {
    entity target = getEnemy();

    if ( !TargetIsValid( target ) ) {
        return 0.f;
    }

    if ( !InRange( target.getWorldOrigin() ) ) {
        return 0.f;
    }

    return 1.f;
}

float deployable_turret::OnUpdateCrosshairInfo( entity p ) {
    if ( sys.getLocalPlayer() == $null_entity ) {
        return 1.f;
    }

    float allegiance = getEntityAllegiance( p );
    vector color = GetAllegianceColor( allegiance );
    float distance = chGetDistance();
    float range = InchesToMetres( distance );
    float health = getHealth();

    chSetNumLines( 0 );
    float index;

    // define length of health bar
    float healthBarLength;
    float maxHealth = getMaxHealth();
    if ( maxHealth >= 2000.f ) {
        healthBarLength = 150.f;
    } else if ( maxHealth >= 1000.f ) {
        healthBarLength = 100.f;
    } else {
        healthBarLength = 75.f;
    }

    // see if theres a valid action to perform
    float code = GetActivateCode( p, distance );
    if ( code != AK_NONE ) {
        index = chAddLine();
        chSetLineMaterial( index, p.vGetActionIcon( code ) );
        chSetLineType( index, CI_IMAGE );
        chSetLineSize( index, 64, 64 );
        chSetLineColor( index, g_colorWhite, 0.9f );

        if ( p.isLocalPlayer() ) {
            if ( !p.isToolTipPlaying() ) {
                if ( sys.getTime() - p.getCrosshairStartTime() > 1.f ) {
                    if ( p.getCurrentWeapon() != p.vGetActionItem( code ) ) {
                        if ( code == AK_HACK ) {
                            p.sendToolTip( useMeToolTip1_Hack );
                        }
                    } else {
                        if ( code == AK_HACK ) {
                            p.sendToolTip( useMeToolTip2_Hack );
                        }
                    }
                }
            }
        }        
    }

    vector disabledColor;
    if ( allegiance == TA_ENEMY || allegiance == TA_FRIEND ) {
        disabledColor = g_colorYellow;
    } else {
        disabledColor = color;
    }

    index = chAddLine();
    chSetLineTextIndex( index, objectTitle );
    chSetLineColor( index, color, 1.f );
    chSetLineType( index, CI_TEXT );
    chSetLineSize( index, 0, 0 );

    if ( health <= 0 ) {
        if ( maxHealth != 0.f ) {
            index = chAddLine();
            chSetLineTextIndex( index, g_locStr_Destroyed );
            chSetLineColor( index, color, 1.f );
            chSetLineType( index, CI_TEXT );
            chSetLineSize( index, 0, 0 );
        }
    } else {
        if ( disabledState ) {
            index = chAddLine();

            float diff = disableEndTime - sys.getTime();            
            if ( diff > 0 ) {
                sys.pushLocString( int( diff ) );
                chSetLineText( index, sys.localizeStringArgs( "game/disabled_info" ) );
            } else {
                chSetLineTextIndex( index, g_locStr_Disabled );
            }

            chSetLineColor( index, disabledColor, 1.f );
            chSetLineType( index, CI_TEXT );
            chSetLineSize( index, 0, 0 );
        }

        index = chAddLine();
        chSetLineColor( index, color, 0.5f );
        chSetLineType( index, CI_BAR );
        chSetLineFraction( index, getHealth() / getMaxHealth() );
        chSetLineSize( index, healthBarLength, CROSSHAIR_INFO_BAR_HEIGHT );

        if ( !disabledState ) {
            float fsState = vGetFiringStatus( $null_entity );
            G_StringForFireSupportState( fsState );

            index = chAddLine();
            chSetLineTextIndex( index, g_fireSupportStateStr );
            chSetLineColor( index, color, 1.f );
            chSetLineType( index, CI_TEXT );
            chSetLineSize( index, 0, 0 );
        }

        if ( range <= 100 ) {
            index = chAddLine();
            chSetLineText( index, G_BuildRangeStr( range ) );
            chSetLineColor( index, color, 1.f );
            chSetLineType( index, CI_TEXT );
            chSetLineSize( index, 0, 0 );
        }
    }

    return 1.f;
}
boolean    deployable_turret::InRange( vector targetPos ) {
    float len = sys.vecLength( targetPos - getWorldOrigin() );
    return ( ( len >= minRange ) && ( len <= maxRange ) );
}

boolean deployable_turret::InFiringRange( vector targetPos ) {
    float len = sys.vecLength( targetPos - getWorldOrigin() );
    return ( ( len >= minRange ) && ( len <= firingRange ) );
}

// ==========================================
// ==========================================

float deployable_turret::OnUsed( entity p, float distance ) {
    entity team = p.getGameTeam();
    if ( team == $null_entity ) {
        return 0.f;
    }

    if ( p.getHealth() <= 0 ) {
        return 0.f;
    }

    if ( distance > 128.f ) {
        return 0.f;
    }

    if ( getEntityAllegiance( p ) != TA_FRIEND ) {
        return 1.f;
    }

    entity other = p.getProxyEntity();
    if ( other != $null_entity ) {
        sys.assert( self == other );

        if ( !sys.isClient() ) {
            removeBoundPlayer( p );
        }

        return 1.f;
    }

    if ( getBoundPlayer( 0 ) != $null_entity ) {
        return 1.f;
    }

    if ( !sys.isClient() ) {
        p.enter( self );
    }

    return 1.f;
}

void deployable_turret::OnKilled( entity inflictor, entity attacker, float damage, vector dir, float location ) {
    entity currentUser = getBoundPlayer( 0 );
    if( currentUser != $null_entity ) {
        currentUser.applyDamage( inflictor, attacker, dir, GetDamage( "damage_deployable_turret_user" ), 1.f, $null_entity );
    }

    DeployableBase_OnKilled( attacker, inflictor );
}

void deployable_turret::OnEnter( entity user ) {
    sys.assert( false );

    if ( user.isDisguised() ) {
        user.disguise( $null_entity );
    }

    myUser = user;
    user.vHideNormalChargeBar( true );
    if ( user == sys.getLocalPlayer() ) {
        sys.setGUIString( GUI_GLOBALS_HANDLE, "gameHud.weaponCrosshair", getKey( "crosshair" ) );
        sys.setGUIFloat( GUI_GLOBALS_HANDLE, "gameHud.weaponShowAllAmmo", 1 );        
        sys.setGUIFloat( GUI_GLOBALS_HANDLE, "gameHud.weaponShowClip", 0 );
        sys.setGUIFloat( GUI_GLOBALS_HANDLE, "gameHud.weaponHideAmmo", 0 );
        sys.setGUIFloat( GUI_GLOBALS_HANDLE, "gameHud.weaponShowCharge", 1 );
        sys.setGUIFloat( GUI_GLOBALS_HANDLE, "weapons.energySegments", 1 );
        sys.setGUIFloat( GUI_GLOBALS_HANDLE, "gameHud.weaponShowCustom", 0 );
        sys.setGUIFloat( GUI_GLOBALS_HANDLE, "weapons.showHeat", 1.f );

        thread UpdateCharge();
    }
}

void deployable_turret::OnExit( entity user ) {
    sys.assert( false );

    myUser = $null_entity;
    user.vHideNormalChargeBar( false );
    if ( user == sys.getLocalPlayer() ) {
        sys.setGUIFloat( GUI_GLOBALS_HANDLE, "weapons.showHeat", 0 );
        sys.setGUIFloat( GUI_GLOBALS_HANDLE, "weapons.energyAvailable", 1 );
        sys.setGUIFloat( GUI_GLOBALS_HANDLE, "weapons.energyBarCharge", 1 );
        sys.setGUIFloat( GUI_GLOBALS_HANDLE, "weapons.cooling", 0 );
    }
}

void deployable_turret::CreateDestroyThread() {
    sys.freeCMIcon( self, commandmapVisibleArcHandle );
    commandmapVisibleArcHandle = -1;
    thread DestroyThread();
}

void deployable_turret::OnBeginAttack() {
    attacking = true;

    KillAttackThread();
    thread AttackThread();
}

void deployable_turret::OnEndAttack() {
    attacking = false;

    KillAttackThread();
}

void deployable_turret::vCheckProficiency() {
    SetupFiringArc();
}

void deployable_turret::OnDisabled() {
    setDisabled( true );
    sys.setCMIconShaderParm( commandMapHandle, 5, 0 );
    if ( owner != $null_entity ) {
        if ( owner.isLocalPlayer() ) {
            sys.setGUIFloat( GUI_GLOBALS_HANDLE, "deployables.state", DS_DISABLED );
        }
    }
}

void deployable_turret::OnReEnabled() {
    setDisabled( false );
    sys.setCMIconShaderParm( commandMapHandle, 5, 1 );
    if ( owner != $null_entity ) {
        if ( owner.isLocalPlayer() ) {
            sys.setGUIFloat( GUI_GLOBALS_HANDLE, "deployables.state", DS_NORMAL );
        }
    }
}

float deployable_turret::GetTurretMaxRange() {
    return firingRange;
}

float deployable_turret::GetTurretMinRange() {
    return minRange;
}

float deployable_turret::vGetFiringStatus( object traceObject ) {
    if ( attacking ) {
        return MPS_FIRING;
    }

    if ( !finishedDeploying ) {
        return MPS_NONE_ACTIVE;
    }

    return MPS_READY;
}