FS2_Open
Open source remastering of the Freespace 2 engine
gamesequence.cpp
Go to the documentation of this file.
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  * All states for game sequencing are defined in GameSequence.h.
14  * States should always be referred to using the macros.
15 */
16 
18 #include "globalincs/pstypes.h"
19 #include "parse/scripting.h"
20 
21 
22 
23 // local defines
24 #define MAX_GAMESEQ_EVENTS 20 // maximum number of events on the game sequencing queue
25 #define GS_STACK_SIZE 10 // maximum number of stacked states
26 
27 // local variables
28 typedef struct state_stack {
33 } state_stack;
34 
35 // DO NOT MAKE THIS NON-STATIC!!!!
37 LOCAL int gs_current_stack = -1; // index of top state on stack.
38 
39 static int state_reentry = 0; // set if we are already in state processing
40 static int state_processing_event_post = 0; // set if we are already processing an event to switch states
41 static int state_in_event_processer = 0;
42 
44 
45 // Text of state, corresponding to enum values for GS_STATE_*
46 //XSTR:OFF
47 char *GS_event_text[] =
48 {
49  "GS_EVENT_MAIN_MENU", // 0
50  "GS_EVENT_START_GAME",
51  "GS_EVENT_ENTER_GAME",
52  "GS_EVENT_START_GAME_QUICK",
53  "GS_EVENT_END_GAME",
54  "GS_EVENT_QUIT_GAME", // 5
55  "GS_EVENT_PAUSE_GAME",
56  "GS_EVENT_PREVIOUS_STATE",
57  "GS_EVENT_OPTIONS_MENU",
58  "GS_EVENT_BARRACKS_MENU",
59  "GS_EVENT_TRAINING_MENU", // 10
60  "GS_EVENT_TECH_MENU",
61  "GS_EVENT_LOAD_MISSION_MENU",
62  "GS_EVENT_SHIP_SELECTION",
63  "GS_EVENT_TOGGLE_FULLSCREEN",
64  "GS_EVENT_START_BRIEFING", // 15
65  "GS_EVENT_DEBUG_PAUSE_GAME",
66  "GS_EVENT_HUD_CONFIG",
67  "GS_EVENT_MULTI_JOIN_GAME",
68  "GS_EVENT_CONTROL_CONFIG",
69  "GS_EVENT_EVENT_DEBUG", // 20
70  "GS_EVENT_WEAPON_SELECTION",
71  "GS_EVENT_MISSION_LOG_SCROLLBACK",
72  "GS_EVENT_GAMEPLAY_HELP",
73  "GS_EVENT_DEATH_DIED",
74  "GS_EVENT_DEATH_BLEW_UP", // 25
75  "GS_EVENT_NEW_CAMPAIGN",
76  "GS_EVENT_CREDITS",
77  "GS_EVENT_SHOW_GOALS",
78  "GS_EVENT_HOTKEY_SCREEN",
79  "GS_EVENT_VIEW_MEDALS", // 30
80  "GS_EVENT_MULTI_HOST_SETUP",
81  "GS_EVENT_MULTI_CLIENT_SETUP",
82  "GS_EVENT_DEBRIEF",
83  "GS_EVENT_GOTO_VIEW_CUTSCENES_SCREEN",
84  "GS_EVENT_MULTI_STD_WAIT", // 35
85  "GS_EVENT_STANDALONE_MAIN",
86  "GS_EVENT_MULTI_PAUSE",
87  "GS_EVENT_TEAM_SELECT",
88  "GS_EVENT_TRAINING_PAUSE",
89  "GS_EVENT_INGAME_PRE_JOIN", // 40
90  "GS_EVENT_PLAYER_WARPOUT_START",
91  "GS_EVENT_PLAYER_WARPOUT_START_FORCED",
92  "GS_EVENT_PLAYER_WARPOUT_STOP",
93  "GS_EVENT_PLAYER_WARPOUT_DONE_STAGE1",
94  "GS_EVENT_PLAYER_WARPOUT_DONE_STAGE2", // 45
95  "GS_EVENT_PLAYER_WARPOUT_DONE",
96  "GS_EVENT_STANDALONE_POSTGAME",
97  "GS_EVENT_INITIAL_PLAYER_SELECT",
98  "GS_EVENT_GAME_INIT",
99  "GS_EVENT_MULTI_MISSION_SYNC", // 50
100  "GS_EVENT_MULTI_START_GAME",
101  "GS_EVENT_MULTI_HOST_OPTIONS",
102  "GS_EVENT_MULTI_DOGFIGHT_DEBRIEF",
103  "GS_EVENT_CAMPAIGN_ROOM",
104  "GS_EVENT_CMD_BRIEF", // 55
105  "GS_EVENT_TOGGLE_GLIDE",
106  "GS_EVENT_RED_ALERT",
107  "GS_EVENT_SIMULATOR_ROOM",
108  "GS_EVENT_END_CAMPAIGN",
109  "GS_EVENT_LOOP_BRIEF", // 60
110  "GS_EVENT_CAMPAIGN_CHEAT",
111  "GS_EVENT_PXO",
112  "GS_EVENT_LAB",
113  "GS_EVENT_PXO_HELP",
114  "GS_EVENT_FICTION_VIEWER", // 65
115  "GS_EVENT_SCRIPTING"
116 };
117 //XSTR:ON
118 
119 int Num_gs_event_text = sizeof(GS_event_text)/sizeof(char*);
120 
121 // Text of state, corresponding to enum values for GS_STATE_*
122 //XSTR:OFF
123 char *GS_state_text[] =
124 {
125  "NOT A VALID STATE", // 0
126  "GS_STATE_MAIN_MENU",
127  "GS_STATE_GAME_PLAY",
128  "GS_STATE_GAME_PAUSED",
129  "GS_STATE_QUIT_GAME",
130  "GS_STATE_OPTIONS_MENU", // 5
131  "GS_STATE_BARRACKS_MENU",
132  "GS_STATE_TECH_MENU",
133  "GS_STATE_TRAINING_MENU",
134  "GS_STATE_LOAD_MISSION_MENU",
135  "GS_STATE_BRIEFING", // 10
136  "GS_STATE_SHIP_SELECT",
137  "GS_STATE_DEBUG_PAUSED",
138  "GS_STATE_HUD_CONFIG",
139  "GS_STATE_MULTI_JOIN_GAME",
140  "GS_STATE_CONTROL_CONFIG", // 15
141  "GS_STATE_WEAPON_SELECT",
142  "GS_STATE_MISSION_LOG_SCROLLBACK",
143  "GS_STATE_DEATH_DIED",
144  "GS_STATE_DEATH_BLEW_UP",
145  "GS_STATE_SIMULATOR_ROOM", // 20
146  "GS_STATE_CREDITS",
147  "GS_STATE_SHOW_GOALS",
148  "GS_STATE_HOTKEY_SCREEN",
149  "GS_STATE_VIEW_MEDALS",
150  "GS_STATE_MULTI_HOST_SETUP", // 25
151  "GS_STATE_MULTI_CLIENT_SETUP",
152  "GS_STATE_DEBRIEF",
153  "GS_STATE_VIEW_CUTSCENES",
154  "GS_STATE_MULTI_STD_WAIT",
155  "GS_STATE_STANDALONE_MAIN", // 30
156  "GS_STATE_MULTI_PAUSED",
157  "GS_STATE_TEAM_SELECT",
158  "GS_STATE_TRAINING_PAUSED",
159  "GS_STATE_INGAME_PRE_JOIN",
160  "GS_STATE_EVENT_DEBUG", // 35
161  "GS_STATE_STANDALONE_POSTGAME",
162  "GS_STATE_INITIAL_PLAYER_SELECT",
163  "GS_STATE_MULTI_MISSION_SYNC",
164  "GS_STATE_MULTI_START_GAME",
165  "GS_STATE_MULTI_HOST_OPTIONS", // 40
166  "GS_STATE_MULTI_DOGFIGHT_DEBRIEF",
167  "GS_STATE_CAMPAIGN_ROOM",
168  "GS_STATE_CMD_BRIEF",
169  "GS_STATE_RED_ALERT",
170  "GS_STATE_END_OF_CAMPAIGN", // 45
171  "GS_STATE_GAMEPLAY_HELP",
172  "GS_STATE_LOOP_BRIEF",
173  "GS_STATE_PXO",
174  "GS_STATE_LAB",
175  "GS_STATE_PXO_HELP", // 50
176  "GS_STATE_START_GAME",
177  "GS_STATE_FICTION_VIEWER",
178  "GS_STATE_SCRIPTING"
179 };
180 //XSTR:ON
181 
182 int Num_gs_state_text = sizeof(GS_state_text)/sizeof(char*);
183 
185 {
186  int i;
187 
188  for (i=0; i<GS_STACK_SIZE; i++ ) {
189  // gs[i].current_state = GS_STATE_MAIN_MENU;
190  gs[i].current_state = 0;
191  gs[i].previous_state = 0;
192  gs[i].queue_tail=0;
193  gs[i].queue_head=0;
194  }
195 
196  for (i=0; i<GS_NUM_STATES; i++ ) {
197  script_hook_init(&GS_state_hooks[i]);
198  }
199 
200  gs_current_stack = 0;
201  state_reentry = 0;
202  state_processing_event_post = 0;
203  state_in_event_processer = 0;
204 }
205 
206 // gameseq_post_event posts a new game sequencing event onto the gameseq
207 // event queue
208 
210 {
211  if (state_processing_event_post) {
212  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] ));
213  }
214 
217  if ( gs[gs_current_stack].queue_tail == MAX_GAMESEQ_EVENTS )
219 }
220 
221 // returns one of the GS_EVENT_ id's on the game sequencing queue
222 
224 {
225  int event;
226 
227  if ( gs[gs_current_stack].queue_head == gs[gs_current_stack].queue_tail )
228  return -1;
230  if ( gs[gs_current_stack].queue_head == MAX_GAMESEQ_EVENTS )
232 
233  return event;
234 }
235 
236 // Is our state stack valid
238 {
239  return (gs_current_stack != -1);
240 }
241 
242 // returns one of the GS_STATE_ macros
244 {
245  Assert(depth <= gs_current_stack);
246 
248 }
249 
251 {
253 }
254 
256 {
257  return gs_current_stack;
258 }
259 
260 void gameseq_set_state(int new_state, int override)
261 {
262  int event, old_state;
263 
264  if ( (new_state == gs[gs_current_stack].current_state) && !override )
265  return;
266 
267  old_state = gs[gs_current_stack].current_state;
268 
269  // Flush all events!!
270  while ( (event = gameseq_get_event()) != -1 ) {
271  mprintf(( "Throwing out event %d because of state set from %d to %d\n", event, old_state, new_state ));
272  }
273 
274  Assert( state_reentry == 1 ); // Get John! (Invalid state sequencing!)
275  Assert( state_in_event_processer == 1 ); // can only call from game_process_event
276 
277  state_processing_event_post++;
278  state_reentry++;
279  game_leave_state(gs[gs_current_stack].current_state,new_state);
280 
281  gs[gs_current_stack].current_state = new_state;
282  gs[gs_current_stack].previous_state = old_state;
283 
284  game_enter_state(old_state,gs[gs_current_stack].current_state);
285  state_reentry--;
286  state_processing_event_post--;
287 }
288 
289 void gameseq_push_state( int new_state )
290 {
291  if ( new_state == gs[gs_current_stack].current_state )
292  return;
293 
294  int old_state = gs[gs_current_stack].current_state;
295 
296  // Flush all events!!
297 // I commented out because I'm not sure if we should throw out events when pushing or not.
298 // int event;
299 // while( (event = gameseq_get_event()) != -1 ) {
300 // mprintf(( "Throwing out event %d because of state push from %d to %d\n", event, old_state, new_state ));
301 // }
302 
303  Assert( state_reentry == 1 ); // Get John! (Invalid state sequencing!)
304  Assert( state_in_event_processer == 1 ); // can only call from game_process_event
305 
308 
309  state_processing_event_post++;
310  state_reentry++;
311  game_leave_state(old_state,new_state);
312 
313  gs[gs_current_stack].current_state = new_state;
314  gs[gs_current_stack].previous_state = old_state;
317 
318  game_enter_state(old_state,gs[gs_current_stack].current_state);
319  state_reentry--;
320  state_processing_event_post--;
321 }
322 
324 {
325  int popped_state = 0;
326 
327  Assert(state_reentry == 1); // Get John! (Invalid state sequencing!)
328 
329  if (gs_current_stack >= 1) {
330  int old_state;
331 
332  // set the old state to be the state which is about to be popped off the queue
333  old_state = gs[gs_current_stack].current_state;
334 
335  // set the popped_state to be the state which is going to be moved into
336  popped_state = gs[gs_current_stack-1].current_state;
337 
338  // leave the current state
339  state_reentry++;
340  game_leave_state(gs[gs_current_stack].current_state,popped_state);
341 
342  // set the popped_state to be the one we moved into
344  popped_state = gs[gs_current_stack].current_state;
345  gs[gs_current_stack].previous_state = old_state;
346 
347  // swap all remaining events from the state which just got popped to this new state
348  while(gs[gs_current_stack+1].queue_head != gs[gs_current_stack+1].queue_tail){
349  gameseq_post_event(gs[gs_current_stack+1].event_queue[gs[gs_current_stack+1].queue_head++]);
350  }
351 
352  game_enter_state(old_state, gs[gs_current_stack].current_state);
353  state_reentry--;
354 
355  }
356 
357 }
358 
359 // gameseq_pop_and_discard_state() is used to remove a state that was pushed onto the stack, but
360 // will never need to be popped. An example of this is entering a state that may require returning
361 // to the previous state (then you would call gameseq_pop_state). Or you may simply continue to
362 // another part of the game, to avoid filling up the stack with states that may never be popped, you
363 // call this function to discard the top of the gs.
364 //
365 
367 {
368  if (gs_current_stack > 0 ) {
370  }
371 }
372 
373 // Returns the last state pushed on stack
375 {
376  if (gs_current_stack >= 1) {
378  } else
379  return -1;
380 }
381 
382 // gameseq_process_events gets called every time through high level loops
383 // (i.e. game loops, main menu loop). Function is responsible for pulling
384 // game sequence events off the queue and changing the state when necessary.
385 // Returns the current state.
386  // pull events game sequence events off of the queue. Process one at a time
387  // based on the current state and the new event.
388 
390 {
391  int event, old_state;
392  old_state = gs[gs_current_stack].current_state;
393 
394  Assert(state_reentry == 0); // Get John! (Invalid state sequencing!)
395 
396  while ( (event = gameseq_get_event()) != -1 ) {
397  state_reentry++;
398  state_in_event_processer++;
399  game_process_event(gs[gs_current_stack].current_state, event);
400  state_in_event_processer--;
401  state_reentry--;
402  // break when state changes so that code will get called at
403  // least one frame for each state.
404  if (old_state != gs[gs_current_stack].current_state)
405  break;
406  }
407 
408  state_reentry++;
409  game_do_state(gs[gs_current_stack].current_state);
410  state_reentry--;
411 
413 }
414 
416 {
417  for(int i = 0; i < Num_gs_event_text; i++)
418  {
419  if(!stricmp(s, GS_event_text[i])) {
420  return i;
421  }
422  }
423 
424  return -1;
425 }
426 
428 {
429  for(int i = 0; i < Num_gs_state_text; i++)
430  {
431  if(!stricmp(s, GS_state_text[i])) {
432  return i;
433  }
434  }
435 
436  return -1;
437 }
438 
439 // If the given state exists in the stack then return the index, -1 if not
440 int gameseq_get_state_idx(int state)
441 {
442  for(int i = 0; i <= gs_current_stack; i++)
443  {
444  if (gs[i].current_state == state) {
445  return i;
446  }
447  }
448 
449  return -1;
450 }
int gameseq_get_previous_state()
bool GameState_Stack_Valid()
int i
Definition: multi_pxo.cpp:466
int gameseq_process_events()
void gameseq_init()
LOCAL state_stack gs[GS_STACK_SIZE]
int gameseq_get_pushed_state()
int event_queue[MAX_GAMESEQ_EVENTS]
Assert(pm!=NULL)
#define mprintf(args)
Definition: pstypes.h:238
GLint GLint GLsizei GLsizei GLsizei depth
Definition: Glext.h:5180
int Num_gs_state_text
int gameseq_get_state(int depth)
struct state_stack state_stack
char * GS_event_text[]
char * GS_state_text[]
void game_do_state(int)
Definition: fredstubs.cpp:205
void game_enter_state(int, int)
Definition: fredstubs.cpp:183
#define nprintf(args)
Definition: pstypes.h:239
int Num_gs_event_text
int gameseq_get_state_idx(char *s)
void gameseq_pop_state()
#define GS_STACK_SIZE
void game_process_event(int, int)
Definition: fredstubs.cpp:206
GLdouble s
Definition: Glext.h:5321
#define MAX_GAMESEQ_EVENTS
void game_leave_state(int, int)
Definition: fredstubs.cpp:184
script_hook GS_state_hooks[GS_NUM_STATES]
struct _cl_event * event
Definition: Glext.h:7296
void gameseq_push_state(int new_state)
int gameseq_get_event_idx(char *s)
LOCAL int gs_current_stack
int gameseq_get_event()
#define LOCAL
Definition: pstypes.h:37
void script_hook_init(script_hook *hook)
Definition: scripting.cpp:97
void gameseq_post_event(int event)
#define stricmp(s1, s2)
Definition: config.h:271
int gameseq_get_depth()
void gameseq_pop_and_discard_state()
void gameseq_set_state(int new_state, int override)