Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #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( "3D: " + printString );
- }
- #/
- }
- drawTankGraphIds()
- {
- /#
- if ( getDvarInt( "tankDebug" ) )
- {
- self notify ( "drawTankGraphIds" );
- self endon ( "drawTankGraphIds" );
- for ( ;; )
- {
- print3d( self.origin + (0,0,128), "FW: " + self.forwardGraphId + " RV: " + self.reverseGraphId, (0,1,0), 1, 3, 1 );
- wait ( 0.05 );
- }
- }
- #/
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement