Script:Files:script/misc/objective manager.script

From Mod Wiki
void G_SetObjectiveManager( object o );

object mapObject_Base {
    void            InitObjectives() { }
    void            CompleteObjective( float index, entity p ) { }
    handle            GetObjectiveMessage( float index );

    void            OnConstructionComplete( entity obj ) { }
    void            OnDestructionComplete( entity obj ) { }
    void            OnHackComplete( entity obj ) { }
    void            OnMCPSpawned( entity obj ) { }
    void            OnMCPDestroyed( entity obj, vector newLocation, vector newAngles ) { }
    void            OnMCPDelivered( entity obj ) { }
    void            OnShieldDeployed( entity obj, entity trigger ) { }
    void            OnShieldDestroyedScud( entity trigger ) { }
    void            OnMiningLaserDeployed( entity obj ) { }
    void            OnMiningLaserConstructed( entity obj ) { }    
    void            OnTimeLimitHit() { }

    void            RunBotMCPMapScript( float actionGroupOff, float actionGroupOn ) { }
    void            OnCarryableItemStolen( string actionName ) { }
    void            OnCarryableItemReturned( string actionName ) { }
    void            OnSpawnCaptured( string actionName ) { }
    void            OnSpawnLiberated( string actionName ) { }

    vector            GetGDFBasePosition() { return g_vectorZero; }
    void            ScudExploded( entity scud ) {}
}

object objectiveManager {
    void            preinit();
    void            destroy();

    void            CountdownVO();

    void            OnMapStart();
    void            OnMapShutdown();
    void            OnLocalMapRestart();
    void            OnNetworkEvent();
    void            OnGameStateChange( float newState );    
    void            OnWriteInitialReliableMessages( entity p );

    void            HandleCenterPrint();
    void            HandleObjectiveEntity();

    void            CompleteObjective( float index, entity p );

    void            SendObjectiveChangedEvent( entity ent, entity p, float index );
    void            SetObjectiveEntity( entity ent, float index );
    void            RefreshObjectiveEntity();

    void            OnConstructionComplete( entity obj );
    void            OnDestructionComplete( entity obj );
    void            OnHackComplete( entity obj );
    void            OnMCPSpawned( entity obj );
    void            OnMCPDestroyed( entity obj, vector newLocation, vector newAngles );
    void            OnMCPDelivered( entity obj );
    void            OnShieldDeployed( entity obj, entity trigger );
    void            OnShieldDestroyedScud( entity trigger );
    void            OnMiningLaserDeployed( entity obj );
    void            OnMiningLaserConstructed( entity obj );
    void            OnTimeLimitHit();

    void            RunBotMCPMapScript( float actionGroupOff, float actionGroupOn );
    void            OnCarryableItemStolen( string actionName );
    void            OnCarryableItemReturned( string actionName );
    void            OnSpawnCaptured( string actionName );
    void            OnSpawnLiberated( string actionName );


    void            PlaySound( string soundShader, object team );
    void            PlaySoundRanged( string soundShader, object team, vector org, float maxRange );
    void             PlaySoundForPlayer( string soundShader, entity p );

    void            OnNextObjectiveSet( object team, float objectiveIndex );

                    // initialize the limbo menu with objective information	
    void            InitObjectiveUI( float index, handle descriptionGDF, handle descriptionStrogg, 
                                                    handle miniDescriptionGDF, handle miniDescriptionStrogg,
                                                    string materialGDF, string materialStrogg );
    vector            GetGDFBasePosition();

    void            ScudExploded( entity scud );

    mapObject_Base    mapObject;

    void            PushCPrintString( string arg );
    void            PushCPrintHandle( handle h );    
    void            CPrintEvent( handle h, object team );
    void            CPrintEventRanged( handle h, object team, vector org, float maxRange );

    void            SetupCPrintHUD( wstring text, float endTime );

    float            GetCountdownTime();

    void            PlayCountdownVO( string sound, float seconds );

    string            printArgs;
    float            numPrintArgs;

    entity            currentPrimaryObjective;

    float            gameState;
}

objectiveManager objManager;

void objectiveManager::preinit() {
    G_SetObjectiveManager( self );
}

#define MIN2SEC( x ) ( x * 60 )

float objectiveManager::GetCountdownTime() {
    return sys.getMatchTimeRemaining() - 1;
}

