1
2 #include "../nx.h"
3 #include "../main.fdh"
4 #include "libretro_shared.h"
5 #include "extract-auto/cachefiles.h"
6
7 #ifdef _WIN32
8 #include "msvc_compat.h"
9 #endif
10
11 const char *data_dir = "data";
12 #ifdef _WIN32
13 const char *stage_dir = "data\\Stage";
14 #else
15 const char *stage_dir = "data/Stage";
16 #endif
17 const char *pic_dir = "endpic";
18 const char *nxdata_dir = ".";
19
20 int fps = 0;
21 static int fps_so_far = 0;
22 static uint32_t fpstimer = 0;
23
24 #define GAME_WAIT (1000/GAME_FPS) // sets framerate
25 #define VISFLAGS (SDL_APPACTIVE | SDL_APPINPUTFOCUS)
26 int framecount = 0;
27 bool freezeframe = false;
28
29 static bool inhibit_loadfade = false;
30 static bool freshstart;
31
32 //extern bool extract_files(FILE *exefp);
33 extern bool extract_stages(FILE *exefp);
34
pre_main(void)35 bool pre_main(void)
36 {
37 char filename[1024];
38 FILE *fp;
39
40 #ifdef DEBUG_LOG
41 char debug_fname[1024];
42 retro_create_path_string(debug_fname, sizeof(debug_fname), g_dir, "debug.txt");
43 SetLogFilename(debug_fname);
44 #endif
45 // start up inputs first thing because settings_load may remap them
46 input_init();
47
48 // load settings, or at least get the defaults,
49 // so we know the initial screen resolution.
50 settings_load();
51
52 NX_LOG("= Extracting Files =\n");
53
54 retro_create_path_string(filename, sizeof(filename), g_dir, "Doukutsu.exe");
55 fp = fopen(filename, "rb");
56
57 //extract_files(fp);
58 if (!cachefiles_init(fp))
59 return 1;
60
61 if (sound_init(fp))
62 {
63 fatal("Failed to initialize sound.");
64 return 1;
65 }
66
67 if (extract_stages(fp))
68 {
69 fclose(fp);
70 return 1;
71 }
72
73 fclose(fp);
74
75 settings->files_extracted = true;
76 settings_save();
77
78 if (Graphics::init(settings->resolution))
79 {
80 NX_ERR("Failed to initialize graphics.\n");
81 return 1;
82 }
83 if (font_init())
84 {
85 NX_ERR("Failed to load font.\n");
86 return 1;
87 }
88
89 //return error;
90
91 if (check_data_exists())
92 return 1;
93
94 if (trig_init())
95 {
96 fatal("Failed trig module init.");
97 return 1;
98 }
99
100 if (tsc_init())
101 {
102 fatal("Failed to initialize script engine.");
103 return 1;
104 }
105
106 if (textbox.Init())
107 {
108 fatal("Failed to initialize textboxes.");
109 return 1;
110 }
111 if (Carets::init())
112 {
113 fatal("Failed to initialize carets.");
114 return 1;
115 }
116
117 if (game.init())
118 return 1;
119
120 game.setmode(GM_NORMAL);
121 // set null stage just to have something to do while we go to intro
122 game.switchstage.mapno = 0;
123
124 //game.switchstage.mapno = LOAD_GAME;
125 //game.pause(GP_OPTIONS);
126
127 if (settings->skip_intro && file_exists(GetProfileName(settings->last_save_slot)))
128 game.switchstage.mapno = LOAD_GAME;
129 else
130 game.setmode(GM_INTRO);
131
132 // for debug
133 if (game.paused) { game.switchstage.mapno = 0; game.switchstage.eventonentry = 0; }
134 if (game.switchstage.mapno == LOAD_GAME) inhibit_loadfade = true;
135
136 game.running = true;
137 freshstart = true;
138
139 NX_LOG("Entering main loop...\n");
140
141 return 0;
142 }
143
post_main(void)144 void post_main(void)
145 {
146 if (game.close)
147 game.close();
148 Carets::close();
149
150 Graphics::close();
151 input_close();
152 font_close();
153 sound_close();
154 tsc_close();
155 textbox.Deinit();
156 }
157
gameloop(void)158 static bool gameloop(void)
159 {
160 //uint32_t gametimer;
161
162 //gametimer = -GAME_WAIT*10;
163
164 if(game.switchstage.mapno < 0)
165 {
166 run_tick();
167 return true;
168 }
169 else
170 return false;
171 }
172
173 static bool in_gameloop = false;
174
run_main(void)175 bool run_main(void)
176 {
177 if (in_gameloop)
178 goto loop;
179 // SSS/SPS persists across stage transitions until explicitly
180 // stopped, or you die & reload. It seems a bit risky to me,
181 // but that's the spec.
182 if (game.switchstage.mapno >= MAPNO_SPECIALS)
183 {
184 StopLoopSounds();
185 }
186
187 // enter next stage, whatever it may be
188 if (game.switchstage.mapno == LOAD_GAME || \
189 game.switchstage.mapno == LOAD_GAME_FROM_MENU)
190 {
191 if (game.switchstage.mapno == LOAD_GAME_FROM_MENU)
192 freshstart = true;
193
194 NX_LOG("= Loading game =\n");
195 if (game_load(settings->last_save_slot))
196 {
197 fatal("savefile error");
198 game.running = false;
199 return 1;
200 }
201
202 if (!inhibit_loadfade) fade.Start(FADE_IN, FADE_CENTER);
203 else inhibit_loadfade = false;
204 }
205 else
206 {
207 if (game.switchstage.mapno == NEW_GAME || \
208 game.switchstage.mapno == NEW_GAME_FROM_MENU)
209 {
210 static bool show_intro = (game.switchstage.mapno == NEW_GAME_FROM_MENU);
211 InitNewGame(show_intro);
212 }
213
214 // slide weapon bar on first intro to Start Point
215 if (game.switchstage.mapno == STAGE_START_POINT && \
216 game.switchstage.eventonentry == 91)
217 {
218 freshstart = true;
219 }
220
221 // switch maps
222 if (load_stage(game.switchstage.mapno))
223 {
224 game.running = false;
225 return 1;
226 }
227
228 player->x = (game.switchstage.playerx * TILE_W) << CSF;
229 player->y = (game.switchstage.playery * TILE_H) << CSF;
230 }
231
232 // start the level
233 if (game.initlevel())
234 {
235 game.running = false;
236 return 1;
237 }
238
239 if (freshstart)
240 weapon_introslide();
241
242 game.switchstage.mapno = -1;
243 loop:
244 in_gameloop = true;
245 if (gameloop())
246 return true;
247 in_gameloop = false;
248
249 game.stageboss.OnMapExit();
250 freshstart = false;
251 return false;
252 }
253
run_tick()254 static inline void run_tick()
255 {
256 input_poll();
257
258 // input handling for a few global things
259 if (justpushed(ESCKEY))
260 {
261 if (settings->instant_quit)
262 {
263 game.running = false;
264 }
265 else if (!game.paused) // no pause from Options
266 {
267 game.pause(GP_PAUSED);
268 }
269 }
270 else if (justpushed(F3KEY))
271 {
272 game.pause(GP_OPTIONS);
273 }
274
275 // freeze frame
276 game.tick();
277
278 org_run();
279
280 memcpy(lastinputs, inputs, sizeof(lastinputs));
281 }
282
InitNewGame(bool with_intro)283 void InitNewGame(bool with_intro)
284 {
285 NX_LOG("= Beginning new game =\n");
286
287 memset(game.flags, 0, sizeof(game.flags));
288 memset(game.skipflags, 0, sizeof(game.skipflags));
289 textbox.StageSelect.ClearSlots();
290
291 game.quaketime = game.megaquaketime = 0;
292 game.showmapnametime = 0;
293 game.debug.god = 0;
294 game.running = true;
295 game.frozen = false;
296
297 // fully re-init the player object
298 Objects::DestroyAll(true);
299 game.createplayer();
300
301 player->maxHealth = 3;
302 player->hp = player->maxHealth;
303
304 game.switchstage.mapno = STAGE_START_POINT;
305 game.switchstage.playerx = 10;
306 game.switchstage.playery = 8;
307 game.switchstage.eventonentry = (with_intro) ? 200 : 91;
308
309 fade.set_full(FADE_OUT);
310 }
311
312 /*
313 void c------------------------------() {}
314 */
315
fatal(const char * str)316 static void fatal(const char *str)
317 {
318 NX_ERR("Fatal error: '%s'\n", str);
319 }
320
check_data_exists()321 static bool check_data_exists()
322 {
323 char fname[1024];
324 retro_create_subpath_string(fname, sizeof(fname), g_dir, data_dir, "npc.tbl");
325 NX_LOG("check_data_exists: %s\n", fname);
326
327 if (file_exists(fname))
328 return 0;
329
330 NX_ERR("Fatal Error\n");
331
332 NX_ERR("Missing \"%s\" directory.\n", data_dir);
333 NX_ERR("Please copy it over from a Doukutsu installation.\n");
334
335 return 1;
336 }
337
visible_warning(const char * fmt,...)338 void visible_warning(const char *fmt, ...)
339 {
340 #if defined(_MSC_VER) && _MSC_VER <= 1310
341 #else
342 va_list ar;
343 char buffer[80];
344
345 va_start(ar, fmt);
346 vsnprintf(buffer, sizeof(buffer), fmt, ar);
347 va_end(ar);
348 #endif
349 }
350