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