]> icculus.org git repositories - taylor/freespace2.git/blob - src/hud/hudsquadmsg.cpp
Initial revision
[taylor/freespace2.git] / src / hud / hudsquadmsg.cpp
1 /*
2  * $Logfile: /Freespace2/code/Hud/HUDsquadmsg.cpp $
3  * $Revision$
4  * $Date$
5  * $Author$
6  *
7  * File to control sqaudmate messaging
8  *
9  * $Log$
10  * Revision 1.1  2002/05/03 03:28:09  root
11  * Initial revision
12  *
13  * 
14  * 16    9/06/99 10:45a Andsager
15  * Add freighter to player override of protected status.
16  * 
17  * 15    9/06/99 10:32a Andsager
18  * Allow attack of protected fighter, bomber, freighters, by player's
19  * orders.
20  * 
21  * 14    8/26/99 8:51p Dave
22  * Gave multiplayer TvT messaging a heavy dose of sanity. Cheat codes.
23  * 
24  * 13    7/30/99 10:31p Dave
25  * Added comm menu to the configurable hud files.
26  * 
27  * 12    7/09/99 5:54p Dave
28  * Seperated cruiser types into individual types. Added tons of new
29  * briefing icons. Campaign screen.
30  * 
31  * 11    6/16/99 10:20a Dave
32  * Added send-message-list sexpression.
33  * 
34  * 10    6/09/99 9:53a Andsager
35  * 1st pass at grey menu items when no ships/wings/fighters accepting
36  * orders.
37  * 
38  * 9     4/23/99 12:01p Johnson
39  * Added SIF_HUGE_SHIP
40  * 
41  * 8     4/16/99 5:54p Dave
42  * Support for on/off style "stream" weapons. Real early support for
43  * target-painting lasers.
44  * 
45  * 7     3/30/99 5:40p Dave
46  * Fixed reinforcements for TvT in multiplayer.
47  * 
48  * 6     3/28/99 5:58p Dave
49  * Added early demo code. Make objects move. Nice and framerate
50  * independant, but not much else. Don't use yet unless you're me :)
51  * 
52  * 5     1/07/99 9:07a Jasen
53  * HUD coords
54  * 
55  * 4     12/28/98 3:17p Dave
56  * Support for multiple hud bitmap filenames for hi-res mode.
57  * 
58  * 3     12/21/98 5:02p Dave
59  * Modified all hud elements to be multi-resolution friendly.
60  * 
61  * 2     10/07/98 10:53a Dave
62  * Initial checkin.
63  * 
64  * 1     10/07/98 10:49a Dave
65  * 
66  * 198   9/11/98 2:05p Allender
67  * make reinforcements work correctly in multiplayer games.  There still
68  * may be a team vs team issue that I haven't thought of yet :-(
69  * 
70  * 197   8/28/98 3:28p Dave
71  * EMP effect done. AI effects may need some tweaking as required.
72  * 
73  * 196   8/25/98 1:48p Dave
74  * First rev of EMP effect. Player side stuff basically done. Next comes
75  * AI code.
76  * 
77  * 195   6/30/98 2:17p Dave
78  * Revised object update system. Removed updates for all weapons. Put
79  * button info back into control info packet.
80  * 
81  * 194   6/09/98 10:31a Hoffoss
82  * Created index numbers for all xstr() references.  Any new xstr() stuff
83  * added from here on out should be added to the end if the list.  The
84  * current list count can be found in FreeSpace.cpp (search for
85  * XSTR_SIZE).
86  * 
87  * 193   5/26/98 11:54a Allender
88  * fix multiplayer problems and sexpression crash
89  * 
90  * 192   5/24/98 4:27p Allender
91  * fix bug when determine who could message in multiplayer
92  * 
93  * 191   5/23/98 2:34a Lawrance
94  * Fix problems with HUD squad messaging, don't save/restore bindings
95  * 
96  * 190   5/22/98 12:41a Allender
97  * don't save/restore key presses in comm menu
98  * 
99  * 189   5/21/98 9:38p Allender
100  * don't save/clear key bindings
101  * 
102  * 188   5/21/98 3:32p Allender
103  * don't allow comm menu in observer mode
104  * 
105  * 187   5/19/98 12:19p Mike
106  * Cheat codes!
107  * 
108  * 186   5/18/98 10:08a Lawrance
109  * increase MSG_KEY_EAT_TIME to 300ms
110  * 
111  * 185   5/18/98 12:41a Allender
112  * fixed subsystem problems on clients (i.e. not reporting properly on
113  * damage indicator).  Fixed ingame join problem with respawns.  minor
114  * comm menu stuff
115  * 
116  * 184   5/13/98 5:08p Allender
117  * fix code in which sometimes wings wouldn't respond in multiplayer when
118  * doing a message all fighters
119  * 
120  * 183   5/08/98 4:38p Allender
121  * always allow player ships to count when counting fighters for
122  * messaging.  Terran command will now always issue the shooting at
123  * friendlies message
124  * 
125  * 182   5/08/98 2:11p Mike
126  * Add "/Repair Subsys" to "Rearm" option in Comm menu.
127  * 
128  * 181   5/06/98 2:57p Allender
129  * always allow rearm ship to be called in
130  * 
131  * 180   5/05/98 2:04a Mike
132  * Fix bug in support ship code.
133  * 
134  * 179   5/05/98 1:41a Mike
135  * Improve support ship availability.
136  * 
137  * 178   5/04/98 12:59a Allender
138  * players who are traitors shouldn't be allowed to rearm or use messaging
139  * shortcuts
140  * 
141  * 177   5/04/98 12:39a Allender
142  * make page up and page down only active when > 10 items on menu
143  * 
144  * 176   4/29/98 10:56p Allender
145  * don't allow shortcuts in mutliplayer when player cannot message (except
146  * for rearm repair)
147  * 
148  * 175   4/23/98 10:06a Allender
149  * don't use the word "player" in event log for rearm event.  Send
150  * shipname instead (players only)
151  * 
152  * 174   4/23/98 9:15a Allender
153  * make rearm shortcut work for clients
154  * 
155  * 173   4/23/98 1:49a Allender
156  * major rearm/repair fixes for multiplayer.  Fixed respawning of AI ships
157  * to not respawn until 5 seconds after they die.  Send escort information
158  * to ingame joiners
159  * 
160  * 172   4/22/98 4:59p Allender
161  * new multiplayer dead popup.  big changes to the comm menu system for
162  * team vs. team.  Start of debriefing stuff for team vs. team  Make form
163  * on my wing work with individual ships who have high priority orders
164  * 
165  * 171   4/21/98 12:15a Allender
166  * don't allow observers to use shortcut messaging keys
167  * 
168  * 170   4/20/98 12:36a Mike
169  * Make team vs. team work when player is hostile.  Several targeting
170  * problems.
171  * 
172  * 169   4/13/98 12:51p Allender
173  * made countermeasure succeed indicator work in multiplayer.  Make rearm
174  * shortcut work more appropriately.
175  * 
176  * 168   4/10/98 2:42p Johnson
177  * (from allender)  when sending wing command, don't assert if ship to
178  * send message not found -- don't send message.  Allow rearm message
179  * shortcut even if comm destroyed
180  * 
181  * 167   4/10/98 2:39p Johnson
182  * 
183  * 166   4/10/98 12:47p Allender
184  * changed working on replay popup.  Don't reference repair in comm menu.
185  * Added Shift-R for repair me
186  * 
187  * 165   4/09/98 12:35p Allender
188  * disallow messaging to departing wings and departing/dying ships
189  * 
190  * 164   4/08/98 4:06p Allender
191  * make selection of wing Player team based, not TEAM_FRIENDLY.
192  * 
193  * 163   4/07/98 5:30p Lawrance
194  * Player can't send/receive messages when comm is destroyed.  Garble
195  * messages when comm is damaged.
196  * 
197  * 162   4/07/98 1:53p Lawrance
198  * Fix uninitialized data bug.
199  * 
200  * 161   4/06/98 12:11a Allender
201  * prevent the comm menu keys from being held over after menu goes away
202  * 
203  * 160   4/05/98 3:06p Allender
204  * don't allow ships/wings to act on orders which they shouldn't receive
205  * 
206  * 159   4/03/98 12:17a Allender
207  * new sexpression to detect departed or destroyed.  optionally disallow
208  * support ships.  Allow docking with escape pods 
209  * 
210  * 158   4/02/98 5:50p Dave
211  * Put in support for standard comm messages to get sent to netplayers as
212  * well as ai ships. Make critical button presses not get evaluated on the
213  * observer.
214  *
215  * $NoKeywords: $
216 */
217  
218
219 #include "freespace.h"
220 #include "2d.h"
221 #include "hud.h"
222 #include "ship.h"
223 #include "player.h"
224 #include "key.h"
225 #include "hudtarget.h"
226 #include "timer.h"
227 #include "hudsquadmsg.h"
228 #include "controlsconfig.h"
229 #include "parselo.h"
230 #include "aigoals.h"
231 #include "missionparse.h"
232 #include "sexp.h"
233 #include "linklist.h"
234 #include "missionlog.h"
235 #include "missionmessage.h"
236 #include "hudtarget.h"
237 #include "gamesnd.h"
238 #include "sound.h"
239 #include "missionparse.h"
240 #include "multimsgs.h"
241 #include "multiutil.h"
242 #include "bmpman.h"
243 #include "hudtargetbox.h"
244 #include "multi_pmsg.h"
245 #include "subsysdamage.h"
246 #include "emp.h"
247
248 // defines for different modes in the squad messaging system
249
250 #define SM_MODE_TYPE_SELECT                     1               //am I going to message a ship or a wing
251 #define SM_MODE_SHIP_SELECT                     2               //choosing actual ship
252 #define SM_MODE_WING_SELECT                     3               //choosing actual wing
253 #define SM_MODE_SHIP_COMMAND                    4               //which command to send to a ship
254 #define SM_MODE_WING_COMMAND                    5               //which command to send to a wing
255 #define SM_MODE_REINFORCEMENTS          6               //call for reinforcements
256 #define SM_MODE_REPAIR_REARM                    7               //repair/rearm player ship
257 #define SM_MODE_REPAIR_REARM_ABORT      8               //abort repair/rearm of player ship
258 #define SM_MODE_ALL_FIGHTERS                    9               //message all fighters/bombers
259
260 #define DEFAULT_MSG_TIMEOUT             (8 * 1000)              // number of seconds * 1000 to get milliseconds
261 #define MSG_KEY_EAT_TIME                        (300)
262
263 LOCAL int Squad_msg_mode;                                                       // current mode that the messaging system is in
264 LOCAL int Msg_key_used;                                                         // local variable which tells if the key being processed
265                                                                                                                         // with the messaging system was actually used
266 LOCAL int Msg_key;                                                                      // global which indicates which key was currently pressed
267 LOCAL int Msg_mode_timestamp;
268 LOCAL int Msg_instance;                                         // variable which holds ship/wing instance to send the message to
269 LOCAL int Msg_shortcut_command;                 // holds command when using a shortcut key
270 LOCAL int Msg_target_objnum;                            // id of the current target of the player
271 LOCAL ship_subsys *Msg_targeted_subsys;// pointer to current subsystem which is targeted
272 //#ifndef NDEBUG
273 LOCAL   int Msg_enemies;                                                // tells us whether or not to message enemy ships or friendlies
274 //#endif
275
276 LOCAL int Msg_eat_key_timestamp;                        // used to temporarily "eat" keys
277
278 // defined to position the messaging box
279 int Mbox_item_h[GR_NUM_RESOLUTIONS] = {
280         10, 
281         10
282 };
283 int Mbox_item_xoffset[GR_NUM_RESOLUTIONS] = {
284         17,
285         17
286 };
287
288 // top of the message box gauge
289 int Mbox_top_coords[GR_NUM_RESOLUTIONS][2] = {
290         { // GR_640
291                 445, 5
292         },
293         { // GR_1024
294                 827, 5
295         }
296 };
297
298 int Mbox_bmap_coords[GR_NUM_RESOLUTIONS][2] = {
299         { // GR_640
300                 445, 17
301         },
302         { // GR_1024
303                 827, 17
304         }
305 };
306
307 // squadmsg menu pgup and pgdn
308 int Menu_pgup_coords[GR_NUM_RESOLUTIONS][2] = {
309         { // GR_640
310                 590, 9
311         },
312         { // GR_1024
313                 937, 9
314         }
315 };
316 int Menu_pgdn_coords[GR_NUM_RESOLUTIONS][2] = {
317         { // GR_640
318                 590, 120
319         },
320         { // GR_1024
321                 937, 120
322         }
323 };
324
325 // -----------
326 // following defines/vars are used to build menus that are used in messaging mode
327
328 typedef struct mmode_item {
329         int     instance;                                       // instance in Ships/Wings array of this menu item
330         int     active;                                         // active items are in bold text -- inactive items greyed out
331         char    text[NAME_LENGTH];              // text to display on the menu
332 } mmode_item;
333
334 #define MAX_MENU_ITEMS          50                              // max number of items in the menu
335 #define MAX_MENU_DISPLAY        10                              // max number that can be displayed
336
337 mmode_item MsgItems[MAX_MENU_ITEMS];
338 int Num_menu_items = -1;                                        // number of items for a message menu
339 int First_menu_item= -1;                                                        // index of first item in the menu
340
341 // -----------
342 // following set of vars/defines are used to store/restore key bindings for keys that
343 // are used in messaging mode
344
345 // array to temporarily store key bindings that will be in use for the messaging
346 // system
347 typedef struct key_store {
348         int     option_num;                                     // which element in the Control_config array is this
349         int     id;                                                     // which id (1 or 2) is this key.
350         int     key_value;                                      // which key value to put there.
351 } key_store;
352
353 #define MAX_KEYS_NO_SCROLL      10
354 #define MAX_KEYS_USED           12              // maximum number of keys used for the messaging system
355
356 key_store key_save[MAX_KEYS_USED];              // array to save the key information during messaging mode
357 int num_keys_saved = 0;                                 // number of keys that are saved.
358
359 // next array is the array of MAX_KEYS_USED size which are the keys to use for messaging mode
360
361 int keys_used[] = {     KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, KEY_0,
362                                                         KEY_PAGEUP, KEY_PAGEDOWN  };
363
364 #define ID1             1
365 #define ID2             2
366
367 // following are defines and character strings that are used as part of messaging mode
368
369 #define TYPE_SHIP_ITEM                                          0
370 #define TYPE_WING_ITEM                                          1
371 #define TYPE_ALL_FIGHTERS_ITEM                  2
372 #define TYPE_REINFORCEMENT_ITEM                 3
373 #define TYPE_REPAIR_REARM_ITEM                  4
374 #define TYPE_REPAIR_REARM_ABORT_ITEM    5
375
376 #define NUM_TYPE_SELECT         6
377
378 char *type_select_str(int n)
379 {
380         #if NUM_TYPE_SELECT != 6 
381         #error type_select_Str is not up to date
382         #endif
383
384         switch(n)       {
385         case TYPE_SHIP_ITEM:
386                 return XSTR( "Ships", 293);
387         case TYPE_WING_ITEM:
388                 return XSTR( "Wings", 294);
389         case TYPE_ALL_FIGHTERS_ITEM:
390                 return XSTR( "All Fighters", 295);
391         case TYPE_REINFORCEMENT_ITEM:
392                 return XSTR( "Reinforcements", 296);
393         case TYPE_REPAIR_REARM_ITEM:
394                 return XSTR( "Rearm/Repair Subsys", 297);
395         case TYPE_REPAIR_REARM_ABORT_ITEM:
396                 return XSTR( "Abort Rearm", 298);
397         }
398         
399         return NULL;    
400 }
401
402 // data structure to hold character string of commands for comm menu
403 typedef struct comm_order {
404         int     value;                          // used to match which command to display on the menu
405 } comm_order;
406
407 // note: If you change this table at all, keep it in sync with version in IgnoreOrdersDlg.cpp
408 // Also make sure you update comm_order_menu_text below this.
409 // Also make sure you update MAX_SHIP_ORDERS in HUDsquadmsg.h
410 comm_order Comm_orders[MAX_SHIP_ORDERS] = {
411         ATTACK_TARGET_ITEM,
412         DISABLE_TARGET_ITEM,
413         DISARM_TARGET_ITEM,
414         DISABLE_SUBSYSTEM_ITEM,
415         PROTECT_TARGET_ITEM,
416         IGNORE_TARGET_ITEM,
417         FORMATION_ITEM,
418         COVER_ME_ITEM,
419         ENGAGE_ENEMY_ITEM,
420         CAPTURE_TARGET_ITEM,
421         REARM_REPAIR_ME_ITEM,
422         ABORT_REARM_REPAIR_ITEM,
423         DEPART_ITEM,
424 };
425
426 // Text to display on the menu
427 // Given an index into the Comm_orders array, return the text associated with it.
428 // MUST BE 1:1 with Comm_orders.
429 char    *comm_order_menu_text(int index)
430 {
431         switch( index ) {
432         case 0: return XSTR( "Destroy my target", 299); break;
433         case 1: return XSTR( "Disable my target", 300); break;
434         case 2: return XSTR( "Disarm my target", 301); break;
435         case 3: return XSTR( "Destroy subsystem", 302); break;
436         case 4: return XSTR( "Protect my target", 303); break;
437         case 5: return XSTR( "Ignore my target", 304); break;
438         case 6: return XSTR( "Form on my wing", 305); break;
439         case 7: return XSTR( "Cover me", 306); break;
440         case 8: return XSTR( "Engage enemy", 307); break;
441         case 9: return XSTR( "Capture my target", 308); break;
442         case 10: return XSTR( "Rearm me", 309); break;
443         case 11: return XSTR( "Abort rearm", 310); break;
444         case 12: return XSTR( "Depart", 311); break;
445         default:
446                 Assert(0);
447         }
448         return NULL;
449 }
450
451 // Text to display on the messaging menu when using the shortcut keys
452 char *comm_order_hotkey_text( int index )
453 {
454         int i;
455
456         for (i = 0; i < MAX_SHIP_ORDERS; i++ ) {
457                 if ( Comm_orders[i].value == index )
458                         return comm_order_menu_text(i);
459         }
460
461         Int3();
462         return NULL;
463 }
464
465 // a define of who can receive message
466 #define CAN_MESSAGE     (SIF_FIGHTER | SIF_BOMBER | SIF_CRUISER | SIF_FREIGHTER | SIF_TRANSPORT | SIF_CAPITAL | SIF_SUPPORT | SIF_SUPERCAP | SIF_DRYDOCK | SIF_GAS_MINER | SIF_AWACS | SIF_CORVETTE)
467
468 int squadmsg_history_index = 0;
469 squadmsg_history Squadmsg_history[SQUADMSG_HISTORY_MAX] = { 0 };
470
471 // used for Message box gauge
472 #define NUM_MBOX_FRAMES         3
473
474 static hud_frames Mbox_gauge[NUM_MBOX_FRAMES];
475 static int Mbox_frames_loaded = 0;
476 static char *Mbox_fnames[GR_NUM_RESOLUTIONS][NUM_MBOX_FRAMES] =
477 {
478 //XSTR:OFF
479         { // GR_640
480                 "message1",             // top part of menu
481                 "message2",             // middle part
482                 "message3"              // bottom part
483         }, 
484         { // GR_1024
485                 "message1",             // top part of menu
486                 "message2",             // middle part
487                 "message3"              // bottom part
488         }
489 //XSTR:ON
490 };
491
492 static int Mbox_title_coord[GR_NUM_RESOLUTIONS][2] = {
493         { // GR_640
494                 447, 6
495         },
496         { // GR_1024
497                 829, 6
498         }
499 };
500 static int Mbox_item_coord[GR_NUM_RESOLUTIONS][2] = {
501         { // GR_640
502                 449, 18
503         },
504         { // GR_1024
505                 831, 18
506         }
507 };
508
509 // define for trapping messages send to "all fighters"
510 #define MESSAGE_ALL_FIGHTERS            -999
511
512 // forward declarations
513 void hud_add_issued_order(char *name, int order, char *target);
514 int hud_squadmsg_is_target_order_valid(int order, int find_order, ai_info *aip = NULL );
515 int hud_squadmsg_ship_order_valid( int shipnum, int order );
516
517 // function to set up variables needed when messaging mode is started
518 void hud_squadmsg_start()
519 {
520 //      int i;
521
522         //if ( num_keys_saved < 0 )  // save the keys if they haven't been saved yet
523         hud_squadmsg_save_keys();
524
525         Msg_key = -1;
526
527 /*
528         for (i=0; i<num_keys_saved; i++)
529                 clear_key_binding ( (short) key_save[i].key_value );                            // removes all mention of this key from Control_config
530 */
531
532         Num_menu_items = -1;                                                                                                    // reset the menu items
533         First_menu_item = 0;
534         Squad_msg_mode = SM_MODE_TYPE_SELECT;                                                   // start off at the base state
535         Msg_mode_timestamp = timestamp(DEFAULT_MSG_TIMEOUT);            // initialize our timer to bogus value
536         Msg_shortcut_command = -1;                                                                                      // assume no shortcut key being used
537         Msg_target_objnum = Player_ai->target_objnum;                           // save the players target object number
538         Msg_targeted_subsys = Player_ai->targeted_subsys;                               // save the players currently targted subsystem
539 #ifndef NDEBUG
540         Msg_enemies = 0;                                                                                                                // tells us if we are messaging enemy ships
541 #endif
542
543         snd_play( &Snds[SND_SQUADMSGING_ON] );
544 }
545
546 // functions which will restore all of the key binding stuff when messaging mode is done
547 void hud_squadmsg_end()
548 {
549 /*
550         int i;
551         key_store *ksp;
552
553         // move through all keys saved and restore their orignal values.
554         for ( i=0; i<num_keys_saved; i++ ) {
555                 ksp = &key_save[i];
556                 Control_config[ksp->option_num].key_id = (short) ksp->key_value;
557         }
558 */
559
560         if ( message_is_playing() == FALSE )
561                 snd_play( &Snds[SND_SQUADMSGING_OFF] );
562 }
563
564 // function which returns true if there are fighters/bombers on the players team
565 // in the mission
566 int hud_squadmsg_count_fighters( )
567 {
568         int count;
569         int team;
570         object *objp;
571         ship *shipp;
572
573         // set up the team to compare for messaging.  In debug versions, we will allow messaging to enemies
574         //team = TEAM_FRIENDLY;
575         team = Player_ship->team;
576 #ifndef NDEBUG
577         if ( Msg_enemies )
578                 team = opposing_team_mask(Player_ship->team);
579 #endif
580
581         count = 0;
582         for ( objp = GET_FIRST(&obj_used_list); objp != END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
583                 if ( objp->type != OBJ_SHIP )
584                         continue;
585                 
586                 shipp = &Ships[objp->instance];
587                 // check fighter is accepting orders
588                 if (shipp->orders_accepted != 0) {
589                         // be sure ship is on correct team, not the player, and is a fighter/bomber
590                         if ( (shipp->team == team) && (objp != Player_obj) && (Ship_info[shipp->ship_info_index].flags & (SIF_FIGHTER | SIF_BOMBER)) ) {
591                                 return 1;
592                         }
593                 }
594         }
595
596         return 0;
597 }
598
599
600 // function which counts the number of ships available for messaging.  Used to determine if
601 // we should grey out a menu or allow a shortcut command to apply.  parameter "flag" is used
602 // to tell us whether or not we should add the ship to a menu item or not.  We include the
603 // flag so that we don't have to have conditions for messaging ships/wings in two places.
604 int hud_squadmsg_count_ships( int add_to_menu )
605 {
606         int count;
607         int team;
608         ship *shipp;
609         ship_obj *so;
610
611         // set up the team to compare for messaging.  In debug versions, we will allow messaging to enemies
612         //team = TEAM_FRIENDLY;
613         team = Player_ship->team;
614 #ifndef NDEBUG
615         if ( Msg_enemies )
616                 team = opposing_team_mask(Player_ship->team);
617 #endif
618
619         count = 0;
620         for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
621                 
622                 shipp = &Ships[Objects[so->objnum].instance];
623                 Assert ( shipp->objnum != -1 );
624
625                 // ships must be able to receive a message
626                 if ( !(Ship_info[shipp->ship_info_index].flags & CAN_MESSAGE) )
627                         continue;
628
629                 // must be on the same team
630                 if ( shipp->team != team )
631                         continue;
632
633                 // departing or dying ships cannot be on list
634                 if ( shipp->flags & (SF_DEPARTING|SF_DYING) )
635                         continue;
636
637                 // MULTI - changed to allow messaging of netplayers
638
639                 // cannot be my ship or an instructor
640                 if ( (&Objects[so->objnum] == Player_obj) || is_instructor(&Objects[so->objnum]) )
641                         continue;
642
643                 // ship must be accepting ship type orders
644                 if ( shipp->orders_accepted == 0)
645                         continue;
646
647                 // if it is a player ship, we must be in multiplayer
648                 if ( (Objects[so->objnum].flags & OF_PLAYER_SHIP) && !(Game_mode & GM_MULTIPLAYER) )
649                         continue;
650
651                 // if a messaging shortcut, be sure this ship can process the order
652                 if ( Msg_shortcut_command != -1 ) {
653                         if ( !(shipp->orders_accepted & Msg_shortcut_command) )
654                                 continue;
655                         else if ( !hud_squadmsg_ship_order_valid(Objects[so->objnum].instance, Msg_shortcut_command) )
656                                 continue;
657                 }
658
659                 count++;
660                 if ( add_to_menu ) {
661                         Assert ( Num_menu_items < MAX_MENU_ITEMS );
662                         strcpy( MsgItems[Num_menu_items].text, shipp->ship_name );
663                         MsgItems[Num_menu_items].instance = SHIP_INDEX(shipp);
664                         MsgItems[Num_menu_items].active = 1;
665                         Num_menu_items++;
666
667                 }
668         }
669
670         // if adding to the menu and we have > 10 items, then don't allow page up and page down to be used.
671         if ( add_to_menu && (Num_menu_items > MAX_MENU_DISPLAY) )
672                 hud_squadmsg_save_keys(1);
673         return count;
674 }
675
676 // routine to return true if a wing should be put onto the messaging menu
677 int hud_squadmsg_wing_valid( wing *wingp, int team )
678 {
679         // int player_count, j;
680
681         // a couple of special cases to account for before adding to count (or to menu).  The wing gone
682         // flags is firm indication to skip this particular wing.  Also, skip if enemy wing
683         if ( (wingp->flags  & WF_WING_GONE) || (wingp->current_count == 0) )
684                 return 0;
685
686         // departing wings don't get attention either
687         if ( wingp->flags & WF_WING_DEPARTING )
688                 return 0;
689
690         // sanity check on ship_index field -- if check is successful, then check the team.
691         Assert (wingp->ship_index[0] != -1 );
692         if ( Ships[wingp->ship_index[0]].team != team )
693                 return 0;
694
695         // if this wing is the players wing, and there is only one ship in the wing, then skip past it
696         if ( (Ships[Player_obj->instance].wingnum == WING_INDEX(wingp)) && (wingp->current_count == 1) )
697                 return 0;
698
699         // check if wing commander is accepting orders
700         if ( Ships[wingp->ship_index[0]].orders_accepted == 0)
701                 return 0;
702
703         // if doing a message shortcut is being used, be sure the wing can "accept" the command.  Only need
704         // to look at the first ship in the wing.
705         if ( Msg_shortcut_command != -1 ) {
706                 if ( !(Ships[wingp->ship_index[0]].orders_accepted & Msg_shortcut_command) )
707                         return 0;
708         }
709         // MULTI - changed to allow messaging of netplayers
710         // don't count wings where all ships are player ships           
711         /*
712         player_count = 0;
713         for ( j = 0; j < wingp->current_count; j++ ) {
714                 if ( Objects[Ships[wingp->ship_index[j]].objnum].flags & OF_PLAYER_SHIP )
715                         player_count++;
716         }
717         if ( player_count == wingp->current_count )
718                 return 0;
719         */
720
721         return 1;
722 }
723
724 // function like above, except for wings
725 int hud_squadmsg_count_wings( int add_to_menu )
726 {
727         int count, i, j;
728         int team;
729
730         // set up the team to compare for messaging.  In debug versions, we will allow messaging to enemies
731         //team = TEAM_FRIENDLY;
732         team = Player_ship->team;
733 #ifndef NDEBUG
734         if ( Msg_enemies )
735                 team = opposing_team_mask(Player_ship->team);
736 #endif
737
738         count = 0;
739
740         // add the player starting wings first
741         for ( i = 0; i < MAX_STARTING_WINGS; i++ ) {
742                 int wingnum;
743
744                 wingnum = Starting_wings[i];
745                 if ( wingnum == -1 )
746                         continue;
747
748                 if ( hud_squadmsg_wing_valid(&Wings[wingnum], team) ) {
749                         count++;
750                         if ( add_to_menu ) {
751                                 Assert ( Num_menu_items < MAX_MENU_ITEMS );
752                                 strcpy( MsgItems[Num_menu_items].text, Wings[wingnum].name );
753                                 MsgItems[Num_menu_items].instance = wingnum;
754                                 MsgItems[Num_menu_items].active = 1;
755                                 Num_menu_items++;
756                         }
757                 }
758         }
759
760         for ( i = 0; i < num_wings; i++ ) {
761                 // if this wing is a player starting wing, skip it since we added it above
762                 for ( j = 0; j < MAX_STARTING_WINGS; j++ ) {
763                         if ( i == Starting_wings[j] )
764                                 break;
765                 }
766                 if ( j < MAX_STARTING_WINGS )
767                         continue;
768
769                 if ( hud_squadmsg_wing_valid(&Wings[i], team) ) {
770                         count++;
771                         if ( add_to_menu ) {
772                                 Assert ( Num_menu_items < MAX_MENU_ITEMS );
773                                 strcpy( MsgItems[Num_menu_items].text, Wings[i].name );
774                                 MsgItems[Num_menu_items].instance = i;
775                                 MsgItems[Num_menu_items].active = 1;
776                                 Num_menu_items++;
777                         }
778                 }
779         }
780         return count;
781 }
782
783
784 // function to set the current submode in message mode -- also resets variables that
785 // should be reset inbetween submodes
786 void hud_squadmsg_do_mode( int mode )
787 {
788         Squad_msg_mode = mode;
789         Num_menu_items = -1;
790         First_menu_item = 0;
791 }
792
793 void hud_squadmsg_page_down()
794 {
795         if ( (First_menu_item + MAX_MENU_DISPLAY) < Num_menu_items ) {
796                 First_menu_item += MAX_MENU_DISPLAY;
797                 Assert ( First_menu_item < Num_menu_items );
798         }
799 }
800
801 void hud_squadmsg_page_up()
802 {
803         if ( First_menu_item > 0 ) {
804                 First_menu_item -= MAX_MENU_DISPLAY;
805                 Assert (First_menu_item >= 0 );
806         }
807 }
808
809 int hud_squadmsg_get_total_keys()
810 {
811         int num_keys_used;
812
813         num_keys_used = MAX_KEYS_NO_SCROLL;
814         if ( Num_menu_items > MAX_MENU_DISPLAY )
815                 num_keys_used = MAX_KEYS_USED;
816
817         return num_keys_used;
818 }
819
820 // function called from high level keyboard read code to give the squadmsg code a key.
821 // return 1 is the key was used by the messaging code, 0 otherwise
822 int hud_squadmsg_read_key( int k )
823 {
824         int i, key_found, num_keys_used;
825
826         num_keys_used = hud_squadmsg_get_total_keys();
827
828         if ( !(Player->flags & PLAYER_FLAGS_MSG_MODE) ) {
829                 // check to see if any messaging keys are still down for some length of time
830                 // after messaging is over.  Return true for a while.
831                 if ( !timestamp_elapsed(Msg_eat_key_timestamp) ) {
832                         for (i = 0; i < num_keys_used; i++ ) {
833                                 if ( keyd_pressed[keys_used[i]] )
834                                         return 1;
835                         }
836                 }
837
838                 return 0;
839         }
840
841         key_found = 0;
842         for (i = 0; i < num_keys_used; i++ ) {
843                 if ( k == keys_used[i] ) {
844                         if ( key_down_count(k) ) {
845                                 Msg_key = k;
846                                 key_found = 1;
847                         }
848
849                         if ( keyd_pressed[k] ) {
850                                 key_found = 1;
851                         }
852
853 //                      key_down_count(k);
854                         break;
855                 }
856         }
857
858         if ( key_found )
859                 return 1;
860
861         return 0;
862 }
863
864 // function which reads the keyboard array and determines if a menu key has been hit
865 int hud_squadmsg_get_key()
866 {
867         int k, i, num_keys_used;
868
869         if ( Msg_key == -1 )
870                 return -1;
871
872         k = Msg_key;
873         Msg_key = -1;
874
875         num_keys_used = hud_squadmsg_get_total_keys();
876
877         // if the emp effect is active, never accept keypresses
878         if(emp_active_local()){
879                 return -1;
880         }
881
882         for ( i = 0; i < num_keys_used; i++ ) {
883                 if ( k == keys_used[i] ) {
884                         Msg_key_used = 1;                                               // this variable will extend the timer
885
886                         // use a timestamp to prevent top level key code from possibly reprocessing this key
887                         Msg_eat_key_timestamp = timestamp(MSG_KEY_EAT_TIME);
888                         if ( k == KEY_PAGEDOWN ) {                      // pageup and pagedown scroll the menu -- deal with these seperately!!
889                                 hud_squadmsg_page_down();
890                                 return -1;
891                         } else if ( k == KEY_PAGEUP ) {
892                                 hud_squadmsg_page_up();
893                                 return -1;
894                         } else if ( k == KEY_ESC ) {
895                                 hud_squadmsg_toggle();
896                                 return -1;
897                         } else if ( (i < Num_menu_items) && (Squad_msg_mode == SM_MODE_REINFORCEMENTS) )                // return any key if selecting reinforcement
898                                 return i;
899
900                         // play general fail sound if inactive item hit.
901                         else if ( (i < Num_menu_items) && !(MsgItems[i].active) )
902                                 gamesnd_play_iface(SND_GENERAL_FAIL);
903
904                         else if ( (i < Num_menu_items) && (MsgItems[i].active) )        // only return keys that are associated with menu items
905                                 return i;
906
907                         else {
908                                 Msg_key_used = 0;                                       // if no #-key pressed for visible item, break and allow timer to 
909                                 break;                                                          // to continue as if no key was pressed
910                         }
911                 }
912         }
913
914         return -1;
915 }
916
917 // function which will essentially print out the contents of the current state of the messaging
918 // menu.  Parameters will be a title.  The menu items and the number of items will be
919 // in global vars since they don't get recomputed every frame.
920 void hud_squadmsg_display_menu( char *title )
921 {
922         int bx, by, sx, sy, i, nitems, none_valid, messaging_allowed;
923
924         // hud_set_bright_color();
925         hud_set_gauge_color(HUD_MESSAGE_BOX, HUD_C_BRIGHT);
926         if ( title ) {
927                 gr_string(Mbox_title_coord[gr_screen.res][0], Mbox_title_coord[gr_screen.res][1], title);
928         }
929
930         if ( Num_menu_items < MAX_MENU_DISPLAY )
931                 nitems = Num_menu_items;
932         else {
933                 if ( First_menu_item == 0 )                                     // First_menu_item == 0 means first page of items
934                         nitems = MAX_MENU_DISPLAY;
935                 else if ( (Num_menu_items - First_menu_item) <= MAX_MENU_DISPLAY )      // check if remaining items fit on one page
936                         nitems = Num_menu_items - First_menu_item;
937                 else {
938                         nitems = MAX_MENU_DISPLAY;
939                 }
940         }
941
942         sx = Mbox_item_coord[gr_screen.res][0];
943         sy = Mbox_item_coord[gr_screen.res][1];
944         bx = Mbox_bmap_coords[gr_screen.res][0];        // global x-offset where bitmap gets drawn
945         by = Mbox_bmap_coords[gr_screen.res][1];                // global y-offset where bitmap gets drawn
946
947         none_valid = 1;         // variable to tell us whether all items in the menu are valid or not
948
949         // use another variable to tell us whether we can message or not.
950         messaging_allowed = 1;
951         if ( (Game_mode & GM_MULTIPLAYER) && !multi_can_message(Net_player) ){
952                 messaging_allowed = 0;
953         }
954
955         for ( i = 0; i < nitems; i++ ) {
956                 int item_num;
957                 char *text = MsgItems[First_menu_item+i].text;
958
959                 // blit the background
960                 // hud_set_default_color();
961                 hud_set_gauge_color(HUD_MESSAGE_BOX);
962                 if ( Mbox_gauge[1].first_frame >= 0 ) {
963                         GR_AABITMAP(Mbox_gauge[1].first_frame, bx, by);                 
964                 }
965                 by += Mbox_item_h[gr_screen.res];
966
967                 // set the text color
968                 if ( MsgItems[First_menu_item+i].active ) {
969                         // hud_set_bright_color();
970                         hud_set_gauge_color(HUD_MESSAGE_BOX, HUD_C_BRIGHT);
971                 } else {
972                         /*
973                         dim_index = min(5, HUD_color_alpha - 2);
974                         if ( dim_index < 0 ) {
975                                 dim_index = 0;
976                         }
977                         gr_set_color_fast(&HUD_color_defaults[dim_index]);
978                         */
979
980                         hud_set_gauge_color(HUD_MESSAGE_BOX, HUD_C_DIM);
981                 }
982
983                 // first do the number
984                 item_num = (i+1) % MAX_MENU_DISPLAY;
985                 emp_hud_printf(sx, sy, EG_SQ1 + i, NOX("%1d."), item_num );             
986
987                 // then the text
988                 emp_hud_string(sx+Mbox_item_xoffset[gr_screen.res], sy, EG_SQ1 + i, text);              
989
990                 sy += Mbox_item_h[gr_screen.res];
991
992                 // if we have at least one item active, then set the variable so we don't display any
993                 // message about no active items
994                 if ( MsgItems[First_menu_item+i].active )
995                         none_valid = 0;
996         }
997
998         // maybe draw an extra line in to make room for [pgdn], or for the 'no active items'
999         // display
1000         if ( !messaging_allowed || none_valid || ((First_menu_item + nitems) < Num_menu_items) || (Msg_shortcut_command != -1) ) {
1001                 // blit the background
1002                 // hud_set_default_color();
1003                 hud_set_gauge_color(HUD_MESSAGE_BOX);
1004                 if ( Mbox_gauge[1].first_frame >= 0 ) {
1005
1006                         GR_AABITMAP(Mbox_gauge[1].first_frame, bx, by);                 
1007                 }
1008                 by += Mbox_item_h[gr_screen.res];
1009         }
1010
1011         // draw the bottom of the frame
1012         // hud_set_default_color();
1013         hud_set_gauge_color(HUD_MESSAGE_BOX);
1014         if ( Mbox_gauge[2].first_frame >= 0 ) {
1015
1016                 GR_AABITMAP(Mbox_gauge[2].first_frame, bx, by);         
1017         }
1018
1019         // determine if we should put the text "[more]" at top or bottom to indicate you can page up or down
1020         hud_targetbox_start_flash(TBOX_FLASH_SQUADMSG);
1021         hud_targetbox_maybe_flash(TBOX_FLASH_SQUADMSG);
1022         if ( First_menu_item > 0 ) {
1023                 gr_printf( Menu_pgup_coords[gr_screen.res][0], Menu_pgup_coords[gr_screen.res][1], XSTR( "[pgup]", 312) );
1024         }
1025
1026         if ( (First_menu_item + nitems) < Num_menu_items ) {
1027                 gr_printf( Menu_pgdn_coords[gr_screen.res][0], Menu_pgdn_coords[gr_screen.res][1], XSTR( "[pgdn]", 313));
1028         }
1029
1030         if ( messaging_allowed ) {
1031                 if ( none_valid ){
1032                         gr_printf( sx, by - Mbox_item_h[gr_screen.res] + 2, XSTR( "No valid items", 314));
1033                 } else if ( !none_valid && (Msg_shortcut_command != -1) ){
1034                         gr_printf( sx, by - Mbox_item_h[gr_screen.res] + 2, "%s", comm_order_hotkey_text(Msg_shortcut_command));
1035                 }
1036         } else {
1037                 // if this player is not allowed to message, then display message saying so
1038                 gr_printf( sx, by - Mbox_item_h[gr_screen.res] + 2, XSTR( "Not allowed to message", 315));
1039         }
1040
1041 }
1042
1043 // function to return true or false if the given ship can rearm, or be repaired
1044 int hud_squadmsg_can_rearm( ship *shipp )
1045 {
1046         // player ships which turns traitor cannot rearm
1047         if ( (shipp == Player_ship) && (Player_ship->team == TEAM_TRAITOR) )
1048                 return 0;
1049
1050         // 5/6/98 -- MWA  Decided to always be able to call in support.
1051         return 1;
1052 }
1053
1054 // calls for repair/rearm of the player ship.  Checks for the presense of the support
1055 // ship and does the appropriate action if found
1056 void hud_squadmsg_repair_rearm( int toggle_state, object *objp)
1057 {
1058         int robjnum;
1059         object *robjp;
1060         object *tobj;
1061         int multi_player_num;
1062
1063         // this is essentially a check for multiplayer server/client mode
1064         // in multiplayer mode, the server may have to issue this command when received from a client
1065         if(objp == NULL) {
1066                 tobj = Player_obj;
1067                 multi_player_num = -1;
1068         } else {
1069                 tobj = objp;
1070                 multi_player_num = multi_find_player_by_object(objp);
1071                 Assert(multi_player_num != -1);
1072         }
1073
1074         // see if player is already scheduled on arriving support ship.  If so, issues appripriate
1075         // message and bail
1076         if ( is_support_allowed(tobj) ) {
1077                 if ( mission_is_repair_scheduled( tobj ) ) {
1078                         message_send_builtin_to_player( MESSAGE_REARM_ON_WAY, NULL, MESSAGE_PRIORITY_NORMAL, MESSAGE_TIME_SOON, 0, 0, multi_player_num, -1 );
1079                 } else {
1080                         robjnum = hud_support_find_closest(OBJ_INDEX(tobj));
1081                         if ( robjnum != -1 ) {
1082                                 message_send_builtin_to_player( MESSAGE_REARM_ON_WAY, &Ships[Objects[robjnum].instance], MESSAGE_PRIORITY_NORMAL, MESSAGE_TIME_SOON, 0, 0, multi_player_num, -1 );
1083                         } else {
1084                                 // request a rearm.  Next function returns -1 if ship is warping in, objnum of repair ship otherwise
1085                                 robjnum = ai_issue_rearm_request( tobj );
1086                                 if ( robjnum != -1) {
1087                                         robjp = &Objects[robjnum];
1088                                         message_send_builtin_to_player( MESSAGE_ON_WAY, &Ships[robjp->instance], MESSAGE_PRIORITY_NORMAL, MESSAGE_TIME_SOON, 0, 0, multi_player_num, -1 );
1089
1090                                 } else {
1091                                         // if we are in this part of the if statment, a support ship has been warped in to
1092                                         // service us.  Issue appropriate message
1093                                         message_send_builtin_to_player( MESSAGE_REARM_WARP, NULL, MESSAGE_PRIORITY_NORMAL, MESSAGE_TIME_SOON, 0, 0, multi_player_num, -1 );
1094                                 }
1095
1096                                 mission_log_add_entry(LOG_PLAYER_REARM, Ships[tobj->instance].ship_name, NULL);
1097                         }
1098                 }
1099         }
1100
1101         //if ( multi_player_num == -1 )         // only do the hud display if it is for me!
1102         //      hud_support_view_start();
1103
1104         if ( toggle_state )
1105                 hud_squadmsg_toggle();                                          // take us out of message mode
1106 }
1107
1108 // function which gets called from keyboard code to issues a shortcut command for rearming.
1109 void hud_squadmsg_rearm_shortcut()
1110 {
1111         if ( !hud_squadmsg_can_rearm(Player_ship) )
1112                 return;
1113
1114         // multiplayer clients need to send this message to the server
1115         if ( MULTIPLAYER_CLIENT ) {
1116                 send_player_order_packet(SQUAD_MSG_SHIP, 0, REARM_REPAIR_ME_ITEM);
1117                 return;
1118         }
1119
1120         hud_squadmsg_repair_rearm(0);
1121 }
1122
1123 // code which is called when a player aborts his rearm request
1124 void hud_squadmsg_repair_rearm_abort( int toggle_state, object *obj)
1125 {
1126 //      ai_info *aip;
1127 //      object *robjp;
1128         object *tobj;
1129
1130         // this is essentially a check for multiplayer server/client mode
1131         // in multiplayer mode, the server may have to issue this command when received from a client
1132         if(obj == NULL)
1133                 tobj = Player_obj;
1134         else
1135                 tobj = obj;
1136
1137         // try to abort the request.  We shoudln't be in this function unless we are actually
1138         // queued for repair.  Send a message from support ship if the support ship is in the mission
1139         ai_abort_rearm_request( tobj );
1140
1141         // move the next statements outside of the above if-statement.  Seems like this place
1142         // is the right place, since we want to change state of the messaging system regardless
1143         // of what happened above.
1144         if ( toggle_state )
1145                 hud_squadmsg_toggle();                                          // take us out of message mode
1146 }
1147
1148 // returns 1 if an order is valid for a ship.  Applies to things like departure when engines are blown, etc.
1149 int hud_squadmsg_ship_order_valid( int shipnum, int order )
1150 {
1151         // disabled ships can't depart.
1152         if ( (order == DEPART_ITEM) && (Ships[shipnum].flags & SF_DISABLED) )
1153                 return 0;
1154
1155         return 1;
1156 }
1157
1158 // returns true or false if the Players target is valid for the given order
1159 // find_order is true when we need to search the comm_orders array for the order entry.  We have
1160 // to do this action in some cases since all we know is the actual "value" of the order
1161 int hud_squadmsg_is_target_order_valid(int order, int find_order, ai_info *aip )
1162 {
1163         int target_objnum, i;
1164         ship *shipp, *ordering_shipp;
1165         object *objp;
1166
1167         if ( aip == NULL )
1168                 aip = Player_ai;
1169
1170         // find the comm_menu item for this command
1171         if ( find_order ) {
1172                 for (i = 0; i < MAX_SHIP_ORDERS; i++ ) {
1173                         if ( Comm_orders[i].value == order )
1174                                 break;
1175                 }
1176                 Assert( i < MAX_SHIP_ORDERS );
1177                 order = i;
1178         }
1179
1180         // orders which don't operate on targets are always valid
1181         if ( !(Comm_orders[order].value & TARGET_MESSAGES) )
1182                 return 1;
1183
1184         target_objnum = aip->target_objnum;
1185
1186         // order isn't valid if there is no player target
1187         if ( target_objnum == -1 ) {
1188                 return 0;
1189         }
1190
1191         objp = &Objects[target_objnum];
1192
1193         ordering_shipp = &Ships[aip->shipnum];
1194
1195         // target isn't a ship, then return 0
1196         if ( (objp->type != OBJ_SHIP) && (objp->type != OBJ_WEAPON) )
1197                 return 0;
1198
1199         // if it's a weapon, then it needs to be a WIF_BOMB weapon.  Only attack order valid, and only
1200         // valid on bombs not on the player's team
1201         if ( objp->type == OBJ_WEAPON ) {
1202                 if ( (Comm_orders[order].value == ATTACK_TARGET_ITEM )
1203                         && (Weapon_info[Weapons[objp->instance].weapon_info_index].wi_flags & WIF_BOMB)
1204                         && (Weapons[objp->instance].team != ordering_shipp->team) )
1205
1206                         return 1;
1207
1208                 return 0;
1209         }
1210
1211         Assert( objp->type == OBJ_SHIP );
1212
1213         shipp = &Ships[objp->instance];
1214
1215         // if target is a navbouy, return 0
1216         if ( Ship_info[shipp->ship_info_index].flags & SIF_NAVBUOY ){
1217                 return 0;
1218         }
1219
1220         // if we are messaging a ship, and that ship is our target, no target type orders are ever active
1221         if ( (Squad_msg_mode == SM_MODE_SHIP_COMMAND) && (target_objnum == Msg_instance) ){
1222                 return 0;
1223         }
1224
1225         // if the order is a disable order or depart, and the ship is disabled, order isn't active
1226         if ( (Comm_orders[order].value == DISABLE_TARGET_ITEM) && (shipp->flags & SF_DISABLED) ){
1227                 return 0;
1228         }
1229
1230         // same as above except for disabled.
1231         if ( (Comm_orders[order].value == DISARM_TARGET_ITEM) && ((shipp->subsys_info[SUBSYSTEM_TURRET].num > 0) && (shipp->subsys_info[SUBSYSTEM_TURRET].current_hits == 0.0f)) ){
1232                 return 0;
1233         }
1234
1235         // if order is disable subsystem, and no subsystem targeted or no hits, then order not valid
1236         if ( (Comm_orders[order].value == DISABLE_SUBSYSTEM_ITEM) && ((aip->targeted_subsys == NULL) || (aip->targeted_subsys->current_hits <= 0.0f)) ){
1237                 return 0;
1238         }
1239
1240         // check based on target's and player's team
1241         if ( (shipp->team == ordering_shipp->team) && (Comm_orders[order].value & FRIENDLY_TARGET_MESSAGES) ){
1242                 return 1;
1243         } else if ( (shipp->team != ordering_shipp->team) && (Comm_orders[order].value & ENEMY_TARGET_MESSAGES) ){
1244                 return 1;
1245         } else {
1246                 return 0;
1247         }
1248 }
1249
1250 // function to send an order to all fighters/bombers.
1251 void hud_squadmsg_send_to_all_fighters( int command, int player_num )
1252 {
1253         ai_info *aip;
1254         ship *shipp, *ordering_shipp;
1255         int i, send_message, to_everyone, do_ship;
1256         object *objp;
1257
1258         // quick short circuit here because of actually showing comm menu even though you cannot message.
1259         // just a safety net.
1260         if ( (Game_mode & GM_MULTIPLAYER) && (player_num != -1) ) {
1261                 if ( !multi_can_message(&Net_players[player_num]) ) {
1262                         return;
1263                 }
1264         }
1265
1266         // check for multiplayer mode
1267         if((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER)) {
1268                 send_player_order_packet(SQUAD_MSG_ALL, 0, command);
1269                 return;
1270         }
1271
1272         // to_everyone tells us whether the command should apply to all ships, or just to fighets/bombers.
1273         // when true, command goes to *all* friendlies.
1274         send_message = 1;                                                                       // internal flag to dictate who sends message
1275         to_everyone = 0;
1276         do_ship = 0;
1277         aip = Player_ai;
1278
1279         if ( player_num != -1 )
1280                 aip = &Ai_info[Ships[Objects[Net_players[player_num].player->objnum].instance].ai_index];
1281
1282         Assert( aip->shipnum != -1 );
1283         ordering_shipp = &Ships[aip->shipnum];
1284
1285         if ( command == IGNORE_TARGET_ITEM ) {
1286                 to_everyone = 1;
1287                 // if we were messaging a ship directly, set flag to send no messages.  We will send one
1288                 // specifically from the ship player is ordering
1289                 if ( (Msg_instance != MESSAGE_ALL_FIGHTERS) && (Squad_msg_mode == SM_MODE_SHIP_COMMAND) ) {
1290                         do_ship = 1;
1291                         send_message = 0;
1292                 }
1293         }
1294
1295         for ( i = 0; i < num_wings; i++ ) {
1296                 int shipnum;
1297
1298                 if ( (Wings[i].flags & WF_WING_GONE) || (Wings[i].current_count == 0) )
1299                         continue;
1300
1301                 if ( Wings[i].flags & WF_WING_DEPARTING )
1302                         continue;
1303
1304                 // get the first ship on the wing list and look at it's team and then it's type
1305                 shipnum = Wings[i].ship_index[0];
1306                 Assert( shipnum != -1 );
1307                 shipp = &Ships[shipnum];
1308
1309                 // can't message if not on players team
1310                 if ( shipp->team != ordering_shipp->team )
1311                         continue;
1312
1313                 // can't message if ship not fighter/bomber if the command isn't to everyone.
1314                 if ( !to_everyone && !(Ship_info[shipp->ship_info_index].flags & (SIF_FIGHTER | SIF_BOMBER)) )
1315                         continue;
1316
1317                 // don't send the command if the "wing" won't accept the command.  We do this by looking at
1318                 // the set of orders accepted for the first ship in the wing.
1319                 if ( !(command & shipp->orders_accepted) )
1320                         continue;
1321
1322                 // send the command to the wing
1323                 if ( Wings[i].current_count > 1 ) {
1324                         if ( hud_squadmsg_send_wing_command(i, command, send_message, player_num) ) {
1325                                 send_message = 0;
1326                         }
1327                 }
1328         }
1329
1330         // now find any friendly fighter/bomber ships not in wings
1331         for ( objp = GET_FIRST(&obj_used_list); objp != END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
1332                 if ( objp->type != OBJ_SHIP )
1333                         continue;
1334
1335                 // don't send messge to ships not on player's team, or that are in a wing.
1336                 shipp = &Ships[objp->instance];
1337                 if ( (shipp->team != ordering_shipp->team) || (shipp->wingnum != -1) )
1338                         continue;
1339
1340                 // don't send message to non fighter wings
1341                 if ( !to_everyone && !(Ship_info[shipp->ship_info_index].flags & (SIF_FIGHTER | SIF_BOMBER)) )
1342                         continue;
1343
1344                 // skip departing/dying ships
1345                 if ( shipp->flags & (SF_DEPARTING|SF_DYING) )
1346                         continue;
1347
1348                 // don't send command if ship won't accept if
1349                 if ( !(command & shipp->orders_accepted) )
1350                         continue;
1351
1352                 if ( hud_squadmsg_send_ship_command(objp->instance, command, send_message, player_num) ) {
1353                         send_message = 0;
1354                 }
1355         }
1356
1357         // we might send the ship command again if we are ignoring a target, and the guy
1358         // we ordered directly is a ship -- we want the response to come directly from the
1359         // guy we orders
1360         if ( do_ship ) {
1361                 Assert( Msg_instance != MESSAGE_ALL_FIGHTERS );
1362                 hud_squadmsg_send_ship_command( Msg_instance, command, 1 );
1363         }
1364 }
1365
1366 // Check if any enemy ships are in the mission
1367 int hud_squadmsg_enemies_present()
1368 {
1369         ship            *shipp;
1370         ship_obj *so;
1371
1372         for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
1373                 shipp = &Ships[Objects[so->objnum].instance];
1374                 if ( shipp->team != Player_ship->team )
1375                         return 1;
1376         }
1377
1378         return 0;
1379 }
1380
1381 #define OVERRIDE_PROTECT_SHIP_TYPE      (SIF_FIGHTER|SIF_BOMBER|SIF_FREIGHTER|SIF_TRANSPORT)
1382 // function which sends a message to a specific ship.  This routine can be called from one of two
1383 // places.  Either after selecting a ship when using a hotkey, or after selecting a command when
1384 // using the entire messaging menu system
1385 //
1386 // if local and addr are non-null, it means the function is being called by the (multiplayer) server in response to 
1387 // a PLAYER_COMMAND_PACKET
1388 int hud_squadmsg_send_ship_command( int shipnum, int command, int send_message, int player_num )
1389 {
1390         ai_info *ainfo;
1391         int ai_mode, ai_submode;                                        // ai mode and submode needed for ship commands
1392         char *target_shipname;                                          // ship number of possible targets
1393         int message;
1394         int target_team, ship_team;                             // team id's for the ship getting message and any target the player has
1395         ship *ordering_shipp;
1396         
1397         // quick short circuit here because of actually showing comm menu even though you cannot message.
1398         // just a safety net.
1399         if ( (Game_mode & GM_MULTIPLAYER) && (player_num != -1) ) {
1400                 if ( !multi_can_message(&Net_players[player_num]) ) {
1401                         return 0;
1402                 }
1403         }
1404
1405         // check for multiplayer mode
1406         if((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
1407                 send_player_order_packet(SQUAD_MSG_SHIP, shipnum, command);
1408                 return 0;
1409         }
1410
1411         ai_mode = AI_GOAL_NONE;                                                 // needs to be initialized
1412         ai_submode = -1234567;
1413         ainfo = Player_ai;
1414
1415         if ( player_num != -1 ){
1416                 ainfo = &Ai_info[Ships[Objects[Net_players[player_num].player->objnum].instance].ai_index];
1417         }
1418
1419         Assert( ainfo->shipnum != -1 );
1420         ordering_shipp = &Ships[ainfo->shipnum];
1421
1422         // a shortcut to save on repetitive coding.  If the order is a 'target' order, make the default
1423         // mesage be "no target"
1424         message = MESSAGE_NOSIR;
1425         if ( (command & TARGET_MESSAGES) && (ainfo->target_objnum == -1) )
1426                 message = MESSAGE_NO_TARGET;
1427
1428         if ( hud_squadmsg_is_target_order_valid(command, 1, ainfo) ) {
1429
1430                 target_shipname = NULL;
1431                 target_team = -1;
1432                 if ( ainfo->target_objnum != -1) {
1433                         if ( Objects[ainfo->target_objnum].type == OBJ_SHIP ) {
1434                                 if ( ainfo->target_objnum != Ships[shipnum].objnum ) {
1435                                         target_shipname = Ships[Objects[ainfo->target_objnum].instance].ship_name;              // I think this is right
1436                                         target_team = Ships[Objects[ainfo->target_objnum].instance].team;
1437                                 }
1438                         }
1439                 }
1440
1441                 Assert ( ainfo->shipnum != -1 );
1442                 ship_team = Ships[ainfo->shipnum].team;         // team of the ship issuing the message
1443
1444                 switch ( command ) {                                                                    // value of k matches the #defines for ship messages
1445                 case ATTACK_TARGET_ITEM:
1446                         if ( Objects[ainfo->target_objnum].type == OBJ_SHIP ) {
1447                                 Assert( target_shipname );
1448                                 Assert( ship_team != target_team );
1449
1450                                 // Orders to override protect
1451                                 if (Ship_info[Ships[Objects[ainfo->target_objnum].instance].ship_info_index].flags & OVERRIDE_PROTECT_SHIP_TYPE) {
1452                                         Objects[ainfo->target_objnum].flags &= ~OF_PROTECTED;
1453                                 }
1454
1455                                 ai_mode = AI_GOAL_CHASE;
1456                                 ai_submode = SM_ATTACK;
1457                         } else if ( Objects[ainfo->target_objnum].type == OBJ_WEAPON ) {
1458                                 ai_mode = AI_GOAL_CHASE_WEAPON;
1459                                 ai_submode = Objects[ainfo->target_objnum].instance;                    // store the instance of the weapon -- ai goals code will deal with it
1460                         } else
1461                                 Int3();
1462                         message = MESSAGE_ATTACK_TARGET;
1463                         break;
1464
1465                 case DISABLE_TARGET_ITEM:
1466                         Assert( target_shipname );
1467                         Assert( ship_team != target_team );
1468
1469                         // Orders to override protect
1470                         if (Ship_info[Ships[Objects[ainfo->target_objnum].instance].ship_info_index].flags & OVERRIDE_PROTECT_SHIP_TYPE) {
1471                                 Objects[ainfo->target_objnum].flags &= ~OF_PROTECTED;
1472                         }
1473
1474                         ai_mode = AI_GOAL_DISABLE_SHIP;
1475                         ai_submode = -SUBSYSTEM_ENGINE;
1476                         message = MESSAGE_DISABLE_TARGET;
1477                         break;
1478
1479                 case DISARM_TARGET_ITEM:
1480                         Assert( target_shipname );
1481                         Assert( ship_team != target_team );
1482
1483                         // Orders to override protect
1484                         if (Ship_info[Ships[Objects[ainfo->target_objnum].instance].ship_info_index].flags & OVERRIDE_PROTECT_SHIP_TYPE) {
1485                                 Objects[ainfo->target_objnum].flags &= ~OF_PROTECTED;
1486                         }
1487
1488                         ai_mode = AI_GOAL_DISARM_SHIP;
1489                         ai_submode = -SUBSYSTEM_TURRET;
1490                         message = MESSAGE_DISARM_TARGET;
1491                         break;
1492
1493                 case DISABLE_SUBSYSTEM_ITEM:
1494                         Assert( target_shipname );
1495                         Assert( ship_team != target_team );
1496                         Assert( ainfo->targeted_subsys != NULL );
1497                         Assert( ainfo->targeted_subsys->current_hits > 0.0f);
1498
1499                         // Orders to override protect
1500                         if (Ship_info[Ships[Objects[ainfo->target_objnum].instance].ship_info_index].flags & OVERRIDE_PROTECT_SHIP_TYPE) {
1501                                 Objects[ainfo->target_objnum].flags &= ~OF_PROTECTED;
1502                         }
1503
1504                         ai_mode = AI_GOAL_DESTROY_SUBSYSTEM;
1505                         ai_submode = ship_get_subsys_index( &Ships[Objects[ainfo->target_objnum].instance], ainfo->targeted_subsys->system_info->subobj_name );
1506                         message = MESSAGE_ATTACK_TARGET;
1507                         break;
1508
1509                 case CAPTURE_TARGET_ITEM:
1510                         Assert( target_shipname );
1511                         Assert( ship_team != target_team );
1512
1513                         Assert(ainfo->target_objnum > -1);
1514
1515                         Objects[ainfo->target_objnum].flags |= OF_PROTECTED;
1516
1517                         ai_mode = AI_GOAL_DOCK;
1518                         ai_submode = AIS_DOCK_0;
1519                         message = MESSAGE_DOCK_YES;
1520                         break;
1521
1522                 case PROTECT_TARGET_ITEM:
1523
1524                         // AL 31-3-98: Can't protect self... this can happen if all fighters
1525                         //                                      are told to protect another friendly ship
1526                         if ( ainfo->target_objnum == Ships[shipnum].objnum ) {
1527                                 return 0;
1528                         }
1529
1530                         Assert( target_shipname );
1531                         Assert( ship_team == target_team );
1532
1533                         ai_mode = AI_GOAL_GUARD;
1534                         ai_submode = AIS_GUARD_PATROL;
1535                         message = MESSAGE_YESSIR;
1536                         break;
1537
1538                 case IGNORE_TARGET_ITEM:
1539                         Assert( target_shipname );
1540                         Assert( ship_team != target_team );
1541
1542                         ai_mode = AI_GOAL_IGNORE;
1543                         ai_submode = 0;
1544                         message = MESSAGE_YESSIR;
1545                         break;
1546                 
1547                 case FORMATION_ITEM:
1548                         message = MESSAGE_YESSIR;
1549                         target_shipname = ordering_shipp->ship_name;
1550                         ai_mode = AI_GOAL_FORM_ON_WING;
1551                         ai_submode = 0;
1552                         break;
1553                 
1554                 case COVER_ME_ITEM:
1555                         ai_mode = AI_GOAL_GUARD;
1556                         ai_submode = AIS_GUARD_PATROL;
1557                         target_shipname = ordering_shipp->ship_name;
1558                         message = MESSAGE_YESSIR;
1559                         break;
1560                 
1561                 case ENGAGE_ENEMY_ITEM:
1562                         ai_mode = AI_GOAL_CHASE_ANY;
1563                         ai_submode = SM_ATTACK;
1564                         // if no enemies present, use the affirmative, instead of engaging enemies message
1565                         if ( hud_squadmsg_enemies_present() )
1566                                 message = MESSAGE_YESSIR;
1567                         else
1568                                 message = MESSAGE_ENGAGE;
1569                         target_shipname = NULL;
1570                         break;
1571                 
1572                 case DEPART_ITEM:
1573                         ai_mode = AI_GOAL_WARP;
1574                         ai_submode = -1;
1575                         message = MESSAGE_WARP_OUT;
1576                         break;
1577                 
1578                 // the following are support ship options!!!
1579                 case REARM_REPAIR_ME_ITEM:              
1580                         if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER) && (player_num != -1) ){
1581                                 hud_squadmsg_repair_rearm(0,&Objects[Net_players[player_num].player->objnum]);
1582                         } else {
1583                                 hud_squadmsg_repair_rearm(0);                           // note we return right away.  repair/rearm code handles messaging, etc
1584                         }
1585                         return 0;
1586                 
1587                 case ABORT_REARM_REPAIR_ITEM:
1588                         if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER) && (player_num != -1) ){
1589                                 hud_squadmsg_repair_rearm_abort(0,&Objects[Net_players[player_num].player->objnum]);
1590                         } else {
1591                                 hud_squadmsg_repair_rearm_abort(0);             // note we return right away.  repair/rearm code handles messaging, etc
1592                         }
1593                         return 0;
1594                 
1595                 case STAY_NEAR_ME_ITEM:
1596                 case STAY_NEAR_TARGET_ITEM:             // can't attack anything on same team
1597
1598                         // cannot stay near a hostile ship(?)
1599                         if ( (command == STAY_NEAR_TARGET_ITEM) && (ship_team != target_team) )
1600                                 break;
1601
1602                         ai_mode = AI_GOAL_STAY_NEAR_SHIP;
1603                         ai_submode = -1;
1604                         message = MESSAGE_YESSIR;
1605                         if ( command == STAY_NEAR_ME_ITEM )
1606                                 target_shipname = ordering_shipp->ship_name;
1607                         break;
1608                 
1609                 case KEEP_SAFE_DIST_ITEM:
1610                         ai_mode = AI_GOAL_KEEP_SAFE_DISTANCE;
1611                         ai_submode = -1;
1612                         message = MESSAGE_YESSIR;
1613                         break;
1614                 
1615                 default:
1616                         Int3();                                                                         // get Allender -- illegal message
1617                         break;
1618
1619                 }
1620
1621                 // handle case of messaging one ship.  Deal with messaging all fighters next.
1622                 if ( ai_mode != AI_GOAL_NONE ) {
1623                         Assert(ai_submode != -1234567);
1624                         ai_add_ship_goal_player( AIG_TYPE_PLAYER_SHIP, ai_mode, ai_submode, target_shipname, &Ai_info[Ships[shipnum].ai_index] );
1625                         if( player_num == -1 )
1626                                 hud_add_issued_order(Ships[shipnum].ship_name, command, target_shipname);
1627                 }
1628         }
1629
1630         // if we're in multiplayer mode, and we're the server, determine if this virtual squadmate order should be
1631         // sent to other players in the game as an actual "order"
1632         if((Game_mode & GM_MULTIPLAYER) && (message != MESSAGE_NOSIR)){
1633                 // if the multi_msg system processed and sent this order to a player, we should not play a response
1634                 if(multi_msg_eval_ship_squadmsg(shipnum,command,ainfo,player_num)){
1635                         send_message = 0;
1636                 }
1637         }
1638         
1639         // this is the _response_
1640         if ( send_message ){
1641                 message_send_builtin_to_player( message, &Ships[shipnum], MESSAGE_PRIORITY_NORMAL, MESSAGE_TIME_ANYTIME, 0, 0, player_num, -1 );        
1642         }
1643         
1644         return send_message;
1645 }
1646
1647 // function to send a command to a wing.  Like above function, called from one of two places
1648 //
1649 // if local and addr are non-null, it means the function is being called by the (multiplayer) server in response to 
1650 // a PLAYER_COMMAND_PACKET
1651 //
1652 // returns whether or not a message was sent
1653 int hud_squadmsg_send_wing_command( int wingnum, int command, int send_message, int player_num )
1654 {
1655         ai_info *ainfo;
1656         int ai_mode, ai_submode;                                        // ai mode and submode needed for ship commands
1657         char *target_shipname;                                          // ship number of possible targets
1658         int message_sent, message;
1659         int target_team, wing_team;                             // team for the wing and the player's target
1660         ship *ordering_shipp;
1661
1662         // quick short circuit here because of actually showing comm menu even though you cannot message.
1663         // just a safety net.
1664         if ( (Game_mode & GM_MULTIPLAYER) && (player_num != -1) ) {
1665                 if ( !multi_can_message(&Net_players[player_num]) ) {
1666                         return 0;
1667                 }
1668         }
1669
1670         // check for multiplayer mode
1671         if((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
1672                 send_player_order_packet(SQUAD_MSG_WING, wingnum,command);
1673                 return 0;
1674         }
1675
1676         ai_mode = AI_GOAL_NONE;                                                 // needs to be initialized
1677         ai_submode = -1234567;
1678         ainfo = Player_ai;
1679
1680         if ( player_num != -1 )
1681                 ainfo = &Ai_info[Ships[Objects[Net_players[player_num].player->objnum].instance].ai_index];
1682
1683         Assert( ainfo->shipnum != -1 );
1684         ordering_shipp = &Ships[ainfo->shipnum];
1685
1686         // get the shipnum of the ship the player has targeted.  Used in enough places to do this just
1687         // once.  If the ship targeted is part of the wing that was messages -- bail out!!!
1688
1689         // a shortcut to save on repetative coding
1690         message = MESSAGE_NOSIR;
1691         if ( (command & TARGET_MESSAGES) && (ainfo->target_objnum == -1) )
1692                 message = MESSAGE_NO_TARGET;
1693
1694         if ( hud_squadmsg_is_target_order_valid(command, 1, ainfo) ) {
1695
1696                 target_shipname = NULL;
1697                 target_team = -1;
1698                 if ( ainfo->target_objnum != -1) {
1699                         if ( Objects[ainfo->target_objnum].type == OBJ_SHIP ) {
1700                                 target_shipname = Ships[Objects[ainfo->target_objnum].instance].ship_name;              // I think this is right
1701                                 target_team = Ships[Objects[ainfo->target_objnum].instance].team;
1702                         }
1703                 }
1704
1705                 Assert ( ainfo->shipnum != -1 );
1706                 Assert ( (wingnum >= 0) && (wingnum < num_wings) );
1707
1708                 // get the team for the wing
1709                 Assert ( Wings[wingnum].ship_index[0] != -1 );
1710                 wing_team = Ships[Wings[wingnum].ship_index[0]].team;
1711
1712                 switch ( command ) {                                                                    // value of k matches the #defines for ship messages
1713                 case ATTACK_TARGET_ITEM:
1714                         if ( Objects[ainfo->target_objnum].type == OBJ_SHIP ) {
1715                                 Assert( target_shipname );
1716                                 Assert( wing_team != target_team );
1717                                 if ( (Ships[Objects[ainfo->target_objnum].instance].wingnum != -1) && (Ships[Objects[ainfo->target_objnum].instance].wingnum == wingnum) ) {
1718                                         message = MESSAGE_NOSIR;
1719                                         ai_mode = AI_GOAL_NONE;
1720                                 } else {
1721                                         ai_mode = AI_GOAL_CHASE;
1722                                         ai_submode = SM_ATTACK;
1723                                         message = MESSAGE_ATTACK_TARGET;
1724                                 }
1725                         } else if ( Objects[ainfo->target_objnum].type == OBJ_WEAPON ) {
1726                                 ai_mode = AI_GOAL_CHASE_WEAPON;
1727                                 ai_submode = Objects[ainfo->target_objnum].instance;                    // store the instance of the weapon -- ai goals code will deal with it
1728                                 message = MESSAGE_ATTACK_TARGET;
1729                         } else
1730                                 Int3();
1731
1732                         break;
1733
1734                 case DISABLE_TARGET_ITEM:
1735                         Assert( target_shipname );
1736                         Assert( wing_team != target_team );
1737
1738                         ai_mode = AI_GOAL_DISABLE_SHIP;
1739                         ai_submode = -SUBSYSTEM_ENGINE;
1740                         message = MESSAGE_DISABLE_TARGET;
1741                         break;
1742
1743                 case DISARM_TARGET_ITEM:
1744                         Assert( target_shipname );
1745                         Assert( wing_team != target_team );
1746
1747                         ai_mode = AI_GOAL_DISARM_SHIP;
1748                         ai_submode = -SUBSYSTEM_TURRET;
1749                         message = MESSAGE_DISARM_TARGET;
1750                         break;
1751
1752                 case DISABLE_SUBSYSTEM_ITEM:
1753                         Assert( target_shipname );
1754                         Assert( wing_team != target_team );
1755                         Assert( ainfo->targeted_subsys != NULL );
1756                         Assert( ainfo->targeted_subsys->current_hits > 0.0f);
1757
1758                         ai_mode = AI_GOAL_DESTROY_SUBSYSTEM;
1759                         ai_submode = ship_get_subsys_index( &Ships[Objects[ainfo->target_objnum].instance], ainfo->targeted_subsys->system_info->subobj_name );
1760                         message = MESSAGE_ATTACK_TARGET;
1761                         break;
1762
1763
1764                 case PROTECT_TARGET_ITEM:
1765                         Assert( target_shipname );
1766                         Assert( wing_team == target_team );
1767
1768                         ai_mode = AI_GOAL_GUARD;
1769                         ai_submode = AIS_GUARD_PATROL;
1770                         message = MESSAGE_YESSIR;
1771                         break;
1772
1773                 case IGNORE_TARGET_ITEM:
1774                         Assert( target_shipname );
1775                         Assert( wing_team != target_team );
1776
1777                         ai_mode = AI_GOAL_IGNORE;
1778                         ai_submode = 0; //      actually, a don't care.
1779                         message = MESSAGE_YESSIR;
1780                         break;
1781
1782                 case FORMATION_ITEM:
1783                         message = MESSAGE_YESSIR;
1784                         target_shipname = ordering_shipp->ship_name;
1785                         ai_mode = AI_GOAL_FORM_ON_WING;
1786                         ai_submode = 0;
1787                         break;
1788
1789                 case COVER_ME_ITEM:
1790                         ai_mode = AI_GOAL_GUARD;
1791                         ai_submode = AIS_GUARD_PATROL;
1792                         target_shipname = ordering_shipp->ship_name;
1793                         message = MESSAGE_YESSIR;
1794                         break;
1795
1796                 case ENGAGE_ENEMY_ITEM:
1797                         ai_mode = AI_GOAL_CHASE_ANY;
1798                         ai_submode = SM_ATTACK;
1799                         if ( hud_squadmsg_enemies_present() )
1800                                 message = MESSAGE_YESSIR;
1801                         else
1802                                 message = MESSAGE_ENGAGE;
1803                         target_shipname = NULL;
1804                         break;
1805
1806                 case DEPART_ITEM:
1807                         ai_mode = AI_GOAL_WARP;
1808                         ai_submode = -1;
1809                         message = MESSAGE_WARP_OUT;
1810                         Wings[wingnum].flags |= WF_DEPARTURE_ORDERED;
1811                         break;
1812
1813                 case REARM_REPAIR_ME_ITEM:
1814                 case ABORT_REARM_REPAIR_ITEM:
1815                 case STAY_NEAR_ME_ITEM:
1816                 case STAY_NEAR_TARGET_ITEM:
1817                 case KEEP_SAFE_DIST_ITEM:
1818                         return 0;
1819
1820                 default:
1821                         Int3();                                                                         // get Allender -- illegal message
1822                         break;
1823
1824                 }
1825
1826                 if ( ai_mode != AI_GOAL_NONE ) {
1827                         Assert(ai_submode != -1234567);
1828                         ai_add_wing_goal_player( AIG_TYPE_PLAYER_WING, ai_mode, ai_submode, target_shipname, wingnum );
1829                 }
1830         }
1831
1832         // if we're in multiplayer mode, and we're the server, determine if this virtual squadmate order should be
1833         // sent to other players in the game as an actual "order"
1834         if((Game_mode & GM_MULTIPLAYER) && (message != MESSAGE_NOSIR)){
1835                 // if there's at least one ai ship which got the command, let the response come through
1836                 if(multi_msg_eval_wing_squadmsg(wingnum,command,ainfo,player_num)){
1837                         send_message = 0;
1838                 }
1839         }
1840
1841         // this is the _response_
1842         message_sent = 0;
1843         if ( send_message ) {
1844                 int ship_num;
1845
1846                 // get a random ship in the wing to send the message to the player              
1847                 ship_num = ship_get_random_ship_in_wing( wingnum, SHIP_GET_NO_PLAYERS );
1848                 
1849                 // in multiplayer, its possible that all ships in a wing are players. so we'll just send from a random ship             
1850                 if(ship_num == -1){
1851                         ship_num = ship_get_random_ship_in_wing(wingnum);
1852                 }
1853                 
1854                 // only send message if ship is found.  There appear to be cases where all ships
1855                 // in a wing die in the same frame causing the wing to appear valid in the message
1856                 // menu, but the get_random_ship* functions won't return dying ships.
1857                 if ( ship_num != -1 ) {
1858                         message_send_builtin_to_player( message, &Ships[ship_num], MESSAGE_PRIORITY_NORMAL, MESSAGE_TIME_ANYTIME, 0, 0, player_num, -1 );
1859                         message_sent = 1;
1860                 }
1861         }
1862
1863         return message_sent;
1864 }
1865
1866
1867 // return number of available reinforcements, 0 if none available
1868 int hud_squadmsg_reinforcements_available(int team)
1869 {
1870         int i, count = 0;
1871
1872         for (i = 0; i < Num_reinforcements; i++) {
1873                 int wingnum;
1874
1875                 // no more left
1876                 if ( Reinforcements[i].num_uses >= Reinforcements[i].uses ){
1877                         continue;
1878                 }
1879
1880                 // incorrect team
1881                 if ( team != ship_get_reinforcement_team(i) ){
1882                         continue;
1883                 }
1884
1885                 //  check the arrival cue sexpression of the ship/wing of this reinforcement.  If known
1886                 //  false, it doesn't count either
1887                 if ( (wingnum = wing_name_lookup(Reinforcements[i].name, 1)) != -1 ) {
1888                         Assert ( Wings[wingnum].arrival_cue >= 0 );
1889                         if ( Sexp_nodes[Wings[wingnum].arrival_cue].value == SEXP_KNOWN_FALSE ){
1890                                 continue;
1891                         }
1892                 } else {
1893                         p_object *p_objp;
1894
1895                         p_objp = mission_parse_get_arrival_ship( Reinforcements[i].name );
1896                         if ( p_objp != NULL ) {
1897                                 if ( Sexp_nodes[p_objp->arrival_cue].value == SEXP_KNOWN_FALSE ){
1898                                         continue;
1899                                 }
1900                         } else {
1901                                 Int3();                                                 // allender says bogus!  reinforcement should be here since it wasn't a wing!
1902                                 continue;
1903                         }
1904                 }
1905                 count++;
1906         }
1907
1908         return count;
1909 }
1910
1911 // function to put up window in upper right to allow for player to select the type
1912 // of entity to select for a message (i.e. a wing or a ship)
1913 void hud_squadmsg_type_select( )
1914 {
1915         int k, i;
1916
1917         First_menu_item = 0;    
1918
1919         // Add the items
1920         for (i=0; i<NUM_TYPE_SELECT; i++ )      {
1921                 strcpy( MsgItems[i].text, type_select_str(i) );
1922                 MsgItems[i].active = 1;                                         // assume active
1923         }
1924         Num_menu_items = NUM_TYPE_SELECT;
1925
1926
1927         // check to see if the players team is TEAM_TRAITOR.  If so, then he is a "traitor", and will not
1928         // be able to do anything from this menu
1929         if ( Player_ship->team == TEAM_TRAITOR ) {
1930                 for (i = 0; i < MAX_MENU_ITEMS; i++ )
1931                         MsgItems[i].active = 0;
1932                 goto do_main_menu;
1933         }
1934
1935         // based on ship counts, wing counts, shortcut active, grey out possible menu choices
1936         if ( !hud_squadmsg_count_ships(0) )
1937                 MsgItems[TYPE_SHIP_ITEM].active = 0;
1938
1939         if ( !hud_squadmsg_count_wings(0) )
1940                 MsgItems[TYPE_WING_ITEM].active = 0;
1941
1942         // check to be sure that we have some fighters/bombers on the players team that we
1943         // can message
1944         if ( !hud_squadmsg_count_fighters() ){
1945                 MsgItems[TYPE_ALL_FIGHTERS_ITEM].active = 0;
1946         }
1947
1948         if ((Player_ship != NULL) && !hud_squadmsg_reinforcements_available(Player_ship->team)) {
1949                 MsgItems[TYPE_REINFORCEMENT_ITEM].active = 0;
1950         }
1951
1952         MsgItems[TYPE_REPAIR_REARM_ITEM].active = 1;                            // this item will always be available (I think)
1953         MsgItems[TYPE_REPAIR_REARM_ABORT_ITEM].active = 0;
1954
1955         // AL: 10/13/97
1956         // If the player ship communications are severely damaged, then the player
1957         // will only be able to call for repair/rearm ships
1958         //
1959         // also, only allow support ship if this player is not allowed to messaage. 
1960         if ( (hud_communications_state(Player_ship) != COMM_OK) || ((Game_mode & GM_MULTIPLAYER) && !multi_can_message(Net_player)) ) {
1961                 for ( i = 0; i < MAX_MENU_ITEMS; i++ ){
1962                         MsgItems[i].active = 0;
1963                 }
1964
1965                 MsgItems[TYPE_REPAIR_REARM_ITEM].active = 1;
1966         }
1967
1968         // check to see if the player is awaiting repair or being repaired.  Active the abort and inactive the repair items
1969         // check to see if the player is scheduled to be repaired by incoming ship
1970         if ( Ai_info[Ships[Player_obj->instance].ai_index].ai_flags & (AIF_AWAITING_REPAIR | AIF_BEING_REPAIRED) ) {
1971                 MsgItems[TYPE_REPAIR_REARM_ITEM].active = 0;
1972                 MsgItems[TYPE_REPAIR_REARM_ABORT_ITEM].active = 1;
1973         } else if ( mission_is_repair_scheduled(Player_obj) ) {
1974                 MsgItems[TYPE_REPAIR_REARM_ITEM].active = 0;
1975                 MsgItems[TYPE_REPAIR_REARM_ABORT_ITEM].active = 1;
1976         }
1977
1978         // if no support available, can't call one in
1979         if ( !is_support_allowed(Player_obj) ) {
1980                 MsgItems[TYPE_REPAIR_REARM_ITEM].active = 0;
1981                 MsgItems[TYPE_REPAIR_REARM_ABORT_ITEM].active = 0;
1982         }
1983
1984         // de-activate the rearm/repair item if the player has a full load of missiles and
1985         // all subsystems at full strength.  We will only check if this item hasn't been marked
1986         // inactive because of some other reason
1987         if ( MsgItems[TYPE_REPAIR_REARM_ITEM].active ) {
1988
1989                 if ( !hud_squadmsg_can_rearm(Player_ship) ){
1990                         MsgItems[TYPE_REPAIR_REARM_ITEM].active = 0;
1991                 }
1992         }
1993
1994         // if using keyboard shortcut, these items are always inactive
1995         if ( Msg_shortcut_command != -1 ) {
1996                 MsgItems[TYPE_REPAIR_REARM_ITEM].active = 0;
1997                 MsgItems[TYPE_REINFORCEMENT_ITEM].active = 0;
1998                 MsgItems[TYPE_REPAIR_REARM_ABORT_ITEM].active = 0;
1999         }
2000
2001 do_main_menu:
2002         hud_squadmsg_display_menu( XSTR( "Message What", 316) );
2003         k = hud_squadmsg_get_key();
2004         if ( k != -1 ) {                                                        // when k != -1, we have a key that associates with menu item
2005                 Assert ( k < Num_menu_items );
2006                 if ( k == TYPE_SHIP_ITEM ){
2007                         hud_squadmsg_do_mode( SM_MODE_SHIP_SELECT );
2008                 } else if ( k == TYPE_WING_ITEM ) {
2009                         hud_squadmsg_do_mode( SM_MODE_WING_SELECT );
2010                 } else if ( k == TYPE_ALL_FIGHTERS_ITEM ) {
2011                         hud_squadmsg_do_mode( SM_MODE_ALL_FIGHTERS );
2012                 }
2013                 
2014                 if ( Msg_shortcut_command == -1 ) {
2015                         if ( k == TYPE_REINFORCEMENT_ITEM ) {
2016                                 hud_squadmsg_do_mode( SM_MODE_REINFORCEMENTS );
2017                                 player_set_next_all_alone_msg_timestamp();
2018                         } else if ( k == TYPE_REPAIR_REARM_ITEM ){
2019                                 hud_squadmsg_do_mode( SM_MODE_REPAIR_REARM );
2020                         } else if ( k == TYPE_REPAIR_REARM_ABORT_ITEM ) {
2021                                 hud_squadmsg_do_mode( SM_MODE_REPAIR_REARM_ABORT );
2022                         }
2023                 }
2024         }
2025 }
2026
2027 // function to display a list of ships to send a command to
2028 void hud_squadmsg_ship_select()
2029 {
2030         int k;
2031
2032         if ( Num_menu_items == -1 ) {
2033                 Num_menu_items = 0;
2034                 hud_squadmsg_count_ships( 1 );
2035         }
2036
2037         hud_squadmsg_display_menu( XSTR( "Select Ship", 317) );
2038         k = hud_squadmsg_get_key();
2039         if ( k != -1 ) {                                                // if true, we have selected a ship.
2040                 if ( Msg_shortcut_command == -1 ) {
2041                         Msg_instance = MsgItems[First_menu_item + k].instance;          // store the instance id in a global
2042                         hud_squadmsg_do_mode( SM_MODE_SHIP_COMMAND );                           // and move to a new mode
2043                 } else {
2044                         // we must convert the Msg_shortcut_command value to a value that the message
2045                         // system normally uses to select a command.  Since the menu 
2046                         Assert( Msg_shortcut_command != IGNORE_TARGET_ITEM );
2047                         hud_squadmsg_send_ship_command( MsgItems[First_menu_item+k].instance, Msg_shortcut_command, 1 );
2048                         hud_squadmsg_toggle();
2049                 }
2050         }
2051
2052 }
2053
2054 // function to display a list of ships to send a command to
2055 void hud_squadmsg_wing_select()
2056 {
2057         int k;
2058
2059         if ( Num_menu_items == -1 ) {
2060                 Num_menu_items = 0;
2061                 hud_squadmsg_count_wings( 1 );
2062         }
2063
2064         hud_squadmsg_display_menu( XSTR( "Select Wing", 318) );
2065         k = hud_squadmsg_get_key();
2066         if ( k != -1 ) {                                                // if true, we have selected a ship.
2067                 if ( Msg_shortcut_command == -1 ) {                                                                     // do normal menu stuff when no hoykey active
2068                         Msg_instance = MsgItems[First_menu_item + k].instance;  // store the instance id in a global
2069                         hud_squadmsg_do_mode( SM_MODE_WING_COMMAND );                           // and move to a new mode
2070                 } else {
2071                         Assert( Msg_shortcut_command != IGNORE_TARGET_ITEM );
2072                         hud_squadmsg_send_wing_command( MsgItems[First_menu_item+k].instance, Msg_shortcut_command, 1 );
2073                         hud_squadmsg_toggle();
2074                 }
2075         }
2076
2077 }
2078
2079 // code which gives an order to all fighters/bombers.  If there is a message shortcut active, then
2080 // make that order apply to all fighters/bombers.  Otherwise, move to the ship_command menu
2081 void hud_squadmsg_msg_all_fighters()
2082 {
2083         if ( Msg_shortcut_command == -1 ) {
2084                 Msg_instance = MESSAGE_ALL_FIGHTERS;
2085                 hud_squadmsg_do_mode( SM_MODE_SHIP_COMMAND );
2086         } else {
2087                 hud_squadmsg_send_to_all_fighters( Msg_shortcut_command );
2088                 hud_squadmsg_toggle();
2089         }
2090 }
2091
2092 // called to actually bring in a reinforcement.  For single player games, always gets called.
2093 // for multiplayer games, always called on the server side.  Clients should never get here
2094 void hud_squadmsg_call_reinforcement(int reinforcement_num, int player_num)
2095 {
2096         int i, delay;
2097         reinforcements *rp;
2098         p_object *p_objp;
2099
2100         rp = &Reinforcements[reinforcement_num];
2101
2102         // safety net mainly for multiplayer servers in case some odd data desync occurs between 
2103         // server and clients
2104         if ( MULTIPLAYER_MASTER && (rp->num_uses == rp->uses) ) {
2105                 return;
2106         }
2107
2108         // check to see if the reinforcement called was a wing.
2109         for (i = 0; i < num_wings; i++ ) {
2110                 if ( !stricmp(rp->name, Wings[i].name) ) {
2111                         // found a wingname.  Call the parse function to create all the ships in this wing
2112                         // we must set the arrival cue of the wing to true, otherwise, this won't work!!
2113                         Wings[i].flags &= ~WF_REINFORCEMENT;
2114                         Wings[i].flags |= WF_RESET_REINFORCEMENT;
2115
2116                         // set up the arrival delay.  If it is 0, then make is some random number of seconds
2117                         delay = rp->arrival_delay;
2118                         if ( delay == 0 )
2119                                 delay = (int)(frand() * 3.0) + 3;
2120                         Wings[i].arrival_delay = timestamp(delay * 1000);
2121                         break;
2122                 }
2123         }
2124
2125         // if we found no wing name that matched the reinforcement name, then look for a ship
2126         // of the same name
2127         if ( i == num_wings ) {
2128                 p_objp = mission_parse_get_arrival_ship( rp->name );
2129                 if ( p_objp ) {
2130                         // by resetting the reinforcement flag, we will allow code which normally handles arrivals
2131                         // to make this reinforcement arrive.  Doing so keeps the data structures clean.
2132                         p_objp->flags &= ~P_SF_REINFORCEMENT;
2133
2134                         // set up the arrival delay
2135                         delay = rp->arrival_delay;
2136                         if ( delay == 0 )
2137                                 delay = (int)(frand() * 3.0) + 3;               // between 3 and 6 seconds to arrive
2138                         p_objp->arrival_delay = timestamp(delay * 1000);
2139                 } else {
2140                         Int3();                         // get allender -- I don't think that this can happen!!!!
2141                         return;
2142                 }
2143         }
2144
2145         // increment the number of times this is used.  Incremented here on single player and multiplayer
2146         // server side only.  Clients keep track of own count when they actually call something in.
2147         rp->num_uses++;
2148
2149         // commented out on 9/9/98 because these messages simply are not used
2150         /*
2151         // now play a message (if there is one to play) for this reinforcement arrival.  The first for loop
2152         // determine how many messages there are to play, since the array is packet.  Then, if >= 1 message
2153         // to play, play one
2154         for (i = 0; i < MAX_REINFORCEMENT_MESSAGES; i++ )
2155                 if ( !strlen(rp->yes_messages[i]) )
2156                         break;
2157
2158         //if ( i > 0 )
2159         //      message_send_to_player( rp->yes_messages[myrand() % i], rp->name, MESSAGE_PRIORITY_NORMAL, HUD_SOURCE_FRIENDLY );
2160         */
2161
2162         mission_log_add_entry(LOG_PLAYER_REINFORCEMENT, rp->name, NULL);
2163 }
2164
2165 // function to display a list of reinforcements available to the player
2166 void hud_squadmsg_reinforcement_select()
2167 {
2168         int i, k;
2169         reinforcements *rp;
2170
2171         if ( Num_menu_items == -1 ) {
2172                 Num_menu_items = 0;
2173                 for (i = 0; i < Num_reinforcements; i++) {
2174                         rp = &Reinforcements[i];
2175
2176                         // don't put reinforcements onto the list that have already been used up.
2177                         if ( (rp->num_uses == rp->uses) ){
2178                                 continue;
2179                         }
2180
2181                         // don't put items which are not on my team
2182                         if((Player_ship != NULL) && (ship_get_reinforcement_team(i) != Player_ship->team)){
2183                                 continue;
2184                         } 
2185
2186                         Assert ( Num_menu_items < MAX_MENU_ITEMS );
2187                         strcpy( MsgItems[Num_menu_items].text, rp->name );
2188                         MsgItems[Num_menu_items].instance = i;
2189                         MsgItems[Num_menu_items].active = 0;
2190
2191                         if ( rp->flags & RF_IS_AVAILABLE ) {
2192                                 MsgItems[Num_menu_items].active = 1;
2193                         }
2194
2195                         Num_menu_items++;
2196                 }
2197         }
2198
2199 //      hud_squadmsg_display_menu( "Select Reinforcement" );
2200         hud_squadmsg_display_menu( XSTR( "Select Ship/Wing", 319) );    // AL 11-14-97: Reinforcement didn't fit, so using this for now
2201         k = hud_squadmsg_get_key();
2202         if (k != -1) {
2203                 int rnum;
2204
2205                 hud_squadmsg_toggle();                                          // take us out of message mode
2206
2207                 rnum = MsgItems[First_menu_item + k].instance;
2208
2209                 // check to see if trying to call a reinforcement not yet available.  If so, maybe play message, but
2210                 // definately bail
2211                 if ( MsgItems[First_menu_item + k].active == 0 ) {                                              
2212                         return;
2213                 }
2214
2215                 // in single player, or a multiplayer master, call in the reinforcement.  Clients send a packet to the
2216                 // server
2217                 if ( MULTIPLAYER_CLIENT ) {
2218                         Reinforcements[rnum].num_uses++;                        // increment this variable here since clients need to maintain a valid count
2219                         send_player_order_packet(SQUAD_MSG_REINFORCEMENT, rnum, 0);
2220                 } else {
2221                         hud_squadmsg_call_reinforcement(rnum);
2222                 }
2223         }
2224 }
2225
2226 // function to display list of commands for a ship
2227 void hud_squadmsg_ship_command()
2228 {
2229         int k;
2230         int i, orders, default_orders;
2231
2232         // when adding ship commands, we must look at the type of ship, and what messages that
2233         // ship allows.  First, place all messages that are possible onto the menu, then 
2234
2235         // see if messaging all ships or just one.  Messaging all ships will mean all default orders
2236         // show on comm menu.
2237         if ( Msg_instance != MESSAGE_ALL_FIGHTERS ) {
2238                 orders = Ships[Msg_instance].orders_accepted;
2239                 default_orders = ship_get_default_orders_accepted( &Ship_info[Ships[Msg_instance].ship_info_index] );
2240         } else {
2241
2242                 default_orders = FIGHTER_MESSAGES;
2243                 orders = default_orders;
2244         }
2245
2246         First_menu_item = 0;
2247         Num_menu_items = 0;
2248         for ( i = 0; i < MAX_SHIP_ORDERS; i++ ) {
2249                 // check to see if the comm order should even be added to the menu -- if so, then add it
2250                 // the order will be activated if the bit is set for the ship.
2251                 if ( default_orders & Comm_orders[i].value ) {
2252                         Assert ( Num_menu_items < MAX_MENU_ITEMS );
2253                         strcpy( MsgItems[Num_menu_items].text, comm_order_menu_text(i) );
2254                         MsgItems[Num_menu_items].instance = Comm_orders[i].value;
2255                         MsgItems[Num_menu_items].active = 0;
2256                         // check the bit to see if the command is active
2257                         if ( orders & Comm_orders[i].value )
2258                                 MsgItems[Num_menu_items].active = 1;
2259
2260                         // if the order cannot be carried out by the ship, then item should be inactive
2261                         if ( (Msg_instance != MESSAGE_ALL_FIGHTERS) && !hud_squadmsg_ship_order_valid( Msg_instance, Comm_orders[i].value ) )
2262                                 MsgItems[Num_menu_items].active = 0;
2263
2264                         // do some other checks to possibly gray out other items.
2265                         // if no target, remove any items which are associated with the players target
2266                         if ( !hud_squadmsg_is_target_order_valid(i, 0) )
2267                                 MsgItems[Num_menu_items].active = 0;
2268
2269                         // if messaging all fighters, see if we should gray out the order if no one will accept it,
2270                         // or modify the text if only some of the ships will accept it
2271                         if ( Msg_instance == MESSAGE_ALL_FIGHTERS ) {
2272                                 ship_obj *so;
2273                                 ship *shipp;
2274                                 int partial_accept, all_accept;                 // value which tells us what to do with menu item
2275
2276                                 all_accept = Comm_orders[i].value;
2277                                 partial_accept = 0;
2278                                 for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
2279
2280                                         // don't send messge to ships not on player's team, or that are in a wing.
2281                                         shipp = &Ships[Objects[so->objnum].instance];
2282                                         if ( shipp->team != Player_ship->team )
2283                                                 continue;
2284
2285                                         // don't send message to non fighter wings
2286                                         if ( !(Ship_info[shipp->ship_info_index].flags & (SIF_FIGHTER | SIF_BOMBER)) )
2287                                                 continue;
2288
2289                                         all_accept &= shipp->orders_accepted;           // 'and'ing will either keep this bit set or zero it properly
2290                                         partial_accept |= (shipp->orders_accepted & Comm_orders[i].value);      // 'or'ing will tell us if at least one accepts
2291                                 }
2292
2293                                 if ( !all_accept ) {
2294                                         // either modify the text if a partial accept, or grey it out if no one accepts
2295                                         if ( partial_accept ) {
2296                                                 strcat( MsgItems[Num_menu_items].text, XSTR( "(*)", 320) );
2297                                         } else {
2298                                                 MsgItems[Num_menu_items].active = 0;
2299                                         }
2300                                 }
2301                         }
2302
2303                         Num_menu_items++;
2304                 }
2305         }
2306
2307         hud_squadmsg_display_menu( XSTR( "What Command", 321) );
2308         k = hud_squadmsg_get_key();
2309
2310         // when we get a valid goal, we must add the goal to the ai ship's goal list
2311
2312         if ( k != -1 ) {
2313                 Assert ( k < Num_menu_items );
2314                 // when messaging all fighters or ignoring target, call the send_to_all_fighters routine
2315                 if ( (Msg_instance != MESSAGE_ALL_FIGHTERS) && (MsgItems[k].instance != IGNORE_TARGET_ITEM) )
2316                         hud_squadmsg_send_ship_command( Msg_instance, MsgItems[k].instance, 1 );
2317                 else
2318                         hud_squadmsg_send_to_all_fighters( MsgItems[k].instance );
2319                 hud_squadmsg_toggle();
2320         }
2321 }
2322
2323 // function to display list of command for a wing
2324 void hud_squadmsg_wing_command()
2325 {
2326         int k;
2327         wing *wingp;
2328         int default_orders, i, orders;
2329
2330         // when adding commands for wings, we will look at all of the ships in the wing, and create
2331         // the order list from that set of ships.  In the future, we may want to do something else....
2332
2333         wingp = &Wings[Msg_instance];
2334
2335         // or together all of the orders for all the ships in the wing
2336         default_orders = 0;
2337         for ( i = 0; i < wingp->current_count; i++ ) {
2338                 orders = ship_get_default_orders_accepted( &Ship_info[Ships[wingp->ship_index[i]].ship_info_index] );
2339                 default_orders |= orders;
2340         }
2341         default_orders &= ~CAPTURE_TARGET_ITEM;         // we cannot capture any target with a wing.
2342
2343         Num_menu_items = 0;
2344         orders = Ships[wingp->ship_index[0]].orders_accepted;           // get the orders that the first ship in the wing will accept
2345         for ( i = 0; i < MAX_SHIP_ORDERS; i++ ) {
2346                 // add the set of default orders to the comm menu.  We will currently allow all messages
2347                 // to be available in the wing.
2348                 if ( default_orders & Comm_orders[i].value ) {
2349                         Assert ( Num_menu_items < MAX_MENU_ITEMS );
2350                         strcpy( MsgItems[Num_menu_items].text, comm_order_menu_text(i) );
2351                         MsgItems[Num_menu_items].instance = Comm_orders[i].value;
2352                         MsgItems[Num_menu_items].active = 0;
2353
2354                         // possibly grey out the menu item depending on whether or not the "wing" will accept this order
2355                         // the "wing" won't accept the order if the first ship in the wing doesn't accept it.
2356                         if ( orders & Comm_orders[i].value )
2357                                 MsgItems[Num_menu_items].active = 1;
2358
2359                         // do some other checks to possibly gray out other items.
2360                         // if no target, remove any items which are associated with the players target
2361                         if ( !hud_squadmsg_is_target_order_valid(i, 0) )
2362                                 MsgItems[Num_menu_items].active = 0;
2363
2364                         Num_menu_items++;
2365                 }
2366         }
2367
2368         hud_squadmsg_display_menu( XSTR( "What Command", 321) );
2369         k = hud_squadmsg_get_key();
2370         if ( k != -1 ) {
2371
2372                 // ignore target gets sent to everyone.
2373                 if ( MsgItems[k].instance != IGNORE_TARGET_ITEM )
2374                         hud_squadmsg_send_wing_command( Msg_instance, MsgItems[k].instance, 1 );
2375                 else
2376                         hud_squadmsg_send_to_all_fighters( MsgItems[k].instance );
2377                 hud_squadmsg_toggle();
2378         }
2379 }
2380
2381
2382
2383 //----------------------------------------------------------
2384 // external entry points below!!!!
2385
2386 // when starting messaging mode, we must remove old bindings from the
2387 // keys that are used for messaging mode (which will get restored when
2388 // messaging mode is done).
2389
2390 // this code below will get called only the key config changes (from ControlsConfig.cpp)
2391 // or if the bindings haven't been saved yet.  This code doesn't remove the bindings
2392 // but just sets up the array so that the bindings can be removed when messaging
2393 // mode is entered.
2394 //
2395 // do_scroll indicates whether we should save the page up and page down keys
2396 void hud_squadmsg_save_keys( int do_scroll )
2397 {
2398 //      int i, j;
2399
2400         num_keys_saved = 0;
2401
2402 /*
2403         for ( j=0; j<MAX_KEYS_USED; j++ ) {
2404                 for ( i=0; Control_config[i].text[0]; i++ ) {   // the text field in this structure is empty at the end of the config list
2405                         if ( Control_config[i].key_id == keys_used[j] ) {               // this is true if we have a match
2406
2407                                 // if we are not saving scrolling keys and we are trying to match page up and page down
2408                                 // then skip them.
2409                                 if ( !do_scroll && ((keys_used[j] == KEY_PAGEDOWN) || (keys_used[j] == KEY_PAGEUP)) )
2410                                         continue;
2411
2412                                 Assert( num_keys_saved < MAX_KEYS_USED );
2413                                 key_save[num_keys_saved].option_num = i;
2414                                 key_save[num_keys_saved].key_value = keys_used[j];
2415                                 num_keys_saved++;
2416                                 break;  // done with this key -- move to next.
2417                         }
2418                 }
2419         }
2420 */
2421 }
2422
2423 // function is called once per mission start.  Initializes those values
2424 // which only need to be inited once per mission.
2425 void hud_init_squadmsg( void ) 
2426 {
2427         int i;
2428
2429         if ( !Mbox_frames_loaded ) {
2430                 for ( i = 0; i < NUM_MBOX_FRAMES; i++ ) {
2431                         Mbox_gauge[i].first_frame = bm_load_animation(Mbox_fnames[gr_screen.res][i], &Mbox_gauge[i].num_frames);
2432                         if ( Mbox_gauge[i].first_frame == -1 ) {
2433                                 Warning(LOCATION, "Could not load in ani: %s\n", Mbox_fnames[gr_screen.res][i]);
2434                                 return;
2435                         }
2436                 }
2437                 Mbox_frames_loaded = 1;
2438         }
2439
2440         Msg_eat_key_timestamp = timestamp(0);
2441 }
2442
2443 // external entry point into code which changes the messaging mode based on the
2444 // previous player flag value.  I thought it better to isolate all system changes
2445 // in this code.
2446 void hud_squadmsg_toggle()
2447 {
2448         // if the emp effect is active, always ignore this
2449         if(emp_active_local()){
2450                 return;
2451         }
2452
2453         // if entering this mode, must setup messaging system.  Don't start squadmessging if 
2454         // the player is dead.
2455         if ( !(Player->flags & PLAYER_FLAGS_MSG_MODE) ) {
2456                 if ( Game_mode & GM_DEAD ){
2457                         return;
2458                 }
2459                 if ( (Game_mode & GM_MULTIPLAYER) && NETPLAYER_IS_OBSERVER(Net_player) ){
2460                         return;
2461                 }
2462                 hud_squadmsg_start();
2463         } else {
2464                 hud_squadmsg_end();
2465         }
2466
2467         Player->flags ^= PLAYER_FLAGS_MSG_MODE;
2468 }
2469
2470 //#ifndef NDEBUG
2471 // extern entry point to allow messaging of enemies
2472 void hud_enemymsg_toggle()
2473 {
2474         hud_squadmsg_toggle();
2475         // if we just entered message mode, turn on var that says to message enemies
2476         if ( Player->flags & PLAYER_FLAGS_MSG_MODE )
2477                 Msg_enemies = 1;
2478 }
2479 //#endif
2480
2481 // external entry point into code when a keyboard shortcut is used for a command
2482 // we are passed in an ID for the command to set internal variables.  This command
2483 // will be used in place of the last menu in the messaging code
2484 void hud_squadmsg_shortcut( int command )
2485 {
2486         // check if the communications system is capable of sending a message
2487         if ( (hud_communications_state(Player_ship, 1) != COMM_OK) && (command != REARM_REPAIR_ME_ITEM) ) {
2488                 return;
2489         }
2490
2491         // observers in multiplayer games cannot have this active either
2492         if ( (Game_mode & GM_MULTIPLAYER) && NETPLAYER_IS_OBSERVER(Net_player) )
2493                 return;
2494
2495         // in multiplayer and I cannot message, don't allow anything except calling in for rearm
2496         if ( (Game_mode & GM_MULTIPLAYER) && !multi_can_message(Net_player) && (command != REARM_REPAIR_ME_ITEM) )
2497                 gamesnd_play_error_beep();
2498
2499         // player ships which turns traitor cannot rearm
2500         if ( Player_ship->team == TEAM_TRAITOR )
2501                 return;
2502
2503         if ( Player->flags & PLAYER_FLAGS_MSG_MODE )            // we are already in messaging mode -- maybe do sometime more interesting?
2504                 return;
2505         hud_squadmsg_toggle();
2506         Msg_shortcut_command = command;                                                                 // save the command for later use
2507         if ( Msg_shortcut_command == CAPTURE_TARGET_ITEM )                      // some commands only apply to wings or ships
2508                 Squad_msg_mode = SM_MODE_SHIP_SELECT;                                           //  -- don't offer choice
2509         else if ( Msg_shortcut_command == IGNORE_TARGET_ITEM ) {        //  ignoring target applied to all ships
2510                 hud_squadmsg_toggle();                                                                                  // turns off mode which was turned on above
2511                 hud_squadmsg_send_to_all_fighters( Msg_shortcut_command );
2512         }
2513 }
2514
2515 // external entry point which is called when the player hits a selection key (1-0) while in messaging
2516 // mode.  If we are in messaging mode, send the shortcut command to the ships that are part of the
2517 // passed in selection set.  If there is no shortcut command, do nothing.  Returns 1 if the key
2518 // was used, else 0.  This return value is used to tell the key control system that it should
2519 // call the normal targeting selection stuff.
2520 int hud_squadmsg_hotkey_select( int k )
2521 {
2522         htarget_list *hitem, *plist;
2523         int send_message;
2524         object *objp;
2525
2526         Assert ( Player->flags & PLAYER_FLAGS_MSG_MODE );
2527
2528         if ( Msg_shortcut_command == -1 )
2529                 return 0;
2530
2531         Assert ( (k >= 0) && (k < MAX_KEYED_TARGETS) );
2532         plist = &(Player->keyed_targets[k]);
2533
2534         if ( EMPTY(plist) )             // be sure that we have at least one ship in the list
2535                 return 0;
2536
2537         send_message = 1;
2538         // for each ship in the selection set list, send the shortcut command that the player
2539         // previously entered.  Be sure to check that we are not trying to send a command to
2540         // an enemy ship.
2541         for ( hitem = GET_FIRST(plist); hitem != END_OF_LIST(plist); hitem = GET_NEXT(hitem) ) {
2542                 objp = hitem->objp;
2543                 Assert ( objp->type == OBJ_SHIP );
2544                 if ( Ships[objp->instance].team != TEAM_FRIENDLY )
2545                         continue;
2546
2547                 // be sure that this ship can accept this command
2548                 if ( !(Msg_shortcut_command, Ships[objp->instance].orders_accepted) )
2549                         continue;
2550
2551                 hud_squadmsg_send_ship_command( objp->instance, Msg_shortcut_command, send_message );
2552                 send_message  = 0;
2553         }
2554
2555         hud_squadmsg_toggle();                  // turn off messaging mode
2556         return 1;
2557 }
2558
2559
2560 // the next function is called once a frame when the player is messaging someone
2561 // in his squad.  After a period of 5 seconds of inactivity (i.e. no keypress to
2562 // select something in the menu), the menu will disappear.  This function will only
2563 // get called if the player flag PLAYER_FLAG_MSG_MODE is set.  Parameter is the key
2564 // that was hit this frame
2565
2566 int hud_squadmsg_do_frame( )
2567 {
2568         int target_changed;
2569
2570         Assert ( Player->flags & PLAYER_FLAGS_MSG_MODE );               // be sure that messaging mode is set!!!
2571
2572         // if the player is now dead, or the timestamp elapsed, then get out of messaging mode.
2573         if ( (Game_mode & GM_DEAD) || timestamp_elapsed(Msg_mode_timestamp) ) {
2574                 hud_squadmsg_toggle();
2575                 return 0;
2576         }
2577
2578         Msg_key_used = 0;
2579
2580         // check the player's current target.  Change in target resets the timer
2581         target_changed = 0;
2582         if ( Msg_target_objnum != Player_ai->target_objnum ) {
2583                 Msg_target_objnum = Player_ai->target_objnum;
2584                 target_changed = 1;
2585         }
2586
2587         if ( Msg_targeted_subsys != Player_ai->targeted_subsys ) {
2588                 Msg_targeted_subsys = Player_ai->targeted_subsys;
2589                 target_changed = 1;
2590         }
2591
2592         // setup color/font info 
2593         // hud_set_default_color();
2594         hud_set_gauge_color(HUD_MESSAGE_BOX);
2595
2596         // check for multiplayer mode - this is really a special case checker for support ship requesting and aborting
2597         if((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && (Squad_msg_mode == SM_MODE_REPAIR_REARM || Squad_msg_mode == SM_MODE_REPAIR_REARM_ABORT)){
2598                 char *subsys_name;
2599 //              int who_to_sig;
2600                 ushort net_sig;
2601                 
2602                 // who_to_sig = Objects[Ships[shipnum].objnum].net_signature;
2603                 if(Player_ai->target_objnum != -1)
2604                         net_sig = Objects[Player_ai->target_objnum].net_signature;
2605                 else 
2606                         net_sig = 0;
2607
2608       if ((Player_ai->targeted_subsys != NULL) && (Player_ai->targeted_subsys->current_hits > 0.0f))
2609                         subsys_name = Player_ai->targeted_subsys->system_info->subobj_name;
2610                 else
2611                         subsys_name = NULL;
2612                 
2613                 // send the correct packet
2614                 if(Squad_msg_mode == SM_MODE_REPAIR_REARM)              
2615                         send_player_order_packet(SQUAD_MSG_SHIP, 0, REARM_REPAIR_ME_ITEM);
2616                 else
2617                         send_player_order_packet(SQUAD_MSG_SHIP, 0, ABORT_REARM_REPAIR_ITEM);
2618
2619                 // make sure to toggle the mode off
2620                 hud_squadmsg_toggle();
2621                 
2622                 return 1;
2623         }
2624
2625         // draw top of frame
2626         if ( Mbox_gauge[0].first_frame >= 0 ) {
2627                 GR_AABITMAP(Mbox_gauge[0].first_frame, Mbox_top_coords[gr_screen.res][0], Mbox_top_coords[gr_screen.res][1]);           
2628         }
2629
2630         switch( Squad_msg_mode ) {
2631
2632         case SM_MODE_TYPE_SELECT:
2633                 hud_squadmsg_type_select();
2634                 break;
2635
2636         case SM_MODE_SHIP_SELECT:
2637                 hud_squadmsg_ship_select();
2638                 break;
2639
2640         case SM_MODE_WING_SELECT:
2641                 hud_squadmsg_wing_select();
2642                 break;
2643
2644         case SM_MODE_SHIP_COMMAND:
2645                 hud_squadmsg_ship_command();
2646                 break;
2647
2648         case SM_MODE_WING_COMMAND:
2649                 hud_squadmsg_wing_command();
2650                 break;
2651
2652         case SM_MODE_REINFORCEMENTS:
2653                 hud_squadmsg_reinforcement_select();
2654                 break;          
2655                 
2656         case SM_MODE_REPAIR_REARM:
2657                 //if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER) && (addr != NULL)){
2658                 //      hud_squadmsg_repair_rearm(1,&Objects[Net_players[player_num].player->objnum]);
2659                 //} else {
2660                         hud_squadmsg_repair_rearm(1);                           // note we return right away.  repair/rearm code handles messaging, etc
2661                 //}     
2662                 break;
2663
2664         case SM_MODE_REPAIR_REARM_ABORT:
2665                 //if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER) && (addr != NULL)){
2666                 //      hud_squadmsg_repair_rearm_abort(1,&Objects[Net_players[player_num].player->objnum]);
2667                 //} else {
2668                         hud_squadmsg_repair_rearm_abort(1);             // note we return right away.  repair/rearm code handles messaging, etc
2669                 //}
2670                 break;
2671
2672         case SM_MODE_ALL_FIGHTERS:
2673                 hud_squadmsg_msg_all_fighters();
2674                 break;
2675
2676         default:
2677                 Int3();         // get allender -- invalid mode in messaging system
2678                 break;
2679
2680         }
2681
2682         // be sure to reset the clip region
2683         HUD_reset_clip();               // JAS: Is this needed?
2684
2685         if ( Msg_key_used || target_changed ) {
2686                 Msg_mode_timestamp = timestamp(DEFAULT_MSG_TIMEOUT);
2687                 return 1;
2688         } else
2689                 return 0;
2690 }
2691
2692 void hud_add_issued_order(char *name, int order, char *target)
2693 {
2694         Squadmsg_history[squadmsg_history_index].ship = get_parse_name_index(name);
2695         Squadmsg_history[squadmsg_history_index].order = order;
2696         if (target)
2697                 Squadmsg_history[squadmsg_history_index].target = get_parse_name_index(target);
2698         else
2699                 Squadmsg_history[squadmsg_history_index].target = -1;
2700
2701         squadmsg_history_index++;
2702         if (squadmsg_history_index >= SQUADMSG_HISTORY_MAX)
2703                 squadmsg_history_index = 0;
2704 }
2705
2706 int hud_query_order_issued(char *name, char *order, char *target)
2707 {
2708         int i, o=-1, ship, t;
2709
2710         ship = get_parse_name_index(name);
2711         t = -1;
2712         if (target)
2713                 t = get_parse_name_index(target);
2714
2715         for (i=0; i<MAX_SHIP_ORDERS; i++)
2716                 if (!stricmp(order, comm_order_menu_text(i)) )
2717                         o = Comm_orders[i].value;
2718
2719         Assert(i < MAX_SHIP_ORDERS);
2720         for (i=0; i<SQUADMSG_HISTORY_MAX; i++)
2721                 if (Squadmsg_history[i].order == o)
2722                         if (ship == Squadmsg_history[i].ship)
2723                                 if (Squadmsg_history[i].target == t)
2724                                         return 1;
2725
2726         return 0;
2727 }
2728
2729
2730 void hudsquadmsg_page_in() 
2731 {
2732         int i;
2733
2734         for ( i = 0; i < NUM_MBOX_FRAMES; i++ ) {
2735                 bm_page_in_aabitmap( Mbox_gauge[i].first_frame, Mbox_gauge[i].num_frames );
2736         }
2737 }