]> icculus.org git repositories - taylor/freespace2.git/blob - src/weapon/emp.cpp
Initial revision
[taylor/freespace2.git] / src / weapon / emp.cpp
1 /*
2  * $Logfile: /Freespace2/code/Weapon/Emp.cpp $
3  * $Revision$
4  * $Date$
5  * $Author$
6  *
7  * Header file for managing corkscrew missiles
8  *
9  * $Log$
10  * Revision 1.1  2002/05/03 03:28:11  root
11  * Initial revision
12  *
13  * 
14  * 9     7/24/99 1:54p Dave
15  * Hud text flash gauge. Reworked dead popup to use 4 buttons in red-alert
16  * missions.
17  * 
18  * 8     7/02/99 4:31p Dave
19  * Much more sophisticated lightning support.
20  * 
21  * 7     4/23/99 12:01p Johnson
22  * Added SIF_HUGE_SHIP
23  * 
24  * 6     2/08/99 9:34a Dave
25  * Put in a little insurance code to make sure EMP effect truly dies when
26  * a player dies (to prevent wacky dead cam action).
27  * 
28  * 5     1/08/99 2:08p Dave
29  * Fixed software rendering for pofview. Super early support for AWACS and
30  * beam weapons.
31  * 
32  * 4     11/05/98 5:55p Dave
33  * Big pass at reducing #includes
34  * 
35  * 3     10/13/98 9:29a Dave
36  * Started neatening up freespace.h. Many variables renamed and
37  * reorganized. Added AlphaColors.[h,cpp]
38  * 
39  * 2     10/07/98 10:54a Dave
40  * Initial checkin.
41  * 
42  * 1     10/07/98 10:51a Dave
43  * 
44  * 3     8/28/98 3:29p Dave
45  * EMP effect done. AI effects may need some tweaking as required.
46  * 
47  * 2     8/25/98 1:49p Dave
48  * First rev of EMP effect. Player side stuff basically done. Next comes
49  * AI code.
50  * 
51  * 1     8/24/98 9:29a Dave
52  *
53  * $NoKeywords: $
54  */
55
56 #include <stdarg.h>
57 #include "emp.h"
58 #include "timer.h"
59 #include "multimsgs.h"
60 #include "multiutil.h"
61 #include "systemvars.h"
62 #include "freespace.h"
63 #include "linklist.h"
64 #include "hudlock.h"
65 #include "hudtarget.h"
66 #include "hudgauges.h"
67 #include "missiongoals.h"
68 #include "multi.h"
69
70 // ----------------------------------------------------------------------------------------------------
71 // EMP EFFECT DEFINES/VARS
72 //
73
74 // intensity of the playing effect
75 float Emp_intensity = -1.0f;                                    // current intensity of the EMP effect (normalized to EMP_INTENSITY_MAX)
76 float Emp_decr = 0.0f;                                                  // how much to decrement the effect per second
77
78 // timestamp until we should randomly choose another target
79 int Emp_wacky_target_timestamp = -1;
80
81 // max time we'll disrupt turrets on big ships
82 #define MAX_TURRET_DISRUPT_TIME                         7500
83
84 // conventient for determining if EMP is active
85 #define EMP_ACTIVE_LOCAL()                      (Emp_intensity > 0.0f)
86
87 // for keeping track of messed up text
88 #define EMP_WACKY_TEXT_LEN                                      256
89 typedef struct wacky_text {
90         char str[EMP_WACKY_TEXT_LEN];
91         int stamp;
92 } wacky_text;
93 wacky_text Emp_wacky_text[NUM_TEXT_STAMPS];
94
95 // for randomly inserting characters
96 #define NUM_RANDOM_CHARS                51
97 char Emp_random_char[NUM_RANDOM_CHARS] = 
98                                                                         { 'a', 'b', 'c', 'd', 'e', 'f', 'g', '4', 'h', '8', '_', '$', ')', '-', '~', 'u', 'q', 
99                                                                           '.', 'x', 'h', '&', '%', '*', '1', '3', 't', 'h', 'o', 'p', '@', 'h', 'i','v', '+', '=',
100                                                                           '|', '{', '}', ':', ';', '^', 'l', 'z', 'u', 'v', '<', '>', '?', '5', '8' };
101
102 // EMP EFFECTS ON PLAYERS -----
103 // 1.) Lose target lock if any, along with ability to lock on
104 // 2.) Display EMP-BLAST icon or something (maybe flash it)
105 // 3.) at wacky intervals, target random ships (which he cannot lock on)
106 // 4.) Randomly flicker HUD gauges
107 // 5.) Randomly swap/mess-up HUD text
108
109 // EMP EFFECTS ON SHIPS -------
110 // 1.) Lightning effect proportional to the emp effect
111
112 // ----------------------------------------------------------------------------------------------------
113 // EMP EFFECT FUNCTIONS
114 //
115
116 // maybe reformat a string 
117 void emp_maybe_reformat_text(char *text, int max_len, int gauge_id);
118
119 // randomize the chars in a string
120 void emp_randomize_chars(char *str);
121
122
123 // initialize the EMP effect for the mission
124 void emp_level_init()
125 {
126         int idx;
127         
128         // reset all vars
129         Emp_intensity = 0.0f;   
130         Emp_wacky_target_timestamp = -1;
131
132         for(idx=0; idx<NUM_TEXT_STAMPS; idx++){
133                 memset(Emp_wacky_text[idx].str, 0, EMP_WACKY_TEXT_LEN);
134                 Emp_wacky_text[idx].stamp = -1;
135         }
136 }
137
138 // apply the EMP effect to all relevant ships
139 void emp_apply(vector *pos, float inner_radius, float outer_radius, float emp_intensity, float emp_time)
140 {       
141         float actual_intensity, actual_time;
142         vector dist;
143         float dist_mag;
144         float scale_factor;
145         object *target;
146         ship_obj *so;
147         missile_obj *mo;
148         ship_subsys *moveup;
149         weapon_info *wip_target;
150
151         // all machines check to see if the blast hit a bomb. if so, shut it down (can't move anymore)  
152         for( mo = GET_FIRST(&Missile_obj_list); mo != END_OF_LIST(&Missile_obj_list); mo = GET_NEXT(mo) ) {
153                 target = &Objects[mo->objnum];
154                 if(target->type != OBJ_WEAPON){
155                         continue;
156                 }
157
158                 Assert(target->instance >= 0);
159                 if(target->instance < 0){
160                         continue;
161                 }
162                 Assert(Weapons[target->instance].weapon_info_index >= 0);
163                 if(Weapons[target->instance].weapon_info_index < 0){
164                         continue;
165                 }
166                 
167                 // if we have a bomb weapon
168                 wip_target = &Weapon_info[Weapons[target->instance].weapon_info_index];
169                 if(wip_target->wi_flags & WIF_BOMB){
170                         // get the distance between the detonation and the target object
171                         vm_vec_sub(&dist, &target->pos, pos);
172                         dist_mag = vm_vec_mag(&dist);
173
174                         // if the bomb was within 1/4 of the outer radius, castrate it
175                         if(dist_mag <= (outer_radius * 0.25f)){
176                                 // memset(&target->phys_info, 0, sizeof(physics_info));
177                                 Weapons[target->instance].weapon_flags |= WF_DEAD_IN_WATER;
178                                 mprintf(("EMP killing bomb\n"));
179                         }
180                 }       
181         }
182
183         // if I'm only a client in a multiplayer game, do nothing
184         if(MULTIPLAYER_CLIENT){
185                 return;
186         }
187
188         // See if there are any friendly ships present, if so return without preventing msg
189         for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {          
190                 target = &Objects[so->objnum];
191                 if(target->type != OBJ_SHIP){
192                         continue;
193                 }       
194                 
195                 Assert(Objects[so->objnum].instance >= 0);
196                 if(Objects[so->objnum].instance < 0){
197                         continue;
198                 }
199                 Assert(Ships[Objects[so->objnum].instance].ship_info_index >= 0);
200                 if(Ships[Objects[so->objnum].instance].ship_info_index < 0){
201                         continue;
202                 }
203
204                 // if the ship is a cruiser or cap ship, only apply the EMP effect to turrets
205                 if(Ship_info[Ships[target->instance].ship_info_index].flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP)){
206                         // void ship_subsys_set_disrupted(ship_subsys *ss, int time)
207                         moveup = &Ships[target->instance].subsys_list;
208                         if(moveup->next != NULL){
209                                 moveup = moveup->next;
210                         }
211                         while(moveup != &Ships[target->instance].subsys_list){
212                                 // if this is a turret, disrupt it
213                                 if((moveup->system_info != NULL) && (moveup->system_info->type == SUBSYSTEM_TURRET)){
214                                         vector actual_pos;                                      
215                                         
216                                         // get the distance to the subsys                                       
217                                         vm_vec_unrotate(&actual_pos, &moveup->system_info->pnt, &target->orient);
218                                         vm_vec_add2(&actual_pos, &target->pos);                                 
219                                         vm_vec_sub(&dist, &actual_pos, pos);
220                                         dist_mag = vm_vec_mag(&dist);
221                         
222                                         // if for some reason, the object was outside the blast, radius
223                                         if(dist_mag > outer_radius){                    
224                                                 // next item
225                                                 moveup = moveup->next;
226                                                 continue;
227                                         }
228
229                                         // compute a scale factor for the emp effect
230                                         scale_factor = 1.0f;
231                                         if(dist_mag >= inner_radius){
232                                                 scale_factor = 1.0f - (dist_mag / outer_radius);
233                                         } 
234                                         
235                                         // disrupt the turret
236                                         ship_subsys_set_disrupted(moveup, (int)(MAX_TURRET_DISRUPT_TIME * scale_factor));
237
238                                         mprintf(("EMP disrupting subsys %s on ship %s (%f, %f)\n", moveup->system_info->name, Ships[Objects[so->objnum].instance].ship_name, scale_factor, MAX_TURRET_DISRUPT_TIME * scale_factor));
239                                 }
240                                 
241                                 // next item
242                                 moveup = moveup->next;
243                         }
244                 }
245                 // otherwise coat the whole ship with the effect. mmmmmmmmm.
246                 else {                          
247                         // get the distance between the detonation and the target object
248                         vm_vec_sub(&dist, &target->pos, pos);
249                         dist_mag = vm_vec_mag(&dist);
250
251                         // if for some reason, the object was outside the blast, radius
252                         if(dist_mag > outer_radius){                    
253                                 continue;
254                         }
255
256                         // compute a scale factor for the emp effect
257                         scale_factor = 1.0f;
258                         if(dist_mag >= inner_radius){
259                                 scale_factor = 1.0f - (dist_mag / outer_radius);
260                                 actual_intensity = emp_intensity * scale_factor;
261                                 actual_time = emp_time * scale_factor;          
262                         } 
263                 
264                         // calculate actual EMP effect values
265                         actual_intensity = emp_intensity * scale_factor;
266                         actual_time = emp_time * scale_factor;                  
267                         mprintf(("EMP effect s : %f, i : %f, t : %f\n", scale_factor, actual_intensity, actual_time));
268
269                         // if this effect happened to be on me, start it now
270                         if((target == Player_obj) && !(Game_mode & GM_STANDALONE_SERVER)){
271                                 emp_start_local(actual_intensity, actual_time);
272                         } 
273
274                         // if this is a multiplayer game, notify other players of the effect
275                         if(Game_mode & GM_MULTIPLAYER){         
276                                 Assert(MULTIPLAYER_MASTER);                             
277                                 send_emp_effect(target->net_signature, actual_intensity, actual_time);
278                         }
279                         
280                         // now be sure to start the emp effect for the ship itself
281                         emp_start_ship(target, actual_intensity, actual_time);
282                 }
283         }
284 }
285
286 // start the emp effect for the passed ship (setup lightning arcs, timestamp, etc)
287 // NOTE : if this ship is also me, I should call emp_start_local() as well
288 void emp_start_ship(object *ship_obj, float intensity, float time)
289 {
290         ship *shipp;
291         ai_info *aip;
292         float start_intensity;
293
294         // make sure this is a ship
295         Assert(ship_obj->type == OBJ_SHIP);
296         Assert(ship_obj->instance >= 0);
297         shipp = &Ships[ship_obj->instance];
298
299         // determining pre-existing EMP intensity (if any)
300         start_intensity = shipp->emp_intensity < 0.0f ? 0.0f : shipp->emp_intensity;
301
302         // setup values (capping them if necessary)     (make sure that we un-normalize start_intensity)
303         if(intensity + (start_intensity * EMP_INTENSITY_MAX) >= EMP_INTENSITY_MAX){
304                 intensity = EMP_INTENSITY_MAX - 1.0f;
305         } else {
306                 intensity += (start_intensity * EMP_INTENSITY_MAX);
307         }
308         intensity /= EMP_INTENSITY_MAX;
309
310         if(time >= EMP_TIME_MAX){
311                 time = EMP_TIME_MAX - 0.1f;
312         }
313         shipp->emp_intensity = intensity;
314         shipp->emp_decr = intensity / time;
315
316         // multiplayer clients should bail now
317         if(MULTIPLAYER_CLIENT){
318                 return;
319         }
320
321         // do any initial AI effects
322         Assert(shipp->ai_index >= 0);
323         aip = &Ai_info[shipp->ai_index];
324
325         // lose his current target
326         set_target_objnum(aip, -1);
327         set_targeted_subsys(aip, NULL, -1);
328 }
329
330 // process a ship for this frame
331 int mod_val = 7;
332 void emp_process_ship(ship *shipp)
333 {
334         object *objp;
335         ai_info *aip;   
336
337         Assert(shipp != NULL);
338         if(shipp == NULL){
339                 return;
340         }
341         Assert(shipp->objnum >= 0);
342         if(shipp->objnum < 0){
343                 return;
344         }
345         objp = &Objects[shipp->objnum];
346
347         // if the emp intensity is < 0, there is no effect
348         if(shipp->emp_intensity < 0.0f){
349                 shipp->emp_intensity = -1.0f;
350
351                 return;
352         }
353
354         // reduce the emp effect
355         shipp->emp_intensity -= shipp->emp_decr * flFrametime;
356
357         // multiplayer clients should bail here
358         if(MULTIPLAYER_CLIENT){
359                 return;
360         }
361
362         // if this is a player ship, don't do anything wacky
363         if(objp->flags & OF_PLAYER_SHIP){
364                 return;
365         }
366
367         // lose lock time, etc, etc.
368         Assert(shipp->ai_index >= 0);
369         aip = &Ai_info[shipp->ai_index];        
370         aip->aspect_locked_time = 0.0f;                         // hasn't gotten aspect lock at all
371         aip->current_target_is_locked = 0;                      // isn't locked on his current target
372         aip->ai_flags &= ~AIF_SEEK_LOCK;
373         aip->nearest_locked_object = -1;                                // nothing near me, so I won't launch countermeasures
374
375         // if he's not a fighter or bomber, bail now
376         if(!(Ship_info[shipp->ship_info_index].flags & (SIF_FIGHTER | SIF_BOMBER))){
377                 return;
378         }
379         
380         // pick targets randomly and wackily so that the ship flies crazily :)  
381         if(((int)f2fl(Missiontime) + (int)(EMP_INTENSITY_MAX * shipp->emp_intensity)) % mod_val == 0){
382                 int team_lookup = TEAM_FRIENDLY;
383                 int ship_lookup;
384                 switch(shipp->team){
385                 case TEAM_HOSTILE:
386                         team_lookup = TEAM_FRIENDLY;
387                         break;
388                 case TEAM_NEUTRAL: case TEAM_FRIENDLY:
389                         team_lookup = TEAM_HOSTILE;
390                         break;
391                 }
392                 ship_lookup = ship_get_random_team_ship(team_lookup);
393
394                 // if we got a valid ship object to target
395                 if((ship_lookup >= 0) && (Ships[ship_lookup].objnum >= 0)){
396                         if(shipp->team == TEAM_HOSTILE){
397                                 mprintf(("EMP random target select\n"));
398                         }
399
400                         // attack the object
401                         ai_attack_object(objp, &Objects[Ships[ship_lookup].objnum], 89, NULL);
402                 }
403         }
404 }
405
406 // start the emp effect for MYSELF (intensity == arbitrary intensity variable, time == time the effect will last)
407 // NOTE : time should be in seconds
408 void emp_start_local(float intensity, float time)
409 {
410         int idx;
411         float start_intensity;
412
413         // determine pre-existing EMP intensity (if any)
414         start_intensity = Emp_intensity < 0.0f ? 0.0f : Emp_intensity;
415
416         // cap all values (make sure that we un-normalize start_intensity)
417         if(intensity + (start_intensity * EMP_INTENSITY_MAX) >= EMP_INTENSITY_MAX){
418                 intensity = EMP_INTENSITY_MAX - 1.0f;
419         } else {
420                 intensity += (start_intensity * EMP_INTENSITY_MAX);
421         }
422         if(time >= EMP_TIME_MAX){
423                 time = EMP_TIME_MAX - 0.1f;
424         }
425
426         // setup all vars
427         Emp_intensity = intensity / EMP_INTENSITY_MAX;  
428
429         // lose my current target if any
430         if(Player_ai != NULL){
431                 Player_ai->target_objnum = -1;
432         }
433         // lose any lock we have or are getting
434         hud_lock_reset();
435
436         // reset HUD gauge text wackiness stuff
437         for(idx=0; idx<NUM_TEXT_STAMPS; idx++){
438                 memset(Emp_wacky_text[idx].str, 0, 256);
439                 Emp_wacky_text[idx].stamp = -1;
440         }
441
442         // start the emp icon flashing
443         hud_start_text_flash(NOX("Emp"), 5000);
444
445         // determine how much we have to decrement the effect per second
446         Emp_decr = Emp_intensity / time;
447
448         // play a flash
449         game_flash( 1.0f, 1.0f, 0.5f );
450 }
451
452 // stop the emp effect cold
453 void emp_stop_local()
454 {
455         // kill off various EMP stuff
456         Emp_intensity = -1.0f;  
457         Emp_wacky_target_timestamp = -1;        
458 }
459
460 // if the EMP effect is active
461 int emp_active_local()
462 {
463         return EMP_ACTIVE_LOCAL();
464 }
465
466 // process some stuff every frame (before frame is rendered)
467 void emp_process_local()
468 {       
469         if(!emp_active_local()){
470                 return;
471         }
472
473         // decrement the intensity a bit
474         Emp_intensity -= (flFrametime * Emp_decr);      
475
476         // see if we should choose a random target
477         if((Emp_wacky_target_timestamp == -1) || timestamp_elapsed(Emp_wacky_target_timestamp)){
478                 // choose a target (if not the "first" time)
479                 if(Emp_wacky_target_timestamp != -1){
480                         hud_target_random_ship();
481                 }
482
483                 // reset the timestamp
484                 Emp_wacky_target_timestamp = timestamp((int)frand_range(100.0f, 750.0f * (1.0f - Emp_intensity)));
485         }                       
486 }
487
488 // randomly say yes or no to a gauge, if emp is not active, always say yes
489 int emp_should_blit_gauge()
490 {
491         // if the EMP effect is not active, always blit
492         if(!emp_active_local()){
493                 return 1;
494         }
495
496         // otherwise, randomly say no
497         return frand_range(0.0f, 1.0f) > Emp_intensity;
498 }
499
500 // emp hud string
501 void emp_hud_string(int x, int y, int gauge_id, char *str)
502 {
503         char tmp[256] = "";
504
505         // copy the string
506         strcpy(tmp, str);
507
508         // if the emp effect is not active, don't even bother messing with the text
509         if(emp_active_local()){
510                 emp_maybe_reformat_text(tmp, 256, gauge_id);
511
512                 // jitter the coords
513                 emp_hud_jitter(&x, &y);
514         }
515
516         // print the string out
517         gr_string(x, y, tmp);
518 }
519
520 // emp hud printf
521 void emp_hud_printf(int x, int y, int gauge_id, char *format, ...)
522 {
523         char tmp[256] = "";
524         va_list args;   
525         
526         // format the text
527         va_start(args, format);
528         vsprintf(tmp, format, args);
529         va_end(args);
530         
531         // if the emp effect is not active, don't even bother messing with the text
532         if(emp_active_local()){
533                 emp_maybe_reformat_text(tmp, 256, gauge_id);
534
535                 // jitter the coords
536                 emp_hud_jitter(&x, &y);
537         }
538
539         // print the string out
540         gr_string(x, y, tmp);
541 }
542
543 // maybe reformat a string 
544 void emp_maybe_reformat_text(char *text, int max_len, int gauge_id)
545 {
546         wacky_text *wt;
547
548         // if the EMP effect is not active, never reformat it
549         if(!emp_active_local()){
550                 return;
551         }
552
553         // randomly _don't_ apply text craziness
554         if(frand_range(0.0f, 1.0f) > Emp_intensity){
555                 return;
556         }
557
558         // if the gauge is EG_NULL, empty the string
559         if(gauge_id == EG_NULL){
560                 strcpy(text, "");
561                 return;
562         }
563
564         // if this gauge has not been wacked out, or if the timestamp has expired, we
565         // neeed to wack it out again
566         Assert((gauge_id >= EG_NULL) && (gauge_id < NUM_TEXT_STAMPS));
567         wt = &Emp_wacky_text[gauge_id];
568         if((wt->stamp == -1) || timestamp_elapsed(wt->stamp)){
569                 // reformat specific gauges differently
570                 switch(gauge_id){       
571                 //      weapons
572                 case EG_WEAPON_TITLE: case EG_WEAPON_P1: case EG_WEAPON_P2: case EG_WEAPON_P3: case EG_WEAPON_S1: case EG_WEAPON_S2:                    
573                         int wep_index;
574                         wep_index = (int)frand_range(0.0f, (float)(MAX_WEAPON_TYPES - 1));
575                         strcpy(wt->str, Weapon_info[ wep_index >= MAX_WEAPON_TYPES ? 0 : wep_index ].name);                     
576                         break;          
577
578                 // escort list
579                 case EG_ESCORT1: case EG_ESCORT2: case EG_ESCORT3:
580                         // choose a random ship
581                         int shipnum;
582                         shipnum = ship_get_random_ship();
583                         if(shipnum >= 0){
584                                 strcpy(wt->str, Ships[shipnum].ship_name);
585                         }
586                         break;
587
588                 // directives title
589                 case EG_OBJ_TITLE:
590                         strcpy(wt->str, "");
591                         break;
592
593                 // directives themselves
594                 case EG_OBJ1: case EG_OBJ2: case EG_OBJ3: case EG_OBJ4: case EG_OBJ5:
595                         strcpy(wt->str, text);
596                         emp_randomize_chars(wt->str);
597                         break;
598
599                 // target box info
600                 case EG_TBOX_EXTRA1: case EG_TBOX_EXTRA2: case EG_TBOX_EXTRA3: case EG_TBOX_CLASS:
601                 case EG_TBOX_DIST: case EG_TBOX_CARGO: case EG_TBOX_HULL: case EG_TBOX_NAME: case EG_TBOX_INTEG:
602                         strcpy(wt->str, text);
603                         emp_randomize_chars(wt->str);
604                         break;
605
606                 // squadmsg menu
607                 case EG_SQ1: case EG_SQ2: case EG_SQ3: case EG_SQ4: case EG_SQ5: case EG_SQ6: case EG_SQ7:
608                 case EG_SQ8: case EG_SQ9: case EG_SQ10:
609                         strcpy(wt->str, text);
610                         emp_randomize_chars(wt->str);
611                         break;
612                         
613                 // default 
614                 default :
615                         return;
616                 }
617
618                 // recalculate the timestamp
619                 wt->stamp = timestamp((int)frand_range(100.0f, 750.0f * (1.0f - Emp_intensity)));
620
621                 // copy the text
622                 strcpy(text, wt->str);
623         }
624         // otherwise, use what we calculated last time
625         else {
626                 strcpy(text, wt->str);
627         }
628 }
629
630 // randomize the chars in a string
631 void emp_randomize_chars(char *str)
632 {       
633         int idx;
634         int char_index;
635         
636         // shuffle chars around
637         for(idx=0; idx<(int)(strlen(str)-1); idx++){
638                 if(frand_range(0.0f, 1.0f) < Emp_intensity){
639                         char_index = Emp_random_char[(int)frand_range(0.0f, (float)(NUM_RANDOM_CHARS - 1))];
640                         str[idx] = Emp_random_char[char_index];
641                 }
642         }
643 }
644
645 // throw some jitter into HUD x and y coords
646 void emp_hud_jitter(int *x, int *y)
647 {
648         // if the emp effect is not active, don't jitter anything
649         if(!emp_active_local()){
650                 return;
651         }
652
653         // some movement
654         *x += (int)frand_range(-8.0f * Emp_intensity, 8.0f * Emp_intensity);
655         *y += (int)frand_range(-8.0f * Emp_intensity, 8.0f * Emp_intensity);
656 }
657
658 // current intensity of the EMP effect (0.0 - 1.0)
659 float emp_current_intensity()
660 {
661         return Emp_intensity;
662 }
663
664 DCF(zap, "zap a ship with an EMP effect")
665 {
666         int shipnum;
667
668         dc_get_arg(ARG_STRING);
669         if(Dc_arg_type & ARG_STRING){
670                  shipnum = ship_name_lookup(Dc_arg, 1);
671
672                  if(shipnum >= 0){
673                         emp_start_ship(&Objects[Ships[shipnum].objnum], 500.0f, 10.0f);
674                  }
675         }
676 }