1082 lines
40 KiB
Plaintext
1082 lines
40 KiB
Plaintext
#using scripts\codescripts\struct;
|
|
|
|
#using scripts\shared\ai\systems\gib;
|
|
#using scripts\shared\callbacks_shared;
|
|
#using scripts\shared\challenges_shared;
|
|
#using scripts\shared\clientfield_shared;
|
|
#using scripts\shared\killcam_shared;
|
|
#using scripts\shared\scoreevents_shared;
|
|
#using scripts\shared\system_shared;
|
|
#using scripts\shared\util_shared;
|
|
#using scripts\shared\visionset_mgr_shared;
|
|
#using scripts\shared\weapons\_weaponobjects;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#namespace hive_gun;
|
|
|
|
#precache( "fx", "weapon/fx_hero_firefly_blood_os" );
|
|
#precache( "fx", "weapon/fx_hero_firefly_sparks_os" );
|
|
#precache( "fx", "weapon/fx_hero_chem_gun_blob_death" );
|
|
#precache( "fx", "weapon/fx_hero_firefly_start" );
|
|
//#precache( "fx", "weapon/fx_hero_firefly_start_entity" );
|
|
|
|
function init_shared()
|
|
{
|
|
level.firefly_pod_weapon = GetWeapon("hero_chemicalgelgun");
|
|
level.firefly_pod_secondary_explosion_weapon = GetWeapon("hive_gungun_secondary_explosion");
|
|
|
|
level.firefly_debug = GetDvarInt( "scr_firefly_debug", 0 );
|
|
level.firefly_pod_detection_radius = GetDvarInt( "scr_fireflyPodDetectionRadius", 150 );
|
|
level.firefly_pod_grace_period = GetDvarFloat( "scr_fireflyPodGracePeriod", 0 );
|
|
level.firefly_pod_activation_time = GetDvarFloat( "scr_fireflyPodActivationTime", 1 );
|
|
level.firefly_pod_partial_move_percent = GetDvarFloat( "scr_fireflyPartialMovePercent", 0.8 );
|
|
|
|
if ( !IsDefined( level.vsmgr_prio_overlay_gel_splat ) )
|
|
{
|
|
level.vsmgr_prio_overlay_gel_splat = 21;
|
|
}
|
|
//visionset_mgr::register_info( "overlay", "hive_gungun_splat", VERSION_SHIP, level.vsmgr_prio_overlay_gel_splat, 7, true, &visionset_mgr::duration_lerp_thread_per_player, false );
|
|
|
|
level.fireflies_spawn_height = getDvarInt( "betty_jump_height_onground", 55 );
|
|
level.fireflies_spawn_height_wall = getDvarInt( "betty_jump_height_wall", 20 );
|
|
level.fireflies_spawn_height_wall_angle = getDvarInt( "betty_onground_angle_threshold", 30 );
|
|
level.fireflies_spawn_height_wall_angle_cos = cos( level.fireflies_spawn_height_wall_angle );
|
|
level.fireflies_emit_time = getDvarFloat( "scr_firefly_emit_time", 0.2 );
|
|
level.fireflies_min_speed = getDvarInt( "scr_firefly_min_speed", 400 );
|
|
level.fireflies_attack_speed_scale = getDvarFloat( "scr_firefly_attack_attack_speed_scale", 1.75 );
|
|
level.fireflies_collision_check_interval = getDvarFloat( "scr_firefly_collision_check_interval", 0.2 );
|
|
|
|
callback::add_weapon_damage( level.firefly_pod_weapon, &on_damage_firefly_pod );
|
|
|
|
level thread register();
|
|
|
|
/#
|
|
level thread update_dvars();
|
|
#/
|
|
}
|
|
|
|
/#
|
|
function update_dvars()
|
|
{
|
|
while(1)
|
|
{
|
|
wait(1);
|
|
level.fireflies_min_speed = getDvarInt( "scr_firefly_speed", 250 );
|
|
level.fireflies_attack_speed_scale = getDvarFloat( "scr_firefly_attack_attack_speed_scale", 1.15 );
|
|
level.firefly_debug = GetDvarInt( "scr_firefly_debug", 0 );
|
|
}
|
|
}
|
|
#/
|
|
function register()
|
|
{
|
|
clientfield::register( "scriptmover", "firefly_state", 1, 3, "int" );
|
|
clientfield::register( "toplayer", "fireflies_attacking", 1, 1, "int" );
|
|
clientfield::register( "toplayer", "fireflies_chasing", 1, 1, "int" );
|
|
}
|
|
|
|
function createFireflyPodWatcher() // self == player
|
|
{
|
|
watcher = self weaponobjects::createProximityWeaponObjectWatcher( "hero_chemicalgelgun", self.team );
|
|
watcher.onSpawn =&on_spawn_firefly_pod;
|
|
watcher.watchForFire = true;
|
|
watcher.hackable = false;
|
|
watcher.headIcon = false;
|
|
watcher.activateFx = true;
|
|
watcher.ownerGetsAssist = true;
|
|
watcher.ignoreDirection = true;
|
|
watcher.immediateDetonation = true;
|
|
watcher.detectionGracePeriod = level.firefly_pod_grace_period;
|
|
watcher.detonateRadius = level.firefly_pod_detection_radius;
|
|
watcher.onStun = &weaponobjects::weaponStun;
|
|
watcher.stunTime = 0;
|
|
watcher.onDetonateCallback =&firefly_pod_detonate;
|
|
watcher.activationDelay = level.firefly_pod_activation_time;
|
|
watcher.activateSound = "wpn_gelgun_blob_burst";
|
|
watcher.shouldDamage = &firefly_pod_should_damage;
|
|
watcher.deleteOnPlayerSpawn = true;
|
|
watcher.timeOut = getDvarFloat( "scr_firefly_pod_timeout", 0 );
|
|
watcher.ignoreVehicles = false; // which now means AI, but not clones
|
|
watcher.ignoreAI = false;
|
|
watcher.onSupplementalDetonateCallback = &firefly_death;
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
// *
|
|
// *
|
|
//******************************************************************
|
|
function on_spawn_firefly_pod( watcher, owner ) // self == betty ent
|
|
{
|
|
weaponobjects::onSpawnProximityWeaponObject( watcher, owner );
|
|
self playloopsound( "wpn_gelgun_blob_alert_lp", 1 );
|
|
|
|
self endon("death");
|
|
self waittill("stationary");
|
|
|
|
self SetModel( "wpn_t7_hero_chemgun_residue3_grn" );
|
|
self SetEnemyModel( "wpn_t7_hero_chemgun_residue3_org" );
|
|
}
|
|
|
|
function start_damage_effects()
|
|
{
|
|
/#
|
|
If ( IsGodMode( self ) )
|
|
{
|
|
return;
|
|
}
|
|
#/
|
|
|
|
// visionset_mgr::activate( "overlay", "hive_gungun_splat", self, firefly_pod_SPLAT_DURATION_MAX, firefly_pod_SPLAT_DURATION_MAX );
|
|
|
|
//self clientfield::set( "damaged_by_firefly_pod", 1 );
|
|
|
|
self thread end_damage_effects();
|
|
}
|
|
|
|
function end_damage_effects()
|
|
{
|
|
self endon( "disconnect" );
|
|
|
|
self waittill( "death" );
|
|
|
|
// visionset_mgr::deactivate( "overlay", "hive_gungun_splat", self );
|
|
|
|
//self clientfield::set( "damaged_by_firefly_pod", 0 );
|
|
}
|
|
|
|
function on_damage_firefly_pod( eAttacker, eInflictor, weapon, meansOfDeath, damage )
|
|
{
|
|
if ( "MOD_GRENADE" != meansOfDeath && "MOD_GRENADE_SPLASH" != meansOfDeath )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// self thread start_damage_effects( );
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
// *
|
|
// *
|
|
//******************************************************************
|
|
function spawn_firefly_mover() // self == betty ent
|
|
{
|
|
// self util::waitTillNotMoving();
|
|
|
|
// self UseAnimTree( #animtree );
|
|
// self SetAnim( %o_spider_mine_deploy, 1.0, 0.0, 1.0 );
|
|
|
|
firefly_mover = spawn( "script_model", self.origin );
|
|
firefly_mover.angles = self.angles;
|
|
firefly_mover SetModel( "tag_origin" );
|
|
// firefly_mover SetModel( "fx_axis_createfx" ); // temp
|
|
firefly_mover.owner = self.owner;
|
|
firefly_mover.killCamOffset = ( 0, 0, GetDvarFloat( "scr_fireflies_start_height", 8.0 ) );
|
|
// firefly_mover.weapon = self.weapon;
|
|
firefly_mover.weapon = GetWeapon("hero_firefly_swarm");
|
|
firefly_mover.takedamage = true;
|
|
firefly_mover.soundMod = "firefly";
|
|
firefly_mover.team = self.team;
|
|
|
|
killcamEnt = spawn( "script_model", firefly_mover.origin + firefly_mover.killCamOffset );
|
|
killcamEnt.angles = ( 0,0,0 );
|
|
killcamEnt SetModel( "tag_origin" );
|
|
killcamEnt SetWeapon( firefly_mover.weapon );
|
|
|
|
// store the blob entity on the killcam entity so we can chain them together
|
|
killcamEnt killcam::store_killcam_entity_on_entity(self);
|
|
|
|
firefly_mover.killcamEnt = killcamEnt;
|
|
|
|
self.firefly_mover = firefly_mover;
|
|
|
|
firefly_mover.debug_time = 1;
|
|
|
|
firefly_mover thread firefly_mover_damage();
|
|
weaponobjects::add_supplemental_object( firefly_mover );
|
|
}
|
|
|
|
function firefly_mover_damage()
|
|
{
|
|
while(1)
|
|
{
|
|
self waittill ( "damage", damage, attacker, direction_vec, point, type, modelName, tagName, partName, weapon, iDFlags );
|
|
|
|
self thread firefly_death();
|
|
}
|
|
}
|
|
|
|
//******************************************************************
|
|
// *
|
|
// *
|
|
//******************************************************************
|
|
function kill_firefly_mover() // self == betty ent
|
|
{
|
|
if ( isdefined( self.firefly_mover ))
|
|
{
|
|
if ( isdefined( self.firefly_mover.killcamEnt ) )
|
|
{
|
|
self.firefly_mover.killcamEnt delete();
|
|
}
|
|
self.firefly_mover delete();
|
|
}
|
|
}
|
|
|
|
//******************************************************************
|
|
// *
|
|
// *
|
|
//******************************************************************
|
|
function firefly_pod_detonate( attacker, weapon, target ) // self == betty
|
|
{
|
|
if ( !isdefined( target ) || !isdefined( target.team ) || !isdefined( self.team ) || self.team == target.team )
|
|
{
|
|
if ( IsDefined( weapon ) && weapon.isValid )
|
|
{
|
|
if ( isdefined( attacker ) )
|
|
{
|
|
if ( self.owner util::IsEnemyPlayer( attacker ) )
|
|
{
|
|
attacker challenges::destroyedExplosive( weapon );
|
|
scoreevents::processScoreEvent( "destroyed_fireflyhive", attacker, self.owner, weapon );
|
|
}
|
|
}
|
|
}
|
|
self firefly_pod_destroyed();
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
// self.firefly_mover SetModel( self.model );
|
|
self spawn_firefly_mover();
|
|
|
|
self.firefly_mover thread firefly_watch_for_target_death( target );
|
|
self.firefly_mover thread firefly_watch_for_game_ended( target );
|
|
|
|
self thread firefly_pod_release_fireflies( attacker, target );
|
|
}
|
|
}
|
|
|
|
//******************************************************************
|
|
// *
|
|
// *
|
|
//******************************************************************
|
|
function firefly_pod_destroyed( ) // self == betty
|
|
{
|
|
fx_ent = PlayFX( "weapon/fx_hero_chem_gun_blob_death", self.origin );
|
|
fx_ent.team = self.team;
|
|
|
|
PlaySoundAtPosition ( "wpn_gelgun_blob_destroy", self.origin );
|
|
|
|
if ( isdefined( self.trigger ) )
|
|
{
|
|
self.trigger delete();
|
|
}
|
|
|
|
self kill_firefly_mover();
|
|
|
|
self delete();
|
|
}
|
|
|
|
//******************************************************************
|
|
// *
|
|
// *
|
|
//******************************************************************
|
|
function firefly_killcam_move( position, time ) // self == script mover spawned at weaponobject location
|
|
{
|
|
if ( !IsDefined( self.killcamEnt ) )
|
|
return;
|
|
|
|
self endon("death");
|
|
wait( 0.5 );
|
|
accel = 0;
|
|
decel = 0;
|
|
self.killCamEnt MoveTo( position, time, accel, decel );
|
|
}
|
|
|
|
//******************************************************************
|
|
// *
|
|
// *
|
|
//******************************************************************
|
|
function firefly_killcam_stop()
|
|
{
|
|
self notify("stop_killcam");
|
|
if ( IsDefined( self.killcamEnt ) )
|
|
{
|
|
self.killcamEnt MoveTo( self.killcamEnt.origin, 0.1, 0, 0);
|
|
}
|
|
}
|
|
|
|
//******************************************************************
|
|
// *
|
|
// *
|
|
//******************************************************************
|
|
function firefly_move( position, time ) // self == script mover spawned at weaponobject location
|
|
{
|
|
self endon("death");
|
|
accel = 0; //time * 0.1;
|
|
decel = 0; //time * 0.1;
|
|
self thread firefly_killcam_move( position, time );
|
|
self MoveTo( position, time, accel, decel );
|
|
self waittill( "movedone" );
|
|
}
|
|
|
|
//******************************************************************
|
|
// *
|
|
// *
|
|
//******************************************************************
|
|
function firefly_partial_move( target, position, time, percent ) // self == script mover spawned at weaponobject location
|
|
{
|
|
self endon("death");
|
|
self endon("stop_killcam");
|
|
accel = 0; //time * 0.1;
|
|
decel = 0; //time * 0.1;z
|
|
self thread firefly_killcam_move( position, time );
|
|
self MoveTo( position, time, accel, decel );
|
|
self thread firefly_check_for_collisions( target, position, time );
|
|
wait( time * percent );
|
|
self notify("movedone");
|
|
}
|
|
|
|
//******************************************************************
|
|
// *
|
|
// *
|
|
//******************************************************************
|
|
function firefly_rotate( angles, time ) // self == script mover spawned at weaponobject location
|
|
{
|
|
self endon("death");
|
|
|
|
self RotateTo( angles, time, 0, 0 );
|
|
self waittill( "rotatedone" );
|
|
}
|
|
|
|
//******************************************************************
|
|
// *
|
|
// *
|
|
//******************************************************************
|
|
function firefly_check_for_collisions( target, move_to, time ) // self == script mover spawned at weaponobject location
|
|
{
|
|
self endon("death");
|
|
self endon("movedone");
|
|
|
|
original_position = self.origin;
|
|
dir = VectorNormalize(move_to - self.origin);
|
|
dist = Distance( self.origin, move_to );
|
|
speed = dist / time;
|
|
|
|
delta = dir * ( speed * level.fireflies_collision_check_interval );
|
|
|
|
while( 1 )
|
|
{
|
|
if ( !firefly_check_move( self.origin + delta, target ) )
|
|
{
|
|
// hit something
|
|
self thread firefly_death();
|
|
self playsound( "wpn_gelgun_hive_wall_impact" );
|
|
}
|
|
wait( level.fireflies_collision_check_interval );
|
|
}
|
|
}
|
|
|
|
//******************************************************************
|
|
// *
|
|
// *
|
|
//******************************************************************
|
|
function firefly_pod_rotated_point( degrees, radius, height )
|
|
{
|
|
angles = ( 0, degrees, 0 );
|
|
forward = ( radius, 0, 0);
|
|
|
|
point = RotatePoint( forward, angles );
|
|
|
|
return self.spawn_origin + point + ( 0, 0, height );
|
|
}
|
|
|
|
//******************************************************************
|
|
// *
|
|
// *
|
|
//******************************************************************
|
|
function firefly_pod_random_point()
|
|
{
|
|
return firefly_pod_rotated_point( RandomInt(359), RandomInt( level.fireflies_radius ), RandomIntRange( -level.fireflies_height_variance, level.fireflies_height_variance ) );
|
|
}
|
|
|
|
//******************************************************************
|
|
// *
|
|
// *
|
|
//******************************************************************
|
|
function firefly_pod_random_movement( ) // self == script mover spawned at weaponobject location
|
|
{
|
|
self endon("death");
|
|
self endon("attacking");
|
|
|
|
while (1)
|
|
{
|
|
point = firefly_pod_random_point();
|
|
|
|
delta = point - self.origin;
|
|
angles = VectorToAngles(delta);
|
|
firefly_rotate( angles, 0.15 );
|
|
|
|
dist = Length( delta );
|
|
|
|
time = 0.01;
|
|
|
|
if ( dist > 0 )
|
|
{
|
|
time = dist / level.fireflies_min_speed;
|
|
}
|
|
firefly_move( point, time );
|
|
|
|
wait( RandomFloatRange( 0.1, 0.7 ) );
|
|
}
|
|
}
|
|
|
|
//******************************************************************
|
|
// *
|
|
// *
|
|
//******************************************************************
|
|
function firefly_spyrograph_patrol( degrees, increment, radius ) // self == script mover spawned at weaponobject location
|
|
{
|
|
self endon("death");
|
|
self endon("attacking");
|
|
|
|
current_degrees = RandomInt( int(360 / degrees) ) * degrees;
|
|
height_offset = 0;
|
|
|
|
while (1)
|
|
{
|
|
point = firefly_pod_rotated_point( current_degrees, radius, height_offset );
|
|
|
|
delta = point - self.origin;
|
|
angles = ( 0, current_degrees, 0 );
|
|
thread firefly_rotate( angles, 0.15 );
|
|
|
|
dist = Length( delta );
|
|
|
|
time = 0.01;
|
|
|
|
if ( dist > 0 )
|
|
{
|
|
time = dist / level.fireflies_min_speed;
|
|
}
|
|
firefly_move( point, time );
|
|
|
|
wait( RandomFloatRange( 0.1, 0.3 ) );
|
|
|
|
current_degrees = ( current_degrees + ( degrees * increment ) ) % 360;
|
|
}
|
|
}
|
|
|
|
//******************************************************************
|
|
// *
|
|
// *
|
|
//******************************************************************
|
|
function firefly_damage_target( target ) // self == script mover spawned at weaponobject location
|
|
{
|
|
level endon("game_ended");
|
|
self endon("death");
|
|
|
|
target endon("disconnect");
|
|
target endon("death");
|
|
target endon ( "entering_last_stand" );
|
|
|
|
damage = 25;
|
|
damage_delay = 0.1;
|
|
weapon = self.weapon;
|
|
target playsound( "wpn_gelgun_hive_attack" );
|
|
target notify( "snd_burn_scream" );
|
|
|
|
remaining_hits = 10; // big number, not too big
|
|
|
|
//if( IS_EQUAL( target.type, "robot" ) )
|
|
if ( !isplayer(target) )
|
|
remaining_hits = 4;
|
|
|
|
while( remaining_hits > 0 )
|
|
{
|
|
wait( damage_delay );
|
|
target DoDamage( damage, self.origin, self.owner, self, "", "MOD_IMPACT", 0, weapon );
|
|
|
|
remaining_hits -= 1;
|
|
|
|
if ( IsAlive( target ) && IsPlayer( target ) )
|
|
{
|
|
bodyType = target GetCharacterBodyType();
|
|
if ( bodyType >= 0 )
|
|
{
|
|
bodyTypeFields = GetCharacterFields( bodyType, CurrentSessionMode() );
|
|
if( (isdefined(bodyTypeFields.digitalBlood)?bodyTypeFields.digitalBlood:false) )
|
|
{
|
|
PlayFXOnTag( "weapon/fx_hero_firefly_sparks_os", target, "J_SpineLower");
|
|
}
|
|
else
|
|
{
|
|
PlayFXOnTag( "weapon/fx_hero_firefly_blood_os", target, "J_SpineLower");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PlayFXOnTag( "weapon/fx_hero_firefly_blood_os", target, "J_SpineLower");
|
|
}
|
|
}
|
|
else if ( !IsPlayer( target ) )
|
|
{
|
|
PlayFXOnTag( "weapon/fx_hero_firefly_sparks_os", target, "tag_origin");
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
// *
|
|
// *
|
|
//******************************************************************
|
|
function firefly_watch_for_target_death( target )
|
|
{
|
|
self endon("death");
|
|
if ( IsAlive( target ) )
|
|
{
|
|
target util::waittill_any("death", "flashback", "game_ended");
|
|
}
|
|
|
|
if( IsPlayer( target ) )
|
|
{
|
|
target clientfield::set_to_player( "fireflies_attacking", 0 );
|
|
target clientfield::set_to_player( "fireflies_chasing", 0 );
|
|
}
|
|
|
|
self thread firefly_death();
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
// *
|
|
// *
|
|
//******************************************************************
|
|
function firefly_watch_for_game_ended( target )
|
|
{
|
|
self endon("death");
|
|
level waittill( "game_ended");
|
|
|
|
if ( IsAlive( target ) && IsPlayer( target ) )
|
|
{
|
|
target clientfield::set_to_player( "fireflies_attacking", 0 );
|
|
target clientfield::set_to_player( "fireflies_chasing", 0 );
|
|
}
|
|
|
|
self thread firefly_death();
|
|
}
|
|
|
|
//******************************************************************
|
|
// *
|
|
// *
|
|
//******************************************************************
|
|
function firefly_death()
|
|
{
|
|
/#
|
|
println("firefly_death " + self getentnum() );
|
|
#/
|
|
self clientfield::set( "firefly_state", 5 );
|
|
self playsound( "wpn_gelgun_hive_die" );
|
|
|
|
if ( IsDefined( self.target_entity ) && isPlayer( self.target_entity ) )
|
|
{
|
|
self.target_entity clientfield::set_to_player( "fireflies_attacking", 0 );
|
|
self.target_entity clientfield::set_to_player( "fireflies_chasing", 0 );
|
|
}
|
|
|
|
waittillframeend;
|
|
|
|
thread cleanup_killcam_entity(self.killcamEnt);
|
|
if ( isdefined( self ) )
|
|
{
|
|
/#
|
|
println("firefly_death deleting " + self getentnum() );
|
|
#/
|
|
|
|
self delete();
|
|
}
|
|
}
|
|
|
|
function cleanup_killcam_entity(killcamEnt)
|
|
{
|
|
wait(5);
|
|
if ( isdefined( killcamEnt ) )
|
|
{
|
|
killcamEnt delete();
|
|
}
|
|
}
|
|
|
|
function get_attack_speed( target )
|
|
{
|
|
velocity = target GetVelocity();
|
|
speed = Length( velocity ) * level.fireflies_attack_speed_scale;
|
|
|
|
if ( speed < level.fireflies_min_speed )
|
|
{
|
|
speed = level.fireflies_min_speed;
|
|
}
|
|
|
|
return speed;
|
|
}
|
|
|
|
//******************************************************************
|
|
// *
|
|
// *
|
|
//******************************************************************
|
|
function firefly_attack( target, state )
|
|
{
|
|
level endon("game_ended");
|
|
self endon("death");
|
|
target endon ( "entering_last_stand" );
|
|
|
|
self thread firefly_killcam_stop();
|
|
|
|
self clientfield::set( "firefly_state", state );
|
|
if( IsPlayer( target ) )
|
|
{
|
|
target clientfield::set_to_player( "fireflies_attacking", 1 );
|
|
}
|
|
|
|
target_origin = target.origin + (0,0,50);
|
|
|
|
delta = self.origin - target_origin;
|
|
dist = Length( delta );
|
|
time = 0.01;
|
|
if ( dist > 0 )
|
|
{
|
|
speed = get_attack_speed( target );
|
|
time = dist / speed;
|
|
}
|
|
|
|
self.enemy = target;
|
|
|
|
firefly_move( target_origin, time );
|
|
|
|
if ( !isdefined( target ) || !IsAlive( target ) )
|
|
return;
|
|
|
|
self LinkTo( target );
|
|
|
|
wait(time);
|
|
|
|
if ( !IsAlive(target) )
|
|
return;
|
|
|
|
self thread firefly_damage_target( target );
|
|
}
|
|
|
|
function get_crumb_position( target )
|
|
{
|
|
height = 50;
|
|
|
|
if( IsPlayer( target ) )
|
|
{
|
|
stance = target GetStance();
|
|
if ( stance == "crouch" )
|
|
height = 30;
|
|
else if ( stance == "prone" )
|
|
height = 15;
|
|
}
|
|
|
|
return target.origin + (0,0,height);
|
|
}
|
|
|
|
/#
|
|
function target_bread_crumbs_render( target )
|
|
{
|
|
self endon("death");
|
|
self endon("attack");
|
|
|
|
|
|
while(1)
|
|
{
|
|
previous_crumb = self.origin;
|
|
|
|
for( i = 0; i < self.target_breadcrumbs.size; i++ )
|
|
{
|
|
|
|
if ( (self.target_breadcrumb_current_index + i) > self.target_breadcrumb_last_added )
|
|
break;
|
|
|
|
crumb_index = (self.target_breadcrumb_current_index + i) % self.target_breadcrumbs.size;
|
|
crumb = self.target_breadcrumbs[crumb_index ];
|
|
|
|
sphere( crumb, 2, (0,1,0), 1, true, 10, self.debug_time );
|
|
|
|
if ( i > 0 )
|
|
line(previous_crumb, crumb, (0,1,0), 1.0, true, self.debug_time );
|
|
|
|
previous_crumb = crumb;
|
|
}
|
|
|
|
{wait(.05);};
|
|
}
|
|
}
|
|
#/
|
|
|
|
function target_bread_crumbs( target )
|
|
{
|
|
self endon("death");
|
|
target endon("death");
|
|
|
|
self.target_breadcrumbs = [];
|
|
self.target_breadcrumb_current_index = 0;
|
|
self.target_breadcrumb_last_added = 0;
|
|
|
|
minimum_delta_sqr = 20 * 20;
|
|
self.max_crumbs = 20;
|
|
|
|
self.target_breadcrumbs[self.target_breadcrumb_last_added] = get_crumb_position( target );
|
|
|
|
/#
|
|
if ( level.firefly_debug )
|
|
{
|
|
self thread target_bread_crumbs_render( target );
|
|
}
|
|
#/
|
|
|
|
while( 1 )
|
|
{
|
|
wait( 0.25 );
|
|
previous_crumb_index = self.target_breadcrumb_last_added % self.max_crumbs;
|
|
potential_crumb_position = get_crumb_position( target );
|
|
|
|
if ( DistanceSquared( potential_crumb_position, self.target_breadcrumbs[previous_crumb_index] ) > minimum_delta_sqr )
|
|
{
|
|
self.target_breadcrumb_last_added++;
|
|
|
|
// if the newly added point will pass the currently targeted point in the buffer make sure to set the current point
|
|
if ( self.target_breadcrumb_last_added >= (self.target_breadcrumb_current_index + self.max_crumbs) )
|
|
self.target_breadcrumb_current_index = self.target_breadcrumb_last_added - self.max_crumbs + 1 ;
|
|
|
|
self.target_breadcrumbs[self.target_breadcrumb_last_added % self.max_crumbs] = potential_crumb_position;
|
|
}
|
|
}
|
|
}
|
|
|
|
function get_target_bread_crumb( target )
|
|
{
|
|
if ( self.target_breadcrumb_current_index > self.target_breadcrumb_last_added )
|
|
return get_crumb_position( target );
|
|
|
|
current_index = self.target_breadcrumb_current_index % self.max_crumbs;
|
|
|
|
if ( !isDefined( self.target_breadcrumbs[current_index] ) )
|
|
return get_crumb_position( target );
|
|
|
|
return self.target_breadcrumbs[current_index];
|
|
}
|
|
|
|
function firefly_check_move( position, target )
|
|
{
|
|
passed = bullettracepassed(self.origin, position, false, self, target );
|
|
|
|
return passed;
|
|
|
|
//results = PhysicsTraceEx( self.origin, position, (-5,-5,-5), (5,5,5), self );
|
|
//if( results["fraction"] == 1 )
|
|
//{
|
|
// return true;
|
|
//}
|
|
//return false;
|
|
}
|
|
|
|
//******************************************************************
|
|
// *
|
|
// *
|
|
//******************************************************************
|
|
function firefly_chase( target ) // self == script mover spawned at weaponobject location
|
|
{
|
|
level endon("game_ended");
|
|
self endon("death");
|
|
target endon("death");
|
|
target endon( "entering_last_stand" );
|
|
|
|
self clientfield::set( "firefly_state", 2 );
|
|
if( IsPlayer( target ) )
|
|
{
|
|
target clientfield::set_to_player( "fireflies_chasing", 1 );
|
|
}
|
|
|
|
max_distance = 500;
|
|
attack_distance = 50;
|
|
max_offset = 10;
|
|
up = (0,0,1);
|
|
|
|
while(1)
|
|
{
|
|
target_origin = target.origin + (0,0,50);
|
|
delta = target_origin - self.origin;
|
|
dist = Length( delta );
|
|
|
|
if ( dist <= attack_distance && firefly_check_move(target_origin, target ) )
|
|
{
|
|
thread firefly_attack( target, 3 );
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
target_origin = get_target_bread_crumb( target );
|
|
|
|
/#
|
|
if ( level.firefly_debug )
|
|
sphere( self.origin, 2, (1,0,0), 1, true, 10, self.debug_time );
|
|
#/
|
|
|
|
// this code will give some randomness to the target point.
|
|
// delta = target_origin - self.origin;
|
|
// normal = VectorNormalize( delta );
|
|
// right = VectorCross( normal, up );
|
|
// offset = RotatePointAroundAxis( (right * max_offset), normal, RandomInt(359) );
|
|
//
|
|
// target_origin = target_origin + offset;
|
|
}
|
|
delta = target_origin - self.origin;
|
|
angles = VectorToAngles(delta);
|
|
|
|
thread firefly_rotate( angles, 0.15 );
|
|
|
|
dist = Length( delta );
|
|
time = 0.01;
|
|
if ( dist > 0 )
|
|
{
|
|
speed = get_attack_speed( target );
|
|
time = dist / speed;
|
|
}
|
|
|
|
firefly_partial_move( target, target_origin, time, level.firefly_pod_partial_move_percent );
|
|
|
|
self.target_breadcrumb_current_index++;
|
|
}
|
|
}
|
|
|
|
//******************************************************************
|
|
// *
|
|
// *
|
|
//******************************************************************
|
|
function firefly_pod_start( start_pos, target, linked ) // self == script mover spawned at weaponobject location
|
|
{
|
|
level endon("game_ended");
|
|
self endon("death");
|
|
self notify("attack");
|
|
|
|
/#
|
|
if ( level.firefly_debug )
|
|
sphere( self.origin, 4, (1,0,0), 1, true, 10, self.debug_time );
|
|
#/
|
|
|
|
level.fireflies_height_variance = 30;
|
|
level.fireflies_radius = 100;
|
|
|
|
self.target_origin_at_start = target.origin;
|
|
self.target_entity = target;
|
|
|
|
if ( linked )
|
|
{
|
|
// fx_ent = PlayFX( "weapon/fx_hero_firefly_start_entity", self.origin );
|
|
// fx_ent.team = self.team;
|
|
thread firefly_attack( target, 4 );
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
// start bread crumbing immediatly
|
|
thread target_bread_crumbs( target );
|
|
|
|
//delta = target.origin - self.origin;
|
|
//angles = VectorToAngles(delta);
|
|
//self.angles = angles;
|
|
|
|
self MoveTo( start_pos, level.fireflies_emit_time, 0, level.fireflies_emit_time );
|
|
self waittill( "movedone" );
|
|
|
|
if ( isdefined( target ) && isdefined( target.origin ) )
|
|
{
|
|
delta = target.origin - self.origin;
|
|
angles = VectorToAngles(delta);
|
|
self.angles = angles;
|
|
|
|
// self thread firefly_spyrograph_patrol( 60, 1, level.fireflies_radius );
|
|
self thread firefly_chase( target );
|
|
}
|
|
}
|
|
|
|
wait( 30 );
|
|
|
|
if ( isdefined( self.killcamEnt ) )
|
|
{
|
|
self.killcamEnt delete();
|
|
}
|
|
self delete();
|
|
}
|
|
|
|
//******************************************************************
|
|
// *
|
|
// *
|
|
//******************************************************************
|
|
function firefly_pod_release_fireflies( attacker, target ) // self == script mover spawned at weaponobject location
|
|
{
|
|
jumpDir = VectorNormalize( AnglesToUp( self.angles ) );
|
|
|
|
if ( jumpDir[2] > level.fireflies_spawn_height_wall_angle_cos )
|
|
{
|
|
jumpHeight = level.fireflies_spawn_height;
|
|
}
|
|
else
|
|
{
|
|
jumpHeight = level.fireflies_spawn_height_wall;
|
|
}
|
|
|
|
explodePos = self.origin + jumpDir * jumpHeight;
|
|
|
|
self.firefly_mover.spawn_origin = explodePos;
|
|
|
|
linked_to = self GetLinkedEnt();
|
|
linked = (linked_to === target);
|
|
|
|
if ( !linked )
|
|
{
|
|
fx_ent = PlayFX( "weapon/fx_hero_firefly_start", self.origin, AnglesToUp( self.angles ) );
|
|
fx_ent.team = self.team;
|
|
self.firefly_mover clientfield::set( "firefly_state", 1 );
|
|
self.firefly_mover.killCamEnt MoveTo( explodePos + self.firefly_mover.killCamOffset, level.fireflies_emit_time, 0, level.fireflies_emit_time );
|
|
}
|
|
else
|
|
{
|
|
// self.firefly_mover.killCamEnt delete();
|
|
// self.firefly_mover.killCamEnt = undefined;
|
|
}
|
|
|
|
self.firefly_mover thread firefly_pod_start( explodePos, target, linked );
|
|
|
|
self delete();
|
|
}
|
|
|
|
function firefly_pod_should_damage( watcher, attacker, weapon, damage )
|
|
{
|
|
// gel blobs do not damage eachother
|
|
if ( weapon == watcher.weapon )
|
|
return false;
|
|
|
|
if ( weapon.isEmp || weapon.destroysEquipment )
|
|
return true;
|
|
|
|
// anything will kill it over 15 damage
|
|
if ( self.damageTaken < 15 )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
//function firefly_spawn_vehicle( targetEnt )
|
|
//{
|
|
// swarm = SpawnVehicle( "spawner_bo3_cybercom_firefly", origin, angles);
|
|
// if(isDefined(swarm))
|
|
// {
|
|
// swarm.threatbias = -300;
|
|
//
|
|
// swarm.owner = self;
|
|
// swarm.team = self.team;
|
|
// swarm.lifetime = 45;
|
|
// swarm.targetEnt = targetEnt; //set this if you want an initial target
|
|
//
|
|
// swarm.state_machine = statemachine::create( "brain", swarm, "swarm_change_state" );
|
|
// swarm.state_machine statemachine::add_state( "init", &swarm_state_enter, &swarm_init, &swarm_state_cleanup );
|
|
// swarm.state_machine statemachine::add_state( "attack", &swarm_state_enter, &swarm_attack_think,&swarm_state_cleanup );
|
|
// swarm.state_machine statemachine::set_state( "init" );
|
|
// targetEnt = undefined;
|
|
// }
|
|
//}
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//function swarm_state_cleanup( params )
|
|
//{
|
|
// if(isDefined(self.badplace))
|
|
// {
|
|
// badplace_delete("swarmBP_"+self.swarm_ID);
|
|
// self.badplace = undefined;
|
|
// }
|
|
//}
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//function swarm_state_enter( params )
|
|
//{
|
|
// WAIT_SERVER_FRAME;
|
|
//}
|
|
//
|
|
//function drawOriginForever()
|
|
//{
|
|
// for( ;; )
|
|
// {
|
|
// drawArrow( self.origin, self.angles );
|
|
// WAIT_SERVER_FRAME;
|
|
// }
|
|
//}
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//function swarm_init( params )
|
|
//{
|
|
// self setmodel("tag_origin");
|
|
// self notsolid();
|
|
// self.ignoreall = true;
|
|
// self.takedamage = false;
|
|
// self.goalradius = 36;
|
|
// self.goalheight = 36;
|
|
// self.good_melee_target = true;
|
|
// self SetNearGoalNotifyDist( 48 );
|
|
//
|
|
// if(SWARM_SHOW_DEBUG)
|
|
// {
|
|
// self thread drawOriginForever();
|
|
// }
|
|
//
|
|
//// self thread swarm_death_wait();
|
|
//// self thread swarm_split_monitor();
|
|
//// self.sndEnt = spawn( "script_origin", self.origin );
|
|
//// self.sndEnt linkto( self );
|
|
// self clearforcedgoal();
|
|
// self SetGoal( self.origin, true, self.goalradius ); //set the goal for swarm
|
|
//
|
|
// if(!IS_TRUE(self.isOffspring))
|
|
// {
|
|
// enemies = self _get_valid_targets();
|
|
// closeTargets = ArraySortClosest(enemies, self.origin,enemies.size,0,512); //if no nearby targets, lets move out from our current position in the direction player was looking
|
|
// if(closeTargets.size == 0 )
|
|
// {
|
|
// //Move the swarm out and away frmo FXAnim ending spot
|
|
// //this will cause the swarm to move out towards locatoin player was observing
|
|
// //We do this to get the swarm closer to targets that the player was looking at.
|
|
// angles = (self.angles[0],self.angles[1],0);
|
|
// frontGoal = self.origin + (anglestoforward( angles)*240); //max 512 units out
|
|
// a_trace = BulletTrace( self.origin,frontGoal, false, undefined, true );
|
|
// hitp = a_trace[ "position" ]; //but lets check that we can go that far, if not, take the trace point
|
|
//
|
|
// queryResult = PositionQuery_Source_Navigation(hitp, 0, 72, 72, 20, self ); //can swarm find node around where it wants to go?
|
|
// if( queryResult.data.size > 0 )
|
|
// {
|
|
// pathSuccess = self FindPath( self.origin, queryResult.data[0].origin, true, false ); //can swarm path to that location?
|
|
// if ( pathSuccess )
|
|
// {
|
|
// if(SWARM_SHOW_DEBUG)
|
|
// {
|
|
// level thread cybercom::debug_Circle( queryResult.data[0].origin, 16, 10, (1,0,0) );
|
|
// }
|
|
// self clearforcedgoal();
|
|
// self SetGoal( queryResult.data[0].origin, true, self.goalradius ); //set the goal for swarm
|
|
//
|
|
// if(!self.fireBugCount)
|
|
// self clientfield::set("firefly_state",FIREFLY_STATE_HUNT_TRANS_TO_MOVE);
|
|
// else
|
|
// self clientfield::set("firefly_state",FIREBUG_STATE_HUNT_TRANS_TO_MOVE);
|
|
//
|
|
// self util::waittill_any_timeout( 5, "near_goal" );
|
|
// }
|
|
// }
|
|
// }
|
|
// }
|
|
//}
|