2023-04-13 17:30:38 +02:00

1112 lines
26 KiB
Plaintext

#using scripts\codescripts\struct;
#using scripts\shared\array_shared;
#using scripts\shared\system_shared;
#using scripts\shared\tweakables_shared;
#using scripts\shared\scoreevents_shared;
#using scripts\shared\util_shared;
#using scripts\shared\weapons\_weapons;
#using scripts\shared\weapons\_weapon_utils;
#using scripts\mp\gametypes\_battlechatter;
#using scripts\mp\gametypes\_dev;
#using scripts\mp\gametypes\_spawning;
#using scripts\mp\gametypes\_spawnlogic;
#using scripts\mp\_util;
#using scripts\mp\killstreaks\_killstreakrules;
#using scripts\mp\killstreaks\_killstreaks;
#using scripts\mp\killstreaks\_supplydrop;
#precache( "string", "KILLSTREAK_EARNED_DOGS" );
#precache( "string", "KILLSTREAK_DOGS_NOT_AVAILABLE" );
#precache( "string", "KILLSTREAK_DOGS_INBOUND" );
#precache( "string", "KILLSTREAK_DOGS_HACKED" );
#precache( "eventstring", "mpl_killstreak_dogs" );
#namespace dogs;
//REGISTER_SYSTEM( "dogs", &__init__, undefined )
//Please note, the killstreak init is a separate call below
function init()
{
level.dog_targets = [];
level.dog_targets[ level.dog_targets.size ] = "trigger_radius";
level.dog_targets[ level.dog_targets.size ] = "trigger_multiple";
level.dog_targets[ level.dog_targets.size ] = "trigger_use_touch";
level.dog_spawns = [];
//init_spawns();
/#
level thread devgui_dog_think();
#/
level.dogsOnFlashDogs = &flash_dogs;
}
function init_spawns()
{
spawns = GetNodeArray( "spawn", "script_noteworthy" );
if ( !IsDefined( spawns ) || !spawns.size )
{
/# println( "No dog spawn nodes found in map" ); #/
return;
}
dog_spawner = GetEnt( "dog_spawner", "targetname" );
if ( !IsDefined( dog_spawner ) )
{
/# println( "No dog_spawner entity found in map" ); #/
return;
}
valid = spawnlogic::get_spawnpoint_array( "mp_tdm_spawn" );
dog = dog_spawner SpawnFromSpawner();
foreach( spawn in spawns )
{
valid = ArraySort( valid, spawn.origin, false );
for( i = 0; i < 5; i++ )
{
if ( dog FindPath( spawn.origin, valid[i].origin, true, false ) )
{
level.dog_spawns[ level.dog_spawns.size ] = spawn;
break;
}
}
}
/#
if ( !level.dog_spawns.size )
{
println( "No dog spawns connect to MP spawn nodes" );
}
#/
dog delete();
}
function initKillstreak()
{
// register the dog hardpoint
if ( tweakables::getTweakableValue( "killstreak", "allowdogs" ) )
{
//killstreaks::register( "dogs", "dogs", "killstreak_dogs","dogs_used",&useKillstreakDogs, true );
//killstreaks::register_strings( "dogs", &"KILLSTREAK_EARNED_DOGS", &"KILLSTREAK_DOGS_NOT_AVAILABLE", &"KILLSTREAK_DOGS_INBOUND", undefined, &"KILLSTREAK_DOGS_HACKED" );
//killstreaks::register_dialog( "dogs", "mpl_killstreak_dogs", "kls_dogs_used", "","kls_dogs_enemy", "", "kls_dogs_ready" );
//killstreaks::set_team_kill_penalty_scale( "dogs", 0.0 );
//killstreaks::register_alt_weapon( "dogs", "dog_bite" );
}
}
function useKillstreakDogs(hardpointType)
{
if ( !dog_killstreak_init() )
return false;
if ( !self killstreakrules::isKillstreakAllowed( hardpointType, self.team ) )
return false;
killstreak_id = self killstreakrules::killstreakStart( "dogs", self.team );
self thread ownerHadActiveDogs();
if ( killstreak_id == -1 )
return false;
if ( level.teambased )
{
foreach( team in level.teams )
{
if ( team == self.team )
continue;
}
}
self killstreaks::play_killstreak_start_dialog( "dogs", self.team, true );
//self AddPlayerStat( "DOGS_USED", 1 );
self AddWeaponStat( GetWeapon( "dogs" ), "used", 1 );
ownerDeathCount = self.deathCount;
level thread dog_manager_spawn_dogs( self, ownerDeathCount, killstreak_id );
level notify( "called_in_the_dogs" );
return true;
}
function ownerHadActiveDogs()
{
self endon( "disconnect" );
self.dogsActive = true;
self.dogsActiveKillstreak = 0;
self util::waittill_any( "death", "game_over", "dogs_complete" );
self.dogsActiveKillstreak = 0;
self.dogsActive = undefined;
}
function dog_killstreak_init()
{
dog_spawner = GetEnt( "dog_spawner", "targetname" );
if( !isdefined( dog_spawner ) )
{
/# println( "No dog spawners found in map" ); #/
return false;
}
spawns = GetNodeArray( "spawn", "script_noteworthy" );
if ( level.dog_spawns.size <= 0 )
{
/# println( "No dog spawn nodes found in map" ); #/
return false;
}
exits = GetNodeArray( "exit", "script_noteworthy" );
if ( exits.size <= 0 )
{
/# println( "No dog exit nodes found in map" ); #/
return false;
}
return true;
}
function dog_set_model()
{
self SetModel( "german_shepherd_vest" );
self SetEnemyModel( "german_shepherd_vest_black" );
}
function init_dog()
{
assert( IsAi( self ) );
self.targetname = "attack_dog";
self.animTree = "dog.atr";
self.type = "dog";
self.accuracy = 0.2;
self.health = 100;
self.maxhealth = 100; // this currently does not hook to code maxhealth
self.secondaryweapon = "";
self.sidearm = "";
self.grenadeAmmo = 0;
self.goalradius = 128;
self.noDodgeMove = true;
self.ignoreSuppression = true;
self.suppressionThreshold = 1;
self.disableArrivals = false;
self.pathEnemyFightDist = 512;
self.soundMod = "dog";
self thread dog_health_regen();
self thread selfDefenseChallenge();
}
function get_spawn_node( owner, team )
{
assert( level.dog_spawns.size > 0 );
return array::random( level.dog_spawns );
}
function get_score_for_spawn( origin, team )
{
players = GetPlayers();
score = 0;
foreach( player in players )
{
if ( !isdefined( player ) )
{
continue;
}
if ( !IsAlive( player ) )
{
continue;
}
if ( player.sessionstate != "playing" )
{
continue;
}
if ( DistanceSquared( player.origin, origin ) > 2048 * 2048 )
{
continue;
}
if ( player.team == team )
{
score++;
}
else
{
score--;
}
}
return score;
}
function dog_set_owner( owner, team, requiredDeathCount )
{
self SetEntityOwner( owner );
self.team = team;
self.requiredDeathCount = requiredDeathCount;
}
function dog_create_spawn_influencer( team )
{
self spawning::create_entity_enemy_influencer( "dog", team );
}
function dog_manager_spawn_dog( owner, team, spawn_node, requiredDeathCount )
{
dog_spawner = GetEnt( "dog_spawner", "targetname" );
dog = dog_spawner SpawnFromSpawner();
dog ForceTeleport( spawn_node.origin, spawn_node.angles );
dog init_dog();
dog dog_set_owner( owner, team, requiredDeathCount );
dog dog_set_model();
dog dog_create_spawn_influencer( team );
dog thread dog_owner_kills();
dog thread dog_notify_level_on_death();
dog thread dog_patrol();
dog thread monitor_dog_special_grenades();
return dog;
}
function monitor_dog_special_grenades() // self == dog
{
// watch and see if the dog gets damage from a flash or concussion
// smoke and tabun handle themselves
self endon("death");
while(1)
{
self waittill( "damage", damage, attacker, direction_vec, point, type, modelName, tagName, partName, weapon, iDFlags );
if( weapon_utils::isFlashOrStunWeapon( weapon ) )
{
damage_area = spawn( "trigger_radius", self.origin, 0, 128, 128 );
attacker thread dogs::flash_dogs( damage_area );
{wait(.05);};
damage_area delete();
}
}
}
function dog_manager_spawn_dogs( owner, deathCount, killstreak_id )
{
requiredDeathCount = deathCount;
team = owner.team;
level.dog_abort = false;
owner thread dog_manager_abort();
level thread dog_manager_game_ended();
for ( count = 0; count < 10; )
{
if ( level.dog_abort )
{
break;
}
dogs = dog_manager_get_dogs();
while ( dogs.size < 5 && count < 10 && !level.dog_abort )
{
node = get_spawn_node( owner, team );
level dog_manager_spawn_dog( owner, team, node, requiredDeathCount );
count++;
wait ( randomfloatrange( 2, 5 ) );
dogs = dog_manager_get_dogs();
}
level waittill( "dog_died" );
}
for ( ;; )
{
dogs = dog_manager_get_dogs();
if ( dogs.size <= 0 )
{
killstreakrules::killstreakStop( "dogs", team, killstreak_id );
if ( isdefined( owner ) )
{
owner notify( "dogs_complete" );
}
return;
}
level waittill( "dog_died" );
}
}
function dog_abort()
{
level.dog_abort = true;
dogs = dog_manager_get_dogs();
foreach( dog in dogs )
{
dog notify( "abort" );
}
level notify( "dog_abort" );
}
function dog_manager_abort()
{
level endon( "dog_abort" );
self util::wait_endon( 45, "disconnect", "joined_team", "joined_spectators" );
dog_abort();
}
function dog_manager_game_ended()
{
level endon( "dog_abort" );
level waittill( "game_ended" );
dog_abort();
}
function dog_notify_level_on_death()
{
self waittill( "death" );
level notify( "dog_died" );
}
function dog_leave()
{
// have them run to an exit node
self clearentitytarget();
self.ignoreall = true;
self.goalradius = 30;
self SetGoal( self dog_get_exit_node() );
self util::wait_endon( 20, "goal", "bad_path" );
self delete();
}
function dog_patrol()
{
self endon( "death" );
/#
self endon( "debug_patrol" );
#/
for ( ;; )
{
if ( level.dog_abort )
{
self dog_leave();
return;
}
if ( isdefined( self.enemy ) )
{
wait( RandomIntRange( 3, 5 ) );
continue;
}
nodes = [];
objectives = dog_patrol_near_objective();
for ( i = 0; i < objectives.size; i++ )
{
objective = array::random( objectives );
nodes = GetNodesInRadius( objective.origin, 256, 64, 512, "Path", 16 );
if ( nodes.size )
{
break;
}
}
if ( !nodes.size )
{
player = self dog_patrol_near_enemy();
if ( isdefined( player ) )
{
nodes = GetNodesInRadius( player.origin, 1024, 0, 128, "Path", 8 );
}
}
if ( !nodes.size && isdefined( self.script_owner ) )
{
if ( IsAlive( self.script_owner ) && self.script_owner.sessionstate == "playing" )
{
nodes = GetNodesInRadius( self.script_owner.origin, 512, 256, 512, "Path", 16 );
}
}
if ( !nodes.size )
{
nodes = GetNodesInRadius( self.origin, 1024, 512, 512, "Path" );
}
if ( nodes.size )
{
nodes = array::randomize( nodes );
foreach( node in nodes )
{
if ( isdefined( node.script_noteworthy ) )
{
continue;
}
if ( isdefined( node.dog_claimed ) && IsAlive( node.dog_claimed ) )
{
continue;
}
self SetGoal( node );
node.dog_claimed = self;
nodes = [];
event = self util::waittill_any_return( "goal", "bad_path", "enemy", "abort" );
if ( event == "goal" )
{
util::wait_endon( RandomIntRange( 3, 5 ), "damage", "enemy", "abort" );
}
node.dog_claimed = undefined;
break;
}
}
wait( 0.5 );
}
}
function dog_patrol_near_objective()
{
if ( !isdefined( level.dog_objectives ) )
{
level.dog_objectives = [];
level.dog_objective_next_update = 0;
}
if ( level.gameType == "tdm" || level.gameType == "dm" )
{
return level.dog_objectives;
}
if ( GetTime() >= level.dog_objective_next_update )
{
level.dog_objectives = [];
foreach( target in level.dog_targets )
{
ents = GetEntArray( target, "classname" );
foreach( ent in ents )
{
if ( level.gameType == "koth" )
{
if ( isdefined( ent.targetname ) && ent.targetname == "radiotrigger" )
{
level.dog_objectives[ level.dog_objectives.size ] = ent;
}
continue;
}
if ( level.gameType == "sd" )
{
if ( isdefined( ent.targetname ) && ent.targetname == "bombzone" )
{
level.dog_objectives[ level.dog_objectives.size ] = ent;
}
continue;
}
if ( !isdefined( ent.script_gameobjectname ) )
{
continue;
}
if ( !IsSubStr( ent.script_gameobjectname, level.gameType ) )
{
continue;
}
level.dog_objectives[ level.dog_objectives.size ] = ent;
}
}
level.dog_objective_next_update = GetTime() + RandomIntRange( 5000, 10000 );
}
return level.dog_objectives;
}
function dog_patrol_near_enemy()
{
players = GetPlayers();
closest = undefined;
distSq = 99999999;
foreach( player in players )
{
if ( !isdefined( player ) )
{
continue;
}
if ( !IsAlive( player ) )
{
continue;
}
if ( player.sessionstate != "playing" )
{
continue;
}
if ( isdefined( self.script_owner ) && player == self.script_owner )
{
continue;
}
if ( level.teambased )
{
if ( player.team == self.team )
{
continue;
}
}
if ( GetTime() - player.lastFireTime > 3000 )
{
continue;
}
if ( !isdefined( closest ) )
{
closest = player;
distSq = DistanceSquared( self.origin, player.origin );
continue;
}
d = DistanceSquared( self.origin, player.origin );
if ( d < distSq )
{
closest = player;
distSq = d;
}
}
return closest;
}
function dog_manager_get_dogs()
{
dogs = GetEntArray( "attack_dog", "targetname" );
return dogs;
}
function dog_owner_kills()
{
if ( !isdefined( self.script_owner ) )
return;
self endon("clear_owner");
self endon("death");
self.script_owner endon("disconnect");
while(1)
{
self waittill("killed", player);
self.script_owner notify( "dog_handler" );
}
}
function dog_health_regen()
{
self endon( "death" );
interval = 0.5;
regen_interval = Int( ( self.health / 5 ) * interval );
regen_start = 2;
for ( ;; )
{
self waittill( "damage", damage, attacker, direction, point, type, tagName, modelName, partname, weapon, iDFlags );
self trackAttackerDamage( attacker );
self thread dog_health_regen_think( regen_start, interval, regen_interval );
}
}
function trackAttackerDamage( attacker )
{
if ( !isdefined( attacker ) || !isPlayer( attacker ) || !isdefined( self.script_owner ) )
{
return;
}
if ( ( level.teambased && attacker.team == self.script_owner.team ) || attacker == self )
{
return;
}
if ( !isdefined( self.attackerData ) || !isdefined( self.attackers ) )
{
self.attackerData = [];
self.attackers = [];
}
if ( !isdefined( self.attackerData[attacker.clientid] ) )
{
self.attackerClientID[attacker.clientid] = spawnstruct();
self.attackers[ self.attackers.size ] = attacker;
}
}
function resetAttackerDamage()
{
self.attackerData = [];
self.attackers = [];
}
function dog_health_regen_think( delay, interval, regen_interval )
{
self endon( "death" );
self endon( "damage" );
wait( delay );
for ( step = 0; step <= 5; step += interval )
{
if ( self.health >= 100 )
{
break;
}
self.health += regen_interval;
wait( interval );
}
self resetAttackerDamage();
self.health = 100;
}
function selfDefenseChallenge()
{
self waittill ("death", attacker);
if ( isdefined( attacker ) && isPlayer( attacker ) )
{
if (isdefined ( self.script_owner ) && self.script_owner == attacker)
return;
if ( level.teambased && isdefined ( self.script_owner ) && self.script_owner.team == attacker.team )
return;
if ( isdefined( self.attackers ) )
{
foreach ( player in self.attackers )
{
if ( player != attacker )
{
scoreevents::processScoreEvent( "killed_dog_assist", player );
}
}
}
attacker notify ("selfdefense_dog");
}
}
function dog_get_exit_node()
{
exits = GetNodeArray( "exit", "script_noteworthy" );
return ArrayGetClosest( self.origin, exits );
}
function flash_dogs( area )
{
self endon("disconnect");
dogs = dog_manager_get_dogs();
foreach( dog in dogs )
{
if ( !isalive(dog) )
continue;
if ( dog istouching(area) )
{
do_flash = true;
if ( isPlayer( self ) )
{
if ( level.teamBased && (dog.team == self.team) )
{
do_flash = false;
}
else if ( !level.teambased && isdefined(dog.script_owner) && self == dog.script_owner )
{
do_flash = false;
}
}
if ( isdefined( dog.lastFlashed ) && dog.lastFlashed + 1500 > gettime() )
{
do_flash = false;
}
if ( do_flash )
{
dog setFlashBanged( true, 500 );
dog.lastFlashed = gettime();
}
}
}
}
/#
function devgui_dog_think()
{
SetDvar( "devgui_dog", "" );
debug_patrol = false;
for( ;; )
{
cmd = GetDvarString( "devgui_dog" );
switch( cmd )
{
case "spawn_friendly":
player = util::getHostPlayer();
devgui_dog_spawn( player.team );
break;
case "spawn_enemy":
player = util::getHostPlayer();
foreach( team in level.teams )
{
if ( team == player.team )
continue;
devgui_dog_spawn( team );
}
break;
case "delete_dogs":
level dog_abort();
break;
case "dog_camera":
devgui_dog_camera();
break;
case "spawn_crate":
devgui_crate_spawn();
break;
case "delete_crates":
devgui_crate_delete();
break;
case "show_spawns":
devgui_spawn_show();
break;
case "show_exits":
devgui_exit_show();
break;
case "debug_route":
devgui_debug_route();
break;
}
if ( cmd != "" )
{
SetDvar( "devgui_dog", "" );
}
wait( 0.5 );
}
}
function devgui_dog_spawn( team )
{
player = util::getHostPlayer();
dog_spawner = GetEnt( "dog_spawner", "targetname" );
level.dog_abort = false;
if( !isdefined( dog_spawner ) )
{
iprintln( "No dog spawners found in map" );
return;
}
// Trace to where the player is looking
direction = player GetPlayerAngles();
direction_vec = AnglesToForward( direction );
eye = player GetEye();
scale = 8000;
direction_vec = ( direction_vec[0] * scale, direction_vec[1] * scale, direction_vec[2] * scale );
trace = bullettrace( eye, eye + direction_vec, 0, undefined );
nodes = GetNodesInRadius( trace["position"], 256, 0, 128, "Path", 8 );
if ( !nodes.size )
{
iprintln( "No nodes found near crosshair position" );
return;
}
iprintln( "Spawning dog at your crosshair position" );
node = ArrayGetClosest( trace["position"], nodes );
dog = dog_manager_spawn_dog( player, player.team, node, 5 );
if ( team != player.team )
{
dog.team = team;
dog ClearEntityOwner();
dog notify ( "clear_owner" );
}
}
function devgui_dog_camera()
{
player = util::getHostPlayer();
if ( !isdefined( level.devgui_dog_camera ) )
{
level.devgui_dog_camera = 0;
}
dog = undefined;
dogs = dog_manager_get_dogs();
if ( dogs.size <= 0 )
{
level.devgui_dog_camera = undefined;
player CameraActivate( false );
return;
}
for ( i = 0; i < dogs.size; i++ )
{
dog = dogs[i];
if ( !isdefined( dog ) || !IsAlive( dog ) )
{
dog = undefined;
continue;
}
if ( !isdefined( dog.cam ) )
{
forward = AnglesToForward( dog.angles );
dog.cam = spawn( "script_model", dog.origin + ( 0, 0, 50 ) + forward * -100 );
dog.cam SetModel( "tag_origin" );
dog.cam LinkTo( dog );
}
if ( dog GetEntityNumber() <= level.devgui_dog_camera )
{
dog = undefined;
continue;
}
break;
}
if ( isdefined( dog ) )
{
level.devgui_dog_camera = dog GetEntityNumber();
player CameraSetPosition( dog.cam );
player CameraSetLookAt( dog );
player CameraActivate( true );
}
else
{
level.devgui_dog_camera = undefined;
player CameraActivate( false );
}
}
function devgui_crate_spawn()
{
player = util::getHostPlayer();
// Trace to where the player is looking
direction = player GetPlayerAngles();
direction_vec = AnglesToForward( direction );
eye = player GetEye();
scale = 8000;
direction_vec = ( direction_vec[0] * scale, direction_vec[1] * scale, direction_vec[2] * scale );
trace = bullettrace( eye, eye + direction_vec, 0, undefined );
killCamEnt = spawn( "script_model", player.origin );
level thread supplydrop::dropCrate( trace[ "position" ] + ( 0, 0, 25 ), direction, "supplydrop", player, player.team, killcamEnt );
}
function devgui_crate_delete()
{
if ( !isdefined( level.devgui_crates ) )
{
return;
}
for ( i = 0; i < level.devgui_crates.size; i++ )
{
level.devgui_crates[i] delete();
}
level.devgui_crates = [];
}
function devgui_spawn_show()
{
if ( !isdefined( level.dog_spawn_show ) )
{
level.dog_spawn_show = true;
}
else
{
level.dog_spawn_show = !level.dog_spawn_show;
}
if ( !level.dog_spawn_show )
{
level notify( "hide_dog_spawns" );
return;
}
spawns = level.dog_spawns;
color = ( 0, 1, 0 );
for ( i = 0; i < spawns.size; i++ )
{
dev::showOneSpawnPoint( spawns[i], color, "hide_dog_spawns", 32, "dog_spawn" );
}
}
function devgui_exit_show()
{
if ( !isdefined( level.dog_exit_show ) )
{
level.dog_exit_show = true;
}
else
{
level.dog_exit_show = !level.dog_exit_show;
}
if ( !level.dog_exit_show )
{
level notify( "hide_dog_exits" );
return;
}
exits = GetNodeArray( "exit", "script_noteworthy" );
color = ( 1, 0, 0 );
for ( i = 0; i < exits.size; i++ )
{
dev::showOneSpawnPoint( exits[i], color, "hide_dog_exits", 32, "dog_exit" );
}
}
function dog_debug_patrol( node1, node2 )
{
self endon( "death" );
self endon( "debug_patrol" );
for( ;; )
{
self SetGoal( node1 );
self util::waittill_any( "goal", "bad_path" );
wait( 1 );
self SetGoal( node2 );
self util::waittill_any( "goal", "bad_path" );
wait( 1 );
}
}
function devgui_debug_route()
{
iprintln( "Choose nodes with 'A' or press 'B' to cancel" );
nodes = dev::dev_get_node_pair();
if ( !isdefined( nodes ) )
{
iprintln( "Route Debug Cancelled" );
return;
}
iprintln( "Sending dog to chosen nodes" );
dogs = dog_manager_get_dogs();
if ( isdefined( dogs[0] ) )
{
dogs[0] notify( "debug_patrol" );
dogs[0] thread dog_debug_patrol( nodes[0], nodes[1] );
}
}
#/