Script:Files:script/items/hecharge.script

From Mod Wiki
/***********************************************************************

item_he_charge.script

***********************************************************************/

object item_he_charge : weapon_base {
    void        preinit();
    void        init();
    void        destroy();

    void        Raise();
    void        Idle();
    void        Fire();

    boolean        CanAttack();
    boolean        DoTrace();
    boolean        CheckNoPlant();

    float        meleeDistance;

    boolean        cancelFire;

    void        ToolTipThread_Raise();

    float        nextInvalidPositionToolTipTime;    
    float        nextChargeToolTipTime;

    void        vCancelFire() { cancelFire = true; }

    handle        statNumUsed;

    boolean        clientWait;

    // cached trace information
    entity        meleeEntity;
    vector        meleeNormal;
    vector        meleeEndPos;
    string        meleeJoint;
    float        meleeSurfaceFlags;
    boolean        meleeInfoValid;
}

void item_he_charge::preinit() {
    meleeDistance        = getFloatKey( "melee_distance" );

    string statName = getKey( "stat_name" );
    if ( statName != "" ) {
        statNumUsed            = sys.allocStatInt( statName + "_uses" );
    }
}

void item_he_charge::init() {
    if ( myPlayer.isLocalPlayer() ) {
        thread ToolTipThread_Raise();
    }

    weaponState( "Raise", 0 );
}

void item_he_charge::destroy() {
    entity myPlayer = getOwner();
    if ( myPlayer != $null_entity ) {
        myPlayer.freeze( 0 );
        myPlayer.freezeTurning( 0 );
    }
}

void item_he_charge::Raise() {
    UpdateCharge();

    Base_Raise();
}

boolean item_he_charge::CheckNoPlant() {
    float count = entitiesInRadius( g_vectorZero, 0.f, CONTENTS_TRIGGER, 0 );
    float index = 0;
    for ( index = 0; index < count; index++ ) {
        entity ent = getBoundsCacheEntity( index );
        if ( ent.getGameTeam() == getGameTeam() ) {
            if ( ent.vDisablePlant() ) {
                return false;
            }
        }
    }

    return true;
}

boolean item_he_charge::CanAttack() {
    if ( !CanRemove( chargePerUse ) ) {
        if ( myPlayer.isLocalPlayer() && !mainFireDown ) {
            if ( !myPlayer.isToolTipPlaying() ) {
                myPlayer.sendToolTip( GetToolTip( getKey( "tt_need_charge" ) ) );
            }
            sys.startSoundDirect( getKey( "snd_need_charge" ), SND_ANY );
            G_NotifyNoCharge( myPlayer );
        }
        return false;
    }

    if ( !CheckNoPlant() ) {
        if ( !myPlayer.isToolTipPlaying() ) {
            if ( sys.getTime() > nextChargeToolTipTime ) {
                nextChargeToolTipTime = sys.getTime() + 5.f;
                myPlayer.sendToolTip( GetToolTip( getKey( "tt_action_failed" ) ) );
            }
        }
        return false;
    }

    boolean valid = true;
    if ( !DoTrace() ) {
        valid = false;
    } else {
        entity other = meleeEntity;
        float shaderFlags = meleeSurfaceFlags;

        if ( other == $null_entity || shaderFlags & SURF_NOPLANT ) {
            valid = false;
        } else {
            valid = !other.vDisablePlantCharge();
        }
    }

    if ( !valid ) {
        if ( !myPlayer.isToolTipPlaying() ) {
            if ( sys.getTime() > nextInvalidPositionToolTipTime ) {
                nextInvalidPositionToolTipTime = sys.getTime() + 5.f;
                myPlayer.sendToolTip( GetToolTip( getKey( "tt_action_failed" ) ) );
            }
        }
    }

    return valid;
}

void item_he_charge::Idle() {
    entity other;
    weaponReady();
    playCycle( ANIMCHANNEL_ALL, "idle" );

    if ( clientWait ) {
        sys.wait( 0.2 );
        clientWait = false;
    }

    while ( true ) {
        if ( WEAPON_LOWERWEAPON ) {
            weaponState( "Lower", 0 );
        }

        if ( WEAPON_ATTACK || myPlayer.getButton( PK_ACTIVATE ) ) {
            if( !mainFireDown ) {
                if ( CanAttack() ) {
                    mainFireDown = true;
                    weaponState( "Fire", 0 );
                }
                mainFireDown = true;
            }
        } else {
            mainFireDown = false;
        }

        UpdateCharge();

        sys.waitFrame();
    }
}

boolean item_he_charge::DoTrace() {
    if ( !melee( MASK_SHOT_BOUNDINGBOX | MASK_PROJECTILE, meleeDistance, true, false ) ) {
        meleeInfoValid = false;
        return false;
    }

    meleeEntity = getMeleeEntity();
    meleeNormal = getMeleeNormal();
    meleeEndPos = getMeleeEndPos();
    meleeSurfaceFlags = getMeleeSurfaceFlags();
    meleeInfoValid = true;
    meleeJoint = getMeleeJoint();
    return true;
}

void item_he_charge::Fire() {
    cancelFire = false;

    myPlayer.freeze( 1 );
    myPlayer.freezeTurning( 1 );

    fired();

    playAnim( ANIMCHANNEL_ALL, "fire" );
    waitUntil( animDone( ANIMCHANNEL_ALL, 0 ) );

    myPlayer.freeze( 0 );
    myPlayer.freezeTurning( 0 );

    if ( cancelFire ) {
        weaponState( "Idle", 0 );
    }

    if( !sys.isClient() ) {
        if ( CanAttack() ) {    
            entity charge = sys.spawn( getKey( "def_charge" ) );

            // we don't want to get the message just after we have planted, as we'll switch to the arming tool anyway
            nextChargeToolTipTime = sys.getTime() + 2.f;

            entity other = meleeEntity;
            charge.setOrigin( meleeEndPos - ( meleeNormal * 0.5f ) );
            charge.alignToAxis( meleeNormal, 0 );
            charge.vSetOwner( myPlayer );
            charge.setGameTeam( myPlayer.getGameTeam() );
            charge.vSetNewTarget( other );
            if ( other != $null_entity ) {
                float jointHandle = other.getJointHandle( meleeJoint );
                if ( jointHandle != INVALID_JOINT ) {
                    charge.bindToJoint( other, meleeJoint, 1 );
                } else {
                    charge.bind( other );
                }
            }

            Remove( chargePerUse );

            team_base team = myPlayer.getGameTeam();
            team.SelectActionItem( myPlayer, AK_CHARGEARM );

            myPlayer.setPlayerChargeOrigin( charge ); //mal: set the origin of the placed charge, so the bots know where to go to arm/disarm it.

            sys.increaseStatInt( statNumUsed, myPlayer.getEntityNumber(), 1 );
        }
    } else {
        // wait for server to select weapon
        clientWait = true;
    }

    weaponState( "Idle", 0 );
}

void item_he_charge::ToolTipThread_Raise() {
    myPlayer.cancelToolTips();
    sys.wait( myPlayer.CalcTooltipWait() );

    WAIT_FOR_TOOLTIP;
    myPlayer.sendToolTip( GetToolTip( getKey( "tt_intro_1" ) ) );

    WAIT_FOR_TOOLTIP;
    myPlayer.sendToolTip( GetToolTip( getKey( "tt_intro_2" ) ) );
}