326 lines
8.2 KiB
Plaintext
326 lines
8.2 KiB
Plaintext
#include maps\mp\_utility;
|
|
#include maps\mp\gametypes\_hud_util;
|
|
#include common_scripts\utility;
|
|
#include maps\mp\agents\_agent_utility;
|
|
#include maps\mp\gametypes\_damage;
|
|
|
|
|
|
//===========================================
|
|
// constants
|
|
//===========================================
|
|
CONST_MAX_ACTIVE_KILLSTREAK_DOGS_PER_GAME = 3;
|
|
CONST_MAX_ACTIVE_KILLSTREAK_DOGS_PER_PLAYER = 3;
|
|
CONST_MAX_ACTIVE_KILLSTREAK_AGENTS_PER_PLAYER = 3;
|
|
CONST_DOG_KILL_COUNT_LIMIT = 2;
|
|
CONST_STREAK_TIMEOUT = 60;
|
|
CONST_STREAK_RETREAT_TIMEOUT=20;
|
|
|
|
init()
|
|
{
|
|
level.killstreakFuncs["mp_instinct"] = ::tryUseMPInstinct;
|
|
level.mapKillStreak = "mp_instinct";
|
|
|
|
level.InstinctDogs = [];
|
|
|
|
//PreCacheModel( "sb_pig_table_noguts" );
|
|
PreCacheModel( "animal_iw6_dog_a" );
|
|
|
|
level.killstreakWieldWeapons[ "killstreak_instinct_mp" ] = "mp_instinct";
|
|
|
|
level.InstinctDogSpawnPoints =[];
|
|
|
|
SpawnPoints = GetNodeArray( "InstinctDogSpawnPoint", "targetname" );
|
|
|
|
foreach( point in SpawnPoints)
|
|
{
|
|
tempPoint = SpawnStruct();
|
|
tempPoint.SpawnPoint = point;
|
|
tempPoint.Weight = 0;
|
|
|
|
level.InstinctDogSpawnPoints = add_to_array(level.InstinctDogSpawnPoints, tempPoint);
|
|
}
|
|
|
|
OnPlayerConnect();
|
|
}
|
|
|
|
tryUseMPInstinct(lifeId, streakName)
|
|
{
|
|
return spawnInstinctDogs();
|
|
}
|
|
|
|
|
|
setMPInstinctPlayer( player )
|
|
{
|
|
level.mp_instinct_owner = player;
|
|
|
|
thread teamPlayerCardSplash( "used_mp_instinct", player );
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
OnPlayerConnect()
|
|
{
|
|
connectCount =0;
|
|
for(;;)
|
|
{
|
|
level waittill("connected", player);
|
|
|
|
if(connectCount==0)
|
|
{
|
|
if ( !IsDefined(level.isHorde) || !level.isHorde )
|
|
{
|
|
level.agent_funcs["dog"]["think"] = maps\mp\agents\dog\_instinct_dog_think::main;
|
|
level.agent_funcs["dog"]["on_killed"] = ::on_agent_dog_killed;
|
|
}
|
|
}
|
|
|
|
connectCount++;
|
|
player thread onPlayerSpawned();
|
|
}
|
|
}
|
|
|
|
|
|
onPlayerSpawned()
|
|
{
|
|
self endon("disconnect");
|
|
|
|
self waittill( "spawned_player" );
|
|
|
|
self thread MonitorKills();
|
|
}
|
|
|
|
|
|
//===========================================
|
|
// spawnInstinctDogs //spawn three from smart spawn locations around the map.
|
|
//===========================================
|
|
spawnInstinctDogs()
|
|
{
|
|
// limit the number of active "dog" agents allowed per game
|
|
if( getNumActiveAgents( "dog" ) >= CONST_MAX_ACTIVE_KILLSTREAK_DOGS_PER_GAME )
|
|
{
|
|
self iPrintLnBold( &"KILLSTREAKS_TOO_MANY_DOGS" );
|
|
return false;
|
|
}
|
|
// limit the number of active "dog" agents allowed per player
|
|
if( getNumOwnedActiveAgentsByType( self, "dog" ) >= CONST_MAX_ACTIVE_KILLSTREAK_DOGS_PER_PLAYER )
|
|
{
|
|
self iPrintLnBold( &"KILLSTREAKS_ALREADY_HAVE_DOG" );
|
|
return false;
|
|
}
|
|
// limit the number of active agents allowed per player
|
|
if( getNumOwnedActiveAgents( self ) >= CONST_MAX_ACTIVE_KILLSTREAK_AGENTS_PER_PLAYER )
|
|
{
|
|
self iPrintLnBold( &"KILLSTREAKS_AGENT_MAX" );
|
|
return false;
|
|
}
|
|
|
|
// TODO: we should probably do a queue system for these, so the player can call it but it'll go into a queue for when an agent dies to open up a spot
|
|
// limit the number of active agents allowed per player
|
|
maxagents = GetMaxAgents();
|
|
if( getNumActiveAgents() >= maxagents )
|
|
{
|
|
self iPrintLnBold( &"KILLSTREAKS_UNAVAILABLE" );
|
|
return false;
|
|
}
|
|
|
|
// make sure the player is still alive before the agent trys to spawn on the player
|
|
if( !isReallyAlive( self ) )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
ConnectAndSpawnInstinctDogPack();
|
|
|
|
return true;
|
|
}
|
|
|
|
SortInstinctDogSpawnPoints()
|
|
{
|
|
foreach(point in level.InstinctDogSpawnPoints)
|
|
{
|
|
point.Weight=0;
|
|
//rate points by distance from owner
|
|
tempDistance = Distance(point.SpawnPoint.origin,self.origin);
|
|
if(tempDistance<1500)
|
|
point.Weight=1;
|
|
else if(tempDistance>1500 && tempDistance<2000)
|
|
point.Weight=2;
|
|
else if(tempDistance>2000 && tempDistance<2500)
|
|
point.Weight=3;
|
|
else if(tempDistance>2500)
|
|
point.Weight=4;
|
|
|
|
//rate points by los and distance to other players
|
|
foreach(player in level.players)
|
|
{
|
|
start_pos = point.SpawnPoint.origin;
|
|
target_pos = player.origin;
|
|
LineOfSightCheck = SightTracePassed(start_pos ,target_pos , false, player);
|
|
|
|
if( LineOfSightCheck )
|
|
point.Weight--;
|
|
|
|
tempDistance = Distance(point.SpawnPoint.origin,player.origin);
|
|
if(tempDistance<256)
|
|
point.Weight--;
|
|
}
|
|
}
|
|
|
|
level.InstinctDogSpawnPoints = array_sort_with_func(level.InstinctDogSpawnPoints, ::isPointAScoredHigherThanB);
|
|
}
|
|
|
|
PickInstinctDogSpawnPoint()
|
|
{
|
|
SpawnPoint = level.InstinctDogSpawnPoints[0];
|
|
|
|
level.InstinctDogSpawnPoints = array_remove(level.InstinctDogSpawnPoints, level.InstinctDogSpawnPoints[0]);
|
|
|
|
return SpawnPoint;
|
|
}
|
|
|
|
isPointAScoredHigherThanB( a, b )
|
|
{
|
|
return ( a.Weight > b.Weight );
|
|
}
|
|
|
|
WaitForTimeout()
|
|
{
|
|
self waittill_any_timeout( CONST_STREAK_TIMEOUT, "KillCountMet" );
|
|
self notify("retreat");
|
|
DeleteNodes = GetNodeArray("DeletePoint", "targetname");
|
|
Node = getClosest(self.origin, DeleteNodes);
|
|
self notify("timeoutRetreat");
|
|
self ScrAgentSetGoalPos( Node.origin );
|
|
|
|
//waits till dog hits retreat node or a timeout for dogs who get stuck...
|
|
self waittill_any_timeout(CONST_STREAK_RETREAT_TIMEOUT, "stop_soon" );
|
|
|
|
//TODO kill the dog gracefully...
|
|
self Suicide();
|
|
self notify("death");
|
|
}
|
|
|
|
ConnectAndSpawnInstinctDogPack()
|
|
{
|
|
SortInstinctDogSpawnPoints();
|
|
for(i=0;i<3;i++)
|
|
{
|
|
// try to spawn the agent on a path node near the player
|
|
nearestPathNode = self PickInstinctDogSpawnPoint( );
|
|
|
|
if( !IsDefined(nearestPathNode) )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// find an available agent
|
|
agent = maps\mp\agents\_agent_common::connectNewAgent( "dog" , self.team );
|
|
if( !IsDefined( agent ) )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
oldHealth = self.health;
|
|
newHealth = 25;
|
|
self.agenthealth = newHealth;
|
|
self.health = newHealth;
|
|
self.maxhealth = newHealth;
|
|
|
|
level.InstinctDogs = array_add(level.InstinctDogs,agent);
|
|
|
|
agent thread WaitForDeath( nearestPathNode );
|
|
|
|
// set the agent to the player's team
|
|
agent set_agent_team( self.team, self );
|
|
|
|
spawnOrigin = nearestPathNode.SpawnPoint.origin;
|
|
spawnAngles = VectorToAngles( self.origin - nearestPathNode.SpawnPoint.origin );
|
|
|
|
agent thread [[ agent agentFunc("spawn") ]]( spawnOrigin, spawnAngles, self );
|
|
|
|
//agent _setNameplateMaterial( "player_name_bg_green_dog", "player_name_bg_red_dog" );
|
|
|
|
if ( IsDefined( self.ballDrone ) && self.ballDrone.ballDroneType == "ball_drone_backup" )
|
|
{
|
|
self maps\mp\gametypes\_missions::processChallenge( "ch_twiceasdeadly" );
|
|
}
|
|
|
|
agent thread WaitForTimeout();
|
|
}
|
|
}
|
|
|
|
WaitForDeath( PathNode )
|
|
{
|
|
self waittill_any( "death", "retreat" );
|
|
level.InstinctDogSpawnPoints = array_add(level.InstinctDogSpawnPoints, PathNode );
|
|
level.InstinctDogs =array_remove(level.InstinctDogs, self);
|
|
}
|
|
|
|
MonitorKills()
|
|
{
|
|
while(true)
|
|
{
|
|
self waittill("death",instigator);
|
|
|
|
foreach(dog in level.InstinctDogs)
|
|
{
|
|
if(instigator == dog)
|
|
{
|
|
if(!IsDefined(dog.EnemyKills))
|
|
dog.EnemyKills =0;
|
|
|
|
dog.EnemyKills++;
|
|
|
|
if(dog.EnemyKills>=CONST_DOG_KILL_COUNT_LIMIT)
|
|
dog notify("KillCountMet");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//=======================================================
|
|
// on_agent_dog_killed
|
|
//=======================================================
|
|
on_agent_dog_killed( eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, timeOffset, deathAnimDuration )
|
|
{
|
|
self.isActive = false;
|
|
self.hasDied = false;
|
|
|
|
eAttacker.lastKillDogTime = GetTime();
|
|
|
|
if ( IsDefined( self.animCBs.OnExit[ self.aiState ] ) )
|
|
self [[ self.animCBs.OnExit[ self.aiState ] ]] ();
|
|
|
|
// award XP for killing agents
|
|
if( isPlayer( eAttacker ) && IsDefined(self.owner) && (eAttacker != self.owner) )
|
|
{
|
|
self.owner leaderDialogOnPlayer( "dog_kia_mp_instinct" );
|
|
self maps\mp\gametypes\_damage::onKillstreakKilled( eAttacker, sWeapon, sMeansOfDeath, iDamage, "destroyed_guard_dog" );
|
|
|
|
if ( IsPlayer( eAttacker ) )
|
|
{
|
|
eAttacker maps\mp\gametypes\_missions::processChallenge( "ch_notsobestfriend" );
|
|
|
|
// assume jumping?
|
|
if ( !self IsOnGround() )
|
|
{
|
|
eAttacker maps\mp\gametypes\_missions::processChallenge( "ch_hoopla" );
|
|
}
|
|
}
|
|
}
|
|
|
|
self SetAnimState( "death" );
|
|
animEntry = self GetAnimEntry();
|
|
animLength = GetAnimLength( animEntry );
|
|
|
|
deathAnimDuration = int( animLength * 1000 ); // duration in milliseconds
|
|
|
|
self.body = self CloneAgent( deathAnimDuration );
|
|
|
|
self PlaySound( "anml_dog_shot_death" );
|
|
|
|
self maps\mp\agents\_agent_utility::deactivateAgent();
|
|
|
|
self notify( "killanimscript" );
|
|
} |