Script:Files:script/maps/generic/zappor.script

From Mod Wiki
// Zappor: Strogg thing that calls down a giant airstrike

#define ZA_DEPLOY        1
#define ZA_IDLE_DAMAGED 2
#define ZA_STARTFIRE    3
#define ZA_FIRING        4
#define ZA_FIRED        5

object mining_laser_beacon {
    void            SetEntities( entity o, entity l );
}

object mining_laser_objective : constructible_materials {
    void            preinit();

    void            SetupConstruction();

    void            OnConstructionFinished( entity p );
    void            DoZap( entity p );
    void            SetEntities( entity o, entity l );

    float            OnUpdateCrosshairInfo( entity p );

    entity            deployer;
    entity            laser;
    boolean            hasZapped;

    handle            constructedMessage;

    handle            objectName;
}

void mining_laser_objective::preinit() {
    forceShowProgress    = true;
    constructedMessage    = sys.localizeString( "maps/generic/zappor/constructed" );
    objectName        = sys.localizeString( getKey( "object_name" ) );
}

void mining_laser_objective::SetupConstruction() {
    multipleStages = false;

    if ( sys.isClient() ) {
        OnStateChanged();
        return;
    }

    firstStage = sys.spawn( getKey( "def_construction" ) );
    firstStage.setOrigin( getWorldOrigin() );
    firstStage.setAngles( getAngles() );
    firstStage.setGameTeam( getGameTeam() );
    firstStage.vSetOwner( self );

    SetConstructionState( CSTATE_NONE );
}

void mining_laser_objective::OnConstructionFinished( entity p ) {
    OnFinishCurrentState( p );
    counter = constructionCount;

    if ( !sys.isClient() ) {    
        objManager.PushCPrintString( p.getUserName() );
        objManager.CPrintEvent( constructedMessage, $null );

        objManager.OnMiningLaserConstructed( self );

        firstStage.remove();

        DoZap( p );
    }
}

void mining_laser_objective::DoZap( entity p ) {
    if ( deployer == $null_entity || hasZapped ) {
        return;
    }

    mining_laser_beacon targ = deployer.getEntityKey( "target" );
    if ( targ == $null_entity ) {
        sys.error( "mining_laser_objective::DoZap could not find target" );
    }
    targ.SetEntities( p, laser );
    targ.vOnDeploy();

    hasZapped = true;
}

void mining_laser_objective::SetEntities( entity o, entity l ) {
    deployer = o;
    laser = l;
    if ( deployer != $null_entity ) {
        vStartObjective();
    }
}

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

    float allegiance = getEntityAllegiance( p );
    float distance;
    if ( deployer != $null_entity ) {
        distance = deployer.chGetDistance();
    } else {
        distance = chGetDistance();
    }
    float range = InchesToMetres( distance );


    chSetNumLines( 0 );

    team_base team;

    if ( p.isLocalPlayer() && objectiveIndex != -1 ) {
        p.sendToolTip( GetToolTip( getKey( "tt_intro_info" ) ) );
    }

    // see if theres a valid action to perform
    float code = GetActivateCode( p, distance );
    if ( code != AK_NONE && p.vHasActionItem( code ) ) {
        float 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 ) ) {
                        p.sendToolTip( useMeToolTip1 );
                    } else {
                        p.sendToolTip( useMeToolTip2 );
                    }
                }
            }
        }
    }

    vector color = GetAllegianceColor( allegiance );

    index = chAddLine();
    chSetLineTextIndex( index, objectName );
    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;
}




object mining_laser {
    void            init();
    void            syncFields();

    void            vOnDeploy();
    void            vSetManualDeploy();
    void            vSetOwner( entity o );

    void            DoDeployAnim();
    float            AnimState( float state );
    void            OnAnimStateChanged();

    void            BoundsKillThread();

    float            OnUpdateCrosshairInfo( entity p );

    boolean            manualDeploy;
    entity            deployer;
    boolean            deployed;

    float            currentAnimState;

    handle            objectName;
}

void mining_laser::syncFields() {
    syncBroadcast( "deployed" );
    syncCallback( "deployed", "vOnDeploy" );

    syncBroadcast( "currentAnimState" );
    syncCallback( "currentAnimState", "OnAnimStateChanged" );
}

