488 lines
22 KiB
Plaintext
488 lines
22 KiB
Plaintext
#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\entityheadicons_shared;
|
|
#using scripts\shared\killcam_shared;
|
|
#using scripts\shared\scoreevents_shared;
|
|
#using scripts\shared\system_shared;
|
|
#using scripts\shared\util_shared;
|
|
#using scripts\shared\weapons\_tacticalinsertion;
|
|
#using scripts\shared\weapons\_weaponobjects;
|
|
#using scripts\shared\_burnplayer;
|
|
|
|
|
|
|
|
|
|
|
|
#namespace incendiary;
|
|
|
|
function autoexec __init__sytem__() { system::register("incendiary_grenade",&init_shared,undefined,undefined); }
|
|
|
|
|
|
function init_shared()
|
|
{
|
|
level.incendiaryfireDamage = GetDvarInt( "scr_incendiaryfireDamage", 35 ); // how much damage will the fire do each tick
|
|
level.incendiaryfireDamageHardcore = GetDvarInt( "scr_incendiaryfireDamageHardcore", 15 ); // how much damage will the fire do each tick in hardcore
|
|
level.incendiaryfireDuration = GetDvarInt ("scr_incendiaryfireDuration", 5 ); // time damage triggers will last.
|
|
level.incendiaryfxDuration = GetDvarFloat( "scr_incendiaryfxDuration", 0.4 ); // Incendiary fx duration
|
|
level.incendiaryDamageRadius = GetDvarInt( "scr_incendiaryDamageRadius", 125 ); // radius of individual damages
|
|
level.incendiaryfireDamageTickTime = GetDvarFloat( "scr_incendiaryfireDamageTickTime", 1 ); // time between damage hits
|
|
|
|
|
|
level.incendiaryDamageThisTick = [];
|
|
|
|
callback::on_spawned( &create_incendiary_watcher );
|
|
}
|
|
|
|
/#
|
|
function updateIncendiaryFromDvars()
|
|
{
|
|
level.incendiaryfireDamage = GetDvarInt( "scr_incendiaryfireDamage", level.incendiaryfireDamage );
|
|
level.incendiaryfireDamageHardcore = GetDvarInt( "scr_incendiaryfireDamageHardcore", level.incendiaryfireDamageHardcore );
|
|
level.incendiaryfireDuration = GetDvarInt( "scr_incendiaryfireDuration", level.incendiaryfireDuration );
|
|
level.incendiaryDamageRadius = GetDvarInt( "scr_incendiaryDamageRadius", level.incendiaryDamageRadius );
|
|
level.incendiaryfireDamageTickTime = GetDvarFloat( "scr_incendiaryfireDamageTickTime", level.incendiaryfireDamageTickTime );
|
|
level.incendiaryfxDuration = GetDvarFloat( "scr_incendiaryfxDuration", level.incendiaryfxDuration );
|
|
}
|
|
#/
|
|
|
|
function create_incendiary_watcher() // self == player
|
|
{
|
|
watcher = self weaponobjects::createUseWeaponObjectWatcher( "incendiary_grenade", self.team );
|
|
|
|
watcher.onSpawn = &incendiary_system_spawn;
|
|
}
|
|
|
|
function incendiary_system_spawn( watcher, player ) // self == incendiary grenade
|
|
{
|
|
player endon( "death" );
|
|
player endon( "disconnect" );
|
|
level endon( "game_ended" );
|
|
|
|
player AddWeaponStat( self.weapon, "used", 1 );
|
|
thread watchForExplode( player );
|
|
}
|
|
|
|
|
|
function watchForExplode( owner )
|
|
{
|
|
self endon( "hacked" );
|
|
self endon( "delete" );
|
|
|
|
killCamEnt = spawn( "script_model", self.origin );
|
|
killCamEnt util::deleteAfterTime( 15.0 );
|
|
killCamEnt.startTime = gettime();
|
|
killCamEnt linkto( self );
|
|
killCamEnt setWeapon( self.weapon );
|
|
|
|
killcamEnt killcam::store_killcam_entity_on_entity(self);
|
|
|
|
self waittill( "projectile_impact_explode", origin, normal, surface );
|
|
killCamEnt unlink();
|
|
/#
|
|
updateIncendiaryFromDvars();
|
|
#/
|
|
PlaySoundAtPosition ("wpn_incendiary_core_start" ,self.origin);
|
|
|
|
generateLocations( origin, owner, normal, killCamEnt );
|
|
}
|
|
|
|
function getstepoutdistance( normal )
|
|
{
|
|
if ( normal[2] < 0.5 )
|
|
{
|
|
stepoutdistance = normal * GetDvarInt( "scr_incendiary_stepout_wall", 50 );
|
|
}
|
|
else
|
|
{
|
|
stepoutdistance = normal * GetDvarInt( "scr_incendiary_stepout_ground", 12 );
|
|
}
|
|
return stepoutdistance;
|
|
}
|
|
|
|
function generateLocations( position, owner, normal, killCamEnt )
|
|
{
|
|
startPos = position + getstepoutdistance( normal );
|
|
desiredEndPos = startPos + ( 0, 0, 60 );
|
|
physTrace = PhysicsTrace( startPos, desiredEndPos, ( -4, -4, -4 ), ( 4, 4, 4 ), self, (1 << 0) );
|
|
goalPos = ( ( physTrace[ "fraction" ] < 1 ) ? physTrace[ "position"] : desiredEndPos );
|
|
|
|
killCamEnt moveto( goalPos, 0.5 );
|
|
rotation = RandomInt( 360 );
|
|
|
|
if ( normal[2] < 0.1 ) // vertical wall
|
|
{
|
|
black = ( 0.1, 0.1, 0.1 );
|
|
|
|
trace = hitPos( startPos, startpos + ( -normal * 70 ) + ( 0,0, -1 ) * 70, black );
|
|
tracePosition = trace["position"];
|
|
incendiaryGrenade = GetWeapon( "incendiary_fire" );
|
|
|
|
if ( trace["fraction"] < 0.9 )
|
|
{
|
|
wallnormal = trace["normal"];
|
|
SpawnTimedFX( incendiaryGrenade, trace["position"], wallnormal, level.incendiaryfireDuration, self.team );
|
|
}
|
|
}
|
|
|
|
fxCount = GetDvarInt( "scr_incendiary_fx_count", 6 );
|
|
spawnAllLocs( owner, startPos, normal, 1, rotation, killcament, fxCount );
|
|
}
|
|
|
|
function getLocationForFX( startPos, fxIndex, fxCount, defaultDistance, rotation )
|
|
{
|
|
currentAngle = ( ( 360 / fxCount ) * fxIndex );
|
|
cosCurrent = cos( currentAngle + rotation );
|
|
sinCurrent = sin( currentAngle + rotation );
|
|
|
|
return startPos + ( defaultDistance * cosCurrent, defaultDistance * sinCurrent, 0 );
|
|
}
|
|
|
|
function spawnAllLocs( owner, startPos, normal, multiplier, rotation, killcament, fxCount )
|
|
{
|
|
defaultDistance = GetDvarInt( "scr_incendiary_trace_distance", 220 ) * multiplier;
|
|
defaultDropDistance = GetDvarInt( "scr_incendiary_trace_down_distance", 90 );
|
|
|
|
// DROCHE:TODO
|
|
// if we are going to keep this grenade this should be moved to code
|
|
|
|
colorArray = [];
|
|
colorArray[colorArray.size] = ( 0.9, 0.2, 0.2 );
|
|
colorArray[colorArray.size] = ( 0.2, 0.9, 0.2 );
|
|
colorArray[colorArray.size] = ( 0.2, 0.2, 0.9 );
|
|
colorArray[colorArray.size] = ( 0.9, 0.9, 0.9 );
|
|
|
|
|
|
locations = [];
|
|
locations["color"] = [];
|
|
locations["loc"] = [];
|
|
locations["tracePos"] = [];
|
|
locations["distSqrd"] = [];
|
|
locations["fxtoplay"] = [];
|
|
locations["radius"] = [];
|
|
|
|
|
|
for( fxIndex = 0; fxIndex < fxCount; fxIndex++ )
|
|
{
|
|
locations["point"][fxIndex] = getLocationForFX( startPos, fxIndex, fxCount, defaultDistance, rotation );
|
|
locations["color"][fxIndex] = colorArray[fxIndex % colorArray.size];
|
|
}
|
|
|
|
for ( count = 0; count < fxCount; count++ )
|
|
{
|
|
trace = hitPos( startPos, locations["point"][count], locations["color"][count] );
|
|
tracePosition = trace["position"];
|
|
locations["tracePos"][count] = tracePosition;
|
|
|
|
if ( trace["fraction"] < 0.7 )
|
|
{
|
|
locations["loc"][count] = tracePosition;
|
|
locations["normal"][count] = trace["normal"];
|
|
continue;
|
|
}
|
|
|
|
average = startPos/2 + tracePosition/2;
|
|
|
|
trace = hitPos( average, average - ( 0, 0, defaultDropDistance ), locations["color"][count] );
|
|
if ( trace["fraction"] != 1 )
|
|
{
|
|
locations["loc"][count] = trace["position"];
|
|
locations["normal"][count] = trace["normal"];
|
|
}
|
|
}
|
|
|
|
// startPos = startPos - getstepoutdistance( normal ); // start pos is already a good position for fx, we are using a different sized trigger now.
|
|
|
|
incendiaryGrenade = GetWeapon( "incendiary_fire" );
|
|
|
|
SpawnTimedFX( incendiaryGrenade, startPos, normal, level.incendiaryfireDuration, self.team );
|
|
|
|
level.incendiaryDamageRadius = GetDvarInt( "scr_incendiaryDamageRadius", level.incendiaryDamageRadius );
|
|
|
|
thread damageEffectArea ( owner, startPos, level.incendiaryDamageRadius, level.incendiaryDamageRadius, killCamEnt );
|
|
|
|
for ( count = 0; count < locations["point"].size; count++ )
|
|
{
|
|
if ( isdefined ( locations["loc"][count] ) )
|
|
{
|
|
normal = locations["normal"][count];
|
|
|
|
SpawnTimedFX( incendiaryGrenade, locations["loc"][count], normal, level.incendiaryfireDuration, self.team );
|
|
}
|
|
}
|
|
}
|
|
|
|
/#
|
|
function incendiary_debug_line( from, to, color, depthTest, time )
|
|
{
|
|
debug_rcbomb = GetDvarInt( "scr_incendiary_debug", 0 );
|
|
if ( debug_rcbomb == 1 )
|
|
{
|
|
if ( !isdefined(time) )
|
|
{
|
|
time = 100;
|
|
}
|
|
if ( !isdefined(depthTest) )
|
|
{
|
|
depthTest = true;
|
|
}
|
|
Line( from, to, color, 1, depthTest, time);
|
|
}
|
|
}
|
|
#/
|
|
|
|
|
|
|
|
function damageEffectArea ( owner, position, radius, height, killCamEnt )
|
|
{
|
|
trigger_radius_position = position - ( 0 , 0, height );
|
|
trigger_radius_height = height * 2;
|
|
|
|
fireEffectArea = spawn( "trigger_radius", trigger_radius_position, 0, radius, trigger_radius_height );
|
|
|
|
// Create head icon
|
|
// objective = GetEquipmentHeadObjective( GetWeapon( "incendiary_grenade" ) );
|
|
// killCamEnt entityheadicons::setEntityHeadIcon( owner.pers["team"], owner, (0,0,0), objective );
|
|
|
|
/#
|
|
if( GetDvarint( "scr_draw_triggers" ) )
|
|
level thread util::drawcylinder( trigger_radius_position, radius, trigger_radius_height, undefined, "incendiary_draw_cylinder_stop" );
|
|
#/
|
|
|
|
// raps stuff
|
|
if ( isdefined( level.rapsOnBurnRaps ) )
|
|
{
|
|
owner thread [[level.rapsOnBurnRaps]]( fireEffectArea );
|
|
}
|
|
|
|
ownerOriginalTeam = owner.team;
|
|
|
|
// loop variables
|
|
loopWaitTime = level.incendiaryFireDamageTickTime;
|
|
durationOfIncendiary = level.incendiaryFireDuration;
|
|
|
|
// loop for the duration of the effect
|
|
while (durationOfIncendiary > 0)
|
|
{
|
|
if ( isdefined( owner ) && owner.team !== ownerOriginalTeam )
|
|
{
|
|
break;
|
|
}
|
|
|
|
durationOfIncendiary -= loopWaitTime;
|
|
damageApplied = false;
|
|
|
|
potential_targets = self getPotentialTargets( owner );
|
|
foreach( target in potential_targets )
|
|
{
|
|
self tryToApplyFireDamage( target, owner, position, fireEffectArea, loopWaitTime, killcament );
|
|
}
|
|
|
|
wait (loopWaitTime);
|
|
}
|
|
|
|
// Delete head icon
|
|
if ( isdefined( killCamEnt ) )
|
|
killCamEnt entityheadicons::destroyEntityHeadIcons();
|
|
// clean up
|
|
fireEffectArea delete();
|
|
|
|
/#
|
|
if( GetDvarint( "scr_draw_triggers" ) )
|
|
level notify( "incendiary_draw_cylinder_stop" );
|
|
#/
|
|
}
|
|
|
|
function getPotentialTargets( owner ) // self == incendiary grenade
|
|
{
|
|
// try getting team based targets first
|
|
owner_team = ( isdefined( owner ) ? owner.team : undefined );
|
|
if ( level.teambased && isdefined( owner_team ) && level.friendlyfire == 0 )
|
|
{
|
|
enemy_team = ( owner_team == "axis" ? "allies" : "axis" );
|
|
potential_targets = [];
|
|
potential_targets = ArrayCombine( potential_targets, GetPlayers( enemy_team ), false, false );
|
|
potential_targets = ArrayCombine( potential_targets, GetAITeamArray( enemy_team ), false, false );
|
|
potential_targets = ArrayCombine( potential_targets, GetVehicleTeamArray( enemy_team ), false, false );
|
|
potential_targets[ potential_targets.size ] = owner;
|
|
return potential_targets;
|
|
}
|
|
|
|
// now get all targets
|
|
all_targets = [];
|
|
all_targets = ArrayCombine( all_targets, level.players, false, false );
|
|
all_targets = ArrayCombine( all_targets, GetAIArray(), false, false );
|
|
all_targets = ArrayCombine( all_targets, GetVehicleArray(), false, false );
|
|
|
|
// if this is hardcore, then every entity is a potential target
|
|
if ( level.friendlyfire > 0 )
|
|
return all_targets;
|
|
|
|
// remove all targets not on the same team, except owner
|
|
potential_targets = [];
|
|
foreach( target in all_targets )
|
|
{
|
|
if ( !isdefined( target ) )
|
|
continue;
|
|
|
|
if( !isdefined( target.team ) )
|
|
continue;
|
|
|
|
if( isdefined( owner ) )
|
|
{
|
|
if( target != owner )
|
|
{
|
|
if( !isdefined( owner_team ) )
|
|
continue;
|
|
|
|
if( target.team == owner_team )
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( !isdefined( self ) )
|
|
continue;
|
|
|
|
if( !isdefined( self.team ) )
|
|
continue;
|
|
|
|
if( target.team == self.team )
|
|
continue;
|
|
}
|
|
|
|
potential_targets[ potential_targets.size ] = target;
|
|
}
|
|
|
|
return potential_targets;
|
|
}
|
|
|
|
function tryToApplyFireDamage( target, owner, position, fireEffectArea, resetFireTime, killcament ) // self == incendiary grenade
|
|
{
|
|
// see if we're not in the fire area
|
|
if ( ( !isdefined(target.infireArea) ) || (target.infireArea == false) )
|
|
{
|
|
// since we're not in the poison area, now see if we're in the fire area
|
|
if ( target istouching(fireEffectArea) && ( !isdefined(target.sessionstate) || target.sessionstate == "playing" ) )
|
|
{
|
|
trace = bullettrace( position, target GetShootAtPos(), false, target, true );
|
|
|
|
if ( trace["fraction"] == 1 )
|
|
{
|
|
target.lastburnedBy = owner;
|
|
target thread damageInFireArea( fireEffectArea, killcament, trace, position, resetFireTime );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function damageInFireArea( fireEffectArea, killcament, trace, position, resetFireTime ) // self == player in fire area
|
|
{
|
|
self endon( "disconnect" );
|
|
self endon( "death" );
|
|
|
|
timer = 0;
|
|
|
|
damage = level.incendiaryfireDamage;
|
|
if( level.hardcoreMode )
|
|
{
|
|
damage = level.incendiaryfireDamageHardcore;
|
|
}
|
|
|
|
if ( canDoFireDamage( killCamEnt, self, resetFireTime ) )
|
|
{
|
|
/#
|
|
level.incendiary_debug = GetDvarInt( "scr_incendiary_debug", 0 );
|
|
if ( level.incendiary_debug )
|
|
{
|
|
if ( !isdefined( level.incendiaryDamageTime ) )
|
|
{
|
|
level.incendiaryDamageTime = GetTime();
|
|
}
|
|
|
|
iprintlnbold( level.incendiaryDamageTime - getTime() );
|
|
level.incendiaryDamageTime = getTime();
|
|
}
|
|
#/
|
|
self DoDamage( damage, fireEffectArea.origin, self.lastburnedBy, killCamEnt, "none", "MOD_BURNED", 0, GetWeapon( "incendiary_fire" ) );
|
|
|
|
entnum = self getentitynumber();
|
|
|
|
self thread sndFireDamage();
|
|
}
|
|
}
|
|
|
|
|
|
function sndFireDamage()
|
|
{
|
|
self notify( "sndFire" );
|
|
self endon( "death" );
|
|
self endon( "disconnect" );
|
|
self endon( "sndFire" );
|
|
|
|
if( !isdefined( self.sndFireEnt ) )
|
|
{
|
|
self.sndFireEnt = spawn( "script_origin", self.origin );
|
|
self.sndFireEnt linkto( self, "tag_origin" );
|
|
self.sndFireEnt playsound( "chr_burn_start" );
|
|
self thread sndFireDamage_DeleteEnt(self.sndFireEnt);
|
|
}
|
|
|
|
self.sndFireEnt playloopsound( "chr_burn_start_loop", .5 );
|
|
wait(3);
|
|
self.sndFireEnt delete();
|
|
self.sndFireEnt = undefined;
|
|
}
|
|
function sndFireDamage_DeleteEnt(ent)
|
|
{
|
|
self endon( "disconnect" );
|
|
self waittill( "death" );
|
|
|
|
if( isdefined( ent ) )
|
|
ent delete(); //pfx_fire_incendiary
|
|
}
|
|
|
|
|
|
function hitPos( start, end, color )
|
|
{
|
|
trace = bullettrace( start, end, false, undefined );
|
|
|
|
/#
|
|
level.incendiary_debug = GetDvarInt( "scr_incendiary_debug", 0 );
|
|
if ( level.incendiary_debug )
|
|
{
|
|
debugstar(trace["position"], 2 * 1000, color);
|
|
}
|
|
|
|
thread incendiary_debug_line( start, trace["position"], color, true, 80 );
|
|
#/
|
|
|
|
return trace;
|
|
}
|
|
|
|
function canDoFireDamage( killCamEnt, victim, resetFireTime )
|
|
{
|
|
entNum = victim getentitynumber();
|
|
if ( !isdefined( level.incendiaryDamageThisTick[entNum] ) )
|
|
{
|
|
level.incendiaryDamageThisTick[entNum] = 0;
|
|
level thread resetFireDamage( entnum, resetFireTime );
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
function resetFireDamage( entnum, time )
|
|
{
|
|
if ( time > 0.05 )
|
|
{
|
|
wait( time - 0.05 );
|
|
}
|
|
level.incendiaryDamageThisTick[entnum] = undefined;
|
|
}
|
|
|
|
|