void objectiveManager::CountdownVO() {
    sys.threadName( "CountdownThread" );

    // need to wait for the time to be set in countdown mode
    sys.waitFrame();

    // don't attempt to play all the sounds if warmup-time is really low
    if ( GetCountdownTime() < 6.5 ) {
        return;
    }

    while( GetCountdownTime() > MIN2SEC( 10 ) ) {
        sys.waitFrame();
    }


    PlayCountdownVO( "snd_countdown_10m", MIN2SEC( 10 ) );

    while( GetCountdownTime() > MIN2SEC( 5 ) ) {        
        sys.waitFrame();
    }

    PlayCountdownVO( "snd_countdown_5m", MIN2SEC( 5 ) );

    while( GetCountdownTime() > MIN2SEC( 2 ) ) {        
        sys.waitFrame();
    }

    PlayCountdownVO( "snd_countdown_2m", MIN2SEC( 2 ) );

    while( GetCountdownTime() > MIN2SEC( 1 ) ) {        
        sys.waitFrame();
    }

    PlayCountdownVO( "snd_countdown_1m", MIN2SEC( 1 ) );

    while( GetCountdownTime() > 30 ) {        
        sys.waitFrame();
    }

    PlayCountdownVO( "snd_countdown_30s", 30 );

    while( GetCountdownTime() > 10 ) {        
        sys.waitFrame();
    }

    PlayCountdownVO( "snd_countdown_10s", 10 );

    while( GetCountdownTime() > 5 ) {        
        sys.waitFrame();
    }

    PlayCountdownVO( "snd_countdown_5s", 5 );
}

void objectiveManager::OnMapStart() {
    delete mapObject;

    if ( sys.doClientSideStuff() ) {
        sys.setGUIFloat( GUI_GLOBALS_HANDLE, "gameHud.successTextTime", 0.f );    
    }

    if ( !sys.isClient() ) {
        mapObject = createMapScript();
        if ( mapObject == $null_entity ) {
            sys.error( "objectiveManager::OnMapStart No Map Script" );
        }
        mapObject.InitObjectives();
    }
}

void objectiveManager::OnMapShutdown() {
    delete mapObject;
}

void objectiveManager::OnLocalMapRestart() {
    entity worldspawn = sys.getEntity( "worldspawn" );

    float count = worldspawn.entitiesOfCollection( "maprestartwatch" );

    float i;
    for ( i = 0; i < count; i++ ) {
        entity ent = worldspawn.getBoundsCacheEntity( i );
        ent.vOnLocalMapRestart();
    }
}

void objectiveManager::OnGameStateChange( float newState ) {
    gameState = newState;

    // kill any previous countdowns
    sys.killThread( "CountdownThread" );

    if ( newState == GS_COUNTDOWN || newState == GS_GAMEON ) {
        thread CountdownVO(); 
    }

    if ( newState == GS_GAMEREVIEW ) {
        entity worldspawn = sys.getEntity( "worldspawn" );
        float count = worldspawn.entitiesOfCollection( "gamereviewwatch" );
        float cacheHandle = worldspawn.saveCachedEntities();

        float i;
        for ( i = 0; i < count; i++ ) {
            entity ent = worldspawn.getSavedCacheEntity( cacheHandle, i );
            ent.vOnEndGame();
        }

        worldspawn.freeSavedCache( cacheHandle );
    }
}

void objectiveManager::destroy() {
    OnMapShutdown();
}

void objectiveManager::CompleteObjective( float index, entity p ) {        
    if ( sys.isClient() ) {        
        return;
    }

    logObjectiveCompletion( index );

    // send a message out with the message
    if ( p == $null_entity ) {
        PushCPrintHandle( g_locStr_Someone );
    } else {
        PushCPrintString( p.getUserName() );
    }
    CPrintEvent( mapObject.GetObjectiveMessage( index ), $null );

    mapObject.CompleteObjective( index, p );
}

void objectiveManager::OnConstructionComplete( entity obj ) {
    if ( sys.isClient() ) {        
        return;
    }

    mapObject.OnConstructionComplete( obj );
}

void objectiveManager::OnDestructionComplete( entity obj ) {
    if ( sys.isClient() ) {        
        return;
    }

    mapObject.OnDestructionComplete( obj );
}

void objectiveManager::OnHackComplete( entity obj ) {
    if ( sys.isClient() ) {        
        return;
    }

    mapObject.OnHackComplete( obj );
}

void objectiveManager::OnMCPSpawned( entity obj ) {
    if ( sys.isClient() ) {        
        return;
    }

    mapObject.OnMCPSpawned( obj );
}

