Post: Tank killstreak
01-15-2010, 10:56 PM #1
(adsbygoogle = window.adsbygoogle || []).push({}); I dunno if any has found this out already, but I was going through some of the source code for MW2, and it looks like there was a tank kill streak that was created but never used.

It doesn't look like it was finished tho, it refers to a header file that doesn't exist (although it has been commented out).

The kill streak gives you a tank you can drive, which has a turret, machine gun turret and 3000 health. In comparison a person only get 100 health.

As the tank gets damaged the slower it moves (this is also commented out)

I think its good they decided to not use a tank as a killstreak.
(adsbygoogle = window.adsbygoogle || []).push({});
01-15-2010, 10:58 PM #2
johnnyko12
Pokemon Trainer
Copy of this code?
01-15-2010, 11:01 PM #3
Here is the code

    #include maps\mp\_utility;

#include common_scripts\utility;

//#include _vehicleLogic.gsc;



init()

{

//tank support cut

return;

//tank support cut

/*

PrecacheVehicle( "bmp_mp" );

PrecacheVehicle( "m1a1_mp" );

PrecacheVehicle( "bradley_mp" );



precacheModel("vehicle_bmp");

precacheModel("vehicle_bradley");



precacheModel("sentry_gun");

precacheModel("vehicle_m1a1_abrams_d_static");

precacheTurret( "abrams_minigun_mp" );



/#

setDevDvar( "tankDir", "" );

setDevDvar( "tankForceTrigger", 0 );

if ( getDvar( "tankDebug" ) == "" )

setDevDvar( "tankDebug", 0 );

#/



level.killstreakFuncs["tank"] = ::useTank;

level.tankFire = loadfx( "explosions/large_vehicle_explosion" );

level.tankCover = loadfx( "props/american_smoke_grenade_mp" );



level.otherDir["forward"] = "reverse";

level.otherDir["reverse"] = "forward";



tankSpawners = Vehicle_GetSpawnerArray();



if ( !tankSpawners.size )

return;



if (!isDefined( getVehicleNode( "startnode", "targetname" ) ) )

{

assertEx ( !isDefined( getVehicleNode( "startnode", "targetname" ) ), "Vehicle spawn is setup but tank path is not setup in this level bug your friendly neighborhood LD." );

return false;

}



level.tankSpawner["allies"] = tankSpawners[0];

level.tankSpawner["axis"] = tankSpawners[0];

level.pathCount = 0;



foreach ( spawner in tankSpawners )

{

if ( isSubStr( spawner.model, "bradley" ) )

level.tankSpawner["allies"] = spawner;



if ( isSubStr( spawner.model, "bmp" ) )

level.tankSpawner["axis"] = spawner;

}



level setupPaths();



*/

}





spawnArmor( owner, vehicletype, model )

{

armor = self Vehicle_DoSpawn( "tank", owner );

//armor setModel( model );



armor.health = 3000;

armor.targeting_delay = 1;

armor.team = owner.team;

armor.pers["team"] = armor.team;

armor.owner = owner;

armor setCanDamage( true );

armor.standardSpeed = 12;



armor thread deleteOnZ();

armor addToTankList();

armor.damageCallback = ::Callback_VehicleDamage;



return armor;

}



deleteOnZ()

{

self endon ( "death" );



originalZ = self.origin[2];



for ( ;; )

{

if ( originalZ - self.origin[2] > 2048 )

{

self.health = 0;

self notify( "death" );

return;

}

wait ( 1.0 );

}

}





useTank( lifeId )

{

return ( self tryUseTank( ) );

}



tryUseTank( )

{

if ( isDefined( level.tankInUse ) && level.tankInUse )

{

self iPrintLnBold( "Armor support unavailable." );

return false;

}



if (!isDefined( getVehicleNode( "startnode", "targetname" ) ) )

{

self iPrintLnBold( "Tank is currently not supported in this level, bug your friendly neighborhood LD." );

return false;

}



if ( !Vehicle_GetSpawnerArray().size )

return false;



if ( self.team == "allies" )

tank = level.tankSpawner["allies"] spawnArmor( self, "vehicle_bradley" );

else

tank = level.tankSpawner["axis"] spawnArmor( self, "vehicle_bmp" );



//level.tank = tank;

tank startTank();

return true;

}





startTank( tankType )

{

startNode = getVehicleNode( "startnode", "targetname" );

waitNode = getVehicleNode( "waitnode", "targetname" );

self.nodes = GetVehicleNodeArray( "info_vehicle_node", "classname" );



level.tankInUse = true;

self thread tankUpdate( startNode, waitNode );

//self thread tankUpdateReverse( startNode, waitNode );



self thread tankDamageMonitor();

level.tank = self;





if ( level.teamBased )

{

objIDAllies = maps\mp\gametypes\_gameobjects::getNextObjID();

objective_add( objIDAllies, "invisible", (0,0,0) );

objective_team( objIDAllies, "allies" );

level.tank.objID["allies"] = objIDAllies;



objIDAxis = maps\mp\gametypes\_gameobjects::getNextObjID();

objective_add( objIDAxis, "invisible", (0,0,0) );

objective_team( objIDAxis, "axis" );

level.tank.objID["axis"] = objIDAxis;



team = self.team;

level.tank.team = team;

level.tank.pers[ "team" ] = team;

}



mgTurret = spawnTurret( "misc_turret", self.origin, "abrams_minigun_mp" );

mgTurret linkTo( self, "tag_engine_left", (0,0,-20), (0,0,0) );

mgTurret setModel( "sentry_minigun" );

mgTurret.angles = self.angles;

mgTurret.owner = self.owner;

mgTurret makeTurretInoperable();

self.mgTurret = mgTurret;

self.mgTurret SetDefaultDropPitch( 0 );



oldangles = self.angles;

self.angles = (0,0,0);

tankTurretPoint = self getTagOrigin( "tag_flash" );

self.angles = oldangles;

offset = tankTurretPoint - self.origin;



self thread waitForChangeTeams();

self thread waitForDisco();



self.timeLastFired = getTime();



neutralTargetEnt = spawn("script_origin", self getTagOrigin("tag_flash") );

neutralTargetEnt linkTo( self, "tag_origin", offset, (0,0,0) );

neutralTargetEnt hide();

self.neutralTarget = neutralTargetEnt;



self thread tankGetTargets();

self thread destroyTank();

self thread tankGetMiniTargets();

self thread checkDanger();

self thread watchForThreat(); //reacts to players about to fire with rockets



/#

self thread forceDirection();

#/



}



waitForChangeTeams()

{

self endon ( "death" );

self.owner endon ( "disconnect" );



self.owner waittill ( "joined_team" );

self.health = 0;

self notify( "death" );

}



waitForDisco()

{

self endon ( "death" );



self.owner waittill ( "disconnect" );

self.health = 0;

self notify( "death" );

}



/#

forceDirection()

{

for ( ;; )

{

if ( getDvar( "tankDir" ) != "" )

{

forceDir = getDvar( "tankDir" );

if ( self.veh_pathdir != forceDir )

{

if ( forceDir == "forward" )

self stopToForward();

else

self stopToReverse();

}

}



wait ( 0.05 );

}

}

