/* =============================================================================== destructible_objective.script generic script for objectives which have to be destroyed =============================================================================== */ /* ===================================================================== destructible_objective_base ===================================================================== */ object destructible_objective_base { void preinit(); void init(); void destroy(); void OnComplete( entity inflictor, entity other ); void vCreateMission(); void vFreeMission(); void vCompleteMission(); boolean vDisablePlantCharge() { return ( objManager.gameState != GS_GAMEON ); } void vOnContextDefend( entity p ); void vOnContextDestroy( entity p ); float objectiveIndex; handle destroyMessage; task missionTask; float destructionProficiency; float splashDamageIndex; flashpoint_obj flashpoint; } void destructible_objective_base::preinit() { destructionProficiency = GetProficiency( getKey( "prof_destroy" ) ); splashDamageIndex = GetDamage( getKey( "dmg_splash_damage" ) ); } void destructible_objective_base::init() { setGameTeam( sys.getTeam( getKey( "team" ) ) ); objectiveIndex = getFloatKeyWithDefault( "objective_index", -1 ); string destroyMessageKey = getKey( "destroy_message" ); if ( destroyMessageKey != "" ) { destroyMessage = sys.localizeString( destroyMessageKey ); } else { destroyMessage = invalid_handle; } } void destructible_objective_base::destroy() { vFreeMission(); if ( flashpoint != $null ) { delete flashpoint; } } void destructible_objective_base::OnComplete( entity inflictor, entity other ) { if ( sys.isClient() ) { return; } boolean increaseStat = true; if ( inflictor != $null_entity ) { if ( inflictor.vInhibitStats() ) { increaseStat = false; } } player p = other; if ( p != $null_entity && increaseStat ) { if ( destructionProficiency != -1 ) { p.giveProficiency( destructionProficiency, 1.f, missionTask, "destruction objective completed" ); } } team_base team = other.getGameTeam(); string statName = team.getName(); if ( objectiveIndex != -1 ) { statName = statName + "_primary"; } else { if ( destroyMessage != invalid_handle ) { if ( p == $null_entity ) { objManager.PushCPrintHandle( g_locStr_Someone ); } else { objManager.PushCPrintString( other.getUserName() ); } objManager.CPrintEvent( destroyMessage, $null ); } statName = statName + "_secondary"; } statName = statName + "_objective_destroyed"; if ( p != $null_entity && increaseStat ) { sys.increaseStatInt( sys.allocStatInt( statName ), p.getEntityNumber(), 1 ); sys.increaseStatInt( sys.allocStatInt( "total_objectives_completed" ), p.getEntityNumber(), 1 ); } if ( objectiveIndex != -1 ) { objManager.CompleteObjective( objectiveIndex, other ); } objManager.OnDestructionComplete( self ); G_PlayObjectiveCompletedRollEnt( self ); objManager.PlaySound( getKey( "snd_destroyed_strogg" ), stroggTeam ); objManager.PlaySound( getKey( "snd_destroyed_gdf" ), gdfTeam ); if ( splashDamageIndex != -1 ) { sys.applyRadiusDamage( getWorldOrigin(), self, $null_entity, self, $null_entity, splashDamageIndex, 1.0f, 1.0f ); } remove(); } void destructible_objective_base::vCreateMission() { vFreeMission(); missionTask = taskManager.allocEntityTask( GetPlayerTask( getKey( "task_destroy" ) ), self ); } void destructible_objective_base::vFreeMission() { if ( missionTask != $null ) { missionTask.free(); missionTask = $null; } } void destructible_objective_base::vCompleteMission() { if ( missionTask != $null ) { missionTask.complete(); missionTask.free(); missionTask = $null; } } void destructible_objective_base::vOnContextDefend( entity p ) { player local = sys.getLocalViewPlayer(); if ( local == $null_entity || p == $null_entity ) { return; } if ( flashpoint != $null ) { delete flashpoint; } flashpoint = new flashpoint_obj; flashpoint.SetOwner( self ); flashpoint.SetMaterial( getKey( "mtr_icon_flash_defend" ) ); } void destructible_objective_base::vOnContextDestroy( entity p ) { player local = sys.getLocalViewPlayer(); if ( local == $null_entity || p == $null_entity ) { return; } if ( flashpoint != $null ) { delete flashpoint; } flashpoint = new flashpoint_obj; flashpoint.SetOwner( self ); flashpoint.SetMaterial( getKey( "mtr_icon_flash" ) ); } /* ===================================================================== destructible_objective_strategic Used for Scud targets and the like ===================================================================== */ object destructible_objective_strategic : destructible_objective_base { void preinit(); void syncFields(); boolean OnPreDamage( entity inflictor, entity attacker ); void OnKilled( entity inflictor, entity attacker, float damage, vector direction, float location ); void vSetState( float state ); void UpdateObjectiveProgress(); void SetObjectiveIndicator(); void OnIsPrimaryObjectiveChanged(); void vMakePrimaryObjective( boolean value ); void UpdateObjectiveThread(); void ClearObjectiveIndicator(); void SetObjectiveReminderTime( float time ); string vGetObjectiveString(); float nextObjectiveReminderTime; float progress; boolean isPrimaryObjective; string guiStr; } void destructible_objective_strategic::preinit() { guiStr = "destroyObjective1"; } void destructible_objective_strategic::syncFields() { syncBroadcast( "progress" ); } void destructible_objective_strategic::vSetState( float state ) { progress = state; } boolean destructible_objective_strategic::OnPreDamage( entity inflictor, entity attacker ) { if( getEntityAllegiance( inflictor ) == TA_FRIEND ) { // e.g. stop stogg destroying the last objective and then winning the map :) return false; } return true; } void destructible_objective_strategic::OnKilled( entity inflictor, entity attacker, float damage, vector direction, float location ) { OnComplete( inflictor, attacker ); } void destructible_objective_strategic::UpdateObjectiveThread() { waitUntil( objManager.gameState == GS_GAMEON ); objManager.PlaySound( getKey( "snd_intro_strogg" ), stroggTeam ); objManager.PlaySound( getKey( "snd_intro_gdf" ), gdfTeam ); SetObjectiveReminderTime( sys.getTime() + OBJECTIVEMESSAGE_WAIT_TIME ); while ( true ) { UpdateObjectiveProgress(); if ( !sys.isClient() ) { if ( sys.getTime() >= nextObjectiveReminderTime ) { if ( objManager.gameState == GS_GAMEON ) { objManager.PlaySound( getKey( "snd_reminder_strogg" ), stroggTeam ); objManager.PlaySound( getKey( "snd_reminder_gdf" ), gdfTeam ); } SetObjectiveReminderTime( sys.getTime() + OBJECTIVEMESSAGE_WAIT_TIME ); } } sys.waitFrame(); } } void destructible_objective_strategic::SetObjectiveIndicator() { UpdateObjectiveProgress(); thread UpdateObjectiveThread(); if ( sys.doClientSideStuff() ) { sys.setGUIFloat( GUI_GLOBALS_HANDLE, guiStr + ".active", 1.f ); } } void destructible_objective_strategic::UpdateObjectiveProgress() { if ( sys.doClientSideStuff() ) { sys.setGUIFloat( GUI_GLOBALS_HANDLE, guiStr + ".progress", progress ); sys.setGUIFloat( GUI_GLOBALS_HANDLE, guiStr + ".disarmProgress", 0.f ); } } void destructible_objective_strategic::OnIsPrimaryObjectiveChanged() { ClearObjectiveIndicator(); if ( isPrimaryObjective ) { SetObjectiveIndicator(); } } void destructible_objective_strategic::ClearObjectiveIndicator() { sys.killThread( "UpdateObjectiveThread_" + getName() ); if ( sys.doClientSideStuff() ) { sys.setGUIFloat( GUI_GLOBALS_HANDLE, guiStr + ".active", 0.f ); } } void destructible_objective_strategic::vMakePrimaryObjective( boolean value ) { isPrimaryObjective = value; OnIsPrimaryObjectiveChanged(); } void destructible_objective_strategic::SetObjectiveReminderTime( float time ) { if ( time > nextObjectiveReminderTime ) { nextObjectiveReminderTime = time; } } string destructible_objective_strategic::vGetObjectiveString() { return guiStr; } /* ===================================================================== destructible_flyerhive_objective_strategic Flyerhive objective ===================================================================== */ object destructible_flyerhive_objective_strategic : destructible_objective_strategic { void preinit(); } void destructible_flyerhive_objective_strategic::preinit() { guiStr = "flyerhiveObjective"; } /* ===================================================================== destructible_objective Destructibles that you use an HE charge on ===================================================================== */ object destructible_objective : destructible_objective_base { void preinit(); void destroy(); void syncFields(); float OnUpdateCrosshairInfo( entity p ); float OnActivate( entity p, float distance ); float GetActivateCode( entity p, float distance ); boolean vChargePlaced( entity charge, entity other ); void vChargeDisarmed( entity charge, entity other ); void vChargeExploded( entity charge, entity other ); boolean HasDestroyContext( entity other ); boolean vIsDestructibleObjective() { return true; } void UpdateCurrentCharge( entity ignoreEnt ); void UpdateObjectiveProgress(); void SetObjectiveIndicator(); void OnIsPrimaryObjectiveChanged(); void vMakePrimaryObjective( boolean value ); void vSetObjectiveString( string message ); void UpdateObjectiveThread(); void ClearObjectiveIndicator(); void SetObjectiveReminderTime( float time ); float vGetDisarmProficiency(); string vGetObjectiveString(); handle objectName; handle progressMessage; handle disarmMessage; entity currentCharge; boolean isPrimaryObjective; boolean vIsPrimaryObjective() { return isPrimaryObjective; } entity vGetSpectateEntity() { return currentCharge; } float disarmProficiency; float useMeToolTip1; float useMeToolTip2; float nextObjectiveReminderTime; string objString; entity proxy; } void destructible_objective::preinit() { useMeToolTip1 = GetToolTip( getKey( "tt_intro_use_me_1" ) ); useMeToolTip2 = GetToolTip( getKey( "tt_intro_use_me_2" ) ); disarmProficiency = GetProficiency( getKey( "prof_disarm" ) ); objectName = sys.localizeString( getKey( "object_name" ) ); progressMessage = sys.localizeString( getKeyWithDefault( "progress_message", "maps/generic/obj_planted" ) ); disarmMessage = sys.localizeString( getKeyWithDefault( "disarm_message", "maps/generic/obj_disarmed" ) ); objString = "destroyObjective1"; } void destructible_objective::destroy() { if ( isPrimaryObjective ) { ClearObjectiveIndicator(); } } void destructible_objective::syncFields() { syncBroadcast( "currentCharge" ); } float destructible_objective::vGetDisarmProficiency() { return disarmProficiency; } void destructible_objective::vSetObjectiveString( string message ) { objString = message; } string destructible_objective::vGetObjectiveString() { return objString; } void destructible_objective::SetObjectiveReminderTime( float time ) { if ( proxy != $null_entity ) { proxy.vSetObjectiveReminderTime( time ); } else if ( time > nextObjectiveReminderTime ) { nextObjectiveReminderTime = time; } } boolean destructible_objective::HasDestroyContext( entity other ) { if ( !takesDamage() ) { return false; } float allegiance = getEntityAllegiance( other ); if ( allegiance == TA_ENEMY ) { return true; } return false; } float destructible_objective::GetActivateCode( entity p, float distance ) { if ( objManager.gameState != GS_GAMEON ) { return AK_INWARMUP; } if ( !takesDamage() ) { return AK_NONE; } if ( p.getHealth() <= 0 ) { return AK_NONE; } if ( p.getViewingEntity() != p ) { return AK_NONE; } float allegiance = getEntityAllegiance( p ); if ( distance < DISTANCE_FOR_ACTION ) { if ( allegiance == TA_ENEMY ) { if ( p.vHasActionItem( AK_PLANT ) ) { return AK_PLANT; } } } return AK_NONE; } float destructible_objective::OnActivate( entity p, float distance ) { if ( p.vSelectActionItem( GetActivateCode( p, distance ) ) ) { return 1.f; } return 0.f; } float destructible_objective::OnUpdateCrosshairInfo( entity p ) { if ( !sys.doClientSideStuff() ) { return 1.f; } if ( !takesDamage() ) { return 0.0f; } float allegiance = getEntityAllegiance( p ); vector color = GetAllegianceColor( allegiance ); float distance = chGetDistance(); chSetNumLines( 0 ); float index; if ( p != $null_entity ) { 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 ) ) { 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 ); } } } } } else if ( code == AK_INWARMUP ) { if ( p.isLocalPlayer() && distance < DISTANCE_FOR_ACTION ) { team_base team = p.getGameTeam(); if ( team != $null_entity ) { p.sendToolTip( GetToolTip( getKey( "tt_noobjective" ) ) ); } } } } index = chAddLine(); chSetLineTextIndex( index, objectName ); chSetLineColor( index, color, 1.f ); chSetLineType( index, CI_TEXT ); chSetLineSize( index, 0, 0 ); return 1.f; } boolean destructible_objective::vChargePlaced( entity charge, entity other ) { if ( !takesDamage() ) { return false; } if ( !sys.isClient() ) { SetObjectiveReminderTime( sys.getTime() + OBJECTIVEMESSAGE_WAIT_TIME ); if ( currentCharge == $null_entity ) { currentCharge = charge; // direct set so we always get a sound in 5 seconds nextObjectiveReminderTime = sys.getTime() + 5.f; } if ( other != $null_entity ) { //mal: this player has an armed charge out there in the world on an obj - mark it as such so that the bots can understand! objManager.setBotActionStateForEvent( ACTION_STATE_PLANTED, charge ); } } objManager.PushCPrintString( other.getUserName() ); objManager.CPrintEvent( progressMessage, $null ); objManager.PlaySound( getKey( "snd_planted_strogg" ), stroggTeam ); objManager.PlaySound( getKey( "snd_planted_gdf" ), gdfTeam ); return true; } void destructible_objective::vChargeExploded( entity charge, entity other ) { if ( !takesDamage() ) { return; } OnComplete( charge, other ); } void destructible_objective::UpdateCurrentCharge( entity ignoreEnt ) { float count = entitiesOfCollection( "charges" ); float i; float bestTime = 99999999.f; for ( i = 0; i < count; i++ ) { entity charge = getBoundsCacheEntity( i ); if ( charge == ignoreEnt ) { continue; } entity target = charge.vGetCurrentTarget(); if ( target != self ) { continue; } float t = charge.vGetFuseRemaining(); if ( t > bestTime ) { continue; } bestTime = t; currentCharge = charge; } } void destructible_objective::vChargeDisarmed( entity charge, entity other ) { if ( !takesDamage() ) { return; } if ( !sys.isClient() ) { if ( currentCharge == charge ) { UpdateCurrentCharge( currentCharge ); } objManager.setBotActionStateForEvent( ACTION_STATE_DEFUSED, charge ); //mal: a charge that was planted has been defused. Let the action know. } objManager.PushCPrintString( other.getUserName() ); objManager.CPrintEvent( disarmMessage, $null ); objManager.PlaySound( getKey( "snd_disarmed_strogg" ), stroggTeam ); objManager.PlaySound( getKey( "snd_disarmed_gdf" ), gdfTeam ); } void destructible_objective::UpdateObjectiveThread() { waitUntil( objManager.gameState == GS_GAMEON ); sys.wait( 2.0f ); if ( proxy == $null_entity ) { objManager.PlaySound( getKey( "snd_intro_strogg" ), stroggTeam ); objManager.PlaySound( getKey( "snd_intro_gdf" ), gdfTeam ); } SetObjectiveReminderTime( sys.getTime() + OBJECTIVEMESSAGE_WAIT_TIME ); while ( true ) { UpdateObjectiveProgress(); if ( !sys.isClient() && proxy == $null_entity ) { if ( sys.getTime() >= nextObjectiveReminderTime ) { if ( objManager.gameState == GS_GAMEON ) { if ( currentCharge == $null_entity ) { objManager.PlaySound( getKey( "snd_reminder_strogg" ), stroggTeam ); objManager.PlaySound( getKey( "snd_reminder_gdf" ), gdfTeam ); } else { objManager.PlaySound( getKey( "snd_defend_strogg" ), stroggTeam ); objManager.PlaySound( getKey( "snd_defend_gdf" ), gdfTeam ); } } SetObjectiveReminderTime( sys.getTime() + OBJECTIVEMESSAGE_WAIT_TIME ); } } sys.waitFrame(); } } void destructible_objective::SetObjectiveIndicator() { UpdateObjectiveProgress(); thread UpdateObjectiveThread(); if ( sys.doClientSideStuff() ) { sys.setGUIFloat( GUI_GLOBALS_HANDLE, objString + ".active", 1.f ); } } void destructible_objective::UpdateObjectiveProgress() { if ( sys.doClientSideStuff() ) { if ( currentCharge == $null_entity ) { sys.setGUIFloat( GUI_GLOBALS_HANDLE, objString + ".progress", 0.f ); sys.setGUIFloat( GUI_GLOBALS_HANDLE, objString + ".disarmProgress", 0.f ); } else { float frac = ( currentCharge.vGetFuseRemaining() / currentCharge.vGetFuseLength() ); sys.setGUIFloat( GUI_GLOBALS_HANDLE, objString + ".progress", 1.f - frac ); sys.setGUIFloat( GUI_GLOBALS_HANDLE, objString + ".disarmProgress", currentCharge.vGetPliersProgressBarValue( AC_DISARM ) ); } } } void destructible_objective::OnIsPrimaryObjectiveChanged() { ClearObjectiveIndicator(); if ( isPrimaryObjective ) { SetObjectiveIndicator(); } } void destructible_objective::ClearObjectiveIndicator() { sys.killThread( "UpdateObjectiveThread_" + getName() ); if ( sys.doClientSideStuff() ) { sys.setGUIFloat( GUI_GLOBALS_HANDLE, objString + ".active", 0.f ); } } void destructible_objective::vMakePrimaryObjective( boolean value ) { isPrimaryObjective = value; OnIsPrimaryObjectiveChanged(); } /* ===================================================================== destructible_objective_trigger Trigger zone around a destructible objective describing the area that you can plant it in that will destroy the objective ===================================================================== */ object destructible_objective_trigger { void OnPostMapSpawn(); void syncFields(); boolean vChargePlaced( entity charge, entity other ); entity vGetCurrentTarget(); entity theObjective; } void destructible_objective_trigger::syncFields() { syncBroadcast( "theObjective" ); } void destructible_objective_trigger::OnPostMapSpawn() { if ( !sys.isClient() ) { theObjective = getEntityKey( "target" ); if ( theObjective == $null_entity ) { sys.error( "destructible_objective_trigger could not find target: " + getKey( "target" ) ); } } } boolean destructible_objective_trigger::vChargePlaced( entity charge, entity other ) { if ( theObjective.getEntityAllegiance( charge ) != TA_ENEMY ) { return false; } return theObjective.vChargePlaced( charge, other ); } entity destructible_objective_trigger::vGetCurrentTarget() { return theObjective; } /* ===================================================================== destructible_objective_dual_proxy ===================================================================== */ object destructible_objective_dual_proxy { void syncFields(); void destroy(); void preinit(); void OnTarget1Changed(); void OnTarget2Changed(); destructible_objective target1; destructible_objective target2; task defendTask; boolean isPrimaryObjective; float nextObjectiveReminderTime; float objectiveIndex; void UpdateObjectiveThread(); void vInitDefendMission( object missionTask ); void vCompleteSubMission( entity other ); entity vGetSpectateEntity(); boolean vIsObjectiveComplete(); void OnPostMapSpawn(); void OnIsPrimaryObjectiveChanged(); void vMakePrimaryObjective( boolean value ); } void destructible_objective_dual_proxy::preinit() { objectiveIndex = getFloatKeyWithDefault( "objective_index", -1 ); } void destructible_objective_dual_proxy::syncFields() { syncBroadcast( "target1" ); syncCallback( "target1", "OnTarget1Changed" ); syncBroadcast( "target2" ); syncCallback( "target2", "OnTarget2Changed" ); } void destructible_objective_dual_proxy::destroy() { vFreeMission(); if ( isPrimaryObjective ) { if ( target1 != $null_entity ) { target1.vMakePrimaryObjective( false ); } if ( target2 != $null_entity ) { target2.vMakePrimaryObjective( false ); } } } void destructible_objective_dual_proxy::vMakePrimaryObjective( boolean value ) { if ( isPrimaryObjective == value ) { return; } isPrimaryObjective = value; OnIsPrimaryObjectiveChanged(); } void destructible_objective_dual_proxy::UpdateObjectiveThread() { waitUntil( objManager.gameState == GS_GAMEON ); sys.wait( 2.0f ); objManager.PlaySound( getKey( "snd_intro_strogg" ), stroggTeam ); objManager.PlaySound( getKey( "snd_intro_gdf" ), gdfTeam ); if ( !sys.isClient() ) { while ( true ) { if ( sys.getTime() >= nextObjectiveReminderTime ) { if ( objManager.gameState == GS_GAMEON ) { objManager.PlaySound( getKey( "snd_reminder_strogg" ), stroggTeam ); objManager.PlaySound( getKey( "snd_reminder_gdf" ), gdfTeam ); } vSetObjectiveReminderTime( sys.getTime() + OBJECTIVEMESSAGE_WAIT_TIME ); } sys.waitFrame(); } } } void destructible_objective_dual_proxy::OnIsPrimaryObjectiveChanged() { if ( target1 != $null_entity ) { target1.vMakePrimaryObjective( isPrimaryObjective ); } if ( target2 != $null_entity ) { target2.vMakePrimaryObjective( isPrimaryObjective ); } if ( isPrimaryObjective ) { thread UpdateObjectiveThread(); } else { sys.killThread( "UpdateObjectiveThread_" + getName() ); } } void destructible_objective_dual_proxy::OnTarget1Changed() { if ( target1 != $null_entity ) { target1.vSetObjectiveString( "destroyObjective1" ); target1.proxy = self; if ( isPrimaryObjective ) { target1.vMakePrimaryObjective( true ); } } } void destructible_objective_dual_proxy::OnTarget2Changed() { if ( target2 != $null_entity ) { target2.vSetObjectiveString( "destroyObjective2" ); target2.proxy = self; if ( isPrimaryObjective ) { target2.vMakePrimaryObjective( true ); } } } void destructible_objective_dual_proxy::OnPostMapSpawn() { if ( !sys.isClient() ) { target1 = getEntityKey( "target1" ); if ( target1 == $null_entity ) { sys.error( "destructible_objective_dual_proxy::OnPostMapSpawn target1 not found or is not a destructible objective" ); } else { OnTarget1Changed(); } target2 = getEntityKey( "target2" ); if ( target2 == $null_entity ) { sys.error( "destructible_objective_dual_proxy::OnPostMapSpawn target2 not found or is not a destructible objective" ); } else { OnTarget2Changed(); } } } void destructible_objective_dual_proxy::vSetObjectiveReminderTime( float time ) { if ( time > nextObjectiveReminderTime ) { nextObjectiveReminderTime = time; } } void destructible_objective_dual_proxy::vInitDefendMission( object missionTask ) { defendTask = missionTask; if ( target1 == $null_entity ) { defendTask.setWayPointState( 0, false ); } else { defendTask.setLocation( 0, target1.getWorldOrigin() ); } if ( target2 == $null_entity ) { defendTask.setWayPointState( 1, false ); } else { defendTask.setLocation( 1, target2.getWorldOrigin() ); } } void destructible_objective_dual_proxy::vCompleteSubMission( entity other ) { if ( other == target1 ) { defendTask.setWayPointState( 0, false ); } else if ( other == target2 ) { defendTask.setWayPointState( 1, false ); } } entity destructible_objective_dual_proxy::vGetSpectateEntity() { if ( target1 == $null_entity ) { return target2.vGetSpectateEntity(); } if ( target2 == $null_entity ) { return target1.vGetSpectateEntity(); } entity charge1 = target1.vGetSpectateEntity(); entity charge2 = target2.vGetSpectateEntity(); if ( charge1 == $null_entity ) { return charge2; } if ( charge2 == $null_entity ) { return charge1; } if ( charge1.vGetFuseRemaining() <= charge2.vGetFuseRemaining() ) { return charge1; } return charge2; } boolean destructible_objective_dual_proxy::vIsObjectiveComplete() { if ( target1 == $null_entity && target2 == $null_entity ) { return true; } return false; }