1 #using scripts\codescripts\struct;
3 #using scripts\shared\challenges_shared;
4 #using scripts\shared\damagefeedback_shared;
5 #using scripts\shared\math_shared;
6 #using scripts\shared\util_shared;
7 #using scripts\shared\weapons\_weaponobjects;
8 #using scripts\shared\weapons\_weapons;
10 #insert scripts\shared\shared.gsh;
12 #using scripts\mp\_util;
14 #namespace airsupport;
20 if ( !isdefined( level.airsupportHeightScale ) )
21 level.airsupportHeightScale = 1;
23 level.airsupportHeightScale = GetDvarInt(
"scr_airsupportHeightScale", level.airsupportHeightScale );
25 level.noFlyZones = [];
26 level.noFlyZones = GetEntArray(
"no_fly_zone",
"targetname");
31 if ( airsupport_heights.size > 1 )
33 util::error(
"Found more then one 'air_support_height' structs in the map" );
37 airsupport_heights = GetEntArray(
"air_support_height",
"targetname");
40 if ( airsupport_heights.size > 0 )
42 util::error(
"Found an entity in the map with an 'air_support_height' targetname. There should be only structs." );
46 heli_height_meshes = GetEntArray(
"heli_height_lock",
"classname");
49 if ( heli_height_meshes.size > 1 )
51 util::error(
"Found more then one 'heli_height_lock' classname in the map" );
60 self notify(
"used" );
63 if( isdefined( usedCallback ) )
65 return self [[usedCallback]]( location );
73 self notify(
"used" );
75 return self [[usedCallback]]( locationStart, locationEnd );
80 self endon(
"death" );
81 self endon(
"disconnect" );
82 self endon(
"cancel_location" );
84 self endon(
"host_migration_begin" );
86 level waittill(
"game_ended" );
87 self notify(
"game_ended" );
92 self endon(
"death" );
93 self endon(
"disconnect" );
94 self endon(
"cancel_location" );
96 self endon(
"game_ended" );
98 level waittill(
"host_migration_begin" );
99 self notify(
"cancel_location" );
104 assert( IsPlayer(
self ) );
105 assert( IsAlive(
self ) );
106 assert( isdefined(
self.selectingLocation ) );
107 assert(
self.selectingLocation ==
true );
112 event =
self util::waittill_any_return(
"death",
"disconnect",
"cancel_location",
"game_ended",
"used",
"weapon_change",
"emp_jammed" );
114 if ( event !=
"disconnect" )
116 self.selectingLocation = undefined;
120 if ( event !=
"used" )
123 self notify(
"confirm_location", undefined, undefined );
129 event =
self util::waittill_any_return(
"death",
"disconnect",
"game_ended",
"used",
"weapon_change",
"emp_jammed",
"weapon_change_complete" );
131 if ( event !=
"disconnect" )
133 self endLocationSelection();
139 self endon (
"death" );
142 self stoploopsound( 2 );
148 gravity = GetDvarint(
"bg_gravity" );
150 time = sqrt( (2 * flyHeight) / gravity );
161 bomb_x = (flySpeed * bombSpeedScale) * falltime;
162 release_time = bomb_x / flySpeed;
164 return ( (flyTime * 0.5) - release_time);
169 airsupport_height =
struct::get(
"air_support_height",
"targetname");
170 if ( isdefined(airsupport_height) )
172 planeFlyHeight = airsupport_height.origin[2];
177 PrintLn(
"WARNING: Missing air_support_height entity in the map. Using default height.");
180 planeFlyHeight = 850;
182 if ( isdefined( level.airsupportHeightScale ) )
184 level.airsupportHeightScale = GetDvarInt(
"scr_airsupportHeightScale", level.airsupportHeightScale );
185 planeFlyHeight *= GetDvarInt(
"scr_airsupportHeightScale", level.airsupportHeightScale );
188 if ( isdefined( level.forceAirsupportMapHeight ) )
190 planeFlyHeight += level.forceAirsupportMapHeight;
194 return planeFlyHeight;
199 level.bomberDamagedEnts = [];
200 level.bomberDamagedEntsCount = 0;
201 level.bomberDamagedEntsIndex = 0;
203 assert( flightPlan.distance != 0,
"callStrike can not be passed a zero fly distance");
205 planeHalfDistance = flightPlan.distance / 2;
207 path =
getStrikePath( flightPlan.target, flightPlan.height, planeHalfDistance );
208 startPoint = path[
"start"];
209 endPoint = path[
"end"];
210 flightPlan.height = path[
"height"];
211 direction = path[
"direction"];
214 d = length( startPoint - endPoint );
215 flyTime = ( d / flightPlan.speed );
217 bombTime =
calculateReleaseTime( flyTime, flightPlan.height, flightPlan.speed, flightPlan.bombSpeedScale);
224 assert( flyTime > bombTime );
226 flightPlan.owner endon(
"disconnect");
228 requiredDeathCount = flightPlan.owner.deathCount;
230 side = VectorCross( anglestoforward( direction ), (0,0,1) );
231 plane_seperation = 25;
232 side_offset = VectorScale( side, plane_seperation );
234 level thread
planeStrike( flightPlan.owner, requiredDeathCount, startPoint, endPoint, bombTime, flyTime, flightPlan.speed, flightPlan.bombSpeedScale, direction, flightPlan.planeSpawnCallback );
235 wait( flightPlan.planeSpacing );
236 level thread
planeStrike( flightPlan.owner, requiredDeathCount, startPoint+side_offset, endPoint+side_offset, bombTime, flyTime, flightPlan.speed, flightPlan.bombSpeedScale, direction, flightPlan.planeSpawnCallback );
237 wait( flightPlan.planeSpacing );
239 side_offset = VectorScale( side, -1 * plane_seperation );
241 level thread
planeStrike( flightPlan.owner, requiredDeathCount, startPoint+side_offset, endPoint+side_offset, bombTime, flyTime, flightPlan.speed, flightPlan.bombSpeedScale, direction, flightPlan.planeSpawnCallback );
245 function planeStrike( owner, requiredDeathCount, pathStart, pathEnd, bombTime, flyTime, flyspeed, bombSpeedScale, direction, planeSpawnedFunction )
250 if ( !isdefined( owner ) )
258 plane = spawnplane( owner,
"script_model", pathStart );
259 plane.angles = direction;
261 plane moveTo( pathEnd, flyTime, 0, 0 );
265 if ( isdefined(planeSpawnedFunction) )
267 plane [[planeSpawnedFunction]]( owner, requiredDeathCount, pathStart, pathEnd, bombTime, bombSpeedScale, flyTime, flyspeed );
272 plane notify(
"delete" );
281 ground = (position[0], position[1], player.origin[2]);
283 trace = bullettrace(ground + (0,0,10000), ground,
false, undefined );
284 return trace[
"position"];
296 return level.spawnMins[2] - 500;
301 return level.spawnMaxs[2] + 500;
309 if ( target[2] < min )
312 if ( target[2] > max )
327 if ( isdefined( height ) )
329 if ( point[2] > base[2] + height )
333 dist = Distance2D( point, base );
343 height = level.noFlyZones[index].height;
345 if ( isdefined(disregardHeight ) )
348 return _insideCylinder( point, level.noFLyZones[index].origin, level.noFlyZones[index].radius, height );
357 for ( i = 0; i < level.noFlyZones.size; i++ )
361 if ( height < level.noFlyZones[i].height )
363 height = level.noFlyZones[i].height;
364 origin = level.noFlyZones[i].origin;
369 if ( !isdefined( origin ) )
372 return origin[2] + height;
379 for ( i = 0; i < level.noFlyZones.size; i++ )
383 noFlyZones[noFlyZones.size] = i;
393 for ( i = 0; i < level.noFlyZones.size; i++ )
396 dist = Distance2D( point, level.noFlyZones[i].origin );
398 if ( point[2] > ( level.noFlyZones[i].origin[2] + level.noFlyZones[i].height ) )
401 if ( dist < level.noFlyZones[i].radius )
413 for ( i = 0; i < level.noFlyZones.size; i++ )
416 dist = Distance2D( point, level.noFlyZones[i].origin );
418 if ( point[2] > ( level.noFlyZones[i].origin[2] + level.noFlyZones[i].height ) )
421 if ( dist < level.noFlyZones[i].radius )
423 zones[zones.size] = i;
433 for ( i = 0; i < level.noFlyZones.size; i++ )
436 dist = Distance2D( point, level.noFlyZones[i].origin );
438 if ( dist < level.noFlyZones[i].radius )
440 if ( height < level.noFlyZones[i].height )
441 height = level.noFlyZones[i].height;
450 if ( !isdefined( noFlyZone ) )
453 for ( i = 0; i < noFlyZones.size; i ++ )
455 if ( isdefined( noFlyZones[i] ) && noFlyZones[i] == noFlyZone )
464 if ( !isdefined( noFlyZone ) )
486 if ( goalNoFlyZones.size )
491 goal_points =
calculatePath(start, goal, startNoFlyZones, goalNoFlyZones );
493 if ( !isdefined( goal_points ) )
496 Assert(goal_points.size >= 1 );
503 for ( i = 0; i < (path.size - 1); i++ )
505 self SetVehGoalPos( path[i],
false );
507 thread
debug_line(
self.origin, path[i], (1,1,0) );
508 self waittill(
"goal" );
511 self SetVehGoalPos( path[path.size - 1], stopAtGoal );
512 thread
debug_line(
self.origin, path[i], (1,1,0) );
514 self waittill(
"goal" );
516 if ( isdefined( doneNotify ) )
518 self notify(doneNotify);
524 if ( !isdefined( stopAtGoal ) )
534 if ( !isdefined(goal_points) )
537 goal_points[0] = goal;
540 followPath( goal_points, doneNotify, stopAtGoal );
547 for ( i = 0 ; i < noFlyZones.size; i++ )
560 for ( i= 0; i < src.size; i++ )
562 dst[ dst.size ]= src[ i ];
572 points[points.size] =
end;
578 for ( i = 0; i < noFlyZones.size; i++ )
580 noFlyZone = noFlyZones[i];
590 points[points.size] =
end;
604 if ( !isdefined(points) )
607 Assert( points.size >= 1 );
610 debug_sphere( points[points.size - 1], 10, (1,0,0), 1, 1000 );
615 for ( i = 0 ; i < points.size; i++ )
626 direction = (0,yaw,0);
628 startPoint = goal + VectorScale( anglestoforward( direction ), -1 * halfDistance );
629 endPoint = goal + VectorScale( anglestoforward( direction ), halfDistance );
635 if ( isdefined( noFlyZone ) )
637 path[
"noFlyZone"] = noFlyZone;
639 startPoint = ( startPoint[0], startPoint[1], level.noFlyZones[noFlyZone].origin[2] + level.noFlyZones[noFlyZone].height );
640 endPoint = ( endPoint[0], endPoint[1], startPoint[2] );
644 path[
"noFlyZone"] = undefined;
647 path[
"start"] = startPoint;
648 path[
"end"] = endPoint;
649 path[
"direction"] = direction;
658 worldHeight = target[2] + height;
660 if ( noFlyZoneHeight > worldHeight )
662 worldHeight = noFlyZoneHeight;
665 goal = ( target[0], target[1], worldHeight );
669 if ( !isdefined( yaw ) || yaw !=
"random" )
672 for ( i = 0; i < 3; i++ )
676 if ( !isdefined( path[
"noFlyZone"] ) )
687 path[
"height"] = worldHeight - target[2];
693 wait(RandomFloatRange(0.05, 0.15));
694 glassRadiusDamage( pos, radius, max, min, mod );
699 dist = distance(pos, ent.damageCenter);
701 if ( ent.isPlayer || ent.isActor )
703 assumed_ceiling_height = 800;
704 eye_position = ent.entity GetEye();
705 head_height = eye_position[2];
706 debug_display_time = 40 * 100;
710 indoors = (
trace[
"fraction"] != 1);
718 test_point =
trace[
"position"];
719 debug_star(test_point, (0,1,0), debug_display_time);
722 indoors = (
trace[
"fraction"] != 1);
726 debug_star((pos[0],pos[1], head_height), (0,1,0), debug_display_time);
734 debug_star((pos[0],pos[1], head_height), (1,0,0), debug_display_time);
736 indoors = (
trace[
"fraction"] != 1);
753 debug_star(ent.entity.origin + (0,0,assumed_ceiling_height), (1,0,0), debug_display_time );
757 ent.damage = int(max + (min-max)*dist/radius);
759 ent.damageOwner = owner;
760 ent.eInflictor = eInflictor;
768 minimapOrigins = getEntArray(
"minimap_corner",
"targetname" );
769 if( miniMapOrigins.size )
779 minimapOrigins = getEntArray(
"minimap_corner",
"targetname" );
780 if( miniMapOrigins.size )
785 if( miniMapOrigins[0].origin[0] < miniMapOrigins[1].origin[0] )
787 rand_x = RandomFloatRange( miniMapOrigins[0].origin[0] * map_x_percentage, miniMapOrigins[1].origin[0] * map_x_percentage );
788 rand_y = RandomFloatRange( miniMapOrigins[0].origin[1] * map_y_percentage, miniMapOrigins[1].origin[1] * map_y_percentage );
792 rand_x = RandomFloatRange( miniMapOrigins[1].origin[0] * map_x_percentage, miniMapOrigins[0].origin[0] * map_x_percentage );
793 rand_y = RandomFloatRange( miniMapOrigins[1].origin[1] * map_y_percentage, miniMapOrigins[0].origin[1] * map_y_percentage );
796 return ( x_offset + rand_x, y_offset + rand_y, 0 );
799 return ( x_offset, y_offset, 0 );
804 minimapOrigins = getEntArray(
"minimap_corner",
"targetname" );
805 if( miniMapOrigins.size )
807 x = abs( miniMapOrigins[0].origin[0] - miniMapOrigins[1].origin[0] );
808 y = abs( miniMapOrigins[0].origin[1] - miniMapOrigins[1].origin[1] );
818 level.airsupport_rotator =
spawn(
"script_model",
GetMapCenter() + (
VAL( level.rotator_x_offset, 0 ),
VAL( level.rotator_y_offset, 0 ), 1200 ) );
819 level.airsupport_rotator setModel(
"tag_origin" );
820 level.airsupport_rotator.angles = ( 0, 115, 0 );
821 level.airsupport_rotator hide();
823 level.airsupport_rotator thread
SwayRig();
830 self rotateyaw( -360, 60 );
837 centerOrigin =
self.origin;
841 z = randomIntRange( -200, -100 );
843 time = randomIntRange( 3, 6 );
844 self moveto( centerOrigin + (0,0,z), time, 1, 1 );
847 z = randomIntRange( 100, 200 );
849 time = randomIntRange( 3, 6 );
850 self moveto( centerOrigin + (0,0,z), time, 1, 1 );
857 self endon(
"death" );
859 self StopLoopSound();
864 self endon(
"death" );
867 if (
self.angles[1] > goal )
871 while( abs(
self.angles[1] - goal ) > 3 )
873 self.angles = (
self.angles[0],
self.angles[1] +
increment,
self.angles[2] );
880 self endon(
"death" );
882 while (
self.angles[2] < 0)
884 self.angles = (
self.angles[0],
self.angles[1],
self.angles[2] + 2.5 );
899 exitVector = ( anglestoforward(
self.angles + ( 0, yaw, 0 ) ) * 20000 );
900 exitPoint = (
self.origin[0] + exitVector[0],
self.origin[1] + exitVector[1],
self.origin[2] - 2500);
901 exitPoint =
self.origin + exitVector;
927 if (
self.angles[2] != 0)
932 if ( IsVehicle(
self ) )
935 self SetVehGoalPos( exitPoint,
false,
false );
939 self moveto( exitPoint, duration, 0, 0 );
941 self notify (
"leaving");
947 dist = -1 * GetDvarInt(
"scr_supplydropIncomingDistance", 10000 );
948 pathRandomness = 100;
949 direction = ( 0, RandomIntRange( -2, 3 ), 0 );
951 start_origin = ( AnglesToForward( direction ) * dist );
952 start_origin += ( ( randomfloat( 2 ) - 1 ) * pathRandomness, ( randomfloat( 2 ) - 1 ) * pathRandomness, 0 );
955 if ( GetDvarInt(
"scr_noflyzones_debug", 0 ) )
957 if ( level.noFlyZones.size )
959 index = RandomIntRange( 0, level.noFlyZones.size );
960 delta = level.noFlyZones[ index ].origin;
961 delta = ( delta[0] + RandomInt( 10 ), delta[ 1 ] + RandomInt( 10 ), 0 );
962 delta = VectorNormalize( delta );
963 start_origin = ( delta * dist );
977 for ( i = 0; i < level.noFlyZones.size; i++ )
979 debug_airsupport_cylinder( level.noFlyZones[i].origin, level.noFlyZones[i].radius, level.noFlyZones[i].height, (1,1,1), undefined, 5000 );
988 delta = VectorNormalize(pathEnd - pathStart);
990 for ( i = 0; i < flyTime; i++ )
992 thread
debug_star( pathStart + VectorScale(delta, i * flyspeed), (1,0,0) );
998 self notify(
"draw_explosion");
1000 self endon(
"draw_explosion");
1002 self waittill(
"projectile_impact", weapon, position );
1004 thread
debug_line( prevpos, position, (.5,1,0) );
1011 self endon(
"death");
1012 level.airsupport_debug = GetDvarInt(
"scr_airsupport_debug", 0 );
1014 if ( !isdefined( color ) )
1019 if ( isdefined( level.airsupport_debug ) && level.airsupport_debug == 1.0 )
1021 prevpos =
self.origin;
1022 while(isdefined (
self.origin ) )
1024 thread
debug_line( prevpos,
self.origin, color, time );
1025 prevpos =
self.origin;
1027 if ( isdefined(projectile) && projectile )
1041 level.airsupport_debug = GetDvarInt(
"scr_airsupport_debug", 0 );
1043 if ( isdefined( level.airsupport_debug ) && level.airsupport_debug == 1.0 )
1045 if( isdefined( frames ) )
1046 thread
draw_text( message, ( 0.8, 0.8, 0.8 ), ent, offset, frames );
1048 thread
draw_text( message, ( 0.8, 0.8, 0.8 ), ent, offset, 0 );
1058 while ( isdefined( ent ) && isdefined( ent.origin ) )
1060 print3d( ent.origin+offset, msg , color, 0.5, 4 );
1066 for( i=0; i < frames; i++ )
1068 if( !isdefined( ent ) )
1070 print3d( ent.origin+offset, msg , color, 0.5, 4 );
1081 level.airsupport_debug = GetDvarInt(
"scr_airsupport_debug", 0 );
1083 if ( isdefined( level.airsupport_debug ) && level.airsupport_debug == 1.0 )
1084 self thread
draw_text( message, color, ent, origin_offset, frames );
1092 level.airsupport_debug = GetDvarInt(
"scr_airsupport_debug", 0 );
1094 if ( isdefined( level.airsupport_debug ) && level.airsupport_debug == 1.0 )
1096 if ( DistanceSquared( from, to ) < 0.01 )
1099 if ( !isdefined(time) )
1103 if ( !isdefined(depthTest) )
1107 Line( from, to, color, 1, depthTest, time);
1116 level.airsupport_debug = GetDvarInt(
"scr_airsupport_debug", 0 );
1118 if ( isdefined( level.airsupport_debug ) && level.airsupport_debug == 1.0 )
1120 if ( !isdefined(time) )
1124 if ( !isdefined(color) )
1128 debugstar( origin, time, color );
1136 level.airsupport_debug = GetDvarInt(
"scr_airsupport_debug", 0 );
1138 if ( isdefined( level.airsupport_debug ) && level.airsupport_debug == 1 )
1140 if ( !isdefined(time) )
1144 if ( !isdefined(color) )
1148 circle( origin, radius, color,
true,
true, time );
1156 level.airsupport_debug = GetDvarInt(
"scr_airsupport_debug", 0 );
1158 if ( isdefined( level.airsupport_debug ) && level.airsupport_debug == 1 )
1160 if ( !isdefined(time) )
1164 if ( !isdefined(color) )
1169 sides = Int(10 * ( 1 + Int(radius / 100) ));
1170 sphere( origin, radius, color, alpha,
true, sides, time );
1178 level.airsupport_debug = GetDvarInt(
"scr_airsupport_debug", 0 );
1180 if ( isdefined( level.airsupport_debug ) && level.airsupport_debug == 1 )
1182 debug_cylinder( origin, radius, height, color, mustRenderHeight, time );
1194 if ( !isdefined(time) )
1198 if ( !isdefined(color) )
1203 count = (height/subdivision);
1205 for ( i = 0; i < count; i++ )
1207 point = origin + ( 0, 0, i * subdivision );
1208 circle( point, radius, color,
true,
true, time );
1211 if( isdefined( mustRenderHeight ) )
1213 point = origin + ( 0, 0, mustRenderHeight );
1214 circle( point, radius, color,
true,
true, time );
1221 nextPoint = ( startPoint[0] + ( ( endPoint[0] - startPoint[0] ) * ratio ) ,
1222 startPoint[1] + ( ( endPoint[1] - startPoint[1] ) * ratio ) ,
1223 startPoint[2] + ( ( endPoint[2] - startPoint[2] ) * ratio ) );
1230 if (
self HasPerk(
"specialty_nottargetedbyairsupport" ) ||
1231 ( isdefined(
self.specialty_nottargetedbyairsupport ) &&
self.specialty_nottargetedbyairsupport ) )
1233 if ( !isdefined(
self.notTargettedAI_underMinSpeedTimer ) ||
self.notTargettedAI_underMinSpeedTimer < GetDvarInt(
"perk_nottargetedbyai_graceperiod" ) )
1242 self endon(
"death" );
1243 self endon(
"disconnect" );
1245 if (
self HasPerk(
"specialty_nottargetedbyairsupport" ) ==
false )
1250 GetDvarString(
"perk_nottargetted_graceperiod" );
1251 gracePeriod = GetDvarInt(
"perk_nottargetedbyai_graceperiod" );
1252 minspeed = GetDvarInt(
"perk_nottargetedbyai_min_speed" );
1253 minspeedSq = minspeed * minspeed;
1255 waitPeriodMilliseconds = waitPeriod * 1000;
1256 if ( minspeedSq == 0 )
1259 self.notTargettedAI_underMinSpeedTimer = 0;
1261 if ( isdefined ( spawnProtectionTime ) )
1263 wait( spawnProtectionTime );
1268 velocity =
self GetVelocity();
1270 speedsq = lengthsquared( velocity );
1272 if ( speedSq < minspeedSq )
1274 self.notTargettedAI_underMinSpeedTimer += waitPeriodMilliseconds;
1278 self.notTargettedAI_underMinSpeedTimer = 0;
1287 if ( isdefined (
self.notTargettedAI_underMinSpeedTimer ) )
1288 self.notTargettedAI_underMinSpeedTimer = 0;