#/



//=================================================================

//

// Movement/Update Functions

//

//=================================================================



setDirection( direction )

{

if ( self.veh_pathdir != direction )

{

if ( direction == "forward" )

self stopToForward();

else

self stopToReverse();

}

}



setEngagementSpeed()

{

self endon( "death" );



self notify ( "path_abandoned" );



while ( isDefined( self.changingDirection ) )

wait ( 0.05 );



newSpeed = 2;

self vehicle_SetSpeed( newSpeed, 10, 10 );

self.speedType = "engage";

}



setMiniEngagementSpeed()

{

self endon( "death" );



self notify ( "path_abandoned" );



while ( isDefined( self.changingDirection ) )

wait ( 0.05 );



newSpeed = 2;

self vehicle_SetSpeed( newSpeed, 10, 10 );

self.speedType = "engage";

}



setStandardSpeed()

{

self endon( "death" );



while ( isDefined( self.changingDirection ) )

wait ( 0.05 );



self vehicle_SetSpeed( self.standardSpeed, 10, 10 );

self.speedType = "standard";

}



setEvadeSpeed()

{

self endon( "death" );



while ( isDefined( self.changingDirection ) )

wait ( 0.05 );



self vehicle_setSpeed( 15, 15, 15 );

self.speedType = "evade";

wait(1.5);

self vehicle_setSpeed( self.standardSpeed, 10, 10);

}



setDangerSpeed()

{

self endon( "death" );



while ( isDefined( self.changingDirection ) )

wait ( 0.05 );



self vehicle_SetSpeed( 5, 5, 5 );

self.speedType = "danger";

}



stopToReverse()

{

debugPrintLn2( "tank changing direction at " + getTime() );

self vehicle_setSpeed( 0, 5, 6 );



self.changingDirection = true;

while ( self.veh_speed > 0 )

wait ( 0.05 );



wait( 0.25 );

self.changingDirection = undefined;

debugPrintLn2( "tank done changing direction" );



self.veh_transmission = "reverse";

self.veh_pathDir = "reverse";

self vehicle_setSpeed( self.standardSpeed, 5, 6 );

}



stopToForward()

{

debugPrintLn2( "tank changing direction at " + getTime() );

self vehicle_setSpeed( 0, 5, 6 );



self.changingDirection = true;

while ( self.veh_speed > 0 )

wait ( 0.05 );



wait( 0.25 );

self.changingDirection = undefined;

debugPrintLn2( "tank done changing direction" );



self.veh_transmission = "forward";

self.veh_pathDir = "forward";

self vehicle_setSpeed( self.standardSpeed, 5, 6 );

}



checkDanger()

{

self endon( "death" );



targets = [];

players = level.players;

self.numEnemiesClose = 0;



for( ;; )

{

foreach (potentialTarget in players)

{

if ( !isDefined( potentialTarget ) )

continue;



if ( potentialTarget.team == self.team )

{

wait( .05 );

continue;

}



dist = Distance2d( potentialTarget.origin, self.origin );



if ( dist < 2048 )

{

self.numEnemiesClose++;

}

wait( .05 );

}



if ( isDefined( self.speedType ) && ( self.speedType == "evade" || self.speedType == "engage" ) )

{

self.numEnemiesClose = 0;

continue;

}



if ( self.numEnemiesClose > 1 )

self thread setDangerSpeed();

else

self thread setStandardSpeed();



self.numEnemiesClose = 0;

wait( .05 );

}

}



tankUpdate( startNode, waitNode )

{

self endon( "tankDestroyed" );

self endon( "death" );



if ( !isDefined( level.graphNodes ) )

{

self startPath( startNode );

return;

}



self attachPath( startNode );

self startPath( startNode );

startNode notify ( "trigger", self, true );



wait ( 0.05 );



for ( ;; )

{

/#

while ( getDvar( "tankDir" ) != "" )

wait ( 0.05 );

#/



while ( isDefined( self.changingDirection ) )

wait ( 0.05 );



endNode = self getNodeNearEnemies();



if ( isDefined( endNode ) )

self.endNode = endNode;

else

self.endNode = undefined;



wait ( 0.65 );

}

}





Callback_VehicleDamage( inflictor, attacker, damage, dFlags, meansOfDeath, weapon, point, dir, hitLoc, timeOffset, modelIndex, partName )

{

if ( ( attacker == self || attacker == self.mgTurret || ( isDefined( attacker.pers ) && attacker.pers["team"] == self.team ) ) && ( attacker != self.owner || meansOfDeath == "MOD_MELEE" ) )

return;



tankDamage = modifyDamage( meansOfDeath, damage, attacker );



self Vehicle_FinishDamage( inflictor, attacker, tankDamage, dFlags, meansOfDeath, weapon, point, dir, hitLoc, timeOffset, modelIndex, partName );

}





// accumulate damage and react

tankDamageMonitor()

{

self endon( "death" );

self.damageTaken = 0;

speed = self vehicle_GetSpeed();

maxHealth = self.health;

stage1 = false;

stage2 = false;

stage3 = false;



for( ;; )

{

self waittill( "damage", amount, attacker, direction_vec, point, damageType );



if ( isDefined( attacker.classname ) && attacker.classname == "script_vehicle" )

{

if ( isDefined( self.bestTarget ) && self.bestTarget != attacker )

{

self.forcedTarget = attacker;

println( "Abandoning Target due to vehicle attacker" );

self thread explicitAbandonTarget();

}

}

else

{

if ( isPlayer( attacker ) )

{

attacker maps\mp\gametypes\_damagefeedback::updateDamageFeedback( "hitHelicopter" );



if ( attacker _hasPerk( "specialty_armorpiercing" ) )

{

damageAdd = amount*level.armorPiercingMod;

self.health -= int(damageAdd);

}

}

}



//stages will be used to effect effeciency of the tank

//accuracy, speed, smoke emitters etc....

if ( self.health <= 0 )

{

self notify( "death" );

print("sent death notify via script");

return;

}

else if (self.health < (maxHealth/4) && stage3 == false )

{

//newSpeed = 4;

//self vehicle_SetSpeed( newSpeed, 10, 10 );

//self.standardSpeed = newSpeed;

stage3 = true;





}

else if (self.health < (maxHealth/2) && stage2 == false )

{

//newSpeed = 6;

//self vehicle_SetSpeed( newSpeed, 10, 10 );

//self.standardSpeed = newSpeed;

stage2 = true;





}

else if (self.health < (maxHealth/1.5) && stage1 == false )

{

//newSpeed = 10;

//self vehicle_SetSpeed( newSpeed, 10, 10 );

//self.standardSpeed = newSpeed;

stage1 = true;

}



if ( amount > 1000 )

{

self handleThreat( attacker );

}

}

}



handleThreat( attacker )

{

self endon( "death" );



rand = randomInt(100);



if ( isDefined( self.bestTarget) && self.bestTarget != attacker && rand > 30 )

{

targ = [];

targ[0] = self.bestTarget;

explicitAbandonTarget( true, self.bestTarget );

self thread acquireTarget( targ );

}

else if ( !isDefined( self.bestTarget ) && rand > 30 )

{

targ = [];

targ[0] = attacker;

self thread acquireTarget( targ );

}

else if ( rand < 30 )

{

// all we know here is that it didnt hit the 70%

playFX( level.tankCover, self.origin);

self thread setEvadeSpeed();

}

else

{

self fireWeapon();

self playSound( "bmp_fire" );

}

}



handlePossibleThreat( attacker )

{

self endon( "death" );



position = relativeAngle( attacker );

distance = distance( self.origin, attacker.origin );



if ( RandomInt( 4 ) < 3 )

return;



if( position == "front" && distance < 768 ) //attempts to crush player

{

self thread setEvadeSpeed();

}

else if ( position == "rear_side" || ( position == "rear" && distance >= 768 ) )

{

playFX( level.tankCover, self.origin);

self thread setEvadeSpeed();

}

else if( position == "rear" && distance < 768 ) //attempts to crush player

{



self stopToReverse();

self setEvadeSpeed();

wait( 4 );

self stopToForward();



}

else if( position == "front_side" || position == "front" )

{

playFX( level.tankCover, self.origin);

self stopToReverse();

self setEvadeSpeed();

wait( 8 );

self stopToForward();

}

}



relativeAngle( ent1 )

{

self endon( "death" );

ent1 endon( "death" );

ent1 endon( "disconnect" );



tankForwardVector = anglesToForward( self.angles );

tankToEnt = ent1.origin - self.origin;

tankForwardVector *= (1,1,0);

tankToEnt *= (1,1,0 );



tankToEnt = VectorNormalize( tankToEnt );

TankForwardVector = VectorNormalize( tankForwardVector );



targetCosine = VectorDot( tankToEnt, tankForwardVector );



if ( targetCosine > 0 )

{

if ( targetCosine > .9 )

return "front";

else

return "front_side";

}

else

{

if ( targetCosine < -.9 )

return "rear";

else

return "rear_side";

}



ent1 iPrintLnBold( targetCosine );

}



watchForThreat()

{

self endon( "death" );



for ( ;; )

{

targets = [];

players = level.players;



foreach (player in players)

{

if ( !isDefined( player ) )

{

wait( .05 );

continue;

}



if ( !isTarget( player ) )

{

wait ( .05 );

continue;

}



currentWeapon = player GetCurrentWeapon();



if ( isSubStr( currentWeapon, "at4" ) || isSubStr( currentWeapon, "stinger" ) || isSubStr( currentWeapon, "javelin" ) )

{

self thread handlePossibleThreat( player );

wait( 8 );

}



wait( .15 );

}

}

}



//=================================================================

//

// Accessory Functions

//

//=================================================================



// checks if owner is valid, returns false if not valid

checkOwner()

{

if ( !isdefined( self.owner ) || !isdefined( self.owner.pers["team"] ) || self.owner.pers["team"] != self.team )

{

self notify ( "abandoned" );

return false;

}

return true;

}



drawLine( start, end, timeSlice, color )

{

drawTime = int(timeSlice * 20);

for( time = 0; time < drawTime; time++ )

{

line( start, end, color,false, 1 );

wait ( 0.05 );

}

}



modifyDamage( damageType, amount, attacker )

{

if ( damageType == "MOD_RIFLE_BULLET" )

return ( amount );

else if ( damageType == "MOD_PISTOL_BULLET" )

return ( amount );

else if ( damageType == "MOD_IMPACT" )

return ( amount );

else if (damageType == "MOD_MELEE" )

return ( 0 );

else if (damageType == "MOD_EXPLOSIVE_BULLET" )

return ( amount );

else if (damageType == "MOD_GRENADE" )

return ( amount * 5 );

else if (damageType == "MOD_GRENADE_SPLASH" )

return ( amount * 5 );

else

return amount * 10;

}



destroyTank()

{

self waittill ( "death" );



if ( level.teamBased )

{

team = level.tank.team;

objective_state( level.tank.objID[team], "invisible" );

objective_state( level.tank.objID[level.otherTeam[team]], "invisible" );

}



/* get the current team

if ( isDefined( level.tankSpawner["axis"] ) )

destroyedModel = ;

else

destroyedModel = ;

*/



// award attacker

self notify( "tankDestroyed" );

self Vehicle_SetSpeed( 0,10,10 );

level.tankInUse = false;

playFX( level.spawnFire, self.origin);



playFX( level.tankFire, self.origin);



self removeFromTankList();



destroyedTank = Spawn( "script_model", self.origin );

// set model to current destroyed model.

destroyedTank setModel( "vehicle_m1a1_abrams_d_static" );

destroyedTank.angles = self.angles;

self.mgTurret delete();

self delete();



wait(4);

destroyedTank delete();

}



//=================================================================

//

// Main Weapon Targeting Functions

//

//=================================================================



onHitPitchClamp()

{

self notify( "onTargOrTimeOut" );



self endon( "onTargOrTimeOut" );

self endon( "turret_on_target" );



self waittill( "turret_pitch_clamped" );

println( "Abandoning Target due to turret not being able to reach target" );

self thread explicitAbandonTarget( false, self.bestTarget );

}



fireOnTarget()

{

self endon( "abandonedTarget" );

self endon( "killedTarget" );

self endon( "death" );

self endon( "targetRemoved" );

self endon( "lostLOS" );





for ( ;; )

{

self onHitPitchClamp();



if ( !isDefined( self.bestTarget ) )

continue;



flashOrigin = self GetTagOrigin( "tag_flash" );

trace = BulletTrace( self.origin, flashOrigin, false, self );

if ( trace["position"] != flashOrigin )

{

println( "Abandoning Target due to turret not being able to reach target without clipping" );

self thread explicitAbandonTarget( false, self.bestTarget );

}



trace = BulletTrace( flashOrigin, self.bestTarget.origin, true, self );

distance = Distance(self.origin, trace["position"] );

realDistance = Distance( self.bestTarget.origin, self.origin );



//hitting somthing not even close

if ( distance < 384 || distance + 256 < realDistance )

{

wait( .5 );



if ( distance > 384 )

{

self waitForTurretReady();

self FireWeapon();

self playSound( "bmp_fire" );

self.timeLastFired = getTime();

}

println( "Abandoning due to not hitting intended space" );



// Adjust forward or backward to hit target...

// check angle of target

position = relativeAngle( self.bestTarget );



//if ( position == "rear_side" )

// backup

//if ( position == "front_side" )





self thread explicitAbandonTarget( false, self.bestTarget );

return;

}



self waitForTurretReady();



self FireWeapon();

self playSound( "bmp_fire" );

self.timeLastFired = getTime();

}

}



waitForTurretReady()

{

self endon( "abandonedTarget" );

self endon( "killedTarget" );

self endon( "death" );

self endon( "targetRemoved" );

self endon( "lostLOS" );



timeWaited = getTime() - self.timeLastFired;



if ( timeWaited < 1499 )

wait( 1.5 - timeWaited/1000 );

}



