boiii-scripts/mp/_incendiary.gsc
2023-04-13 17:30:38 +02:00

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;
}