2 * $Logfile: /Freespace2/code/GameSequence/GameSequence.cpp $
7 * File to control Game Sequencing
10 * Revision 1.1 2002/05/03 03:28:09 root
14 * 3 2/23/99 2:29p Dave
15 * First run of oldschool dogfight mode.
17 * 2 10/07/98 10:52a Dave
20 * 1 10/07/98 10:48a Dave
22 * 65 5/15/98 12:09a Dave
23 * New tracker api code. New game tracker code. Finished up first run of
24 * the PXO screen. Fixed a few game server list exceptions.
26 * 64 5/12/98 2:46a Dave
27 * Rudimentary communication between Parallax Online and freespace. Can
28 * get and store channel lists.
30 * 63 5/06/98 1:12a Allender
31 * fix sequencing names, added nprintf to help respawn debugging
33 * 62 4/25/98 7:39p Allender
34 * fixd some small hotkey stuff. Worked on turret orientation being
35 * correct for multiplayer. new sexpression called end-campaign will will
36 * end the main campaign
38 * 61 4/23/98 7:08p John
39 * Removed some obsoleted states.
41 * 60 4/16/98 4:31p Hoffoss
42 * Changed demo screen referenced to view cutscenes screen, which is now
45 * 59 4/02/98 5:40p Hoffoss
46 * Added the Load Mission screen to FreeSpace.
48 * 58 3/11/98 5:32p Lawrance
49 * Fix up text arrays for events/states
51 * 57 3/09/98 12:13a Lawrance
52 * Add support for Red Alert missions
54 * 56 3/05/98 4:12p John
55 * Made Debug+F4 switch Glide and windowed.
57 * 55 3/03/98 1:00p Hoffoss
58 * Added new command briefing event and state.
60 * 54 3/02/98 4:23p Hoffoss
61 * Forgot to add state label.
63 * 53 3/02/98 3:44p Hoffoss
64 * Added new Campaign Room state and event.
66 * 52 2/21/98 11:58a John
67 * Put in some stuff to externalize strings
69 * 51 2/19/98 6:26p Dave
70 * Fixed a few file xfer bugs. Tweaked mp team select screen. Put in
71 * initial support for player data uploading.
73 * 50 2/18/98 10:21p Dave
74 * Ripped out old file xfer system. Put in brand new xfer system.
76 * 49 2/08/98 5:07p Dave
77 * Put in support for multiplayer furball mode.
79 * 48 1/28/98 6:21p Dave
80 * Made the standalone use ~8 megs less memory. Fixed multiplayer submenu
83 * 47 1/23/98 5:43p Dave
84 * Finished bringing standalone up to speed. Coded in new host options
87 * 46 1/22/98 5:25p Dave
88 * Modified some pregame sequencing packets. Starting to repair broken
91 * 45 1/22/98 4:15p Hoffoss
92 * Added code to allow popup to tell player he needs to bind a key for the
95 * 44 1/20/98 5:42p Dave
96 * Moved ingame join to its own module. Improved it a bit.
98 * 43 1/19/98 12:57p Allender
99 * removed confusing comment
101 * 42 1/19/98 12:56p Allender
102 * fix problem of freespace_start_misison possibly failing due to mission
103 * not properly loading (for single player only right now).
105 * 41 1/15/98 6:12p Dave
106 * Fixed weapons loadout bugs with multiplayer respawning. Added
107 * multiplayer start screen. Fixed a few chatbox bugs.
109 * 40 1/15/98 6:00p Hoffoss
110 * Added option to quit menu (in game) to restart the mission. Doesn't
111 * seem to quite work, though. Checking code in so someone else can look
114 * 39 1/05/98 10:05a Dave
115 * Big re-sequencing of server transfer. Centralized _all_ server transfer
116 * code to one module.
118 * 38 12/30/97 4:28p Lawrance
119 * Give text descriptions for events, change debug output to give text
120 * desciption of event/state
122 * 37 12/24/97 8:56p Lawrance
123 * took out obsolete state used for non-existant sound config screen
125 * 36 11/19/97 8:28p Dave
126 * Hooked in Main Hall screen. Put in Anim support for ping ponging
127 * animations as well as general reversal of anim direction.
129 * 35 11/15/97 2:36p Dave
130 * Added more multiplayer campaign support.
132 * 34 11/13/97 7:01p Hoffoss
133 * Fixed GS_state_text[], which didn't match the current states we have
136 * 33 11/10/97 6:02p Hoffoss
137 * Added new debug paused state.
139 * 32 11/03/97 10:12p Hoffoss
140 * Finished up work on the hud message/mission log scrollback screen.
142 * 31 10/22/97 11:00p Lawrance
143 * modify pop_and_discard() to allow discarding of all states on the stack
145 * 30 10/22/97 5:08p John
146 * fixed a whole slew of bugs and clean up a bunch of stuff dealing with
147 * end of mission stuff.
149 * 29 10/02/97 9:49p Hoffoss
150 * Added event evaluation analysis debug screen so we can determine the
151 * state of events and their sexp trees to track down logic problems and
154 * 28 9/23/97 11:53p Lawrance
155 * add state do perform multiplayer on-line help
157 * 27 9/22/97 4:55p Hoffoss
158 * Added a training message window display thingy.
160 * 26 9/19/97 4:24p Allender
161 * added team selection state -- initialze player* variable in
164 * 25 9/18/97 10:17p Lawrance
165 * add help state for briefing
167 * 24 9/18/97 10:15p Lawrance
168 * add help state for briefing
170 * 23 7/14/97 12:03a Lawrance
173 * 22 6/13/97 2:30p Lawrance
176 * 21 5/20/97 10:02a Lawrance
177 * added view medals screen
179 * 20 4/28/97 2:17p Lawrance
180 * added help state for hotkey assignment screen
182 * 19 4/25/97 3:41p Lawrance
183 * added support for hotkey assignment screen
185 * 18 4/23/97 9:54a Lawrance
186 * made show goals screen a separate state
188 * 17 4/22/97 11:06a Lawrance
189 * added credits state
191 * 16 4/17/97 9:01p Allender
192 * start of campaign stuff. Campaigns now stored in external file (no
193 * filenames in code). Continuing campaign won't work at this point
195 * 15 4/03/97 8:40p Lawrance
196 * add new player death states to GS_state_text[]
198 * 14 3/05/97 5:04p Lawrance
199 * added new states for different context help
201 * 13 1/09/97 12:41a Lawrance
202 * added function to pop a state without restoring that state
204 * 12 12/22/96 3:41p Lawrance
205 * integrating energy transfer system
207 * 11 12/09/96 2:35p Allender
208 * modifed game sequencing so that game_leave_state and game_enter_state
209 * are *always* called.
211 * 10 12/08/96 1:54a Lawrance
212 * put check in to see if a state change request is invalid (ie already in
215 * 9 11/18/96 5:07p John
216 * Changed sequencing code to call entry,leave functions for each state
217 * change. Added Shift+Pause debug pause thing.
219 * 8 11/13/96 4:02p Lawrance
220 * complete over-haul of the menu system and the states associated with
223 * 7 10/23/96 9:08a Allender
224 * Removed primary and secondary goal complete states -- to be implemented
230 * All states for game sequencing are defined in GameSequence.h.
231 * States should always be referred to using the macros.
234 #include "freespace.h"
235 #include "gamesequence.h"
238 #define MAX_GAMESEQ_EVENTS 20 // maximum number of events on the game sequencing queue
239 #define GS_STACK_SIZE 10 // maximum number of stacked states
242 typedef struct state_stack {
244 int event_queue[MAX_GAMESEQ_EVENTS];
245 int queue_tail, queue_head;
248 // DO NOT MAKE THIS NON-STATIC!!!!
249 LOCAL state_stack gs[GS_STACK_SIZE];
250 LOCAL int gs_current_stack = -1; // index of top state on stack.
252 static int state_reentry = 0; // set if we are already in state processing
253 static int state_processing_event_post = 0; // set if we are already processing an event to switch states
254 static int state_in_event_processer = 0;
256 // Text of state, corresponding to #define values for GS_STATE_*
258 char *GS_event_text[] =
260 "GS_EVENT_MAIN_MENU",
261 "GS_EVENT_START_GAME",
262 "GS_EVENT_ENTER_GAME",
263 "GS_EVENT_START_GAME_QUICK",
265 "GS_EVENT_QUIT_GAME", // 5
266 "GS_EVENT_PAUSE_GAME",
267 "GS_EVENT_PREVIOUS_STATE",
268 "GS_EVENT_OPTIONS_MENU",
269 "GS_EVENT_BARRACKS_MENU",
270 "GS_EVENT_TRAINING_MENU", // 10
271 "GS_EVENT_TECH_MENU",
272 "GS_EVENT_LOAD_MISSION_MENU",
273 "GS_EVENT_SHIP_SELECTION",
274 "GS_EVENT_TOGGLE_FULLSCREEN",
275 "GS_EVENT_WEAPON_SELECT_HELP", // 15
276 "GS_EVENT_START_BRIEFING",
277 "GS_EVENT_DEBUG_PAUSE_GAME",
278 "GS_EVENT_HUD_CONFIG",
279 "GS_EVENT_MULTI_SETUP",
280 "GS_EVENT_MULTI_JOIN_GAME", // 20
281 "GS_EVENT_CONTROL_CONFIG",
282 "GS_EVENT_EVENT_DEBUG",
283 "GS_EVENT_MULTI_PROTO_CHOICE",
284 "GS_EVENT_SAVE_RESTORE",
285 "GS_EVENT_CHOOSE_SAVE_OR_RESTORE", // 25
286 "GS_EVENT_WEAPON_SELECTION",
287 "GS_EVENT_MISSION_LOG_SCROLLBACK",
288 "GS_EVENT_MAIN_MENU_HELP",
289 "GS_EVENT_GAMEPLAY_HELP",
290 "GS_EVENT_SHIP_SELECT_HELP", // 30
291 "GS_EVENT_DEATH_DIED",
292 "GS_EVENT_DEATH_BLEW_UP",
293 "GS_EVENT_NEW_CAMPAIGN",
295 "GS_EVENT_SHOW_GOALS", // 35
296 "GS_EVENT_HOTKEY_SCREEN",
297 "GS_EVENT_HOTKEY_SCREEN_HELP",
298 "GS_EVENT_VIEW_MEDALS",
299 "GS_EVENT_MULTI_HOST_SETUP",
300 "GS_EVENT_MULTI_CLIENT_SETUP", // 40
303 "GS_EVENT_MULTI_JOIN_TRACKER",
304 "GS_EVENT_GOTO_VIEW_CUTSCENES_SCREEN",
305 "GS_EVENT_MULTI_STD_WAIT", // 45
306 "GS_EVENT_STANDALONE_MAIN",
307 "GS_EVENT_MULTI_PAUSE",
308 "GS_EVENT_BRIEFING_HELP",
309 "GS_EVENT_TEAM_SELECT",
310 "GS_EVENT_TRAINING_PAUSE", // 50
311 "GS_EVENT_MULTI_HELP",
312 "GS_EVENT_INGAME_PRE_JOIN",
313 "GS_EVENT_PLAYER_WARPOUT_START",
314 "GS_EVENT_PLAYER_WARPOUT_START_FORCED",
315 "GS_EVENT_PLAYER_WARPOUT_STOP", // 55
316 "GS_EVENT_PLAYER_WARPOUT_DONE_STAGE1",
317 "GS_EVENT_PLAYER_WARPOUT_DONE_STAGE2",
318 "GS_EVENT_PLAYER_WARPOUT_DONE",
319 "GS_EVENT_STANDALONE_POSTGAME",
320 "GS_EVENT_INITIAL_PLAYER_SELECT", // 60
321 "GS_EVENT_GAME_INIT",
322 "GS_EVENT_MULTI_MISSION_SYNC",
323 "GS_EVENT_MULTI_CAMPAIGN_SELECT",
324 "GS_EVENT_MULTI_SERVER_TRANSFER",
325 "GS_EVENT_MULTI_START_GAME", // 65
326 "GS_EVENT_MULTI_HOST_OPTIONS",
327 "GS_EVENT_MULTI_DOGFIGHT_DEBRIEF",
328 "GS_EVENT_CAMPAIGN_ROOM",
329 "GS_EVENT_CMD_BRIEF",
330 "GS_EVENT_TOGGLE_GLIDE", // 70
331 "GS_EVENT_RED_ALERT",
332 "GS_EVENT_SIMULATOR_ROOM",
333 "GS_EVENT_EMD_CAMPAIGN",
337 // Text of state, corresponding to #define values for GS_STATE_*
339 char *GS_state_text[] =
342 "GS_STATE_MAIN_MENU", // 1
343 "GS_STATE_GAME_PLAY",
344 "GS_STATE_GAME_PAUSED",
345 "GS_STATE_QUIT_GAME",
346 "GS_STATE_OPTIONS_MENU", // 5
347 "GS_EVENT_WEAPON_SELECT_HELP",
348 "GS_STATE_BARRACKS_MENU",
349 "GS_STATE_TECH_MENU",
350 "GS_STATE_TRAINING_MENU",
351 "GS_STATE_LOAD_MISSION_MENU", // 10
353 "GS_STATE_SHIP_SELECT",
354 "GS_STATE_DEBUG_PAUSED",
355 "GS_STATE_HUD_CONFIG",
356 "GS_STATE_MULTI_SETUP", // 15
357 "GS_STATE_MULTI_JOIN_GAME",
358 "GS_STATE_CONTROL_CONFIG",
359 "GS_STATE_MULTI_PROTO_CHOICE",
360 "GS_STATE_SAVE_RESTORE",
361 "GS_STATE_WEAPON_SELECT", // 20
362 "GS_STATE_MISSION_LOG_SCROLLBACK",
363 "GS_STATE_MAIN_MENU_HELP",
364 "GS_STATE_GAMEPLAY_HELP",
365 "GS_STATE_SHIP_SELECT_HELP",
366 "GS_STATE_DEATH_DIED", // 25
367 "GS_STATE_DEATH_BLEW_UP",
368 "GS_STATE_SIMULATOR_ROOM",
370 "GS_STATE_SHOW_GOALS",
371 "GS_STATE_HOTKEY_SCREEN", // 30
372 "GS_STATE_HOTKEY_SCREEN_HELP",
373 "GS_STATE_VIEW_MEDALS",
374 "GS_STATE_MULTI_HOST_SETUP",
375 "GS_STATE_MULTI_CLIENT_SETUP",
376 "GS_STATE_DEBRIEF", // 35
378 "GS_STATE_MULTI_JOIN_TRACKER",
379 "GS_STATE_VIEW_CUTSCENES",
380 "GS_STATE_MULTI_STD_WAIT",
381 "GS_STATE_STANDALONE_MAIN", // 40
382 "GS_STATE_MULTI_PAUSED",
383 "GS_STATE_BRIEFING_HELP",
384 "GS_STATE_TEAM_SELECT",
385 "GS_STATE_TRAINING_PAUSED",
386 "GS_STATE_MULTI_HELP", // 45
387 "GS_STATE_INGAME_PRE_JOIN",
388 "GS_STATE_EVENT_DEBUG",
389 "GS_STATE_STANDALONE_POSTGAME",
390 "GS_STATE_INITIAL_PLAYER_SELECT",
391 "GS_STATE_MULTI_MISSION_SYNC", // 50
392 "GS_STATE_MULTI_SERVER_TRANSFER",
393 "GS_STATE_MULTI_START_GAME",
394 "GS_STATE_MULTI_HOST_OPTIONS",
395 "GS_STATE_MULTI_DOGFIGHT_DEBRIEF",
396 "GS_STATE_CAMPAIGN_ROOM", // 55
397 "GS_STATE_CMD_BRIEF",
398 "GS_STATE_RED_ALERT",
399 "GS_STATE_END_OF_CAMPAIGN",
407 for (i=0; i<GS_STACK_SIZE; i++ ) {
408 // gs[i].current_state = GS_STATE_MAIN_MENU;
409 gs[i].current_state = 0;
414 gs_current_stack = 0;
416 state_processing_event_post = 0;
417 state_in_event_processer = 0;
420 // gameseq_post_event posts a new game sequencing event onto the gameseq
423 void gameseq_post_event( int event )
425 if (state_processing_event_post) {
426 nprintf(("Warning", "Received post for event %s during state transtition. Find Allender if you are unsure if this is bad.\n", GS_event_text[event] ));
429 Assert(gs[gs_current_stack].queue_tail < MAX_GAMESEQ_EVENTS);
430 gs[gs_current_stack].event_queue[gs[gs_current_stack].queue_tail++] = event;
431 if ( gs[gs_current_stack].queue_tail == MAX_GAMESEQ_EVENTS )
432 gs[gs_current_stack].queue_tail = 0;
435 // returns one of the GS_EVENT_ id's on the game sequencing queue
437 int gameseq_get_event()
441 if ( gs[gs_current_stack].queue_head == gs[gs_current_stack].queue_tail )
443 event = gs[gs_current_stack].event_queue[gs[gs_current_stack].queue_head++];
444 if ( gs[gs_current_stack].queue_head == MAX_GAMESEQ_EVENTS )
445 gs[gs_current_stack].queue_head = 0;
450 // returns one of the GS_STATE_ macros
451 int gameseq_get_state(int depth)
453 Assert(depth <= gs_current_stack);
455 return gs[gs_current_stack - depth].current_state;
458 int gameseq_get_depth()
460 return gs_current_stack;
463 void gameseq_set_state(int new_state, int override)
465 int event, old_state;
467 if ( (new_state == gs[gs_current_stack].current_state) && !override )
470 old_state = gs[gs_current_stack].current_state;
472 // Flush all events!!
473 while ( (event = gameseq_get_event()) != -1 ) {
474 mprintf(( "Throwing out event %d because of state set from %d to %d\n", event, old_state, new_state ));
477 Assert( state_reentry == 1 ); // Get John! (Invalid state sequencing!)
478 Assert( state_in_event_processer == 1 ); // can only call from game_process_event
480 state_processing_event_post++;
482 game_leave_state(gs[gs_current_stack].current_state,new_state);
484 gs[gs_current_stack].current_state = new_state;
486 game_enter_state(old_state,gs[gs_current_stack].current_state);
488 state_processing_event_post--;
491 void gameseq_push_state( int new_state )
493 if ( new_state == gs[gs_current_stack].current_state )
496 int old_state = gs[gs_current_stack].current_state;
498 // Flush all events!!
499 // I commented out because I'm not sure if we should throw out events when pushing or not.
501 // while( (event = gameseq_get_event()) != -1 ) {
502 // mprintf(( "Throwing out event %d because of state push from %d to %d\n", event, old_state, new_state ));
505 Assert( state_reentry == 1 ); // Get John! (Invalid state sequencing!)
506 Assert( state_in_event_processer == 1 ); // can only call from game_process_event
509 Assert(gs_current_stack < GS_STACK_SIZE);
511 state_processing_event_post++;
513 game_leave_state(old_state,new_state);
515 gs[gs_current_stack].current_state = new_state;
516 gs[gs_current_stack].queue_tail = 0;
517 gs[gs_current_stack].queue_head = 0;
519 game_enter_state(old_state,gs[gs_current_stack].current_state);
521 state_processing_event_post--;
524 void gameseq_pop_state()
526 int popped_state = 0;
528 Assert(state_reentry == 1); // Get John! (Invalid state sequencing!)
530 if (gs_current_stack >= 1) {
533 // set the old state to be the state which is about to be popped off the queue
534 old_state = gs[gs_current_stack].current_state;
536 // set the popped_state to be the state which is going to be moved into
537 popped_state = gs[gs_current_stack-1].current_state;
539 // leave the current state
541 game_leave_state(gs[gs_current_stack].current_state,popped_state);
543 // set the popped_state to be the one we moved into
545 popped_state = gs[gs_current_stack].current_state;
547 // swap all remaining events from the state which just got popped to this new state
548 while(gs[gs_current_stack+1].queue_head != gs[gs_current_stack+1].queue_tail){
549 gameseq_post_event(gs[gs_current_stack+1].event_queue[gs[gs_current_stack+1].queue_head++]);
552 game_enter_state(old_state, gs[gs_current_stack].current_state);
559 // gameseq_pop_and_discard_state() is used to remove a state that was pushed onto the stack, but
560 // will never need to be popped. An example of this is entering a state that may require returning
561 // to the previous state (then you would call gameseq_pop_state). Or you may simply continue to
562 // another part of the game, to avoid filling up the stack with states that may never be popped, you
563 // call this function to discard the top of the gs.
566 void gameseq_pop_and_discard_state()
568 if (gs_current_stack > 0 ) {
573 // Returns the last state pushed on stack
574 int gameseq_get_pushed_state()
576 if (gs_current_stack >= 1) {
577 return gs[gs_current_stack-1].current_state;
582 // gameseq_process_events gets called every time through high level loops
583 // (i.e. game loops, main menu loop). Function is responsible for pulling
584 // game sequence events off the queue and changing the state when necessary.
585 // Returns the current state.
586 // pull events game sequence events off of the queue. Process one at a time
587 // based on the current state and the new event.
589 int gameseq_process_events()
591 int event, old_state;
592 old_state = gs[gs_current_stack].current_state;
594 Assert(state_reentry == 0); // Get John! (Invalid state sequencing!)
596 while ( (event = gameseq_get_event()) != -1 ) {
598 state_in_event_processer++;
599 game_process_event(gs[gs_current_stack].current_state, event);
600 state_in_event_processer--;
602 // break when state changes so that code will get called at
603 // least one frame for each state.
604 if (old_state != gs[gs_current_stack].current_state)
609 game_do_state(gs[gs_current_stack].current_state);
612 return gs[gs_current_stack].current_state;