1 /*
2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
3 *
4 * All source code herein is the property of Volition, Inc. You may not sell
5 * or otherwise commercially exploit the source or things you created based on the
6 * source.
7 *
8 */
9
10
11
12
13 #include "globalincs/pstypes.h"
14 #include "globalincs/globals.h"
15 #include "globalincs/linklist.h"
16 #include "io/key.h"
17 #include "io/joy.h"
18 #include "io/timer.h"
19 #include "ship/ship.h"
20 #include "playerman/player.h"
21 #include "weapon/weapon.h"
22 #include "hud/hud.h"
23 #include "gamesequence/gamesequence.h"
24 #include "mission/missiongoals.h"
25 #include "hud/hudets.h"
26 #include "gamesnd/gamesnd.h"
27 #include "hud/hudsquadmsg.h"
28 #include "gamesnd/eventmusic.h"
29 #include "freespace2/freespace.h"
30 #include "mission/missionhotkey.h"
31 #include "hud/hudescort.h"
32 #include "hud/hudshield.h"
33 #include "io/keycontrol.h"
34 #include "ship/shiphit.h"
35 #include "ship/shipfx.h"
36 #include "mission/missionlog.h"
37 #include "hud/hudtargetbox.h"
38 #include "popup/popup.h"
39 #include "object/objcollide.h"
40 #include "object/object.h"
41 #include "hud/hudconfig.h"
42 #include "hud/hudmessage.h"
43 #include "network/multi_pmsg.h"
44 #include "starfield/supernova.h"
45 #include "mission/missionmessage.h"
46 #include "menuui/mainhallmenu.h"
47 #include "missionui/missionpause.h"
48 #include "hud/hudgauges.h"
49 #include "freespace2/freespace.h" //For time compression stuff
50 #include "species_defs/species_defs.h"
51 #include "asteroid/asteroid.h"
52 #include "iff_defs/iff_defs.h"
53 #include "network/multi.h"
54 #include "network/multiutil.h"
55 #include "network/multimsgs.h"
56 #include "network/multi_pause.h"
57 #include "network/multi_observer.h"
58 #include "network/multi_endgame.h"
59 #include "autopilot/autopilot.h"
60 #include "cmdline/cmdline.h"
61 #include "object/objectshield.h"
62
63 #define MAX_NUM_SLOTS 6
64
65 struct ftable
66 {
67 int count;
68 int table[ MAX_NUM_SLOTS ];
69 };
70
71 #define MAX_SLOT_COUNT 25
72
73 class factor_table
74 {
75 public:
76 factor_table();
~factor_table()77 ~factor_table(){ delete[] table; };
78 int getNextSlots( int slots_on_ship, int cur_slots );
79
80 private:
81 ftable * table;
82 };
83
84 factor_table ftables;
85
isAPrimeFactor(int factor,int product)86 static bool isAPrimeFactor( int factor, int product )
87 {
88 return ( (float)product / (float)factor ) == (product / factor);
89 }
90
factor_table()91 factor_table::factor_table()
92 {
93 table = new ftable[ MAX_NUM_SLOTS ];
94
95 memset( table, 0x00, sizeof( ftable ) * MAX_NUM_SLOTS );
96 for( int i = 0 ; i < MAX_NUM_SLOTS; ++i )
97 {
98 table[ i ].count = 0;
99 for( int j = 1; j <= i; ++j )
100 {
101 if( isAPrimeFactor( j, i ) )
102 {
103 table[ i ].table[ table[ i ].count ] = j;
104 table[ i ].count ++;
105 }
106 }
107 }
108 }
109
getNextSlots(int slots_on_ship,int cur_slots)110 int factor_table::getNextSlots(int slots_on_ship, int cur_slots)
111 {
112 Assert( slots_on_ship <= MAX_NUM_SLOTS );
113 Assert( slots_on_ship >= 0 );
114
115 for( int i = 0; i < table[ slots_on_ship ].count; ++i )
116 {
117 if( table[ slots_on_ship ].table[ i ] == cur_slots )
118 {
119 if( table[ slots_on_ship ].count == i + 1 )
120 {
121 //Overflow back to 1
122 return 1;
123 }
124 else
125 {
126 //Next block in the table
127 return table[ slots_on_ship ].table[ i + 1 ];
128 }
129 }
130 }
131 //Did not find cur_slots, try and get back on track
132
133 Assert( 0 );
134 return 1;
135 }
136
137 // --------------------------------------------------------------
138 // Global to file
139 // --------------------------------------------------------------
140
141 // time compression/dilation values - Goober5000
142 // (Volition sez "can't compress below 0.25"... not sure if
143 // this is arbitrary or dictated by code)
144 #define MAX_TIME_MULTIPLIER 64
145 #define MAX_TIME_DIVIDER 4
146
147 #define CHEAT_BUFFER_LEN 17
148 char CheatBuffer[CHEAT_BUFFER_LEN+1];
149
150 enum cheatCode {
151 CHEAT_CODE_NONE = 0,
152 CHEAT_CODE_FREESPACE,
153 CHEAT_CODE_FISH,
154 CHEAT_CODE_HEADZ,
155 CHEAT_CODE_TOOLED,
156 CHEAT_CODE_PIRATE,
157 CHEAT_CODE_SKIP
158 };
159
160 struct Cheat {
161 cheatCode code;
162 char* data;
163 };
164
165 static struct Cheat cheatsTable[] = {
166 { CHEAT_CODE_FREESPACE, "www.freespace2.com" },
167 { CHEAT_CODE_FISH, "vasudanswuvfishes" },
168 { CHEAT_CODE_HEADZ, "humanheadsinside." },
169 { CHEAT_CODE_TOOLED, "tooledworkedowned" },
170 { CHEAT_CODE_PIRATE, "arrrrwalktheplank" },
171 { CHEAT_CODE_SKIP, "skipmemymissionyo" }
172 };
173
174 #define CHEATS_TABLE_LEN 6
175
176 int Tool_enabled = 0;
177 bool Perspective_locked=false;
178 bool quit_mission_popup_shown = false;
179
180 extern int AI_watch_object;
181 extern int Countermeasures_enabled;
182
183 extern float do_subobj_hit_stuff(object *ship_obj, object *other_obj, vec3d *hitpos, int submodel_num, float damage, bool *hull_should_apply_armor);
184
185 extern void mission_goal_mark_all_true( int type );
186
187 int Normal_key_set[] = {
188 TARGET_NEXT,
189 TARGET_PREV,
190 TARGET_NEXT_CLOSEST_HOSTILE,
191 TARGET_PREV_CLOSEST_HOSTILE,
192 TARGET_NEXT_CLOSEST_FRIENDLY,
193 TARGET_PREV_CLOSEST_FRIENDLY,
194 TARGET_TARGETS_TARGET,
195 TARGET_SHIP_IN_RETICLE,
196 TARGET_LAST_TRANMISSION_SENDER,
197 TARGET_CLOSEST_SHIP_ATTACKING_TARGET,
198 TARGET_CLOSEST_SHIP_ATTACKING_SELF,
199 STOP_TARGETING_SHIP,
200 TOGGLE_AUTO_TARGETING,
201 TARGET_SUBOBJECT_IN_RETICLE,
202 TARGET_PREV_SUBOBJECT,
203 TARGET_NEXT_SUBOBJECT,
204 STOP_TARGETING_SUBSYSTEM,
205
206 TARGET_NEXT_UNINSPECTED_CARGO,
207 TARGET_PREV_UNINSPECTED_CARGO,
208 TARGET_NEWEST_SHIP,
209 TARGET_NEXT_LIVE_TURRET,
210 TARGET_PREV_LIVE_TURRET,
211 TARGET_NEXT_BOMB,
212 TARGET_PREV_BOMB,
213
214 ATTACK_MESSAGE,
215 DISARM_MESSAGE,
216 DISABLE_MESSAGE,
217 ATTACK_SUBSYSTEM_MESSAGE,
218 CAPTURE_MESSAGE,
219 ENGAGE_MESSAGE,
220 FORM_MESSAGE,
221 PROTECT_MESSAGE,
222 COVER_MESSAGE,
223 WARP_MESSAGE,
224 REARM_MESSAGE,
225 IGNORE_MESSAGE,
226 SQUADMSG_MENU,
227
228 VIEW_CHASE,
229 VIEW_OTHER_SHIP,
230 VIEW_TOPDOWN,
231 VIEW_TRACK_TARGET,
232
233 SHOW_GOALS,
234 END_MISSION,
235
236 ADD_REMOVE_ESCORT,
237 ESCORT_CLEAR,
238 TARGET_NEXT_ESCORT_SHIP,
239
240 XFER_SHIELD,
241 XFER_LASER,
242 INCREASE_SHIELD,
243 INCREASE_WEAPON,
244 INCREASE_ENGINE,
245 DECREASE_SHIELD,
246 DECREASE_WEAPON,
247 DECREASE_ENGINE,
248 ETS_EQUALIZE,
249 SHIELD_EQUALIZE,
250 SHIELD_XFER_TOP,
251 SHIELD_XFER_BOTTOM,
252 SHIELD_XFER_RIGHT,
253 SHIELD_XFER_LEFT,
254
255 CYCLE_NEXT_PRIMARY,
256 CYCLE_PREV_PRIMARY,
257 CYCLE_SECONDARY,
258 CYCLE_NUM_MISSLES,
259 RADAR_RANGE_CYCLE,
260
261 MATCH_TARGET_SPEED,
262 TOGGLE_AUTO_MATCH_TARGET_SPEED,
263
264 VIEW_EXTERNAL,
265 VIEW_EXTERNAL_TOGGLE_CAMERA_LOCK,
266 LAUNCH_COUNTERMEASURE,
267 ONE_THIRD_THROTTLE,
268 TWO_THIRDS_THROTTLE,
269 PLUS_5_PERCENT_THROTTLE,
270 MINUS_5_PERCENT_THROTTLE,
271 ZERO_THROTTLE,
272 MAX_THROTTLE,
273
274 TARGET_CLOSEST_REPAIR_SHIP,
275
276 MULTI_MESSAGE_ALL,
277 MULTI_MESSAGE_FRIENDLY,
278 MULTI_MESSAGE_HOSTILE,
279 MULTI_MESSAGE_TARGET,
280 MULTI_OBSERVER_ZOOM_TO,
281
282 TIME_SPEED_UP,
283 TIME_SLOW_DOWN,
284
285 TOGGLE_HUD_CONTRAST,
286
287 MULTI_TOGGLE_NETINFO,
288 MULTI_SELF_DESTRUCT,
289
290 TOGGLE_HUD,
291
292 HUD_TARGETBOX_TOGGLE_WIREFRAME,
293 AUTO_PILOT_TOGGLE,
294 NAV_CYCLE,
295
296 TOGGLE_GLIDING,
297 CYCLE_PRIMARY_WEAPON_SEQUENCE
298 };
299
300 int Dead_key_set[] = {
301 TARGET_NEXT,
302 TARGET_PREV,
303 TARGET_NEXT_CLOSEST_HOSTILE,
304 TARGET_PREV_CLOSEST_HOSTILE,
305 TARGET_NEXT_CLOSEST_FRIENDLY,
306 TARGET_PREV_CLOSEST_FRIENDLY,
307 TARGET_TARGETS_TARGET,
308 TARGET_CLOSEST_SHIP_ATTACKING_TARGET,
309 STOP_TARGETING_SHIP,
310 TOGGLE_AUTO_TARGETING,
311 TARGET_SUBOBJECT_IN_RETICLE,
312 TARGET_PREV_SUBOBJECT,
313 TARGET_NEXT_SUBOBJECT,
314 STOP_TARGETING_SUBSYSTEM,
315 TARGET_NEWEST_SHIP,
316 TARGET_NEXT_LIVE_TURRET,
317 TARGET_PREV_LIVE_TURRET,
318 TARGET_NEXT_BOMB,
319 TARGET_PREV_BOMB,
320
321 VIEW_CHASE,
322 VIEW_OTHER_SHIP,
323 VIEW_TOPDOWN,
324
325 SHOW_GOALS,
326
327 ADD_REMOVE_ESCORT,
328 ESCORT_CLEAR,
329 TARGET_NEXT_ESCORT_SHIP,
330 TARGET_CLOSEST_REPAIR_SHIP,
331
332 MULTI_MESSAGE_ALL,
333 MULTI_MESSAGE_FRIENDLY,
334 MULTI_MESSAGE_HOSTILE,
335 MULTI_MESSAGE_TARGET,
336 MULTI_OBSERVER_ZOOM_TO,
337
338 TIME_SPEED_UP,
339 TIME_SLOW_DOWN
340 };
341
342 int Critical_key_set[] = {
343 CYCLE_NEXT_PRIMARY,
344 CYCLE_PREV_PRIMARY,
345 CYCLE_SECONDARY,
346 CYCLE_NUM_MISSLES,
347 INCREASE_WEAPON,
348 DECREASE_WEAPON,
349 INCREASE_SHIELD,
350 DECREASE_SHIELD,
351 INCREASE_ENGINE,
352 DECREASE_ENGINE,
353 ETS_EQUALIZE,
354 SHIELD_EQUALIZE,
355 SHIELD_XFER_TOP,
356 SHIELD_XFER_BOTTOM,
357 SHIELD_XFER_LEFT,
358 SHIELD_XFER_RIGHT,
359 XFER_SHIELD,
360 XFER_LASER,
361 };
362
363 int Non_critical_key_set[] = {
364 MATCH_TARGET_SPEED,
365 TOGGLE_AUTO_MATCH_TARGET_SPEED,
366 TARGET_NEXT,
367 TARGET_PREV,
368 TARGET_NEXT_CLOSEST_HOSTILE,
369 TARGET_PREV_CLOSEST_HOSTILE,
370 TOGGLE_AUTO_TARGETING,
371 TARGET_NEXT_CLOSEST_FRIENDLY,
372 TARGET_PREV_CLOSEST_FRIENDLY,
373 TARGET_SHIP_IN_RETICLE,
374 TARGET_LAST_TRANMISSION_SENDER,
375 TARGET_CLOSEST_REPAIR_SHIP,
376 TARGET_CLOSEST_SHIP_ATTACKING_TARGET,
377 STOP_TARGETING_SHIP,
378 TARGET_CLOSEST_SHIP_ATTACKING_SELF,
379 TARGET_TARGETS_TARGET,
380 TARGET_SUBOBJECT_IN_RETICLE,
381 TARGET_PREV_SUBOBJECT,
382 TARGET_NEXT_SUBOBJECT,
383 STOP_TARGETING_SUBSYSTEM,
384 TARGET_NEXT_BOMB,
385 TARGET_PREV_BOMB,
386 TARGET_NEXT_UNINSPECTED_CARGO,
387 TARGET_PREV_UNINSPECTED_CARGO,
388 TARGET_NEWEST_SHIP,
389 TARGET_NEXT_LIVE_TURRET,
390 TARGET_PREV_LIVE_TURRET,
391 ATTACK_MESSAGE,
392 DISARM_MESSAGE,
393 DISABLE_MESSAGE,
394 ATTACK_SUBSYSTEM_MESSAGE,
395 CAPTURE_MESSAGE,
396 ENGAGE_MESSAGE,
397 FORM_MESSAGE,
398 PROTECT_MESSAGE,
399 COVER_MESSAGE,
400 WARP_MESSAGE,
401 IGNORE_MESSAGE,
402 REARM_MESSAGE,
403 VIEW_CHASE,
404 VIEW_EXTERNAL,
405 VIEW_EXTERNAL_TOGGLE_CAMERA_LOCK,
406 VIEW_OTHER_SHIP,
407 VIEW_TOPDOWN,
408 VIEW_TRACK_TARGET,
409 RADAR_RANGE_CYCLE,
410 SQUADMSG_MENU,
411 SHOW_GOALS,
412 END_MISSION,
413 ADD_REMOVE_ESCORT,
414 ESCORT_CLEAR,
415 TARGET_NEXT_ESCORT_SHIP,
416 MULTI_MESSAGE_ALL,
417 MULTI_MESSAGE_FRIENDLY,
418 MULTI_MESSAGE_HOSTILE,
419 MULTI_MESSAGE_TARGET,
420 MULTI_OBSERVER_ZOOM_TO,
421 TOGGLE_HUD_CONTRAST,
422
423 MULTI_TOGGLE_NETINFO,
424 MULTI_SELF_DESTRUCT,
425
426 TOGGLE_HUD,
427
428 HUD_TARGETBOX_TOGGLE_WIREFRAME,
429 AUTO_PILOT_TOGGLE,
430 NAV_CYCLE,
431 TOGGLE_GLIDING,
432 CYCLE_PRIMARY_WEAPON_SEQUENCE
433 };
434
435 int Ignored_keys[CCFG_MAX];
436
437 // set sizes of the key sets automatically
438 int Normal_key_set_size = sizeof(Normal_key_set) / sizeof(int);
439 int Dead_key_set_size = sizeof(Dead_key_set) / sizeof(int);
440 int Critical_key_set_size = sizeof(Critical_key_set) / sizeof(int);
441 int Non_critical_key_set_size = sizeof(Non_critical_key_set) / sizeof(int);
442
443 // --------------------------------------------------------------
444 // routine to process keys used only for debugging
445 // --------------------------------------------------------------
446
debug_cycle_player_ship(int delta)447 void debug_cycle_player_ship(int delta)
448 {
449 if ( Player_obj == NULL )
450 return;
451
452 int si_index = Ships[Player_obj->instance].ship_info_index;
453 int sanity = 0;
454 ship_info *sip;
455 while ( TRUE ) {
456 si_index += delta;
457 if ( si_index > Num_ship_classes ){
458 si_index = 0;
459 }
460 if ( si_index < 0 ){
461 si_index = Num_ship_classes - 1;
462 }
463 sip = &Ship_info[si_index];
464 if ( sip->flags & SIF_PLAYER_SHIP ){
465 break;
466 }
467
468 // just in case
469 sanity++;
470 if ( sanity > Num_ship_classes ){
471 break;
472 }
473 }
474
475 change_ship_type(Player_obj->instance, si_index);
476 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Player ship changed to %s", 0), Ship_info[si_index].name);
477 }
478
479 /**
480 * Cycle targeted ship to next ship in that species
481 * @param delta Increment
482 */
debug_cycle_targeted_ship(int delta)483 void debug_cycle_targeted_ship(int delta)
484 {
485 object *objp;
486 ship_info *sip;
487 int si_index, species;
488 char name[NAME_LENGTH];
489
490 if ( Player_ai->target_objnum == -1 )
491 return;
492
493 objp = &Objects[Player_ai->target_objnum];
494 if ( objp->type != OBJ_SHIP )
495 return;
496
497 si_index = Ships[objp->instance].ship_info_index;
498 Assert(si_index != -1 );
499 species = Ship_info[si_index].species;
500
501 int sanity = 0;
502
503 while ( TRUE ) {
504 si_index += delta;
505 if ( si_index > Num_ship_classes )
506 si_index = 0;
507 if ( si_index < 0 )
508 si_index = Num_ship_classes-1;
509
510
511 sip = &Ship_info[si_index];
512
513 // if it has test in the name, jump over it
514 strcpy_s(name, sip->name);
515 _strlwr(name);
516 if ( strstr(name,NOX("test")) != NULL )
517 continue;
518
519 if ( sip->species == species && (sip->flags & (SIF_FIGHTER | SIF_BOMBER | SIF_TRANSPORT) ) )
520 break;
521
522 // just in case
523 sanity++;
524 if ( sanity > Num_ship_classes )
525 break;
526 }
527
528 change_ship_type(objp->instance, si_index);
529 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Changed player target to %s", 1), Ship_info[si_index].name);
530 }
531
debug_max_secondary_weapons(object * objp)532 void debug_max_secondary_weapons(object *objp)
533 {
534 int index;
535 ship *shipp = &Ships[objp->instance];
536 ship_info *sip = &Ship_info[shipp->ship_info_index];
537 ship_weapon *swp = &shipp->weapons;
538
539 for ( index = 0; index < MAX_SHIP_SECONDARY_BANKS; index++ )
540 {
541 swp->secondary_bank_ammo[index] = sip->secondary_bank_ammo_capacity[index];
542 }
543 }
544
debug_max_primary_weapons(object * objp)545 void debug_max_primary_weapons(object *objp) // Goober5000
546 {
547 Assert(objp); // Goober5000
548
549 int index;
550 ship *shipp = &Ships[objp->instance];
551 ship_info *sip = &Ship_info[shipp->ship_info_index];
552 ship_weapon *swp = &shipp->weapons;
553 weapon_info *wip;
554
555 if (sip->flags & SIF_BALLISTIC_PRIMARIES)
556 {
557 for ( index = 0; index < MAX_SHIP_PRIMARY_BANKS; index++ )
558 {
559 wip = &Weapon_info[swp->primary_bank_weapons[index]];
560 if (wip->wi_flags2 & WIF2_BALLISTIC)
561 {
562 float capacity, size;
563 capacity = (float) sip->primary_bank_ammo_capacity[index];
564 size = (float) wip->cargo_size;
565 swp->primary_bank_ammo[index] = fl2i((capacity / size)+0.5f);
566 }
567 }
568 }
569 }
570
debug_change_song(int delta)571 void debug_change_song(int delta)
572 {
573 char buf[256];
574 if ( event_music_next_soundtrack(delta) != -1 ) {
575 event_music_get_soundtrack_name(buf);
576 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Soundtrack changed to: %s", 2), buf);
577
578 } else {
579 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Event music is not playing", 3));
580 }
581 }
582
583 extern void hud_target_asteroid();
584 extern int Framerate_delay;
585
586 extern void snd_stop_any_sound();
587
588 extern vec3d Eye_position;
589 extern matrix Eye_matrix;
590 extern void g3_set_view_matrix(vec3d *view_pos,matrix *view_matrix,float zoom);
591
592 extern int Show_cpu;
593
get_prev_weapon_looped(int current_weapon,int subtype)594 int get_prev_weapon_looped(int current_weapon, int subtype)
595 {
596 int i, new_index;
597
598 for (i = 1; i < Num_weapon_types; i++)
599 {
600 new_index = (Num_weapon_types + current_weapon - i) % Num_weapon_types;
601
602 if(Weapon_info[new_index].subtype == subtype)
603 {
604 return new_index;
605 }
606 }
607
608 return current_weapon;
609 }
610
get_next_weapon_looped(int current_weapon,int subtype)611 int get_next_weapon_looped(int current_weapon, int subtype)
612 {
613 int i, new_index;
614
615 for (i = 1; i < Num_weapon_types; i++)
616 {
617 new_index = (current_weapon + i) % Num_weapon_types;
618
619 if(Weapon_info[new_index].subtype == subtype)
620 {
621 return new_index;
622 }
623 }
624
625 return current_weapon;
626 }
627
process_debug_keys(int k)628 void process_debug_keys(int k)
629 {
630 // Kazan -- NO CHEATS IN MULTI
631 if (Game_mode & GM_MULTIPLAYER)
632 {
633 Cheats_enabled = 0;
634 return;
635 }
636
637 switch (k) {
638 case KEY_DEBUGGED + KEY_Q:
639 Snapshot_all_events = true;
640 break;
641
642 case KEY_DEBUGGED + KEY_H:
643 hud_target_toggle_hidden_from_sensors();
644 break;
645
646 case KEY_DEBUGGED + KEY_F:
647 extern int wacky_scheme;
648 if(wacky_scheme == 3){
649 wacky_scheme = 0;
650 } else {
651 wacky_scheme++;
652 }
653 break;
654
655 case KEY_DEBUGGED + KEY_ALTED + KEY_F:
656 Framerate_delay += 10;
657 HUD_printf(XSTR( "Framerate delay increased to %i milliseconds per frame.", 4), Framerate_delay);
658 break;
659
660 case KEY_DEBUGGED + KEY_ALTED + KEY_SHIFTED + KEY_F:
661 Framerate_delay -= 10;
662 if (Framerate_delay < 0)
663 Framerate_delay = 0;
664
665 HUD_printf(XSTR( "Framerate delay decreased to %i milliseconds per frame.", 5), Framerate_delay);
666 break;
667
668 case KEY_DEBUGGED + KEY_X:
669 case KEY_DEBUGGED1 + KEY_X:
670 HUD_printf("Cloaking has been disabled, thank you for playing fs2_open, %s", Player->callsign);
671 break;
672
673 case KEY_DEBUGGED + KEY_C:
674 case KEY_DEBUGGED1 + KEY_C:
675 if(Player_obj->flags & OF_COLLIDES){
676 obj_set_flags(Player_obj, Player_obj->flags & ~(OF_COLLIDES));
677 HUD_sourced_printf(HUD_SOURCE_HIDDEN, "Player no longer collides");
678 } else {
679 obj_set_flags(Player_obj, Player_obj->flags | OF_COLLIDES);
680 HUD_sourced_printf(HUD_SOURCE_HIDDEN, "Player collides");
681 }
682 break;
683
684 case KEY_DEBUGGED + KEY_SHIFTED + KEY_C:
685 case KEY_DEBUGGED1 + KEY_SHIFTED + KEY_C:
686 Countermeasures_enabled = !Countermeasures_enabled;
687 HUD_printf(XSTR( "Countermeasure firing: %s", 6), Countermeasures_enabled ? XSTR( "ENABLED", 7) : XSTR( "DISABLED", 8));
688 break;
689
690 // Goober5000: this should only be compiled in debug builds, since it crashes release
691 #ifndef NDEBUG
692 case KEY_DEBUGGED + KEY_E:
693 gameseq_post_event(GS_EVENT_EVENT_DEBUG);
694 break;
695 #endif
696
697 // Goober5000: handle time dilation in cheat section
698 case KEY_DEBUGGED + KEY_SHIFTED + KEY_COMMA:
699 case KEY_DEBUGGED1 + KEY_SHIFTED + KEY_COMMA:
700 if ( Game_mode & GM_NORMAL ) {
701 if ( Game_time_compression > (F1_0/MAX_TIME_DIVIDER) ) {
702 change_time_compression(0.5);
703 } else {
704 gamesnd_play_error_beep();
705 }
706 } else {
707 gamesnd_play_error_beep();
708 }
709 break;
710
711 // Goober5000: handle as normal here
712 case KEY_DEBUGGED + KEY_SHIFTED + KEY_PERIOD:
713 case KEY_DEBUGGED1 + KEY_SHIFTED + KEY_PERIOD:
714 if ( Game_mode & GM_NORMAL ) {
715 if ( Game_time_compression < (F1_0*MAX_TIME_MULTIPLIER) ) {
716 change_time_compression(2);
717 } else {
718 gamesnd_play_error_beep();
719 }
720 } else {
721 gamesnd_play_error_beep();
722 }
723 break;
724
725 // Kill! the currently targeted ship.
726 case KEY_DEBUGGED + KEY_K:
727 case KEY_DEBUGGED1 + KEY_K:
728 if (Player_ai->target_objnum != -1) {
729 object *objp = &Objects[Player_ai->target_objnum];
730
731 switch (objp->type) {
732 case OBJ_SHIP:
733
734 // remove guardian flag -- kazan
735 Ships[objp->instance].ship_guardian_threshold = 0;
736
737 ship_apply_local_damage( objp, Player_obj, &objp->pos, 100000.0f, MISS_SHIELDS, CREATE_SPARKS);
738 ship_apply_local_damage( objp, Player_obj, &objp->pos, 1.0f, MISS_SHIELDS, CREATE_SPARKS);
739 break;
740 case OBJ_WEAPON:
741 Weapons[objp->instance].lifeleft = 0.01f;
742 break;
743 }
744 }
745
746 break;
747
748 // play the next mission message
749 case KEY_DEBUGGED + KEY_V:
750 extern int Message_debug_index;
751 extern int Num_messages_playing;
752 // stop any other messages
753 if(Num_messages_playing){
754 message_kill_all(1);
755 }
756
757 // next message
758 if(Message_debug_index >= Num_messages - 1){
759 Message_debug_index = Num_builtin_messages;
760 } else {
761 Message_debug_index++;
762 }
763
764 // play the message
765 message_send_unique_to_player( Messages[Message_debug_index].name, Message_waves[Messages[Message_debug_index].wave_info.index].name, MESSAGE_SOURCE_SPECIAL, MESSAGE_PRIORITY_HIGH, 0, 0 );
766 if (Messages[Message_debug_index].avi_info.index == -1) {
767 HUD_printf("No anim set for message \"%s\"; None will play!", Messages[Message_debug_index].name);
768 }
769 break;
770
771 // play the previous mission message
772 case KEY_DEBUGGED + KEY_SHIFTED + KEY_V:
773 extern int Message_debug_index;
774 extern int Num_messages_playing;
775 // stop any other messages
776 if(Num_messages_playing){
777 message_kill_all(1);
778 }
779
780 // go maybe go down one
781 if(Message_debug_index == Num_builtin_messages - 1){
782 Message_debug_index = Num_builtin_messages;
783 } else if(Message_debug_index > Num_builtin_messages){
784 Message_debug_index--;
785 }
786
787 // play the message
788 message_send_unique_to_player( Messages[Message_debug_index].name, Message_waves[Messages[Message_debug_index].wave_info.index].name, MESSAGE_SOURCE_SPECIAL, MESSAGE_PRIORITY_HIGH, 0, 0 );
789 if (Messages[Message_debug_index].avi_info.index == -1) {
790 HUD_printf("No avi associated with this message; None will play!");
791 }
792 break;
793
794 // reset to the beginning of mission messages
795 case KEY_DEBUGGED + KEY_ALTED + KEY_V:
796 extern int Message_debug_index;
797 Message_debug_index = Num_builtin_messages - 1;
798 HUD_printf("Resetting to first mission message");
799 break;
800
801 // Kill! the currently targeted ship.
802 case KEY_DEBUGGED + KEY_ALTED + KEY_SHIFTED + KEY_K:
803 case KEY_DEBUGGED1 + KEY_ALTED + KEY_SHIFTED + KEY_K:
804 if (Player_ai->target_objnum != -1) {
805 object *objp = &Objects[Player_ai->target_objnum];
806
807 if (objp->type == OBJ_SHIP) {
808 ship_apply_local_damage( objp, Player_obj, &objp->pos, Ships[objp->instance].ship_max_hull_strength * 0.1f + 10.0f, MISS_SHIELDS, CREATE_SPARKS);
809 }
810 }
811 break;
812
813 // Kill the currently targeted subsystem.
814 case KEY_DEBUGGED + KEY_SHIFTED + KEY_K:
815 case KEY_DEBUGGED1 + KEY_SHIFTED + KEY_K:
816 if ((Player_ai->target_objnum != -1) && (Player_ai->targeted_subsys != NULL)) {
817 object *objp = &Objects[Player_ai->target_objnum];
818 if ( objp->type == OBJ_SHIP ) {
819 ship *sp = &Ships[objp->instance];
820 vec3d g_subobj_pos;
821
822 get_subsystem_world_pos(objp, Player_ai->targeted_subsys, &g_subobj_pos);
823
824 do_subobj_hit_stuff(objp, Player_obj, &g_subobj_pos, Player_ai->targeted_subsys->system_info->subobj_num, (float) -Player_ai->targeted_subsys->system_info->type, NULL); //100.0f);
825
826 if ( sp->subsys_info[SUBSYSTEM_ENGINE].aggregate_current_hits <= 0.0f ) {
827 mission_log_add_entry(LOG_SHIP_DISABLED, sp->ship_name, NULL );
828 sp->flags |= SF_DISABLED; // add the disabled flag
829 }
830
831 if ( sp->subsys_info[SUBSYSTEM_TURRET].aggregate_current_hits <= 0.0f ) {
832 mission_log_add_entry(LOG_SHIP_DISARMED, sp->ship_name, NULL );
833 }
834 }
835 }
836 break;
837
838 case KEY_DEBUGGED + KEY_ALTED + KEY_K:
839 case KEY_DEBUGGED1 + KEY_ALTED + KEY_K:
840 {
841 float shield, integrity;
842 vec3d pos, randvec;
843
844 vm_vec_rand_vec_quick(&randvec);
845 vm_vec_scale_add(&pos, &Player_obj->pos, &randvec, Player_obj->radius);
846 ship_apply_local_damage(Player_obj, Player_obj, &pos, 25.0f, MISS_SHIELDS, CREATE_SPARKS);
847 hud_get_target_strength(Player_obj, &shield, &integrity);
848 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "You knocked yourself down to %7.3f percent hull.\n", 9), 100.0f * integrity);
849 break;
850 }
851
852 // Whack down the player's shield and hull by a little more than 50%
853 // Select next object to be viewed by AI.
854 case KEY_DEBUGGED + KEY_I:
855 case KEY_DEBUGGED1 + KEY_I:
856 Player_obj->flags ^= OF_INVULNERABLE;
857 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "You are %s", 10), Player_obj->flags & OF_INVULNERABLE ? XSTR( "now INVULNERABLE!", 11) : XSTR( "no longer invulnerable...", 12));
858 break;
859
860 case KEY_DEBUGGED + KEY_SHIFTED + KEY_I:
861 case KEY_DEBUGGED1 + KEY_SHIFTED + KEY_I:
862 if (Player_ai->target_objnum != -1) {
863 object *objp = &Objects[Player_ai->target_objnum];
864
865 objp->flags ^= OF_INVULNERABLE;
866 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Player's target [%s] is %s", 13), Ships[objp->instance].ship_name, objp->flags & OF_INVULNERABLE ? XSTR( "now INVULNERABLE!", 11) : XSTR( "no longer invulnerable...", 12));
867 }
868 break;
869
870 case KEY_DEBUGGED + KEY_N:
871 AI_watch_object++;
872 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Spewing debug info about object #%d", 14), AI_watch_object);
873 break;
874
875 case KEY_DEBUGGED + KEY_O:
876 case KEY_DEBUGGED1 + KEY_O:
877 toggle_player_object();
878 break;
879
880 case KEY_DEBUGGED + KEY_SHIFTED + KEY_O:
881 extern int Debug_octant;
882 if(Debug_octant == 7){
883 Debug_octant = -1;
884 } else {
885 Debug_octant++;
886 }
887 nprintf(("General", "Debug_octant == %d\n", Debug_octant));
888 break;
889
890 case KEY_DEBUGGED + KEY_P:
891 supernova_start(20);
892 break;
893
894 case KEY_DEBUGGED + KEY_W:
895 case KEY_DEBUGGED1 + KEY_W:
896 case KEY_DEBUGGED + KEY_SHIFTED + KEY_W:
897 case KEY_DEBUGGED1 + KEY_SHIFTED + KEY_W:
898 // temp code for testing purposes, toggles weapon energy cheat
899 Weapon_energy_cheat = !Weapon_energy_cheat;
900 if (Weapon_energy_cheat) {
901 if (k & KEY_SHIFTED)
902 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Weapon energy and missile count will always be at full ALL SHIPS!", 15));
903 else
904 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Weapon energy and missile count will always be at full for player", 16));
905
906 debug_max_secondary_weapons(Player_obj);
907 debug_max_primary_weapons(Player_obj);
908 if (k & KEY_SHIFTED) {
909 object *objp;
910
911 for ( objp = GET_FIRST(&obj_used_list); objp !=END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) )
912 if (objp->type == OBJ_SHIP) {
913 debug_max_secondary_weapons(objp);
914 debug_max_primary_weapons(objp);
915 }
916 }
917
918 } else
919 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Normal weapon energy system / missile count restored", 17));
920
921 break;
922
923 case KEY_DEBUGGED + KEY_G:
924 case KEY_DEBUGGED1 + KEY_G:
925 mission_goal_mark_all_true( PRIMARY_GOAL );
926 break;
927
928 case KEY_DEBUGGED + KEY_G + KEY_SHIFTED:
929 case KEY_DEBUGGED1 + KEY_G + KEY_SHIFTED:
930 mission_goal_mark_all_true( SECONDARY_GOAL );
931 break;
932
933 case KEY_DEBUGGED + KEY_G + KEY_ALTED:
934 case KEY_DEBUGGED1 + KEY_G + KEY_ALTED:
935 mission_goal_mark_all_true( BONUS_GOAL );
936 break;
937
938 case KEY_DEBUGGED + KEY_9: {
939 case KEY_DEBUGGED1 + KEY_9:
940 ship* shipp;
941
942 shipp = &Ships[Player_obj->instance];
943 int *weap = &shipp->weapons.secondary_bank_weapons[shipp->weapons.current_secondary_bank];
944 *weap = get_next_weapon_looped(*weap, WP_MISSILE);
945
946 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Secondary Weapon forced to %s", 18), Weapon_info[*weap].name);
947 break;
948 }
949
950
951 case KEY_DEBUGGED + KEY_SHIFTED + KEY_9: {
952 case KEY_DEBUGGED1 + KEY_SHIFTED + KEY_9:
953 ship* shipp;
954
955 shipp = &Ships[Player_obj->instance];
956 int *weap = &shipp->weapons.secondary_bank_weapons[shipp->weapons.current_secondary_bank];
957 *weap = get_prev_weapon_looped(*weap, WP_MISSILE);
958
959 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Secondary Weapon forced to %s", 18), Weapon_info[*weap].name);
960 break;
961 }
962
963 case KEY_DEBUGGED + KEY_U: {
964 case KEY_DEBUGGED1 + KEY_U:
965 // launch asteroid
966 object *asteroid_create(asteroid_field *asfieldp, int asteroid_type, int subtype);
967 object *objp = asteroid_create(&Asteroid_field, 0, 0);
968 if(objp == NULL) {
969 break;
970 }
971 vec3d vel;
972 vm_vec_copy_scale(&vel, &Player_obj->orient.vec.fvec, 50.0f);
973 objp->phys_info.vel = vel;
974 objp->phys_info.desired_vel = vel;
975 objp->pos = Player_obj->pos;
976 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Asteroid launched", 1595));
977 break;
978 }
979
980 case KEY_DEBUGGED + KEY_0: {
981 case KEY_DEBUGGED1 + KEY_0:
982 ship* shipp;
983
984 shipp = &Ships[Player_obj->instance];
985 int *weap = &shipp->weapons.primary_bank_weapons[shipp->weapons.current_primary_bank];
986 *weap = get_next_weapon_looped(*weap, WP_LASER);
987
988 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Primary Weapon forced to %s", 19), Weapon_info[*weap].name);
989 break;
990 }
991
992 case KEY_DEBUGGED + KEY_SHIFTED + KEY_0: {
993 case KEY_DEBUGGED1 + KEY_SHIFTED + KEY_0:
994 ship* shipp;
995
996 shipp = &Ships[Player_obj->instance];
997 int *weap = &shipp->weapons.primary_bank_weapons[shipp->weapons.current_primary_bank];
998 *weap = get_prev_weapon_looped(*weap, WP_LASER);
999
1000 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Primary Weapon forced to %s", 19), Weapon_info[*weap].name);
1001 break;
1002 }
1003
1004 case KEY_DEBUGGED + KEY_J: {
1005 int new_pattern = event_music_return_current_pattern();
1006
1007 new_pattern++;
1008 if ( new_pattern >= MAX_PATTERNS )
1009 new_pattern = 0;
1010
1011 event_music_change_pattern(new_pattern);
1012 break;
1013 }
1014
1015 case KEY_DEBUGGED + KEY_M: {
1016 if ( Event_music_enabled ) {
1017 event_music_disable();
1018 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Event music disabled", 20));
1019
1020 } else {
1021 event_music_enable();
1022 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Event music enabled", 21));
1023 }
1024
1025 break;
1026 }
1027
1028 case KEY_DEBUGGED + KEY_R:
1029 case KEY_DEBUGGED1 + KEY_R:
1030 {
1031 // rearm the target, if we have one
1032 object *obj_to_rearm = (Player_ai->target_objnum >= 0) ? &Objects[Player_ai->target_objnum] : Player_obj;
1033
1034 if (is_support_allowed(obj_to_rearm))
1035 {
1036 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR("Issuing rearm request for %s", -1), Ships[obj_to_rearm->instance].ship_name);
1037 ai_issue_rearm_request(obj_to_rearm);
1038 }
1039 else
1040 {
1041 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR("Cannot issue rearm request for %s", -1), Ships[obj_to_rearm->instance].ship_name);
1042 }
1043
1044 break;
1045 }
1046
1047 case KEY_DEBUGGED + KEY_SHIFTED + KEY_UP:
1048 Game_detail_level++;
1049 HUD_printf( XSTR( "Detail level set to %+d\n", 22), Game_detail_level );
1050 break;
1051
1052 case KEY_DEBUGGED + KEY_SHIFTED + KEY_DOWN:
1053 Game_detail_level--;
1054 HUD_printf( XSTR( "Detail level set to %+d\n", 22), Game_detail_level );
1055 break;
1056
1057 #ifndef NDEBUG
1058 case KEY_DEBUGGED + KEY_SHIFTED + KEY_T: {
1059 extern int Test_begin;
1060
1061 if ( Test_begin == 1 )
1062 break;
1063
1064 Test_begin = 1;
1065 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Frame Rate test started", 23));
1066
1067 break;
1068 }
1069 #endif
1070 case KEY_DEBUGGED + KEY_A: {
1071
1072 HUD_printf("frame rate currently is %0.2 FPS", 1/flFrametime);
1073
1074 break;
1075 }
1076
1077
1078 case KEY_DEBUGGED + KEY_D:
1079 extern int OO_update_index;
1080
1081 if(MULTIPLAYER_MASTER){
1082 do {
1083 OO_update_index++;
1084 } while((OO_update_index < (MAX_PLAYERS-1)) && !MULTI_CONNECTED(Net_players[OO_update_index]));
1085 if(OO_update_index >= MAX_PLAYERS-1){
1086 OO_update_index = -1;
1087 }
1088 } else {
1089 if(OO_update_index < 0){
1090 OO_update_index = MY_NET_PLAYER_NUM;
1091 } else {
1092 OO_update_index = -1;
1093 }
1094 }
1095 break;
1096
1097 // change player ship to next flyable type
1098 case KEY_DEBUGGED + KEY_RIGHT:
1099 debug_cycle_player_ship(1);
1100 break;
1101
1102 // change player ship to previous flyable ship
1103 case KEY_DEBUGGED + KEY_LEFT:
1104 debug_cycle_player_ship(-1);
1105 break;
1106
1107 // cycle target to ship
1108 case KEY_DEBUGGED + KEY_SHIFTED + KEY_RIGHT:
1109 debug_cycle_targeted_ship(1);
1110 break;
1111
1112 // cycle target to previous ship
1113 case KEY_DEBUGGED + KEY_SHIFTED + KEY_LEFT:
1114 debug_cycle_targeted_ship(-1);
1115 break;
1116
1117 // change species of the targeted ship
1118 case KEY_DEBUGGED + KEY_S: {
1119 if ( Player_ai->target_objnum < 0 )
1120 break;
1121
1122 object *objp;
1123 ship_info *sip;
1124
1125 objp = &Objects[Player_ai->target_objnum];
1126 if ( objp->type != OBJ_SHIP )
1127 return;
1128
1129 sip = &Ship_info[Ships[objp->instance].ship_info_index];
1130 sip->species++;
1131
1132 if (sip->species >= (int)Species_info.size())
1133 sip->species = 0;
1134
1135 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Species of target changed to: %s", 24), Species_info[sip->species].species_name);
1136 break;
1137 }
1138
1139 case KEY_DEBUGGED + KEY_SHIFTED + KEY_S:
1140 game_increase_skill_level();
1141 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Skill level set to %s.", 25), Skill_level_names(Game_skill_level));
1142 break;
1143
1144 case KEY_DEBUGGED + KEY_T: {
1145 char buf[256];
1146 event_music_get_info(buf);
1147 HUD_sourced_printf(HUD_SOURCE_HIDDEN, buf);
1148 break;
1149 }
1150
1151 case KEY_DEBUGGED + KEY_UP:
1152 case KEY_DEBUGGED1 + KEY_UP:
1153 debug_change_song(1);
1154 break;
1155
1156 case KEY_DEBUGGED + KEY_DOWN:
1157 case KEY_DEBUGGED1 + KEY_DOWN:
1158 debug_change_song(-1);
1159 break;
1160
1161 case KEY_PADMINUS: {
1162 int init_flag = 0;
1163
1164 if ( keyd_pressed[KEY_1] ) {
1165 init_flag = 1;
1166 HUD_color_red -= 4;
1167 }
1168
1169 if ( keyd_pressed[KEY_2] ) {
1170 init_flag = 1;
1171 HUD_color_green -= 4;
1172 }
1173
1174 if ( keyd_pressed[KEY_3] ) {
1175 init_flag = 1;
1176 HUD_color_blue -= 4;
1177 }
1178
1179 if (init_flag)
1180 HUD_init_colors();
1181
1182 break;
1183 }
1184
1185 case KEY_DEBUGGED + KEY_Y:
1186 extern int tst;
1187 tst = 2;
1188 break;
1189
1190 case KEY_PADPLUS: {
1191 int init_flag = 0;
1192
1193 if ( keyd_pressed[KEY_1] ) {
1194 init_flag = 1;
1195 HUD_color_red += 4;
1196 }
1197
1198 if ( keyd_pressed[KEY_2] ) {
1199 init_flag = 1;
1200 HUD_color_green += 4;
1201 }
1202
1203 if ( keyd_pressed[KEY_3] ) {
1204 init_flag = 1;
1205 HUD_color_blue += 4;
1206 }
1207
1208 if (init_flag)
1209 HUD_init_colors();
1210
1211 break;
1212 }
1213 case KEY_DEBUGGED + KEY_ALTED + KEY_EQUAL:
1214 case KEY_DEBUGGED1 + KEY_ALTED + KEY_EQUAL:
1215 {
1216 camera *cam = Main_camera.getCamera();
1217 if(cam == NULL)
1218 {
1219 HUD_sourced_printf(HUD_SOURCE_HIDDEN, "Couldn't get camera FOV");
1220 break;
1221 }
1222 cam->set_fov(cam->get_fov() + 0.1f);
1223 HUD_sourced_printf(HUD_SOURCE_HIDDEN, "Camera fov raised to %0.2f" , cam->get_fov());
1224 }
1225 break;
1226
1227 case KEY_DEBUGGED + KEY_ALTED + KEY_MINUS:
1228 case KEY_DEBUGGED1 + KEY_ALTED + KEY_MINUS:
1229 {
1230 camera *cam = Main_camera.getCamera();
1231 if(cam == NULL)
1232 {
1233 HUD_sourced_printf(HUD_SOURCE_HIDDEN, "Couldn't get camera FOV");
1234 break;
1235 }
1236 cam->set_fov(cam->get_fov() - 0.1f);
1237 HUD_sourced_printf(HUD_SOURCE_HIDDEN, "Camera fov lowered to %0.2f" , cam->get_fov());
1238 }
1239 break;
1240 case KEY_DEBUGGED + KEY_Z:
1241 case KEY_DEBUGGED1 + KEY_Z:
1242 {
1243 Show_cpu = !Show_cpu;
1244 }
1245 break;
1246
1247 } // end switch
1248 }
1249
ppsk_hotkeys(int k)1250 void ppsk_hotkeys(int k)
1251 {
1252 // use k to check for keys that can have Shift,Ctrl,Alt,Del status
1253 int hotkey_set;
1254
1255 #ifndef NDEBUG
1256 k &= ~KEY_DEBUGGED; // since hitting F11 will set this bit
1257 #endif
1258
1259 switch (k) {
1260 case KEY_F5:
1261 case KEY_F6:
1262 case KEY_F7:
1263 case KEY_F8:
1264 case KEY_F9:
1265 case KEY_F10:
1266 case KEY_F11:
1267 case KEY_F12:
1268 hotkey_set = mission_hotkey_get_set_num(k);
1269 if ( !(Players[Player_num].flags & PLAYER_FLAGS_MSG_MODE) )
1270 hud_target_hotkey_select( hotkey_set );
1271 else
1272 hud_squadmsg_hotkey_select( hotkey_set );
1273
1274 break;
1275
1276 case KEY_F5 + KEY_SHIFTED:
1277 case KEY_F6 + KEY_SHIFTED:
1278 case KEY_F7 + KEY_SHIFTED:
1279 case KEY_F8 + KEY_SHIFTED:
1280 case KEY_F9 + KEY_SHIFTED:
1281 case KEY_F10 + KEY_SHIFTED:
1282 case KEY_F11 + KEY_SHIFTED:
1283 case KEY_F12 + KEY_SHIFTED:
1284 hotkey_set = mission_hotkey_get_set_num(k&(~KEY_SHIFTED));
1285 mprintf(("Adding to set %d\n", hotkey_set+1));
1286 if ( Player_ai->target_objnum == -1)
1287 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "No target to add/remove from set %d.", 26), hotkey_set+1);
1288 else {
1289 hud_target_hotkey_add_remove( hotkey_set, &Objects[Player_ai->target_objnum], HOTKEY_USER_ADDED);
1290 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "%s added to set %d. (F%d)", 27), Ships[Objects[Player_ai->target_objnum].instance].ship_name, hotkey_set, 4+hotkey_set+1);
1291 }
1292
1293 break;
1294
1295 case KEY_F5 + KEY_SHIFTED + KEY_ALTED:
1296 case KEY_F6 + KEY_SHIFTED + KEY_ALTED:
1297 case KEY_F7 + KEY_SHIFTED + KEY_ALTED:
1298 case KEY_F8 + KEY_SHIFTED + KEY_ALTED:
1299 case KEY_F9 + KEY_SHIFTED + KEY_ALTED:
1300 case KEY_F10 + KEY_SHIFTED + KEY_ALTED:
1301 case KEY_F11 + KEY_SHIFTED + KEY_ALTED:
1302 case KEY_F12 + KEY_SHIFTED + KEY_ALTED:
1303 hotkey_set = mission_hotkey_get_set_num(k & ~KEY_SHIFTED+KEY_ALTED);
1304 hud_target_hotkey_clear( hotkey_set );
1305 break;
1306
1307 case KEY_SHIFTED + KEY_MINUS:
1308 if ( HUD_color_alpha > HUD_COLOR_ALPHA_USER_MIN ) {
1309 HUD_color_alpha--;
1310 HUD_init_colors();
1311 }
1312 break;
1313
1314 case KEY_SHIFTED + KEY_EQUAL:
1315 if ( HUD_color_alpha < HUD_COLOR_ALPHA_USER_MAX ) {
1316 HUD_color_alpha++;
1317 HUD_init_colors();
1318 }
1319 break;
1320 } // end switch
1321 }
1322
1323 /**
1324 * Check keypress 'key' against a set of valid controls and mark the match in the
1325 * player's button info bitfield. Also checks joystick controls in the set.
1326 *
1327 * @param key Scancode (plus modifiers).
1328 * @param count Total size of the list
1329 * @param list List of ::Control_config struct action indices to check for
1330 */
process_set_of_keys(int key,int count,int * list)1331 void process_set_of_keys(int key, int count, int *list)
1332 {
1333 int i;
1334
1335 for (i=0; i<count; i++)
1336 if (check_control(list[i], key))
1337 button_info_set(&Player->bi, list[i]);
1338 }
1339
1340 /**
1341 * Routine to process keys used for player ship stuff (*not* ship movement).
1342 */
process_player_ship_keys(int k)1343 void process_player_ship_keys(int k)
1344 {
1345 int masked_k;
1346
1347 masked_k = k & ~KEY_CTRLED; // take out CTRL modifier only
1348
1349 // moved this line to beginning of function since hotkeys now encompass
1350 // F5 - F12. We can return after using F11 as a hotkey.
1351 ppsk_hotkeys(masked_k);
1352 if (keyd_pressed[KEY_DEBUG_KEY]){
1353 return;
1354 }
1355
1356 // if we're in supernova mode. do nothing
1357 if(Player->control_mode == PCM_SUPERNOVA){
1358 return;
1359 }
1360
1361 // pass the key to the squadmate messaging code. If the messaging code took the key, then return
1362 // from here immediately since we don't want to do further key processing.
1363 if ( hud_squadmsg_read_key(k) )
1364 return;
1365
1366 if ( Player->control_mode == PCM_NORMAL ) {
1367 // The following things are not legal to do while dead.
1368 if ( !(Game_mode & GM_DEAD) ) {
1369 process_set_of_keys(masked_k, Normal_key_set_size, Normal_key_set);
1370 } else {
1371 process_set_of_keys(masked_k, Dead_key_set_size, Dead_key_set);
1372 }
1373 if (lua_game_control & LGC_B_POLL_ALL) {
1374 // first clear all
1375 button_info_clear(&Player->lua_bi_full);
1376
1377 // then check the keys.
1378 int i;
1379 for(i = 0; i < CCFG_MAX; i++) {
1380 if (check_control(i, masked_k))
1381 button_info_set(&Player->lua_bi_full, i);
1382 }
1383 }
1384 } else {
1385
1386 }
1387 }
1388
1389 /**
1390 * Handler for when player hits 'ESC' during the game
1391 */
game_do_end_mission_popup()1392 void game_do_end_mission_popup()
1393 {
1394 int pf_flags, choice;
1395
1396 // do the multiplayer version of this
1397 if(Game_mode & GM_MULTIPLAYER){
1398 multi_quit_game(PROMPT_ALL);
1399 } else {
1400 // single player version....
1401 // do housekeeping things.
1402 game_stop_time();
1403 game_stop_looped_sounds();
1404 snd_stop_all();
1405
1406 quit_mission_popup_shown = true;
1407
1408 pf_flags = PF_BODY_BIG | PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON;
1409 choice = popup(pf_flags, 3, POPUP_NO, XSTR( "&Yes, Quit", 28), XSTR( "Yes, &Restart", 29), XSTR( "Do you really want to end the mission?", 30));
1410
1411 switch (choice) {
1412 case 1:
1413 gameseq_post_event(GS_EVENT_END_GAME);
1414 break;
1415
1416 case 2:
1417 gameseq_post_event(GS_EVENT_ENTER_GAME);
1418 break;
1419
1420 default:
1421 break; // do nothing
1422 }
1423 quit_mission_popup_shown = false;
1424
1425 game_start_time();
1426 game_flush();
1427 }
1428 }
1429
1430 /**
1431 * Handle pause keypress
1432 */
game_process_pause_key()1433 void game_process_pause_key()
1434 {
1435 // special processing for multiplayer
1436 if (Game_mode & GM_MULTIPLAYER) {
1437 if(Multi_pause_status){
1438 multi_pause_request(0);
1439 } else {
1440 multi_pause_request(1);
1441 }
1442 } else {
1443 gameseq_post_event( GS_EVENT_PAUSE_GAME );
1444 }
1445 }
1446
1447 /**
1448 * Process cheat codes
1449 */
game_process_cheats(int k)1450 void game_process_cheats(int k)
1451 {
1452 size_t i;
1453
1454 if ( k == 0 ){
1455 return;
1456 }
1457
1458 // no cheats in multiplayer, ever
1459 if(Game_mode & GM_MULTIPLAYER){
1460 Cheats_enabled = 0;
1461 return;
1462 }
1463
1464 for (i = 0; i < CHEAT_BUFFER_LEN; i++){
1465 CheatBuffer[i]=CheatBuffer[i+1];
1466 }
1467
1468 CheatBuffer[CHEAT_BUFFER_LEN - 1] = (char)key_to_ascii(k);
1469
1470 cheatCode detectedCheatCode = CHEAT_CODE_NONE;
1471
1472 for(i=0; i < CHEATS_TABLE_LEN; i++) {
1473 Cheat cheat = cheatsTable[i];
1474
1475 if(!strncmp(cheat.data, CheatBuffer, CHEAT_BUFFER_LEN)){
1476 detectedCheatCode = cheat.code;
1477 break;
1478 }
1479 }
1480
1481 if(detectedCheatCode == CHEAT_CODE_FREESPACE){
1482 Cheats_enabled = 1;
1483
1484 // cheating allows the changing of weapons so we have to grab anything
1485 // that we don't already have loaded, just in case
1486 extern void weapons_page_in_cheats();
1487 weapons_page_in_cheats();
1488
1489 HUD_printf("Cheats enabled");
1490 }
1491 if(detectedCheatCode == CHEAT_CODE_FISH){
1492 // only enable in the Vasudan main hall
1493 if ((gameseq_get_state() == GS_STATE_MAIN_MENU) && main_hall_is_vasudan()) {
1494 extern void fishtank_start();
1495 fishtank_start();
1496 }
1497 }
1498 if(detectedCheatCode == CHEAT_CODE_HEADZ){
1499 // only enable in the Vasudan main hall
1500 if ((gameseq_get_state() == GS_STATE_MAIN_MENU) && main_hall_is_vasudan()) {
1501 main_hall_vasudan_funny();
1502 }
1503 }
1504 if(detectedCheatCode == CHEAT_CODE_SKIP && (gameseq_get_state() == GS_STATE_MAIN_MENU)){
1505 extern void main_hall_campaign_cheat();
1506 main_hall_campaign_cheat();
1507 }
1508 if(detectedCheatCode == CHEAT_CODE_TOOLED && (Game_mode & GM_IN_MISSION)){
1509 Tool_enabled = 1;
1510 HUD_printf("Prepare to be taken to school");
1511 }
1512 if(detectedCheatCode == CHEAT_CODE_PIRATE && (Game_mode & GM_IN_MISSION) && (Player_obj != NULL)){
1513 extern void prevent_spawning_collision(object *new_obj);
1514 ship_subsys *ptr;
1515 char name[NAME_LENGTH];
1516 int ship_idx, ship_class;
1517
1518 // if not found, then don't create it :(
1519 ship_class = ship_info_lookup("Volition Bravos");
1520 if (ship_class < 0)
1521 return;
1522
1523 HUD_printf(NOX("Walk the plank"));
1524
1525 vec3d pos = Player_obj->pos;
1526 matrix orient = Player_obj->orient;
1527 pos.xyz.x += frand_range(-700.0f, 700.0f);
1528 pos.xyz.y += frand_range(-700.0f, 700.0f);
1529 pos.xyz.z += frand_range(-700.0f, 700.0f);
1530
1531 int objnum = ship_create(&orient, &pos, ship_class);
1532 if (objnum < 0)
1533 return;
1534
1535 ship *shipp = &Ships[Objects[objnum].instance];
1536 shipp->ship_name[0] = '\0';
1537 shipp->orders_accepted = (1<<NUM_COMM_ORDER_ITEMS)-1;
1538
1539 // Goober5000 - stolen from support ship creation
1540 // create a name for the ship. use "Volition Bravos #". look for collisions until one isn't found anymore
1541 ship_idx = 1;
1542 do {
1543 sprintf(name, NOX("Volition Bravos %d"), ship_idx);
1544 if ( (ship_name_lookup(name) == -1) && (ship_find_exited_ship_by_name(name) == -1) )
1545 {
1546 strcpy_s(shipp->ship_name, name);
1547 break;
1548 }
1549
1550 ship_idx++;
1551 } while(1);
1552
1553 shipp->flags |= SF_ESCORT;
1554 shipp->escort_priority = 1000 - ship_idx;
1555
1556 // now make sure we're not colliding with anyone
1557 prevent_spawning_collision(&Objects[objnum]);
1558
1559 // Goober5000 - beam free
1560 for (ptr = GET_FIRST(&shipp->subsys_list); ptr != END_OF_LIST(&shipp->subsys_list); ptr = GET_NEXT(ptr))
1561 {
1562 // mark all turrets as beam free
1563 if (ptr->system_info->type == SUBSYSTEM_TURRET)
1564 {
1565 ptr->weapons.flags |= SW_FLAG_BEAM_FREE;
1566 ptr->turret_next_fire_stamp = timestamp((int) frand_range(50.0f, 4000.0f));
1567 }
1568 }
1569
1570 // warpin
1571 shipfx_warpin_start(&Objects[objnum]);
1572 }
1573 }
1574
game_process_keys()1575 void game_process_keys()
1576 {
1577 int k;
1578
1579 button_info_clear(&Player->bi); // clear out the button info struct for the player
1580 do
1581 {
1582 k = game_poll();
1583
1584 if ( Game_mode & GM_DEAD_BLEW_UP ) {
1585 continue;
1586 }
1587
1588 game_process_cheats( k );
1589 process_player_ship_keys(k);
1590 process_debug_keys(k);
1591
1592 switch (k) {
1593 case 0:
1594 // No key
1595 break;
1596
1597 case KEY_ESC:
1598 if ( Player->control_mode != PCM_NORMAL ) {
1599 if ( Player->control_mode == PCM_WARPOUT_STAGE1 ) {
1600 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
1601 } else {
1602 // too late to abort warp out!
1603 }
1604 } else {
1605 // let the ESC key break out of messaging mode
1606 if ( Players[Player_num].flags & PLAYER_FLAGS_MSG_MODE ) {
1607 hud_squadmsg_toggle();
1608 break;
1609 }
1610
1611 //If topdown view in non-2D mission, go back to cockpit view.
1612 if ( (Viewer_mode & VM_TOPDOWN) && !(The_mission.flags & MISSION_FLAG_2D_MISSION) && !(Perspective_locked) ) {
1613 Viewer_mode &= ~VM_TOPDOWN;
1614 break;
1615 }
1616
1617 // if in external view or chase view, go back to cockpit view
1618 if ( (Viewer_mode & (VM_EXTERNAL|VM_CHASE|VM_OTHER_SHIP)) && !(Perspective_locked) ) {
1619 Viewer_mode &= ~(VM_EXTERNAL|VM_CHASE|VM_OTHER_SHIP);
1620 break;
1621 }
1622
1623 if (!(Game_mode & GM_DEAD_DIED))
1624 game_do_end_mission_popup();
1625
1626 }
1627 break;
1628
1629 case KEY_Y:
1630 break;
1631
1632 case KEY_N:
1633 break;
1634
1635 case KEY_ALTED + KEY_SHIFTED+KEY_J:
1636 // treat the current joystick position as the center position
1637 joy_set_cen();
1638 break;
1639
1640 case KEY_DEBUGGED | KEY_PAUSE:
1641 gameseq_post_event( GS_EVENT_DEBUG_PAUSE_GAME );
1642 break;
1643
1644 case KEY_ALTED + KEY_PAUSE:
1645 if( Game_mode & GM_DEAD_BLEW_UP ||
1646 Game_mode & GM_DEAD_DIED) {
1647 break;
1648 }
1649
1650 pause_set_type(PAUSE_TYPE_VIEWER);
1651 game_process_pause_key();
1652 break;
1653 case KEY_PAUSE:
1654 if( Game_mode & GM_DEAD_BLEW_UP ||
1655 Game_mode & GM_DEAD_DIED) {
1656 break;
1657 }
1658
1659 pause_set_type(PAUSE_TYPE_NORMAL);
1660 game_process_pause_key();
1661 break;
1662
1663 } // end switch
1664 }
1665 while (k);
1666
1667 // lua button command override goes here!!
1668 if (lua_game_control & LGC_B_OVERRIDE) {
1669 button_info temp = Player->bi;
1670 Player->bi = Player->lua_bi;
1671 Player->lua_bi = temp;
1672 } else if (lua_game_control & LGC_B_ADDITIVE) {
1673 // add the lua commands to current commands
1674 int i;
1675 for (i=0; i<NUM_BUTTON_FIELDS; i++)
1676 Player->bi.status[i] |= Player->lua_bi.status[i];
1677 Player->lua_bi = Player->bi;
1678 } else {
1679 // just copy over the values
1680 Player->lua_bi = Player->bi;
1681 }
1682 // there.. wasnt that bad hack was it?
1683
1684 button_info_do(&Player->bi); // call functions based on status of button_info bit vectors
1685 }
1686
button_function_critical(int n,net_player * p=NULL)1687 int button_function_critical(int n, net_player *p = NULL)
1688 {
1689 object *objp;
1690 player *pl;
1691 net_player *npl;
1692 int at_self; // flag indicating the object is local (for hud messages, etc)
1693
1694 Assert(n >= 0);
1695
1696 // multiplayer clients should leave critical button bits alone and pass them to the server instead
1697 if (MULTIPLAYER_CLIENT) {
1698 // if this flag is set, we should apply the button itself (came from the server)
1699 if (!Multi_button_info_ok){
1700 return 0;
1701 }
1702 }
1703
1704 // in single player mode make sure we're using the player object and the player himself, otherwise use the object and
1705 // player pertaining to the passed net_player
1706 npl = NULL;
1707 if (p == NULL) {
1708 objp = Player_obj;
1709 pl = Player;
1710
1711 if(Game_mode & GM_MULTIPLAYER){
1712 npl = Net_player;
1713
1714 // if we're the server in multiplayer and we're an observer, don't process our own critical button functions
1715 if((Net_player->flags & NETINFO_FLAG_AM_MASTER) && (Net_player->flags & NETINFO_FLAG_OBSERVER)){
1716 return 0;
1717 }
1718 }
1719
1720 at_self = 1;
1721 } else {
1722 objp = &Objects[p->m_player->objnum];
1723 pl = p->m_player;
1724 npl = p;
1725 at_self = 0;
1726
1727 if ( NETPLAYER_IS_DEAD(npl) || (Ships[Objects[pl->objnum].instance].flags & SF_DYING) )
1728 return 0;
1729 }
1730
1731 switch (n) {
1732 // cycle num primaries to fire at once
1733 case CYCLE_PRIMARY_WEAPON_SEQUENCE:
1734 {
1735 int count;
1736 ship * shipp = &Ships[objp->instance];
1737 ship_weapon *swp = &shipp->weapons;
1738 ship_info *sip = &Ship_info[shipp->ship_info_index];
1739 polymodel *pm = model_get( sip->model_num );
1740 count = ftables.getNextSlots( pm->gun_banks[ swp->current_primary_bank ].num_slots, swp->primary_bank_slot_count[ swp->current_primary_bank ] );
1741 swp->primary_bank_slot_count[ swp->current_primary_bank ] = count;
1742 shipp->last_fired_point[ swp->current_primary_bank ] += count - ( shipp->last_fired_point[ swp->current_primary_bank ] % count);
1743 shipp->last_fired_point[ swp->current_primary_bank ] -= 1;
1744 shipp->last_fired_point[ swp->current_primary_bank ] %= swp->primary_bank_slot_count[ swp->current_primary_bank ];
1745 }
1746 break;
1747
1748 // cycle to next primary weapon
1749 case CYCLE_NEXT_PRIMARY:
1750 if (at_self) {
1751 control_used(CYCLE_NEXT_PRIMARY);
1752 }
1753
1754 hud_gauge_popup_start(HUD_WEAPONS_GAUGE);
1755 if (ship_select_next_primary(objp, CYCLE_PRIMARY_NEXT)) {
1756 ship* shipp = &Ships[objp->instance];
1757 if ( timestamp_elapsed(shipp->weapons.next_primary_fire_stamp[shipp->weapons.current_primary_bank]) ) {
1758 shipp->weapons.next_primary_fire_stamp[shipp->weapons.current_primary_bank] = timestamp(250); // 1/4 second delay until can fire
1759 }
1760
1761 // multiplayer server should maintain bank/link status here
1762 if ( MULTIPLAYER_MASTER ) {
1763 Assert(npl != NULL);
1764 multi_server_update_player_weapons(npl,shipp);
1765 }
1766 }
1767 break;
1768
1769 // cycle to previous primary weapon
1770 case CYCLE_PREV_PRIMARY:
1771 if (at_self) {
1772 control_used(CYCLE_PREV_PRIMARY);
1773 }
1774
1775 hud_gauge_popup_start(HUD_WEAPONS_GAUGE);
1776 if (ship_select_next_primary(objp, CYCLE_PRIMARY_PREV)) {
1777 ship* shipp = &Ships[objp->instance];
1778 if ( timestamp_elapsed(shipp->weapons.next_primary_fire_stamp[shipp->weapons.current_primary_bank]) ) {
1779 shipp->weapons.next_primary_fire_stamp[shipp->weapons.current_primary_bank] = timestamp(250); // 1/4 second delay until can fire
1780 }
1781
1782 // multiplayer server should maintain bank/link status here
1783 if ( MULTIPLAYER_MASTER ) {
1784 Assert(npl != NULL);
1785 multi_server_update_player_weapons(npl,shipp);
1786 }
1787 }
1788 break;
1789
1790 // cycle to next secondary weapon
1791 case CYCLE_SECONDARY:
1792 if(at_self)
1793 control_used(CYCLE_SECONDARY);
1794
1795 hud_gauge_popup_start(HUD_WEAPONS_GAUGE);
1796 if (ship_select_next_secondary(objp)) {
1797 ship* shipp = &Ships[objp->instance];
1798 if ( timestamp_elapsed(shipp->weapons.next_secondary_fire_stamp[shipp->weapons.current_secondary_bank]) ) {
1799 shipp->weapons.next_secondary_fire_stamp[shipp->weapons.current_secondary_bank] = timestamp(250); // 1/4 second delay until can fire
1800 }
1801
1802 // multiplayer server should maintain bank/link status here
1803 if( MULTIPLAYER_MASTER ){
1804 Assert(npl != NULL);
1805 multi_server_update_player_weapons(npl,shipp);
1806 }
1807 }
1808 break;
1809
1810 // cycle number of missiles
1811 case CYCLE_NUM_MISSLES: {
1812 if(at_self)
1813 control_used(CYCLE_NUM_MISSLES);
1814
1815 if ( objp == Player_obj ) {
1816 if ( Player_ship->weapons.num_secondary_banks <= 0 ) {
1817 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "This ship has no secondary weapons", 33));
1818 gamesnd_play_iface(SND_GENERAL_FAIL);
1819 break;
1820 }
1821 }
1822
1823 polymodel *pm = model_get(Ship_info[Ships[objp->instance].ship_info_index].model_num);
1824
1825 int firepoints = pm->missile_banks[Ships[objp->instance].weapons.current_secondary_bank].num_slots;
1826
1827 if ( Ships[objp->instance].flags & SF_SECONDARY_DUAL_FIRE || firepoints < 2) {
1828 Ships[objp->instance].flags &= ~SF_SECONDARY_DUAL_FIRE;
1829 if(at_self) {
1830 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Secondary weapon set to normal fire mode", 34));
1831 snd_play( &Snds[ship_get_sound(Player_obj, SND_SECONDARY_CYCLE)] );
1832 hud_gauge_popup_start(HUD_WEAPONS_GAUGE);
1833 }
1834 } else {
1835 Ships[objp->instance].flags |= SF_SECONDARY_DUAL_FIRE;
1836 if(at_self) {
1837 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Secondary weapon set to dual fire mode", 35));
1838 snd_play( &Snds[ship_get_sound(Player_obj, SND_SECONDARY_CYCLE)] );
1839 hud_gauge_popup_start(HUD_WEAPONS_GAUGE);
1840 }
1841 }
1842
1843 // multiplayer server should maintain bank/link status here
1844 if( MULTIPLAYER_MASTER ){
1845 Assert(npl != NULL);
1846 multi_server_update_player_weapons(npl,&Ships[objp->instance]);
1847 }
1848 break;
1849 }
1850
1851 // increase weapon recharge rate
1852 case INCREASE_WEAPON:
1853 if(at_self)
1854 control_used(INCREASE_WEAPON);
1855 increase_recharge_rate(objp, WEAPONS);
1856
1857 // multiplayer server should maintain bank/link status here
1858 if( MULTIPLAYER_MASTER ){
1859 Assert(npl != NULL);
1860 multi_server_update_player_weapons(npl,&Ships[objp->instance]);
1861 }
1862 break;
1863
1864 // decrease weapon recharge rate
1865 case DECREASE_WEAPON:
1866 if(at_self)
1867 control_used(DECREASE_WEAPON);
1868 decrease_recharge_rate(objp, WEAPONS);
1869
1870 // multiplayer server should maintain bank/link status here
1871 if( MULTIPLAYER_MASTER ){
1872 Assert(npl != NULL);
1873 multi_server_update_player_weapons(npl,&Ships[objp->instance]);
1874 }
1875 break;
1876
1877 // increase shield recharge rate
1878 case INCREASE_SHIELD:
1879 if(at_self)
1880 control_used(INCREASE_SHIELD);
1881 increase_recharge_rate(objp, SHIELDS);
1882
1883 // multiplayer server should maintain bank/link status here
1884 if( MULTIPLAYER_MASTER ){
1885 Assert(npl != NULL);
1886 multi_server_update_player_weapons(npl,&Ships[objp->instance]);
1887 }
1888 break;
1889
1890 // decrease shield recharge rate
1891 case DECREASE_SHIELD:
1892 if(at_self)
1893 control_used(DECREASE_SHIELD);
1894 decrease_recharge_rate(objp, SHIELDS);
1895
1896 // multiplayer server should maintain bank/link status here
1897 if( MULTIPLAYER_MASTER ){
1898 Assert(npl != NULL);
1899 multi_server_update_player_weapons(npl,&Ships[objp->instance]);
1900 }
1901 break;
1902
1903 // increase energy to engines
1904 case INCREASE_ENGINE:
1905 if(at_self)
1906 control_used(INCREASE_ENGINE);
1907 increase_recharge_rate(objp, ENGINES);
1908
1909 // multiplayer server should maintain bank/link status here
1910 if( MULTIPLAYER_MASTER ){
1911 Assert(npl != NULL);
1912 multi_server_update_player_weapons(npl,&Ships[objp->instance]);
1913 }
1914 break;
1915
1916 // decrease energy to engines
1917 case DECREASE_ENGINE:
1918 if(at_self)
1919 control_used(DECREASE_ENGINE);
1920 decrease_recharge_rate(objp, ENGINES);
1921
1922 // multiplayer server should maintain bank/link status here
1923 if( MULTIPLAYER_MASTER ){
1924 Assert(npl != NULL);
1925 multi_server_update_player_weapons(npl,&Ships[objp->instance]);
1926 }
1927 break;
1928
1929 // equalize recharge rates
1930 case ETS_EQUALIZE:
1931 if (at_self) {
1932 control_used(ETS_EQUALIZE);
1933 }
1934
1935 set_default_recharge_rates(objp);
1936 snd_play( &Snds[SND_ENERGY_TRANS] );
1937
1938 // multiplayer server should maintain bank/link status here
1939 if( MULTIPLAYER_MASTER ){
1940 Assert(npl != NULL);
1941 multi_server_update_player_weapons(npl,&Ships[objp->instance]);
1942 }
1943 break;
1944
1945 // equalize shield energy to all quadrants
1946 case SHIELD_EQUALIZE:
1947 if(at_self){
1948 control_used(SHIELD_EQUALIZE);
1949 }
1950 hud_shield_equalize(objp, pl);
1951 break;
1952
1953 // transfer shield energy to front
1954 case SHIELD_XFER_TOP:
1955 if(at_self){
1956 control_used(SHIELD_XFER_TOP);
1957 }
1958 hud_augment_shield_quadrant(objp, FRONT_QUAD);
1959 break;
1960
1961 // transfer shield energy to rear
1962 case SHIELD_XFER_BOTTOM:
1963 if(at_self)
1964 control_used(SHIELD_XFER_BOTTOM);
1965 hud_augment_shield_quadrant(objp, REAR_QUAD);
1966 break;
1967
1968 // transfer shield energy to left
1969 case SHIELD_XFER_LEFT:
1970 if(at_self)
1971 control_used(SHIELD_XFER_LEFT);
1972 hud_augment_shield_quadrant(objp, LEFT_QUAD);
1973 break;
1974
1975 // transfer shield energy to right
1976 case SHIELD_XFER_RIGHT:
1977 if(at_self)
1978 control_used(SHIELD_XFER_RIGHT);
1979 hud_augment_shield_quadrant(objp, RIGHT_QUAD);
1980 break;
1981
1982 // transfer energy to shield from weapons
1983 case XFER_SHIELD:
1984 if(at_self)
1985 control_used(XFER_SHIELD);
1986 transfer_energy_to_shields(objp);
1987 break;
1988
1989 // transfer energy to weapons from shield
1990 case XFER_LASER:
1991 if(at_self)
1992 control_used(XFER_LASER);
1993 transfer_energy_to_weapons(objp);
1994 break;
1995
1996 // following are not handled here, but we need to bypass the Int3()
1997 case LAUNCH_COUNTERMEASURE:
1998 case VIEW_SLEW:
1999 case VIEW_EXTERNAL:
2000 case VIEW_EXTERNAL_TOGGLE_CAMERA_LOCK:
2001 case VIEW_TRACK_TARGET:
2002 case ONE_THIRD_THROTTLE:
2003 case TWO_THIRDS_THROTTLE:
2004 case MINUS_5_PERCENT_THROTTLE:
2005 case PLUS_5_PERCENT_THROTTLE:
2006 case ZERO_THROTTLE:
2007 case MAX_THROTTLE:
2008 case TOGGLE_GLIDING:
2009 return 0;
2010
2011 default :
2012 Int3(); // bad bad bad
2013 break;
2014 }
2015
2016 return 1;
2017 }
2018
2019 /**
2020 * Execute function corresponding to action n
2021 * Basically, these are actions which don't affect demo playback at all
2022 * @param n Action number
2023 */
button_function_demo_valid(int n)2024 int button_function_demo_valid(int n)
2025 {
2026 // by default, we'll return "not processed". ret will get set to 1, if this is one of the keys which is always allowed, even in demo
2027 // playback.
2028 int ret = 0;
2029
2030 // No keys, not even targeting keys, when player in death roll. He can press keys after he blows up.
2031 if (Game_mode & GM_DEAD_DIED){
2032 return 0;
2033 }
2034
2035 // any of these buttons are valid
2036 switch(n){
2037 case VIEW_CHASE:
2038 control_used(VIEW_CHASE);
2039 if(!Perspective_locked)
2040 {
2041 Viewer_mode ^= VM_CHASE;
2042 }
2043 else
2044 {
2045 snd_play( &Snds[SND_TARGET_FAIL] );
2046 }
2047 ret = 1;
2048 break;
2049
2050 case VIEW_TRACK_TARGET: // Target padlock mode toggle (Swifty)
2051 control_used(VIEW_TRACK_TARGET);
2052 if (!Perspective_locked) {
2053 if(Viewer_mode & VM_TRACK) {
2054 chase_slew_angles.h = 0;
2055 chase_slew_angles.p = 0;
2056 }
2057 Viewer_mode ^= VM_TRACK;
2058 } else {
2059 snd_play( &Snds[SND_TARGET_FAIL] );
2060 }
2061 ret = 1;
2062 break;
2063
2064 case VIEW_EXTERNAL:
2065 control_used(VIEW_EXTERNAL);
2066 if(!Perspective_locked)
2067 {
2068 Viewer_mode ^= VM_EXTERNAL;
2069 Viewer_mode &= ~VM_EXTERNAL_CAMERA_LOCKED; // reset camera lock when leaving/entering external view
2070 }
2071 else
2072 {
2073 snd_play( &Snds[SND_TARGET_FAIL] );
2074 }
2075 ret = 1;
2076 break;
2077
2078 case VIEW_TOPDOWN:
2079 control_used(VIEW_TOPDOWN);
2080 if(!Perspective_locked)
2081 {
2082 Viewer_mode ^= VM_TOPDOWN;
2083 }
2084 else
2085 {
2086 snd_play( &Snds[SND_TARGET_FAIL] );
2087 }
2088 ret = 1;
2089 break;
2090
2091 case VIEW_EXTERNAL_TOGGLE_CAMERA_LOCK:
2092 control_used(VIEW_EXTERNAL_TOGGLE_CAMERA_LOCK);
2093 if ( Viewer_mode & VM_EXTERNAL ) {
2094 Viewer_mode ^= VM_EXTERNAL_CAMERA_LOCKED;
2095 if ( Viewer_mode & VM_EXTERNAL_CAMERA_LOCKED ) {
2096 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "External camera is locked, controls will move ship", 36));
2097 } else {
2098 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "External camera is free, controls will move the camera, not the ship", 37));
2099 }
2100 }
2101 ret = 1;
2102 break;
2103
2104 case VIEW_OTHER_SHIP:
2105 control_used(VIEW_OTHER_SHIP);
2106 if ( Player_ai->target_objnum < 0 || Perspective_locked) {
2107 snd_play( &Snds[SND_TARGET_FAIL] );
2108 } else {
2109 if ( Objects[Player_ai->target_objnum].type != OBJ_SHIP ) {
2110 snd_play( &Snds[SND_TARGET_FAIL] );
2111 } else {
2112 Viewer_mode ^= VM_OTHER_SHIP;
2113 }
2114 }
2115 ret = 1;
2116 break;
2117
2118 case TIME_SLOW_DOWN:
2119 if ( Game_mode & GM_NORMAL ) {
2120 // Goober5000 - time dilation only available in cheat mode (see above);
2121 // now you can do it with or without pressing the tilde, per Kazan's request
2122 if ( ((Game_time_compression > F1_0) || (Cheats_enabled && (Game_time_compression > (F1_0/MAX_TIME_DIVIDER)))) && !Time_compression_locked) {
2123 change_time_compression(0.5f);
2124 } else {
2125 gamesnd_play_error_beep();
2126 }
2127 } else {
2128 gamesnd_play_error_beep();
2129 }
2130 ret = 1;
2131 break;
2132
2133 case TIME_SPEED_UP:
2134 if ( Game_mode & GM_NORMAL ) {
2135 if ( (Game_time_compression < (F1_0*MAX_TIME_MULTIPLIER)) && !Time_compression_locked ) {
2136 change_time_compression(2.0f);
2137 } else {
2138 gamesnd_play_error_beep();
2139 }
2140 } else {
2141 gamesnd_play_error_beep();
2142 }
2143 ret = 1;
2144 break;
2145 }
2146
2147 // done
2148 return ret;
2149 }
2150
key_is_targeting(int n)2151 bool key_is_targeting(int n)
2152 {
2153 switch(n) {
2154 case TARGET_NEXT:
2155 case TARGET_PREV:
2156 case TARGET_NEXT_CLOSEST_HOSTILE:
2157 case TARGET_PREV_CLOSEST_HOSTILE:
2158 case TARGET_NEXT_CLOSEST_FRIENDLY:
2159 case TARGET_PREV_CLOSEST_FRIENDLY:
2160 case TARGET_SHIP_IN_RETICLE:
2161 case TARGET_LAST_TRANMISSION_SENDER:
2162 case TARGET_CLOSEST_SHIP_ATTACKING_TARGET:
2163 case TARGET_CLOSEST_SHIP_ATTACKING_SELF:
2164 case TARGET_TARGETS_TARGET:
2165 case TARGET_SUBOBJECT_IN_RETICLE:
2166 case TARGET_PREV_SUBOBJECT:
2167 case TARGET_NEXT_SUBOBJECT:
2168 return true;
2169
2170 default:
2171 return false;
2172 }
2173 }
2174
2175 /**
2176 * Execute function corresponding to action n (BUTTON_ from KeyControl.h)
2177 * @return 1 when action was taken
2178 */
button_function(int n)2179 int button_function(int n)
2180 {
2181 Assert(n >= 0);
2182
2183 if (Control_config[n].disabled)
2184 return 0;
2185
2186 // check if the button has been set to be ignored by a SEXP
2187 if (Ignored_keys[n]) {
2188 if (Ignored_keys[n] > 0) {
2189 Ignored_keys[n]--;
2190 }
2191 return 0;
2192 }
2193
2194 // No keys, not even targeting keys, when player in death roll. He can press keys after he blows up.
2195 if (Game_mode & GM_DEAD_DIED){
2196 return 0;
2197 }
2198
2199 // Goober5000 - if the ship doesn't have subspace drive, jump key doesn't work: so test and exit early
2200 if (Player_ship->flags2 & SF2_NO_SUBSPACE_DRIVE)
2201 {
2202 switch(n)
2203 {
2204 case END_MISSION:
2205 control_used(n); // set the timestamp for when we used the control, in case we need it
2206 return 1; // pretend we took the action: if we return 0, strange stuff may happen
2207 }
2208 }
2209
2210 // Goober5000 - if we have primitive sensors, some keys don't work: so test and exit early
2211 if (Player_ship->flags2 & SF2_PRIMITIVE_SENSORS)
2212 {
2213 switch (n)
2214 {
2215 case MATCH_TARGET_SPEED:
2216 case TOGGLE_AUTO_MATCH_TARGET_SPEED:
2217 case TOGGLE_AUTO_TARGETING:
2218 case TARGET_NEXT:
2219 case TARGET_PREV:
2220 case TARGET_NEXT_CLOSEST_HOSTILE:
2221 case TARGET_PREV_CLOSEST_HOSTILE:
2222 case TARGET_NEXT_CLOSEST_FRIENDLY:
2223 case TARGET_PREV_CLOSEST_FRIENDLY:
2224 case TARGET_SHIP_IN_RETICLE:
2225 case TARGET_LAST_TRANMISSION_SENDER:
2226 case TARGET_CLOSEST_REPAIR_SHIP:
2227 case TARGET_CLOSEST_SHIP_ATTACKING_TARGET:
2228 case STOP_TARGETING_SHIP:
2229 case TARGET_CLOSEST_SHIP_ATTACKING_SELF:
2230 case TARGET_TARGETS_TARGET:
2231 case TARGET_SUBOBJECT_IN_RETICLE:
2232 case TARGET_NEXT_SUBOBJECT:
2233 case TARGET_PREV_SUBOBJECT:
2234 case STOP_TARGETING_SUBSYSTEM:
2235 case TARGET_NEXT_BOMB:
2236 case TARGET_PREV_BOMB:
2237 case TARGET_NEXT_UNINSPECTED_CARGO:
2238 case TARGET_PREV_UNINSPECTED_CARGO:
2239 case TARGET_NEWEST_SHIP:
2240 case TARGET_NEXT_LIVE_TURRET:
2241 case TARGET_PREV_LIVE_TURRET:
2242 case TARGET_NEXT_ESCORT_SHIP:
2243 control_used(n); // set the timestamp for when we used the control, in case we need it
2244 return 1; // pretend we took the action: if we return 0, strange stuff may happen
2245 }
2246 }
2247
2248 switch(n) {
2249 // following are not handled here, but we need to bypass the Int3()
2250 case LAUNCH_COUNTERMEASURE:
2251 case VIEW_SLEW:
2252 case VIEW_TRACK_TARGET:
2253 case ONE_THIRD_THROTTLE:
2254 case TWO_THIRDS_THROTTLE:
2255 case MINUS_5_PERCENT_THROTTLE:
2256 case PLUS_5_PERCENT_THROTTLE:
2257 case ZERO_THROTTLE:
2258 case MAX_THROTTLE:
2259 case TOGGLE_GLIDING:
2260 case GLIDE_WHEN_PRESSED:
2261 return 0;
2262 }
2263
2264 /**
2265 * This switch handles the critical buttons
2266 *
2267 * button_function_critical is also called from network
2268 */
2269 switch (n) {
2270 case CYCLE_PRIMARY_WEAPON_SEQUENCE:
2271 case CYCLE_NEXT_PRIMARY: // cycle to next primary weapon
2272 case CYCLE_PREV_PRIMARY: // cycle to previous primary weapon
2273 case CYCLE_SECONDARY: // cycle to next secondary weapon
2274 case CYCLE_NUM_MISSLES: // cycle number of missiles fired from secondary bank
2275 case SHIELD_EQUALIZE: // equalize shield energy to all quadrants
2276 case SHIELD_XFER_TOP: // transfer shield energy to front
2277 case SHIELD_XFER_BOTTOM: // transfer shield energy to rear
2278 case SHIELD_XFER_LEFT: // transfer shield energy to left
2279 case SHIELD_XFER_RIGHT: // transfer shield energy to right
2280 case XFER_SHIELD: // transfer energy to shield from weapons
2281 case XFER_LASER: // transfer energy to weapons from shield
2282 return button_function_critical(n);
2283 break;
2284
2285 case INCREASE_WEAPON: // increase weapon recharge rate
2286 case DECREASE_WEAPON: // decrease weapon recharge rate
2287 case INCREASE_SHIELD: // increase shield recharge rate
2288 case DECREASE_SHIELD: // decrease shield recharge rate
2289 case INCREASE_ENGINE: // increase energy to engines
2290 case DECREASE_ENGINE: // decrease energy to engines
2291 case ETS_EQUALIZE:
2292 if ((Player_ship->flags2 & SF2_NO_ETS) == 0) {
2293 hud_gauge_popup_start(HUD_ETS_GAUGE);
2294 return button_function_critical(n);
2295 }
2296 return 1;
2297 break;
2298 }
2299
2300 /**
2301 * Assume the switches below will catch the key, if not, set to FALSE in default
2302 *
2303 * Below, you must not use return in cases,
2304 * else the check for invalid keys will fail
2305 */
2306 int keyHasBeenUsed = TRUE;
2307
2308 switch(n) {
2309 // message all netplayers button
2310 case MULTI_MESSAGE_ALL:
2311 multi_msg_key_down(MULTI_MSG_ALL);
2312 break;
2313
2314 // message all friendlies button
2315 case MULTI_MESSAGE_FRIENDLY:
2316 multi_msg_key_down(MULTI_MSG_FRIENDLY);
2317 break;
2318
2319 // message all hostiles button
2320 case MULTI_MESSAGE_HOSTILE:
2321 multi_msg_key_down(MULTI_MSG_HOSTILE);
2322 break;
2323
2324 // message targeted ship (if player)
2325 case MULTI_MESSAGE_TARGET:
2326 multi_msg_key_down(MULTI_MSG_TARGET);
2327 break;
2328
2329 // undefined in multiplayer for clients right now
2330 // toggle auto-match target speed
2331 case TOGGLE_AUTO_MATCH_TARGET_SPEED:
2332 // multiplayer observers can't match target speed
2333 if((Game_mode & GM_MULTIPLAYER) && (Net_player != NULL) && ((Net_player->flags & NETINFO_FLAG_OBSERVER) || (Player_obj->type == OBJ_OBSERVER)) ){
2334 break;
2335 }
2336
2337 Player->flags ^= PLAYER_FLAGS_AUTO_MATCH_SPEED;
2338 control_used(TOGGLE_AUTO_MATCH_TARGET_SPEED);
2339 hud_gauge_popup_start(HUD_AUTO_SPEED);
2340 if ( Players[Player_num].flags & PLAYER_FLAGS_AUTO_MATCH_SPEED ) {
2341 snd_play(&Snds[SND_SHIELD_XFER_OK], 1.0f);
2342 if ( !(Player->flags & PLAYER_FLAGS_MATCH_TARGET) ) {
2343 player_match_target_speed();
2344 }
2345 }
2346 else
2347 {
2348 snd_play(&Snds[SND_SHIELD_XFER_OK], 1.0f);
2349 player_match_target_speed();
2350 }
2351 break;
2352
2353 case TARGET_NEXT_UNINSPECTED_CARGO:
2354 hud_target_uninspected_object(1);
2355 break;
2356
2357 case TARGET_PREV_UNINSPECTED_CARGO:
2358 hud_target_uninspected_object(0);
2359 break;
2360
2361 case TARGET_NEWEST_SHIP:
2362 hud_target_newest_ship();
2363 break;
2364
2365 case TARGET_NEXT_LIVE_TURRET:
2366 hud_target_live_turret(1);
2367 break;
2368
2369 case TARGET_PREV_LIVE_TURRET:
2370 hud_target_live_turret(0);
2371 break;
2372
2373 // end the mission
2374 case END_MISSION:
2375 // in multiplayer, all end mission requests should go through the server
2376 if (Game_mode & GM_MULTIPLAYER) {
2377 multi_handle_end_mission_request();
2378 break;
2379 }
2380
2381 control_used(END_MISSION);
2382
2383 if (collide_predict_large_ship(Player_obj, 200.0f)
2384 || (Ship_info[Ships[Player_obj->instance].ship_info_index].warpout_type == WT_HYPERSPACE
2385 && collide_predict_large_ship(Player_obj, 100000.0f)))
2386 {
2387 gamesnd_play_iface(SND_GENERAL_FAIL);
2388 HUD_printf(XSTR( "** WARNING ** Collision danger. Subspace drive not activated.", 39));
2389 } else if (!ship_engine_ok_to_warp(Player_ship)) {
2390 gamesnd_play_iface(SND_GENERAL_FAIL);
2391 HUD_printf(XSTR("Engine failure. Cannot engage subspace drive.", 40));
2392 } else if (!ship_navigation_ok_to_warp(Player_ship)) {
2393 gamesnd_play_iface(SND_GENERAL_FAIL);
2394 HUD_printf(XSTR("Navigation failure. Cannot engage subspace drive.", 1596));
2395 } else if ( (Player_obj != NULL) && object_get_gliding(Player_obj)) {
2396 gamesnd_play_iface(SND_GENERAL_FAIL);
2397 HUD_printf(XSTR("Cannot engage subspace drive while gliding.", 1597));
2398 } else {
2399 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_START );
2400 }
2401 break;
2402
2403 case ADD_REMOVE_ESCORT:
2404 if ( Player_ai->target_objnum >= 0 ) {
2405 control_used(ADD_REMOVE_ESCORT);
2406 hud_add_remove_ship_escort(Player_ai->target_objnum);
2407 }
2408 break;
2409
2410 // if i'm an observer, zoom to my targeted object
2411 case MULTI_OBSERVER_ZOOM_TO:
2412 multi_obs_zoom_to_target();
2413 break;
2414
2415 // toggle between high and low HUD contrast
2416 case TOGGLE_HUD_CONTRAST:
2417 gamesnd_play_iface(SND_USER_SELECT);
2418 hud_toggle_contrast();
2419 break;
2420
2421 // toggle network info
2422 case MULTI_TOGGLE_NETINFO:
2423 extern int Multi_display_netinfo;
2424 Multi_display_netinfo = !Multi_display_netinfo;
2425 break;
2426
2427 // self destruct (multiplayer only)
2428 case MULTI_SELF_DESTRUCT:
2429 if (!(Game_mode & GM_MULTIPLAYER)) {
2430 break;
2431 }
2432
2433 // bogus netplayer
2434 if ( (Net_player == NULL) || (Net_player->m_player == NULL) ) {
2435 break;
2436 }
2437
2438 // blow myself up, if I'm the server
2439 if (Net_player->flags & NETINFO_FLAG_AM_MASTER) {
2440 if ( (Net_player->m_player->objnum >= 0) &&
2441 (Net_player->m_player->objnum < MAX_OBJECTS) &&
2442 (Objects[Net_player->m_player->objnum].type == OBJ_SHIP) &&
2443 (Objects[Net_player->m_player->objnum].instance >= 0) &&
2444 (Objects[Net_player->m_player->objnum].instance < MAX_SHIPS) )
2445 {
2446
2447 ship_self_destruct(&Objects[Net_player->m_player->objnum]);
2448 }
2449 } else { // otherwise send a packet to the server
2450 send_self_destruct_packet();
2451 }
2452 break;
2453
2454 case TOGGLE_HUD:
2455 gamesnd_play_iface(SND_USER_SELECT);
2456 hud_toggle_draw();
2457 break;
2458
2459 case HUD_TARGETBOX_TOGGLE_WIREFRAME:
2460 if (!Lock_targetbox_mode) {
2461 gamesnd_play_iface(SND_USER_SELECT);
2462 hud_targetbox_switch_wireframe_mode();
2463 } else {
2464 gamesnd_play_iface(SND_GENERAL_FAIL);
2465 }
2466 break;
2467
2468 // Autopilot key control
2469 case AUTO_PILOT_TOGGLE:
2470 if (!(The_mission.flags & MISSION_FLAG_DEACTIVATE_AP)) {
2471 if (AutoPilotEngaged) {
2472 if (Cmdline_autopilot_interruptable == 1) //allow WCS to disable autopilot interrupt via commandline
2473 EndAutoPilot();
2474 } else {
2475 if (!StartAutopilot())
2476 gamesnd_play_iface(SND_GENERAL_FAIL);
2477 }
2478 }
2479 break;
2480
2481 case NAV_CYCLE:
2482 if (!Sel_NextNav())
2483 gamesnd_play_iface(SND_GENERAL_FAIL);
2484 break;
2485 default:
2486 keyHasBeenUsed = FALSE;
2487 break;
2488 }
2489
2490 /**
2491 * The key has been handled, return early before the timestamp is set
2492 */
2493 if (keyHasBeenUsed) {
2494 return 1;
2495 }
2496
2497 /**
2498 * Update the last used timestamp of this key
2499 */
2500 control_used(n);
2501
2502 if ( hud_sensors_ok(Player_ship) ) {
2503 int keyHasBeenUsed = TRUE;
2504 switch(n) {
2505 // target next
2506 case TARGET_NEXT:
2507 hud_target_next();
2508 break;
2509
2510 // target previous
2511 case TARGET_PREV:
2512 hud_target_prev();
2513 break;
2514
2515 // target the next hostile target
2516 case TARGET_NEXT_CLOSEST_HOSTILE:
2517 hud_target_next_list();
2518 break;
2519
2520 // target the previous closest hostile
2521 case TARGET_PREV_CLOSEST_HOSTILE:
2522 hud_target_next_list(1,0);
2523 break;
2524
2525 // target the next friendly ship
2526 case TARGET_NEXT_CLOSEST_FRIENDLY:
2527 hud_target_next_list(0);
2528 break;
2529
2530 // target the closest friendly ship
2531 case TARGET_PREV_CLOSEST_FRIENDLY:
2532 hud_target_next_list(0,0);
2533 break;
2534
2535 // target ship closest to center of reticle
2536 case TARGET_SHIP_IN_RETICLE:
2537 hud_target_in_reticle_new();
2538 break;
2539
2540 case TARGET_LAST_TRANMISSION_SENDER:
2541 hud_target_last_transmit();
2542 break;
2543
2544 // target the closest ship attacking current target
2545 case TARGET_CLOSEST_SHIP_ATTACKING_TARGET:
2546 if (Player_ai->target_objnum < 0) {
2547 snd_play(&Snds[SND_TARGET_FAIL]);
2548 break;
2549 }
2550
2551 hud_target_closest(iff_get_attacker_mask(obj_team(&Objects[Player_ai->target_objnum])), Player_ai->target_objnum);
2552 break;
2553
2554 // target closest ship that is attacking player
2555 case TARGET_CLOSEST_SHIP_ATTACKING_SELF:
2556 hud_target_next_list(1, 0, iff_get_attacker_mask(Player_ship->team), OBJ_INDEX(Player_obj), TRUE, 0, 1);
2557 break;
2558
2559 // target your target's target
2560 case TARGET_TARGETS_TARGET:
2561 hud_target_targets_target();
2562 break;
2563
2564 // target ships subsystem in reticle
2565 case TARGET_SUBOBJECT_IN_RETICLE:
2566 hud_target_subsystem_in_reticle();
2567 break;
2568
2569 case TARGET_PREV_SUBOBJECT:
2570 hud_target_prev_subobject();
2571 break;
2572
2573 // target next subsystem on current target
2574 case TARGET_NEXT_SUBOBJECT:
2575 hud_target_next_subobject();
2576 break;
2577
2578 default:
2579 keyHasBeenUsed = FALSE;
2580 break;
2581 };
2582 if (keyHasBeenUsed) {
2583 return 1;
2584 }
2585 }
2586 else
2587 {
2588 //if sensors are gone, and the passed key is one of the targeting keys, we need to exit here before we hit the Int3() later in this function
2589 if (key_is_targeting(n)) {
2590 return 1;
2591 }
2592 }
2593
2594 keyHasBeenUsed = TRUE;
2595 switch(n) {
2596 // undefined in multiplayer for clients right now
2597 // match target speed
2598 case MATCH_TARGET_SPEED:
2599 // If player is auto-matching, break auto-match speed
2600 if ( Player->flags & PLAYER_FLAGS_AUTO_MATCH_SPEED ) {
2601 Player->flags &= ~PLAYER_FLAGS_AUTO_MATCH_SPEED;
2602 }
2603 player_match_target_speed();
2604 break;
2605
2606 // toggle auto-targeting
2607 case TOGGLE_AUTO_TARGETING:
2608 hud_gauge_popup_start(HUD_AUTO_TARGET);
2609 Players[Player_num].flags ^= PLAYER_FLAGS_AUTO_TARGETING;
2610 if ( Players[Player_num].flags & PLAYER_FLAGS_AUTO_TARGETING ) {
2611 if (hud_sensors_ok(Player_ship)) {
2612 hud_target_closest(iff_get_attackee_mask(Player_ship->team), -1, FALSE, TRUE );
2613 snd_play(&Snds[SND_SHIELD_XFER_OK], 1.0f);
2614 //HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Auto targeting activated", -1));
2615 } else {
2616 Players[Player_num].flags ^= PLAYER_FLAGS_AUTO_TARGETING;
2617 }
2618 } else {
2619 snd_play(&Snds[SND_SHIELD_XFER_OK], 1.0f);
2620 //HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Auto targeting deactivated", -1));
2621 }
2622 break;
2623
2624 // target the closest repair ship
2625 case TARGET_CLOSEST_REPAIR_SHIP:
2626 // AL: Try to find the closest repair ship coming to repair the player... if no support
2627 // ships are coming to rearm the player, just try for the closest repair ship
2628 if ( hud_target_closest_repair_ship(OBJ_INDEX(Player_obj)) == 0 ) {
2629 if ( hud_target_closest_repair_ship() == 0 ) {
2630 snd_play(&Snds[SND_TARGET_FAIL]);
2631 }
2632 }
2633 break;
2634
2635 // stop targeting ship
2636 case STOP_TARGETING_SHIP:
2637 hud_cease_targeting();
2638 break;
2639
2640 // stop targeting subsystems on ship
2641 case STOP_TARGETING_SUBSYSTEM:
2642 hud_cease_subsystem_targeting();
2643 break;
2644
2645 case TARGET_NEXT_BOMB:
2646 hud_target_missile(Player_obj, 1);
2647 break;
2648
2649 case TARGET_PREV_BOMB:
2650 hud_target_missile(Player_obj, 0);
2651 break;
2652
2653 // wingman message: attack current target
2654 case ATTACK_MESSAGE:
2655 hud_squadmsg_shortcut( ATTACK_TARGET_ITEM );
2656 break;
2657
2658 // wingman message: disarm current target
2659 case DISARM_MESSAGE:
2660 hud_squadmsg_shortcut( DISARM_TARGET_ITEM );
2661 break;
2662
2663 // wingman message: disable current target
2664 case DISABLE_MESSAGE:
2665 hud_squadmsg_shortcut( DISABLE_TARGET_ITEM );
2666 break;
2667
2668 // wingman message: disable current target
2669 case ATTACK_SUBSYSTEM_MESSAGE:
2670 hud_squadmsg_shortcut( DISABLE_SUBSYSTEM_ITEM );
2671 break;
2672
2673 // wingman message: capture current target
2674 case CAPTURE_MESSAGE:
2675 hud_squadmsg_shortcut( CAPTURE_TARGET_ITEM );
2676 break;
2677
2678 // wingman message: engage enemy
2679 case ENGAGE_MESSAGE:
2680 hud_squadmsg_shortcut( ENGAGE_ENEMY_ITEM );
2681 break;
2682
2683 // wingman message: form on my wing
2684 case FORM_MESSAGE:
2685 hud_squadmsg_shortcut( FORMATION_ITEM );
2686 break;
2687
2688 // wingman message: protect current target
2689 case PROTECT_MESSAGE:
2690 hud_squadmsg_shortcut( PROTECT_TARGET_ITEM );
2691 break;
2692
2693 // wingman message: cover me
2694 case COVER_MESSAGE:
2695 hud_squadmsg_shortcut( COVER_ME_ITEM );
2696 break;
2697
2698 // wingman message: warp out
2699 case WARP_MESSAGE:
2700 hud_squadmsg_shortcut( DEPART_ITEM );
2701 break;
2702
2703 case IGNORE_MESSAGE:
2704 hud_squadmsg_shortcut( IGNORE_TARGET_ITEM );
2705 break;
2706
2707 // rearm message
2708 case REARM_MESSAGE:
2709 hud_squadmsg_rearm_shortcut();
2710 break;
2711
2712 // cycle to next radar range
2713 case RADAR_RANGE_CYCLE:
2714 HUD_config.rp_dist++;
2715 if ( HUD_config.rp_dist >= RR_MAX_RANGES )
2716 HUD_config.rp_dist = 0;
2717
2718 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Radar range set to %s", 38), Radar_range_text(HUD_config.rp_dist));
2719 break;
2720
2721 // toggle the squadmate messaging menu
2722 case SQUADMSG_MENU:
2723 hud_squadmsg_toggle(); // leave the details to the messaging code!!!
2724 break;
2725
2726 // show the mission goals screen
2727 case SHOW_GOALS:
2728 gameseq_post_event( GS_EVENT_SHOW_GOALS );
2729 break;
2730
2731 // end the mission
2732 case END_MISSION:
2733 // in multiplayer, all end mission requests should go through the server
2734 if(Game_mode & GM_MULTIPLAYER){
2735 multi_handle_end_mission_request();
2736 break;
2737 }
2738
2739 control_used(END_MISSION);
2740
2741 if (collide_predict_large_ship(Player_obj, 200.0f)
2742 || (Ship_info[Ships[Player_obj->instance].ship_info_index].warpout_type == WT_HYPERSPACE
2743 && collide_predict_large_ship(Player_obj, 100000.0f)))
2744 {
2745 gamesnd_play_iface(SND_GENERAL_FAIL);
2746 HUD_printf(XSTR( "** WARNING ** Collision danger. Subspace drive not activated.", 39));
2747 } else if (!ship_engine_ok_to_warp(Player_ship)) {
2748 gamesnd_play_iface(SND_GENERAL_FAIL);
2749 HUD_printf(XSTR("Engine failure. Cannot engage subspace drive.", 40));
2750 } else if (!ship_navigation_ok_to_warp(Player_ship)) {
2751 gamesnd_play_iface(SND_GENERAL_FAIL);
2752 HUD_printf(XSTR("Navigation failure. Cannot engage subspace drive.", 1572));
2753 } else if (Player_obj != NULL && object_get_gliding(Player_obj)) {
2754 gamesnd_play_iface(SND_GENERAL_FAIL);
2755 HUD_printf(XSTR("Cannot engage subspace drive while gliding.", 1573));
2756 } else {
2757 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_START );
2758 }
2759 break;
2760
2761 case ADD_REMOVE_ESCORT:
2762 if ( Player_ai->target_objnum >= 0 ) {
2763 control_used(ADD_REMOVE_ESCORT);
2764 hud_add_remove_ship_escort(Player_ai->target_objnum);
2765 }
2766 break;
2767
2768 case ESCORT_CLEAR:
2769 hud_escort_clear_all(true);
2770 break;
2771
2772 case TARGET_NEXT_ESCORT_SHIP:
2773 hud_escort_target_next();
2774 break;
2775
2776 default:
2777 keyHasBeenUsed = FALSE;
2778 break;
2779 };
2780 if (keyHasBeenUsed) {
2781 return 1;
2782 }
2783
2784 /**
2785 * All keys should have been handled above, if not panic
2786 */
2787 mprintf(("Unknown key %d at %s:%u\n", n, __FILE__, __LINE__));
2788 Int3();
2789
2790 return 1;
2791 }
2792
2793 /**
2794 * Calls multiple event handlers for each active button
2795 * @param bi currently active buttons
2796 */
button_info_do(button_info * bi)2797 void button_info_do(button_info *bi)
2798 {
2799 for (int i = 0; i < CCFG_MAX; i++) {
2800 if( button_info_query(bi, i) ) {
2801 int keyHasBeenUsed = FALSE;
2802
2803 if( !keyHasBeenUsed ) {
2804 keyHasBeenUsed = button_function_demo_valid(i);
2805 }
2806
2807 if( !keyHasBeenUsed ) {
2808 keyHasBeenUsed = button_function(i);
2809 }
2810
2811 if( keyHasBeenUsed ) {
2812 button_info_unset(bi, i);
2813 }
2814 }
2815 }
2816 }
2817
2818
2819 /**
2820 * Set the bit for the corresponding action n (BUTTON_ from KeyControl.h)
2821 */
button_info_set(button_info * bi,int n)2822 void button_info_set(button_info *bi, int n)
2823 {
2824 int field_num, bit_num;
2825
2826 field_num = n / 32;
2827 bit_num = n % 32;
2828
2829 bi->status[field_num] |= (1 << bit_num);
2830 }
2831
2832 /**
2833 * Unset the bit for the corresponding action n (BUTTON_ from KeyControl.h)
2834 */
button_info_unset(button_info * bi,int n)2835 void button_info_unset(button_info *bi, int n)
2836 {
2837 int field_num, bit_num;
2838
2839 field_num = n / 32;
2840 bit_num = n % 32;
2841
2842 bi->status[field_num] &= ~(1 << bit_num);
2843 }
2844
button_info_query(button_info * bi,int n)2845 int button_info_query(button_info *bi, int n)
2846 {
2847 return bi->status[n / 32] & (1 << (n % 32));
2848 }
2849
2850 /**
2851 * Clear out the ::button_info struct
2852 */
button_info_clear(button_info * bi)2853 void button_info_clear(button_info *bi)
2854 {
2855 int i;
2856
2857 for (i=0; i<NUM_BUTTON_FIELDS; i++) {
2858 bi->status[i] = 0;
2859 }
2860 }
2861
2862 /**
2863 * Strip out all noncritical keys from the ::button_info struct
2864 */
button_strip_noncritical_keys(button_info * bi)2865 void button_strip_noncritical_keys(button_info *bi)
2866 {
2867 int idx;
2868
2869 // clear out all noncritical keys
2870 for(idx=0;idx<Non_critical_key_set_size;idx++){
2871 button_info_unset(bi,Non_critical_key_set[idx]);
2872 }
2873 }
2874