tankGetTargets( badTarget )

{

self endon( "death" );

self endon( "leaving" );

targets = [];



prof_begin( "tankTargets" );



for ( ;; )

{

targets = [];

players = level.players;



if ( isDefined( self.forcedTarget ) )

{

targets = [];

targets[0] = self.ForcedTarget;

self acquireTarget( targets );

self.forcedTarget = undefined;

}



if ( isDefined( level.harrier ) && level.harrier.team != self.team && isAlive( level.harrier ) )

{

if( isVehicleTarget( level.tank ) )

targets[targets.size] = level.tank;

}



if ( isDefined( level.chopper ) && level.chopper.team != self.team && isAlive( level.chopper ) )

{

if( isVehicleTarget( level.chopper ) )

targets[targets.size] = level.chopper;

}



foreach ( potentialTarget in players )

{

if (!isDefined( potentialTarget ) )

{

wait(.05);

continue;

}



if ( isDefined( badTarget ) && potentialTarget == badTarget )

continue;



if ( isTarget( potentialTarget ) )

{

if( isDefined( potentialTarget ) )

targets[targets.size] = potentialTarget;

}

else

continue;

}

if ( targets.size > 0 )

{

self acquireTarget( targets );

}

else

wait( 1 );

}

prof_end( "tankTargets" );

}



acquireTarget( targets )

{

self endon( "death" );



if ( targets.size == 1 )

self.bestTarget = targets[0];

else

self.bestTarget = self getBestTarget( targets );



self thread setEngagementSpeed(); // slows tank down to fire on target



// checks to abandon target

//self thread lostTarget(); // sets lost LOS and time of lost target

//self thread abandonTarget(); // if target is lost for 3+ seconds drops target and gets new one

self thread watchTargetDeath( targets ); //abandons target when target killed





self SetTurretTargetEnt( self.bestTarget ); // sets turret to target entity

self fireOnTarget(); // fires on current target.

self thread setNoTarget();

}



setNoTarget()

{

self endon( "death" );



self setStandardSpeed();

self removeTarget();

self setTurretTargetEnt( self.neutralTarget );

}



getBestTarget( targets )

{

self endon( "death" );

mainGunPointOrigin = self getTagOrigin( "tag_flash" );

tankOrigin = self.origin;



bestYaw = undefined;

bestTarget = undefined;

targetHasRocket = false;



foreach ( targ in targets )

{

angle = abs ( vectorToAngles ( ( targ.origin - self.origin ) )[1] );

cannonAngle = abs( self getTagAngles( "tag_flash" )[1] );

angle = abs ( angle - cannonAngle );



//vehicle priorities

if ( isDefined( level.chopper ) && targ == level.chopper )

return targ;



if ( isDefined( level.harrier ) && targ == level.harrier )

return targ;



// in this calculation having a rocket removes 40d of rotation cost from best target calculation

// to prioritize targeting dangerous targets.

weaponsArray = targ GetWeaponsListItems();

foreach ( weapon in weaponsArray )

{

if ( isSubStr( weapon, "at4" ) || isSubStr( weapon, "jav" ) || isSubStr( weapon, "c4" ) )

angle -= 40;

}



if ( !isDefined( bestYaw ) )

{

bestYaw = angle;

bestTarget = targ;

}

else if ( bestYaw > angle )

{

bestYaw = angle;

bestTarget = targ;

}

}



return ( bestTarget );

}



watchTargetDeath( targets )

{

self endon( "abandonedTarget" );

self endon( "lostLOS" );

self endon( "death" );

self endon( "targetRemoved" );



bestTarg = self.bestTarget;

bestTarg endon ( "disconnect" );



bestTarg waittill( "death" );



self notify( "killedTarget" );

self removeTarget();

self setStandardSpeed();

self thread setNoTarget();

}



explicitAbandonTarget( noNewTarget, targ )

{

self endon( "death" );



self notify( "abandonedTarget" );

println("ABANDON TARGET EXPLICIT");

self setStandardSpeed();

self thread Setnotarget();

self removeTarget();



if ( isDefined(targ) )

{

self.badTarget = targ;

badTargetReset();

}



if ( isDefined(noNewTarget) && noNewTarget )

return;



return;

}



badTargetReset()

{

self endon("death");



wait (1.5);

self.badTarget = undefined;

}



removeTarget()

{

self notify( "targetRemoved" );



self.bestTarget = undefined;

self.lastLostTime = undefined;

}



isVehicleTarget( potentialTarget )

{

if ( distance2D( potentialTarget.origin, self.origin ) > 4096 )

return false;



if ( distance( potentialTarget.origin , self.origin ) < 512 )

return false;



return turretSightTrace( potentialTarget, false );

}



isTarget( potentialTarget )

{

self endon( "death" );



dist = distanceSquared( potentialTarget.origin, self.origin );



if ( !level.teamBased && isDefined( self.owner ) && potentialTarget == self.owner )

return false;



if ( !isalive( potentialTarget ) || potentialTarget.sessionstate != "playing" )

return false;



if ( dist > 4096*4096 )

return false;



if ( dist < 512*512 )

return false;



if ( !isdefined( potentialTarget.pers["team"] ) )

return false;



if ( potentialTarget == self.owner )

return false;



if ( level.teamBased && potentialTarget.pers["team"] == self.team )

return false;



if ( potentialTarget.pers["team"] == "spectator" )

return false;



if ( isdefined( potentialTarget.spawntime ) && ( gettime() - potentialTarget.spawntime )/1000 <= 5 )

return false;



if ( potentialTarget _hasPerk( "specialty_coldblooded" ) )

return false;



return self Vehicle_CanTurretTargetPoint( potentialTarget.origin, 1, self );



//return self turretSightTrace( potentialTarget, false );

}



turretSightTrace( targ, debug )

{

turretCanSeeTarget = targ sightConeTrace( self getTagOrigin( "tag_turret" ), self );



if ( turretCanSeeTarget < .7 )

{

return false;

}



if ( isDefined(debug) && debug )

self thread drawLine( targ.origin, self getTagOrigin( "tag_turret" ), 10, (1,0,0) );



return true;

}



//=================================================================

//

// Secondary Weapon Targeting Functions

//

//=================================================================



isMiniTarget( potentialTarget )

{

self endon( "death" );



if ( !isalive( potentialTarget ) || potentialTarget.sessionstate != "playing" )

return false;



if ( !isdefined( potentialTarget.pers["team"] ) )

return false;



if ( potentialTarget == self.owner )

return false;



if ( distanceSquared( potentialTarget.origin , self.origin ) > 1024*1024 )

return false;



if ( level.teamBased && potentialTarget.pers["team"] == self.team )

return false;



if ( potentialTarget.pers["team"] == "spectator" )

return false;



if ( isdefined( potentialTarget.spawntime ) && ( gettime() - potentialTarget.spawntime )/1000 <= 5 )

return false;





if ( isDefined( self ) )

{

minTurretEye = self.mgTurret.origin + ( 0, 0, 64 );

minTurretCanSeeTarget = potentialTarget sightConeTrace( minTurretEye, self );



if ( minTurretCanSeeTarget < 1 )

return false;

}



return true;

}



