5 #include "graphics/safemode.h"
8 const char *data_dir
= "data";
9 const char *stage_dir
= "data/Stage";
10 const char *pic_dir
= "endpic";
11 const char *nxdata_dir
= ".";
14 static int fps_so_far
= 0;
15 static uint32_t fpstimer
= 0;
17 #define GAME_WAIT (1000/GAME_FPS) // sets framerate
18 #define VISFLAGS (SDL_APPACTIVE | SDL_APPINPUTFOCUS)
20 bool freezeframe
= false;
21 int flipacceltime
= 0;
23 int main(int argc
, char *argv
[])
25 bool inhibit_loadfade
= false;
29 SetLogFilename("debug.txt");
30 if (SDL_Init(SDL_INIT_VIDEO
| SDL_INIT_AUDIO
) < 0)
32 staterr("ack, sdl_init failed: %s.", SDL_GetError());
37 // start up inputs first thing because settings_load may remap them
40 // load settings, or at least get the defaults,
41 // so we know the initial screen resolution.
44 if (Graphics::init(settings
->resolution
)) { staterr("Failed to initialize graphics."); return 1; }
45 if (font_init()) { staterr("Failed to load font."); return 1; }
50 #ifdef CONFIG_DATA_EXTRACTOR
51 if (!settings
->files_extracted
)
61 settings
->files_extracted
= true;
67 if (check_data_exists())
72 //Graphics::ShowLoadingScreen();
73 if (sound_init()) { fatal("Failed to initialize sound."); return 1; }
74 if (trig_init()) { fatal("Failed trig module init."); return 1; }
76 if (tsc_init()) { fatal("Failed to initialize script engine."); return 1; }
77 if (textbox
.Init()) { fatal("Failed to initialize textboxes."); return 1; }
78 if (Carets::init()) { fatal("Failed to initialize carets."); return 1; }
80 if (game
.init()) return 1;
81 game
.setmode(GM_NORMAL
);
82 // set null stage just to have something to do while we go to intro
83 game
.switchstage
.mapno
= 0;
87 game
.switchstage
.mapno
= START_REPLAY
;
88 //Replay::set_ffwd(6000);
89 //Replay::set_stopat(3500);
90 game
.switchstage
.param
= 1;
92 //game.switchstage.mapno = LOAD_GAME;
93 //game.pause(GP_OPTIONS);
95 if (settings
->skip_intro
&& file_exists(GetProfileName(settings
->last_save_slot
)))
96 game
.switchstage
.mapno
= LOAD_GAME
;
98 game
.setmode(GM_INTRO
);
102 if (game
.paused
) { game
.switchstage
.mapno
= 0; game
.switchstage
.eventonentry
= 0; }
103 if (game
.switchstage
.mapno
== LOAD_GAME
) inhibit_loadfade
= true;
108 stat("Entering main loop...");
110 set_console_visible(false);
118 // SSS/SPS persists across stage transitions until explicitly
119 // stopped, or you die & reload. It seems a bit risky to me,
120 // but that's the spec.
121 if (game
.switchstage
.mapno
>= MAPNO_SPECIALS
)
126 // enter next stage, whatever it may be
127 if (game
.switchstage
.mapno
== LOAD_GAME
|| \
128 game
.switchstage
.mapno
== LOAD_GAME_FROM_MENU
)
130 if (game
.switchstage
.mapno
== LOAD_GAME_FROM_MENU
)
133 stat("= Loading game =");
134 if (game_load(settings
->last_save_slot
))
136 fatal("savefile error");
140 Replay::OnGameStarting();
142 if (!inhibit_loadfade
) fade
.Start(FADE_IN
, FADE_CENTER
);
143 else inhibit_loadfade
= false;
145 else if (game
.switchstage
.mapno
== START_REPLAY
)
147 stat(">> beginning replay '%s'", GetReplayName(game
.switchstage
.param
));
150 if (Replay::begin_playback(GetReplayName(game
.switchstage
.param
)))
152 fatal("error starting playback");
158 if (game
.switchstage
.mapno
== NEW_GAME
|| \
159 game
.switchstage
.mapno
== NEW_GAME_FROM_MENU
)
161 bool show_intro
= (game
.switchstage
.mapno
== NEW_GAME_FROM_MENU
);
162 InitNewGame(show_intro
);
165 // slide weapon bar on first intro to Start Point
166 if (game
.switchstage
.mapno
== STAGE_START_POINT
&& \
167 game
.switchstage
.eventonentry
== 91)
173 if (load_stage(game
.switchstage
.mapno
)) goto ingame_error
;
175 player
->x
= (game
.switchstage
.playerx
* TILE_W
) << CSF
;
176 player
->y
= (game
.switchstage
.playery
* TILE_H
) << CSF
;
180 if (game
.initlevel()) return 1;
186 game
.stageboss
.OnMapExit();
205 stat(" ************************************************");
206 stat(" * An in-game error occurred. Game shutting down.");
207 stat(" ************************************************");
215 int32_t nexttick
= 0;
217 game
.switchstage
.mapno
= -1;
219 while(game
.running
&& game
.switchstage
.mapno
< 0)
221 // get time until next tick
222 int32_t curtime
= SDL_GetTicks();
223 int32_t timeRemaining
= nexttick
- curtime
;
225 if (timeRemaining
<= 0 || game
.ffwdtime
)
229 // try to "catch up" if something else on the system bogs us down for a moment.
230 // but if we get really far behind, it's ok to start dropping frames
234 nexttick
= curtime
+ GAME_WAIT
;
236 // pause game if window minimized
237 if ((SDL_GetAppState() & VISFLAGS
) != VISFLAGS
)
245 // don't needlessly hog CPU, but don't sleep for entire
246 // time left, some CPU's/kernels will fall asleep for
247 // too long and cause us to run slower than we should
250 SDL_Delay(timeRemaining
);
255 static inline void run_tick()
257 static bool can_tick
= true;
258 static bool last_freezekey
= false;
259 static bool last_framekey
= false;
260 static int frameskip
= 0;
264 // input handling for a few global things
265 if (justpushed(ESCKEY
))
267 if (settings
->instant_quit
)
269 game
.running
= false;
271 else if (!game
.paused
) // no pause from Options
273 game
.pause(GP_PAUSED
);
276 else if (justpushed(F3KEY
))
278 game
.pause(GP_OPTIONS
);
282 if (settings
->enable_debug_keys
)
284 if (inputs
[FREEZE_FRAME_KEY
] && !last_freezekey
)
291 if (inputs
[FRAME_ADVANCE_KEY
] && !last_framekey
)
301 last_freezekey
= inputs
[FREEZE_FRAME_KEY
];
302 last_framekey
= inputs
[FRAME_ADVANCE_KEY
];
305 // fast-forward key (F5)
306 if (inputs
[FFWDKEY
] && (settings
->enable_debug_keys
|| Replay::IsPlaying()))
318 sprintf(buf
, "[] Tick %d", framecount
++);
319 font_draw_shaded(4, (SCREEN_HEIGHT
-GetFontHeight()-4), buf
, 0, &greenfont
);
324 Replay::DrawStatus();
327 if (settings
->show_fps
)
334 //platform_sync_to_vblank();
347 memcpy(lastinputs
, inputs
, sizeof(lastinputs
));
350 { // frame is frozen; don't hog CPU
354 // immediately after a game tick is when we have the most amount of time before
355 // the game needs to run again. so now's as good a time as any for some
356 // BGM audio processing, wouldn't you say?
364 if ((SDL_GetTicks() - fpstimer
) >= 500)
366 fpstimer
= SDL_GetTicks();
367 fps
= (fps_so_far
<< 1);
372 sprintf(fpstext
, "%d fps", fps
);
374 int x
= (SCREEN_WIDTH
- 4) - GetFontWidth(fpstext
, 0, true);
375 font_draw_shaded(x
, 4, fpstext
, 0, &greenfont
);
379 void InitNewGame(bool with_intro
)
381 stat("= Beginning new game =");
383 memset(game
.flags
, 0, sizeof(game
.flags
));
384 memset(game
.skipflags
, 0, sizeof(game
.skipflags
));
385 textbox
.StageSelect
.ClearSlots();
387 game
.quaketime
= game
.megaquaketime
= 0;
388 game
.showmapnametime
= 0;
393 // fully re-init the player object
394 Objects::DestroyAll(true);
397 player
->maxHealth
= 3;
398 player
->hp
= player
->maxHealth
;
400 game
.switchstage
.mapno
= STAGE_START_POINT
;
401 game
.switchstage
.playerx
= 10;
402 game
.switchstage
.playery
= 8;
403 game
.switchstage
.eventonentry
= (with_intro
) ? 200 : 91;
405 fade
.set_full(FADE_OUT
);
409 void AppMinimized(void)
411 stat("Game minimized or lost focus--pausing...");
416 if ((SDL_GetAppState() & VISFLAGS
) == VISFLAGS
)
426 stat("Focus regained, resuming play...");
431 void c------------------------------() {}
434 static void fatal(const char *str
)
436 staterr("fatal: '%s'", str
);
438 if (!safemode::init())
440 safemode::moveto(SM_UPPER_THIRD
);
441 safemode::print("Fatal Error");
443 safemode::moveto(SM_CENTER
);
444 safemode::print("%s", str
);
446 safemode::run_until_key();
451 static bool check_data_exists()
453 char fname
[MAXPATHLEN
];
455 sprintf(fname
, "%s/npc.tbl", data_dir
);
456 if (file_exists(fname
)) return 0;
458 if (!safemode::init())
460 safemode::moveto(SM_UPPER_THIRD
);
461 safemode::print("Fatal Error");
463 safemode::moveto(SM_CENTER
);
464 safemode::print("Missing \"%s\" directory.", data_dir
);
465 safemode::print("Please copy it over from a Doukutsu installation.");
467 safemode::run_until_key();
474 void visible_warning(const char *fmt
, ...)
480 vsnprintf(buffer
, sizeof(buffer
), fmt
, ar
);
483 console
.Print(buffer
);
487 void c------------------------------() {}
492 void speed_test(void)
499 ClearScreen(255, 0, 0);
504 if (SDL_GetTicks() >= end
)
506 SDLS_VRAMSurface
->h
= 320;
507 SDLS_VRAMSurface
->cliprect
.h
= 320;
512 SDL_FillRect(SDLS_VRAMSurface
, &textrect
, 0);
515 sprintf(buffer
, "%d fps ", fps
);
516 direct_text_draw(5, 250, buffer
);
517 SDLS_VRAMSurface
->h
= 240;
518 SDLS_VRAMSurface
->cliprect
.h
= 240;
523 end
= SDL_GetTicks() + 1000;
533 void speed_test(void)
536 SDL_Surface
*vram
= screen
->GetSDLSurface();
542 SDL_FillRect(vram
, NULL
, SDL_MapRGB(vram
->format
, 255, 0, 0));
548 //SDL_FillRect(vram, NULL, c ^= 255);
550 if (SDL_GetTicks() >= end
)
554 end
= SDL_GetTicks() + 1000;
569 void org_test_miniloop(void)
571 uint32_t start
= 0, curtime
;
574 stat("Starting org test");
576 font_draw(5, 5, "ORG test in progress...", 0, &greenfont
);
577 font_draw(5, 15, "Logging statistics to nx.log", 0, &greenfont
);
578 font_draw(5, 25, "Press any button to quit", 0, &greenfont
);
581 music_set_enabled(1);
590 if (++counter
> 1024)
594 curtime
= SDL_GetTicks();
595 if ((curtime
- start
) >= 100)
600 if (last_sdl_key
!= -1)
607 void SDL_Delay(int ms
)