#using scripts\codescripts\struct; #using scripts\shared\callbacks_shared; #using scripts\shared\challenges_shared; #using scripts\shared\clientfield_shared; #using scripts\shared\damagefeedback_shared; #using scripts\shared\scoreevents_shared; #using scripts\shared\system_shared; #using scripts\shared\util_shared; #using scripts\shared\weapons\_decoy; #using scripts\shared\weapons\_hacker_tool; #using scripts\shared\weapons\_weaponobjects; #namespace sensor_grenade; function init_shared() { level.isplayerTrackedFunc =&isPlayerTracked; callback::add_weapon_watcher( &createSensorGrenadeWatcher ); } //****************************************************************** // * // * //****************************************************************** function createSensorGrenadeWatcher() { watcher = self weaponobjects::createUseWeaponObjectWatcher( "sensor_grenade", self.team ); watcher.headicon = false; watcher.onSpawn =&onSpawnSensorGrenade; watcher.onDetonateCallback =&sensorGrenadeDestroyed; watcher.onStun = &weaponobjects::weaponStun; watcher.stunTime = 0; watcher.onDamage =&watchsensorGrenadeDamage; watcher.enemyDestroy = true; } //****************************************************************** // * // * //****************************************************************** function onSpawnSensorGrenade( watcher, player ) // self == sensor sensor { self endon( "death" ); self thread weaponobjects::onSpawnUseWeaponObject( watcher, player ); self SetOwner( player ); self SetTeam( player.team ); self.owner = player; self PlayLoopSound ( "wpn_sensor_nade_lp" ); self hacker_tool::registerWithHackerTool( level.equipmentHackerToolRadius, level.equipmentHackerToolTimeMs ); player AddWeaponStat( self.weapon, "used", 1 ); self thread watchForStationary( player ); self thread watchForExplode( player ); self thread watch_for_decoys( player ); } function watchForStationary( owner ) { self endon( "death" ); self endon( "hacked" ); self endon( "explode" ); owner endon( "death" ); owner endon( "disconnect" ); self waittill("stationary" ); checkForTracking( self.origin ); } function watchForExplode( owner ) { self endon( "hacked" ); self endon( "delete" ); owner endon( "death" ); owner endon( "disconnect" ); self waittill( "explode", origin ); checkForTracking( origin + ( 0,0,1) ); } function checkForTracking( origin ) { if ( isdefined ( self.owner ) == false ) return; players = level.players; foreach( player in level.players ) { if ( player util::IsEnemyPlayer( self.owner ) ) { if ( ! ( player hasPerk ("specialty_nomotionsensor") ) && ! ( player hasPerk ("specialty_sengrenjammer") && player clientfield::get( "sg_jammer_active" ) ) ) { if ( DistanceSquared( player.origin, origin ) < 750 * 750 ) { trace = bullettrace( origin, player.origin + (0,0,12), false, player ); if ( trace["fraction"] == 1 ) { self.owner trackSensorGrenadeVictim( player ); } } } } } } function trackSensorGrenadeVictim( victim ) { if ( !isdefined( self.sensorGrenadeData ) ) { self.sensorGrenadeData = []; } if ( !isdefined( self.sensorGrenadeData[victim.clientid] ) ) { self.sensorGrenadeData[victim.clientid] = getTime(); } } function isPlayerTracked( player, time ) { playerTracked = false; if ( isdefined ( self.sensorGrenadeData ) && isdefined( self.sensorGrenadeData[player.clientid] ) ) { if ( self.sensorGrenadeData[player.clientid] + 10000 > time ) { playerTracked = true; } } return playerTracked; } //****************************************************************** // * // * //****************************************************************** function sensorGrenadeDestroyed( attacker, weapon, target ) { if ( !isdefined( weapon ) || !weapon.isEmp ) { PlayFX( level._equipment_explode_fx, self.origin ); } if ( isdefined( attacker ) ) { if ( self.owner util::IsEnemyPlayer( attacker ) ) { attacker challenges::destroyedEquipment( weapon ); scoreevents::processScoreEvent( "destroyed_motion_sensor", attacker, self.owner, weapon ); } } PlaySoundAtPosition ( "wpn_sensor_nade_explo", self.origin ); self delete(); } //****************************************************************** // * // * //****************************************************************** function watchSensorGrenadeDamage( watcher ) // self == sensor grenade { self endon( "death" ); self endon( "hacked" ); self SetCanDamage( true ); damageMax = 1; if ( !self util::isHacked() ) { self.damageTaken = 0; } while( true ) { self.maxhealth = 100000; self.health = self.maxhealth; self waittill( "damage", damage, attacker, direction, point, type, tagName, modelName, partname, weapon, iDFlags ); if( !isdefined( attacker ) || !isplayer( attacker ) ) continue; if ( level.teambased && IsPlayer( attacker ) ) { // if we're not hardcore and the team is the same, do not destroy if( !level.hardcoreMode && self.owner.team == attacker.pers["team"] && self.owner != attacker ) { continue; } } // most equipment should be flash/concussion-able, so it'll disable for a short period of time // check to see if the equipment has been flashed/concussed and disable it (checking damage < 5 is a bad idea, so check the weapon name) // we're currently allowing the owner/teammate to flash their own // do damage feedback if ( watcher.stunTime > 0 && weapon.doStun ) { self thread weaponobjects::stunStart( watcher, watcher.stunTime ); } if ( weapon.doDamageFeedback ) { // if we're not on the same team then show damage feedback if ( level.teambased && self.owner.team != attacker.team ) { if ( damagefeedback::doDamageFeedback( weapon, attacker ) ) attacker damagefeedback::update(); } // for ffa just make sure the owner isn't the same else if ( !level.teambased && self.owner != attacker ) { if ( damagefeedback::doDamageFeedback( weapon, attacker ) ) attacker damagefeedback::update(); } } if ( type == "MOD_MELEE" || weapon.isEmp || weapon.destroysEquipment ) { self.damageTaken = damageMax; } else { self.damageTaken += damage; } if( self.damageTaken >= damageMax ) { watcher thread weaponobjects::waitAndDetonate( self, 0.0, attacker, weapon ); return; } } } //****************************************************************** // * // * //****************************************************************** function watch_for_decoys( owner ) { self waittill("stationary" ); players = level.players; foreach( player in level.players ) { if ( player util::IsEnemyPlayer( self.owner ) ) { if ( IsAlive(player) && player hasPerk ("specialty_decoy") ) { if ( DistanceSquared( player.origin, self.origin ) < 240 * 240 ) { player thread watch_decoy( self ); } } } } } function get_decoy_spawn_loc() { // this needs to be much more intelligent return self.origin - 240 * AnglesToForward(self.angles); } function watch_decoy( sensor_grenade ) { origin = self get_decoy_spawn_loc(); decoy_grenade = sys::Spawn( "script_model", origin ); decoy_grenade.angles = -1 * self.angles; {wait(.05);}; decoy_grenade.initial_velocity = -1 * self GetVelocity(); decoy_grenade thread decoy::simulate_weapon_fire(self); wait 15; decoy_grenade notify( "done"); decoy_grenade notify( "death_before_explode"); decoy_grenade delete(); }