tankGetMiniTargets()

{

self endon( "death" );

self endon( "leaving" );

miniTargets = [];

println( "Geting Mini Targets" );



for ( ;; )

{

miniTargets = [];

players = level.players;



for (i = 0; i <= players.size; i++)

{

if ( isMiniTarget( players[i] ) )

{

if( isdefined( players[i] ) )

miniTargets[miniTargets.size] = players[i];

}

else

continue;



wait( .05 );

}

if ( miniTargets.size > 0 )

{

self acquireMiniTarget( miniTargets );

return;

}

else

wait( .5 );

}

}



getBestMiniTarget( targets )

{

self endon( "death" );

tankOrigin = self.origin;



closest = undefined;

bestTarget = undefined;



foreach ( targ in targets )

{

curDist = Distance( self.origin, targ.origin );



// in this calculation having a rocket javelin or c4 increases mini turret priority

// to prioritize targeting dangerous targets.

curWeaon = targ GetCurrentWeapon();

if ( isSubStr( curWeaon, "at4" ) || isSubStr( curWeaon, "jav" ) || isSubStr( curWeaon, "c4" ) || isSubStr( curWeaon, "smart" ) || isSubStr( curWeaon, "grenade" ) )

curDist -= 200;



if ( !isDefined( closest ) )

{

closest = curDist;

bestTarget = targ;

}

else if ( closest > curDist )

{

closest = curDist;

bestTarget = targ;

}

}

return ( bestTarget );

}



acquireMiniTarget( targets )

{

self endon( "death" );



if ( targets.size == 1 )

self.bestMiniTarget = targets[0];

else

self.bestMiniTarget = self getBestMiniTarget( targets );



if ( distance2D( self.origin, self.bestMiniTarget.origin) > 768 )

self thread setMiniEngagementSpeed();



self notify( "acquiringMiniTarget" );

self.mgTurret SetTargetEntity( self.bestMiniTarget, ( 0,0,64 ) ); // sets turret to target entity

wait( .15 );

self thread fireMiniOnTarget(); // fires on current target.

self thread watchMiniTargetDeath( targets ); //abandons target when target killed

self thread watchMiniTargetDistance( targets );

self thread watchMiniTargetThreat( self.bestMiniTarget );

}



fireMiniOnTarget()

{

self endon( "death" );

self endon( "abandonedMiniTarget" );

self endon( "killedMiniTarget" );

noTargTime = undefined;

miniAcquiredTime = getTime();



if ( !isDefined( self.bestMiniTarget ) )

{

println("No Targ to fire on");

return;

}



println("firing on best target");



while( 1 )

{

if ( !isDefined ( self.mgTurret getTurretTarget( true ) ) )

{

if ( !isDefined( noTargTime ) )

noTargTime = getTime();



curTime = getTime();



if ( noTargTime - curTime > 1 )

{

noTargTime = undefined;

self thread explicitAbandonMiniTarget();

return;

}



//println("Waiting because the turret doesnt have a target" );



wait ( .5 );

continue;

}



if ( getTime() > miniAcquiredTime + 1000 && !isDefined( self.bestTarget ) )

{

if ( distance2D(self.origin, self.bestMiniTarget.origin ) > 768 )

{

targets[0] = self.bestMiniTarget;

self acquireTarget( targets );

}

}



numShots = randomIntRange( 10, 16 );

for ( i = 0; i < numShots; i++ )

{

self.mgTurret ShootTurret();

wait ( .1 );

}

wait ( randomFloatRange( 0.5, 3.0 ) );

}

}



watchMiniTargetDeath( targets )

{

self endon( "abandonedMiniTarget" );

self endon( "death" );

if ( ! isDefined( self.bestMiniTarget ) )

return;



self.bestMiniTarget waittill( "death" );



self notify( "killedMiniTarget" );

println( "Killed Mini Target" );



self.bestMiniTarget = undefined;

self.mgTurret ClearTargetEntity();

self tankGetMiniTargets();

}



watchMiniTargetDistance( targets )

{

self endon( "abandonedMiniTarget" );

self endon( "death" );



for ( ;; )

{

if (! isDefined( self.bestMiniTarget ) )

return;



trace = BulletTrace( self.mgTurret.origin, self.bestMiniTarget.origin, false, self );

traceDistance = Distance(self.origin, trace["position"] );



if ( traceDistance > 1024 )

{

println( "MINI TARGET DIST TOO FAR!!!" );

self thread explicitAbandonMiniTarget();

return;

}

println( traceDistance );

wait ( 2 );

}

}



watchMiniTargetThreat( curTarget )

{

self endon( "abandonedMiniTarget" );

self endon( "death" );

self endon( "killedMiniTarget" );



for ( ;; )

{

miniTargets = [];

players = level.players;



for (i = 0; i <= players.size; i++)

{

if ( isMiniTarget( players[i] ) )

{

if( !isdefined( players[i] ) )

continue;



if( !isdefined(curTarget) )

return;



traceOldTarg = Distance(self.origin, CurTarget.origin );

traceNewTarg = Distance(self.origin, players[i].origin );



if ( traceNewTarg < traceOldTarg )

{

self thread explicitAbandonMiniTarget();

return;

}

}



wait( .05 );

}



wait( .25 );

}

}



explicitAbandonMiniTarget( noNewTarget )

{



self notify( "abandonedMiniTarget" );



println( "ABANDONED MINI TARGET" );



self.bestMiniTarget = undefined;

self.mgTurret ClearTargetEntity();



if ( isDefined(noNewTarget) && noNewTarget )

return;



self thread tankGetMiniTargets();

return;

}





addToTankList()

{

level.tanks[self getEntityNumber()] = self;

}



removeFromTankList()

{

level.tanks[self getEntityNumber()] = undefined;

}





/*************************************************************************

*

* PATHFINDING AND PATH NODE FUNCTIONS

*

***************************************************************************/



getNodeNearEnemies()

{

validEnemies = [];



foreach ( player in level.players )

{

if ( player.team == "spectator" )

continue;



if ( player.team == self.team )

continue;



if ( !isAlive( player ) )

continue;



player.dist = 0;

validEnemies[validEnemies.size] = player;

}



if ( !validEnemies.size )

return undefined;



for ( i = 0; i < validEnemies.size; i++ )

{

for ( j = i + 1; j < validEnemies.size; j++ )

{

dist = distanceSquared( validEnemies[i].origin, validEnemies[j].origin );



validEnemies[i].dist += dist;

validEnemies[j].dist += dist;

}

}



bestPlayer = validEnemies[0];

foreach ( player in validEnemies )

{

if ( player.dist < bestPlayer.dist )

bestPlayer = player;

}



bestOrigin = bestPlayer.origin;



sortedNodes = sortByDistance( level.graphNodes, bestOrigin );



//thread drawLine( bestOrigin, sortedNodes[0].origin, 10.0, (1,0,1) );



return ( sortedNodes[0] );

}





setupPaths()

{

tankNodes = [];

startNodes = [];

endNodes = [];

aStarGraphNodes = [];



// setup the start node

tankNode = GetVehicleNode( "startnode", "targetname" );

tankNodes[tankNodes.size] = tankNode;

startNodes[startNodes.size] = tankNode;



while ( isDefined( tankNode.target ) )

{

lastNode = tankNode;

tankNode = GetVehicleNode( tankNode.target, "targetname" );

tankNode.prev = lastNode;



// case for connected path

if ( tankNode == tankNodes[0] )

break;



tankNodes[tankNodes.size] = tankNode;



// case for disconnected path

if ( !isDefined( tankNode.target ) )

return;

}



tankNodes[0].branchNodes = [];

tankNodes[0] thread handleBranchNode( "forward" );

aStarGraphNodes[aStarGraphNodes.size] = tankNodes[0];



// find the start and end nodes of the branches

branchNodes = GetVehicleNodeArray( "branchnode", "targetname" );

foreach ( branchNode in branchNodes )

{

tankNode = branchNode;

tankNodes[tankNodes.size] = tankNode;

startNodes[startNodes.size] = tankNode;



while ( isDefined( tankNode.target ) )

{

lastNode = tankNode;

tankNode = GetVehicleNode( tankNode.target, "targetname" );

tankNodes[tankNodes.size] = tankNode;

tankNode.prev = lastNode;



if ( !isDefined( tankNode.target ) )

endNodes[endNodes.size] = tankNode;

}

}



// detect and initialize the branch nodes. These will be used for the aStar node graph

foreach ( tankNode in tankNodes )

{

isBranchNode = false;

foreach ( startNode in startNodes )

{

if ( startNode == tankNode )

continue;



if ( startNode.target == tankNode.targetname )

continue;



if ( isDefined( tankNode.target ) && tankNode.target == startNode.targetname )

continue;



if ( distance2d( tankNode.origin, startNode.origin ) > 80 )

continue;



startNode thread handleCapNode( tankNode, "reverse" );

startNode.prev = tankNode;



if ( !isDefined( tankNode.branchNodes ) )

tankNode.branchNodes = [];



tankNode.branchNodes[tankNode.branchNodes.size] = startNode;



isBranchNode = true;

}



if ( isBranchNode )

tankNode thread handleBranchNode( "forward" );



isJoinNode = false;

foreach ( endNode in endNodes)

{

if ( endNode == tankNode )

continue;



if ( !isDefined( tankNode.target ) )

continue;



if ( tankNode.target == endNode.targetname )

continue;



if ( isDefined( endNode.target ) && endNode.target == tankNode.targetname )

continue;



if ( distance2d( tankNode.origin, endNode.origin ) > 80 )

continue;



endNode thread handleCapNode( tankNode, "forward" );

endNode.next = getVehicleNode( tankNode.targetname, "targetname" );

//endNode.target = tankNode.targetname; // READ-ONLY field...

endNode.length = distance( endNode.origin, tankNode.origin );



if ( !isDefined( tankNode.branchNodes ) )

tankNode.branchNodes = [];



tankNode.branchNodes[tankNode.branchNodes.size] = endNode;



isJoinNode = true;

}



if ( isJoinNode )

{

assert( !isBranchNode );

tankNode thread handleBranchNode( "reverse" );

}



if ( isJoinNode || isBranchNode )

aStarGraphNodes[aStarGraphNodes.size] = tankNode;

}



if ( aStarGraphNodes.size < 3 )

{

level notify ( "end_tankPathHandling" );

return;

}



// subdivide the path a bit...

segmentNodes = [];

foreach( tankNode in tankNodes )

{

if ( !isDefined( tankNode.branchNodes ) )

continue;



segmentNodes[segmentNodes.size] = tankNode;

}



foreach ( segmentNode in segmentNodes )

{

tankNode = segmentNode;

pathLength = 0;



while ( isDefined( tankNode.target ) )

{

prevNode = tankNode;

tankNode = GetVehicleNode( tankNode.target, "targetname" );

pathLength += distance( tankNode.origin, prevNode.origin );



if ( tankNode == segmentNode )

break;



if ( isDefined( tankNode.branchNodes ) )

break;

}



if ( pathLength > 1000 )

{

tankNode = segmentNode;

curLength = 0;



while ( isDefined( tankNode.target ) )

{

prevNode = tankNode;

tankNode = GetVehicleNode( tankNode.target, "targetname" );



curLength += distance( tankNode.origin, prevNode.origin );

if ( curLength < pathLength / 2 )

continue;



tankNode.branchNodes = []; // necessary?

tankNode thread handleBranchNode( "forward" );

aStarGraphNodes[aStarGraphNodes.size] = tankNode;

break;

}

}

}



level.graphNodes = initNodeGraph( aStarGraphNodes );



foreach ( tankNode in tankNodes )

{

if ( !isDefined( tankNode.graphId ) )

tankNode thread nodeTracker();

}

}







getRandomBranchNode( direction )

{

branchNodes = [];

foreach ( graphId, linkNode in self.links )

{

// pick a branch in the direction we're already heading

if ( self.linkDirs[graphId] != direction )

continue;



branchNodes[branchNodes.size] = linkNode;

}



return ( branchNodes[randomInt( branchNodes.size )] );

}





getNextNodeForEndNode( endNode, direction )

{

graphNode = level.graphNodes[self.graphId];



continuePath = generatePath( graphNode, endNode, undefined, direction );

continueG = continuePath[0].g;



changePath = generatePath( graphNode, endNode, undefined, level.otherDir[direction] );

changeG = changePath[0].g;



// temporarily force the tank to only go forward

if ( !getDvarInt( "tankDebug" ) )

changeG = 9999999;



if ( continueG <= changeG )

return ( continuePath[1] );

}





handleBranchNode( direction )

{

level endon ( "end_tankPathHandling" );

for ( ;; )

{

self waittill( "trigger", tank, wasForced );



graphNode = level.graphNodes[self.graphId];



tank.node = self;



nextGraphNode = undefined;

if ( isDefined( tank.endNode ) && tank.endNode != graphNode )

{

nextGraphNode = getNextNodeForEndNode( tank.endNode, tank.veh_pathdir );



if ( !isDefined( nextGraphNode ) )

tank thread setDirection( level.otherDir[tank.veh_pathdir] );

}



if ( !isDefined( nextGraphNode ) || nextGraphNode == graphNode )

{

nextGraphNode = graphNode getRandomBranchNode( tank.veh_pathdir );

}



goalNode = graphNode.linkStartNodes[nextGraphNode.graphId];



if ( tank.veh_pathdir == "forward" )

nextLinkNode = self getNextNode();

else

nextLinkNode = self getPrevNode();



// if we're already on this path, just keep going

if ( nextLinkNode != goalNode )

tank startPath( goalNode );

}

}





handleCapNode( joinNode, direction )

{

for ( ;; )

{

self waittill( "trigger", tank );



if ( tank.veh_pathdir != direction )

continue;



debugPrintLn2( "tank starting path at join node: " + joinNode.graphId );



tank startPath( joinNode );

}

}





nodeTracker()

{

self.forwardGraphId = getForwardGraphNode().graphId;

self.reverseGraphId = getReverseGraphNode().graphId;



for ( ;; )

{

self waittill ( "trigger", tank, wasForced );



tank.node = self;



/#

if ( getDvarInt( "tankForceTrigger" ) )

{

if ( tank.veh_pathdir == "forward" )

tank thread forceTrigger( self, self getNextNode(), tank );

else

tank thread forceTrigger( self, self getPrevNode(), tank );

}

#/



tank.forwardGraphId = self.forwardGraphId;

tank.reverseGraphId = self.reverseGraphId;



if ( !isDefined( self.target ) || self.targetname == "branchnode" )

nodeType = "TRANS";

else

nodeType = "NODE";



if ( isDefined( wasForced ) )

debugPrint3D( self.origin, nodeType, (1,0.5,0), 1, 2, 100 );

else

debugPrint3D( self.origin, nodeType, (0,1,0), 1, 2, 100 );

}

}





forceTrigger( prevNode, nextNode, tank )

{

nextNode endon ( "trigger" );

prevNode endon ( "trigger" );

tank endon ( "death" );



minDist = distanceSquared( tank.origin, nextNode.origin );

tankDir = tank.veh_pathdir;



debugPrint3D( prevNode.origin+(0,0,30), "LAST", (0,0,1), 0.5, 1, 100 );

debugPrint3D( nextNode.origin+(0,0,60), "NEXT", (0,1,0), 0.5, 1, 100 );



timeOutNextFrame = false;

for ( ;; )

{

wait ( 0.05 );



// tank changed direction

if ( tankDir != tank.veh_pathdir )

{

debugPrintLn2( "tank missed node: reversing direction" );

tank thread forceTrigger( nextNode, prevNode, tank );

return;

}



if ( timeOutNextFrame )

{

debugPrintLn2( "... sending notify." );

nextNode notify ( "trigger", tank, true );

return;

}



curDist = distanceSquared( tank.origin, nextNode.origin );



if ( curDist > minDist )

{

timeOutNextFrame = true;

debugPrintLn2( "tank missed node: forcing notify in one frame..." );

}



minDist = curDist;

}

}





getForwardGraphNode()

{

assert( !isDefined( self.graphId ) );



checkNode = self;

while ( !isDefined( checkNode.graphId ) )

checkNode = checkNode getNextNode();



return checkNode;

}





getReverseGraphNode()

{

assert( !isDefined( self.graphId ) );



checkNode = self;

while ( !isDefined( checkNode.graphId ) )

checkNode = checkNode getPrevNode();



return checkNode;

}





getNextNode()

{

if ( isDefined( self.target ) )

return ( GetVehicleNode( self.target, "targetname" ) );

else

return ( self.next );

}





getPrevNode()

{

return self.prev;

}







// Builds the aStar node graph

initNodeGraph( astarBaseNodes )

{

graphNodes = [];

foreach ( pathNode in aStarBaseNodes )

{

graphNode = spawnStruct();

graphNode.linkInfos = [];

graphNode.links = [];

graphNode.linkLengths = [];

graphNode.linkDirs = [];

graphNode.linkStartNodes = [];

graphNode.node = pathNode;

graphNode.origin = pathNode.origin;

graphNode.graphId = graphNodes.size;

pathNode.graphId = graphNodes.size;



debugPrint3D( graphNode.origin + (0,0,80), graphNode.graphId, (1,1,1), 0.65, 2, 100000 );



graphNodes[graphNodes.size] = graphNode;

}



foreach ( pathNode in aStarBaseNodes )

{

graphId = pathNode.graphId;



checkNode = GetVehicleNode( pathNode.target, "targetname" );

linkLength = distance( pathNode.origin, checkNode.origin );

linkStartNode = checkNode;



while ( !isDefined( checkNode.graphId ) )

{

linkLength += distance( checkNode.origin, checkNode.prev.origin );



if ( isDefined( checkNode.target ) )

checkNode = GetVehicleNode( checkNode.target, "targetname" );

else

checkNode = checkNode.next;

}



assert( checkNode != pathNode );

graphNodes[graphId] addLinkNode( graphNodes[checkNode.graphId], linkLength, "forward", linkStartNode );



checkNode = pathNode.prev;

linkLength = distance( pathNode.origin, checkNode.origin );

linkStartNode = checkNode;



while ( !isDefined( checkNode.graphId ) )

{

linkLength += distance( checkNode.origin, checkNode.prev.origin );

checkNode = checkNode.prev;

}



assert( checkNode != pathNode );

graphNodes[graphId] addLinkNode( graphNodes[checkNode.graphId], linkLength, "reverse", linkStartNode );



foreach ( branchNode in pathNode.branchNodes )

{

checkNode = branchNode;

linkLength = distance( pathNode.origin, checkNode.origin );

linkStartNode = checkNode;



if ( checkNode.targetname == "branchnode" )

{

while ( !isDefined( checkNode.graphId ) )

{

if ( isDefined( checkNode.target ) )

nextNode = GetVehicleNode( checkNode.target, "targetname" );

else

nextNode = checkNode.next;



linkLength += distance( checkNode.origin, nextNode.origin );

checkNode = nextNode;

}



assert( checkNode != pathNode );

graphNodes[graphId] addLinkNode( graphNodes[checkNode.graphId], linkLength, "forward", linkStartNode );

}

else

{

while ( !isDefined( checkNode.graphId ) )

{

linkLength += distance( checkNode.origin, checkNode.prev.origin );

checkNode = checkNode.prev;

}



assert( checkNode != pathNode );

graphNodes[graphId] addLinkNode( graphNodes[checkNode.graphId], linkLength, "reverse", linkStartNode );

}

}

}



return graphNodes;

}





addLinkNode( graphNode, linkLength, linkDir, linkStartNode )

{

assert( self.graphId != graphNode.graphId );

assert( !isDefined( self.links[graphNode.graphId] ) );



self.links[graphNode.graphId] = graphNode;

self.linkLengths[graphNode.graphId] = linkLength;

self.linkDirs[graphNode.graphId] = linkDir;

self.linkStartNodes[graphNode.graphId] = linkStartNode;



linkInfo = spawnStruct();

linkInfo.toGraphNode = graphNode;

linkInfo.toGraphId = graphNode.graphId;

linkInfo.length = linkLength;

linkInfo.direction = linkDir;

linkInfo.startNode = linkStartNode;



self.linkInfos[graphNode.graphId] = linkInfo;

}





// call function as generatePath(startNode, destNode), otherwise paths will be reversed

generatePath( destNode, startNode, blockedNodes, direction )

