Script:Files:script/tools/force shield.script
From Mod Wiki
/*********************************************************************** tool_force_shield.script ***********************************************************************/ object force_shield { void preinit(); void init(); void destroy(); void Idle(); void OnHit( object traceObject, vector v, entity other ); void OnKilled( entity inflictor, entity attacker, float damage, vector direction, float location ); float dieTime; float nextBlink; boolean blinkState; float nextEffectTime; entity owner; } object tool_force_shield : weapon_base { void preinit(); void init(); void destroy(); void Raise(); void Lower(); void Idle(); void Fire(); boolean CanFire(); void ToolTipThread_Raise(); void StartIdleEffect(); void StopIdleEffect(); void StartRechargeEffect(); void StopRechargeEffect(); boolean recharge; float nextChargeMessageTime; boolean rechargeEffectOn; boolean idleEffectOn; } void tool_force_shield::preinit() { rechargeEffectOn = false; idleEffectOn = false; } void tool_force_shield::init() { if ( myPlayer.isLocalPlayer() ) { thread ToolTipThread_Raise(); } weaponState( "Raise", 0 ); } void tool_force_shield::destroy() { StopIdleEffect(); StopRechargeEffect(); } void tool_force_shield::Raise() { UpdateCharge(); Base_Raise(); } void tool_force_shield::Lower() { StopIdleEffect(); StopRechargeEffect(); Base_Lower(); } void tool_force_shield::Idle() { weaponReady(); boolean playingRecharge; if ( recharge ) { playingRecharge = true; recharge = false; playAnim( ANIMCHANNEL_ALL, "recharge" ); StopIdleEffect(); StartRechargeEffect(); } else { playCycle( ANIMCHANNEL_ALL, "idle" ); StopRechargeEffect(); StartIdleEffect(); } while ( true ) { if ( WEAPON_LOWERWEAPON ) { weaponState( "Lower", 4 ); } if ( WEAPON_ATTACK ) { if ( !mainFireDown ) { mainFireDown = true; if ( CanFire() ) { weaponState( "Fire", 0 ); } else { if ( myPlayer.isLocalPlayer() ) { myPlayer.sendToolTip( GetToolTip( getKey( "tt_need_charge" ) ) ); sys.startSoundDirect( getKey( "snd_need_charge" ), SND_ANY ); G_NotifyNoCharge( myPlayer ); } } } } else { mainFireDown = false; } UpdateCharge(); if ( playingRecharge && animDone( ANIMCHANNEL_ALL, 4 ) ) { playingRecharge = false; setBlendFrames( ANIMCHANNEL_ALL, 4 ); playCycle( ANIMCHANNEL_ALL, "idle" ); StopRechargeEffect(); StartIdleEffect(); } sys.waitFrame(); } } boolean tool_force_shield::CanFire() { return myPlayer.EnergyBar_CanRemove( chargePerUse ); } void tool_force_shield::Fire() { playAnim( ANIMCHANNEL_ALL, "fire" ); fired(); sys.wait( 0.1 ); if ( !sys.isClient() ) { myPlayer.EnergyBar_Remove( chargePerUse ); string defName = "def_forcefield"; if ( myPlayer.getProficiency( g_proficiencyOppressor ) >= 2 ) { defName = "def_forcefield_mega"; } entity shieldProj = sys.spawn( getKey( defName ) ); vector origin = myPlayer.getViewOrigin(); vector forward = sys.angToForward( myPlayer.getViewAngles() ); float throwDistance = 32.0f; vector throwPos = origin + forward * throwDistance; float meleeDistance = 64.0f; if( melee( MASK_SHOT_BOUNDINGBOX | MASK_PROJECTILE, meleeDistance, true, false ) ) { float traceDistance = getMeleeFraction() * meleeDistance; vector size = shieldProj.getSize(); float pullOut = sys.vecLength( size ) * 0.6f; if ( traceDistance < meleeDistance + pullOut ) { throwPos = origin + forward * ( traceDistance - pullOut ); } } myPlayer.setForceShieldState( false, shieldProj ); //mal: let the bots know theres a shield out there in the world. shieldProj.setOrigin( throwPos ); vector velocity = shieldProj.getVectorKeyWithDefault( "velocity", '400 0 0' ); velocity = forward * velocity_x; shieldProj.setLinearVelocity( velocity ); shieldProj.vSetOwner( myPlayer ); } waitUntil( animDone( ANIMCHANNEL_ALL, 1 ) ); recharge = true; nextChargeMessageTime = sys.getTime() + 2.f; weaponState( "Idle", 1 ); } void tool_force_shield::ToolTipThread_Raise() { myPlayer.cancelToolTips(); sys.wait( myPlayer.CalcTooltipWait() ); WAIT_FOR_TOOLTIP; myPlayer.sendToolTip( GetToolTip( getKey( "tt_intro_1" ) ) ); WAIT_FOR_TOOLTIP; myPlayer.sendToolTip( GetToolTip( getKey( "tt_intro_2" ) ) ); } void tool_force_shield::StartIdleEffect() { if ( idleEffectOn == false ) { if ( myPlayer == sys.getLocalPlayer() ) { playEffect( "fx_loop", "joint7", 1 ); idleEffectOn = true; } } } void tool_force_shield::StopIdleEffect() { if ( idleEffectOn == true ) { if ( myPlayer == sys.getLocalPlayer() ) { stopEffect( "fx_loop" ); idleEffectOn = false; } } } void tool_force_shield::StartRechargeEffect() { if ( rechargeEffectOn == false ) { playEffect( "fx_recharge", "joint7", 0 ); playEffect( "fx_recharge2", "joint4", 0 ); playEffect( "fx_recharge3", "joint1", 0 ); rechargeEffectOn = true; } } void tool_force_shield::StopRechargeEffect() { if ( rechargeEffectOn == true ) { stopEffect( "fx_recharge" ); stopEffect( "fx_recharge2" ); stopEffect( "fx_recharge3" ); rechargeEffectOn = false; } } /*********************************************************************** The force_shield itself ***********************************************************************/ void force_shield::preinit() { nextEffectTime = 0; } void force_shield::init() { setContents( CONTENTS_FORCEFIELD | CONTENTS_EXPLOSIONSOLID ); setClipmask( CONTENTS_PROJECTILE ); setState( "Idle" ); } void force_shield::destroy() { } void force_shield::Idle() { setNetworkSynced( 1.f ); float blinkStart = getFloatKey( "blink_start" ); float blinkMultiplier = getFloatKey( "blink_multiplier" ); float blinkMaxOff = getFloatKey( "blink_max_off" ); dieTime = sys.getTime() + getFloatKey( "life_time" ); float nextBlink = blinkStart + 0.01; blinkState = false; setShaderParm( 4, 0 ); startSound( "snd_start", SND_WEAPON_IDLE ); while ( true ) { float timeLeft = dieTime - sys.getTime(); if ( timeLeft <= blinkStart ) { // Shader does a table lookup based on the time left float fade = 1.0f - ( timeLeft / blinkStart ); setShaderParm( 4, fade ); } setShaderParm( 5, getHealth() / getMaxHealth()); if ( timeLeft <= 0 && !sys.isClient() ) { remove(); } sys.waitFrame(); } } void force_shield::OnKilled( entity inflictor, entity attacker, float damage, vector direction, float location ) { if ( !sys.isClient() ) { // TODO: Apply a nice effect here remove(); } } void force_shield::OnHit( object traceObject, vector v, entity other ) { if ( sys.getTime() > nextEffectTime ) { vector endPos = traceObject.getTracePoint(); vector endNormal = traceObject.getTraceNormal(); playOriginEffect( "fx_hit", "", endPos, endNormal, false ); nextEffectTime = sys.getTime() + 0.1; } } /*********************************************************************** The projectile that spawns the force_shield itself ***********************************************************************/ object projectile_forceshield { void preinit(); void init(); void destroy(); void syncFields(); void Idle(); void OnTouch( entity other, object traceObject ); float OnCollide( object traceObject, vector velocity, float bodyId ); void OnShieldProjSync(); void OnUnbind(); void OnPostThink(); entity owner; force_shield shieldProj; boolean placedShield; vector launchAngles; void vSetOwner( entity o ); }; void projectile_forceshield::preinit() { } void projectile_forceshield::init() { placedShield = false; setContents( 0 ); setClipmask( MASK_SHOT_RENDERMODEL | MASK_PROJECTILE ); setState( "Idle" ); } void projectile_forceshield::vSetOwner( entity o ) { owner = o; launchAngles = owner.getViewAngles(); } void projectile_forceshield::destroy() { } void projectile_forceshield::syncFields() { syncBroadcast( "shieldProj" ); syncCallback( "shieldProj", "OnShieldProjSync" ); } void projectile_forceshield::OnShieldProjSync() { shieldProj.bind( self ); placedShield = true; } void projectile_forceshield::Idle() { if ( !sys.isClient() ) { float dieTime = sys.getTime() + 5.0f; while ( true ) { if ( shieldProj == $null_entity && placedShield ) { remove(); } if ( !placedShield && sys.getTime() > dieTime ) { remove(); } sys.waitFrame(); } } } void projectile_forceshield::OnUnbind() { if ( !sys.isClient() ) { if ( shieldProj != $null_entity ) { shieldProj.remove(); } } } void projectile_forceshield::OnTouch( entity other, object traceObject ) { } // NOTE: If this returns true, all momentum on the object will be cleared, otherwise, it will bounce float projectile_forceshield::OnCollide( object traceObject, vector velocity, float bodyId ) { float shaderFlags; entity collisionEnt; shaderFlags = traceObject.getTraceSurfaceFlags(); if ( shaderFlags & SURF_NOIMPACT || shaderFlags & SURF_NOPLANT ) { return false; } collisionEnt = traceObject.getTraceEntity(); // don't let it stick to a player or a vehicle player collisionPlayer = collisionEnt; if ( collisionPlayer != $null_entity ) { return false; } if ( collisionEnt.vDisablePlantCharge() ) { return false; } // push the view out of the surface a bit vector normal = traceObject.getTraceNormal(); // align to the surface normal alignToAxis( normal, Z_AXIS ); if ( !sys.isClient() ) { freeze( 1.f ); clearContacts(); putToRest(); if ( collisionEnt != $null_entity ) { string joint = traceObject.getTraceJoint(); float jointHandle = collisionEnt.getJointHandle( joint ); if ( jointHandle != INVALID_JOINT ) { bindToJoint( collisionEnt, joint, 1 ); } else { bind( collisionEnt ); } } // create the fancy shield shieldProj = sys.spawn( getKey( "def_shield" ) ); shieldProj.setWorldOrigin( getWorldOrigin() ); launchAngles_x = 0; launchAngles_z = 0; vector forward = sys.angToForward( launchAngles ); vector newAngles = launchAngles; vector origin = getWorldOrigin(); float dot = forward * normal; if ( forward * normal < -0.707 ) { // the forward that the player wanted is kind of embedded into the surface // so align it with the normal of the surface newAngles = sys.vecToAngles( normal ); } shieldProj.setAngles( newAngles ); shieldProj.owner = owner; shieldProj.setGameTeam( owner.getGameTeam() ); OnShieldProjSync(); } return true; } void projectile_forceshield::OnPostThink() { if ( isBound() ) { forceRunPhysics(); } }