1 //Copyright Paul Reiche, Fred Ford. 1992-2002
2
3 /*
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18
19 #include <stdlib.h>
20
21 #include "comm.h"
22 #include "battle.h"
23 #include "fmv.h"
24 #include "gameev.h"
25 #include "types.h"
26 #include "globdata.h"
27 #include "resinst.h"
28 #include "restart.h"
29 #include "starbase.h"
30 #include "save.h"
31 #include "setup.h"
32 #include "master.h"
33 #include "controls.h"
34 #include "starcon.h"
35 #include "clock.h"
36 // for GameClockTick()
37 #include "hyper.h"
38 // for SeedUniverse()
39 #include "planets/planets.h"
40 // for ExploreSolarSys()
41 #include "uqmdebug.h"
42 #include "libs/tasklib.h"
43 #include "libs/log.h"
44 #include "libs/gfxlib.h"
45 #include "libs/graphics/gfx_common.h"
46 #include "libs/graphics/tfb_draw.h"
47 #include "libs/misc.h"
48
49 #include "uqmversion.h"
50 #include "options.h"
51
52 volatile int MainExited = FALSE;
53 #ifdef DEBUG_SLEEP
54 uint32 mainThreadId;
55 extern uint32 SDL_ThreadID(void);
56 #endif
57
58 // Open or close the periodically occuring QuasiSpace portal.
59 // It changes the appearant portal size when necessary.
60 static void
checkArilouGate(void)61 checkArilouGate (void)
62 {
63 BYTE counter;
64
65 counter = GET_GAME_STATE (ARILOU_SPACE_COUNTER);
66 if (GET_GAME_STATE (ARILOU_SPACE) == OPENING)
67 { // The portal is opening or fully open
68 if (counter < 9)
69 ++counter;
70 }
71 else
72 { // The portal is closing or fully closed
73 if (counter > 0)
74 --counter;
75 }
76 SET_GAME_STATE (ARILOU_SPACE_COUNTER, counter);
77 }
78
79 // Battle frame callback function.
80 static void
on_battle_frame(void)81 on_battle_frame (void)
82 {
83 GameClockTick ();
84 checkArilouGate ();
85
86 if (!(GLOBAL (CurrentActivity) & (CHECK_ABORT | CHECK_LOAD)))
87 SeedUniverse ();
88
89 DrawAutoPilotMessage (FALSE);
90 }
91
92 static void
BackgroundInitKernel(DWORD TimeOut)93 BackgroundInitKernel (DWORD TimeOut)
94 {
95 LoadMasterShipList (TaskSwitch);
96 TaskSwitch ();
97 InitGameKernel ();
98
99 while ((GetTimeCounter () <= TimeOut) &&
100 !(GLOBAL (CurrentActivity) & CHECK_ABORT))
101 {
102 UpdateInputState ();
103 TaskSwitch ();
104 }
105 }
106
107 // Executes on the main() thread
108 void
SignalStopMainThread(void)109 SignalStopMainThread (void)
110 {
111 GamePaused = FALSE;
112 GLOBAL (CurrentActivity) |= CHECK_ABORT;
113 TaskSwitch ();
114 }
115
116 // Executes on the main() thread
117 void
ProcessUtilityKeys(void)118 ProcessUtilityKeys (void)
119 {
120 if (ImmediateInputState.menu[KEY_ABORT])
121 {
122 log_showBox (false, false);
123 exit (EXIT_SUCCESS);
124 }
125
126 if (ImmediateInputState.menu[KEY_FULLSCREEN])
127 {
128 int flags = GfxFlags ^ TFB_GFXFLAGS_FULLSCREEN;
129 // clear ImmediateInputState so we don't repeat this next frame
130 FlushInput ();
131 TFB_DrawScreen_ReinitVideo (GraphicsDriver, flags, ScreenWidthActual,
132 ScreenHeightActual);
133 }
134
135 #if defined(DEBUG) || defined(USE_DEBUG_KEY)
136 { // Only call the debug func on the rising edge of
137 // ImmediateInputState[KEY_DEBUG] so it does not execute repeatedly.
138 // This duplicates the PulsedInputState somewhat, but we cannot
139 // use PulsedInputState here because it is meant for another thread.
140 static int debugKeyState;
141
142 if (ImmediateInputState.menu[KEY_DEBUG] && debugKeyState == 0)
143 {
144 debugKeyPressed ();
145 }
146 debugKeyState = ImmediateInputState.menu[KEY_DEBUG];
147 }
148 #endif /* DEBUG */
149 }
150
151 /* TODO: Remove these declarations once threading is gone. */
152 extern int snddriver, soundflags;
153
154 int
Starcon2Main(void * threadArg)155 Starcon2Main (void *threadArg)
156 {
157 #ifdef DEBUG_SLEEP
158 mainThreadId = SDL_ThreadID();
159 #endif
160
161 #if CREATE_JOURNAL
162 {
163 int ac = argc;
164 char **av = argv;
165
166 while (--ac > 0)
167 {
168 ++av;
169 if ((*av)[0] == '-')
170 {
171 switch ((*av)[1])
172 {
173 #if CREATE_JOURNAL
174 case 'j':
175 ++create_journal;
176 break;
177 #endif //CREATE_JOURNAL
178 }
179 }
180 }
181 }
182 #endif // CREATE_JOURNAL
183
184 {
185 /* TODO: Put initAudio back in main where it belongs once threading
186 * is gone.
187 */
188 extern sint32 initAudio (sint32 driver, sint32 flags);
189 initAudio (snddriver, soundflags);
190 }
191
192 if (!LoadKernel (0,0))
193 {
194 log_add (log_Fatal, "\n *** FATAL ERROR: Could not load basic content ***\n\nUQM requires at least the base content pack to run properly.");
195 log_add (log_Fatal, "This file is typically called uqm-%d.%d.0-content.uqm. UQM was expecting", UQM_MAJOR_VERSION, UQM_MINOR_VERSION);
196 log_add (log_Fatal, "it in the %s/packages directory.", baseContentPath);
197 log_add (log_Fatal, "Either your installation did not install the content pack at all, or it\ninstalled it in a different directory.\n\nFix your installation and rerun UQM.\n\n *******************\n");
198 log_showBox (true, true);
199
200 MainExited = TRUE;
201 return EXIT_FAILURE;
202 }
203 log_add (log_Info, "We've loaded the Kernel");
204
205 GLOBAL (CurrentActivity) = 0;
206 // show splash and init the kernel in the meantime
207 SplashScreen (BackgroundInitKernel);
208
209 // OpenJournal ();
210 while (StartGame ())
211 {
212 // Initialise a new game
213 if (!SetPlayerInputAll ()) {
214 log_add (log_Fatal, "Could not set player input.");
215 explode (); // Does not return;
216 }
217 InitGameStructures ();
218 InitGameClock ();
219 AddInitialGameEvents();
220
221 do
222 {
223 #ifdef DEBUG
224 if (debugHook != NULL)
225 {
226 void (*saveDebugHook) (void);
227 saveDebugHook = debugHook;
228 debugHook = NULL;
229 // No further debugHook calls unless the called
230 // function resets debugHook.
231 (*saveDebugHook) ();
232 continue;
233 }
234 #endif
235 SetStatusMessageMode (SMM_DEFAULT);
236
237 if (!((GLOBAL (CurrentActivity) | NextActivity) & CHECK_LOAD))
238 ZeroVelocityComponents (&GLOBAL (velocity));
239 // not going into talking pet conversation
240 else if (GLOBAL (CurrentActivity) & CHECK_LOAD)
241 GLOBAL (CurrentActivity) = NextActivity;
242
243 if ((GLOBAL (CurrentActivity) & START_ENCOUNTER)
244 || GET_GAME_STATE (CHMMR_BOMB_STATE) == 2)
245 {
246 if (GET_GAME_STATE (CHMMR_BOMB_STATE) == 2
247 && !GET_GAME_STATE (STARBASE_AVAILABLE))
248 { /* BGD mode */
249 InstallBombAtEarth ();
250 }
251 else if (GET_GAME_STATE (GLOBAL_FLAGS_AND_DATA) == (BYTE)~0
252 || GET_GAME_STATE (CHMMR_BOMB_STATE) == 2)
253 {
254 GLOBAL (CurrentActivity) |= START_ENCOUNTER;
255 VisitStarBase ();
256 }
257 else
258 {
259 GLOBAL (CurrentActivity) |= START_ENCOUNTER;
260 RaceCommunication ();
261 }
262
263 if (!(GLOBAL (CurrentActivity) & (CHECK_ABORT | CHECK_LOAD)))
264 {
265 GLOBAL (CurrentActivity) &= ~START_ENCOUNTER;
266 if (LOBYTE (GLOBAL (CurrentActivity)) == IN_INTERPLANETARY)
267 GLOBAL (CurrentActivity) |= START_INTERPLANETARY;
268 }
269 }
270 else if (GLOBAL (CurrentActivity) & START_INTERPLANETARY)
271 {
272 GLOBAL (CurrentActivity) = MAKE_WORD (IN_INTERPLANETARY, 0);
273
274 DrawAutoPilotMessage (TRUE);
275 SetGameClockRate (INTERPLANETARY_CLOCK_RATE);
276 ExploreSolarSys ();
277 }
278 else
279 {
280 // Entering HyperSpace or QuasiSpace.
281 GLOBAL (CurrentActivity) = MAKE_WORD (IN_HYPERSPACE, 0);
282
283 DrawAutoPilotMessage (TRUE);
284 SetGameClockRate (HYPERSPACE_CLOCK_RATE);
285 Battle (&on_battle_frame);
286 }
287
288 SetFlashRect (NULL);
289
290 LastActivity = GLOBAL (CurrentActivity);
291
292 if (!(GLOBAL (CurrentActivity) & (CHECK_ABORT | CHECK_LOAD))
293 && (LOBYTE (GLOBAL (CurrentActivity)) == WON_LAST_BATTLE
294 // if died for some reason
295 || GLOBAL_SIS (CrewEnlisted) == (COUNT)~0))
296 {
297 if (GET_GAME_STATE (KOHR_AH_KILLED_ALL))
298 InitCommunication (BLACKURQ_CONVERSATION);
299 // surrendered to Ur-Quan
300 else if (GLOBAL (CurrentActivity) & CHECK_RESTART)
301 GLOBAL (CurrentActivity) &= ~CHECK_RESTART;
302 break;
303 }
304 } while (!(GLOBAL (CurrentActivity) & CHECK_ABORT));
305
306 StopSound ();
307 UninitGameClock ();
308 UninitGameStructures ();
309 ClearPlayerInputAll ();
310 }
311 // CloseJournal ();
312
313 UninitGameKernel ();
314 FreeMasterShipList ();
315 FreeKernel ();
316
317 log_showBox (false, false);
318 MainExited = TRUE;
319
320 (void) threadArg; /* Satisfying compiler (unused parameter) */
321 return 0;
322 }
323
324