void objectiveManager::OnMCPDestroyed( entity obj, vector newLocation, vector newAngles ) {
    if ( sys.isClient() ) {        
        return;
    }

    PlaySound( obj.getKey( "snd_vo_off_course_0_gdf" ), gdfTeam );
    PlaySound( obj.getKey( "snd_vo_off_course_0_strogg" ), stroggTeam );
    CPrintEvent( sys.localizeString( "maps/generic/mcp/destroyed" ), $null );

    mapObject.OnMCPDestroyed( obj, newLocation, newAngles );
}

void objectiveManager::OnMCPDelivered( entity obj ) {
    if ( sys.isClient() ) {        
        return;
    }

    mapObject.OnMCPDelivered( obj );
}

void objectiveManager::OnShieldDestroyedScud( entity trigger ) {
    if ( sys.isClient() ) {        
        return;
    }

    mapObject.OnShieldDestroyedScud( trigger );
}


void objectiveManager::OnShieldDeployed( entity obj, entity trigger ) {
    if ( sys.isClient() ) {        
        return;
    }

    mapObject.OnShieldDeployed( obj, trigger );
}

void objectiveManager::OnMiningLaserDeployed( entity obj ) {
    if ( sys.isClient() ) {        
        return;
    }

    mapObject.OnMiningLaserDeployed( obj );
}

void objectiveManager::OnMiningLaserConstructed( entity obj ) {
    if ( sys.isClient() ) {        
        return;
    }

    mapObject.OnMiningLaserConstructed( obj );
}

void objectiveManager::OnTimeLimitHit() {
    if ( sys.isClient() ) {        
        return;
    }

    mapObject.OnTimeLimitHit();
}

void objectiveManager::RunBotMCPMapScript( float actionGroupOff, float actionGroupOn ) {
    if ( sys.isClient() ) {
        return;
    }

    mapObject.RunBotMCPMapScript( actionGroupOff, actionGroupOn );
}

void objectiveManager::OnCarryableItemStolen( string actionName ) {
    if ( sys.isClient() ) {
        return;
    }

    mapObject.OnCarryableItemStolen( actionName );
} 


void objectiveManager::OnCarryableItemReturned( string actionName ) {
    if ( sys.isClient() ) {
        return;
    }

    mapObject.OnCarryableItemReturned( actionName );
}

void objectiveManager::OnSpawnCaptured( string actionName ) {
    if ( sys.isClient() ) {
        return;
    }

    mapObject.OnSpawnCaptured( actionName );
}


void objectiveManager::OnSpawnLiberated( string actionName ) {
    if ( sys.isClient() ) {
        return;
    }

    mapObject.OnSpawnLiberated( actionName );
}

void objectiveManager::PlaySound( string soundShader, object team ) {
    PlaySoundRanged( soundShader, team, vec3_origin, -1.f );
}

void objectiveManager::PlaySoundRanged( string soundShader, object team, vector org, float maxRange ) {
    if ( sys.isClient() ) { // Gordon: this function really should only be called for things the client cannot predict
        return;
    }

    if ( soundShader == "" ) {
        return;
    }

    float shaderIndex = GetSoundShader( soundShader );
    if ( shaderIndex == -1 ) {
        sys.warning( "objectiveManager::PlaySound - couldn't find shader for sound " + soundShader );
        return;
    }

    entity p;

    if ( sys.isServer() ) {
        float rangeSqr = maxRange * maxRange;

        string message = "s " + shaderIndex;

        float maxClients = sys.getMaxClients();
        float index;
        for ( index = 0; index < maxClients; index++ ) {
            p = sys.getClient( index );
            if ( p == $null_entity ) {
                continue;
            }

            if ( team != $null ) {
                if ( team != p.getGameTeam() ) {
                    continue;
                }
            }

            if ( maxRange > 0.f ) {
                if ( sys.vecLengthSquared( p.getWorldOrigin() - org ) > rangeSqr ) {
                    continue;
                }
            }

            sendNetworkEvent( p, message );
        }
    }

    p = sys.getLocalPlayer();
    if ( p != $null_entity ) {
        if ( team == p.getGameTeam() || team == $null_entity ) {
            sys.startSoundDirect( soundShader, SND_PLAYER_VO );
        }
    }
}