void mining_laser::init() {
    setContents( CONTENTS_PLAYERCLIP | CONTENTS_VEHICLECLIP | CONTENTS_FLYERHIVECLIP );

    objectName = sys.localizeString( getKey( "object_name" ) );

    if ( !sys.isClient() ) {
        thread BoundsKillThread();

        if ( !manualDeploy ) {
            vOnDeploy();
        }
    }

    disableImpact();
}

void mining_laser::OnAnimStateChanged() {
    AnimState( currentAnimState );
}

void mining_laser::vOnDeploy() {
    deployed = true;
    putToRest();
    disableImpact();

    if ( !sys.isClient() ) {
        sys.killThread( "BoundsKillThread_" + getName() );

        mining_laser_objective objectiveThing = sys.spawn( getKey( "def_objective" ) );
        if ( objectiveThing == $null ) {
            sys.error( "mining_laser::vOnDeploy failed to spawn objective" );
        }
        objectiveThing.setOrigin( getWorldOrigin() );
        objectiveThing.setAngles( getAngles() );
        objectiveThing.setGameTeam( getGameTeam() );
        objectiveThing.SetEntities( deployer, self );
        objectiveThing.vOnDeploy();

        objManager.OnMiningLaserDeployed( objectiveThing );

        thread DoDeployAnim();
    }
}

float mining_laser::AnimState( float state ) {
    currentAnimState = state;

    if ( currentAnimState == ZA_DEPLOY ) {
        return playAnim( ANIMCHANNEL_ALL, "deploy" );
    }
    if ( currentAnimState == ZA_IDLE_DAMAGED ) {
        return playAnim( ANIMCHANNEL_ALL, "idle_damaged" );
    }
    if ( currentAnimState == ZA_STARTFIRE ) {
        return playAnim( ANIMCHANNEL_ALL, "startfire" );
    }
    if ( currentAnimState == ZA_FIRING ) {
        return playAnim( ANIMCHANNEL_ALL, "fire" );
    }
    if ( currentAnimState == ZA_FIRED ) {
        return playAnim( ANIMCHANNEL_ALL, "idle_after_firing" );
    }

    return 0.f;
}

void mining_laser::DoDeployAnim() {
    sys.wait( AnimState( ZA_DEPLOY ) );
    AnimState( ZA_IDLE_DAMAGED );
}

void mining_laser::vSetOwner( entity o ) { 
    deployer = o; 
}

void mining_laser::vSetManualDeploy() {
    manualDeploy = true;
}

void mining_laser::BoundsKillThread() {
    float damageIndex = GetDamage( getKey( "dmg_crush" ) );

    while ( true ) {
        BoundsDamage( self, damageIndex );
        sys.waitFrame();
    }
}


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

    float allegiance = getEntityAllegiance( p );
    vector color = GetAllegianceColor( allegiance );
    float distance;
    if ( deployer != $null_entity ) {
        distance = deployer.chGetDistance();
    } else {
        distance = chGetDistance();
    }
    float range = InchesToMetres( distance );

    chSetNumLines( 0 );
    float index;

    index = chAddLine();
    chSetLineTextIndex( index, objectName );
    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;
}




object mining_laser_beacon {
    void            preinit();
    void            init();
    void            destroy();

    void            syncFields();

    void            Idle();
    void            Update();

    void            vOnDeploy();

    void            OnFiringChanged();

    entity            destroyTarget;
    entity            destroyTarget2;

    float            beamEndTime;
    float            beamRotationSpeed;

    object            beamEffect;

    float            damageIndex;
    float            splashDamageIndex;    

    boolean            hasFired;
    boolean            firing;

    float            muzzleJoint;

    entity            caller;
    mining_laser    laser;

    vector            target_offset;
}

void mining_laser_beacon::preinit() {
    beamRotationSpeed    = getFloatKey( "beam_rotation_speed" );    
    damageIndex            = GetDamage( getKey( "dmg_damage" ) );
    splashDamageIndex    = GetDamage( getKey( "dmg_splash_damage" ) );
    target_offset        = getVectorKey( "target_offset" );
}

void mining_laser_beacon::init() {
    destroyTarget = getEntityKey( "target" );
    destroyTarget2 = getEntityKey( "target_secondary" );
}

void mining_laser_beacon::destroy() {
    stopEffect( "fx_beam_impact" );
    if ( beamEffect != $null_entity ) {
        beamEffect.remove();
        beamEffect = $null_entity;
    }
}

