/*********************************************************************** projectile_charge.script ***********************************************************************/ object projectile_charge : projectile_armable { void preinit(); void destroy(); void syncFields(); void vSetOwner( entity other ); void vSetNewTarget( entity target ); void vOnEndGame(); float OnUpdateCrosshairInfo( entity p ); void DoExplodeEffect( entity collisionEnt ); float FindObjectives(); void GiveDisarmBonus( entity p ); void DoRadiusDamage(); void OnDisarmed( entity p ); void OnArmed( entity p ); void OnUnbind(); void SoundThread(); boolean IsCharge(); void UpdateGUI( entity armee ); void vOnTargetDestroyed(); float vGetFuseRemaining(); float vGetFuseLength(); entity vGetCurrentTarget(); boolean vDecayBody() { return true; } void PlaceGlowThread(); void vOnContextDisarm( entity p ); float disarmProficiency; entity owner; entity armer; entity bindTarget; float disableRadius; float disableTime; float explodeTime; task disarmTask; entity objectiveTarget; float guiHandle; flashpoint_obj flashpoint; } void projectile_charge::preinit() { ScheduleFizzle( getFloatKeyWithDefault( "fizzle_time", 30 ) ); explodeTime = GetGlobalFloat( "charge_explode_time" ); disarmProficiency = GetProficiency( getKey( "prof_disarm" ) ); disableRadius = getFloatKeyWithDefault( "disable_radius", 512 ); disableTime = getFloatKeyWithDefault( "disable_time", 30 ); guiHandle = GUI_INVALID; thread PlaceGlowThread(); stuck = true; } void projectile_charge::syncFields() { syncBroadcast( "bindTarget" ); syncBroadcast( "objectiveTarget" ); syncBroadcast( "owner" ); } void projectile_charge::destroy() { if ( disarmTask != $null_entity ) { disarmTask.free(); } if ( owner == sys.getLocalPlayer() ) { sys.setGUIFloat( GUI_GLOBALS_HANDLE, "gameHud.weaponChargePercent", 0 ); } stopEffect( "fx_unarmed_glow" ); stopEffect( "fx_glow" ); if ( !sys.isClient() ) { player p = owner; if ( p != $null_entity ) { p.setPlayerChargeArmed( false, self ); //mal: if we fizzled, or blew up, clear out our owners tracker. } } if ( flashpoint != $null ) { delete flashpoint; } sys.killThread( "UpdateGUI_" + getName() ); sys.killThread( "SoundThread_" + getName() ); } void projectile_charge::UpdateGUI( entity armee ) { float length = vGetFuseLength(); if( length <= 0 ) { return; } // Gordon: Not sure why this is being done like this, it could easily be fire and forget float value; player p = owner; float timeLeft; boolean updateGui; while( true ) { value = 1.0 - ( vGetFuseRemaining() / length ); if( value >= 1.0f ) { return; } updateGui = false; if ( p != $null_entity ) { if ( p == sys.getLocalPlayer() ) { if ( getEntityAllegiance( p ) == TA_FRIEND ) { float armeeClass = p.getPlayerClass(); if ( armeeClass == g_playerClassSoldier || armeeClass == g_playerClassAggressor ) { updateGui = true; sys.setGUIFloat( GUI_GLOBALS_HANDLE, "gameHud.weaponChargePercent", value ); } } } } if ( !updateGui ) { sys.setGUIFloat( GUI_GLOBALS_HANDLE, "gameHud.weaponChargePercent", 0 ); break; } if ( guiHandle != GUI_INVALID ) { sys.setGUIFloat( guiHandle, "charge.timeLeft", vGetFuseRemaining() ); } sys.waitFrame(); } } void projectile_charge::vSetOwner( entity other ) { owner = other; } float projectile_charge::FindObjectives() { return entitiesOfCollection( "hetrigger" ); } void projectile_charge::OnArmed( entity p ) { armer = p; ProjectileArmable_OnArmed( p ); CancelFizzle(); if ( sys.doClientSideStuff() ) { thread SoundThread(); thread UpdateGUI( p ); } ScheduleExplosion( explodeTime, MS_EXPLODED ); if ( !sys.isClient() ) { player playerEnt = p; if ( playerEnt != $null_entity ) { playerEnt.setPlayerChargeArmed( true, self ); //mal: this charge is armed. Code elsewhere will notify the bots if its a noteworthy arming event. } // alert nearby entities float count; float i; entity ent; count = FindObjectives(); for ( i = 0; i < count; i++ ) { ent = getBoundsCacheEntity( i ); if ( self.touches( ent, 0 ) ) { if ( bindTarget != ent.vGetCurrentTarget() ) { continue; } if ( ent.vChargePlaced( self, armer ) ) { objectiveTarget = ent.vGetCurrentTarget(); if ( getGameTeam() == gdfTeam ) { objManager.PlaySound( getKey( "snd_disarm_strogg" ), stroggTeam ); } else { objManager.PlaySound( getKey( "snd_disarm_gdf" ), gdfTeam ); } break; } } } if ( objectiveTarget != $null_entity ) { disarmTask = taskManager.allocEntityTask( GetPlayerTask( getKey( "task_defuse" ) ), self ); } } } void projectile_charge::OnUnbind() { if( armingEntity == sys.getLocalPlayer() ) { // Gordon: I don't really get what this is meant to do sys.setGUIFloat( GUI_GLOBALS_HANDLE, "gameHud.weaponChargePercent", 0 ); } stopEffect( "fx_unarmed_glow" ); stopEffect( "fx_glow" ); Fizzle(); } void projectile_charge::GiveDisarmBonus( entity p ) { float useDisarmProficiency = disarmProficiency; if ( objectiveTarget != $null_entity ) { objectiveTarget.vChargeDisarmed( self, p ); useDisarmProficiency = objectiveTarget.vGetDisarmProficiency(); } if ( useDisarmProficiency != -1 ) { if ( getEntityAllegiance( p ) == TA_ENEMY ) { p.giveProficiency( useDisarmProficiency, 1.f, disarmTask, "disarmed charge" ); } } } void projectile_charge::OnDisarmed( entity p ) { GiveDisarmBonus( p ); ProjectileArmable_OnDisarmed( p ); if ( bindTarget.vIsDestructibleObjective() ) { if ( getGameTeam() == gdfTeam ) { objManager.PlaySound( getKey( "snd_disarmed_strogg" ), stroggTeam ); } else { objManager.PlaySound( getKey( "snd_disarmed_gdf" ), gdfTeam ); } } if ( owner == sys.getLocalPlayer() ) { sys.setGUIFloat( GUI_GLOBALS_HANDLE, "gameHud.weaponChargePercent", 0 ); } if ( !sys.isClient() ) { if ( disarmTask != $null_entity ) { disarmTask.free(); } } CancelExplosion(); stopEffect( "fx_glow" ); Fizzle(); } float projectile_charge::OnUpdateCrosshairInfo( entity p ) { if ( !sys.doClientSideStuff() ) { return 1.f; } float allegiance = getEntityAllegiance( p ); vector color = GetAllegianceColor( allegiance ); float distance = chGetDistance(); float range = InchesToMetres( distance ); float health = getHealth(); chSetNumLines( 0 ); float index; team_base team; if ( p != $null_entity ) { 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 ); CheckContextToolTip( allegiance, code, p ); } } handle nameHandle = sys.localizeString( getKey( "task_name" ) ); if ( objectiveTarget != $null_entity ) { string objName = objectiveTarget.getKey( "charge_name" ); if ( objName != "" ) { nameHandle = sys.localizeString( objName ); } } index = chAddLine(); chSetLineTextIndex( index, nameHandle ); 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; } void projectile_charge::DoRadiusDamage() { if ( splashDamageIndex != -1 ) { float power = 1.f; sys.applyRadiusDamage( getWorldOrigin(), self, armer, radiusDamageIgnoreEntity, self, splashDamageIndex, power, 1.f ); } } void projectile_charge::DoExplodeEffect( entity collisionEnt ) { if ( objectiveTarget != $null_entity ) { objectiveTarget.vChargeExploded( self, armer ); } DoRadiusDamage(); ScheduleRemoval( 0.5f ); } boolean projectile_charge::IsCharge() { return true; } void projectile_charge::vSetNewTarget( entity target ) { bindTarget = target; } void projectile_charge::SoundThread() { stopEffect( "fx_unarmed_glow" ); sys.wait( startSound( "snd_armed", SND_WEAPON_SIG ) ); if ( IsCharge() ) { // find a good position for the light vector lStart = getWorldOrigin() + getWorldAxis( 0 ); vector lEnd = getWorldOrigin() + getWorldAxis( 0 ) * 50.0f; float frac = sys.tracePoint( lStart, lEnd, CONTENTS_SOLID, self ); playOriginEffect( "fx_glow", "", lStart + ( lEnd - lStart ) * frac * 0.95f, vec3_up, 1 ); sys.wait( 24.f ); stopEffect( "fx_glow" ); while ( true ) { playOriginEffect( "fx_glow", "", lStart + ( lEnd - lStart ) * frac * 0.95f, vec3_up, 1 ); sys.wait( 0.5f ); killEffect( "fx_glow" ); } } } void projectile_charge::vOnTargetDestroyed() { remove(); } float projectile_charge::vGetFuseRemaining() { return explodeTime - ( sys.getTime() - armTime ); } float projectile_charge::vGetFuseLength() { return explodeTime; } entity projectile_charge::vGetCurrentTarget() { return objectiveTarget; } void projectile_charge::PlaceGlowThread() { while ( true ) { if ( getWorldOrigin() != vec3_origin ) { break; } sys.wait( 1.0f ); } vector lStart = getWorldOrigin() + getWorldAxis( 0 ); vector lEnd = getWorldOrigin() + getWorldAxis( 0 ) * 50.0f; float frac = sys.tracePoint( lStart, lEnd, CONTENTS_SOLID, self ); playOriginEffect( "fx_unarmed_glow", "", lStart + ( lEnd - lStart ) * frac * 0.95f, vec3_up, 1 ); } void projectile_charge::vOnContextDisarm( entity p ) { player local = sys.getLocalViewPlayer(); if ( local == $null_entity || p == $null_entity ) { return; } if ( objectiveTarget == $null_entity ) { return; } if ( flashpoint != $null ) { delete flashpoint; } flashpoint = new flashpoint_obj; flashpoint.SetOwner( self ); flashpoint.SetMaterial( getKey( "mtr_icon_flash" ) ); } void projectile_charge::vOnEndGame() { stopEffect( "fx_unarmed_glow" ); stopEffect( "fx_glow" ); Fizzle(); }