void objectiveManager::PlaySoundForPlayer( string soundShader, entity p ) {
    if ( sys.isClient() ) { // Gordon: this function really should only be called for things the client cannot predict
        return;
    }

    if ( soundShader == "" || p == $null_entity ) {
        return;
    }

    float index = GetSoundShader( soundShader );
    if ( index == -1 ) {
        sys.warning( "objectiveManager::PlaySoundForPlayer: couldn't find shader for sound " + soundShader );
        return;
    }

    if ( sys.getLocalPlayer() == p ) {
        sys.startSoundDirect( soundShader, SND_PLAYER_VO );
    } else {
        sendNetworkEvent( p, "s " + index );
    }
}


void objectiveManager::OnNextObjectiveSet( object team, float objectiveIndex ) {
    if( sys.doClientSideStuff() ) {
        sys.setGUIFloat( GUI_GLOBALS_HANDLE, "mapinfo.currentObjective", objectiveIndex );
        sys.setGUIHandle( GUI_GLOBALS_HANDLE, "mapinfo.gdfCurrentObjective", objManager.getShortDescription( gdfTeam, objectiveIndex ) );
        sys.setGUIHandle( GUI_GLOBALS_HANDLE, "mapinfo.stroggCurrentObjective", objManager.getShortDescription( stroggTeam, objectiveIndex ) );
    }
}

void objectiveManager::HandleObjectiveEntity() {
    entity ent = sys.getEntityByID( sys.argv( 1 ) );
    float index = sys.argvf( 2 );

    G_SetPrimaryObjectiveIndex( index );

    if ( currentPrimaryObjective != $null_entity ) {
        currentPrimaryObjective.vMakePrimaryObjective( false );
    }

    currentPrimaryObjective = ent;

    if ( currentPrimaryObjective != $null_entity ) {        
        currentPrimaryObjective.vMakePrimaryObjective( true );        
    }
}

void objectiveManager::HandleCenterPrint() {
    handle h = sys.stringToHandle( sys.argv( 1 ) );
    float endTime = sys.argvf( 2 );

    float index;
    float count = sys.argc() - 3;
    for ( index = 0; index < count; index++ ) {
        string ident = sys.strLeft( sys.argv( 3 + index ), 1 );
        string value = sys.strSkip( sys.argv( 3 + index ), 1 );

        if ( ident == "P" ) {
            // plain text, likely a player name
            sys.pushLocString( sys.toWStr( value ) );
            continue;
        }

        if ( ident == "H" ) {
            // localisation handle
            sys.pushLocStringIndex( sys.stringToHandle( value ) );
            continue;
        }
    }

    SetupCPrintHUD( sys.localizeStringIndexArgs( h ), endTime );
}

void objectiveManager::OnNetworkEvent() {
    string message = sys.argv( 0 );

    if ( message == "cp" ) {
        HandleCenterPrint();
        return;
    }

    if ( message == "s" ) {
        sys.startSoundDirect( GetSoundShaderName( sys.argvf( 1 ) ), SND_PLAYER_VO );
        return;
    }

    if ( message == "oe" ) {
        HandleObjectiveEntity();
        return;
    }
}

void objectiveManager::InitObjectiveUI( float index, handle descriptionGDF, handle descriptionStrogg, handle miniDescriptionGDF, handle miniDescriptionStrogg, string materialGDF, string materialStrogg ) {
    if ( sys.getLocalPlayer() != $null_entity ) {
        sys.setGUIHandle( GUI_GLOBALS_HANDLE, "mapinfo.stroggObjective" + index, descriptionStrogg );
        sys.setGUIHandle( GUI_GLOBALS_HANDLE, "mapinfo.gdfObjective" + index, descriptionGDF );

        sys.setGUIString( GUI_GLOBALS_HANDLE, "mapinfo.stroggObjectiveMat" + index, materialStrogg );
        sys.setGUIString( GUI_GLOBALS_HANDLE, "mapinfo.gdfObjectiveMat" + index, materialGDF );
    }

    // tell the game what the short descriptions are
    objManager.setShortDescription( gdfTeam, index, miniDescriptionGDF );
    objManager.setShortDescription( stroggTeam, index, miniDescriptionStrogg );    
}

vector objectiveManager::GetGDFBasePosition() {
    return mapObject.GetGDFBasePosition();
}

void objectiveManager::SetupCPrintHUD( wstring text, float endTime ) {
    if ( sys.getLocalPlayer() != $null_entity ) {
        sys.setGUIFloat( GUI_GLOBALS_HANDLE, "gameHud.successTextTime", endTime );    
        sys.setGUIWString( GUI_GLOBALS_HANDLE, "gameHud.successText", text );
    }
}