void mining_laser_beacon::syncFields() {
    syncBroadcast( "laser" );
    syncBroadcast( "firing" );
    syncCallback( "firing", "OnFiringChanged" );
}

void mining_laser_beacon::vOnDeploy() {
    setState( "Idle" );
}

void mining_laser_beacon::OnFiringChanged() {
    if ( firing ) {
        setState( "Idle" );
    }
}

void mining_laser_beacon::SetEntities( entity o, entity l ) {
    caller = o;
    laser = l;
}

void mining_laser_beacon::Idle() {    
    if ( !sys.isClient() ) {
        sys.wait( laser.AnimState( ZA_STARTFIRE ) );

        beamEndTime = sys.getTime() + laser.AnimState( ZA_FIRING );

        firing = true;
    }

    muzzleJoint = laser.getJointHandle( "muzzle" );

    while ( firing ) {
        Update();
        sys.waitFrame();
    }

    if ( !sys.isClient() ) {
        laser.AnimState( ZA_FIRED );
    } else {
        stopEffect( "fx_beam_impact" );
        playOriginEffect( "fx_explode", "", getWorldOrigin(), getWorldAxis( 0 ), 0 );
        startSound( "snd_beam_stop", SND_WEAPON_FIRE2 );

        if ( beamEffect != $null_entity ) {
            beamEffect.remove();
            beamEffect = $null_entity;
        }
    }

    sys.wait( 10.f );

    stopEffect( "fx_beam_impact" );

    if ( beamEffect != $null_entity ) {
        beamEffect.remove();
        beamEffect = $null_entity;
    }
}

void mining_laser_beacon::Update() {    
    float currentTime = sys.getTime();

    vector endPos = getWorldOrigin();
    vector startPos = laser.getJointPos( muzzleJoint );

    float count = entitiesInTranslation( startPos, endPos, MASK_SHOT_RENDERMODEL | MASK_SHOT_BOUNDINGBOX, $null_entity );

    boolean doFire;
    if ( sys.isClient() ) {
        doFire = firing;
    } else {
        doFire = currentTime < beamEndTime;
    }

    if ( doFire ) {
        if ( beamEffect == $null_entity ) {
            beamEffect = spawnClientEffect( "fx_beam" );
            if ( beamEffect != $null_entity ) {
                beamEffect.setEffectLooping( 1 );
                beamEffect.setOrigin( startPos );
                beamEffect.setEffectEndOrigin( endPos );
            }
            playOriginEffect( "fx_beam_impact", "", endPos + target_offset, getWorldAxis( 0 ), true );
            startSound( "snd_beam_start", SND_WEAPON_FIRE2 );
        }

        float i;
        for ( i = 0; i < count; i++ ) {
            entity ent = getBoundsCacheEntity( i );

            if ( ent == $null_entity ) {
                continue;
            }

            if ( ent == destroyTarget || ent == destroyTarget2 ) {
                continue;
            }

            ent.applyDamage( self, $null_entity, vec3_down, damageIndex, 1.0f, $null_entity );
        }
    } else {
        firing = false;

        if ( beamEffect != $null_entity ) {
            beamEffect.endEffect( false );    
        }

        if ( !hasFired ) {
            stopEffect( "fx_beam_impact" );
            playOriginEffect( "fx_explode", "", endPos, getWorldAxis( 0 ), 0 );
            startSound( "snd_beam_stop", SND_WEAPON_FIRE2 );
            if ( destroyTarget != $null_entity ) {
                destroyTarget.applyDamage( self, caller, '0 0 1', damageIndex, 1.0f, $null_entity );
            }
            if ( destroyTarget2 != $null_entity ) {
                destroyTarget2.applyDamage( self, caller, '0 0 1', damageIndex, 1.0f, $null_entity );
            }
            sys.applyRadiusDamage( endPos, self, caller, $null_entity, self, splashDamageIndex, 1.f, 1.f );
            hasFired = true;
        }
    }

    if ( beamEffect != $null_entity ) {
        vector forward = sys.vecNormalize(endPos - startPos);
        vector up = '0 0 1';
        vector right = sys.crossProduct( up, forward );
        up = sys.crossProduct( forward, right );

        beamEffect.setWorldAxis( forward, right, up );
    }
}