init
This commit is contained in:
22
maps/animated_models/com_roofvent2.gsc
Normal file
22
maps/animated_models/com_roofvent2.gsc
Normal file
@ -0,0 +1,22 @@
|
||||
#include common_scripts\utility;
|
||||
|
||||
#using_animtree( "animated_props" );
|
||||
main()
|
||||
{
|
||||
if( !isdefined ( level.anim_prop_models ) )
|
||||
level.anim_prop_models = [];
|
||||
|
||||
// Would use isSP() but this runs before we can
|
||||
mapname = tolower( getdvar( "mapname" ) );
|
||||
SP = true;
|
||||
if ( string_starts_with( mapname, "mp_" ) )
|
||||
SP = false;
|
||||
|
||||
model = "com_roofvent2_animated";
|
||||
if ( SP )
|
||||
{
|
||||
level.anim_prop_models[ model ][ "rotate" ] = %roofvent_rotate;
|
||||
}
|
||||
else
|
||||
level.anim_prop_models[ model ][ "rotate" ] = "roofvent_rotate";
|
||||
}
|
16
maps/animated_models/foliage_pacific_bushtree01.gsc
Normal file
16
maps/animated_models/foliage_pacific_bushtree01.gsc
Normal file
@ -0,0 +1,16 @@
|
||||
#include common_scripts\utility;
|
||||
|
||||
#using_animtree( "animated_props" );
|
||||
main()
|
||||
{
|
||||
if( !isdefined ( level.anim_prop_models ) )
|
||||
level.anim_prop_models = [];
|
||||
|
||||
model = "foliage_pacific_bushtree01_animated";
|
||||
if ( isSp() )
|
||||
{
|
||||
level.anim_prop_models[ model ][ "sway" ] = %foliage_pacific_bushtree01_sway;
|
||||
}
|
||||
else
|
||||
level.anim_prop_models[ model ][ "sway" ] = "foliage_pacific_bushtree01_sway";
|
||||
}
|
14
maps/animated_models/hanging_apron_wind_medium.gsc
Normal file
14
maps/animated_models/hanging_apron_wind_medium.gsc
Normal file
@ -0,0 +1,14 @@
|
||||
#include common_scripts\utility;
|
||||
|
||||
#using_animtree( "animated_props" );
|
||||
main()
|
||||
{
|
||||
if( !isdefined ( level.anim_prop_models ) )
|
||||
level.anim_prop_models = [];
|
||||
|
||||
model = "clothes_line_tank_iw6";
|
||||
if ( isSP() )
|
||||
level.anim_prop_models[ model ][ "wind_medium" ] = %hanging_clothes_apron_wind_medium;
|
||||
else
|
||||
level.anim_prop_models[ model ][ "wind_medium" ] = "hanging_clothes_apron_wind_medium";
|
||||
}
|
14
maps/animated_models/hanging_longsleeve_wind_medium.gsc
Normal file
14
maps/animated_models/hanging_longsleeve_wind_medium.gsc
Normal file
@ -0,0 +1,14 @@
|
||||
#include common_scripts\utility;
|
||||
|
||||
#using_animtree( "animated_props" );
|
||||
main()
|
||||
{
|
||||
if( !isdefined ( level.anim_prop_models ) )
|
||||
level.anim_prop_models = [];
|
||||
|
||||
model = "clothes_line_sweater_iw6";
|
||||
if ( isSP() )
|
||||
level.anim_prop_models[ model ][ "wind_medium" ] = %hanging_clothes_long_sleeve_wind_medium;
|
||||
else
|
||||
level.anim_prop_models[ model ][ "wind_medium" ] = "hanging_clothes_long_sleeve_wind_medium";
|
||||
}
|
14
maps/animated_models/hanging_sheet_wind_medium.gsc
Normal file
14
maps/animated_models/hanging_sheet_wind_medium.gsc
Normal file
@ -0,0 +1,14 @@
|
||||
#include common_scripts\utility;
|
||||
|
||||
#using_animtree( "animated_props" );
|
||||
main()
|
||||
{
|
||||
if( !isdefined ( level.anim_prop_models ) )
|
||||
level.anim_prop_models = [];
|
||||
|
||||
model = "clothes_line_sheet_iw6";
|
||||
if ( isSP() )
|
||||
level.anim_prop_models[ model ][ "wind_medium" ] = %hanging_clothes_sheet_wind_medium;
|
||||
else
|
||||
level.anim_prop_models[ model ][ "wind_medium" ] = "hanging_clothes_sheet_wind_medium";
|
||||
}
|
14
maps/animated_models/hanging_shortsleeve_wind_medium.gsc
Normal file
14
maps/animated_models/hanging_shortsleeve_wind_medium.gsc
Normal file
@ -0,0 +1,14 @@
|
||||
#include common_scripts\utility;
|
||||
|
||||
#using_animtree( "animated_props" );
|
||||
main()
|
||||
{
|
||||
if( !isdefined ( level.anim_prop_models ) )
|
||||
level.anim_prop_models = [];
|
||||
|
||||
model = "clothes_line_tshirt_iw6";
|
||||
if ( isSP() )
|
||||
level.anim_prop_models[ model ][ "wind_medium" ] = %hanging_clothes_short_sleeve_wind_medium;
|
||||
else
|
||||
level.anim_prop_models[ model ][ "wind_medium" ] = "hanging_clothes_short_sleeve_wind_medium";
|
||||
}
|
22
maps/animated_models/mp_flooded_water_debris_bob.gsc
Normal file
22
maps/animated_models/mp_flooded_water_debris_bob.gsc
Normal file
@ -0,0 +1,22 @@
|
||||
#include common_scripts\utility;
|
||||
|
||||
#using_animtree( "animated_props" );
|
||||
main()
|
||||
{
|
||||
if( !isdefined ( level.anim_prop_models ) )
|
||||
level.anim_prop_models = [];
|
||||
|
||||
// Would use isSP() but this runs before we can
|
||||
mapname = tolower( getdvar( "mapname" ) );
|
||||
SP = true;
|
||||
if ( string_starts_with( mapname, "mp_" ) )
|
||||
SP = false;
|
||||
|
||||
model = "debris_water_trash";
|
||||
if ( SP )
|
||||
{
|
||||
level.anim_prop_models[ model ][ "debris_water_trash" ] = %debris_water_trash_bob_anim;
|
||||
}
|
||||
else
|
||||
level.anim_prop_models[ model ][ "debris_water_trash" ] = "debris_water_trash_bob_anim";
|
||||
}
|
23
maps/animated_models/mp_flooded_water_debris_spiral.gsc
Normal file
23
maps/animated_models/mp_flooded_water_debris_spiral.gsc
Normal file
@ -0,0 +1,23 @@
|
||||
#include common_scripts\utility;
|
||||
|
||||
#using_animtree( "animated_props" );
|
||||
main()
|
||||
{
|
||||
if( !isdefined ( level.anim_prop_models ) )
|
||||
level.anim_prop_models = [];
|
||||
|
||||
// Would use isSP() but this runs before we can
|
||||
mapname = tolower( getdvar( "mapname" ) );
|
||||
SP = true;
|
||||
if ( string_starts_with( mapname, "mp_" ) )
|
||||
SP = false;
|
||||
|
||||
model = "debris_water_trash";
|
||||
if ( SP )
|
||||
{
|
||||
level.anim_prop_models[ model ][ "debris_water_trash" ] = %debris_water_trash_spiral_anim;
|
||||
}
|
||||
else
|
||||
level.anim_prop_models[ model ][ "debris_water_trash" ] = "debris_water_trash_spiral_anim";
|
||||
}
|
||||
|
23
maps/animated_models/mp_flooded_water_street.gsc
Normal file
23
maps/animated_models/mp_flooded_water_street.gsc
Normal file
@ -0,0 +1,23 @@
|
||||
#include common_scripts\utility;
|
||||
|
||||
#using_animtree( "animated_props" );
|
||||
main()
|
||||
{
|
||||
if( !isdefined ( level.anim_prop_models ) )
|
||||
level.anim_prop_models = [];
|
||||
|
||||
// Would use isSP() but this runs before we can
|
||||
mapname = tolower( getdvar( "mapname" ) );
|
||||
SP = true;
|
||||
if ( string_starts_with( mapname, "mp_" ) )
|
||||
SP = false;
|
||||
|
||||
model = "mp_flooded_street_water";
|
||||
if ( SP )
|
||||
{
|
||||
level.anim_prop_models[ model ][ "mp_flooded_street_water" ] = %mp_flooded_street_water_anim;
|
||||
}
|
||||
else
|
||||
level.anim_prop_models[ model ][ "mp_flooded_street_water" ] = "mp_flooded_street_water_anim";
|
||||
}
|
||||
|
16
maps/animated_models/mp_frag_crane.gsc
Normal file
16
maps/animated_models/mp_frag_crane.gsc
Normal file
@ -0,0 +1,16 @@
|
||||
#include common_scripts\utility;
|
||||
|
||||
#using_animtree( "animated_props" );
|
||||
main()
|
||||
{
|
||||
if( !isdefined ( level.anim_prop_models ) )
|
||||
level.anim_prop_models = [];
|
||||
|
||||
model = "mp_frag_crane_anim";
|
||||
if ( isSP() )
|
||||
{
|
||||
level.anim_prop_models[ model ][ "idle" ] = %mp_frag_crane_sway;
|
||||
}
|
||||
else
|
||||
level.anim_prop_models[ model ][ "idle" ] = "mp_frag_crane_sway";
|
||||
}
|
23
maps/animated_models/wire_hanging_192long.gsc
Normal file
23
maps/animated_models/wire_hanging_192long.gsc
Normal file
@ -0,0 +1,23 @@
|
||||
#include common_scripts\utility;
|
||||
|
||||
#using_animtree( "animated_props" );
|
||||
main()
|
||||
{
|
||||
if( !isdefined ( level.anim_prop_models ) )
|
||||
level.anim_prop_models = [];
|
||||
|
||||
// Would use isSP() but this runs before we can
|
||||
mapname = tolower( getdvar( "mapname" ) );
|
||||
SP = true;
|
||||
if ( string_starts_with( mapname, "mp_" ) )
|
||||
SP = false;
|
||||
|
||||
model = "prop_wire_hanging_192long";
|
||||
if ( SP )
|
||||
{
|
||||
level.anim_prop_models[ model ][ "self.wind" ] = %prop_wire_hanging_192long_wind1;
|
||||
}
|
||||
else
|
||||
level.anim_prop_models[ model ][ "self.wind" ] = "prop_wire_hanging_192long_wind1";
|
||||
}
|
||||
|
11
maps/createart/mp_alien_town_art.gsc
Normal file
11
maps/createart/mp_alien_town_art.gsc
Normal file
@ -0,0 +1,11 @@
|
||||
// _createart generated. modify at your own risk. Changing values should be fine.
|
||||
main()
|
||||
{
|
||||
level.tweakfile = true;
|
||||
level.parse_fog_func = maps\createart\mp_alien_town_fog::main;
|
||||
//* Fog section *
|
||||
setDevDvar( "scr_fog_disable", "0" );
|
||||
//setExpFog( 0, 5211.68, 0.627451, 0.717647, 0.745098, 0.38927, 0, 0.838639, 0.691254, 0.567937, (0.00390755, 0.00323934, -1), 83.5416, 92.7872, 2.25266 );
|
||||
//VisionSetNaked( "mp_alien_town", 0 );
|
||||
|
||||
}
|
10
maps/createart/mp_battery3_art.gsc
Normal file
10
maps/createart/mp_battery3_art.gsc
Normal file
@ -0,0 +1,10 @@
|
||||
// _createart generated. modify at your own risk. Changing values should be fine.
|
||||
main()
|
||||
{
|
||||
level.tweakfile = true;
|
||||
level.parse_fog_func = maps\createart\mp_battery3_fog::main;
|
||||
|
||||
setDevDvar( "scr_fog_disable", "0" );
|
||||
// setExpFog( 7346.26, 10487.6, 0.583682, 0.52939, 0.302793, 1, 1, 0, 0, 0, 0 );
|
||||
VisionSetNaked( "mp_battery3", 0 );
|
||||
}
|
10
maps/createart/mp_boneyard_ns_art.gsc
Normal file
10
maps/createart/mp_boneyard_ns_art.gsc
Normal file
@ -0,0 +1,10 @@
|
||||
// _createart generated. modify at your own risk. Changing values should be fine.
|
||||
main()
|
||||
{
|
||||
level.tweakfile = true;
|
||||
level.parse_fog_func = maps\createart\mp_boneyard_ns_fog::main;
|
||||
//* Fog section *
|
||||
|
||||
VisionSetNaked( "mp_boneyard_ns", 0 );
|
||||
|
||||
}
|
10
maps/createart/mp_ca_behemoth_art.gsc
Normal file
10
maps/createart/mp_ca_behemoth_art.gsc
Normal file
@ -0,0 +1,10 @@
|
||||
// _createart generated. modify at your own risk. Changing values should be fine.
|
||||
main()
|
||||
{
|
||||
level.tweakfile = true;
|
||||
level.parse_fog_func = maps\createart\mp_ca_behemoth_fog::main;
|
||||
|
||||
setDevDvar( "scr_fog_disable", "0" );
|
||||
// setExpFog( 0, 34658, 0.423529, 0.490196, 0.666667, 0.88, 0.776167, 0, 0.482353, 0.458824, 0.4, 2.3, (0, 0, -1), 0, 135, 10, 0.901, 180, 113 );
|
||||
VisionSetNaked( "mp_ca_behemoth", 0 );
|
||||
}
|
10
maps/createart/mp_ca_impact_art.gsc
Normal file
10
maps/createart/mp_ca_impact_art.gsc
Normal file
@ -0,0 +1,10 @@
|
||||
// _createart generated. modify at your own risk. Changing values should be fine.
|
||||
main()
|
||||
{
|
||||
level.tweakfile = true;
|
||||
level.parse_fog_func = maps\createart\mp_ca_impact_fog::main;
|
||||
|
||||
setDevDvar( "scr_fog_disable", "0" );
|
||||
// setExpFog( 3026.57, 1163.94, 0.711328, 0.78437, 0.798145, 0.793067, 0.811095, 0, 1, -0.538688, 90 );
|
||||
VisionSetNaked( "mp_ca_impact", 0 );
|
||||
}
|
10
maps/createart/mp_ca_red_river_art.gsc
Normal file
10
maps/createart/mp_ca_red_river_art.gsc
Normal file
@ -0,0 +1,10 @@
|
||||
// _createart generated. modify at your own risk. Changing values should be fine.
|
||||
main()
|
||||
{
|
||||
level.tweakfile = true;
|
||||
level.parse_fog_func = maps\createart\mp_ca_red_river_fog::main;
|
||||
|
||||
setDevDvar( "scr_fog_disable", "0" );
|
||||
// setExpFog( 7220, 1084, 0.901961, 0.917647, 0.843137, 1, 0.2094, 0, 0, 0, 90 );
|
||||
VisionSetNaked( "mp_ca_red_river", 0 );
|
||||
}
|
10
maps/createart/mp_ca_rumble_art.gsc
Normal file
10
maps/createart/mp_ca_rumble_art.gsc
Normal file
@ -0,0 +1,10 @@
|
||||
// _createart generated. modify at your own risk. Changing values should be fine.
|
||||
main()
|
||||
{
|
||||
level.tweakfile = true;
|
||||
level.parse_fog_func = maps\createart\mp_ca_rumble_fog::main;
|
||||
|
||||
setDevDvar( "scr_fog_disable", "0" );
|
||||
// setExpFog( 562.278, 5000, 0.685692, 0.564965, 0.436857, 1, 0.60214, 0, 0, 0, 90 );
|
||||
VisionSetNaked( "mp_ca_rumble", 0 );
|
||||
}
|
14
maps/createart/mp_chasm_art.gsc
Normal file
14
maps/createart/mp_chasm_art.gsc
Normal file
@ -0,0 +1,14 @@
|
||||
// _createart generated. modify at your own risk. Changing values should be fine.
|
||||
main()
|
||||
{
|
||||
level.tweakfile = true;
|
||||
level.parse_fog_func = maps\createart\mp_chasm_fog::main;
|
||||
|
||||
//* Fog section *
|
||||
|
||||
setDevDvar( "scr_fog_disable", "0" );
|
||||
|
||||
// setExpFog( 0, 5211.68, 0.480657, 0.755661, 0.785471, 2.01908, 0, 0, 0, 0, 0 );
|
||||
VisionSetNaked( "mp_chasm", 0 );
|
||||
|
||||
}
|
10
maps/createart/mp_conflict_art.gsc
Normal file
10
maps/createart/mp_conflict_art.gsc
Normal file
@ -0,0 +1,10 @@
|
||||
// _createart generated. modify at your own risk. Changing values should be fine.
|
||||
main()
|
||||
{
|
||||
level.tweakfile = true;
|
||||
level.parse_fog_func = maps\createart\mp_conflict_fog::main;
|
||||
|
||||
setDevDvar( "scr_fog_disable", "0" );
|
||||
// setExpFog( 0, 1958.84, 0.656882, 0.680657, 0.696267, 2, 0.90625, 0, 0.396688, 0.396688, 0.396619, 0.5, (0, 0, -1), 80, 105, 0.0625, 0.960938, 0, 54 );
|
||||
VisionSetNaked( "mp_conflict", 0 );
|
||||
}
|
10
maps/createart/mp_dart_art.gsc
Normal file
10
maps/createart/mp_dart_art.gsc
Normal file
@ -0,0 +1,10 @@
|
||||
// _createart generated. modify at your own risk. Changing values should be fine.
|
||||
main()
|
||||
{
|
||||
level.tweakfile = true;
|
||||
level.parse_fog_func = maps\createart\mp_dart_fog::main;
|
||||
|
||||
setDevDvar( "scr_fog_disable", "0" );
|
||||
// setExpFog( 200, 3500, 0.54, 0.54, 0.54, 1, 0.75, 0, 0.92, 0.69, 0.44, 1, (-0.27, -0.86, 0.4), 15, 60, 2.25, 1, 61, 85 );
|
||||
VisionSetNaked( "mp_dart", 0 );
|
||||
}
|
13
maps/createart/mp_descent_new_art.gsc
Normal file
13
maps/createart/mp_descent_new_art.gsc
Normal file
@ -0,0 +1,13 @@
|
||||
main()
|
||||
{
|
||||
level.tweakfile = true;
|
||||
level.parse_fog_func = maps\createart\mp_descent_new_fog::main;
|
||||
|
||||
//* Fog section *
|
||||
|
||||
setDevDvar( "scr_fog_disable", "0" );
|
||||
|
||||
// setExpFog( 0, 5211.68, 0.480657, 0.755661, 0.785471, 2.01908, 0, 0, 0, 0, 0 );
|
||||
VisionSetNaked( "mp_descent_new", 0 );
|
||||
|
||||
}
|
11
maps/createart/mp_dig_art.gsc
Normal file
11
maps/createart/mp_dig_art.gsc
Normal file
@ -0,0 +1,11 @@
|
||||
// _createart generated. modify at your own risk. Changing values should be fine.
|
||||
main()
|
||||
{
|
||||
level.tweakfile = true;
|
||||
level.parse_fog_func = maps\createart\mp_dig_fog::main;
|
||||
//* Fog section *
|
||||
setDevDvar( "scr_fog_disable", "0" );
|
||||
// setExpFog( 0, 5211.68, 0.627451, 0.717647, 0.745098, 0.38927, 0, 0.838639, 0.691254, 0.567937, (0.00390755, 0.00323934, -1), 83.5416, 92.7872, 2.25266 );
|
||||
VisionSetNaked( "mp_dig", 0 );
|
||||
|
||||
}
|
16
maps/createart/mp_dome_ns_art.gsc
Normal file
16
maps/createart/mp_dome_ns_art.gsc
Normal file
@ -0,0 +1,16 @@
|
||||
// _createart generated. modify at your own risk. Changing values should be fine.
|
||||
main()
|
||||
{
|
||||
level.tweakfile = true;
|
||||
level.parse_fog_func = maps\createart\mp_dome_ns_fog::main;
|
||||
//* Fog section *
|
||||
//setDevDvar( "scr_fog_disable", "0" );
|
||||
//setExpFog( 0, 5211.68, 0.627451, 0.717647, 0.745098, 0.38927, 0, 0.838639, 0.691254, 0.567937, (0.00390755, 0.00323934, -1), 83.5416, 92.7872, 2.25266 );
|
||||
VisionSetNaked( "mp_dome_ns", 0 );
|
||||
|
||||
|
||||
|
||||
//setdvar_cg_ng("r_specularColorScale", 3, 8.5);
|
||||
|
||||
|
||||
}
|
10
maps/createart/mp_fahrenheit_art.gsc
Normal file
10
maps/createart/mp_fahrenheit_art.gsc
Normal file
@ -0,0 +1,10 @@
|
||||
// _createart generated. modify at your own risk. Changing values should be fine.
|
||||
main()
|
||||
{
|
||||
level.tweakfile = true;
|
||||
level.parse_fog_func = maps\createart\mp_fahrenheit_fog::main;
|
||||
|
||||
setDevDvar( "scr_fog_disable", "0" );
|
||||
// setExpFog( 624.344, 2914.77, 0.53, 0.52, 0.57, 1, 1, 0, 0.84, 0.77, 0.67, 1, (-0.79, 0.17, 0.57), 0, 80.7, 0.9, 1, 23.32, 89.58 );
|
||||
VisionSetNaked( "mp_fahrenheit", 0 );
|
||||
}
|
11
maps/createart/mp_favela_iw6_art.gsc
Normal file
11
maps/createart/mp_favela_iw6_art.gsc
Normal file
@ -0,0 +1,11 @@
|
||||
// _createart generated. modify at your own risk. Changing values should be fine.
|
||||
main()
|
||||
{
|
||||
level.tweakfile = true;
|
||||
level.parse_fog_func = maps\createart\mp_favela_iw6_fog::main;
|
||||
//* Fog section *
|
||||
setDevDvar( "scr_fog_disable", "0" );
|
||||
// setExpFog( 0, 5211.68, 0.627451, 0.717647, 0.745098, 0.38927, 0, 0.838639, 0.691254, 0.567937, (0.00390755, 0.00323934, -1), 83.5416, 92.7872, 2.25266 );
|
||||
VisionSetNaked( "mp_favela_iw6", 0 );
|
||||
|
||||
}
|
10
maps/createart/mp_flooded_art.gsc
Normal file
10
maps/createart/mp_flooded_art.gsc
Normal file
@ -0,0 +1,10 @@
|
||||
// _createart generated. modify at your own risk. Changing values should be fine.
|
||||
main()
|
||||
{
|
||||
level.tweakfile = true;
|
||||
level.parse_fog_func = maps\createart\mp_flooded_fog::main;
|
||||
|
||||
setDevDvar( "scr_fog_disable", "0" );
|
||||
// setExpFog( 600, 1600, 0.721569, 0.823529, 0.929412, 1, 0.314067, 0, 0, 0, 90 );
|
||||
VisionSetNaked( "mp_flooded", 0 );
|
||||
}
|
10
maps/createart/mp_frag_art.gsc
Normal file
10
maps/createart/mp_frag_art.gsc
Normal file
@ -0,0 +1,10 @@
|
||||
// _createart generated. modify at your own risk. Changing values should be fine.
|
||||
main()
|
||||
{
|
||||
level.tweakfile = true;
|
||||
level.parse_fog_func = maps\createart\mp_frag_fog::main;
|
||||
|
||||
setDevDvar( "scr_fog_disable", "0" );
|
||||
// setExpFog( 1500, 6145, 0.8, 0.88, 1, 1, 0.25, 0, 1, 1, 0.94, 1.06, (0.76, 0.38, 0.51), 0, 100, 1, 1, 60, 85 );
|
||||
VisionSetNaked( "mp_frag", 0 );
|
||||
}
|
10
maps/createart/mp_hashima_art.gsc
Normal file
10
maps/createart/mp_hashima_art.gsc
Normal file
@ -0,0 +1,10 @@
|
||||
// _createart generated. modify at your own risk. Changing values should be fine.
|
||||
main()
|
||||
{
|
||||
level.tweakfile = true;
|
||||
level.parse_fog_func = maps\createart\mp_hashima_fog::main;
|
||||
|
||||
setDevDvar( "scr_fog_disable", "0" );
|
||||
// setExpFog( 1536, 10241, 0, 0.705811, 0.921875, 1, 0.5, 0, 0.757813, 0.607019, 0.363672, 1, (0.097, -0.031, -0.375), 55, 180, 2.5, 1, 60, 80 );
|
||||
VisionSetNaked( "mp_hashima", 0 );
|
||||
}
|
10
maps/createart/mp_lonestar_art.gsc
Normal file
10
maps/createart/mp_lonestar_art.gsc
Normal file
@ -0,0 +1,10 @@
|
||||
// _createart generated. modify at your own risk. Changing values should be fine.
|
||||
main()
|
||||
{
|
||||
level.tweakfile = true;
|
||||
level.parse_fog_func = maps\createart\mp_lonestar_fog::main;
|
||||
|
||||
setDevDvar( "scr_fog_disable", "0" );
|
||||
// setExpFog( 512, 7760.62, 0.5, 0.5, 0.5, 0.75, 0.859375, 0, 0.328125, 0.328125, 0.328125, 1, (0, 0, 1), 64, 91, 0.5, 1, 54, 82 );
|
||||
VisionSetNaked( "mp_lonestar", 0 );
|
||||
}
|
10
maps/createart/mp_mine_art.gsc
Normal file
10
maps/createart/mp_mine_art.gsc
Normal file
@ -0,0 +1,10 @@
|
||||
// _createart generated. modify at your own risk. Changing values should be fine.
|
||||
main()
|
||||
{
|
||||
level.tweakfile = true;
|
||||
level.parse_fog_func = maps\createart\mp_mine_fog::main;
|
||||
|
||||
setDevDvar( "scr_fog_disable", "0" );
|
||||
// setExpFog( 122.24, 25282, 0.846864, 0.748939, 0.5479, 1, 1, 0, 0, 0, 0 );
|
||||
VisionSetNaked( "mp_mine", 0 );
|
||||
}
|
10
maps/createart/mp_pirate_art.gsc
Normal file
10
maps/createart/mp_pirate_art.gsc
Normal file
@ -0,0 +1,10 @@
|
||||
// _createart generated. modify at your own risk. Changing values should be fine.
|
||||
main()
|
||||
{
|
||||
level.tweakfile = true;
|
||||
level.parse_fog_func = maps\createart\mp_pirate_fog::main;
|
||||
|
||||
setDevDvar( "scr_fog_disable", "0" );
|
||||
// setExpFog( 0, 1, 0.109, 0.113, 0.124, 0.807, 1, 0, 1, 30, 90 );
|
||||
VisionSetNaked( "mp_pirate", 0 );
|
||||
}
|
11
maps/createart/mp_prisonbreak_art.gsc
Normal file
11
maps/createart/mp_prisonbreak_art.gsc
Normal file
@ -0,0 +1,11 @@
|
||||
// _createart generated. modify at your own risk. Changing values should be fine.
|
||||
main()
|
||||
{
|
||||
level.tweakfile = true;
|
||||
level.parse_fog_func = maps\createart\mp_prisonbreak_fog::main;
|
||||
//* Fog section *
|
||||
setDevDvar( "scr_fog_disable", "0" );
|
||||
//setExpFog( 1400, 40500, 0.92, 0.99, 1.0, 0.22, 1, 0.64, 0.50, 0.50, (0.98, 0.09, 0.1), 0, 80.0, 5.0 );
|
||||
VisionSetNaked( "mp_prisonbreak", 0 );
|
||||
|
||||
}
|
9
maps/createart/mp_shipment_ns_art.gsc
Normal file
9
maps/createart/mp_shipment_ns_art.gsc
Normal file
@ -0,0 +1,9 @@
|
||||
// _createart generated. modify at your own risk. Changing values should be fine.
|
||||
main()
|
||||
{
|
||||
level.tweakfile = true;
|
||||
level.parse_fog_func = maps\createart\mp_shipment_ns_fog::main;
|
||||
|
||||
setDevDvar( "scr_fog_disable", 0 );
|
||||
VisionSetNaked( "mp_shipment_ns", 0 );
|
||||
}
|
10
maps/createart/mp_skeleton_art.gsc
Normal file
10
maps/createart/mp_skeleton_art.gsc
Normal file
@ -0,0 +1,10 @@
|
||||
// _createart generated. modify at your own risk. Changing values should be fine.
|
||||
main()
|
||||
{
|
||||
level.tweakfile = true;
|
||||
level.parse_fog_func = maps\createart\mp_skeleton_fog::main;
|
||||
|
||||
setDevDvar( "scr_fog_disable", "0" );
|
||||
// setExpFog( 575.658, 5181.9, 0.899167, 0.930833, 1, 3.42928, 0.619243, 0, 1, 78.972, 92.2944 );
|
||||
VisionSetNaked( "mp_skeleton", 0 );
|
||||
}
|
10
maps/createart/mp_snow_art.gsc
Normal file
10
maps/createart/mp_snow_art.gsc
Normal file
@ -0,0 +1,10 @@
|
||||
// _createart generated. modify at your own risk. Changing values should be fine.
|
||||
main()
|
||||
{
|
||||
level.tweakfile = true;
|
||||
level.parse_fog_func = maps\createart\mp_snow_fog::main;
|
||||
|
||||
setDevDvar( "scr_fog_disable", "0" );
|
||||
// setExpFog( 714.363, 7073.18, 0.345189, 0.457268, 0.453545, 1, 0.55, 0, 0.608505, 0.999996, 0.828083, 1, (0.12, -0.03, 0.99), 0, 55, 0.38, 1, 67.2161, 92.6819 );
|
||||
VisionSetNaked( "mp_snow", 0 );
|
||||
}
|
15
maps/createart/mp_sovereign_art.gsc
Normal file
15
maps/createart/mp_sovereign_art.gsc
Normal file
@ -0,0 +1,15 @@
|
||||
// _createart generated. modify at your own risk. Changing values should be fine.
|
||||
main()
|
||||
{
|
||||
|
||||
level.tweakfile = true;
|
||||
level.parse_fog_func = maps\createart\mp_sovereign_fog::main;
|
||||
|
||||
//* Fog section *
|
||||
|
||||
setDevDvar( "scr_fog_disable", "0" );
|
||||
|
||||
//setExpFog( 650, 2049, 0.352941, 0.411765, 0.478431, 1, 0.5, 0, 1, 0.854902, 0.74902, 1, (0.00390755, 0.00323934, -1), 61, 93.7872, 0.25 );
|
||||
VisionSetNaked( "mp_sovereign", 0 );
|
||||
|
||||
}
|
10
maps/createart/mp_strikezone_art.gsc
Normal file
10
maps/createart/mp_strikezone_art.gsc
Normal file
@ -0,0 +1,10 @@
|
||||
// _createart generated. modify at your own risk. Changing values should be fine.
|
||||
main()
|
||||
{
|
||||
level.tweakfile = true;
|
||||
level.parse_fog_func = maps\createart\mp_strikezone_fog::main;
|
||||
|
||||
setDevDvar( "scr_fog_disable", "0" );
|
||||
// setExpFog( 525.762, 18137.9, 0.62, 0.81, 0.81, 1.4, 1, 0, 0.99, 0.97, 0.83, 1.2, (-0.05, -0.89, 0.44), 0, 100, 0.9, 1, 13.7392, 117.129 );
|
||||
VisionSetNaked( "mp_strikezone", 0 );
|
||||
}
|
10
maps/createart/mp_swamp_art.gsc
Normal file
10
maps/createart/mp_swamp_art.gsc
Normal file
@ -0,0 +1,10 @@
|
||||
// _createart generated. modify at your own risk. Changing values should be fine.
|
||||
main()
|
||||
{
|
||||
level.tweakfile = true;
|
||||
level.parse_fog_func = maps\createart\mp_swamp_fog::main;
|
||||
|
||||
setDevDvar( "scr_fog_disable", "0" );
|
||||
// setExpFog( 0, 2985.05, 0.339273, 0.302975, 0.400243, 1, 0.485193, 0, 0, 0, 0 );
|
||||
VisionSetNaked( "mp_swamp", 0 );
|
||||
}
|
10
maps/createart/mp_warhawk_art.gsc
Normal file
10
maps/createart/mp_warhawk_art.gsc
Normal file
@ -0,0 +1,10 @@
|
||||
// _createart generated. modify at your own risk. Changing values should be fine.
|
||||
main()
|
||||
{
|
||||
level.tweakfile = true;
|
||||
level.parse_fog_func = maps\createart\mp_warhawk_fog::main;
|
||||
|
||||
setDevDvar( "scr_fog_disable", "0" );
|
||||
// setExpFog( 1307.29, 8178.08, 0.888789, 0.851156, 0.664851, 1.07658, 0.468766, 0, 0.639683, 0.464798, 0.346012, 0.573353, (0.89, 0.06, 0.44), 0, 137, 2.40463, 0.730742, 26.9803, 63.638 );
|
||||
VisionSetNaked( "mp_warhawk", 0 );
|
||||
}
|
10
maps/createart/mp_zebra_art.gsc
Normal file
10
maps/createart/mp_zebra_art.gsc
Normal file
@ -0,0 +1,10 @@
|
||||
// _createart generated. modify at your own risk. Changing values should be fine.
|
||||
main()
|
||||
{
|
||||
level.tweakfile = true;
|
||||
level.parse_fog_func = maps\createart\mp_zebra_fog::main;
|
||||
|
||||
setDevDvar( "scr_fog_disable", "0" );
|
||||
// setExpFog( 371.287, 7055.43, 0.395946, 0.358963, 0.352442, 0.742574, 0.919554, 0, 0, 0, 0 );
|
||||
VisionSetNaked( "mp_zebra", 0 );
|
||||
}
|
12
maps/createart/mp_zerosub_art.gsc
Normal file
12
maps/createart/mp_zerosub_art.gsc
Normal file
@ -0,0 +1,12 @@
|
||||
// _createart generated. modify at your own risk. Changing values should be fine.
|
||||
main()
|
||||
{
|
||||
level.tweakfile = true;
|
||||
level.parse_fog_func = maps\createart\mp_zerosub_fog::main;
|
||||
|
||||
setDevDvar( "scr_fog_disable", "0" );
|
||||
// setExpFog( 0, 2985.05, 0.339273, 0.302975, 0.400243, 1, 0.485193, 0, 0, 0, 0 );
|
||||
VisionSetNaked( "mp_zerosub", 0 );
|
||||
}
|
||||
|
||||
|
10
maps/createart/mp_zulu_art.gsc
Normal file
10
maps/createart/mp_zulu_art.gsc
Normal file
@ -0,0 +1,10 @@
|
||||
// _createart generated. modify at your own risk. Changing values should be fine.
|
||||
main()
|
||||
{
|
||||
level.tweakfile = true;
|
||||
level.parse_fog_func = maps\createart\mp_zulu_fog::main;
|
||||
|
||||
setDevDvar( "scr_fog_disable", "0" );
|
||||
// setExpFog( 7346.26, 10487.6, 0.583682, 0.52939, 0.302793, 1, 1, 0, 0, 0, 0 );
|
||||
VisionSetNaked( "mp_zulu", 0 );
|
||||
}
|
1230
maps/interactive_models/_birds_dlc.gsc
Normal file
1230
maps/interactive_models/_birds_dlc.gsc
Normal file
File diff suppressed because it is too large
Load Diff
664
maps/interactive_models/_interactive_utility.gsc
Normal file
664
maps/interactive_models/_interactive_utility.gsc
Normal file
@ -0,0 +1,664 @@
|
||||
#include common_scripts\utility;
|
||||
|
||||
/*
|
||||
=============
|
||||
///ScriptDocBegin
|
||||
"Name: delete_on_notify( <ent>, <notify1>, <notify2>, <notify3> )"
|
||||
"Summary: Just like delete_on_death, but takes up to 3 strings. Notifying any of the strings will result in ent being deleted."
|
||||
"Module: Entity"
|
||||
"CallOn: An entity"
|
||||
"MandatoryArg: <ent>: The entity to be deleted"
|
||||
"OptionalArg: <notify1>: Strings on the called-on-entity that you want to listen for."
|
||||
"Example: self thread delete_on_notify( trigger, "death", "damage" );"
|
||||
"SPMP: both"
|
||||
///ScriptDocEnd
|
||||
=============
|
||||
*/
|
||||
delete_on_notify( ent, notify1, notify2, notify3 )
|
||||
{
|
||||
//self ==> the entity you want to wait for a notify on before deleting the ent
|
||||
ent endon( "death" );
|
||||
self waittill_any( notify1, notify2, notify3 );
|
||||
if ( IsDefined( ent ) )
|
||||
ent Delete();
|
||||
}
|
||||
|
||||
// array_sortByArray - given an array, and another array of equal size containing a value to sort on, returns a copy of the first array, sorted.
|
||||
// Not optimized. O(n^2), I think.
|
||||
array_sortByArray( array, sorters )
|
||||
{
|
||||
newArray = [];
|
||||
newArray[0] = array[0];
|
||||
newSorters = [];
|
||||
newSorters[0] = sorters[0];
|
||||
for ( i=1; i<array.size; i++ )
|
||||
{
|
||||
sorted = false;
|
||||
for ( j=0; j<newArray.size; j++ )
|
||||
{
|
||||
if ( sorters[i] < newSorters[j] )
|
||||
{
|
||||
for ( k=newArray.size-1; k>=j; k-- )
|
||||
{
|
||||
newArray[ k+1 ] = newArray[ k ];
|
||||
newSorters[ k+1 ] = newSorters[ k ];
|
||||
}
|
||||
newArray[ j ] = array[ i ];
|
||||
newSorters[ j ] = sorters[ i ];
|
||||
sorted = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( !sorted )
|
||||
{
|
||||
newArray[ i ] = array[ i ];
|
||||
newSorters[ i ] = sorters[ i ];
|
||||
}
|
||||
}
|
||||
return newArray;
|
||||
}
|
||||
|
||||
// array_sortBySorter - given an array of structs, each of which contains a field named "sorter", returns a copy of the array, sorted.
|
||||
// Notes:
|
||||
// Not optimized. O(n^2), I think.
|
||||
// Does not copy the structs. Copies the array but references the original structs.
|
||||
array_sortBySorter( array )
|
||||
{
|
||||
newArray = [];
|
||||
newArray[0] = array[0];
|
||||
for ( i=1; i<array.size; i++ )
|
||||
{
|
||||
sorted = false;
|
||||
for ( j=0; j<newArray.size; j++ )
|
||||
{
|
||||
if ( array[i].sorter < newArray[j].sorter )
|
||||
{
|
||||
for ( k=newArray.size-1; k>=j; k-- )
|
||||
{
|
||||
newArray[ k+1 ] = newArray[ k ];
|
||||
}
|
||||
newArray[ j ] = array[ i ];
|
||||
sorted = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( !sorted )
|
||||
{
|
||||
newArray[ i ] = array[ i ];
|
||||
}
|
||||
}
|
||||
return newArray;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
///ScriptDocBegin
|
||||
"Name: wait_then_fn( <notifyStr>, <fn>, <arg1>, <arg2>, <arg3> )"
|
||||
"Summary: Waits for a notify or a time, then calls the specified function with specified args."
|
||||
"Module: "
|
||||
"CallOn: Entity"
|
||||
"MandatoryArg: <notifyStr> : String to notify or time to wait"
|
||||
"MandatoryArg: <enders>: String (or array of strings) to kill the thread. Can be undefined."
|
||||
"MandatoryArg: <fn> : pointer to a script function"
|
||||
"OptionalArg: <arg1> : parameter 1 to pass to the process"
|
||||
"OptionalArg: <arg2> : parameter 2 to pass to the process"
|
||||
"OptionalArg: <arg3> : parameter 3 to pass to the process"
|
||||
"OptionalArg: <arg4> : parameter 4 to pass to the process"
|
||||
"Example: fish1 thread wait_then_fn( "path_complete", ::arriveAtLocation, false );"
|
||||
"SPMP: both"
|
||||
///ScriptDocEnd
|
||||
=============
|
||||
*/
|
||||
wait_then_fn( notifyStr, enders, fn, arg1, arg2, arg3, arg4 )
|
||||
{
|
||||
self endon( "death" );
|
||||
if ( IsDefined( enders ) ) {
|
||||
if ( IsArray( enders ) ) {
|
||||
foreach ( ender in enders )
|
||||
{
|
||||
self endon( ender );
|
||||
}
|
||||
} else {
|
||||
self endon( enders );
|
||||
}
|
||||
}
|
||||
if ( isString( notifyStr ) )
|
||||
self waittill( notifyStr );
|
||||
else // Assume it's a time
|
||||
wait ( notifyStr );
|
||||
if ( IsDefined( arg4 ) )
|
||||
self [[ fn ]]( arg1, arg2, arg3, arg4 );
|
||||
else if ( IsDefined( arg3 ) )
|
||||
self [[ fn ]]( arg1, arg2, arg3 );
|
||||
else if ( IsDefined( arg2 ) )
|
||||
self [[ fn ]]( arg1, arg2 );
|
||||
else if ( IsDefined( arg1 ) )
|
||||
self [[ fn ]]( arg1 );
|
||||
else
|
||||
self [[ fn ]]();
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
///ScriptDocBegin
|
||||
"Name: waittill_notify ( <waitStr> , <notifyEnt> , <notifyStr> , <ender> )"
|
||||
"Summary: Wait for a notify on one ent and then notify another ent."
|
||||
"Module: Entity"
|
||||
"CallOn: An entity"
|
||||
"MandatoryArg: <waitStr>: String to wait for."
|
||||
"MandatoryArg: <notifyEnt>: Entity to notify."
|
||||
"MandatoryArg: <notifyStr>: String to notify."
|
||||
"OptionalArg: <ender>: String that will end this thread."
|
||||
"OptionalArg: <multiple>: Continue waiting for more notifies after the first one. Defaults to false."
|
||||
"Example: waittill_notify ( "trigger", self, trigger.script_triggername );"
|
||||
"SPMP: singleplayer"
|
||||
///ScriptDocEnd
|
||||
=============
|
||||
*/
|
||||
|
||||
waittill_notify ( waitStr, notifyEnt, notifyStr, ender, multiple )
|
||||
{
|
||||
if ( !isDefined( multiple ) ) multiple = false;
|
||||
doItAgain = true;
|
||||
while ( doItAgain )
|
||||
{
|
||||
self endon( "death" );
|
||||
if ( IsDefined( ender ) ) self endon( ender );
|
||||
self waittill( waitStr );
|
||||
notifyEnt notify( notifyStr );
|
||||
doItAgain = multiple;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
///ScriptDocBegin
|
||||
"Name: loop_anim( <animArray> , <animName> , <ender> )"
|
||||
"Summary: Plays an animation or a group of animations over and over until notified. A very simple alternative to anim_loop_solo. Takes the animations as a parameter, so you don't need to set the model up in level.scr_anim."
|
||||
"Module: Anim"
|
||||
"CallOn: An entity"
|
||||
"MandatoryArg: <animArray>: An array. Can contain animations, arrays of animations and animweights (just like those found in level.scr_anim[animname])."
|
||||
"MandatoryArg: <animName>: The animation index in the array, just like anime in anim_loop_solo."
|
||||
"OptionalArg: <ender>: Notify string"
|
||||
"OptionalArg: <animRate>: Playback speed for the animation. Defaults to 1."
|
||||
"Example: "
|
||||
"SPMP: singleplayer"
|
||||
///ScriptDocEnd
|
||||
=============
|
||||
*/
|
||||
loop_anim( animArray, animName, ender, animRate )
|
||||
{
|
||||
self endon( "death" );
|
||||
if ( IsDefined( ender ) ) self endon( ender );
|
||||
|
||||
while ( 1 )
|
||||
{
|
||||
a = self single_anim( animArray, animName, "loop_anim", false, animRate );
|
||||
if ( isSP() ) {
|
||||
self waittillmatch( "loop_anim", "end" );
|
||||
} else {
|
||||
wait GetAnimLength( a );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
///ScriptDocBegin
|
||||
"Name: single_anim( <animArray> , <animName> , <notifyStr> , <restartAnim> )"
|
||||
"Summary: Plays an animation or a group of animations. Similar to (but much simpler than) anim_single_solo. Takes the animations as a parameter, so you don't need to set the model up in level.scr_anim. Returns the animation chosen, so you can check the length or whatever."
|
||||
"Module: Anim"
|
||||
"CallOn: An entity"
|
||||
"MandatoryArg: <animArray>: An array. Can contain animations, arrays of animations and weights (just like those found in level.scr_anim[animname]). Can also contain mp animations (strings) using the suffix "mp"."
|
||||
"MandatoryArg: <animName>: The animation index in the array, just like anime in anim_loop_solo."
|
||||
"OptionalArg: <notifyStr>: String that the animation will notify for notetracks and when finished. Defaults to single_anim. SP only."
|
||||
"OptionalArg: <restartAnim>: Set to true to force the animation to start from the beginning, otherwise it will simply continue if it is already playing. Defaults to false. SP only."
|
||||
"OptionalArg: <animRate>: Playback speed for the animation. Defaults to 1. SP only."
|
||||
"Example: "
|
||||
"SPMP: both"
|
||||
///ScriptDocEnd
|
||||
=============
|
||||
*/
|
||||
|
||||
single_anim( animArray, animName, notifyStr, restartAnim, animRate )
|
||||
{
|
||||
if ( !IsDefined( notifyStr ) ) notifyStr = "single_anim";
|
||||
if ( !IsDefined( animRate ) ) animRate = 1;
|
||||
|
||||
if ( IsArray( animArray[ animName ] ) )
|
||||
{
|
||||
//AssertEx( IsDefined( animArray[ ( animName + "weight" ) ] ) , "Array of anims labeled \""+animName+"\" does not have associated \""+animName+"weight\" array." );
|
||||
if ( !IsDefined( animArray[ ( animName + "weight" ) ] ) )
|
||||
{
|
||||
animArray[ ( animName + "weight" ) ] = [];
|
||||
keys = GetArrayKeys( animArray[ animName ] );
|
||||
foreach ( key in keys )
|
||||
{
|
||||
animArray[ ( animName + "weight" ) ][ key ] = 1;
|
||||
}
|
||||
}
|
||||
AssertEx( IsArray( animArray[ ( animName + "weight" ) ] ) , "Array of anim weights labeled \""+animName+"weight\" is not an array." );
|
||||
AssertEx( animArray[ ( animName + "weight" ) ].size == animArray[ animName ].size, "Array of anims labeled \""+animName+"\" does not have a matching array of weights." );
|
||||
numAnims = animArray[ animName ].size;
|
||||
totalWeight = 0;
|
||||
for ( i = 0; i < numAnims; i++ )
|
||||
{
|
||||
totalWeight += animArray[ ( animName + "weight" ) ][ i ];
|
||||
}
|
||||
rand = RandomFloat( totalWeight );
|
||||
runningWeight = 0;
|
||||
sel = -1;
|
||||
while ( runningWeight <= rand )
|
||||
{
|
||||
sel++;
|
||||
runningWeight += animArray[ ( animName + "weight" ) ][ sel ];
|
||||
}
|
||||
animation = animArray[ animName ][ sel ];
|
||||
if ( IsDefined( animArray[ animName + "mp" ] ) ) {
|
||||
animation_mp = animArray[ animName + "mp" ][ sel ];
|
||||
} else {
|
||||
animation_mp = undefined;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
animation = animArray[ animName ];
|
||||
animation_mp = animArray[ animName + "mp" ];
|
||||
}
|
||||
if ( isSP() ) {
|
||||
if ( IsDefined( restartAnim) && restartAnim )
|
||||
self call [[ level.func[ "setflaggedanimknobrestart" ] ]]( notifyStr, animation, 1, 0.1, animRate );
|
||||
else
|
||||
self call [[ level.func[ "setflaggedanimknob" ] ]]( notifyStr, animation, 1, 0.1, animRate );
|
||||
} else {
|
||||
self call [[ level.func[ "scriptModelPlayAnim" ] ]]( animation_mp );
|
||||
}
|
||||
return animation;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
///ScriptDocBegin
|
||||
"Name: blendAnimsBySpeed( <speed> , <anims> , <animSpeeds>, <animLengths> )"
|
||||
"Summary: Only blends in SPBlends between animations in an array according to the speed parameter. Keeps all animations playing in sync (without using loopsync in the animtree). Note: uses SetAnimLimited, so be sure to set the parent node in the animtree separately."
|
||||
"Module: Anim"
|
||||
"CallOn: An entity"
|
||||
"MandatoryArg: <speed>: The number to be compared to the values in animSpeeds."
|
||||
"MandatoryArg: <anims>: Array of animations."
|
||||
"MandatoryArg: <anims>: Array of speeds that correspond to the animations."
|
||||
"MandatoryArg: <animLengths>: Array of lengths of the animations, to save it having to be calculated every time the function is called."
|
||||
"OptionalArg: <blendTime>: Blend time used as a parameter to SetAnim."
|
||||
"Example: "
|
||||
"SPMP: both"
|
||||
///ScriptDocEnd
|
||||
=============
|
||||
*/
|
||||
blendAnimsBySpeed( speed, anims, animSpeeds, animLengths, blendTime )
|
||||
{
|
||||
/#
|
||||
Assert( anims.size == animSpeeds.size && anims.size == animLengths.size );
|
||||
for ( i=1; i<animSpeeds.size; i++)
|
||||
Assert( animSpeeds[ i-1 ] < animSpeeds[ i ] );
|
||||
#/
|
||||
if ( !IsDefined( blendTime ) ) blendTime = 0.1;
|
||||
|
||||
speed = clamp( speed, animSpeeds[ 0 ], animSpeeds[ animSpeeds.size-1 ] );
|
||||
i = 0;
|
||||
while ( speed > animSpeeds[ i+1 ] )
|
||||
{
|
||||
i++;
|
||||
}
|
||||
fastWeight = speed - animSpeeds[ i ];
|
||||
fastWeight /=animSpeeds[ i+1 ] - animSpeeds[ i ];
|
||||
if ( isSP() ) // We only blend in SP
|
||||
{
|
||||
fastWeight = clamp( fastWeight, 0.01, 0.99 ); // Don't allow anims to blend out so they don't lose their time.
|
||||
// Scale playback rates according to blend weights.
|
||||
// I'd love to use loopsync to achieve this but it appears to prevent SetAnimTime from working.
|
||||
speedRatio = animLengths[ i+1 ] / animLengths[ i ];
|
||||
fastRate = fastWeight + ( ( 1 - fastWeight ) * speedRatio );
|
||||
self call [[ level.func[ "setanimlimited" ] ]]( anims[ i ], 1 - fastWeight, blendTime, fastRate / speedRatio );
|
||||
self call [[ level.func[ "setanimlimited" ] ]]( anims[ i+1 ], fastWeight, blendTime, fastRate );
|
||||
for ( j=0; j<i; j++ )
|
||||
{
|
||||
speedRatio = animLengths[ i+1 ] / animLengths[ j ];
|
||||
self call [[ level.func[ "setanimlimited" ] ]]( anims[ j ], 0.01, blendTime, fastRate / speedRatio );
|
||||
}
|
||||
for ( j=i+2; j<animSpeeds.size; j++ )
|
||||
{
|
||||
speedRatio = animLengths[ i+1 ] / animLengths[ j ];
|
||||
self call [[ level.func[ "setanimlimited" ] ]]( anims[ j ], 0.01, blendTime, fastRate / speedRatio );
|
||||
}
|
||||
}
|
||||
else // MP. Just play the one that matches the speed best.
|
||||
{
|
||||
if ( fastWeight > 0.5 )
|
||||
{
|
||||
self call [[ level.func[ "scriptModelPlayAnim" ] ]]( anims[ i+1 ] );
|
||||
}
|
||||
else
|
||||
{
|
||||
self call [[ level.func[ "scriptModelPlayAnim" ] ]]( anims[ i ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
///ScriptDocBegin
|
||||
"Name: detect_events()"
|
||||
"Summary: Makes an entity sentient and sets it up to detect nearby firefights. self.interrupted will be set to true for the frame in which an interruption occurs, so you can check it in situations where you can't wait for a notification."
|
||||
"Module: Entity"
|
||||
"CallOn: An entity"
|
||||
"MandatoryArg: <notifyString>: String that will be notified when violence is detected."
|
||||
"Example: self thread detect_events( "interrupted" );"
|
||||
"SPMP: singleplayer"
|
||||
///ScriptDocEnd
|
||||
=============
|
||||
*/
|
||||
|
||||
detect_events( notifyString )
|
||||
{
|
||||
if ( isSP() ) {
|
||||
self endon( "death" );
|
||||
self endon( "damage" );
|
||||
self call [[ level.makeEntitySentient_func ]]( "neutral" );
|
||||
self call [[ level.addAIEventListener_func ]]( "projectile_impact" );
|
||||
self call [[ level.addAIEventListener_func ]]( "bulletwhizby" );
|
||||
self call [[ level.addAIEventListener_func ]]( "gunshot" );
|
||||
self call [[ level.addAIEventListener_func ]]( "explode" );
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
self waittill( "ai_event", eventtype );
|
||||
self notify( notifyString );
|
||||
self.interrupted = true;
|
||||
waittillframeend;
|
||||
self.interrupted = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
///ScriptDocBegin
|
||||
"Name: detect_people( <radius> , <notifyStr> )"
|
||||
"Summary: Creates a trigger that detects people and vehicles. self.interrupted will be set to true for the frame in which an interruption occurs, so you can check it in situations where you can't wait for a notification."
|
||||
"Module: Entity"
|
||||
"CallOn: An entity"
|
||||
"MandatoryArg: <radius>: Radious and height of the trigger volume."
|
||||
"MandatoryArg: <notifyStr>: String to notify when someone enters the trigger."
|
||||
"MandatoryArg: <endonStr>: String(s) that will end this thread and delete the trigger when notified."
|
||||
"Example: self thread detect_people( info.react_distance, "interrupted", [ "death", "damage" ] );"
|
||||
"SPMP: singleplayer"
|
||||
///ScriptDocEnd
|
||||
=============
|
||||
*/
|
||||
|
||||
detect_people( radius, notifyStr, endonStr )
|
||||
{
|
||||
if ( !IsArray( endonStr ) )
|
||||
{
|
||||
tempStr = endonStr;
|
||||
endonStr = [];
|
||||
endonStr[0] = tempStr;
|
||||
}
|
||||
foreach (str in endonStr )
|
||||
self endon( str );
|
||||
|
||||
// I think the trigger_radius flags are as follows: AI_AXIS = 1, AI_ALLIES = 2, AI_NEUTRAL = 4, NOTPLAYER = 8 VEHICLE = 16 TRIGGER_SPAWN = 32 TOUCH_ONCE = 64
|
||||
// AI_AXIS + AI_ALLIES + AI_NEUTRAL + VEHICLE = 23
|
||||
self.detect_people_trigger[ notifyStr ] = Spawn( "trigger_radius", self.origin, 23, radius, radius );
|
||||
|
||||
for ( i = endonStr.size; i < 3; i++ ) // Pad the array to make it easier to use for function parameters.
|
||||
endonStr[i] = undefined;
|
||||
self thread delete_on_notify( self.detect_people_trigger[ notifyStr ], endonStr[0], endonStr[1], endonStr[2] );
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
self.detect_people_trigger[ notifyStr ] waittill( "trigger", interruptedEnt );
|
||||
self.interruptedEnt = interruptedEnt; // (self.interruptedEnt can't be modified directly as a parameter to waittill.)
|
||||
self notify( notifyStr );
|
||||
self.interrupted = true;
|
||||
waittillframeend;
|
||||
self.interrupted = false;
|
||||
}
|
||||
}
|
||||
|
||||
detect_player_event( radius, notifyStr, endonStr, eventStr )
|
||||
{
|
||||
if ( !IsArray( endonStr ) )
|
||||
{
|
||||
tempStr = endonStr;
|
||||
endonStr = [];
|
||||
endonStr[0] = tempStr;
|
||||
}
|
||||
foreach (str in endonStr )
|
||||
self endon( str );
|
||||
|
||||
while( 1 ) {
|
||||
level.player waittill( eventStr );
|
||||
if ( DistanceSquared( level.player.origin, self.origin ) < radius*radius ) {
|
||||
self notify( notifyStr );
|
||||
self.interruptedEnt = level.player;
|
||||
self notify( notifyStr );
|
||||
self.interrupted = true;
|
||||
waittillframeend;
|
||||
self.interrupted = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Wraps <number> into 0 to <range>, just like AngleClamp does for the range of 0-360. Result will be >=0 and < abs(range). AKA modulo, %, remainder.
|
||||
wrap( number, range )
|
||||
{
|
||||
quotient = Int( number / range );
|
||||
remainder = number - ( range * quotient );
|
||||
if ( number < 0 ) remainder += range;
|
||||
if ( remainder == range ) remainder = 0;
|
||||
return remainder;
|
||||
}
|
||||
|
||||
interactives_DrawDebugLineForTime( org1, org2, r, g, b, timer )
|
||||
{
|
||||
/#
|
||||
if ( GetDvarInt( "interactives_debug" ) )
|
||||
{
|
||||
thread draw_line_for_time( org1, org2, r, g, b, timer );
|
||||
}
|
||||
#/
|
||||
}
|
||||
|
||||
// Draws a cross in 3D space
|
||||
drawCross( origin, size, color, timeSeconds )
|
||||
{
|
||||
thread draw_line_for_time ( origin -( size, 0, 0 ), origin +( size, 0, 0 ), color[0], color[1], color[2], timeSeconds );
|
||||
thread draw_line_for_time ( origin -( 0, size, 0 ), origin +( 0, size, 0 ), color[0], color[1], color[2], timeSeconds );
|
||||
thread draw_line_for_time ( origin -( 0, 0, size ), origin +( 0, 0, size ), color[0], color[1], color[2], timeSeconds );
|
||||
}
|
||||
|
||||
// Draws a circle in 3D space
|
||||
drawCircle( origin, radius, color, timeSeconds )
|
||||
{
|
||||
numSegments = 16;
|
||||
for ( i=0; i<360; i+=(360/numSegments) )
|
||||
{
|
||||
j = i + (360/numSegments);
|
||||
thread draw_line_for_time ( origin + ( radius*Cos(i), radius*Sin(i), 0 ), origin + ( radius*Cos(j), radius*Sin(j), 0 ), color[0], color[1], color[2], timeSeconds );
|
||||
}
|
||||
}
|
||||
|
||||
// Draw an arc with an arrowhead on the end, in 3D space. Positive degrees means counterclockwise.
|
||||
drawCircularArrow( origin, radius, color, timeseconds, degrees )
|
||||
{
|
||||
if ( degrees == 0 ) return;
|
||||
numSegmentsFullCircle = 16;
|
||||
numSegments = int( 1 + (numSegmentsFullCircle * abs(degrees) / 360 ) );
|
||||
for ( seg=0; seg<numSegments; seg++ )
|
||||
{
|
||||
i = seg * degrees / numSegments;
|
||||
j = i + (degrees / numSegments);
|
||||
thread draw_line_for_time ( origin + ( radius*Cos(i), radius*Sin(i), 0 ), origin + ( radius*Cos(j), radius*Sin(j), 0 ), color[0], color[1], color[2], timeSeconds );
|
||||
}
|
||||
i = degrees;
|
||||
j = degrees - ( sign( degrees ) * 20 );
|
||||
thread draw_line_for_time ( origin + ( radius*Cos(i), radius*Sin(i), 0 ), origin + ( radius*0.8*Cos(j), radius*0.8*Sin(j), 0 ), color[0], color[1], color[2], timeSeconds );
|
||||
thread draw_line_for_time ( origin + ( radius*Cos(i), radius*Sin(i), 0 ), origin + ( radius*1.2*Cos(j), radius*1.2*Sin(j), 0 ), color[0], color[1], color[2], timeSeconds );
|
||||
}
|
||||
|
||||
IsInArray( e, array )
|
||||
{
|
||||
foreach ( a in array )
|
||||
{
|
||||
if ( e == a ) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Newton's Method (Newton-Raphson method) to find a root of the polynomial y = p3*x^3 + p2*x^2 + p1*x + p0 in the interval x0 to x1.
|
||||
newtonsMethod( x0, x1, p3, p2, p1, p0, tolerance )
|
||||
{
|
||||
iterations = 5;
|
||||
x = ( x0 + x1 ) / 2;
|
||||
offset = tolerance + 1;
|
||||
while ( abs( offset ) > tolerance && iterations > 0)
|
||||
{
|
||||
value = (p3*x*x*x) + (p2*x*x) + (p1*x) + p0;
|
||||
slope = (3*p3*x*x) + (2*p2*x) + p1;
|
||||
AssertEx( slope != 0, "newtonsMethod found zero slope. Can't work with that." );
|
||||
offset = -1 * value / slope;
|
||||
oldx = x;
|
||||
x += offset;
|
||||
// Hack to keep the value within the bounds
|
||||
if ( x > x1 )
|
||||
x = ( oldX + (3*x1) ) / 4;
|
||||
else if ( x < x0 )
|
||||
x = ( oldX + (3*x0) ) / 4;
|
||||
iterations--;
|
||||
/# if ( iterations == 0 )
|
||||
Print( "_interactive_utility::newtonsMethod failed to converge. x0:"+x0+", x1:"+x1+", p3:"+p3+", p2:"+p2+", p1:"+p1+", p0:"+p0+", x:"+x );
|
||||
#/
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
// rootsOfCubic. Doesn't work.
|
||||
rootsOfCubic(a,b,c,d)
|
||||
{
|
||||
if ( a == 0 ) {
|
||||
return rootsOfQuadratic(b,c,d);
|
||||
}
|
||||
// I can't do this mathematically without having a cube root function.
|
||||
q = (2*b*b*b) - (9*a*b*c) + (27*a*a*d);
|
||||
//Q = sqrt( q*q*q );
|
||||
bSquared3ac = (b*b) - (3*a*c);
|
||||
if ( ( bSquared3ac == 0 ) )
|
||||
{
|
||||
// If ( bSquared3ac == 0 ) there's only one real root regardless of what q is, but I can't find it without a cube root function.
|
||||
// root = cubeRoot( d/a );
|
||||
}
|
||||
if ( q == 0 && bSquared3ac==0 )
|
||||
{
|
||||
x[0] = -1 * b / (3*a);
|
||||
}
|
||||
else if ( q == 0 && bSquared3ac!=0 )
|
||||
{
|
||||
// There's a double root that I don't care about since it isn't a change from acceleration to deceleration
|
||||
// The other root is
|
||||
x[0] = ( (9*a*a*d) - (4*a*b*c) + (b*b*b) ) / ( a * ( (3*a*c) - (b*b) ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Typical case...can't do it mathematically so do it numerically.
|
||||
// Need to break the curve into intervals and use Newton's Method above.
|
||||
}
|
||||
}
|
||||
|
||||
rootsOfQuadratic(a,b,c)
|
||||
{
|
||||
// The spline code generates some big numbers which cause errors due to overflow
|
||||
while ( abs(a)>65536 || abs(b)>65536 || abs(c)>65536 ) {
|
||||
a /= 10;
|
||||
b /= 10;
|
||||
c /= 10;
|
||||
}
|
||||
x = [];
|
||||
if ( a == 0 ) {
|
||||
if ( b != 0 ) {
|
||||
x[0] = -1 * c / b;
|
||||
}
|
||||
}
|
||||
else {
|
||||
bSquared4ac = (b*b) - (4*a*c);
|
||||
if ( bSquared4ac > 0 ) {
|
||||
x[0] = ( (-1*b) - sqrt( bSquared4ac ) ) / (2*a);
|
||||
x[1] = ( (-1*b) + sqrt( bSquared4ac ) ) / (2*a);
|
||||
}
|
||||
else if ( bSquared4ac == 0 ) {
|
||||
x[0] = -1 * b / (2*a);
|
||||
}
|
||||
}
|
||||
// Note: If there are no roots, x will be empty.
|
||||
return x;
|
||||
}
|
||||
|
||||
// NonVectorLength
|
||||
// Just like Length, but gets the length of a vector represented as an array.
|
||||
// Optional second array will be sutracted (per-component) from the first. That is, NonVectorLength(origin1,origtin2) is the same as Length(origin1-origin2).
|
||||
NonVectorLength( array, array2 )
|
||||
{
|
||||
AssertEx( ( !IsDefined(array2) ) || ( array.size==array2.size ), "NonVectorLength: second array must have same number of components as first array." );
|
||||
sum = 0;
|
||||
for ( i=0; i<array.size; i++ )
|
||||
{
|
||||
value = array[i];
|
||||
if ( IsDefined(array2) ) value -= array2[i];
|
||||
sum += value*value;
|
||||
}
|
||||
return sqrt( sum );
|
||||
}
|
||||
|
||||
// clampAndNormalize
|
||||
// Clamps x to the range min-max and then divides it by that range, to give a result between 0 and 1.
|
||||
// Works for min<max and max<min.
|
||||
clampAndNormalize( x, min, max )
|
||||
{
|
||||
AssertEx( min != max, "clampAndNormalize: min must not equal max" );
|
||||
if ( min < max )
|
||||
x = clamp( x, min, max );
|
||||
else x = clamp( x, max, min );
|
||||
return ( x - min ) / (max - min );
|
||||
}
|
||||
|
||||
PointOnCircle( center, radius, deg )
|
||||
{
|
||||
x = Cos( deg );
|
||||
x *= radius;
|
||||
x += center[0];
|
||||
y = Sin( deg );
|
||||
y *= radius;
|
||||
y += center[1];
|
||||
z = center[2];
|
||||
return (x,y,z);
|
||||
}
|
||||
|
||||
zeroComponent( vector, comp )
|
||||
{
|
||||
return ( vector[0] * (comp != 0 ), vector[1] * (comp != 1 ), vector[2] * (comp != 2 ) );
|
||||
}
|
||||
|
||||
rotate90AroundAxis( vector, comp )
|
||||
{
|
||||
if ( comp == 0 )
|
||||
{
|
||||
return ( vector[0], vector[2], -1 * vector[1] );
|
||||
}
|
||||
else if ( comp == 1 )
|
||||
{
|
||||
return ( -1 * vector[2], vector[1], vector[0] );
|
||||
}
|
||||
else
|
||||
{
|
||||
return ( vector[1], -1 * vector[0], vector[2] );
|
||||
}
|
||||
}
|
136
maps/interactive_models/batcave.gsc
Normal file
136
maps/interactive_models/batcave.gsc
Normal file
@ -0,0 +1,136 @@
|
||||
/*
|
||||
* How to use this script:
|
||||
* You need an exploder which creates the FX of the bats flying,
|
||||
* and an animation which moves "tag_attach" along the flight path (for the sound).
|
||||
* You need a trigger with a targetname, to detect if players are close to the bats spawn location.
|
||||
* Then, just call vfxBatCaveWaitInit() with all those things.
|
||||
*/
|
||||
#include common_scripts\utility;
|
||||
|
||||
VFX_BAT_COOLDOWN = 60;
|
||||
|
||||
/*
|
||||
=============
|
||||
///ScriptDocBegin
|
||||
"Name: vfxBatCaveWaitInit( <triggername> , <exploderID> , <audioAnim> , <pos> , <emptyRoomCooldown> )"
|
||||
"Summary: Sets up a bat colony to detect players and play a bat exploder when a player fires his/her weapon nearby."
|
||||
"Module: "
|
||||
"CallOn: "
|
||||
"MandatoryArg: <triggername>: Targetname of a trigger that will detect players."
|
||||
"MandatoryArg: <exploderID>: ID of the exploder to be triggered."
|
||||
"OptionalArg: <audioAnim>: Animation with 'tag_attach' moving along the path of the EFX, for a sound to be attached to."
|
||||
"OptionalArg: <pos>: Position of the exploder, for the animation to be placed at."
|
||||
"OptionalArg: <emptyRoomCooldown>: Time the trigger must be undisturbed before the exploder can fire again. If undefined or 0, the exploder can fire periodically even the trigger has never been empty."
|
||||
"Example: thread vfxBatCaveWaitInit( "bats_1", 1, "bats_flyaway_1", (-2028, 464, 413) );"
|
||||
"SPMP: both"
|
||||
///ScriptDocEnd
|
||||
=============
|
||||
*/
|
||||
|
||||
vfxBatCaveWaitInit( triggername, exploderID, audioAnim, pos, emptyRoomCooldown )
|
||||
{
|
||||
if ( !IsDefined( emptyRoomCooldown ) )
|
||||
emptyRoomCooldown = 0;
|
||||
|
||||
level endon( "game_ended" );
|
||||
|
||||
// get the trigger
|
||||
trigger = GetEnt( triggername, "targetname" );
|
||||
if ( IsDefined( trigger ) )
|
||||
{
|
||||
trigger childthread vfxBatCaveTrigger( exploderID, audioAnim, pos );
|
||||
trigger childthread vfxBatCaveWatchForEmpty( emptyRoomCoolDown );
|
||||
|
||||
while ( true )
|
||||
{
|
||||
trigger waittill( "trigger", player );
|
||||
|
||||
trigger thread vfxBatCaveWatchPlayerState( player );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vfxBatCaveWatchPlayerState( player ) // self == bat trigger
|
||||
{
|
||||
// if any other player starts the bats, stop checking
|
||||
self endon( "batCaveTrigger" );
|
||||
|
||||
player endon( "death" );
|
||||
player endon( "disconnect" );
|
||||
|
||||
// make sure we aren't already runnning one
|
||||
player notify( "batCaveExit" );
|
||||
player endon( "batCaveExit" );
|
||||
|
||||
self childthread vfxBatCaveWatchPlayerWeapons( player );
|
||||
|
||||
// this detects if the player has exited the trigger
|
||||
while ( player IsTouching( self ) )
|
||||
{
|
||||
waitframe();
|
||||
self.lastTouchedTime = GetTime();
|
||||
}
|
||||
|
||||
player notify( "batCaveExit" );
|
||||
}
|
||||
|
||||
vfxBatCaveWatchPlayerWeapons( player )
|
||||
{
|
||||
player waittill( "weapon_fired" );
|
||||
self notify ( "batCaveTrigger" );
|
||||
}
|
||||
|
||||
vfxBatCaveWatchForEmpty( emptyRoomCoolDown )
|
||||
{
|
||||
self.lastTouchedTime = GetTime();
|
||||
self.batCaveReset = true;
|
||||
while ( true )
|
||||
{
|
||||
waitframe();
|
||||
if ( self.lastTouchedTime + emptyRoomCoolDown <= GetTime() ) {
|
||||
self.batCaveReset = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vfxBatCaveTrigger( exploderID, audioAnim, pos )
|
||||
{
|
||||
/#
|
||||
SetDvarIfUninitialized( "scr_dbg_batcave_cooldown", VFX_BAT_COOLDOWN );
|
||||
#/
|
||||
|
||||
while ( true )
|
||||
{
|
||||
self waittill( "batCaveTrigger" );
|
||||
|
||||
if ( self.batCaveReset ) {
|
||||
vfxBatsFly( exploderID, audioAnim, pos );
|
||||
self.batCaveReset = false;
|
||||
|
||||
waitTime = VFX_BAT_COOLDOWN;
|
||||
/#
|
||||
waitTime = GetDvarInt( "scr_dbg_batcave_cooldown" );
|
||||
#/
|
||||
|
||||
wait ( waitTime );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Plays the bats effect and moving sound
|
||||
vfxBatsFly(exploderID, audioAnim, pos)
|
||||
{
|
||||
exploder(exploderID); // It's become pretty pointless to do these as exploders, but it works, so I'm leaving it for now.
|
||||
|
||||
// Play a sound that moves with the bats as they fly.
|
||||
if ( IsDefined(audioAnim) && IsDefined(pos) ) {
|
||||
soundrig = Spawn( "script_model", pos );
|
||||
soundrig SetModel( "vulture_circle_rig" );
|
||||
soundrig ScriptModelPlayAnim( audioAnim );
|
||||
dummy = Spawn( "script_model", soundrig GetTagOrigin( "tag_attach" ) );
|
||||
dummy LinkTo( soundrig, "tag_attach" );
|
||||
wait(0.1); // Without this the sound won't play. Because the tag is inside the wall?
|
||||
dummy PlaySoundOnMovingEnt( "scn_mp_swamp_bat_cave_big" );
|
||||
}
|
||||
}
|
||||
|
78
maps/interactive_models/crows_dlc.gsc
Normal file
78
maps/interactive_models/crows_dlc.gsc
Normal file
@ -0,0 +1,78 @@
|
||||
// Interactive_models\crows_dlc.gsc
|
||||
|
||||
// At Nate's suggestion I'm trying not to entangle this with other systems. There are some things I can't avoid though.
|
||||
// I introduced a level array called "_interactive" that I'll use for all this stuff that isn't a traditional destructible.
|
||||
// However, my intention is that any given type of interactive object can have its own struct in this array.
|
||||
// Crows are interactive_birds. They have a rig that all the birds attach to and different bird models for flying vs sitting.
|
||||
|
||||
// The 'dlc' version uses modified mp animations, which are hacky but still, it should be copied over the original version if
|
||||
// we plan to continue using it for the next game. (NB: It hasn't been tested in SP yet.)
|
||||
#include common_scripts\utility;
|
||||
|
||||
#using_animtree( "animals_dlc" );
|
||||
main()
|
||||
{
|
||||
info = SpawnStruct();
|
||||
info.interactive_type = "crows_dlc";
|
||||
info.rig_model = "use_radiant_model";
|
||||
info.rig_animtree = #animtree;
|
||||
info.rig_numtags = 2;//backup, really handled in Radiant
|
||||
info.bird_model["idle"] = "crow_fly";
|
||||
info.bird_model["fly"] = "crow_fly";
|
||||
info.bird_animtree = #animtree;
|
||||
info.topSpeed = 300; // Inches per second.
|
||||
info.accn = 75; // Use this for both acceleration and deceleration.
|
||||
info.scareRadius = 600; // Default distance at which pigeons will leave perch to avoid player or AI.
|
||||
info.death_effect = LoadFX( "fx/props/bird_feather_exp_black" );
|
||||
info.birdmodel_anims = [];
|
||||
info.rigmodel_anims = [];
|
||||
info.birdmodel_anims[ "idle" ][ 0 ] = %crow_idle_1;
|
||||
info.birdmodel_anims[ "idleweight" ][ 0 ] = 1;
|
||||
info.birdmodel_anims[ "idle" ][ 1 ] = %crow_idle_2;
|
||||
info.birdmodel_anims[ "idleweight" ][ 1 ] = 0.3;
|
||||
info.birdmodel_anims[ "flying" ] = %crow_fly;
|
||||
info.rigmodel_anims[ "flying" ] = %pigeon_flock_fly_loop;
|
||||
info.rigmodel_anims[ "takeoff_wire" ] = %pigeon_flock_takeoff_wire; // These match the Radiant keypairs "interactive_takeoffAnim" and "interactive_landAnim"
|
||||
info.rigmodel_anims[ "land_wire" ] = %pigeon_flock_land_wire;
|
||||
info.rigmodel_anims[ "takeoff_ground" ] = %pigeon_flock_takeoff_ground;
|
||||
info.rigmodel_anims[ "land_ground" ] = %pigeon_flock_land_ground;
|
||||
info.rigmodel_anims[ "takeoff_inpipe" ] = %pigeon_flock_takeoff_inpipe;
|
||||
info.rigmodel_anims[ "land_inpipe" ] = %pigeon_flock_land_inpipe;
|
||||
if ( !isSP() ) {
|
||||
info.birdmodel_anims[ "idlemp" ][ 0 ] = "crow_idle_1";
|
||||
info.birdmodel_anims[ "idlemp" ][ 1 ] = "crow_idle_2";
|
||||
info.birdmodel_anims[ "flyingmp" ] = "crow_fly";
|
||||
// These _mp animations for the rig are a hack. They are identical to the SP animations in length and
|
||||
// motion, but keep the tags all facing forward, since the MP animations can't be rotated the same way
|
||||
// the SP ones can.
|
||||
info.rigmodel_anims[ "flyingmp" ] = "pigeon_flock_fly_loop_mp";
|
||||
info.rigmodel_anims[ "takeoff_wiremp" ] = "pigeon_flock_takeoff_wire_mp";
|
||||
info.rigmodel_anims[ "land_wiremp" ] = "pigeon_flock_land_wire_mp";
|
||||
info.rigmodel_anims[ "takeoff_groundmp" ] = "pigeon_flock_takeoff_ground_mp";
|
||||
info.rigmodel_anims[ "land_groundmp" ] = "pigeon_flock_land_ground_mp";
|
||||
info.rigmodel_anims[ "takeoff_inpipemp" ] = "pigeon_flock_takeoff_inpipe_mp";
|
||||
info.rigmodel_anims[ "land_inpipemp" ] = "pigeon_flock_land_inpipe_mp";
|
||||
/*info.rigmodel_anims[ "flyingmp" ] = "pigeon_flock_fly_loop";
|
||||
info.rigmodel_anims[ "takeoff_wiremp" ] = "pigeon_flock_takeoff_wire";
|
||||
info.rigmodel_anims[ "land_wiremp" ] = "pigeon_flock_land_wire";
|
||||
info.rigmodel_anims[ "takeoff_groundmp" ] = "pigeon_flock_takeoff_ground";
|
||||
info.rigmodel_anims[ "land_groundmp" ] = "pigeon_flock_land_ground";
|
||||
info.rigmodel_anims[ "takeoff_inpipemp" ] = "pigeon_flock_takeoff_inpipe";
|
||||
info.rigmodel_anims[ "land_inpipemp" ] = "pigeon_flock_land_inpipe";*/
|
||||
|
||||
}
|
||||
info.sounds = [];
|
||||
info.sounds[ "takeoff" ] = "anml_crow_startle_flyaway";
|
||||
info.sounds[ "idle" ] = "anml_crow_idle";
|
||||
//TODO JL will also need to change KVPs in 'prefabs/mp_shipment_ns/shns_interactive_crows.map' from 'sound_csv_include:animal_bird' to the new csv
|
||||
|
||||
PreCacheModel( info.rig_model );
|
||||
foreach ( model in info.bird_model ) {
|
||||
PreCacheModel( model );
|
||||
}
|
||||
|
||||
if( !isdefined ( level._interactive ) )
|
||||
level._interactive = [];
|
||||
level._interactive[ info.interactive_type ] = info;
|
||||
thread maps\interactive_models\_birds_dlc::birds(info);
|
||||
}
|
76
maps/interactive_models/parakeets_dlc.gsc
Normal file
76
maps/interactive_models/parakeets_dlc.gsc
Normal file
@ -0,0 +1,76 @@
|
||||
// Interactive_models\Parakeets.gsc
|
||||
|
||||
// At Nate's suggestion I'm trying not to entangle this with other systems. There are some things I can't avoid though.
|
||||
// I introduced a level array called "_interactive" that I'll use for all this stuff that isn't a traditional destructible.
|
||||
// However, my intention is that any given type of interactive object can have its own struct in this array.
|
||||
// Parakeets are interactive_birds. They have a rig that all the birds attach to and different bird models for flying vs sitting.
|
||||
|
||||
// The 'dlc' version uses modified mp animations, which are hacky but still, it should be copied over the original version if
|
||||
// we plan to continue using it for the next game. (NB: It hasn't been tested in SP yet.)
|
||||
#include common_scripts\utility;
|
||||
|
||||
#using_animtree( "animals_dlc" );
|
||||
main()
|
||||
{
|
||||
info = SpawnStruct();
|
||||
info.interactive_type = "parakeets_dlc";
|
||||
info.rig_model = "pigeon_flock_rig";
|
||||
info.rig_animtree = #animtree;
|
||||
info.rig_numtags = 12;
|
||||
info.bird_model["idle"] = "parakeet";
|
||||
info.bird_model["fly"] = "parakeet_fly";
|
||||
info.bird_animtree = #animtree;
|
||||
info.topSpeed = 600; // Inches per second.
|
||||
info.accn = 150; // Use this for both acceleration and deceleration.
|
||||
info.scareRadius = 300; // Default distance at which pigeons will leave perch to avoid player or AI.
|
||||
info.death_effect = LoadFX( "fx/props/chicken_exp_white" );
|
||||
info.birdmodel_anims = [];
|
||||
info.rigmodel_anims = [];
|
||||
info.birdmodel_anims[ "idle" ][ 0 ] = %pigeon_idle;
|
||||
info.birdmodel_anims[ "idleweight" ][ 0 ] = 1;
|
||||
info.birdmodel_anims[ "idle" ][ 1 ] = %pigeon_idle_twitch_1;
|
||||
info.birdmodel_anims[ "idleweight" ][ 1 ] = 0.3;
|
||||
info.birdmodel_anims[ "flying" ] = %pigeon_flying_cycle;
|
||||
info.rigmodel_anims[ "flying" ] = %pigeon_flock_fly_loop;
|
||||
info.rigmodel_anims[ "takeoff_wire" ] = %pigeon_flock_takeoff_wire; // These match the Radiant keypairs "interactive_takeoffAnim" and "interactive_landAnim"
|
||||
info.rigmodel_anims[ "land_wire" ] = %pigeon_flock_land_wire;
|
||||
info.rigmodel_anims[ "takeoff_ground" ] = %pigeon_flock_takeoff_ground;
|
||||
info.rigmodel_anims[ "land_ground" ] = %pigeon_flock_land_ground;
|
||||
info.rigmodel_anims[ "takeoff_inpipe" ] = %pigeon_flock_takeoff_inpipe;
|
||||
info.rigmodel_anims[ "land_inpipe" ] = %pigeon_flock_land_inpipe;
|
||||
if ( !isSP() ) {
|
||||
info.birdmodel_anims[ "idlemp" ][ 0 ] = "pigeon_idle";
|
||||
info.birdmodel_anims[ "idlemp" ][ 1 ] = "pigeon_idle_twitch_1";
|
||||
info.birdmodel_anims[ "flyingmp" ] = "pigeon_flying_cycle";
|
||||
// These _mp animations for the rig are a hack. They are identical to the SP animations in length and
|
||||
// motion, but keep the tags all facing forward, since the MP animations can't be rotated the same way
|
||||
// the SP ones can.
|
||||
info.rigmodel_anims[ "flyingmp" ] = "pigeon_flock_fly_loop_mp";
|
||||
info.rigmodel_anims[ "takeoff_wiremp" ] = "pigeon_flock_takeoff_wire_mp";
|
||||
info.rigmodel_anims[ "land_wiremp" ] = "pigeon_flock_land_wire_mp";
|
||||
info.rigmodel_anims[ "takeoff_groundmp" ] = "pigeon_flock_takeoff_ground_mp";
|
||||
info.rigmodel_anims[ "land_groundmp" ] = "pigeon_flock_land_ground_mp";
|
||||
info.rigmodel_anims[ "takeoff_inpipemp" ] = "pigeon_flock_takeoff_inpipe_mp";
|
||||
info.rigmodel_anims[ "land_inpipemp" ] = "pigeon_flock_land_inpipe_mp";
|
||||
/*info.rigmodel_anims[ "flyingmp" ] = "pigeon_flock_fly_loop";
|
||||
info.rigmodel_anims[ "takeoff_wiremp" ] = "pigeon_flock_takeoff_wire";
|
||||
info.rigmodel_anims[ "land_wiremp" ] = "pigeon_flock_land_wire";
|
||||
info.rigmodel_anims[ "takeoff_groundmp" ] = "pigeon_flock_takeoff_ground";
|
||||
info.rigmodel_anims[ "land_groundmp" ] = "pigeon_flock_land_ground";
|
||||
info.rigmodel_anims[ "takeoff_inpipemp" ] = "pigeon_flock_takeoff_inpipe";
|
||||
info.rigmodel_anims[ "land_inpipemp" ] = "pigeon_flock_land_inpipe";*/
|
||||
|
||||
}
|
||||
info.sounds = [];
|
||||
info.sounds[ "takeoff" ] = "anml_bird_startle_flyaway";
|
||||
|
||||
PreCacheModel( info.rig_model );
|
||||
foreach ( model in info.bird_model ) {
|
||||
PreCacheModel( model );
|
||||
}
|
||||
|
||||
if( !isdefined ( level._interactive ) )
|
||||
level._interactive = [];
|
||||
level._interactive[ info.interactive_type ] = info;
|
||||
thread maps\interactive_models\_birds_dlc::birds(info);
|
||||
}
|
96
maps/interactive_models/vulture_mp.gsc
Normal file
96
maps/interactive_models/vulture_mp.gsc
Normal file
@ -0,0 +1,96 @@
|
||||
#include common_scripts\utility;
|
||||
|
||||
/*
|
||||
=============
|
||||
///ScriptDocBegin
|
||||
"Name: vulture_circling( <origin> )"
|
||||
"Summary: Creates a vulture circling around the specified origin. Don't forget to include interactive_vulture_circling.csv in your zone file."
|
||||
"Module: "
|
||||
"CallOn: Nothing"
|
||||
"MandatoryArg: <origin>: A vector specifying a point in space."
|
||||
"Example: vulture_circling((105, -1320, 1600));"
|
||||
"SPMP: Both"
|
||||
///ScriptDocEnd
|
||||
=============
|
||||
*/
|
||||
|
||||
vulture_circling(origin, number)
|
||||
{
|
||||
if ( !IsDefined(number) )
|
||||
number = 1;
|
||||
if ( !IsDefined(level._interactive) ) {
|
||||
level._interactive = [];
|
||||
}
|
||||
if ( !IsDefined(level._interactive["vultures"]) ) {
|
||||
level._interactive["vultures"]["count"] = 0;
|
||||
level._interactive["vultures"]["anims"][0] = "vulture_rig_circle";
|
||||
level._interactive["vultures"]["anims"][1] = "vulture_rig_circle2";
|
||||
level._interactive["vultures"]["anims"][2] = "vulture_rig_circle3";
|
||||
level._interactive["vultures"]["rigs"] = [];
|
||||
level._interactive["vultures"]["vultures"] = [];
|
||||
}
|
||||
for ( i=0; i<number; i++ ) {
|
||||
newOrigin = origin + ( (0,0,50) * i );
|
||||
if ( i > 0 )
|
||||
newOrigin += (0,0,RandomIntRange(-20,20));
|
||||
thread vulture_circling_internal(newOrigin);
|
||||
}
|
||||
}
|
||||
|
||||
vulture_circling_internal(origin)
|
||||
{
|
||||
count = level._interactive["vultures"]["rigs"].size;
|
||||
|
||||
yaw = RandomInt(360);
|
||||
|
||||
rig = Spawn( "script_model", origin );
|
||||
rig.angles = (0, yaw, 0);
|
||||
rig SetModel( "vulture_circle_rig" );
|
||||
|
||||
vulture = Spawn( "script_model", rig.origin );
|
||||
vulture.angles = (0, yaw, 0);
|
||||
vulture SetModel( "ng_vulture" );
|
||||
|
||||
vulture LinkTo( rig, "tag_attach" );
|
||||
riganim = level._interactive["vultures"]["anims"][mod(count, 3)];
|
||||
rig ScriptModelPlayAnim( riganim );
|
||||
level._interactive["vultures"]["vultures"][count] = vulture;
|
||||
level._interactive["vultures"]["rigs"][count] = rig;
|
||||
|
||||
vulture endon("death");
|
||||
wait( RandomFloat(5) );
|
||||
vulture ScriptModelPlayAnim( "vulture_fly_loop_all" );
|
||||
}
|
||||
|
||||
/#
|
||||
vultures_toggle_thread()
|
||||
{
|
||||
SetDevDvar("vultures_enable", "1");
|
||||
while ( true ) {
|
||||
while( GetDvarInt("vultures_enable") >= 1 )
|
||||
{
|
||||
wait .5;
|
||||
}
|
||||
IPrintLn("Deleting vultures");
|
||||
positions = [];
|
||||
foreach (vulture in level._interactive["vultures"]["vultures"] ) {
|
||||
vulture Delete();
|
||||
}
|
||||
foreach ( rig in level._interactive["vultures"]["rigs"] ) {
|
||||
positions[positions.size] = rig.origin;
|
||||
rig Delete();
|
||||
}
|
||||
level._interactive["vultures"]["rigs"] = [];
|
||||
level._interactive["vultures"]["vultures"] = [];
|
||||
|
||||
while( GetDvarInt("vultures_enable") < 1 )
|
||||
{
|
||||
wait .5;
|
||||
}
|
||||
IPrintLn("Adding vultures");
|
||||
foreach ( position in positions ) {
|
||||
thread vulture_circling(position);
|
||||
}
|
||||
}
|
||||
}
|
||||
#/
|
63
maps/mp/_animatedmodels.gsc
Normal file
63
maps/mp/_animatedmodels.gsc
Normal file
@ -0,0 +1,63 @@
|
||||
#include common_scripts\utility;
|
||||
|
||||
#using_animtree( "animated_props" );
|
||||
main()
|
||||
{
|
||||
//level.init_animatedmodels_dump = false;
|
||||
|
||||
if ( !isdefined( level.anim_prop_models ) )
|
||||
level.anim_prop_models = []; // this is what the LD puts in their map
|
||||
|
||||
// Do special MP anim precaching
|
||||
model_keys = GetArrayKeys( level.anim_prop_models );
|
||||
foreach ( model_key in model_keys )
|
||||
{
|
||||
anim_keys = GetArrayKeys( level.anim_prop_models[model_key] );
|
||||
foreach ( anim_key in anim_keys )
|
||||
PrecacheMpAnim( level.anim_prop_models[model_key][anim_key] );
|
||||
//PrecacheMpAnim( level.anim_prop_models[ "foliage_tree_palm_bushy_1" ][ "strong" ] );
|
||||
}
|
||||
|
||||
// wait until the end of the frame so that maps can init their trees
|
||||
// in their _anim instead of only above _load
|
||||
waittillframeend;
|
||||
|
||||
level.init_animatedmodels = [];
|
||||
|
||||
animated_models = getentarray( "animated_model", "targetname" );
|
||||
//array_thread( animated_models, ::model_init );
|
||||
|
||||
// one or more of the models initialized by model_init() was not setup by the map
|
||||
// so print this helpful note so the designer can see how to add it ot their level
|
||||
//if ( level.init_animatedmodels_dump )
|
||||
//assertmsg( "anims not cached for animated prop model, Repackage Zones and Rebuild Precache Script in Launcher:" );
|
||||
|
||||
array_thread_amortized( animated_models, ::animateModel, 0.05 );
|
||||
|
||||
level.init_animatedmodels = undefined;
|
||||
}
|
||||
|
||||
// Disabled for now since we are precaching .animation prefabs in a non-standard way
|
||||
/*model_init()
|
||||
{
|
||||
if ( !isdefined( level.anim_prop_models[ self.model ] ) )
|
||||
level.init_animatedmodels_dump = true;
|
||||
}*/
|
||||
|
||||
// TODO: When we have multiple animations, instead of choosing randomly, do round-robin to get an even spread
|
||||
animateModel()
|
||||
{
|
||||
if ( IsDefined( self.animation ) )
|
||||
{
|
||||
animation = self.animation;
|
||||
}
|
||||
else
|
||||
{
|
||||
keys = GetArrayKeys( level.anim_prop_models[ self.model ] );
|
||||
animkey = keys[ RandomInt( keys.size ) ];
|
||||
animation = level.anim_prop_models[ self.model ][ animkey ];
|
||||
}
|
||||
|
||||
self ScriptModelPlayAnim( animation );
|
||||
self willNeverChange();
|
||||
}
|
98
maps/mp/_areas.gsc
Normal file
98
maps/mp/_areas.gsc
Normal file
@ -0,0 +1,98 @@
|
||||
#include maps\mp\_utility;
|
||||
#include common_scripts\utility;
|
||||
|
||||
/*QUAKED trigger_multiple_area (0.12 0.23 1.0)
|
||||
defaulttexture="trigger"
|
||||
"script_area" - A localized string that names the area. e.g. "MP_FLOWER_SHOP"
|
||||
Defines an area that the player is in.*/
|
||||
|
||||
/*QUAKED trigger_multiple_softlanding (0.12 0.23 1.0)
|
||||
defaulttexture="trigger"
|
||||
"script_type" - "car", "boxes", "trash"
|
||||
Defines a soft landing area.*/
|
||||
|
||||
|
||||
init()
|
||||
{
|
||||
level.softLandingTriggers = getEntArray( "trigger_multiple_softlanding", "classname" );
|
||||
|
||||
destructibles = getEntArray( "destructible_vehicle", "targetname" );
|
||||
|
||||
foreach ( trigger in level.softLandingTriggers )
|
||||
{
|
||||
if ( trigger.script_type != "car" )
|
||||
continue;
|
||||
|
||||
foreach ( destructible in destructibles )
|
||||
{
|
||||
/*
|
||||
if ( !trigger isTouching( destructible ) )
|
||||
{
|
||||
println( distance( trigger.origin, destructible.origin ) );
|
||||
continue;
|
||||
}
|
||||
*/
|
||||
|
||||
if ( distance( trigger.origin, destructible.origin ) > 64.0 )
|
||||
continue;
|
||||
|
||||
assert( !isDefined( trigger.destructible ) );
|
||||
|
||||
trigger.destructible = destructible;
|
||||
}
|
||||
}
|
||||
|
||||
//foreach ( trigger in level.softLandingTriggers )
|
||||
// trigger thread common_scripts\_dynamic_world::triggerTouchThink( ::playerEnterSoftLanding, ::playerLeaveSoftLanding );
|
||||
|
||||
thread onPlayerConnect();
|
||||
}
|
||||
|
||||
|
||||
onPlayerConnect()
|
||||
{
|
||||
for ( ;; )
|
||||
{
|
||||
level waittill ( "connected", player );
|
||||
|
||||
player.softLanding = undefined;
|
||||
|
||||
player thread softLandingWaiter();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
playerEnterSoftLanding( trigger )
|
||||
{
|
||||
self.softLanding = trigger;
|
||||
}
|
||||
|
||||
|
||||
playerLeaveSoftLanding( trigger )
|
||||
{
|
||||
self.softLanding = undefined;
|
||||
}
|
||||
|
||||
|
||||
softLandingWaiter()
|
||||
{
|
||||
self endon ( "disconnect" );
|
||||
|
||||
for ( ;; )
|
||||
{
|
||||
self waittill ( "soft_landing", trigger, damage );
|
||||
|
||||
//if ( damage < 10 )
|
||||
// continue;
|
||||
|
||||
if ( !isDefined( trigger.destructible ) )
|
||||
continue;
|
||||
|
||||
//magicBullet( "mp5_mp", self.origin, self.origin + (0,0,-100), self );
|
||||
|
||||
//self waittill( "damage", damage, attacker, direction_vec, point, type, modelName, tagName, partName, dflags );
|
||||
|
||||
//traceData = bulletTrace( self.origin, self.origin + (0,0,-100), true, self );
|
||||
|
||||
}
|
||||
}
|
714
maps/mp/_art.gsc
Normal file
714
maps/mp/_art.gsc
Normal file
@ -0,0 +1,714 @@
|
||||
// This function should take care of grain and glow settings for each map, plus anything else that artists
|
||||
// need to be able to tweak without bothering level designers.
|
||||
#include common_scripts\utility;
|
||||
#include common_scripts\_artCommon;
|
||||
#include maps\mp\_utility;
|
||||
|
||||
main()
|
||||
{
|
||||
/#
|
||||
PrecacheMenu( "dev_vision_noloc" );
|
||||
PrecacheMenu( "dev_vision_exec" );
|
||||
|
||||
setDevDvarIfUninitialized( "scr_art_tweak", 0 );
|
||||
setDevDvarIfUninitialized( "scr_cmd_plr_sun", "0" );
|
||||
SetDevDvarIfUninitialized( "scr_cmd_plr_sunflare", "0" );
|
||||
setDevDvarIfUninitialized( "scr_art_visionfile", level.script );
|
||||
SetDevDvar( "r_artUseTweaks", false );
|
||||
|
||||
thread tweakart();
|
||||
|
||||
tess_init();
|
||||
|
||||
if ( !isdefined( level.script ) )
|
||||
level.script = ToLower( GetDvar( "mapname" ) );
|
||||
#/
|
||||
}
|
||||
|
||||
/#
|
||||
initTweaks()
|
||||
{
|
||||
SetDevDvar( "r_artUseTweaks", true );
|
||||
|
||||
if ( IsDefined( level.parse_fog_func ) )
|
||||
[[level.parse_fog_func]]();
|
||||
|
||||
if ( !IsDefined( level.buttons ) )
|
||||
level.buttons = [];
|
||||
|
||||
level._clearalltextafterhudelem = false;
|
||||
|
||||
if ( !IsDefined( level.vision_set_names ) )
|
||||
level.vision_set_names = [];
|
||||
|
||||
if( !IsDefined( level.vision_set_fog ) )
|
||||
{
|
||||
level.vision_set_fog = [];
|
||||
create_default_vision_set_fog( level.script );
|
||||
common_scripts\_artCommon::setfogsliders();
|
||||
}
|
||||
|
||||
foreach( key, value in level.vision_set_fog )
|
||||
{
|
||||
common_scripts\_artCommon::add_vision_set_to_list( key );
|
||||
}
|
||||
|
||||
add_vision_sets_from_triggers();
|
||||
|
||||
update_current_vision_set_dvars();
|
||||
|
||||
if ( !IsDefined( level.current_vision_set ) )
|
||||
level.current_vision_set = GetDvar( "r_artTweaksLastVisionSet", "" );
|
||||
|
||||
IPrintLnBold( "ART TWEAK ENABLED" );
|
||||
hud_init();
|
||||
|
||||
last_vision_set = level.current_vision_set;
|
||||
if ( !IsDefined( last_vision_set ) || last_vision_set == "" )
|
||||
last_vision_set = level.script;
|
||||
|
||||
setcurrentgroup( last_vision_set );
|
||||
}
|
||||
|
||||
tweakart()
|
||||
{
|
||||
if ( !isdefined( level.tweakfile ) )
|
||||
level.tweakfile = false;
|
||||
|
||||
// not in DEVGUI
|
||||
SetDevDvar( "scr_fog_fraction", "1.0" );
|
||||
SetDevDvar( "scr_art_dump", "0" );
|
||||
|
||||
printed = false;
|
||||
|
||||
last_vision_set = "";
|
||||
|
||||
for ( ;; )
|
||||
{
|
||||
while ( GetDvarInt( "scr_art_tweak", 0 ) == 0 )
|
||||
wait .05;
|
||||
|
||||
if ( !printed )
|
||||
{
|
||||
printed = true;
|
||||
initTweaks();
|
||||
}
|
||||
|
||||
//translate the slider values to script variables
|
||||
common_scripts\_artCommon::translateFogSlidersToScript();
|
||||
|
||||
common_scripts\_artCommon::fogslidercheck();
|
||||
|
||||
updateSunFlarePosition();
|
||||
|
||||
dumpsettings();
|
||||
|
||||
updateFogFromScript();
|
||||
|
||||
if ( getdvarint( "scr_select_art_next" ) || button_down( "dpad_down", "kp_downarrow" ) )
|
||||
setgroup_down();
|
||||
else if ( getdvarint( "scr_select_art_prev" ) || button_down( "dpad_up", "kp_uparrow" ) )
|
||||
setgroup_up();
|
||||
else if( level.current_vision_set != last_vision_set )
|
||||
{
|
||||
last_vision_set = level.current_vision_set;
|
||||
setcurrentgroup( last_vision_set );
|
||||
}
|
||||
|
||||
wait .05;
|
||||
}
|
||||
}
|
||||
|
||||
tess_init()
|
||||
{
|
||||
using_tessellation = GetDvar( "r_tessellation" );
|
||||
if( using_tessellation == "" )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
level.tess = SpawnStruct();
|
||||
|
||||
// Default Tessellation Values - push base settings to game values
|
||||
level.tess.cutoff_distance_current = GetDvarFloat( "r_tessellationCutoffDistanceBase", 960.0 );
|
||||
level.tess.cutoff_distance_goal = level.tess.cutoff_distance_current;
|
||||
level.tess.cutoff_falloff_current = GetDvarFloat( "r_tessellationCutoffFalloffBase", 320.0 );
|
||||
level.tess.cutoff_falloff_goal = level.tess.cutoff_falloff_current;
|
||||
level.tess.time_remaining = 0.0;
|
||||
SetDvar( "r_tessellationCutoffDistance", level.tess.cutoff_distance_current );
|
||||
SetDvar( "r_tessellationCutoffFalloff" , level.tess.cutoff_falloff_current );
|
||||
|
||||
thread tess_update();
|
||||
}
|
||||
|
||||
tess_set_goal( cutoff_distance, cutoff_falloff, blend_time )
|
||||
{
|
||||
level.tess.cutoff_distance_goal = cutoff_distance;
|
||||
level.tess.cutoff_falloff_goal = cutoff_falloff;
|
||||
level.tess.time_remaining = blend_time;
|
||||
}
|
||||
|
||||
tess_update()
|
||||
{
|
||||
while ( 1 )
|
||||
{
|
||||
cutoff_distance_old = level.tess.cutoff_distance_current;
|
||||
cutoff_falloff_old = level.tess.cutoff_falloff_current;
|
||||
|
||||
waitframe();
|
||||
if ( level.tess.time_remaining > 0.0 )
|
||||
{
|
||||
frames = level.tess.time_remaining * 20;
|
||||
distance_increment = ( level.tess.cutoff_distance_goal - level.tess.cutoff_distance_current ) / frames;
|
||||
falloff_increment = ( level.tess.cutoff_falloff_goal - level.tess.cutoff_falloff_current ) / frames;
|
||||
level.tess.cutoff_distance_current += distance_increment;
|
||||
level.tess.cutoff_falloff_current += falloff_increment;
|
||||
level.tess.time_remaining -= 0.05;
|
||||
}
|
||||
else
|
||||
{
|
||||
level.tess.cutoff_distance_current = level.tess.cutoff_distance_goal;
|
||||
level.tess.cutoff_falloff_current = level.tess.cutoff_falloff_goal;
|
||||
}
|
||||
|
||||
if( cutoff_distance_old != level.tess.cutoff_distance_current )
|
||||
{
|
||||
SetDvar( "r_tessellationCutoffDistance", level.tess.cutoff_distance_current );
|
||||
}
|
||||
if( cutoff_falloff_old != level.tess.cutoff_falloff_current )
|
||||
{
|
||||
SetDvar( "r_tessellationCutoffFalloff" , level.tess.cutoff_falloff_current );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateSunFlarePosition()
|
||||
{
|
||||
if ( GetDvarInt( "scr_cmd_plr_sunflare" ) )
|
||||
{
|
||||
SetDevDvar( "scr_cmd_plr_sunflare", 0 );
|
||||
|
||||
pos = level.players[0] GetPlayerAngles();
|
||||
|
||||
// Output the pos to the window
|
||||
pos_string = "Sun Flare = ( " + pos[0] + ", " + pos[1] + ", " + pos[2] + " )";
|
||||
IPrintLnBold( pos_string );
|
||||
Print( pos_string );
|
||||
}
|
||||
}
|
||||
|
||||
dumpsettings()
|
||||
{
|
||||
if ( GetDvarInt( "scr_art_dump" ) == 0 )
|
||||
return false;
|
||||
|
||||
SetdevDvar( "scr_art_dump", "0" );
|
||||
|
||||
////////////////// [level]_art.gsc
|
||||
fileprint_launcher_start_file();
|
||||
fileprint_launcher( "// _createart generated. modify at your own risk. Changing values should be fine." );
|
||||
fileprint_launcher( "main()" );
|
||||
fileprint_launcher( "{" );
|
||||
fileprint_launcher( "\tlevel.tweakfile = true;" );
|
||||
if ( IsDefined( level.parse_fog_func ) ) // Don't print this unless it already exists (otherwise [levelname]_fog.gsc will likely fail to compile)
|
||||
fileprint_launcher( "\tlevel.parse_fog_func = maps\\createart\\" + level.script + "_fog::main;" );
|
||||
fileprint_launcher( "" );
|
||||
fileprint_launcher( "\tsetDevDvar( \"scr_fog_disable\"" + ", " + "\"" + GetDvarInt( "scr_fog_disable" ) + "\"" + " );" );
|
||||
// Writing this out in case someone needs it
|
||||
if ( ! GetDvarInt( "scr_fog_disable" ) )
|
||||
{
|
||||
if ( level.sunFogEnabled )
|
||||
fileprint_launcher( "//\tsetExpFog( " + level.fognearplane + ", " + level.fogexphalfplane + ", " + level.fogcolor[0] + ", " + level.fogcolor[1] + ", " + level.fogcolor[2] + ", " + level.fogHDRColorIntensity + ", " + level.fogmaxopacity + ", 0, " + level.sunFogColor[0] + ", " + level.sunFogColor[1] + ", " + level.sunFogColor[2] + ", " + level.sunFogHDRColorIntensity + ", (" + level.sunFogDir[0] + ", " + level.sunFogDir[1] + ", " + level.sunFogDir[2] + "), " + level.sunFogBeginFadeAngle + ", " + level.sunFogEndFadeAngle + ", " + level.sunFogScale + ", " + level.skyFogIntensity + ", " + level.skyFogMinAngle + ", " + level.skyFogMaxAngle + " );" );
|
||||
else
|
||||
fileprint_launcher( "//\tsetExpFog( " + level.fognearplane + ", " + level.fogexphalfplane + ", " + level.fogcolor[0] + ", " + level.fogcolor[1] + ", " + level.fogcolor[2] + ", " + level.fogHDRColorIntensity + ", " + level.fogmaxopacity + ", 0, " + level.skyFogIntensity + ", " + level.skyFogMinAngle + ", " + level.skyFogMaxAngle + " );" );
|
||||
}
|
||||
fileprint_launcher( "\tVisionSetNaked( \"" + level.script + "\", 0 );" );
|
||||
fileprint_launcher( "}" );
|
||||
if ( !fileprint_launcher_end_file( "\\share\\raw\\maps\\createart\\" + level.script + "_art.gsc", true ) )
|
||||
return;
|
||||
//////////////////////////////
|
||||
|
||||
|
||||
// MP doesn't write [level]_art.csv?
|
||||
|
||||
|
||||
////////////////// [level]_fog.gsc
|
||||
if ( IsDefined( level.parse_fog_func ) )
|
||||
{
|
||||
fileprint_launcher_start_file();
|
||||
fileprint_launcher( "// _createart generated. modify at your own risk. Do not use block comments." );
|
||||
fileprint_launcher( "main()" );
|
||||
fileprint_launcher( "{" );
|
||||
common_scripts\_artCommon::print_fog_ents( true );
|
||||
fileprint_launcher( "}" );
|
||||
if ( !fileprint_launcher_end_file( "\\share\\raw\\maps\\createart\\" + level.script + "_fog.gsc", true ) )
|
||||
return;
|
||||
}
|
||||
//////////////////////////////
|
||||
|
||||
|
||||
////////////////// [level].vision
|
||||
if ( !common_scripts\_artCommon::print_vision( level.current_vision_set ) )
|
||||
return;
|
||||
|
||||
iprintlnbold( "Save successful!" );
|
||||
|
||||
PrintLn( "Art settings dumped success!" );
|
||||
}
|
||||
|
||||
add_vision_sets_from_triggers()
|
||||
{
|
||||
assert( IsDefined( level.vision_set_fog ) );
|
||||
|
||||
triggers = GetEntArray( "trigger_multiple_visionset" , "classname" );
|
||||
|
||||
// mkornkven: probably won't get anything -- need a way to get at the client trigger data?
|
||||
foreach( trigger in triggers )
|
||||
{
|
||||
name = undefined;
|
||||
|
||||
if( IsDefined( trigger.script_visionset ) )
|
||||
name = ToLower( trigger.script_visionset );
|
||||
else if ( IsDefined( trigger.script_visionset_start ) )
|
||||
name = ToLower( trigger.script_visionset_start );
|
||||
else if ( IsDefined( trigger.script_visionset_end ) )
|
||||
name = ToLower( trigger.script_visionset_end );
|
||||
|
||||
if ( IsDefined( name ) )
|
||||
add_vision_set( name );
|
||||
}
|
||||
}
|
||||
|
||||
add_vision_set( vision_set_name )
|
||||
{
|
||||
assert( vision_set_name == ToLower( vision_set_name ) );
|
||||
|
||||
if ( IsDefined( level.vision_set_fog[ vision_set_name ] ) )
|
||||
return;
|
||||
|
||||
create_default_vision_set_fog( vision_set_name );
|
||||
common_scripts\_artCommon::add_vision_set_to_list( vision_set_name );
|
||||
|
||||
IPrintLnBold( "new vision: " + vision_set_name );
|
||||
}
|
||||
|
||||
button_down( btn, btn2 )
|
||||
{
|
||||
pressed = level.players[0] ButtonPressed( btn );
|
||||
|
||||
if ( !pressed )
|
||||
{
|
||||
pressed = level.players[0] ButtonPressed( btn2 );
|
||||
}
|
||||
|
||||
if ( !IsDefined( level.buttons[ btn ] ) )
|
||||
{
|
||||
level.buttons[ btn ] = 0;
|
||||
}
|
||||
|
||||
// To Prevent Spam
|
||||
if ( GetTime() < level.buttons[ btn ] )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
level.buttons[ btn ] = GetTime() + 400;
|
||||
return pressed;
|
||||
}
|
||||
|
||||
updateFogFromScript()
|
||||
{
|
||||
if ( GetDvarInt( "scr_cmd_plr_sun" ) )
|
||||
{
|
||||
SetDevDvar( "scr_sunFogDir", AnglesToForward( level.players[0] GetPlayerAngles() ) );
|
||||
SetDevDvar( "scr_cmd_plr_sun", 0 );
|
||||
}
|
||||
|
||||
ent = get_fog_ent_for_vision_set( level.current_vision_set );
|
||||
|
||||
if( IsDefined( ent ) && isdefined( ent.name ) )
|
||||
{
|
||||
ent.startDist = level.fognearplane;
|
||||
ent.halfwayDist = level.fogexphalfplane;
|
||||
ent.red = level.fogcolor[ 0 ];
|
||||
ent.green = level.fogcolor[ 1 ];
|
||||
ent.blue = level.fogcolor[ 2 ];
|
||||
ent.HDRColorIntensity = level.fogHDRColorIntensity;
|
||||
ent.maxOpacity = level.fogmaxopacity;
|
||||
|
||||
ent.sunFogEnabled = level.sunFogEnabled;
|
||||
ent.sunRed = level.sunFogColor[ 0 ];
|
||||
ent.sunGreen = level.sunFogColor[ 1 ];
|
||||
ent.sunBlue = level.sunFogColor[ 2 ];
|
||||
ent.HDRSunColorIntensity = level.sunFogHDRColorIntensity;
|
||||
ent.sunDir = level.sunFogDir;
|
||||
ent.sunBeginFadeAngle = level.sunFogBeginFadeAngle;
|
||||
ent.sunEndFadeAngle = level.sunFogEndFadeAngle;
|
||||
ent.normalFogScale = level.sunFogScale;
|
||||
|
||||
ent.skyFogIntensity = level.skyFogIntensity;
|
||||
ent.skyFogMinAngle = level.skyFogMinAngle;
|
||||
ent.skyFogMaxAngle = level.skyFogMaxAngle;
|
||||
|
||||
if ( GetDvarInt( "scr_fog_disable" ) )
|
||||
{
|
||||
ent.startDist = 2000000000;
|
||||
ent.halfwayDist = 2000000001;
|
||||
ent.red = 0;
|
||||
ent.green = 0;
|
||||
ent.blue = 0;
|
||||
ent.HDRSunColorIntensity = 1;
|
||||
ent.maxOpacity = 0;
|
||||
ent.skyFogIntensity = 0;
|
||||
}
|
||||
|
||||
if ( IsDefined( level.parse_fog_func ) ) // Otherwise, this is the default set, which we don't want to set
|
||||
set_fog_to_ent_values( ent, 0 );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
update_current_vision_set_dvars()
|
||||
{
|
||||
level.players[0] openpopupmenu("dev_vision_exec");
|
||||
wait( 0.05 );
|
||||
level.players[0] closepopupmenu();
|
||||
}
|
||||
|
||||
vision_set_changes( vision_set )
|
||||
{
|
||||
// Set the vision set and push the values to tweak dvars in code
|
||||
VisionSetNaked( vision_set, 0 );
|
||||
update_current_vision_set_dvars();
|
||||
level.current_vision_set = vision_set;
|
||||
}
|
||||
|
||||
vision_set_fog_changes( vision_set, transition_time )
|
||||
{
|
||||
vision_set_changes( vision_set );
|
||||
fog_ent = get_fog_ent_for_vision_set( vision_set );
|
||||
if ( IsDefined( fog_ent ) )
|
||||
{
|
||||
translateFogEntTosliders( fog_ent );
|
||||
if ( IsDefined( level.parse_fog_func ) ) // Otherwise, this is the default set, which we don't want to set
|
||||
set_fog_to_ent_values( fog_ent, transition_time);
|
||||
}
|
||||
}
|
||||
|
||||
get_fog_ent_for_vision_set( vision_set )
|
||||
{
|
||||
fog_ent = level.vision_set_fog[ ToLower( vision_set ) ];
|
||||
if ( using_hdr_fog() && IsDefined( fog_ent ) && IsDefined( fog_ent.HDROverride ) )
|
||||
fog_ent = level.vision_set_fog[ ToLower( fog_ent.HDROverride ) ];
|
||||
|
||||
return fog_ent;
|
||||
}
|
||||
|
||||
using_hdr_fog()
|
||||
{
|
||||
if ( !IsDefined( level.console ) )
|
||||
set_console_status();
|
||||
AssertEx( IsDefined( level.console ) && IsDefined( level.xb3 ) && IsDefined( level.ps4 ), "Expected platform defines to be complete." );
|
||||
|
||||
return is_gen4();
|
||||
}
|
||||
|
||||
translateFogEntTosliders( ent )
|
||||
{
|
||||
SetDevDvar( "scr_fog_exp_halfplane", ent.halfwayDist );
|
||||
SetDevDvar( "scr_fog_nearplane", ent.startDist );
|
||||
SetDevDvar( "scr_fog_color", ( ent.red, ent.green, ent.blue ) );
|
||||
SetDevDvar( "scr_fog_color_intensity", ent.HDRColorIntensity );
|
||||
SetDevDvar( "scr_fog_max_opacity", ent.maxOpacity );
|
||||
|
||||
SetDevDvar( "scr_skyFogIntensity", ent.skyFogIntensity );
|
||||
SetDevDvar( "scr_skyFogMinAngle", ent.skyFogMinAngle );
|
||||
SetDevDvar( "scr_skyFogMaxAngle", ent.skyFogMaxAngle );
|
||||
|
||||
if ( IsDefined( ent.sunFogEnabled ) && ent.sunFogEnabled )
|
||||
{
|
||||
SetDevDvar( "scr_sunFogEnabled", 1 );
|
||||
SetDevDvar( "scr_sunFogColor", ( ent.sunRed, ent.sunGreen,ent.sunBlue ) );
|
||||
SetDevDvar( "scr_sunFogColorIntensity", ent.HDRSunColorIntensity );
|
||||
SetDevDvar( "scr_sunFogDir", ent.sunDir );
|
||||
SetDevDvar( "scr_sunFogBeginFadeAngle", ent.sunBeginFadeAngle );
|
||||
SetDevDvar( "scr_sunFogEndFadeAngle", ent.sunEndFadeAngle );
|
||||
SetDevDvar( "scr_sunFogScale", ent.normalFogScale );
|
||||
}
|
||||
else
|
||||
{
|
||||
SetDevDvar( "scr_sunFogEnabled", 0 );
|
||||
}
|
||||
}
|
||||
|
||||
set_fog_to_ent_values( ent, transition_time )
|
||||
{
|
||||
if ( IsDefined( ent.sunFogEnabled) && ent.sunFogEnabled )
|
||||
{
|
||||
if ( !isPlayer( self ) )
|
||||
{
|
||||
SetExpFog(
|
||||
ent.startDist,
|
||||
ent.halfwayDist,
|
||||
ent.red,
|
||||
ent.green,
|
||||
ent.blue,
|
||||
ent.HDRColorIntensity,
|
||||
ent.maxOpacity,
|
||||
transition_time,
|
||||
ent.sunRed,
|
||||
ent.sunGreen,
|
||||
ent.sunBlue,
|
||||
ent.HDRSunColorIntensity,
|
||||
ent.sunDir,
|
||||
ent.sunBeginFadeAngle,
|
||||
ent.sunEndFadeAngle,
|
||||
ent.normalFogScale,
|
||||
ent.skyFogIntensity,
|
||||
ent.skyFogMinAngle,
|
||||
ent.skyFogMaxAngle );
|
||||
}
|
||||
else
|
||||
{
|
||||
self PlayerSetExpFog(
|
||||
ent.startDist,
|
||||
ent.halfwayDist,
|
||||
ent.red,
|
||||
ent.green,
|
||||
ent.blue,
|
||||
ent.HDRColorIntensity,
|
||||
ent.maxOpacity,
|
||||
transition_time,
|
||||
ent.sunRed,
|
||||
ent.sunGreen,
|
||||
ent.sunBlue,
|
||||
ent.HDRSunColorIntensity,
|
||||
ent.sunDir,
|
||||
ent.sunBeginFadeAngle,
|
||||
ent.sunEndFadeAngle,
|
||||
ent.normalFogScale,
|
||||
ent.skyFogIntensity,
|
||||
ent.skyFogMinAngle,
|
||||
ent.skyFogMaxAngle );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( !isPlayer( self ) )
|
||||
{
|
||||
SetExpFog(
|
||||
ent.startDist,
|
||||
ent.halfwayDist,
|
||||
ent.red,
|
||||
ent.green,
|
||||
ent.blue,
|
||||
ent.HDRColorIntensity,
|
||||
ent.maxOpacity,
|
||||
transition_time,
|
||||
ent.skyFogIntensity,
|
||||
ent.skyFogMinAngle,
|
||||
ent.skyFogMaxAngle );
|
||||
}
|
||||
else
|
||||
{
|
||||
self PlayerSetExpFog(
|
||||
ent.startDist,
|
||||
ent.halfwayDist,
|
||||
ent.red,
|
||||
ent.green,
|
||||
ent.blue,
|
||||
ent.HDRColorIntensity,
|
||||
ent.maxOpacity,
|
||||
transition_time,
|
||||
ent.skyFogIntensity,
|
||||
ent.skyFogMinAngle,
|
||||
ent.skyFogMaxAngle );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
create_default_vision_set_fog( name )
|
||||
{
|
||||
ent = create_vision_set_fog( name );
|
||||
ent.startDist = 3764.17;
|
||||
ent.halfwayDist = 19391;
|
||||
ent.red = 0.661137;
|
||||
ent.green = 0.554261;
|
||||
ent.blue = 0.454014;
|
||||
ent.maxOpacity = 0.7;
|
||||
ent.transitionTime = 0;
|
||||
ent.skyFogIntensity = 0;
|
||||
ent.skyFogMinAngle = 0;
|
||||
ent.skyFogMaxAngle = 0;
|
||||
}
|
||||
|
||||
hud_init()
|
||||
{
|
||||
listsize = 7;
|
||||
|
||||
hudelems = [];
|
||||
spacer = 15;
|
||||
div = int( listsize / 2 );
|
||||
org = 240 - div * spacer;
|
||||
alphainc = .5 / div;
|
||||
alpha = alphainc;
|
||||
|
||||
for ( i = 0;i < listsize;i++ )
|
||||
{
|
||||
hudelems[ i ] = _newhudelem();
|
||||
hudelems[ i ].location = 0;
|
||||
hudelems[ i ].alignX = "left";
|
||||
hudelems[ i ].alignY = "middle";
|
||||
hudelems[ i ].foreground = 1;
|
||||
hudelems[ i ].fontScale = 2;
|
||||
hudelems[ i ].sort = 20;
|
||||
if ( i == div )
|
||||
hudelems[ i ].alpha = 1;
|
||||
else
|
||||
hudelems[ i ].alpha = alpha;
|
||||
|
||||
hudelems[ i ].x = 20;
|
||||
hudelems[ i ].y = org;
|
||||
hudelems[ i ] _settext( "." );
|
||||
|
||||
if ( i == div )
|
||||
alphainc *= -1;
|
||||
|
||||
alpha += alphainc;
|
||||
|
||||
org += spacer;
|
||||
}
|
||||
|
||||
level.spam_group_hudelems = hudelems;
|
||||
}
|
||||
|
||||
_newhudelem()
|
||||
{
|
||||
if ( !isdefined( level.scripted_elems ) )
|
||||
level.scripted_elems = [];
|
||||
elem = newhudelem(); // client?
|
||||
level.scripted_elems[ level.scripted_elems.size ] = elem;
|
||||
return elem;
|
||||
}
|
||||
|
||||
_settext( text )
|
||||
{
|
||||
self.realtext = text;
|
||||
self setDevText( "_" );
|
||||
self thread _clearalltextafterhudelem();
|
||||
sizeofelems = 0;
|
||||
foreach ( elem in level.scripted_elems )
|
||||
{
|
||||
if ( isdefined( elem.realtext ) )
|
||||
{
|
||||
sizeofelems += elem.realtext.size;
|
||||
elem setDevText( elem.realtext );
|
||||
}
|
||||
}
|
||||
println( "Size of elems: " + sizeofelems );
|
||||
}
|
||||
|
||||
_clearalltextafterhudelem()
|
||||
{
|
||||
if ( level._clearalltextafterhudelem )
|
||||
return;
|
||||
level._clearalltextafterhudelem = true;
|
||||
self clearalltextafterhudelem();
|
||||
wait .05;
|
||||
level._clearalltextafterhudelem = false;
|
||||
}
|
||||
|
||||
setgroup_up()
|
||||
{
|
||||
reset_cmds();
|
||||
|
||||
current_vision_set_name = level.current_vision_set;
|
||||
|
||||
index = array_find( level.vision_set_names, current_vision_set_name );
|
||||
if ( !IsDefined( index ) )
|
||||
return;
|
||||
|
||||
index -= 1;
|
||||
|
||||
if ( index < 0 )
|
||||
return;
|
||||
|
||||
setcurrentgroup( level.vision_set_names[index] );
|
||||
}
|
||||
|
||||
setgroup_down()
|
||||
{
|
||||
reset_cmds();
|
||||
|
||||
current_vision_set_name = level.current_vision_set;
|
||||
|
||||
index = array_find( level.vision_set_names, current_vision_set_name );
|
||||
if ( !IsDefined( index ) )
|
||||
return;
|
||||
|
||||
index += 1;
|
||||
|
||||
if ( index >= level.vision_set_names.size )
|
||||
return;
|
||||
|
||||
setcurrentgroup( level.vision_set_names[index] );
|
||||
}
|
||||
|
||||
reset_cmds()
|
||||
{
|
||||
SetDevDvar( "scr_select_art_next", 0 );
|
||||
SetDevDvar( "scr_select_art_prev", 0 );
|
||||
}
|
||||
|
||||
setcurrentgroup( group )
|
||||
{
|
||||
level.spam_model_current_group = group;
|
||||
|
||||
index = array_find( level.vision_set_names, group );
|
||||
if ( !IsDefined( index ) )
|
||||
index = -1;
|
||||
|
||||
hud_list_size = level.spam_group_hudelems.size;
|
||||
hud_start_index = index - int( hud_list_size / 2 );
|
||||
|
||||
for ( i = 0; i < hud_list_size; i++ )
|
||||
{
|
||||
hud_index = hud_start_index + i;
|
||||
if ( hud_index < 0 || hud_index >= level.vision_set_names.size )
|
||||
{
|
||||
level.spam_group_hudelems[i] _settext( "." );
|
||||
continue;
|
||||
}
|
||||
|
||||
level.spam_group_hudelems[i] _settext( level.vision_set_names[hud_index] );
|
||||
}
|
||||
|
||||
group_name = "";
|
||||
if ( index >= 0 )
|
||||
group_name = level.vision_set_names[ index ];
|
||||
|
||||
vision_set_fog_changes( group_name, 0 );
|
||||
}
|
||||
#/
|
||||
|
||||
create_vision_set_fog( fogsetName )
|
||||
{
|
||||
/#
|
||||
if ( !isdefined( level.vision_set_fog ) )
|
||||
level.vision_set_fog = [];
|
||||
|
||||
ent = SpawnStruct();
|
||||
ent.name = fogsetName;
|
||||
|
||||
// Special init for variables that may not exist on every set of fog yet -- add variable defaults here to avoid IsDefined checks everywhere later on
|
||||
ent.HDRColorIntensity = 1;
|
||||
ent.HDRSunColorIntensity = 1;
|
||||
ent.skyFogIntensity = 0;
|
||||
ent.skyFogMinAngle = 0;
|
||||
ent.skyFogMaxAngle = 0;
|
||||
|
||||
level.vision_set_fog[ ToLower(fogsetName) ] = ent;
|
||||
return ent;
|
||||
#/
|
||||
}
|
||||
|
139
maps/mp/_audio.gsc
Normal file
139
maps/mp/_audio.gsc
Normal file
@ -0,0 +1,139 @@
|
||||
#include maps\mp\_utility;
|
||||
#include common_scripts\utility;
|
||||
|
||||
init_audio()
|
||||
{
|
||||
if ( !IsDefined( level.audio ) )
|
||||
{
|
||||
level.audio = SpawnStruct();
|
||||
}
|
||||
|
||||
init_reverb();
|
||||
init_whizby();
|
||||
|
||||
level.onPlayerConnectAudioInit = ::OnPlayerConnectAudioInit;
|
||||
}
|
||||
|
||||
OnPlayerConnectAudioInit()
|
||||
{
|
||||
self apply_reverb( "default" );
|
||||
// self apply_whizby(); <-- Does not work yet... Looks like it overflows the server.
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// Reverb Section
|
||||
//---------------------------------------------------------
|
||||
init_reverb()
|
||||
{
|
||||
add_reverb( "default", "generic", 0.15, 0.9, 2 );
|
||||
}
|
||||
|
||||
add_reverb( name, type, wetlevel, drylevel, fadetime )
|
||||
{
|
||||
Assert( IsDefined( type ) );
|
||||
Assert( IsDefined( wetlevel ) );
|
||||
Assert( IsDefined( drylevel ) );
|
||||
|
||||
reverb = [];
|
||||
|
||||
is_roomtype_valid( type );
|
||||
|
||||
reverb[ "roomtype" ] = type;
|
||||
reverb[ "wetlevel" ] = wetlevel;
|
||||
reverb[ "drylevel" ] = drylevel;
|
||||
reverb[ "fadetime" ] = fadetime;
|
||||
|
||||
level.audio.reverb_settings[ name ] = reverb;
|
||||
}
|
||||
|
||||
is_roomtype_valid( type )
|
||||
{
|
||||
/#
|
||||
switch ( type )
|
||||
{
|
||||
case "generic":
|
||||
case "paddedcell":
|
||||
case "room":
|
||||
case "bathroom":
|
||||
case "livingroom":
|
||||
case "stoneroom":
|
||||
case "auditorium":
|
||||
case "concerthall":
|
||||
case "cave":
|
||||
case "arena":
|
||||
case "hangar":
|
||||
case "carpetedhallway":
|
||||
case "hallway":
|
||||
case "stonecorridor":
|
||||
case "alley":
|
||||
case "forest":
|
||||
case "city":
|
||||
case "mountains":
|
||||
case "quarry":
|
||||
case "plain":
|
||||
case "parkinglot":
|
||||
case "sewerpipe":
|
||||
case "underwater":
|
||||
case "drugged":
|
||||
case "dizzy":
|
||||
case "psychotic":
|
||||
return;
|
||||
default:
|
||||
AssertMsg( type + " is an Invalid Roomtype" );
|
||||
break;
|
||||
}
|
||||
#/
|
||||
}
|
||||
|
||||
apply_reverb( name )
|
||||
{
|
||||
if ( !IsDefined( level.audio.reverb_settings[ name ] ) )
|
||||
{
|
||||
reverb = level.audio.reverb_settings[ "default" ];
|
||||
}
|
||||
else
|
||||
{
|
||||
reverb = level.audio.reverb_settings[ name ];
|
||||
}
|
||||
|
||||
self SetReverb( "snd_enveffectsprio_level", reverb[ "roomtype" ], reverb[ "drylevel" ], reverb[ "wetlevel" ], reverb[ "fadetime" ] );
|
||||
// self SetClientDvar( "cg_levelReverbRoomType", reverb[ "roomtype" ] );
|
||||
// self SetClientDvar( "cg_levelReverbDryLevel", reverb[ "drylevel" ] );
|
||||
// self SetClientDvar( "cg_levelReverbWetLevel", reverb[ "wetlevel" ] );
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// whizBy Section
|
||||
//---------------------------------------------------------
|
||||
|
||||
init_whizby()
|
||||
{
|
||||
SetDevDvar( "snd_newwhizby", 1 );
|
||||
|
||||
// Default settings -- Call wrappers in your level to overwrite.
|
||||
level.audio.whizby_settings = [];
|
||||
set_whizby_radius( 15.0, 30.0, 50.0 );
|
||||
set_whizby_spread( 150.0, 250.0, 350.0 );
|
||||
}
|
||||
|
||||
set_whizby_radius( near, medium, far )
|
||||
{
|
||||
assertex( near != 0, "whizby near radius cannot be zero" );
|
||||
level.audio.whizby_settings[ "radius" ] = [ near, medium, far ];
|
||||
}
|
||||
|
||||
set_whizby_spread( near, medium, far )
|
||||
{
|
||||
level.audio.whizby_settings[ "spread" ] = [ near, medium, far ];
|
||||
}
|
||||
|
||||
apply_whizby()
|
||||
{
|
||||
settings = level.audio.whizby_settings;
|
||||
|
||||
spread = settings[ "spread" ];
|
||||
rad = settings[ "radius" ];
|
||||
|
||||
self SetWhizbySpreads( spread[ 0 ], spread[ 1 ], spread[ 2 ] );
|
||||
self SetWhizbyRadii( rad[ 0 ], rad[ 1 ], rad[ 2 ] );
|
||||
}
|
1084
maps/mp/_awards.gsc
Normal file
1084
maps/mp/_awards.gsc
Normal file
File diff suppressed because it is too large
Load Diff
335
maps/mp/_barrels_leak.gsc
Normal file
335
maps/mp/_barrels_leak.gsc
Normal file
@ -0,0 +1,335 @@
|
||||
#include common_scripts\utility;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// CONSTANTS //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
level_limit_barrel_fx = 8;
|
||||
max_fires_from_entity = 4;
|
||||
level_barrel_fx_chance = 33;
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// LOGIC //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
main()
|
||||
{
|
||||
if ( IsDefined( level.barrels_init ) )
|
||||
return;
|
||||
|
||||
|
||||
level.barrels_init = true;
|
||||
//level._barrel_fx_time = 25; //handle this individually for different barrel types
|
||||
barrels = GetEntArray( "barrel_shootable", "targetname" );
|
||||
if ( !barrels.size )
|
||||
return;
|
||||
level._barrels = SpawnStruct();
|
||||
level._barrels.num_barrel_fx = 0;
|
||||
|
||||
barrels thread precacheFX();
|
||||
barrels thread methodsInit();
|
||||
|
||||
thread post_load( barrels );
|
||||
}
|
||||
|
||||
post_load( barrels )
|
||||
{
|
||||
waittillframeend;// insure that structs are initialized
|
||||
if( level.createFX_enabled )
|
||||
return;
|
||||
array_thread( barrels, ::barrelsetup );
|
||||
}
|
||||
|
||||
barrelsetup()
|
||||
{
|
||||
self SetCanDamage( true );
|
||||
self SetCanRadiusDamage( false ); // optimization
|
||||
self.barrel_fx_array = [];
|
||||
|
||||
|
||||
node = undefined;
|
||||
|
||||
if ( IsDefined( self.target ) )
|
||||
{
|
||||
node = getstruct( self.target, "targetname" );
|
||||
self.A = node.origin;
|
||||
vec = AnglesToForward( node.angles );
|
||||
vec = ( vec * 128 );
|
||||
self.B = self.A + vec;
|
||||
}
|
||||
else
|
||||
{
|
||||
vec = AnglesToForward( self.angles );
|
||||
vec1 = ( vec * 64 );
|
||||
self.A = self.origin + vec1;
|
||||
vec1 = ( vec * -64 );
|
||||
self.B = self.origin + vec1;
|
||||
}
|
||||
|
||||
self thread barrel_wait_loop();
|
||||
}
|
||||
|
||||
barrel_wait_loop()
|
||||
{
|
||||
P = ( 0, 0, 0 );// just to initialize P as a vector
|
||||
|
||||
hasTakenDamage = false;
|
||||
remaining = max_fires_from_entity;
|
||||
|
||||
while ( 1 )
|
||||
{
|
||||
self waittill( "damage", damage, attacker, direction_vec, P, type );
|
||||
|
||||
// random so we don't get so many fx, but the very first time is guarenteed
|
||||
if ( hasTakenDamage )
|
||||
{
|
||||
if ( randomint( 100 ) <= level_barrel_fx_chance )
|
||||
continue;
|
||||
}
|
||||
hasTakenDamage = true;
|
||||
|
||||
result = self barrel_logic( direction_vec, P, type, attacker );
|
||||
if ( result )
|
||||
remaining--;
|
||||
|
||||
if ( remaining <= 0 )
|
||||
break;
|
||||
}
|
||||
|
||||
self SetCanDamage( false );
|
||||
}
|
||||
|
||||
barrel_logic( direction_vec, P, type, damageOwner )
|
||||
{
|
||||
if ( level._barrels.num_barrel_fx > level_limit_barrel_fx )
|
||||
return false;
|
||||
|
||||
if ( !isDefined( level._barrels._barrel_methods[ type ] ) )
|
||||
P = self barrel_calc_nofx( P, type );
|
||||
else
|
||||
P = self [[ level._barrels._barrel_methods[ type ] ]]( P, type );
|
||||
|
||||
if ( !isdefined( P ) )
|
||||
return false;
|
||||
|
||||
if ( IsDefined( damageOwner.classname ) && damageOwner.classname == "worldspawn" )
|
||||
return false;
|
||||
|
||||
foreach ( value in self.barrel_fx_array )
|
||||
{
|
||||
if ( DistanceSquared( P, value.origin ) < 25 )
|
||||
return false;
|
||||
}
|
||||
|
||||
//calculate the vector derived from the center line of our barrel and the point of damage
|
||||
|
||||
// generate a vector from the attacker's eye to the impact point (AI) or origin to impact point (non-AI)
|
||||
E = undefined;
|
||||
if( IsAI( damageOwner ))
|
||||
E = damageOwner GetEye();
|
||||
else
|
||||
E = damageOwner.origin;
|
||||
|
||||
temp_vec = P - E;
|
||||
|
||||
// Extend the vector (this is to ensure it intersects the damaged entity, tracing to the point itself generated new points which were slightly off and bad normals) and return a trace
|
||||
trace = BulletTrace ( E, E + 1.5 * temp_vec, false, damageOwner, false );
|
||||
if ( isdefined ( trace [ "normal" ] ) && isdefined ( trace [ "entity" ] ) && trace ["entity"] == self )
|
||||
{
|
||||
vec = trace[ "normal" ];
|
||||
|
||||
// Use the surface normal of the impact point to generate the angles for the burst effect
|
||||
self thread barrelfx( P, vec, damageOwner );
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
//DC_NOTE commented out all sound related stuff because it was giving me grief in mp_zulu
|
||||
barrelfx( P, vec, damageOwner )
|
||||
{
|
||||
time = level._barrels.fx_time[ self.script_noteworthy ] ;
|
||||
fx_time = level._barrels._barrel_fx_time[ self.script_noteworthy ] ;
|
||||
intervals = Int( fx_time / time );// loops for 25 seconds
|
||||
intervals_end = 30;
|
||||
hitsnd = level._barrels._sound[ self.script_noteworthy + "_hit" ];
|
||||
loopsnd = level._barrels._sound[ self.script_noteworthy + "_loop" ];
|
||||
endsnd = level._barrels._sound[ self.script_noteworthy + "_end" ];
|
||||
|
||||
snd = Spawn( "script_origin", P );
|
||||
// snd Hide();
|
||||
snd PlaySound( hitsnd );
|
||||
snd PlayLoopSound( loopsnd );
|
||||
self.barrel_fx_array[ self.barrel_fx_array.size ] = snd;
|
||||
|
||||
// if ( isSP() || self.script_noteworthy != "steam" )
|
||||
if ( isSP() )
|
||||
self thread barrel_damage( P, vec, damageOwner, snd );
|
||||
|
||||
//rotate the emitter angle over time
|
||||
efx_rot = Spawn( "script_model", P );
|
||||
efx_rot SetModel( "tag_origin" );
|
||||
efx_rot.angles = VectorToAngles( vec );
|
||||
wait .05;//cant play fx on same frame it's spawned in mp appearantly
|
||||
PlayFXOnTag( level._barrels._effect[ self.script_noteworthy ] , efx_rot, "tag_origin" );
|
||||
level._barrels.num_barrel_fx++;
|
||||
efx_rot RotatePitch( 90, time, 1, 1 );
|
||||
wait time;
|
||||
StopFXOnTag( level._barrels._effect[ self.script_noteworthy ] , efx_rot, "tag_origin" );
|
||||
intervals--;
|
||||
//now check for other fx and rest of intervals
|
||||
while ( level._barrels.num_barrel_fx <= level_limit_barrel_fx && intervals > 0 )
|
||||
{
|
||||
efx_rot = Spawn( "script_model", P );
|
||||
efx_rot SetModel( "tag_origin" );
|
||||
efx_rot.angles = VectorToAngles( vec );
|
||||
wait .05;//cant play fx on same frame it's spawned in mp appearantly
|
||||
PlayFXOnTag( level._barrels._effect[ self.script_noteworthy ] , efx_rot, "tag_origin" );
|
||||
level._barrels.num_barrel_fx++;
|
||||
efx_rot RotatePitch( 90, time, 1, 1 );
|
||||
wait time;
|
||||
StopFXOnTag( level._barrels._effect[ self.script_noteworthy ] , efx_rot, "tag_origin" );
|
||||
}
|
||||
|
||||
// snd PlaySound( endsnd );
|
||||
wait( .5 );
|
||||
// snd StopLoopSound( loopsnd );
|
||||
snd Delete();
|
||||
self.barrel_fx_array = array_removeUndefined( self.barrel_fx_array );
|
||||
|
||||
level._barrels.num_barrel_fx--;
|
||||
}
|
||||
|
||||
barrel_damage( P, vec, damageOwner, fx )
|
||||
{
|
||||
if ( !allow_barrel_damage() )
|
||||
return;
|
||||
|
||||
fx endon( "death" );
|
||||
|
||||
origin = fx.origin + ( VectorNormalize( vec ) * 40 );
|
||||
dmg = level._barrels._dmg[ self.script_noteworthy ];
|
||||
|
||||
while ( 1 )
|
||||
{
|
||||
// do not pass damage owner if they have disconnected before the barrels explode.. the barrels?
|
||||
if ( !isdefined( self.damageOwner ) )
|
||||
{
|
||||
// MOD_TRIGGER_HURT so they dont do dirt on the player's screen
|
||||
self RadiusDamage( origin, 36, dmg, dmg * 0.75, undefined, "MOD_TRIGGER_HURT" );
|
||||
}
|
||||
else
|
||||
{
|
||||
// MOD_TRIGGER_HURT so they dont do dirt on the player's screen
|
||||
self RadiusDamage( origin, 36, dmg, dmg * 0.75, damageOwner, "MOD_TRIGGER_HURT" );
|
||||
}
|
||||
|
||||
wait( 0.4 );
|
||||
}
|
||||
}
|
||||
|
||||
allow_barrel_damage()
|
||||
{
|
||||
if( !isSP() )
|
||||
return false;
|
||||
|
||||
if ( !isDefined( level.barrelsDamage ) )
|
||||
return false;
|
||||
|
||||
return ( level.barrelsDamage );
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// CALCULATIONS / SETUP //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
methodsInit()
|
||||
{
|
||||
level._barrels._barrel_methods = [];
|
||||
level._barrels._barrel_methods[ "MOD_UNKNOWN" ] = ::barrel_calc_splash;
|
||||
level._barrels._barrel_methods[ "MOD_PISTOL_BULLET" ] = ::barrel_calc_ballistic;
|
||||
level._barrels._barrel_methods[ "MOD_RIFLE_BULLET" ] = ::barrel_calc_ballistic;
|
||||
level._barrels._barrel_methods[ "MOD_GRENADE" ] = ::barrel_calc_splash;
|
||||
level._barrels._barrel_methods[ "MOD_GRENADE_SPLASH" ] = ::barrel_calc_splash;
|
||||
level._barrels._barrel_methods[ "MOD_PROJECTILE" ] = ::barrel_calc_splash;
|
||||
level._barrels._barrel_methods[ "MOD_PROJECTILE_SPLASH" ] = ::barrel_calc_splash;
|
||||
level._barrels._barrel_methods[ "MOD_TRIGGER_HURT" ] = ::barrel_calc_splash;
|
||||
level._barrels._barrel_methods[ "MOD_EXPLOSIVE" ] = ::barrel_calc_splash;
|
||||
level._barrels._barrel_methods[ "MOD_EXPLOSIVE_BULLET" ] = ::barrel_calc_splash;
|
||||
}
|
||||
|
||||
barrel_calc_ballistic( P, type )
|
||||
{
|
||||
return P;
|
||||
}
|
||||
|
||||
barrel_calc_splash( P, type )
|
||||
{
|
||||
vec = VectorNormalize( VectorFromLineToPoint( self.A, self.B, P ) );
|
||||
P = PointOnSegmentNearestToPoint( self.A, self.B, P );
|
||||
return( P + ( vec * 4 ) );
|
||||
}
|
||||
|
||||
barrel_calc_nofx( P, type )
|
||||
{
|
||||
return undefined;
|
||||
}
|
||||
|
||||
precacheFX()
|
||||
{
|
||||
oil_leak = false;
|
||||
oil_cap = false;
|
||||
beer_leak = false;
|
||||
foreach ( value in self )
|
||||
{
|
||||
if ( value.script_noteworthy == "oil_leak" )
|
||||
{
|
||||
value willNeverChange();
|
||||
oil_leak = true;
|
||||
}
|
||||
else if ( value.script_noteworthy == "oil_cap" )
|
||||
{
|
||||
value willNeverChange();
|
||||
oil_cap = true;
|
||||
}
|
||||
else if ( value.script_noteworthy == "beer_leak" )
|
||||
{
|
||||
value willNeverChange();
|
||||
beer_leak = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
println( "Unknown 'barrel_shootable' script_noteworthy type '%s'\n", value.script_noteworthy );
|
||||
}
|
||||
}
|
||||
|
||||
//DC_NOTE commented out all sound related stuff because it was giving me grief in mp_zulu
|
||||
if ( oil_leak )
|
||||
{
|
||||
level._barrels._effect[ "oil_leak" ] = loadfx( "fx/impacts/pipe_oil_barrel_spill" );
|
||||
//level._barrels._sound[ "oil_leak_hit" ] = "mtl_oil_barrel_hit";
|
||||
//level._barrels._sound[ "oil_leak_loop" ] = "mtl_oil_barrel_hiss_loop";
|
||||
//level._barrels._sound[ "oil_leak_end" ] = "mtl_oil_barrel_hiss_loop_end";
|
||||
level._barrels.fx_time[ "oil_leak" ] = 6;
|
||||
level._barrels._barrel_fx_time["oil_leak"] = 6;
|
||||
level._barrels._dmg[ "oil_leak" ] = 5;
|
||||
}
|
||||
if ( oil_cap )
|
||||
{
|
||||
level._barrels._effect[ "oil_cap" ] = loadfx( "fx/impacts/pipe_oil_barrel_squirt" );
|
||||
//level._barrels._sound[ "oil_cap_hit" ] = "mtl_oil_barrel_hit";
|
||||
//level._barrels._sound[ "oil_cap_loop" ] = "mtl_oil_barrel_hiss_loop";
|
||||
//level._barrels._sound[ "oil_cap_end" ] = "mtl_oil_barrel_hiss_loop_end";
|
||||
level._barrels.fx_time[ "oil_cap" ] = 3;
|
||||
level._barrels._dmg[ "oil_cap" ] = 5;
|
||||
level._barrels._barrel_fx_time["oil_cap"] = 5;
|
||||
}
|
||||
if ( beer_leak )//DC_TODO create beer fx
|
||||
{
|
||||
level._barrels._effect[ "beer_leak" ] = loadfx( "fx/impacts/beer_barrel_spill" );
|
||||
level._barrels._sound[ "beer_leak_hit" ] = "mtl_beer_keg_hit";
|
||||
level._barrels._sound[ "beer_leak_loop" ] = "mtl_beer_keg_hiss_loop";
|
||||
level._barrels._sound[ "beer_leak_end" ] = "mtl_beer_keg_hiss_loop_end";
|
||||
level._barrels.fx_time[ "beer_leak" ] = 6;
|
||||
level._barrels._barrel_fx_time["beer_leak"] = 6;
|
||||
level._barrels._dmg[ "beer_leak" ] = 5;
|
||||
}
|
||||
}
|
753
maps/mp/_breach.gsc
Normal file
753
maps/mp/_breach.gsc
Normal file
@ -0,0 +1,753 @@
|
||||
#include common_scripts\utility;
|
||||
#include maps\mp\_utility;
|
||||
#include maps\mp\gametypes\_hud_util;
|
||||
|
||||
main()
|
||||
{
|
||||
thread main_thread();
|
||||
}
|
||||
|
||||
main_thread()
|
||||
{
|
||||
breach_precache();
|
||||
waitframe();
|
||||
|
||||
breach = getstructarray("breach", "targetname");
|
||||
array_thread(breach, ::breach_init);
|
||||
}
|
||||
|
||||
breach_precache()
|
||||
{
|
||||
level.breach_icon_count = -1;
|
||||
|
||||
level._effect["default"] = loadfx("fx/explosions/breach_room_cheap");
|
||||
}
|
||||
|
||||
breach_init()
|
||||
{
|
||||
if( getDvar( "r_reflectionProbeGenerate" ) == "1" )
|
||||
return;
|
||||
|
||||
if(!IsDefined(self.target))
|
||||
return;
|
||||
self.breach_targets = [];
|
||||
self.auto_breach_gametypes = [];
|
||||
|
||||
if(IsDefined(self.script_noteworthy))
|
||||
{
|
||||
toks = StrTok(self.script_noteworthy, ",");
|
||||
foreach(tok in toks)
|
||||
{
|
||||
if(GetSubStr(tok,0,7) == "not_in_")
|
||||
{
|
||||
self.auto_breach_gametypes[self.auto_breach_gametypes.size] = GetSubStr(tok,7,tok.size);
|
||||
}
|
||||
|
||||
if(tok == "only_if_allowClassChoice")
|
||||
{
|
||||
if(!allowClassChoice())
|
||||
{
|
||||
self.auto_breach_gametypes[self.auto_breach_gametypes.size] = level.gameType;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ents = GetEntArray(self.target, "targetname");
|
||||
structs = getstructarray(self.target, "targetname");
|
||||
targets = array_combine(ents, structs);
|
||||
nodes = self getLinknameNodes();
|
||||
foreach (node in nodes)
|
||||
{
|
||||
node.isPathNode = true;
|
||||
}
|
||||
targets = array_combine(targets, nodes);
|
||||
|
||||
foreach(target in targets)
|
||||
{
|
||||
if(!IsDefined(target.script_noteworthy))
|
||||
{
|
||||
target.script_noteworthy = target.classname;
|
||||
}
|
||||
|
||||
if(target.script_noteworthy == "trigger_use_touch")
|
||||
{
|
||||
target UseTriggerRequireLookAt();
|
||||
target.script_noteworthy = "trigger_use";
|
||||
}
|
||||
if(!IsDefined(target.isPathNode) || target.isPathNode == false)
|
||||
target.script_noteworthy = ToLower(target.script_noteworthy);
|
||||
types = StrTok(target.script_noteworthy, ", ");
|
||||
|
||||
foreach(type in types)
|
||||
{
|
||||
event_name = undefined;
|
||||
toks = StrTok(type, "_");
|
||||
if(toks.size>=3 && toks[toks.size-2] == "on")
|
||||
{
|
||||
event_name = toks[toks.size-1];
|
||||
type = toks[0];
|
||||
for(i=1;i<toks.size-2;i++)
|
||||
type = type + "_" + toks[i];
|
||||
}
|
||||
|
||||
useSide = false;
|
||||
toks = StrTok(type, "_");
|
||||
if(toks.size>=2 && toks[toks.size-1] == "useside")
|
||||
{
|
||||
useSide = true;
|
||||
type = toks[0];
|
||||
for(i=1;i<toks.size-2;i++)
|
||||
type = type + "_" + toks[i];
|
||||
}
|
||||
|
||||
|
||||
add_breach_target(target, type, event_name, useSide);
|
||||
|
||||
switch(type)
|
||||
{
|
||||
case "show":
|
||||
case "animated":
|
||||
target Hide();
|
||||
break;
|
||||
case "solid":
|
||||
if( IsDefined( target.spawnflags ) && ( target.spawnflags & 2 ) ) // AI_SIGHT_LINE
|
||||
{
|
||||
target SetAISightLineVisible( 0 );
|
||||
}
|
||||
target NotSolid();
|
||||
break;
|
||||
case "teleport_show":
|
||||
target trigger_off();
|
||||
break;
|
||||
case "use_icon":
|
||||
// self thread breach_icon("use", target.origin, target.angles, ["breach_used","breach_activated"] );
|
||||
break;
|
||||
case "trigger_damage":
|
||||
self thread breach_damage_watch(target);
|
||||
break;
|
||||
case "fx":
|
||||
if(!IsDefined(target.angles))
|
||||
target.angles = (0,0,0);
|
||||
break;
|
||||
case "connect_node":
|
||||
target DisconnectNode();
|
||||
break;
|
||||
case "disconnect_node":
|
||||
target ConnectNode();
|
||||
break;
|
||||
case "delete":
|
||||
if( IsDefined( target.spawnflags ) && ( target.spawnflags & 2 ) ) // AI_SIGHT_LINE
|
||||
{
|
||||
target SetAISightLineVisible( 1 );
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(level.createFX_enabled)
|
||||
return;
|
||||
|
||||
use_trigger = get_breach_target("trigger_use");
|
||||
if(IsDefined(use_trigger))
|
||||
{
|
||||
|
||||
if(!IsDefined(get_breach_target("sound")))
|
||||
{
|
||||
script_origin = spawn("script_origin", use_trigger.origin);
|
||||
add_breach_target(script_origin, "sound");
|
||||
}
|
||||
if(!IsDefined(get_breach_target("damage")))
|
||||
{
|
||||
damage = SpawnStruct();
|
||||
damage.origin = use_trigger.origin;
|
||||
add_breach_target(damage, "damage");
|
||||
}
|
||||
|
||||
//init default damage info,
|
||||
damages = get_breach_targets("damage");
|
||||
foreach(damage in damages)
|
||||
{
|
||||
if(!IsDefined(damage.radius))
|
||||
damage.radius = 128;
|
||||
if(!IsDefined(damage.max_damage))
|
||||
damage.max_damage = 100;
|
||||
if(!IsDefined(damage.min_damage))
|
||||
damage.min_damage = 1;
|
||||
}
|
||||
self thread breach_use_watch();
|
||||
}
|
||||
|
||||
self thread breach_on_activate();
|
||||
|
||||
self breach_on_event("init");
|
||||
|
||||
foreach(type in self.auto_breach_gametypes)
|
||||
{
|
||||
if(level.gametype == type)
|
||||
{
|
||||
self notify("breach_activated", undefined, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
add_breach_target(target, action, event_name, useSide)
|
||||
{
|
||||
if(!IsDefined(event_name))
|
||||
event_name = "activate";
|
||||
if(!IsDefined(useSide))
|
||||
useSide = false;
|
||||
|
||||
if(!IsDefined(self.breach_targets[event_name]))
|
||||
self.breach_targets[event_name] = [];
|
||||
|
||||
if(!IsDefined(self.breach_targets[event_name][action]))
|
||||
self.breach_targets[event_name][action] = [];
|
||||
|
||||
s = spawnStruct();
|
||||
s.target = target;
|
||||
|
||||
//Check if object has a facing
|
||||
if(useSide)
|
||||
{
|
||||
s.facing_dot = 0;
|
||||
s.facing_angles3d = false;
|
||||
s.facing_dir = AnglesToForward(target.angles);
|
||||
|
||||
if(IsDefined(target.target))
|
||||
{
|
||||
target_targets = getstructarray(target.target, "targetname");
|
||||
foreach(target_target in target_targets)
|
||||
{
|
||||
if(!IsDefined(target_target.script_noteworthy))
|
||||
continue;
|
||||
|
||||
switch(target_target.script_noteworthy)
|
||||
{
|
||||
case "angles":
|
||||
case "angles_3d":
|
||||
s.facing_angles3d = true;
|
||||
//fall through
|
||||
case "angles_2d":
|
||||
if(!IsDefined(s.angles3d))
|
||||
s.facing_angles3d = false;
|
||||
s.facing_dir = AnglesToForward(target_target.angles);
|
||||
if(IsDefined(target_target.script_dot))
|
||||
s.facing_dot = target_target.script_dot;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
size = self.breach_targets[event_name][action].size;
|
||||
self.breach_targets[event_name][action][size] = s;
|
||||
}
|
||||
|
||||
get_breach_target(action, event_name, player)
|
||||
{
|
||||
targets = get_breach_targets(action, event_name, player);
|
||||
if(targets.size>0)
|
||||
{
|
||||
return targets[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
get_breach_targets(action, event_name, player)
|
||||
{
|
||||
targets = [];
|
||||
|
||||
if(!IsDefined(event_name))
|
||||
event_name = "activate";
|
||||
|
||||
if(!IsDefined(self.breach_targets[event_name]))
|
||||
return targets;
|
||||
if(!IsDefined(self.breach_targets[event_name][action]))
|
||||
return targets;
|
||||
|
||||
foreach(s in self.breach_targets[event_name][action])
|
||||
{
|
||||
if(IsDefined(s.facing_dir) && IsDefined(player))
|
||||
{
|
||||
player_dir = player.origin - s.target.origin;
|
||||
if(!s.facing_angles3d)
|
||||
player_dir = (player_dir[0], player_dir[1], 0);
|
||||
player_dir = VectorNormalize(player_dir);
|
||||
|
||||
dot = VectorDot(player_dir, s.facing_dir);
|
||||
if(dot<s.facing_dot)
|
||||
continue;
|
||||
}
|
||||
|
||||
targets[targets.size] = s.target;
|
||||
}
|
||||
|
||||
return targets;
|
||||
}
|
||||
|
||||
breach_damage_watch( trigger )
|
||||
{
|
||||
self endon( "breach_activated" );
|
||||
|
||||
trigger waittill( "trigger", player );
|
||||
|
||||
self notify( "breach_activated", player, false );
|
||||
}
|
||||
|
||||
breach_on_activate()
|
||||
{
|
||||
self waittill("breach_activated", player, no_fx);
|
||||
if(!isDefined(no_fx))
|
||||
no_fx = false;
|
||||
|
||||
if( IsDefined(self.useObject) && !no_fx )
|
||||
{
|
||||
self.useObject breach_set_2dIcon("hud_grenadeicon_back_red");
|
||||
self.useObject delayThread(3, ::breach_set_2dIcon, undefined);
|
||||
}
|
||||
|
||||
breach_on_event("activate", player, no_fx);
|
||||
|
||||
if(IsDefined(self.useObject))
|
||||
self.useObject.visuals = [];
|
||||
|
||||
breach_set_can_use(false);
|
||||
}
|
||||
|
||||
breach_on_event( event_name, player, no_fx )
|
||||
{
|
||||
if ( !IsDefined( no_fx ) )
|
||||
no_fx = false;
|
||||
|
||||
if ( event_name == "use" ) // breach is being manually planted
|
||||
{
|
||||
targets = get_breach_targets( "damage", "activate", player );
|
||||
foreach ( target in targets )
|
||||
{
|
||||
target.planted = true;
|
||||
}
|
||||
}
|
||||
|
||||
array_call( get_breach_targets( "solid", event_name, player ), ::Solid );
|
||||
array_call( get_breach_targets( "notsolid", event_name, player ), ::NotSolid );
|
||||
array_thread( get_breach_targets( "hide", event_name, player ), ::breach_hide );
|
||||
array_thread( get_breach_targets( "show", event_name, player ), ::breach_show );
|
||||
array_thread( get_breach_targets( "teleport_show", event_name, player ), ::trigger_on );
|
||||
array_thread( get_breach_targets( "delete", event_name, player ), ::breach_delete );
|
||||
array_thread( get_breach_targets( "teleport_hide", event_name, player ), ::trigger_off );
|
||||
array_call( get_breach_targets( "connect_node", event_name, player ), ::ConnectNode );
|
||||
array_call( get_breach_targets( "disconnect_node", event_name, player ), ::DisconnectNode );
|
||||
array_thread( get_breach_targets( "break_glass", event_name, player ), ::breach_break_glass );
|
||||
array_thread( get_breach_targets( "animated", event_name, player ), ::breach_animate_model );
|
||||
|
||||
if ( !no_fx )
|
||||
{
|
||||
array_thread( get_breach_targets( "fx", event_name, player ), ::breach_play_fx, self );
|
||||
array_thread( get_breach_targets( "damage", event_name, player ), ::breach_damage_radius, player );
|
||||
}
|
||||
}
|
||||
|
||||
breach_delete()
|
||||
{
|
||||
if(IsDefined(self.script_index))
|
||||
{
|
||||
exploder(self.script_index);
|
||||
}
|
||||
|
||||
self SetAISightLineVisible( 0 );
|
||||
self delete();
|
||||
}
|
||||
|
||||
breach_hide()
|
||||
{
|
||||
self SetAISightLineVisible( 0 );
|
||||
self Hide();
|
||||
}
|
||||
|
||||
breach_show()
|
||||
{
|
||||
self SetAISightLineVisible( 1 );
|
||||
self Show();
|
||||
}
|
||||
|
||||
breach_play_fx(root)
|
||||
{
|
||||
fx_name = undefined;
|
||||
if(isdefined(self.script_fxid))
|
||||
{
|
||||
fx_name = self.script_fxid;
|
||||
}
|
||||
else if(IsDefined(root.script_fxid))
|
||||
{
|
||||
fx_name = root.script_fxid;
|
||||
}
|
||||
|
||||
if(!IsDefined(fx_name) || !IsDefined(level._effect[fx_name]))
|
||||
{
|
||||
fx_name = "default";
|
||||
}
|
||||
|
||||
PlayFX(level._effect[fx_name], self.origin, AnglesToForward(self.angles), AnglesToUp(self.angles));
|
||||
}
|
||||
|
||||
breach_damage_radius(attacker)
|
||||
{
|
||||
stuntime = 2.0; // 2 seconds is the minimum a concussion grenade will do
|
||||
|
||||
if( IsDefined( self.planted ) && ( self.planted == true ) )
|
||||
{
|
||||
// RadiusDamage(self.origin, self.radius, self.max_damage, self.min_damage, attacker);
|
||||
foreach( participant in level.participants )
|
||||
{
|
||||
participant_to_breach_dist_sq = DistanceSquared( self.origin, participant.origin );
|
||||
if( participant_to_breach_dist_sq < ( self.radius * self.radius ) )
|
||||
{
|
||||
participant ShellShock( "mp_radiation_high", stuntime );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PlayRumbleOnPosition( "artillery_rumble", self.origin );
|
||||
}
|
||||
|
||||
breach_break_glass()
|
||||
{
|
||||
GlassRadiusDamage( self.origin, 128, 500, 500 );
|
||||
}
|
||||
|
||||
breach_animate_model()
|
||||
{
|
||||
self SetAISightLineVisible( 1 );
|
||||
self Show();
|
||||
|
||||
if ( IsDefined( self.animation ) )
|
||||
{
|
||||
self ScriptModelPlayAnim( self.animation );
|
||||
}
|
||||
}
|
||||
|
||||
breach_use_watch()
|
||||
{
|
||||
self endon("breach_activated");
|
||||
wait .05;
|
||||
|
||||
self.useObject = maps\mp\gametypes\_gameobjects::createUseObject( "neutral", get_breach_target("trigger_use"), get_breach_targets("use_model"), (0,0,0) );
|
||||
self.useObject.parent = self;
|
||||
self.useObject.useWeapon = "breach_plant_mp";
|
||||
self.useObject.id = "breach";
|
||||
|
||||
self breach_set_can_use(true);
|
||||
self.useObject maps\mp\gametypes\_gameobjects::setUseTime( 0.5 );
|
||||
self.useObject maps\mp\gametypes\_gameobjects::setUseText( &"MP_BREACHING" );
|
||||
self.useObject maps\mp\gametypes\_gameobjects::setUseHintText( &"MP_BREACH" );
|
||||
self.useObject maps\mp\gametypes\_gameobjects::setVisibleTeam( "any" );
|
||||
self.useObject.onUse = ::breach_onUse;
|
||||
self.useObject.onEndUse = ::breach_onEndUse;
|
||||
}
|
||||
|
||||
breach_set_can_use(canUse)
|
||||
{
|
||||
if(!IsDefined(self.useObject))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(canUse)
|
||||
{
|
||||
foreach(vis in self.useObject.visuals)
|
||||
{
|
||||
if( vis.model == "mil_semtex_belt" )
|
||||
{
|
||||
vis SetModel("mil_semtex_belt_obj");
|
||||
}
|
||||
}
|
||||
self.useObject maps\mp\gametypes\_gameobjects::allowUse( "any" );
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach(vis in self.useObject.visuals)
|
||||
{
|
||||
if( vis.model == "mil_semtex_belt" )
|
||||
{
|
||||
vis SetModel("mil_semtex_belt");
|
||||
}
|
||||
}
|
||||
self.useObject notify( "disabled" );
|
||||
self.useObject maps\mp\gametypes\_gameobjects::allowUse( "none" );
|
||||
}
|
||||
}
|
||||
|
||||
breach_onUse(player)
|
||||
{
|
||||
self.parent endon("breach_activated");
|
||||
|
||||
self.parent notify("breach_used");
|
||||
self.parent breach_set_can_use(false);
|
||||
|
||||
self.parent breach_on_event("use", player);
|
||||
|
||||
self.parent thread breach_warning_icon(self);
|
||||
|
||||
sound_ent = undefined;
|
||||
sound_targets = self.parent get_breach_targets( "sound" );
|
||||
if ( sound_targets.size > 1 )
|
||||
{
|
||||
sound_targets = SortByDistance( sound_targets, player.origin );
|
||||
sound_ent = sound_targets[0];
|
||||
}
|
||||
else if ( sound_targets.size > 0 )
|
||||
{
|
||||
sound_ent = sound_targets[0];
|
||||
}
|
||||
|
||||
breaching_team = player.team; // need to store this in case the player switches teams between starting and finishing the breach
|
||||
|
||||
if(IsDefined(sound_ent))
|
||||
{
|
||||
for(i=0;i<3; i++)
|
||||
{
|
||||
sound_ent PlaySound("breach_beep");
|
||||
wait .75;
|
||||
}
|
||||
|
||||
if( IsDefined( sound_ent.script_parameters ) )
|
||||
{
|
||||
params = StrTok( sound_ent.script_parameters, ";" );
|
||||
foreach ( param in params )
|
||||
{
|
||||
toks = StrTok( param, "=" );
|
||||
if ( toks.size < 2 )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
switch( toks[ 0 ] )
|
||||
{
|
||||
case "play_sound":
|
||||
switch( toks[ 1 ] )
|
||||
{
|
||||
case "concrete":
|
||||
sound_ent PlaySound( "detpack_explo_concrete" );
|
||||
break;
|
||||
case "wood":
|
||||
sound_ent PlaySound( "detpack_explo_wood" );
|
||||
break;
|
||||
case "custom":
|
||||
if ( toks.size == 3 )
|
||||
{
|
||||
sound_ent PlaySound( toks[2] );
|
||||
}
|
||||
break;
|
||||
case "metal":
|
||||
case "undefined":
|
||||
default:
|
||||
sound_ent PlaySound( "detpack_explo_metal" );
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
sound_ent PlaySound( "detpack_explo_metal" );
|
||||
}
|
||||
}
|
||||
|
||||
self.parent notify( "breach_activated", player, undefined, breaching_team );
|
||||
}
|
||||
|
||||
breach_onEndUse( team, player, success )
|
||||
{
|
||||
if( IsPlayer( player ) )
|
||||
{
|
||||
player maps\mp\gametypes\_gameobjects::updateUIProgress( self, false );
|
||||
}
|
||||
}
|
||||
|
||||
breach_set_2dIcon( icon )
|
||||
{
|
||||
self maps\mp\gametypes\_gameobjects::set2DIcon( "enemy" , icon );
|
||||
self maps\mp\gametypes\_gameobjects::set2DIcon( "friendly", icon );
|
||||
}
|
||||
|
||||
breach_warning_icon( useObject )
|
||||
{
|
||||
icon_origin = useObject.curOrigin + ( 0, 0, 5 );
|
||||
if ( useobject.parent get_breach_targets( "use_icon" ).size )
|
||||
icon_origin = useobject.parent get_breach_targets( "use_icon" )[ 0 ].origin;
|
||||
|
||||
useObject.parent thread breach_icon( "warning", icon_origin, undefined, "breach_activated" );
|
||||
}
|
||||
|
||||
breach_icon( type, origin, angles, end_ons )
|
||||
{
|
||||
if ( level.createFX_enabled )
|
||||
return;
|
||||
|
||||
level.breach_icon_count++;
|
||||
|
||||
icon_id = "breach_icon_" + level.breach_icon_count;
|
||||
|
||||
breach_icon_update( type, origin, angles, icon_id, end_ons );
|
||||
|
||||
foreach ( player in level.players )
|
||||
{
|
||||
if ( IsDefined( player.breach_icons ) && IsDefined( player.breach_icons[ icon_id ] ) )
|
||||
{
|
||||
player.breach_icons[ icon_id ] thread breach_icon_fade_out();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
breach_icon_update( type, origin, angles, icon_id, end_ons )
|
||||
{
|
||||
if ( IsDefined( end_ons ) )
|
||||
{
|
||||
if ( IsString( end_ons ) )
|
||||
end_ons = [ end_ons ];
|
||||
|
||||
foreach ( end_on in end_ons )
|
||||
self endon( end_on );
|
||||
}
|
||||
|
||||
|
||||
show_dist = 100;
|
||||
show_z = 70;
|
||||
icon = "hud_grenadeicon";
|
||||
pin = true;
|
||||
switch( type )
|
||||
{
|
||||
case "use":
|
||||
show_dist = 300;
|
||||
icon = "breach_icon";
|
||||
pin = false;
|
||||
break;
|
||||
case "warning":
|
||||
show_dist = 400;
|
||||
damage_info = get_breach_target( "damage" );
|
||||
if ( IsDefined( damage_info ) )
|
||||
show_dist = damage_info.radius;
|
||||
icon = "hud_grenadeicon";
|
||||
pin = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
show_dir = undefined;
|
||||
if ( IsDefined( angles ) )
|
||||
{
|
||||
show_dir = AnglesToForward( angles );
|
||||
}
|
||||
|
||||
while ( 1 )
|
||||
{
|
||||
foreach ( player in level.players )
|
||||
{
|
||||
if ( !IsDefined( player.breach_icons ) )
|
||||
player.breach_icons = [];
|
||||
|
||||
if ( breach_icon_update_is_player_in_range( player, origin, show_dist, show_dir, show_z ) )
|
||||
{
|
||||
if ( !IsDefined( player.breach_icons[ icon_id ] ) )
|
||||
{
|
||||
player.breach_icons[ icon_id ] = breach_icon_create( player, icon, origin, pin );
|
||||
player.breach_icons[ icon_id ].alpha = 0;
|
||||
}
|
||||
|
||||
player.breach_icons[ icon_id ] notify( "stop_fade" );
|
||||
player.breach_icons[ icon_id ] thread breach_icon_fade_in();
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( IsDefined( player.breach_icons[ icon_id ] ) )
|
||||
{
|
||||
player.breach_icons[ icon_id ] thread breach_icon_fade_out();
|
||||
}
|
||||
}
|
||||
}
|
||||
wait 0.05;
|
||||
}
|
||||
}
|
||||
|
||||
breach_icon_update_is_player_in_range( player, origin, show_dist, show_dir, show_z )
|
||||
{
|
||||
test_origin = player.origin+(0,0,30);
|
||||
|
||||
if(IsDefined(show_z) && abs(test_origin[2] - origin[2]) > show_z)
|
||||
return false;
|
||||
|
||||
if(IsDefined(show_dist))
|
||||
{
|
||||
show_dist_sqr = show_dist*show_dist;
|
||||
dist_sqr = DistanceSquared(test_origin, origin);
|
||||
if(dist_sqr>show_dist_sqr)
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if(IsDefined(show_dir))
|
||||
{
|
||||
dir_to_player = test_origin - origin;
|
||||
//Normalize dir_to_player if not checking against zero.
|
||||
if(VectorDot(show_dir, dir_to_player)<0)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
breach_icon_create(player, icon, origin, pin)
|
||||
{
|
||||
icon = player createIcon( icon, 16, 16 );
|
||||
icon setWayPoint( true, pin );
|
||||
icon.x = origin[0];
|
||||
icon.y = origin[1];
|
||||
icon.z = origin[2];
|
||||
return icon;
|
||||
}
|
||||
|
||||
breach_icon_fade_in()
|
||||
{
|
||||
self endon("death");
|
||||
|
||||
if(self.alpha == 1)
|
||||
return;
|
||||
|
||||
self FadeOverTime(.5);
|
||||
self.alpha = 1;
|
||||
}
|
||||
|
||||
breach_icon_fade_out()
|
||||
{
|
||||
self endon("death");
|
||||
self endon("stop_fade");
|
||||
|
||||
if(self.alpha == 0)
|
||||
return;
|
||||
|
||||
time = .5;
|
||||
self FadeOverTime(time);
|
||||
self.alpha = 0;
|
||||
wait time;
|
||||
|
||||
self Destroy();
|
||||
}
|
85
maps/mp/_compass.gsc
Normal file
85
maps/mp/_compass.gsc
Normal file
@ -0,0 +1,85 @@
|
||||
setupMiniMap(material)
|
||||
{
|
||||
// use 0 for no required map aspect ratio.
|
||||
requiredMapAspectRatio = level.requiredMapAspectRatio;
|
||||
|
||||
corners = getentarray("minimap_corner", "targetname");
|
||||
if (corners.size != 2)
|
||||
{
|
||||
println("^1Error: There are not exactly two \"minimap_corner\" entities in the map. Could not set up minimap.");
|
||||
return;
|
||||
}
|
||||
|
||||
corner0 = (corners[0].origin[0], corners[0].origin[1], 0);
|
||||
corner1 = (corners[1].origin[0], corners[1].origin[1], 0);
|
||||
|
||||
cornerdiff = corner1 - corner0;
|
||||
|
||||
north = (cos(getnorthyaw()), sin(getnorthyaw()), 0);
|
||||
west = (0 - north[1], north[0], 0);
|
||||
|
||||
// we need the northwest and southeast corners. all we know is that corner0 is opposite of corner1.
|
||||
if (vectordot(cornerdiff, west) > 0) {
|
||||
// corner1 is further west than corner0
|
||||
if (vectordot(cornerdiff, north) > 0) {
|
||||
// corner1 is northwest, corner0 is southeast
|
||||
northwest = corner1;
|
||||
southeast = corner0;
|
||||
}
|
||||
else {
|
||||
// corner1 is southwest, corner0 is northeast
|
||||
side = vecscale(north, vectordot(cornerdiff, north));
|
||||
northwest = corner1 - side;
|
||||
southeast = corner0 + side;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// corner1 is further east than corner0
|
||||
if (vectordot(cornerdiff, north) > 0) {
|
||||
// corner1 is northeast, corner0 is southwest
|
||||
side = vecscale(north, vectordot(cornerdiff, north));
|
||||
northwest = corner0 + side;
|
||||
southeast = corner1 - side;
|
||||
}
|
||||
else {
|
||||
// corner1 is southeast, corner0 is northwest
|
||||
northwest = corner0;
|
||||
southeast = corner1;
|
||||
}
|
||||
}
|
||||
|
||||
if( GetDvar("mapname") == "mp_boneyard_ns")
|
||||
{
|
||||
southeast -= (220,220,0);
|
||||
northwest += (220,220,0);
|
||||
}
|
||||
|
||||
// expand map area to fit required aspect ratio
|
||||
if ( requiredMapAspectRatio > 0 )
|
||||
{
|
||||
northportion = vectordot(northwest - southeast, north);
|
||||
westportion = vectordot(northwest - southeast, west);
|
||||
mapAspectRatio = westportion / northportion;
|
||||
if ( mapAspectRatio < requiredMapAspectRatio )
|
||||
{
|
||||
incr = requiredMapAspectRatio / mapAspectRatio;
|
||||
addvec = vecscale( west, westportion * (incr - 1) * 0.5 );
|
||||
}
|
||||
else
|
||||
{
|
||||
incr = mapAspectRatio / requiredMapAspectRatio;
|
||||
addvec = vecscale( north, northportion * (incr - 1) * 0.5 );
|
||||
}
|
||||
northwest += addvec;
|
||||
southeast -= addvec;
|
||||
}
|
||||
|
||||
level.mapSize = vectordot(northwest - southeast, north);
|
||||
|
||||
setMiniMap(material, northwest[0], northwest[1], southeast[0], southeast[1]);
|
||||
}
|
||||
|
||||
vecscale(vec, scalar)
|
||||
{
|
||||
return (vec[0]*scalar, vec[1]*scalar, vec[2]*scalar);
|
||||
}
|
74
maps/mp/_createfx.gsc
Normal file
74
maps/mp/_createfx.gsc
Normal file
@ -0,0 +1,74 @@
|
||||
#include common_scripts\utility;
|
||||
#include maps\mp\_utility;
|
||||
#include common_scripts\_createFxMenu;
|
||||
#include common_scripts\_createfx;
|
||||
#include common_scripts\_fx;
|
||||
|
||||
createfx()
|
||||
{
|
||||
level.func_position_player = ::void;
|
||||
level.func_position_player_get = ::func_position_player_get;
|
||||
level.func_loopfxthread = ::loopfxthread;
|
||||
level.func_oneshotfxthread = ::oneshotfxthread;
|
||||
level.func_create_loopsound = ::create_loopsound;
|
||||
// level.func_exploder_preload = ::exploder_before_load;;
|
||||
// level.func_exploder_postload = ::exploder_after_load;;
|
||||
level.func_updatefx = ::restart_fx_looper;
|
||||
level.func_process_fx_rotater = ::process_fx_rotater;
|
||||
level.func_player_speed = ::func_player_speed;
|
||||
|
||||
level.mp_createfx = true;
|
||||
|
||||
// MP only stuff
|
||||
level.callbackStartGameType = ::void;
|
||||
level.callbackPlayerConnect = ::void;
|
||||
level.callbackPlayerDisconnect = ::void;
|
||||
level.callbackPlayerDamage = ::void;
|
||||
level.callbackPlayerKilled = ::void;
|
||||
level.callbackCodeEndGame = ::void;
|
||||
level.callbackPlayerLastStand = ::void;
|
||||
level.callbackPlayerConnect = ::Callback_PlayerConnect;
|
||||
level.callbackPlayerMigrated = ::void;
|
||||
|
||||
thread func_get_level_fx(); // start gettin these on start
|
||||
createfx_common();
|
||||
|
||||
level waittill( "eternity" );
|
||||
}
|
||||
|
||||
func_position_player_get( lastPlayerOrigin )
|
||||
{
|
||||
return level.player.origin;
|
||||
}
|
||||
|
||||
Callback_PlayerConnect()
|
||||
{
|
||||
self waittill( "begin" );
|
||||
|
||||
if ( !isdefined( level.player ) )
|
||||
{
|
||||
spawnpoints = getentarray( "mp_global_intermission", "classname" );
|
||||
self spawn( spawnpoints[0].origin, spawnpoints[0].angles );
|
||||
self updateSessionState( "playing", "" );
|
||||
self.maxhealth = 10000000;
|
||||
self.health = 10000000;
|
||||
level.player = self;
|
||||
|
||||
thread createFxLogic();
|
||||
//thread ufo_mode();
|
||||
}
|
||||
else
|
||||
kick( self GetEntityNumber() );
|
||||
}
|
||||
|
||||
//ufo_mode()
|
||||
//{
|
||||
// level.player openpopupmenu( "painter_mp" );// painter.menu execs some console commands( ufo mode ).. sneaky hacks.
|
||||
// level.player closepopupmenu( "painter_mp" );
|
||||
//}
|
||||
|
||||
func_player_speed()
|
||||
{
|
||||
scale = level._createfx.player_speed / 190;
|
||||
level.player SetMoveSpeedScale( scale );
|
||||
}
|
727
maps/mp/_crib.gsc
Normal file
727
maps/mp/_crib.gsc
Normal file
@ -0,0 +1,727 @@
|
||||
#include maps\mp\_utility;
|
||||
#include common_scripts\utility;
|
||||
|
||||
CONST_default_radial_radius = 8; // default distance between radial button and center
|
||||
CONST_radial_center_extrude_dist = 40; // this is the distance between the floating radial center and the oberver's eye
|
||||
CONST_direct_travel = 1; // no path, directly zoom to position
|
||||
CONST_view_travel_unit_dist = 1200; // distance unit per travel interval
|
||||
CONST_view_travel_unit_time = 1; // in seconds per travel interval
|
||||
CONST_blur_strength = 3; // blur strength during view travel, sine curved over travel duration
|
||||
|
||||
init()
|
||||
{
|
||||
precacheShellShock( "frag_grenade_mp" );
|
||||
|
||||
radial_button_definitions(); // define radial button sets and buttons
|
||||
radial_init(); // setup radial button mechanism
|
||||
view_path_setup(); // setup view flight paths
|
||||
player_init();
|
||||
}
|
||||
|
||||
// ====================================================================================
|
||||
// == inits ==
|
||||
// ====================================================================================
|
||||
|
||||
radial_button_definitions()
|
||||
{
|
||||
newRadialButtonGroup( "main", "player_view1_start", "player_view1_end" );
|
||||
|
||||
// Main menu's buttons:
|
||||
bWeapons_a = newRadialButton( "main", "Primary Weapon", "radial_weapons_primary", ::action_weapons_primary );
|
||||
bWeapons_b = newRadialButton( "main", "Secondary Weapon", "radial_weapons_secondary", ::action_weapons_secondary );
|
||||
bGears = newRadialButton( "main", "Gears", "radial_gears", ::action_gears );
|
||||
bKillStreaks= newRadialButton( "main", "Kill Streaks", "radial_killstreaks", ::action_killstreak );
|
||||
bLeadboards = newRadialButton( "main", "Leaderboards", "radial_leaderboards", ::action_leaderboards );
|
||||
//
|
||||
|
||||
newRadialButtonGroup( "gears", "player_view2_start", "player_view2_end" );
|
||||
newRadialButtonGroup( "weapons_primary", "player_view3_start", "player_view3_end" );
|
||||
newRadialButtonGroup( "weapons_secondary", "player_view3_start", "player_view3_end" );
|
||||
newRadialButtonGroup( "killstreak", "player_view4_start", "player_view4_end" );
|
||||
newRadialButtonGroup( "leaderboards", "player_view5_start", "player_view5_end" );
|
||||
}
|
||||
|
||||
|
||||
radial_init()
|
||||
{
|
||||
// calculate start & end angles of all buttons for range selection
|
||||
foreach ( button_group in level.radial_button_group )
|
||||
{
|
||||
// sort buttons by angle so we can calculate mid angles in sequence
|
||||
sort_buttons_by_angle( button_group );
|
||||
|
||||
for ( i = 0; i < button_group.size; i ++ )
|
||||
{
|
||||
if ( isdefined( button_group[ i + 1 ] ) )
|
||||
{
|
||||
mid_angle = getMidAngle( button_group[ i ].pos_angle, button_group[ i + 1 ].pos_angle );
|
||||
button_group[ i ].end_angle = mid_angle;
|
||||
button_group[ i + 1 ].start_angle = mid_angle;
|
||||
}
|
||||
else
|
||||
{
|
||||
mid_angle = getMidAngle( button_group[ i ].pos_angle, button_group[ 0 ].pos_angle ) + 180; // +180 to mirror angle
|
||||
if ( mid_angle > 360 )
|
||||
mid_angle -= 360;
|
||||
|
||||
button_group[ i ].end_angle = mid_angle;
|
||||
button_group[ 0 ].start_angle = mid_angle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// monitors
|
||||
thread updateSelectedButton();
|
||||
thread watchSelectButtonPress();
|
||||
thread watchBackButtonPress();
|
||||
thread debug_toggle();
|
||||
}
|
||||
|
||||
|
||||
debug_toggle()
|
||||
{
|
||||
level endon( "game_ended" );
|
||||
level.crib_debug = 1;
|
||||
|
||||
while ( 1 )
|
||||
{
|
||||
if ( !isdefined( level.observer ) )
|
||||
{
|
||||
wait 0.05;
|
||||
continue;
|
||||
}
|
||||
|
||||
button_reset = true;
|
||||
while ( !( level.observer buttonPressed( "BUTTON_Y" ) ) )
|
||||
wait 0.05;
|
||||
|
||||
level.observer playsound("mouse_click");
|
||||
|
||||
if ( button_reset )
|
||||
{
|
||||
level.crib_debug *= -1;
|
||||
button_reset = false;
|
||||
}
|
||||
|
||||
while ( level.observer buttonPressed( "BUTTON_Y" ) )
|
||||
wait 0.05;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
player_init()
|
||||
{
|
||||
level thread onPlayerConnect();
|
||||
level thread return_hud();
|
||||
}
|
||||
|
||||
|
||||
return_hud()
|
||||
{
|
||||
level waittill( "game_ended" );
|
||||
setdvar( "cg_draw2d", 1 );
|
||||
}
|
||||
|
||||
|
||||
onPlayerConnect()
|
||||
{
|
||||
level waittill("connected", player);
|
||||
|
||||
player thread readyPlayer();
|
||||
player waittill( "spawned_player" );
|
||||
|
||||
wait 1;
|
||||
|
||||
player takeallweapons();
|
||||
setdvar( "cg_draw2d", 0 );
|
||||
|
||||
if ( !isdefined( player ) )
|
||||
return;
|
||||
else
|
||||
level.observer = player;
|
||||
|
||||
player thread get_right_stick_angle();
|
||||
|
||||
zoom_to_radial_menu( "main" ); // fly to the first radial menu
|
||||
}
|
||||
|
||||
|
||||
readyPlayer()
|
||||
{
|
||||
self endon( "disconnect" );
|
||||
|
||||
team = "autoassign";
|
||||
|
||||
while(!isdefined(self.pers["team"]))
|
||||
wait .05;
|
||||
|
||||
self notify("menuresponse", game["menu_team"], team);
|
||||
wait 0.5;
|
||||
|
||||
classes = getArrayKeys( level.classMap );
|
||||
okclasses = [];
|
||||
for ( i = 0; i < classes.size; i++ )
|
||||
{
|
||||
if ( !isSubStr( classes[i], "custom" ) )
|
||||
okclasses[ okclasses.size ] = classes[i];
|
||||
}
|
||||
|
||||
assert( okclasses.size );
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
class = okclasses[ 0 ];
|
||||
self notify("menuresponse", "changeclass", class);
|
||||
|
||||
self waittill( "spawned_player" );
|
||||
wait ( 0.10 );
|
||||
}
|
||||
}
|
||||
|
||||
// ====================================================================================
|
||||
// == Radial Mechanics ==
|
||||
// ====================================================================================
|
||||
|
||||
get_right_stick_angle()
|
||||
{
|
||||
// self is user
|
||||
level endon( "game_ended" );
|
||||
self endon( "disconnect" );
|
||||
|
||||
while ( 1 )
|
||||
{
|
||||
rs_vec = self GetNormalizedMovement();
|
||||
rs_angles = vectortoangles( rs_vec );
|
||||
level.rs_angle = int( rs_angles[1] );
|
||||
|
||||
wait 0.05; // update rate
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
newRadialButtonGroup( group_name, view_start, view_end )
|
||||
{
|
||||
if ( isdefined( level.radial_button_group ) && level.radial_button_group.size )
|
||||
assertex( !isdefined( level.radial_button_group[ group_name ] ), "Radial button group: " + group_name + " is already defined." );
|
||||
|
||||
player_view_ent = getent( view_end, "targetname" );
|
||||
assertex( isdefined( player_view_ent ), "Missing player view entity, can not setup radial menu in space" );
|
||||
|
||||
extruded_vec = ( VectorNormalize( AnglesToForward( player_view_ent.angles ) ) * CONST_radial_center_extrude_dist );
|
||||
|
||||
level.radial_button_group[ group_name ] = [];
|
||||
level.radial_button_group_info[ group_name ][ "view_start" ] = view_start;
|
||||
level.radial_button_group_info[ group_name ][ "view_pos" ] = player_view_ent.origin + extruded_vec;
|
||||
level.radial_button_group_info[ group_name ][ "player_view_pos" ] = player_view_ent.origin;
|
||||
level.radial_button_group_info[ group_name ][ "view_angles" ] = player_view_ent.angles;
|
||||
}
|
||||
|
||||
|
||||
newRadialButton( button_group, button_label, button_ent_name, action_func )
|
||||
{
|
||||
assertex( isdefined( level.radial_button_group[ button_group ] ), "Radial button group: " + button_group + " does not exist." );
|
||||
|
||||
ent = getent( button_ent_name, "targetname" );
|
||||
new_button_angle = getRadialAngleFromEnt( button_group, ent );
|
||||
|
||||
button = spawnstruct();
|
||||
button.pos = ent.origin;
|
||||
button.label = button_label;
|
||||
button.font_size = 1;
|
||||
button.font_color = ( 0.5, 0.5, 1 );
|
||||
button.pos_angle = new_button_angle;
|
||||
button.action_func = action_func;
|
||||
button.radius_pos = CONST_default_radial_radius;
|
||||
|
||||
level.radial_button_group[ button_group ][ level.radial_button_group[ button_group ].size ] = button;
|
||||
return button;
|
||||
}
|
||||
|
||||
|
||||
updateSelectedButton()
|
||||
{
|
||||
level endon( "game_ended" );
|
||||
|
||||
while ( 1 )
|
||||
{
|
||||
if ( !isdefined( level.radial_button_current_group ) )
|
||||
{
|
||||
wait 0.05;
|
||||
continue;
|
||||
}
|
||||
|
||||
last_active_button = level.active_button;
|
||||
|
||||
foreach ( button in level.radial_button_group[ level.radial_button_current_group ] )
|
||||
{
|
||||
if ( isInRange( button.start_angle, button.end_angle ) )
|
||||
level.active_button = button;
|
||||
else
|
||||
button.font_color = ( 0.5, 0.5, 1 );
|
||||
}
|
||||
|
||||
if ( isdefined ( level.active_button ) )
|
||||
{
|
||||
level.active_button.font_color = ( 1, 1, 0.5 );
|
||||
|
||||
if ( isdefined( last_active_button ) && last_active_button != level.active_button )
|
||||
level.observer playsound("mouse_over");
|
||||
}
|
||||
|
||||
wait 0.05;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
watchSelectButtonPress()
|
||||
{
|
||||
level endon( "game_ended" );
|
||||
|
||||
while ( 1 )
|
||||
{
|
||||
if ( !isdefined( level.observer ) )
|
||||
{
|
||||
wait 0.05;
|
||||
continue;
|
||||
}
|
||||
|
||||
button_reset = true;
|
||||
while ( !( level.observer buttonPressed( "BUTTON_A" ) ) )
|
||||
wait 0.05;
|
||||
|
||||
level.observer playsound("mouse_click");
|
||||
|
||||
if ( isdefined( level.active_button ) && button_reset )
|
||||
{
|
||||
level.active_button notify( "select_button_pressed" );
|
||||
[[level.active_button.action_func]]();
|
||||
button_reset = false;
|
||||
}
|
||||
|
||||
while ( level.observer buttonPressed( "BUTTON_A" ) )
|
||||
wait 0.05;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
watchBackButtonPress()
|
||||
{
|
||||
level endon( "game_ended" );
|
||||
|
||||
while ( 1 )
|
||||
{
|
||||
if ( !isdefined( level.observer ) )
|
||||
{
|
||||
wait 0.05;
|
||||
continue;
|
||||
}
|
||||
|
||||
button_reset = true;
|
||||
while ( !( level.observer buttonPressed( "BUTTON_X" ) ) )
|
||||
wait 0.05;
|
||||
|
||||
level.observer playsound("mouse_click");
|
||||
|
||||
if ( button_reset )
|
||||
{
|
||||
action_back();
|
||||
button_reset = false;
|
||||
}
|
||||
|
||||
while ( level.observer buttonPressed( "BUTTON_X" ) )
|
||||
wait 0.05;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sort_buttons_by_angle( button_group )
|
||||
{
|
||||
// button_group is actual array
|
||||
// bubble sort buttons
|
||||
for ( i = 0; i < button_group.size - 1; i++ )
|
||||
{
|
||||
for ( j = 0; j < button_group.size - 1 - i; j++ )
|
||||
{
|
||||
if ( button_group[ j + 1 ].pos_angle < button_group[ j ].pos_angle )
|
||||
button_switch( button_group[ j ], button_group[ j + 1 ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
button_switch( button1, button2 )
|
||||
{
|
||||
temp_pos = button1.pos;
|
||||
temp_label = button1.label;
|
||||
temp_pos_angle = button1.pos_angle;
|
||||
temp_action_func = button1.action_func;
|
||||
temp_radius_pos = button1.radius_pos;
|
||||
|
||||
button1.pos = button2.pos;
|
||||
button1.label = button2.label;
|
||||
button1.pos_angle = button2.pos_angle;
|
||||
button1.action_func = button2.action_func;
|
||||
button1.radius_pos = button2.radius_pos;
|
||||
|
||||
button2.pos = temp_pos;
|
||||
button2.label = temp_label;
|
||||
button2.pos_angle = temp_pos_angle;
|
||||
button2.action_func = temp_action_func;
|
||||
button2.radius_pos = temp_radius_pos;
|
||||
}
|
||||
|
||||
|
||||
draw_radial_buttons( button_group )
|
||||
{
|
||||
foreach ( button in level.radial_button_group[ button_group ] )
|
||||
button thread draw_radial_button( button_group );
|
||||
}
|
||||
|
||||
|
||||
//print3d(<origin>, <text>, <color>, <alpha>, <scale>, <duration> )
|
||||
draw_radial_button( button_group )
|
||||
{
|
||||
level endon( "game_ended" );
|
||||
self endon( "remove_button" );
|
||||
|
||||
floating_origin = level.radial_button_group_info[ button_group ][ "view_pos" ];
|
||||
button_radial_pos = floating_origin + radial_angle_to_vector( self.pos_angle, 4 );
|
||||
|
||||
while ( 1 )
|
||||
{
|
||||
//line( level.radial_button_group_info[ button_group ][ "view_pos" ], self.pos, ( 0, 1, 0 ), 0.05, false );
|
||||
|
||||
range_color = ( 1, 0, 0 );
|
||||
if ( isInRange( self.start_angle, self.end_angle ) )
|
||||
range_color = ( 1, 1, 0 );
|
||||
|
||||
print3d( self.pos, self.label, self.font_color, 0.75, self.font_size, 1 );
|
||||
|
||||
if ( isdefined( level.crib_debug ) && level.crib_debug > 0 )
|
||||
{
|
||||
print3d( button_radial_pos, ".("+int(self.pos_angle)+")", range_color, 0.75, 0.05, 1 );
|
||||
|
||||
line( floating_origin, floating_origin + radial_angle_to_vector( self.start_angle, 2 ), range_color, 0.05 );
|
||||
line( floating_origin + radial_angle_to_vector( self.start_angle, 2 ), floating_origin + radial_angle_to_vector( self.end_angle, 2 ), range_color, 0.05 );
|
||||
|
||||
// right stick debug ling
|
||||
r_radial_pos = floating_origin + radial_angle_to_vector( level.rs_angle, 2 );
|
||||
line( floating_origin, r_radial_pos, ( 1, 1, 1 ), 0.05 );
|
||||
|
||||
|
||||
}
|
||||
print3d( floating_origin - ( 0, 0, 4.5 ), "(A)=Select (X)=Back", (1, 1, 1), 0.5, 0.05, 1 );
|
||||
|
||||
wait 0.05;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Zoom_To_Radial_Menu( button_group, reverse )
|
||||
{
|
||||
level.active_button = undefined;
|
||||
|
||||
assertex( isdefined( level.observer ), "Missing observer (connected player), can not attach player to view path" );
|
||||
|
||||
if ( isdefined( level.radial_button_current_group ) && level.radial_button_current_group != "" )
|
||||
{
|
||||
level.radial_button_previous_group = level.radial_button_current_group;
|
||||
}
|
||||
else
|
||||
{
|
||||
level.radial_button_previous_group = "main";
|
||||
level.radial_button_current_group = "main";
|
||||
}
|
||||
|
||||
foreach ( button in level.radial_button_group[ level.radial_button_previous_group ] )
|
||||
button notify( "remove_button" );
|
||||
|
||||
//iPrintLnBold( "flying to: " + button_group );
|
||||
|
||||
if ( isdefined( reverse ) && reverse )
|
||||
level.observer go_path_by_targetname_reverse( level.radial_button_group_info[ level.radial_button_previous_group ][ "view_start" ], button_group );
|
||||
else
|
||||
level.observer go_path_by_targetname( level.radial_button_group_info[ button_group ][ "view_start" ] );
|
||||
|
||||
level thread draw_radial_buttons( button_group );
|
||||
level.radial_button_current_group = button_group;
|
||||
}
|
||||
|
||||
|
||||
// ====================================================================================
|
||||
// == Radial menu - math ==
|
||||
// ====================================================================================
|
||||
|
||||
// edit function with care, returns orientation-sensistive angles
|
||||
getRadialAngleFromEnt( button_group, ent )
|
||||
{
|
||||
assertex( isdefined( level.radial_button_group[ button_group ] ), "getRadialAngleFromEnt: Radial button group does not exist." );
|
||||
assertex( isdefined( ent ), "getRadialAngleFromEnt: Missing entity to be measured." );
|
||||
|
||||
rAngle = level.radial_button_group_info[ button_group ][ "view_angles" ];
|
||||
rPos = level.radial_button_group_info[ button_group ][ "view_pos" ];
|
||||
rPos += ( VectorNormalize( AnglesToForward( rAngle ) ) * CONST_radial_center_extrude_dist );
|
||||
rForward = AnglesToForward( rAngle );
|
||||
rUpwardNorm = VectorNormalize( AnglesToUp( rAngle ) );
|
||||
|
||||
eAngle = ent.angles;
|
||||
ePos = ent.origin;
|
||||
|
||||
projNorm = VectorNormalize( VectorFromLineToPoint( rPos, ( rPos + rForward ), ePos ) );
|
||||
radial_angle = Acos( VectorDot( projNorm, rUpwardNorm ) );
|
||||
|
||||
// vector mirroring
|
||||
if ( VectorDot( AnglesToRight( rAngle ), projNorm ) < 0 )
|
||||
radial_angle = 360 - radial_angle;
|
||||
|
||||
return radial_angle;
|
||||
}
|
||||
|
||||
|
||||
// converts projected angle into player's view plane into a vector
|
||||
radial_angle_to_vector( angle, scaler )
|
||||
{
|
||||
b_angles = ( 270 - ( angle ), 0 , 0 ); // 270 degrees offset to face the player
|
||||
b_vec = AnglesToForward( b_angles );
|
||||
b_vec_norm = VectorNormalize( b_vec );
|
||||
b_vec_final = ( b_vec_norm * scaler );
|
||||
|
||||
return b_vec_final;
|
||||
}
|
||||
|
||||
|
||||
getMidAngle( a1, a2 )
|
||||
{
|
||||
// 0 -> 360 domain
|
||||
mid_angle = ( ( a1 + a2 + 720 ) / 2 ) - 360;
|
||||
return mid_angle;
|
||||
}
|
||||
|
||||
|
||||
isInRange( start_angle, end_angle )
|
||||
{
|
||||
inside_big_angle = ( level.rs_angle > start_angle && level.rs_angle < 360 );
|
||||
inside_small_angle = ( level.rs_angle > 0 && level.rs_angle < end_angle );
|
||||
|
||||
if ( start_angle > end_angle )
|
||||
in_range = ( inside_big_angle || inside_small_angle );
|
||||
else
|
||||
in_range = ( level.rs_angle > start_angle && level.rs_angle < end_angle );
|
||||
|
||||
return in_range;
|
||||
}
|
||||
|
||||
// ====================================================================================
|
||||
// == Button action functions ==
|
||||
// ====================================================================================
|
||||
|
||||
// close radial buttons
|
||||
action_back()
|
||||
{
|
||||
//if ( isdefined( level.radial_button_previous_group ) && level.radial_button_previous_group != "" )
|
||||
// zoom_to_radial_menu( level.radial_button_previous_group );
|
||||
/*else*/ if ( isdefined( level.radial_button_current_group ) && level.radial_button_current_group != "main" )
|
||||
zoom_to_radial_menu( "main", true );
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// ==== main ====
|
||||
action_weapons_primary()
|
||||
{
|
||||
iPrintLnBold( "action_weapons_primary" );
|
||||
zoom_to_radial_menu( "weapons_primary" );
|
||||
}
|
||||
|
||||
|
||||
action_weapons_secondary()
|
||||
{
|
||||
iPrintLnBold( "action_weapons_secondary" );
|
||||
zoom_to_radial_menu( "weapons_secondary" );
|
||||
}
|
||||
|
||||
action_gears()
|
||||
{
|
||||
iPrintLnBold( "action_gears" );
|
||||
zoom_to_radial_menu( "gears" );
|
||||
}
|
||||
|
||||
|
||||
action_killstreak()
|
||||
{
|
||||
iPrintLnBold( "action_killstreak" );
|
||||
zoom_to_radial_menu( "killstreak" );
|
||||
}
|
||||
|
||||
|
||||
action_leaderboards()
|
||||
{
|
||||
iPrintLnBold( "action_leaderboards" );
|
||||
zoom_to_radial_menu( "leaderboards" );
|
||||
}
|
||||
|
||||
// ====================================================================================
|
||||
// == Pathing functions ==
|
||||
// ====================================================================================
|
||||
|
||||
view_path_setup()
|
||||
{
|
||||
// setup all paths
|
||||
level.view_paths = [];
|
||||
|
||||
// build paths
|
||||
build_path_by_targetname( "player_view1_start" );
|
||||
build_path_by_targetname( "player_view2_start" );
|
||||
build_path_by_targetname( "player_view3_start" );
|
||||
build_path_by_targetname( "player_view4_start" );
|
||||
build_path_by_targetname( "player_view5_start" );
|
||||
}
|
||||
|
||||
|
||||
build_path_by_targetname( path_name )
|
||||
{
|
||||
level.view_paths[ path_name ] = [];
|
||||
|
||||
path_node = getent( path_name, "targetname" );
|
||||
level.view_paths[ path_name ][ level.view_paths[ path_name ].size ] = path_node;
|
||||
|
||||
while( isdefined( path_node ) && isdefined( path_node.target ) )
|
||||
{
|
||||
next_node = getent( path_node.target, "targetname" );
|
||||
level.view_paths[ path_name ][ level.view_paths[ path_name ].size ] = next_node;
|
||||
path_node = next_node;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
go_path_by_targetname( path_name )
|
||||
{
|
||||
// self is player
|
||||
if ( !isdefined( level.dummy_mover ) )
|
||||
{
|
||||
start_node = level.view_paths[ path_name ][ 0 ];
|
||||
level.dummy_mover = spawn( "script_model", start_node.origin );
|
||||
level.dummy_mover.angles = start_node.angles;
|
||||
//self AllowedStances( "stand" );
|
||||
self setOrigin( level.dummy_mover.origin - ( 0, 0, 65 ) );
|
||||
self linkTo( level.dummy_mover );
|
||||
wait 0.05;
|
||||
self setplayerangles ( level.dummy_mover.angles );
|
||||
|
||||
self thread force_player_angles();
|
||||
}
|
||||
|
||||
/*
|
||||
travel_time = 1;
|
||||
dist = 0;
|
||||
foreach ( idx, node in level.view_paths[ path_name ] )
|
||||
{
|
||||
if ( isdefined( level.view_paths[ path_name ][ idx + 1 ] ) )
|
||||
dist += abs( distance( level.view_paths[ path_name ][ idx ].origin, level.view_paths[ path_name ][ idx + 1 ].origin ) );
|
||||
}*/
|
||||
|
||||
travel_speed = CONST_view_travel_unit_time;
|
||||
total_distance = abs( distance( level.dummy_mover.origin, level.view_paths[ path_name ][ level.view_paths[ path_name ].size - 1 ].origin ) );
|
||||
travel_speed *= total_distance / CONST_view_travel_unit_dist;
|
||||
travel_speed = max( travel_speed, 0.1 ); // due to repeated button presses, the travel distance can be cut to 0 travel speed at times.
|
||||
|
||||
blur_time = travel_speed;
|
||||
if ( !CONST_direct_travel )
|
||||
blur_time *= travel_speed * ( level.view_paths[ path_name ].size + 1 );
|
||||
self thread blur_sine( CONST_blur_strength, blur_time );
|
||||
|
||||
foreach ( idx, node in level.view_paths[ path_name ] )
|
||||
{
|
||||
//travel_speed = travel_time * ( abs( distance( level.dummy_mover.origin, node.origin ) ) / dist );
|
||||
//travel_speed += 0.05;
|
||||
|
||||
if ( CONST_direct_travel )
|
||||
{
|
||||
if ( idx != level.view_paths[ path_name ].size - 1 )
|
||||
continue;
|
||||
}
|
||||
|
||||
//level.dummy_mover MoveTo( node.origin, travel_speed );
|
||||
level.dummy_mover MoveTo( node.origin, travel_speed, travel_speed * 0.5, 0 );
|
||||
level.dummy_mover RotateTo( node.angles, travel_speed, travel_speed * 0.5, 0);
|
||||
wait travel_speed;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
go_path_by_targetname_reverse( path_name, back_to_button_group )
|
||||
{
|
||||
assertex( isdefined( level.dummy_mover ), "go_path_by_targetname_reverse called before go_path_by_targetname" );
|
||||
|
||||
travel_speed = CONST_view_travel_unit_time;
|
||||
total_distance = abs( distance( level.dummy_mover.origin, level.radial_button_group_info[ back_to_button_group ][ "player_view_pos" ] ) );
|
||||
travel_speed *= total_distance / CONST_view_travel_unit_dist;
|
||||
travel_speed = max( travel_speed, 0.1 ); // due to repeated button presses, the travel distance can be cut to 0 travel speed at times.
|
||||
|
||||
blur_time = travel_speed;
|
||||
if ( !CONST_direct_travel )
|
||||
blur_time *= travel_speed * ( level.view_paths[ path_name ].size + 1 );
|
||||
self thread blur_sine( CONST_blur_strength, blur_time );
|
||||
|
||||
if ( !CONST_direct_travel )
|
||||
{
|
||||
for ( idx = level.view_paths[ path_name ].size - 1; idx >= 0; idx-- )
|
||||
{
|
||||
node = level.view_paths[ path_name ][ idx ];
|
||||
level.dummy_mover MoveTo( node.origin, travel_speed );
|
||||
level.dummy_mover RotateTo( node.angles, travel_speed );
|
||||
|
||||
//self thread travel_view_fx( travel_speed );
|
||||
wait travel_speed;
|
||||
}
|
||||
}
|
||||
|
||||
self thread blur_sine( CONST_blur_strength, travel_speed );
|
||||
|
||||
pos = level.radial_button_group_info[ back_to_button_group ][ "player_view_pos" ];
|
||||
angle = level.radial_button_group_info[ back_to_button_group ][ "view_angles" ];
|
||||
|
||||
level.dummy_mover MoveTo( pos, travel_speed, travel_speed * 0.5, 0 );
|
||||
level.dummy_mover RotateTo( angle, travel_speed, travel_speed * 0.5, 0 );
|
||||
wait travel_speed;
|
||||
}
|
||||
|
||||
|
||||
travel_view_fx( time )
|
||||
{
|
||||
self setblurforplayer( 20, ( time + 0.2 )/2 );
|
||||
self setblurforplayer( 0, ( time + 0.2 )/2 );
|
||||
self shellshock( "frag_grenade_mp", time + 0.2 );
|
||||
}
|
||||
|
||||
|
||||
blur_sine( strength, time )
|
||||
{
|
||||
time_scaled = int( time/0.05 );
|
||||
|
||||
for( i = 0; i < time_scaled; i ++ )
|
||||
{
|
||||
fraction = ( i / ( time_scaled ) );
|
||||
cos_fraction= sin( 180 * fraction );
|
||||
blur_amount = strength * cos_fraction;
|
||||
|
||||
setdvar( "r_blur", blur_amount );
|
||||
wait 0.05;
|
||||
}
|
||||
setdvar( "r_blur", 0 );
|
||||
}
|
||||
|
||||
|
||||
force_player_angles()
|
||||
{
|
||||
level endon( "game_ended" );
|
||||
self endon( "disconnect" );
|
||||
level.dummy_mover endon( "remove_dummy" );
|
||||
|
||||
while ( 1 )
|
||||
{
|
||||
self setplayerangles ( level.dummy_mover.angles );
|
||||
wait 0.05;
|
||||
}
|
||||
}
|
137
maps/mp/_defcon.gsc
Normal file
137
maps/mp/_defcon.gsc
Normal file
@ -0,0 +1,137 @@
|
||||
#include common_scripts\utility;
|
||||
#include maps\mp\_utility;
|
||||
#include maps\mp\gametypes\_hud_util;
|
||||
|
||||
// if ( game["state"] == "postgame" && game["teamScores"][attacker.team] > game["teamScores"][level.otherTeam[attacker.team]] )
|
||||
|
||||
ICONSIZE = 20;
|
||||
|
||||
init()
|
||||
{
|
||||
if ( !isDefined( level.defconMode ) || level.defconMode == false )
|
||||
return;
|
||||
|
||||
if ( !isDefined( game["defcon"] ) )
|
||||
game["defcon"] = 4;
|
||||
|
||||
SetDvar( "scr_defcon", game["defcon"] );
|
||||
|
||||
/# setDevDvarIfUninitialized( "scr_defconStreak", 10 ); #/
|
||||
|
||||
level.defconStreakAdd[5] = 0;
|
||||
level.defconStreakAdd[4] = 0;
|
||||
level.defconStreakAdd[3] = -1;
|
||||
level.defconStreakAdd[2] = -1;
|
||||
level.defconStreakAdd[1] = -1;
|
||||
|
||||
level.defconPointMod[5] = 1;
|
||||
level.defconPointMod[4] = 1;
|
||||
level.defconPointMod[3] = 1;
|
||||
level.defconPointMod[2] = 1;
|
||||
level.defconPointMod[1] = 2;
|
||||
|
||||
updateDefcon( game["defcon"] );
|
||||
thread defconKillstreakThread();
|
||||
}
|
||||
|
||||
defconKillstreakWait( streakCount )
|
||||
{
|
||||
for ( ;; )
|
||||
{
|
||||
level waittill ( "player_got_killstreak_" + streakCount, player );
|
||||
level notify ( "defcon_killstreak", streakCount, player );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
defconKillstreakThread()
|
||||
{
|
||||
level endon ( "game_ended" );
|
||||
|
||||
requiredKillCount = 10;
|
||||
|
||||
/#
|
||||
requiredKillCount = getDvarInt( "scr_defconStreak" );
|
||||
#/
|
||||
|
||||
level thread defconKillstreakWait( requiredKillCount );
|
||||
level thread defconKillstreakWait( requiredKillCount - 1 );
|
||||
level thread defconKillstreakWait( requiredKillCount - 2 );
|
||||
|
||||
level thread defconKillstreakWait( (requiredKillCount * 2) );
|
||||
level thread defconKillstreakWait( (requiredKillCount * 2) - 1 );
|
||||
level thread defconKillstreakWait( (requiredKillCount * 2) - 2 );
|
||||
|
||||
level thread defconKillstreakWait( (requiredKillCount * 3) );
|
||||
level thread defconKillstreakWait( (requiredKillCount * 3) - 1 );
|
||||
level thread defconKillstreakWait( (requiredKillCount * 3) - 2 );
|
||||
|
||||
for ( ;; )
|
||||
{
|
||||
level waittill ( "defcon_killstreak", streakCount, changingPlayer );
|
||||
|
||||
if ( game["defcon"] <= 1 )
|
||||
continue;
|
||||
|
||||
if ( (streakCount % requiredKillCount) == requiredKillCount - 2 )
|
||||
{
|
||||
foreach ( player in level.players )
|
||||
{
|
||||
if ( !isAlive( player ) )
|
||||
continue;
|
||||
|
||||
player thread maps\mp\gametypes\_hud_message::playerCardSplashNotify( "two_from_defcon", changingPlayer );
|
||||
}
|
||||
}
|
||||
else if ( (streakCount % requiredKillCount) == requiredKillCount - 1 )
|
||||
{
|
||||
foreach ( player in level.players )
|
||||
{
|
||||
if ( !isAlive( player ) )
|
||||
continue;
|
||||
|
||||
player thread maps\mp\gametypes\_hud_message::playerCardSplashNotify( "one_from_defcon", changingPlayer );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
updateDefcon( game["defcon"] - 1, changingPlayer, streakCount );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
updateDefcon( newDefcon, changingPlayer, streakCount )
|
||||
{
|
||||
newDefcon = int( newDefcon );
|
||||
oldDefcon = game["defcon"];
|
||||
game["defcon"] = newDefcon;
|
||||
|
||||
// level.killStreakMod = level.defconStreakAdd[newDefcon];
|
||||
level.objectivePointsMod = level.defconPointMod[newDefcon];
|
||||
|
||||
setDvar( "scr_defcon", game["defcon"] );
|
||||
|
||||
//isdefined used for variable init
|
||||
if( isDefined( changingPlayer ) )
|
||||
changingPlayer notify( "changed_defcon" );
|
||||
|
||||
if ( newDefcon == oldDefcon )
|
||||
return;
|
||||
|
||||
if ( game["defcon"] == 3 && isDefined( changingPlayer ) )
|
||||
{
|
||||
changingPlayer maps\mp\killstreaks\_killstreaks::giveKillstreak( "airdrop_mega" );
|
||||
changingPlayer thread maps\mp\gametypes\_hud_message::splashNotify( "caused_defcon" , streakCount );
|
||||
}
|
||||
|
||||
foreach ( player in level.players )
|
||||
{
|
||||
if ( isAlive( player ) )
|
||||
{
|
||||
player thread maps\mp\gametypes\_hud_message::defconSplashNotify( game["defcon"], newDefcon < oldDefcon );
|
||||
if ( isDefined( changingPlayer ) )
|
||||
player thread maps\mp\gametypes\_hud_message::playerCardSplashNotify( "changed_defcon", changingPlayer );
|
||||
}
|
||||
}
|
||||
}
|
82
maps/mp/_destructables.gsc
Normal file
82
maps/mp/_destructables.gsc
Normal file
@ -0,0 +1,82 @@
|
||||
init()
|
||||
{
|
||||
// level.destructableFX = loadfx("fx/breakables/exp_wall_cinderblock_96");
|
||||
|
||||
ents = getentarray("destructable", "targetname");
|
||||
|
||||
if (getdvar("scr_destructables") == "0")
|
||||
{
|
||||
for (i = 0; i < ents.size; i++)
|
||||
ents[i] delete();
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < ents.size; i++)
|
||||
{
|
||||
ents[i] thread destructable_think();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
destructable_think()
|
||||
{
|
||||
accumulate = 40;
|
||||
threshold = 0;
|
||||
|
||||
if (isdefined(self.script_accumulate))
|
||||
accumulate = self.script_accumulate;
|
||||
if (isdefined(self.script_threshold))
|
||||
threshold = self.script_threshold;
|
||||
|
||||
if (isdefined(self.script_destructable_area)) {
|
||||
areas = strtok(self.script_destructable_area, " ");
|
||||
for (i = 0; i < areas.size; i++)
|
||||
self blockArea(areas[i]);
|
||||
}
|
||||
|
||||
if ( isdefined( self.script_fxid ) )
|
||||
self.fx = loadfx( self.script_fxid );
|
||||
|
||||
dmg = 0;
|
||||
|
||||
self setcandamage(true);
|
||||
while(1)
|
||||
{
|
||||
self waittill("damage", amount, other);
|
||||
if (amount >= threshold)
|
||||
{
|
||||
dmg += amount;
|
||||
if (dmg >= accumulate)
|
||||
{
|
||||
self thread destructable_destruct();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
destructable_destruct()
|
||||
{
|
||||
ent = self;
|
||||
if (isdefined(self.script_destructable_area)) {
|
||||
areas = strtok(self.script_destructable_area, " ");
|
||||
for (i = 0; i < areas.size; i++)
|
||||
self unblockArea(areas[i]);
|
||||
}
|
||||
if ( isdefined( ent.fx ) )
|
||||
playfx( ent.fx, ent.origin + (0,0,6) );
|
||||
ent delete();
|
||||
}
|
||||
|
||||
blockArea(area)
|
||||
{
|
||||
}
|
||||
blockEntsInArea(ents, area)
|
||||
{
|
||||
}
|
||||
unblockArea(area)
|
||||
{
|
||||
}
|
||||
unblockEntsInArea(ents, area)
|
||||
{
|
||||
}
|
294
maps/mp/_dlcalienegg.gsc
Normal file
294
maps/mp/_dlcalienegg.gsc
Normal file
@ -0,0 +1,294 @@
|
||||
#include common_scripts\utility;
|
||||
#include maps\mp\_utility;
|
||||
#include maps\mp\gametypes\_hud_util;
|
||||
|
||||
CONST_EGG_ID = "dlcEggStatus";
|
||||
CONST_ALL_EGG_CHALLENGE = "ch_weekly_1";
|
||||
|
||||
init()
|
||||
{
|
||||
// this is a terrible hack.
|
||||
// We are tracking all of the egg state in one 32-bit integer.
|
||||
// The lower 16 bits track whether the player has shot the egg for that level, 4-bits per map-pack.
|
||||
|
||||
|
||||
|
||||
// the number of bits shifted should correspond to the order in mapNames.csv
|
||||
// we'll use this to check completion of player data
|
||||
level.dlcAlienEggs = [];
|
||||
// pack 1
|
||||
level.dlcAlienEggs[ "mp_boneyard_ns" ] = 1 << 0;
|
||||
level.dlcAlienEggs[ "mp_swamp" ] = 1 << 1;
|
||||
level.dlcAlienEggs[ "mp_ca_red_river" ] = 1 << 2;
|
||||
level.dlcAlienEggs[ "mp_ca_rumble" ] = 1 << 3;
|
||||
|
||||
// pack 2
|
||||
level.dlcAlienEggs[ "mp_dome_ns" ] = 1 << 4;
|
||||
level.dlcAlienEggs[ "mp_battery3" ] = 1 << 5;
|
||||
level.dlcAlienEggs[ "mp_ca_impact" ] = 1 << 6;
|
||||
level.dlcAlienEggs[ "mp_ca_behemoth" ] = 1 << 7;
|
||||
|
||||
// pack 3. bits 8-11
|
||||
level.dlcAlienEggs[ "mp_dig" ] = 1 << 8;
|
||||
level.dlcAlienEggs[ "mp_favela_iw6" ] = 1 << 9;
|
||||
level.dlcAlienEggs[ "mp_pirate" ] = 1 << 10;
|
||||
level.dlcAlienEggs[ "mp_zulu" ] = 1 << 11;
|
||||
|
||||
// pack 4. bits 12-15
|
||||
level.dlcAlienEggs[ "mp_conflict" ] = 1 << 12;
|
||||
level.dlcAlienEggs[ "mp_mine" ] = 1 << 13;
|
||||
level.dlcAlienEggs[ "mp_zerosub" ] = 1 << 14;
|
||||
level.dlcAlienEggs[ "mp_shipment_ns" ] = 1 << 15;
|
||||
|
||||
// Translate each map name to its pack number (0-based)
|
||||
level.dlcAliengEggMapToPack[ "mp_boneyard_ns" ] = 0;
|
||||
level.dlcAliengEggMapToPack[ "mp_swamp" ] = 0;
|
||||
level.dlcAliengEggMapToPack[ "mp_ca_red_river" ] = 0;
|
||||
level.dlcAliengEggMapToPack[ "mp_ca_rumble" ] = 0;
|
||||
|
||||
level.dlcAliengEggMapToPack[ "mp_dome_ns" ] = 1;
|
||||
level.dlcAliengEggMapToPack[ "mp_battery3" ] = 1;
|
||||
level.dlcAliengEggMapToPack[ "mp_ca_impact" ] = 1;
|
||||
level.dlcAliengEggMapToPack[ "mp_ca_behemoth" ] = 1;
|
||||
|
||||
level.dlcAliengEggMapToPack[ "mp_dig" ] = 2;
|
||||
level.dlcAliengEggMapToPack[ "mp_favela_iw6" ] = 2;
|
||||
level.dlcAliengEggMapToPack[ "mp_pirate" ] = 2;
|
||||
level.dlcAliengEggMapToPack[ "mp_zulu" ] = 2;
|
||||
|
||||
// pack 4. bits 12-15
|
||||
level.dlcAliengEggMapToPack[ "mp_conflict" ] = 3;
|
||||
level.dlcAliengEggMapToPack[ "mp_mine" ] = 3;
|
||||
level.dlcAliengEggMapToPack[ "mp_zerosub" ] = 3;
|
||||
level.dlcAliengEggMapToPack[ "mp_shipment_ns" ] = 3;
|
||||
|
||||
// # of set bits in 0 - 15
|
||||
// use to look up how many eggs have been achieved
|
||||
level.bitCounts = [ 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 ];
|
||||
|
||||
level._effect[ "vfx_alien_easter_egg_hit" ] = loadfx( "vfx/gameplay/alien/vfx_alien_easter_egg_hit" );
|
||||
}
|
||||
|
||||
setupEggForMap( eggName )
|
||||
{
|
||||
if ( level.rankedMatch )
|
||||
{
|
||||
init();
|
||||
|
||||
flags = level.dlcAlienEggs[ getMapName() ];
|
||||
|
||||
AssertEx( IsDefined( flags ), "dlcAlienEggs bit flag not set up for map: " + getMapName() );
|
||||
|
||||
egg = GetEnt( eggName, "targetname" );
|
||||
if ( IsDefined( egg ) )
|
||||
{
|
||||
// add flags
|
||||
// playlistType = GetDvarInt( "scr_playlist_type", 0 );
|
||||
|
||||
if ( egg.classname == "script_model" )
|
||||
{
|
||||
egg SetCanDamage( true );
|
||||
}
|
||||
|
||||
egg thread eggTrackHits();
|
||||
}
|
||||
|
||||
/#
|
||||
thread eggDebug();
|
||||
#/
|
||||
}
|
||||
}
|
||||
|
||||
eggTrackHits()
|
||||
{
|
||||
level endon( "game_ended" );
|
||||
self.health = 99999;
|
||||
|
||||
level.eggHits = [];
|
||||
|
||||
while ( true )
|
||||
{
|
||||
self waittill( "damage", damage, attacker, direction, point, damageType );
|
||||
|
||||
// play a sound and effect?
|
||||
PlayFX( getfx( "vfx_alien_easter_egg_hit" ), point, AnglesToForward( direction ), AnglesToUp( direction ) );
|
||||
|
||||
if ( IsPlayer( attacker ) && !IsAI( attacker ) )
|
||||
{
|
||||
attackerNum = attacker getUniqueId();
|
||||
// we have not hit this egg before
|
||||
if ( !IsDefined( level.eggHits[ attackerNum ] ) )
|
||||
{
|
||||
level.eggHits[ attackerNum ] = 1;
|
||||
self eggRegisterHit( damage, attacker, direction, point, damageType );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
eggRegisterHit( damage, attacker, direction, point, type )
|
||||
{
|
||||
self.health += damage; // don't let the health drop
|
||||
|
||||
if ( !( attacker eggHasCompletedForMap( getMapName() ) ) )
|
||||
{
|
||||
attacker eggSetCompletedForMap( getMapName() );
|
||||
}
|
||||
else if ( attacker eggAllFound()
|
||||
&& attacker ch_getState( CONST_ALL_EGG_CHALLENGE ) < 2
|
||||
)
|
||||
{
|
||||
attacker eggAwardPatch();
|
||||
}
|
||||
}
|
||||
|
||||
eggHasCompletedForMap( mapName ) // self == player
|
||||
{
|
||||
eggState = self GetRankedPlayerDataReservedInt( CONST_EGG_ID );
|
||||
|
||||
bitFlag = level.dlcAlienEggs[ mapName ];
|
||||
if ( IsDefined( bitFlag ) &&
|
||||
(eggState & bitFlag) != 0 )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
eggSetCompletedForMap( mapName ) // self == player
|
||||
{
|
||||
bitFlag = level.dlcAlienEggs[ mapName ];
|
||||
|
||||
if ( IsDefined( bitFlag ) )
|
||||
{
|
||||
eggState = self GetRankedPlayerDataReservedInt( CONST_EGG_ID );
|
||||
|
||||
eggState |= bitFlag;
|
||||
self SetRankedPlayerDataReservedInt( CONST_EGG_ID, eggState );
|
||||
|
||||
packNum = level.dlcAliengEggMapToPack[ mapName ];
|
||||
AssertEx( IsDefined( packNum ), "MapPack ID not defined for " + mapName );
|
||||
|
||||
numCompleted = eggCountCompletedEggsForPack( packNum, eggState );
|
||||
packNum++; // the splashes are indexed 1-4, instead of 0-3
|
||||
if ( numCompleted < 4 )
|
||||
{
|
||||
self maps\mp\gametypes\_hud_message::playerCardSplashNotify( "dlc_eggFound_" + packNum, self, numCompleted );
|
||||
}
|
||||
else
|
||||
{
|
||||
// if all the eggs are found, give ultimate award
|
||||
if ( self eggAllFound()
|
||||
&& ch_getState( CONST_ALL_EGG_CHALLENGE ) < 2
|
||||
)
|
||||
{
|
||||
self eggAwardPatch();
|
||||
}
|
||||
// otherwise give award for this pack
|
||||
else
|
||||
{
|
||||
self maps\mp\gametypes\_hud_message::playerCardSplashNotify( "dlc_eggAllFound_" + packNum, self );
|
||||
self thread maps\mp\gametypes\_rank::giveRankXP( "dlc_egg_hunt" );
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
self PlayLocalSound( "ui_extinction_egg_splash" );
|
||||
}
|
||||
}
|
||||
|
||||
eggAwardPatch()
|
||||
{
|
||||
self maps\mp\gametypes\_hud_message::playerCardSplashNotify( "dlc_eggAllFound", self );
|
||||
self thread maps\mp\gametypes\_rank::giveRankXP( "dlc_egg_hunt_all" );
|
||||
|
||||
ch_setState( CONST_ALL_EGG_CHALLENGE, 2 ); // patch. Weekly challenges are unlocked with state set to 2.
|
||||
}
|
||||
|
||||
eggCountCompletedEggsForPack( packNum, eggState )
|
||||
{
|
||||
flags = eggState >> (packnum * 4); // move the bits to the first set of 4
|
||||
flags &= 15; // mask out everything but the first four bits
|
||||
|
||||
return level.bitCounts[ flags ];
|
||||
}
|
||||
|
||||
// packNum is 0-indexed
|
||||
eggAllFoundForPack( packNum )
|
||||
{
|
||||
eggState = self GetRankedPlayerDataReservedInt( CONST_EGG_ID );
|
||||
packEggState = (eggState >> (packnum *4)) & 15;
|
||||
|
||||
return (packEggState != 0);
|
||||
}
|
||||
|
||||
// all 16 eggs found
|
||||
CONST_ALL_EGGS_MASK = (1 << 16) - 1;
|
||||
eggAllFound()
|
||||
{
|
||||
eggState = self GetRankedPlayerDataReservedInt( CONST_EGG_ID );
|
||||
|
||||
return ( eggState == CONST_ALL_EGGS_MASK );
|
||||
}
|
||||
|
||||
/#
|
||||
eggDebug()
|
||||
{
|
||||
level endon( "game_ended" );
|
||||
|
||||
level waittill( "connected", player );
|
||||
|
||||
player thread eggDebugPlayer();
|
||||
}
|
||||
|
||||
eggDebugPlayer() // self == player
|
||||
{
|
||||
level endon( "game_ended" );
|
||||
|
||||
SetDvarIfUninitialized( "scr_egg_set", "" );
|
||||
SetDvarIfUninitialized( "scr_egg_pack_set", 0 );
|
||||
SetDvarIfUninitialized( "scr_egg_clear", 0 );
|
||||
|
||||
while ( true )
|
||||
{
|
||||
mapName = GetDvar( "scr_egg_set" );
|
||||
if ( mapName != "" )
|
||||
{
|
||||
self eggSetCompletedForMap( mapName );
|
||||
SetDvar( "scr_egg_set", "" );
|
||||
}
|
||||
|
||||
if ( GetDvarInt( "scr_egg_clear" ) != 0 )
|
||||
{
|
||||
self SetRankedPlayerDataReservedInt( CONST_EGG_ID, 0 );
|
||||
SetDvar( "scr_egg_clear", 0 );
|
||||
level.eggHits = [];
|
||||
|
||||
ch_setState( CONST_ALL_EGG_CHALLENGE, 0 );
|
||||
}
|
||||
|
||||
// set all the flags for one pack
|
||||
targetPackNum = GetDvarInt( "scr_egg_pack_set" );
|
||||
if ( targetPackNum > 0 )
|
||||
{
|
||||
targetPackNum--;
|
||||
|
||||
foreach ( mapName, packNum in level.dlcAliengEggMapToPack )
|
||||
{
|
||||
if ( packNum == targetPackNum && !( self eggHasCompletedForMap( mapName ) ) )
|
||||
{
|
||||
self eggSetCompletedForMap( mapName );
|
||||
wait (3.6); // a little bit more than the duration of the splash
|
||||
}
|
||||
}
|
||||
|
||||
SetDvar( "scr_egg_pack_set", "" );
|
||||
}
|
||||
|
||||
wait ( 0.25 );
|
||||
}
|
||||
}
|
||||
#/
|
378
maps/mp/_elevator.gsc
Normal file
378
maps/mp/_elevator.gsc
Normal file
@ -0,0 +1,378 @@
|
||||
#include maps\mp\_utility;
|
||||
#include common_scripts\utility;
|
||||
|
||||
// ELEVATOR TEST
|
||||
ELEVATOR_DOOR_TIME = 2;
|
||||
ELEVATOR_FLOOR_MOVE_TIME = 5;
|
||||
ELEVATOR_AUTOCLOSE_TIMEOUT = 10;
|
||||
|
||||
ELEVATOR_DOOR_STATE_CLOSED = 0;
|
||||
ELEVATOR_DOOR_STATE_OPENING = 1;
|
||||
ELEVATOR_DOOR_STATE_OPEN = 2;
|
||||
ELEVATOR_DOOR_STATE_CLOSING = 3;
|
||||
|
||||
// should scale elevator door speed based on the actual distance moved
|
||||
// in case of interrupts
|
||||
|
||||
init_elevator( config )
|
||||
{
|
||||
elevator = GetEnt( config.name, "targetname" );
|
||||
AssertEx( IsDefined( elevator ), "Could not find an elevator entity named " + config.name );
|
||||
elevator.unresolved_collision_func = ::handleUnreslovedCollision;
|
||||
|
||||
elevator.doors = [];
|
||||
foreach ( floorname, doorset in config.doors )
|
||||
{
|
||||
list = [];
|
||||
foreach ( doorname in doorset )
|
||||
{
|
||||
list[ list.size ] = setupDoor( doorName + "left", false, config.doorMoveDist );
|
||||
list[ list.size ] = setupDoor( doorName + "right", true, config.doorMoveDist );
|
||||
}
|
||||
|
||||
elevator.doors[ floorname ] = list;
|
||||
}
|
||||
|
||||
elevator.trigBlock = GetEnt( config.trigBlockName, "targetname" );
|
||||
AssertEx( IsDefined( elevator.trigBlock ), "Could not find an elevator trigger named " + config.trigBlockName );
|
||||
|
||||
elevator.curFloor = "floor1";
|
||||
elevator.requestedFloor = elevator.curFloor;
|
||||
elevator.doorState = ELEVATOR_DOOR_STATE_CLOSED;
|
||||
|
||||
elevator.doorOpenTime = 2.0;
|
||||
elevator.doorSpeed = config.doorMoveDist / elevator.doorOpenTime;
|
||||
elevator.moveTime = 5.0;
|
||||
elevator.autoCloseTimeout = 10.0;
|
||||
|
||||
elevator.destinations = [];
|
||||
elevator.pathBlockers = [];
|
||||
elevator.buttons = GetEntArray( config.buttons, "targetname" );
|
||||
foreach ( button in elevator.buttons )
|
||||
{
|
||||
button setupButton( elevator );
|
||||
}
|
||||
|
||||
elevatorModels = GetEntArray( "elevator_models", "targetname" );
|
||||
foreach ( eleModel in elevatorModels )
|
||||
{
|
||||
eleModel LinkTo( elevator );
|
||||
}
|
||||
|
||||
elevator thread elevatorThink();
|
||||
|
||||
elevator thread openElevatorDoors( elevator.curFloor, false );
|
||||
}
|
||||
|
||||
setupDoor( doorName, isRightSide, moveDistance )
|
||||
{
|
||||
door = GetEnt( doorName, "targetname" );
|
||||
if (IsDefined(door))
|
||||
{
|
||||
door.closePos = door.origin;
|
||||
if (IsDefined(door.target))
|
||||
{
|
||||
targetStruct = getstruct( door.target, "targetname" );
|
||||
door.openPos = targetStruct.origin;
|
||||
}
|
||||
else
|
||||
{
|
||||
offset = AnglesToForward( door.angles ) * moveDistance;
|
||||
/*
|
||||
if (isRightSide)
|
||||
{
|
||||
offset *= -1;
|
||||
}
|
||||
*/
|
||||
door.openPos = door.origin + offset;
|
||||
}
|
||||
|
||||
// door.unresolved_collision_func = ::handleUnreslovedCollision;
|
||||
|
||||
return door;
|
||||
}
|
||||
else
|
||||
{
|
||||
AssertEx( IsDefined( door ), "Could not find an elevator door entity named " + doorName );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
setupButton( elevator ) // self == button
|
||||
{
|
||||
self.owner = elevator;
|
||||
|
||||
if ( IsDefined( self.target ) )
|
||||
{
|
||||
destination = getstruct( self.target, "targetname" );
|
||||
if ( IsDefined( destination ) )
|
||||
{
|
||||
elevator.destinations[ self.script_label ] = destination.origin;
|
||||
if ( IsDefined( destination.target ) )
|
||||
{
|
||||
blocker = GetEnt( destination.target, "targetname" );
|
||||
if ( IsDefined( blocker ) )
|
||||
{
|
||||
elevator.pathBlockers[ self.script_label ] = blocker;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self enableButton();
|
||||
}
|
||||
|
||||
enableButton() // self == button
|
||||
{
|
||||
self SetHintString( &"MP_ELEVATOR_USE" );
|
||||
self MakeUsable();
|
||||
|
||||
self thread buttonThink();
|
||||
}
|
||||
|
||||
disableButton()
|
||||
{
|
||||
self MakeUnusable();
|
||||
}
|
||||
|
||||
buttonThink()
|
||||
{
|
||||
elevator = self.owner;
|
||||
elevator endon( "elevator_busy" );
|
||||
|
||||
while ( true )
|
||||
{
|
||||
self waittill( "trigger" );
|
||||
|
||||
if ( self.script_label == "elevator" )
|
||||
{
|
||||
// do some stuff
|
||||
if ( elevator.curFloor == "floor1" )
|
||||
{
|
||||
elevator.requestedFloor = "floor2";
|
||||
}
|
||||
else
|
||||
{
|
||||
elevator.requestedFloor = "floor1";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
elevator.requestedFloor = self.script_label;
|
||||
}
|
||||
|
||||
elevator notify( "elevator_called" );
|
||||
}
|
||||
}
|
||||
|
||||
elevatorThink()
|
||||
{
|
||||
while ( true )
|
||||
{
|
||||
self waittill( "elevator_called" );
|
||||
|
||||
foreach ( button in self.buttons )
|
||||
{
|
||||
button disableButton();
|
||||
}
|
||||
|
||||
if ( self.curFloor != self.requestedFloor )
|
||||
{
|
||||
if ( self.doorState != ELEVATOR_DOOR_STATE_CLOSED )
|
||||
{
|
||||
self notify ("elevator_stop_autoclose");
|
||||
self thread closeElevatorDoors( self.curFloor );
|
||||
self waittill( "elevator_doors_closed" );
|
||||
}
|
||||
|
||||
self elevatorMoveToFloor( self.requestedFloor );
|
||||
wait (0.25);
|
||||
}
|
||||
|
||||
self thread openElevatorDoors( self.curFloor, false );
|
||||
|
||||
self waittill ( "elevator_doors_open" );
|
||||
foreach ( button in self.buttons )
|
||||
{
|
||||
button enableButton();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
elevatorMoveToFloor( targetFloor )
|
||||
{
|
||||
self PlaySound( "scn_elevator_startup" );
|
||||
self PlayLoopSound( "scn_elevator_moving_lp" );
|
||||
|
||||
destinationPos = self.destinations[ targetFloor ];
|
||||
deltaZ = destinationPos[2] - self.origin[2];
|
||||
|
||||
// move doors
|
||||
foreach ( door in self.doors[ "elevator" ] )
|
||||
{
|
||||
door MoveZ( deltaZ, self.moveTime );
|
||||
}
|
||||
// move the floor
|
||||
self MoveZ( deltaZ, self.moveTime );
|
||||
|
||||
wait ( self.moveTime );
|
||||
|
||||
self StopLoopSound ( "scn_elevator_moving_lp" );
|
||||
self PlaySound ( "scn_elevator_stopping" );
|
||||
self PlaySound ( "scn_elevator_beep" );
|
||||
|
||||
self.curFloor = self.requestedFloor;
|
||||
}
|
||||
|
||||
openElevatorDoors( floorName, autoClose ) // elevator
|
||||
{
|
||||
doorset = self.doors[ floorName ];
|
||||
|
||||
self.doorState = ELEVATOR_DOOR_STATE_OPENING;
|
||||
|
||||
// figre out the time it takes to move 1 door, assume it's the same fo rall
|
||||
door = doorset[0];
|
||||
doorDest = (door.openPos[0], door.openPos[1], door.origin[2]);
|
||||
moveDelta = doorDest - door.origin;
|
||||
moveDist = Length( moveDelta );
|
||||
|
||||
// this might move 0 time / 0 dist
|
||||
// but we need it to counteract the closing elevator
|
||||
// wish I could just tell it to stop, instead
|
||||
movetime = moveDist / self.doorSpeed;
|
||||
accelTime = 0.25;
|
||||
if (moveTime == 0.0)
|
||||
{
|
||||
moveTime = 0.05;
|
||||
accelTime = 0.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
self PlaySound( "scn_elevator_doors_opening" );
|
||||
accelTime = min(accelTime, moveTime);
|
||||
}
|
||||
|
||||
foreach ( door in doorset )
|
||||
{
|
||||
door MoveTo( (door.openPos[0], door.openPos[1], door.origin[2]), movetime, 0.0, accelTime );
|
||||
}
|
||||
wait ( movetime );
|
||||
|
||||
self.doorState = ELEVATOR_DOOR_STATE_OPEN;
|
||||
|
||||
self notify ( "elevator_doors_open" );
|
||||
|
||||
self elevatorClearPath( floorName );
|
||||
|
||||
if ( autoClose )
|
||||
{
|
||||
self thread elevatorDoorsAutoClose();
|
||||
}
|
||||
}
|
||||
|
||||
closeElevatorDoors( floorName )
|
||||
{
|
||||
self endon( "elevator_close_interrupted" );
|
||||
|
||||
self thread watchCloseInterrupted( floorName );
|
||||
|
||||
doorset = self.doors[ floorName ];
|
||||
|
||||
self.doorState = ELEVATOR_DOOR_STATE_CLOSING;
|
||||
|
||||
// figre out the time it takes to move 1 door, assume it's the same fo rall
|
||||
door = doorset[0];
|
||||
doorDest = (door.closePos[0], door.closePos[1], door.origin[2]);
|
||||
moveDelta = doorDest - door.origin;
|
||||
moveDist = Length( moveDelta );
|
||||
|
||||
if ( moveDist != 0.0 )
|
||||
{
|
||||
movetime = moveDist / self.doorSpeed;
|
||||
foreach ( door in doorset )
|
||||
{
|
||||
// we assume the doors all begin closed,
|
||||
// so door.closePos should eventually be defined by the time we need it
|
||||
door MoveTo( (door.closePos[0], door.closePos[1], door.origin[2]), movetime, 0.0, 0.25 );
|
||||
}
|
||||
self PlaySound( "scn_elevator_doors_closing" );
|
||||
wait ( movetime );
|
||||
}
|
||||
|
||||
self.doorState = ELEVATOR_DOOR_STATE_CLOSED;
|
||||
|
||||
self elevatorBlockPath( floorName );
|
||||
|
||||
self notify( "elevator_doors_closed" );
|
||||
}
|
||||
|
||||
watchCloseInterrupted( floorName )
|
||||
{
|
||||
// if the doors have closed successfully, we don't care any more
|
||||
self endon( "elevator_doors_closed" );
|
||||
|
||||
// make sure there is nothing in the way now
|
||||
nothingBlocking = true;
|
||||
foreach ( character in level.characters )
|
||||
{
|
||||
if ( character isTouchingTrigger( self.trigBlock ) )
|
||||
{
|
||||
nothingBlocking = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( nothingBlocking )
|
||||
{
|
||||
self.trigBlock waittill( "trigger" );
|
||||
}
|
||||
|
||||
self notify( "elevator_close_interrupted" );
|
||||
|
||||
self openElevatorDoors( floorName, true );
|
||||
}
|
||||
|
||||
isTouchingTrigger( trigger ) // self == player
|
||||
{
|
||||
return ( IsAlive( self ) && self IsTouching( trigger ) );
|
||||
}
|
||||
|
||||
elevatorDoorsAutoClose() // self == elevator
|
||||
{
|
||||
self endon( "elevator_doors_closed" );
|
||||
self endon( "elevator_stop_autoclose" );
|
||||
|
||||
wait ( self.autoCloseTimeout );
|
||||
|
||||
self closeElevatorDoors( self.curFloor);
|
||||
}
|
||||
|
||||
handleUnreslovedCollision( hitEnt ) // self == mover, hitEnt == player (usually)
|
||||
{
|
||||
if ( !IsPlayer( hitEnt ) )
|
||||
{
|
||||
hitEnt DoDamage( 1000, hitEnt.origin, self, self, "MOD_CRUSH" );
|
||||
}
|
||||
}
|
||||
|
||||
elevatorClearPath( floorName ) // self == elevator
|
||||
{
|
||||
blocker = self.pathBlockers[ floorName ];
|
||||
if ( IsDefined( blocker ) )
|
||||
{
|
||||
blocker ConnectPaths();
|
||||
blocker Hide();
|
||||
blocker NotSolid();
|
||||
}
|
||||
}
|
||||
|
||||
elevatorBlockPath( floorName )
|
||||
{
|
||||
blocker = self.pathBlockers[ floorName ];
|
||||
if ( IsDefined( blocker ) )
|
||||
{
|
||||
blocker Show();
|
||||
blocker Solid();
|
||||
blocker DisconnectPaths();
|
||||
}
|
||||
}
|
468
maps/mp/_elevator_v2.gsc
Normal file
468
maps/mp/_elevator_v2.gsc
Normal file
@ -0,0 +1,468 @@
|
||||
#include maps\mp\_utility;
|
||||
#include common_scripts\utility;
|
||||
|
||||
// _elevator_v2: used in mp_mines.gsc (original was used in mp_fahrenheit).
|
||||
// Making adjustments to allow for multiple types of elevators
|
||||
|
||||
// ELEVATOR TEST
|
||||
ELEVATOR_DOOR_TIME = 2;
|
||||
ELEVATOR_FLOOR_MOVE_TIME = 5;
|
||||
ELEVATOR_AUTOCLOSE_TIMEOUT = 10;
|
||||
|
||||
ELEVATOR_DOOR_STATE_CLOSED = 0;
|
||||
ELEVATOR_DOOR_STATE_OPENING = 1;
|
||||
ELEVATOR_DOOR_STATE_OPEN = 2;
|
||||
ELEVATOR_DOOR_STATE_CLOSING = 3;
|
||||
|
||||
// should scale elevator door speed based on the actual distance moved
|
||||
// in case of interrupts
|
||||
|
||||
init_elevator( config )
|
||||
{
|
||||
elevator = GetEnt( config.name, "targetname" );
|
||||
AssertEx( IsDefined( elevator ), "Could not find an elevator entity named " + config.name );
|
||||
elevator.unresolved_collision_func = ::handleUnreslovedCollision;
|
||||
|
||||
elevator.doors = [];
|
||||
if ( IsDefined( config.doors ) )
|
||||
{
|
||||
foreach ( floorname, doorset in config.doors )
|
||||
{
|
||||
list = [];
|
||||
foreach ( doorname in doorset )
|
||||
{
|
||||
list[ list.size ] = setupDoor( doorName + "left", false, config.doorMoveDist );
|
||||
list[ list.size ] = setupDoor( doorName + "right", true, config.doorMoveDist );
|
||||
}
|
||||
|
||||
elevator.doors[ floorname ] = list;
|
||||
}
|
||||
|
||||
if ( IsDefined( config.doorOpenTime ) )
|
||||
elevator.doorOpenTime = config.doorOpenTime;
|
||||
else
|
||||
elevator.doorOpenTime = ELEVATOR_DOOR_TIME;
|
||||
|
||||
elevator.doorSpeed = config.doorMoveDist / elevator.doorOpenTime;
|
||||
|
||||
if ( IsDefined( config.autoCloseTimeout ) )
|
||||
elevator.autoCloseTimeout = config.autoCloseTimeout;
|
||||
else
|
||||
elevator.autoCloseTimeout = ELEVATOR_AUTOCLOSE_TIMEOUT;
|
||||
|
||||
elevator.trigBlock = GetEnt( config.trigBlockName, "targetname" );
|
||||
AssertEx( IsDefined( elevator.trigBlock ), "Could not find an elevator trigger named " + config.trigBlockName );
|
||||
|
||||
if ( IsDefined( config.autoCloseTimeout ) )
|
||||
elevator.autoCloseTimeout = config.autoCloseTimeout;
|
||||
else
|
||||
elevator.autoCloseTimeout = ELEVATOR_AUTOCLOSE_TIMEOUT;
|
||||
|
||||
elevator.doorOpenSfx = config.doorOpenSfx; // scn_elevator_doors_opening
|
||||
elevator.doorCloseSfx = config.doorCloseSfx; // scn_elevator_doors_closing
|
||||
}
|
||||
|
||||
if ( IsDefined( config.moveTime ) )
|
||||
elevator.moveTime = config.moveTime;
|
||||
else
|
||||
elevator.moveTime = ELEVATOR_FLOOR_MOVE_TIME;
|
||||
|
||||
elevator.destinations = [];
|
||||
elevator.pathBlockers = [];
|
||||
elevator.buttons = GetEntArray( config.buttons, "targetname" );
|
||||
foreach ( button in elevator.buttons )
|
||||
{
|
||||
button setupButton( elevator );
|
||||
}
|
||||
|
||||
// set up destinations
|
||||
destinationStructs = getstructarray( config.destinations, "targetname" );
|
||||
foreach ( destination in destinationStructs )
|
||||
{
|
||||
elevator setupDestination( destination );
|
||||
}
|
||||
elevator.destinationNames = config.destinationNames;
|
||||
|
||||
elevator.curFloor = config.destinationNames[0]; // "floor1"; should this be determined from destinations?
|
||||
elevator.requestedFloor = elevator.curFloor;
|
||||
elevator.doorState = ELEVATOR_DOOR_STATE_CLOSED;
|
||||
|
||||
if ( IsDefined( config.models ) )
|
||||
{
|
||||
elevatorModels = GetEntArray( config.models, "targetname" );
|
||||
if ( IsDefined( elevatorModels ) )
|
||||
{
|
||||
foreach ( eleModel in elevatorModels )
|
||||
{
|
||||
eleModel LinkTo( elevator );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
elevator thread elevatorThink();
|
||||
|
||||
if (elevator.doors.size > 0)
|
||||
{
|
||||
elevator thread openElevatorDoors( elevator.curFloor, false );
|
||||
}
|
||||
|
||||
// sounds
|
||||
elevator.startSfx = config.startSfx; // "scn_elevator_startup"
|
||||
elevator.stopSfx = config.stopSfx; // "scn_elevator_stopping"
|
||||
elevator.loopSfx = config.loopSfx; // "scn_elevator_moving_lp"
|
||||
elevator.beepSfx = config.beepSfx; // "scn_elevator_beep"
|
||||
|
||||
|
||||
// callback on init
|
||||
elevator.onMoveCallback = config.onMoveCallback;
|
||||
elevator.onArrivedCallback = config.onArrivedCallback;
|
||||
|
||||
return elevator;
|
||||
}
|
||||
|
||||
setupDoor( doorName, isRightSide, moveDistance )
|
||||
{
|
||||
door = GetEnt( doorName, "targetname" );
|
||||
if (IsDefined(door))
|
||||
{
|
||||
door.closePos = door.origin;
|
||||
if (IsDefined(door.target))
|
||||
{
|
||||
targetStruct = getstruct( door.target, "targetname" );
|
||||
door.openPos = targetStruct.origin;
|
||||
}
|
||||
else
|
||||
{
|
||||
offset = AnglesToForward( door.angles ) * moveDistance;
|
||||
/*
|
||||
if (isRightSide)
|
||||
{
|
||||
offset *= -1;
|
||||
}
|
||||
*/
|
||||
door.openPos = door.origin + offset;
|
||||
}
|
||||
|
||||
// door.unresolved_collision_func = ::handleUnreslovedCollision;
|
||||
|
||||
return door;
|
||||
}
|
||||
else
|
||||
{
|
||||
AssertEx( IsDefined( door ), "Could not find an elevator door entity named " + doorName );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
setupButton( elevator ) // self == button
|
||||
{
|
||||
self.owner = elevator;
|
||||
|
||||
if ( IsDefined( self.target ) )
|
||||
{
|
||||
destination = getstruct( self.target, "targetname" );
|
||||
self setupDestination( destination );
|
||||
}
|
||||
|
||||
self enableButton();
|
||||
}
|
||||
|
||||
setupDestination( destination ) // self == elevator
|
||||
{
|
||||
|
||||
if ( IsDefined( destination ) )
|
||||
{
|
||||
self.destinations[ destination.script_label ] = destination.origin;
|
||||
if ( IsDefined( destination.target ) )
|
||||
{
|
||||
blocker = GetEnt( destination.target, "targetname" );
|
||||
if ( IsDefined( blocker ) )
|
||||
{
|
||||
self.pathBlockers[ destination.script_label ] = blocker;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enableButton() // self == button
|
||||
{
|
||||
self SetHintString( &"MP_ELEVATOR_USE" );
|
||||
self MakeUsable();
|
||||
|
||||
self thread buttonThink();
|
||||
}
|
||||
|
||||
disableButton()
|
||||
{
|
||||
self MakeUnusable();
|
||||
}
|
||||
|
||||
buttonThink()
|
||||
{
|
||||
elevator = self.owner;
|
||||
elevator endon( "elevator_busy" );
|
||||
|
||||
while ( true )
|
||||
{
|
||||
self waittill( "trigger" );
|
||||
|
||||
if ( !IsDefined( self.script_label ) || self.script_label == "elevator" )
|
||||
{
|
||||
// do some stuff
|
||||
if ( elevator.curFloor == elevator.destinationNames[0] )
|
||||
{
|
||||
elevator.requestedFloor = elevator.destinationNames[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
elevator.requestedFloor = elevator.destinationNames[0];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
elevator.requestedFloor = self.script_label;
|
||||
}
|
||||
|
||||
elevator notify( "elevator_called" );
|
||||
}
|
||||
}
|
||||
|
||||
elevatorThink()
|
||||
{
|
||||
hasDoors = self.doors.size > 0;
|
||||
|
||||
while ( true )
|
||||
{
|
||||
self waittill( "elevator_called" );
|
||||
|
||||
foreach ( button in self.buttons )
|
||||
{
|
||||
button disableButton();
|
||||
}
|
||||
|
||||
if ( self.curFloor != self.requestedFloor )
|
||||
{
|
||||
if ( self.doorState != ELEVATOR_DOOR_STATE_CLOSED )
|
||||
{
|
||||
self notify ("elevator_stop_autoclose");
|
||||
self thread closeElevatorDoors( self.curFloor );
|
||||
self waittill( "elevator_doors_closed" );
|
||||
}
|
||||
else if ( !hasDoors )
|
||||
{
|
||||
self elevatorBlockPath( self.curFloor );
|
||||
}
|
||||
|
||||
self elevatorMoveToFloor( self.requestedFloor );
|
||||
wait (0.25);
|
||||
}
|
||||
|
||||
if ( hasDoors )
|
||||
{
|
||||
self thread openElevatorDoors( self.curFloor, false );
|
||||
self waittill ( "elevator_doors_open" );
|
||||
}
|
||||
else
|
||||
{
|
||||
self elevatorClearPath( self.curFloor );
|
||||
}
|
||||
|
||||
foreach ( button in self.buttons )
|
||||
{
|
||||
button enableButton();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
elevatorMoveToFloor( targetFloor )
|
||||
{
|
||||
//self PlaySound( self.startSfx );
|
||||
//self PlayLoopSound( self.loopSfx );
|
||||
|
||||
destinationPos = self.destinations[ targetFloor ];
|
||||
deltaZ = destinationPos[2] - self.origin[2]; // may need to change this to full vector later
|
||||
|
||||
if ( IsDefined( self.doors[ "elevator" ] ) )
|
||||
{
|
||||
// move doors
|
||||
foreach ( door in self.doors[ "elevator" ] )
|
||||
{
|
||||
door MoveZ( deltaZ, self.moveTime );
|
||||
}
|
||||
}
|
||||
|
||||
// move the floor
|
||||
self MoveZ( deltaZ, self.moveTime );
|
||||
|
||||
if ( IsDefined( self.onMoveCallback ) )
|
||||
{
|
||||
self thread [[ self.onMoveCallback ]]( targetFloor );
|
||||
}
|
||||
|
||||
wait ( self.moveTime );
|
||||
|
||||
//self StopLoopSound ( self.loopSfx );
|
||||
//self PlaySound ( self.stopSfx );
|
||||
if ( IsDefined( self.beepSfx ) )
|
||||
self PlaySound ( self.beepSfx );
|
||||
|
||||
self.curFloor = self.requestedFloor;
|
||||
|
||||
if ( IsDefined( self.onArrivedCallback ) )
|
||||
{
|
||||
self thread [[ self.onArrivedCallback ]]( self.curFloor );
|
||||
}
|
||||
}
|
||||
|
||||
openElevatorDoors( floorName, autoClose ) // elevator
|
||||
{
|
||||
doorset = self.doors[ floorName ];
|
||||
|
||||
self.doorState = ELEVATOR_DOOR_STATE_OPENING;
|
||||
|
||||
// figre out the time it takes to move 1 door, assume it's the same fo rall
|
||||
door = doorset[0];
|
||||
doorDest = (door.openPos[0], door.openPos[1], door.origin[2]);
|
||||
moveDelta = doorDest - door.origin;
|
||||
moveDist = Length( moveDelta );
|
||||
|
||||
// this might move 0 time / 0 dist
|
||||
// but we need it to counteract the closing elevator
|
||||
// wish I could just tell it to stop, instead
|
||||
movetime = moveDist / self.doorSpeed;
|
||||
accelTime = 0.25;
|
||||
if (moveTime == 0.0)
|
||||
{
|
||||
moveTime = 0.05;
|
||||
accelTime = 0.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
self PlaySound( self.doorOpenSfx );
|
||||
accelTime = min(accelTime, moveTime);
|
||||
}
|
||||
|
||||
foreach ( door in doorset )
|
||||
{
|
||||
door MoveTo( (door.openPos[0], door.openPos[1], door.origin[2]), movetime, 0.0, accelTime );
|
||||
}
|
||||
wait ( movetime );
|
||||
|
||||
self.doorState = ELEVATOR_DOOR_STATE_OPEN;
|
||||
|
||||
self notify ( "elevator_doors_open" );
|
||||
|
||||
self elevatorClearPath( floorName );
|
||||
|
||||
if ( autoClose )
|
||||
{
|
||||
self thread elevatorDoorsAutoClose();
|
||||
}
|
||||
}
|
||||
|
||||
closeElevatorDoors( floorName )
|
||||
{
|
||||
self endon( "elevator_close_interrupted" );
|
||||
|
||||
self thread watchCloseInterrupted( floorName );
|
||||
|
||||
doorset = self.doors[ floorName ];
|
||||
|
||||
self.doorState = ELEVATOR_DOOR_STATE_CLOSING;
|
||||
|
||||
// figre out the time it takes to move 1 door, assume it's the same fo rall
|
||||
door = doorset[0];
|
||||
doorDest = (door.closePos[0], door.closePos[1], door.origin[2]);
|
||||
moveDelta = doorDest - door.origin;
|
||||
moveDist = Length( moveDelta );
|
||||
|
||||
if ( moveDist != 0.0 )
|
||||
{
|
||||
movetime = moveDist / self.doorSpeed;
|
||||
foreach ( door in doorset )
|
||||
{
|
||||
// we assume the doors all begin closed,
|
||||
// so door.closePos should eventually be defined by the time we need it
|
||||
door MoveTo( (door.closePos[0], door.closePos[1], door.origin[2]), movetime, 0.0, 0.25 );
|
||||
}
|
||||
self PlaySound( self.doorCloseSfx );
|
||||
wait ( movetime );
|
||||
}
|
||||
|
||||
self.doorState = ELEVATOR_DOOR_STATE_CLOSED;
|
||||
|
||||
self elevatorBlockPath( floorName );
|
||||
|
||||
self notify( "elevator_doors_closed" );
|
||||
}
|
||||
|
||||
watchCloseInterrupted( floorName )
|
||||
{
|
||||
// if the doors have closed successfully, we don't care any more
|
||||
self endon( "elevator_doors_closed" );
|
||||
|
||||
// make sure there is nothing in the way now
|
||||
nothingBlocking = true;
|
||||
foreach ( character in level.characters )
|
||||
{
|
||||
if ( character isTouchingTrigger( self.trigBlock ) )
|
||||
{
|
||||
nothingBlocking = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( nothingBlocking )
|
||||
{
|
||||
self.trigBlock waittill( "trigger" );
|
||||
}
|
||||
|
||||
self notify( "elevator_close_interrupted" );
|
||||
|
||||
self openElevatorDoors( floorName, true );
|
||||
}
|
||||
|
||||
isTouchingTrigger( trigger ) // self == player
|
||||
{
|
||||
return ( IsAlive( self ) && self IsTouching( trigger ) );
|
||||
}
|
||||
|
||||
elevatorDoorsAutoClose() // self == elevator
|
||||
{
|
||||
self endon( "elevator_doors_closed" );
|
||||
self endon( "elevator_stop_autoclose" );
|
||||
|
||||
wait ( self.autoCloseTimeout );
|
||||
|
||||
self closeElevatorDoors( self.curFloor);
|
||||
}
|
||||
|
||||
handleUnreslovedCollision( hitEnt ) // self == mover, hitEnt == player (usually)
|
||||
{
|
||||
if ( !IsPlayer( hitEnt ) )
|
||||
{
|
||||
hitEnt DoDamage( 1000, hitEnt.origin, self, self, "MOD_CRUSH" );
|
||||
}
|
||||
}
|
||||
|
||||
elevatorClearPath( floorName ) // self == elevator
|
||||
{
|
||||
blocker = self.pathBlockers[ floorName ];
|
||||
if ( IsDefined( blocker ) )
|
||||
{
|
||||
blocker ConnectPaths();
|
||||
blocker Hide();
|
||||
blocker NotSolid();
|
||||
}
|
||||
}
|
||||
|
||||
elevatorBlockPath( floorName )
|
||||
{
|
||||
blocker = self.pathBlockers[ floorName ];
|
||||
if ( IsDefined( blocker ) )
|
||||
{
|
||||
blocker Show();
|
||||
blocker Solid();
|
||||
blocker DisconnectPaths();
|
||||
}
|
||||
}
|
171
maps/mp/_empgrenade.gsc
Normal file
171
maps/mp/_empgrenade.gsc
Normal file
@ -0,0 +1,171 @@
|
||||
#include maps\mp\_utility;
|
||||
#include common_scripts\utility;
|
||||
#include maps\mp\killstreaks\_emp_common;
|
||||
|
||||
|
||||
init()
|
||||
{
|
||||
thread onPlayerConnect();
|
||||
}
|
||||
|
||||
onPlayerConnect()
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
level waittill("connected", player);
|
||||
player thread onPlayerSpawned();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
onPlayerSpawned()
|
||||
{
|
||||
self endon("disconnect");
|
||||
|
||||
for(;;)
|
||||
{
|
||||
self waittill( "spawned_player" );
|
||||
|
||||
self thread monitorEMPGrenade();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
monitorEMPGrenade()
|
||||
{
|
||||
self endon("death");
|
||||
self endon("disconnect");
|
||||
self endon("faux_spawn");
|
||||
self.empEndTime = 0;
|
||||
|
||||
while(1)
|
||||
{
|
||||
// self waittill( "emp_grenaded", attacker );
|
||||
self waittill( "emp_damage", attacker, duration );
|
||||
|
||||
if ( !IsAlive( self )
|
||||
|| IsDefined( self.usingRemote )
|
||||
|| ( self _hasPerk( "specialty_empimmune" ) ) //MW3 emp resistance perk
|
||||
|| !IsDefined( attacker )
|
||||
)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
hurtVictim = true;
|
||||
hurtAttacker = false;
|
||||
|
||||
assert( IsDefined(self.pers["team"]) );
|
||||
|
||||
if ( level.teamBased
|
||||
&& attacker != self
|
||||
&& IsDefined(attacker.pers["team"])
|
||||
&& attacker.pers["team"] == self.pers["team"]
|
||||
)
|
||||
{
|
||||
if(level.friendlyfire == 0) // no FF
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if(level.friendlyfire == 1) // FF
|
||||
{
|
||||
hurtattacker = false;
|
||||
hurtvictim = true;
|
||||
}
|
||||
else if(level.friendlyfire == 2) // reflect
|
||||
{
|
||||
hurtvictim = false;
|
||||
hurtattacker = true;
|
||||
}
|
||||
else if(level.friendlyfire == 3) // share
|
||||
{
|
||||
hurtattacker = true;
|
||||
hurtvictim = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
attacker notify( "emp_hit" );
|
||||
|
||||
if( attacker != self )
|
||||
{
|
||||
attacker maps\mp\gametypes\_missions::processChallenge( "ch_onthepulse" );
|
||||
}
|
||||
}
|
||||
|
||||
if ( hurtvictim && IsDefined(self) )
|
||||
{
|
||||
self thread applyEMP( duration );
|
||||
}
|
||||
if ( hurtattacker )
|
||||
{
|
||||
attacker thread applyEMP( duration );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
applyEMP( duration )
|
||||
{
|
||||
self notify( "applyEmp" );
|
||||
self endon( "applyEmp" );
|
||||
self endon( "disconnect" );
|
||||
|
||||
self endon( "death" );
|
||||
|
||||
wait .05;
|
||||
|
||||
self.empGrenaded = true;
|
||||
self shellshock( "flashbang_mp", 1 );
|
||||
self.empEndTime = GetTime() + (duration * 1000);
|
||||
|
||||
self applyPerPlayerEMPEffects_OnDetonate();
|
||||
self applyPerPlayerEMPEffects();
|
||||
self thread empRumbleLoop( .75 );
|
||||
self thread empGrenadeDeathWaiter();
|
||||
|
||||
wait ( duration );
|
||||
|
||||
self notify( "empGrenadeTimedOut" );
|
||||
self checkToTurnOffEmp();
|
||||
}
|
||||
|
||||
empGrenadeDeathWaiter()
|
||||
{
|
||||
self notify( "empGrenadeDeathWaiter" );
|
||||
self endon( "empGrenadeDeathWaiter" );
|
||||
|
||||
self endon( "empGrenadeTimedOut" );
|
||||
|
||||
self waittill( "death" );
|
||||
self checkToTurnOffEmp();
|
||||
}
|
||||
|
||||
checkToTurnOffEmp()
|
||||
{
|
||||
self.empGrenaded = false;
|
||||
|
||||
if ( !(self shouldPlayerBeAffectedByEMP()) )
|
||||
{
|
||||
self removePerPlayerEMPEffects();
|
||||
}
|
||||
}
|
||||
|
||||
empRumbleLoop( duration )
|
||||
{
|
||||
self endon("emp_rumble_loop");
|
||||
self notify("emp_rumble_loop");
|
||||
|
||||
goalTime = GetTime() + duration * 1000;
|
||||
|
||||
while ( GetTime() < goalTime )
|
||||
{
|
||||
self PlayRumbleOnEntity( "damage_heavy" );
|
||||
wait( 0.05 );
|
||||
}
|
||||
}
|
||||
|
||||
// 2013-06-30 wallace: is isEMPGrenaded being used any more? Not sure if we even need the timestamp
|
||||
isEMPGrenaded()
|
||||
{
|
||||
return isDefined( self.empEndTime ) && gettime() < self.empEndTime;
|
||||
}
|
331
maps/mp/_entityheadicons.gsc
Normal file
331
maps/mp/_entityheadicons.gsc
Normal file
@ -0,0 +1,331 @@
|
||||
#include maps\mp\_utility;
|
||||
#include common_scripts\utility;
|
||||
#include maps\mp\gametypes\_hud_util;
|
||||
|
||||
init()
|
||||
{
|
||||
if (isdefined(level.initedEntityHeadIcons))
|
||||
return;
|
||||
level.initedEntityHeadIcons = true;
|
||||
|
||||
if( level.multiTeamBased )
|
||||
{
|
||||
foreach ( teamName in level.teamNameList )
|
||||
{
|
||||
str_team_headicon = "entity_headicon_" + teamName;
|
||||
game[ str_team_headicon ] = maps\mp\gametypes\_teams::MT_getTeamHeadIcon( teamName );
|
||||
precacheShader( game[ str_team_headicon ] );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
game["entity_headicon_allies"] = maps\mp\gametypes\_teams::getTeamHeadIcon( "allies" );
|
||||
game["entity_headicon_axis"] = maps\mp\gametypes\_teams::getTeamHeadIcon( "axis" );
|
||||
|
||||
precacheShader( game["entity_headicon_allies"] );
|
||||
precacheShader( game["entity_headicon_axis"] );
|
||||
}
|
||||
}
|
||||
|
||||
// This can show to single players or to teams. Showing to a single player destroys instances of
|
||||
// the icon that are shown to their team. Showing to a team destroys instances of the icon that
|
||||
// are shown to players on that team
|
||||
setHeadIcon( showTo, icon, offset, width, height, archived, delay, constantSize, pinToScreenEdge, fadeOutPinnedIcon, is3D )
|
||||
{
|
||||
if ( IsGameParticipant( showTo ) && !IsPlayer( showTo ) )
|
||||
return; // Doesn't work for Agents, etc.
|
||||
|
||||
if ( !isDefined( self.entityHeadIcons ) )
|
||||
self.entityHeadIcons = [];
|
||||
|
||||
if( !IsDefined( archived ) )
|
||||
archived = true;
|
||||
|
||||
if( !IsDefined( delay ) )
|
||||
delay = 0.05;
|
||||
|
||||
if( !IsDefined( constantSize ) )
|
||||
constantSize = true;
|
||||
|
||||
if( !IsDefined( pinToScreenEdge ) )
|
||||
pinToScreenEdge = true;
|
||||
|
||||
if( !IsDefined( fadeOutPinnedIcon ) )
|
||||
fadeOutPinnedIcon = false;
|
||||
|
||||
if( !IsDefined( is3D ) )
|
||||
is3D = true;
|
||||
|
||||
if ( !isPlayer( showTo ) && showTo == "none" )
|
||||
{
|
||||
foreach ( key, headIcon in self.entityHeadIcons )
|
||||
{
|
||||
// TODO: remove and fix properly after ship
|
||||
if ( isDefined( headIcon ) )
|
||||
headIcon destroy();
|
||||
|
||||
self.entityHeadIcons[ key ] = undefined;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ( isPlayer( showTo ) )
|
||||
{
|
||||
if ( isDefined( self.entityHeadIcons[ showTo.guid ] ) )
|
||||
{
|
||||
self.entityHeadIcons[ showTo.guid ] destroy();
|
||||
self.entityHeadIcons[ showTo.guid ] = undefined;
|
||||
}
|
||||
|
||||
if ( icon == "" )
|
||||
return;
|
||||
|
||||
if ( isDefined(showTo.team) )
|
||||
{
|
||||
// remove from team or we'd have two icons
|
||||
if ( isDefined( self.entityHeadIcons[ showTo.team ] ) )
|
||||
{
|
||||
self.entityHeadIcons[ showTo.team ] destroy();
|
||||
self.entityHeadIcons[ showTo.team ] = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
headIcon = newClientHudElem( showTo );
|
||||
self.entityHeadIcons[ showTo.guid ] = headIcon;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert( showTo == "axis" || showTo == "allies" || isSubStr( showTo, "team_" ));
|
||||
assert( level.teamBased );
|
||||
|
||||
if ( isDefined( self.entityHeadIcons[ showTo ] ) )
|
||||
{
|
||||
self.entityHeadIcons[ showTo ] destroy();
|
||||
self.entityHeadIcons[ showTo ] = undefined;
|
||||
}
|
||||
|
||||
if ( icon == "" )
|
||||
return;
|
||||
|
||||
foreach ( key, hudIcon in self.entityHeadIcons )
|
||||
{
|
||||
if ( key == "axis" || key == "allies" )
|
||||
continue;
|
||||
|
||||
player = getPlayerForGuid( key );
|
||||
if ( player.team == showTo )
|
||||
{
|
||||
self.entityHeadIcons[ key ] destroy();
|
||||
self.entityHeadIcons[ key ] = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
headIcon = newTeamHudElem( showTo );
|
||||
self.entityHeadIcons[ showTo ] = headIcon;
|
||||
}
|
||||
|
||||
if ( !isDefined( width ) || !isDefined( height ) )
|
||||
{
|
||||
width = 10;
|
||||
height = 10;
|
||||
}
|
||||
|
||||
headIcon.archived = archived;
|
||||
headIcon.x = self.origin[0] + offset[0];
|
||||
headIcon.y = self.origin[1] + offset[1];
|
||||
headIcon.z = self.origin[2] + offset[2];
|
||||
headIcon.alpha = 0.85;
|
||||
headIcon setShader( icon, width, height );
|
||||
headIcon setWaypoint( constantSize, pinToScreenEdge, fadeOutPinnedIcon, is3D );
|
||||
|
||||
headIcon thread keepPositioned( self, offset, delay );
|
||||
self thread destroyIconsOnDeath();
|
||||
if ( isPlayer( showTo ) )
|
||||
headIcon thread destroyOnOwnerDisconnect( showTo );
|
||||
if ( isPlayer( self ) )
|
||||
headIcon thread destroyOnOwnerDisconnect( self );
|
||||
|
||||
return headIcon;
|
||||
}
|
||||
|
||||
|
||||
destroyOnOwnerDisconnect( owner )
|
||||
{
|
||||
self endon ( "death" );
|
||||
|
||||
owner waittill ( "disconnect" );
|
||||
|
||||
self destroy();
|
||||
}
|
||||
|
||||
|
||||
destroyIconsOnDeath()
|
||||
{
|
||||
self notify ( "destroyIconsOnDeath" );
|
||||
self endon ( "destroyIconsOnDeath" );
|
||||
|
||||
self waittill ( "death" );
|
||||
|
||||
if ( !isDefined( self.entityHeadIcons ) )
|
||||
return;
|
||||
|
||||
foreach ( key, headIcon in self.entityHeadIcons )
|
||||
{
|
||||
// TODO: remove and fix properly after ship
|
||||
if( !isDefined(headIcon) ) //needed for FFA host migration (when host has active head icons)
|
||||
continue;
|
||||
|
||||
headIcon destroy();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
keepPositioned( owner, offset, delay )
|
||||
{
|
||||
self endon ( "death" );
|
||||
owner endon ( "death" );
|
||||
owner endon ( "disconnect" );
|
||||
|
||||
allowCodeLink = ( IsDefined(owner.classname) && !isOwnerCarePakage(owner) );
|
||||
|
||||
if( allowCodeLink )
|
||||
{
|
||||
self LinkWaypointToTargetWithOffset( owner, offset );
|
||||
}
|
||||
|
||||
for ( ;; )
|
||||
{
|
||||
if( !IsDefined( owner ) )
|
||||
return;
|
||||
|
||||
if( !allowCodeLink )
|
||||
{
|
||||
pos = owner.origin;
|
||||
|
||||
self.x = pos[0] + offset[0];
|
||||
self.y = pos[1] + offset[1];
|
||||
self.z = pos[2] + offset[2];
|
||||
}
|
||||
|
||||
if ( delay > 0.05 )
|
||||
{
|
||||
self.alpha = 0.85;
|
||||
self FadeOverTime( delay );
|
||||
self.alpha = 0;
|
||||
}
|
||||
|
||||
wait delay;
|
||||
}
|
||||
}
|
||||
|
||||
isOwnerCarePakage( owner )
|
||||
{
|
||||
return ( IsDefined(owner.targetname) && ( owner.targetname == "care_package" ) );
|
||||
}
|
||||
|
||||
setTeamHeadIcon( team, offset ) // "allies", "axis", "all", "none"
|
||||
{
|
||||
if ( !level.teamBased )
|
||||
return;
|
||||
|
||||
if ( !isDefined( self.entityHeadIconTeam ) )
|
||||
{
|
||||
self.entityHeadIconTeam = "none";
|
||||
self.entityHeadIcon = undefined;
|
||||
}
|
||||
|
||||
shader = game["entity_headicon_" + team];
|
||||
|
||||
self.entityHeadIconTeam = team;
|
||||
|
||||
if ( isDefined( offset ) )
|
||||
self.entityHeadIconOffset = offset;
|
||||
else
|
||||
self.entityHeadIconOffset = (0,0,0);
|
||||
|
||||
self notify( "kill_entity_headicon_thread" );
|
||||
|
||||
if ( team == "none" )
|
||||
{
|
||||
if ( isDefined( self.entityHeadIcon ) )
|
||||
self.entityHeadIcon destroy();
|
||||
return;
|
||||
}
|
||||
|
||||
headIcon = newTeamHudElem( team );
|
||||
headIcon.archived = true;
|
||||
headIcon.x = self.origin[0] + self.entityHeadIconOffset[0];
|
||||
headIcon.y = self.origin[1] + self.entityHeadIconOffset[1];
|
||||
headIcon.z = self.origin[2] + self.entityHeadIconOffset[2];
|
||||
headIcon.alpha = .8;
|
||||
headIcon setShader( shader, 10, 10 );
|
||||
headIcon setWaypoint( false, false, false, true );
|
||||
self.entityHeadIcon = headIcon;
|
||||
|
||||
self thread keepIconPositioned();
|
||||
self thread destroyHeadIconsOnDeath();
|
||||
}
|
||||
|
||||
setPlayerHeadIcon( player, offset ) // "allies", "axis", "all", "none"
|
||||
{
|
||||
if ( level.teamBased )
|
||||
return;
|
||||
|
||||
if ( !isDefined( self.entityHeadIconTeam ) )
|
||||
{
|
||||
self.entityHeadIconTeam = "none";
|
||||
self.entityHeadIcon = undefined;
|
||||
}
|
||||
|
||||
self notify( "kill_entity_headicon_thread" );
|
||||
|
||||
if ( !isDefined( player ) )
|
||||
{
|
||||
if ( isDefined( self.entityHeadIcon ) )
|
||||
self.entityHeadIcon destroy();
|
||||
return;
|
||||
}
|
||||
|
||||
team = player.team;
|
||||
self.entityHeadIconTeam = team;
|
||||
|
||||
if ( isDefined( offset ) )
|
||||
self.entityHeadIconOffset = offset;
|
||||
else
|
||||
self.entityHeadIconOffset = (0,0,0);
|
||||
|
||||
shader = game["entity_headicon_" + team];
|
||||
|
||||
headIcon = newClientHudElem( player );
|
||||
headIcon.archived = true;
|
||||
headIcon.x = self.origin[0] + self.entityHeadIconOffset[0];
|
||||
headIcon.y = self.origin[1] + self.entityHeadIconOffset[1];
|
||||
headIcon.z = self.origin[2] + self.entityHeadIconOffset[2];
|
||||
headIcon.alpha = .8;
|
||||
headIcon setShader( shader, 10, 10 );
|
||||
headIcon setWaypoint( false, false, false, true );
|
||||
self.entityHeadIcon = headIcon;
|
||||
|
||||
self thread keepIconPositioned();
|
||||
self thread destroyHeadIconsOnDeath();
|
||||
}
|
||||
|
||||
keepIconPositioned()
|
||||
{
|
||||
self.entityHeadIcon LinkWaypointToTargetWithOffset( self, self.entityHeadIconOffset );
|
||||
}
|
||||
|
||||
destroyHeadIconsOnDeath()
|
||||
{
|
||||
self endon( "kill_entity_headicon_thread" );
|
||||
self waittill ( "death" );
|
||||
|
||||
// TODO: remove and fix properly after ship
|
||||
if( !isDefined(self.entityHeadIcon) )
|
||||
return;
|
||||
|
||||
self.entityHeadIcon destroy();
|
||||
}
|
||||
|
||||
|
984
maps/mp/_events.gsc
Normal file
984
maps/mp/_events.gsc
Normal file
@ -0,0 +1,984 @@
|
||||
#include maps\mp\_utility;
|
||||
#include maps\mp\gametypes\_hud_util;
|
||||
#include common_scripts\utility;
|
||||
|
||||
init()
|
||||
{
|
||||
// load all of the scoring data for the current game mode
|
||||
game_type_col = [];
|
||||
game_type_col[ "dm" ] = 3; // free for all
|
||||
game_type_col[ "war" ] = 4; // team deathmatch
|
||||
game_type_col[ "sd" ] = 5; // search and destroy
|
||||
game_type_col[ "dom" ] = 6; // domination
|
||||
game_type_col[ "conf" ] = 7; // kill confirmed
|
||||
game_type_col[ "sr" ] = 8; // search and rescue
|
||||
game_type_col[ "bnty" ] = 9; // bounty
|
||||
game_type_col[ "grind" ] = 10; // grind
|
||||
game_type_col[ "blitz" ] = 11; // blitz
|
||||
game_type_col[ "cranked" ] = 12; // cranked
|
||||
game_type_col[ "infect" ] = 13; // infected
|
||||
game_type_col[ "sotf" ] = 14; // survival of the fittest
|
||||
game_type_col[ "sotf_ffa" ] = 15; // survival of the fittest FFA
|
||||
game_type_col[ "horde" ] = 16; // horde
|
||||
game_type_col[ "mugger" ] = 17; // mugger
|
||||
game_type_col[ "aliens" ] = 18; // aliens
|
||||
game_type_col[ "gun" ] = 19; // gun game
|
||||
game_type_col[ "grnd" ] = 20; // drop zone
|
||||
game_type_col[ "siege" ] = 21; // reinforce
|
||||
|
||||
game_type = level.gameType;
|
||||
if( !IsDefined( game_type ) )
|
||||
game_type = GetDvar( "g_gametype" );
|
||||
|
||||
row = 0;
|
||||
while( true )
|
||||
{
|
||||
value = TableLookupByRow( "mp/xp_event_table.csv", row, game_type_col[ game_type ] );
|
||||
if( !IsDefined( value ) || value == "" )
|
||||
break;
|
||||
|
||||
ref = TableLookupByRow( "mp/xp_event_table.csv", row, 0 );
|
||||
|
||||
if( ref == "win" || ref == "loss" || ref == "tie" )
|
||||
value = float( value );
|
||||
else
|
||||
value = int( value );
|
||||
|
||||
if( value != -1 )
|
||||
maps\mp\gametypes\_rank::registerScoreInfo( ref, value );
|
||||
|
||||
row++;
|
||||
}
|
||||
// end scoring data
|
||||
|
||||
maps\mp\killstreaks\_killstreaks::registerAdrenalineInfo( "damage", 0 );
|
||||
maps\mp\killstreaks\_killstreaks::registerAdrenalineInfo( "heavy_damage", 0 );
|
||||
maps\mp\killstreaks\_killstreaks::registerAdrenalineInfo( "damaged", 0 );
|
||||
maps\mp\killstreaks\_killstreaks::registerAdrenalineInfo( "kill", 1 );
|
||||
maps\mp\killstreaks\_killstreaks::registerAdrenalineInfo( "killed", 0 );
|
||||
|
||||
maps\mp\killstreaks\_killstreaks::registerAdrenalineInfo( "healed", 0);
|
||||
|
||||
maps\mp\killstreaks\_killstreaks::registerAdrenalineInfo( "headshot", 0 );
|
||||
maps\mp\killstreaks\_killstreaks::registerAdrenalineInfo( "melee", 0 );
|
||||
maps\mp\killstreaks\_killstreaks::registerAdrenalineInfo( "backstab", 0 );
|
||||
maps\mp\killstreaks\_killstreaks::registerAdrenalineInfo( "longshot", 0 );
|
||||
maps\mp\killstreaks\_killstreaks::registerAdrenalineInfo( "pointblank", 0 );
|
||||
maps\mp\killstreaks\_killstreaks::registerAdrenalineInfo( "assistedsuicide", 0);
|
||||
maps\mp\killstreaks\_killstreaks::registerAdrenalineInfo( "defender", 0 );
|
||||
maps\mp\killstreaks\_killstreaks::registerAdrenalineInfo( "avenger", 0 );
|
||||
maps\mp\killstreaks\_killstreaks::registerAdrenalineInfo( "execution", 0 );
|
||||
maps\mp\killstreaks\_killstreaks::registerAdrenalineInfo( "comeback", 0 );
|
||||
maps\mp\killstreaks\_killstreaks::registerAdrenalineInfo( "revenge", 0 );
|
||||
maps\mp\killstreaks\_killstreaks::registerAdrenalineInfo( "buzzkill", 0 );
|
||||
maps\mp\killstreaks\_killstreaks::registerAdrenalineInfo( "double", 0 );
|
||||
maps\mp\killstreaks\_killstreaks::registerAdrenalineInfo( "triple", 0 );
|
||||
maps\mp\killstreaks\_killstreaks::registerAdrenalineInfo( "multi", 0 );
|
||||
maps\mp\killstreaks\_killstreaks::registerAdrenalineInfo( "assist", 0 );
|
||||
maps\mp\killstreaks\_killstreaks::registerAdrenalineInfo( "firstBlood", 0 );
|
||||
maps\mp\killstreaks\_killstreaks::registerAdrenalineInfo( "capture", 1 );
|
||||
maps\mp\killstreaks\_killstreaks::registerAdrenalineInfo( "assistedCapture", 0 );
|
||||
maps\mp\killstreaks\_killstreaks::registerAdrenalineInfo( "plant", 1 );
|
||||
maps\mp\killstreaks\_killstreaks::registerAdrenalineInfo( "defuse", 1 );
|
||||
maps\mp\killstreaks\_killstreaks::registerAdrenalineInfo( "vehicleDestroyed", 1);
|
||||
|
||||
maps\mp\killstreaks\_killstreaks::registerAdrenalineInfo( "3streak", 0 );
|
||||
maps\mp\killstreaks\_killstreaks::registerAdrenalineInfo( "4streak", 0 );
|
||||
maps\mp\killstreaks\_killstreaks::registerAdrenalineInfo( "5streak", 0 );
|
||||
maps\mp\killstreaks\_killstreaks::registerAdrenalineInfo( "6streak", 0 );
|
||||
maps\mp\killstreaks\_killstreaks::registerAdrenalineInfo( "7streak", 0 );
|
||||
maps\mp\killstreaks\_killstreaks::registerAdrenalineInfo( "8streak", 0 );
|
||||
maps\mp\killstreaks\_killstreaks::registerAdrenalineInfo( "9streak", 0 );
|
||||
maps\mp\killstreaks\_killstreaks::registerAdrenalineInfo( "10streak", 0 );
|
||||
maps\mp\killstreaks\_killstreaks::registerAdrenalineInfo( "regen", 0 );
|
||||
|
||||
precacheShader( "crosshair_red" );
|
||||
|
||||
level._effect["money"] = loadfx ("fx/props/cash_player_drop");
|
||||
|
||||
level.numKills = 0;
|
||||
|
||||
level thread onPlayerConnect();
|
||||
}
|
||||
|
||||
|
||||
onPlayerConnect()
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
level waittill( "connected", player );
|
||||
|
||||
player.killedPlayers = [];
|
||||
player.killedPlayersCurrent = [];
|
||||
player.ch_extremeCrueltyComplete = false; // setting a player var to throttle challenge completion rate
|
||||
player.ch_tangoDownComplete = false; // for iw7 we should handle this in the challenge table
|
||||
player.killedBy = [];
|
||||
player.lastKilledBy = undefined;
|
||||
player.greatestUniquePlayerKills = 0;
|
||||
|
||||
player.recentKillCount = 0;
|
||||
player.lastKillTime = 0;
|
||||
player.lastKillDogTime = 0;
|
||||
player.damagedPlayers = [];
|
||||
|
||||
player thread monitorCrateJacking();
|
||||
player thread monitorObjectives();
|
||||
player thread monitorHealed();
|
||||
}
|
||||
}
|
||||
|
||||
damagedPlayer( victim, damage, weapon )
|
||||
{
|
||||
if ( damage < 50 && damage > 10 )
|
||||
self maps\mp\killstreaks\_killstreaks::giveAdrenaline( "damage" );
|
||||
else
|
||||
self maps\mp\killstreaks\_killstreaks::giveAdrenaline( "heavy_damage" );
|
||||
}
|
||||
|
||||
//notifies killed player over necessary frames
|
||||
killedPlayerNotifySys( killId, victim, weapon, meansOfDeath )
|
||||
{
|
||||
self endon ( "disconnect" );
|
||||
level endon ( "game_ended" );
|
||||
|
||||
self notify ( "killedPlayerNotify" );
|
||||
self endon ( "killedPlayerNotify" );
|
||||
|
||||
if( !isDefined( self.killsInAFrameCount ) )
|
||||
self.killsInAFrameCount = 0;
|
||||
|
||||
self.killsInAFrameCount++;
|
||||
|
||||
wait ( 0.05 );
|
||||
|
||||
if ( self.killsInAFrameCount > 1 )
|
||||
self thread notifyKilledPlayer( killId, victim, weapon, meansOfDeath, self.killsInAFrameCount );
|
||||
else
|
||||
self notify( "got_a_kill", victim, weapon, meansOfDeath );
|
||||
|
||||
self.killsInAFrameCount = 0;
|
||||
}
|
||||
|
||||
//possible loss of proper killID etc here. Using last killed properties
|
||||
notifyKilledPlayer( killId, victim, weapon, meansOfDeath, numKills )
|
||||
{
|
||||
for( i = 0; i < numKills; i++ )
|
||||
{
|
||||
//used by intel
|
||||
self notify( "got_a_kill", victim, weapon, meansOfDeath );
|
||||
wait ( 0.05 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
killedPlayer( killId, victim, weapon, meansOfDeath )
|
||||
{
|
||||
victimGuid = victim.guid;
|
||||
myGuid = self.guid;
|
||||
curTime = getTime();
|
||||
|
||||
self thread killedPlayerNotifySys( killId, victim, weapon, meansOfDeath );
|
||||
self thread updateRecentKills( killId );
|
||||
self.lastKillTime = getTime();
|
||||
self.lastKilledPlayer = victim;
|
||||
|
||||
self.modifiers = [];
|
||||
|
||||
level.numKills++;
|
||||
|
||||
// a player is either damaged, or killed; never both
|
||||
self.damagedPlayers[victimGuid] = undefined;
|
||||
|
||||
if ( !isKillstreakWeapon( weapon ) && !self isJuggernaut() && !self _hasPerk( "specialty_explosivebullets" ) )
|
||||
{
|
||||
if ( weapon == "none" )
|
||||
return false;
|
||||
|
||||
// added a failsafe here because this could be the victim killing themselves with something like the dead man's hand deathstreak
|
||||
if ( victim.attackers.size == 1 && !IsDefined( victim.attackers[victim.guid] ) )
|
||||
{
|
||||
/#
|
||||
if ( !isDefined( victim.attackers[self.guid] ) )
|
||||
{
|
||||
println("Weapon: " + weapon );
|
||||
println("meansOfDeath: " + meansOfDeath );
|
||||
println("Attacker GUID: " + self.guid + " (name: " + self.name + ")" );
|
||||
|
||||
i = 0;
|
||||
foreach ( key,value in victim.attackers )
|
||||
{
|
||||
println( "victim.attackers " + i + " GUID: " + key + " (name: " + value.name + ")" );
|
||||
i++;
|
||||
}
|
||||
}
|
||||
#/
|
||||
assertEx( isDefined( victim.attackers[self.guid] ), "See console log for details" );
|
||||
|
||||
weaponClass = getWeaponClass( weapon );
|
||||
|
||||
if( weaponClass == "weapon_sniper" &&
|
||||
meansOfDeath != "MOD_MELEE" &&
|
||||
getTime() == victim.attackerData[self.guid].firstTimeDamaged )
|
||||
{
|
||||
self.modifiers["oneshotkill"] = true;
|
||||
self thread maps\mp\gametypes\_rank::xpEventPopup( "one_shot_kill" );
|
||||
}
|
||||
}
|
||||
|
||||
if ( isDefined( victim.throwingGrenade ) && victim.throwingGrenade == "frag_grenade_mp" )
|
||||
self.modifiers["cooking"] = true;
|
||||
|
||||
if ( isDefined(self.assistedSuicide) && self.assistedSuicide )
|
||||
self assistedSuicide( killId, weapon, meansOfDeath );
|
||||
|
||||
if ( level.numKills == 1 )
|
||||
self firstBlood( killId, weapon, meansOfDeath );
|
||||
|
||||
if ( self.pers["cur_death_streak"] > 3 )
|
||||
self comeBack( killId, weapon, meansOfDeath );
|
||||
|
||||
if ( meansOfDeath == "MOD_HEAD_SHOT" )
|
||||
{
|
||||
if ( isDefined( victim.lastStand ) )
|
||||
execution( killId, weapon, meansOfDeath );
|
||||
else
|
||||
headShot( killId, weapon, meansOfDeath );
|
||||
}
|
||||
|
||||
if ( isDefined(self.wasti) && self.wasti && getTime() - self.spawnTime <= 5000 )
|
||||
self.modifiers["jackintheboxkill"] = true;
|
||||
|
||||
if ( !isAlive( self ) && self.deathtime + 800 < getTime() )
|
||||
postDeathKill( killId );
|
||||
|
||||
if ( level.teamBased && curTime - victim.lastKillTime < 500 )
|
||||
{
|
||||
if ( victim.lastkilledplayer != self )
|
||||
self avengedPlayer( killId, weapon, meansOfDeath );
|
||||
}
|
||||
|
||||
if ( IsDefined( victim.lastKillDogTime ) && curTime - victim.lastKillDogTime < 2000 )
|
||||
{
|
||||
self avengedDog( killId, weapon, meansOfDeath );
|
||||
}
|
||||
|
||||
foreach ( guid, damageTime in victim.damagedPlayers )
|
||||
{
|
||||
if ( guid == self.guid )
|
||||
continue;
|
||||
|
||||
if ( level.teamBased && curTime - damageTime < 500 )
|
||||
self defendedPlayer( killId, weapon, meansOfDeath );
|
||||
}
|
||||
|
||||
if ( isDefined( victim.attackerPosition ) )
|
||||
attackerPosition = victim.attackerPosition;
|
||||
else
|
||||
attackerPosition = self.origin;
|
||||
|
||||
if ( isPointBlank ( self, weapon, meansOfDeath, attackerPosition, victim ) )
|
||||
self thread pointblank( killId, weapon, meansOfDeath );
|
||||
else if( isLongShot( self, weapon, meansOfDeath, attackerPosition, victim ) )
|
||||
self thread longshot( killId, weapon, meansOfDeath );
|
||||
|
||||
victim_pers_cur_kill_streak = victim.pers[ "cur_kill_streak" ];
|
||||
if ( victim_pers_cur_kill_streak > 0 && isDefined( victim.killstreaks[ victim_pers_cur_kill_streak + 1 ] ) )
|
||||
{
|
||||
// playercard splash for the killstreak stopped
|
||||
self buzzKill( killId, victim, weapon, meansOfDeath );
|
||||
}
|
||||
|
||||
self thread checkMatchDataKills( killId, victim, weapon, meansOfDeath);
|
||||
|
||||
}
|
||||
else if( weapon == "guard_dog_mp" )
|
||||
{
|
||||
if( !isAlive( self ) && self.deathtime < GetTime() )
|
||||
postDeathDogKill();
|
||||
}
|
||||
|
||||
if ( !isDefined( self.killedPlayers[victimGuid] ) )
|
||||
self.killedPlayers[victimGuid] = 0;
|
||||
|
||||
if ( !isDefined( self.killedPlayersCurrent[victimGuid] ) )
|
||||
self.killedPlayersCurrent[victimGuid] = 0;
|
||||
|
||||
if ( !isDefined( victim.killedBy[myGuid] ) )
|
||||
victim.killedBy[myGuid] = 0;
|
||||
|
||||
self.killedPlayers[victimGuid]++;
|
||||
|
||||
//this sets player stat for routine customer award
|
||||
if ( self.killedPlayers[victimGuid] > self.greatestUniquePlayerKills )
|
||||
self setPlayerStat( "killedsameplayer", self.killedPlayers[victimGuid] );
|
||||
|
||||
self.killedPlayersCurrent[victimGuid]++;
|
||||
victim.killedBy[myGuid]++;
|
||||
|
||||
victim.lastKilledBy = self;
|
||||
}
|
||||
|
||||
isLongShot( attacker, weapon, meansOfDeath, attackerPosition, victim )
|
||||
{
|
||||
if( isAlive( attacker ) &&
|
||||
!attacker isUsingRemote() &&
|
||||
( meansOfDeath == "MOD_RIFLE_BULLET" || meansOfDeath == "MOD_PISTOL_BULLET" || meansOfDeath == "MOD_HEAD_SHOT" ) &&
|
||||
!isKillstreakWeapon( weapon ) && !isDefined( attacker.assistedSuicide ) )
|
||||
{
|
||||
// check depending on the weapon being used to kill
|
||||
thisWeaponClass = getWeaponClass( weapon );
|
||||
switch( thisWeaponClass )
|
||||
{
|
||||
case "weapon_pistol":
|
||||
weapDist = 800;
|
||||
break;
|
||||
case "weapon_smg":
|
||||
weapDist = 1200;
|
||||
break;
|
||||
case "weapon_dmr":
|
||||
case "weapon_assault":
|
||||
case "weapon_lmg":
|
||||
weapDist = 1500;
|
||||
break;
|
||||
case "weapon_sniper":
|
||||
weapDist = 2000;
|
||||
break;
|
||||
case "weapon_shotgun":
|
||||
weapDist = 500;
|
||||
break;
|
||||
case "weapon_projectile":
|
||||
default:
|
||||
weapDist = 1536; // the old number
|
||||
break;
|
||||
}
|
||||
|
||||
weapDistSq = weapDist * weapDist;
|
||||
if( DistanceSquared( attackerPosition, victim.origin ) > weapDistSq )
|
||||
{
|
||||
if( attacker IsItemUnlocked( "specialty_holdbreath" ) && attacker _hasPerk( "specialty_holdbreath" ) )
|
||||
attacker maps\mp\gametypes\_missions::processChallenge( "ch_longdistance" );
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
isPointBlank( attacker, weapon, meansOfDeath, attackerPosition, victim )
|
||||
{
|
||||
if( isAlive( attacker ) &&
|
||||
!attacker isUsingRemote() &&
|
||||
( meansOfDeath == "MOD_RIFLE_BULLET" || meansOfDeath == "MOD_PISTOL_BULLET" || meansOfDeath == "MOD_HEAD_SHOT" ) &&
|
||||
!isKillstreakWeapon( weapon ) && !isDefined( attacker.assistedSuicide ) )
|
||||
{
|
||||
// point blank is the same for all classes of weapons, about 8'
|
||||
weapDistSq = 96 * 96;
|
||||
if( DistanceSquared( attackerPosition, victim.origin ) < weapDistSq )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
checkMatchDataKills( killId, victim, weapon, meansOfDeath )
|
||||
{
|
||||
weaponClass = getWeaponClass( weapon );
|
||||
alreadyUsed = false;
|
||||
|
||||
self thread camperCheck();
|
||||
|
||||
if ( isDefined( self.lastKilledBy ) && self.lastKilledBy == victim )
|
||||
{
|
||||
self.lastKilledBy = undefined;
|
||||
self revenge( killId );
|
||||
}
|
||||
|
||||
if ( victim.iDFlags & level.iDFLAGS_PENETRATION )
|
||||
self incPlayerStat( "bulletpenkills", 1 );
|
||||
|
||||
self_pers_rank = self.pers["rank"];
|
||||
victim_pers_rank = victim.pers["rank"];
|
||||
if ( self_pers_rank < victim_pers_rank )
|
||||
self incPlayerStat( "higherrankkills", 1 );
|
||||
|
||||
if ( self_pers_rank > victim_pers_rank )
|
||||
self incPlayerStat( "lowerrankkills", 1 );
|
||||
|
||||
if ( isDefined( self.inFinalStand ) && self.inFinalStand )
|
||||
self incPlayerStat( "laststandkills", 1 );
|
||||
|
||||
if ( isDefined( victim.inFinalStand ) && victim.inFinalStand )
|
||||
self incPlayerStat( "laststanderkills", 1 );
|
||||
|
||||
if ( self getCurrentWeapon() != self.primaryWeapon && self getCurrentWeapon() != self.secondaryWeapon )
|
||||
self incPlayerStat( "otherweaponkills", 1 );
|
||||
|
||||
timeAlive = getTime() - victim.spawnTime ;
|
||||
|
||||
if( !matchMakingGame() )
|
||||
victim setPlayerStatIfLower( "shortestlife", timeAlive );
|
||||
|
||||
victim setPlayerStatIfGreater( "longestlife", timeAlive );
|
||||
|
||||
if( meansOfDeath != "MOD_MELEE" )
|
||||
{
|
||||
switch( weaponClass )
|
||||
{
|
||||
case "weapon_pistol":
|
||||
case "weapon_smg":
|
||||
case "weapon_assault":
|
||||
case "weapon_projectile":
|
||||
case "weapon_dmr":
|
||||
case "weapon_sniper":
|
||||
case "weapon_shotgun":
|
||||
case "weapon_lmg":
|
||||
self checkMatchDataWeaponKills( victim, weapon, meansOfDeath, weaponClass );
|
||||
break;
|
||||
case "weapon_grenade":
|
||||
case "weapon_explosive":
|
||||
self checkMatchDataEquipmentKills( victim, weapon, meansOfDeath );
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Need to make sure these only apply to kills of an enemy, not friendlies or yourself
|
||||
checkMatchDataWeaponKills( victim, weapon, meansOfDeath, weaponType )
|
||||
{
|
||||
attacker = self;
|
||||
kill_ref = undefined;
|
||||
headshot_ref = undefined;
|
||||
death_ref = undefined;
|
||||
|
||||
switch( weaponType )
|
||||
{
|
||||
case "weapon_pistol":
|
||||
kill_ref = "pistolkills";
|
||||
headshot_ref = "pistolheadshots";
|
||||
break;
|
||||
case "weapon_smg":
|
||||
kill_ref = "smgkills";
|
||||
headshot_ref = "smgheadshots";
|
||||
break;
|
||||
case "weapon_assault":
|
||||
kill_ref = "arkills";
|
||||
headshot_ref = "arheadshots";
|
||||
break;
|
||||
case "weapon_projectile":
|
||||
if ( weaponClass( weapon ) == "rocketlauncher" )
|
||||
kill_ref = "rocketkills";
|
||||
break;
|
||||
case "weapon_dmr":
|
||||
kill_ref = "dmrkills";
|
||||
headshot_ref = "dmrheadshots";
|
||||
break;
|
||||
case "weapon_sniper":
|
||||
kill_ref = "sniperkills";
|
||||
headshot_ref = "sniperheadshots";
|
||||
break;
|
||||
case "weapon_shotgun":
|
||||
kill_ref = "shotgunkills";
|
||||
headshot_ref = "shotgunheadshots";
|
||||
death_ref = "shotgundeaths";
|
||||
break;
|
||||
case "weapon_lmg":
|
||||
kill_ref = "lmgkills";
|
||||
headshot_ref = "lmgheadshots";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if ( isDefined ( kill_ref ) )
|
||||
attacker incPlayerStat( kill_ref, 1 );
|
||||
|
||||
if ( isDefined ( headshot_ref ) && meansOfDeath == "MOD_HEAD_SHOT" )
|
||||
attacker incPlayerStat( headshot_ref, 1 );
|
||||
|
||||
if ( isDefined ( death_ref ) && !matchMakingGame() )
|
||||
victim incPlayerStat( death_ref, 1 );
|
||||
|
||||
if ( attacker isPlayerAds() )
|
||||
{
|
||||
attacker incPlayerStat( "adskills", 1 );
|
||||
|
||||
isThermal = IsSubStr( weapon, "thermal" );
|
||||
|
||||
// If weapon sniper, or acog or scope. Scope covers weapon_dmr with default scope
|
||||
if ( isThermal || IsSubStr( weapon, "acog" ) || IsSubStr( weapon, "scope" ) )
|
||||
attacker incPlayerStat( "scopedkills", 1 );
|
||||
|
||||
if ( isThermal )
|
||||
attacker incPlayerStat( "thermalkills", 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
attacker incPlayerStat( "hipfirekills", 1 );
|
||||
}
|
||||
}
|
||||
|
||||
// Need to make sure these only apply to kills of an enemy, not friendlies or yourself
|
||||
checkMatchDataEquipmentKills( victim, weapon, meansOfDeath )
|
||||
{
|
||||
attacker = self;
|
||||
|
||||
// equipment kills
|
||||
switch( weapon )
|
||||
{
|
||||
case "frag_grenade_mp":
|
||||
attacker incPlayerStat( "fragkills", 1 );
|
||||
attacker incPlayerStat( "grenadekills", 1 );
|
||||
isEquipment = true;
|
||||
break;
|
||||
case "c4_mp":
|
||||
attacker incPlayerStat( "c4kills", 1 );
|
||||
isEquipment = true;
|
||||
break;
|
||||
case "semtex_mp":
|
||||
attacker incPlayerStat( "semtexkills", 1 );
|
||||
attacker incPlayerStat( "grenadekills", 1 );
|
||||
isEquipment = true;
|
||||
break;
|
||||
case "claymore_mp":
|
||||
attacker incPlayerStat( "claymorekills", 1 );
|
||||
isEquipment = true;
|
||||
break;
|
||||
case "throwingknife_mp":
|
||||
attacker incPlayerStat( "throwingknifekills", 1 );
|
||||
self thread maps\mp\gametypes\_rank::xpEventPopup( "knifethrow" );
|
||||
isEquipment = true;
|
||||
break;
|
||||
default:
|
||||
isEquipment = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if ( isEquipment )
|
||||
attacker incPlayerStat( "equipmentkills", 1 );
|
||||
}
|
||||
|
||||
camperCheck()
|
||||
{
|
||||
self.lastKillWasCamping = false;
|
||||
if ( !isDefined ( self.lastKillLocation ) )
|
||||
{
|
||||
self.lastKillLocation = self.origin;
|
||||
self.lastCampKillTime = getTime();
|
||||
return;
|
||||
}
|
||||
|
||||
if ( Distance( self.lastKillLocation, self.origin ) < 512 && getTime() - self.lastCampKillTime > 5000 )
|
||||
{
|
||||
self incPlayerStat( "mostcamperkills", 1 );
|
||||
self.lastKillWasCamping = true;
|
||||
}
|
||||
|
||||
self.lastKillLocation = self.origin;
|
||||
self.lastCampKillTime = getTime();
|
||||
}
|
||||
|
||||
consolation( killId )
|
||||
{
|
||||
/*
|
||||
value = int( maps\mp\gametypes\_rank::getScoreInfoValue( "kill" ) * 0.25 );
|
||||
|
||||
self thread maps\mp\gametypes\_hud_message::SplashNotifyDelayed( "consolation", value );
|
||||
self thread maps\mp\gametypes\_rank::giveRankXP( "consolation", value );
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
proximityAssist( killId )
|
||||
{
|
||||
self.modifiers["proximityAssist"] = true;
|
||||
|
||||
self thread maps\mp\gametypes\_rank::xpEventPopup( "proximityassist" );
|
||||
|
||||
self thread maps\mp\gametypes\_rank::giveRankXP( "proximityassist" );
|
||||
//self thread maps\mp\_matchdata::logKillEvent( killId, "proximityAssist" );
|
||||
}
|
||||
|
||||
|
||||
proximityKill( killId )
|
||||
{
|
||||
self.modifiers["proximityKill"] = true;
|
||||
|
||||
self thread maps\mp\gametypes\_rank::xpEventPopup( "proximitykill" );
|
||||
|
||||
self thread maps\mp\gametypes\_rank::giveRankXP( "proximitykill" );
|
||||
//self thread maps\mp\_matchdata::logKillEvent( killId, "proximityKill" );
|
||||
}
|
||||
|
||||
|
||||
longshot( killId, weapon, meansOfDeath )
|
||||
{
|
||||
self.modifiers["longshot"] = true;
|
||||
|
||||
self thread maps\mp\gametypes\_rank::xpEventPopup( "longshot" );
|
||||
|
||||
self thread maps\mp\gametypes\_rank::giveRankXP( "longshot", undefined, weapon, meansOfDeath );
|
||||
self maps\mp\killstreaks\_killstreaks::giveAdrenaline( "longshot" );
|
||||
self incPlayerStat( "longshots", 1 );
|
||||
self thread maps\mp\_matchdata::logKillEvent( killId, "longshot" );
|
||||
}
|
||||
|
||||
pointblank( killId, weapon, meansOfDeath )
|
||||
{
|
||||
self.modifiers["pointblank"] = true;
|
||||
|
||||
self thread maps\mp\gametypes\_rank::xpEventPopup( "pointblank" );
|
||||
|
||||
self thread maps\mp\gametypes\_rank::giveRankXP( "pointblank", undefined, weapon, meansOfDeath );
|
||||
self maps\mp\killstreaks\_killstreaks::giveAdrenaline( "pointblank" );
|
||||
// self incPlayerStat( "pointblank", 1 );
|
||||
self thread maps\mp\_matchdata::logKillEvent( killId, "pointblank" );
|
||||
}
|
||||
|
||||
|
||||
execution( killId, weapon, meansOfDeath )
|
||||
{
|
||||
self.modifiers["execution"] = true;
|
||||
|
||||
self thread maps\mp\gametypes\_rank::xpEventPopup( "execution" );
|
||||
|
||||
self thread maps\mp\gametypes\_rank::giveRankXP( "execution", undefined, weapon, meansOfDeath );
|
||||
self maps\mp\killstreaks\_killstreaks::giveAdrenaline( "execution" );
|
||||
self thread maps\mp\_matchdata::logKillEvent( killId, "execution" );
|
||||
}
|
||||
|
||||
|
||||
headShot( killId, weapon, meansOfDeath )
|
||||
{
|
||||
self.modifiers["headshot"] = true;
|
||||
|
||||
self thread maps\mp\gametypes\_rank::xpEventPopup( "headshot" );
|
||||
|
||||
self thread maps\mp\gametypes\_rank::giveRankXP( "headshot", undefined, weapon, meansOfDeath );
|
||||
self maps\mp\killstreaks\_killstreaks::giveAdrenaline( "headshot" );
|
||||
self thread maps\mp\_matchdata::logKillEvent( killId, "headshot" );
|
||||
}
|
||||
|
||||
|
||||
avengedPlayer( killId, weapon, meansOfDeath )
|
||||
{
|
||||
self.modifiers["avenger"] = true;
|
||||
|
||||
self thread maps\mp\gametypes\_rank::xpEventPopup( "avenger" );
|
||||
|
||||
self thread maps\mp\gametypes\_rank::giveRankXP( "avenger", undefined, weapon, meansOfDeath );
|
||||
self maps\mp\killstreaks\_killstreaks::giveAdrenaline( "avenger" );
|
||||
self thread maps\mp\_matchdata::logKillEvent( killId, "avenger" );
|
||||
|
||||
self incPlayerStat( "avengekills", 1 );
|
||||
}
|
||||
|
||||
avengedDog( killId, weapon, meansOfDeath )
|
||||
{
|
||||
self thread maps\mp\gametypes\_rank::xpEventPopup( "dog_avenger" );
|
||||
|
||||
self thread maps\mp\gametypes\_rank::giveRankXP( "dog_avenger", undefined, weapon, meansOfDeath );
|
||||
}
|
||||
|
||||
assistedSuicide( killId, weapon, meansOfDeath )
|
||||
{
|
||||
self.modifiers["assistedsuicide"] = true;
|
||||
|
||||
self thread maps\mp\gametypes\_rank::xpEventPopup( "assistedsuicide" );
|
||||
|
||||
self thread maps\mp\gametypes\_rank::giveRankXP( "assistedsuicide", undefined, weapon, meansOfDeath );
|
||||
self maps\mp\killstreaks\_killstreaks::giveAdrenaline( "assistedsuicide" );
|
||||
self thread maps\mp\_matchdata::logKillEvent( killId, "assistedsuicide" );
|
||||
}
|
||||
|
||||
defendedPlayer( killId, weapon, meansOfDeath )
|
||||
{
|
||||
self.modifiers["defender"] = true;
|
||||
|
||||
self thread maps\mp\gametypes\_rank::xpEventPopup( "defender" );
|
||||
|
||||
self thread maps\mp\gametypes\_rank::giveRankXP( "defender", undefined, weapon, meansOfDeath );
|
||||
self maps\mp\killstreaks\_killstreaks::giveAdrenaline( "defender" );
|
||||
self thread maps\mp\_matchdata::logKillEvent( killId, "defender" );
|
||||
|
||||
self incPlayerStat( "rescues", 1 );
|
||||
}
|
||||
|
||||
|
||||
postDeathKill( killId )
|
||||
{
|
||||
self.modifiers[ "posthumous" ] = true;
|
||||
|
||||
self thread maps\mp\gametypes\_rank::xpEventPopup( "posthumous" );
|
||||
|
||||
self thread maps\mp\gametypes\_rank::giveRankXP( "posthumous" );
|
||||
self thread maps\mp\_matchdata::logKillEvent( killId, "posthumous" );
|
||||
}
|
||||
|
||||
postDeathDogKill()
|
||||
{
|
||||
self thread maps\mp\gametypes\_rank::xpEventPopup( "martyrdog" );
|
||||
|
||||
self thread maps\mp\gametypes\_rank::giveRankXP( "martyrdog" );
|
||||
}
|
||||
|
||||
backStab( killId )
|
||||
{
|
||||
self iPrintLnBold( "backstab" );
|
||||
}
|
||||
|
||||
|
||||
revenge( killId )
|
||||
{
|
||||
self.modifiers["revenge"] = true;
|
||||
|
||||
self thread maps\mp\gametypes\_rank::xpEventPopup( "revenge" );
|
||||
|
||||
self thread maps\mp\gametypes\_rank::giveRankXP( "revenge" );
|
||||
self maps\mp\killstreaks\_killstreaks::giveAdrenaline( "revenge" );
|
||||
self thread maps\mp\_matchdata::logKillEvent( killId, "revenge" );
|
||||
|
||||
self incPlayerStat( "revengekills", 1 );
|
||||
}
|
||||
|
||||
|
||||
multiKill( killId, killCount )
|
||||
{
|
||||
assert( killCount > 1 );
|
||||
|
||||
if ( killCount == 2 )
|
||||
{
|
||||
self thread maps\mp\gametypes\_rank::xpEventPopup( "double" );
|
||||
|
||||
self maps\mp\killstreaks\_killstreaks::giveAdrenaline( "double" );
|
||||
}
|
||||
else if ( killCount == 3 )
|
||||
{
|
||||
self thread maps\mp\gametypes\_rank::xpEventPopup( "triple" );
|
||||
|
||||
self maps\mp\killstreaks\_killstreaks::giveAdrenaline( "triple" );
|
||||
thread teamPlayerCardSplash( "callout_3xkill", self );
|
||||
}
|
||||
else
|
||||
{
|
||||
self thread maps\mp\gametypes\_rank::xpEventPopup( "multi" );
|
||||
|
||||
self maps\mp\killstreaks\_killstreaks::giveAdrenaline( "multi" );
|
||||
thread teamPlayerCardSplash( "callout_3xpluskill", self );
|
||||
}
|
||||
|
||||
self thread maps\mp\_matchdata::logMultiKill( killId, killCount );
|
||||
|
||||
// update player multikill record
|
||||
self setPlayerStatIfGreater( "multikill", killCount );
|
||||
|
||||
// update player multikill count
|
||||
self incPlayerStat( "mostmultikills", 1 );
|
||||
}
|
||||
|
||||
|
||||
firstBlood( killId, weapon, meansOfDeath )
|
||||
{
|
||||
self.modifiers["firstblood"] = true;
|
||||
|
||||
self thread maps\mp\gametypes\_rank::xpEventPopup( "firstblood" );
|
||||
|
||||
self thread maps\mp\gametypes\_rank::giveRankXP( "firstblood", undefined, weapon, meansOfDeath );
|
||||
self thread maps\mp\_matchdata::logKillEvent( killId, "firstblood" );
|
||||
self maps\mp\killstreaks\_killstreaks::giveAdrenaline( "firstBlood" );
|
||||
|
||||
thread teamPlayerCardSplash( "callout_firstblood", self );
|
||||
|
||||
self maps\mp\gametypes\_missions::processChallenge( "ch_bornready" );
|
||||
}
|
||||
|
||||
|
||||
winningShot( killId )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
buzzKill( killId, victim, weapon, meansOfDeath )
|
||||
{
|
||||
self.modifiers["buzzkill"] = victim.pers["cur_kill_streak"];
|
||||
|
||||
self thread maps\mp\gametypes\_rank::xpEventPopup( "buzzkill" );
|
||||
|
||||
self thread maps\mp\gametypes\_rank::giveRankXP( "buzzkill", undefined, weapon, meansOfDeath );
|
||||
self maps\mp\killstreaks\_killstreaks::giveAdrenaline( "buzzkill" );
|
||||
self thread maps\mp\_matchdata::logKillEvent( killId, "buzzkill" );
|
||||
}
|
||||
|
||||
|
||||
comeBack( killId, weapon, meansOfDeath )
|
||||
{
|
||||
self.modifiers["comeback"] = true;
|
||||
|
||||
self thread maps\mp\gametypes\_rank::xpEventPopup( "comeback" );
|
||||
|
||||
self thread maps\mp\gametypes\_rank::giveRankXP( "comeback", undefined, weapon, meansOfDeath );
|
||||
self maps\mp\killstreaks\_killstreaks::giveAdrenaline( "comeback" );
|
||||
self thread maps\mp\_matchdata::logKillEvent( killId, "comeback" );
|
||||
|
||||
self incPlayerStat( "comebacks", 1 );
|
||||
}
|
||||
|
||||
|
||||
disconnected()
|
||||
{
|
||||
myGuid = self.guid;
|
||||
|
||||
for ( entry = 0; entry < level.players.size; entry++ )
|
||||
{
|
||||
if ( isDefined( level.players[entry].killedPlayers[myGuid] ) )
|
||||
level.players[entry].killedPlayers[myGuid] = undefined;
|
||||
|
||||
if ( isDefined( level.players[entry].killedPlayersCurrent[myGuid] ) )
|
||||
level.players[entry].killedPlayersCurrent[myGuid] = undefined;
|
||||
|
||||
if ( isDefined( level.players[entry].killedBy[myGuid] ) )
|
||||
level.players[entry].killedBy[myGuid] = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
monitorHealed()
|
||||
{
|
||||
level endon( "end_game" );
|
||||
self endon( "disconnect" );
|
||||
|
||||
for (;;)
|
||||
{
|
||||
self waittill( "healed");
|
||||
self maps\mp\killstreaks\_killstreaks::giveAdrenaline( "healed" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
updateRecentKills( killId )
|
||||
{
|
||||
self endon ( "disconnect" );
|
||||
level endon ( "game_ended" );
|
||||
|
||||
self notify ( "updateRecentKills" );
|
||||
self endon ( "updateRecentKills" );
|
||||
|
||||
self.recentKillCount++;
|
||||
|
||||
wait ( 1.0 );
|
||||
|
||||
if ( self.recentKillCount > 1 )
|
||||
self multiKill( killId, self.recentKillCount );
|
||||
|
||||
self.recentKillCount = 0;
|
||||
}
|
||||
|
||||
monitorCrateJacking()
|
||||
{
|
||||
level endon( "end_game" );
|
||||
self endon( "disconnect" );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
self waittill( "hijacker", crateType, owner );
|
||||
|
||||
self thread maps\mp\gametypes\_rank::xpEventPopup( "hijacker" );
|
||||
self thread maps\mp\gametypes\_rank::giveRankXP( "hijacker" );
|
||||
|
||||
splashName = "hijacked_airdrop";
|
||||
challengeName = "ch_hijacker";
|
||||
|
||||
switch( crateType )
|
||||
{
|
||||
case "sentry":
|
||||
splashName = "hijacked_sentry";
|
||||
break;
|
||||
case "juggernaut":
|
||||
splashName = "hijacked_juggernaut";
|
||||
break;
|
||||
case "maniac":
|
||||
splashname = "hijacked_maniac";
|
||||
break;
|
||||
case "juggernaut_swamp_slasher":
|
||||
splashname = "hijacked_juggernaut_swamp_slasher";
|
||||
break;
|
||||
case "juggernaut_predator":
|
||||
splashname = "hijacked_juggernaut_predator";
|
||||
break;
|
||||
case "juggernaut_death_mariachi":
|
||||
splashname = "hijacked_juggernaut_death_mariachi";
|
||||
break;
|
||||
case "remote_tank":
|
||||
splashName = "hijacked_remote_tank";
|
||||
break;
|
||||
case "mega":
|
||||
case "emergency_airdrop":
|
||||
splashName = "hijacked_emergency_airdrop";
|
||||
challengeName = "ch_newjack";
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if( IsDefined( owner ) )
|
||||
owner maps\mp\gametypes\_hud_message::playerCardSplashNotify( splashName, self );
|
||||
self notify( "process", challengeName );
|
||||
}
|
||||
}
|
||||
|
||||
monitorObjectives()
|
||||
{
|
||||
level endon( "end_game" );
|
||||
self endon( "disconnect" );
|
||||
|
||||
for (;;)
|
||||
{
|
||||
self waittill( "objective", objType );
|
||||
|
||||
switch( objType )
|
||||
{
|
||||
case "captured":
|
||||
self maps\mp\killstreaks\_killstreaks::giveAdrenaline( "capture" );
|
||||
if ( isDefined( self.lastStand ) && self.lastStand )
|
||||
{
|
||||
self thread maps\mp\gametypes\_hud_message::SplashNotifyDelayed( "heroic", maps\mp\gametypes\_rank::getScoreInfoValue( "reviver" ) );
|
||||
self thread maps\mp\gametypes\_rank::giveRankXP( "reviver" );
|
||||
}
|
||||
break;
|
||||
case "plant":
|
||||
self maps\mp\killstreaks\_killstreaks::giveAdrenaline( "plant" );
|
||||
break;
|
||||
case "defuse":
|
||||
self maps\mp\killstreaks\_killstreaks::giveAdrenaline( "defuse" );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// this gets called directly from the game mode gscs instead of leaning on the above notify system
|
||||
giveObjectivePointStreaks()
|
||||
{
|
||||
halfTick_activate = true; // turn this to true in ffotd / patch to activate the objective point system
|
||||
if ( halfTick_activate )
|
||||
{
|
||||
// DM - 5/2/14 - make sure this isn't getting applied to squadmates
|
||||
if( !IsAgent( self ) )
|
||||
{
|
||||
self.pers["objectivePointStreak"]++;
|
||||
// for every two objective points earned, give 1 killstreak tick
|
||||
should_give_point = ( self.pers["objectivePointStreak"] % 2 == 0 );
|
||||
|
||||
if ( should_give_point )
|
||||
{
|
||||
self maps\mp\killstreaks\_killstreaks::giveAdrenaline( "kill" );
|
||||
}
|
||||
// if this results false, set a half killstreak tick in lua
|
||||
// NOTE: this gets overridden in KillstreakHud.lua if the player is using specialist and is maxed to avoid showing the half tick
|
||||
self SetClientOmnvar( "ui_half_tick", !should_give_point );
|
||||
}
|
||||
}
|
||||
}
|
176
maps/mp/_flashgrenades.gsc
Normal file
176
maps/mp/_flashgrenades.gsc
Normal file
@ -0,0 +1,176 @@
|
||||
#include maps\mp\_utility;
|
||||
|
||||
main()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
startMonitoringFlash()
|
||||
{
|
||||
self thread monitorFlash();
|
||||
}
|
||||
|
||||
|
||||
stopMonitoringFlash(disconnected)
|
||||
{
|
||||
self notify("stop_monitoring_flash");
|
||||
}
|
||||
|
||||
|
||||
flashRumbleLoop( duration )
|
||||
{
|
||||
self endon("stop_monitoring_flash");
|
||||
|
||||
self endon("flash_rumble_loop");
|
||||
self notify("flash_rumble_loop");
|
||||
|
||||
goalTime = getTime() + duration * 1000;
|
||||
|
||||
while ( getTime() < goalTime )
|
||||
{
|
||||
self PlayRumbleOnEntity( "damage_heavy" );
|
||||
wait( 0.05 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
monitorFlash()
|
||||
{
|
||||
self endon("disconnect");
|
||||
|
||||
self notify("monitorFlash");
|
||||
self endon("monitorFlash");
|
||||
|
||||
self.flashEndTime = 0;
|
||||
|
||||
durationMultiplier = 1; // how long the flash lasts
|
||||
|
||||
while(1)
|
||||
{
|
||||
self waittill( "flashbang", origin, percent_distance, percent_angle, attacker, teamName, extraDuration );
|
||||
|
||||
if ( !IsAlive( self ) )
|
||||
break;
|
||||
|
||||
if ( IsDefined( self.usingRemote ) )
|
||||
continue;
|
||||
|
||||
// an agent killstreak should not be flashed by its owner
|
||||
if( IsDefined(self.owner) && IsDefined(attacker) && (attacker == self.owner) )
|
||||
continue;
|
||||
|
||||
if( !IsDefined( extraDuration ) )
|
||||
extraDuration = 0;
|
||||
|
||||
hurtattacker = false;
|
||||
hurtvictim = true;
|
||||
|
||||
// with this being the 9-bang we shouldn't consider angle as a variable because of the multiple blasts
|
||||
//if ( percent_angle < 0.25 )
|
||||
// percent_angle = 0.25;
|
||||
//else if ( percent_angle > 0.8 )
|
||||
percent_angle = 1;
|
||||
|
||||
duration = percent_distance * percent_angle * durationMultiplier;
|
||||
duration += extraDuration;
|
||||
|
||||
// MW3 stun resistance perk
|
||||
duration = maps\mp\perks\_perkfunctions::applyStunResistence( duration );
|
||||
|
||||
if ( duration < 0.25 )
|
||||
continue;
|
||||
|
||||
rumbleduration = undefined;
|
||||
if ( duration > 2 )
|
||||
rumbleduration = 0.75;
|
||||
else
|
||||
rumbleduration = 0.25;
|
||||
|
||||
assert(IsDefined(self.team));
|
||||
if (level.teamBased && IsDefined(attacker) && IsDefined(attacker.team) && attacker.team == self.team && attacker != self)
|
||||
{
|
||||
if(level.friendlyfire == 0) // no FF
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if(level.friendlyfire == 1) // FF
|
||||
{
|
||||
}
|
||||
else if(level.friendlyfire == 2) // reflect
|
||||
{
|
||||
duration = duration * .5;
|
||||
rumbleduration = rumbleduration * .5;
|
||||
hurtvictim = false;
|
||||
hurtattacker = true;
|
||||
}
|
||||
else if(level.friendlyfire == 3) // share
|
||||
{
|
||||
duration = duration * .5;
|
||||
rumbleduration = rumbleduration * .5;
|
||||
hurtattacker = true;
|
||||
}
|
||||
}
|
||||
else if( IsDefined(attacker) )
|
||||
{
|
||||
attacker notify( "flash_hit" );
|
||||
if( attacker != self )
|
||||
attacker maps\mp\gametypes\_missions::processChallenge( "ch_indecentexposure" );
|
||||
}
|
||||
|
||||
if ( hurtvictim && IsDefined(self) )
|
||||
{
|
||||
self thread applyFlash(duration, rumbleduration);
|
||||
|
||||
if ( IsDefined(attacker) && attacker != self )
|
||||
{
|
||||
attacker thread maps\mp\gametypes\_damagefeedback::updateDamageFeedback( "flash" );
|
||||
|
||||
// need this here because there are instances where you can not take damage from a flashbang but still get flashed
|
||||
// since you don't take damage the recon perk won't paint you when it should
|
||||
// show the victim on the minimap for N seconds
|
||||
victim = self;
|
||||
if( IsPlayer( attacker ) && attacker IsItemUnlocked( "specialty_paint" ) && attacker _hasPerk( "specialty_paint" ) )
|
||||
{
|
||||
if( !victim maps\mp\perks\_perkfunctions::isPainted() )
|
||||
attacker maps\mp\gametypes\_missions::processChallenge( "ch_paint_pro" );
|
||||
|
||||
victim thread maps\mp\perks\_perkfunctions::setPainted( attacker );
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( hurtattacker && IsDefined(attacker) )
|
||||
{
|
||||
attacker thread applyFlash(duration, rumbleduration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
applyFlash(duration, rumbleduration)
|
||||
{
|
||||
// wait for the highest flash duration this frame,
|
||||
// and apply it in the following frame
|
||||
|
||||
if (!IsDefined(self.flashDuration) || duration > self.flashDuration)
|
||||
self.flashDuration = duration;
|
||||
if (!IsDefined(self.flashRumbleDuration) || rumbleduration > self.flashRumbleDuration)
|
||||
self.flashRumbleDuration = rumbleduration;
|
||||
|
||||
wait .05;
|
||||
|
||||
if (IsDefined(self.flashDuration)) {
|
||||
self shellshock( "flashbang_mp", self.flashDuration ); // TODO: avoid shellshock overlap
|
||||
self.flashEndTime = getTime() + (self.flashDuration * 1000);
|
||||
}
|
||||
if (IsDefined(self.flashRumbleDuration)) {
|
||||
self thread flashRumbleLoop( self.flashRumbleDuration ); //TODO: Non-hacky rumble.
|
||||
}
|
||||
|
||||
self.flashDuration = undefined;
|
||||
self.flashRumbleDuration = undefined;
|
||||
}
|
||||
|
||||
|
||||
isFlashbanged()
|
||||
{
|
||||
return IsDefined( self.flashEndTime ) && gettime() < self.flashEndTime;
|
||||
}
|
272
maps/mp/_fx.gsc
Normal file
272
maps/mp/_fx.gsc
Normal file
@ -0,0 +1,272 @@
|
||||
#include common_scripts\utility;
|
||||
#include common_scripts\_fx;
|
||||
#include common_scripts\_createfx;
|
||||
#include maps\mp\_utility;
|
||||
#include maps\mp\_createfx;
|
||||
|
||||
/*
|
||||
****************************************************************************************************************
|
||||
OneShotfx: Fires an effect once.
|
||||
maps\mp\_fx::OneShotfx( effectname, (x y z), predelay);
|
||||
|
||||
Example:
|
||||
maps\mp\_fx::OneShotfx(level.medFire, // Medium fire effect
|
||||
(-701, -18361, 148), // Origin
|
||||
5); // Wait 5 seconds before doing effect
|
||||
****************************************************************************************************************
|
||||
|
||||
|
||||
****************************************************************************************************************
|
||||
Loopfx: Loops an effect with a waittime.
|
||||
maps\mp\_fx::loopfx( effectname, (x y z), delay_between_shots);
|
||||
|
||||
Example:
|
||||
maps\mp\_fx::loopfx(level.medFire, // Medium fire effect
|
||||
(-701, -18361, 148), // Origin
|
||||
0.3); // Wait 0.3 seconds between shots
|
||||
****************************************************************************************************************
|
||||
|
||||
|
||||
****************************************************************************************************************
|
||||
GunFireLoopfx: Simulates bursts of fire.
|
||||
maps\mp\_fx::gunfireloopfx(fxId, fxPos, shotsMin, shotsMax, shotdelayMin, shotdelayMax, betweenSetsMin, betweenSetsMax)
|
||||
|
||||
Example:
|
||||
maps\mp\_fx::gunfireloopfx (level.medFire, // Medium fire effect
|
||||
(-701, -18361, 148), // Origin
|
||||
10, 15, // 10 to 15 shots
|
||||
0.1, 0.3, // 0.1 to 0.3 seconds between shots
|
||||
2.5, 9); // 2.5 to 9 seconds between sets of shots.
|
||||
****************************************************************************************************************
|
||||
|
||||
****************************************************************************************************************
|
||||
GrenadeExplosionfx: Creates a grenade explosion with view jitter.
|
||||
maps\mp\_fx::GrenadeExplosionfx((x y z));
|
||||
|
||||
Example:
|
||||
maps\mp\_fx::GrenadeExplosionfx( (-701, -18361, 148) ); // origin
|
||||
****************************************************************************************************************
|
||||
*/
|
||||
|
||||
script_print_fx()
|
||||
{
|
||||
if ( ( !isdefined( self.script_fxid ) ) || ( !isdefined( self.script_fxcommand ) ) || ( !isdefined( self.script_delay ) ) )
|
||||
{
|
||||
println( "Effect at origin ", self.origin, " doesn't have script_fxid/script_fxcommand/script_delay" );
|
||||
self delete();
|
||||
return;
|
||||
}
|
||||
|
||||
if ( isdefined( self.target ) )
|
||||
org = getent( self.target ).origin;
|
||||
else
|
||||
org = "undefined";
|
||||
|
||||
// println ("^a Command:", self.script_fxcommand, " Effect:", self.script_fxID, " Delay:", self.script_delay, " ", self.origin);
|
||||
if ( self.script_fxcommand == "OneShotfx" )
|
||||
println( "maps\mp\_fx::OneShotfx(\"" + self.script_fxid + "\", " + self.origin + ", " + self.script_delay + ", " + org + ");" );
|
||||
|
||||
if ( self.script_fxcommand == "loopfx" )
|
||||
println( "maps\mp\_fx::LoopFx(\"" + self.script_fxid + "\", " + self.origin + ", " + self.script_delay + ", " + org + ");" );
|
||||
|
||||
if ( self.script_fxcommand == "loopsound" )
|
||||
println( "maps\mp\_fx::LoopSound(\"" + self.script_fxid + "\", " + self.origin + ", " + self.script_delay + ", " + org + ");" );
|
||||
}
|
||||
|
||||
|
||||
GrenadeExplosionfx( pos )
|
||||
{
|
||||
playfx( level._effect[ "mechanical explosion" ], pos );
|
||||
earthquake( 0.15, 0.5, pos, 250 );
|
||||
// TODO: Add explosion effect and view jitter
|
||||
// println("The script command grenadeExplosionEffect has been removed. maps\\mp\\_fx::GrenadeExplosionfx must be set up to make an effect and jitter the view.");
|
||||
}
|
||||
|
||||
|
||||
soundfx( fxId, fxPos, endonNotify )
|
||||
{
|
||||
org = spawn( "script_origin", ( 0, 0, 0 ) );
|
||||
org.origin = fxPos;
|
||||
org playloopsound( fxId );
|
||||
if ( isdefined( endonNotify ) )
|
||||
org thread soundfxDelete( endonNotify );
|
||||
|
||||
/*
|
||||
ent = level thread createfx_showOrigin ( fxId, fxPos, undefined, undefined, "soundfx" );
|
||||
ent.delay = 0;
|
||||
ent endon ("effect deleted");
|
||||
ent.soundfx = org;
|
||||
*/
|
||||
}
|
||||
|
||||
soundfxDelete( endonNotify )
|
||||
{
|
||||
level waittill( endonNotify );
|
||||
self delete();
|
||||
}
|
||||
|
||||
func_glass_handler()
|
||||
{
|
||||
// FuncGlassIndex [ Index ]
|
||||
// FuncGlassDecals [ Glass Index ] [ Attached SINGLE Decal ]
|
||||
// Funcglass.Targetname == Decal.Script_noteworthy
|
||||
funcglass_indexies = [];
|
||||
funcglass_decals = [];
|
||||
temp_decals = GetEntArray("vfx_custom_glass","targetname");
|
||||
foreach ( decal in temp_decals)
|
||||
{
|
||||
if (IsDefined(decal.script_noteworthy))
|
||||
{
|
||||
attached_glass = GetGlass(decal.script_noteworthy);
|
||||
if (IsDefined (attached_glass))
|
||||
{
|
||||
funcglass_decals[attached_glass] = decal;
|
||||
funcglass_indexies[funcglass_indexies.size] = attached_glass;
|
||||
}
|
||||
}
|
||||
}
|
||||
funcglass_alive_count = funcglass_indexies.size;
|
||||
funcglass_count = funcglass_indexies.size;
|
||||
|
||||
// Run up to 5 times on each frame, avoid too much going on
|
||||
max_iterations = 5;
|
||||
current_index = 0;
|
||||
while(funcglass_alive_count!=0)
|
||||
{
|
||||
max_index = current_index+max_iterations-1;
|
||||
if (max_index > funcglass_count)
|
||||
max_index = funcglass_count;
|
||||
if (current_index ==funcglass_count)
|
||||
current_index = 0;
|
||||
for (; current_index < max_index ; current_index++ )
|
||||
{
|
||||
glass_index = funcglass_indexies[current_index];
|
||||
decal = funcglass_decals[glass_index];
|
||||
|
||||
// Decal is defined, glass isn't destroyed yet (here)
|
||||
if (IsDefined(decal))
|
||||
{
|
||||
// Glass is destroyed in the world
|
||||
if (IsGlassDestroyed(glass_index))
|
||||
{
|
||||
decal delete();
|
||||
funcglass_alive_count--;
|
||||
funcglass_decals[glass_index] = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
wait(.05);
|
||||
}
|
||||
}
|
||||
|
||||
/*rainfx( fxId, fxId2, fxPos )
|
||||
{
|
||||
org = spawn( "script_origin", ( 0, 0, 0 ) );
|
||||
org.origin = fxPos;
|
||||
org thread rainLoop( fxId, fxId2 );
|
||||
|
||||
//ent = level thread createfx_showOrigin( fxId, fxPos, undefined, undefined, "rainfx", undefined, fxId2 );
|
||||
//ent.delay = 0;
|
||||
//ent endon ("effect deleted");
|
||||
//ent.soundfx = org;
|
||||
}
|
||||
|
||||
rainLoop( hardRain, lightRain )
|
||||
{
|
||||
// org playloopsound (fxId);
|
||||
self endon( "death" );
|
||||
blend = spawn( "sound_blend", ( 0.0, 0.0, 0.0 ) );
|
||||
blend.origin = self.origin;
|
||||
self thread blendDelete( blend );
|
||||
|
||||
blend2 = spawn( "sound_blend", ( 0.0, 0.0, 0.0 ) );
|
||||
blend2.origin = self.origin;
|
||||
self thread blendDelete( blend2 );
|
||||
|
||||
|
||||
// lerp of 0 will play _null only
|
||||
blend setSoundBlend( lightRain + "_null", lightRain, 0 );
|
||||
blend2 setSoundBlend( hardRain + "_null", hardRain, 1 );
|
||||
rain = "hard";
|
||||
blendTime = undefined;
|
||||
for ( ;; )
|
||||
{
|
||||
level waittill( "rain_change", change, blendTime );
|
||||
blendTime *= 20;// internal framerate
|
||||
assert( change == "hard" || change == "light" || change == "none" );
|
||||
assert( blendtime > 0 );
|
||||
|
||||
if ( change == "hard" )
|
||||
{
|
||||
if ( rain == "none" )
|
||||
{
|
||||
blendTime *= 0.5;// gotta do 2 blends to go from none to hard
|
||||
for ( i = 0;i < blendtime;i++ )
|
||||
{
|
||||
blend setSoundBlend( lightRain + "_null", lightRain, i / blendtime );
|
||||
wait( 0.05 );
|
||||
}
|
||||
rain = "light";
|
||||
}
|
||||
if ( rain == "light" )
|
||||
{
|
||||
for ( i = 0;i < blendtime;i++ )
|
||||
{
|
||||
blend setSoundBlend( lightRain + "_null", lightRain, 1 - ( i / blendtime ) );
|
||||
blend2 setSoundBlend( hardRain + "_null", hardRain, i / blendtime );
|
||||
wait( 0.05 );
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( change == "none" )
|
||||
{
|
||||
if ( rain == "hard" )
|
||||
{
|
||||
blendTime *= 0.5;// gotta do 2 blends to go from hard to none
|
||||
for ( i = 0;i < blendtime;i++ )
|
||||
{
|
||||
blend setSoundBlend( lightRain + "_null", lightRain, ( i / blendtime ) );
|
||||
blend2 setSoundBlend( hardRain + "_null", hardRain, 1 - ( i / blendtime ) );
|
||||
wait( 0.05 );
|
||||
}
|
||||
rain = "light";
|
||||
}
|
||||
if ( rain == "light" )
|
||||
{
|
||||
for ( i = 0;i < blendtime;i++ )
|
||||
{
|
||||
blend setSoundBlend( lightRain + "_null", lightRain, 1 - ( i / blendtime ) );
|
||||
wait( 0.05 );
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( change == "light" )
|
||||
{
|
||||
if ( rain == "none" )
|
||||
{
|
||||
for ( i = 0;i < blendtime;i++ )
|
||||
{
|
||||
blend setSoundBlend( lightRain + "_null", lightRain, i / blendtime );
|
||||
wait( 0.05 );
|
||||
}
|
||||
}
|
||||
if ( rain == "hard" )
|
||||
{
|
||||
for ( i = 0;i < blendtime;i++ )
|
||||
{
|
||||
blend setSoundBlend( lightRain + "_null", lightRain, i / blendtime );
|
||||
blend2 setSoundBlend( hardRain + "_null", hardRain, 1 - ( i / blendtime ) );
|
||||
wait( 0.05 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rain = change;
|
||||
}
|
||||
}*/
|
||||
|
||||
blendDelete( blend )
|
||||
{
|
||||
self waittill( "death" );
|
||||
blend delete();
|
||||
}
|
50
maps/mp/_global_fx.gsc
Normal file
50
maps/mp/_global_fx.gsc
Normal file
@ -0,0 +1,50 @@
|
||||
#include maps\mp\_global_fx_code;
|
||||
|
||||
// This script automaticly plays a users specified oneshot effect on all prefabs that have the
|
||||
// specified "script_struct" and "targetname" It also excepts angles from the "script_struct"
|
||||
// but will set a default angle of ( 0, 0, 0 ) if none is defined.
|
||||
|
||||
main()
|
||||
{
|
||||
// targetname fxFile
|
||||
global_FX( "ch_streetlight_02_FX_origin" , "fx/misc/lighthaze" );
|
||||
global_FX( "me_streetlight_01_FX_origin" , "fx/misc/lighthaze_bog_a" );
|
||||
global_FX( "ch_street_light_01_on" , "fx/misc/light_glow_white" );
|
||||
global_FX( "lamp_post_globe_on" , "fx/misc/light_glow_white" );
|
||||
global_FX( "highway_lamp_post" , "fx/misc/lighthaze_villassault" );
|
||||
global_FX( "cs_cargoship_spotlight_on_FX_origin" , "fx/misc/lighthaze" );
|
||||
global_FX( "com_tires_burning01_FX_origin" , "fx/fire/tire_fire_med" );
|
||||
global_FX( "icbm_powerlinetower_FX_origin" , "fx/misc/power_tower_light_red_blink" );
|
||||
global_FX( "icbm_mainframe_FX_origin" , "fx/props/icbm_mainframe_lightblink" );
|
||||
global_FX( "lighthaze_oilrig_FX_origin" , "fx/misc/lighthaze_oilrig" );
|
||||
global_FX( "lighthaze_white_FX_origin" , "fx/misc/lighthaze_white" );
|
||||
global_FX( "light_glow_walllight_white_FX_origin", "fx/misc/light_glow_walllight_white" );
|
||||
global_FX( "fluorescent_glow_FX_origin" , "fx/misc/fluorescent_glow" );
|
||||
global_FX( "light_glow_industrial_FX_origin" , "fx/misc/light_glow_industrial" );
|
||||
global_FX( "highrise_blinky_tower" , "fx/misc/power_tower_light_red_blink_large" );
|
||||
global_FX( "light_glow_white_bulb_FX_origin" , "fx/misc/light_glow_white_bulb" );
|
||||
global_FX( "light_glow_white_lamp_FX_origin" , "fx/misc/light_glow_white_lamp" );
|
||||
global_FX( "mp_snow_light_on" , "vfx/ambient/lights/vfx_bulb_prismatic_mp_snow" );
|
||||
global_FX( "vfx_fog_water_mp" , "vfx/ambient/atmospheric/vfx_fog_water_mp" );
|
||||
global_FX( "vfx_mp_handflare" , "vfx/ambient/props/vfx_handflare_sov" );
|
||||
global_FX( "vfx_mp_sov_ceiling_light" , "vfx/ambient/lights/vfx_glow_ceil_light_sov" );
|
||||
|
||||
|
||||
|
||||
|
||||
// targetname fxFile delay
|
||||
global_FX( "light_red_steady_FX_origin" , "fx/misc/tower_light_red_steady" , -2 );
|
||||
global_FX( "light_blue_steady_FX_origin" , "fx/misc/tower_light_blue_steady" , -2 );
|
||||
global_FX( "light_orange_steady_FX_origin" , "fx/misc/tower_light_orange_steady" , -2 );
|
||||
global_FX( "glow_stick_pile_FX_origin" , "fx/misc/glow_stick_glow_pile" , -2 );
|
||||
global_FX( "glow_stick_orange_pile_FX_origin", "fx/misc/glow_stick_glow_pile_orange" , -2 );
|
||||
global_FX( "light_pulse_red_FX_origin" , "fx/misc/light_glow_red_generic_pulse" , -2 );
|
||||
global_FX( "light_pulse_red_FX_origin" , "fx/misc/light_glow_red_generic_pulse" , -2 );
|
||||
global_FX( "light_pulse_orange_FX_origin" , "fx/misc/light_glow_orange_generic_pulse", -2 );
|
||||
global_FX( "light_red_blink_FX_origin" , "fx/misc/power_tower_light_red_blink" , -2 );
|
||||
|
||||
// targetname fxFile delay fxName soundalias
|
||||
global_FX( "flare_ambient_FX_origin" , "fx/misc/flare_ambient" , undefined, undefined, "emt_road_flare_burn" );
|
||||
global_FX( "me_dumpster_fire_FX_origin", "fx/fire/firelp_med_pm" , undefined, undefined, "fire_dumpster_medium" );
|
||||
global_FX( "barrel_fireFX_origin" , "fx/fire/firelp_barrel_pm", undefined, undefined, "fire_barrel_temp" );
|
||||
}
|
35
maps/mp/_global_fx_code.gsc
Normal file
35
maps/mp/_global_fx_code.gsc
Normal file
@ -0,0 +1,35 @@
|
||||
#include common_scripts\utility;
|
||||
|
||||
global_FX( targetname, fxFile, delay, fxName, soundalias )
|
||||
{
|
||||
// script_structs
|
||||
ents = getstructarray( targetname, "targetname" );
|
||||
if ( ents.size <= 0 )
|
||||
return;
|
||||
|
||||
if ( ! IsDefined( delay ) )
|
||||
delay = RandomFloatRange( -20, -15 );
|
||||
|
||||
if ( !IsDefined( fxName ) )
|
||||
fxName = fxFile;
|
||||
|
||||
foreach ( fxEnt in ents )
|
||||
{
|
||||
if ( !IsDefined( level._effect ) )
|
||||
level._effect = [];
|
||||
if ( !IsDefined( level._effect[ fxName ] ) )
|
||||
level._effect[ fxName ] = LoadFX( fxFile );
|
||||
|
||||
// default effect angles if they dont exist
|
||||
if ( !IsDefined( fxEnt.angles ) )
|
||||
fxEnt.angles = ( 0, 0, 0 );
|
||||
|
||||
ent = createOneshotEffect( fxName );
|
||||
ent.v[ "origin" ] = ( fxEnt.origin );
|
||||
ent.v[ "angles" ] = ( fxEnt.angles );
|
||||
ent.v[ "fxid" ] = fxName;
|
||||
ent.v[ "delay" ] = delay;
|
||||
if ( IsDefined( soundalias ) )
|
||||
ent.v[ "soundalias" ] = soundalias;
|
||||
}
|
||||
}
|
16
maps/mp/_highlights.gsc
Normal file
16
maps/mp/_highlights.gsc
Normal file
@ -0,0 +1,16 @@
|
||||
#include maps\mp\_utility;
|
||||
#include common_scripts\utility;
|
||||
|
||||
giveHighlight( ref, value )
|
||||
{
|
||||
highlightCount = getClientMatchData( "highlightCount" );
|
||||
if ( highlightCount < 18 ) // must match MaxHighlights in clientmatchdata definition
|
||||
{
|
||||
setClientMatchData( "highlights", highlightCount, "award", ref );
|
||||
setClientMatchData( "highlights", highlightCount, "clientId", self.clientMatchDataId );
|
||||
setClientMatchData( "highlights", highlightCount, "value", value );
|
||||
|
||||
highlightCount++;
|
||||
setClientMatchData( "highlightCount", highlightCount );
|
||||
}
|
||||
}
|
522
maps/mp/_javelin.gsc
Normal file
522
maps/mp/_javelin.gsc
Normal file
@ -0,0 +1,522 @@
|
||||
#include maps\mp\_utility;
|
||||
#include common_scripts\utility;
|
||||
|
||||
InitJavelinUsage()
|
||||
{
|
||||
self.javelinStage = undefined;
|
||||
self.javelinPoints = undefined;
|
||||
self.javelinNormals = undefined;
|
||||
self.javelinLockMisses = undefined;
|
||||
self.javelinTargetPoint = undefined;
|
||||
self.javelinTargetNormal = undefined;
|
||||
self.javelinLockStartTime = undefined;
|
||||
}
|
||||
|
||||
|
||||
ResetJavelinLocking()
|
||||
{
|
||||
if ( !IsDefined( self.javelinUseEntered ) )
|
||||
return;
|
||||
self.javelinUseEntered = undefined;
|
||||
|
||||
self notify( "stop_lockon_sound" );
|
||||
|
||||
self WeaponLockFree();
|
||||
self WeaponLockTargetTooClose( false );
|
||||
self WeaponLockNoClearance( false );
|
||||
self.currentlyLocking = false;
|
||||
self.currentlyLocked = false;
|
||||
self.javelinTarget = undefined;
|
||||
|
||||
self StopLocalSound( "javelin_clu_lock" );
|
||||
self StopLocalSound( "javelin_clu_aquiring_lock" );
|
||||
|
||||
InitJavelinUsage();
|
||||
}
|
||||
|
||||
|
||||
/#
|
||||
DrawStar( point, color )
|
||||
{
|
||||
Line( point + (10,0,0), point - (10,0,0), color );
|
||||
Line( point + (0,10,0), point - (0,10,0), color );
|
||||
Line( point + (0,0,10), point - (0,0,10), color );
|
||||
}
|
||||
#/
|
||||
|
||||
|
||||
EyeTraceForward()
|
||||
{
|
||||
origin = self GetEye();
|
||||
angles = self GetPlayerAngles();
|
||||
forward = AnglesToForward( angles );
|
||||
endpoint = origin + forward * 15000;
|
||||
|
||||
res = BulletTrace( origin, endpoint, false, undefined );
|
||||
|
||||
if ( res["surfacetype"] == "none" )
|
||||
return undefined;
|
||||
if ( res["surfacetype"] == "default" )
|
||||
return undefined;
|
||||
|
||||
ent = res["entity"];
|
||||
if ( IsDefined( ent ) )
|
||||
{
|
||||
if ( ent == level.ac130.planeModel )
|
||||
return undefined;
|
||||
}
|
||||
|
||||
results = [];
|
||||
results[0] = res["position"];
|
||||
results[1] = res["normal"];
|
||||
return results;
|
||||
}
|
||||
|
||||
|
||||
LockMissesReset()
|
||||
{
|
||||
self.javelinLockMisses = undefined;
|
||||
}
|
||||
|
||||
|
||||
LockMissesIncr()
|
||||
{
|
||||
if ( !IsDefined( self.javelinLockMisses ) )
|
||||
self.javelinLockMisses = 1;
|
||||
else
|
||||
self.javelinLockMisses++;
|
||||
}
|
||||
|
||||
|
||||
LockMissesPassedThreshold()
|
||||
{
|
||||
MAX_MISSES = 4;
|
||||
|
||||
if ( IsDefined( self.javelinLockMisses ) && (self.javelinLockMisses >= MAX_MISSES) )
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
TargetPointTooClose( targetPoint )
|
||||
{
|
||||
MY_MIN_DIST = 1100;
|
||||
|
||||
dist = Distance( self.origin, targetPoint );
|
||||
if ( dist < MY_MIN_DIST )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
LoopLocalSeekSound( alias, interval )
|
||||
{
|
||||
self endon ( "death" );
|
||||
self endon ( "disconnect" );
|
||||
self endon ( "stop_lockon_sound" );
|
||||
|
||||
for ( ;; )
|
||||
{
|
||||
self PlayLocalSound( alias );
|
||||
wait interval;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TopAttackPasses( targPoint, targNormal )
|
||||
{
|
||||
origin = targPoint + (targNormal * 10.0);
|
||||
endpoint = origin + (0,0,2000);
|
||||
|
||||
result = BulletTrace( origin, endpoint, false, undefined );
|
||||
|
||||
if ( SightTracePassed( origin, endpoint, false, undefined ) )
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
JavelinUsageLoop()
|
||||
{
|
||||
self endon("death");
|
||||
self endon("disconnect");
|
||||
self endon("faux_spawn");
|
||||
|
||||
LOCK_LENGTH = 1150;
|
||||
GATHER_DELAY = 25;
|
||||
ADS_DELAY = 100;
|
||||
MAX_POINT_PEER_DIST = 400;
|
||||
POINTS_NEEDED_TO_START_LOCK = 12;
|
||||
|
||||
lastGatherTime = 0;
|
||||
lastOutOfADS = 0;
|
||||
self.javelinTarget = undefined;
|
||||
|
||||
InitJavelinUsage();
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
wait 0.05;
|
||||
|
||||
weapon = self getCurrentWeapon();
|
||||
if ( (IsBot(self) && (weapon != "javelin_mp")) || !isSubStr( weapon, "javelin" ) || self isEMPed() )
|
||||
{
|
||||
if ( IsDefined( self.javelinUseEntered ) )
|
||||
ResetJavelinLocking();
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( self PlayerADS() < 0.95 )
|
||||
{
|
||||
lastOutOfADS = GetTime();
|
||||
|
||||
ResetJavelinLocking();
|
||||
continue;
|
||||
}
|
||||
|
||||
debugDraw = false;
|
||||
if ( GetDVar( "missileDebugDraw" ) == "1" )
|
||||
debugDraw = true;
|
||||
|
||||
debugText = false;
|
||||
if ( GetDVar( "missileDebugText" ) == "1" )
|
||||
debugText = true;
|
||||
|
||||
self.javelinUseEntered = true;
|
||||
if ( !IsDefined( self.javelinStage ) )
|
||||
self.javelinStage = 1;
|
||||
|
||||
if ( self.javelinStage == 1 ) // SCANNING: try to find a good point to lock to
|
||||
{
|
||||
|
||||
targets = maps\mp\gametypes\_weapons::lockOnLaunchers_getTargetArray();
|
||||
if ( targets.size != 0 )
|
||||
{
|
||||
|
||||
targetsInReticle = [];
|
||||
foreach ( target in targets )
|
||||
{
|
||||
insideReticle = self WorldPointInReticle_Circle( target.origin, 65, 40 );
|
||||
if ( insideReticle )
|
||||
targetsInReticle[targetsInReticle.size] = target;
|
||||
}
|
||||
|
||||
if ( targetsInReticle.size != 0 )
|
||||
{
|
||||
|
||||
sortedTargets = SortByDistance( targetsInReticle, self.origin );
|
||||
|
||||
if ( !( self VehicleLockSightTest( sortedTargets[0] ) ) )
|
||||
continue;
|
||||
|
||||
if ( debugText )
|
||||
PrintLn( "Javelin found a vehicle target to lock to." );
|
||||
|
||||
self.javelinTarget = sortedTargets[0];
|
||||
|
||||
if ( !isDefined( self.javelinLockStartTime ) )
|
||||
self.javelinLockStartTime = GetTime();
|
||||
|
||||
self.javelinStage = 2;
|
||||
self.javelinLostSightlineTime = 0;
|
||||
|
||||
self javelinLockVehicle( LOCK_LENGTH );
|
||||
self.javelinStage = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( LockMissesPassedThreshold() )
|
||||
{
|
||||
ResetJavelinLocking();
|
||||
continue;
|
||||
}
|
||||
|
||||
timePassed = GetTime() - lastOutOfADS;
|
||||
if ( timePassed < ADS_DELAY )
|
||||
continue;
|
||||
|
||||
/#
|
||||
if ( debugDraw && IsDefined( self.javelinPoints ) )
|
||||
{
|
||||
foreach( javPoint in self.javelinPoints )
|
||||
DrawStar( javPoint, (0.8, 1.0, 0.8) );
|
||||
DrawStar( self.javelinPoints[self.javelinPoints.size - 1], (1, 1, 0.2) );
|
||||
DrawStar( AveragePoint( self.javelinPoints ), (0.2, 0.2, 1) );
|
||||
}
|
||||
#/
|
||||
|
||||
timePassed = GetTime() - lastGatherTime;
|
||||
if ( timePassed < GATHER_DELAY )
|
||||
continue;
|
||||
lastGatherTime = GetTime();
|
||||
|
||||
traceRes = (self EyeTraceForward());
|
||||
if ( !IsDefined( traceRes ) )
|
||||
{
|
||||
self LockMissesIncr();
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( self TargetPointTooClose( traceRes[0] ) )
|
||||
{
|
||||
self WeaponLockTargetTooClose( true );
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
self WeaponLockTargetTooClose( false );
|
||||
}
|
||||
|
||||
// make sure we haven't strayed too far
|
||||
if ( IsDefined( self.javelinPoints ) )
|
||||
{
|
||||
prevAvgPoint = AveragePoint( self.javelinPoints );
|
||||
dist = Distance( prevAvgPoint, traceRes[0] );
|
||||
//PrintLn( "[", self.javelinPoints.size, "] - Dist: ", dist );
|
||||
|
||||
if ( dist > MAX_POINT_PEER_DIST )
|
||||
{
|
||||
LockMissesIncr();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self.javelinPoints = [];
|
||||
self.javelinNormals = [];
|
||||
}
|
||||
|
||||
self.javelinPoints[self.javelinPoints.size] = traceRes[0];
|
||||
self.javelinNormals[self.javelinNormals.size] = traceRes[1];
|
||||
|
||||
self LockMissesReset();
|
||||
if ( self.javelinPoints.size < POINTS_NEEDED_TO_START_LOCK )
|
||||
continue;
|
||||
|
||||
// Go to stage 2:
|
||||
self.javelinTargetPoint = AveragePoint( self.javelinPoints );;
|
||||
self.javelinTargetNormal = AverageNormal( self.javelinNormals );;
|
||||
self.javelinLockMisses = undefined;
|
||||
self.javelinPoints = undefined;
|
||||
self.javelinNormals = undefined;
|
||||
self.javelinLockStartTime = GetTime();
|
||||
|
||||
self WeaponLockStart( self.javelinTargetPoint );
|
||||
self thread LoopLocalSeekSound( "javelin_clu_aquiring_lock", 0.6 );
|
||||
|
||||
self.javelinStage = 2;
|
||||
}
|
||||
|
||||
if ( self.javelinStage == 2 ) // LOCKING: complete lockon to point
|
||||
{
|
||||
/#
|
||||
if ( debugDraw )
|
||||
DrawStar( self.javelinTargetPoint, (0.5, 1.0, 0.6) );
|
||||
#/
|
||||
|
||||
insideReticle = self WorldPointInReticle_Circle( self.javelinTargetPoint, 65, 45 );
|
||||
if ( !insideReticle )
|
||||
{
|
||||
ResetJavelinLocking();
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( self TargetPointTooClose( self.javelinTargetPoint ) )
|
||||
self WeaponLockTargetTooClose( true );
|
||||
else
|
||||
self WeaponLockTargetTooClose( false );
|
||||
|
||||
timePassed = getTime() - self.javelinLockStartTime;
|
||||
//PrintLn( "Locking [", timePassed, "]..." );
|
||||
if ( timePassed < LOCK_LENGTH )
|
||||
continue;
|
||||
|
||||
self WeaponLockFinalize( self.javelinTargetPoint, (0,0,0), true );
|
||||
self notify( "stop_lockon_sound" );
|
||||
self PlayLocalSound( "javelin_clu_lock" );
|
||||
self.javelinStage = 3;
|
||||
}
|
||||
|
||||
if ( self.javelinStage == 3 ) // LOCKED: try and hold it
|
||||
{
|
||||
/#
|
||||
if ( debugDraw )
|
||||
DrawStar( self.javelinTargetPoint, (0.1, 0.15, 1.0) );
|
||||
#/
|
||||
|
||||
insideReticle = self WorldPointInReticle_Circle( self.javelinTargetPoint, 65, 45 );
|
||||
if ( !insideReticle )
|
||||
{
|
||||
ResetJavelinLocking();
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( self TargetPointTooClose( self.javelinTargetPoint ) )
|
||||
self WeaponLockTargetTooClose( true );
|
||||
else
|
||||
self WeaponLockTargetTooClose( false );
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DebugSightLine( start, end, passed )
|
||||
{
|
||||
/#
|
||||
if ( GetDVar( "missileDebugDraw" ) != "1" )
|
||||
return;
|
||||
|
||||
if ( passed )
|
||||
color = ( 0.3, 1.0, 0.3 );
|
||||
else
|
||||
color = ( 1.0, 0.2, 0.2 );
|
||||
|
||||
MY_OFFSET = ( 0, 0, 5 );
|
||||
|
||||
Line( start + MY_OFFSET, end, color );
|
||||
#/
|
||||
}
|
||||
|
||||
VehicleLockSightTest( target )
|
||||
{
|
||||
eyePos = self GetEye();
|
||||
|
||||
center = target GetPointInBounds( 0, 0, 0 );
|
||||
passed = SightTracePassed( eyePos, center, false, target );
|
||||
DebugSightLine( eyePos, center, passed );
|
||||
if ( passed )
|
||||
return true;
|
||||
|
||||
front = target GetPointInBounds( 1, 0, 0 );
|
||||
passed = SightTracePassed( eyePos, front, false, target );
|
||||
DebugSightLine( eyePos, front, passed );
|
||||
if ( passed )
|
||||
return true;
|
||||
|
||||
back = target GetPointInBounds( -1, 0, 0 );
|
||||
passed = SightTracePassed( eyePos, back, false, target );
|
||||
DebugSightLine( eyePos, back, passed );
|
||||
if ( passed )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
javelinLockVehicle( lockLength )
|
||||
{
|
||||
if ( self.javelinStage == 2 ) // locking on to a target
|
||||
{
|
||||
self WeaponLockStart( self.javelinTarget );
|
||||
|
||||
if ( !(self StillValidJavelinLock( self.javelinTarget ) ) )
|
||||
{
|
||||
ResetJavelinLocking();
|
||||
self.javelinLockStartTime = undefined;
|
||||
return;
|
||||
}
|
||||
|
||||
passed = SoftSightTest();
|
||||
if ( !passed )
|
||||
{
|
||||
self.javelinLockStartTime = undefined;
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !isDefined( self.currentlyLocking ) || !self.currentlyLocking )
|
||||
{
|
||||
self thread LoopLocalSeekSound( "javelin_clu_aquiring_lock", 0.6 );
|
||||
self.currentlyLocking = true;
|
||||
}
|
||||
|
||||
timePassed = getTime() - self.javelinLockStartTime;
|
||||
|
||||
if( self _hasPerk( "specialty_fasterlockon" ) )
|
||||
{
|
||||
if( timePassed < ( lockLength * 0.5 ) )
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( timePassed < lockLength )
|
||||
return;
|
||||
}
|
||||
|
||||
//strangely buggy with the moving target...
|
||||
//javTarg = eyeTraceForward();
|
||||
//if ( !isDefined( javTarg ) )
|
||||
// return;
|
||||
|
||||
//topAttack = TopAttackPasses( javTarg[0], javTarg[1] );
|
||||
|
||||
if ( isPlayer( self.javelinTarget ) )
|
||||
self WeaponLockFinalize( self.javelinTarget, (0,0,64), false );
|
||||
else
|
||||
self WeaponLockFinalize( self.javelinTarget, (0,0,0), false );
|
||||
|
||||
|
||||
self notify( "stop_lockon_sound" );
|
||||
|
||||
if ( !isDefined( self.currentlyLocked ) || !self.currentlyLocked )
|
||||
{
|
||||
self PlayLocalSound( "javelin_clu_lock" );
|
||||
self.currentlyLocked = true;
|
||||
}
|
||||
|
||||
self.javelinStage = 3;
|
||||
}
|
||||
|
||||
if ( self.javelinStage == 3 ) // target locked
|
||||
{
|
||||
passed = SoftSightTest();
|
||||
if ( !passed )
|
||||
return;
|
||||
|
||||
if ( !(self StillValidJavelinLock( self.javelinTarget ) ) )
|
||||
{
|
||||
ResetJavelinLocking();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
StillValidJavelinLock( ent )
|
||||
{
|
||||
assert( IsDefined( self ) );
|
||||
|
||||
if ( !IsDefined( ent ) )
|
||||
return false;
|
||||
if ( !(self WorldPointInReticle_Circle( ent.origin, 65, 85 )) )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
SoftSightTest()
|
||||
{
|
||||
LOST_SIGHT_LIMIT = 500;
|
||||
|
||||
if ( self VehicleLockSightTest( self.javelinTarget ) )
|
||||
{
|
||||
self.javelinLostSightlineTime = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( self.javelinLostSightlineTime == 0 )
|
||||
self.javelinLostSightlineTime = getTime();
|
||||
|
||||
timePassed = GetTime() - self.javelinLostSightlineTime;
|
||||
|
||||
if ( timePassed >= LOST_SIGHT_LIMIT )
|
||||
{
|
||||
ResetJavelinLocking();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
674
maps/mp/_laserguidedlauncher.gsc
Normal file
674
maps/mp/_laserguidedlauncher.gsc
Normal file
@ -0,0 +1,674 @@
|
||||
#include maps\mp\_utility;
|
||||
#include common_scripts\utility;
|
||||
|
||||
// -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. //
|
||||
// Init
|
||||
// -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. //
|
||||
|
||||
CONST_LOCK_ON_TIME_MSEC = 1500;
|
||||
|
||||
LGM_init( fxSplit, fxHoming )
|
||||
{
|
||||
level._effect[ "laser_guided_launcher_missile_split" ] = LoadFX( fxSplit );
|
||||
level._effect[ "laser_guided_launcher_missile_spawn_homing" ] = LoadFX( fxHoming );
|
||||
}
|
||||
|
||||
// -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. //
|
||||
// Monitor Player Weapon for Use as CAC Launcher
|
||||
// -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. //
|
||||
|
||||
// Function to use if you want to have a laser guided launcher as
|
||||
// a launcher in CAC. Just thread this watch off in _weapons.gsc::init()
|
||||
LGM_update_launcherUsage( weaponName, weaponNameHoming )
|
||||
{
|
||||
self endon( "death" );
|
||||
self endon( "disconnect" );
|
||||
self endon( "faux_spawn" );
|
||||
|
||||
self thread LGM_monitorLaser();
|
||||
|
||||
weaponCurr = self GetCurrentWeapon();
|
||||
while ( 1 )
|
||||
{
|
||||
while ( weaponCurr != weaponName )
|
||||
{
|
||||
self waittill( "weapon_change", weaponCurr );
|
||||
}
|
||||
|
||||
self childthread LGM_firing_monitorMissileFire( weaponCurr, weaponNameHoming );
|
||||
|
||||
self waittill( "weapon_change", weaponCurr );
|
||||
|
||||
self LGM_firing_endMissileFire();
|
||||
}
|
||||
}
|
||||
|
||||
LGM_monitorLaser()
|
||||
{
|
||||
self endon( "LGM_player_endMonitorFire" );
|
||||
|
||||
self waittill_any( "death", "disconnect" );
|
||||
|
||||
if ( IsDefined( self ) )
|
||||
{
|
||||
self LGM_disableLaser();
|
||||
}
|
||||
}
|
||||
|
||||
// -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. //
|
||||
// Monitor Player Firing
|
||||
// -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. //
|
||||
|
||||
LASER_GUIDED_MISSILE_LASER_TRACE_CLOSE_TIME_MSEC = 400; // Time after firing that the trace distance is short. This forces the missiles forward.
|
||||
LASER_GUIDED_MISSILE_LASER_TRACE_LENGTH_SHORT = 800;
|
||||
LASER_GUIDED_MISSILE_LASER_TRACE_LENGTH = 8000;
|
||||
LASER_GUIDED_MISSILE_DELAY_CHILDREN_SPAWN = 0.35;
|
||||
LASER_GUIDED_MISSILE_DELAY_CHILDREN_TRACK = 0.1;
|
||||
LASER_GUIDED_MISSILE_PITCH_CHILDREN_DIVERGE = 20;
|
||||
LASER_GUIDED_MISSILE_YAW_CHILDREN_DIVERGE = 20;
|
||||
|
||||
LGM_firing_endMissileFire()
|
||||
{
|
||||
self LGM_disableLaser();
|
||||
|
||||
self notify( "LGM_player_endMonitorFire" );
|
||||
}
|
||||
|
||||
LGM_firing_monitorMissileFire( weaponName, weaponNameChild, weaponNameHoming )
|
||||
{
|
||||
self endon( "LGM_player_endMonitorFire" );
|
||||
|
||||
self LGM_enableLaser();
|
||||
|
||||
entTarget = undefined;
|
||||
|
||||
while ( 1 )
|
||||
{
|
||||
missile = undefined;
|
||||
self waittill( "missile_fire", missile, weaponNotified );
|
||||
|
||||
// Ignore missiles fired by script
|
||||
if ( IsDefined( missile.isMagicBullet ) && missile.isMagicBullet )
|
||||
continue;
|
||||
|
||||
// The hind magic bullets missiles on behalf of the player, so ignore without assert.
|
||||
if ( weaponNotified != weaponName )
|
||||
continue;
|
||||
|
||||
if ( !IsDefined( entTarget ) )
|
||||
{
|
||||
entTarget = LGM_requestMissileGuideEnt( self );
|
||||
}
|
||||
|
||||
self thread LGM_firing_delaySpawnChildren( weaponName, weaponNameChild, weaponNameHoming, LASER_GUIDED_MISSILE_DELAY_CHILDREN_SPAWN, LASER_GUIDED_MISSILE_DELAY_CHILDREN_TRACK, missile, entTarget );
|
||||
}
|
||||
}
|
||||
|
||||
LGM_firing_delaySpawnChildren( weaponName, weaponNameChild, weaponNameHoming, delaySpawn, delayTrack, missile, entTarget )
|
||||
{
|
||||
// If the player fires rapidly, cancel the previous missile spawn
|
||||
self notify( "monitor_laserGuidedMissile_delaySpawnChildren" );
|
||||
self endon( "monitor_laserGuidedMissile_delaySpawnChildren" );
|
||||
|
||||
// If the player dies this function needs to be cleared up immediately. This is because
|
||||
// the target ent gets scrubbed on death so any created missiles may have been
|
||||
// removed from the array
|
||||
self endon( "death" );
|
||||
self endon( "LGM_player_endMonitorFire" );
|
||||
|
||||
// Only let one set of rockets be guided by releasing
|
||||
// any previously fired rockets
|
||||
LGM_missilesNotifyAndRelease( entTarget );
|
||||
|
||||
wait( delaySpawn );
|
||||
|
||||
// Exit if missile has blown up
|
||||
if ( !IsValidMissile( missile ) )
|
||||
return;
|
||||
|
||||
missileOrigin = missile.origin;
|
||||
missileFwd = AnglesToForward( missile.angles );
|
||||
missileUp = AnglesToUp( missile.angles );
|
||||
missileRight = AnglesToRight( missile.angles );
|
||||
|
||||
missile Delete();
|
||||
|
||||
// Spawn missile break apart fx
|
||||
PlayFX( level._effect[ "laser_guided_launcher_missile_split" ], missileOrigin, missileFwd, missileUp );
|
||||
|
||||
missiles = [];
|
||||
|
||||
for ( i = 0; i < 2; i++ )
|
||||
{
|
||||
pitch = LASER_GUIDED_MISSILE_PITCH_CHILDREN_DIVERGE; // Default Upwards Pitch: Forward and Up n degrees
|
||||
yaw = 0;
|
||||
|
||||
if ( i == 0 ) // Right Missile: Up 45 degrees and then 45 degrees around Z
|
||||
{
|
||||
yaw = LASER_GUIDED_MISSILE_YAW_CHILDREN_DIVERGE;
|
||||
}
|
||||
else if ( i == 1 ) // Left Missile: Up 45 degrees and then -45 degrees around Z
|
||||
{
|
||||
yaw = -1 * LASER_GUIDED_MISSILE_YAW_CHILDREN_DIVERGE;
|
||||
}
|
||||
else if ( i == 2 )// Middle Missile: Already rotated up
|
||||
{
|
||||
// All done
|
||||
}
|
||||
|
||||
childMissileFwd = RotatePointAroundVector( missileRight, missileFwd, pitch );
|
||||
childMissileFwd = RotatePointAroundVector( missileUp, childMissileFwd, yaw );
|
||||
|
||||
missileChild = MagicBullet( weaponNameChild, missileOrigin, missileOrigin + childMissileFwd * 180, self );
|
||||
missileChild.isMagicBullet = true;
|
||||
missiles[ missiles.size ] = missileChild;
|
||||
|
||||
// Don't spawn missiles on the same frame
|
||||
waitframe();
|
||||
}
|
||||
|
||||
wait( delayTrack );
|
||||
|
||||
missiles = LGM_removeInvalidMissiles( missiles );
|
||||
|
||||
if ( missiles.size > 0 )
|
||||
{
|
||||
foreach ( missChild in missiles )
|
||||
{
|
||||
entTarget.missilesChasing[ entTarget.missilesChasing.size ] = missChild;
|
||||
missChild Missile_SetTargetEnt( entTarget );
|
||||
|
||||
self thread LGM_onMissileNotifies( entTarget, missChild );
|
||||
}
|
||||
|
||||
self thread LGM_firing_monitorPlayerAim( entTarget, weaponNameHoming );
|
||||
}
|
||||
}
|
||||
|
||||
LGM_onMissileNotifies( entTarget, missile )
|
||||
{
|
||||
missile waittill_any( "death", "missile_pairedWithFlare", "LGM_missile_abandoned" );
|
||||
|
||||
if ( IsDefined( entTarget.missilesChasing ) && entTarget.missilesChasing.size > 0 )
|
||||
{
|
||||
entTarget.missilesChasing = array_remove( entTarget.missilesChasing, missile );
|
||||
entTarget.missilesChasing = LGM_removeInvalidMissiles( entTarget.missilesChasing );
|
||||
}
|
||||
|
||||
if ( !IsDefined( entTarget.missilesChasing ) || entTarget.missilesChasing.size == 0 )
|
||||
{
|
||||
self notify( "LGM_player_allMissilesDestroyed" );
|
||||
}
|
||||
}
|
||||
|
||||
// Handles initial lock visual / audio fx
|
||||
|
||||
LGM_firing_monitorPlayerAim( entTarget, weaponNameHoming )
|
||||
{
|
||||
self notify( "LGM_player_newMissilesFired" );
|
||||
self endon( "LGM_player_newMissilesFired" );
|
||||
|
||||
self endon( "LGM_player_allMissilesDestroyed" );
|
||||
self endon( "LGM_player_endMonitorFire" );
|
||||
self endon( "death" );
|
||||
self endon( "disconnect" );
|
||||
|
||||
originGoal = undefined;
|
||||
targetVeh = undefined;
|
||||
lockOnTime = undefined;
|
||||
lockedOn = false;
|
||||
|
||||
timeTraceFar = GetTime() + LASER_GUIDED_MISSILE_LASER_TRACE_CLOSE_TIME_MSEC;
|
||||
|
||||
while ( IsDefined( entTarget.missilesChasing ) && entTarget.missilesChasing.size > 0 )
|
||||
{
|
||||
targetLook = self LGM_targetFind();
|
||||
|
||||
if ( !IsDefined( targetLook ) )
|
||||
{
|
||||
// If there was a previous target, clear that target and
|
||||
// notify systmes watching the missiles that the
|
||||
// target has changed
|
||||
if ( IsDefined( targetVeh ) )
|
||||
{
|
||||
self notify( "LGM_player_targetLost" );
|
||||
targetVeh = undefined;
|
||||
|
||||
foreach ( missile in entTarget.missilesChasing )
|
||||
{
|
||||
missile notify( "missile_targetChanged" );
|
||||
}
|
||||
}
|
||||
|
||||
lockOnTime = undefined;
|
||||
lockedOn = false;
|
||||
|
||||
traceDist = ter_op( GetTime() > timeTraceFar, LASER_GUIDED_MISSILE_LASER_TRACE_LENGTH, LASER_GUIDED_MISSILE_LASER_TRACE_LENGTH_SHORT );
|
||||
viewDir = AnglesToForward( self GetPlayerAngles() );
|
||||
startPos = self GetEye() + viewDir * 12;
|
||||
trace = BulletTrace( startPos, startPos + viewDir * traceDist, true, self, false, false, false );
|
||||
|
||||
originGoal = trace[ "position" ];
|
||||
}
|
||||
else
|
||||
{
|
||||
originGoal = targetLook.origin;
|
||||
|
||||
newTarget = !IsDefined( targetVeh ) || targetLook != targetVeh;
|
||||
targetVeh = targetLook;
|
||||
|
||||
if ( newTarget || !IsDefined( lockOnTime ) )
|
||||
{
|
||||
lockOnTime = GetTime() + CONST_LOCK_ON_TIME_MSEC;
|
||||
level thread LGM_locking_think( targetVeh, self );
|
||||
}
|
||||
else if ( GetTime() >= lockOnTime )
|
||||
{
|
||||
// incoming notify was fired as soon as the player looked at
|
||||
// the target
|
||||
lockedOn = true;
|
||||
self notify( "LGM_player_lockedOn" );
|
||||
}
|
||||
|
||||
if ( lockedOn )
|
||||
{
|
||||
// In case the current live missiles are paired with flares
|
||||
// this script update wait untill after they're removed
|
||||
// from missilesChasing
|
||||
waittillframeend;
|
||||
|
||||
if ( entTarget.missilesChasing.size > 0 )
|
||||
{
|
||||
missileOrigins = [];
|
||||
|
||||
foreach ( missile in entTarget.missilesChasing )
|
||||
{
|
||||
if ( !IsValidMissile( missile ) )
|
||||
continue;
|
||||
|
||||
missileOrigins[ missileOrigins.size ] = missile.origin;
|
||||
|
||||
missile notify( "missile_targetChanged" );
|
||||
missile notify( "LGM_missile_abandoned" );
|
||||
missile Delete();
|
||||
}
|
||||
|
||||
if ( missileOrigins.size > 0 )
|
||||
{
|
||||
level thread LGM_locked_think( targetVeh, self, weaponNameHoming, missileOrigins );
|
||||
}
|
||||
|
||||
entTarget.missilesChasing = [];
|
||||
}
|
||||
else
|
||||
{
|
||||
// All missiles were removed during the waittillframeend
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if ( newTarget )
|
||||
{
|
||||
LGM_targetNotifyMissiles( targetVeh, self, entTarget.missilesChasing );
|
||||
}
|
||||
}
|
||||
|
||||
entTarget.origin = originGoal;
|
||||
|
||||
waitframe();
|
||||
}
|
||||
}
|
||||
|
||||
// -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. //
|
||||
// Monitor LaserGuided Missile Ent Pool
|
||||
// - Prevent too many ents being created
|
||||
// -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. //
|
||||
|
||||
TARGET_ENT_COUNT_PREFERRED_MAX = 4; // The pool of target ents can get larger than this but should shrink back down when less are needed.
|
||||
|
||||
LGM_requestMissileGuideEnt( player )
|
||||
{
|
||||
if ( !IsDefined( level.laserGuidedMissileEnts_inUse ) )
|
||||
{
|
||||
level.laserGuidedMissileEnts_inUse = [];
|
||||
}
|
||||
|
||||
if ( !IsDefined( level.laserGuidedMissileEnts_ready ) )
|
||||
{
|
||||
level.laserGuidedMissileEnts_ready = [];
|
||||
}
|
||||
|
||||
ent = undefined;
|
||||
|
||||
if ( level.laserGuidedMissileEnts_ready.size )
|
||||
{
|
||||
ent = level.laserGuidedMissileEnts_ready[ 0 ];
|
||||
level.laserGuidedMissileEnts_ready = array_remove( level.laserGuidedMissileEnts_ready, ent );
|
||||
}
|
||||
else
|
||||
{
|
||||
ent = spawn( "script_origin", player.origin );
|
||||
}
|
||||
|
||||
level.laserGuidedMissileEnts_inUse[ level.laserGuidedMissileEnts_inUse.size ] = ent;
|
||||
|
||||
level thread LGM_monitorLaserEntCleanUp( ent, player );
|
||||
|
||||
ent.missilesChasing = [];
|
||||
|
||||
return ent;
|
||||
}
|
||||
|
||||
LGM_monitorLaserEntCleanUp( entTarget, player )
|
||||
{
|
||||
player waittill_any( "death", "disconnect", "LGM_player_endMonitorFire" );
|
||||
|
||||
AssertEx( array_contains( level.laserGuidedMissileEnts_inUse, entTarget ), "LGM_monitorLaserEntCleanUp() attempting to clean up laser target ent not currently in use." );
|
||||
|
||||
// Scrub ent clean
|
||||
AssertEx( IsDefined( entTarget.missilesChasing ) && IsArray( entTarget.missilesChasing ), "LGM_monitorLaserEntCleanUp() given missile ent with now missile array." );
|
||||
foreach ( missile in entTarget.missilesChasing )
|
||||
{
|
||||
if ( IsValidMissile( missile ) )
|
||||
{
|
||||
missile Missile_ClearTarget();
|
||||
}
|
||||
}
|
||||
|
||||
entTarget.missilesChasing = undefined;
|
||||
|
||||
// Move ent fron in use to ready array
|
||||
level.laserGuidedMissileEnts_inUse = array_remove( level.laserGuidedMissileEnts_inUse, entTarget );
|
||||
|
||||
// If the too many ents exist delete it, otherwise add it to ready array
|
||||
if ( level.laserGuidedMissileEnts_ready.size + level.laserGuidedMissileEnts_inUse.size < TARGET_ENT_COUNT_PREFERRED_MAX )
|
||||
{
|
||||
level.laserGuidedMissileEnts_ready[ level.laserGuidedMissileEnts_ready.size ] = entTarget;
|
||||
}
|
||||
else
|
||||
{
|
||||
entTarget Delete();
|
||||
}
|
||||
}
|
||||
|
||||
// -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. //
|
||||
// Monitor Locking and Locked On
|
||||
// -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. //
|
||||
|
||||
LGM_locking_think( targetVeh, player )
|
||||
{
|
||||
AssertEx( IsDefined( player ), "LGM_locking_think called with undefined player." );
|
||||
|
||||
outline = outlineEnableForPlayer( targetVeh, "orange", player, true, "killstreak_personal" );
|
||||
|
||||
level thread LGM_locking_loopSound( player, "maaws_reticle_tracking", 1.5, "LGM_player_lockingDone" );
|
||||
level thread LGM_locking_notifyOnTargetDeath( targetVeh, player );
|
||||
|
||||
player waittill_any(
|
||||
"death", // targetting player died
|
||||
"disconnect", // targetting player left game
|
||||
"LGM_player_endMonitorFire", // ks system stopped launcher logic
|
||||
"LGM_player_newMissilesFired", // player fired again, these missiles are going to be abandoned
|
||||
"LGM_player_targetLost", // player looked away or new enemy came into view during lock on
|
||||
"LGM_player_lockedOn", // player obtained full lock, this outlin is removed, a new outlin call is made
|
||||
"LGM_player_allMissilesDestroyed", // the current set of tracked missiles all died or were paired with flares
|
||||
"LGM_player_targetDied" // target destroyed
|
||||
);
|
||||
|
||||
// Some entities delete instantly on death and may
|
||||
// be removed at this point
|
||||
if ( IsDefined( targetVeh ) )
|
||||
{
|
||||
outlineDisable( outline, targetVeh );
|
||||
}
|
||||
|
||||
if ( IsDefined( player ) )
|
||||
{
|
||||
player notify( "LGM_player_lockingDone" );
|
||||
|
||||
player StopLocalSound( "maaws_reticle_tracking" );
|
||||
}
|
||||
}
|
||||
|
||||
LGM_locked_missileOnDeath( missile, targetVeh, groupID )
|
||||
{
|
||||
targetVeh endon( "death" );
|
||||
|
||||
missile waittill( "death" );
|
||||
|
||||
targetVeh.LG_missilesLocked[ groupID ] = array_remove( targetVeh.LG_missilesLocked[ groupID ], missile );
|
||||
|
||||
if ( targetVeh.LG_missilesLocked[ groupID ].size == 0 )
|
||||
{
|
||||
targetVeh.LG_missilesLocked[ groupID ] = undefined;
|
||||
targetVeh notify( "LGM_target_lockedMissilesDestroyed" );
|
||||
}
|
||||
}
|
||||
|
||||
LGM_locking_notifyOnTargetDeath( target, player )
|
||||
{
|
||||
player endon( "death" );
|
||||
player endon( "disconnect" );
|
||||
player endon( "LGM_player_lockingDone" );
|
||||
|
||||
target waittill( "death" );
|
||||
|
||||
player notify( "LGM_player_targetDied" );
|
||||
}
|
||||
|
||||
LGM_locking_loopSound( player, sound, time, endonPlayer )
|
||||
{
|
||||
player endon( "death" );
|
||||
player endon( "disconnect" );
|
||||
player endon( endOnPlayer );
|
||||
|
||||
while ( 1 )
|
||||
{
|
||||
player PlayLocalSound( sound );
|
||||
wait( time );
|
||||
}
|
||||
}
|
||||
|
||||
LGM_locked_spawnMissiles( target, player, weaponNameHoming, missileOrigins )
|
||||
{
|
||||
target endon( "death" );
|
||||
player endon( "death" );
|
||||
player endon( "disconnect" );
|
||||
|
||||
missilesLocked = [];
|
||||
|
||||
for ( i = 0; i < missileOrigins.size; i++ )
|
||||
{
|
||||
missileChild = MagicBullet( weaponNameHoming, missileOrigins[ i ], target.origin, player );
|
||||
missileChild.isMagicBullet = true;
|
||||
missilesLocked[ missilesLocked.size ] = missileChild;
|
||||
|
||||
PlayFX( level._effect[ "laser_guided_launcher_missile_spawn_homing" ], missileChild.origin, AnglesToForward( missileChild.angles ), AnglesToUp( missileChild.angles ) );
|
||||
|
||||
// Don't spawn missiles on the same frame
|
||||
waitframe();
|
||||
}
|
||||
|
||||
return missilesLocked;
|
||||
}
|
||||
|
||||
// Handles locked on visual / audio fx
|
||||
LGM_locked_think( targetVeh, player, weaponNameHoming, missileOrigins )
|
||||
{
|
||||
AssertEx( missileOrigins.size > 0, "LGM_locked_think() passed empty missile origin array." );
|
||||
|
||||
if ( missileOrigins.size == 0 )
|
||||
return;
|
||||
|
||||
missilesLocked = LGM_locked_spawnMissiles( targetVeh, player, weaponNameHoming, missileOrigins );
|
||||
|
||||
// If undefined the player died or the target died
|
||||
if ( !IsDefined( missilesLocked ) )
|
||||
return;
|
||||
|
||||
// In case a missile died after the above wait frame
|
||||
missilesLocked = LGM_removeInvalidMissiles( missilesLocked );
|
||||
if ( missilesLocked.size == 0 )
|
||||
return;
|
||||
|
||||
// Visual and audio fx
|
||||
player PlayLocalSound( "maaws_reticle_locked" );
|
||||
outlineID = outlineEnableForPlayer( targetVeh, "red", player, false, "killstreak_personal" );
|
||||
|
||||
// Give missiles their target with an offset
|
||||
targetOffset = LGM_getTargetOffset( targetVeh );
|
||||
|
||||
foreach ( mChild in missilesLocked )
|
||||
{
|
||||
mChild missile_setTargetAndFlightMode( targetVeh, "direct", targetOffset );
|
||||
|
||||
LGM_targetNotifyMissiles( targetVeh, player, missilesLocked );
|
||||
}
|
||||
|
||||
if ( !IsDefined( targetVeh.LG_missilesLocked ) )
|
||||
{
|
||||
targetVeh.LG_missilesLocked = [];
|
||||
}
|
||||
|
||||
// Because multiple sets of missiles from the same or different players
|
||||
// can be tracking the helicopter at the same timed, add the missiles
|
||||
// to an array by the unique outline ID
|
||||
targetVeh.LG_missilesLocked[ outlineID ] = missilesLocked;
|
||||
|
||||
foreach ( vMiss in missilesLocked )
|
||||
{
|
||||
level thread LGM_locked_missileOnDeath( vMiss, targetVeh, outlineID );
|
||||
}
|
||||
|
||||
outlineOn = true;
|
||||
while ( outlineOn )
|
||||
{
|
||||
msg = targetVeh waittill_any_return( "death", "LGM_target_lockedMissilesDestroyed" );
|
||||
|
||||
if ( msg == "death" )
|
||||
{
|
||||
outlineOn = false;
|
||||
if ( IsDefined( targetVeh ) )
|
||||
{
|
||||
targetVeh.LG_missilesLocked[ outlineID ] = undefined;
|
||||
}
|
||||
}
|
||||
else if ( msg == "LGM_target_lockedMissilesDestroyed" )
|
||||
{
|
||||
// Two sets of missiles could potentially throw the "LGM_target_lockedMissilesDestroyed"
|
||||
// notification on the same frame. Wait until frame end and then check to see if this
|
||||
// outline's missiles are all gone
|
||||
waittillframeend;
|
||||
|
||||
if ( !IsDefined( targetVeh.LG_missilesLocked[ outlineID ] ) || targetVeh.LG_missilesLocked[ outlineID ].size == 0 )
|
||||
{
|
||||
outlineOn = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Targetveh may be deleted at this point
|
||||
if ( IsDefined( targetVeh ) )
|
||||
{
|
||||
outlineDisable( outlineID, targetVeh );
|
||||
}
|
||||
}
|
||||
|
||||
LGM_targetFind()
|
||||
{
|
||||
targets = self maps\mp\gametypes\_weapons::lockOnLaunchers_getTargetArray();
|
||||
targets = SortByDistance( targets, self.origin );
|
||||
|
||||
targetLook = undefined;
|
||||
foreach ( target in targets )
|
||||
{
|
||||
if ( self WorldPointInReticle_Circle( target.origin, 65, 75 ) )
|
||||
{
|
||||
targetLook = target;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return targetLook;
|
||||
}
|
||||
|
||||
// -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. //
|
||||
// LaserGuided Missile Utils
|
||||
// -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. //
|
||||
|
||||
LGM_enableLaser()
|
||||
{
|
||||
if ( !IsDefined( self.laserGuidedLauncher_laserOn ) || self.laserGuidedLauncher_laserOn == false )
|
||||
{
|
||||
self.laserGuidedLauncher_laserOn = true;
|
||||
self enableWeaponLaser();
|
||||
}
|
||||
}
|
||||
|
||||
LGM_disableLaser()
|
||||
{
|
||||
if ( IsDefined( self.laserGuidedLauncher_laserOn ) && self.laserGuidedLauncher_laserOn == true )
|
||||
{
|
||||
self disableWeaponLaser();
|
||||
}
|
||||
|
||||
self.laserGuidedLauncher_laserOn = undefined;
|
||||
}
|
||||
|
||||
LGM_removeInvalidMissiles( missiles )
|
||||
{
|
||||
valid = [];
|
||||
foreach ( m in missiles )
|
||||
{
|
||||
if ( IsValidMissile( m ) )
|
||||
{
|
||||
valid[ valid.size ] = m;
|
||||
}
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
LGM_targetNotifyMissiles( targetVeh, attacker, missiles )
|
||||
{
|
||||
// General notifies to other systems to handle incoming missiles
|
||||
level notify( "laserGuidedMissiles_incoming", attacker, missiles, targetVeh );
|
||||
targetVeh notify( "targeted_by_incoming_missile", missiles );
|
||||
}
|
||||
|
||||
LGM_getTargetOffset( target )
|
||||
{
|
||||
targetPoint = undefined;
|
||||
//AH: HACK: The harrier doesn't have the tag_missile_target, but it does have a tag_body.
|
||||
// The code works fine without this check, but GetTagOrigin throws an SRE if the tag does not exist.
|
||||
if ( target.model != "vehicle_av8b_harrier_jet_mp" )
|
||||
targetPoint = target GetTagOrigin( "tag_missile_target" );
|
||||
else
|
||||
targetPoint = target GetTagOrigin( "tag_body" );
|
||||
|
||||
if ( !IsDefined( targetPoint ) )
|
||||
{
|
||||
targetPoint = target GetPointInBounds( 0, 0, 0 );
|
||||
AssertMsg( "LGM_getTargetOffset() failed to find tag_missile_target on entity." + target.classname );
|
||||
}
|
||||
|
||||
return targetPoint - target.origin;
|
||||
}
|
||||
|
||||
LGM_missilesNotifyAndRelease( entTarget )
|
||||
{
|
||||
if ( IsDefined( entTarget.missilesChasing ) && entTarget.missilesChasing.size > 0 )
|
||||
{
|
||||
foreach ( missChasing in entTarget.missilesChasing )
|
||||
{
|
||||
if ( IsValidMissile( missChasing ) )
|
||||
{
|
||||
// Let systems watching incoming missiles know the
|
||||
// target has changed
|
||||
missChasing notify( "missile_targetChanged" );
|
||||
missChasing notify( "LGM_missile_abandoned" );
|
||||
missChasing Missile_ClearTarget();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
entTarget.missilesChasing = [];
|
||||
}
|
399
maps/mp/_load.gsc
Normal file
399
maps/mp/_load.gsc
Normal file
@ -0,0 +1,399 @@
|
||||
#include common_scripts\utility;
|
||||
#include common_scripts\_fx;
|
||||
#include maps\mp\_utility;
|
||||
|
||||
main()
|
||||
{
|
||||
if ( isDefined( level._loadStarted ) )
|
||||
return;
|
||||
|
||||
level._loadStarted = true;
|
||||
|
||||
level.createFX_enabled = ( getdvar( "createfx" ) != "" );
|
||||
|
||||
struct_class_init();
|
||||
|
||||
initGameFlags();
|
||||
initLevelFlags();
|
||||
initGlobals();
|
||||
|
||||
level.generic_index = 0;
|
||||
// flag_struct is used as a placeholder when a flag is set without an entity
|
||||
|
||||
level.flag_struct = spawnstruct();
|
||||
level.flag_struct assign_unique_id();
|
||||
if ( !isdefined( level.flag ) )
|
||||
{
|
||||
level.flag = [];
|
||||
level.flags_lock = [];
|
||||
}
|
||||
|
||||
level.requiredMapAspectRatio = getDvarFloat( "scr_RequiredMapAspectratio", 1 );
|
||||
level.createClientFontString_func = maps\mp\gametypes\_hud_util::createFontString;
|
||||
level.HUDsetPoint_func = maps\mp\gametypes\_hud_util::setPoint;
|
||||
level.leaderDialogOnPlayer_func = maps\mp\_utility::leaderDialogOnPlayer;
|
||||
|
||||
thread maps\mp\gametypes\_tweakables::init();
|
||||
|
||||
|
||||
if ( !isdefined( level.func ) )
|
||||
level.func = [];
|
||||
level.func[ "precacheMpAnim" ] = ::precacheMpAnim;
|
||||
level.func[ "scriptModelPlayAnim" ] = ::scriptModelPlayAnim;
|
||||
level.func[ "scriptModelClearAnim" ] = ::scriptModelClearAnim;
|
||||
|
||||
// dodge this stuff for createfx tool.
|
||||
if( ! level.createFX_enabled )
|
||||
{
|
||||
thread maps\mp\_minefields::minefields();
|
||||
thread maps\mp\_radiation::radiation();
|
||||
thread maps\mp\_shutter::main();
|
||||
thread maps\mp\_movers::init();
|
||||
thread maps\mp\_destructables::init();
|
||||
thread common_scripts\_elevator::init();
|
||||
thread common_scripts\_dynamic_world::init();
|
||||
thread common_scripts\_destructible::init();
|
||||
level notify( "interactive_start" );
|
||||
}
|
||||
|
||||
game["thermal_vision"] = "thermal_mp";
|
||||
|
||||
VisionSetNaked( "", 0 ); // go to default visionset
|
||||
VisionSetNight( "default_night_mp" );
|
||||
VisionSetMissilecam( "missilecam" );
|
||||
VisionSetThermal( game[ "thermal_vision" ] );
|
||||
VisionSetPain( "", 0 );
|
||||
|
||||
lanterns = getentarray("lantern_glowFX_origin","targetname");
|
||||
for( i = 0 ; i < lanterns.size ; i++ )
|
||||
lanterns[i] thread lanterns();
|
||||
|
||||
maps\mp\_audio::init_audio();
|
||||
maps\mp\_art::main();
|
||||
/#
|
||||
thread common_scripts\_painter::main("painter_mp");
|
||||
#/
|
||||
|
||||
setupExploders();
|
||||
|
||||
thread common_scripts\_fx::initFX();
|
||||
if ( level.createFX_enabled )
|
||||
{
|
||||
maps\mp\gametypes\_spawnlogic::setMapCenterForDev();
|
||||
maps\mp\_createfx::createfx();
|
||||
}
|
||||
|
||||
if ( getdvar( "r_reflectionProbeGenerate" ) == "1" )
|
||||
{
|
||||
maps\mp\gametypes\_spawnlogic::setMapCenterForDev();
|
||||
maps\mp\_global_fx::main();
|
||||
level waittill( "eternity" );
|
||||
}
|
||||
|
||||
thread maps\mp\_global_fx::main();
|
||||
|
||||
// Do various things on triggers
|
||||
for ( p = 0;p < 6;p ++ )
|
||||
{
|
||||
switch( p )
|
||||
{
|
||||
case 0:
|
||||
triggertype = "trigger_multiple";
|
||||
break;
|
||||
|
||||
case 1:
|
||||
triggertype = "trigger_once";
|
||||
break;
|
||||
|
||||
case 2:
|
||||
triggertype = "trigger_use";
|
||||
break;
|
||||
|
||||
case 3:
|
||||
triggertype = "trigger_radius";
|
||||
break;
|
||||
|
||||
case 4:
|
||||
triggertype = "trigger_lookat";
|
||||
break;
|
||||
|
||||
default:
|
||||
assert( p == 5 );
|
||||
triggertype = "trigger_damage";
|
||||
break;
|
||||
}
|
||||
|
||||
triggers = getentarray( triggertype, "classname" );
|
||||
|
||||
for ( i = 0;i < triggers.size;i ++ )
|
||||
{
|
||||
if( isdefined( triggers[ i ].script_prefab_exploder) )
|
||||
triggers[i].script_exploder = triggers[ i ].script_prefab_exploder;
|
||||
|
||||
if( isdefined( triggers[ i ].script_exploder) )
|
||||
level thread maps\mp\_load::exploder_load( triggers[ i ] );
|
||||
}
|
||||
}
|
||||
|
||||
thread maps\mp\_animatedmodels::main();
|
||||
|
||||
// auto-sentry
|
||||
level.func[ "damagefeedback" ] = maps\mp\gametypes\_damagefeedback::updateDamageFeedback;
|
||||
level.func[ "setTeamHeadIcon" ] = maps\mp\_entityheadicons::setTeamHeadIcon;
|
||||
level.laserOn_func = ::laserOn;
|
||||
level.laserOff_func = ::laserOff;
|
||||
|
||||
level.connectPathsFunction = ::connectPaths;
|
||||
level.disconnectPathsFunction = ::disconnectPaths;
|
||||
|
||||
// defaults
|
||||
setDvar( "sm_sunShadowScale", 1 );
|
||||
setDvar( "sm_spotLightScoreModelScale", 0 );
|
||||
setDvar( "r_specularcolorscale", 2.5 );
|
||||
setDvar( "r_diffusecolorscale", 1 );
|
||||
setDvar( "r_lightGridEnableTweaks", 0 );
|
||||
setDvar( "r_lightGridIntensity", 1 );
|
||||
setDvar( "r_lightGridContrast", 0 );
|
||||
|
||||
// created these so we can turn things on/off individually without having to set the game to hardcore
|
||||
SetDvar( "ui_showInfo", 1 );
|
||||
SetDvar( "ui_showMinimap", 1 );
|
||||
|
||||
// setup kill cam ents on destructibles
|
||||
setupDestructibleKillCamEnts();
|
||||
|
||||
// precache the bomb site weapon
|
||||
PreCacheItem( "bomb_site_mp" );
|
||||
|
||||
// precache dog fur for PC
|
||||
if ( !level.console )
|
||||
{
|
||||
level.furFX = loadfx( "vfx/apex/nv_dog_a" );
|
||||
level.wolfFurFX = [];
|
||||
level.wolfFurFX[0] = loadfx( "vfx/apex/nv_wolf_b" );
|
||||
level.wolfFurFX[1] = loadfx( "vfx/apex/nv_wolf_c" );
|
||||
}
|
||||
|
||||
level.fauxVehicleCount = 0; // this keeps an artificial count so we can check airspace and vehicles limits preemptively
|
||||
level.littlebird_model = "vehicle_aas_72x_killstreak";
|
||||
|
||||
/#
|
||||
// when host migration happens, all of the dev dvars get cleared, so this will reset them all
|
||||
level thread reInitializeDevDvarsOnMigration();
|
||||
#/
|
||||
}
|
||||
|
||||
exploder_load( trigger )
|
||||
{
|
||||
level endon( "killexplodertridgers" + trigger.script_exploder );
|
||||
trigger waittill( "trigger" );
|
||||
if ( isdefined( trigger.script_chance ) && randomfloat( 1 ) > trigger.script_chance )
|
||||
{
|
||||
if ( isdefined( trigger.script_delay ) )
|
||||
wait trigger.script_delay;
|
||||
else
|
||||
wait 4;
|
||||
level thread exploder_load( trigger );
|
||||
return;
|
||||
}
|
||||
exploder( trigger.script_exploder );
|
||||
level notify( "killexplodertridgers" + trigger.script_exploder );
|
||||
}
|
||||
|
||||
|
||||
setupExploders()
|
||||
{
|
||||
// Hide exploder models.
|
||||
ents = getentarray( "script_brushmodel", "classname" );
|
||||
smodels = getentarray( "script_model", "classname" );
|
||||
for ( i = 0;i < smodels.size;i ++ )
|
||||
ents[ ents.size ] = smodels[ i ];
|
||||
|
||||
for ( i = 0;i < ents.size;i ++ )
|
||||
{
|
||||
if ( isdefined( ents[ i ].script_prefab_exploder ) )
|
||||
ents[ i ].script_exploder = ents[ i ].script_prefab_exploder;
|
||||
|
||||
if ( isdefined( ents[ i ].script_exploder ) )
|
||||
{
|
||||
if ( ( ents[ i ].model == "fx" ) && ( ( !isdefined( ents[ i ].targetname ) ) || ( ents[ i ].targetname != "exploderchunk" ) ) )
|
||||
ents[ i ] hide();
|
||||
else if ( ( isdefined( ents[ i ].targetname ) ) && ( ents[ i ].targetname == "exploder" ) )
|
||||
{
|
||||
ents[ i ] hide();
|
||||
ents[ i ] notsolid();
|
||||
//if ( isdefined( ents[ i ].script_disconnectpaths ) )
|
||||
//ents[ i ] connectpaths();
|
||||
}
|
||||
else if ( ( isdefined( ents[ i ].targetname ) ) && ( ents[ i ].targetname == "exploderchunk" ) )
|
||||
{
|
||||
ents[ i ] hide();
|
||||
ents[ i ] notsolid();
|
||||
//if ( isdefined( ents[ i ].spawnflags ) && ( ents[ i ].spawnflags & 1 ) )
|
||||
//ents[ i ] connectpaths();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
script_exploders = [];
|
||||
|
||||
potentialExploders = getentarray( "script_brushmodel", "classname" );
|
||||
for ( i = 0;i < potentialExploders.size;i ++ )
|
||||
{
|
||||
if ( isdefined( potentialExploders[ i ].script_prefab_exploder ) )
|
||||
potentialExploders[ i ].script_exploder = potentialExploders[ i ].script_prefab_exploder;
|
||||
|
||||
if ( isdefined( potentialExploders[ i ].script_exploder ) )
|
||||
script_exploders[ script_exploders.size ] = potentialExploders[ i ];
|
||||
}
|
||||
|
||||
potentialExploders = getentarray( "script_model", "classname" );
|
||||
for ( i = 0;i < potentialExploders.size;i ++ )
|
||||
{
|
||||
if ( isdefined( potentialExploders[ i ].script_prefab_exploder ) )
|
||||
potentialExploders[ i ].script_exploder = potentialExploders[ i ].script_prefab_exploder;
|
||||
|
||||
if ( isdefined( potentialExploders[ i ].script_exploder ) )
|
||||
script_exploders[ script_exploders.size ] = potentialExploders[ i ];
|
||||
}
|
||||
|
||||
potentialExploders = getentarray( "item_health", "classname" );
|
||||
for ( i = 0;i < potentialExploders.size;i ++ )
|
||||
{
|
||||
if ( isdefined( potentialExploders[ i ].script_prefab_exploder ) )
|
||||
potentialExploders[ i ].script_exploder = potentialExploders[ i ].script_prefab_exploder;
|
||||
|
||||
if ( isdefined( potentialExploders[ i ].script_exploder ) )
|
||||
script_exploders[ script_exploders.size ] = potentialExploders[ i ];
|
||||
}
|
||||
|
||||
if ( !isdefined( level.createFXent ) )
|
||||
level.createFXent = [];
|
||||
|
||||
acceptableTargetnames = [];
|
||||
acceptableTargetnames[ "exploderchunk visible" ] = true;
|
||||
acceptableTargetnames[ "exploderchunk" ] = true;
|
||||
acceptableTargetnames[ "exploder" ] = true;
|
||||
|
||||
for ( i = 0; i < script_exploders.size; i ++ )
|
||||
{
|
||||
exploder = script_exploders[ i ];
|
||||
ent = createExploder( exploder.script_fxid );
|
||||
ent.v = [];
|
||||
ent.v[ "origin" ] = exploder.origin;
|
||||
ent.v[ "angles" ] = exploder.angles;
|
||||
ent.v[ "delay" ] = exploder.script_delay;
|
||||
ent.v[ "firefx" ] = exploder.script_firefx;
|
||||
ent.v[ "firefxdelay" ] = exploder.script_firefxdelay;
|
||||
ent.v[ "firefxsound" ] = exploder.script_firefxsound;
|
||||
ent.v[ "firefxtimeout" ] = exploder.script_firefxtimeout;
|
||||
ent.v[ "earthquake" ] = exploder.script_earthquake;
|
||||
ent.v[ "damage" ] = exploder.script_damage;
|
||||
ent.v[ "damage_radius" ] = exploder.script_radius;
|
||||
ent.v[ "soundalias" ] = exploder.script_soundalias;
|
||||
ent.v[ "repeat" ] = exploder.script_repeat;
|
||||
ent.v[ "delay_min" ] = exploder.script_delay_min;
|
||||
ent.v[ "delay_max" ] = exploder.script_delay_max;
|
||||
ent.v[ "target" ] = exploder.target;
|
||||
ent.v[ "ender" ] = exploder.script_ender;
|
||||
ent.v[ "type" ] = "exploder";
|
||||
// ent.v[ "worldfx" ] = true;
|
||||
if ( !isdefined( exploder.script_fxid ) )
|
||||
ent.v[ "fxid" ] = "No FX";
|
||||
else
|
||||
ent.v[ "fxid" ] = exploder.script_fxid;
|
||||
ent.v[ "exploder" ] = exploder.script_exploder;
|
||||
assertEx( isdefined( exploder.script_exploder ), "Exploder at origin " + exploder.origin + " has no script_exploder" );
|
||||
|
||||
if ( !isdefined( ent.v[ "delay" ] ) )
|
||||
ent.v[ "delay" ] = 0;
|
||||
|
||||
if ( isdefined( exploder.target ) )
|
||||
{
|
||||
org = getent( ent.v[ "target" ], "targetname" ).origin;
|
||||
ent.v[ "angles" ] = vectortoangles( org - ent.v[ "origin" ] );
|
||||
// forward = anglestoforward( angles );
|
||||
// up = anglestoup( angles );
|
||||
}
|
||||
|
||||
// this basically determines if its a brush / model exploder or not
|
||||
if ( exploder.classname == "script_brushmodel" || isdefined( exploder.model ) )
|
||||
{
|
||||
ent.model = exploder;
|
||||
ent.model.disconnect_paths = exploder.script_disconnectpaths;
|
||||
}
|
||||
|
||||
if ( isdefined( exploder.targetname ) && isdefined( acceptableTargetnames[ exploder.targetname ] ) )
|
||||
ent.v[ "exploder_type" ] = exploder.targetname;
|
||||
else
|
||||
ent.v[ "exploder_type" ] = "normal";
|
||||
|
||||
ent common_scripts\_createfx::post_entity_creation_function();
|
||||
}
|
||||
}
|
||||
|
||||
lanterns()
|
||||
{
|
||||
if (!isdefined(level._effect["lantern_light"]))
|
||||
level._effect["lantern_light"] = loadfx("fx/props/glow_latern");
|
||||
|
||||
loopfx("lantern_light", self.origin, 0.3, self.origin + (0,0,1));
|
||||
}
|
||||
|
||||
setupDestructibleKillCamEnts()
|
||||
{
|
||||
// TODO: this needs to be done in code
|
||||
|
||||
destructible_vehicles = GetEntArray( "scriptable_destructible_vehicle", "targetname" );
|
||||
foreach( dest in destructible_vehicles )
|
||||
{
|
||||
bulletStart = dest.origin + ( 0, 0, 5 );
|
||||
bulletEnd = ( dest.origin + ( 0, 0, 128 ) );
|
||||
result = BulletTrace( bulletStart, bulletEnd, false, dest );
|
||||
dest.killCamEnt = Spawn( "script_model", result[ "position" ] );
|
||||
dest.killCamEnt.targetname = "killCamEnt_destructible_vehicle";
|
||||
dest.killCamEnt SetScriptMoverKillCam( "explosive" );
|
||||
dest thread deleteDestructibleKillCamEnt();
|
||||
}
|
||||
|
||||
// Not needed anymore?
|
||||
// destructible_toys = GetEntArray( "destructible_toy", "targetname" );
|
||||
// foreach( dest in destructible_toys )
|
||||
// {
|
||||
// bulletStart = dest.origin + ( 0, 0, 5 );
|
||||
// bulletEnd = ( dest.origin + ( 0, 0, 128 ) );
|
||||
// result = BulletTrace( bulletStart, bulletEnd, false, dest );
|
||||
// dest.killCamEnt = Spawn( "script_model", result[ "position" ] );
|
||||
// dest.killCamEnt.targetname = "killCamEnt_destructible_toy";
|
||||
// dest.killCamEnt SetScriptMoverKillCam( "explosive" );
|
||||
// dest thread deleteDestructibleKillCamEnt();
|
||||
// }
|
||||
//
|
||||
explodable_barrels = GetEntArray( "scriptable_destructible_barrel", "targetname" );
|
||||
foreach( dest in explodable_barrels )
|
||||
{
|
||||
bulletStart = dest.origin + ( 0, 0, 5 );
|
||||
bulletEnd = ( dest.origin + ( 0, 0, 128 ) );
|
||||
result = BulletTrace( bulletStart, bulletEnd, false, dest );
|
||||
dest.killCamEnt = Spawn( "script_model", result[ "position" ] );
|
||||
dest.killCamEnt.targetname = "killCamEnt_explodable_barrel";
|
||||
dest.killCamEnt SetScriptMoverKillCam( "explosive" );
|
||||
dest thread deleteDestructibleKillCamEnt();
|
||||
}
|
||||
|
||||
// ADD MORE DESTRUCTIBLES HERE IF APPLICABLE
|
||||
}
|
||||
|
||||
deleteDestructibleKillCamEnt()
|
||||
{
|
||||
level endon( "game_ended" );
|
||||
|
||||
killCamEnt = self.killCamEnt;
|
||||
killCamEnt endon( "death" );
|
||||
|
||||
self waittill( "death" );
|
||||
|
||||
wait( 10 );
|
||||
if( IsDefined( killCamEnt ) )
|
||||
killCamEnt delete();
|
||||
}
|
598
maps/mp/_matchdata.gsc
Normal file
598
maps/mp/_matchdata.gsc
Normal file
@ -0,0 +1,598 @@
|
||||
#include maps\mp\_utility;
|
||||
#include maps\mp\gametypes\_hud_util;
|
||||
#include common_scripts\utility;
|
||||
|
||||
init()
|
||||
{
|
||||
if ( !isDefined( game["gamestarted"] ) )
|
||||
{
|
||||
//setMatchDataDef( "mp/matchdata_" + level.gametype + ".def" );
|
||||
setMatchDataDef( "mp/matchdata.def" );
|
||||
setMatchData( "map", level.script );
|
||||
if( level.hardcoremode )
|
||||
{
|
||||
tmp = level.gametype + " hc";
|
||||
setMatchData( "gametype", tmp );
|
||||
}
|
||||
else
|
||||
{
|
||||
setMatchData( "gametype", level.gametype );
|
||||
}
|
||||
setMatchData( "buildVersion", getBuildVersion() );
|
||||
setMatchData( "buildNumber", getBuildNumber() );
|
||||
setMatchData( "dateTime", getSystemTime() );
|
||||
setMatchDataID();
|
||||
}
|
||||
|
||||
level.MaxLives = 285; // must match MaxKills in matchdata definition
|
||||
level.MaxNameLength = 26; // must match Player xuid size in clientmatchdata definition
|
||||
level.MaxEvents = 150;
|
||||
level.MaxKillstreaks = 64;
|
||||
level.MaxLogClients = 30;
|
||||
level.MaxNumChallengesPerPlayer = 10;
|
||||
level.MaxNumAwardsPerPlayer = 10;
|
||||
|
||||
if ( !is_aliens() )
|
||||
{
|
||||
level thread gameEndListener();
|
||||
level thread endOfGameSummaryLogger();
|
||||
}
|
||||
}
|
||||
|
||||
getMatchDateTime()
|
||||
{
|
||||
return GetMatchData( "dateTime" );
|
||||
}
|
||||
|
||||
logKillstreakEvent( event, position )
|
||||
{
|
||||
assertEx( IsGameParticipant( self ), "self is not a player: " + self.code_classname );
|
||||
|
||||
if ( !canLogClient( self ) || !canLogKillstreak() )
|
||||
return;
|
||||
|
||||
eventId = getMatchData( "killstreakCount" );
|
||||
setMatchData( "killstreakCount", eventId+1 );
|
||||
|
||||
setMatchData( "killstreaks", eventId, "eventType", event );
|
||||
setMatchData( "killstreaks", eventId, "player", self.clientid );
|
||||
setMatchData( "killstreaks", eventId, "eventTime", getTime() );
|
||||
setMatchData( "killstreaks", eventId, "eventPos", 0, int( position[0] ) );
|
||||
setMatchData( "killstreaks", eventId, "eventPos", 1, int( position[1] ) );
|
||||
setMatchData( "killstreaks", eventId, "eventPos", 2, int( position[2] ) );
|
||||
}
|
||||
|
||||
|
||||
logGameEvent( event, position )
|
||||
{
|
||||
assertEx( IsGameParticipant( self ), "self is not a player: " + self.code_classname );
|
||||
|
||||
if ( !canLogClient( self ) || !canLogEvent() )
|
||||
return;
|
||||
|
||||
eventId = getMatchData( "eventCount" );
|
||||
setMatchData( "eventCount", eventId+1 );
|
||||
|
||||
setMatchData( "events", eventId, "eventType", event );
|
||||
setMatchData( "events", eventId, "player", self.clientid );
|
||||
setMatchData( "events", eventId, "eventTime", getTime() );
|
||||
setMatchData( "events", eventId, "eventPos", 0, int( position[0] ) );
|
||||
setMatchData( "events", eventId, "eventPos", 1, int( position[1] ) );
|
||||
setMatchData( "events", eventId, "eventPos", 2, int( position[2] ) );
|
||||
}
|
||||
|
||||
|
||||
logKillEvent( lifeId, eventRef )
|
||||
{
|
||||
if ( !canLogLife( lifeId ) )
|
||||
return;
|
||||
|
||||
setMatchData( "lives", lifeId, "modifiers", eventRef, true );
|
||||
}
|
||||
|
||||
|
||||
logMultiKill( lifeId, multikillCount )
|
||||
{
|
||||
if ( !canLogLife( lifeId ) )
|
||||
return;
|
||||
|
||||
setMatchData( "lives", lifeId, "multikill", multikillCount );
|
||||
}
|
||||
|
||||
|
||||
logPlayerLife()
|
||||
{
|
||||
if ( !canLogClient( self ) )
|
||||
lifeId = level.MaxLives;
|
||||
|
||||
if ( self.curClass == "gamemode" )
|
||||
{
|
||||
lifeId = self LogMatchDataLife( self.clientid, self.spawnPos, self.spawnTime, self.wasTI );
|
||||
}
|
||||
else if ( IsSubStr( self.curClass, "custom" ) )
|
||||
{
|
||||
class_num = getClassIndex( self.curClass );
|
||||
|
||||
primaryWeapon = maps\mp\gametypes\_class::cac_getWeapon( class_num, 0 );
|
||||
primaryAttachment1 = maps\mp\gametypes\_class::cac_getWeaponAttachment( class_num, 0 );
|
||||
primaryAttachment2 = maps\mp\gametypes\_class::cac_getWeaponAttachmentTwo( class_num, 0 );
|
||||
|
||||
secondaryWeapon = maps\mp\gametypes\_class::cac_getWeapon( class_num, 1 );
|
||||
secondaryAttachment1 = maps\mp\gametypes\_class::cac_getWeaponAttachment( class_num, 1 );
|
||||
secondaryAttachment2 = maps\mp\gametypes\_class::cac_getWeaponAttachmentTwo( class_num, 1 );
|
||||
|
||||
offhandWeapon = "none"; //maps\mp\gametypes\_class::cac_getOffhand( class_num );
|
||||
|
||||
equipment = maps\mp\gametypes\_class::cac_getPerk( class_num, 0 );
|
||||
|
||||
lifeId = self LogMatchDataLife( self.clientid, self.spawnPos, self.spawnTime, self.wasTI, primaryWeapon, primaryAttachment1, primaryAttachment2, secondaryWeapon, secondaryAttachment1, secondaryAttachment2, offhandWeapon, equipment );
|
||||
self logPlayerAbilityPerks( lifeId );
|
||||
}
|
||||
else
|
||||
{
|
||||
class_num = getClassIndex( self.curClass );
|
||||
|
||||
primaryWeapon = maps\mp\gametypes\_class::table_getWeapon( level.classTableName, class_num, 0 );
|
||||
primaryAttachment1 = maps\mp\gametypes\_class::table_getWeaponAttachment( level.classTableName, class_num, 0 , 0);
|
||||
primaryAttachment2 = maps\mp\gametypes\_class::table_getWeaponAttachment( level.classTableName, class_num, 0, 1 );
|
||||
|
||||
secondaryWeapon = maps\mp\gametypes\_class::table_getWeapon( level.classTableName, class_num, 1 );
|
||||
secondaryAttachment1 = maps\mp\gametypes\_class::table_getWeaponAttachment( level.classTableName, class_num, 1 , 0);
|
||||
secondaryAttachment2 = maps\mp\gametypes\_class::table_getWeaponAttachment( level.classTableName, class_num, 1, 1 );;
|
||||
|
||||
offhandWeapon = maps\mp\gametypes\_class::table_getOffhand( level.classTableName, class_num );
|
||||
|
||||
equipment = maps\mp\gametypes\_class::table_getEquipment( level.classTableName, class_num, 0 );
|
||||
|
||||
lifeId = self LogMatchDataLife( self.clientid, self.spawnPos, self.spawnTime, self.wasTI, primaryWeapon, primaryAttachment1, primaryAttachment2, secondaryWeapon, secondaryAttachment1, secondaryAttachment2, offhandWeapon, equipment );
|
||||
self logPlayerAbilityPerks( lifeId );
|
||||
}
|
||||
|
||||
return lifeId;
|
||||
}
|
||||
|
||||
// 2014-09-10 wallace: in IW6, we changed how perks (abilities) are stored, so for much of the game's life, we weren't tracking
|
||||
// which perks players were using with their loadouts. We add this data now to try to capture some of that data in the live game
|
||||
// We don't care about game mode specific loadouts, so we skip that case
|
||||
logPlayerAbilityPerks( lifeId ) // self == player
|
||||
{
|
||||
// check dvar
|
||||
if ( GetDvarInt( "scr_trackPlayerAbilities", 0 ) != 0 )
|
||||
{
|
||||
if ( IsDefined( self.abilityFlags ) && self.abilityFlags.size == 2 )
|
||||
{
|
||||
SetMatchData( "lives", lifeId, "abilityFlags", 0, self.abilityFlags[0] );
|
||||
SetMatchData( "lives", lifeId, "abilityFlags", 1, self.abilityFlags[1] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logPlayerXP( xp, xpName )
|
||||
{
|
||||
if ( !canLogClient( self ) )
|
||||
return;
|
||||
setMatchData( "players", self.clientid, xpName, xp );
|
||||
}
|
||||
|
||||
|
||||
logPlayerDeath( lifeId, attacker, iDamage, sMeansOfDeath, sWeapon, sPrimaryWeapon, sHitLoc )
|
||||
{
|
||||
if ( !canLogClient( self ) )
|
||||
return;
|
||||
|
||||
if ( lifeId >= level.MaxLives )
|
||||
return;
|
||||
|
||||
// JC-ToDo: May need to tokenize the weapon name and change the attachments to their base name. That or code needs to do this in the LogMatchDataDeath()
|
||||
|
||||
if ( IsPlayer( attacker ) && canLogClient( attacker ) )
|
||||
self LogMatchDataDeath( lifeId, self.clientid, attacker, attacker.clientid, sWeapon, sMeansOfDeath, isKillstreakWeapon( sWeapon ), attacker isJuggernaut() );
|
||||
else
|
||||
self LogMatchDataDeath( lifeId, self.clientid, undefined, undefined, sWeapon, sMeansOfDeath, isKillstreakWeapon( sWeapon ), false );
|
||||
}
|
||||
|
||||
|
||||
logPlayerData()
|
||||
{
|
||||
if ( !canLogClient( self ) )
|
||||
return;
|
||||
|
||||
setMatchData( "players", self.clientid, "score", self getPersStat( "score" ) );
|
||||
|
||||
if( self getPersStat( "assists" ) > 255 )
|
||||
setMatchData( "players", self.clientid, "assists", 255 );
|
||||
else
|
||||
setMatchData( "players", self.clientid, "assists", self getPersStat( "assists" ) );
|
||||
|
||||
if( self getPersStat( "longestStreak" ) > 255 )
|
||||
setMatchData( "players", self.clientid, "longestStreak", 255 );
|
||||
else
|
||||
setMatchData( "players", self.clientid, "longestStreak", self getPersStat( "longestStreak" ) );
|
||||
|
||||
if( self getPersStat( "validationInfractions" ) > 255 )
|
||||
setMatchData( "players", self.clientid, "validationInfractions", 255 );
|
||||
else
|
||||
setMatchData( "players", self.clientid, "validationInfractions", self getPersStat( "validationInfractions" ) );
|
||||
}
|
||||
|
||||
|
||||
// log the weapons and weaponXP to playerdata.
|
||||
endOfGameSummaryLogger()
|
||||
{
|
||||
level waittill ( "game_ended" );
|
||||
|
||||
foreach ( player in level.players )
|
||||
{
|
||||
wait( 0.05 );
|
||||
|
||||
//player may disconnect during waits
|
||||
if ( !isdefined( player ) )
|
||||
continue;
|
||||
|
||||
if ( isDefined( player.detectedExploit ) && player.detectedExploit && ( player rankingEnabled() ) )
|
||||
player setRankedPlayerData( "restXPGoal", player.detectedExploit );
|
||||
|
||||
if ( isDefined ( player.weaponsUsed ) )
|
||||
{
|
||||
player doubleBubbleSort();
|
||||
counter = 0;
|
||||
|
||||
if ( player.weaponsUsed.size > 3 )
|
||||
{
|
||||
for ( i = (player.weaponsUsed.size - 1); i > (player.weaponsUsed.size - 3); i-- )
|
||||
{
|
||||
player setCommonPlayerData( "round", "weaponsUsed", counter, player.weaponsUsed[i] );
|
||||
player setCommonPlayerData( "round", "weaponXpEarned", counter, player.weaponXpEarned[i] );
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for ( i = (player.weaponsUsed.size - 1); i >= 0; i-- )
|
||||
{
|
||||
player setCommonPlayerData( "round", "weaponsUsed", counter, player.weaponsUsed[i] );
|
||||
player setCommonPlayerData( "round", "weaponXpEarned", counter, player.weaponXpEarned[i] );
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
player setCommonPlayerData( "round", "weaponsUsed", 0, "none" );
|
||||
player setCommonPlayerData( "round", "weaponsUsed", 1, "none" );
|
||||
player setCommonPlayerData( "round", "weaponsUsed", 2, "none" );
|
||||
player setCommonPlayerData( "round", "weaponXpEarned", 0, 0 );
|
||||
player setCommonPlayerData( "round", "weaponXpEarned", 1, 0 );
|
||||
player setCommonPlayerData( "round", "weaponXpEarned", 2, 0 );
|
||||
}
|
||||
|
||||
//log operations
|
||||
if ( isDefined ( player.operationsCompleted ) )
|
||||
{
|
||||
player setCommonPlayerData( "round", "operationNumCompleted", player.operationsCompleted.size );
|
||||
}
|
||||
else
|
||||
{
|
||||
player setCommonPlayerData( "round", "operationNumCompleted", 0 );
|
||||
}
|
||||
|
||||
for ( i = 0; i < 5; i++ )
|
||||
{
|
||||
if ( isDefined( player.operationsCompleted ) && isDefined( player.operationsCompleted[i] ) && player.operationsCompleted[i] != "ch_prestige" && !IsSubStr( player.operationsCompleted[i], "_daily" ) && !IsSubStr( player.operationsCompleted[i], "_weekly" ) )
|
||||
player setCommonPlayerData( "round", "operationsCompleted", i, player.operationsCompleted[i] );
|
||||
else
|
||||
player setCommonPlayerData( "round", "operationsCompleted", i, "" );
|
||||
}
|
||||
|
||||
//log challenges
|
||||
if ( isDefined ( player.challengesCompleted ) )
|
||||
{
|
||||
player setCommonPlayerData( "round", "challengeNumCompleted", player.challengesCompleted.size );
|
||||
}
|
||||
else
|
||||
{
|
||||
player setCommonPlayerData( "round", "challengeNumCompleted", 0 );
|
||||
}
|
||||
|
||||
for ( i = 0; i < 20; i++ )
|
||||
{
|
||||
if ( isDefined( player.challengesCompleted ) && isDefined( player.challengesCompleted[i] ) && player.challengesCompleted[i] != "ch_prestige" && !IsSubStr( player.challengesCompleted[i], "_daily" ) && !IsSubStr( player.challengesCompleted[i], "_weekly" ) )
|
||||
player setCommonPlayerData( "round", "challengesCompleted", i, player.challengesCompleted[i] );
|
||||
else
|
||||
player setCommonPlayerData( "round", "challengesCompleted", i, "" );
|
||||
}
|
||||
|
||||
|
||||
player setCommonPlayerData( "round", "gameMode", level.gametype );
|
||||
player setCommonPlayerData( "round", "map", ToLower( GetDvar( "mapname" ) ) );
|
||||
if ( IsSquadsMode() )
|
||||
{
|
||||
player setCommonPlayerData( "round", "squadMode", 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
player setCommonPlayerData( "round", "squadMode", 0 );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
doubleBubbleSort()
|
||||
{
|
||||
A = self.weaponXpEarned;
|
||||
n = self.weaponXpEarned.size;
|
||||
|
||||
for (i =(n-1); i > 0; i--)
|
||||
{
|
||||
for (j = 1; j <= i; j++)
|
||||
{
|
||||
if( A[j-1] < A[j] )
|
||||
{
|
||||
temp = self.weaponsUsed[j];
|
||||
self.weaponsUsed[j] = self.weaponsUsed[j-1];
|
||||
self.weaponsUsed[j-1] = temp;
|
||||
|
||||
temp2 = self.weaponXpEarned[j];
|
||||
self.weaponXpEarned[j] = self.weaponXpEarned[j-1];
|
||||
self.weaponXpEarned[j-1] = temp2;
|
||||
A = self.weaponXpEarned;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*Recursive nonsense sorts based on array 1 and sorts array 2's indexes (should be logn)
|
||||
quickDoubleSort()
|
||||
{
|
||||
quickDoubleSortMid( 0, self.weaponsUsed.size -1 );
|
||||
}
|
||||
quickDoubleSortMid( start, end )
|
||||
{
|
||||
i = start;
|
||||
k = end;
|
||||
|
||||
if (end - start >= 1)
|
||||
{
|
||||
pivot = self.weaponXpEarned[start];
|
||||
|
||||
while (k > i)
|
||||
{
|
||||
while (self.weaponXpEarned[i] <= pivot && i <= end && k > i)
|
||||
i++;
|
||||
while (self.weaponXpEarned[k] > pivot && k >= start && k >= i)
|
||||
k--;
|
||||
if (k > i)
|
||||
self.weaponXpEarned = doubleSwap( i, k );
|
||||
}
|
||||
array = doubleSwap( start, k );
|
||||
array = quickDoubleSortMid(start, k - 1);
|
||||
array = quickDoubleSortMid(k + 1, end);
|
||||
}
|
||||
}
|
||||
doubleSwap(index1, index2)
|
||||
{
|
||||
temp = self.weaponsUsed[index1];
|
||||
self.weaponsUsed[index1] = self.weaponsUsed[index2];
|
||||
self.weaponsUsed[index2] = temp;
|
||||
|
||||
temp2 = self.weaponXpEarned[index1];
|
||||
self.weaponXpEarned[index1] = self.weaponXpEarned[index2];
|
||||
self.weaponXpEarned[index2] = temp2;
|
||||
}
|
||||
*///end recursive nightmare sort.
|
||||
|
||||
|
||||
// log the lives of players who are still alive at match end.
|
||||
gameEndListener()
|
||||
{
|
||||
level waittill ( "game_ended" );
|
||||
|
||||
foreach ( player in level.players )
|
||||
{
|
||||
player logPlayerData();
|
||||
|
||||
if ( !isAlive( player ) )
|
||||
continue;
|
||||
|
||||
player logPlayerLife();
|
||||
}
|
||||
}
|
||||
|
||||
canLogClient( client )
|
||||
{
|
||||
if ( IsAgent( client ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
assertEx( isPlayer( client ) , "Client is not a player: " + client.code_classname );
|
||||
return ( client.clientid < level.MaxLogClients );
|
||||
}
|
||||
|
||||
canLogEvent()
|
||||
{
|
||||
return ( getMatchData( "eventCount" ) < level.MaxEvents );
|
||||
}
|
||||
|
||||
canLogKillstreak()
|
||||
{
|
||||
return ( getMatchData( "killstreakCount" ) < level.MaxKillstreaks );
|
||||
}
|
||||
|
||||
canLogLife( lifeId )
|
||||
{
|
||||
return ( getMatchData( "lifeCount" ) < level.MaxLives );
|
||||
}
|
||||
|
||||
logWeaponStat( weaponName, statName, incValue )
|
||||
{
|
||||
if ( !canLogClient( self ) )
|
||||
return;
|
||||
|
||||
// HACK for gold pdw / knife. This should use weaponMap() but in this
|
||||
// case the weapon is the script base name not the code base
|
||||
// name. Next project no script base names! - JC
|
||||
if ( weaponName == "iw6_pdwauto" )
|
||||
weaponName = "iw6_pdw";
|
||||
else if ( weaponName == "iw6_knifeonlyfast" )
|
||||
weaponName = "iw6_knifeonly";
|
||||
|
||||
if( isKillstreakWeapon( weaponName ) )
|
||||
return;
|
||||
|
||||
self storeWeaponAndAttachmentStats( "weaponStats", weaponName, statName, incValue );
|
||||
}
|
||||
|
||||
logAttachmentStat( weaponName, statName, incValue )
|
||||
{
|
||||
if ( !canLogClient( self ) )
|
||||
return;
|
||||
|
||||
self storeWeaponAndAttachmentStats( "attachmentsStats", weaponName, statName, incValue );
|
||||
}
|
||||
|
||||
storeWeaponAndAttachmentStats( statCategory, weaponName, statName, incValue )
|
||||
{
|
||||
oldValue = GetMatchData( "players", self.clientid, statCategory, weaponName, statName );
|
||||
newValue = oldValue + incValue;
|
||||
|
||||
// these values are bytes - see itemStats in matchdata.def
|
||||
if( statName == "kills" || statName == "deaths" || statName == "headShots" )
|
||||
{
|
||||
if (newValue > 255)
|
||||
newValue = 255;
|
||||
}
|
||||
// we assume the rest to be shorts
|
||||
else if (newValue > 65535)
|
||||
{
|
||||
newValue = 65535;
|
||||
}
|
||||
|
||||
SetMatchData( "players", self.clientid, statCategory, weaponName, statName, newValue );
|
||||
}
|
||||
|
||||
buildBaseWeaponList()
|
||||
{
|
||||
baseWeapons = [];
|
||||
max_weapon_num = 149;
|
||||
for( weaponId = 0; weaponId <= max_weapon_num; weaponId++ )
|
||||
{
|
||||
weapon_name = tablelookup( "mp/statstable.csv", 0, weaponId, 4 );
|
||||
|
||||
// HACK - Make sure the gold knife stats table entries do not get put into the weapon list. - JC
|
||||
if (
|
||||
weapon_name == ""
|
||||
|| weapon_name == "uav"
|
||||
|| weapon_name == "iw6_knifeonlyfast"
|
||||
|| weapon_name == "laser_designator"
|
||||
|| weapon_name == "iw6_pdwauto"
|
||||
)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( !isSubStr( tableLookup( "mp/statsTable.csv", 0, weaponId, 2 ), "weapon_" ) )
|
||||
continue;
|
||||
|
||||
if ( tableLookup( "mp/statsTable.csv", 0, weaponId, 2 ) == "weapon_other" )
|
||||
continue;
|
||||
|
||||
baseWeapons[baseWeapons.size] = weapon_name;
|
||||
}
|
||||
return baseWeapons;
|
||||
}
|
||||
|
||||
logChallenge( challengeName, tier )
|
||||
{
|
||||
if ( !canLogClient( self ) )
|
||||
return;
|
||||
|
||||
// we don't want to log daily and weekly challenges
|
||||
if( IsSubStr( challengeName, "_daily" ) || IsSubStr( challengeName, "_weekly" ) )
|
||||
return;
|
||||
|
||||
challengeCount = getMatchData( "players", self.clientid, "challengeCount" );
|
||||
if( challengeCount < level.MaxNumChallengesPerPlayer )
|
||||
{
|
||||
setMatchData( "players", self.clientid, "challenge", challengeCount, challengeName );
|
||||
setMatchData( "players", self.clientid, "tier", challengeCount, tier );
|
||||
setMatchData( "players", self.clientid, "challengeCount", challengeCount + 1 );
|
||||
}
|
||||
}
|
||||
|
||||
logAward( awardName )
|
||||
{
|
||||
if ( !canLogClient( self ) )
|
||||
return;
|
||||
|
||||
awardCount = getMatchData( "players", self.clientid, "awardCount" );
|
||||
if( awardCount < level.MaxNumAwardsPerPlayer )
|
||||
{
|
||||
setMatchData( "players", self.clientid, "awards", awardCount, awardName );
|
||||
setMatchData( "players", self.clientid, "awardCount", awardCount + 1 );
|
||||
}
|
||||
}
|
||||
|
||||
logKillsConfirmed()
|
||||
{
|
||||
if ( !canLogClient( self ) )
|
||||
return;
|
||||
|
||||
setMatchData( "players", self.clientid, "killsConfirmed", self.pers["confirmed"] );
|
||||
}
|
||||
|
||||
logKillsDenied()
|
||||
{
|
||||
if ( !canLogClient( self ) )
|
||||
return;
|
||||
|
||||
setMatchData( "players", self.clientid, "killsDenied", self.pers["denied"] );
|
||||
}
|
||||
|
||||
logInitialStats()
|
||||
{
|
||||
if ( GetDvarInt( "mdsd" ) > 0 )
|
||||
{
|
||||
setMatchData( "players", self.clientid, "startXp", self getRankedPlayerData( "experience" ) );
|
||||
setMatchData( "players", self.clientid, "startKills", self getRankedPlayerData( "kills" ) );
|
||||
setMatchData( "players", self.clientid, "startDeaths", self getRankedPlayerData( "deaths" ) );
|
||||
setMatchData( "players", self.clientid, "startWins", self getRankedPlayerData( "wins" ) );
|
||||
setMatchData( "players", self.clientid, "startLosses", self getRankedPlayerData( "losses" ) );
|
||||
setMatchData( "players", self.clientid, "startHits", self getRankedPlayerData( "hits" ) );
|
||||
setMatchData( "players", self.clientid, "startMisses", self getRankedPlayerData( "misses" ) );
|
||||
setMatchData( "players", self.clientid, "startGamesPlayed", self getRankedPlayerData( "gamesPlayed" ) );
|
||||
setMatchData( "players", self.clientid, "startTimePlayedTotal", self getRankedPlayerData( "timePlayedTotal" ) );
|
||||
setMatchData( "players", self.clientid, "startScore", self getRankedPlayerData( "score" ) );
|
||||
setMatchData( "players", self.clientid, "startUnlockPoints", self getRankedPlayerData( "unlockPoints" ) );
|
||||
setMatchData( "players", self.clientid, "startPrestige", self getRankedPlayerData( "prestige" ) );
|
||||
|
||||
for ( squadMember = 0; squadMember < 10; squadMember++ )
|
||||
{
|
||||
setMatchData( "players", self.clientid, "startCharacterXP", squadMember, self getRankedPlayerData( "characterXP", squadMember ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logFinalStats()
|
||||
{
|
||||
if ( GetDvarInt( "mdsd" ) > 0 )
|
||||
{
|
||||
setMatchData( "players", self.clientid, "endXp", self getRankedPlayerData( "experience" ) );
|
||||
setMatchData( "players", self.clientid, "endKills", self getRankedPlayerData( "kills" ) );
|
||||
setMatchData( "players", self.clientid, "endDeaths", self getRankedPlayerData( "deaths" ) );
|
||||
setMatchData( "players", self.clientid, "endWins", self getRankedPlayerData( "wins" ) );
|
||||
setMatchData( "players", self.clientid, "endLosses", self getRankedPlayerData( "losses" ) );
|
||||
setMatchData( "players", self.clientid, "endHits", self getRankedPlayerData( "hits" ) );
|
||||
setMatchData( "players", self.clientid, "endMisses", self getRankedPlayerData( "misses" ) );
|
||||
setMatchData( "players", self.clientid, "endGamesPlayed", self getRankedPlayerData( "gamesPlayed" ) );
|
||||
setMatchData( "players", self.clientid, "endTimePlayedTotal", self getRankedPlayerData( "timePlayedTotal" ) );
|
||||
setMatchData( "players", self.clientid, "endScore", self getRankedPlayerData( "score" ) );
|
||||
setMatchData( "players", self.clientid, "endUnlockPoints", self getRankedPlayerData( "unlockPoints" ) );
|
||||
setMatchData( "players", self.clientid, "endPrestige", self getRankedPlayerData( "prestige" ) );
|
||||
|
||||
for ( squadMember = 0; squadMember < 10; squadMember++ )
|
||||
{
|
||||
setMatchData( "players", self.clientid, "endCharacterXP", squadMember, self getRankedPlayerData( "characterXP", squadMember ) );
|
||||
}
|
||||
}
|
||||
}
|
532
maps/mp/_matchevents.gsc
Normal file
532
maps/mp/_matchevents.gsc
Normal file
@ -0,0 +1,532 @@
|
||||
#include maps\mp\_utility;
|
||||
#include maps\mp\gametypes\_hud_util;
|
||||
#include common_scripts\utility;
|
||||
|
||||
|
||||
//////////////////////////////////////////////
|
||||
//
|
||||
// Initialization
|
||||
|
||||
|
||||
|
||||
// add this back to common_mp_weapons.csv
|
||||
// nodamage rocket for visual only
|
||||
// weapon,mp/nodamage_rocket_mp
|
||||
|
||||
|
||||
init()
|
||||
{
|
||||
level.match_events_fx["smoke"] = loadFx( "fx/smoke/smoke_grenade_11sec_mp" );
|
||||
level.match_events_fx["tracer"] = loadFx( "fx/misc/tracer_incoming" );
|
||||
level.match_events_fx["explosion"] = loadFx( "fx/explosions/building_explosion_huge_gulag" );
|
||||
|
||||
|
||||
//precacheItem( "nodamage_rocket_mp" );
|
||||
|
||||
level.matchEvents["mortar"] = ::doMortar;
|
||||
level.matchEvents["smoke"] = ::doSmoke;
|
||||
level.matchEvents["airstrike"] = ::doAirstrike;
|
||||
level.matchEvents["pavelow"] = ::doPavelow;
|
||||
level.matchEvents["heli_insertion"] = ::doHeliInsertion;
|
||||
level.matchEvents["osprey_insertion"] = ::doOspreyInsertion;
|
||||
|
||||
level.matchEventStarted = false;
|
||||
level thread onPlayerConnect();
|
||||
}
|
||||
|
||||
|
||||
onPlayerConnect()
|
||||
{
|
||||
if ( level.prematchPeriod > 0 )
|
||||
{
|
||||
for ( ;; )
|
||||
{
|
||||
level waittill( "connected", player );
|
||||
//player thread onPlayerSpawned();
|
||||
//player thread doHeliInsertion();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
onPlayerSpawned()
|
||||
{
|
||||
self endon( "disconnect" );
|
||||
level endon( "matchevent_started" );
|
||||
//level.alliesInsertChopper endon ("stopLinking");
|
||||
|
||||
self waittill( "spawned_player" );
|
||||
|
||||
if ( isDefined( level.alliesInsertChopper ) && !level.alliesInsertChopper.droppedOff && level.prematchPeriod > 0 && self.team == "allies")
|
||||
{
|
||||
self PlayerLinkTo( level.alliesInsertChopper );
|
||||
level.alliesInsertChopper.linkedPlayers[level.alliesInsertChopper.linkedPlayers.size] = self;
|
||||
}
|
||||
else if ( isDefined( level.alliesInsertChopper ) && !level.alliesInsertChopper.droppedOff && level.prematchPeriod > 0 && self.team == "axis")
|
||||
{
|
||||
self PlayerLinkTo( level.axisInsertChopper );
|
||||
level.axisInsertChopper.linkedPlayers[level.axisInsertChopper.linkedPlayers.size] = self;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////
|
||||
//
|
||||
// Utilities
|
||||
|
||||
|
||||
getMapCenter()
|
||||
{
|
||||
if ( isDefined( level.mapCenter ) )
|
||||
return level.mapCenter;
|
||||
|
||||
alliesStart = GetSpawnArray( "mp_tdm_spawn_allies_start");
|
||||
axisStart = GetSpawnArray( "mp_tdm_spawn_axis_start");
|
||||
if ( isDefined( alliesStart ) && isDefined( alliesStart[0] ) && isDefined( axisStart ) && isDefined( axisStart[0] ) )
|
||||
{
|
||||
halfDist = Distance( alliesStart[0].origin, axisStart[0].origin ) / 2;
|
||||
dir = vectorToAngles( alliesStart[0].origin - axisStart[0].origin );
|
||||
dir = vectorNormalize( dir );
|
||||
return alliesStart[0].origin + dir*halfDist;
|
||||
}
|
||||
return (0,0,0);
|
||||
}
|
||||
|
||||
|
||||
getStartSpawns()
|
||||
{
|
||||
alliesStart = GetSpawnArray( "mp_tdm_spawn_allies_start");
|
||||
axisStart = GetSpawnArray( "mp_tdm_spawn_axis_start");
|
||||
|
||||
if ( isDefined( alliesStart ) && isDefined( alliesStart[0] ) && isDefined( axisStart ) && isDefined( axisStart[0] ) )
|
||||
{
|
||||
startSpawns = [];
|
||||
startSpawns["axis"] = axisStart;
|
||||
startSpawns["allies"] = alliesStart;
|
||||
|
||||
return startSpawns;
|
||||
}
|
||||
else
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////
|
||||
//
|
||||
// Event - Heli Insertion
|
||||
|
||||
doHeliInsertion( teamHeli, axisPoint, alliesPoint )
|
||||
{
|
||||
spawnHeight = 1200;
|
||||
hoverOffset = 1200;
|
||||
leaveOffset = 1000;
|
||||
|
||||
if( !isdefined( teamHeli ) )
|
||||
teamHeli = "both";
|
||||
|
||||
if ( teamHeli == "axis" )
|
||||
{
|
||||
self thread insertaxisInsertChopper( axisPoint );
|
||||
}
|
||||
else if ( teamHeli == "allies" )
|
||||
{
|
||||
self thread insertalliesInsertChopper( alliesPoint );
|
||||
}
|
||||
else
|
||||
{
|
||||
self thread insertalliesInsertChopper( alliesPoint );
|
||||
self thread insertaxisInsertChopper( axisPoint );
|
||||
}
|
||||
}
|
||||
|
||||
insertalliesInsertChopper( pointOverRide )
|
||||
{
|
||||
startSpawns = getStartSpawns();
|
||||
spawnHeight = 1200;
|
||||
hoverOffset = 1200;
|
||||
leaveOffset = 1000;
|
||||
|
||||
if ( !isDefined( pointOverRide ) )
|
||||
pointOverRide = startSpawns["allies"][0];
|
||||
|
||||
// allies chopper
|
||||
forward1 = AnglesToForward( startSpawns["allies"][0].angles ) * 300;
|
||||
up1 = AnglesToUp( startSpawns["allies"][0].angles ) * spawnHeight;
|
||||
right1 = AnglesToRight( startSpawns["allies"][0].angles ) * 3200;
|
||||
left1 = AnglesToRight( startSpawns["allies"][0].angles ) * -3200;
|
||||
rightPos1 = startSpawns["allies"][0].origin+forward1+up1+right1;
|
||||
leftPos1 = startSpawns["allies"][0].origin+forward1+up1+left1;
|
||||
|
||||
alliesInsertChopper = spawnHelicopter( self, rightPos1, startSpawns["allies"][0].angles, "pavelow_mp", "vehicle_pavelow" );
|
||||
if ( !isDefined( alliesInsertChopper ) )
|
||||
return;
|
||||
|
||||
level.alliesInsertChopper = alliesInsertChopper;
|
||||
level.alliesInsertChopper.linkedPlayers = [];
|
||||
level.alliesInsertChopper.droppedOff = false;
|
||||
|
||||
// move to spawn position
|
||||
alliesInsertChopper Vehicle_SetSpeed( 50, 15 );
|
||||
alliesInsertChopper setVehGoalPos( startSpawns["allies"][0].origin + (0,0,hoverOffset/2), 1 );
|
||||
alliesInsertChopper waittill ( "goal" );
|
||||
|
||||
// lower to drop off
|
||||
alliesInsertChopper setyawspeed( 0, 1, 1 );
|
||||
alliesInsertChopper setVehGoalPos( startSpawns["allies"][0].origin + (0,0,hoverOffset/6), 1 );
|
||||
alliesInsertChopper waittill ( "goal" );
|
||||
|
||||
level.alliesInsertChopper.droppedOff = true;
|
||||
|
||||
foreach( player in level.alliesInsertChopper.linkedPlayers )
|
||||
{
|
||||
player Unlink();
|
||||
}
|
||||
|
||||
wait( 2 );
|
||||
|
||||
alliesInsertChopper SetYawSpeed( 60, 40, 40, 0.3 );
|
||||
alliesInsertChopper setVehGoalPos( startSpawns["allies"][0].origin + (0,0,hoverOffset), 1 );
|
||||
alliesInsertChopper waittill ( "goal" );
|
||||
|
||||
// rise to leave
|
||||
|
||||
alliesInsertChopper Vehicle_SetSpeed( 80, 60 );
|
||||
alliesInsertChopper setVehGoalPos( rightPos1+(0,0,leaveOffset)+right1*2, 1 );
|
||||
|
||||
alliesInsertChopper waittill ( "goal" );
|
||||
|
||||
// leave
|
||||
|
||||
alliesInsertChopper Vehicle_SetSpeed( 120, 120 );
|
||||
alliesInsertChopper setVehGoalPos( rightPos1+(0,0,leaveOffset)+right1*2+forward1*-20, 1 );
|
||||
|
||||
alliesInsertChopper waittill ( "goal" );
|
||||
alliesInsertChopper delete();
|
||||
}
|
||||
|
||||
insertaxisInsertChopper( pointOverRide )
|
||||
{
|
||||
startSpawns = getStartSpawns();
|
||||
spawnHeight = 1200;
|
||||
hoverOffset = 1200;
|
||||
leaveOffset = 1000;
|
||||
|
||||
// axis chopper
|
||||
forward1 = AnglesToForward( startSpawns["axis"][0].angles ) * 300;
|
||||
up1 = AnglesToUp( startSpawns["axis"][0].angles ) * spawnHeight;
|
||||
right1 = AnglesToRight( startSpawns["axis"][0].angles ) * 3200;
|
||||
left1 = AnglesToRight( startSpawns["axis"][0].angles ) * -3200;
|
||||
rightPos1 = startSpawns["axis"][0].origin+forward1+up1+right1;
|
||||
leftPos1 = startSpawns["axis"][0].origin+forward1+up1+left1;
|
||||
|
||||
axisInsertChopper = spawnHelicopter( self, rightPos1, startSpawns["axis"][0].angles, "pavelow_mp", "vehicle_pavelow" );
|
||||
if ( !isDefined( axisInsertChopper ) )
|
||||
return;
|
||||
|
||||
level.axisInsertChopper = axisInsertChopper;
|
||||
level.axisInsertChopper.linkedPlayers = [];
|
||||
level.axisInsertChopper.droppedOff = false;
|
||||
|
||||
// move to spawn position
|
||||
axisInsertChopper Vehicle_SetSpeed( 50, 15 );
|
||||
axisInsertChopper setVehGoalPos( startSpawns["axis"][0].origin + (0,0,hoverOffset/2), 1 );
|
||||
axisInsertChopper waittill ( "goal" );
|
||||
|
||||
// lower to drop off
|
||||
axisInsertChopper setyawspeed( 0, 1, 1 );
|
||||
axisInsertChopper setVehGoalPos( startSpawns["axis"][0].origin + (0,0,hoverOffset/6), 1 );
|
||||
axisInsertChopper waittill ( "goal" );
|
||||
|
||||
level.axisInsertChopper.droppedOff = true;
|
||||
|
||||
foreach( player in level.axisInsertChopper.linkedPlayers )
|
||||
{
|
||||
player Unlink();
|
||||
}
|
||||
|
||||
wait( 2 );
|
||||
|
||||
axisInsertChopper SetYawSpeed( 60, 40, 40, 0.3 );
|
||||
axisInsertChopper setVehGoalPos( startSpawns["axis"][0].origin + (0,0,hoverOffset), 1 );
|
||||
axisInsertChopper waittill ( "goal" );
|
||||
|
||||
// rise to leave
|
||||
axisInsertChopper Vehicle_SetSpeed( 80, 60 );
|
||||
axisInsertChopper setVehGoalPos( rightPos1+(0,0,leaveOffset)+right1*2, 1 );
|
||||
|
||||
axisInsertChopper waittill ( "goal" );
|
||||
|
||||
// leave
|
||||
axisInsertChopper Vehicle_SetSpeed( 120, 120 );
|
||||
axisInsertChopper setVehGoalPos( rightPos1+(0,0,leaveOffset)+right1*2+forward1*-20, 1 );
|
||||
|
||||
axisInsertChopper waittill ( "goal" );
|
||||
axisInsertChopper delete();
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////
|
||||
//
|
||||
// Event - Mortar
|
||||
|
||||
|
||||
doMortar()
|
||||
{
|
||||
mapCenter = getMapCenter();
|
||||
offset = 1;
|
||||
for ( i=0; i<5; i++ )
|
||||
{
|
||||
mortarTarget = mapCenter + ( RandomIntRange(100, 600)*offset, RandomIntRange(100, 600)*offset, 0 );
|
||||
|
||||
traceData = BulletTrace( mortarTarget+(0,0,500), mortarTarget-(0,0,500), false );
|
||||
if ( isDefined( traceData["position"] ) )
|
||||
{
|
||||
PlayFx( level.match_events_fx["tracer"], mortarTarget );
|
||||
thread playSoundinSpace( "fast_artillery_round", mortarTarget );
|
||||
|
||||
wait( RandomFloatRange( 0.5, 1.5 ) );
|
||||
|
||||
PlayFx( level.match_events_fx["explosion"], mortarTarget );
|
||||
PlayRumbleOnPosition( "grenade_rumble", mortarTarget );
|
||||
Earthquake( 1.0, 0.6, mortarTarget, 2000 );
|
||||
thread playSoundinSpace( "exp_suitcase_bomb_main", mortarTarget );
|
||||
physicsExplosionSphere( mortarTarget + (0,0,30), 250, 125, 2 );
|
||||
|
||||
offset *= -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////
|
||||
//
|
||||
// Event - Smoke
|
||||
|
||||
|
||||
doSmoke()
|
||||
{
|
||||
mapCenter = getMapCenter();
|
||||
offset = 1;
|
||||
for ( i=0; i<3; i++ )
|
||||
{
|
||||
smokeTarget = mapCenter + ( RandomIntRange(100, 600)*offset, RandomIntRange(100, 600)*offset, 0 );
|
||||
|
||||
PlayFx( level.match_events_fx["smoke"], smokeTarget );
|
||||
offset *= -1;
|
||||
wait( 2 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////
|
||||
//
|
||||
// Event - Airstrike
|
||||
|
||||
|
||||
doAirstrike()
|
||||
{
|
||||
level endon( "game_ended" );
|
||||
|
||||
offset = 1;
|
||||
mapCenter = getMapCenter();
|
||||
for( i = 0; i < 3; i++ )
|
||||
{
|
||||
strikeTarget = mapCenter + ( RandomIntRange(100, 600)*offset, RandomIntRange(100, 600)*offset, 0 );
|
||||
traceData = BulletTrace( strikeTarget+(0,0,500), strikeTarget-(0,0,500), false );
|
||||
if ( isDefined( traceData["position"] ) )
|
||||
{
|
||||
thread doAirstrikeFlyBy( traceData["position"] );
|
||||
offset *= -1;
|
||||
wait ( randomIntRange( 2,4 ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
doAirstrikeFlyBy( strikeTarget )
|
||||
{
|
||||
randSpawn = randomInt( level.spawnPoints.size - 1 );
|
||||
targetPos = level.spawnPoints[randSpawn].origin * (1,1,0);
|
||||
|
||||
backDist = 8000;
|
||||
forwardDist = 8000;
|
||||
heightEnt = GetEnt( "airstrikeheight", "targetname" );
|
||||
|
||||
upVector = (0, 0, heightEnt.origin[2] + randomIntRange(-100, 600) );
|
||||
|
||||
forward = AnglesToForward( (0,randomInt(45),0) );
|
||||
|
||||
startpos = targetPos + upVector + forward * backDist * -1;
|
||||
endPos = targetPos + upVector + forward * forwardDist;
|
||||
|
||||
plane2StartPos = startpos + ( randomIntRange(400,500), randomIntRange(400,500), randomIntRange(200,300) );
|
||||
plane2EndPos = endPos + ( randomIntRange(400,500), randomIntRange(400,500), randomIntRange(200,300) );
|
||||
|
||||
plane = spawnplane( self, "script_model", startpos );
|
||||
plane2 = spawnplane( self, "script_model", plane2StartPos );
|
||||
|
||||
if ( cointoss() )
|
||||
{
|
||||
plane setModel( "vehicle_av8b_harrier_jet_mp" );
|
||||
plane2 setModel( "vehicle_av8b_harrier_jet_mp" );
|
||||
}
|
||||
else
|
||||
{
|
||||
plane setModel( "vehicle_av8b_harrier_jet_opfor_mp" );
|
||||
plane2 setModel( "vehicle_av8b_harrier_jet_opfor_mp" );
|
||||
}
|
||||
|
||||
plane.angles = vectorToAngles( endPos-startPos );
|
||||
plane playloopsound( "veh_mig29_dist_loop" );
|
||||
plane thread playPlaneFx();
|
||||
|
||||
plane2.angles = vectorToAngles( endPos-plane2StartPos );
|
||||
plane2 playloopsound( "veh_mig29_dist_loop" );
|
||||
plane2 thread playPlaneFx();
|
||||
|
||||
length = distance(startPos, endPos);
|
||||
plane moveTo( endPos * 2, length/2000, 0, 0 );
|
||||
wait( randomFloatRange( .25, .5 ) );
|
||||
plane2 moveTo( plane2EndPos * 2, length/2000, 0, 0 );
|
||||
|
||||
//MagicBullet( "nodamage_rocket_mp", plane.origin, strikeTarget );
|
||||
|
||||
wait( length/2000 );
|
||||
plane delete();
|
||||
plane2 delete();
|
||||
}
|
||||
|
||||
playPlaneFx()
|
||||
{
|
||||
self endon ( "death" );
|
||||
|
||||
wait( 0.5);
|
||||
playfxontag( level.fx_airstrike_afterburner, self, "tag_engine_right" );
|
||||
wait( 0.5);
|
||||
playfxontag( level.fx_airstrike_afterburner, self, "tag_engine_left" );
|
||||
wait( 0.5);
|
||||
playfxontag( level.fx_airstrike_contrail, self, "tag_right_wingtip" );
|
||||
wait( 0.5);
|
||||
playfxontag( level.fx_airstrike_contrail, self, "tag_left_wingtip" );
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////
|
||||
//
|
||||
// Event - Pavelow
|
||||
|
||||
|
||||
doPavelow()
|
||||
{
|
||||
mapCenter = getMapCenter();
|
||||
traceData = BulletTrace( mapCenter+(0,0,500), mapCenter-(0,0,500), false );
|
||||
if ( isDefined( traceData["position"] ) )
|
||||
{
|
||||
if ( cointoss() )
|
||||
vehicleModel = "vehicle_pavelow";
|
||||
else
|
||||
vehicleModel = "vehicle_pavelow_opfor";
|
||||
chopper = spawnHelicopter( self, traceData["position"]+(0,0,1000), (0,0,0), "pavelow_mp", vehicleModel );
|
||||
if ( !isDefined( chopper ) )
|
||||
return;
|
||||
|
||||
chopper.team = self.pers["team"];
|
||||
chopper.heli_type = level.heli_types[ vehicleModel ];
|
||||
chopper thread [[ level.lightFxFunc[ level.heli_types[ vehicleModel ] ] ]]();
|
||||
chopper.zOffset = (0,0,chopper getTagOrigin( "tag_origin" )[2] - chopper getTagOrigin( "tag_ground" )[2]);
|
||||
|
||||
wait( 1 );
|
||||
|
||||
playFxOnTag( level.chopper_fx["damage"]["on_fire"], chopper, "tag_engine_left" );
|
||||
chopper thread maps\mp\killstreaks\_helicopter::heli_crash();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////
|
||||
//
|
||||
// Event - Osprey Insertion
|
||||
|
||||
|
||||
doOspreyInsertion()
|
||||
{
|
||||
startSpawns = getStartSpawns();
|
||||
if ( isDefined( startSpawns ) )
|
||||
{
|
||||
spawnHeight = 200;
|
||||
hoverOffset = 200;
|
||||
leaveOffset = 1000;
|
||||
|
||||
// allies osprey
|
||||
|
||||
forward1 = AnglesToForward( startSpawns["allies"][0].angles ) * 300;
|
||||
up1 = AnglesToUp( startSpawns["allies"][0].angles ) * spawnHeight;
|
||||
pos1 = startSpawns["allies"][0].origin+forward1+up1;
|
||||
airShip1 = spawnHelicopter( self, pos1, startSpawns["allies"][0].angles, "osprey_minigun_mp", "vehicle_v22_osprey_body_mp" );
|
||||
if ( !isDefined( airShip1 ) )
|
||||
return;
|
||||
|
||||
// axis osprey
|
||||
|
||||
forward2 = AnglesToForward( startSpawns["axis"][0].angles ) * 300;
|
||||
up2 = AnglesToUp( startSpawns["axis"][0].angles ) * spawnHeight;
|
||||
pos2 = startSpawns["axis"][0].origin+forward2+up2;
|
||||
airShip2 = spawnHelicopter( self, pos2, startSpawns["axis"][0].angles, "osprey_minigun_mp", "vehicle_v22_osprey_body_mp" );
|
||||
if ( !isDefined( airShip2 ) )
|
||||
{
|
||||
airShip1 delete();
|
||||
return;
|
||||
}
|
||||
|
||||
// rise to hover
|
||||
|
||||
airship1 thread maps\mp\killstreaks\_escortairdrop::airShipPitchPropsUp();
|
||||
airship2 thread maps\mp\killstreaks\_escortairdrop::airShipPitchPropsUp();
|
||||
airShip1 thread maps\mp\killstreaks\_escortairdrop::airShipPitchHatchDown();
|
||||
airShip2 thread maps\mp\killstreaks\_escortairdrop::airShipPitchHatchDown();
|
||||
|
||||
airShip1 Vehicle_SetSpeed( 20, 10 );
|
||||
airShip1 SetYawSpeed( 3, 3, 3, 0.3 );
|
||||
airShip1 setVehGoalPos( pos1+(0,0,hoverOffset), 1 );
|
||||
|
||||
airShip2 Vehicle_SetSpeed( 20, 10 );
|
||||
airShip2 SetYawSpeed( 3, 3, 3, 0.3 );
|
||||
airShip2 setVehGoalPos( pos2+(0,0,hoverOffset), 1 );
|
||||
|
||||
airShip1 waittill ( "goal" );
|
||||
|
||||
airShip1 thread maps\mp\killstreaks\_escortairdrop::airShipPitchHatchUp();
|
||||
airShip2 thread maps\mp\killstreaks\_escortairdrop::airShipPitchHatchUp();
|
||||
|
||||
wait( 2 );
|
||||
|
||||
// rise to leave
|
||||
|
||||
airShip1 Vehicle_SetSpeed( 80, 60 );
|
||||
airShip1 SetYawSpeed( 30, 15, 15, 0.3 );
|
||||
airShip1 setVehGoalPos( pos1+(0,0,leaveOffset), 1 );
|
||||
|
||||
airShip2 Vehicle_SetSpeed( 80, 60 );
|
||||
airShip2 SetYawSpeed( 30, 15, 15, 0.3 );
|
||||
airShip2 setVehGoalPos( pos2+(0,0,leaveOffset), 1 );
|
||||
|
||||
airShip1 waittill ( "goal" );
|
||||
|
||||
// leave
|
||||
|
||||
airship1 thread maps\mp\killstreaks\_escortairdrop::airShipPitchPropsDown();
|
||||
airship2 thread maps\mp\killstreaks\_escortairdrop::airShipPitchPropsDown();
|
||||
|
||||
airShip1 Vehicle_SetSpeed( 120, 120 );
|
||||
airShip1 SetYawSpeed( 100, 100, 40, 0.3 );
|
||||
airShip1 setVehGoalPos( pos1+(0,0,leaveOffset)+forward1*-20, 1 );
|
||||
|
||||
airShip2 Vehicle_SetSpeed( 120, 120 );
|
||||
airShip2 SetYawSpeed( 100, 100, 40, 0.3 );
|
||||
airShip2 setVehGoalPos( pos2+(0,0,leaveOffset)+forward2*-20, 1 );
|
||||
|
||||
airShip1 waittill ( "goal" );
|
||||
|
||||
airShip1 delete();
|
||||
airShip2 delete();
|
||||
}
|
||||
}
|
3
maps/mp/_menus.gsc
Normal file
3
maps/mp/_menus.gsc
Normal file
@ -0,0 +1,3 @@
|
||||
init()
|
||||
{
|
||||
}
|
50
maps/mp/_minefields.gsc
Normal file
50
maps/mp/_minefields.gsc
Normal file
@ -0,0 +1,50 @@
|
||||
minefields()
|
||||
{
|
||||
minefields = getentarray("minefield", "targetname");
|
||||
if (minefields.size > 0)
|
||||
{
|
||||
level._effect["mine_explosion"] = loadfx ("vfx/gameplay/explosions/weap/gre/vfx_exp_gre_dirt_cg");
|
||||
}
|
||||
|
||||
for(i = 0; i < minefields.size; i++)
|
||||
{
|
||||
minefields[i] thread minefield_think();
|
||||
}
|
||||
}
|
||||
|
||||
minefield_think()
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
self waittill ("trigger",other);
|
||||
|
||||
if(isPlayer(other))
|
||||
other thread minefield_kill(self);
|
||||
}
|
||||
}
|
||||
|
||||
minefield_kill(trigger)
|
||||
{
|
||||
if(isDefined(self.minefield))
|
||||
return;
|
||||
|
||||
self.minefield = true;
|
||||
// self playsound ("minefield_click");
|
||||
|
||||
wait(.5);
|
||||
wait(randomFloat(.5));
|
||||
|
||||
if(isdefined(self) && self istouching(trigger))
|
||||
{
|
||||
origin = self getorigin();
|
||||
range = 300;
|
||||
maxdamage = 2000;
|
||||
mindamage = 50;
|
||||
|
||||
// self playsound("explo_mine");
|
||||
// playfx(level._effect["mine_explosion"], origin);
|
||||
radiusDamage(origin, range, maxdamage, mindamage);
|
||||
}
|
||||
|
||||
self.minefield = undefined;
|
||||
}
|
660
maps/mp/_movable_cover.gsc
Normal file
660
maps/mp/_movable_cover.gsc
Normal file
@ -0,0 +1,660 @@
|
||||
#include maps\mp\_utility;
|
||||
#include common_scripts\utility;
|
||||
#include maps\mp\gametypes\_hud_util;
|
||||
|
||||
///////
|
||||
// movable_cover
|
||||
///////
|
||||
init()
|
||||
{
|
||||
if( getDvar( "r_reflectionProbeGenerate" ) == "1" )
|
||||
return;
|
||||
|
||||
movable_cover_precache();
|
||||
waitframe();
|
||||
covers = GetEntArray("movable_cover", "targetname");
|
||||
cover_proxy = getstructarray("movable_cover", "targetname");
|
||||
foreach(proxy in cover_proxy)
|
||||
{
|
||||
if(IsDefined(proxy.target))
|
||||
{
|
||||
cover = GetEnt(proxy.target, "targetname");
|
||||
if(IsDefined(cover))
|
||||
{
|
||||
covers[covers.size] = cover;
|
||||
}
|
||||
}
|
||||
}
|
||||
array_thread(covers, ::movable_cover_init);
|
||||
|
||||
}
|
||||
|
||||
movable_cover_precache()
|
||||
{
|
||||
level.movable_cover_use_icons = [];
|
||||
level.movable_cover_use_icons["dumpster"] = "hud_icon_push";
|
||||
|
||||
level.movable_cover_move_sounds = [];
|
||||
level.movable_cover_move_sounds["dumpster"]["start"] = "mp_dumpster_start";
|
||||
level.movable_cover_move_sounds["dumpster"]["move"] = "mp_dumpster_mvmt_loop";
|
||||
level.movable_cover_move_sounds["dumpster"]["stop"] = "mp_dumpster_end";
|
||||
|
||||
level.movable_cover_move_anim = [];
|
||||
level.movable_cover_move_anim["dumpster"] = [];
|
||||
level.movable_cover_move_anim["dumpster"]["move"] = "mp_lonestar_dumpster_jitter";
|
||||
level.movable_cover_move_anim["dumpster"]["idle"] = "mp_lonestar_dumpster_jitter_idle";
|
||||
|
||||
level.movable_cover_default_parameters = [];
|
||||
level.movable_cover_default_parameters["dumpster"] = "goal_radius=1;max_speed=80;accel_time=.8;decel_time=.8;stances=crouch,stand";
|
||||
|
||||
foreach(move_anim_type in level.movable_cover_move_anim)
|
||||
{
|
||||
foreach(move_anim in move_anim_type)
|
||||
{
|
||||
PrecacheMpAnim(move_anim);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
movable_cover_init()
|
||||
{
|
||||
self.moving = false;
|
||||
self.stay = false;
|
||||
self.updatePaths = self.spawnflags & 1;
|
||||
|
||||
self.movable_type = "default";
|
||||
if(IsDefined(self.script_noteworthy))
|
||||
self.movable_type = self.script_noteworthy;
|
||||
|
||||
self movable_cover_parse_parameters();
|
||||
|
||||
//Find End points
|
||||
end_points = [];
|
||||
|
||||
links = self get_links();
|
||||
foreach(link in links)
|
||||
{
|
||||
point = getstruct(link, "script_linkname");
|
||||
if(IsDefined(point) && IsDefined(point.script_label))
|
||||
{
|
||||
point.auto = IsDefined(point.script_parameters) && point.script_parameters=="auto";
|
||||
point.stay = IsDefined(point.script_parameters) && point.script_parameters=="stay";
|
||||
end_points[point.script_label] = point;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
targets = [];
|
||||
if(IsDefined(self.target))
|
||||
{
|
||||
structs = GetStructArray(self.target, "targetname");
|
||||
ents = GetEntArray(self.target, "targetname");
|
||||
targets = array_combine(structs, ents);
|
||||
}
|
||||
|
||||
link_to_ent = self;
|
||||
link_to_tag = undefined;
|
||||
if(IsDefined(level.movable_cover_move_anim[self.movable_type]))
|
||||
{
|
||||
self.animate_ent = spawn("script_model", self.origin);
|
||||
self.animate_ent SetModel("generic_prop_raven");
|
||||
self.animate_ent.angles = self.angles;
|
||||
self.animate_ent linkTo(self);
|
||||
link_to_ent = self.animate_ent;
|
||||
link_to_tag = "j_prop_1";
|
||||
}
|
||||
|
||||
self.linked_ents = [];
|
||||
foreach(target in targets)
|
||||
{
|
||||
if(!IsDefined(target.script_noteworthy))
|
||||
continue;
|
||||
|
||||
switch(target.script_noteworthy)
|
||||
{
|
||||
case "move_trigger":
|
||||
if(!IsDefined(target.script_label) || !IsDefined(end_points[target.script_label]))
|
||||
continue;
|
||||
target EnableLinkTo();
|
||||
target LinkTo(self);
|
||||
self thread movable_cover_trigger(target, end_points[target.script_label]);
|
||||
self thread movable_cover_update_use_icon(target, end_points[target.script_label]);
|
||||
break;
|
||||
case "link":
|
||||
self.linked_ents[self.linked_ents.size] = target;
|
||||
break;
|
||||
case "angels":
|
||||
if(IsDefined(target.angles) && IsDefined(self.animate_ent))
|
||||
self.animate_ent.angles = target.angles;
|
||||
break;
|
||||
case "mantlebrush":
|
||||
self.linked_ents[self.linked_ents.size] = target;
|
||||
//self thread movable_cover_mantlebrush_think( target );
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//link after to make sure the angels on animate_ent is set
|
||||
foreach(ent in self.linked_ents)
|
||||
{
|
||||
if(IsDefined(link_to_tag))
|
||||
{
|
||||
ent LinkTo(link_to_ent, link_to_tag);
|
||||
}
|
||||
else
|
||||
{
|
||||
ent LinkTo(link_to_ent);
|
||||
}
|
||||
}
|
||||
|
||||
//Traversals
|
||||
all_nodes = self getLinknameNodes();
|
||||
self.traverse_nodes = [];
|
||||
foreach(node in all_nodes)
|
||||
{
|
||||
if(!IsDefined(node.type))
|
||||
continue;
|
||||
|
||||
node.node_type = node.script_noteworthy;
|
||||
if(!IsDefined(node.node_type))
|
||||
node.node_type = "closest";
|
||||
|
||||
node_type_valid = false;
|
||||
switch(node.node_type)
|
||||
{
|
||||
case "closest":
|
||||
node_type_valid= true;
|
||||
break;
|
||||
case "radius":
|
||||
case "radius3d": //fallthrough
|
||||
case "radius2d": //fallthrough
|
||||
if(IsDefined(node.target))
|
||||
{
|
||||
target = getstruct(node.target, "targetname");
|
||||
if(IsDefined(target) && IsDefined(target.radius))
|
||||
{
|
||||
node.test_origin = target.origin;
|
||||
node.test_radius = target.radius;
|
||||
node_type_valid= true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
node_type_valid = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if(!node_type_valid)
|
||||
continue;
|
||||
|
||||
if(node.type == "Begin" || node.type == "End")
|
||||
{
|
||||
if(node.type == "Begin")
|
||||
{
|
||||
node.connected_nodes = GetNodeArray(node.target, "targetname");
|
||||
}
|
||||
else //"End"
|
||||
{
|
||||
node.connected_nodes = GetNodeArray(node.targetname, "target");
|
||||
}
|
||||
|
||||
//Disconnect all conenctions to start
|
||||
foreach(connected_node in node.connected_nodes)
|
||||
{
|
||||
DisconnectNodePair(node, connected_node);
|
||||
}
|
||||
|
||||
self.traverse_nodes[self.traverse_nodes.size] = node;
|
||||
}
|
||||
}
|
||||
self movable_cover_connect_traversals(); //Reconnect the closest
|
||||
}
|
||||
|
||||
movable_cover_set_user(user, trigger)
|
||||
{
|
||||
if(!IsDefined(self.user) && IsDefined(user))
|
||||
self notify("new_user");
|
||||
else if(IsDefined(self.user) && IsDefined(user) && self.user!=user)
|
||||
self notify("new_user");
|
||||
else if(IsDefined(self.user) && !IsDefined(user))
|
||||
self notify("clear_user");
|
||||
|
||||
self.user = user;
|
||||
self.user_trigger= trigger;
|
||||
}
|
||||
|
||||
movable_cover_update_use_icon(trigger, move_to)
|
||||
{
|
||||
if(!IsDefined(level.movable_cover_use_icons[self.movable_type]))
|
||||
return;
|
||||
|
||||
while( !IsDefined( level.players ) )
|
||||
{
|
||||
waitframe();
|
||||
continue;
|
||||
}
|
||||
|
||||
show_dist=100;
|
||||
show_dist_sqr = show_dist*show_dist;
|
||||
|
||||
ent_num = trigger GetEntityNumber();
|
||||
trigger_name = "trigger_" + ent_num;
|
||||
while(1)
|
||||
{
|
||||
foreach(player in level.players)
|
||||
{
|
||||
if(!IsDefined(player.movable_cover_huds))
|
||||
player.movable_cover_huds = [];
|
||||
|
||||
dist_sqr = DistanceSquared(player.origin+(0,0,30), trigger.origin);
|
||||
if(dist_sqr<=show_dist_sqr && !self movable_cover_at_goal(move_to.origin))
|
||||
{
|
||||
if(!IsDefined(player.movable_cover_huds[trigger_name]))
|
||||
{
|
||||
player.movable_cover_huds[trigger_name] = movable_cover_use_icon(player, trigger);
|
||||
player.movable_cover_huds[trigger_name].alpha = 0;
|
||||
}
|
||||
|
||||
player.movable_cover_huds[trigger_name] notify("stop_fade");
|
||||
player.movable_cover_huds[trigger_name] thread movable_cover_fade_in_use_icon();
|
||||
}
|
||||
else
|
||||
{
|
||||
if(IsDefined(player.movable_cover_huds[trigger_name]))
|
||||
{
|
||||
player.movable_cover_huds[trigger_name] thread movable_cover_fade_out_use_icon();
|
||||
}
|
||||
}
|
||||
}
|
||||
wait .05;
|
||||
}
|
||||
}
|
||||
|
||||
movable_cover_fade_in_use_icon()
|
||||
{
|
||||
self endon("death");
|
||||
|
||||
if(self.alpha == 1)
|
||||
return;
|
||||
|
||||
self FadeOverTime(.5);
|
||||
self.alpha = 1;
|
||||
}
|
||||
|
||||
movable_cover_fade_out_use_icon()
|
||||
{
|
||||
self endon("death");
|
||||
self endon("stop_fade");
|
||||
|
||||
if(self.alpha == 0)
|
||||
return;
|
||||
|
||||
time = .5;
|
||||
self FadeOverTime(time);
|
||||
self.alpha = 0;
|
||||
wait time;
|
||||
|
||||
self Destroy();
|
||||
}
|
||||
|
||||
movable_cover_use_icon(player, ent)
|
||||
{
|
||||
icon = player createIcon( level.movable_cover_use_icons[self.movable_type], 16, 16 );
|
||||
icon setWayPoint( true, false );
|
||||
icon SetTargetEnt(ent);
|
||||
icon.fading = false;
|
||||
return icon;
|
||||
}
|
||||
|
||||
movable_cover_parse_parameters()
|
||||
{
|
||||
//Init Delfaults
|
||||
self.goal_radius = 1;
|
||||
self.max_speed = 50;
|
||||
self.accel_time = 1;
|
||||
self.decel_time = 1;
|
||||
self.requires_push = 1;
|
||||
self.start_delay = .2;
|
||||
self.stances = ["stand","crouch"];
|
||||
|
||||
if(!IsDefined(self.script_parameters))
|
||||
self.script_parameters = "";
|
||||
|
||||
default_parameters = level.movable_cover_default_parameters[self.movable_type];
|
||||
if(IsDefined(default_parameters))
|
||||
self.script_parameters = default_parameters + self.script_parameters;
|
||||
|
||||
params = StrTok(self.script_parameters, ";");
|
||||
foreach(param in params)
|
||||
{
|
||||
toks = strtok(param,"=");
|
||||
if(toks.size!=2)
|
||||
continue;
|
||||
|
||||
switch(toks[0])
|
||||
{
|
||||
case "goal_radius":
|
||||
self.goal_radius = float(toks[1]);
|
||||
self.goal_radius = max(1,self.goal_radius);
|
||||
break;
|
||||
case "max_speed":
|
||||
self.max_speed = float(toks[1]);
|
||||
break;
|
||||
case "accel_time":
|
||||
self.accel_time = float(toks[1]);
|
||||
break;
|
||||
case "decel_time":
|
||||
self.decel_time = float(toks[1]);
|
||||
self.decel_time = max(0.05,self.decel_time);
|
||||
break;
|
||||
case "stances":
|
||||
self.stances = StrTok(toks[1], ",");
|
||||
break;
|
||||
case "requires_push":
|
||||
self.requires_push = int(toks[1]);
|
||||
break;
|
||||
case "start_delay":
|
||||
self.start_delay = float(toks[1]);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
movable_cover_trigger(trigger, move_to)
|
||||
{
|
||||
auto = move_to.auto;
|
||||
stay = move_to.stay;
|
||||
while(1)
|
||||
{
|
||||
player=undefined;
|
||||
if(auto && !self.stay)
|
||||
{
|
||||
waitframe();
|
||||
if(IsDefined(self.user) && self.user_trigger != trigger)
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
self movable_cover_set_user(undefined, undefined);
|
||||
while(1)
|
||||
{
|
||||
trigger waittill("trigger", player);
|
||||
if(isPlayer(player))
|
||||
break;
|
||||
}
|
||||
self movable_cover_set_user(player, trigger);
|
||||
}
|
||||
|
||||
if(self movable_cover_at_goal(move_to.origin))
|
||||
continue;
|
||||
|
||||
move_dir = VectorNormalize(move_to.origin - self.origin);
|
||||
if(!auto && !self movable_cover_move_delay(self.start_delay, player, trigger, move_dir) )
|
||||
continue;
|
||||
|
||||
dist = Distance(self.origin, move_to.origin);
|
||||
time = dist/self.max_speed;
|
||||
|
||||
if(auto && self.stay && !IsDefined(self.user))
|
||||
continue;
|
||||
|
||||
if(self.moving)
|
||||
continue;
|
||||
|
||||
if(self.updatePaths)
|
||||
self ConnectPaths();
|
||||
self movable_cover_disconnect_traversals();
|
||||
self.moving = true;
|
||||
self.stay = false;
|
||||
|
||||
self notify( "move_start" );
|
||||
|
||||
start_time = GetTime();
|
||||
accel_time = min(time, self.accel_time);
|
||||
if(auto)
|
||||
accel_time = time;
|
||||
|
||||
start_sound = movable_cover_get_sound("start");
|
||||
if(IsDefined(start_sound))
|
||||
self PlaySound(start_sound);
|
||||
|
||||
move_sound = movable_cover_get_sound("move");
|
||||
if(IsDefined(move_sound))
|
||||
self PlayLoopSound(move_sound);
|
||||
|
||||
if(IsDefined(self.animate_ent) && IsDefined(level.movable_cover_move_anim[self.movable_type]["move"]))
|
||||
{
|
||||
self.animate_ent scriptmodelPlayanim(level.movable_cover_move_anim[self.movable_type]["move"]);
|
||||
//self.animate_ent ScriptModelPlayAnimDeltaMotion(level.movable_cover_move_anim[self.movable_type]);
|
||||
}
|
||||
|
||||
self MoveTo(move_to.origin, time, accel_time);
|
||||
|
||||
if(auto)
|
||||
{
|
||||
self movable_cover_wait_for_user_or_timeout(time);
|
||||
}
|
||||
else
|
||||
{
|
||||
while(movable_cover_is_pushed(player, trigger, move_dir) && !self movable_cover_at_goal(move_to.origin))
|
||||
{
|
||||
wait .05;
|
||||
}
|
||||
self movable_cover_set_user(undefined, undefined);
|
||||
}
|
||||
|
||||
if(!self movable_cover_at_goal(move_to.origin))
|
||||
{
|
||||
current_speed_scale = movable_cover_calc_move_speed_scale((GetTime()-start_time)/1000, time, accel_time);
|
||||
current_speed = self.max_speed * current_speed_scale;
|
||||
|
||||
dist = Distance(self.origin, move_to.origin);
|
||||
stop_dist = dist;
|
||||
if(current_speed>0)
|
||||
{
|
||||
stop_dist = min(dist,current_speed*self.decel_time);
|
||||
}
|
||||
time = (2*stop_dist)/self.max_speed;
|
||||
self MoveTo(self.origin+(stop_dist*move_dir),time, 0, time);
|
||||
wait time;
|
||||
}
|
||||
|
||||
self StopLoopSound();
|
||||
|
||||
stop_sound = movable_cover_get_sound("stop");
|
||||
if(IsDefined(stop_sound))
|
||||
self PlaySound(stop_sound);
|
||||
if(IsDefined(self.animate_ent) && IsDefined(level.movable_cover_move_anim[self.movable_type]["idle"]))
|
||||
{
|
||||
self.animate_ent scriptmodelPlayanim(level.movable_cover_move_anim[self.movable_type]["idle"]);
|
||||
}
|
||||
|
||||
if(stay && self movable_cover_at_goal(move_to.origin))
|
||||
{
|
||||
self.stay = true;
|
||||
}
|
||||
|
||||
if(self.updatePaths)
|
||||
self DisconnectPaths();
|
||||
self movable_cover_connect_traversals();
|
||||
self.moving = false;
|
||||
|
||||
self notify( "move_end" );
|
||||
}
|
||||
}
|
||||
|
||||
movable_cover_connect_traversals()
|
||||
{
|
||||
self movable_cover_disconnect_traversals();
|
||||
foreach(node in self.traverse_nodes)
|
||||
{
|
||||
switch(node.node_type)
|
||||
{
|
||||
case "closest":
|
||||
node.connected_to = getClosest(node.origin, node.connected_nodes);
|
||||
break;
|
||||
case "radius":
|
||||
case "radius3d": //fallthrough
|
||||
dist = Distance(node.origin, node.test_origin);
|
||||
if(dist<=node.test_radius)
|
||||
node.connected_to = node.connected_nodes[0];
|
||||
break;
|
||||
case "radius2d":
|
||||
dist2d = Distance2d(node.origin, node.test_origin);
|
||||
if(dist2d<=node.test_radius)
|
||||
node.connected_to = node.connected_nodes[0];
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if(IsDefined(node.connected_to))
|
||||
{
|
||||
ConnectNodePair(node, node.connected_to);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
movable_cover_disconnect_traversals()
|
||||
{
|
||||
foreach(node in self.traverse_nodes)
|
||||
{
|
||||
if(IsDefined(node.connected_to))
|
||||
{
|
||||
DisconnectNodePair(node, node.connected_to);
|
||||
node.connected_to = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
movable_cover_get_sound(type)
|
||||
{
|
||||
if(!IsDefined(level.movable_cover_move_sounds[self.movable_type]))
|
||||
return undefined;
|
||||
|
||||
return level.movable_cover_move_sounds[self.movable_type][type];
|
||||
}
|
||||
|
||||
movable_cover_wait_for_user_or_timeout(time)
|
||||
{
|
||||
self endon("new_user");
|
||||
wait time;
|
||||
}
|
||||
|
||||
movable_cover_calc_move_speed_scale(current_time, move_time, accel_time, decel_time)
|
||||
{
|
||||
if(!IsDefined(accel_time))
|
||||
accel_time = 0;
|
||||
if(!IsDefined(decel_time))
|
||||
decel_time = 0;
|
||||
|
||||
if(current_time >= move_time || current_time <= 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if(current_time < accel_time)
|
||||
{
|
||||
return 1 - ((accel_time - current_time) / accel_time);
|
||||
}
|
||||
else if(current_time > (move_time - decel_time))
|
||||
{
|
||||
return 1 - ((current_time - (move_time - decel_time)) / decel_time);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
movable_cover_is_pushed(player, trigger, move_dir)
|
||||
{
|
||||
//We have the player check so that the trigger doesn't error out when a dog enters.
|
||||
if( !IsDefined( player ) || !IsReallyAlive( player ) || !IsPlayer( player) )
|
||||
return false;
|
||||
|
||||
if(!movable_cover_is_touched(trigger, player))
|
||||
return false;
|
||||
|
||||
if(player IsMantling())
|
||||
return false;
|
||||
|
||||
stance = player GetStance();
|
||||
if(!array_contains(self.stances, stance))
|
||||
return false;
|
||||
|
||||
if(self.requires_push)
|
||||
{
|
||||
player_move_dir = player GetNormalizedMovement();
|
||||
player_move_dir = RotateVector(player_move_dir, -1*player.angles);
|
||||
player_move_dir = VectorNormalize((player_move_dir[0], -1*player_move_dir[1], 0));
|
||||
dot = VectorDot(move_dir, player_move_dir);
|
||||
return dot>0.2;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
movable_cover_is_touched(trigger, player)
|
||||
{
|
||||
return IsDefined( player ) && isReallyAlive( player ) && player IsTouching(trigger);
|
||||
}
|
||||
|
||||
movable_cover_move_delay(delay, player, trigger, move_dir)
|
||||
{
|
||||
endTime = (delay*1000)+GetTime();
|
||||
|
||||
while(1)
|
||||
{
|
||||
if( !IsDefined( player ) || !isReallyAlive( player ) )
|
||||
return false;
|
||||
|
||||
if(player IsMantling())
|
||||
return false;
|
||||
|
||||
if(!movable_cover_is_pushed(player, trigger, move_dir))
|
||||
return false;
|
||||
|
||||
if(self.moving)
|
||||
return false;
|
||||
|
||||
if(getTime()>=endTime)
|
||||
return true;
|
||||
|
||||
wait .05;
|
||||
}
|
||||
}
|
||||
|
||||
movable_cover_at_goal(goal)
|
||||
{
|
||||
distSqr = DistanceSquared(self.origin, goal);
|
||||
|
||||
return distSqr<=(self.goal_radius*self.goal_radius);
|
||||
}
|
||||
|
||||
// Make movers unmantleable while moving - avoids animating into solid architecture
|
||||
movable_cover_mantlebrush_think( mantlebrush )// self = mover
|
||||
{
|
||||
self endon("death");
|
||||
|
||||
while(1)
|
||||
{
|
||||
self waittill( "move_start" );
|
||||
if ( IsDefined( mantlebrush ) )
|
||||
{
|
||||
mantlebrush.old_contents = mantlebrush SetContents( 0 );
|
||||
mantlebrush Hide();
|
||||
}
|
||||
self waittill( "move_end" );
|
||||
if ( IsDefined( mantlebrush ) )
|
||||
{
|
||||
mantlebrush Show();
|
||||
mantlebrush SetContents( mantlebrush.old_contents );
|
||||
}
|
||||
}
|
||||
}
|
1289
maps/mp/_movers.gsc
Normal file
1289
maps/mp/_movers.gsc
Normal file
File diff suppressed because it is too large
Load Diff
223
maps/mp/_radiation.gsc
Normal file
223
maps/mp/_radiation.gsc
Normal file
@ -0,0 +1,223 @@
|
||||
#include maps\mp\_utility;
|
||||
#include common_scripts\utility;
|
||||
|
||||
radiation()
|
||||
{
|
||||
radiationFields = getentarray("radiation", "targetname");
|
||||
|
||||
if (radiationFields.size > 0)
|
||||
{
|
||||
foreach ( trigger in radiationFields )
|
||||
trigger thread common_scripts\_dynamic_world::triggerTouchThink( ::playerEnterArea, ::playerLeaveArea );
|
||||
|
||||
thread onPlayerConnect();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
onPlayerConnect()
|
||||
{
|
||||
for ( ;; )
|
||||
{
|
||||
level waittill ( "connected", player );
|
||||
player.numAreas = 0;
|
||||
}
|
||||
}
|
||||
|
||||
playerEnterArea( trigger )
|
||||
{
|
||||
self.numAreas++;
|
||||
|
||||
if ( self.numAreas == 1 )
|
||||
self radiationEffect();
|
||||
}
|
||||
|
||||
|
||||
playerLeaveArea( trigger )
|
||||
{
|
||||
self.numAreas--;
|
||||
assert( self.numAreas >= 0 );
|
||||
|
||||
if ( self.numAreas != 0 )
|
||||
return;
|
||||
|
||||
self.poison = 0;
|
||||
self notify( "leftTrigger");
|
||||
|
||||
if ( isDefined( self.radiationOverlay ) )
|
||||
self.radiationOverlay fadeoutBlackOut( .10, 0 );
|
||||
}
|
||||
|
||||
soundWatcher( soundOrg )
|
||||
{
|
||||
self waittill_any( "death", "leftTrigger" );
|
||||
|
||||
self stopLoopSound();
|
||||
}
|
||||
|
||||
radiationEffect()
|
||||
{
|
||||
self endon( "disconnect" );
|
||||
self endon( "game_ended" );
|
||||
self endon( "death" );
|
||||
self endon( "leftTrigger" );
|
||||
|
||||
self.poison = 0;
|
||||
self thread soundWatcher( self );
|
||||
|
||||
while (1)
|
||||
{
|
||||
self.poison ++;
|
||||
|
||||
switch( self.poison )
|
||||
{
|
||||
case 1:
|
||||
self.radiationSound = "item_geigercouner_level2";
|
||||
self playLoopSound( self.radiationSound );
|
||||
self ViewKick( 1, self.origin );
|
||||
break;
|
||||
case 3:
|
||||
self shellshock( "mp_radiation_low", 4);
|
||||
self.radiationSound = "item_geigercouner_level3";
|
||||
self stopLoopSound();
|
||||
self playLoopSound( self.radiationSound );
|
||||
self ViewKick( 3, self.origin );
|
||||
self doRadiationDamage(15);
|
||||
break;
|
||||
case 4:
|
||||
self shellshock( "mp_radiation_med", 5);
|
||||
self.radiationSound = "item_geigercouner_level3";
|
||||
self stopLoopSound();
|
||||
self playLoopSound( self.radiationSound );
|
||||
self ViewKick( 15, self.origin );
|
||||
self thread blackout();
|
||||
self doRadiationDamage(25);
|
||||
break;
|
||||
case 6:
|
||||
self shellshock( "mp_radiation_high", 5);
|
||||
self.radiationSound = "item_geigercouner_level4";
|
||||
self stopLoopSound();
|
||||
self playLoopSound( self.radiationSound );
|
||||
self ViewKick( 75, self.origin );
|
||||
self doRadiationDamage(45);
|
||||
break;
|
||||
case 8:
|
||||
self shellshock( "mp_radiation_high", 5);
|
||||
self.radiationSound = "item_geigercouner_level4";
|
||||
self stopLoopSound();
|
||||
self playLoopSound( self.radiationSound );
|
||||
self ViewKick( 127, self.origin );
|
||||
self doRadiationDamage(175);
|
||||
|
||||
break;
|
||||
}
|
||||
wait(1);
|
||||
}
|
||||
wait(5);
|
||||
}
|
||||
blackout( )
|
||||
{
|
||||
self endon( "disconnect" );
|
||||
self endon( "game_ended" );
|
||||
self endon( "death" );
|
||||
self endon( "leftTrigger" );
|
||||
|
||||
if ( !isDefined( self.radiationOverlay ) )
|
||||
{
|
||||
self.radiationOverlay = newClientHudElem( self );
|
||||
self.radiationOverlay.x = 0;
|
||||
self.radiationOverlay.y = 0;
|
||||
self.radiationOverlay setshader( "black", 640, 480 );
|
||||
self.radiationOverlay.alignX = "left";
|
||||
self.radiationOverlay.alignY = "top";
|
||||
self.radiationOverlay.horzAlign = "fullscreen";
|
||||
self.radiationOverlay.vertAlign = "fullscreen";
|
||||
self.radiationOverlay.alpha = 0;
|
||||
}
|
||||
|
||||
min_length = 1;
|
||||
max_length = 2;
|
||||
min_alpha = .25;
|
||||
max_alpha = 1;
|
||||
|
||||
min_percent = 5;
|
||||
max_percent = 100;
|
||||
|
||||
fraction = 0;
|
||||
|
||||
for ( ;; )
|
||||
{
|
||||
while ( self.poison > 1 )
|
||||
{
|
||||
percent_range = max_percent - min_percent;
|
||||
fraction = ( self.poison - min_percent ) / percent_range;
|
||||
|
||||
if ( fraction < 0 )
|
||||
fraction = 0;
|
||||
else if ( fraction > 1 )
|
||||
fraction = 1;
|
||||
|
||||
length_range = max_length - min_length;
|
||||
length = min_length + ( length_range * ( 1 - fraction ) );
|
||||
|
||||
alpha_range = max_alpha - min_alpha;
|
||||
alpha = min_alpha + ( alpha_range * fraction );
|
||||
|
||||
end_alpha = fraction * 0.5;
|
||||
|
||||
if ( fraction == 1 )
|
||||
break;
|
||||
|
||||
duration = length / 2;
|
||||
|
||||
self.radiationOverlay fadeinBlackOut( duration, alpha );
|
||||
self.radiationOverlay fadeoutBlackOut( duration, end_alpha);
|
||||
|
||||
// wait a variable amount based on self.radiation.totalpercent, this is the space in between pulses
|
||||
//wait 1;
|
||||
wait( fraction * 0.5 );
|
||||
}
|
||||
|
||||
if ( fraction == 1 )
|
||||
break;
|
||||
|
||||
if ( self.radiationOverlay.alpha != 0 )
|
||||
self.radiationOverlay fadeoutBlackOut( 1, 0);
|
||||
|
||||
wait 0.05;
|
||||
}
|
||||
self.radiationOverlay fadeinBlackOut( 2, 0);
|
||||
}
|
||||
|
||||
doRadiationDamage( iDamage )
|
||||
{
|
||||
// TODO: make a radiation weapon instead of using the claymore, so we can track kills correctly, also so we can do the correct check in _damage.gsc for attackerIsInflictorVictim
|
||||
|
||||
self thread [[ level.callbackPlayerDamage ]](
|
||||
self,// eInflictor The entity that causes the damage.( e.g. a turret )
|
||||
self,// eAttacker The entity that is attacking.
|
||||
iDamage,// iDamage Integer specifying the amount of damage done
|
||||
0,// iDFlags Integer specifying flags that are to be applied to the damage
|
||||
"MOD_SUICIDE",// sMeansOfDeath Integer specifying the method of death
|
||||
"claymore_mp",// sWeapon The weapon number of the weapon used to inflict the damage
|
||||
self.origin,// vPoint The point the damage is from?
|
||||
( 0,0,0 ) - self.origin,// vDir The direction of the damage
|
||||
"none",// sHitLoc The location of the hit
|
||||
0// psOffsetTime The time offset for the damage
|
||||
);
|
||||
}
|
||||
|
||||
fadeinBlackOut( duration, alpha )
|
||||
{
|
||||
self fadeOverTime( duration );
|
||||
self.alpha = alpha;
|
||||
wait duration;
|
||||
}
|
||||
|
||||
fadeoutBlackOut( duration, alpha )
|
||||
{
|
||||
self fadeOverTime( duration );
|
||||
self.alpha = alpha;
|
||||
wait duration;
|
||||
}
|
||||
|
221
maps/mp/_scoreboard.gsc
Normal file
221
maps/mp/_scoreboard.gsc
Normal file
@ -0,0 +1,221 @@
|
||||
#include maps\mp\_utility;
|
||||
#include common_scripts\utility;
|
||||
|
||||
processLobbyScoreboards()
|
||||
{
|
||||
foreach ( player in level.placement["all"] )
|
||||
player setPlayerScoreboardInfo();
|
||||
|
||||
if( level.multiTeamBased )
|
||||
{
|
||||
buildScoreboardType( "multiteam" );
|
||||
|
||||
foreach ( player in level.players )
|
||||
player setCommonPlayerData( "round", "scoreboardType", "multiteam" );
|
||||
|
||||
setClientMatchData( "alliesScore", -1 );
|
||||
setClientMatchData( "axisScore", -1 );
|
||||
|
||||
setClientMatchData( "alliesKills", -1 );
|
||||
setClientMatchData( "alliesDeaths", -1 );
|
||||
}
|
||||
else if ( level.teamBased )
|
||||
{
|
||||
alliesScore = getTeamScore( "allies" );
|
||||
axisScore = getTeamScore( "axis" );
|
||||
|
||||
kills = 0;
|
||||
deaths = 0;
|
||||
foreach ( player in level.players )
|
||||
{
|
||||
if ( isDefined( player.pers[ "team" ] ) && player.pers[ "team" ] == "allies" )
|
||||
{
|
||||
kills = kills + player.pers[ "kills" ];
|
||||
deaths = deaths + player.pers[ "deaths" ];
|
||||
}
|
||||
}
|
||||
|
||||
setClientMatchData( "alliesScore", alliesScore );
|
||||
setClientMatchData( "axisScore", axisScore );
|
||||
|
||||
setClientMatchData( "alliesKills", kills );
|
||||
setClientMatchData( "alliesDeaths", deaths );
|
||||
|
||||
if ( alliesScore == axisScore )
|
||||
winner = "tied";
|
||||
else if ( alliesScore > axisScore )
|
||||
winner = "allies";
|
||||
else
|
||||
winner = "axis";
|
||||
|
||||
if ( winner == "tied" )
|
||||
{
|
||||
// build both, assign type to your team
|
||||
buildScoreboardType( "allies" );
|
||||
buildScoreboardType( "axis" );
|
||||
|
||||
foreach ( player in level.players )
|
||||
{
|
||||
player_pers_team = player.pers["team"];
|
||||
if ( !IsDefined(player_pers_team) )
|
||||
continue;
|
||||
|
||||
if ( player_pers_team == "spectator" )
|
||||
player setCommonPlayerData( "round", "scoreboardType", "allies" );
|
||||
else
|
||||
player setCommonPlayerData( "round", "scoreboardType", player_pers_team );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// build just winner, assign type to winner
|
||||
buildScoreboardType( winner );
|
||||
|
||||
foreach ( player in level.players )
|
||||
player setCommonPlayerData( "round", "scoreboardType", winner );
|
||||
}
|
||||
}
|
||||
else // not teambased
|
||||
{
|
||||
buildScoreboardType( "neutral" );
|
||||
|
||||
foreach ( player in level.players )
|
||||
player setCommonPlayerData( "round", "scoreboardType", "neutral" );
|
||||
|
||||
setClientMatchData( "alliesScore", -1 );
|
||||
setClientMatchData( "axisScore", -1 );
|
||||
|
||||
setClientMatchData( "alliesKills", -1 );
|
||||
setClientMatchData( "alliesDeaths", -1 );
|
||||
}
|
||||
|
||||
foreach ( player in level.players )
|
||||
{
|
||||
//log xp gains, and the squad member that earned them
|
||||
if ( !isAi(player) && ( privateMatch() || MatchMakingGame() ) )
|
||||
player setCommonPlayerData( "round", "squadMemberIndex", player.pers[ "activeSquadMember" ] );
|
||||
|
||||
player setCommonPlayerData( "round", "totalXp", player.pers["summary"]["xp"] );
|
||||
player setCommonPlayerData( "round", "scoreXp", player.pers["summary"]["score"] );
|
||||
player setCommonPlayerData( "round", "operationXp", player.pers["summary"]["operation"] );
|
||||
player setCommonPlayerData( "round", "challengeXp", player.pers["summary"]["challenge"] );
|
||||
player setCommonPlayerData( "round", "matchXp", player.pers["summary"]["match"] );
|
||||
player setCommonPlayerData( "round", "miscXp", player.pers["summary"]["misc"] );
|
||||
player setCommonPlayerDataReservedInt( "common_entitlement_xp", player.pers["summary"]["entitlementXP"] );
|
||||
player setCommonPlayerDataReservedInt( "common_clan_wars_xp", player.pers["summary"]["clanWarsXP"] );
|
||||
}
|
||||
}
|
||||
|
||||
setPlayerScoreboardInfo()
|
||||
{
|
||||
scoreboardPlayerCount = getClientMatchData( "scoreboardPlayerCount" );
|
||||
if ( scoreboardPlayerCount <= 24 ) //MaxPlayers
|
||||
{
|
||||
setClientMatchData( "players", self.clientMatchDataId, "score", self.pers["score"] );
|
||||
println( "Scoreboard: [" + self.name + "(" + self.clientMatchDataId + ")][score]: " + self.pers["score"] );
|
||||
|
||||
if( IsDefined( level.isHorde ) )
|
||||
{
|
||||
kills = self.pers["hordeKills"];
|
||||
}
|
||||
else
|
||||
{
|
||||
kills = self.pers["kills"];
|
||||
}
|
||||
setClientMatchData( "players", self.clientMatchDataId, "kills", kills );
|
||||
println( "Scoreboard: [" + self.name + "(" + self.clientMatchDataId + ")][kills]: " + kills );
|
||||
|
||||
if( IsDefined( level.isHorde ) )
|
||||
{
|
||||
// Horde revives are stored in the "assists" field for the in-game scoreboard, and also for clientmatchdata.
|
||||
assists = self.pers["hordeRevives"];
|
||||
}
|
||||
else if ( level.gameType == "dm" || level.gameType == "sotf_ffa" || level.gameType == "gun" )
|
||||
{
|
||||
// FFA stores max streak in assists
|
||||
assists = self.assists;
|
||||
}
|
||||
else
|
||||
{
|
||||
assists = self.pers["assists"];
|
||||
}
|
||||
setClientMatchData( "players", self.clientMatchDataId, "assists", assists );
|
||||
println( "Scoreboard: [" + self.name + "(" + self.clientMatchDataId + ")][assists]: " + assists );
|
||||
|
||||
deaths = self.pers["deaths"];
|
||||
setClientMatchData( "players", self.clientMatchDataId, "deaths", deaths );
|
||||
println( "Scoreboard: [" + self.name + "(" + self.clientMatchDataId + ")][deaths]: " + deaths );
|
||||
|
||||
team = self.pers["team"];
|
||||
setClientMatchData( "players", self.clientMatchDataId, "team", team );
|
||||
println( "Scoreboard: [" + self.name + "(" + self.clientMatchDataId + ")][team]: " + team );
|
||||
|
||||
faction = game[self.pers["team"]];
|
||||
setClientMatchData( "players", self.clientMatchDataId, "faction", faction );
|
||||
println( "Scoreboard: [" + self.name + "(" + self.clientMatchDataId + ")][faction]: " + faction );
|
||||
|
||||
extrascore0 = self.pers["extrascore0"];
|
||||
setClientMatchData( "players", self.clientMatchDataId, "extrascore0", extrascore0 );
|
||||
println( "Scoreboard: [" + self.name + "(" + self.clientMatchDataId + ")][extrascore0]: " + extrascore0 );
|
||||
|
||||
println( "Scoreboard: scoreboardPlayerCount was " + scoreboardPlayerCount );
|
||||
scoreboardPlayerCount++;
|
||||
setClientMatchData( "scoreboardPlayerCount", scoreboardPlayerCount );
|
||||
println( "Scoreboard: scoreboardPlayerCount now " + scoreboardPlayerCount );
|
||||
}
|
||||
else
|
||||
{
|
||||
println( "Scoreboard: scoreboardPlayerCount is greater than 24 (" + scoreboardPlayerCount + ")" );
|
||||
}
|
||||
}
|
||||
|
||||
buildScoreboardType( team )
|
||||
{
|
||||
assert( team == "allies" || team == "axis" || team == "neutral" || team == "multiteam" );
|
||||
|
||||
println( "Scoreboard: Building scoreboard (" + team + ")" );
|
||||
|
||||
if ( team == "multiteam" )
|
||||
{
|
||||
index = 0;
|
||||
|
||||
foreach( teamname in level.teamNameList )
|
||||
{
|
||||
foreach ( player in level.placement[teamname] )
|
||||
{
|
||||
setClientMatchData( "scoreboards", "multiteam", index, player.clientMatchDataId );
|
||||
println( "Scoreboard: [scoreboards][" + team + "][" + index + "][" + player.clientMatchDataId + "]" );
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( team == "neutral" )
|
||||
{
|
||||
index = 0;
|
||||
foreach ( player in level.placement["all"] )
|
||||
{
|
||||
setClientMatchData( "scoreboards", team, index, player.clientMatchDataId );
|
||||
println( "Scoreboard: [scoreboards][" + team + "][" + index + "][" + player.clientMatchDataId + "]" );
|
||||
index++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
otherTeam = getOtherTeam( team );
|
||||
|
||||
index = 0;
|
||||
foreach ( player in level.placement[team] )
|
||||
{
|
||||
setClientMatchData( "scoreboards", team, index, player.clientMatchDataId );
|
||||
println( "Scoreboard: [scoreboards][" + team + "][" + index + "][" + player.name + "(" + player.clientMatchDataId + ")]" );
|
||||
index++;
|
||||
}
|
||||
|
||||
foreach ( player in level.placement[otherTeam] )
|
||||
{
|
||||
setClientMatchData( "scoreboards", team, index, player.clientMatchDataId );
|
||||
println( "Scoreboard: [scoreboards][" + team + "][" + index + "][" + player.name + "(" + player.clientMatchDataId + ")]" );
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
179
maps/mp/_shutter.gsc
Normal file
179
maps/mp/_shutter.gsc
Normal file
@ -0,0 +1,179 @@
|
||||
#include common_scripts\utility;
|
||||
#include maps\mp\_utility;
|
||||
main()
|
||||
{
|
||||
// thread windController();
|
||||
level.inc = 0;
|
||||
|
||||
array_levelthread (getentarray("wire","targetname"), ::wireWander);
|
||||
|
||||
leftShutters = getentarray ("shutter_left","targetname");
|
||||
addShutters = getentarray ("shutter_right_open","targetname");
|
||||
for (i=0;i<addShutters.size;i++)
|
||||
leftShutters[leftShutters.size] = addShutters[i];
|
||||
addShutters = getentarray ("shutter_left_closed","targetname");
|
||||
for (i=0;i<addShutters.size;i++)
|
||||
leftShutters[leftShutters.size] = addShutters[i];
|
||||
|
||||
for (i=0;i<leftShutters.size;i++)
|
||||
{
|
||||
shutter = leftShutters[i];
|
||||
shutter rotateto((shutter.angles[0], shutter.angles[1] + 180, shutter.angles[2]), 0.1);
|
||||
}
|
||||
wait (0.2);
|
||||
|
||||
for (i=0;i<leftShutters.size;i++)
|
||||
leftShutters[i].startYaw = leftShutters[i].angles[1];
|
||||
|
||||
rightShutters = getentarray ("shutter_right","targetname");
|
||||
addShutters = getentarray ("shutter_left_open","targetname");
|
||||
for (i=0;i<addShutters.size;i++)
|
||||
rightShutters[rightShutters.size] = addShutters[i];
|
||||
addShutters = getentarray ("shutter_right_closed","targetname");
|
||||
for (i=0;i<addShutters.size;i++)
|
||||
rightShutters[rightShutters.size] = addShutters[i];
|
||||
|
||||
for (i=0;i<rightShutters.size;i++)
|
||||
rightShutters[i].startYaw = rightShutters[i].angles[1];
|
||||
|
||||
addShutters = undefined;
|
||||
|
||||
windDirection = "left";
|
||||
for (;;)
|
||||
{
|
||||
array_levelthread (leftShutters, ::shutterWanderLeft, windDirection);
|
||||
array_levelthread (rightShutters, ::shutterWanderRight, windDirection);
|
||||
level waittill ("wind blows", windDirection);
|
||||
}
|
||||
}
|
||||
|
||||
windController()
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
windDirection = "left";
|
||||
if (randomint(100) > 50)
|
||||
windDirection = "right";
|
||||
level notify ("wind blows", windDirection);
|
||||
wait (2 + randomfloat(10));
|
||||
}
|
||||
}
|
||||
|
||||
shutterWanderLeft(shutter, windDirection)
|
||||
{
|
||||
// println ("shutter angles ", shutter.angles[1]);
|
||||
// assert (shutter.angles[1] >= shutter.startYaw);
|
||||
// assert (shutter.angles[1] < shutter.startYaw + 180);
|
||||
|
||||
// println ("Wind + ", level.inc);
|
||||
level.inc++;
|
||||
level endon ("wind blows");
|
||||
|
||||
newYaw = shutter.startYaw;
|
||||
if (windDirection == "left")
|
||||
newYaw += 179.9;
|
||||
|
||||
newTime = 0.2;
|
||||
shutter rotateto((shutter.angles[0], newYaw, shutter.angles[2]), newTime);
|
||||
wait (newTime + 0.1);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
rot = randomint(80);
|
||||
if (randomint(100) > 50)
|
||||
rot *= -1;
|
||||
|
||||
newYaw = shutter.angles[1] + rot;
|
||||
altYaw = shutter.angles[1] + (rot*-1);
|
||||
if ((newYaw < shutter.startYaw) || (newYaw > shutter.startYaw + 179))
|
||||
{
|
||||
newYaw = altYaw;
|
||||
}
|
||||
|
||||
dif = abs(shutter.angles[1] - newYaw);
|
||||
|
||||
newTime = dif*0.02 + randomfloat(2);
|
||||
if (newTime < 0.3)
|
||||
newTime = 0.3;
|
||||
// println ("startyaw " + shutter.startyaw + " newyaw " + newYaw);
|
||||
|
||||
// assert (newYaw >= shutter.startYaw);
|
||||
// assert (newYaw < shutter.startYaw + 179);
|
||||
|
||||
shutter rotateto((shutter.angles[0], newYaw, shutter.angles[2]), newTime, newTime * 0.5, newTime * 0.5);
|
||||
wait (newTime);
|
||||
}
|
||||
}
|
||||
|
||||
shutterWanderRight(shutter, windDirection)
|
||||
{
|
||||
// println ("shutter angles ", shutter.angles[1]);
|
||||
// assert (shutter.angles[1] >= shutter.startYaw);
|
||||
// assert (shutter.angles[1] < shutter.startYaw + 180);
|
||||
|
||||
// println ("Wind + ", level.inc);
|
||||
level.inc++;
|
||||
level endon ("wind blows");
|
||||
|
||||
newYaw = shutter.startYaw;
|
||||
if (windDirection == "left")
|
||||
newYaw += 179.9;
|
||||
|
||||
newTime = 0.2;
|
||||
shutter rotateto((shutter.angles[0], newYaw, shutter.angles[2]), newTime);
|
||||
wait (newTime + 0.1);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
rot = randomint(80);
|
||||
if (randomint(100) > 50)
|
||||
rot *= -1;
|
||||
|
||||
newYaw = shutter.angles[1] + rot;
|
||||
altYaw = shutter.angles[1] + (rot*-1);
|
||||
if ((newYaw < shutter.startYaw) || (newYaw > shutter.startYaw + 179))
|
||||
{
|
||||
newYaw = altYaw;
|
||||
}
|
||||
|
||||
dif = abs(shutter.angles[1] - newYaw);
|
||||
|
||||
newTime = dif*0.02 + randomfloat(2);
|
||||
if (newTime < 0.3)
|
||||
newTime = 0.3;
|
||||
// println ("startyaw " + shutter.startyaw + " newyaw " + newYaw);
|
||||
|
||||
// assert (newYaw >= shutter.startYaw);
|
||||
// assert (newYaw < shutter.startYaw + 179);
|
||||
|
||||
shutter rotateto((shutter.angles[0], newYaw, shutter.angles[2]), newTime, newTime * 0.5, newTime * 0.5);
|
||||
wait (newTime);
|
||||
}
|
||||
}
|
||||
|
||||
wireWander (wire)
|
||||
{
|
||||
origins = getentarray (wire.target,"targetname");
|
||||
org1 = origins[0].origin;
|
||||
org2 = origins[1].origin;
|
||||
|
||||
angles = vectortoangles (org1 - org2);
|
||||
ent = spawn ("script_model",(0,0,0));
|
||||
ent.origin = ( org1 * 0.5 ) + ( org2 * 0.5 );
|
||||
// ent setmodel ("temp");
|
||||
ent.angles = angles;
|
||||
wire linkto (ent);
|
||||
rottimer = 2;
|
||||
rotrange = 0.9;
|
||||
dist = 4 + randomfloat(2);
|
||||
ent rotateroll(dist*0.5,0.2);
|
||||
wait (0.2);
|
||||
for (;;)
|
||||
{
|
||||
rottime = rottimer + randomfloat (rotRange) - (rotRange * 0.5);
|
||||
ent rotateroll(dist,rottime, rottime*0.5, rottime*0.5);
|
||||
wait (rottime);
|
||||
ent rotateroll(dist * -1,rottime, rottime*0.5, rottime*0.5);
|
||||
wait (rottime);
|
||||
}
|
||||
}
|
319
maps/mp/_stinger.gsc
Normal file
319
maps/mp/_stinger.gsc
Normal file
@ -0,0 +1,319 @@
|
||||
#include maps\mp\_utility;
|
||||
|
||||
InitStingerUsage()
|
||||
{
|
||||
self.stingerStage = undefined;
|
||||
self.stingerTarget = undefined;
|
||||
self.stingerLockStartTime = undefined;
|
||||
self.stingerLostSightlineTime = undefined;
|
||||
|
||||
self thread ResetStingerLockingOnDeath();
|
||||
level.stingerTargets = [];
|
||||
}
|
||||
|
||||
|
||||
ResetStingerLocking()
|
||||
{
|
||||
if ( !IsDefined( self.stingerUseEntered ) )
|
||||
return;
|
||||
self.stingerUseEntered = undefined;
|
||||
|
||||
self notify( "stop_javelin_locking_feedback" );
|
||||
self notify( "stop_javelin_locked_feedback" );
|
||||
|
||||
self WeaponLockFree();
|
||||
InitStingerUsage();
|
||||
}
|
||||
|
||||
|
||||
ResetStingerLockingOnDeath()
|
||||
{
|
||||
self endon( "disconnect" );
|
||||
|
||||
self notify ( "ResetStingerLockingOnDeath" );
|
||||
self endon ( "ResetStingerLockingOnDeath" );
|
||||
|
||||
for ( ;; )
|
||||
{
|
||||
self waittill( "death" );
|
||||
self ResetStingerLocking();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
StillValidStingerLock( ent )
|
||||
{
|
||||
assert( IsDefined( self ) );
|
||||
|
||||
if ( !IsDefined( ent ) )
|
||||
return false;
|
||||
if ( !(self WorldPointInReticle_Circle( ent.origin, 65, 85 )) )
|
||||
return false;
|
||||
|
||||
if ( self.stingerTarget == level.ac130.planeModel && !isDefined( level.ac130player ) )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
LoopStingerLockingFeedback()
|
||||
{
|
||||
self endon( "stop_javelin_locking_feedback" );
|
||||
|
||||
for ( ;; )
|
||||
{
|
||||
if ( isDefined( level.chopper ) && isDefined( level.chopper.gunner ) && isDefined( self.stingerTarget ) && self.stingerTarget == level.chopper.gunner )
|
||||
level.chopper.gunner playLocalSound( "missile_locking" );
|
||||
|
||||
if ( isDefined( level.ac130player ) && isDefined( self.stingerTarget ) && self.stingerTarget == level.ac130.planeModel )
|
||||
level.ac130player playLocalSound( "missile_locking" );
|
||||
|
||||
self playLocalSound( "stinger_locking" );
|
||||
self PlayRumbleOnEntity( "ac130_25mm_fire" );
|
||||
|
||||
wait 0.6;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
LoopStingerLockedFeedback()
|
||||
{
|
||||
self endon( "stop_javelin_locked_feedback" );
|
||||
|
||||
for ( ;; )
|
||||
{
|
||||
if ( isDefined( level.chopper ) && isDefined( level.chopper.gunner ) && isDefined( self.stingerTarget ) && self.stingerTarget == level.chopper.gunner )
|
||||
level.chopper.gunner playLocalSound( "missile_locking" );
|
||||
|
||||
if ( isDefined( level.ac130player ) && isDefined( self.stingerTarget ) && self.stingerTarget == level.ac130.planeModel )
|
||||
level.ac130player playLocalSound( "missile_locking" );
|
||||
|
||||
self playLocalSound( "stinger_locked" );
|
||||
self PlayRumbleOnEntity( "ac130_25mm_fire" );
|
||||
|
||||
wait 0.25;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/#
|
||||
DrawStar( point )
|
||||
{
|
||||
Line( point + (10,0,0), point - (10,0,0) );
|
||||
Line( point + (0,10,0), point - (0,10,0) );
|
||||
Line( point + (0,0,10), point - (0,0,10) );
|
||||
}
|
||||
#/
|
||||
|
||||
|
||||
LockSightTest( target )
|
||||
{
|
||||
eyePos = self GetEye();
|
||||
|
||||
if ( !isDefined( target ) ) //targets can disapear during targeting.
|
||||
return false;
|
||||
|
||||
passed = SightTracePassed( eyePos, target.origin, false, target );
|
||||
if ( passed )
|
||||
return true;
|
||||
|
||||
front = target GetPointInBounds( 1, 0, 0 );
|
||||
passed = SightTracePassed( eyePos, front, false, target );
|
||||
if ( passed )
|
||||
return true;
|
||||
|
||||
back = target GetPointInBounds( -1, 0, 0 );
|
||||
passed = SightTracePassed( eyePos, back, false, target );
|
||||
if ( passed )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
StingerDebugDraw( target )
|
||||
{
|
||||
/#
|
||||
if ( GetDVar( "missileDebugDraw" ) != "1" )
|
||||
return;
|
||||
if ( !IsDefined( target ) )
|
||||
return;
|
||||
|
||||
org = target.origin;
|
||||
DrawStar( org );
|
||||
org = target GetPointInBounds( 1, 0, 0 );
|
||||
DrawStar( org );
|
||||
org = target GetPointInBounds( -1, 0, 0 );
|
||||
DrawStar( org );
|
||||
#/
|
||||
}
|
||||
|
||||
|
||||
SoftSightTest()
|
||||
{
|
||||
LOST_SIGHT_LIMIT = 500;
|
||||
|
||||
if ( self LockSightTest( self.stingerTarget ) )
|
||||
{
|
||||
self.stingerLostSightlineTime = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( self.stingerLostSightlineTime == 0 )
|
||||
self.stingerLostSightlineTime = getTime();
|
||||
|
||||
timePassed = GetTime() - self.stingerLostSightlineTime;
|
||||
//PrintLn( "Losing sight of target [", timePassed, "]..." );
|
||||
|
||||
if ( timePassed >= LOST_SIGHT_LIMIT )
|
||||
{
|
||||
//PrintLn( "Lost sight of target." );
|
||||
ResetStingerLocking();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
StingerUsageLoop()
|
||||
{
|
||||
if ( !IsPlayer(self) )
|
||||
return;
|
||||
|
||||
self endon("death");
|
||||
self endon("disconnect");
|
||||
self endon("faux_spawn");
|
||||
|
||||
LOCK_LENGTH = 1000;
|
||||
|
||||
InitStingerUsage();
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
wait 0.05;
|
||||
|
||||
if ( self PlayerADS() < 0.95 )
|
||||
{
|
||||
ResetStingerLocking();
|
||||
continue;
|
||||
}
|
||||
|
||||
weapon = self getCurrentWeapon();
|
||||
|
||||
if ( weapon != "stinger_mp" && weapon != "at4_mp" && weapon != "iw5_smaw_mp" )
|
||||
{
|
||||
ResetStingerLocking();
|
||||
continue;
|
||||
}
|
||||
|
||||
self.stingerUseEntered = true;
|
||||
|
||||
if ( !IsDefined( self.stingerStage ) )
|
||||
self.stingerStage = 0;
|
||||
|
||||
StingerDebugDraw( self.stingerTarget );
|
||||
|
||||
if ( self.stingerStage == 0 ) // searching for target
|
||||
{
|
||||
targets = maps\mp\gametypes\_weapons::lockOnLaunchers_getTargetArray();
|
||||
if ( targets.size == 0 )
|
||||
continue;
|
||||
|
||||
targetsInReticle = [];
|
||||
foreach ( target in targets )
|
||||
{
|
||||
if ( !isDefined( target ) )
|
||||
continue;
|
||||
|
||||
insideReticle = self WorldPointInReticle_Circle( target.origin, 65, 75 );
|
||||
|
||||
if ( insideReticle )
|
||||
targetsInReticle[targetsInReticle.size] = target;
|
||||
}
|
||||
if ( targetsInReticle.size == 0 )
|
||||
continue;
|
||||
|
||||
sortedTargets = SortByDistance( targetsInReticle, self.origin );
|
||||
if ( !( self LockSightTest( sortedTargets[0] ) ) )
|
||||
continue;
|
||||
|
||||
//PrintLn( "Found a target to lock to..." );
|
||||
thread LoopStingerLockingFeedback();
|
||||
self.stingerTarget = sortedTargets[0];
|
||||
self.stingerLockStartTime = GetTime();
|
||||
self.stingerStage = 1;
|
||||
self.stingerLostSightlineTime = 0;
|
||||
}
|
||||
|
||||
if ( self.stingerStage == 1 ) // locking on to a target
|
||||
{
|
||||
if ( !(self StillValidStingerLock( self.stingerTarget )) )
|
||||
{
|
||||
//PrintLn( "Failed to get lock." );
|
||||
ResetStingerLocking();
|
||||
continue;
|
||||
}
|
||||
|
||||
passed = SoftSightTest();
|
||||
if ( !passed )
|
||||
continue;
|
||||
|
||||
timePassed = getTime() - self.stingerLockStartTime;
|
||||
//PrintLn( "Locking [", timePassed, "]..." );
|
||||
if( self _hasPerk( "specialty_fasterlockon" ) )
|
||||
{
|
||||
if( timePassed < ( LOCK_LENGTH * 0.5 ) )
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( timePassed < LOCK_LENGTH )
|
||||
continue;
|
||||
}
|
||||
|
||||
self notify( "stop_javelin_locking_feedback" );
|
||||
thread LoopStingerLockedFeedback();
|
||||
|
||||
//PrintLn( "Locked!");
|
||||
if( checkVehicleModelForLock( self.stingerTarget.model ) )
|
||||
self WeaponLockFinalize( self.stingerTarget );
|
||||
else if ( isPlayer( self.stingerTarget ) )
|
||||
self WeaponLockFinalize( self.stingerTarget, ( 100,0, 64 ) );
|
||||
else
|
||||
self WeaponLockFinalize( self.stingerTarget, ( 100,0,-32 ) );
|
||||
|
||||
self.stingerStage = 2;
|
||||
}
|
||||
|
||||
if ( self.stingerStage == 2 ) // target locked
|
||||
{
|
||||
passed = SoftSightTest();
|
||||
if ( !passed )
|
||||
continue;
|
||||
|
||||
if ( !(self StillValidStingerLock( self.stingerTarget )) )
|
||||
{
|
||||
//PrintLn( "Gave up lock." );
|
||||
ResetStingerLocking();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
checkVehicleModelForLock( model )
|
||||
{
|
||||
switch( model )
|
||||
{
|
||||
case "vehicle_av8b_harrier_jet_opfor_mp":
|
||||
case "vehicle_av8b_harrier_jet_mp":
|
||||
case "vehicle_ugv_talon_mp":
|
||||
return true;
|
||||
default:
|
||||
if( model == level.littlebird_model )
|
||||
return true;
|
||||
};
|
||||
|
||||
return false;
|
||||
}
|
1474
maps/mp/_teleport.gsc
Normal file
1474
maps/mp/_teleport.gsc
Normal file
File diff suppressed because it is too large
Load Diff
7455
maps/mp/_utility.gsc
Normal file
7455
maps/mp/_utility.gsc
Normal file
File diff suppressed because it is too large
Load Diff
425
maps/mp/_water.gsc
Normal file
425
maps/mp/_water.gsc
Normal file
@ -0,0 +1,425 @@
|
||||
#include common_scripts\utility;
|
||||
#include maps\mp\_utility;
|
||||
|
||||
waterShallowFx()
|
||||
{
|
||||
level._effect[ "water_kick" ] = LoadFX( "vfx/moments/flood/flood_db_foam_allie_ch_fast_cheap" );
|
||||
level._effect[ "water_splash_emerge" ] = LoadFX( "vfx/moments/flood/flood_db_foam_allie_vertical_splash_sml" );
|
||||
level._effect[ "water_splash_large" ] = LoadFX( "vfx/moments/flood/flood_db_foam_allie_vertical_splash_lrg" );
|
||||
}
|
||||
|
||||
waterShallowInit( waterDeleteZ, waterShallowSplashZ )
|
||||
{
|
||||
if ( IsDefined( waterDeleteZ ) )
|
||||
{
|
||||
level.waterDeleteZ = waterDeleteZ;
|
||||
}
|
||||
|
||||
level.trigUnderWater = GetEnt( "trigger_underwater", "targetname" );
|
||||
level.trigAboveWater = GetEnt( "trigger_abovewater", "targetname" );
|
||||
level.trigUnderWater thread watchPlayerEnterWater( level.trigAboveWater, waterShallowSplashZ );
|
||||
level thread clearWaterVarsOnSpawn( level.trigUnderWater );
|
||||
|
||||
if ( IsDefined( waterDeleteZ ) )
|
||||
{
|
||||
level thread watchEntsInDeepWater( level.trigUnderWater, waterDeleteZ );
|
||||
}
|
||||
}
|
||||
|
||||
watchEntsInDeepWater( trigUnderWater, waterDeleteZ )
|
||||
{
|
||||
level childthread watchEntsInDeepWater_mines( trigUnderWater, waterDeleteZ );
|
||||
level childthread watchEntsInDeepWater_ks( trigUnderWater, waterDeleteZ );
|
||||
}
|
||||
|
||||
CONST_SENTRY_AND_AGENT_OFFSET = 35;
|
||||
CONST_TROPHY_OFFSET = 28;
|
||||
watchEntsInDeepWater_ks( trigUnderWater, waterDeleteZ )
|
||||
{
|
||||
level endon( "game_ended" );
|
||||
|
||||
while ( true )
|
||||
{
|
||||
wait( 0.05 );
|
||||
|
||||
ksToDestroy = level.placedIMS;
|
||||
ksToDestroy = array_combine( ksToDestroy, level.uplinks );
|
||||
ksToDestroy = array_combine( ksToDestroy, level.turrets );
|
||||
|
||||
foreach ( kstreak in ksToDestroy )
|
||||
{
|
||||
if ( !IsDefined( kstreak ) )
|
||||
continue;
|
||||
waterZoverride = ter_op( IsDefined( kstreak.sentrytype ) && kstreak.sentrytype == "sentry_minigun", waterDeleteZ - CONST_SENTRY_AND_AGENT_OFFSET, waterDeleteZ );
|
||||
if ( kstreak.origin[ 2 ] <= waterZoverride && kstreak IsTouching( trigUnderWater ) )
|
||||
{
|
||||
// Destroy ims, uplink or sentry
|
||||
kstreak notify( "death" );
|
||||
}
|
||||
}
|
||||
|
||||
wait( 0.05 );
|
||||
|
||||
foreach ( character in level.characters )
|
||||
{
|
||||
// Damage bots and agents that fall into deep water to prevent AI
|
||||
// from getting stuck. This will do 8% damage 10 times a second.
|
||||
if ( IsDefined( character )
|
||||
&& IsAlive( character )
|
||||
&& IsAI( character )
|
||||
&& character.origin[ 2 ] <= waterDeleteZ - CONST_SENTRY_AND_AGENT_OFFSET // Most AI will early out here
|
||||
&& character IsTouching( trigUnderWater )
|
||||
)
|
||||
{
|
||||
if ( IsAgent( character )
|
||||
&& IsDefined( character.agent_type )
|
||||
&& character.agent_type == "dog"
|
||||
)
|
||||
{
|
||||
if ( !IsDefined(character.spawnTime) || (GetTime() - character.spawnTime) > 2000 ) // Wait till dog has existed for 2s before we destroy him (so that his body can be visible)
|
||||
{
|
||||
// Dogs block DoDamage() code call so use agent damage func
|
||||
character [[ character maps\mp\agents\_agent_utility::agentFunc( "on_damaged" ) ]]( level, undefined, Int( ceil( character.maxhealth * 0.08 ) ), 0, "MOD_CRUSH", "none", ( 0, 0, 0 ), (0, 0, 0), "none", 0 );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
character DoDamage( Int( ceil( character.maxhealth * 0.08 ) ), character.origin );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
watchEntsInDeepWater_mines( trigUnderWater, waterDeleteZ )
|
||||
{
|
||||
level endon( "game_ended" );
|
||||
|
||||
while ( true )
|
||||
{
|
||||
level waittill( "mine_planted" );
|
||||
|
||||
// In case multiple mines land this frame
|
||||
waittillframeend;
|
||||
|
||||
mines = level.mines;
|
||||
foreach ( uId, mine in mines )
|
||||
{
|
||||
if ( !IsDefined( mine ) )
|
||||
continue;
|
||||
|
||||
offset = 0;
|
||||
if ( IsDefined( mine.isTallForWaterChecks ) )
|
||||
offset = CONST_TROPHY_OFFSET;
|
||||
|
||||
if ( mine.origin[ 2 ] <= waterDeleteZ - offset && mine IsTouching( trigUnderWater ) )
|
||||
{
|
||||
mine maps\mp\gametypes\_weapons::deleteExplosive();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
clearWaterVarsOnSpawn( underWater )
|
||||
{
|
||||
level endon ( "game_ended" );
|
||||
|
||||
while ( true )
|
||||
{
|
||||
level waittill( "player_spawned", player );
|
||||
|
||||
if ( !player IsTouching( underWater ) )
|
||||
{
|
||||
player.inWater = undefined;
|
||||
player.underWater = undefined;
|
||||
player notify( "out_of_water" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
watchPlayerEnterWater( aboveWater, waterShallowSplashZ )
|
||||
{
|
||||
level endon( "game_ended" );
|
||||
|
||||
while ( true )
|
||||
{
|
||||
self waittill( "trigger", ent );
|
||||
|
||||
if ( !IsPlayer( ent ) && !IsAgent( ent ) )
|
||||
continue;
|
||||
|
||||
// Don't let dogs die from water because they take
|
||||
// damage all the time due to height
|
||||
if ( !IsAlive( ent ) || ( IsAgent( ent ) && IsDefined( ent.agent_type ) && ent.agent_type == "dog" ) )
|
||||
continue;
|
||||
|
||||
if ( !IsDefined( ent.inWater ) )
|
||||
{
|
||||
ent.inWater = true;
|
||||
ent thread playerInWater( self, aboveWater, waterShallowSplashZ );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
playerSplash()
|
||||
{
|
||||
self endon( "out_of_water" );
|
||||
self endon( "death" );
|
||||
self endon( "disconnect" );
|
||||
|
||||
vel = self GetVelocity();
|
||||
if ( vel[ 2 ] > -100 )
|
||||
return;
|
||||
|
||||
wait( 0.2 );
|
||||
|
||||
vel = self GetVelocity();
|
||||
if ( vel[ 2 ] <= -100 )
|
||||
{
|
||||
self PlaySound( "watersplash_lrg" );
|
||||
PlayFX( level._effect[ "water_splash_large" ], self.origin + (0,0,36), (0,0,1), AnglesToForward( (0,self.angles[1],0) ) );
|
||||
}
|
||||
}
|
||||
|
||||
playerInWater( underWater, aboveWater, waterShallowSplashZ )
|
||||
{
|
||||
level endon( "game_ended" );
|
||||
self endon( "death" );
|
||||
self endon( "disconnect" );
|
||||
|
||||
self thread inWaterWake( waterShallowSplashZ );
|
||||
self thread playerWaterClearWait();
|
||||
|
||||
self thread playerSplash();
|
||||
|
||||
while ( true )
|
||||
{
|
||||
if ( !self IsTouching( underWater ) )
|
||||
{
|
||||
self.inWater = undefined;
|
||||
self.underWater = undefined;
|
||||
self notify( "out_of_water" );
|
||||
stopWaterVisuals();
|
||||
break;
|
||||
}
|
||||
|
||||
if ( !IsDefined( self.underWater ) && !self IsTouching( aboveWater ) )
|
||||
{
|
||||
// if we do want remotes to function in water, we'll need to filter by type
|
||||
if( self.classname == "script_vehicle" )
|
||||
{
|
||||
self notify( "death" );
|
||||
}
|
||||
else
|
||||
{
|
||||
self.underWater = true;
|
||||
self thread playerUnderWater();
|
||||
}
|
||||
}
|
||||
|
||||
// Player emerged from under water and touched above water trigger
|
||||
if ( IsDefined( self.underWater ) && self IsTouching( aboveWater ) )
|
||||
{
|
||||
self.underWater = undefined;
|
||||
self notify( "above_water" );
|
||||
stopWaterVisuals();
|
||||
|
||||
if ( IsPlayer( self ) )
|
||||
{
|
||||
if ( self hasFemaleCustomizationModel() )
|
||||
{
|
||||
self playLocalSound("Fem_breathing_better");
|
||||
}
|
||||
else
|
||||
{
|
||||
self playLocalSound("breathing_better");
|
||||
}
|
||||
}
|
||||
PlayFX( level._effect[ "water_splash_emerge" ], self.origin + (0,0,24) );
|
||||
}
|
||||
|
||||
wait ( 0.05 );
|
||||
}
|
||||
}
|
||||
|
||||
IsActiveKillstreakPoolRestricted( player )
|
||||
{
|
||||
if ( IsDefined( player.killstreakIndexWeapon ) )
|
||||
{
|
||||
streakName = self.pers[ "killstreaks" ][ self.killstreakIndexWeapon ].streakName;
|
||||
if ( IsDefined( streakName ) )
|
||||
{
|
||||
switch ( streakName )
|
||||
{
|
||||
case "remote_uav":
|
||||
case "remote_mg_turret":
|
||||
case "minigun_turret":
|
||||
case "ims":
|
||||
case "sentry":
|
||||
case "remote_tank":
|
||||
case "sam_turret":
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
playerWaterClearWait()
|
||||
{
|
||||
self waittill_any( "death", "disconnect", "out_of_water" );
|
||||
|
||||
if ( !IsDefined( self ) )
|
||||
return;
|
||||
|
||||
self.inWater = undefined;
|
||||
self.underWater = undefined;
|
||||
}
|
||||
|
||||
CONST_WATER_KICK_MIN_MSEC = 200;
|
||||
|
||||
inWaterWake( waterShallowSplashZ )
|
||||
{
|
||||
level endon( "game_ended" );
|
||||
self endon( "death" );
|
||||
self endon( "disconnect" );
|
||||
self endon( "out_of_water" );
|
||||
|
||||
zGround = ter_op( IsDefined( waterShallowSplashZ ), waterShallowSplashZ, self.origin[2] );
|
||||
fxPlayedRecently = false;
|
||||
while ( true )
|
||||
{
|
||||
if ( fxPlayedRecently )
|
||||
wait( 0.05 );
|
||||
else
|
||||
wait( 0.3 );
|
||||
|
||||
if ( !IsDefined( level.waterKickTimeNext ) )
|
||||
{
|
||||
level.waterKickTimeNext = GetTime() + CONST_WATER_KICK_MIN_MSEC;
|
||||
}
|
||||
else
|
||||
{
|
||||
time = GetTime();
|
||||
if ( GetTime() < level.waterKickTimeNext )
|
||||
{
|
||||
fxPlayedRecently = true;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
level.waterKickTimeNext = time + CONST_WATER_KICK_MIN_MSEC;
|
||||
}
|
||||
}
|
||||
|
||||
fxPlayedRecently = false;
|
||||
|
||||
vel = self GetVelocity();
|
||||
|
||||
if ( !IsDefined( waterShallowSplashZ ) )
|
||||
{
|
||||
if ( abs( vel[ 2 ] ) <= 1 )
|
||||
{
|
||||
zGround = self.origin[2];
|
||||
}
|
||||
}
|
||||
|
||||
// Jump
|
||||
if ( abs( vel[ 2 ] ) > 30 )
|
||||
{
|
||||
PlayFX( level._effect[ "water_kick" ], (self.origin[0], self.origin[1], min( zGround, self.origin[2]) ) );
|
||||
}
|
||||
// Running
|
||||
else if ( Length2DSquared( vel ) > 60 * 60 )
|
||||
{
|
||||
fwd = VectorNormalize( ( vel[0], vel[1], 0 ) );
|
||||
PlayFX( level._effect[ "water_kick" ], (self.origin[0], self.origin[1], min( zGround, self.origin[2] )) + fwd * 36, fwd, (0,0,1) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
playerUnderWater()
|
||||
{
|
||||
level endon( "game_ended" );
|
||||
self endon( "death" );
|
||||
self endon( "disconnect" );
|
||||
self endon( "above_water" );
|
||||
self endon( "out_of_water" );
|
||||
|
||||
if ( !self maps\mp\_utility::isUsingRemote() )
|
||||
{
|
||||
self startWaterVisuals();
|
||||
// Disabled underwater bubbles for flooded / all under water maps -JC
|
||||
//self thread underWaterBubbles();
|
||||
// players can glitch into a remote after going underwater
|
||||
self thread stopWaterVisualsOnRemote();
|
||||
}
|
||||
|
||||
PlayFX( level._effect[ "water_splash_emerge" ], self GetEye() - (0,0,24) );
|
||||
|
||||
wait( 2 );
|
||||
self thread onPlayerDrowned();
|
||||
|
||||
while ( true )
|
||||
{
|
||||
self DoDamage( 20, self.origin );
|
||||
wait( 1 );
|
||||
}
|
||||
}
|
||||
|
||||
onPlayerDrowned()
|
||||
{
|
||||
level endon( "game_ended" );
|
||||
self endon( "disconnect" );
|
||||
self endon( "above_water" );
|
||||
self endon( "out_of_water" );
|
||||
|
||||
self waittill( "death" );
|
||||
|
||||
self.inWater = undefined;
|
||||
self.underWater = undefined;
|
||||
}
|
||||
|
||||
underWaterBubbles()
|
||||
{
|
||||
level endon( "game_ended" );
|
||||
self endon( "death" );
|
||||
self endon( "using_remote" );
|
||||
self endon( "disconnect" );
|
||||
self endon( "above_water" );
|
||||
self endon( "out_of_water" );
|
||||
|
||||
while ( true )
|
||||
{
|
||||
PlayFX( level._effect[ "water_bubbles" ], self GetEye() + ( AnglesToUp( self.angles ) * -13 ) + ( AnglesToForward( self.angles ) * 25 ) );
|
||||
wait( 0.75 );
|
||||
}
|
||||
}
|
||||
|
||||
startWaterVisuals()
|
||||
{
|
||||
self ShellShock( "mp_flooded_water", 8 );
|
||||
if ( IsPlayer( self ) )
|
||||
self SetBlurForPlayer( 10, 0.0 );
|
||||
}
|
||||
|
||||
stopWaterVisuals()
|
||||
{
|
||||
self StopShellShock();
|
||||
if ( IsPlayer( self ) )
|
||||
self SetBlurForPlayer( 0, 0.85 );
|
||||
}
|
||||
|
||||
stopWaterVisualsOnRemote()
|
||||
{
|
||||
level endon( "game_ended" );
|
||||
self endon( "death" );
|
||||
self endon( "disconnect" );
|
||||
self endon( "above_water" );
|
||||
self endon( "out_of_water" );
|
||||
|
||||
self waittill( "using_remote" );
|
||||
self stopWaterVisuals();
|
||||
}
|
136
maps/mp/_zipline.gsc
Normal file
136
maps/mp/_zipline.gsc
Normal file
@ -0,0 +1,136 @@
|
||||
#include maps\mp\_utility;
|
||||
#include common_scripts\utility;
|
||||
|
||||
// prototype for generic zipline / rappel
|
||||
// - player can use their weapon while travelling on line
|
||||
// - player can drop off line by jumping
|
||||
|
||||
// SETUP:
|
||||
// - trigger_touch marks the area where the player will be prompted to use the zipline (suggest 32x32x32 trigger touching ground)
|
||||
// - script_origin marked as the target of the trigger_use_touch is the destination
|
||||
|
||||
init()
|
||||
{
|
||||
visuals = [];
|
||||
triggers = getentarray("zipline", "targetname");
|
||||
|
||||
for( i = 0; i < triggers.size; i++ )
|
||||
{
|
||||
zipline = maps\mp\gametypes\_gameobjects::createUseObject( "neutral", triggers[i], visuals, (0,0,0) );
|
||||
zipline maps\mp\gametypes\_gameobjects::allowUse( "any" );
|
||||
zipline maps\mp\gametypes\_gameobjects::setUseTime( 0.25 );
|
||||
zipline maps\mp\gametypes\_gameobjects::setUseText( &"MP_ZIPLINE_USE" );
|
||||
zipline maps\mp\gametypes\_gameobjects::setUseHintText( &"MP_ZIPLINE_USE" );
|
||||
zipline maps\mp\gametypes\_gameobjects::setVisibleTeam( "any" );
|
||||
zipline.onBeginUse = ::onBeginUse;
|
||||
zipline.onUse = ::onUse;
|
||||
|
||||
targets = [];
|
||||
target = getEnt( triggers[i].target, "targetname");
|
||||
|
||||
if ( !isDefined( target ) )
|
||||
assertmsg( "No target found for zipline trigger located at: ( " + triggers[i].origin[0] + ", " + triggers[i].origin[1] + ", " + triggers[i].origin[2] + " )" );
|
||||
|
||||
while ( isDefined( target ) )
|
||||
{
|
||||
targets[targets.size] = target;
|
||||
if ( isDefined( target.target ) )
|
||||
target = getEnt( target.target, "targetname");
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
zipline.targets = targets;
|
||||
}
|
||||
|
||||
precacheModel( "tag_player" );
|
||||
}
|
||||
|
||||
|
||||
onBeginUse( player )
|
||||
{
|
||||
player playSound( "scrambler_pullout_lift_plr" );
|
||||
}
|
||||
|
||||
|
||||
onUse( player )
|
||||
{
|
||||
player thread zip( self );
|
||||
}
|
||||
|
||||
|
||||
zip( useObj )
|
||||
{
|
||||
self endon( "death" );
|
||||
self endon( "disconnect" );
|
||||
self endon( "zipline_drop" );
|
||||
level endon( "game_ended" );
|
||||
|
||||
// make the carrier
|
||||
carrier = spawn( "script_origin", useObj.trigger.origin );
|
||||
carrier.origin = useObj.trigger.origin;
|
||||
carrier.angles = self.angles;
|
||||
carrier setModel( "tag_player" );
|
||||
|
||||
// link the player
|
||||
self playerLinkToDelta( carrier, "tag_player", 1, 180, 180, 180, 180 );
|
||||
|
||||
// monitor player
|
||||
self thread watchDeath( carrier );
|
||||
self thread watchDrop( carrier );
|
||||
|
||||
// loop through the path of targets
|
||||
targets = useObj.targets;
|
||||
for( i=0; i < targets.size; i++ )
|
||||
{
|
||||
// time
|
||||
// JDS TODO: look into LDs specifying speed, accelleration, deceleration on the nodes
|
||||
time = distance( carrier.origin, targets[i].origin ) / 600;
|
||||
|
||||
// send it on its way
|
||||
acceleration = 0.0;
|
||||
if ( i==0 )
|
||||
acceleration = time*0.2;
|
||||
carrier moveTo( targets[i].origin, time, acceleration );
|
||||
if ( carrier.angles != targets[i].angles )
|
||||
carrier rotateTo( targets[i].angles, time*0.8 );
|
||||
|
||||
// wait
|
||||
wait( time );
|
||||
}
|
||||
|
||||
// all done
|
||||
self notify( "destination" );
|
||||
self unlink();
|
||||
carrier delete();
|
||||
}
|
||||
|
||||
|
||||
watchDrop( carrier )
|
||||
{
|
||||
self endon( "death" );
|
||||
self endon( "disconnect" );
|
||||
self endon( "destination" );
|
||||
level endon( "game_ended" );
|
||||
|
||||
self notifyOnPlayerCommand( "zipline_drop", "+gostand" );
|
||||
|
||||
self waittill( "zipline_drop" );
|
||||
|
||||
self unlink();
|
||||
carrier delete();
|
||||
}
|
||||
|
||||
|
||||
watchDeath( carrier )
|
||||
{
|
||||
self endon( "disconnect" );
|
||||
self endon( "destination" );
|
||||
self endon( "zipline_drop" );
|
||||
level endon( "game_ended" );
|
||||
|
||||
self waittill( "death" );
|
||||
|
||||
self unlink();
|
||||
carrier delete();
|
||||
}
|
129
maps/mp/agents/_agent_common.gsc
Normal file
129
maps/mp/agents/_agent_common.gsc
Normal file
@ -0,0 +1,129 @@
|
||||
#include maps\mp\agents\_agent_utility;
|
||||
#include common_scripts\utility;
|
||||
#include maps\mp\_utility;
|
||||
|
||||
//=======================================================
|
||||
// CodeCallback_AgentAdded
|
||||
//=======================================================
|
||||
CodeCallback_AgentAdded()
|
||||
{
|
||||
self initAgentScriptVariables();
|
||||
|
||||
agentTeam = "axis";
|
||||
|
||||
if( (level.numagents % 2) == 0 )
|
||||
{
|
||||
agentTeam = "allies";
|
||||
}
|
||||
|
||||
level.numagents++;
|
||||
self set_agent_team( agentTeam );
|
||||
|
||||
level.agentArray[ level.agentArray.size ] = self;
|
||||
}
|
||||
|
||||
//=======================================================
|
||||
// CodeCallback_AgentDamaged
|
||||
//=======================================================
|
||||
CodeCallback_AgentDamaged( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, timeOffset )
|
||||
{
|
||||
eAttacker = _validateAttacker( eAttacker );
|
||||
|
||||
self [[ self agentFunc( "on_damaged" ) ]]( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, timeOffset );
|
||||
}
|
||||
|
||||
|
||||
//=======================================================
|
||||
// CodeCallback_AgentKilled
|
||||
//=======================================================
|
||||
CodeCallback_AgentKilled(eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, timeOffset, deathAnimDuration)
|
||||
{
|
||||
eAttacker = _validateAttacker( eAttacker );
|
||||
|
||||
self thread [[ self agentFunc("on_killed") ]](eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, timeOffset, deathAnimDuration);
|
||||
}
|
||||
|
||||
//========================================================
|
||||
// init
|
||||
//========================================================
|
||||
init()
|
||||
{
|
||||
initAgentLevelVariables();
|
||||
|
||||
// add all the agents we're supposed to have in the game with us
|
||||
level thread add_agents_to_game();
|
||||
}
|
||||
|
||||
|
||||
//=======================================================
|
||||
// connectNewAgent
|
||||
//=======================================================
|
||||
connectNewAgent( agent_type, team, class )
|
||||
{
|
||||
agent = getFreeAgent( agent_type );
|
||||
|
||||
if ( IsDefined( agent ) )
|
||||
{
|
||||
agent.connectTime = GetTime();
|
||||
|
||||
if ( IsDefined( team ) )
|
||||
agent set_agent_team( team );
|
||||
else
|
||||
agent set_agent_team( agent.team );
|
||||
|
||||
if ( IsDefined( class ) )
|
||||
agent.class_override = class;
|
||||
|
||||
if( IsDefined(level.agent_funcs[agent_type]["onAIConnect"]) )
|
||||
agent [[ agent agentFunc("onAIConnect") ]]();
|
||||
|
||||
agent maps\mp\gametypes\_spawnlogic::addToCharactersArray();
|
||||
|
||||
AssertEx(agent.connectTime == GetTime(), "Agent spawn took too long - there should be no waits in connectNewAgent");
|
||||
}
|
||||
|
||||
return agent;
|
||||
}
|
||||
|
||||
|
||||
//========================================================
|
||||
// initAgentLevelVariables
|
||||
//========================================================
|
||||
initAgentLevelVariables()
|
||||
{
|
||||
level.agentArray = [];
|
||||
level.numagents = 0;
|
||||
}
|
||||
|
||||
//========================================================
|
||||
// add_agents_to_game
|
||||
//========================================================
|
||||
add_agents_to_game()
|
||||
{
|
||||
level endon( "game_ended" );
|
||||
level waittill("connected", player);
|
||||
|
||||
maxagents = GetMaxAgents();
|
||||
|
||||
while( level.agentArray.size < maxagents )
|
||||
{
|
||||
agent = AddAgent();
|
||||
|
||||
if( !IsDefined( agent) )
|
||||
{
|
||||
waitframe();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//========================================================
|
||||
// set_agent_health
|
||||
//========================================================
|
||||
set_agent_health( health )
|
||||
{
|
||||
self.agenthealth = health;
|
||||
self.health = health;
|
||||
self.maxhealth = health;
|
||||
}
|
447
maps/mp/agents/_agent_utility.gsc
Normal file
447
maps/mp/agents/_agent_utility.gsc
Normal file
@ -0,0 +1,447 @@
|
||||
#include common_scripts\utility;
|
||||
#include maps\mp\_utility;
|
||||
|
||||
//========================================================
|
||||
// agentFunc
|
||||
//========================================================
|
||||
agentFunc( func_name )
|
||||
{
|
||||
assert( IsAgent( self ) );
|
||||
assert( IsDefined(func_name) );
|
||||
assert( isDefined(self.agent_type) );
|
||||
assert( isDefined(level.agent_funcs[self.agent_type]) );
|
||||
assert( isDefined(level.agent_funcs[self.agent_type][func_name]) );
|
||||
|
||||
return level.agent_funcs[self.agent_type][func_name];
|
||||
}
|
||||
|
||||
//========================================================
|
||||
// set_agent_team
|
||||
//========================================================
|
||||
set_agent_team( team, optional_owner )
|
||||
{
|
||||
// since an agent entity has both a "sentient" and an "agent", we need both
|
||||
// these to understand the team the entity is on (much as client entities
|
||||
// have a "sentient" and a "client"). The "team" field sets the "sentient"
|
||||
// team and the "agentteam" field sets the "agent" team.
|
||||
self.team = team;
|
||||
self.agentteam = team;
|
||||
self.pers["team"] = team;
|
||||
|
||||
self.owner = optional_owner;
|
||||
self SetOtherEnt( optional_owner );
|
||||
self SetEntityOwner( optional_owner );
|
||||
}
|
||||
|
||||
|
||||
//=======================================================
|
||||
// initAgentScriptVariables
|
||||
//=======================================================
|
||||
initAgentScriptVariables()
|
||||
{
|
||||
self.agent_type = "player"; // TODO: communicate this to code?
|
||||
self.pers = [];
|
||||
self.hasDied = false;
|
||||
self.isActive = false;
|
||||
self.isAgent = true;
|
||||
self.wasTI = false;
|
||||
self.isSniper = false;
|
||||
self.spawnTime = 0;
|
||||
self.entity_number = self GetEntityNumber();
|
||||
self.agent_teamParticipant = false;
|
||||
self.agent_gameParticipant = false;
|
||||
self.canPerformClientTraces = false;
|
||||
self.agentname = undefined;
|
||||
|
||||
self DetachAll();
|
||||
|
||||
self initPlayerScriptVariables( false );
|
||||
}
|
||||
|
||||
|
||||
//========================================================
|
||||
// initPlayerScriptVariables
|
||||
//========================================================
|
||||
initPlayerScriptVariables( asPlayer )
|
||||
{
|
||||
if ( !asPlayer )
|
||||
{
|
||||
// Not as a player
|
||||
self.class = undefined;
|
||||
self.lastClass = undefined;
|
||||
self.moveSpeedScaler = undefined;
|
||||
self.avoidKillstreakOnSpawnTimer = undefined;
|
||||
self.guid = undefined;
|
||||
self.name = undefined;
|
||||
self.saved_actionSlotData = undefined;
|
||||
self.perks = undefined;
|
||||
self.weaponList = undefined;
|
||||
self.omaClassChanged = undefined;
|
||||
self.objectiveScaler = undefined;
|
||||
self.touchTriggers = undefined;
|
||||
self.carryObject = undefined;
|
||||
self.claimTrigger = undefined;
|
||||
self.canPickupObject = undefined;
|
||||
self.killedInUse = undefined;
|
||||
self.sessionteam = undefined;
|
||||
self.sessionstate = undefined;
|
||||
self.lastSpawnTime = undefined;
|
||||
self.lastspawnpoint = undefined;
|
||||
self.disabledWeapon = undefined;
|
||||
self.disabledWeaponSwitch = undefined;
|
||||
self.disabledOffhandWeapons = undefined;
|
||||
self.disabledUsability = undefined;
|
||||
self.shieldDamage = undefined;
|
||||
self.shieldBulletHits = undefined;
|
||||
self.recentShieldXP = undefined;
|
||||
}
|
||||
else
|
||||
{
|
||||
// As a player
|
||||
self.moveSpeedScaler = 1;
|
||||
self.avoidKillstreakOnSpawnTimer = 5;
|
||||
self.guid = self getUniqueId();
|
||||
self.name = self.guid;
|
||||
self.sessionteam = self.team;
|
||||
self.sessionstate = "playing";
|
||||
self.shieldDamage = 0;
|
||||
self.shieldBulletHits = 0;
|
||||
self.recentShieldXP = 0;
|
||||
self.agent_gameParticipant = true; // If initialized as a player, always make agent a game participant
|
||||
|
||||
self maps\mp\gametypes\_playerlogic::setupSavedActionSlots();
|
||||
self thread maps\mp\perks\_perks::onPlayerSpawned();
|
||||
|
||||
if ( IsGameParticipant( self ) )
|
||||
{
|
||||
self.objectiveScaler = 1;
|
||||
self maps\mp\gametypes\_gameobjects::init_player_gameobjects();
|
||||
self.disabledWeapon = 0;
|
||||
self.disabledWeaponSwitch = 0;
|
||||
self.disabledOffhandWeapons = 0;
|
||||
}
|
||||
}
|
||||
|
||||
self.disabledUsability = 1;
|
||||
}
|
||||
|
||||
//===========================================
|
||||
// getFreeAgent
|
||||
//===========================================
|
||||
getFreeAgent( agent_type )
|
||||
{
|
||||
freeAgent = undefined;
|
||||
|
||||
if( IsDefined( level.agentArray ) )
|
||||
{
|
||||
foreach( agent in level.agentArray )
|
||||
{
|
||||
if( !IsDefined( agent.isActive ) || !agent.isActive )
|
||||
{
|
||||
if ( IsDefined(agent.waitingToDeactivate) && agent.waitingToDeactivate )
|
||||
continue;
|
||||
|
||||
freeAgent = agent;
|
||||
|
||||
freeAgent initAgentScriptVariables();
|
||||
|
||||
if ( IsDefined( agent_type ) )
|
||||
freeAgent.agent_type = agent_type; // TODO: communicate this to code?
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return freeAgent;
|
||||
}
|
||||
|
||||
|
||||
//=======================================================
|
||||
// activateAgent
|
||||
//=======================================================
|
||||
activateAgent()
|
||||
{
|
||||
/#
|
||||
if ( !self.isActive )
|
||||
{
|
||||
// Activating this agent, ensure that he has connected on the same frame
|
||||
AssertEx(self.connectTime == GetTime(), "Agent spawn took too long - there should be no waits in between connectNewAgent and spawning the agent");
|
||||
}
|
||||
#/
|
||||
self.isActive = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=======================================================
|
||||
// deactivateAgent
|
||||
//=======================================================
|
||||
deactivateAgent()
|
||||
{
|
||||
self thread deactivateAgentDelayed();
|
||||
}
|
||||
|
||||
//=======================================================
|
||||
// deactivateAgentDelayed
|
||||
//=======================================================
|
||||
deactivateAgentDelayed()
|
||||
{
|
||||
self notify("deactivateAgentDelayed");
|
||||
self endon("deactivateAgentDelayed");
|
||||
|
||||
// During the 0.05s wait in deactivateAgentDelayed, the agent's script variables are all cleared out
|
||||
// So we need to do this now while IsGameParticipant can still be checked
|
||||
if ( IsGameParticipant(self) )
|
||||
self maps\mp\gametypes\_spawnlogic::removeFromParticipantsArray();
|
||||
|
||||
self maps\mp\gametypes\_spawnlogic::removeFromCharactersArray();
|
||||
|
||||
// Wait till next frame before we "disconnect"
|
||||
// That way things waiting on "death" but have endon("disconnect") will still function
|
||||
// e.g. maps\mp\killstreaks\_juggernaut::juggRemover()
|
||||
wait 0.05;
|
||||
|
||||
self.isActive = false;
|
||||
self.hasDied = false;
|
||||
self.owner = undefined;
|
||||
self.connectTime = undefined;
|
||||
self.waitingToDeactivate = undefined;
|
||||
|
||||
// Clear this agent from any other character's attackers array
|
||||
foreach ( character in level.characters )
|
||||
{
|
||||
if ( IsDefined( character.attackers ) )
|
||||
{
|
||||
foreach ( index, attacker in character.attackers )
|
||||
{
|
||||
if ( attacker == self )
|
||||
character.attackers[index] = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( IsDefined( self.headModel ) )
|
||||
{
|
||||
self Detach( self.headModel );
|
||||
self.headModel = undefined;
|
||||
}
|
||||
|
||||
self notify("disconnect");
|
||||
}
|
||||
|
||||
|
||||
//===========================================
|
||||
// getNumActiveAgents
|
||||
//===========================================
|
||||
getNumActiveAgents( type )
|
||||
{
|
||||
if ( !IsDefined(type) )
|
||||
type = "all";
|
||||
|
||||
agents = getActiveAgentsOfType(type);
|
||||
return agents.size;
|
||||
}
|
||||
|
||||
|
||||
//===========================================
|
||||
// getActiveAgentsOfType
|
||||
//===========================================
|
||||
getActiveAgentsOfType( type )
|
||||
{
|
||||
Assert(IsDefined(type));
|
||||
agents = [];
|
||||
|
||||
if ( !IsDefined( level.agentArray ) )
|
||||
return agents;
|
||||
|
||||
foreach ( agent in level.agentArray )
|
||||
{
|
||||
if ( IsDefined( agent.isActive ) && agent.isActive )
|
||||
{
|
||||
if ( type == "all" || agent.agent_type == type )
|
||||
agents[agents.size] = agent;
|
||||
}
|
||||
}
|
||||
|
||||
return agents;
|
||||
}
|
||||
|
||||
|
||||
//===========================================
|
||||
// getNumOwnedActiveAgents
|
||||
//===========================================
|
||||
getNumOwnedActiveAgents( player )
|
||||
{
|
||||
return getNumOwnedActiveAgentsByType( player, "all" );
|
||||
}
|
||||
|
||||
//===========================================
|
||||
// getNumOwnedActiveAgentsByType
|
||||
//===========================================
|
||||
getNumOwnedActiveAgentsByType( player, type )
|
||||
{
|
||||
Assert(IsDefined(type));
|
||||
numOwnedActiveAgents = 0;
|
||||
|
||||
if( !IsDefined(level.agentArray) )
|
||||
{
|
||||
return numOwnedActiveAgents;
|
||||
}
|
||||
|
||||
foreach( agent in level.agentArray )
|
||||
{
|
||||
if( IsDefined( agent.isActive ) && agent.isActive )
|
||||
{
|
||||
if ( IsDefined(agent.owner) && (agent.owner == player) )
|
||||
{
|
||||
// Adding exclusion for "alien" type from a request for "all" to prevent the Seeker killstreak in mp_dome_ns from overloading the max allowable agents per player.
|
||||
if ( ( type == "all" && agent.agent_type != "alien" ) || agent.agent_type == type )
|
||||
numOwnedActiveAgents++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return numOwnedActiveAgents;
|
||||
}
|
||||
|
||||
//=======================================================
|
||||
// getValidSpawnPathNodeNearPlayer
|
||||
//=======================================================
|
||||
getValidSpawnPathNodeNearPlayer( bDoPhysicsTraceToPlayer, bDoPhysicsTraceToValidateNode ) // self = player
|
||||
{
|
||||
assert( isPlayer( self ) );
|
||||
|
||||
nodeArray = GetNodesInRadius( self.origin, 350, 64, 128, "Path" );
|
||||
|
||||
if( !IsDefined(nodeArray) || (nodeArray.size == 0) )
|
||||
{
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if ( IsDefined(level.waterDeleteZ) && IsDefined(level.trigUnderWater) )
|
||||
{
|
||||
// Ignore any nodes where the agent would die immediately upon spawning
|
||||
nodeArrayOld = nodeArray;
|
||||
nodeArray = [];
|
||||
foreach( node in nodeArrayOld )
|
||||
{
|
||||
if ( node.origin[ 2 ] > level.waterDeleteZ || !IsPointInVolume( node.origin, level.trigUnderWater ) )
|
||||
nodeArray[nodeArray.size] = node;
|
||||
}
|
||||
}
|
||||
|
||||
playerDirection = AnglesToForward( self.angles );
|
||||
bestDot = -10;
|
||||
|
||||
playerHeight = maps\mp\gametypes\_spawnlogic::getPlayerTraceHeight( self );
|
||||
zOffset = ( 0, 0, playerHeight );
|
||||
|
||||
if ( !IsDefined(bDoPhysicsTraceToPlayer) )
|
||||
bDoPhysicsTraceToPlayer = false;
|
||||
|
||||
if ( !IsDefined(bDoPhysicsTraceToValidateNode) )
|
||||
bDoPhysicsTraceToValidateNode = false;
|
||||
|
||||
pathNodeSortedByDot = [];
|
||||
pathNodeDotValues = [];
|
||||
foreach( pathNode in nodeArray )
|
||||
{
|
||||
if ( !pathNode DoesNodeAllowStance("stand") || isDefined ( pathnode.no_agent_spawn) )
|
||||
continue;
|
||||
|
||||
|
||||
directionToNode = VectorNormalize( pathNode.origin - self.origin );
|
||||
dot = VectorDot( playerDirection, directionToNode );
|
||||
|
||||
i = 0;
|
||||
for ( ; i < pathNodeDotValues.size; i++ )
|
||||
{
|
||||
if ( dot > pathNodeDotValues[i] )
|
||||
{
|
||||
for ( j = pathNodeDotValues.size; j > i; j-- )
|
||||
{
|
||||
pathNodeDotValues[j] = pathNodeDotValues[j-1];
|
||||
pathNodeSortedByDot[j] = pathNodeSortedByDot[j-1];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
pathNodeSortedByDot[i] = pathNode;
|
||||
pathNodeDotValues[i] = dot;
|
||||
}
|
||||
|
||||
// pick a path node in the player's view
|
||||
for ( i = 0; i < pathNodeSortedByDot.size; i++ )
|
||||
{
|
||||
pathNode = pathNodeSortedByDot[i];
|
||||
|
||||
traceStart = self.origin + zOffset;
|
||||
traceEnd = pathNode.origin + zOffset;
|
||||
|
||||
if ( i > 0 )
|
||||
wait(0.05); // Spread out the traces across multiple frames
|
||||
|
||||
// prevent selecting a node that the player cannot see
|
||||
if( !SightTracePassed( traceStart, traceEnd, false, self ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( bDoPhysicsTraceToValidateNode )
|
||||
{
|
||||
if ( i > 0 )
|
||||
wait(0.05); // Spread out the traces across multiple frames
|
||||
|
||||
hitPos = PlayerPhysicsTrace( pathNode.origin + zOffset, pathNode.origin );
|
||||
if ( DistanceSquared( hitPos, pathNode.origin ) > 1 )
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( bDoPhysicsTraceToPlayer )
|
||||
{
|
||||
if ( i > 0 )
|
||||
wait(0.05); // Spread out the traces across multiple frames
|
||||
|
||||
hitPos = PhysicsTrace( traceStart, traceEnd );
|
||||
if ( DistanceSquared( hitPos, traceEnd ) > 1 )
|
||||
continue;
|
||||
}
|
||||
|
||||
return pathNode;
|
||||
}
|
||||
|
||||
// always return a node for safeguard
|
||||
if( (pathNodeSortedByDot.size > 0) && IsDefined(level.isHorde) )
|
||||
return pathNodeSortedByDot[0];
|
||||
}
|
||||
|
||||
|
||||
//=======================================================
|
||||
// killAgent
|
||||
//=======================================================
|
||||
killAgent( agent )
|
||||
{
|
||||
// do enough damage to kill the agent regardless of any damage mitigation
|
||||
agent DoDamage( agent.health + 500000, agent.origin );
|
||||
}
|
||||
|
||||
|
||||
//=======================================================
|
||||
// killDog
|
||||
//=======================================================
|
||||
killDog() // self == dog
|
||||
{
|
||||
self [[ self agentFunc( "on_damaged" ) ]](
|
||||
level, // eInflictor The entity that causes the damage.(e.g. a turret)
|
||||
undefined, // eAttacker The entity that is attacking.
|
||||
self.health + 1, // iDamage Integer specifying the amount of damage done
|
||||
0, // iDFlags Integer specifying flags that are to be applied to the damage
|
||||
"MOD_CRUSH", // sMeansOfDeath Integer specifying the method of death
|
||||
"none", // sWeapon The weapon number of the weapon used to inflict the damage
|
||||
( 0, 0, 0 ), // vPoint The point the damage is from?
|
||||
(0, 0, 0), // vDir The direction of the damage
|
||||
"none", // sHitLoc The location of the hit
|
||||
0 // psOffsetTime The time offset for the damage
|
||||
);
|
||||
}
|
502
maps/mp/agents/_agents.gsc
Normal file
502
maps/mp/agents/_agents.gsc
Normal file
@ -0,0 +1,502 @@
|
||||
#include common_scripts\utility;
|
||||
#include maps\mp\_utility;
|
||||
#include maps\mp\gametypes\_damage;
|
||||
#include maps\mp\gametypes\_gamelogic;
|
||||
#include maps\mp\agents\_agent_utility;
|
||||
|
||||
//=======================================================================
|
||||
// main
|
||||
// This is functions is called directly from native code on game startup
|
||||
// The particular gametype's main() is called from native code afterward
|
||||
//=======================================================================
|
||||
main()
|
||||
{
|
||||
if( IsDefined( level.createFX_enabled ) && level.createFX_enabled )
|
||||
return;
|
||||
|
||||
setup_callbacks();
|
||||
|
||||
// Enable badplaces in destructibles
|
||||
level.badplace_cylinder_func = ::badplace_cylinder;
|
||||
level.badplace_delete_func = ::badplace_delete;
|
||||
|
||||
/#
|
||||
level thread monitor_scr_agent_players();
|
||||
#/
|
||||
|
||||
level thread maps\mp\agents\_agent_common::init();
|
||||
level thread maps\mp\killstreaks\_agent_killstreak::init();
|
||||
level thread maps\mp\killstreaks\_dog_killstreak::init();
|
||||
}
|
||||
|
||||
|
||||
//========================================================
|
||||
// setup_callbacks
|
||||
//========================================================
|
||||
setup_callbacks()
|
||||
{
|
||||
if ( !IsDefined( level.agent_funcs ) )
|
||||
level.agent_funcs = [];
|
||||
|
||||
level.agent_funcs["player"] = [];
|
||||
|
||||
level.agent_funcs["player"]["spawn"] = ::spawn_agent_player;
|
||||
level.agent_funcs["player"]["think"] = maps\mp\bots\_bots_gametype_war::bot_war_think;
|
||||
level.agent_funcs["player"]["on_killed"] = ::on_agent_player_killed;
|
||||
level.agent_funcs["player"]["on_damaged"] = ::on_agent_player_damaged;
|
||||
level.agent_funcs["player"]["on_damaged_finished"] = ::agent_damage_finished;
|
||||
|
||||
maps\mp\killstreaks\_agent_killstreak::setup_callbacks();
|
||||
maps\mp\killstreaks\_dog_killstreak::setup_callbacks();
|
||||
}
|
||||
|
||||
wait_till_agent_funcs_defined()
|
||||
{
|
||||
while( !IsDefined(level.agent_funcs) )
|
||||
wait(0.05);
|
||||
}
|
||||
|
||||
|
||||
/#
|
||||
//=======================================================
|
||||
// new_scr_agent_team
|
||||
//=======================================================
|
||||
new_scr_agent_team()
|
||||
{
|
||||
teamCounts = [];
|
||||
teamCounts["allies"] = 0;
|
||||
teamCounts["axis"] = 0;
|
||||
minTeam = undefined;
|
||||
foreach( player in level.participants )
|
||||
{
|
||||
if ( !IsDefined( teamCounts[player.team] ) )
|
||||
teamCounts[player.team] = 0;
|
||||
if ( IsTeamParticipant( player ) )
|
||||
teamCounts[player.team]++;
|
||||
}
|
||||
foreach ( team, count in teamCounts )
|
||||
{
|
||||
if ( (team != "spectator") && (!IsDefined(minTeam) || teamCounts[minTeam] > count) )
|
||||
minTeam = team;
|
||||
}
|
||||
|
||||
return minTeam;
|
||||
}
|
||||
|
||||
//=======================================================
|
||||
// monitor_scr_agent_players
|
||||
//=======================================================
|
||||
monitor_scr_agent_players()
|
||||
{
|
||||
SetDevDvarIfUninitialized( "scr_agent_players_add", "0" );
|
||||
SetDevDvarIfUninitialized( "scr_agent_players_drop", "0" );
|
||||
|
||||
while(level.players.size == 0)
|
||||
wait(0.05); // Agents don't exist until a player connects
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
wait(0.1);
|
||||
|
||||
add_agent_players = getdvarInt("scr_agent_players_add");
|
||||
drop_agent_players = getdvarInt("scr_agent_players_drop");
|
||||
|
||||
if ( add_agent_players != 0 )
|
||||
SetDevDvar( "scr_agent_players_add", 0 );
|
||||
|
||||
if ( drop_agent_players != 0 )
|
||||
SetDevDvar( "scr_agent_players_drop", 0 );
|
||||
|
||||
for ( i = 0; i < add_agent_players; i++ )
|
||||
{
|
||||
agent = add_humanoid_agent( "player", new_scr_agent_team(), undefined, undefined, undefined, undefined, true, true );
|
||||
if ( IsDefined( agent ) )
|
||||
agent.agent_teamParticipant = true;
|
||||
}
|
||||
|
||||
foreach ( agent in level.agentArray )
|
||||
{
|
||||
if ( !IsDefined( agent.isActive ) )
|
||||
continue;
|
||||
|
||||
if ( IsDefined( agent.isActive ) && agent.isActive && agent.agent_type == "player" )
|
||||
{
|
||||
if ( drop_agent_players > 0 )
|
||||
{
|
||||
agent maps\mp\agents\_agent_utility::deactivateAgent();
|
||||
agent Suicide();
|
||||
drop_agent_players--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#/
|
||||
|
||||
|
||||
//=======================================================
|
||||
// add_humanoid_agent
|
||||
//=======================================================
|
||||
add_humanoid_agent( agent_type, team, class, optional_spawnOrigin, optional_spawnAngles, optional_owner, use_randomized_personality, respawn_on_death, difficulty )
|
||||
{
|
||||
agent = maps\mp\agents\_agent_common::connectNewAgent( agent_type, team, class );
|
||||
|
||||
if( IsDefined( agent ) )
|
||||
{
|
||||
agent thread [[ agent agentFunc("spawn") ]]( optional_spawnOrigin, optional_spawnAngles, optional_owner, use_randomized_personality, respawn_on_death, difficulty );
|
||||
}
|
||||
|
||||
return agent;
|
||||
}
|
||||
|
||||
|
||||
//========================================================
|
||||
// spawn_agent_player
|
||||
//========================================================
|
||||
spawn_agent_player( optional_spawnOrigin, optional_spawnAngles, optional_owner, use_randomized_personality, respawn_on_death, difficulty )
|
||||
{
|
||||
self endon("disconnect");
|
||||
|
||||
while( !IsDefined(level.getSpawnPoint) )
|
||||
{
|
||||
waitframe();
|
||||
}
|
||||
|
||||
if( self.hasDied )
|
||||
{
|
||||
wait( RandomIntRange(6, 10) );
|
||||
}
|
||||
|
||||
self initPlayerScriptVariables( true );
|
||||
|
||||
// allow killstreaks to pass in specific spawn locations
|
||||
if( IsDefined(optional_spawnOrigin) && IsDefined(optional_spawnAngles) )
|
||||
{
|
||||
spawnOrigin = optional_spawnOrigin;
|
||||
spawnAngles = optional_spawnAngles;
|
||||
|
||||
self.lastSpawnPoint = SpawnStruct();
|
||||
self.lastSpawnPoint.origin = spawnOrigin;
|
||||
self.lastSpawnPoint.angles = spawnAngles;
|
||||
}
|
||||
else
|
||||
{
|
||||
spawnPoint = self [[level.getSpawnPoint]]();
|
||||
spawnOrigin = spawnpoint.origin;
|
||||
spawnAngles = spawnpoint.angles;
|
||||
|
||||
// Player specific variables needed in damage processing
|
||||
self.lastSpawnPoint = spawnpoint;
|
||||
}
|
||||
self activateAgent();
|
||||
self.lastSpawnTime = GetTime();
|
||||
self.spawnTime = GetTime();
|
||||
|
||||
phys_trace_start = spawnOrigin + (0,0,25);
|
||||
phys_trace_end = spawnOrigin;
|
||||
newSpawnOrigin = PlayerPhysicsTrace(phys_trace_start, phys_trace_end);
|
||||
if ( DistanceSquared( newSpawnOrigin, phys_trace_start ) > 1 )
|
||||
{
|
||||
// If the result from the physics trace wasn't immediately in solid, then use it instead
|
||||
spawnOrigin = newSpawnOrigin;
|
||||
}
|
||||
|
||||
// called from code when an agent is done initializing after AddAgent is called
|
||||
// this should set up any state specific to this agent and game
|
||||
self SpawnAgent( spawnOrigin, spawnAngles );
|
||||
|
||||
if ( IsDefined(use_randomized_personality) && use_randomized_personality )
|
||||
{
|
||||
/#
|
||||
self maps\mp\bots\_bots::bot_set_personality_from_dev_dvar();
|
||||
#/
|
||||
self maps\mp\bots\_bots_personality::bot_assign_personality_functions(); // Randomized personality was already set, so just need to setup functions
|
||||
}
|
||||
else
|
||||
{
|
||||
self maps\mp\bots\_bots_util::bot_set_personality( "default" );
|
||||
}
|
||||
|
||||
if ( IsDefined( difficulty ) )
|
||||
self maps\mp\bots\_bots_util::bot_set_difficulty( difficulty );
|
||||
|
||||
self initPlayerClass();
|
||||
|
||||
self maps\mp\agents\_agent_common::set_agent_health( 100 );
|
||||
if ( IsDefined(respawn_on_death) && respawn_on_death )
|
||||
self.respawn_on_death = true;
|
||||
|
||||
// must set the team after SpawnAgent to fix a bug with weapon crosshairs and nametags
|
||||
if( IsDefined(optional_owner) )
|
||||
self set_agent_team( optional_owner.team, optional_owner );
|
||||
|
||||
if( isDefined( self.owner ) )
|
||||
self thread destroyOnOwnerDisconnect( self.owner );
|
||||
|
||||
self thread maps\mp\_flashgrenades::monitorFlash();
|
||||
|
||||
// switch to agent bot mode and wipe all AI info clean
|
||||
self EnableAnimState( false );
|
||||
|
||||
self [[level.onSpawnPlayer]]();
|
||||
self maps\mp\gametypes\_class::giveLoadout( self.team, self.class, true );
|
||||
|
||||
self thread maps\mp\bots\_bots::bot_think_watch_enemy( true );
|
||||
self thread maps\mp\bots\_bots::bot_think_crate();
|
||||
if ( self.agent_type == "player" )
|
||||
self thread maps\mp\bots\_bots::bot_think_level_actions();
|
||||
else if ( self.agent_type == "odin_juggernaut" )
|
||||
self thread maps\mp\bots\_bots::bot_think_level_actions( 128 );
|
||||
self thread maps\mp\bots\_bots_strategy::bot_think_tactical_goals();
|
||||
self thread [[ self agentFunc("think") ]]();
|
||||
|
||||
if ( !self.hasDied )
|
||||
self maps\mp\gametypes\_spawnlogic::addToParticipantsArray();
|
||||
|
||||
self.hasDied = false;
|
||||
|
||||
self thread maps\mp\gametypes\_weapons::onPlayerSpawned();
|
||||
self thread maps\mp\gametypes\_healthoverlay::playerHealthRegen();
|
||||
self thread maps\mp\gametypes\_battlechatter_mp::onPlayerSpawned();
|
||||
|
||||
level notify( "spawned_agent_player", self );
|
||||
level notify( "spawned_agent", self );
|
||||
self notify( "spawned_player" );
|
||||
}
|
||||
|
||||
|
||||
//========================================================
|
||||
// destroyOnOwnerDisconnect
|
||||
//========================================================
|
||||
destroyOnOwnerDisconnect( owner )
|
||||
{
|
||||
self endon( "death" );
|
||||
|
||||
owner waittill( "killstreak_disowned" );
|
||||
|
||||
self notify( "owner_disconnect" );
|
||||
|
||||
// Wait till host migration finishes before suiciding
|
||||
if ( maps\mp\gametypes\_hostmigration::waitTillHostMigrationDone() )
|
||||
wait 0.05;
|
||||
|
||||
// kill the agent
|
||||
self Suicide();
|
||||
}
|
||||
|
||||
|
||||
//========================================================
|
||||
// agent_damage_finished
|
||||
//========================================================
|
||||
agent_damage_finished( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, timeOffset )
|
||||
{
|
||||
if( IsDefined( eInflictor ) || IsDefined( eAttacker ) )
|
||||
{
|
||||
if( !IsDefined( eInflictor ) )
|
||||
eInflictor = eAttacker;
|
||||
|
||||
if( isdefined(self.allowVehicleDamage) && !self.allowVehicleDamage )
|
||||
{
|
||||
if( IsDefined( eInflictor.classname ) && eInflictor.classname == "script_vehicle" )
|
||||
return false;
|
||||
}
|
||||
|
||||
if( IsDefined( eInflictor.classname ) && eInflictor.classname == "auto_turret" )
|
||||
eAttacker = eInflictor;
|
||||
|
||||
if( IsDefined( eAttacker ) && sMeansOfDeath != "MOD_FALLING" && sMeansOfDeath != "MOD_SUICIDE" )
|
||||
{
|
||||
if( level.teamBased )
|
||||
{
|
||||
if( IsDefined( eAttacker.team ) && eAttacker.team != self.team )
|
||||
{
|
||||
self SetAgentAttacker( eAttacker );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self SetAgentAttacker( eAttacker );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Assert(IsDefined(self.isActive) && self.isActive);
|
||||
self FinishAgentDamage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, timeOffset, 0.0 );
|
||||
if ( !IsDefined(self.isActive) )
|
||||
{
|
||||
// Agent just died and cleared out all his script variables
|
||||
// So don't allow this agent to be freed up until he is properly deactivated in deactivateAgentDelayed
|
||||
self.waitingToDeactivate = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//=======================================================
|
||||
// on_agent_generic_damaged
|
||||
//=======================================================
|
||||
on_agent_generic_damaged( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, timeOffset )
|
||||
{
|
||||
attckerIsOwner = IsDefined(eAttacker) && IsDefined(self.owner) && (self.owner == eAttacker);
|
||||
attackerIsTeammate = attackerIsHittingTeam( self.owner, eAttacker ) || attckerIsOwner;
|
||||
|
||||
// ignore friendly fire damage for team based modes
|
||||
if( level.teambased && attackerIsTeammate && !level.friendlyfire )
|
||||
return false;
|
||||
|
||||
// ignore damage from owner in non team based modes
|
||||
if( !level.teambased && attckerIsOwner )
|
||||
return false;
|
||||
|
||||
// don't let helicopters and other vehicles crush a player, if we want it to then put in a special case here
|
||||
if( IsDefined( sMeansOfDeath ) && sMeansOfDeath == "MOD_CRUSH" && IsDefined( eInflictor ) && IsDefined( eInflictor.classname ) && eInflictor.classname == "script_vehicle" )
|
||||
return false;
|
||||
|
||||
if ( !IsDefined( self ) || !isReallyAlive( self ) )
|
||||
return false;
|
||||
|
||||
if ( IsDefined( eAttacker ) && eAttacker.classname == "script_origin" && IsDefined( eAttacker.type ) && eAttacker.type == "soft_landing" )
|
||||
return false;
|
||||
|
||||
if ( sWeapon == "killstreak_emp_mp" )
|
||||
return false;
|
||||
|
||||
if ( sWeapon == "bouncingbetty_mp" && !maps\mp\gametypes\_weapons::mineDamageHeightPassed( eInflictor, self ) )
|
||||
return false;
|
||||
|
||||
// JC-ToDo: - Kept this here in case I bring back mine logic for the mk32
|
||||
// if ( sWeapon == "xm25_mp" && sMeansOfDeath == "MOD_IMPACT" )
|
||||
// iDamage = 95;
|
||||
|
||||
// ensure throwing knife death
|
||||
if ( ( sWeapon == "throwingknife_mp" || sWeapon == "throwingknifejugg_mp" ) && sMeansOfDeath == "MOD_IMPACT" )
|
||||
iDamage = self.health + 1;
|
||||
|
||||
// ensures stuck death
|
||||
if ( IsDefined( eInflictor ) && IsDefined( eInflictor.stuckEnemyEntity ) && eInflictor.stuckEnemyEntity == self )
|
||||
iDamage = self.health + 1;
|
||||
|
||||
if( iDamage <= 0 )
|
||||
return false;
|
||||
|
||||
if ( IsDefined( eAttacker ) && eAttacker != self && iDamage > 0 && ( !IsDefined( sHitLoc ) || sHitLoc != "shield" ) )
|
||||
{
|
||||
if( iDFlags & level.iDFLAGS_STUN )
|
||||
typeHit = "stun";
|
||||
else if( !shouldWeaponFeedback( sWeapon ) )
|
||||
typeHit = "none";
|
||||
else
|
||||
typeHit = ter_op( iDamage >= self.health, "hitkill" ,"standard" ); // adds final kill hitmarker to dogs
|
||||
|
||||
eAttacker thread maps\mp\gametypes\_damagefeedback::updateDamageFeedback( typeHit );
|
||||
}
|
||||
|
||||
if ( IsDefined( level.modifyPlayerDamage ) )
|
||||
iDamage = [[level.modifyPlayerDamage]]( self, eAttacker, iDamage, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc );
|
||||
|
||||
return self [[ self agentFunc( "on_damaged_finished" ) ]]( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, timeOffset );
|
||||
}
|
||||
|
||||
|
||||
//========================================================
|
||||
// on_agent_player_damaged
|
||||
//========================================================
|
||||
on_agent_player_damaged( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, timeOffset )
|
||||
{
|
||||
attckerIsOwner = IsDefined(eAttacker) && IsDefined(self.owner) && (self.owner == eAttacker);
|
||||
|
||||
// ignore damage from owner in non team based modes
|
||||
if( !level.teambased && attckerIsOwner )
|
||||
return false;
|
||||
|
||||
Callback_PlayerDamage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, timeOffset );
|
||||
}
|
||||
|
||||
|
||||
//=======================================================
|
||||
// on_agent_player_killed
|
||||
//=======================================================
|
||||
on_agent_player_killed(eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, timeOffset, deathAnimDuration)
|
||||
{
|
||||
self on_humanoid_agent_killed_common(eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, timeOffset, deathAnimDuration, true);
|
||||
|
||||
// award XP for killing agents
|
||||
if( isPlayer( eAttacker ) && (!isDefined(self.owner) || eAttacker != self.owner) )
|
||||
{
|
||||
// TODO: should play vo for killing the agent
|
||||
self maps\mp\gametypes\_damage::onKillstreakKilled( eAttacker, sWeapon, sMeansOfDeath, iDamage, "destroyed_squad_mate" );
|
||||
}
|
||||
|
||||
self maps\mp\gametypes\_weapons::dropScavengerForDeath( eAttacker );
|
||||
|
||||
if ( self.isActive )
|
||||
{
|
||||
self.hasDied = true;
|
||||
|
||||
if ( getGametypeNumLives() != 1 && ( IsDefined(self.respawn_on_death) && self.respawn_on_death ) )
|
||||
{
|
||||
self thread [[ self agentFunc("spawn") ]]();
|
||||
}
|
||||
else
|
||||
{
|
||||
self deactivateAgent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//=======================================================
|
||||
// on_humanoid_agent_killed_common
|
||||
//=======================================================
|
||||
on_humanoid_agent_killed_common(eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, timeOffset, deathAnimDuration, dropWeapons )
|
||||
{
|
||||
// Things that happen on every type of humanoid agent that dies
|
||||
|
||||
if ( self.hasRiotShieldEquipped )
|
||||
{
|
||||
self LaunchShield( iDamage, sMeansofDeath );
|
||||
|
||||
if ( !dropWeapons )
|
||||
{
|
||||
// If not dropping weapons, need to make sure we at least drop the riot shield
|
||||
item = self dropItem( self GetCurrentWeapon() );
|
||||
|
||||
if( IsDefined(item) )
|
||||
{
|
||||
item thread maps\mp\gametypes\_weapons::deletePickupAfterAWhile();
|
||||
item.owner = self;
|
||||
item.ownersattacker = eAttacker;
|
||||
item MakeUnusable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( dropWeapons )
|
||||
self [[level.weaponDropFunction]]( eAttacker, sMeansOfDeath );
|
||||
|
||||
// ragdoll
|
||||
self.body = self CloneAgent( deathAnimDuration );
|
||||
thread delayStartRagdoll( self.body, sHitLoc, vDir, sWeapon, eInflictor, sMeansOfDeath );
|
||||
|
||||
self riotShield_clear();
|
||||
}
|
||||
|
||||
|
||||
//===========================================
|
||||
// initPlayerClass
|
||||
//===========================================
|
||||
initPlayerClass()
|
||||
{
|
||||
// Must be called AFTER agent has been spawned as a bot agent
|
||||
if ( IsDefined(self.class_override) )
|
||||
{
|
||||
self.class = self.class_override;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( self maps\mp\bots\_bots_loadout::bot_setup_loadout_callback() )
|
||||
self.class = "callback";
|
||||
else
|
||||
self.class = "class1";
|
||||
}
|
||||
}
|
193
maps/mp/agents/_agents_civ_hvt.gsc
Normal file
193
maps/mp/agents/_agents_civ_hvt.gsc
Normal file
@ -0,0 +1,193 @@
|
||||
#include common_scripts\utility;
|
||||
#include maps\mp\_utility;
|
||||
#include maps\mp\gametypes\_gamelogic;
|
||||
#include maps\mp\bots\_bots_util;
|
||||
#include maps\mp\bots\_bots_strategy;
|
||||
// #include maps\mp\bots\_bots_personality;
|
||||
#include maps\mp\gametypes\_damage;
|
||||
#include maps\mp\agents\_agent_utility;
|
||||
|
||||
//=======================================================
|
||||
// main
|
||||
//=======================================================
|
||||
main()
|
||||
{
|
||||
setup_callbacks();
|
||||
}
|
||||
|
||||
setup_callbacks()
|
||||
{
|
||||
level.agent_funcs["civ_hvt"] = [];
|
||||
|
||||
level.agent_funcs["civ_hvt"]["spawn"] = ::onSpawn;
|
||||
level.agent_funcs["civ_hvt"]["think"] = ::agentThink;
|
||||
level.agent_funcs["civ_hvt"]["on_killed"] = ::onAgentKilled;
|
||||
level.agent_funcs["civ_hvt"]["on_damaged"] = maps\mp\agents\_agents::on_agent_player_damaged;
|
||||
level.agent_funcs["civ_hvt"]["on_damaged_finished"] = maps\mp\agents\_agents::agent_damage_finished;
|
||||
}
|
||||
|
||||
onSpawn( optional_spawnOrigin, optional_spawnAngles, optional_owner, use_randomized_personality, respawn_on_death, difficulty )
|
||||
{
|
||||
self.hvtIsFollowing = false;
|
||||
|
||||
self maps\mp\agents\_agents::spawn_agent_player( optional_spawnOrigin, optional_spawnAngles, optional_owner, use_randomized_personality, respawn_on_death, difficulty );
|
||||
|
||||
self thread handlePlayerUse();
|
||||
}
|
||||
|
||||
onAgentKilled( eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, timeOffset, deathAnimDuration )
|
||||
{
|
||||
self.defendNode = undefined;
|
||||
self.hvtTrigger MakeUnusable();
|
||||
self.hvtTrigger = undefined;
|
||||
|
||||
// ragdoll
|
||||
self.body = self CloneAgent( deathAnimDuration );
|
||||
thread delayStartRagdoll( self.body, sHitLoc, vDir, sWeapon, eInflictor, sMeansOfDeath );
|
||||
|
||||
if ( IsDefined( self.onKilledCallback ) )
|
||||
{
|
||||
self [[ self.onKilledCallback ]]( eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, timeOffset, deathAnimDuration );
|
||||
}
|
||||
|
||||
self maps\mp\agents\_agent_utility::deactivateAgent();
|
||||
|
||||
// send a message to owner
|
||||
self.owner notify( "hvt_killed" );
|
||||
}
|
||||
|
||||
agentThink()
|
||||
{
|
||||
self notify( "agent_think" );
|
||||
self endon( "agent_think" );
|
||||
|
||||
self endon( "death" );
|
||||
self endon( "disconnect" );
|
||||
level endon( "game_ended" );
|
||||
self endon( "owner_disconnect" );
|
||||
|
||||
while ( true )
|
||||
{
|
||||
if ( self.hvtIsFollowing )
|
||||
{
|
||||
self followThink();
|
||||
}
|
||||
else
|
||||
{
|
||||
self waitThink( 150 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
waitThink( radius )
|
||||
{
|
||||
self BotSetStance("none");
|
||||
self BotClearScriptGoal();
|
||||
self bot_disable_tactical_goals();
|
||||
|
||||
defendNode = self.owner getValidSpawnPathNodeNearPlayer();
|
||||
|
||||
self.cur_defend_node = undefined;
|
||||
self.bot_defending = true;
|
||||
self.bot_defending_center = defendNode.origin;
|
||||
self.bot_defending_radius = radius;
|
||||
self.cur_defend_stance = "crouch";
|
||||
self.bot_defending_type = "protect";
|
||||
|
||||
result = "";
|
||||
while( result != "goal" )
|
||||
{
|
||||
self.cur_defend_node = defendNode;
|
||||
|
||||
self BotSetScriptGoalNode( self.cur_defend_node, "tactical" );
|
||||
result = self waittill_any_return( "goal", "bad_path" );
|
||||
|
||||
self.node_closest_to_defend_center = defendNode;
|
||||
|
||||
self.cur_defend_node = undefined;
|
||||
}
|
||||
|
||||
self childthread defense_watch_entrances_at_goal();
|
||||
|
||||
self waittill( "hvt_toggle" );
|
||||
}
|
||||
|
||||
followThink() // self == agent
|
||||
{
|
||||
self BotClearScriptGoal();
|
||||
self bot_disable_tactical_goals();
|
||||
|
||||
if ( !self bot_is_guarding_player( self.owner ) )
|
||||
{
|
||||
self bot_guard_player( self.owner, 250 );
|
||||
}
|
||||
|
||||
self waittill( "hvt_toggle" );
|
||||
}
|
||||
|
||||
handlePlayerUse() // self == agent
|
||||
{
|
||||
level endon( "game_ended" );
|
||||
self endon( "death" );
|
||||
|
||||
if ( !IsDefined( self.hvtTrigger ) )
|
||||
{
|
||||
self.hvtTrigger = Spawn( "script_model", self.origin );
|
||||
self.hvtTrigger LinkTo( self );
|
||||
}
|
||||
|
||||
self.hvtTrigger MakeUsable();
|
||||
foreach ( player in level.players )
|
||||
{
|
||||
if ( player != self.owner )
|
||||
{
|
||||
self.hvtTrigger DisablePlayerUse( player );
|
||||
}
|
||||
else
|
||||
{
|
||||
self.hvtTrigger EnablePlayerUse( player );
|
||||
}
|
||||
}
|
||||
|
||||
self thread waitForPlayerConnect();
|
||||
|
||||
while ( true )
|
||||
{
|
||||
self setFollowerHintString();
|
||||
|
||||
self.hvtTrigger waittill ( "trigger", player );
|
||||
|
||||
assert( player == self.owner );
|
||||
|
||||
self.hvtIsFollowing = !self.hvtIsFollowing;
|
||||
// do something with the AI
|
||||
|
||||
print( "Is Following: " + self.hvtIsFollowing );
|
||||
|
||||
self notify( "hvt_toggle" );
|
||||
}
|
||||
}
|
||||
|
||||
setFollowerHintString()
|
||||
{
|
||||
hintString = &"MP_HVT_FOLLOW";
|
||||
if ( self.hvtIsFollowing )
|
||||
{
|
||||
hintString = &"MP_HVT_WAIT";
|
||||
}
|
||||
self.hvtTrigger setHintString( hintString );
|
||||
}
|
||||
|
||||
waitForPlayerConnect()
|
||||
{
|
||||
level endon( "game_ended" );
|
||||
self endon( "death" );
|
||||
|
||||
while ( true )
|
||||
{
|
||||
level waittill( "connected", player );
|
||||
|
||||
self.hvtTrigger disablePlayerUse( player );
|
||||
}
|
||||
}
|
7
maps/mp/agents/_agents_gametype_aliens.gsc
Normal file
7
maps/mp/agents/_agents_gametype_aliens.gsc
Normal file
@ -0,0 +1,7 @@
|
||||
//=======================================================
|
||||
// main
|
||||
//=======================================================
|
||||
main()
|
||||
{
|
||||
// nothing for now...
|
||||
}
|
14
maps/mp/agents/_agents_gametype_blitz.gsc
Normal file
14
maps/mp/agents/_agents_gametype_blitz.gsc
Normal file
@ -0,0 +1,14 @@
|
||||
#include common_scripts\utility;
|
||||
#include maps\mp\_utility;
|
||||
#include maps\mp\gametypes\_gamelogic;
|
||||
#include maps\mp\bots\_bots_util;
|
||||
#include maps\mp\bots\_bots_strategy;
|
||||
#include maps\mp\bots\_bots_personality;
|
||||
|
||||
//=======================================================
|
||||
// main
|
||||
//=======================================================
|
||||
main()
|
||||
{
|
||||
// nothing for now...
|
||||
}
|
68
maps/mp/agents/_agents_gametype_conf.gsc
Normal file
68
maps/mp/agents/_agents_gametype_conf.gsc
Normal file
@ -0,0 +1,68 @@
|
||||
#include common_scripts\utility;
|
||||
#include maps\mp\_utility;
|
||||
#include maps\mp\gametypes\_gamelogic;
|
||||
#include maps\mp\bots\_bots_util;
|
||||
#include maps\mp\bots\_bots_strategy;
|
||||
#include maps\mp\bots\_bots_personality;
|
||||
|
||||
main()
|
||||
{
|
||||
setup_callbacks();
|
||||
}
|
||||
|
||||
setup_callbacks()
|
||||
{
|
||||
level.agent_funcs["squadmate"]["gametype_update"] = ::agent_squadmember_conf_think;
|
||||
level.agent_funcs["player"]["think"] = ::agent_player_conf_think;
|
||||
}
|
||||
|
||||
agent_player_conf_think()
|
||||
{
|
||||
self thread maps\mp\bots\_bots_gametype_conf::bot_conf_think();
|
||||
}
|
||||
|
||||
agent_squadmember_conf_think()
|
||||
{
|
||||
// Returning true means the "think" was handled here. "False" means use the default think
|
||||
|
||||
if ( !IsDefined(self.tags_seen_by_owner) )
|
||||
self.tags_seen_by_owner = [];
|
||||
|
||||
if ( !IsDefined(self.next_time_check_tags) )
|
||||
self.next_time_check_tags = GetTime() + 500;
|
||||
|
||||
if ( GetTime() > self.next_time_check_tags )
|
||||
{
|
||||
self.next_time_check_tags = GetTime() + 500;
|
||||
|
||||
current_player_fov = 0.78; // approximation
|
||||
nearest_node_to_player = self.owner GetNearestNode();
|
||||
if ( IsDefined(nearest_node_to_player) )
|
||||
{
|
||||
new_visible_tags_to_player = self.owner maps\mp\bots\_bots_gametype_conf::bot_find_visible_tags( true, nearest_node_to_player, current_player_fov );
|
||||
self.tags_seen_by_owner = maps\mp\bots\_bots_gametype_conf::bot_combine_tag_seen_arrays( new_visible_tags_to_player, self.tags_seen_by_owner );
|
||||
}
|
||||
}
|
||||
|
||||
self.tags_seen_by_owner = self maps\mp\bots\_bots_gametype_conf::bot_remove_invalid_tags( self.tags_seen_by_owner );
|
||||
best_tag = self maps\mp\bots\_bots_gametype_conf::bot_find_best_tag_from_array( self.tags_seen_by_owner, false );
|
||||
|
||||
if ( IsDefined(best_tag) )
|
||||
{
|
||||
if ( !IsDefined(self.tag_getting) || DistanceSquared(best_tag.curorigin, self.tag_getting.curorigin) > 1 )
|
||||
{
|
||||
self.tag_getting = best_tag;
|
||||
self bot_defend_stop();
|
||||
self BotSetScriptGoal( self.tag_getting.curorigin, 0, "objective", undefined, level.bot_tag_obj_radius );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if ( IsDefined(self.tag_getting) )
|
||||
{
|
||||
self BotClearScriptGoal();
|
||||
self.tag_getting = undefined;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
14
maps/mp/agents/_agents_gametype_cranked.gsc
Normal file
14
maps/mp/agents/_agents_gametype_cranked.gsc
Normal file
@ -0,0 +1,14 @@
|
||||
#include common_scripts\utility;
|
||||
#include maps\mp\_utility;
|
||||
#include maps\mp\gametypes\_gamelogic;
|
||||
#include maps\mp\bots\_bots_util;
|
||||
#include maps\mp\bots\_bots_strategy;
|
||||
#include maps\mp\bots\_bots_personality;
|
||||
|
||||
//=======================================================
|
||||
// main
|
||||
//=======================================================
|
||||
main()
|
||||
{
|
||||
// nothing for now...
|
||||
}
|
14
maps/mp/agents/_agents_gametype_dm.gsc
Normal file
14
maps/mp/agents/_agents_gametype_dm.gsc
Normal file
@ -0,0 +1,14 @@
|
||||
#include common_scripts\utility;
|
||||
#include maps\mp\_utility;
|
||||
#include maps\mp\gametypes\_gamelogic;
|
||||
#include maps\mp\bots\_bots_util;
|
||||
#include maps\mp\bots\_bots_strategy;
|
||||
#include maps\mp\bots\_bots_personality;
|
||||
|
||||
//=======================================================
|
||||
// main
|
||||
//=======================================================
|
||||
main()
|
||||
{
|
||||
// nothing for now...
|
||||
}
|
48
maps/mp/agents/_agents_gametype_dom.gsc
Normal file
48
maps/mp/agents/_agents_gametype_dom.gsc
Normal file
@ -0,0 +1,48 @@
|
||||
#include common_scripts\utility;
|
||||
#include maps\mp\_utility;
|
||||
#include maps\mp\gametypes\_gamelogic;
|
||||
#include maps\mp\bots\_bots_util;
|
||||
#include maps\mp\bots\_bots_strategy;
|
||||
#include maps\mp\bots\_bots_personality;
|
||||
|
||||
main()
|
||||
{
|
||||
setup_callbacks();
|
||||
}
|
||||
|
||||
setup_callbacks()
|
||||
{
|
||||
level.agent_funcs["squadmate"]["gametype_update"]= ::agent_squadmember_dom_think;
|
||||
level.agent_funcs["player"]["think"] = ::agent_player_dom_think;
|
||||
}
|
||||
|
||||
agent_player_dom_think()
|
||||
{
|
||||
self thread maps\mp\bots\_bots_gametype_dom::bot_dom_think();
|
||||
}
|
||||
|
||||
agent_squadmember_dom_think()
|
||||
{
|
||||
// Returning true means the "think" was handled here. "False" means use the default think
|
||||
|
||||
owner_flag = undefined;
|
||||
foreach( trigger in self.owner.touchTriggers )
|
||||
{
|
||||
if ( trigger.useobj.id == "domFlag" )
|
||||
owner_flag = trigger;
|
||||
}
|
||||
|
||||
if ( IsDefined(owner_flag) )
|
||||
{
|
||||
owner_flag_team = owner_flag maps\mp\gametypes\dom::getFlagTeam();
|
||||
if ( owner_flag_team != self.team )
|
||||
{
|
||||
if ( !self maps\mp\bots\_bots_gametype_dom::bot_is_capturing_flag( owner_flag ) )
|
||||
self maps\mp\bots\_bots_gametype_dom::capture_flag(owner_flag, "critical", true);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
20
maps/mp/agents/_agents_gametype_grind.gsc
Normal file
20
maps/mp/agents/_agents_gametype_grind.gsc
Normal file
@ -0,0 +1,20 @@
|
||||
#include common_scripts\utility;
|
||||
#include maps\mp\_utility;
|
||||
#include maps\mp\gametypes\_gamelogic;
|
||||
#include maps\mp\bots\_bots_util;
|
||||
#include maps\mp\bots\_bots_strategy;
|
||||
#include maps\mp\bots\_bots_personality;
|
||||
|
||||
//=======================================================
|
||||
// main
|
||||
//=======================================================
|
||||
main()
|
||||
{
|
||||
setup_callbacks();
|
||||
}
|
||||
|
||||
setup_callbacks()
|
||||
{
|
||||
level.agent_funcs["squadmate"]["gametype_update"] = maps\mp\agents\_agents_gametype_conf::agent_squadmember_conf_think;
|
||||
level.agent_funcs["player"]["think"] = maps\mp\agents\_agents_gametype_conf::agent_player_conf_think;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user