void objectiveManager::PushCPrintString( string arg ) {
    if ( sys.isClient() ) {
        return;
    }

    numPrintArgs = numPrintArgs + 1;
    printArgs = printArgs + " \"P" + arg + "\"";
}

void objectiveManager::PushCPrintHandle( handle h ) {
    if ( sys.isClient() ) {
        return;
    }

    numPrintArgs = numPrintArgs + 1;
    printArgs = printArgs + " H" + sys.handleToString( h );
}

void objectiveManager::RefreshObjectiveEntity() {
    entity old = currentPrimaryObjective;
    float oldIndex = g_primaryObjectiveIndex;
    SetObjectiveEntity( $null_entity, -1 );
    SetObjectiveEntity( old, oldIndex );
}

void objectiveManager::SetObjectiveEntity( entity ent, float index ) {
    if ( sys.isClient() ) {
        return;
    }

    if ( currentPrimaryObjective == ent ) {
        return;
    }

    SendObjectiveChangedEvent( ent, $null_entity, index );
}

void objectiveManager::SendObjectiveChangedEvent( entity ent, entity p, float index ) {
    string spawnId;
    if ( ent == $null_entity ) {
        spawnId = "0";
    } else {
        spawnId = ent.getSpawnID();
    }

    string message = "oe " + spawnId + " " + index;

    if ( sys.isServer() ) {    
        sendNetworkEvent( p, message );
    }

    if ( p == $null_entity ) {
        sys.setActionCommand( message );
        OnNetworkEvent();
    }
}


void objectiveManager::CPrintEvent( handle h, object team ) {
    CPrintEventRanged( h, team, vec3_origin, -1.f );
}

void objectiveManager::CPrintEventRanged( handle h, object team, vector org, float maxRange ) {
    if ( sys.isClient() ) {
        return;
    }

    float endTime = ( sys.getTime() + 10 ) * 1000;

    string message = "cp\"" + sys.handleToString( h ) + "\"" + endTime + printArgs; // Gordon: printargs should always be last, as it is variable length

    numPrintArgs = 0.f;
    printArgs = "";

    if ( sys.isServer() ) {    
        float rangeSqr = maxRange * maxRange;

        float maxClients = sys.getMaxClients();
        float index;
        for ( index = 0; index < maxClients; index++ ) {
            entity p = sys.getClient( index );
            if ( p == $null_entity ) {
                continue;
            }

            if ( team != $null ) {
                if ( team != p.getGameTeam() ) {
                    continue;
                }
            }

            if ( maxRange > 0.f ) {
                if ( sys.vecLengthSquared( p.getWorldOrigin() - org ) > rangeSqr ) {
                    continue;
                }                
            }

            sendNetworkEvent( p, message );
        }
    }

    // this is solely for the benefit of devmap
    entity local = sys.getLocalPlayer();
    if ( local != $null_entity ) {
        if ( team == $null || local.getGameTeam() == team ) {
            sys.setActionCommand( message );
            OnNetworkEvent();
        }
    }
}

void objectiveManager::ScudExploded( entity scud ) {
    if ( mapObject != $null_entity ) {
        entity team = scud.getGameTeam();
        mapObject.ScudExploded( scud );
    }
}

void objectiveManager::OnWriteInitialReliableMessages( entity p ) {
    if ( !p.isLocalPlayer() ) {
        SendObjectiveChangedEvent( currentPrimaryObjective, p, g_primaryObjectiveIndex );
    }
}

void objectiveManager::PlayCountdownVO( string sound, float seconds ) {
    if ( GetCountdownTime() > seconds - 2.f ) {
        PlaySound( gdfTeam.getKey( sound ), gdfTeam );
        PlaySound( stroggTeam.getKey( sound ), stroggTeam );
    }
}

void G_SetObjectiveManager( object o ) {
    objManager = o;
}

handle mapObject_Base::GetObjectiveMessage( float index ) {
    return sys.localizeString( "maps/obj/complete_obj_generic" );
}




// Gordon: putting this here sucks
void team_base::PlayIntelRepairedMessage() {
    objManager.PlaySound( getKey( "snd_intel_repaired" ), self );
}

void team_base::PlayIntelDamagedMessage() {
    objManager.PlaySound( getKey( "snd_intel_damaged" ), self );
}