{

level.openList = [];

level.closedList = [];

foundPath = false;

pathNodes = [];



if ( !isDefined( blockedNodes ) )

blockedNodes = [];



startNode.g = 0;

startNode.h = getHValue( startNode, destNode );

startNode.f = startNode.g + startNode.h;



addToClosedList( startNode );



curNode = startNode;

for ( ;; )

{

foreach ( linkId, checkNode in curNode.links )

{

if ( is_in_array( blockedNodes, checkNode ) )

continue;



if ( is_in_array( level.closedList, checkNode ) )

continue;



if ( isDefined( direction ) && checkNode.linkDirs[curNode.graphId] != direction )

continue;



if ( !is_in_array( level.openList, checkNode ) )

{

addToOpenList( checkNode );



checkNode.parentNode = curNode;

checkNode.g = getGValue( checkNode, curNode );

checkNode.h = getHValue( checkNode, destNode );

checkNode.f = checkNode.g + checkNode.h;



if ( checkNode == destNode )

foundPath = true;

}

else

{

if ( checkNode.g < getGValue( curNode, checkNode ) )

continue;



checkNode.parentNode = curNode;

checkNode.g = getGValue( checkNode, curNode );

checkNode.f = checkNode.g + checkNode.h;

}

}



if ( foundPath )

break;



addToClosedList( curNode );



bestNode = level.openList[0];



foreach ( testNode in level.openList )

{

if ( testNode.f > bestNode.f )

continue;



bestNode = testNode;

}



assert( isDefined( bestNode ) ); // the tank should always have a path



addToClosedList( bestNode );

curNode = bestNode;

}



assert( isDefined( destNode.parentNode ) );



curNode = destNode;

while (curNode != startNode)

{

pathNodes[pathNodes.size] = curNode;

curNode = curNode.parentNode;

}

pathNodes[pathNodes.size] = curNode;



return pathNodes;

}





addToOpenList( node )

{

node.openListID = level.openList.size;

level.openList[level.openList.size] = node;

node.closedListID = undefined;

}





addToClosedList( node )

{

if (isdefined (node.closedListID))

return;



node.closedListID = level.closedList.size;

level.closedList[level.closedList.size] = node;



if (!is_in_array (level.openList, node))

return;



level.openList[node.openListID] = level.openList[level.openList.size - 1];

level.openList[node.openListID].openListID = node.openListID;

level.openList[level.openList.size - 1] = undefined;

node.openListID = undefined;

}





getHValue (node1, node2)

{

return (distance (node1.node.origin, node2.node.origin));

}





getGValue(node1, node2)

{

return ( node1.parentNode.g + node1.linkLengths[node2.graphId] );

}





is_in_array( aeCollection, eFindee )

{

for ( i = 0; i < aeCollection.size; i++ )

{

if ( aeCollection[ i ] == eFindee )

return( true );

}



return( false );

}





drawPath( pathNodes )

{

for ( i = 1; i < pathNodes.size; i++ )

{

startNode = pathNodes[i-1];

endNode = pathNodes[i];



if ( startNode.linkDirs[endNode.graphId] == "reverse" )

level thread drawLink( startNode.node.origin, endNode.node.origin, (1,0,0) );

else

level thread drawLink( startNode.node.origin, endNode.node.origin, (0,1,0) );



vehNode = startNode.linkStartNodes[endNode.graphId];

level thread drawLink( startNode.node.origin + (0,0,4), vehNode.origin + (0,0,4), (0,0,1) );



if ( startNode.linkDirs[endNode.graphId] == "reverse" )

{

while ( !isDefined( vehNode.graphId ) )

{

lastVehNode = vehNode;

vehNode = vehNode.prev;

level thread drawLink( lastVehNode.origin + (0,0,4), vehNode.origin + (0,0,4), (0,1,1) );

}

}

else

{

while ( !isDefined( vehNode.graphId ) )

{

lastVehNode = vehNode;



if ( isDefined( vehNode.target ) )

vehNode = GetVehicleNode( vehNode.target, "targetname" );

else

vehNode = vehNode.next;



level thread drawLink( lastVehNode.origin + (0,0,4), vehNode.origin + (0,0,4), (0,1,1) );

}

}

}

}





drawGraph( pathNodes )

{

/*

level.pathZOffset = 0;

foreach ( node in pathNodes )

{

println( node.links.size );

foreach ( linkId, graphNode in node.links )

{

if ( node.linkDirs[linkId] == "reverse" )

level thread drawLink( node.node.origin, graphNode.node.origin, (0,1,0) );

else

level thread drawLink( node.node.origin, graphNode.node.origin, (1,0,0) );



//if ( node.linkDirs[linkId] == "reverse" )

// continue;



//level thread drawLink( pathNodes[graphId].node.origin, pathNodes[node.graphId].node.origin, (randomFloat( 2 ), randomFloat( 2 ), randomFloat( 2 )) );

}

}

*/

}





drawLink( start, end, color )

{

level endon ( "endpath" );

for ( ;; )

{

line(start, end, color, true);

wait 0.05;

}

}



debugPrintLn2( printString )

{

/#

if ( getDvarInt( "tankDebug" ) )

printLn( printString );

#/

}



debugPrint( printString )

{

/#

if ( getDvarInt( "tankDebug" ) )

print( printString );

#/

}





debugPrint3D( origin, printString, color, alpha, scale, duration )

{

/#

if ( getDvarInt( "tankDebug" ) )

{

print3d( origin, printString, color, alpha, scale, duration );

println( "3Sad Awesome " + printString );

}

#/

}





drawTankGraphIds()

{

/#

if ( getDvarInt( "tankDebug" ) )

{

self notify ( "drawTankGraphIds" );

self endon ( "drawTankGraphIds" );



for ( ;; )

{

print3d( self.origin + (0,0,12Cool Man (aka Tustin), "FW: " + self.forwardGraphId + " RV: " + self.reverseGraphId, (0,1,0), 1, 3, 1 );

wait ( 0.05 );

}

}

#/

}


01-15-2010, 11:18 PM #4
rjive
Love Big Titty Bitches
was this code from the PC game?
01-15-2010, 11:20 PM #5
EJ94c
Poke Smot
how would you call it in? one of those HUGE cargo planes drop it in at low altitudes?
01-15-2010, 11:20 PM #6
mattk3650
Climbing up the ladder
They should have Tanks and Dogs be unlockable 10 kill streaks thats probably why there's a huge gap in the 30's and 40's. They could fill them in with the next patch.

I also think that missile strike should have been a 7 killstreak, like a really big precision airstrike.
A little bird helicopter a 6 killstreak that flies extremely high with a sniper.
At 15 you should get a team of highly trained campers that wait at every choke point and are very hard to spot/kill. IDK if I'm joking or not but lol anyway
01-15-2010, 11:21 PM #7
im just guessing but it looks like it's from ps3 as he has the ps3 icon thing
01-16-2010, 12:40 AM #8
juddylovespizza
I'VE GOT JUNGLE FEVER
Any dogs in there too?
01-16-2010, 12:42 AM #9
Se7en x BeasTz
Pokemon Trainer
A tank? That would make people get even more upset.
01-16-2010, 09:30 AM #10
Originally posted by rjive View Post
was this code from the PC game?


This is for all platforms.

Originally posted by h0M3bReW3r View Post
Any dogs in there too?
No, tanks are the only kill streak they didn't use.

Copyright © 2026, NextGenUpdate.
All Rights Reserved.

Gray NextGenUpdate Logo