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