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