Advertisement
Guest User

Hidden Tank Killstreak - aIW|Insignia

a guest
Jun 30th, 2010
469
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 50.66 KB | None | 0 0
  1. #include maps\mp\_utility;
  2. #include common_scripts\utility;
  3. //#include _vehicleLogic.gsc;
  4.  
  5. init()
  6. {
  7.     //tank support cut
  8.     return;
  9.     //tank support cut
  10.     /*
  11.     PrecacheVehicle( "bmp_mp" );
  12.     PrecacheVehicle( "m1a1_mp" );
  13.     PrecacheVehicle( "bradley_mp" );
  14.  
  15.     precacheModel("vehicle_bmp");
  16.     precacheModel("vehicle_bradley");
  17.  
  18.     precacheModel("sentry_gun");
  19.     precacheModel("vehicle_m1a1_abrams_d_static");
  20.     precacheTurret( "abrams_minigun_mp" );
  21.    
  22.     /#
  23.     setDevDvar( "tankDir", "" );
  24.     setDevDvar( "tankForceTrigger", 0 );
  25.     if ( getDvar( "tankDebug" ) == "" )
  26.         setDevDvar( "tankDebug", 0 );
  27.     #/
  28.    
  29.     level.killstreakFuncs["tank"] = ::useTank;
  30.     level.tankFire = loadfx( "explosions/large_vehicle_explosion" );
  31.     level.tankCover = loadfx( "props/american_smoke_grenade_mp" );
  32.  
  33.     level.otherDir["forward"] = "reverse";
  34.     level.otherDir["reverse"] = "forward";
  35.  
  36.     tankSpawners = Vehicle_GetSpawnerArray();
  37.    
  38.     if ( !tankSpawners.size )
  39.         return;
  40.    
  41.     if (!isDefined( getVehicleNode( "startnode", "targetname" ) ) )
  42.     {
  43.         assertEx ( !isDefined( getVehicleNode( "startnode", "targetname" ) ), "Vehicle spawn is setup but tank path is not setup in this level bug your friendly neighborhood LD."  );
  44.         return false;
  45.     }
  46.  
  47.     level.tankSpawner["allies"] = tankSpawners[0];
  48.     level.tankSpawner["axis"] = tankSpawners[0];
  49.     level.pathCount = 0;
  50.    
  51.     foreach ( spawner in tankSpawners )
  52.     {
  53.         if ( isSubStr( spawner.model, "bradley" ) )
  54.             level.tankSpawner["allies"] = spawner;
  55.        
  56.         if ( isSubStr( spawner.model, "bmp" ) )
  57.             level.tankSpawner["axis"] = spawner;
  58.     }
  59.    
  60.     level setupPaths();
  61.    
  62.     */
  63. }
  64.  
  65.  
  66. spawnArmor( owner, vehicletype, model )
  67. {
  68.     armor = self Vehicle_DoSpawn( "tank", owner );
  69.     //armor setModel( model );
  70.    
  71.     armor.health = 3000;
  72.     armor.targeting_delay = 1;
  73.     armor.team = owner.team;
  74.     armor.pers["team"] = armor.team;
  75.     armor.owner = owner;
  76.     armor setCanDamage( true );
  77.     armor.standardSpeed = 12;
  78.  
  79.     armor thread deleteOnZ();
  80.     armor addToTankList();
  81.     armor.damageCallback = ::Callback_VehicleDamage;
  82.    
  83.     return armor;
  84. }
  85.  
  86. deleteOnZ()
  87. {
  88.     self endon ( "death" );
  89.    
  90.     originalZ = self.origin[2];
  91.    
  92.     for ( ;; )
  93.     {
  94.         if ( originalZ - self.origin[2] > 2048 )
  95.         {
  96.             self.health = 0;
  97.             self notify( "death" );
  98.             return;
  99.         }
  100.         wait ( 1.0 );
  101.     }
  102. }
  103.  
  104.  
  105. useTank( lifeId )
  106. {
  107.     return ( self tryUseTank( ) );
  108. }
  109.  
  110. tryUseTank( )
  111. {
  112.     if ( isDefined( level.tankInUse ) && level.tankInUse )
  113.     {
  114.         self iPrintLnBold( "Armor support unavailable." );
  115.         return false;
  116.     }
  117.        
  118.     if (!isDefined( getVehicleNode( "startnode", "targetname" ) ) )
  119.     {
  120.         self iPrintLnBold( "Tank is currently not supported in this level, bug your friendly neighborhood LD." );
  121.         return false;
  122.     }
  123.  
  124.     if ( !Vehicle_GetSpawnerArray().size )
  125.         return false;
  126.    
  127.     if ( self.team == "allies" )
  128.         tank = level.tankSpawner["allies"] spawnArmor( self, "vehicle_bradley" );  
  129.     else
  130.         tank = level.tankSpawner["axis"] spawnArmor( self, "vehicle_bmp" );
  131.    
  132.     //level.tank = tank;
  133.     tank startTank();
  134.     return true;
  135. }
  136.  
  137.  
  138. startTank( tankType )
  139. {
  140.     startNode = getVehicleNode( "startnode", "targetname" );
  141.     waitNode = getVehicleNode( "waitnode", "targetname" );
  142.     self.nodes = GetVehicleNodeArray( "info_vehicle_node", "classname" );
  143.    
  144.     level.tankInUse = true;
  145.     self thread tankUpdate( startNode, waitNode );
  146.     //self thread tankUpdateReverse( startNode, waitNode );
  147.    
  148.     self thread tankDamageMonitor();
  149.     level.tank = self;
  150.  
  151.  
  152.     if ( level.teamBased )
  153.     {
  154.         objIDAllies = maps\mp\gametypes\_gameobjects::getNextObjID();
  155.         objective_add( objIDAllies, "invisible", (0,0,0) );
  156.         objective_team( objIDAllies, "allies" );
  157.         level.tank.objID["allies"] = objIDAllies;
  158.    
  159.         objIDAxis = maps\mp\gametypes\_gameobjects::getNextObjID();
  160.         objective_add( objIDAxis, "invisible", (0,0,0) );
  161.         objective_team( objIDAxis, "axis" );
  162.         level.tank.objID["axis"] = objIDAxis;
  163.        
  164.         team = self.team;
  165.         level.tank.team = team;
  166.         level.tank.pers[ "team" ] = team;
  167.     }
  168.    
  169.     mgTurret = spawnTurret( "misc_turret", self.origin, "abrams_minigun_mp" );
  170.     mgTurret linkTo( self, "tag_engine_left", (0,0,-20), (0,0,0) );
  171.     mgTurret setModel( "sentry_minigun" );
  172.     mgTurret.angles = self.angles;
  173.     mgTurret.owner = self.owner;
  174.     mgTurret makeTurretInoperable();
  175.     self.mgTurret = mgTurret;
  176.     self.mgTurret SetDefaultDropPitch( 0 );
  177.    
  178.     oldangles = self.angles;
  179.     self.angles = (0,0,0);
  180.     tankTurretPoint = self getTagOrigin( "tag_flash" );
  181.     self.angles = oldangles;
  182.     offset = tankTurretPoint - self.origin;
  183.    
  184.     self thread waitForChangeTeams();
  185.     self thread waitForDisco();
  186.    
  187.     self.timeLastFired = getTime();
  188.    
  189.     neutralTargetEnt = spawn("script_origin", self getTagOrigin("tag_flash") );
  190.     neutralTargetEnt linkTo( self, "tag_origin", offset, (0,0,0) );
  191.     neutralTargetEnt hide();
  192.     self.neutralTarget = neutralTargetEnt;
  193.    
  194.     self thread tankGetTargets();
  195.     self thread destroyTank();
  196.     self thread tankGetMiniTargets();
  197.     self thread checkDanger();
  198.     self thread watchForThreat(); //reacts to players about to fire with rockets
  199.    
  200.     /#
  201.     self thread forceDirection();
  202.     #/
  203.    
  204. }
  205.  
  206. waitForChangeTeams()
  207. {
  208.     self endon ( "death" );
  209.     self.owner endon ( "disconnect" );
  210.    
  211.     self.owner waittill ( "joined_team" );
  212.     self.health = 0;
  213.     self notify( "death" );
  214. }
  215.  
  216. waitForDisco()
  217. {
  218.     self endon ( "death" );
  219.    
  220.     self.owner waittill ( "disconnect" );
  221.     self.health = 0;
  222.     self notify( "death" );
  223. }
  224.  
  225. /#
  226. forceDirection()
  227. {
  228.     for ( ;; )
  229.     {
  230.         if ( getDvar( "tankDir" ) != "" )
  231.         {
  232.             forceDir = getDvar( "tankDir" );
  233.             if ( self.veh_pathdir != forceDir )
  234.             {
  235.                 if ( forceDir == "forward" )
  236.                     self stopToForward();
  237.                 else
  238.                     self stopToReverse();
  239.             }
  240.         }
  241.        
  242.         wait ( 0.05 );
  243.     }
  244. }
  245. #/
  246.  
  247. //=================================================================
  248. //
  249. //                  Movement/Update Functions
  250. //
  251. //=================================================================
  252.  
  253. setDirection( direction )
  254. {
  255.     if ( self.veh_pathdir != direction )
  256.     {
  257.         if ( direction == "forward" )
  258.             self stopToForward();
  259.         else
  260.             self stopToReverse();
  261.     }
  262. }
  263.  
  264. setEngagementSpeed()
  265. {
  266.     self endon( "death" );
  267.  
  268.     self notify ( "path_abandoned" );
  269.  
  270.     while ( isDefined( self.changingDirection ) )
  271.         wait ( 0.05 );
  272.  
  273.     newSpeed = 2;
  274.     self vehicle_SetSpeed( newSpeed, 10, 10 );
  275.     self.speedType = "engage";
  276. }
  277.  
  278. setMiniEngagementSpeed()
  279. {
  280.     self endon( "death" );
  281.  
  282.     self notify ( "path_abandoned" );
  283.  
  284.     while ( isDefined( self.changingDirection ) )
  285.         wait ( 0.05 );
  286.  
  287.     newSpeed = 2;
  288.     self vehicle_SetSpeed( newSpeed, 10, 10 );
  289.     self.speedType = "engage";
  290. }
  291.  
  292. setStandardSpeed()
  293. {
  294.     self endon( "death" );
  295.  
  296.     while ( isDefined( self.changingDirection ) )
  297.         wait ( 0.05 );
  298.  
  299.     self vehicle_SetSpeed( self.standardSpeed, 10, 10 );
  300.     self.speedType = "standard";
  301. }
  302.  
  303. setEvadeSpeed()
  304. {
  305.     self endon( "death" );
  306.  
  307.     while ( isDefined( self.changingDirection ) )
  308.         wait ( 0.05 );
  309.  
  310.     self vehicle_setSpeed( 15, 15, 15 );
  311.     self.speedType = "evade";
  312.     wait(1.5);
  313.     self vehicle_setSpeed( self.standardSpeed, 10, 10);
  314. }
  315.  
  316. setDangerSpeed()
  317. {
  318.     self endon( "death" );
  319.  
  320.     while ( isDefined( self.changingDirection ) )
  321.         wait ( 0.05 );
  322.  
  323.     self vehicle_SetSpeed( 5, 5, 5 );
  324.     self.speedType = "danger";
  325. }
  326.  
  327. stopToReverse()
  328. {
  329.     debugPrintLn2( "tank changing direction at " + getTime() );
  330.     self vehicle_setSpeed( 0, 5, 6 );
  331.    
  332.     self.changingDirection = true;
  333.     while ( self.veh_speed > 0 )
  334.         wait ( 0.05 );
  335.  
  336.     wait( 0.25 );
  337.     self.changingDirection = undefined;
  338.     debugPrintLn2( "tank done changing direction" );
  339.  
  340.     self.veh_transmission = "reverse";
  341.     self.veh_pathDir = "reverse";
  342.     self vehicle_setSpeed( self.standardSpeed, 5, 6 );
  343. }
  344.  
  345. stopToForward()
  346. {
  347.     debugPrintLn2( "tank changing direction at " + getTime() );
  348.     self vehicle_setSpeed( 0, 5, 6 );
  349.  
  350.     self.changingDirection = true;
  351.     while ( self.veh_speed > 0 )
  352.         wait ( 0.05 );
  353.  
  354.     wait( 0.25 );
  355.     self.changingDirection = undefined;
  356.     debugPrintLn2( "tank done changing direction" );
  357.  
  358.     self.veh_transmission = "forward";
  359.     self.veh_pathDir = "forward";
  360.     self vehicle_setSpeed( self.standardSpeed, 5, 6 );
  361. }
  362.  
  363. checkDanger()
  364. {
  365.     self endon( "death" );
  366.    
  367.     targets = [];
  368.     players = level.players;
  369.     self.numEnemiesClose = 0;
  370.    
  371.     for( ;; )
  372.     {
  373.         foreach (potentialTarget in players)
  374.         {
  375.             if ( !isDefined( potentialTarget ) )
  376.                 continue;
  377.            
  378.             if ( potentialTarget.team == self.team )
  379.             {
  380.                 wait( .05 );
  381.                 continue;
  382.             }
  383.            
  384.             dist = Distance2d( potentialTarget.origin, self.origin );
  385.            
  386.             if ( dist < 2048 )
  387.             {
  388.                 self.numEnemiesClose++;
  389.             }
  390.             wait( .05 );
  391.         }
  392.        
  393.         if ( isDefined( self.speedType ) && ( self.speedType == "evade" || self.speedType == "engage" ) )
  394.         {
  395.             self.numEnemiesClose = 0;
  396.             continue;
  397.         }
  398.        
  399.         if ( self.numEnemiesClose > 1 )
  400.             self thread setDangerSpeed();
  401.         else
  402.             self thread setStandardSpeed();
  403.        
  404.         self.numEnemiesClose = 0;
  405.         wait( .05 );
  406.     }
  407. }
  408.            
  409. tankUpdate( startNode, waitNode )
  410. {
  411.     self endon( "tankDestroyed" );
  412.     self endon( "death" );
  413.    
  414.     if ( !isDefined( level.graphNodes ) )
  415.     {
  416.         self startPath( startNode );
  417.         return;
  418.     }
  419.    
  420.     self attachPath( startNode );
  421.     self startPath( startNode );
  422.     startNode notify ( "trigger", self, true );
  423.  
  424.     wait ( 0.05 );
  425.  
  426.     for ( ;; )
  427.     {
  428.         /#
  429.         while ( getDvar( "tankDir" ) != "" )
  430.             wait ( 0.05 );
  431.         #/
  432.  
  433.         while ( isDefined( self.changingDirection ) )
  434.             wait ( 0.05 );
  435.  
  436.         endNode = self getNodeNearEnemies();
  437.  
  438.         if ( isDefined( endNode ) )
  439.             self.endNode = endNode;
  440.         else
  441.             self.endNode = undefined;
  442.  
  443.         wait ( 0.65 );
  444.     }
  445. }
  446.  
  447.  
  448. Callback_VehicleDamage( inflictor, attacker, damage, dFlags, meansOfDeath, weapon, point, dir, hitLoc, timeOffset, modelIndex, partName )
  449. {
  450.     if ( ( attacker == self || attacker == self.mgTurret || ( isDefined( attacker.pers ) && attacker.pers["team"] == self.team ) ) && ( attacker != self.owner || meansOfDeath == "MOD_MELEE" ) )
  451.         return;
  452.    
  453.     tankDamage = modifyDamage( meansOfDeath, damage, attacker );
  454.  
  455.     self Vehicle_FinishDamage( inflictor, attacker, tankDamage, dFlags, meansOfDeath, weapon, point, dir, hitLoc, timeOffset, modelIndex, partName );
  456. }
  457.  
  458.  
  459. // accumulate damage and react
  460. tankDamageMonitor()
  461. {
  462.     self endon( "death" );
  463.     self.damageTaken = 0;
  464.     speed = self vehicle_GetSpeed();
  465.     maxHealth = self.health;
  466.     stage1 = false;
  467.     stage2 = false;
  468.     stage3 = false;
  469.  
  470.     for( ;; )
  471.     {
  472.         self waittill( "damage", amount, attacker, direction_vec, point, damageType );
  473.        
  474.         if ( isDefined( attacker.classname ) && attacker.classname == "script_vehicle"  )
  475.         {
  476.             if ( isDefined( self.bestTarget ) && self.bestTarget != attacker )
  477.             {
  478.                 self.forcedTarget = attacker;
  479.                 println( "Abandoning Target due to vehicle attacker" );
  480.                 self thread explicitAbandonTarget();
  481.             }          
  482.         }
  483.         else
  484.         {
  485.             if ( isPlayer( attacker ) )
  486.             {
  487.                 attacker maps\mp\gametypes\_damagefeedback::updateDamageFeedback( "hitHelicopter" );
  488.    
  489.                 if ( attacker _hasPerk( "specialty_armorpiercing" ) )
  490.                 {
  491.                     damageAdd = amount*level.armorPiercingMod;
  492.                     self.health -= int(damageAdd);
  493.                 }          
  494.             }
  495.         }
  496.        
  497.         //stages will be used to effect effeciency of the tank
  498.         //accuracy, speed, smoke emitters etc....
  499.         if ( self.health <= 0 )
  500.         {
  501.             self notify( "death" );
  502.             print("sent death notify via script");
  503.             return;
  504.         }
  505.         else if (self.health < (maxHealth/4) && stage3 == false )
  506.         {
  507.             //newSpeed = 4;
  508.             //self vehicle_SetSpeed( newSpeed, 10, 10 );
  509.             //self.standardSpeed = newSpeed;
  510.             stage3 = true;
  511.            
  512.            
  513.         }
  514.         else if (self.health < (maxHealth/2) && stage2 == false )
  515.         {
  516.             //newSpeed = 6;
  517.             //self vehicle_SetSpeed( newSpeed, 10, 10 );
  518.             //self.standardSpeed = newSpeed;
  519.             stage2 = true;
  520.            
  521.            
  522.         }
  523.         else if (self.health < (maxHealth/1.5) && stage1 == false )
  524.         {
  525.             //newSpeed = 10;
  526.             //self vehicle_SetSpeed( newSpeed, 10, 10 );
  527.             //self.standardSpeed = newSpeed;
  528.             stage1 = true;
  529.         }
  530.        
  531.         if ( amount > 1000 )
  532.         {
  533.             self handleThreat( attacker );
  534.         }
  535.     }
  536. }
  537.  
  538. handleThreat( attacker )
  539. {
  540.     self endon( "death" );
  541.    
  542.     rand = randomInt(100);
  543.    
  544.     if ( isDefined( self.bestTarget) && self.bestTarget != attacker && rand > 30 )
  545.     {  
  546.         targ = [];
  547.         targ[0] = self.bestTarget;
  548.         explicitAbandonTarget( true, self.bestTarget );
  549.         self thread acquireTarget( targ );
  550.     }
  551.     else if ( !isDefined( self.bestTarget ) && rand > 30 )
  552.     {
  553.         targ = [];
  554.         targ[0] = attacker;
  555.         self thread acquireTarget( targ ); 
  556.     }
  557.     else if ( rand < 30 )
  558.     {
  559.         // all we know here is that it didnt hit the 70%
  560.         playFX( level.tankCover, self.origin);
  561.         self thread setEvadeSpeed();
  562.     }
  563.     else
  564.     {
  565.         self fireWeapon(); 
  566.         self playSound( "bmp_fire" );
  567.     }
  568. }
  569.  
  570. handlePossibleThreat( attacker )
  571. {
  572.     self endon( "death" );
  573.    
  574.     position = relativeAngle( attacker );
  575.     distance = distance( self.origin, attacker.origin );
  576.    
  577.     if ( RandomInt( 4 ) < 3 )
  578.         return;
  579.    
  580.     if( position == "front"  && distance < 768 ) //attempts to crush player
  581.     {
  582.         self thread setEvadeSpeed();
  583.     }
  584.     else if ( position == "rear_side" || ( position == "rear" && distance >= 768 ) )
  585.     {
  586.         playFX( level.tankCover, self.origin);
  587.         self thread setEvadeSpeed();   
  588.     }
  589.     else if( position == "rear" && distance < 768 ) //attempts to crush player
  590.     {  
  591.        
  592.         self stopToReverse();
  593.         self setEvadeSpeed();
  594.         wait( 4 );
  595.         self stopToForward();
  596.  
  597.     }
  598.     else if( position == "front_side" || position == "front" )
  599.     {
  600.         playFX( level.tankCover, self.origin);
  601.         self stopToReverse();
  602.         self setEvadeSpeed();
  603.         wait( 8 );
  604.         self stopToForward();
  605.     }
  606. }
  607.  
  608. relativeAngle( ent1 )
  609. {
  610.     self endon( "death" );
  611.     ent1 endon( "death" );
  612.     ent1 endon( "disconnect" );
  613.    
  614.     tankForwardVector = anglesToForward( self.angles );
  615.     tankToEnt = ent1.origin - self.origin;
  616.     tankForwardVector *= (1,1,0);
  617.     tankToEnt *= (1,1,0 );
  618.    
  619.     tankToEnt = VectorNormalize( tankToEnt );
  620.     TankForwardVector = VectorNormalize( tankForwardVector );
  621.    
  622.     targetCosine = VectorDot( tankToEnt, tankForwardVector );
  623.    
  624.     if ( targetCosine > 0 )
  625.     {
  626.         if ( targetCosine > .9 )
  627.             return "front";
  628.         else
  629.             return "front_side";
  630.     }
  631.     else
  632.     {
  633.         if ( targetCosine < -.9 )
  634.             return "rear";
  635.         else
  636.             return "rear_side";
  637.     }  
  638.        
  639.     ent1 iPrintLnBold( targetCosine );
  640. }
  641.  
  642. watchForThreat()
  643. {
  644.     self endon( "death" );
  645.    
  646.     for ( ;; )
  647.     {
  648.         targets = [];
  649.         players = level.players;
  650.        
  651.         foreach (player in players)
  652.         {
  653.             if ( !isDefined( player ) )
  654.             {
  655.                 wait( .05 );
  656.                 continue;
  657.             }
  658.            
  659.             if ( !isTarget( player ) )
  660.             {
  661.                 wait ( .05 );
  662.                 continue;
  663.             }
  664.            
  665.             currentWeapon = player GetCurrentWeapon();
  666.  
  667.             if ( isSubStr( currentWeapon, "at4" ) || isSubStr( currentWeapon, "stinger" ) || isSubStr( currentWeapon, "javelin" ) )
  668.             {
  669.                 self thread handlePossibleThreat( player );
  670.                 wait( 8 );
  671.             }
  672.            
  673.             wait( .15 );
  674.         }
  675.     }
  676. }
  677.  
  678. //=================================================================
  679. //
  680. //                  Accessory Functions
  681. //
  682. //=================================================================
  683.  
  684. // checks if owner is valid, returns false if not valid
  685. checkOwner()
  686. {
  687.     if ( !isdefined( self.owner ) || !isdefined( self.owner.pers["team"] ) || self.owner.pers["team"] != self.team )
  688.     {
  689.         self notify ( "abandoned" );
  690.         return false;  
  691.     }
  692.     return true;
  693. }
  694.  
  695. drawLine( start, end, timeSlice, color )
  696. {
  697.     drawTime = int(timeSlice * 20);
  698.     for( time = 0; time < drawTime; time++ )
  699.     {
  700.         line( start, end, color,false, 1 );
  701.         wait ( 0.05 );
  702.     }
  703. }
  704.  
  705. modifyDamage( damageType, amount, attacker )
  706. {
  707.     if ( damageType == "MOD_RIFLE_BULLET" )
  708.         return ( amount );
  709.     else if ( damageType == "MOD_PISTOL_BULLET" )
  710.         return ( amount );
  711.     else if ( damageType == "MOD_IMPACT" )
  712.         return ( amount );
  713.     else if (damageType == "MOD_MELEE" )
  714.         return ( 0 );
  715.     else if (damageType == "MOD_EXPLOSIVE_BULLET" )
  716.         return ( amount );
  717.     else if (damageType == "MOD_GRENADE" )
  718.         return ( amount * 5 );
  719.     else if (damageType == "MOD_GRENADE_SPLASH" )
  720.         return ( amount * 5 );
  721.     else
  722.         return amount * 10;
  723. }
  724.  
  725. destroyTank()
  726. {
  727.     self waittill ( "death" );
  728.    
  729.     if ( level.teamBased )
  730.     {
  731.         team = level.tank.team;
  732.         objective_state( level.tank.objID[team], "invisible" );    
  733.         objective_state( level.tank.objID[level.otherTeam[team]], "invisible" );
  734.     }
  735.    
  736.     /* get the current team
  737.     if ( isDefined( level.tankSpawner["axis"] ) )
  738.         destroyedModel = ;
  739.     else
  740.         destroyedModel = ;
  741.     */
  742.    
  743.     // award attacker
  744.     self notify( "tankDestroyed" );
  745.     self Vehicle_SetSpeed( 0,10,10 );
  746.     level.tankInUse = false;
  747.     playFX( level.spawnFire, self.origin);
  748.    
  749.     playFX( level.tankFire, self.origin);
  750.    
  751.     self removeFromTankList();
  752.    
  753.     destroyedTank = Spawn( "script_model", self.origin );
  754.     // set model to current destroyed model.
  755.     destroyedTank setModel( "vehicle_m1a1_abrams_d_static" );
  756.     destroyedTank.angles = self.angles;
  757.     self.mgTurret delete();
  758.     self delete();
  759.    
  760.     wait(4);
  761.     destroyedTank delete();
  762. }
  763.  
  764. //=================================================================
  765. //
  766. //                  Main Weapon Targeting Functions
  767. //
  768. //=================================================================
  769.  
  770. onHitPitchClamp()
  771. {  
  772.     self notify( "onTargOrTimeOut" );
  773.    
  774.     self endon( "onTargOrTimeOut" );
  775.     self endon( "turret_on_target" );
  776.    
  777.     self waittill( "turret_pitch_clamped" );
  778.     println( "Abandoning Target due to turret not being able to reach target" );   
  779.     self thread explicitAbandonTarget( false, self.bestTarget );
  780. }
  781.  
  782. fireOnTarget()
  783. {
  784.     self endon( "abandonedTarget" );
  785.     self endon( "killedTarget" );
  786.     self endon( "death" );
  787.     self endon( "targetRemoved" );
  788.     self endon( "lostLOS" );
  789.    
  790.    
  791.     for ( ;; )
  792.     {
  793.         self onHitPitchClamp();
  794.        
  795.         if ( !isDefined( self.bestTarget ) )
  796.             continue;
  797.        
  798.         flashOrigin = self GetTagOrigin( "tag_flash" );
  799.         trace = BulletTrace( self.origin, flashOrigin, false, self );
  800.         if ( trace["position"] != flashOrigin )
  801.         {
  802.             println( "Abandoning Target due to turret not being able to reach target without clipping" );  
  803.             self thread explicitAbandonTarget( false, self.bestTarget );
  804.         }
  805.        
  806.         trace = BulletTrace( flashOrigin, self.bestTarget.origin, true, self );
  807.         distance = Distance(self.origin, trace["position"] );
  808.         realDistance = Distance( self.bestTarget.origin, self.origin );
  809.        
  810.         //hitting somthing not even close
  811.         if ( distance < 384 || distance + 256 < realDistance )
  812.         {
  813.             wait( .5 );
  814.            
  815.             if ( distance > 384 )
  816.             {
  817.                 self waitForTurretReady();
  818.                 self FireWeapon();
  819.                 self playSound( "bmp_fire" );
  820.                 self.timeLastFired = getTime();
  821.             }
  822.             println( "Abandoning due to not hitting intended space" );
  823.            
  824.             // Adjust forward or backward to hit target...
  825.             // check angle of target
  826.             position = relativeAngle( self.bestTarget );
  827.            
  828.             //if ( position == "rear_side" )
  829.                 // backup
  830.             //if ( position == "front_side" )
  831.            
  832.            
  833.             self thread explicitAbandonTarget( false, self.bestTarget );
  834.             return;
  835.         }
  836.            
  837.         self waitForTurretReady();
  838.        
  839.         self FireWeapon();
  840.         self playSound( "bmp_fire" );
  841.         self.timeLastFired = getTime();
  842.     }
  843. }
  844.  
  845. waitForTurretReady()
  846. {
  847.     self endon( "abandonedTarget" );
  848.     self endon( "killedTarget" );
  849.     self endon( "death" );
  850.     self endon( "targetRemoved" );
  851.     self endon( "lostLOS" );
  852.    
  853.     timeWaited = getTime() - self.timeLastFired;
  854.        
  855.     if ( timeWaited < 1499 )
  856.             wait( 1.5 - timeWaited/1000 );
  857. }
  858.  
  859. tankGetTargets( badTarget )
  860. {
  861.     self endon( "death" );
  862.     self endon( "leaving" );
  863.     targets = [];
  864.    
  865.     prof_begin( "tankTargets" );
  866.    
  867.     for ( ;; )
  868.     {
  869.         targets = [];
  870.         players = level.players;
  871.        
  872.         if ( isDefined( self.forcedTarget ) )
  873.         {
  874.             targets = [];
  875.             targets[0] = self.ForcedTarget;
  876.             self acquireTarget( targets );
  877.             self.forcedTarget = undefined;
  878.         }
  879.        
  880.         if ( isDefined( level.harrier ) && level.harrier.team != self.team && isAlive( level.harrier ) )
  881.         {
  882.             if( isVehicleTarget( level.tank ) )
  883.                 targets[targets.size] = level.tank;
  884.         }
  885.        
  886.         if ( isDefined( level.chopper ) && level.chopper.team != self.team  && isAlive( level.chopper ) )
  887.         {  
  888.             if( isVehicleTarget( level.chopper ) )
  889.                 targets[targets.size] = level.chopper;
  890.         }
  891.        
  892.         foreach ( potentialTarget in players )
  893.         {
  894.             if (!isDefined( potentialTarget ) )
  895.             {
  896.                 wait(.05);
  897.                 continue;
  898.             }
  899.            
  900.             if ( isDefined( badTarget ) && potentialTarget == badTarget )
  901.                 continue;
  902.            
  903.             if ( isTarget( potentialTarget ) )
  904.             {
  905.                 if( isDefined( potentialTarget ) )
  906.                     targets[targets.size] = potentialTarget;
  907.             }
  908.             else
  909.                 continue;
  910.         }
  911.         if ( targets.size > 0 )
  912.         {
  913.             self acquireTarget( targets );
  914.         }
  915.         else
  916.             wait( 1 );
  917.     }
  918.     prof_end( "tankTargets" );
  919. }
  920.  
  921. acquireTarget( targets )
  922. {
  923.     self endon( "death" );
  924.    
  925.     if ( targets.size == 1 )
  926.         self.bestTarget = targets[0];
  927.     else
  928.         self.bestTarget = self getBestTarget( targets );
  929.    
  930.     self thread setEngagementSpeed(); // slows tank down to fire on target
  931.    
  932.     // checks to abandon target
  933.     //self thread lostTarget(); // sets lost LOS and time of lost target
  934.     //self thread abandonTarget(); // if target is lost for 3+ seconds drops target and gets new one
  935.     self thread watchTargetDeath( targets ); //abandons target when target killed
  936.    
  937.    
  938.     self SetTurretTargetEnt( self.bestTarget ); // sets turret to target entity
  939.     self fireOnTarget(); // fires on current target.
  940.     self thread setNoTarget();
  941. }
  942.  
  943. setNoTarget()
  944. {
  945.     self endon( "death" );
  946.    
  947.     self setStandardSpeed();
  948.     self removeTarget();
  949.     self setTurretTargetEnt( self.neutralTarget );
  950. }
  951.  
  952. getBestTarget( targets )
  953. {
  954.     self endon( "death" );
  955.     mainGunPointOrigin = self getTagOrigin( "tag_flash" );
  956.     tankOrigin = self.origin;
  957.    
  958.     bestYaw = undefined;
  959.     bestTarget = undefined;
  960.     targetHasRocket = false;
  961.    
  962.     foreach ( targ in targets )
  963.     {
  964.         angle = abs ( vectorToAngles ( ( targ.origin - self.origin ) )[1] );
  965.         cannonAngle = abs( self getTagAngles( "tag_flash" )[1] );
  966.         angle = abs ( angle - cannonAngle );           
  967.        
  968.         //vehicle priorities
  969.         if ( isDefined( level.chopper ) && targ == level.chopper )
  970.             return targ;
  971.        
  972.         if ( isDefined( level.harrier ) && targ == level.harrier )
  973.             return targ;
  974.        
  975.         // in this calculation having a rocket removes 40d of rotation cost from best target calculation
  976.         // to prioritize targeting dangerous targets.
  977.         weaponsArray = targ GetWeaponsListItems();
  978.         foreach ( weapon in weaponsArray )
  979.         {
  980.             if ( isSubStr( weapon, "at4" ) || isSubStr( weapon, "jav" ) || isSubStr( weapon, "c4" ) )
  981.                 angle -= 40;
  982.         }
  983.                
  984.         if ( !isDefined( bestYaw ) )
  985.         {              
  986.             bestYaw = angle;
  987.             bestTarget = targ;
  988.         }
  989.         else if ( bestYaw > angle )
  990.         {
  991.             bestYaw = angle;
  992.             bestTarget = targ;         
  993.         }
  994.     }
  995.    
  996.     return ( bestTarget );
  997. }
  998.  
  999. watchTargetDeath( targets )
  1000. {
  1001.     self endon( "abandonedTarget" );
  1002.     self endon( "lostLOS" );
  1003.     self endon( "death" );
  1004.     self endon( "targetRemoved" );
  1005.        
  1006.     bestTarg = self.bestTarget;
  1007.     bestTarg endon ( "disconnect" );
  1008.    
  1009.     bestTarg waittill( "death" );
  1010.    
  1011.     self notify( "killedTarget" );
  1012.     self removeTarget();
  1013.     self setStandardSpeed();
  1014.     self thread setNoTarget();
  1015. }
  1016.  
  1017. explicitAbandonTarget( noNewTarget, targ )
  1018. {
  1019.     self endon( "death" );
  1020.    
  1021.     self notify( "abandonedTarget" );
  1022.     println("ABANDON TARGET EXPLICIT");
  1023.     self setStandardSpeed();
  1024.     self thread Setnotarget();
  1025.     self removeTarget();
  1026.    
  1027.     if ( isDefined(targ) )
  1028.     {
  1029.         self.badTarget = targ;
  1030.         badTargetReset();
  1031.     }  
  1032.    
  1033.     if ( isDefined(noNewTarget) && noNewTarget )
  1034.         return;
  1035.    
  1036.     return;
  1037. }
  1038.  
  1039. badTargetReset()
  1040. {
  1041.     self endon("death");
  1042.    
  1043.     wait (1.5);
  1044.     self.badTarget = undefined;    
  1045. }
  1046.  
  1047. removeTarget()
  1048. {
  1049.     self notify( "targetRemoved" );
  1050.    
  1051.     self.bestTarget = undefined;
  1052.     self.lastLostTime = undefined; 
  1053. }
  1054.  
  1055. isVehicleTarget( potentialTarget )
  1056. {
  1057.     if ( distance2D( potentialTarget.origin, self.origin ) > 4096 )
  1058.         return false;
  1059.    
  1060.     if ( distance( potentialTarget.origin , self.origin ) < 512 )
  1061.         return false;
  1062.        
  1063.     return turretSightTrace( potentialTarget, false );
  1064. }
  1065.  
  1066. isTarget( potentialTarget )
  1067. {
  1068.     self endon( "death" );
  1069.    
  1070.     dist = distanceSquared( potentialTarget.origin, self.origin );
  1071.    
  1072.     if ( !level.teamBased && isDefined( self.owner ) && potentialTarget == self.owner )
  1073.         return false;
  1074.    
  1075.     if ( !isalive( potentialTarget ) || potentialTarget.sessionstate != "playing" )
  1076.         return false;
  1077.        
  1078.     if ( dist > 4096*4096 )
  1079.         return false;
  1080.    
  1081.     if ( dist < 512*512 )
  1082.         return false;
  1083.    
  1084.     if ( !isdefined( potentialTarget.pers["team"] ) )
  1085.         return false;
  1086.        
  1087.     if ( potentialTarget == self.owner )
  1088.         return false;
  1089.    
  1090.     if ( level.teamBased && potentialTarget.pers["team"] == self.team )
  1091.         return false;
  1092.    
  1093.     if ( potentialTarget.pers["team"] == "spectator" )
  1094.         return false;
  1095.    
  1096.     if ( isdefined( potentialTarget.spawntime ) && ( gettime() - potentialTarget.spawntime )/1000 <= 5 )
  1097.         return false;
  1098.  
  1099.     if ( potentialTarget _hasPerk( "specialty_coldblooded" ) )
  1100.         return false;
  1101.    
  1102.     return self Vehicle_CanTurretTargetPoint( potentialTarget.origin, 1, self );
  1103.    
  1104.     //return self turretSightTrace( potentialTarget, false );
  1105. }
  1106.  
  1107. turretSightTrace( targ, debug )
  1108. {
  1109.     turretCanSeeTarget = targ sightConeTrace( self getTagOrigin( "tag_turret" ), self );
  1110.    
  1111.     if ( turretCanSeeTarget < .7 )
  1112.     {
  1113.         return false;  
  1114.     }
  1115.    
  1116.     if ( isDefined(debug) && debug )
  1117.         self thread drawLine( targ.origin, self getTagOrigin( "tag_turret" ), 10, (1,0,0) );
  1118.    
  1119.     return true;   
  1120. }
  1121.  
  1122. //=================================================================
  1123. //
  1124. //                  Secondary Weapon Targeting Functions
  1125. //
  1126. //=================================================================
  1127.  
  1128. isMiniTarget( potentialTarget )
  1129. {
  1130.     self endon( "death" );
  1131.    
  1132.     if ( !isalive( potentialTarget ) || potentialTarget.sessionstate != "playing" )
  1133.         return false;
  1134.    
  1135.     if ( !isdefined( potentialTarget.pers["team"] ) )
  1136.         return false;
  1137.    
  1138.     if ( potentialTarget == self.owner )
  1139.         return false;
  1140.    
  1141.     if ( distanceSquared( potentialTarget.origin , self.origin ) > 1024*1024 )
  1142.         return false;
  1143.    
  1144.     if ( level.teamBased && potentialTarget.pers["team"] == self.team )
  1145.         return false;
  1146.    
  1147.     if ( potentialTarget.pers["team"] == "spectator" )
  1148.         return false;
  1149.    
  1150.     if ( isdefined( potentialTarget.spawntime ) && ( gettime() - potentialTarget.spawntime )/1000 <= 5 )
  1151.         return false;
  1152.  
  1153.    
  1154.     if ( isDefined( self ) )
  1155.     {
  1156.         minTurretEye = self.mgTurret.origin + ( 0, 0, 64 );
  1157.         minTurretCanSeeTarget = potentialTarget sightConeTrace( minTurretEye, self );
  1158.    
  1159.         if ( minTurretCanSeeTarget < 1 )
  1160.             return false;  
  1161.     }
  1162.    
  1163.     return true;
  1164. }
  1165.  
  1166. tankGetMiniTargets()
  1167. {
  1168.     self endon( "death" );
  1169.     self endon( "leaving" );
  1170.     miniTargets = [];
  1171.     println( "Geting Mini Targets" );
  1172.    
  1173.     for ( ;; )
  1174.     {
  1175.         miniTargets = [];
  1176.         players = level.players;
  1177.        
  1178.         for (i = 0; i <= players.size; i++)
  1179.         {
  1180.             if ( isMiniTarget( players[i] ) )
  1181.             {
  1182.                 if( isdefined( players[i] ) )
  1183.                     miniTargets[miniTargets.size] = players[i];
  1184.             }
  1185.             else
  1186.                 continue;
  1187.            
  1188.             wait( .05 );
  1189.         }
  1190.         if ( miniTargets.size > 0 )
  1191.         {
  1192.             self acquireMiniTarget( miniTargets );
  1193.             return;
  1194.         }  
  1195.         else
  1196.             wait( .5 );
  1197.     }
  1198. }
  1199.  
  1200. getBestMiniTarget( targets )
  1201. {
  1202.     self endon( "death" );
  1203.     tankOrigin = self.origin;
  1204.    
  1205.     closest = undefined;
  1206.     bestTarget = undefined;
  1207.    
  1208.     foreach ( targ in targets )
  1209.     {      
  1210.         curDist = Distance( self.origin, targ.origin );
  1211.        
  1212.         // in this calculation having a rocket javelin or c4 increases mini turret priority
  1213.         // to prioritize targeting dangerous targets.
  1214.         curWeaon = targ GetCurrentWeapon();
  1215.         if ( isSubStr( curWeaon, "at4" ) || isSubStr( curWeaon, "jav" ) || isSubStr( curWeaon, "c4" ) || isSubStr( curWeaon, "smart" ) || isSubStr( curWeaon, "grenade" ) )
  1216.                 curDist -= 200;
  1217.        
  1218.         if ( !isDefined( closest ) )
  1219.         {
  1220.             closest = curDist;
  1221.             bestTarget = targ;
  1222.         }
  1223.         else if ( closest > curDist )
  1224.         {
  1225.             closest = curDist;
  1226.             bestTarget = targ;
  1227.         }  
  1228.     }
  1229.     return ( bestTarget );
  1230. }
  1231.  
  1232. acquireMiniTarget( targets )
  1233. {
  1234.     self endon( "death" );
  1235.    
  1236.     if ( targets.size == 1 )
  1237.         self.bestMiniTarget = targets[0];
  1238.     else
  1239.         self.bestMiniTarget = self getBestMiniTarget( targets );
  1240.  
  1241.     if ( distance2D( self.origin, self.bestMiniTarget.origin) > 768 )
  1242.         self thread setMiniEngagementSpeed();
  1243.    
  1244.     self notify( "acquiringMiniTarget" );
  1245.     self.mgTurret SetTargetEntity( self.bestMiniTarget, ( 0,0,64 ) );   // sets turret to target entity
  1246.     wait( .15 );
  1247.     self thread fireMiniOnTarget(); // fires on current target.
  1248.     self thread watchMiniTargetDeath( targets ); //abandons target when target killed  
  1249.     self thread watchMiniTargetDistance( targets );
  1250.     self thread watchMiniTargetThreat( self.bestMiniTarget );
  1251. }
  1252.  
  1253. fireMiniOnTarget()
  1254. {
  1255.     self endon( "death" );
  1256.     self endon( "abandonedMiniTarget" );
  1257.     self endon( "killedMiniTarget" );
  1258.     noTargTime = undefined;
  1259.     miniAcquiredTime = getTime();
  1260.    
  1261.     if ( !isDefined( self.bestMiniTarget ) )
  1262.     {
  1263.         println("No Targ to fire on");
  1264.         return;
  1265.     }
  1266.    
  1267.     println("firing on best target");
  1268.    
  1269.     while( 1 )
  1270.     {
  1271.         if ( !isDefined ( self.mgTurret getTurretTarget( true ) ) )
  1272.         {
  1273.             if ( !isDefined( noTargTime ) )
  1274.                 noTargTime = getTime();
  1275.            
  1276.             curTime = getTime();
  1277.            
  1278.             if ( noTargTime - curTime > 1 )
  1279.             {  
  1280.                 noTargTime = undefined;
  1281.                 self thread explicitAbandonMiniTarget();
  1282.                 return;
  1283.             }
  1284.            
  1285.             //println("Waiting because the turret doesnt have a target" );
  1286.            
  1287.             wait ( .5 );
  1288.             continue;
  1289.         }
  1290.    
  1291.         if ( getTime() > miniAcquiredTime + 1000 && !isDefined( self.bestTarget ) )
  1292.         {
  1293.             if ( distance2D(self.origin, self.bestMiniTarget.origin ) > 768 )
  1294.             {
  1295.                 targets[0] = self.bestMiniTarget;
  1296.                 self acquireTarget( targets );
  1297.             }
  1298.         }
  1299.        
  1300.         numShots = randomIntRange( 10, 16 );
  1301.         for ( i = 0; i < numShots; i++ )
  1302.         {
  1303.             self.mgTurret ShootTurret();
  1304.             wait ( .1 );
  1305.         }
  1306.         wait ( randomFloatRange( 0.5, 3.0 ) );
  1307.     }
  1308. }
  1309.  
  1310. watchMiniTargetDeath( targets )
  1311. {
  1312.     self endon( "abandonedMiniTarget" );
  1313.     self endon( "death" );
  1314.     if ( ! isDefined( self.bestMiniTarget ) )
  1315.         return;
  1316.    
  1317.     self.bestMiniTarget waittill( "death" );
  1318.    
  1319.     self notify( "killedMiniTarget" );
  1320.     println( "Killed Mini Target" );
  1321.    
  1322.     self.bestMiniTarget = undefined;
  1323.     self.mgTurret ClearTargetEntity();
  1324.     self tankGetMiniTargets();
  1325. }
  1326.  
  1327. watchMiniTargetDistance( targets )
  1328. {
  1329.     self endon( "abandonedMiniTarget" );
  1330.     self endon( "death" );
  1331.    
  1332.     for ( ;; )
  1333.     {
  1334.         if (! isDefined( self.bestMiniTarget ) )
  1335.             return;
  1336.    
  1337.         trace = BulletTrace( self.mgTurret.origin, self.bestMiniTarget.origin, false, self );
  1338.         traceDistance = Distance(self.origin, trace["position"] );
  1339.        
  1340.         if ( traceDistance > 1024 )
  1341.         {
  1342.             println( "MINI TARGET DIST TOO FAR!!!" );
  1343.             self thread explicitAbandonMiniTarget();
  1344.             return;
  1345.         }
  1346.         println( traceDistance );
  1347.         wait ( 2 );
  1348.     }  
  1349. }
  1350.  
  1351. watchMiniTargetThreat( curTarget )
  1352. {
  1353.     self endon( "abandonedMiniTarget" );
  1354.     self endon( "death" );
  1355.     self endon( "killedMiniTarget" );
  1356.    
  1357.     for ( ;; )
  1358.     {
  1359.         miniTargets = [];
  1360.         players = level.players;
  1361.        
  1362.         for (i = 0; i <= players.size; i++)
  1363.         {
  1364.             if ( isMiniTarget( players[i] ) )
  1365.             {
  1366.                 if( !isdefined( players[i] ) )
  1367.                     continue;
  1368.                
  1369.                 if( !isdefined(curTarget) )
  1370.                     return;
  1371.                
  1372.                 traceOldTarg = Distance(self.origin, CurTarget.origin );
  1373.                 traceNewTarg = Distance(self.origin, players[i].origin );
  1374.                
  1375.                 if ( traceNewTarg < traceOldTarg )
  1376.                 {
  1377.                     self thread explicitAbandonMiniTarget();
  1378.                     return;
  1379.                 }
  1380.             }
  1381.            
  1382.             wait( .05 );
  1383.         }
  1384.        
  1385.         wait( .25 );       
  1386.     }  
  1387. }
  1388.  
  1389. explicitAbandonMiniTarget( noNewTarget )
  1390. {
  1391.  
  1392.     self notify( "abandonedMiniTarget" );
  1393.    
  1394.     println( "ABANDONED MINI TARGET" );
  1395.    
  1396.     self.bestMiniTarget = undefined;
  1397.     self.mgTurret ClearTargetEntity();
  1398.    
  1399.     if ( isDefined(noNewTarget) && noNewTarget )
  1400.         return;
  1401.    
  1402.     self thread tankGetMiniTargets();
  1403.     return;
  1404. }
  1405.  
  1406.  
  1407. addToTankList()
  1408. {
  1409.     level.tanks[self getEntityNumber()] = self;
  1410. }
  1411.  
  1412. removeFromTankList()
  1413. {
  1414.     level.tanks[self getEntityNumber()] = undefined;
  1415. }  
  1416.  
  1417.  
  1418. /*************************************************************************
  1419. *
  1420. *   PATHFINDING AND PATH NODE FUNCTIONS
  1421. *
  1422. ***************************************************************************/
  1423.  
  1424. getNodeNearEnemies()
  1425. {
  1426.     validEnemies = [];
  1427.    
  1428.     foreach ( player in level.players )
  1429.     {
  1430.         if ( player.team == "spectator" )
  1431.             continue;
  1432.            
  1433.         if ( player.team == self.team )
  1434.             continue;
  1435.            
  1436.         if ( !isAlive( player ) )
  1437.             continue;
  1438.            
  1439.         player.dist = 0;
  1440.         validEnemies[validEnemies.size] = player;      
  1441.     }
  1442.    
  1443.     if ( !validEnemies.size )
  1444.         return undefined;
  1445.  
  1446.     for ( i = 0; i < validEnemies.size; i++ )
  1447.     {
  1448.         for ( j = i + 1; j < validEnemies.size; j++ )
  1449.         {
  1450.             dist = distanceSquared( validEnemies[i].origin, validEnemies[j].origin );
  1451.            
  1452.             validEnemies[i].dist += dist;
  1453.             validEnemies[j].dist += dist;
  1454.         }
  1455.     }
  1456.    
  1457.     bestPlayer = validEnemies[0];
  1458.     foreach ( player in validEnemies )
  1459.     {
  1460.         if ( player.dist < bestPlayer.dist )
  1461.             bestPlayer = player;
  1462.     }
  1463.  
  1464.     bestOrigin = bestPlayer.origin;
  1465.    
  1466.     sortedNodes = sortByDistance( level.graphNodes, bestOrigin );
  1467.    
  1468.     //thread drawLine( bestOrigin, sortedNodes[0].origin, 10.0, (1,0,1) );
  1469.    
  1470.     return ( sortedNodes[0] );
  1471. }
  1472.  
  1473.  
  1474. setupPaths()
  1475. {
  1476.     tankNodes = [];
  1477.     startNodes = [];
  1478.     endNodes = [];
  1479.     aStarGraphNodes = [];
  1480.    
  1481.     // setup the start node
  1482.     tankNode = GetVehicleNode( "startnode", "targetname" );
  1483.     tankNodes[tankNodes.size] = tankNode;
  1484.     startNodes[startNodes.size] = tankNode;
  1485.    
  1486.     while ( isDefined( tankNode.target ) )
  1487.     {
  1488.         lastNode = tankNode;
  1489.         tankNode = GetVehicleNode( tankNode.target, "targetname" );
  1490.         tankNode.prev = lastNode;
  1491.        
  1492.         // case for connected path
  1493.         if ( tankNode == tankNodes[0] )
  1494.             break;
  1495.  
  1496.         tankNodes[tankNodes.size] = tankNode;
  1497.        
  1498.         // case for disconnected path
  1499.         if ( !isDefined( tankNode.target ) )
  1500.             return;
  1501.     }
  1502.  
  1503.     tankNodes[0].branchNodes = [];
  1504.     tankNodes[0] thread handleBranchNode( "forward" );
  1505.     aStarGraphNodes[aStarGraphNodes.size] = tankNodes[0];
  1506.  
  1507.     // find the start and end nodes of the branches
  1508.     branchNodes = GetVehicleNodeArray( "branchnode", "targetname" );
  1509.     foreach ( branchNode in branchNodes )
  1510.     {
  1511.         tankNode = branchNode;
  1512.         tankNodes[tankNodes.size] = tankNode;
  1513.         startNodes[startNodes.size] = tankNode;
  1514.  
  1515.         while ( isDefined( tankNode.target ) )
  1516.         {
  1517.             lastNode = tankNode;
  1518.             tankNode = GetVehicleNode( tankNode.target, "targetname" );
  1519.             tankNodes[tankNodes.size] = tankNode;
  1520.             tankNode.prev = lastNode;
  1521.  
  1522.             if ( !isDefined( tankNode.target ) )
  1523.                 endNodes[endNodes.size] = tankNode;
  1524.         }
  1525.     }
  1526.  
  1527.     // detect and initialize the branch nodes.  These will be used for the aStar node graph
  1528.     foreach ( tankNode in tankNodes )
  1529.     {      
  1530.         isBranchNode = false;
  1531.         foreach ( startNode in startNodes )
  1532.         {
  1533.             if ( startNode == tankNode )
  1534.                 continue;
  1535.            
  1536.             if ( startNode.target == tankNode.targetname )
  1537.                 continue;
  1538.                
  1539.             if ( isDefined( tankNode.target ) && tankNode.target == startNode.targetname )
  1540.                 continue;
  1541.            
  1542.             if ( distance2d( tankNode.origin, startNode.origin ) > 80 )
  1543.                 continue;
  1544.  
  1545.             startNode thread handleCapNode( tankNode, "reverse" );
  1546.             startNode.prev = tankNode;
  1547.  
  1548.             if ( !isDefined( tankNode.branchNodes ) )
  1549.                 tankNode.branchNodes = [];
  1550.  
  1551.             tankNode.branchNodes[tankNode.branchNodes.size] = startNode;
  1552.            
  1553.             isBranchNode = true;
  1554.         }
  1555.        
  1556.         if ( isBranchNode )
  1557.             tankNode thread handleBranchNode( "forward" );
  1558.        
  1559.         isJoinNode = false;
  1560.         foreach ( endNode in endNodes)
  1561.         {
  1562.             if ( endNode == tankNode )
  1563.                 continue;
  1564.            
  1565.             if ( !isDefined( tankNode.target ) )
  1566.                 continue;
  1567.            
  1568.             if ( tankNode.target == endNode.targetname )
  1569.                 continue;  
  1570.  
  1571.             if ( isDefined( endNode.target ) && endNode.target == tankNode.targetname )
  1572.                 continue;  
  1573.            
  1574.             if ( distance2d( tankNode.origin, endNode.origin ) > 80 )
  1575.                 continue;
  1576.  
  1577.             endNode thread handleCapNode( tankNode, "forward" );
  1578.             endNode.next = getVehicleNode( tankNode.targetname, "targetname" );
  1579.             //endNode.target = tankNode.targetname; // READ-ONLY field...
  1580.             endNode.length = distance( endNode.origin, tankNode.origin );
  1581.  
  1582.             if ( !isDefined( tankNode.branchNodes ) )
  1583.                 tankNode.branchNodes = [];
  1584.  
  1585.             tankNode.branchNodes[tankNode.branchNodes.size] = endNode;
  1586.            
  1587.             isJoinNode = true;
  1588.         }
  1589.        
  1590.         if ( isJoinNode )
  1591.         {
  1592.             assert( !isBranchNode );
  1593.             tankNode thread handleBranchNode( "reverse" );
  1594.         }
  1595.        
  1596.         if ( isJoinNode || isBranchNode )
  1597.             aStarGraphNodes[aStarGraphNodes.size] = tankNode;
  1598.     }
  1599.  
  1600.     if ( aStarGraphNodes.size < 3 )
  1601.     {
  1602.         level notify ( "end_tankPathHandling" );
  1603.         return;
  1604.     }
  1605.  
  1606.     // subdivide the path a bit...
  1607.     segmentNodes = [];
  1608.     foreach( tankNode in tankNodes )
  1609.     {
  1610.         if ( !isDefined( tankNode.branchNodes ) )
  1611.             continue;
  1612.            
  1613.         segmentNodes[segmentNodes.size] = tankNode;
  1614.     }
  1615.  
  1616.     foreach ( segmentNode in segmentNodes )
  1617.     {
  1618.         tankNode = segmentNode;
  1619.         pathLength = 0;
  1620.        
  1621.         while ( isDefined( tankNode.target ) )
  1622.         {
  1623.             prevNode = tankNode;
  1624.             tankNode = GetVehicleNode( tankNode.target, "targetname" );
  1625.             pathLength += distance( tankNode.origin, prevNode.origin );
  1626.            
  1627.             if ( tankNode == segmentNode ) 
  1628.                 break;
  1629.                
  1630.             if ( isDefined( tankNode.branchNodes ) )
  1631.                 break;
  1632.         }
  1633.  
  1634.         if ( pathLength > 1000 )
  1635.         {
  1636.             tankNode = segmentNode;
  1637.             curLength = 0;
  1638.  
  1639.             while ( isDefined( tankNode.target ) )
  1640.             {
  1641.                 prevNode = tankNode;
  1642.                 tankNode = GetVehicleNode( tankNode.target, "targetname" );
  1643.                
  1644.                 curLength += distance( tankNode.origin, prevNode.origin );
  1645.                 if ( curLength < pathLength / 2 )
  1646.                     continue;
  1647.  
  1648.                 tankNode.branchNodes = []; // necessary?
  1649.                 tankNode thread handleBranchNode( "forward" );
  1650.                 aStarGraphNodes[aStarGraphNodes.size] = tankNode;
  1651.                 break;
  1652.             }
  1653.         }
  1654.     }
  1655.  
  1656.     level.graphNodes = initNodeGraph( aStarGraphNodes );
  1657.    
  1658.     foreach ( tankNode in tankNodes )
  1659.     {
  1660.         if ( !isDefined( tankNode.graphId ) )
  1661.             tankNode thread nodeTracker();
  1662.     }
  1663. }
  1664.  
  1665.  
  1666.  
  1667. getRandomBranchNode( direction )
  1668. {
  1669.     branchNodes = [];
  1670.     foreach ( graphId, linkNode in self.links )
  1671.     {
  1672.         // pick a branch in the direction we're already heading
  1673.         if ( self.linkDirs[graphId] != direction )
  1674.             continue;
  1675.            
  1676.         branchNodes[branchNodes.size] = linkNode;
  1677.     }
  1678.    
  1679.     return ( branchNodes[randomInt( branchNodes.size )] );
  1680. }
  1681.  
  1682.  
  1683. getNextNodeForEndNode( endNode, direction )
  1684. {
  1685.     graphNode = level.graphNodes[self.graphId];
  1686.    
  1687.     continuePath = generatePath( graphNode, endNode, undefined, direction );
  1688.     continueG = continuePath[0].g;
  1689.    
  1690.     changePath = generatePath( graphNode, endNode, undefined, level.otherDir[direction] );
  1691.     changeG = changePath[0].g;
  1692.  
  1693.     // temporarily force the tank to only go forward
  1694.     if ( !getDvarInt( "tankDebug" ) )
  1695.         changeG = 9999999;
  1696.    
  1697.     if ( continueG <= changeG )
  1698.         return ( continuePath[1] );
  1699. }
  1700.  
  1701.  
  1702. handleBranchNode( direction )
  1703. {
  1704.     level endon ( "end_tankPathHandling" );
  1705.     for ( ;; )
  1706.     {
  1707.         self waittill( "trigger", tank, wasForced );
  1708.  
  1709.         graphNode = level.graphNodes[self.graphId];
  1710.  
  1711.         tank.node = self;
  1712.        
  1713.         nextGraphNode = undefined;
  1714.         if ( isDefined( tank.endNode ) && tank.endNode != graphNode )
  1715.         {
  1716.             nextGraphNode = getNextNodeForEndNode( tank.endNode, tank.veh_pathdir );
  1717.            
  1718.             if ( !isDefined( nextGraphNode ) )
  1719.                 tank thread setDirection( level.otherDir[tank.veh_pathdir] );
  1720.         }
  1721.        
  1722.         if ( !isDefined( nextGraphNode ) || nextGraphNode == graphNode )
  1723.         {
  1724.             nextGraphNode = graphNode getRandomBranchNode( tank.veh_pathdir );
  1725.         }
  1726.  
  1727.         goalNode = graphNode.linkStartNodes[nextGraphNode.graphId];
  1728.  
  1729.         if ( tank.veh_pathdir == "forward" )
  1730.             nextLinkNode = self getNextNode();
  1731.         else
  1732.             nextLinkNode = self getPrevNode();
  1733.  
  1734.         // if we're already on this path, just keep going
  1735.         if ( nextLinkNode != goalNode )
  1736.             tank startPath( goalNode );
  1737.     }
  1738. }
  1739.  
  1740.  
  1741. handleCapNode( joinNode, direction )
  1742. {
  1743.     for ( ;; )
  1744.     {
  1745.         self waittill( "trigger", tank );
  1746.        
  1747.         if ( tank.veh_pathdir != direction )
  1748.             continue;
  1749.        
  1750.         debugPrintLn2( "tank starting path at join node: " + joinNode.graphId );
  1751.            
  1752.         tank startPath( joinNode );
  1753.     }
  1754. }
  1755.  
  1756.  
  1757. nodeTracker()
  1758. {
  1759.     self.forwardGraphId = getForwardGraphNode().graphId;
  1760.     self.reverseGraphId = getReverseGraphNode().graphId;
  1761.    
  1762.     for ( ;; )
  1763.     {
  1764.         self waittill ( "trigger", tank, wasForced );
  1765.        
  1766.         tank.node = self;
  1767.        
  1768.         /#
  1769.         if ( getDvarInt( "tankForceTrigger" ) )
  1770.         {
  1771.             if ( tank.veh_pathdir == "forward" )
  1772.                 tank thread forceTrigger( self, self getNextNode(), tank );
  1773.             else
  1774.                 tank thread forceTrigger( self, self getPrevNode(), tank );
  1775.             }
  1776.         #/
  1777.  
  1778.         tank.forwardGraphId = self.forwardGraphId;
  1779.         tank.reverseGraphId = self.reverseGraphId;
  1780.        
  1781.         if ( !isDefined( self.target ) || self.targetname == "branchnode" )
  1782.             nodeType = "TRANS";
  1783.         else
  1784.             nodeType = "NODE";
  1785.        
  1786.         if ( isDefined( wasForced ) )
  1787.             debugPrint3D( self.origin, nodeType, (1,0.5,0), 1, 2, 100 );
  1788.         else
  1789.             debugPrint3D( self.origin, nodeType, (0,1,0), 1, 2, 100 );
  1790.     }
  1791. }
  1792.  
  1793.  
  1794. forceTrigger( prevNode, nextNode, tank )
  1795. {
  1796.     nextNode endon ( "trigger" );
  1797.     prevNode endon ( "trigger" );
  1798.     tank endon ( "death" );
  1799.    
  1800.     minDist = distanceSquared( tank.origin, nextNode.origin );
  1801.     tankDir = tank.veh_pathdir;
  1802.  
  1803.     debugPrint3D( prevNode.origin+(0,0,30), "LAST", (0,0,1), 0.5, 1, 100 );
  1804.     debugPrint3D( nextNode.origin+(0,0,60), "NEXT", (0,1,0), 0.5, 1, 100 );
  1805.  
  1806.     timeOutNextFrame = false;
  1807.     for ( ;; )
  1808.     {
  1809.         wait ( 0.05 );
  1810.        
  1811.         // tank changed direction
  1812.         if ( tankDir != tank.veh_pathdir )
  1813.         {
  1814.             debugPrintLn2( "tank missed node: reversing direction" );
  1815.             tank thread forceTrigger( nextNode, prevNode, tank );
  1816.             return;
  1817.         }
  1818.        
  1819.         if ( timeOutNextFrame )
  1820.         {
  1821.             debugPrintLn2( "... sending notify." );
  1822.             nextNode notify ( "trigger", tank, true );
  1823.             return;
  1824.         }
  1825.        
  1826.         curDist = distanceSquared( tank.origin, nextNode.origin );
  1827.        
  1828.         if ( curDist > minDist )
  1829.         {
  1830.             timeOutNextFrame = true;
  1831.             debugPrintLn2( "tank missed node: forcing notify in one frame..." );
  1832.         }
  1833.            
  1834.         minDist = curDist;     
  1835.     }
  1836. }
  1837.  
  1838.  
  1839. getForwardGraphNode()
  1840. {
  1841.     assert( !isDefined( self.graphId ) );
  1842.    
  1843.     checkNode = self;  
  1844.     while ( !isDefined( checkNode.graphId ) )
  1845.         checkNode = checkNode getNextNode();
  1846.        
  1847.     return checkNode;
  1848. }
  1849.  
  1850.  
  1851. getReverseGraphNode()
  1852. {
  1853.     assert( !isDefined( self.graphId ) );
  1854.    
  1855.     checkNode = self;  
  1856.     while ( !isDefined( checkNode.graphId ) )
  1857.         checkNode = checkNode getPrevNode();
  1858.        
  1859.     return checkNode;
  1860. }
  1861.  
  1862.  
  1863. getNextNode()
  1864. {
  1865.     if ( isDefined( self.target ) )
  1866.         return ( GetVehicleNode( self.target, "targetname" ) );
  1867.     else
  1868.         return ( self.next );
  1869. }
  1870.  
  1871.  
  1872. getPrevNode()
  1873. {
  1874.     return self.prev;
  1875. }
  1876.  
  1877.  
  1878.  
  1879. // Builds the aStar node graph
  1880. initNodeGraph( astarBaseNodes )
  1881. {
  1882.     graphNodes = [];
  1883.     foreach ( pathNode in aStarBaseNodes )
  1884.     {
  1885.         graphNode = spawnStruct();
  1886.         graphNode.linkInfos = [];
  1887.         graphNode.links = [];
  1888.         graphNode.linkLengths = [];
  1889.         graphNode.linkDirs = [];
  1890.         graphNode.linkStartNodes = [];
  1891.         graphNode.node = pathNode;
  1892.         graphNode.origin = pathNode.origin;
  1893.         graphNode.graphId = graphNodes.size;
  1894.         pathNode.graphId = graphNodes.size;
  1895.  
  1896.         debugPrint3D( graphNode.origin + (0,0,80), graphNode.graphId, (1,1,1), 0.65, 2, 100000 );
  1897.  
  1898.         graphNodes[graphNodes.size] = graphNode;       
  1899.     }
  1900.  
  1901.     foreach ( pathNode in aStarBaseNodes )
  1902.     {
  1903.         graphId = pathNode.graphId;
  1904.  
  1905.         checkNode = GetVehicleNode( pathNode.target, "targetname" );
  1906.         linkLength = distance( pathNode.origin, checkNode.origin );
  1907.         linkStartNode = checkNode;
  1908.        
  1909.         while ( !isDefined( checkNode.graphId ) )
  1910.         {
  1911.             linkLength += distance( checkNode.origin, checkNode.prev.origin );
  1912.            
  1913.             if ( isDefined( checkNode.target ) )
  1914.                 checkNode = GetVehicleNode( checkNode.target, "targetname" );
  1915.             else
  1916.                 checkNode = checkNode.next;
  1917.         }
  1918.  
  1919.         assert( checkNode != pathNode );
  1920.         graphNodes[graphId] addLinkNode( graphNodes[checkNode.graphId], linkLength, "forward", linkStartNode );
  1921.  
  1922.         checkNode = pathNode.prev;
  1923.         linkLength = distance( pathNode.origin, checkNode.origin );
  1924.         linkStartNode = checkNode;
  1925.        
  1926.         while ( !isDefined( checkNode.graphId ) )
  1927.         {
  1928.             linkLength += distance( checkNode.origin, checkNode.prev.origin );
  1929.             checkNode = checkNode.prev;
  1930.         }
  1931.  
  1932.         assert( checkNode != pathNode );       
  1933.         graphNodes[graphId] addLinkNode( graphNodes[checkNode.graphId], linkLength, "reverse", linkStartNode );
  1934.        
  1935.         foreach ( branchNode in pathNode.branchNodes )
  1936.         {
  1937.             checkNode = branchNode;
  1938.             linkLength = distance( pathNode.origin, checkNode.origin );
  1939.             linkStartNode = checkNode;
  1940.            
  1941.             if ( checkNode.targetname == "branchnode" )
  1942.             {
  1943.                 while ( !isDefined( checkNode.graphId ) )
  1944.                 {
  1945.                     if ( isDefined( checkNode.target ) )
  1946.                         nextNode = GetVehicleNode( checkNode.target, "targetname" );
  1947.                     else
  1948.                         nextNode = checkNode.next;
  1949.                        
  1950.                     linkLength += distance( checkNode.origin, nextNode.origin );
  1951.                     checkNode = nextNode;
  1952.                 }
  1953.                
  1954.                 assert( checkNode != pathNode );       
  1955.                 graphNodes[graphId] addLinkNode( graphNodes[checkNode.graphId], linkLength, "forward", linkStartNode );
  1956.             }  
  1957.             else
  1958.             {
  1959.                 while ( !isDefined( checkNode.graphId ) )
  1960.                 {
  1961.                     linkLength += distance( checkNode.origin, checkNode.prev.origin );
  1962.                     checkNode = checkNode.prev;
  1963.                 }
  1964.        
  1965.                 assert( checkNode != pathNode );       
  1966.                 graphNodes[graphId] addLinkNode( graphNodes[checkNode.graphId], linkLength, "reverse", linkStartNode );
  1967.             }
  1968.         }
  1969.     }
  1970.  
  1971.     return graphNodes;
  1972. }
  1973.  
  1974.  
  1975. addLinkNode( graphNode, linkLength, linkDir, linkStartNode )
  1976. {
  1977.     assert( self.graphId != graphNode.graphId );
  1978.     assert( !isDefined( self.links[graphNode.graphId] ) );
  1979.    
  1980.     self.links[graphNode.graphId] = graphNode;
  1981.     self.linkLengths[graphNode.graphId] = linkLength;
  1982.     self.linkDirs[graphNode.graphId] = linkDir;
  1983.     self.linkStartNodes[graphNode.graphId] = linkStartNode;
  1984.  
  1985.     linkInfo = spawnStruct();
  1986.     linkInfo.toGraphNode = graphNode;
  1987.     linkInfo.toGraphId = graphNode.graphId;
  1988.     linkInfo.length = linkLength;
  1989.     linkInfo.direction = linkDir;
  1990.     linkInfo.startNode = linkStartNode;
  1991.    
  1992.     self.linkInfos[graphNode.graphId] = linkInfo;
  1993. }
  1994.  
  1995.  
  1996. // call function as generatePath(startNode, destNode), otherwise paths will be reversed
  1997. generatePath( destNode, startNode, blockedNodes, direction )
  1998. {
  1999.     level.openList = [];
  2000.     level.closedList = [];
  2001.     foundPath = false;
  2002.     pathNodes = [];
  2003.    
  2004.     if ( !isDefined( blockedNodes ) )
  2005.         blockedNodes = [];
  2006.    
  2007.     startNode.g = 0;
  2008.     startNode.h = getHValue( startNode, destNode );
  2009.     startNode.f = startNode.g + startNode.h;
  2010.    
  2011.     addToClosedList( startNode );
  2012.  
  2013.     curNode = startNode;
  2014.     for ( ;; )
  2015.     {
  2016.         foreach ( linkId, checkNode in curNode.links )
  2017.         {
  2018.             if ( is_in_array( blockedNodes, checkNode ) )
  2019.                 continue;
  2020.                
  2021.             if ( is_in_array( level.closedList, checkNode ) )
  2022.                 continue;
  2023.                
  2024.             if ( isDefined( direction ) && checkNode.linkDirs[curNode.graphId] != direction )
  2025.                 continue;
  2026.                
  2027.             if ( !is_in_array( level.openList, checkNode ) )
  2028.             {
  2029.                 addToOpenList( checkNode );
  2030.                
  2031.                 checkNode.parentNode = curNode;
  2032.                 checkNode.g = getGValue( checkNode, curNode );
  2033.                 checkNode.h = getHValue( checkNode, destNode );
  2034.                 checkNode.f = checkNode.g + checkNode.h;
  2035.                
  2036.                 if ( checkNode == destNode )
  2037.                     foundPath = true;  
  2038.             }
  2039.             else
  2040.             {
  2041.                 if ( checkNode.g < getGValue( curNode, checkNode ) )
  2042.                     continue;
  2043.                    
  2044.                 checkNode.parentNode = curNode;
  2045.                 checkNode.g = getGValue( checkNode, curNode );
  2046.                 checkNode.f = checkNode.g + checkNode.h;
  2047.             }
  2048.         }
  2049.        
  2050.         if ( foundPath )
  2051.             break;
  2052.            
  2053.         addToClosedList( curNode );
  2054.        
  2055.         bestNode = level.openList[0];
  2056.  
  2057.         foreach ( testNode in level.openList )
  2058.         {
  2059.             if ( testNode.f > bestNode.f )
  2060.                 continue;
  2061.                
  2062.             bestNode = testNode;
  2063.         }
  2064.        
  2065.         assert( isDefined( bestNode ) ); // the tank should always have a path
  2066.  
  2067.         addToClosedList( bestNode );
  2068.         curNode = bestNode;
  2069.     }
  2070.  
  2071.     assert( isDefined( destNode.parentNode ) );
  2072.    
  2073.     curNode = destNode;
  2074.     while (curNode != startNode)
  2075.     {
  2076.         pathNodes[pathNodes.size] = curNode;
  2077.         curNode = curNode.parentNode;
  2078.     }
  2079.     pathNodes[pathNodes.size] = curNode;
  2080.    
  2081.     return pathNodes;  
  2082. }
  2083.  
  2084.  
  2085. addToOpenList( node )
  2086. {
  2087.     node.openListID = level.openList.size;
  2088.     level.openList[level.openList.size] = node;
  2089.     node.closedListID = undefined;
  2090. }
  2091.  
  2092.  
  2093. addToClosedList( node )
  2094. {
  2095.     if (isdefined (node.closedListID))
  2096.         return;
  2097.    
  2098.     node.closedListID = level.closedList.size;
  2099.     level.closedList[level.closedList.size] = node;
  2100.    
  2101.     if (!is_in_array (level.openList, node))
  2102.         return;
  2103.        
  2104.     level.openList[node.openListID] = level.openList[level.openList.size - 1];
  2105.     level.openList[node.openListID].openListID = node.openListID;
  2106.     level.openList[level.openList.size - 1] = undefined;
  2107.     node.openListID = undefined;
  2108. }
  2109.  
  2110.  
  2111. getHValue (node1, node2)
  2112. {
  2113.     return (distance (node1.node.origin, node2.node.origin));
  2114. }
  2115.  
  2116.  
  2117. getGValue(node1, node2)
  2118. {
  2119.     return ( node1.parentNode.g + node1.linkLengths[node2.graphId] );
  2120. }
  2121.  
  2122.  
  2123. is_in_array( aeCollection, eFindee )
  2124. {
  2125.     for ( i = 0; i < aeCollection.size; i++ )
  2126.     {
  2127.         if ( aeCollection[ i ] == eFindee )
  2128.             return( true );
  2129.     }
  2130.  
  2131.     return( false );
  2132. }
  2133.  
  2134.  
  2135. drawPath( pathNodes )
  2136. {
  2137.     for ( i = 1; i < pathNodes.size; i++ )
  2138.     {
  2139.         startNode = pathNodes[i-1];
  2140.         endNode = pathNodes[i];
  2141.        
  2142.         if ( startNode.linkDirs[endNode.graphId] == "reverse" )
  2143.             level thread drawLink( startNode.node.origin, endNode.node.origin, (1,0,0) );
  2144.         else
  2145.             level thread drawLink( startNode.node.origin, endNode.node.origin, (0,1,0) );
  2146.            
  2147.         vehNode = startNode.linkStartNodes[endNode.graphId];
  2148.         level thread drawLink( startNode.node.origin + (0,0,4), vehNode.origin + (0,0,4), (0,0,1) );
  2149.        
  2150.         if ( startNode.linkDirs[endNode.graphId] == "reverse" )
  2151.         {
  2152.             while ( !isDefined( vehNode.graphId ) )
  2153.             {
  2154.                 lastVehNode = vehNode;
  2155.                 vehNode = vehNode.prev;
  2156.                 level thread drawLink( lastVehNode.origin + (0,0,4), vehNode.origin + (0,0,4), (0,1,1) );
  2157.             }
  2158.         }
  2159.         else
  2160.         {
  2161.             while ( !isDefined( vehNode.graphId ) )
  2162.             {
  2163.                 lastVehNode = vehNode;
  2164.                
  2165.                 if ( isDefined( vehNode.target ) )
  2166.                     vehNode = GetVehicleNode( vehNode.target, "targetname" );              
  2167.                 else
  2168.                     vehNode = vehNode.next;
  2169.  
  2170.                 level thread drawLink( lastVehNode.origin + (0,0,4), vehNode.origin + (0,0,4), (0,1,1) );
  2171.             }          
  2172.         }
  2173.     }
  2174. }
  2175.  
  2176.  
  2177. drawGraph( pathNodes )
  2178. {
  2179.     /*
  2180.     level.pathZOffset = 0;
  2181.     foreach ( node in pathNodes )
  2182.     {
  2183.         println( node.links.size );
  2184.         foreach ( linkId, graphNode in node.links )
  2185.         {
  2186.             if ( node.linkDirs[linkId] == "reverse" )
  2187.                 level thread drawLink( node.node.origin, graphNode.node.origin, (0,1,0) );
  2188.             else
  2189.                 level thread drawLink( node.node.origin, graphNode.node.origin, (1,0,0) );
  2190.  
  2191.             //if ( node.linkDirs[linkId] == "reverse" )
  2192.             //  continue;
  2193.                
  2194.             //level thread drawLink( pathNodes[graphId].node.origin, pathNodes[node.graphId].node.origin, (randomFloat( 2 ), randomFloat( 2 ), randomFloat( 2 )) );    
  2195.         }
  2196.     }
  2197.     */
  2198. }
  2199.  
  2200.  
  2201. drawLink( start, end, color )
  2202. {
  2203.     level endon ( "endpath" );
  2204.     for ( ;; )
  2205.     {
  2206.         line(start, end, color, true);
  2207.         wait 0.05;
  2208.     }
  2209. }
  2210.  
  2211. debugPrintLn2( printString )
  2212. {
  2213.     /#
  2214.     if ( getDvarInt( "tankDebug" ) )
  2215.         printLn( printString );
  2216.     #/
  2217. }
  2218.  
  2219. debugPrint( printString )
  2220. {
  2221.     /#
  2222.     if ( getDvarInt( "tankDebug" ) )
  2223.         print( printString );
  2224.     #/
  2225. }
  2226.  
  2227.  
  2228. debugPrint3D( origin, printString, color, alpha, scale, duration )
  2229. {
  2230.     /#
  2231.     if ( getDvarInt( "tankDebug" ) )
  2232.     {
  2233.         print3d( origin, printString, color, alpha, scale, duration );
  2234.         println( "3D: " + printString );
  2235.     }
  2236.     #/
  2237. }
  2238.  
  2239.  
  2240. drawTankGraphIds()
  2241. {
  2242.     /#
  2243.     if ( getDvarInt( "tankDebug" ) )
  2244.     {
  2245.         self notify ( "drawTankGraphIds" );
  2246.         self endon ( "drawTankGraphIds" );
  2247.        
  2248.         for ( ;; )
  2249.         {
  2250.             print3d( self.origin + (0,0,128), "FW: " + self.forwardGraphId + " RV: " + self.reverseGraphId, (0,1,0), 1, 3, 1 );
  2251.             wait ( 0.05 );
  2252.         }
  2253.     }
  2254.     #/
  2255. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement