‪Black Ops 3 Source Code Explorer  0.1
‪An script explorer for Black Ops 3 by ZeRoY
zombie_vortex.gsc
Go to the documentation of this file.
1 #using scripts\shared\system_shared;
2 #using scripts\codescripts\struct;
3 #using scripts\shared\clientfield_shared;
4 #using scripts\shared\visionset_mgr_shared;
5 #using scripts\shared\audio_shared;
6 #using scripts\shared\util_shared;
7 #using scripts\shared\array_shared;
8 #using scripts\shared\vehicle_ai_shared;
9 #using scripts\shared\vehicle_death_shared;
10 
11 #insert scripts\shared\shared.gsh;
12 #insert scripts\shared\ai\zombie_vortex.gsh;
13 #insert scripts\shared\version.gsh;
14 #insert scripts\shared\archetype_shared\archetype_shared.gsh;
15 
16 #namespace zombie_vortex;
17 
18 ‪REGISTER_SYSTEM_EX( "vortex_shared", &‪__init__, &‪__main__, undefined )
19 
20 
21 function ‪__init__()
22 {
23  ‪DEFAULT( level.vsmgr_prio_visionset_zombie_vortex, ‪VORTEX_VISIONSET_PRIORITY );
24  ‪DEFAULT( level.vsmgr_prio_overlay_zombie_vortex, ‪VORTEX_OVERLAY_PRIORITY );
25 
26  ‪visionset_mgr::register_info( "visionset", ‪VORTEX_SCREEN_EFFECT_NAME + "_visionset", ‪VERSION_SHIP, level.vsmgr_prio_visionset_zombie_vortex, ‪VORTEX_VISIONSET_LERP_COUNT, true, &‪visionset_mgr::ramp_in_out_thread_per_player, false );
28 
30  ‪clientfield::register( "allplayers", "vision_blur", ‪VERSION_SHIP, 1, "int" );
31 
32  level.vortex_manager = SpawnStruct();
33  level.vortex_manager.count = 0;
34  level.vortex_manager.a_vorticies = [];
35  level.vortex_manager.a_active_vorticies = [];
36 
37  level.vortex_id = 0;
38 
40 }
41 
42 function ‪__main__()
43 {
45 }
46 
47 
48 function ‪init_vortices()
49 {
50  i = 0;
51  while( i < ‪NUMBER_OF_VORTICES )
52  {
53  sVortex = ‪Spawn( "script_model", (0,0,0) );
54  ‪ARRAY_ADD( level.vortex_manager.a_vorticies, sVortex );
55  i++;
56  }
57 }
58 
60 {
61  foreach( vortex in level.vortex_manager.a_vorticies )
62  {
63  if( !‪IS_TRUE( vortex.in_use ) )
64  {
65  return vortex;
66  }
67  }
68  return level.vortex_manager.a_vorticies[0];
69 }
70 
72 {
73  count = 0;
74  foreach( vortex in level.vortex_manager.a_vorticies )
75  {
76  if( ‪IS_TRUE( vortex.in_use ) )
77  {
78  count++;
79  }
80  }
81  return count;
82 }
83 
84 
85 function private ‪stop_vortex_fx_after_time( vortex_fx_handle, vortex_position, vortex_explosion_fx, n_vortex_time )
86 {
87  n_starttime = GetTime();
88  n_curtime = GetTime() - n_starttime;
89 
90  while( n_curtime < n_vortex_time )
91  {
92  wait 0.05;
93  n_curtime = GetTime() - n_starttime;
94  }
95 
96 
97 }
98 
99 
122 function ‪start_timed_vortex( v_vortex_origin, n_vortex_radius, vortex_pull_duration, vortex_effect_duration, n_vortex_explosion_radius, eAttacker, weapon, should_shellshock_player = false, visionset_func = undefined, should_shield = false, effect_version = ‪VORTEX_EFFECT_VERSION_NONE, should_explode = true, vortex_projectile = undefined )
123 {
124  self endon("death");
125  self endon("disconnect");
126 
127  assert( IsDefined( v_vortex_origin ), "Tried to create a vortex without an origin" );
128  assert( IsDefined( n_vortex_radius ), "Tried to create a vortex without a radius" );
129  assert( IsDefined( vortex_pull_duration ), "Tried to create a vortex without a duration" );
130 
131  n_starttime = GetTime();
132  n_currtime = GetTime() - n_starttime;
133 
134  a_e_players = GetPlayers();
135 
136  if( !isDefined( n_vortex_explosion_radius ) )
137  {
138  n_vortex_explosion_radius = n_vortex_radius * 1.5;
139  }
140 
141  sVortex = ‪get_unused_vortex();
142  sVortex.in_use = true;
143  sVortex.attacker = eAttacker;
144  sVortex.weapon = weapon;
145  sVortex.angles = (0,0,0);
146  sVortex.origin = v_vortex_origin;
147 
148  sVortex DontInterpolate();
149 
150  sVortex ‪clientfield::increment( ‪VORTEX_START_CLIENTFIELD, effect_version );
151 
152  s_active_vortex = ‪struct::spawn(v_vortex_origin);
153  s_active_vortex.weapon = weapon;
154  s_active_vortex.attacker = eAttacker;
155 
156  ‪ARRAY_ADD( level.vortex_manager.a_active_vorticies, s_active_vortex );
157 
158  n_vortex_time_sv = vortex_pull_duration;
159  n_vortex_time_cl = ( IsDefined( vortex_effect_duration ) ? vortex_effect_duration : vortex_pull_duration );
160 
161  n_vortex_time = n_vortex_time_sv * 1000;
162 
163  team = "axis";
164 
165  if( IsDefined( level.zombie_team ) )
166  {
167  team = level.zombie_team;
168  }
169 
170  while( n_currtime <= n_vortex_time )
171  {
172  a_ai_zombies = array::get_all_closest( v_vortex_origin, getAITeamArray( team ), undefined, undefined, n_vortex_radius );
173 
174  // Check for zombies below vortex
175  a_ai_zombies = ArrayCombine( a_ai_zombies, ‪vortex_z_extension( a_ai_zombies, v_vortex_origin, n_vortex_radius ), false, false );
176 
177  sVortex.zombies = a_ai_zombies;
178 
179  if( ‪IS_TRUE( level.idgun_draw_debug ) )
180  {
181 /#
182  Circle( v_vortex_origin, n_vortex_radius, ( 0, 0, 1 ), false, true, 1 );
183 #/
184  }
185 
186 
187  foreach( ai_zombie in a_ai_zombies )
188  {
189  if( IsVehicle( ai_zombie ) )
190  {
191  if(
192  IsAlive( ai_zombie ) &&
193  IsDefined( ai_zombie ‪vehicle_ai::get_state_callbacks( "idgun_death" ) ) &&
194  ai_zombie ‪vehicle_ai::get_current_state() != "idgun_death" &&
195  !ai_zombie.ignorevortices
196  )
197  {
198  params = SpawnStruct();
199  params.vpoint = v_vortex_origin;
200  params.attacker = eAttacker;
201  params.weapon = weapon;
202  if ( IsDefined( ai_zombie.idgun_death_speed ) )
203  {
204  params.idgun_death_speed = ai_zombie.idgun_death_speed;
205  }
206  ai_zombie ‪vehicle_ai::set_state( "idgun_death", params );
207  }
208  }
209  else
210  {
211  if( !‪IS_TRUE( ai_zombie.interdimensional_gun_kill ) && !ai_zombie.ignorevortices )
212  {
213  ai_zombie.damageOrigin = v_vortex_origin;
214  if(‪IS_TRUE(should_shield))
215  {
216  ai_zombie.allowdeath = false;
217  ai_zombie.magic_bullet_shield = true;
218  }
219  ai_zombie.interdimensional_gun_kill = true;
220  ai_zombie.interdimensional_gun_attacker = eAttacker;
221  ai_zombie.interdimensional_gun_inflictor = eAttacker;
222  ai_zombie.interdimensional_gun_weapon = weapon;
223  ai_zombie.interdimensional_gun_projectile = vortex_projectile;
224  }
225  }
226  }
227 
228  if( should_shellshock_player )
229  {
230  foreach( e_player in a_e_players )
231  {
232  if( IsDefined( visionset_func ) )
233  {
234  e_player thread [[visionset_func]](v_vortex_origin, n_vortex_radius, n_starttime, n_vortex_time_sv, n_vortex_time_cl );
235  }
236  else
237  {
238  if( IsDefined(e_player) && !‪IS_TRUE( e_player.idgun_vision_on ) )
239  {
240  // If Player is within vortex range, apply vision overlay
241  if( Distance( e_player.origin, v_vortex_origin ) < Float( n_vortex_radius / 2 ) )
242  {
244  }
245  }
246  }
247  }
248  }
249 
250  wait 0.05;
251  n_currtime = GetTime() - n_starttime;
252  }
253 
254  if( ‪IS_TRUE( should_explode ) )
255  {
256  n_time_to_wait_for_explosion = ( n_vortex_time_cl - n_vortex_time_sv ) + 0.35; //0.35 = time in which the vortex shrinks
257 
258  wait( n_time_to_wait_for_explosion );
259 
260  sVortex.in_use = false;
261  ArrayRemoveValue( level.vortex_manager.a_active_vorticies, s_active_vortex );
262 
263  ‪vortex_explosion( v_vortex_origin, eAttacker, n_vortex_explosion_radius );
264  }
265  else
266  {
267  //release zombies that didn't make it into the vortex
268  foreach( zombie in sVortex.zombies )
269  {
270  if( !IsDefined( zombie ) || !IsAlive( zombie ) )
271  {
272  continue;
273  }
274  if( IsDefined( level.vortexResetCondition ) && [[level.vortexResetCondition]]( zombie ) )
275  {
276  continue;
277  }
278 
279  zombie.interdimensional_gun_kill = undefined;
280  zombie.interdimensional_gun_attacker = undefined;
281  zombie.interdimensional_gun_inflictor = undefined;
282  zombie.interdimensional_gun_weapon = undefined;
283  zombie.interdimensional_gun_projectile = undefined;
284 
285  zombie PathMode( "move allowed" );
286  }
287 
288  sVortex.in_use = false;
289  ArrayRemoveValue( level.vortex_manager.a_active_vorticies, s_active_vortex );
290  }
291 }
292 
293 // Include zombies whose bodies are inside the vortex radius, but have origins that are outside the vortex radius
294 function ‪vortex_z_extension( a_ai_zombies, v_vortex_origin, n_vortex_radius )
295 {
296  a_ai_zombies_extended = array::get_all_closest( v_vortex_origin, getAITeamArray( "axis" ), undefined, undefined, n_vortex_radius + 72 ); // 72 units is the standard AI character height
297  a_ai_zombies_extended_filtered = array::exclude( a_ai_zombies_extended, a_ai_zombies );
298 
299  i = 0;
300  while ( i < a_ai_zombies_extended_filtered.size )
301  {
302  if ( ( a_ai_zombies_extended_filtered[ i ].origin[2] < v_vortex_origin[2] )
303  && BulletTracePassed( a_ai_zombies_extended_filtered[ i ].origin + ( 0, 0, 5 ), v_vortex_origin + ( 0, 0, 20 ), false, self, undefined, false, false ) )
304  {
305  i++;
306  }
307  else
308  {
309  ArrayRemoveValue( a_ai_zombies_extended_filtered, a_ai_zombies_extended_filtered[i]);
310  }
311  }
312 
313  return a_ai_zombies_extended_filtered;
314 }
315 
316 function private ‪vortex_explosion( v_vortex_explosion_origin, eAttacker, n_vortex_radius )
317 {
318 
319  team = "axis";
320 
321  if( IsDefined( level.zombie_team ) )
322  {
323  team = level.zombie_team;
324  }
325 
326  a_ai_zombies = array::get_all_closest( v_vortex_explosion_origin, getAITeamArray( team), undefined, undefined, n_vortex_radius );
327 
328  if( ‪IS_TRUE( level.idgun_draw_debug ) )
329  {
330 /#
331  Circle( v_vortex_explosion_origin, n_vortex_radius, ( 1, 0, 0 ), false, true, 1000 );
332 #/
333  }
334  foreach( ai_zombie in a_ai_zombies )
335  {
336  if( !ai_zombie.ignorevortices )
337  {
338  if( ‪IS_TRUE( ai_zombie.interdimensional_gun_kill ) )
339  {
340  ai_zombie Hide();
341  }
342  else
343  {
344 
345  ai_zombie.interdimensional_gun_kill = undefined;
346  ai_zombie.interdimensional_gun_kill_vortex_explosion = 1;
347  ai_zombie.veh_idgun_allow_damage = true;
348  if( IsDefined( eAttacker ) )
349  {
350  ai_zombie DoDamage( ai_zombie.health + 10000, ai_zombie.origin, eAttacker, undefined, undefined, "MOD_EXPLOSIVE" );
351  }
352  else
353  {
354  ai_zombie DoDamage( ai_zombie.health + 10000, ai_zombie.origin, undefined, undefined, undefined, "MOD_EXPLOSIVE" );
355  }
356 
357  n_radius_sqr = n_vortex_radius * n_vortex_radius;
358  n_distance_sqr = DistanceSquared( ai_zombie.origin, v_vortex_explosion_origin );
359 
360  n_dist_mult = n_distance_sqr / n_radius_sqr;
361 
362  v_fling = VectorNormalize( ai_zombie.origin - v_vortex_explosion_origin );
363 
364  v_fling = (v_fling[0], v_fling[1], abs( v_fling[2] ));
365  v_fling = VectorScale( v_fling, 100 + 100 * n_dist_mult);
366 
367  if ( !‪IS_TRUE( level.ignore_vortex_ragdoll ) )
368  {
369  ai_zombie StartRagdoll();
370  ai_zombie LaunchRagdoll( v_fling );
371  }
372  }
373  }
374  }
375 }
376 
377 // Vision overlay and blur when player enters vortex
378 // self == player
380 {
383  self.idgun_vision_on = true;
384  wait 2.5;
385  self.idgun_vision_on = false;
386 }
387 
388 //self = vehicle
390 {
391  if( IsAirborne( self ) )
392  {
393  self ‪vehicle_ai::add_state( "idgun_death",
396  undefined );
397  }
398  else
399  {
400  self ‪vehicle_ai::add_state( "idgun_death",
403  undefined );
404  }
405 }
406 
407 // ----------------------------------------------
408 //vehicle idgun death state
409 // ----------------------------------------------
410 
411 function ‪state_idgun_crush_enter( params )
412 {
415  self CancelAIMove();
416 }
417 
418 function ‪flyEntDelete(entToWatch)
419 {
420  self endon("death");
421  entToWatch waittill("death");
422  self delete();
423 }
424 
425 function ‪state_idgun_crush_update( params )
426 {
427  self endon( "death" );
428 
429  const veh_idgun_move_speed = 8.0;
430  const veh_idgun_crush_dist_sqr = 40.0 * 40.0;
431 
432  black_hole_center = params.vpoint;
433  attacker = params.attacker;
434  weapon = params.weapon;
435 
436  if( self.archetype == ‪ARCHETYPE_RAPS )
437  {
438  crush_anim = "ai_zombie_zod_raps_dth_f_id_gun_crush";
439  }
440 
441 
442  veh_to_black_hole_vec = VectorNormalize( black_hole_center - self.origin );
443 
444  fly_ent = ‪Spawn( "script_origin", self.origin );
445  fly_ent thread ‪flyEntDelete(self);
446  self LinkTo( fly_ent );
447 
448  while( 1 )
449  {
450  veh_to_black_hole_dist_sqr = DistanceSquared( self.origin, black_hole_center );
451 
452  if( veh_to_black_hole_dist_sqr < ‪IDGUN_VEH_KILL_DIST_SQR )
453  {
454  self.veh_idgun_allow_damage = true;
455  self DoDamage( self.health + 666, self.origin, attacker, undefined, "none", "MOD_UNKNOWN", 0, weapon );
456  return;
457  }
458  else if( !‪IS_TRUE( self.crush_anim_started ) && veh_to_black_hole_dist_sqr < veh_idgun_crush_dist_sqr )
459  {
460  if(isDefined(crush_anim) )
461  {
462  self AnimScripted( "anim_notify", self.origin, self.angles, crush_anim, "normal", undefined, undefined, 0.2 );
463  }
464  self.crush_anim_started = true;
465  }
466 
467  fly_ent.origin += veh_to_black_hole_vec * veh_idgun_move_speed;
468  wait( 0.1 );
469  }
470 }
471 
473 {
475  self CancelAIMove();
476 
477  self SetNearGoalNotifyDist( 4 );
478  self.vehAirCraftCollisionEnabled = false;
479 }
480 
482 {
483  self endon( "death" );
484 
485  black_hole_center = params.vpoint;
486  attacker = params.attacker;
487  weapon = params.weapon;
488  death_speed = 2;
489 
490  if ( IsDefined( params.idgun_death_speed ) )
491  {
492  death_speed = params.idgun_death_speed;
493  }
494 
495  self SetSpeed( death_speed );
496 
497  self ASMRequestSubstate( "idgun@movement" );
498 
499  self thread ‪switch_to_crush_asm( black_hole_center );
500  self SetVehGoalPos( black_hole_center, false, false );
501  self waittill( "near_goal" );
502 
504  self.veh_idgun_allow_damage = true;
505  self DoDamage( self.health + 666, self.origin, attacker, undefined, "none", "MOD_UNKNOWN", 0, weapon );
506 }
507 
508 function ‪switch_to_crush_asm( black_hole_center )
509 {
510  self endon( "death" );
511  const veh_idgun_crush_dist_sqr = 30.0 * 30.0;
512 
513  while( 1 )
514  {
515  if( DistanceSquared( self.origin, black_hole_center ) < veh_idgun_crush_dist_sqr )
516  {
517  self ASMRequestSubstate( "idgun_crush@movement" );
518  return;
519  }
520  wait 0.1;
521  }
522 }
523 
525 {
526  self endon( "death" );
527 
528  if( IsDefined( self.parasiteEnemy ) && IsDefined( self.parasiteEnemy.hunted_by ) )
529  {
530  self.parasiteEnemy.hunted_by--;
531  }
532 
533  self playsound( "zmb_parasite_explo" );
534 
535  //wait for sound/fx
536  wait 0.2;
537 
538  self Delete();
539 }
‪player_vortex_visionset
‪function player_vortex_visionset(name)
Definition: zombie_vortex.gsc:379
‪get_unused_vortex
‪function get_unused_vortex()
Definition: zombie_vortex.gsc:59
‪activate
‪function activate()
Definition: traps_shared.gsc:655
‪add_state
‪function add_state(name, enter_func, update_func, exit_func, reenter_func)
Definition: statemachine_shared.gsc:59
‪set_state
‪function set_state(name, state_params)
Definition: statemachine_shared.gsc:133
‪ClearAllLookingAndTargeting
‪function ClearAllLookingAndTargeting()
Definition: vehicle_ai_shared.gsc:697
‪register_custom_add_state_callback
‪function register_custom_add_state_callback(func)
Definition: vehicle_ai_shared.gsc:1142
‪ClearAllMovement
‪function ClearAllMovement(zeroOutSpeed=false)
Definition: vehicle_ai_shared.gsc:707
‪get_current_state
‪function get_current_state()
Definition: vehicle_ai_shared.gsc:960
‪VORTEX_OVERLAY_PRIORITY
‪#define VORTEX_OVERLAY_PRIORITY
Definition: zombie_vortex.gsh:37
‪stop_vortex_fx_after_time
‪function private stop_vortex_fx_after_time(vortex_fx_handle, vortex_position, vortex_explosion_fx, n_vortex_time)
Definition: zombie_vortex.gsc:85
‪VORTEX_LOOP_DURATION
‪#define VORTEX_LOOP_DURATION
Definition: zombie_vortex.gsh:33
‪VERSION_SHIP
‪#define VERSION_SHIP
Definition: version.gsh:36
‪VORTEX_VISIONSET_PRIORITY
‪#define VORTEX_VISIONSET_PRIORITY
Definition: zombie_vortex.gsh:30
‪spawn
‪function spawn(v_origin=(0, 0, 0), v_angles=(0, 0, 0))
Definition: struct.csc:23
‪IS_TRUE
‪#define IS_TRUE(__a)
Definition: shared.gsh:251
‪vortex_explosion
‪function private vortex_explosion(v_vortex_explosion_origin, eAttacker, n_vortex_radius)
Definition: zombie_vortex.gsc:316
‪VORTEX_EFFECT_VERSION_NONE
‪#define VORTEX_EFFECT_VERSION_NONE
Definition: zombie_vortex.gsh:18
‪VORTEX_SCREEN_EFFECT_NAME
‪#define VORTEX_SCREEN_EFFECT_NAME
Definition: zombie_vortex.gsh:15
‪DEFAULT
‪#define DEFAULT(__var, __default)
Definition: shared.gsh:270
‪state_idgun_flying_crush_enter
‪function state_idgun_flying_crush_enter(params)
Definition: zombie_vortex.gsc:472
‪VORTEX_VISIONSET_LERP_COUNT
‪#define VORTEX_VISIONSET_LERP_COUNT
Definition: zombie_vortex.gsh:31
‪get_active_vortex_count
‪function get_active_vortex_count()
Definition: zombie_vortex.gsc:71
‪__main__
‪function __main__()
Definition: zombie_vortex.gsc:42
‪REGISTER_SYSTEM_EX
‪#define REGISTER_SYSTEM_EX(__sys, __func_init_preload, __func_init_postload, __reqs)
Definition: shared.gsh:209
‪state_idgun_flying_death_update
‪function state_idgun_flying_death_update(params)
Definition: zombie_vortex.gsc:524
‪ARRAY_ADD
‪#define ARRAY_ADD(__array, __item)
Definition: shared.gsh:304
‪NUMBER_OF_VORTICES
‪#define NUMBER_OF_VORTICES
Definition: zombie_vortex.gsh:1
‪VORTEX_ENTER_DURATION
‪#define VORTEX_ENTER_DURATION
Definition: zombie_vortex.gsh:32
‪state_idgun_crush_enter
‪function state_idgun_crush_enter(params)
Definition: zombie_vortex.gsc:411
‪ARCHETYPE_RAPS
‪#define ARCHETYPE_RAPS
Definition: archetype_shared.gsh:33
‪IDGUN_VEH_KILL_DIST_SQR
‪#define IDGUN_VEH_KILL_DIST_SQR
Definition: zombie_vortex.gsh:22
‪increment
‪function increment(str_field_name, n_increment_count=1)
Definition: clientfield_shared.gsc:110
‪idgun_add_vehicle_death_state
‪function idgun_add_vehicle_death_state()
Definition: zombie_vortex.gsc:389
‪Spawn
‪function Spawn(parent, onDeathCallback)
Definition: _flak_drone.gsc:427
‪__init__
‪function __init__()
Definition: zombie_vortex.gsc:21
‪state_idgun_flying_crush_update
‪function state_idgun_flying_crush_update(params)
Definition: zombie_vortex.gsc:481
‪register_info
‪function register_info(type, name, version, lerp_step_count)
Definition: visionset_mgr_shared.csc:334
‪flyEntDelete
‪function flyEntDelete(entToWatch)
Definition: zombie_vortex.gsc:418
‪register
‪function register()
Definition: _ai_tank.gsc:126
‪state_idgun_crush_update
‪function state_idgun_crush_update(params)
Definition: zombie_vortex.gsc:425
‪vortex_z_extension
‪function vortex_z_extension(a_ai_zombies, v_vortex_origin, n_vortex_radius)
Definition: zombie_vortex.gsc:294
‪VORTEX_OVERLAY_LERP_COUNT
‪#define VORTEX_OVERLAY_LERP_COUNT
Definition: zombie_vortex.gsh:38
‪VORTEX_EXIT_DURATION
‪#define VORTEX_EXIT_DURATION
Definition: zombie_vortex.gsh:34
‪switch_to_crush_asm
‪function switch_to_crush_asm(black_hole_center)
Definition: zombie_vortex.gsc:508
‪init_vortices
‪function init_vortices()
Definition: zombie_vortex.gsc:48
‪name
‪class GroundFx name
‪ramp_in_out_thread_per_player
‪function ramp_in_out_thread_per_player(player, ramp_in, full_period, ramp_out)
Definition: visionset_mgr_shared.gsc:392
‪VORTEX_START_CLIENTFIELD
‪#define VORTEX_START_CLIENTFIELD
Definition: zombie_vortex.gsh:17
‪get_state_callbacks
‪function get_state_callbacks(statename)
Definition: vehicle_ai_shared.gsc:927
‪start_timed_vortex
‪function start_timed_vortex(v_vortex_origin, n_vortex_radius, vortex_pull_duration, vortex_effect_duration, n_vortex_explosion_radius, eAttacker, weapon, should_shellshock_player=false, visionset_func=undefined, should_shield=false, effect_version=VORTEX_EFFECT_VERSION_NONE, should_explode=true, vortex_projectile=undefined)
Definition: zombie_vortex.gsc:122