/* =============================================================================== constructible_objective base class for objectives that get constructed =============================================================================== */ object constructible_objective { void preinit(); void destroy(); void syncFields(); boolean CheckActionCode_Base( entity p, float actionCode ); boolean vCheckActionCode( entity p, float actionCode ) { return CheckActionCode_Base( p, actionCode ); } void vSetOwner( entity o ) { ; } void vConstruct( entity p ); void OnConstructionStarted() {} void OnConstructionFinished( entity p ) {} void OnConstructionFizzled(); void vCreateMission(); void vFreeMission(); void vCompleteMission(); float OnActivate( entity p, float distance ); float GetActivateCode( entity p, float distance ); boolean HasConstructContext( entity other ); void OnDisabledChanged(); void OnIsPrimaryObjectiveChanged(); void OnCounterChanged(); void UpdateObjectiveProgress(); void UpdateObjectiveProgress_Base(); void SetObjectiveIndicator(); void ClearObjectiveIndicator(); float CalcObjectiveProgress(); void UpdateObjectiveThread(); void SetObjectiveReminderTime( float time ); float vGetPliersProgressBarValue( float action ); float OnUpdateCrosshairInfo( entity p ); void FinishObjective_Base(); void StartObjective_Base(); void vFinishObjective() { FinishObjective_Base(); } void vStartObjective() { StartObjective_Base(); } void vMakePrimaryObjective( boolean value ); void KillFizzleThread(); void CreateFizzleThread( float delay ); void FizzleThread( float delay ); entity GetConstructionStage() { return $null_entity; } void OnConstructing() { } void ShowAndEnableClip(); void HideAndDisableClip(); boolean vIsPrimaryObjective(); boolean IsPrimaryConstruction(); string vGetObjectiveString() { return "constructObjective"; } boolean isPrimaryObjective; float totalCount; float constructionCount; float counter; float fizzleTime; boolean fizzleThreadActive; float fizzleEndTime; float constructProficiency; boolean constructed; entity constructor; float lastConstructTime; float lastWarningUpdate; float objectiveIndex; handle progressMessage; boolean forceShowProgress; float nextProgressMessageTime; boolean disabled; float useMeToolTip1; float useMeToolTip2; float nextObjectiveReminderTime; handle objectName; handle constructedMessage; task missionTask; float dmgIndex; boolean fizzling; } void constructible_objective::syncFields() { sync( "counter" ); syncBroadcast( "fizzling" ); syncBroadcast( "disabled" ); syncCallback( "counter", "OnCounterChanged" ); syncCallback( "disabled", "OnDisabledChanged" ); } void constructible_objective::OnDisabledChanged() { if ( disabled ) { vFinishObjective(); } else { vStartObjective(); } } void constructible_objective::OnIsPrimaryObjectiveChanged() { ClearObjectiveIndicator(); if ( isPrimaryObjective ) { SetObjectiveIndicator(); } } void constructible_objective::OnCounterChanged() { OnConstructing(); } void constructible_objective::SetObjectiveReminderTime( float time ) { if ( time > nextObjectiveReminderTime ) { nextObjectiveReminderTime = time; } } void constructible_objective::UpdateObjectiveProgress() { UpdateObjectiveProgress_Base(); } void constructible_objective::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 constructible_objective::SetObjectiveIndicator() { UpdateObjectiveProgress(); thread UpdateObjectiveThread(); if ( sys.doClientSideStuff() ) { sys.setGUIFloat( GUI_GLOBALS_HANDLE, "constructObjective.active", 1.f ); sys.setGUIFloat( GUI_GLOBALS_HANDLE, "constructObjective.stage1", 0.f ); sys.setGUIFloat( GUI_GLOBALS_HANDLE, "constructObjective.stage2", 0.f ); } } void constructible_objective::ClearObjectiveIndicator() { sys.killThread( "UpdateObjectiveThread_" + getName() ); if ( sys.doClientSideStuff() ) { sys.setGUIFloat( GUI_GLOBALS_HANDLE, "constructObjective.active", 0 ); } } void constructible_objective::UpdateObjectiveProgress_Base() { if ( sys.doClientSideStuff() ) { sys.setGUIFloat( GUI_GLOBALS_HANDLE, "constructObjective.stage1", CalcObjectiveProgress() ); } } float constructible_objective::CalcObjectiveProgress() { return counter / constructionCount; } void constructible_objective::FinishObjective_Base() { if ( !sys.isClient() ) { disabled = true; } HideAndDisableClip(); } void constructible_objective::StartObjective_Base() { if ( !sys.isClient() ) { disabled = false; } ShowAndEnableClip(); } void constructible_objective::vMakePrimaryObjective( boolean value ) { isPrimaryObjective = value; OnIsPrimaryObjectiveChanged(); } void constructible_objective::preinit() { counter = 0; objectiveIndex = getFloatKeyWithDefault( "objective_index", -1 ); forceShowProgress = getIntKey( "force_show_progress" ); useMeToolTip1 = GetToolTip( getKey( "tt_intro_use_me_1" ) ); useMeToolTip2 = GetToolTip( getKey( "tt_intro_use_me_2" ) ); constructionCount = gameRules.GetFloatKeyWithSuffix( self, "construct_count", 100.f ); totalCount = constructionCount; fizzleTime = getFloatKeyWithDefault( "fizzle_time", 60.f ); progressMessage = sys.localizeString( getKeyWithDefault( "progress_message", "maps/generic/obj_construct" ) ); constructProficiency = GetProficiency( getKey( "prof_construct" ) ); objectName = sys.localizeString( getKey( "object_name" ) ); string temp = getKey( "constructed_message" ); if ( temp != "" ) { constructedMessage = sys.localizeString( temp ); } else { constructedMessage = invalid_handle; } nextProgressMessageTime = 0; dmgIndex = GetDamage( getKey( "dmg_kill" ) ); } void constructible_objective::destroy() { if ( isPrimaryObjective ) { ClearObjectiveIndicator(); } vFreeMission(); } boolean constructible_objective::CheckActionCode_Base( entity p, float actionCode ) { if ( objManager.gameState != GS_GAMEON ) { return false; } if ( getEntityAllegiance( p ) != TA_FRIEND ) { return false; } if ( actionCode == AC_CONSTRUCT ) { return true; } return false; } void constructible_objective::vConstruct( entity p ) { float time = sys.getTime(); entity oldConstructor = constructor; if ( constructor == $null_entity || lastConstructTime < time - 2 ) { constructor = p; if ( lastConstructTime < time - 10 ) { oldConstructor = $null_entity; } } if ( p == constructor && ( forceShowProgress || objectiveIndex >= 0 ) ) { if ( sys.getTime() > nextProgressMessageTime ) { objManager.PushCPrintString( p.getUserName() ); objManager.CPrintEvent( progressMessage, $null ); nextProgressMessageTime = sys.getTime() + 5.f; } if ( constructor != oldConstructor ) { objManager.PlaySound( getKey( "snd_constructing_strogg" ), stroggTeam ); objManager.PlaySound( getKey( "snd_constructing_gdf" ), gdfTeam ); SetObjectiveReminderTime( sys.getTime() + ( OBJECTIVEMESSAGE_WAIT_TIME * 0.5f ) ); } } lastConstructTime = time; team_base team = p.getGameTeam(); if ( counter >= constructionCount ) { counter = 0; } if ( counter == 0 ) { OnConstructionStarted(); } float count = 1; if ( team.HasConstructionBonus( p ) ) { count = count * 1.25f; } counter = counter + count; if ( !sys.isClient() ) { if ( constructProficiency != -1 ) { p.giveProficiency( constructProficiency, count / totalCount, missionTask, "construction" ); } if ( counter >= constructionCount ) { OnConstructionFinished( p ); } else { CreateFizzleThread( fizzleTime ); } } OnConstructing(); } void constructible_objective::KillFizzleThread() { fizzling = false; fizzleEndTime = 0; sys.killThread( "FizzleThread_" + getName() ); fizzleThreadActive = false; } void constructible_objective::CreateFizzleThread( float delay ) { KillFizzleThread(); fizzleEndTime = sys.getTime() + delay; if ( !fizzleThreadActive ) { thread FizzleThread( delay ); } } void constructible_objective::OnConstructionFizzled() { counter = 0; } void constructible_objective::FizzleThread( float delay ) { fizzling = false; sys.threadName( "FizzleThread_" + getName() ); fizzleThreadActive = true; while ( sys.getTime() < fizzleEndTime ) { sys.wait( fizzleEndTime - sys.getTime() ); } fizzleThreadActive = false; if ( fizzleEndTime != 0 ) { OnConstructionFizzled(); } } float constructible_objective::vGetPliersProgressBarValue( float action ) { return counter / constructionCount; } float constructible_objective::OnUpdateCrosshairInfo( entity p ) { if ( !sys.doClientSideStuff() ) { return 1.f; } float allegiance = getEntityAllegiance( p ); float distance = chGetDistance(); float range = InchesToMetres( distance ); chSetNumLines( 0 ); vector color = GetAllegianceColor( allegiance ); 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 ) ) { 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 ); } } } } } 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 ); if ( ( range <= 25.f ) && ( range >= 5.f ) ) { index = chAddLine(); chSetLineText( index, G_BuildRangeStr( range ) ); chSetLineColor( index, color, 1.f ); chSetLineType( index, CI_TEXT ); chSetLineSize( index, 0, 0 ); } return 1.f; } float constructible_objective::OnActivate( entity p, float distance ) { float code = GetActivateCode( p, distance ); if ( code == AK_NONE ) { return 0.f; } p.vSelectActionItem( code ); return 1.f; } float constructible_objective::GetActivateCode( entity p, float distance ) { if ( objManager.gameState != GS_GAMEON ) { return AK_INWARMUP; } if ( p.getViewingEntity() != p ) { return AK_NONE; } if ( p.getHealth() <= 0 ) { return AK_NONE; } if ( distance > DISTANCE_FOR_ACTION ) { return AK_NONE; } float allegiance = getEntityAllegiance( p ); if ( allegiance == TA_FRIEND ) { return AK_CONSTRUCT; } return AK_NONE; } boolean constructible_objective::HasConstructContext( entity other ) { float allegiance = getEntityAllegiance( other ); if ( allegiance != TA_FRIEND ) { return false; } return true; } void constructible_objective::vCreateMission() { vFreeMission(); missionTask = taskManager.allocEntityTask( GetPlayerTask( getKey( "task_construct" ) ), self ); } void constructible_objective::vFreeMission() { if ( missionTask != $null ) { missionTask.free(); missionTask = $null; } } void constructible_objective::vCompleteMission() { if ( missionTask != $null ) { missionTask.complete(); missionTask.free(); missionTask = $null; } } void constructible_objective::ShowAndEnableClip() { show(); if ( hasForceDisableClip() ) { forceEnableClip(); if ( !sys.isClient() ) { // destroy touching entities float count = self.entitiesInBounds( getAbsMins(), getAbsMaxs(), MASK_SHOT_RENDERMODEL | MASK_SHOT_BOUNDINGBOX, 1 ); float index; for ( index = 0; index < count; index++ ) { entity other = self.getBoundsCacheEntity( index ); if ( other == self ) { continue; } if ( other != $null_entity ) { float entTouch = other.touches( self, true ); if ( entTouch == 0.0f && inCollection( "bounds_check" ) ) { if ( G_ContainsBounds( getAbsMins(), getAbsMaxs(), other.getAbsMins(), other.getAbsMaxs(), 2 ) ) { entTouch = 1; } } if ( entTouch ) { projectile_landmine mine = other; if ( mine != $null_entity ) { mine.vSetOwner( $null_entity ); } else { if ( dmgIndex != -1 ) { other.applyDamage( $null_entity, self, vec3_down, dmgIndex, 1.0f, $null_entity ); } } } } } } } } void constructible_objective::HideAndDisableClip() { hide(); if ( !hasForceDisableClip() ) { forceDisableClip(); if ( !sys.isClient() ) { entity next; entity current; for ( current = getNextTeamEntity(); current != $null_entity; current = next ) { next = current.getNextTeamEntity(); current.vOnBindMasterDestroyed(); } } } } boolean constructible_objective::vIsPrimaryObjective() { if ( objectiveIndex == -1 ) { return false; } if ( !isPrimaryObjective ) { return false; } return true; } boolean constructible_objective::IsPrimaryConstruction() { if ( objectiveIndex >= 0 ) { return true; } return false; } /* =============================================================================== constructible_materials the script object attached to the construct materials =============================================================================== */ #define CSTATE_BLANK 0 #define CSTATE_PROGRESS 1 #define CSTATE_COMPLETE 2 object constructible_materials : constructible_objective { void preinit(); void init(); void syncFields(); void destroy(); boolean vCheckActionCode( entity p, float actionCode ); void OnConstructionStarted(); void OnConstructionFinished( entity p ); void OnConstructionFizzled(); void UpdateObjectiveProgress(); void SetupConstruction(); void OnStateChanged(); void SetConstructionState( float newState ); void AfterConstructed(); void vSetConstructionState( float newState ) { SetConstructionState( newState ); } void vFinishObjective(); void vStartObjective(); void OnStartNewState(); void OnFinishCurrentState( entity other ); entity GetConstructionStage(); void OnConstructing(); string vGetQuickChatString( entity p ); void vOnContextConstruct( entity p ); void vOnContextDefend( entity p ); entity vGetSpectateEntity(); boolean vIsObjectiveComplete(); float startConstructed; float state; float oldState; // todo nick; make a seperate multi-staged constructible entity firstStage; entity secondStage; entity intermediateStage; entity removeEnt; entity constructedEnt; boolean multipleStages; float constructDelay; flashpoint_obj flashpoint; boolean firstCompletedVO; } void constructible_materials::syncFields() { syncBroadcast( "removeEnt" ); syncBroadcast( "firstStage" ); syncBroadcast( "secondStage" ); syncBroadcast( "intermediateStage" ); syncBroadcast( "constructedEnt" ); syncBroadcast( "state" ); syncCallback( "state", "OnStateChanged" ); } void constructible_materials::destroy() { if ( flashpoint != $null ) { delete flashpoint; } } void constructible_materials::vFinishObjective() { FinishObjective_Base(); HideAndDisableClip(); } void constructible_materials::vStartObjective() { StartObjective_Base(); SetConstructionState( state ); } void constructible_materials::preinit() { setGameTeam( sys.getTeam( getKey( "team" ) ) ); multipleStages = getIntKey( "multiple_stages" ); if ( multipleStages ) { totalCount = totalCount * 2; } constructDelay = 0; state = -1; } void constructible_materials::SetupConstruction() { if ( sys.isClient() ) { OnStateChanged(); return; } firstStage = getEntityKey( "construction" ); if ( firstStage == $null_entity ) { sys.error( "No construction found on " + self.getName() ); } firstStage.setGameTeam( getGameTeam() ); firstStage.vSetOwner( self ); removeEnt = getEntityKey( "construction_remove" ); if ( removeEnt != $null_entity ) { removeEnt.setGameTeam( getGameTeam() ); } if( multipleStages ) { intermediateStage = getEntityKey( "construction_intermediate" ); intermediateStage.vSetOwner( self ); secondStage = getEntityKey( "construction_second" ); if( secondStage == $null_entity ) { sys.error( "No construction_second found on " + self.getName()); } secondStage.vSetOwner( self ); secondStage.setGameTeam( getGameTeam() ); } constructedEnt = getEntityKey( "constructed" ); if ( constructedEnt != $null_entity ) { constructedEnt.setGameTeam( getGameTeam() ); constructedEnt.vSetOwner( self ); } float newState; startConstructed = getFloatKey( "start_constructed" ); if( !startConstructed ) { newState = CSTATE_NONE; } else { if( multipleStages ) { newState = CSTATE_FIRST_SECOND; } else { newState = CSTATE_FIRST; } } SetConstructionState( newState ); } void constructible_materials::init() { SetupConstruction(); } boolean constructible_materials::vCheckActionCode( entity p, float actionCode ) { if ( !CheckActionCode_Base( p, actionCode ) ) { return false; } if ( sys.getTime() < constructDelay ) { return false; } if( multipleStages ) { return state != CSTATE_FIRST_SECOND; } return state != CSTATE_FIRST; } void constructible_materials::OnConstructionStarted() { OnStartNewState(); if ( !sys.isClient() ) { objManager.setBotActionStateForEvent( ACTION_STATE_START_BUILD, self ); //mal: let the bots know someone is building the obj! } } void constructible_materials::OnConstructionFinished( entity p ) { //mal: the map script will handle this particular case. OnFinishCurrentState( p ); counter = constructionCount; } void constructible_materials::OnConstructionFizzled() { float fizzleDuration = g_objectiveDecayTime.getFloatValue(); // fizzle over time while ( counter > 0 ) { fizzling = true; float fizzleAmount = constructionCount * ( sys.getFrameTime() / fizzleDuration ); counter = counter - fizzleAmount; sys.waitFrame(); } fizzling = false; counter = 0; float newState; if ( state == CSTATE_FIRST_PROGRESS ) { newState = CSTATE_NONE; if ( !sys.isClient() ) { objManager.setBotActionStateForEvent( ACTION_STATE_BUILD_FIZZLED, self ); //mal: its fizzled - update the bots. } } else if ( state == CSTATE_FIRST_SECOND_PROGRESS ) { newState = CSTATE_FIRST; } else { sys.warning( "constructible_materials::FizzleThread Invalid State" ); return; } // we've fallen back a stage SetConstructionState( newState ); } void constructible_materials::OnStartNewState() { float newState; if ( state == CSTATE_NONE ) { newState = CSTATE_FIRST_PROGRESS; } else if ( state == CSTATE_FIRST ) { newState = CSTATE_FIRST_SECOND_PROGRESS; } else { sys.warning( "constructible_materials::OnStartNewState Invalid State " + state ); return; } SetConstructionState( newState ); } void constructible_materials::UpdateObjectiveProgress() { if ( sys.doClientSideStuff() ) { sys.setGUIFloat( GUI_GLOBALS_HANDLE, "constructObjective.multiStage", multipleStages ); sys.setGUIFloat( GUI_GLOBALS_HANDLE, "constructObjective.decaying", fizzling ); if( state == CSTATE_FIRST_SECOND_PROGRESS ) { sys.setGUIFloat( GUI_GLOBALS_HANDLE, "constructObjective.stage1", 1 ); sys.setGUIFloat( GUI_GLOBALS_HANDLE, "constructObjective.stage2", CalcObjectiveProgress() ); return; } if ( state == CSTATE_FIRST ) { sys.setGUIFloat( GUI_GLOBALS_HANDLE, "constructObjective.stage1", 1 ); sys.setGUIFloat( GUI_GLOBALS_HANDLE, "constructObjective.stage2", 0 ); return; } UpdateObjectiveProgress_Base(); } } void constructible_materials::OnFinishCurrentState( entity other ) { boolean finished = true; float newState; if ( state == CSTATE_FIRST_PROGRESS ) { newState = CSTATE_FIRST; if ( multipleStages ) { finished = false; } } else if ( state == CSTATE_FIRST_SECOND_PROGRESS ) { newState = CSTATE_FIRST_SECOND; } else { sys.warning( "constructible_materials::OnFinishCurrentState Invalid State" ); return; } if ( finished ) { player p = other; if ( p != $null_entity ) { team_base team = p.getGameTeam(); string statName = team.getName(); if ( IsPrimaryConstruction() ) { statName = statName + "_primary"; } else { statName = statName + "_secondary"; } statName = statName + "_objective_constructed"; sys.increaseStatInt( sys.allocStatInt( statName ), p.getEntityNumber(), 1 ); sys.increaseStatInt( sys.allocStatInt( "total_objectives_completed" ), p.getEntityNumber(), 1 ); } } SetConstructionState( newState ); constructDelay = sys.getTime() + 0.5f; KillFizzleThread(); } void constructible_materials::OnStateChanged() { SetConstructionState( state ); } void constructible_materials::SetConstructionState( float newState ) { if ( newState == CSTATE_DESTROY ) { // special notification state that is CSTATE_NONE, to distinguish between this and a fizzle // Gordon: doing the extra check here, because constructions may be put directly into the none state when they spawn if ( oldState != CSTATE_NONE ) { objManager.OnDestructionComplete( self ); } newState = CSTATE_NONE; } if ( newState == CSTATE_NONE ) { firstStage.vSetState( CSTATE_NONE ); if ( !disabled ) { ShowAndEnableClip(); } if ( multipleStages ) { secondStage.vSetState( CSTATE_NONE ); if ( intermediateStage != $null_entity ) { intermediateStage.vSetState( CSTATE_NONE ); } } if ( constructedEnt != $null_entity ) { constructedEnt.vSetState( CSTATE_NONE ); } if ( removeEnt != $null_entity ) { removeEnt.vSetState( CSTATE_COMPLETE ); } } else if ( newState == CSTATE_FIRST_PROGRESS ) { firstStage.vSetState( CSTATE_PROGRESS ); if ( !disabled ) { ShowAndEnableClip(); } if ( multipleStages ) { secondStage.vSetState( CSTATE_NONE ); if ( intermediateStage != $null_entity ) { intermediateStage.vSetState( CSTATE_PROGRESS ); } } if ( constructedEnt != $null_entity ) { constructedEnt.vSetState( CSTATE_NONE ); } if ( removeEnt != $null_entity ) { removeEnt.vSetState( CSTATE_COMPLETE ); } } else if ( newState == CSTATE_FIRST ) { firstStage.vSetState( CSTATE_COMPLETE ); if ( multipleStages ) { secondStage.vSetState( CSTATE_NONE ); if ( intermediateStage != $null_entity ) { intermediateStage.vSetState( CSTATE_COMPLETE ); } if ( !disabled ) { ShowAndEnableClip(); } if ( constructedEnt != $null_entity ) { constructedEnt.vSetState( CSTATE_NONE ); } if ( removeEnt != $null_entity ) { removeEnt.vSetState( CSTATE_COMPLETE ); } if ( !firstCompletedVO ) { objManager.PlaySound( getKey( "snd_firststage_strogg" ), stroggTeam ); objManager.PlaySound( getKey( "snd_firststage_gdf" ), gdfTeam ); firstCompletedVO = true; } } else { AfterConstructed(); } } else if( newState == CSTATE_FIRST_SECOND_PROGRESS ) { if( !multipleStages ) { sys.warning( "constructible_materials::SetConstructionState Not Multistage!" ); return; } secondStage.vSetState( CSTATE_PROGRESS ); if ( !disabled ) { ShowAndEnableClip(); } if ( intermediateStage != $null_entity ) { intermediateStage.vSetState( CSTATE_COMPLETE ); } if ( constructedEnt != $null_entity ) { constructedEnt.vSetState( CSTATE_NONE ); } if ( removeEnt != $null_entity ) { removeEnt.vSetState( CSTATE_COMPLETE ); } } else if( newState == CSTATE_FIRST_SECOND ) { if( !multipleStages ) { sys.warning( "constructible_materials::SetConstructionState Not Multistage!" ); return; } if ( intermediateStage != $null_entity ) { intermediateStage.vSetState( CSTATE_NONE ); } firstStage.vSetState( CSTATE_NONE ); secondStage.vSetState( CSTATE_COMPLETE ); AfterConstructed(); } state = newState; oldState = newState; } void constructible_materials::AfterConstructed() { if ( objectiveIndex >= 0 ) { if ( getGameTeam() == stroggTeam ) { G_PlayObjectiveCompletedRoll( GDF ); } else if ( getGameTeam() == gdfTeam ) { G_PlayObjectiveCompletedRoll( STROGG ); } objManager.CompleteObjective( objectiveIndex, constructor ); } else { if ( constructedMessage != invalid_handle ) { objManager.PushCPrintString( constructor.getUserName() ); objManager.CPrintEvent( constructedMessage, $null ); } } objManager.OnConstructionComplete( self ); if ( constructedEnt != $null_entity ) { firstStage.vSetState( CSTATE_NONE ); if ( multipleStages ) { secondStage.vSetState( CSTATE_NONE ); } constructedEnt.vSetState( CSTATE_COMPLETE ); } if( removeEnt != $null_entity ) { removeEnt.vSetState( CSTATE_NONE ); } HideAndDisableClip(); objManager.PlaySound( getKey( "snd_finished_strogg" ), stroggTeam ); objManager.PlaySound( getKey( "snd_finished_gdf" ), gdfTeam ); } entity constructible_materials::GetConstructionStage() { if ( state == CSTATE_FIRST_PROGRESS ) { if ( multipleStages ) { return intermediateStage; } return firstStage; } else if ( state == CSTATE_FIRST_SECOND_PROGRESS ) { return secondStage; } return $null_entity; } void constructible_materials::OnConstructing() { entity stage = GetConstructionStage(); if ( stage == $null_entity ) { return; } player p = sys.getLocalPlayer(); if ( p == $null_entity ) { return; } if ( sys.getTime() - lastWarningUpdate < 1.0f ) { return; } lastWarningUpdate = sys.getTime(); sys.assert( stage.hasForceDisableClip() ); stage.forceEnableClip(); if ( !p.touches( stage, 0.0f ) ) { stage.forceDisableClip(); return; } float contents = p.getEntityContents(); stage.forceDisableClip(); if ( contents == 0.0f ) { return; } if ( !p.isToolTipPlaying() ) { p.sendToolTip( GetToolTip( getKey( "tt_warning" ) ) ); } } string constructible_materials::vGetQuickChatString( entity p ) { if ( getEntityAllegiance( p ) == TA_FRIEND ) { return getKey( "contextmenu_quickchat_friendly" ); } return getKey( "contextmenu_quickchat_enemy" ); } void constructible_materials::vOnContextConstruct( 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" ) ); } void constructible_materials::vOnContextDefend( entity p ) { player local = sys.getLocalViewPlayer(); if ( local == $null_entity || p == $null_entity ) { return; } if ( objectiveIndex == -1 ) { return; } if ( flashpoint != $null ) { delete flashpoint; } flashpoint = new flashpoint_obj; flashpoint.SetOwner( self ); flashpoint.SetMaterial( getKey( "mtr_icon_flash_destroy" ) ); } entity constructible_materials::vGetSpectateEntity() { float time = sys.getTime(); if ( lastConstructTime >= time - 0.5f ) { return constructor; } return $null_entity; } boolean constructible_materials::vIsObjectiveComplete() { if ( multipleStages ) { if ( state == CSTATE_FIRST_SECOND ) { return true; } } else { if ( state == CSTATE_FIRST ) { return true; } } return false; } /* ================================================ constructible_base This entity simply gets hidden, shown and its skin changed ================================================ */ object constructible_base { float state; string constructionSkin; float maxHealth; float dmgIndex; void preinit() { state = -1; constructionSkin = getKeyWithDefault( "skin_construct", "deployEffect" ); } void init() { maxHealth = getMaxHealth(); dmgIndex = GetDamage( getKey( "dmg_kill" ) ); } void SetState_Base( float newState ); void vSetState( float newState ) { SetState_Base( newState ); } void OnStateChanged() { vSetState( state ); } string vGetQuickChatString( entity p ); } void constructible_base::SetState_Base( float newState ) { if ( state == newState ) { return; } setHealth( maxHealth ); if ( newState == CSTATE_NONE ) { hide(); forceDisableClip(); if ( !sys.isClient() ) { entity next; entity current; for ( current = getNextTeamEntity(); current != $null_entity; current = next ) { next = current.getNextTeamEntity(); current.vOnBindMasterDestroyed(); } } } else if ( newState == CSTATE_PROGRESS ) { show(); forceDisableClip(); setSkin( constructionSkin ); } else if ( newState == CSTATE_COMPLETE ) { show(); setSkin( "" ); if ( hasForceDisableClip() ) { forceEnableClip(); if ( !sys.isClient() ) { // destroy touching entities float count = self.entitiesInBounds( getAbsMins(), getAbsMaxs(), MASK_SHOT_RENDERMODEL | MASK_SHOT_BOUNDINGBOX, 1 ); float index; for ( index = 0; index < count; index++ ) { entity other = self.getBoundsCacheEntity( index ); if ( other == self ) { continue; } if ( other != $null_entity ) { float entTouch = other.touches( self, true ); if ( entTouch == 0.0f && inCollection( "bounds_check" ) ) { if ( G_ContainsBounds( getAbsMins(), getAbsMaxs(), other.getAbsMins(), other.getAbsMaxs(), 2 ) ) { entTouch = 1; } } if ( entTouch ) { projectile_landmine mine = other; if ( mine != $null_entity ) { mine.vSetOwner( $null_entity ); } else { if ( dmgIndex != -1 ) { other.applyDamage( $null_entity, self, vec3_down, dmgIndex, 1.0f, $null_entity ); } } } } } } } } state = newState; } string constructible_base::vGetQuickChatString( entity p ) { if ( getEntityAllegiance( p ) == TA_FRIEND ) { return getKey( "contextmenu_quickchat_friendly" ); } return getKey( "contextmenu_quickchat_enemy" ); } /* ================================================ constructible_tower ================================================ */ object constructible_tower : constructible_base { void preinit(); void init(); void destroy(); void vSetState( float newState ); void OnKilled( entity inflictor, entity attacker, float damage, vector dir, float location ); float OnUpdateCrosshairInfo( entity p ); float OnActivate( entity p, float distance ); float GetActivateCode( entity p, float distance ); void UpdateItemStates(); void vSetOwner( entity o ); void vCreateMission(); void vFreeMission(); void vCompleteMission(); void vOnContextDestroy( entity p ); entity gun; entity ladder; handle objectName; constructible_materials materials; task missionTask; float dmgIndexDestroy; flashpoint_obj flashpoint; } void constructible_tower::OnKilled( entity inflictor, entity attacker, float damage, vector dir, float location ) { if ( !sys.isClient() ) { // destroy touching entities float count = self.entitiesInBounds( getAbsMins(), getAbsMaxs(), MASK_SHOT_RENDERMODEL | MASK_SHOT_BOUNDINGBOX, 1 ); float entityCache = saveCachedEntities(); float index; for ( index = 0; index < count; index++ ) { entity other = self.getSavedCacheEntity( entityCache, index ); if ( other == self ) { continue; } if ( other != $null_entity ) { if ( dmgIndexDestroy != -1 ) { other.applyDamage( inflictor, attacker, vec3_down, dmgIndexDestroy, 1.0f, $null_entity ); } } } freeSavedCache( entityCache ); } materials.SetConstructionState( CSTATE_DESTROY ); } void constructible_tower::preinit() { objectName = sys.localizeString( getKey( "object_name" ) ); } void constructible_tower::vCreateMission() { vFreeMission(); missionTask = taskManager.allocEntityTask( GetPlayerTask( getKey( "task_destroy" ) ), self ); } void constructible_tower::vFreeMission() { if ( missionTask != $null ) { missionTask.free(); missionTask = $null; } } void constructible_tower::vCompleteMission() { if ( missionTask != $null ) { missionTask.complete(); missionTask.free(); missionTask = $null; } } void constructible_tower::init() { gun = getEntityKey( "gun_entity" ); ladder = getEntityKey( "ladder_entity" ); dmgIndex = GetDamage( getKey( "dmg_kill" ) ); dmgIndexDestroy = GetDamage( getKey( "dmg_kill_destroy" ) ); if ( state != -1 ) { UpdateItemStates(); } } void constructible_tower::destroy() { if ( flashpoint != $null ) { delete flashpoint; } } void constructible_tower::vSetState( float newState ) { SetState_Base( newState ); UpdateItemStates(); } void constructible_tower::UpdateItemStates() { if ( gun != $null_entity ) { if ( state == CSTATE_COMPLETE ) { gun.vSetConstructed( true ); } else { gun.vSetConstructed( false ); } } if ( ladder != $null_entity ) { if ( state == CSTATE_COMPLETE ) { ladder.forceEnableClip(); } else { ladder.forceDisableClip(); } } if ( state == CSTATE_COMPLETE ) { setTakesDamage( true ); } else { setTakesDamage( false ); } } void constructible_tower::vSetOwner( entity o ) { materials = o; } float constructible_tower::OnUpdateCrosshairInfo( entity p ) { if ( !sys.doClientSideStuff() ) { return 1.f; } float allegiance = getEntityAllegiance( p ); float distance = chGetDistance(); vector color = GetAllegianceColor( allegiance ); chSetNumLines( 0 ); if ( p != $null_entity ) { // 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 ); } } index = chAddLine(); chSetLineTextIndex( index, objectName ); chSetLineColor( index, color, 1.f ); chSetLineType( index, CI_TEXT ); chSetLineSize( index, 0, 0 ); return 1.f; } float constructible_tower::OnActivate( entity p, float distance ) { float code = GetActivateCode( p, distance ); if ( code == AK_NONE ) { return 0.f; } p.vSelectActionItem( code ); return 1.f; } float constructible_tower::GetActivateCode( entity p, float distance ) { if ( p.getViewingEntity() != p ) { return AK_NONE; } if ( p.getHealth() <= 0 ) { return AK_NONE; } if ( distance > DISTANCE_FOR_ACTION ) { return AK_NONE; } float allegiance = getEntityAllegiance( p ); if ( allegiance == TA_ENEMY ) { if ( p.vHasActionItem( AK_PLANT ) ) { return AK_PLANT; } } return AK_NONE; } void constructible_tower::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_destroy" ) ); }