‪Black Ops 3 Source Code Explorer  0.1
‪An script explorer for Black Ops 3 by ZeRoY
_supplydrop.gsc
Go to the documentation of this file.
1 #using scripts\codescripts\struct;
2 
3 #using scripts\shared\callbacks_shared;
4 #using scripts\shared\challenges_shared;
5 #using scripts\shared\clientfield_shared;
6 #using scripts\shared\entityheadicons_shared;
7 #using scripts\shared\gameobjects_shared;
8 #using scripts\shared\hostmigration_shared;
9 #using scripts\shared\hud_util_shared;
10 #using scripts\shared\killstreaks_shared;
11 #using scripts\shared\popups_shared;
12 #using scripts\shared\scoreevents_shared;
13 #using scripts\shared\sound_shared;
14 #using scripts\shared\util_shared;
15 #using scripts\shared\weapons\_hacker_tool;
16 #using scripts\shared\weapons\_smokegrenade;
17 #using scripts\shared\weapons\_tacticalinsertion;
18 #using scripts\shared\weapons\_weapons;
19 #using scripts\shared\weapons\_heatseekingmissile;
20 #using scripts\shared\weapons\_weaponobjects;
21 #using scripts\shared\vehicleriders_shared;
22 #using scripts\shared\flag_shared;
23 #using scripts\shared\flagsys_shared;
24 
25 #using scripts\mp\_challenges;
26 #using scripts\mp\_util;
27 #using scripts\mp\gametypes\_battlechatter;
28 #using scripts\mp\gametypes\_hostmigration;
29 #using scripts\mp\killstreaks\_ai_tank;
30 #using scripts\mp\killstreaks\_airsupport;
31 #using scripts\mp\killstreaks\_emp;
32 #using scripts\mp\killstreaks\_helicopter;
33 #using scripts\mp\killstreaks\_killstreak_bundles;
34 #using scripts\mp\killstreaks\_killstreak_detect;
35 #using scripts\mp\killstreaks\_killstreak_hacking;
36 #using scripts\mp\killstreaks\_killstreak_weapons;
37 #using scripts\mp\killstreaks\_killstreakrules;
38 #using scripts\mp\killstreaks\_killstreaks;
39 #using scripts\mp\killstreaks\_supplydrop;
40 #using scripts\mp\killstreaks\_combat_robot;
41 
42 #insert scripts\mp\_hacker_tool.gsh;
43 #insert scripts\shared\shared.gsh;
44 #insert scripts\shared\version.gsh;
45 #insert scripts\mp\killstreaks\_killstreaks.gsh;
46 
47 #define SUPPLY_DROP_NAME "supply_drop"
48 #define SUPPLY_DROP_AI_TANK_NAME "supply_drop_ai_tank"
49 #define SUPPLY_DROP_COMBAT_ROBOT_NAME "supply_drop_combat_robot"
50 
51 #define SUPPY_DROP_ON_TARGET_DISTANCE 3.7
52 #define SUPPY_DROP_NAV_MESH_VALID_LOCATION_BOUNDARY 12
53 #define SUPPY_DROP_NAV_MESH_VALID_LOCATION_TOLERANCE 4
54 
55 #define SUPPLY_DROP_CRATE_STATE_NONE 0
56 #define SUPPLY_DROP_CRATE_STATE_CAPTURE 1
57 #define SUPPLY_DROP_CRATE_STATE_HACK 2
58 #define SUPPLY_DROP_CRATE_STATE_DISARM 3
59 
60 
61 #precache( "material", "compass_supply_drop_black" );
62 #precache( "material", "compass_supply_drop_green" );
63 #precache( "material", "compass_supply_drop_red" );
64 #precache( "material", "compass_supply_drop_white" );
65 #precache( "material", "waypoint_recon_artillery_strike" );
66 #precache( "material", "t7_hud_ks_wpn_turret_drop" );
67 #precache( "material", "t7_hud_ks_rolling_thunder_drop" );
68 #precache( "material", "t7_hud_ks_drone_amws_drop" );
69 
70 
71 // TODO: this is a placeholder head icon for when a supply drop is hacked and a booby trap is made
72 #precache( "material","headicon_dead");
73 #precache( "string", "KILLSTREAK_CAPTURING_CRATE" );
74 #precache( "string", "KILLSTREAK_HACKING_CRATE" );
75 #precache( "string", "KILLSTREAK_SUPPLY_DROP_DISARM_HINT" );
76 #precache( "triggerstring", "KILLSTREAK_SUPPLY_DROP_DISARM_HINT" );
77 #precache( "string", "KILLSTREAK_SUPPLY_DROP_DISARMING_CRATE" );
78 #precache( "string", "KILLSTREAK_SUPPLY_DROP_HACKED" );
79 
80 #precache( "triggerstring", "KILLSTREAK_AI_TANK_CRATE" );
81 #precache( "triggerstring", "KILLSTREAK_MINIGUN_CRATE" );
82 #precache( "triggerstring", "PLATFORM_MINIGUN_GAMBLER" );
83 #precache( "triggerstring", "KILLSTREAK_M32_CRATE" );
84 #precache( "triggerstring", "PLATFORM_M32_GAMBLER" );
85 #precache( "triggerstring", "KILLSTREAK_AMMO_CRATE" );
86 #precache( "triggerstring", "PLATFORM_AMMO_CRATE_GAMBLER" );
87 #precache( "triggerstring", "KILLSTREAK_RADAR_CRATE" );
88 #precache( "triggerstring", "PLATFORM_RADAR_GAMBLER" );
89 #precache( "triggerstring", "KILLSTREAK_RCBOMB_CRATE" );
90 #precache( "triggerstring", "PLATFORM_RCBOMB_GAMBLER" );
91 #precache( "triggerstring", "KILLSTREAK_MISSILE_DRONE_CRATE" );
92 #precache( "triggerstring", "PLATFORM_MISSILE_DRONE_GAMBLER" );
93 #precache( "triggerstring", "KILLSTREAK_COUNTERU2_CRATE" );
94 #precache( "triggerstring", "PLATFORM_COUNTERU2_GAMBLER" );
95 #precache( "triggerstring", "KILLSTREAK_REMOTE_MISSILE_CRATE" );
96 #precache( "triggerstring", "PLATFORM_REMOTE_MISSILE_GAMBLER" );
97 #precache( "triggerstring", "KILLSTREAK_PLANE_MORTAR_CRATE");
98 #precache( "triggerstring", "PLATFORM_PLANE_MORTAR_GAMBLER" );
99 #precache( "triggerstring", "KILLSTREAK_AUTO_TURRET_CRATE" );
100 #precache( "triggerstring", "PLATFORM_AUTO_TURRET_GAMBLER" );
101 #precache( "triggerstring", "KILLSTREAK_MICROWAVE_TURRET_CRATE" );
102 #precache( "triggerstring", "PLATFORM_MICROWAVE_TURRET_GAMBLER" );
103 #precache( "triggerstring", "KILLSTREAK_MINIGUN_CRATE" );
104 #precache( "triggerstring", "PLATFORM_MINIGUN_GAMBLER" );
105 #precache( "triggerstring", "KILLSTREAK_M32_CRATE" );
106 #precache( "triggerstring", "PLATFORM_M32_GAMBLER" );
107 #precache( "triggerstring", "KILLSTREAK_HELICOPTER_GUARD_CRATE" );
108 #precache( "triggerstring", "PLATFORM_HELICOPTER_GUARD_GAMBLER" );
109 #precache( "triggerstring", "KILLSTREAK_SATELLITE_CRATE" );
110 #precache( "triggerstring", "PLATFORM_SATELLITE_GAMBLER" );
111 #precache( "triggerstring", "KILLSTREAK_QRDRONE_CRATE" );
112 #precache( "triggerstring", "PLATFORM_QRDRONE_GAMBLER" );
113 #precache( "triggerstring", "KILLSTREAK_AI_TANK_CRATE" );
114 #precache( "triggerstring", "PLATFORM_AI_TANK_GAMBLER" );
115 #precache( "triggerstring", "KILLSTREAK_HELICOPTER_CRATE" );
116 #precache( "triggerstring", "PLATFORM_HELICOPTER_GAMBLER" );
117 #precache( "triggerstring", "KILLSTREAK_EMP_CRATE" );
118 #precache( "triggerstring", "PLATFORM_EMP_GAMBLER" );
119 #precache( "triggerstring", "KILLSTREAK_RAPS_CRATE" );
120 #precache( "triggerstring", "PLATFORM_RAPS_GAMBLER" );
121 #precache( "triggerstring", "KILLSTREAK_DART_CRATE" );
122 #precache( "triggerstring", "PLATFORM_DART_GAMBLER" );
123 #precache( "triggerstring", "KILLSTREAK_SENTINEL_CRATE" );
124 #precache( "triggerstring", "PLATFORM_SENTINEL_GAMBLER" );
125 #precache( "triggerstring", "KILLSTREAK_COMBAT_ROBOT_CRATE" );
126 #precache( "triggerstring", "PLATFORM_COMBAT_ROBOT_GAMBLER" );
127 #precache( "triggerstring", "KILLSTREAK_REMOTE_MORTAR_CRATE" );
128 #precache( "triggerstring", "PLATFORM_REMOTE_MORTAR_GAMBLER" );
129 #precache( "triggerstring", "KILLSTREAK_HELICOPTER_GUNNER_CRATE" );
130 #precache( "triggerstring", "PLATFORM_HELICOPTER_GUNNER_GAMBLER" );
131 #precache( "triggerstring", "KILLSTREAK_DOGS_CRATE" );
132 #precache( "triggerstring", "PLATFORM_DOGS_GAMBLER" );
133 #precache( "triggerstring", "KILLSTREAK_MISSILE_SWARM_CRATE" );
134 #precache( "triggerstring", "PLATFORM_MISSILE_SWARM_GAMBLER" );
135 #precache( "triggerstring", "KILLSTREAK_EARNED_SUPPLY_DROP" );
136 #precache( "triggerstring", "KILLSTREAK_DRONE_STRIKE_CRATE" );
137 #precache( "triggerstring", "PLATFORM_DRONE_STRIKE_GAMBLER" );
138 #precache( "triggerstring", "PLATFORM_AI_TANK_CRATE_GAMBLER" );
139 
140 #precache( "string", "KILLSTREAK_AIRSPACE_FULL" );
141 #precache( "string", "KILLSTREAK_SUPPLY_DROP_INBOUND" );
142 #precache( "string", "FriendlyBlue" );
143 #precache( "string", "EnemyOrange" );
144 #precache( "eventstring", "mpl_killstreak_supply" );
145 #precache( "fx", "killstreaks/fx_supply_drop_smoke" );
146 #precache( "fx", "explosions/fx_exp_grenade_default" );
147 
148 #using_animtree ( "mp_vehicles" );
149 
150 #namespace supplydrop;
151 
152 function ‪init()
153 {
154  level.crateModelFriendly = "wpn_t7_care_package_world";
155  level.crateModelEnemy = "wpn_t7_care_package_world";
156  level.crateModelTank = "wpn_t7_drop_box";
157  level.crateModelBoobyTrapped = "wpn_t7_care_package_world";
158  level.vtolDropHelicopterVehicleInfo = "vtol_supplydrop_mp";
159 
160  level.crateOwnerUseTime = 500;
161  level.crateNonOwnerUseTime = GetGametypeSetting("crateCaptureTime") * 1000;
162  level.crate_headicon_offset = (0, 0, 15);
163  level.supplyDropDisarmCrate = &"KILLSTREAK_SUPPLY_DROP_DISARM_HINT";
164  level.disarmingCrate = &"KILLSTREAK_SUPPLY_DROP_DISARMING_CRATE";
165 
166  level.supplydropCarePackageIdleAnim = %o_drone_supply_care_idle;
167  level.supplydropCarePackageDropAnim = %o_drone_supply_care_drop;
168  level.supplydropAiTankIdleAnim = %o_drone_supply_agr_idle;
169  level.supplydropAiTankDropAnim = %o_drone_supply_agr_drop;
170 
171  ‪clientfield::register( "helicopter", "supplydrop_care_package_state", ‪VERSION_SHIP, 1, "int" );
172  ‪clientfield::register( "helicopter", "supplydrop_ai_tank_state", ‪VERSION_SHIP, 1, "int" );
173 
174  ‪clientfield::register( "vehicle", "supplydrop_care_package_state", ‪VERSION_SHIP, 1, "int" );
175  ‪clientfield::register( "vehicle", "supplydrop_ai_tank_state", ‪VERSION_SHIP, 1, "int" );
176 
177  ‪clientfield::register( "scriptmover", "supplydrop_thrusters_state", ‪VERSION_SHIP, 1, "int" );
178  ‪clientfield::register( "scriptmover", "aitank_thrusters_state", ‪VERSION_SHIP, 1, "int" );
179 
180  ‪clientfield::register( "toplayer", "marker_state", ‪VERSION_SHIP, 2, "int" );
181 
182  level._supply_drop_smoke_fx = "killstreaks/fx_supply_drop_smoke";
183  level._supply_drop_explosion_fx = "explosions/fx_exp_grenade_default";
184 
185  ‪killstreaks::register( ‪SUPPLY_DROP_NAME, "supplydrop_marker", "killstreak_supply_drop", "supply_drop_used",&‪useKillstreakSupplyDrop, undefined, true );
186  ‪killstreaks::register_strings(‪SUPPLY_DROP_NAME, &"KILLSTREAK_EARNED_SUPPLY_DROP", &"KILLSTREAK_AIRSPACE_FULL", &"KILLSTREAK_SUPPLY_DROP_INBOUND", undefined, &"KILLSTREAK_SUPPLY_DROP_HACKED" );
187  ‪killstreaks::register_dialog(‪SUPPLY_DROP_NAME, "mpl_killstreak_supply", "supplyDropDialogBundle", "supplyDropPilotDialogBundle", "friendlySupplyDrop", "enemySupplyDrop", "enemySupplyDropMultiple", "friendlySupplyDropHacked", "enemySupplyDropHacked", "requestSupplyDrop", "threatSupplyDrop" );
191 
192  ‪killstreak_bundles::register_killstreak_bundle( "supply_drop_ai_tank" ); // only registering for damage processing only, to limit scope of change
193  ‪killstreak_bundles::register_killstreak_bundle( "supply_drop_combat_robot" ); // only registering for damage processing only, to limit scope of change
194 
195  level.crateTypes = [];
196  level.categoryTypeWeight = [];
197 
198  // percentage of drop explanation:
199  // add all of the numbers up: 15 + 2 + 3 + etc. = 80 for example
200  // now if you want to know the percentage of the minigun_mp drop, you'd do (minigun_mp number / total) or 2/80 = 2.5% chance of dropping
201  // right now this is at a perfect 1000, so the percentages are easy to understand
202  //registerCrateType( "supplydrop", "ammo", "ammo", 0, &"KILLSTREAK_AMMO_CRATE", &"PLATFORM_AMMO_CRATE_GAMBLER",&giveCrateAmmo );
203  ‪registerCrateType( "supplydrop", "killstreak", "uav", 125, &"KILLSTREAK_RADAR_CRATE", &"PLATFORM_RADAR_GAMBLER", &‪giveCrateKillstreak );
204  ‪registerCrateType( "supplydrop", "killstreak", "rcbomb", 105, &"KILLSTREAK_RCBOMB_CRATE", &"PLATFORM_RCBOMB_GAMBLER", &‪giveCrateKillstreak );
205  ‪registerCrateType( "supplydrop", "killstreak", "counteruav", 115, &"KILLSTREAK_COUNTERU2_CRATE", &"PLATFORM_COUNTERU2_GAMBLER", &‪giveCrateKillstreak );
206  ‪registerCrateType( "supplydrop", "killstreak", "remote_missile", 90, &"KILLSTREAK_REMOTE_MISSILE_CRATE", &"PLATFORM_REMOTE_MISSILE_GAMBLER", &‪giveCrateKillstreak );
207  ‪registerCrateType( "supplydrop", "killstreak", "planemortar", 80, &"KILLSTREAK_PLANE_MORTAR_CRATE", &"PLATFORM_PLANE_MORTAR_GAMBLER", &‪giveCrateKillstreak );
208  ‪registerCrateType( "supplydrop", "killstreak", "autoturret", 90, &"KILLSTREAK_AUTO_TURRET_CRATE", &"PLATFORM_AUTO_TURRET_GAMBLER", &‪giveCrateKillstreak );
209  ‪registerCrateType( "supplydrop", "killstreak", "microwave_turret", 120, &"KILLSTREAK_MICROWAVE_TURRET_CRATE", &"PLATFORM_MICROWAVE_TURRET_GAMBLER", &‪giveCrateKillstreak );
210  ‪registerCrateType( "supplydrop", "killstreak", "satellite", 20, &"KILLSTREAK_SATELLITE_CRATE", &"PLATFORM_SATELLITE_GAMBLER", &‪giveCrateKillstreak );
211  ‪registerCrateType( "supplydrop", "killstreak", "drone_strike", 75, &"KILLSTREAK_DRONE_STRIKE_CRATE", &"PLATFORM_DRONE_STRIKE_GAMBLER", &‪giveCrateKillstreak );
212  ‪registerCrateType( "supplydrop", "killstreak", "helicopter_comlink", 30, &"KILLSTREAK_HELICOPTER_CRATE", &"PLATFORM_HELICOPTER_GAMBLER", &‪giveCrateKillstreak );
213  ‪registerCrateType( "supplydrop", "killstreak", "emp", 5, &"KILLSTREAK_EMP_CRATE", &"PLATFORM_EMP_GAMBLER", &‪giveCrateKillstreak );
214 // registerCrateType( "supplydrop", "killstreak", "helicopter_player_gunner", 2, &"KILLSTREAK_HELICOPTER_GUNNER_CRATE", &"PLATFORM_HELICOPTER_GUNNER_GAMBLER",&giveCrateKillstreak );
215  ‪registerCrateType( "supplydrop", "killstreak", "raps", 20, &"KILLSTREAK_RAPS_CRATE", &"PLATFORM_RAPS_GAMBLER", &‪giveCrateKillstreak );
216  ‪registerCrateType( "supplydrop", "killstreak", "dart", 75, &"KILLSTREAK_DART_CRATE", &"PLATFORM_DART_GAMBLER", &‪giveCrateKillstreak );
217  ‪registerCrateType( "supplydrop", "killstreak", "sentinel", 20, &"KILLSTREAK_SENTINEL_CRATE", &"PLATFORM_SENTINEL_GAMBLER", &‪giveCrateKillstreak );
218  ‪registerCrateType( "supplydrop", "killstreak", "combat_robot", 5, &"KILLSTREAK_COMBAT_ROBOT_CRATE", &"PLATFORM_COMBAT_ROBOT_GAMBLER", &‪giveCrateKillstreak );
219  ‪registerCrateType( "supplydrop", "killstreak", "ai_tank_drop", 25, &"KILLSTREAK_AI_TANK_CRATE", &"PLATFORM_AI_TANK_CRATE_GAMBLER", &‪giveCrateKillstreak );
220 
221  ‪registerCrateType( "inventory_supplydrop", "killstreak", "uav", 125, &"KILLSTREAK_RADAR_CRATE", &"PLATFORM_RADAR_GAMBLER", &‪giveCrateKillstreak );
222  ‪registerCrateType( "inventory_supplydrop", "killstreak", "counteruav", 115, &"KILLSTREAK_COUNTERU2_CRATE", &"PLATFORM_COUNTERU2_GAMBLER", &‪giveCrateKillstreak );
223  ‪registerCrateType( "inventory_supplydrop", "killstreak", "rcbomb", 105, &"KILLSTREAK_RCBOMB_CRATE", &"PLATFORM_RCBOMB_GAMBLER", &‪giveCrateKillstreak );
224  ‪registerCrateType( "inventory_supplydrop", "killstreak", "remote_missile", 90, &"KILLSTREAK_REMOTE_MISSILE_CRATE", &"PLATFORM_REMOTE_MISSILE_GAMBLER", &‪giveCrateKillstreak );
225  ‪registerCrateType( "inventory_supplydrop", "killstreak", "planemortar", 80, &"KILLSTREAK_PLANE_MORTAR_CRATE", &"PLATFORM_PLANE_MORTAR_GAMBLER", &‪giveCrateKillstreak );
226  ‪registerCrateType( "inventory_supplydrop", "killstreak", "autoturret", 90, &"KILLSTREAK_AUTO_TURRET_CRATE", &"PLATFORM_AUTO_TURRET_GAMBLER", &‪giveCrateKillstreak );
227  ‪registerCrateType( "inventory_supplydrop", "killstreak", "microwave_turret", 120, &"KILLSTREAK_MICROWAVE_TURRET_CRATE", &"PLATFORM_MICROWAVE_TURRET_GAMBLER", &‪giveCrateKillstreak );
228  ‪registerCrateType( "inventory_supplydrop", "killstreak", "satellite", 20, &"KILLSTREAK_SATELLITE_CRATE", &"PLATFORM_SATELLITE_GAMBLER", &‪giveCrateKillstreak );
229  ‪registerCrateType( "inventory_supplydrop", "killstreak", "helicopter_comlink", 30, &"KILLSTREAK_HELICOPTER_CRATE", &"PLATFORM_HELICOPTER_GAMBLER", &‪giveCrateKillstreak );
230  ‪registerCrateType( "inventory_supplydrop", "killstreak", "emp", 5, &"KILLSTREAK_EMP_CRATE", &"PLATFORM_EMP_GAMBLER", &‪giveCrateKillstreak );
231 // registerCrateType( "inventory_supplydrop", "killstreak", "helicopter_player_gunner", 2, &"KILLSTREAK_HELICOPTER_GUNNER_CRATE", &"PLATFORM_HELICOPTER_GUNNER_GAMBLER", &giveCrateKillstreak );
232  ‪registerCrateType( "inventory_supplydrop", "killstreak", "raps", 20, &"KILLSTREAK_RAPS_CRATE", &"PLATFORM_RAPS_GAMBLER", &‪giveCrateKillstreak );
233  ‪registerCrateType( "inventory_supplydrop", "killstreak", "dart", 75, &"KILLSTREAK_DART_CRATE", &"PLATFORM_DART_GAMBLER", &‪giveCrateKillstreak );
234  ‪registerCrateType( "inventory_supplydrop", "killstreak", "sentinel", 20, &"KILLSTREAK_SENTINEL_CRATE", &"PLATFORM_SENTINEL_GAMBLER", &‪giveCrateKillstreak );
235  ‪registerCrateType( "inventory_supplydrop", "killstreak", "combat_robot", 5, &"KILLSTREAK_COMBAT_ROBOT_CRATE", &"PLATFORM_COMBAT_ROBOT_GAMBLER", &‪giveCrateKillstreak );
236  ‪registerCrateType( "inventory_supplydrop", "killstreak", "ai_tank_drop", 25, &"KILLSTREAK_AI_TANK_CRATE", &"PLATFORM_AI_TANK_CRATE_GAMBLER", &‪giveCrateKillstreak );
237  ‪registerCrateType( "inventory_supplydrop", "killstreak", "drone_strike", 75, &"KILLSTREAK_DRONE_STRIKE_CRATE", &"PLATFORM_DRONE_STRIKE_GAMBLER", &‪giveCrateKillstreak );
238 
239  ‪registerCrateType( "inventory_ai_tank_drop", "killstreak", "ai_tank_drop", 75, &"KILLSTREAK_AI_TANK_CRATE", undefined, undefined, &‪ai_tank::crateLand );
240  ‪registerCrateType( "ai_tank_drop", "killstreak", "ai_tank_drop", 75, &"KILLSTREAK_AI_TANK_CRATE", undefined, undefined, &‪ai_tank::crateLand );
241 
242  // for the gambler perk, have its own crate types with a greater chance to get good stuff
243  // right now this is at a perfect 1000, so the percentages are easy to understand
244  //registerCrateType( "gambler", "ammo", "ammo", 0, &"KILLSTREAK_AMMO_CRATE", undefined, &giveCrateAmmo );
245  ‪registerCrateType( "gambler", "killstreak", "uav", 95, &"KILLSTREAK_RADAR_CRATE", undefined, &‪giveCrateKillstreak );
246  ‪registerCrateType( "gambler", "killstreak", "counteruav", 85, &"KILLSTREAK_COUNTERU2_CRATE", undefined, &‪giveCrateKillstreak );
247  ‪registerCrateType( "gambler", "killstreak", "rcbomb", 75, &"KILLSTREAK_RCBOMB_CRATE", undefined, &‪giveCrateKillstreak );
248  ‪registerCrateType( "gambler", "killstreak", "microwave_turret", 110, &"KILLSTREAK_MICROWAVE_TURRET_CRATE", undefined, &‪giveCrateKillstreak );
249  ‪registerCrateType( "gambler", "killstreak", "remote_missile", 100, &"KILLSTREAK_REMOTE_MISSILE_CRATE", undefined, &‪giveCrateKillstreak );
250  ‪registerCrateType( "gambler", "killstreak", "planemortar", 80, &"KILLSTREAK_PLANE_MORTAR_CRATE", undefined, &‪giveCrateKillstreak );
251  ‪registerCrateType( "gambler", "killstreak", "autoturret", 100, &"KILLSTREAK_AUTO_TURRET_CRATE", undefined, &‪giveCrateKillstreak );
252 // registerCrateType( "gambler", "killstreak", "helicopter_guard", 0, &"KILLSTREAK_HELICOPTER_GUARD_CRATE", undefined, &giveCrateKillstreak );
253  ‪registerCrateType( "gambler", "killstreak", "satellite", 30, &"KILLSTREAK_SATELLITE_CRATE", undefined, &‪giveCrateKillstreak );
254  ‪registerCrateType( "gambler", "killstreak", "ai_tank_drop", 40, &"KILLSTREAK_AI_TANK_CRATE", undefined, &‪giveCrateKillstreak );
255  ‪registerCrateType( "gambler", "killstreak", "helicopter_comlink", 45, &"KILLSTREAK_HELICOPTER_CRATE", undefined, &‪giveCrateKillstreak );
256  ‪registerCrateType( "gambler", "killstreak", "emp", 10, &"KILLSTREAK_EMP_CRATE", undefined, &‪giveCrateKillstreak );
257 // registerCrateType( "gambler", "killstreak", "helicopter_player_gunner", 8, &"KILLSTREAK_HELICOPTER_GUNNER_CRATE", undefined, &giveCrateKillstreak );
258  ‪registerCrateType( "gambler", "killstreak", "raps", 35, &"KILLSTREAK_RAPS_CRATE", undefined, &‪giveCrateKillstreak );
259  ‪registerCrateType( "gambler", "killstreak", "dart", 75, &"KILLSTREAK_DART_CRATE", undefined, &‪giveCrateKillstreak );
260  ‪registerCrateType( "gambler", "killstreak", "sentinel", 35, &"KILLSTREAK_SENTINEL_CRATE", undefined, &‪giveCrateKillstreak );
261  ‪registerCrateType( "gambler", "killstreak", "combat_robot", 10, &"KILLSTREAK_COMBAT_ROBOT_CRATE", undefined, &‪giveCrateKillstreak );
262  ‪registerCrateType( "gambler", "killstreak", "drone_strike", 75, &"KILLSTREAK_DRONE_STRIKE_CRATE", undefined, &‪giveCrateKillstreak );
263 
264  level.crateCategoryWeights = [];
265  level.crateCategoryTypeWeights = [];
266 
267  foreach( categoryKey, category in level.crateTypes )
268  {
269  ‪finalizeCrateCategory( categoryKey );
270  }
271 
272  /#
273  level thread ‪supply_drop_dev_gui();
274  #/
275 }
276 
277 function ‪finalizeCrateCategory( category )
278 {
279  level.crateCategoryWeights[category] = 0;
280 
281  crateTypeKeys = getarraykeys( level.crateTypes[category] );
282 
283  // must leave this as a for loop not a foreach loop
284  // it must match the loop in getRandomCrateType
285  for ( crateType = 0; crateType < crateTypeKeys.size; crateType++ )
286  {
287  typeKey = crateTypeKeys[crateType];
288  level.crateTypes[category][typeKey].previousWeight = level.crateCategoryWeights[category];
289  level.crateCategoryWeights[category] += level.crateTypes[category][typeKey].weight;
290  level.crateTypes[category][typeKey].weight = level.crateCategoryWeights[category];
291  }
292 }
293 
295 {
296  level.crateCategoryTypeWeights[category] = 0;
297  crateTypeKeys = getarraykeys( level.categoryTypeWeight[category] );
298 
299  // must leave this as a for loop not a foreach loop
300  // it must match the loop in getRandomCrateType
301  for ( crateType = 0; crateType < crateTypeKeys.size; crateType++ )
302  {
303  typeKey = crateTypeKeys[crateType];
304  level.crateCategoryTypeWeights[category] += level.categoryTypeWeight[category][typeKey].weight;
305  level.categoryTypeWeight[category][typeKey].weight = level.crateCategoryTypeWeights[category];
306  }
307 
308  ‪finalizeCrateCategory( category );
309 }
310 
311 function ‪setCategoryTypeWeight( category, type, weight )
312 {
313  if ( !isdefined(level.categoryTypeWeight[category]) )
314  {
315  level.categoryTypeWeight[category] = [];
316  }
317 
318  level.categoryTypeWeight[category][type] = SpawnStruct();
319 
320  level.categoryTypeWeight[category][type].weight = weight;
321 
322  count = 0;
323  totalWeight = 0;
324  startIndex = undefined;
325  finalIndex = undefined;
326 
327  crateNameKeys = getarraykeys( level.crateTypes[category] );
328 
329  // must leave this as a for loop not a foreach loop
330  // it must match the loop in getRandomCrateType
331  for ( crateName = 0; crateName < crateNameKeys.size; crateName++ )
332  {
333  nameKey = crateNameKeys[crateName];
334 
335  if ( level.crateTypes[category][nameKey].type == type )
336  {
337  count++;
338  totalWeight = totalWeight + level.crateTypes[category][nameKey].weight;
339 
340  if ( !isdefined( startIndex ) )
341  {
342  startIndex = crateName;
343  }
344 
345  if ( isdefined( finalIndex ) && (( finalIndex + 1 ) != crateName ) )
346  {
347  /#‪util::error("Crate type declaration must be contiguous");#/
349 
350  return;
351  }
352 
353  finalIndex = crateName;
354  }
355  }
356 
357  level.categoryTypeWeight[category][type].totalCrateWeight = totalWeight;
358  level.categoryTypeWeight[category][type].crateCount = count;
359  level.categoryTypeWeight[category][type].startIndex = startIndex;
360  level.categoryTypeWeight[category][type].finalIndex = finalIndex;
361 }
362 
363 function ‪registerCrateType( category, type, ‪name, weight, hint, hint_gambler, giveFunction, landFunctionOverride )
364 {
365 /#
366  // do not register a crate for any scorestreak that does not exist
367  //if ( !killstreaks::is_registered(name) )
368  //{
369  // return;
370  //}
371 #/
372 
373  itemName = level.killstreaks[‪name].menuName;
374 
375  if( IsItemRestricted( itemName ) )
376  return;
377 
378  if ( !isdefined(level.crateTypes[category]) )
379  {
380  level.crateTypes[category] = [];
381  }
382 
383  crateType = SpawnStruct();
384  crateType.type = type;
385  crateType.name = ‪name;
386  crateType.weight = weight;
387  crateType.hint = hint;
388  crateType.hint_gambler = hint_gambler;
389  crateType.giveFunction = giveFunction;
391  if( isdefined(crateWeapon) )
392  {
393  crateType.objective = GetCrateHeadObjective( crateWeapon );
394  }
395  if ( isdefined( landFunctionOverride ) )
396  {
397  crateType.landFunctionOverride = landFunctionOverride;
398  }
399 
400  level.crateTypes[category][‪name] = crateType;
401 
402  game["strings"][‪name + "_hint"] = hint;
403 }
404 
405 function ‪getRandomCrateType( category, gambler_crate_name )
406 {
407  if( !isdefined(level.crateTypes) || !isdefined(level.crateTypes[category]) )
408  return;
409 
410  Assert( isdefined(level.crateTypes) );
411  Assert( isdefined(level.crateTypes[category]) );
412  Assert( isdefined(level.crateCategoryWeights[category]) );
413 
414  typeKey = undefined;
415  crateTypeStart = 0;
416  randomWeightEnd = RandomIntRange( 1, level.crateCategoryWeights[category] + 1 );
417  find_another = false;
418 
419  crateNameKeys = getarraykeys( level.crateTypes[category] );
420 
421  if ( isdefined( level.categoryTypeWeight[category] ) )
422  {
423  randomWeightEnd = RandomInt(level.crateCategoryTypeWeights[category] ) + 1;
424  crateTypeKeys = getarraykeys( level.categoryTypeWeight[category] );
425 
426  for ( crateType = 0; crateType < crateTypeKeys.size; crateType++ )
427  {
428  typeKey = crateTypeKeys[crateType];
429 
430  if ( level.categoryTypeWeight[category][typeKey].weight < randomWeightEnd )
431  continue;
432 
433  crateTypeStart = level.categoryTypeWeight[category][typeKey].startIndex;
434  randomWeightEnd = RandomInt( level.categoryTypeWeight[category][typeKey].totalCrateWeight) + 1;
435  randomWeightEnd += level.crateTypes[category][crateNameKeys[crateTypeStart]].previousWeight;
436  break;
437  }
438  }
439 
440  for ( crateType = crateTypeStart; crateType < crateNameKeys.size; crateType++ )
441  {
442  typeKey = crateNameKeys[crateType];
443 
444  if ( level.crateTypes[category][typeKey].weight < randomWeightEnd )
445  continue;
446 
447  // if we have the gambler perk then make sure we aren't getting the same thing again
448  if( isdefined( gambler_crate_name ) && level.crateTypes[category][typeKey].name == gambler_crate_name )
449  {
450  find_another = true;
451  }
452 
453  // go find another crate
454  if( find_another )
455  {
456  if( crateType < crateNameKeys.size - 1 )
457  {
458  crateType++;
459  }
460  else if( crateType > 0 )
461  {
462  crateType--;
463  }
464  typeKey = crateNameKeys[crateType];
465  }
466 
467  break;
468  }
469 
470  /#
471  if( isdefined(level.dev_gui_supply_drop) && level.dev_gui_supply_drop != "random" && level.dev_gui_supply_drop != "" )
472  {
473  typeKey = level.dev_gui_supply_drop;
474  }
475  #/
476 
477  return level.crateTypes[category][typeKey];
478 }
479 
480 function ‪giveCrateItem( crate )
481 {
482  if ( !IsAlive( self ) || !isdefined( crate.crateType ) )
483  return;
484 
485  Assert( isdefined(crate.crateType.giveFunction), "no give function defined for " + crate.crateType.name );
486 
487  return [[crate.crateType.giveFunction]]( "inventory_" + crate.crateType.name );
488 }
489 
490 function ‪giveCrateKillstreakWaiter( event, removeCrate, extraEndon )
491 {
492  self endon( "give_crate_killstreak_done" );
493  if ( isdefined( extraEndon ) )
494  {
495  self endon( extraEndon );
496  }
497  self waittill( event );
498  self notify( "give_crate_killstreak_done", removeCrate );
499 }
500 
501 function ‪giveCrateKillstreak( killstreak )
502 {
503  self ‪killstreaks::give( killstreak );
504 }
505 
507 {
508  switch ( weapon.name )
509  {
510  case "minigun":
511  level thread ‪popups::DisplayTeamMessageToAll( &"KILLSTREAK_MINIGUN_INBOUND", self );
512  level ‪weapons::add_limited_weapon( weapon, self, 3 );
513  break;
514  case "m32":
515  level thread ‪popups::DisplayTeamMessageToAll( &"KILLSTREAK_M32_INBOUND", self );
516  level ‪weapons::add_limited_weapon( weapon, self, 3 );
517  break;
518  case "m202_flash":
519  level thread ‪popups::DisplayTeamMessageToAll( &"KILLSTREAK_M202_FLASH_INBOUND", self );
520  level ‪weapons::add_limited_weapon( weapon, self, 3 );
521  break;
522  case "m220_tow":
523  level thread ‪popups::DisplayTeamMessageToAll( &"KILLSTREAK_M220_TOW_INBOUND", self );
524  level ‪weapons::add_limited_weapon( weapon, self, 3 );
525  break;
526  case "mp40_blinged":
527  level thread ‪popups::DisplayTeamMessageToAll( &"KILLSTREAK_MP40_INBOUND", self );
528  level ‪weapons::add_limited_weapon( weapon, self, 3 );
529  break;
530 
531  default:
532  break;
533  }
534 
535 }
536 
537 function ‪giveCrateWeapon( weapon_name )
538 {
539  weapon = GetWeapon(weapon_name);
540  if ( weapon == level.weaponNone )
541  return;
542 
543  currentWeapon = self GetCurrentWeapon();
544 
545  if ( currentWeapon == weapon || self HasWeapon( weapon ) )
546  {
547  self GiveMaxAmmo( weapon );
548  return true;
549  }
550 
551  // if the player is holding anything other than primary or secondary weapons,
552  // take away the last primary or secondary weapon the player was holding before giving the crate weapon.
553  if ( currentWeapon.isSupplyDropWeapon || isdefined( level.grenade_array[currentWeapon] )|| isdefined( level.inventory_array[currentWeapon] ) )
554  {
555  self TakeWeapon( self.lastdroppableweapon );
556  self GiveWeapon( weapon );
557  self switchToWeapon( weapon );
558  return true;
559  }
560 
561  self AddWeaponStat( weapon, "used", 1 );
562 
564 
565  self GiveWeapon( weapon );
566  self switchToWeapon( weapon );
567 
568  self waittill( "weapon_change", newWeapon );
569 
571 
572  return true;
573 }
574 
575 function ‪useSupplyDropMarker( package_contents_id, context )
576 {
577  player = self;
578  //self endon("death"); // never endon death in for this thread
579  self endon("disconnect");
580  self endon("spawned_player");
581 
582  supplyDropWeapon = level.weaponNone;
583  currentWeapon = self GetCurrentWeapon();
584  prevWeapon = currentWeapon;
585  if ( currentWeapon.isSupplyDropWeapon )
586  {
587  supplyDropWeapon = currentWeapon;
588  }
589 
590  if( supplyDropWeapon.isGrenadeWeapon )
591  trigger_event = "grenade_fire";
592  else
593  trigger_event = "weapon_fired";
594 
595  self thread ‪supplyDropWatcher( package_contents_id, trigger_event, supplyDropWeapon, context );
596 
597  self.supplyGrenadeDeathDrop = false;
598 
599  while( true )
600  {
601  player AllowMelee( false );
602  notifyString = self ‪util::waittill_any_return( "weapon_change", trigger_event, "disconnect", "spawned_player" );
603  player AllowMelee( true );
604 
605  if ( !isdefined( notifyString ) || ( notifyString != trigger_event ) )
606  {
607  ‪cleanup( context, player );
608  return false;
609  }
610 
611 
612  if( isdefined( player.markerPosition ) )
613  {
614  break;
615  }
616  }
617 
618  self notify ( "trigger_weapon_shutdown" );
619 
620  // for some reason we never had the supply drop weapon
621  if ( supplyDropWeapon == level.weaponNone )
622  {
623  ‪cleanup( context, player );
624  return false;
625  }
626 
627  if ( isdefined( self ) )
628  {
629  // don't take the supplyDropWeapon until the throwing (firing) state is completed
630  notifyString = self ‪util::waittill_any_return( "weapon_change", "death", "disconnect", "spawned_player" );
631 
632  self TakeWeapon( supplyDropWeapon );
633 
634  // if we no longer have the supply drop weapon in our inventory then
635  // it must have been successful
636  if ( self HasWeapon( supplyDropWeapon ) || self GetAmmoCount( supplyDropWeapon ) )
637  {
638  ‪cleanup( context, player );
639  return false;
640  }
641  }
642 
643  return true;
644 }
645 
646 function ‪isSupplyDropGrenadeAllowed( killstreak )
647 {
648  if ( !self ‪killstreakrules::isKillstreakAllowed( killstreak, self.team ) )
649  {
651 
652  return false;
653  }
654 
655  return true;
656 }
657 
658 function ‪AddDropLocation( killstreak_id, location )
659 {
660  level.droplocations[killstreak_id] = location;
661 }
662 
663 function ‪DelDropLocation( killstreak_id )
664 {
665  level.droplocations[killstreak_id] = undefined;
666 }
667 
668 function ‪IsLocationGood( location, context )
669 {
670  //check no zones
671  foreach( dropLocation in level.dropLocations )
672  {
673  if( Distance2DSquared( dropLocation, location ) < 60 * 60 )
674  return false;
675  }
676 
677  if ( context.perform_physics_trace === true )
678  {
680  if( isdefined( context.tracemask ) )
681  mask = context.tracemask;
682 
683  radius = context.radius;
684  //trace = physicstrace( location + ( 0,0, 5000 ), location + ( 0, 0, 10 ), ( -radius, -radius, 0 ), ( radius, radius, radius ), undefined, mask );
685  ‪trace = physicstrace( location + ( 0,0, 5000 ), location + ( 0, 0, 10 ), ( -radius, -radius, 0 ), ( radius, radius, 2 * radius ), undefined, mask );
686 
688 
689  if( ‪trace["fraction"] < 1 )
690  {
692  return false;
693  }
694  else
695  {
697  }
698  }
699 
700  // check for a valid start node
701  closestPoint = GetClosestPointOnNavMesh( location, max( context.max_dist_from_location, 24 ), context.dist_from_boundary );
702 
703  isValidPoint = isdefined( closestPoint );
704 
705  // make sure the selected point is roughly on the same floor
706  if ( isValidPoint && context.check_same_floor === true && Abs( location[2] - closestPoint[2] ) > 96 )
707  isValidPoint = false;
708 
709  if ( isValidPoint && Distance2DSquared( location, closestPoint ) > ‪SQR( context.max_dist_from_location ) )
710  isValidPoint = false;
711 
712 
713 /#
714  if ( GetDVarInt( "scr_supply_drop_valid_location_debug", 0 ) )
715  {
716  if ( !isValidPoint )
717  {
718  // debug draw closest valid location on nav mesh (red)
719  otherClosestPoint = GetClosestPointOnNavMesh( location, GetDVarFloat( "scr_supply_drop_valid_location_radius_debug", 96 ), context.dist_from_boundary );
720  if ( isdefined( otherClosestPoint ) )
721  {
722  sphere( otherClosestPoint, context.max_dist_from_location, ( 1, 0, 0 ), 0.8, false, 20, 1 );
723  }
724  }
725  else
726  {
727  // debug draw valid location on nav mesh (green)
728  sphere( closestPoint, context.max_dist_from_location, ( 0, 1, 0 ), 0.8, false, 20, 1 );
729  ‪util::drawcylinder( closestPoint, context.radius, 8000, 1.0/60.0, undefined, ( 0, 0.9, 0 ), 0.7 );
730  }
731  }
732 #/
733 
734  return isValidPoint;
735 }
736 
737 function ‪useKillstreakSupplyDrop( killstreak )
738 {
739  player = self;
740 
741  if ( !player ‪isSupplyDropGrenadeAllowed( killstreak ) )
742  return false;
743 
744  context = SpawnStruct();
745  context.radius = level.killstreakCoreBundle.ksAirdropSupplydropRadius;
746  context.dist_from_boundary = ‪SUPPY_DROP_NAV_MESH_VALID_LOCATION_BOUNDARY;
747  context.max_dist_from_location = ‪SUPPY_DROP_NAV_MESH_VALID_LOCATION_TOLERANCE;
748  context.perform_physics_trace = true;
749  context.isLocationGood = &‪IsLocationGood;
750  context.objective = &"airdrop_supplydrop";
751  context.validLocationSound = level.killstreakCoreBundle.ksValidCarepackageLocationSound;
753  context.dropTag = "tag_attach";
754  context.dropTagOffset = ( -32, 0, 23 );
755  context.killstreakType = killstreak;
756 
757  ‪result = player ‪useSupplyDropMarker( undefined, context );
758 
759  player notify( "supply_drop_marker_done" );
760 
761  if ( !isdefined( ‪result ) || !‪result )
762  return false;
763 
764  return ‪result;
765 }
766 
767 function ‪use_killstreak_death_machine( killstreak )
768 {
769  if ( !self ‪killstreakrules::isKillstreakAllowed( killstreak, self.team ) )
770  return false;
771 
772  weapon = GetWeapon( "minigun" );
773  currentWeapon = self GetCurrentWeapon();
774 
775  // if the player is holding anything other than primary or secondary weapons,
776  // take away the last primary or secondary weapon the player was holding before giving the crate weapon.
777  if ( currentWeapon.isSupplyDropWeapon || isdefined( level.grenade_array[currentWeapon] ) || isdefined( level.inventory_array[currentWeapon] ) )
778  {
779  self TakeWeapon( self.lastdroppableweapon );
780  self GiveWeapon( weapon );
781  self SwitchToWeapon( weapon );
782 
783  //This will make it so the player cannot pick up weapons while using this weapon for the first time.
784  self setBlockWeaponPickup( weapon, true );
785  return true;
786  }
787 
788  level thread ‪popups::DisplayTeamMessageToAll( &"KILLSTREAK_MINIGUN_INBOUND", self );
789  level ‪weapons::add_limited_weapon( weapon, self, 3 );
790 
791  self TakeWeapon( currentWeapon );
792  self GiveWeapon( weapon );
793  self SwitchToWeapon( weapon );
794 
795  //This will make it so the player cannot pick up weapons while using this weapon for the first time.
796  self setBlockWeaponPickup( weapon, true );
797  return true;
798 }
799 
800 function ‪use_killstreak_grim_reaper( killstreak )
801 {
802  if ( !self ‪killstreakrules::isKillstreakAllowed( killstreak, self.team ) )
803  return false;
804 
805  weapon = GetWeapon( "m202_flash" );
806  currentWeapon = self GetCurrentWeapon();
807 
808  // if the player is holding anything other than primary or secondary weapons,
809  // take away the last primary or secondary weapon the player was holding before giving the crate weapon.
810  if ( currentWeapon.isSupplyDropWeapon || isdefined( level.grenade_array[currentWeapon] ) || isdefined( level.inventory_array[currentWeapon] ) )
811  {
812  self TakeWeapon( self.lastdroppableweapon );
813  self GiveWeapon( weapon );
814  self SwitchToWeapon( weapon );
815 
816  //This will make it so the player cannot pick up weapons while using this weapon for the first time.
817  self setBlockWeaponPickup( weapon, true );
818  return true;
819  }
820 
821  level thread ‪popups::DisplayTeamMessageToAll( &"KILLSTREAK_M202_FLASH_INBOUND", self );
822  level ‪weapons::add_limited_weapon( weapon, self, 3 );
823 
824  self TakeWeapon( currentWeapon );
825  self GiveWeapon( weapon );
826  self SwitchToWeapon( weapon );
827 
828  //This will make it so the player cannot pick up weapons while using this weapon for the first time.
829  self setBlockWeaponPickup( weapon, true );
830  return true;
831 }
832 
834 {
835  if ( !‪killstreakrules::isKillstreakAllowed( killstreak, self.team ) )
836  {
837  self iPrintLnBold( level.killstreaks[ killstreak].notAvailableText );
838 
839  return false;
840  }
841 
842  weapon = GetWeapon( "m220_tow" );
843  currentWeapon = self GetCurrentWeapon();
844 
845  // if the player is holding anything other than primary or secondary weapons,
846  // take away the last primary or secondary weapon the player was holding before giving the crate weapon.
847  if ( currentWeapon.isSupplyDropWeapon || isdefined( level.grenade_array[currentWeapon] ) || isdefined( level.inventory_array[currentWeapon] ) )
848  {
849  self TakeWeapon( self.lastdroppableweapon );
850  self GiveWeapon( weapon );
851  self SwitchToWeapon( weapon );
852 
853  //This will make it so the player cannot pick up weapons while using this weapon for the first time.
854  self setBlockWeaponPickup( weapon, true );
855  return true;
856  }
857 
858  level thread ‪popups::DisplayTeamMessageToAll( &"KILLSTREAK_M220_TOW_INBOUND", self );
859  level ‪weapons::add_limited_weapon( weapon, self, 3 );
860 
861  self TakeWeapon( currentWeapon );
862  self GiveWeapon( weapon );
863  self SwitchToWeapon( weapon );
864 
865  //This will make it so the player cannot pick up weapons while using this weapon for the first time.
866  self setBlockWeaponPickup( weapon, true );
867  return true;
868 }
869 
870 function ‪use_killstreak_mp40( killstreak )
871 {
872  if ( !‪killstreakrules::isKillstreakAllowed( killstreak, self.team ) )
873  {
874  self iPrintLnBold( level.killstreaks[killstreak].notAvailableText );
875 
876  return false;
877  }
878 
879  weapon = GetWeapon( "mp40_blinged" );
880  currentWeapon = self GetCurrentWeapon();
881 
882  // if the player is holding anything other than primary or secondary weapons,
883  // take away the last primary or secondary weapon the player was holding before giving the crate weapon.
884  if ( currentWeapon.isSupplyDropWeapon || isdefined( level.grenade_array[currentWeapon] ) || isdefined( level.inventory_array[currentWeapon] ) )
885  {
886  self TakeWeapon( self.lastdroppableweapon );
887  self GiveWeapon( weapon );
888  self SwitchToWeapon( weapon );
889 
890  //This will make it so the player cannot pick up weapons while using this weapon for the first time.
891  self setBlockWeaponPickup( weapon, true );
892  return true;
893  }
894 
895  level thread ‪popups::DisplayTeamMessageToAll( &"KILLSTREAK_MP40_INBOUND", self );
896  level ‪weapons::add_limited_weapon( weapon, self, 3 );
897 
898  self TakeWeapon( currentWeapon );
899  self GiveWeapon( weapon );
900  self SwitchToWeapon( weapon );
901 
902  //This will make it so the player cannot pick up weapons while using this weapon for the first time.
903  self setBlockWeaponPickup( weapon, true );
904  return true;
905 }
906 
907 function ‪cleanUpWatcherOnDeath( team, killstreak_id )
908 {
909  player = self;
910  self endon( "disconnect" );
911  self endon( "supplyDropWatcher" );
912  self endon( "trigger_weapon_shutdown" );
913  self endon( "spawned_player" );
914  self endon( "weapon_change" );
915 
916  self ‪util::waittill_any( "death", "joined_team", "joined_spectators" );
917 
919  self notify( "cleanup_marker" );
920 }
921 
922 function ‪cleanup( context, player )
923 {
924  if( isdefined( context ) && isdefined( context.marker ) )
925  {
926  context.marker delete();
927  context.marker = undefined;
928  if( isdefined( context.markerFXHandle ) )
929  {
930  context.markerFXHandle delete();
931  context.markerFXHandle = undefined;
932  }
933 
934  if ( isdefined( player ) )
935  {
936  player ‪clientfield::set_to_player( "marker_state", 0 ); // off
937  }
938 
939  ‪DelDropLocation( context.killstreak_id );
940  }
941 }
942 
943 function ‪MarkerUpdateThread( context )
944 {
945  player = self;
946  player endon( "supplyDropWatcher" );
947  player endon( "spawned_player" );
948  player endon( "disconnect" );
949  player endon( "weapon_change" );
950  player endon( "death" );
951 
952  markerModel = ‪spawn( "script_model", ( 0, 0, 0 ) );
953  context.marker = markerModel;
954 
955  player thread ‪MarkerCleanupThread( context );
956 
957  while( true )
958  {
959  if( player ‪flagsys::get( "marking_done" ) )
960  break; // we dont delete the marker yet, just stop moving it around.
961 
962  minRange = level.killstreakCoreBundle.ksMinAirdropTargetRange;
963  maxRange = level.killstreakCoreBundle.ksMaxAirdropTargetRange;
964 
965  forwardVector = VectorScale( AnglesToForward( player GetPlayerAngles() ), maxRange );
966  //results = BulletTrace( player GetEye(), player GetEye() + forwardVector, false, player );
967 
969  if( isdefined( context.tracemask ) )
970  mask = context.tracemask;
971 
972  radius = 2;
973  results = physicstrace( player GetEye(), player GetEye() + forwardVector, ( -radius, -radius, 0 ), ( radius, radius, 2 * radius ), player, mask );
974 
975 
976  markerModel.origin = results["position"];
977 
978  tooClose = DistanceSquared( markerModel.origin, player.origin ) < minRange * minRange;
979 
980  if( ( results["normal"][2] > 0.7 ) && !tooClose && isdefined( context.isLocationGood ) && [[context.isLocationGood]]( markerModel.origin, context ) )
981  {
982  player.markerPosition = markerModel.origin;
983  player ‪clientfield::set_to_player( "marker_state", 1 ); // good
984  }
985  else
986  {
987  player.markerPosition = undefined;
988  player ‪clientfield::set_to_player( "marker_state", 2 ); // bad
989  }
990 
992  }
993 }
994 
995 function ‪supplyDropWatcher( package_contents_id, trigger_event, supplyDropWeapon, context )
996 {
997  player = self;
998  self notify( "supplyDropWatcher" );
999 
1000  self endon( "supplyDropWatcher" );
1001  self endon( "spawned_player" );
1002  self endon( "disconnect" );
1003  self endon( "weapon_change" );
1004 
1005  team = self.team;
1006 
1007  killstreak_id = ‪killstreakrules::killstreakStart( ‪SUPPLY_DROP_NAME, team, false, false );
1008  if ( killstreak_id == -1 )
1009  return;
1010 
1011  context.killstreak_id = killstreak_id;
1012 
1013  player ‪flagsys::clear( "marking_done" );
1014 
1015  if( !supplyDropWeapon.isGrenadeWeapon )
1016  self thread ‪MarkerUpdateThread( context );
1017 
1018  self thread ‪checkForEmp();
1019 
1020  self thread ‪checkWeaponChange( team, killstreak_id );
1021 
1022  self thread ‪cleanUpWatcherOnDeath( team, killstreak_id );
1023 
1024  while( true )
1025  {
1026  self waittill( trigger_event, weapon_instance, weapon );
1027 
1028  isSupplyDropWeapon = true;
1029  if( trigger_event == "grenade_fire" )
1030  isSupplyDropWeapon = weapon.isSupplyDropWeapon;
1031 
1032  if ( isdefined( self ) && isSupplyDropWeapon )
1033  {
1034  if( isdefined( context ) )
1035  {
1036  if( !isdefined( player.markerPosition ) || !supplydrop::islocationgood( player.markerPosition, context ) )
1037  {
1038  if( isdefined( level.killstreakCoreBundle.ksInvalidLocationSound ) )
1039  player playsoundtoplayer( level.killstreakCoreBundle.ksInvalidLocationSound, player );
1040 
1041  if( isdefined( level.killstreakCoreBundle.ksInvalidLocationString ) )
1042  player iPrintLnBold( Istring( level.killstreakCoreBundle.ksInvalidLocationString ) );
1043 
1044  continue;
1045  }
1046 
1047  if( isdefined( context.validLocationSound ) )
1048  player playsoundtoplayer( context.validLocationSound, player );
1049 
1050  self thread ‪heliDeliverCrate( player.markerPosition, weapon_instance, self, team, killstreak_id, package_contents_id, context );
1051  }
1052  else
1053  {
1054  self thread ‪doSupplyDrop( weapon_instance, weapon, self, killstreak_id, package_contents_id );
1055  weapon_instance thread ‪do_supply_drop_detonation( weapon, self );
1056  weapon_instance thread ‪supplyDropGrenadeTimeout( team, killstreak_id, weapon );
1057  }
1059  }
1060  else
1061  {
1063  self notify( "cleanup_marker" );
1064  }
1065 
1066  break;
1067  }
1068 
1069  player ‪flagsys::set( "marking_done" );
1070  player ‪clientfield::set_to_player( "marker_state", 0 );
1071 }
1072 
1073 function ‪checkForEmp()
1074 {
1075  self endon( "supplyDropWatcher" );
1076  self endon( "spawned_player" );
1077  self endon( "disconnect" );
1078  self endon( "weapon_change" );
1079  self endon( "death" );
1080  self endon( "trigger_weapon_shutdown" );
1081 
1082  self waittill( "emp_jammed" );
1083 
1085 }
1086 
1087 function ‪supplyDropGrenadeTimeout( team, killstreak_id, weapon )
1088 {
1089  self endon( "death" );
1090  self endon("stationary");
1091 
1092  GRENADE_LIFETIME = 10;
1093 
1094  //If the grenade hasn't stopped moving after a certain time delete it.
1095  wait( GRENADE_LIFETIME );
1096 
1097  if( !isdefined( self ) )
1098  return;
1099 
1100  self notify( "grenade_timeout" );
1101 
1103 
1104  if ( weapon.name == "ai_tank_drop" )
1105  {
1106  ‪killstreakrules::killstreakStop( "ai_tank_drop", team, killstreak_id );
1107  self notify( "cleanup_marker" );
1108  }
1109  else if ( weapon.name == "inventory_ai_tank_drop" )
1110  {
1111  ‪killstreakrules::killstreakStop( "inventory_ai_tank_drop", team, killstreak_id );
1112  self notify( "cleanup_marker" );
1113  }
1114  else if ( weapon.name == "combat_robot_drop" )
1115  {
1116  ‪killstreakrules::killstreakStop( "combat_robot_drop", team, killstreak_id );
1117  self notify( "cleanup_marker" );
1118  }
1119  else if ( weapon.name == "inventory_combat_robot_drop" )
1120  {
1121  ‪killstreakrules::killstreakStop( "inventory_combat_robot_drop", team, killstreak_id );
1122  self notify( "cleanup_marker" );
1123  }
1124 
1125  self delete();
1126 }
1127 
1128 function ‪checkWeaponChange( team, killstreak_id )
1129 {
1130  self endon( "supplyDropWatcher" );
1131  self endon( "spawned_player" );
1132  self endon( "disconnect" );
1133  self endon( "trigger_weapon_shutdown" );
1134  self endon( "death" );
1135 
1136  self waittill( "weapon_change" );
1138  self notify( "cleanup_marker" );
1139 }
1140 
1141 function ‪supplyDropGrenadePullWatcher( killstreak_id )
1142 {
1143  self endon( "disconnect" );
1144  self endon( "weapon_change" );
1145 
1146  self waittill ( "grenade_pullback", weapon );
1147 
1149 
1150  self thread ‪watchForGrenadePutDown();
1151 
1152  self waittill ( "death" );
1153 
1154  killstreak = ‪SUPPLY_DROP_NAME;
1155  self.supplyGrenadeDeathDrop = true;
1156 
1157  if( weapon.isSupplyDropWeapon )
1158  {
1159  killstreak = ‪killstreaks::get_killstreak_for_weapon( weapon );
1160  }
1161 
1162  if ( !‪IS_TRUE( self.usingKillstreakFromInventory ) )
1163  {
1164  self ‪killstreaks::change_killstreak_quantity( weapon, -1 );
1165  }
1166  else
1167  {
1168  ‪killstreaks::remove_used_killstreak( killstreak, killstreak_id );
1169  }
1170 }
1171 
1173 {
1174  self notify( "watchForGrenadePutDown" );
1175  self endon( "watchForGrenadePutDown" );
1176  self endon( "death" );
1177  self endon( "disconnect" );
1178 
1179  self ‪util::waittill_any( "grenade_fire", "weapon_change" );
1180 
1181  self notify ( "trigger_weapon_shutdown" );
1182 
1184 }
1185 
1187 {
1188  self endon( "supply_drop_marker_done" );
1189 
1190  self endon( "disconnect" );
1191  self endon( "spawned_player" );
1192 
1193  currentWeapon = self GetCurrentWeapon();
1194 
1195  while ( currentWeapon.isSupplyDropWeapon )
1196  {
1197  self waittill( "weapon_change", currentWeapon );
1198  }
1199 
1200  // if the killstreak ended because of a weapon change
1201  // give a frame to allow the weapon_change to trigger in other scripts
1202  waittillframeend;
1203 
1204  self notify( "supply_drop_marker_done" );
1205 }
1206 
1208 {
1209  icon = undefined;
1210 
1211  switch ( self.crateType.type )
1212  {
1213  case "killstreak":
1214  {
1215  if( isDefined(self.crateType.objective) )
1216  {
1217  return self.crateType.objective;
1218  }
1219  else if (self.crateType.name == "inventory_ai_tank_drop" )
1220  {
1221  icon = "t7_hud_ks_drone_amws";
1222  }
1223  else
1224  {
1225  killstreak = ‪killstreaks::get_menu_name( self.crateType.name );
1226  icon = level.killStreakIcons[killstreak];
1227  }
1228  }
1229  break;
1230 
1231  case "weapon":
1232  {
1233  switch( self.crateType.name )
1234  {
1235  case "minigun":
1236  icon = "hud_ks_minigun";
1237  break;
1238  case "m32":
1239  icon = "hud_ks_m32";
1240  break;
1241  case "m202_flash":
1242  icon = "hud_ks_m202";
1243  break;
1244  case "m220_tow":
1245  icon = "hud_ks_tv_guided_missile";
1246  break;
1247  case "mp40_drop":
1248  icon = "hud_mp40";
1249  break;
1250  default:
1251  icon = "waypoint_recon_artillery_strike";
1252  break;
1253  }
1254  }
1255  break;
1256 
1257  case "ammo":
1258  {
1259  icon = "hud_ammo_refill";
1260  }
1261  break;
1262 
1263  default:
1264  return undefined;
1265  break;
1266  }
1267 
1268  return icon + "_drop";
1269 }
1270 
1271 function ‪crateActivate( hacker )
1272 {
1273  self MakeUsable();
1274  self SetCursorHint("HINT_NOICON");
1275 
1276  if( !isdefined( self.crateType ) )
1277  return;
1278 
1279  self setHintString( self.crateType.hint );
1280  if ( isdefined( self.crateType.hint_gambler ) )
1281  {
1282  self setHintStringForPerk( "specialty_showenemyequipment", self.crateType.hint_gambler );
1283  }
1284 
1285  crateObjID = ‪gameobjects::get_next_obj_id();
1286  objective_add( crateObjID, "invisible", self.origin );
1287  //blue/friendly
1288  objective_icon( crateObjID, "compass_supply_drop_white" );
1289  objective_setcolor( crateObjID, &"FriendlyBlue" );
1290  objective_state( crateObjID, "active" );
1291  self.friendlyObjID = crateObjID;
1292  self.enemyObjID = [];
1293 
1294  icon = self ‪getIconForCrate();
1295 
1296  if (isdefined( hacker ))
1297  {
1298  // hacked crate stops appearing as enemy equipment
1299  self ‪clientfield::set( "enemyequip", 0 );
1300  }
1301 
1302  if ( level.teambased )
1303  {
1304  objective_team( crateObjID, self.team );
1305 
1306  foreach( team in level.teams )
1307  {
1308  if ( self.team == team )
1309  continue;
1310 
1311  crateObjID = ‪gameobjects::get_next_obj_id();
1312  objective_add( crateObjID, "invisible", self.origin );
1313  if( isdefined( self.hacker ) )
1314  {
1315  //black/hacked
1316  objective_icon( crateObjID, "compass_supply_drop_black" );
1317  }
1318  else
1319  {
1320  //orange/enemy
1321  objective_icon( crateObjID, "compass_supply_drop_white" );
1322  objective_setcolor( crateObjID, &"EnemyOrange" );
1323  }
1324  objective_team( crateObjID, team );
1325  objective_state( crateObjID, "active" );
1326  self.enemyObjID[self.enemyObjID.size] = crateObjID;
1327  }
1328  }
1329  else
1330  {
1331  if ( !self.visibleToAll )
1332  {
1333  Objective_SetInvisibleToAll( crateObjID );
1334 
1335  enemyCrateObjID = ‪gameobjects::get_next_obj_id();
1336  objective_add( enemyCrateObjID, "invisible", self.origin );
1337  objective_icon( enemyCrateObjID, "compass_supply_drop_white" );
1338  objective_setcolor( enemyCrateObjID, &"EnemyOrange" );
1339  objective_state( enemyCrateObjID, "active" );
1340 
1341  if ( isplayer( self.owner ) )
1342  {
1343  Objective_SetInvisibleToPlayer( enemyCrateObjID, self.owner );
1344  }
1345 
1346  self.enemyObjID[self.enemyObjID.size] = enemyCrateObjID;
1347  }
1348 
1349  if ( isplayer( self.owner ) )
1350  {
1351  Objective_SetVisibleToPlayer( crateObjID, self.owner );
1352  }
1353 
1354  if( isdefined( self.hacker ) )
1355  {
1356  Objective_SetInvisibleToPlayer( crateObjID, self.hacker );
1357 
1358  crateObjID = ‪gameobjects::get_next_obj_id();
1359  objective_add( crateObjID, "invisible", self.origin );
1360  //black/hacked
1361  objective_icon( crateObjID, "compass_supply_drop_black" );
1362  objective_state( crateObjID, "active" );
1363  Objective_SetInvisibleToAll( crateObjID );
1364  Objective_SetVisibleToPlayer( crateObjID, self.hacker );
1365  self.hackerObjID = crateObjID;
1366  }
1367  }
1368 
1369  if( !self.visibleToAll && isdefined( icon ) )
1370  {
1371  self ‪entityheadIcons::setEntityHeadIcon( self.team, self, level.crate_headicon_offset, icon, true );
1372  if( self.entityHeadObjectives.size > 0 )
1373  {
1374  objectiveID = self.entityHeadObjectives[self.entityHeadObjectives.size - 1];
1375  if( isdefined( objectiveID ) )
1376  {
1377  Objective_SetInvisibleToAll( objectiveID );
1378  Objective_SetVisibleToPlayer( objectiveID, self.owner );
1379  }
1380  }
1381  }
1382 
1383  if ( isdefined( self.owner ) && IsPlayer(self.owner) && self.owner ‪util::is_bot() )
1384  {
1385  self.owner notify( "bot_crate_landed", self );
1386  }
1387 
1388  if ( isdefined( self.owner ) )
1389  {
1390  self.owner notify( "crate_landed", self );
1391 
1392  ‪setRicochetProtectionEndTime( ‪SUPPLY_DROP_NAME, self.killstreak_id, self.owner );
1393  }
1394 }
1395 
1396 function ‪setRicochetProtectionEndTime( killstreak, killstreak_id, owner )
1397 {
1398  ksBundle = level.killstreakBundle[ killstreak ];
1399  if ( isdefined( ksBundle ) && isdefined( ksBundle.ksRicochetPostLandDuration ) && ksBundle.ksRicochetPostLandDuration > 0 )
1400  {
1401  endtime = GetTime() + ( ksBundle.ksRicochetPostLandDuration * 1000 );
1402  ‪killstreaks::set_ricochet_protection_endtime( killstreak_id, owner, endtime );
1403  }
1404 }
1405 
1407 {
1408  self makeunusable();
1409 
1410  if ( isdefined(self.friendlyObjID) )
1411  {
1412  Objective_Delete( self.friendlyObjID );
1413  ‪gameobjects::release_obj_id(self.friendlyObjID);
1414  self.friendlyObjID = undefined;
1415  }
1416 
1417  if ( isdefined(self.enemyObjID) )
1418  {
1419  foreach( objId in self.enemyObjID )
1420  {
1421  Objective_Delete( objId );
1423  }
1424  self.enemyObjID = [];
1425  }
1426 
1427  if ( isdefined(self.hackerObjID) )
1428  {
1429  Objective_Delete( self.hackerObjID );
1430  ‪gameobjects::release_obj_id(self.hackerObjID);
1431  self.hackerObjID = undefined;
1432  }
1433 }
1434 
1435 
1437 {
1438  self notify( "ownerTeamChangeWatcher_singleton" );
1439  self endon ("ownerTeamChangeWatcher_singleton");
1440 
1441  self endon("death");
1442 
1443  if ( !level.teamBased || !isdefined( self.owner ) )
1444  return;
1445 
1446  self.owner waittill("joined_team");
1447 
1448  self.owner = undefined;
1449 }
1450 
1451 function ‪dropAllToGround( origin, radius, stickyObjectRadius )
1452 {
1453  PhysicsExplosionSphere( origin, radius, radius, 0 );
1455  ‪weapons::drop_all_to_ground( origin, radius );
1456 
1457  ‪supplydrop::dropCratesToGround( origin, radius );
1458  level notify( "drop_objects_to_ground", origin, stickyObjectRadius );
1459 }
1460 
1462 {
1463  // a sphere with a radius of 44 covers the current supply drop exactly
1464  ‪dropAllToGround( origin, 70, 70 );
1465 }
1466 
1467 function ‪dropAllToGroundAfterCrateDelete( crate, crate_origin )
1468 {
1469  crate waittill("death");
1470  wait( 0.1 );
1471 
1472  crate ‪dropEverythingTouchingCrate( crate_origin );
1473 }
1474 
1475 function ‪dropCratesToGround( origin, radius )
1476 {
1477  crate_ents = GetEntArray( "care_package", "script_noteworthy" );
1478  radius_sq = radius * radius;
1479  for ( i = 0 ; i < crate_ents.size ; i++ )
1480  {
1481  if ( DistanceSquared( origin, crate_ents[i].origin ) < radius_sq )
1482  {
1483  crate_ents[i] thread ‪dropCrateToGround();
1484  }
1485  }
1486 }
1487 
1489 {
1490  self endon("death");
1491 
1492  if ( isdefined( self.droppingToGround ) )
1493  return;
1494 
1495  self.droppingToGround = true;
1496 
1497  // we need to recursively have this crate trigger a drop to ground as well
1498  ‪dropEverythingTouchingCrate( self.origin );
1499 
1500  self ‪crateDeactivate();
1501  self thread ‪crateDropToGroundKill();
1502  self ‪crateRedoPhysics();
1503  self ‪crateActivate();
1504 
1505  self.droppingToGround = undefined;
1506 }
1507 
1508 function ‪ConfigureTeamPost( owner )
1509 {
1510  crate = self;
1511 
1512  crate thread ‪ownerTeamChangeWatcher();
1513 }
1514 
1515 function ‪crateSpawn( killstreak, killstreakId, owner, team, drop_origin, drop_angle )
1516 {
1517  crate = ‪spawn( "script_model", drop_origin, 1 );
1518  crate ‪killstreaks::configure_team( killstreak, killstreakId, owner, undefined, undefined, &‪ConfigureTeamPost );
1519 
1520  crate.angles = drop_angle;
1521  crate.visibleToAll = false;
1522  crate.script_noteworthy = "care_package";
1523  crate ‪clientfield::set( "enemyequip", 1 );
1524 
1525  if ( killstreak == "ai_tank_drop" || killstreak == "inventory_ai_tank_drop" )
1526  {
1527  crate setModel( level.crateModelTank );
1528  crate setEnemyModel( level.crateModelTank );
1529  }
1530  else
1531  {
1532  crate setModel( level.crateModelFriendly );
1533  crate setEnemyModel( level.crateModelEnemy );
1534  }
1535 
1536  // Care Packages will cut the navmesh causing AI's to walk around them.
1537  crate DisconnectPaths();
1538 
1539  switch( killstreak )
1540  {
1541  case "turret_drop":
1542  crate.crateType = level.crateTypes[ killstreak ][ "autoturret" ];
1543  break;
1544  case "tow_turret_drop":
1545  crate.crateType = level.crateTypes[ killstreak ][ "auto_tow" ];
1546  break;
1547  case "m220_tow_drop":
1548  crate.crateType = level.crateTypes[ killstreak ][ "m220_tow" ];
1549  break;
1550  case "ai_tank_drop":
1551  case "inventory_ai_tank_drop":
1552  crate.crateType = level.crateTypes[ killstreak ][ "ai_tank_drop" ];
1553  break;
1554  case "minigun_drop":
1555  case "inventory_minigun_drop":
1556  crate.crateType = level.crateTypes[ killstreak ][ "minigun" ];
1557  break;
1558  case "m32_drop":
1559  case "inventory_m32_drop":
1560  crate.crateType = level.crateTypes[ killstreak ][ "m32" ];
1561  break;
1562  default:
1563  crate.crateType = ‪getRandomCrateType( "supplydrop" );
1564  break;
1565  }
1566 
1567  return crate;
1568 }
1569 
1571 {
1572  if( !isdefined( self ) )
1573  return;
1574 
1575  ‪killstreaks::remove_ricochet_protection( self.killstreak_id, self.originalowner );
1576 
1577  if( !isdefined( ‪drop_all_to_ground ) )
1578  {
1579  ‪drop_all_to_ground = true;
1580  }
1581 
1582  if ( isdefined(self.friendlyObjID) )
1583  {
1584  Objective_Delete( self.friendlyObjID );
1585  ‪gameobjects::release_obj_id(self.friendlyObjID);
1586  self.friendlyObjID = undefined;
1587  }
1588 
1589  if ( isdefined(self.enemyObjID) )
1590  {
1591  foreach( objId in self.enemyObjID )
1592  {
1593  Objective_Delete( objId );
1595  }
1596  self.enemyObjID = undefined;
1597  }
1598 
1599  if ( isdefined(self.hackerObjID) )
1600  {
1601  Objective_Delete( self.hackerObjID );
1602  ‪gameobjects::release_obj_id(self.hackerObjID);
1603  self.hackerObjID = undefined;
1604  }
1605 
1606  if( ‪drop_all_to_ground )
1607  {
1608  level thread ‪dropAllToGroundAfterCrateDelete( self, self.origin );
1609  }
1610 
1611  if ( isdefined ( self.killcament ) )
1612  {
1613  self.killcament thread ‪util::deleteAfterTime( 5 );
1614  }
1615 
1616  self Delete();
1617 }
1618 
1620 {
1621  self endon("death");
1622  self endon("stationary");
1623 
1624  wait( 3 ); // give some time for the physics to settle
1625 
1626  // if not turn it off and fire the notify
1627 
1628  self.angles = self.angles;
1629  self.origin = self.origin; // this should turn off the physics
1630 
1631  self notify( "stationary" );
1632 }
1633 
1635 {
1636  self endon("death");
1637  self endon("stationary");
1638 
1639  // if the crate has not stopped moving for some time just get rid of it
1640  wait( 20 );
1641 
1642  self ‪crateDelete( true );
1643 }
1644 
1646 {
1647  //forcePointVariance = 200.0;
1648  //vertVelocityMin = -100.0;
1649  //vertVelocityMax = 100.0;
1650 
1651  //forcePointX = RandomFloatRange( 0-forcePointVariance, forcePointVariance );
1652  //forcePointY = RandomFloatRange( 0-forcePointVariance, forcePointVariance );
1653  //forcePoint = ( forcePointX, forcePointY, 0 );
1654  //initialVelocityZ = RandomFloatRange( vertVelocityMin, vertVelocityMax );
1655  //forcePoint += self.origin;
1656 
1657  forcePoint = self.origin;
1658  params = level.killstreakBundle[‪SUPPLY_DROP_NAME];
1659  ‪DEFAULT( params.ksLandingVelocity, 100 );
1660  initialVelocity = ( 0, 0, -params.ksLandingVelocity / 40 );
1661 
1662  self PhysicsLaunch( forcePoint, initialVelocity );
1663 
1664  self thread ‪timeoutCrateWaiter();
1665  self thread ‪stationaryCrateOverride();
1666 
1667  self thread ‪update_crate_velocity();
1668  self thread ‪play_impact_sound();
1669 
1670  self waittill("stationary");
1671 }
1672 
1673 function ‪get_height( e_ignore )
1674 {
1675  ‪DEFAULT( e_ignore, self );
1676 
1677  const height_diff = 10;
1678  ‪trace = GroundTrace( self.origin + (0,0,height_diff), self.origin + ( 0, 0, -10000 ), false, e_ignore, false );
1679 
1680  /#
1681  recordLine( self.origin + (0,0,height_diff), ‪trace[ "position" ], ‪ORANGE, "Animscript", self );
1682  #/
1683 
1684  return Distance( self.origin, ‪trace[ "position" ] );
1685 }
1686 
1687 function ‪crateControlledDrop( killstreak, v_target_location )
1688 {
1689  crate = self;
1690 
1691  supplydrop = true;
1692  if( killstreak == ‪AI_TANK_AGR_NAME )
1693  supplydrop = false;
1694 
1695  if( supplydrop )
1696  params = level.killstreakBundle[‪SUPPLY_DROP_NAME];
1697  else
1698  params = level.killstreakBundle[‪AI_TANK_AGR_NAME];
1699 
1700  ‪DEFAULT( params.ksThrustersOffHeight, 100 );
1701  ‪DEFAULT( params.ksTotalDropTime, 4 );
1702  ‪DEFAULT( params.ksAccelTimePercentage, 0.65 );
1703 
1704  accelTime = params.ksTotalDropTime * params.ksAccelTimePercentage;
1705  decelTime = params.ksTotalDropTime - accelTime;
1706 
1707  target = ( v_target_location[0], v_target_location[1], v_target_location[2] + params.ksThrustersOffHeight );
1708 
1710  crate moveto( target, params.ksTotalDropTime, accelTime, decelTime ) ;
1711 
1712  crate thread ‪WatchForCrateKill( v_target_location[2] + ‪VAL( params.ksStartCrateKillHeightFromGround, 200 ) );
1713 
1714  wait( accelTime - 0.05 );
1715 
1716  if( supplydrop )
1717  crate ‪clientfield::set( "supplydrop_thrusters_state", 1 );
1718  else
1719  crate ‪clientfield::set( "aitank_thrusters_state", 1 );
1720 
1721  crate waittill( "movedone" );
1722 
1724 
1725  if( supplydrop )
1726  crate ‪clientfield::set( "supplydrop_thrusters_state", 0 );
1727  else
1728  crate ‪clientfield::set( "aitank_thrusters_state", 0 );
1729 
1730  crate ‪cratePhysics();
1731 }
1732 
1733 function ‪play_impact_sound() //self == crate
1734 {
1735  self endon( "entityshutdown" );
1736  self endon( "stationary" );
1737  self endon( "death" );
1738 
1739  wait( 0.5 ); //this wait is to delay the fall speed check
1740 
1741  while( abs( self.velocity[2] ) > 5 ) //this is not 0 since the crate will sometimes rock a bit before it stops moving
1742  {
1743  wait( 0.1 );
1744  }
1745 
1746  self PlaySound( "phy_impact_supply" );
1747 }
1748 
1749 function ‪update_crate_velocity() //self == crate
1750 {
1751  self endon( "entityshutdown" );
1752  self endon( "stationary" );
1753 
1754  self.velocity = ( 0,0,0 );
1755  self.old_origin = self.origin;
1756 
1757  while( isdefined( self ) )
1758  {
1759  self.velocity = ( self.origin - self.old_origin );
1760  self.old_origin = self.origin;
1761 
1763  }
1764 }
1765 
1766 
1768 {
1769  forcePoint = self.origin;
1770 
1771  initialVelocity = ( 0, 0, 0 );
1772 
1773  self PhysicsLaunch(forcePoint,initialVelocity);
1774 
1775  self thread ‪timeoutCrateWaiter();
1776  self thread ‪stationaryCrateOverride();
1777 
1778  self waittill("stationary");
1779 }
1780 
1781 function ‪do_supply_drop_detonation( weapon, owner ) // self == weapon_instance
1782 {
1783  self notify( "supplyDropWatcher" );
1784 
1785  self endon( "supplyDropWatcher" );
1786  self endon( "spawned_player" );
1787  self endon( "disconnect" );
1788  self endon( "death" );
1789  self endon ( "grenade_timeout" );
1790 
1791  // control the explosion events to circumvent the code cleanup
1793  self.angles = ( 0, self.angles[1], 90 );
1794  fuse_time = weapon.fuseTime / 1000; // fuse time comes back in milliseconds
1795  wait( fuse_time );
1796 
1797  if ( !isdefined( owner ) || !owner ‪EMP::EnemyEMPActive() )
1798  {
1799  thread ‪smokegrenade::playSmokeSound( self.origin, 6, level.sound_smoke_start, level.sound_smoke_stop, level.sound_smoke_loop );
1800  PlayFXOnTag( level._supply_drop_smoke_fx, self, "tag_fx" );
1801  proj_explosion_sound = weapon.projExplosionSound;
1802  ‪sound::play_in_space( proj_explosion_sound, self.origin );
1803  }
1804 
1805  // need to clean up the canisters
1806  wait( 3 );
1807  self delete();
1808 }
1809 
1810 function ‪doSupplyDrop( weapon_instance, weapon, owner, killstreak_id, package_contents_id, context )
1811 {
1812  weapon endon ( "explode" );
1813  weapon endon ( "grenade_timeout" );
1814  self endon( "disconnect" );
1815  team = owner.team;
1816  weapon_instance thread ‪watchExplode( weapon, owner, killstreak_id, package_contents_id );
1817  weapon_instance ‪util::waitTillNotMoving();
1818  weapon_instance notify( "stoppedMoving" );
1819 
1820  self thread ‪heliDeliverCrate( weapon_instance.origin, weapon, owner, team, killstreak_id, package_contents_id, context );
1821 }
1822 
1823 function ‪watchExplode( weapon, owner, killstreak_id, package_contents_id )
1824 {
1825  self endon( "stoppedMoving" );
1826  team = owner.team;
1827  self waittill( "explode", position );
1828 
1829  owner thread ‪heliDeliverCrate( position, weapon, owner, team, killstreak_id, package_contents_id );
1830 }
1831 
1833 {
1834  crate = self;
1835  ‪crateTimeOut( 90 );
1836  crate thread deleteOnOwnerLeave();
1837 }
1838 function ‪crateTimeOut( time )
1839 {
1840  crate = self;
1841  self thread ‪killstreaks::WaitForTimeout( "inventory_supply_drop", 90 * 1000, &‪crateDelete, "death" );
1842 }
1843 
1845 {
1846  crate = self;
1847  crate endon( "death" );
1848  crate.owner ‪util::waittill_any( "joined_team", "joined_spectators", "disconnect" );
1849  crate ‪crateDelete( true );
1850 }
1851 
1852 function ‪WaitAndDelete( time )
1853 {
1854  self endon( "death" );
1855  wait( time );
1856  self delete();
1857 }
1858 
1859 function ‪dropCrate( origin, angle, killstreak, owner, team, killcamEnt, killstreak_id, package_contents_id, crate_, context )
1860 {
1861  angle = ( angle[0] * 0.5, angle[1] * 0.5, angle[2] * 0.5 );
1862 
1863  if ( isdefined( crate_ ) )
1864  {
1865  origin = crate_.origin;
1866  angle = crate_.angles;
1867  crate_ thread ‪WaitAndDelete( 0.1 );
1868  }
1869  crate = ‪crateSpawn( killstreak, killstreak_id, owner, team, origin, angle );
1870  killCamEnt unlink();
1871  killCamEnt linkto( crate );
1872  crate.killcamEnt = killcamEnt;
1873  crate.killstreak_id = killstreak_id;
1874  crate.package_contents_id = package_contents_id;
1875  killCamEnt thread ‪util::deleteAfterTime( 15 );
1876  killCamEnt thread ‪unlinkOnRotation( crate );
1877 
1878  crate endon("death");
1879 
1880  crate ‪crateTimeOutThreader();
1881 
1882  ‪trace = GroundTrace( crate.origin + ( 0, 0, -100 ), crate.origin + ( 0, 0, -10000 ), false, crate, false );
1883  v_target_location = ‪trace["position"];
1884 
1885 /#
1886  if ( GetDvarInt( "scr_supply_drop_valid_location_debug", 0 ) )
1887  {
1888  ‪util::drawcylinder( v_target_location, context.radius, 8000, 99999999, "stop_heli_drop_valid_location_dropped_cylinder", ( 0, 0, 0.9 ), 0.8 );
1889  }
1890 #/
1891 
1892  crate ‪crateControlledDrop(killstreak, v_target_location );
1893 
1894  crate thread ‪hacker_tool::registerWithHackerTool( level.carePackageHackerToolRadius, level.carePackageHackerToolTimeMs );
1895 
1896  ‪cleanup( context, owner ) ;
1897 
1898  if ( isdefined( crate.crateType ) && isdefined( crate.crateType.landFunctionOverride ) )
1899  {
1900  [[crate.crateType.landFunctionOverride]]( crate, killstreak, owner, team, context );
1901  }
1902  else
1903  {
1904  crate ‪crateActivate();
1905 
1906  crate thread ‪crateUseThink();
1907  crate thread ‪crateUseThinkOwner();
1908 
1909  if( isdefined( crate.crateType ) && isdefined( crate.crateType.hint_gambler ))
1910  {
1911  crate thread ‪crateGamblerThink();
1912  }
1913 
1914  ‪default_land_function( crate, killstreak, owner, team );
1915  }
1916 
1917 
1918 }
1919 
1920 function ‪unlinkOnRotation( crate )
1921 {
1922  self endon( "delete" );
1923  crate endon( "death" );
1924  crate endon( "entityshutdown" );
1925  crate endon( "stationary" );
1926 
1927  waitBeforeRotationCheck = GetDvarFloat( "scr_supplydrop_killcam_rot_wait", 0.5 );
1928  wait( waitBeforeRotationCheck ); //this wait is to delay the fall speed check
1929 
1930  minCos = GetDvarFloat( "scr_supplydrop_killcam_max_rot", 0.999 );
1931 
1932  cosine = 1;
1933 
1934  currentDirection = VectorNormalize( AnglesToForward( crate.angles ) );
1935 
1936  while( cosine > minCos )
1937  {
1938  oldDirection = currentDirection;
1940  currentDirection = VectorNormalize( AnglesToForward( crate.angles ) );
1941  cosine = vectordot( oldDirection, currentDirection );
1942  }
1943  self unlink();
1944 }
1945 
1946 
1947 function ‪default_land_function( crate, category, owner, team )
1948 {
1949  while ( 1 )
1950  {
1951  crate waittill("captured", player, remote_hack );
1952 
1953  player ‪challenges::capturedCrate( owner );
1954  deleteCrate = player ‪giveCrateItem( crate );
1955  if ( isdefined( deleteCrate ) && !deleteCrate )
1956  {
1957  continue;
1958  }
1959 
1960  playerHasEngineerPerk = player HasPerk( "specialty_showenemyequipment" );
1961 
1962  // added functionality to specialty_showenemyequipment to create a booby trapped supply crate once this is captured
1963  if( ( playerHasEngineerPerk || remote_hack==true ) &&
1964  owner != player &&
1965  ((level.teambased && team != player.team) || !level.teambased) )
1966  {
1967  // spawn an explosive crate right before we delete the other
1968  ‪spawn_explosive_crate( crate.origin, crate.angles, category, owner, team, player, playerHasEngineerPerk );
1969  crate MakeUnusable();
1970  ‪util::wait_network_frame(); // to avoid crate blinking
1971  crate ‪crateDelete( false );
1972  }
1973  else
1974  {
1975  crate ‪crateDelete( true );
1976  }
1977  return;
1978  }
1979 }
1980 
1981 function ‪spawn_explosive_crate( origin, angle, killstreak, owner, team, hacker, playerHasEngineerPerk ) // self == crate
1982 {
1983  // No killstreakId needed since there's currently no dialog to attach to an exploding crate
1984  crate = ‪crateSpawn( killstreak, undefined, owner, team, origin, angle );
1985  crate SetOwner( owner );
1986  crate SetTeam( team );
1987 
1988  if ( level.teambased )
1989  {
1990  crate setEnemyModel( level.crateModelBoobyTrapped );
1991  crate MakeUsable( team );
1992  }
1993  else
1994  {
1995  crate setEnemyModel( level.crateModelEnemy );
1996  }
1997 
1998  crate.hacker = hacker;
1999  crate.visibleToAll = false;
2000  crate ‪crateActivate( hacker );
2001  crate setHintStringForPerk( "specialty_showenemyequipment", level.supplyDropDisarmCrate );
2002  crate thread ‪crateUseThink();
2003  crate thread ‪crateUseThinkOwner();
2004  crate thread ‪watch_explosive_crate();
2005  crate ‪crateTimeOutThreader();
2006  crate.playerHasEngineerPerk = playerHasEngineerPerk;
2007 }
2008 
2009 function ‪watch_explosive_crate() // self == crate
2010 {
2011  killCamEnt = ‪spawn( "script_model", self.origin + (0,0,60) );
2012  self.killcament = killcament;
2013  self waittill( "captured", player, remote_hack );
2014 
2015  // give warning and then explode if the capturer didnt have hacker perk
2016  if ( !player HasPerk( "specialty_showenemyequipment" ) && !remote_hack )
2017  {
2018  self thread ‪entityheadIcons::setEntityHeadIcon( player.team, player, level.crate_headicon_offset, "headicon_dead", true );
2019  self ‪loop_sound( "wpn_semtex_alert", 0.15 );
2020 
2021  if( !isdefined( self.hacker ) )
2022  {
2023  self.hacker = self;
2024  }
2025  self RadiusDamage( self.origin, 256, 300, 75, self.hacker, "MOD_EXPLOSIVE", GetWeapon( "supplydrop" ) );
2026  PlayFX( level._supply_drop_explosion_fx, self.origin );
2027  PlaySoundAtPosition( "wpn_grenade_explode", self.origin );
2028  }
2029  else
2030  {
2031  PlaySoundAtPosition ( "mpl_turret_alert", self.origin );
2032  ‪scoreevents::processScoreEvent( "disarm_hacked_care_package", player );
2034  }
2035  wait ( 0.1 );
2036  self ‪crateDelete();
2037  killcament thread ‪util::deleteAfterTime( 5 );
2038 }
2039 
2040 function ‪loop_sound( alias, interval ) // self == crate
2041 {
2042  self endon( "death" );
2043  while( 1 )
2044  {
2045  PlaySoundAtPosition( alias, self.origin );
2046 
2047  wait interval;
2048  interval = (interval / 1.2);
2049 
2050  if (interval < .08)
2051  {
2052  break;
2053  }
2054  }
2055 }
2056 
2057 function ‪WatchForCrateKill( start_kill_watch_z_threshold )
2058 {
2059  crate = self;
2060  crate endon( "death" );
2061  crate endon( "stationary" );
2062 
2063  while ( crate.origin[2] > start_kill_watch_z_threshold )
2064  {
2066  }
2067 
2068  stationaryThreshold = 2;
2069  killThreshold = 15;
2070  maxFramesTillStationary = 20;
2071  numFramesStationary = 0;
2072 
2073  while( true )
2074  {
2075  vel = 0;
2076  if( isdefined( self.velocity ) )
2077  vel = abs( self.velocity[2] );
2078 
2079  if( vel > killThreshold )
2080  {
2081  crate ‪is_touching_crate();
2083  }
2084 
2085  if( vel < stationaryThreshold )
2086  numFramesStationary++;
2087  else
2088  numFramesStationary = 0;
2089 
2090  if( numFramesStationary >= maxFramesTillStationary )
2091  break;
2092 
2094  }
2095 }
2096 
2097 function ‪crateKill() // self == crate
2098 {
2099  self endon( "death" );
2100 
2101  // kill anyone under it
2102  stationaryThreshold = 2;
2103  killThreshold = 15;
2104  maxFramesTillStationary = 20;
2105  numFramesStationary = 0;
2106  while( true )
2107  {
2108  vel = 0;
2109  if ( isdefined( self.velocity ) )
2110  vel = abs( self.velocity[2] );
2111 
2112  if ( vel > killThreshold )
2113  {
2114  self ‪is_touching_crate();
2116  }
2117 
2118  if ( vel < stationaryThreshold )
2119  numFramesStationary++;
2120  else
2121  numFramesStationary = 0;
2122 
2123  if ( numFramesStationary >= maxFramesTillStationary )
2124  break;
2125 
2126  wait 0.01;
2127  }
2128 }
2129 
2131 {
2132  self endon( "death" );
2133  self endon( "stationary" );
2134 
2135  for ( ;; )
2136  {
2137  players = GetPlayers();
2138  doTrace = false;
2139 
2140  for ( i = 0; i < players.size; i++ )
2141  {
2142  if ( players[i].sessionstate != "playing" )
2143  continue;
2144 
2145  if ( players[i].team == "spectator" )
2146  continue;
2147 
2148  //Check if any equipment gets landed on
2149  self ‪is_equipment_touching_crate( players[i] );
2150 
2151  if ( !IsAlive( players[i] ) )
2152  continue;
2153 
2154  flattenedSelfOrigin = (self.origin[0], self.origin[1], 0 );
2155  flattenedPlayerOrigin = (players[i].origin[0], players[i].origin[1], 0 );
2156 
2157  if ( DistanceSquared( flattenedSelfOrigin, flattenedPlayerOrigin ) > 64 * 64 )
2158  continue;
2159 
2160  doTrace = true;
2161  break;
2162  }
2163 
2164  // do the trace
2165  if ( doTrace )
2166  {
2167  start = self.origin;
2168  ‪crateDropToGroundTrace( start );
2169 
2170  start = self GetPointInBounds( 1.0, 0.0, 0.0 );
2171  ‪crateDropToGroundTrace( start );
2172 
2173  start = self GetPointInBounds( -1.0, 0.0, 0.0 );
2174  ‪crateDropToGroundTrace( start );
2175 
2176  start = self GetPointInBounds( 0.0, -1.0, 0.0 );
2177  ‪crateDropToGroundTrace( start );
2178 
2179  start = self GetPointInBounds( 0.0, 1.0, 0.0 );
2180  ‪crateDropToGroundTrace( start );
2181 
2182  start = self GetPointInBounds( 1.0, 1.0, 0.0 );
2183  ‪crateDropToGroundTrace( start );
2184 
2185  start = self GetPointInBounds( -1.0, 1.0, 0.0 );
2186  ‪crateDropToGroundTrace( start );
2187 
2188  start = self GetPointInBounds( 1.0, -1.0, 0.0 );
2189  ‪crateDropToGroundTrace( start );
2190 
2191  start = self GetPointInBounds( -1.0, -1.0, 0.0 );
2192  ‪crateDropToGroundTrace( start );
2193 
2194  wait( 0.2 );
2195  }
2196  else
2197  {
2198  wait( 0.5 );
2199  }
2200  }
2201 }
2202 
2203 function ‪crateDropToGroundTrace( start )
2204 {
2205  ‪end = start + ( 0, 0, -8000 );
2206 
2207  ‪trace = BulletTrace( start, ‪end, true, self, true, true );
2208 
2209  if ( isdefined( ‪trace[ "entity" ] ) && IsPlayer( ‪trace[ "entity" ] ) && IsAlive( ‪trace[ "entity" ] ) )
2210  {
2211  player = ‪trace[ "entity" ];
2212 
2213  if ( player.sessionstate != "playing" )
2214  return;
2215 
2216  if ( player.team == "spectator" )
2217  return;
2218 
2219  if ( DistanceSquared( start, ‪trace[ "position" ] ) < 12 * 12 || self IsTouching( player ) )
2220  {
2221  player DoDamage( player.health + 1, player.origin, self.owner, self, "none", "MOD_HIT_BY_OBJECT", 0, GetWeapon( "supplydrop" ) );
2222  player playsound ( "mpl_supply_crush" );
2223  player playsound ( "phy_impact_supply" );
2224  }
2225  }
2226 }
2227 
2228 function ‪is_touching_crate() // self == crate
2229 {
2230  if ( !isdefined( self ) )
2231  return;
2232 
2233  crate = self;
2234  extraBoundary = ( 10, 10, 10 );
2235  players = GetPlayers();
2236 
2237  //crate_bottom_point = self GetPointInBounds( 0.0, 0.0, -1.0 );
2238  crate_bottom_point = self.origin;
2239 
2240  // /# sphere( crate_bottom_point, 10, ( 1.0, 0, 0 ), 1.0, true, 20, 120 ); #/
2241 
2242  foreach( player in level.players )
2243  {
2244  if( isdefined( player ) && IsAlive( player ) )
2245  {
2246  stance = player GetStance();
2247  stance_z_offset = ( ( stance == "stand" ) ? 40 : ( ( stance == "crouch" ) ? 18 : 6 ) );
2248  player_test_point = player.origin + ( 0, 0, stance_z_offset );
2249 
2250  // /# sphere( player_test_point, 10, ( 0, 0, 1.0 ), 1.0, true, 20, 120 ); #/
2251 
2252  if ( ( player_test_point[2] < crate_bottom_point[2] ) && self IsTouching( player, extraBoundary ) )
2253  {
2254  attacker = ( isdefined( self.owner ) ? self.owner : self );
2255 
2256  player DoDamage( player.health + 1, player.origin, attacker, self, "none", "MOD_HIT_BY_OBJECT", 0, GetWeapon( "supplydrop" ) );
2257  player playsound ("mpl_supply_crush");
2258  player playsound ("phy_impact_supply");
2259  }
2260  }
2261 
2262  self ‪is_equipment_touching_crate( player );
2263  }
2264 
2265  vehicles = GetEntArray( "script_vehicle", "classname" );
2266  foreach( vehicle in vehicles )
2267  {
2268  if( IsVehicle( vehicle ) )
2269  {
2270  if( isdefined( vehicle.archetype ) && ( vehicle.archetype == "wasp" ) )
2271  {
2272  if( crate IsTouching( vehicle, ( 2, 2, 2 ) ) )
2273  {
2274  vehicle notify( "sentinel_shutdown" );
2275  }
2276  }
2277  }
2278  }
2279 }
2280 
2281 function ‪is_clone_touching_crate() // self == crate
2282 {
2283  if ( !isdefined( self ) )
2284  return;
2285 
2286  extraBoundary = ( 10, 10, 10 );
2287  actors = GetActorArray();
2288  for( i = 0; i < actors.size; i++ )
2289  {
2290  if( isdefined( actors[i] ) && isdefined( actors[i].isAiClone ) && IsAlive( actors[i] ) && ( actors[i].origin[2] < self.origin[2] ) && self IsTouching( actors[i], extraBoundary ) )
2291  {
2292  attacker = ( isdefined( self.owner ) ? self.owner : self );
2293 
2294  actors[i] DoDamage( actors[i].health + 1, actors[i].origin, attacker, self, "none", "MOD_HIT_BY_OBJECT", 0, GetWeapon( "supplydrop" ) );
2295  actors[i] playsound ("mpl_supply_crush");
2296  actors[i] playsound ("phy_impact_supply");
2297  }
2298  }
2299 }
2300 
2301 function ‪is_equipment_touching_crate( player ) // self == crate, player is passed to access their equipment
2302 {
2303  extraBoundary = ( 10, 10, 10 );
2304  if( isdefined( player ) && isdefined( player.weaponObjectWatcherArray ) )
2305  {
2306  for( watcher = 0; watcher < player.weaponObjectWatcherArray.size; watcher++ )
2307  {
2308  objectWatcher = player.weaponObjectWatcherArray[watcher];
2309  objectArray = objectWatcher.objectArray;
2310 
2311  if( isdefined( objectArray ) )
2312  {
2313  for( weaponObject = 0; weaponObject < objectArray.size; weaponObject++ )
2314  {
2315  if( isdefined(objectArray[weaponObject]) && self IsTouching( objectArray[weaponObject], extraBoundary ) )
2316  {
2317  if( isdefined(objectWatcher.onDetonateCallback) )
2318  {
2319  objectWatcher thread ‪weaponobjects::waitAndDetonate( objectArray[weaponObject], 0 );
2320  }
2321  else
2322  {
2323  ‪weaponobjects::removeWeaponObject( objectWatcher, objectArray[weaponObject] );
2324 
2325  // TODO-T8: this doesn't actually delete the weapon object; make a call to weaponobjects::deleteWeaponObjectInstance here after it is implemented
2326 
2327  }
2328  }
2329  }
2330  }
2331  }
2332  }
2333 
2334  //Check for tactical insertion
2335  extraBoundary = ( 15, 15, 15 );
2336  if( isdefined( player ) && isdefined( player.tacticalInsertion ) && self IsTouching( player.tacticalInsertion, extraBoundary ) )
2337  {
2338  player.tacticalInsertion thread ‪tacticalinsertion::fizzle();
2339  }
2340 }
2341 
2342 function ‪spawnUseEnt()
2343 {
2344  useEnt = ‪spawn( "script_origin", self.origin );
2345  useEnt.curProgress = 0;
2346  useEnt.inUse = false;
2347  useEnt.useRate = 0;
2348  useEnt.useTime = 0;
2349  useEnt.owner = self;
2350 
2351  useEnt thread ‪useEntOwnerDeathWaiter( self );
2352 
2353  return useEnt;
2354 }
2355 
2356 function ‪useEntOwnerDeathWaiter( owner )
2357 {
2358  self endon ( "death" );
2359  owner waittill ( "death" );
2360 
2361  self delete();
2362 }
2363 
2364 // taken from _gameobject maybe we can just use the _gameobject code
2365 function ‪crateUseThink() // self == crate
2366 {
2367  while( isdefined(self) )
2368  {
2369  self waittill("trigger", player );
2370 
2371  if ( !isdefined( self ) )
2372  break;
2373 
2374  if ( !isAlive( player ) )
2375  continue;
2376 
2377  if ( !player isOnGround() )
2378  continue;
2379 
2380  if ( isdefined( self.owner ) && self.owner == player )
2381  continue;
2382 
2383  useEnt = self ‪spawnUseEnt();
2384  ‪result = false;
2385 
2386  // if the crate has been hacked then we'll need to know later on the useEnt
2387  if( isdefined( self.hacker ) )
2388  {
2389  useEnt.hacker = self.hacker;
2390  }
2391 
2392  self.useEnt = useEnt;
2393 
2394  ‪result = useEnt ‪useHoldThink( player, level.crateNonOwnerUseTime );
2395 
2396  if ( isdefined( useEnt ) )
2397  {
2398  useEnt Delete();
2399  }
2400 
2401  if ( ‪result && isdefined( self ) )
2402  {
2403  ‪scoreevents::giveCrateCaptureMedal( self, player );
2404  self notify("captured", player, false );
2405  }
2406  }
2407 }
2408 
2409 function ‪crateUseThinkOwner() // self == crate
2410 {
2411  self endon("joined_team");
2412 
2413  while( isdefined(self) )
2414  {
2415  self waittill("trigger", player );
2416 
2417  if ( !isdefined( self ) )
2418  break;
2419 
2420  if ( !isAlive( player ) )
2421  continue;
2422 
2423  //if ( !player isOnGround() )
2424  //continue;
2425 
2426  if ( !isdefined( self.owner ) )
2427  continue;
2428 
2429  if ( self.owner != player )
2430  continue;
2431 
2432  ‪result = self ‪useHoldThink( player, level.crateOwnerUseTime );
2433 
2434  if ( ‪result && isdefined( self ) && isdefined( player ) )
2435  {
2436  self notify("captured", player, false );
2437  }
2438  }
2439 }
2440 
2441 function ‪useHoldThink( player, useTime ) // self == a script origin (useEnt) or the crate
2442 {
2443  player notify ( "use_hold" );
2444  player ‪util::freeze_player_controls( true );
2445 
2446  player ‪util::_disableWeapon();
2447 
2448  self.curProgress = 0;
2449  self.inUse = true;
2450  self.useRate = 0;
2451  self.useTime = useTime;
2452 
2453  player thread ‪personalUseBar( self );
2454 
2455  ‪result = ‪useHoldThinkLoop( player );
2456 
2457  if ( isdefined( player ) )
2458  {
2459  player notify( "done_using" );
2460  }
2461 
2462  if ( isdefined( player ) )
2463  {
2464 
2465  if ( IsAlive(player) )
2466  {
2467  player ‪util::_enableWeapon();
2468 
2469  player ‪util::freeze_player_controls( false );
2470  }
2471  }
2472 
2473  if ( isdefined( self ) )
2474  {
2475  self.inUse = false;
2476  }
2477 
2478  // result may be undefined if useholdthinkloop hits an endon
2479  if ( isdefined( ‪result ) && ‪result )
2480  return true;
2481 
2482  return false;
2483 }
2484 
2485 function ‪continueHoldThinkLoop( player )
2486 {
2487  if ( !isdefined(self ) )
2488  return false;
2489 
2490  if ( self.curProgress >= self.useTime )
2491  return false;
2492 
2493  if ( !IsAlive( player ) )
2494  return false;
2495 
2496  if ( player.throwingGrenade )
2497  return false;
2498 
2499  if ( !(player useButtonPressed()) )
2500  return false;
2501 
2502  if ( player meleeButtonPressed() )
2503  return false;
2504 
2505  if ( player IsInVehicle() )
2506  return false;
2507 
2508  if ( player IsWeaponViewOnlyLinked() )
2509  return false;
2510 
2511  if ( player IsRemoteControlling() )
2512  return false;
2513 
2514  return true;
2515 }
2516 
2517 function ‪useHoldThinkLoop( player )
2518 {
2519  level endon ( "game_ended" );
2520  self endon("disabled");
2521  self.owner endon( "crate_use_interrupt" );
2522 
2523  timedOut = 0;
2524 
2525  while( self ‪continueHoldThinkLoop( player ) )
2526  {
2527  timedOut += 0.05;
2528 
2529  self.curProgress += (50 * self.useRate);
2530  self.useRate = 1;
2531 
2532  if ( self.curProgress >= self.useTime )
2533  {
2534  self.inUse = false;
2535 
2536  wait .05;
2537 
2538  return isAlive( player );
2539  }
2540 
2543  }
2544 
2545  return false;
2546 }
2547 
2549 {
2550  self endon( "death" );
2551 
2552  for ( ;; )
2553  {
2554 
2555  self waittill( "trigger_use_doubletap", player );
2556 
2557 
2558  if ( !player HasPerk( "specialty_showenemyequipment" ))
2559  {
2560  continue;
2561  }
2562  if( isdefined( self.useEnt ) && self.useEnt.inUse )
2563  {
2564  // TODO: get a fail sound for this
2565  if( IsDefined( self.owner ) && self.owner != player )
2566  continue;
2567  }
2568 
2569  player playlocalsound ("uin_gamble_perk");
2570 
2571  self.crateType = ‪getRandomCrateType( "gambler", self.crateType.name );
2572  self ‪crateReactivate();
2573  self setHintStringForPerk( "specialty_showenemyequipment", self.crateType.hint );
2574 
2575  self notify( "crate_use_interrupt" );
2576  level notify( "use_interrupt", self );
2577 
2578  return;
2579  }
2580 }
2581 
2583 {
2584  self setHintString( self.crateType.hint );
2585 
2586  icon = self ‪getIconForCrate();
2587 
2588  self thread ‪entityheadIcons::setEntityHeadIcon( self.team, self, level.crate_headicon_offset, icon, true );
2589 }
2590 
2591 function ‪personalUseBar( object ) // self == player, object == a script origin (useEnt) or the crate
2592 {
2593  self endon("disconnect");
2594 
2595  captureCrateState = ‪SUPPLY_DROP_CRATE_STATE_NONE;
2596 
2597  if( self HasPerk( "specialty_showenemyequipment" ) &&
2598  object.owner != self &&
2599  !isdefined( object.hacker ) &&
2600  ( ( level.teambased && object.owner.team != self.team ) || !level.teambased ) )
2601  {
2602  captureCrateState = ‪SUPPLY_DROP_CRATE_STATE_HACK;
2603  self PlayLocalSound ( "evt_hacker_hacking" );
2604  }
2605  else if( self HasPerk( "specialty_showenemyequipment" ) &&
2606  isdefined( object.hacker ) &&
2607  (object.owner == self ||
2608  ( level.teambased && object.owner.team == self.team ) ) )
2609  {
2610  captureCrateState = ‪SUPPLY_DROP_CRATE_STATE_DISARM;
2611  self PlayLocalSound ( "evt_hacker_hacking" );
2612  }
2613  else
2614  {
2615  captureCrateState = ‪SUPPLY_DROP_CRATE_STATE_CAPTURE;
2616  self.is_capturing_own_supply_drop = ( object.owner === self ) && ( !isdefined( object.originalOwner ) || object.originalOwner == self );
2617  }
2618 
2619  lastRate = -1;
2620  while ( isAlive( self ) && isdefined(object) && object.inUse && !level.gameEnded )
2621  {
2622  if ( lastRate != object.useRate )
2623  {
2624  if( object.curProgress > object.useTime)
2625  object.curProgress = object.useTime;
2626 
2627  if ( !object.useRate )
2628  {
2629  self ‪clientfield::set_player_uimodel( "hudItems.captureCrateTotalTime", 0 );
2630  self ‪clientfield::set_player_uimodel( "hudItems.captureCrateState", ‪SUPPLY_DROP_CRATE_STATE_NONE );
2631  }
2632  else
2633  {
2634  barFrac = object.curProgress / object.useTime;
2635  rateOfChange = object.useRate / object.useTime;
2636  captureCrateTotalTime = 0;
2637  if ( rateOfChange > 0 )
2638  {
2639  captureCrateTotalTime = ( ( 1 - barFrac ) / rateOfChange );
2640  }
2641 
2642  self ‪clientfield::set_player_uimodel( "hudItems.captureCrateTotalTime", Int( captureCrateTotalTime ) );
2643  self ‪clientfield::set_player_uimodel( "hudItems.captureCrateState", captureCrateState );
2644  }
2645  }
2646  lastRate = object.useRate;
2648  }
2649 
2650  self.is_capturing_own_supply_drop = false;
2651  self ‪clientfield::set_player_uimodel( "hudItems.captureCrateTotalTime", 0 );
2652  self ‪clientfield::set_player_uimodel( "hudItems.captureCrateState", ‪SUPPLY_DROP_CRATE_STATE_NONE );
2653 }
2654 
2655 function ‪spawn_helicopter( owner, team, origin, angles, model, targetname, killstreak_id, context )
2656 {
2657  chopper = spawnHelicopter( owner, origin, angles, model, targetname );
2658  if ( !isdefined( chopper ) )
2659  {
2660  if ( isplayer( owner ) )
2661  {
2663  self notify( "cleanup_marker" );
2664  }
2665  return undefined;
2666  }
2667 
2668  chopper ‪killstreaks::configure_team( ‪SUPPLY_DROP_NAME, killstreak_id, owner );
2669 // chopper killstreak_hacking::enable_hacking( SUPPLY_DROP_NAME );
2670 // if ( isdefined ( context.killstreakRef ) )
2671 // {
2672 // chopper killstreak_hacking::override_hacked_killstreak_reference( context.killstreakRef );
2673 // }
2674 
2675  chopper.maxhealth = level.heli_maxhealth; // max health
2676  //chopper.health = 999999; // we check against maxhealth in the damage monitor to see if this gets destroyed, so we don't want this to die prematurely
2677  chopper.rocketDamageOneShot = chopper.maxhealth + 1; // Make it so the heatseeker blows it up in one hit for now
2678  chopper.damageTaken = 0;
2679 
2680  hardpointTypeForDamage = ‪SUPPLY_DROP_NAME;
2681  if ( context.killstreakref === "inventory_ai_tank_drop" || context.killstreakref === "ai_tank_drop" )
2682  {
2683  hardpointTypeForDamage = ‪SUPPLY_DROP_AI_TANK_NAME;
2684  }
2685  else if ( context.killstreakref === "inventory_combat_robot" || context.killstreakref === "combat_robot" )
2686  {
2687  hardpointTypeForDamage = ‪SUPPLY_DROP_COMBAT_ROBOT_NAME;
2688  }
2689 
2690  chopper thread ‪helicopter::heli_damage_monitor( hardpointTypeForDamage );
2692  chopper.spawnTime = GetTime();
2693  chopper ‪clientfield::set( "enemyvehicle", ‪ENEMY_VEHICLE_ACTIVE );
2694 
2695  supplydropSpeed = GetDvarInt( "scr_supplydropSpeedStarting", 250 ); // 250);
2696  supplydropAccel = GetDvarInt( "scr_supplydropAccelStarting", 100 ); //175);
2697  chopper SetSpeed( supplydropSpeed, supplydropAccel );
2698 
2699  maxPitch = GetDvarInt( "scr_supplydropMaxPitch", 25);
2700  maxRoll = GetDvarInt( "scr_supplydropMaxRoll", 45 ); // 85);
2701  chopper SetMaxPitchRoll( 0, maxRoll );
2702 
2703  chopper SetDrawInfrared( true );
2704 
2705  Target_Set(chopper, ( 0, 0, -25 ));
2706 
2707  if ( isplayer( owner ) )
2708  {
2709  chopper thread ‪refCountDecChopper(team, killstreak_id);
2710  }
2711  chopper thread ‪heliDestroyed();
2712 
2713  return chopper;
2714 }
2715 
2716 function ‪getDropHeight(origin)
2717 {
2719 }
2720 
2722 {
2723  return (0, RandomInt(360), 0);
2724 }
2725 
2726 function ‪getNextDropDirection( drop_direction, degrees )
2727 {
2728  drop_direction = (0, drop_direction[1] + degrees, 0 );
2729 
2730  if( drop_direction[1] >= 360 )
2731  drop_direction = (0, drop_direction[1] - 360, 0 );
2732 
2733  return drop_direction;
2734 }
2735 
2736 function ‪getHeliStart( drop_origin, drop_direction )
2737 {
2738  dist = -1 * GetDvarInt( "scr_supplydropIncomingDistance", 15000 ); // 15000);
2739  pathRandomness = 100;
2740  direction = drop_direction + (0, RandomIntRange( -2, 3 ), 0);
2741 
2742  start_origin = drop_origin + ( AnglesToForward( direction ) * dist );
2743  start_origin += ( (randomfloat(2) - 1)*pathRandomness, (randomfloat(2) - 1)*pathRandomness, 0 );
2744 /#
2745  if ( GetDvarInt( "scr_noflyzones_debug", 0 ) )
2746  {
2747  if ( level.noFlyZones.size )
2748  {
2749  index = RandomIntRange( 0, level.noFlyZones.size );
2750  delta = drop_origin - level.noFlyZones[index].origin;
2751  delta = ( delta[0] + RandomInt(10), delta[1] + RandomInt(10), 0 );
2752  delta = VectorNormalize( delta );
2753  start_origin = drop_origin + ( delta * dist );
2754  }
2755  }
2756 #/
2757  return start_origin;
2758 }
2759 
2760 function ‪getHeliEnd( drop_origin, drop_direction )
2761 {
2762  pathRandomness = 150;
2763  dist = -1 * GetDvarInt( "scr_supplydropOutgoingDistance", 15000);
2764 
2765  // have the heli do a sharp turn when leaving
2766  if ( RandomIntRange(0,2) == 0 )
2767  turn = RandomIntRange( 60,121);
2768  else
2769  turn = -1 * RandomIntRange( 60,121);
2770 
2771  direction = drop_direction + (0, turn, 0);
2772 
2773  end_origin = drop_origin + ( AnglesToForward( direction ) * dist );
2774  end_origin += ( (randomfloat(2) - 1)*pathRandomness , (randomfloat(2) - 1)*pathRandomness , 0 );
2775 
2776  return end_origin;
2777 }
2778 
2779 function ‪addOffsetOntoPoint( point, direction, offset )
2780 {
2781  angles = VectorToAngles( (direction[0], direction[1], 0) );
2782 
2783  offset_world = RotatePoint( offset, angles );
2784 
2785  return (point + offset_world);
2786 }
2787 
2788 function ‪supplyDropHeliStartPath_v2_setup( goal, goal_offset )
2789 {
2790  goalPath = SpawnStruct();
2791 
2792  goalPath.start = ‪helicopter::getValidRandomStartNode( goal ).origin;
2793 
2794  return goalPath;
2795 }
2796 
2797 function ‪supplyDropHeliStartPath_v2_part2_local( goal, goalPath, goal_local_offset )
2798 {
2799  direction = ( goal - goalPath.start );
2800 
2801  goalPath.path = [];
2802  goalPath.path[0] = ‪addOffsetOntoPoint( goal, direction, goal_local_offset );
2803 }
2804 
2805 function ‪supplyDropHeliStartPath_v2_part2( goal, goalPath, goal_world_offset )
2806 {
2807  goalPath.path = [];
2808  goalPath.path[0] = goal + goal_world_offset;
2809 }
2810 
2811 function ‪supplyDropHeliStartPath(goal, goal_offset)
2812 {
2813  total_tries = 12;
2814  tries = 0;
2815 
2816  goalPath = SpawnStruct();
2817  drop_direction = ‪getDropDirection();
2818 
2819 
2820  while ( tries < total_tries )
2821  {
2822  goalPath.start = ‪getHeliStart( goal, drop_direction );
2823 
2824  goalPath.path = ‪airsupport::getHeliPath( goalPath.start, goal );
2825 
2826  startNoFlyZones = ‪airsupport::insideNoFlyZones( goalPath.start, false );
2827 
2828  if ( IsDefined( goalPath.path ) && startNoFlyZones.size == 0 )
2829  {
2830  if ( goalPath.path.size > 1 )
2831  {
2832  direction = ( goalPath.path[goalPath.path.size - 1] - goalPath.path[goalPath.path.size - 2] );
2833  }
2834  else
2835  {
2836  direction = ( goalPath.path[goalPath.path.size - 1] - goalPath.start );
2837  }
2838  goalPath.path[goalPath.path.size - 1] = ‪addOffsetOntoPoint(goalPath.path[goalPath.path.size - 1], direction, goal_offset);
2839 /#
2840  sphere( goalPath.path[goalPath.path.size - 1], 10, (0,0,1), 1, true, 10, 1000 );
2841 #/
2842  return goalPath;
2843  }
2844 
2845  //Couldn't find a path that didn't cross a no fly zone picking random directions, so try the last tried direction plus 30 degrees
2846  drop_direction = ‪getNextDropDirection( drop_direction, 30 );
2847 
2848  tries++;
2849  }
2850 
2851  //Couldn't find a valid direction, so just bring it in even if it will fly through something
2852  drop_direction = ‪getDropDirection();
2853  goalPath.start = ‪getHeliStart( goal, drop_direction );
2854 
2855  direction = ( goal - goalPath.start );
2856  goalPath.path = [];
2857  goalPath.path[0] = ‪addOffsetOntoPoint( goal, direction, goal_offset );
2858 
2859  return goalPath;
2860 }
2861 
2863 {
2864  goalPath = SpawnStruct();
2865 
2866  goalPath.start = start;
2867 
2868  goal = ‪helicopter::getValidRandomLeaveNode( start ).origin;
2869 
2870  goalPath.path = [];
2871  goalPath.path[0] = goal;
2872 
2873  return goalPath;
2874 }
2875 
2876 function ‪supplyDropHeliEndPath(origin, drop_direction)
2877 {
2878  total_tries = 5;
2879  tries = 0;
2880 
2881  goalPath = SpawnStruct();
2882 
2883  while ( tries < total_tries )
2884  {
2885  goal = ‪getHeliEnd( origin, drop_direction );
2886 
2887  goalPath.path = ‪airsupport::getHeliPath( origin, goal );
2888 
2889  if ( isdefined( goalPath.path ) )
2890  {
2891  return goalPath;
2892  }
2893 
2894  tries++;
2895  }
2896 
2897  // could not locate a clear path try the leave nodes
2898  leave_nodes = getentarray( "heli_leave", "targetname" );
2899  foreach ( node in leave_nodes )
2900  {
2901  goalPath.path = ‪airsupport::getHeliPath( origin, node.origin );
2902 
2903  if ( isdefined( goalPath.path ) )
2904  {
2905  return goalPath;
2906  }
2907  }
2908 
2909  // points where the helicopter leaves to
2910  goalPath.path = [];
2911  goalPath.path[0] = ‪getHeliEnd( origin, drop_direction );
2912 
2913  return goalPath;
2914 }
2915 
2916 function ‪incCrateKillstreakUsageStat(weapon, killstreak_id)
2917 {
2918  if ( weapon == level.weaponNone )
2919  return;
2920 
2921  switch ( weapon.name )
2922  {
2923  case "turret_drop":
2924  self ‪killstreaks::play_killstreak_start_dialog( "turret_drop", self.pers["team"], killstreak_id );
2925  break;
2926  case "tow_turret_drop":
2927  self ‪killstreaks::play_killstreak_start_dialog( "tow_turret_drop", self.pers["team"], killstreak_id );
2928  break;
2929  case "supplydrop_marker":
2930  case "inventory_supplydrop_marker":
2931  self ‪killstreaks::play_killstreak_start_dialog( ‪SUPPLY_DROP_NAME, self.pers["team"], killstreak_id );
2934  self AddWeaponStat( GetWeapon( "supplydrop" ), "used", 1 );
2935  break;
2936  case "ai_tank_drop":
2937  case "inventory_ai_tank_drop":
2938  self ‪killstreaks::play_killstreak_start_dialog( "ai_tank_drop", self.pers["team"], killstreak_id );
2939  level thread ‪popups::DisplayKillstreakTeamMessageToAll( "ai_tank_drop", self );
2940  self AddWeaponStat( GetWeapon( "ai_tank_drop" ), "used", 1 );
2941  break;
2942  case "inventory_minigun_drop":
2943  case "minigun_drop":
2944  self ‪killstreaks::play_killstreak_start_dialog( "minigun", self.pers["team"], killstreak_id );
2945  break;
2946  case "m32_drop":
2947  case "inventory_m32_drop":
2948  self ‪killstreaks::play_killstreak_start_dialog( "m32", self.pers["team"], killstreak_id );
2949  break;
2950  case "combat_robot_drop":
2951  level thread ‪popups::DisplayKillstreakTeamMessageToAll( "combat_robot", self );
2952  break;
2953 
2954  }
2955 }
2956 
2957 function ‪MarkerCleanupThread( context )
2958 {
2959  player = self;
2960  player ‪util::waittill_any( "death", "disconnect", "joined_team", "joined_spectators", "cleanup_marker" );
2961  ‪cleanup( context, player );
2962 }
2963 
2964 // gets the world drop point from which a payload is dropped from (also the payload's origin while attached to the chopper)
2965 function ‪GetChopperDropPoint( context ) // self = chopper
2966 {
2967  chopper = self;
2968  return ( isdefined( context.dropTag ) ? chopper GetTagOrigin( context.dropTag ) + RotatePoint( ‪VAL( context.dropTagOffset, (0,0,0) ), chopper.angles ) : chopper.origin );
2969 }
2970 
2971 function ‪heliDeliverCrate( origin, weapon, owner, team, killstreak_id, package_contents_id, context )
2972 {
2973  if ( owner ‪EMP::EnemyEMPActive() && !owner hasperk("specialty_immuneemp") )
2974  {
2976  self notify( "cleanup_marker" );
2977  return;
2978  }
2979 
2980 /#
2981  if ( GetDvarInt( "scr_supply_drop_valid_location_debug", 0 ) )
2982  {
2983  level notify( "stop_heli_drop_valid_location_marked_cylinder" );
2984  level notify( "stop_heli_drop_valid_location_arrived_at_goal_cylinder" );
2985  level notify( "stop_heli_drop_valid_location_dropped_cylinder" );
2986  ‪util::drawcylinder( origin, context.radius, 8000, 99999999, "stop_heli_drop_valid_location_marked_cylinder", ( 0.4, 0, 0.4 ), 0.8 );
2987  }
2988 #/
2989 
2990  if ( !isdefined( context.marker ) )
2991  return;
2992 
2993  context.markerFXHandle = SpawnFx( level.killstreakCoreBundle.fxMarkedLocation, context.marker.origin + ( 0, 0, 5 ), ( 0, 0, 1 ), ( 1, 0, 0 ) );
2994  context.markerFXHandle.team = owner.team;
2995  TriggerFX( context.markerFXHandle );
2996  ‪AddDropLocation( killstreak_id, context.marker.origin );
2997  killstreakBundle = ( isdefined( context.killstreakType ) ? level.killstreakbundle[ context.killstreakType ] : undefined );
2998  ricochetDistance = ( isdefined( killstreakBundle ) ? killstreakBundle.ksRicochetDistance : undefined );
2999  ‪killstreaks::add_ricochet_protection( killstreak_id, owner, context.marker.origin, ricochetDistance );
3000 
3001  context.marker.team = owner.team;
3003 
3004  // the offset for the icon can be controlled from the objective in APE
3005  context.marker ‪entityheadicons::setEntityHeadIcon( owner.pers["team"], owner, undefined, context.objective );
3006 
3007  if( isdefined( weapon ) )
3008  ‪incCrateKillstreakUsageStat( weapon, killstreak_id );
3009 
3010  rear_hatch_offset_local = GetDvarInt( "scr_supplydropOffset", 0);
3011 
3012  drop_origin = origin;
3013  drop_height = ‪getDropHeight(drop_origin);
3014  drop_height += level.zOffsetCounter * 350;
3015  level.zOffsetCounter++;
3016  if( level.zOffsetCounter >= 5 )
3017  level.zOffsetCounter = 0;
3018 
3019  heli_drop_goal = ( drop_origin[0], drop_origin[1], drop_height ); // + rear_hatch_offset_world;
3020 
3021 /#
3022  sphere( heli_drop_goal, 10, (0,1,0), 1, true, 10, 1000 );
3023 #/
3024 
3025  goalPath = undefined;
3026 
3027  if ( IsDefined( context.dropOffset ) )
3028  {
3029  goalPath = ‪supplyDropHeliStartPath_v2_setup(heli_drop_goal, context.dropOffset );
3030  ‪supplyDropHeliStartPath_v2_part2_local(heli_drop_goal, goalPath, context.dropOffset );
3031  }
3032  else
3033  {
3034  goalPath = ‪supplyDropHeliStartPath_v2_setup(heli_drop_goal, (rear_hatch_offset_local, 0, 0 ));
3035  goal_path_setup_needs_finishing = true;
3036  }
3037 
3038  drop_direction = VectorToAngles( (heli_drop_goal[0], heli_drop_goal[1], 0) - (goalPath.start[0], goalPath.start[1], 0));
3039 
3040  if( isdefined( context.vehiclename ) )
3041  helicopterVehicleInfo = context.vehiclename;
3042  else
3043  helicopterVehicleInfo = level.vtolDropHelicopterVehicleInfo;
3044 
3045  chopper = ‪spawn_helicopter( owner,
3046  team,
3047  goalPath.start,
3048  drop_direction,
3049  helicopterVehicleInfo,
3050  "",
3051  killstreak_id, context );
3052 
3053  if ( goal_path_setup_needs_finishing === true )
3054  {
3055  goal_world_offset = chopper.origin - chopper ‪GetChopperDropPoint( context );
3056  ‪supplyDropHeliStartPath_v2_part2( heli_drop_goal, goalPath, goal_world_offset );
3057  goal_path_setup_needs_finishing = false;
3058  }
3059 
3060  // disable drop location wait until we have a more proper design-approved solution
3061  waitForOnlyOneDropLocation = false;
3062 
3063  while( level.dropLocations.size > 1 && waitForOnlyOneDropLocation) // wait for the older ongoing drops to finish
3064  {
3065  // remove old drop locations
3066  ArrayRemoveValue( level.dropLocations, undefined );
3067 
3068  wait_for_drop = false;
3069  foreach( id, dropLocation in level.dropLocations )
3070  { // check if older drop is still ongoing
3071  if( id < killstreak_id )
3072  {
3073  wait_for_drop = true;
3074  break;
3075  }
3076  }
3077  if( wait_for_drop )
3078  wait 0.5;
3079  else
3080  break;
3081  }
3082 
3083  chopper.killstreakWeaponName = weapon.name;
3084 
3085  if( isdefined( context ) && isdefined( context.hasFlares ) )
3086  {
3087  chopper.numFlares = 3;
3088  chopper.flareOffset = ( 0, 0 ,0 );
3089  chopper thread ‪helicopter::create_flare_ent( (0, 0, -50 ) );
3090  }
3091  else
3092  {
3093  chopper.numFlares = 0;
3094  }
3095 
3096  killCamEnt = ‪spawn( "script_model", chopper.origin + (0,0,800) );
3097  killCamEnt.angles = (100, chopper.angles[1], chopper.angles[2]);
3098  killCamEnt.startTime = gettime();
3099  killCamEnt linkTo( chopper );
3100 
3101  //Wait until the chopper is within the map bounds or within a certain distance of it's target before the SAM turret can target it
3102  if ( isplayer( owner ) )
3103  {
3104  Target_SetTurretAquire( self, false );
3105  chopper thread ‪SAMTurretWatcher( drop_origin );
3106  }
3107 
3108  if ( !isdefined( chopper ) )
3109  return;
3110 
3111  if( isdefined( context ) && isdefined( context.prolog ) ) // we need callbacks for this
3112  {
3113  chopper [[context.prolog]]( context );
3114  }
3115  else
3116  {
3117  chopper thread ‪heliDropCrate( level.killstreakWeapons[weapon], owner, rear_hatch_offset_local, killCamEnt, killstreak_id, package_contents_id, context );
3118  //chopper thread heliDropCrate( weapon.name, owner, rear_hatch_offset_local, killCamEnt, killstreak_id, package_contents_id, context );
3119  }
3120 
3121  chopper endon("death");
3122 
3123  chopper thread ‪airsupport::followPath( goalPath.path, "drop_goal", true);
3124 
3125  chopper thread ‪speedRegulator(heli_drop_goal);
3126 
3127  chopper waittill( "drop_goal" );
3128 
3129  if( isdefined( context ) && isdefined( context.epilog ) )
3130  {
3131  chopper [[context.epilog]]( context );
3132  }
3133 
3134 /#
3135  PrintLn("Chopper Incoming Time: " + ( GetTime() - chopper.spawnTime ) );
3136 #/
3137 
3138  // wait 0.1;
3139 
3140 /#
3141  if ( GetDvarInt( "scr_supply_drop_valid_location_debug", 0 ) )
3142  {
3143  if ( isdefined( context.dropOffset ) )
3144  {
3145  chopper_drop_point = chopper.origin - RotatePoint( context.dropOffset, chopper.angles );
3146  }
3147  else
3148  {
3149  chopper_drop_point = chopper ‪GetChopperDropPoint( context );
3150  }
3151 
3152  ‪trace = GroundTrace( chopper_drop_point + ( 0, 0, -100 ), chopper_drop_point + ( 0, 0, -10000 ), false, undefined, false );
3153  debug_drop_location = ‪trace["position"];
3154 
3155  ‪util::drawcylinder( debug_drop_location, context.radius, 8000, 99999999, "stop_heli_drop_valid_location_arrived_at_goal_cylinder", ( 1.0, 0.6, 0.0 ), 0.9 );
3156 
3157  IPrintLn( "Goal notified at 2D distance: " + Distance2D( chopper_drop_point, heli_drop_goal ) );
3158  }
3159 #/
3160 
3161  on_target = false;
3162  last_distance_from_goal_squared = ‪SQR( 9999999.0 );
3163  continue_waiting = true;
3164  remaining_tries = 30; // fail-safe, about one and a half seconds
3165  while ( continue_waiting && remaining_tries > 0 )
3166  {
3167  if ( isdefined( context.dropOffset ) )
3168  {
3169  chopper_drop_point = chopper.origin - RotatePoint( context.dropOffset, chopper.angles );
3170  }
3171  else
3172  {
3173  chopper_drop_point = chopper ‪GetChopperDropPoint( context );
3174  }
3175 
3176  current_distance_from_goal_squared = Distance2DSquared( chopper_drop_point, heli_drop_goal );
3177  continue_waiting = ( ( current_distance_from_goal_squared < last_distance_from_goal_squared ) && ( current_distance_from_goal_squared > ‪SQR( ‪SUPPY_DROP_ON_TARGET_DISTANCE ) ) );
3178  last_distance_from_goal_squared = current_distance_from_goal_squared;
3179 
3180  /#
3181  if ( GetDvarInt( "scr_supply_drop_valid_location_debug", 0 ) )
3182  {
3183  sphere( chopper_drop_point, 8, ( 1, 0, 0 ), 0.9, false, 20, 1 );
3184  }
3185  #/
3186 
3187  if ( continue_waiting )
3188  {
3189  /#
3190  if ( GetDvarInt( "scr_supply_drop_valid_location_debug", 0 ) )
3191  {
3192  IPrintLn( "--- 2D distance: " + Distance2D( chopper_drop_point, heli_drop_goal ) );
3193  }
3194  #/
3195 
3197  }
3198 
3199  remaining_tries--;
3200  }
3201 
3202 /#
3203  if ( GetDvarInt( "scr_supply_drop_valid_location_debug", 0 ) )
3204  {
3205  IPrintLn( "Crate Dropped at 2D distance: " + Distance2D( chopper_drop_point, heli_drop_goal ) );
3206  }
3207 #/
3208 
3209  chopper notify("drop_crate", chopper.origin, chopper.angles, chopper.owner);
3210  chopper.dropTime = GetTime();
3211  chopper playsound ("veh_supply_drop");
3212 
3213  wait ( 0.7 );
3214 
3215  if ( isdefined( level.killstreakWeapons[weapon] ) )
3216  {
3217  chopper ‪killstreaks::play_pilot_dialog_on_owner( "waveStartFinal", level.killstreakWeapons[weapon], chopper.killstreak_id );
3218  }
3219 
3220  supplydropSpeed = GetDvarInt( "scr_supplydropSpeedLeaving", 250 );
3221  supplydropAccel = GetDvarInt( "scr_supplydropAccelLeaving", 60 );
3222  chopper setspeed( supplydropSpeed, supplydropAccel );
3223 
3224  goalPath = ‪supplyDropHeliEndPath_v2( chopper.origin );
3225 
3226  chopper ‪airsupport::followPath( goalPath.path, undefined, false );
3227 /#
3228  PrintLn("Chopper Outgoing Time: " + ( GetTime() - chopper.dropTime ) );
3229 #/
3230  chopper notify( "leaving" );
3231  chopper Delete();
3232 
3233 }
3234 
3235 function ‪SAMTurretWatcher( destination )
3236 {
3237  self endon( "leaving" );
3238  self endon( "helicopter_gone" );
3239  self endon( "death" );
3240 
3241  SAM_TURRET_AQUIRE_DIST = 1500;
3242 
3243  while(1)
3244  {
3245  if( Distance( destination, self.origin ) < SAM_TURRET_AQUIRE_DIST )
3246  break;
3247 
3248  if( self.origin[0] > level.spawnMins[0] && self.origin[0] < level.spawnMaxs[0] &&
3249  self.origin[1] > level.spawnMins[1] && self.origin[1] < level.spawnMaxs[1] )
3250  break;
3251 
3252  wait( 0.1 );
3253  }
3254 
3255  Target_SetTurretAquire( self, true );
3256 }
3257 
3258 function ‪speedRegulator( goal )
3259 {
3260  self endon("drop_goal");
3261  self endon("death");
3262 
3263  wait (3);
3264 
3265  supplydropSpeed = GetDvarInt( "scr_supplydropSpeed", 400);
3266  supplydropAccel = GetDvarInt( "scr_supplydropAccel", 60);
3267  self SetYawSpeed( 100, 60, 60 );
3268  self SetSpeed( supplydropSpeed, supplydropAccel );
3269 
3270  wait (1);
3271  maxPitch = GetDvarInt( "scr_supplydropMaxPitch", 25);
3272  maxRoll = GetDvarInt( "scr_supplydropMaxRoll", 35 ); // 85);
3273  self SetMaxPitchRoll( maxPitch, maxRoll );
3274 }
3275 
3276 function ‪heliDropCrate( killstreak, originalOwner, offset, killCamEnt, killstreak_id, package_contents_id, context )
3277 {
3278  helicopter = self;
3279  originalOwner endon ( "disconnect" );
3280 
3281  crate = ‪crateSpawn( killstreak, killstreak_id, originalOwner, self.team, self.origin, self.angles );
3282 
3283  if ( killstreak == "inventory_supply_drop" || killstreak == "supply_drop" )
3284  {
3285  crate LinkTo( helicopter, ‪VAL( context.dropTag, "tag_origin" ), ‪VAL( context.dropTagOffset, (0,0,0) ) );
3286  helicopter ‪clientfield::set( "supplydrop_care_package_state", 1 );
3287  }
3288  else if ( killstreak == "inventory_ai_tank_drop" || killstreak == "ai_tank_drop" || killstreak == "ai_tank_marker" )
3289  {
3290  crate LinkTo( helicopter, ‪VAL( context.dropTag, "tag_origin" ), ‪VAL( context.dropTagOffset, (0,0,0) ) );
3291  helicopter ‪clientfield::set( "supplydrop_ai_tank_state", 1 );
3292  }
3293 
3294  team = self.team;
3295 
3296  helicopter waittill("drop_crate", origin, angles, chopperOwner );
3297 
3298  if ( isdefined( chopperOwner ) )
3299  {
3300  owner = chopperOwner;
3301 
3302  if ( owner != originalOwner ) // chopper has been hacked
3303  {
3304  crate ‪killstreaks::configure_team( killstreak, owner );
3305  ‪killstreaks::remove_ricochet_protection( killstreak_id, owner );
3306  }
3307  }
3308  else
3309  {
3310  owner = originalOwner;
3311  }
3312 
3313  if ( isdefined( self ) )
3314  {
3315  team = self.team;
3316 
3317  if ( killstreak == "inventory_supply_drop" || killstreak == "supply_drop" )
3318  {
3319  helicopter ‪clientfield::set( "supplydrop_care_package_state", 0 );
3320  }
3321  else if ( killstreak == "inventory_ai_tank_drop" || killstreak == "ai_tank_drop" )
3322  {
3323  helicopter ‪clientfield::set( "supplydrop_ai_tank_state", 0 );
3324  }
3325 
3326  enemy = helicopter.owner ‪battlechatter::get_closest_player_enemy( helicopter.origin, true );
3327  enemyRadius = ‪battlechatter::mpdialog_value( "supplyDropRadius", 0 );
3328 
3329  if ( isdefined( enemy ) && Distance2DSquared( origin, enemy.origin ) < enemyRadius * enemyRadius )
3330  {
3331  enemy ‪battlechatter::play_killstreak_threat( killstreak );
3332  }
3333  }
3334 
3335  if( team == owner.team ) // dont drop if the team changed //
3336  {
3337  //ideally we can not respawn a new crate, but unlink the old crate then zero out the velocity
3338  rear_hatch_offset_height = GetDvarInt( "scr_supplydropOffsetHeight", 200);
3339  rear_hatch_offset_world = RotatePoint( ( offset, 0, 0), angles );
3340  drop_origin = origin - (0,0,rear_hatch_offset_height) - rear_hatch_offset_world;
3341  thread ‪dropCrate(drop_origin, angles, killstreak, owner, team, killCamEnt, killstreak_id, package_contents_id, crate, context );
3342  }
3343 }
3344 
3346 {
3347  self endon( "leaving" );
3348  self endon( "helicopter_gone" );
3349  self endon( "death" );
3350 
3351  while( true )
3352  {
3353  if( self.damageTaken > self.maxhealth )
3354  break;
3355 
3357  }
3358 
3359  if (! isdefined(self) )
3360  return;
3361 
3362 
3363  self SetSpeed( 25, 5 );
3364  self thread ‪lbSpin( RandomIntRange(180, 220) );
3365 
3366  wait( RandomFloatRange( .5, 1.5 ) );
3367 
3368  self notify( "drop_crate", self.origin, self.angles, self.owner );
3369 
3370  ‪lbExplode();
3371 }
3372 
3373 // crash explosion
3374 function ‪lbExplode()
3375 {
3376  forward = ( self.origin + ( 0, 0, 1 ) ) - self.origin;
3377  playfx ( level.chopper_fx["explode"]["death"], self.origin, forward );
3378 
3379  // play heli explosion sound
3380  self playSound( level.heli_sound["crash"] );
3381  self notify ( "explode" );
3382 
3383  if ( isdefined( self.delete_after_destruction_wait_time ) )
3384  {
3385  self Hide();
3386  self ‪WaitAndDelete( self.delete_after_destruction_wait_time );
3387  }
3388  else
3389  {
3390  self delete();
3391  }
3392 }
3393 
3394 
3395 function ‪lbSpin( speed )
3396 {
3397  self endon( "explode" );
3398 
3399  // tail explosion that caused the spinning
3400  playfxontag( level.chopper_fx["explode"]["large"], self, "tail_rotor_jnt" );
3401  playfxontag( level.chopper_fx["fire"]["trail"]["large"], self, "tail_rotor_jnt" );
3402 
3403  self setyawspeed( speed, speed, speed );
3404  while ( isdefined( self ) )
3405  {
3406  self settargetyaw( self.angles[1]+(speed*0.9) );
3407  wait ( 1 );
3408  }
3409 }
3410 
3411 function ‪refCountDecChopper( team, killstreak_id )
3412 {
3413  self waittill("death");
3415  self notify( "cleanup_marker" );
3416 }
3417 
3418 /#
3419 //Adds functionality so we can drop specific supply drops when we want for development purposes
3421 {
3422  //Init my dvar
3423  SetDvar("scr_supply_drop_gui", "");
3424 
3425  while(1)
3426  {
3427  wait(0.5);
3428 
3429  //Grab my dvar every frame
3430  devgui_string = GetDvarString( "scr_supply_drop_gui");
3431 
3432  level.dev_gui_supply_drop = devgui_string;
3433  }
3434 }
3435 #/
‪registerWithHackerTool
‪function registerWithHackerTool(radius, hackTimeMs)
Definition: _hacker_tool.gsc:944
‪waitTillHostMigrationDone
‪function waitTillHostMigrationDone()
Definition: hostmigration_shared.gsc:193
‪add_ricochet_protection
‪function add_ricochet_protection(killstreak_id, owner, origin, ricochet_distance)
Definition: _killstreaks.gsc:3149
‪processScoreEvent
‪function processScoreEvent(event, player, victim, weapon)
Definition: scoreevents_shared.gsc:19
‪insideNoFlyZones
‪function insideNoFlyZones(point, disregardHeight)
Definition: _airsupport.gsc:375
‪continueHoldThinkLoop
‪function continueHoldThinkLoop(player)
Definition: _supplydrop.gsc:2485
‪crateControlledDrop
‪function crateControlledDrop(killstreak, v_target_location)
Definition: _supplydrop.gsc:1687
‪speedRegulator
‪function speedRegulator(goal)
Definition: _supplydrop.gsc:3258
‪drop_all_to_ground
‪function drop_all_to_ground(origin, radius)
Definition: _weapons.gsc:663
‪getValidRandomLeaveNode
‪function getValidRandomLeaveNode(start)
Definition: _helicopter.gsc:426
‪GetChopperDropPoint
‪function GetChopperDropPoint(context)
Definition: _supplydrop.gsc:2965
‪dropAllToGroundAfterCrateDelete
‪function dropAllToGroundAfterCrateDelete(crate, crate_origin)
Definition: _supplydrop.gsc:1467
‪dropEverythingTouchingCrate
‪function dropEverythingTouchingCrate(origin)
Definition: _supplydrop.gsc:1461
‪timeoutCrateWaiter
‪function timeoutCrateWaiter()
Definition: _supplydrop.gsc:1634
‪SUPPY_DROP_NAV_MESH_VALID_LOCATION_BOUNDARY
‪#define SUPPY_DROP_NAV_MESH_VALID_LOCATION_BOUNDARY
Definition: _supplydrop.gsc:52
‪SUPPY_DROP_NAV_MESH_VALID_LOCATION_TOLERANCE
‪#define SUPPY_DROP_NAV_MESH_VALID_LOCATION_TOLERANCE
Definition: _supplydrop.gsc:53
‪getValidRandomStartNode
‪function getValidRandomStartNode(dest)
Definition: _helicopter.gsc:455
‪mpdialog_value
‪function mpdialog_value(mpdialogKey, defaultValue)
Definition: _battlechatter.gsc:253
‪crateRedoPhysics
‪function crateRedoPhysics()
Definition: _supplydrop.gsc:1767
‪is_clone_touching_crate
‪function is_clone_touching_crate()
Definition: _supplydrop.gsc:2281
‪SUPPLY_DROP_COMBAT_ROBOT_NAME
‪#define SUPPLY_DROP_COMBAT_ROBOT_NAME
Definition: _supplydrop.gsc:49
‪setRicochetProtectionEndTime
‪function setRicochetProtectionEndTime(killstreak, killstreak_id, owner)
Definition: _supplydrop.gsc:1396
‪is_bot
‪function is_bot()
Definition: util_shared.gsc:2488
‪useKillstreakWeaponFromCrate
‪function useKillstreakWeaponFromCrate(hardpointType)
Definition: _killstreak_weapons.gsc:236
‪WaitForTimeout
‪function WaitForTimeout(killstreak, duration, callback, endCondition1, endCondition2, endCondition3)
Definition: _killstreaks.gsc:2913
‪allow_assists
‪function allow_assists(killstreakType, allow)
Definition: _killstreaks.gsc:399
‪is_equipment_touching_crate
‪function is_equipment_touching_crate(player)
Definition: _supplydrop.gsc:2301
‪useEntOwnerDeathWaiter
‪function useEntOwnerDeathWaiter(owner)
Definition: _supplydrop.gsc:2356
‪spawn_helicopter
‪function spawn_helicopter(owner, team, origin, angles, model, targetname, killstreak_id, context)
Definition: _supplydrop.gsc:2655
‪play_in_space
‪function play_in_space(localClientNum, alias, origin)
Definition: sound_shared.csc:30
‪use_killstreak_tv_guided_missile
‪function use_killstreak_tv_guided_missile(killstreak)
Definition: _supplydrop.gsc:833
‪disarmedHackedCarepackage
‪function disarmedHackedCarepackage()
Definition: challenges_shared.gsc:584
‪set_to_player
‪function set_to_player(str_field_name, n_value)
Definition: clientfield_shared.gsc:58
‪crateKill
‪function crateKill()
Definition: _supplydrop.gsc:2097
‪clear
‪function clear(str_flag)
Definition: flag_shared.csc:130
‪advancedFinalizeCrateCategory
‪function advancedFinalizeCrateCategory(category)
Definition: _supplydrop.gsc:294
‪register_killstreak_bundle
‪function register_killstreak_bundle(killstreakType)
Definition: _killstreak_bundles.gsc:20
‪crateReactivate
‪function crateReactivate()
Definition: _supplydrop.gsc:2582
‪MissileTarget_ProximityDetonateIncomingMissile
‪function MissileTarget_ProximityDetonateIncomingMissile(endon1, endon2, allowDirectDamage)
Definition: _heatseekingmissile.gsc:1085
‪getMinimumFlyHeight
‪function getMinimumFlyHeight()
Definition: _airsupport.gsc:167
‪destroyEntityHeadIcons
‪function destroyEntityHeadIcons()
Definition: entityheadicons_shared.gsc:234
‪SUPPLY_DROP_CRATE_STATE_CAPTURE
‪#define SUPPLY_DROP_CRATE_STATE_CAPTURE
Definition: _supplydrop.gsc:56
‪VERSION_SHIP
‪#define VERSION_SHIP
Definition: version.gsh:36
‪dropCrateToGround
‪function dropCrateToGround()
Definition: _supplydrop.gsc:1488
‪personalUseBar
‪function personalUseBar(object)
Definition: _supplydrop.gsc:2591
‪waittill_any_return
‪function waittill_any_return(string1, string2, string3, string4, string5, string6, string7)
Definition: util_shared.csc:212
‪play_killstreak_start_dialog
‪function play_killstreak_start_dialog(killstreakType, team, killstreakId)
Definition: _killstreaks.gsc:1905
‪SUPPLY_DROP_AI_TANK_NAME
‪#define SUPPLY_DROP_AI_TANK_NAME
Definition: _supplydrop.gsc:48
‪deleteAfterTime
‪function deleteAfterTime(time)
Definition: util_shared.gsc:2710
‪PHYSICS_TRACE_MASK_WATER
‪#define PHYSICS_TRACE_MASK_WATER
Definition: shared.gsh:132
‪checkWeaponChange
‪function checkWeaponChange(team, killstreak_id)
Definition: _supplydrop.gsc:1128
‪VAL
‪#define VAL(__var, __default)
Definition: shared.gsh:272
‪play_pilot_dialog_on_owner
‪function play_pilot_dialog_on_owner(dialogKey, killstreakType, killstreakId)
Definition: _killstreaks.gsc:2010
‪get_menu_name
‪function get_menu_name(killstreakType)
Definition: _killstreaks.gsc:435
‪use_killstreak_death_machine
‪function use_killstreak_death_machine(killstreak)
Definition: _supplydrop.gsc:767
‪crateGamblerThink
‪function crateGamblerThink()
Definition: _supplydrop.gsc:2548
‪getDropHeight
‪function getDropHeight(origin)
Definition: _supplydrop.gsc:2716
‪use_killstreak_grim_reaper
‪function use_killstreak_grim_reaper(killstreak)
Definition: _supplydrop.gsc:800
‪is_touching_crate
‪function is_touching_crate()
Definition: _supplydrop.gsc:2228
‪giveCrateKillstreakWaiter
‪function giveCrateKillstreakWaiter(event, removeCrate, extraEndon)
Definition: _supplydrop.gsc:490
‪trace
‪function trace(from, to, target)
Definition: grapple.gsc:369
‪MarkerCleanupThread
‪function MarkerCleanupThread(context)
Definition: _supplydrop.gsc:2957
‪supplyDropHeliEndPath_v2
‪function supplyDropHeliEndPath_v2(start)
Definition: _supplydrop.gsc:2862
‪get_closest_player_enemy
‪function get_closest_player_enemy(origin, teamOnly)
Definition: _battlechatter.gsc:1517
‪ENEMY_VEHICLE_ACTIVE
‪#define ENEMY_VEHICLE_ACTIVE
Definition: _hacker_tool.gsh:2
‪useKillstreakSupplyDrop
‪function useKillstreakSupplyDrop(killstreak)
Definition: _supplydrop.gsc:737
‪WaitAndDelete
‪function WaitAndDelete(time)
Definition: _supplydrop.gsc:1852
‪freeze_player_controls
‪function freeze_player_controls(b_frozen=true)
Definition: util_shared.gsc:2474
‪unlinkOnRotation
‪function unlinkOnRotation(crate)
Definition: _supplydrop.gsc:1920
‪spawn
‪function spawn(v_origin=(0, 0, 0), v_angles=(0, 0, 0))
Definition: struct.csc:23
‪crateDelete
‪function crateDelete(drop_all_to_ground)
Definition: _supplydrop.gsc:1570
‪EnemyEMPActive
‪function EnemyEMPActive()
Definition: _emp.gsc:365
‪getIconForCrate
‪function getIconForCrate()
Definition: _supplydrop.gsc:1207
‪crateDropToGroundTrace
‪function crateDropToGroundTrace(start)
Definition: _supplydrop.gsc:2203
‪IS_TRUE
‪#define IS_TRUE(__a)
Definition: shared.gsh:251
‪supplyDropGrenadePullWatcher
‪function supplyDropGrenadePullWatcher(killstreak_id)
Definition: _supplydrop.gsc:1141
‪fizzle
‪function fizzle(attacker)
Definition: _tacticalinsertion.gsc:187
‪giveCrateWeapon
‪function giveCrateWeapon(weapon_name)
Definition: _supplydrop.gsc:537
‪get
‪function get(kvp_value, kvp_key="targetname")
Definition: struct.csc:13
‪_enableWeapon
‪function _enableWeapon()
Definition: util_shared.gsc:1145
‪SQR
‪#define SQR(__var)
Definition: shared.gsh:293
‪crateDropToGroundKill
‪function crateDropToGroundKill()
Definition: _supplydrop.gsc:2130
‪play_killstreak_threat
‪function play_killstreak_threat(killstreakType)
Definition: _battlechatter.gsc:892
‪playSmokeSound
‪function playSmokeSound(position, duration, startSound, stopSound, loopSound)
Definition: _smokegrenade.gsc:169
‪init
‪function init()
Definition: _supplydrop.gsc:152
‪waitAndDetonate
‪function waitAndDetonate(object, delay, attacker, weapon)
Definition: _weaponobjects.gsc:615
‪error
‪function error(msg)
Definition: _util.gsc:28
‪DisplayKillstreakTeamMessageToAll
‪function DisplayKillstreakTeamMessageToAll(killstreak, player)
Definition: popups_shared.gsc:91
‪get_next_obj_id
‪function get_next_obj_id()
Definition: gameobjects_shared.gsc:4132
‪MarkerUpdateThread
‪function MarkerUpdateThread(context)
Definition: _supplydrop.gsc:943
‪add_limited_weapon
‪function add_limited_weapon(weapon, owner, num_drops)
Definition: _weapons.gsc:1651
‪change_killstreak_quantity
‪function change_killstreak_quantity(killstreakWeapon, delta)
Definition: _killstreaks.gsc:1012
‪incCrateKillstreakUsageStat
‪function incCrateKillstreakUsageStat(weapon, killstreak_id)
Definition: _supplydrop.gsc:2916
‪crateUseThinkOwner
‪function crateUseThinkOwner()
Definition: _supplydrop.gsc:2409
‪spawn_explosive_crate
‪function spawn_explosive_crate(origin, angle, killstreak, owner, team, hacker, playerHasEngineerPerk)
Definition: _supplydrop.gsc:1981
‪checkForEmp
‪function checkForEmp()
Definition: _supplydrop.gsc:1073
‪useSupplyDropMarker
‪function useSupplyDropMarker(package_contents_id, context)
Definition: _supplydrop.gsc:575
‪calledInCarePackage
‪function calledInCarePackage()
Definition: challenges_shared.gsc:1358
‪get_killstreak_for_weapon
‪function get_killstreak_for_weapon(weapon)
Definition: _killstreaks.gsc:1357
‪get_killstreak_weapon
‪function get_killstreak_weapon(killstreak)
Definition: killstreaks_shared.gsc:106
‪addOffsetOntoPoint
‪function addOffsetOntoPoint(point, direction, offset)
Definition: _supplydrop.gsc:2779
‪watchExplode
‪function watchExplode(weapon, owner, killstreak_id, package_contents_id)
Definition: _supplydrop.gsc:1823
‪setCategoryTypeWeight
‪function setCategoryTypeWeight(category, type, weight)
Definition: _supplydrop.gsc:311
‪deleteOnOwnerleave
‪function deleteOnOwnerleave()
Definition: _supplydrop.gsc:1844
‪getRandomCrateType
‪function getRandomCrateType(category, gambler_crate_name)
Definition: _supplydrop.gsc:405
‪loop_sound
‪function loop_sound(alias, interval)
Definition: _supplydrop.gsc:2040
‪switch_to_last_non_killstreak_weapon
‪function switch_to_last_non_killstreak_weapon(immediate, awayfromBall)
Definition: killstreaks_shared.gsc:36
‪release_obj_id
‪function release_obj_id(objID)
Definition: gameobjects_shared.gsc:4166
‪crateLand
‪function crateLand(crate, category, owner, team, context)
Definition: _ai_tank.gsc:188
‪getNextDropDirection
‪function getNextDropDirection(drop_direction, degrees)
Definition: _supplydrop.gsc:2726
‪DEFAULT
‪#define DEFAULT(__var, __default)
Definition: shared.gsh:270
‪dropCratesToGround
‪function dropCratesToGround(origin, radius)
Definition: _supplydrop.gsc:1475
‪followPath
‪function followPath(path, doneNotify, stopAtGoal)
Definition: _airsupport.gsc:501
‪wait_network_frame
‪function wait_network_frame(n_count=1)
Definition: util_shared.gsc:64
‪supply_drop_dev_gui
‪function supply_drop_dev_gui()
Definition: _supplydrop.gsc:3420
‪crateTimeOut
‪function crateTimeOut(time)
Definition: _supplydrop.gsc:1838
‪isKillstreakAllowed
‪function isKillstreakAllowed(hardpointType, team)
Definition: _killstreakrules.gsc:352
‪isSupplyDropGrenadeAllowed
‪function isSupplyDropGrenadeAllowed(killstreak)
Definition: _supplydrop.gsc:646
‪_disableWeapon
‪function _disableWeapon()
Definition: util_shared.gsc:1137
‪supplyDropGrenadeTimeout
‪function supplyDropGrenadeTimeout(team, killstreak_id, weapon)
Definition: _supplydrop.gsc:1087
‪lbExplode
‪function lbExplode()
Definition: _supplydrop.gsc:3374
‪end
‪function end(final)
Definition: _killcam.gsc:511
‪crateActivate
‪function crateActivate(hacker)
Definition: _supplydrop.gsc:1271
‪lbSpin
‪function lbSpin(speed)
Definition: _supplydrop.gsc:3395
‪supplyDropWatcher
‪function supplyDropWatcher(package_contents_id, trigger_event, supplyDropWeapon, context)
Definition: _supplydrop.gsc:995
‪crateUseThink
‪function crateUseThink()
Definition: _supplydrop.gsc:2365
‪DisplayTeamMessageToAll
‪function DisplayTeamMessageToAll(message, player)
Definition: popups_shared.gsc:122
‪cleanUpWatcherOnDeath
‪function cleanUpWatcherOnDeath(team, killstreak_id)
Definition: _supplydrop.gsc:907
‪DelDropLocation
‪function DelDropLocation(killstreak_id)
Definition: _supplydrop.gsc:663
‪waittill_any
‪function waittill_any(str_notify1, str_notify2, str_notify3, str_notify4, str_notify5)
Definition: util_shared.csc:375
‪AI_TANK_AGR_NAME
‪#define AI_TANK_AGR_NAME
Definition: _killstreaks.gsh:16
‪giveCrateItem
‪function giveCrateItem(crate)
Definition: _supplydrop.gsc:480
‪capturedCrate
‪function capturedCrate(owner)
Definition: challenges_shared.gsc:767
‪register_dialog
‪function register_dialog(killstreakType, informDialog, taacomDialogBundleKey, pilotDialogArrayKey, startDialogKey, enemyStartDialogKey, enemyStartMultipleDialogKey, hackedDialogKey, hackedStartDialogKey, requestDialogKey, threatDialogKey, isInventory)
Definition: _killstreaks.gsc:239
‪SUPPLY_DROP_CRATE_STATE_DISARM
‪#define SUPPLY_DROP_CRATE_STATE_DISARM
Definition: _supplydrop.gsc:58
‪PHYSICS_TRACE_MASK_PHYSICS
‪#define PHYSICS_TRACE_MASK_PHYSICS
Definition: shared.gsh:130
‪use_killstreak_mp40
‪function use_killstreak_mp40(killstreak)
Definition: _supplydrop.gsc:870
‪refCountDecChopper
‪function refCountDecChopper(team, killstreak_id)
Definition: _supplydrop.gsc:3411
‪SUPPY_DROP_ON_TARGET_DISTANCE
‪#define SUPPY_DROP_ON_TARGET_DISTANCE
Definition: _supplydrop.gsc:51
‪abort_level
‪function abort_level()
Definition: callbacks_shared.gsc:1018
‪remove_used_killstreak
‪function remove_used_killstreak(killstreak, killstreakId, take_weapon_after_use=true)
Definition: _killstreaks.gsc:1222
‪useHoldThinkLoop
‪function useHoldThinkLoop(player)
Definition: _supplydrop.gsc:2517
‪SAMTurretWatcher
‪function SAMTurretWatcher(destination)
Definition: _supplydrop.gsc:3235
‪ConfigureTeamPost
‪function ConfigureTeamPost(owner)
Definition: _supplydrop.gsc:1508
‪giveCrateKillstreak
‪function giveCrateKillstreak(killstreak)
Definition: _supplydrop.gsc:501
‪register_strings
‪function register_strings(killstreakType, receivedText, notUsableText, inboundText, inboundNearPlayerText, hackedText, utilizesAirspace=true, isInventory=false)
Definition: _killstreaks.gsc:223
‪registerCrateType
‪function registerCrateType(category, type, name, weight, hint, hint_gambler, giveFunction, landFunctionOverride)
Definition: _supplydrop.gsc:363
‪killstreakStop
‪function killstreakStop(hardpointType, team, id)
Definition: _killstreakrules.gsc:293
‪getDropDirection
‪function getDropDirection()
Definition: _supplydrop.gsc:2721
‪AddDropLocation
‪function AddDropLocation(killstreak_id, location)
Definition: _supplydrop.gsc:658
‪_disableUsability
‪function _disableUsability()
Definition: util_shared.gsc:1112
‪crateTimeOutThreader
‪function crateTimeOutThreader()
Definition: _supplydrop.gsc:1832
‪play_impact_sound
‪function play_impact_sound()
Definition: _supplydrop.gsc:1733
‪watch_explosive_crate
‪function watch_explosive_crate()
Definition: _supplydrop.gsc:2009
‪crateDeactivate
‪function crateDeactivate()
Definition: _supplydrop.gsc:1406
‪getHeliPath
‪function getHeliPath(start, goal)
Definition: _airsupport.gsc:477
‪heliDestroyed
‪function heliDestroyed()
Definition: _supplydrop.gsc:3345
‪dropAllToGround
‪function dropAllToGround(origin, radius, stickyObjectRadius)
Definition: _supplydrop.gsc:1451
‪ownerTeamChangeWatcher
‪function ownerTeamChangeWatcher()
Definition: _supplydrop.gsc:1436
‪useHoldThink
‪function useHoldThink(player, useTime)
Definition: _supplydrop.gsc:2441
‪finalizeCrateCategory
‪function finalizeCrateCategory(category)
Definition: _supplydrop.gsc:277
‪heliDeliverCrate
‪function heliDeliverCrate(origin, weapon, owner, team, killstreak_id, package_contents_id, context)
Definition: _supplydrop.gsc:2971
‪killstreakStart
‪function killstreakStart(hardpointType, team, hacked, displayTeamMessage)
Definition: _killstreakrules.gsc:184
‪heli_damage_monitor
‪function heli_damage_monitor(hardpointtype)
Definition: _helicopter.gsc:1258
‪setEntityHeadIcon
‪function setEntityHeadIcon(team, owner, offset, objective, constant_size)
Definition: entityheadicons_shared.gsc:43
‪doSupplyDrop
‪function doSupplyDrop(weapon_instance, weapon, owner, killstreak_id, package_contents_id, context)
Definition: _supplydrop.gsc:1810
‪set
‪function set(str_field_name, n_value)
Definition: clientfield_shared.gsc:34
‪default_land_function
‪function default_land_function(crate, category, owner, team)
Definition: _supplydrop.gsc:1947
‪waitTillNotMoving
‪function waitTillNotMoving()
Definition: util_shared.gsc:2621
‪spawnUseEnt
‪function spawnUseEnt()
Definition: _supplydrop.gsc:2342
‪IsLocationGood
‪function IsLocationGood(location, context)
Definition: _supplydrop.gsc:668
‪configure_team
‪function configure_team(killstreakType, killstreakId, owner, influencerType, configureTeamPreFunction, configureTeamPostFunction, isHacked=false)
Definition: _killstreaks.gsc:2806
‪remove_ricochet_protection
‪function remove_ricochet_protection(killstreak_id, owner)
Definition: _killstreaks.gsc:3177
‪get_height
‪function get_height(e_ignore)
Definition: _supplydrop.gsc:1673
‪cleanup
‪function cleanup(context, player)
Definition: _supplydrop.gsc:922
‪set_player_uimodel
‪function set_player_uimodel(str_field_name, n_value)
Definition: clientfield_shared.gsc:75
‪set_ricochet_protection_endtime
‪function set_ricochet_protection_endtime(killstreak_id, owner, endTime)
Definition: _killstreaks.gsc:3166
‪register_alt_weapon
‪function register_alt_weapon(killstreakType, weaponName, isInventory)
Definition: _killstreaks.gsc:318
‪create_flare_ent
‪function create_flare_ent(offset)
Definition: _helicopter.gsc:645
‪update_crate_velocity
‪function update_crate_velocity()
Definition: _supplydrop.gsc:1749
‪register
‪function register()
Definition: _ai_tank.gsc:126
‪drawcylinder
‪function drawcylinder(pos, rad, height)
Definition: laststand_shared.gsc:170
‪getHeliEnd
‪function getHeliEnd(drop_origin, drop_direction)
Definition: _supplydrop.gsc:2760
‪dropCrate
‪function dropCrate(origin, angle, killstreak, owner, team, killcamEnt, killstreak_id, package_contents_id, crate_, context)
Definition: _supplydrop.gsc:1859
‪giveCrateCaptureMedal
‪function giveCrateCaptureMedal(crate, capturer)
Definition: scoreevents_shared.gsc:279
‪supplyDropHeliStartPath_v2_part2
‪function supplyDropHeliStartPath_v2_part2(goal, goalPath, goal_world_offset)
Definition: _supplydrop.gsc:2805
‪SUPPLY_DROP_CRATE_STATE_HACK
‪#define SUPPLY_DROP_CRATE_STATE_HACK
Definition: _supplydrop.gsc:57
‪_enableUsability
‪function _enableUsability()
Definition: util_shared.gsc:1119
‪crateSpawn
‪function crateSpawn(killstreak, killstreakId, owner, team, drop_origin, drop_angle)
Definition: _supplydrop.gsc:1515
‪give
‪function give(killstreakType, streak, suppressNotification, noXP, toBottom)
Definition: _killstreaks.gsc:539
‪WatchForCrateKill
‪function WatchForCrateKill(start_kill_watch_z_threshold)
Definition: _supplydrop.gsc:2057
‪result
‪function result(death, attacker, mod, weapon)
Definition: _zm_aat_blast_furnace.gsc:46
‪SUPPLY_DROP_CRATE_STATE_NONE
‪#define SUPPLY_DROP_CRATE_STATE_NONE
Definition: _supplydrop.gsc:55
‪ORANGE
‪#define ORANGE
Definition: shared.gsh:179
‪removeWeaponObject
‪function removeWeaponObject(watcher, weapon_ent)
Definition: _weaponobjects.gsc:911
‪name
‪class GroundFx name
‪playerChangeWeaponWaiter
‪function playerChangeWeaponWaiter()
Definition: _supplydrop.gsc:1186
‪watchForGrenadePutDown
‪function watchForGrenadePutDown()
Definition: _supplydrop.gsc:1172
‪supplyDropHeliEndPath
‪function supplyDropHeliEndPath(origin, drop_direction)
Definition: _supplydrop.gsc:2876
‪supplyDropHeliStartPath
‪function supplyDropHeliStartPath(goal, goal_offset)
Definition: _supplydrop.gsc:2811
‪heliDropCrate
‪function heliDropCrate(killstreak, originalOwner, offset, killCamEnt, killstreak_id, package_contents_id, context)
Definition: _supplydrop.gsc:3276
‪do_supply_drop_detonation
‪function do_supply_drop_detonation(weapon, owner)
Definition: _supplydrop.gsc:1781
‪getHeliStart
‪function getHeliStart(drop_origin, drop_direction)
Definition: _supplydrop.gsc:2736
‪supplyDropHeliStartPath_v2_setup
‪function supplyDropHeliStartPath_v2_setup(goal, goal_offset)
Definition: _supplydrop.gsc:2788
‪supplyDropHeliStartPath_v2_part2_local
‪function supplyDropHeliStartPath_v2_part2_local(goal, goalPath, goal_local_offset)
Definition: _supplydrop.gsc:2797
‪stationaryCrateOverride
‪function stationaryCrateOverride()
Definition: _supplydrop.gsc:1619
‪cratePhysics
‪function cratePhysics()
Definition: _supplydrop.gsc:1645
‪SUPPLY_DROP_NAME
‪#define SUPPLY_DROP_NAME
Definition: _supplydrop.gsc:47
‪WAIT_SERVER_FRAME
‪#define WAIT_SERVER_FRAME
Definition: shared.gsh:265
‪giveSpecializedCrateWeapon
‪function giveSpecializedCrateWeapon(weapon)
Definition: _supplydrop.gsc:506